arm-trusted-firmware/lib/xlat_tables_v2/xlat_tables_private.h

111 lines
3.0 KiB
C
Raw Normal View History

/*
* Copyright (c) 2017-2018, ARM Limited and Contributors. All rights reserved.
*
* SPDX-License-Identifier: BSD-3-Clause
*/
#ifndef XLAT_TABLES_PRIVATE_H
#define XLAT_TABLES_PRIVATE_H
#include <stdbool.h>
#include <platform_def.h>
#include <lib/xlat_tables/xlat_tables_defs.h>
#if PLAT_XLAT_TABLES_DYNAMIC
/*
* Private shifts and masks to access fields of an mmap attribute
*/
/* Dynamic or static */
#define MT_DYN_SHIFT U(31)
/*
* Memory mapping private attributes
*
* Private attributes not exposed in the public header.
*/
/*
* Regions mapped before the MMU can't be unmapped dynamically (they are
* static) and regions mapped with MMU enabled can be unmapped. This
* behaviour can't be overridden.
*
* Static regions can overlap each other, dynamic regions can't.
*/
#define MT_STATIC (U(0) << MT_DYN_SHIFT)
#define MT_DYNAMIC (U(1) << MT_DYN_SHIFT)
#endif /* PLAT_XLAT_TABLES_DYNAMIC */
extern uint64_t mmu_cfg_params[MMU_CFG_PARAM_MAX];
/*
* Return the execute-never mask that will prevent instruction fetch at the
* given translation regime.
*/
uint64_t xlat_arch_regime_get_xn_desc(int xlat_regime);
/*
* Invalidate all TLB entries that match the given virtual address. This
* operation applies to all PEs in the same Inner Shareable domain as the PE
* that executes this function. This functions must be called for every
* translation table entry that is modified. It only affects the specified
* translation regime.
*
* Note, however, that it is architecturally UNDEFINED to invalidate TLB entries
* pertaining to a higher exception level, e.g. invalidating EL3 entries from
* S-EL1.
*/
void xlat_arch_tlbi_va(uintptr_t va, int xlat_regime);
/*
* This function has to be called at the end of any code that uses the function
* xlat_arch_tlbi_va().
*/
void xlat_arch_tlbi_va_sync(void);
/* Print VA, PA, size and attributes of all regions in the mmap array. */
void xlat_mmap_print(const mmap_region_t *mmap);
/*
* Print the current state of the translation tables by reading them from
* memory.
*/
void xlat_tables_print(xlat_ctx_t *ctx);
/*
* Returns a block/page table descriptor for the given level and attributes.
*/
uint64_t xlat_desc(const xlat_ctx_t *ctx, uint32_t attr,
unsigned long long addr_pa, unsigned int level);
/*
* Architecture-specific initialization code.
*/
Fix execute-never permissions in xlat tables libs Translation regimes that only support one virtual address space (such as the ones for EL2 and EL3) can flag memory regions as execute-never by setting to 1 the XN bit in the Upper Attributes field in the translation tables descriptors. Translation regimes that support two different virtual address spaces (such as the one shared by EL1 and EL0) use bits PXN and UXN instead. The Trusted Firmware runs at EL3 and EL1, it has to handle translation tables of both translation regimes, but the previous code handled both regimes the same way, as if both had only 1 VA range. When trying to set a descriptor as execute-never it would set the XN bit correctly in EL3, but it would set the XN bit in EL1 as well. XN is at the same bit position as UXN, which means that EL0 was being prevented from executing code at this region, not EL1 as the code intended. Therefore, the PXN bit was unset to 0 all the time. The result is that, in AArch64 mode, read-only data sections of BL2 weren't protected from being executed. This patch adds support of translation regimes with two virtual address spaces to both versions of the translation tables library, fixing the execute-never permissions for translation tables in EL1. The library currently does not support initializing translation tables for EL0 software, therefore it does not set/unset the UXN bit. If EL1 software needs to initialize translation tables for EL0 software, it should use a different library instead. Change-Id: If27588f9820ff42988851d90dc92801c8ecbe0c9 Signed-off-by: Antonio Nino Diaz <antonio.ninodiaz@arm.com>
2017-04-27 13:30:22 +01:00
/* Returns the current Exception Level. The returned EL must be 1 or higher. */
unsigned int xlat_arch_current_el(void);
Fix execute-never permissions in xlat tables libs Translation regimes that only support one virtual address space (such as the ones for EL2 and EL3) can flag memory regions as execute-never by setting to 1 the XN bit in the Upper Attributes field in the translation tables descriptors. Translation regimes that support two different virtual address spaces (such as the one shared by EL1 and EL0) use bits PXN and UXN instead. The Trusted Firmware runs at EL3 and EL1, it has to handle translation tables of both translation regimes, but the previous code handled both regimes the same way, as if both had only 1 VA range. When trying to set a descriptor as execute-never it would set the XN bit correctly in EL3, but it would set the XN bit in EL1 as well. XN is at the same bit position as UXN, which means that EL0 was being prevented from executing code at this region, not EL1 as the code intended. Therefore, the PXN bit was unset to 0 all the time. The result is that, in AArch64 mode, read-only data sections of BL2 weren't protected from being executed. This patch adds support of translation regimes with two virtual address spaces to both versions of the translation tables library, fixing the execute-never permissions for translation tables in EL1. The library currently does not support initializing translation tables for EL0 software, therefore it does not set/unset the UXN bit. If EL1 software needs to initialize translation tables for EL0 software, it should use a different library instead. Change-Id: If27588f9820ff42988851d90dc92801c8ecbe0c9 Signed-off-by: Antonio Nino Diaz <antonio.ninodiaz@arm.com>
2017-04-27 13:30:22 +01:00
/*
* 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);
/*
* Returns true if the MMU of the translation regime managed by the given
* xlat_ctx_t is enabled, false otherwise.
*/
bool is_mmu_enabled_ctx(const xlat_ctx_t *ctx);
xlat v2: Flush xlat tables after being modified During cold boot, the initial translation tables are created with data caches disabled, so all modifications go to memory directly. After the MMU is enabled and data cache is enabled, any modification to the tables goes to data cache, and eventually may get flushed to memory. If CPU0 modifies the tables while CPU1 is off, CPU0 will have the modified tables in its data cache. When CPU1 is powered on, the MMU is enabled, then it enables coherency, and then it enables the data cache. Until this is done, CPU1 isn't in coherency, and the translation tables it sees can be outdated if CPU0 still has some modified entries in its data cache. This can be a problem in some cases. For example, the warm boot code uses only the tables mapped during cold boot, which don't normally change. However, if they are modified (and a RO page is made RW, or a XN page is made executable) the CPU will see the old attributes and crash when it tries to access it. This doesn't happen in systems with HW_ASSISTED_COHERENCY or WARMBOOT_ENABLE_DCACHE_EARLY. In these systems, the data cache is enabled at the same time as the MMU. As soon as this happens, the CPU is in coherency. There was an attempt of a fix in psci_helpers.S, but it didn't solve the problem. That code has been deleted. The code was introduced in commit <264410306381> ("Invalidate TLB entries during warm boot"). Now, during a map or unmap operation, the memory associated to each modified table is flushed. Traversing a table will also flush it's memory, as there is no way to tell in the current implementation if the table that has been traversed has also been modified. Change-Id: I4b520bca27502f1018878061bc5fb82af740bb92 Signed-off-by: Antonio Nino Diaz <antonio.ninodiaz@arm.com>
2018-08-07 12:47:12 +01:00
/* 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 */