diff options
-rw-r--r-- | src/vboot/vbnv.c | 6 | ||||
-rw-r--r-- | src/vboot/vbnv.h | 1 | ||||
-rw-r--r-- | src/vboot/vbnv_cmos.c | 17 | ||||
-rw-r--r-- | src/vboot/vbnv_layout.h | 3 |
4 files changed, 27 insertions, 0 deletions
diff --git a/src/vboot/vbnv.c b/src/vboot/vbnv.c index ce6492855d..6537bf04dc 100644 --- a/src/vboot/vbnv.c +++ b/src/vboot/vbnv.c @@ -79,6 +79,12 @@ int verify_vbnv(uint8_t *vbnv_copy) (crc8_vbnv(vbnv_copy, CRC_OFFSET) == vbnv_copy[CRC_OFFSET]); } +/* Re-generate VBNV checksum. */ +void regen_vbnv_crc(uint8_t *vbnv_copy) +{ + vbnv_copy[CRC_OFFSET] = crc8_vbnv(vbnv_copy, CRC_OFFSET); +} + /* * Read VBNV data from configured storage backend. * If VBNV verification fails, reset the vbnv copy. diff --git a/src/vboot/vbnv.h b/src/vboot/vbnv.h index 78ca8f66f3..30da6a50c5 100644 --- a/src/vboot/vbnv.h +++ b/src/vboot/vbnv.h @@ -22,6 +22,7 @@ void read_vbnv(uint8_t *vbnv_copy); void save_vbnv(const uint8_t *vbnv_copy); int verify_vbnv(uint8_t *vbnv_copy); +void regen_vbnv_crc(uint8_t *vbnv_copy); int get_recovery_mode_from_vbnv(void); void set_recovery_mode_into_vbnv(int recovery_reason); int vboot_wants_oprom(void); diff --git a/src/vboot/vbnv_cmos.c b/src/vboot/vbnv_cmos.c index 5eda8e6e50..b7ef3e767f 100644 --- a/src/vboot/vbnv_cmos.c +++ b/src/vboot/vbnv_cmos.c @@ -20,6 +20,22 @@ #include <vboot/vbnv.h> #include <vboot/vbnv_layout.h> +static void clear_vbnv_battery_cutoff_flag(uint8_t *vbnv_copy) +{ + /* + * Currently battery cutoff is done in payload stage, which does not + * update backup VBNV. And doing battery cutoff will invalidate CMOS. + * This means for every reboot after cutoff, read_vbnv_cmos will reload + * backup VBNV and try to cutoff again, causing endless reboot loop. + * So we should always clear battery cutoff flag from loaded backup. + */ + if (vbnv_copy[MISC_FLAGS_OFFSET] & MISC_FLAGS_BATTERY_CUTOFF_MASK) { + printk(BIOS_INFO, "VBNV: Remove battery cut-off request.\n"); + vbnv_copy[MISC_FLAGS_OFFSET] &= ~MISC_FLAGS_BATTERY_CUTOFF_MASK; + regen_vbnv_crc(vbnv_copy); + } +} + void read_vbnv_cmos(uint8_t *vbnv_copy) { int i; @@ -35,6 +51,7 @@ void read_vbnv_cmos(uint8_t *vbnv_copy) 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 { diff --git a/src/vboot/vbnv_layout.h b/src/vboot/vbnv_layout.h index 59acd0c354..1dc01c909a 100644 --- a/src/vboot/vbnv_layout.h +++ b/src/vboot/vbnv_layout.h @@ -41,6 +41,9 @@ #define DEV_BOOT_USB_MASK 0x01 #define DEV_BOOT_SIGNED_ONLY_MASK 0x02 +#define MISC_FLAGS_OFFSET 8 +#define MISC_FLAGS_BATTERY_CUTOFF_MASK 0x08 + #define KERNEL_FIELD_OFFSET 11 #define CRC_OFFSET 15 |