1 /* SPDX-License-Identifier: GPL-2.0-only */
4 #include <boot/coreboot_tables.h>
5 #include <console/console.h>
7 #include <pc80/mc146818rtc.h>
8 #include <security/vboot/vbnv.h>
9 #include <security/vboot/vbnv_layout.h>
11 static void clear_vbnv_battery_cutoff_flag(uint8_t *vbnv_copy
)
14 * Currently battery cutoff is done in payload stage, which does not
15 * update backup VBNV. And doing battery cutoff will invalidate CMOS.
16 * This means for every reboot after cutoff, read_vbnv_cmos will reload
17 * backup VBNV and try to cutoff again, causing endless reboot loop.
18 * So we should always clear battery cutoff flag from loaded backup.
20 if (vbnv_copy
[MISC_FLAGS_OFFSET
] & MISC_FLAGS_BATTERY_CUTOFF_MASK
) {
21 printk(BIOS_INFO
, "VBNV: Remove battery cut-off request.\n");
22 vbnv_copy
[MISC_FLAGS_OFFSET
] &= ~MISC_FLAGS_BATTERY_CUTOFF_MASK
;
23 regen_vbnv_crc(vbnv_copy
);
27 /* Return non-zero if backup was used. */
28 static int restore_from_backup(uint8_t *vbnv_copy
)
30 if (!CONFIG(VBOOT_VBNV_CMOS_BACKUP_TO_FLASH
))
33 printk(BIOS_INFO
, "VBNV: CMOS invalid, restoring from flash\n");
34 read_vbnv_flash(vbnv_copy
);
36 if (verify_vbnv(vbnv_copy
)) {
37 clear_vbnv_battery_cutoff_flag(vbnv_copy
);
38 save_vbnv_cmos(vbnv_copy
);
39 printk(BIOS_INFO
, "VBNV: Flash backup restored\n");
43 printk(BIOS_INFO
, "VBNV: Restore from flash failed\n");
48 void read_vbnv_cmos(uint8_t *vbnv_copy
)
52 for (i
= 0; i
< VBOOT_VBNV_BLOCK_SIZE
; i
++)
53 vbnv_copy
[i
] = cmos_read(CONFIG_VBOOT_VBNV_OFFSET
+ 14 + i
);
55 /* Verify contents before attempting a restore from backup storage. */
56 if (verify_vbnv(vbnv_copy
))
59 restore_from_backup(vbnv_copy
);
62 void save_vbnv_cmos(const uint8_t *vbnv_copy
)
66 for (i
= 0; i
< VBOOT_VBNV_BLOCK_SIZE
; i
++)
67 cmos_write(vbnv_copy
[i
], CONFIG_VBOOT_VBNV_OFFSET
+ 14 + i
);
70 void vbnv_init_cmos(uint8_t *vbnv_copy
)
72 /* If no CMOS failure just defer to the normal read path for checking
73 vbnv contents' integrity. */
74 if (!vbnv_cmos_failed())
77 /* In the case of CMOS failure force the backup. If backup wasn't used
78 force the vbnv CMOS to be reset. */
79 if (!restore_from_backup(vbnv_copy
)) {
80 vbnv_reset(vbnv_copy
);
81 /* This parallels the vboot_reference implementation. */
82 vbnv_copy
[HEADER_OFFSET
] = HEADER_SIGNATURE
|
83 HEADER_FIRMWARE_SETTINGS_RESET
|
84 HEADER_KERNEL_SETTINGS_RESET
;
85 regen_vbnv_crc(vbnv_copy
);
86 save_vbnv_cmos(vbnv_copy
);
90 void lb_table_add_vbnv_cmos(struct lb_header
*header
)
92 struct lb_range
*vbnv
;
94 vbnv
= (struct lb_range
*)lb_new_record(header
);
95 vbnv
->tag
= LB_TAG_VBNV
;
96 vbnv
->size
= sizeof(*vbnv
);
97 vbnv
->range_start
= CONFIG_VBOOT_VBNV_OFFSET
+ 14;
98 vbnv
->range_size
= VBOOT_VBNV_BLOCK_SIZE
;
101 #if CONFIG(VBOOT_VBNV_CMOS_BACKUP_TO_FLASH)
102 static void back_up_vbnv_cmos(void *unused
)
104 uint8_t vbnv_cmos
[VBOOT_VBNV_BLOCK_SIZE
];
106 /* Read current VBNV from CMOS. */
107 read_vbnv_cmos(vbnv_cmos
);
109 /* Save to flash, will only be saved if different. */
110 save_vbnv_flash(vbnv_cmos
);
112 BOOT_STATE_INIT_ENTRY(BS_POST_DEVICE
, BS_ON_EXIT
, back_up_vbnv_cmos
, NULL
);