aboutsummaryrefslogtreecommitdiff
path: root/src/vendorcode
diff options
context:
space:
mode:
Diffstat (limited to 'src/vendorcode')
-rw-r--r--src/vendorcode/google/chromeos/vboot2/Makefile.inc9
-rw-r--r--src/vendorcode/google/chromeos/vboot2/common.c33
-rw-r--r--src/vendorcode/google/chromeos/vboot2/misc.h3
-rw-r--r--src/vendorcode/google/chromeos/vboot2/vboot_handoff.c53
-rw-r--r--src/vendorcode/google/chromeos/vboot2/vboot_loader.c244
-rw-r--r--src/vendorcode/google/chromeos/vboot2/verstub.c107
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 fe1d237931..7a2ea24643 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 d70a108b05..beffebeba1 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 7425082064..d942d5649b 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 b84e47ef16..16261b4a02 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 0000000000..929f0cbb2b
--- /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 c4319ba256..0000000000
--- 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;
-}