diff options
author | Antonio Nino Diaz <antonio.ninodiaz@arm.com> | 2017-10-04 16:52:15 +0100 |
---|---|---|
committer | Antonio Nino Diaz <antonio.ninodiaz@arm.com> | 2017-10-05 14:32:12 +0100 |
commit | 609c91917f95e5c2c0dcccbfbea6ff32539bf738 (patch) | |
tree | 6ac537dd481d17911bf6278a8273272a14f8adba /lib/xlat_tables_v2 | |
parent | b4ae615bd734104cfed5d2534b4c14278415057e (diff) |
xlat: Add support for EL0 and EL1 mappings
This patch introduces the ability of the xlat tables library to manage
EL0 and EL1 mappings from a higher exception level.
Attributes MT_USER and MT_PRIVILEGED have been added to allow the user
specify the target EL in the translation regime EL1&0.
REGISTER_XLAT_CONTEXT2 macro is introduced to allow creating a
xlat_ctx_t that targets a given translation regime (EL1&0 or EL3).
A new member is added to xlat_ctx_t to represent the translation regime
the xlat_ctx_t manages. The execute_never mask member is removed as it
is computed from existing information.
Change-Id: I95e14abc3371d7a6d6a358cc54c688aa9975c110
Co-authored-by: Douglas Raillard <douglas.raillard@arm.com>
Co-authored-by: Sandrine Bailleux <sandrine.bailleux@arm.com>
Co-authored-by: Antonio Nino Diaz <antonio.ninodiaz@arm.com>
Signed-off-by: Antonio Nino Diaz <antonio.ninodiaz@arm.com>
Diffstat (limited to 'lib/xlat_tables_v2')
-rw-r--r-- | lib/xlat_tables_v2/aarch32/xlat_tables_arch.c | 7 | ||||
-rw-r--r-- | lib/xlat_tables_v2/aarch32/xlat_tables_arch_private.h | 22 | ||||
-rw-r--r-- | lib/xlat_tables_v2/aarch64/xlat_tables_arch.c | 34 | ||||
-rw-r--r-- | lib/xlat_tables_v2/aarch64/xlat_tables_arch_private.h | 28 | ||||
-rw-r--r-- | lib/xlat_tables_v2/xlat_tables.mk | 2 | ||||
-rw-r--r-- | lib/xlat_tables_v2/xlat_tables_internal.c | 135 | ||||
-rw-r--r-- | lib/xlat_tables_v2/xlat_tables_private.h | 14 |
7 files changed, 171 insertions, 71 deletions
diff --git a/lib/xlat_tables_v2/aarch32/xlat_tables_arch.c b/lib/xlat_tables_v2/aarch32/xlat_tables_arch.c index 30ad91e1..cbc86850 100644 --- a/lib/xlat_tables_v2/aarch32/xlat_tables_arch.c +++ b/lib/xlat_tables_v2/aarch32/xlat_tables_arch.c @@ -22,7 +22,7 @@ unsigned long long xlat_arch_get_max_supported_pa(void) } #endif /* ENABLE_ASSERTIONS*/ -int is_mmu_enabled(void) +int is_mmu_enabled_ctx(const xlat_ctx_t *ctx __unused) { return (read_sctlr() & SCTLR_M_BIT) != 0; } @@ -88,11 +88,6 @@ int xlat_arch_current_el(void) return 3; } -uint64_t xlat_arch_get_xn_desc(int el __unused) -{ - return UPPER_ATTRS(XN); -} - /******************************************************************************* * Function for enabling the MMU in Secure PL1, assuming that the page tables * have already been created. diff --git a/lib/xlat_tables_v2/aarch32/xlat_tables_arch_private.h b/lib/xlat_tables_v2/aarch32/xlat_tables_arch_private.h new file mode 100644 index 00000000..509395d8 --- /dev/null +++ b/lib/xlat_tables_v2/aarch32/xlat_tables_arch_private.h @@ -0,0 +1,22 @@ +/* + * Copyright (c) 2017, ARM Limited and Contributors. All rights reserved. + * + * SPDX-License-Identifier: BSD-3-Clause + */ + +#ifndef __XLAT_TABLES_ARCH_PRIVATE_H__ +#define __XLAT_TABLES_ARCH_PRIVATE_H__ + +#include <xlat_tables_defs.h> +#include <xlat_tables_v2.h> + +/* + * Return the execute-never mask that will prevent instruction fetch at the + * given translation regime. + */ +static inline uint64_t xlat_arch_regime_get_xn_desc(xlat_regime_t regime __unused) +{ + return UPPER_ATTRS(XN); +} + +#endif /* __XLAT_TABLES_ARCH_PRIVATE_H__ */ diff --git a/lib/xlat_tables_v2/aarch64/xlat_tables_arch.c b/lib/xlat_tables_v2/aarch64/xlat_tables_arch.c index 06bd4978..eda38d34 100644 --- a/lib/xlat_tables_v2/aarch64/xlat_tables_arch.c +++ b/lib/xlat_tables_v2/aarch64/xlat_tables_arch.c @@ -16,12 +16,6 @@ #include <xlat_tables_v2.h> #include "../xlat_tables_private.h" -#if defined(IMAGE_BL1) || defined(IMAGE_BL31) -# define IMAGE_EL 3 -#else -# define IMAGE_EL 1 -#endif - static unsigned long long calc_physical_addr_size_bits( unsigned long long max_addr) { @@ -70,17 +64,19 @@ unsigned long long xlat_arch_get_max_supported_pa(void) } #endif /* ENABLE_ASSERTIONS*/ -int is_mmu_enabled(void) +int is_mmu_enabled_ctx(const xlat_ctx_t *ctx) { -#if IMAGE_EL == 1 - assert(IS_IN_EL(1)); - return (read_sctlr_el1() & SCTLR_M_BIT) != 0; -#elif IMAGE_EL == 3 - assert(IS_IN_EL(3)); - return (read_sctlr_el3() & SCTLR_M_BIT) != 0; -#endif + if (ctx->xlat_regime == EL1_EL0_REGIME) { + assert(xlat_arch_current_el() >= 1); + return (read_sctlr_el1() & SCTLR_M_BIT) != 0; + } else { + assert(ctx->xlat_regime == EL3_REGIME); + assert(xlat_arch_current_el() >= 3); + return (read_sctlr_el3() & SCTLR_M_BIT) != 0; + } } + void xlat_arch_tlbi_va(uintptr_t va) { #if IMAGE_EL == 1 @@ -149,16 +145,6 @@ int xlat_arch_current_el(void) return el; } -uint64_t xlat_arch_get_xn_desc(int el) -{ - if (el == 3) { - return UPPER_ATTRS(XN); - } else { - assert(el == 1); - return UPPER_ATTRS(PXN); - } -} - /******************************************************************************* * Macro generating the code for the function enabling the MMU in the given * exception level, assuming that the pagetables have already been created. diff --git a/lib/xlat_tables_v2/aarch64/xlat_tables_arch_private.h b/lib/xlat_tables_v2/aarch64/xlat_tables_arch_private.h new file mode 100644 index 00000000..d201590a --- /dev/null +++ b/lib/xlat_tables_v2/aarch64/xlat_tables_arch_private.h @@ -0,0 +1,28 @@ +/* + * Copyright (c) 2017, ARM Limited and Contributors. All rights reserved. + * + * SPDX-License-Identifier: BSD-3-Clause + */ + +#ifndef __XLAT_TABLES_ARCH_PRIVATE_H__ +#define __XLAT_TABLES_ARCH_PRIVATE_H__ + +#include <assert.h> +#include <xlat_tables_defs.h> +#include <xlat_tables_v2.h> + +/* + * Return the execute-never mask that will prevent instruction fetch at all ELs + * that are part of the given translation regime. + */ +static inline uint64_t xlat_arch_regime_get_xn_desc(xlat_regime_t regime) +{ + if (regime == EL1_EL0_REGIME) { + return UPPER_ATTRS(UXN) | UPPER_ATTRS(PXN); + } else { + assert(regime == EL3_REGIME); + return UPPER_ATTRS(XN); + } +} + +#endif /* __XLAT_TABLES_ARCH_PRIVATE_H__ */ diff --git a/lib/xlat_tables_v2/xlat_tables.mk b/lib/xlat_tables_v2/xlat_tables.mk index b94ce5d0..06dd844a 100644 --- a/lib/xlat_tables_v2/xlat_tables.mk +++ b/lib/xlat_tables_v2/xlat_tables.mk @@ -7,3 +7,5 @@ XLAT_TABLES_LIB_SRCS := $(addprefix lib/xlat_tables_v2/, \ ${ARCH}/xlat_tables_arch.c \ xlat_tables_internal.c) + +INCLUDES += -Ilib/xlat_tables_v2/${ARCH} diff --git a/lib/xlat_tables_v2/xlat_tables_internal.c b/lib/xlat_tables_v2/xlat_tables_internal.c index feca964b..9faeb7ef 100644 --- a/lib/xlat_tables_v2/xlat_tables_internal.c +++ b/lib/xlat_tables_v2/xlat_tables_internal.c @@ -14,7 +14,7 @@ #include <string.h> #include <types.h> #include <utils.h> -#include <xlat_tables_arch.h> +#include <xlat_tables_arch_private.h> #include <xlat_tables_defs.h> #include <xlat_tables_v2.h> @@ -112,9 +112,11 @@ static uint64_t *xlat_table_get_empty(xlat_ctx_t *ctx) #endif /* PLAT_XLAT_TABLES_DYNAMIC */ -/* Returns a block/page table descriptor for the given level and attributes. */ -static uint64_t xlat_desc(mmap_attr_t attr, unsigned long long addr_pa, - int level, uint64_t execute_never_mask) +/* + * Returns a block/page table descriptor for the given level and attributes. + */ +uint64_t xlat_desc(const xlat_ctx_t *ctx, mmap_attr_t attr, + unsigned long long addr_pa, int level) { uint64_t desc; int mem_type; @@ -133,9 +135,28 @@ static uint64_t xlat_desc(mmap_attr_t attr, unsigned long long addr_pa, * Deduce other fields of the descriptor based on the MT_NS and MT_RW * memory region attributes. */ + desc |= LOWER_ATTRS(ACCESS_FLAG); + desc |= (attr & MT_NS) ? LOWER_ATTRS(NS) : 0; desc |= (attr & MT_RW) ? LOWER_ATTRS(AP_RW) : LOWER_ATTRS(AP_RO); - desc |= LOWER_ATTRS(ACCESS_FLAG); + + /* + * Do not allow unprivileged access when the mapping is for a privileged + * EL. For translation regimes that do not have mappings for access for + * lower exception levels, set AP[2] to AP_NO_ACCESS_UNPRIVILEGED. + */ + if (ctx->xlat_regime == EL1_EL0_REGIME) { + if (attr & MT_USER) { + /* EL0 mapping requested, so we give User access */ + desc |= LOWER_ATTRS(AP_ACCESS_UNPRIVILEGED); + } else { + /* EL1 mapping requested, no User access granted */ + desc |= LOWER_ATTRS(AP_NO_ACCESS_UNPRIVILEGED); + } + } else { + assert(ctx->xlat_regime == EL3_REGIME); + desc |= LOWER_ATTRS(AP_NO_ACCESS_UNPRIVILEGED); + } /* * Deduce shareability domain and executability of the memory region @@ -156,7 +177,7 @@ static uint64_t xlat_desc(mmap_attr_t attr, unsigned long long addr_pa, * fetch, which could be an issue if this memory region * corresponds to a read-sensitive peripheral. */ - desc |= execute_never_mask; + desc |= xlat_arch_regime_get_xn_desc(ctx->xlat_regime); } else { /* Normal memory */ /* @@ -171,10 +192,13 @@ static uint64_t xlat_desc(mmap_attr_t attr, unsigned long long addr_pa, * translation table. * * For read-only memory, rely on the MT_EXECUTE/MT_EXECUTE_NEVER - * attribute to figure out the value of the XN bit. + * attribute to figure out the value of the XN bit. The actual + * XN bit(s) to set in the descriptor depends on the context's + * translation regime and the policy applied in + * xlat_arch_regime_get_xn_desc(). */ if ((attr & MT_RW) || (attr & MT_EXECUTE_NEVER)) { - desc |= execute_never_mask; + desc |= xlat_arch_regime_get_xn_desc(ctx->xlat_regime); } if (mem_type == MT_MEMORY) { @@ -314,7 +338,7 @@ static void xlat_tables_unmap_region(xlat_ctx_t *ctx, mmap_region_t *mm, if (action == ACTION_WRITE_BLOCK_ENTRY) { table_base[table_idx] = INVALID_DESC; - xlat_arch_tlbi_va(table_idx_va); + xlat_arch_tlbi_va_regime(table_idx_va, ctx->xlat_regime); } else if (action == ACTION_RECURSE_INTO_TABLE) { @@ -330,7 +354,8 @@ static void xlat_tables_unmap_region(xlat_ctx_t *ctx, mmap_region_t *mm, */ if (xlat_table_is_empty(ctx, subtable)) { table_base[table_idx] = INVALID_DESC; - xlat_arch_tlbi_va(table_idx_va); + xlat_arch_tlbi_va_regime(table_idx_va, + ctx->xlat_regime); } } else { @@ -536,8 +561,7 @@ static uintptr_t xlat_tables_map_region(xlat_ctx_t *ctx, mmap_region_t *mm, if (action == ACTION_WRITE_BLOCK_ENTRY) { table_base[table_idx] = - xlat_desc(mm->attr, table_idx_pa, level, - ctx->execute_never_mask); + xlat_desc(ctx, mm->attr, table_idx_pa, level); } else if (action == ACTION_CREATE_NEW_TABLE) { @@ -882,9 +906,8 @@ int mmap_add_dynamic_region_ctx(xlat_ctx_t *ctx, mmap_region_t *mm) .size = end_va - mm->base_va, .attr = 0 }; - xlat_tables_unmap_region(ctx, - &unmap_mm, 0, ctx->base_table, - ctx->base_table_entries, ctx->base_level); + xlat_tables_unmap_region(ctx, &unmap_mm, 0, ctx->base_table, + ctx->base_table_entries, ctx->base_level); return -ENOMEM; } @@ -999,9 +1022,10 @@ int mmap_remove_dynamic_region(uintptr_t base_va, size_t size) #if LOG_LEVEL >= LOG_LEVEL_VERBOSE /* Print the attributes of the specified block descriptor. */ -static void xlat_desc_print(uint64_t desc, uint64_t execute_never_mask) +static void xlat_desc_print(xlat_ctx_t *ctx, uint64_t desc) { int mem_type_index = ATTR_INDEX_GET(desc); + xlat_regime_t xlat_regime = ctx->xlat_regime; if (mem_type_index == ATTR_IWBWA_OWBWA_NTR_INDEX) { tf_printf("MEM"); @@ -1012,9 +1036,49 @@ static void xlat_desc_print(uint64_t desc, uint64_t execute_never_mask) tf_printf("DEV"); } - tf_printf(LOWER_ATTRS(AP_RO) & desc ? "-RO" : "-RW"); + const char *priv_str = "(PRIV)"; + const char *user_str = "(USER)"; + + /* + * Showing Privileged vs Unprivileged only makes sense for EL1&0 + * mappings + */ + const char *ro_str = "-RO"; + const char *rw_str = "-RW"; + const char *no_access_str = "-NOACCESS"; + + if (xlat_regime == EL3_REGIME) { + /* For EL3, the AP[2] bit is all what matters */ + tf_printf((desc & LOWER_ATTRS(AP_RO)) ? ro_str : rw_str); + } else { + const char *ap_str = (desc & LOWER_ATTRS(AP_RO)) ? ro_str : rw_str; + tf_printf(ap_str); + tf_printf(priv_str); + /* + * EL0 can only have the same permissions as EL1 or no + * permissions at all. + */ + tf_printf((desc & LOWER_ATTRS(AP_ACCESS_UNPRIVILEGED)) + ? ap_str : no_access_str); + tf_printf(user_str); + } + + const char *xn_str = "-XN"; + const char *exec_str = "-EXEC"; + + if (xlat_regime == EL3_REGIME) { + /* For EL3, the XN bit is all what matters */ + tf_printf(LOWER_ATTRS(XN) & desc ? xn_str : exec_str); + } else { + /* For EL0 and EL1, we need to know who has which rights */ + tf_printf(LOWER_ATTRS(PXN) & desc ? xn_str : exec_str); + tf_printf(priv_str); + + tf_printf(LOWER_ATTRS(UXN) & desc ? xn_str : exec_str); + tf_printf(user_str); + } + tf_printf(LOWER_ATTRS(NS) & desc ? "-NS" : "-S"); - tf_printf(execute_never_mask & desc ? "-XN" : "-EXEC"); } static const char * const level_spacers[] = { @@ -1031,9 +1095,10 @@ static const char *invalid_descriptors_ommited = * Recursive function that reads the translation tables passed as an argument * and prints their status. */ -static void xlat_tables_print_internal(const uintptr_t table_base_va, +static void xlat_tables_print_internal(xlat_ctx_t *ctx, + const uintptr_t table_base_va, uint64_t *const table_base, const int table_entries, - const unsigned int level, const uint64_t execute_never_mask) + const unsigned int level) { assert(level <= XLAT_TABLE_LEVEL_MAX); @@ -1092,17 +1157,16 @@ static void xlat_tables_print_internal(const uintptr_t table_base_va, uintptr_t addr_inner = desc & TABLE_ADDR_MASK; - xlat_tables_print_internal(table_idx_va, + xlat_tables_print_internal(ctx, table_idx_va, (uint64_t *)addr_inner, - XLAT_TABLE_ENTRIES, level+1, - execute_never_mask); + XLAT_TABLE_ENTRIES, level + 1); } else { tf_printf("%sVA:%p PA:0x%llx size:0x%zx ", level_spacers[level], (void *)table_idx_va, (unsigned long long)(desc & TABLE_ADDR_MASK), level_size); - xlat_desc_print(desc, execute_never_mask); + xlat_desc_print(ctx, desc); tf_printf("\n"); } } @@ -1122,7 +1186,15 @@ static void xlat_tables_print_internal(const uintptr_t table_base_va, void xlat_tables_print(xlat_ctx_t *ctx) { #if LOG_LEVEL >= LOG_LEVEL_VERBOSE + const char *xlat_regime_str; + if (ctx->xlat_regime == EL1_EL0_REGIME) { + xlat_regime_str = "1&0"; + } else { + assert(ctx->xlat_regime == EL3_REGIME); + xlat_regime_str = "3"; + } VERBOSE("Translation tables state:\n"); + VERBOSE(" Xlat regime: EL%s\n", xlat_regime_str); VERBOSE(" Max allowed PA: 0x%llx\n", ctx->pa_max_address); VERBOSE(" Max allowed VA: %p\n", (void *) ctx->va_max_address); VERBOSE(" Max mapped PA: 0x%llx\n", ctx->max_pa); @@ -1146,22 +1218,21 @@ void xlat_tables_print(xlat_ctx_t *ctx) used_page_tables, ctx->tables_num, ctx->tables_num - used_page_tables); - xlat_tables_print_internal(0, ctx->base_table, ctx->base_table_entries, - ctx->base_level, ctx->execute_never_mask); + xlat_tables_print_internal(ctx, 0, ctx->base_table, + ctx->base_table_entries, ctx->base_level); #endif /* LOG_LEVEL >= LOG_LEVEL_VERBOSE */ } void init_xlat_tables_ctx(xlat_ctx_t *ctx) { - mmap_region_t *mm = ctx->mmap; - - assert(!is_mmu_enabled()); + assert(ctx != NULL); assert(!ctx->initialized); + assert(ctx->xlat_regime == EL3_REGIME || ctx->xlat_regime == EL1_EL0_REGIME); + assert(!is_mmu_enabled_ctx(ctx)); - print_mmap(mm); + mmap_region_t *mm = ctx->mmap; - ctx->execute_never_mask = - xlat_arch_get_xn_desc(xlat_arch_current_el()); + print_mmap(mm); /* All tables must be zeroed before mapping any region. */ diff --git a/lib/xlat_tables_v2/xlat_tables_private.h b/lib/xlat_tables_v2/xlat_tables_private.h index 2730ab6c..79efbebb 100644 --- a/lib/xlat_tables_v2/xlat_tables_private.h +++ b/lib/xlat_tables_v2/xlat_tables_private.h @@ -76,13 +76,6 @@ void xlat_tables_print(xlat_ctx_t *ctx); int xlat_arch_current_el(void); /* - * Returns the bit mask that has to be ORed to the rest of a translation table - * descriptor so that execution of code is prohibited at the given Exception - * Level. - */ -uint64_t xlat_arch_get_xn_desc(int el); - -/* * Return the maximum physical address supported by the hardware. * This value depends on the execution state (AArch32/AArch64). */ @@ -92,7 +85,10 @@ unsigned long long xlat_arch_get_max_supported_pa(void); void enable_mmu_arch(unsigned int flags, uint64_t *base_table, unsigned long long pa, uintptr_t max_va); -/* Return 1 if the MMU of this Exception Level is enabled, 0 otherwise. */ -int is_mmu_enabled(void); +/* + * Return 1 if the MMU of the translation regime managed by the given xlat_ctx_t + * is enabled, 0 otherwise. + */ +int is_mmu_enabled_ctx(const xlat_ctx_t *ctx); #endif /* __XLAT_TABLES_PRIVATE_H__ */ |