vboot: use vboot persistent context

vb2_context object is now stored on the workbuf as part of
vb2_shared_data.  Use vboot's new API functions vb2api_init
and vb2api_relocate to create and move the workbuf.

BUG=b:124141368, chromium:994060
TEST=Build locally
BRANCH=none

Change-Id: I051be1e47bf79b15a1689d49a5d4c031e9363dfa
Signed-off-by: Joel Kitching <kitching@google.com>
Also-Reviewed-on: https://chromium-review.googlesource.com/c/chromiumos/third_party/coreboot/+/1902339
Reviewed-on: https://review.coreboot.org/c/coreboot/+/36300
Tested-by: build bot (Jenkins) <no-reply@coreboot.org>
Reviewed-by: Patrick Georgi <pgeorgi@google.com>
Reviewed-by: Stefan Reinauer <stefan.reinauer@coreboot.org>
Reviewed-by: Maulik V Vaghela <maulik.v.vaghela@intel.com>
This commit is contained in:
Joel Kitching 2019-10-23 15:01:37 +08:00 committed by Patrick Georgi
parent d3c58fdc64
commit 2332c7459e
7 changed files with 89 additions and 79 deletions

2
3rdparty/vboot vendored

@ -1 +1 @@
Subproject commit 87276ffed46b3c64ff62153ac8599a79b9bcb683 Subproject commit ecdca931ae0637d1a9498f64862939bd5bb99e0b

View File

@ -95,8 +95,8 @@ int get_recovery_mode_switch(void)
* and the value from the TPM would be wrong anyway since the verstage * and the value from the TPM would be wrong anyway since the verstage
* read would have cleared the value on the TPM. * read would have cleared the value on the TPM.
* *
* The TPM recovery request is passed between stages through the * The TPM recovery request is passed between stages through vboot data
* vboot_get_shared_data or cbmem depending on stage. * or cbmem depending on stage.
*/ */
if (ENV_VERSTAGE && if (ENV_VERSTAGE &&
tlcl_cr50_get_recovery_button(&cr50_state) == TPM_SUCCESS && tlcl_cr50_get_recovery_button(&cr50_state) == TPM_SUCCESS &&

View File

@ -93,8 +93,8 @@ int get_recovery_mode_switch(void)
* and the value from the TPM would be wrong anyway since the verstage * and the value from the TPM would be wrong anyway since the verstage
* read would have cleared the value on the TPM. * read would have cleared the value on the TPM.
* *
* The TPM recovery request is passed between stages through the * The TPM recovery request is passed between stages through vboot data
* vboot_get_shared_data or cbmem depending on stage. * or cbmem depending on stage.
*/ */
if (ENV_VERSTAGE && if (ENV_VERSTAGE &&
tlcl_cr50_get_recovery_button(&cr50_state) == TPM_SUCCESS && tlcl_cr50_get_recovery_button(&cr50_state) == TPM_SUCCESS &&

View File

@ -26,7 +26,7 @@
static int vboot_get_recovery_reason_shared_data(void) static int vboot_get_recovery_reason_shared_data(void)
{ {
struct vb2_shared_data *sd = vboot_get_shared_data(); struct vb2_shared_data *sd = vb2_get_sd(vboot_get_context());
assert(sd); assert(sd);
return sd->recovery_reason; return sd->recovery_reason;
} }

View File

@ -24,6 +24,8 @@
#include <security/vboot/symbols.h> #include <security/vboot/symbols.h>
#include <security/vboot/vboot_common.h> #include <security/vboot/vboot_common.h>
static struct vb2_context *vboot_ctx CAR_GLOBAL;
struct vboot_working_data *vboot_get_working_data(void) struct vboot_working_data *vboot_get_working_data(void)
{ {
struct vboot_working_data *wd = NULL; struct vboot_working_data *wd = NULL;
@ -40,43 +42,45 @@ struct vboot_working_data *vboot_get_working_data(void)
return wd; return wd;
} }
void vboot_init_work_context(struct vb2_context *ctx) static inline void *vboot_get_workbuf(struct vboot_working_data *wd)
{ {
return (void *)((uintptr_t)wd + wd->buffer_offset);
}
struct vb2_context *vboot_get_context(void)
{
struct vb2_context **vboot_ctx_ptr = car_get_var_ptr(&vboot_ctx);
struct vboot_working_data *wd; struct vboot_working_data *wd;
/* First initialize the working data region. */ /* Return if context has already been initialized/restored. */
if (*vboot_ctx_ptr)
return *vboot_ctx_ptr;
wd = vboot_get_working_data(); wd = vboot_get_working_data();
memset(wd, 0, VB2_FIRMWARE_WORKBUF_RECOMMENDED_SIZE);
/* Restore context from a previous stage. */
if (vboot_logic_executed()) {
assert(vb2api_reinit(vboot_get_workbuf(wd),
vboot_ctx_ptr) == VB2_SUCCESS);
return *vboot_ctx_ptr;
}
assert(verification_should_run());
/* /*
* vboot prefers 16-byte alignment. This takes away 16 bytes * vboot prefers 16-byte alignment. This takes away 16 bytes
* from the VBOOT2_WORK region, but the vboot devs said that's okay. * from the VBOOT2_WORK region, but the vboot devs said that's okay.
*/ */
memset(wd, 0, sizeof(*wd));
wd->buffer_offset = ALIGN_UP(sizeof(*wd), 16); wd->buffer_offset = ALIGN_UP(sizeof(*wd), 16);
wd->buffer_size = VB2_FIRMWARE_WORKBUF_RECOMMENDED_SIZE wd->buffer_size = VB2_FIRMWARE_WORKBUF_RECOMMENDED_SIZE
- wd->buffer_offset; - wd->buffer_offset;
/* Initialize the vb2_context. */ /* Initialize vb2_shared_data and friends. */
memset(ctx, 0, sizeof(*ctx)); assert(vb2api_init(vboot_get_workbuf(wd), wd->buffer_size,
ctx->workbuf = (void *)vboot_get_shared_data(); vboot_ctx_ptr) == VB2_SUCCESS);
ctx->workbuf_size = wd->buffer_size;
}
void vboot_finalize_work_context(struct vb2_context *ctx) return *vboot_ctx_ptr;
{
/*
* Shrink buffer_size so that vboot_migrate_cbmem knows how
* much of vboot_working_data needs to be copied into CBMEM
* (if applicable), and so that downstream users know how much
* of the workbuf is currently used.
*/
vboot_get_working_data()->buffer_size = ctx->workbuf_used;
}
struct vb2_shared_data *vboot_get_shared_data(void)
{
struct vboot_working_data *wd = vboot_get_working_data();
return (void *)((uintptr_t)wd + wd->buffer_offset);
} }
int vboot_get_selected_region(struct region *region) int vboot_get_selected_region(struct region *region)
@ -126,17 +130,25 @@ int vboot_is_slot_selected(void)
*/ */
static void vboot_migrate_cbmem(int unused) static void vboot_migrate_cbmem(int unused)
{ {
const struct vboot_working_data *wd_preram = const size_t cbmem_size = VB2_KERNEL_WORKBUF_RECOMMENDED_SIZE;
struct vboot_working_data *wd_preram =
(struct vboot_working_data *)_vboot2_work; (struct vboot_working_data *)_vboot2_work;
size_t cbmem_size = wd_preram->buffer_offset + wd_preram->buffer_size;
struct vboot_working_data *wd_cbmem = struct vboot_working_data *wd_cbmem =
cbmem_add(CBMEM_ID_VBOOT_WORKBUF, cbmem_size); cbmem_add(CBMEM_ID_VBOOT_WORKBUF, cbmem_size);
assert(wd_cbmem != NULL); assert(wd_cbmem != NULL);
memcpy(wd_cbmem, wd_preram, sizeof(struct vboot_working_data));
printk(BIOS_DEBUG, /*
"VBOOT: copying vboot_working_data (%zu bytes) to CBMEM...\n", * TODO(chromium:1021452): buffer_size is uint16_t and not large enough
cbmem_size); * to hold the kernel verification workbuf size. The only code which
memcpy(wd_cbmem, wd_preram, cbmem_size); * reads this value is in lb_vboot_workbuf() for lb_range->range_size.
* This value being zero doesn't cause any problems, since it is never
* read downstream. Fix or deprecate vboot_working_data.
*/
wd_cbmem->buffer_size = 0;
vb2api_relocate(vboot_get_workbuf(wd_cbmem),
vboot_get_workbuf(wd_preram),
cbmem_size - wd_cbmem->buffer_offset,
car_get_var_ptr(&vboot_ctx));
} }
ROMSTAGE_CBMEM_INIT_HOOK(vboot_migrate_cbmem) ROMSTAGE_CBMEM_INIT_HOOK(vboot_migrate_cbmem)
#else #else
@ -144,7 +156,7 @@ static void vboot_setup_cbmem(int unused)
{ {
struct vboot_working_data *wd_cbmem = struct vboot_working_data *wd_cbmem =
cbmem_add(CBMEM_ID_VBOOT_WORKBUF, cbmem_add(CBMEM_ID_VBOOT_WORKBUF,
VB2_FIRMWARE_WORKBUF_RECOMMENDED_SIZE); VB2_KERNEL_WORKBUF_RECOMMENDED_SIZE);
assert(wd_cbmem != NULL); assert(wd_cbmem != NULL);
} }
ROMSTAGE_CBMEM_INIT_HOOK(vboot_setup_cbmem) ROMSTAGE_CBMEM_INIT_HOOK(vboot_setup_cbmem)

View File

@ -29,10 +29,11 @@ struct selected_region {
}; };
/* /*
* this is placed at the start of the vboot work buffer. selected_region is used * Stores vboot-related information. selected_region is used by verstage to
* for the verstage to return the location of the selected slot. buffer is used * store the location of the selected slot. buffer is used by vboot to store
* by the vboot2 core. Keep the struct CPU architecture agnostic as it crosses * its work buffer. vb2_context is contained within this work buffer, and is
* stage boundaries. * accessible via vboot_init_context() and vboot_get_context() (see below).
* Keep the struct CPU architecture agnostic as it crosses stage boundaries.
*/ */
struct vboot_working_data { struct vboot_working_data {
struct selected_region selected_region; struct selected_region selected_region;
@ -54,9 +55,7 @@ struct vboot_working_data {
* Source: security/vboot/common.c * Source: security/vboot/common.c
*/ */
struct vboot_working_data *vboot_get_working_data(void); struct vboot_working_data *vboot_get_working_data(void);
void vboot_init_work_context(struct vb2_context *ctx); struct vb2_context *vboot_get_context(void);
void vboot_finalize_work_context(struct vb2_context *ctx);
struct vb2_shared_data *vboot_get_shared_data(void);
/* Returns 0 on success. < 0 on failure. */ /* Returns 0 on success. < 0 on failure. */
int vboot_get_selected_region(struct region *region); int vboot_get_selected_region(struct region *region);

View File

@ -319,17 +319,17 @@ ROMSTAGE_CBMEM_INIT_HOOK(vboot_log_and_clear_recovery_mode_switch)
*/ */
void verstage_main(void) void verstage_main(void)
{ {
struct vb2_context ctx; struct vb2_context *ctx;
struct region_device fw_main; struct region_device fw_main;
vb2_error_t rv; vb2_error_t rv;
timestamp_add_now(TS_START_VBOOT); timestamp_add_now(TS_START_VBOOT);
/* Set up context and work buffer */ /* Set up context and work buffer */
vboot_init_work_context(&ctx); ctx = vboot_get_context();
/* Initialize and read nvdata from non-volatile storage. */ /* Initialize and read nvdata from non-volatile storage. */
vbnv_init(ctx.nvdata); vbnv_init(ctx->nvdata);
/* Set S3 resume flag if vboot should behave differently when selecting /* Set S3 resume flag if vboot should behave differently when selecting
* which slot to boot. This is only relevant to vboot if the platform * which slot to boot. This is only relevant to vboot if the platform
@ -337,51 +337,51 @@ void verstage_main(void)
* the same slot that it booted from. */ * the same slot that it booted from. */
if (CONFIG(RESUME_PATH_SAME_AS_BOOT) && if (CONFIG(RESUME_PATH_SAME_AS_BOOT) &&
vboot_platform_is_resuming()) vboot_platform_is_resuming())
ctx.flags |= VB2_CONTEXT_S3_RESUME; ctx->flags |= VB2_CONTEXT_S3_RESUME;
/* Read secdata from TPM. Initialize TPM if secdata not found. We don't /* Read secdata from TPM. Initialize TPM if secdata not found. We don't
* check the return value here because vb2api_fw_phase1 will catch * check the return value here because vb2api_fw_phase1 will catch
* invalid secdata and tell us what to do (=reboot). */ * invalid secdata and tell us what to do (=reboot). */
timestamp_add_now(TS_START_TPMINIT); timestamp_add_now(TS_START_TPMINIT);
if (vboot_setup_tpm(&ctx) == TPM_SUCCESS) if (vboot_setup_tpm(ctx) == TPM_SUCCESS)
antirollback_read_space_firmware(&ctx); antirollback_read_space_firmware(ctx);
timestamp_add_now(TS_END_TPMINIT); timestamp_add_now(TS_END_TPMINIT);
/* Enable measured boot mode */ /* Enable measured boot mode */
if (CONFIG(VBOOT_MEASURED_BOOT) && if (CONFIG(VBOOT_MEASURED_BOOT) &&
!(ctx.flags & VB2_CONTEXT_S3_RESUME)) { !(ctx->flags & VB2_CONTEXT_S3_RESUME)) {
if (vboot_init_crtm() != VB2_SUCCESS) if (vboot_init_crtm() != VB2_SUCCESS)
die_with_post_code(POST_INVALID_ROM, die_with_post_code(POST_INVALID_ROM,
"Initializing measured boot mode failed!"); "Initializing measured boot mode failed!");
} }
if (get_recovery_mode_switch()) { if (get_recovery_mode_switch()) {
ctx.flags |= VB2_CONTEXT_FORCE_RECOVERY_MODE; ctx->flags |= VB2_CONTEXT_FORCE_RECOVERY_MODE;
if (CONFIG(VBOOT_DISABLE_DEV_ON_RECOVERY)) if (CONFIG(VBOOT_DISABLE_DEV_ON_RECOVERY))
ctx.flags |= VB2_CONTEXT_DISABLE_DEVELOPER_MODE; ctx->flags |= VB2_CONTEXT_DISABLE_DEVELOPER_MODE;
} }
if (CONFIG(VBOOT_WIPEOUT_SUPPORTED) && if (CONFIG(VBOOT_WIPEOUT_SUPPORTED) &&
get_wipeout_mode_switch()) get_wipeout_mode_switch())
ctx.flags |= VB2_CONTEXT_FORCE_WIPEOUT_MODE; ctx->flags |= VB2_CONTEXT_FORCE_WIPEOUT_MODE;
if (CONFIG(VBOOT_LID_SWITCH) && !get_lid_switch()) if (CONFIG(VBOOT_LID_SWITCH) && !get_lid_switch())
ctx.flags |= VB2_CONTEXT_NOFAIL_BOOT; ctx->flags |= VB2_CONTEXT_NOFAIL_BOOT;
/* Mainboard/SoC always initializes display. */ /* Mainboard/SoC always initializes display. */
if (!CONFIG(VBOOT_MUST_REQUEST_DISPLAY)) if (!CONFIG(VBOOT_MUST_REQUEST_DISPLAY))
ctx.flags |= VB2_CONTEXT_DISPLAY_INIT; ctx->flags |= VB2_CONTEXT_DISPLAY_INIT;
/* Do early init (set up secdata and NVRAM, load GBB) */ /* Do early init (set up secdata and NVRAM, load GBB) */
printk(BIOS_INFO, "Phase 1\n"); printk(BIOS_INFO, "Phase 1\n");
rv = vb2api_fw_phase1(&ctx); rv = vb2api_fw_phase1(ctx);
/* Jot down some information from vboot which may be required later on /* Jot down some information from vboot which may be required later on
in coreboot boot flow. */ in coreboot boot flow. */
if (ctx.flags & VB2_CONTEXT_DISPLAY_INIT) if (ctx->flags & VB2_CONTEXT_DISPLAY_INIT)
/* Mainboard/SoC should initialize display. */ /* Mainboard/SoC should initialize display. */
vboot_get_working_data()->flags |= VBOOT_WD_FLAG_DISPLAY_INIT; vboot_get_working_data()->flags |= VBOOT_WD_FLAG_DISPLAY_INIT;
if (ctx.flags & VB2_CONTEXT_DEVELOPER_MODE) if (ctx->flags & VB2_CONTEXT_DEVELOPER_MODE)
vboot_get_working_data()->flags |= VBOOT_WD_FLAG_DEVELOPER_MODE; vboot_get_working_data()->flags |= VBOOT_WD_FLAG_DEVELOPER_MODE;
if (rv) { if (rv) {
@ -393,58 +393,58 @@ void verstage_main(void)
*/ */
if (rv == VB2_ERROR_API_PHASE1_RECOVERY) { if (rv == VB2_ERROR_API_PHASE1_RECOVERY) {
printk(BIOS_INFO, "Recovery requested (%x)\n", rv); printk(BIOS_INFO, "Recovery requested (%x)\n", rv);
save_if_needed(&ctx); save_if_needed(ctx);
extend_pcrs(&ctx); /* ignore failures */ extend_pcrs(ctx); /* ignore failures */
goto verstage_main_exit; goto verstage_main_exit;
} }
printk(BIOS_INFO, "Reboot requested (%x)\n", rv); printk(BIOS_INFO, "Reboot requested (%x)\n", rv);
save_if_needed(&ctx); save_if_needed(ctx);
vboot_reboot(); vboot_reboot();
} }
/* Determine which firmware slot to boot (based on NVRAM) */ /* Determine which firmware slot to boot (based on NVRAM) */
printk(BIOS_INFO, "Phase 2\n"); printk(BIOS_INFO, "Phase 2\n");
rv = vb2api_fw_phase2(&ctx); rv = vb2api_fw_phase2(ctx);
if (rv) { if (rv) {
printk(BIOS_INFO, "Reboot requested (%x)\n", rv); printk(BIOS_INFO, "Reboot requested (%x)\n", rv);
save_if_needed(&ctx); save_if_needed(ctx);
vboot_reboot(); vboot_reboot();
} }
/* Try that slot (verify its keyblock and preamble) */ /* Try that slot (verify its keyblock and preamble) */
printk(BIOS_INFO, "Phase 3\n"); printk(BIOS_INFO, "Phase 3\n");
timestamp_add_now(TS_START_VERIFY_SLOT); timestamp_add_now(TS_START_VERIFY_SLOT);
rv = vb2api_fw_phase3(&ctx); rv = vb2api_fw_phase3(ctx);
timestamp_add_now(TS_END_VERIFY_SLOT); timestamp_add_now(TS_END_VERIFY_SLOT);
if (rv) { if (rv) {
printk(BIOS_INFO, "Reboot requested (%x)\n", rv); printk(BIOS_INFO, "Reboot requested (%x)\n", rv);
save_if_needed(&ctx); save_if_needed(ctx);
vboot_reboot(); vboot_reboot();
} }
printk(BIOS_INFO, "Phase 4\n"); printk(BIOS_INFO, "Phase 4\n");
rv = locate_firmware(&ctx, &fw_main); rv = locate_firmware(ctx, &fw_main);
if (rv) if (rv)
die_with_post_code(POST_INVALID_ROM, die_with_post_code(POST_INVALID_ROM,
"Failed to read FMAP to locate firmware"); "Failed to read FMAP to locate firmware");
rv = hash_body(&ctx, &fw_main); rv = hash_body(ctx, &fw_main);
save_if_needed(&ctx); save_if_needed(ctx);
if (rv) { if (rv) {
printk(BIOS_INFO, "Reboot requested (%x)\n", rv); printk(BIOS_INFO, "Reboot requested (%x)\n", rv);
vboot_reboot(); vboot_reboot();
} }
/* Only extend PCRs once on boot. */ /* Only extend PCRs once on boot. */
if (!(ctx.flags & VB2_CONTEXT_S3_RESUME)) { if (!(ctx->flags & VB2_CONTEXT_S3_RESUME)) {
timestamp_add_now(TS_START_TPMPCR); timestamp_add_now(TS_START_TPMPCR);
rv = extend_pcrs(&ctx); rv = extend_pcrs(ctx);
if (rv) { if (rv) {
printk(BIOS_WARNING, printk(BIOS_WARNING,
"Failed to extend TPM PCRs (%#x)\n", rv); "Failed to extend TPM PCRs (%#x)\n", rv);
vb2api_fail(&ctx, VB2_RECOVERY_RO_TPM_U_ERROR, rv); vb2api_fail(ctx, VB2_RECOVERY_RO_TPM_U_ERROR, rv);
save_if_needed(&ctx); save_if_needed(ctx);
vboot_reboot(); vboot_reboot();
} }
timestamp_add_now(TS_END_TPMPCR); timestamp_add_now(TS_END_TPMPCR);
@ -456,8 +456,8 @@ void verstage_main(void)
rv = antirollback_lock_space_firmware(); rv = antirollback_lock_space_firmware();
if (rv) { if (rv) {
printk(BIOS_INFO, "Failed to lock TPM (%x)\n", rv); printk(BIOS_INFO, "Failed to lock TPM (%x)\n", rv);
vb2api_fail(&ctx, VB2_RECOVERY_RO_TPM_L_ERROR, 0); vb2api_fail(ctx, VB2_RECOVERY_RO_TPM_L_ERROR, 0);
save_if_needed(&ctx); save_if_needed(ctx);
vboot_reboot(); vboot_reboot();
} }
timestamp_add_now(TS_END_TPMLOCK); timestamp_add_now(TS_END_TPMLOCK);
@ -468,14 +468,14 @@ void verstage_main(void)
if (rv) { if (rv) {
printk(BIOS_INFO, "Failed to lock rec hash space(%x)\n", printk(BIOS_INFO, "Failed to lock rec hash space(%x)\n",
rv); rv);
vb2api_fail(&ctx, VB2_RECOVERY_RO_TPM_REC_HASH_L_ERROR, vb2api_fail(ctx, VB2_RECOVERY_RO_TPM_REC_HASH_L_ERROR,
0); 0);
save_if_needed(&ctx); save_if_needed(ctx);
vboot_reboot(); vboot_reboot();
} }
} }
printk(BIOS_INFO, "Slot %c is selected\n", is_slot_a(&ctx) ? 'A' : 'B'); printk(BIOS_INFO, "Slot %c is selected\n", is_slot_a(ctx) ? 'A' : 'B');
vboot_set_selected_region(region_device_region(&fw_main)); vboot_set_selected_region(region_device_region(&fw_main));
verstage_main_exit: verstage_main_exit:
@ -487,6 +487,5 @@ void verstage_main(void)
/* Save recovery reason in case of unexpected reboots on x86. */ /* Save recovery reason in case of unexpected reboots on x86. */
vboot_save_recovery_reason_vbnv(); vboot_save_recovery_reason_vbnv();
vboot_finalize_work_context(&ctx);
timestamp_add_now(TS_END_VBOOT); timestamp_add_now(TS_END_VBOOT);
} }