From 6dca1d9ad38de9b7f9a44d2c6eaa6acf9be6c2c0 Mon Sep 17 00:00:00 2001 From: Rasmus Villemoes Date: Mon, 22 Aug 2022 09:34:23 +0200 Subject: fdt_support: add optional board_rng_seed() hook A recurring theme on LKML is the boot process deadlocking due to some process blocking waiting for random numbers, while the kernel's Cryptographic Random Number Generator (crng) is not initalized yet, but that very blocking means no activity happens that would generate the entropy necessary to finalize seeding the crng. This is not a problem on boards that have a good hwrng (when the kernel is configured to trust it), whether in the CPU or in a TPM or elsewhere. However, that's far from all boards out there. Moreover, there are consumers in the kernel that try to obtain random numbers very early, before the kernel has had any chance to initialize any hwrng or other peripherals. Allow a board to provide a board_rng_seed() function, which is responsible for providing a value to be put into the rng-seed property under the /chosen node. The board code is responsible for how to actually obtain those bytes. - One possibility is for the board to load a seed "file" from somewhere (it need not be a file in a filesystem of course), and then ensure that that the same seed file does not get used on subsequent boots. * One way to do that is to delete the file, or otherwise mark it as invalid, then rely on userspace to create a new one, and living with the possibility of not finding a seed file during some boots. * Another is to use the scheme used by systemd-boot and create a new seed file immediately, but in a way that the seed passed to the kernel and the new (i.e. next) seed cannot be deduced from each other, see the explanation at https://lore.kernel.org/lkml/20190929090512.GB13049@gardel-login/ and the current code at https://github.com/systemd/systemd/blob/main/src/boot/efi/random-seed.c - The board may have an hwrng from which some bytes can be read; while the kernel can also do that, doing it in U-Boot and providing a seed ensures that even very early users in the kernel get good random numbers. - If the board has a sensor of some sort (temperature, humidity, GPS, RTC, whatever), mixing in a reading of that doesn't hurt. - etc. etc. These can of course be combined. The rng-seed property is mixed into the pool used by the linux kernel's CRNG very early during boot. Whether it then actually contributes towards the kernel considering the CRNG initialized depends on whether the kernel has been configured with CONFIG_RANDOM_TRUST_BOOTLOADER (nowadays overridable via the random.trust_bootloader command line option). But that's for the BSP developer to ultimately decide. So, if the board needs to have all that logic, why not also just have it do the actual population of /chosen/rng-seed in ft_board_setup(), which is not that many extra lines of code? I considered that, but decided handling this logically belongs in fdt_chosen(). Also, apart from saving the board code from the few lines of boilerplate, doing it in ft_board_setup() is too late for at least some use cases. For example, I want to allow the board logic to decide ok, let's pass back this buffer and use that as seed, but also let's set random.trust_bootloader=n so no entropy is credited. This requires the rng-seed handling to happen before bootargs handling. For example, during the very first boot, the board might not have a proper seed file, but the board could still return (a hash of) some CPU serial# or whatnot, so that at least no two boards ever get the same seed - the kernel always mixes in the value passed in rng-seed, but if it is not "trusted", the kernel would still go through the same motions as it would if no rng-seed was passed before considering its CRNG initialized. I.e., by returning that unique-to-this-board value and setting random.trust_bootloader=n, the board would be no worse off than if board_rng_seed() returned nothing at all. Signed-off-by: Rasmus Villemoes --- common/Kconfig | 14 ++++++++++++++ common/fdt_support.c | 13 +++++++++++++ include/fdt_support.h | 13 +++++++++++++ 3 files changed, 40 insertions(+) diff --git a/common/Kconfig b/common/Kconfig index e7914ca750a..ebee856e567 100644 --- a/common/Kconfig +++ b/common/Kconfig @@ -768,6 +768,20 @@ config TPL_STACKPROTECTOR bool "Stack Protector buffer overflow detection for TPL" depends on STACKPROTECTOR && TPL +config BOARD_RNG_SEED + bool "Provide /chosen/rng-seed property to the linux kernel" + help + Selecting this option requires the board to define a + board_rng_seed() function, which should return a buffer + which will be used to populate the /chosen/rng-seed property + in the device tree for the OS being booted. + + It is up to the board code (and more generally the whole + BSP) where and how to store (or generate) such a seed, how + to ensure a given seed is only used once, how to create a + new seed for use on subsequent boots, and whether or not the + kernel should account any entropy from the given seed. + endmenu menu "Update support" diff --git a/common/fdt_support.c b/common/fdt_support.c index 8c18af2ce15..baf7fb70659 100644 --- a/common/fdt_support.c +++ b/common/fdt_support.c @@ -7,6 +7,7 @@ */ #include +#include #include #include #include @@ -279,6 +280,7 @@ __weak char *board_fdt_chosen_bootargs(void) int fdt_chosen(void *fdt) { + struct abuf buf = {}; int nodeoffset; int err; char *str; /* used to set string properties */ @@ -294,6 +296,17 @@ int fdt_chosen(void *fdt) if (nodeoffset < 0) return nodeoffset; + if (IS_ENABLED(CONFIG_BOARD_RNG_SEED) && !board_rng_seed(&buf)) { + err = fdt_setprop(fdt, nodeoffset, "rng-seed", + abuf_data(&buf), abuf_size(&buf)); + abuf_uninit(&buf); + if (err < 0) { + printf("WARNING: could not set rng-seed %s.\n", + fdt_strerror(err)); + return err; + } + } + str = board_fdt_chosen_bootargs(); if (str) { diff --git a/include/fdt_support.h b/include/fdt_support.h index ac76939e817..b8380716f39 100644 --- a/include/fdt_support.h +++ b/include/fdt_support.h @@ -11,6 +11,7 @@ #include #include +#include /** * arch_fixup_fdt() - Write arch-specific information to fdt @@ -186,6 +187,18 @@ int fdt_find_or_add_subnode(void *fdt, int parentoffset, const char *name); */ int ft_board_setup(void *blob, struct bd_info *bd); +/** + * board_rng_seed() - Provide a seed to be passed via /chosen/rng-seed + * + * This function is called if CONFIG_BOARD_RNG_SEED is set, and must + * be provided by the board. It should return, via @buf, some suitable + * seed value to pass to the kernel. + * + * @param buf A struct abuf for returning the seed and its size. + * @return 0 if ok, negative on error. + */ +int board_rng_seed(struct abuf *buf); + /** * board_fdt_chosen_bootargs() - Arbitrarily amend fdt kernel command line * -- cgit v1.2.3 From 6ad2452bc61d925eaa40f52377baaddf92c43464 Mon Sep 17 00:00:00 2001 From: Simon Glass Date: Mon, 28 Feb 2022 07:16:54 -0700 Subject: binman: Add VPL support Add support for U-Boot's Verifying Program Loader phase. Signed-off-by: Simon Glass --- 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 | 109 +++++++++++++++++++++++------ tools/binman/state.py | 3 +- tools/binman/test/082_fdt_update_all.dts | 2 + tools/binman/test/255_u_boot_vpl.dts | 11 +++ tools/binman/test/256_u_boot_vpl_nodtb.dts | 13 ++++ tools/binman/test/257_fdt_incl_vpl.dts | 13 ++++ tools/binman/test/258_vpl_bss_pad.dts | 19 +++++ 12 files changed, 349 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/255_u_boot_vpl.dts create mode 100644 tools/binman/test/256_u_boot_vpl_nodtb.dts create mode 100644 tools/binman/test/257_fdt_incl_vpl.dts create mode 100644 tools/binman/test/258_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 +# +# 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..b2ce2a31352 --- /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 +# +# 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.get_input_filename('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.get_bytes(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 +# +# 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..92c64f0a65e --- /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 +# +# 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.do_output(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 +# +# 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 3ced14b7e98..ecb35956031 100644 --- a/tools/binman/ftest.py +++ b/tools/binman/ftest.py @@ -44,12 +44,14 @@ U_BOOT_DATA = b'1234' U_BOOT_IMG_DATA = b'img' U_BOOT_SPL_DATA = b'56780123456789abcdefghijklm' U_BOOT_TPL_DATA = b'tpl9876543210fedcbazywvuts' +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' @@ -60,6 +62,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' U_BOOT_EXP_DATA = U_BOOT_NODTB_DATA + U_BOOT_DTB_DATA U_BOOT_SPL_EXP_DATA = U_BOOT_SPL_NODTB_DATA + U_BOOT_SPL_DTB_DATA U_BOOT_TPL_EXP_DATA = U_BOOT_TPL_NODTB_DATA + U_BOOT_TPL_DTB_DATA @@ -140,6 +143,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) @@ -165,6 +169,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) @@ -296,6 +302,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 @@ -431,8 +438,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 @@ -502,11 +509,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, @@ -612,6 +619,16 @@ class TestFunctional(unittest.TestCase): TestFunctional._MakeInputFile('tpl/u-boot-tpl', tools.read_file(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.read_file(cls.ElfTestFile(src_fname))) + @classmethod def _SetupDescriptor(cls): with open(cls.TestFile('descriptor.bin'), 'rb') as fd: @@ -1907,21 +1924,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. @@ -1929,11 +1949,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 @@ -1953,7 +1974,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.get_output_filename(os.path.split(fname)[1]) @@ -1961,7 +1982,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, @@ -5928,6 +5949,52 @@ fdt fdtmap Extract the devicetree blob from the fdtmap fname = tools.get_output_filename('mkimage-test.bin') self.assertTrue(os.path.exists(fname)) + 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('255_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('256_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('257_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('258_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 a302e1f00eb..56e5bf8bc10 100644 --- a/tools/binman/state.py +++ b/tools/binman/state.py @@ -22,6 +22,7 @@ OUR_PATH = os.path.dirname(os.path.realpath(__file__)) 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. @@ -292,7 +293,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/255_u_boot_vpl.dts b/tools/binman/test/255_u_boot_vpl.dts new file mode 100644 index 00000000000..a3a281a91e0 --- /dev/null +++ b/tools/binman/test/255_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/256_u_boot_vpl_nodtb.dts b/tools/binman/test/256_u_boot_vpl_nodtb.dts new file mode 100644 index 00000000000..055016badd5 --- /dev/null +++ b/tools/binman/test/256_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/257_fdt_incl_vpl.dts b/tools/binman/test/257_fdt_incl_vpl.dts new file mode 100644 index 00000000000..435256fe317 --- /dev/null +++ b/tools/binman/test/257_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/258_vpl_bss_pad.dts b/tools/binman/test/258_vpl_bss_pad.dts new file mode 100644 index 00000000000..d308dcade17 --- /dev/null +++ b/tools/binman/test/258_vpl_bss_pad.dts @@ -0,0 +1,19 @@ +// SPDX-License-Identifier: GPL-2.0+ + +/dts-v1/; + +/ { + #address-cells = <1>; + #size-cells = <1>; + + binman { + u-boot-vpl { + }; + + u-boot-vpl-bss-pad { + }; + + u-boot { + }; + }; +}; -- cgit v1.2.3