This patch introduces a new "fel uboot" command. Its purpose is to
handle not only the SPL part of a combined u-boot-sunxi-with-spl.bin
boot file, but additionally transfer the main u-boot binary (image)
contained within the second part of such files.

With recent (dtb-based) U-Boot versions, the idea of this modification
is to prevent users mixing up u-boot.bin and u-boot-dtb.bin (possibly
unconscious, e.g. by relying on outdated FEL scripts).
see e.g. http://lists.denx.de/pipermail/u-boot/2015-June/217476.html

Signed-off-by: Bernhard Nortmann <[email protected]>
---
 fel.c | 68 ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++-
 1 file changed, 67 insertions(+), 1 deletion(-)

diff --git a/fel.c b/fel.c
index adf8f35..843be14 100644
--- a/fel.c
+++ b/fel.c
@@ -599,6 +599,11 @@ void aw_restore_and_enable_mmu(libusb_device_handle *usb, 
uint32_t *tt)
        free(tt);
 }
 
+/*
+ * Maximum size of SPL, at the same time this is the start offset
+ * of the main U-Boot image within u-boot-sunxi-with-spl.bin
+ */
+static const int SPL_LEN_LIMIT = 0x8000;
 
 void aw_fel_write_and_execute_spl(libusb_device_handle *usb,
                                  uint8_t *buf, size_t len)
@@ -608,7 +613,7 @@ void aw_fel_write_and_execute_spl(libusb_device_handle *usb,
        char header_signature[9] = { 0 };
        size_t i, thunk_size;
        uint32_t *thunk_buf;
-       uint32_t spl_checksum, spl_len, spl_len_limit = 0x8000;
+       uint32_t spl_checksum, spl_len, spl_len_limit = SPL_LEN_LIMIT;
        uint32_t *buf32 = (uint32_t *)buf;
        uint32_t written = 0;
        uint32_t *tt = NULL;
@@ -722,6 +727,58 @@ void aw_fel_write_and_execute_spl(libusb_device_handle 
*usb,
        aw_restore_and_enable_mmu(usb, tt);
 }
 
+/* Constants taken from ${U-BOOT}/include/image.h */
+#define IH_MAGIC       0x27051956      /* Image Magic Number   */
+#define IH_ARCH_ARM            2       /* ARM                  */
+#define IH_TYPE_FIRMWARE       5       /* Firmware Image       */
+#define IH_NMLEN               32      /* Image Name Length    */
+
+#define HEADER_NAME_OFFSET     32      /* offset of name field */
+#define HEADER_SIZE            (HEADER_NAME_OFFSET + IH_NMLEN)
+
+void aw_fel_write_uboot_image(libusb_device_handle *usb,
+                               uint8_t *buf, size_t len)
+{
+       uint32_t *buf32 = (uint32_t *)buf;
+       uint32_t load_addr, data_size;
+
+       /* Check for a valid mkimage header */
+       if (be32toh(buf32[0]) != IH_MAGIC) {
+               fprintf(stderr, "U-Boot image verification failure: "
+                       "expected IH_MAGIC, got 0x%X\n", be32toh(buf32[0]));
+               exit(1);
+       }
+       if (buf[29] != IH_ARCH_ARM|| buf[30] != IH_TYPE_FIRMWARE) {
+               fprintf(stderr, "U-Boot image verification failure: "
+                       "expected ARM firmware, got %02X %02X\n", buf[29], 
buf[30]);
+               exit(1);
+       }
+       data_size = be32toh(buf32[3]); /* Image Data Size */
+       load_addr = be32toh(buf32[4]); /* Data Load Address */
+       if (data_size != len - HEADER_SIZE) {
+               fprintf(stderr, "U-Boot image data size mismatch: "
+                       "expected %u, got %u\n", len - HEADER_SIZE, data_size);
+               exit(1);
+       }
+       /* TODO: Verify image data integrity using the checksum field ih_dcrc,
+        * available from be32toh(buf32[6])
+        *
+        * However, this requires CRC routines that mimic their U-Boot
+        * counterparts, namely image_check_dcrc() in 
${U-BOOT}/common/image.cabs
+        * and crc_wd() in ${U-BOOT}/lib/crc32.c
+        *
+        * It should be investigated if existing CRC routines in sunxi-tools
+        * could be factored out and reused for this purpose - e.g. calc_crc32()
+        * from nand-part-main.c
+        */
+
+       /* If we get here, we're "good to go" (i.e. actually write the data) */
+       pr_info("Writing image \"%.*s\", %u bytes @ 0x%X\n",
+               IH_NMLEN, buf + HEADER_NAME_OFFSET, data_size, load_addr);
+
+       aw_fel_write(usb, buf + HEADER_SIZE, load_addr, data_size);
+}
+
 static int aw_fel_get_endpoint(libusb_device_handle *usb)
 {
        struct libusb_device *dev = libusb_get_device(usb);
@@ -790,6 +847,7 @@ int main(int argc, char **argv)
                        "       clear address length            Clear memory\n"
                        "       fill address length value       Fill memory\n"
                        "       spl file                        Load and 
execute U-Boot SPL\n"
+                       "       uboot file-with-spl             Load and 
execute SPL, and write U-Boot\n"
                        , argv[0]
                );
        }
@@ -874,6 +932,14 @@ int main(int argc, char **argv)
                        uint8_t *buf = load_file(argv[2], &size);
                        aw_fel_write_and_execute_spl(handle, buf, size);
                        skip=2;
+               } else if (strcmp(argv[1], "uboot") == 0 && argc > 2) {
+                       /* Write (and execute) SPL, then write (main) U-Boot */
+                       size_t size;
+                       uint8_t *buf = load_file(argv[2], &size);
+                       aw_fel_write_and_execute_spl(handle, buf, size);
+                       usleep(500000); // give SPL execution some time (0.5s) 
to complete
+                       aw_fel_write_uboot_image(handle, buf + SPL_LEN_LIMIT, 
size - SPL_LEN_LIMIT);
+                       skip=2;
                } else {
                        fprintf(stderr,"Invalid command %s\n", argv[1]);
                        exit(1);
-- 
2.0.5

-- 
You received this message because you are subscribed to the Google Groups 
"linux-sunxi" group.
To unsubscribe from this group and stop receiving emails from it, send an email 
to [email protected].
For more options, visit https://groups.google.com/d/optout.

Reply via email to