Aaron Durbin (adurbin@chromium.org) just uploaded a new patch set to gerrit, which you can find at http://review.coreboot.org/10154
-gerrit
commit 5b986b46f04e2ab1f3c71d85fabcbce6b697d807 Author: Aaron Durbin adurbin@chromium.org Date: Fri May 1 16:48:54 2015 -0500
vboot: inject vboot loader for stage loading
As previously done the vboot loader can be optionally inserted in the stage loading logic in order to decide the source of each stage. This current patch allows for verstage to be loaded and interrogated for the source of all subsequent stages. Additionally, it's also possible to build this logic directly into one of the additional stages.
Note that this patch does not allow x86 to work.
Change-Id: Iece018f01b220720c2803dc73c60b2c080d637d0 Signed-off-by: Aaron Durbin adurbin@chromium.org --- src/include/program_loading.h | 1 + src/lib/Makefile.inc | 1 + src/lib/loaders/Makefile.inc | 2 + src/lib/loaders/load_and_run_payload.c | 4 +- src/lib/loaders/load_and_run_ramstage.c | 4 +- src/lib/loaders/load_and_run_romstage.c | 7 + src/vendorcode/google/chromeos/vboot2/Makefile.inc | 9 +- src/vendorcode/google/chromeos/vboot2/common.c | 33 --- src/vendorcode/google/chromeos/vboot2/misc.h | 3 +- .../google/chromeos/vboot2/vboot_handoff.c | 53 ++--- .../google/chromeos/vboot2/vboot_loader.c | 243 +++++++++++++++++++++ src/vendorcode/google/chromeos/vboot2/verstub.c | 107 --------- 12 files changed, 279 insertions(+), 188 deletions(-)
diff --git a/src/include/program_loading.h b/src/include/program_loading.h index ca80b0e..5fc0fd6 100644 --- a/src/include/program_loading.h +++ b/src/include/program_loading.h @@ -39,6 +39,7 @@ struct buffer_area { };
enum prog_type { + PROG_VERSTAGE, PROG_ROMSTAGE, PROG_RAMSTAGE, PROG_PAYLOAD, diff --git a/src/lib/Makefile.inc b/src/lib/Makefile.inc index ef4e2aa..b50e3aa 100644 --- a/src/lib/Makefile.inc +++ b/src/lib/Makefile.inc @@ -34,6 +34,7 @@ verstage-y += prog_ops.c verstage-y += delay.c verstage-y += cbfs.c verstage-y += cbfs_core.c +verstage-y += halt.c verstage-y += memcmp.c verstage-$(CONFIG_COLLECT_TIMESTAMPS) += timestamp.c verstage-$(CONFIG_CONSOLE_CBMEM) += cbmem_console.c diff --git a/src/lib/loaders/Makefile.inc b/src/lib/loaders/Makefile.inc index fbc7f87..9dca06b 100644 --- a/src/lib/loaders/Makefile.inc +++ b/src/lib/loaders/Makefile.inc @@ -23,3 +23,5 @@ romstage-y += cbfs_ramstage_loader.c romstage-y += load_and_run_ramstage.c ramstage-y += cbfs_payload_loader.c ramstage-y += load_and_run_payload.c +verstage-y += cbfs_romstage_loader.c +verstage-y += load_and_run_romstage.c diff --git a/src/lib/loaders/load_and_run_payload.c b/src/lib/loaders/load_and_run_payload.c index 7a08097..4928e0c 100644 --- a/src/lib/loaders/load_and_run_payload.c +++ b/src/lib/loaders/load_and_run_payload.c @@ -27,12 +27,12 @@ #include <symbols.h> #include <timestamp.h>
-extern const struct prog_loader_ops vboot_payload_loader; +extern const struct prog_loader_ops vboot_loader; extern const struct prog_loader_ops cbfs_payload_loader;
static const struct prog_loader_ops *payload_ops[] = { #if CONFIG_VBOOT_VERIFY_FIRMWARE - &vboot_payload_loader, + &vboot_loader, #endif &cbfs_payload_loader, }; diff --git a/src/lib/loaders/load_and_run_ramstage.c b/src/lib/loaders/load_and_run_ramstage.c index fddea4d..504dbff 100644 --- a/src/lib/loaders/load_and_run_ramstage.c +++ b/src/lib/loaders/load_and_run_ramstage.c @@ -27,11 +27,11 @@ #include <timestamp.h>
extern const struct prog_loader_ops cbfs_ramstage_loader; -extern const struct prog_loader_ops vboot_ramstage_loader; +extern const struct prog_loader_ops vboot_loader;
static const struct prog_loader_ops *loaders[] = { #if CONFIG_VBOOT_VERIFY_FIRMWARE - &vboot_ramstage_loader, + &vboot_loader, #endif &cbfs_ramstage_loader, }; diff --git a/src/lib/loaders/load_and_run_romstage.c b/src/lib/loaders/load_and_run_romstage.c index b54bfc7..b54c691 100644 --- a/src/lib/loaders/load_and_run_romstage.c +++ b/src/lib/loaders/load_and_run_romstage.c @@ -24,12 +24,19 @@ #include <cbfs.h> #include <halt.h> #include <program_loading.h> +#include <rules.h> #include <timestamp.h>
extern const struct prog_loader_ops cbfs_romstage_loader; +extern const struct prog_loader_ops vboot_loader;
static const struct prog_loader_ops *loaders[] = { +#if CONFIG_VBOOT_VERIFY_FIRMWARE + &vboot_loader, +#endif +#if !ENV_VERSTAGE || (ENV_VERSTAGE && !CONFIG_RETURN_FROM_VERSTAGE) &cbfs_romstage_loader, +#endif };
void run_romstage(void) diff --git a/src/vendorcode/google/chromeos/vboot2/Makefile.inc b/src/vendorcode/google/chromeos/vboot2/Makefile.inc index e9377b2..6ec352f 100644 --- a/src/vendorcode/google/chromeos/vboot2/Makefile.inc +++ b/src/vendorcode/google/chromeos/vboot2/Makefile.inc @@ -20,13 +20,16 @@ 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 + bootblock-y += ../vboot_common.c verstage-y += ../vboot_common.c romstage-y += ../vboot_common.c ramstage-y += ../vboot_common.c
-bootblock-y += verstub.c -libverstage-y += verstub.c bootblock-y += common.c libverstage-y += verstage.c verstage-y += common.c @@ -37,6 +40,8 @@ libverstage-y += antirollback.c endif romstage-y += vboot_handoff.c common.c
+ramstage-y += common.c + verstage-y += verstage.ld
ifeq ($(CONFIG_SEPARATE_VERSTAGE),y) diff --git a/src/vendorcode/google/chromeos/vboot2/common.c b/src/vendorcode/google/chromeos/vboot2/common.c index d70a108..beffebe 100644 --- a/src/vendorcode/google/chromeos/vboot2/common.c +++ b/src/vendorcode/google/chromeos/vboot2/common.c @@ -25,39 +25,6 @@ #include "../vboot_handoff.h" #include "misc.h"
-void *vboot_load_stage(int stage_index, - struct vboot_region *fw_main, - struct vboot_components *fw_info) -{ - struct cbfs_media default_media, *media = &default_media; - uintptr_t fc_addr; - uint32_t fc_size; - void *entry; - - if (stage_index >= fw_info->num_components) { - printk(BIOS_INFO, "invalid stage index\n"); - return NULL; - } - - fc_addr = fw_main->offset_addr + fw_info->entries[stage_index].offset; - fc_size = fw_info->entries[stage_index].size; - if (fc_size == 0 || - fc_addr + fc_size > fw_main->offset_addr + fw_main->size) { - printk(BIOS_INFO, "invalid stage address or size\n"); - return NULL; - } - - init_default_cbfs_media(media); - - /* we're making cbfs access offset outside of the region managed by - * cbfs. this works because cbfs_load_stage_by_offset does not check - * the offset. */ - entry = cbfs_load_stage_by_offset(media, fc_addr); - if (entry == (void *)-1) - entry = NULL; - return entry; -} - struct vb2_working_data * const vboot_get_working_data(void) { return (struct vb2_working_data *)_vboot2_work; diff --git a/src/vendorcode/google/chromeos/vboot2/misc.h b/src/vendorcode/google/chromeos/vboot2/misc.h index 7425082..d942d56 100644 --- a/src/vendorcode/google/chromeos/vboot2/misc.h +++ b/src/vendorcode/google/chromeos/vboot2/misc.h @@ -22,8 +22,7 @@
#include "../vboot_common.h"
-void *vboot2_verify_firmware(void); -void *vboot2_load_ramstage(void); +void vboot_fill_handoff(void); void verstage_main(void); void *vboot_load_stage(int stage_index, struct vboot_region *fw_main, diff --git a/src/vendorcode/google/chromeos/vboot2/vboot_handoff.c b/src/vendorcode/google/chromeos/vboot2/vboot_handoff.c index b84e47e..16261b4 100644 --- a/src/vendorcode/google/chromeos/vboot2/vboot_handoff.c +++ b/src/vendorcode/google/chromeos/vboot2/vboot_handoff.c @@ -36,30 +36,6 @@ #include "../vboot_handoff.h" #include "misc.h"
-static void *load_ramstage(struct vboot_handoff *vboot_handoff, - struct vboot_region *fw_main) -{ - struct vboot_components *fw_info; - void *ret; - int i; - - fw_info = vboot_locate_components(fw_main); - if (fw_info == NULL) - die("failed to locate firmware components\n"); - - /* these offset & size are used to load a rw boot loader */ - for (i = 0; i < fw_info->num_components; i++) { - vboot_handoff->components[i].address = - fw_main->offset_addr + fw_info->entries[i].offset; - vboot_handoff->components[i].size = fw_info->entries[i].size; - } - - timestamp_add_now(TS_START_COPYRAM); - ret = vboot_load_stage(CONFIG_VBOOT_RAMSTAGE_INDEX, fw_main, fw_info); - timestamp_add_now(TS_END_COPYRAM); - return ret; -} - /** * Sets vboot_handoff based on the information in vb2_shared_data * @@ -146,14 +122,13 @@ static void fill_vboot_handoff(struct vboot_handoff *vboot_handoff, vb_sd->recovery_reason = vb2_sd->recovery_reason; }
-/** - * Load ramstage and return the entry point - */ -void *vboot2_load_ramstage(void) +void vboot_fill_handoff(void) { + int i; struct vboot_handoff *vh; struct vb2_shared_data *sd; struct vboot_region fw_main; + struct vboot_components *fw_info; struct vb2_working_data *wd = vboot_get_working_data();
sd = vboot_get_work_buffer(wd); @@ -172,17 +147,15 @@ void *vboot2_load_ramstage(void) /* needed until we finish transtion to vboot2 for kernel verification */ fill_vboot_handoff(vh, sd);
- if (vboot_is_readonly_path(wd)) - /* we're on recovery path. continue to ro-ramstage. */ - return NULL; - - if (IS_ENABLED(CONFIG_MULTIPLE_CBFS_INSTANCES)) { - return cbfs_load_stage(CBFS_DEFAULT_MEDIA, - CONFIG_CBFS_PREFIX "/ramstage"); - } else { - printk(BIOS_INFO, "loading ramstage from Slot %c\n", - sd->fw_slot ? 'B' : 'A'); - vb2_get_selected_region(wd, &fw_main); - return load_ramstage(vh, &fw_main); + vb2_get_selected_region(wd, &fw_main); + fw_info = vboot_locate_components(&fw_main); + if (fw_info == NULL) + die("failed to locate firmware components\n"); + + /* these offset & size are used to load a rw boot loader */ + for (i = 0; i < fw_info->num_components; i++) { + vh->components[i].address = + fw_main.offset_addr + fw_info->entries[i].offset; + vh->components[i].size = fw_info->entries[i].size; } } diff --git a/src/vendorcode/google/chromeos/vboot2/vboot_loader.c b/src/vendorcode/google/chromeos/vboot2/vboot_loader.c new file mode 100644 index 0000000..c731abb --- /dev/null +++ b/src/vendorcode/google/chromeos/vboot2/vboot_loader.c @@ -0,0 +1,243 @@ +/* + * 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. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc. + */ + +#include <cbfs.h> +#include <console/console.h> +#include <program_loading.h> +#include <rules.h> +#include <string.h> +#include "misc.h" +#include "../symbols.h" + +/* The stage loading code is compiled and entered from mutilple stages. The + * helper functions below attempt to provde 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 void init_vb2_working_data(void) +{ + struct vb2_working_data *wd; + + wd = vboot_get_working_data(); + memset(wd, 0, _vboot2_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 = _vboot2_work_size - wd->buffer_offset; +} + +static int vboot_loader_active(struct prog *prog) +{ + struct vb2_working_data *wd; + int run_verification; + + run_verification = verification_should_run(); + + if (run_verification) { + init_vb2_working_data(); + verstage_main(); + } else if (verstage_should_load()) { + struct prog verstage = { + .type = PROG_VERSTAGE, + .name = CONFIG_CBFS_PREFIX "/verstage", + }; + + /* load verstage from RO */ + if (cbfs_load_prog_stage(CBFS_DEFAULT_MEDIA, &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 0; + } + + wd = vboot_get_working_data(); + + if (vboot_is_slot_selected(wd)) { + if (IS_ENABLED(CONFIG_MULTIPLE_CBFS_INSTANCES) && + run_verification) { + /* RW A or B */ + struct vboot_region fw_main; + + vb2_get_selected_region(wd, &fw_main); + cbfs_set_header_offset(fw_main.offset_addr); + } + return 1; + } + + return 0; +} + +static uintptr_t vboot_fw_region(int fw_index, struct vboot_region *fw_main, + struct vboot_components *fw_info, size_t *size) +{ + uintptr_t fc_addr; + uint32_t fc_size; + + if (fw_index >= fw_info->num_components) { + printk(BIOS_INFO, "invalid stage index: %d\n", fw_index); + return 0; + } + + fc_addr = fw_main->offset_addr + fw_info->entries[fw_index].offset; + fc_size = fw_info->entries[fw_index].size; + if (fc_size == 0 || + fc_addr + fc_size > fw_main->offset_addr + fw_main->size) { + printk(BIOS_INFO, "invalid stage address or size\n"); + return 0; + } + + *size = fc_addr; + return fc_addr; +} + +/* This function is only called when vboot_loader_active() returns 1. That + * means we are taking vboot paths. */ +static int vboot_prepare(struct prog *prog) +{ + struct vb2_working_data *wd; + struct vboot_region fw_main; + struct vboot_components *fw_info; + + /* Code size optimization. We'd never actually get called under the + * followin cirumstances because verstage was loaded and ran -- never + * returning. */ + if (verstage_should_load() && !IS_ENABLED(CONFIG_RETURN_FROM_VERSTAGE)) + return 0; + + /* In the multi cbfs case the cbfs offset pointer has already been + * updated after firmware verification. */ + if (IS_ENABLED(CONFIG_MULTIPLE_CBFS_INSTANCES)) { + if (!ENV_RAMSTAGE && + cbfs_load_prog_stage(CBFS_DEFAULT_MEDIA, prog) != 0) + return -1; + + /* Need to load payload. */ + if (ENV_RAMSTAGE) { + void *payload; + size_t size; + + payload = cbfs_get_file_content(CBFS_DEFAULT_MEDIA, + prog->name, + CBFS_TYPE_PAYLOAD, + &size); + + if (payload == NULL) + die("Couldn't load payload\n"); + + prog_set_area(prog, payload, size); + } + return 0; + } + + wd = vboot_get_working_data(); + vb2_get_selected_region(wd, &fw_main); + fw_info = vboot_locate_components(&fw_main); + if (fw_info == NULL) + die("failed to locate firmware components\n"); + + /* Load payload in ramstage. */ + if (ENV_RAMSTAGE) { + uintptr_t payload; + void *payload_ptr; + size_t size; + + payload = vboot_fw_region(CONFIG_VBOOT_BOOT_LOADER_INDEX, + &fw_main, fw_info, &size); + + if (payload == 0) + die("Couldn't load payload."); + + payload_ptr = vboot_get_region(payload, size, NULL); + + if (payload_ptr == NULL) + die("Couldn't load payload."); + + prog_set_area(prog, payload_ptr, size); + } else { + uintptr_t stage; + size_t size; + int stage_index = 0; + + if (prog->type == PROG_ROMSTAGE) + stage_index = CONFIG_VBOOT_ROMSTAGE_INDEX; + else if (prog->type == PROG_RAMSTAGE) + stage_index = CONFIG_VBOOT_RAMSTAGE_INDEX; + else + die("Invalid program type for vboot."); + + stage = vboot_fw_region(stage_index, &fw_main, fw_info, &size); + + if (stage == 0) + die("Vboot stage load failed."); + + if (cbfs_load_prog_stage_by_offset(CBFS_DEFAULT_MEDIA, + prog, stage) < 0) + die("Vboot couldn't load stage"); + } + + /* Fill in vboot handoff structure before moving to ramstage. */ + if (ENV_ROMSTAGE) + vboot_fill_handoff(); + + return 0; +} + +const struct prog_loader_ops vboot_loader = { + .name = "VBOOT", + .is_loader_active = vboot_loader_active, + .prepare = vboot_prepare, +}; diff --git a/src/vendorcode/google/chromeos/vboot2/verstub.c b/src/vendorcode/google/chromeos/vboot2/verstub.c deleted file mode 100644 index c4319ba..0000000 --- a/src/vendorcode/google/chromeos/vboot2/verstub.c +++ /dev/null @@ -1,107 +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. - * - * You should have received a copy of the GNU General Public License - * along with this program; if not, write to the Free Software - * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA - */ - -#include <arch/stages.h> -#include <cbfs.h> -#include <console/console.h> -#include <string.h> -#include <timestamp.h> -#include "../chromeos.h" -#include "../symbols.h" -#include "misc.h" - -static struct vb2_working_data *init_vb2_working_data(void) -{ - struct vb2_working_data *wd; - - wd = vboot_get_working_data(); - memset(wd, 0, _vboot2_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 = _vboot2_work_size - wd->buffer_offset; - - return wd; -} - -/** - * Verify a slot and jump to the next stage - * - * This could be either part of the (1) bootblock or the (2) verstage, depending - * on CONFIG_RETURN_FROM_VERSTAGE. - * - * 1) It jumps to the verstage and comes back, then, loads the romstage over the - * verstage space and exits to it. (note the cbfs cache is trashed on return - * from the verstage.) - * - * 2) We're already in the verstage. Verify firmware, then load the romstage and - * exits to it. - */ -void *vboot2_verify_firmware(void) -{ - void *entry; - struct vb2_working_data *wd; - - wd = init_vb2_working_data(); - - if (IS_ENABLED(CONFIG_RETURN_FROM_VERSTAGE)) { - /* load verstage from RO */ - entry = cbfs_load_stage(CBFS_DEFAULT_MEDIA, - CONFIG_CBFS_PREFIX "/verstage"); - if (entry == (void *)-1) - die("failed to load verstage"); - - /* verify and select a slot */ - stage_exit(entry); - } else { - verstage_main(); - } - - /* jump to the selected slot */ - timestamp_add_now(TS_START_COPYROM); - entry = (void *)-1; - if (vboot_is_slot_selected(wd)) { - /* RW A or B */ - struct vboot_region fw_main; - - vb2_get_selected_region(wd, &fw_main); - - if (IS_ENABLED(CONFIG_MULTIPLE_CBFS_INSTANCES)) { - cbfs_set_header_offset(fw_main.offset_addr); - entry = cbfs_load_stage(CBFS_DEFAULT_MEDIA, - CONFIG_CBFS_PREFIX "/romstage"); - } else { - struct vboot_components *fw_info; - fw_info = vboot_locate_components(&fw_main); - if (fw_info == NULL) - die("failed to locate firmware components\n"); - entry = vboot_load_stage(CONFIG_VBOOT_ROMSTAGE_INDEX, - &fw_main, fw_info); - } - } else if (vboot_is_readonly_path(wd)) { - /* RO */ - entry = cbfs_load_stage(CBFS_DEFAULT_MEDIA, - CONFIG_CBFS_PREFIX "/romstage"); - } - timestamp_add_now(TS_END_COPYROM); - - return entry; -}