blob: b7ef3e767fd10d721b3cebf2843e2d54ef0c0aa1 [file] [log] [blame]
/*
* This file is part of the coreboot project.
*
* Copyright (C) 2011 The ChromiumOS Authors. All rights reserved.
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; version 2 of the License.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*/
#include <bootstate.h>
#include <console/console.h>
#include <types.h>
#include <pc80/mc146818rtc.h>
#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;
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;
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");
}
}
}
void save_vbnv_cmos(const uint8_t *vbnv_copy)
{
int i;
for (i = 0; i < VBOOT_VBNV_BLOCK_SIZE; i++)
cmos_write(vbnv_copy[i], CONFIG_VBOOT_VBNV_OFFSET + 14 + i);
}
void init_vbnv_cmos(int rtc_fail)
{
uint8_t vbnv[VBOOT_VBNV_BLOCK_SIZE];
if (rtc_fail)
read_vbnv_cmos(vbnv);
cmos_init(rtc_fail);
if (rtc_fail)
save_vbnv_cmos(vbnv);
}
#if IS_ENABLED(CONFIG_VBOOT_VBNV_CMOS_BACKUP_TO_FLASH)
static void back_up_vbnv_cmos(void *unused)
{
uint8_t vbnv_cmos[VBOOT_VBNV_BLOCK_SIZE];
/* Read current VBNV from CMOS. */
read_vbnv_cmos(vbnv_cmos);
/* Save to flash, will only be saved if different. */
save_vbnv_flash(vbnv_cmos);
}
BOOT_STATE_INIT_ENTRY(BS_POST_DEVICE, BS_ON_EXIT, back_up_vbnv_cmos, NULL);
#endif