diff options
-rw-r--r-- | Makefile | 1 | ||||
-rw-r--r-- | include/lib/xlat_tables/xlat_mmu_helpers.h | 43 | ||||
-rw-r--r-- | include/lib/xlat_tables/xlat_tables.h | 115 | ||||
-rw-r--r-- | include/lib/xlat_tables/xlat_tables_defs.h (renamed from include/lib/xlat_tables.h) | 128 | ||||
-rw-r--r-- | include/lib/xlat_tables/xlat_tables_v2.h | 126 | ||||
-rw-r--r-- | lib/xlat_tables_v2/aarch32/xlat_tables_arch.c | 125 | ||||
-rw-r--r-- | lib/xlat_tables_v2/aarch32/xlat_tables_arch.h | 95 | ||||
-rw-r--r-- | lib/xlat_tables_v2/aarch64/xlat_tables_arch.c | 203 | ||||
-rw-r--r-- | lib/xlat_tables_v2/aarch64/xlat_tables_arch.h | 108 | ||||
-rw-r--r-- | lib/xlat_tables_v2/xlat_tables.mk | 34 | ||||
-rw-r--r-- | lib/xlat_tables_v2/xlat_tables_common.c | 140 | ||||
-rw-r--r-- | lib/xlat_tables_v2/xlat_tables_internal.c | 667 | ||||
-rw-r--r-- | lib/xlat_tables_v2/xlat_tables_private.h | 137 |
13 files changed, 1821 insertions, 101 deletions
@@ -186,6 +186,7 @@ INCLUDES += -Iinclude/bl1 \ -Iinclude/lib/el3_runtime/${ARCH} \ -Iinclude/lib/pmf \ -Iinclude/lib/psci \ + -Iinclude/lib/xlat_tables \ -Iinclude/plat/common \ -Iinclude/services \ ${PLAT_INCLUDES} \ diff --git a/include/lib/xlat_tables/xlat_mmu_helpers.h b/include/lib/xlat_tables/xlat_mmu_helpers.h new file mode 100644 index 000000000..260ef3e9d --- /dev/null +++ b/include/lib/xlat_tables/xlat_mmu_helpers.h @@ -0,0 +1,43 @@ +/* + * Copyright (c) 2014-2017, ARM Limited and Contributors. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are met: + * + * Redistributions of source code must retain the above copyright notice, this + * list of conditions and the following disclaimer. + * + * Redistributions in binary form must reproduce the above copyright notice, + * this list of conditions and the following disclaimer in the documentation + * and/or other materials provided with the distribution. + * + * Neither the name of ARM nor the names of its contributors may be used + * to endorse or promote products derived from this software without specific + * prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" + * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE + * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR + * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF + * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS + * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN + * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) + * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE + * POSSIBILITY OF SUCH DAMAGE. + */ + +#ifndef __XLAT_MMU_HELPERS_H__ +#define __XLAT_MMU_HELPERS_H__ + +#ifdef AARCH32 +/* AArch32 specific translation table API */ +void enable_mmu_secure(uint32_t flags); +#else +/* AArch64 specific translation table APIs */ +void enable_mmu_el1(unsigned int flags); +void enable_mmu_el3(unsigned int flags); +#endif /* AARCH32 */ + +#endif /* __XLAT_MMU_HELPERS_H__ */ diff --git a/include/lib/xlat_tables/xlat_tables.h b/include/lib/xlat_tables/xlat_tables.h new file mode 100644 index 000000000..4e855032b --- /dev/null +++ b/include/lib/xlat_tables/xlat_tables.h @@ -0,0 +1,115 @@ +/* + * Copyright (c) 2014-2017, ARM Limited and Contributors. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are met: + * + * Redistributions of source code must retain the above copyright notice, this + * list of conditions and the following disclaimer. + * + * Redistributions in binary form must reproduce the above copyright notice, + * this list of conditions and the following disclaimer in the documentation + * and/or other materials provided with the distribution. + * + * Neither the name of ARM nor the names of its contributors may be used + * to endorse or promote products derived from this software without specific + * prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" + * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE + * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR + * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF + * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS + * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN + * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) + * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE + * POSSIBILITY OF SUCH DAMAGE. + */ + +#ifndef __XLAT_TABLES_H__ +#define __XLAT_TABLES_H__ + +#include <xlat_tables_defs.h> + +#ifndef __ASSEMBLY__ +#include <stddef.h> +#include <stdint.h> +#include <xlat_mmu_helpers.h> + +/* Helper macro to define entries for mmap_region_t. It creates + * identity mappings for each region. + */ +#define MAP_REGION_FLAT(adr, sz, attr) MAP_REGION(adr, adr, sz, attr) + +/* Helper macro to define entries for mmap_region_t. It allows to + * re-map address mappings from 'pa' to 'va' for each region. + */ +#define MAP_REGION(pa, va, sz, attr) {(pa), (va), (sz), (attr)} + +/* + * Shifts and masks to access fields of an mmap_attr_t + */ +#define MT_TYPE_MASK 0x7 +#define MT_TYPE(_attr) ((_attr) & MT_TYPE_MASK) +/* Access permissions (RO/RW) */ +#define MT_PERM_SHIFT 3 +/* Security state (SECURE/NS) */ +#define MT_SEC_SHIFT 4 +/* Access permissions for instruction execution (EXECUTE/EXECUTE_NEVER) */ +#define MT_EXECUTE_SHIFT 5 + +/* + * Memory mapping attributes + */ +typedef enum { + /* + * Memory types supported. + * These are organised so that, going down the list, the memory types + * are getting weaker; conversely going up the list the memory types are + * getting stronger. + */ + MT_DEVICE, + MT_NON_CACHEABLE, + MT_MEMORY, + /* Values up to 7 are reserved to add new memory types in the future */ + + MT_RO = 0 << MT_PERM_SHIFT, + MT_RW = 1 << MT_PERM_SHIFT, + + MT_SECURE = 0 << MT_SEC_SHIFT, + MT_NS = 1 << MT_SEC_SHIFT, + + /* + * Access permissions for instruction execution are only relevant for + * normal read-only memory, i.e. MT_MEMORY | MT_RO. They are ignored + * (and potentially overridden) otherwise: + * - Device memory is always marked as execute-never. + * - Read-write normal memory is always marked as execute-never. + */ + MT_EXECUTE = 0 << MT_EXECUTE_SHIFT, + MT_EXECUTE_NEVER = 1 << MT_EXECUTE_SHIFT, +} mmap_attr_t; + +#define MT_CODE (MT_MEMORY | MT_RO | MT_EXECUTE) +#define MT_RO_DATA (MT_MEMORY | MT_RO | MT_EXECUTE_NEVER) + +/* + * Structure for specifying a single region of memory. + */ +typedef struct mmap_region { + unsigned long long base_pa; + uintptr_t base_va; + size_t size; + mmap_attr_t attr; +} mmap_region_t; + +/* Generic translation table APIs */ +void init_xlat_tables(void); +void mmap_add_region(unsigned long long base_pa, uintptr_t base_va, + size_t size, unsigned int attr); +void mmap_add(const mmap_region_t *mm); + +#endif /*__ASSEMBLY__*/ +#endif /* __XLAT_TABLES_H__ */ diff --git a/include/lib/xlat_tables.h b/include/lib/xlat_tables/xlat_tables_defs.h index f44761836..1f4ae6d0c 100644 --- a/include/lib/xlat_tables.h +++ b/include/lib/xlat_tables/xlat_tables_defs.h @@ -1,5 +1,5 @@ /* - * Copyright (c) 2014-2016, ARM Limited and Contributors. All rights reserved. + * Copyright (c) 2017, ARM Limited and Contributors. All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions are met: @@ -28,8 +28,10 @@ * POSSIBILITY OF SUCH DAMAGE. */ -#ifndef __XLAT_TABLES_H__ -#define __XLAT_TABLES_H__ +#ifndef __XLAT_TABLES_DEFS_H__ +#define __XLAT_TABLES_DEFS_H__ + +#include <utils.h> /* Miscellaneous MMU related constants */ #define NUM_2MB_IN_GB (1 << 9) @@ -48,23 +50,26 @@ #define BLOCK_DESC 0x1 /* Table levels 0-2 */ #define TABLE_DESC 0x3 /* Table levels 0-2 */ #define PAGE_DESC 0x3 /* Table level 3 */ +#define DESC_MASK 0x3 #define FIRST_LEVEL_DESC_N ONE_GB_SHIFT #define SECOND_LEVEL_DESC_N TWO_MB_SHIFT #define THIRD_LEVEL_DESC_N FOUR_KB_SHIFT -#define XN (1ull << 2) -#define PXN (1ull << 1) -#define CONT_HINT (1ull << 0) +#define XN (ULL(1) << 2) +#define PXN (ULL(1) << 1) +#define CONT_HINT (ULL(1) << 0) +#define UPPER_ATTRS(x) (((x) & ULL(0x7)) << 52) -#define UPPER_ATTRS(x) (x & 0x7) << 52 #define NON_GLOBAL (1 << 9) #define ACCESS_FLAG (1 << 8) #define NSH (0x0 << 6) #define OSH (0x2 << 6) #define ISH (0x3 << 6) -#define PAGE_SIZE_SHIFT FOUR_KB_SHIFT +#define TABLE_ADDR_MASK ULL(0x0000FFFFFFFFF000) + +#define PAGE_SIZE_SHIFT FOUR_KB_SHIFT /* 4, 16 or 64 KB */ #define PAGE_SIZE (1 << PAGE_SIZE_SHIFT) #define PAGE_SIZE_MASK (PAGE_SIZE - 1) #define IS_PAGE_ALIGNED(addr) (((addr) & PAGE_SIZE_MASK) == 0) @@ -72,7 +77,7 @@ #define XLAT_ENTRY_SIZE_SHIFT 3 /* Each MMU table entry is 8 bytes (1 << 3) */ #define XLAT_ENTRY_SIZE (1 << XLAT_ENTRY_SIZE_SHIFT) -#define XLAT_TABLE_SIZE_SHIFT PAGE_SIZE_SHIFT +#define XLAT_TABLE_SIZE_SHIFT PAGE_SIZE_SHIFT /* Size of one complete table */ #define XLAT_TABLE_SIZE (1 << XLAT_TABLE_SIZE_SHIFT) #ifdef AARCH32 @@ -97,116 +102,37 @@ ((XLAT_TABLE_LEVEL_MAX - (level)) * XLAT_TABLE_ENTRIES_SHIFT)) #define XLAT_BLOCK_SIZE(level) ((u_register_t)1 << XLAT_ADDR_SHIFT(level)) +/* Mask to get the bits used to index inside a block of a certain level */ #define XLAT_BLOCK_MASK(level) (XLAT_BLOCK_SIZE(level) - 1) +/* Mask to get the address bits common to a block of a certain table level*/ +#define XLAT_ADDR_MASK(level) (~XLAT_BLOCK_MASK(level)) /* * AP[1] bit is ignored by hardware and is * treated as if it is One in EL2/EL3 */ -#define AP_RO (0x1 << 5) -#define AP_RW (0x0 << 5) +#define AP_RO (0x1 << 5) +#define AP_RW (0x0 << 5) #define NS (0x1 << 3) #define ATTR_NON_CACHEABLE_INDEX 0x2 #define ATTR_DEVICE_INDEX 0x1 #define ATTR_IWBWA_OWBWA_NTR_INDEX 0x0 #define LOWER_ATTRS(x) (((x) & 0xfff) << 2) +/* Normal Memory, Outer Write-Through non-transient, Inner Non-cacheable */ #define ATTR_NON_CACHEABLE (0x44) +/* Device-nGnRE */ #define ATTR_DEVICE (0x4) +/* Normal Memory, Outer Write-Back non-transient, Inner Write-Back non-transient */ #define ATTR_IWBWA_OWBWA_NTR (0xff) -#define MAIR_ATTR_SET(attr, index) (attr << (index << 3)) +#define MAIR_ATTR_SET(attr, index) ((attr) << ((index) << 3)) +#define ATTR_INDEX_MASK 0x3 +#define ATTR_INDEX_GET(attr) (((attr) >> 2) & ATTR_INDEX_MASK) /* * Flags to override default values used to program system registers while * enabling the MMU. */ -#define DISABLE_DCACHE (1 << 0) - -#ifndef __ASSEMBLY__ -#include <stddef.h> -#include <stdint.h> - -/* Helper macro to define entries for mmap_region_t. It creates - * identity mappings for each region. - */ -#define MAP_REGION_FLAT(adr, sz, attr) MAP_REGION(adr, adr, sz, attr) - -/* Helper macro to define entries for mmap_region_t. It allows to - * re-map address mappings from 'pa' to 'va' for each region. - */ -#define MAP_REGION(pa, va, sz, attr) {(pa), (va), (sz), (attr)} - -/* - * Shifts and masks to access fields of an mmap_attr_t - */ -#define MT_TYPE_MASK 0x7 -#define MT_TYPE(_attr) ((_attr) & MT_TYPE_MASK) -/* Access permissions (RO/RW) */ -#define MT_PERM_SHIFT 3 -/* Security state (SECURE/NS) */ -#define MT_SEC_SHIFT 4 -/* Access permissions for instruction execution (EXECUTE/EXECUTE_NEVER) */ -#define MT_EXECUTE_SHIFT 5 - -/* - * Memory mapping attributes - */ -typedef enum { - /* - * Memory types supported. - * These are organised so that, going down the list, the memory types - * are getting weaker; conversely going up the list the memory types are - * getting stronger. - */ - MT_DEVICE, - MT_NON_CACHEABLE, - MT_MEMORY, - /* Values up to 7 are reserved to add new memory types in the future */ - - MT_RO = 0 << MT_PERM_SHIFT, - MT_RW = 1 << MT_PERM_SHIFT, - - MT_SECURE = 0 << MT_SEC_SHIFT, - MT_NS = 1 << MT_SEC_SHIFT, - - /* - * Access permissions for instruction execution are only relevant for - * normal read-only memory, i.e. MT_MEMORY | MT_RO. They are ignored - * (and potentially overridden) otherwise: - * - Device memory is always marked as execute-never. - * - Read-write normal memory is always marked as execute-never. - */ - MT_EXECUTE = 0 << MT_EXECUTE_SHIFT, - MT_EXECUTE_NEVER = 1 << MT_EXECUTE_SHIFT, -} mmap_attr_t; - -#define MT_CODE (MT_MEMORY | MT_RO | MT_EXECUTE) -#define MT_RO_DATA (MT_MEMORY | MT_RO | MT_EXECUTE_NEVER) - -/* - * Structure for specifying a single region of memory. - */ -typedef struct mmap_region { - unsigned long long base_pa; - uintptr_t base_va; - size_t size; - mmap_attr_t attr; -} mmap_region_t; - -/* Generic translation table APIs */ -void init_xlat_tables(void); -void mmap_add_region(unsigned long long base_pa, uintptr_t base_va, - size_t size, unsigned int attr); -void mmap_add(const mmap_region_t *mm); - -#ifdef AARCH32 -/* AArch32 specific translation table API */ -void enable_mmu_secure(uint32_t flags); -#else -/* AArch64 specific translation table APIs */ -void enable_mmu_el1(unsigned int flags); -void enable_mmu_el3(unsigned int flags); -#endif /* AARCH32 */ +#define DISABLE_DCACHE (1 << 0) -#endif /*__ASSEMBLY__*/ -#endif /* __XLAT_TABLES_H__ */ +#endif /* __XLAT_TABLES_DEFS_H__ */ diff --git a/include/lib/xlat_tables/xlat_tables_v2.h b/include/lib/xlat_tables/xlat_tables_v2.h new file mode 100644 index 000000000..6fec57d4c --- /dev/null +++ b/include/lib/xlat_tables/xlat_tables_v2.h @@ -0,0 +1,126 @@ +/* + * Copyright (c) 2017, ARM Limited and Contributors. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are met: + * + * Redistributions of source code must retain the above copyright notice, this + * list of conditions and the following disclaimer. + * + * Redistributions in binary form must reproduce the above copyright notice, + * this list of conditions and the following disclaimer in the documentation + * and/or other materials provided with the distribution. + * + * Neither the name of ARM nor the names of its contributors may be used + * to endorse or promote products derived from this software without specific + * prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" + * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE + * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR + * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF + * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS + * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN + * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) + * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE + * POSSIBILITY OF SUCH DAMAGE. + */ + +#ifndef __XLAT_TABLES_V2_H__ +#define __XLAT_TABLES_V2_H__ + +#include <xlat_tables_defs.h> + +#ifndef __ASSEMBLY__ +#include <stddef.h> +#include <stdint.h> +#include <xlat_mmu_helpers.h> + +/* Helper macro to define entries for mmap_region_t. It creates + * identity mappings for each region. + */ +#define MAP_REGION_FLAT(adr, sz, attr) MAP_REGION(adr, adr, sz, attr) + +/* Helper macro to define entries for mmap_region_t. It allows to + * re-map address mappings from 'pa' to 'va' for each region. + */ +#define MAP_REGION(pa, va, sz, attr) {(pa), (va), (sz), (attr)} + +/* + * Shifts and masks to access fields of an mmap_attr_t + */ +#define MT_TYPE_MASK 0x7 +#define MT_TYPE(_attr) ((_attr) & MT_TYPE_MASK) +/* Access permissions (RO/RW) */ +#define MT_PERM_SHIFT 3 +/* Security state (SECURE/NS) */ +#define MT_SEC_SHIFT 4 +/* Access permissions for instruction execution (EXECUTE/EXECUTE_NEVER) */ +#define MT_EXECUTE_SHIFT 5 + +/* + * Memory mapping attributes + */ +typedef enum { + /* + * Memory types supported. + * These are organised so that, going down the list, the memory types + * are getting weaker; conversely going up the list the memory types are + * getting stronger. + */ + MT_DEVICE, + MT_NON_CACHEABLE, + MT_MEMORY, + /* Values up to 7 are reserved to add new memory types in the future */ + + MT_RO = 0 << MT_PERM_SHIFT, + MT_RW = 1 << MT_PERM_SHIFT, + + MT_SECURE = 0 << MT_SEC_SHIFT, + MT_NS = 1 << MT_SEC_SHIFT, + + /* + * Access permissions for instruction execution are only relevant for + * normal read-only memory, i.e. MT_MEMORY | MT_RO. They are ignored + * (and potentially overridden) otherwise: + * - Device memory is always marked as execute-never. + * - Read-write normal memory is always marked as execute-never. + */ + MT_EXECUTE = 0 << MT_EXECUTE_SHIFT, + MT_EXECUTE_NEVER = 1 << MT_EXECUTE_SHIFT, +} mmap_attr_t; + +#define MT_CODE (MT_MEMORY | MT_RO | MT_EXECUTE) +#define MT_RO_DATA (MT_MEMORY | MT_RO | MT_EXECUTE_NEVER) + +/* + * Structure for specifying a single region of memory. + */ +typedef struct mmap_region { + unsigned long long base_pa; + uintptr_t base_va; + size_t size; + mmap_attr_t attr; +} mmap_region_t; + +/* Generic translation table APIs */ +void init_xlat_tables(void); + +/* + * Add a region with defined base PA and base VA. This type of region can only + * be added before initializing the MMU and cannot be removed later. + */ +void mmap_add_region(unsigned long long base_pa, uintptr_t base_va, + size_t size, unsigned int attr); + +/* + * Add an array of static regions with defined base PA and base VA. This type + * of region can only be added before initializing the MMU and cannot be + * removed later. + */ +void mmap_add(const mmap_region_t *mm); + +#endif /*__ASSEMBLY__*/ +#endif /* __XLAT_TABLES_V2_H__ */ diff --git a/lib/xlat_tables_v2/aarch32/xlat_tables_arch.c b/lib/xlat_tables_v2/aarch32/xlat_tables_arch.c new file mode 100644 index 000000000..9a08cf8ea --- /dev/null +++ b/lib/xlat_tables_v2/aarch32/xlat_tables_arch.c @@ -0,0 +1,125 @@ +/* + * Copyright (c) 2017, ARM Limited and Contributors. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are met: + * + * Redistributions of source code must retain the above copyright notice, this + * list of conditions and the following disclaimer. + * + * Redistributions in binary form must reproduce the above copyright notice, + * this list of conditions and the following disclaimer in the documentation + * and/or other materials provided with the distribution. + * + * Neither the name of ARM nor the names of its contributors may be used + * to endorse or promote products derived from this software without specific + * prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" + * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE + * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR + * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF + * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS + * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN + * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) + * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE + * POSSIBILITY OF SUCH DAMAGE. + */ + +#include <arch.h> +#include <arch_helpers.h> +#include <assert.h> +#include <cassert.h> +#include <platform_def.h> +#include <utils.h> +#include <xlat_tables_v2.h> +#include "../xlat_tables_private.h" + +#if DEBUG +static unsigned long long xlat_arch_get_max_supported_pa(void) +{ + /* Physical address space size for long descriptor format. */ + return (1ull << 40) - 1ull; +} +#endif /* DEBUG*/ + +int is_mmu_enabled(void) +{ + return (read_sctlr() & SCTLR_M_BIT) != 0; +} + +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; + + assert(IS_IN_SECURE()); + assert((read_sctlr() & SCTLR_M_BIT) == 0); + + /* Invalidate TLBs at the current exception level */ + tlbiall(); + + /* Set attributes in the right indices of the MAIR */ + mair0 = MAIR0_ATTR_SET(ATTR_DEVICE, ATTR_DEVICE_INDEX); + mair0 |= MAIR0_ATTR_SET(ATTR_IWBWA_OWBWA_NTR, + 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 as Inner + * & outer WBWA & shareable. Disable TTBR1. + */ + 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_EPD1_BIT; + write_ttbcr(ttbcr); + + /* Set TTBR0 bits as well */ + ttbr0 = (uint64_t)(uintptr_t) base_table; + write64_ttbr0(ttbr0); + write64_ttbr1(0); + + /* + * Ensure all translation table writes have drained + * into memory, the TLB invalidation is complete, + * and translation register writes are committed + * before enabling the MMU + */ + dsb(); + isb(); + + sctlr = read_sctlr(); + sctlr |= SCTLR_WXN_BIT | SCTLR_M_BIT; + + if (flags & DISABLE_DCACHE) + sctlr &= ~SCTLR_C_BIT; + else + sctlr |= SCTLR_C_BIT; + + write_sctlr(sctlr); + + /* Ensure the MMU enable takes effect immediately */ + isb(); +} + +void enable_mmu_arch(unsigned int flags, uint64_t *base_table) +{ + enable_mmu_internal_secure(flags, base_table); +} diff --git a/lib/xlat_tables_v2/aarch32/xlat_tables_arch.h b/lib/xlat_tables_v2/aarch32/xlat_tables_arch.h new file mode 100644 index 000000000..070877bb7 --- /dev/null +++ b/lib/xlat_tables_v2/aarch32/xlat_tables_arch.h @@ -0,0 +1,95 @@ +/* + * Copyright (c) 2017, ARM Limited and Contributors. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are met: + * + * Redistributions of source code must retain the above copyright notice, this + * list of conditions and the following disclaimer. + * + * Redistributions in binary form must reproduce the above copyright notice, + * this list of conditions and the following disclaimer in the documentation + * and/or other materials provided with the distribution. + * + * Neither the name of ARM nor the names of its contributors may be used + * to endorse or promote products derived from this software without specific + * prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" + * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE + * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR + * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF + * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS + * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN + * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) + * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE + * POSSIBILITY OF SUCH DAMAGE. + */ + +#ifndef __XLAT_TABLES_ARCH_H__ +#define __XLAT_TABLES_ARCH_H__ + +#include <arch.h> +#include <platform_def.h> +#include <xlat_tables_defs.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.c b/lib/xlat_tables_v2/aarch64/xlat_tables_arch.c new file mode 100644 index 000000000..413eaded1 --- /dev/null +++ b/lib/xlat_tables_v2/aarch64/xlat_tables_arch.c @@ -0,0 +1,203 @@ +/* + * Copyright (c) 2017, ARM Limited and Contributors. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are met: + * + * Redistributions of source code must retain the above copyright notice, this + * list of conditions and the following disclaimer. + * + * Redistributions in binary form must reproduce the above copyright notice, + * this list of conditions and the following disclaimer in the documentation + * and/or other materials provided with the distribution. + * + * Neither the name of ARM nor the names of its contributors may be used + * to endorse or promote products derived from this software without specific + * prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" + * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE + * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR + * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF + * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS + * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN + * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) + * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE + * POSSIBILITY OF SUCH DAMAGE. + */ + +#include <arch.h> +#include <arch_helpers.h> +#include <assert.h> +#include <bl_common.h> +#include <cassert.h> +#include <common_def.h> +#include <platform_def.h> +#include <sys/types.h> +#include <utils.h> +#include <xlat_tables_v2.h> +#include "../xlat_tables_private.h" + +#if defined(IMAGE_BL1) || defined(IMAGE_BL31) +# define IMAGE_EL 3 +#else +# define IMAGE_EL 1 +#endif + +static unsigned long long tcr_ps_bits; + +static unsigned long long calc_physical_addr_size_bits( + unsigned long long max_addr) +{ + /* Physical address can't exceed 48 bits */ + assert((max_addr & ADDR_MASK_48_TO_63) == 0); + + /* 48 bits address */ + if (max_addr & ADDR_MASK_44_TO_47) + return TCR_PS_BITS_256TB; + + /* 44 bits address */ + if (max_addr & ADDR_MASK_42_TO_43) + return TCR_PS_BITS_16TB; + + /* 42 bits address */ + if (max_addr & ADDR_MASK_40_TO_41) + return TCR_PS_BITS_4TB; + + /* 40 bits address */ + if (max_addr & ADDR_MASK_36_TO_39) + return TCR_PS_BITS_1TB; + + /* 36 bits address */ + if (max_addr & ADDR_MASK_32_TO_35) + return TCR_PS_BITS_64GB; + + return TCR_PS_BITS_4GB; +} + +#if DEBUG +/* Physical Address ranges supported in the AArch64 Memory Model */ +static const unsigned int pa_range_bits_arr[] = { + PARANGE_0000, PARANGE_0001, PARANGE_0010, PARANGE_0011, PARANGE_0100, + PARANGE_0101 +}; + +unsigned long long xlat_arch_get_max_supported_pa(void) +{ + u_register_t pa_range = read_id_aa64mmfr0_el1() & + ID_AA64MMFR0_EL1_PARANGE_MASK; + + /* All other values are reserved */ + assert(pa_range < ARRAY_SIZE(pa_range_bits_arr)); + + return (1ull << pa_range_bits_arr[pa_range]) - 1ull; +} +#endif /* DEBUG*/ + +int is_mmu_enabled(void) +{ +#if IMAGE_EL == 1 + assert(IS_IN_EL(1)); + return (read_sctlr_el1() & SCTLR_M_BIT) != 0; +#elif IMAGE_EL == 3 + assert(IS_IN_EL(3)); + return (read_sctlr_el3() & SCTLR_M_BIT) != 0; +#endif +} + +void init_xlat_tables_arch(unsigned long long max_pa) +{ + assert((PLAT_PHY_ADDR_SPACE_SIZE - 1) <= + xlat_arch_get_max_supported_pa()); + + tcr_ps_bits = calc_physical_addr_size_bits(max_pa); +} + +/******************************************************************************* + * Macro generating the code for the function enabling the MMU in the given + * 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) \ + { \ + uint64_t mair, tcr, ttbr; \ + uint32_t sctlr; \ + \ + assert(IS_IN_EL(_el)); \ + assert((read_sctlr_el##_el() & 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. */ \ + /* Inner & outer WBWA & shareable. */ \ + /* Set T0SZ to (64 - width of virtual address space) */ \ + 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 */ \ + /* into memory, the TLB invalidation is complete, */ \ + /* and translation register writes are committed */ \ + /* before enabling the MMU */ \ + dsb(); \ + isb(); \ + \ + sctlr = read_sctlr_el##_el(); \ + sctlr |= SCTLR_WXN_BIT | SCTLR_M_BIT; \ + \ + if (flags & DISABLE_DCACHE) \ + sctlr &= ~SCTLR_C_BIT; \ + else \ + sctlr |= SCTLR_C_BIT; \ + \ + write_sctlr_el##_el(sctlr); \ + \ + /* Ensure the MMU enable takes effect immediately */ \ + isb(); \ + } + +/* 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) +#elif IMAGE_EL == 3 +DEFINE_ENABLE_MMU_EL(3, + TCR_EL3_RES1 | (tcr_ps_bits << TCR_EL3_PS_SHIFT), + tlbialle3) +#endif + +void enable_mmu_arch(unsigned int flags, uint64_t *base_table) +{ +#if IMAGE_EL == 1 + assert(IS_IN_EL(1)); + enable_mmu_internal_el1(flags, base_table); +#elif IMAGE_EL == 3 + assert(IS_IN_EL(3)); + enable_mmu_internal_el3(flags, base_table); +#endif +} diff --git a/lib/xlat_tables_v2/aarch64/xlat_tables_arch.h b/lib/xlat_tables_v2/aarch64/xlat_tables_arch.h new file mode 100644 index 000000000..3336b62d9 --- /dev/null +++ b/lib/xlat_tables_v2/aarch64/xlat_tables_arch.h @@ -0,0 +1,108 @@ +/* + * Copyright (c) 2017, ARM Limited and Contributors. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are met: + * + * Redistributions of source code must retain the above copyright notice, this + * list of conditions and the following disclaimer. + * + * Redistributions in binary form must reproduce the above copyright notice, + * this list of conditions and the following disclaimer in the documentation + * and/or other materials provided with the distribution. + * + * Neither the name of ARM nor the names of its contributors may be used + * to endorse or promote products derived from this software without specific + * prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" + * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE + * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR + * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF + * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS + * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN + * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) + * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE + * POSSIBILITY OF SUCH DAMAGE. + */ + +#ifndef __XLAT_TABLES_ARCH_H__ +#define __XLAT_TABLES_ARCH_H__ + +#include <arch.h> +#include <platform_def.h> +#include <xlat_tables_defs.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.mk b/lib/xlat_tables_v2/xlat_tables.mk new file mode 100644 index 000000000..3d4b2a073 --- /dev/null +++ b/lib/xlat_tables_v2/xlat_tables.mk @@ -0,0 +1,34 @@ +# +# Copyright (c) 2017, ARM Limited and Contributors. All rights reserved. +# +# Redistribution and use in source and binary forms, with or without +# modification, are permitted provided that the following conditions are met: +# +# Redistributions of source code must retain the above copyright notice, this +# list of conditions and the following disclaimer. +# +# Redistributions in binary form must reproduce the above copyright notice, +# this list of conditions and the following disclaimer in the documentation +# and/or other materials provided with the distribution. +# +# Neither the name of ARM nor the names of its contributors may be used +# to endorse or promote products derived from this software without specific +# prior written permission. +# +# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" +# AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE +# IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE +# ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE +# LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR +# CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF +# SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS +# INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN +# CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) +# ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE +# POSSIBILITY OF SUCH DAMAGE. +# + +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 new file mode 100644 index 000000000..0b17842ca --- /dev/null +++ b/lib/xlat_tables_v2/xlat_tables_common.c @@ -0,0 +1,140 @@ +/* + * Copyright (c) 2017, ARM Limited and Contributors. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are met: + * + * Redistributions of source code must retain the above copyright notice, this + * list of conditions and the following disclaimer. + * + * Redistributions in binary form must reproduce the above copyright notice, + * this list of conditions and the following disclaimer in the documentation + * and/or other materials provided with the distribution. + * + * Neither the name of ARM nor the names of its contributors may be used + * to endorse or promote products derived from this software without specific + * prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" + * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE + * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR + * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF + * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS + * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN + * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) + * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE + * POSSIBILITY OF SUCH DAMAGE. + */ + +#include <arch.h> +#include <arch_helpers.h> +#include <assert.h> +#include <cassert.h> +#include <common_def.h> +#include <debug.h> +#include <errno.h> +#include <platform_def.h> +#include <string.h> +#include <types.h> +#include <utils.h> +#include <xlat_tables_v2.h> +#ifdef AARCH32 +# include "aarch32/xlat_tables_arch.h" +#else +# include "aarch64/xlat_tables_arch.h" +#endif +#include "xlat_tables_private.h" + +/* + * Private variables used by the TF + */ +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)); + +static mmap_region_t tf_mmap[MAX_MMAP_REGIONS + 1]; + +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, + + .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 +}; + +void mmap_add_region(unsigned long long base_pa, uintptr_t base_va, + size_t size, unsigned int 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++; + } +} + +void init_xlat_tables(void) +{ + assert(!is_mmu_enabled()); + assert(!tf_xlat_ctx.initialized); + print_mmap(tf_xlat_ctx.mmap); + 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); + + 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 new file mode 100644 index 000000000..9d4c83795 --- /dev/null +++ b/lib/xlat_tables_v2/xlat_tables_internal.c @@ -0,0 +1,667 @@ +/* + * Copyright (c) 2017, ARM Limited and Contributors. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are met: + * + * Redistributions of source code must retain the above copyright notice, this + * list of conditions and the following disclaimer. + * + * Redistributions in binary form must reproduce the above copyright notice, + * this list of conditions and the following disclaimer in the documentation + * and/or other materials provided with the distribution. + * + * Neither the name of ARM nor the names of its contributors may be used + * to endorse or promote products derived from this software without specific + * prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" + * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE + * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR + * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF + * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS + * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN + * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) + * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE + * POSSIBILITY OF SUCH DAMAGE. + */ + +#include <arch.h> +#include <arch_helpers.h> +#include <assert.h> +#include <cassert.h> +#include <common_def.h> +#include <debug.h> +#include <errno.h> +#include <platform_def.h> +#include <string.h> +#include <types.h> +#include <utils.h> +#include <xlat_tables_v2.h> +#ifdef AARCH32 +# include "aarch32/xlat_tables_arch.h" +#else +# include "aarch64/xlat_tables_arch.h" +#endif +#include "xlat_tables_private.h" + +/* Returns a pointer to the first empty translation table. */ +static uint64_t *xlat_table_get_empty(xlat_ctx_t *ctx) +{ + assert(ctx->next_table < ctx->tables_num); + + return ctx->tables[ctx->next_table++]; +} + +/* Returns a block/page table descriptor for the given level and attributes. */ +static uint64_t xlat_desc(unsigned int attr, unsigned long long addr_pa, + int level) +{ + uint64_t desc; + int mem_type; + + /* Make sure that the granularity is fine enough to map this address. */ + assert((addr_pa & XLAT_BLOCK_MASK(level)) == 0); + + desc = addr_pa; + /* + * There are different translation table descriptors for level 3 and the + * rest. + */ + desc |= (level == XLAT_TABLE_LEVEL_MAX) ? PAGE_DESC : BLOCK_DESC; + /* + * Always set the access flag, as TF doesn't manage access flag faults. + * Deduce other fields of the descriptor based on the MT_NS and MT_RW + * memory region attributes. + */ + desc |= (attr & MT_NS) ? LOWER_ATTRS(NS) : 0; + desc |= (attr & MT_RW) ? LOWER_ATTRS(AP_RW) : LOWER_ATTRS(AP_RO); + desc |= LOWER_ATTRS(ACCESS_FLAG); + + /* + * Deduce shareability domain and executability of the memory region + * from the memory type of the attributes (MT_TYPE). + * + * Data accesses to device memory and non-cacheable normal memory are + * coherent for all observers in the system, and correspondingly are + * always treated as being Outer Shareable. Therefore, for these 2 types + * of memory, it is not strictly needed to set the shareability field + * in the translation tables. + */ + mem_type = MT_TYPE(attr); + if (mem_type == MT_DEVICE) { + desc |= LOWER_ATTRS(ATTR_DEVICE_INDEX | OSH); + /* + * Always map device memory as execute-never. + * This is to avoid the possibility of a speculative instruction + * fetch, which could be an issue if this memory region + * corresponds to a read-sensitive peripheral. + */ + desc |= UPPER_ATTRS(XN); + } else { /* Normal memory */ + /* + * Always map read-write normal memory as execute-never. + * (Trusted Firmware doesn't self-modify its code, therefore + * R/W memory is reserved for data storage, which must not be + * executable.) + * Note that setting the XN bit here is for consistency only. + * The enable_mmu_elx() function sets the SCTLR_EL3.WXN bit, + * which makes any writable memory region to be treated as + * execute-never, regardless of the value of the XN bit in the + * translation table. + * + * For read-only memory, rely on the MT_EXECUTE/MT_EXECUTE_NEVER + * attribute to figure out the value of the XN bit. + */ + if ((attr & MT_RW) || (attr & MT_EXECUTE_NEVER)) + desc |= UPPER_ATTRS(XN); + + if (mem_type == MT_MEMORY) { + desc |= LOWER_ATTRS(ATTR_IWBWA_OWBWA_NTR_INDEX | ISH); + } else { + assert(mem_type == MT_NON_CACHEABLE); + desc |= LOWER_ATTRS(ATTR_NON_CACHEABLE_INDEX | OSH); + } + } + + return desc; +} + +/* + * Enumeration of actions that can be made when mapping table entries depending + * on the previous value in that entry and information about the region being + * mapped. + */ +typedef enum { + + /* Do nothing */ + ACTION_NONE, + + /* Write a block (or page, if in level 3) entry. */ + ACTION_WRITE_BLOCK_ENTRY, + + /* + * Create a new table and write a table entry pointing to it. Recurse + * into it for further processing. + */ + ACTION_CREATE_NEW_TABLE, + + /* + * There is a table descriptor in this entry, read it and recurse into + * that table for further processing. + */ + ACTION_RECURSE_INTO_TABLE, + +} action_t; + +/* + * From the given arguments, it decides which action to take when mapping the + * specified region. + */ +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) +{ + uintptr_t mm_end_va = mm->base_va + mm->size - 1; + uintptr_t table_entry_end_va = + table_entry_base_va + XLAT_BLOCK_SIZE(level) - 1; + + /* + * The descriptor types allowed depend on the current table level. + */ + + if ((mm->base_va <= table_entry_base_va) && + (mm_end_va >= table_entry_end_va)) { + + /* + * Table entry is covered by region + * -------------------------------- + * + * This means that this table entry can describe the whole + * translation with this granularity in principle. + */ + + if (level == 3) { + /* + * Last level, only page descriptors are allowed. + */ + if (desc_type == PAGE_DESC) { + /* + * There's another region mapped here, don't + * overwrite. + */ + return ACTION_NONE; + } else { + assert(desc_type == INVALID_DESC); + return ACTION_WRITE_BLOCK_ENTRY; + } + + } else { + + /* + * Other levels. Table descriptors are allowed. Block + * descriptors too, but they have some limitations. + */ + + if (desc_type == TABLE_DESC) { + /* There's already a table, recurse into it. */ + return ACTION_RECURSE_INTO_TABLE; + + } else if (desc_type == INVALID_DESC) { + /* + * There's nothing mapped here, create a new + * entry. + * + * Check if the destination granularity allows + * us to use a block descriptor or we need a + * finer table for it. + * + * Also, check if the current level allows block + * descriptors. If not, create a table instead. + */ + if ((dest_pa & XLAT_BLOCK_MASK(level)) || + (level < MIN_LVL_BLOCK_DESC)) + return ACTION_CREATE_NEW_TABLE; + else + return ACTION_WRITE_BLOCK_ENTRY; + + } else { + /* + * There's another region mapped here, don't + * overwrite. + */ + assert(desc_type == BLOCK_DESC); + + return ACTION_NONE; + } + } + + } else if ((mm->base_va <= table_entry_end_va) || + (mm_end_va >= table_entry_base_va)) { + + /* + * Region partially covers table entry + * ----------------------------------- + * + * This means that this table entry can't describe the whole + * translation, a finer table is needed. + + * There cannot be partial block overlaps in level 3. If that + * happens, some of the preliminary checks when adding the + * mmap region failed to detect that PA and VA must at least be + * aligned to PAGE_SIZE. + */ + assert(level < 3); + + if (desc_type == INVALID_DESC) { + /* + * The block is not fully covered by the region. Create + * a new table, recurse into it and try to map the + * region with finer granularity. + */ + return ACTION_CREATE_NEW_TABLE; + + } else { + assert(desc_type == TABLE_DESC); + /* + * The block is not fully covered by the region, but + * there is already a table here. Recurse into it and + * try to map with finer granularity. + * + * PAGE_DESC for level 3 has the same value as + * TABLE_DESC, but this code can't run on a level 3 + * table because there can't be overlaps in level 3. + */ + return ACTION_RECURSE_INTO_TABLE; + } + } + + /* + * This table entry is outside of the region specified in the arguments, + * don't write anything to it. + */ + return ACTION_NONE; +} + +/* + * Recursive function that writes to the translation tables and maps the + * specified region. + */ +static void xlat_tables_map_region(xlat_ctx_t *ctx, mmap_region_t *mm, + const uintptr_t table_base_va, + uint64_t *const table_base, + const int table_entries, + const int level) +{ + assert(level >= ctx->base_level && level <= XLAT_TABLE_LEVEL_MAX); + + uintptr_t mm_end_va = mm->base_va + mm->size - 1; + + uintptr_t table_idx_va; + unsigned long long table_idx_pa; + + uint64_t *subtable; + uint64_t desc; + + int table_idx; + + if (mm->base_va > table_base_va) { + /* Find the first index of the table affected by the region. */ + table_idx_va = mm->base_va & ~XLAT_BLOCK_MASK(level); + + table_idx = (table_idx_va - table_base_va) >> + XLAT_ADDR_SHIFT(level); + + assert(table_idx < table_entries); + } else { + /* Start from the beginning of the table. */ + table_idx_va = table_base_va; + table_idx = 0; + } + + while (table_idx < table_entries) { + + desc = table_base[table_idx]; + + table_idx_pa = mm->base_pa + table_idx_va - mm->base_va; + + action_t action = xlat_tables_map_region_action(mm, + desc & DESC_MASK, table_idx_pa, table_idx_va, level); + + if (action == ACTION_WRITE_BLOCK_ENTRY) { + + table_base[table_idx] = + xlat_desc(mm->attr, table_idx_pa, level); + + } else if (action == ACTION_CREATE_NEW_TABLE) { + + subtable = xlat_table_get_empty(ctx); + assert(subtable != NULL); + /* Recurse to write into subtable */ + xlat_tables_map_region(ctx, mm, table_idx_va, subtable, + XLAT_TABLE_ENTRIES, level + 1); + /* Point to new subtable from this one. */ + table_base[table_idx] = + TABLE_DESC | (unsigned long)subtable; + + } else if (action == ACTION_RECURSE_INTO_TABLE) { + + subtable = (uint64_t *)(uintptr_t)(desc & TABLE_ADDR_MASK); + /* Recurse to write into subtable */ + xlat_tables_map_region(ctx, mm, table_idx_va, subtable, + XLAT_TABLE_ENTRIES, level + 1); + + } else { + + assert(action == ACTION_NONE); + + } + + table_idx++; + table_idx_va += XLAT_BLOCK_SIZE(level); + + /* If reached the end of the region, exit */ + if (mm_end_va <= table_idx_va) + break; + } +} + +void print_mmap(mmap_region_t *const mmap) +{ +#if LOG_LEVEL >= LOG_LEVEL_VERBOSE + tf_printf("mmap:\n"); + mmap_region_t *mm = mmap; + + while (mm->size) { + tf_printf(" VA:%p PA:0x%llx size:0x%zx attr:0x%x\n", + (void *)mm->base_va, mm->base_pa, + mm->size, mm->attr); + ++mm; + }; + tf_printf("\n"); +#endif +} + +/* + * Function that verifies that a region can be mapped. + * Returns: + * 0: Success, the mapping is allowed. + * EINVAL: Invalid values were used as arguments. + * ERANGE: The memory limits were surpassed. + * ENOMEM: There is not enough memory in the mmap array. + * EPERM: Region overlaps another one in an invalid way. + */ +static int mmap_add_region_check(xlat_ctx_t *ctx, unsigned long long base_pa, + uintptr_t base_va, size_t size, + unsigned int attr) +{ + mmap_region_t *mm = ctx->mmap; + unsigned long long end_pa = base_pa + size - 1; + uintptr_t end_va = base_va + size - 1; + + if (!IS_PAGE_ALIGNED(base_pa) || !IS_PAGE_ALIGNED(base_va) || + !IS_PAGE_ALIGNED(size)) + return -EINVAL; + + /* Check for overflows */ + if ((base_pa > end_pa) || (base_va > end_va)) + return -ERANGE; + + if ((base_va + (uintptr_t)size - (uintptr_t)1) > ctx->va_max_address) + return -ERANGE; + + if ((base_pa + (unsigned long long)size - 1ULL) > ctx->pa_max_address) + return -ERANGE; + + /* Check that there is space in the mmap array */ + if (ctx->mmap[ctx->mmap_num - 1].size != 0) + return -ENOMEM; + + /* Check for PAs and VAs overlaps with all other regions */ + for (mm = ctx->mmap; mm->size; ++mm) { + + uintptr_t mm_end_va = mm->base_va + mm->size - 1; + + /* + * Check if one of the regions is completely inside the other + * one. + */ + int fully_overlapped_va = + ((base_va >= mm->base_va) && (end_va <= mm_end_va)) || + ((mm->base_va >= base_va) && (mm_end_va <= end_va)); + + /* + * Full VA overlaps are only allowed if both regions are + * identity mapped (zero offset) or have the same VA to PA + * offset. Also, make sure that it's not the exact same area. + * This can only be done with locked regions. + */ + if (fully_overlapped_va) { + + if ((mm->base_va - mm->base_pa) != (base_va - base_pa)) + return -EPERM; + + if ((base_va == mm->base_va) && (size == mm->size)) + return -EPERM; + + } else { + /* + * If the regions do not have fully overlapping VAs, + * then they must have fully separated VAs and PAs. + * Partial overlaps are not allowed + */ + + unsigned long long mm_end_pa = + mm->base_pa + mm->size - 1; + + int separated_pa = + (end_pa < mm->base_pa) || (base_pa > mm_end_pa); + int separated_va = + (end_va < mm->base_va) || (base_va > mm_end_va); + + if (!(separated_va && separated_pa)) + return -EPERM; + } + } + + return 0; +} + +void mmap_add_region_ctx(xlat_ctx_t *ctx, mmap_region_t *mm) +{ + mmap_region_t *mm_cursor = ctx->mmap; + mmap_region_t *mm_last = mm_cursor + ctx->mmap_num; + unsigned long long end_pa = mm->base_pa + mm->size - 1; + uintptr_t end_va = mm->base_va + mm->size - 1; + int ret; + + /* Ignore empty regions */ + if (!mm->size) + return; + + ret = mmap_add_region_check(ctx, mm->base_pa, mm->base_va, mm->size, + mm->attr); + if (ret != 0) { + ERROR("mmap_add_region_check() failed. error %d\n", ret); + assert(0); + return; + } + + /* + * Find correct place in mmap to insert new region. + * + * 1 - Lower region VA end first. + * 2 - Smaller region size first. + * + * VA 0 0xFF + * + * 1st |------| + * 2nd |------------| + * 3rd |------| + * 4th |---| + * 5th |---| + * 6th |----------| + * 7th |-------------------------------------| + * + * This is required for overlapping regions only. It simplifies adding + * regions with the loop in xlat_tables_init_internal because the outer + * ones won't overwrite block or page descriptors of regions added + * previously. + */ + + while ((mm_cursor->base_va + mm_cursor->size - 1) < end_va + && mm_cursor->size) + ++mm_cursor; + + while ((mm_cursor->base_va + mm_cursor->size - 1 == end_va) + && (mm_cursor->size < mm->size)) + ++mm_cursor; + + /* Make room for new region by moving other regions up by one place */ + memmove(mm_cursor + 1, mm_cursor, + (uintptr_t)mm_last - (uintptr_t)mm_cursor); + + /* + * Check we haven't lost the empty sentinel from the end of the array. + * This shouldn't happen as we have checked in mmap_add_region_check + * that there is free space. + */ + assert(mm_last->size == 0); + + mm_cursor->base_pa = mm->base_pa; + mm_cursor->base_va = mm->base_va; + mm_cursor->size = mm->size; + mm_cursor->attr = mm->attr; + + if (end_pa > ctx->max_pa) + ctx->max_pa = end_pa; + if (end_va > ctx->max_va) + ctx->max_va = end_va; +} + +#if LOG_LEVEL >= LOG_LEVEL_VERBOSE + +/* Print the attributes of the specified block descriptor. */ +static void xlat_desc_print(uint64_t desc) +{ + int mem_type_index = ATTR_INDEX_GET(desc); + + if (mem_type_index == ATTR_IWBWA_OWBWA_NTR_INDEX) { + tf_printf("MEM"); + } else if (mem_type_index == ATTR_NON_CACHEABLE_INDEX) { + tf_printf("NC"); + } else { + assert(mem_type_index == ATTR_DEVICE_INDEX); + tf_printf("DEV"); + } + + tf_printf(LOWER_ATTRS(AP_RO) & desc ? "-RO" : "-RW"); + tf_printf(LOWER_ATTRS(NS) & desc ? "-NS" : "-S"); + tf_printf(UPPER_ATTRS(XN) & desc ? "-XN" : "-EXEC"); +} + +static const char * const level_spacers[] = { + "", + " ", + " ", + " " +}; + +/* + * Recursive function that reads the translation tables passed as an argument + * and prints their status. + */ +static void xlat_tables_print_internal(const uintptr_t table_base_va, + uint64_t *const table_base, const int table_entries, + const int level) +{ + assert(level <= XLAT_TABLE_LEVEL_MAX); + + uint64_t desc; + uintptr_t table_idx_va = table_base_va; + int table_idx = 0; + + size_t level_size = XLAT_BLOCK_SIZE(level); + + while (table_idx < table_entries) { + + desc = table_base[table_idx]; + + if ((desc & DESC_MASK) == INVALID_DESC) { + + tf_printf("%sVA:%p size:0x%zx\n", + level_spacers[level], + (void *)table_idx_va, level_size); + + } else { + + /* + * Check if this is a table or a block. Tables are only + * allowed in levels other than 3, but DESC_PAGE has the + * same value as DESC_TABLE, so we need to check. + */ + if (((desc & DESC_MASK) == TABLE_DESC) && + (level < XLAT_TABLE_LEVEL_MAX)) { + /* + * Do not print any PA for a table descriptor, + * as it doesn't directly map physical memory + * but instead points to the next translation + * table in the translation table walk. + */ + tf_printf("%sVA:%p size:0x%zx\n", + level_spacers[level], + (void *)table_idx_va, level_size); + + uintptr_t addr_inner = desc & TABLE_ADDR_MASK; + + xlat_tables_print_internal(table_idx_va, + (uint64_t *)addr_inner, + XLAT_TABLE_ENTRIES, level+1); + } else { + tf_printf("%sVA:%p PA:0x%llx size:0x%zx ", + level_spacers[level], + (void *)table_idx_va, + (unsigned long long)(desc & TABLE_ADDR_MASK), + level_size); + xlat_desc_print(desc); + tf_printf("\n"); + } + } + + table_idx++; + table_idx_va += level_size; + } +} + +#endif /* LOG_LEVEL >= LOG_LEVEL_VERBOSE */ + +void xlat_tables_print(xlat_ctx_t *ctx) +{ +#if LOG_LEVEL >= LOG_LEVEL_VERBOSE + xlat_tables_print_internal(0, ctx->base_table, ctx->base_table_entries, + ctx->base_level); +#endif /* LOG_LEVEL >= LOG_LEVEL_VERBOSE */ +} + +void init_xlation_table(xlat_ctx_t *ctx) +{ + mmap_region_t *mm = ctx->mmap; + + /* All tables must be zeroed before mapping any region. */ + + for (int i = 0; i < ctx->base_table_entries; i++) + ctx->base_table[i] = INVALID_DESC; + + for (int j = 0; j < ctx->tables_num; j++) { + for (int i = 0; i < XLAT_TABLE_ENTRIES; i++) + ctx->tables[j][i] = INVALID_DESC; + } + + while (mm->size) + xlat_tables_map_region(ctx, mm++, 0, ctx->base_table, + ctx->base_table_entries, ctx->base_level); + + ctx->initialized = 1; +} diff --git a/lib/xlat_tables_v2/xlat_tables_private.h b/lib/xlat_tables_v2/xlat_tables_private.h new file mode 100644 index 000000000..4b4840528 --- /dev/null +++ b/lib/xlat_tables_v2/xlat_tables_private.h @@ -0,0 +1,137 @@ +/* + * Copyright (c) 2017, ARM Limited and Contributors. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are met: + * + * Redistributions of source code must retain the above copyright notice, this + * list of conditions and the following disclaimer. + * + * Redistributions in binary form must reproduce the above copyright notice, + * this list of conditions and the following disclaimer in the documentation + * and/or other materials provided with the distribution. + * + * Neither the name of ARM nor the names of its contributors may be used + * to endorse or promote products derived from this software without specific + * prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" + * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE + * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR + * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF + * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS + * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN + * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) + * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE + * POSSIBILITY OF SUCH DAMAGE. + */ + +#ifndef __XLAT_TABLES_PRIVATE_H__ +#define __XLAT_TABLES_PRIVATE_H__ + +#include <cassert.h> +#include <platform_def.h> +#include <utils.h> + +/* + * 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); + +/* 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. + */ + mmap_region_t *mmap; /* mmap_num + 1 elements */ + 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]; + int tables_num; + + 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; + int base_table_entries; + + unsigned long long max_pa; + uintptr_t max_va; + + /* Level of the base translation table. */ + int base_level; + + /* Set to 1 when the translation tables are initialized. */ + int initialized; + +} xlat_ctx_t; + +/* Print VA, PA, size and attributes of all regions in the mmap array. */ +void print_mmap(mmap_region_t *const mmap); + +/* + * Print the current state of the translation tables by reading them from + * memory. + */ +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. + */ + +/* Execute architecture-specific translation table initialization code. */ +void init_xlat_tables_arch(unsigned long long max_pa); + +/* Enable MMU and configure it to use the specified translation tables. */ +void enable_mmu_arch(unsigned int flags, uint64_t *base_table); + +/* Return 1 if the MMU of this Exception Level is enabled, 0 otherwise. */ +int is_mmu_enabled(void); + +#endif /* __XLAT_TABLES_PRIVATE_H__ */ |