vboot: Separate vboot from chromeos

VBOOT_VERIFY_FIRMWARE should be independent of CHROMEOS. This allows use
of verified boot library without having to stick to CHROMEOS.

BUG=chrome-os-partner:55639

Change-Id: Ia2c328712caedd230ab295b8a613e3c1ed1532d9
Signed-off-by: Furquan Shaikh <furquan@google.com>
Reviewed-on: https://review.coreboot.org/15867
Tested-by: build bot (Jenkins)
Reviewed-by: Duncan Laurie <dlaurie@chromium.org>
This commit is contained in:
Furquan Shaikh
2016-07-25 11:48:03 -07:00
parent af8ef2a810
commit 2a12e2e8da
95 changed files with 310 additions and 299 deletions

View File

@ -13,4 +13,3 @@
##
source src/vendorcode/google/chromeos/Kconfig

View File

@ -28,7 +28,7 @@ config CHROMEOS
select BOOTMODE_STRAPS
select ELOG if SPI_FLASH
select COLLECT_TIMESTAMPS
select VBOOT_VERIFY_FIRMWARE
select VBOOT
select MULTIPLE_CBFS_INSTANCES
help
Enable ChromeOS specific features like the GPIO sub table in
@ -37,39 +37,6 @@ config CHROMEOS
if CHROMEOS
config VBNV_OFFSET
hex
default 0x26
depends on PC80_SYSTEM
help
CMOS offset for VbNv data. This value must match cmos.layout
in the mainboard directory, minus 14 bytes for the RTC.
config CHROMEOS_VBNV_CMOS
bool "Vboot non-volatile storage in CMOS."
default n
help
VBNV is stored in CMOS
config CHROMEOS_VBNV_CMOS_BACKUP_TO_FLASH
bool "Back up Vboot non-volatile storage from CMOS to flash."
default n
depends on CHROMEOS_VBNV_CMOS
help
Vboot non-volatile storage data will be backed up from CMOS to flash
and restored from flash if the CMOS is invalid due to power loss.
config CHROMEOS_VBNV_EC
bool "Vboot non-volatile storage in EC."
default n
help
VBNV is stored in EC
config CHROMEOS_VBNV_FLASH
def_bool n
help
VBNV is stored in flash storage
config CHROMEOS_RAMOOPS
bool "Reserve space for Chrome OS ramoops"
default y
@ -97,7 +64,7 @@ config CHROMEOS_RAMOOPS_RAM_SIZE
config EC_SOFTWARE_SYNC
bool "Enable EC software sync"
default n
depends on VBOOT_VERIFY_FIRMWARE
depends on VBOOT
help
EC software sync is a mechanism where the AP helps the EC verify its
firmware similar to how vboot verifies the main system firmware. This
@ -111,33 +78,13 @@ config VBOOT_EC_SLOW_UPDATE
Whether the EC (or PD) is slow to update and needs to display a
screen that informs the user the update is happening.
config VBOOT_OPROM_MATTERS
bool "Video option ROM matters (= can skip display init)"
default n
depends on VBOOT_VERIFY_FIRMWARE
help
Set this option to indicate to vboot that this platform will skip its
display initialization on a normal (non-recovery, non-developer) boot.
Vboot calls this "oprom matters" because on x86 devices this
traditionally meant that the video option ROM will not be loaded, but
it works functionally the same for other platforms that can skip their
native display initialization code instead.
config VIRTUAL_DEV_SWITCH
bool "Virtual developer switch support"
default n
depends on VBOOT_VERIFY_FIRMWARE
depends on VBOOT
help
Whether this platform has a virtual developer switch.
config VBOOT_VERIFY_FIRMWARE
bool "Verify firmware with vboot."
default n
depends on HAVE_HARD_RESET
help
Enabling VBOOT_VERIFY_FIRMWARE will use vboot to verify the components
of the firmware (stages, payload, etc).
config NO_TPM_RESUME
bool
default n
@ -172,8 +119,6 @@ config HAVE_REGULATORY_DOMAIN
help
This option is needed to add ACPI regulatory domain methods
source src/vendorcode/google/chromeos/vboot2/Kconfig
menu "GBB configuration"
config GBB_HWID

View File

@ -18,31 +18,6 @@ verstage-y += chromeos.c
romstage-y += chromeos.c
ramstage-y += chromeos.c
bootblock-y += vbnv.c
verstage-y += vbnv.c
romstage-y += vbnv.c
ramstage-y += vbnv.c
bootblock-$(CONFIG_CHROMEOS_VBNV_CMOS) += vbnv_cmos.c
verstage-$(CONFIG_CHROMEOS_VBNV_CMOS) += vbnv_cmos.c
romstage-$(CONFIG_CHROMEOS_VBNV_CMOS) += vbnv_cmos.c
ramstage-$(CONFIG_CHROMEOS_VBNV_CMOS) += vbnv_cmos.c
bootblock-$(CONFIG_CHROMEOS_VBNV_CMOS_BACKUP_TO_FLASH) += vbnv_flash.c
verstage-$(CONFIG_CHROMEOS_VBNV_CMOS_BACKUP_TO_FLASH) += vbnv_flash.c
romstage-$(CONFIG_CHROMEOS_VBNV_CMOS_BACKUP_TO_FLASH) += vbnv_flash.c
ramstage-$(CONFIG_CHROMEOS_VBNV_CMOS_BACKUP_TO_FLASH) += vbnv_flash.c
bootblock-$(CONFIG_CHROMEOS_VBNV_EC) += vbnv_ec.c
verstage-$(CONFIG_CHROMEOS_VBNV_EC) += vbnv_ec.c
romstage-$(CONFIG_CHROMEOS_VBNV_EC) += vbnv_ec.c
ramstage-$(CONFIG_CHROMEOS_VBNV_EC) += vbnv_ec.c
bootblock-$(CONFIG_CHROMEOS_VBNV_FLASH) += vbnv_flash.c
verstage-$(CONFIG_CHROMEOS_VBNV_FLASH) += vbnv_flash.c
romstage-$(CONFIG_CHROMEOS_VBNV_FLASH) += vbnv_flash.c
ramstage-$(CONFIG_CHROMEOS_VBNV_FLASH) += vbnv_flash.c
ramstage-$(CONFIG_ELOG) += elog.c
ramstage-$(CONFIG_HAVE_ACPI_TABLES) += gnvs.c
ramstage-$(CONFIG_CHROMEOS_RAMOOPS) += ramoops.c
@ -60,8 +35,6 @@ else
CFLAGS_common += -DMOCK_TPM=0
endif
subdirs-$(CONFIG_VBOOT_VERIFY_FIRMWARE) += vboot2
CONFIG_GBB_HWID := $(call strip_quotes,$(CONFIG_GBB_HWID))
CONFIG_GBB_BMPFV_FILE := $(call strip_quotes,$(CONFIG_GBB_BMPFV_FILE))
CONFIG_VBOOT_KEYBLOCK := $(call strip_quotes,$(CONFIG_VBOOT_KEYBLOCK))

View File

@ -13,7 +13,7 @@
* GNU General Public License for more details.
*/
#include <vendorcode/google/chromeos/vbnv_layout.h>
#include <vboot/vbnv_layout.h>
Device (CRHW)
{
@ -71,8 +71,8 @@ Device (CRHW)
Name(VNBV, Package() {
// See src/vendorcode/google/chromeos/Kconfig
// for the definition of these:
CONFIG_VBNV_OFFSET,
VBNV_BLOCK_SIZE
CONFIG_VBOOT_VBNV_OFFSET,
VBOOT_VBNV_BLOCK_SIZE
})
Return(VNBV)
}

View File

@ -20,9 +20,8 @@
#include <stdint.h>
#include <bootmode.h>
#include <rules.h>
#include "vbnv.h"
#include "vboot_common.h"
#include "vboot2/misc.h"
#include <vboot/misc.h>
#include <vboot/vboot_common.h>
void save_chromeos_gpios(void);

View File

@ -17,8 +17,9 @@
#include <console/console.h>
#include <elog.h>
#include <vendorcode/google/chromeos/chromeos.h>
#if CONFIG_VBOOT_VERIFY_FIRMWARE
#include "vboot_common.h"
#if CONFIG_VBOOT
#include <vboot/vbnv.h>
#include <vboot/vboot_common.h>
#include <vboot_struct.h>
#endif
@ -29,7 +30,7 @@ void elog_add_boot_reason(void)
printk(BIOS_DEBUG, "%s: Logged dev mode boot\n", __func__);
} else if (recovery_mode_enabled()) {
u8 reason = 0;
#if CONFIG_VBOOT_VERIFY_FIRMWARE
#if CONFIG_VBOOT
struct vboot_handoff *vbho = cbmem_find(CBMEM_ID_VBOOT_HANDOFF);
reason = get_recovery_mode_from_vbnv();

View File

@ -23,8 +23,9 @@
#include "chromeos.h"
#include "gnvs.h"
#if CONFIG_VBOOT_VERIFY_FIRMWARE
#include "vboot_common.h"
#if CONFIG_VBOOT
#include <vboot/vbnv.h>
#include <vboot/vboot_common.h>
#include <vboot_struct.h>
#endif
@ -38,7 +39,7 @@ void chromeos_init_vboot(chromeos_acpi_t *chromeos)
/* Copy saved ME hash into NVS */
memcpy(vboot_data->mehh, me_hash_saved, sizeof(vboot_data->mehh));
#if CONFIG_VBOOT_VERIFY_FIRMWARE
#if CONFIG_VBOOT
/* Save the vdat from the vboot handoff structure. Downstream software
* consumes the data located in the ACPI table. Ensure it reflects
* the shared data from VbInit() and VbSelectFirmware(). */
@ -57,7 +58,7 @@ void chromeos_init_vboot(chromeos_acpi_t *chromeos)
elog_add_event(ELOG_TYPE_CROS_DEVELOPER_MODE);
if (recovery_mode_enabled()) {
int reason = get_recovery_mode_from_vbnv();
#if CONFIG_VBOOT_VERIFY_FIRMWARE
#if CONFIG_VBOOT
if (vboot_handoff && !reason) {
VbSharedDataHeader *sd = (VbSharedDataHeader *)
vboot_handoff->shared_data;

View File

@ -16,15 +16,6 @@
#ifndef __CHROMEOS_SYMBOLS_H
#define __CHROMEOS_SYMBOLS_H
extern u8 _vboot2_work[];
extern u8 _evboot2_work[];
#define _vboot2_work_size (_evboot2_work - _vboot2_work)
/* Careful: _e<stage> and _<stage>_size only defined for the current stage! */
extern u8 _verstage[];
extern u8 _everstage[];
#define _verstage_size (_everstage - _verstage)
extern u8 _watchdog_tombstone[];
extern u8 _ewatchdog_tombstone[];
#define _watchdog_tombstone_size (_ewatchdog_tombstone - _watchdog_tombstone)

View File

@ -1,143 +0,0 @@
/*
* This file is part of the coreboot project.
*
* Copyright (C) 2016 Google Inc.
*
* 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 <arch/early_variables.h>
#include <string.h>
#include <types.h>
#include "chromeos.h"
#include "vbnv.h"
#include "vbnv_layout.h"
static int vbnv_initialized CAR_GLOBAL;
static uint8_t vbnv[VBNV_BLOCK_SIZE] CAR_GLOBAL;
/* Wrappers for accessing the variables marked as CAR_GLOBAL. */
static inline int is_vbnv_initialized(void)
{
return car_get_var(vbnv_initialized);
}
static inline uint8_t *vbnv_data_addr(int index)
{
uint8_t *vbnv_arr = car_get_var_ptr(vbnv);
return &vbnv_arr[index];
}
static inline uint8_t vbnv_data(int index)
{
return *vbnv_data_addr(index);
}
/* Return CRC-8 of the data, using x^8 + x^2 + x + 1 polynomial. */
static uint8_t crc8_vbnv(const uint8_t *data, int len)
{
unsigned crc = 0;
int i, j;
for (j = len; j; j--, data++) {
crc ^= (*data << 8);
for (i = 8; i; i--) {
if (crc & 0x8000)
crc ^= (0x1070 << 3);
crc <<= 1;
}
}
return (uint8_t) (crc >> 8);
}
static void reset_vbnv(uint8_t *vbnv_copy)
{
memset(vbnv_copy, 0, VBNV_BLOCK_SIZE);
}
/* Read VBNV data into cache. */
static void vbnv_setup(void)
{
if (!is_vbnv_initialized()) {
read_vbnv(vbnv_data_addr(0));
car_set_var(vbnv_initialized, 1);
}
}
/* Verify VBNV header and checksum. */
int verify_vbnv(uint8_t *vbnv_copy)
{
return (HEADER_SIGNATURE == (vbnv_copy[HEADER_OFFSET] & HEADER_MASK)) &&
(crc8_vbnv(vbnv_copy, CRC_OFFSET) == vbnv_copy[CRC_OFFSET]);
}
/*
* Read VBNV data from configured storage backend.
* If VBNV verification fails, reset the vbnv copy.
*/
void read_vbnv(uint8_t *vbnv_copy)
{
if (IS_ENABLED(CONFIG_CHROMEOS_VBNV_CMOS))
read_vbnv_cmos(vbnv_copy);
else if (IS_ENABLED(CONFIG_CHROMEOS_VBNV_EC))
read_vbnv_ec(vbnv_copy);
else if (IS_ENABLED(CONFIG_CHROMEOS_VBNV_FLASH))
read_vbnv_flash(vbnv_copy);
/* Check data for consistency */
if (!verify_vbnv(vbnv_copy))
reset_vbnv(vbnv_copy);
}
/*
* Write VBNV data to configured storage backend.
* This assumes that the caller has updated the CRC already.
*/
void save_vbnv(const uint8_t *vbnv_copy)
{
if (IS_ENABLED(CONFIG_CHROMEOS_VBNV_CMOS))
save_vbnv_cmos(vbnv_copy);
else if (IS_ENABLED(CONFIG_CHROMEOS_VBNV_EC))
save_vbnv_ec(vbnv_copy);
else if (IS_ENABLED(CONFIG_CHROMEOS_VBNV_FLASH))
save_vbnv_flash(vbnv_copy);
/* Clear initialized flag to force cached data to be updated */
car_set_var(vbnv_initialized, 0);
}
/* Save a recovery reason into VBNV. */
void set_recovery_mode_into_vbnv(int recovery_reason)
{
uint8_t vbnv_copy[VBNV_BLOCK_SIZE];
read_vbnv(vbnv_copy);
vbnv_copy[RECOVERY_OFFSET] = recovery_reason;
vbnv_copy[CRC_OFFSET] = crc8_vbnv(vbnv_copy, CRC_OFFSET);
save_vbnv(vbnv_copy);
}
/* Read the recovery reason from VBNV. */
int get_recovery_mode_from_vbnv(void)
{
vbnv_setup();
return vbnv_data(RECOVERY_OFFSET);
}
/* Read the BOOT_OPROM_NEEDED flag from VBNV. */
int vboot_wants_oprom(void)
{
vbnv_setup();
return (vbnv_data(BOOT_OFFSET) & BOOT_OPROM_NEEDED) ? 1 : 0;
}

View File

@ -1,42 +0,0 @@
/*
* This file is part of the coreboot project.
*
* Copyright (C) 2016 Google Inc.
*
* 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.
*/
#ifndef __CHROMEOS_VBNV_H__
#define __CHROMEOS_VBNV_H__
#include <types.h>
/* Generic functions */
void read_vbnv(uint8_t *vbnv_copy);
void save_vbnv(const uint8_t *vbnv_copy);
int verify_vbnv(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);
/* CMOS backend */
void read_vbnv_cmos(uint8_t *vbnv_copy);
void save_vbnv_cmos(const uint8_t *vbnv_copy);
void init_vbnv_cmos(int rtc_fail);
/* Flash backend */
void read_vbnv_flash(uint8_t *vbnv_copy);
void save_vbnv_flash(const uint8_t *vbnv_copy);
/* EC backend */
void read_vbnv_ec(uint8_t *vbnv_copy);
void save_vbnv_ec(const uint8_t *vbnv_copy);
#endif

View File

@ -1,79 +0,0 @@
/*
* 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 "vbnv.h"
#include "vbnv_layout.h"
void read_vbnv_cmos(uint8_t *vbnv_copy)
{
int i;
for (i = 0; i < VBNV_BLOCK_SIZE; i++)
vbnv_copy[i] = cmos_read(CONFIG_VBNV_OFFSET + 14 + i);
if (IS_ENABLED(CONFIG_CHROMEOS_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)) {
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 < VBNV_BLOCK_SIZE; i++)
cmos_write(vbnv_copy[i], CONFIG_VBNV_OFFSET + 14 + i);
}
void init_vbnv_cmos(int rtc_fail)
{
uint8_t vbnv[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_CHROMEOS_VBNV_CMOS_BACKUP_TO_FLASH)
static void back_up_vbnv_cmos(void *unused)
{
uint8_t vbnv_cmos[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

View File

@ -1,29 +0,0 @@
/*
* 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 <types.h>
#include <ec/google/chromeec/ec.h>
#include "vbnv.h"
#include "vbnv_layout.h"
void read_vbnv_ec(uint8_t *vbnv_copy)
{
google_chromeec_vbnv_context(1, vbnv_copy, VBNV_BLOCK_SIZE);
}
void save_vbnv_ec(const uint8_t *vbnv_copy)
{
google_chromeec_vbnv_context(0, (uint8_t *)vbnv_copy, VBNV_BLOCK_SIZE);
}

View File

@ -1,227 +0,0 @@
/*
* This file is part of the coreboot project.
*
* Copyright (C) 2014 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 <arch/early_variables.h>
#include <assert.h>
#include <console/console.h>
#include <spi_flash.h>
#include <string.h>
#include <vb2_api.h>
#include <vboot_nvstorage.h>
#include "chromeos.h"
#include "vbnv.h"
#include "vbnv_layout.h"
#define BLOB_SIZE VB2_NVDATA_SIZE
struct vbnv_flash_ctx {
/* VBNV flash is initialized */
int initialized;
/* Offset of the current nvdata in SPI flash */
int blob_offset;
/* Offset of the topmost nvdata blob in SPI flash */
int top_offset;
/* SPI flash handler used when saving data */
struct spi_flash *flash;
/* FMAP descriptor of the NVRAM area */
struct region_device region;
/* Cache of the current nvdata */
uint8_t cache[BLOB_SIZE];
};
static struct vbnv_flash_ctx vbnv_flash CAR_GLOBAL;
/*
* This code assumes that flash is erased to 1-bits, and write operations can
* only change 1-bits to 0-bits. So if the new contents only change 1-bits to
* 0-bits, we can reuse the current blob.
*/
static inline uint8_t erase_value(void)
{
return 0xff;
}
static inline int can_overwrite(uint8_t current, uint8_t new)
{
return (current & new) == new;
}
static int init_vbnv(void)
{
struct vbnv_flash_ctx *ctx = car_get_var_ptr(&vbnv_flash);
uint8_t buf[BLOB_SIZE];
uint8_t empty_blob[BLOB_SIZE];
int offset;
int i;
if (vboot_named_region_device("RW_NVRAM", &ctx->region) ||
region_device_sz(&ctx->region) < BLOB_SIZE) {
printk(BIOS_ERR, "%s: failed to locate NVRAM\n", __func__);
return 1;
}
/* Prepare an empty blob to compare against. */
for (i = 0; i < BLOB_SIZE; i++)
empty_blob[i] = erase_value();
offset = 0;
ctx->top_offset = region_device_sz(&ctx->region) - BLOB_SIZE;
/*
* after the loop, offset is supposed to point the blob right before
* the first empty blob, the last blob in the nvram if there is no
* empty blob, or the base of the region if the nvram has never been
* used.
*/
for (i = 0; i <= ctx->top_offset; i += BLOB_SIZE) {
if (rdev_readat(&ctx->region, buf, i, BLOB_SIZE) < 0) {
printk(BIOS_ERR, "failed to read nvdata\n");
return 1;
}
if (!memcmp(buf, empty_blob, BLOB_SIZE))
break;
offset = i;
}
/* reread the nvdata and write it to the cache */
if (rdev_readat(&ctx->region, ctx->cache, offset, BLOB_SIZE) < 0) {
printk(BIOS_ERR, "failed to read nvdata\n");
return 1;
}
ctx->blob_offset = offset;
ctx->initialized = 1;
return 0;
}
static void vbnv_is_erasable(void)
{
/*
* We check whether the region is aligned or not in advance to ensure
* we can erase the region when it's all used up.
*
* The region offset & size are determined by fmap.dts yet the check can
* be confidently done only by the spi flash driver. We use the same
* check as the one used by spi_flash_cmd_erase, which happens to be
* common to all the spi flash parts we support.
*
* TODO: Check by calling can_erase implemented by each spi flash driver
*/
struct vbnv_flash_ctx *ctx = car_get_var_ptr(&vbnv_flash);
assert(!(region_device_offset(&ctx->region) % ctx->flash->sector_size));
assert(!(region_device_sz(&ctx->region) % ctx->flash->sector_size));
}
static int vbnv_flash_probe(void)
{
struct vbnv_flash_ctx *ctx = car_get_var_ptr(&vbnv_flash);
if (!ctx->flash) {
ctx->flash = spi_flash_probe(CONFIG_BOOT_MEDIA_SPI_BUS, 0);
if (!ctx->flash) {
printk(BIOS_ERR, "failed to probe spi flash\n");
return 1;
}
/*
* Called here instead of init_vbnv to reduce impact on boot
* speed.
*/
vbnv_is_erasable();
}
/*
* Handle the case where spi_flash_probe returns a CAR_GLOBAL
* in early execution on x86 but then later is moved to RAM.
*/
ctx->flash = car_get_var_ptr(ctx->flash);
return 0;
}
static int erase_nvram(void)
{
struct vbnv_flash_ctx *ctx = car_get_var_ptr(&vbnv_flash);
if (vbnv_flash_probe())
return 1;
if (ctx->flash->erase(ctx->flash, region_device_offset(&ctx->region),
region_device_sz(&ctx->region))) {
printk(BIOS_ERR, "failed to erase nvram\n");
return 1;
}
printk(BIOS_INFO, "nvram is cleared\n");
return 0;
}
void read_vbnv_flash(uint8_t *vbnv_copy)
{
struct vbnv_flash_ctx *ctx = car_get_var_ptr(&vbnv_flash);
if (!ctx->initialized)
if (init_vbnv())
return; /* error */
memcpy(vbnv_copy, ctx->cache, BLOB_SIZE);
}
void save_vbnv_flash(const uint8_t *vbnv_copy)
{
struct vbnv_flash_ctx *ctx = car_get_var_ptr(&vbnv_flash);
int new_offset;
int i;
if (!ctx->initialized)
if (init_vbnv())
return; /* error */
/* Bail out if there have been no changes. */
if (!memcmp(vbnv_copy, ctx->cache, BLOB_SIZE))
return;
new_offset = ctx->blob_offset;
/* See if we can overwrite the current blob with the new one */
for (i = 0; i < BLOB_SIZE; i++) {
if (!can_overwrite(ctx->cache[i], vbnv_copy[i])) {
/* unable to overwrite. need to use the next blob */
new_offset += BLOB_SIZE;
if (new_offset > ctx->top_offset) {
if (erase_nvram())
return; /* error */
new_offset = 0;
}
break;
}
}
if (!vbnv_flash_probe() &&
!ctx->flash->write(ctx->flash,
region_device_offset(&ctx->region) + new_offset,
BLOB_SIZE, vbnv_copy)) {
/* write was successful. safely move pointer forward */
ctx->blob_offset = new_offset;
memcpy(ctx->cache, vbnv_copy, BLOB_SIZE);
} else {
printk(BIOS_ERR, "failed to save nvdata\n");
}
}

View File

@ -1,47 +0,0 @@
/*
* This file is part of the coreboot project.
*
* Copyright (C) 2015 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.
*/
#ifndef VBNV_LAYOUT_H
#define VBNV_LAYOUT_H
#define VBNV_BLOCK_SIZE 16 /* Size of NV storage block in bytes */
/* Constants for NV storage. We use this rather than structs and
* bitfields so the data format is consistent across platforms and
* compilers.
*/
#define HEADER_OFFSET 0
#define HEADER_MASK 0xC0
#define HEADER_SIGNATURE 0x40
#define HEADER_FIRMWARE_SETTINGS_RESET 0x20
#define HEADER_KERNEL_SETTINGS_RESET 0x10
#define BOOT_OFFSET 1
#define BOOT_DEBUG_RESET_MODE 0x80
#define BOOT_DISABLE_DEV_REQUEST 0x40
#define BOOT_OPROM_NEEDED 0x20
#define BOOT_TRY_B_COUNT_MASK 0x0F
#define RECOVERY_OFFSET 2
#define LOCALIZATION_OFFSET 3
#define DEV_FLAGS_OFFSET 4
#define DEV_BOOT_USB_MASK 0x01
#define DEV_BOOT_SIGNED_ONLY_MASK 0x02
#define KERNEL_FIELD_OFFSET 11
#define CRC_OFFSET 15
#endif /* VBNV_LAYOUT_H */

View File

@ -1,89 +0,0 @@
## This file is part of the coreboot project.
##
## Copyright (C) 2014 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.
##
config VBOOT_STARTS_IN_BOOTBLOCK
bool "Vboot starts verifying in bootblock"
default n
depends on VBOOT_VERIFY_FIRMWARE
help
Firmware verification happens during or at the end of bootblock.
config VBOOT_STARTS_IN_ROMSTAGE
bool "Vboot starts verifying in romstage"
default n
depends on VBOOT_VERIFY_FIRMWARE && !VBOOT_STARTS_IN_BOOTBLOCK
help
Firmware verification happens during or at the end of romstage.
config VBOOT2_MOCK_SECDATA
bool "Mock secdata for firmware verification"
default n
depends on VBOOT_VERIFY_FIRMWARE
help
Enabling VBOOT2_MOCK_SECDATA will mock secdata for the firmware
verification to avoid access to a secdata storage (typically TPM).
All operations for a secdata storage will be successful. This option
can be used during development when a TPM is not present or broken.
THIS SHOULD NOT BE LEFT ON FOR PRODUCTION DEVICES.
config VBOOT_DISABLE_DEV_ON_RECOVERY
bool "Disable dev mode on recovery requests"
default n
depends on VBOOT_VERIFY_FIRMWARE
help
When this option is enabled, the Chrome OS device leaves the
developer mode as soon as recovery request is detected. This is
handy on embedded devices with limited input capabilities.
config SEPARATE_VERSTAGE
bool "Vboot verification is built into a separate stage"
default n
depends on VBOOT_VERIFY_FIRMWARE
config RETURN_FROM_VERSTAGE
bool "The separate verification stage returns to its caller"
default n
depends on SEPARATE_VERSTAGE
help
If this is set, the verstage returns back to the calling stage instead
of exiting to the succeeding stage so that the verstage space can be
reused by the succeeding stage. This is useful if a ram space is too
small to fit both the verstage and the succeeding stage.
config CHIPSET_PROVIDES_VERSTAGE_MAIN_SYMBOL
bool "The chipset provides the main() entry point for verstage"
default n
depends on SEPARATE_VERSTAGE
help
The chipset code provides their own main() entry point.
config VBOOT_DYNAMIC_WORK_BUFFER
bool "Vboot's work buffer is dynamically allocated."
default y if ARCH_ROMSTAGE_X86_32 && !SEPARATE_VERSTAGE
default n
depends on VBOOT_VERIFY_FIRMWARE
help
This option is used when there isn't enough pre-main memory
ram to allocate the vboot work buffer. That means vboot verification
is after memory init and requires main memory to back the work
buffer.
config VBOOT_SAVE_RECOVERY_REASON_ON_REBOOT
bool
default n
depends on VBOOT_VERIFY_FIRMWARE
help
This option ensures that the recovery request is not lost because of
reboots caused after vboot verification is run. e.g. reboots caused by
FSP components on Intel platforms.

View File

@ -1,118 +0,0 @@
##
## This file is part of the coreboot project.
##
## Copyright (C) 2014 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.
##
libverstage-generic-ccopts += -D__PRE_RAM__ -D__VERSTAGE__
verstage-generic-ccopts += -D__PRE_RAM__ -D__VERSTAGE__
bootblock-y += vboot_loader.c
romstage-y += vboot_loader.c
ramstage-y += vboot_loader.c
verstage-y += vboot_loader.c
postcar-y += vboot_loader.c
bootblock-y += ../vboot_common.c
verstage-y += ../vboot_common.c
romstage-y += ../vboot_common.c
ramstage-y += ../vboot_common.c
postcar-y += ../vboot_common.c
bootblock-y += recovery.c
romstage-y += recovery.c
ramstage-y += recovery.c
verstage-y += recovery.c
postcar-y += recovery.c
bootblock-y += common.c
libverstage-y += vboot_logic.c
verstage-y += common.c
verstage-y += verstage.c
ifeq (${CONFIG_VBOOT2_MOCK_SECDATA},y)
libverstage-y += secdata_mock.c
else
libverstage-y += antirollback.c
endif
romstage-y += vboot_handoff.c common.c
ramstage-y += common.c
postcar-y += common.c
ifeq ($(CONFIG_SEPARATE_VERSTAGE),y)
VB_FIRMWARE_ARCH := $(ARCHDIR-$(ARCH-verstage-y))
else
ifeq ($(CONFIG_VBOOT_STARTS_IN_BOOTBLOCK),y)
VB_FIRMWARE_ARCH := $(ARCHDIR-$(ARCH-bootblock-y))
else
VB_FIRMWARE_ARCH := $(ARCHDIR-$(ARCH-romstage-y))
endif
endif # CONFIG_SEPARATE_VERSTAGE
VB2_LIB = $(obj)/external/vboot_reference/vboot_fw20.a
VBOOT_CFLAGS += $(patsubst -I%,-I$(top)/%, $(filter-out -I$(obj), $(filter-out -include $(src)/include/kconfig.h, $(CPPFLAGS_libverstage))))
VBOOT_CFLAGS += $(CFLAGS_libverstage)
VBOOT_CFLAGS += $(libverstage-c-ccopts)
VBOOT_CFLAGS += -I$(abspath $(obj)) -include $(top)/src/include/kconfig.h -Wno-missing-prototypes
VBOOT_CFLAGS += -DVBOOT_DEBUG
$(VB2_LIB): $(obj)/config.h
@printf " MAKE $(subst $(obj)/,,$(@))\n"
$(Q)FIRMWARE_ARCH=$(VB_FIRMWARE_ARCH) \
CC="$(CC_verstage)" \
CFLAGS="$(VBOOT_CFLAGS)" VBOOT2="y" \
$(MAKE) -C $(VBOOT_SOURCE) \
BUILD=$(abspath $(dir $(VB2_LIB))) \
V=$(V) \
fwlib20
libverstage-srcs += $(VB2_LIB)
ifeq ($(CONFIG_SEPARATE_VERSTAGE),y)
cbfs-files-$(CONFIG_SEPARATE_VERSTAGE) += $(CONFIG_CBFS_PREFIX)/verstage
$(CONFIG_CBFS_PREFIX)/verstage-file := $(objcbfs)/verstage.elf
$(CONFIG_CBFS_PREFIX)/verstage-type := stage
$(CONFIG_CBFS_PREFIX)/verstage-compression := $(CBFS_PRERAM_COMPRESS_FLAG)
ifeq ($(CONFIG_ARCH_VERSTAGE_X86_32)$(CONFIG_ARCH_VERSTAGE_X86_64),y)
$(CONFIG_CBFS_PREFIX)/verstage-options := -a 64 -S ".car.data"
# If CAR does not support execution of code, verstage on x86 is expected to be
# xip.
ifneq ($(CONFIG_NO_XIP_EARLY_STAGES),y)
$(CONFIG_CBFS_PREFIX)/verstage-options += --xip
endif
endif
else
ifeq ($(CONFIG_VBOOT_STARTS_IN_BOOTBLOCK),y)
bootblock-srcs += $(objgenerated)/libverstage.a
else
romstage-srcs += $(objgenerated)/libverstage.a
endif
endif # CONFIG_SEPARATE_VERSTAGE
# Define a list of files that need to be in RO only.
# All other files will be installed into RO and RW regions
# Use $(sort) to cut down on extra spaces that would be translated to commas
regions-for-file = $(subst $(spc),$(comma),$(sort \
$(if $(filter \
$(if $(filter y,$(CONFIG_VBOOT_STARTS_IN_BOOTBLOCK)),, \
%/romstage) \
mts \
%/verstage \
locales \
locale_%.bin \
font.bin \
vbgfx.bin \
,$(1)),COREBOOT,COREBOOT FW_MAIN_A FW_MAIN_B)))

View File

@ -1,436 +0,0 @@
/* Copyright (c) 2013 The Chromium OS Authors. All rights reserved.
* Use of this source code is governed by a BSD-style license that can be
* found in the LICENSE file.
*
* Functions for querying, manipulating and locking rollback indices
* stored in the TPM NVRAM.
*/
#include <antirollback.h>
#include <stdlib.h>
#include <string.h>
#include <tpm_lite/tlcl.h>
#include <vb2_api.h>
#include <console/console.h>
#ifndef offsetof
#define offsetof(A,B) __builtin_offsetof(A,B)
#endif
#ifdef FOR_TEST
#include <stdio.h>
#define VBDEBUG(format, args...) printf(format, ## args)
#else
#include <console/console.h>
#define VBDEBUG(format, args...) \
printk(BIOS_INFO, "%s():%d: " format, __func__, __LINE__, ## args)
#endif
#define RETURN_ON_FAILURE(tpm_cmd) do { \
uint32_t result_; \
if ((result_ = (tpm_cmd)) != TPM_SUCCESS) { \
VBDEBUG("Antirollback: %08x returned by " #tpm_cmd \
"\n", (int)result_); \
return result_; \
} \
} while (0)
static uint32_t safe_write(uint32_t index, const void *data, uint32_t length);
uint32_t tpm_extend_pcr(struct vb2_context *ctx, int pcr,
enum vb2_pcr_digest which_digest)
{
uint8_t buffer[VB2_PCR_DIGEST_RECOMMENDED_SIZE];
uint32_t size = sizeof(buffer);
int rv;
rv = vb2api_get_pcr_digest(ctx, which_digest, buffer, &size);
if (rv != VB2_SUCCESS)
return rv;
if (size < TPM_PCR_DIGEST)
return VB2_ERROR_UNKNOWN;
return tlcl_extend(pcr, buffer, NULL);
}
static uint32_t read_space_firmware(struct vb2_context *ctx)
{
int attempts = 3;
while (attempts--) {
RETURN_ON_FAILURE(tlcl_read(FIRMWARE_NV_INDEX, ctx->secdata,
VB2_SECDATA_SIZE));
if (vb2api_secdata_check(ctx) == VB2_SUCCESS)
return TPM_SUCCESS;
VBDEBUG("TPM: %s() - bad CRC\n", __func__);
}
VBDEBUG("TPM: %s() - too many bad CRCs, giving up\n", __func__);
return TPM_E_CORRUPTED_STATE;
}
static uint32_t write_secdata(uint32_t index,
const uint8_t *secdata,
uint32_t len)
{
uint8_t sd[32];
uint32_t rv;
int attempts = 3;
if (len > sizeof(sd)) {
VBDEBUG("TPM: %s() - data is too large\n", __func__);
return TPM_E_WRITE_FAILURE;
}
while (attempts--) {
rv = safe_write(index, secdata, len);
/* Can't write, not gonna try again */
if (rv != TPM_SUCCESS)
return rv;
/* Read it back to be sure it got the right values. */
rv = tlcl_read(index, sd, len);
if (rv == TPM_SUCCESS && memcmp(secdata, sd, len) == 0)
return rv;
VBDEBUG("TPM: %s() failed. trying again\n", __func__);
/* Try writing it again. Maybe it was garbled on the way out. */
}
VBDEBUG("TPM: %s() - too many failures, giving up\n", __func__);
return TPM_E_CORRUPTED_STATE;
}
/*
* This is derived from rollback_index.h of vboot_reference. see struct
* RollbackSpaceKernel for details.
*/
static const uint8_t secdata_kernel[] = {
0x02,
0x4C, 0x57, 0x52, 0x47,
0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00,
0xE8,
};
#if IS_ENABLED(CONFIG_TPM2)
/* Nothing special in the TPM2 path yet. */
static uint32_t safe_write(uint32_t index, const void *data, uint32_t length)
{
return tlcl_write(index, data, length);
}
static uint32_t set_firmware_space(const void *firmware_blob)
{
RETURN_ON_FAILURE(tlcl_define_space(FIRMWARE_NV_INDEX,
VB2_SECDATA_SIZE));
RETURN_ON_FAILURE(safe_write(FIRMWARE_NV_INDEX, firmware_blob,
VB2_SECDATA_SIZE));
return TPM_SUCCESS;
}
static uint32_t set_kernel_space(const void *kernel_blob)
{
RETURN_ON_FAILURE(tlcl_define_space(KERNEL_NV_INDEX,
sizeof(secdata_kernel)));
RETURN_ON_FAILURE(safe_write(KERNEL_NV_INDEX, kernel_blob,
sizeof(secdata_kernel)));
return TPM_SUCCESS;
}
static uint32_t _factory_initialize_tpm(struct vb2_context *ctx)
{
RETURN_ON_FAILURE(tlcl_force_clear());
RETURN_ON_FAILURE(set_firmware_space(ctx->secdata));
RETURN_ON_FAILURE(set_kernel_space(secdata_kernel));
return TPM_SUCCESS;
}
uint32_t tpm_clear_and_reenable(void)
{
VBDEBUG("TPM: Clear and re-enable\n");
return TPM_SUCCESS;
}
uint32_t antirollback_lock_space_firmware(void)
{
return tlcl_lock_nv_write(FIRMWARE_NV_INDEX);
}
#else
uint32_t tpm_clear_and_reenable(void)
{
VBDEBUG("TPM: Clear and re-enable\n");
RETURN_ON_FAILURE(tlcl_force_clear());
RETURN_ON_FAILURE(tlcl_set_enable());
RETURN_ON_FAILURE(tlcl_set_deactivated(0));
return TPM_SUCCESS;
}
/**
* Like tlcl_write(), but checks for write errors due to hitting the 64-write
* limit and clears the TPM when that happens. This can only happen when the
* TPM is unowned, so it is OK to clear it (and we really have no choice).
* This is not expected to happen frequently, but it could happen.
*/
static uint32_t safe_write(uint32_t index, const void *data, uint32_t length)
{
uint32_t result = tlcl_write(index, data, length);
if (result == TPM_E_MAXNVWRITES) {
RETURN_ON_FAILURE(tpm_clear_and_reenable());
return tlcl_write(index, data, length);
} else {
return result;
}
}
/**
* Similarly to safe_write(), this ensures we don't fail a DefineSpace because
* we hit the TPM write limit. This is even less likely to happen than with
* writes because we only define spaces once at initialization, but we'd
* rather be paranoid about this.
*/
static uint32_t safe_define_space(uint32_t index, uint32_t perm, uint32_t size)
{
uint32_t result = tlcl_define_space(index, perm, size);
if (result == TPM_E_MAXNVWRITES) {
RETURN_ON_FAILURE(tpm_clear_and_reenable());
return tlcl_define_space(index, perm, size);
} else {
return result;
}
}
static uint32_t _factory_initialize_tpm(struct vb2_context *ctx)
{
TPM_PERMANENT_FLAGS pflags;
uint32_t result;
result = tlcl_get_permanent_flags(&pflags);
if (result != TPM_SUCCESS)
return result;
/*
* TPM may come from the factory without physical presence finalized.
* Fix if necessary.
*/
VBDEBUG("TPM: physicalPresenceLifetimeLock=%d\n",
pflags.physicalPresenceLifetimeLock);
if (!pflags.physicalPresenceLifetimeLock) {
VBDEBUG("TPM: Finalizing physical presence\n");
RETURN_ON_FAILURE(tlcl_finalize_physical_presence());
}
/*
* The TPM will not enforce the NV authorization restrictions until the
* execution of a TPM_NV_DefineSpace with the handle of
* TPM_NV_INDEX_LOCK. Here we create that space if it doesn't already
* exist. */
VBDEBUG("TPM: nvLocked=%d\n", pflags.nvLocked);
if (!pflags.nvLocked) {
VBDEBUG("TPM: Enabling NV locking\n");
RETURN_ON_FAILURE(tlcl_set_nv_locked());
}
/* Clear TPM owner, in case the TPM is already owned for some reason. */
VBDEBUG("TPM: Clearing owner\n");
RETURN_ON_FAILURE(tpm_clear_and_reenable());
/* Define the backup space. No need to initialize it, though. */
RETURN_ON_FAILURE(safe_define_space(BACKUP_NV_INDEX,
TPM_NV_PER_PPWRITE,
VB2_NVDATA_SIZE));
/* Define and initialize the kernel space */
RETURN_ON_FAILURE(safe_define_space(KERNEL_NV_INDEX,
TPM_NV_PER_PPWRITE,
sizeof(secdata_kernel)));
RETURN_ON_FAILURE(write_secdata(KERNEL_NV_INDEX,
secdata_kernel,
sizeof(secdata_kernel)));
/* Defines and sets vb2 secdata space */
vb2api_secdata_create(ctx);
RETURN_ON_FAILURE(safe_define_space(FIRMWARE_NV_INDEX,
TPM_NV_PER_GLOBALLOCK |
TPM_NV_PER_PPWRITE,
VB2_SECDATA_SIZE));
RETURN_ON_FAILURE(write_secdata(FIRMWARE_NV_INDEX,
ctx->secdata,
VB2_SECDATA_SIZE));
return TPM_SUCCESS;
}
uint32_t antirollback_lock_space_firmware(void)
{
return tlcl_set_global_lock();
}
#endif
uint32_t factory_initialize_tpm(struct vb2_context *ctx)
{
uint32_t result;
/* Defines and sets vb2 secdata space */
vb2api_secdata_create(ctx);
VBDEBUG("TPM: factory initialization\n");
/*
* Do a full test. This only happens the first time the device is
* turned on in the factory, so performance is not an issue. This is
* almost certainly not necessary, but it gives us more confidence
* about some code paths below that are difficult to
* test---specifically the ones that set lifetime flags, and are only
* executed once per physical TPM.
*/
result = tlcl_self_test_full();
if (result != TPM_SUCCESS)
return result;
result = _factory_initialize_tpm(ctx);
if (result != TPM_SUCCESS)
return result;
VBDEBUG("TPM: factory initialization successful\n");
return TPM_SUCCESS;
}
/*
* SetupTPM starts the TPM and establishes the root of trust for the
* anti-rollback mechanism. SetupTPM can fail for three reasons. 1 A bug. 2 a
* TPM hardware failure. 3 An unexpected TPM state due to some attack. In
* general we cannot easily distinguish the kind of failure, so our strategy is
* to reboot in recovery mode in all cases. The recovery mode calls SetupTPM
* again, which executes (almost) the same sequence of operations. There is a
* good chance that, if recovery mode was entered because of a TPM failure, the
* failure will repeat itself. (In general this is impossible to guarantee
* because we have no way of creating the exact TPM initial state at the
* previous boot.) In recovery mode, we ignore the failure and continue, thus
* giving the recovery kernel a chance to fix things (that's why we don't set
* bGlobalLock). The choice is between a knowingly insecure device and a
* bricked device.
*
* As a side note, observe that we go through considerable hoops to avoid using
* the STCLEAR permissions for the index spaces. We do this to avoid writing
* to the TPM flashram at every reboot or wake-up, because of concerns about
* the durability of the NVRAM.
*/
uint32_t setup_tpm(struct vb2_context *ctx)
{
uint8_t disable;
uint8_t deactivated;
uint32_t result;
RETURN_ON_FAILURE(tlcl_lib_init());
/* Handle special init for S3 resume path */
if (ctx->flags & VB2_CONTEXT_S3_RESUME) {
result = tlcl_resume();
if (result == TPM_E_INVALID_POSTINIT)
printk(BIOS_DEBUG, "TPM: Already initialized.\n");
return TPM_SUCCESS;
}
#ifdef TEGRA_SOFT_REBOOT_WORKAROUND
result = tlcl_startup();
if (result == TPM_E_INVALID_POSTINIT) {
/*
* Some prototype hardware doesn't reset the TPM on a CPU
* reset. We do a hard reset to get around this.
*/
VBDEBUG("TPM: soft reset detected\n", result);
ctx->flags |= VB2_CONTEXT_SECDATA_WANTS_REBOOT;
return TPM_E_MUST_REBOOT;
} else if (result != TPM_SUCCESS) {
VBDEBUG("TPM: tlcl_startup returned %08x\n", result);
return result;
}
#else
RETURN_ON_FAILURE(tlcl_startup());
#endif
/*
* Some TPMs start the self test automatically at power on. In that case
* we don't need to call ContinueSelfTest. On some (other) TPMs,
* continue_self_test may block. In that case, we definitely don't want
* to call it here. For TPMs in the intersection of these two sets, we
* are screwed. (In other words: TPMs that require manually starting the
* self-test AND block will have poor performance until we split
* tlcl_send_receive() into send() and receive(), and have a state
* machine to control setup.)
*
* This comment is likely to become obsolete in the near future, so
* don't trust it. It may have not been updated.
*/
#ifdef TPM_MANUAL_SELFTEST
#ifdef TPM_BLOCKING_CONTINUESELFTEST
#warning "lousy TPM!"
#endif
RETURN_ON_FAILURE(tlcl_continue_self_test());
#endif
result = tlcl_assert_physical_presence();
if (result != TPM_SUCCESS) {
/*
* It is possible that the TPM was delivered with the physical
* presence command disabled. This tries enabling it, then
* tries asserting PP again.
*/
RETURN_ON_FAILURE(tlcl_physical_presence_cmd_enable());
RETURN_ON_FAILURE(tlcl_assert_physical_presence());
}
/* Check that the TPM is enabled and activated. */
RETURN_ON_FAILURE(tlcl_get_flags(&disable, &deactivated, NULL));
if (disable || deactivated) {
VBDEBUG("TPM: disabled (%d) or deactivated (%d). Fixing...\n",
disable, deactivated);
RETURN_ON_FAILURE(tlcl_set_enable());
RETURN_ON_FAILURE(tlcl_set_deactivated(0));
VBDEBUG("TPM: Must reboot to re-enable\n");
ctx->flags |= VB2_CONTEXT_SECDATA_WANTS_REBOOT;
return TPM_E_MUST_REBOOT;
}
VBDEBUG("TPM: SetupTPM() succeeded\n");
return TPM_SUCCESS;
}
uint32_t antirollback_read_space_firmware(struct vb2_context *ctx)
{
uint32_t rv;
rv = setup_tpm(ctx);
if (rv)
return rv;
/* Read the firmware space. */
rv = read_space_firmware(ctx);
if (rv == TPM_E_BADINDEX) {
/*
* This seems the first time we've run. Initialize the TPM.
*/
VBDEBUG("TPM: Not initialized yet.\n");
RETURN_ON_FAILURE(factory_initialize_tpm(ctx));
} else if (rv != TPM_SUCCESS) {
VBDEBUG("TPM: Firmware space in a bad state; giving up.\n");
//RETURN_ON_FAILURE(factory_initialize_tpm(ctx));
return TPM_E_CORRUPTED_STATE;
}
return TPM_SUCCESS;
}
uint32_t antirollback_write_space_firmware(struct vb2_context *ctx)
{
return write_secdata(FIRMWARE_NV_INDEX, ctx->secdata, VB2_SECDATA_SIZE);
}

View File

@ -1,183 +0,0 @@
/*
* This file is part of the coreboot project.
*
* Copyright (C) 2014 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 <assert.h>
#include <cbfs.h>
#include <cbmem.h>
#include <console/console.h>
#include <reset.h>
#include <string.h>
#include <vb2_api.h>
#include "../chromeos.h"
#include "../symbols.h"
#include "../vboot_common.h"
#include "misc.h"
struct selected_region {
uint32_t offset;
uint32_t size;
};
/*
* this is placed at the start of the vboot work buffer. selected_region is used
* for the verstage to return the location of the selected slot. buffer is used
* by the vboot2 core. Keep the struct cpu architecture agnostic as it crosses
* stage boundaries.
*/
struct vb2_working_data {
struct selected_region selected_region;
/* offset of the buffer from the start of this struct */
uint32_t buffer_offset;
uint32_t buffer_size;
};
static const size_t vb_work_buf_size = 16 * KiB;
static struct vb2_working_data * const vboot_get_working_data(void)
{
if (IS_ENABLED(CONFIG_VBOOT_DYNAMIC_WORK_BUFFER))
/* cbmem_add() does a cbmem_find() first. */
return cbmem_add(CBMEM_ID_VBOOT_WORKBUF, vb_work_buf_size);
else
return (struct vb2_working_data *)_vboot2_work;
}
static size_t vb2_working_data_size(void)
{
if (IS_ENABLED(CONFIG_VBOOT_DYNAMIC_WORK_BUFFER))
return vb_work_buf_size;
else
return _vboot2_work_size;
}
static struct selected_region *vb2_selected_region(void)
{
struct selected_region *sel_reg = NULL;
/* Ramstage and postcar always uses cbmem as a source of truth. */
if (ENV_RAMSTAGE || ENV_POSTCAR)
sel_reg = cbmem_find(CBMEM_ID_VBOOT_SEL_REG);
else if (ENV_ROMSTAGE) {
/* Try cbmem first. Fall back on working data if not found. */
sel_reg = cbmem_find(CBMEM_ID_VBOOT_SEL_REG);
if (sel_reg == NULL) {
struct vb2_working_data *wd = vboot_get_working_data();
sel_reg = &wd->selected_region;
}
} else {
/* Stages such as bootblock and verstage use working data. */
struct vb2_working_data *wd = vboot_get_working_data();
sel_reg = &wd->selected_region;
}
return sel_reg;
}
void vb2_init_work_context(struct vb2_context *ctx)
{
struct vb2_working_data *wd;
size_t work_size;
/* First initialize the working data region. */
work_size = vb2_working_data_size();
wd = vboot_get_working_data();
memset(wd, 0, work_size);
/*
* vboot prefers 16-byte alignment. This takes away 16 bytes
* from the VBOOT2_WORK region, but the vboot devs said that's okay.
*/
wd->buffer_offset = ALIGN_UP(sizeof(*wd), 16);
wd->buffer_size = work_size - wd->buffer_offset;
/* Initialize the vb2_context. */
memset(ctx, 0, sizeof(*ctx));
ctx->workbuf = (void *)vb2_get_shared_data();
ctx->workbuf_size = wd->buffer_size;
}
struct vb2_shared_data *vb2_get_shared_data(void)
{
struct vb2_working_data *wd = vboot_get_working_data();
return (void *)((uintptr_t)wd + wd->buffer_offset);
}
int vb2_get_selected_region(struct region *region)
{
const struct selected_region *reg = vb2_selected_region();
if (reg == NULL)
return -1;
if (reg->offset == 0 && reg->size == 0)
return -1;
region->offset = reg->offset;
region->size = reg->size;
return 0;
}
void vb2_set_selected_region(const struct region *region)
{
struct selected_region *reg = vb2_selected_region();
assert(reg != NULL);
reg->offset = region_offset(region);
reg->size = region_sz(region);
}
int vb2_is_slot_selected(void)
{
const struct selected_region *reg = vb2_selected_region();
assert(reg != NULL);
return reg->size > 0;
}
void vb2_store_selected_region(void)
{
const struct vb2_working_data *wd;
struct selected_region *sel_reg;
/* Always use the working data in this path since it's the object
* which has the result.. */
wd = vboot_get_working_data();
sel_reg = cbmem_add(CBMEM_ID_VBOOT_SEL_REG, sizeof(*sel_reg));
assert(sel_reg != NULL);
sel_reg->offset = wd->selected_region.offset;
sel_reg->size = wd->selected_region.size;
}
/*
* For platforms that employ VBOOT_DYNAMIC_WORK_BUFFER, the vboot
* verification doesn't happen until after cbmem is brought online.
* Therefore, the selected region contents would not be initialized
* so don't automatically add results when cbmem comes online.
*/
#if !IS_ENABLED(CONFIG_VBOOT_DYNAMIC_WORK_BUFFER)
static void vb2_store_selected_region_cbmem(int unused)
{
vb2_store_selected_region();
}
ROMSTAGE_CBMEM_INIT_HOOK(vb2_store_selected_region_cbmem)
#endif

View File

@ -1,40 +0,0 @@
/*
* This file is part of the coreboot project.
*
* Copyright (C) 2014 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.
*/
#ifndef __CHROMEOS_VBOOT2_MISC_H__
#define __CHROMEOS_VBOOT2_MISC_H__
#include "../vboot_common.h"
struct vb2_context;
struct vb2_shared_data;
void vboot_fill_handoff(void);
void vb2_init_work_context(struct vb2_context *ctx);
struct vb2_shared_data *vb2_get_shared_data(void);
/* Returns 0 on success. < 0 on failure. */
int vb2_get_selected_region(struct region *region);
void vb2_set_selected_region(const struct region *region);
int vb2_is_slot_selected(void);
int vb2_logic_executed(void);
/* Store the selected region in cbmem for later use. */
void vb2_store_selected_region(void);
void vb2_save_recovery_reason_vbnv(void);
#endif /* __CHROMEOS_VBOOT2_MISC_H__ */

View File

@ -1,154 +0,0 @@
/*
* This file is part of the coreboot project.
*
* Copyright 2016 Google Inc.
*
* 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 <assert.h>
#include <bootstate.h>
#include <rules.h>
#include <string.h>
#include <vb2_api.h>
#include "misc.h"
#include "../vboot_common.h"
static int vb2_get_recovery_reason_shared_data(void)
{
/* Shared data does not exist for Ramstage and Post-CAR stage. */
if (ENV_RAMSTAGE || ENV_POSTCAR)
return 0;
struct vb2_shared_data *sd = vb2_get_shared_data();
assert(sd);
return sd->recovery_reason;
}
void vb2_save_recovery_reason_vbnv(void)
{
if (!IS_ENABLED(CONFIG_VBOOT_SAVE_RECOVERY_REASON_ON_REBOOT))
return;
int reason = vb2_get_recovery_reason_shared_data();
if (!reason)
return;
set_recovery_mode_into_vbnv(reason);
}
static void vb2_clear_recovery_reason_vbnv(void *unused)
{
if (!IS_ENABLED(CONFIG_VBOOT_SAVE_RECOVERY_REASON_ON_REBOOT))
return;
set_recovery_mode_into_vbnv(0);
}
/*
* Recovery reason stored in VBNV needs to be cleared before the state of VBNV
* is backed-up anywhere or jumping to the payload (whichever occurs
* first). Currently, vbnv_cmos.c backs up VBNV on POST_DEVICE. Thus, we need to
* make sure that the stored recovery reason is cleared off before that
* happens.
* IMPORTANT: Any reboot occurring after BS_DEV_INIT state will cause loss of
* recovery reason on reboot. Until now, we have seen reboots occuring on x86
* only in FSP stages which run before BS_DEV_INIT.
*/
BOOT_STATE_INIT_ENTRY(BS_DEV_INIT, BS_ON_EXIT,
vb2_clear_recovery_reason_vbnv, NULL);
/*
* Returns 0 for the stages where we know that cbmem does not come online.
* Even if this function returns 1 for romstage, depending upon the point in
* bootup, cbmem might not actually be online.
*/
static int cbmem_possibly_online(void)
{
if (ENV_BOOTBLOCK)
return 0;
if (ENV_VERSTAGE && IS_ENABLED(CONFIG_VBOOT_STARTS_IN_BOOTBLOCK))
return 0;
return 1;
}
/*
* Returns 1 if vboot is being used and currently in a stage which might have
* already executed vboot verification.
*/
static int vboot_possibly_executed(void)
{
if (!IS_ENABLED(CONFIG_VBOOT_VERIFY_FIRMWARE))
return 0;
if (IS_ENABLED(CONFIG_VBOOT_STARTS_IN_BOOTBLOCK)) {
if (ENV_BOOTBLOCK && IS_ENABLED(CONFIG_SEPARATE_VERSTAGE))
return 0;
return 1;
}
if (IS_ENABLED(CONFIG_VBOOT_STARTS_IN_ROMSTAGE)) {
if (ENV_BOOTBLOCK)
return 0;
return 1;
}
return 0;
}
/*
* vb2_check_recovery_request looks up different components to identify if there
* is a recovery request and returns appropriate reason code:
* 1. Checks if recovery mode is initiated by EC. If yes, returns
* VB2_RECOVERY_RO_MANUAL.
* 2. Checks if recovery request is present in VBNV and returns the code read
* from it.
* 3. Checks recovery request in handoff for stages post-cbmem.
* 4. For non-CBMEM stages, check if vboot verification is done and look-up
* selected region to identify if vboot_refence library has requested recovery
* path. If yes, return the reason code from shared data.
* 5. If nothing applies, return 0 indicating no recovery request.
*/
int vboot_check_recovery_request(void)
{
int reason = 0;
/* EC-initiated recovery. */
if (get_recovery_mode_switch())
return VB2_RECOVERY_RO_MANUAL;
/* Recovery request in VBNV. */
if ((reason = get_recovery_mode_from_vbnv()) != 0)
return reason;
/*
* Check recovery flag in vboot_handoff for stages post CBMEM coming
* online. Since for some stages there is no way to know if cbmem has
* already come online, try looking up handoff anyways. If it fails,
* flow will fallback to looking up shared data.
*/
if (cbmem_possibly_online() &&
((reason = vboot_handoff_get_recovery_reason()) != 0))
return reason;
/*
* For stages where CBMEM might not be online, identify if vboot
* verification is already complete and no slot was selected
* i.e. recovery path was requested.
*/
if (vboot_possibly_executed() && vb2_logic_executed() &&
!vb2_is_slot_selected())
return vb2_get_recovery_reason_shared_data();
return 0;
}

View File

@ -1,38 +0,0 @@
/* Copyright (c) 2015 The Chromium OS Authors. All rights reserved.
* Use of this source code is governed by a BSD-style license that can be
* found in the LICENSE file.
*
* Functions for querying, manipulating and locking rollback indices
* stored in the TPM NVRAM.
*/
#include <antirollback.h>
#include <stdlib.h>
#include <vb2_api.h>
uint32_t tpm_extend_pcr(struct vb2_context *ctx, int pcr,
enum vb2_pcr_digest which_digest)
{
return TPM_SUCCESS;
}
uint32_t tpm_clear_and_reenable(void)
{
return TPM_SUCCESS;
}
uint32_t antirollback_read_space_firmware(struct vb2_context *ctx)
{
vb2api_secdata_create(ctx);
return TPM_SUCCESS;
}
uint32_t antirollback_write_space_firmware(struct vb2_context *ctx)
{
return TPM_SUCCESS;
}
uint32_t antirollback_lock_space_firmware()
{
return TPM_SUCCESS;
}

View File

@ -1,179 +0,0 @@
/*
* This file is part of the coreboot project.
*
* Copyright (C) 2013 Google, Inc.
*
* 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 <arch/stages.h>
#include <assert.h>
#include <stdint.h>
#include <stddef.h>
#include <string.h>
#include <cbfs.h>
#include <cbmem.h>
#include <console/console.h>
#include <console/vtxprintf.h>
#include <fmap.h>
#include <stdlib.h>
#include <timestamp.h>
#define NEED_VB20_INTERNALS /* TODO: remove me! */
#include <vb2_api.h>
#include <vboot_struct.h>
#include "../chromeos.h"
#include "misc.h"
/**
* Sets vboot_handoff based on the information in vb2_shared_data
*/
static void fill_vboot_handoff(struct vboot_handoff *vboot_handoff,
struct vb2_shared_data *vb2_sd)
{
VbSharedDataHeader *vb_sd =
(VbSharedDataHeader *)vboot_handoff->shared_data;
uint32_t *oflags = &vboot_handoff->init_params.out_flags;
vb_sd->flags |= VBSD_BOOT_FIRMWARE_VBOOT2;
vboot_handoff->selected_firmware = vb2_sd->fw_slot;
vb_sd->firmware_index = vb2_sd->fw_slot;
vb_sd->magic = VB_SHARED_DATA_MAGIC;
vb_sd->struct_version = VB_SHARED_DATA_VERSION;
vb_sd->struct_size = sizeof(VbSharedDataHeader);
vb_sd->data_size = VB_SHARED_DATA_MIN_SIZE;
vb_sd->data_used = sizeof(VbSharedDataHeader);
vb_sd->fw_version_tpm = vb2_sd->fw_version_secdata;
if (get_write_protect_state())
vb_sd->flags |= VBSD_BOOT_FIRMWARE_WP_ENABLED;
if (get_sw_write_protect_state())
vb_sd->flags |= VBSD_BOOT_FIRMWARE_SW_WP_ENABLED;
if (vb2_sd->recovery_reason) {
vb_sd->firmware_index = 0xFF;
if (vb2_sd->flags & VB2_SD_FLAG_MANUAL_RECOVERY)
vb_sd->flags |= VBSD_BOOT_REC_SWITCH_ON;
*oflags |= VB_INIT_OUT_ENABLE_RECOVERY;
*oflags |= VB_INIT_OUT_CLEAR_RAM;
*oflags |= VB_INIT_OUT_ENABLE_DISPLAY;
*oflags |= VB_INIT_OUT_ENABLE_USB_STORAGE;
}
if (vb2_sd->flags & VB2_SD_DEV_MODE_ENABLED) {
*oflags |= VB_INIT_OUT_ENABLE_DEVELOPER;
*oflags |= VB_INIT_OUT_CLEAR_RAM;
*oflags |= VB_INIT_OUT_ENABLE_DISPLAY;
*oflags |= VB_INIT_OUT_ENABLE_USB_STORAGE;
vb_sd->flags |= VBSD_BOOT_DEV_SWITCH_ON;
vb_sd->flags |= VBSD_LF_DEV_SWITCH_ON;
}
/* TODO: Set these in depthcharge */
if (IS_ENABLED(CONFIG_VIRTUAL_DEV_SWITCH))
vb_sd->flags |= VBSD_HONOR_VIRT_DEV_SWITCH;
if (IS_ENABLED(CONFIG_EC_SOFTWARE_SYNC))
vb_sd->flags |= VBSD_EC_SOFTWARE_SYNC;
if (!IS_ENABLED(CONFIG_PHYSICAL_REC_SWITCH))
vb_sd->flags |= VBSD_BOOT_REC_SWITCH_VIRTUAL;
if (IS_ENABLED(CONFIG_VBOOT_EC_SLOW_UPDATE))
vb_sd->flags |= VBSD_EC_SLOW_UPDATE;
if (IS_ENABLED(CONFIG_VBOOT_OPROM_MATTERS)) {
vb_sd->flags |= VBSD_OPROM_MATTERS;
/*
* Inform vboot if the display was enabled by dev/rec
* mode or was requested by vboot kernel phase.
*/
if (*oflags & VB_INIT_OUT_ENABLE_DISPLAY ||
vboot_wants_oprom()) {
vb_sd->flags |= VBSD_OPROM_LOADED;
*oflags |= VB_INIT_OUT_ENABLE_DISPLAY;
}
}
/* In vboot1, VBSD_FWB_TRIED is
* set only if B is booted as explicitly requested. Therefore, if B is
* booted because A was found bad, the flag should not be set. It's
* better not to touch it if we can only ambiguously control it. */
/* if (vb2_sd->fw_slot)
vb_sd->flags |= VBSD_FWB_TRIED; */
/* copy kernel subkey if it's found */
if (vb2_sd->workbuf_preamble_size) {
struct vb2_fw_preamble *fp;
uintptr_t dst, src;
printk(BIOS_INFO, "Copying FW preamble\n");
fp = (struct vb2_fw_preamble *)((uintptr_t)vb2_sd +
vb2_sd->workbuf_preamble_offset);
src = (uintptr_t)&fp->kernel_subkey +
fp->kernel_subkey.key_offset;
dst = (uintptr_t)vb_sd + sizeof(VbSharedDataHeader);
assert(dst + fp->kernel_subkey.key_size <=
(uintptr_t)vboot_handoff + sizeof(*vboot_handoff));
memcpy((void *)dst, (void *)src,
fp->kernel_subkey.key_size);
vb_sd->data_used += fp->kernel_subkey.key_size;
vb_sd->kernel_subkey.key_offset =
dst - (uintptr_t)&vb_sd->kernel_subkey;
vb_sd->kernel_subkey.key_size = fp->kernel_subkey.key_size;
vb_sd->kernel_subkey.algorithm = fp->kernel_subkey.algorithm;
vb_sd->kernel_subkey.key_version =
fp->kernel_subkey.key_version;
}
vb_sd->recovery_reason = vb2_sd->recovery_reason;
}
void vboot_fill_handoff(void)
{
struct vboot_handoff *vh;
struct vb2_shared_data *sd;
sd = vb2_get_shared_data();
sd->workbuf_hash_offset = 0;
sd->workbuf_hash_size = 0;
printk(BIOS_INFO, "creating vboot_handoff structure\n");
vh = cbmem_add(CBMEM_ID_VBOOT_HANDOFF, sizeof(*vh));
if (vh == NULL)
/* we don't need to failover gracefully here because this
* shouldn't happen with the image that has passed QA. */
die("failed to allocate vboot_handoff structure\n");
memset(vh, 0, sizeof(*vh));
/* needed until we finish transtion to vboot2 for kernel verification */
fill_vboot_handoff(vh, sd);
/*
* The recovery mode switch is cleared (typically backed by EC) here
* to allow multiple queries to get_recovery_mode_switch() and have
* them return consistent results during the verified boot path as well
* as dram initialization. x86 systems ignore the saved dram settings
* in the recovery path in order to start from a clean slate. Therefore
* clear the state here since this function is called when memory
* is known to be up.
*/
clear_recovery_mode_switch();
}
/*
* For platforms that employ VBOOT_DYNAMIC_WORK_BUFFER, the vboot
* verification doesn't happen until after cbmem is brought online.
* Therefore, the vboot results would not be initialized so don't
* automatically add results when cbmem comes online.
*/
#if !IS_ENABLED(CONFIG_VBOOT_DYNAMIC_WORK_BUFFER)
static void vb2_fill_handoff_cbmem(int unused)
{
vboot_fill_handoff();
}
ROMSTAGE_CBMEM_INIT_HOOK(vb2_fill_handoff_cbmem)
#endif

View File

@ -1,159 +0,0 @@
/*
* This file is part of the coreboot project.
*
* Copyright 2015 Google, Inc.
*
* 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 <arch/early_variables.h>
#include <cbfs.h>
#include <cbmem.h>
#include <console/console.h>
#include <rmodule.h>
#include <rules.h>
#include <string.h>
#include "misc.h"
#include "../vboot_common.h"
#include "../symbols.h"
/* The stage loading code is compiled and entered from multiple stages. The
* helper functions below attempt to provide more clarity on when certain
* code should be called. */
static int verification_should_run(void)
{
if (ENV_VERSTAGE && IS_ENABLED(CONFIG_SEPARATE_VERSTAGE))
return 1;
if (!IS_ENABLED(CONFIG_SEPARATE_VERSTAGE)) {
if (ENV_ROMSTAGE &&
IS_ENABLED(CONFIG_VBOOT_STARTS_IN_ROMSTAGE))
return 1;
if (ENV_BOOTBLOCK &&
IS_ENABLED(CONFIG_VBOOT_STARTS_IN_BOOTBLOCK))
return 1;
}
return 0;
}
static int verstage_should_load(void)
{
if (!IS_ENABLED(CONFIG_SEPARATE_VERSTAGE))
return 0;
if (ENV_ROMSTAGE && IS_ENABLED(CONFIG_VBOOT_STARTS_IN_ROMSTAGE))
return 1;
if (ENV_BOOTBLOCK && IS_ENABLED(CONFIG_VBOOT_STARTS_IN_BOOTBLOCK))
return 1;
return 0;
}
static int vboot_executed CAR_GLOBAL;
int vb2_logic_executed(void)
{
/* If this stage is supposed to run the vboot logic ensure it has been
* executed. */
if (verification_should_run() && car_get_var(vboot_executed))
return 1;
/* If this stage is supposed to load verstage and verstage is returning
* back to the calling stage check that it has been executed. */
if (verstage_should_load() && IS_ENABLED(CONFIG_RETURN_FROM_VERSTAGE))
if (car_get_var(vboot_executed))
return 1;
/* Handle all other stages post vboot execution. */
if (!ENV_BOOTBLOCK) {
if (IS_ENABLED(CONFIG_VBOOT_STARTS_IN_BOOTBLOCK))
return 1;
if (IS_ENABLED(CONFIG_VBOOT_STARTS_IN_ROMSTAGE) &&
!ENV_ROMSTAGE)
return 1;
}
return 0;
}
static void vboot_prepare(void)
{
if (verification_should_run()) {
verstage_main();
car_set_var(vboot_executed, 1);
vb2_save_recovery_reason_vbnv();
} else if (verstage_should_load()) {
struct cbfsf file;
struct prog verstage =
PROG_INIT(PROG_VERSTAGE,
CONFIG_CBFS_PREFIX "/verstage");
printk(BIOS_DEBUG, "VBOOT: Loading verstage.\n");
/* load verstage from RO */
if (cbfs_boot_locate(&file, prog_name(&verstage), NULL))
die("failed to load verstage");
cbfs_file_data(prog_rdev(&verstage), &file);
if (cbfs_prog_stage_load(&verstage))
die("failed to load verstage");
/* verify and select a slot */
prog_run(&verstage);
/* This is not actually possible to hit this condition at
* runtime, but this provides a hint to the compiler for dead
* code elimination below. */
if (!IS_ENABLED(CONFIG_RETURN_FROM_VERSTAGE))
return;
car_set_var(vboot_executed, 1);
}
/*
* Fill in vboot cbmem objects before moving to ramstage so all
* downstream users have access to vboot results. This path only
* applies to platforms employing VBOOT_DYNAMIC_WORK_BUFFER because
* cbmem comes online prior to vboot verification taking place. For
* other platforms the vboot cbmem objects are initialized when
* cbmem comes online.
*/
if (ENV_ROMSTAGE && IS_ENABLED(CONFIG_VBOOT_DYNAMIC_WORK_BUFFER)) {
vb2_store_selected_region();
vboot_fill_handoff();
}
}
static int vboot_locate(struct cbfs_props *props)
{
struct region selected_region;
/* Don't honor vboot results until the vboot logic has run. */
if (!vb2_logic_executed())
return -1;
if (vb2_get_selected_region(&selected_region))
return -1;
props->offset = region_offset(&selected_region);
props->size = region_sz(&selected_region);
return 0;
}
const struct cbfs_locator vboot_locator = {
.name = "VBOOT",
.prepare = vboot_prepare,
.locate = vboot_locate,
};

View File

@ -1,415 +0,0 @@
/*
* This file is part of the coreboot project.
*
* Copyright 2014 Google Inc.
*
* 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 <antirollback.h>
#include <arch/exception.h>
#include <assert.h>
#include <console/console.h>
#include <console/vtxprintf.h>
#include <delay.h>
#include <string.h>
#include <timestamp.h>
#include <vb2_api.h>
#include "../chromeos.h"
#include "misc.h"
/* The max hash size to expect is for SHA512. */
#define VBOOT_MAX_HASH_SIZE VB2_SHA512_DIGEST_SIZE
#define TODO_BLOCK_SIZE 1024
static int is_slot_a(struct vb2_context *ctx)
{
return !(ctx->flags & VB2_CONTEXT_FW_SLOT_B);
}
/* exports */
void vb2ex_printf(const char *func, const char *fmt, ...)
{
va_list args;
printk(BIOS_INFO, "VB2:%s() ", func);
va_start(args, fmt);
do_printk_va_list(BIOS_INFO, fmt, args);
va_end(args);
return;
}
int vb2ex_tpm_clear_owner(struct vb2_context *ctx)
{
uint32_t rv;
printk(BIOS_INFO, "Clearing TPM owner\n");
rv = tpm_clear_and_reenable();
if (rv)
return VB2_ERROR_EX_TPM_CLEAR_OWNER;
return VB2_SUCCESS;
}
int vb2ex_read_resource(struct vb2_context *ctx,
enum vb2_resource_index index,
uint32_t offset,
void *buf,
uint32_t size)
{
struct region_device rdev;
const char *name;
switch (index) {
case VB2_RES_GBB:
name = "GBB";
break;
case VB2_RES_FW_VBLOCK:
if (is_slot_a(ctx))
name = "VBLOCK_A";
else
name = "VBLOCK_B";
break;
default:
return VB2_ERROR_EX_READ_RESOURCE_INDEX;
}
if (vboot_named_region_device(name, &rdev))
return VB2_ERROR_EX_READ_RESOURCE_SIZE;
if (rdev_readat(&rdev, buf, offset, size) != size)
return VB2_ERROR_EX_READ_RESOURCE_SIZE;
return VB2_SUCCESS;
}
/* No-op stubs that can be overridden by SoCs with hardware crypto support. */
__attribute__((weak))
int vb2ex_hwcrypto_digest_init(enum vb2_hash_algorithm hash_alg,
uint32_t data_size)
{
return VB2_ERROR_EX_HWCRYPTO_UNSUPPORTED;
}
__attribute__((weak))
int vb2ex_hwcrypto_digest_extend(const uint8_t *buf, uint32_t size)
{
BUG(); /* Should never get called if init() returned an error. */
return VB2_ERROR_UNKNOWN;
}
__attribute__((weak))
int vb2ex_hwcrypto_digest_finalize(uint8_t *digest, uint32_t digest_size)
{
BUG(); /* Should never get called if init() returned an error. */
return VB2_ERROR_UNKNOWN;
}
static int handle_digest_result(void *slot_hash, size_t slot_hash_sz)
{
int is_resume;
/*
* Nothing to do since resuming on the platform doesn't require
* vboot verification again.
*/
if (!IS_ENABLED(CONFIG_RESUME_PATH_SAME_AS_BOOT))
return 0;
/*
* Assume that if vboot doesn't start in bootblock verified
* RW memory init code is not employed. i.e. memory init code
* lives in RO CBFS.
*/
if (!IS_ENABLED(CONFIG_VBOOT_STARTS_IN_BOOTBLOCK))
return 0;
is_resume = vboot_platform_is_resuming();
if (is_resume > 0) {
uint8_t saved_hash[VBOOT_MAX_HASH_SIZE];
const size_t saved_hash_sz = sizeof(saved_hash);
assert(slot_hash_sz == saved_hash_sz);
printk(BIOS_DEBUG, "Platform is resuming.\n");
if (vboot_retrieve_hash(saved_hash, saved_hash_sz)) {
printk(BIOS_ERR, "Couldn't retrieve saved hash.\n");
return -1;
}
if (memcmp(saved_hash, slot_hash, slot_hash_sz)) {
printk(BIOS_ERR, "Hash mismatch on resume.\n");
return -1;
}
} else if (is_resume < 0)
printk(BIOS_ERR, "Unable to determine if platform resuming.\n");
printk(BIOS_DEBUG, "Saving vboot hash.\n");
/* Always save the hash for the current boot. */
if (vboot_save_hash(slot_hash, slot_hash_sz)) {
printk(BIOS_ERR, "Error saving vboot hash.\n");
/* Though this is an error don't report it up since it could
* lead to a reboot loop. The consequence of this is that
* we will most likely fail resuming because of EC issues or
* the hash digest not matching. */
return 0;
}
return 0;
}
static int hash_body(struct vb2_context *ctx, struct region_device *fw_main)
{
uint64_t load_ts;
uint32_t expected_size;
uint8_t block[TODO_BLOCK_SIZE];
uint8_t hash_digest[VBOOT_MAX_HASH_SIZE];
const size_t hash_digest_sz = sizeof(hash_digest);
size_t block_size = sizeof(block);
size_t offset;
int rv;
/* Clear the full digest so that any hash digests less than the
* max have trailing zeros. */
memset(hash_digest, 0, hash_digest_sz);
/*
* Since loading the firmware and calculating its hash is intertwined,
* we use this little trick to measure them separately and pretend it
* was first loaded and then hashed in one piece with the timestamps.
* (This split won't make sense with memory-mapped media like on x86.)
*/
load_ts = timestamp_get();
timestamp_add(TS_START_HASH_BODY, load_ts);
expected_size = region_device_sz(fw_main);
offset = 0;
/* Start the body hash */
rv = vb2api_init_hash(ctx, VB2_HASH_TAG_FW_BODY, &expected_size);
if (rv)
return rv;
/*
* Honor vboot's RW slot size. The expected size is pulled out of
* the preamble and obtained through vb2api_init_hash() above. By
* creating sub region the RW slot portion of the boot media is
* limited.
*/
if (rdev_chain(fw_main, fw_main, 0, expected_size)) {
printk(BIOS_ERR, "Unable to restrict CBFS size.\n");
return VB2_ERROR_UNKNOWN;
}
/* Extend over the body */
while (expected_size) {
uint64_t temp_ts;
if (block_size > expected_size)
block_size = expected_size;
temp_ts = timestamp_get();
if (rdev_readat(fw_main, block, offset, block_size) < 0)
return VB2_ERROR_UNKNOWN;
load_ts += timestamp_get() - temp_ts;
rv = vb2api_extend_hash(ctx, block, block_size);
if (rv)
return rv;
expected_size -= block_size;
offset += block_size;
}
timestamp_add(TS_DONE_LOADING, load_ts);
timestamp_add_now(TS_DONE_HASHING);
/* Check the result (with RSA signature verification) */
rv = vb2api_check_hash_get_digest(ctx, hash_digest, hash_digest_sz);
if (rv)
return rv;
timestamp_add_now(TS_END_HASH_BODY);
if (handle_digest_result(hash_digest, hash_digest_sz))
return VB2_ERROR_UNKNOWN;
return VB2_SUCCESS;
}
static int locate_firmware(struct vb2_context *ctx,
struct region_device *fw_main)
{
const char *name;
if (is_slot_a(ctx))
name = "FW_MAIN_A";
else
name = "FW_MAIN_B";
return vboot_named_region_device(name, fw_main);
}
/**
* Save non-volatile and/or secure data if needed.
*/
static void save_if_needed(struct vb2_context *ctx)
{
if (ctx->flags & VB2_CONTEXT_NVDATA_CHANGED) {
printk(BIOS_INFO, "Saving nvdata\n");
save_vbnv(ctx->nvdata);
ctx->flags &= ~VB2_CONTEXT_NVDATA_CHANGED;
}
if (ctx->flags & VB2_CONTEXT_SECDATA_CHANGED) {
printk(BIOS_INFO, "Saving secdata\n");
antirollback_write_space_firmware(ctx);
ctx->flags &= ~VB2_CONTEXT_SECDATA_CHANGED;
}
}
static uint32_t extend_pcrs(struct vb2_context *ctx)
{
return tpm_extend_pcr(ctx, 0, BOOT_MODE_PCR) ||
tpm_extend_pcr(ctx, 1, HWID_DIGEST_PCR);
}
/**
* Verify and select the firmware in the RW image
*
* TODO: Avoid loading a stage twice (once in hash_body & again in load_stage).
* when per-stage verification is ready.
*/
void verstage_main(void)
{
struct vb2_context ctx;
struct region_device fw_main;
int rv;
timestamp_add_now(TS_START_VBOOT);
/* Set up context and work buffer */
vb2_init_work_context(&ctx);
/* Read nvdata from a non-volatile storage. */
read_vbnv(ctx.nvdata);
/* Set S3 resume flag if vboot should behave differently when selecting
* which slot to boot. This is only relevant to vboot if the platform
* does verification of memory init and thus must ensure it resumes with
* the same slot that it booted from. */
if (IS_ENABLED(CONFIG_RESUME_PATH_SAME_AS_BOOT) &&
IS_ENABLED(CONFIG_VBOOT_STARTS_IN_BOOTBLOCK) &&
vboot_platform_is_resuming())
ctx.flags |= VB2_CONTEXT_S3_RESUME;
/* Read secdata from TPM. Initialize TPM if secdata not found. We don't
* check the return value here because vb2api_fw_phase1 will catch
* invalid secdata and tell us what to do (=reboot). */
timestamp_add_now(TS_START_TPMINIT);
antirollback_read_space_firmware(&ctx);
timestamp_add_now(TS_END_TPMINIT);
if (!IS_ENABLED(CONFIG_VIRTUAL_DEV_SWITCH) &&
get_developer_mode_switch())
ctx.flags |= VB2_CONTEXT_FORCE_DEVELOPER_MODE;
if (get_recovery_mode_switch()) {
ctx.flags |= VB2_CONTEXT_FORCE_RECOVERY_MODE;
if (IS_ENABLED(CONFIG_VBOOT_DISABLE_DEV_ON_RECOVERY))
ctx.flags |= VB2_DISABLE_DEVELOPER_MODE;
}
if (IS_ENABLED(CONFIG_WIPEOUT_SUPPORTED) && get_wipeout_mode_switch())
ctx.flags |= VB2_CONTEXT_FORCE_WIPEOUT_MODE;
if (IS_ENABLED(CONFIG_LID_SWITCH) && !get_lid_switch())
ctx.flags |= VB2_CONTEXT_NOFAIL_BOOT;
/* Do early init (set up secdata and NVRAM, load GBB) */
printk(BIOS_INFO, "Phase 1\n");
rv = vb2api_fw_phase1(&ctx);
if (rv) {
/*
* If vb2api_fw_phase1 fails, check for return value.
* If it is set to VB2_ERROR_API_PHASE1_RECOVERY, then continue
* into recovery mode.
* For any other error code, save context if needed and reboot.
*/
if (rv == VB2_ERROR_API_PHASE1_RECOVERY) {
printk(BIOS_INFO, "Recovery requested (%x)\n", rv);
save_if_needed(&ctx);
extend_pcrs(&ctx); /* ignore failures */
timestamp_add_now(TS_END_VBOOT);
return;
}
printk(BIOS_INFO, "Reboot reqested (%x)\n", rv);
save_if_needed(&ctx);
vboot_reboot();
}
/* Determine which firmware slot to boot (based on NVRAM) */
printk(BIOS_INFO, "Phase 2\n");
rv = vb2api_fw_phase2(&ctx);
if (rv) {
printk(BIOS_INFO, "Reboot requested (%x)\n", rv);
save_if_needed(&ctx);
vboot_reboot();
}
/* Try that slot (verify its keyblock and preamble) */
printk(BIOS_INFO, "Phase 3\n");
timestamp_add_now(TS_START_VERIFY_SLOT);
rv = vb2api_fw_phase3(&ctx);
timestamp_add_now(TS_END_VERIFY_SLOT);
if (rv) {
printk(BIOS_INFO, "Reboot requested (%x)\n", rv);
save_if_needed(&ctx);
vboot_reboot();
}
printk(BIOS_INFO, "Phase 4\n");
rv = locate_firmware(&ctx, &fw_main);
if (rv)
die("Failed to read FMAP to locate firmware");
rv = hash_body(&ctx, &fw_main);
save_if_needed(&ctx);
if (rv) {
printk(BIOS_INFO, "Reboot requested (%x)\n", rv);
vboot_reboot();
}
rv = extend_pcrs(&ctx);
if (rv) {
printk(BIOS_WARNING, "Failed to extend TPM PCRs (%#x)\n", rv);
vb2api_fail(&ctx, VB2_RECOVERY_RO_TPM_U_ERROR, rv);
save_if_needed(&ctx);
vboot_reboot();
}
/* Lock TPM */
rv = antirollback_lock_space_firmware();
if (rv) {
printk(BIOS_INFO, "Failed to lock TPM (%x)\n", rv);
vb2api_fail(&ctx, VB2_RECOVERY_RO_TPM_L_ERROR, 0);
save_if_needed(&ctx);
vboot_reboot();
}
printk(BIOS_INFO, "Slot %c is selected\n", is_slot_a(&ctx) ? 'A' : 'B');
vb2_set_selected_region(region_device_region(&fw_main));
timestamp_add_now(TS_END_VBOOT);
}

View File

@ -1,44 +0,0 @@
/*
* This file is part of the coreboot project.
*
* Copyright 2015 Google Inc.
*
* 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 <arch/exception.h>
#include <arch/hlt.h>
#include <console/console.h>
#include <program_loading.h>
#include "../vboot_common.h"
void __attribute__((weak)) verstage_mainboard_init(void)
{
/* Default empty implementation. */
}
void verstage(void)
{
console_init();
exception_init();
verstage_mainboard_init();
if (IS_ENABLED(CONFIG_RETURN_FROM_VERSTAGE)) {
verstage_main();
} else {
run_romstage();
hlt();
}
}
#if !IS_ENABLED(CONFIG_CHIPSET_PROVIDES_VERSTAGE_MAIN_SYMBOL)
/* This is for boards that rely on main() for an entry point of a stage. */
void main(void) __attribute__((alias ("verstage")));
#endif

View File

@ -1,112 +0,0 @@
/*
* This file is part of the coreboot project.
*
* Copyright (C) 2014 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 <boot/coreboot_tables.h>
#include <boot_device.h>
#include <cbmem.h>
#include <console/cbmem_console.h>
#include <console/console.h>
#include <fmap.h>
#include <reset.h>
#include <rules.h>
#include <stddef.h>
#include <string.h>
#include "chromeos.h"
#include "vboot_common.h"
int vboot_named_region_device(const char *name, struct region_device *rdev)
{
return fmap_locate_area_as_rdev(name, rdev);
}
/* ========================== VBOOT HANDOFF APIs =========================== */
int vboot_get_handoff_info(void **addr, uint32_t *size)
{
/*
* vboot_handoff is present only after cbmem comes online. If we are in
* pre-ram stage, then bail out early.
*/
if (ENV_BOOTBLOCK ||
(ENV_VERSTAGE && IS_ENABLED(CONFIG_VBOOT_STARTS_IN_BOOTBLOCK)))
return -1;
struct vboot_handoff *vboot_handoff;
vboot_handoff = cbmem_find(CBMEM_ID_VBOOT_HANDOFF);
if (vboot_handoff == NULL)
return -1;
*addr = vboot_handoff;
if (size)
*size = sizeof(*vboot_handoff);
return 0;
}
static int vboot_get_handoff_flag(uint32_t flag)
{
struct vboot_handoff *vbho;
/*
* If vboot_handoff cannot be found, return default value of flag as 0.
*/
if (vboot_get_handoff_info((void **)&vbho, NULL))
return 0;
return !!(vbho->init_params.out_flags & flag);
}
int vboot_handoff_skip_display_init(void)
{
return !vboot_get_handoff_flag(VB_INIT_OUT_ENABLE_DISPLAY);
}
int vboot_handoff_check_developer_flag(void)
{
return vboot_get_handoff_flag(VB_INIT_OUT_ENABLE_DEVELOPER);
}
int vboot_handoff_check_recovery_flag(void)
{
return vboot_get_handoff_flag(VB_INIT_OUT_ENABLE_RECOVERY);
}
int vboot_handoff_get_recovery_reason(void)
{
struct vboot_handoff *vbho;
VbSharedDataHeader *sd;
if (vboot_get_handoff_info((void **)&vbho, NULL))
return 0;
sd = (VbSharedDataHeader *)vbho->shared_data;
return sd->recovery_reason;
}
/* ============================ VBOOT REBOOT ============================== */
void __attribute__((weak)) vboot_platform_prepare_reboot(void)
{
}
void vboot_reboot(void)
{
if (IS_ENABLED(CONFIG_CONSOLE_CBMEM_DUMP_TO_UART))
cbmem_dump_console();
vboot_platform_prepare_reboot();
hard_reset();
die("failed to reboot");
}

View File

@ -1,106 +0,0 @@
/*
* This file is part of the coreboot project.
*
* Copyright (C) 2014 Google, Inc.
*
* 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.
*/
#ifndef VBOOT_COMMON_H
#define VBOOT_COMMON_H
#include <commonlib/region.h>
#include <stdint.h>
#include <vboot_api.h>
#include <vboot_struct.h>
#include "chromeos.h"
/* Locate vboot area by name. Returns 0 on success and -1 on error. */
int vboot_named_region_device(const char *name, struct region_device *rdev);
/*
* Function to check if there is a request to enter recovery mode. Returns
* reason code if request to enter recovery mode is present, otherwise 0.
*/
int vboot_check_recovery_request(void);
/* ========================== VBOOT HANDOFF APIs =========================== */
/*
* The vboot_handoff structure contains the data to be consumed by downstream
* firmware after firmware selection has been completed. Namely it provides
* vboot shared data as well as the flags from VbInit.
*/
struct vboot_handoff {
VbInitParams init_params;
uint32_t selected_firmware;
char shared_data[VB_SHARED_DATA_MIN_SIZE];
} __attribute__((packed));
/*
* vboot_get_handoff_info returns pointer to the vboot_handoff structure if
* available. vboot_handoff is available only after CBMEM comes online. If size
* is not NULL, size of the vboot_handoff structure is returned in it.
* Returns 0 on success and -1 on error.
*/
int vboot_get_handoff_info(void **addr, uint32_t *size);
/*
* The following functions read vboot_handoff structure to obtain requested
* information. If vboot handoff is not available, 0 is returned by default.
* If vboot handoff is available:
* Returns 1 for flag if true
* Returns 0 for flag if false
* Returns value read for other fields
*/
int vboot_handoff_skip_display_init(void);
int vboot_handoff_check_recovery_flag(void);
int vboot_handoff_check_developer_flag(void);
int vboot_handoff_get_recovery_reason(void);
/* ============================ VBOOT REBOOT ============================== */
/*
* vboot_reboot handles the reboot requests made by vboot_reference library. It
* allows the platform to run any preparation steps before the reboot and then
* does a hard reset.
*/
void vboot_reboot(void);
/* Allow the platform to do any clean up work when vboot requests a reboot. */
void vboot_platform_prepare_reboot(void);
/* ============================ VBOOT RESUME ============================== */
/*
* Save the provided hash digest to a secure location to check against in
* the resume path. Returns 0 on success, < 0 on error.
*/
int vboot_save_hash(void *digest, size_t digest_size);
/*
* Retrieve the previously saved hash digest. Returns 0 on success,
* < 0 on error.
*/
int vboot_retrieve_hash(void *digest, size_t digest_size);
/*
* Determine if the platform is resuming from suspend. Returns 0 when
* not resuming, > 0 if resuming, and < 0 on error.
*/
int vboot_platform_is_resuming(void);
/* ============================= VERSTAGE ================================== */
/*
* Main logic for verified boot. verstage() is the stage entry point
* while the verstage_main() is just the core logic.
*/
void verstage_main(void);
void verstage(void);
void verstage_mainboard_init(void);
#endif /* VBOOT_COMMON_H */