[coreboot-gerrit] Patch set updated for coreboot: ac1efe4 vboot2: separate verstage from bootblock

Aaron Durbin (adurbin@google.com) gerrit at coreboot.org
Mon Mar 23 22:55:33 CET 2015


Aaron Durbin (adurbin at google.com) just uploaded a new patch set to gerrit, which you can find at http://review.coreboot.org/8881

-gerrit

commit ac1efe43d7394ab77985549cd3954a7379dde8a4
Author: Daisuke Nojiri <dnojiri at chromium.org>
Date:   Thu Sep 4 09:55:34 2014 -0700

    vboot2: separate verstage from bootblock
    
    With CONFIG_RETURN_FROM_VERSTAGE false, the verstage loads the romstage over
    the bootblock, then exits to the romstage. this is necessary for some SOC
    (e.g. tegra124) which runs the bootblock on a different architecture.
    
    With CONFIG_RETURN_FROM_VERSTAGE true, the verstage returns to the bootblock.
    Then, the bootblock loads the romstage over the verstage and exits to the
    romstage. this is probably necessary for some SOC (e.g. rockchip) which does not
    have SRAM big enough to fit the verstage and the romstage at the same time.
    
    BUG=none
    TEST=Built Blaze with USE=+/-vboot2. Ran faft on Blaze.
    BRANCH=none
    Original-Signed-off-by: Daisuke Nojiri <dnojiri at chromium.org>
    Original-Change-Id: I673945c5e21afc800d523fbb25d49fdc83693544
    Original-Reviewed-on: https://chromium-review.googlesource.com/212365
    Original-Reviewed-by: Aaron Durbin <adurbin at chromium.org>
    
    Note: This purposefully is probably broken in vendorcode/google/chromeos
    as I'm just trying to set a base for dropping more patches in. The vboot
    paths will have to change from how they are currently constructed.
    
    (cherry picked from commit 4fa17395113d86445660091413ecb005485f8014)
    Signed-off-by: Aaron Durbin <adurbin at chromium.org>
    
    Change-Id: I9117434ce99695f9b7021a06196d864f180df5c9
---
 Makefile.inc                                   |   6 -
 src/arch/arm/Makefile.inc                      |   5 +-
 src/arch/arm/bootblock.ld                      |   1 -
 src/arch/arm/verstage.ld                       |  67 ++++++
 src/mainboard/google/nyan/romstage.c           |   3 +-
 src/mainboard/google/nyan_big/romstage.c       |   3 +-
 src/mainboard/google/nyan_blaze/Kconfig        |   1 +
 src/mainboard/google/nyan_blaze/Makefile.inc   |   2 +-
 src/mainboard/google/nyan_blaze/romstage.c     |  21 +-
 src/soc/nvidia/tegra124/Kconfig                |  24 ++-
 src/soc/nvidia/tegra124/bootblock.c            |  13 +-
 src/soc/nvidia/tegra124/verstage.c             |  58 ++++-
 src/soc/nvidia/tegra124/verstage.h             |   2 -
 src/vendorcode/google/chromeos/Kconfig         |  39 +++-
 src/vendorcode/google/chromeos/Makefile.inc    |  32 +--
 src/vendorcode/google/chromeos/chromeos.c      | 284 +++++++++++++++++++++++++
 src/vendorcode/google/chromeos/chromeos.h      |  61 +++++-
 src/vendorcode/google/chromeos/vboot_context.h |  11 +-
 src/vendorcode/google/chromeos/vboot_handoff.c |  77 ++++---
 src/vendorcode/google/chromeos/vboot_handoff.h |  11 +-
 src/vendorcode/google/chromeos/vboot_loader.c  |  54 +----
 src/vendorcode/google/chromeos/verstage.c      | 250 ++++++----------------
 src/vendorcode/google/chromeos/verstub.c       |  93 ++++++++
 23 files changed, 781 insertions(+), 337 deletions(-)

diff --git a/Makefile.inc b/Makefile.inc
index bf1b95a..8d732ea 100644
--- a/Makefile.inc
+++ b/Makefile.inc
@@ -131,8 +131,6 @@ ramstage-postprocess=$(foreach d,$(sort $(dir $(1))), \
 	$(eval $(d)ramstage.o: $(call files-in-dir,$(d),$(1)); $$(LD_ramstage) -o $$@ -r $$^ ) \
 	$(eval ramstage-objs:=$(d)ramstage.o $(filter-out $(call files-in-dir,$(d),$(1)),$(ramstage-objs))))
 
-verstage-c-ccopts:=-D__PRE_RAM__ -D__VER_STAGE__
-verstage-S-ccopts:=-D__PRE_RAM__ -D__VER_STAGE__
 romstage-c-ccopts:=-D__PRE_RAM__
 romstage-S-ccopts:=-D__PRE_RAM__
 ifeq ($(CONFIG_TRACE),y)
@@ -360,10 +358,6 @@ $(obj)/%.romstage.o $(abspath $(obj))/%.romstage.o: $(obj)/%.c $(obj)/config.h $
 	@printf "    CC         $(subst $(obj)/,,$(@))\n"
 	$(CC_romstage) -MMD $(CFLAGS_romstage) $(CPPFLAGS_romstage) $(romstage-c-ccopts) -c -o $@ $<
 
-$(obj)/%.verstage.o $(abspath $(obj))/%.verstage.o: $(obj)/%.c $(obj)/config.h $(OPTION_TABLE_H)
-	@printf "    CC         $(subst $(obj)/,,$(@))\n"
-	$(CC_verstage) -MMD $(CFLAGS_verstage) $(verstage-c-ccopts) -c -o $@ $<
-
 $(obj)/%.bootblock.o $(abspath $(obj))/%.bootblock.o: $(obj)/%.c $(obj)/config.h $(OPTION_TABLE_H)
 	@printf "    CC         $(subst $(obj)/,,$(@))\n"
 	$(CC_bootblock) -MMD $(CFLAGS_bootblock) $(CPPFLAGS_bootblock) $(bootblock-c-ccopts) -c -o $@ $<
diff --git a/src/arch/arm/Makefile.inc b/src/arch/arm/Makefile.inc
index e339be1..25f764c 100644
--- a/src/arch/arm/Makefile.inc
+++ b/src/arch/arm/Makefile.inc
@@ -72,7 +72,10 @@ endif # CONFIG_ARCH_BOOTBLOCK_ARM
 # verification stage
 ###############################################################################
 
-verstage-y += early_console.c
+$(objcbfs)/verstage.debug: $$(verstage-objs) $(src)/arch/arm/verstage.ld $(obj)/ldoptions $$(VB2_LIB)
+	@printf "    LINK       $(subst $(obj)/,,$(@))\n"
+	$(LD_verstage) --gc-sections -static -o $@ -L$(obj) --start-group $(verstage-objs) --end-group -T $(src)/arch/arm/verstage.ld
+
 verstage-y += div0.c
 verstage-y += eabi_compat.c
 verstage-y += memset.S
diff --git a/src/arch/arm/bootblock.ld b/src/arch/arm/bootblock.ld
index 8a410ec..23d66f1 100644
--- a/src/arch/arm/bootblock.ld
+++ b/src/arch/arm/bootblock.ld
@@ -51,7 +51,6 @@ SECTIONS
 	} : to_load = 0xff
 
 	preram_cbmem_console = CONFIG_CONSOLE_PRERAM_BUFFER_BASE;
-	verstage_preram_cbmem_console = CONFIG_CONSOLE_PRERAM_BUFFER_BASE;
 
 	/DISCARD/ : {
 		*(.comment)
diff --git a/src/arch/arm/verstage.ld b/src/arch/arm/verstage.ld
new file mode 100644
index 0000000..f0e88e5
--- /dev/null
+++ b/src/arch/arm/verstage.ld
@@ -0,0 +1,67 @@
+/*
+ *	Memory map:
+ *
+ *	CONFIG_VERSTAGE_BASE	: text segment
+ *				: rodata segment
+ *				: data segment
+ *				: bss segment
+ */
+
+/* We use ELF as output format. So that we can debug the code in some form. */
+OUTPUT_FORMAT("elf32-littlearm", "elf32-littlearm", "elf32-littlearm")
+OUTPUT_ARCH(arm)
+INCLUDE ldoptions
+
+PHDRS
+{
+	to_load PT_LOAD;
+}
+
+ENTRY(stage_entry)
+
+SECTIONS
+{
+	. = CONFIG_VERSTAGE_BASE;
+
+	.romtext . : {
+		_start = .;
+		*(.text.stage_entry.arm);
+		*(.text.startup);
+		*(.text);
+		*(.text.*);
+	} : to_load
+
+	.romdata . : {
+		*(.rodata);
+		*(.rodata.*);
+		*(.data);
+		*(.data.*);
+		. = ALIGN(8);
+	}
+
+	/* bss does not contain data, it is just a space that should be zero
+	 * initialized on startup. (typically uninitialized global variables)
+	 */
+	.bss . : {
+		. = ALIGN(8);
+		_bss = .;
+		*(.bss)
+		*(.bss.*)
+		*(.sbss)
+		*(.sbss.*)
+		_ebss = .;
+	}
+
+	_end = .;
+
+	preram_cbmem_console = CONFIG_CONSOLE_PRERAM_BUFFER_BASE;
+
+	/* Discard the sections we don't need/want */
+	/DISCARD/ : {
+		*(.comment)
+		*(.note)
+		*(.comment.*)
+		*(.note.*)
+		*(.eh_frame);
+	}
+}
diff --git a/src/mainboard/google/nyan/romstage.c b/src/mainboard/google/nyan/romstage.c
index 0baf2b7..fffe0de 100644
--- a/src/mainboard/google/nyan/romstage.c
+++ b/src/mainboard/google/nyan/romstage.c
@@ -46,8 +46,6 @@ static void __attribute__((noinline)) romstage(void)
 	timestamp_init(0);
 	timestamp_add_now(TS_START_ROMSTAGE);
 
-	configure_l2_cache();
-
 	console_init();
 	exception_init();
 
@@ -58,6 +56,7 @@ static void __attribute__((noinline)) romstage(void)
 	u32 dram_end = sdram_max_addressable_mb();	/* plus one... */
 	u32 dram_size = dram_end - dram_start;
 
+	configure_l2_cache();
 	mmu_init();
 	/* Device memory below DRAM is uncached. */
 	mmu_config_range(0, dram_start, DCACHE_OFF);
diff --git a/src/mainboard/google/nyan_big/romstage.c b/src/mainboard/google/nyan_big/romstage.c
index 0baf2b7..fffe0de 100644
--- a/src/mainboard/google/nyan_big/romstage.c
+++ b/src/mainboard/google/nyan_big/romstage.c
@@ -46,8 +46,6 @@ static void __attribute__((noinline)) romstage(void)
 	timestamp_init(0);
 	timestamp_add_now(TS_START_ROMSTAGE);
 
-	configure_l2_cache();
-
 	console_init();
 	exception_init();
 
@@ -58,6 +56,7 @@ static void __attribute__((noinline)) romstage(void)
 	u32 dram_end = sdram_max_addressable_mb();	/* plus one... */
 	u32 dram_size = dram_end - dram_start;
 
+	configure_l2_cache();
 	mmu_init();
 	/* Device memory below DRAM is uncached. */
 	mmu_config_range(0, dram_start, DCACHE_OFF);
diff --git a/src/mainboard/google/nyan_blaze/Kconfig b/src/mainboard/google/nyan_blaze/Kconfig
index 789937f..9557ec4 100644
--- a/src/mainboard/google/nyan_blaze/Kconfig
+++ b/src/mainboard/google/nyan_blaze/Kconfig
@@ -93,6 +93,7 @@ config EC_GOOGLE_CHROMEEC_SPI_BUS
 
 config VBOOT_RAMSTAGE_INDEX
 	hex
+	default 0x3 if VBOOT2_VERIFY_FIRMWARE
 	default 0x2
 
 config FLASHMAP_OFFSET
diff --git a/src/mainboard/google/nyan_blaze/Makefile.inc b/src/mainboard/google/nyan_blaze/Makefile.inc
index daf9039..8cfa298 100644
--- a/src/mainboard/google/nyan_blaze/Makefile.inc
+++ b/src/mainboard/google/nyan_blaze/Makefile.inc
@@ -30,9 +30,9 @@ subdirs-y += bct
 bootblock-y += bootblock.c
 bootblock-y += pmic.c
 bootblock-y += reset.c
-bootblock-y += early_configs.c
 
 verstage-$(CONFIG_CHROMEOS) += chromeos.c
+verstage-y += early_configs.c
 verstage-y += reset.c
 
 romstage-y += early_configs.c
diff --git a/src/mainboard/google/nyan_blaze/romstage.c b/src/mainboard/google/nyan_blaze/romstage.c
index cfeb77a..65596a2 100644
--- a/src/mainboard/google/nyan_blaze/romstage.c
+++ b/src/mainboard/google/nyan_blaze/romstage.c
@@ -46,8 +46,6 @@ static void __attribute__((noinline)) romstage(void)
 	timestamp_init(0);
 	timestamp_add_now(TS_START_ROMSTAGE);
 
-	configure_l2_cache();
-
 	console_init();
 	exception_init();
 
@@ -58,21 +56,25 @@ static void __attribute__((noinline)) romstage(void)
 	u32 dram_end = sdram_max_addressable_mb();	/* plus one... */
 	u32 dram_size = dram_end - dram_start;
 
+#if !CONFIG_VBOOT2_VERIFY_FIRMWARE
+	configure_l2_cache();
 	mmu_init();
 	/* Device memory below DRAM is uncached. */
 	mmu_config_range(0, dram_start, DCACHE_OFF);
 	/* SRAM is cached. Round the size up to 2MB, the LPAE page size. */
 	mmu_config_range(0x40000000 >> 20, 2, DCACHE_WRITEBACK);
-	/* DRAM is cached. */
-	mmu_config_range(dram_start, dram_size, DCACHE_WRITEBACK);
-	/* A window for DMA is uncached. */
-	mmu_config_range(CONFIG_DRAM_DMA_START >> 20,
-			 CONFIG_DRAM_DMA_SIZE >> 20, DCACHE_OFF);
 	/* The space above DRAM is uncached. */
 	if (dram_end < 4096)
 		mmu_config_range(dram_end, 4096 - dram_end, DCACHE_OFF);
 	mmu_disable_range(0, 1);
 	dcache_mmu_enable();
+#endif
+
+	/* DRAM is cached. */
+	mmu_config_range(dram_start, dram_size, DCACHE_WRITEBACK);
+	/* A window for DMA is uncached. */
+	mmu_config_range(CONFIG_DRAM_DMA_START >> 20,
+			 CONFIG_DRAM_DMA_SIZE >> 20, DCACHE_OFF);
 
 	/*
 	 * A watchdog reset only resets part of the system so it ends up in
@@ -91,8 +93,9 @@ static void __attribute__((noinline)) romstage(void)
 	early_mainboard_init();
 
 #if CONFIG_VBOOT2_VERIFY_FIRMWARE
-	vboot_create_handoff((void *)CONFIG_VBOOT_WORK_BUFFER_ADDRESS);
+	entry = vboot_load_ramstage();
 #else
+	early_mainboard_init();
 	vboot_verify_firmware(romstage_handoff_find_or_add());
 #endif
 
@@ -102,7 +105,9 @@ static void __attribute__((noinline)) romstage(void)
 /* Stub to force arm_init_caches to the top, before any stack/memory accesses */
 void main(void)
 {
+#if !CONFIG_VBOOT2_VERIFY_FIRMWARE
 	asm volatile ("bl arm_init_caches"
 		      ::: "r0","r1","r2","r3","r4","r5","ip");
+#endif
 	romstage();
 }
diff --git a/src/soc/nvidia/tegra124/Kconfig b/src/soc/nvidia/tegra124/Kconfig
index fddb6da..4fcc6b4 100644
--- a/src/soc/nvidia/tegra124/Kconfig
+++ b/src/soc/nvidia/tegra124/Kconfig
@@ -38,6 +38,16 @@ config BOOTBLOCK_CPU_INIT
 # 0x4002_0000 Bootblock (max 48KB).
 # 0x4002_C000 ROM stage (max 80KB).
 # 0x4003_FFFF End of iRAM.
+#
+# if VBOOT2_VERIFY_FIRMWARE,
+# 0x4000_0000 TTB (16K+32B). 32B is for L1 table of LPAE.
+# 0x4000_4020 CBMEM console area (8K-32B)
+# 0x4000_6000 CBFS mapping cache (72K)
+# 0x4001_8000 vboot work buffer (16K)
+# 0x4001_C000 Stack (16KB... don't reduce without comparing LZMA scratchpad!).
+# 0x4002_0000 bootblock and romstage (max 70KB).
+# 0x4003_1000 verstage (max 60KB).
+# 0x4003_FFFF End of iRAM.
 
 config BOOTBLOCK_ROM_OFFSET
 	hex
@@ -45,12 +55,10 @@ config BOOTBLOCK_ROM_OFFSET
 
 config CBFS_HEADER_ROM_OFFSET
 	hex "offset of master CBFS header in ROM"
-	default 0x1e000 if VBOOT2_VERIFY_FIRMWARE
 	default 0x18000
 
 config CBFS_ROM_OFFSET
 	hex "offset of CBFS data in ROM"
-	default 0x1e080 if VBOOT2_VERIFY_FIRMWARE
 	default 0x18080
 
 config SYS_SDRAM_BASE
@@ -61,9 +69,16 @@ config BOOTBLOCK_BASE
 	hex
 	default 0x40020000
 
+# this has to be big enough to leave room big enough for the larger of the
+# bootblock and the romstage.
+config VERSTAGE_BASE
+	hex
+	default 0x40031000
+
+# with vboot2, romstage is loaded over to the bootblock space
 config ROMSTAGE_BASE
 	hex
-	default 0x4002d000 if VBOOT2_VERIFY_FIRMWARE
+	default 0x40020000 if VBOOT2_VERIFY_FIRMWARE
 	default 0x4002c000
 
 config RAMSTAGE_BASE
@@ -94,7 +109,8 @@ config CBFS_CACHE_ADDRESS
 
 config CBFS_CACHE_SIZE
 	hex "size of CBFS cache data"
-	default 0x00017fe0
+	default 0x00012000 if VBOOT2_VERIFY_FIRMWARE
+	default 0x00016000
 
 config VBOOT_WORK_BUFFER_ADDRESS
 	hex "memory address of vboot work buffer"
diff --git a/src/soc/nvidia/tegra124/bootblock.c b/src/soc/nvidia/tegra124/bootblock.c
index 1d18f1e..f08ca41 100644
--- a/src/soc/nvidia/tegra124/bootblock.c
+++ b/src/soc/nvidia/tegra124/bootblock.c
@@ -18,18 +18,15 @@
  */
 
 #include <assert.h>
-#include <arch/cache.h>
 #include <arch/exception.h>
 #include <bootblock_common.h>
 #include <cbfs.h>
 #include <console/console.h>
 #include <soc/clock.h>
 #include <soc/nvidia/tegra/apbmisc.h>
-#include <soc/nvidia/tegra124/early_configs.h>
 #include <vendorcode/google/chromeos/chromeos.h>
 #include "pinmux.h"
 #include "power.h"
-#include "verstage.h"
 
 void main(void)
 {
@@ -73,11 +70,11 @@ void main(void)
 			  PINMUX_PWR_INT_N_FUNC_PMICINTR |
 			  PINMUX_INPUT_ENABLE);
 
-	if (IS_ENABLED(CONFIG_VBOOT2_VERIFY_FIRMWARE)) {
-		early_mainboard_init();
-		entry = (void *)verstage_vboot_main;
-	} else
-		entry = cbfs_load_stage(CBFS_DEFAULT_MEDIA, "fallback/romstage");
+	if (IS_ENABLED(CONFIG_VBOOT2_VERIFY_FIRMWARE))
+		entry = NULL;
+	else
+		entry = cbfs_load_stage(CBFS_DEFAULT_MEDIA,
+					CONFIG_CBFS_PREFIX "/romstage");
 
 	ASSERT(entry);
 	clock_cpu0_config(entry);
diff --git a/src/soc/nvidia/tegra124/verstage.c b/src/soc/nvidia/tegra124/verstage.c
index d85fc5c..60361a2 100644
--- a/src/soc/nvidia/tegra124/verstage.c
+++ b/src/soc/nvidia/tegra124/verstage.c
@@ -1,15 +1,55 @@
-#include "verstage.h"
+/*
+ * 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/cache.h>
+#include <arch/exception.h>
+#include <console/console.h>
+#include <soc/nvidia/tegra124/cache.h>
+#include <soc/nvidia/tegra124/early_configs.h>
 #include <vendorcode/google/chromeos/chromeos.h>
 
-/**
- * Stage entry point
- */
-void vboot_main(void)
+static void enable_cache(void)
+{
+	mmu_init();
+	/* Whole space is uncached. */
+	mmu_config_range(0, 4096, DCACHE_OFF);
+	/* SRAM is cached. Round the size up to 2MB, the LPAE page size. */
+	mmu_config_range(0x40000000 >> 20, 1, DCACHE_WRITEBACK);
+	mmu_disable_range(0, 1);
+	dcache_mmu_enable();
+}
+
+/* Do the minimum to run vboot at full speed */
+static void soc_init(void)
+{
+	configure_l2_cache();
+	console_init();
+	exception_init();
+	enable_cache();
+}
+
+void main(void)
 {
-	/* Stub to force arm_init_caches to the top, before any stack/memory
-	 * accesses */
 	asm volatile ("bl arm_init_caches"
-		      ::: "r0","r1","r2","r3","r4","r5","ip");
+		      : : : "r0", "r1", "r2", "r3", "r4", "r5", "ip");
 
-	select_firmware();
+	soc_init();
+	early_mainboard_init();
+	vboot2_verify_firmware();
 }
diff --git a/src/soc/nvidia/tegra124/verstage.h b/src/soc/nvidia/tegra124/verstage.h
deleted file mode 100644
index a0bac34..0000000
--- a/src/soc/nvidia/tegra124/verstage.h
+++ /dev/null
@@ -1,2 +0,0 @@
-void vboot_main(void);
-void verstage_vboot_main(void);
diff --git a/src/vendorcode/google/chromeos/Kconfig b/src/vendorcode/google/chromeos/Kconfig
index 69ecaf2..4e71c3b 100644
--- a/src/vendorcode/google/chromeos/Kconfig
+++ b/src/vendorcode/google/chromeos/Kconfig
@@ -98,17 +98,17 @@ config VBOOT_VERIFY_FIRMWARE
 	  and boot loader.
 
 config VBOOT2_VERIFY_FIRMWARE
-  bool "Firmware Verification with vboot2"
-  default n
-  depends on CHROMEOS
-  help
+	bool "Firmware Verification with vboot2"
+	default n
+	depends on CHROMEOS
+	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
-	depends on VBOOT_VERIFY_FIRMWARE
+	depends on VBOOT_VERIFY_FIRMWARE || VBOOT2_VERIFY_FIRMWARE
 	help
 	  EC software sync is a mechanism where the AP helps the EC verify its
 	  firmware similar to how vboot verifies the main system firmware. This
@@ -117,22 +117,45 @@ config EC_SOFTWARE_SYNC
 config VIRTUAL_DEV_SWITCH
 	bool "Virtual developer switch support"
 	default n
-	depends on VBOOT_VERIFY_FIRMWARE
+	depends on VBOOT_VERIFY_FIRMWARE || VBOOT2_VERIFY_FIRMWARE
 	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.
+# Unfortunately, there is no programmatical link between the blob list and the
+# index number here.
 config VBOOT_BOOT_LOADER_INDEX
 	hex "Bootloader component index"
 	default 0
-	depends on VBOOT_VERIFY_FIRMWARE
+	depends on VBOOT_VERIFY_FIRMWARE || VBOOT2_VERIFY_FIRMWARE
 	help
 	  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
-	depends on VBOOT_VERIFY_FIRMWARE
+	depends on VBOOT_VERIFY_FIRMWARE || VBOOT2_VERIFY_FIRMWARE
 	help
 	  This is the index of the ramstage component in the verified
 	  firmware block.
diff --git a/src/vendorcode/google/chromeos/Makefile.inc b/src/vendorcode/google/chromeos/Makefile.inc
index 701feb7..e9eef4a 100644
--- a/src/vendorcode/google/chromeos/Makefile.inc
+++ b/src/vendorcode/google/chromeos/Makefile.inc
@@ -71,7 +71,7 @@ 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../%,$(filter-out -include $(src)/include/kconfig.h, $(CFLAGS_romstage)))
+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)
 
@@ -89,7 +89,7 @@ $(VB_LIB):
 		CFLAGS="$(VBOOT_CFLAGS)" \
 		make -C $(VB_SOURCE) \
 		$(VBOOT_MAKEFLAGS) \
-		BUILD=../$(dir $(VB_LIB)) \
+		BUILD=$(top)/$(dir $(VB_LIB)) \
 		V=$(V) \
 		fwlib
 
@@ -97,10 +97,17 @@ endif
 
 ifeq ($(CONFIG_VBOOT2_VERIFY_FIRMWARE),y)
 VB_SOURCE := vboot_reference
-VERSTAGE_LIB = $(obj)/vendorcode/google/chromeos/verstage.a
-
 INCLUDES += -I$(VB_SOURCE)/firmware/2lib/include
 INCLUDES += -I$(VB_SOURCE)/firmware/include
+
+verstage-c-ccopts += -D__PRE_RAM__ -D__VER_STAGE__
+verstage-S-ccopts += -D__PRE_RAM__ -D__VER_STAGE__
+
+ifeq ($(CONFIG_RETURN_FROM_VERSTAGE),y)
+bootblock-y += verstub.c
+else
+verstage-y += verstub.c
+endif
 verstage-y += verstage.c fmap.c chromeos.c
 verstage-y += antirollback.c vbnv_ec.c
 romstage-y += vboot_handoff.c
@@ -121,13 +128,10 @@ $(VB2_LIB): $(obj)/config.h
 		BUILD=$(top)/$(dir $(VB2_LIB)) \
 		V=$(V) \
 		fwlib2
-	mv $@ $@.tmp
-	@printf "    OBJCOPY    $(subst $(obj)/,,$(@))\n"
-	$(OBJCOPY_verstage) --prefix-symbols=verstage_ $@.tmp $@
-
-$(VERSTAGE_LIB): $$(verstage-objs)
-	@printf "    AR         $(subst $(obj)/,,$(@))\n"
-	$(AR_verstage) rc $@.tmp $(verstage-objs)
-	@printf "    OBJCOPY    $(subst $(obj)/,,$(@))\n"
-	$(OBJCOPY_verstage) --prefix-symbols=verstage_ $@.tmp $@
-endif
+
+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/chromeos.c b/src/vendorcode/google/chromeos/chromeos.c
new file mode 100644
index 0000000..d2f62d7
--- /dev/null
+++ b/src/vendorcode/google/chromeos/chromeos.c
@@ -0,0 +1,284 @@
+/*
+ * This file is part of the coreboot project.
+ *
+ * Copyright (C) 2011 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 <stddef.h>
+#include <string.h>
+#include "chromeos.h"
+#if CONFIG_VBOOT_VERIFY_FIRMWARE || CONFIG_VBOOT2_VERIFY_FIRMWARE
+#include "fmap.h"
+#include "vboot_handoff.h"
+#include <reset.h>
+#endif
+#include <boot/coreboot_tables.h>
+#include <cbfs.h>
+#include <cbmem.h>
+#include <console/console.h>
+
+#if CONFIG_VBOOT_VERIFY_FIRMWARE
+static int vboot_enable_developer(void)
+{
+	struct vboot_handoff *vbho;
+
+	vbho = cbmem_find(CBMEM_ID_VBOOT_HANDOFF);
+
+	if (vbho == NULL) {
+		printk(BIOS_ERR, "%s: Couldn't find vboot_handoff structure!\n",
+		        __func__);
+		return 0;
+	}
+
+	return !!(vbho->init_params.out_flags & VB_INIT_OUT_ENABLE_DEVELOPER);
+}
+
+static int vboot_enable_recovery(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_RECOVERY);
+}
+#else
+static inline int vboot_enable_developer(void) { return 0; }
+static inline int vboot_enable_recovery(void) { return 0; }
+#endif
+
+int developer_mode_enabled(void)
+{
+	return get_developer_mode_switch() || vboot_enable_developer();
+}
+
+int recovery_mode_enabled(void)
+{
+	/*
+	 * This is called in multiple places and has to detect
+	 * recovery mode triggered from the EC and via shared
+	 * recovery reason set with crossystem.
+	 *
+	 * If shared recovery reason is set:
+	 * - before VbInit then get_recovery_mode_from_vbnv() is true
+	 * - after VbInit then vboot_enable_recovery() is true
+	 *
+	 * Otherwise the mainboard handler for get_recovery_mode_switch()
+	 * will detect recovery mode initiated by the EC.
+	 */
+	return get_recovery_mode_switch() || get_recovery_mode_from_vbnv() ||
+		vboot_enable_recovery();
+}
+
+int __attribute__((weak)) clear_recovery_mode_switch(void)
+{
+	// Can be implemented by a mainboard
+	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 __PRE_RAM__
+void __attribute__((weak)) save_chromeos_gpios(void)
+{
+	// Can be implemented by a mainboard
+}
+
+int __attribute((weak)) vboot_get_sw_write_protect(void)
+{
+	// Can be implemented by a platform / mainboard
+	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 **)&region->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(*region);
+	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_stage *stage;
+	uint32_t fc_addr;
+	uint32_t fc_size;
+
+	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;
+	}
+
+	/* Loading to cbfs cache. This stage data must be retained until it's
+	 * decompressed. */
+	stage = vboot_get_region(fc_addr, fc_size, NULL);
+
+	if (stage == NULL) {
+		printk(BIOS_INFO, "failed to load a stage\n");
+		return NULL;
+	}
+
+	/* Stages rely the below clearing so that the bss is initialized. */
+	memset((void *) (uintptr_t)stage->load, 0, stage->memlen);
+
+	if (cbfs_decompress(stage->compression,
+			    (unsigned char *)stage + sizeof(*stage),
+			    (void *) (uintptr_t) stage->load,
+			    stage->len)) {
+		printk(BIOS_INFO, "failed to decompress a stage\n");
+		return NULL;
+	}
+
+	return (void *)(uintptr_t)stage->entry;
+}
+
+struct vb2_working_data * const vboot_get_working_data(void)
+{
+	return (struct vb2_working_data *)CONFIG_VBOOT_WORK_BUFFER_ADDRESS;
+}
+
+int vboot_is_slot_selected(struct vb2_working_data *wd)
+{
+	return wd->selected_region.size > 0;
+}
+
+int vboot_is_readonly_path(struct vb2_working_data *wd)
+{
+	return wd->selected_region.size == 0;
+}
+
+void vboot_reboot(void)
+{
+	hard_reset();
+}
+#endif
diff --git a/src/vendorcode/google/chromeos/chromeos.h b/src/vendorcode/google/chromeos/chromeos.h
index 724ff57..14e0b10 100644
--- a/src/vendorcode/google/chromeos/chromeos.h
+++ b/src/vendorcode/google/chromeos/chromeos.h
@@ -47,6 +47,38 @@ 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
@@ -87,8 +119,31 @@ static inline void chromeos_reserve_ram_oops(struct device *dev, int idx) {}
 #endif /* CONFIG_CHROMEOS_RAMOOPS */
 
 #if CONFIG_VBOOT2_VERIFY_FIRMWARE
-void select_firmware(void);
-void vboot_create_handoff(void * vboot_workbuf);
-#endif
+void *vboot_load_ramstage(void);
+void vboot2_verify_firmware(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.
+ *
+ * TODO: Make the sizes of the struct and its members independent of cpu
+ * architectures as it crosses stage boundaries.
+ */
+struct vb2_working_data {
+	struct vboot_region selected_region;
+	size_t buffer_size;
+	uint8_t *buffer;
+};
+
+struct vb2_working_data * const vboot_get_working_data(void);
+int vboot_is_slot_selected(struct vb2_working_data *wd);
+int vboot_is_readonly_path(struct vb2_working_data *wd);
+#endif /* CONFIG_VBOOT2_VERIFY_FIRMWARE */
 
 #endif
diff --git a/src/vendorcode/google/chromeos/vboot_context.h b/src/vendorcode/google/chromeos/vboot_context.h
index cd82aac..2517f63 100644
--- a/src/vendorcode/google/chromeos/vboot_context.h
+++ b/src/vendorcode/google/chromeos/vboot_context.h
@@ -21,21 +21,12 @@
 
 #include <stdint.h>
 #include <vboot_api.h>
+#include "chromeos.h"
 
 struct cbmem_entry;
 
 /* The vboot context structure provides all the necessary data for invoking
  * vboot. The vboot loader sets everything up for vboot module to use. */
-
-struct vboot_region {
-	/*
-	 * The offset_addr field may be an offset or an address. It depends
-	 * on the capabilities of the underlying architecture.
-	 */
-	uintptr_t offset_addr;
-	int32_t size;
-};
-
 struct vboot_context {
 	struct vboot_handoff *handoff;
 	VbCommonParams *cparams;
diff --git a/src/vendorcode/google/chromeos/vboot_handoff.c b/src/vendorcode/google/chromeos/vboot_handoff.c
index 3b276aa..ae3096a 100644
--- a/src/vendorcode/google/chromeos/vboot_handoff.c
+++ b/src/vendorcode/google/chromeos/vboot_handoff.c
@@ -19,6 +19,8 @@
 
 #include <2recovery_reasons.h>
 #include <2struct.h>
+#include <arch/stages.h>
+#include <assert.h>
 #include <stdint.h>
 #include <stddef.h>
 #include <string.h>
@@ -33,13 +35,33 @@
 #include "vboot_handoff.h"
 #include <vboot_struct.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)
+			       struct vb2_shared_data *vb2_sd)
 {
 	VbSharedDataHeader *vb_sd =
 		(VbSharedDataHeader *)vboot_handoff->shared_data;
@@ -49,7 +71,6 @@ static void fill_vboot_handoff(struct vboot_handoff *vboot_handoff,
 
 	vboot_handoff->selected_firmware = vb2_sd->fw_slot;
 
-	/* TODO: fw_slot is never 0xff while firmware_index can. */
 	vb_sd->firmware_index = vb2_sd->fw_slot;
 
 	vb_sd->magic = VB_SHARED_DATA_MAGIC;
@@ -61,7 +82,7 @@ static void fill_vboot_handoff(struct vboot_handoff *vboot_handoff,
 	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;
+			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;
@@ -75,6 +96,7 @@ static void fill_vboot_handoff(struct vboot_handoff *vboot_handoff,
 		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) {
@@ -92,51 +114,58 @@ static void fill_vboot_handoff(struct vboot_handoff *vboot_handoff,
 	if (vb2_sd->workbuf_preamble_size) {
 		struct vb2_fw_preamble *fp;
 		uintptr_t dst, src;
-		printk(BIOS_ERR, "Copying FW preamble\n");
+		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;
+		src = (uintptr_t)&fp->kernel_subkey +
+				fp->kernel_subkey.key_offset;
 		dst = (uintptr_t)vb_sd + sizeof(VbSharedDataHeader);
-		memcpy((void *)dst, (void *)src, fp->kernel_subkey.key_size);
-                vb_sd->data_used += fp->kernel_subkey.key_size;
+		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->kernel_subkey.key_version =
+				fp->kernel_subkey.key_version;
 	}
 
 	vb_sd->recovery_reason = vb2_sd->recovery_reason;
 }
 
 /**
- * Create vboot handoff struct
- *
- *      struct vboot_handoff {
- *              VbInitParams init_params;
- *              uint32_t selected_firmware;
- *              struct firmware_component components[MAX_PARSED_FW_COMPONENTS];
- *              char shared_data[VB_SHARED_DATA_MIN_SIZE];
- *      } __attribute__((packed));
+ * Load ramstage and return the entry point
  */
-void vboot_create_handoff(void *vboot_workbuf)
+void *vboot_load_ramstage(void)
 {
 	struct vboot_handoff *vh;
 	struct vb2_shared_data *sd;
+	struct vb2_working_data *wd = vboot_get_working_data();
 
-	sd = (struct vb2_shared_data *)vboot_workbuf;
+	sd = (struct vb2_shared_data *)wd->buffer;
 	sd->workbuf_hash_offset = 0;
 	sd->workbuf_hash_size = 0;
 
-	printk(BIOS_INFO, "Creating vboot_handoff structure\n");
+	printk(BIOS_INFO, "creating vboot_handoff structure\n");
 	vh = cbmem_add(CBMEM_ID_VBOOT_HANDOFF, sizeof(*vh));
-
-	if (vh == NULL) {
-		printk(BIOS_ERR, "Could not add vboot_handoff structure\n");
-		return;
-	}
+	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');
+	return load_ramstage(vh, &wd->selected_region);
 }
diff --git a/src/vendorcode/google/chromeos/vboot_handoff.h b/src/vendorcode/google/chromeos/vboot_handoff.h
index e1e519f..b001743 100644
--- a/src/vendorcode/google/chromeos/vboot_handoff.h
+++ b/src/vendorcode/google/chromeos/vboot_handoff.h
@@ -21,16 +21,7 @@
 
 #include <vboot_api.h>
 #include <vboot_struct.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
+#include "chromeos.h"
 
 struct firmware_component {
 	uint32_t address;
diff --git a/src/vendorcode/google/chromeos/vboot_loader.c b/src/vendorcode/google/chromeos/vboot_loader.c
index 0294ac6..2a1ee3e 100644
--- a/src/vendorcode/google/chromeos/vboot_loader.c
+++ b/src/vendorcode/google/chromeos/vboot_loader.c
@@ -34,26 +34,9 @@
 #include <stdlib.h>
 #include <timestamp.h>
 #include "chromeos.h"
-#include "fmap.h"
 #include "vboot_context.h"
 #include "vboot_handoff.h"
 
-/* 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 component_entry {
-	uint32_t offset;
-	uint32_t size;
-} __attribute__((packed));
-
-struct components {
-	uint32_t num_components;
-	struct component_entry entries[0];
-} __attribute__((packed));
-
-
 #define TEMP_CBMEM_ID_VBOOT	0xffffffff
 #define TEMP_CBMEM_ID_VBLOCKS	0xfffffffe
 
@@ -93,24 +76,13 @@ static void fatal_error(void)
 	hard_reset();
 }
 
-static void locate_region(const char *name, struct vboot_region *region)
-{
-	region->size = find_fmap_entry(name, (void **)&region->offset_addr);
-}
-
 static int fw_region_size(struct vboot_region *r)
 {
-	struct components *fw_info;
+	struct vboot_components *fw_info;
 	int32_t size;
-	size_t req_size;
 	int i;
 
-	req_size = sizeof(*fw_info);
-	req_size += sizeof(struct component_entry) * MAX_PARSED_FW_COMPONENTS;
-
-	/* This will leak a mapping. */
-	fw_info = vboot_get_region(r->offset_addr, req_size, NULL);
-
+	fw_info = vboot_locate_components(r);
 	if (fw_info == NULL)
 		return -1;
 
@@ -118,7 +90,7 @@ static int fw_region_size(struct vboot_region *r)
 		return -1;
 
 	size = sizeof(*fw_info);
-	size += sizeof(struct component_entry) * fw_info->num_components;
+	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));
@@ -190,9 +162,8 @@ static int vboot_fill_params(struct vboot_context *ctx)
 
 static void fill_handoff(struct vboot_context *context)
 {
-	struct components *fw_info;
+	struct vboot_components *fw_info;
 	struct vboot_region *region;
-	size_t req_size;
 	int i;
 
 	/* Fix up the handoff structure. */
@@ -207,12 +178,7 @@ static void fill_handoff(struct vboot_context *context)
 	else
 		return;
 
-	req_size = sizeof(*fw_info);
-	req_size += sizeof(struct component_entry) * MAX_PARSED_FW_COMPONENTS;
-
-	/* This will leak a mapping. */
-	fw_info = vboot_get_region(region->offset_addr, req_size, NULL);
-
+	fw_info = vboot_locate_components(region);
 	if (fw_info == NULL)
 		return;
 
@@ -273,11 +239,11 @@ static void vboot_invoke_wrapper(struct vboot_handoff *vboot_handoff)
 	cparams.shared_data_size = VB_SHARED_DATA_MIN_SIZE;
 	cparams.caller_context = &context;
 
-	locate_region("GBB", &context.gbb);
-	locate_region("VBLOCK_A", &context.vblock_a);
-	locate_region("VBLOCK_B", &context.vblock_b);
-	locate_region("FW_MAIN_A", &context.fw_a);
-	locate_region("FW_MAIN_B", &context.fw_b);
+	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 ||
diff --git a/src/vendorcode/google/chromeos/verstage.c b/src/vendorcode/google/chromeos/verstage.c
index 1564d80..4970124 100644
--- a/src/vendorcode/google/chromeos/verstage.c
+++ b/src/vendorcode/google/chromeos/verstage.c
@@ -1,58 +1,38 @@
+/*
+ * 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 <arch/exception.h>
-#include <arch/stages.h>
-#include <soc/nvidia/tegra124/cache.h>
-#include <cbfs.h>
 #include <console/console.h>
 #include <console/vtxprintf.h>
-#include <reset.h>
-#include <soc/addressmap.h>
-#include <soc/clock.h>
 #include <string.h>
 
 #include "chromeos.h"
-#include "fmap.h"
-
-#define VBDEBUG(format, args...) \
-	printk(BIOS_INFO, "%s():%d: " format,  __func__, __LINE__, ## args)
-#define TODO_BLOCK_SIZE 8192
-#define MAX_PARSED_FW_COMPONENTS 5
-#define ROMSTAGE_INDEX 2
-
-struct component_entry {
-	uint32_t offset;
-	uint32_t size;
-} __attribute__((packed));
-
-struct components {
-	uint32_t num_components;
-	struct component_entry entries[MAX_PARSED_FW_COMPONENTS];
-} __attribute__((packed));
-
-struct vboot_region {
-	uintptr_t offset_addr;
-	int32_t size;
-};
-
-static void locate_region(const char *name, struct vboot_region *region)
-{
-	region->size = find_fmap_entry(name, (void **)&region->offset_addr);
-	VBDEBUG("Located %s @%x\n", name, region->offset_addr);
-}
+
+#define TODO_BLOCK_SIZE 1024
 
 static int is_slot_a(struct vb2_context *ctx)
 {
 	return !(ctx->flags & VB2_CONTEXT_FW_SLOT_B);
 }
 
-static int in_ro(void)
-{
-	/* TODO: Implement */
-	return 1;
-}
-
 /* exports */
 
 void vb2ex_printf(const char *func, const char *fmt, ...)
@@ -61,7 +41,7 @@ void vb2ex_printf(const char *func, const char *fmt, ...)
 
 	printk(BIOS_INFO, "VB2:%s() ", func);
 	va_start(args, fmt);
-	printk(BIOS_INFO, fmt, args);
+	vprintk(BIOS_INFO, fmt, args);
 	va_end(args);
 
 	return;
@@ -70,7 +50,7 @@ void vb2ex_printf(const char *func, const char *fmt, ...)
 int vb2ex_tpm_clear_owner(struct vb2_context *ctx)
 {
 	uint32_t rv;
-	VBDEBUG("Clearing TPM owner\n");
+	printk(BIOS_INFO, "Clearing TPM owner\n");
 	rv = tpm_clear_and_reenable();
 	if (rv)
 		return VB2_ERROR_EX_TPM_CLEAR_OWNER;
@@ -87,13 +67,13 @@ int vb2ex_read_resource(struct vb2_context *ctx,
 
 	switch (index) {
 	case VB2_RES_GBB:
-		locate_region("GBB", &region);
+		vboot_locate_region("GBB", &region);
 		break;
 	case VB2_RES_FW_VBLOCK:
 		if (is_slot_a(ctx))
-			locate_region("VBLOCK_A", &region);
+			vboot_locate_region("VBLOCK_A", &region);
 		else
-			locate_region("VBLOCK_B", &region);
+			vboot_locate_region("VBLOCK_B", &region);
 		break;
 	default:
 		return VB2_ERROR_EX_READ_RESOURCE_INDEX;
@@ -108,29 +88,10 @@ int vb2ex_read_resource(struct vb2_context *ctx,
 	return VB2_SUCCESS;
 }
 
-static void reboot(void)
-{
-	cpu_reset();
-}
-
-static void recovery(void)
-{
-	void *entry;
-
-	if (!in_ro())
-		reboot();
-
-	entry = cbfs_load_stage(CBFS_DEFAULT_MEDIA, "fallback/romstage");
-	if (entry != (void *)-1)
-		stage_exit(entry);
-
-	for (;;);
-}
-
 static int hash_body(struct vb2_context *ctx, struct vboot_region *fw_main)
 {
 	uint32_t expected_size;
-	uint8_t block[TODO_BLOCK_SIZE];
+	MAYBE_STATIC uint8_t block[TODO_BLOCK_SIZE];
 	size_t block_size = sizeof(block);
 	uintptr_t offset;
 	int rv;
@@ -168,122 +129,57 @@ static int hash_body(struct vb2_context *ctx, struct vboot_region *fw_main)
 	return VB2_SUCCESS;
 }
 
-static int locate_fw_components(struct vb2_context *ctx,
-				struct vboot_region *fw_main,
-				struct components *fw_info)
+static int locate_firmware(struct vb2_context *ctx,
+			   struct vboot_region *fw_main)
 {
 	if (is_slot_a(ctx))
-		locate_region("FW_MAIN_A", fw_main);
+		vboot_locate_region("FW_MAIN_A", fw_main);
 	else
-		locate_region("FW_MAIN_B", fw_main);
+		vboot_locate_region("FW_MAIN_B", fw_main);
+
 	if (fw_main->size < 0)
 		return 1;
 
-	if (vboot_get_region(fw_main->offset_addr,
-			     sizeof(*fw_info), fw_info) == NULL)
-		return 1;
 	return 0;
 }
 
-static struct cbfs_stage *load_stage(struct vb2_context *ctx,
-				     int stage_index,
-				     struct vboot_region *fw_main,
-				     struct components *fw_info)
-{
-	struct cbfs_stage *stage;
-	uint32_t fc_addr;
-	uint32_t fc_size;
-
-	/* Check for invalid address. */
-	fc_addr = fw_main->offset_addr + fw_info->entries[stage_index].offset;
-	fc_size = fw_info->entries[stage_index].size;
-	if (fc_addr == 0 || fc_size == 0) {
-		VBDEBUG("romstage address invalid.\n");
-		return NULL;
-	}
-
-	/* Loading to cbfs cache. This stage data must be retained until it's
-	 * decompressed. */
-	stage = vboot_get_region(fc_addr, fc_size, NULL);
-
-	if (stage == NULL) {
-		VBDEBUG("Unable to load a stage.\n");
-		return NULL;
-	}
-
-	return stage;
-}
-
-static void enter_stage(struct cbfs_stage *stage)
-{
-	/* Stages rely the below clearing so that the bss is initialized. */
-	memset((void *) (uintptr_t)stage->load, 0, stage->memlen);
-
-	if (cbfs_decompress(stage->compression,
-			    (unsigned char *)stage + sizeof(*stage),
-			    (void *) (uintptr_t) stage->load,
-			    stage->len))
-		return;
-
-	VBDEBUG("Jumping to entry @%llx.\n", stage->entry);
-	stage_exit((void *)(uintptr_t)stage->entry);
-}
-
-static void enable_cache(void)
-{
-	mmu_init();
-	mmu_config_range(0, CONFIG_SYS_SDRAM_BASE >> 20, DCACHE_OFF);
-	mmu_config_range(0x40000000 >> 20, 2, DCACHE_WRITEBACK);
-	mmu_disable_range(0, 1);
-	VBDEBUG("Enabling cache\n");
-	dcache_mmu_enable();
-}
-
 /**
  * Save non-volatile and/or secure data if needed.
  */
 static void save_if_needed(struct vb2_context *ctx)
 {
 	if (ctx->flags & VB2_CONTEXT_NVDATA_CHANGED) {
-		VBDEBUG("Saving nvdata\n");
+		printk(BIOS_INFO, "Saving nvdata\n");
 		save_vbnv(ctx->nvdata);
 		ctx->flags &= ~VB2_CONTEXT_NVDATA_CHANGED;
 	}
 	if (ctx->flags & VB2_CONTEXT_SECDATA_CHANGED) {
-		VBDEBUG("Saving secdata\n");
+		printk(BIOS_INFO, "Saving secdata\n");
 		antirollback_write_space_firmware(ctx);
 		ctx->flags &= ~VB2_CONTEXT_SECDATA_CHANGED;
 	}
 }
 
 /**
- * Load and verify the next stage from RW image and jump to it
- *
- * If validation fails, it exits to romstage for recovery or reboots.
+ * 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.
  */
-void __attribute__((noinline)) select_firmware(void)
+#if CONFIG_RETURN_FROM_VERSTAGE
+void main(void)
+#else
+void verstage_main(void)
+#endif /* CONFIG_RETURN_FROM_VERSTAGE */
 {
 	struct vb2_context ctx;
-	uint8_t *workbuf = (uint8_t *)CONFIG_VBOOT_WORK_BUFFER_ADDRESS;
-	struct vboot_region fw_main;
-	struct components fw_info;
-	struct cbfs_stage *stage;
+	struct vb2_working_data *wd = vboot_get_working_data();
 	int rv;
 
-	/* Do minimum to enable cache and run vboot at full speed */
-	configure_l2_cache();
-	console_init();
-	exception_init();
-	enable_cache();
-
-	/* Set up context */
+	/* Set up context and work buffer */
 	memset(&ctx, 0, sizeof(ctx));
-	ctx.workbuf = workbuf;
-	ctx.workbuf_size = CONFIG_VBOOT_WORK_BUFFER_SIZE;
-	memset(ctx.workbuf, 0, ctx.workbuf_size);
+	ctx.workbuf = wd->buffer;
+	ctx.workbuf_size = wd->buffer_size;
 
 	/* Read nvdata from a non-volatile storage */
 	read_vbnv(ctx.nvdata);
@@ -301,59 +197,53 @@ void __attribute__((noinline)) select_firmware(void)
 	}
 
 	/* Do early init */
-	VBDEBUG("Phase 1\n");
+	printk(BIOS_INFO, "Phase 1\n");
 	rv = vb2api_fw_phase1(&ctx);
 	if (rv) {
-		VBDEBUG("Recovery requested (%x)\n", rv);
+		printk(BIOS_INFO, "Recovery requested (%x)\n", rv);
 		/* If we need recovery mode, leave firmware selection now */
 		save_if_needed(&ctx);
-		recovery();
+		return;
 	}
 
 	/* Determine which firmware slot to boot */
-	VBDEBUG("Phase 2\n");
+	printk(BIOS_INFO, "Phase 2\n");
 	rv = vb2api_fw_phase2(&ctx);
 	if (rv) {
-		VBDEBUG("Reboot requested (%x)\n", rv);
+		printk(BIOS_INFO, "Reboot requested (%x)\n", rv);
 		save_if_needed(&ctx);
-		reboot();
+		vboot_reboot();
 	}
 
 	/* Try that slot */
-	VBDEBUG("Phase 3\n");
+	printk(BIOS_INFO, "Phase 3\n");
 	rv = vb2api_fw_phase3(&ctx);
 	if (rv) {
-		VBDEBUG("Reboot requested (%x)\n", rv);
+		printk(BIOS_INFO, "Reboot requested (%x)\n", rv);
 		save_if_needed(&ctx);
-		reboot();
+		vboot_reboot();
 	}
 
-	VBDEBUG("Phase 4\n");
-	rv = locate_fw_components(&ctx, &fw_main, &fw_info);
-	if (rv) {
-		VBDEBUG("Failed to locate firmware components\n");
-		reboot();
-	}
-	rv = hash_body(&ctx, &fw_main);
-	stage = load_stage(&ctx, ROMSTAGE_INDEX, &fw_main, &fw_info);
-	if (stage == NULL) {
-		VBDEBUG("Failed to load stage\n");
-		reboot();
-	}
+	printk(BIOS_INFO, "Phase 4\n");
+	rv = locate_firmware(&ctx, &wd->selected_region);
+	if (rv)
+		die("Failed to read FMAP to locate firmware");
+
+	rv = hash_body(&ctx, &wd->selected_region);
 	save_if_needed(&ctx);
 	if (rv) {
-		VBDEBUG("Reboot requested (%x)\n", rv);
-		reboot();
+		printk(BIOS_INFO, "Reboot requested (%x)\n", rv);
+		vboot_reboot();
 	}
 
-	/* TODO: Do we need to lock secdata? */
-	VBDEBUG("Locking TPM\n");
-
-	/* Load next stage and jump to it */
-	VBDEBUG("Jumping to rw-romstage @%llx\n", stage->entry);
-	enter_stage(stage);
+	/* 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();
+	}
 
-	/* Shouldn't reach here */
-	VBDEBUG("Halting\n");
-	for (;;);
+	printk(BIOS_INFO, "Slot %c is selected\n", is_slot_a(&ctx) ? 'A' : 'B');
 }
diff --git a/src/vendorcode/google/chromeos/verstub.c b/src/vendorcode/google/chromeos/verstub.c
new file mode 100644
index 0000000..5df1777
--- /dev/null
+++ b/src/vendorcode/google/chromeos/verstub.c
@@ -0,0 +1,93 @@
+/*
+ * 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"
+
+static struct vb2_working_data *init_vb2_working_data(void)
+{
+	struct vb2_working_data *wd;
+
+	wd = vboot_get_working_data();
+	memset(wd, 0, CONFIG_VBOOT_WORK_BUFFER_SIZE);
+	/* 8-byte alignment for ARMv7 */
+	wd->buffer = (uint8_t *)ALIGN_UP((uintptr_t)&wd[1], 8);
+	wd->buffer_size = CONFIG_VBOOT_WORK_BUFFER_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 == -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_components *fw_info =
+				vboot_locate_components(&wd->selected_region);
+		if (fw_info == NULL)
+			die("failed to locate firmware components\n");
+		entry = vboot_load_stage(CONFIG_VBOOT_ROMSTAGE_INDEX,
+					 &wd->selected_region, 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");
+}



More information about the coreboot-gerrit mailing list