aboutsummaryrefslogtreecommitdiff
path: root/src/vboot
diff options
context:
space:
mode:
Diffstat (limited to 'src/vboot')
-rw-r--r--src/vboot/vbnv.c2
-rw-r--r--src/vboot/vbnv.h5
-rw-r--r--src/vboot/vbnv_cmos.c59
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)
{