]> git.dujemihanovic.xyz Git - u-boot.git/commitdiff
tools: kwboot: Add check that kwbimage contains DDR init code
authorPali Rohár <pali@kernel.org>
Sun, 8 Jan 2023 12:46:14 +0000 (13:46 +0100)
committerStefan Roese <sr@denx.de>
Wed, 1 Mar 2023 05:39:17 +0000 (06:39 +0100)
Some NOR images may be execute-in-place and do not contain DDR init code in
its kwbimage header. Such images cannot be booted over UART as BootROM
loads them to RAM. Add check that kwbimage contains DDR init code in its
header (either as binary code header or as the simple register-value set).

In some cases it is possible to load very small image into L2SRAM and when
DDR init code is not required. So check for L2SRAM load address and skip
DDR init code check in this case.

Signed-off-by: Pali Rohár <pali@kernel.org>
tools/kwboot.c

index c8c7a8d2465829dd4f5db873320e78fd8c5d347c..f624edc7798f278f06f9b9defcc0ca8fb28b6501 100644 (file)
@@ -1780,6 +1780,47 @@ kwboot_img_is_secure(void *img)
        return 0;
 }
 
+static int
+kwboot_img_has_ddr_init(void *img)
+{
+       const struct register_set_hdr_v1 *rhdr;
+       const struct main_hdr_v0 *hdr0;
+       struct opt_hdr_v1 *ohdr;
+       u32 ohdrsz;
+       int last;
+
+       /*
+        * kwbimage v0 image headers contain DDR init code either in
+        * extension header or in binary code header.
+        */
+       if (kwbimage_version(img) == 0) {
+               hdr0 = img;
+               return hdr0->ext || hdr0->bin;
+       }
+
+       /*
+        * kwbimage v1 image headers contain DDR init code either in binary
+        * code header or in a register set list header with SDRAM_SETUP.
+        */
+       for_each_opt_hdr_v1 (ohdr, img) {
+               if (ohdr->headertype == OPT_HDR_V1_BINARY_TYPE)
+                       return 1;
+               if (ohdr->headertype == OPT_HDR_V1_REGISTER_TYPE) {
+                       rhdr = (const struct register_set_hdr_v1 *)ohdr;
+                       ohdrsz = opt_hdr_v1_size(ohdr);
+                       if (ohdrsz >= sizeof(*ohdr) + sizeof(rhdr->data[0].last_entry)) {
+                               ohdrsz -= sizeof(*ohdr) + sizeof(rhdr->data[0].last_entry);
+                               last = ohdrsz / sizeof(rhdr->data[0].entry);
+                               if (rhdr->data[last].last_entry.delay ==
+                                   REGISTER_SET_HDR_OPT_DELAY_SDRAM_SETUP)
+                                       return 1;
+                       }
+               }
+       }
+
+       return 0;
+}
+
 static void *
 kwboot_img_grow_data_right(void *img, size_t *size, size_t grow)
 {
@@ -2011,6 +2052,13 @@ kwboot_img_patch(void *img, size_t *size, int baudrate)
                kwboot_img_grow_data_right(img, size, sizeof(uint32_t));
        }
 
+       if (!kwboot_img_has_ddr_init(img) &&
+           (le32_to_cpu(hdr->destaddr) < 0x40000000 ||
+            le32_to_cpu(hdr->destaddr) + le32_to_cpu(hdr->blocksize) > 0x40034000)) {
+               fprintf(stderr, "Image does not contain DDR init code needed for UART booting\n");
+               goto err;
+       }
+
        is_secure = kwboot_img_is_secure(img);
 
        if (hdr->blockid != IBR_HDR_UART_ID) {