Introduce Verifying Program Loader (VPL)

Add support for VPL, a new phase of U-Boot. This runs after TPL. It is
responsible for selecting which SPL binary to run, based on a
verified-boot process.

Signed-off-by: Simon Glass <sjg@chromium.org>
This commit is contained in:
Simon Glass 2022-04-30 00:56:52 -06:00 committed by Tom Rini
parent d3eba95a7e
commit f86ca5ad8f
13 changed files with 131 additions and 19 deletions

View File

@ -911,6 +911,12 @@ else
TPL_SIZE_CHECK =
endif
ifneq ($(CONFIG_VPL_SIZE_LIMIT),0x0)
VPL_SIZE_CHECK = @$(call size_check,$@,$(CONFIG_VPL_SIZE_LIMIT))
else
VPL_SIZE_CHECK =
endif
# Statically apply RELA-style relocations (currently arm64 only)
# This is useful for arm64 where static relocation needs to be performed on
# the raw binary, but certain simulators only accept an ELF file (but don't
@ -951,6 +957,7 @@ INPUTS-$(CONFIG_SPL_FRAMEWORK) += u-boot.img
endif
endif
INPUTS-$(CONFIG_TPL) += tpl/u-boot-tpl.bin
INPUTS-$(CONFIG_VPL) += vpl/u-boot-vpl.bin
# Allow omitting the .dtb output if it is not normally used
INPUTS-$(CONFIG_OF_SEPARATE) += $(if $(CONFIG_OF_OMIT_DTB),dts/dt.dtb,u-boot.dtb)
@ -2117,6 +2124,13 @@ tpl/u-boot-tpl.bin: tpl/u-boot-tpl
tpl/u-boot-tpl: tools prepare $(if $(CONFIG_TPL_OF_CONTROL),dts/dt.dtb)
$(Q)$(MAKE) obj=tpl -f $(srctree)/scripts/Makefile.spl all
vpl/u-boot-vpl.bin: vpl/u-boot-vpl
@:
$(VPL_SIZE_CHECK)
vpl/u-boot-vpl: tools prepare $(if $(CONFIG_TPL_OF_CONTROL),dts/dt.dtb)
$(Q)$(MAKE) obj=vpl -f $(srctree)/scripts/Makefile.spl all
TAG_SUBDIRS := $(patsubst %,$(srctree)/%,$(u-boot-dirs) include)
FIND := find

View File

@ -1,4 +1,4 @@
menu "SPL / TPL"
menu "SPL / TPL / VPL"
config SUPPORT_SPL
bool
@ -6,6 +6,9 @@ config SUPPORT_SPL
config SUPPORT_TPL
bool
config SUPPORT_VPL
bool
config SPL_DFU_NO_RESET
bool
@ -302,6 +305,16 @@ config SPL_READ_ONLY
writeable memory) of anything it wants to modify, such as
device-private data.
config TPL_SEPARATE_BSS
bool "BSS section is in a different memory region from text"
default y if SPL_SEPARATE_BSS
help
Some platforms need a large BSS region in TPL and can provide this
because RAM is already set up. In this case BSS can be moved to RAM.
This option should then be enabled so that the correct device tree
location is used. Normally we put the device tree at the end of BSS
but with this option enabled, it goes at _image_binary_end.
config SPL_BANNER_PRINT
bool "Enable output of the SPL banner 'U-Boot SPL ...'"
default y

View File

@ -61,6 +61,11 @@ binman_sym_declare(ulong, u_boot_spl, image_pos);
binman_sym_declare(ulong, u_boot_spl, size);
#endif
#ifdef CONFIG_VPL
binman_sym_declare(ulong, u_boot_vpl, image_pos);
binman_sym_declare(ulong, u_boot_vpl, size);
#endif
/* Define board data structure */
static struct bd_info bdata __attribute__ ((section(".data")));
@ -146,14 +151,22 @@ void spl_fixup_fdt(void *fdt_blob)
#if CONFIG_IS_ENABLED(BINMAN_SYMBOLS)
ulong spl_get_image_pos(void)
{
return spl_phase() == PHASE_TPL ?
#ifdef CONFIG_VPL
if (spl_next_phase() == PHASE_VPL)
return binman_sym(ulong, u_boot_vpl, image_pos);
#endif
return spl_next_phase() == PHASE_SPL ?
binman_sym(ulong, u_boot_spl, image_pos) :
binman_sym(ulong, u_boot_any, image_pos);
}
ulong spl_get_image_size(void)
{
return spl_phase() == PHASE_TPL ?
#ifdef CONFIG_VPL
if (spl_next_phase() == PHASE_VPL)
return binman_sym(ulong, u_boot_vpl, size);
#endif
return spl_next_phase() == PHASE_SPL ?
binman_sym(ulong, u_boot_spl, size) :
binman_sym(ulong, u_boot_any, size);
}
@ -161,7 +174,11 @@ ulong spl_get_image_size(void)
ulong spl_get_image_text_base(void)
{
return spl_phase() == PHASE_TPL ? CONFIG_SPL_TEXT_BASE :
#ifdef CONFIG_VPL
if (spl_next_phase() == PHASE_VPL)
return CONFIG_VPL_TEXT_BASE;
#endif
return spl_next_phase() == PHASE_SPL ? CONFIG_SPL_TEXT_BASE :
CONFIG_SYS_TEXT_BASE;
}
@ -466,6 +483,8 @@ static enum bootstage_id get_bootstage_id(bool start)
if (IS_ENABLED(CONFIG_TPL_BUILD) && phase == PHASE_TPL)
return start ? BOOTSTAGE_ID_START_TPL : BOOTSTAGE_ID_END_TPL;
else if (IS_ENABLED(CONFIG_VPL_BUILD) && phase == PHASE_VPL)
return start ? BOOTSTAGE_ID_START_VPL : BOOTSTAGE_ID_END_VPL;
else
return start ? BOOTSTAGE_ID_START_SPL : BOOTSTAGE_ID_END_SPL;
}

View File

@ -83,7 +83,12 @@ U-Boot Phases
U-Boot boots through the following phases:
TPL
Very early init, as tiny as possible. This loads SPL.
Very early init, as tiny as possible. This loads SPL (or VPL if enabled).
VPL
Optional verification step, which can select one of several SPL binaries,
if A/B verified boot is enabled. Implementation of the VPL logic is
work-in-progress. For now it just boots into SPL.
SPL
Secondary program loader. Sets up SDRAM and loads U-Boot proper. It may also

View File

@ -38,6 +38,7 @@ obj-$(CONFIG_XEN) += xen/
obj-$(CONFIG_$(SPL_)FPGA) += fpga/
ifndef CONFIG_TPL_BUILD
ifndef CONFIG_VPL_BUILD
ifdef CONFIG_SPL_BUILD
obj-$(CONFIG_SPL_CPU) += cpu/
@ -60,6 +61,7 @@ obj-$(CONFIG_SPL_SATA) += ata/ scsi/
obj-$(CONFIG_HAVE_BLOCK_DEVICE) += block/
obj-$(CONFIG_SPL_THERMAL) += thermal/
endif
endif
endif

View File

@ -176,6 +176,8 @@ enum bootstage_id {
BOOTSTAGE_ID_END_TPL,
BOOTSTAGE_ID_START_SPL,
BOOTSTAGE_ID_END_SPL,
BOOTSTAGE_ID_START_VPL,
BOOTSTAGE_ID_END_VPL,
BOOTSTAGE_ID_START_UBOOT_F,
BOOTSTAGE_ID_START_UBOOT_R,
BOOTSTAGE_ID_USB_START,

View File

@ -38,6 +38,8 @@
#define _CONFIG_PREFIX TOOLS_
#elif defined(CONFIG_TPL_BUILD)
#define _CONFIG_PREFIX TPL_
#elif defined(CONFIG_VPL_BUILD)
#define _CONFIG_PREFIX VPL_
#elif defined(CONFIG_SPL_BUILD)
#define _CONFIG_PREFIX SPL_
#else
@ -54,6 +56,7 @@
* CONFIG_FOO if CONFIG_SPL_BUILD is undefined,
* CONFIG_SPL_FOO if CONFIG_SPL_BUILD is defined.
* CONFIG_TPL_FOO if CONFIG_TPL_BUILD is defined.
* CONFIG_VPL_FOO if CONFIG_VPL_BUILD is defined.
*/
#define CONFIG_VAL(option) config_val(option)

View File

@ -62,6 +62,7 @@ static inline bool u_boot_first_phase(void)
enum u_boot_phase {
PHASE_NONE, /* Invalid phase, signifying before U-Boot */
PHASE_TPL, /* Running in TPL */
PHASE_VPL, /* Running in VPL */
PHASE_SPL, /* Running in SPL */
PHASE_BOARD_F, /* Running in U-Boot before relocation */
PHASE_BOARD_R, /* Running in U-Boot after relocation */
@ -114,7 +115,9 @@ static inline enum u_boot_phase spl_phase(void)
{
#ifdef CONFIG_TPL_BUILD
return PHASE_TPL;
#elif CONFIG_SPL_BUILD
#elif defined(CONFIG_VPL_BUILD)
return PHASE_VPL;
#elif defined(CONFIG_SPL_BUILD)
return PHASE_SPL;
#else
DECLARE_GLOBAL_DATA_PTR;
@ -136,10 +139,15 @@ static inline enum u_boot_phase spl_prev_phase(void)
{
#ifdef CONFIG_TPL_BUILD
return PHASE_NONE;
#elif defined(CONFIG_VPL_BUILD)
return PHASE_TPL; /* VPL requires TPL */
#elif defined(CONFIG_SPL_BUILD)
return IS_ENABLED(CONFIG_TPL) ? PHASE_TPL : PHASE_NONE;
return IS_ENABLED(CONFIG_VPL) ? PHASE_VPL :
IS_ENABLED(CONFIG_TPL) ? PHASE_TPL :
PHASE_NONE;
#else
return IS_ENABLED(CONFIG_SPL) ? PHASE_SPL : PHASE_NONE;
return IS_ENABLED(CONFIG_SPL) ? PHASE_SPL :
PHASE_NONE;
#endif
}
@ -152,6 +160,8 @@ static inline enum u_boot_phase spl_prev_phase(void)
static inline enum u_boot_phase spl_next_phase(void)
{
#ifdef CONFIG_TPL_BUILD
return IS_ENABLED(CONFIG_VPL) ? PHASE_VPL : PHASE_SPL;
#elif defined(CONFIG_VPL_BUILD)
return PHASE_SPL;
#else
return PHASE_BOARD_F;
@ -168,6 +178,8 @@ static inline const char *spl_phase_name(enum u_boot_phase phase)
switch (phase) {
case PHASE_TPL:
return "TPL";
case PHASE_VPL:
return "VPL";
case PHASE_SPL:
return "SPL";
case PHASE_BOARD_F:
@ -189,6 +201,8 @@ static inline const char *spl_phase_prefix(enum u_boot_phase phase)
switch (phase) {
case PHASE_TPL:
return "tpl";
case PHASE_VPL:
return "vpl";
case PHASE_SPL:
return "spl";
case PHASE_BOARD_F:
@ -203,6 +217,8 @@ static inline const char *spl_phase_prefix(enum u_boot_phase phase)
#ifdef CONFIG_SPL_BUILD
# ifdef CONFIG_TPL_BUILD
# define SPL_TPL_NAME "TPL"
# elif defined(CONFIG_VPL_BUILD)
# define SPL_TPL_NAME "VPL"
# else
# define SPL_TPL_NAME "SPL"
# endif

View File

@ -322,11 +322,15 @@ endif
ifdef CONFIG_SPL_BUILD
SPL_ := SPL_
ifeq ($(CONFIG_VPL_BUILD),y)
SPL_TPL_ := VPL_
else
ifeq ($(CONFIG_TPL_BUILD),y)
SPL_TPL_ := TPL_
else
SPL_TPL_ := SPL_
endif
endif
else
SPL_ :=
SPL_TPL_ :=

View File

@ -18,6 +18,10 @@ ifeq ($(shell grep -q '^CONFIG_TPL=y' include/config/auto.conf 2>/dev/null && ec
__all: tpl/include/autoconf.mk
endif
ifeq ($(shell grep -q '^CONFIG_VPL=y' include/config/auto.conf 2>/dev/null && echo y),y)
__all: vpl/include/autoconf.mk
endif
include include/config/auto.conf
include scripts/Kbuild.include
@ -85,6 +89,10 @@ tpl/u-boot.cfg: include/config.h FORCE
$(Q)mkdir -p $(dir $@)
$(call cmd,u_boot_cfg,-DCONFIG_SPL_BUILD -DCONFIG_TPL_BUILD)
vpl/u-boot.cfg: include/config.h FORCE
$(Q)mkdir -p $(dir $@)
$(call cmd,u_boot_cfg,-DCONFIG_SPL_BUILD -DCONFIG_VPL_BUILD)
include/autoconf.mk: u-boot.cfg
$(call cmd,autoconf)
@ -96,6 +104,10 @@ tpl/include/autoconf.mk: tpl/u-boot.cfg
$(Q)mkdir -p $(dir $@)
$(call cmd,autoconf)
vpl/include/autoconf.mk: vpl/u-boot.cfg
$(Q)mkdir -p $(dir $@)
$(call cmd,autoconf)
# include/config.h
# Prior to Kconfig, it was generated by mkconfig. Now it is created here.
define filechk_config_h

View File

@ -4,6 +4,9 @@
# ==========================================================================
# Modified for U-Boot
prefix := vpl
src := $(patsubst $(prefix)/%,%,$(obj))
ifeq ($(obj),$(src))
prefix := tpl
src := $(patsubst $(prefix)/%,%,$(obj))
ifeq ($(obj),$(src))
@ -13,6 +16,7 @@ ifeq ($(obj),$(src))
prefix := .
endif
endif
endif
PHONY := __build
__build:

View File

@ -581,16 +581,21 @@ cmd_mkimage = $(objtree)/tools/mkimage $(MKIMAGEFLAGS_$(@F)) -d $< $@ \
# 'u-boot,dm-pre-reloc' property and thus are not needed by SPL. The second
# pass removes various unused properties from the remaining nodes.
# The output is typically a much smaller device tree file.
ifeq ($(CONFIG_VPL_BUILD),y)
fdtgrep_props := -b u-boot,dm-pre-reloc -b u-boot,dm-vpl
else
ifeq ($(CONFIG_TPL_BUILD),y)
fdtgrep_props := -b u-boot,dm-pre-reloc -b u-boot,dm-tpl
else
fdtgrep_props := -b u-boot,dm-pre-reloc -b u-boot,dm-spl
endif
endif
quiet_cmd_fdtgrep = FDTGREP $@
cmd_fdtgrep = $(objtree)/tools/fdtgrep $(fdtgrep_props) -RT $< \
-n /chosen -n /config -O dtb | \
$(objtree)/tools/fdtgrep -r -O dtb - -o $@ \
-P u-boot,dm-pre-reloc -P u-boot,dm-spl -P u-boot,dm-tpl \
-P u-boot,dm-vpl \
$(addprefix -P ,$(subst $\",,$(CONFIG_OF_SPL_REMOVE_PROPS)))
# fdt_rm_props

View File

@ -27,8 +27,16 @@ UBOOTINCLUDE := -I$(obj)/include $(UBOOTINCLUDE)
KBUILD_CPPFLAGS += -DCONFIG_SPL_BUILD
ifeq ($(CONFIG_TPL_BUILD),y)
KBUILD_CPPFLAGS += -DCONFIG_TPL_BUILD
else
ifeq ($(CONFIG_VPL_BUILD),y)
KBUILD_CPPFLAGS += -DCONFIG_VPL_BUILD
endif
endif
ifeq ($(CONFIG_VPL_BUILD),y)
SPL_BIN := u-boot-vpl
SPL_NAME := vpl
else
ifeq ($(CONFIG_TPL_BUILD),y)
SPL_BIN := u-boot-tpl
SPL_NAME := tpl
@ -36,16 +44,21 @@ else
SPL_BIN := u-boot-spl
SPL_NAME := spl
endif
endif
export SPL_NAME
ifdef CONFIG_SPL_BUILD
SPL_ := SPL_
ifeq ($(CONFIG_VPL_BUILD),y)
SPL_TPL_ := VPL_
else
ifeq ($(CONFIG_TPL_BUILD),y)
SPL_TPL_ := TPL_
else
SPL_TPL_ := SPL_
endif
endif
else
SPL_ :=
SPL_TPL_ :=
@ -57,6 +70,9 @@ endif
ifeq ($(obj)$(CONFIG_SUPPORT_TPL),tpl)
$(error You cannot build TPL without enabling CONFIG_SUPPORT_TPL)
endif
ifeq ($(obj)$(CONFIG_SUPPORT_VPL),vpl)
$(error You cannot build VPL without enabling CONFIG_SUPPORT_VPL)
endif
include $(srctree)/config.mk
include $(srctree)/arch/$(ARCH)/Makefile
@ -90,17 +106,12 @@ libs-$(CONFIG_SPL_FRAMEWORK) += common/spl/
endif
libs-y += common/init/
# Special handling for a few options which support SPL/TPL
ifeq ($(CONFIG_TPL_BUILD),y)
libs-$(CONFIG_TPL_LIBCOMMON_SUPPORT) += boot/ common/ cmd/ env/
libs-$(CONFIG_TPL_LIBGENERIC_SUPPORT) += lib/
else
libs-$(CONFIG_SPL_LIBCOMMON_SUPPORT) += boot/ common/ cmd/ env/
libs-$(CONFIG_SPL_LIBGENERIC_SUPPORT) += lib/
# Special handling for a few options which support SPL/TPL/VPL
libs-$(CONFIG_$(SPL_TPL_)LIBCOMMON_SUPPORT) += boot/ common/ cmd/ env/
libs-$(CONFIG_$(SPL_TPL_)LIBGENERIC_SUPPORT) += lib/
ifdef CONFIG_SPL_FRAMEWORK
libs-$(CONFIG_PARTITIONS) += disk/
endif
endif
libs-y += drivers/
libs-$(CONFIG_SPL_USB_GADGET) += drivers/usb/dwc3/
@ -182,7 +193,7 @@ LDPPFLAGS += \
sed -ne 's/GNU ld version \([0-9][0-9]*\)\.\([0-9][0-9]*\).*/-DLD_MAJOR=\1 -DLD_MINOR=\2/p')
# Turn various CONFIG symbols into IMAGE symbols for easy reuse of
# the scripts between SPL and TPL.
# the scripts between SPL, TPL and VPL.
ifneq ($(CONFIG_$(SPL_TPL_)MAX_SIZE),)
LDPPFLAGS += -DIMAGE_MAX_SIZE=$(CONFIG_$(SPL_TPL_)MAX_SIZE)
endif
@ -264,6 +275,7 @@ ifeq ($(CONFIG_SYS_SOC),"at91")
INPUTS-y += $(obj)/boot.bin
endif
ifndef CONFIG_VPL_BUILD
ifdef CONFIG_TPL_BUILD
INPUTS-$(CONFIG_TPL_X86_16BIT_INIT) += $(obj)/u-boot-x86-start16-tpl.bin \
$(obj)/u-boot-x86-reset16-tpl.bin
@ -271,6 +283,7 @@ else
INPUTS-$(CONFIG_SPL_X86_16BIT_INIT) += $(obj)/u-boot-x86-start16-spl.bin \
$(obj)/u-boot-x86-reset16-spl.bin
endif
endif
INPUTS-$(CONFIG_ARCH_ZYNQ) += $(obj)/boot.bin
INPUTS-$(CONFIG_ARCH_ZYNQMP) += $(obj)/boot.bin
@ -307,7 +320,7 @@ endif
ifneq ($(build_dtb),)
$(obj)/$(SPL_BIN)-dtb.bin: $(obj)/$(SPL_BIN)-nodtb.bin \
$(if $(CONFIG_SPL_SEPARATE_BSS),,$(obj)/$(SPL_BIN)-pad.bin) \
$(if $(CONFIG_$(SPL_TPL_)SEPARATE_BSS),,$(obj)/$(SPL_BIN)-pad.bin) \
$(FINAL_DTB_CONTAINER) FORCE
$(call if_changed,cat)
@ -398,7 +411,7 @@ LDFLAGS_$(SPL_BIN) += $(call ld-option, --no-dynamic-linker)
LDFLAGS_$(SPL_BIN) += --build-id=none
# Pick the best-match (i.e. SPL_TEXT_BASE for SPL, TPL_TEXT_BASE for TPL)
# Pick the best match (e.g. SPL_TEXT_BASE for SPL, TPL_TEXT_BASE for TPL)
ifneq ($(CONFIG_$(SPL_TPL_)TEXT_BASE),)
LDFLAGS_$(SPL_BIN) += -Ttext $(CONFIG_$(SPL_TPL_)TEXT_BASE)
endif