Attention is currently required from: Jason Glenesk, Raul Rangel, Matt DeVillier, Felix Held.
Fred Reitberger has uploaded this change for review. ( https://review.coreboot.org/c/coreboot/+/67301 )
Change subject: soc/amd/common/block/apob: Add hashed APOB support ......................................................................
soc/amd/common/block/apob: Add hashed APOB support
Comparing the APOB in RAM to flash takes a significant amount of time (~11ms). Instead of comparing the entire APOB, use a fast hash function and compare just that. Reading, hashing, and comparing the hash take ~70 microseconds.
BUG=b:193557430 TEST=compile and boot to OS in chausie with and without this option set
Signed-off-by: Fred Reitberger reitbergerfred@gmail.com Change-Id: I241968b115aaf41af63445410660bdd5199ceaba --- M src/soc/amd/common/block/apob/Kconfig M src/soc/amd/common/block/apob/apob_cache.c 2 files changed, 91 insertions(+), 0 deletions(-)
git pull ssh://review.coreboot.org:29418/coreboot refs/changes/01/67301/1
diff --git a/src/soc/amd/common/block/apob/Kconfig b/src/soc/amd/common/block/apob/Kconfig index b0cca51..c8ebc19 100644 --- a/src/soc/amd/common/block/apob/Kconfig +++ b/src/soc/amd/common/block/apob/Kconfig @@ -3,3 +3,9 @@ help Select this option to add firmware support for the non-volatile APOB cache to the build. + +config SOC_AMD_COMMON_BLOCK_APOB_HASH + bool + help + Select this to use a hash of the APOB data to determine when to update + the non-volatile APOB store. diff --git a/src/soc/amd/common/block/apob/apob_cache.c b/src/soc/amd/common/block/apob/apob_cache.c index 32207bb..8f2cff1 100644 --- a/src/soc/amd/common/block/apob/apob_cache.c +++ b/src/soc/amd/common/block/apob/apob_cache.c @@ -15,9 +15,19 @@ #include <string.h> #include <thread.h> #include <timestamp.h> +#include <xxhash.h>
#define DEFAULT_MRC_CACHE "RW_MRC_CACHE" #define DEFAULT_MRC_CACHE_SIZE FMAP_SECTION_RW_MRC_CACHE_SIZE +#define DEFAULT_MRC_HASH "RW_MRC_HASH" + +#define MRC_HASH_UNINITIALIZED 0xffffffffull + +#ifndef FMAP_SECTION_RW_MRC_HASH_SIZE +#define DEFAULT_MRC_HASH_SIZE 0 +#else +#define DEFAULT_MRC_HASH_SIZE FMAP_SECTION_RW_MRC_HASH_SIZE +#endif
#if !CONFIG_PSP_APOB_DRAM_ADDRESS #error Incorrect APOB configuration setting(s) @@ -139,6 +149,44 @@ return rdev_mmap_full(read_rdev); }
+static uint64_t get_apob_hash_from_nv_rdev(void) +{ + struct region_device r; + uint64_t hash; + + if (fmap_locate_area_as_rdev(DEFAULT_MRC_HASH, &r) < 0) { + printk(BIOS_ERR, "No APOB NV hash region is found in flash\n"); + return MRC_HASH_UNINITIALIZED; + } + + if (rdev_readat(&r, &hash, 0, sizeof(hash)) < 0) { + printk(BIOS_ERR, "Couldn't read APOB hash!\n"); + return MRC_HASH_UNINITIALIZED; + } + + return hash; +} + +static void update_apob_nv_hash(uint64_t hash) +{ + struct region_device write_rdev; + + if (fmap_locate_area_as_rdev_rw(DEFAULT_MRC_HASH, &write_rdev) < 0) { + printk(BIOS_ERR, "No RW APOB NV hash region is found in flash\n"); + return; + } + + if (rdev_eraseat(&write_rdev, 0, DEFAULT_MRC_HASH_SIZE) < 0) { + printk(BIOS_ERR, "APOB hash flash region erase failed\n"); + return; + } + + if (rdev_writeat(&write_rdev, &hash, 0, sizeof(hash)) < 0) { + printk(BIOS_ERR, "APOB hash flash region update failed\n"); + return; + } +} + /* Save APOB buffer to flash */ static void soc_update_apob_cache(void *unused) { @@ -146,6 +194,7 @@ struct region_device read_rdev, write_rdev; bool update_needed = false; const struct apob_base_header *apob_src_ram; + uint64_t ram_hash, nv_hash;
/* Nothing to update in case of S3 resume. */ if (acpi_is_wakeup_s3()) @@ -160,6 +209,20 @@
timestamp_add_now(TS_AMD_APOB_READ_START);
+ if (CONFIG(SOC_AMD_COMMON_BLOCK_APOB_HASH)) { + nv_hash = get_apob_hash_from_nv_rdev(); + ram_hash = xxh64(apob_src_ram, apob_src_ram->size, 0); + + if (nv_hash != ram_hash) { + printk(BIOS_INFO, "APOB RAM hash differs from flash\n"); + update_needed = true; + } else { + printk(BIOS_DEBUG, "APOB hash matches flash\n"); + timestamp_add_now(TS_AMD_APOB_END); + return; + } + } + if (CONFIG(COOP_MULTITASKING) && thread_join(&global_apob_thread.handle) == CB_SUCCESS) apob_rom = (struct apob_base_header *)global_apob_thread.buffer; else @@ -202,6 +265,10 @@ return; }
+ if (CONFIG(SOC_AMD_COMMON_BLOCK_APOB_HASH)) { + update_apob_nv_hash(ram_hash); + } + timestamp_add_now(TS_AMD_APOB_END);
printk(BIOS_INFO, "Updated APOB in flash\n");