Patrick Georgi (pgeorgi(a)google.com) just uploaded a new patch set to gerrit, which you can find at https://review.coreboot.org/13600
-gerrit
commit c6feb09df0e3f30fd99b0613d1442d5dca475f18
Author: Duncan Laurie <dlaurie(a)chromium.org>
Date: Tue Jan 26 16:30:36 2016 -0800
chromeos: Add option to backup VBNV CMOS into flash
This adds a new kconfig option that will backup the VBNV data
from CMOS to flash, and restore it if the CMOS data is invalid
during boot.
This allows special flags to not get lost when power is lost,
RTC reset is triggered, or CMOS is corrupted.
BUG=chrome-os-partner:47915
BRANCH=glados
TEST=manually tested on chell:
1-boot and run "enable_dev_usb_boot"
2-reboot and check that it is enabled with crossystem
3-run "mosys nvram clear"
4-reboot and check that it is still enabled
Change-Id: I38103d100117da34471734a6dd31eb7058735c12
Signed-off-by: Patrick Georgi <pgeorgi(a)chromium.org>
Original-Commit-Id: 8a356e616c6885d5ae3b776691929675d48a28f9
Original-Change-Id: I06e7ddff7b272e579c704914a0cf8cc14d6994e8
Original-Signed-off-by: Duncan Laurie <dlaurie(a)chromium.org>
Original-Reviewed-on: https://chromium-review.googlesource.com/324122
Original-Reviewed-by: Aaron Durbin <adurbin(a)chromium.org>
---
src/vendorcode/google/chromeos/Kconfig | 8 ++++++++
src/vendorcode/google/chromeos/Makefile.inc | 5 +++++
src/vendorcode/google/chromeos/vbnv_cmos.c | 31 +++++++++++++++++++++++++++++
3 files changed, 44 insertions(+)
diff --git a/src/vendorcode/google/chromeos/Kconfig b/src/vendorcode/google/chromeos/Kconfig
index 04a2fad..baa6ca7 100644
--- a/src/vendorcode/google/chromeos/Kconfig
+++ b/src/vendorcode/google/chromeos/Kconfig
@@ -50,6 +50,14 @@ config CHROMEOS_VBNV_CMOS
help
VBNV is stored in CMOS
+config CHROMEOS_VBNV_CMOS_BACKUP_TO_FLASH
+ bool "Backup Vboot non-volatile storage from CMOS to flash."
+ default n
+ depends on CHROMEOS_VBNV_CMOS
+ help
+ Vboot non-volatile storage data will be backed up from CMOS to flash
+ and restored from flash if the CMOS is invalid due to power loss.
+
config CHROMEOS_VBNV_EC
bool "Vboot non-volatile storage in EC."
default n
diff --git a/src/vendorcode/google/chromeos/Makefile.inc b/src/vendorcode/google/chromeos/Makefile.inc
index 4a65963..d450efb 100644
--- a/src/vendorcode/google/chromeos/Makefile.inc
+++ b/src/vendorcode/google/chromeos/Makefile.inc
@@ -28,6 +28,11 @@ verstage-$(CONFIG_CHROMEOS_VBNV_CMOS) += vbnv_cmos.c
romstage-$(CONFIG_CHROMEOS_VBNV_CMOS) += vbnv_cmos.c
ramstage-$(CONFIG_CHROMEOS_VBNV_CMOS) += vbnv_cmos.c
+bootblock-$(CONFIG_CHROMEOS_VBNV_CMOS_BACKUP_TO_FLASH) += vbnv_flash.c
+verstage-$(CONFIG_CHROMEOS_VBNV_CMOS_BACKUP_TO_FLASH) += vbnv_flash.c
+romstage-$(CONFIG_CHROMEOS_VBNV_CMOS_BACKUP_TO_FLASH) += vbnv_flash.c
+ramstage-$(CONFIG_CHROMEOS_VBNV_CMOS_BACKUP_TO_FLASH) += vbnv_flash.c
+
bootblock-$(CONFIG_CHROMEOS_VBNV_EC) += vbnv_ec.c
verstage-$(CONFIG_CHROMEOS_VBNV_EC) += vbnv_ec.c
romstage-$(CONFIG_CHROMEOS_VBNV_EC) += vbnv_ec.c
diff --git a/src/vendorcode/google/chromeos/vbnv_cmos.c b/src/vendorcode/google/chromeos/vbnv_cmos.c
index e0d7ba1..22acefa 100644
--- a/src/vendorcode/google/chromeos/vbnv_cmos.c
+++ b/src/vendorcode/google/chromeos/vbnv_cmos.c
@@ -13,6 +13,8 @@
* GNU General Public License for more details.
*/
+#include <bootstate.h>
+#include <console/console.h>
#include <types.h>
#include <pc80/mc146818rtc.h>
#include "vbnv.h"
@@ -24,6 +26,21 @@ void read_vbnv_cmos(uint8_t *vbnv_copy)
for (i = 0; i < VBNV_BLOCK_SIZE; i++)
vbnv_copy[i] = cmos_read(CONFIG_VBNV_OFFSET + 14 + i);
+
+ if (IS_ENABLED(CONFIG_CHROMEOS_VBNV_CMOS_BACKUP_TO_FLASH)) {
+ if (verify_vbnv(vbnv_copy))
+ return;
+
+ printk(BIOS_INFO, "VBNV: CMOS invalid, restoring from flash\n");
+ read_vbnv_flash(vbnv_copy);
+
+ if (verify_vbnv(vbnv_copy)) {
+ save_vbnv_cmos(vbnv_copy);
+ printk(BIOS_INFO, "VBNV: Flash backup restored\n");
+ } else {
+ printk(BIOS_INFO, "VBNV: Restore from flash failed\n");
+ }
+ }
}
void save_vbnv_cmos(const uint8_t *vbnv_copy)
@@ -33,3 +50,17 @@ void save_vbnv_cmos(const uint8_t *vbnv_copy)
for (i = 0; i < VBNV_BLOCK_SIZE; i++)
cmos_write(vbnv_copy[i], CONFIG_VBNV_OFFSET + 14 + i);
}
+
+#if IS_ENABLED(CONFIG_CHROMEOS_VBNV_CMOS_BACKUP_TO_FLASH)
+static void backup_vbnv_cmos(void *unused)
+{
+ uint8_t vbnv_cmos[VBNV_BLOCK_SIZE];
+
+ /* Read current VBNV from CMOS. */
+ read_vbnv_cmos(vbnv_cmos);
+
+ /* Save to flash, will only be saved if different. */
+ save_vbnv_flash(vbnv_cmos);
+}
+BOOT_STATE_INIT_ENTRY(BS_POST_DEVICE, BS_ON_EXIT, backup_vbnv_cmos, NULL);
+#endif
Patrick Georgi (pgeorgi(a)google.com) just uploaded a new patch set to gerrit, which you can find at https://review.coreboot.org/13599
-gerrit
commit 61e209aa6ee529bf3f5c26cf97629b0ed42f699f
Author: Duncan Laurie <dlaurie(a)chromium.org>
Date: Tue Jan 26 16:22:53 2016 -0800
chromeos: Make vbnv_flash driver safe for CAR usage
This modifies the vbnv_flash driver to make it safe for use
in cache-as-ram by handling the global variables safely.
To make this cleaner all of the variables were moved into
one structure and referenced from there.
BUG=chrome-os-partner:47915
BRANCH=glados
TEST=build and boot on chell using following patches to
test backup and restore of vbnv_cmos into flash
Change-Id: I3a17fa51cfd754455502ac2e5f181dae35967f2a
Signed-off-by: Patrick Georgi <pgeorgi(a)chromium.org>
Original-Commit-Id: 48876561fa4fb61e1ec8f92596c5610d97135201
Original-Change-Id: Id9fda8467edcc55e5ed760ddab197ab97d1f3d25
Original-Signed-off-by: Duncan Laurie <dlaurie(a)chromium.org>
Original-Reviewed-on: https://chromium-review.googlesource.com/324121
Original-Reviewed-by: Aaron Durbin <adurbin(a)chromium.org>
---
src/vendorcode/google/chromeos/vbnv_flash.c | 105 ++++++++++++++++------------
1 file changed, 62 insertions(+), 43 deletions(-)
diff --git a/src/vendorcode/google/chromeos/vbnv_flash.c b/src/vendorcode/google/chromeos/vbnv_flash.c
index ea5d9f3..88f39b0 100644
--- a/src/vendorcode/google/chromeos/vbnv_flash.c
+++ b/src/vendorcode/google/chromeos/vbnv_flash.c
@@ -11,10 +11,9 @@
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
- *
- * TODO: Make this CAR-friendly in case we use it on x86 some day.
*/
+#include <arch/early_variables.h>
#include <assert.h>
#include <console/console.h>
#include <spi_flash.h>
@@ -27,20 +26,26 @@
#define BLOB_SIZE VB2_NVDATA_SIZE
-/* FMAP descriptor of the NVRAM area */
-static struct region_device nvram_region;
+struct vbnv_flash_ctx {
+ /* VBNV flash is initialized */
+ int initialized;
+
+ /* Offset of the current nvdata in SPI flash */
+ int blob_offset;
-/* offset of the current nvdata in SPI flash */
-static int blob_offset = -1;
+ /* Offset of the topmost nvdata blob in SPI flash */
+ int top_offset;
-/* Offset of the topmost nvdata blob in SPI flash */
-static int top_offset;
+ /* SPI flash handler used when saving data */
+ struct spi_flash *flash;
-/* cache of the current nvdata */
-static uint8_t cache[BLOB_SIZE];
+ /* FMAP descriptor of the NVRAM area */
+ struct region_device region;
-/* spi_flash struct used when saving data */
-static struct spi_flash *spi_flash = NULL;
+ /* Cache of the current nvdata */
+ uint8_t cache[BLOB_SIZE];
+};
+static struct vbnv_flash_ctx vbnv_flash CAR_GLOBAL;
/*
* This code assumes that flash is erased to 1-bits, and write operations can
@@ -57,20 +62,16 @@ static inline int can_overwrite(uint8_t current, uint8_t new)
return (current & new) == new;
}
-static inline int is_initialized(void)
-{
- return blob_offset >= 0;
-}
-
static int init_vbnv(void)
{
+ struct vbnv_flash_ctx *ctx = car_get_var_ptr(&vbnv_flash);
uint8_t buf[BLOB_SIZE];
uint8_t empty_blob[BLOB_SIZE];
int offset;
int i;
- if (vboot_named_region_device("RW_NVRAM", &nvram_region) ||
- region_device_sz(&nvram_region) < BLOB_SIZE) {
+ if (vboot_named_region_device("RW_NVRAM", &ctx->region) ||
+ region_device_sz(&ctx->region) < BLOB_SIZE) {
printk(BIOS_ERR, "%s: failed to locate NVRAM\n", __func__);
return 1;
}
@@ -80,7 +81,7 @@ static int init_vbnv(void)
empty_blob[i] = erase_value();
offset = 0;
- top_offset = region_device_sz(&nvram_region) - BLOB_SIZE;
+ ctx->top_offset = region_device_sz(&ctx->region) - BLOB_SIZE;
/*
* after the loop, offset is supposed to point the blob right before
@@ -88,8 +89,8 @@ static int init_vbnv(void)
* empty blob, or the base of the region if the nvram has never been
* used.
*/
- for (i = 0; i <= top_offset; i += BLOB_SIZE) {
- if (rdev_readat(&nvram_region, buf, i, BLOB_SIZE) < 0) {
+ for (i = 0; i <= ctx->top_offset; i += BLOB_SIZE) {
+ if (rdev_readat(&ctx->region, buf, i, BLOB_SIZE) < 0) {
printk(BIOS_ERR, "failed to read nvdata\n");
return 1;
}
@@ -99,12 +100,13 @@ static int init_vbnv(void)
}
/* reread the nvdata and write it to the cache */
- if (rdev_readat(&nvram_region, cache, offset, BLOB_SIZE) < 0) {
+ if (rdev_readat(&ctx->region, ctx->cache, offset, BLOB_SIZE) < 0) {
printk(BIOS_ERR, "failed to read nvdata\n");
return 1;
}
- blob_offset = offset;
+ ctx->blob_offset = offset;
+ ctx->initialized = 1;
return 0;
}
@@ -122,15 +124,19 @@ static void vbnv_is_erasable(void)
*
* TODO: Check by calling can_erase implemented by each spi flash driver
*/
- assert(!(region_device_offset(&nvram_region) % spi_flash->sector_size));
- assert(!(region_device_sz(&nvram_region) % spi_flash->sector_size));
+ struct vbnv_flash_ctx *ctx = car_get_var_ptr(&vbnv_flash);
+
+ assert(!(region_device_offset(&ctx->region) % ctx->flash->sector_size));
+ assert(!(region_device_sz(&ctx->region) % ctx->flash->sector_size));
}
static int vbnv_flash_probe(void)
{
- if (!spi_flash) {
- spi_flash = spi_flash_probe(CONFIG_BOOT_MEDIA_SPI_BUS, 0);
- if (!spi_flash) {
+ struct vbnv_flash_ctx *ctx = car_get_var_ptr(&vbnv_flash);
+
+ if (!ctx->flash) {
+ ctx->flash = spi_flash_probe(CONFIG_BOOT_MEDIA_SPI_BUS, 0);
+ if (!ctx->flash) {
printk(BIOS_ERR, "failed to probe spi flash\n");
return 1;
}
@@ -140,16 +146,25 @@ static int vbnv_flash_probe(void)
*/
vbnv_is_erasable();
}
+
+ /*
+ * Handle the case where spi_flash_probe returns a CAR_GLOBAL
+ * in early execution on x86 but then later is moved to RAM.
+ */
+ ctx->flash = car_get_var_ptr(ctx->flash);
+
return 0;
}
static int erase_nvram(void)
{
+ struct vbnv_flash_ctx *ctx = car_get_var_ptr(&vbnv_flash);
+
if (vbnv_flash_probe())
return 1;
- if (spi_flash->erase(spi_flash, region_device_offset(&nvram_region),
- region_device_sz(&nvram_region))) {
+ if (ctx->flash->erase(ctx->flash, region_device_offset(&ctx->region),
+ region_device_sz(&ctx->region))) {
printk(BIOS_ERR, "failed to erase nvram\n");
return 1;
}
@@ -160,33 +175,37 @@ static int erase_nvram(void)
void read_vbnv_flash(uint8_t *vbnv_copy)
{
- if (!is_initialized())
+ struct vbnv_flash_ctx *ctx = car_get_var_ptr(&vbnv_flash);
+
+ if (!ctx->initialized)
if (init_vbnv())
return; /* error */
- memcpy(vbnv_copy, cache, BLOB_SIZE);
+
+ memcpy(vbnv_copy, ctx->cache, BLOB_SIZE);
}
void save_vbnv_flash(const uint8_t *vbnv_copy)
{
+ struct vbnv_flash_ctx *ctx = car_get_var_ptr(&vbnv_flash);
int new_offset;
int i;
- if (!is_initialized())
+ if (!ctx->initialized)
if (init_vbnv())
return; /* error */
/* Bail out if there have been no changes. */
- if (!memcmp(vbnv_copy, cache, BLOB_SIZE))
+ if (!memcmp(vbnv_copy, ctx->cache, BLOB_SIZE))
return;
- new_offset = blob_offset;
+ new_offset = ctx->blob_offset;
/* See if we can overwrite the current blob with the new one */
for (i = 0; i < BLOB_SIZE; i++) {
- if (!can_overwrite(cache[i], vbnv_copy[i])) {
+ if (!can_overwrite(ctx->cache[i], vbnv_copy[i])) {
/* unable to overwrite. need to use the next blob */
new_offset += BLOB_SIZE;
- if (new_offset > top_offset) {
+ if (new_offset > ctx->top_offset) {
if (erase_nvram())
return; /* error */
new_offset = 0;
@@ -196,12 +215,12 @@ void save_vbnv_flash(const uint8_t *vbnv_copy)
}
if (!vbnv_flash_probe() &&
- !spi_flash->write(spi_flash,
- region_device_offset(&nvram_region) + new_offset,
- BLOB_SIZE, vbnv_copy)) {
+ !ctx->flash->write(ctx->flash,
+ region_device_offset(&ctx->region) + new_offset,
+ BLOB_SIZE, vbnv_copy)) {
/* write was successful. safely move pointer forward */
- blob_offset = new_offset;
- memcpy(cache, vbnv_copy, BLOB_SIZE);
+ ctx->blob_offset = new_offset;
+ memcpy(ctx->cache, vbnv_copy, BLOB_SIZE);
} else {
printk(BIOS_ERR, "failed to save nvdata\n");
}
Patrick Georgi (pgeorgi(a)google.com) just uploaded a new patch set to gerrit, which you can find at https://review.coreboot.org/13586
-gerrit
commit 1d3fc77268f9c05c33ec3b5911c779c6cd38467b
Author: Aaron Durbin <adurbin(a)chromium.org>
Date: Wed Jan 27 14:23:17 2016 -0600
google/chromeos/vboot2: honor boot region device size
Vboot keeps track of the size of the hashed region in each
RW slot. While that size was being used to calculate the hash
it wasn't being honored in restricting the access within the
FMAP region for that RW slot. To alleviate that create a sub
region that covers the hashed data for the region in which
we boot from while performing CBFS accesses.
BUG=chrome-os-partner:49764
BUG=chromium:445938
BRANCH=glados
TEST=Built and booted chell with cbfstool and dev-util patches.
Change-Id: I1a4f45573a6eb8d53a63bc4b2453592664c4f78b
Signed-off-by: Patrick Georgi <pgeorgi(a)chromium.org>
Original-Commit-Id: 4ac9e84af5b632e5735736d505bb2ca6dba4ce28
Original-Change-Id: Idca946926f5cfd2c87c4a740ad2108010b6b6973
Original-Signed-off-by: Aaron Durbin <adurbin(a)chromium.org>
Original-Reviewed-on: https://chromium-review.googlesource.com/324093
Original-Reviewed-by: Duncan Laurie <dlaurie(a)chromium.org>
---
src/vendorcode/google/chromeos/vboot2/vboot_logic.c | 11 +++++++++++
1 file changed, 11 insertions(+)
diff --git a/src/vendorcode/google/chromeos/vboot2/vboot_logic.c b/src/vendorcode/google/chromeos/vboot2/vboot_logic.c
index 0d08d6a..fec368c 100644
--- a/src/vendorcode/google/chromeos/vboot2/vboot_logic.c
+++ b/src/vendorcode/google/chromeos/vboot2/vboot_logic.c
@@ -202,6 +202,17 @@ static int hash_body(struct vb2_context *ctx, struct region_device *fw_main)
if (rv)
return rv;
+ /*
+ * Honor vboot's RW slot size. The expected size is pulled out of
+ * the preamble and obtained through vb2api_init_hash() above. By
+ * creating sub region the RW slot portion of the boot media is
+ * limited.
+ */
+ if (rdev_chain(fw_main, fw_main, 0, expected_size)) {
+ printk(BIOS_ERR, "Unable to restrict CBFS size.\n");
+ return VB2_ERROR_UNKNOWN;
+ }
+
/* Extend over the body */
while (expected_size) {
uint64_t temp_ts;
Patrick Georgi (pgeorgi(a)google.com) just uploaded a new patch set to gerrit, which you can find at https://review.coreboot.org/13596
-gerrit
commit 2ad28bbb7feef54e53ea45dc1ae44d03593ccd18
Author: Julius Werner <jwerner(a)chromium.org>
Date: Mon Feb 1 19:47:10 2016 -0800
arch/arm64: Use correct SPSR.DAIF mask for BL31 and payload
The PSTATE mask bits for Debug exceptions, external Aborts, Interrupts
and Fast interrupts are usually best left unset: under normal
circumstances none of those exceptions should occur in firmware, and if
they do it's better to get a crash close to the code that caused it
(rather than much later when the kernel first unmasks them). For this
reason arm64_cpu_init unmasks them right after boot. However, the EL2
payload was still running with all mask bits set, which this patch
fixes.
BL31, on the other hand, explicitly wants to be entered with all masks
set (see calling convention in docs/firmware-design.md), which we had
previously not been doing. It doesn't seem to make a difference at the
moment, but since it's explicitly specified we should probably comply.
BRANCH=None
BUG=None
TEST=Booted Oak, confirmed with raw_read_daif() in payload that mask
bits are now cleared.
Change-Id: I04406da4c435ae7d44e2592c41f9807934bbc802
Signed-off-by: Patrick Georgi <pgeorgi(a)chromium.org>
Original-Commit-Id: 6ba55bc23fbde962d91c87dc0f982437572a69a8
Original-Change-Id: Ic5fbdd4e1cd7933c8b0c7c5fe72eac2022c9553c
Original-Signed-off-by: Julius Werner <jwerner(a)chromium.org>
Original-Reviewed-on: https://chromium-review.googlesource.com/325056
Original-Reviewed-by: Aaron Durbin <adurbin(a)chromium.org>
---
src/arch/arm64/arm_tf.c | 1 +
src/arch/arm64/boot.c | 2 +-
2 files changed, 2 insertions(+), 1 deletion(-)
diff --git a/src/arch/arm64/arm_tf.c b/src/arch/arm64/arm_tf.c
index 1cb35ba..9735e1b 100644
--- a/src/arch/arm64/arm_tf.c
+++ b/src/arch/arm64/arm_tf.c
@@ -84,6 +84,7 @@ void arm_tf_run_bl31(u64 payload_entry, u64 payload_arg0, u64 payload_spsr)
dcache_clean_by_mva(&bl31_params, sizeof(bl31_params));
dcache_clean_by_mva(&bl33_ep_info, sizeof(bl33_ep_info));
+ raw_write_daif(SPSR_EXCEPTION_MASK);
mmu_disable();
bl31_entry(&bl31_params, bl31_plat_params);
die("BL31 returned!");
diff --git a/src/arch/arm64/boot.c b/src/arch/arm64/boot.c
index eea758c..fa83c3f 100644
--- a/src/arch/arm64/boot.c
+++ b/src/arch/arm64/boot.c
@@ -31,7 +31,7 @@ static void run_payload(struct prog *prog)
doit = prog_entry(prog);
arg = prog_entry_arg(prog);
- u64 payload_spsr = SPSR_EXCEPTION_MASK | get_eret_el(EL2, SPSR_USE_L);
+ u64 payload_spsr = get_eret_el(EL2, SPSR_USE_L);
if (IS_ENABLED(CONFIG_ARM64_USE_ARM_TRUSTED_FIRMWARE))
arm_tf_run_bl31((u64)doit, (u64)arg, payload_spsr);
Patrick Georgi (pgeorgi(a)google.com) just uploaded a new patch set to gerrit, which you can find at https://review.coreboot.org/13595
-gerrit
commit fb5f1284831ccba9ebcd37231a9c95705cc5b58c
Author: Julius Werner <jwerner(a)chromium.org>
Date: Tue Jan 26 19:17:53 2016 -0800
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(a)chromium.org>
Original-Commit-Id: f3947f4bb0abf4466006d5e3a962bbcb8919b12d
Original-Change-Id: I1008883e5ed4cc37d30cae5777a60287d3d01af0
Original-Signed-off-by: Julius Werner <jwerner(a)chromium.org>
Original-Reviewed-on: https://chromium-review.googlesource.com/323862
Original-Reviewed-by: Aaron Durbin <adurbin(a)chromium.org>
---
src/arch/arm64/armv8/mmu.c | 26 ++++++++++++++++++++++++++
src/arch/arm64/include/armv8/arch/mmu.h | 1 +
2 files changed, 27 insertions(+)
diff --git a/src/arch/arm64/armv8/mmu.c b/src/arch/arm64/armv8/mmu.c
index 5d957d4..9280fc2 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);
diff --git a/src/arch/arm64/include/armv8/arch/mmu.h b/src/arch/arm64/include/armv8/arch/mmu.h
index 7c3b6a7..a812073 100644
--- a/src/arch/arm64/include/armv8/arch/mmu.h
+++ b/src/arch/arm64/include/armv8/arch/mmu.h
@@ -102,6 +102,7 @@
#define BLOCK_INDEX_MEM_NORMAL_NC 3
#define BLOCK_INDEX_MEM_NORMAL 4
+#define BLOCK_INDEX_MASK 0x7
#define BLOCK_INDEX_SHIFT 2
/* MAIR attributes */