summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--src/soc/intel/common/Kconfig4
-rw-r--r--src/soc/intel/common/mrc_cache.c21
-rw-r--r--src/soc/intel/common/nvm.c44
-rw-r--r--src/soc/intel/common/nvm.h6
4 files changed, 75 insertions, 0 deletions
diff --git a/src/soc/intel/common/Kconfig b/src/soc/intel/common/Kconfig
index 8b02a4a905..aadd64d0b5 100644
--- a/src/soc/intel/common/Kconfig
+++ b/src/soc/intel/common/Kconfig
@@ -14,6 +14,10 @@ config MRC_SETTINGS_CACHE_SIZE
hex
default 0x10000
+config MRC_SETTINGS_PROTECT
+ bool "Enable protection on MRC settings"
+ default n
+
endif # CACHE_MRC_SETTINGS
endif # HAVE_MRC
diff --git a/src/soc/intel/common/mrc_cache.c b/src/soc/intel/common/mrc_cache.c
index 5860201477..f854046459 100644
--- a/src/soc/intel/common/mrc_cache.c
+++ b/src/soc/intel/common/mrc_cache.c
@@ -247,6 +247,25 @@ mrc_cache_next_slot(const struct mrc_data_region *region,
return next_slot;
}
+/* Protect RW_MRC_CACHE region with a Protected Range Register */
+static int protect_mrc_cache(const struct mrc_data_region *region)
+{
+#if IS_ENABLED(CONFIG_MRC_SETTINGS_PROTECT)
+ if (nvm_is_write_protected() <= 0) {
+ printk(BIOS_INFO, "NOT enabling PRR for RW_MRC_CACHE region\n");
+ return 1;
+ }
+
+ if (nvm_protect(region->base, region->size) < 0) {
+ printk(BIOS_ERR, "ERROR setting PRR for RW_MRC_CACHE region\n");
+ return -1;
+ }
+
+ printk(BIOS_INFO, "Enabled Protected Range on RW_MRC_CACHE region\n");
+#endif
+ return 0;
+}
+
static void update_mrc_cache(void *unused)
{
const struct mrc_saved_data *current_boot;
@@ -279,6 +298,7 @@ static void update_mrc_cache(void *unused)
!memcmp(&current_saved->data[0], &current_boot->data[0],
current_saved->size)) {
printk(BIOS_DEBUG, "MRC cache up to date.\n");
+ protect_mrc_cache(&region);
return;
}
}
@@ -301,6 +321,7 @@ static void update_mrc_cache(void *unused)
printk(BIOS_DEBUG, "Failure writing MRC cache to %p.\n",
next_slot);
}
+ protect_mrc_cache(&region);
}
BOOT_STATE_INIT_ENTRY(BS_WRITE_TABLES, BS_ON_ENTRY, update_mrc_cache, NULL);
diff --git a/src/soc/intel/common/nvm.c b/src/soc/intel/common/nvm.c
index 791422fe30..01138da0a6 100644
--- a/src/soc/intel/common/nvm.c
+++ b/src/soc/intel/common/nvm.c
@@ -23,6 +23,10 @@
#include <string.h>
#include <spi-generic.h>
#include <spi_flash.h>
+#include <soc/spi.h>
+#if CONFIG_CHROMEOS
+#include <vendorcode/google/chromeos/chromeos.h>
+#endif
#include "nvm.h"
/* This module assumes the flash is memory mapped just below 4GiB in the
@@ -80,3 +84,43 @@ int nvm_write(void *start, const void *data, size_t size)
return -1;
return flash->write(flash, to_flash_offset(start), size, data);
}
+
+/* Read flash status register to determine if write protect is active */
+int nvm_is_write_protected(void)
+{
+ u8 sr1;
+ u8 wp_gpio = 0;
+ u8 wp_spi;
+
+ if (nvm_init() < 0)
+ return -1;
+
+#if IS_ENABLED(CONFIG_CHROMEOS)
+ /* Read Write Protect GPIO if available */
+ wp_gpio = get_write_protect_state();
+#endif
+
+ /* Read Status Register 1 */
+ if (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);
+
+ return wp_gpio && wp_spi;
+}
+
+/* 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(to_flash_offset(start), size);
+#else
+ return -1;
+#endif
+}
diff --git a/src/soc/intel/common/nvm.h b/src/soc/intel/common/nvm.h
index d332d831f7..2e6b364c9f 100644
--- a/src/soc/intel/common/nvm.h
+++ b/src/soc/intel/common/nvm.h
@@ -31,4 +31,10 @@ 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);
+/* 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);
+
#endif /* _COMMON_NVM_H_ */