Introduce Verifying Program Loader (VPL)
authorSimon Glass <sjg@chromium.org>
Sat, 30 Apr 2022 06:56:52 +0000 (00:56 -0600)
committerTom Rini <trini@konsulko.com>
Mon, 2 May 2022 13:58:13 +0000 (09:58 -0400)
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>
13 files changed:
Makefile
common/spl/Kconfig
common/spl/spl.c
doc/develop/spl.rst
drivers/Makefile
include/bootstage.h
include/linux/kconfig.h
include/spl.h
scripts/Kbuild.include
scripts/Makefile.autoconf
scripts/Makefile.build
scripts/Makefile.lib
scripts/Makefile.spl

index 82c35a9..ea80f00 100644 (file)
--- a/Makefile
+++ b/Makefile
@@ -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
index ac61b25..be09866 100644 (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
index c9750ee..c8c463f 100644 (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;
 }
index 1059b2f..aec7b56 100644 (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
index 4e7cf28..67c8af7 100644 (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/
@@ -62,6 +63,7 @@ obj-$(CONFIG_SPL_THERMAL) += thermal/
 
 endif
 endif
+endif
 
 ifdef CONFIG_TPL_BUILD
 
index 99a334a..bca9438 100644 (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,
index d20da61..2bc704e 100644 (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)
 
index 6134aba..83ac583 100644 (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
index 09506cb..9c14310 100644 (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_ :=
index 0b3ffa0..3fa4d50 100644 (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
index 5df8f61..3b8c9d8 100644 (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:
index 2ff39d3..3db2550 100644 (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
index 30672a6..f047d4e 100644 (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