Hi,

On 15-07-15 18:33, Bernhard Nortmann wrote:
A patch to extend the "fel spl" command to properly handle not only the SPL
part of a combined u-boot-sunxi-with-spl.bin boot file, but additionally
also transfer the main u-boot binary (image) contained within the second
part of such files.

This can simplify the boot process / steps required to get a proper FEL
setup - e.g. it avoids having to select u-boot.bin vs. u-boot-dtb.bin,
see e.g. http://lists.denx.de/pipermail/u-boot/2015-June/217476.html

On top of that a new "fel uboot" command is introduced. As per suggestions
on the mailing list, it will take such a combined (SPL + U-Boot) file and
actually start U-Boot execution before the program exits. "uboot" may thus
also be combined with other "write" commands to transfer additional files
required for the boot (e.g. boot script, kernel, initrd).

Original patch/RFC was here: 
https://groups.google.com/forum/#!topic/linux-sunxi/wBEGUoLNRro

Signed-off-by: Bernhard Nortmann <[email protected]>

Thanks, pushed with Siarhei's ack added.

We really should do a new sunxi-tools release one of these days.

Does anyone feel up to doing this ?

Regards,

Hans


---
  fel.c | 124 +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++---
  1 file changed, 119 insertions(+), 5 deletions(-)

diff --git a/fel.c b/fel.c
index adf8f35..8a7974c 100644
--- a/fel.c
+++ b/fel.c
@@ -62,6 +62,9 @@ static int AW_USB_FEL_BULK_EP_OUT;
  static int AW_USB_FEL_BULK_EP_IN;
  static int timeout = 60000;
  static int verbose = 0; /* Makes the 'fel' tool more talkative if non-zero */
+static uint32_t uboot_entry = 0; /* entry point (address) of U-Boot */
+static uint32_t uboot_size  = 0; /* size of U-Boot binary */
+static int uboot_autostart  = 0; /* "uboot" command flag = autostart U-Boot */

  static void pr_info(const char *fmt, ...)
  {
@@ -208,6 +211,13 @@ void aw_fel_read(libusb_device_handle *usb, uint32_t 
offset, void *buf, size_t l

  void aw_fel_write(libusb_device_handle *usb, void *buf, uint32_t offset, 
size_t len)
  {
+       /* safeguard against overwriting an already loaded U-Boot binary */
+       if (uboot_size > 0 && offset <= uboot_entry + uboot_size && offset + len 
>= uboot_entry) {
+               fprintf(stderr, "ERROR: Attempt to overwrite U-Boot! "
+                       "Request 0x%08X-0x%08X overlaps 0x%08X-0x%08X.\n",
+                       offset, offset + len, uboot_entry, uboot_entry + 
uboot_size);
+               exit(1);
+       }
        aw_send_fel_request(usb, AW_FEL_1_WRITE, offset, len);
        aw_usb_write(usb, buf, len);
        aw_read_fel_status(usb);
@@ -599,6 +609,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 +623,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 +737,85 @@ 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)
+
+/*
+ * This function tests a given buffer address and length for a valid U-Boot
+ * image. Upon success, the image data gets transferred to the default memory
+ * address stored within the image header; and the function preserves the
+ * U-Boot entry point (offset) and size values.
+ */
+void aw_fel_write_uboot_image(libusb_device_handle *usb,
+               uint8_t *buf, size_t len)
+{
+       if (len <= HEADER_SIZE)
+               return; /* Insufficient size (no actual data), just bail out */
+
+       /* Check for a valid mkimage header */
+       uint32_t *buf32 = (uint32_t *)buf;
+
+       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);
+       }
+       uint32_t data_size = be32toh(buf32[3]); /* Image Data Size */
+       uint32_t load_addr = be32toh(buf32[4]); /* Data Load Address */
+       if ((size_t)data_size != len - HEADER_SIZE) {
+               fprintf(stderr, "U-Boot image data size mismatch: "
+                       "expected %d, 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%08X.\n",
+               IH_NMLEN, buf + HEADER_NAME_OFFSET, data_size, load_addr);
+
+       aw_fel_write(usb, buf + HEADER_SIZE, load_addr, data_size);
+
+       /* keep track of U-Boot memory region in global vars */
+       uboot_entry = load_addr;
+       uboot_size = data_size;
+}
+
+/*
+ * This function handles the common part of both "spl" and "uboot" commands.
+ */
+void aw_fel_process_spl_and_uboot(libusb_device_handle *usb,
+               const char *filename)
+{
+       /* load file into memory buffer */
+       size_t size;
+       uint8_t *buf = load_file(filename, &size);
+       /* write and execute the SPL from the buffer */
+       aw_fel_write_and_execute_spl(usb, buf, size);
+       /* check for optional main U-Boot binary (and transfer it, if 
applicable) */
+       aw_fel_write_uboot_image(usb, buf + SPL_LEN_LIMIT, size - 
SPL_LEN_LIMIT);
+}
+
  static int aw_fel_get_endpoint(libusb_device_handle *usb)
  {
        struct libusb_device *dev = libusb_get_device(usb);
@@ -781,6 +875,17 @@ int main(int argc, char **argv)
        if (argc <= 1) {
                printf("Usage: %s [options] command arguments... [command...]\n"
                        "  -v, --verbose                   Verbose logging\n"
+                       "\n"
+                       "  spl file                        Load and execute U-Boot 
SPL\n"
+                       "          If file additionally contains a main U-Boot 
binary\n"
+                       "          (u-boot-sunxi-with-spl.bin), this command also 
transfers that\n"
+                       "          to memory (default address from image), but won't 
execute it.\n"
+                       "\n"
+                       "  uboot file-with-spl             like \"spl\", but 
actually starts U-Boot\n"
+                       "          U-Boot execution will take place when the fel 
utility exits.\n"
+                       "          This allows combining \"uboot\" with further 
\"write\" commands\n"
+                       "          (to transfer other files needed for the 
boot).\n"
+                       "\n"
                        "  hex[dump] address length        Dumps memory region in 
hex\n"
                        "  dump address length             Binary memory dump\n"
                        "  exe[cute] address               Call function 
address\n"
@@ -789,7 +894,6 @@ int main(int argc, char **argv)
                        "  ver[sion]                       Show BROM version\n"
                        "  clear address length            Clear memory\n"
                        "  fill address length value       Fill memory\n"
-                       "  spl file                        Load and execute U-Boot 
SPL\n"
                        , argv[0]
                );
        }
@@ -870,9 +974,13 @@ int main(int argc, char **argv)
                        aw_fel_fill(handle, strtoul(argv[2], NULL, 0), 
strtoul(argv[3], NULL, 0), (unsigned char)strtoul(argv[4], NULL, 0));
                        skip=4;
                } else if (strcmp(argv[1], "spl") == 0 && argc > 2) {
-                       size_t size;
-                       uint8_t *buf = load_file(argv[2], &size);
-                       aw_fel_write_and_execute_spl(handle, buf, size);
+                       aw_fel_process_spl_and_uboot(handle, argv[2]);
+                       skip=2;
+               } else if (strcmp(argv[1], "uboot") == 0 && argc > 2) {
+                       aw_fel_process_spl_and_uboot(handle, argv[2]);
+                       uboot_autostart = (uboot_entry > 0 && uboot_size > 0);
+                       if (!uboot_autostart)
+                               printf("Warning: \"uboot\" command failed to detect 
image! Can't execute U-Boot.\n");
                        skip=2;
                } else {
                        fprintf(stderr,"Invalid command %s\n", argv[1]);
@@ -882,6 +990,12 @@ int main(int argc, char **argv)
                argv+=skip;
        }

+       // auto-start U-Boot if requested (by the "uboot" command)
+       if (uboot_autostart) {
+               pr_info("Starting U-Boot (0x%08X).\n", uboot_entry);
+               aw_fel_execute(handle, uboot_entry);
+       }
+
  #if defined(__linux__)
        if (iface_detached >= 0)
                libusb_attach_kernel_driver(handle, iface_detached);


--
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