summaryrefslogtreecommitdiff
path: root/src/vendorcode
diff options
context:
space:
mode:
authorDaisuke Nojiri <dnojiri@chromium.org>2014-06-19 19:16:24 -0700
committerMarc Jones <marc.jones@se-eng.com>2015-01-27 01:43:01 +0100
commitbcc1d422a2508dc54737fd941336c8cc09c51de1 (patch)
treec5912b1551b86641d4685be56f5e4578a086e281 /src/vendorcode
parent77b1655d9bccd0c93cb1a6b86ecc98e2074504a3 (diff)
vboot2: implement select_firmware for pre-romstage verification
This patch has a basic structure of vboot2 integration. It supports only Nyans, which have bootblock architecture and romstage architecture are compatible from linker's perspective. TEST=Built with VBOOT2_VERIFY_FIRMWARE on/off. Booted Nyan Blaze. BUG=None BRANCH=none Signed-off-by: Daisuke Nojiri <dnojiri@chromium.org> Original-Change-Id: I4bbd4d0452604943b376bef20ea8a258820810aa Original-Reviewed-on: https://chromium-review.googlesource.com/204522 Original-Reviewed-by: Daisuke Nojiri <dnojiri@chromium.org> Original-Commit-Queue: Daisuke Nojiri <dnojiri@chromium.org> Original-Tested-by: Daisuke Nojiri <dnojiri@chromium.org> (cherry picked from commit a6bce0cbed34def60386f3d9aece59e739740c58) Signed-off-by: Marc Jones <marc.jones@se-eng.com> Change-Id: I63ddfbf463c8a83120828ec8ab994f8146f90001 Reviewed-on: http://review.coreboot.org/8160 Reviewed-by: Stefan Reinauer <stefan.reinauer@coreboot.org> Tested-by: build bot (Jenkins)
Diffstat (limited to 'src/vendorcode')
-rw-r--r--src/vendorcode/google/chromeos/Makefile.inc26
-rw-r--r--src/vendorcode/google/chromeos/chromeos.h9
-rw-r--r--src/vendorcode/google/chromeos/vboot_handoff.c7
-rw-r--r--src/vendorcode/google/chromeos/vboot_main.c311
4 files changed, 351 insertions, 2 deletions
diff --git a/src/vendorcode/google/chromeos/Makefile.inc b/src/vendorcode/google/chromeos/Makefile.inc
index 12d35b64c8..cb3d9a68b8 100644
--- a/src/vendorcode/google/chromeos/Makefile.inc
+++ b/src/vendorcode/google/chromeos/Makefile.inc
@@ -95,7 +95,33 @@ $(VB_LIB):
endif
ifeq ($(CONFIG_VBOOT2_VERIFY_FIRMWARE),y)
+VB_SOURCE := vboot_reference
VERSTAGE_LIB = $(obj)/vendorcode/google/chromeos/verstage.a
+
+INCLUDES += -I$(VB_SOURCE)/firmware/2lib/include
+INCLUDES += -I$(VB_SOURCE)/firmware/include
+verstage-y += vboot_main.c fmap.c chromeos.c
+
+VB_FIRMWARE_ARCH := $(ARCHDIR-$(ARCH-VERSTAGE-y))
+VB2_LIB = $(obj)/external/vboot_reference/vboot_fw2.a
+VBOOT_CFLAGS += $(patsubst -I%,-I$(top)/%,$(filter-out -include $(src)/include/kconfig.h, $(CFLAGS_verstage)))
+VBOOT_CFLAGS += $(verstage-c-ccopts)
+VBOOT_CFLAGS += -include $(top)/src/include/kconfig.h -Wno-missing-prototypes
+VBOOT_CFLAGS += -DVBOOT_DEBUG
+
+$(VB2_LIB): $(obj)/config.h
+ @printf " MAKE $(subst $(obj)/,,$(@))\n"
+ $(Q)FIRMWARE_ARCH=$(VB_FIRMWARE_ARCH) \
+ CC="$(CC_verstage)" \
+ CFLAGS="$(VBOOT_CFLAGS)" VBOOT2="y" \
+ make -C $(VB_SOURCE) \
+ BUILD=$(top)/$(dir $(VB2_LIB)) \
+ V=$(V) \
+ fwlib2
+ mv $@ $@.tmp
+ @printf " OBJCOPY $(subst $(obj)/,,$(@))\n"
+ $(OBJCOPY_verstage) --prefix-symbols=verstage_ $@.tmp $@
+
$(VERSTAGE_LIB): $$(verstage-objs)
@printf " AR $(subst $(obj)/,,$(@))\n"
$(AR_verstage) rc $@.tmp $(verstage-objs)
diff --git a/src/vendorcode/google/chromeos/chromeos.h b/src/vendorcode/google/chromeos/chromeos.h
index a2ecac849f..a799528d53 100644
--- a/src/vendorcode/google/chromeos/chromeos.h
+++ b/src/vendorcode/google/chromeos/chromeos.h
@@ -46,7 +46,7 @@ struct romstage_handoff;
/* TODO(shawnn): Remove these CONFIGs and define default weak functions
* that can be overridden in the platform / MB code. */
-#if CONFIG_VBOOT_VERIFY_FIRMWARE
+#if CONFIG_VBOOT_VERIFY_FIRMWARE || CONFIG_VBOOT2_VERIFY_FIRMWARE
/*
* This is a dual purpose routine. If dest is non-NULL the region at
* offset_addr will be read into the area pointed to by dest. If dest
@@ -67,7 +67,8 @@ static inline int vboot_get_handoff_info(void **addr, uint32_t *size)
return -1;
}
static inline int vboot_skip_display_init(void) { return 0; }
-#endif
+#endif /* CONFIG_VBOOT_VERIFY_FIRMWARE || CONFIG_VBOOT2_VERIFY_FIRMWARE */
+
int vboot_get_sw_write_protect(void);
#include "gnvs.h"
@@ -85,4 +86,8 @@ static inline void chromeos_ram_oops_init(chromeos_acpi_t *chromeos) {}
static inline void chromeos_reserve_ram_oops(struct device *dev, int idx) {}
#endif /* CONFIG_CHROMEOS_RAMOOPS */
+#if CONFIG_VBOOT2_VERIFY_FIRMWARE
+void select_firmware(void);
+#endif
+
#endif
diff --git a/src/vendorcode/google/chromeos/vboot_handoff.c b/src/vendorcode/google/chromeos/vboot_handoff.c
index 7ef2c7ee5a..7ea21ea61b 100644
--- a/src/vendorcode/google/chromeos/vboot_handoff.c
+++ b/src/vendorcode/google/chromeos/vboot_handoff.c
@@ -105,6 +105,12 @@ int __attribute((weak)) vboot_get_sw_write_protect(void)
return 0;
}
+#if CONFIG_VBOOT2_VERIFY_FIRMWARE
+
+void *vboot_get_payload(int *len) { return NULL; }
+
+#else /* CONFIG_VBOOT2_VERIFY_FIRMWARE */
+
static void *vboot_get_payload(size_t *len)
{
struct vboot_handoff *vboot_handoff;
@@ -131,6 +137,7 @@ static void *vboot_get_payload(size_t *len)
return (void *)fwc->address;
}
+#endif
static int vboot_locate_payload(struct payload *payload)
{
diff --git a/src/vendorcode/google/chromeos/vboot_main.c b/src/vendorcode/google/chromeos/vboot_main.c
new file mode 100644
index 0000000000..9779d35eea
--- /dev/null
+++ b/src/vendorcode/google/chromeos/vboot_main.c
@@ -0,0 +1,311 @@
+#include <2api.h>
+#include <2struct.h>
+#include <arch/stages.h>
+#include <cbfs.h>
+#include <console/console.h>
+#include <console/vtxprintf.h>
+#include <reset.h>
+#include <string.h>
+
+#include "chromeos.h"
+#include "fmap.h"
+
+#define VBDEBUG(format, args...) \
+ printk(BIOS_INFO, "%s():%d: " format, __func__, __LINE__, ## args)
+#define TODO_BLOCK_SIZE 8192
+#define MAX_PARSED_FW_COMPONENTS 5
+#define ROMSTAGE_INDEX 2
+
+struct component_entry {
+ uint32_t offset;
+ uint32_t size;
+} __attribute__((packed));
+
+struct components {
+ uint32_t num_components;
+ struct component_entry entries[MAX_PARSED_FW_COMPONENTS];
+} __attribute__((packed));
+
+struct vboot_region {
+ uintptr_t offset_addr;
+ int32_t size;
+};
+
+/* exports */
+
+void vb2ex_printf(const char *func, const char *fmt, ...)
+{
+ va_list args;
+
+ printk(BIOS_INFO, "VB2:%s() ", func);
+ va_start(args, fmt);
+ printk(BIOS_INFO, fmt, args);
+ va_end(args);
+
+ return;
+}
+
+int vb2ex_tpm_clear_owner(struct vb2_context *ctx)
+{
+ VBDEBUG("Clearing owner\n");
+ return VB2_ERROR_UNKNOWN;
+}
+
+int vb2ex_read_resource(struct vb2_context *ctx,
+ enum vb2_resource_index index,
+ uint32_t offset,
+ void *buf,
+ uint32_t size)
+{
+ VBDEBUG("Reading resource\n");
+ return VB2_ERROR_UNKNOWN;
+}
+
+/* locals */
+
+static void locate_region(const char *name, struct vboot_region *region)
+{
+ region->size = find_fmap_entry(name, (void **)&region->offset_addr);
+ VBDEBUG("Located %s @%x\n", name, region->offset_addr);
+}
+
+static int is_slot_a(struct vb2_context *ctx)
+{
+ return !(ctx->flags & VB2_CONTEXT_FW_SLOT_B);
+}
+
+static int in_ro(void)
+{
+ /* TODO: Implement */
+ return 1;
+}
+
+static void reboot(void)
+{
+ cpu_reset();
+}
+
+static void recovery(void)
+{
+ void *entry;
+
+ if (!in_ro())
+ reboot();
+
+ entry = cbfs_load_stage(CBFS_DEFAULT_MEDIA, "fallback/romstage");
+ if (entry != (void *)-1)
+ stage_exit(entry);
+
+ for(;;);
+}
+
+static int hash_body(struct vb2_context *ctx, struct vboot_region *fw_main)
+{
+ uint32_t expected_size;
+ uint8_t block[TODO_BLOCK_SIZE];
+ size_t block_size = sizeof(block);
+ uintptr_t offset;
+ int rv;
+
+ expected_size = fw_main->size;
+ offset= fw_main->offset_addr;
+
+ /* Start the body hash */
+ rv = vb2api_init_hash(ctx, VB2_HASH_TAG_FW_BODY, &expected_size);
+ if (rv) {
+ return rv;
+ }
+
+ /* Extend over the body */
+ while (expected_size) {
+ void *b;
+ if (block_size > expected_size)
+ block_size = expected_size;
+
+ b = vboot_get_region(offset, block_size, block);
+ if (b == NULL)
+ return VB2_ERROR_UNKNOWN;
+ rv = vb2api_extend_hash(ctx, b, block_size);
+ if (rv)
+ return rv;
+
+ expected_size -= block_size;
+ offset+= block_size;
+ }
+
+ /* Check the result */
+ rv = vb2api_check_hash(ctx);
+ if (rv) {
+ return rv;
+ }
+
+ return VB2_SUCCESS;
+}
+
+static int locate_fw_components(struct vb2_context *ctx,
+ struct vboot_region *fw_main,
+ struct components *fw_info)
+{
+ if (is_slot_a(ctx))
+ locate_region("FW_MAIN_A", fw_main);
+ else
+ locate_region("FW_MAIN_B", fw_main);
+ if (fw_main->size < 0)
+ return 1;
+
+ if (vboot_get_region(fw_main->offset_addr,
+ sizeof(*fw_info), fw_info) == NULL)
+ return 1;
+ return 0;
+}
+
+static struct cbfs_stage *load_stage(struct vb2_context *ctx,
+ int stage_index,
+ struct vboot_region *fw_main,
+ struct components *fw_info)
+{
+ struct cbfs_stage *stage;
+ uint32_t fc_addr;
+ uint32_t fc_size;
+
+ /* Check for invalid address. */
+ fc_addr = fw_main->offset_addr + fw_info->entries[stage_index].offset;
+ fc_size = fw_info->entries[stage_index].size;
+ if (fc_addr == 0 || fc_size == 0) {
+ VBDEBUG("romstage address invalid.\n");
+ return NULL;
+ }
+
+ /* Loading to cbfs cache. This stage data must be retained until it's
+ * decompressed. */
+ stage = vboot_get_region(fc_addr, fc_size, NULL);
+
+ if (stage == NULL) {
+ VBDEBUG("Unable to load a stage.\n");
+ return NULL;
+ }
+
+ return stage;
+}
+
+static void enter_stage(struct cbfs_stage *stage)
+{
+ /* Stages rely the below clearing so that the bss is initialized. */
+ memset((void *) (uintptr_t)stage->load, 0, stage->memlen);
+
+ if (cbfs_decompress(stage->compression,
+ (unsigned char *)stage + sizeof(*stage),
+ (void *) (uintptr_t) stage->load,
+ stage->len))
+ return;
+
+ VBDEBUG("Jumping to entry @%llx.\n", stage->entry);
+ stage_exit((void *)(uintptr_t)stage->entry);
+}
+
+/**
+ * Save non-volatile and/or secure data if needed.
+ */
+static void save_if_needed(struct vb2_context *ctx)
+{
+ if (ctx->flags & VB2_CONTEXT_NVDATA_CHANGED) {
+ VBDEBUG("Saving nvdata\n");
+ //save_vbnv(ctx->nvdata);
+ ctx->flags &= ~VB2_CONTEXT_NVDATA_CHANGED;
+ }
+ if (ctx->flags & VB2_CONTEXT_SECDATA_CHANGED) {
+ VBDEBUG("Saving secdata\n");
+ //antirollback_write_space_firmware(ctx);
+ ctx->flags &= ~VB2_CONTEXT_SECDATA_CHANGED;
+ }
+}
+
+void __attribute__((noinline)) select_firmware(void)
+{
+ struct vb2_context ctx;
+ uint8_t *workbuf = (uint8_t *)CONFIG_VBOOT_WORK_BUFFER_ADDRESS;
+ struct vboot_region fw_main;
+ struct components fw_info;
+ struct cbfs_stage *stage;
+ int rv;
+
+ console_init();
+
+ /* Set up context */
+ memset(&ctx, 0, sizeof(ctx));
+ ctx.workbuf = workbuf;
+ ctx.workbuf_size = CONFIG_VBOOT_WORK_BUFFER_SIZE;
+ memset(ctx.workbuf, 0, ctx.workbuf_size);
+
+ /* Read nvdata from a non-volatile storage */
+ //read_vbnv(ctx.nvdata);
+
+ /* Read secdata from TPM. Initialize TPM if secdata not found. We don't
+ * check the return value here because vb2api_fw_phase1 will catch
+ * invalid secdata and tell us what to do (=reboot). */
+ //antirollback_read_space_firmware(&ctx);
+
+ //if (get_developer_mode_switch())
+ // ctx.flags |= VB2_CONTEXT_FORCE_DEVELOPER_MODE;
+ //if (get_recovery_mode_switch()) {
+ // clear_recovery_mode_switch();
+ // ctx.flags |= VB2_CONTEXT_FORCE_RECOVERY_MODE;
+ //}
+
+ /* Do early init */
+ VBDEBUG("Phase 1\n");
+ rv = vb2api_fw_phase1(&ctx);
+ if (rv) {
+ VBDEBUG("Recovery requested (%x)\n", rv);
+ /* If we need recovery mode, leave firmware selection now */
+ save_if_needed(&ctx);
+ recovery();
+ }
+
+ /* Determine which firmware slot to boot */
+ VBDEBUG("Phase 2\n");
+ rv = vb2api_fw_phase2(&ctx);
+ if (rv) {
+ VBDEBUG("Reboot requested (%x)\n", rv);
+ save_if_needed(&ctx);
+ reboot();
+ }
+
+ /* Try that slot */
+ VBDEBUG("Phase 3\n");
+ rv = vb2api_fw_phase3(&ctx);
+ if (rv) {
+ VBDEBUG("Reboot requested (%x)\n", rv);
+ save_if_needed(&ctx);
+ reboot();
+ }
+
+ VBDEBUG("Phase 4\n");
+ rv = locate_fw_components(&ctx, &fw_main, &fw_info);
+ if (rv) {
+ VBDEBUG("Failed to locate firmware components\n");
+ reboot();
+ }
+ rv = hash_body(&ctx, &fw_main);
+ stage = load_stage(&ctx, ROMSTAGE_INDEX, &fw_main, &fw_info);
+ if (stage == NULL) {
+ VBDEBUG("Failed to load stage\n");
+ reboot();
+ }
+ save_if_needed(&ctx);
+ if (rv) {
+ VBDEBUG("Reboot requested (%x)\n", rv);
+ reboot();
+ }
+
+ /* TODO: Do we need to lock secdata? */
+ VBDEBUG("Locking TPM\n");
+
+ /* Load next stage and jump to it */
+ VBDEBUG("Jumping to rw-romstage @%llx\n", stage->entry);
+ enter_stage(stage);
+
+ /* Shouldn't reach here */
+ VBDEBUG("Halting\n");
+ for(;;);
+}