vbnv flash: use proper SPI flash offset for NVRAM

The current vbnv flash code mistakenly uses the offset into the NVRAM
area as the absolute offset into the SPI NOR. This causes overwrites
RO section of the flash (when it is not protected) and causes failures
to retrieve the NVRAM contents by the user space apps.

This patch makes sure that the correct offset is used when accessing
NVRAM area in the SPI flash.

BRANCH=storm
BUG=chrome-os-partner:35316
TEST=run the update code on storm.
 - no more RO section corruption observed
 - running 'crossystem recovery_request=1' at Linux prompt causes the
   next boot happen in recovery mode

Change-Id: Iba96cd2e0e5e01c990f8c1de8d2a2233cd9e9bc9
Signed-off-by: Stefan Reinauer <reinauer@chromium.org>
Original-Commit-Id: 9fd15ff4b7aa77536723edbb94fa81f0ae767aed
Original-Change-Id: I86fe4b9a35f7c16b72abf49cfbfcd42cc87937e3
Original-Signed-off-by: Vadim Bendebury <vbendeb@chromium.org>
Original-Reviewed-on: https://chromium-review.googlesource.com/240143
Original-Reviewed-by: Daisuke Nojiri <dnojiri@chromium.org>
Reviewed-on: http://review.coreboot.org/9561
Tested-by: build bot (Jenkins)
Reviewed-by: Patrick Georgi <pgeorgi@google.com>
This commit is contained in:
Vadim Bendebury 2015-01-10 23:11:43 -08:00 committed by Patrick Georgi
parent 6fd3501cbd
commit 9e381a140f
1 changed files with 24 additions and 21 deletions

View File

@ -37,9 +37,12 @@
/* FMAP descriptor of the NVRAM area */ /* FMAP descriptor of the NVRAM area */
static struct vboot_region nvram_region; static struct vboot_region nvram_region;
/* offset of the current nvdata in nvram */ /* offset of the current nvdata in SPI flash */
static int blob_offset = -1; static int blob_offset = -1;
/* Offset of the topmost nvdata blob in SPI flash */
static int top_offset;
/* cache of the current nvdata */ /* cache of the current nvdata */
static uint8_t cache[BLOB_SIZE]; static uint8_t cache[BLOB_SIZE];
@ -83,13 +86,16 @@ static int init_vbnv(void)
for (i = 0; i < BLOB_SIZE; i++) for (i = 0; i < BLOB_SIZE; i++)
empty_blob[i] = erase_value(); empty_blob[i] = erase_value();
offset = nvram_region.offset_addr;
top_offset = nvram_region.offset_addr + nvram_region.size - BLOB_SIZE;
/* /*
* after the loop, offset is supposed to point the blob right before the * after the loop, offset is supposed to point the blob right before
* first empty blob, the last blob in the nvram if there is no empty * the first empty blob, the last blob in the nvram if there is no
* blob, or 0 if the nvram has never been used. * empty blob, or the base of the region if the nvram has never been
* used.
*/ */
for (i = 0, offset = 0; i <= nvram_region.size - BLOB_SIZE; for (i = offset; i <= top_offset; i += BLOB_SIZE) {
i += BLOB_SIZE) {
if (vboot_get_region(i, BLOB_SIZE, buf) == NULL) { if (vboot_get_region(i, BLOB_SIZE, buf) == NULL) {
printk(BIOS_ERR, "failed to read nvdata\n"); printk(BIOS_ERR, "failed to read nvdata\n");
return 1; return 1;
@ -147,7 +153,7 @@ void read_vbnv(uint8_t *vbnv_copy)
void save_vbnv(const uint8_t *vbnv_copy) void save_vbnv(const uint8_t *vbnv_copy)
{ {
int new_offset = blob_offset; int new_offset;
int i; int i;
if (!is_initialized()) if (!is_initialized())
@ -158,31 +164,28 @@ void save_vbnv(const uint8_t *vbnv_copy)
if (!memcmp(vbnv_copy, cache, BLOB_SIZE)) if (!memcmp(vbnv_copy, cache, BLOB_SIZE))
return; return;
new_offset = blob_offset;
/* See if we can overwrite the current blob with the new one */ /* See if we can overwrite the current blob with the new one */
for (i = 0; i < BLOB_SIZE; i++) { for (i = 0; i < BLOB_SIZE; i++) {
if (!can_overwrite(cache[i], vbnv_copy[i])) { if (!can_overwrite(cache[i], vbnv_copy[i])) {
/* unable to overwrite. need to use the next blob */ /* unable to overwrite. need to use the next blob */
new_offset += BLOB_SIZE; new_offset += BLOB_SIZE;
if (new_offset > nvram_region.size - BLOB_SIZE) { if (new_offset > top_offset) {
if (erase_nvram()) if (erase_nvram())
return; /* error */ return; /* error */
new_offset = 0; new_offset = nvram_region.offset_addr;
} }
break; break;
} }
} }
if (vbnv_flash_probe()) if (!vbnv_flash_probe() &&
return; /* error */ !spi_flash->write(spi_flash, new_offset, BLOB_SIZE, vbnv_copy)) {
/* write was successful. safely move pointer forward */
if (spi_flash->write(spi_flash, new_offset, BLOB_SIZE, vbnv_copy)) { blob_offset = new_offset;
printk(BIOS_ERR, "failed to write nvdata\n"); memcpy(cache, vbnv_copy, BLOB_SIZE);
return; /* error */ } else {
printk(BIOS_ERR, "failed to save nvdata\n");
} }
/* write was successful. safely move pointer forward */
blob_offset = new_offset;
memcpy(cache, vbnv_copy, BLOB_SIZE);
return;
} }