diff options
Diffstat (limited to 'src/vendorcode/google')
-rw-r--r-- | src/vendorcode/google/chromeos/vboot2/Makefile.inc | 9 | ||||
-rw-r--r-- | src/vendorcode/google/chromeos/vboot2/common.c | 33 | ||||
-rw-r--r-- | src/vendorcode/google/chromeos/vboot2/misc.h | 3 | ||||
-rw-r--r-- | src/vendorcode/google/chromeos/vboot2/vboot_handoff.c | 53 | ||||
-rw-r--r-- | src/vendorcode/google/chromeos/vboot2/vboot_loader.c | 244 | ||||
-rw-r--r-- | src/vendorcode/google/chromeos/vboot2/verstub.c | 107 |
6 files changed, 265 insertions, 184 deletions
diff --git a/src/vendorcode/google/chromeos/vboot2/Makefile.inc b/src/vendorcode/google/chromeos/vboot2/Makefile.inc index fe1d23793182..7a2ea2464364 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 d70a108b059d..beffebeba168 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 7425082064c4..d942d5649bfe 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 b84e47ef1679..16261b4a0229 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 000000000000..929f0cbb2bcd --- /dev/null +++ b/src/vendorcode/google/chromeos/vboot2/vboot_loader.c @@ -0,0 +1,244 @@ +/* + * 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 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 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; + } + + /* Fill in vboot handoff structure before moving to ramstage so all + * downstream users have access to vboot results. */ + if (ENV_ROMSTAGE) + vboot_fill_handoff(); + + 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_size; + 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"); + } + + 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 c4319ba2560e..000000000000 --- 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; -} |