security/vboot: Add vboot callbacks to support EC software sync
Use the new functions introduced into the EC driver to support performing EC software sync via vboot callbacks. NOTE: This patch assumes that the EC image is added to CBFS uncompressed. Streaming decompression of the image will be added in a future patch. Also adds a new Kconfig option VBOOT_EARLY_EC_SYNC. The new Kconfig option compiles EC software sync into romstage, dependent upon having a CrOS EC. BUG=b:112198832 BRANCH=none TEST=Successful EC software sync Change-Id: I9b1458a45ab3ed5623af50f78036c4f88461b226 Signed-off-by: Tim Wawrzynczak <twawrzynczak@chromium.org> Reviewed-on: https://review.coreboot.org/c/coreboot/+/36208 Reviewed-by: Julius Werner <jwerner@chromium.org> Tested-by: build bot (Jenkins) <no-reply@coreboot.org>
This commit is contained in:
parent
fe338e2319
commit
d6fc557b93
|
@ -242,6 +242,18 @@ config VBOOT_ENABLE_CBFS_FALLBACK
|
|||
When this option is enabled cbfs_boot_locate will look for a file in the RO
|
||||
(COREBOOT) region if it isn't available in the active RW region.
|
||||
|
||||
config VBOOT_EARLY_EC_SYNC
|
||||
bool
|
||||
default n
|
||||
depends on EC_GOOGLE_CHROMEEC
|
||||
help
|
||||
Enables CrOS EC software sync in romstage, before memory training
|
||||
runs. This is useful mainly as a way to achieve full USB-PD
|
||||
negotiation earlier in the boot flow, as the EC will only do this once
|
||||
it has made the sysjump to its RW firmware. It should not
|
||||
significantly impact boot time, as this operation will be performed
|
||||
later in the boot flow if it is disabled here.
|
||||
|
||||
menu "GBB configuration"
|
||||
|
||||
config GBB_HWID
|
||||
|
|
|
@ -37,6 +37,8 @@ verstage-y += vbnv.c
|
|||
romstage-y += vbnv.c
|
||||
ramstage-y += vbnv.c
|
||||
|
||||
romstage-$(CONFIG_VBOOT_EARLY_EC_SYNC) += ec_sync.c
|
||||
|
||||
bootblock-$(CONFIG_VBOOT_VBNV_CMOS) += vbnv_cmos.c
|
||||
verstage-$(CONFIG_VBOOT_VBNV_CMOS) += vbnv_cmos.c
|
||||
romstage-$(CONFIG_VBOOT_VBNV_CMOS) += vbnv_cmos.c
|
||||
|
|
|
@ -0,0 +1,549 @@
|
|||
/*
|
||||
* This file is part of the coreboot project.
|
||||
*
|
||||
* 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 <console/console.h>
|
||||
#include <delay.h>
|
||||
#include <ec/google/chromeec/ec.h>
|
||||
#include <security/vboot/misc.h>
|
||||
#include <security/vboot/vbnv.h>
|
||||
#include <security/vboot/vboot_common.h>
|
||||
#include <timer.h>
|
||||
#include <vb2_api.h>
|
||||
|
||||
#define _EC_FILENAME(select, suffix) \
|
||||
(select == VB_SELECT_FIRMWARE_READONLY ? "ecro" suffix : "ecrw" suffix)
|
||||
#define EC_IMAGE_FILENAME(select) _EC_FILENAME(select, "")
|
||||
#define EC_HASH_FILENAME(select) _EC_FILENAME(select, ".hash")
|
||||
|
||||
/* Wait 10 ms between attempts to check if EC's hash is ready */
|
||||
#define CROS_EC_HASH_CHECK_DELAY_MS 10
|
||||
/* Give the EC 2 seconds to finish calculating its hash */
|
||||
#define CROS_EC_HASH_TIMEOUT_MS 2000
|
||||
|
||||
/* Wait 3 seconds after software sync for EC to clear the limit power flag. */
|
||||
#define LIMIT_POWER_WAIT_TIMEOUT_MS 3000
|
||||
/* Check the limit power flag every 10 ms while waiting. */
|
||||
#define LIMIT_POWER_POLL_SLEEP_MS 10
|
||||
|
||||
/* Wait 3 seconds for EC to sysjump to RW */
|
||||
#define CROS_EC_SYSJUMP_TIMEOUT_MS 3000
|
||||
|
||||
/*
|
||||
* The external API for EC software sync. This function calls into
|
||||
* vboot, which kicks off the process. Vboot runs the verified boot
|
||||
* logic, and requires the client program to provide callbacks which
|
||||
* perform the work.
|
||||
*/
|
||||
void vboot_sync_ec(void)
|
||||
{
|
||||
vb2_error_t retval = VB2_SUCCESS;
|
||||
struct vb2_context *ctx;
|
||||
|
||||
ctx = vboot_get_context();
|
||||
ctx->flags |= VB2_CONTEXT_EC_SYNC_SUPPORTED;
|
||||
|
||||
retval = vb2api_ec_sync(ctx);
|
||||
vboot_save_nvdata_only(ctx);
|
||||
|
||||
if (retval != VB2_SUCCESS) {
|
||||
printk(BIOS_ERR, "EC software sync failed (%#x), rebooting\n", retval);
|
||||
vboot_reboot();
|
||||
}
|
||||
}
|
||||
|
||||
/* Convert firmware image type into a flash offset */
|
||||
static uint32_t get_vboot_hash_offset(enum vb2_firmware_selection select)
|
||||
{
|
||||
switch (select) {
|
||||
case VB_SELECT_FIRMWARE_READONLY:
|
||||
return EC_VBOOT_HASH_OFFSET_RO;
|
||||
case VB_SELECT_FIRMWARE_EC_UPDATE:
|
||||
return EC_VBOOT_HASH_OFFSET_UPDATE;
|
||||
default:
|
||||
return EC_VBOOT_HASH_OFFSET_ACTIVE;
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
* Asks the EC to calculate a hash of the specified firmware image, and
|
||||
* returns the information in **hash and *hash_size.
|
||||
*/
|
||||
static vb2_error_t ec_hash_image(enum vb2_firmware_selection select,
|
||||
const uint8_t **hash, int *hash_size)
|
||||
{
|
||||
static struct ec_response_vboot_hash resp;
|
||||
uint32_t hash_offset;
|
||||
int recalc_requested = 0;
|
||||
struct stopwatch sw;
|
||||
|
||||
hash_offset = get_vboot_hash_offset(select);
|
||||
|
||||
stopwatch_init_msecs_expire(&sw, CROS_EC_HASH_TIMEOUT_MS);
|
||||
do {
|
||||
if (google_chromeec_get_vboot_hash(hash_offset, &resp))
|
||||
return VB2_ERROR_UNKNOWN;
|
||||
|
||||
switch (resp.status) {
|
||||
case EC_VBOOT_HASH_STATUS_NONE:
|
||||
/*
|
||||
* There is no hash available right now.
|
||||
* Request a recalc if it hasn't been done yet.
|
||||
*/
|
||||
if (recalc_requested)
|
||||
break;
|
||||
|
||||
printk(BIOS_WARNING,
|
||||
"%s: No valid hash (status=%d size=%d). "
|
||||
"Computing...\n", __func__, resp.status,
|
||||
resp.size);
|
||||
|
||||
if (google_chromeec_start_vboot_hash(
|
||||
EC_VBOOT_HASH_TYPE_SHA256, hash_offset, &resp))
|
||||
return VB2_ERROR_UNKNOWN;
|
||||
|
||||
recalc_requested = 1;
|
||||
|
||||
/*
|
||||
* Expect status to be busy since we just sent
|
||||
* a recalc request.
|
||||
*/
|
||||
resp.status = EC_VBOOT_HASH_STATUS_BUSY;
|
||||
|
||||
/* Hash just started calculating, let it go for a bit */
|
||||
mdelay(CROS_EC_HASH_CHECK_DELAY_MS);
|
||||
break;
|
||||
|
||||
case EC_VBOOT_HASH_STATUS_BUSY:
|
||||
/* Hash is still calculating. */
|
||||
mdelay(CROS_EC_HASH_CHECK_DELAY_MS);
|
||||
break;
|
||||
|
||||
case EC_VBOOT_HASH_STATUS_DONE: /* intentional fallthrough */
|
||||
default:
|
||||
/* Hash is ready! */
|
||||
break;
|
||||
}
|
||||
} while (resp.status == EC_VBOOT_HASH_STATUS_BUSY &&
|
||||
!stopwatch_expired(&sw));
|
||||
|
||||
if (resp.status != EC_VBOOT_HASH_STATUS_DONE) {
|
||||
printk(BIOS_ERR, "%s: Hash status not done: %d\n", __func__,
|
||||
resp.status);
|
||||
return VB2_ERROR_UNKNOWN;
|
||||
}
|
||||
if (resp.hash_type != EC_VBOOT_HASH_TYPE_SHA256) {
|
||||
printk(BIOS_ERR, "EC hash was the wrong type.\n");
|
||||
return VB2_ERROR_UNKNOWN;
|
||||
}
|
||||
|
||||
printk(BIOS_INFO, "EC took %luus to calculate image hash\n",
|
||||
stopwatch_duration_usecs(&sw));
|
||||
|
||||
*hash = resp.hash_digest;
|
||||
*hash_size = resp.digest_size;
|
||||
|
||||
return VB2_SUCCESS;
|
||||
}
|
||||
|
||||
/*
|
||||
* Asks the EC to protect or unprotect the specified flash region.
|
||||
*/
|
||||
static vb2_error_t ec_protect_flash(enum vb2_firmware_selection select, int enable)
|
||||
{
|
||||
struct ec_response_flash_protect resp;
|
||||
uint32_t protected_region = EC_FLASH_PROTECT_ALL_NOW;
|
||||
const uint32_t mask = EC_FLASH_PROTECT_ALL_NOW | EC_FLASH_PROTECT_ALL_AT_BOOT;
|
||||
|
||||
if (select == VB_SELECT_FIRMWARE_READONLY)
|
||||
protected_region = EC_FLASH_PROTECT_RO_NOW;
|
||||
|
||||
if (google_chromeec_flash_protect(mask, enable ? mask : 0, &resp) != 0)
|
||||
return VB2_ERROR_UNKNOWN;
|
||||
|
||||
if (!enable) {
|
||||
/* If protection is still enabled, need reboot */
|
||||
if (resp.flags & protected_region)
|
||||
return VBERROR_EC_REBOOT_TO_RO_REQUIRED;
|
||||
|
||||
return VB2_SUCCESS;
|
||||
}
|
||||
|
||||
/*
|
||||
* If write protect and ro-at-boot aren't both asserted, don't expect
|
||||
* protection enabled.
|
||||
*/
|
||||
if ((~resp.flags) & (EC_FLASH_PROTECT_GPIO_ASSERTED |
|
||||
EC_FLASH_PROTECT_RO_AT_BOOT))
|
||||
return VB2_SUCCESS;
|
||||
|
||||
/* If flash is protected now, success */
|
||||
if (resp.flags & EC_FLASH_PROTECT_ALL_NOW)
|
||||
return VB2_SUCCESS;
|
||||
|
||||
/* If RW will be protected at boot but not now, need a reboot */
|
||||
if (resp.flags & EC_FLASH_PROTECT_ALL_AT_BOOT)
|
||||
return VBERROR_EC_REBOOT_TO_RO_REQUIRED;
|
||||
|
||||
/* Otherwise, it's an error */
|
||||
return VB2_ERROR_UNKNOWN;
|
||||
}
|
||||
|
||||
/* Convert a firmware image type to an EC flash region */
|
||||
static enum ec_flash_region vboot_to_ec_region(enum vb2_firmware_selection select)
|
||||
{
|
||||
switch (select) {
|
||||
case VB_SELECT_FIRMWARE_READONLY:
|
||||
return EC_FLASH_REGION_WP_RO;
|
||||
case VB_SELECT_FIRMWARE_EC_UPDATE:
|
||||
return EC_FLASH_REGION_UPDATE;
|
||||
default:
|
||||
return EC_FLASH_REGION_ACTIVE;
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
* Read the EC's burst size bytes at a time from CBFS, and then send
|
||||
* the chunk to the EC for it to write into its flash.
|
||||
*/
|
||||
static vb2_error_t ec_flash_write(struct region_device *image_region,
|
||||
uint32_t region_offset, int image_size)
|
||||
{
|
||||
struct ec_response_get_protocol_info resp_proto;
|
||||
struct ec_response_flash_info resp_flash;
|
||||
ssize_t pdata_max_size;
|
||||
ssize_t burst;
|
||||
uint8_t *file_buf;
|
||||
struct ec_params_flash_write *params;
|
||||
uint32_t end, off;
|
||||
|
||||
/*
|
||||
* Get EC's protocol information, so that we can figure out how much
|
||||
* data can be sent in one message.
|
||||
*/
|
||||
if (google_chromeec_get_protocol_info(&resp_proto)) {
|
||||
printk(BIOS_ERR, "Failed to get EC protocol information; "
|
||||
"skipping flash write\n");
|
||||
return VB2_ERROR_UNKNOWN;
|
||||
}
|
||||
|
||||
/*
|
||||
* Determine burst size. This must be a multiple of the write block
|
||||
* size, and must also fit into the host parameter buffer.
|
||||
*/
|
||||
if (google_chromeec_flash_info(&resp_flash)) {
|
||||
printk(BIOS_ERR, "Failed to get EC flash information; "
|
||||
"skipping flash write\n");
|
||||
return VB2_ERROR_UNKNOWN;
|
||||
}
|
||||
|
||||
/* Limit the potential buffer stack allocation to 1K */
|
||||
pdata_max_size = MIN(1024, resp_proto.max_request_packet_size -
|
||||
sizeof(struct ec_host_request));
|
||||
|
||||
/* Round burst to a multiple of the flash write block size */
|
||||
burst = pdata_max_size - sizeof(*params);
|
||||
burst = (burst / resp_flash.write_block_size) *
|
||||
resp_flash.write_block_size;
|
||||
|
||||
/* Buffer too small */
|
||||
if (burst <= 0) {
|
||||
printk(BIOS_ERR, "Flash write buffer too small! skipping "
|
||||
"flash write\n");
|
||||
return VB2_ERROR_UNKNOWN;
|
||||
}
|
||||
|
||||
/* Allocate buffer on the stack */
|
||||
params = alloca(burst + sizeof(*params));
|
||||
|
||||
/* Fill up the buffer */
|
||||
end = region_offset + image_size;
|
||||
for (off = region_offset; off < end; off += burst) {
|
||||
uint32_t todo = MIN(end - off, burst);
|
||||
uint32_t xfer_size = todo + sizeof(*params);
|
||||
|
||||
/* Map 'todo' bytes into memory */
|
||||
file_buf = rdev_mmap(image_region, off - region_offset, todo);
|
||||
if (file_buf == NULL)
|
||||
return VB2_ERROR_UNKNOWN;
|
||||
|
||||
params->offset = off;
|
||||
params->size = todo;
|
||||
|
||||
/* Read todo bytes into the buffer */
|
||||
memcpy(params + 1, file_buf, todo);
|
||||
|
||||
if (rdev_munmap(image_region, file_buf))
|
||||
return VB2_ERROR_UNKNOWN;
|
||||
|
||||
/* Make sure to add back in the size of the parameters */
|
||||
if (google_chromeec_flash_write_block(
|
||||
(const uint8_t *)params, xfer_size)) {
|
||||
printk(BIOS_ERR, "EC failed flash write command, "
|
||||
"relative offset %u!\n", off - region_offset);
|
||||
return VB2_ERROR_UNKNOWN;
|
||||
}
|
||||
}
|
||||
|
||||
return VB2_SUCCESS;
|
||||
}
|
||||
|
||||
/*
|
||||
* The logic for updating an EC firmware image.
|
||||
*/
|
||||
static vb2_error_t ec_update_image(enum vb2_firmware_selection select)
|
||||
{
|
||||
uint32_t region_offset, region_size;
|
||||
enum ec_flash_region region;
|
||||
vb2_error_t rv;
|
||||
size_t image_size;
|
||||
struct cbfsf fh;
|
||||
const char *filename;
|
||||
struct region_device image_region;
|
||||
|
||||
/* Un-protect the flash region */
|
||||
rv = ec_protect_flash(select, 0);
|
||||
if (rv != VB2_SUCCESS)
|
||||
return rv;
|
||||
|
||||
/* Convert vboot region into an EC region */
|
||||
region = vboot_to_ec_region(select);
|
||||
|
||||
/* Get information about the flash region */
|
||||
if (google_chromeec_flash_region_info(region, ®ion_offset,
|
||||
®ion_size))
|
||||
return VB2_ERROR_UNKNOWN;
|
||||
|
||||
/* Locate the CBFS file */
|
||||
filename = EC_IMAGE_FILENAME(select);
|
||||
if (cbfs_boot_locate(&fh, filename, NULL))
|
||||
return VB2_ERROR_UNKNOWN;
|
||||
|
||||
/* Get the file size and the region struct */
|
||||
image_size = region_device_sz(&fh.data);
|
||||
cbfs_file_data(&image_region, &fh);
|
||||
|
||||
/* Bail if the image is too large */
|
||||
if (image_size > region_size)
|
||||
return VB2_ERROR_INVALID_PARAMETER;
|
||||
|
||||
/* Erase the region */
|
||||
if (google_chromeec_flash_erase(region_offset, region_size))
|
||||
return VB2_ERROR_UNKNOWN;
|
||||
|
||||
/* Write the image into the region */
|
||||
if (ec_flash_write(&image_region, region_offset, image_size))
|
||||
return VB2_ERROR_UNKNOWN;
|
||||
|
||||
/* Verify the image */
|
||||
if (google_chromeec_efs_verify(region))
|
||||
return VB2_ERROR_UNKNOWN;
|
||||
|
||||
return VB2_SUCCESS;
|
||||
}
|
||||
|
||||
static vb2_error_t ec_get_expected_hash(enum vb2_firmware_selection select,
|
||||
const uint8_t **hash,
|
||||
int *hash_size)
|
||||
{
|
||||
size_t size;
|
||||
const char *filename = EC_HASH_FILENAME(select);
|
||||
const uint8_t *file = cbfs_boot_map_with_leak(filename, CBFS_TYPE_RAW, &size);
|
||||
|
||||
if (file == NULL)
|
||||
return VB2_ERROR_UNKNOWN;
|
||||
|
||||
*hash = file;
|
||||
*hash_size = (int)size;
|
||||
|
||||
return VB2_SUCCESS;
|
||||
}
|
||||
|
||||
/***********************************************************************
|
||||
* Vboot Callbacks
|
||||
***********************************************************************/
|
||||
|
||||
/*
|
||||
* Unsupported.
|
||||
*
|
||||
* coreboot does not support the graphics initialization needed to
|
||||
* display the vboot "wait" screens, etc., because the use case for
|
||||
* supporting software sync early in the boot flow is to be able to
|
||||
* quickly update the EC and/or sysjump to RW earlier so that USB-PD
|
||||
* power (> 15 W) can be negotiated for earlier.
|
||||
*/
|
||||
vb2_error_t VbExDisplayScreen(uint32_t screen_type, uint32_t locale,
|
||||
const VbScreenData *data)
|
||||
{
|
||||
return VB2_ERROR_UNKNOWN;
|
||||
}
|
||||
|
||||
/*
|
||||
* Write opaque data into NV storage region.
|
||||
*/
|
||||
vb2_error_t VbExNvStorageWrite(const uint8_t *buf)
|
||||
{
|
||||
save_vbnv(buf);
|
||||
return VB2_SUCCESS;
|
||||
}
|
||||
|
||||
/*
|
||||
* Report whether the EC is in RW or not.
|
||||
*/
|
||||
vb2_error_t vb2ex_ec_running_rw(int *in_rw)
|
||||
{
|
||||
*in_rw = !google_ec_running_ro();
|
||||
return VB2_SUCCESS;
|
||||
}
|
||||
|
||||
/*
|
||||
* Callback for when Vboot is finished.
|
||||
*/
|
||||
vb2_error_t vb2ex_ec_vboot_done(struct vb2_context *ctx)
|
||||
{
|
||||
int limit_power = 0;
|
||||
bool message_printed = false;
|
||||
struct stopwatch sw;
|
||||
vb2_error_t rv = VB2_SUCCESS;
|
||||
int in_recovery = !!(ctx->flags & VB2_CONTEXT_RECOVERY_MODE);
|
||||
|
||||
/*
|
||||
* Do not wait for the limit power flag to be cleared in
|
||||
* recovery mode since we didn't just sysjump.
|
||||
*/
|
||||
if (in_recovery)
|
||||
return VB2_SUCCESS;
|
||||
|
||||
stopwatch_init_msecs_expire(&sw, LIMIT_POWER_WAIT_TIMEOUT_MS);
|
||||
|
||||
/* Ensure we have enough power to continue booting */
|
||||
while (1) {
|
||||
if (google_chromeec_read_limit_power_request(&limit_power)) {
|
||||
printk(BIOS_ERR, "Failed to check EC limit power"
|
||||
"flag.\n");
|
||||
rv = VB2_ERROR_UNKNOWN;
|
||||
break;
|
||||
}
|
||||
|
||||
if (!limit_power || stopwatch_expired(&sw))
|
||||
break;
|
||||
|
||||
if (!message_printed) {
|
||||
printk(BIOS_SPEW,
|
||||
"Waiting for EC to clear limit power flag.\n");
|
||||
message_printed = true;
|
||||
}
|
||||
|
||||
mdelay(LIMIT_POWER_POLL_SLEEP_MS);
|
||||
}
|
||||
|
||||
if (limit_power) {
|
||||
printk(BIOS_INFO,
|
||||
"EC requests limited power usage. Request shutdown.\n");
|
||||
rv = VBERROR_SHUTDOWN_REQUESTED;
|
||||
} else {
|
||||
printk(BIOS_INFO, "Waited %luus to clear limit power flag.\n",
|
||||
stopwatch_duration_usecs(&sw));
|
||||
}
|
||||
|
||||
return rv;
|
||||
}
|
||||
|
||||
/*
|
||||
* Support battery cutoff if required.
|
||||
*/
|
||||
vb2_error_t vb2ex_ec_battery_cutoff(void)
|
||||
{
|
||||
if (google_chromeec_battery_cutoff(EC_BATTERY_CUTOFF_FLAG_AT_SHUTDOWN))
|
||||
return VB2_ERROR_UNKNOWN;
|
||||
|
||||
return VB2_SUCCESS;
|
||||
}
|
||||
|
||||
/*
|
||||
* Vboot callback for calculating an EC image's hash.
|
||||
*/
|
||||
vb2_error_t vb2ex_ec_hash_image(enum vb2_firmware_selection select,
|
||||
const uint8_t **hash, int *hash_size)
|
||||
{
|
||||
return ec_hash_image(select, hash, hash_size);
|
||||
}
|
||||
|
||||
/*
|
||||
* Vboot callback for EC flash protection.
|
||||
*/
|
||||
vb2_error_t vb2ex_ec_protect(enum vb2_firmware_selection select)
|
||||
{
|
||||
return ec_protect_flash(select, 1);
|
||||
}
|
||||
|
||||
/*
|
||||
* Get hash for image.
|
||||
*/
|
||||
vb2_error_t vb2ex_ec_get_expected_image_hash(enum vb2_firmware_selection select,
|
||||
const uint8_t **hash,
|
||||
int *hash_size)
|
||||
{
|
||||
return ec_get_expected_hash(select, hash, hash_size);
|
||||
}
|
||||
|
||||
/*
|
||||
* Disable further sysjumps (i.e., stay in RW until next reboot)
|
||||
*/
|
||||
vb2_error_t vb2ex_ec_disable_jump(void)
|
||||
{
|
||||
if (google_chromeec_reboot(0, EC_REBOOT_DISABLE_JUMP, 0))
|
||||
return VB2_ERROR_UNKNOWN;
|
||||
|
||||
return VB2_SUCCESS;
|
||||
}
|
||||
|
||||
/*
|
||||
* Update EC image.
|
||||
*/
|
||||
vb2_error_t vb2ex_ec_update_image(enum vb2_firmware_selection select)
|
||||
{
|
||||
return ec_update_image(select);
|
||||
}
|
||||
|
||||
/*
|
||||
* Vboot callback for commanding EC to sysjump to RW.
|
||||
*/
|
||||
vb2_error_t vb2ex_ec_jump_to_rw(void)
|
||||
{
|
||||
struct stopwatch sw;
|
||||
|
||||
if (google_chromeec_reboot(0, EC_REBOOT_JUMP_RW, 0))
|
||||
return VB2_ERROR_UNKNOWN;
|
||||
|
||||
/* Give the EC 3 seconds to sysjump */
|
||||
stopwatch_init_msecs_expire(&sw, CROS_EC_SYSJUMP_TIMEOUT_MS);
|
||||
|
||||
/* Default delay to wait after EC reboot */
|
||||
mdelay(50);
|
||||
while (google_chromeec_hello()) {
|
||||
if (stopwatch_expired(&sw)) {
|
||||
printk(BIOS_ERR, "EC did not return from reboot after %luus\n",
|
||||
stopwatch_duration_usecs(&sw));
|
||||
return VB2_ERROR_UNKNOWN;
|
||||
}
|
||||
|
||||
mdelay(5);
|
||||
}
|
||||
|
||||
printk(BIOS_INFO, "\nEC returned from reboot after %luus\n",
|
||||
stopwatch_duration_usecs(&sw));
|
||||
|
||||
return VB2_SUCCESS;
|
||||
}
|
|
@ -80,4 +80,13 @@ static inline int vboot_can_enable_udc(void) { return 1; }
|
|||
static inline void vboot_run_logic(void) {}
|
||||
#endif
|
||||
|
||||
void vboot_save_nvdata_only(struct vb2_context *ctx);
|
||||
void vboot_save_data(struct vb2_context *ctx);
|
||||
|
||||
/*
|
||||
* The API for performing EC software sync. Does not support
|
||||
* "slow" updates or Auxiliary FW sync.
|
||||
*/
|
||||
void vboot_sync_ec(void);
|
||||
|
||||
#endif /* __VBOOT_VBOOT_COMMON_H__ */
|
||||
|
|
|
@ -251,21 +251,27 @@ static vb2_error_t hash_body(struct vb2_context *ctx,
|
|||
return VB2_SUCCESS;
|
||||
}
|
||||
|
||||
/**
|
||||
* Save non-volatile and/or secure data if needed.
|
||||
*/
|
||||
static void save_if_needed(struct vb2_context *ctx)
|
||||
void vboot_save_nvdata_only(struct vb2_context *ctx)
|
||||
{
|
||||
assert(!(ctx->flags & (VB2_CONTEXT_SECDATA_FIRMWARE_CHANGED |
|
||||
VB2_CONTEXT_SECDATA_KERNEL_CHANGED)));
|
||||
|
||||
if (ctx->flags & VB2_CONTEXT_NVDATA_CHANGED) {
|
||||
printk(BIOS_INFO, "Saving nvdata\n");
|
||||
save_vbnv(ctx->nvdata);
|
||||
ctx->flags &= ~VB2_CONTEXT_NVDATA_CHANGED;
|
||||
}
|
||||
}
|
||||
|
||||
void vboot_save_data(struct vb2_context *ctx)
|
||||
{
|
||||
if (ctx->flags & VB2_CONTEXT_SECDATA_CHANGED) {
|
||||
printk(BIOS_INFO, "Saving secdata\n");
|
||||
antirollback_write_space_firmware(ctx);
|
||||
ctx->flags &= ~VB2_CONTEXT_SECDATA_CHANGED;
|
||||
}
|
||||
|
||||
vboot_save_nvdata_only(ctx);
|
||||
}
|
||||
|
||||
static uint32_t extend_pcrs(struct vb2_context *ctx)
|
||||
|
@ -368,13 +374,13 @@ void verstage_main(void)
|
|||
*/
|
||||
if (rv == VB2_ERROR_API_PHASE1_RECOVERY) {
|
||||
printk(BIOS_INFO, "Recovery requested (%x)\n", rv);
|
||||
save_if_needed(ctx);
|
||||
vboot_save_data(ctx);
|
||||
extend_pcrs(ctx); /* ignore failures */
|
||||
goto verstage_main_exit;
|
||||
}
|
||||
|
||||
printk(BIOS_INFO, "Reboot requested (%x)\n", rv);
|
||||
save_if_needed(ctx);
|
||||
vboot_save_data(ctx);
|
||||
vboot_reboot();
|
||||
}
|
||||
|
||||
|
@ -383,7 +389,7 @@ void verstage_main(void)
|
|||
rv = vb2api_fw_phase2(ctx);
|
||||
if (rv) {
|
||||
printk(BIOS_INFO, "Reboot requested (%x)\n", rv);
|
||||
save_if_needed(ctx);
|
||||
vboot_save_data(ctx);
|
||||
vboot_reboot();
|
||||
}
|
||||
|
||||
|
@ -394,7 +400,7 @@ void verstage_main(void)
|
|||
timestamp_add_now(TS_END_VERIFY_SLOT);
|
||||
if (rv) {
|
||||
printk(BIOS_INFO, "Reboot requested (%x)\n", rv);
|
||||
save_if_needed(ctx);
|
||||
vboot_save_data(ctx);
|
||||
vboot_reboot();
|
||||
}
|
||||
|
||||
|
@ -405,7 +411,7 @@ void verstage_main(void)
|
|||
"Failed to read FMAP to locate firmware");
|
||||
|
||||
rv = hash_body(ctx, &fw_main);
|
||||
save_if_needed(ctx);
|
||||
vboot_save_data(ctx);
|
||||
if (rv) {
|
||||
printk(BIOS_INFO, "Reboot requested (%x)\n", rv);
|
||||
vboot_reboot();
|
||||
|
@ -419,7 +425,7 @@ void verstage_main(void)
|
|||
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_save_data(ctx);
|
||||
vboot_reboot();
|
||||
}
|
||||
timestamp_add_now(TS_END_TPMPCR);
|
||||
|
@ -432,7 +438,7 @@ void verstage_main(void)
|
|||
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_save_data(ctx);
|
||||
vboot_reboot();
|
||||
}
|
||||
timestamp_add_now(TS_END_TPMLOCK);
|
||||
|
@ -445,7 +451,7 @@ void verstage_main(void)
|
|||
rv);
|
||||
vb2api_fail(ctx, VB2_RECOVERY_RO_TPM_REC_HASH_L_ERROR,
|
||||
0);
|
||||
save_if_needed(ctx);
|
||||
vboot_save_data(ctx);
|
||||
vboot_reboot();
|
||||
}
|
||||
}
|
||||
|
|
Loading…
Reference in New Issue