summaryrefslogtreecommitdiffstats
path: root/bsps/aarch64/include/bsp/aarch64-mmu.h
diff options
context:
space:
mode:
Diffstat (limited to 'bsps/aarch64/include/bsp/aarch64-mmu.h')
-rw-r--r--bsps/aarch64/include/bsp/aarch64-mmu.h165
1 files changed, 98 insertions, 67 deletions
diff --git a/bsps/aarch64/include/bsp/aarch64-mmu.h b/bsps/aarch64/include/bsp/aarch64-mmu.h
index e82012576f..8c69705230 100644
--- a/bsps/aarch64/include/bsp/aarch64-mmu.h
+++ b/bsps/aarch64/include/bsp/aarch64-mmu.h
@@ -37,54 +37,20 @@
#ifndef LIBBSP_AARCH64_SHARED_AARCH64_MMU_H
#define LIBBSP_AARCH64_SHARED_AARCH64_MMU_H
-#include <bsp/start.h>
+#include <bsp/fatal.h>
#include <bsp/linker-symbols.h>
-#include <rtems/score/aarch64-system-registers.h>
-#include <bspopts.h>
+#include <bsp/start.h>
#include <bsp/utility.h>
+#include <bspopts.h>
+#include <libcpu/mmu-vmsav8-64.h>
+#include <rtems/score/aarch64-system-registers.h>
#ifdef __cplusplus
extern "C" {
#endif /* __cplusplus */
-/* VMSAv8 Long-descriptor fields */
-#define MMU_DESC_AF BSP_BIT64( 10 )
-#define MMU_DESC_SH_INNER ( BSP_BIT64( 9 ) | BSP_BIT64( 8 ) )
-#define MMU_DESC_WRITE_DISABLE BSP_BIT64( 7 )
-/* PAGE and TABLE flags are the same bit, but only apply on certain levels */
-#define MMU_DESC_TYPE_TABLE BSP_BIT64( 1 )
-#define MMU_DESC_TYPE_PAGE BSP_BIT64( 1 )
-#define MMU_DESC_VALID BSP_BIT64( 0 )
-#define MMU_DESC_MAIR_ATTR( val ) BSP_FLD64( val, 2, 3 )
-#define MMU_DESC_MAIR_ATTR_GET( reg ) BSP_FLD64GET( reg, 2, 3 )
-#define MMU_DESC_MAIR_ATTR_SET( reg, val ) BSP_FLD64SET( reg, val, 2, 3 )
-#define MMU_DESC_PAGE_TABLE_MASK 0xFFFFFFFFF000LL
-
-/* Page table configuration */
-#define MMU_PAGE_BITS 12
-#define MMU_PAGE_SIZE ( 1 << MMU_PAGE_BITS )
-#define MMU_BITS_PER_LEVEL 9
-#define MMU_TOP_LEVEL_PAGE_BITS ( 2 * MMU_BITS_PER_LEVEL + MMU_PAGE_BITS )
-
-#define AARCH64_MMU_FLAGS_BASE \
- ( MMU_DESC_VALID | MMU_DESC_SH_INNER | MMU_DESC_AF )
-
-#define AARCH64_MMU_DATA_RO_CACHED \
- ( AARCH64_MMU_FLAGS_BASE | MMU_DESC_MAIR_ATTR( 3 ) | MMU_DESC_WRITE_DISABLE )
-#define AARCH64_MMU_CODE_CACHED AARCH64_MMU_DATA_RO_CACHED
-#define AARCH64_MMU_CODE_RW_CACHED AARCH64_MMU_DATA_RW_CACHED
-
-#define AARCH64_MMU_DATA_RO \
- ( AARCH64_MMU_FLAGS_BASE | MMU_DESC_MAIR_ATTR( 1 ) | MMU_DESC_WRITE_DISABLE )
-#define AARCH64_MMU_CODE AARCH64_MMU_DATA_RO
-#define AARCH64_MMU_CODE_RW AARCH64_MMU_DATA_RW
-
-/* RW implied by not ORing in RO */
-#define AARCH64_MMU_DATA_RW_CACHED \
- ( AARCH64_MMU_FLAGS_BASE | MMU_DESC_MAIR_ATTR( 3 ) )
-#define AARCH64_MMU_DATA_RW \
- ( AARCH64_MMU_FLAGS_BASE | MMU_DESC_MAIR_ATTR( 1 ) )
-#define AARCH64_MMU_DEVICE ( AARCH64_MMU_FLAGS_BASE | MMU_DESC_MAIR_ATTR( 0 ) )
+/* AArch64 uses levels 0, 1, 2, and 3 */
+#define MMU_MAX_SUBTABLE_PAGE_BITS ( 3 * MMU_BITS_PER_LEVEL + MMU_PAGE_BITS )
typedef struct {
uintptr_t begin;
@@ -130,6 +96,10 @@ typedef struct {
.end = (uintptr_t) bsp_section_rtemsstack_end, \
.flags = AARCH64_MMU_DATA_RW_CACHED \
}, { \
+ .begin = (uintptr_t) bsp_section_noinit_begin, \
+ .end = (uintptr_t) bsp_section_noinit_end, \
+ .flags = AARCH64_MMU_DATA_RW_CACHED \
+ }, { \
.begin = (uintptr_t) bsp_section_work_begin, \
.end = (uintptr_t) bsp_section_work_end, \
.flags = AARCH64_MMU_DATA_RW_CACHED \
@@ -183,8 +153,8 @@ BSP_START_TEXT_SECTION static inline rtems_status_code
aarch64_mmu_page_table_alloc( uint64_t **page_table )
{
/* First page table is already in use as TTB0 */
- static uintptr_t *current_page_table =
- (uintptr_t *) bsp_translation_table_base;
+ static uintptr_t current_page_table =
+ (uintptr_t) bsp_translation_table_base;
current_page_table += MMU_PAGE_SIZE;
*page_table = (uint64_t *) current_page_table;
@@ -250,15 +220,15 @@ aarch64_mmu_get_sub_table(
BSP_START_TEXT_SECTION static inline rtems_status_code aarch64_mmu_map_block(
uint64_t *page_table,
- uintptr_t root_address,
- uintptr_t addr,
+ uint64_t root_address,
+ uint64_t addr,
uint64_t size,
- uint32_t level,
+ int8_t level,
uint64_t flags
)
{
uint32_t shift = ( 2 - level ) * MMU_BITS_PER_LEVEL + MMU_PAGE_BITS;
- uintptr_t granularity = 1 << shift;
+ uint64_t granularity = 1LLU << shift;
uint64_t page_flag = 0;
if ( level == 2 ) {
@@ -267,23 +237,35 @@ BSP_START_TEXT_SECTION static inline rtems_status_code aarch64_mmu_map_block(
while ( size > 0 ) {
uintptr_t index = aarch64_mmu_get_index( root_address, addr, shift );
- uintptr_t block_bottom = RTEMS_ALIGN_DOWN( addr, granularity );
+ uint64_t block_bottom = RTEMS_ALIGN_DOWN( addr, granularity );
uint64_t chunk_size = granularity;
/* check for perfect block match */
if ( block_bottom == addr ) {
if ( size >= chunk_size ) {
- /* when page_flag is set the last level must be a page descriptor */
- if ( page_flag || ( page_table[index] & MMU_DESC_TYPE_TABLE ) != MMU_DESC_TYPE_TABLE ) {
+ /* level -1 can't contain block descriptors, fall through to subtable */
+ if ( level != -1 ) {
+ /* when page_flag is set the last level must be a page descriptor */
+ if ( page_flag || ( page_table[index] & MMU_DESC_TYPE_TABLE ) != MMU_DESC_TYPE_TABLE ) {
+ /* no sub-table, apply block properties */
+ page_table[index] = addr | flags | page_flag;
+ size -= chunk_size;
+ addr += chunk_size;
+ continue;
+ }
+ }
+ } else {
+ /* block starts on a boundary, but is short */
+ chunk_size = size;
+
+ /* it isn't possible to go beyond page table level 2 */
+ if ( page_flag ) {
/* no sub-table, apply block properties */
page_table[index] = addr | flags | page_flag;
size -= chunk_size;
addr += chunk_size;
continue;
}
- } else {
- /* block starts on a boundary, but is short */
- chunk_size = size;
}
} else {
uintptr_t block_top = RTEMS_ALIGN_UP( addr, granularity );
@@ -295,7 +277,7 @@ BSP_START_TEXT_SECTION static inline rtems_status_code aarch64_mmu_map_block(
}
/* Deal with any subtable modification */
- uintptr_t new_root_address = root_address + index * granularity;
+ uint64_t new_root_address = root_address + index * granularity;
uint64_t *sub_table = NULL;
rtems_status_code sc;
@@ -336,6 +318,33 @@ BSP_START_DATA_SECTION extern const aarch64_mmu_config_entry
BSP_START_DATA_SECTION extern const size_t
aarch64_mmu_config_table_size;
+/* Get the maximum number of bits supported by this hardware */
+BSP_START_TEXT_SECTION static inline uint64_t
+aarch64_mmu_get_cpu_pa_bits( void )
+{
+ uint64_t id_reg = _AArch64_Read_id_aa64mmfr0_el1();
+
+ switch ( AARCH64_ID_AA64MMFR0_EL1_PARANGE_GET( id_reg ) ) {
+ case 0:
+ return 32;
+ case 1:
+ return 36;
+ case 2:
+ return 40;
+ case 3:
+ return 42;
+ case 4:
+ return 44;
+ case 5:
+ return 48;
+ case 6:
+ return 52;
+ default:
+ return 48;
+ }
+ return 48;
+}
+
BSP_START_TEXT_SECTION static inline void
aarch64_mmu_set_translation_table_entries(
uint64_t *ttb,
@@ -345,14 +354,19 @@ aarch64_mmu_set_translation_table_entries(
/* Force alignemnt to 4k page size */
uintptr_t begin = RTEMS_ALIGN_DOWN( config->begin, MMU_PAGE_SIZE );
uintptr_t end = RTEMS_ALIGN_UP( config->end, MMU_PAGE_SIZE );
+ uint64_t max_mappable = 1LLU << aarch64_mmu_get_cpu_pa_bits();
rtems_status_code sc;
+ if ( begin >= max_mappable || end > max_mappable ) {
+ bsp_fatal( BSP_FATAL_MMU_ADDRESS_INVALID );
+ }
+
sc = aarch64_mmu_map_block(
ttb,
0x0,
begin,
end - begin,
- 0,
+ -1,
config->flags
);
@@ -372,7 +386,7 @@ BSP_START_TEXT_SECTION static inline void aarch64_mmu_setup_translation_table(
aarch64_mmu_page_table_set_blocks(
ttb,
(uintptr_t) NULL,
- MMU_TOP_LEVEL_PAGE_BITS,
+ MMU_MAX_SUBTABLE_PAGE_BITS,
0
);
@@ -385,17 +399,15 @@ BSP_START_TEXT_SECTION static inline void aarch64_mmu_setup_translation_table(
}
BSP_START_TEXT_SECTION static inline void
-aarch64_mmu_setup_translation_table_and_enable(
- const aarch64_mmu_config_entry *config_table,
- size_t config_count
-)
+aarch64_mmu_enable( void )
{
uint64_t sctlr;
- aarch64_mmu_setup_translation_table(
- config_table,
- config_count
- );
+ /* CPUECTLR_EL1.SMPEN is already set on ZynqMP and is not writable */
+
+ /* Flush and invalidate cache */
+ rtems_cache_flush_entire_data();
+ rtems_cache_invalidate_entire_data();
/* Enable MMU and cache */
sctlr = _AArch64_Read_sctlr_el1();
@@ -403,13 +415,32 @@ aarch64_mmu_setup_translation_table_and_enable(
_AArch64_Write_sctlr_el1( sctlr );
}
+BSP_START_TEXT_SECTION static inline void
+aarch64_mmu_disable( void )
+{
+ uint64_t sctlr;
+
+ /*
+ * Flush data cache before disabling the MMU. While the MMU is disabled, all
+ * accesses are treated as uncached device memory.
+ */
+ rtems_cache_flush_entire_data();
+
+ /* Disable MMU */
+ sctlr = _AArch64_Read_sctlr_el1();
+ sctlr &= ~(AARCH64_SCTLR_EL1_M);
+ _AArch64_Write_sctlr_el1( sctlr );
+}
+
BSP_START_TEXT_SECTION static inline void aarch64_mmu_setup( void )
{
/* Set TCR */
- /* 128GB/36 bits mappable (64-0x1c) */
+ /* 256TB/48 bits mappable (64-0x10) */
_AArch64_Write_tcr_el1(
- AARCH64_TCR_EL1_T0SZ( 0x1c ) | AARCH64_TCR_EL1_IRGN0( 0x1 ) |
- AARCH64_TCR_EL1_ORGN0( 0x1 ) | AARCH64_TCR_EL1_SH0( 0x3 ) | AARCH64_TCR_EL1_TG0( 0x0 )
+ AARCH64_TCR_EL1_T0SZ( 0x10 ) | AARCH64_TCR_EL1_IRGN0( 0x1 ) |
+ AARCH64_TCR_EL1_ORGN0( 0x1 ) | AARCH64_TCR_EL1_SH0( 0x3 ) |
+ AARCH64_TCR_EL1_TG0( 0x0 ) | AARCH64_TCR_EL1_IPS( 0x5ULL ) |
+ AARCH64_TCR_EL1_EPD1
);
/* Set MAIR */