diff --git a/Makefile.inc b/Makefile.inc index 49a449b1e4..a9de19785c 100644 --- a/Makefile.inc +++ b/Makefile.inc @@ -104,8 +104,6 @@ ramstage-postprocess=$(foreach d,$(sort $(dir $(1))), \ $(eval $(d)ramstage.o: $(call files-in-dir,$(d),$(1)); $$(LINK) -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) @@ -321,10 +319,6 @@ $(obj)/%.romstage.o $(abspath $(obj))/%.romstage.o: $(obj)/%.c $(obj)/config.h $ @printf " CC $(subst $(obj)/,,$(@))\n" $(CC_romstage) -MMD $(CFLAGS_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) $(bootblock-c-ccopts) -c -o $@ $< diff --git a/src/arch/arm/Makefile.inc b/src/arch/arm/Makefile.inc index 62f712a5af..ef9ec90cae 100644 --- a/src/arch/arm/Makefile.inc +++ b/src/arch/arm/Makefile.inc @@ -55,14 +55,14 @@ bootblock-y += memset.S bootblock-y += memcpy.S bootblock-y += memmove.S -$(objcbfs)/bootblock.debug: $(src)/arch/arm/bootblock.ld $(obj)/ldoptions $$(bootblock-objs) $$(VERSTAGE_LIB) $$(VB2_LIB) $(obj)/config.h +$(objcbfs)/bootblock.debug: $(src)/arch/arm/bootblock.ld $(obj)/ldoptions $$(bootblock-objs) $(obj)/config.h @printf " LINK $(subst $(obj)/,,$(@))\n" ifeq ($(CONFIG_COMPILER_LLVM_CLANG),y) $(LD_bootblock) -nostdlib -m armelf_linux_eabi --gc-sections -static -o $@ -L$(obj) $< -T $(src)/arch/arm/bootblock.ld else # This is based on the assumption that bootblock and verstage are compatible # from the linker's perspective. - $(CC_bootblock) $(CFLAGS_bootblock) -nostdlib -Wl,--gc-sections -static -o $@ -L$(obj) -T $(src)/arch/arm/bootblock.ld -Wl,--start-group $(bootblock-objs) $(VERSTAGE_LIB) $(VB2_LIB) -Wl,--end-group + $(CC_bootblock) $(CFLAGS_bootblock) -nostdlib -Wl,--gc-sections -static -o $@ -L$(obj) -T $(src)/arch/arm/bootblock.ld -Wl,--start-group $(bootblock-objs) -Wl,--end-group endif endif @@ -71,6 +71,14 @@ endif # verification stage ############################################################################### +$(objcbfs)/verstage.debug: $$(verstage-objs) $(src)/arch/arm/verstage.ld $(obj)/ldoptions $$(VB2_LIB) + @printf " LINK $(subst $(obj)/,,$(@))\n" +ifeq ($(CONFIG_COMPILER_LLVM_CLANG),y) + $(LD_verstage) -nostdlib --gc-sections -static -o $@ -L$(obj) $(verstage-objs) -T $(src)/arch/arm/verstage.ld +else + $(CC_verstage) $(CFLAGS_verstage) -nostdlib -Wl,--gc-sections -static -o $@ -L$(obj) -T $(src)/arch/arm/verstage.ld -Wl,--start-group $(verstage-objs) $(VB2_LIB) -Wl,--end-group +endif + verstage-$(CONFIG_EARLY_CONSOLE) += early_console.c verstage-y += div0.c verstage-y += eabi_compat.c @@ -147,4 +155,3 @@ else endif endif - diff --git a/src/arch/arm/bootblock.ld b/src/arch/arm/bootblock.ld index 57bcd309de..0d1cf754a7 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_CBMEM_CONSOLE_PRERAM_BASE; - verstage_preram_cbmem_console = CONFIG_CBMEM_CONSOLE_PRERAM_BASE; /DISCARD/ : { *(.comment) @@ -60,4 +59,4 @@ SECTIONS *(.note.*) *(.ARM.*) } -} +} \ No newline at end of file diff --git a/src/arch/arm/verstage.ld b/src/arch/arm/verstage.ld new file mode 100644 index 0000000000..3c4da7aab1 --- /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_CBMEM_CONSOLE_PRERAM_BASE; + + /* Discard the sections we don't need/want */ + /DISCARD/ : { + *(.comment) + *(.note) + *(.comment.*) + *(.note.*) + *(.eh_frame); + } +} diff --git a/src/console/Makefile.inc b/src/console/Makefile.inc index 3536eaf2c6..299bcea3ed 100644 --- a/src/console/Makefile.inc +++ b/src/console/Makefile.inc @@ -32,4 +32,5 @@ ramstage-$(CONFIG_CONSOLE_SERIAL_IPQ806X) += uart_wrapper.c $(obj)/console/console.ramstage.o : $(obj)/build.h $(obj)/console/console.romstage.o : $(obj)/build.h +$(obj)/console/console.verstage.o : $(obj)/build.h $(obj)/console/console.bootblock.o : $(obj)/build.h diff --git a/src/lib/cbfs.c b/src/lib/cbfs.c index ef6d0d86ee..8eca396a94 100644 --- a/src/lib/cbfs.c +++ b/src/lib/cbfs.c @@ -335,6 +335,8 @@ void *cbfs_load_payload(struct cbfs_media *media, const char *name) payload = (struct cbfs_payload *)cbfs_get_file_content( media, name, CBFS_TYPE_PAYLOAD); + if (payload) + printk(BIOS_DEBUG, "Booting payload %s from cbfs\n", name); return payload; } #endif diff --git a/src/mainboard/google/nyan/romstage.c b/src/mainboard/google/nyan/romstage.c index 113427a975..48966894b1 100644 --- a/src/mainboard/google/nyan/romstage.c +++ b/src/mainboard/google/nyan/romstage.c @@ -48,8 +48,6 @@ static void __attribute__((noinline)) romstage(void) uint64_t romstage_start_time = timestamp_get(); #endif - configure_l2_cache(); - console_init(); exception_init(); @@ -60,6 +58,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 113427a975..48966894b1 100644 --- a/src/mainboard/google/nyan_big/romstage.c +++ b/src/mainboard/google/nyan_big/romstage.c @@ -48,8 +48,6 @@ static void __attribute__((noinline)) romstage(void) uint64_t romstage_start_time = timestamp_get(); #endif - configure_l2_cache(); - console_init(); exception_init(); @@ -60,6 +58,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 403e8003ef..db721fad51 100644 --- a/src/mainboard/google/nyan_blaze/Kconfig +++ b/src/mainboard/google/nyan_blaze/Kconfig @@ -92,6 +92,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 844fb727b3..10e2147dd5 100644 --- a/src/mainboard/google/nyan_blaze/Makefile.inc +++ b/src/mainboard/google/nyan_blaze/Makefile.inc @@ -30,8 +30,8 @@ subdirs-y += bct bootblock-y += bootblock.c bootblock-y += pmic.c bootblock-y += reset.c -bootblock-y += early_configs.c +verstage-y += early_configs.c verstage-y += chromeos.c verstage-y += reset.c diff --git a/src/mainboard/google/nyan_blaze/romstage.c b/src/mainboard/google/nyan_blaze/romstage.c index 26d393c301..765297ee0f 100644 --- a/src/mainboard/google/nyan_blaze/romstage.c +++ b/src/mainboard/google/nyan_blaze/romstage.c @@ -44,12 +44,11 @@ static void __attribute__((noinline)) romstage(void) { + void *entry = NULL; #if CONFIG_COLLECT_TIMESTAMPS uint64_t romstage_start_time = timestamp_get(); #endif - configure_l2_cache(); - console_init(); exception_init(); @@ -60,21 +59,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 @@ -90,22 +93,25 @@ static void __attribute__((noinline)) romstage(void) timestamp_init(0); timestamp_add(TS_START_ROMSTAGE, romstage_start_time); - early_mainboard_init(); - #if CONFIG_CONSOLE_CBMEM cbmemc_reinit(); #endif #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 - timestamp_add(TS_START_COPYRAM, timestamp_get()); - void *entry = cbfs_load_stage(CBFS_DEFAULT_MEDIA, - "fallback/ramstage"); - timestamp_add(TS_END_COPYRAM, timestamp_get()); + if (entry == NULL) { + timestamp_add(TS_START_COPYRAM, timestamp_get()); + entry = cbfs_load_stage(CBFS_DEFAULT_MEDIA, + CONFIG_CBFS_PREFIX "/ramstage"); + timestamp_add(TS_END_COPYRAM, timestamp_get()); + if (entry == (void *)-1) + die("failed to load ramstage\n"); + } stage_exit(entry); } @@ -113,7 +119,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 7d48d8b749..31f94a87a0 100644 --- a/src/soc/nvidia/tegra124/Kconfig +++ b/src/soc/nvidia/tegra124/Kconfig @@ -42,6 +42,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 @@ -49,12 +59,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 @@ -65,9 +73,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 @@ -98,6 +113,7 @@ config CBFS_CACHE_ADDRESS config CBFS_CACHE_SIZE hex "size of CBFS cache data" + default 0x00012000 if VBOOT2_VERIFY_FIRMWARE default 0x00016000 config VBOOT_WORK_BUFFER_ADDRESS diff --git a/src/soc/nvidia/tegra124/bootblock.c b/src/soc/nvidia/tegra124/bootblock.c index 3719e0f423..9205ce33ec 100644 --- a/src/soc/nvidia/tegra124/bootblock.c +++ b/src/soc/nvidia/tegra124/bootblock.c @@ -18,7 +18,6 @@ */ #include -#include #include #include #include @@ -26,11 +25,9 @@ #include #include #include -#include #include #include "pinmux.h" #include "power.h" -#include "verstage.h" void main(void) { @@ -74,12 +71,12 @@ void main(void) PINMUX_PWR_INT_N_FUNC_PMICINTR | PINMUX_INPUT_ENABLE); -#if CONFIG_VBOOT2_VERIFY_FIRMWARE - early_mainboard_init(); - entry = (void *)verstage_vboot_main; -#else - entry = cbfs_load_stage(CBFS_DEFAULT_MEDIA, "fallback/romstage"); -#endif + if (IS_ENABLED(CONFIG_VBOOT2_VERIFY_FIRMWARE)) + entry = cbfs_load_stage(CBFS_DEFAULT_MEDIA, + CONFIG_CBFS_PREFIX "/verstage"); + 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 d85fc5c8cf..60361a2afd 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 +#include +#include +#include +#include #include -/** - * Stage entry point - */ -void vboot_main(void) +static void enable_cache(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"); - - select_firmware(); + 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) +{ + asm volatile ("bl arm_init_caches" + : : : "r0", "r1", "r2", "r3", "r4", "r5", "ip"); + + 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 a0bac347c6..0000000000 --- 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 aa64d31e98..e8b44f5d1b 100644 --- a/src/vendorcode/google/chromeos/Kconfig +++ b/src/vendorcode/google/chromeos/Kconfig @@ -93,17 +93,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 @@ -112,22 +112,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 33d7f47c5b..36a873bef7 100644 --- a/src/vendorcode/google/chromeos/Makefile.inc +++ b/src/vendorcode/google/chromeos/Makefile.inc @@ -86,7 +86,7 @@ endif VBOOT_STUB_DEPS += $(VB_LIB) # Remove the '-include' option since that will break vboot's build and ensure # vboot_reference can get to coreboot's include files. -VBOOT_CFLAGS += $(patsubst -I%,-I../%,$(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) @@ -104,7 +104,7 @@ $(VB_LIB): CFLAGS="$(VBOOT_CFLAGS)" \ make -C $(VB_SOURCE) \ $(VBOOT_MAKEFLAGS) \ - BUILD=../$(dir $(VB_LIB)) \ + BUILD=$(top)/$(dir $(VB_LIB)) \ V=$(V) \ fwlib @@ -112,10 +112,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 @@ -136,13 +143,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 \ No newline at end of file diff --git a/src/vendorcode/google/chromeos/chromeos.c b/src/vendorcode/google/chromeos/chromeos.c index 176d0e9d69..d2f62d7da7 100644 --- a/src/vendorcode/google/chromeos/chromeos.c +++ b/src/vendorcode/google/chromeos/chromeos.c @@ -21,7 +21,9 @@ #include #include "chromeos.h" #if CONFIG_VBOOT_VERIFY_FIRMWARE || CONFIG_VBOOT2_VERIFY_FIRMWARE +#include "fmap.h" #include "vboot_handoff.h" +#include #endif #include #include @@ -119,6 +121,11 @@ int __attribute((weak)) vboot_get_sw_write_protect(void) #endif #if CONFIG_VBOOT_VERIFY_FIRMWARE || CONFIG_VBOOT2_VERIFY_FIRMWARE +void vboot_locate_region(const char *name, struct vboot_region *region) +{ + region->size = find_fmap_entry(name, (void **)®ion->offset_addr); +} + void *vboot_get_region(uintptr_t offset_addr, size_t size, void *dest) { if (IS_ENABLED(CONFIG_SPI_FLASH_MEMORY_MAPPED)) { @@ -159,13 +166,24 @@ int vboot_get_handoff_info(void **addr, uint32_t *size) *size = sizeof(*vboot_handoff); return 0; } -#endif -#if CONFIG_VBOOT2_VERIFY_FIRMWARE -void *vboot_get_payload(int *len) { return NULL; } -#endif +/* 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; +} -#if CONFIG_VBOOT_VERIFY_FIRMWARE void *vboot_get_payload(int *len) { struct vboot_handoff *vboot_handoff; @@ -191,10 +209,76 @@ void *vboot_get_payload(int *len) if (len != NULL) *len = fwc->size; - printk(BIOS_DEBUG, "Booting 0x%x byte payload at 0x%08x.\n", + 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 7022780f75..6c2f1618ec 100644 --- a/src/vendorcode/google/chromeos/chromeos.h +++ b/src/vendorcode/google/chromeos/chromeos.h @@ -68,6 +68,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 @@ -116,8 +148,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 cd82aacf0a..2517f63e63 100644 --- a/src/vendorcode/google/chromeos/vboot_context.h +++ b/src/vendorcode/google/chromeos/vboot_context.h @@ -21,21 +21,12 @@ #include #include +#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 3b276aac95..ae3096aee2 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 +#include #include #include #include @@ -33,13 +35,33 @@ #include "vboot_handoff.h" #include +static void *load_ramstage(struct vboot_handoff *vboot_handoff, + struct vboot_region *fw_main) +{ + struct vboot_components *fw_info; + int i; + + fw_info = vboot_locate_components(fw_main); + if (fw_info == NULL) + die("failed to locate firmware components\n"); + + /* these offset & size are used to load a rw boot loader */ + for (i = 0; i < fw_info->num_components; i++) { + vboot_handoff->components[i].address = + fw_main->offset_addr + fw_info->entries[i].offset; + vboot_handoff->components[i].size = fw_info->entries[i].size; + } + + return vboot_load_stage(CONFIG_VBOOT_RAMSTAGE_INDEX, fw_main, fw_info); +} + /** * Sets vboot_handoff based on the information in vb2_shared_data * * TODO: Read wp switch to set VBSD_BOOT_FIRMWARE_WP_ENABLED */ static void fill_vboot_handoff(struct vboot_handoff *vboot_handoff, - struct vb2_shared_data *vb2_sd) + 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 e1e519f081..b0017438ac 100644 --- a/src/vendorcode/google/chromeos/vboot_handoff.h +++ b/src/vendorcode/google/chromeos/vboot_handoff.h @@ -21,16 +21,7 @@ #include #include - -/* - * 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 97edd7c990..20598201f2 100644 --- a/src/vendorcode/google/chromeos/vboot_loader.c +++ b/src/vendorcode/google/chromeos/vboot_loader.c @@ -34,26 +34,9 @@ #include #include #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 @@ -94,24 +77,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 **)®ion->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; @@ -119,7 +91,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)); @@ -191,9 +163,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. */ @@ -208,12 +179,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; @@ -274,11 +240,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 f6d81962aa..4970124b04 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 -#include -#include -#include -#include #include #include -#include -#include -#include #include #include "chromeos.h" -#include "fmap.h" -#define VBDEBUG(format, args...) \ - printk(BIOS_INFO, "%s():%d: " format, __func__, __LINE__, ## args) -#define TODO_BLOCK_SIZE 8192 -#define MAX_PARSED_FW_COMPONENTS 5 -#define ROMSTAGE_INDEX 2 - -struct component_entry { - uint32_t offset; - uint32_t size; -} __attribute__((packed)); - -struct components { - uint32_t num_components; - struct component_entry entries[MAX_PARSED_FW_COMPONENTS]; -} __attribute__((packed)); - -struct vboot_region { - uintptr_t offset_addr; - int32_t size; -}; - -static void locate_region(const char *name, struct vboot_region *region) -{ - region->size = find_fmap_entry(name, (void **)®ion->offset_addr); - VBDEBUG("Located %s @%x\n", name, region->offset_addr); -} +#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", ®ion); + vboot_locate_region("GBB", ®ion); break; case VB2_RES_FW_VBLOCK: if (is_slot_a(ctx)) - locate_region("VBLOCK_A", ®ion); + vboot_locate_region("VBLOCK_A", ®ion); else - locate_region("VBLOCK_B", ®ion); + vboot_locate_region("VBLOCK_B", ®ion); 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) -{ - hard_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"); + /* 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(); + } - /* Load next stage and jump to it */ - VBDEBUG("Jumping to rw-romstage @%llx\n", stage->entry); - enter_stage(stage); - - /* Shouldn't reach here */ - VBDEBUG("Halting\n"); - for (;;); + 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 0000000000..5df1777bb2 --- /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 +#include +#include +#include +#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"); +}