From: Simon Glass Date: Mon, 28 Feb 2022 14:16:54 +0000 (-0700) Subject: binman: Add VPL support X-Git-Url: http://git.dujemihanovic.xyz/img/sics.gif?a=commitdiff_plain;h=6ad2452bc61d925eaa40f52377baaddf92c43464;p=u-boot.git binman: Add VPL support Add support for U-Boot's Verifying Program Loader phase. Signed-off-by: Simon Glass --- diff --git a/tools/binman/etype/u_boot_vpl.py b/tools/binman/etype/u_boot_vpl.py new file mode 100644 index 0000000000..9daaca4f6f --- /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 0000000000..b2ce2a3135 --- /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 0000000000..f6253bf243 --- /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 0000000000..92c64f0a65 --- /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 0000000000..25c966cf34 --- /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 3ced14b7e9..ecb3595603 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 a302e1f00e..56e5bf8bc1 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 284975cc28..1aea56989f 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 0000000000..a3a281a91e --- /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 0000000000..055016badd --- /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 0000000000..435256fe31 --- /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 0000000000..d308dcade1 --- /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 { + }; + }; +};