From 742fc8d768829eaa3ff1048a4b101f7fad8c8ab7 Mon Sep 17 00:00:00 2001 From: Daisuke Nojiri Date: Fri, 10 Oct 2014 10:51:06 -0700 Subject: vboot: move vboot files to designated directory This moves vboot1 and vboot2 files to their designated directory. Common code stays in vendorcode/google/chromeos. BUG=none BRANCH=none TEST=built cosmos, veyron_pinky, rush_ryu, nyan_blaze, samus, parrot, lumpy, daisy_spring, and storm. Signed-off-by: Daisuke Nojiri Original-Change-Id: Ia9fb41ba30930b79b222269acfade7ef44b23626 Original-Reviewed-on: https://chromium-review.googlesource.com/222874 Original-Reviewed-by: Daisuke Nojiri Original-Commit-Queue: Daisuke Nojiri Original-Tested-by: Daisuke Nojiri (cherry picked from commit cbfef9ad40776d890e2149b9db788fe0b387d210) Signed-off-by: Aaron Durbin Change-Id: Ia73696accfd93cc14ca83516fa77f87331faef51 Reviewed-on: http://review.coreboot.org/9433 Tested-by: build bot (Jenkins) Reviewed-by: Patrick Georgi --- src/vendorcode/google/chromeos/Kconfig | 47 +-- src/vendorcode/google/chromeos/Makefile.inc | 97 +---- src/vendorcode/google/chromeos/antirollback.c | 329 ---------------- src/vendorcode/google/chromeos/chromeos.c | 183 +-------- src/vendorcode/google/chromeos/chromeos.h | 99 +---- src/vendorcode/google/chromeos/memlayout.h | 47 --- src/vendorcode/google/chromeos/symbols.h | 32 -- src/vendorcode/google/chromeos/vboot1/Kconfig | 34 ++ src/vendorcode/google/chromeos/vboot1/Makefile.inc | 74 ++++ .../google/chromeos/vboot1/vboot_loader.c | 416 +++++++++++++++++++++ .../google/chromeos/vboot1/vboot_wrapper.c | 266 +++++++++++++ src/vendorcode/google/chromeos/vboot2/Kconfig | 43 +++ src/vendorcode/google/chromeos/vboot2/Makefile.inc | 60 +++ .../google/chromeos/vboot2/antirollback.c | 329 ++++++++++++++++ src/vendorcode/google/chromeos/vboot2/common.c | 70 ++++ src/vendorcode/google/chromeos/vboot2/memlayout.h | 47 +++ src/vendorcode/google/chromeos/vboot2/misc.h | 72 ++++ src/vendorcode/google/chromeos/vboot2/symbols.h | 32 ++ .../google/chromeos/vboot2/vboot_handoff.c | 175 +++++++++ src/vendorcode/google/chromeos/vboot2/verstage.c | 252 +++++++++++++ src/vendorcode/google/chromeos/vboot2/verstage.ld | 58 +++ src/vendorcode/google/chromeos/vboot2/verstub.c | 97 +++++ src/vendorcode/google/chromeos/vboot_common.c | 122 ++++++ src/vendorcode/google/chromeos/vboot_common.h | 55 +++ src/vendorcode/google/chromeos/vboot_handoff.c | 174 --------- src/vendorcode/google/chromeos/vboot_handoff.h | 11 + src/vendorcode/google/chromeos/vboot_loader.c | 416 --------------------- src/vendorcode/google/chromeos/vboot_wrapper.c | 266 ------------- src/vendorcode/google/chromeos/verstage.c | 251 ------------- src/vendorcode/google/chromeos/verstage.ld | 58 --- src/vendorcode/google/chromeos/verstub.c | 96 ----- 31 files changed, 2236 insertions(+), 2072 deletions(-) delete mode 100644 src/vendorcode/google/chromeos/antirollback.c delete mode 100644 src/vendorcode/google/chromeos/memlayout.h delete mode 100644 src/vendorcode/google/chromeos/symbols.h create mode 100644 src/vendorcode/google/chromeos/vboot1/Kconfig create mode 100644 src/vendorcode/google/chromeos/vboot1/Makefile.inc create mode 100644 src/vendorcode/google/chromeos/vboot1/vboot_loader.c create mode 100644 src/vendorcode/google/chromeos/vboot1/vboot_wrapper.c create mode 100644 src/vendorcode/google/chromeos/vboot2/Kconfig create mode 100644 src/vendorcode/google/chromeos/vboot2/Makefile.inc create mode 100644 src/vendorcode/google/chromeos/vboot2/antirollback.c create mode 100644 src/vendorcode/google/chromeos/vboot2/common.c create mode 100644 src/vendorcode/google/chromeos/vboot2/memlayout.h create mode 100644 src/vendorcode/google/chromeos/vboot2/misc.h create mode 100644 src/vendorcode/google/chromeos/vboot2/symbols.h create mode 100644 src/vendorcode/google/chromeos/vboot2/vboot_handoff.c create mode 100644 src/vendorcode/google/chromeos/vboot2/verstage.c create mode 100644 src/vendorcode/google/chromeos/vboot2/verstage.ld create mode 100644 src/vendorcode/google/chromeos/vboot2/verstub.c create mode 100644 src/vendorcode/google/chromeos/vboot_common.c create mode 100644 src/vendorcode/google/chromeos/vboot_common.h delete mode 100644 src/vendorcode/google/chromeos/vboot_handoff.c delete mode 100644 src/vendorcode/google/chromeos/vboot_loader.c delete mode 100644 src/vendorcode/google/chromeos/vboot_wrapper.c delete mode 100644 src/vendorcode/google/chromeos/verstage.c delete mode 100644 src/vendorcode/google/chromeos/verstage.ld delete mode 100644 src/vendorcode/google/chromeos/verstub.c (limited to 'src/vendorcode') diff --git a/src/vendorcode/google/chromeos/Kconfig b/src/vendorcode/google/chromeos/Kconfig index 8826a148e8..62a415b813 100644 --- a/src/vendorcode/google/chromeos/Kconfig +++ b/src/vendorcode/google/chromeos/Kconfig @@ -94,22 +94,6 @@ config FLASHMAP_OFFSET help Offset of flash map in firmware image -config VBOOT_VERIFY_FIRMWARE - bool "Verify firmware with vboot." - default n - select RELOCATABLE_MODULES - help - Enabling VBOOT_VERIFY_FIRMWARE will use vboot to verify the ramstage - and boot loader. - -config VBOOT2_VERIFY_FIRMWARE - bool "Firmware Verification with vboot2" - default n - depends on CHROMEOS && HAVE_HARD_RESET - help - Enabling VBOOT2_VERIFY_FIRMWARE will use vboot2 to verify the romstage - and boot loader. - config EC_SOFTWARE_SYNC bool "Enable EC software sync" default n @@ -141,16 +125,6 @@ config VIRTUAL_DEV_SWITCH help Whether this platform has a virtual developer switch. -config RETURN_FROM_VERSTAGE - bool "return from verstage" - default n - depends on VBOOT2_VERIFY_FIRMWARE - help - If this is set, the verstage returns back to the bootblock instead of - exits to the romstage so that the verstage space can be reused by the - romstage. Useful if a ram space is too small to fit both the verstage - and the romstage. - # These VBOOT_X_INDEX are the position of X in FW_MAIN_A/B region. The index # table is created by cros_bundle_firmware at build time based on the positions # of the blobs listed in fmap.dts and stored at the top of FW_MAIN_A/B region. @@ -164,14 +138,6 @@ config VBOOT_BOOT_LOADER_INDEX This is the index of the bootloader component in the verified firmware block. -config VBOOT_ROMSTAGE_INDEX - hex - default 2 - depends on VBOOT2_VERIFY_FIRMWARE - help - This is the index of the romstage component in the verified - firmware block. - config VBOOT_RAMSTAGE_INDEX hex "Ramstage component index" default 1 @@ -180,14 +146,6 @@ config VBOOT_RAMSTAGE_INDEX This is the index of the ramstage component in the verified firmware block. -config VBOOT_REFCODE_INDEX - hex "Reference code firmware index" - default 1 - depends on VBOOT_VERIFY_FIRMWARE - help - This is the index of the reference code component in the verified - firmware block. - config NO_TPM_RESUME bool default n @@ -196,5 +154,8 @@ config NO_TPM_RESUME boards, booting Windows will break if the TPM resume command is sent during an S3 resume. -endif +source src/vendorcode/google/chromeos/vboot1/Kconfig +source src/vendorcode/google/chromeos/vboot2/Kconfig + +endif # CHROMEOS endmenu diff --git a/src/vendorcode/google/chromeos/Makefile.inc b/src/vendorcode/google/chromeos/Makefile.inc index da1db8bc4d..fbd12fbad2 100644 --- a/src/vendorcode/google/chromeos/Makefile.inc +++ b/src/vendorcode/google/chromeos/Makefile.inc @@ -37,101 +37,8 @@ else CFLAGS_common += -DMOCK_TPM=0 endif -ifeq ($(CONFIG_VBOOT_VERIFY_FIRMWARE),y) -romstage-y += vboot_helper.c -ramstage-y += vboot_helper.c -romstage-y += vboot_loader.c -rmodules_$(ARCH-romstage-y)-y += vboot_wrapper.c - -ifneq ($(CONFIG_SPI_FLASH_MEMORY_MAPPED),y) -VBOOT_MAKEFLAGS = REGION_READ=1 -endif - -VB_LIB = $(obj)/external/vboot_reference/vboot_fw.a -# Currently, vboot comes into picture only during the romstage, thus -# is compiled for being used in romstage only. Since, we are splitting -# up all components in one of the three stages of coreboot, vboot seems -# most logical to fall under the romstage. Thus, all references to arch -# and other compiler stuff for vboot is using the romstage arch. -VB_FIRMWARE_ARCH := $(ARCHDIR-$(ARCH-romstage-y)) -VB_SOURCE := vboot_reference - -# Add the vboot include paths. -CPPFLAGS_common += -I$(VB_SOURCE)/firmware/include - -VBOOT_STUB_ELF = $(obj)/vendorcode/google/chromeos/vbootstub.elf -VBOOT_STUB = $(VBOOT_STUB_ELF).rmod - -# Dependency for the vboot rmodules. Ordering matters. -VBOOT_STUB_DEPS += $(obj)/vendorcode/google/chromeos/vboot_wrapper.rmodules_$(ARCH-romstage-y).o -VBOOT_STUB_DEPS += $(obj)/lib/memcmp.rmodules_$(ARCH-romstage-y).o -VBOOT_STUB_DEPS += $(obj)/arch/x86/lib/memset.rmodules_$(ARCH-romstage-y).o -VBOOT_STUB_DEPS += $(obj)/arch/x86/lib/memcpy.rmodules_$(ARCH-romstage-y).o -VBOOT_STUB_DEPS += $(VB_LIB) -# Remove the '-include' option since that will break vboot's build and ensure -# vboot_reference can get to coreboot's include files. -VBOOT_CFLAGS += $(patsubst -I%,-I$(top)/%,$(filter-out -include $(src)/include/kconfig.h, $(CFLAGS_romstage) $(CPPFLAGS_romstage))) -VBOOT_CFLAGS += -DVBOOT_DEBUG -VBOOT_CFLAGS += $(rmodules_$(ARCH-ROMSTAGE-y)-c-ccopts) - -# Link the vbootstub module with a 64KiB-byte heap. -$(eval $(call rmodule_link,$(VBOOT_STUB_ELF), $(VBOOT_STUB_DEPS), 0x10000,$(ARCH-romstage-y))) - -# Build vboot library without the default includes from coreboot proper. -$(VB_LIB): - @printf " MAKE $(subst $(obj)/,,$(@))\n" - $(Q)$(MAKE) -C $(VB_SOURCE) \ - CC="$(CC_romstage)" \ - CFLAGS="$(VBOOT_CFLAGS)" \ - $(VBOOT_MAKEFLAGS) \ - FIRMWARE_ARCH=$(VB_FIRMWARE_ARCH) \ - BUILD=$(top)/$(dir $(VB_LIB)) \ - V=$(V) \ - fwlib - -endif - -ifeq ($(CONFIG_VBOOT2_VERIFY_FIRMWARE),y) VB_SOURCE := vboot_reference +subdirs-$(CONFIG_VBOOT_VERIFY_FIRMWARE) += vboot1 +subdirs-$(CONFIG_VBOOT2_VERIFY_FIRMWARE) += vboot2 CPPFLAGS_common += -I$(VB_SOURCE)/firmware/2lib/include CPPFLAGS_common += -I$(VB_SOURCE)/firmware/include - -verstage-generic-ccopts += -D__PRE_RAM__ -D__VERSTAGE__ - -ifeq ($(CONFIG_RETURN_FROM_VERSTAGE),y) -bootblock-y += verstub.c chromeos.c -else -verstage-y += verstub.c -endif -verstage-y += verstage.c fmap.c chromeos.c -verstage-y += antirollback.c -verstage-$(CONFIG_CHROMEOS_VBNV_CMOS) += vbnv_cmos.c -verstage-$(CONFIG_CHROMEOS_VBNV_EC) += vbnv_ec.c -verstage-$(CONFIG_CHROMEOS_VBNV_FLASH) += vbnv_flash.c -romstage-y += vboot_handoff.c - -verstage-y += verstage.ld - -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) $(CPPFLAGS_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)$(MAKE) -C $(VB_SOURCE) \ - CC="$(CC_verstage)" \ - CFLAGS="$(VBOOT_CFLAGS)" VBOOT2="y" \ - FIRMWARE_ARCH=$(VB_FIRMWARE_ARCH) \ - BUILD=$(top)/$(dir $(VB2_LIB)) \ - V=$(V) \ - fwlib2 - -VERSTAGE_ELF = $(objcbfs)/verstage.elf -cbfs-files-y += $(call strip_quotes,$(CONFIG_CBFS_PREFIX))/verstage -fallback/verstage-file = $(VERSTAGE_ELF) -fallback/verstage-type = stage -fallback/verstage-compression = none -endif # CONFIG_VBOOT2_VERIFY_FIRMWARE diff --git a/src/vendorcode/google/chromeos/antirollback.c b/src/vendorcode/google/chromeos/antirollback.c deleted file mode 100644 index bb547b51bc..0000000000 --- a/src/vendorcode/google/chromeos/antirollback.c +++ /dev/null @@ -1,329 +0,0 @@ -/* Copyright (c) 2013 The Chromium OS Authors. All rights reserved. - * Use of this source code is governed by a BSD-style license that can be - * found in the LICENSE file. - * - * Functions for querying, manipulating and locking rollback indices - * stored in the TPM NVRAM. - */ - -#include <2api.h> -#include <2sysincludes.h> -#include -#include -#include - -#ifndef offsetof -#define offsetof(A,B) __builtin_offsetof(A,B) -#endif - -#ifdef FOR_TEST -#include -#define VBDEBUG(format, args...) printf(format, ## args) -#else -#include -#define VBDEBUG(format, args...) \ - printk(BIOS_INFO, "%s():%d: " format, __func__, __LINE__, ## args) -#endif - -#define RETURN_ON_FAILURE(tpm_cmd) do { \ - uint32_t result_; \ - if ((result_ = (tpm_cmd)) != TPM_SUCCESS) { \ - VBDEBUG("Antirollback: %08x returned by " #tpm_cmd \ - "\n", (int)result_); \ - return result_; \ - } \ - } while (0) - -uint32_t tpm_clear_and_reenable(void) -{ - VBDEBUG("TPM: Clear and re-enable\n"); - RETURN_ON_FAILURE(tlcl_force_clear()); - RETURN_ON_FAILURE(tlcl_set_enable()); - RETURN_ON_FAILURE(tlcl_set_deactivated(0)); - - return TPM_SUCCESS; -} - -uint32_t safe_write(uint32_t index, const void *data, uint32_t length) -{ - uint32_t result = tlcl_write(index, data, length); - if (result == TPM_E_MAXNVWRITES) { - RETURN_ON_FAILURE(tpm_clear_and_reenable()); - return tlcl_write(index, data, length); - } else { - return result; - } -} - -uint32_t safe_define_space(uint32_t index, uint32_t perm, uint32_t size) -{ - uint32_t result = tlcl_define_space(index, perm, size); - if (result == TPM_E_MAXNVWRITES) { - RETURN_ON_FAILURE(tpm_clear_and_reenable()); - return tlcl_define_space(index, perm, size); - } else { - return result; - } -} - -static uint32_t read_space_firmware(struct vb2_context *ctx) -{ - int attempts = 3; - - while (attempts--) { - RETURN_ON_FAILURE(tlcl_read(FIRMWARE_NV_INDEX, ctx->secdata, - VB2_SECDATA_SIZE)); - - if (vb2api_secdata_check(ctx) == VB2_SUCCESS) - return TPM_SUCCESS; - - VBDEBUG("TPM: %s() - bad CRC\n", __func__); - } - - VBDEBUG("TPM: %s() - too many bad CRCs, giving up\n", __func__); - return TPM_E_CORRUPTED_STATE; -} - -static uint32_t write_secdata(uint32_t index, - const uint8_t *secdata, - uint32_t len) -{ - uint8_t sd[32]; - uint32_t rv; - int attempts = 3; - - if (len > sizeof(sd)) { - VBDEBUG("TPM: %s() - data is too large\n", __func__); - return TPM_E_WRITE_FAILURE; - } - - while (attempts--) { - rv = safe_write(index, secdata, len); - /* Can't write, not gonna try again */ - if (rv != TPM_SUCCESS) - return rv; - - /* Read it back to be sure it got the right values. */ - rv = tlcl_read(index, sd, len); - if (rv == TPM_SUCCESS && memcmp(secdata, sd, len) == 0) - return rv; - - VBDEBUG("TPM: %s() failed. trying again\n", __func__); - /* Try writing it again. Maybe it was garbled on the way out. */ - } - - VBDEBUG("TPM: %s() - too many failures, giving up\n", __func__); - - return TPM_E_CORRUPTED_STATE; -} - -uint32_t factory_initialize_tpm(struct vb2_context *ctx) -{ - TPM_PERMANENT_FLAGS pflags; - uint32_t result; - /* this is derived from rollback_index.h of vboot_reference. see struct - * RollbackSpaceKernel for details. */ - static const uint8_t secdata_kernel[] = { - 0x02, - 0x4C, 0x57, 0x52, 0x47, - 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, - 0xE8, - }; - - VBDEBUG("TPM: factory initialization\n"); - - /* - * Do a full test. This only happens the first time the device is - * turned on in the factory, so performance is not an issue. This is - * almost certainly not necessary, but it gives us more confidence - * about some code paths below that are difficult to - * test---specifically the ones that set lifetime flags, and are only - * executed once per physical TPM. - */ - result = tlcl_self_test_full(); - if (result != TPM_SUCCESS) - return result; - - result = tlcl_get_permanent_flags(&pflags); - if (result != TPM_SUCCESS) - return result; - - /* - * TPM may come from the factory without physical presence finalized. - * Fix if necessary. - */ - VBDEBUG("TPM: physicalPresenceLifetimeLock=%d\n", - pflags.physicalPresenceLifetimeLock); - if (!pflags.physicalPresenceLifetimeLock) { - VBDEBUG("TPM: Finalizing physical presence\n"); - RETURN_ON_FAILURE(tlcl_finalize_physical_presence()); - } - - /* - * The TPM will not enforce the NV authorization restrictions until the - * execution of a TPM_NV_DefineSpace with the handle of - * TPM_NV_INDEX_LOCK. Here we create that space if it doesn't already - * exist. */ - VBDEBUG("TPM: nvLocked=%d\n", pflags.nvLocked); - if (!pflags.nvLocked) { - VBDEBUG("TPM: Enabling NV locking\n"); - RETURN_ON_FAILURE(tlcl_set_nv_locked()); - } - - /* Clear TPM owner, in case the TPM is already owned for some reason. */ - VBDEBUG("TPM: Clearing owner\n"); - RETURN_ON_FAILURE(tpm_clear_and_reenable()); - - /* Define the backup space. No need to initialize it, though. */ - RETURN_ON_FAILURE(safe_define_space(BACKUP_NV_INDEX, - TPM_NV_PER_PPWRITE, - VB2_NVDATA_SIZE)); - - /* Define and initialize the kernel space */ - RETURN_ON_FAILURE(safe_define_space(KERNEL_NV_INDEX, - TPM_NV_PER_PPWRITE, - sizeof(secdata_kernel))); - RETURN_ON_FAILURE(write_secdata(KERNEL_NV_INDEX, - secdata_kernel, - sizeof(secdata_kernel))); - - /* Defines and sets vb2 secdata space */ - vb2api_secdata_create(ctx); - RETURN_ON_FAILURE(safe_define_space(FIRMWARE_NV_INDEX, - TPM_NV_PER_GLOBALLOCK | - TPM_NV_PER_PPWRITE, - VB2_SECDATA_SIZE)); - RETURN_ON_FAILURE(write_secdata(FIRMWARE_NV_INDEX, - ctx->secdata, - VB2_SECDATA_SIZE)); - - VBDEBUG("TPM: factory initialization successful\n"); - - return TPM_SUCCESS; -} - -/* - * SetupTPM starts the TPM and establishes the root of trust for the - * anti-rollback mechanism. SetupTPM can fail for three reasons. 1 A bug. 2 a - * TPM hardware failure. 3 An unexpected TPM state due to some attack. In - * general we cannot easily distinguish the kind of failure, so our strategy is - * to reboot in recovery mode in all cases. The recovery mode calls SetupTPM - * again, which executes (almost) the same sequence of operations. There is a - * good chance that, if recovery mode was entered because of a TPM failure, the - * failure will repeat itself. (In general this is impossible to guarantee - * because we have no way of creating the exact TPM initial state at the - * previous boot.) In recovery mode, we ignore the failure and continue, thus - * giving the recovery kernel a chance to fix things (that's why we don't set - * bGlobalLock). The choice is between a knowingly insecure device and a - * bricked device. - * - * As a side note, observe that we go through considerable hoops to avoid using - * the STCLEAR permissions for the index spaces. We do this to avoid writing - * to the TPM flashram at every reboot or wake-up, because of concerns about - * the durability of the NVRAM. - */ -uint32_t setup_tpm(struct vb2_context *ctx) -{ - uint8_t disable; - uint8_t deactivated; - uint32_t result; - - RETURN_ON_FAILURE(tlcl_lib_init()); - -#ifdef TEGRA_SOFT_REBOOT_WORKAROUND - result = tlcl_startup(); - if (result == TPM_E_INVALID_POSTINIT) { - /* - * Some prototype hardware doesn't reset the TPM on a CPU - * reset. We do a hard reset to get around this. - */ - VBDEBUG("TPM: soft reset detected\n", result); - return TPM_E_MUST_REBOOT; - } else if (result != TPM_SUCCESS) { - VBDEBUG("TPM: tlcl_startup returned %08x\n", result); - return result; - } -#else - RETURN_ON_FAILURE(tlcl_startup()); -#endif - - /* - * Some TPMs start the self test automatically at power on. In that case - * we don't need to call ContinueSelfTest. On some (other) TPMs, - * continue_self_test may block. In that case, we definitely don't want - * to call it here. For TPMs in the intersection of these two sets, we - * are screwed. (In other words: TPMs that require manually starting the - * self-test AND block will have poor performance until we split - * tlcl_send_receive() into send() and receive(), and have a state - * machine to control setup.) - * - * This comment is likely to become obsolete in the near future, so - * don't trust it. It may have not been updated. - */ -#ifdef TPM_MANUAL_SELFTEST -#ifdef TPM_BLOCKING_CONTINUESELFTEST -#warning "lousy TPM!" -#endif - RETURN_ON_FAILURE(tlcl_continue_self_test()); -#endif - result = tlcl_assert_physical_presence(); - if (result != TPM_SUCCESS) { - /* - * It is possible that the TPM was delivered with the physical - * presence command disabled. This tries enabling it, then - * tries asserting PP again. - */ - RETURN_ON_FAILURE(tlcl_physical_presence_cmd_enable()); - RETURN_ON_FAILURE(tlcl_assert_physical_presence()); - } - - /* Check that the TPM is enabled and activated. */ - RETURN_ON_FAILURE(tlcl_get_flags(&disable, &deactivated, NULL)); - if (disable || deactivated) { - VBDEBUG("TPM: disabled (%d) or deactivated (%d). Fixing...\n", - disable, deactivated); - RETURN_ON_FAILURE(tlcl_set_enable()); - RETURN_ON_FAILURE(tlcl_set_deactivated(0)); - VBDEBUG("TPM: Must reboot to re-enable\n"); - return TPM_E_MUST_REBOOT; - } - - VBDEBUG("TPM: SetupTPM() succeeded\n"); - return TPM_SUCCESS; -} - -uint32_t antirollback_read_space_firmware(struct vb2_context *ctx) -{ - uint32_t rv; - - rv = setup_tpm(ctx); - if (rv) - return rv; - - /* Read the firmware space. */ - rv = read_space_firmware(ctx); - if (rv == TPM_E_BADINDEX) { - /* - * This seems the first time we've run. Initialize the TPM. - */ - VBDEBUG("TPM: Not initialized yet.\n"); - RETURN_ON_FAILURE(factory_initialize_tpm(ctx)); - } else if (rv != TPM_SUCCESS) { - VBDEBUG("TPM: Firmware space in a bad state; giving up.\n"); - //RETURN_ON_FAILURE(factory_initialize_tpm(ctx)); - return TPM_E_CORRUPTED_STATE; - } - - return TPM_SUCCESS; -} - -uint32_t antirollback_write_space_firmware(struct vb2_context *ctx) -{ - return write_secdata(FIRMWARE_NV_INDEX, ctx->secdata, VB2_SECDATA_SIZE); -} - -uint32_t antirollback_lock_space_firmware() -{ - return tlcl_set_global_lock(); -} diff --git a/src/vendorcode/google/chromeos/chromeos.c b/src/vendorcode/google/chromeos/chromeos.c index c4d651a29b..437e128e7b 100644 --- a/src/vendorcode/google/chromeos/chromeos.c +++ b/src/vendorcode/google/chromeos/chromeos.c @@ -20,18 +20,11 @@ #include #include #include "chromeos.h" -#if CONFIG_VBOOT_VERIFY_FIRMWARE || CONFIG_VBOOT2_VERIFY_FIRMWARE -#include "fmap.h" -#include "symbols.h" -#include "vboot_handoff.h" -#include -#endif #include #include #include #include -#if CONFIG_VBOOT_VERIFY_FIRMWARE static int vboot_enable_developer(void) { struct vboot_handoff *vbho; @@ -58,10 +51,18 @@ static int vboot_enable_recovery(void) return !!(vbho->init_params.out_flags & VB_INIT_OUT_ENABLE_RECOVERY); } -#else -static inline int vboot_enable_developer(void) { return 0; } -static inline int vboot_enable_recovery(void) { return 0; } -#endif + +int vboot_skip_display_init(void) +{ + struct vboot_handoff *vbho; + + vbho = cbmem_find(CBMEM_ID_VBOOT_HANDOFF); + + if (vbho == NULL) + return 0; + + return !(vbho->init_params.out_flags & VB_INIT_OUT_ENABLE_DISPLAY); +} int developer_mode_enabled(void) { @@ -92,22 +93,6 @@ int __attribute__((weak)) clear_recovery_mode_switch(void) return 0; } -int vboot_skip_display_init(void) -{ -#if CONFIG_VBOOT_VERIFY_FIRMWARE - struct vboot_handoff *vbho; - - vbho = cbmem_find(CBMEM_ID_VBOOT_HANDOFF); - - if (vbho == NULL) - return 0; - - return !(vbho->init_params.out_flags & VB_INIT_OUT_ENABLE_DISPLAY); -#else - return 0; -#endif -} - #ifdef __ROMSTAGE__ void __attribute__((weak)) save_chromeos_gpios(void) { @@ -120,147 +105,3 @@ int __attribute((weak)) vboot_get_sw_write_protect(void) return 0; } #endif - -#if CONFIG_VBOOT_VERIFY_FIRMWARE || CONFIG_VBOOT2_VERIFY_FIRMWARE -void vboot_locate_region(const char *name, struct vboot_region *region) -{ - region->size = find_fmap_entry(name, (void **)®ion->offset_addr); -} - -void *vboot_get_region(uintptr_t offset_addr, size_t size, void *dest) -{ - if (IS_ENABLED(CONFIG_SPI_FLASH_MEMORY_MAPPED)) { - if (dest != NULL) - return memcpy(dest, (void *)offset_addr, size); - else - return (void *)offset_addr; - } else { - struct cbfs_media default_media, *media = &default_media; - void *cache; - - init_default_cbfs_media(media); - media->open(media); - if (dest != NULL) { - cache = dest; - if (media->read(media, dest, offset_addr, size) != size) - cache = NULL; - } else { - cache = media->map(media, offset_addr, size); - if (cache == CBFS_MEDIA_INVALID_MAP_ADDRESS) - cache = NULL; - } - media->close(media); - return cache; - } -} - -int vboot_get_handoff_info(void **addr, uint32_t *size) -{ - struct vboot_handoff *vboot_handoff; - - vboot_handoff = cbmem_find(CBMEM_ID_VBOOT_HANDOFF); - - if (vboot_handoff == NULL) - return -1; - - *addr = vboot_handoff; - *size = sizeof(*vboot_handoff); - return 0; -} - -/* This will leak a mapping of a fw region */ -struct vboot_components *vboot_locate_components(struct vboot_region *region) -{ - size_t req_size; - struct vboot_components *vbc; - - req_size = sizeof(*vbc); - req_size += sizeof(struct vboot_component_entry) * - MAX_PARSED_FW_COMPONENTS; - - vbc = vboot_get_region(region->offset_addr, req_size, NULL); - if (vbc && vbc->num_components > MAX_PARSED_FW_COMPONENTS) - vbc = NULL; - - return vbc; -} - -void *vboot_get_payload(int *len) -{ - struct vboot_handoff *vboot_handoff; - struct firmware_component *fwc; - - vboot_handoff = cbmem_find(CBMEM_ID_VBOOT_HANDOFF); - - if (vboot_handoff == NULL) - return NULL; - - if (CONFIG_VBOOT_BOOT_LOADER_INDEX >= MAX_PARSED_FW_COMPONENTS) { - printk(BIOS_ERR, "Invalid boot loader index: %d\n", - CONFIG_VBOOT_BOOT_LOADER_INDEX); - return NULL; - } - - fwc = &vboot_handoff->components[CONFIG_VBOOT_BOOT_LOADER_INDEX]; - - /* If payload size is zero fall back to cbfs path. */ - if (fwc->size == 0) - return NULL; - - if (len != NULL) - *len = fwc->size; - - printk(BIOS_DEBUG, "Booting 0x%x byte verified payload at 0x%08x.\n", - fwc->size, fwc->address); - - /* This will leak a mapping. */ - return vboot_get_region(fwc->address, fwc->size, NULL); -} -#endif - -#if CONFIG_VBOOT2_VERIFY_FIRMWARE -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; -} - -void vboot_reboot(void) -{ - hard_reset(); - die("failed to reboot"); -} - -#endif diff --git a/src/vendorcode/google/chromeos/chromeos.h b/src/vendorcode/google/chromeos/chromeos.h index ed6c75bd57..5ba54571a5 100644 --- a/src/vendorcode/google/chromeos/chromeos.h +++ b/src/vendorcode/google/chromeos/chromeos.h @@ -23,6 +23,8 @@ #include #include #include +#include "vboot_common.h" +#include "vboot2/misc.h" /*for mainboard use only*/ void setup_chromeos_gpios(void); @@ -47,54 +49,14 @@ static inline void elog_add_boot_reason(void) { return; } 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 || CONFIG_VBOOT2_VERIFY_FIRMWARE -struct vboot_region { - uintptr_t offset_addr; - int32_t size; -}; - -/* - * The vboot handoff structure keeps track of a maximum number of firmware - * components in the verfieid RW area of flash. This is not a restriction on - * the number of components packed in a firmware block. It's only the maximum - * number of parsed firmware components (address and size) included in the - * handoff structure. - */ -#define MAX_PARSED_FW_COMPONENTS 5 - -/* The FW areas consist of multiple components. At the beginning of - * each area is the number of total compoments as well as the size and - * offset for each component. One needs to caculate the total size of the - * signed firmware region based off of the embedded metadata. */ -struct vboot_component_entry { - uint32_t offset; - uint32_t size; -} __attribute__((packed)); - -struct vboot_components { - uint32_t num_components; - struct vboot_component_entry entries[0]; -} __attribute__((packed)); - -void vboot_locate_region(const char *name, struct vboot_region *region); - -struct vboot_components *vboot_locate_components(struct vboot_region *region); - -/* - * 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 - * is NULL,the region will be mapped to a memory location. NULL is - * returned on error else the location of the requested region. - */ -void *vboot_get_region(uintptr_t offset_addr, size_t size, void *dest); /* Returns 0 on success < 0 on error. */ int vboot_get_handoff_info(void **addr, uint32_t *size); int vboot_enable_developer(void); int vboot_enable_recovery(void); int vboot_skip_display_init(void); -#else +void *vboot_get_payload(int *len); +#else /* CONFIG_VBOOT_VERIFY_FIRMWARE || CONFIG_VBOOT2_VERIFY_FIRMWARE */ static inline void vboot_verify_firmware(struct romstage_handoff *h) {} static inline void *vboot_get_payload(int *len) { return NULL; } static inline int vboot_get_handoff_info(void **addr, uint32_t *size) @@ -121,55 +83,4 @@ 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 */ -void vboot2_verify_firmware(void); - -#if CONFIG_VBOOT2_VERIFY_FIRMWARE -void *vboot_load_ramstage(void); -void verstage_main(void); -void *vboot_load_stage(int stage_index, - struct vboot_region *fw_main, - struct vboot_components *fw_info); -void vboot_reboot(void); - -/* - * this is placed at the start of the vboot work buffer. selected_region is used - * for the verstage to return the location of the selected slot. buffer is used - * by the vboot2 core. Keep the struct cpu architecture agnostic as it crosses - * stage boundaries. - */ -struct vb2_working_data { - uint32_t selected_region_offset; - uint32_t selected_region_size; - uint64_t buffer_size; - uint64_t buffer; -}; - -struct vb2_working_data * const vboot_get_working_data(void); - -static inline void vb2_get_selected_region(struct vb2_working_data *wd, - struct vboot_region *region) -{ - region->offset_addr = wd->selected_region_offset; - region->size = wd->selected_region_size; -} - -static inline void vb2_set_selected_region(struct vb2_working_data *wd, - struct vboot_region *region) -{ - wd->selected_region_offset = region->offset_addr; - wd->selected_region_size = region->size; -} - -static inline int vboot_is_slot_selected(struct vb2_working_data *wd) -{ - return wd->selected_region_size > 0; -} - -static inline int vboot_is_readonly_path(struct vb2_working_data *wd) -{ - return wd->selected_region_size == 0; -} - -#endif /* CONFIG_VBOOT2_VERIFY_FIRMWARE */ - -#endif +#endif /* __CHROMEOS_H__ */ diff --git a/src/vendorcode/google/chromeos/memlayout.h b/src/vendorcode/google/chromeos/memlayout.h deleted file mode 100644 index 468f746775..0000000000 --- a/src/vendorcode/google/chromeos/memlayout.h +++ /dev/null @@ -1,47 +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 - */ - -/* This file contains macro definitions for memlayout.ld linker scripts. */ - -#ifndef __CHROMEOS_MEMLAYOUT_H -#define __CHROMEOS_MEMLAYOUT_H - -#define VBOOT2_WORK(addr, size) \ - REGION(vboot2_work, addr, size, 4) \ - _ = ASSERT(size >= 16K, "vboot2 work buffer must be at least 16K!"); - -#ifdef __VERSTAGE__ - #define VERSTAGE(addr, sz) \ - SET_COUNTER(VERSTAGE, addr) \ - _ = ASSERT(_everstage - _verstage <= sz, \ - STR(Verstage exceeded its allotted size! (sz))); \ - INCLUDE "vendorcode/google/chromeos/verstage.verstage.ld" -#else - #define VERSTAGE(addr, sz) \ - SET_COUNTER(VERSTAGE, addr) \ - . += sz; -#endif - -#ifdef __VERSTAGE__ - #define OVERLAP_VERSTAGE_ROMSTAGE(addr, size) VERSTAGE(addr, size) -#else - #define OVERLAP_VERSTAGE_ROMSTAGE(addr, size) ROMSTAGE(addr, size) -#endif - -#endif /* __CHROMEOS_MEMLAYOUT_H */ diff --git a/src/vendorcode/google/chromeos/symbols.h b/src/vendorcode/google/chromeos/symbols.h deleted file mode 100644 index 21169f0b3a..0000000000 --- a/src/vendorcode/google/chromeos/symbols.h +++ /dev/null @@ -1,32 +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 - */ - -#ifndef __CHROMEOS_SYMBOLS_H -#define __CHROMEOS_SYMBOLS_H - -extern u8 _vboot2_work[]; -extern u8 _evboot2_work[]; -#define _vboot2_work_size (_evboot2_work - _vboot2_work) - -/* Careful: _e and __size only defined for the current stage! */ -extern u8 _verstage[]; -extern u8 _everstage[]; -#define _verstage_size (_everstage - _verstage) - -#endif /* __CHROMEOS_SYMBOLS_H */ diff --git a/src/vendorcode/google/chromeos/vboot1/Kconfig b/src/vendorcode/google/chromeos/vboot1/Kconfig new file mode 100644 index 0000000000..0102869797 --- /dev/null +++ b/src/vendorcode/google/chromeos/vboot1/Kconfig @@ -0,0 +1,34 @@ +## This file is part of the coreboot project. +## +## Copyright (C) 2014 The ChromiumOS Authors. All rights reserved. +## +## 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 +## + +config VBOOT_VERIFY_FIRMWARE + bool "Verify firmware with vboot." + default n + depends on CHROMEOS + select RELOCATABLE_MODULES + help + Enabling VBOOT_VERIFY_FIRMWARE will use vboot to verify the ramstage + and boot loader. + +config VBOOT_REFCODE_INDEX + hex "Reference code firmware index" + default 1 + depends on VBOOT_VERIFY_FIRMWARE + help + This is the index of the reference code component in the verified + firmware block. diff --git a/src/vendorcode/google/chromeos/vboot1/Makefile.inc b/src/vendorcode/google/chromeos/vboot1/Makefile.inc new file mode 100644 index 0000000000..a2d42b45f3 --- /dev/null +++ b/src/vendorcode/google/chromeos/vboot1/Makefile.inc @@ -0,0 +1,74 @@ +## +## This file is part of the coreboot project. +## +## Copyright (C) 2014 The ChromiumOS Authors. All rights reserved. +## +## 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 +## + +ramstage-y += ../vboot_common.c +romstage-y += vboot_loader.c ../vboot_common.c +rmodules_$(ARCH-ROMSTAGE-y)-y += vboot_wrapper.c ../vboot_common.c + +ifneq ($(CONFIG_SPI_FLASH_MEMORY_MAPPED),y) +VBOOT_MAKEFLAGS = REGION_READ=1 +endif + +VB_LIB = $(obj)/external/vboot_reference/vboot_fw.a +# Currently, vboot comes into picture only during the romstage, thus +# is compiled for being used in romstage only. Since, we are splitting +# up all components in one of the three stages of coreboot, vboot seems +# most logical to fall under the romstage. Thus, all references to arch +# and other compiler stuff for vboot is using the romstage arch. +VB_FIRMWARE_ARCH := $(ARCHDIR-$(ARCH-ROMSTAGE-y)) + +VBOOT_STUB_ELF = $(obj)/vendorcode/google/chromeos/vboot1/vbootstub.elf +VBOOT_STUB = $(VBOOT_STUB_ELF).rmod + +# Dependency for the vboot rmodules. Ordering matters. +VBOOT_STUB_DEPS += $(obj)/vendorcode/google/chromeos/vboot1/vboot_wrapper.rmodules_$(ARCH-ROMSTAGE-y).o +VBOOT_STUB_DEPS += $(obj)/lib/memcmp.rmodules_$(ARCH-ROMSTAGE-y).o +ifeq ($(CONFIG_ARCH_ROMSTAGE_X86_32),y) +VBOOT_STUB_DEPS += $(obj)/arch/x86/lib/memset.rmodules_$(ARCH-ROMSTAGE-y).o +VBOOT_STUB_DEPS += $(obj)/arch/x86/lib/memcpy.rmodules_$(ARCH-ROMSTAGE-y).o +endif +ifeq ($(CONFIG_ARCH_ROMSTAGE_ARM),y) +VBOOT_STUB_DEPS += $(obj)/arch/arm/memset.rmodules_$(ARCH-ROMSTAGE-y).o +VBOOT_STUB_DEPS += $(obj)/arch/arm/memcpy.rmodules_$(ARCH-ROMSTAGE-y).o +endif +ifeq ($(CONFIG_ARCH_ROMSTAGE_ARM64),y) +VBOOT_STUB_DEPS += $(obj)/lib/memset.rmodules.o +VBOOT_STUB_DEPS += $(obj)/lib/memcpy.rmodules.o +endif +VBOOT_STUB_DEPS += $(VB_LIB) +# Remove the '-include' option since that will break vboot's build and ensure +# vboot_reference can get to coreboot's include files. +VBOOT_CFLAGS += $(patsubst -I%,-I$(top)/%,$(filter-out -include $(src)/include/kconfig.h, $(CFLAGS_romstage))) +VBOOT_CFLAGS += -DVBOOT_DEBUG +VBOOT_CFLAGS += $(rmodules_$(ARCH-ROMSTAGE-y)-c-ccopts) + +# Link the vbootstub module with a 64KiB-byte heap. +$(eval $(call rmodule_link,$(VBOOT_STUB_ELF), $(VBOOT_STUB_DEPS), 0x10000,$(ARCH-ROMSTAGE-y))) + +# Build vboot library without the default includes from coreboot proper. +$(VB_LIB): + @printf " MAKE $(subst $(obj)/,,$(@))\n" + $(Q)FIRMWARE_ARCH=$(VB_FIRMWARE_ARCH) \ + CC="$(CC_romstage)" \ + CFLAGS="$(VBOOT_CFLAGS)" \ + $(MAKE) -C $(VB_SOURCE) \ + $(VBOOT_MAKEFLAGS) \ + BUILD=$(top)/$(dir $(VB_LIB)) \ + V=$(V) \ + fwlib diff --git a/src/vendorcode/google/chromeos/vboot1/vboot_loader.c b/src/vendorcode/google/chromeos/vboot1/vboot_loader.c new file mode 100644 index 0000000000..0353a3a08e --- /dev/null +++ b/src/vendorcode/google/chromeos/vboot1/vboot_loader.c @@ -0,0 +1,416 @@ +/* + * This file is part of the coreboot project. + * + * Copyright (C) 2013 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 +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include "../chromeos.h" +#include "../vboot_context.h" +#include "../vboot_handoff.h" + +#define TEMP_CBMEM_ID_VBOOT 0xffffffff +#define TEMP_CBMEM_ID_VBLOCKS 0xfffffffe + +static void vboot_run_stub(struct vboot_context *context) +{ + struct rmod_stage_load rmod_stage = { + .cbmem_id = TEMP_CBMEM_ID_VBOOT, + .name = CONFIG_CBFS_PREFIX "/vboot", + }; + void (*entry)(struct vboot_context *context); + + if (rmodule_stage_load_from_cbfs(&rmod_stage)) { + printk(BIOS_DEBUG, "Could not load vboot stub.\n"); + goto out; + } + + entry = rmod_stage.entry; + + /* Call stub. */ + entry(context); + +out: + /* Tear down the region no longer needed. */ + if (rmod_stage.cbmem_entry != NULL) + cbmem_entry_remove(rmod_stage.cbmem_entry); +} + +/* Helper routines for the vboot stub. */ +static void log_msg(const char *fmt, va_list args) +{ + do_vtxprintf(fmt, args); +} + +static void fatal_error(void) +{ + printk(BIOS_ERR, "vboot encountered fatal error. Resetting.\n"); + hard_reset(); +} + +static int fw_region_size(struct vboot_region *r) +{ + struct vboot_components *fw_info; + int32_t size; + int i; + + fw_info = vboot_locate_components(r); + if (fw_info == NULL) + return -1; + + if (fw_info->num_components > MAX_PARSED_FW_COMPONENTS) + return -1; + + size = sizeof(*fw_info); + size += sizeof(struct vboot_component_entry) * fw_info->num_components; + + for (i = 0; i < fw_info->num_components; i++) + size += ALIGN(fw_info->entries[i].size, sizeof(uint32_t)); + + /* Check that size of comopnents does not exceed the region's size. */ + if (size > r->size) + return -1; + + /* Update region with the correct size. */ + r->size = size; + + return 0; +} + +static int vboot_fill_params(struct vboot_context *ctx) +{ + VbCommonParams *cparams; + VbSelectFirmwareParams *fparams; + + if (fw_region_size(&ctx->fw_a)) + return -1; + + if (fw_region_size(&ctx->fw_b)) + return -1; + + cparams = ctx->cparams; + fparams = ctx->fparams; + + cparams->gbb_size = ctx->gbb.size; + fparams->verification_size_A = ctx->vblock_a.size; + fparams->verification_size_B = ctx->vblock_b.size; + + if (IS_ENABLED(CONFIG_SPI_FLASH_MEMORY_MAPPED)) { + /* Get memory-mapped pointers to the regions. */ + cparams->gbb_data = vboot_get_region(ctx->gbb.offset_addr, + ctx->gbb.size, NULL); + fparams->verification_block_A = + vboot_get_region(ctx->vblock_a.offset_addr, + ctx->vblock_a.size, NULL); + fparams->verification_block_B = + vboot_get_region(ctx->vblock_b.offset_addr, + ctx->vblock_b.size, NULL); + } else { + /* + * Copy the vblock info into a buffer in cbmem. The gbb will + * be read using VbExRegionRead(). + */ + char *dest; + size_t vblck_sz; + + vblck_sz = ctx->vblock_a.size + ctx->vblock_b.size; + ctx->vblocks = cbmem_entry_add(TEMP_CBMEM_ID_VBLOCKS, vblck_sz); + if (ctx->vblocks == NULL) + return -1; + dest = cbmem_entry_start(ctx->vblocks); + if (vboot_get_region(ctx->vblock_a.offset_addr, + ctx->vblock_a.size, dest) == NULL) + return -1; + fparams->verification_block_A = (void *)dest; + dest += ctx->vblock_a.size; + if (vboot_get_region(ctx->vblock_b.offset_addr, + ctx->vblock_b.size, dest) == NULL) + return -1; + fparams->verification_block_B = (void *)dest; + } + + return 0; +} + +static void fill_handoff(struct vboot_context *context) +{ + struct vboot_components *fw_info; + struct vboot_region *region; + int i; + + /* Fix up the handoff structure. */ + context->handoff->selected_firmware = + context->fparams->selected_firmware; + + /* Parse out the components for downstream consumption. */ + if (context->handoff->selected_firmware == VB_SELECT_FIRMWARE_A) + region = &context->fw_a; + else if (context->handoff->selected_firmware == VB_SELECT_FIRMWARE_B) + region = &context->fw_b; + else + return; + + fw_info = vboot_locate_components(region); + if (fw_info == NULL) + return; + + for (i = 0; i < fw_info->num_components; i++) { + context->handoff->components[i].address = + region->offset_addr + fw_info->entries[i].offset; + context->handoff->components[i].size = fw_info->entries[i].size; + } +} + +static void vboot_clean_up(struct vboot_context *context) +{ + if (context->vblocks != NULL) + cbmem_entry_remove(context->vblocks); +} + +static void reset(void) +{ + hard_reset(); +} + +static void vboot_invoke_wrapper(struct vboot_handoff *vboot_handoff) +{ + VbCommonParams cparams; + VbSelectFirmwareParams fparams; + struct vboot_context context; + uint32_t *iflags; + + vboot_handoff->selected_firmware = VB_SELECT_FIRMWARE_READONLY; + + memset(&cparams, 0, sizeof(cparams)); + memset(&fparams, 0, sizeof(fparams)); + memset(&context, 0, sizeof(context)); + + iflags = &vboot_handoff->init_params.flags; + if (get_developer_mode_switch()) + *iflags |= VB_INIT_FLAG_DEV_SWITCH_ON; + if (get_recovery_mode_switch()) { + clear_recovery_mode_switch(); + *iflags |= VB_INIT_FLAG_REC_BUTTON_PRESSED; + } + if (get_write_protect_state()) + *iflags |= VB_INIT_FLAG_WP_ENABLED; + if (vboot_get_sw_write_protect()) + *iflags |= VB_INIT_FLAG_SW_WP_ENABLED; + if (CONFIG_VIRTUAL_DEV_SWITCH) + *iflags |= VB_INIT_FLAG_VIRTUAL_DEV_SWITCH; + if (CONFIG_EC_SOFTWARE_SYNC) { + *iflags |= VB_INIT_FLAG_EC_SOFTWARE_SYNC; + *iflags |= VB_INIT_FLAG_VIRTUAL_REC_SWITCH; + } + if (CONFIG_VBOOT_EC_SLOW_UPDATE) + *iflags |= VB_INIT_FLAG_EC_SLOW_UPDATE; + if (CONFIG_VBOOT_OPROM_MATTERS) { + *iflags |= VB_INIT_FLAG_OPROM_MATTERS; + /* Will load VGA option rom during this boot */ + if (developer_mode_enabled() || recovery_mode_enabled() || + vboot_wants_oprom()) { + *iflags |= VB_INIT_FLAG_OPROM_LOADED; + } + } + + context.handoff = vboot_handoff; + context.cparams = &cparams; + context.fparams = &fparams; + + cparams.shared_data_blob = &vboot_handoff->shared_data[0]; + cparams.shared_data_size = VB_SHARED_DATA_MIN_SIZE; + cparams.caller_context = &context; + + vboot_locate_region("GBB", &context.gbb); + vboot_locate_region("VBLOCK_A", &context.vblock_a); + vboot_locate_region("VBLOCK_B", &context.vblock_b); + vboot_locate_region("FW_MAIN_A", &context.fw_a); + vboot_locate_region("FW_MAIN_B", &context.fw_b); + + /* Check all fmap entries. */ + if (context.fw_a.size < 0 || context.fw_b.size < 0 || + context.vblock_a.size < 0 || context.vblock_b.size < 0 || + context.gbb.size < 0) { + printk(BIOS_DEBUG, "Not all fmap entries found for vboot.\n"); + return; + } + + /* Fill in vboot parameters. */ + if (vboot_fill_params(&context)) { + vboot_clean_up(&context); + return; + } + + /* Initialize callbacks. */ + context.read_vbnv = &read_vbnv; + context.save_vbnv = &save_vbnv; + context.tis_init = &tis_init; + context.tis_open = &tis_open; + context.tis_close = &tis_close; + context.tis_sendrecv = &tis_sendrecv; + context.log_msg = &log_msg; + context.fatal_error = &fatal_error; + context.get_region = &vboot_get_region; + context.reset = &reset; + + vboot_run_stub(&context); + + fill_handoff(&context); + + vboot_clean_up(&context); +} + +#if CONFIG_RELOCATABLE_RAMSTAGE +static void *vboot_load_ramstage(uint32_t cbmem_id, const char *name, + const struct cbmem_entry **cbmem_entry) +{ + struct vboot_handoff *vboot_handoff; + struct cbfs_stage *stage; + const struct firmware_component *fwc; + struct rmod_stage_load rmod_load = { + .cbmem_id = cbmem_id, + .name = name, + }; + + timestamp_add_now(TS_START_VBOOT); + + vboot_handoff = cbmem_add(CBMEM_ID_VBOOT_HANDOFF, + sizeof(*vboot_handoff)); + + if (vboot_handoff == NULL) { + printk(BIOS_DEBUG, "Could not add vboot_handoff structure.\n"); + return NULL; + } + + memset(vboot_handoff, 0, sizeof(*vboot_handoff)); + + vboot_invoke_wrapper(vboot_handoff); + + timestamp_add_now(TS_END_VBOOT); + + /* Take RO firmware path since no RW area was selected. */ + if (vboot_handoff->selected_firmware != VB_SELECT_FIRMWARE_A && + vboot_handoff->selected_firmware != VB_SELECT_FIRMWARE_B) { + printk(BIOS_DEBUG, "No RW firmware selected: 0x%08x\n", + vboot_handoff->selected_firmware); + return NULL; + } + + if (CONFIG_VBOOT_RAMSTAGE_INDEX >= MAX_PARSED_FW_COMPONENTS) { + printk(BIOS_ERR, "Invalid ramstage index: %d\n", + CONFIG_VBOOT_RAMSTAGE_INDEX); + return NULL; + } + + /* Check for invalid address. */ + fwc = &vboot_handoff->components[CONFIG_VBOOT_RAMSTAGE_INDEX]; + if (fwc->address == 0) { + printk(BIOS_DEBUG, "RW ramstage image address invalid.\n"); + return NULL; + } + + printk(BIOS_DEBUG, "RW ramstage image at 0x%08x, 0x%08x bytes.\n", + fwc->address, fwc->size); + + stage = (void *)fwc->address; + + if (rmodule_stage_load(&rmod_load, stage)) { + vboot_handoff->selected_firmware = VB_SELECT_FIRMWARE_READONLY; + printk(BIOS_DEBUG, "Could not load ramstage region.\n"); + return NULL; + } + + *cbmem_entry = rmod_load.cbmem_entry; + + return rmod_load.entry; +} +#else /* CONFIG_RELOCATABLE_RAMSTAGE */ +static void vboot_load_ramstage(struct vboot_handoff *vboot_handoff, + struct romstage_handoff *handoff) +{ + struct cbfs_stage *stage; + const struct firmware_component *fwc; + + if (CONFIG_VBOOT_RAMSTAGE_INDEX >= MAX_PARSED_FW_COMPONENTS) { + printk(BIOS_ERR, "Invalid ramstage index: %d\n", + CONFIG_VBOOT_RAMSTAGE_INDEX); + return; + } + + /* Check for invalid address. */ + fwc = &vboot_handoff->components[CONFIG_VBOOT_RAMSTAGE_INDEX]; + if (fwc->address == 0) { + printk(BIOS_DEBUG, "RW ramstage image address invalid.\n"); + return; + } + + printk(BIOS_DEBUG, "RW ramstage image at 0x%08x, 0x%08x bytes.\n", + fwc->address, fwc->size); + + /* This will leak a mapping. */ + stage = vboot_get_region(fwc->address, fwc->size, NULL); + + if (stage == NULL) { + printk(BIOS_DEBUG, "Unable to get RW ramstage region.\n"); + return; + } + + timestamp_add_now(TS_START_COPYRAM); + + /* 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(struct cbfs_stage), + (void *) (uintptr_t) stage->load, + stage->len)) + return; + + timestamp_add_now(TS_END_COPYRAM); + +#if CONFIG_ARCH_X86 + __asm__ volatile ( + "movl $0, %%ebp\n" + "jmp *%%edi\n" + :: "D"(stage->entry) + ); +#elif CONFIG_ARCH_ARM + stage_exit((void *)(uintptr_t)stage->entry); +#endif +} +#endif /* CONFIG_RELOCATABLE_RAMSTAGE */ + + +const struct ramstage_loader_ops vboot_ramstage_loader = { + .name = "VBOOT", + .load = vboot_load_ramstage, +}; diff --git a/src/vendorcode/google/chromeos/vboot1/vboot_wrapper.c b/src/vendorcode/google/chromeos/vboot1/vboot_wrapper.c new file mode 100644 index 0000000000..5b9dbbbb31 --- /dev/null +++ b/src/vendorcode/google/chromeos/vboot1/vboot_wrapper.c @@ -0,0 +1,266 @@ +/* + * This file is part of the coreboot project. + * + * Copyright (C) 2013 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 +#if CONFIG_ARCH_X86 +#include +#else +#include +#endif +#include +#include +#include +#include "../vboot_context.h" +#include "../vboot_handoff.h" + +/* Keep a global context pointer around for the callbacks to use. */ +static struct vboot_context *gcontext; + +static void vboot_wrapper(void *arg) +{ + VbError_t res; + struct vboot_context *context; + + context = arg; + gcontext = context; + + VbExDebug("Calling VbInit()\n"); + res = VbInit(context->cparams, &context->handoff->init_params); + VbExDebug("VbInit() returned 0x%08x\n", res); + + if (res != VBERROR_SUCCESS) { + if(res == VBERROR_TPM_REBOOT_REQUIRED) { + VbExDebug("TPM Reboot Required. Proceeding reboot.\n"); + gcontext->reset(); + } + return; + } + + VbExDebug("Calling VbSelectFirmware()\n"); + res = VbSelectFirmware(context->cparams, context->fparams); + VbExDebug("VbSelectFirmware() returned 0x%08x\n", res); + + if (res != VBERROR_SUCCESS) + return; +} + +void VbExError(const char *format, ...) +{ + va_list args; + + va_start(args, format); + gcontext->log_msg(format, args); + va_end(args); + + gcontext->fatal_error(); +} + +void VbExDebug(const char *format, ...) +{ + va_list args; + + va_start(args, format); + gcontext->log_msg(format, args); + va_end(args); +} + +uint64_t VbExGetTimer(void) +{ +#if CONFIG_ARCH_X86 + return rdtscll(); +#else + struct mono_time mt; + timer_monotonic_get(&mt); + return mt.microseconds; +#endif +} + +VbError_t VbExNvStorageRead(uint8_t *buf) +{ + gcontext->read_vbnv(buf); + return VBERROR_SUCCESS; +} + +VbError_t VbExNvStorageWrite(const uint8_t *buf) +{ + gcontext->save_vbnv(buf); + return VBERROR_SUCCESS; +} + +extern char _heap[]; +extern char _eheap[]; +static char *heap_current; +static int heap_size; + +void *VbExMalloc(size_t size) +{ + void *ptr; + + if (heap_current == NULL) { + heap_current = &_heap[0]; + heap_size = &_eheap[0] - &_heap[0]; + VbExDebug("vboot heap: %p 0x%08x bytes\n", + heap_current, heap_size); + } + + if (heap_size < size) { + VbExError("vboot heap request cannot be fulfilled. " + "0x%08x available, 0x%08x requested\n", + heap_size, size); + } + + ptr = heap_current; + heap_size -= size; + heap_current += size; + + return ptr; +} + +void VbExFree(void *ptr) +{ + /* Leak all memory. */ +} + +/* vboot doesn't expose these through the vboot_api.h, but they are needed. + * coreboot requires declarations so provide them to avoid compiler errors. */ +int Memcmp(const void *src1, const void *src2, size_t n); +void *Memcpy(void *dest, const void *src, uint64_t n); +void *Memset(void *dest, const uint8_t c, uint64_t n); + +int Memcmp(const void *src1, const void *src2, size_t n) +{ + return memcmp(src1, src2, n); +} + +void *Memcpy(void *dest, const void *src, uint64_t n) +{ + return memcpy(dest, src, n); +} + +void *Memset(void *dest, const uint8_t c, uint64_t n) +{ + return memset(dest, c, n); +} + +static inline size_t get_hash_block_size(size_t requested_size) +{ + if (!IS_ENABLED(CONFIG_SPI_FLASH_MEMORY_MAPPED)) { + const size_t block_size = 64 * 1024; + if (requested_size > block_size) + return block_size; + } + return requested_size; +} + +VbError_t VbExHashFirmwareBody(VbCommonParams *cparams, uint32_t firmware_index) +{ + uint8_t *data; + struct vboot_region *region; + struct vboot_context *ctx; + size_t data_size; + uintptr_t offset_addr; + + ctx = cparams->caller_context; + + switch (firmware_index) { + case VB_SELECT_FIRMWARE_A: + region = &ctx->fw_a; + break; + case VB_SELECT_FIRMWARE_B: + region = &ctx->fw_b; + break; + default: + return VBERROR_UNKNOWN; + } + + data_size = region->size; + offset_addr = region->offset_addr; + while (data_size) { + size_t block_size; + + block_size = get_hash_block_size(data_size); + data = ctx->get_region(offset_addr, block_size, NULL); + if (data == NULL) + return VBERROR_UNKNOWN; + VbUpdateFirmwareBodyHash(cparams, data, block_size); + + data_size -= block_size; + offset_addr += block_size; + } + + return VBERROR_SUCCESS; +} + +VbError_t VbExTpmInit(void) +{ + if (gcontext->tis_init()) + return VBERROR_UNKNOWN; + return VbExTpmOpen(); +} + +VbError_t VbExTpmClose(void) +{ + if (gcontext->tis_close()) + return VBERROR_UNKNOWN; + return VBERROR_SUCCESS; +} + +VbError_t VbExTpmOpen(void) +{ + if (gcontext->tis_open()) + return VBERROR_UNKNOWN; + return VBERROR_SUCCESS; +} + +VbError_t VbExTpmSendReceive(const uint8_t *request, uint32_t request_length, + uint8_t *response, uint32_t *response_length) +{ + size_t len = *response_length; + if (gcontext->tis_sendrecv(request, request_length, response, &len)) + return VBERROR_UNKNOWN; + /* check 64->32bit overflow and (re)check response buffer overflow */ + if (len > *response_length) + return VBERROR_UNKNOWN; + *response_length = len; + return VBERROR_SUCCESS; +} + +#if !CONFIG_SPI_FLASH_MEMORY_MAPPED +VbError_t VbExRegionRead(VbCommonParams *cparams, + enum vb_firmware_region region, uint32_t offset, + uint32_t size, void *buf) +{ + struct vboot_context *ctx; + VbExDebug("VbExRegionRead: offset=%x size=%x, buf=%p\n", + offset, size, buf); + ctx = cparams->caller_context; + + if (region == VB_REGION_GBB) { + if (offset + size > cparams->gbb_size) + return VBERROR_REGION_READ_INVALID; + offset += ctx->gbb.offset_addr; + if (ctx->get_region(offset, size, buf) == NULL) + return VBERROR_REGION_READ_INVALID; + return VBERROR_SUCCESS; + } + + return VBERROR_UNSUPPORTED_REGION; +} +#endif /* CONFIG_SPI_FLASH_MEMORY_MAPPED */ + +RMODULE_ENTRY(vboot_wrapper); diff --git a/src/vendorcode/google/chromeos/vboot2/Kconfig b/src/vendorcode/google/chromeos/vboot2/Kconfig new file mode 100644 index 0000000000..20d2f1fc85 --- /dev/null +++ b/src/vendorcode/google/chromeos/vboot2/Kconfig @@ -0,0 +1,43 @@ +## This file is part of the coreboot project. +## +## Copyright (C) 2014 The ChromiumOS Authors. All rights reserved. +## +## 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 +## + +config VBOOT2_VERIFY_FIRMWARE + bool "Firmware Verification with vboot2" + default n + depends on CHROMEOS && HAVE_HARD_RESET + help + Enabling VBOOT2_VERIFY_FIRMWARE will use vboot2 to verify the romstage + and boot loader. + +config RETURN_FROM_VERSTAGE + bool "return from verstage" + default n + depends on VBOOT2_VERIFY_FIRMWARE + help + If this is set, the verstage returns back to the bootblock instead of + exits to the romstage so that the verstage space can be reused by the + romstage. Useful if a ram space is too small to fit both the verstage + and the romstage. + +config VBOOT_ROMSTAGE_INDEX + hex + default 2 + depends on VBOOT2_VERIFY_FIRMWARE + help + This is the index of the romstage component in the verified + firmware block. diff --git a/src/vendorcode/google/chromeos/vboot2/Makefile.inc b/src/vendorcode/google/chromeos/vboot2/Makefile.inc new file mode 100644 index 0000000000..3c07a5129e --- /dev/null +++ b/src/vendorcode/google/chromeos/vboot2/Makefile.inc @@ -0,0 +1,60 @@ +## +## This file is part of the coreboot project. +## +## Copyright (C) 2014 The ChromiumOS Authors. All rights reserved. +## +## 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 +## + +verstage-generic-ccopts += -D__PRE_RAM__ -D__VERSTAGE__ + +ramstage-y += ../vboot_common.c +romstage-y += ../vboot_common.c + +ifeq ($(CONFIG_RETURN_FROM_VERSTAGE),y) +bootblock-y += common.c verstub.c ../chromeos.c ../vboot_common.c +else +verstage-y += verstub.c +endif +verstage-y += verstage.c ../fmap.c ../chromeos.c ../vboot_common.c +verstage-y += antirollback.c common.c +verstage-$(CONFIG_CHROMEOS_VBNV_CMOS) += ../vbnv_cmos.c +verstage-$(CONFIG_CHROMEOS_VBNV_EC) += ../vbnv_ec.c +verstage-$(CONFIG_CHROMEOS_VBNV_FLASH) += ../vbnv_flash.c +romstage-y += vboot_handoff.c common.c + +verstage-y += verstage.ld + +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 + +VERSTAGE_ELF = $(objcbfs)/verstage.elf +cbfs-files-y += $(call strip_quotes,$(CONFIG_CBFS_PREFIX))/verstage +fallback/verstage-file = $(VERSTAGE_ELF) +fallback/verstage-type = stage +fallback/verstage-compression = none diff --git a/src/vendorcode/google/chromeos/vboot2/antirollback.c b/src/vendorcode/google/chromeos/vboot2/antirollback.c new file mode 100644 index 0000000000..bb547b51bc --- /dev/null +++ b/src/vendorcode/google/chromeos/vboot2/antirollback.c @@ -0,0 +1,329 @@ +/* Copyright (c) 2013 The Chromium OS Authors. All rights reserved. + * Use of this source code is governed by a BSD-style license that can be + * found in the LICENSE file. + * + * Functions for querying, manipulating and locking rollback indices + * stored in the TPM NVRAM. + */ + +#include <2api.h> +#include <2sysincludes.h> +#include +#include +#include + +#ifndef offsetof +#define offsetof(A,B) __builtin_offsetof(A,B) +#endif + +#ifdef FOR_TEST +#include +#define VBDEBUG(format, args...) printf(format, ## args) +#else +#include +#define VBDEBUG(format, args...) \ + printk(BIOS_INFO, "%s():%d: " format, __func__, __LINE__, ## args) +#endif + +#define RETURN_ON_FAILURE(tpm_cmd) do { \ + uint32_t result_; \ + if ((result_ = (tpm_cmd)) != TPM_SUCCESS) { \ + VBDEBUG("Antirollback: %08x returned by " #tpm_cmd \ + "\n", (int)result_); \ + return result_; \ + } \ + } while (0) + +uint32_t tpm_clear_and_reenable(void) +{ + VBDEBUG("TPM: Clear and re-enable\n"); + RETURN_ON_FAILURE(tlcl_force_clear()); + RETURN_ON_FAILURE(tlcl_set_enable()); + RETURN_ON_FAILURE(tlcl_set_deactivated(0)); + + return TPM_SUCCESS; +} + +uint32_t safe_write(uint32_t index, const void *data, uint32_t length) +{ + uint32_t result = tlcl_write(index, data, length); + if (result == TPM_E_MAXNVWRITES) { + RETURN_ON_FAILURE(tpm_clear_and_reenable()); + return tlcl_write(index, data, length); + } else { + return result; + } +} + +uint32_t safe_define_space(uint32_t index, uint32_t perm, uint32_t size) +{ + uint32_t result = tlcl_define_space(index, perm, size); + if (result == TPM_E_MAXNVWRITES) { + RETURN_ON_FAILURE(tpm_clear_and_reenable()); + return tlcl_define_space(index, perm, size); + } else { + return result; + } +} + +static uint32_t read_space_firmware(struct vb2_context *ctx) +{ + int attempts = 3; + + while (attempts--) { + RETURN_ON_FAILURE(tlcl_read(FIRMWARE_NV_INDEX, ctx->secdata, + VB2_SECDATA_SIZE)); + + if (vb2api_secdata_check(ctx) == VB2_SUCCESS) + return TPM_SUCCESS; + + VBDEBUG("TPM: %s() - bad CRC\n", __func__); + } + + VBDEBUG("TPM: %s() - too many bad CRCs, giving up\n", __func__); + return TPM_E_CORRUPTED_STATE; +} + +static uint32_t write_secdata(uint32_t index, + const uint8_t *secdata, + uint32_t len) +{ + uint8_t sd[32]; + uint32_t rv; + int attempts = 3; + + if (len > sizeof(sd)) { + VBDEBUG("TPM: %s() - data is too large\n", __func__); + return TPM_E_WRITE_FAILURE; + } + + while (attempts--) { + rv = safe_write(index, secdata, len); + /* Can't write, not gonna try again */ + if (rv != TPM_SUCCESS) + return rv; + + /* Read it back to be sure it got the right values. */ + rv = tlcl_read(index, sd, len); + if (rv == TPM_SUCCESS && memcmp(secdata, sd, len) == 0) + return rv; + + VBDEBUG("TPM: %s() failed. trying again\n", __func__); + /* Try writing it again. Maybe it was garbled on the way out. */ + } + + VBDEBUG("TPM: %s() - too many failures, giving up\n", __func__); + + return TPM_E_CORRUPTED_STATE; +} + +uint32_t factory_initialize_tpm(struct vb2_context *ctx) +{ + TPM_PERMANENT_FLAGS pflags; + uint32_t result; + /* this is derived from rollback_index.h of vboot_reference. see struct + * RollbackSpaceKernel for details. */ + static const uint8_t secdata_kernel[] = { + 0x02, + 0x4C, 0x57, 0x52, 0x47, + 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, + 0xE8, + }; + + VBDEBUG("TPM: factory initialization\n"); + + /* + * Do a full test. This only happens the first time the device is + * turned on in the factory, so performance is not an issue. This is + * almost certainly not necessary, but it gives us more confidence + * about some code paths below that are difficult to + * test---specifically the ones that set lifetime flags, and are only + * executed once per physical TPM. + */ + result = tlcl_self_test_full(); + if (result != TPM_SUCCESS) + return result; + + result = tlcl_get_permanent_flags(&pflags); + if (result != TPM_SUCCESS) + return result; + + /* + * TPM may come from the factory without physical presence finalized. + * Fix if necessary. + */ + VBDEBUG("TPM: physicalPresenceLifetimeLock=%d\n", + pflags.physicalPresenceLifetimeLock); + if (!pflags.physicalPresenceLifetimeLock) { + VBDEBUG("TPM: Finalizing physical presence\n"); + RETURN_ON_FAILURE(tlcl_finalize_physical_presence()); + } + + /* + * The TPM will not enforce the NV authorization restrictions until the + * execution of a TPM_NV_DefineSpace with the handle of + * TPM_NV_INDEX_LOCK. Here we create that space if it doesn't already + * exist. */ + VBDEBUG("TPM: nvLocked=%d\n", pflags.nvLocked); + if (!pflags.nvLocked) { + VBDEBUG("TPM: Enabling NV locking\n"); + RETURN_ON_FAILURE(tlcl_set_nv_locked()); + } + + /* Clear TPM owner, in case the TPM is already owned for some reason. */ + VBDEBUG("TPM: Clearing owner\n"); + RETURN_ON_FAILURE(tpm_clear_and_reenable()); + + /* Define the backup space. No need to initialize it, though. */ + RETURN_ON_FAILURE(safe_define_space(BACKUP_NV_INDEX, + TPM_NV_PER_PPWRITE, + VB2_NVDATA_SIZE)); + + /* Define and initialize the kernel space */ + RETURN_ON_FAILURE(safe_define_space(KERNEL_NV_INDEX, + TPM_NV_PER_PPWRITE, + sizeof(secdata_kernel))); + RETURN_ON_FAILURE(write_secdata(KERNEL_NV_INDEX, + secdata_kernel, + sizeof(secdata_kernel))); + + /* Defines and sets vb2 secdata space */ + vb2api_secdata_create(ctx); + RETURN_ON_FAILURE(safe_define_space(FIRMWARE_NV_INDEX, + TPM_NV_PER_GLOBALLOCK | + TPM_NV_PER_PPWRITE, + VB2_SECDATA_SIZE)); + RETURN_ON_FAILURE(write_secdata(FIRMWARE_NV_INDEX, + ctx->secdata, + VB2_SECDATA_SIZE)); + + VBDEBUG("TPM: factory initialization successful\n"); + + return TPM_SUCCESS; +} + +/* + * SetupTPM starts the TPM and establishes the root of trust for the + * anti-rollback mechanism. SetupTPM can fail for three reasons. 1 A bug. 2 a + * TPM hardware failure. 3 An unexpected TPM state due to some attack. In + * general we cannot easily distinguish the kind of failure, so our strategy is + * to reboot in recovery mode in all cases. The recovery mode calls SetupTPM + * again, which executes (almost) the same sequence of operations. There is a + * good chance that, if recovery mode was entered because of a TPM failure, the + * failure will repeat itself. (In general this is impossible to guarantee + * because we have no way of creating the exact TPM initial state at the + * previous boot.) In recovery mode, we ignore the failure and continue, thus + * giving the recovery kernel a chance to fix things (that's why we don't set + * bGlobalLock). The choice is between a knowingly insecure device and a + * bricked device. + * + * As a side note, observe that we go through considerable hoops to avoid using + * the STCLEAR permissions for the index spaces. We do this to avoid writing + * to the TPM flashram at every reboot or wake-up, because of concerns about + * the durability of the NVRAM. + */ +uint32_t setup_tpm(struct vb2_context *ctx) +{ + uint8_t disable; + uint8_t deactivated; + uint32_t result; + + RETURN_ON_FAILURE(tlcl_lib_init()); + +#ifdef TEGRA_SOFT_REBOOT_WORKAROUND + result = tlcl_startup(); + if (result == TPM_E_INVALID_POSTINIT) { + /* + * Some prototype hardware doesn't reset the TPM on a CPU + * reset. We do a hard reset to get around this. + */ + VBDEBUG("TPM: soft reset detected\n", result); + return TPM_E_MUST_REBOOT; + } else if (result != TPM_SUCCESS) { + VBDEBUG("TPM: tlcl_startup returned %08x\n", result); + return result; + } +#else + RETURN_ON_FAILURE(tlcl_startup()); +#endif + + /* + * Some TPMs start the self test automatically at power on. In that case + * we don't need to call ContinueSelfTest. On some (other) TPMs, + * continue_self_test may block. In that case, we definitely don't want + * to call it here. For TPMs in the intersection of these two sets, we + * are screwed. (In other words: TPMs that require manually starting the + * self-test AND block will have poor performance until we split + * tlcl_send_receive() into send() and receive(), and have a state + * machine to control setup.) + * + * This comment is likely to become obsolete in the near future, so + * don't trust it. It may have not been updated. + */ +#ifdef TPM_MANUAL_SELFTEST +#ifdef TPM_BLOCKING_CONTINUESELFTEST +#warning "lousy TPM!" +#endif + RETURN_ON_FAILURE(tlcl_continue_self_test()); +#endif + result = tlcl_assert_physical_presence(); + if (result != TPM_SUCCESS) { + /* + * It is possible that the TPM was delivered with the physical + * presence command disabled. This tries enabling it, then + * tries asserting PP again. + */ + RETURN_ON_FAILURE(tlcl_physical_presence_cmd_enable()); + RETURN_ON_FAILURE(tlcl_assert_physical_presence()); + } + + /* Check that the TPM is enabled and activated. */ + RETURN_ON_FAILURE(tlcl_get_flags(&disable, &deactivated, NULL)); + if (disable || deactivated) { + VBDEBUG("TPM: disabled (%d) or deactivated (%d). Fixing...\n", + disable, deactivated); + RETURN_ON_FAILURE(tlcl_set_enable()); + RETURN_ON_FAILURE(tlcl_set_deactivated(0)); + VBDEBUG("TPM: Must reboot to re-enable\n"); + return TPM_E_MUST_REBOOT; + } + + VBDEBUG("TPM: SetupTPM() succeeded\n"); + return TPM_SUCCESS; +} + +uint32_t antirollback_read_space_firmware(struct vb2_context *ctx) +{ + uint32_t rv; + + rv = setup_tpm(ctx); + if (rv) + return rv; + + /* Read the firmware space. */ + rv = read_space_firmware(ctx); + if (rv == TPM_E_BADINDEX) { + /* + * This seems the first time we've run. Initialize the TPM. + */ + VBDEBUG("TPM: Not initialized yet.\n"); + RETURN_ON_FAILURE(factory_initialize_tpm(ctx)); + } else if (rv != TPM_SUCCESS) { + VBDEBUG("TPM: Firmware space in a bad state; giving up.\n"); + //RETURN_ON_FAILURE(factory_initialize_tpm(ctx)); + return TPM_E_CORRUPTED_STATE; + } + + return TPM_SUCCESS; +} + +uint32_t antirollback_write_space_firmware(struct vb2_context *ctx) +{ + return write_secdata(FIRMWARE_NV_INDEX, ctx->secdata, VB2_SECDATA_SIZE); +} + +uint32_t antirollback_lock_space_firmware() +{ + return tlcl_set_global_lock(); +} diff --git a/src/vendorcode/google/chromeos/vboot2/common.c b/src/vendorcode/google/chromeos/vboot2/common.c new file mode 100644 index 0000000000..178e8b53f1 --- /dev/null +++ b/src/vendorcode/google/chromeos/vboot2/common.c @@ -0,0 +1,70 @@ +/* + * This file is part of the coreboot project. + * + * Copyright (C) 2014 The ChromiumOS Authors. All rights reserved. + * + * 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 +#include +#include +#include "../chromeos.h" +#include "../vboot_handoff.h" +#include "misc.h" +#include "symbols.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; +} + +void vboot_reboot(void) +{ + hard_reset(); + die("failed to reboot"); +} diff --git a/src/vendorcode/google/chromeos/vboot2/memlayout.h b/src/vendorcode/google/chromeos/vboot2/memlayout.h new file mode 100644 index 0000000000..9e1920039d --- /dev/null +++ b/src/vendorcode/google/chromeos/vboot2/memlayout.h @@ -0,0 +1,47 @@ +/* + * 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 + */ + +/* This file contains macro definitions for memlayout.ld linker scripts. */ + +#ifndef __CHROMEOS_VBOOT2_MEMLAYOUT_H +#define __CHROMEOS_VBOOT2_MEMLAYOUT_H + +#define VBOOT2_WORK(addr, size) \ + REGION(vboot2_work, addr, size, 4) \ + _ = ASSERT(size >= 16K, "vboot2 work buffer must be at least 16K!"); + +#ifdef __VERSTAGE__ + #define VERSTAGE(addr, sz) \ + SET_COUNTER(VERSTAGE, addr) \ + _ = ASSERT(_everstage - _verstage <= sz, \ + STR(Verstage exceeded its allotted size! (sz))); \ + INCLUDE "vendorcode/google/chromeos/vboot2/verstage.verstage.ld" +#else + #define VERSTAGE(addr, sz) \ + SET_COUNTER(VERSTAGE, addr) \ + . += sz; +#endif + +#ifdef __VERSTAGE__ + #define OVERLAP_VERSTAGE_ROMSTAGE(addr, size) VERSTAGE(addr, size) +#else + #define OVERLAP_VERSTAGE_ROMSTAGE(addr, size) ROMSTAGE(addr, size) +#endif + +#endif /* __CHROMEOS_VBOOT2_MEMLAYOUT_H */ diff --git a/src/vendorcode/google/chromeos/vboot2/misc.h b/src/vendorcode/google/chromeos/vboot2/misc.h new file mode 100644 index 0000000000..cae302bc1f --- /dev/null +++ b/src/vendorcode/google/chromeos/vboot2/misc.h @@ -0,0 +1,72 @@ +/* + * This file is part of the coreboot project. + * + * Copyright (C) 2014 The ChromiumOS Authors. All rights reserved. + * + * 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 + */ + +#ifndef __CHROMEOS_VBOOT2_MISC_H__ +#define __CHROMEOS_VBOOT2_MISC_H__ + +#include "../vboot_common.h" + +void vboot2_verify_firmware(void); +void *vboot2_load_ramstage(void); +void verstage_main(void); +void *vboot_load_stage(int stage_index, + struct vboot_region *fw_main, + struct vboot_components *fw_info); +void vboot_reboot(void); + +/* + * this is placed at the start of the vboot work buffer. selected_region is used + * for the verstage to return the location of the selected slot. buffer is used + * by the vboot2 core. Keep the struct cpu architecture agnostic as it crosses + * stage boundaries. + */ +struct vb2_working_data { + uint32_t selected_region_offset; + uint32_t selected_region_size; + uint64_t buffer_size; + uint64_t buffer; +}; + +struct vb2_working_data * const vboot_get_working_data(void); + +static inline void vb2_get_selected_region(struct vb2_working_data *wd, + struct vboot_region *region) +{ + region->offset_addr = wd->selected_region_offset; + region->size = wd->selected_region_size; +} + +static inline void vb2_set_selected_region(struct vb2_working_data *wd, + struct vboot_region *region) +{ + wd->selected_region_offset = region->offset_addr; + wd->selected_region_size = region->size; +} + +static inline int vboot_is_slot_selected(struct vb2_working_data *wd) +{ + return wd->selected_region_size > 0; +} + +static inline int vboot_is_readonly_path(struct vb2_working_data *wd) +{ + return wd->selected_region_size == 0; +} + +#endif /* __CHROMEOS_VBOOT2_MISC_H__ */ diff --git a/src/vendorcode/google/chromeos/vboot2/symbols.h b/src/vendorcode/google/chromeos/vboot2/symbols.h new file mode 100644 index 0000000000..fda7114853 --- /dev/null +++ b/src/vendorcode/google/chromeos/vboot2/symbols.h @@ -0,0 +1,32 @@ +/* + * 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 + */ + +#ifndef __CHROMEOS_VBOOT2_SYMBOLS_H +#define __CHROMEOS_VBOOT2_SYMBOLS_H + +extern u8 _vboot2_work[]; +extern u8 _evboot2_work[]; +#define _vboot2_work_size (_evboot2_work - _vboot2_work) + +/* Careful: _e and __size only defined for the current stage! */ +extern u8 _verstage[]; +extern u8 _everstage[]; +#define _verstage_size (_everstage - _verstage) + +#endif /* __CHROMEOS_VBOOT2_SYMBOLS_H */ diff --git a/src/vendorcode/google/chromeos/vboot2/vboot_handoff.c b/src/vendorcode/google/chromeos/vboot2/vboot_handoff.c new file mode 100644 index 0000000000..a8573d0c88 --- /dev/null +++ b/src/vendorcode/google/chromeos/vboot2/vboot_handoff.c @@ -0,0 +1,175 @@ +/* + * This file is part of the coreboot project. + * + * Copyright (C) 2013 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 <2recovery_reasons.h> +#include <2struct.h> +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include "../chromeos.h" +#include "../fmap.h" +#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; + 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; + } + + return vboot_load_stage(CONFIG_VBOOT_RAMSTAGE_INDEX, fw_main, fw_info); +} + +/** + * Sets vboot_handoff based on the information in vb2_shared_data + * + * TODO: Read wp switch to set VBSD_BOOT_FIRMWARE_WP_ENABLED + */ +static void fill_vboot_handoff(struct vboot_handoff *vboot_handoff, + struct vb2_shared_data *vb2_sd) +{ + VbSharedDataHeader *vb_sd = + (VbSharedDataHeader *)vboot_handoff->shared_data; + uint32_t *oflags = &vboot_handoff->init_params.out_flags; + + vb_sd->flags |= VBSD_BOOT_FIRMWARE_VBOOT2; + + vboot_handoff->selected_firmware = vb2_sd->fw_slot; + + vb_sd->firmware_index = vb2_sd->fw_slot; + + vb_sd->magic = VB_SHARED_DATA_MAGIC; + vb_sd->struct_version = VB_SHARED_DATA_VERSION; + vb_sd->struct_size = sizeof(VbSharedDataHeader); + vb_sd->data_size = VB_SHARED_DATA_MIN_SIZE; + vb_sd->data_used = sizeof(VbSharedDataHeader); + + if (vb2_sd->recovery_reason) { + vb_sd->firmware_index = 0xFF; + if (vb2_sd->recovery_reason == VB2_RECOVERY_RO_MANUAL) + vb_sd->flags |= VBSD_BOOT_REC_SWITCH_ON; + *oflags |= VB_INIT_OUT_ENABLE_RECOVERY; + *oflags |= VB_INIT_OUT_CLEAR_RAM; + *oflags |= VB_INIT_OUT_ENABLE_DISPLAY; + *oflags |= VB_INIT_OUT_ENABLE_USB_STORAGE; + } + if (vb2_sd->flags & VB2_SD_DEV_MODE_ENABLED) { + *oflags |= VB_INIT_OUT_ENABLE_DEVELOPER; + *oflags |= VB_INIT_OUT_CLEAR_RAM; + *oflags |= VB_INIT_OUT_ENABLE_DISPLAY; + *oflags |= VB_INIT_OUT_ENABLE_USB_STORAGE; + vb_sd->flags |= VBSD_BOOT_DEV_SWITCH_ON; + vb_sd->flags |= VBSD_LF_DEV_SWITCH_ON; + } + /* TODO: Set these in depthcharge */ + if (CONFIG_VIRTUAL_DEV_SWITCH) + vb_sd->flags |= VBSD_HONOR_VIRT_DEV_SWITCH; + if (CONFIG_EC_SOFTWARE_SYNC) { + vb_sd->flags |= VBSD_EC_SOFTWARE_SYNC; + vb_sd->flags |= VBSD_BOOT_REC_SWITCH_VIRTUAL; + } + /* In vboot1, VBSD_FWB_TRIED is + * set only if B is booted as explicitly requested. Therefore, if B is + * booted because A was found bad, the flag should not be set. It's + * better not to touch it if we can only ambiguously control it. */ + /* if (vb2_sd->fw_slot) + vb_sd->flags |= VBSD_FWB_TRIED; */ + + /* copy kernel subkey if it's found */ + if (vb2_sd->workbuf_preamble_size) { + struct vb2_fw_preamble *fp; + uintptr_t dst, src; + printk(BIOS_INFO, "Copying FW preamble\n"); + fp = (struct vb2_fw_preamble *)((uintptr_t)vb2_sd + + vb2_sd->workbuf_preamble_offset); + src = (uintptr_t)&fp->kernel_subkey + + fp->kernel_subkey.key_offset; + dst = (uintptr_t)vb_sd + sizeof(VbSharedDataHeader); + assert(dst + fp->kernel_subkey.key_size <= + (uintptr_t)vboot_handoff + sizeof(*vboot_handoff)); + memcpy((void *)dst, (void *)src, + fp->kernel_subkey.key_size); + vb_sd->data_used += fp->kernel_subkey.key_size; + vb_sd->kernel_subkey.key_offset = + dst - (uintptr_t)&vb_sd->kernel_subkey; + vb_sd->kernel_subkey.key_size = fp->kernel_subkey.key_size; + vb_sd->kernel_subkey.algorithm = fp->kernel_subkey.algorithm; + vb_sd->kernel_subkey.key_version = + fp->kernel_subkey.key_version; + } + + vb_sd->recovery_reason = vb2_sd->recovery_reason; +} + +/** + * Load ramstage and return the entry point + */ +void *vboot2_load_ramstage(void) +{ + struct vboot_handoff *vh; + struct vb2_shared_data *sd; + struct vboot_region fw_main; + struct vb2_working_data *wd = vboot_get_working_data(); + + sd = (struct vb2_shared_data *)(uintptr_t)wd->buffer; + sd->workbuf_hash_offset = 0; + sd->workbuf_hash_size = 0; + + printk(BIOS_INFO, "creating vboot_handoff structure\n"); + vh = cbmem_add(CBMEM_ID_VBOOT_HANDOFF, sizeof(*vh)); + if (vh == NULL) + /* we don't need to failover gracefully here because this + * shouldn't happen with the image that has passed QA. */ + die("failed to allocate vboot_handoff structure\n"); + + memset(vh, 0, sizeof(*vh)); + + /* 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; + + 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); +} diff --git a/src/vendorcode/google/chromeos/vboot2/verstage.c b/src/vendorcode/google/chromeos/vboot2/verstage.c new file mode 100644 index 0000000000..572e161825 --- /dev/null +++ b/src/vendorcode/google/chromeos/vboot2/verstage.c @@ -0,0 +1,252 @@ +/* + * 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 <2api.h> +#include <2struct.h> +#include +#include +#include +#include + +#include "../chromeos.h" +#include "misc.h" + +#define TODO_BLOCK_SIZE 1024 + +static int is_slot_a(struct vb2_context *ctx) +{ + return !(ctx->flags & VB2_CONTEXT_FW_SLOT_B); +} + +/* exports */ + +void vb2ex_printf(const char *func, const char *fmt, ...) +{ + va_list args; + + printk(BIOS_INFO, "VB2:%s() ", func); + va_start(args, fmt); + vprintk(BIOS_INFO, fmt, args); + va_end(args); + + return; +} + +int vb2ex_tpm_clear_owner(struct vb2_context *ctx) +{ + uint32_t rv; + printk(BIOS_INFO, "Clearing TPM owner\n"); + rv = tpm_clear_and_reenable(); + if (rv) + return VB2_ERROR_EX_TPM_CLEAR_OWNER; + return VB2_SUCCESS; +} + +int vb2ex_read_resource(struct vb2_context *ctx, + enum vb2_resource_index index, + uint32_t offset, + void *buf, + uint32_t size) +{ + struct vboot_region region; + + switch (index) { + case VB2_RES_GBB: + vboot_locate_region("GBB", ®ion); + break; + case VB2_RES_FW_VBLOCK: + if (is_slot_a(ctx)) + vboot_locate_region("VBLOCK_A", ®ion); + else + vboot_locate_region("VBLOCK_B", ®ion); + break; + default: + return VB2_ERROR_EX_READ_RESOURCE_INDEX; + } + + if (offset + size > region.size) + return VB2_ERROR_EX_READ_RESOURCE_SIZE; + + if (vboot_get_region(region.offset_addr + offset, size, buf) == NULL) + return VB2_ERROR_UNKNOWN; + + return VB2_SUCCESS; +} + +static int hash_body(struct vb2_context *ctx, struct vboot_region *fw_main) +{ + uint32_t expected_size; + MAYBE_STATIC 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_firmware(struct vb2_context *ctx, + struct vboot_region *fw_main) +{ + if (is_slot_a(ctx)) + vboot_locate_region("FW_MAIN_A", fw_main); + else + vboot_locate_region("FW_MAIN_B", fw_main); + + if (fw_main->size < 0) + return 1; + + return 0; +} + +/** + * 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) { + printk(BIOS_INFO, "Saving nvdata\n"); + save_vbnv(ctx->nvdata); + ctx->flags &= ~VB2_CONTEXT_NVDATA_CHANGED; + } + if (ctx->flags & VB2_CONTEXT_SECDATA_CHANGED) { + printk(BIOS_INFO, "Saving secdata\n"); + antirollback_write_space_firmware(ctx); + ctx->flags &= ~VB2_CONTEXT_SECDATA_CHANGED; + } +} + +/** + * Verify and select the firmware in the RW image + * + * TODO: Avoid loading a stage twice (once in hash_body & again in load_stage). + * when per-stage verification is ready. + */ +#if CONFIG_RETURN_FROM_VERSTAGE +void main(void) +#else +void verstage_main(void) +#endif /* CONFIG_RETURN_FROM_VERSTAGE */ +{ + struct vb2_context ctx; + struct vboot_region fw_main; + struct vb2_working_data *wd = vboot_get_working_data(); + int rv; + + /* Set up context and work buffer */ + memset(&ctx, 0, sizeof(ctx)); + ctx.workbuf = (uint8_t *)(uintptr_t)wd->buffer; + ctx.workbuf_size = wd->buffer_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 */ + printk(BIOS_INFO, "Phase 1\n"); + rv = vb2api_fw_phase1(&ctx); + if (rv) { + printk(BIOS_INFO, "Recovery requested (%x)\n", rv); + /* If we need recovery mode, leave firmware selection now */ + save_if_needed(&ctx); + return; + } + + /* Determine which firmware slot to boot */ + printk(BIOS_INFO, "Phase 2\n"); + rv = vb2api_fw_phase2(&ctx); + if (rv) { + printk(BIOS_INFO, "Reboot requested (%x)\n", rv); + save_if_needed(&ctx); + vboot_reboot(); + } + + /* Try that slot */ + printk(BIOS_INFO, "Phase 3\n"); + rv = vb2api_fw_phase3(&ctx); + if (rv) { + printk(BIOS_INFO, "Reboot requested (%x)\n", rv); + save_if_needed(&ctx); + vboot_reboot(); + } + + printk(BIOS_INFO, "Phase 4\n"); + rv = locate_firmware(&ctx, &fw_main); + if (rv) + die("Failed to read FMAP to locate firmware"); + + rv = hash_body(&ctx, &fw_main); + save_if_needed(&ctx); + if (rv) { + printk(BIOS_INFO, "Reboot requested (%x)\n", rv); + vboot_reboot(); + } + + /* Lock TPM */ + rv = antirollback_lock_space_firmware(); + if (rv) { + printk(BIOS_INFO, "Failed to lock TPM (%x)\n", rv); + vb2api_fail(&ctx, VB2_RECOVERY_RO_TPM_L_ERROR, 0); + save_if_needed(&ctx); + vboot_reboot(); + } + + printk(BIOS_INFO, "Slot %c is selected\n", is_slot_a(&ctx) ? 'A' : 'B'); + vb2_set_selected_region(wd, &fw_main); +} diff --git a/src/vendorcode/google/chromeos/vboot2/verstage.ld b/src/vendorcode/google/chromeos/vboot2/verstage.ld new file mode 100644 index 0000000000..c7fd6462a3 --- /dev/null +++ b/src/vendorcode/google/chromeos/vboot2/verstage.ld @@ -0,0 +1,58 @@ +/* + * 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 + */ + +/* This file is included inside a SECTIONS block */ + +.text . : { + _program = .; + _verstage = .; + *(.text._start); + *(.text.stage_entry); + *(.text); + *(.text.*); +} : to_load + +.data . : { + *(.rodata); + *(.rodata.*); + *(.data); + *(.data.*); + . = ALIGN(8); +} + +.bss . : { + . = ALIGN(8); + _bss = .; + *(.bss) + *(.bss.*) + *(.sbss) + *(.sbss.*) + _ebss = .; + _everstage = .; + _eprogram = .; +} + +/* Discard the sections we don't need/want */ +/DISCARD/ : { + *(.comment) + *(.note) + *(.comment.*) + *(.note.*) + *(.eh_frame); +} diff --git a/src/vendorcode/google/chromeos/vboot2/verstub.c b/src/vendorcode/google/chromeos/vboot2/verstub.c new file mode 100644 index 0000000000..e8faa071c5 --- /dev/null +++ b/src/vendorcode/google/chromeos/vboot2/verstub.c @@ -0,0 +1,97 @@ +/* + * 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 +#include +#include +#include +#include "../chromeos.h" +#include "misc.h" +#include "symbols.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); + /* 8-byte alignment for ARMv7 */ + wd->buffer = ALIGN_UP((uintptr_t)&wd[1], 8); + wd->buffer_size = _vboot2_work_size + (uintptr_t)wd + - (uintptr_t)wd->buffer; + + 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 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(); +#endif /* CONFIG_RETURN_FROM_VERSTAGE */ + + /* jump to the selected slot */ + entry = NULL; + if (vboot_is_slot_selected(wd)) { + /* RW A or B */ + struct vboot_region fw_main; + struct vboot_components *fw_info; + 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"); + 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"); + } + + if (entry != NULL && entry != (void *)-1) + stage_exit(entry); + + die("failed to exit from stage\n"); +} diff --git a/src/vendorcode/google/chromeos/vboot_common.c b/src/vendorcode/google/chromeos/vboot_common.c new file mode 100644 index 0000000000..b2893d9fa9 --- /dev/null +++ b/src/vendorcode/google/chromeos/vboot_common.c @@ -0,0 +1,122 @@ +/* + * This file is part of the coreboot project. + * + * Copyright (C) 2014 The ChromiumOS Authors. All rights reserved. + * + * 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 +#include +#include +#include +#include +#include +#include "chromeos.h" +#include "vboot_common.h" + +void vboot_locate_region(const char *name, struct vboot_region *region) +{ + region->size = find_fmap_entry(name, (void **)®ion->offset_addr); +} + +void *vboot_get_region(uintptr_t offset_addr, size_t size, void *dest) +{ + if (IS_ENABLED(CONFIG_SPI_FLASH_MEMORY_MAPPED)) { + if (dest != NULL) + return memcpy(dest, (void *)offset_addr, size); + else + return (void *)offset_addr; + } else { + struct cbfs_media default_media, *media = &default_media; + void *cache; + + init_default_cbfs_media(media); + media->open(media); + if (dest != NULL) { + cache = dest; + if (media->read(media, dest, offset_addr, size) != size) + cache = NULL; + } else { + cache = media->map(media, offset_addr, size); + if (cache == CBFS_MEDIA_INVALID_MAP_ADDRESS) + cache = NULL; + } + media->close(media); + return cache; + } +} + +int vboot_get_handoff_info(void **addr, uint32_t *size) +{ + struct vboot_handoff *vboot_handoff; + + vboot_handoff = cbmem_find(CBMEM_ID_VBOOT_HANDOFF); + + if (vboot_handoff == NULL) + return -1; + + *addr = vboot_handoff; + *size = sizeof(*vboot_handoff); + return 0; +} + +/* This will leak a mapping of a fw region */ +struct vboot_components *vboot_locate_components(struct vboot_region *region) +{ + size_t req_size; + struct vboot_components *vbc; + + req_size = sizeof(*vbc); + req_size += sizeof(struct vboot_component_entry) * + MAX_PARSED_FW_COMPONENTS; + + vbc = vboot_get_region(region->offset_addr, req_size, NULL); + if (vbc && vbc->num_components > MAX_PARSED_FW_COMPONENTS) + vbc = NULL; + + return vbc; +} + +void *vboot_get_payload(int *len) +{ + struct vboot_handoff *vboot_handoff; + struct firmware_component *fwc; + + vboot_handoff = cbmem_find(CBMEM_ID_VBOOT_HANDOFF); + + if (vboot_handoff == NULL) + return NULL; + + if (CONFIG_VBOOT_BOOT_LOADER_INDEX >= MAX_PARSED_FW_COMPONENTS) { + printk(BIOS_ERR, "Invalid boot loader index: %d\n", + CONFIG_VBOOT_BOOT_LOADER_INDEX); + return NULL; + } + + fwc = &vboot_handoff->components[CONFIG_VBOOT_BOOT_LOADER_INDEX]; + + /* If payload size is zero fall back to cbfs path. */ + if (fwc->size == 0) + return NULL; + + if (len != NULL) + *len = fwc->size; + + printk(BIOS_DEBUG, "Booting 0x%x byte verified payload at 0x%08x.\n", + fwc->size, fwc->address); + + /* This will leak a mapping. */ + return vboot_get_region(fwc->address, fwc->size, NULL); +} diff --git a/src/vendorcode/google/chromeos/vboot_common.h b/src/vendorcode/google/chromeos/vboot_common.h new file mode 100644 index 0000000000..c6c9b50419 --- /dev/null +++ b/src/vendorcode/google/chromeos/vboot_common.h @@ -0,0 +1,55 @@ +/* + * This file is part of the coreboot project. + * + * Copyright (C) 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 + */ +#ifndef VBOOT_COMMON_H +#define VBOOT_COMMON_H + +#include + +struct vboot_region { + uintptr_t offset_addr; + int32_t size; +}; + +/* The FW areas consist of multiple components. At the beginning of + * each area is the number of total compoments as well as the size and + * offset for each component. One needs to caculate the total size of the + * signed firmware region based off of the embedded metadata. */ +struct vboot_component_entry { + uint32_t offset; + uint32_t size; +} __attribute__((packed)); + +struct vboot_components { + uint32_t num_components; + struct vboot_component_entry entries[0]; +} __attribute__((packed)); + +void vboot_locate_region(const char *name, struct vboot_region *region); + +struct vboot_components *vboot_locate_components(struct vboot_region *region); + +/* + * 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 + * is NULL,the region will be mapped to a memory location. NULL is + * returned on error else the location of the requested region. + */ +void *vboot_get_region(uintptr_t offset_addr, size_t size, void *dest); + +#endif /* VBOOT_COMMON_H */ diff --git a/src/vendorcode/google/chromeos/vboot_handoff.c b/src/vendorcode/google/chromeos/vboot_handoff.c deleted file mode 100644 index f929a59a29..0000000000 --- a/src/vendorcode/google/chromeos/vboot_handoff.c +++ /dev/null @@ -1,174 +0,0 @@ -/* - * This file is part of the coreboot project. - * - * Copyright (C) 2013 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 <2recovery_reasons.h> -#include <2struct.h> -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include "chromeos.h" -#include "fmap.h" -#include "vboot_handoff.h" -#include - -static void *load_ramstage(struct vboot_handoff *vboot_handoff, - struct vboot_region *fw_main) -{ - struct vboot_components *fw_info; - 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; - } - - return vboot_load_stage(CONFIG_VBOOT_RAMSTAGE_INDEX, fw_main, fw_info); -} - -/** - * Sets vboot_handoff based on the information in vb2_shared_data - * - * TODO: Read wp switch to set VBSD_BOOT_FIRMWARE_WP_ENABLED - */ -static void fill_vboot_handoff(struct vboot_handoff *vboot_handoff, - struct vb2_shared_data *vb2_sd) -{ - VbSharedDataHeader *vb_sd = - (VbSharedDataHeader *)vboot_handoff->shared_data; - uint32_t *oflags = &vboot_handoff->init_params.out_flags; - - vb_sd->flags |= VBSD_BOOT_FIRMWARE_VBOOT2; - - vboot_handoff->selected_firmware = vb2_sd->fw_slot; - - vb_sd->firmware_index = vb2_sd->fw_slot; - - vb_sd->magic = VB_SHARED_DATA_MAGIC; - vb_sd->struct_version = VB_SHARED_DATA_VERSION; - vb_sd->struct_size = sizeof(VbSharedDataHeader); - vb_sd->data_size = VB_SHARED_DATA_MIN_SIZE; - vb_sd->data_used = sizeof(VbSharedDataHeader); - - if (vb2_sd->recovery_reason) { - vb_sd->firmware_index = 0xFF; - if (vb2_sd->recovery_reason == VB2_RECOVERY_RO_MANUAL) - vb_sd->flags |= VBSD_BOOT_REC_SWITCH_ON; - *oflags |= VB_INIT_OUT_ENABLE_RECOVERY; - *oflags |= VB_INIT_OUT_CLEAR_RAM; - *oflags |= VB_INIT_OUT_ENABLE_DISPLAY; - *oflags |= VB_INIT_OUT_ENABLE_USB_STORAGE; - } - if (vb2_sd->flags & VB2_SD_DEV_MODE_ENABLED) { - *oflags |= VB_INIT_OUT_ENABLE_DEVELOPER; - *oflags |= VB_INIT_OUT_CLEAR_RAM; - *oflags |= VB_INIT_OUT_ENABLE_DISPLAY; - *oflags |= VB_INIT_OUT_ENABLE_USB_STORAGE; - vb_sd->flags |= VBSD_BOOT_DEV_SWITCH_ON; - vb_sd->flags |= VBSD_LF_DEV_SWITCH_ON; - } - /* TODO: Set these in depthcharge */ - if (CONFIG_VIRTUAL_DEV_SWITCH) - vb_sd->flags |= VBSD_HONOR_VIRT_DEV_SWITCH; - if (CONFIG_EC_SOFTWARE_SYNC) { - vb_sd->flags |= VBSD_EC_SOFTWARE_SYNC; - vb_sd->flags |= VBSD_BOOT_REC_SWITCH_VIRTUAL; - } - /* In vboot1, VBSD_FWB_TRIED is - * set only if B is booted as explicitly requested. Therefore, if B is - * booted because A was found bad, the flag should not be set. It's - * better not to touch it if we can only ambiguously control it. */ - /* if (vb2_sd->fw_slot) - vb_sd->flags |= VBSD_FWB_TRIED; */ - - /* copy kernel subkey if it's found */ - if (vb2_sd->workbuf_preamble_size) { - struct vb2_fw_preamble *fp; - uintptr_t dst, src; - printk(BIOS_INFO, "Copying FW preamble\n"); - fp = (struct vb2_fw_preamble *)( (uintptr_t)vb2_sd + - vb2_sd->workbuf_preamble_offset); - src = (uintptr_t)&fp->kernel_subkey + - fp->kernel_subkey.key_offset; - dst = (uintptr_t)vb_sd + sizeof(VbSharedDataHeader); - assert(dst + fp->kernel_subkey.key_size <= - (uintptr_t)vboot_handoff + sizeof(*vboot_handoff)); - memcpy((void *)dst, (void *)src, - fp->kernel_subkey.key_size); - vb_sd->data_used += fp->kernel_subkey.key_size; - vb_sd->kernel_subkey.key_offset = - dst - (uintptr_t)&vb_sd->kernel_subkey; - vb_sd->kernel_subkey.key_size = fp->kernel_subkey.key_size; - vb_sd->kernel_subkey.algorithm = fp->kernel_subkey.algorithm; - vb_sd->kernel_subkey.key_version = - fp->kernel_subkey.key_version; - } - - vb_sd->recovery_reason = vb2_sd->recovery_reason; -} - -/** - * Load ramstage and return the entry point - */ -void *vboot_load_ramstage(void) -{ - struct vboot_handoff *vh; - struct vb2_shared_data *sd; - struct vboot_region fw_main; - struct vb2_working_data *wd = vboot_get_working_data(); - - sd = (struct vb2_shared_data *)(uintptr_t)wd->buffer; - sd->workbuf_hash_offset = 0; - sd->workbuf_hash_size = 0; - - printk(BIOS_INFO, "creating vboot_handoff structure\n"); - vh = cbmem_add(CBMEM_ID_VBOOT_HANDOFF, sizeof(*vh)); - if (vh == NULL) - /* we don't need to failover gracefully here because this - * shouldn't happen with the image that has passed QA. */ - die("failed to allocate vboot_handoff structure\n"); - - memset(vh, 0, sizeof(*vh)); - - /* 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; - - 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); -} diff --git a/src/vendorcode/google/chromeos/vboot_handoff.h b/src/vendorcode/google/chromeos/vboot_handoff.h index b0017438ac..e6b2d6931d 100644 --- a/src/vendorcode/google/chromeos/vboot_handoff.h +++ b/src/vendorcode/google/chromeos/vboot_handoff.h @@ -19,9 +19,20 @@ #ifndef VBOOT_HANDOFF_H #define VBOOT_HANDOFF_H + #include #include #include "chromeos.h" +#include "vboot_common.h" + +/* + * The vboot handoff structure keeps track of a maximum number of firmware + * components in the verfieid RW area of flash. This is not a restriction on + * the number of components packed in a firmware block. It's only the maximum + * number of parsed firmware components (address and size) included in the + * handoff structure. + */ +#define MAX_PARSED_FW_COMPONENTS 5 struct firmware_component { uint32_t address; diff --git a/src/vendorcode/google/chromeos/vboot_loader.c b/src/vendorcode/google/chromeos/vboot_loader.c deleted file mode 100644 index d13608c50e..0000000000 --- a/src/vendorcode/google/chromeos/vboot_loader.c +++ /dev/null @@ -1,416 +0,0 @@ -/* - * This file is part of the coreboot project. - * - * Copyright (C) 2013 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 -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include "chromeos.h" -#include "vboot_context.h" -#include "vboot_handoff.h" - -#define TEMP_CBMEM_ID_VBOOT 0xffffffff -#define TEMP_CBMEM_ID_VBLOCKS 0xfffffffe - -static void vboot_run_stub(struct vboot_context *context) -{ - struct rmod_stage_load rmod_stage = { - .cbmem_id = TEMP_CBMEM_ID_VBOOT, - .name = CONFIG_CBFS_PREFIX "/vboot", - }; - void (*entry)(struct vboot_context *context); - - if (rmodule_stage_load_from_cbfs(&rmod_stage)) { - printk(BIOS_DEBUG, "Could not load vboot stub.\n"); - goto out; - } - - entry = rmod_stage.entry; - - /* Call stub. */ - entry(context); - -out: - /* Tear down the region no longer needed. */ - if (rmod_stage.cbmem_entry != NULL) - cbmem_entry_remove(rmod_stage.cbmem_entry); -} - -/* Helper routines for the vboot stub. */ -static void log_msg(const char *fmt, va_list args) -{ - do_vtxprintf(fmt, args); -} - -static void fatal_error(void) -{ - printk(BIOS_ERR, "vboot encountered fatal error. Resetting.\n"); - hard_reset(); -} - -static int fw_region_size(struct vboot_region *r) -{ - struct vboot_components *fw_info; - int32_t size; - int i; - - fw_info = vboot_locate_components(r); - if (fw_info == NULL) - return -1; - - if (fw_info->num_components > MAX_PARSED_FW_COMPONENTS) - return -1; - - size = sizeof(*fw_info); - size += sizeof(struct vboot_component_entry) * fw_info->num_components; - - for (i = 0; i < fw_info->num_components; i++) - size += ALIGN(fw_info->entries[i].size, sizeof(uint32_t)); - - /* Check that size of comopnents does not exceed the region's size. */ - if (size > r->size) - return -1; - - /* Update region with the correct size. */ - r->size = size; - - return 0; -} - -static int vboot_fill_params(struct vboot_context *ctx) -{ - VbCommonParams *cparams; - VbSelectFirmwareParams *fparams; - - if (fw_region_size(&ctx->fw_a)) - return -1; - - if (fw_region_size(&ctx->fw_b)) - return -1; - - cparams = ctx->cparams; - fparams = ctx->fparams; - - cparams->gbb_size = ctx->gbb.size; - fparams->verification_size_A = ctx->vblock_a.size; - fparams->verification_size_B = ctx->vblock_b.size; - - if (IS_ENABLED(CONFIG_SPI_FLASH_MEMORY_MAPPED)) { - /* Get memory-mapped pointers to the regions. */ - cparams->gbb_data = vboot_get_region(ctx->gbb.offset_addr, - ctx->gbb.size, NULL); - fparams->verification_block_A = - vboot_get_region(ctx->vblock_a.offset_addr, - ctx->vblock_a.size, NULL); - fparams->verification_block_B = - vboot_get_region(ctx->vblock_b.offset_addr, - ctx->vblock_b.size, NULL); - } else { - /* - * Copy the vblock info into a buffer in cbmem. The gbb will - * be read using VbExRegionRead(). - */ - char *dest; - size_t vblck_sz; - - vblck_sz = ctx->vblock_a.size + ctx->vblock_b.size; - ctx->vblocks = cbmem_entry_add(TEMP_CBMEM_ID_VBLOCKS, vblck_sz); - if (ctx->vblocks == NULL) - return -1; - dest = cbmem_entry_start(ctx->vblocks); - if (vboot_get_region(ctx->vblock_a.offset_addr, - ctx->vblock_a.size, dest) == NULL) - return -1; - fparams->verification_block_A = (void *)dest; - dest += ctx->vblock_a.size; - if (vboot_get_region(ctx->vblock_b.offset_addr, - ctx->vblock_b.size, dest) == NULL) - return -1; - fparams->verification_block_B = (void *)dest; - } - - return 0; -} - -static void fill_handoff(struct vboot_context *context) -{ - struct vboot_components *fw_info; - struct vboot_region *region; - int i; - - /* Fix up the handoff structure. */ - context->handoff->selected_firmware = - context->fparams->selected_firmware; - - /* Parse out the components for downstream consumption. */ - if (context->handoff->selected_firmware == VB_SELECT_FIRMWARE_A) - region = &context->fw_a; - else if (context->handoff->selected_firmware == VB_SELECT_FIRMWARE_B) - region = &context->fw_b; - else - return; - - fw_info = vboot_locate_components(region); - if (fw_info == NULL) - return; - - for (i = 0; i < fw_info->num_components; i++) { - context->handoff->components[i].address = - region->offset_addr + fw_info->entries[i].offset; - context->handoff->components[i].size = fw_info->entries[i].size; - } -} - -static void vboot_clean_up(struct vboot_context *context) -{ - if (context->vblocks != NULL) - cbmem_entry_remove(context->vblocks); -} - -static void reset(void) -{ - hard_reset(); -} - -static void vboot_invoke_wrapper(struct vboot_handoff *vboot_handoff) -{ - VbCommonParams cparams; - VbSelectFirmwareParams fparams; - struct vboot_context context; - uint32_t *iflags; - - vboot_handoff->selected_firmware = VB_SELECT_FIRMWARE_READONLY; - - memset(&cparams, 0, sizeof(cparams)); - memset(&fparams, 0, sizeof(fparams)); - memset(&context, 0, sizeof(context)); - - iflags = &vboot_handoff->init_params.flags; - if (get_developer_mode_switch()) - *iflags |= VB_INIT_FLAG_DEV_SWITCH_ON; - if (get_recovery_mode_switch()) { - clear_recovery_mode_switch(); - *iflags |= VB_INIT_FLAG_REC_BUTTON_PRESSED; - } - if (get_write_protect_state()) - *iflags |= VB_INIT_FLAG_WP_ENABLED; - if (vboot_get_sw_write_protect()) - *iflags |= VB_INIT_FLAG_SW_WP_ENABLED; - if (CONFIG_VIRTUAL_DEV_SWITCH) - *iflags |= VB_INIT_FLAG_VIRTUAL_DEV_SWITCH; - if (CONFIG_EC_SOFTWARE_SYNC) { - *iflags |= VB_INIT_FLAG_EC_SOFTWARE_SYNC; - *iflags |= VB_INIT_FLAG_VIRTUAL_REC_SWITCH; - } - if (CONFIG_VBOOT_EC_SLOW_UPDATE) - *iflags |= VB_INIT_FLAG_EC_SLOW_UPDATE; - if (CONFIG_VBOOT_OPROM_MATTERS) { - *iflags |= VB_INIT_FLAG_OPROM_MATTERS; - /* Will load VGA option rom during this boot */ - if (developer_mode_enabled() || recovery_mode_enabled() || - vboot_wants_oprom()) { - *iflags |= VB_INIT_FLAG_OPROM_LOADED; - } - } - - context.handoff = vboot_handoff; - context.cparams = &cparams; - context.fparams = &fparams; - - cparams.shared_data_blob = &vboot_handoff->shared_data[0]; - cparams.shared_data_size = VB_SHARED_DATA_MIN_SIZE; - cparams.caller_context = &context; - - vboot_locate_region("GBB", &context.gbb); - vboot_locate_region("VBLOCK_A", &context.vblock_a); - vboot_locate_region("VBLOCK_B", &context.vblock_b); - vboot_locate_region("FW_MAIN_A", &context.fw_a); - vboot_locate_region("FW_MAIN_B", &context.fw_b); - - /* Check all fmap entries. */ - if (context.fw_a.size < 0 || context.fw_b.size < 0 || - context.vblock_a.size < 0 || context.vblock_b.size < 0 || - context.gbb.size < 0) { - printk(BIOS_DEBUG, "Not all fmap entries found for vboot.\n"); - return; - } - - /* Fill in vboot parameters. */ - if (vboot_fill_params(&context)) { - vboot_clean_up(&context); - return; - } - - /* Initialize callbacks. */ - context.read_vbnv = &read_vbnv; - context.save_vbnv = &save_vbnv; - context.tis_init = &tis_init; - context.tis_open = &tis_open; - context.tis_close = &tis_close; - context.tis_sendrecv = &tis_sendrecv; - context.log_msg = &log_msg; - context.fatal_error = &fatal_error; - context.get_region = &vboot_get_region; - context.reset = &reset; - - vboot_run_stub(&context); - - fill_handoff(&context); - - vboot_clean_up(&context); -} - -#if CONFIG_RELOCATABLE_RAMSTAGE -static void *vboot_load_ramstage(uint32_t cbmem_id, const char *name, - const struct cbmem_entry **cbmem_entry) -{ - struct vboot_handoff *vboot_handoff; - struct cbfs_stage *stage; - const struct firmware_component *fwc; - struct rmod_stage_load rmod_load = { - .cbmem_id = cbmem_id, - .name = name, - }; - - timestamp_add_now(TS_START_VBOOT); - - vboot_handoff = cbmem_add(CBMEM_ID_VBOOT_HANDOFF, - sizeof(*vboot_handoff)); - - if (vboot_handoff == NULL) { - printk(BIOS_DEBUG, "Could not add vboot_handoff structure.\n"); - return NULL; - } - - memset(vboot_handoff, 0, sizeof(*vboot_handoff)); - - vboot_invoke_wrapper(vboot_handoff); - - timestamp_add_now(TS_END_VBOOT); - - /* Take RO firmware path since no RW area was selected. */ - if (vboot_handoff->selected_firmware != VB_SELECT_FIRMWARE_A && - vboot_handoff->selected_firmware != VB_SELECT_FIRMWARE_B) { - printk(BIOS_DEBUG, "No RW firmware selected: 0x%08x\n", - vboot_handoff->selected_firmware); - return NULL; - } - - if (CONFIG_VBOOT_RAMSTAGE_INDEX >= MAX_PARSED_FW_COMPONENTS) { - printk(BIOS_ERR, "Invalid ramstage index: %d\n", - CONFIG_VBOOT_RAMSTAGE_INDEX); - return NULL; - } - - /* Check for invalid address. */ - fwc = &vboot_handoff->components[CONFIG_VBOOT_RAMSTAGE_INDEX]; - if (fwc->address == 0) { - printk(BIOS_DEBUG, "RW ramstage image address invalid.\n"); - return NULL; - } - - printk(BIOS_DEBUG, "RW ramstage image at 0x%08x, 0x%08x bytes.\n", - fwc->address, fwc->size); - - stage = (void *)fwc->address; - - if (rmodule_stage_load(&rmod_load, stage)) { - vboot_handoff->selected_firmware = VB_SELECT_FIRMWARE_READONLY; - printk(BIOS_DEBUG, "Could not load ramstage region.\n"); - return NULL; - } - - *cbmem_entry = rmod_load.cbmem_entry; - - return rmod_load.entry; -} -#else /* CONFIG_RELOCATABLE_RAMSTAGE */ -static void vboot_load_ramstage(struct vboot_handoff *vboot_handoff, - struct romstage_handoff *handoff) -{ - struct cbfs_stage *stage; - const struct firmware_component *fwc; - - if (CONFIG_VBOOT_RAMSTAGE_INDEX >= MAX_PARSED_FW_COMPONENTS) { - printk(BIOS_ERR, "Invalid ramstage index: %d\n", - CONFIG_VBOOT_RAMSTAGE_INDEX); - return; - } - - /* Check for invalid address. */ - fwc = &vboot_handoff->components[CONFIG_VBOOT_RAMSTAGE_INDEX]; - if (fwc->address == 0) { - printk(BIOS_DEBUG, "RW ramstage image address invalid.\n"); - return; - } - - printk(BIOS_DEBUG, "RW ramstage image at 0x%08x, 0x%08x bytes.\n", - fwc->address, fwc->size); - - /* This will leak a mapping. */ - stage = vboot_get_region(fwc->address, fwc->size, NULL); - - if (stage == NULL) { - printk(BIOS_DEBUG, "Unable to get RW ramstage region.\n"); - return; - } - - timestamp_add_now(TS_START_COPYRAM); - - /* 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(struct cbfs_stage), - (void *) (uintptr_t) stage->load, - stage->len)) - return; - - timestamp_add_now(TS_END_COPYRAM); - -#if CONFIG_ARCH_X86 - __asm__ volatile ( - "movl $0, %%ebp\n" - "jmp *%%edi\n" - :: "D"(stage->entry) - ); -#elif CONFIG_ARCH_ARM - stage_exit((void *)(uintptr_t)stage->entry); -#endif -} -#endif /* CONFIG_RELOCATABLE_RAMSTAGE */ - - -const struct ramstage_loader_ops vboot_ramstage_loader = { - .name = "VBOOT", - .load = vboot_load_ramstage, -}; diff --git a/src/vendorcode/google/chromeos/vboot_wrapper.c b/src/vendorcode/google/chromeos/vboot_wrapper.c deleted file mode 100644 index dd6065cb81..0000000000 --- a/src/vendorcode/google/chromeos/vboot_wrapper.c +++ /dev/null @@ -1,266 +0,0 @@ -/* - * This file is part of the coreboot project. - * - * Copyright (C) 2013 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 -#if CONFIG_ARCH_X86 -#include -#else -#include -#endif -#include -#include -#include -#include "vboot_context.h" -#include "vboot_handoff.h" - -/* Keep a global context pointer around for the callbacks to use. */ -static struct vboot_context *gcontext; - -static void vboot_wrapper(void *arg) -{ - VbError_t res; - struct vboot_context *context; - - context = arg; - gcontext = context; - - VbExDebug("Calling VbInit()\n"); - res = VbInit(context->cparams, &context->handoff->init_params); - VbExDebug("VbInit() returned 0x%08x\n", res); - - if (res != VBERROR_SUCCESS) { - if(res == VBERROR_TPM_REBOOT_REQUIRED) { - VbExDebug("TPM Reboot Required. Proceeding reboot.\n"); - gcontext->reset(); - } - return; - } - - VbExDebug("Calling VbSelectFirmware()\n"); - res = VbSelectFirmware(context->cparams, context->fparams); - VbExDebug("VbSelectFirmware() returned 0x%08x\n", res); - - if (res != VBERROR_SUCCESS) - return; -} - -void VbExError(const char *format, ...) -{ - va_list args; - - va_start(args, format); - gcontext->log_msg(format, args); - va_end(args); - - gcontext->fatal_error(); -} - -void VbExDebug(const char *format, ...) -{ - va_list args; - - va_start(args, format); - gcontext->log_msg(format, args); - va_end(args); -} - -uint64_t VbExGetTimer(void) -{ -#if CONFIG_ARCH_X86 - return rdtscll(); -#else - struct mono_time mt; - timer_monotonic_get(&mt); - return mt.microseconds; -#endif -} - -VbError_t VbExNvStorageRead(uint8_t *buf) -{ - gcontext->read_vbnv(buf); - return VBERROR_SUCCESS; -} - -VbError_t VbExNvStorageWrite(const uint8_t *buf) -{ - gcontext->save_vbnv(buf); - return VBERROR_SUCCESS; -} - -extern char _heap[]; -extern char _eheap[]; -static char *heap_current; -static int heap_size; - -void *VbExMalloc(size_t size) -{ - void *ptr; - - if (heap_current == NULL) { - heap_current = &_heap[0]; - heap_size = &_eheap[0] - &_heap[0]; - VbExDebug("vboot heap: %p 0x%08x bytes\n", - heap_current, heap_size); - } - - if (heap_size < size) { - VbExError("vboot heap request cannot be fulfilled. " - "0x%08x available, 0x%08x requested\n", - heap_size, size); - } - - ptr = heap_current; - heap_size -= size; - heap_current += size; - - return ptr; -} - -void VbExFree(void *ptr) -{ - /* Leak all memory. */ -} - -/* vboot doesn't expose these through the vboot_api.h, but they are needed. - * coreboot requires declarations so provide them to avoid compiler errors. */ -int Memcmp(const void *src1, const void *src2, size_t n); -void *Memcpy(void *dest, const void *src, uint64_t n); -void *Memset(void *dest, const uint8_t c, uint64_t n); - -int Memcmp(const void *src1, const void *src2, size_t n) -{ - return memcmp(src1, src2, n); -} - -void *Memcpy(void *dest, const void *src, uint64_t n) -{ - return memcpy(dest, src, n); -} - -void *Memset(void *dest, const uint8_t c, uint64_t n) -{ - return memset(dest, c, n); -} - -static inline size_t get_hash_block_size(size_t requested_size) -{ - if (!IS_ENABLED(CONFIG_SPI_FLASH_MEMORY_MAPPED)) { - const size_t block_size = 64 * 1024; - if (requested_size > block_size) - return block_size; - } - return requested_size; -} - -VbError_t VbExHashFirmwareBody(VbCommonParams *cparams, uint32_t firmware_index) -{ - uint8_t *data; - struct vboot_region *region; - struct vboot_context *ctx; - size_t data_size; - uintptr_t offset_addr; - - ctx = cparams->caller_context; - - switch (firmware_index) { - case VB_SELECT_FIRMWARE_A: - region = &ctx->fw_a; - break; - case VB_SELECT_FIRMWARE_B: - region = &ctx->fw_b; - break; - default: - return VBERROR_UNKNOWN; - } - - data_size = region->size; - offset_addr = region->offset_addr; - while (data_size) { - size_t block_size; - - block_size = get_hash_block_size(data_size); - data = ctx->get_region(offset_addr, block_size, NULL); - if (data == NULL) - return VBERROR_UNKNOWN; - VbUpdateFirmwareBodyHash(cparams, data, block_size); - - data_size -= block_size; - offset_addr += block_size; - } - - return VBERROR_SUCCESS; -} - -VbError_t VbExTpmInit(void) -{ - if (gcontext->tis_init()) - return VBERROR_UNKNOWN; - return VbExTpmOpen(); -} - -VbError_t VbExTpmClose(void) -{ - if (gcontext->tis_close()) - return VBERROR_UNKNOWN; - return VBERROR_SUCCESS; -} - -VbError_t VbExTpmOpen(void) -{ - if (gcontext->tis_open()) - return VBERROR_UNKNOWN; - return VBERROR_SUCCESS; -} - -VbError_t VbExTpmSendReceive(const uint8_t *request, uint32_t request_length, - uint8_t *response, uint32_t *response_length) -{ - size_t len = *response_length; - if (gcontext->tis_sendrecv(request, request_length, response, &len)) - return VBERROR_UNKNOWN; - /* check 64->32bit overflow and (re)check response buffer overflow */ - if (len > *response_length) - return VBERROR_UNKNOWN; - *response_length = len; - return VBERROR_SUCCESS; -} - -#if !CONFIG_SPI_FLASH_MEMORY_MAPPED -VbError_t VbExRegionRead(VbCommonParams *cparams, - enum vb_firmware_region region, uint32_t offset, - uint32_t size, void *buf) -{ - struct vboot_context *ctx; - VbExDebug("VbExRegionRead: offset=%x size=%x, buf=%p\n", - offset, size, buf); - ctx = cparams->caller_context; - - if (region == VB_REGION_GBB) { - if (offset + size > cparams->gbb_size) - return VBERROR_REGION_READ_INVALID; - offset += ctx->gbb.offset_addr; - if (ctx->get_region(offset, size, buf) == NULL) - return VBERROR_REGION_READ_INVALID; - return VBERROR_SUCCESS; - } - - return VBERROR_UNSUPPORTED_REGION; -} -#endif /* CONFIG_SPI_FLASH_MEMORY_MAPPED */ - -RMODULE_ENTRY(vboot_wrapper); diff --git a/src/vendorcode/google/chromeos/verstage.c b/src/vendorcode/google/chromeos/verstage.c deleted file mode 100644 index 1b42bb6830..0000000000 --- a/src/vendorcode/google/chromeos/verstage.c +++ /dev/null @@ -1,251 +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 <2api.h> -#include <2struct.h> -#include -#include -#include -#include - -#include "chromeos.h" - -#define TODO_BLOCK_SIZE 1024 - -static int is_slot_a(struct vb2_context *ctx) -{ - return !(ctx->flags & VB2_CONTEXT_FW_SLOT_B); -} - -/* exports */ - -void vb2ex_printf(const char *func, const char *fmt, ...) -{ - va_list args; - - printk(BIOS_INFO, "VB2:%s() ", func); - va_start(args, fmt); - vprintk(BIOS_INFO, fmt, args); - va_end(args); - - return; -} - -int vb2ex_tpm_clear_owner(struct vb2_context *ctx) -{ - uint32_t rv; - printk(BIOS_INFO, "Clearing TPM owner\n"); - rv = tpm_clear_and_reenable(); - if (rv) - return VB2_ERROR_EX_TPM_CLEAR_OWNER; - return VB2_SUCCESS; -} - -int vb2ex_read_resource(struct vb2_context *ctx, - enum vb2_resource_index index, - uint32_t offset, - void *buf, - uint32_t size) -{ - struct vboot_region region; - - switch (index) { - case VB2_RES_GBB: - vboot_locate_region("GBB", ®ion); - break; - case VB2_RES_FW_VBLOCK: - if (is_slot_a(ctx)) - vboot_locate_region("VBLOCK_A", ®ion); - else - vboot_locate_region("VBLOCK_B", ®ion); - break; - default: - return VB2_ERROR_EX_READ_RESOURCE_INDEX; - } - - if (offset + size > region.size) - return VB2_ERROR_EX_READ_RESOURCE_SIZE; - - if (vboot_get_region(region.offset_addr + offset, size, buf) == NULL) - return VB2_ERROR_UNKNOWN; - - return VB2_SUCCESS; -} - -static int hash_body(struct vb2_context *ctx, struct vboot_region *fw_main) -{ - uint32_t expected_size; - MAYBE_STATIC 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_firmware(struct vb2_context *ctx, - struct vboot_region *fw_main) -{ - if (is_slot_a(ctx)) - vboot_locate_region("FW_MAIN_A", fw_main); - else - vboot_locate_region("FW_MAIN_B", fw_main); - - if (fw_main->size < 0) - return 1; - - return 0; -} - -/** - * 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) { - printk(BIOS_INFO, "Saving nvdata\n"); - save_vbnv(ctx->nvdata); - ctx->flags &= ~VB2_CONTEXT_NVDATA_CHANGED; - } - if (ctx->flags & VB2_CONTEXT_SECDATA_CHANGED) { - printk(BIOS_INFO, "Saving secdata\n"); - antirollback_write_space_firmware(ctx); - ctx->flags &= ~VB2_CONTEXT_SECDATA_CHANGED; - } -} - -/** - * Verify and select the firmware in the RW image - * - * TODO: Avoid loading a stage twice (once in hash_body & again in load_stage). - * when per-stage verification is ready. - */ -#if CONFIG_RETURN_FROM_VERSTAGE -void main(void) -#else -void verstage_main(void) -#endif /* CONFIG_RETURN_FROM_VERSTAGE */ -{ - struct vb2_context ctx; - struct vboot_region fw_main; - struct vb2_working_data *wd = vboot_get_working_data(); - int rv; - - /* Set up context and work buffer */ - memset(&ctx, 0, sizeof(ctx)); - ctx.workbuf = (uint8_t *)(uintptr_t)wd->buffer; - ctx.workbuf_size = wd->buffer_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 */ - printk(BIOS_INFO, "Phase 1\n"); - rv = vb2api_fw_phase1(&ctx); - if (rv) { - printk(BIOS_INFO, "Recovery requested (%x)\n", rv); - /* If we need recovery mode, leave firmware selection now */ - save_if_needed(&ctx); - return; - } - - /* Determine which firmware slot to boot */ - printk(BIOS_INFO, "Phase 2\n"); - rv = vb2api_fw_phase2(&ctx); - if (rv) { - printk(BIOS_INFO, "Reboot requested (%x)\n", rv); - save_if_needed(&ctx); - vboot_reboot(); - } - - /* Try that slot */ - printk(BIOS_INFO, "Phase 3\n"); - rv = vb2api_fw_phase3(&ctx); - if (rv) { - printk(BIOS_INFO, "Reboot requested (%x)\n", rv); - save_if_needed(&ctx); - vboot_reboot(); - } - - printk(BIOS_INFO, "Phase 4\n"); - rv = locate_firmware(&ctx, &fw_main); - if (rv) - die("Failed to read FMAP to locate firmware"); - - rv = hash_body(&ctx, &fw_main); - save_if_needed(&ctx); - if (rv) { - printk(BIOS_INFO, "Reboot requested (%x)\n", rv); - vboot_reboot(); - } - - /* Lock TPM */ - rv = antirollback_lock_space_firmware(); - if (rv) { - printk(BIOS_INFO, "Failed to lock TPM (%x)\n", rv); - vb2api_fail(&ctx, VB2_RECOVERY_RO_TPM_L_ERROR, 0); - save_if_needed(&ctx); - vboot_reboot(); - } - - printk(BIOS_INFO, "Slot %c is selected\n", is_slot_a(&ctx) ? 'A' : 'B'); - vb2_set_selected_region(wd, &fw_main); -} diff --git a/src/vendorcode/google/chromeos/verstage.ld b/src/vendorcode/google/chromeos/verstage.ld deleted file mode 100644 index c7fd6462a3..0000000000 --- a/src/vendorcode/google/chromeos/verstage.ld +++ /dev/null @@ -1,58 +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 - */ - -/* This file is included inside a SECTIONS block */ - -.text . : { - _program = .; - _verstage = .; - *(.text._start); - *(.text.stage_entry); - *(.text); - *(.text.*); -} : to_load - -.data . : { - *(.rodata); - *(.rodata.*); - *(.data); - *(.data.*); - . = ALIGN(8); -} - -.bss . : { - . = ALIGN(8); - _bss = .; - *(.bss) - *(.bss.*) - *(.sbss) - *(.sbss.*) - _ebss = .; - _everstage = .; - _eprogram = .; -} - -/* Discard the sections we don't need/want */ -/DISCARD/ : { - *(.comment) - *(.note) - *(.comment.*) - *(.note.*) - *(.eh_frame); -} diff --git a/src/vendorcode/google/chromeos/verstub.c b/src/vendorcode/google/chromeos/verstub.c deleted file mode 100644 index eb91c22977..0000000000 --- a/src/vendorcode/google/chromeos/verstub.c +++ /dev/null @@ -1,96 +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 -#include -#include -#include -#include "chromeos.h" -#include "symbols.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); - /* 8-byte alignment for ARMv7 */ - wd->buffer = ALIGN_UP((uintptr_t)&wd[1], 8); - wd->buffer_size = _vboot2_work_size + (uintptr_t)wd - - (uintptr_t)wd->buffer; - - 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 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(); -#endif /* CONFIG_RETURN_FROM_VERSTAGE */ - - /* jump to the selected slot */ - entry = NULL; - if (vboot_is_slot_selected(wd)) { - /* RW A or B */ - struct vboot_region fw_main; - struct vboot_components *fw_info; - 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"); - 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"); - } - - if (entry != NULL && entry != (void *)-1) - stage_exit(entry); - - die("failed to exit from stage\n"); -} -- cgit v1.2.3