[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 = _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 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 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 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(, 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), _addr); + if (!efuse) + return -ENOMEM; + + data =
[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 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), ); + 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, , 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), ); + 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 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
[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
[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
[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
[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 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 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 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 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 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 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 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 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 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 3/3] zynq: Add function to lock JTAG enable bits
From: Stefan Herbrechtsmeier Add function to prevent debug access from being enabled. If the debug lock is set the debug access cannot be enabled after a soft-reset. The debug access can only be enabled after a power-on-reset is performed. Signed-off-by: Stefan Herbrechtsmeier Signed-off-by: Lukas Funke --- arch/arm/mach-zynq/cpu.c| 10 ++ arch/arm/mach-zynq/include/mach/sys_proto.h | 1 + 2 files changed, 11 insertions(+) diff --git a/arch/arm/mach-zynq/cpu.c b/arch/arm/mach-zynq/cpu.c index b8d413b69a..e6151bc21d 100644 --- a/arch/arm/mach-zynq/cpu.c +++ b/arch/arm/mach-zynq/cpu.c @@ -20,6 +20,7 @@ #define ZYNQ_DEV_CFG_CTRL_SPIDEM BIT(5) #define ZYNQ_DEV_CFG_CTRL_SPNIDEN BIT(6) #define ZYNQ_DEV_CFG_CTRL_JTAG_CHAIN_DIS BIT(23) +#define ZYNQ_DEV_CFG_LOCK_DBG_LOCK BIT(0) #define ZYNQ_SILICON_VER_MASK 0xF000 #define ZYNQ_SILICON_VER_SHIFT 28 @@ -93,6 +94,15 @@ void zynq_enable_jtag(void) writel(v, _base->ctrl); } +void zynq_lock_jtag(void) +{ + unsigned int v; + + v = readl(_base->lock); + v |= ZYNQ_DEV_CFG_LOCK_DBG_LOCK; + writel(v, _base->lock); +} + unsigned int zynq_get_silicon_version(void) { return (readl(_base->mctrl) & ZYNQ_SILICON_VER_MASK) diff --git a/arch/arm/mach-zynq/include/mach/sys_proto.h b/arch/arm/mach-zynq/include/mach/sys_proto.h index f583ef090d..3377fe2c23 100644 --- a/arch/arm/mach-zynq/include/mach/sys_proto.h +++ b/arch/arm/mach-zynq/include/mach/sys_proto.h @@ -16,6 +16,7 @@ extern u32 zynq_slcr_get_idcode(void); extern int zynq_slcr_get_mio_pin_status(const char *periph); extern void zynq_ddrc_init(void); extern void zynq_enable_jtag(void); +extern void zynq_lock_jtag(void); extern unsigned int zynq_get_silicon_version(void); extern unsigned int zynq_get_mulitboot_addr(void); extern void zynq_set_mulitboot_addr(unsigned int); -- 2.30.2
[PATCH 2/3] zynq: Add function to enable JTAG
From: Stefan Herbrechtsmeier In non-secure boot mode jtag is restored by the BootROM. In secure boot mode jtag has to be restored by the trusted application, i.e. the bootloader. This commit adds a function to enable the jtag interface on zynq devices from u-boot. Signed-off-by: Stefan Herbrechtsmeier Signed-off-by: Lukas Funke --- arch/arm/mach-zynq/cpu.c| 19 +++ arch/arm/mach-zynq/include/mach/sys_proto.h | 1 + 2 files changed, 20 insertions(+) diff --git a/arch/arm/mach-zynq/cpu.c b/arch/arm/mach-zynq/cpu.c index 3d2866422e..b8d413b69a 100644 --- a/arch/arm/mach-zynq/cpu.c +++ b/arch/arm/mach-zynq/cpu.c @@ -14,6 +14,13 @@ #include #include +#define ZYNQ_DEV_CFG_CTRL_DAP_EN GENMASK(0, 2) +#define ZYNQ_DEV_CFG_CTRL_DBGENBIT(3) +#define ZYNQ_DEV_CFG_CTRL_NIDENBIT(4) +#define ZYNQ_DEV_CFG_CTRL_SPIDEM BIT(5) +#define ZYNQ_DEV_CFG_CTRL_SPNIDEN BIT(6) +#define ZYNQ_DEV_CFG_CTRL_JTAG_CHAIN_DIS BIT(23) + #define ZYNQ_SILICON_VER_MASK 0xF000 #define ZYNQ_SILICON_VER_SHIFT 28 #define ZYNQ_MULTIBOOT_ADDR_MASK 0x1FFF @@ -74,6 +81,18 @@ int arch_cpu_init(void) return 0; } +void zynq_enable_jtag(void) +{ + unsigned int v; + + v = readl(_base->ctrl); + v &= ~ZYNQ_DEV_CFG_CTRL_JTAG_CHAIN_DIS; + v |= ZYNQ_DEV_CFG_CTRL_DAP_EN | ZYNQ_DEV_CFG_CTRL_DBGEN + | ZYNQ_DEV_CFG_CTRL_NIDEN | ZYNQ_DEV_CFG_CTRL_NIDEN + | ZYNQ_DEV_CFG_CTRL_SPIDEM | ZYNQ_DEV_CFG_CTRL_SPNIDEN; + writel(v, _base->ctrl); +} + unsigned int zynq_get_silicon_version(void) { return (readl(_base->mctrl) & ZYNQ_SILICON_VER_MASK) diff --git a/arch/arm/mach-zynq/include/mach/sys_proto.h b/arch/arm/mach-zynq/include/mach/sys_proto.h index 6b85682808..f583ef090d 100644 --- a/arch/arm/mach-zynq/include/mach/sys_proto.h +++ b/arch/arm/mach-zynq/include/mach/sys_proto.h @@ -15,6 +15,7 @@ extern u32 zynq_slcr_get_boot_mode(void); extern u32 zynq_slcr_get_idcode(void); extern int zynq_slcr_get_mio_pin_status(const char *periph); extern void zynq_ddrc_init(void); +extern void zynq_enable_jtag(void); extern unsigned int zynq_get_silicon_version(void); extern unsigned int zynq_get_mulitboot_addr(void); extern void zynq_set_mulitboot_addr(unsigned int); -- 2.30.2
[PATCH 1/3] zynq: Add get function for multi boot address register
From: Stefan Herbrechtsmeier This commit adds a function to get/set the multiboot register. This becomes handy in order to ensure a fresh bootimage search after reset. Signed-off-by: Stefan Herbrechtsmeier Signed-off-by: Lukas Funke --- arch/arm/mach-zynq/cpu.c| 19 +-- arch/arm/mach-zynq/include/mach/hardware.h | 3 ++- arch/arm/mach-zynq/include/mach/sys_proto.h | 2 ++ 3 files changed, 21 insertions(+), 3 deletions(-) diff --git a/arch/arm/mach-zynq/cpu.c b/arch/arm/mach-zynq/cpu.c index 3b6518c71c..3d2866422e 100644 --- a/arch/arm/mach-zynq/cpu.c +++ b/arch/arm/mach-zynq/cpu.c @@ -14,8 +14,9 @@ #include #include -#define ZYNQ_SILICON_VER_MASK 0xF000 -#define ZYNQ_SILICON_VER_SHIFT 28 +#define ZYNQ_SILICON_VER_MASK 0xF000 +#define ZYNQ_SILICON_VER_SHIFT 28 +#define ZYNQ_MULTIBOOT_ADDR_MASK 0x1FFF #if CONFIG_IS_ENABLED(FPGA) xilinx_desc fpga = { @@ -79,6 +80,20 @@ unsigned int zynq_get_silicon_version(void) >> ZYNQ_SILICON_VER_SHIFT; } +unsigned int zynq_get_mulitboot_addr(void) +{ + return readl(_base->multiboot_addr) & ZYNQ_MULTIBOOT_ADDR_MASK; +} + +void zynq_set_mulitboot_addr(unsigned int value) +{ + unsigned int v = readl(_base->multiboot_addr); + + v &= ~ZYNQ_MULTIBOOT_ADDR_MASK; + v |= value & ZYNQ_MULTIBOOT_ADDR_MASK; + writel(v, _base->multiboot_addr); +} + void reset_cpu(void) { zynq_slcr_cpu_reset(); diff --git a/arch/arm/mach-zynq/include/mach/hardware.h b/arch/arm/mach-zynq/include/mach/hardware.h index 89eb565c94..9199baccfa 100644 --- a/arch/arm/mach-zynq/include/mach/hardware.h +++ b/arch/arm/mach-zynq/include/mach/hardware.h @@ -96,7 +96,8 @@ struct devcfg_regs { u32 dma_src_len; /* 0x20 */ u32 dma_dst_len; /* 0x24 */ u32 rom_shadow; /* 0x28 */ - u32 reserved1[2]; + u32 multiboot_addr; /* 0x2c */ + u32 reserved1[1]; u32 unlock; /* 0x34 */ u32 reserved2[18]; u32 mctrl; /* 0x80 */ diff --git a/arch/arm/mach-zynq/include/mach/sys_proto.h b/arch/arm/mach-zynq/include/mach/sys_proto.h index 268ec50ad8..6b85682808 100644 --- a/arch/arm/mach-zynq/include/mach/sys_proto.h +++ b/arch/arm/mach-zynq/include/mach/sys_proto.h @@ -16,5 +16,7 @@ extern u32 zynq_slcr_get_idcode(void); extern int zynq_slcr_get_mio_pin_status(const char *periph); extern void zynq_ddrc_init(void); extern unsigned int zynq_get_silicon_version(void); +extern unsigned int zynq_get_mulitboot_addr(void); +extern void zynq_set_mulitboot_addr(unsigned int); #endif /* _SYS_PROTO_H_ */ -- 2.30.2
[PATCH 0/3] Add support for jtag disable/enable and multiboot get/set for zynq
From: Lukas Funke This series adds support to enable/disable/lock the jtag interface from u-boot. This becomes handy if secure boot is used but debugging should be poissible for non-productions builds. The series also adds support to get/set the multiboot register in order to ensure a freash bootimage search after soft reset. Stefan Herbrechtsmeier (3): zynq: Add get function for multi boot address register zynq: Add function to enable JTAG zynq: Add function to lock JTAG enable bits arch/arm/mach-zynq/cpu.c| 48 - arch/arm/mach-zynq/include/mach/hardware.h | 3 +- arch/arm/mach-zynq/include/mach/sys_proto.h | 4 ++ 3 files changed, 52 insertions(+), 3 deletions(-) -- 2.30.2
[PATCH v3 1/2] spl: Introduce SoC specific init function
From: Lukas Funke Some architectures use spl_board_init() in their SoC specific implementation. Board developers should be able to add board specific implementation via spl_board_init(). Hence, introduce a spl_soc_init() method which is called right before spl_board_init() for SoC specific implementation. Signed-off-by: Lukas Funke Reviewed-by: Devarsh Thakkar --- (no changes since v1) common/spl/Kconfig | 7 +++ common/spl/spl.c | 3 +++ include/spl.h | 8 3 files changed, 18 insertions(+) diff --git a/common/spl/Kconfig b/common/spl/Kconfig index 6405374bcc..eece8e58ce 100644 --- a/common/spl/Kconfig +++ b/common/spl/Kconfig @@ -272,6 +272,13 @@ config SPL_TEXT_BASE help The address in memory that SPL will be running from. +config SPL_SOC_INIT + bool "Call SoC-specific initialization in SPL" + help + If this option is enabled, U-Boot will call the function + spl_soc_init() from board_init_r(). This function should be + provided by the SoC vendor. + config SPL_BOARD_INIT bool "Call board-specific initialization in SPL" help diff --git a/common/spl/spl.c b/common/spl/spl.c index b65c439e7a..9b83c85df5 100644 --- a/common/spl/spl.c +++ b/common/spl/spl.c @@ -711,6 +711,9 @@ void board_init_r(gd_t *dummy1, ulong dummy2) } } + if (CONFIG_IS_ENABLED(SOC_INIT)) + spl_soc_init(); + if (CONFIG_IS_ENABLED(BOARD_INIT)) spl_board_init(); diff --git a/include/spl.h b/include/spl.h index 043875f10f..5dfdf778d2 100644 --- a/include/spl.h +++ b/include/spl.h @@ -816,6 +816,14 @@ int spl_early_init(void); */ int spl_init(void); +/* + * spl_soc_init() - Do architecture-specific init in SPL + * + * If SPL_SOC_INIT is enabled, this is called from board_init_r() before + * jumping to the next phase. + */ +void spl_soc_init(void); + /* * spl_board_init() - Do board-specific init in SPL * -- 2.30.2
[PATCH v3 2/2] arm64: zynq(mp): Rename spl_board_init() to spl_soc_init()
From: Lukas Funke Rename spl_board_init() to spl_soc_init(). SoC specific implementation should be separated from board specific implementation in order to be extended by board developers. Signed-off-by: Lukas Funke --- Changes in v3: - Rephrase Kconfig description and correct minor typo Changes in v2: - Change spl_arch_init() to spl_soc_init() arch/arm/Kconfig | 4 ++-- arch/arm/mach-zynq/spl.c | 4 ++-- arch/arm/mach-zynqmp/spl.c | 4 ++-- 3 files changed, 6 insertions(+), 6 deletions(-) diff --git a/arch/arm/Kconfig b/arch/arm/Kconfig index 01d6556c42..db56db9414 100644 --- a/arch/arm/Kconfig +++ b/arch/arm/Kconfig @@ -1275,7 +1275,7 @@ config ARCH_ZYNQ select OF_CONTROL select MTD select SPI - select SPL_BOARD_INIT if SPL + select SPL_SOC_INIT if SPL select SPL_CLK if SPL select SPL_DM if SPL select SPL_DM_SPI if SPL @@ -1318,7 +1318,7 @@ config ARCH_ZYNQMP imply FIRMWARE select GICV2 select OF_CONTROL - select SPL_BOARD_INIT if SPL + select SPL_SOC_INIT if SPL select SPL_CLK if SPL select SPL_DM if SPL select SPL_DM_SPI if SPI && SPL_DM diff --git a/arch/arm/mach-zynq/spl.c b/arch/arm/mach-zynq/spl.c index fea1c9b12a..112b44e2e1 100644 --- a/arch/arm/mach-zynq/spl.c +++ b/arch/arm/mach-zynq/spl.c @@ -32,8 +32,8 @@ void board_init_f(ulong dummy) arch_cpu_init(); } -#ifdef CONFIG_SPL_BOARD_INIT -void spl_board_init(void) +#ifdef CONFIG_SPL_SOC_INIT +void spl_soc_init(void) { preloader_console_init(); #if defined(CONFIG_ARCH_EARLY_INIT_R) && defined(CONFIG_SPL_FPGA) diff --git a/arch/arm/mach-zynqmp/spl.c b/arch/arm/mach-zynqmp/spl.c index a0f35f36fa..71f9932525 100644 --- a/arch/arm/mach-zynqmp/spl.c +++ b/arch/arm/mach-zynqmp/spl.c @@ -56,8 +56,8 @@ static void ps_mode_reset(ulong mode) # define MODE_RESETPS_MODE1 #endif -#ifdef CONFIG_SPL_BOARD_INIT -void spl_board_init(void) +#ifdef CONFIG_SPL_SOC_INIT +void spl_soc_init(void) { preloader_console_init(); ps_mode_reset(MODE_RESET); -- 2.30.2
[PATCH v3 0/2] Introduce spl_soc_init() for SoC specific initialization
From: Lukas Funke Currently some vendors use spl_board_init() for their SoC specific initialization. This prohibits board developers from adding board init code using said function. This series introduces a new function in order to separate SoC init code from board init code. Changes in v3: - Rephrase Kconfig description and correct minor typo Changes in v2: - Change spl_arch_init() to spl_soc_init() Lukas Funke (2): spl: Introduce SoC specific init function arm64: zynq(mp): Rename spl_board_init() to spl_soc_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
[PATCH v2 2/2] arm64: zynq(mp): Rename spl_board_init() to spl_soc_init()
From: Lukas Funke Rename spl_board_init() to spl_soc_init(). SoC specific implementation should be separated from board specific implementation in order to be extended by board developers. Signed-off-by: Lukas Funke --- Changes in v2: - Change spl_arch_init() to spl_soc_init() arch/arm/Kconfig | 4 ++-- arch/arm/mach-zynq/spl.c | 4 ++-- arch/arm/mach-zynqmp/spl.c | 4 ++-- 3 files changed, 6 insertions(+), 6 deletions(-) diff --git a/arch/arm/Kconfig b/arch/arm/Kconfig index 01d6556c42..db56db9414 100644 --- a/arch/arm/Kconfig +++ b/arch/arm/Kconfig @@ -1275,7 +1275,7 @@ config ARCH_ZYNQ select OF_CONTROL select MTD select SPI - select SPL_BOARD_INIT if SPL + select SPL_SOC_INIT if SPL select SPL_CLK if SPL select SPL_DM if SPL select SPL_DM_SPI if SPL @@ -1318,7 +1318,7 @@ config ARCH_ZYNQMP imply FIRMWARE select GICV2 select OF_CONTROL - select SPL_BOARD_INIT if SPL + select SPL_SOC_INIT if SPL select SPL_CLK if SPL select SPL_DM if SPL select SPL_DM_SPI if SPI && SPL_DM diff --git a/arch/arm/mach-zynq/spl.c b/arch/arm/mach-zynq/spl.c index fea1c9b12a..112b44e2e1 100644 --- a/arch/arm/mach-zynq/spl.c +++ b/arch/arm/mach-zynq/spl.c @@ -32,8 +32,8 @@ void board_init_f(ulong dummy) arch_cpu_init(); } -#ifdef CONFIG_SPL_BOARD_INIT -void spl_board_init(void) +#ifdef CONFIG_SPL_SOC_INIT +void spl_soc_init(void) { preloader_console_init(); #if defined(CONFIG_ARCH_EARLY_INIT_R) && defined(CONFIG_SPL_FPGA) diff --git a/arch/arm/mach-zynqmp/spl.c b/arch/arm/mach-zynqmp/spl.c index a0f35f36fa..71f9932525 100644 --- a/arch/arm/mach-zynqmp/spl.c +++ b/arch/arm/mach-zynqmp/spl.c @@ -56,8 +56,8 @@ static void ps_mode_reset(ulong mode) # define MODE_RESETPS_MODE1 #endif -#ifdef CONFIG_SPL_BOARD_INIT -void spl_board_init(void) +#ifdef CONFIG_SPL_SOC_INIT +void spl_soc_init(void) { preloader_console_init(); ps_mode_reset(MODE_RESET); -- 2.30.2
[PATCH v2 0/2] Introduce spl_soc_init() for SoC specific initialization
From: Lukas Funke Currently some vendors use spl_board_init() for their SoC specific initialization. This prohibits board developers from adding board init code using said function. This series introduces a new function in order to separate SoC init code from board init code. Changes in v2: - Change spl_arch_init() to spl_soc_init() Lukas Funke (2): spl: Introduce SoC specific init function arm64: zynq(mp): Rename spl_board_init() to spl_soc_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
[PATCH v2 1/2] spl: Introduce SoC specific init function
From: Lukas Funke Some architectures use spl_board_init() in their SoC specific implementation. Board developers should be able to add board specific implementation via spl_board_init(). Hence, introduce a spl_soc_init() method which is called right before spl_board_init() for SoC specific implementation. Signed-off-by: Lukas Funke --- (no changes since v1) common/spl/Kconfig | 7 +++ common/spl/spl.c | 3 +++ include/spl.h | 8 3 files changed, 18 insertions(+) diff --git a/common/spl/Kconfig b/common/spl/Kconfig index 6405374bcc..9b5cc8daa7 100644 --- a/common/spl/Kconfig +++ b/common/spl/Kconfig @@ -272,6 +272,13 @@ config SPL_TEXT_BASE help The address in memory that SPL will be running from. +config SPL_SOC_INIT + bool "Call arch-specific initialization in SPL" + help + If this option is enabled, U-Boot will call the function + spl_soc_init() from board_init_r(). This function should be + provided by the architecture. + config SPL_BOARD_INIT bool "Call board-specific initialization in SPL" help diff --git a/common/spl/spl.c b/common/spl/spl.c index b65c439e7a..9b83c85df5 100644 --- a/common/spl/spl.c +++ b/common/spl/spl.c @@ -711,6 +711,9 @@ void board_init_r(gd_t *dummy1, ulong dummy2) } } + if (CONFIG_IS_ENABLED(SOC_INIT)) + spl_soc_init(); + if (CONFIG_IS_ENABLED(BOARD_INIT)) spl_board_init(); diff --git a/include/spl.h b/include/spl.h index 043875f10f..5dfdf778d2 100644 --- a/include/spl.h +++ b/include/spl.h @@ -816,6 +816,14 @@ int spl_early_init(void); */ int spl_init(void); +/* + * spl_soc_init() - Do architecture-specific init in SPL + * + * If SPL_SOC_INIT is enabled, this is called from board_init_r() before + * jumping to the next phase. + */ +void spl_soc_init(void); + /* * spl_board_init() - Do board-specific init in SPL * -- 2.30.2
[PATCH 1/2] spl: Introduce architecture specific init function
From: Lukas Funke Some architectures use spl_board_init() in their architecture specific implementation. Board developers should be able to add board specific implementation via spl_board_init(). Hence, introduce a spl_arch_init() method which is called right before spl_board_init() for architecture specific implementation. Signed-off-by: Lukas Funke --- common/spl/Kconfig | 7 +++ common/spl/spl.c | 3 +++ include/spl.h | 8 3 files changed, 18 insertions(+) diff --git a/common/spl/Kconfig b/common/spl/Kconfig index 6405374bcc..1a987037bb 100644 --- a/common/spl/Kconfig +++ b/common/spl/Kconfig @@ -272,6 +272,13 @@ config SPL_TEXT_BASE help The address in memory that SPL will be running from. +config SPL_ARCH_INIT + bool "Call arch-specific initialization in SPL" + help + If this option is enabled, U-Boot will call the function + spl_arch_init() from board_init_r(). This function should be + provided by the architecture. + config SPL_BOARD_INIT bool "Call board-specific initialization in SPL" help diff --git a/common/spl/spl.c b/common/spl/spl.c index b65c439e7a..2f2deae14f 100644 --- a/common/spl/spl.c +++ b/common/spl/spl.c @@ -711,6 +711,9 @@ void board_init_r(gd_t *dummy1, ulong dummy2) } } + if (CONFIG_IS_ENABLED(ARCH_INIT)) + spl_arch_init(); + if (CONFIG_IS_ENABLED(BOARD_INIT)) spl_board_init(); diff --git a/include/spl.h b/include/spl.h index 043875f10f..2d23c8c0de 100644 --- a/include/spl.h +++ b/include/spl.h @@ -816,6 +816,14 @@ int spl_early_init(void); */ int spl_init(void); +/* + * spl_arch_init() - Do architecture-specific init in SPL + * + * If SPL_ARCH_INIT is enabled, this is called from board_init_r() before + * jumping to the next phase. + */ +void spl_arch_init(void); + /* * spl_board_init() - Do board-specific init in SPL * -- 2.30.2
[PATCH 2/2] arm64: zynq(mp): Rename spl_board_init() to spl_arch_init()
From: Lukas Funke Rename spl_board_init() to spl_arch_init(). Architecture specific implementation should be separated from board specific implementation in order to be extended by board developers. Signed-off-by: Lukas Funke --- arch/arm/Kconfig | 4 ++-- arch/arm/mach-zynq/spl.c | 4 ++-- arch/arm/mach-zynqmp/spl.c | 4 ++-- 3 files changed, 6 insertions(+), 6 deletions(-) diff --git a/arch/arm/Kconfig b/arch/arm/Kconfig index 01d6556c42..4ea889d09b 100644 --- a/arch/arm/Kconfig +++ b/arch/arm/Kconfig @@ -1275,7 +1275,7 @@ config ARCH_ZYNQ select OF_CONTROL select MTD select SPI - select SPL_BOARD_INIT if SPL + select SPL_ARCH_INIT if SPL select SPL_CLK if SPL select SPL_DM if SPL select SPL_DM_SPI if SPL @@ -1318,7 +1318,7 @@ config ARCH_ZYNQMP imply FIRMWARE select GICV2 select OF_CONTROL - select SPL_BOARD_INIT if SPL + select SPL_ARCH_INIT if SPL select SPL_CLK if SPL select SPL_DM if SPL select SPL_DM_SPI if SPI && SPL_DM diff --git a/arch/arm/mach-zynq/spl.c b/arch/arm/mach-zynq/spl.c index fea1c9b12a..0cae792e21 100644 --- a/arch/arm/mach-zynq/spl.c +++ b/arch/arm/mach-zynq/spl.c @@ -32,8 +32,8 @@ void board_init_f(ulong dummy) arch_cpu_init(); } -#ifdef CONFIG_SPL_BOARD_INIT -void spl_board_init(void) +#ifdef CONFIG_SPL_ARCH_INIT +void spl_arch_init(void) { preloader_console_init(); #if defined(CONFIG_ARCH_EARLY_INIT_R) && defined(CONFIG_SPL_FPGA) diff --git a/arch/arm/mach-zynqmp/spl.c b/arch/arm/mach-zynqmp/spl.c index a0f35f36fa..03a45173e6 100644 --- a/arch/arm/mach-zynqmp/spl.c +++ b/arch/arm/mach-zynqmp/spl.c @@ -56,8 +56,8 @@ static void ps_mode_reset(ulong mode) # define MODE_RESETPS_MODE1 #endif -#ifdef CONFIG_SPL_BOARD_INIT -void spl_board_init(void) +#ifdef CONFIG_SPL_ARCH_INIT +void spl_arch_init(void) { preloader_console_init(); ps_mode_reset(MODE_RESET); -- 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
[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 = <>; interrupts = , -- 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 = <>; interrupts = , -- 2.39.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, )) + return CMD_RET_FAILURE; + + if (field_width > BITS_PER_LONG) { + printf_str(inf, format, aval.bmap); + free(aval.bmap); + } else { + printf_str(inf, format, ); + } + + 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 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 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 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, )) + if (setexpr_get_arg(argv[2], w, )) 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, )) { + if (setexpr_get_arg(argv[4], w, )) { if (w == CMD_DATA_SIZE_STR) free(aval.sval); return CMD_RET_FAILURE; -- 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 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 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, ); + 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 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 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 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 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 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 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, ); + + 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 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 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 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 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 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 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 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 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, ); + + 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 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 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 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 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] 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] 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 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 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. +
[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 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 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 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
[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 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):
[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 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 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 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 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 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 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 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 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 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 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 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 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 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 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 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 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 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 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 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 07/12] binman: btool: Add fdt_add_pubkey as btool
From: Lukas Funke Add btool which calls 'fdt_add_pubkey' Signed-off-by: Lukas Funke --- 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 08/12] 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 --- tools/binman/etype/u_boot_spl_pubkey_dtb.py | 105 1 file changed, 105 insertions(+) create mode 100644 tools/binman/etype/u_boot_spl_pubkey_dtb.py 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..25aa817975 --- /dev/null +++ b/tools/binman/etype/u_boot_spl_pubkey_dtb.py @@ -0,0 +1,105 @@ +# 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: + +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 which is pointed out by +'key-name' to node 'signature' in the spl-dtb + +This is equivalent to the '-K' option of 'mkimage' + +Args: +fake_size (int): unused +""" + +# We don't pass fake_size and skip_entry upwards +# because this is currently not support by the blob type +super().ObtainContents() + +with tempfile.NamedTemporaryFile(prefix=os.path.basename( + self.GetFdtEtype()), + dir=tools.get_output_dir())\ + as pubkey_tdb: +tools.write_file(pubkey_tdb.name, self.GetData()) +keyname = tools.get_input_filename(self._keyname + ".crt") +self.fdt_add_pubkey.run(pubkey_tdb.name, +os.path.dirname(keyname), +self._keyname, +self._required, self._algo) +dtb = tools.read_file(pubkey_tdb.name) +self.SetContents(dtb) +state.UpdateFdtContents(self.GetFdtEtype(), dtb) + +return True + +# pylint: disable=R0201,C0116 +def GetDefaultFilename(self): +return 'spl/u-boot-spl-pubkey.dtb' + +# pylint: disable=R0201,C0116 +def GetFdtEtype(self): +return 'u-boot-spl-dtb' + +# pylint: disable=R0201,C0116 +def AddBintools(self, btools): +super().AddBintools(btools) +self.fdt_add_pubkey = self.AddBintool(btools, 'fdt_add_pubkey') -- 2.30.2
[PATCH 03/12] 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 --- 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 02/12] binman: mkimage: Remove extra colon
From: Lukas Funke Remove extra colon typo Signed-off-by: Lukas Funke --- tools/binman/etype/mkimage.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/tools/binman/etype/mkimage.py b/tools/binman/etype/mkimage.py index e028c44070..dd734fc779 100644 --- a/tools/binman/etype/mkimage.py +++ b/tools/binman/etype/mkimage.py @@ -24,7 +24,7 @@ class Entry_mkimage(Entry): - filename: filename of output binary generated by mkimage The data passed to mkimage via the -d flag is collected from subnodes of the -mkimage node, e.g.:: +mkimage node, e.g.: mkimage { filename = "imximage.bin"; -- 2.30.2
[PATCH 09/12] binman: doc: Add documentation for Xilinx Bootgen bintool
From: Lukas Funke Add documentation for the 'bootgen' bintool Signed-off-by: Lukas Funke --- 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 11/12] 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 --- tools/binman/ftest.py | 8 tools/binman/test/280_xilinx_fsb_auth.dts | 22 ++ 2 files changed, 30 insertions(+) create mode 100644 tools/binman/test/280_xilinx_fsb_auth.dts diff --git a/tools/binman/ftest.py b/tools/binman/ftest.py index 3bd09d3fea..f0a7861649 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_fsb_auth.dts') def testSplPubkeyDtb(self): """Test u_boot_spl_pubkey_dtb etype""" diff --git a/tools/binman/test/280_xilinx_fsb_auth.dts b/tools/binman/test/280_xilinx_fsb_auth.dts new file mode 100644 index 00..2bfd36c22e --- /dev/null +++ b/tools/binman/test/280_xilinx_fsb_auth.dts @@ -0,0 +1,22 @@ +// SPDX-License-Identifier: GPL-2.0+ + +/dts-v1/; + +/ { + #address-cells = <1>; + #size-cells = <1>; + + binman { + xilinx_fsbl_auth { + + 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 05/12] 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 --- 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 06/12] 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 --- 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..3bd09d3fea 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..5a2952ed7d --- /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 12/12] 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 --- tools/binman/etype/xilinx_fsbl_auth.py | 186 + 1 file changed, 186 insertions(+) create mode 100644 tools/binman/etype/xilinx_fsbl_auth.py diff --git a/tools/binman/etype/xilinx_fsbl_auth.py b/tools/binman/etype/xilinx_fsbl_auth.py new file mode 100644 index 00..ec70db9414 --- /dev/null +++ b/tools/binman/etype/xilinx_fsbl_auth.py @@ -0,0 +1,186 @@ +# 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 flat binary for booting Xilinx +ZynqMP devices + +Properties / Entry arguments: +- auth-params: (Optional) Authentication parameters passed to bootgen +- fsbl-config: (Optional) FSBL parameters passed to bootgen +- 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. + +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: + +xilinx_fsbl_auth { +psk-filename = "psk0.pem"; +ssk-filename = "ssk0.pem"; +... +fsbl-config = "bh_auth_enable"; +... +}; + +""" +def __init__(self, section, etype, node): +super().__init__(section, etype, node) +self.align_default = None +self.bootgen = None +self._entries = OrderedDict() +self._filename = self.GetDefaultFilename() +self.required_props = ['psk-filename', 'ssk-filename'] + +def ReadNode(self): +"""Read properties from the xilinx_fsbl_auth node""" +super().ReadNode() +self._auth_params = fdt_util.GetStringList(self._node, + 'auth-params') +self._fsbl_config = fdt_util.GetStringList(self._node, + 'fsbl-config') +self._pmufw_filename = fdt_util.GetString(self._node, + 'pmufw-filename', + 'pmu-firmware.elf') +self._psk_filename = fdt_util.GetString(self._node, 'psk-filename', +'psk.pem') +self._ssk_filename = fdt_util.GetString(self._node, 'ssk-filename', +'ssk.pem') +self.ReadEntries() + +def ReadEntries(self): +"""Read the subnodes to find out what should go in this image""" +for node in self._node.subnodes: +entry = Entry.Create(self, node) +entry.ReadNode() +self._entries[entry.name] = entry + +@classmethod +def __ToElf(self, data,
[PATCH 10/12] 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. Signed-off-by: Lukas Funke --- tools/binman/btool/bootgen.py | 82 +++ 1 file changed, 82 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..8bc727a54f --- /dev/null +++ b/tools/binman/btool/bootgen.py @@ -0,0 +1,82 @@ +# 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, output_fname): +""" Sign FSBL(SPL) elf file and bundle it with pmu firmware +to a bootable image + +Args: +arch (str): Xilinx SoC architecture +spl_elf_fname (str): Filename of FSBL ELF file +pmufw_elf_fname (str): Filename pmu firmware +psk_fname (str): Filename of the primary secret key +ssk_fname (str): Filename of the secondary secret key +fsbl_config (str): FSBL config options +auth_params (str): Authentication parameter +output_fname (str): Filename where bootgen should write the result +""" + +_fsbl_config = f"[fsbl_config] {fsbl_config}" if fsbl_config else "" +_auth_params = f"[auth_params] {auth_params}" if auth_params else "" + +bif_template = f"""u_boot_spl_aes_rsa: {{ +[pskfile] {psk_fname} +[sskfile] {ssk_fname} +{_fsbl_config} +{_auth_params} +[ bootloader, + authentication = rsa, + destination_cpu=a53-0] {spl_elf_fname} +[pmufw_image] {pmufw_elf_fname} +}}""" +args = ["-arch", arch] + +with tempfile.NamedTemporaryFile(suffix=".bif", + dir=tools.get_output_dir()) as bif: +tools.write_file(bif.name, bif_template, binary=False) +args += ["-image", bif.name, '-w', '-o', output_fname] +self.run_cmd(*args) + +def fetch(self, method): +"""Fetch bootgen from git""" +if method != bintool.FETCH_BUILD: +return None + +result = self.build_from_git( +'https://github.com/Xilinx/bootgen', +'all', +'build/bootgen/bootgen') +return result -- 2.30.2