2017-03-08 14:40:23 +00:00
|
|
|
/*
|
xlat v2: Split MMU setup and enable
At present, the function provided by the translation library to enable
MMU constructs appropriate values for translation library, and programs
them to the right registers. The construction of initial values,
however, is only required once as both the primary and secondaries
program the same values.
Additionally, the MMU-enabling function is written in C, which means
there's an active stack at the time of enabling MMU. On some systems,
like Arm DynamIQ, having active stack while enabling MMU during warm
boot might lead to coherency problems.
This patch addresses both the above problems by:
- Splitting the MMU-enabling function into two: one that sets up
values to be programmed into the registers, and another one that
takes the pre-computed values and writes to the appropriate
registers. With this, the primary effectively calls both functions
to have the MMU enabled, but secondaries only need to call the
latter.
- Rewriting the function that enables MMU in assembly so that it
doesn't use stack.
This patch fixes a bunch of MISRA issues on the way.
Change-Id: I0faca97263a970ffe765f0e731a1417e43fbfc45
Signed-off-by: Jeenu Viswambharan <jeenu.viswambharan@arm.com>
2018-04-27 15:06:57 +01:00
|
|
|
* Copyright (c) 2017-2018, ARM Limited and Contributors. All rights reserved.
|
2017-03-08 14:40:23 +00:00
|
|
|
*
|
2017-05-03 09:38:09 +01:00
|
|
|
* SPDX-License-Identifier: BSD-3-Clause
|
2017-03-08 14:40:23 +00:00
|
|
|
*/
|
|
|
|
|
|
|
|
#include <arch.h>
|
|
|
|
#include <arch_helpers.h>
|
|
|
|
#include <assert.h>
|
|
|
|
#include <cassert.h>
|
|
|
|
#include <platform_def.h>
|
|
|
|
#include <utils.h>
|
2017-08-07 11:20:13 +01:00
|
|
|
#include <utils_def.h>
|
2017-03-08 14:40:23 +00:00
|
|
|
#include <xlat_tables_v2.h>
|
|
|
|
#include "../xlat_tables_private.h"
|
|
|
|
|
2017-11-08 12:53:47 +00:00
|
|
|
#if ARM_ARCH_MAJOR == 7 && !defined(ARMV7_SUPPORTS_LARGE_PAGE_ADDRESSING)
|
|
|
|
#error ARMv7 target does not support LPAE MMU descriptors
|
|
|
|
#endif
|
|
|
|
|
2018-06-11 13:40:32 +01:00
|
|
|
/*
|
|
|
|
* Returns 1 if the provided granule size is supported, 0 otherwise.
|
|
|
|
*/
|
|
|
|
int xlat_arch_is_granule_size_supported(size_t size)
|
|
|
|
{
|
|
|
|
/*
|
2018-07-12 15:54:10 +01:00
|
|
|
* The library uses the long descriptor translation table format, which
|
|
|
|
* supports 4 KiB pages only.
|
2018-06-11 13:40:32 +01:00
|
|
|
*/
|
|
|
|
return (size == (4U * 1024U));
|
|
|
|
}
|
|
|
|
|
|
|
|
size_t xlat_arch_get_max_supported_granule_size(void)
|
|
|
|
{
|
|
|
|
return 4U * 1024U;
|
|
|
|
}
|
|
|
|
|
2017-03-22 15:48:51 +00:00
|
|
|
#if ENABLE_ASSERTIONS
|
2017-05-31 13:31:48 +01:00
|
|
|
unsigned long long xlat_arch_get_max_supported_pa(void)
|
2017-03-08 14:40:23 +00:00
|
|
|
{
|
|
|
|
/* Physical address space size for long descriptor format. */
|
2018-02-16 21:12:58 +00:00
|
|
|
return (1ULL << 40) - 1ULL;
|
2017-03-08 14:40:23 +00:00
|
|
|
}
|
2017-03-22 15:48:51 +00:00
|
|
|
#endif /* ENABLE_ASSERTIONS*/
|
2017-03-08 14:40:23 +00:00
|
|
|
|
2017-10-04 16:52:15 +01:00
|
|
|
int is_mmu_enabled_ctx(const xlat_ctx_t *ctx __unused)
|
2017-03-08 14:40:23 +00:00
|
|
|
{
|
|
|
|
return (read_sctlr() & SCTLR_M_BIT) != 0;
|
|
|
|
}
|
|
|
|
|
2018-07-05 08:11:48 +01:00
|
|
|
uint64_t xlat_arch_regime_get_xn_desc(int xlat_regime __unused)
|
|
|
|
{
|
|
|
|
return UPPER_ATTRS(XN);
|
|
|
|
}
|
|
|
|
|
2018-07-11 09:46:45 +01:00
|
|
|
void xlat_arch_tlbi_va(uintptr_t va, int xlat_regime __unused)
|
2017-09-25 15:23:22 +01:00
|
|
|
{
|
|
|
|
/*
|
|
|
|
* Ensure the translation table write has drained into memory before
|
|
|
|
* invalidating the TLB entry.
|
|
|
|
*/
|
|
|
|
dsbishst();
|
|
|
|
|
|
|
|
tlbimvaais(TLBI_ADDR(va));
|
|
|
|
}
|
|
|
|
|
2017-02-27 17:23:54 +00:00
|
|
|
void xlat_arch_tlbi_va_sync(void)
|
|
|
|
{
|
|
|
|
/* Invalidate all entries from branch predictors. */
|
|
|
|
bpiallis();
|
|
|
|
|
|
|
|
/*
|
|
|
|
* A TLB maintenance instruction can complete at any time after
|
|
|
|
* it is issued, but is only guaranteed to be complete after the
|
|
|
|
* execution of DSB by the PE that executed the TLB maintenance
|
|
|
|
* instruction. After the TLB invalidate instruction is
|
|
|
|
* complete, no new memory accesses using the invalidated TLB
|
|
|
|
* entries will be observed by any observer of the system
|
|
|
|
* domain. See section D4.8.2 of the ARMv8 (issue k), paragraph
|
|
|
|
* "Ordering and completion of TLB maintenance instructions".
|
|
|
|
*/
|
|
|
|
dsbish();
|
|
|
|
|
|
|
|
/*
|
|
|
|
* The effects of a completed TLB maintenance instruction are
|
|
|
|
* only guaranteed to be visible on the PE that executed the
|
|
|
|
* instruction after the execution of an ISB instruction by the
|
|
|
|
* PE that executed the TLB maintenance instruction.
|
|
|
|
*/
|
|
|
|
isb();
|
|
|
|
}
|
|
|
|
|
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
|
|
|
int xlat_arch_current_el(void)
|
|
|
|
{
|
|
|
|
/*
|
|
|
|
* If EL3 is in AArch32 mode, all secure PL1 modes (Monitor, System,
|
|
|
|
* SVC, Abort, UND, IRQ and FIQ modes) execute at EL3.
|
2018-07-12 15:43:07 +01:00
|
|
|
*
|
|
|
|
* The PL1&0 translation regime in AArch32 behaves like the EL1&0 regime
|
|
|
|
* in AArch64 except for the XN bits, but we set and unset them at the
|
|
|
|
* same time, so there's no difference in practice.
|
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
|
|
|
*/
|
2018-07-12 15:43:07 +01:00
|
|
|
return 1;
|
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
|
|
|
}
|
|
|
|
|
2017-03-08 14:40:23 +00:00
|
|
|
/*******************************************************************************
|
2017-05-31 13:38:51 +01:00
|
|
|
* Function for enabling the MMU in Secure PL1, assuming that the page tables
|
|
|
|
* have already been created.
|
2017-03-08 14:40:23 +00:00
|
|
|
******************************************************************************/
|
2018-07-15 16:42:01 +01:00
|
|
|
void setup_mmu_cfg(uint64_t *params, unsigned int flags,
|
|
|
|
const uint64_t *base_table, unsigned long long max_pa,
|
|
|
|
uintptr_t max_va, __unused int xlat_regime)
|
2017-03-08 14:40:23 +00:00
|
|
|
{
|
2018-07-12 15:44:42 +01:00
|
|
|
uint64_t mair, ttbr0;
|
|
|
|
uint32_t ttbcr;
|
2017-03-08 14:40:23 +00:00
|
|
|
|
|
|
|
assert(IS_IN_SECURE());
|
2017-05-31 13:38:51 +01:00
|
|
|
|
2017-03-08 14:40:23 +00:00
|
|
|
/* Set attributes in the right indices of the MAIR */
|
2018-07-12 15:44:42 +01:00
|
|
|
mair = MAIR0_ATTR_SET(ATTR_DEVICE, ATTR_DEVICE_INDEX);
|
|
|
|
mair |= MAIR0_ATTR_SET(ATTR_IWBWA_OWBWA_NTR,
|
2017-03-08 14:40:23 +00:00
|
|
|
ATTR_IWBWA_OWBWA_NTR_INDEX);
|
2018-07-12 15:44:42 +01:00
|
|
|
mair |= MAIR0_ATTR_SET(ATTR_NON_CACHEABLE,
|
2017-03-08 14:40:23 +00:00
|
|
|
ATTR_NON_CACHEABLE_INDEX);
|
|
|
|
|
|
|
|
/*
|
2017-05-31 13:38:51 +01:00
|
|
|
* 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
|
2017-07-11 15:11:10 +01:00
|
|
|
* using TTBR0 to the given virtual address space size, if smaller than
|
|
|
|
* 32 bits.
|
2017-05-31 13:38:51 +01:00
|
|
|
*/
|
2017-07-11 15:11:10 +01:00
|
|
|
if (max_va != UINT32_MAX) {
|
|
|
|
uintptr_t virtual_addr_space_size = max_va + 1;
|
|
|
|
assert(CHECK_VIRT_ADDR_SPACE_SIZE(virtual_addr_space_size));
|
|
|
|
/*
|
2017-07-19 10:11:13 +01:00
|
|
|
* __builtin_ctzll(0) is undefined but here we are guaranteed
|
2017-07-11 15:11:10 +01:00
|
|
|
* that virtual_addr_space_size is in the range [1, UINT32_MAX].
|
|
|
|
*/
|
2017-07-19 10:11:13 +01:00
|
|
|
ttbcr |= 32 - __builtin_ctzll(virtual_addr_space_size);
|
2017-07-11 15:11:10 +01:00
|
|
|
}
|
2017-05-31 13:38:51 +01:00
|
|
|
|
|
|
|
/*
|
|
|
|
* Set the cacheability and shareability attributes for memory
|
|
|
|
* associated with translation table walks using TTBR0.
|
2017-03-08 14:40:23 +00:00
|
|
|
*/
|
2017-03-16 17:16:34 +00:00
|
|
|
if (flags & XLAT_TABLE_NC) {
|
|
|
|
/* Inner & outer non-cacheable non-shareable. */
|
2017-05-31 13:38:51 +01:00
|
|
|
ttbcr |= TTBCR_SH0_NON_SHAREABLE | TTBCR_RGN0_OUTER_NC |
|
|
|
|
TTBCR_RGN0_INNER_NC;
|
2017-03-16 17:16:34 +00:00
|
|
|
} else {
|
|
|
|
/* Inner & outer WBWA & shareable. */
|
2017-05-31 13:38:51 +01:00
|
|
|
ttbcr |= TTBCR_SH0_INNER_SHAREABLE | TTBCR_RGN0_OUTER_WBA |
|
|
|
|
TTBCR_RGN0_INNER_WBA;
|
2017-03-16 17:16:34 +00:00
|
|
|
}
|
2017-03-08 14:40:23 +00:00
|
|
|
|
|
|
|
/* Set TTBR0 bits as well */
|
|
|
|
ttbr0 = (uint64_t)(uintptr_t) base_table;
|
2018-07-12 15:44:42 +01:00
|
|
|
|
2017-08-07 11:20:13 +01:00
|
|
|
#if ARM_ARCH_AT_LEAST(8, 2)
|
|
|
|
/*
|
2018-07-12 15:44:42 +01:00
|
|
|
* Enable CnP bit so as to share page tables with all PEs. This
|
|
|
|
* is mandatory for ARMv8.2 implementations.
|
2017-08-07 11:20:13 +01:00
|
|
|
*/
|
|
|
|
ttbr0 |= TTBR_CNP_BIT;
|
|
|
|
#endif
|
2017-05-31 13:38:51 +01:00
|
|
|
|
xlat v2: Split MMU setup and enable
At present, the function provided by the translation library to enable
MMU constructs appropriate values for translation library, and programs
them to the right registers. The construction of initial values,
however, is only required once as both the primary and secondaries
program the same values.
Additionally, the MMU-enabling function is written in C, which means
there's an active stack at the time of enabling MMU. On some systems,
like Arm DynamIQ, having active stack while enabling MMU during warm
boot might lead to coherency problems.
This patch addresses both the above problems by:
- Splitting the MMU-enabling function into two: one that sets up
values to be programmed into the registers, and another one that
takes the pre-computed values and writes to the appropriate
registers. With this, the primary effectively calls both functions
to have the MMU enabled, but secondaries only need to call the
latter.
- Rewriting the function that enables MMU in assembly so that it
doesn't use stack.
This patch fixes a bunch of MISRA issues on the way.
Change-Id: I0faca97263a970ffe765f0e731a1417e43fbfc45
Signed-off-by: Jeenu Viswambharan <jeenu.viswambharan@arm.com>
2018-04-27 15:06:57 +01:00
|
|
|
/* Now populate MMU configuration */
|
2018-07-15 16:42:01 +01:00
|
|
|
params[MMU_CFG_MAIR] = mair;
|
|
|
|
params[MMU_CFG_TCR] = (uint64_t) ttbcr;
|
|
|
|
params[MMU_CFG_TTBR0] = ttbr0;
|
2017-03-08 14:40:23 +00:00
|
|
|
}
|