aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--src/arch/x86/Makefile.inc5
-rw-r--r--src/lib/cbfs.c15
-rw-r--r--src/southbridge/intel/lynxpoint/spi_loading.c15
-rw-r--r--src/vendorcode/google/chromeos/Kconfig40
-rw-r--r--src/vendorcode/google/chromeos/Makefile.inc44
-rw-r--r--src/vendorcode/google/chromeos/chromeos.c32
-rw-r--r--src/vendorcode/google/chromeos/chromeos.h12
-rw-r--r--src/vendorcode/google/chromeos/gnvs.c18
-rw-r--r--src/vendorcode/google/chromeos/vbnv.c26
-rw-r--r--src/vendorcode/google/chromeos/vboot_context.h48
-rw-r--r--src/vendorcode/google/chromeos/vboot_handoff.h53
-rw-r--r--src/vendorcode/google/chromeos/vboot_loader.c280
-rw-r--r--src/vendorcode/google/chromeos/vboot_wrapper.c268
13 files changed, 847 insertions, 9 deletions
diff --git a/src/arch/x86/Makefile.inc b/src/arch/x86/Makefile.inc
index 7cda5b6d8b..377a86388e 100644
--- a/src/arch/x86/Makefile.inc
+++ b/src/arch/x86/Makefile.inc
@@ -76,7 +76,7 @@ $(obj)/coreboot.pre1: $(CBFSTOOL)
mv $(obj)/coreboot.rom $@
endif
-$(obj)/coreboot.rom: $(obj)/coreboot.pre $(objcbfs)/coreboot_ram.elf $(CBFSTOOL) $(call strip_quotes,$(COREBOOT_ROM_DEPENDENCIES)) $$(INTERMEDIATE)
+$(obj)/coreboot.rom: $(obj)/coreboot.pre $(objcbfs)/coreboot_ram.elf $(CBFSTOOL) $(call strip_quotes,$(COREBOOT_ROM_DEPENDENCIES)) $$(INTERMEDIATE) $$(VBOOT_STUB_ELF)
@printf " CBFS $(subst $(obj)/,,$(@))\n"
cp $(obj)/coreboot.pre $@.tmp
if [ -f $(objcbfs)/coreboot_ap.elf ]; \
@@ -110,6 +110,9 @@ ifeq ($(CONFIG_INCLUDE_CONFIG_FILE),y)
sed -e '/^#/d' -e '/^ *$$/d' $(DOTCONFIG) >> $(obj)/config.tmp ; \
$(CBFSTOOL) $@.tmp add -f $(obj)/config.tmp -n config -t raw; rm -f $(obj)/config.tmp ; fi
endif
+ifeq ($(CONFIG_VBOOT_VERIFY_FIRMWARE),y)
+ $(CBFSTOOL) $@.tmp add-stage -f $(VBOOT_STUB_ELF) -n $(CONFIG_CBFS_PREFIX)/vboot -c $(CBFS_COMPRESS_FLAG)
+endif
mv $@.tmp $@
@printf " CBFSPRINT $(subst $(obj)/,,$(@))\n\n"
$(CBFSTOOL) $@ print
diff --git a/src/lib/cbfs.c b/src/lib/cbfs.c
index 45ae7c7683..39e6c11000 100644
--- a/src/lib/cbfs.c
+++ b/src/lib/cbfs.c
@@ -63,6 +63,12 @@
#include "cbfs_core.c"
+#if CONFIG_VBOOT_VERIFY_FIRMWARE
+#include <vendorcode/google/chromeos/chromeos.h>
+#else
+static inline void *vboot_get_payload(int *len) { return NULL; }
+#endif
+
#ifndef __SMM__
static inline int tohex4(unsigned int c)
{
@@ -302,8 +308,15 @@ int cbfs_execute_stage(struct cbfs_media *media, const char *name)
#if !CONFIG_ALT_CBFS_LOAD_PAYLOAD
void *cbfs_load_payload(struct cbfs_media *media, const char *name)
{
- return (struct cbfs_payload *)cbfs_get_file_content(
+ struct cbfs_payload *payload;
+
+ payload = vboot_get_payload(NULL);
+ if (payload != NULL)
+ return payload;
+
+ payload = (struct cbfs_payload *)cbfs_get_file_content(
media, name, CBFS_TYPE_PAYLOAD);
+ return payload;
}
#endif
diff --git a/src/southbridge/intel/lynxpoint/spi_loading.c b/src/southbridge/intel/lynxpoint/spi_loading.c
index eb3082bb5a..1ae7a263eb 100644
--- a/src/southbridge/intel/lynxpoint/spi_loading.c
+++ b/src/southbridge/intel/lynxpoint/spi_loading.c
@@ -21,9 +21,15 @@
#include <stdlib.h>
#include <string.h>
#include <arch/byteorder.h>
+#include <cbmem.h>
#include <cbfs.h>
#include <console/console.h>
#include <cpu/x86/smm.h>
+#if CONFIG_VBOOT_VERIFY_FIRMWARE
+#include <vendorcode/google/chromeos/chromeos.h>
+#else
+static inline void *vboot_get_payload(int *len) { return NULL; }
+#endif
#define CACHELINE_SIZE 64
#define INTRA_CACHELINE_MASK (CACHELINE_SIZE - 1)
@@ -69,7 +75,14 @@ void *cbfs_load_payload(struct cbfs_media *media, const char *name)
{
int file_len;
void *file_start;
- struct cbfs_file *file = cbfs_get_file(media, name);
+ struct cbfs_file *file;
+
+ file_start = vboot_get_payload(&file_len);
+
+ if (file_start != NULL)
+ return spi_mirror(file_start, file_len);
+
+ file = cbfs_get_file(media, name);
if (file == NULL)
return NULL;
diff --git a/src/vendorcode/google/chromeos/Kconfig b/src/vendorcode/google/chromeos/Kconfig
index 31094de956..06ed7d3255 100644
--- a/src/vendorcode/google/chromeos/Kconfig
+++ b/src/vendorcode/google/chromeos/Kconfig
@@ -67,6 +67,46 @@ config FLASHMAP_OFFSET
endmenu
+config VBOOT_VERIFY_FIRMWARE
+ bool "Verify firmware with vboot."
+ default n
+ depends on CHROMEOS
+ help
+ Enabling VBOOT_VERIFY_FIRMWARE will use vboot to verify the ramstage
+ and boot loader.
+
+config EC_SOFTWARE_SYNC
+ bool "Enable EC software sync"
+ default n
+ depends on VBOOT_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
+ option selects whether depthcharge should support EC software sync.
+
+config VIRTUAL_DEV_SWITCH
+ bool "Virtual developer switch support"
+ default n
+ depends on VBOOT_VERIFY_FIRMWARE
+ help
+ Whether this platform has a virtual developer switch.
+
+config VBOOT_BOOT_LOADER_INDEX
+ hex "Bootloader component index"
+ default 0
+ depends on VBOOT_VERIFY_FIRMWARE
+ help
+ This is the index of the bootloader component in the verified
+ firmware block.
+
+config VBOOT_RAMSTAGE_INDEX
+ hex "Ramstage component index"
+ default 1
+ depends on VBOOT_VERIFY_FIRMWARE
+ help
+ This is the index of the ramstage component in the verified
+ firmware block.
+
config NO_TPM_RESUME
bool
default n
diff --git a/src/vendorcode/google/chromeos/Makefile.inc b/src/vendorcode/google/chromeos/Makefile.inc
index 8ae14fdb0b..9bc4d64163 100644
--- a/src/vendorcode/google/chromeos/Makefile.inc
+++ b/src/vendorcode/google/chromeos/Makefile.inc
@@ -30,3 +30,47 @@ ifneq ($(wildcard src/mainboard/$(MAINBOARDDIR)/chromeos.c),)
ramstage-srcs += src/mainboard/$(MAINBOARDDIR)/chromeos.c
romstage-srcs += src/mainboard/$(MAINBOARDDIR)/chromeos.c
endif
+
+ifeq ($(CONFIG_VBOOT_VERIFY_FIRMWARE),y)
+romstage-y += vboot_loader.c
+rmodules-y += vboot_wrapper.c
+
+VB_LIB = $(obj)/external/vboot_reference/vboot_fw.a
+VB_FIRMWARE_ARCH := $(ARCHDIR-y)
+VB_SOURCE := vboot_reference
+
+# Add the vboot include paths.
+VB_INCLUDES += -I$(VB_SOURCE)/firmware/include
+VB_INCLUDES += -I$(VB_SOURCE)/firmware/arch/$(VB_FIRMWARE_ARCH)/include
+INCLUDES += $(VB_INCLUDES)
+
+VBOOT_STUB_ELF = $(obj)/vendorcode/google/chromeos/vbootstub.elf
+VBOOT_STUB_DOTO = $(VBOOT_STUB_ELF:.elf=.o)
+
+# Dependency for the vboot rmodules. Ordering matters.
+VBOOT_STUB_DEPS += $(obj)/vendorcode/google/chromeos/vboot_wrapper.rmodules.o
+VBOOT_STUB_DEPS += $(obj)/lib/memcmp.rmodules.o
+VBOOT_STUB_DEPS += $(obj)/arch/x86/lib/memset.rmodules.o
+VBOOT_STUB_DEPS += $(obj)/arch/x86/lib/memcpy.rmodules.o
+VBOOT_STUB_DEPS += $(VB_LIB)
+# Remove the '-include' option since that will break vboot's build.
+VBOOT_CFLAGS += $(filter-out -include $(src)/include/kconfig.h, $(CFLAGS))
+VBOOT_CFLAGS += -DVBOOT_DEBUG
+
+$(VBOOT_STUB_DOTO): $(VBOOT_STUB_DEPS)
+ $(CC) $(LDFLAGS) -nostdlib -r -o $@ $^
+
+# Link the vbootstub module with a 64KiB-byte heap.
+$(eval $(call rmodule_link,$(VBOOT_STUB_ELF), $(VBOOT_STUB_DOTO), 0x10000))
+
+# Build vboot library without the default includes from coreboot proper.
+$(VB_LIB):
+ @printf " MAKE $(subst $(obj)/,,$(@))\n"
+ $(Q)FIRMWARE_ARCH=$(VB_FIRMWARE_ARCH) \
+ CFLAGS="$(VBOOT_CFLAGS)" \
+ make -C $(VB_SOURCE) \
+ BUILD=../$(dir $(VB_LIB)) \
+ V=$(V) \
+ fwlib
+
+endif
diff --git a/src/vendorcode/google/chromeos/chromeos.c b/src/vendorcode/google/chromeos/chromeos.c
index c1c3b3834c..559f1f0fdd 100644
--- a/src/vendorcode/google/chromeos/chromeos.c
+++ b/src/vendorcode/google/chromeos/chromeos.c
@@ -18,7 +18,11 @@
*/
#include "chromeos.h"
+#if CONFIG_VBOOT_VERIFY_FIRMWARE
+#include "vboot_handoff.h"
+#endif
#include <arch/coreboot_tables.h>
+#include <cbmem.h>
#include <console/console.h>
int developer_mode_enabled(void)
@@ -35,3 +39,31 @@ int recovery_mode_enabled(void)
return get_recovery_mode_switch() || get_recovery_mode_from_vbnv();
}
+#if CONFIG_VBOOT_VERIFY_FIRMWARE
+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 (len != NULL)
+ *len = fwc->size;
+
+ printk(BIOS_DEBUG, "Booting 0x%x byte payload at 0x%08x.\n",
+ fwc->size, fwc->address);
+
+ return (void *)fwc->address;
+}
+#endif
diff --git a/src/vendorcode/google/chromeos/chromeos.h b/src/vendorcode/google/chromeos/chromeos.h
index 37630a69bc..8410707a9b 100644
--- a/src/vendorcode/google/chromeos/chromeos.h
+++ b/src/vendorcode/google/chromeos/chromeos.h
@@ -20,9 +20,12 @@
#ifndef __CHROMEOS_H__
#define __CHROMEOS_H__
+#include <stdint.h>
+
/* functions implemented per mainboard: */
int get_developer_mode_switch(void);
int get_recovery_mode_switch(void);
+int get_write_protect_state(void);
#ifdef __PRE_RAM__
void save_chromeos_gpios(void);
#endif
@@ -32,6 +35,9 @@ int get_recovery_mode_from_vbnv(void);
int vboot_wants_oprom(void);
extern int oprom_is_loaded;
+void read_vbnv(uint8_t *vbnv_copy);
+void save_vbnv(const uint8_t *vbnv_copy);
+
/* functions implemented in chromeos.c: */
int developer_mode_enabled(void);
int recovery_mode_enabled(void);
@@ -39,4 +45,10 @@ int recovery_mode_enabled(void);
/* functions implemented in vboot.c */
void init_chromeos(int bootmode);
+#if CONFIG_VBOOT_VERIFY_FIRMWARE
+struct romstage_handoff;
+void vboot_verify_firmware(struct romstage_handoff *handoff);
+void *vboot_get_payload(int *len);
+#endif
+
#endif
diff --git a/src/vendorcode/google/chromeos/gnvs.c b/src/vendorcode/google/chromeos/gnvs.c
index 2e9975c9cb..0d4095061d 100644
--- a/src/vendorcode/google/chromeos/gnvs.c
+++ b/src/vendorcode/google/chromeos/gnvs.c
@@ -19,12 +19,17 @@
#include <types.h>
#include <string.h>
+#include <stdlib.h>
#include <cbfs.h>
+#include <cbmem.h>
#include <console/console.h>
#include <elog.h>
#include "chromeos.h"
#include "gnvs.h"
+#if CONFIG_VBOOT_VERIFY_FIRMWARE
+#include "vboot_handoff.h"
+#endif
chromeos_acpi_t *vboot_data = NULL;
static u32 me_hash_saved[8];
@@ -36,6 +41,19 @@ void chromeos_init_vboot(chromeos_acpi_t *chromeos)
/* Copy saved ME hash into NVS */
memcpy(vboot_data->mehh, me_hash_saved, sizeof(vboot_data->mehh));
+#if CONFIG_VBOOT_VERIFY_FIRMWARE
+ /* Save the vdat from the vboot handoff structure. Downstream software
+ * consumes the data located in the ACPI table. Ensure it reflects
+ * the shared data from VbInit() and VbSelectFirmware(). */
+ struct vboot_handoff *vboot_handoff;
+
+ vboot_handoff = cbmem_find(CBMEM_ID_VBOOT_HANDOFF);
+
+ if (vboot_handoff != NULL)
+ memcpy(&chromeos->vdat[0], &vboot_handoff->shared_data[0],
+ ARRAY_SIZE(chromeos->vdat));
+#endif
+
#if CONFIG_ELOG
if (developer_mode_enabled() ||
(vboot_wants_oprom() && !recovery_mode_enabled()))
diff --git a/src/vendorcode/google/chromeos/vbnv.c b/src/vendorcode/google/chromeos/vbnv.c
index 3f333f7211..2a2faf9e96 100644
--- a/src/vendorcode/google/chromeos/vbnv.c
+++ b/src/vendorcode/google/chromeos/vbnv.c
@@ -77,25 +77,39 @@ static uint8_t crc8(const uint8_t * data, int len)
return (uint8_t) (crc >> 8);
}
-static void vbnv_setup(void)
+void read_vbnv(uint8_t *vbnv_copy)
{
int i;
for (i = 0; i < CONFIG_VBNV_SIZE; i++)
- vbnv[i] = cmos_read(CONFIG_VBNV_OFFSET + 14 + i);
+ vbnv_copy[i] = cmos_read(CONFIG_VBNV_OFFSET + 14 + i);
/* Check data for consistency */
- if ((HEADER_SIGNATURE != (vbnv[HEADER_OFFSET] & HEADER_MASK))
- || (crc8(vbnv, CRC_OFFSET) != vbnv[CRC_OFFSET])) {
+ if ((HEADER_SIGNATURE != (vbnv_copy[HEADER_OFFSET] & HEADER_MASK))
+ || (crc8(vbnv_copy, CRC_OFFSET) != vbnv_copy[CRC_OFFSET])) {
/* Data is inconsistent (bad CRC or header),
* so reset to defaults
*/
- memset(vbnv, 0, VBNV_BLOCK_SIZE);
- vbnv[HEADER_OFFSET] =
+ memset(vbnv_copy, 0, VBNV_BLOCK_SIZE);
+ vbnv_copy[HEADER_OFFSET] =
(HEADER_SIGNATURE | HEADER_FIRMWARE_SETTINGS_RESET |
HEADER_KERNEL_SETTINGS_RESET);
}
+}
+
+void save_vbnv(const uint8_t *vbnv_copy)
+{
+ int i;
+
+ for (i = 0; i < CONFIG_VBNV_SIZE; i++)
+ cmos_write(vbnv_copy[i], CONFIG_VBNV_OFFSET + 14 + i);
+}
+
+
+static void vbnv_setup(void)
+{
+ read_vbnv(vbnv);
vbnv_initialized = 1;
}
diff --git a/src/vendorcode/google/chromeos/vboot_context.h b/src/vendorcode/google/chromeos/vboot_context.h
new file mode 100644
index 0000000000..72a05350cd
--- /dev/null
+++ b/src/vendorcode/google/chromeos/vboot_context.h
@@ -0,0 +1,48 @@
+/*
+ * 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
+ */
+#ifndef VBOOT_CONTEXT_H
+#define VBOOT_CONTEXT_H
+
+#include <stdint.h>
+#include <vboot_api.h>
+
+/* 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_context {
+ struct vboot_handoff *handoff;
+ VbCommonParams *cparams;
+ VbSelectFirmwareParams *fparams;
+ uint8_t *fw_a;
+ uint32_t fw_a_size;
+ uint8_t *fw_b;
+ uint32_t fw_b_size;
+ /* Callback implementations living in romstage. */
+ void (*read_vbnv)(uint8_t *vbnv_copy);
+ void (*save_vbnv)(const uint8_t *vbnv_copy);
+ int (*tis_init)(void);
+ int (*tis_open)(void);
+ int (*tis_close)(void);
+ int (*tis_sendrecv)(const u8 *sendbuf, size_t send_size, u8 *recvbuf,
+ size_t *recv_len);
+ void (*log_msg)(const char *fmt, va_list args);
+ void (*fatal_error)(void);
+};
+
+#endif /* VBOOT_CONTEXT_H */
diff --git a/src/vendorcode/google/chromeos/vboot_handoff.h b/src/vendorcode/google/chromeos/vboot_handoff.h
new file mode 100644
index 0000000000..09c7897f54
--- /dev/null
+++ b/src/vendorcode/google/chromeos/vboot_handoff.h
@@ -0,0 +1,53 @@
+/*
+ * 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
+ */
+#ifndef VBOOT_HANDOFF_H
+#define VBOOT_HANDOFF_H
+
+#include <vboot_api.h>
+
+/*
+ * The vboot handoff structure keeps track of a maximum number of firmware
+ * components in the verfieid RW area of flash. This is not a restriction on
+ * the number of components packed in a firmware block. It's only the maximum
+ * number of parsed firmware components (address and size) included in the
+ * handoff structure.
+ */
+
+#define MAX_PARSED_FW_COMPONENTS 5
+
+struct firmware_component {
+ uint32_t address;
+ uint32_t size;
+} __attribute__((packed));
+
+/*
+ * The vboot_handoff structure contains the data to be consumed by downstream
+ * firmware after firmware selection has been completed. Namely it provides
+ * vboot shared data as well as the flags from VbInit. As noted above a finite
+ * number of components are parsed from the verfieid firmare region.
+ */
+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));
+
+
+#endif /* VBOOT_HANDOFF_H */
diff --git a/src/vendorcode/google/chromeos/vboot_loader.c b/src/vendorcode/google/chromeos/vboot_loader.c
new file mode 100644
index 0000000000..a1a4586d5c
--- /dev/null
+++ b/src/vendorcode/google/chromeos/vboot_loader.c
@@ -0,0 +1,280 @@
+/*
+ * 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 <stdint.h>
+#include <stddef.h>
+#include <cbfs.h>
+#include <cbmem.h>
+#include <console/console.h>
+#include <console/vtxprintf.h>
+#include <pc80/tpm.h>
+#include <reset.h>
+#include <romstage_handoff.h>
+#include <rmodule.h>
+#include <string.h>
+#include <stdlib.h>
+#include <timestamp.h>
+#include "chromeos.h"
+#include "fmap.h"
+#include "vboot_context.h"
+#include "vboot_handoff.h"
+
+static void vboot_run_stub(struct vboot_context *context)
+{
+ const struct cbmem_entry *vboot_entry;
+ struct rmodule vbootstub;
+ struct cbfs_stage *stage;
+ size_t region_size;
+ int rmodule_offset;
+ int load_offset;
+ char *vboot_region;
+ void (*entry)(struct vboot_context *context);
+
+ stage = cbfs_find_file(CONFIG_CBFS_PREFIX "/vboot", CBFS_TYPE_STAGE);
+
+ if (stage == NULL)
+ return;
+
+ rmodule_offset =
+ rmodule_calc_region(DYN_CBMEM_ALIGN_SIZE,
+ stage->memlen, &region_size, &load_offset);
+
+ vboot_entry = cbmem_entry_add(0xffffffff, region_size);
+
+ if (vboot_entry == NULL) {
+ printk(BIOS_DEBUG, "Couldn't get region for vboot stub.\n");
+ return;
+ }
+
+ vboot_region = cbmem_entry_start(vboot_entry);
+
+ if (cbfs_decompress(stage->compression, &stage[1],
+ &vboot_region[rmodule_offset], stage->len)) {
+ printk(BIOS_DEBUG, "Couldn't decompress vboot stub.\n");
+ goto out;
+ }
+
+ if (rmodule_parse(&vboot_region[rmodule_offset], &vbootstub)) {
+ printk(BIOS_DEBUG, "Couldn't parse vboot stub rmodule.\n");
+ goto out;
+ }
+
+ if (rmodule_load(&vboot_region[load_offset], &vbootstub)) {
+ printk(BIOS_DEBUG, "Couldn't load vboot stub.\n");
+ goto out;
+ }
+
+ entry = rmodule_entry(&vbootstub);
+
+ /* Call stub. */
+ entry(context);
+
+out:
+ /* Tear down the region no longer needed. */
+ cbmem_entry_remove(vboot_entry);
+}
+
+/* Helper routines for the vboot stub. */
+static void log_msg(const char *fmt, va_list args)
+{
+ vtxprintf(console_tx_byte, fmt, args);
+ console_tx_flush();
+}
+
+static void fatal_error(void)
+{
+ printk(BIOS_ERR, "vboot encountered fatal error. Reseting.\n");
+ hard_reset();
+}
+
+static void vboot_invoke_wrapper(struct vboot_handoff *vboot_handoff)
+{
+ VbCommonParams cparams;
+ VbSelectFirmwareParams fparams;
+ struct vboot_context context;
+ uint32_t *iflags;
+
+ vboot_handoff->selected_firmware = VB_SELECT_FIRMWARE_READONLY;
+
+ memset(&cparams, 0, sizeof(cparams));
+ memset(&fparams, 0, sizeof(fparams));
+ memset(&context, 0, sizeof(context));
+
+ iflags = &vboot_handoff->init_params.flags;
+ if (get_developer_mode_switch())
+ *iflags |= VB_INIT_FLAG_DEV_SWITCH_ON;
+ if (get_recovery_mode_switch())
+ *iflags |= VB_INIT_FLAG_REC_BUTTON_PRESSED;
+ if (get_write_protect_state())
+ *iflags |= VB_INIT_FLAG_WP_ENABLED;
+ if (CONFIG_VIRTUAL_DEV_SWITCH)
+ *iflags |= VB_INIT_FLAG_VIRTUAL_DEV_SWITCH;
+ if (CONFIG_EC_SOFTWARE_SYNC)
+ *iflags |= VB_INIT_FLAG_EC_SOFTWARE_SYNC;
+
+ context.handoff = vboot_handoff;
+ context.cparams = &cparams;
+ context.fparams = &fparams;
+
+ cparams.gbb_size = find_fmap_entry("GBB", &cparams.gbb_data);
+ cparams.shared_data_blob = &vboot_handoff->shared_data[0];
+ cparams.shared_data_size = VB_SHARED_DATA_MIN_SIZE;
+ cparams.caller_context = &context;
+
+ fparams.verification_size_A =
+ find_fmap_entry("VBLOCK_A", &fparams.verification_block_A);
+ fparams.verification_size_B =
+ find_fmap_entry("VBLOCK_B", &fparams.verification_block_B);
+
+ context.fw_a_size =
+ find_fmap_entry("FW_MAIN_A", (void **)&context.fw_a);
+ context.fw_b_size =
+ find_fmap_entry("FW_MAIN_B", (void **)&context.fw_b);
+
+ /* Check all fmap entries. */
+ if (context.fw_a == NULL || context.fw_b == NULL ||
+ fparams.verification_block_A == NULL ||
+ fparams.verification_block_B == NULL ||
+ cparams.gbb_data == NULL) {
+ printk(BIOS_DEBUG, "Not all fmap entries found for vboot.\n");
+ return;
+ }
+
+ /* Initialize callbacks. */
+ context.read_vbnv = &read_vbnv;
+ context.save_vbnv = &save_vbnv;
+ context.tis_init = &tis_init;
+ context.tis_open = &tis_open;
+ context.tis_close = &tis_close;
+ context.tis_sendrecv = &tis_sendrecv;
+ context.log_msg = &log_msg;
+ context.fatal_error = &fatal_error;
+
+ vboot_run_stub(&context);
+}
+
+static void vboot_load_ramstage(struct vboot_handoff *vboot_handoff,
+ struct romstage_handoff *handoff)
+{
+ struct cbfs_stage *stage;
+ struct rmodule ramstage;
+ void *entry_point;
+ size_t region_size;
+ char *ramstage_region;
+ int rmodule_offset;
+ int load_offset;
+ const struct cbmem_entry *ramstage_entry;
+ const struct firmware_component *fwc;
+
+ if (CONFIG_VBOOT_RAMSTAGE_INDEX >= MAX_PARSED_FW_COMPONENTS) {
+ printk(BIOS_ERR, "Invalid ramstage index: %d\n",
+ CONFIG_VBOOT_RAMSTAGE_INDEX);
+ return;
+ }
+
+ /* Check for invalid address. */
+ fwc = &vboot_handoff->components[CONFIG_VBOOT_RAMSTAGE_INDEX];
+ if (fwc->address == 0) {
+ printk(BIOS_DEBUG, "RW ramstage image address invalid.\n");
+ return;
+ }
+
+ printk(BIOS_DEBUG, "RW ramstage image at 0x%08x, 0x%08x bytes.\n",
+ fwc->address, fwc->size);
+
+ stage = (void *)fwc->address;
+
+ rmodule_offset =
+ rmodule_calc_region(DYN_CBMEM_ALIGN_SIZE,
+ stage->memlen, &region_size, &load_offset);
+
+ ramstage_entry = cbmem_entry_add(CBMEM_ID_RAMSTAGE, region_size);
+
+ if (ramstage_entry == NULL) {
+ vboot_handoff->selected_firmware = VB_SELECT_FIRMWARE_READONLY;
+ printk(BIOS_DEBUG, "Could not add ramstage region.\n");
+ return;
+ }
+
+ timestamp_add_now(TS_START_COPYRAM);
+
+ ramstage_region = cbmem_entry_start(ramstage_entry);
+
+ printk(BIOS_DEBUG, "Decompressing ramstage @ 0x%p (%d bytes)\n",
+ &ramstage_region[rmodule_offset], stage->memlen);
+
+ if (cbfs_decompress(stage->compression, &stage[1],
+ &ramstage_region[rmodule_offset], stage->len))
+ return;
+
+ if (rmodule_parse(&ramstage_region[rmodule_offset], &ramstage))
+ return;
+
+ /* The ramstage is responsible for clearing its own bss. */
+ if (rmodule_load_no_clear_bss(&ramstage_region[load_offset], &ramstage))
+ return;
+
+ entry_point = rmodule_entry(&ramstage);
+
+ cache_loaded_ramstage(handoff, ramstage_entry, entry_point);
+
+ timestamp_add_now(TS_END_COPYRAM);
+
+ __asm__ volatile (
+ "movl $0, %%ebp\n"
+ "jmp *%%edi\n"
+ :: "D"(entry_point)
+ );
+}
+
+void vboot_verify_firmware(struct romstage_handoff *handoff)
+{
+ struct vboot_handoff *vboot_handoff;
+
+ /* Don't go down verified boot path on S3 resume. */
+ if (handoff != NULL && handoff->s3_resume)
+ return;
+
+ timestamp_add_now(TS_START_VBOOT);
+
+ vboot_handoff = cbmem_add(CBMEM_ID_VBOOT_HANDOFF,
+ sizeof(*vboot_handoff));
+
+ if (vboot_handoff == NULL) {
+ printk(BIOS_DEBUG, "Could not add vboot_handoff structure.\n");
+ return;
+ }
+
+ memset(vboot_handoff, 0, sizeof(*vboot_handoff));
+
+ vboot_invoke_wrapper(vboot_handoff);
+
+ timestamp_add_now(TS_END_VBOOT);
+
+ /* Take RO firmware path since no RW area was selected. */
+ if (vboot_handoff->selected_firmware != VB_SELECT_FIRMWARE_A &&
+ vboot_handoff->selected_firmware != VB_SELECT_FIRMWARE_B) {
+ printk(BIOS_DEBUG, "No RW firmware selected: 0x%08x\n",
+ vboot_handoff->selected_firmware);
+ return;
+ }
+
+ /* Load ramstage from the vboot_handoff structure. */
+ vboot_load_ramstage(vboot_handoff, handoff);
+}
diff --git a/src/vendorcode/google/chromeos/vboot_wrapper.c b/src/vendorcode/google/chromeos/vboot_wrapper.c
new file mode 100644
index 0000000000..66b7cfb276
--- /dev/null
+++ b/src/vendorcode/google/chromeos/vboot_wrapper.c
@@ -0,0 +1,268 @@
+/*
+ * 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 <console/vtxprintf.h>
+#include <cpu/x86/tsc.h>
+#include <rmodule.h>
+#include <stdlib.h>
+#include <string.h>
+#include "vboot_context.h"
+#include "vboot_handoff.h"
+
+static void vboot_wrapper(struct vboot_context *context);
+
+DEFINE_RMODULE_HEADER(vboot_wrapper_header, vboot_wrapper, RMODULE_TYPE_VBOOT);
+
+/* Keep a global context pointer around for the callbacks to use. */
+static struct vboot_context *gcontext;
+
+/* 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. */
+#define MAX_NUM_COMPONENTS 20
+
+struct component_entry {
+ uint32_t offset;
+ uint32_t size;
+} __attribute__((packed));
+
+struct components {
+ uint32_t num_components;
+ struct component_entry entries[0];
+} __attribute__((packed));
+
+
+static void parse_component(const struct components *components, int num,
+ struct firmware_component *fw)
+{
+ const char *base;
+
+ if (num >= components->num_components)
+ return;
+
+ /* Offsets are relative to the stat of the book keeping structure. */
+ base = (void *)components;
+
+ fw->address = (uint32_t)&base[components->entries[num].offset];
+ fw->size = (uint32_t)components->entries[num].size;
+}
+
+static void vboot_wrapper(struct vboot_context *context)
+{
+ int i;
+ VbError_t res;
+ const struct components *components;
+
+ gcontext = context;
+
+ VbExDebug("Calling VbInit()\n");
+ res = VbInit(context->cparams, &context->handoff->init_params);
+ VbExDebug("VbInit() returned 0x%08x\n", res);
+
+ if (res != VBERROR_SUCCESS)
+ return;
+
+ VbExDebug("Calling VbSelectFirmware()\n");
+ res = VbSelectFirmware(context->cparams, context->fparams);
+ VbExDebug("VbSelectFirmware() returned 0x%08x\n", res);
+
+ if (res != VBERROR_SUCCESS)
+ return;
+
+ /* Fix up the handoff structure. */
+ context->handoff->selected_firmware =
+ context->fparams->selected_firmware;
+
+ /* Parse out the components for downstream consumption. */
+ if (context->handoff->selected_firmware == VB_SELECT_FIRMWARE_A)
+ components = (void *)context->fw_a;
+ else if (context->handoff->selected_firmware == VB_SELECT_FIRMWARE_B)
+ components = (void *)context->fw_b;
+ else
+ return;
+
+ for (i = 0; i < MAX_PARSED_FW_COMPONENTS; i++) {
+ parse_component(components, i,
+ &context->handoff->components[i]);
+ }
+}
+
+void VbExError(const char *format, ...)
+{
+ va_list args;
+
+ va_start(args, format);
+ gcontext->log_msg(format, args);
+ va_end(args);
+
+ gcontext->fatal_error();
+}
+
+void VbExDebug(const char *format, ...)
+{
+ va_list args;
+
+ va_start(args, format);
+ gcontext->log_msg(format, args);
+ va_end(args);
+}
+
+uint64_t VbExGetTimer(void)
+{
+ return rdtscll();
+}
+
+VbError_t VbExNvStorageRead(uint8_t *buf)
+{
+ gcontext->read_vbnv(buf);
+ return VBERROR_SUCCESS;
+}
+
+VbError_t VbExNvStorageWrite(const uint8_t *buf)
+{
+ gcontext->save_vbnv(buf);
+ return VBERROR_SUCCESS;
+}
+
+extern char _heap[];
+extern char _eheap[];
+static char *heap_current;
+static int heap_size;
+
+void *VbExMalloc(size_t size)
+{
+ void *ptr;
+
+ if (heap_current == NULL) {
+ heap_current = &_heap[0];
+ heap_size = &_eheap[0] - &_heap[0];
+ VbExDebug("vboot heap: %p 0x%08x bytes\n",
+ heap_current, heap_size);
+ }
+
+ if (heap_size < size) {
+ VbExError("vboot heap request cannot be fulfilled. "
+ "0x%08x available, 0x%08x requested\n",
+ heap_size, size);
+ }
+
+ ptr = heap_current;
+ heap_size -= size;
+ heap_current += size;
+
+ return ptr;
+}
+
+void VbExFree(void *ptr)
+{
+ /* Leak all memory. */
+}
+
+/* vboot doesn't expose these through the vboot_api.h, but they are needed.
+ * coreboot requires declarations so provide them to avoid compiler errors. */
+int Memcmp(const void *src1, const void *src2, size_t n);
+void *Memcpy(void *dest, const void *src, uint64_t n);
+void *Memset(void *dest, const uint8_t c, uint64_t n);
+
+int Memcmp(const void *src1, const void *src2, size_t n)
+{
+ return memcmp(src1, src2, n);
+}
+
+void *Memcpy(void *dest, const void *src, uint64_t n)
+{
+ return memcpy(dest, src, n);
+}
+
+void *Memset(void *dest, const uint8_t c, uint64_t n)
+{
+ return memset(dest, c, n);
+}
+
+VbError_t VbExHashFirmwareBody(VbCommonParams *cparams, uint32_t firmware_index)
+{
+ uint8_t *data;
+ uint32_t size;
+ uint32_t data_size;
+ struct components *components;
+ uint32_t i;
+
+ switch (firmware_index) {
+ case VB_SELECT_FIRMWARE_A:
+ data = gcontext->fw_a;
+ size = gcontext->fw_a_size;
+ break;
+ case VB_SELECT_FIRMWARE_B:
+ data = gcontext->fw_b;
+ size = gcontext->fw_b_size;
+ break;
+ default:
+ return VBERROR_UNKNOWN;
+ }
+
+ components = (void *)data;
+ data_size = sizeof(struct components);
+
+ if (components->num_components > MAX_NUM_COMPONENTS)
+ return VBERROR_UNKNOWN;
+
+ data_size +=
+ components->num_components * sizeof(struct component_entry);
+
+ for (i = 0; i < components->num_components; i++)
+ data_size += ALIGN(components->entries[i].size, 4);
+
+ if (size < data_size)
+ return VBERROR_UNKNOWN;
+
+ VbUpdateFirmwareBodyHash(cparams, data, data_size);
+
+ return VBERROR_SUCCESS;
+}
+
+VbError_t VbExTpmInit(void)
+{
+ if (gcontext->tis_init())
+ return VBERROR_UNKNOWN;
+ return VbExTpmOpen();
+}
+
+VbError_t VbExTpmClose(void)
+{
+ if (gcontext->tis_close())
+ return VBERROR_UNKNOWN;
+ return VBERROR_SUCCESS;
+}
+
+VbError_t VbExTpmOpen(void)
+{
+ if (gcontext->tis_open())
+ return VBERROR_UNKNOWN;
+ return VBERROR_SUCCESS;
+}
+
+VbError_t VbExTpmSendReceive(const uint8_t *request, uint32_t request_length,
+ uint8_t *response, uint32_t *response_length)
+{
+ if (gcontext->tis_sendrecv(request, request_length,
+ response, response_length))
+ return VBERROR_UNKNOWN;
+ return VBERROR_SUCCESS;
+}
+