xlat lib v2: Refactor the functions enabling the MMU
This patch refactors both the AArch32 and AArch64 versions of the
function enable_mmu_arch().
In both versions, the code now computes the VMSA-related system
registers upfront then program them in one go (rather than interleaving
the 2).
In the AArch64 version, this allows to reduce the amount of code
generated by the C preprocessor and limits it to the actual differences
between EL1 and EL3.
In the AArch32 version, this patch also removes the function
enable_mmu_internal_secure() and moves its code directly inside
enable_mmu_arch(), as it was its only caller.
Change-Id: I35c09b6db4404916cbb2e2fd3fda2ad59f935954
Signed-off-by: Sandrine Bailleux <sandrine.bailleux@arm.com>
diff --git a/lib/xlat_tables_v2/aarch32/xlat_tables_arch.c b/lib/xlat_tables_v2/aarch32/xlat_tables_arch.c
index 84f1a7d..78aae2b 100644
--- a/lib/xlat_tables_v2/aarch32/xlat_tables_arch.c
+++ b/lib/xlat_tables_v2/aarch32/xlat_tables_arch.c
@@ -82,16 +82,20 @@
}
/*******************************************************************************
- * Function for enabling the MMU in Secure PL1, assuming that the
- * page-tables have already been created.
+ * Function for enabling the MMU in Secure PL1, assuming that the page tables
+ * have already been created.
******************************************************************************/
-void enable_mmu_internal_secure(unsigned int flags, uint64_t *base_table)
+void enable_mmu_arch(unsigned int flags,
+ uint64_t *base_table,
+ unsigned long long max_pa)
{
u_register_t mair0, ttbcr, sctlr;
uint64_t ttbr0;
assert(IS_IN_SECURE());
- assert((read_sctlr() & SCTLR_M_BIT) == 0);
+
+ sctlr = read_sctlr();
+ assert((sctlr & SCTLR_M_BIT) == 0);
/* Invalidate TLBs at the current exception level */
tlbiall();
@@ -102,29 +106,47 @@
ATTR_IWBWA_OWBWA_NTR_INDEX);
mair0 |= MAIR0_ATTR_SET(ATTR_NON_CACHEABLE,
ATTR_NON_CACHEABLE_INDEX);
- write_mair0(mair0);
+
+ /*
+ * Configure the control register for stage 1 of the PL1&0 translation
+ * regime.
+ */
+
+ /* Use the Long-descriptor translation table format. */
+ ttbcr = TTBCR_EAE_BIT;
+
+ /*
+ * Disable translation table walk for addresses that are translated
+ * using TTBR1. Therefore, only TTBR0 is used.
+ */
+ ttbcr |= TTBCR_EPD1_BIT;
/*
- * Set TTBCR bits as well. Set TTBR0 table properties. Disable TTBR1.
+ * Limit the input address ranges and memory region sizes translated
+ * using TTBR0 to the given virtual address space size.
+ */
+ ttbcr |= 32 - __builtin_ctzl((uintptr_t) PLAT_VIRT_ADDR_SPACE_SIZE);
+
+ /*
+ * Set the cacheability and shareability attributes for memory
+ * associated with translation table walks using TTBR0.
*/
if (flags & XLAT_TABLE_NC) {
/* Inner & outer non-cacheable non-shareable. */
- ttbcr = TTBCR_EAE_BIT |
- TTBCR_SH0_NON_SHAREABLE | TTBCR_RGN0_OUTER_NC |
- TTBCR_RGN0_INNER_NC |
- (32 - __builtin_ctzl((uintptr_t)PLAT_VIRT_ADDR_SPACE_SIZE));
+ ttbcr |= TTBCR_SH0_NON_SHAREABLE | TTBCR_RGN0_OUTER_NC |
+ TTBCR_RGN0_INNER_NC;
} else {
/* Inner & outer WBWA & shareable. */
- ttbcr = TTBCR_EAE_BIT |
- TTBCR_SH0_INNER_SHAREABLE | TTBCR_RGN0_OUTER_WBA |
- TTBCR_RGN0_INNER_WBA |
- (32 - __builtin_ctzl((uintptr_t)PLAT_VIRT_ADDR_SPACE_SIZE));
+ ttbcr |= TTBCR_SH0_INNER_SHAREABLE | TTBCR_RGN0_OUTER_WBA |
+ TTBCR_RGN0_INNER_WBA;
}
- ttbcr |= TTBCR_EPD1_BIT;
- write_ttbcr(ttbcr);
/* Set TTBR0 bits as well */
ttbr0 = (uint64_t)(uintptr_t) base_table;
+
+ /* Now program the relevant system registers */
+ write_mair0(mair0);
+ write_ttbcr(ttbcr);
write64_ttbr0(ttbr0);
write64_ttbr1(0);
@@ -137,7 +159,6 @@
dsbish();
isb();
- sctlr = read_sctlr();
sctlr |= SCTLR_WXN_BIT | SCTLR_M_BIT;
if (flags & DISABLE_DCACHE)
@@ -150,10 +171,3 @@
/* Ensure the MMU enable takes effect immediately */
isb();
}
-
-void enable_mmu_arch(unsigned int flags,
- uint64_t *base_table,
- unsigned long long max_pa)
-{
- enable_mmu_internal_secure(flags, base_table);
-}
diff --git a/lib/xlat_tables_v2/aarch64/xlat_tables_arch.c b/lib/xlat_tables_v2/aarch64/xlat_tables_arch.c
index ba1ab73..49b0605 100644
--- a/lib/xlat_tables_v2/aarch64/xlat_tables_arch.c
+++ b/lib/xlat_tables_v2/aarch64/xlat_tables_arch.c
@@ -22,8 +22,6 @@
# define IMAGE_EL 1
#endif
-static unsigned long long tcr_ps_bits;
-
static unsigned long long calc_physical_addr_size_bits(
unsigned long long max_addr)
{
@@ -151,50 +149,23 @@
* exception level, assuming that the pagetables have already been created.
*
* _el: Exception level at which the function will run
- * _tcr_extra: Extra bits to set in the TCR register. This mask will
- * be OR'ed with the default TCR value.
* _tlbi_fct: Function to invalidate the TLBs at the current
* exception level
******************************************************************************/
-#define DEFINE_ENABLE_MMU_EL(_el, _tcr_extra, _tlbi_fct) \
- void enable_mmu_internal_el##_el(unsigned int flags, \
- uint64_t *base_table) \
+#define DEFINE_ENABLE_MMU_EL(_el, _tlbi_fct) \
+ static void enable_mmu_internal_el##_el(int flags, \
+ uint64_t mair, \
+ uint64_t tcr, \
+ uint64_t ttbr) \
{ \
- uint64_t mair, tcr, ttbr; \
- uint32_t sctlr; \
- \
- assert(IS_IN_EL(_el)); \
- assert((read_sctlr_el##_el() & SCTLR_M_BIT) == 0); \
+ uint32_t sctlr = read_sctlr_el##_el(); \
+ assert((sctlr & SCTLR_M_BIT) == 0); \
\
/* Invalidate TLBs at the current exception level */ \
_tlbi_fct(); \
\
- /* Set attributes in the right indices of the MAIR */ \
- mair = MAIR_ATTR_SET(ATTR_DEVICE, ATTR_DEVICE_INDEX); \
- mair |= MAIR_ATTR_SET(ATTR_IWBWA_OWBWA_NTR, \
- ATTR_IWBWA_OWBWA_NTR_INDEX); \
- mair |= MAIR_ATTR_SET(ATTR_NON_CACHEABLE, \
- ATTR_NON_CACHEABLE_INDEX); \
write_mair_el##_el(mair); \
- \
- /* Set TCR bits as well. */ \
- /* Set T0SZ to (64 - width of virtual address space) */ \
- if (flags & XLAT_TABLE_NC) { \
- /* Inner & outer non-cacheable non-shareable. */\
- tcr = TCR_SH_NON_SHAREABLE | \
- TCR_RGN_OUTER_NC | TCR_RGN_INNER_NC | \
- (64 - __builtin_ctzl(PLAT_VIRT_ADDR_SPACE_SIZE));\
- } else { \
- /* Inner & outer WBWA & shareable. */ \
- tcr = TCR_SH_INNER_SHAREABLE | \
- TCR_RGN_OUTER_WBA | TCR_RGN_INNER_WBA | \
- (64 - __builtin_ctzl(PLAT_VIRT_ADDR_SPACE_SIZE));\
- } \
- tcr |= _tcr_extra; \
write_tcr_el##_el(tcr); \
- \
- /* Set TTBR bits as well */ \
- ttbr = (uint64_t) base_table; \
write_ttbr0_el##_el(ttbr); \
\
/* Ensure all translation table writes have drained */ \
@@ -204,9 +175,7 @@
dsbish(); \
isb(); \
\
- sctlr = read_sctlr_el##_el(); \
sctlr |= SCTLR_WXN_BIT | SCTLR_M_BIT; \
- \
if (flags & DISABLE_DCACHE) \
sctlr &= ~SCTLR_C_BIT; \
else \
@@ -220,30 +189,61 @@
/* Define EL1 and EL3 variants of the function enabling the MMU */
#if IMAGE_EL == 1
-DEFINE_ENABLE_MMU_EL(1,
- (tcr_ps_bits << TCR_EL1_IPS_SHIFT),
- tlbivmalle1)
+DEFINE_ENABLE_MMU_EL(1, tlbivmalle1)
#elif IMAGE_EL == 3
-DEFINE_ENABLE_MMU_EL(3,
- TCR_EL3_RES1 | (tcr_ps_bits << TCR_EL3_PS_SHIFT),
- tlbialle3)
+DEFINE_ENABLE_MMU_EL(3, tlbialle3)
#endif
void enable_mmu_arch(unsigned int flags,
uint64_t *base_table,
unsigned long long max_pa)
{
+ uint64_t mair, ttbr, tcr;
+
+ /* Set attributes in the right indices of the MAIR. */
+ mair = MAIR_ATTR_SET(ATTR_DEVICE, ATTR_DEVICE_INDEX);
+ mair |= MAIR_ATTR_SET(ATTR_IWBWA_OWBWA_NTR, ATTR_IWBWA_OWBWA_NTR_INDEX);
+ mair |= MAIR_ATTR_SET(ATTR_NON_CACHEABLE, ATTR_NON_CACHEABLE_INDEX);
+
+ ttbr = (uint64_t) base_table;
+
+ /*
+ * Set TCR bits as well.
+ */
+
+ /*
+ * Limit the input address ranges and memory region sizes translated
+ * using TTBR0 to the given virtual address space size.
+ */
+ tcr = 64 - __builtin_ctzl(PLAT_VIRT_ADDR_SPACE_SIZE);
+
+ /*
+ * Set the cacheability and shareability attributes for memory
+ * associated with translation table walks.
+ */
+ if (flags & XLAT_TABLE_NC) {
+ /* Inner & outer non-cacheable non-shareable. */
+ tcr |= TCR_SH_NON_SHAREABLE |
+ TCR_RGN_OUTER_NC | TCR_RGN_INNER_NC;
+ } else {
+ /* Inner & outer WBWA & shareable. */
+ tcr |= TCR_SH_INNER_SHAREABLE |
+ TCR_RGN_OUTER_WBA | TCR_RGN_INNER_WBA;
+ }
+
/*
* It is safer to restrict the max physical address accessible by the
* hardware as much as possible.
*/
- tcr_ps_bits = calc_physical_addr_size_bits(max_pa);
+ unsigned long long tcr_ps_bits = calc_physical_addr_size_bits(max_pa);
#if IMAGE_EL == 1
assert(IS_IN_EL(1));
- enable_mmu_internal_el1(flags, base_table);
+ tcr |= tcr_ps_bits << TCR_EL1_IPS_SHIFT;
+ enable_mmu_internal_el1(flags, mair, tcr, ttbr);
#elif IMAGE_EL == 3
assert(IS_IN_EL(3));
- enable_mmu_internal_el3(flags, base_table);
+ tcr |= TCR_EL3_RES1 | (tcr_ps_bits << TCR_EL3_PS_SHIFT);
+ enable_mmu_internal_el3(flags, mair, tcr, ttbr);
#endif
}