diff options
Diffstat (limited to 'src/vboot')
-rw-r--r-- | src/vboot/vbnv.c | 2 | ||||
-rw-r--r-- | src/vboot/vbnv.h | 5 | ||||
-rw-r--r-- | src/vboot/vbnv_cmos.c | 59 |
3 files changed, 52 insertions, 14 deletions
diff --git a/src/vboot/vbnv.c b/src/vboot/vbnv.c index 3eaa0ad4b2..79bdc8e5df 100644 --- a/src/vboot/vbnv.c +++ b/src/vboot/vbnv.c @@ -149,5 +149,7 @@ int vboot_wants_oprom(void) void vbnv_init(uint8_t *vbnv_copy) { + if (IS_ENABLED(CONFIG_VBOOT_VBNV_CMOS)) + vbnv_init_cmos(vbnv_copy); read_vbnv(vbnv_copy); } diff --git a/src/vboot/vbnv.h b/src/vboot/vbnv.h index 540f25c2ca..0288d0df4d 100644 --- a/src/vboot/vbnv.h +++ b/src/vboot/vbnv.h @@ -32,6 +32,11 @@ void vbnv_init(uint8_t *vbnv_copy); void vbnv_reset(uint8_t *vbnv_copy); /* CMOS backend */ +/* Initialize the vbnv cmos backing store. The vbnv_copy pointer is used for + optional temporary storage in the init function. */ +void vbnv_init_cmos(uint8_t *vbnv_copy); +/* Return non-zero if cmos power was lost. */ +int vbnv_cmos_failed(void); void read_vbnv_cmos(uint8_t *vbnv_copy); void save_vbnv_cmos(const uint8_t *vbnv_copy); diff --git a/src/vboot/vbnv_cmos.c b/src/vboot/vbnv_cmos.c index 8bdcb31f9c..a311fddbb1 100644 --- a/src/vboot/vbnv_cmos.c +++ b/src/vboot/vbnv_cmos.c @@ -36,6 +36,27 @@ static void clear_vbnv_battery_cutoff_flag(uint8_t *vbnv_copy) } } +/* Return non-zero if backup was used. */ +static int restore_from_backup(uint8_t *vbnv_copy) +{ + if (!IS_ENABLED(CONFIG_VBOOT_VBNV_CMOS_BACKUP_TO_FLASH)) + return 0; + + printk(BIOS_INFO, "VBNV: CMOS invalid, restoring from flash\n"); + read_vbnv_flash(vbnv_copy); + + if (verify_vbnv(vbnv_copy)) { + clear_vbnv_battery_cutoff_flag(vbnv_copy); + save_vbnv_cmos(vbnv_copy); + printk(BIOS_INFO, "VBNV: Flash backup restored\n"); + return 1; + } + + printk(BIOS_INFO, "VBNV: Restore from flash failed\n"); + + return 0; +} + void read_vbnv_cmos(uint8_t *vbnv_copy) { int i; @@ -43,21 +64,11 @@ void read_vbnv_cmos(uint8_t *vbnv_copy) for (i = 0; i < VBOOT_VBNV_BLOCK_SIZE; i++) vbnv_copy[i] = cmos_read(CONFIG_VBOOT_VBNV_OFFSET + 14 + i); - if (IS_ENABLED(CONFIG_VBOOT_VBNV_CMOS_BACKUP_TO_FLASH)) { - if (verify_vbnv(vbnv_copy)) - return; + /* Verify contents before attempting a restore from backup storage. */ + if (verify_vbnv(vbnv_copy)) + return; - printk(BIOS_INFO, "VBNV: CMOS invalid, restoring from flash\n"); - read_vbnv_flash(vbnv_copy); - - if (verify_vbnv(vbnv_copy)) { - clear_vbnv_battery_cutoff_flag(vbnv_copy); - save_vbnv_cmos(vbnv_copy); - printk(BIOS_INFO, "VBNV: Flash backup restored\n"); - } else { - printk(BIOS_INFO, "VBNV: Restore from flash failed\n"); - } - } + restore_from_backup(vbnv_copy); } void save_vbnv_cmos(const uint8_t *vbnv_copy) @@ -68,6 +79,26 @@ void save_vbnv_cmos(const uint8_t *vbnv_copy) cmos_write(vbnv_copy[i], CONFIG_VBOOT_VBNV_OFFSET + 14 + i); } +void vbnv_init_cmos(uint8_t *vbnv_copy) +{ + /* If no cmos failure just defer to the normal read path for checking + vbnv contents' integrity. */ + if (!vbnv_cmos_failed()) + return; + + /* In the case of cmos failure force the backup. If backup wasn't used + force the vbnv cmos to be reset. */ + if (!restore_from_backup(vbnv_copy)) { + vbnv_reset(vbnv_copy); + /* This parallels the vboot_reference implementation. */ + vbnv_copy[HEADER_OFFSET] = HEADER_SIGNATURE | + HEADER_FIRMWARE_SETTINGS_RESET | + HEADER_KERNEL_SETTINGS_RESET; + regen_vbnv_crc(vbnv_copy); + save_vbnv_cmos(vbnv_copy); + } +} + #if IS_ENABLED(CONFIG_VBOOT_VBNV_CMOS_BACKUP_TO_FLASH) static void back_up_vbnv_cmos(void *unused) { |