File indexing completed on 2025-05-11 08:22:42
0001
0002
0003
0004
0005
0006
0007
0008
0009
0010
0011
0012
0013
0014
0015
0016
0017
0018
0019
0020
0021
0022
0023
0024
0025
0026
0027
0028
0029
0030
0031
0032
0033
0034
0035
0036
0037 #include <bsp/aarch64-mmu.h>
0038
0039 #include <bsp/fatal.h>
0040 #include <bsp/linker-symbols.h>
0041 #include <bsp/start.h>
0042 #include <rtems/score/aarch64-system-registers.h>
0043 #include <rtems/score/assert.h>
0044
0045 aarch64_mmu_control aarch64_mmu_instance = {
0046 .ttb = (uint64_t *) bsp_translation_table_base,
0047
0048
0049 .used_page_tables = 1
0050 };
0051
0052
0053 #define MMU_MAX_SUBTABLE_PAGE_BITS ( 3 * MMU_BITS_PER_LEVEL + MMU_PAGE_BITS )
0054
0055
0056 BSP_START_TEXT_SECTION static inline void aarch64_mmu_page_table_set_blocks(
0057 uint64_t *page_table,
0058 uint64_t base,
0059 uint32_t bits_offset,
0060 uint64_t default_attr
0061 )
0062 {
0063 uint64_t page_flag = 0;
0064
0065 if ( bits_offset == MMU_PAGE_BITS ) {
0066 page_flag = MMU_DESC_TYPE_PAGE;
0067 }
0068
0069 for ( uint64_t i = 0; i < ( 1 << MMU_BITS_PER_LEVEL ); i++ ) {
0070 page_table[i] = base | ( i << bits_offset );
0071 page_table[i] |= default_attr | page_flag;
0072 }
0073 }
0074
0075 BSP_START_TEXT_SECTION static inline uint64_t *
0076 aarch64_mmu_page_table_alloc( aarch64_mmu_control *control )
0077 {
0078 size_t used_page_tables = control->used_page_tables;
0079
0080 if ( used_page_tables >= AARCH64_MMU_TRANSLATION_TABLE_PAGES ) {
0081 return NULL;
0082 }
0083
0084 control->used_page_tables = used_page_tables + 1;
0085 return (uint64_t *)
0086 ( (uintptr_t) control->ttb + ( used_page_tables << MMU_PAGE_BITS ) );
0087 }
0088
0089 BSP_START_TEXT_SECTION static inline uintptr_t aarch64_mmu_get_index(
0090 uintptr_t root_address,
0091 uintptr_t vaddr,
0092 uint32_t shift
0093 )
0094 {
0095 uintptr_t mask = ( 1 << ( MMU_BITS_PER_LEVEL + 1 ) ) - 1;
0096
0097 return ( ( vaddr - root_address ) >> shift ) & mask;
0098 }
0099
0100 BSP_START_TEXT_SECTION static uint64_t *
0101 aarch64_mmu_get_sub_table(
0102 aarch64_mmu_control *control,
0103 uint64_t *page_table_entry,
0104 uintptr_t physical_root_address,
0105 uint32_t shift
0106 )
0107 {
0108
0109 if ( ( *page_table_entry & MMU_DESC_TYPE_TABLE ) == MMU_DESC_TYPE_TABLE ) {
0110
0111 uint64_t table_pointer = *page_table_entry & MMU_DESC_PAGE_TABLE_MASK;
0112
0113 return (uint64_t *) (uintptr_t) table_pointer;
0114 }
0115
0116
0117 uint64_t *sub_table = aarch64_mmu_page_table_alloc( control );
0118
0119 if ( sub_table == NULL ) {
0120 return NULL;
0121 }
0122
0123 aarch64_mmu_page_table_set_blocks(
0124 sub_table,
0125 physical_root_address,
0126 shift - MMU_BITS_PER_LEVEL,
0127 *page_table_entry & ~MMU_DESC_PAGE_TABLE_MASK
0128 );
0129 *page_table_entry = (uintptr_t) sub_table;
0130 *page_table_entry |= MMU_DESC_TYPE_TABLE | MMU_DESC_VALID;
0131
0132 return sub_table;
0133 }
0134
0135 BSP_START_TEXT_SECTION static inline rtems_status_code aarch64_mmu_map_block(
0136 aarch64_mmu_control *control,
0137 uint64_t *page_table,
0138 uint64_t root_address,
0139 uint64_t addr,
0140 uint64_t size,
0141 int8_t level,
0142 uint64_t flags
0143 )
0144 {
0145 uint32_t shift = ( 2 - level ) * MMU_BITS_PER_LEVEL + MMU_PAGE_BITS;
0146 uint64_t granularity = 1LLU << shift;
0147
0148 do {
0149 uintptr_t index = aarch64_mmu_get_index( root_address, addr, shift );
0150 uint64_t block_bottom = RTEMS_ALIGN_DOWN( addr, granularity );
0151 uint64_t chunk_size = granularity;
0152
0153
0154 if ( block_bottom == addr ) {
0155 if ( size >= chunk_size ) {
0156
0157 if ( level != -1 ) {
0158 uint64_t page_flag = 0;
0159
0160 if ( level == 2 ) {
0161 page_flag = MMU_DESC_TYPE_PAGE;
0162 }
0163
0164
0165 if ( page_flag || ( page_table[index] & MMU_DESC_TYPE_TABLE ) != MMU_DESC_TYPE_TABLE ) {
0166
0167 page_table[index] = addr | flags | page_flag;
0168 size -= chunk_size;
0169 addr += chunk_size;
0170 continue;
0171 }
0172 }
0173 } else {
0174
0175
0176
0177
0178
0179
0180
0181 _Assert( level < 2 );
0182 chunk_size = size;
0183 }
0184 } else {
0185 uintptr_t block_top = RTEMS_ALIGN_UP( addr, granularity );
0186 chunk_size = block_top - addr;
0187
0188 if ( chunk_size > size ) {
0189 chunk_size = size;
0190 }
0191 }
0192
0193
0194 uint64_t new_root_address = root_address + index * granularity;
0195 rtems_status_code sc;
0196
0197 uint64_t *sub_table = aarch64_mmu_get_sub_table(
0198 control,
0199 &page_table[index],
0200 new_root_address,
0201 shift
0202 );
0203
0204 if ( sub_table == NULL ) {
0205 return RTEMS_TOO_MANY;
0206 }
0207
0208 sc = aarch64_mmu_map_block(
0209 control,
0210 sub_table,
0211 new_root_address,
0212 addr,
0213 chunk_size,
0214 level + 1,
0215 flags
0216 );
0217
0218 if ( sc != RTEMS_SUCCESSFUL ) {
0219 return sc;
0220 }
0221
0222 size -= chunk_size;
0223 addr += chunk_size;
0224 } while ( size > 0 );
0225
0226 return RTEMS_SUCCESSFUL;
0227 }
0228
0229 BSP_START_TEXT_SECTION static inline uint64_t
0230 aarch64_mmu_get_cpu_pa_bits( void )
0231 {
0232 #ifdef AARCH64_MMU_PHYSICAL_ADDRESS_RANGE_BITS
0233 return AARCH64_MMU_PHYSICAL_ADDRESS_RANGE_BITS;
0234 #else
0235 uint64_t id_reg = _AArch64_Read_id_aa64mmfr0_el1();
0236
0237 switch ( AARCH64_ID_AA64MMFR0_EL1_PARANGE_GET( id_reg ) ) {
0238 case 0:
0239 return 32;
0240 case 1:
0241 return 36;
0242 case 2:
0243 return 40;
0244 case 3:
0245 return 42;
0246 case 4:
0247 return 44;
0248 case 5:
0249 return 48;
0250 case 6:
0251 return 52;
0252 default:
0253 return 48;
0254 }
0255 return 48;
0256 #endif
0257 }
0258
0259 BSP_START_TEXT_SECTION rtems_status_code
0260 aarch64_mmu_set_translation_table_entries(
0261 aarch64_mmu_control *control,
0262 const aarch64_mmu_config_entry *config
0263 )
0264 {
0265 uint64_t max_mappable = 1LLU << aarch64_mmu_get_cpu_pa_bits();
0266
0267 uintptr_t begin = RTEMS_ALIGN_DOWN( config->begin, MMU_PAGE_SIZE );
0268 uintptr_t end = RTEMS_ALIGN_UP( config->end, MMU_PAGE_SIZE );
0269 uintptr_t size = end - begin;
0270
0271 if ( config->begin == config->end ) {
0272 return RTEMS_SUCCESSFUL;
0273 }
0274
0275 if ( begin >= max_mappable ) {
0276 return RTEMS_INVALID_ADDRESS;
0277 }
0278
0279 if ( size > max_mappable - begin ) {
0280 return RTEMS_INVALID_SIZE;
0281 }
0282
0283 return aarch64_mmu_map_block(
0284 control,
0285 control->ttb,
0286 0x0,
0287 begin,
0288 size,
0289 -1,
0290 config->flags
0291 );
0292 }
0293
0294 BSP_START_TEXT_SECTION void aarch64_mmu_setup_translation_table(
0295 aarch64_mmu_control *control,
0296 const aarch64_mmu_config_entry *config_table,
0297 size_t config_count
0298 )
0299 {
0300 size_t i;
0301
0302 aarch64_mmu_page_table_set_blocks(
0303 control->ttb,
0304 (uintptr_t) NULL,
0305 MMU_MAX_SUBTABLE_PAGE_BITS,
0306 0
0307 );
0308
0309
0310 for ( i = 0; i < config_count; ++i ) {
0311 rtems_status_code sc;
0312
0313 sc = aarch64_mmu_set_translation_table_entries( control, &config_table[i] );
0314
0315 if ( sc != RTEMS_SUCCESSFUL ) {
0316 bsp_fatal( AARCH64_FATAL_MMU_CANNOT_MAP_BLOCK );
0317 }
0318 }
0319 }