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 <
bernhard...@web.de>
---
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