[PATCH v2 01/11] binman: elf: Check for ELF_TOOLS availability and remove extra semicolon
From: Lukas Funke Check if elf tools are available when running DecodeElf(). Also remove superfuous semicolon at line ending. Signed-off-by: Lukas Funke Reviewed-by: Simon Glass --- (no changes since v1) tools/binman/elf.py | 10 ++ 1 file changed, 6 insertions(+), 4 deletions(-) diff --git a/tools/binman/elf.py b/tools/binman/elf.py index 5816284c32..a53f4b9c4f 100644 --- a/tools/binman/elf.py +++ b/tools/binman/elf.py @@ -438,13 +438,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 = 0x; -data_end = 0; -mem_end = 0; -virt_to_phys = 0; +data_start = 0x +data_end = 0 +mem_end = 0 +virt_to_phys = 0 for i in range(elf.num_segments()): segment = elf.get_segment(i) -- 2.30.2
[PATCH v2 02/11] binman: Don't decompress data while signing
From: Lukas Funke 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 Reviewed-by: Simon Glass --- (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. -- 2.30.2
[PATCH v2 05/11] binman: ftest: Add test for u_boot_spl_pubkey_dtb
From: Lukas Funke 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 Reviewed-by: Simon Glass --- Changes in v2: - Changed u_boot_spl_pubkey_dtb to u-boot-spl-pubkey-dtb tools/binman/ftest.py| 32 tools/binman/test/281_spl_pubkey_dtb.dts | 16 2 files changed, 48 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..0ee0ce1155 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,27 @@ fdt fdtmapExtract 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 00..f845db66f5 --- /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 = "key"; + }; + }; +}; -- 2.30.2
[PATCH v2 03/11] binman: blob_dtb: Add fake_size argument to ObtainContents()
From: Lukas Funke 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 Reviewed-by: Simon Glass --- (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()) -- 2.30.2
[PATCH v2 00/11] Sign Xilinx ZynqMP SPL/FSBL boot images using binman
From: Lukas Funke 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-filename = "psk0.pem"; ssk-filename = "ssk0.pem"; auth-params = "ppk_select=0", "spk_id=0x"; u_boot_spl_nodtb { }; u_boot_spl_pubkey_dtb { algo = "sha384,rsa4096"; required = "conf"; key-name = "dev"; }; }; }; 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 | 10 +- tools/binman/entries.rst| 92 + tools/binman/etype/blob_dtb.py | 2 +- tools/binman/etype/u_boot_spl_pubkey_dtb.py | 109 ++ tools/binman/etype/xilinx_fsbl_auth.py | 213 tools/binman/ftest.py | 42 +++- tools/binman/test/280_xilinx_fsbl_auth.dts | 23 +++ tools/binman/test/281_spl_pubkey_dtb.dts| 16 ++ 12 files changed, 727 insertions(+), 7 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/281_spl_pubkey_dtb.dts -- 2.30.2
[PATCH v2 04/11] binman: doc: Add documentation for fdt_add_pubkey bintool
From: Lukas Funke Add documentation for btool which calls 'fdt_add_pubkey' Signed-off-by: Lukas Funke Reviewed-by: Simon Glass --- (no changes since v1) tools/binman/bintools.rst | 10 ++ 1 file changed, 10 insertions(+) diff --git a/tools/binman/bintools.rst b/tools/binman/bintools.rst index c30e7eb9ff..88221adbe1 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` -- 2.30.2
[PATCH v2 06/11] binman: btool: Add fdt_add_pubkey as btool
From: Lukas Funke Add btool which calls 'fdt_add_pubkey' Signed-off-by: Lukas Funke Reviewed-by: Simon Glass --- (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 00..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 +# +"""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') -- 2.30.2
[PATCH v2 08/11] binman: doc: Add documentation for Xilinx Bootgen bintool
From: Lukas Funke Add documentation for the 'bootgen' bintool Signed-off-by: Lukas Funke Reviewed-by: Simon Glass --- (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 88221adbe1..c8d69f7177 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. -- 2.30.2
[PATCH v2 10/11] binman: ftest: Add test for xilinx_fsbl_auth etype
From: Lukas Funke Add test for the 'xilinx_fsbl_auth' etype Signed-off-by: Lukas Funke --- Changes in v2: - Fixed typo in dts name tools/binman/ftest.py | 8 tools/binman/test/280_xilinx_fsbl_auth.dts | 23 ++ 2 files changed, 31 insertions(+) create mode 100644 tools/binman/test/280_xilinx_fsbl_auth.dts diff --git a/tools/binman/ftest.py b/tools/binman/ftest.py index 0ee0ce1155..27a8a37864 100644 --- a/tools/binman/ftest.py +++ b/tools/binman/ftest.py @@ -6686,6 +6686,14 @@ fdt fdtmapExtract 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') 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 00..a37c5aa072 --- /dev/null +++ b/tools/binman/test/280_xilinx_fsbl_auth.dts @@ -0,0 +1,23 @@ +// SPDX-License-Identifier: GPL-2.0+ + +/dts-v1/; + +/ { + #address-cells = <1>; + #size-cells = <1>; + + binman { + xilinx-fsbl-auth { + filename = "boot.bin"; + + psk-filename = "psk.pem"; + ssk-filename = "ssk.pem"; + auth-params = "ppk_select=0", "spk_id=0x"; + + u-boot-spl-nodtb { + }; + u-boot-spl-dtb { + }; + }; + }; +}; -- 2.30.2
[PATCH v2 07/11] binman: etype: Add u_boot_spl_pubkey_dtb etype
From: Lukas Funke 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 Reviewed-by: Simon Glass --- 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..c3c5bda881 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: Public key name without extension (e.g. .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 = "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 00..e043001b11 --- /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 +# +# 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: Public key name without extension (e.g. .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 = "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'] +self.fdt_add_pubkey = None +self._algo = fdt_util.GetString(self._node, 'algo') +self._required = fdt_util.GetString(self._node, 'required') +self._keyname = fdt_util.GetString(self._node, 'key-name') + +def ObtainContents(self, fake_size=0): +""" Add public key to SPL dtb + +Add public key which is pointed out by +'key-name' to node 'signature' in the spl-dtb + +This is equivalent to the '-K' option of 'mkimage' + +
[PATCH v2 11/11] binman: etype: Add xilinx_fsbl_auth etype
From: Lukas Funke This adds a new etype 'xilinx_fsbl_auth'. 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 seconrady 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-filename = "psk0.pem"; ssk-filename = "ssk0.pem"; auth-params = "ppk_select=0", "spk_id=0x"; 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 --- 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 | 53 ++ tools/binman/etype/xilinx_fsbl_auth.py | 213 + 2 files changed, 266 insertions(+) create mode 100644 tools/binman/etype/xilinx_fsbl_auth.py diff --git a/tools/binman/entries.rst b/tools/binman/entries.rst index c3c5bda881..98ec3c82a5 100644 --- a/tools/binman/entries.rst +++ b/tools/binman/entries.rst @@ -2462,3 +2462,56 @@ 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-filename: Filename of primary public key +- ssk-filename: Filename of secondary public key + +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-filename = "psk0.pem"; +ssk-filename = "ssk0.pem"; +auth-params = "ppk_select=0", "spk_id=0x"; + +u-boot-spl-nodtb { +}; +u-boot-spl-pubkey-dtb { +algo = "sha384,rsa4096"; +required = "conf"; +key-name = "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-filename = "psk0.pem"; +ssk-filename = "ssk0.pem"; +... +fsbl-config = "bh_auth_enable"; +... +}; + + + diff --git a/tools/binman/etype/xilinx_fsbl_auth.py b/tools/binman/etype/xilinx_fsbl_auth.py new file mode 100644 index 00..72794ad2bc --- /dev/null +++ b/tools/binman/etype/xilinx_fsbl_auth.py @@ -0,0 +1,213 @@ +# SPDX-License-Identifier: GPL-2.0+ +# Copyright (c) 2023 Weidmueller GmbH +# Written by Lukas Funke +# +# Entry-type module for signed ZynqMP boot images (boot.bin) +# + +import tempfile + +from collections import OrderedDict + +from binman import elf +from binman.entry import Entry + +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): +"""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-filename: Filename of primary public key +- ssk-filename: Filename of secondary public key + +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-filename = "psk0.pem"; +ssk-filename = "ssk0.pem"; +auth-params = "ppk_select=0", "spk_id=0x"; +
[PATCH v2 09/11] binman: btool: Add Xilinx Bootgen btool
From: Lukas Funke 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 --- Changes in v2: - Pass additional 'keysrc_enc' parameter to Bootgen - Added more information and terms to documentation tools/binman/btool/bootgen.py | 136 ++ 1 file changed, 136 insertions(+) create mode 100644 tools/binman/btool/bootgen.py diff --git a/tools/binman/btool/bootgen.py b/tools/binman/btool/bootgen.py new file mode 100644 index 00..a30268c964 --- /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 +# +"""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-bootgen-user-guide.pdf + +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='') + +# 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=" - 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: +
[PATCH v3 01/11] binman: elf: Check for ELF_TOOLS availability and remove extra semicolon
From: Lukas Funke Check if elf tools are available when running DecodeElf(). Also remove superfuous semicolon at line ending. Signed-off-by: Lukas Funke Reviewed-by: Simon Glass --- 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 = 0x; -data_end = 0; -mem_end = 0; -virt_to_phys = 0; +data_start = 0x +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: -- 2.30.2
[PATCH v3 00/11] Sign Xilinx ZynqMP SPL/FSBL boot images using binman
From: Lukas Funke 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=0x"; 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
[PATCH v3 03/11] binman: blob_dtb: Add fake_size argument to ObtainContents()
From: Lukas Funke 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 Reviewed-by: Simon Glass --- (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()) -- 2.30.2
[PATCH v3 02/11] binman: Don't decompress data while signing
From: Lukas Funke 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 Reviewed-by: Simon Glass --- (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. -- 2.30.2
[PATCH v3 05/11] binman: ftest: Add test for u_boot_spl_pubkey_dtb
From: Lukas Funke 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 Reviewed-by: Simon Glass --- 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 fdtmapExtract 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 00..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"; + }; + }; +}; -- 2.30.2
[PATCH v3 04/11] binman: doc: Add documentation for fdt_add_pubkey bintool
From: Lukas Funke Add documentation for btool which calls 'fdt_add_pubkey' Signed-off-by: Lukas Funke Reviewed-by: Simon Glass --- 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` -- 2.30.2
[PATCH v3 06/11] binman: btool: Add fdt_add_pubkey as btool
From: Lukas Funke Add btool which calls 'fdt_add_pubkey' Signed-off-by: Lukas Funke Reviewed-by: Simon Glass --- (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 00..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 +# +"""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') -- 2.30.2
[PATCH v3 08/11] binman: doc: Add documentation for Xilinx Bootgen bintool
From: Lukas Funke Add documentation for the 'bootgen' bintool Signed-off-by: Lukas Funke Reviewed-by: Simon Glass --- (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. -- 2.30.2
[PATCH v3 09/11] binman: btool: Add Xilinx Bootgen btool
From: Lukas Funke 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 --- 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 00..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 +# +"""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-bootgen-user-guide.pdf + +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): A
[PATCH v3 10/11] binman: ftest: Add test for xilinx_fsbl_auth etype
From: Lukas Funke Add test for the 'xilinx_fsbl_auth' etype Signed-off-by: Lukas Funke --- 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 fdtmapExtract 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 00..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=0x"; + + 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 00..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 =
[PATCH v3 07/11] binman: etype: Add u-boot-spl-pubkey-dtb etype
From: Lukas Funke 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 Reviewed-by: Simon Glass --- 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 00..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 +# +# 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 ke
[PATCH v3 11/11] binman: etype: Add xilinx_fsbl_auth etype
From: Lukas Funke 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=0x"; 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 --- 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=0x"; + +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-Authentication + + + + diff --git a/tools/binman/etype/xilinx_fsbl_auth.py b/tools/binman/etype/xilinx_fsbl_auth.py new file mode 100644 index 00..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 +# +# Entry-type module for signed ZynqMP boot
[PATCH] arm64: zynqmp: Corrected pcap_prog register address
From: Lukas Funke Currently the pcap_prog struct variable is pointing to 0x3004 which is incorrect according to [1]. The variable should point to 0x3000. [1] https://www.xilinx.com/htmldocs/registers/ug1087/ug1087-zynq-ultrascale-registers.html#csu___pcap_prog.html Signed-off-by: Lukas Funke --- arch/arm/mach-zynqmp/include/mach/hardware.h | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/arch/arm/mach-zynqmp/include/mach/hardware.h b/arch/arm/mach-zynqmp/include/mach/hardware.h index 634bf169c6..8cb6494e52 100644 --- a/arch/arm/mach-zynqmp/include/mach/hardware.h +++ b/arch/arm/mach-zynqmp/include/mach/hardware.h @@ -166,7 +166,7 @@ struct csu_regs { u32 jtag_dap_cfg; u32 idcode; u32 version; - u32 reserved2[3055]; + u32 reserved2[3054]; u32 pcap_prog; }; -- 2.30.2
[PATCH] binman: bintool: Change make target arg type from string to list
From: Lukas Funke The argument type of `build_from_git` was changed from string to list in d71e7116997f14097735f04cc7847f0a68dbc485. This commit adapts the argument type of all bintools using this function. Signed-off-by: Lukas Funke --- tools/binman/btool/bootgen.py | 2 +- tools/binman/btool/fiptool.py | 2 +- tools/binman/btool/futility.py | 2 +- 3 files changed, 3 insertions(+), 3 deletions(-) diff --git a/tools/binman/btool/bootgen.py b/tools/binman/btool/bootgen.py index f2ca552dc2..1bc9f0aa96 100644 --- a/tools/binman/btool/bootgen.py +++ b/tools/binman/btool/bootgen.py @@ -132,6 +132,6 @@ class Bintoolbootgen(bintool.Bintool): result = self.build_from_git( 'https://github.com/Xilinx/bootgen', -'all', +['all'], 'bootgen') return result diff --git a/tools/binman/btool/fiptool.py b/tools/binman/btool/fiptool.py index c80f8275c4..34002f54af 100644 --- a/tools/binman/btool/fiptool.py +++ b/tools/binman/btool/fiptool.py @@ -109,6 +109,6 @@ class Bintoolfiptool(bintool.Bintool): return None result = self.build_from_git( 'https://git.trustedfirmware.org/TF-A/trusted-firmware-a.git', -'fiptool', +['fiptool'], 'tools/fiptool/fiptool') return result diff --git a/tools/binman/btool/futility.py b/tools/binman/btool/futility.py index 04c9aefe9b..0d3980d071 100644 --- a/tools/binman/btool/futility.py +++ b/tools/binman/btool/futility.py @@ -170,7 +170,7 @@ class Bintoolfutility(bintool.Bintool): # .gitcookies file. So use a mirror instead. result = self.build_from_git( 'https://github.com/sjg20/vboot_reference.git', -'all', +['all'], 'build/futility/futility', flags=['USE_FLASHROM=0']) return result -- 2.30.2
[PATCH v4 0/3] Sign Xilinx ZynqMP SPL/FSBL boot images using binman
From: Lukas Funke 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=0x"; 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 -- 2.30.2
[PATCH v4 2/3] binman: ftest: Add test for xilinx-bootgen etype
From: Lukas Funke Add test for the 'xilinx-bootgen' etype Signed-off-by: Lukas Funke Reviewed-by: Simon Glass --- 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 fdtmapExtract 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 00..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=0x"; + pmufw-filename = "pmu-firmware.elf"; + psk-key-name-hint = "psk"; +
[PATCH v4 1/3] binman: btool: Add Xilinx Bootgen btool
From: Lukas Funke 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 --- 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 00..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 +# +"""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-bootgen-user-guide.pdf + +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. +a
[PATCH v4 3/3] binman: etype: Add xilinx-bootgen etype
From: Lukas Funke 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=0x"; 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 Reviewed-by: Simon Glass --- 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=0x"; + +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-Authentication + + + + diff --git a/tools/binman/etype/xilinx_bootgen.py b/tools/binman/etype/xilinx_bootgen.py new file mode 100644 index 00..70a4b2e242 --- /dev/null +
[PATCH 3/5] test: cmd: setexptr: Add tests for bitmap string format
From: Lukas Funke Add test to test the bitmap format specifier Signed-off-by: Lukas Funke --- test/cmd/setexpr.c | 9 + 1 file changed, 9 insertions(+) diff --git a/test/cmd/setexpr.c b/test/cmd/setexpr.c index 312593e1e3..4e1c9e983b 100644 --- a/test/cmd/setexpr.c +++ b/test/cmd/setexpr.c @@ -465,6 +465,15 @@ static int setexpr_test_fmt(struct unit_test_state *uts) ut_asserteq(1, run_command("setexpr fred fmt hello% bf", 0)); /* Error exceeding maximum string length */ ut_asserteq(1, run_command("setexpr fred fmt \"%0128d\" 456", 0)); + /* Test bitmask long string*/ + ut_assertok(run_command("setexpr fred fmt isolcpu=%32pbl 0x1F1", 0)); + ut_asserteq_str("isolcpu=0,4-8", env_get("fred")); + /* Test bitmask long string (more complicated) */ + ut_assertok(run_command("setexpr fred fmt nohz_full=%32pbl 0x", 0)); + ut_asserteq_str("nohz_full=0,2,4,6,8,10,12,14,16,18,20,22,24,26,28,30", env_get("fred")); + /* Test bitmask short string*/ + ut_assertok(run_command("setexpr fred fmt %32pb 0x", 0)); + ut_asserteq_str("", env_get("fred")); unmap_sysmem(buf); -- 2.30.2
[PATCH 0/5] Enable setexpr command to print cpu-list like bitmaps
From: Lukas Funke This series enables the 'setexpr' command to print "cpu list"-like bitmaps based on the printk format specifier [1]. One use-case is to pass cpu list [2] based kernel parameter like 'isolcpu', 'nohz_full', irq affinity or RCU related CPU parameter to the kernel via a separate firmware variable without exposing the 'bootargs' variable to directly. Example: setexpr isolcpu_bootarg=%32pbl $myCPUisolation && env set bootargs "$isolcpu_bootarg" && bootm [1] https://www.kernel.org/doc/Documentation/printk-formats.txt [2] https://www.kernel.org/doc/html/latest/admin-guide/kernel-parameters.html Lukas Funke (5): sandbox: add generic find_next_zero_bit implementation linux: bitmap.h: add 'for_each_set_bitrange' iteration macro test: cmd: setexptr: Add tests for bitmap string format lib: vsprintf: enable '%*pb[l]' format specifier cmd: printf: forward '%p' format string specifier arch/sandbox/include/asm/bitops.h | 16 ++- cmd/printf.c | 29 include/linux/bitmap.h| 7 +++ lib/vsprintf.c| 75 +++ test/cmd/setexpr.c| 9 5 files changed, 134 insertions(+), 2 deletions(-) -- 2.30.2
[PATCH 1/5] sandbox: add generic find_next_zero_bit implementation
From: Lukas Funke Add generic 'find_next_zero_bit' implementation in order to enable the use of the 'for_each_set_bitrange' macro. The implementation is currently missing for the sandbox-arch and using the function results in a linker error. There are more efficient implementations in the architecture specific implementations. However, for the sandbox the implementation should be simple and portable. Signed-off-by: Lukas Funke --- arch/sandbox/include/asm/bitops.h | 16 ++-- 1 file changed, 14 insertions(+), 2 deletions(-) diff --git a/arch/sandbox/include/asm/bitops.h b/arch/sandbox/include/asm/bitops.h index f27d5e98c5..453ff005d2 100644 --- a/arch/sandbox/include/asm/bitops.h +++ b/arch/sandbox/include/asm/bitops.h @@ -104,8 +104,20 @@ static inline int __test_and_change_bit(int nr, void *addr) return (old & mask) != 0; } -extern int find_first_zero_bit(void *addr, unsigned size); -extern int find_next_zero_bit(void *addr, int size, int offset); +#define find_first_zero_bit(addr, size) \ + find_next_zero_bit((addr), (size), 0) + +static inline int find_next_zero_bit(const unsigned long *addr, int size, +int offset) { + unsigned long *p = ((unsigned long *)addr) + (offset >> 5); + + while ((~(*p) & 0x1 << offset) == 0x0ll && (offset < size)) { + offset++; + p = ((unsigned long *)addr) + (offset >> 5); + } + + return offset; +} /* * This routine doesn't need to be atomic. -- 2.30.2
[PATCH 2/5] linux: bitmap.h: add 'for_each_set_bitrange' iteration macro
From: Lukas Funke Add 'for_each_set_bitrange' (from Linux kernel) in order to iterate over each set bitrange of a bitmap. This becomes handy if one wants to generate a cpu list i.e. for isolcpu or nohz_full. Signed-off-by: Lukas Funke --- include/linux/bitmap.h | 7 +++ 1 file changed, 7 insertions(+) diff --git a/include/linux/bitmap.h b/include/linux/bitmap.h index 0a8503af9f..9714533078 100644 --- a/include/linux/bitmap.h +++ b/include/linux/bitmap.h @@ -159,6 +159,13 @@ static inline unsigned long find_first_bit(const unsigned long *addr, unsigned l (bit) < (size);\ (bit) = find_next_bit((addr), (size), (bit) + 1)) +#define for_each_set_bitrange(b, e, addr, size)\ + for ((b) = 0; \ +(b) = find_next_bit((addr), (size), b),\ +(e) = find_next_zero_bit((addr), (size), (b) + 1), \ +(b) < (size); \ +(b) = (e) + 1) + static inline unsigned long bitmap_find_next_zero_area(unsigned long *map, unsigned long size, -- 2.30.2
[PATCH 5/5] cmd: printf: forward '%p' format string specifier
From: Lukas Funke Forward '%p' format specifier to the underlying format logic in order to print pointers, especially bitmaps. Signed-off-by: Lukas Funke --- cmd/printf.c | 29 + 1 file changed, 29 insertions(+) diff --git a/cmd/printf.c b/cmd/printf.c index 0c6887e0d6..a90c923871 100644 --- a/cmd/printf.c +++ b/cmd/printf.c @@ -90,6 +90,7 @@ #include #include #include +#include #define WANT_HEX_ESCAPES 0 #define PRINT_CONVERSION_ERROR 1 @@ -476,6 +477,16 @@ static int get_width_prec(const char *str) return (int)v; } +static int print_pointer(struct print_inf *inf, char *format, +unsigned int fmt_length, const char *argument) +{ + u64 value = simple_strtoull(argument, NULL, 0); + + printf_str(inf, format, &value); + + return inf->error; +} + /* Print the text in FORMAT, using ARGV for arguments to any '%' directives. * Return advanced ARGV. */ @@ -536,6 +547,24 @@ static char **print_formatted(struct print_inf *inf, char *f, char **argv, int * } } } + if (*f == 'p') { + static const char ptr_format_chars[] = "bl"; + ++f; + ++direc_length; + char *p = strchr(ptr_format_chars, *f); + /* consume whole format token */ + while (*f != '\0' && *(p++) == *f) { + ++f; + ++direc_length; + } + if (print_pointer(inf, direc_start, direc_length, *argv++)) { + printf("`%s': invalid format\n", direc_start); + /* causes main() to exit with error */ + return saved_argv - 1; + } + f--; + break; + } /* Remove "lLhz" size modifiers, repeatedly. * bash does not like "%lld", but coreutils -- 2.30.2
[PATCH 4/5] lib: vsprintf: enable '%*pb[l]' format specifier
From: Lukas Funke The commit enables vsprintf() to handle the '%*pb[l]' format specifier in order to print bitmaps and its derivatives such as cpumask and nodemask [1]. This can be used to derive kernel boot parameters from bitmaks such as 'isolcpu' or 'nohz_full' [2]. [1] https://www.kernel.org/doc/Documentation/printk-formats.txt [2] https://www.kernel.org/doc/html/latest/admin-guide/kernel-parameters.html Signed-off-by: Lukas Funke --- lib/vsprintf.c | 75 ++ 1 file changed, 75 insertions(+) diff --git a/lib/vsprintf.c b/lib/vsprintf.c index e14c6ca9f9..abbd80ea9c 100644 --- a/lib/vsprintf.c +++ b/lib/vsprintf.c @@ -25,6 +25,7 @@ #include #include #include +#include /* we use this so that we can do without the ctype library */ #define is_digit(c)((c) >= '0' && (c) <= '9') @@ -390,6 +391,71 @@ static char *ip4_addr_string(char *buf, char *end, u8 *addr, int field_width, flags & ~SPECIAL); } +static char *bitmap_string(char *buf, char *end, const unsigned long *bitmap, + int field_width, int precision, int flags) +{ + const int CHUNKSIZE = 32; + int nr_bits = max_t(int, field_width, 0); + int i, chunksz; + int first = 1; + + chunksz = nr_bits & (CHUNKSIZE - 1); + if (chunksz == 0) + chunksz = CHUNKSIZE; + + i = ALIGN(nr_bits, CHUNKSIZE) - CHUNKSIZE; + for (; i >= 0; i -= CHUNKSIZE) { + u32 chunkmask, val; + int word, bit; + + chunkmask = ((1ULL << chunksz) - 1); + word = i / BITS_PER_LONG; + bit = i % BITS_PER_LONG; + val = (bitmap[word] >> bit) & chunkmask; + + if (!first) { + if (buf < end) + *buf = ','; + buf++; + } + first = 0; + + field_width = DIV_ROUND_UP(chunksz, 4); + buf = number(buf, end, val, 16, field_width, precision, +(SMALL | ZEROPAD)); + + chunksz = CHUNKSIZE; + } + return buf; +} + +static char *bitmap_list_string(char *buf, char *end, unsigned long *addr, + int field_width, int precision, int flags) +{ + int nr_bits = max_t(int, field_width, 0); + int first = 1; + int rbot, rtop; + + for_each_set_bitrange(rbot, rtop, addr, nr_bits) { + if (!first) { + if (buf < end) + *buf = ','; + buf++; + } + first = 0; + + buf = number(buf, end, rbot, 10, 0, -1, 0); + if (rtop == rbot + 1) + continue; + + if (buf < end) + *buf = '-'; + buf = number(++buf, end, rtop - 1, 10, 0, -1, 0); + } + + return buf; +} + #ifdef CONFIG_LIB_UUID /* * This works (roughly) the same way as Linux's. @@ -503,6 +569,15 @@ static char *pointer(const char *fmt, char *buf, char *end, void *ptr, precision, flags); flags &= ~SPECIAL; break; + case 'b': + switch (fmt[1]) { + case 'l': + return bitmap_list_string(buf, end, ptr, field_width, + precision, flags); + default: + return bitmap_string(buf, end, ptr, field_width, + precision, flags); + } #ifdef CONFIG_LIB_UUID case 'U': return uuid_string(buf, end, ptr, field_width, precision, -- 2.30.2
[PATCH v2 1/6] sandbox: add generic find_next_zero_bit implementation
From: Lukas Funke Add generic 'find_next_zero_bit' implementation in order to enable the use of the 'for_each_set_bitrange' macro. The implementation is currently missing for the sandbox-arch and using the function results in a linker error. There are more efficient implementations in the architecture specific implementations. However, for the sandbox the implementation should be simple and portable. Signed-off-by: Lukas Funke --- (no changes since v1) arch/sandbox/include/asm/bitops.h | 16 ++-- 1 file changed, 14 insertions(+), 2 deletions(-) diff --git a/arch/sandbox/include/asm/bitops.h b/arch/sandbox/include/asm/bitops.h index f27d5e98c5..453ff005d2 100644 --- a/arch/sandbox/include/asm/bitops.h +++ b/arch/sandbox/include/asm/bitops.h @@ -104,8 +104,20 @@ static inline int __test_and_change_bit(int nr, void *addr) return (old & mask) != 0; } -extern int find_first_zero_bit(void *addr, unsigned size); -extern int find_next_zero_bit(void *addr, int size, int offset); +#define find_first_zero_bit(addr, size) \ + find_next_zero_bit((addr), (size), 0) + +static inline int find_next_zero_bit(const unsigned long *addr, int size, +int offset) { + unsigned long *p = ((unsigned long *)addr) + (offset >> 5); + + while ((~(*p) & 0x1 << offset) == 0x0ll && (offset < size)) { + offset++; + p = ((unsigned long *)addr) + (offset >> 5); + } + + return offset; +} /* * This routine doesn't need to be atomic. -- 2.30.2
[PATCH v2 0/6] Enable setexpr command to print cpu-list like bitmaps
From: Lukas Funke This series enables the 'setexpr' command to print "cpu list"-like bitmaps based on the printk format specifier [1]. One use-case is to pass cpu list [2] based kernel parameter like 'isolcpu', 'nohz_full', irq affinity or RCU related CPU parameter to the kernel via a separate firmware variable without exposing the 'bootargs' variable to directly. Example: setexpr isolcpu_bootarg=%32pbl $myCPUisolation && env set bootargs "$isolcpu_bootarg" && bootm [1] https://www.kernel.org/doc/Documentation/printk-formats.txt [2] https://www.kernel.org/doc/html/latest/admin-guide/kernel-parameters.html Changes in v2: - Add bitmap format specifier to documentation Lukas Funke (6): sandbox: add generic find_next_zero_bit implementation linux: bitmap.h: add 'for_each_set_bitrange' iteration macro test: cmd: setexptr: Add tests for bitmap string format doc: printf() codes: Add bitmap format specifier lib: vsprintf: enable '%*pb[l]' format specifier cmd: printf: forward '%p' format string specifier arch/sandbox/include/asm/bitops.h | 16 ++- cmd/printf.c | 29 doc/develop/printf.rst| 6 +++ include/linux/bitmap.h| 7 +++ lib/vsprintf.c| 75 +++ test/cmd/setexpr.c| 9 6 files changed, 140 insertions(+), 2 deletions(-) -- 2.30.2
[PATCH v2 2/6] linux: bitmap.h: add 'for_each_set_bitrange' iteration macro
From: Lukas Funke Add 'for_each_set_bitrange' (from Linux kernel) in order to iterate over each set bitrange of a bitmap. This becomes handy if one wants to generate a cpu list i.e. for isolcpu or nohz_full. Signed-off-by: Lukas Funke --- (no changes since v1) include/linux/bitmap.h | 7 +++ 1 file changed, 7 insertions(+) diff --git a/include/linux/bitmap.h b/include/linux/bitmap.h index 0a8503af9f..9714533078 100644 --- a/include/linux/bitmap.h +++ b/include/linux/bitmap.h @@ -159,6 +159,13 @@ static inline unsigned long find_first_bit(const unsigned long *addr, unsigned l (bit) < (size);\ (bit) = find_next_bit((addr), (size), (bit) + 1)) +#define for_each_set_bitrange(b, e, addr, size)\ + for ((b) = 0; \ +(b) = find_next_bit((addr), (size), b),\ +(e) = find_next_zero_bit((addr), (size), (b) + 1), \ +(b) < (size); \ +(b) = (e) + 1) + static inline unsigned long bitmap_find_next_zero_area(unsigned long *map, unsigned long size, -- 2.30.2
[PATCH v2 3/6] test: cmd: setexptr: Add tests for bitmap string format
From: Lukas Funke Add test to test the bitmap format specifier Signed-off-by: Lukas Funke --- (no changes since v1) test/cmd/setexpr.c | 9 + 1 file changed, 9 insertions(+) diff --git a/test/cmd/setexpr.c b/test/cmd/setexpr.c index 312593e1e3..4e1c9e983b 100644 --- a/test/cmd/setexpr.c +++ b/test/cmd/setexpr.c @@ -465,6 +465,15 @@ static int setexpr_test_fmt(struct unit_test_state *uts) ut_asserteq(1, run_command("setexpr fred fmt hello% bf", 0)); /* Error exceeding maximum string length */ ut_asserteq(1, run_command("setexpr fred fmt \"%0128d\" 456", 0)); + /* Test bitmask long string*/ + ut_assertok(run_command("setexpr fred fmt isolcpu=%32pbl 0x1F1", 0)); + ut_asserteq_str("isolcpu=0,4-8", env_get("fred")); + /* Test bitmask long string (more complicated) */ + ut_assertok(run_command("setexpr fred fmt nohz_full=%32pbl 0x", 0)); + ut_asserteq_str("nohz_full=0,2,4,6,8,10,12,14,16,18,20,22,24,26,28,30", env_get("fred")); + /* Test bitmask short string*/ + ut_assertok(run_command("setexpr fred fmt %32pb 0x", 0)); + ut_asserteq_str("", env_get("fred")); unmap_sysmem(buf); -- 2.30.2
[PATCH v2 4/6] doc: printf() codes: Add bitmap format specifier
From: Lukas Funke Add '%*pb[l]' printf format specifier as descriped in [1]. [1] https://www.kernel.org/doc/Documentation/printk-formats.txt Signed-off-by: Lukas Funke --- (no changes since v1) doc/develop/printf.rst | 6 ++ 1 file changed, 6 insertions(+) diff --git a/doc/develop/printf.rst b/doc/develop/printf.rst index 99d05061b1..c3537b1796 100644 --- a/doc/develop/printf.rst +++ b/doc/develop/printf.rst @@ -165,6 +165,12 @@ Pointers * phys_size_t * resource_size_t +%*pb, %*pbl +prints bitmap and its derivatives such as cpumask and nodemask. +'%*pb' outputs the bitmap with field width as the number of bits +and '%*pbl' outputs the bitmap as range list with field width as +the number of bits. + %pD prints a UEFI device path -- 2.30.2
[PATCH v2 5/6] lib: vsprintf: enable '%*pb[l]' format specifier
From: Lukas Funke The commit enables vsprintf() to handle the '%*pb[l]' format specifier in order to print bitmaps and its derivatives such as cpumask and nodemask [1]. This can be used to derive kernel boot parameters from bitmaks such as 'isolcpu' or 'nohz_full' [2]. [1] https://www.kernel.org/doc/Documentation/printk-formats.txt [2] https://www.kernel.org/doc/html/latest/admin-guide/kernel-parameters.html Signed-off-by: Lukas Funke --- (no changes since v1) lib/vsprintf.c | 75 ++ 1 file changed, 75 insertions(+) diff --git a/lib/vsprintf.c b/lib/vsprintf.c index e14c6ca9f9..abbd80ea9c 100644 --- a/lib/vsprintf.c +++ b/lib/vsprintf.c @@ -25,6 +25,7 @@ #include #include #include +#include /* we use this so that we can do without the ctype library */ #define is_digit(c)((c) >= '0' && (c) <= '9') @@ -390,6 +391,71 @@ static char *ip4_addr_string(char *buf, char *end, u8 *addr, int field_width, flags & ~SPECIAL); } +static char *bitmap_string(char *buf, char *end, const unsigned long *bitmap, + int field_width, int precision, int flags) +{ + const int CHUNKSIZE = 32; + int nr_bits = max_t(int, field_width, 0); + int i, chunksz; + int first = 1; + + chunksz = nr_bits & (CHUNKSIZE - 1); + if (chunksz == 0) + chunksz = CHUNKSIZE; + + i = ALIGN(nr_bits, CHUNKSIZE) - CHUNKSIZE; + for (; i >= 0; i -= CHUNKSIZE) { + u32 chunkmask, val; + int word, bit; + + chunkmask = ((1ULL << chunksz) - 1); + word = i / BITS_PER_LONG; + bit = i % BITS_PER_LONG; + val = (bitmap[word] >> bit) & chunkmask; + + if (!first) { + if (buf < end) + *buf = ','; + buf++; + } + first = 0; + + field_width = DIV_ROUND_UP(chunksz, 4); + buf = number(buf, end, val, 16, field_width, precision, +(SMALL | ZEROPAD)); + + chunksz = CHUNKSIZE; + } + return buf; +} + +static char *bitmap_list_string(char *buf, char *end, unsigned long *addr, + int field_width, int precision, int flags) +{ + int nr_bits = max_t(int, field_width, 0); + int first = 1; + int rbot, rtop; + + for_each_set_bitrange(rbot, rtop, addr, nr_bits) { + if (!first) { + if (buf < end) + *buf = ','; + buf++; + } + first = 0; + + buf = number(buf, end, rbot, 10, 0, -1, 0); + if (rtop == rbot + 1) + continue; + + if (buf < end) + *buf = '-'; + buf = number(++buf, end, rtop - 1, 10, 0, -1, 0); + } + + return buf; +} + #ifdef CONFIG_LIB_UUID /* * This works (roughly) the same way as Linux's. @@ -503,6 +569,15 @@ static char *pointer(const char *fmt, char *buf, char *end, void *ptr, precision, flags); flags &= ~SPECIAL; break; + case 'b': + switch (fmt[1]) { + case 'l': + return bitmap_list_string(buf, end, ptr, field_width, + precision, flags); + default: + return bitmap_string(buf, end, ptr, field_width, + precision, flags); + } #ifdef CONFIG_LIB_UUID case 'U': return uuid_string(buf, end, ptr, field_width, precision, -- 2.30.2
[PATCH v2 6/6] cmd: printf: forward '%p' format string specifier
From: Lukas Funke Forward '%p' format specifier to the underlying format logic in order to print pointers, especially bitmaps. Signed-off-by: Lukas Funke --- (no changes since v1) cmd/printf.c | 29 + 1 file changed, 29 insertions(+) diff --git a/cmd/printf.c b/cmd/printf.c index 0c6887e0d6..a90c923871 100644 --- a/cmd/printf.c +++ b/cmd/printf.c @@ -90,6 +90,7 @@ #include #include #include +#include #define WANT_HEX_ESCAPES 0 #define PRINT_CONVERSION_ERROR 1 @@ -476,6 +477,16 @@ static int get_width_prec(const char *str) return (int)v; } +static int print_pointer(struct print_inf *inf, char *format, +unsigned int fmt_length, const char *argument) +{ + u64 value = simple_strtoull(argument, NULL, 0); + + printf_str(inf, format, &value); + + return inf->error; +} + /* Print the text in FORMAT, using ARGV for arguments to any '%' directives. * Return advanced ARGV. */ @@ -536,6 +547,24 @@ static char **print_formatted(struct print_inf *inf, char *f, char **argv, int * } } } + if (*f == 'p') { + static const char ptr_format_chars[] = "bl"; + ++f; + ++direc_length; + char *p = strchr(ptr_format_chars, *f); + /* consume whole format token */ + while (*f != '\0' && *(p++) == *f) { + ++f; + ++direc_length; + } + if (print_pointer(inf, direc_start, direc_length, *argv++)) { + printf("`%s': invalid format\n", direc_start); + /* causes main() to exit with error */ + return saved_argv - 1; + } + f--; + break; + } /* Remove "lLhz" size modifiers, repeatedly. * bash does not like "%lld", but coreutils -- 2.30.2
[PATCH 0/2] Enable reset_cpu() in SPL for ZynqMP
From: Lukas Funke This series enables the CPU reset in the SPL for ZynqMP based platforms. This only works if CONFIG_SYSRESET is disabled. This is usually the case since the the regular sysreset requires bl31 firmware to be loaded in order to hand the sysreset over to PMU firmware. In SPL we can talk to the PMU firmware directly and request a CPU reset. The series also introduces SPL_ZYNQMP_FIRMWARE Kconfig symbol in order to make 'CONFIG_IS_ENABLED()' work in SPL. Lukas Funke (2): arm64: zynqmp: Add 'SPL_ZYNQMP_FIRMWARE' to Kconfig xilinx: zynqmp: Enable reset_cpu() in SPL arch/arm/mach-zynqmp/Kconfig | 2 +- arch/arm/mach-zynqmp/aes.c | 2 ++ arch/arm/mach-zynqmp/cpu.c | 4 ++-- board/xilinx/zynqmp/zynqmp.c | 13 +++-- drivers/firmware/Kconfig | 5 + drivers/mmc/zynq_sdhci.c | 4 ++-- drivers/pinctrl/Kconfig | 2 +- 7 files changed, 24 insertions(+), 8 deletions(-) -- 2.30.2
[PATCH 2/2] xilinx: zynqmp: Enable reset_cpu() in SPL
From: Lukas Funke This commit enables SPL to reset the CPU via PMU-firmware. The usual reset mechanism requires bl31 to be loaded which may not be the case in SPL. Signed-off-by: Lukas Funke --- board/xilinx/zynqmp/zynqmp.c | 9 + 1 file changed, 9 insertions(+) diff --git a/board/xilinx/zynqmp/zynqmp.c b/board/xilinx/zynqmp/zynqmp.c index 95a134b972d..99f5c178c1d 100644 --- a/board/xilinx/zynqmp/zynqmp.c +++ b/board/xilinx/zynqmp/zynqmp.c @@ -40,6 +40,7 @@ #include #include #include +#include #include "../common/board.h" #include "pm_cfg_obj.h" @@ -285,6 +286,14 @@ int dram_init(void) #if !CONFIG_IS_ENABLED(SYSRESET) void reset_cpu(void) { + if (!CONFIG_IS_ENABLED(ZYNQMP_FIRMWARE)) { + log_warning("reset failed: ZYNQMP_FIRMWARE disabled"); + return; + } + + xilinx_pm_request(PM_RESET_ASSERT, + ZYNQMP_PM_RESET_START + ZYNQMP_RESET_SOFT, + PM_RESET_ACTION_ASSERT, 0, 0, NULL); } #endif -- 2.30.2
[PATCH 1/2] arm64: zynqmp: Add 'SPL_ZYNQMP_FIRMWARE' to Kconfig
From: Lukas Funke In order to make CONFIG_IS_ENABLED() work with 'ZYNQMP_FIRMWARE' introduce an additional Kconfig 'SPL_ZYNQMP_FIRMWARE' which is selected if and only if ZYNQMP_FIRMWARE is enabled. Driver are adapted such that they build with and without the config being set. Signed-off-by: Lukas Funke --- arch/arm/mach-zynqmp/Kconfig | 2 +- arch/arm/mach-zynqmp/aes.c | 2 ++ arch/arm/mach-zynqmp/cpu.c | 4 ++-- board/xilinx/zynqmp/zynqmp.c | 4 ++-- drivers/firmware/Kconfig | 5 + drivers/mmc/zynq_sdhci.c | 4 ++-- drivers/pinctrl/Kconfig | 2 +- 7 files changed, 15 insertions(+), 8 deletions(-) diff --git a/arch/arm/mach-zynqmp/Kconfig b/arch/arm/mach-zynqmp/Kconfig index 0d2238ace1e..304dce45439 100644 --- a/arch/arm/mach-zynqmp/Kconfig +++ b/arch/arm/mach-zynqmp/Kconfig @@ -36,7 +36,7 @@ config PMUFW_INIT_FILE config ZYNQMP_SPL_PM_CFG_OBJ_FILE string "PMU firmware configuration object to load at runtime by SPL" - depends on SPL + depends on SPL && ZYNQMP_FIRMWARE help Path to a binary PMU firmware configuration object to be linked into U-Boot SPL and loaded at runtime into the PMU firmware. diff --git a/arch/arm/mach-zynqmp/aes.c b/arch/arm/mach-zynqmp/aes.c index 8a2b7fdcbe9..100dde2f372 100644 --- a/arch/arm/mach-zynqmp/aes.c +++ b/arch/arm/mach-zynqmp/aes.c @@ -17,6 +17,7 @@ int zynqmp_aes_operation(struct zynqmp_aes *aes) { +#if CONFIG_IS_ENABLED(ZYNQMP_FIRMWARE) u32 ret_payload[PAYLOAD_ARG_CNT]; int ret; @@ -54,6 +55,7 @@ int zynqmp_aes_operation(struct zynqmp_aes *aes) ret, ret_payload[1]); return -EIO; } +#endif return 0; } diff --git a/arch/arm/mach-zynqmp/cpu.c b/arch/arm/mach-zynqmp/cpu.c index 6ae27894ecd..3515be257a5 100644 --- a/arch/arm/mach-zynqmp/cpu.c +++ b/arch/arm/mach-zynqmp/cpu.c @@ -188,7 +188,7 @@ int zynqmp_mmio_write(const u32 address, { if (IS_ENABLED(CONFIG_SPL_BUILD) || current_el() == 3) return zynqmp_mmio_rawwrite(address, mask, value); -#if defined(CONFIG_ZYNQMP_FIRMWARE) +#if CONFIG_IS_ENABLED(ZYNQMP_FIRMWARE) else return xilinx_pm_request(PM_MMIO_WRITE, address, mask, value, 0, NULL); @@ -207,7 +207,7 @@ int zynqmp_mmio_read(const u32 address, u32 *value) if (IS_ENABLED(CONFIG_SPL_BUILD) || current_el() == 3) { ret = zynqmp_mmio_rawread(address, value); } -#if defined(CONFIG_ZYNQMP_FIRMWARE) +#if CONFIG_IS_ENABLED(ZYNQMP_FIRMWARE) else { u32 ret_payload[PAYLOAD_ARG_CNT]; diff --git a/board/xilinx/zynqmp/zynqmp.c b/board/xilinx/zynqmp/zynqmp.c index f370fb7347a..95a134b972d 100644 --- a/board/xilinx/zynqmp/zynqmp.c +++ b/board/xilinx/zynqmp/zynqmp.c @@ -147,14 +147,14 @@ int board_init(void) int ret; #endif -#if defined(CONFIG_SPL_BUILD) +#if defined(CONFIG_SPL_BUILD) && CONFIG_IS_ENABLED(ZYNQMP_FIRMWARE) /* Check *at build time* if the filename is an non-empty string */ if (sizeof(CONFIG_ZYNQMP_SPL_PM_CFG_OBJ_FILE) > 1) zynqmp_pmufw_load_config_object(zynqmp_pm_cfg_obj, zynqmp_pm_cfg_obj_size); #endif -#if defined(CONFIG_ZYNQMP_FIRMWARE) +#if CONFIG_IS_ENABLED(ZYNQMP_FIRMWARE) struct udevice *dev; uclass_get_device_by_name(UCLASS_FIRMWARE, "power-management", &dev); diff --git a/drivers/firmware/Kconfig b/drivers/firmware/Kconfig index 8789b1ea141..ae785d55d54 100644 --- a/drivers/firmware/Kconfig +++ b/drivers/firmware/Kconfig @@ -30,6 +30,7 @@ config TI_SCI_PROTOCOL config ZYNQMP_FIRMWARE bool "ZynqMP Firmware interface" select FIRMWARE + select SPL_ZYNQMP_FIRMWARE if SPL help Firmware interface driver is used by different drivers to communicate with the firmware for @@ -37,6 +38,10 @@ config ZYNQMP_FIRMWARE Say yes to enable ZynqMP firmware interface driver. If in doubt, say N. +config SPL_ZYNQMP_FIRMWARE + bool "Enable ZynqMP Firmware interface in SPL" + depends on FIRMWARE && SPL + config ARM_SMCCC_FEATURES bool "Arm SMCCC features discovery" depends on ARM_PSCI_FW diff --git a/drivers/mmc/zynq_sdhci.c b/drivers/mmc/zynq_sdhci.c index 935540d1719..3e4cae60c17 100644 --- a/drivers/mmc/zynq_sdhci.c +++ b/drivers/mmc/zynq_sdhci.c @@ -992,7 +992,7 @@ static const struct sdhci_ops arasan_ops = { }; #endif -#if defined(CONFIG_ARCH_ZYNQMP) && defined(CONFIG_ZYNQMP_FIRMWARE) +#if defined(CONFIG_ARCH_ZYNQMP) && CONFIG_IS_ENABLED(ZYNQMP_FIRMWARE) static int sdhci_zynqmp_set_dynamic_config(struct arasan_sdhci_priv *priv, struct udevice *dev) { @@ -1094,7 +1094,7 @@ static int arasan_sdhci_probe(struct udevice *dev) host = priv->host; -#if defined(CONFIG_ARCH_ZYNQMP) && defined(CONFIG_ZYNQMP_FIRMWARE) +#i
[PATCH v2 1/1] xilinx: zynqmp: Enable reset_cpu() in SPL
From: Lukas Funke This commit enables SPL to reset the CPU via PMU-firmware. The usual reset mechanism requires bl31 to be loaded which may not be the case in SPL. Signed-off-by: Lukas Funke --- Changes in v2: - Drop 2/2 since reworking ZYNQMP_FIRMWARE dependency is out-of-scope board/xilinx/zynqmp/zynqmp.c | 9 + 1 file changed, 9 insertions(+) diff --git a/board/xilinx/zynqmp/zynqmp.c b/board/xilinx/zynqmp/zynqmp.c index f370fb7347a..a129b1dbbbc 100644 --- a/board/xilinx/zynqmp/zynqmp.c +++ b/board/xilinx/zynqmp/zynqmp.c @@ -40,6 +40,7 @@ #include #include #include +#include #include "../common/board.h" #include "pm_cfg_obj.h" @@ -285,6 +286,14 @@ int dram_init(void) #if !CONFIG_IS_ENABLED(SYSRESET) void reset_cpu(void) { + if (!IS_ENABLED(CONFIG_ZYNQMP_FIRMWARE)) { + log_warning("reset failed: ZYNQMP_FIRMWARE disabled"); + return; + } + + xilinx_pm_request(PM_RESET_ASSERT, + ZYNQMP_PM_RESET_START + ZYNQMP_RESET_SOFT, + PM_RESET_ACTION_ASSERT, 0, 0, NULL); } #endif -- 2.30.2
[PATCH v2 0/1] Enable reset_cpu() in SPL for ZynqMP
From: Lukas Funke This series enables the CPU reset in the SPL for ZynqMP based platforms. This only works if CONFIG_SYSRESET is disabled. This is usually the case since the the regular sysreset requires bl31 firmware to be loaded in order to hand the sysreset over to PMU firmware. In SPL we can talk to the PMU firmware directly and request a CPU reset. Changes in v2: - Drop 2/2 since reworking ZYNQMP_FIRMWARE dependency is out-of-scope Lukas Funke (1): xilinx: zynqmp: Enable reset_cpu() in SPL board/xilinx/zynqmp/zynqmp.c | 9 + 1 file changed, 9 insertions(+) -- 2.30.2
[PATCH v3 0/7] Add eFuse access for ZynqMP
From: Lukas Funke This series adds a driver to read and write ZynqMP eFuses [1]. The driver can be accessed by the 'fuse read' and 'fuse write' commands Example: => fuse read 0 0xc 3 Reading bank 0: Word 0x000c: 3cb16685 013af244 4000 Note: Accessing eFuses requires eFuse access to be enabled in the underlying PMU firmware. Use cases are: - Reading/writing user specific eFuses to enable device specific implementations - Revoking SPK IDs - Reading SoC version/DNA [1] https://docs.amd.com/r/en-US/ug1085-zynq-ultrascale-trm/eFUSE Changes in v3: - Align ZynqMP eFuse driver with Linux kernel - Adapt versal, versal-net and zynqmp to use common chip-id function - Enable CMD_FUSE and ZYNQMP_EFUSE for zynqmp_virt and zynqmp_kria defconfig - Use 'dev_err' instead 'log_msg_ret' if possible Changes in v2: - Drop vendor specific fuse cmd, use existing fuse cmd - Minor code refactoring (reverse x-mas tree) Lukas Funke (7): configs: zynqmp_kria: Enable CMD_FUSE and ZYNQMP_EFUSE configs: zynqmp_virt: Enable CMD_FUSE and ZYNQMP_EFUSE soc: xilinx: versal: Use zynqmp_pm_get_chipid() to get chip revision soc: xilinx: versal-net: Use zynqmp_pm_get_chipid() to get chip revision soc: xilinx: zynqmp: Use zynqmp_pm_get_chipid() to get chip revision firmware: zynqmp: Add support to access efuses drivers: misc: Add driver to access ZynqMP efuses configs/xilinx_zynqmp_kria_defconfig | 2 + configs/xilinx_zynqmp_virt_defconfig | 2 + drivers/firmware/firmware-zynqmp.c | 31 +++ drivers/misc/Kconfig | 8 + drivers/misc/Makefile| 1 + drivers/misc/zynqmp_efuse.c | 360 +++ drivers/soc/soc_xilinx_versal.c | 13 +- drivers/soc/soc_xilinx_versal_net.c | 13 +- drivers/soc/soc_xilinx_zynqmp.c | 21 +- include/zynqmp_firmware.h| 2 + 10 files changed, 427 insertions(+), 26 deletions(-) create mode 100644 drivers/misc/zynqmp_efuse.c -- 2.30.2
[PATCH v3 1/7] configs: zynqmp_kria: Enable CMD_FUSE and ZYNQMP_EFUSE
From: Lukas Funke Enable CMD_FUSE and ZYNQMP_EFUSE in order to be able to write ZyqnMP eFuses from within the bootloader for Kria SoM. Signed-off-by: Lukas Funke --- (no changes since v1) configs/xilinx_zynqmp_virt_defconfig | 2 ++ 1 file changed, 2 insertions(+) diff --git a/configs/xilinx_zynqmp_virt_defconfig b/configs/xilinx_zynqmp_virt_defconfig index ee87beb19c6..1edd4ac77b1 100644 --- a/configs/xilinx_zynqmp_virt_defconfig +++ b/configs/xilinx_zynqmp_virt_defconfig @@ -65,6 +65,7 @@ CONFIG_CMD_DFU=y CONFIG_CMD_FPGA_LOADBP=y CONFIG_CMD_FPGA_LOADP=y CONFIG_CMD_FPGA_LOAD_SECURE=y +CONFIG_CMD_FUSE=y CONFIG_CMD_GPIO=y CONFIG_CMD_PWM=y CONFIG_CMD_GPT=y @@ -147,6 +148,7 @@ CONFIG_I2C_MUX_PCA954x=y CONFIG_LED=y CONFIG_LED_GPIO=y CONFIG_MISC=y +CONFIG_ZYNQMP_EFUSE=y CONFIG_I2C_EEPROM=y CONFIG_SUPPORT_EMMC_BOOT=y CONFIG_MMC_IO_VOLTAGE=y -- 2.30.2
[PATCH v3 2/7] configs: zynqmp_virt: Enable CMD_FUSE and ZYNQMP_EFUSE
From: Lukas Funke Enable CMD_FUSE and ZYNQMP_EFUSE in order to be able to write ZyqnMP eFuses from within the bootloader. Signed-off-by: Lukas Funke --- (no changes since v1) configs/xilinx_zynqmp_kria_defconfig | 2 ++ 1 file changed, 2 insertions(+) diff --git a/configs/xilinx_zynqmp_kria_defconfig b/configs/xilinx_zynqmp_kria_defconfig index ba42f0c7848..ac91dccbe64 100644 --- a/configs/xilinx_zynqmp_kria_defconfig +++ b/configs/xilinx_zynqmp_kria_defconfig @@ -65,6 +65,7 @@ CONFIG_CMD_DFU=y CONFIG_CMD_FPGA_LOADBP=y CONFIG_CMD_FPGA_LOADP=y CONFIG_CMD_FPGA_LOAD_SECURE=y +CONFIG_CMD_FUSE=y CONFIG_CMD_GPIO=y CONFIG_CMD_PWM=y CONFIG_CMD_GPT=y @@ -147,6 +148,7 @@ CONFIG_I2C_MUX_PCA954x=y CONFIG_LED=y CONFIG_LED_GPIO=y CONFIG_MISC=y +CONFIG_ZYNQMP_EFUSE=y CONFIG_I2C_EEPROM=y CONFIG_SUPPORT_EMMC_BOOT=y CONFIG_MMC_IO_VOLTAGE=y -- 2.30.2
[PATCH v3 4/7] soc: xilinx: versal-net: Use zynqmp_pm_get_chipid() to get chip revision
From: Lukas Funke Use common zynqmp_pm_get_chipid() function to get the chip revision Signed-off-by: Lukas Funke --- (no changes since v1) drivers/soc/soc_xilinx_versal_net.c | 13 ++--- 1 file changed, 6 insertions(+), 7 deletions(-) diff --git a/drivers/soc/soc_xilinx_versal_net.c b/drivers/soc/soc_xilinx_versal_net.c index 146d068bb4a..76467a3bbb5 100644 --- a/drivers/soc/soc_xilinx_versal_net.c +++ b/drivers/soc/soc_xilinx_versal_net.c @@ -47,23 +47,22 @@ static const struct soc_ops soc_xilinx_versal_net_ops = { static int soc_xilinx_versal_net_probe(struct udevice *dev) { struct soc_xilinx_versal_net_priv *priv = dev_get_priv(dev); - u32 ret_payload[PAYLOAD_ARG_CNT]; + u32 idcode, version; int ret; priv->family = versal_family; - if (IS_ENABLED(CONFIG_ZYNQMP_FIRMWARE)) { - ret = xilinx_pm_request(PM_GET_CHIPID, 0, 0, 0, 0, - ret_payload); + if (CONFIG_IS_ENABLED(ZYNQMP_FIRMWARE)) { + ret = zynqmp_pm_get_chipid(&idcode, &version); if (ret) return ret; } else { - ret_payload[2] = readl(PMC_TAP_VERSION); - if (!ret_payload[2]) + version = readl(PMC_TAP_VERSION); + if (!version) return -EINVAL; } - priv->revision = FIELD_GET(PS_VERSION_MASK, ret_payload[2]); + priv->revision = FIELD_GET(PS_VERSION_MASK, version); return 0; } -- 2.30.2
[PATCH v3 3/7] soc: xilinx: versal: Use zynqmp_pm_get_chipid() to get chip revision
From: Lukas Funke Use common zynqmp_pm_get_chipid() function to get the chip revision Signed-off-by: Lukas Funke --- (no changes since v1) drivers/soc/soc_xilinx_versal.c | 13 ++--- 1 file changed, 6 insertions(+), 7 deletions(-) diff --git a/drivers/soc/soc_xilinx_versal.c b/drivers/soc/soc_xilinx_versal.c index 3d8c25c19bb..3d949c4e612 100644 --- a/drivers/soc/soc_xilinx_versal.c +++ b/drivers/soc/soc_xilinx_versal.c @@ -45,23 +45,22 @@ static const struct soc_ops soc_xilinx_versal_ops = { static int soc_xilinx_versal_probe(struct udevice *dev) { struct soc_xilinx_versal_priv *priv = dev_get_priv(dev); - u32 ret_payload[PAYLOAD_ARG_CNT]; + u32 idcode, version; int ret; priv->family = versal_family; - if (IS_ENABLED(CONFIG_ZYNQMP_FIRMWARE)) { - ret = xilinx_pm_request(PM_GET_CHIPID, 0, 0, 0, 0, - ret_payload); + if (CONFIG_IS_ENABLED(ZYNQMP_FIRMWARE)) { + ret = zynqmp_pm_get_chipid(&idcode, &version); if (ret) return ret; } else { - ret_payload[2] = readl(VERSAL_PS_PMC_VERSION); - if (!ret_payload[2]) + version = readl(VERSAL_PS_PMC_VERSION); + if (!version) return -EINVAL; } - priv->revision = ret_payload[2] >> VERSAL_PS_VER_SHIFT; + priv->revision = version >> VERSAL_PS_VER_SHIFT; return 0; } -- 2.30.2
[PATCH v3 5/7] soc: xilinx: zynqmp: Use zynqmp_pm_get_chipid() to get chip revision
From: Lukas Funke Use common zynqmp_pm_get_chipid() function to get the chip revision Signed-off-by: Lukas Funke --- (no changes since v1) drivers/soc/soc_xilinx_zynqmp.c | 21 + 1 file changed, 9 insertions(+), 12 deletions(-) diff --git a/drivers/soc/soc_xilinx_zynqmp.c b/drivers/soc/soc_xilinx_zynqmp.c index d8b4f172a39..8a65810b7d7 100644 --- a/drivers/soc/soc_xilinx_zynqmp.c +++ b/drivers/soc/soc_xilinx_zynqmp.c @@ -346,22 +346,21 @@ static const struct soc_ops soc_xilinx_zynqmp_ops = { static int soc_xilinx_zynqmp_probe(struct udevice *dev) { struct soc_xilinx_zynqmp_priv *priv = dev_get_priv(dev); - u32 ret_payload[PAYLOAD_ARG_CNT]; + u32 idcode, version; int ret; priv->family = zynqmp_family; - if (!IS_ENABLED(CONFIG_ZYNQMP_FIRMWARE)) - ret = zynqmp_mmio_read(ZYNQMP_PS_VERSION, &ret_payload[2]); + if (!CONFIG_IS_ENABLED(ZYNQMP_FIRMWARE)) + ret = zynqmp_mmio_read(ZYNQMP_PS_VERSION, &version); else - ret = xilinx_pm_request(PM_GET_CHIPID, 0, 0, 0, 0, - ret_payload); + ret = zynqmp_pm_get_chipid(&idcode, &version); if (ret < 0) return ret; - priv->revision = ret_payload[2] & ZYNQMP_PS_VER_MASK; + priv->revision = version & ZYNQMP_PS_VER_MASK; - if (IS_ENABLED(CONFIG_ZYNQMP_FIRMWARE)) { + if (CONFIG_IS_ENABLED(ZYNQMP_FIRMWARE)) { /* * Firmware returns: * payload[0][31:0] = status of the operation @@ -370,11 +369,9 @@ static int soc_xilinx_zynqmp_probe(struct udevice *dev) * payload[2][28:20] = EXTENDED_IDCODE * payload[2][29] = PL_INIT */ - u32 idcode = ret_payload[1]; - u32 idcode2 = ret_payload[2] >> - ZYNQMP_CSU_VERSION_EMPTY_SHIFT; - dev_dbg(dev, "IDCODE: 0x%0x, IDCODE2: 0x%0x\n", idcode, - idcode2); + u32 idcode2 = version >> ZYNQMP_CSU_VERSION_EMPTY_SHIFT; + + dev_dbg(dev, "IDCODE: 0x%0x, IDCODE2: 0x%0x\n", idcode, idcode2); ret = soc_xilinx_zynqmp_detect_machine(dev, idcode, idcode2); if (ret) -- 2.30.2
[PATCH v3 6/7] firmware: zynqmp: Add support to access efuses
From: Lukas Funke Add functions to access efuses through PMU firmware interface. Signed-off-by: Lukas Funke --- (no changes since v1) drivers/firmware/firmware-zynqmp.c | 31 ++ include/zynqmp_firmware.h | 2 ++ 2 files changed, 33 insertions(+) diff --git a/drivers/firmware/firmware-zynqmp.c b/drivers/firmware/firmware-zynqmp.c index dfad798a2e7..8e9687693dd 100644 --- a/drivers/firmware/firmware-zynqmp.c +++ b/drivers/firmware/firmware-zynqmp.c @@ -211,6 +211,37 @@ int zynqmp_pm_feature(const u32 api_id) return ret_payload[1] & FIRMWARE_VERSION_MASK; } +int zynqmp_pm_get_chipid(u32 *idcode, u32 *version) +{ + u32 ret_payload[PAYLOAD_ARG_CNT]; + int ret; + + if (!idcode || !version) + return -EINVAL; + + ret = xilinx_pm_request(PM_GET_CHIPID, 0, 0, 0, 0, ret_payload); + *idcode = ret_payload[1]; + *version = ret_payload[2]; + + return ret; +} + +int zynqmp_pm_efuse_access(const u64 address, u32 *out) +{ + u32 ret_payload[PAYLOAD_ARG_CNT]; + int ret; + + if (!out) + return -EINVAL; + + ret = xilinx_pm_request(PM_EFUSE_ACCESS, upper_32_bits(address), + lower_32_bits(address), 0, 0, ret_payload); + + *out = ret_payload[1]; + + return ret; +} + int zynqmp_pm_is_function_supported(const u32 api_id, const u32 id) { int ret; diff --git a/include/zynqmp_firmware.h b/include/zynqmp_firmware.h index 73198a6a6ea..7f18b4d59bf 100644 --- a/include/zynqmp_firmware.h +++ b/include/zynqmp_firmware.h @@ -453,6 +453,8 @@ int xilinx_pm_request(u32 api_id, u32 arg0, u32 arg1, u32 arg2, int zynqmp_pm_set_sd_config(u32 node, enum pm_sd_config_type config, u32 value); int zynqmp_pm_set_gem_config(u32 node, enum pm_gem_config_type config, u32 value); +int zynqmp_pm_get_chipid(u32 *idcode, u32 *version); +int zynqmp_pm_efuse_access(const u64 address, u32 *out); int zynqmp_pm_is_function_supported(const u32 api_id, const u32 id); int zynqmp_mmio_read(const u32 address, u32 *value); int zynqmp_mmio_write(const u32 address, const u32 mask, const u32 value); -- 2.30.2
[PATCH v3 7/7] drivers: misc: Add driver to access ZynqMP efuses
From: Lukas Funke Add driver to access ZynqMP efuses. This is a u-boot port of [1]. Note: Accessing eFuses requires eFuse access to be enabled in the underlying PMU firmware. [1] https://lore.kernel.org/all/20240224114516.86365-8-srinivas.kandaga...@linaro.org/ Signed-off-by: Lukas Funke --- Changes in v3: - Align ZynqMP eFuse driver with Linux kernel - Adapt versal, versal-net and zynqmp to use common chip-id function - Enable CMD_FUSE and ZYNQMP_EFUSE for zynqmp_virt and zynqmp_kria defconfig - Use 'dev_err' instead 'log_msg_ret' if possible Changes in v2: - Drop vendor specific fuse cmd, use existing fuse cmd - Minor code refactoring (reverse x-mas tree) drivers/misc/Kconfig| 8 + drivers/misc/Makefile | 1 + drivers/misc/zynqmp_efuse.c | 360 3 files changed, 369 insertions(+) create mode 100644 drivers/misc/zynqmp_efuse.c diff --git a/drivers/misc/Kconfig b/drivers/misc/Kconfig index 6009d55f400..c07f50c9a76 100644 --- a/drivers/misc/Kconfig +++ b/drivers/misc/Kconfig @@ -298,6 +298,14 @@ config FSL_SEC_MON Security Monitor can be transitioned on any security failures, like software violations or hardware security violations. +config ZYNQMP_EFUSE + bool "Enable ZynqMP eFUSE Driver" + depends on ZYNQMP_FIRMWARE + help + Enable access to Zynq UltraScale (ZynqMP) eFUSEs thought PMU firmware + interface. ZnyqMP has 256 eFUSEs where some of them are security related + and cannot be read back (i.e. AES key). + choice prompt "Security monitor interaction endianess" depends on FSL_SEC_MON diff --git a/drivers/misc/Makefile b/drivers/misc/Makefile index e53d52c47b3..68ba5648eab 100644 --- a/drivers/misc/Makefile +++ b/drivers/misc/Makefile @@ -92,3 +92,4 @@ obj-$(CONFIG_ESM_K3) += k3_esm.o obj-$(CONFIG_ESM_PMIC) += esm_pmic.o obj-$(CONFIG_SL28CPLD) += sl28cpld.o obj-$(CONFIG_SPL_SOCFPGA_DT_REG) += socfpga_dtreg.o +obj-$(CONFIG_ZYNQMP_EFUSE) += zynqmp_efuse.o diff --git a/drivers/misc/zynqmp_efuse.c b/drivers/misc/zynqmp_efuse.c new file mode 100644 index 000..d12de7494d2 --- /dev/null +++ b/drivers/misc/zynqmp_efuse.c @@ -0,0 +1,360 @@ +// SPDX-License-Identifier: GPL-2.0+ +/* + * (C) Copyright 2014 - 2015 Xilinx, Inc. + * Michal Simek + * + * (C) Copyright 2024 Weidmueller Interface GmbH + * Lukas Funke + */ + +#include +#include +#include +#include +#include +#include +#include +#include + +#define SILICON_REVISION_MASK 0xF +#define P_USER_0_64_UPPER_MASK GENMASK(31, 16) +#define P_USER_127_LOWER_4_BIT_MASK GENMASK(3, 0) +#define WORD_INBYTES 4 +#define SOC_VER_SIZE 0x4 +#define EFUSE_MEMORY_SIZE 0x177 +#define UNUSED_SPACE 0x8 +#define ZYNQMP_NVMEM_SIZE (SOC_VER_SIZE + UNUSED_SPACE + \ +EFUSE_MEMORY_SIZE) +#define SOC_VERSION_OFFSET 0x0 +#define EFUSE_START_OFFSET 0xC +#define EFUSE_END_OFFSET 0xFC +#define EFUSE_PUF_START_OFFSET 0x100 +#define EFUSE_PUF_MID_OFFSET 0x140 +#define EFUSE_PUF_END_OFFSET 0x17F +#define EFUSE_NOT_ENABLED 29 + +/* + * efuse access type + */ +enum efuse_access { + EFUSE_READ = 0, + EFUSE_WRITE +}; + +/** + * struct xilinx_efuse - the basic structure + * @src: address of the buffer to store the data to be write/read + * @size: read/write word count + * @offset:read/write offset + * @flag: 0 - represents efuse read and 1- represents efuse write + * @pufuserfuse:0 - represents non-puf efuses, offset is used for read/write + * 1 - represents puf user fuse row number. + * + * this structure stores all the required details to + * read/write efuse memory. + */ +struct xilinx_efuse { + u64 src; + u32 size; + u32 offset; + enum efuse_access flag; + u32 pufuserfuse; +}; + +/** + * struct efuse_map_entry - offset and length of zynqmp fuses + * @offset:offset of efuse to be read/write + * @length:length of efuse + */ +struct efuse_map_entry { + u32 offset; + u32 length; +}; + +struct efuse_map_entry zynqmp_efuse_table[] = { + {0x000, 0x04}, /* soc revision */ + {0x00c, 0x0c}, /* SoC DNA */ + {0x020, 0x04}, /* efuse-usr0 */ + {0x024, 0x04}, /* efuse-usr1 */ + {0x028, 0x04}, /* efuse-usr2 */ + {0x02c, 0x04}, /* efuse-usr3 */ + {0x030, 0x04}, /* efuse-usr4 */ + {0x034, 0x04}, /* efuse-usr5 */ + {0x038, 0x04}, /* efuse-usr6 */ + {0x03c, 0x04}, /* efuse-usr7 */ + {0x040, 0x04}, /* efuse-miscusr */ + {0x050, 0x04}, /* efuse-chash */ + {0x054, 0x04}, /* efuse-pufmisc */ + {0x058, 0x04}, /* efuse-sec */ + {0x05c, 0x04}, /* efuse-spkid */ + {0x060, 0x30}, /* efuse-aeskey */ + {0x0a0, 0x30}, /* ppk0-hash */ + {0x0d0, 0x30}, /* ppk1-hash */ + {0x100, 0x7f}, /* pufuser */ +}; + +static int zynqmp_efuse_get_length(u32 offset, u32 *base_offs
[PATCH v3 0/1] Enable reset_cpu() in SPL for ZynqMP
From: Lukas Funke This series enables the CPU reset in the SPL for ZynqMP based platforms. This only works if CONFIG_SYSRESET is disabled. This is usually the case since the the regular sysreset requires bl31 firmware to be loaded in order to hand the sysreset over to PMU firmware. In SPL we can talk to the PMU firmware directly and request a CPU reset. Changes in v3: - Use 'ZYNQMP_PM_RESET_SOFT' directly - Add comment on what happens if CONFIG_ZYNQMP_FIRMWARE is not enabled Changes in v2: - Drop 2/2 since reworking ZYNQMP_FIRMWARE dependency is out-of-scope Lukas Funke (1): xilinx: zynqmp: Enable reset_cpu() in SPL board/xilinx/zynqmp/zynqmp.c | 12 1 file changed, 12 insertions(+) -- 2.30.2
[PATCH v3 1/1] xilinx: zynqmp: Enable reset_cpu() in SPL
From: Lukas Funke This commit enables SPL to reset the CPU via PMU-firmware. The usual reset mechanism requires bl31 to be loaded which may not be the case in SPL. Signed-off-by: Lukas Funke --- Changes in v3: - Use 'ZYNQMP_PM_RESET_SOFT' directly - Add comment on what happens if CONFIG_ZYNQMP_FIRMWARE is not enabled Changes in v2: - Drop 2/2 since reworking ZYNQMP_FIRMWARE dependency is out-of-scope board/xilinx/zynqmp/zynqmp.c | 12 1 file changed, 12 insertions(+) diff --git a/board/xilinx/zynqmp/zynqmp.c b/board/xilinx/zynqmp/zynqmp.c index f370fb7347a..c37c198ec55 100644 --- a/board/xilinx/zynqmp/zynqmp.c +++ b/board/xilinx/zynqmp/zynqmp.c @@ -285,6 +285,18 @@ int dram_init(void) #if !CONFIG_IS_ENABLED(SYSRESET) void reset_cpu(void) { + if (!IS_ENABLED(CONFIG_ZYNQMP_FIRMWARE)) { + log_warning("reset failed: ZYNQMP_FIRMWARE disabled"); + return; + } + + /* In case of !CONFIG_ZYNQMP_FIRMWARE the call to 'xilinx_pm_request()' +* will be removed by the compiler due to the early return. +* If CONFIG_ZYNQMP_FIRMWARE is defined in SPL 'xilinx_pm_request()' +* will send command over IPI and requires pmufw to be present. +*/ + xilinx_pm_request(PM_RESET_ASSERT, ZYNQMP_PM_RESET_SOFT, + PM_RESET_ACTION_ASSERT, 0, 0, NULL); } #endif -- 2.30.2
[PATCH 0/2] Import environment variables from FIT configuration
From: Lukas Funke This series enables U-Boot to import environment variables from the selectd FIT configuration. One use-case is that the overall build process enriches the FIT configuration node with dm-verity information which should be injected into the kernel commandline. U-Boot will then read these (possibly signed) environment variables and put them into the actual Kernel commandline using variable replacement (see CONFIG_BOOTARGS_SUBST). Example: Config: CONFIG_BOOTARGS_SUBST=y CONFIG_ENV_IMPORT_FIT_CONF=y FIT: configurations { default = "conf-1"; conf-1 { kernel = "kernel-1"; fdt = "fdt-1"; env,dm-verity-args = "dm-mod.create=..."; env,bar = "someothervalue"; }; }; U-Boot cmdline: => env set bootargs="rootfstype=squashfs root=/dev/xyz ${dm-verity-args} ro" => boot Kernel cmdline: Kernel command line: rootfstype=squashfs ... dm-mod.create= ... Lukas Funke (2): env: Add function to import environment variables from FIT conf node test: fit: Add test to check environment extraction from FIT conf node boot/image-fit.c | 4 configs/sandbox_defconfig | 1 + env/Kconfig | 10 + env/common.c | 28 include/env.h | 11 ++ test/py/tests/test_fit.py | 45 +++ 6 files changed, 99 insertions(+) -- 2.30.2
[PATCH 1/2] env: Add function to import environment variables from FIT conf node
From: Lukas Funke Add function which reads properties from FIT conf node prefixed with "env,". Import property name (without 'env,') and it's value as runtime environment variables. Note: this only works with string properties Example: configurations { default = "conf-1"; conf-1 { kernel = "kernel-1"; fdt = "fdt-1"; env,foo = "somevalue"; env,bar = "someothervalue"; }; }; => env print foo foo=somevalue Signed-off-by: Lukas Funke --- boot/image-fit.c | 4 env/Kconfig | 10 ++ env/common.c | 28 include/env.h| 11 +++ 4 files changed, 53 insertions(+) diff --git a/boot/image-fit.c b/boot/image-fit.c index 89e377563ce..0ca31c5f851 100644 --- a/boot/image-fit.c +++ b/boot/image-fit.c @@ -34,6 +34,7 @@ DECLARE_GLOBAL_DATA_PTR; #endif /* !USE_HOSTCC*/ +#include #include #include #include @@ -2128,6 +2129,9 @@ int fit_image_load(struct bootm_headers *images, ulong addr, puts("OK\n"); } +#if !defined(USE_HOSTCC) + env_import_fit_conf(fit, cfg_noffset); +#endif bootstage_mark(BOOTSTAGE_ID_FIT_CONFIG); noffset = fit_conf_get_prop_node(fit, cfg_noffset, prop_name, diff --git a/env/Kconfig b/env/Kconfig index 1f8e90af55e..01b802e54b9 100644 --- a/env/Kconfig +++ b/env/Kconfig @@ -748,6 +748,16 @@ config ENV_FDT_PATH help The initial value of the env_fdt_path variable. +config ENV_IMPORT_FIT_CONF + bool "Amend environment by FIT configuration node properties" + depends on OF_CONTROL + help + If selected, after the environment has been loaded from its + persistent location, the "env,*" properties in the conf-node + of FIT image are used to update the run-time environment. This + can be useful in order to transport signed environment variables + to the kernel cmdline. + config ENV_APPEND bool "Always append the environment with new data" help diff --git a/env/common.c b/env/common.c index 48a565107c1..c8aa59447e9 100644 --- a/env/common.c +++ b/env/common.c @@ -24,6 +24,7 @@ #include #include #include +#include DECLARE_GLOBAL_DATA_PTR; @@ -661,3 +662,30 @@ void env_import_fdt(void) } } #endif + +#define FIT_CONF_ENV_PROPERTY_PREFIX "env," +void env_import_fit_conf(const void *fdt, int conf_node) +{ + int offset, len; + const char *name; + const void *value; + const struct fdt_property *property; + + if (!CONFIG_IS_ENABLED(ENV_IMPORT_FIT_CONF)) + return; + + fdt_for_each_property_offset(offset, fdt, conf_node) { + property = fdt_get_property_by_offset(fdt, offset, NULL); + + name = fdt_get_string(fdt, fdt32_to_cpu(property->nameoff), NULL); + if (strncmp(name, FIT_CONF_ENV_PROPERTY_PREFIX, + sizeof(FIT_CONF_ENV_PROPERTY_PREFIX) - 1)) + continue; + + value = fdt_getprop(fdt, conf_node, name, &len); + /* Get the actual variable name "env,somename" -> "somename" */ + name += sizeof(FIT_CONF_ENV_PROPERTY_PREFIX) - 1; + + env_set(name, value); + } +} diff --git a/include/env.h b/include/env.h index d2a5954ded8..fa4c67056e7 100644 --- a/include/env.h +++ b/include/env.h @@ -382,4 +382,15 @@ void env_import_fdt(void); static inline void env_import_fdt(void) {} #endif +/** + * env_import_fit_conf() - Import environment values from FIT configuration node + * + * This imports environment variables from FIT configuration node. Each + * property name starting with an "env,"-prefix is imported as variable where + * the variable name is the suffix of the property name. + * + * Example: env,somevalue = "foobar" --> somevalue=foobar + */ +void env_import_fit_conf(const void *fdt, int conf_node); + #endif -- 2.30.2
[PATCH 2/2] test: fit: Add test to check environment extraction from FIT conf node
From: Lukas Funke Add test which adds environment variables to the FIT configuration node and checks whether they are exported to the runtime environment. Signed-off-by: Lukas Funke --- configs/sandbox_defconfig | 1 + test/py/tests/test_fit.py | 45 +++ 2 files changed, 46 insertions(+) diff --git a/configs/sandbox_defconfig b/configs/sandbox_defconfig index 93b52f2de5c..7431c8a910e 100644 --- a/configs/sandbox_defconfig +++ b/configs/sandbox_defconfig @@ -142,6 +142,7 @@ CONFIG_ENV_IS_IN_EXT4=y CONFIG_ENV_EXT4_INTERFACE="host" CONFIG_ENV_EXT4_DEVICE_AND_PART="0:0" CONFIG_ENV_IMPORT_FDT=y +CONFIG_ENV_IMPORT_FIT_CONF=y CONFIG_BOOTP_SEND_HOSTNAME=y CONFIG_NETCONSOLE=y CONFIG_IP_DEFRAG=y diff --git a/test/py/tests/test_fit.py b/test/py/tests/test_fit.py index 8f9c4b26411..2a3aba74502 100755 --- a/test/py/tests/test_fit.py +++ b/test/py/tests/test_fit.py @@ -74,6 +74,8 @@ base_its = ''' fdt = "fdt-1"; %(ramdisk_config)s %(loadables_config)s +%(env_var0)s +%(env_var1)s }; }; }; @@ -308,6 +310,13 @@ def test_fit(u_boot_console): 'loadables_config' : '', 'compression' : 'none', + +'env_var0': '', +'env_var0_name': 'foo', +'env_var0_value': 'somevalue', +'env_var1': '', +'env_var1_name': 'bar', +'env_var1_value': 'anothervalue', } # Make a basic FIT and a script to load it @@ -396,6 +405,42 @@ def test_fit(u_boot_console): check_not_equal(ramdisk, ramdisk_out, 'Ramdisk got decompressed?') check_equal(ramdisk + '.gz', ramdisk_out, 'Ramdist not loaded') +# Now a kernel, FDT and environment variables +with cons.log.section('Kernel + FDT load + env'): +params['fdt_load'] = 'load = <%#x>;' % params['fdt_addr'] +params['env_var0'] = ('env,%s = "%s";' % + (params['env_var0_name'], + params['env_var0_value'])) +params['env_var1'] = ('env,%s = "%s";' % + (params['env_var1_name'], + params['env_var1_value'])) +fit = fit_util.make_fit(cons, mkimage, base_its, params) +cons.restart_uboot() + +output = cons.run_command_list(cmd.splitlines()) +check_equal(kernel, kernel_out, 'Kernel not loaded') +check_equal(control_dtb, fdt_out, 'FDT not loaded') +check_not_equal(ramdisk, ramdisk_out, +'Ramdisk loaded but should not be') + +# Check if bootargs strings substitution works +output = cons.run_command_list([ +'env set bootargs \\\"\'my_boot_var=${%s}\'\\\"' % params['env_var0_name'], +'bootm prep', +'env print %s' % params['env_var0_name'], +'env print %s' % params['env_var1_name'], +'env print bootargs']) +assert ('%s=%s' % +(params['env_var0_name'], + params['env_var0_value'])) \ +in output, "Environment not loaded from configuration" +assert ('%s=%s' % +(params['env_var1_name'], + params['env_var1_value'])) \ +in output, "Environment not loaded from configuration" +assert 'bootargs="my_boot_var=%s"' % params['env_var0_value'] \ +in output, "Bootargs strings not substituted" + cons = u_boot_console # We need to use our own device tree file. Remember to restore it -- 2.30.2
[PATCH 0/1] tpm: fix uninitalized field access
From: Lukas Funke tpm_tis_wait_init() is using the 'chip->timeout_b' field which is initialized in tpm_tis_init(). However, the init-function is called *after* tpm_tis_wait_init() introducing an uninitalized field access. This series/commit fixes the issue. Lukas Funke (1): tpm: call tpm_tis_wait_init() after tpm_tis_init() drivers/tpm/tpm2_tis_spi.c | 10 +- 1 file changed, 5 insertions(+), 5 deletions(-) -- 2.30.2
[PATCH 1/1] tpm: call tpm_tis_wait_init() after tpm_tis_init()
From: Lukas Funke tpm_tis_wait_init() is using the 'chip->timeout_b' field which is initialized in tpm_tis_init(). However, the init-function is called *after* tpm_tis_wait_init() introducing an uninitalized field access. This commit switches both routines. Signed-off-by: Lukas Funke --- drivers/tpm/tpm2_tis_spi.c | 10 +- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/drivers/tpm/tpm2_tis_spi.c b/drivers/tpm/tpm2_tis_spi.c index b0fe97ab1d0..5a4dbfd3ccb 100644 --- a/drivers/tpm/tpm2_tis_spi.c +++ b/drivers/tpm/tpm2_tis_spi.c @@ -256,17 +256,17 @@ static int tpm_tis_spi_probe(struct udevice *dev) /* Ensure a minimum amount of time elapsed since reset of the TPM */ mdelay(drv_data->time_before_first_cmd_ms); + tpm_tis_ops_register(dev, &phy_ops); + ret = tpm_tis_init(dev); + if (ret) + goto err; + ret = tpm_tis_wait_init(dev, chip->locality); if (ret) { log(LOGC_DM, LOGL_ERR, "%s: no device found\n", __func__); return ret; } - tpm_tis_ops_register(dev, &phy_ops); - ret = tpm_tis_init(dev); - if (ret) - goto err; - priv->pcr_count = drv_data->pcr_count; priv->pcr_select_min = drv_data->pcr_select_min; priv->version = TPM_V2; -- 2.30.2
[PATCH v2 1/1] tpm: call tpm_tis_wait_init() after tpm_tis_init()
From: Lukas Funke tpm_tis_wait_init() is using the 'chip->timeout_b' field which is initialized in tpm_tis_init(). However, the init-function is called *after* tpm_tis_wait_init() introducing an uninitalized field access. This commit switches both routines. Signed-off-by: Lukas Funke Acked-by: Miquel Raynal --- Changes in v2: - Call tpm_tis_wait_init() from tpm_tis_init() - Use phy_ops for bus access in tpm_tis_wait_init() drivers/tpm/tpm2_tis_core.c | 28 drivers/tpm/tpm2_tis_spi.c | 29 - 2 files changed, 28 insertions(+), 29 deletions(-) diff --git a/drivers/tpm/tpm2_tis_core.c b/drivers/tpm/tpm2_tis_core.c index 680a6409433..1fdf8cfa319 100644 --- a/drivers/tpm/tpm2_tis_core.c +++ b/drivers/tpm/tpm2_tis_core.c @@ -419,6 +419,28 @@ static bool tis_check_ops(struct tpm_tis_phy_ops *phy_ops) return true; } +static int tpm_tis_wait_init(struct udevice *dev, int loc) +{ + struct tpm_chip *chip = dev_get_priv(dev); + unsigned long start, stop; + u8 status; + int ret; + + start = get_timer(0); + stop = chip->timeout_b; + do { + mdelay(TPM_TIMEOUT_MS); + ret = chip->phy_ops->read_bytes(dev, TPM_ACCESS(loc), 1, &status); + if (ret) + break; + + if (status & TPM_ACCESS_VALID) + return 0; + } while (get_timer(start) < stop); + + return -EIO; +} + int tpm_tis_init(struct udevice *dev) { struct tpm_chip *chip = dev_get_priv(dev); @@ -436,6 +458,12 @@ int tpm_tis_init(struct udevice *dev) chip->timeout_c = TIS_SHORT_TIMEOUT_MS; chip->timeout_d = TIS_SHORT_TIMEOUT_MS; + ret = tpm_tis_wait_init(dev, chip->locality); + if (ret) { + log(LOGC_DM, LOGL_ERR, "%s: no device found\n", __func__); + return ret; + } + ret = tpm_tis_request_locality(dev, 0); if (ret) return ret; diff --git a/drivers/tpm/tpm2_tis_spi.c b/drivers/tpm/tpm2_tis_spi.c index b0fe97ab1d0..7909a147c2d 100644 --- a/drivers/tpm/tpm2_tis_spi.c +++ b/drivers/tpm/tpm2_tis_spi.c @@ -188,29 +188,6 @@ static int tpm_tis_spi_write32(struct udevice *dev, u32 addr, u32 value) return tpm_tis_spi_write(dev, addr, sizeof(value), (u8 *)&value_le); } -static int tpm_tis_wait_init(struct udevice *dev, int loc) -{ - struct tpm_chip *chip = dev_get_priv(dev); - unsigned long start, stop; - u8 status; - int ret; - - start = get_timer(0); - stop = chip->timeout_b; - do { - mdelay(TPM_TIMEOUT_MS); - - ret = tpm_tis_spi_read(dev, TPM_ACCESS(loc), 1, &status); - if (ret) - break; - - if (status & TPM_ACCESS_VALID) - return 0; - } while (get_timer(start) < stop); - - return -EIO; -} - static struct tpm_tis_phy_ops phy_ops = { .read_bytes = tpm_tis_spi_read, .write_bytes = tpm_tis_spi_write, @@ -256,12 +233,6 @@ static int tpm_tis_spi_probe(struct udevice *dev) /* Ensure a minimum amount of time elapsed since reset of the TPM */ mdelay(drv_data->time_before_first_cmd_ms); - ret = tpm_tis_wait_init(dev, chip->locality); - if (ret) { - log(LOGC_DM, LOGL_ERR, "%s: no device found\n", __func__); - return ret; - } - tpm_tis_ops_register(dev, &phy_ops); ret = tpm_tis_init(dev); if (ret) -- 2.30.2
[PATCH v2 0/1] tpm: fix uninitalized field access
From: Lukas Funke tpm_tis_wait_init() is using the 'chip->timeout_b' field which is initialized in tpm_tis_init(). However, the init-function is called *after* tpm_tis_wait_init() introducing an uninitalized field access. This series/commit fixes the issue. Changes in v2: - Call tpm_tis_wait_init() from tpm_tis_init() - Use phy_ops for bus access in tpm_tis_wait_init() Lukas Funke (1): tpm: call tpm_tis_wait_init() after tpm_tis_init() drivers/tpm/tpm2_tis_core.c | 28 drivers/tpm/tpm2_tis_spi.c | 29 - 2 files changed, 28 insertions(+), 29 deletions(-) -- 2.30.2
[PATCH v3 01/11] sandbox: add generic find_next_zero_bit implementation
From: Lukas Funke Add generic 'find_next_zero_bit()' implementation in order to enable the use of the 'for_each_set_bitrange' macro. The implementation is currently missing for the sandbox-arch and using the function results in a linker error. The implementation is copied from the 'arm' implementation. Signed-off-by: Lukas Funke Reviewed-by: Simon Glass --- Changes in v3: - Use generic find_next_zero_bit() from arch/arm/include/asm/bitops.h - Redirect sandbox ffz() implementation to generic __ffs() impl arch/sandbox/include/asm/bitops.h | 60 +++ 1 file changed, 38 insertions(+), 22 deletions(-) diff --git a/arch/sandbox/include/asm/bitops.h b/arch/sandbox/include/asm/bitops.h index f27d5e98c5..6950916962 100644 --- a/arch/sandbox/include/asm/bitops.h +++ b/arch/sandbox/include/asm/bitops.h @@ -104,9 +104,6 @@ static inline int __test_and_change_bit(int nr, void *addr) return (old & mask) != 0; } -extern int find_first_zero_bit(void *addr, unsigned size); -extern int find_next_zero_bit(void *addr, int size, int offset); - /* * This routine doesn't need to be atomic. */ @@ -119,27 +116,46 @@ static inline int test_bit(int nr, const void *addr) * ffz = Find First Zero in word. Undefined if no zero exists, * so code should check against ~0UL first.. */ -static inline unsigned long ffz(unsigned long word) -{ - int k; - - word = ~word; - k = 31; - if (word & 0x) { - k -= 16; word <<= 16; - } - if (word & 0x00ff) { - k -= 8; word <<= 8; - } - if (word & 0x0f00) { - k -= 4; word <<= 4; +#define ffz(x) __ffs(~(x)) + +#define find_first_zero_bit(addr, size) \ + find_next_zero_bit((addr), (size), 0) + +static inline int find_next_zero_bit(const unsigned long *addr, int size, +int offset) { + unsigned long *p = ((unsigned long *)addr) + (offset / BITS_PER_LONG); + unsigned long result = offset & ~(BITS_PER_LONG - 1); + unsigned long tmp; + + if (offset >= size) + return size; + size -= result; + offset &= (BITS_PER_LONG - 1); + if (offset) { + tmp = *(p++); + tmp |= ~0UL >> (BITS_PER_LONG - offset); + if (size < BITS_PER_LONG) + goto found_first; + if (~tmp) + goto found_middle; + size -= BITS_PER_LONG; + result += BITS_PER_LONG; } - if (word & 0x3000) { - k -= 2; word <<= 2; + while (size & ~(BITS_PER_LONG - 1)) { + tmp = *(p++); + if (~tmp) + goto found_middle; + result += BITS_PER_LONG; + size -= BITS_PER_LONG; } - if (word & 0x4000) - k -= 1; - return k; + if (!size) + return result; + tmp = *p; + +found_first: + tmp |= ~0UL << size; +found_middle: + return result + ffz(tmp); } /* -- 2.30.2
[PATCH v3 00/11] Enable setexpr command to print cpu-list like bitmaps
From: Lukas Funke This series enables the 'setexpr' command to print "cpu list"-like bitmaps based on the printk format specifier [1]. One use-case is to pass cpu list [2] based kernel parameter like 'isolcpu', 'nohz_full', irq affinity or RCU related CPU parameter to the kernel via a separate firmware variable without exposing the 'bootargs' variable to directly. Example: => env set value 0xdeadbeef => setexpr a fmt isolcpus=%32pbl $value => echo $a isolcpus=0-3,5-7,9-13,15-16,18-19,21,23,25-28,30-31 [1] https://www.kernel.org/doc/Documentation/printk-formats.txt [2] https://www.kernel.org/doc/html/latest/admin-guide/kernel-parameters.html Changes in v3: - Use generic find_next_zero_bit() from arch/arm/include/asm/bitops.h - Redirect sandbox ffz() implementation to generic __ffs() impl - Remove '%bp' from documentation - Give an example output in the documentation - Remove bitmap_string() conversion function since the same function can be achieved using other format specifier - Dereference pointer argument (i.e. *value) in the 'setexpr name fmt value' case. This is currently only supported in the 'setexptr [*]' and 'setexptr [*] [*]' case Changes in v2: - Add bitmap format specifier to documentation Lukas Funke (11): sandbox: add generic find_next_zero_bit implementation linux: bitmap.h: add 'for_each_set_bitrange' iteration macro test: cmd: setexpr: Add tests for bitmap string format doc: printf() codes: Add bitmap format specifier cmd: printf: Correctly handle field width lib: Add hextobarray() function lib: vsprintf: enable '%pbl' format specifier setexpr: rename 'get_arg()' to 'setexpr_get_arg()' setexpr: Promote 'setexpr_get_arg()' to a public function setexptr: Extend setexpr_get_arg() to handle pointer to memory cmd: printf: forward '%p' format string specifier arch/sandbox/include/asm/bitops.h | 60 +++ cmd/printf.c | 53 ++- cmd/setexpr.c | 48 +++-- doc/develop/printf.rst| 4 +++ include/command.h | 27 ++ include/linux/bitmap.h| 7 include/vsprintf.h| 7 lib/strto.c | 35 ++ lib/vsprintf.c| 42 ++ test/cmd/setexpr.c| 22 10 files changed, 263 insertions(+), 42 deletions(-) -- 2.30.2
[PATCH v3 05/11] cmd: printf: Correctly handle field width
From: Lukas Funke Correctly parse the field width from the format specifier. Before this commit the field_width was simply ignored. Signed-off-by: Lukas Funke --- (no changes since v1) cmd/printf.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/cmd/printf.c b/cmd/printf.c index 0c6887e0d6..f56543b79e 100644 --- a/cmd/printf.c +++ b/cmd/printf.c @@ -517,7 +517,7 @@ static char **print_formatted(struct print_inf *inf, char *f, char **argv, int * field_width = get_width_prec(*argv++); } else { while (isdigit(*f)) { - ++f; + field_width = field_width * 10 + *(f++) - '0'; ++direc_length; } } -- 2.30.2
[PATCH v3 02/11] linux: bitmap.h: add 'for_each_set_bitrange' iteration macro
From: Lukas Funke Add 'for_each_set_bitrange' (from Linux kernel) in order to iterate over each set bitrange of a bitmap. This becomes handy if one wants to generate a cpu list i.e. for isolcpu or nohz_full. Signed-off-by: Lukas Funke Reviewed-by: Simon Glass --- (no changes since v1) include/linux/bitmap.h | 7 +++ 1 file changed, 7 insertions(+) diff --git a/include/linux/bitmap.h b/include/linux/bitmap.h index 0a8503af9f..9714533078 100644 --- a/include/linux/bitmap.h +++ b/include/linux/bitmap.h @@ -159,6 +159,13 @@ static inline unsigned long find_first_bit(const unsigned long *addr, unsigned l (bit) < (size);\ (bit) = find_next_bit((addr), (size), (bit) + 1)) +#define for_each_set_bitrange(b, e, addr, size)\ + for ((b) = 0; \ +(b) = find_next_bit((addr), (size), b),\ +(e) = find_next_zero_bit((addr), (size), (b) + 1), \ +(b) < (size); \ +(b) = (e) + 1) + static inline unsigned long bitmap_find_next_zero_area(unsigned long *map, unsigned long size, -- 2.30.2
[PATCH v3 03/11] test: cmd: setexpr: Add tests for bitmap string format
From: Lukas Funke Add tests to test the bitmap format specifier. Test different bit widths and access to memory by pointer. Signed-off-by: Lukas Funke --- (no changes since v1) test/cmd/setexpr.c | 22 ++ 1 file changed, 22 insertions(+) diff --git a/test/cmd/setexpr.c b/test/cmd/setexpr.c index 312593e1e3..c536c9e963 100644 --- a/test/cmd/setexpr.c +++ b/test/cmd/setexpr.c @@ -465,6 +465,28 @@ static int setexpr_test_fmt(struct unit_test_state *uts) ut_asserteq(1, run_command("setexpr fred fmt hello% bf", 0)); /* Error exceeding maximum string length */ ut_asserteq(1, run_command("setexpr fred fmt \"%0128d\" 456", 0)); + /* Test bitmask long string */ + ut_assertok(run_command("setexpr fred fmt isolcpu=%64pbl 0x1F1", 0)); + ut_asserteq_str("isolcpu=0,4-8", env_get("fred")); + /* Test bitmask long string (more complicated) */ + ut_assertok(run_command("setexpr fred fmt nohz_full=%32pbl 0x", 0)); + ut_asserteq_str("nohz_full=0,2,4,6,8,10,12,14,16,18,20,22,24,26,28,30", env_get("fred")); + ut_assertok(run_command("setexpr fred fmt %64pbl 0xdeadbeef", 0)); + ut_asserteq_str("0-3,5-7,9-13,15-16,18-19,21,23,25-28,30-31", env_get("fred")); + /* Test bitmask on 64...256 */ + ut_assertok(run_command("setexpr fred fmt %64pbl 0xf0f0f0f0f0f0f0f0", 0)); + ut_asserteq_str("4-7,12-15,20-23,28-31,36-39,44-47,52-55,60-63", env_get("fred")); + ut_assertok(run_command("setexpr fred fmt %128pbl 0xf0f0f0f0f0f0f0f0f0f0f0f0f0f0f0f0", 0)); + ut_asserteq_str("4-7,12-15,20-23,28-31,36-39,44-47,52-55,60-63,68-71,76-79,84-87,92-95,100-103,108-111,116-119,124-127", env_get("fred")); + /* clear lower bitmask, otherwise output gets truncated */ + ut_assertok(run_command("setexpr fred fmt %256pbl 0xf0f0f0f0f0f0f0f0f0f0f0f0f0f0f0f0", 0)); + ut_asserteq_str("132-135,140-143,148-151,156-159,164-167,172-175,180-183,188-191,196-199,204-207,212-215,220-223,228-231,236-239,244-247,252-255", env_get("fred")); + /* Test memory access */ + memset(buf, 0, BUF_SIZE); + ut_assertok(run_command("env set myaddr 0x0;" + "mw.l $myaddr 0xdeadbeef 1;" + "setexpr fred fmt %64pbl *$myaddr", 0)); + ut_asserteq_str("0-3,5-7,9-13,15-16,18-19,21,23,25-28,30-31", env_get("fred")); unmap_sysmem(buf); -- 2.30.2
[PATCH v3 06/11] lib: Add hextobarray() function
From: Lukas Funke Add a 'hextobarray()' function which converts a hex string to it's memory representation. This can be used to represent large integer numbers or bitmasks which do not fit in a regular unsigned long value. Signed-off-by: Lukas Funke --- (no changes since v1) include/vsprintf.h | 7 +++ lib/strto.c| 35 +++ 2 files changed, 42 insertions(+) diff --git a/include/vsprintf.h b/include/vsprintf.h index ed8a060ee1..82c8bf029e 100644 --- a/include/vsprintf.h +++ b/include/vsprintf.h @@ -368,4 +368,11 @@ int vsscanf(const char *inp, char const *fmt0, va_list ap); */ int sscanf(const char *buf, const char *fmt, ...); +/** + * hextobarray - Convert a hex-string to a byte array + * @cp:hex string to convert + * Return: a pointer to a byte array, -ENOMEM on error + */ +uchar *hextobarray(const char *cp); + #endif diff --git a/lib/strto.c b/lib/strto.c index 5157332d6c..eb507e4ab8 100644 --- a/lib/strto.c +++ b/lib/strto.c @@ -13,6 +13,7 @@ #include #include #include +#include /* from lib/kstrtox.c */ static const char *_parse_integer_fixup_radix(const char *s, uint *basep) @@ -73,6 +74,40 @@ ulong simple_strtoul(const char *cp, char **endp, uint base) return result; } +uchar *hextobarray(const char *cp) +{ + int i, len; + __maybe_unused unsigned int base; + __maybe_unused const char *endptr; + unsigned char *array; + + len = strlen(cp); + array = (unsigned char *)malloc(len); + if (!array) + return ERR_PTR(-ENOMEM); + + memset(array, 0, len); + +#if __BYTE_ORDER == __LITTLE_ENDIAN + endptr = (cp + len - 1); + for (i = 0; i < len && endptr > cp; i++) { + array[i] |= decode_digit(*(endptr)); + endptr--; + array[i] |= decode_digit(*endptr) << 4; + endptr--; + } +#else + cp = _parse_integer_fixup_radix(cp, &base); + for (i = 0; i < len && *cp; i++) { + array[i] |= decode_digit(*cp) << 4; + cp++; + array[i] |= decode_digit(*cp); + cp++; + } +#endif + return array; +} + ulong hextoul(const char *cp, char **endp) { return simple_strtoul(cp, endp, 16); -- 2.30.2
[PATCH v3 04/11] doc: printf() codes: Add bitmap format specifier
From: Lukas Funke Add '%pbl' printf format specifier as descriped in [1]. [1] https://www.kernel.org/doc/Documentation/printk-formats.txt Signed-off-by: Lukas Funke --- Changes in v3: - Remove '%bp' from documentation - Give an example output in the documentation doc/develop/printf.rst | 4 1 file changed, 4 insertions(+) diff --git a/doc/develop/printf.rst b/doc/develop/printf.rst index 99d05061b1..8220c7c12b 100644 --- a/doc/develop/printf.rst +++ b/doc/develop/printf.rst @@ -165,6 +165,10 @@ Pointers * phys_size_t * resource_size_t +%pbl +'%pbl' outputs a bitmap as range list with field width as +the number of bits. e.g. '0,8-11,13-16,18-19,22-25,27,29,31' + %pD prints a UEFI device path -- 2.30.2
[PATCH v3 09/11] setexpr: Promote 'setexpr_get_arg()' to a public function
From: Lukas Funke Promote 'setexpr_get_arg()' to a public function in order to use it from the setexpr command and in the printf-internals. Signed-off-by: Lukas Funke --- (no changes since v1) cmd/setexpr.c | 15 +-- include/command.h | 27 +++ 2 files changed, 28 insertions(+), 14 deletions(-) diff --git a/cmd/setexpr.c b/cmd/setexpr.c index bc57d41448..9caa68d20d 100644 --- a/cmd/setexpr.c +++ b/cmd/setexpr.c @@ -21,20 +21,7 @@ #define MAX_STR_LEN 128 -/** - * struct expr_arg: Holds an argument to an expression - * - * @ival: Integer value (if width is not CMD_DATA_SIZE_STR) - * @sval: String value (if width is CMD_DATA_SIZE_STR) - */ -struct expr_arg { - union { - ulong ival; - char *sval; - }; -}; - -static int setexpr_get_arg(char *s, int w, struct expr_arg *argp) +int setexpr_get_arg(char *s, int w, struct expr_arg *argp) { struct expr_arg arg; diff --git a/include/command.h b/include/command.h index 4cec634545..d0aa98b1f6 100644 --- a/include/command.h +++ b/include/command.h @@ -248,6 +248,33 @@ int do_env_set_efi(struct cmd_tbl *cmdtp, int flag, int argc, int setexpr_regex_sub(char *data, uint data_size, char *nbuf, uint nbuf_size, const char *r, const char *s, bool global); +/** + * struct expr_arg: Holds an argument to an expression + * + * @ival: Integer value (if width is not CMD_DATA_SIZE_STR) + * @sval: String value (if width is CMD_DATA_SIZE_STR) + * @bmap: Bitmap value (if width is > u64) + */ +struct expr_arg { + union { + ulong ival; + char *sval; + uchar *bmap; + }; +}; + +/** + * setexpr_get_arg() - Converts a string argument to it's value. If argument + * starts with a '*' treat it as a pointer and dereference. + * + * @s: Argument string + * @w: Byte width of argument + * @argp: Pointer where the value should be stored + * + * Return: 0 on success, -EINVAL on failure + */ +int setexpr_get_arg(char *s, int w, struct expr_arg *argp); + /* * Error codes that commands return to cmd_process(). We use the standard 0 * and 1 for success and failure, but add one more case - failure with a -- 2.30.2
[PATCH v3 08/11] setexpr: rename 'get_arg()' to 'setexpr_get_arg()'
From: Lukas Funke Prefix the get_arg() function with 'setexpr_' in order to prepare the removal of the static specifier. The prefix shall denote the origin of the function. Signed-off-by: Lukas Funke --- (no changes since v1) cmd/setexpr.c | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/cmd/setexpr.c b/cmd/setexpr.c index 233471f6cb..bc57d41448 100644 --- a/cmd/setexpr.c +++ b/cmd/setexpr.c @@ -34,7 +34,7 @@ struct expr_arg { }; }; -static int get_arg(char *s, int w, struct expr_arg *argp) +static int setexpr_get_arg(char *s, int w, struct expr_arg *argp) { struct expr_arg arg; @@ -388,7 +388,7 @@ static int do_setexpr(struct cmd_tbl *cmdtp, int flag, int argc, w = cmd_get_data_size(argv[0], 4); - if (get_arg(argv[2], w, &aval)) + if (setexpr_get_arg(argv[2], w, &aval)) return CMD_RET_FAILURE; /* format string assignment: "setexpr name fmt %d value" */ @@ -441,7 +441,7 @@ static int do_setexpr(struct cmd_tbl *cmdtp, int flag, int argc, if (strlen(argv[3]) != 1) return CMD_RET_USAGE; - if (get_arg(argv[4], w, &bval)) { + if (setexpr_get_arg(argv[4], w, &bval)) { if (w == CMD_DATA_SIZE_STR) free(aval.sval); return CMD_RET_FAILURE; -- 2.30.2
[PATCH v3 07/11] lib: vsprintf: enable '%pbl' format specifier
From: Lukas Funke The commit enables vsprintf() to handle the '%pbl' format specifier in order to print bitmaps and its derivatives such as cpumask and nodemask [1]. This can be used to derive kernel boot parameters from bitmaks such as 'isolcpu' or 'nohz_full' [2]. [1] https://www.kernel.org/doc/Documentation/printk-formats.txt [2] https://www.kernel.org/doc/html/latest/admin-guide/kernel-parameters.html Signed-off-by: Lukas Funke --- Changes in v3: - Remove bitmap_string() conversion function since the same function can be achieved using other format specifier lib/vsprintf.c | 42 ++ 1 file changed, 42 insertions(+) diff --git a/lib/vsprintf.c b/lib/vsprintf.c index 27ea9c907a..e1779d75f8 100644 --- a/lib/vsprintf.c +++ b/lib/vsprintf.c @@ -24,6 +24,7 @@ #include #include #include +#include /* we use this so that we can do without the ctype library */ #define is_digit(c)((c) >= '0' && (c) <= '9') @@ -389,6 +390,33 @@ static char *ip4_addr_string(char *buf, char *end, u8 *addr, int field_width, flags & ~SPECIAL); } +static char *bitmap_list_string(char *buf, char *end, unsigned long *addr, + int field_width, int precision, int flags) +{ + int nr_bits = max_t(int, field_width, 0); + int first = 1; + int rbot, rtop; + + for_each_set_bitrange(rbot, rtop, addr, nr_bits) { + if (!first) { + if (buf < end) + *buf = ','; + buf++; + } + first = 0; + + buf = number(buf, end, rbot, 10, 0, -1, 0); + if (rtop == rbot + 1) + continue; + + if (buf < end) + *buf = '-'; + buf = number(++buf, end, rtop - 1, 10, 0, -1, 0); + } + + return buf; +} + #ifdef CONFIG_LIB_UUID /* * This works (roughly) the same way as Linux's. @@ -502,6 +530,20 @@ static char *pointer(const char *fmt, char *buf, char *end, void *ptr, precision, flags); flags &= ~SPECIAL; break; + case 'b': + switch (fmt[1]) { + case 'l': + /* if the field width is not a multiple of the underlying +* datatype (ulong), we get incorrect results from the bit twiddle +* macros. Thus, round up to a multiple of field width of ulong +*/ + field_width = field_width % BITS_PER_LONG ? + ALIGN(field_width, BITS_PER_LONG) : field_width; + return bitmap_list_string(buf, end, ptr, field_width, + precision, flags); + default: + return ERR_PTR(-EINVAL); + } #ifdef CONFIG_LIB_UUID case 'U': return uuid_string(buf, end, ptr, field_width, precision, -- 2.30.2
[PATCH v3 10/11] setexptr: Extend setexpr_get_arg() to handle pointer to memory
From: Lukas Funke Extend setexpr_get_arg() function in order to handle bitmaps with length greater than 8 byte. If the bitmap is provided as hex string the string is parsed into a bitmap. Signed-off-by: Lukas Funke --- (no changes since v1) cmd/setexpr.c | 29 ++--- 1 file changed, 26 insertions(+), 3 deletions(-) diff --git a/cmd/setexpr.c b/cmd/setexpr.c index 9caa68d20d..fed457bb7e 100644 --- a/cmd/setexpr.c +++ b/cmd/setexpr.c @@ -17,6 +17,7 @@ #include #include #include +#include #include "printf.h" #define MAX_STR_LEN 128 @@ -24,6 +25,8 @@ int setexpr_get_arg(char *s, int w, struct expr_arg *argp) { struct expr_arg arg; + uchar *bmap; + ulong val; /* * If the parameter starts with a '*' then assume it is a pointer to @@ -32,7 +35,6 @@ int setexpr_get_arg(char *s, int w, struct expr_arg *argp) if (s[0] == '*') { ulong *p; ulong addr; - ulong val; int len; char *str; @@ -71,17 +73,38 @@ int setexpr_get_arg(char *s, int w, struct expr_arg *argp) unmap_sysmem(p); arg.ival = val; break; - default: +#if BITS_PER_LONG == 64 + case 8: p = map_sysmem(addr, sizeof(ulong)); val = *p; unmap_sysmem(p); arg.ival = val; break; +#endif + default: + p = map_sysmem(addr, w); + bmap = malloc(w); + if (!bmap) { + printf("Out of memory\n"); + return -ENOMEM; + } + memcpy(bmap, p, w); + arg.bmap = bmap; + unmap_sysmem(p); } } else { if (w == CMD_DATA_SIZE_STR) return -EINVAL; - arg.ival = hextoul(s, NULL); + if (w > sizeof(ulong)) { + bmap = hextobarray(s); + if (IS_ERR(bmap)) { + printf("Out of memory\n"); + return -ENOMEM; + } + arg.bmap = bmap; + } else { + arg.ival = hextoul(s, NULL); + } } *argp = arg; -- 2.30.2
[PATCH v3 11/11] cmd: printf: forward '%p' format string specifier
From: Lukas Funke Forward '%p' format specifier to the underlying format logic in order to print pointers, especially bitmaps. Signed-off-by: Lukas Funke --- Changes in v3: - Dereference pointer argument (i.e. *value) in the 'setexpr name fmt value' case. This is currently only supported in the 'setexptr [*]' and 'setexptr [*] [*]' case cmd/printf.c | 51 +++ 1 file changed, 51 insertions(+) diff --git a/cmd/printf.c b/cmd/printf.c index f56543b79e..2e54faf339 100644 --- a/cmd/printf.c +++ b/cmd/printf.c @@ -85,11 +85,13 @@ */ #include +#include #include #include #include #include #include +#include #define WANT_HEX_ESCAPES 0 #define PRINT_CONVERSION_ERROR 1 @@ -476,6 +478,38 @@ static int get_width_prec(const char *str) return (int)v; } +static int print_pointer(struct print_inf *inf, char *format, +unsigned int fmt_length, int field_width, +int precision, const char *argument) +{ + struct expr_arg aval; + + if (setexpr_get_arg(skip_whitespace(argument), field_width >> 3, &aval)) + return CMD_RET_FAILURE; + + if (field_width > BITS_PER_LONG) { + printf_str(inf, format, aval.bmap); + free(aval.bmap); + } else { + printf_str(inf, format, &aval.ival); + } + + switch (inf->error) { + case 0: + return 0; + case PRINT_SIZE_ERROR: + printf("printf: size error\n"); break; + case PRINT_CONVERSION_ERROR: + printf("printf: conversion error\n"); break; + case PRINT_TRUNCATED_ERROR: + printf("printf: output truncated\n"); break; + default: + printf("printf: unknown error\n"); + } + + return -1; +} + /* Print the text in FORMAT, using ARGV for arguments to any '%' directives. * Return advanced ARGV. */ @@ -536,6 +570,23 @@ static char **print_formatted(struct print_inf *inf, char *f, char **argv, int * } } } + if (*f == 'p') { + static const char ptr_format_chars[] = "bl"; + ++f; + ++direc_length; + char *p = strchr(ptr_format_chars, *f); + /* consume whole format token */ + while (*f != '\0' && *(p++) == *f) { + ++f; + ++direc_length; + } + if (print_pointer(inf, direc_start, direc_length, + field_width, precision, *argv++)) { + return saved_argv - 1; + } + f--; + break; + } /* Remove "lLhz" size modifiers, repeatedly. * bash does not like "%lld", but coreutils -- 2.30.2
[PATCH 1/3] firmware: zynqmp: Add support to access efuses
From: Lukas Funke Add functions to access efuses through PMU firmware interface. Signed-off-by: Lukas Funke --- drivers/firmware/firmware-zynqmp.c | 31 ++ include/zynqmp_firmware.h | 2 ++ 2 files changed, 33 insertions(+) diff --git a/drivers/firmware/firmware-zynqmp.c b/drivers/firmware/firmware-zynqmp.c index f99507d86c6..7483f2a8709 100644 --- a/drivers/firmware/firmware-zynqmp.c +++ b/drivers/firmware/firmware-zynqmp.c @@ -210,6 +210,37 @@ int zynqmp_pm_feature(const u32 api_id) return ret_payload[1] & FIRMWARE_VERSION_MASK; } +int zynqmp_pm_get_chipid(u32 *idcode, u32 *version) +{ + int ret; + u32 ret_payload[PAYLOAD_ARG_CNT]; + + if (!idcode || !version) + return -EINVAL; + + ret = xilinx_pm_request(PM_GET_CHIPID, 0, 0, 0, 0, ret_payload); + *idcode = ret_payload[1]; + *version = ret_payload[2]; + + return ret; +} + +int zynqmp_pm_efuse_access(const u64 address, u32 *out) +{ + int ret; + u32 ret_payload[PAYLOAD_ARG_CNT]; + + if (!out) + return -EINVAL; + + ret = xilinx_pm_request(PM_EFUSE_ACCESS, upper_32_bits(address), + lower_32_bits(address), 0, 0, ret_payload); + + *out = ret_payload[1]; + + return ret; +} + int zynqmp_pm_is_function_supported(const u32 api_id, const u32 id) { int ret; diff --git a/include/zynqmp_firmware.h b/include/zynqmp_firmware.h index 73198a6a6ea..7f18b4d59bf 100644 --- a/include/zynqmp_firmware.h +++ b/include/zynqmp_firmware.h @@ -453,6 +453,8 @@ int xilinx_pm_request(u32 api_id, u32 arg0, u32 arg1, u32 arg2, int zynqmp_pm_set_sd_config(u32 node, enum pm_sd_config_type config, u32 value); int zynqmp_pm_set_gem_config(u32 node, enum pm_gem_config_type config, u32 value); +int zynqmp_pm_get_chipid(u32 *idcode, u32 *version); +int zynqmp_pm_efuse_access(const u64 address, u32 *out); int zynqmp_pm_is_function_supported(const u32 api_id, const u32 id); int zynqmp_mmio_read(const u32 address, u32 *value); int zynqmp_mmio_write(const u32 address, const u32 mask, const u32 value); -- 2.30.2
[PATCH 2/3] amd64: zynqmp: Add command to program efuses
From: Lukas Funke Add subcommands to read/write eFuses using u-boot. The subcommands through the 'zynqmp' command. Example: => zynqmp efuse_read 0xc 0xc : 85 36 b1 3c 34 f2 3b 01 00 00 00 40 .f. --- board/xilinx/zynqmp/cmds.c | 101 + 1 file changed, 101 insertions(+) diff --git a/board/xilinx/zynqmp/cmds.c b/board/xilinx/zynqmp/cmds.c index bf39c5472ea..e8d70ffecd6 100644 --- a/board/xilinx/zynqmp/cmds.c +++ b/board/xilinx/zynqmp/cmds.c @@ -16,6 +16,9 @@ #include #include #include +#include +#include +#include static int do_zynqmp_verify_secure(struct cmd_tbl *cmdtp, int flag, int argc, char *const argv[]) @@ -340,6 +343,99 @@ static int do_zynqmp_sha3(struct cmd_tbl *cmdtp, int flag, return CMD_RET_SUCCESS; } +static int do_zynqmp_efuse_read(struct cmd_tbl *cmdtp, int flag, + int argc, char * const argv[]) +{ + struct udevice *dev; + u32 offset, len; + u8 buf[32]; + int ret; + + if (!CONFIG_IS_ENABLED(ZYNQMP_EFUSE)) { + printf("Failed: not supported\n"); + return CMD_RET_FAILURE; + } + + if (argc > cmdtp->maxargs || argc < (cmdtp->maxargs - 1)) + return CMD_RET_USAGE; + + memset(buf, 0, sizeof(buf)); + + offset = hextoul(argv[2], NULL); + len = hextoul(argv[3], NULL); + + if (len > sizeof(buf)) { + printf("Failed: length exceeds buffer size"); + return CMD_RET_FAILURE; + } + + ret = uclass_get_device_by_driver(UCLASS_MISC, + DM_DRIVER_GET(zynqmp_efuse), &dev); + if (ret) { + printf("Failed to initialize zynqmp_efuse: %d\n", ret); + return CMD_RET_FAILURE; + } + + ret = misc_read(dev, offset, (void *)buf, len); + if (ret) { + printf("Failed: cannot read efuse at 0x%x, errocode %d\n", + offset, ret); + return CMD_RET_FAILURE; + } + + if (CONFIG_IS_ENABLED(HEXDUMP)) + print_hex_dump_bytes("", DUMP_PREFIX_OFFSET, buf, len); + + return CMD_RET_SUCCESS; +} + +static int do_zynqmp_efuse_write(struct cmd_tbl *cmdtp, int flag, +int argc, char * const argv[]) +{ + struct udevice *dev; + u64 value; + u32 offset, len; + u8 buf[sizeof(u64)]; + int ret; + + if (!CONFIG_IS_ENABLED(ZYNQMP_EFUSE)) { + printf("Failed: not supported\n"); + return CMD_RET_FAILURE; + } + + if (argc > cmdtp->maxargs || argc < (cmdtp->maxargs - 1)) + return CMD_RET_USAGE; + + memset(buf, 0, sizeof(buf)); + + offset = hextoul(argv[2], NULL); + len = hextoul(argv[3], NULL); + + if (len <= sizeof(u64)) { + value = hextoul(argv[4], NULL); + memcpy(buf, &value, sizeof(value)); + } else { + printf("Cannot write more than %zu byte to efuse\n", sizeof(u64)); + return CMD_RET_FAILURE; + } + + ret = uclass_get_device_by_driver(UCLASS_MISC, + DM_DRIVER_GET(zynqmp_efuse), &dev); + if (ret) { + printf("Failed to initialize zynqmp_efuse: %d\n", ret); + return CMD_RET_FAILURE; + } + + ret = misc_write(dev, offset, (void *)buf, sizeof(buf)); + if (ret) { + printf("Failed: cannot read efuse at 0x%x, errocode 0x%x\n", + offset, ret); + return CMD_RET_FAILURE; + } + + return CMD_RET_SUCCESS; +} + static struct cmd_tbl cmd_zynqmp_sub[] = { U_BOOT_CMD_MKENT(secure, 5, 0, do_zynqmp_verify_secure, "", ""), U_BOOT_CMD_MKENT(pmufw, 4, 0, do_zynqmp_pmufw, "", ""), @@ -348,6 +444,8 @@ static struct cmd_tbl cmd_zynqmp_sub[] = { U_BOOT_CMD_MKENT(aes, 9, 0, do_zynqmp_aes, "", ""), U_BOOT_CMD_MKENT(rsa, 7, 0, do_zynqmp_rsa, "", ""), U_BOOT_CMD_MKENT(sha3, 5, 0, do_zynqmp_sha3, "", ""), + U_BOOT_CMD_MKENT(efuse_read, 4, 0, do_zynqmp_efuse_read, "", ""), + U_BOOT_CMD_MKENT(efuse_write, 5, 0, do_zynqmp_efuse_write, "", ""), #ifdef CONFIG_DEFINE_TCM_OCM_MMAP U_BOOT_CMD_MKENT(tcminit, 3, 0, do_zynqmp_tcm_init, "", ""), #endif @@ -422,6 +520,9 @@ U_BOOT_LONGHELP(zynqmp, " 48 bytes hash value into srcaddr\n" " Optional key_addr can be specified for saving sha3 hash value\n" " Note: srcaddr/srclen should not be 0\n" + "zynqmp efuse_read offset len - read efuse at given offset\n" + "zynqmp efuse_write offset len value - write value of length \n" + " to efuse at given offset\n" ); U_BOOT_CMD( -- 2.30.2
[PATCH 0/3] Add eFuse access for ZynqMP
From: Lukas Funke This series adds a driver to read and write ZynqMP eFuses [1]. The driver can be accessed by the 'efuse_read' and 'efuse_write' subcommands of the 'zynqmp' command. Example: => zynqmp efuse_read 0xc 0xc : 85 66 b1 32 43 f2 4a 02 00 00 00 40 .f.https://docs.amd.com/r/en-US/ug1085-zynq-ultrascale-trm/eFUSE Lukas Funke (3): firmware: zynqmp: Add support to access efuses amd64: zynqmp: Add command to program efuses drivers: misc: Add driver to access ZynqMP efuses board/xilinx/zynqmp/cmds.c | 101 ++ drivers/firmware/firmware-zynqmp.c | 31 + drivers/misc/Kconfig | 8 ++ drivers/misc/Makefile | 1 + drivers/misc/zynqmp_efuse.c| 213 + include/zynqmp_firmware.h | 2 + 6 files changed, 356 insertions(+) create mode 100644 drivers/misc/zynqmp_efuse.c -- 2.30.2
[PATCH 3/3] drivers: misc: Add driver to access ZynqMP efuses
From: Lukas Funke Add driver to access ZynqMP efuses. This is a u-boot port of [1]. [1] https://lore.kernel.org/all/20240224114516.86365-8-srinivas.kandaga...@linaro.org/ Signed-off-by: Lukas Funke --- drivers/misc/Kconfig| 8 ++ drivers/misc/Makefile | 1 + drivers/misc/zynqmp_efuse.c | 213 3 files changed, 222 insertions(+) create mode 100644 drivers/misc/zynqmp_efuse.c diff --git a/drivers/misc/Kconfig b/drivers/misc/Kconfig index 6009d55f400..c07f50c9a76 100644 --- a/drivers/misc/Kconfig +++ b/drivers/misc/Kconfig @@ -298,6 +298,14 @@ config FSL_SEC_MON Security Monitor can be transitioned on any security failures, like software violations or hardware security violations. +config ZYNQMP_EFUSE + bool "Enable ZynqMP eFUSE Driver" + depends on ZYNQMP_FIRMWARE + help + Enable access to Zynq UltraScale (ZynqMP) eFUSEs thought PMU firmware + interface. ZnyqMP has 256 eFUSEs where some of them are security related + and cannot be read back (i.e. AES key). + choice prompt "Security monitor interaction endianess" depends on FSL_SEC_MON diff --git a/drivers/misc/Makefile b/drivers/misc/Makefile index e53d52c47b3..68ba5648eab 100644 --- a/drivers/misc/Makefile +++ b/drivers/misc/Makefile @@ -92,3 +92,4 @@ obj-$(CONFIG_ESM_K3) += k3_esm.o obj-$(CONFIG_ESM_PMIC) += esm_pmic.o obj-$(CONFIG_SL28CPLD) += sl28cpld.o obj-$(CONFIG_SPL_SOCFPGA_DT_REG) += socfpga_dtreg.o +obj-$(CONFIG_ZYNQMP_EFUSE) += zynqmp_efuse.o diff --git a/drivers/misc/zynqmp_efuse.c b/drivers/misc/zynqmp_efuse.c new file mode 100644 index 000..0cfc42a4f39 --- /dev/null +++ b/drivers/misc/zynqmp_efuse.c @@ -0,0 +1,213 @@ +// SPDX-License-Identifier: GPL-2.0+ +/* + * (C) Copyright 2014 - 2015 Xilinx, Inc. + * Michal Simek + * + * (C) Copyright 2024 Weidmueller Interface GmbH + * Lukas Funke + */ + +#include +#include +#include +#include +#include +#include +#include +#include + +#define SILICON_REVISION_MASK 0xF +#define P_USER_0_64_UPPER_MASK 0x5FFF +#define P_USER_127_LOWER_4_BIT_MASK 0xF +#define WORD_INBYTES (4) +#define SOC_VER_SIZE (0x4) +#define EFUSE_MEMORY_SIZE (0x177) +#define UNUSED_SPACE (0x8) +#define ZYNQMP_NVMEM_SIZE (SOC_VER_SIZE + UNUSED_SPACE + \ +EFUSE_MEMORY_SIZE) +#define SOC_VERSION_OFFSET (0x0) +#define EFUSE_START_OFFSET (0xC) +#define EFUSE_END_OFFSET (0xFC) +#define EFUSE_PUF_START_OFFSET (0x100) +#define EFUSE_PUF_MID_OFFSET (0x140) +#define EFUSE_PUF_END_OFFSET (0x17F) +#define EFUSE_NOT_ENABLED (29) +#define EFUSE_READ (0) +#define EFUSE_WRITE(1) + +/** + * struct xilinx_efuse - the basic structure + * @src: address of the buffer to store the data to be write/read + * @size: no of words to be read/write + * @offset:offset to be read/write` + * @flag: 0 - represents efuse read and 1- represents efuse write + * @pufuserfuse:0 - represents non-puf efuses, offset is used for read/write + * 1 - represents puf user fuse row number. + * + * this structure stores all the required details to + * read/write efuse memory. + */ +struct xilinx_efuse { + u64 src; + u32 size; + u32 offset; + u32 flag; + u32 pufuserfuse; +}; + +static int zynqmp_efuse_access(struct udevice *dev, unsigned int offset, + void *val, size_t bytes, unsigned int flag, + unsigned int pufflag) +{ + size_t words = bytes / WORD_INBYTES; + ulong dma_addr, dma_buf; + struct xilinx_efuse *efuse; + char *data; + int ret, value; + + if (bytes % WORD_INBYTES != 0) { + dev_err(dev, "Bytes requested should be word aligned\n"); + return -EOPNOTSUPP; + } + + if (pufflag == 0 && offset % WORD_INBYTES) { + dev_err(dev, "Offset requested should be word aligned\n"); + return -EOPNOTSUPP; + } + + if (pufflag == 1 && flag == EFUSE_WRITE) { + memcpy(&value, val, bytes); + if ((offset == EFUSE_PUF_START_OFFSET || +offset == EFUSE_PUF_MID_OFFSET) && + value & P_USER_0_64_UPPER_MASK) { + dev_err(dev, "Only lower 4 bytes are allowed to be programmed in P_USER_0 & P_USER_64\n"); + return -EOPNOTSUPP; + } + + if (offset == EFUSE_PUF_END_OFFSET && + (value & P_USER_127_LOWER_4_BIT_MASK)) { + dev_err(dev, "Only MSB 28 bits are allowed to be programmed for P_USER_127\n"); + return -EOPNOTSUPP; + } + } + + efuse = dma_alloc_coherent(sizeof(struct xilinx_efuse), &dma_addr); + if (!efuse) + return -ENOMEM; + + data = dma_alloc_
[PATCH v2 0/2] Add eFuse access for ZynqMP
From: Lukas Funke This series adds a driver to read and write ZynqMP eFuses [1]. The driver can be accessed by the 'fuse read' and 'fuse write' commands Example: => fuse read 0 0xc 3 Reading bank 0: Word 0x000c: 3cb16685 013af244 4000 Note: Accessing eFuses requires eFuse access to be enabled in the underlying PMU firmware. Use cases are: - Reading/writing user specific eFuses to enable device specific implementations - Revoking SPK IDs - Reading SoC version/DNA [1] https://docs.amd.com/r/en-US/ug1085-zynq-ultrascale-trm/eFUSE Changes in v2: - Drop vendor specific fuse cmd, use existing fuse cmd - Minor code refactoring (reverse x-mas tree) Lukas Funke (2): firmware: zynqmp: Add support to access efuses drivers: misc: Add driver to access ZynqMP efuses drivers/firmware/firmware-zynqmp.c | 31 +++ drivers/misc/Kconfig | 8 + drivers/misc/Makefile | 1 + drivers/misc/zynqmp_efuse.c| 324 + include/zynqmp_firmware.h | 2 + 5 files changed, 366 insertions(+) create mode 100644 drivers/misc/zynqmp_efuse.c -- 2.30.2
[PATCH v2 1/2] firmware: zynqmp: Add support to access efuses
From: Lukas Funke Add functions to access efuses through PMU firmware interface. Signed-off-by: Lukas Funke --- (no changes since v1) drivers/firmware/firmware-zynqmp.c | 31 ++ include/zynqmp_firmware.h | 2 ++ 2 files changed, 33 insertions(+) diff --git a/drivers/firmware/firmware-zynqmp.c b/drivers/firmware/firmware-zynqmp.c index f99507d86c6..d7fbe6a3efb 100644 --- a/drivers/firmware/firmware-zynqmp.c +++ b/drivers/firmware/firmware-zynqmp.c @@ -210,6 +210,37 @@ int zynqmp_pm_feature(const u32 api_id) return ret_payload[1] & FIRMWARE_VERSION_MASK; } +int zynqmp_pm_get_chipid(u32 *idcode, u32 *version) +{ + u32 ret_payload[PAYLOAD_ARG_CNT]; + int ret; + + if (!idcode || !version) + return -EINVAL; + + ret = xilinx_pm_request(PM_GET_CHIPID, 0, 0, 0, 0, ret_payload); + *idcode = ret_payload[1]; + *version = ret_payload[2]; + + return ret; +} + +int zynqmp_pm_efuse_access(const u64 address, u32 *out) +{ + u32 ret_payload[PAYLOAD_ARG_CNT]; + int ret; + + if (!out) + return -EINVAL; + + ret = xilinx_pm_request(PM_EFUSE_ACCESS, upper_32_bits(address), + lower_32_bits(address), 0, 0, ret_payload); + + *out = ret_payload[1]; + + return ret; +} + int zynqmp_pm_is_function_supported(const u32 api_id, const u32 id) { int ret; diff --git a/include/zynqmp_firmware.h b/include/zynqmp_firmware.h index 73198a6a6ea..7f18b4d59bf 100644 --- a/include/zynqmp_firmware.h +++ b/include/zynqmp_firmware.h @@ -453,6 +453,8 @@ int xilinx_pm_request(u32 api_id, u32 arg0, u32 arg1, u32 arg2, int zynqmp_pm_set_sd_config(u32 node, enum pm_sd_config_type config, u32 value); int zynqmp_pm_set_gem_config(u32 node, enum pm_gem_config_type config, u32 value); +int zynqmp_pm_get_chipid(u32 *idcode, u32 *version); +int zynqmp_pm_efuse_access(const u64 address, u32 *out); int zynqmp_pm_is_function_supported(const u32 api_id, const u32 id); int zynqmp_mmio_read(const u32 address, u32 *value); int zynqmp_mmio_write(const u32 address, const u32 mask, const u32 value); -- 2.30.2
[PATCH v2 2/2] drivers: misc: Add driver to access ZynqMP efuses
From: Lukas Funke Add driver to access ZynqMP efuses. This is a u-boot port of [1]. [1] https://lore.kernel.org/all/20240224114516.86365-8-srinivas.kandaga...@linaro.org/ Signed-off-by: Lukas Funke --- Changes in v2: - Drop vendor specific fuse cmd, use existing fuse cmd - Minor code refactoring (reverse x-mas tree) drivers/misc/Kconfig| 8 + drivers/misc/Makefile | 1 + drivers/misc/zynqmp_efuse.c | 324 3 files changed, 333 insertions(+) create mode 100644 drivers/misc/zynqmp_efuse.c diff --git a/drivers/misc/Kconfig b/drivers/misc/Kconfig index 6009d55f400..c07f50c9a76 100644 --- a/drivers/misc/Kconfig +++ b/drivers/misc/Kconfig @@ -298,6 +298,14 @@ config FSL_SEC_MON Security Monitor can be transitioned on any security failures, like software violations or hardware security violations. +config ZYNQMP_EFUSE + bool "Enable ZynqMP eFUSE Driver" + depends on ZYNQMP_FIRMWARE + help + Enable access to Zynq UltraScale (ZynqMP) eFUSEs thought PMU firmware + interface. ZnyqMP has 256 eFUSEs where some of them are security related + and cannot be read back (i.e. AES key). + choice prompt "Security monitor interaction endianess" depends on FSL_SEC_MON diff --git a/drivers/misc/Makefile b/drivers/misc/Makefile index e53d52c47b3..68ba5648eab 100644 --- a/drivers/misc/Makefile +++ b/drivers/misc/Makefile @@ -92,3 +92,4 @@ obj-$(CONFIG_ESM_K3) += k3_esm.o obj-$(CONFIG_ESM_PMIC) += esm_pmic.o obj-$(CONFIG_SL28CPLD) += sl28cpld.o obj-$(CONFIG_SPL_SOCFPGA_DT_REG) += socfpga_dtreg.o +obj-$(CONFIG_ZYNQMP_EFUSE) += zynqmp_efuse.o diff --git a/drivers/misc/zynqmp_efuse.c b/drivers/misc/zynqmp_efuse.c new file mode 100644 index 000..98a39c1ebdd --- /dev/null +++ b/drivers/misc/zynqmp_efuse.c @@ -0,0 +1,324 @@ +// SPDX-License-Identifier: GPL-2.0+ +/* + * (C) Copyright 2014 - 2015 Xilinx, Inc. + * Michal Simek + * + * (C) Copyright 2024 Weidmueller Interface GmbH + * Lukas Funke + */ + +#include +#include +#include +#include +#include +#include +#include +#include + +#define SILICON_REVISION_MASK 0xF +#define P_USER_0_64_UPPER_MASK 0x5FFF +#define P_USER_127_LOWER_4_BIT_MASK 0xF +#define WORD_INBYTES (4) +#define SOC_VER_SIZE (0x4) +#define SOC_VERSION_OFFSET (0x0) +#define EFUSE_START_OFFSET (0xC) +#define EFUSE_END_OFFSET (0xFC) +#define EFUSE_PUF_START_OFFSET (0x100) +#define EFUSE_PUF_MID_OFFSET (0x140) +#define EFUSE_PUF_END_OFFSET (0x17F) +#define EFUSE_NOT_ENABLED (29) +#define EFUSE_READ (0) +#define EFUSE_WRITE(1) + +/** + * struct efuse_map_entry - offset and length of zynqmp fuses + * @offset:offset of efuse to be read/write + * @length:length of efuse + */ +struct efuse_map_entry { + u32 offset; + u32 length; +}; + +struct efuse_map_entry zynqmp_efuse_table[] = { + {0x000, 0x04}, /* soc revision */ + {0x00c, 0x0c}, /* SoC DNA */ + {0x020, 0x04}, /* efuse-usr0 */ + {0x024, 0x04}, /* efuse-usr1 */ + {0x028, 0x04}, /* efuse-usr2 */ + {0x02c, 0x04}, /* efuse-usr3 */ + {0x030, 0x04}, /* efuse-usr4 */ + {0x034, 0x04}, /* efuse-usr5 */ + {0x038, 0x04}, /* efuse-usr6 */ + {0x03c, 0x04}, /* efuse-usr7 */ + {0x040, 0x04}, /* efuse-miscusr */ + {0x050, 0x04}, /* efuse-chash */ + {0x054, 0x04}, /* efuse-pufmisc */ + {0x058, 0x04}, /* efuse-sec */ + {0x05c, 0x04}, /* efuse-spkid */ + {0x060, 0x30}, /* efuse-aeskey */ + {0x0a0, 0x30}, /* ppk0-hash */ + {0x0d0, 0x30}, /* ppk1-hash */ + {0x100, 0x7f}, /* pufuser */ +}; + +/** + * struct xilinx_efuse - the basic structure + * @src: address of the buffer to store the data to be write/read + * @size: no of words to be read/write + * @offset:offset to be read/write` + * @flag: 0 - represents efuse read and 1- represents efuse write + * @pufuserfuse:0 - represents non-puf efuses, offset is used for read/write + * 1 - represents puf user fuse row number. + * + * this structure stores all the required details to + * read/write efuse memory. + */ +struct xilinx_efuse { + u64 src; + u32 size; + u32 offset; + u32 flag; + u32 pufuserfuse; +}; + +static int zynqmp_efuse_get_length(u32 offset, u32 *base_offset, u32 *len) +{ + struct efuse_map_entry *fuse; + int i; + + for (i = 0; i < ARRAY_SIZE(zynqmp_efuse_table); ++i) { + fuse = &zynqmp_efuse_table[i]; + if (offset >= fuse->offset && + offset < fuse->offset + fuse->length) { + *base_offset = fuse->offset; + *len = fuse->length; + return 0; + } + } + + return -ENOENT; +} + +static int zynqmp_efuse_access(struct udevice *dev, unsigned int offset, +
[PATCH v1 1/3] arch: riscv: Rename spl_soc_init() to spl_dram_init()
From: Lukas Funke Rename spl_soc_init() to spl_dram_init() because the generic function name does not reflect what the function is actually doing. In addition spl_dram_init() is commonly used for dram initialization and should be called from board_init_f(). Signed-off-by: Lukas Funke --- arch/riscv/cpu/fu540/spl.c | 2 +- arch/riscv/cpu/fu740/spl.c | 2 +- arch/riscv/cpu/jh7110/spl.c | 2 +- arch/riscv/include/asm/arch-fu540/spl.h | 2 +- arch/riscv/include/asm/arch-fu740/spl.h | 2 +- arch/riscv/include/asm/arch-jh7110/spl.h | 2 +- 6 files changed, 6 insertions(+), 6 deletions(-) diff --git a/arch/riscv/cpu/fu540/spl.c b/arch/riscv/cpu/fu540/spl.c index 45657b7909..cedb70b66a 100644 --- a/arch/riscv/cpu/fu540/spl.c +++ b/arch/riscv/cpu/fu540/spl.c @@ -7,7 +7,7 @@ #include #include -int spl_soc_init(void) +int spl_dram_init(void) { int ret; struct udevice *dev; diff --git a/arch/riscv/cpu/fu740/spl.c b/arch/riscv/cpu/fu740/spl.c index c6816e9ed4..16b307f036 100644 --- a/arch/riscv/cpu/fu740/spl.c +++ b/arch/riscv/cpu/fu740/spl.c @@ -10,7 +10,7 @@ #define CSR_U74_FEATURE_DISABLE0x7c1 -int spl_soc_init(void) +int spl_dram_init(void) { int ret; struct udevice *dev; diff --git a/arch/riscv/cpu/jh7110/spl.c b/arch/riscv/cpu/jh7110/spl.c index 6bdf8b9c72..87aaf86524 100644 --- a/arch/riscv/cpu/jh7110/spl.c +++ b/arch/riscv/cpu/jh7110/spl.c @@ -28,7 +28,7 @@ static bool check_ddr_size(phys_size_t size) } } -int spl_soc_init(void) +int spl_dram_init(void) { int ret; struct udevice *dev; diff --git a/arch/riscv/include/asm/arch-fu540/spl.h b/arch/riscv/include/asm/arch-fu540/spl.h index 4697279f43..519e7eb210 100644 --- a/arch/riscv/include/asm/arch-fu540/spl.h +++ b/arch/riscv/include/asm/arch-fu540/spl.h @@ -9,6 +9,6 @@ #ifndef _SPL_SIFIVE_H #define _SPL_SIFIVE_H -int spl_soc_init(void); +int spl_dram_init(void); #endif /* _SPL_SIFIVE_H */ diff --git a/arch/riscv/include/asm/arch-fu740/spl.h b/arch/riscv/include/asm/arch-fu740/spl.h index 15ad9e7c8b..b327ac5036 100644 --- a/arch/riscv/include/asm/arch-fu740/spl.h +++ b/arch/riscv/include/asm/arch-fu740/spl.h @@ -9,6 +9,6 @@ #ifndef _SPL_SIFIVE_H #define _SPL_SIFIVE_H -int spl_soc_init(void); +int spl_dram_init(void); #endif /* _SPL_SIFIVE_H */ diff --git a/arch/riscv/include/asm/arch-jh7110/spl.h b/arch/riscv/include/asm/arch-jh7110/spl.h index 23ce8871b3..d73355bf35 100644 --- a/arch/riscv/include/asm/arch-jh7110/spl.h +++ b/arch/riscv/include/asm/arch-jh7110/spl.h @@ -7,6 +7,6 @@ #ifndef _SPL_STARFIVE_H #define _SPL_STARFIVE_H -int spl_soc_init(void); +int spl_dram_init(void); #endif /* _SPL_STARFIVE_H */ -- 2.30.2
[PATCH v1 3/3] board: starfive: Call spl_dram_init() for DRAM initialization
From: Lukas Funke Call spl_dram_init() since this is commonly used for dram initialization in u-boot. Signed-off-by: Lukas Funke --- board/starfive/visionfive2/spl.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/board/starfive/visionfive2/spl.c b/board/starfive/visionfive2/spl.c index 45848db6d8..d1db7ee87b 100644 --- a/board/starfive/visionfive2/spl.c +++ b/board/starfive/visionfive2/spl.c @@ -285,9 +285,9 @@ int spl_board_init_f(void) jh7110_jtag_init(); - ret = spl_soc_init(); + ret = spl_dram_init(); if (ret) { - debug("JH7110 SPL init failed: %d\n", ret); + debug("JH7110 dram init failed: %d\n", ret); return ret; } -- 2.30.2
[PATCH v1 2/3] board: sifive: Call spl_dram_init() for DRAM initialization
From: Lukas Funke Call spl_dram_init() since this is commonly used for dram initialization in u-boot. Signed-off-by: Lukas Funke --- board/sifive/unleashed/spl.c | 4 ++-- board/sifive/unmatched/spl.c | 4 ++-- 2 files changed, 4 insertions(+), 4 deletions(-) diff --git a/board/sifive/unleashed/spl.c b/board/sifive/unleashed/spl.c index fe27316b2d..d6725a0e0e 100644 --- a/board/sifive/unleashed/spl.c +++ b/board/sifive/unleashed/spl.c @@ -27,9 +27,9 @@ int spl_board_init_f(void) { int ret; - ret = spl_soc_init(); + ret = spl_dram_init(); if (ret) { - debug("FU540 SPL init failed: %d\n", ret); + debug("FU540 dram init failed: %d\n", ret); return ret; } diff --git a/board/sifive/unmatched/spl.c b/board/sifive/unmatched/spl.c index e69bed9d99..500f484844 100644 --- a/board/sifive/unmatched/spl.c +++ b/board/sifive/unmatched/spl.c @@ -134,9 +134,9 @@ int spl_board_init_f(void) { int ret; - ret = spl_soc_init(); + ret = spl_dram_init(); if (ret) { - debug("HiFive Unmatched FU740 SPL init failed: %d\n", ret); + debug("HiFive Unmatched FU740 dram init failed: %d\n", ret); goto end; } -- 2.30.2
[PATCH v1 0/3] riscv: Rename spl_soc_init() to spl_dram_init()
From: Lukas Funke This patch series renames spl_soc_init() to spl_dram_init() since the purpose of the function is to initialization the DRAM on sifive/starfive boards. spl_dram_init() is a commonly used function for this purpose. Lukas Funke (3): arch: riscv: Rename spl_soc_init() to spl_dram_init() board: sifive: Call spl_dram_init() for DRAM initialization board: starfive: Call spl_dram_init() for DRAM initialization arch/riscv/cpu/fu540/spl.c | 2 +- arch/riscv/cpu/fu740/spl.c | 2 +- arch/riscv/cpu/jh7110/spl.c | 2 +- arch/riscv/include/asm/arch-fu540/spl.h | 2 +- arch/riscv/include/asm/arch-fu740/spl.h | 2 +- arch/riscv/include/asm/arch-jh7110/spl.h | 2 +- board/sifive/unleashed/spl.c | 4 ++-- board/sifive/unmatched/spl.c | 4 ++-- board/starfive/visionfive2/spl.c | 4 ++-- 9 files changed, 12 insertions(+), 12 deletions(-) -- 2.30.2
[PATCH v2 0/3] riscv: Rename spl_soc_init() to spl_dram_init()
From: Lukas Funke This patch series renames spl_soc_init() to spl_dram_init() since the purpose of the function is to initialization the DRAM on sifive/starfive boards. spl_dram_init() is a commonly used function for this purpose. Changes in v2: - capitalized acronym DRAM Lukas Funke (3): arch: riscv: Rename spl_soc_init() to spl_dram_init() board: sifive: Call spl_dram_init() for DRAM initialization board: starfive: Call spl_dram_init() for DRAM initialization arch/riscv/cpu/fu540/spl.c | 2 +- arch/riscv/cpu/fu740/spl.c | 2 +- arch/riscv/cpu/jh7110/spl.c | 2 +- arch/riscv/include/asm/arch-fu540/spl.h | 2 +- arch/riscv/include/asm/arch-fu740/spl.h | 2 +- arch/riscv/include/asm/arch-jh7110/spl.h | 2 +- board/sifive/unleashed/spl.c | 4 ++-- board/sifive/unmatched/spl.c | 4 ++-- board/starfive/visionfive2/spl.c | 4 ++-- 9 files changed, 12 insertions(+), 12 deletions(-) -- 2.30.2
[PATCH v2 2/3] board: sifive: Call spl_dram_init() for DRAM initialization
From: Lukas Funke Call spl_dram_init() since this is commonly used for DRAM initialization in u-boot. Signed-off-by: Lukas Funke --- (no changes since v1) board/sifive/unleashed/spl.c | 4 ++-- board/sifive/unmatched/spl.c | 4 ++-- 2 files changed, 4 insertions(+), 4 deletions(-) diff --git a/board/sifive/unleashed/spl.c b/board/sifive/unleashed/spl.c index fe27316b2d..9df9c68604 100644 --- a/board/sifive/unleashed/spl.c +++ b/board/sifive/unleashed/spl.c @@ -27,9 +27,9 @@ int spl_board_init_f(void) { int ret; - ret = spl_soc_init(); + ret = spl_dram_init(); if (ret) { - debug("FU540 SPL init failed: %d\n", ret); + debug("FU540 DRAM init failed: %d\n", ret); return ret; } diff --git a/board/sifive/unmatched/spl.c b/board/sifive/unmatched/spl.c index e69bed9d99..6fc1d80954 100644 --- a/board/sifive/unmatched/spl.c +++ b/board/sifive/unmatched/spl.c @@ -134,9 +134,9 @@ int spl_board_init_f(void) { int ret; - ret = spl_soc_init(); + ret = spl_dram_init(); if (ret) { - debug("HiFive Unmatched FU740 SPL init failed: %d\n", ret); + debug("HiFive Unmatched FU740 DRAM init failed: %d\n", ret); goto end; } -- 2.30.2
[PATCH v2 1/3] arch: riscv: Rename spl_soc_init() to spl_dram_init()
From: Lukas Funke Rename spl_soc_init() to spl_dram_init() because the generic function name does not reflect what the function is actually doing. In addition spl_dram_init() is commonly used for dram initialization and should be called from board_init_f(). Signed-off-by: Lukas Funke --- (no changes since v1) arch/riscv/cpu/fu540/spl.c | 2 +- arch/riscv/cpu/fu740/spl.c | 2 +- arch/riscv/cpu/jh7110/spl.c | 2 +- arch/riscv/include/asm/arch-fu540/spl.h | 2 +- arch/riscv/include/asm/arch-fu740/spl.h | 2 +- arch/riscv/include/asm/arch-jh7110/spl.h | 2 +- 6 files changed, 6 insertions(+), 6 deletions(-) diff --git a/arch/riscv/cpu/fu540/spl.c b/arch/riscv/cpu/fu540/spl.c index 45657b7909..cedb70b66a 100644 --- a/arch/riscv/cpu/fu540/spl.c +++ b/arch/riscv/cpu/fu540/spl.c @@ -7,7 +7,7 @@ #include #include -int spl_soc_init(void) +int spl_dram_init(void) { int ret; struct udevice *dev; diff --git a/arch/riscv/cpu/fu740/spl.c b/arch/riscv/cpu/fu740/spl.c index c6816e9ed4..16b307f036 100644 --- a/arch/riscv/cpu/fu740/spl.c +++ b/arch/riscv/cpu/fu740/spl.c @@ -10,7 +10,7 @@ #define CSR_U74_FEATURE_DISABLE0x7c1 -int spl_soc_init(void) +int spl_dram_init(void) { int ret; struct udevice *dev; diff --git a/arch/riscv/cpu/jh7110/spl.c b/arch/riscv/cpu/jh7110/spl.c index 6bdf8b9c72..87aaf86524 100644 --- a/arch/riscv/cpu/jh7110/spl.c +++ b/arch/riscv/cpu/jh7110/spl.c @@ -28,7 +28,7 @@ static bool check_ddr_size(phys_size_t size) } } -int spl_soc_init(void) +int spl_dram_init(void) { int ret; struct udevice *dev; diff --git a/arch/riscv/include/asm/arch-fu540/spl.h b/arch/riscv/include/asm/arch-fu540/spl.h index 4697279f43..519e7eb210 100644 --- a/arch/riscv/include/asm/arch-fu540/spl.h +++ b/arch/riscv/include/asm/arch-fu540/spl.h @@ -9,6 +9,6 @@ #ifndef _SPL_SIFIVE_H #define _SPL_SIFIVE_H -int spl_soc_init(void); +int spl_dram_init(void); #endif /* _SPL_SIFIVE_H */ diff --git a/arch/riscv/include/asm/arch-fu740/spl.h b/arch/riscv/include/asm/arch-fu740/spl.h index 15ad9e7c8b..b327ac5036 100644 --- a/arch/riscv/include/asm/arch-fu740/spl.h +++ b/arch/riscv/include/asm/arch-fu740/spl.h @@ -9,6 +9,6 @@ #ifndef _SPL_SIFIVE_H #define _SPL_SIFIVE_H -int spl_soc_init(void); +int spl_dram_init(void); #endif /* _SPL_SIFIVE_H */ diff --git a/arch/riscv/include/asm/arch-jh7110/spl.h b/arch/riscv/include/asm/arch-jh7110/spl.h index 23ce8871b3..d73355bf35 100644 --- a/arch/riscv/include/asm/arch-jh7110/spl.h +++ b/arch/riscv/include/asm/arch-jh7110/spl.h @@ -7,6 +7,6 @@ #ifndef _SPL_STARFIVE_H #define _SPL_STARFIVE_H -int spl_soc_init(void); +int spl_dram_init(void); #endif /* _SPL_STARFIVE_H */ -- 2.30.2
[PATCH v2 3/3] board: starfive: Call spl_dram_init() for DRAM initialization
From: Lukas Funke Call spl_dram_init() since this is commonly used for dram initialization in u-boot. Signed-off-by: Lukas Funke --- Changes in v2: - capitalized acronym DRAM board/starfive/visionfive2/spl.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/board/starfive/visionfive2/spl.c b/board/starfive/visionfive2/spl.c index 45848db6d8..ca61b5be22 100644 --- a/board/starfive/visionfive2/spl.c +++ b/board/starfive/visionfive2/spl.c @@ -285,9 +285,9 @@ int spl_board_init_f(void) jh7110_jtag_init(); - ret = spl_soc_init(); + ret = spl_dram_init(); if (ret) { - debug("JH7110 SPL init failed: %d\n", ret); + debug("JH7110 DRAM init failed: %d\n", ret); return ret; } -- 2.30.2
[PATCH v3 0/2] riscv: Rename spl_soc_init() to spl_dram_init()
From: Lukas Funke This patch series renames spl_soc_init() to spl_dram_init() since the purpose of the function is to initialization the DRAM on sifive/starfive boards. spl_dram_init() is a commonly used function for this purpose. Changes in v3: - Reorganize patches such that each patch can be built individually Changes in v2: - capitalized acronym DRAM Lukas Funke (2): board: sifive: Rename spl_soc_init() to spl_dram_init() board: starfive: Rename spl_soc_init() to spl_dram_init() arch/riscv/cpu/fu540/spl.c | 2 +- arch/riscv/cpu/fu740/spl.c | 2 +- arch/riscv/cpu/jh7110/spl.c | 2 +- arch/riscv/include/asm/arch-fu540/spl.h | 2 +- arch/riscv/include/asm/arch-fu740/spl.h | 2 +- arch/riscv/include/asm/arch-jh7110/spl.h | 2 +- board/sifive/unleashed/spl.c | 4 ++-- board/sifive/unmatched/spl.c | 4 ++-- board/starfive/visionfive2/spl.c | 4 ++-- 9 files changed, 12 insertions(+), 12 deletions(-) -- 2.30.2
[PATCH v3 1/2] board: sifive: Rename spl_soc_init() to spl_dram_init()
From: Lukas Funke Rename spl_soc_init() to spl_dram_init() because the generic function name does not reflect what the function actually does. Also spl_dram_init() is commonly used for dram initialization and should be called from board_init_f(). Signed-off-by: Lukas Funke --- (no changes since v1) arch/riscv/cpu/fu540/spl.c | 2 +- arch/riscv/cpu/fu740/spl.c | 2 +- arch/riscv/include/asm/arch-fu540/spl.h | 2 +- arch/riscv/include/asm/arch-fu740/spl.h | 2 +- board/sifive/unleashed/spl.c| 4 ++-- board/sifive/unmatched/spl.c| 4 ++-- 6 files changed, 8 insertions(+), 8 deletions(-) diff --git a/arch/riscv/cpu/fu540/spl.c b/arch/riscv/cpu/fu540/spl.c index 45657b7909..cedb70b66a 100644 --- a/arch/riscv/cpu/fu540/spl.c +++ b/arch/riscv/cpu/fu540/spl.c @@ -7,7 +7,7 @@ #include #include -int spl_soc_init(void) +int spl_dram_init(void) { int ret; struct udevice *dev; diff --git a/arch/riscv/cpu/fu740/spl.c b/arch/riscv/cpu/fu740/spl.c index c6816e9ed4..16b307f036 100644 --- a/arch/riscv/cpu/fu740/spl.c +++ b/arch/riscv/cpu/fu740/spl.c @@ -10,7 +10,7 @@ #define CSR_U74_FEATURE_DISABLE0x7c1 -int spl_soc_init(void) +int spl_dram_init(void) { int ret; struct udevice *dev; diff --git a/arch/riscv/include/asm/arch-fu540/spl.h b/arch/riscv/include/asm/arch-fu540/spl.h index 4697279f43..519e7eb210 100644 --- a/arch/riscv/include/asm/arch-fu540/spl.h +++ b/arch/riscv/include/asm/arch-fu540/spl.h @@ -9,6 +9,6 @@ #ifndef _SPL_SIFIVE_H #define _SPL_SIFIVE_H -int spl_soc_init(void); +int spl_dram_init(void); #endif /* _SPL_SIFIVE_H */ diff --git a/arch/riscv/include/asm/arch-fu740/spl.h b/arch/riscv/include/asm/arch-fu740/spl.h index 15ad9e7c8b..b327ac5036 100644 --- a/arch/riscv/include/asm/arch-fu740/spl.h +++ b/arch/riscv/include/asm/arch-fu740/spl.h @@ -9,6 +9,6 @@ #ifndef _SPL_SIFIVE_H #define _SPL_SIFIVE_H -int spl_soc_init(void); +int spl_dram_init(void); #endif /* _SPL_SIFIVE_H */ diff --git a/board/sifive/unleashed/spl.c b/board/sifive/unleashed/spl.c index fe27316b2d..9df9c68604 100644 --- a/board/sifive/unleashed/spl.c +++ b/board/sifive/unleashed/spl.c @@ -27,9 +27,9 @@ int spl_board_init_f(void) { int ret; - ret = spl_soc_init(); + ret = spl_dram_init(); if (ret) { - debug("FU540 SPL init failed: %d\n", ret); + debug("FU540 DRAM init failed: %d\n", ret); return ret; } diff --git a/board/sifive/unmatched/spl.c b/board/sifive/unmatched/spl.c index e69bed9d99..6fc1d80954 100644 --- a/board/sifive/unmatched/spl.c +++ b/board/sifive/unmatched/spl.c @@ -134,9 +134,9 @@ int spl_board_init_f(void) { int ret; - ret = spl_soc_init(); + ret = spl_dram_init(); if (ret) { - debug("HiFive Unmatched FU740 SPL init failed: %d\n", ret); + debug("HiFive Unmatched FU740 DRAM init failed: %d\n", ret); goto end; } -- 2.30.2
[PATCH v3 2/2] board: starfive: Rename spl_soc_init() to spl_dram_init()
From: Lukas Funke Rename spl_soc_init() to spl_dram_init() because the generic function name does not reflect what the function actually does. Also spl_dram_init() is commonly used for dram initialization and should be called from board_init_f(). Signed-off-by: Lukas Funke --- Changes in v3: - Reorganize patches such that each patch can be built individually Changes in v2: - capitalized acronym DRAM arch/riscv/cpu/jh7110/spl.c | 2 +- arch/riscv/include/asm/arch-jh7110/spl.h | 2 +- board/starfive/visionfive2/spl.c | 4 ++-- 3 files changed, 4 insertions(+), 4 deletions(-) diff --git a/arch/riscv/cpu/jh7110/spl.c b/arch/riscv/cpu/jh7110/spl.c index 6bdf8b9c72..87aaf86524 100644 --- a/arch/riscv/cpu/jh7110/spl.c +++ b/arch/riscv/cpu/jh7110/spl.c @@ -28,7 +28,7 @@ static bool check_ddr_size(phys_size_t size) } } -int spl_soc_init(void) +int spl_dram_init(void) { int ret; struct udevice *dev; diff --git a/arch/riscv/include/asm/arch-jh7110/spl.h b/arch/riscv/include/asm/arch-jh7110/spl.h index 23ce8871b3..d73355bf35 100644 --- a/arch/riscv/include/asm/arch-jh7110/spl.h +++ b/arch/riscv/include/asm/arch-jh7110/spl.h @@ -7,6 +7,6 @@ #ifndef _SPL_STARFIVE_H #define _SPL_STARFIVE_H -int spl_soc_init(void); +int spl_dram_init(void); #endif /* _SPL_STARFIVE_H */ diff --git a/board/starfive/visionfive2/spl.c b/board/starfive/visionfive2/spl.c index 45848db6d8..ca61b5be22 100644 --- a/board/starfive/visionfive2/spl.c +++ b/board/starfive/visionfive2/spl.c @@ -285,9 +285,9 @@ int spl_board_init_f(void) jh7110_jtag_init(); - ret = spl_soc_init(); + ret = spl_dram_init(); if (ret) { - debug("JH7110 SPL init failed: %d\n", ret); + debug("JH7110 DRAM init failed: %d\n", ret); return ret; } -- 2.30.2
[RFC PATCH v1 0/1] mmc: zynq_sdhci: Only evaluate card-stable signal if card was detected
From: Lukas Funke On ZynqMp there seems to be a dependency between the card-stable bit and the card-detect bit. The card-stable bit is set *if and only if* the card-detect bit was set before, indicating that the signal was stable and reliable during card insertion. If the card-detect bit is *not* evaluated the corresponding check leads to a timeout indicating that the card-detect was not stable. There was another patch that tried to mitigate this behaviour: https://lore.kernel.org/u-boot/20230516142116.29996-1-stefan.herbrechtsmeier-...@weidmueller.com/T/#m295a0158fe62da7289baa26bcd7272ad8598af56 However, the discussion stalled and the solution was not accepted. This patch introduces another way to deal with the observed behaviour. Lukas Funke (1): mmc: zynq_sdhci: Only evaluate card-stable signal if card was detected drivers/mmc/zynq_sdhci.c | 7 +-- 1 file changed, 5 insertions(+), 2 deletions(-) -- 2.30.2
[RFC PATCH v1 1/1] mmc: zynq_sdhci: Only evaluate card-stable signal if card was detected
From: Lukas Funke On ZynqMp there seems to be a dependency between the card-stable bit and the card-detect bit. The card-stable bit is set *if and only if* the card-detect bit was set before, indicating that the signal was stable and reliable during card insertion. If the card-detect bit is *not* evaluated the corresponding check leads to a timeout indicating that the card-detect was not stable. Signed-off-by: Lukas Funke --- drivers/mmc/zynq_sdhci.c | 7 +-- 1 file changed, 5 insertions(+), 2 deletions(-) diff --git a/drivers/mmc/zynq_sdhci.c b/drivers/mmc/zynq_sdhci.c index 935540d171..d0bccd41cc 100644 --- a/drivers/mmc/zynq_sdhci.c +++ b/drivers/mmc/zynq_sdhci.c @@ -1168,11 +1168,14 @@ static int arasan_sdhci_probe(struct udevice *dev) */ if (IS_ENABLED(CONFIG_ARCH_ZYNQMP) || IS_ENABLED(CONFIG_ARCH_VERSAL)) { u32 timeout = 100; + u32 value; - while (((sdhci_readl(host, SDHCI_PRESENT_STATE) & -SDHCI_CARD_STATE_STABLE) == 0) && timeout) { + value = sdhci_readl(host, SDHCI_PRESENT_STATE); + while ((value & SDHCI_CARD_PRESENT) && + ((value & SDHCI_CARD_STATE_STABLE) == 0) && timeout) { udelay(1); timeout--; + value = sdhci_readl(host, SDHCI_PRESENT_STATE); } if (!timeout) { dev_err(dev, "Sdhci card detect state not stable\n"); -- 2.30.2
[PATCH] arm64: zynqmp: Add label to pmu fwnode
From: Lukas Funke Some zynqmp SoCs (the cg series) only have two cpus. Thus, for some cases the cpu-affinity has to adapted, because cpu3 and cpu4 are missing. By adding a label to the pmu fwnode the cpu affinity can be adapted in a device specific dt. Signed-off-by: Lukas Funke --- arch/arm/dts/zynqmp.dtsi | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/arch/arm/dts/zynqmp.dtsi b/arch/arm/dts/zynqmp.dtsi index b50b83b772..457f8e394f 100644 --- a/arch/arm/dts/zynqmp.dtsi +++ b/arch/arm/dts/zynqmp.dtsi @@ -168,7 +168,7 @@ bootph-all; }; - pmu { + pmu: pmu { compatible = "arm,armv8-pmuv3"; interrupt-parent = <&gic>; interrupts = , -- 2.39.2
[PATCH v2] arm64: zynqmp: Add label to pmu fwnode
From: Lukas Funke ZynqMP CG series devices only have two cpus. In this case the interrupt-affinity property has to adapted, because cpu3 and cpu4 are missing. By adding a label to the pmu fwnode the interrupt-affinity can be adapted in a device specific DT. Signed-off-by: Lukas Funke --- arch/arm/dts/zynqmp.dtsi | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/arch/arm/dts/zynqmp.dtsi b/arch/arm/dts/zynqmp.dtsi index b50b83b772..457f8e394f 100644 --- a/arch/arm/dts/zynqmp.dtsi +++ b/arch/arm/dts/zynqmp.dtsi @@ -168,7 +168,7 @@ bootph-all; }; - pmu { + pmu: pmu { compatible = "arm,armv8-pmuv3"; interrupt-parent = <&gic>; interrupts = , -- 2.30.2
[PATCH 0/2] Introduce spl_arch_init() for architecture specific initialization
From: Lukas Funke Currently some architectures use spl_board_init() for their architecture specific initialization. This prohibits board developers from adding board init code using said function. This series introduces a new function in order to separate arch init code from board init code. Lukas Funke (2): spl: Introduce architecture specific init function arm64: zynq(mp): Rename spl_board_init() to spl_arch_init() arch/arm/Kconfig | 4 ++-- arch/arm/mach-zynq/spl.c | 4 ++-- arch/arm/mach-zynqmp/spl.c | 4 ++-- common/spl/Kconfig | 7 +++ common/spl/spl.c | 3 +++ include/spl.h | 8 6 files changed, 24 insertions(+), 6 deletions(-) -- 2.30.2