diff options
author | Duncan Laurie <dlaurie@chromium.org> | 2012-01-03 11:14:53 -0800 |
---|---|---|
committer | Duncan Laurie <dlaurie@chromium.org> | 2012-01-03 13:49:14 -0800 |
commit | ae23071e4528961593a6c9cf8e490e906cdd5ab0 (patch) | |
tree | a0353e9a70c64d50c15761f3dbcf423b30407b38 | |
parent | 392bdcc9a7e548b108f5cd3b1c514e68b65b985f (diff) |
CHROMIUMOS: Add U-boot support for wear-leveling the MRC data
- Depends on related Coreboot changes
- There is a 64k region allocated so use it all
- Write each data blob in a 4K aligned container
- Find the last entry in the region to compare against coreboot copy
- Detect a full region and erase it all and start over at zero
BUG=chrome-os-partner:6962
TEST=manual
I started writing an autotest for this, but it was taking more time
than just doing a thorough manual test. I will finish the autotest
but for now I relied on manual testing and using /sys/firmware/log
to tell what happened in Coreboot/U-boot on each boot.
TEST CASE 1 - newly flashed image:
1) Install the new bios with flashrom and reboot
2) Check that no MRC data was found by Coreboot in firmware log:
"prepare_mrc_cache: invalid MRC data"
3) Check that U-boot wrote training data in firmware log:
"handle_mrc_cache: cached storage mismatch (-1/2895)"
"firmware_storage_spi: before adjustment"
"firmware_storage_spi: offset: 0x1ec000"
"firmware_storage_spi: length: 0xb58"
"firmware_storage_spi: after adjustment"
"firmware_storage_spi: offset: 0x1ec000"
"firmware_storage_spi: length: 0x1000"
"firmware_storage_spi: offset: 0x001ec000"
"firmware_storage_spi: adjusted offset: 0x001ec000"
4) Check the flash to see if it has data in first slot
> flashrom -r /tmp/bios.now
> hexdump -Cv -s $((0x1ec000)) -n $((0x10000)) /tmp/bios.now
TEST CASE 2 - ensure that it uses the saved training data:
1) Reboot
2) Check that Coreboot used the training data in firmware log:
"prepare_mrc_cache: at ff9ec009, entry 0 size b4f checksum 9c"
3) Check that U-boot did not have to update the data in firmware log:
"handle_mrc_cache: cached storage match"
4) Check the flash to see if it still only has data in first slot:
> flashrom -r /tmp/bios.now
> hexdump -Cv -s $((0x1ec000)) -n $((0x10000)) /tmp/bios.now
TEST CASE 3 - ensure that it fills the next slot with new data:
1) Corrupt the seed checksum in CMOS:
> io_write8 0x70 0x78
> io_write8 0x71 0x00
2) Reboot
3) Check that Coreboot did not use cached data in firmware log:
"prepare_mrc_cache: invalid seed checksum"
4) Check that U-boot wrote new training data at new offset in firmware log:
"handle_mrc_cache: cached storage mismatch (2895/2895)"
"firmware_storage_spi: before adjustment"
"firmware_storage_spi: offset: 0x1ed000"
"firmware_storage_spi: length: 0xb58"
"firmware_storage_spi: after adjustment"
"firmware_storage_spi: offset: 0x1ed000"
"firmware_storage_spi: length: 0x1000"
"firmware_storage_spi: offset: 0x001ed000"
"firmware_storage_spi: adjusted offset: 0x001ed000"
Signed-off-by: Duncan Laurie <dlaurie@chromium.org>
Change-Id: Ifffce29c5f9324f110c047a44a3f66d2e21cd6a4
Reviewed-on: https://gerrit.chromium.org/gerrit/13589
Reviewed-by: Stefan Reinauer <reinauer@chromium.org>
Reviewed-by: Ronald G. Minnich <rminnich@chromium.org>
-rw-r--r-- | board/chromebook-x86/coreboot/coreboot.c | 57 |
1 files changed, 47 insertions, 10 deletions
diff --git a/board/chromebook-x86/coreboot/coreboot.c b/board/chromebook-x86/coreboot/coreboot.c index ac4fae9531b..06c610c131b 100644 --- a/board/chromebook-x86/coreboot/coreboot.c +++ b/board/chromebook-x86/coreboot/coreboot.c @@ -42,6 +42,7 @@ #include <asm/msr.h> #include <asm/cache.h> #include <coreboot/timestamp.h> +#include <spi_flash.h> #ifdef CONFIG_HW_WATCHDOG #include <watchdog.h> #endif @@ -102,10 +103,15 @@ void setup_pcat_compatibility() { } +#define MRC_DATA_SIGNATURE (('M'<<0)|('R'<<8)|('C'<<16)|('D'<<24)) +#define MRC_DATA_ALIGN 0x1000 + struct mrc_data_container { + u32 mrc_signature; u32 mrc_data_size; /* Actual total size of this structure */ + u16 mrc_checksum; u8 mrc_data[0]; /* Variable size, platform/run time dependent */ -}; +} __packed; /** * handle_mrc_cache: @@ -121,8 +127,9 @@ static void handle_mrc_cache(void) struct fmap_entry fme; struct mrc_data_container *saved_entry; struct mrc_data_container *passed_entry; - u32 passed_size; - u32 saved_size; + struct mrc_data_container *entry, *next_entry; + u32 passed_size, entry_size, container_size; + u32 next_offset = 0; firmware_storage_t file; @@ -133,6 +140,7 @@ static void handle_mrc_cache(void) passed_entry = (struct mrc_data_container *)lib_sysinfo.mrc_cache; passed_size = passed_entry->mrc_data_size; + entry_size = sizeof(*passed_entry) + passed_size; if (passed_size > fme.length) { printf("%s: passed entry of %d won't fit into %d\n", __func__, passed_size, fme.length); @@ -160,14 +168,43 @@ static void handle_mrc_cache(void) return; } - saved_size = saved_entry->mrc_data_size; - if ((saved_size != passed_size) || - memcmp(passed_entry, saved_entry, passed_size)) { + /* Size is aligned to flash sector size. */ + container_size = passed_entry->mrc_data_size + sizeof(*passed_entry); + if (container_size & (MRC_DATA_ALIGN - 1UL)) { + container_size &= ~(MRC_DATA_ALIGN - 1UL); + container_size += MRC_DATA_ALIGN; + } + + /* Find the last entry in the region. */ + next_entry = saved_entry; + do { + entry = next_entry; + next_offset += container_size; + next_entry = (struct mrc_data_container *) + ((u8 *)saved_entry + next_offset); + } while (next_entry && next_entry->mrc_signature == MRC_DATA_SIGNATURE); + + /* Adjust entry offset back to the entry we want to examine. */ + if (entry->mrc_signature != MRC_DATA_SIGNATURE) + next_offset = 0; + + if ((entry->mrc_data_size != passed_size) || + memcmp(passed_entry, entry, entry_size)) { printf("%s: cached storage mismatch (%d/%d)\n", __func__, - saved_size, passed_size); - if (passed_size <= fme.length) { - if (file.write(&file, fme.offset, - passed_size, passed_entry)) + entry->mrc_data_size, passed_size); + + /* Erase entire region and start over at entry 0. */ + if ((next_offset + container_size) > fme.length) { + struct spi_flash *flash = file.context; + flash->erase(flash, fme.offset, fme.length); + next_offset = 0; + printf("%s: region full, erase and start over\n", + __func__); + } + + if ((next_offset + container_size) <= fme.length) { + if (file.write(&file, fme.offset + next_offset, + entry_size, passed_entry)) printf("%s: write failed!\n", __func__); } else { printf("%s: passed size too big (%d)\n", |