diff options
-rw-r--r-- | src/soc/intel/common/Kconfig | 4 | ||||
-rw-r--r-- | src/soc/intel/common/mrc_cache.c | 21 | ||||
-rw-r--r-- | src/soc/intel/common/nvm.c | 44 | ||||
-rw-r--r-- | src/soc/intel/common/nvm.h | 6 |
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(¤t_saved->data[0], ¤t_boot->data[0], current_saved->size)) { printk(BIOS_DEBUG, "MRC cache up to date.\n"); + protect_mrc_cache(®ion); 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(®ion); } 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_ */ |