summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--src/vboot/vbnv.c6
-rw-r--r--src/vboot/vbnv.h1
-rw-r--r--src/vboot/vbnv_cmos.c17
-rw-r--r--src/vboot/vbnv_layout.h3
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