From a85a71d3960d8183fc7ec2bc775693dee940021c Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Pali=20Roh=C3=A1r?= Date: Thu, 21 Oct 2021 16:46:06 +0200 Subject: [PATCH 1/9] tools: kwboot: Align UART baudrate change code in BIN header to 128-bit boundary MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit ARM executable code inside the BIN header on some mvebu platforms (e.g. A370, AXP) must always be aligned with the 128-bit boundary. This requirement can be met by inserting dummy arguments into BIN header. Signed-off-by: Pali Rohár Reviewed-by: Stefan Roese --- tools/kwboot.c | 22 +++++++++++++++++----- 1 file changed, 17 insertions(+), 5 deletions(-) diff --git a/tools/kwboot.c b/tools/kwboot.c index 6a1a030308..eb4f5ab879 100644 --- a/tools/kwboot.c +++ b/tools/kwboot.c @@ -255,7 +255,7 @@ static unsigned char kwboot_baud_code[] = { }; #define KWBOOT_BAUDRATE_BIN_HEADER_SZ (sizeof(kwboot_baud_code) + \ - sizeof(struct opt_hdr_v1) + 8) + sizeof(struct opt_hdr_v1) + 8 + 16) static const char kwb_baud_magic[16] = "$baudratechange"; @@ -1328,11 +1328,10 @@ kwboot_add_bin_ohdr_v1(void *img, size_t *size, uint32_t binsz) { struct main_hdr_v1 *hdr = img; struct opt_hdr_v1 *ohdr; + uint32_t num_args; + uint32_t offset; uint32_t ohdrsz; - ohdrsz = binsz + 8 + sizeof(*ohdr); - kwboot_img_grow_hdr(img, size, ohdrsz); - if (hdr->ext & 0x1) { for_each_opt_hdr_v1 (ohdr, img) if (opt_hdr_v1_next(ohdr) == NULL) @@ -1345,13 +1344,26 @@ kwboot_add_bin_ohdr_v1(void *img, size_t *size, uint32_t binsz) ohdr = (void *)(hdr + 1); } + /* + * ARM executable code inside the BIN header on some mvebu platforms + * (e.g. A370, AXP) must always be aligned with the 128-bit boundary. + * This requirement can be met by inserting dummy arguments into + * BIN header, if needed. + */ + offset = &ohdr->data[4] - (char *)img; + num_args = ((16 - offset % 16) % 16) / sizeof(uint32_t); + + ohdrsz = sizeof(*ohdr) + 4 + 4 * num_args + binsz + 4; + kwboot_img_grow_hdr(hdr, size, ohdrsz); + ohdr->headertype = OPT_HDR_V1_BINARY_TYPE; ohdr->headersz_msb = ohdrsz >> 16; ohdr->headersz_lsb = cpu_to_le16(ohdrsz & 0xffff); memset(&ohdr->data[0], 0, ohdrsz - sizeof(*ohdr)); + *(uint32_t *)&ohdr->data[0] = cpu_to_le32(num_args); - return &ohdr->data[4]; + return &ohdr->data[4 + 4 * num_args]; } static void From e58f08b479bb512e4976fc2481657f6cfaf7e7b5 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Pali=20Roh=C3=A1r?= Date: Thu, 21 Oct 2021 16:46:07 +0200 Subject: [PATCH 2/9] tools: kwbimage: Align BIN header executable code to 128-bit boundary MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit ARM executable code inside the BIN header on some mvebu platforms (e.g. A370, AXP) must always be aligned with the 128-bit boundary. This requirement can be met by inserting dummy arguments into BIN header. Signed-off-by: Pali Rohár Reviewed-by: Stefan Roese --- tools/kwbimage.c | 51 ++++++++++++++++++++++++++++++++---------------- 1 file changed, 34 insertions(+), 17 deletions(-) diff --git a/tools/kwbimage.c b/tools/kwbimage.c index 77bf4dd886..e9324baddb 100644 --- a/tools/kwbimage.c +++ b/tools/kwbimage.c @@ -932,6 +932,12 @@ static size_t image_headersz_v1(int *hasext) */ headersz = sizeof(struct main_hdr_v1); + if (image_get_csk_index() >= 0) { + headersz += sizeof(struct secure_hdr_v1); + if (hasext) + *hasext = 1; + } + count = image_count_options(IMAGE_CFG_DATA); if (count > 0) headersz += sizeof(struct register_set_hdr_v1) + 8 * count + 4; @@ -963,15 +969,10 @@ static size_t image_headersz_v1(int *hasext) return 0; } - headersz += sizeof(struct opt_hdr_v1) + - ALIGN(s.st_size, 4) + - (binarye->binary.nargs + 2) * sizeof(uint32_t); - if (hasext) - *hasext = 1; - } - - if (image_get_csk_index() >= 0) { - headersz += sizeof(struct secure_hdr_v1); + headersz += sizeof(struct opt_hdr_v1) + sizeof(uint32_t) + + (binarye->binary.nargs) * sizeof(uint32_t); + headersz = ALIGN(headersz, 16); + headersz += ALIGN(s.st_size, 4) + sizeof(uint32_t); if (hasext) *hasext = 1; } @@ -984,9 +985,12 @@ static size_t image_headersz_v1(int *hasext) } int add_binary_header_v1(uint8_t **cur, uint8_t **next_ext, - struct image_cfg_element *binarye) + struct image_cfg_element *binarye, + struct main_hdr_v1 *main_hdr) { struct opt_hdr_v1 *hdr = (struct opt_hdr_v1 *)*cur; + uint32_t add_args; + uint32_t offset; uint32_t *args; size_t binhdrsz; struct stat s; @@ -1009,12 +1013,6 @@ int add_binary_header_v1(uint8_t **cur, uint8_t **next_ext, goto err_close; } - binhdrsz = sizeof(struct opt_hdr_v1) + - (binarye->binary.nargs + 2) * sizeof(uint32_t) + - ALIGN(s.st_size, 4); - hdr->headersz_lsb = cpu_to_le16(binhdrsz & 0xFFFF); - hdr->headersz_msb = (binhdrsz & 0xFFFF0000) >> 16; - *cur += sizeof(struct opt_hdr_v1); args = (uint32_t *)*cur; @@ -1025,6 +1023,19 @@ int add_binary_header_v1(uint8_t **cur, uint8_t **next_ext, *cur += (binarye->binary.nargs + 1) * sizeof(uint32_t); + /* + * ARM executable code inside the BIN header on some mvebu platforms + * (e.g. A370, AXP) must always be aligned with the 128-bit boundary. + * This requirement can be met by inserting dummy arguments into + * BIN header, if needed. + */ + offset = *cur - (uint8_t *)main_hdr; + add_args = ((16 - offset % 16) % 16) / sizeof(uint32_t); + if (add_args) { + *(args - 1) = cpu_to_le32(binarye->binary.nargs + add_args); + *cur += add_args * sizeof(uint32_t); + } + ret = fread(*cur, s.st_size, 1, bin); if (ret != 1) { fprintf(stderr, @@ -1043,6 +1054,12 @@ int add_binary_header_v1(uint8_t **cur, uint8_t **next_ext, *cur += sizeof(uint32_t); + binhdrsz = sizeof(struct opt_hdr_v1) + + (binarye->binary.nargs + add_args + 2) * sizeof(uint32_t) + + ALIGN(s.st_size, 4); + hdr->headersz_lsb = cpu_to_le16(binhdrsz & 0xFFFF); + hdr->headersz_msb = (binhdrsz & 0xFFFF0000) >> 16; + return 0; err_close: @@ -1299,7 +1316,7 @@ static void *image_create_v1(size_t *imagesz, struct image_tool_params *params, if (e->type != IMAGE_CFG_BINARY) continue; - if (add_binary_header_v1(&cur, &next_ext, e)) + if (add_binary_header_v1(&cur, &next_ext, e, main_hdr)) return NULL; } From 701769d87ea3006103c93fd0ecc26875e02d461f Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Pali=20Roh=C3=A1r?= Date: Thu, 21 Oct 2021 16:46:08 +0200 Subject: [PATCH 3/9] arm: mvebu: Add documentation for save_boot_params() function MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Important detail is availability of kwbimage BIN header arguments passed via r0 and r1 registers by BootROM. Signed-off-by: Pali Rohár Reviewed-by: Stefan Roese --- arch/arm/mach-mvebu/lowlevel_spl.S | 9 +++++++++ 1 file changed, 9 insertions(+) diff --git a/arch/arm/mach-mvebu/lowlevel_spl.S b/arch/arm/mach-mvebu/lowlevel_spl.S index dde77b7652..501c239e9d 100644 --- a/arch/arm/mach-mvebu/lowlevel_spl.S +++ b/arch/arm/mach-mvebu/lowlevel_spl.S @@ -3,6 +3,15 @@ #include #include +/* + * BootROM loads the header part of kwbimage into L2 cache. BIN header usually + * contains U-Boot SPL, optionally it can also contain additional arguments. + * The number of these arguments is in r0, pointer to the argument array in r1. + * BootROM expects executable BIN header code to return to address stored in lr. + * Other registers (r2 - r12) must be preserved. We save all registers to + * CONFIG_SPL_BOOTROM_SAVE address. BIN header arguments (passed via r0 and r1) + * are currently not used by U-Boot SPL binary. + */ ENTRY(save_boot_params) stmfd sp!, {r0 - r12, lr} /* @ save registers on stack */ ldr r12, =CONFIG_SPL_BOOTROM_SAVE From e6571f38c943f7ff1ed38b90940d1265f6c7b9ba Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Pali=20Roh=C3=A1r?= Date: Thu, 21 Oct 2021 16:46:09 +0200 Subject: [PATCH 4/9] arm: mvebu: Remove dummy BIN header arguments for SPL binary MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit U-Boot SPL binary does not read BIN header arguments, so passing some dummy values 0000005b and 00000068 has no effect for U-Boot SPL code. Probably these two values comes from old Marvell DDR training code which was separated from U-Boot and used it for some configuration. Seems that two 32-bit values were specified here to ensure SPL code alignment to 128-bit boundary as it is required e.g. for A370 or AXP processors. Main kwbimage header is 64-byte long which is aligned to 128-bit boundary. Optional kwbheader is 32-bit long, number of BIN header arguments is stored in 32-bit number. So for alignment to 128-bit boundary is needed 64-bit padding which exactly these two 32-bit dummy arguments provided. Now when mkimage correctly aligns start of executable code in BIN header to 128-bit boundary, there is no requirement to put dummy argument values into kwbimage. So remove them. Signed-off-by: Pali Rohár Reviewed-by: Stefan Roese --- arch/arm/mach-mvebu/kwbimage.cfg.in | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/arch/arm/mach-mvebu/kwbimage.cfg.in b/arch/arm/mach-mvebu/kwbimage.cfg.in index 72e67d75c3..049d23c6ef 100644 --- a/arch/arm/mach-mvebu/kwbimage.cfg.in +++ b/arch/arm/mach-mvebu/kwbimage.cfg.in @@ -9,4 +9,4 @@ VERSION 1 #@BOOT_FROM # Binary Header (bin_hdr) with DDR3 training code -BINARY spl/u-boot-spl.bin 0000005b 00000068 +BINARY spl/u-boot-spl.bin From 59102987be25920b2180ebe2a18fbaf56c5a8278 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Pali=20Roh=C3=A1r?= Date: Thu, 21 Oct 2021 17:55:48 +0200 Subject: [PATCH 5/9] arm: mvebu: turris_omnia: Fix MTD partitions order for Linux MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Linux enumerates MTD partitions in DTB order, while the fdt_add_subnode() function puts a new subnode at the beginning. To fix this, put MTD partitions into DTB in reverse order. Fixes: 92f36c8e74c1 ("arm: mvebu: turris_omnia: fixup MTD partitions in Linux' DTB") Signed-off-by: Pali Rohár Reviewed-by: Marek Behún Reviewed-by: Stefan Roese --- board/CZ.NIC/turris_omnia/turris_omnia.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/board/CZ.NIC/turris_omnia/turris_omnia.c b/board/CZ.NIC/turris_omnia/turris_omnia.c index 39051a803a..36c596efc5 100644 --- a/board/CZ.NIC/turris_omnia/turris_omnia.c +++ b/board/CZ.NIC/turris_omnia/turris_omnia.c @@ -603,7 +603,7 @@ static bool fixup_mtd_partitions(void *blob, int offset, struct mtd_info *mtd) mtd_probe_devices(); - list_for_each_entry(slave, &mtd->partitions, node) { + list_for_each_entry_reverse(slave, &mtd->partitions, node) { char name[32]; int part; From 2fdba4f6585c31da748eee69a8dea1cf0a11d311 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Pali=20Roh=C3=A1r?= Date: Fri, 22 Oct 2021 12:37:46 +0200 Subject: [PATCH 6/9] tools: kwbimage: Add support for NAND_PAGE_SIZE command also for v1 images MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit The NAND_PAGE_SIZE command is already supported by mkimage for v0 images, but not for v1 images. A38x and A39x BootROM supports reading NAND flash page size from v1 image in the same way as Kirkwood BootROM from v0 image. It it documented in A38x and A39x Functional Specification. Signed-off-by: Pali Rohár Reviewed-by: Stefan Roese --- tools/kwbimage.c | 3 +++ tools/kwbimage.h | 2 +- 2 files changed, 4 insertions(+), 1 deletion(-) diff --git a/tools/kwbimage.c b/tools/kwbimage.c index e9324baddb..67c0c628ae 100644 --- a/tools/kwbimage.c +++ b/tools/kwbimage.c @@ -1231,6 +1231,9 @@ static void *image_create_v1(size_t *imagesz, struct image_tool_params *params, e = image_find_option(IMAGE_CFG_NAND_BLKSZ); if (e) main_hdr->nandblocksize = e->nandblksz / (64 * 1024); + e = image_find_option(IMAGE_CFG_NAND_PAGESZ); + if (e) + main_hdr->nandpagesize = cpu_to_le16(e->nandpagesz); e = image_find_option(IMAGE_CFG_NAND_BADBLK_LOCATION); if (e) main_hdr->nandbadblklocation = e->nandbadblklocation; diff --git a/tools/kwbimage.h b/tools/kwbimage.h index 126d482fe7..f1ba95c2fa 100644 --- a/tools/kwbimage.h +++ b/tools/kwbimage.h @@ -73,7 +73,7 @@ struct ext_hdr_v0 { struct main_hdr_v1 { uint8_t blockid; /* 0x0 */ uint8_t flags; /* 0x1 */ - uint16_t reserved2; /* 0x2-0x3 */ + uint16_t nandpagesize; /* 0x2-0x3 */ uint32_t blocksize; /* 0x4-0x7 */ uint8_t version; /* 0x8 */ uint8_t headersz_msb; /* 0x9 */ From 0089f61e2dad50650d848ce8625d2b2141f56984 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Pali=20Roh=C3=A1r?= Date: Fri, 22 Oct 2021 12:37:47 +0200 Subject: [PATCH 7/9] tools: kwboot: Patch nandpagesize to zero also for v1 image MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit kwbimage v1 has also nandpagesize field. So set it to zero for both image versions when image is not signed. Signed-off-by: Pali Rohár Reviewed-by: Stefan Roese --- tools/kwboot.c | 13 ++++++------- 1 file changed, 6 insertions(+), 7 deletions(-) diff --git a/tools/kwboot.c b/tools/kwboot.c index eb4f5ab879..7e1be29623 100644 --- a/tools/kwboot.c +++ b/tools/kwboot.c @@ -1428,13 +1428,6 @@ kwboot_img_patch(void *img, size_t *size, int baudrate) if (csum != hdr->checksum) goto err; - if (image_ver == 0) { - struct main_hdr_v0 *hdr_v0 = img; - - hdr_v0->nandeccmode = IBR_HDR_ECC_DISABLED; - hdr_v0->nandpagesize = 0; - } - srcaddr = le32_to_cpu(hdr->srcaddr); switch (hdr->blockid) { @@ -1480,6 +1473,12 @@ kwboot_img_patch(void *img, size_t *size, int baudrate) hdr->blockid = IBR_HDR_UART_ID; } + if (!is_secure) { + if (image_ver == 0) + ((struct main_hdr_v0 *)img)->nandeccmode = IBR_HDR_ECC_DISABLED; + hdr->nandpagesize = 0; + } + if (baudrate) { uint32_t codesz = sizeof(kwboot_baud_code); void *code; From 33cdd9eeaaff48d083af5c0126823348c2b44d97 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Pali=20Roh=C3=A1r?= Date: Fri, 22 Oct 2021 12:37:48 +0200 Subject: [PATCH 8/9] arm: mvebu: Update name of kwbimage v1 field at offset 0x2-0x3 MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit At this offset is stored nand page size. Signed-off-by: Pali Rohár Reviewed-by: Stefan Roese --- arch/arm/mach-mvebu/spl.c | 2 +- cmd/mvebu/bubt.c | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/arch/arm/mach-mvebu/spl.c b/arch/arm/mach-mvebu/spl.c index b798c797cc..27389bfa78 100644 --- a/arch/arm/mach-mvebu/spl.c +++ b/arch/arm/mach-mvebu/spl.c @@ -76,7 +76,7 @@ struct kwbimage_main_hdr_v1 { uint8_t blockid; /* 0x0 */ uint8_t flags; /* 0x1 */ - uint16_t reserved2; /* 0x2-0x3 */ + uint16_t nandpagesize; /* 0x2-0x3 */ uint32_t blocksize; /* 0x4-0x7 */ uint8_t version; /* 0x8 */ uint8_t headersz_msb; /* 0x9 */ diff --git a/cmd/mvebu/bubt.c b/cmd/mvebu/bubt.c index d4f381b6ad..543eca817c 100644 --- a/cmd/mvebu/bubt.c +++ b/cmd/mvebu/bubt.c @@ -89,7 +89,7 @@ struct mvebu_image_info { struct a38x_main_hdr_v1 { u8 blockid; /* 0x0 */ u8 flags; /* 0x1 */ - u16 reserved2; /* 0x2-0x3 */ + u16 nandpagesize; /* 0x2-0x3 */ u32 blocksize; /* 0x4-0x7 */ u8 version; /* 0x8 */ u8 headersz_msb; /* 0x9 */ From 7af368f4717a2c4b118f8cae597e268dc88a726c Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Pali=20Roh=C3=A1r?= Date: Fri, 22 Oct 2021 12:41:10 +0200 Subject: [PATCH 9/9] arm: mvebu: Fix comments about kwbimage structures MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit kwbimage v1 is used on more SoCs. Signed-off-by: Pali Rohár Reviewed-by: Stefan Roese --- arch/arm/mach-mvebu/spl.c | 2 +- cmd/mvebu/bubt.c | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/arch/arm/mach-mvebu/spl.c b/arch/arm/mach-mvebu/spl.c index 27389bfa78..cad3f0a488 100644 --- a/arch/arm/mach-mvebu/spl.c +++ b/arch/arm/mach-mvebu/spl.c @@ -72,7 +72,7 @@ #define IBR_HDR_UART_ID 0x69 #define IBR_HDR_SDIO_ID 0xAE -/* Structure of the main header, version 1 (Armada 370/38x/XP) */ +/* Structure of the main header, version 1 (Armada 370/XP/375/38x/39x) */ struct kwbimage_main_hdr_v1 { uint8_t blockid; /* 0x0 */ uint8_t flags; /* 0x1 */ diff --git a/cmd/mvebu/bubt.c b/cmd/mvebu/bubt.c index 543eca817c..a7f3ff3c6f 100644 --- a/cmd/mvebu/bubt.c +++ b/cmd/mvebu/bubt.c @@ -85,7 +85,7 @@ struct mvebu_image_info { }; #endif -/* Structure of the main header, version 1 (Armada 370/38x/XP) */ +/* Structure of the main header, version 1 (Armada 370/XP/375/38x/39x) */ struct a38x_main_hdr_v1 { u8 blockid; /* 0x0 */ u8 flags; /* 0x1 */