[PATCH v4 0/3] Sign Xilinx ZynqMP SPL/FSBL boot images using binman

From: Lukas Funke lukas.funke@weidmueller.com
This series adds one etype to create a verified boot chain for Xilinx ZynqMP devices. The etype 'xilinx-bootgen' is used to create a bootable, signed image for ZynqMP boards using the Xilinx Bootgen tool. The series also contains the corresponding btool for calling 'bootgen'.
The following block shows an example on how to use this functionality:
spl { filename = "boot.signed.bin";
xilinx-bootgen { psk-key-name-hint = "psk0"; ssk-key-name-hint = "ssk0"; pmufw-filename = "pmu-firmware.elf"; 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 v4: - Fixed some typos - Add test to check for missing bootgen tool - Renamed etype from "xilinx-fsbl-auth" to "xilinx-bootgen" - Add detection of missing bintool - Promote 'pmufw-filename' to required property
Changes in v3: - 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: - 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 (3): binman: btool: Add Xilinx Bootgen btool binman: ftest: Add test for xilinx-bootgen etype binman: etype: Add xilinx-bootgen etype
tools/binman/bintools.rst | 2 +- tools/binman/btool/bootgen.py | 137 +++++++++++ tools/binman/entries.rst | 75 ++++++ tools/binman/etype/xilinx_bootgen.py | 225 ++++++++++++++++++ tools/binman/ftest.py | 75 ++++++ tools/binman/test/307_xilinx_bootgen_sign.dts | 22 ++ .../test/308_xilinx_bootgen_sign_enc.dts | 24 ++ 7 files changed, 559 insertions(+), 1 deletion(-) create mode 100644 tools/binman/btool/bootgen.py create mode 100644 tools/binman/etype/xilinx_bootgen.py create mode 100644 tools/binman/test/307_xilinx_bootgen_sign.dts create mode 100644 tools/binman/test/308_xilinx_bootgen_sign_enc.dts

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 v4: - Fixed some typos
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 | 137 ++++++++++++++++++++++++++++++++++ 2 files changed, 138 insertions(+), 1 deletion(-) create mode 100644 tools/binman/btool/bootgen.py
diff --git a/tools/binman/bintools.rst b/tools/binman/bintools.rst index 20ee24395a..1336f4d011 100644 --- a/tools/binman/bintools.rst +++ b/tools/binman/bintools.rst @@ -208,7 +208,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..f2ca552dc2 --- /dev/null +++ b/tools/binman/btool/bootgen.py @@ -0,0 +1,137 @@ +# 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 + +""" + +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 with 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' (psk). 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 Loader). 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 secondary 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 actual 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 further 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 + + Returns: + str: Bootgen output from stdout + + [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] + return 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

On Thu, 3 Aug 2023 at 09:22, 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 v4:
- Fixed some typos
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 | 137 ++++++++++++++++++++++++++++++++++ 2 files changed, 138 insertions(+), 1 deletion(-) create mode 100644 tools/binman/btool/bootgen.py
Reviewed-by: Simon Glass sjg@chromium.org

On Thu, 3 Aug 2023 at 09:22, 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 v4:
- Fixed some typos
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 | 137 ++++++++++++++++++++++++++++++++++ 2 files changed, 138 insertions(+), 1 deletion(-) create mode 100644 tools/binman/btool/bootgen.py
Reviewed-by: Simon Glass sjg@chromium.org
Applied to u-boot-dm, thanks!

Hi,
On Sat, 5 Aug 2023 at 13:51, Simon Glass sjg@chromium.org wrote:
On Thu, 3 Aug 2023 at 09:22, 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 v4:
- Fixed some typos
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 | 137 ++++++++++++++++++++++++++++++++++ 2 files changed, 138 insertions(+), 1 deletion(-) create mode 100644 tools/binman/btool/bootgen.py
Reviewed-by: Simon Glass sjg@chromium.org
Applied to u-boot-dm, thanks!
On -next I see this:
binman tool -f bootgen Fetch: bootgen - trying method: binary download - trying method: build from source - clone git repo 'https://github.com/Xilinx/bootgen' to '/tmp/binmanf.0bzta5ph' - build target 'a' Exception: Error 2 running 'make -C /tmp/binmanf.0bzta5ph -j 64 a': make: *** No rule to make target 'a'. Stop.
- failed to fetch with all methods
2. There seems to be some test coverage missing:
tools/binman/etype/xilinx_bootgen.py 72 1 99%
The offending line is 216:
data = tools.read_file(bootbin_fname)
Please could you take a look?
Regards, Simon

From: Lukas Funke lukas.funke@weidmueller.com
Add test for the 'xilinx-bootgen' etype
Signed-off-by: Lukas Funke lukas.funke@weidmueller.com Reviewed-by: Simon Glass sjg@chromium.org
---
Changes in v4: - Add test to check for missing bootgen tool
Changes in v3: - Improved test coverage for xilinx-fsbl-auth etype
Changes in v2: - Fixed typo in dts name
tools/binman/ftest.py | 75 +++++++++++++++++++ tools/binman/test/307_xilinx_bootgen_sign.dts | 22 ++++++ .../test/308_xilinx_bootgen_sign_enc.dts | 24 ++++++ 3 files changed, 121 insertions(+) create mode 100644 tools/binman/test/307_xilinx_bootgen_sign.dts create mode 100644 tools/binman/test/308_xilinx_bootgen_sign_enc.dts
diff --git a/tools/binman/ftest.py b/tools/binman/ftest.py index 36428ec343..2d541c32b9 100644 --- a/tools/binman/ftest.py +++ b/tools/binman/ftest.py @@ -7139,5 +7139,80 @@ fdt fdtmap Extract the devicetree blob from the fdtmap self.assertEqual(fdt_util.GetString(key_node, "key-name-hint"), "key")
+ def testXilinxBootgenSigning(self): + """Test xilinx-bootgen 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('307_xilinx_bootgen_sign.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 testXilinxBootgenSigningEncryption(self): + """Test xilinx-bootgen 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('308_xilinx_bootgen_sign_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 testXilinxBootgenMissing(self): + """Test that binman still produces an image if ifwitool is missing""" + data = tools.read_file(self.TestFile("key.key")) + self._MakeInputFile("psk.pem", data) + self._MakeInputFile("ssk.pem", data) + self._SetupPmuFwlElf() + self._SetupSplElf() + with test_util.capture_sys_output() as (_, stderr): + self._DoTestFile('307_xilinx_bootgen_sign.dts', + force_missing_bintools='bootgen') + err = stderr.getvalue() + self.assertRegex(err, + "Image 'image'.*missing bintools.*: bootgen") + if __name__ == "__main__": unittest.main() diff --git a/tools/binman/test/307_xilinx_bootgen_sign.dts b/tools/binman/test/307_xilinx_bootgen_sign.dts new file mode 100644 index 0000000000..02acf8652a --- /dev/null +++ b/tools/binman/test/307_xilinx_bootgen_sign.dts @@ -0,0 +1,22 @@ +// SPDX-License-Identifier: GPL-2.0+ + +/dts-v1/; + +/ { + #address-cells = <1>; + #size-cells = <1>; + + binman { + xilinx-bootgen { + auth-params = "ppk_select=0", "spk_id=0x00000000"; + pmufw-filename = "pmu-firmware.elf"; + psk-key-name-hint = "psk"; + ssk-key-name-hint = "ssk"; + + u-boot-spl-nodtb { + }; + u-boot-spl-dtb { + }; + }; + }; +}; diff --git a/tools/binman/test/308_xilinx_bootgen_sign_enc.dts b/tools/binman/test/308_xilinx_bootgen_sign_enc.dts new file mode 100644 index 0000000000..5d7ce4c1f5 --- /dev/null +++ b/tools/binman/test/308_xilinx_bootgen_sign_enc.dts @@ -0,0 +1,24 @@ +// SPDX-License-Identifier: GPL-2.0+ + +/dts-v1/; + +/ { + #address-cells = <1>; + #size-cells = <1>; + + binman { + xilinx-bootgen { + auth-params = "ppk_select=0", "spk_id=0x00000000"; + fsbl-config = "auth_only"; + keysrc-enc = "efuse_red_key"; + pmufw-filename = "pmu-firmware.elf"; + psk-key-name-hint = "psk"; + ssk-key-name-hint = "ssk"; + + u-boot-spl-nodtb { + }; + u-boot-spl-dtb { + }; + }; + }; +};

From: Lukas Funke lukas.funke@weidmueller.com
Add test for the 'xilinx-bootgen' etype
Signed-off-by: Lukas Funke lukas.funke@weidmueller.com Reviewed-by: Simon Glass sjg@chromium.org
---
Changes in v4: - Add test to check for missing bootgen tool
Changes in v3: - Improved test coverage for xilinx-fsbl-auth etype
Changes in v2: - Fixed typo in dts name
tools/binman/ftest.py | 75 +++++++++++++++++++ tools/binman/test/307_xilinx_bootgen_sign.dts | 22 ++++++ .../test/308_xilinx_bootgen_sign_enc.dts | 24 ++++++ 3 files changed, 121 insertions(+) create mode 100644 tools/binman/test/307_xilinx_bootgen_sign.dts create mode 100644 tools/binman/test/308_xilinx_bootgen_sign_enc.dts
Applied to u-boot-dm, thanks!

From: Lukas Funke lukas.funke@weidmueller.com
This adds a new etype 'xilinx-bootgen'. By using this etype it is possible to created an signed 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-bootgen { pmufw-filename = "pmu-firmware.elf"; 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 Reviewed-by: Simon Glass sjg@chromium.org
---
Changes in v4: - Renamed etype from "xilinx-fsbl-auth" to "xilinx-bootgen" - Add detection of missing bintool - Promote 'pmufw-filename' to required property
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 | 75 +++++++++ tools/binman/etype/xilinx_bootgen.py | 225 +++++++++++++++++++++++++++ 2 files changed, 300 insertions(+) create mode 100644 tools/binman/etype/xilinx_bootgen.py
diff --git a/tools/binman/entries.rst b/tools/binman/entries.rst index f2376932be..e7dfe6b2a3 100644 --- a/tools/binman/entries.rst +++ b/tools/binman/entries.rst @@ -2667,3 +2667,78 @@ may be used instead.
+.. _etype_xilinx_bootgen: + +Entry: xilinx-bootgen: Signed SPL boot image for 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 a boot image for Xilinx ZynqMP +devices. + +Information for signed images: + +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 a signed 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-bootgen { + 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-bootgen { + 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_bootgen.py b/tools/binman/etype/xilinx_bootgen.py new file mode 100644 index 0000000000..70a4b2e242 --- /dev/null +++ b/tools/binman/etype/xilinx_bootgen.py @@ -0,0 +1,225 @@ +# SPDX-License-Identifier: GPL-2.0+ +# Copyright (c) 2023 Weidmueller GmbH +# Written by Lukas Funke lukas.funke@weidmueller.com +# +# Entry-type module for Zynq(MP) 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_bootgen(Entry_section): + """Signed SPL boot image for 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 a boot image for Xilinx ZynqMP + devices. + + Information for signed images: + + 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 a signed 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-bootgen { + 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-bootgen { + 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 = ['pmufw-filename', + 'psk-key-name-hint', + 'ssk-key-name-hint'] + + def ReadNode(self): + """Read properties from the xilinx-bootgen 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') + self._psk_key_name_hint = fdt_util.GetString(self._node, + 'psk-key-name-hint') + self._ssk_key_name_hint = fdt_util.GetString(self._node, + 'ssk-key-name-hint') + 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, signed 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 + if self.bootgen.sign('zynqmp', spl_elf_fname, pmufw_elf_fname, + psk_fname, ssk_fname, fsbl_config, + auth_params, self._keysrc_enc, bootbin_fname) is None: + # Bintool is missing; just use empty data as the output + self.record_missing_bintool(self.bootgen) + data = tools.get_bytes(0, 1024) + else: + 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')

From: Lukas Funke lukas.funke@weidmueller.com
This adds a new etype 'xilinx-bootgen'. By using this etype it is possible to created an signed 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-bootgen { pmufw-filename = "pmu-firmware.elf"; 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 Reviewed-by: Simon Glass sjg@chromium.org
---
Changes in v4: - Renamed etype from "xilinx-fsbl-auth" to "xilinx-bootgen" - Add detection of missing bintool - Promote 'pmufw-filename' to required property
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 | 75 +++++++++ tools/binman/etype/xilinx_bootgen.py | 225 +++++++++++++++++++++++++++ 2 files changed, 300 insertions(+) create mode 100644 tools/binman/etype/xilinx_bootgen.py
Applied to u-boot-dm, thanks!
participants (2)
-
lukas.funke-oss@weidmueller.com
-
Simon Glass