[PATCH 0/4] vpl: Introduce a verifying program loader

U-Boot provides a verified-boot feature based around FIT, but there is no standard way of implementing it for a board. At present the various required pieces must be built up separately, to produce a working implementation. In particular, there is no built-in support for selecting A/B boot or recovery mode.
This series introduces VPL, a verified program loader. Its purpose is to run the verified-boot process and decide which SPL binary should be run. Adding VPL into the boot flow provides a standard way of implementing verified boot. So far, only the phase itself is added. More work is needed to add logic to the phase, based on continuing discussions about how best to standardise this feature.
Simon Glass (4): doc: Convert SPL documentation to ReST doc: Expand SPL docs to explain the phase and config binman: Add VPL support Introduce Verifying Program Loader (VPL)
common/Kconfig | 67 ++++++++ common/spl/Kconfig | 168 ++++++++++++++++++++- common/spl/spl.c | 25 ++- doc/develop/index.rst | 1 + doc/{README.SPL => develop/spl.rst} | 99 +++++++----- include/bootstage.h | 2 + include/linux/kconfig.h | 3 + include/spl.h | 20 ++- lib/Kconfig | 54 +++++++ scripts/Kbuild.include | 4 + scripts/Makefile.build | 4 + tools/binman/etype/u_boot_vpl.py | 42 ++++++ tools/binman/etype/u_boot_vpl_bss_pad.py | 44 ++++++ tools/binman/etype/u_boot_vpl_dtb.py | 28 ++++ tools/binman/etype/u_boot_vpl_expanded.py | 45 ++++++ tools/binman/etype/u_boot_vpl_nodtb.py | 42 ++++++ tools/binman/ftest.py | 110 +++++++++++--- tools/binman/state.py | 3 +- tools/binman/test/082_fdt_update_all.dts | 2 + tools/binman/test/201_u_boot_vpl.dts | 11 ++ tools/binman/test/202_u_boot_vpl_nodtb.dts | 13 ++ tools/binman/test/203_fdt_incl_vpl.dts | 13 ++ tools/binman/test/204_vpl_bss_pad.dts | 17 +++ 23 files changed, 748 insertions(+), 69 deletions(-) rename doc/{README.SPL => develop/spl.rst} (61%) create mode 100644 tools/binman/etype/u_boot_vpl.py create mode 100644 tools/binman/etype/u_boot_vpl_bss_pad.py create mode 100644 tools/binman/etype/u_boot_vpl_dtb.py create mode 100644 tools/binman/etype/u_boot_vpl_expanded.py create mode 100644 tools/binman/etype/u_boot_vpl_nodtb.py create mode 100644 tools/binman/test/201_u_boot_vpl.dts create mode 100644 tools/binman/test/202_u_boot_vpl_nodtb.dts create mode 100644 tools/binman/test/203_fdt_incl_vpl.dts create mode 100644 tools/binman/test/204_vpl_bss_pad.dts

Move this documentation over to .rst format.
Signed-off-by: Simon Glass sjg@chromium.org ---
doc/develop/index.rst | 1 + doc/{README.SPL => develop/spl.rst} | 36 +++++++++++++++-------------- 2 files changed, 20 insertions(+), 17 deletions(-) rename doc/{README.SPL => develop/spl.rst} (87%)
diff --git a/doc/develop/index.rst b/doc/develop/index.rst index 3edffbc6373..79f345c9331 100644 --- a/doc/develop/index.rst +++ b/doc/develop/index.rst @@ -14,6 +14,7 @@ Implementation global_data logging menus + spl uefi/index version
diff --git a/doc/README.SPL b/doc/develop/spl.rst similarity index 87% rename from doc/README.SPL rename to doc/develop/spl.rst index 2beb6d8f11b..1165f95335f 100644 --- a/doc/README.SPL +++ b/doc/develop/spl.rst @@ -20,19 +20,19 @@ u-boot-spl.map. A config option named CONFIG_SPL_BUILD is enabled by Kconfig for SPL. Source files can therefore be compiled for SPL with different settings.
-For example: +For example::
-ifeq ($(CONFIG_SPL_BUILD),y) -obj-y += board_spl.o -else -obj-y += board.o -endif + ifeq ($(CONFIG_SPL_BUILD),y) + obj-y += board_spl.o + else + obj-y += board.o + endif
-obj-$(CONFIG_SPL_BUILD) += foo.o + obj-$(CONFIG_SPL_BUILD) += foo.o
-#ifdef CONFIG_SPL_BUILD - foo(); -#endif + #ifdef CONFIG_SPL_BUILD + foo(); + #endif
The building of SPL images can be enabled by CONFIG_SPL option in Kconfig. @@ -71,11 +71,13 @@ Device tree The U-Boot device tree is filtered by the fdtgrep tools during the build process to generate a much smaller device tree used in SPL (spl/u-boot-spl.dtb) with: + - the mandatory nodes (/alias, /chosen, /config) - the nodes with one pre-relocation property: 'u-boot,dm-pre-reloc' or 'u-boot,dm-spl'
fdtgrep is also used to remove: + - the properties defined in CONFIG_OF_SPL_REMOVE_PROPS - all the pre-relocation properties ('u-boot,dm-pre-reloc', 'u-boot,dm-spl' and 'u-boot,dm-tpl') @@ -98,14 +100,14 @@ stack usage at various points in run sequence of SPL. The -fstack-usage option to gcc will produce '.su' files (such as arch/arm/cpu/armv7/syslib.su) that will give stack usage information and cflow can construct program flow.
-Must have gcc 4.6 or later, which supports -fstack-usage +Must have gcc 4.6 or later, which supports -fstack-usage:
-1) Build normally -2) Perform the following shell command to generate a list of C files used in -SPL: -$ find spl -name '*.su' | sed -e 's:^spl/::' -e 's:[.]su$:.c:' > used-spl.list -3) Execute cflow: -$ cflow --main=board_init_r `cat used-spl.list` 2>&1 | $PAGER +#. Build normally +#. Perform the following shell command to generate a list of C files used in + SPL: +#. `find spl -name '*.su' | sed -e 's:^spl/::' -e 's:[.]su$:.c:' > used-spl.list` +#. Execute cflow: + `$ cflow --main=board_init_r $(cat used-spl.list) 2>&1 | $PAGER`
cflow will spit out a number of warnings as it does not parse the config files and picks functions based on #ifdef. Parsing the '.i'

Add a bit more information about how to use SPL.
Signed-off-by: Simon Glass sjg@chromium.org ---
doc/develop/spl.rst | 59 +++++++++++++++++++++++++++------------------ 1 file changed, 36 insertions(+), 23 deletions(-)
diff --git a/doc/develop/spl.rst b/doc/develop/spl.rst index 1165f95335f..c2a29a8c0a4 100644 --- a/doc/develop/spl.rst +++ b/doc/develop/spl.rst @@ -42,29 +42,42 @@ configured by defining CONFIG_SPL_TEXT_BASE. The linker script has to be defined with CONFIG_SPL_LDSCRIPT.
To support generic U-Boot libraries and drivers in the SPL binary one can -optionally define CONFIG_SPL_XXX_SUPPORT. Currently following options -are supported: - -CONFIG_SPL_LIBCOMMON_SUPPORT (common/libcommon.o) -CONFIG_SPL_LIBDISK_SUPPORT (disk/libdisk.o) -CONFIG_SPL_I2C_SUPPORT (drivers/i2c/libi2c.o) -CONFIG_SPL_GPIO_SUPPORT (drivers/gpio/libgpio.o) -CONFIG_SPL_MMC_SUPPORT (drivers/mmc/libmmc.o) -CONFIG_SPL_SERIAL_SUPPORT (drivers/serial/libserial.o) -CONFIG_SPL_SPI_FLASH_SUPPORT (drivers/mtd/spi/libspi_flash.o) -CONFIG_SPL_SPI_SUPPORT (drivers/spi/libspi.o) -CONFIG_SPL_FS_FAT (fs/fat/libfat.o) -CONFIG_SPL_FS_EXT4 -CONFIG_SPL_LIBGENERIC_SUPPORT (lib/libgeneric.o) -CONFIG_SPL_POWER_SUPPORT (drivers/power/libpower.o) -CONFIG_SPL_NAND_SUPPORT (drivers/mtd/nand/raw/libnand.o) -CONFIG_SPL_DRIVERS_MISC_SUPPORT (drivers/misc) -CONFIG_SPL_DMA (drivers/dma/libdma.o) -CONFIG_SPL_POST_MEM_SUPPORT (post/drivers/memory.o) -CONFIG_SPL_NAND_LOAD (drivers/mtd/nand/raw/nand_spl_load.o) -CONFIG_SPL_SPI_LOAD (drivers/mtd/spi/spi_spl_load.o) -CONFIG_SPL_RAM_DEVICE (common/spl/spl.c) -CONFIG_SPL_WATCHDOG_SUPPORT (drivers/watchdog/libwatchdog.o) +optionally define CONFIG_SPL_XXX_SUPPORT (or CONFIG_SPL_XXX_SUPPORT for older +options). + +Adding SPL-specific code +------------------------ + +To check whether a feature is enabled, use CONFIG_IS_ENABLED():: + + if (CONFIG_IS_ENABLED(CLK)) + ... + +This checks CONFIG_CLK for the main build, CONFIG_SPL_CLK for the SPL build, +CONFIG_TPL_CLK for the TPL build, etc. + +U-Boot Phases +------------- + +U-Boot boots through the following phases: + +TPL + Very early init, as tiny as possible. This loads SPL. + +SPL + Secondary program loader. Sets up SDRAM and loads U-Boot proper. It may also + load other firmware components. + +U-Boot + U-Boot proper, containing the command line and boot logic. + + +Checking the boot phase +----------------------- + +Use `spl_phase()` to find the current U-Boot phase, e.g. `PHASE_SPL`. You can +also find the previous and next phase and get the phase name. +
Device tree -----------

Add support for U-Boot's Verifying Program Loader phase.
Signed-off-by: Simon Glass sjg@chromium.org ---
tools/binman/etype/u_boot_vpl.py | 42 ++++++++ tools/binman/etype/u_boot_vpl_bss_pad.py | 44 +++++++++ tools/binman/etype/u_boot_vpl_dtb.py | 28 ++++++ tools/binman/etype/u_boot_vpl_expanded.py | 45 +++++++++ tools/binman/etype/u_boot_vpl_nodtb.py | 42 ++++++++ tools/binman/ftest.py | 110 +++++++++++++++++---- tools/binman/state.py | 3 +- tools/binman/test/082_fdt_update_all.dts | 2 + tools/binman/test/201_u_boot_vpl.dts | 11 +++ tools/binman/test/202_u_boot_vpl_nodtb.dts | 13 +++ tools/binman/test/203_fdt_incl_vpl.dts | 13 +++ tools/binman/test/204_vpl_bss_pad.dts | 17 ++++ 12 files changed, 348 insertions(+), 22 deletions(-) create mode 100644 tools/binman/etype/u_boot_vpl.py create mode 100644 tools/binman/etype/u_boot_vpl_bss_pad.py create mode 100644 tools/binman/etype/u_boot_vpl_dtb.py create mode 100644 tools/binman/etype/u_boot_vpl_expanded.py create mode 100644 tools/binman/etype/u_boot_vpl_nodtb.py create mode 100644 tools/binman/test/201_u_boot_vpl.dts create mode 100644 tools/binman/test/202_u_boot_vpl_nodtb.dts create mode 100644 tools/binman/test/203_fdt_incl_vpl.dts create mode 100644 tools/binman/test/204_vpl_bss_pad.dts
diff --git a/tools/binman/etype/u_boot_vpl.py b/tools/binman/etype/u_boot_vpl.py new file mode 100644 index 00000000000..9daaca4f6fd --- /dev/null +++ b/tools/binman/etype/u_boot_vpl.py @@ -0,0 +1,42 @@ +# SPDX-License-Identifier: GPL-2.0+ +# Copyright (c) 2016 Google, Inc +# Written by Simon Glass sjg@chromium.org +# +# Entry-type module for vpl/u-boot-vpl.bin +# + +from binman import elf +from binman.entry import Entry +from binman.etype.blob import Entry_blob + +class Entry_u_boot_vpl(Entry_blob): + """U-Boot VPL binary + + Properties / Entry arguments: + - filename: Filename of u-boot-vpl.bin (default 'vpl/u-boot-vpl.bin') + + This is the U-Boot VPL (Verifying Program Loader) binary. This is a small + binary which loads before SPL, typically into on-chip SRAM. It is + responsible for locating, loading and jumping to SPL, the next-stage + loader. Note that VPL is not relocatable so must be loaded to the correct + address in SRAM, or written to run from the correct address if direct + flash execution is possible (e.g. on x86 devices). + + SPL can access binman symbols at runtime. See: + + 'Access to binman entry offsets at run time (symbols)' + + in the binman README for more information. + + The ELF file 'vpl/u-boot-vpl' must also be available for this to work, since + binman uses that to look up symbols to write into the VPL binary. + """ + def __init__(self, section, etype, node): + super().__init__(section, etype, node) + self.elf_fname = 'vpl/u-boot-vpl' + + def GetDefaultFilename(self): + return 'vpl/u-boot-vpl.bin' + + def WriteSymbols(self, section): + elf.LookupAndWriteSymbols(self.elf_fname, self, section.GetImage()) diff --git a/tools/binman/etype/u_boot_vpl_bss_pad.py b/tools/binman/etype/u_boot_vpl_bss_pad.py new file mode 100644 index 00000000000..073833b3d0d --- /dev/null +++ b/tools/binman/etype/u_boot_vpl_bss_pad.py @@ -0,0 +1,44 @@ +# SPDX-License-Identifier: GPL-2.0+ +# Copyright 2021 Google LLC +# Written by Simon Glass sjg@chromium.org +# +# Entry-type module for BSS padding for vpl/u-boot-vpl.bin. This padding +# can be added after the VPL binary to ensure that anything concatenated +# to it will appear to VPL to be at the end of BSS rather than the start. +# + +from binman import elf +from binman.entry import Entry +from binman.etype.blob import Entry_blob +from patman import tools + +class Entry_u_boot_vpl_bss_pad(Entry_blob): + """U-Boot VPL binary padded with a BSS region + + Properties / Entry arguments: + None + + This holds the padding added after the VPL binary to cover the BSS (Block + Started by Symbol) region. This region holds the various variables used by + VPL. It is set to 0 by VPL when it starts up. If you want to append data to + the VPL image (such as a device tree file), you must pad out the BSS region + to avoid the data overlapping with U-Boot variables. This entry is useful in + that case. It automatically pads out the entry size to cover both the code, + data and BSS. + + The contents of this entry will a certain number of zero bytes, determined + by __bss_size + + The ELF file 'vpl/u-boot-vpl' must also be available for this to work, since + binman uses that to look up the BSS address. + """ + def __init__(self, section, etype, node): + super().__init__(section, etype, node) + + def ObtainContents(self): + fname = tools.GetInputFilename('vpl/u-boot-vpl') + bss_size = elf.GetSymbolAddress(fname, '__bss_size') + if not bss_size: + self.Raise('Expected __bss_size symbol in vpl/u-boot-vpl') + self.SetContents(tools.GetBytes(0, bss_size)) + return True diff --git a/tools/binman/etype/u_boot_vpl_dtb.py b/tools/binman/etype/u_boot_vpl_dtb.py new file mode 100644 index 00000000000..f6253bf2431 --- /dev/null +++ b/tools/binman/etype/u_boot_vpl_dtb.py @@ -0,0 +1,28 @@ +# SPDX-License-Identifier: GPL-2.0+ +# Copyright (c) 2016 Google, Inc +# Written by Simon Glass sjg@chromium.org +# +# Entry-type module for U-Boot device tree in VPL (Verifying Program Loader) +# + +from binman.entry import Entry +from binman.etype.blob_dtb import Entry_blob_dtb + +class Entry_u_boot_vpl_dtb(Entry_blob_dtb): + """U-Boot VPL device tree + + Properties / Entry arguments: + - filename: Filename of u-boot.dtb (default 'vpl/u-boot-vpl.dtb') + + This is the VPL device tree, containing configuration information for + VPL. VPL needs this to know what devices are present and which drivers + to activate. + """ + def __init__(self, section, etype, node): + super().__init__(section, etype, node) + + def GetDefaultFilename(self): + return 'vpl/u-boot-vpl.dtb' + + def GetFdtEtype(self): + return 'u-boot-vpl-dtb' diff --git a/tools/binman/etype/u_boot_vpl_expanded.py b/tools/binman/etype/u_boot_vpl_expanded.py new file mode 100644 index 00000000000..945a90f856e --- /dev/null +++ b/tools/binman/etype/u_boot_vpl_expanded.py @@ -0,0 +1,45 @@ +# SPDX-License-Identifier: GPL-2.0+ +# Copyright 2021 Google LLC +# Written by Simon Glass sjg@chromium.org +# +# Entry-type module for expanded U-Boot VPL binary +# + +from patman import tout + +from binman import state +from binman.etype.blob_phase import Entry_blob_phase + +class Entry_u_boot_vpl_expanded(Entry_blob_phase): + """U-Boot VPL flat binary broken out into its component parts + + Properties / Entry arguments: + - vpl-dtb: Controls whether this entry is selected (set to 'y' or '1' to + select) + + This is a section containing the U-Boot binary, BSS padding if needed and a + devicetree. Using this entry type automatically creates this section, with + the following entries in it: + + u-boot-vpl-nodtb + u-boot-vpl-bss-pad + u-boot-dtb + + Having the devicetree separate allows binman to update it in the final + image, so that the entries positions are provided to the running U-Boot. + + This entry is selected based on the value of the 'vpl-dtb' entryarg. If + this is non-empty (and not 'n' or '0') then this expanded entry is selected. + """ + def __init__(self, section, etype, node): + bss_pad = state.GetEntryArgBool('vpl-bss-pad') + super().__init__(section, etype, node, 'u-boot-vpl', 'u-boot-vpl-dtb', + bss_pad) + + @classmethod + def UseExpanded(cls, node, etype, new_etype): + val = state.GetEntryArgBool('vpl-dtb') + tout.DoOutput(tout.INFO if val else tout.DETAIL, + "Node '%s': etype '%s': %s %sselected" % + (node.path, etype, new_etype, '' if val else 'not ')) + return val diff --git a/tools/binman/etype/u_boot_vpl_nodtb.py b/tools/binman/etype/u_boot_vpl_nodtb.py new file mode 100644 index 00000000000..25c966cf342 --- /dev/null +++ b/tools/binman/etype/u_boot_vpl_nodtb.py @@ -0,0 +1,42 @@ +# SPDX-License-Identifier: GPL-2.0+ +# Copyright (c) 2016 Google, Inc +# Written by Simon Glass sjg@chromium.org +# +# Entry-type module for 'u-boot-vpl-nodtb.bin' +# + +from binman import elf +from binman.entry import Entry +from binman.etype.blob import Entry_blob + +class Entry_u_boot_vpl_nodtb(Entry_blob): + """VPL binary without device tree appended + + Properties / Entry arguments: + - filename: Filename to include (default 'vpl/u-boot-vpl-nodtb.bin') + + This is the U-Boot VPL binary, It does not include a device tree blob at + the end of it so may not be able to work without it, assuming VPL needs + a device tree to operate on your platform. You can add a u_boot_vpl_dtb + entry after this one, or use a u_boot_vpl entry instead, which normally + expands to a section containing u-boot-vpl-dtb, u-boot-vpl-bss-pad and + u-boot-vpl-dtb + + VPL can access binman symbols at runtime. See: + + 'Access to binman entry offsets at run time (symbols)' + + in the binman README for more information. + + The ELF file 'vpl/u-boot-vpl' must also be available for this to work, since + binman uses that to look up symbols to write into the VPL binary. + """ + def __init__(self, section, etype, node): + super().__init__(section, etype, node) + self.elf_fname = 'vpl/u-boot-vpl' + + def GetDefaultFilename(self): + return 'vpl/u-boot-vpl-nodtb.bin' + + def WriteSymbols(self, section): + elf.LookupAndWriteSymbols(self.elf_fname, self, section.GetImage()) diff --git a/tools/binman/ftest.py b/tools/binman/ftest.py index f36823f51be..5e7839bb630 100644 --- a/tools/binman/ftest.py +++ b/tools/binman/ftest.py @@ -40,12 +40,14 @@ U_BOOT_DATA = b'1234' U_BOOT_IMG_DATA = b'img' U_BOOT_SPL_DATA = b'56780123456789abcdefghi' U_BOOT_TPL_DATA = b'tpl9876543210fedcbazyw' +U_BOOT_VPL_DATA = b'vpl76543210fedcbazywxyz_' BLOB_DATA = b'89' ME_DATA = b'0abcd' VGA_DATA = b'vga' U_BOOT_DTB_DATA = b'udtb' U_BOOT_SPL_DTB_DATA = b'spldtb' U_BOOT_TPL_DTB_DATA = b'tpldtb' +U_BOOT_VPL_DTB_DATA = b'vpldtb' X86_START16_DATA = b'start16' X86_START16_SPL_DATA = b'start16spl' X86_START16_TPL_DATA = b'start16tpl' @@ -56,6 +58,7 @@ PPC_MPC85XX_BR_DATA = b'ppcmpc85xxbr' U_BOOT_NODTB_DATA = b'nodtb with microcode pointer somewhere in here' U_BOOT_SPL_NODTB_DATA = b'splnodtb with microcode pointer somewhere in here' U_BOOT_TPL_NODTB_DATA = b'tplnodtb with microcode pointer somewhere in here' +U_BOOT_VPL_NODTB_DATA = b'vplnodtb' FSP_DATA = b'fsp' CMC_DATA = b'cmc' VBT_DATA = b'vbt' @@ -125,6 +128,7 @@ class TestFunctional(unittest.TestCase): TestFunctional._MakeInputFile('u-boot.img', U_BOOT_IMG_DATA) TestFunctional._MakeInputFile('spl/u-boot-spl.bin', U_BOOT_SPL_DATA) TestFunctional._MakeInputFile('tpl/u-boot-tpl.bin', U_BOOT_TPL_DATA) + TestFunctional._MakeInputFile('vpl/u-boot-vpl.bin', U_BOOT_VPL_DATA) TestFunctional._MakeInputFile('blobfile', BLOB_DATA) TestFunctional._MakeInputFile('me.bin', ME_DATA) TestFunctional._MakeInputFile('vga.bin', VGA_DATA) @@ -150,6 +154,8 @@ class TestFunctional(unittest.TestCase): U_BOOT_SPL_NODTB_DATA) TestFunctional._MakeInputFile('tpl/u-boot-tpl-nodtb.bin', U_BOOT_TPL_NODTB_DATA) + TestFunctional._MakeInputFile('vpl/u-boot-vpl-nodtb.bin', + U_BOOT_VPL_NODTB_DATA) TestFunctional._MakeInputFile('fsp.bin', FSP_DATA) TestFunctional._MakeInputFile('cmc.bin', CMC_DATA) TestFunctional._MakeInputFile('vbt.bin', VBT_DATA) @@ -271,6 +277,7 @@ class TestFunctional(unittest.TestCase): TestFunctional._MakeInputFile('u-boot.dtb', U_BOOT_DTB_DATA) TestFunctional._MakeInputFile('spl/u-boot-spl.dtb', U_BOOT_SPL_DTB_DATA) TestFunctional._MakeInputFile('tpl/u-boot-tpl.dtb', U_BOOT_TPL_DTB_DATA) + TestFunctional._MakeInputFile('vpl/u-boot-vpl.dtb', U_BOOT_VPL_DTB_DATA)
def _RunBinman(self, *args, **kwargs): """Run binman using the command line @@ -383,8 +390,8 @@ class TestFunctional(unittest.TestCase): shutil.rmtree(tmpdir) return data
- def _GetDtbContentsForSplTpl(self, dtb_data, name): - """Create a version of the main DTB for SPL or SPL + def _GetDtbContentsForSpls(self, dtb_data, name): + """Create a version of the main DTB for SPL / TPL / VPL
For testing we don't actually have different versions of the DTB. With U-Boot we normally run fdtgrep to remove unwanted nodes, but for tests @@ -452,11 +459,11 @@ class TestFunctional(unittest.TestCase):
# For testing purposes, make a copy of the DT for SPL and TPL. Add # a node indicating which it is, so aid verification. - for name in ['spl', 'tpl']: + for name in ['spl', 'tpl', 'vpl']: dtb_fname = '%s/u-boot-%s.dtb' % (name, name) outfile = os.path.join(self._indir, dtb_fname) TestFunctional._MakeInputFile(dtb_fname, - self._GetDtbContentsForSplTpl(dtb_data, name)) + self._GetDtbContentsForSpls(dtb_data, name))
try: retcode = self._DoTestFile(fname, map=map, update_dtb=update_dtb, @@ -561,6 +568,16 @@ class TestFunctional(unittest.TestCase): TestFunctional._MakeInputFile('tpl/u-boot-tpl', tools.ReadFile(cls.ElfTestFile(src_fname)))
+ @classmethod + def _SetupVplElf(cls, src_fname='bss_data'): + """Set up an ELF file with a '_dt_ucode_base_size' symbol + + Args: + Filename of ELF file to use as VPL + """ + TestFunctional._MakeInputFile('vpl/u-boot-vpl', + tools.ReadFile(cls.ElfTestFile(src_fname))) + @classmethod def _SetupDescriptor(cls): with open(cls.TestFile('descriptor.bin'), 'rb') as fd: @@ -1830,21 +1847,24 @@ class TestFunctional(unittest.TestCase): data = self._DoReadFileRealDtb('082_fdt_update_all.dts')
base_expected = { - 'section:image-pos': 0, - 'u-boot-tpl-dtb:size': 513, - 'u-boot-spl-dtb:size': 513, - 'u-boot-spl-dtb:offset': 493, - 'image-pos': 0, - 'section/u-boot-dtb:image-pos': 0, - 'u-boot-spl-dtb:image-pos': 493, - 'section/u-boot-dtb:size': 493, - 'u-boot-tpl-dtb:image-pos': 1006, - 'section/u-boot-dtb:offset': 0, - 'section:size': 493, 'offset': 0, + 'image-pos': 0, + 'size': 2320, 'section:offset': 0, - 'u-boot-tpl-dtb:offset': 1006, - 'size': 1519 + 'section:image-pos': 0, + 'section:size': 565, + 'section/u-boot-dtb:offset': 0, + 'section/u-boot-dtb:image-pos': 0, + 'section/u-boot-dtb:size': 565, + 'u-boot-spl-dtb:offset': 565, + 'u-boot-spl-dtb:image-pos': 565, + 'u-boot-spl-dtb:size': 585, + 'u-boot-tpl-dtb:offset': 1150, + 'u-boot-tpl-dtb:image-pos': 1150, + 'u-boot-tpl-dtb:size': 585, + 'u-boot-vpl-dtb:image-pos': 1735, + 'u-boot-vpl-dtb:offset': 1735, + 'u-boot-vpl-dtb:size': 585, }
# We expect three device-tree files in the output, one after the other. @@ -1852,11 +1872,12 @@ class TestFunctional(unittest.TestCase): # and 'tpl' in the TPL tree, to make sure they are distinct from the # main U-Boot tree. All three should have the same postions and offset. start = 0 - for item in ['', 'spl', 'tpl']: + self.maxDiff = None + for item in ['', 'spl', 'tpl', 'vpl']: dtb = fdt.Fdt.FromData(data[start:]) dtb.Scan() props = self._GetPropTree(dtb, BASE_DTB_PROPS + REPACK_DTB_PROPS + - ['spl', 'tpl']) + ['spl', 'tpl', 'vpl']) expected = dict(base_expected) if item: expected[item] = 0 @@ -1876,7 +1897,7 @@ class TestFunctional(unittest.TestCase): # over to the expected place. start = 0 for fname in ['u-boot.dtb.out', 'spl/u-boot-spl.dtb.out', - 'tpl/u-boot-tpl.dtb.out']: + 'tpl/u-boot-tpl.dtb.out', 'vpl/u-boot-vpl.dtb.out']: dtb = fdt.Fdt.FromData(data[start:]) size = dtb._fdt_obj.totalsize() pathname = tools.GetOutputFilename(os.path.split(fname)[1]) @@ -1884,7 +1905,7 @@ class TestFunctional(unittest.TestCase): name = os.path.split(fname)[0]
if name: - orig_indata = self._GetDtbContentsForSplTpl(dtb_data, name) + orig_indata = self._GetDtbContentsForSpls(dtb_data, name) else: orig_indata = dtb_data self.assertNotEqual(outdata, orig_indata, @@ -4535,5 +4556,52 @@ class TestFunctional(unittest.TestCase): expected += tools.GetBytes(0, 88 - len(expected)) + U_BOOT_NODTB_DATA self.assertEqual(expected, data)
+ def testVpl(self): + """Test that an image with VPL and its device tree can be created""" + # ELF file with a '__bss_size' symbol + self._SetupVplElf() + data = self._DoReadFile('201_u_boot_vpl.dts') + self.assertEqual(U_BOOT_VPL_DATA + U_BOOT_VPL_DTB_DATA, data) + + def testVplNoDtb(self): + """Test that an image with vpl/u-boot-vpl-nodtb.bin can be created""" + self._SetupVplElf() + data = self._DoReadFile('202_u_boot_vpl_nodtb.dts') + self.assertEqual(U_BOOT_VPL_NODTB_DATA, + data[:len(U_BOOT_VPL_NODTB_DATA)]) + + def testExpandedVpl(self): + """Test that an expanded entry type is selected for TPL when needed""" + self._SetupVplElf() + + entry_args = { + 'vpl-bss-pad': 'y', + 'vpl-dtb': 'y', + } + self._DoReadFileDtb('203_fdt_incl_vpl.dts', use_expanded=True, + entry_args=entry_args) + image = control.images['image'] + entries = image.GetEntries() + self.assertEqual(1, len(entries)) + + # We only have u-boot-vpl, which be expanded + self.assertIn('u-boot-vpl', entries) + entry = entries['u-boot-vpl'] + self.assertEqual('u-boot-vpl-expanded', entry.etype) + subent = entry.GetEntries() + self.assertEqual(3, len(subent)) + self.assertIn('u-boot-vpl-nodtb', subent) + self.assertIn('u-boot-vpl-bss-pad', subent) + self.assertIn('u-boot-vpl-dtb', subent) + + def testVplBssPadMissing(self): + """Test that a missing symbol is detected""" + self._SetupVplElf('u_boot_ucode_ptr') + with self.assertRaises(ValueError) as e: + self._DoReadFile('204_vpl_bss_pad.dts') + self.assertIn('Expected __bss_size symbol in vpl/u-boot-vpl', + str(e.exception)) + + if __name__ == "__main__": unittest.main() diff --git a/tools/binman/state.py b/tools/binman/state.py index dfb17604554..e4a3abd2805 100644 --- a/tools/binman/state.py +++ b/tools/binman/state.py @@ -17,6 +17,7 @@ from patman import tout DTB_TYPE_FNAME = { 'u-boot-spl-dtb': 'spl/u-boot-spl.dtb', 'u-boot-tpl-dtb': 'tpl/u-boot-tpl.dtb', + 'u-boot-vpl-dtb': 'vpl/u-boot-vpl.dtb', }
# Records the device-tree files known to binman, keyed by entry type (e.g. @@ -263,7 +264,7 @@ def GetAllFdts(): """Yield all device tree files being used by binman
Yields: - Device trees being used (U-Boot proper, SPL, TPL) + Device trees being used (U-Boot proper, SPL, TPL, VPL) """ if main_dtb: yield main_dtb diff --git a/tools/binman/test/082_fdt_update_all.dts b/tools/binman/test/082_fdt_update_all.dts index 284975cc289..1aea56989f0 100644 --- a/tools/binman/test/082_fdt_update_all.dts +++ b/tools/binman/test/082_fdt_update_all.dts @@ -14,5 +14,7 @@ }; u-boot-tpl-dtb { }; + u-boot-vpl-dtb { + }; }; }; diff --git a/tools/binman/test/201_u_boot_vpl.dts b/tools/binman/test/201_u_boot_vpl.dts new file mode 100644 index 00000000000..a3a281a91e0 --- /dev/null +++ b/tools/binman/test/201_u_boot_vpl.dts @@ -0,0 +1,11 @@ +// SPDX-License-Identifier: GPL-2.0+ +/dts-v1/; + +/ { + binman { + u-boot-vpl { + }; + u-boot-vpl-dtb { + }; + }; +}; diff --git a/tools/binman/test/202_u_boot_vpl_nodtb.dts b/tools/binman/test/202_u_boot_vpl_nodtb.dts new file mode 100644 index 00000000000..055016badd5 --- /dev/null +++ b/tools/binman/test/202_u_boot_vpl_nodtb.dts @@ -0,0 +1,13 @@ +// SPDX-License-Identifier: GPL-2.0+ + +/dts-v1/; + +/ { + #address-cells = <1>; + #size-cells = <1>; + + binman { + u-boot-vpl-nodtb { + }; + }; +}; diff --git a/tools/binman/test/203_fdt_incl_vpl.dts b/tools/binman/test/203_fdt_incl_vpl.dts new file mode 100644 index 00000000000..435256fe317 --- /dev/null +++ b/tools/binman/test/203_fdt_incl_vpl.dts @@ -0,0 +1,13 @@ +// SPDX-License-Identifier: GPL-2.0+ + +/dts-v1/; + +/ { + #address-cells = <1>; + #size-cells = <1>; + + binman { + u-boot-vpl { + }; + }; +}; diff --git a/tools/binman/test/204_vpl_bss_pad.dts b/tools/binman/test/204_vpl_bss_pad.dts new file mode 100644 index 00000000000..d1e55fff4f2 --- /dev/null +++ b/tools/binman/test/204_vpl_bss_pad.dts @@ -0,0 +1,17 @@ +/dts-v1/; + +/ { + #address-cells = <1>; + #size-cells = <1>; + + binman { + u-boot-vpl { + }; + + u-boot-vpl-bss-pad { + }; + + u-boot { + }; + }; +};

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 ---
common/Kconfig | 67 ++++++++++++++++ common/spl/Kconfig | 168 +++++++++++++++++++++++++++++++++++++++- common/spl/spl.c | 25 +++++- doc/develop/spl.rst | 6 +- include/bootstage.h | 2 + include/linux/kconfig.h | 3 + include/spl.h | 20 ++++- lib/Kconfig | 54 +++++++++++++ scripts/Kbuild.include | 4 + scripts/Makefile.build | 4 + 10 files changed, 345 insertions(+), 8 deletions(-)
diff --git a/common/Kconfig b/common/Kconfig index 26496f9a2e7..2a7f08af1dc 100644 --- a/common/Kconfig +++ b/common/Kconfig @@ -81,6 +81,15 @@ config TPL_LOGLEVEL int default LOGLEVEL
+config VPL_LOGLEVEL + int "loglevel for VPL" + default LOGLEVEL + help + All Messages with a loglevel smaller than the console loglevel will + be compiled in to VPL. See LOGLEVEL for a list of available log + levels. Setting this to a value above 4 may increase the code size + significantly. + config SILENT_CONSOLE bool "Support a silent console" help @@ -254,6 +263,15 @@ config LOG
if LOG
+config VPL_LOG + bool "Enable logging support in VPL" + depends on LOG + help + This enables support for logging of status and debug messages. These + can be displayed on the console, recorded in a memory buffer, or + discarded if not needed. Logging supports various categories and + levels of severity. + config LOG_MAX_LEVEL int "Maximum log level to record" default 6 @@ -415,6 +433,47 @@ config TPL_LOG_CONSOLE
endif
+config VPL_LOG + bool "Enable logging support in VPL" + depends on LOG + help + This enables support for logging of status and debug messages. These + can be displayed on the console, recorded in a memory buffer, or + discarded if not needed. Logging supports various categories and + levels of severity. + +if VPL_LOG + +config VPL_LOG_MAX_LEVEL + int "Maximum log level to record in VPL" + default 3 + help + This selects the maximum log level that will be recorded. Any value + higher than this will be ignored. If possible log statements below + this level will be discarded at build time. Levels: + + 0 - emergency + 1 - alert + 2 - critical + 3 - error + 4 - warning + 5 - note + 6 - info + 7 - debug + 8 - debug content + 9 - debug hardware I/O + +config VPL_LOG_CONSOLE + bool "Allow log output to the console in VPL" + default y + help + Enables a log driver which writes log records to the console. + Generally the console is the serial port or LCD display. Only the + log message is shown - other details like level, category, file and + line number are omitted. + +endif + config LOG_ERROR_RETURN bool "Log all functions which return an error" help @@ -711,6 +770,14 @@ config TPL_BLOBLIST This enables a bloblist in TPL. The bloblist is set up in TPL and passed to SPL and U-Boot proper.
+config VPL_BLOBLIST + bool "Support for a bloblist in VPL" + depends on BLOBLIST + default y if TPL_BLOBLIST + help + This enables a bloblist in VPL. The bloblist is set up in VPL and + passed to SPL and U-Boot proper. + config BLOBLIST_SIZE hex "Size of bloblist" depends on BLOBLIST diff --git a/common/spl/Kconfig b/common/spl/Kconfig index df5468f1ac2..274686fd3ad 100644 --- a/common/spl/Kconfig +++ b/common/spl/Kconfig @@ -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
@@ -280,6 +283,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 @@ -297,6 +310,15 @@ config TPL_BANNER_PRINT info. Disabling this option could be useful to reduce TPL boot time (e.g. approx. 6 ms faster, when output on i.MX6 with 115200 baud).
+config VPL_BANNER_PRINT + bool "Enable output of the VPL banner 'U-Boot VPL ...'" + depends on VPL + default y + help + If this option is enabled, VPL will print the banner with version + info. Disabling this option could be useful to reduce VPL boot time + (e.g. approx. 6 ms faster, when output on i.MX6 with 115200 baud). + config SPL_EARLY_BSS depends on ARM && !ARM64 bool "Allows initializing BSS early before entering board_init_f" @@ -817,6 +839,27 @@ config SPL_DM_SPI_FLASH Enable support for SPI DM flash drivers in SPL.
endif + +if TPL + +config VPL_CACHE + depends on CACHE + bool "Support cache drivers in SPL" + help + Enable support for cache drivers in SPL. + +config VPL_DM_SPI + bool "Support SPI DM drivers in SPL" + help + Enable support for SPI DM drivers in SPL. + +config VPL_DM_SPI_FLASH + bool "Support SPI DM FLASH drivers in SPL" + help + Enable support for SPI DM flash drivers in SPL. + +endif + if SPL_UBI config SPL_UBI_LOAD_BY_VOLNAME bool "Support loading volumes by name" @@ -1623,6 +1666,129 @@ config TPL_YMODEM_SUPPORT
endif # TPL
+config VPL + bool + depends on SUPPORT_SPL + prompt "Enable VPL" + help + If you want to build VPL as well as the normal image, TPL and SPL, + say Y. + +if VPL + +config VPL_FRAMEWORK + bool "Support VPL based upon the common SPL framework" + default y + help + Enable the SPL framework under common/spl/ for VPL builds. + This framework supports MMC, NAND and YMODEM and other methods + loading of U-Boot's next stage. If unsure, say Y. + +config VPL_LIBCOMMON_SUPPORT + bool "Support common libraries" + default y if SPL_LIBCOMMON_SUPPORT + help + Enable support for common U-Boot libraries within VPL. See + SPL_LIBCOMMON_SUPPORT for details. + +config VPL_LIBGENERIC_SUPPORT + bool "Support generic libraries" + default y if SPL_LIBGENERIC_SUPPORT + help + Enable support for generic U-Boot libraries within VPL. These + libraries include generic code to deal with device tree, hashing, + printf(), compression and the like. This option is enabled on many + boards. Enable this option to build the code in lib/ as part of an + SPL build. + +config VPL_DRIVERS_MISC_SUPPORT + bool "Support misc drivers" + default y if TPL_DRIVERS_MISC_SUPPORT + help + Enable miscellaneous drivers in VPL. These drivers perform various + tasks that don't fall nicely into other categories, Enable this + option to build the drivers in drivers/misc as part of an VPL + build, for those that support building in VPL (not all drivers do). + +config VPL_GPIO_SUPPORT + bool "Support GPIO in VPL" + default y if SPL_GPIO_SUPPORT + help + Enable support for GPIOs (General-purpose Input/Output) in VPL. + GPIOs allow U-Boot to read the state of an input line (high or + low) and set the state of an output line. This can be used to + drive LEDs, control power to various system parts and read user + input. GPIOs can be useful in TPL to enable a 'sign-of-life' LED, + for example. Enable this option to build the drivers in + drivers/gpio as part of an TPL build. + +config VPL_I2C_SUPPORT + bool "Support I2C in VPL" + default y if SPL_I2C_SUPPORT + help + Enable support for the I2C bus in TPL. Vee SPL_I2C_SUPPORT for + details. + +config VPL_PCH_SUPPORT + bool "Support PCH drivers" + default y if TPL_PCH_SUPPORT + help + Enable support for PCH (Platform Controller Hub) devices in VPL. + These are used to set up GPIOs and the SPI peripheral early in + boot. This enables the drivers in drivers/pch as part of a VPL + build. + +config VPL_PCI + bool "Support PCI drivers" + default y if SPL_PCI + help + Enable support for PCI in VPL. For platforms that need PCI to boot, + or must perform some init using PCI in VPL, this provides the + necessary driver support. This enables the drivers in drivers/pci + as part of a VPL build. + +config VPL_RTC_SUPPORT + bool "Support RTC drivers" + help + Enable RTC (Real-time Clock) support in VPL. This includes support + for reading and setting the time. Some RTC devices also have some + non-volatile (battery-backed) memory which is accessible if + needed. This enables the drivers in drivers/rtc as part of an VPL + build. + +config VPL_SERIAL_SUPPORT + bool "Support serial" + default y if TPL_SERIAL_SUPPORT + select VPL_PRINTF + select VPL_STRTO + help + Enable support for serial in VPL. See SPL_SERIAL_SUPPORT for + details. + +config VPL_SPI_SUPPORT + bool "Support SPI drivers" + help + Enable support for using SPI in VPL. See SPL_SPI_SUPPORT for + details. + +config VPL_SPI_FLASH_SUPPORT + bool "Support SPI flash drivers" + help + Enable support for using SPI flash in VPL, and loading U-Boot from + SPI flash. SPI flash (Serial Peripheral Bus flash) is named after + the SPI bus that is used to connect it to a system. It is a simple + but fast bidirectional 4-wire bus (clock, chip select and two data + lines). This enables the drivers in drivers/mtd/spi as part of an + VPL build. This normally requires VPL_SPI_SUPPORT. + +config VPL_TEXT_BASE + hex "VPL Text Base" + default 0x0 + help + The address in memory that VPL will be running from. + +endif + config SPL_AT91_MCK_BYPASS bool "Use external clock signal as a source of main clock for AT91 platforms" depends on ARCH_AT91 diff --git a/common/spl/spl.c b/common/spl/spl.c index a0a608fd772..cd428c1cbc9 100644 --- a/common/spl/spl.c +++ b/common/spl/spl.c @@ -55,6 +55,11 @@ binman_sym_declare(ulong, spl, image_pos); binman_sym_declare(ulong, spl, size); #endif
+#ifdef CONFIG_VPL +binman_sym_declare(ulong, vpl, image_pos); +binman_sym_declare(ulong, vpl, size); +#endif + /* Define board data structure */ static struct bd_info bdata __attribute__ ((section(".data")));
@@ -137,21 +142,33 @@ void spl_fixup_fdt(void *fdt_blob)
ulong spl_get_image_pos(void) { - return spl_phase() == PHASE_TPL ? +#ifdef CONFIG_VPL + if (spl_next_phase() == PHASE_VPL) + return binman_sym(ulong, vpl, image_pos); +#endif + return spl_next_phase() == PHASE_SPL ? binman_sym(ulong, 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, vpl, size); +#endif + return spl_next_phase() == PHASE_SPL ? binman_sym(ulong, spl, size) : binman_sym(ulong, u_boot_any, size); }
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; }
@@ -428,6 +445,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; } diff --git a/doc/develop/spl.rst b/doc/develop/spl.rst index c2a29a8c0a4..ede79431118 100644 --- a/doc/develop/spl.rst +++ b/doc/develop/spl.rst @@ -62,7 +62,11 @@ 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
SPL Secondary program loader. Sets up SDRAM and loads U-Boot proper. It may also diff --git a/include/bootstage.h b/include/bootstage.h index 00c85fb86aa..23df36c8e80 100644 --- a/include/bootstage.h +++ b/include/bootstage.h @@ -174,6 +174,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, diff --git a/include/linux/kconfig.h b/include/linux/kconfig.h index d109ed3119e..26f1216f7da 100644 --- a/include/linux/kconfig.h +++ b/include/linux/kconfig.h @@ -37,6 +37,8 @@
#if 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 @@ -52,6 +54,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)
diff --git a/include/spl.h b/include/spl.h index cee9a42ddb5..d9fe4e1bfd4 100644 --- a/include/spl.h +++ b/include/spl.h @@ -60,6 +60,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 */ @@ -112,7 +113,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; @@ -134,10 +137,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 }
@@ -150,6 +158,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; @@ -166,6 +176,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: @@ -180,6 +192,8 @@ static inline const char *spl_phase_name(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 diff --git a/lib/Kconfig b/lib/Kconfig index 6d2d41de301..da27e71abf3 100644 --- a/lib/Kconfig +++ b/lib/Kconfig @@ -72,6 +72,11 @@ config TPL_PRINTF select TPL_SPRINTF select TPL_STRTO if !TPL_USE_TINY_PRINTF
+config VPL_PRINTF + bool + select VPL_SPRINTF + select VPL_STRTO if !VPL_USE_TINY_PRINTF + config SPRINTF bool default y @@ -82,6 +87,9 @@ config SPL_SPRINTF config TPL_SPRINTF bool
+config VPL_SPRINTF + bool + config SSCANF bool default n @@ -96,6 +104,9 @@ config SPL_STRTO config TPL_STRTO bool
+config VPL_STRTO + bool + config IMAGE_SPARSE bool
@@ -148,6 +159,17 @@ config TPL_USE_TINY_PRINTF
The supported format specifiers are %c, %s, %u/%d and %x.
+config VPL_USE_TINY_PRINTF + bool "Enable tiny printf() version for VPL" + depends on VPL + help + This option enables a tiny, stripped down printf version. + This should only be used in space limited environments, + like SPL versions with hard memory limits. This version + reduces the code size by about 2.5KiB on armv7. + + The supported format specifiers are %c, %s, %u/%d and %x. + config PANIC_HANG bool "Do not reset the system on fatal error" help @@ -331,6 +353,17 @@ config TPL_TPM for the low-level TPM interface, but only one TPM is supported at a time by the TPM library.
+config VPL_TPM + bool "Trusted Platform Module (TPM) Support in VPL" + depends on VPL_DM + help + This enables support for TPMs which can be used to provide security + features for your board. The TPM can be connected via LPC or I2C + and a sandbox TPM is provided for testing purposes. Use the 'tpm' + command to interactive the TPM. Driver model support is provided + for the low-level TPM interface, but only one TPM is supported at + a time by the TPM library. + endmenu
menu "Android Verified Boot" @@ -627,6 +660,27 @@ config TPL_OF_LIBFDT_ASSUME_MASK 0xff means all assumptions are made and any invalid data may cause unsafe execution. See FDT_ASSUME_PERFECT, etc. in libfdt_internal.h
+config VPL_OF_LIBFDT + bool "Enable the FDT library for VPL" + default y if VPL_OF_CONTROL && !VPL_OF_PLATDATA + help + This enables the FDT library (libfdt). It provides functions for + accessing binary device tree images in memory, such as adding and + removing nodes and properties, scanning through the tree and finding + particular compatible nodes. The library operates on a flattened + version of the device tree. + +config VPL_OF_LIBFDT_ASSUME_MASK + hex "Mask of conditions to assume for libfdt" + depends on VPL_OF_LIBFDT || FIT + default 0xff + help + Use this to change the assumptions made by libfdt in SPL about the + device tree it is working with. A value of 0 means that no assumptions + are made, and libfdt is able to deal with malicious data. A value of + 0xff means all assumptions are made and any invalid data may cause + unsafe execution. See FDT_ASSUME_PERFECT, etc. in libfdt_internal.h + config FDT_FIXUP_PARTITIONS bool "overwrite MTD partitions in DTS through defined in 'mtdparts'" depends on OF_LIBFDT diff --git a/scripts/Kbuild.include b/scripts/Kbuild.include index dfb67226b08..c87d9c9f5f2 100644 --- a/scripts/Kbuild.include +++ b/scripts/Kbuild.include @@ -325,11 +325,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_ := diff --git a/scripts/Makefile.build b/scripts/Makefile.build index 705a886cb98..b64a961f6fa 100644 --- a/scripts/Makefile.build +++ b/scripts/Makefile.build @@ -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:

Hi Simon,
On 5/8/21 12:37 AM, Simon Glass wrote:
U-Boot provides a verified-boot feature based around FIT, but there is no standard way of implementing it for a board. At present the various required pieces must be built up separately, to produce a working implementation. In particular, there is no built-in support for selecting A/B boot or recovery mode.
This series introduces VPL, a verified program loader. Its purpose is to run the verified-boot process and decide which SPL binary should be run. Adding VPL into the boot flow provides a standard way of implementing verified boot. So far, only the phase itself is added. More work is needed to add logic to the phase, based on continuing discussions about how best to standardise this feature.
This is quite interesting. Where is that data stored which SPL should run? fallback options? Do you have any proposal/document which describes it?
Thanks, Michal

Hi Michal,
On Wed, 19 May 2021 at 01:16, Michal Simek michal.simek@xilinx.com wrote:
Hi Simon,
On 5/8/21 12:37 AM, Simon Glass wrote:
U-Boot provides a verified-boot feature based around FIT, but there is no standard way of implementing it for a board. At present the various required pieces must be built up separately, to produce a working implementation. In particular, there is no built-in support for selecting A/B boot or recovery mode.
This series introduces VPL, a verified program loader. Its purpose is to run the verified-boot process and decide which SPL binary should be run. Adding VPL into the boot flow provides a standard way of implementing verified boot. So far, only the phase itself is added. More work is needed to add logic to the phase, based on continuing discussions about how best to standardise this feature.
This is quite interesting. Where is that data stored which SPL should run? fallback options? Do you have any proposal/document which describes it?
It is not quite ready for release. But I could talk about it on the U-Boot call next week if that suits.
Regards, Simon

Hi Simon,
On 5/20/21 12:17 AM, Simon Glass wrote:
Hi Michal,
On Wed, 19 May 2021 at 01:16, Michal Simek michal.simek@xilinx.com wrote:
Hi Simon,
On 5/8/21 12:37 AM, Simon Glass wrote:
U-Boot provides a verified-boot feature based around FIT, but there is no standard way of implementing it for a board. At present the various required pieces must be built up separately, to produce a working implementation. In particular, there is no built-in support for selecting A/B boot or recovery mode.
This series introduces VPL, a verified program loader. Its purpose is to run the verified-boot process and decide which SPL binary should be run. Adding VPL into the boot flow provides a standard way of implementing verified boot. So far, only the phase itself is added. More work is needed to add logic to the phase, based on continuing discussions about how best to standardise this feature.
This is quite interesting. Where is that data stored which SPL should run? fallback options? Do you have any proposal/document which describes it?
It is not quite ready for release. But I could talk about it on the U-Boot call next week if that suits.
I don't have conflict that's why no problem for me. Will try to attend.
Thanks, Michal

Hi,
On Fri, 7 May 2021 at 16:37, Simon Glass sjg@chromium.org wrote:
U-Boot provides a verified-boot feature based around FIT, but there is no standard way of implementing it for a board. At present the various required pieces must be built up separately, to produce a working implementation. In particular, there is no built-in support for selecting A/B boot or recovery mode.
This series introduces VPL, a verified program loader. Its purpose is to run the verified-boot process and decide which SPL binary should be run. Adding VPL into the boot flow provides a standard way of implementing verified boot. So far, only the phase itself is added. More work is needed to add logic to the phase, based on continuing discussions about how best to standardise this feature.
Simon Glass (4): doc: Convert SPL documentation to ReST doc: Expand SPL docs to explain the phase and config binman: Add VPL support Introduce Verifying Program Loader (VPL)
common/Kconfig | 67 ++++++++ common/spl/Kconfig | 168 ++++++++++++++++++++- common/spl/spl.c | 25 ++- doc/develop/index.rst | 1 + doc/{README.SPL => develop/spl.rst} | 99 +++++++----- include/bootstage.h | 2 + include/linux/kconfig.h | 3 + include/spl.h | 20 ++- lib/Kconfig | 54 +++++++ scripts/Kbuild.include | 4 + scripts/Makefile.build | 4 + tools/binman/etype/u_boot_vpl.py | 42 ++++++ tools/binman/etype/u_boot_vpl_bss_pad.py | 44 ++++++ tools/binman/etype/u_boot_vpl_dtb.py | 28 ++++ tools/binman/etype/u_boot_vpl_expanded.py | 45 ++++++ tools/binman/etype/u_boot_vpl_nodtb.py | 42 ++++++ tools/binman/ftest.py | 110 +++++++++++--- tools/binman/state.py | 3 +- tools/binman/test/082_fdt_update_all.dts | 2 + tools/binman/test/201_u_boot_vpl.dts | 11 ++ tools/binman/test/202_u_boot_vpl_nodtb.dts | 13 ++ tools/binman/test/203_fdt_incl_vpl.dts | 13 ++ tools/binman/test/204_vpl_bss_pad.dts | 17 +++ 23 files changed, 748 insertions(+), 69 deletions(-) rename doc/{README.SPL => develop/spl.rst} (61%) create mode 100644 tools/binman/etype/u_boot_vpl.py create mode 100644 tools/binman/etype/u_boot_vpl_bss_pad.py create mode 100644 tools/binman/etype/u_boot_vpl_dtb.py create mode 100644 tools/binman/etype/u_boot_vpl_expanded.py create mode 100644 tools/binman/etype/u_boot_vpl_nodtb.py create mode 100644 tools/binman/test/201_u_boot_vpl.dts create mode 100644 tools/binman/test/202_u_boot_vpl_nodtb.dts create mode 100644 tools/binman/test/203_fdt_incl_vpl.dts create mode 100644 tools/binman/test/204_vpl_bss_pad.dts
-- 2.31.1.607.g51e8a6a459-goog
Are there any comments on this series?
I plan to build on this to actually implement the verifying loader at some point.
Regards, Simon
participants (2)
-
Michal Simek
-
Simon Glass