From 576a7a7c82af16402c930e9dae493a5642786950 Mon Sep 17 00:00:00 2001 From: Peter Collingbourne Date: Thu, 12 May 2022 15:37:03 -0700 Subject: [PATCH] [arch][arm64] determine the correct TCR_EL1.IPS at runtime Change the early startup code to set TCR_EL1.IPS to ID_AA64MMFR0_EL1.PARange if it has a defined value (the currently defined values have the same meanings), but use 48-bit PAs if 52-bit PAs are supported because 52-bit PAs have a different translation table format that we don't support. Stash the computed TCR_EL1 in a variable and use it in the context switch code. --- arch/arm64/include/arch/arm64/mmu.h | 7 +++---- arch/arm64/mmu.c | 9 ++++++--- arch/arm64/start.S | 23 ++++++++++++++++++++++- 3 files changed, 31 insertions(+), 8 deletions(-) diff --git a/arch/arm64/include/arch/arm64/mmu.h b/arch/arm64/include/arch/arm64/mmu.h index 64bba083d..35bb3ca84 100644 --- a/arch/arm64/include/arch/arm64/mmu.h +++ b/arch/arm64/include/arch/arm64/mmu.h @@ -197,8 +197,6 @@ MMU_MAIR_ATTR4 | MMU_MAIR_ATTR5 | \ MMU_MAIR_ATTR6 | MMU_MAIR_ATTR7 ) -#define MMU_TCR_IPS_DEFAULT MMU_TCR_IPS(2) /* TODO: read at runtime, or configure per platform */ - /* Enable cached page table walks: * inner/outer (IRGN/ORGN): write-back + write-allocate */ @@ -212,8 +210,9 @@ MMU_TCR_ORGN0(MMU_RGN_WRITE_BACK_ALLOCATE) | \ MMU_TCR_IRGN0(MMU_RGN_WRITE_BACK_ALLOCATE) | \ MMU_TCR_T0SZ(64 - MMU_USER_SIZE_SHIFT)) -#define MMU_TCR_FLAGS_KERNEL (MMU_TCR_IPS_DEFAULT | MMU_TCR_FLAGS1 | MMU_TCR_FLAGS0 | MMU_TCR_EPD0) -#define MMU_TCR_FLAGS_USER (MMU_TCR_IPS_DEFAULT | MMU_TCR_FLAGS1 | MMU_TCR_FLAGS0) +#define MMU_TCR_FLAGS_BASE (MMU_TCR_FLAGS1 | MMU_TCR_FLAGS0) +#define MMU_TCR_FLAGS_KERNEL (MMU_TCR_EPD0) +#define MMU_TCR_FLAGS_USER (0) #define MMU_PTE_KERNEL_RO_FLAGS \ (MMU_PTE_ATTR_UXN | \ diff --git a/arch/arm64/mmu.c b/arch/arm64/mmu.c index f3bc5dac8..0fd2dc015 100644 --- a/arch/arm64/mmu.c +++ b/arch/arm64/mmu.c @@ -30,6 +30,9 @@ pte_t arm64_kernel_translation_table[MMU_KERNEL_PAGE_TABLE_ENTRIES_TOP] __ALIGNED(MMU_KERNEL_PAGE_TABLE_ENTRIES_TOP * 8) __SECTION(".bss.prebss.translation_table"); +/* the base TCR flags, computed from early init code in start.S */ +uint64_t arm64_mmu_tcr_flags __SECTION(".bss.prebss.tcr_flags"); + static inline bool is_valid_vaddr(arch_aspace_t *aspace, vaddr_t vaddr) { return (vaddr >= aspace->base && vaddr <= aspace->base + aspace->size - 1); } @@ -630,12 +633,12 @@ void arch_mmu_context_switch(arch_aspace_t *aspace) { if (TRACE_CONTEXT_SWITCH) TRACEF("aspace %p\n", aspace); - uint64_t tcr; + uint64_t tcr = arm64_mmu_tcr_flags; uint64_t ttbr; if (aspace) { DEBUG_ASSERT((aspace->flags & ARCH_ASPACE_FLAG_KERNEL) == 0); - tcr = MMU_TCR_FLAGS_USER; + tcr |= MMU_TCR_FLAGS_USER; ttbr = ((uint64_t)MMU_ARM64_USER_ASID << 48) | aspace->tt_phys; ARM64_WRITE_SYSREG(ttbr0_el1, ttbr); @@ -643,7 +646,7 @@ void arch_mmu_context_switch(arch_aspace_t *aspace) { TRACEF("ttbr 0x%llx, tcr 0x%llx\n", ttbr, tcr); ARM64_TLBI(aside1, (uint64_t)MMU_ARM64_USER_ASID << 48); } else { - tcr = MMU_TCR_FLAGS_KERNEL; + tcr |= MMU_TCR_FLAGS_KERNEL; if (TRACE_CONTEXT_SWITCH) TRACEF("tcr 0x%llx\n", tcr); diff --git a/arch/arm64/start.S b/arch/arm64/start.S index de06af3fd..2582bcd61 100644 --- a/arch/arm64/start.S +++ b/arch/arm64/start.S @@ -266,6 +266,25 @@ arm_reset: b .Lmap_range_one_table_loop .Linitial_mapping_done: + /* compute the base TCR configuration and save away in a global for future use */ + ldr tmp, =MMU_TCR_FLAGS_BASE + + /* Set TCR_EL1.IPS to ID_AA64MMFR0_EL1.PARange */ + mrs tmp2, id_aa64mmfr0_el1 + and tmp2, tmp2, #0xf + /* + * Give up if we see a reserved value. 52-bit PAs have a different translation + * table format that we don't support, so use 48-bit PAs in that case. + */ + cmp tmp2, #6 + b.hi . + b.lo 1f + mov tmp2, #5 +1: + orr tmp, tmp, tmp2, lsl #32 + adrp tmp2, arm64_mmu_tcr_flags + str tmp, [tmp2, #:lo12:arm64_mmu_tcr_flags] + #if WITH_SMP adrp tmp, page_tables_not_ready add tmp, tmp, #:lo12:page_tables_not_ready @@ -295,7 +314,9 @@ arm_reset: /* Initialize TCR_EL1 */ /* set cacheable attributes on translation walk */ /* (SMP extensions) non-shareable, inner write-back write-allocate */ - ldr tmp, =MMU_TCR_FLAGS_KERNEL + adrp tmp, arm64_mmu_tcr_flags + ldr tmp, [tmp, #:lo12:arm64_mmu_tcr_flags] + orr tmp, tmp, #MMU_TCR_FLAGS_KERNEL msr tcr_el1, tmp isb