diff options
author | Julius Werner <jwerner@chromium.org> | 2016-01-26 19:17:53 -0800 |
---|---|---|
committer | Patrick Georgi <pgeorgi@google.com> | 2016-02-10 09:39:23 +0100 |
commit | 372d0ff1d12b23f3c724f7c35fa57e4858dc0db6 (patch) | |
tree | b6fc7cfcc7c7cc7a1e326d040719651d5ef86611 /src/arch/arm64/armv8/mmu.c | |
parent | 89c61b563044aa89a41349a44ce850dfe888689b (diff) | |
download | coreboot-372d0ff1d12b23f3c724f7c35fa57e4858dc0db6.tar.xz |
arch/arm64: mmu: Spot check TTB memory attributes
On ARM64, the memory type for accessing page table descriptors during
address translation is governed by the Translation Control Register
(TCR). When the MMU code accesses the same descriptors to change page
mappings, it uses the standard memory type rules (defined by the page
table descriptor for the page that contains that table, or 'device' if
the MMU is off).
Accessing the same memory with different memory types can lead to all
kinds of fun and hard to debug effects. In particular, if the TCR says
"cacheable" and the page tables say "uncacheable", page table walks will
pull stale entries into the cache and later mmu_config_range() calls
will write directly to memory, bypassing those cache lines. This means
the translations will not get updated even after a TLB flush, and later
cache flushes/evictions may write the stale entries back to memory.
Since page table configuration is currently always done from SoC code,
we can't generally ensure that the TTB is always mapped as cacheable.
We can however save developers of future SoCs a lot of headaches and
time by spot checking the attributes when the MMU gets enabled, as this
patch does.
BRANCH=None
BUG=None
TEST=Booted Oak. Manually tested get_pte() with a few addresses.
Change-Id: I3afd29dece848c4b5f759ce2f00ca2b7433374da
Signed-off-by: Patrick Georgi <pgeorgi@chromium.org>
Original-Commit-Id: f3947f4bb0abf4466006d5e3a962bbcb8919b12d
Original-Change-Id: I1008883e5ed4cc37d30cae5777a60287d3d01af0
Original-Signed-off-by: Julius Werner <jwerner@chromium.org>
Original-Reviewed-on: https://chromium-review.googlesource.com/323862
Original-Reviewed-by: Aaron Durbin <adurbin@chromium.org>
Reviewed-on: https://review.coreboot.org/13595
Tested-by: build bot (Jenkins)
Reviewed-by: Stefan Reinauer <stefan.reinauer@coreboot.org>
Diffstat (limited to 'src/arch/arm64/armv8/mmu.c')
-rw-r--r-- | src/arch/arm64/armv8/mmu.c | 26 |
1 files changed, 26 insertions, 0 deletions
diff --git a/src/arch/arm64/armv8/mmu.c b/src/arch/arm64/armv8/mmu.c index 5d957d454f..9280fc2d7c 100644 --- a/src/arch/arm64/armv8/mmu.c +++ b/src/arch/arm64/armv8/mmu.c @@ -199,6 +199,26 @@ static void sanity_check(uint64_t addr, uint64_t size) size >= GRANULE_SIZE); } +/* Func : get_pte + * Desc : Returns the page table entry governing a specific address. */ +static uint64_t get_pte(void *addr) +{ + int shift = BITS_PER_VA > L1_ADDR_SHIFT ? L1_ADDR_SHIFT : L2_ADDR_SHIFT; + uint64_t *pte = (uint64_t *)_ttb; + + while (1) { + int index = ((uintptr_t)addr >> shift) & + ((1UL << BITS_RESOLVED_PER_LVL) - 1); + + if ((pte[index] & DESC_MASK) != TABLE_DESC || + shift <= GRANULE_SIZE_SHIFT) + return pte[index]; + + pte = (uint64_t *)(pte[index] & XLAT_ADDR_MASK); + shift -= BITS_RESOLVED_PER_LVL; + } +} + /* Func : mmu_config_range * Desc : This function repeatedly calls init_xlat_table with the base * address. Based on size returned from init_xlat_table, base_addr is updated @@ -256,6 +276,12 @@ void mmu_init(void) void mmu_enable(void) { + if (((get_pte(_ttb) >> BLOCK_INDEX_SHIFT) & BLOCK_INDEX_MASK) + != BLOCK_INDEX_MEM_NORMAL || + ((get_pte(_ettb - 1) >> BLOCK_INDEX_SHIFT) & BLOCK_INDEX_MASK) + != BLOCK_INDEX_MEM_NORMAL) + die("TTB memory type must match TCR (normal, cacheable)!"); + uint32_t sctlr = raw_read_sctlr_el3(); sctlr |= SCTLR_C | SCTLR_M | SCTLR_I; raw_write_sctlr_el3(sctlr); |