From 0350bc6d05f05a3007aead7138297c9f4aef1c5a Mon Sep 17 00:00:00 2001 From: Sandrine Bailleux Date: Fri, 26 May 2017 15:47:08 +0100 Subject: [PATCH 01/11] xlat lib v2: Print some debug statistics This patch adds some debug prints to display some statistics about page tables usage. They are printed only if the LOG_LEVEL is at least 50 (i.e. VERBOSE). Sample output for BL1: VERBOSE: Translation tables state: VERBOSE: Max allowed PA: 0xffffffff VERBOSE: Max allowed VA: 0xffffffff VERBOSE: Max mapped PA: 0x7fffffff VERBOSE: Max mapped VA: 0x7fffffff VERBOSE: Initial lookup level: 1 VERBOSE: Entries @initial lookup level: 4 VERBOSE: Used 4 sub-tables out of 5 (spare: 1) Change-Id: If38956902e9616cdcd6065ecd140fe21482597ea Signed-off-by: Sandrine Bailleux --- lib/xlat_tables_v2/xlat_tables_internal.c | 24 +++++++++++++++++++++++ 1 file changed, 24 insertions(+) diff --git a/lib/xlat_tables_v2/xlat_tables_internal.c b/lib/xlat_tables_v2/xlat_tables_internal.c index f60d78c10..91e02d3d1 100644 --- a/lib/xlat_tables_v2/xlat_tables_internal.c +++ b/lib/xlat_tables_v2/xlat_tables_internal.c @@ -1042,6 +1042,30 @@ 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 + VERBOSE("Translation tables state:\n"); + 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); + VERBOSE(" Max mapped VA: %p\n", (void *) ctx->max_va); + + VERBOSE(" Initial lookup level: %i\n", ctx->base_level); + VERBOSE(" Entries @initial lookup level: %i\n", + ctx->base_table_entries); + + int used_page_tables; +#if PLAT_XLAT_TABLES_DYNAMIC + used_page_tables = 0; + for (int i = 0; i < ctx->tables_num; ++i) { + if (ctx->tables_mapped_regions[i] != 0) + ++used_page_tables; + } +#else + used_page_tables = ctx->next_table; +#endif + VERBOSE(" Used %i sub-tables out of %i (spare: %i)\n", + 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); #endif /* LOG_LEVEL >= LOG_LEVEL_VERBOSE */ From 284c3d67090586b20c7eed2955c05094dccff2e1 Mon Sep 17 00:00:00 2001 From: Sandrine Bailleux Date: Fri, 26 May 2017 15:48:10 +0100 Subject: [PATCH 02/11] FVP: Do not map DEVICE2 memory range when TBB is disabled The DEVICE2 memory range is needed to access the Root of Trust Public Key registers. This is not needed when Trusted Board Boot is disabled so it's safer to not map it in this case. This also saves one level-2 page table in each of BL1 and BL2 images. Also add some comments. Change-Id: I67456b44f3fd5e145f6510a8499b7fdf720a7273 Signed-off-by: Sandrine Bailleux --- plat/arm/board/common/board_css_common.c | 1 + plat/arm/board/fvp/fvp_common.c | 13 +++++++++++-- 2 files changed, 12 insertions(+), 2 deletions(-) diff --git a/plat/arm/board/common/board_css_common.c b/plat/arm/board/common/board_css_common.c index 42f754e25..f6a554f32 100644 --- a/plat/arm/board/common/board_css_common.c +++ b/plat/arm/board/common/board_css_common.c @@ -19,6 +19,7 @@ const mmap_region_t plat_arm_mmap[] = { CSS_MAP_DEVICE, SOC_CSS_MAP_DEVICE, #if TRUSTED_BOARD_BOOT + /* Map DRAM to authenticate NS_BL2U image. */ ARM_MAP_NS_DRAM1, #endif {0} diff --git a/plat/arm/board/fvp/fvp_common.c b/plat/arm/board/fvp/fvp_common.c index eb37f113a..2f5d7fcf5 100644 --- a/plat/arm/board/fvp/fvp_common.c +++ b/plat/arm/board/fvp/fvp_common.c @@ -36,6 +36,10 @@ arm_config_t arm_config; DEVICE1_SIZE, \ MT_DEVICE | MT_RW | MT_SECURE) +/* + * Need to be mapped with write permissions in order to set a new non-volatile + * counter value. + */ #define MAP_DEVICE2 MAP_REGION_FLAT(DEVICE2_BASE, \ DEVICE2_SIZE, \ MT_DEVICE | MT_RW | MT_SECURE) @@ -56,8 +60,10 @@ const mmap_region_t plat_arm_mmap[] = { V2M_MAP_IOFPGA, MAP_DEVICE0, MAP_DEVICE1, - MAP_DEVICE2, #if TRUSTED_BOARD_BOOT + /* To access the Root of Trust Public Key registers. */ + MAP_DEVICE2, + /* Map DRAM to authenticate NS_BL2U image. */ ARM_MAP_NS_DRAM1, #endif {0} @@ -70,9 +76,12 @@ const mmap_region_t plat_arm_mmap[] = { V2M_MAP_IOFPGA, MAP_DEVICE0, MAP_DEVICE1, - MAP_DEVICE2, ARM_MAP_NS_DRAM1, ARM_MAP_TSP_SEC_MEM, +#if TRUSTED_BOARD_BOOT + /* To access the Root of Trust Public Key registers. */ + MAP_DEVICE2, +#endif #if ARM_BL31_IN_DRAM ARM_MAP_BL31_SEC_DRAM, #endif From 8933c34bbc8f0afb32030a4b3793f2e4cd6afbff Mon Sep 17 00:00:00 2001 From: Sandrine Bailleux Date: Fri, 19 May 2017 09:59:37 +0100 Subject: [PATCH 03/11] xlat lib: Reorganize architectural defs Move the header files that provide translation tables architectural definitions from the library v2 source files to the library include directory. This allows to share these definitions between both versions (v1 and v2) of the library. Create a new header file that includes the AArch32 or AArch64 definitions based on the AARCH32 build flag, so that the library user doesn't have to worry about handling it on their side. Also repurpose some of the definitions the header files provide to concentrate on the things that differ between AArch32 and AArch64. As a result they now contain the following information: - the first table level that allows block descriptors; - the architectural limits of the virtual address space; - the initial lookup level to cover the entire address space. Additionally, move the XLAT_TABLE_LEVEL_MIN macro from xlat_tables_defs.h to the AArch32/AArch64 architectural definitions. This new organisation eliminates duplicated information in the AArch32 and AArch64 versions. It also decouples these architectural files from any platform-specific information. Previously, they were dependent on the address space size, which is platform-specific. Finally, for the v2 of the library, move the compatibility code for ADDR_SPACE_SIZE into a C file as it is not needed outside of this file. For v1, this code hasn't been changed and stays in a header file because it's needed by several files. Change-Id: If746c684acd80eebf918abd3ab6e8481d004ac68 Signed-off-by: Sandrine Bailleux --- .../xlat_tables/aarch32/xlat_tables_aarch32.h | 72 ++++++++++++++++ .../xlat_tables/aarch64/xlat_tables_aarch64.h | 77 +++++++++++++++++ include/lib/xlat_tables/xlat_tables_arch.h | 43 ++++++++++ include/lib/xlat_tables/xlat_tables_defs.h | 6 -- lib/xlat_tables/aarch32/xlat_tables.c | 49 ++--------- lib/xlat_tables/aarch64/xlat_tables.c | 57 ++----------- lib/xlat_tables/xlat_tables_private.h | 39 ++------- lib/xlat_tables_v2/aarch32/xlat_tables_arch.h | 72 ---------------- lib/xlat_tables_v2/aarch64/xlat_tables_arch.h | 85 ------------------- lib/xlat_tables_v2/xlat_tables_common.c | 37 ++++++-- lib/xlat_tables_v2/xlat_tables_internal.c | 8 +- lib/xlat_tables_v2/xlat_tables_private.h | 26 +----- 12 files changed, 244 insertions(+), 327 deletions(-) create mode 100644 include/lib/xlat_tables/aarch32/xlat_tables_aarch32.h create mode 100644 include/lib/xlat_tables/aarch64/xlat_tables_aarch64.h create mode 100644 include/lib/xlat_tables/xlat_tables_arch.h delete mode 100644 lib/xlat_tables_v2/aarch32/xlat_tables_arch.h delete mode 100644 lib/xlat_tables_v2/aarch64/xlat_tables_arch.h diff --git a/include/lib/xlat_tables/aarch32/xlat_tables_aarch32.h b/include/lib/xlat_tables/aarch32/xlat_tables_aarch32.h new file mode 100644 index 000000000..28be8e3d6 --- /dev/null +++ b/include/lib/xlat_tables/aarch32/xlat_tables_aarch32.h @@ -0,0 +1,72 @@ +/* + * Copyright (c) 2017, ARM Limited and Contributors. All rights reserved. + * + * SPDX-License-Identifier: BSD-3-Clause + */ + +#ifndef __XLAT_TABLES_AARCH32_H__ +#define __XLAT_TABLES_AARCH32_H__ + +#include +#include +#include + +#if !defined(PAGE_SIZE) +#error "PAGE_SIZE is not defined." +#endif + +/* + * In AArch32 state, the MMU only supports 4KB page granularity, which means + * that the first translation table level is either 1 or 2. Both of them are + * allowed to have block and table descriptors. See section G4.5.6 of the + * ARMv8-A Architecture Reference Manual (DDI 0487A.k) for more information. + * + * The define below specifies the first table level that allows block + * descriptors. + */ +#if PAGE_SIZE != (4 * 1024) +#error "Invalid granule size. AArch32 supports 4KB pages only." +#endif + +#define MIN_LVL_BLOCK_DESC 1 + +#define XLAT_TABLE_LEVEL_MIN U(1) + +/* + * Define the architectural limits of the virtual address space in AArch32 + * state. + * + * TTBCR.TxSZ is calculated as 32 minus the width of said address space. The + * value of TTBCR.TxSZ must be in the range 0 to 7 [1], which means that the + * virtual address space width must be in the range 32 to 25 bits. + * + * [1] See the ARMv8-A Architecture Reference Manual (DDI 0487A.j) for more + * information, Section G4.6.5 + */ +#define MIN_VIRT_ADDR_SPACE_SIZE (1 << (32 - TTBCR_TxSZ_MAX)) +#define MAX_VIRT_ADDR_SPACE_SIZE (ULL(1) << (32 - TTBCR_TxSZ_MIN)) + +/* + * Here we calculate the initial lookup level from the value of the given + * virtual address space size. For a 4 KB page size, + * - level 1 supports virtual address spaces of widths 32 to 31 bits; + * - level 2 from 30 to 25. + * + * Wider or narrower address spaces are not supported. As a result, level 3 + * cannot be used as the initial lookup level with 4 KB granularity. + * See the ARMv8-A Architecture Reference Manual (DDI 0487A.j) for more + * information, Section G4.6.5 + * + * For example, for a 31-bit address space (i.e. virt_addr_space_size == + * 1 << 31), TTBCR.TxSZ will be programmed to (32 - 31) = 1. According to Table + * G4-5 in the ARM ARM, the initial lookup level for an address space like that + * is 1. + * + * Note that this macro assumes that the given virtual address space size is + * valid. Therefore, the caller is expected to check it is the case using the + * CHECK_VIRT_ADDR_SPACE_SIZE() macro first. + */ +#define GET_XLAT_TABLE_LEVEL_BASE(virt_addr_space_size) \ + (((virt_addr_space_size) > (1 << L1_XLAT_ADDRESS_SHIFT)) ? 1 : 2) + +#endif /* __XLAT_TABLES_AARCH32_H__ */ diff --git a/include/lib/xlat_tables/aarch64/xlat_tables_aarch64.h b/include/lib/xlat_tables/aarch64/xlat_tables_aarch64.h new file mode 100644 index 000000000..9cad0353f --- /dev/null +++ b/include/lib/xlat_tables/aarch64/xlat_tables_aarch64.h @@ -0,0 +1,77 @@ +/* + * Copyright (c) 2017, ARM Limited and Contributors. All rights reserved. + * + * SPDX-License-Identifier: BSD-3-Clause + */ + +#ifndef __XLAT_TABLES_AARCH64_H__ +#define __XLAT_TABLES_AARCH64_H__ + +#include +#include +#include + +#if !defined(PAGE_SIZE) +#error "PAGE_SIZE is not defined." +#endif + +/* + * In AArch64 state, the MMU may support 4 KB, 16 KB and 64 KB page + * granularity. For 4KB granularity, a level 0 table descriptor doesn't support + * block translation. For 16KB, the same thing happens to levels 0 and 1. For + * 64KB, same for level 1. See section D4.3.1 of the ARMv8-A Architecture + * Reference Manual (DDI 0487A.k) for more information. + * + * The define below specifies the first table level that allows block + * descriptors. + */ +#if PAGE_SIZE == (4 * 1024) +# define MIN_LVL_BLOCK_DESC 1 +#elif PAGE_SIZE == (16 * 1024) || PAGE_SIZE == (64 * 1024) +# define MIN_LVL_BLOCK_DESC 2 +#endif + +#define XLAT_TABLE_LEVEL_MIN U(0) + +/* + * Define the architectural limits of the virtual address space in AArch64 + * state. + * + * TCR.TxSZ is calculated as 64 minus the width of said address space. + * The value of TCR.TxSZ must be in the range 16 to 39 [1], which means that + * the virtual address space width must be in the range 48 to 25 bits. + * + * [1] See the ARMv8-A Architecture Reference Manual (DDI 0487A.j) for more + * information: + * Page 1730: 'Input address size', 'For all translation stages'. + */ +#define MIN_VIRT_ADDR_SPACE_SIZE (1 << (64 - TCR_TxSZ_MAX)) +#define MAX_VIRT_ADDR_SPACE_SIZE (ULL(1) << (64 - TCR_TxSZ_MIN)) + +/* + * Here we calculate the initial lookup level from the value of the given + * virtual address space size. For a 4 KB page size, + * - level 0 supports virtual address spaces of widths 48 to 40 bits; + * - level 1 from 39 to 31; + * - level 2 from 30 to 25. + * + * Wider or narrower address spaces are not supported. As a result, level 3 + * cannot be used as initial lookup level with 4 KB granularity. See section + * D4.2.5 in the ARMv8-A Architecture Reference Manual (DDI 0487A.j) for more + * information. + * + * For example, for a 35-bit address space (i.e. virt_addr_space_size == + * 1 << 35), TCR.TxSZ will be programmed to (64 - 35) = 29. According to Table + * D4-11 in the ARM ARM, the initial lookup level for an address space like that + * is 1. + * + * Note that this macro assumes that the given virtual address space size is + * valid. Therefore, the caller is expected to check it is the case using the + * CHECK_VIRT_ADDR_SPACE_SIZE() macro first. + */ +#define GET_XLAT_TABLE_LEVEL_BASE(virt_addr_space_size) \ + (((virt_addr_space_size) > (ULL(1) << L0_XLAT_ADDRESS_SHIFT)) \ + ? 0 \ + : (((virt_addr_space_size) > (1 << L1_XLAT_ADDRESS_SHIFT)) ? 1 : 2)) + +#endif /* __XLAT_TABLES_AARCH64_H__ */ diff --git a/include/lib/xlat_tables/xlat_tables_arch.h b/include/lib/xlat_tables/xlat_tables_arch.h new file mode 100644 index 000000000..165b161d2 --- /dev/null +++ b/include/lib/xlat_tables/xlat_tables_arch.h @@ -0,0 +1,43 @@ +/* + * Copyright (c) 2017, ARM Limited and Contributors. All rights reserved. + * + * SPDX-License-Identifier: BSD-3-Clause + */ + +#ifndef __XLAT_TABLES_ARCH_H__ +#define __XLAT_TABLES_ARCH_H__ + +#ifdef AARCH32 +#include "aarch32/xlat_tables_aarch32.h" +#else +#include "aarch64/xlat_tables_aarch64.h" +#endif + +/* + * Evaluates to 1 if the given virtual address space size is valid, or 0 if it's + * not. + * + * A valid size is one that is a power of 2 and is within the architectural + * limits. Not that these limits are different for AArch32 and AArch64. + */ +#define CHECK_VIRT_ADDR_SPACE_SIZE(size) \ + (((size) >= MIN_VIRT_ADDR_SPACE_SIZE) && \ + ((size) <= MAX_VIRT_ADDR_SPACE_SIZE) && \ + IS_POWER_OF_TWO(size)) + +/* + * Evaluates to 1 if the given physical address space size is a power of 2, + * or 0 if it's not. + */ +#define CHECK_PHY_ADDR_SPACE_SIZE(size) \ + (IS_POWER_OF_TWO(size)) + +/* + * Compute the number of entries required at the initial lookup level to address + * the whole virtual address space. + */ +#define GET_NUM_BASE_LEVEL_ENTRIES(addr_space_size) \ + ((addr_space_size) >> \ + XLAT_ADDR_SHIFT(GET_XLAT_TABLE_LEVEL_BASE(addr_space_size))) + +#endif /* __XLAT_TABLES_ARCH_H__ */ diff --git a/include/lib/xlat_tables/xlat_tables_defs.h b/include/lib/xlat_tables/xlat_tables_defs.h index 4b993a04c..779532e9e 100644 --- a/include/lib/xlat_tables/xlat_tables_defs.h +++ b/include/lib/xlat_tables/xlat_tables_defs.h @@ -59,12 +59,6 @@ #define XLAT_TABLE_SIZE_SHIFT PAGE_SIZE_SHIFT /* Size of one complete table */ #define XLAT_TABLE_SIZE (U(1) << XLAT_TABLE_SIZE_SHIFT) -#ifdef AARCH32 -#define XLAT_TABLE_LEVEL_MIN U(1) -#else -#define XLAT_TABLE_LEVEL_MIN U(0) -#endif /* AARCH32 */ - #define XLAT_TABLE_LEVEL_MAX U(3) /* Values for number of entries in each MMU translation table */ diff --git a/lib/xlat_tables/aarch32/xlat_tables.c b/lib/xlat_tables/aarch32/xlat_tables.c index 9c1562407..71db2d5f6 100644 --- a/lib/xlat_tables/aarch32/xlat_tables.c +++ b/lib/xlat_tables/aarch32/xlat_tables.c @@ -7,56 +7,17 @@ #include #include #include -#include #include #include +#include #include #include "../xlat_tables_private.h" -/* - * Each platform can define the size of the virtual address space, which is - * defined in PLAT_VIRT_ADDR_SPACE_SIZE. TTBCR.TxSZ is calculated as 32 minus - * the width of said address space. The value of TTBCR.TxSZ must be in the - * range 0 to 7 [1], which means that the virtual address space width must be - * in the range 32 to 25 bits. - * - * Here we calculate the initial lookup level from the value of - * PLAT_VIRT_ADDR_SPACE_SIZE. For a 4 KB page size, level 1 supports virtual - * address spaces of widths 32 to 31 bits, and level 2 from 30 to 25. Wider or - * narrower address spaces are not supported. As a result, level 3 cannot be - * used as initial lookup level with 4 KB granularity [1]. - * - * For example, for a 31-bit address space (i.e. PLAT_VIRT_ADDR_SPACE_SIZE == - * 1 << 31), TTBCR.TxSZ will be programmed to (32 - 31) = 1. According to Table - * G4-5 in the ARM ARM, the initial lookup level for an address space like that - * is 1. - * - * See the ARMv8-A Architecture Reference Manual (DDI 0487A.j) for more - * information: - * [1] Section G4.6.5 - */ +#define XLAT_TABLE_LEVEL_BASE \ + GET_XLAT_TABLE_LEVEL_BASE(PLAT_VIRT_ADDR_SPACE_SIZE) -#if PLAT_VIRT_ADDR_SPACE_SIZE > (1ULL << (32 - TTBCR_TxSZ_MIN)) - -# error "PLAT_VIRT_ADDR_SPACE_SIZE is too big." - -#elif PLAT_VIRT_ADDR_SPACE_SIZE > (1 << L1_XLAT_ADDRESS_SHIFT) - -# define XLAT_TABLE_LEVEL_BASE 1 -# define NUM_BASE_LEVEL_ENTRIES \ - (PLAT_VIRT_ADDR_SPACE_SIZE >> L1_XLAT_ADDRESS_SHIFT) - -#elif PLAT_VIRT_ADDR_SPACE_SIZE >= (1 << (32 - TTBCR_TxSZ_MAX)) - -# define XLAT_TABLE_LEVEL_BASE 2 -# define NUM_BASE_LEVEL_ENTRIES \ - (PLAT_VIRT_ADDR_SPACE_SIZE >> L2_XLAT_ADDRESS_SHIFT) - -#else - -# error "PLAT_VIRT_ADDR_SPACE_SIZE is too small." - -#endif +#define NUM_BASE_LEVEL_ENTRIES \ + GET_NUM_BASE_LEVEL_ENTRIES(PLAT_VIRT_ADDR_SPACE_SIZE) static uint64_t base_xlation_table[NUM_BASE_LEVEL_ENTRIES] __aligned(NUM_BASE_LEVEL_ENTRIES * sizeof(uint64_t)); diff --git a/lib/xlat_tables/aarch64/xlat_tables.c b/lib/xlat_tables/aarch64/xlat_tables.c index 309cb9bd5..4125651e9 100644 --- a/lib/xlat_tables/aarch64/xlat_tables.c +++ b/lib/xlat_tables/aarch64/xlat_tables.c @@ -8,66 +8,19 @@ #include #include #include -#include #include #include #include #include #include +#include #include "../xlat_tables_private.h" -/* - * Each platform can define the size of the virtual address space, which is - * defined in PLAT_VIRT_ADDR_SPACE_SIZE. TCR.TxSZ is calculated as 64 minus the - * width of said address space. The value of TCR.TxSZ must be in the range 16 - * to 39 [1], which means that the virtual address space width must be in the - * range 48 to 25 bits. - * - * Here we calculate the initial lookup level from the value of - * PLAT_VIRT_ADDR_SPACE_SIZE. For a 4 KB page size, level 0 supports virtual - * address spaces of widths 48 to 40 bits, level 1 from 39 to 31, and level 2 - * from 30 to 25. Wider or narrower address spaces are not supported. As a - * result, level 3 cannot be used as initial lookup level with 4 KB - * granularity. [2] - * - * For example, for a 35-bit address space (i.e. PLAT_VIRT_ADDR_SPACE_SIZE == - * 1 << 35), TCR.TxSZ will be programmed to (64 - 35) = 29. According to Table - * D4-11 in the ARM ARM, the initial lookup level for an address space like - * that is 1. - * - * See the ARMv8-A Architecture Reference Manual (DDI 0487A.j) for more - * information: - * [1] Page 1730: 'Input address size', 'For all translation stages'. - * [2] Section D4.2.5 - */ +#define XLAT_TABLE_LEVEL_BASE \ + GET_XLAT_TABLE_LEVEL_BASE(PLAT_VIRT_ADDR_SPACE_SIZE) -#if PLAT_VIRT_ADDR_SPACE_SIZE > (1ULL << (64 - TCR_TxSZ_MIN)) - -# error "PLAT_VIRT_ADDR_SPACE_SIZE is too big." - -#elif PLAT_VIRT_ADDR_SPACE_SIZE > (1ULL << L0_XLAT_ADDRESS_SHIFT) - -# define XLAT_TABLE_LEVEL_BASE 0 -# define NUM_BASE_LEVEL_ENTRIES \ - (PLAT_VIRT_ADDR_SPACE_SIZE >> L0_XLAT_ADDRESS_SHIFT) - -#elif PLAT_VIRT_ADDR_SPACE_SIZE > (1 << L1_XLAT_ADDRESS_SHIFT) - -# define XLAT_TABLE_LEVEL_BASE 1 -# define NUM_BASE_LEVEL_ENTRIES \ - (PLAT_VIRT_ADDR_SPACE_SIZE >> L1_XLAT_ADDRESS_SHIFT) - -#elif PLAT_VIRT_ADDR_SPACE_SIZE >= (1 << (64 - TCR_TxSZ_MAX)) - -# define XLAT_TABLE_LEVEL_BASE 2 -# define NUM_BASE_LEVEL_ENTRIES \ - (PLAT_VIRT_ADDR_SPACE_SIZE >> L2_XLAT_ADDRESS_SHIFT) - -#else - -# error "PLAT_VIRT_ADDR_SPACE_SIZE is too small." - -#endif +#define NUM_BASE_LEVEL_ENTRIES \ + GET_NUM_BASE_LEVEL_ENTRIES(PLAT_VIRT_ADDR_SPACE_SIZE) static uint64_t base_xlation_table[NUM_BASE_LEVEL_ENTRIES] __aligned(NUM_BASE_LEVEL_ENTRIES * sizeof(uint64_t)); diff --git a/lib/xlat_tables/xlat_tables_private.h b/lib/xlat_tables/xlat_tables_private.h index b5c3ac84c..50d6bd59c 100644 --- a/lib/xlat_tables/xlat_tables_private.h +++ b/lib/xlat_tables/xlat_tables_private.h @@ -9,7 +9,7 @@ #include #include -#include +#include /* * If the platform hasn't defined a physical and a virtual address space size @@ -28,41 +28,14 @@ # endif #endif -/* The virtual and physical address space sizes must be powers of two. */ -CASSERT(IS_POWER_OF_TWO(PLAT_VIRT_ADDR_SPACE_SIZE), +CASSERT(CHECK_VIRT_ADDR_SPACE_SIZE(PLAT_VIRT_ADDR_SPACE_SIZE), assert_valid_virt_addr_space_size); -CASSERT(IS_POWER_OF_TWO(PLAT_PHY_ADDR_SPACE_SIZE), + +CASSERT(CHECK_PHY_ADDR_SPACE_SIZE(PLAT_PHY_ADDR_SPACE_SIZE), assert_valid_phy_addr_space_size); -/* - * In AArch32 state, the MMU only supports 4KB page granularity, which means - * that the first translation table level is either 1 or 2. Both of them are - * allowed to have block and table descriptors. See section G4.5.6 of the - * ARMv8-A Architecture Reference Manual (DDI 0487A.k) for more information. - * - * In AArch64 state, the MMU may support 4 KB, 16 KB and 64 KB page - * granularity. For 4KB granularity, a level 0 table descriptor doesn't support - * block translation. For 16KB, the same thing happens to levels 0 and 1. For - * 64KB, same for level 1. See section D4.3.1 of the ARMv8-A Architecture - * Reference Manual (DDI 0487A.k) for more information. - * - * The define below specifies the first table level that allows block - * descriptors. - */ - -#ifdef AARCH32 - -# define XLAT_BLOCK_LEVEL_MIN 1 - -#else /* if AArch64 */ - -# if PAGE_SIZE == (4*1024) /* 4KB */ -# define XLAT_BLOCK_LEVEL_MIN 1 -# else /* 16KB or 64KB */ -# define XLAT_BLOCK_LEVEL_MIN 2 -# endif - -#endif /* AARCH32 */ +/* Alias to retain compatibility with the old #define name */ +#define XLAT_BLOCK_LEVEL_MIN MIN_LVL_BLOCK_DESC void print_mmap(void); diff --git a/lib/xlat_tables_v2/aarch32/xlat_tables_arch.h b/lib/xlat_tables_v2/aarch32/xlat_tables_arch.h deleted file mode 100644 index f75ab7910..000000000 --- a/lib/xlat_tables_v2/aarch32/xlat_tables_arch.h +++ /dev/null @@ -1,72 +0,0 @@ -/* - * Copyright (c) 2017, ARM Limited and Contributors. All rights reserved. - * - * SPDX-License-Identifier: BSD-3-Clause - */ - -#ifndef __XLAT_TABLES_ARCH_H__ -#define __XLAT_TABLES_ARCH_H__ - -#include -#include -#include -#include "../xlat_tables_private.h" - -/* - * In AArch32 state, the MMU only supports 4KB page granularity, which means - * that the first translation table level is either 1 or 2. Both of them are - * allowed to have block and table descriptors. See section G4.5.6 of the - * ARMv8-A Architecture Reference Manual (DDI 0487A.k) for more information. - * - * The define below specifies the first table level that allows block - * descriptors. - */ - -#define MIN_LVL_BLOCK_DESC 1 - -/* - * Each platform can define the size of the virtual address space, which is - * defined in PLAT_VIRT_ADDR_SPACE_SIZE. TTBCR.TxSZ is calculated as 32 minus - * the width of said address space. The value of TTBCR.TxSZ must be in the - * range 0 to 7 [1], which means that the virtual address space width must be - * in the range 32 to 25 bits. - * - * Here we calculate the initial lookup level from the value of - * PLAT_VIRT_ADDR_SPACE_SIZE. For a 4 KB page size, level 1 supports virtual - * address spaces of widths 32 to 31 bits, and level 2 from 30 to 25. Wider or - * narrower address spaces are not supported. As a result, level 3 cannot be - * used as initial lookup level with 4 KB granularity [1]. - * - * For example, for a 31-bit address space (i.e. PLAT_VIRT_ADDR_SPACE_SIZE == - * 1 << 31), TTBCR.TxSZ will be programmed to (32 - 31) = 1. According to Table - * G4-5 in the ARM ARM, the initial lookup level for an address space like that - * is 1. - * - * See the ARMv8-A Architecture Reference Manual (DDI 0487A.j) for more - * information: - * [1] Section G4.6.5 - */ - -#if PLAT_VIRT_ADDR_SPACE_SIZE > (1ULL << (32 - TTBCR_TxSZ_MIN)) - -# error "PLAT_VIRT_ADDR_SPACE_SIZE is too big." - -#elif PLAT_VIRT_ADDR_SPACE_SIZE > (1 << L1_XLAT_ADDRESS_SHIFT) - -# define XLAT_TABLE_LEVEL_BASE 1 -# define NUM_BASE_LEVEL_ENTRIES \ - (PLAT_VIRT_ADDR_SPACE_SIZE >> L1_XLAT_ADDRESS_SHIFT) - -#elif PLAT_VIRT_ADDR_SPACE_SIZE >= (1 << (32 - TTBCR_TxSZ_MAX)) - -# define XLAT_TABLE_LEVEL_BASE 2 -# define NUM_BASE_LEVEL_ENTRIES \ - (PLAT_VIRT_ADDR_SPACE_SIZE >> L2_XLAT_ADDRESS_SHIFT) - -#else - -# error "PLAT_VIRT_ADDR_SPACE_SIZE is too small." - -#endif - -#endif /* __XLAT_TABLES_ARCH_H__ */ diff --git a/lib/xlat_tables_v2/aarch64/xlat_tables_arch.h b/lib/xlat_tables_v2/aarch64/xlat_tables_arch.h deleted file mode 100644 index caccb7360..000000000 --- a/lib/xlat_tables_v2/aarch64/xlat_tables_arch.h +++ /dev/null @@ -1,85 +0,0 @@ -/* - * Copyright (c) 2017, ARM Limited and Contributors. All rights reserved. - * - * SPDX-License-Identifier: BSD-3-Clause - */ - -#ifndef __XLAT_TABLES_ARCH_H__ -#define __XLAT_TABLES_ARCH_H__ - -#include -#include -#include -#include "../xlat_tables_private.h" - -/* - * In AArch64 state, the MMU may support 4 KB, 16 KB and 64 KB page - * granularity. For 4KB granularity, a level 0 table descriptor doesn't support - * block translation. For 16KB, the same thing happens to levels 0 and 1. For - * 64KB, same for level 1. See section D4.3.1 of the ARMv8-A Architecture - * Reference Manual (DDI 0487A.k) for more information. - * - * The define below specifies the first table level that allows block - * descriptors. - */ - -#if PAGE_SIZE == (4*1024) /* 4KB */ -# define MIN_LVL_BLOCK_DESC 1 -#else /* 16KB or 64KB */ -# define MIN_LVL_BLOCK_DESC 2 -#endif - -/* - * Each platform can define the size of the virtual address space, which is - * defined in PLAT_VIRT_ADDR_SPACE_SIZE. TCR.TxSZ is calculated as 64 minus the - * width of said address space. The value of TCR.TxSZ must be in the range 16 - * to 39 [1], which means that the virtual address space width must be in the - * range 48 to 25 bits. - * - * Here we calculate the initial lookup level from the value of - * PLAT_VIRT_ADDR_SPACE_SIZE. For a 4 KB page size, level 0 supports virtual - * address spaces of widths 48 to 40 bits, level 1 from 39 to 31, and level 2 - * from 30 to 25. Wider or narrower address spaces are not supported. As a - * result, level 3 cannot be used as initial lookup level with 4 KB - * granularity. [2] - * - * For example, for a 35-bit address space (i.e. PLAT_VIRT_ADDR_SPACE_SIZE == - * 1 << 35), TCR.TxSZ will be programmed to (64 - 35) = 29. According to Table - * D4-11 in the ARM ARM, the initial lookup level for an address space like - * that is 1. - * - * See the ARMv8-A Architecture Reference Manual (DDI 0487A.j) for more - * information: - * [1] Page 1730: 'Input address size', 'For all translation stages'. - * [2] Section D4.2.5 - */ - -#if PLAT_VIRT_ADDR_SPACE_SIZE > (1ULL << (64 - TCR_TxSZ_MIN)) - -# error "PLAT_VIRT_ADDR_SPACE_SIZE is too big." - -#elif PLAT_VIRT_ADDR_SPACE_SIZE > (1ULL << L0_XLAT_ADDRESS_SHIFT) - -# define XLAT_TABLE_LEVEL_BASE 0 -# define NUM_BASE_LEVEL_ENTRIES \ - (PLAT_VIRT_ADDR_SPACE_SIZE >> L0_XLAT_ADDRESS_SHIFT) - -#elif PLAT_VIRT_ADDR_SPACE_SIZE > (1 << L1_XLAT_ADDRESS_SHIFT) - -# define XLAT_TABLE_LEVEL_BASE 1 -# define NUM_BASE_LEVEL_ENTRIES \ - (PLAT_VIRT_ADDR_SPACE_SIZE >> L1_XLAT_ADDRESS_SHIFT) - -#elif PLAT_VIRT_ADDR_SPACE_SIZE >= (1 << (64 - TCR_TxSZ_MAX)) - -# define XLAT_TABLE_LEVEL_BASE 2 -# define NUM_BASE_LEVEL_ENTRIES \ - (PLAT_VIRT_ADDR_SPACE_SIZE >> L2_XLAT_ADDRESS_SHIFT) - -#else - -# error "PLAT_VIRT_ADDR_SPACE_SIZE is too small." - -#endif - -#endif /* __XLAT_TABLES_ARCH_H__ */ diff --git a/lib/xlat_tables_v2/xlat_tables_common.c b/lib/xlat_tables_v2/xlat_tables_common.c index f20bf93ac..fce601785 100644 --- a/lib/xlat_tables_v2/xlat_tables_common.c +++ b/lib/xlat_tables_v2/xlat_tables_common.c @@ -15,14 +15,41 @@ #include #include #include +#include #include -#ifdef AARCH32 -# include "aarch32/xlat_tables_arch.h" -#else -# include "aarch64/xlat_tables_arch.h" -#endif + #include "xlat_tables_private.h" +/* + * Each platform can define the size of its physical and virtual address spaces. + * If the platform hasn't defined one or both of them, default to + * ADDR_SPACE_SIZE. The latter is deprecated, though. + */ +#if ERROR_DEPRECATED +# ifdef ADDR_SPACE_SIZE +# error "ADDR_SPACE_SIZE is deprecated. Use PLAT_xxx_ADDR_SPACE_SIZE instead." +# endif +#elif defined(ADDR_SPACE_SIZE) +# ifndef PLAT_PHY_ADDR_SPACE_SIZE +# define PLAT_PHY_ADDR_SPACE_SIZE ADDR_SPACE_SIZE +# endif +# ifndef PLAT_VIRT_ADDR_SPACE_SIZE +# define PLAT_VIRT_ADDR_SPACE_SIZE ADDR_SPACE_SIZE +# endif +#endif + +CASSERT(CHECK_VIRT_ADDR_SPACE_SIZE(PLAT_VIRT_ADDR_SPACE_SIZE), + assert_invalid_virtual_addr_space_size); + +CASSERT(CHECK_PHY_ADDR_SPACE_SIZE(PLAT_PHY_ADDR_SPACE_SIZE), + assert_invalid_physical_addr_space_size); + +#define NUM_BASE_LEVEL_ENTRIES \ + GET_NUM_BASE_LEVEL_ENTRIES(PLAT_VIRT_ADDR_SPACE_SIZE) + +#define XLAT_TABLE_LEVEL_BASE \ + GET_XLAT_TABLE_LEVEL_BASE(PLAT_VIRT_ADDR_SPACE_SIZE) + /* * Private variables used by the TF */ diff --git a/lib/xlat_tables_v2/xlat_tables_internal.c b/lib/xlat_tables_v2/xlat_tables_internal.c index 91e02d3d1..a3a98d197 100644 --- a/lib/xlat_tables_v2/xlat_tables_internal.c +++ b/lib/xlat_tables_v2/xlat_tables_internal.c @@ -15,12 +15,10 @@ #include #include #include +#include +#include #include -#ifdef AARCH32 -# include "aarch32/xlat_tables_arch.h" -#else -# include "aarch64/xlat_tables_arch.h" -#endif + #include "xlat_tables_private.h" #if PLAT_XLAT_TABLES_DYNAMIC diff --git a/lib/xlat_tables_v2/xlat_tables_private.h b/lib/xlat_tables_v2/xlat_tables_private.h index 83e0b6eac..83aa5b1e5 100644 --- a/lib/xlat_tables_v2/xlat_tables_private.h +++ b/lib/xlat_tables_v2/xlat_tables_private.h @@ -7,32 +7,8 @@ #ifndef __XLAT_TABLES_PRIVATE_H__ #define __XLAT_TABLES_PRIVATE_H__ -#include #include -#include - -/* - * If the platform hasn't defined a physical and a virtual address space size - * default to ADDR_SPACE_SIZE. - */ -#if ERROR_DEPRECATED -# ifdef ADDR_SPACE_SIZE -# error "ADDR_SPACE_SIZE is deprecated. Use PLAT_xxx_ADDR_SPACE_SIZE instead." -# endif -#elif defined(ADDR_SPACE_SIZE) -# ifndef PLAT_PHY_ADDR_SPACE_SIZE -# define PLAT_PHY_ADDR_SPACE_SIZE ADDR_SPACE_SIZE -# endif -# ifndef PLAT_VIRT_ADDR_SPACE_SIZE -# define PLAT_VIRT_ADDR_SPACE_SIZE ADDR_SPACE_SIZE -# endif -#endif - -/* The virtual and physical address space sizes must be powers of two. */ -CASSERT(IS_POWER_OF_TWO(PLAT_VIRT_ADDR_SPACE_SIZE), - assert_valid_virt_addr_space_size); -CASSERT(IS_POWER_OF_TWO(PLAT_PHY_ADDR_SPACE_SIZE), - assert_valid_phy_addr_space_size); +#include /* Struct that holds all information about the translation tables. */ typedef struct { From 55c84964f72dc90d00c9dede027be3b284dd60e1 Mon Sep 17 00:00:00 2001 From: Sandrine Bailleux Date: Mon, 10 Jul 2017 13:37:48 +0100 Subject: [PATCH 04/11] xlat lib v2: Export translation context as an opaque type At the moment, the translation context type (xlat_ctx_t) is a private type reserved for the internal usage of the translation table library. All exported APIs (implemented in xlat_tables_common.c) are wrappers over the internal implementations that use such a translation context. These wrappers unconditionally pass the current translation context representing the memory mappings of the executing BL image. This means that the caller has no control over which translation context the library functions act on. As a first step to make this code more flexible, this patch exports the 'xlat_ctx_t' type. Note that, although the declaration of this type is now public, its definition stays private. A macro is introduced to statically allocate and initialize such a translation context. The library now internally uses this macro to allocate the default translation context for the running BL image. Change-Id: Icece1cde4813fac19452c782b682c758142b1489 Signed-off-by: Sandrine Bailleux --- include/lib/xlat_tables/xlat_tables_v2.h | 39 +++++ .../lib/xlat_tables/xlat_tables_v2_helpers.h | 151 ++++++++++++++++++ lib/xlat_tables_v2/xlat_tables_common.c | 60 +------ lib/xlat_tables_v2/xlat_tables_private.h | 67 -------- 4 files changed, 196 insertions(+), 121 deletions(-) create mode 100644 include/lib/xlat_tables/xlat_tables_v2_helpers.h diff --git a/include/lib/xlat_tables/xlat_tables_v2.h b/include/lib/xlat_tables/xlat_tables_v2.h index 9db671910..a5cdfee8d 100644 --- a/include/lib/xlat_tables/xlat_tables_v2.h +++ b/include/lib/xlat_tables/xlat_tables_v2.h @@ -13,6 +13,7 @@ #include #include #include +#include /* Helper macro to define entries for mmap_region_t. It creates * identity mappings for each region. @@ -82,6 +83,44 @@ typedef struct mmap_region { mmap_attr_t attr; } mmap_region_t; +/* + * Declare the translation context type. + * Its definition is private. + */ +typedef struct xlat_ctx xlat_ctx_t; + +/* + * Statically allocate a translation context and associated structures. Also + * initialize them. + * + * _ctx_name: + * Prefix for the translation context variable. + * E.g. If _ctx_name is 'foo', the variable will be called 'foo_xlat_ctx'. + * Useful to distinguish multiple contexts from one another. + * + * _mmap_count: + * Number of mmap_region_t to allocate. + * Would typically be MAX_MMAP_REGIONS for the translation context describing + * the BL image currently executing. + * + * _xlat_tables_count: + * Number of sub-translation tables to allocate. + * Would typically be MAX_XLAT_TABLES for the translation context describing + * the BL image currently executing. + * Note that this is only for sub-tables ; at the initial lookup level, there + * is always a single table. + * + * _virt_addr_space_size, _phy_addr_space_size: + * Size (in bytes) of the virtual (resp. physical) address space. + * Would typically be PLAT_VIRT_ADDR_SPACE_SIZE + * (resp. PLAT_PHY_ADDR_SPACE_SIZE) for the translation context describing the + * BL image currently executing. + */ +#define REGISTER_XLAT_CONTEXT(_ctx_name, _mmap_count, _xlat_tables_count, \ + _virt_addr_space_size, _phy_addr_space_size) \ + _REGISTER_XLAT_CONTEXT(_ctx_name, _mmap_count, _xlat_tables_count, \ + _virt_addr_space_size, _phy_addr_space_size) + /* Generic translation table APIs */ /* diff --git a/include/lib/xlat_tables/xlat_tables_v2_helpers.h b/include/lib/xlat_tables/xlat_tables_v2_helpers.h new file mode 100644 index 000000000..f5e310066 --- /dev/null +++ b/include/lib/xlat_tables/xlat_tables_v2_helpers.h @@ -0,0 +1,151 @@ +/* + * Copyright (c) 2017, ARM Limited and Contributors. All rights reserved. + * + * SPDX-License-Identifier: BSD-3-Clause + */ + +/* + * This header file contains internal definitions that are not supposed to be + * used outside of this library code. + */ + +#ifndef __XLAT_TABLES_V2_HELPERS_H__ +#define __XLAT_TABLES_V2_HELPERS_H__ + +#ifndef __XLAT_TABLES_V2_H__ +#error "Do not include this header file directly. Include xlat_tables_v2.h instead." +#endif + +#ifndef __ASSEMBLY__ + +#include +#include +#include +#include +#include + +/* Forward declaration */ +struct mmap_region; + +/* Struct that holds all information about the translation tables. */ +struct xlat_ctx { + /* + * Max allowed Virtual and Physical Addresses. + */ + unsigned long long pa_max_address; + uintptr_t va_max_address; + + /* + * Array of all memory regions stored in order of ascending end address + * and ascending size to simplify the code that allows overlapping + * regions. The list is terminated by the first entry with size == 0. + * The max size of the list is stored in `mmap_num`. `mmap` points to an + * array of mmap_num + 1 elements, so that there is space for the final + * null entry. + */ + struct mmap_region *mmap; + unsigned int mmap_num; + + /* + * Array of finer-grain translation tables. + * For example, if the initial lookup level is 1 then this array would + * contain both level-2 and level-3 entries. + */ + uint64_t (*tables)[XLAT_TABLE_ENTRIES]; + unsigned int tables_num; + /* + * Keep track of how many regions are mapped in each table. The base + * table can't be unmapped so it isn't needed to keep track of it. + */ +#if PLAT_XLAT_TABLES_DYNAMIC + int *tables_mapped_regions; +#endif /* PLAT_XLAT_TABLES_DYNAMIC */ + + unsigned int next_table; + + /* + * Base translation table. It doesn't need to have the same amount of + * entries as the ones used for other levels. + */ + uint64_t *base_table; + unsigned int base_table_entries; + + /* + * Max Physical and Virtual addresses currently in use by the + * translation tables. These might get updated as we map/unmap memory + * regions but they will never go beyond pa/va_max_address. + */ + unsigned long long max_pa; + uintptr_t max_va; + + /* Level of the base translation table. */ + unsigned int base_level; + + /* Set to 1 when the translation tables are initialized. */ + unsigned int initialized; + + /* + * Bit mask that has to be ORed to the rest of a translation table + * descriptor in order to prohibit execution of code at the exception + * level of this translation context. + */ + uint64_t execute_never_mask; +}; + +#if PLAT_XLAT_TABLES_DYNAMIC +#define _ALLOC_DYNMAP_STRUCT(_ctx_name, _xlat_tables_count) \ + static int _ctx_name##_mapped_regions[_xlat_tables_count]; + +#define _REGISTER_DYNMAP_STRUCT(_ctx_name) \ + .tables_mapped_regions = _ctx_name##_mapped_regions, +#else +#define _ALLOC_DYNMAP_STRUCT(_ctx_name, _xlat_tables_count) \ + /* do nothing */ + +#define _REGISTER_DYNMAP_STRUCT(_ctx_name) \ + /* do nothing */ +#endif /* PLAT_XLAT_TABLES_DYNAMIC */ + + +#define _REGISTER_XLAT_CONTEXT(_ctx_name, _mmap_count, _xlat_tables_count, \ + _virt_addr_space_size, _phy_addr_space_size) \ + CASSERT(CHECK_VIRT_ADDR_SPACE_SIZE(_virt_addr_space_size), \ + assert_invalid_virtual_addr_space_size_for_##_ctx_name); \ + \ + CASSERT(CHECK_PHY_ADDR_SPACE_SIZE(_phy_addr_space_size), \ + assert_invalid_physical_addr_space_sizefor_##_ctx_name); \ + \ + static mmap_region_t _ctx_name##_mmap[_mmap_count + 1]; \ + \ + static uint64_t _ctx_name##_xlat_tables[_xlat_tables_count] \ + [XLAT_TABLE_ENTRIES] \ + __aligned(XLAT_TABLE_SIZE) __section("xlat_table"); \ + \ + static uint64_t _ctx_name##_base_xlat_table \ + [GET_NUM_BASE_LEVEL_ENTRIES(_virt_addr_space_size)] \ + __aligned(GET_NUM_BASE_LEVEL_ENTRIES(_virt_addr_space_size) \ + * sizeof(uint64_t)); \ + \ + _ALLOC_DYNMAP_STRUCT(_ctx_name, _xlat_tables_count) \ + \ + static xlat_ctx_t _ctx_name##_xlat_ctx = { \ + .va_max_address = (_virt_addr_space_size) - 1, \ + .pa_max_address = (_phy_addr_space_size) - 1, \ + .mmap = _ctx_name##_mmap, \ + .mmap_num = _mmap_count, \ + .base_level = GET_XLAT_TABLE_LEVEL_BASE(_virt_addr_space_size), \ + .base_table = _ctx_name##_base_xlat_table, \ + .base_table_entries = \ + GET_NUM_BASE_LEVEL_ENTRIES(_virt_addr_space_size), \ + .tables = _ctx_name##_xlat_tables, \ + .tables_num = _xlat_tables_count, \ + _REGISTER_DYNMAP_STRUCT(_ctx_name) \ + .max_pa = 0, \ + .max_va = 0, \ + .next_table = 0, \ + .initialized = 0, \ + } + +#endif /*__ASSEMBLY__*/ + +#endif /* __XLAT_TABLES_V2_HELPERS_H__ */ diff --git a/lib/xlat_tables_v2/xlat_tables_common.c b/lib/xlat_tables_v2/xlat_tables_common.c index fce601785..f214e5cc0 100644 --- a/lib/xlat_tables_v2/xlat_tables_common.c +++ b/lib/xlat_tables_v2/xlat_tables_common.c @@ -7,7 +7,6 @@ #include #include #include -#include #include #include #include @@ -38,59 +37,12 @@ # endif #endif -CASSERT(CHECK_VIRT_ADDR_SPACE_SIZE(PLAT_VIRT_ADDR_SPACE_SIZE), - assert_invalid_virtual_addr_space_size); - -CASSERT(CHECK_PHY_ADDR_SPACE_SIZE(PLAT_PHY_ADDR_SPACE_SIZE), - assert_invalid_physical_addr_space_size); - -#define NUM_BASE_LEVEL_ENTRIES \ - GET_NUM_BASE_LEVEL_ENTRIES(PLAT_VIRT_ADDR_SPACE_SIZE) - -#define XLAT_TABLE_LEVEL_BASE \ - GET_XLAT_TABLE_LEVEL_BASE(PLAT_VIRT_ADDR_SPACE_SIZE) - /* - * Private variables used by the TF + * Allocate and initialise the default translation context for the BL image + * currently executing. */ -static mmap_region_t tf_mmap[MAX_MMAP_REGIONS + 1]; - -static uint64_t tf_xlat_tables[MAX_XLAT_TABLES][XLAT_TABLE_ENTRIES] - __aligned(XLAT_TABLE_SIZE) __section("xlat_table"); - -static uint64_t tf_base_xlat_table[NUM_BASE_LEVEL_ENTRIES] - __aligned(NUM_BASE_LEVEL_ENTRIES * sizeof(uint64_t)); - -#if PLAT_XLAT_TABLES_DYNAMIC -static int xlat_tables_mapped_regions[MAX_XLAT_TABLES]; -#endif /* PLAT_XLAT_TABLES_DYNAMIC */ - -xlat_ctx_t tf_xlat_ctx = { - - .pa_max_address = PLAT_PHY_ADDR_SPACE_SIZE - 1, - .va_max_address = PLAT_VIRT_ADDR_SPACE_SIZE - 1, - - .mmap = tf_mmap, - .mmap_num = MAX_MMAP_REGIONS, - - .tables = tf_xlat_tables, - .tables_num = MAX_XLAT_TABLES, -#if PLAT_XLAT_TABLES_DYNAMIC - .tables_mapped_regions = xlat_tables_mapped_regions, -#endif /* PLAT_XLAT_TABLES_DYNAMIC */ - - .base_table = tf_base_xlat_table, - .base_table_entries = NUM_BASE_LEVEL_ENTRIES, - - .max_pa = 0, - .max_va = 0, - - .next_table = 0, - - .base_level = XLAT_TABLE_LEVEL_BASE, - - .initialized = 0 -}; +REGISTER_XLAT_CONTEXT(tf, MAX_MMAP_REGIONS, MAX_XLAT_TABLES, + PLAT_VIRT_ADDR_SPACE_SIZE, PLAT_PHY_ADDR_SPACE_SIZE); void mmap_add_region(unsigned long long base_pa, uintptr_t base_va, size_t size, mmap_attr_t attr) @@ -143,8 +95,8 @@ void init_xlat_tables(void) init_xlation_table(&tf_xlat_ctx); xlat_tables_print(&tf_xlat_ctx); - assert(tf_xlat_ctx.max_va <= PLAT_VIRT_ADDR_SPACE_SIZE - 1); - assert(tf_xlat_ctx.max_pa <= PLAT_PHY_ADDR_SPACE_SIZE - 1); + assert(tf_xlat_ctx.max_va <= tf_xlat_ctx.va_max_address); + assert(tf_xlat_ctx.max_pa <= tf_xlat_ctx.pa_max_address); init_xlat_tables_arch(tf_xlat_ctx.max_pa); } diff --git a/lib/xlat_tables_v2/xlat_tables_private.h b/lib/xlat_tables_v2/xlat_tables_private.h index 83aa5b1e5..45eaf55d2 100644 --- a/lib/xlat_tables_v2/xlat_tables_private.h +++ b/lib/xlat_tables_v2/xlat_tables_private.h @@ -10,73 +10,6 @@ #include #include -/* Struct that holds all information about the translation tables. */ -typedef struct { - - /* - * Max allowed Virtual and Physical Addresses. - */ - unsigned long long pa_max_address; - uintptr_t va_max_address; - - /* - * Array of all memory regions stored in order of ascending end address - * and ascending size to simplify the code that allows overlapping - * regions. The list is terminated by the first entry with size == 0. - * The max size of the list is stored in `mmap_num`. `mmap` points to an - * array of mmap_num + 1 elements, so that there is space for the final - * null entry. - */ - mmap_region_t *mmap; - unsigned int mmap_num; - - /* - * Array of finer-grain translation tables. - * For example, if the initial lookup level is 1 then this array would - * contain both level-2 and level-3 entries. - */ - uint64_t (*tables)[XLAT_TABLE_ENTRIES]; - unsigned int tables_num; - /* - * Keep track of how many regions are mapped in each table. The base - * table can't be unmapped so it isn't needed to keep track of it. - */ -#if PLAT_XLAT_TABLES_DYNAMIC - int *tables_mapped_regions; -#endif /* PLAT_XLAT_TABLES_DYNAMIC */ - - unsigned int next_table; - - /* - * Base translation table. It doesn't need to have the same amount of - * entries as the ones used for other levels. - */ - uint64_t *base_table; - unsigned int base_table_entries; - - /* - * Max Physical and Virtual addresses currently in use by the - * translation tables. These might get updated as we map/unmap memory - * regions but they will never go beyond pa/va_max_address. - */ - unsigned long long max_pa; - uintptr_t max_va; - - /* Level of the base translation table. */ - unsigned int base_level; - - /* Set to 1 when the translation tables are initialized. */ - unsigned int initialized; - - /* - * Bit mask that has to be ORed to the rest of a translation table - * descriptor in order to prohibit execution of code at the exception - * level of this translation context. - */ - uint64_t execute_never_mask; - -} xlat_ctx_t; - #if PLAT_XLAT_TABLES_DYNAMIC /* * Shifts and masks to access fields of an mmap_attr_t From a9ad848ccf084998a17bbb2870903b0a686de2ef Mon Sep 17 00:00:00 2001 From: Sandrine Bailleux Date: Tue, 18 Jul 2017 13:26:36 +0100 Subject: [PATCH 05/11] xlat lib v2: Expose *_ctx() APIs In a previous patch, the xlat_ctx_t type has been made public. This patch now makes the *_ctx() APIs public. Each API now has a *_ctx() variant. Most of them were already implemented and this patch just makes them public. However, some of them were missing so this patch introduces them. Now that all these APIs are public, there's no good reason for splitting them accross 2 files (xlat_tables_internal.c and xlat_tables_common.c). Therefore, this patch moves all code into xlat_tables_internal.c and removes xlat_tables_common.c. It removes it from the library's makefile as well. This last change introduces a compatibility break for platform ports that specifically include the xlat_tables_common.c file instead of including the library's Makefile. The UniPhier platform makefile has been updated to now omit this file from the list of source files. The prototype of mmap_add_region_ctx() has been slightly changed. The mmap_region_t passed in argument needs to be constant because it gets called from map_add(), which receives a constant region. The former implementation of mmap_add() used to cast the const qualifier away, which is not a good practice. Also remove init_xlation_table(), which was a sub-function of init_xlat_tables(). Now there's just init_xlat_tables() (and init_xlat_tables_ctx()). Both names were too similar, which was confusing. Besides, now that all the code is in a single file, it's no longer needed to have 2 functions for that. Change-Id: I4ed88c68e44561c3902fbebb89cb197279c5293b Signed-off-by: Sandrine Bailleux --- include/lib/xlat_tables/xlat_tables_v2.h | 33 ++++-- lib/xlat_tables_v2/xlat_tables.mk | 1 - lib/xlat_tables_v2/xlat_tables_common.c | 123 ---------------------- lib/xlat_tables_v2/xlat_tables_internal.c | 117 +++++++++++++++++++- lib/xlat_tables_v2/xlat_tables_private.h | 16 --- plat/socionext/uniphier/platform.mk | 1 - 6 files changed, 139 insertions(+), 152 deletions(-) delete mode 100644 lib/xlat_tables_v2/xlat_tables_common.c diff --git a/include/lib/xlat_tables/xlat_tables_v2.h b/include/lib/xlat_tables/xlat_tables_v2.h index a5cdfee8d..288a8e0be 100644 --- a/include/lib/xlat_tables/xlat_tables_v2.h +++ b/include/lib/xlat_tables/xlat_tables_v2.h @@ -121,7 +121,13 @@ typedef struct xlat_ctx xlat_ctx_t; _REGISTER_XLAT_CONTEXT(_ctx_name, _mmap_count, _xlat_tables_count, \ _virt_addr_space_size, _phy_addr_space_size) -/* Generic translation table APIs */ +/****************************************************************************** + * Generic translation table APIs. + * Each API comes in 2 variants: + * - one that acts on the current translation context for this BL image + * - another that acts on the given translation context instead. This variant + * is named after the 1st version, with an additional '_ctx' suffix. + *****************************************************************************/ /* * Initialize translation tables from the current list of mmap regions. Calling @@ -129,6 +135,7 @@ typedef struct xlat_ctx xlat_ctx_t; * longer be added. */ void init_xlat_tables(void); +void init_xlat_tables_ctx(xlat_ctx_t *ctx); /* * Add a static region with defined base PA and base VA. This function can only @@ -137,7 +144,18 @@ void init_xlat_tables(void); */ void mmap_add_region(unsigned long long base_pa, uintptr_t base_va, size_t size, mmap_attr_t attr); +void mmap_add_region_ctx(xlat_ctx_t *ctx, const mmap_region_t *mm); +/* + * Add an array of static regions with defined base PA and base VA. This + * function can only be used before initializing the translation tables. The + * regions cannot be removed afterwards. + */ +void mmap_add(const mmap_region_t *mm); +void mmap_add_ctx(xlat_ctx_t *ctx, const mmap_region_t *mm); + + +#if PLAT_XLAT_TABLES_DYNAMIC /* * Add a dynamic region with defined base PA and base VA. This type of region * can be added and removed even after the translation tables are initialized. @@ -151,13 +169,7 @@ void mmap_add_region(unsigned long long base_pa, uintptr_t base_va, */ int mmap_add_dynamic_region(unsigned long long base_pa, uintptr_t base_va, size_t size, mmap_attr_t attr); - -/* - * Add an array of static regions with defined base PA and base VA. This - * function can only be used before initializing the translation tables. The - * regions cannot be removed afterwards. - */ -void mmap_add(const mmap_region_t *mm); +int mmap_add_dynamic_region_ctx(xlat_ctx_t *ctx, mmap_region_t *mm); /* * Remove a region with the specified base VA and size. Only dynamic regions can @@ -170,6 +182,11 @@ void mmap_add(const mmap_region_t *mm); * EPERM: Trying to remove a static region. */ int mmap_remove_dynamic_region(uintptr_t base_va, size_t size); +int mmap_remove_dynamic_region_ctx(xlat_ctx_t *ctx, + uintptr_t base_va, + size_t size); + +#endif /* PLAT_XLAT_TABLES_DYNAMIC */ #endif /*__ASSEMBLY__*/ #endif /* __XLAT_TABLES_V2_H__ */ diff --git a/lib/xlat_tables_v2/xlat_tables.mk b/lib/xlat_tables_v2/xlat_tables.mk index 4f804341f..b94ce5d07 100644 --- a/lib/xlat_tables_v2/xlat_tables.mk +++ b/lib/xlat_tables_v2/xlat_tables.mk @@ -6,5 +6,4 @@ XLAT_TABLES_LIB_SRCS := $(addprefix lib/xlat_tables_v2/, \ ${ARCH}/xlat_tables_arch.c \ - xlat_tables_common.c \ xlat_tables_internal.c) diff --git a/lib/xlat_tables_v2/xlat_tables_common.c b/lib/xlat_tables_v2/xlat_tables_common.c deleted file mode 100644 index f214e5cc0..000000000 --- a/lib/xlat_tables_v2/xlat_tables_common.c +++ /dev/null @@ -1,123 +0,0 @@ -/* - * Copyright (c) 2017, ARM Limited and Contributors. All rights reserved. - * - * SPDX-License-Identifier: BSD-3-Clause - */ - -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include - -#include "xlat_tables_private.h" - -/* - * Each platform can define the size of its physical and virtual address spaces. - * If the platform hasn't defined one or both of them, default to - * ADDR_SPACE_SIZE. The latter is deprecated, though. - */ -#if ERROR_DEPRECATED -# ifdef ADDR_SPACE_SIZE -# error "ADDR_SPACE_SIZE is deprecated. Use PLAT_xxx_ADDR_SPACE_SIZE instead." -# endif -#elif defined(ADDR_SPACE_SIZE) -# ifndef PLAT_PHY_ADDR_SPACE_SIZE -# define PLAT_PHY_ADDR_SPACE_SIZE ADDR_SPACE_SIZE -# endif -# ifndef PLAT_VIRT_ADDR_SPACE_SIZE -# define PLAT_VIRT_ADDR_SPACE_SIZE ADDR_SPACE_SIZE -# endif -#endif - -/* - * Allocate and initialise the default translation context for the BL image - * currently executing. - */ -REGISTER_XLAT_CONTEXT(tf, MAX_MMAP_REGIONS, MAX_XLAT_TABLES, - PLAT_VIRT_ADDR_SPACE_SIZE, PLAT_PHY_ADDR_SPACE_SIZE); - -void mmap_add_region(unsigned long long base_pa, uintptr_t base_va, - size_t size, mmap_attr_t attr) -{ - mmap_region_t mm = { - .base_va = base_va, - .base_pa = base_pa, - .size = size, - .attr = attr, - }; - mmap_add_region_ctx(&tf_xlat_ctx, (mmap_region_t *)&mm); -} - -void mmap_add(const mmap_region_t *mm) -{ - while (mm->size) { - mmap_add_region_ctx(&tf_xlat_ctx, (mmap_region_t *)mm); - mm++; - } -} - -#if PLAT_XLAT_TABLES_DYNAMIC - -int mmap_add_dynamic_region(unsigned long long base_pa, - uintptr_t base_va, size_t size, mmap_attr_t attr) -{ - mmap_region_t mm = { - .base_va = base_va, - .base_pa = base_pa, - .size = size, - .attr = attr, - }; - return mmap_add_dynamic_region_ctx(&tf_xlat_ctx, &mm); -} - -int mmap_remove_dynamic_region(uintptr_t base_va, size_t size) -{ - return mmap_remove_dynamic_region_ctx(&tf_xlat_ctx, base_va, size); -} - -#endif /* PLAT_XLAT_TABLES_DYNAMIC */ - -void init_xlat_tables(void) -{ - assert(!is_mmu_enabled()); - assert(!tf_xlat_ctx.initialized); - print_mmap(tf_xlat_ctx.mmap); - tf_xlat_ctx.execute_never_mask = - xlat_arch_get_xn_desc(xlat_arch_current_el()); - init_xlation_table(&tf_xlat_ctx); - xlat_tables_print(&tf_xlat_ctx); - - assert(tf_xlat_ctx.max_va <= tf_xlat_ctx.va_max_address); - assert(tf_xlat_ctx.max_pa <= tf_xlat_ctx.pa_max_address); - - init_xlat_tables_arch(tf_xlat_ctx.max_pa); -} - -#ifdef AARCH32 - -void enable_mmu_secure(unsigned int flags) -{ - enable_mmu_arch(flags, tf_xlat_ctx.base_table); -} - -#else - -void enable_mmu_el1(unsigned int flags) -{ - enable_mmu_arch(flags, tf_xlat_ctx.base_table); -} - -void enable_mmu_el3(unsigned int flags) -{ - enable_mmu_arch(flags, tf_xlat_ctx.base_table); -} - -#endif /* AARCH32 */ diff --git a/lib/xlat_tables_v2/xlat_tables_internal.c b/lib/xlat_tables_v2/xlat_tables_internal.c index a3a98d197..82b3489c4 100644 --- a/lib/xlat_tables_v2/xlat_tables_internal.c +++ b/lib/xlat_tables_v2/xlat_tables_internal.c @@ -7,7 +7,6 @@ #include #include #include -#include #include #include #include @@ -21,6 +20,31 @@ #include "xlat_tables_private.h" +/* + * Each platform can define the size of its physical and virtual address spaces. + * If the platform hasn't defined one or both of them, default to + * ADDR_SPACE_SIZE. The latter is deprecated, though. + */ +#if ERROR_DEPRECATED +# ifdef ADDR_SPACE_SIZE +# error "ADDR_SPACE_SIZE is deprecated. Use PLAT_xxx_ADDR_SPACE_SIZE instead." +# endif +#elif defined(ADDR_SPACE_SIZE) +# ifndef PLAT_PHY_ADDR_SPACE_SIZE +# define PLAT_PHY_ADDR_SPACE_SIZE ADDR_SPACE_SIZE +# endif +# ifndef PLAT_VIRT_ADDR_SPACE_SIZE +# define PLAT_VIRT_ADDR_SPACE_SIZE ADDR_SPACE_SIZE +# endif +#endif + +/* + * Allocate and initialise the default translation context for the BL image + * currently executing. + */ +REGISTER_XLAT_CONTEXT(tf, MAX_MMAP_REGIONS, MAX_XLAT_TABLES, + PLAT_VIRT_ADDR_SPACE_SIZE, PLAT_PHY_ADDR_SPACE_SIZE); + #if PLAT_XLAT_TABLES_DYNAMIC /* @@ -664,7 +688,7 @@ static int mmap_add_region_check(xlat_ctx_t *ctx, unsigned long long base_pa, return 0; } -void mmap_add_region_ctx(xlat_ctx_t *ctx, mmap_region_t *mm) +void mmap_add_region_ctx(xlat_ctx_t *ctx, const mmap_region_t *mm) { mmap_region_t *mm_cursor = ctx->mmap; mmap_region_t *mm_last = mm_cursor + ctx->mmap_num; @@ -741,6 +765,34 @@ void mmap_add_region_ctx(xlat_ctx_t *ctx, mmap_region_t *mm) ctx->max_va = end_va; } +void mmap_add_region(unsigned long long base_pa, + uintptr_t base_va, + size_t size, + mmap_attr_t attr) +{ + mmap_region_t mm = { + .base_va = base_va, + .base_pa = base_pa, + .size = size, + .attr = attr, + }; + mmap_add_region_ctx(&tf_xlat_ctx, &mm); +} + + +void mmap_add_ctx(xlat_ctx_t *ctx, const mmap_region_t *mm) +{ + while (mm->size) { + mmap_add_region_ctx(ctx, mm); + mm++; + } +} + +void mmap_add(const mmap_region_t *mm) +{ + mmap_add_ctx(&tf_xlat_ctx, mm); +} + #if PLAT_XLAT_TABLES_DYNAMIC int mmap_add_dynamic_region_ctx(xlat_ctx_t *ctx, mmap_region_t *mm) @@ -837,6 +889,18 @@ int mmap_add_dynamic_region_ctx(xlat_ctx_t *ctx, mmap_region_t *mm) return 0; } +int mmap_add_dynamic_region(unsigned long long base_pa, + uintptr_t base_va, size_t size, mmap_attr_t attr) +{ + mmap_region_t mm = { + .base_va = base_va, + .base_pa = base_pa, + .size = size, + .attr = attr, + }; + return mmap_add_dynamic_region_ctx(&tf_xlat_ctx, &mm); +} + /* * Removes the region with given base Virtual Address and size from the given * context. @@ -912,6 +976,12 @@ int mmap_remove_dynamic_region_ctx(xlat_ctx_t *ctx, uintptr_t base_va, return 0; } +int mmap_remove_dynamic_region(uintptr_t base_va, size_t size) +{ + return mmap_remove_dynamic_region_ctx(&tf_xlat_ctx, + base_va, size); +} + #endif /* PLAT_XLAT_TABLES_DYNAMIC */ #if LOG_LEVEL >= LOG_LEVEL_VERBOSE @@ -1069,10 +1139,18 @@ void xlat_tables_print(xlat_ctx_t *ctx) #endif /* LOG_LEVEL >= LOG_LEVEL_VERBOSE */ } -void init_xlation_table(xlat_ctx_t *ctx) +void init_xlat_tables_ctx(xlat_ctx_t *ctx) { mmap_region_t *mm = ctx->mmap; + assert(!is_mmu_enabled()); + assert(!ctx->initialized); + + print_mmap(mm); + + ctx->execute_never_mask = + xlat_arch_get_xn_desc(xlat_arch_current_el()); + /* All tables must be zeroed before mapping any region. */ for (unsigned int i = 0; i < ctx->base_table_entries; i++) @@ -1101,4 +1179,37 @@ void init_xlation_table(xlat_ctx_t *ctx) } ctx->initialized = 1; + + xlat_tables_print(ctx); + + assert(ctx->max_va <= ctx->va_max_address); + assert(ctx->max_pa <= ctx->pa_max_address); + + init_xlat_tables_arch(ctx->max_pa); } + +void init_xlat_tables(void) +{ + init_xlat_tables_ctx(&tf_xlat_ctx); +} + +#ifdef AARCH32 + +void enable_mmu_secure(unsigned int flags) +{ + enable_mmu_arch(flags, tf_xlat_ctx.base_table); +} + +#else + +void enable_mmu_el1(unsigned int flags) +{ + enable_mmu_arch(flags, tf_xlat_ctx.base_table); +} + +void enable_mmu_el3(unsigned int flags) +{ + enable_mmu_arch(flags, tf_xlat_ctx.base_table); +} + +#endif /* AARCH32 */ diff --git a/lib/xlat_tables_v2/xlat_tables_private.h b/lib/xlat_tables_v2/xlat_tables_private.h index 45eaf55d2..9ff1bdb3c 100644 --- a/lib/xlat_tables_v2/xlat_tables_private.h +++ b/lib/xlat_tables_v2/xlat_tables_private.h @@ -47,13 +47,6 @@ void xlat_arch_tlbi_va(uintptr_t va); */ void xlat_arch_tlbi_va_sync(void); -/* Add a dynamic region to the specified context. */ -int mmap_add_dynamic_region_ctx(xlat_ctx_t *ctx, mmap_region_t *mm); - -/* Remove a dynamic region from the specified context. */ -int mmap_remove_dynamic_region_ctx(xlat_ctx_t *ctx, uintptr_t base_va, - size_t size); - #endif /* PLAT_XLAT_TABLES_DYNAMIC */ /* Print VA, PA, size and attributes of all regions in the mmap array. */ @@ -65,15 +58,6 @@ void print_mmap(mmap_region_t *const mmap); */ void xlat_tables_print(xlat_ctx_t *ctx); -/* - * Initialize the translation tables by mapping all regions added to the - * specified context. - */ -void init_xlation_table(xlat_ctx_t *ctx); - -/* Add a static region to the specified context. */ -void mmap_add_region_ctx(xlat_ctx_t *ctx, mmap_region_t *mm); - /* * Architecture-specific initialization code. */ diff --git a/plat/socionext/uniphier/platform.mk b/plat/socionext/uniphier/platform.mk index 7ea0f1080..72792f8a9 100644 --- a/plat/socionext/uniphier/platform.mk +++ b/plat/socionext/uniphier/platform.mk @@ -38,7 +38,6 @@ IO_SOURCES := drivers/io/io_block.c \ # common sources for BL1, BL2, BL31 PLAT_BL_COMMON_SOURCES += drivers/console/aarch64/console.S \ lib/xlat_tables_v2/aarch64/xlat_tables_arch.c \ - lib/xlat_tables_v2/xlat_tables_common.c \ lib/xlat_tables_v2/xlat_tables_internal.c \ $(PLAT_PATH)/uniphier_console.S \ $(PLAT_PATH)/uniphier_helpers.S \ From 99f607989133b12ef28b41aeb1251784b3a7052c Mon Sep 17 00:00:00 2001 From: Sandrine Bailleux Date: Wed, 31 May 2017 13:31:48 +0100 Subject: [PATCH 06/11] xlat lib v2: Remove init_xlat_tables_arch() function In both the AArch32 and AArch64 versions, this function used to check the sanity of the PLAT_PHY_ADDR_SPACE_SIZE in regard to the architectural maximum value. Instead, export the xlat_arch_get_max_supported_pa() function and move the debug assertion in AArch-agnostic code. The AArch64 used to also precalculate the TCR.PS field value, based on the size of the physical address space. This is now done directly by enable_mmu_arch(), which now receives the physical address space size in argument. Change-Id: Ie77ea92eb06db586f28784fdb479c6e27dd1acc1 Signed-off-by: Sandrine Bailleux --- lib/xlat_tables_v2/aarch32/xlat_tables_arch.c | 13 +++----- lib/xlat_tables_v2/aarch64/xlat_tables_arch.c | 30 ++++++----------- lib/xlat_tables_v2/xlat_tables_internal.c | 33 ++++++++++++++----- lib/xlat_tables_v2/xlat_tables_private.h | 11 +++++-- 4 files changed, 47 insertions(+), 40 deletions(-) diff --git a/lib/xlat_tables_v2/aarch32/xlat_tables_arch.c b/lib/xlat_tables_v2/aarch32/xlat_tables_arch.c index 40fd2d0b0..84f1a7dd3 100644 --- a/lib/xlat_tables_v2/aarch32/xlat_tables_arch.c +++ b/lib/xlat_tables_v2/aarch32/xlat_tables_arch.c @@ -14,7 +14,7 @@ #include "../xlat_tables_private.h" #if ENABLE_ASSERTIONS -static unsigned long long xlat_arch_get_max_supported_pa(void) +unsigned long long xlat_arch_get_max_supported_pa(void) { /* Physical address space size for long descriptor format. */ return (1ull << 40) - 1ull; @@ -81,18 +81,11 @@ uint64_t xlat_arch_get_xn_desc(int el __unused) return UPPER_ATTRS(XN); } -void init_xlat_tables_arch(unsigned long long max_pa) -{ - assert((PLAT_PHY_ADDR_SPACE_SIZE - 1) <= - xlat_arch_get_max_supported_pa()); -} - /******************************************************************************* * 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) - { u_register_t mair0, ttbcr, sctlr; uint64_t ttbr0; @@ -158,7 +151,9 @@ void enable_mmu_internal_secure(unsigned int flags, uint64_t *base_table) isb(); } -void enable_mmu_arch(unsigned int flags, uint64_t *base_table) +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 14f6cd6a0..ba1ab7376 100644 --- a/lib/xlat_tables_v2/aarch64/xlat_tables_arch.c +++ b/lib/xlat_tables_v2/aarch64/xlat_tables_arch.c @@ -60,7 +60,7 @@ static const unsigned int pa_range_bits_arr[] = { PARANGE_0101 }; -static unsigned long long xlat_arch_get_max_supported_pa(void) +unsigned long long xlat_arch_get_max_supported_pa(void) { u_register_t pa_range = read_id_aa64mmfr0_el1() & ID_AA64MMFR0_EL1_PARANGE_MASK; @@ -146,24 +146,6 @@ uint64_t xlat_arch_get_xn_desc(int el) } } -void init_xlat_tables_arch(unsigned long long max_pa) -{ - assert((PLAT_PHY_ADDR_SPACE_SIZE - 1) <= - xlat_arch_get_max_supported_pa()); - - /* - * If dynamic allocation of new regions is enabled the code can't make - * assumptions about the max physical address because it could change - * after adding new regions. If this functionality is disabled it is - * safer to restrict the max physical address as much as possible. - */ -#ifdef PLAT_XLAT_TABLES_DYNAMIC - tcr_ps_bits = calc_physical_addr_size_bits(PLAT_PHY_ADDR_SPACE_SIZE); -#else - tcr_ps_bits = calc_physical_addr_size_bits(max_pa); -#endif -} - /******************************************************************************* * Macro generating the code for the function enabling the MMU in the given * exception level, assuming that the pagetables have already been created. @@ -247,8 +229,16 @@ DEFINE_ENABLE_MMU_EL(3, tlbialle3) #endif -void enable_mmu_arch(unsigned int flags, uint64_t *base_table) +void enable_mmu_arch(unsigned int flags, + uint64_t *base_table, + unsigned long long max_pa) { + /* + * 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); + #if IMAGE_EL == 1 assert(IS_IN_EL(1)); enable_mmu_internal_el1(flags, base_table); diff --git a/lib/xlat_tables_v2/xlat_tables_internal.c b/lib/xlat_tables_v2/xlat_tables_internal.c index 82b3489c4..cdf16694a 100644 --- a/lib/xlat_tables_v2/xlat_tables_internal.c +++ b/lib/xlat_tables_v2/xlat_tables_internal.c @@ -1178,14 +1178,14 @@ void init_xlat_tables_ctx(xlat_ctx_t *ctx) mm++; } - ctx->initialized = 1; - - xlat_tables_print(ctx); - + assert((PLAT_PHY_ADDR_SPACE_SIZE - 1) <= + xlat_arch_get_max_supported_pa()); assert(ctx->max_va <= ctx->va_max_address); assert(ctx->max_pa <= ctx->pa_max_address); - init_xlat_tables_arch(ctx->max_pa); + ctx->initialized = 1; + + xlat_tables_print(ctx); } void init_xlat_tables(void) @@ -1193,23 +1193,40 @@ void init_xlat_tables(void) init_xlat_tables_ctx(&tf_xlat_ctx); } +/* + * If dynamic allocation of new regions is disabled then by the time we call the + * function enabling the MMU, we'll have registered all the memory regions to + * map for the system's lifetime. Therefore, at this point we know the maximum + * physical address that will ever be mapped. + * + * If dynamic allocation is enabled then we can't make any such assumption + * because the maximum physical address could get pushed while adding a new + * region. Therefore, in this case we have to assume that the whole address + * space size might be mapped. + */ +#ifdef PLAT_XLAT_TABLES_DYNAMIC +#define MAX_PHYS_ADDR PLAT_PHY_ADDR_SPACE_SIZE +#else +#define MAX_PHYS_ADDR tf_xlat_ctx.max_pa +#endif + #ifdef AARCH32 void enable_mmu_secure(unsigned int flags) { - enable_mmu_arch(flags, tf_xlat_ctx.base_table); + enable_mmu_arch(flags, tf_xlat_ctx.base_table, MAX_PHYS_ADDR); } #else void enable_mmu_el1(unsigned int flags) { - enable_mmu_arch(flags, tf_xlat_ctx.base_table); + enable_mmu_arch(flags, tf_xlat_ctx.base_table, MAX_PHYS_ADDR); } void enable_mmu_el3(unsigned int flags) { - enable_mmu_arch(flags, tf_xlat_ctx.base_table); + enable_mmu_arch(flags, tf_xlat_ctx.base_table, MAX_PHYS_ADDR); } #endif /* AARCH32 */ diff --git a/lib/xlat_tables_v2/xlat_tables_private.h b/lib/xlat_tables_v2/xlat_tables_private.h index 9ff1bdb3c..30303888f 100644 --- a/lib/xlat_tables_v2/xlat_tables_private.h +++ b/lib/xlat_tables_v2/xlat_tables_private.h @@ -72,11 +72,16 @@ int xlat_arch_current_el(void); */ uint64_t xlat_arch_get_xn_desc(int el); -/* Execute architecture-specific translation table initialization code. */ -void init_xlat_tables_arch(unsigned long long max_pa); +/* + * Return the maximum physical address supported by the hardware. + * This value depends on the execution state (AArch32/AArch64). + */ +unsigned long long xlat_arch_get_max_supported_pa(void); /* Enable MMU and configure it to use the specified translation tables. */ -void enable_mmu_arch(unsigned int flags, uint64_t *base_table); +void enable_mmu_arch(unsigned int flags, + uint64_t *base_table, + unsigned long long max_pa); /* Return 1 if the MMU of this Exception Level is enabled, 0 otherwise. */ int is_mmu_enabled(void); From d83f3579528e8808807974044dd1acf3bff83cb3 Mon Sep 17 00:00:00 2001 From: Sandrine Bailleux Date: Wed, 31 May 2017 13:38:51 +0100 Subject: [PATCH 07/11] 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 --- lib/xlat_tables_v2/aarch32/xlat_tables_arch.c | 62 +++++++----- lib/xlat_tables_v2/aarch64/xlat_tables_arch.c | 94 +++++++++---------- 2 files changed, 85 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 84f1a7dd3..78aae2b5f 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 @@ uint64_t xlat_arch_get_xn_desc(int el __unused) } /******************************************************************************* - * 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 @@ void enable_mmu_internal_secure(unsigned int flags, uint64_t *base_table) ATTR_IWBWA_OWBWA_NTR_INDEX); mair0 |= MAIR0_ATTR_SET(ATTR_NON_CACHEABLE, ATTR_NON_CACHEABLE_INDEX); - write_mair0(mair0); /* - * Set TTBCR bits as well. Set TTBR0 table properties. Disable TTBR1. + * 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; + + /* + * 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 @@ void enable_mmu_internal_secure(unsigned int flags, uint64_t *base_table) dsbish(); isb(); - sctlr = read_sctlr(); sctlr |= SCTLR_WXN_BIT | SCTLR_M_BIT; if (flags & DISABLE_DCACHE) @@ -150,10 +171,3 @@ void enable_mmu_internal_secure(unsigned int flags, uint64_t *base_table) /* 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 ba1ab7376..49b0605bd 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 @@ uint64_t xlat_arch_get_xn_desc(int el) * 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 @@ uint64_t xlat_arch_get_xn_desc(int el) 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 @@ uint64_t xlat_arch_get_xn_desc(int el) /* 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 } From 347621bb476843fd977c6dce37718cf3bd47bc3f Mon Sep 17 00:00:00 2001 From: Sandrine Bailleux Date: Tue, 11 Jul 2017 15:11:10 +0100 Subject: [PATCH 08/11] xlat lib v2: Remove hard-coded virtual address space size Previous patches have made it possible to specify the physical and virtual address spaces sizes for each translation context. However, there are still some places in the code where the physical (resp. virtual) address space size is assumed to be PLAT_PHY_ADDR_SPACE_SIZE (resp. PLAT_VIRT_ADDR_SPACE_SIZE). This patch removes them and reads the relevant address space size from the translation context itself instead. This information is now passed in argument to the enable_mmu_arch() function, which needs it to configure the TCR_ELx.T0SZ field (in AArch64) or the TTBCR.T0SZ field (in AArch32) appropriately. Change-Id: I20b0e68b03a143e998695d42911d9954328a06aa Signed-off-by: Sandrine Bailleux --- lib/xlat_tables_v2/aarch32/xlat_tables_arch.c | 16 +++++++++++++--- lib/xlat_tables_v2/aarch64/xlat_tables_arch.c | 12 ++++++++++-- lib/xlat_tables_v2/xlat_tables_internal.c | 14 ++++++++------ lib/xlat_tables_v2/xlat_tables_private.h | 5 ++--- 4 files changed, 33 insertions(+), 14 deletions(-) diff --git a/lib/xlat_tables_v2/aarch32/xlat_tables_arch.c b/lib/xlat_tables_v2/aarch32/xlat_tables_arch.c index 78aae2b5f..9c4d68bc3 100644 --- a/lib/xlat_tables_v2/aarch32/xlat_tables_arch.c +++ b/lib/xlat_tables_v2/aarch32/xlat_tables_arch.c @@ -87,7 +87,8 @@ uint64_t xlat_arch_get_xn_desc(int el __unused) ******************************************************************************/ void enable_mmu_arch(unsigned int flags, uint64_t *base_table, - unsigned long long max_pa) + unsigned long long max_pa, + uintptr_t max_va) { u_register_t mair0, ttbcr, sctlr; uint64_t ttbr0; @@ -123,9 +124,18 @@ void enable_mmu_arch(unsigned int flags, /* * Limit the input address ranges and memory region sizes translated - * using TTBR0 to the given virtual address space size. + * using TTBR0 to the given virtual address space size, if smaller than + * 32 bits. */ - ttbcr |= 32 - __builtin_ctzl((uintptr_t) PLAT_VIRT_ADDR_SPACE_SIZE); + if (max_va != UINT32_MAX) { + uintptr_t virtual_addr_space_size = max_va + 1; + assert(CHECK_VIRT_ADDR_SPACE_SIZE(virtual_addr_space_size)); + /* + * __builtin_ctzl(0) is undefined but here we are guaranteed + * that virtual_addr_space_size is in the range [1, UINT32_MAX]. + */ + ttbcr |= 32 - __builtin_ctzl(virtual_addr_space_size); + } /* * Set the cacheability and shareability attributes for memory diff --git a/lib/xlat_tables_v2/aarch64/xlat_tables_arch.c b/lib/xlat_tables_v2/aarch64/xlat_tables_arch.c index 49b0605bd..5f389f365 100644 --- a/lib/xlat_tables_v2/aarch64/xlat_tables_arch.c +++ b/lib/xlat_tables_v2/aarch64/xlat_tables_arch.c @@ -196,7 +196,8 @@ DEFINE_ENABLE_MMU_EL(3, tlbialle3) void enable_mmu_arch(unsigned int flags, uint64_t *base_table, - unsigned long long max_pa) + unsigned long long max_pa, + uintptr_t max_va) { uint64_t mair, ttbr, tcr; @@ -215,7 +216,14 @@ void enable_mmu_arch(unsigned int flags, * 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); + assert(max_va < UINTPTR_MAX); + uintptr_t virtual_addr_space_size = max_va + 1; + assert(CHECK_VIRT_ADDR_SPACE_SIZE(virtual_addr_space_size)); + /* + * __builtin_ctzl(0) is undefined but here we are guaranteed that + * virtual_addr_space_size is in the range [1,UINTPTR_MAX]. + */ + tcr = 64 - __builtin_ctzl(virtual_addr_space_size); /* * Set the cacheability and shareability attributes for memory diff --git a/lib/xlat_tables_v2/xlat_tables_internal.c b/lib/xlat_tables_v2/xlat_tables_internal.c index cdf16694a..5efc834fa 100644 --- a/lib/xlat_tables_v2/xlat_tables_internal.c +++ b/lib/xlat_tables_v2/xlat_tables_internal.c @@ -1178,8 +1178,7 @@ void init_xlat_tables_ctx(xlat_ctx_t *ctx) mm++; } - assert((PLAT_PHY_ADDR_SPACE_SIZE - 1) <= - xlat_arch_get_max_supported_pa()); + assert(ctx->pa_max_address <= xlat_arch_get_max_supported_pa()); assert(ctx->max_va <= ctx->va_max_address); assert(ctx->max_pa <= ctx->pa_max_address); @@ -1205,7 +1204,7 @@ void init_xlat_tables(void) * space size might be mapped. */ #ifdef PLAT_XLAT_TABLES_DYNAMIC -#define MAX_PHYS_ADDR PLAT_PHY_ADDR_SPACE_SIZE +#define MAX_PHYS_ADDR tf_xlat_ctx.pa_max_address #else #define MAX_PHYS_ADDR tf_xlat_ctx.max_pa #endif @@ -1214,19 +1213,22 @@ void init_xlat_tables(void) void enable_mmu_secure(unsigned int flags) { - enable_mmu_arch(flags, tf_xlat_ctx.base_table, MAX_PHYS_ADDR); + enable_mmu_arch(flags, tf_xlat_ctx.base_table, MAX_PHYS_ADDR, + tf_xlat_ctx.va_max_address); } #else void enable_mmu_el1(unsigned int flags) { - enable_mmu_arch(flags, tf_xlat_ctx.base_table, MAX_PHYS_ADDR); + enable_mmu_arch(flags, tf_xlat_ctx.base_table, MAX_PHYS_ADDR, + tf_xlat_ctx.va_max_address); } void enable_mmu_el3(unsigned int flags) { - enable_mmu_arch(flags, tf_xlat_ctx.base_table, MAX_PHYS_ADDR); + enable_mmu_arch(flags, tf_xlat_ctx.base_table, MAX_PHYS_ADDR, + tf_xlat_ctx.va_max_address); } #endif /* AARCH32 */ diff --git a/lib/xlat_tables_v2/xlat_tables_private.h b/lib/xlat_tables_v2/xlat_tables_private.h index 30303888f..d352583c9 100644 --- a/lib/xlat_tables_v2/xlat_tables_private.h +++ b/lib/xlat_tables_v2/xlat_tables_private.h @@ -79,9 +79,8 @@ uint64_t xlat_arch_get_xn_desc(int el); unsigned long long xlat_arch_get_max_supported_pa(void); /* Enable MMU and configure it to use the specified translation tables. */ -void enable_mmu_arch(unsigned int flags, - uint64_t *base_table, - unsigned long long max_pa); +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); From 7bba6884a0112ec38ad5992b1eb3f0398abf5cf7 Mon Sep 17 00:00:00 2001 From: Sandrine Bailleux Date: Wed, 19 Jul 2017 14:05:47 +0100 Subject: [PATCH 09/11] Import ctzdi2.c from LLVM compiler-rt When using __builtin_ctzll() in AArch32 code, the compiler may translate that into a call to the __ctzdi2() function. In this case, the linking phase fails because TF doesn't provide an implementation for it. This patch imports the implementation of the __ctzdi2() function from LLVM's compiler-rt project and hooks it into TF's build system. The ctzdi2.c file is an unmodified copy from the master branch as of July 19 2017 (SVN revision: 308480). Change-Id: I96766a025ba28e1afc6ef6a5c4ef91d85fc8f32b Signed-off-by: Sandrine Bailleux --- lib/compiler-rt/builtins/ctzdi2.c | 29 +++++++++++++++++++++++++++++ lib/compiler-rt/compiler-rt.mk | 3 ++- 2 files changed, 31 insertions(+), 1 deletion(-) create mode 100644 lib/compiler-rt/builtins/ctzdi2.c diff --git a/lib/compiler-rt/builtins/ctzdi2.c b/lib/compiler-rt/builtins/ctzdi2.c new file mode 100644 index 000000000..db3c6fdc0 --- /dev/null +++ b/lib/compiler-rt/builtins/ctzdi2.c @@ -0,0 +1,29 @@ +/* ===-- ctzdi2.c - Implement __ctzdi2 -------------------------------------=== + * + * The LLVM Compiler Infrastructure + * + * This file is dual licensed under the MIT and the University of Illinois Open + * Source Licenses. See LICENSE.TXT for details. + * + * ===----------------------------------------------------------------------=== + * + * This file implements __ctzdi2 for the compiler_rt library. + * + * ===----------------------------------------------------------------------=== + */ + +#include "int_lib.h" + +/* Returns: the number of trailing 0-bits */ + +/* Precondition: a != 0 */ + +COMPILER_RT_ABI si_int +__ctzdi2(di_int a) +{ + dwords x; + x.all = a; + const si_int f = -(x.s.low == 0); + return __builtin_ctz((x.s.high & f) | (x.s.low & ~f)) + + (f & ((si_int)(sizeof(si_int) * CHAR_BIT))); +} diff --git a/lib/compiler-rt/compiler-rt.mk b/lib/compiler-rt/compiler-rt.mk index 3bdd31903..cb5ab31c0 100644 --- a/lib/compiler-rt/compiler-rt.mk +++ b/lib/compiler-rt/compiler-rt.mk @@ -30,5 +30,6 @@ ifeq (${ARCH},aarch32) COMPILER_RT_SRCS := lib/compiler-rt/builtins/arm/aeabi_uldivmod.S \ - lib/compiler-rt/builtins/udivmoddi4.c + lib/compiler-rt/builtins/udivmoddi4.c \ + lib/compiler-rt/builtins/ctzdi2.c endif From 0044231d434997428b2a2de0088433779a2555bf Mon Sep 17 00:00:00 2001 From: Sandrine Bailleux Date: Wed, 19 Jul 2017 10:11:13 +0100 Subject: [PATCH 10/11] xlat lib: Fix some types Fix the type length and signedness of some of the constants and variables used in the translation table library. This patch supersedes Pull Request #1018: https://github.com/ARM-software/arm-trusted-firmware/pull/1018 Change-Id: Ibd45faf7a4fb428a0bf71c752551d35800212fb2 Signed-off-by: Sandrine Bailleux --- include/lib/xlat_tables/aarch32/xlat_tables_aarch32.h | 6 +++--- include/lib/xlat_tables/aarch64/xlat_tables_aarch64.h | 9 +++++---- lib/xlat_tables/aarch32/xlat_tables.c | 4 ++-- lib/xlat_tables/aarch64/xlat_tables.c | 4 ++-- lib/xlat_tables_v2/aarch32/xlat_tables_arch.c | 4 ++-- lib/xlat_tables_v2/aarch64/xlat_tables_arch.c | 4 ++-- lib/xlat_tables_v2/xlat_tables_internal.c | 2 +- 7 files changed, 17 insertions(+), 16 deletions(-) diff --git a/include/lib/xlat_tables/aarch32/xlat_tables_aarch32.h b/include/lib/xlat_tables/aarch32/xlat_tables_aarch32.h index 28be8e3d6..a418d2dd6 100644 --- a/include/lib/xlat_tables/aarch32/xlat_tables_aarch32.h +++ b/include/lib/xlat_tables/aarch32/xlat_tables_aarch32.h @@ -28,7 +28,7 @@ #error "Invalid granule size. AArch32 supports 4KB pages only." #endif -#define MIN_LVL_BLOCK_DESC 1 +#define MIN_LVL_BLOCK_DESC U(1) #define XLAT_TABLE_LEVEL_MIN U(1) @@ -43,7 +43,7 @@ * [1] See the ARMv8-A Architecture Reference Manual (DDI 0487A.j) for more * information, Section G4.6.5 */ -#define MIN_VIRT_ADDR_SPACE_SIZE (1 << (32 - TTBCR_TxSZ_MAX)) +#define MIN_VIRT_ADDR_SPACE_SIZE (ULL(1) << (32 - TTBCR_TxSZ_MAX)) #define MAX_VIRT_ADDR_SPACE_SIZE (ULL(1) << (32 - TTBCR_TxSZ_MIN)) /* @@ -67,6 +67,6 @@ * CHECK_VIRT_ADDR_SPACE_SIZE() macro first. */ #define GET_XLAT_TABLE_LEVEL_BASE(virt_addr_space_size) \ - (((virt_addr_space_size) > (1 << L1_XLAT_ADDRESS_SHIFT)) ? 1 : 2) + (((virt_addr_space_size) > (ULL(1) << L1_XLAT_ADDRESS_SHIFT)) ? 1 : 2) #endif /* __XLAT_TABLES_AARCH32_H__ */ diff --git a/include/lib/xlat_tables/aarch64/xlat_tables_aarch64.h b/include/lib/xlat_tables/aarch64/xlat_tables_aarch64.h index 9cad0353f..7381bc829 100644 --- a/include/lib/xlat_tables/aarch64/xlat_tables_aarch64.h +++ b/include/lib/xlat_tables/aarch64/xlat_tables_aarch64.h @@ -26,9 +26,9 @@ * descriptors. */ #if PAGE_SIZE == (4 * 1024) -# define MIN_LVL_BLOCK_DESC 1 +# define MIN_LVL_BLOCK_DESC U(1) #elif PAGE_SIZE == (16 * 1024) || PAGE_SIZE == (64 * 1024) -# define MIN_LVL_BLOCK_DESC 2 +# define MIN_LVL_BLOCK_DESC U(2) #endif #define XLAT_TABLE_LEVEL_MIN U(0) @@ -45,7 +45,7 @@ * information: * Page 1730: 'Input address size', 'For all translation stages'. */ -#define MIN_VIRT_ADDR_SPACE_SIZE (1 << (64 - TCR_TxSZ_MAX)) +#define MIN_VIRT_ADDR_SPACE_SIZE (ULL(1) << (64 - TCR_TxSZ_MAX)) #define MAX_VIRT_ADDR_SPACE_SIZE (ULL(1) << (64 - TCR_TxSZ_MIN)) /* @@ -72,6 +72,7 @@ #define GET_XLAT_TABLE_LEVEL_BASE(virt_addr_space_size) \ (((virt_addr_space_size) > (ULL(1) << L0_XLAT_ADDRESS_SHIFT)) \ ? 0 \ - : (((virt_addr_space_size) > (1 << L1_XLAT_ADDRESS_SHIFT)) ? 1 : 2)) + : (((virt_addr_space_size) > (ULL(1) << L1_XLAT_ADDRESS_SHIFT)) \ + ? 1 : 2)) #endif /* __XLAT_TABLES_AARCH64_H__ */ diff --git a/lib/xlat_tables/aarch32/xlat_tables.c b/lib/xlat_tables/aarch32/xlat_tables.c index 71db2d5f6..c7e34f20f 100644 --- a/lib/xlat_tables/aarch32/xlat_tables.c +++ b/lib/xlat_tables/aarch32/xlat_tables.c @@ -88,13 +88,13 @@ void enable_mmu_secure(unsigned int flags) 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)); + (32 - __builtin_ctzll(PLAT_VIRT_ADDR_SPACE_SIZE)); } 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)); + (32 - __builtin_ctzll(PLAT_VIRT_ADDR_SPACE_SIZE)); } ttbcr |= TTBCR_EPD1_BIT; write_ttbcr(ttbcr); diff --git a/lib/xlat_tables/aarch64/xlat_tables.c b/lib/xlat_tables/aarch64/xlat_tables.c index 4125651e9..2ddf8cba8 100644 --- a/lib/xlat_tables/aarch64/xlat_tables.c +++ b/lib/xlat_tables/aarch64/xlat_tables.c @@ -145,12 +145,12 @@ void init_xlat_tables(void) /* 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));\ + (64 - __builtin_ctzll(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));\ + (64 - __builtin_ctzll(PLAT_VIRT_ADDR_SPACE_SIZE));\ } \ tcr |= _tcr_extra; \ write_tcr_el##_el(tcr); \ diff --git a/lib/xlat_tables_v2/aarch32/xlat_tables_arch.c b/lib/xlat_tables_v2/aarch32/xlat_tables_arch.c index 9c4d68bc3..be18552e3 100644 --- a/lib/xlat_tables_v2/aarch32/xlat_tables_arch.c +++ b/lib/xlat_tables_v2/aarch32/xlat_tables_arch.c @@ -131,10 +131,10 @@ void enable_mmu_arch(unsigned int flags, uintptr_t virtual_addr_space_size = max_va + 1; assert(CHECK_VIRT_ADDR_SPACE_SIZE(virtual_addr_space_size)); /* - * __builtin_ctzl(0) is undefined but here we are guaranteed + * __builtin_ctzll(0) is undefined but here we are guaranteed * that virtual_addr_space_size is in the range [1, UINT32_MAX]. */ - ttbcr |= 32 - __builtin_ctzl(virtual_addr_space_size); + ttbcr |= 32 - __builtin_ctzll(virtual_addr_space_size); } /* diff --git a/lib/xlat_tables_v2/aarch64/xlat_tables_arch.c b/lib/xlat_tables_v2/aarch64/xlat_tables_arch.c index 5f389f365..61eac1064 100644 --- a/lib/xlat_tables_v2/aarch64/xlat_tables_arch.c +++ b/lib/xlat_tables_v2/aarch64/xlat_tables_arch.c @@ -220,10 +220,10 @@ void enable_mmu_arch(unsigned int flags, uintptr_t virtual_addr_space_size = max_va + 1; assert(CHECK_VIRT_ADDR_SPACE_SIZE(virtual_addr_space_size)); /* - * __builtin_ctzl(0) is undefined but here we are guaranteed that + * __builtin_ctzll(0) is undefined but here we are guaranteed that * virtual_addr_space_size is in the range [1,UINTPTR_MAX]. */ - tcr = 64 - __builtin_ctzl(virtual_addr_space_size); + tcr = 64 - __builtin_ctzll(virtual_addr_space_size); /* * Set the cacheability and shareability attributes for memory diff --git a/lib/xlat_tables_v2/xlat_tables_internal.c b/lib/xlat_tables_v2/xlat_tables_internal.c index 5efc834fa..940337bef 100644 --- a/lib/xlat_tables_v2/xlat_tables_internal.c +++ b/lib/xlat_tables_v2/xlat_tables_internal.c @@ -357,7 +357,7 @@ static void xlat_tables_unmap_region(xlat_ctx_t *ctx, mmap_region_t *mm, */ static action_t xlat_tables_map_region_action(const mmap_region_t *mm, const int desc_type, const unsigned long long dest_pa, - const uintptr_t table_entry_base_va, const int level) + const uintptr_t table_entry_base_va, const unsigned int level) { uintptr_t mm_end_va = mm->base_va + mm->size - 1; uintptr_t table_entry_end_va = From de3d704d74018b7104afad5a9b4cb19bc5de0611 Mon Sep 17 00:00:00 2001 From: Sandrine Bailleux Date: Thu, 20 Jul 2017 16:11:01 +0100 Subject: [PATCH 11/11] Emphasize that TF only supports 4 KB granule size At the moment, various parts of the Trusted Firmware code assume that the granule size used is 4 KB. For example, the linker scripts enforce 4 KB alignment restrictions on some sections. However, the ARMv8-A architecture allows 16 KB and 64 KB granule sizes as well. Some other parts of the TF code, particularly the architectural code and definitions, have been implemented with this in mind and cater for all 3 cases. This discrepancy creates some confusion as to what is effectively supported in TF. This patch adds some code comments and clarification in the documentation to make this limitation clearer. Change-Id: I1f202369b240d8bed9d43d57ecd2a548c86c8598 Signed-off-by: Sandrine Bailleux --- docs/porting-guide.rst | 15 ++++++++++----- include/lib/xlat_tables/xlat_tables_defs.h | 6 +++++- 2 files changed, 15 insertions(+), 6 deletions(-) diff --git a/docs/porting-guide.rst b/docs/porting-guide.rst index 66fe0f1d4..4d4cdcd6e 100644 --- a/docs/porting-guide.rst +++ b/docs/porting-guide.rst @@ -60,11 +60,16 @@ A platform port must enable the Memory Management Unit (MMU) as well as the instruction and data caches for each BL stage. Setting up the translation tables is the responsibility of the platform port because memory maps differ across platforms. A memory translation library (see ``lib/xlat_tables/``) is -provided to help in this setup. Note that although this library supports -non-identity mappings, this is intended only for re-mapping peripheral physical -addresses and allows platforms with high I/O addresses to reduce their virtual -address space. All other addresses corresponding to code and data must currently -use an identity mapping. +provided to help in this setup. + +Note that although this library supports non-identity mappings, this is intended +only for re-mapping peripheral physical addresses and allows platforms with high +I/O addresses to reduce their virtual address space. All other addresses +corresponding to code and data must currently use an identity mapping. + +Also, the only translation granule size supported in Trusted Firmware is 4KB, as +various parts of the code assume that is the case. It is not possible to switch +to 16 KB or 64 KB granule sizes at the moment. In ARM standard platforms, each BL stage configures the MMU in the platform-specific architecture setup function, ``blX_plat_arch_setup()``, and uses diff --git a/include/lib/xlat_tables/xlat_tables_defs.h b/include/lib/xlat_tables/xlat_tables_defs.h index 779532e9e..008ae9bc5 100644 --- a/include/lib/xlat_tables/xlat_tables_defs.h +++ b/include/lib/xlat_tables/xlat_tables_defs.h @@ -48,7 +48,11 @@ #define TABLE_ADDR_MASK ULL(0x0000FFFFFFFFF000) -#define PAGE_SIZE_SHIFT FOUR_KB_SHIFT /* 4, 16 or 64 KB */ +/* + * The ARMv8-A architecture allows translation granule sizes of 4KB, 16KB or + * 64KB. However, TF only supports the 4KB case at the moment. + */ +#define PAGE_SIZE_SHIFT FOUR_KB_SHIFT #define PAGE_SIZE (U(1) << PAGE_SIZE_SHIFT) #define PAGE_SIZE_MASK (PAGE_SIZE - 1) #define IS_PAGE_ALIGNED(addr) (((addr) & PAGE_SIZE_MASK) == 0)