summaryrefslogtreecommitdiff
path: root/src/vendorcode/google/chromeos/vboot2
diff options
context:
space:
mode:
authorDaisuke Nojiri <dnojiri@chromium.org>2014-10-10 10:51:06 -0700
committerAaron Durbin <adurbin@chromium.org>2015-04-10 16:46:55 +0200
commit742fc8d768829eaa3ff1048a4b101f7fad8c8ab7 (patch)
treef69c92a7f9585525a661498c3eb8e9ab1febf1cd /src/vendorcode/google/chromeos/vboot2
parentb952f6b68b025bbb9d13deffd3bd621a236537c7 (diff)
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 <dnojiri@chromium.org> Original-Change-Id: Ia9fb41ba30930b79b222269acfade7ef44b23626 Original-Reviewed-on: https://chromium-review.googlesource.com/222874 Original-Reviewed-by: Daisuke Nojiri <dnojiri@chromium.org> Original-Commit-Queue: Daisuke Nojiri <dnojiri@chromium.org> Original-Tested-by: Daisuke Nojiri <dnojiri@chromium.org> (cherry picked from commit cbfef9ad40776d890e2149b9db788fe0b387d210) Signed-off-by: Aaron Durbin <adurbin@chromium.org> Change-Id: Ia73696accfd93cc14ca83516fa77f87331faef51 Reviewed-on: http://review.coreboot.org/9433 Tested-by: build bot (Jenkins) Reviewed-by: Patrick Georgi <pgeorgi@google.com>
Diffstat (limited to 'src/vendorcode/google/chromeos/vboot2')
-rw-r--r--src/vendorcode/google/chromeos/vboot2/Kconfig43
-rw-r--r--src/vendorcode/google/chromeos/vboot2/Makefile.inc60
-rw-r--r--src/vendorcode/google/chromeos/vboot2/antirollback.c329
-rw-r--r--src/vendorcode/google/chromeos/vboot2/common.c70
-rw-r--r--src/vendorcode/google/chromeos/vboot2/memlayout.h47
-rw-r--r--src/vendorcode/google/chromeos/vboot2/misc.h72
-rw-r--r--src/vendorcode/google/chromeos/vboot2/symbols.h32
-rw-r--r--src/vendorcode/google/chromeos/vboot2/vboot_handoff.c175
-rw-r--r--src/vendorcode/google/chromeos/vboot2/verstage.c252
-rw-r--r--src/vendorcode/google/chromeos/vboot2/verstage.ld58
-rw-r--r--src/vendorcode/google/chromeos/vboot2/verstub.c97
11 files changed, 1235 insertions, 0 deletions
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 <antirollback.h>
+#include <tpm_lite/tlcl.h>
+#include <tpm_lite/tss_constants.h>
+
+#ifndef offsetof
+#define offsetof(A,B) __builtin_offsetof(A,B)
+#endif
+
+#ifdef FOR_TEST
+#include <stdio.h>
+#define VBDEBUG(format, args...) printf(format, ## args)
+#else
+#include <console/console.h>
+#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 <cbfs.h>
+#include <console/console.h>
+#include <reset.h>
+#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<stage> and _<stage>_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 <arch/stages.h>
+#include <assert.h>
+#include <stdint.h>
+#include <stddef.h>
+#include <string.h>
+#include <cbfs.h>
+#include <cbmem.h>
+#include <console/console.h>
+#include <console/vtxprintf.h>
+#include <stdlib.h>
+#include <timestamp.h>
+#include <vboot_struct.h>
+#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 <antirollback.h>
+#include <console/console.h>
+#include <console/vtxprintf.h>
+#include <string.h>
+
+#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", &region);
+ break;
+ case VB2_RES_FW_VBLOCK:
+ if (is_slot_a(ctx))
+ vboot_locate_region("VBLOCK_A", &region);
+ else
+ vboot_locate_region("VBLOCK_B", &region);
+ 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 <arch/stages.h>
+#include <cbfs.h>
+#include <console/console.h>
+#include <string.h>
+#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");
+}