[coreboot-gerrit] Patch set updated for coreboot: soc/intel/common: remove mrc cache assumptions

Aaron Durbin (adurbin@chromium.org) gerrit at coreboot.org
Tue Dec 6 16:12:16 CET 2016


Aaron Durbin (adurbin at chromium.org) just uploaded a new patch set to gerrit, which you can find at https://review.coreboot.org/17717

-gerrit

commit d9959b08e690e9bea9ad6bd447e89e8be3e18550
Author: Aaron Durbin <adurbin at chromium.org>
Date:   Sat Dec 3 22:08:20 2016 -0600

    soc/intel/common: remove mrc cache assumptions
    
    Update the mrc cache implementation to use region_file. Instead
    of relying on memory-mapped access and pointer arithmetic
    use the region_devices and region_file to obtain the latest
    data associated with the region. This removes the need for the
    nvm wrapper as the region_devices can be used directly. Thus,
    the library is more generic and can be extended to work on
    different boot mediums.
    
    BUG=chrome-os-partner:56151
    
    Change-Id: Ic14e2d2f7339e50256b4a3a297fc33991861ca44
    Signed-off-by: Aaron Durbin <adurbin at chromium.org>
---
 src/drivers/intel/fsp1_1/romstage.c        |  29 +-
 src/drivers/intel/fsp2_0/memory_init.c     |  58 +--
 src/soc/intel/apollolake/mmap_boot.c       |  17 -
 src/soc/intel/apollolake/romstage.c        |  15 +-
 src/soc/intel/baytrail/romstage/raminit.c  |  15 +-
 src/soc/intel/broadwell/romstage/raminit.c |  16 +-
 src/soc/intel/common/mrc_cache.c           | 619 +++++++++++++++--------------
 src/soc/intel/common/mrc_cache.h           |  45 +--
 src/soc/intel/common/nvm.c                 | 122 ++----
 src/soc/intel/common/nvm.h                 |  16 +-
 10 files changed, 433 insertions(+), 519 deletions(-)

diff --git a/src/drivers/intel/fsp1_1/romstage.c b/src/drivers/intel/fsp1_1/romstage.c
index bb3e96c..73fb66d 100644
--- a/src/drivers/intel/fsp1_1/romstage.c
+++ b/src/drivers/intel/fsp1_1/romstage.c
@@ -19,6 +19,7 @@
 #include <arch/io.h>
 #include <arch/cbfs.h>
 #include <arch/early_variables.h>
+#include <assert.h>
 #include <boardid.h>
 #include <console/console.h>
 #include <cbmem.h>
@@ -99,7 +100,7 @@ void *cache_as_ram_stage_main(FSP_INFO_HEADER *fih)
 /* Entry from the mainboard. */
 void romstage_common(struct romstage_params *params)
 {
-	const struct mrc_saved_data *cache;
+	struct region_device rdev;
 	struct pei_data *pei_data;
 
 	post_code(0x32);
@@ -127,11 +128,15 @@ void romstage_common(struct romstage_params *params)
 			printk(BIOS_DEBUG,
 			       "Recovery mode: not using MRC cache.\n");
 		} else if (IS_ENABLED(CONFIG_CACHE_MRC_SETTINGS)
-			&& (!mrc_cache_get_current_with_version(&cache,
-							params->fsp_version))) {
+			&& (!mrc_cache_get_current(MRC_TRAINING_DATA,
+							params->fsp_version,
+							&rdev))) {
 			/* MRC cache found */
-			params->pei_data->saved_data_size = cache->size;
-			params->pei_data->saved_data = &cache->data[0];
+			params->pei_data->saved_data_size =
+				region_device_sz(&rdev);
+			params->pei_data->saved_data = rdev_mmap_full(&rdev);
+			/* Assum boot device is memory mapped. */
+			assert(IS_ENABLED(CONFIG_BOOT_DEVICE_MEMORY_MAPPED));
 		} else if (params->pei_data->boot_mode == ACPI_S3) {
 			/* Waking from S3 and no cache. */
 			printk(BIOS_DEBUG,
@@ -155,10 +160,10 @@ void romstage_common(struct romstage_params *params)
 		if ((params->pei_data->boot_mode != ACPI_S3)
 			&& (params->pei_data->data_to_save_size != 0)
 			&& (params->pei_data->data_to_save != NULL))
-				mrc_cache_stash_data_with_version(
+				mrc_cache_stash_data(MRC_TRAINING_DATA,
+					params->fsp_version,
 					params->pei_data->data_to_save,
-					params->pei_data->data_to_save_size,
-					params->fsp_version);
+					params->pei_data->data_to_save_size);
 	}
 
 	/* Save DIMM information */
@@ -355,15 +360,15 @@ __attribute__((weak)) void mainboard_add_dimm_info(
 }
 
 /* Get the memory configuration data */
-__attribute__((weak)) int mrc_cache_get_current_with_version(
-	const struct mrc_saved_data **cache, uint32_t version)
+__attribute__((weak)) int mrc_cache_get_current(int type, uint32_t version,
+				struct region_device *rdev)
 {
 	return -1;
 }
 
 /* Save the memory configuration data */
-__attribute__((weak)) int mrc_cache_stash_data_with_version(const void *data,
-	size_t size, uint32_t version)
+__attribute__((weak)) int mrc_cache_stash_data(int type, uint32_t version,
+					const void *data, size_t size)
 {
 	return -1;
 }
diff --git a/src/drivers/intel/fsp2_0/memory_init.c b/src/drivers/intel/fsp2_0/memory_init.c
index 283b179..fab65f2 100644
--- a/src/drivers/intel/fsp2_0/memory_init.c
+++ b/src/drivers/intel/fsp2_0/memory_init.c
@@ -15,6 +15,7 @@
 #include <arch/io.h>
 #include <arch/cpu.h>
 #include <arch/symbols.h>
+#include <assert.h>
 #include <cbfs.h>
 #include <cbmem.h>
 #include <console/console.h>
@@ -107,9 +108,9 @@ static void save_memory_training_data(bool s3wake, uint32_t fsp_version)
 	 * code which saves the data to flash doesn't write if the latest
 	 * training data matches this one.
 	 */
-	if (mrc_cache_stash_data_with_version(mrc_data, mrc_data_size,
-						fsp_version) < 0)
-			printk(BIOS_ERR, "Failed to stash MRC data\n");
+	if (mrc_cache_stash_data(MRC_TRAINING_DATA, fsp_version, mrc_data,
+				mrc_data_size) < 0)
+		printk(BIOS_ERR, "Failed to stash MRC data\n");
 
 	mrc_cache_update_tpm_hash(mrc_data, mrc_data_size);
 }
@@ -146,24 +147,6 @@ static void do_fsp_post_memory_init(bool s3wake, uint32_t fsp_version)
 	romstage_handoff_init(s3wake);
 }
 
-static const char *mrc_cache_get_region_name(void)
-{
-	/* In normal mode, always use DEFAULT_MRC_CACHE */
-	if (!vboot_recovery_mode_enabled())
-		return DEFAULT_MRC_CACHE;
-
-	/*
-	 * In recovery mode, force retraining by returning NULL if:
-	 * 1. Recovery cache is not supported, or
-	 * 2. Memory retrain switch is set.
-	 */
-	if (!IS_ENABLED(CONFIG_HAS_RECOVERY_MRC_CACHE) ||
-	    vboot_recovery_mode_memory_retrain())
-		return NULL;
-
-	return RECOVERY_MRC_CACHE;
-}
-
 static int mrc_cache_verify_tpm_hash(const uint8_t *data, size_t size)
 {
 	uint8_t data_hash[VB2_SHA256_DIGEST_SIZE];
@@ -209,29 +192,46 @@ static int mrc_cache_verify_tpm_hash(const uint8_t *data, size_t size)
 static void fsp_fill_mrc_cache(FSPM_ARCH_UPD *arch_upd, bool s3wake,
 				uint32_t fsp_version)
 {
-	const struct mrc_saved_data *mrc_cache;
-	const char *name;
+	struct region_device rdev;
+	void *data;
 
 	arch_upd->NvsBufferPtr = NULL;
 
 	if (!IS_ENABLED(CONFIG_CACHE_MRC_SETTINGS))
 		return;
 
-	name = mrc_cache_get_region_name();
+	/*
+	 * In recovery mode, force retraining:
+	 * 1. Recovery cache is not supported, or
+	 * 2. Memory retrain switch is set.
+	 */
+	if (vboot_recovery_mode_enabled()) {
+		if (!IS_ENABLED(CONFIG_HAS_RECOVERY_MRC_CACHE))
+			return;
+		if (vboot_recovery_mode_memory_retrain())
+			return;
+	}
+
+	if (mrc_cache_get_current(MRC_TRAINING_DATA, fsp_version, &rdev) < 0)
+		return;
+
+	/* Assume boot device is memory mapped. */
+	assert(IS_ENABLED(CONFIG_BOOT_DEVICE_MEMORY_MAPPED));
+	data = rdev_mmap_full(&rdev);
 
-	if (mrc_cache_get_current_from_region(&mrc_cache, fsp_version, name))
+	if (data == NULL)
 		return;
 
-	if (!mrc_cache_verify_tpm_hash(mrc_cache->data, mrc_cache->size))
+	if (!mrc_cache_verify_tpm_hash(data, region_device_sz(&rdev)))
 		return;
 
 	/* MRC cache found */
-	arch_upd->NvsBufferPtr = (void *)mrc_cache->data;
+	arch_upd->NvsBufferPtr = data;
 	arch_upd->BootMode = s3wake ?
 		FSP_BOOT_ON_S3_RESUME:
 		FSP_BOOT_ASSUMING_NO_CONFIGURATION_CHANGES;
-	printk(BIOS_SPEW, "MRC cache found, size %x bootmode:%d\n",
-				mrc_cache->size, arch_upd->BootMode);
+	printk(BIOS_SPEW, "MRC cache found, size %zx bootmode:%d\n",
+				region_device_sz(&rdev), arch_upd->BootMode);
 }
 
 static enum cb_err check_region_overlap(const struct memranges *ranges,
diff --git a/src/soc/intel/apollolake/mmap_boot.c b/src/soc/intel/apollolake/mmap_boot.c
index bf2e5b9..4617630 100644
--- a/src/soc/intel/apollolake/mmap_boot.c
+++ b/src/soc/intel/apollolake/mmap_boot.c
@@ -22,7 +22,6 @@
 #include <commonlib/region.h>
 #include <console/console.h>
 #include <fmap.h>
-#include <soc/intel/common/nvm.h>
 #include <soc/mmap_boot.h>
 #include <soc/spi.h>
 
@@ -148,22 +147,6 @@ const struct cbfs_locator cbfs_master_header_locator = {
 	.locate = iafw_boot_region_properties,
 };
 
-uint32_t nvm_mmio_to_flash_offset(void *p)
-{
-	bios_mmap_init();
-
-	size_t start, size;
-	start = car_get_var(bios_start);
-	size = car_get_var(bios_size);
-
-	/*
-	 * Returns :
-	 * addr - base of mmaped region in addr space + offset of mmaped region
-	 * start on flash
-	 */
-	return (uintptr_t)p - (4ULL * GiB - size) + start;
-}
-
 size_t get_bios_size(void)
 {
 	bios_mmap_init();
diff --git a/src/soc/intel/apollolake/romstage.c b/src/soc/intel/apollolake/romstage.c
index 039b586..feb566b 100644
--- a/src/soc/intel/apollolake/romstage.c
+++ b/src/soc/intel/apollolake/romstage.c
@@ -201,8 +201,9 @@ asmlinkage void car_stage_entry(void)
 	new_var_data = fsp_find_extension_hob_by_guid(hob_variable_guid,
 							&var_size);
 	if (new_var_data)
-		mrc_cache_stash_vardata(new_var_data, var_size,
-					car_get_var(fsp_version));
+		mrc_cache_stash_data(MRC_VARIABLE_DATA,
+				car_get_var(fsp_version), new_var_data,
+				var_size);
 	else
 		printk(BIOS_ERR, "Failed to determine variable data\n");
 
@@ -257,7 +258,7 @@ static void fill_console_params(FSPM_UPD *mupd)
 
 void platform_fsp_memory_init_params_cb(FSPM_UPD *mupd, uint32_t version)
 {
-	const struct mrc_saved_data *msd;
+	struct region_device rdev;
 
 	fill_console_params(mupd);
 	mainboard_memory_init_params(mupd);
@@ -292,10 +293,10 @@ void platform_fsp_memory_init_params_cb(FSPM_UPD *mupd, uint32_t version)
 	 * wrong/missing key renders DRAM contents useless.
 	 */
 
-	if (mrc_cache_get_vardata(&msd, version) < 0) {
-		printk(BIOS_DEBUG, "MRC variable data missing/invalid\n");
-	} else {
-		mupd->FspmConfig.VariableNvsBufferPtr = (void*) msd->data;
+	if (mrc_cache_get_current(MRC_VARIABLE_DATA, version, &rdev) == 0) {
+		/* Assume leaking is ok. */
+		assert(IS_ENABLED(CONFIG_BOOT_DEVICE_MEMORY_MAPPED));
+		mupd->FspmConfig.VariableNvsBufferPtr = rdev_mmap_full(&rdev);
 	}
 
 	car_set_var(fsp_version, version);
diff --git a/src/soc/intel/baytrail/romstage/raminit.c b/src/soc/intel/baytrail/romstage/raminit.c
index a79fe95..190231d 100644
--- a/src/soc/intel/baytrail/romstage/raminit.c
+++ b/src/soc/intel/baytrail/romstage/raminit.c
@@ -15,7 +15,7 @@
 
 #include <stddef.h>
 #include <arch/acpi.h>
-#include <arch/io.h>
+#include <assert.h>
 #include <cbfs.h>
 #include <cbmem.h>
 #include <console/console.h>
@@ -111,7 +111,7 @@ void raminit(struct mrc_params *mp, int prev_sleep_state)
 {
 	int ret;
 	mrc_wrapper_entry_t mrc_entry;
-	const struct mrc_saved_data *cache;
+	struct region_device rdev;
 
 	/* Fill in default entries. */
 	mp->version = MRC_PARAMS_VER;
@@ -125,9 +125,11 @@ void raminit(struct mrc_params *mp, int prev_sleep_state)
 
 	if (vboot_recovery_mode_enabled()) {
 		printk(BIOS_DEBUG, "Recovery mode: not using MRC cache.\n");
-	} else if (!mrc_cache_get_current(&cache)) {
-		mp->saved_data_size = cache->size;
-		mp->saved_data = &cache->data[0];
+	} else if (!mrc_cache_get_current(MRC_TRAINING_DATA, 0, &rdev)) {
+		mp->saved_data_size = region_device_sz(&rdev);
+		mp->saved_data = rdev_mmap_full(&rdev);
+		/* Assume boot device is memory mapped. */
+		assert(IS_ENABLED(CONFIG_BOOT_DEVICE_MEMORY_MAPPED));
 	} else if (prev_sleep_state == ACPI_S3) {
 		/* If waking from S3 and no cache then. */
 		printk(BIOS_DEBUG, "No MRC cache found in S3 resume path.\n");
@@ -178,5 +180,6 @@ void raminit(struct mrc_params *mp, int prev_sleep_state)
 	       mp->data_to_save_size);
 
 	if (mp->data_to_save != NULL && mp->data_to_save_size > 0)
-		mrc_cache_stash_data(mp->data_to_save, mp->data_to_save_size);
+		mrc_cache_stash_data(MRC_TRAINING_DATA, 0, mp->data_to_save,
+					mp->data_to_save_size);
 }
diff --git a/src/soc/intel/broadwell/romstage/raminit.c b/src/soc/intel/broadwell/romstage/raminit.c
index 61b1bc9..1185788 100644
--- a/src/soc/intel/broadwell/romstage/raminit.c
+++ b/src/soc/intel/broadwell/romstage/raminit.c
@@ -15,6 +15,7 @@
 
 #include <arch/cbfs.h>
 #include <arch/io.h>
+#include <assert.h>
 #include <cbfs.h>
 #include <cbmem.h>
 #include <console/console.h>
@@ -41,7 +42,7 @@
  */
 void raminit(struct pei_data *pei_data)
 {
-	const struct mrc_saved_data *cache;
+	struct region_device rdev;
 	struct memory_info* mem_info;
 	pei_wrapper_entry_t entry;
 	int ret;
@@ -51,10 +52,12 @@ void raminit(struct pei_data *pei_data)
 	if (vboot_recovery_mode_enabled()) {
 		/* Recovery mode does not use MRC cache */
 		printk(BIOS_DEBUG, "Recovery mode: not using MRC cache.\n");
-	} else if (!mrc_cache_get_current(&cache)) {
+	} else if (!mrc_cache_get_current(MRC_TRAINING_DATA, 0, &rdev)) {
 		/* MRC cache found */
-		pei_data->saved_data_size = cache->size;
-		pei_data->saved_data = &cache->data[0];
+		pei_data->saved_data_size = region_device_sz(&rdev);
+		pei_data->saved_data = rdev_mmap_full(&rdev);
+		/* Assume boot device is memory mapped. */
+		assert(IS_ENABLED(CONFIG_BOOT_DEVICE_MEMORY_MAPPED));
 	} else if (pei_data->boot_mode == ACPI_S3) {
 		/* Waking from S3 and no cache. */
 		printk(BIOS_DEBUG, "No MRC cache found in S3 resume path.\n");
@@ -118,8 +121,9 @@ void raminit(struct pei_data *pei_data)
 	       pei_data->data_to_save_size);
 
 	if (pei_data->data_to_save != NULL && pei_data->data_to_save_size > 0)
-		mrc_cache_stash_data(pei_data->data_to_save,
-				     pei_data->data_to_save_size);
+		mrc_cache_stash_data(MRC_TRAINING_DATA, 0,
+					pei_data->data_to_save,
+					pei_data->data_to_save_size);
 
 	printk(BIOS_DEBUG, "create cbmem for dimm information\n");
 	mem_info = cbmem_add(CBMEM_ID_MEMINFO, sizeof(struct memory_info));
diff --git a/src/soc/intel/common/mrc_cache.c b/src/soc/intel/common/mrc_cache.c
index e9d670e..bcb191e 100644
--- a/src/soc/intel/common/mrc_cache.c
+++ b/src/soc/intel/common/mrc_cache.c
@@ -14,344 +14,343 @@
  */
 
 #include <string.h>
+#include <boot_device.h>
 #include <bootstate.h>
 #include <console/console.h>
 #include <cbmem.h>
 #include <elog.h>
 #include <fmap.h>
 #include <ip_checksum.h>
+#include <region_file.h>
 #include <vboot/vboot_common.h>
 
 #include "mrc_cache.h"
 #include "nvm.h"
 
-#define MRC_DATA_ALIGN           0x1000
+#define DEFAULT_MRC_CACHE	"RW_MRC_CACHE"
+#define VARIABLE_MRC_CACHE	"RW_VAR_MRC_CACHE"
+#define RECOVERY_MRC_CACHE	"RECOVERY_MRC_CACHE"
+#define UNIFIED_MRC_CACHE	"UNIFIED_MRC_CACHE"
+
 #define MRC_DATA_SIGNATURE       (('M'<<0)|('R'<<8)|('C'<<16)|('D'<<24))
 
-/* The mrc_data_region describes the larger non-volatile area to store
- * mrc_saved_data objects.*/
-struct mrc_data_region {
-	void *base;
-	uint32_t size;
-};
+struct mrc_metadata {
+	uint32_t signature;
+	uint32_t data_size;
+	uint16_t data_checksum;
+	uint16_t header_checksum;
+	uint32_t version;
+} __attribute__((packed));
 
 enum result {
-	WRITE_FAILURE		= -1,
-	ERASE_FAILURE		= -2,
-	OTHER_FAILURE		= -3,
+	UPDATE_FAILURE		= -1,
 	UPDATE_SUCCESS		= 0,
 	ALREADY_UPTODATE	= 1
 };
 
-/* common code */
-static int mrc_cache_get_region(const char *name,
-				struct mrc_data_region *region)
-{
-	bool located_by_fmap = true;
-	struct region_device rdev;
+#define NORMAL_FLAG (1 << 0)
+#define RECOVERY_FLAG (1 << 1)
 
-	region->base = NULL;
-	region->size = 0;
-
-	if (fmap_locate_area_as_rdev(name, &rdev))
-		located_by_fmap =  false;
+struct cache_region {
+	const char *name;
+	uint32_t cbmem_id;
+	int type;
+	int elog_slot;
+	int flags;
+};
 
-	/* CHROMEOS builds must get their MRC cache from FMAP. */
-	if (IS_ENABLED(CONFIG_CHROMEOS) && !located_by_fmap)
-		return -1;
+static const struct cache_region recovery_training = {
+	.name = RECOVERY_MRC_CACHE,
+	.cbmem_id = CBMEM_ID_MRCDATA,
+	.type = MRC_TRAINING_DATA,
+	.elog_slot = ELOG_MEM_CACHE_UPDATE_SLOT_RECOVERY,
+#if IS_ENABLED(CONFIG_HAS_RECOVERY_MRC_CACHE)
+	.flags = RECOVERY_FLAG,
+#else
+	.flags = 0,
+#endif
+};
 
-	if (located_by_fmap) {
-		region->size = region_device_sz(&rdev);
-		region->base = rdev_mmap_full(&rdev);
+static const struct cache_region normal_training = {
+	.name = DEFAULT_MRC_CACHE,
+	.cbmem_id = CBMEM_ID_MRCDATA,
+	.type = MRC_TRAINING_DATA,
+	.elog_slot = ELOG_MEM_CACHE_UPDATE_SLOT_NORMAL,
+	.flags = NORMAL_FLAG | RECOVERY_FLAG,
+};
 
-		if (region->base == NULL)
-			return -1;
-	} else {
-		region->base = (void *)CONFIG_MRC_SETTINGS_CACHE_BASE;
-		region->size = CONFIG_MRC_SETTINGS_CACHE_SIZE;
-	}
+static const struct cache_region variable_data = {
+	.name = VARIABLE_MRC_CACHE,
+	.cbmem_id = CBMEM_ID_VAR_MRCDATA,
+	.type = MRC_VARIABLE_DATA,
+	.elog_slot = ELOG_MEM_CACHE_UPDATE_SLOT_VARIABLE,
+	.flags = NORMAL_FLAG | RECOVERY_FLAG,
+};
 
-	return 0;
-}
+/* Order matters here for priority in matching. */
+static const struct cache_region *cache_regions[] = {
+	&recovery_training,
+	&normal_training,
+	&variable_data,
+};
 
-/* Protect mrc region with a Protected Range Register */
-static int __protect_mrc_cache(const struct mrc_data_region *region,
-			       const char *name)
+static int lookup_region_by_name(const char *name, struct region *r)
 {
-	if (!IS_ENABLED(CONFIG_MRC_SETTINGS_PROTECT))
+	/* This assumes memory mapped boot media just under 4GiB. */
+	const uint32_t pointer_base_32bit = -CONFIG_ROM_SIZE;
+
+	if (fmap_locate_area(name, r) == 0)
 		return 0;
 
-	if (nvm_is_write_protected() <= 0) {
-		printk(BIOS_INFO, "MRC: NOT enabling PRR for %s.\n", name);
-		return 1;
+	/* CHROMEOS builds must get their MRC cache from FMAP. */
+	if (IS_ENABLED(CONFIG_CHROMEOS)) {
+		printk(BIOS_ERR, "MRC: Chrome OS lookup failure.\n");
+		return -1;
 	}
 
-	if (nvm_protect(region->base, region->size) < 0) {
-		printk(BIOS_ERR, "MRC: ERROR setting PRR for %s.\n", name);
+	if (!IS_ENABLED(CONFIG_BOOT_DEVICE_MEMORY_MAPPED))
 		return -1;
-	}
 
-	printk(BIOS_INFO, "MRC: Enabled Protected Range on %s.\n", name);
+	/* Base is in the form of a pointer. Make it an offset. */
+	r->offset = CONFIG_MRC_SETTINGS_CACHE_BASE - pointer_base_32bit;
+	r->size = CONFIG_MRC_SETTINGS_CACHE_SIZE;
+
 	return 0;
 }
 
-static int protect_mrc_cache(const char *name)
+static const struct cache_region *lookup_region_type(int type)
 {
-	struct mrc_data_region region;
-	if (mrc_cache_get_region(name, &region) < 0) {
-		printk(BIOS_ERR, "MRC: Could not find region %s\n", name);
-		return -1;
+	int i;
+	int flags;
+
+	if (vboot_recovery_mode_enabled())
+		flags = RECOVERY_FLAG;
+	else
+		flags = NORMAL_FLAG;
+
+	for (i = 0; i < ARRAY_SIZE(cache_regions); i++) {
+		if (cache_regions[i]->type != type)
+			continue;
+		if ((cache_regions[i]->flags & flags) == flags)
+			return cache_regions[i];
 	}
 
-	return __protect_mrc_cache(&region, name);
+	return NULL;
 }
 
-static int mrc_cache_in_region(const struct mrc_data_region *region,
-                               const struct mrc_saved_data *cache)
+int mrc_cache_stash_data(int type, uint32_t version, const void *data,
+			size_t size)
 {
-	uintptr_t region_end;
-	uintptr_t cache_end;
-
-	if ((uintptr_t)cache < (uintptr_t)region->base)
-		return 0;
+	const struct cache_region *cr;
+	size_t cbmem_size;
+	struct mrc_metadata *md;
+
+	cr = lookup_region_type(type);
+	if (cr == NULL) {
+		printk(BIOS_ERR, "MRC: failed to add to cbmem for type %d.\n",
+			type);
+		return -1;
+	}
 
-	region_end = (uintptr_t)region->base;
-	region_end += region->size;
+	cbmem_size = sizeof(*md) + size;
 
-	if ((uintptr_t)cache >= region_end)
-		return 0;
+	md = cbmem_add(cr->cbmem_id, cbmem_size);
 
-	if ((sizeof(*cache) + (uintptr_t)cache) >= region_end)
-		return 0;
+	if (md == NULL) {
+		printk(BIOS_ERR, "MRC: failed to add '%s' to cbmem.\n",
+			cr->name);
+		return -1;
+	}
 
-	cache_end = (uintptr_t)cache;
-	cache_end += cache->size + sizeof(*cache);
+	memset(md, 0, sizeof(*md));
+	md->signature = MRC_DATA_SIGNATURE;
+	md->data_size = size;
+	md->version = version;
+	md->data_checksum = compute_ip_checksum(data, size);
+	md->header_checksum = compute_ip_checksum(md, sizeof(*md));
+	memcpy(&md[1], data, size);
 
-	if (cache_end > region_end)
-		return 0;
-
-	return 1;
+	return 0;
 }
 
-static int mrc_cache_valid(const struct mrc_data_region *region,
-                           const struct mrc_saved_data *cache)
+static const struct cache_region *lookup_region(struct region *r, int type)
 {
-	uint32_t checksum;
-
-	if (cache->signature != MRC_DATA_SIGNATURE)
-		return 0;
-
-	if (cache->size > region->size)
-		return 0;
-
-	checksum = compute_ip_checksum((void *)&cache->data[0], cache->size);
-
-	if (cache->checksum != checksum)
-		return 0;
+	const struct cache_region *cr;
 
-	return 1;
-}
+	cr = lookup_region_type(type);
 
-static const struct mrc_saved_data *
-next_cache_block(const struct mrc_saved_data *cache)
-{
-	uintptr_t next = (uintptr_t)cache;
+	if (cr == NULL) {
+		printk(BIOS_ERR, "MRC: failed to locate region type %d.\n",
+			type);
+		return NULL;
+	}
 
-	next += ALIGN(cache->size + sizeof(*cache), MRC_DATA_ALIGN);
+	if (lookup_region_by_name(cr->name, r) < 0)
+		return NULL;
 
-	return (const struct mrc_saved_data *)next;
+	return cr;
 }
 
-/* Locate the most recently saved MRC data. */
-static int __mrc_cache_get_current(const struct mrc_data_region *region,
-                                   const struct mrc_saved_data **cache,
-                                   uint32_t version)
+static int mrc_header_valid(struct region_device *rdev, struct mrc_metadata *md)
 {
-	const struct mrc_saved_data *msd;
-	const struct mrc_saved_data *verified_cache;
-	int slot = 0;
+	uint16_t checksum;
+	uint16_t checksum_result;
+	size_t size;
 
-	msd = region->base;
-
-	verified_cache = NULL;
+	if (rdev_readat(rdev, md, 0, sizeof(*md)) < 0) {
+		printk(BIOS_ERR, "MRC: couldn't read metadata\n");
+		return -1;
+	}
 
-	while (mrc_cache_in_region(region, msd) &&
-	       mrc_cache_valid(region, msd)) {
-		verified_cache = msd;
-		msd = next_cache_block(msd);
-		slot++;
+	if (md->signature != MRC_DATA_SIGNATURE) {
+		printk(BIOS_ERR, "MRC: invalid header signature\n");
+		return -1;
 	}
 
-	/*
-	 * Update pointer to the most recently saved MRC data before returning
-	 * any error. This ensures that the caller can use next available slot
-	 * if required.
-	 */
-	*cache = verified_cache;
+	/* Compute checksum over header with 0 as the value. */
+	checksum = md->header_checksum;
+	md->header_checksum = 0;
+	checksum_result = compute_ip_checksum(md, sizeof(*md));
 
-	if (verified_cache == NULL)
+	if (checksum != checksum_result) {
+		printk(BIOS_ERR, "MRC: header checksum mismatch: %x vs %x\n",
+			checksum, checksum_result);
 		return -1;
+	}
+
+	/* Put back original. */
+	md->header_checksum = checksum;
 
-	if (verified_cache->version != version) {
-		printk(BIOS_DEBUG, "MRC: cache version mismatch: %x vs %x\n",
-			verified_cache->version, version);
+	/* Re-size the region device according to the metadata as a region_file
+	 * does block allocation. */
+	size = sizeof(*md) + md->data_size;
+	if (rdev_chain(rdev, rdev, 0, size) < 0) {
+		printk(BIOS_ERR, "MRC: size exceeds rdev size: %zx vs %zx\n",
+			size, region_device_sz(rdev));
 		return -1;
 	}
 
-	printk(BIOS_DEBUG, "MRC: cache slot %d @ %p\n", slot-1, verified_cache);
-
 	return 0;
 }
 
-int mrc_cache_get_current_from_region(const struct mrc_saved_data **cache,
-				      uint32_t version,
-				      const char *region_name)
+static int mrc_data_valid(const struct region_device *rdev,
+				struct mrc_metadata *md)
 {
-	struct mrc_data_region region;
-
-	if (!region_name) {
-		printk(BIOS_ERR, "MRC: Requires memory retraining.\n");
+	void *data;
+	uint16_t checksum;
+	const size_t md_size = sizeof(*md);
+	const size_t data_size = region_device_sz(rdev) - md_size;
+
+	data = rdev_mmap(rdev, md_size, data_size);
+	if (data == NULL) {
+		printk(BIOS_ERR, "MRC: mmap failure on data verification.\n");
 		return -1;
 	}
 
-	printk(BIOS_ERR, "MRC: Using data from %s\n", region_name);
-
-	if (mrc_cache_get_region(region_name, &region) < 0) {
-		printk(BIOS_ERR, "MRC: Region %s not found. "
-		       "Requires memory retraining.\n", region_name);
-		return -1;
-	}
+	checksum = compute_ip_checksum(data, data_size);
 
-	if (__mrc_cache_get_current(&region, cache, version) < 0) {
-		printk(BIOS_ERR, "MRC: Valid slot not found in %s."
-		       "Requires memory retraining.\n", region_name);
+	rdev_munmap(rdev, data);
+	if (md->data_checksum != checksum) {
+		printk(BIOS_ERR, "MRC: data checksum mismatch: %x vs %x\n",
+			md->data_checksum, checksum);
 		return -1;
 	}
 
 	return 0;
 }
 
-int mrc_cache_get_current_with_version(const struct mrc_saved_data **cache,
-				       uint32_t version)
-{
-	return mrc_cache_get_current_from_region(cache, version,
-						 DEFAULT_MRC_CACHE);
-}
-
-int mrc_cache_get_current(const struct mrc_saved_data **cache)
+static int mrc_cache_latest(const char *name,
+				const struct region_device *backing_rdev,
+				struct mrc_metadata *md,
+				struct region_file *cache_file,
+				struct region_device *rdev,
+				bool fail_bad_data)
 {
-	return mrc_cache_get_current_with_version(cache, 0);
-}
-
-int mrc_cache_get_vardata(const struct mrc_saved_data **cache, uint32_t version)
-{
-	struct mrc_data_region region;
-
-	if (mrc_cache_get_region(VARIABLE_MRC_CACHE, &region) < 0)
+	/* Init and obtain a handle to the file data. */
+	if (region_file_init(cache_file, backing_rdev) < 0) {
+		printk(BIOS_ERR, "MRC: region file invalid in '%s'\n", name);
 		return -1;
+	}
 
-	return __mrc_cache_get_current(&region, cache, version);
-}
-
-/* Fill in mrc_saved_data structure with payload. */
-static void mrc_cache_fill(struct mrc_saved_data *cache, const void *data,
-                           size_t size, uint32_t version)
-{
-	cache->signature = MRC_DATA_SIGNATURE;
-	cache->size = size;
-	cache->version = version;
-	memcpy(&cache->data[0], data, size);
-	cache->checksum = compute_ip_checksum((void *)&cache->data[0],
-	                                      cache->size);
-}
-
-static int _mrc_stash_data(const void *data, size_t size, uint32_t version,
-			    uint32_t cbmem_id)
-{
-	int cbmem_size;
-	struct mrc_saved_data *cache;
-
-	cbmem_size = sizeof(*cache) + ALIGN(size, 16);
-
-	cache = cbmem_add(cbmem_id, cbmem_size);
+	/* Provide a 0 sized region_device from here on out so the caller
+	 * has a valid yet unusable region_device. */
+	rdev_chain(rdev, backing_rdev, 0, 0);
 
-	if (cache == NULL) {
-		printk(BIOS_ERR, "MRC: No space in cbmem for training data.\n");
-		return -1;
+	/* No data to return. */
+	if (region_file_data(cache_file, rdev) < 0) {
+		printk(BIOS_ERR, "MRC: no data in '%s'\n", name);
+		return fail_bad_data ? -1 : 0;
 	}
 
-	/* Clear alignment padding bytes at end of data. */
-	memset(&cache->data[size], 0, cbmem_size - size - sizeof(*cache));
-
-	printk(BIOS_DEBUG, "MRC: Relocate data from %p to %p (%zu bytes)\n",
-	       data, cache, size);
+	/* Validate header and resize region to reflect actual usage on the
+	 * saved medium (including metadata and data). */
+	if (mrc_header_valid(rdev, md) < 0) {
+		printk(BIOS_ERR, "MRC: invalid header in '%s'\n", name);
+		return fail_bad_data ? -1 : 0;
+	}
 
-	mrc_cache_fill(cache, data, size, version);
+	/* Validate Data */
+	if (mrc_data_valid(rdev, md) < 0) {
+		printk(BIOS_ERR, "MRC: invalid data in '%s'\n", name);
+		return fail_bad_data ? -1 : 0;
+	}
 
 	return 0;
 }
 
-int mrc_cache_stash_data_with_version(const void *data, size_t size,
-					uint32_t version)
+int mrc_cache_get_current(int type, uint32_t version,
+				struct region_device *rdev)
 {
-	return _mrc_stash_data(data, size, version, CBMEM_ID_MRCDATA);
-}
+	const struct cache_region *cr;
+	struct region region;
+	struct region_device read_rdev;
+	struct region_file cache_file;
+	struct mrc_metadata md;
+	size_t data_size;
+	const size_t md_size = sizeof(md);
+	const bool fail_bad_data = true;
+
+	cr = lookup_region(&region, type);
+
+	if (cr == NULL)
+		return -1;
 
-int mrc_cache_stash_vardata(const void *data, size_t size, uint32_t version)
-{
-	return _mrc_stash_data(data, size, version, CBMEM_ID_VAR_MRCDATA);
-}
+	if (boot_device_ro_subregion(&region, &read_rdev) < 0)
+		return -1;
 
+	if (mrc_cache_latest(cr->name, &read_rdev, &md, &cache_file, rdev,
+		fail_bad_data) < 0)
+		return -1;
 
-int mrc_cache_stash_data(const void *data, size_t size)
-{
-	return mrc_cache_stash_data_with_version(data, size, 0);
+	if (version != md.version) {
+		printk(BIOS_INFO, "MRC: version mismatch: %x vs %x\n",
+			md.version, version);
+		return -1;
+	}
+
+	/* Re-size rdev to only contain the data. i.e. remove metadata. */
+	data_size = region_device_sz(rdev) - md_size;
+	return rdev_chain(rdev, rdev, md_size, data_size);
 }
 
-static int mrc_slot_valid(const struct mrc_data_region *region,
-                          const struct mrc_saved_data *slot,
-                          const struct mrc_saved_data *to_save)
+static bool mrc_cache_needs_update(const struct region_device *rdev,
+				const struct cbmem_entry *to_be_updated)
 {
-	uintptr_t region_begin;
-	uintptr_t region_end;
-	uintptr_t slot_end;
-	uintptr_t slot_begin;
-	uint32_t size;
-
-	region_begin = (uintptr_t)region->base;
-	region_end = region_begin + region->size;
-	slot_begin = (uintptr_t)slot;
-	size = to_save->size + sizeof(*to_save);
-	slot_end = slot_begin + size;
-
-	if (slot_begin < region_begin || slot_begin >= region_end)
-		return 0;
+	void *mapping;
+	size_t size = region_device_sz(rdev);
+	bool need_update = false;
 
-	if (size > region->size)
-		return 0;
-
-	if (slot_end > region_end || slot_end < region_begin)
-		return 0;
-
-	if (!nvm_is_erased(slot, size))
-		return 0;
+	if (cbmem_entry_size(to_be_updated) != size)
+		return true;
 
-	return 1;
-}
+	mapping = rdev_mmap_full(rdev);
 
-static const struct mrc_saved_data *
-mrc_cache_next_slot(const struct mrc_data_region *region,
-                    const struct mrc_saved_data *current_slot)
-{
-	const struct mrc_saved_data *next_slot;
+	if (memcmp(cbmem_entry_start(to_be_updated), mapping, size))
+		need_update = true;
 
-	if (current_slot == NULL) {
-		next_slot = region->base;
-	} else {
-		next_slot = next_cache_block(current_slot);
-	}
+	rdev_munmap(rdev, mapping);
 
-	return next_slot;
+	return need_update;
 }
 
 static void log_event_cache_update(uint8_t slot, enum result res)
@@ -363,9 +362,7 @@ static void log_event_cache_update(uint8_t slot, enum result res)
 
 	/* Filter through interesting events only */
 	switch (res) {
-	case WRITE_FAILURE:				/* fall-through */
-	case ERASE_FAILURE:				/* fall-through */
-	case OTHER_FAILURE:				/* fall-through */
+	case UPDATE_FAILURE:
 		event.status = ELOG_MEM_CACHE_UPDATE_STATUS_FAIL;
 		break;
 	case UPDATE_SUCCESS:
@@ -379,63 +376,95 @@ static void log_event_cache_update(uint8_t slot, enum result res)
 		printk(BIOS_ERR, "Failed to log mem cache update event.\n");
 }
 
-static int update_mrc_cache_type(uint32_t cbmem_id, const char *region_name)
+/* During ramstage this code purposefully uses incoherent transactions between
+ * read and write. The read assumes a memory-mapped boot device that can be used
+ * to quickly locate and compare the up-to-date data. However, when an update
+ * is required it uses the writeable region access to perform the update. */
+static void update_mrc_cache_by_type(int type)
 {
-	const struct mrc_saved_data *current_boot;
-	const struct mrc_saved_data *current_saved;
-	const struct mrc_saved_data *next_slot;
-	struct mrc_data_region region;
-	int res;
+	const struct cache_region *cr;
+	struct region region;
+	struct region_device read_rdev;
+	struct region_device write_rdev;
+	struct region_file cache_file;
+	struct mrc_metadata md;
+	const struct cbmem_entry *to_be_updated;
+	struct incoherent_rdev backing_irdev;
+	const struct region_device *backing_rdev;
+	struct region_device latest_rdev;
+	const bool fail_bad_data = false;
+
+	cr = lookup_region(&region, type);
+
+	if (cr == NULL)
+		return;
 
-	printk(BIOS_DEBUG, "MRC: Updating cache data.\n");
+	to_be_updated = cbmem_entry_find(cr->cbmem_id);
+	if (to_be_updated == NULL) {
+		printk(BIOS_ERR, "MRC: No data in cbmem for '%s'.\n",
+			cr->name);
+		return;
+	}
 
-	printk(BIOS_ERR, "MRC: Cache region selected - %s\n", region_name);
+	printk(BIOS_DEBUG, "MRC: Checking cached data update for '%s'.\n",
+		cr->name);
 
-	if (mrc_cache_get_region(region_name, &region)) {
-		printk(BIOS_ERR, "MRC: Could not obtain cache region.\n");
-		return OTHER_FAILURE;
-	}
+	if (boot_device_ro_subregion(&region, &read_rdev) < 0)
+		return;
 
-	current_boot = cbmem_find(cbmem_id);
-	if (!current_boot) {
-		printk(BIOS_ERR, "MRC: No cache in cbmem.\n");
-		return OTHER_FAILURE;
-	}
+	if (boot_device_rw_subregion(&region, &write_rdev) < 0)
+		return;
+
+	backing_rdev = incoherent_rdev_init(&backing_irdev, &region, &read_rdev,
+						&write_rdev);
 
-	if (!mrc_cache_valid(&region, current_boot)) {
-		printk(BIOS_ERR, "MRC: Cache data in cbmem invalid.\n");
-		return OTHER_FAILURE;
+	if (backing_rdev == NULL)
+		return;
+
+	if (mrc_cache_latest(cr->name, backing_rdev, &md, &cache_file,
+		&latest_rdev, fail_bad_data) < 0)
+		return;
+
+	if (!mrc_cache_needs_update(&latest_rdev, to_be_updated)) {
+		log_event_cache_update(cr->elog_slot, ALREADY_UPTODATE);
+		return;
 	}
 
-	current_saved = NULL;
+	printk(BIOS_DEBUG, "MRC: cache data '%s' needs update.\n", cr->name);
+
+	if (region_file_update_data(&cache_file,
+		cbmem_entry_start(to_be_updated),
+		cbmem_entry_size(to_be_updated)) < 0)
+		log_event_cache_update(cr->elog_slot, UPDATE_FAILURE);
+	else
+		log_event_cache_update(cr->elog_slot, UPDATE_SUCCESS);
+}
+
+/* Protect mrc region with a Protected Range Register */
+static int protect_mrc_cache(const char *name)
+{
+	struct region region;
+
+	if (!IS_ENABLED(CONFIG_MRC_SETTINGS_PROTECT))
+		return 0;
+
+	if (lookup_region_by_name(name, &region) < 0) {
+		printk(BIOS_ERR, "MRC: Could not find region '%s'\n", name);
+		return -1;
+	}
 
-	if (!__mrc_cache_get_current(&region, &current_saved,
-					current_boot->version)) {
-		if (current_saved->size == current_boot->size &&
-		    !memcmp(&current_saved->data[0], &current_boot->data[0],
-		            current_saved->size)) {
-			printk(BIOS_DEBUG, "MRC: Cache up to date.\n");
-			return ALREADY_UPTODATE;
-		}
+	if (nvm_is_write_protected() <= 0) {
+		printk(BIOS_INFO, "MRC: NOT enabling PRR for '%s'.\n", name);
+		return 0;
 	}
 
-	next_slot = mrc_cache_next_slot(&region, current_saved);
-
-	if (!mrc_slot_valid(&region, next_slot, current_boot)) {
-		printk(BIOS_DEBUG, "MRC: Slot @ %p is invalid.\n", next_slot);
-		if (!nvm_is_erased(region.base, region.size)) {
-			if (nvm_erase(region.base, region.size) < 0) {
-				printk(BIOS_DEBUG, "MRC: Failure erasing "
-				       "region %s.\n", region_name);
-				return ERASE_FAILURE;
-			}
-		}
-		next_slot = region.base;
+	if (nvm_protect(&region) < 0) {
+		printk(BIOS_ERR, "MRC: ERROR setting PRR for '%s'.\n", name);
+		return -1;
 	}
 
-	res = nvm_write((void *)next_slot, current_boot, current_boot->size
-			 + sizeof(*current_boot));
-	return res < 0 ? WRITE_FAILURE : UPDATE_SUCCESS;
+	printk(BIOS_INFO, "MRC: Enabled Protected Range on '%s'.\n", name);
+	return 0;
 }
 
 static void protect_mrc_region(void)
@@ -459,30 +488,10 @@ static void protect_mrc_region(void)
 
 static void update_mrc_cache(void *unused)
 {
-	uint8_t slot;
-	const char *region_name;
-	enum result res;
-
-	/* First update either recovery or default cache */
-	if (vboot_recovery_mode_enabled() &&
-	    IS_ENABLED(CONFIG_HAS_RECOVERY_MRC_CACHE)) {
-		region_name = RECOVERY_MRC_CACHE;
-		slot = ELOG_MEM_CACHE_UPDATE_SLOT_RECOVERY;
-	} else {
-		region_name = DEFAULT_MRC_CACHE;
-		slot = ELOG_MEM_CACHE_UPDATE_SLOT_NORMAL;
-	}
+	update_mrc_cache_by_type(MRC_TRAINING_DATA);
 
-	res = update_mrc_cache_type(CBMEM_ID_MRCDATA, region_name);
-	log_event_cache_update(slot, res);
-
-	/* Next update variable cache if in use */
-	if (IS_ENABLED(CONFIG_MRC_SETTINGS_VARIABLE_DATA)) {
-		res = update_mrc_cache_type(CBMEM_ID_VAR_MRCDATA,
-					    VARIABLE_MRC_CACHE);
-		log_event_cache_update(ELOG_MEM_CACHE_UPDATE_SLOT_VARIABLE,
-					res);
-	}
+	if (IS_ENABLED(CONFIG_MRC_SETTINGS_VARIABLE_DATA))
+		update_mrc_cache_by_type(MRC_VARIABLE_DATA);
 
 	protect_mrc_region();
 }
diff --git a/src/soc/intel/common/mrc_cache.h b/src/soc/intel/common/mrc_cache.h
index 6414acc..4511fc3 100644
--- a/src/soc/intel/common/mrc_cache.h
+++ b/src/soc/intel/common/mrc_cache.h
@@ -19,34 +19,25 @@
 #include <stddef.h>
 #include <stdint.h>
 
-#define DEFAULT_MRC_CACHE	"RW_MRC_CACHE"
-#define VARIABLE_MRC_CACHE	"RW_VAR_MRC_CACHE"
-#define RECOVERY_MRC_CACHE	"RECOVERY_MRC_CACHE"
-#define UNIFIED_MRC_CACHE	"UNIFIED_MRC_CACHE"
+enum {
+	MRC_TRAINING_DATA,
+	MRC_VARIABLE_DATA,
+};
 
-/* Wrapper object to save MRC information. */
-struct mrc_saved_data {
-	uint32_t signature;
-	uint32_t size;
-	uint32_t checksum;
-	uint32_t version;
-	uint8_t  data[0];
-} __attribute__((packed));
-
-/* Locate the most recently saved MRC data. */
-int mrc_cache_get_current(const struct mrc_saved_data **cache);
-int mrc_cache_get_current_with_version(const struct mrc_saved_data **cache,
-					uint32_t version);
-int mrc_cache_get_vardata(const struct mrc_saved_data **cache,
-			    uint32_t version);
-int mrc_cache_get_current_from_region(const struct mrc_saved_data **cache,
-				      uint32_t version,
-				      const char *region_name);
+/*
+ * It's up to the caller to decide when to retrieve and stash data. There is
+ * differentiation on recovery mode CONFIG_HAS_RECOVERY_MRC_CACHE, but that's
+ * only for locating where to retrieve and save the data. If a platform doesn't
+ * want to update the data then it shouldn't stash the data for saving.
+ * Similarly, if the platform doesn't need the data for booting because of a
+ * policy don't request the data.
+ */
 
-/* Stash the resulting MRC data to be saved in non-volatile storage later. */
-int mrc_cache_stash_data(const void *data, size_t size);
-int mrc_cache_stash_data_with_version(const void *data, size_t size,
-					uint32_t version);
-int mrc_cache_stash_vardata(const void *data, size_t size, uint32_t version);
+/* Get and stash data for saving provided the type passed in. The functions
+ * return < 0 on error, 0 on success. */
+int mrc_cache_get_current(int type, uint32_t version,
+				struct region_device *rdev);
+int mrc_cache_stash_data(int type, uint32_t version, const void *data,
+			size_t size);
 
 #endif /* _COMMON_MRC_CACHE_H_ */
diff --git a/src/soc/intel/common/nvm.c b/src/soc/intel/common/nvm.c
index 99a1fbf..b7e0f4e 100644
--- a/src/soc/intel/common/nvm.c
+++ b/src/soc/intel/common/nvm.c
@@ -24,113 +24,43 @@
 #include "nvm.h"
 #include "spi_flash.h"
 
-/* This module assumes the flash is memory mapped just below 4GiB in the
- * address space for reading. Also this module assumes an area it erased
- * when all bytes read as all 0xff's. */
-
-static struct spi_flash *flash;
-
-static int nvm_init(void)
+/* Read flash status register to determine if write protect is active */
+int nvm_is_write_protected(void)
 {
-	if (flash != NULL)
-		return 0;
+	u8 sr1;
+	u8 wp_gpio;
+	u8 wp_spi;
 
-	spi_init();
-	flash = spi_flash_probe(0, 0);
-	if (!flash) {
-		printk(BIOS_DEBUG, "Could not find SPI device\n");
-		return -1;
-	}
-
-	return 0;
-}
+	if (!IS_ENABLED(CONFIG_CHROMEOS))
+		return 0;
 
-/*
- * Convert memory mapped pointer to flash offset.
- *
- * This is weak because not every platforms memory-maps the NVM media in the
- * same manner. This is a stop-gap solution.
- *
- * The root of the problem is that users of this API work in memory space for
- * both reads and writes, but erase and write must be done in flash space. This
- * also only works when the media is memory-mapped, which is no longer
- * universally true. The long-term approach should be to rewrite this and its
- * users to work in flash space, while using rdev_read() instead of rdev_mmap().
- */
-__attribute__((weak))
-uint32_t nvm_mmio_to_flash_offset(void *p)
-{
-	return CONFIG_ROM_SIZE + (uintptr_t)p;
-}
+	if (!IS_ENABLED(CONFIG_BOOT_DEVICE_SPI_FLASH))
+		return 0;
 
-int nvm_is_erased(const void *start, size_t size)
-{
-	const uint8_t *cur = start;
-	const uint8_t erased_value = 0xff;
+	/* Read Write Protect GPIO if available */
+	wp_gpio = get_write_protect_state();
 
-	while (size > 0) {
-		if (*cur != erased_value)
-			return 0;
-		cur++;
-		size--;
+	/* Read Status Register 1 */
+	if (spi_flash_status(boot_device_spi_flash(), &sr1) < 0) {
+		printk(BIOS_ERR, "Failed to read SPI status register 1\n");
+		return -1;
 	}
-	return 1;
-}
+	wp_spi = !!(sr1 & 0x80);
 
-int nvm_erase(void *start, size_t size)
-{
-	if (nvm_init() < 0)
-		return -1;
-	return spi_flash_erase(flash, nvm_mmio_to_flash_offset(start), size);
-}
+	printk(BIOS_DEBUG, "SPI flash protection: WPSW=%d SRP0=%d\n",
+		wp_gpio, wp_spi);
 
-/* Write data to NVM. Returns 0 on success < 0 on error.  */
-int nvm_write(void *start, const void *data, size_t size)
-{
-	if (nvm_init() < 0)
-		return -1;
-	return spi_flash_write(flash, nvm_mmio_to_flash_offset(start), size,
-				data);
+	return wp_gpio && wp_spi;
 }
 
-/* Read flash status register to determine if write protect is active */
-int nvm_is_write_protected(void)
+/* Apply protection to a range of flash */
+int nvm_protect(const struct region *r)
 {
-	if (nvm_init() < 0)
-		return -1;
-
-	if (IS_ENABLED(CONFIG_CHROMEOS)) {
-		u8 sr1;
-		u8 wp_gpio;
-		u8 wp_spi;
-
-		/* Read Write Protect GPIO if available */
-		wp_gpio = get_write_protect_state();
-
-		/* Read Status Register 1 */
-		if (spi_flash_status(flash, &sr1) < 0) {
-			printk(BIOS_ERR,
-				"Failed to read SPI status register 1\n");
-			return -1;
-		}
-		wp_spi = !!(sr1 & 0x80);
-
-		printk(BIOS_DEBUG, "SPI flash protection: WPSW=%d SRP0=%d\n",
-		       wp_gpio, wp_spi);
+	if (!IS_ENABLED(CONFIG_MRC_SETTINGS_PROTECT))
+		return 0;
 
-		return wp_gpio && wp_spi;
-	}
-	return 0;
-}
+	if (!IS_ENABLED(CONFIG_BOOT_DEVICE_SPI_FLASH))
+		return 0;
 
-/* Apply protection to a range of flash */
-int nvm_protect(void *start, size_t size)
-{
-#if IS_ENABLED(CONFIG_MRC_SETTINGS_PROTECT)
-	if (nvm_init() < 0)
-		return -1;
-	return spi_flash_protect(nvm_mmio_to_flash_offset(start), size);
-#else
-	return -1;
-#endif
+	return spi_flash_protect(region_offset(r), region_sz(r));
 }
diff --git a/src/soc/intel/common/nvm.h b/src/soc/intel/common/nvm.h
index 074a2ce..1e32ed8 100644
--- a/src/soc/intel/common/nvm.h
+++ b/src/soc/intel/common/nvm.h
@@ -16,24 +16,12 @@
 #ifndef _COMMON_NVM_H_
 #define _COMMON_NVM_H_
 
-#include <stddef.h>
-
-/* Determine if area is erased. returns 1 if erased. 0 otherwise. */
-int nvm_is_erased(const void *start, size_t size);
-
-/* Erase region according to start and size. Returns < 0 on error else 0. */
-int nvm_erase(void *start, size_t size);
-
-/* Write data to NVM. Returns 0 on success < 0 on error.  */
-int nvm_write(void *start, const void *data, size_t size);
+#include <commonlib/region.h>
 
 /* Determine if flash device is write protected */
 int nvm_is_write_protected(void);
 
 /* Apply protection to a range of flash */
-int nvm_protect(void *start, size_t size);
-
-/* Map MMIO address to actual address in flash */
-uint32_t nvm_mmio_to_flash_offset(void *p);
+int nvm_protect(const struct region *region);
 
 #endif /* _COMMON_NVM_H_ */



More information about the coreboot-gerrit mailing list