diff --git a/include/arch/aarch64/arch.h b/include/arch/aarch64/arch.h index 9e2bfface..76c3e277b 100644 --- a/include/arch/aarch64/arch.h +++ b/include/arch/aarch64/arch.h @@ -204,6 +204,10 @@ /* ID_AA64MMFR2_EL1 definitions */ #define ID_AA64MMFR2_EL1 S3_0_C0_C7_2 + +#define ID_AA64MMFR2_EL1_ST_SHIFT U(28) +#define ID_AA64MMFR2_EL1_ST_MASK ULL(0xf) + #define ID_AA64MMFR2_EL1_CNP_SHIFT U(0) #define ID_AA64MMFR2_EL1_CNP_MASK ULL(0xf) @@ -427,6 +431,7 @@ #define TCR_TxSZ_MIN ULL(16) #define TCR_TxSZ_MAX ULL(39) +#define TCR_TxSZ_MAX_TTST ULL(48) /* (internal) physical address size bits in EL3/EL1 */ #define TCR_PS_BITS_4GB ULL(0x0) diff --git a/include/arch/aarch64/arch_features.h b/include/arch/aarch64/arch_features.h index 2b09ba07f..9bf43bf85 100644 --- a/include/arch/aarch64/arch_features.h +++ b/include/arch/aarch64/arch_features.h @@ -17,4 +17,10 @@ static inline bool is_armv8_2_ttcnp_present(void) ID_AA64MMFR2_EL1_CNP_MASK) != 0U; } +static inline bool is_armv8_4_ttst_present(void) +{ + return ((read_id_aa64mmfr2_el1() >> ID_AA64MMFR2_EL1_ST_SHIFT) & + ID_AA64MMFR2_EL1_ST_MASK) == 1U; +} + #endif /* ARCH_FEATURES_H */ diff --git a/include/lib/xlat_tables/aarch32/xlat_tables_aarch32.h b/include/lib/xlat_tables/aarch32/xlat_tables_aarch32.h index a333d1e4e..30eb5e9ec 100644 --- a/include/lib/xlat_tables/aarch32/xlat_tables_aarch32.h +++ b/include/lib/xlat_tables/aarch32/xlat_tables_aarch32.h @@ -63,8 +63,7 @@ * 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. + * valid. */ #define GET_XLAT_TABLE_LEVEL_BASE(_virt_addr_space_sz) \ (((_virt_addr_space_sz) > (ULL(1) << L1_XLAT_ADDRESS_SHIFT)) ? \ diff --git a/include/lib/xlat_tables/aarch64/xlat_tables_aarch64.h b/include/lib/xlat_tables/aarch64/xlat_tables_aarch64.h index cc5624c91..3014c8fea 100644 --- a/include/lib/xlat_tables/aarch64/xlat_tables_aarch64.h +++ b/include/lib/xlat_tables/aarch64/xlat_tables_aarch64.h @@ -43,14 +43,22 @@ unsigned long long tcr_physical_addr_size_bits(unsigned long long max_addr); * 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. + * The value of TCR.TxSZ must be in the range 16 to 39 [1] or 48 [2], + * depending on Small Translation Table Support which means that + * the virtual address space width must be in the range 48 to 25 or 16 bits. * * [1] See the ARMv8-A Architecture Reference Manual (DDI 0487A.j) for more * information: * Page 1730: 'Input address size', 'For all translation stages'. + * [2] See section 12.2.55 in the ARMv8-A Architecture Reference Manual + * (DDI 0487D.a) */ +/* Maximum value of TCR_ELx.T(0,1)SZ is 39 */ #define MIN_VIRT_ADDR_SPACE_SIZE (ULL(1) << (U(64) - TCR_TxSZ_MAX)) + +/* Maximum value of TCR_ELx.T(0,1)SZ is 48 */ +#define MIN_VIRT_ADDR_SPACE_SIZE_TTST \ + (ULL(1) << (U(64) - TCR_TxSZ_MAX_TTST)) #define MAX_VIRT_ADDR_SPACE_SIZE (ULL(1) << (U(64) - TCR_TxSZ_MIN)) /* @@ -58,9 +66,13 @@ unsigned long long tcr_physical_addr_size_bits(unsigned long long max_addr); * 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. + * - level 2 from 30 to 22. + * - level 3 from 21 to 16. * - * Wider or narrower address spaces are not supported. As a result, level 3 + * Small Translation Table (Armv8.4-TTST) support allows the starting level + * of the translation table from 3 for 4KB granularity. See section 12.2.55 in + * the ARMv8-A Architecture Reference Manual (DDI 0487D.a). In Armv8.3 and below + * 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. @@ -71,13 +83,14 @@ unsigned long long tcr_physical_addr_size_bits(unsigned long long max_addr); * 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. + * valid. */ #define GET_XLAT_TABLE_LEVEL_BASE(_virt_addr_space_sz) \ (((_virt_addr_space_sz) > (ULL(1) << L0_XLAT_ADDRESS_SHIFT)) \ ? 0U \ - : (((_virt_addr_space_sz) > (ULL(1) << L1_XLAT_ADDRESS_SHIFT)) \ - ? 1U : 2U)) + : (((_virt_addr_space_sz) > (ULL(1) << L1_XLAT_ADDRESS_SHIFT)) \ + ? 1U \ + : (((_virt_addr_space_sz) > (ULL(1) << L2_XLAT_ADDRESS_SHIFT)) \ + ? 2U : 3U))) #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 index 251b0206a..723753403 100644 --- a/include/lib/xlat_tables/xlat_tables_arch.h +++ b/include/lib/xlat_tables/xlat_tables_arch.h @@ -13,18 +13,6 @@ #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) \ - (((unsigned long long)(size) >= MIN_VIRT_ADDR_SPACE_SIZE) && \ - ((unsigned long long)(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. diff --git a/include/lib/xlat_tables/xlat_tables_v2_helpers.h b/include/lib/xlat_tables/xlat_tables_v2_helpers.h index ce5cf820a..6a1be3258 100644 --- a/include/lib/xlat_tables/xlat_tables_v2_helpers.h +++ b/include/lib/xlat_tables/xlat_tables_v2_helpers.h @@ -125,9 +125,6 @@ struct xlat_ctx { #define REGISTER_XLAT_CONTEXT_FULL_SPEC(_ctx_name, _mmap_count, \ _xlat_tables_count, _virt_addr_space_size, \ _phy_addr_space_size, _xlat_regime, _section_name)\ - 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);\ \ diff --git a/lib/xlat_tables/aarch32/xlat_tables.c b/lib/xlat_tables/aarch32/xlat_tables.c index 468a9e7dd..4b01b9b7a 100644 --- a/lib/xlat_tables/aarch32/xlat_tables.c +++ b/lib/xlat_tables/aarch32/xlat_tables.c @@ -55,6 +55,11 @@ void init_xlat_tables(void) { unsigned long long max_pa; uintptr_t max_va; + + assert(PLAT_VIRT_ADDR_SPACE_SIZE >= MIN_VIRT_ADDR_SPACE_SIZE); + assert(PLAT_VIRT_ADDR_SPACE_SIZE <= MAX_VIRT_ADDR_SPACE_SIZE); + assert(IS_POWER_OF_TWO(PLAT_VIRT_ADDR_SPACE_SIZE)); + print_mmap(); init_xlation_table(0U, base_xlation_table, XLAT_TABLE_LEVEL_BASE, &max_va, &max_pa); diff --git a/lib/xlat_tables/aarch64/xlat_tables.c b/lib/xlat_tables/aarch64/xlat_tables.c index 71f491a21..e64fd3ef7 100644 --- a/lib/xlat_tables/aarch64/xlat_tables.c +++ b/lib/xlat_tables/aarch64/xlat_tables.c @@ -10,7 +10,7 @@ #include #include -#include +#include #include #include #include @@ -79,6 +79,21 @@ static unsigned long long get_max_supported_pa(void) return (1ULL << pa_range_bits_arr[pa_range]) - 1ULL; } + +/* + * Return minimum virtual address space size supported by the architecture + */ +static uintptr_t xlat_get_min_virt_addr_space_size(void) +{ + uintptr_t ret; + + if (is_armv8_4_ttst_present()) + ret = MIN_VIRT_ADDR_SPACE_SIZE_TTST; + else + ret = MIN_VIRT_ADDR_SPACE_SIZE; + + return ret; +} #endif /* ENABLE_ASSERTIONS */ unsigned int xlat_arch_current_el(void) @@ -104,6 +119,12 @@ void init_xlat_tables(void) { unsigned long long max_pa; uintptr_t max_va; + + assert(PLAT_VIRT_ADDR_SPACE_SIZE >= + (xlat_get_min_virt_addr_space_size() - 1U)); + assert(PLAT_VIRT_ADDR_SPACE_SIZE <= MAX_VIRT_ADDR_SPACE_SIZE); + assert(IS_POWER_OF_TWO(PLAT_VIRT_ADDR_SPACE_SIZE)); + print_mmap(); init_xlation_table(0U, base_xlation_table, XLAT_TABLE_LEVEL_BASE, &max_va, &max_pa); diff --git a/lib/xlat_tables/xlat_tables_private.h b/lib/xlat_tables/xlat_tables_private.h index 4390f34ea..82bc70cd0 100644 --- a/lib/xlat_tables/xlat_tables_private.h +++ b/lib/xlat_tables/xlat_tables_private.h @@ -16,9 +16,6 @@ #error xlat tables v2 must be used with HW_ASSISTED_COHERENCY #endif -CASSERT(CHECK_VIRT_ADDR_SPACE_SIZE(PLAT_VIRT_ADDR_SPACE_SIZE), - assert_valid_virt_addr_space_size); - CASSERT(CHECK_PHY_ADDR_SPACE_SIZE(PLAT_PHY_ADDR_SPACE_SIZE), assert_valid_phy_addr_space_size); diff --git a/lib/xlat_tables_v2/aarch32/xlat_tables_arch.c b/lib/xlat_tables_v2/aarch32/xlat_tables_arch.c index 913c86d39..b69c6702b 100644 --- a/lib/xlat_tables_v2/aarch32/xlat_tables_arch.c +++ b/lib/xlat_tables_v2/aarch32/xlat_tables_arch.c @@ -45,6 +45,14 @@ unsigned long long xlat_arch_get_max_supported_pa(void) /* Physical address space size for long descriptor format. */ return (1ULL << 40) - 1ULL; } + +/* + * Return minimum virtual address space size supported by the architecture + */ +uintptr_t xlat_get_min_virt_addr_space_size(void) +{ + return MIN_VIRT_ADDR_SPACE_SIZE; +} #endif /* ENABLE_ASSERTIONS*/ bool is_mmu_enabled_ctx(const xlat_ctx_t *ctx) @@ -193,7 +201,12 @@ void setup_mmu_cfg(uint64_t *params, unsigned int flags, if (max_va != UINT32_MAX) { uintptr_t virtual_addr_space_size = max_va + 1U; - assert(CHECK_VIRT_ADDR_SPACE_SIZE(virtual_addr_space_size)); + assert(virtual_addr_space_size >= + xlat_get_min_virt_addr_space_size()); + assert(virtual_addr_space_size <= + MAX_VIRT_ADDR_SPACE_SIZE); + assert(IS_POWER_OF_TWO(virtual_addr_space_size)); + /* * __builtin_ctzll(0) is undefined but here we are guaranteed * that virtual_addr_space_size is in the range [1, UINT32_MAX]. diff --git a/lib/xlat_tables_v2/aarch64/xlat_tables_arch.c b/lib/xlat_tables_v2/aarch64/xlat_tables_arch.c index 228f75147..e7593dde7 100644 --- a/lib/xlat_tables_v2/aarch64/xlat_tables_arch.c +++ b/lib/xlat_tables_v2/aarch64/xlat_tables_arch.c @@ -101,6 +101,21 @@ unsigned long long xlat_arch_get_max_supported_pa(void) return (1ULL << pa_range_bits_arr[pa_range]) - 1ULL; } + +/* + * Return minimum virtual address space size supported by the architecture + */ +uintptr_t xlat_get_min_virt_addr_space_size(void) +{ + uintptr_t ret; + + if (is_armv8_4_ttst_present()) + ret = MIN_VIRT_ADDR_SPACE_SIZE_TTST; + else + ret = MIN_VIRT_ADDR_SPACE_SIZE; + + return ret; +} #endif /* ENABLE_ASSERTIONS*/ bool is_mmu_enabled_ctx(const xlat_ctx_t *ctx) @@ -221,7 +236,11 @@ void setup_mmu_cfg(uint64_t *params, unsigned int flags, assert(max_va < ((uint64_t)UINTPTR_MAX)); virtual_addr_space_size = (uintptr_t)max_va + 1U; - assert(CHECK_VIRT_ADDR_SPACE_SIZE(virtual_addr_space_size)); + + assert(virtual_addr_space_size >= + xlat_get_min_virt_addr_space_size()); + assert(virtual_addr_space_size <= MAX_VIRT_ADDR_SPACE_SIZE); + assert(IS_POWER_OF_TWO(virtual_addr_space_size)); /* * __builtin_ctzll(0) is undefined but here we are guaranteed that diff --git a/lib/xlat_tables_v2/xlat_tables_core.c b/lib/xlat_tables_v2/xlat_tables_core.c index c49554f1f..4820b4f80 100644 --- a/lib/xlat_tables_v2/xlat_tables_core.c +++ b/lib/xlat_tables_v2/xlat_tables_core.c @@ -1146,6 +1146,11 @@ void __init init_xlat_tables_ctx(xlat_ctx_t *ctx) mmap_region_t *mm = ctx->mmap; + assert(ctx->va_max_address >= + (xlat_get_min_virt_addr_space_size() - 1U)); + assert(ctx->va_max_address <= (MAX_VIRT_ADDR_SPACE_SIZE - 1U)); + assert(IS_POWER_OF_TWO(ctx->va_max_address + 1U)); + xlat_mmap_print(mm); /* All tables must be zeroed before mapping any region. */ diff --git a/lib/xlat_tables_v2/xlat_tables_private.h b/lib/xlat_tables_v2/xlat_tables_private.h index fc709554b..70ef39523 100644 --- a/lib/xlat_tables_v2/xlat_tables_private.h +++ b/lib/xlat_tables_v2/xlat_tables_private.h @@ -102,4 +102,9 @@ bool is_mmu_enabled_ctx(const xlat_ctx_t *ctx); /* Returns true if the data cache is enabled at the current EL. */ bool is_dcache_enabled(void); +/* + * Returns minimum virtual address space size supported by the architecture + */ +uintptr_t xlat_get_min_virt_addr_space_size(void); + #endif /* XLAT_TABLES_PRIVATE_H */