[PATCH v3 00/11] Sign Xilinx ZynqMP SPL/FSBL boot images using binman

From: Lukas Funke lukas.funke@weidmueller.com
This series adds two etypes to create a verified boot chain for Xilinx ZynqMP devices. The first etype 'xilinx-fsbl-auth' is used to create a bootable, signed image for ZynqMP boards using the Xilinx Bootgen tool. The second etype 'u-boot-spl-pubkey-dtb' is used to add a '/signature' node to the SPL. The public key in the signature is read from a certificate file and added using the 'fdt_add_pubkey' tool. The series also contains the corresponding btool for calling 'bootgen' and 'fdt_add_pubkey'.
The following block shows an example on how to use this functionality:
spl { filename = "boot.signed.bin";
xilinx-fsbl-auth { psk-key-name-hint = "psk0"; ssk-key-name-hint = "ssk0"; auth-params = "ppk_select=0", "spk_id=0x00000000";
u-boot-spl-nodtb { }; u-boot-spl-pubkey-dtb { algo = "sha384,rsa4096"; required = "conf"; key-name-hint = "dev"; }; }; };
Changes in v3: - Improved test coverage regarding missing libelf - Align error message - Fix rst headline length - Add newline before main - Adapted test due to property renaming - Fixed minor python doc typo in u-boot-spl-pubkey-dtb etype - Renamed key property from 'key-name' to 'key-name-hint' - Fixed an issue where the build result was not found - Fixed an issue where the version string was not reported correctly - Improved test coverage for xilinx-fsbl-auth etype - Changed etype from entry to section - Changed property name "psk-filename" to "psk-key-name-hint" - Changed property name "ssk-filename" to "ssk-key-name-hint" - Decode spl elf file instead of reading start symbol - Improved test coverage - Improved documentation
Changes in v2: - Changed u_boot_spl_pubkey_dtb to u-boot-spl-pubkey-dtb - Improved rst/python documentation - Changed u_boot_spl_pubkey_dtb to u-boot-spl-pubkey-dtb in example - Pass additional 'keysrc_enc' parameter to Bootgen - Added more information and terms to documentation - Fixed typo in dts name - Add 'keysrc-enc' property to pass down to Bootgen - Improved documentation - Use predictable output names for intermediated results
Lukas Funke (11): binman: elf: Check for ELF_TOOLS availability and remove extra semicolon binman: Don't decompress data while signing binman: blob_dtb: Add fake_size argument to ObtainContents() binman: doc: Add documentation for fdt_add_pubkey bintool binman: ftest: Add test for u_boot_spl_pubkey_dtb binman: btool: Add fdt_add_pubkey as btool binman: etype: Add u-boot-spl-pubkey-dtb etype binman: doc: Add documentation for Xilinx Bootgen bintool binman: btool: Add Xilinx Bootgen btool binman: ftest: Add test for xilinx_fsbl_auth etype binman: etype: Add xilinx_fsbl_auth etype
tools/binman/bintools.rst | 22 ++ tools/binman/btool/bootgen.py | 136 +++++++++++ tools/binman/btool/fdt_add_pubkey.py | 67 ++++++ tools/binman/control.py | 2 +- tools/binman/elf.py | 14 +- tools/binman/elf_test.py | 11 + tools/binman/entries.rst | 110 +++++++++ tools/binman/etype/blob_dtb.py | 2 +- tools/binman/etype/u_boot_spl_pubkey_dtb.py | 109 +++++++++ tools/binman/etype/xilinx_fsbl_auth.py | 221 ++++++++++++++++++ tools/binman/ftest.py | 94 ++++++++ tools/binman/test/280_xilinx_fsbl_auth.dts | 21 ++ .../binman/test/280_xilinx_fsbl_auth_enc.dts | 23 ++ tools/binman/test/281_spl_pubkey_dtb.dts | 16 ++ 14 files changed, 839 insertions(+), 9 deletions(-) create mode 100644 tools/binman/btool/bootgen.py create mode 100644 tools/binman/btool/fdt_add_pubkey.py create mode 100644 tools/binman/etype/u_boot_spl_pubkey_dtb.py create mode 100644 tools/binman/etype/xilinx_fsbl_auth.py create mode 100644 tools/binman/test/280_xilinx_fsbl_auth.dts create mode 100644 tools/binman/test/280_xilinx_fsbl_auth_enc.dts create mode 100644 tools/binman/test/281_spl_pubkey_dtb.dts

From: Lukas Funke lukas.funke@weidmueller.com
Check if elf tools are available when running DecodeElf(). Also remove superfuous semicolon at line ending.
Signed-off-by: Lukas Funke lukas.funke@weidmueller.com Reviewed-by: Simon Glass sjg@chromium.org
---
Changes in v3: - Improved test coverage regarding missing libelf - Align error message
tools/binman/elf.py | 14 +++++++------- tools/binman/elf_test.py | 11 +++++++++++ 2 files changed, 18 insertions(+), 7 deletions(-)
diff --git a/tools/binman/elf.py b/tools/binman/elf.py index 5816284c32..e1a17cef96 100644 --- a/tools/binman/elf.py +++ b/tools/binman/elf.py @@ -255,9 +255,7 @@ def LookupAndWriteSymbols(elf_fname, entry, section, is_elf=False, syms = GetSymbols(fname, ['image', 'binman']) if is_elf: if not ELF_TOOLS: - msg = ("Section '%s': entry '%s'" % - (section.GetPath(), entry.GetPath())) - raise ValueError(f'{msg}: Cannot write symbols to an ELF file without Python elftools') + raise ValueError("Python: No module named 'elftools'") new_syms = {} with open(fname, 'rb') as fd: elf = ELFFile(fd) @@ -438,13 +436,15 @@ def DecodeElf(data, location): Returns: ElfInfo object containing information about the decoded ELF file """ + if not ELF_TOOLS: + raise ValueError("Python: No module named 'elftools'") file_size = len(data) with io.BytesIO(data) as fd: elf = ELFFile(fd) - data_start = 0xffffffff; - data_end = 0; - mem_end = 0; - virt_to_phys = 0; + data_start = 0xffffffff + data_end = 0 + mem_end = 0 + virt_to_phys = 0
for i in range(elf.num_segments()): segment = elf.get_segment(i) diff --git a/tools/binman/elf_test.py b/tools/binman/elf_test.py index c98083961b..f78ad647d6 100644 --- a/tools/binman/elf_test.py +++ b/tools/binman/elf_test.py @@ -253,6 +253,17 @@ class TestElf(unittest.TestCase): fname = self.ElfTestFile('embed_data') with self.assertRaises(ValueError) as e: elf.GetSymbolFileOffset(fname, ['embed_start', 'embed_end']) + with self.assertRaises(ValueError) as e: + elf.DecodeElf(tools.read_file(fname), 0xdeadbeef) + with self.assertRaises(ValueError) as e: + elf.GetFileOffset(fname, 0xdeadbeef) + with self.assertRaises(ValueError) as e: + elf.GetSymbolFromAddress(fname, 0xdeadbeef) + with self.assertRaises(ValueError) as e: + entry = FakeEntry(10) + section = FakeSection() + elf.LookupAndWriteSymbols(fname, entry, section, True) + self.assertIn("Python: No module named 'elftools'", str(e.exception)) finally:

From: Lukas Funke lukas.funke@weidmueller.com
Check if elf tools are available when running DecodeElf(). Also remove superfuous semicolon at line ending.
Signed-off-by: Lukas Funke lukas.funke@weidmueller.com Reviewed-by: Simon Glass sjg@chromium.org
---
Changes in v3: - Improved test coverage regarding missing libelf - Align error message
tools/binman/elf.py | 14 +++++++------- tools/binman/elf_test.py | 11 +++++++++++ 2 files changed, 18 insertions(+), 7 deletions(-)
Applied to u-boot-dm, thanks!

From: Lukas Funke lukas.funke@weidmueller.com
While signing a fit compressed data (i.e. 'blob-ext') is decompressed, but never compressed again. When compressed data was wrapped in a section, decompression leads to an error because the outer section had the original compressed size but the inner entry has the uncompressed size now.
While singing there is no reason to decompress data. Thus, decompression should be disabled.
Furthermore, bintools should be collected before loading the data. This way bintools are available if processing is required on a node.
Signed-off-by: Lukas Funke lukas.funke@weidmueller.com Reviewed-by: Simon Glass sjg@chromium.org ---
(no changes since v1)
tools/binman/control.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-)
diff --git a/tools/binman/control.py b/tools/binman/control.py index 68597c4e77..affc33ff3d 100644 --- a/tools/binman/control.py +++ b/tools/binman/control.py @@ -306,8 +306,8 @@ def BeforeReplace(image, allow_resize): image: Image to prepare """ state.PrepareFromLoadedData(image) - image.LoadData() image.CollectBintools() + image.LoadData(decomp=False)
# If repacking, drop the old offset/size values except for the original # ones, so we are only left with the constraints.

From: Lukas Funke lukas.funke@weidmueller.com
While signing a fit compressed data (i.e. 'blob-ext') is decompressed, but never compressed again. When compressed data was wrapped in a section, decompression leads to an error because the outer section had the original compressed size but the inner entry has the uncompressed size now.
While singing there is no reason to decompress data. Thus, decompression should be disabled.
Furthermore, bintools should be collected before loading the data. This way bintools are available if processing is required on a node.
Signed-off-by: Lukas Funke lukas.funke@weidmueller.com Reviewed-by: Simon Glass sjg@chromium.org ---
(no changes since v1)
tools/binman/control.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-)
Applied to u-boot-dm, thanks!

From: Lukas Funke lukas.funke@weidmueller.com
The method 'connect_contents_to_file()' calls ObtainsContents() with 'fake_size' argument. Without providing the argument in the blob_dtb we are not able to call this method without error.
Signed-off-by: Lukas Funke lukas.funke@weidmueller.com Reviewed-by: Simon Glass sjg@chromium.org ---
(no changes since v1)
tools/binman/etype/blob_dtb.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-)
diff --git a/tools/binman/etype/blob_dtb.py b/tools/binman/etype/blob_dtb.py index 6a3fbc4775..d543de9f75 100644 --- a/tools/binman/etype/blob_dtb.py +++ b/tools/binman/etype/blob_dtb.py @@ -38,7 +38,7 @@ class Entry_blob_dtb(Entry_blob): self.Raise("Invalid prepend in '%s': '%s'" % (self._node.name, self.prepend))
- def ObtainContents(self): + def ObtainContents(self, fake_size=0): """Get the device-tree from the list held by the 'state' module""" self._filename = self.GetDefaultFilename() self._pathname, _ = state.GetFdtContents(self.GetFdtEtype())

From: Lukas Funke lukas.funke@weidmueller.com
The method 'connect_contents_to_file()' calls ObtainsContents() with 'fake_size' argument. Without providing the argument in the blob_dtb we are not able to call this method without error.
Signed-off-by: Lukas Funke lukas.funke@weidmueller.com Reviewed-by: Simon Glass sjg@chromium.org ---
(no changes since v1)
tools/binman/etype/blob_dtb.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-)
Applied to u-boot-dm, thanks!

From: Lukas Funke lukas.funke@weidmueller.com
Add documentation for btool which calls 'fdt_add_pubkey'
Signed-off-by: Lukas Funke lukas.funke@weidmueller.com Reviewed-by: Simon Glass sjg@chromium.org
---
Changes in v3: - Fix rst headline length
tools/binman/bintools.rst | 10 ++++++++++ 1 file changed, 10 insertions(+)
diff --git a/tools/binman/bintools.rst b/tools/binman/bintools.rst index c30e7eb9ff..0c5d510886 100644 --- a/tools/binman/bintools.rst +++ b/tools/binman/bintools.rst @@ -183,3 +183,13 @@ Documentation is available via::
+Bintool: fdt_add_pubkey: Add public key to device tree +------------------------------------------------------ + +This bintool supports running `fdt_add_pubkey` in order to add a public +key coming from a certificate to a device-tree. + +Normally signing is done using `mkimage` in context of `binman sign`. However, +in this process the public key is not added to the stage before u-boot proper. +Using `fdt_add_pubkey` the key can be injected to the SPL independent of +`mkimage`

From: Lukas Funke lukas.funke@weidmueller.com
Add documentation for btool which calls 'fdt_add_pubkey'
Signed-off-by: Lukas Funke lukas.funke@weidmueller.com Reviewed-by: Simon Glass sjg@chromium.org
---
Changes in v3: - Fix rst headline length
tools/binman/bintools.rst | 10 ++++++++++ 1 file changed, 10 insertions(+)
Applied to u-boot-dm, thanks!

From: Lukas Funke lukas.funke@weidmueller.com
Add test for u_boot_spl_pubkey_dtb. The test adds a public key to the dtb and checks if the required nodes will be added to the images dtb.
Signed-off-by: Lukas Funke lukas.funke@weidmueller.com Reviewed-by: Simon Glass sjg@chromium.org
---
Changes in v3: - Add newline before main - Adapted test due to property renaming
Changes in v2: - Changed u_boot_spl_pubkey_dtb to u-boot-spl-pubkey-dtb
tools/binman/ftest.py | 33 ++++++++++++++++++++++++ tools/binman/test/281_spl_pubkey_dtb.dts | 16 ++++++++++++ 2 files changed, 49 insertions(+) create mode 100644 tools/binman/test/281_spl_pubkey_dtb.dts
diff --git a/tools/binman/ftest.py b/tools/binman/ftest.py index 43b4f850a6..959c760792 100644 --- a/tools/binman/ftest.py +++ b/tools/binman/ftest.py @@ -638,6 +638,16 @@ class TestFunctional(unittest.TestCase): TestFunctional._MakeInputFile('vpl/u-boot-vpl', tools.read_file(cls.ElfTestFile(src_fname)))
+ @classmethod + def _SetupPmuFwlElf(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('pmu-firmware.elf', + tools.read_file(cls.ElfTestFile(src_fname))) + @classmethod def _SetupDescriptor(cls): with open(cls.TestFile('descriptor.bin'), 'rb') as fd: @@ -6677,5 +6687,28 @@ fdt fdtmap Extract the devicetree blob from the fdtmap self.assertIn("Node '/fit': Missing tool: 'mkimage'", str(e.exception))
+ def testSplPubkeyDtb(self): + """Test u_boot_spl_pubkey_dtb etype""" + data = tools.read_file(self.TestFile("key.pem")) + self._MakeInputFile("key.crt", data) + self._DoReadFileRealDtb('281_spl_pubkey_dtb.dts') + image = control.images['image'] + entries = image.GetEntries() + dtb_entry = entries['u-boot-spl-pubkey-dtb'] + dtb_data = dtb_entry.GetData() + dtb = fdt.Fdt.FromData(dtb_data) + dtb.Scan() + + signature_node = dtb.GetNode('/signature') + self.assertIsNotNone(signature_node) + key_node = signature_node.FindNode("key-key") + self.assertIsNotNone(key_node) + self.assertEqual(fdt_util.GetString(key_node, "required"), + "conf") + self.assertEqual(fdt_util.GetString(key_node, "algo"), + "sha384,rsa4096") + self.assertEqual(fdt_util.GetString(key_node, "key-name-hint"), + "key") + if __name__ == "__main__": unittest.main() diff --git a/tools/binman/test/281_spl_pubkey_dtb.dts b/tools/binman/test/281_spl_pubkey_dtb.dts new file mode 100644 index 0000000000..3256ff970c --- /dev/null +++ b/tools/binman/test/281_spl_pubkey_dtb.dts @@ -0,0 +1,16 @@ +// SPDX-License-Identifier: GPL-2.0+ + +/dts-v1/; + +/ { + #address-cells = <1>; + #size-cells = <1>; + + binman { + u-boot-spl-pubkey-dtb { + algo = "sha384,rsa4096"; + required = "conf"; + key-name-hint = "key"; + }; + }; +};

From: Lukas Funke lukas.funke@weidmueller.com
Add test for u_boot_spl_pubkey_dtb. The test adds a public key to the dtb and checks if the required nodes will be added to the images dtb.
Signed-off-by: Lukas Funke lukas.funke@weidmueller.com Reviewed-by: Simon Glass sjg@chromium.org
---
Changes in v3: - Add newline before main - Adapted test due to property renaming
Changes in v2: - Changed u_boot_spl_pubkey_dtb to u-boot-spl-pubkey-dtb
tools/binman/ftest.py | 33 ++++++++++++++++++++++++ tools/binman/test/281_spl_pubkey_dtb.dts | 16 ++++++++++++ 2 files changed, 49 insertions(+) create mode 100644 tools/binman/test/281_spl_pubkey_dtb.dts
Applied to u-boot-dm, thanks!

From: Lukas Funke lukas.funke@weidmueller.com
Add btool which calls 'fdt_add_pubkey'
Signed-off-by: Lukas Funke lukas.funke@weidmueller.com Reviewed-by: Simon Glass sjg@chromium.org ---
(no changes since v1)
tools/binman/btool/fdt_add_pubkey.py | 67 ++++++++++++++++++++++++++++ 1 file changed, 67 insertions(+) create mode 100644 tools/binman/btool/fdt_add_pubkey.py
diff --git a/tools/binman/btool/fdt_add_pubkey.py b/tools/binman/btool/fdt_add_pubkey.py new file mode 100644 index 0000000000..a50774200c --- /dev/null +++ b/tools/binman/btool/fdt_add_pubkey.py @@ -0,0 +1,67 @@ +# SPDX-License-Identifier: GPL-2.0+ +# Copyright (C) 2023 Weidmüller Interface GmbH & Co. KG +# Lukas Funke lukas.funke@weidmueller.com +# +"""Bintool implementation for fdt_add_pubkey""" + +from binman import bintool + +class Bintoolfdt_add_pubkey(bintool.Bintool): + """Add public key to control dtb (spl or u-boot proper) + + This bintool supports running `fdt_add_pubkey`. + + Normally mkimage adds signature information to the control dtb. However + binman images are built independent from each other. Thus it is required + to add the public key separately from mkimage. + """ + def __init__(self, name): + super().__init__(name, 'Generate image for U-Boot') + + # pylint: disable=R0913 + def run(self, input_fname, keydir, keyname, required, algo): + """Run fdt_add_pubkey + + Args: + input_fname (str): dtb file to sign + keydir (str): Directory with public key. Optional parameter, + default value: '.' (current directory) + keyname (str): Public key name. Optional parameter, + default value: key + required (str): If present this indicates that the key must be + verified for the image / configuration to be considered valid. + algo (str): Cryptographic algorithm. Optional parameter, + default value: sha1,rsa2048 + """ + args = [] + if algo: + args += ['-a', algo] + if keydir: + args += ['-k', keydir] + if keyname: + args += ['-n', keyname] + if required: + args += ['-r', required] + + args += [ input_fname ] + + return self.run_cmd(*args) + + def fetch(self, method): + """Fetch handler for fdt_add_pubkey + + This installs fdt_add_pubkey using the apt utility. + + Args: + method (FETCH_...): Method to use + + Returns: + True if the file was fetched and now installed, None if a method + other than FETCH_BIN was requested + + Raises: + Valuerror: Fetching could not be completed + """ + if method != bintool.FETCH_BIN: + return None + return self.apt_install('u-boot-tools')

From: Lukas Funke lukas.funke@weidmueller.com
Add btool which calls 'fdt_add_pubkey'
Signed-off-by: Lukas Funke lukas.funke@weidmueller.com Reviewed-by: Simon Glass sjg@chromium.org ---
(no changes since v1)
tools/binman/btool/fdt_add_pubkey.py | 67 ++++++++++++++++++++++++++++ 1 file changed, 67 insertions(+) create mode 100644 tools/binman/btool/fdt_add_pubkey.py
Applied to u-boot-dm, thanks!

From: Lukas Funke lukas.funke@weidmueller.com
This adds a new etype 'u-boot-spl-pubkey-dtb'. The etype adds the public key from a certificate to the dtb. This creates a '/signature' node which is turn contains the fields which make up the public key. Usually this is done by 'mkimage -K'. However, 'binman sign' does not add the public key to the SPL. This is why the pubkey is added using this etype.
The etype calls the underlying 'fdt_add_pubkey' tool.
Signed-off-by: Lukas Funke lukas.funke@weidmueller.com Reviewed-by: Simon Glass sjg@chromium.org
---
Changes in v3: - Fixed minor python doc typo in u-boot-spl-pubkey-dtb etype - Renamed key property from 'key-name' to 'key-name-hint'
Changes in v2: - Improved rst/python documentation - Changed u_boot_spl_pubkey_dtb to u-boot-spl-pubkey-dtb in example
tools/binman/entries.rst | 39 +++++++ tools/binman/etype/u_boot_spl_pubkey_dtb.py | 109 ++++++++++++++++++++ 2 files changed, 148 insertions(+) create mode 100644 tools/binman/etype/u_boot_spl_pubkey_dtb.py
diff --git a/tools/binman/entries.rst b/tools/binman/entries.rst index b71af801fd..c368ea8053 100644 --- a/tools/binman/entries.rst +++ b/tools/binman/entries.rst @@ -1912,6 +1912,45 @@ binman uses that to look up symbols to write into the SPL binary.
+.. _etype_u_boot_spl_pubkey_dtb: + +Entry: u-boot-spl-pubkey-dtb: U-Boot SPL device tree including public key +------------------------------------------------------------------------- + +Properties / Entry arguments: + - key-name-hint: Public key name without extension (.crt). + Default is determined by underlying + bintool (fdt_add_pubkey), usually 'key'. + - algo: (Optional) Algorithm used for signing. Default is determined by + underlying bintool (fdt_add_pubkey), usually 'sha1,rsa2048' + - required: (Optional) If present this indicates that the key must be + verified for the image / configuration to be + considered valid + +The following example shows an image containing an SPL which +is packed together with the dtb. Binman will add a signature +node to the dtb. + +Example node:: + + image { + ... + spl { + filename = "spl.bin" + + u-boot-spl-nodtb { + }; + u-boot-spl-pubkey-dtb { + algo = "sha384,rsa4096"; + required = "conf"; + key-name-hint = "dev"; + }; + }; + ... + } + + + .. _etype_u_boot_spl_with_ucode_ptr:
Entry: u-boot-spl-with-ucode-ptr: U-Boot SPL with embedded microcode pointer diff --git a/tools/binman/etype/u_boot_spl_pubkey_dtb.py b/tools/binman/etype/u_boot_spl_pubkey_dtb.py new file mode 100644 index 0000000000..cc92175ca3 --- /dev/null +++ b/tools/binman/etype/u_boot_spl_pubkey_dtb.py @@ -0,0 +1,109 @@ +# SPDX-License-Identifier: GPL-2.0+ +# Copyright (c) 2023 Weidmueller GmbH +# Written by Lukas Funke lukas.funke@weidmueller.com +# +# Entry-type module for 'u-boot-spl-pubkey.dtb' +# + +import tempfile +import os + +from binman.etype.blob_dtb import Entry_blob_dtb + +from dtoc import fdt_util + +from u_boot_pylib import tools + +# pylint: disable=C0103 +class Entry_u_boot_spl_pubkey_dtb(Entry_blob_dtb): + """U-Boot SPL device tree including public key + + Properties / Entry arguments: + - key-name-hint: Public key name without extension (.crt). + Default is determined by underlying + bintool (fdt_add_pubkey), usually 'key'. + - algo: (Optional) Algorithm used for signing. Default is determined by + underlying bintool (fdt_add_pubkey), usually 'sha1,rsa2048' + - required: (Optional) If present this indicates that the key must be + verified for the image / configuration to be + considered valid + + The following example shows an image containing an SPL which + is packed together with the dtb. Binman will add a signature + node to the dtb. + + Example node:: + + image { + ... + spl { + filename = "spl.bin" + + u-boot-spl-nodtb { + }; + u-boot-spl-pubkey-dtb { + algo = "sha384,rsa4096"; + required = "conf"; + key-name-hint = "dev"; + }; + }; + ... + } + """ + + def __init__(self, section, etype, node): + # Put this here to allow entry-docs and help to work without libfdt + global state + from binman import state + + super().__init__(section, etype, node) + self.required_props = ['key-name-hint'] + self.fdt_add_pubkey = None + self._algo = fdt_util.GetString(self._node, 'algo') + self._required = fdt_util.GetString(self._node, 'required') + self._key_name_hint = fdt_util.GetString(self._node, 'key-name-hint') + + def ObtainContents(self, fake_size=0): + """Add public key to SPL dtb + + Add public key which is pointed out by + 'key-name-hint' to node 'signature' in the spl-dtb + + This is equivalent to the '-K' option of 'mkimage' + + Args: + fake_size (int): unused + """ + + # We don't pass fake_size upwards because this is currently + # not supported by the blob type + super().ObtainContents() + + with tempfile.NamedTemporaryFile(prefix=os.path.basename( + self.GetFdtEtype()), + dir=tools.get_output_dir())\ + as pubkey_tdb: + tools.write_file(pubkey_tdb.name, self.GetData()) + keyname = tools.get_input_filename(self._key_name_hint + ".crt") + self.fdt_add_pubkey.run(pubkey_tdb.name, + os.path.dirname(keyname), + self._key_name_hint, + self._required, self._algo) + dtb = tools.read_file(pubkey_tdb.name) + self.SetContents(dtb) + state.UpdateFdtContents(self.GetFdtEtype(), dtb) + + return True + + # pylint: disable=R0201,C0116 + def GetDefaultFilename(self): + return 'spl/u-boot-spl-pubkey.dtb' + + # pylint: disable=R0201,C0116 + def GetFdtEtype(self): + return 'u-boot-spl-dtb' + + # pylint: disable=R0201,C0116 + def AddBintools(self, btools): + super().AddBintools(btools) + self.fdt_add_pubkey = self.AddBintool(btools, 'fdt_add_pubkey')

From: Lukas Funke lukas.funke@weidmueller.com
This adds a new etype 'u-boot-spl-pubkey-dtb'. The etype adds the public key from a certificate to the dtb. This creates a '/signature' node which is turn contains the fields which make up the public key. Usually this is done by 'mkimage -K'. However, 'binman sign' does not add the public key to the SPL. This is why the pubkey is added using this etype.
The etype calls the underlying 'fdt_add_pubkey' tool.
Signed-off-by: Lukas Funke lukas.funke@weidmueller.com Reviewed-by: Simon Glass sjg@chromium.org
---
Changes in v3: - Fixed minor python doc typo in u-boot-spl-pubkey-dtb etype - Renamed key property from 'key-name' to 'key-name-hint'
Changes in v2: - Improved rst/python documentation - Changed u_boot_spl_pubkey_dtb to u-boot-spl-pubkey-dtb in example
tools/binman/entries.rst | 39 +++++++ tools/binman/etype/u_boot_spl_pubkey_dtb.py | 109 ++++++++++++++++++++ 2 files changed, 148 insertions(+) create mode 100644 tools/binman/etype/u_boot_spl_pubkey_dtb.py
Applied to u-boot-dm, thanks!

From: Lukas Funke lukas.funke@weidmueller.com
Add documentation for the 'bootgen' bintool
Signed-off-by: Lukas Funke lukas.funke@weidmueller.com Reviewed-by: Simon Glass sjg@chromium.org ---
(no changes since v1)
tools/binman/bintools.rst | 12 ++++++++++++ 1 file changed, 12 insertions(+)
diff --git a/tools/binman/bintools.rst b/tools/binman/bintools.rst index 0c5d510886..c6c9a88c21 100644 --- a/tools/binman/bintools.rst +++ b/tools/binman/bintools.rst @@ -193,3 +193,15 @@ Normally signing is done using `mkimage` in context of `binman sign`. However, in this process the public key is not added to the stage before u-boot proper. Using `fdt_add_pubkey` the key can be injected to the SPL independent of `mkimage` + + + +Bintool: bootgen: Sign ZynqMP FSBL image +--------------------------------------------- + +This bintool supports running `bootgen` in order to sign a SPL for ZynqMP +devices. + +The bintool automatically creates an appropriate input image file (.bif) for +bootgen based on the passed arguments. The output is a bootable, +authenticated `boot.bin` file.

From: Lukas Funke lukas.funke@weidmueller.com
Add documentation for the 'bootgen' bintool
Signed-off-by: Lukas Funke lukas.funke@weidmueller.com Reviewed-by: Simon Glass sjg@chromium.org ---
(no changes since v1)
tools/binman/bintools.rst | 12 ++++++++++++ 1 file changed, 12 insertions(+)
Applied to u-boot-dm, thanks!

From: Lukas Funke lukas.funke@weidmueller.com
Add the Xilinx Bootgen as bintool. Xilinx Bootgen is used to create bootable SPL (FSBL in Xilinx terms) images for Zynq/ZynqMP devices. The btool creates a signed version of the SPL. Additionally to signing the key source for the decryption engine can be passend to the boot image.
Signed-off-by: Lukas Funke lukas.funke@weidmueller.com
---
Changes in v3: - Fixed an issue where the build result was not found - Fixed an issue where the version string was not reported correctly
Changes in v2: - Pass additional 'keysrc_enc' parameter to Bootgen - Added more information and terms to documentation
tools/binman/bintools.rst | 2 +- tools/binman/btool/bootgen.py | 136 ++++++++++++++++++++++++++++++++++ 2 files changed, 137 insertions(+), 1 deletion(-) create mode 100644 tools/binman/btool/bootgen.py
diff --git a/tools/binman/bintools.rst b/tools/binman/bintools.rst index c6c9a88c21..8f58aaebf7 100644 --- a/tools/binman/bintools.rst +++ b/tools/binman/bintools.rst @@ -197,7 +197,7 @@ Using `fdt_add_pubkey` the key can be injected to the SPL independent of
Bintool: bootgen: Sign ZynqMP FSBL image ---------------------------------------------- +----------------------------------------
This bintool supports running `bootgen` in order to sign a SPL for ZynqMP devices. diff --git a/tools/binman/btool/bootgen.py b/tools/binman/btool/bootgen.py new file mode 100644 index 0000000000..83bbe124dc --- /dev/null +++ b/tools/binman/btool/bootgen.py @@ -0,0 +1,136 @@ +# SPDX-License-Identifier: GPL-2.0+ +# Copyright (C) 2023 Weidmüller Interface GmbH & Co. KG +# Lukas Funke lukas.funke@weidmueller.com +# +"""Bintool implementation for bootgen + +bootgen allows creating bootable SPL for Zynq(MP) + +Documentation is available via:: +https://www.xilinx.com/support/documents/sw_manuals/xilinx2022_1/ug1283-boot... + +Source code is available at: + +https://github.com/Xilinx/bootgen + +""" +import tempfile + +from binman import bintool +from u_boot_pylib import tools + +# pylint: disable=C0103 +class Bintoolbootgen(bintool.Bintool): + """Generate bootable fsbl image for zynq/zynqmp + + This bintools supports running Xilinx "bootgen" in order + to generate a bootable, authenticated image form an SPL. + + """ + def __init__(self, name): + super().__init__(name, 'Xilinx Bootgen', + version_regex=r'^****** *Xilinx Bootgen *(.*)', + version_args='-help') + + # pylint: disable=R0913 + def sign(self, arch, spl_elf_fname, pmufw_elf_fname, + psk_fname, ssk_fname, fsbl_config, auth_params, keysrc_enc, + output_fname): + """ Sign SPL elf file and bundle it PMU firmware into an image + + The method bundels the SPL together with a 'Platform Management Unit' + (PMU)[1] firmware into a single bootable image. The image in turn is + signed with the provided 'secondary secret key' (ssk), which in turn is + signed with the 'primary secret key' (ppk). In order to verify the + authenticity of the ppk, it's hash has to be fused into the device + itself. + + In Xilinx terms the SPL is usually called 'FSBL' + (First Stage Boot Loder). The jobs of the SPL and the FSBL are mostly + the same: load bitstream, bootstrap u-boot. + + Args: + arch (str): Xilinx SoC architecture. Currently only 'zynqmp' is + supported. + spl_elf_fname (str): Filename of SPL ELF file. The filename must end + with '.elf' in order for bootgen to recognized it as an ELF + file. Otherwise the start address field is missinterpreted. + pmufw_elf_fname (str): Filename PMU ELF firmware. + psk_fname (str): Filename of the primary secret key (psk). The psk + is a .pem file which holds the RSA private key used for signing + the secondardy secret key. + ssk_fname (str): Filename of the secondary secret key. The ssk + is a .pem file which holds the RSA private key used for signing + the aktual boot firmware. + fsbl_config (str): FSBL config options. A string list of fsbl config + options. Valid values according to [2] are: + "bh_auth_enable": Boot Header Authentication Enable: RSA + authentication of the bootimage is done + excluding the verification of PPK hash and SPK ID. This is + useful for debugging before bricking a device. + "auth_only": Boot image is only RSA signed. FSBL should not be + decrypted. See the + Zynq UltraScale+ Device Technical Reference Manual (UG1085) + for more information. + There are more options which relate to PUF (physical unclonable + functions). Please refer to Xilinx manuals for fruther info. + auth_params (str): Authentication parameter. A semicolon separated + list of authentication parameters. Valid values according to [3] + are: + "ppk_select=<0|1>" - Select which ppk to use + "spk_id=<32-bit spk id>" - Specifies which SPK can be + used or revoked, default is 0x0 + "spk_select=<spk-efuse/user-efuse>" - To differentiate spk and + user efuses. + "auth_header" - To authenticate headers when no partition + is authenticated. + keysrc_enc (str): This specifies the Key source for encryption. + Valid values according to [3] are: + "bbram_red_key" - RED key stored in BBRAM + "efuse_red_key" - RED key stored in efuse + "efuse_gry_key" - Grey (Obfuscated) Key stored in eFUSE. + "bh_gry_key" - Grey (Obfuscated) Key stored in boot header. + "bh_blk_key" - Black Key stored in boot header. + "efuse_blk_key" - Black Key stored in eFUSE. + "kup_key" - User Key. + + output_fname (str): Filename where bootgen should write the result + + [1] https://xilinx-wiki.atlassian.net/wiki/spaces/A/pages/18841724/PMU+Firmware + [2] https://docs.xilinx.com/r/en-US/ug1283-bootgen-user-guide/fsbl_config + [3] https://docs.xilinx.com/r/en-US/ug1283-bootgen-user-guide/auth_params + [4] https://docs.xilinx.com/r/en-US/ug1283-bootgen-user-guide/keysrc_encryption + """ + + _fsbl_config = f"[fsbl_config] {fsbl_config}" if fsbl_config else "" + _auth_params = f"[auth_params] {auth_params}" if auth_params else "" + _keysrc_enc = f"[keysrc_encryption] {keysrc_enc}" if keysrc_enc else "" + + bif_template = f"""u_boot_spl_aes_rsa: {{ + [pskfile] {psk_fname} + [sskfile] {ssk_fname} + {_keysrc_enc} + {_fsbl_config} + {_auth_params} + [ bootloader, + authentication = rsa, + destination_cpu=a53-0] {spl_elf_fname} + [pmufw_image] {pmufw_elf_fname} + }}""" + args = ["-arch", arch] + + bif_fname = tools.get_output_filename('bootgen-in.sign.bif') + tools.write_file(bif_fname, bif_template, False) + args += ["-image", bif_fname, '-w', '-o', output_fname] + self.run_cmd(*args) + + def fetch(self, method): + """Fetch bootgen from git""" + if method != bintool.FETCH_BUILD: + return None + + result = self.build_from_git( + 'https://github.com/Xilinx/bootgen', + 'all', + 'bootgen') + return result

Hi,
On Tue, 18 Jul 2023 at 05:53, lukas.funke-oss@weidmueller.com wrote:
From: Lukas Funke lukas.funke@weidmueller.com
Add the Xilinx Bootgen as bintool. Xilinx Bootgen is used to create bootable SPL (FSBL in Xilinx terms) images for Zynq/ZynqMP devices. The btool creates a signed version of the SPL. Additionally to signing the key source for the decryption engine can be passend to the boot image.
Signed-off-by: Lukas Funke lukas.funke@weidmueller.com
Changes in v3:
- Fixed an issue where the build result was not found
- Fixed an issue where the version string was not reported correctly
Changes in v2:
- Pass additional 'keysrc_enc' parameter to Bootgen
- Added more information and terms to documentation
tools/binman/bintools.rst | 2 +- tools/binman/btool/bootgen.py | 136 ++++++++++++++++++++++++++++++++++ 2 files changed, 137 insertions(+), 1 deletion(-) create mode 100644 tools/binman/btool/bootgen.py
diff --git a/tools/binman/bintools.rst b/tools/binman/bintools.rst index c6c9a88c21..8f58aaebf7 100644 --- a/tools/binman/bintools.rst +++ b/tools/binman/bintools.rst @@ -197,7 +197,7 @@ Using `fdt_add_pubkey` the key can be injected to the SPL independent of
Bintool: bootgen: Sign ZynqMP FSBL image
+----------------------------------------
This bintool supports running `bootgen` in order to sign a SPL for ZynqMP devices. diff --git a/tools/binman/btool/bootgen.py b/tools/binman/btool/bootgen.py new file mode 100644 index 0000000000..83bbe124dc --- /dev/null +++ b/tools/binman/btool/bootgen.py @@ -0,0 +1,136 @@ +# SPDX-License-Identifier: GPL-2.0+ +# Copyright (C) 2023 Weidmüller Interface GmbH & Co. KG +# Lukas Funke lukas.funke@weidmueller.com +# +"""Bintool implementation for bootgen
+bootgen allows creating bootable SPL for Zynq(MP)
+Documentation is available via:: +https://www.xilinx.com/support/documents/sw_manuals/xilinx2022_1/ug1283-boot...
+Source code is available at:
+https://github.com/Xilinx/bootgen
+""" +import tempfile
+from binman import bintool +from u_boot_pylib import tools
+# pylint: disable=C0103 +class Bintoolbootgen(bintool.Bintool):
- """Generate bootable fsbl image for zynq/zynqmp
- This bintools supports running Xilinx "bootgen" in order
- to generate a bootable, authenticated image form an SPL.
- """
- def __init__(self, name):
super().__init__(name, 'Xilinx Bootgen',
version_regex=r'^\*\*\*\*\*\* *Xilinx Bootgen *(.*)',
version_args='-help')
- # pylint: disable=R0913
- def sign(self, arch, spl_elf_fname, pmufw_elf_fname,
psk_fname, ssk_fname, fsbl_config, auth_params, keysrc_enc,
output_fname):
""" Sign SPL elf file and bundle it PMU firmware into an image
The method bundels the SPL together with a 'Platform Management Unit'
(PMU)[1] firmware into a single bootable image. The image in turn is
signed with the provided 'secondary secret key' (ssk), which in turn is
signed with the 'primary secret key' (ppk). In order to verify the
authenticity of the ppk, it's hash has to be fused into the device
itself.
Please regen the entry-docs in the same patch, so that entries.rst is updated. Also check your references like [1]. Looking at the docs output you should be able to click on the link, i.e. you should use rST style [..]
Regards, Simon

On 7/18/23 13:53, lukas.funke-oss@weidmueller.com wrote:
From: Lukas Funke lukas.funke@weidmueller.com
Add the Xilinx Bootgen as bintool. Xilinx Bootgen is used to create bootable SPL (FSBL in Xilinx terms) images for Zynq/ZynqMP devices. The btool creates a signed version of the SPL. Additionally to signing the key source for the decryption engine can be passend to the boot image.
Signed-off-by: Lukas Funke lukas.funke@weidmueller.com
Changes in v3:
- Fixed an issue where the build result was not found
- Fixed an issue where the version string was not reported correctly
Changes in v2:
Pass additional 'keysrc_enc' parameter to Bootgen
Added more information and terms to documentation
tools/binman/bintools.rst | 2 +- tools/binman/btool/bootgen.py | 136 ++++++++++++++++++++++++++++++++++ 2 files changed, 137 insertions(+), 1 deletion(-) create mode 100644 tools/binman/btool/bootgen.py
diff --git a/tools/binman/bintools.rst b/tools/binman/bintools.rst index c6c9a88c21..8f58aaebf7 100644 --- a/tools/binman/bintools.rst +++ b/tools/binman/bintools.rst @@ -197,7 +197,7 @@ Using `fdt_add_pubkey` the key can be injected to the SPL independent of
Bintool: bootgen: Sign ZynqMP FSBL image
+----------------------------------------
This bintool supports running `bootgen` in order to sign a SPL for ZynqMP devices. diff --git a/tools/binman/btool/bootgen.py b/tools/binman/btool/bootgen.py new file mode 100644 index 0000000000..83bbe124dc --- /dev/null +++ b/tools/binman/btool/bootgen.py @@ -0,0 +1,136 @@ +# SPDX-License-Identifier: GPL-2.0+ +# Copyright (C) 2023 Weidmüller Interface GmbH & Co. KG +# Lukas Funke lukas.funke@weidmueller.com +# +"""Bintool implementation for bootgen
+bootgen allows creating bootable SPL for Zynq(MP)
+Documentation is available via:: +https://www.xilinx.com/support/documents/sw_manuals/xilinx2022_1/ug1283-boot...
+Source code is available at:
+https://github.com/Xilinx/bootgen
+""" +import tempfile
+from binman import bintool +from u_boot_pylib import tools
+# pylint: disable=C0103 +class Bintoolbootgen(bintool.Bintool):
- """Generate bootable fsbl image for zynq/zynqmp
- This bintools supports running Xilinx "bootgen" in order
- to generate a bootable, authenticated image form an SPL.
- """
- def __init__(self, name):
super().__init__(name, 'Xilinx Bootgen',
version_regex=r'^\*\*\*\*\*\* *Xilinx Bootgen *(.*)',
version_args='-help')
- # pylint: disable=R0913
- def sign(self, arch, spl_elf_fname, pmufw_elf_fname,
psk_fname, ssk_fname, fsbl_config, auth_params, keysrc_enc,
output_fname):
""" Sign SPL elf file and bundle it PMU firmware into an image
The method bundels the SPL together with a 'Platform Management Unit'
(PMU)[1] firmware into a single bootable image. The image in turn is
signed with the provided 'secondary secret key' (ssk), which in turn is
signed with the 'primary secret key' (ppk). In order to verify the
authenticity of the ppk, it's hash has to be fused into the device
itself.
In Xilinx terms the SPL is usually called 'FSBL'
(First Stage Boot Loder). The jobs of the SPL and the FSBL are mostly
the same: load bitstream, bootstrap u-boot.
Args:
arch (str): Xilinx SoC architecture. Currently only 'zynqmp' is
supported.
spl_elf_fname (str): Filename of SPL ELF file. The filename must end
with '.elf' in order for bootgen to recognized it as an ELF
file. Otherwise the start address field is missinterpreted.
pmufw_elf_fname (str): Filename PMU ELF firmware.
psk_fname (str): Filename of the primary secret key (psk). The psk
is a .pem file which holds the RSA private key used for signing
the secondardy secret key.
typo
ssk_fname (str): Filename of the secondary secret key. The ssk
is a .pem file which holds the RSA private key used for signing
the aktual boot firmware.
actual
fsbl_config (str): FSBL config options. A string list of fsbl config
options. Valid values according to [2] are:
"bh_auth_enable": Boot Header Authentication Enable: RSA
authentication of the bootimage is done
excluding the verification of PPK hash and SPK ID. This is
useful for debugging before bricking a device.
"auth_only": Boot image is only RSA signed. FSBL should not be
decrypted. See the
Zynq UltraScale+ Device Technical Reference Manual (UG1085)
for more information.
There are more options which relate to PUF (physical unclonable
functions). Please refer to Xilinx manuals for fruther info.
auth_params (str): Authentication parameter. A semicolon separated
list of authentication parameters. Valid values according to [3]
are:
"ppk_select=<0|1>" - Select which ppk to use
"spk_id=<32-bit spk id>" - Specifies which SPK can be
used or revoked, default is 0x0
"spk_select=<spk-efuse/user-efuse>" - To differentiate spk and
user efuses.
"auth_header" - To authenticate headers when no partition
is authenticated.
keysrc_enc (str): This specifies the Key source for encryption.
Valid values according to [3] are:
"bbram_red_key" - RED key stored in BBRAM
"efuse_red_key" - RED key stored in efuse
eFUSE to be aligned with description below.
"efuse_gry_key" - Grey (Obfuscated) Key stored in eFUSE.
"bh_gry_key" - Grey (Obfuscated) Key stored in boot header.
"bh_blk_key" - Black Key stored in boot header.
"efuse_blk_key" - Black Key stored in eFUSE.
"kup_key" - User Key.
output_fname (str): Filename where bootgen should write the result
[1] https://xilinx-wiki.atlassian.net/wiki/spaces/A/pages/18841724/PMU+Firmware
[2] https://docs.xilinx.com/r/en-US/ug1283-bootgen-user-guide/fsbl_config
[3] https://docs.xilinx.com/r/en-US/ug1283-bootgen-user-guide/auth_params
[4] https://docs.xilinx.com/r/en-US/ug1283-bootgen-user-guide/keysrc_encryption
"""
_fsbl_config = f"[fsbl_config] {fsbl_config}" if fsbl_config else ""
_auth_params = f"[auth_params] {auth_params}" if auth_params else ""
_keysrc_enc = f"[keysrc_encryption] {keysrc_enc}" if keysrc_enc else ""
bif_template = f"""u_boot_spl_aes_rsa: {{
[pskfile] {psk_fname}
[sskfile] {ssk_fname}
{_keysrc_enc}
{_fsbl_config}
{_auth_params}
[ bootloader,
authentication = rsa,
destination_cpu=a53-0] {spl_elf_fname}
[pmufw_image] {pmufw_elf_fname}
}}"""
args = ["-arch", arch]
bif_fname = tools.get_output_filename('bootgen-in.sign.bif')
tools.write_file(bif_fname, bif_template, False)
args += ["-image", bif_fname, '-w', '-o', output_fname]
self.run_cmd(*args)
- def fetch(self, method):
"""Fetch bootgen from git"""
if method != bintool.FETCH_BUILD:
return None
result = self.build_from_git(
'https://github.com/Xilinx/bootgen',
'all',
'bootgen')
return result
M

Hi,
On Fri, 21 Jul 2023 at 08:20, Michal Simek michal.simek@amd.com wrote:
On 7/18/23 13:53, lukas.funke-oss@weidmueller.com wrote:
From: Lukas Funke lukas.funke@weidmueller.com
Add the Xilinx Bootgen as bintool. Xilinx Bootgen is used to create bootable SPL (FSBL in Xilinx terms) images for Zynq/ZynqMP devices. The btool creates a signed version of the SPL. Additionally to signing the key source for the decryption engine can be passend to the boot image.
Signed-off-by: Lukas Funke lukas.funke@weidmueller.com
Changes in v3:
- Fixed an issue where the build result was not found
- Fixed an issue where the version string was not reported correctly
Changes in v2:
Pass additional 'keysrc_enc' parameter to Bootgen
Added more information and terms to documentation
tools/binman/bintools.rst | 2 +- tools/binman/btool/bootgen.py | 136 ++++++++++++++++++++++++++++++++++ 2 files changed, 137 insertions(+), 1 deletion(-) create mode 100644 tools/binman/btool/bootgen.py
diff --git a/tools/binman/bintools.rst b/tools/binman/bintools.rst index c6c9a88c21..8f58aaebf7 100644 --- a/tools/binman/bintools.rst +++ b/tools/binman/bintools.rst @@ -197,7 +197,7 @@ Using `fdt_add_pubkey` the key can be injected to the SPL independent of
Bintool: bootgen: Sign ZynqMP FSBL image
+----------------------------------------
This bintool supports running `bootgen` in order to sign a SPL for ZynqMP devices. diff --git a/tools/binman/btool/bootgen.py b/tools/binman/btool/bootgen.py new file mode 100644 index 0000000000..83bbe124dc --- /dev/null +++ b/tools/binman/btool/bootgen.py @@ -0,0 +1,136 @@ +# SPDX-License-Identifier: GPL-2.0+ +# Copyright (C) 2023 Weidmüller Interface GmbH & Co. KG +# Lukas Funke lukas.funke@weidmueller.com +# +"""Bintool implementation for bootgen
+bootgen allows creating bootable SPL for Zynq(MP)
+Documentation is available via:: +https://www.xilinx.com/support/documents/sw_manuals/xilinx2022_1/ug1283-boot...
+Source code is available at:
+https://github.com/Xilinx/bootgen
+""" +import tempfile
+from binman import bintool +from u_boot_pylib import tools
+# pylint: disable=C0103 +class Bintoolbootgen(bintool.Bintool):
- """Generate bootable fsbl image for zynq/zynqmp
- This bintools supports running Xilinx "bootgen" in order
- to generate a bootable, authenticated image form an SPL.
- """
- def __init__(self, name):
super().__init__(name, 'Xilinx Bootgen',
version_regex=r'^\*\*\*\*\*\* *Xilinx Bootgen *(.*)',
version_args='-help')
- # pylint: disable=R0913
- def sign(self, arch, spl_elf_fname, pmufw_elf_fname,
psk_fname, ssk_fname, fsbl_config, auth_params, keysrc_enc,
output_fname):
""" Sign SPL elf file and bundle it PMU firmware into an image
The method bundels the SPL together with a 'Platform Management Unit'
(PMU)[1] firmware into a single bootable image. The image in turn is
signed with the provided 'secondary secret key' (ssk), which in turn is
signed with the 'primary secret key' (ppk). In order to verify the
authenticity of the ppk, it's hash has to be fused into the device
itself.
In Xilinx terms the SPL is usually called 'FSBL'
(First Stage Boot Loder). The jobs of the SPL and the FSBL are mostly
the same: load bitstream, bootstrap u-boot.
Args:
arch (str): Xilinx SoC architecture. Currently only 'zynqmp' is
supported.
spl_elf_fname (str): Filename of SPL ELF file. The filename must end
with '.elf' in order for bootgen to recognized it as an ELF
file. Otherwise the start address field is missinterpreted.
pmufw_elf_fname (str): Filename PMU ELF firmware.
psk_fname (str): Filename of the primary secret key (psk). The psk
is a .pem file which holds the RSA private key used for signing
the secondardy secret key.
typo
ssk_fname (str): Filename of the secondary secret key. The ssk
is a .pem file which holds the RSA private key used for signing
the aktual boot firmware.
actual
fsbl_config (str): FSBL config options. A string list of fsbl config
options. Valid values according to [2] are:
"bh_auth_enable": Boot Header Authentication Enable: RSA
authentication of the bootimage is done
excluding the verification of PPK hash and SPK ID. This is
useful for debugging before bricking a device.
"auth_only": Boot image is only RSA signed. FSBL should not be
decrypted. See the
Zynq UltraScale+ Device Technical Reference Manual (UG1085)
for more information.
There are more options which relate to PUF (physical unclonable
functions). Please refer to Xilinx manuals for fruther info.
auth_params (str): Authentication parameter. A semicolon separated
list of authentication parameters. Valid values according to [3]
are:
"ppk_select=<0|1>" - Select which ppk to use
"spk_id=<32-bit spk id>" - Specifies which SPK can be
used or revoked, default is 0x0
"spk_select=<spk-efuse/user-efuse>" - To differentiate spk and
user efuses.
"auth_header" - To authenticate headers when no partition
is authenticated.
keysrc_enc (str): This specifies the Key source for encryption.
Valid values according to [3] are:
"bbram_red_key" - RED key stored in BBRAM
"efuse_red_key" - RED key stored in efuse
eFUSE to be aligned with description below.
"efuse_gry_key" - Grey (Obfuscated) Key stored in eFUSE.
"bh_gry_key" - Grey (Obfuscated) Key stored in boot header.
"bh_blk_key" - Black Key stored in boot header.
"efuse_blk_key" - Black Key stored in eFUSE.
"kup_key" - User Key.
output_fname (str): Filename where bootgen should write the result
[1] https://xilinx-wiki.atlassian.net/wiki/spaces/A/pages/18841724/PMU+Firmware
[2] https://docs.xilinx.com/r/en-US/ug1283-bootgen-user-guide/fsbl_config
[3] https://docs.xilinx.com/r/en-US/ug1283-bootgen-user-guide/auth_params
[4] https://docs.xilinx.com/r/en-US/ug1283-bootgen-user-guide/keysrc_encryption
"""
_fsbl_config = f"[fsbl_config] {fsbl_config}" if fsbl_config else ""
_auth_params = f"[auth_params] {auth_params}" if auth_params else ""
_keysrc_enc = f"[keysrc_encryption] {keysrc_enc}" if keysrc_enc else ""
bif_template = f"""u_boot_spl_aes_rsa: {{
[pskfile] {psk_fname}
[sskfile] {ssk_fname}
{_keysrc_enc}
{_fsbl_config}
{_auth_params}
[ bootloader,
authentication = rsa,
destination_cpu=a53-0] {spl_elf_fname}
[pmufw_image] {pmufw_elf_fname}
}}"""
args = ["-arch", arch]
bif_fname = tools.get_output_filename('bootgen-in.sign.bif')
tools.write_file(bif_fname, bif_template, False)
args += ["-image", bif_fname, '-w', '-o', output_fname]
self.run_cmd(*args)
- def fetch(self, method):
"""Fetch bootgen from git"""
if method != bintool.FETCH_BUILD:
return None
result = self.build_from_git(
'https://github.com/Xilinx/bootgen',
'all',
'bootgen')
return result
M
There is some missing test coverage in the entry type. Please make sure that 'binman test -T' produces 100% for your series. It is OK if it drops due to an intermediate patch, but the final patch must resolve that.
I would like to get this in now if we can..otherwise it will have to skip the release.
Regards, Simon

From: Lukas Funke lukas.funke@weidmueller.com
Add test for the 'xilinx_fsbl_auth' etype
Signed-off-by: Lukas Funke lukas.funke@weidmueller.com
---
Changes in v3: - Improved test coverage for xilinx-fsbl-auth etype
Changes in v2: - Fixed typo in dts name
tools/binman/ftest.py | 61 +++++++++++++++++++ tools/binman/test/280_xilinx_fsbl_auth.dts | 21 +++++++ .../binman/test/280_xilinx_fsbl_auth_enc.dts | 23 +++++++ 3 files changed, 105 insertions(+) create mode 100644 tools/binman/test/280_xilinx_fsbl_auth.dts create mode 100644 tools/binman/test/280_xilinx_fsbl_auth_enc.dts
diff --git a/tools/binman/ftest.py b/tools/binman/ftest.py index 959c760792..fd01eb2030 100644 --- a/tools/binman/ftest.py +++ b/tools/binman/ftest.py @@ -6686,6 +6686,67 @@ fdt fdtmap Extract the devicetree blob from the fdtmap ['fit']) self.assertIn("Node '/fit': Missing tool: 'mkimage'", str(e.exception))
+ def testXilinxFsblAuth(self): + """Test xilinx_fsbl_auth etype""" + data = tools.read_file(self.TestFile("key.key")) + self._MakeInputFile("psk.pem", data) + self._MakeInputFile("ssk.pem", data) + self._SetupPmuFwlElf() + self._SetupSplElf() + self._DoReadFileRealDtb('280_xilinx_fsbl_auth.dts') + image_fname = tools.get_output_filename('image.bin') + bootgen = bintool.Bintool.create('bootgen') + + # Read partition header table and check if authentication is enabled + bootgen_out = bootgen.run_cmd("-arch", "zynqmp", + "-read", image_fname, "pht").splitlines() + attributes = {"authentication": None, + "core": None, + "encryption": None} + + for l in bootgen_out: + for a in attributes.keys(): + if a in l: + m = re.match(fr".*{a} [([^]]+)]", l) + attributes[a] = m.group(1) + + self.assertTrue(attributes['authentication'] == "rsa") + self.assertTrue(attributes['core'] == "a53-0") + self.assertTrue(attributes['encryption'] == "no") + + def testXilinxFsblAuthAndEncryption(self): + """Test xilinx_fsbl_auth etype""" + data = tools.read_file(self.TestFile("key.key")) + self._MakeInputFile("psk.pem", data) + self._MakeInputFile("ssk.pem", data) + self._SetupPmuFwlElf() + self._SetupSplElf() + self._DoReadFileRealDtb('280_xilinx_fsbl_auth_enc.dts') + image_fname = tools.get_output_filename('image.bin') + bootgen = bintool.Bintool.create('bootgen') + + # Read boot header in order to verify encryption source and + # encryption parameter + bootgen_out = bootgen.run_cmd("-arch", "zynqmp", + "-read", image_fname, "bh").splitlines() + attributes = {"auth_only": + {"re": r".*auth_only [([^]]+)]", "value": None}, + "encryption_keystore": + {"re": r" *encryption_keystore (0x28) : (.*)", + "value": None}, + } + + for l in bootgen_out: + for a in attributes.keys(): + if a in l: + m = re.match(attributes[a]['re'], l) + attributes[a] = m.group(1) + + # Check if fsbl-attribute is set correctly + self.assertTrue(attributes['auth_only'] == "true") + # Check if key is stored in efuse + self.assertTrue(attributes['encryption_keystore'] == "0xa5c3c5a3") +
def testSplPubkeyDtb(self): """Test u_boot_spl_pubkey_dtb etype""" diff --git a/tools/binman/test/280_xilinx_fsbl_auth.dts b/tools/binman/test/280_xilinx_fsbl_auth.dts new file mode 100644 index 0000000000..71b19edf44 --- /dev/null +++ b/tools/binman/test/280_xilinx_fsbl_auth.dts @@ -0,0 +1,21 @@ +// SPDX-License-Identifier: GPL-2.0+ + +/dts-v1/; + +/ { + #address-cells = <1>; + #size-cells = <1>; + + binman { + xilinx-fsbl-auth { + psk-key-name-hint = "psk"; + ssk-key-name-hint = "ssk"; + auth-params = "ppk_select=0", "spk_id=0x00000000"; + + u-boot-spl-nodtb { + }; + u-boot-spl-dtb { + }; + }; + }; +}; diff --git a/tools/binman/test/280_xilinx_fsbl_auth_enc.dts b/tools/binman/test/280_xilinx_fsbl_auth_enc.dts new file mode 100644 index 0000000000..4889ab4c27 --- /dev/null +++ b/tools/binman/test/280_xilinx_fsbl_auth_enc.dts @@ -0,0 +1,23 @@ +// SPDX-License-Identifier: GPL-2.0+ + +/dts-v1/; + +/ { + #address-cells = <1>; + #size-cells = <1>; + + binman { + xilinx-fsbl-auth { + psk-key-name-hint = "psk"; + ssk-key-name-hint = "ssk"; + auth-params = "ppk_select=0", "spk_id=0x00000000"; + fsbl-config = "auth_only"; + keysrc-enc = "efuse_red_key"; + + u-boot-spl-nodtb { + }; + u-boot-spl-dtb { + }; + }; + }; +};

On Tue, 18 Jul 2023 at 05:53, lukas.funke-oss@weidmueller.com wrote:
From: Lukas Funke lukas.funke@weidmueller.com
Add test for the 'xilinx_fsbl_auth' etype
Signed-off-by: Lukas Funke lukas.funke@weidmueller.com
Changes in v3:
- Improved test coverage for xilinx-fsbl-auth etype
Changes in v2:
- Fixed typo in dts name
tools/binman/ftest.py | 61 +++++++++++++++++++ tools/binman/test/280_xilinx_fsbl_auth.dts | 21 +++++++ .../binman/test/280_xilinx_fsbl_auth_enc.dts | 23 +++++++ 3 files changed, 105 insertions(+) create mode 100644 tools/binman/test/280_xilinx_fsbl_auth.dts create mode 100644 tools/binman/test/280_xilinx_fsbl_auth_enc.dts
Reviewed-by: Simon Glass sjg@chromium.org
Nice job on the test coverage!

From: Lukas Funke lukas.funke@weidmueller.com
This adds a new etype 'xilinx-fsbl-auth'. By using this etype it is possible to created an authenticated SPL (FSBL in Xilinx terms) for ZynqMP boards.
The etype uses Xilinx Bootgen tools in order to transform the SPL into a bootable image and sign the image with a given primary and secondary public key. For more information to signing the FSBL please refer to the Xilinx Bootgen documentation.
Here is an example of the etype in use:
spl { filename = "boot.signed.bin";
xilinx-fsbl-auth { psk-key-name-hint = "psk0"; ssk-key-name-hint = "ssk0"; auth-params = "ppk_select=0", "spk_id=0x00000000";
u-boot-spl-nodtb { }; u-boot-spl-dtb { }; }; };
For this to work the hash of the primary public key has to be fused into the ZynqMP device and authentication (RSA_EN) has to be set.
For testing purposes: if ppk hash check should be skipped one can add the property 'fsbl_config = "bh_auth_enable";' to the etype. However, this should only be used for testing(!).
Signed-off-by: Lukas Funke lukas.funke@weidmueller.com
---
Changes in v3: - Changed etype from entry to section - Changed property name "psk-filename" to "psk-key-name-hint" - Changed property name "ssk-filename" to "ssk-key-name-hint" - Decode spl elf file instead of reading start symbol - Improved test coverage - Improved documentation
Changes in v2: - Add 'keysrc-enc' property to pass down to Bootgen - Improved documentation - Use predictable output names for intermediated results
tools/binman/entries.rst | 71 ++++++++ tools/binman/etype/xilinx_fsbl_auth.py | 221 +++++++++++++++++++++++++ 2 files changed, 292 insertions(+) create mode 100644 tools/binman/etype/xilinx_fsbl_auth.py
diff --git a/tools/binman/entries.rst b/tools/binman/entries.rst index c368ea8053..47af8c7226 100644 --- a/tools/binman/entries.rst +++ b/tools/binman/entries.rst @@ -2462,3 +2462,74 @@ may be used instead.
+.. _etype_xilinx_fsbl_auth: + +Entry: xilinx-fsbl-auth: Authenticated SPL for booting Xilinx ZynqMP devices +---------------------------------------------------------------------------- + +Properties / Entry arguments: + - auth-params: (Optional) Authentication parameters passed to bootgen + - fsbl-config: (Optional) FSBL parameters passed to bootgen + - keysrc-enc: (Optional) Key source when using decryption engine + - pmufw-filename: Filename of PMU firmware. Default: pmu-firmware.elf + - psk-key-name-hint: Name of primary secret key to use for signing the + secondardy public key. Format: .pem file + - ssk-key-name-hint: Name of secondardy secret key to use for signing + the boot image. Format: .pem file + +The etype is used to create an authenticated boot image for Xilinx ZynqMP +devices. In AMD/Xilinx SoCs, two pairs of public and secret keys are used +- primary and secondary. The function of the primary public/secret key pair +is to authenticate the secondary public/secret key pair. +The function of the secondary key is to sign/verify the boot image. [1] + +AMD/Xilinx uses the following terms for private/public keys [1]: + + PSK = Primary Secret Key (Used to sign Secondary Public Key) + PPK = Primary Public Key (Used to verify Secondary Public Key) + SSK = Secondary Secret Key (Used to sign the boot image/partitions) + SPK = Used to verify the actual boot image + +The following example builds an authenticated boot image. The fuses of +the primary public key (ppk) should be fused together with the RSA_EN flag. + +Example node:: + + spl { + filename = "boot.signed.bin"; + + xilinx-fsbl-auth { + psk-key-name-hint = "psk0"; + ssk-key-name-hint = "ssk0"; + auth-params = "ppk_select=0", "spk_id=0x00000000"; + + u-boot-spl-nodtb { + }; + u-boot-spl-pubkey-dtb { + algo = "sha384,rsa4096"; + required = "conf"; + key-name-hint = "dev"; + }; + }; + }; + +For testing purposes, e.g. if no RSA_EN should be fused, one could add +the "bh_auth_enable" flag in the fsbl-config field. This will skip the +verification of the ppk fuses and boot the image, even if ppk hash is +invalid. + +Example node:: + + xilinx-fsbl-auth { + psk-key-name-hint = "psk0"; + psk-key-name-hint = "ssk0"; + ... + fsbl-config = "bh_auth_enable"; + ... + }; + +[1] https://docs.xilinx.com/r/en-US/ug1283-bootgen-user-guide/Using-Authenticati... + + + + diff --git a/tools/binman/etype/xilinx_fsbl_auth.py b/tools/binman/etype/xilinx_fsbl_auth.py new file mode 100644 index 0000000000..1f85784024 --- /dev/null +++ b/tools/binman/etype/xilinx_fsbl_auth.py @@ -0,0 +1,221 @@ +# SPDX-License-Identifier: GPL-2.0+ +# Copyright (c) 2023 Weidmueller GmbH +# Written by Lukas Funke lukas.funke@weidmueller.com +# +# Entry-type module for signed ZynqMP boot images (boot.bin) +# + +import tempfile + +from collections import OrderedDict + +from binman import elf +from binman.etype.section import Entry_section + +from dtoc import fdt_util + +from u_boot_pylib import tools +from u_boot_pylib import command + +# pylint: disable=C0103 +class Entry_xilinx_fsbl_auth(Entry_section): + """Authenticated SPL for booting Xilinx ZynqMP devices + + Properties / Entry arguments: + - auth-params: (Optional) Authentication parameters passed to bootgen + - fsbl-config: (Optional) FSBL parameters passed to bootgen + - keysrc-enc: (Optional) Key source when using decryption engine + - pmufw-filename: Filename of PMU firmware. Default: pmu-firmware.elf + - psk-key-name-hint: Name of primary secret key to use for signing the + secondardy public key. Format: .pem file + - ssk-key-name-hint: Name of secondardy secret key to use for signing + the boot image. Format: .pem file + + The etype is used to create an authenticated boot image for Xilinx ZynqMP + devices. In AMD/Xilinx SoCs, two pairs of public and secret keys are used + - primary and secondary. The function of the primary public/secret key pair + is to authenticate the secondary public/secret key pair. + The function of the secondary key is to sign/verify the boot image. [1] + + AMD/Xilinx uses the following terms for private/public keys [1]: + + PSK = Primary Secret Key (Used to sign Secondary Public Key) + PPK = Primary Public Key (Used to verify Secondary Public Key) + SSK = Secondary Secret Key (Used to sign the boot image/partitions) + SPK = Used to verify the actual boot image + + The following example builds an authenticated boot image. The fuses of + the primary public key (ppk) should be fused together with the RSA_EN flag. + + Example node:: + + spl { + filename = "boot.signed.bin"; + + xilinx-fsbl-auth { + psk-key-name-hint = "psk0"; + ssk-key-name-hint = "ssk0"; + auth-params = "ppk_select=0", "spk_id=0x00000000"; + + u-boot-spl-nodtb { + }; + u-boot-spl-pubkey-dtb { + algo = "sha384,rsa4096"; + required = "conf"; + key-name-hint = "dev"; + }; + }; + }; + + For testing purposes, e.g. if no RSA_EN should be fused, one could add + the "bh_auth_enable" flag in the fsbl-config field. This will skip the + verification of the ppk fuses and boot the image, even if ppk hash is + invalid. + + Example node:: + + xilinx-fsbl-auth { + psk-key-name-hint = "psk0"; + psk-key-name-hint = "ssk0"; + ... + fsbl-config = "bh_auth_enable"; + ... + }; + + [1] https://docs.xilinx.com/r/en-US/ug1283-bootgen-user-guide/Using-Authenticati... + + """ + def __init__(self, section, etype, node): + super().__init__(section, etype, node) + self._auth_params = None + self._entries = OrderedDict() + self._filename = None + self._fsbl_config = None + self._keysrc_enc = None + self._pmufw_filename = None + self._psk_key_name_hint = None + self._ssk_key_name_hint = None + self.align_default = None + self.bootgen = None + self.required_props = ['psk-key-name-hint', 'ssk-key-name-hint'] + + def ReadNode(self): + """Read properties from the xilinx_fsbl_auth node""" + super().ReadNode() + self._auth_params = fdt_util.GetStringList(self._node, + 'auth-params') + self._filename = fdt_util.GetString(self._node, 'filename') + self._fsbl_config = fdt_util.GetStringList(self._node, + 'fsbl-config') + self._keysrc_enc = fdt_util.GetString(self._node, + 'keysrc-enc') + self._pmufw_filename = fdt_util.GetString(self._node, + 'pmufw-filename', + 'pmu-firmware.elf') + self._psk_key_name_hint = fdt_util.GetString(self._node, + 'psk-key-name-hint', + 'psk.pem') + self._ssk_key_name_hint = fdt_util.GetString(self._node, + 'psk-key-name-hint', + 'ssk.pem') + self.ReadEntries() + + @classmethod + def _ToElf(cls, data, output_fname): + """Convert SPL object file to bootable ELF file. + + Args: + data (bytearray): u-boot-spl-nodtb + u-boot-spl-pubkey-dtb obj file + data + output_fname (str): Filename of converted FSBL ELF file + """ + platform_elfflags = {"aarch64": + ["-B", "aarch64", "-O", "elf64-littleaarch64"], + # amd64 support makes no sense for the target + # platform, but we include it here to enable + # testing on hosts + "x86_64": + ["-B", "i386", "-O", "elf64-x86-64"] + } + + gcc, args = tools.get_target_compile_tool('cc') + args += ['-dumpmachine'] + stdout = command.output(gcc, *args) + # split target machine triplet (arch, vendor, os) + arch, _, _ = stdout.split('-') + + spl_elf = elf.DecodeElf(tools.read_file( + tools.get_input_filename('spl/u-boot-spl')), 0) + + # Obj file to swap data and text section (rename-section) + with tempfile.NamedTemporaryFile(prefix="u-boot-spl-pubkey-", + suffix=".o.tmp", + dir=tools.get_output_dir())\ + as tmp_obj: + input_objcopy_fname = tmp_obj.name + # Align packed content to 4 byte boundary + pad = bytearray(tools.align(len(data), 4) - len(data)) + tools.write_file(input_objcopy_fname, data + pad) + # Final output elf file which contains a valid start address + with tempfile.NamedTemporaryFile(prefix="u-boot-spl-pubkey-elf-", + suffix=".o.tmp", + dir=tools.get_output_dir())\ + as tmp_elf_obj: + input_ld_fname = tmp_elf_obj.name + objcopy, args = tools.get_target_compile_tool('objcopy') + args += ["--rename-section", ".data=.text", + "-I", "binary"] + args += platform_elfflags[arch] + args += [input_objcopy_fname, input_ld_fname] + command.run(objcopy, *args) + + ld, args = tools.get_target_compile_tool('ld') + args += [input_ld_fname, '-o', output_fname, + "--defsym", f"_start={hex(spl_elf.entry)}", + "-Ttext", hex(spl_elf.entry)] + command.run(ld, *args) + + def BuildSectionData(self, required): + """Pack node content, and create bootable, signed ZynqMP boot image + + The method collects the content of this node (usually SPL + dtb) and + converts them to an ELF file. The ELF file is passed to the + Xilinx bootgen tool which packs the SPL ELF file together with + Platform Management Unit (PMU) firmware into a bootable image + for ZynqMP devices. The image is signed within this step. + + The result is a bootable, authenticated SPL image for Xilinx ZynqMP + devices. + + """ + data = super().BuildSectionData(required) + bootbin_fname = self._filename if self._filename else \ + tools.get_output_filename( + f'boot.{self.GetUniqueName()}.bin') + + pmufw_elf_fname = tools.get_input_filename(self._pmufw_filename) + psk_fname = tools.get_input_filename(self._psk_key_name_hint + ".pem") + ssk_fname = tools.get_input_filename(self._ssk_key_name_hint + ".pem") + fsbl_config = ";".join(self._fsbl_config) if self._fsbl_config else None + auth_params = ";".join(self._auth_params) if self._auth_params else None + + spl_elf_fname = tools.get_output_filename('u-boot-spl-pubkey.dtb.elf') + + # We need to convert to node content (see above) into an ELF + # file in order to be processed by bootgen. + self._ToElf(bytearray(data), spl_elf_fname) + + # Call Bootgen in order to sign the SPL + self.bootgen.sign('zynqmp', spl_elf_fname, pmufw_elf_fname, + psk_fname, ssk_fname, fsbl_config, + auth_params, self._keysrc_enc, bootbin_fname) + + data = tools.read_file(bootbin_fname) + self.SetContents(data) + + return data + + # pylint: disable=C0116 + def AddBintools(self, btools): + super().AddBintools(btools) + self.bootgen = self.AddBintool(btools, 'bootgen')

On Tue, 18 Jul 2023 at 05:53, lukas.funke-oss@weidmueller.com wrote:
From: Lukas Funke lukas.funke@weidmueller.com
This adds a new etype 'xilinx-fsbl-auth'. By using this etype it is possible to created an authenticated SPL (FSBL in Xilinx terms) for ZynqMP boards.
The etype uses Xilinx Bootgen tools in order to transform the SPL into a bootable image and sign the image with a given primary and secondary public key. For more information to signing the FSBL please refer to the Xilinx Bootgen documentation.
Here is an example of the etype in use:
spl { filename = "boot.signed.bin"; xilinx-fsbl-auth { psk-key-name-hint = "psk0"; ssk-key-name-hint = "ssk0"; auth-params = "ppk_select=0", "spk_id=0x00000000"; u-boot-spl-nodtb { }; u-boot-spl-dtb { }; }; };
For this to work the hash of the primary public key has to be fused into the ZynqMP device and authentication (RSA_EN) has to be set.
For testing purposes: if ppk hash check should be skipped one can add the property 'fsbl_config = "bh_auth_enable";' to the etype. However, this should only be used for testing(!).
Signed-off-by: Lukas Funke lukas.funke@weidmueller.com
Changes in v3:
- Changed etype from entry to section
- Changed property name "psk-filename" to "psk-key-name-hint"
- Changed property name "ssk-filename" to "ssk-key-name-hint"
- Decode spl elf file instead of reading start symbol
- Improved test coverage
- Improved documentation
Changes in v2:
- Add 'keysrc-enc' property to pass down to Bootgen
- Improved documentation
- Use predictable output names for intermediated results
tools/binman/entries.rst | 71 ++++++++ tools/binman/etype/xilinx_fsbl_auth.py | 221 +++++++++++++++++++++++++ 2 files changed, 292 insertions(+) create mode 100644 tools/binman/etype/xilinx_fsbl_auth.py
Reviewed-by: Simon Glass sjg@chromium.org

Hi,
On Tue, 18 Jul 2023 at 05:53, lukas.funke-oss@weidmueller.com wrote:
From: Lukas Funke lukas.funke@weidmueller.com
This series adds two etypes to create a verified boot chain for Xilinx ZynqMP devices. The first etype 'xilinx-fsbl-auth' is used to create a bootable, signed image for ZynqMP boards using the Xilinx Bootgen tool. The second etype 'u-boot-spl-pubkey-dtb' is used to add a '/signature' node to the SPL. The public key in the signature is read from a certificate file and added using the 'fdt_add_pubkey' tool. The series also contains the corresponding btool for calling 'bootgen' and 'fdt_add_pubkey'.
The following block shows an example on how to use this functionality:
spl { filename = "boot.signed.bin"; xilinx-fsbl-auth { psk-key-name-hint = "psk0"; ssk-key-name-hint = "ssk0"; auth-params = "ppk_select=0", "spk_id=0x00000000"; u-boot-spl-nodtb { }; u-boot-spl-pubkey-dtb { algo = "sha384,rsa4096"; required = "conf"; key-name-hint = "dev"; }; }; };
Changes in v3:
- Improved test coverage regarding missing libelf
- Align error message
- Fix rst headline length
- Add newline before main
- Adapted test due to property renaming
- Fixed minor python doc typo in u-boot-spl-pubkey-dtb etype
- Renamed key property from 'key-name' to 'key-name-hint'
- Fixed an issue where the build result was not found
- Fixed an issue where the version string was not reported correctly
- Improved test coverage for xilinx-fsbl-auth etype
- Changed etype from entry to section
- Changed property name "psk-filename" to "psk-key-name-hint"
- Changed property name "ssk-filename" to "ssk-key-name-hint"
- Decode spl elf file instead of reading start symbol
- Improved test coverage
- Improved documentation
Changes in v2:
- Changed u_boot_spl_pubkey_dtb to u-boot-spl-pubkey-dtb
- Improved rst/python documentation
- Changed u_boot_spl_pubkey_dtb to u-boot-spl-pubkey-dtb in example
- Pass additional 'keysrc_enc' parameter to Bootgen
- Added more information and terms to documentation
- Fixed typo in dts name
- Add 'keysrc-enc' property to pass down to Bootgen
- Improved documentation
- Use predictable output names for intermediated results
Lukas Funke (11): binman: elf: Check for ELF_TOOLS availability and remove extra semicolon binman: Don't decompress data while signing binman: blob_dtb: Add fake_size argument to ObtainContents() binman: doc: Add documentation for fdt_add_pubkey bintool binman: ftest: Add test for u_boot_spl_pubkey_dtb binman: btool: Add fdt_add_pubkey as btool binman: etype: Add u-boot-spl-pubkey-dtb etype binman: doc: Add documentation for Xilinx Bootgen bintool binman: btool: Add Xilinx Bootgen btool binman: ftest: Add test for xilinx_fsbl_auth etype binman: etype: Add xilinx_fsbl_auth etype
tools/binman/bintools.rst | 22 ++ tools/binman/btool/bootgen.py | 136 +++++++++++ tools/binman/btool/fdt_add_pubkey.py | 67 ++++++ tools/binman/control.py | 2 +- tools/binman/elf.py | 14 +- tools/binman/elf_test.py | 11 + tools/binman/entries.rst | 110 +++++++++ tools/binman/etype/blob_dtb.py | 2 +- tools/binman/etype/u_boot_spl_pubkey_dtb.py | 109 +++++++++ tools/binman/etype/xilinx_fsbl_auth.py | 221 ++++++++++++++++++ tools/binman/ftest.py | 94 ++++++++ tools/binman/test/280_xilinx_fsbl_auth.dts | 21 ++ .../binman/test/280_xilinx_fsbl_auth_enc.dts | 23 ++ tools/binman/test/281_spl_pubkey_dtb.dts | 16 ++ 14 files changed, 839 insertions(+), 9 deletions(-) create mode 100644 tools/binman/btool/bootgen.py create mode 100644 tools/binman/btool/fdt_add_pubkey.py create mode 100644 tools/binman/etype/u_boot_spl_pubkey_dtb.py create mode 100644 tools/binman/etype/xilinx_fsbl_auth.py create mode 100644 tools/binman/test/280_xilinx_fsbl_auth.dts create mode 100644 tools/binman/test/280_xilinx_fsbl_auth_enc.dts create mode 100644 tools/binman/test/281_spl_pubkey_dtb.dts
-- 2.30.2
With this I get test failures:
====================================================================== ERROR: binman.ftest.TestFunctional.testXilinxFsblAuthAndEncryption (subunit.RemotedTestCase) binman.ftest.TestFunctional.testXilinxFsblAuthAndEncryption ---------------------------------------------------------------------- testtools.testresult.real._StringException: Traceback (most recent call last): File "/scratch/sglass/cosarm/src/third_party/u-boot/files/tools/binman/ftest.py", line 6932, in testXilinxFsblAuthAndEncryption self._DoReadFileRealDtb('280_xilinx_fsbl_auth_enc.dts') File "/scratch/sglass/cosarm/src/third_party/u-boot/files/tools/binman/ftest.py", line 561, in _DoReadFileRealDtb return self._DoReadFileDtb(fname, use_real_dtb=True, update_dtb=True)[0] File "/scratch/sglass/cosarm/src/third_party/u-boot/files/tools/binman/ftest.py", line 528, in _DoReadFileDtb retcode = self._DoTestFile(fname, map=map, update_dtb=update_dtb, File "/scratch/sglass/cosarm/src/third_party/u-boot/files/tools/binman/ftest.py", line 427, in _DoTestFile return self._DoBinman(*args) File "/scratch/sglass/cosarm/src/third_party/u-boot/files/tools/binman/ftest.py", line 343, in _DoBinman return control.Binman(args) File "/scratch/sglass/cosarm/src/third_party/u-boot/files/tools/binman/control.py", line 815, in Binman invalid |= ProcessImage(image, args.update_fdt, args.map, File "/scratch/sglass/cosarm/src/third_party/u-boot/files/tools/binman/control.py", line 632, in ProcessImage image.PackEntries() File "/scratch/sglass/cosarm/src/third_party/u-boot/files/tools/binman/image.py", line 154, in PackEntries super().Pack(0) File "/scratch/sglass/cosarm/src/third_party/u-boot/files/tools/binman/etype/section.py", line 433, in Pack self._PackEntries() File "/scratch/sglass/cosarm/src/third_party/u-boot/files/tools/binman/etype/section.py", line 454, in _PackEntries offset = entry.Pack(offset) File "/scratch/sglass/cosarm/src/third_party/u-boot/files/tools/binman/etype/section.py", line 441, in Pack data = self.BuildSectionData(True) File "/scratch/sglass/cosarm/src/third_party/u-boot/files/tools/binman/etype/xilinx_fsbl_auth.py", line 213, in BuildSectionData data = tools.read_file(bootbin_fname) File "/scratch/sglass/cosarm/src/third_party/u-boot/files/tools/u_boot_pylib/tools.py", line 467, in read_file with open(filename(fname), binary and 'rb' or 'r') as fd: FileNotFoundError: [Errno 2] No such file or directory: '/tmp/binman.q0wccwnl/boot.xilinx-fsbl-auth.bin'
====================================================================== ERROR: binman.ftest.TestFunctional.testXilinxFsblAuth (subunit.RemotedTestCase) binman.ftest.TestFunctional.testXilinxFsblAuth ---------------------------------------------------------------------- testtools.testresult.real._StringException: Traceback (most recent call last): File "/scratch/sglass/cosarm/src/third_party/u-boot/files/tools/binman/ftest.py", line 6904, in testXilinxFsblAuth self._DoReadFileRealDtb('280_xilinx_fsbl_auth.dts') File "/scratch/sglass/cosarm/src/third_party/u-boot/files/tools/binman/ftest.py", line 561, in _DoReadFileRealDtb return self._DoReadFileDtb(fname, use_real_dtb=True, update_dtb=True)[0] File "/scratch/sglass/cosarm/src/third_party/u-boot/files/tools/binman/ftest.py", line 528, in _DoReadFileDtb retcode = self._DoTestFile(fname, map=map, update_dtb=update_dtb, File "/scratch/sglass/cosarm/src/third_party/u-boot/files/tools/binman/ftest.py", line 427, in _DoTestFile return self._DoBinman(*args) File "/scratch/sglass/cosarm/src/third_party/u-boot/files/tools/binman/ftest.py", line 343, in _DoBinman return control.Binman(args) File "/scratch/sglass/cosarm/src/third_party/u-boot/files/tools/binman/control.py", line 815, in Binman invalid |= ProcessImage(image, args.update_fdt, args.map, File "/scratch/sglass/cosarm/src/third_party/u-boot/files/tools/binman/control.py", line 632, in ProcessImage image.PackEntries() File "/scratch/sglass/cosarm/src/third_party/u-boot/files/tools/binman/image.py", line 154, in PackEntries super().Pack(0) File "/scratch/sglass/cosarm/src/third_party/u-boot/files/tools/binman/etype/section.py", line 433, in Pack self._PackEntries() File "/scratch/sglass/cosarm/src/third_party/u-boot/files/tools/binman/etype/section.py", line 454, in _PackEntries offset = entry.Pack(offset) File "/scratch/sglass/cosarm/src/third_party/u-boot/files/tools/binman/etype/section.py", line 441, in Pack data = self.BuildSectionData(True) File "/scratch/sglass/cosarm/src/third_party/u-boot/files/tools/binman/etype/xilinx_fsbl_auth.py", line 213, in BuildSectionData data = tools.read_file(bootbin_fname) File "/scratch/sglass/cosarm/src/third_party/u-boot/files/tools/u_boot_pylib/tools.py", line 467, in read_file with open(filename(fname), binary and 'rb' or 'r') as fd: FileNotFoundError: [Errno 2] No such file or directory: '/tmp/binman.k7fg_p9o/boot.xilinx-fsbl-auth.bin'
====================================================================== FAIL: binman.ftest.TestFunctional.testSymbolsElfBad (subunit.RemotedTestCase) binman.ftest.TestFunctional.testSymbolsElfBad ---------------------------------------------------------------------- testtools.testresult.real._StringException: Traceback (most recent call last): File "/scratch/sglass/cosarm/src/third_party/u-boot/files/tools/binman/ftest.py", line 6242, in testSymbolsElfBad self.assertIn( File "/usr/lib/python3.10/unittest/case.py", line 1112, in assertIn self.fail(self._formatMessage(msg, standardMsg)) File "/usr/lib/python3.10/unittest/case.py", line 675, in fail raise self.failureException(msg) AssertionError: "Section '/binman': entry '/binman/u-boot-spl-elf': Cannot write symbols to an ELF file without Python elftools" not found in "Python: No module named 'elftools'"
Regards, Simon

On 7/18/23 13:53, lukas.funke-oss@weidmueller.com wrote:
From: Lukas Funke lukas.funke@weidmueller.com
This series adds two etypes to create a verified boot chain for Xilinx ZynqMP devices. The first etype 'xilinx-fsbl-auth' is used to create a bootable, signed image for ZynqMP boards using the Xilinx Bootgen tool. The second etype 'u-boot-spl-pubkey-dtb' is used to add a '/signature' node to the SPL. The public key in the signature is read from a certificate file and added using the 'fdt_add_pubkey' tool. The series also contains the corresponding btool for calling 'bootgen' and 'fdt_add_pubkey'.
The following block shows an example on how to use this functionality:
spl { filename = "boot.signed.bin"; xilinx-fsbl-auth { psk-key-name-hint = "psk0"; ssk-key-name-hint = "ssk0"; auth-params = "ppk_select=0", "spk_id=0x00000000"; u-boot-spl-nodtb { }; u-boot-spl-pubkey-dtb { algo = "sha384,rsa4096"; required = "conf"; key-name-hint = "dev"; }; }; };
I was looking at binman couple of times in past but never had time to do any development with it. Maybe it is good opportunity to look at it now with this series. Is there a way to see more verbose output?
I expect that keys should be generated as is described here.
https://docs.xilinx.com/r/en-US/ug1283-bootgen-user-guide/Key-Generation?toc...
Anyway I tried to use u-boot-spl-nodtb like this.
&binman { spl { filename = "boot.signed.bin"; xilinx-fsbl-auth { psk-key-name-hint = "/tmp/ddd/psk0"; ssk-key-name-hint = "/tmp/ddd/ssk0"; auth-params = "ppk_select=0", "spk_id=0x00000000"; pmufw-filename = "/mnt/disk/u-boot-bins/zynqmp/zynqmp-zcu102-revA/pmufw.elf";
u-boot-spl-nodtb { }; }; }; };
but getting error BINMAN .binman_stamp Using input directories ['.', '.', './board/xilinx/zynqmp', 'arch/arm/dts'] Using output directory '.' Processing entry args: of-list = avnet-ultra96-rev1 zynqmp-a2197-revA zynqmp-e-a2197-00-revA zynqmp-g-a2197-00-revA zynqmp-m-a2197-01-revA zynqmp-m-a2197-02-revA zynqmp-m-a2197-03-revA zynqmp-p-a2197-00-revA zynqmp-zc1232-revA zynqmp-zc1254-revA zynqmp-zc1751-xm015-dc1 zynqmp-zc1751-xm016-dc2 zynqmp-zc1751-xm017-dc3 zynqmp-zc1751-xm018-dc4 zynqmp-zc1751-xm019-dc5 zynqmp-zcu100-revC zynqmp-zcu102-rev1.1 zynqmp-zcu102-rev1.0 zynqmp-zcu102-revA zynqmp-zcu102-revB zynqmp-zcu104-revA zynqmp-zcu104-revC zynqmp-zcu106-revA zynqmp-zcu106-rev1.0 zynqmp-zcu111-revA zynqmp-zcu1275-revA zynqmp-zcu1275-revB zynqmp-zcu1285-revA zynqmp-zcu208-revA zynqmp-zcu216-revA zynqmp-topic-miamimp-xilinx-xdp-v1r1 zynqmp-sm-k26-revA zynqmp-smk-k26-revA zynqmp-dlc21-revA atf-bl31-path = /tftpboot/bl31.bin tee-os-path = /tftpboot/tee.bin opensbi-path = default-dt = zynqmp-zcu100-revC scp-path = rockchip-tpl-path = spl-bss-pad = tpl-bss-pad = 1 spl-dtb = y tpl-dtb = pre-load-key-path = Processing entry args done Node '/binman/spl/xilinx-fsbl-auth/u-boot-spl-nodtb': Packing: offset=None, size=None, content_size=240d8 Node '/binman/spl/xilinx-fsbl-auth/u-boot-spl-nodtb': - packed: offset=0x0, size=0x240d8, content_size=0x240d8, next_offset=240d8 Node '/binman/spl/xilinx-fsbl-auth/u-boot-spl-nodtb': GetData: size 0x240d8 Node '/binman/spl/xilinx-fsbl-auth': GetPaddedDataForEntry: size None Node '/binman/spl/xilinx-fsbl-auth': GetData: 1 entries, total size 0x240d8 bintool: bootgen -arch zynqmp -image ./bootgen-in.sign.bif -w -o ./boot.spl.xilinx-fsbl-auth.bin
****** Xilinx Bootgen v2022.2.0 **** Build date : Oct 13 2022-12:22:43 ** Copyright 1986-2022 Xilinx, Inc. All Rights Reserved.
[WARNING]: Authentication padding scheme will be as per silicon 2.0(ES2) and above. The image generated will NOT work for 1.0(ES1). Use '-zynqmpes1' to generate image for 1.0(ES1)
[INFO] : Bootimage generated successfully
Node '/binman/spl': GetPaddedDataForEntry: size None Node '/binman/spl/xilinx-fsbl-auth': Packing: offset=None, size=0x47280, content_size=47280 Node '/binman/spl/xilinx-fsbl-auth': - packed: offset=0x0, size=0x47280, content_size=0x47280, next_offset=47280 Node '/binman/spl/xilinx-fsbl-auth/u-boot-spl-nodtb': GetData: size 0x240d8 Node '/binman/spl/xilinx-fsbl-auth': GetPaddedDataForEntry: size 0x47280 Node '/binman/spl/xilinx-fsbl-auth': GetData: 1 entries, total size 0x240d8 bintool: bootgen -arch zynqmp -image ./bootgen-in.sign.bif -w -o ./boot.spl.xilinx-fsbl-auth.bin
****** Xilinx Bootgen v2022.2.0 **** Build date : Oct 13 2022-12:22:43 ** Copyright 1986-2022 Xilinx, Inc. All Rights Reserved.
[WARNING]: Authentication padding scheme will be as per silicon 2.0(ES2) and above. The image generated will NOT work for 1.0(ES1). Use '-zynqmpes1' to generate image for 1.0(ES1)
[INFO] : Bootimage generated successfully
Node '/binman/spl': GetPaddedDataForEntry: size None Node '/binman/spl': GetData: 1 entries, total size 0x47280 Node '/binman/spl': GetPaddedDataForEntry: size 0x47280 Node '/binman/spl': Packing: offset=None, size=0x47280, content_size=47280 Node '/binman/spl': - packed: offset=0x0, size=0x47280, content_size=0x47280, next_offset=47280 File ./u-boot.dtb.out: Update node '/binman/spl' prop 'offset' to 0x0 File ./u-boot.dtb.out: Update node '/binman/spl' prop 'size' to 0x47280 File ./u-boot.dtb.out: Update node '/binman/spl' prop 'image-pos' to 0x0 File ./u-boot.dtb.out: Update node '/binman/spl/xilinx-fsbl-auth' prop 'offset' to 0x0 File ./u-boot.dtb.out: Update node '/binman/spl/xilinx-fsbl-auth' prop 'size' to 0x47280 File ./u-boot.dtb.out: Update node '/binman/spl/xilinx-fsbl-auth' prop 'image-pos' to 0x0 File ./u-boot.dtb.out: Update node '/binman/spl/xilinx-fsbl-auth/u-boot-spl-nodtb' prop 'offset' to 0x0 File ./u-boot.dtb.out: Update node '/binman/spl/xilinx-fsbl-auth/u-boot-spl-nodtb' prop 'size' to 0x240d8 File ./u-boot.dtb.out: Update node '/binman/spl/xilinx-fsbl-auth/u-boot-spl-nodtb' prop 'image-pos' to 0x0 Section '/binman/spl': Symbol '_binman_sym_magic' in entry '/binman/spl/xilinx-fsbl-auth/u-boot-spl-nodtb': insert _binman_sym_magic, offset 22f80, value 4d595342, length 8 binman: Section '/binman/spl': Symbol '_binman_u_boot_any_prop_image_pos' in entry '/binman/spl/xilinx-fsbl-auth/u-boot-spl-nodtb': Entry 'u-boot-any' not found in list (u-boot-spl-nodtb,xilinx-fsbl-auth,spl)
Traceback (most recent call last): File "/home/monstr/data/disk/u-boot/./tools/binman/binman", line 134, in RunBinman ret_code = control.Binman(args) File "/home/monstr/data/disk/u-boot/tools/binman/control.py", line 787, in Binman invalid |= ProcessImage(image, args.update_fdt, args.map, File "/home/monstr/data/disk/u-boot/tools/binman/control.py", line 616, in ProcessImage image.WriteSymbols() File "/home/monstr/data/disk/u-boot/tools/binman/image.py", line 172, in WriteSymbols super().WriteSymbols(self) File "/home/monstr/data/disk/u-boot/tools/binman/etype/section.py", line 499, in WriteSymbols entry.WriteSymbols(self) File "/home/monstr/data/disk/u-boot/tools/binman/etype/section.py", line 499, in WriteSymbols entry.WriteSymbols(self) File "/home/monstr/data/disk/u-boot/tools/binman/entry.py", line 701, in WriteSymbols elf.LookupAndWriteSymbols(self.elf_fname, self, section.GetImage(), File "/home/monstr/data/disk/u-boot/tools/binman/elf.py", line 298, in LookupAndWriteSymbols value = section.GetImage().LookupImageSymbol(name, sym.weak, File "/home/monstr/data/disk/u-boot/tools/binman/image.py", line 404, in LookupImageSymbol return self.LookupSymbol(sym_name, optional, msg, base_addr, File "/home/monstr/data/disk/u-boot/tools/binman/etype/section.py", line 650, in LookupSymbol raise ValueError(err) ValueError: Section '/binman/spl': Symbol '_binman_u_boot_any_prop_image_pos' in entry '/binman/spl/xilinx-fsbl-auth/u-boot-spl-nodtb': Entry 'u-boot-any' not found in list (u-boot-spl-nodtb,xilinx-fsbl-auth,spl) make: *** [Makefile:1115: .binman_stamp] Error 1
with u-boot-spl-dtb it works fine.
Anyway kind of curious if that support can be more generalized that bif can be generated for other configurations too. It means
xilinx-bootgen { pmufw-filename = "/mnt/disk/u-boot-bins/zynqmp/zynqmp-zcu102-revA/pmufw.elf";
u-boot-spl-dtb { }; };
you will get boot.bin which images you defined.
And regarding name "xilinx-fsbl-auth". That authentication is done by bootrom not by FSBL that's why you should maybe consider to rename it. And as you wrote "arch (str): Xilinx SoC architecture. Currently only 'zynqmp' is supported." then I expect in future this can be extended for on other SOCs which don't have FSBL unless you will use it as generic name first stage bootloader.
That's why I would say xilinx-bootgen would be maybe better name even if it has tool name there.
Thanks, Michal

Hi Michal,
On Fri, 21 Jul 2023 at 08:41, Michal Simek michal.simek@amd.com wrote:
On 7/18/23 13:53, lukas.funke-oss@weidmueller.com wrote:
From: Lukas Funke lukas.funke@weidmueller.com
This series adds two etypes to create a verified boot chain for Xilinx ZynqMP devices. The first etype 'xilinx-fsbl-auth' is used to create a bootable, signed image for ZynqMP boards using the Xilinx Bootgen tool. The second etype 'u-boot-spl-pubkey-dtb' is used to add a '/signature' node to the SPL. The public key in the signature is read from a certificate file and added using the 'fdt_add_pubkey' tool. The series also contains the corresponding btool for calling 'bootgen' and 'fdt_add_pubkey'.
The following block shows an example on how to use this functionality:
spl { filename = "boot.signed.bin"; xilinx-fsbl-auth { psk-key-name-hint = "psk0"; ssk-key-name-hint = "ssk0"; auth-params = "ppk_select=0", "spk_id=0x00000000"; u-boot-spl-nodtb { }; u-boot-spl-pubkey-dtb { algo = "sha384,rsa4096"; required = "conf"; key-name-hint = "dev"; }; }; };
I was looking at binman couple of times in past but never had time to do any development with it. Maybe it is good opportunity to look at it now with this series. Is there a way to see more verbose output?
https://u-boot.readthedocs.io/en/latest/develop/package/binman.html#logging
I expect that keys should be generated as is described here.
https://docs.xilinx.com/r/en-US/ug1283-bootgen-user-guide/Key-Generation?toc...
Anyway I tried to use u-boot-spl-nodtb like this.
&binman { spl { filename = "boot.signed.bin";
xilinx-fsbl-auth { psk-key-name-hint = "/tmp/ddd/psk0"; ssk-key-name-hint = "/tmp/ddd/ssk0"; auth-params = "ppk_select=0", "spk_id=0x00000000"; pmufw-filename = "/mnt/disk/u-boot-bins/zynqmp/zynqmp-zcu102-revA/pmufw.elf"; u-boot-spl-nodtb { }; }; };
};
but getting error BINMAN .binman_stamp Using input directories ['.', '.', './board/xilinx/zynqmp', 'arch/arm/dts'] Using output directory '.' Processing entry args: of-list = avnet-ultra96-rev1 zynqmp-a2197-revA zynqmp-e-a2197-00-revA zynqmp-g-a2197-00-revA zynqmp-m-a2197-01-revA zynqmp-m-a2197-02-revA zynqmp-m-a2197-03-revA zynqmp-p-a2197-00-revA zynqmp-zc1232-revA zynqmp-zc1254-revA zynqmp-zc1751-xm015-dc1 zynqmp-zc1751-xm016-dc2 zynqmp-zc1751-xm017-dc3 zynqmp-zc1751-xm018-dc4 zynqmp-zc1751-xm019-dc5 zynqmp-zcu100-revC zynqmp-zcu102-rev1.1 zynqmp-zcu102-rev1.0 zynqmp-zcu102-revA zynqmp-zcu102-revB zynqmp-zcu104-revA zynqmp-zcu104-revC zynqmp-zcu106-revA zynqmp-zcu106-rev1.0 zynqmp-zcu111-revA zynqmp-zcu1275-revA zynqmp-zcu1275-revB zynqmp-zcu1285-revA zynqmp-zcu208-revA zynqmp-zcu216-revA zynqmp-topic-miamimp-xilinx-xdp-v1r1 zynqmp-sm-k26-revA zynqmp-smk-k26-revA zynqmp-dlc21-revA atf-bl31-path = /tftpboot/bl31.bin tee-os-path = /tftpboot/tee.bin opensbi-path = default-dt = zynqmp-zcu100-revC scp-path = rockchip-tpl-path = spl-bss-pad = tpl-bss-pad = 1 spl-dtb = y tpl-dtb = pre-load-key-path = Processing entry args done Node '/binman/spl/xilinx-fsbl-auth/u-boot-spl-nodtb': Packing: offset=None, size=None, content_size=240d8 Node '/binman/spl/xilinx-fsbl-auth/u-boot-spl-nodtb': - packed: offset=0x0, size=0x240d8, content_size=0x240d8, next_offset=240d8 Node '/binman/spl/xilinx-fsbl-auth/u-boot-spl-nodtb': GetData: size 0x240d8 Node '/binman/spl/xilinx-fsbl-auth': GetPaddedDataForEntry: size None Node '/binman/spl/xilinx-fsbl-auth': GetData: 1 entries, total size 0x240d8 bintool: bootgen -arch zynqmp -image ./bootgen-in.sign.bif -w -o ./boot.spl.xilinx-fsbl-auth.bin
****** Xilinx Bootgen v2022.2.0 **** Build date : Oct 13 2022-12:22:43 ** Copyright 1986-2022 Xilinx, Inc. All Rights Reserved.
[WARNING]: Authentication padding scheme will be as per silicon 2.0(ES2) and above. The image generated will NOT work for 1.0(ES1). Use '-zynqmpes1' to generate image for 1.0(ES1)
[INFO] : Bootimage generated successfully
BTW tools are not allowed to generate output normally, so this will need to be suppressed somehow by the binman btool.
Regards, Simon

Hi again,
On Sat, 22 Jul 2023 at 21:48, Simon Glass sjg@chromium.org wrote:
Hi Michal,
On Fri, 21 Jul 2023 at 08:41, Michal Simek michal.simek@amd.com wrote:
On 7/18/23 13:53, lukas.funke-oss@weidmueller.com wrote:
From: Lukas Funke lukas.funke@weidmueller.com
This series adds two etypes to create a verified boot chain for Xilinx ZynqMP devices. The first etype 'xilinx-fsbl-auth' is used to create a bootable, signed image for ZynqMP boards using the Xilinx Bootgen tool. The second etype 'u-boot-spl-pubkey-dtb' is used to add a '/signature' node to the SPL. The public key in the signature is read from a certificate file and added using the 'fdt_add_pubkey' tool. The series also contains the corresponding btool for calling 'bootgen' and 'fdt_add_pubkey'.
The following block shows an example on how to use this functionality:
spl { filename = "boot.signed.bin"; xilinx-fsbl-auth { psk-key-name-hint = "psk0"; ssk-key-name-hint = "ssk0"; auth-params = "ppk_select=0", "spk_id=0x00000000"; u-boot-spl-nodtb { }; u-boot-spl-pubkey-dtb { algo = "sha384,rsa4096"; required = "conf"; key-name-hint = "dev"; }; }; };
I was looking at binman couple of times in past but never had time to do any development with it. Maybe it is good opportunity to look at it now with this series. Is there a way to see more verbose output?
https://u-boot.readthedocs.io/en/latest/develop/package/binman.html#logging
I expect that keys should be generated as is described here.
https://docs.xilinx.com/r/en-US/ug1283-bootgen-user-guide/Key-Generation?toc...
Anyway I tried to use u-boot-spl-nodtb like this.
&binman { spl { filename = "boot.signed.bin";
xilinx-fsbl-auth { psk-key-name-hint = "/tmp/ddd/psk0"; ssk-key-name-hint = "/tmp/ddd/ssk0"; auth-params = "ppk_select=0", "spk_id=0x00000000"; pmufw-filename = "/mnt/disk/u-boot-bins/zynqmp/zynqmp-zcu102-revA/pmufw.elf"; u-boot-spl-nodtb { }; }; };
};
but getting error BINMAN .binman_stamp Using input directories ['.', '.', './board/xilinx/zynqmp', 'arch/arm/dts'] Using output directory '.' Processing entry args: of-list = avnet-ultra96-rev1 zynqmp-a2197-revA zynqmp-e-a2197-00-revA zynqmp-g-a2197-00-revA zynqmp-m-a2197-01-revA zynqmp-m-a2197-02-revA zynqmp-m-a2197-03-revA zynqmp-p-a2197-00-revA zynqmp-zc1232-revA zynqmp-zc1254-revA zynqmp-zc1751-xm015-dc1 zynqmp-zc1751-xm016-dc2 zynqmp-zc1751-xm017-dc3 zynqmp-zc1751-xm018-dc4 zynqmp-zc1751-xm019-dc5 zynqmp-zcu100-revC zynqmp-zcu102-rev1.1 zynqmp-zcu102-rev1.0 zynqmp-zcu102-revA zynqmp-zcu102-revB zynqmp-zcu104-revA zynqmp-zcu104-revC zynqmp-zcu106-revA zynqmp-zcu106-rev1.0 zynqmp-zcu111-revA zynqmp-zcu1275-revA zynqmp-zcu1275-revB zynqmp-zcu1285-revA zynqmp-zcu208-revA zynqmp-zcu216-revA zynqmp-topic-miamimp-xilinx-xdp-v1r1 zynqmp-sm-k26-revA zynqmp-smk-k26-revA zynqmp-dlc21-revA atf-bl31-path = /tftpboot/bl31.bin tee-os-path = /tftpboot/tee.bin opensbi-path = default-dt = zynqmp-zcu100-revC scp-path = rockchip-tpl-path = spl-bss-pad = tpl-bss-pad = 1 spl-dtb = y tpl-dtb = pre-load-key-path = Processing entry args done Node '/binman/spl/xilinx-fsbl-auth/u-boot-spl-nodtb': Packing: offset=None, size=None, content_size=240d8 Node '/binman/spl/xilinx-fsbl-auth/u-boot-spl-nodtb': - packed: offset=0x0, size=0x240d8, content_size=0x240d8, next_offset=240d8 Node '/binman/spl/xilinx-fsbl-auth/u-boot-spl-nodtb': GetData: size 0x240d8 Node '/binman/spl/xilinx-fsbl-auth': GetPaddedDataForEntry: size None Node '/binman/spl/xilinx-fsbl-auth': GetData: 1 entries, total size 0x240d8 bintool: bootgen -arch zynqmp -image ./bootgen-in.sign.bif -w -o ./boot.spl.xilinx-fsbl-auth.bin
****** Xilinx Bootgen v2022.2.0 **** Build date : Oct 13 2022-12:22:43 ** Copyright 1986-2022 Xilinx, Inc. All Rights Reserved.
[WARNING]: Authentication padding scheme will be as per silicon 2.0(ES2) and above. The image generated will NOT work for 1.0(ES1). Use '-zynqmpes1' to generate image for 1.0(ES1)
[INFO] : Bootimage generated successfully
BTW tools are not allowed to generate output normally, so this will need to be suppressed somehow by the binman btool.
Actually this happens automatically. I think the above was due to verbose being on.
I applied what patches I could from this series, so please rebase to master (or dm/master if before the PR is applied), and resend.
Regards, Simon

Hi Michal,
On 21.07.2023 16:41, Michal Simek wrote:
On 7/18/23 13:53, lukas.funke-oss@weidmueller.com wrote:
From: Lukas Funke lukas.funke@weidmueller.com
This series adds two etypes to create a verified boot chain for Xilinx ZynqMP devices. The first etype 'xilinx-fsbl-auth' is used to create a bootable, signed image for ZynqMP boards using the Xilinx Bootgen tool. The second etype 'u-boot-spl-pubkey-dtb' is used to add a '/signature' node to the SPL. The public key in the signature is read from a certificate file and added using the 'fdt_add_pubkey' tool. The series also contains the corresponding btool for calling 'bootgen' and 'fdt_add_pubkey'.
The following block shows an example on how to use this functionality:
spl { filename = "boot.signed.bin";
xilinx-fsbl-auth { psk-key-name-hint = "psk0"; ssk-key-name-hint = "ssk0"; auth-params = "ppk_select=0", "spk_id=0x00000000";
u-boot-spl-nodtb { }; u-boot-spl-pubkey-dtb { algo = "sha384,rsa4096"; required = "conf"; key-name-hint = "dev"; }; }; };
I was looking at binman couple of times in past but never had time to do any development with it. Maybe it is good opportunity to look at it now with this series. Is there a way to see more verbose output?
I expect that keys should be generated as is described here.
https://docs.xilinx.com/r/en-US/ug1283-bootgen-user-guide/Key-Generation?toc...
Yes.
Anyway I tried to use u-boot-spl-nodtb like this.
&binman { spl { filename = "boot.signed.bin";
xilinx-fsbl-auth { psk-key-name-hint = "/tmp/ddd/psk0"; ssk-key-name-hint = "/tmp/ddd/ssk0"; auth-params = "ppk_select=0", "spk_id=0x00000000"; pmufw-filename = "/mnt/disk/u-boot-bins/zynqmp/zynqmp-zcu102-revA/pmufw.elf";
u-boot-spl-nodtb { }; }; }; };
but getting error BINMAN .binman_stamp Using input directories ['.', '.', './board/xilinx/zynqmp', 'arch/arm/dts'] Using output directory '.' Processing entry args: of-list = avnet-ultra96-rev1 zynqmp-a2197-revA zynqmp-e-a2197-00-revA zynqmp-g-a2197-00-revA zynqmp-m-a2197-01-revA zynqmp-m-a2197-02-revA zynqmp-m-a2197-03-revA zynqmp-p-a2197-00-revA zynqmp-zc1232-revA zynqmp-zc1254-revA zynqmp-zc1751-xm015-dc1 zynqmp-zc1751-xm016-dc2 zynqmp-zc1751-xm017-dc3 zynqmp-zc1751-xm018-dc4 zynqmp-zc1751-xm019-dc5 zynqmp-zcu100-revC zynqmp-zcu102-rev1.1 zynqmp-zcu102-rev1.0 zynqmp-zcu102-revA zynqmp-zcu102-revB zynqmp-zcu104-revA zynqmp-zcu104-revC zynqmp-zcu106-revA zynqmp-zcu106-rev1.0 zynqmp-zcu111-revA zynqmp-zcu1275-revA zynqmp-zcu1275-revB zynqmp-zcu1285-revA zynqmp-zcu208-revA zynqmp-zcu216-revA zynqmp-topic-miamimp-xilinx-xdp-v1r1 zynqmp-sm-k26-revA zynqmp-smk-k26-revA zynqmp-dlc21-revA atf-bl31-path = /tftpboot/bl31.bin tee-os-path = /tftpboot/tee.bin opensbi-path = default-dt = zynqmp-zcu100-revC scp-path = rockchip-tpl-path = spl-bss-pad = tpl-bss-pad = 1 spl-dtb = y tpl-dtb = pre-load-key-path = Processing entry args done Node '/binman/spl/xilinx-fsbl-auth/u-boot-spl-nodtb': Packing: offset=None, size=None, content_size=240d8 Node '/binman/spl/xilinx-fsbl-auth/u-boot-spl-nodtb': - packed: offset=0x0, size=0x240d8, content_size=0x240d8, next_offset=240d8 Node '/binman/spl/xilinx-fsbl-auth/u-boot-spl-nodtb': GetData: size 0x240d8 Node '/binman/spl/xilinx-fsbl-auth': GetPaddedDataForEntry: size None Node '/binman/spl/xilinx-fsbl-auth': GetData: 1 entries, total size 0x240d8 bintool: bootgen -arch zynqmp -image ./bootgen-in.sign.bif -w -o ./boot.spl.xilinx-fsbl-auth.bin
****** Xilinx Bootgen v2022.2.0 **** Build date : Oct 13 2022-12:22:43 ** Copyright 1986-2022 Xilinx, Inc. All Rights Reserved.
[WARNING]: Authentication padding scheme will be as per silicon 2.0(ES2) and above. The image generated will NOT work for 1.0(ES1). Use '-zynqmpes1' to generate image for 1.0(ES1)
[INFO] : Bootimage generated successfully
Node '/binman/spl': GetPaddedDataForEntry: size None Node '/binman/spl/xilinx-fsbl-auth': Packing: offset=None, size=0x47280, content_size=47280 Node '/binman/spl/xilinx-fsbl-auth': - packed: offset=0x0, size=0x47280, content_size=0x47280, next_offset=47280 Node '/binman/spl/xilinx-fsbl-auth/u-boot-spl-nodtb': GetData: size 0x240d8 Node '/binman/spl/xilinx-fsbl-auth': GetPaddedDataForEntry: size 0x47280 Node '/binman/spl/xilinx-fsbl-auth': GetData: 1 entries, total size 0x240d8 bintool: bootgen -arch zynqmp -image ./bootgen-in.sign.bif -w -o ./boot.spl.xilinx-fsbl-auth.bin
****** Xilinx Bootgen v2022.2.0 **** Build date : Oct 13 2022-12:22:43 ** Copyright 1986-2022 Xilinx, Inc. All Rights Reserved.
[WARNING]: Authentication padding scheme will be as per silicon 2.0(ES2) and above. The image generated will NOT work for 1.0(ES1). Use '-zynqmpes1' to generate image for 1.0(ES1)
[INFO] : Bootimage generated successfully
Node '/binman/spl': GetPaddedDataForEntry: size None Node '/binman/spl': GetData: 1 entries, total size 0x47280 Node '/binman/spl': GetPaddedDataForEntry: size 0x47280 Node '/binman/spl': Packing: offset=None, size=0x47280, content_size=47280 Node '/binman/spl': - packed: offset=0x0, size=0x47280, content_size=0x47280, next_offset=47280 File ./u-boot.dtb.out: Update node '/binman/spl' prop 'offset' to 0x0 File ./u-boot.dtb.out: Update node '/binman/spl' prop 'size' to 0x47280 File ./u-boot.dtb.out: Update node '/binman/spl' prop 'image-pos' to 0x0 File ./u-boot.dtb.out: Update node '/binman/spl/xilinx-fsbl-auth' prop 'offset' to 0x0 File ./u-boot.dtb.out: Update node '/binman/spl/xilinx-fsbl-auth' prop 'size' to 0x47280 File ./u-boot.dtb.out: Update node '/binman/spl/xilinx-fsbl-auth' prop 'image-pos' to 0x0 File ./u-boot.dtb.out: Update node '/binman/spl/xilinx-fsbl-auth/u-boot-spl-nodtb' prop 'offset' to 0x0 File ./u-boot.dtb.out: Update node '/binman/spl/xilinx-fsbl-auth/u-boot-spl-nodtb' prop 'size' to 0x240d8 File ./u-boot.dtb.out: Update node '/binman/spl/xilinx-fsbl-auth/u-boot-spl-nodtb' prop 'image-pos' to 0x0 Section '/binman/spl': Symbol '_binman_sym_magic' in entry '/binman/spl/xilinx-fsbl-auth/u-boot-spl-nodtb': insert _binman_sym_magic, offset 22f80, value 4d595342, length 8 binman: Section '/binman/spl': Symbol '_binman_u_boot_any_prop_image_pos' in entry '/binman/spl/xilinx-fsbl-auth/u-boot-spl-nodtb': Entry 'u-boot-any' not found in list (u-boot-spl-nodtb,xilinx-fsbl-auth,spl)
Traceback (most recent call last): File "/home/monstr/data/disk/u-boot/./tools/binman/binman", line 134, in RunBinman ret_code = control.Binman(args) File "/home/monstr/data/disk/u-boot/tools/binman/control.py", line 787, in Binman invalid |= ProcessImage(image, args.update_fdt, args.map, File "/home/monstr/data/disk/u-boot/tools/binman/control.py", line 616, in ProcessImage image.WriteSymbols() File "/home/monstr/data/disk/u-boot/tools/binman/image.py", line 172, in WriteSymbols super().WriteSymbols(self) File "/home/monstr/data/disk/u-boot/tools/binman/etype/section.py", line 499, in WriteSymbols entry.WriteSymbols(self) File "/home/monstr/data/disk/u-boot/tools/binman/etype/section.py", line 499, in WriteSymbols entry.WriteSymbols(self) File "/home/monstr/data/disk/u-boot/tools/binman/entry.py", line 701, in WriteSymbols elf.LookupAndWriteSymbols(self.elf_fname, self, section.GetImage(), File "/home/monstr/data/disk/u-boot/tools/binman/elf.py", line 298, in LookupAndWriteSymbols value = section.GetImage().LookupImageSymbol(name, sym.weak, File "/home/monstr/data/disk/u-boot/tools/binman/image.py", line 404, in LookupImageSymbol return self.LookupSymbol(sym_name, optional, msg, base_addr, File "/home/monstr/data/disk/u-boot/tools/binman/etype/section.py", line 650, in LookupSymbol raise ValueError(err) ValueError: Section '/binman/spl': Symbol '_binman_u_boot_any_prop_image_pos' in entry '/binman/spl/xilinx-fsbl-auth/u-boot-spl-nodtb': Entry 'u-boot-any' not found in list (u-boot-spl-nodtb,xilinx-fsbl-auth,spl) make: *** [Makefile:1115: .binman_stamp] Error 1
Thanks for testing/reviewing. I had the same problem. The root cause is documented here: https://lists.denx.de/pipermail/u-boot/2022-October/498746.html
In short: disable 'CONFIG_SPL_BINMAN_UBOOT_SYMBOLS' helps. I think the problem should addressed in a separate discussion.
with u-boot-spl-dtb it works fine.
Anyway kind of curious if that support can be more generalized that bif can be generated for other configurations too. It means
xilinx-bootgen { pmufw-filename = "/mnt/disk/u-boot-bins/zynqmp/zynqmp-zcu102-revA/pmufw.elf";
u-boot-spl-dtb { }; };
you will get boot.bin which images you defined.
And regarding name "xilinx-fsbl-auth". That authentication is done by bootrom not by FSBL that's why you should maybe consider to rename it. And as you wrote "arch (str): Xilinx SoC architecture. Currently only 'zynqmp' is supported." then I expect in future this can be extended for on other SOCs which don't have FSBL unless you will use it as generic name first stage bootloader.
That's why I would say xilinx-bootgen would be maybe better name even if it has tool name there.
The name was choosen after the output it creates. However, I agree on your idea for a more generic approach and will consider it in the next version.
Thanks, Michal
Thanks, Lukas
participants (4)
-
Lukas Funke
-
lukas.funke-oss@weidmueller.com
-
Michal Simek
-
Simon Glass