From bcc1d422a2508dc54737fd941336c8cc09c51de1 Mon Sep 17 00:00:00 2001 From: Daisuke Nojiri Date: Thu, 19 Jun 2014 19:16:24 -0700 Subject: 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 Original-Change-Id: I4bbd4d0452604943b376bef20ea8a258820810aa Original-Reviewed-on: https://chromium-review.googlesource.com/204522 Original-Reviewed-by: Daisuke Nojiri Original-Commit-Queue: Daisuke Nojiri Original-Tested-by: Daisuke Nojiri (cherry picked from commit a6bce0cbed34def60386f3d9aece59e739740c58) Signed-off-by: Marc Jones Change-Id: I63ddfbf463c8a83120828ec8ab994f8146f90001 Reviewed-on: http://review.coreboot.org/8160 Reviewed-by: Stefan Reinauer Tested-by: build bot (Jenkins) --- src/vendorcode/google/chromeos/Makefile.inc | 26 +++ src/vendorcode/google/chromeos/chromeos.h | 9 +- src/vendorcode/google/chromeos/vboot_handoff.c | 7 + src/vendorcode/google/chromeos/vboot_main.c | 311 +++++++++++++++++++++++++ 4 files changed, 351 insertions(+), 2 deletions(-) create mode 100644 src/vendorcode/google/chromeos/vboot_main.c (limited to 'src/vendorcode/google/chromeos') 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 +#include +#include +#include +#include +#include + +#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 **)®ion->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(;;); +} -- cgit v1.2.3