blob: fe5d6ce9229c3b4c08dbcc3cae11b496dfb261a8 [file] [log] [blame]
Stefan Reinauer9aea04a2012-03-30 12:01:06 -07001/*
2 * This file is part of the coreboot project.
3 *
4 * Copyright (C) 2011 The ChromiumOS Authors. All rights reserved.
5 *
6 * This program is free software; you can redistribute it and/or modify
7 * it under the terms of the GNU General Public License as published by
8 * the Free Software Foundation; version 2 of the License.
9 *
10 * This program is distributed in the hope that it will be useful,
11 * but WITHOUT ANY WARRANTY; without even the implied warranty of
12 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
13 * GNU General Public License for more details.
Stefan Reinauer9aea04a2012-03-30 12:01:06 -070014 */
15
Duncan Lauriefe970132016-01-26 16:30:36 -080016#include <bootstate.h>
17#include <console/console.h>
Stefan Reinauer9aea04a2012-03-30 12:01:06 -070018#include <types.h>
Stefan Reinauer9aea04a2012-03-30 12:01:06 -070019#include <pc80/mc146818rtc.h>
Philipp Deppenwiesefea24292017-10-17 17:02:29 +020020#include <security/vboot/vbnv.h>
21#include <security/vboot/vbnv_layout.h>
Stefan Reinauer9aea04a2012-03-30 12:01:06 -070022
Hung-Te Linfe2fc832016-12-29 20:59:37 +080023static void clear_vbnv_battery_cutoff_flag(uint8_t *vbnv_copy)
24{
25 /*
26 * Currently battery cutoff is done in payload stage, which does not
27 * update backup VBNV. And doing battery cutoff will invalidate CMOS.
28 * This means for every reboot after cutoff, read_vbnv_cmos will reload
29 * backup VBNV and try to cutoff again, causing endless reboot loop.
30 * So we should always clear battery cutoff flag from loaded backup.
31 */
32 if (vbnv_copy[MISC_FLAGS_OFFSET] & MISC_FLAGS_BATTERY_CUTOFF_MASK) {
33 printk(BIOS_INFO, "VBNV: Remove battery cut-off request.\n");
34 vbnv_copy[MISC_FLAGS_OFFSET] &= ~MISC_FLAGS_BATTERY_CUTOFF_MASK;
35 regen_vbnv_crc(vbnv_copy);
36 }
37}
38
Aaron Durbin0990fbf2017-09-15 15:23:04 -060039/* Return non-zero if backup was used. */
40static int restore_from_backup(uint8_t *vbnv_copy)
41{
Julius Wernercd49cce2019-03-05 16:53:33 -080042 if (!CONFIG(VBOOT_VBNV_CMOS_BACKUP_TO_FLASH))
Aaron Durbin0990fbf2017-09-15 15:23:04 -060043 return 0;
44
45 printk(BIOS_INFO, "VBNV: CMOS invalid, restoring from flash\n");
46 read_vbnv_flash(vbnv_copy);
47
48 if (verify_vbnv(vbnv_copy)) {
49 clear_vbnv_battery_cutoff_flag(vbnv_copy);
50 save_vbnv_cmos(vbnv_copy);
51 printk(BIOS_INFO, "VBNV: Flash backup restored\n");
52 return 1;
53 }
54
55 printk(BIOS_INFO, "VBNV: Restore from flash failed\n");
56
57 return 0;
58}
59
Duncan Laurie88b28ad2016-01-25 17:13:27 -080060void read_vbnv_cmos(uint8_t *vbnv_copy)
Stefan Reinauer9aea04a2012-03-30 12:01:06 -070061{
62 int i;
63
Furquan Shaikh2a12e2e2016-07-25 11:48:03 -070064 for (i = 0; i < VBOOT_VBNV_BLOCK_SIZE; i++)
65 vbnv_copy[i] = cmos_read(CONFIG_VBOOT_VBNV_OFFSET + 14 + i);
Duncan Lauriefe970132016-01-26 16:30:36 -080066
Aaron Durbin0990fbf2017-09-15 15:23:04 -060067 /* Verify contents before attempting a restore from backup storage. */
68 if (verify_vbnv(vbnv_copy))
69 return;
Duncan Lauriefe970132016-01-26 16:30:36 -080070
Aaron Durbin0990fbf2017-09-15 15:23:04 -060071 restore_from_backup(vbnv_copy);
Aaron Durbinfd795622013-03-01 17:12:26 -060072}
73
Duncan Laurie88b28ad2016-01-25 17:13:27 -080074void save_vbnv_cmos(const uint8_t *vbnv_copy)
Aaron Durbinfd795622013-03-01 17:12:26 -060075{
76 int i;
77
Furquan Shaikh2a12e2e2016-07-25 11:48:03 -070078 for (i = 0; i < VBOOT_VBNV_BLOCK_SIZE; i++)
79 cmos_write(vbnv_copy[i], CONFIG_VBOOT_VBNV_OFFSET + 14 + i);
Aaron Durbinfd795622013-03-01 17:12:26 -060080}
Duncan Lauriefe970132016-01-26 16:30:36 -080081
Aaron Durbin0990fbf2017-09-15 15:23:04 -060082void vbnv_init_cmos(uint8_t *vbnv_copy)
83{
Elyes HAOUAS2119d0b2020-02-16 10:01:33 +010084 /* If no CMOS failure just defer to the normal read path for checking
Aaron Durbin0990fbf2017-09-15 15:23:04 -060085 vbnv contents' integrity. */
86 if (!vbnv_cmos_failed())
87 return;
88
Elyes HAOUAS2119d0b2020-02-16 10:01:33 +010089 /* In the case of CMOS failure force the backup. If backup wasn't used
90 force the vbnv CMOS to be reset. */
Aaron Durbin0990fbf2017-09-15 15:23:04 -060091 if (!restore_from_backup(vbnv_copy)) {
92 vbnv_reset(vbnv_copy);
93 /* This parallels the vboot_reference implementation. */
94 vbnv_copy[HEADER_OFFSET] = HEADER_SIGNATURE |
95 HEADER_FIRMWARE_SETTINGS_RESET |
96 HEADER_KERNEL_SETTINGS_RESET;
97 regen_vbnv_crc(vbnv_copy);
98 save_vbnv_cmos(vbnv_copy);
99 }
100}
101
Julius Wernercd49cce2019-03-05 16:53:33 -0800102#if CONFIG(VBOOT_VBNV_CMOS_BACKUP_TO_FLASH)
Patrick Georgi6b881b22016-02-09 14:01:08 +0100103static void back_up_vbnv_cmos(void *unused)
Duncan Lauriefe970132016-01-26 16:30:36 -0800104{
Furquan Shaikh2a12e2e2016-07-25 11:48:03 -0700105 uint8_t vbnv_cmos[VBOOT_VBNV_BLOCK_SIZE];
Duncan Lauriefe970132016-01-26 16:30:36 -0800106
107 /* Read current VBNV from CMOS. */
108 read_vbnv_cmos(vbnv_cmos);
109
110 /* Save to flash, will only be saved if different. */
111 save_vbnv_flash(vbnv_cmos);
112}
Patrick Georgi6b881b22016-02-09 14:01:08 +0100113BOOT_STATE_INIT_ENTRY(BS_POST_DEVICE, BS_ON_EXIT, back_up_vbnv_cmos, NULL);
Duncan Lauriefe970132016-01-26 16:30:36 -0800114#endif