ARMv7: Made some improvements to usbboot.
authorDavid Cock <david.cock@inf.ethz.ch>
Tue, 19 Jul 2016 13:11:50 +0000 (15:11 +0200)
committerDavid Cock <david.cock@inf.ethz.ch>
Tue, 19 Jul 2016 13:13:26 +0000 (15:13 +0200)
Customised a bit for Barrelfish now, and supports loading from an ELF without
specifying an explicit base address.  The existing code was also chopping the
last few hundred bytes off of every image it loaded.

Signed-off-by: David Cock <david.cock@inf.ethz.ch>

devices/Hakefile
devices/omap/omap44xx_boot.dev [new file with mode: 0644]
platforms/Hakefile
tools/usbboot/Hakefile
tools/usbboot/aboot.c
tools/usbboot/boot.c [deleted file]
tools/usbboot/include/aboot/aboot.h
tools/usbboot/include/omap4/boot.h [new file with mode: 0644]
tools/usbboot/usb-linux.c
tools/usbboot/usbboot.c

index def00a9..6b52e43 100644 (file)
@@ -70,6 +70,7 @@
            "omap/ehci",
            "omap/ohci",
            "omap/omap_uart",
+           "omap/omap44xx_boot",
            "omap/omap44xx_cam_cm2",
            "omap/omap44xx_cam_prm",
            "omap/omap44xx_ckgen_cm1",
diff --git a/devices/omap/omap44xx_boot.dev b/devices/omap/omap44xx_boot.dev
new file mode 100644 (file)
index 0000000..7e83f99
--- /dev/null
@@ -0,0 +1,21 @@
+/* See OMAP4460 TRM S27.4.5. */
+device omap44xx_boot msbfirst () "OMAP44xx Peripheral Boot Messages" {
+
+    constants boot_msg "Booting Messages" {
+        periph_boot = 0xF0030002 "Continue peripherial booting";
+        get_asic_id = 0xF0030003 "Request ASIC ID";
+        /* Change device requests. */
+        chdev_void    = 0xF0030006 "Void, no device";
+        chdev_xip     = 0xF0030106 "Switch to XIP memory";
+        chdev_xipwait = 0xF0030206 "Switch to XIP memory, monitor wait signal";
+        chdev_nand    = 0xF0030306 "Switch to NAND";
+        chdev_onenand = 0xF0030406 "Switch to OneNAND";
+        chdev_mmc1    = 0xF0030506 "Switch to MMC1";
+        chdev_mmc2_1  = 0xF0030606 "Switch to MMC2(1)";
+        chdev_mmc2_2  = 0xF0030706 "Switch to MMC2(2)";
+        chdev_uart3   = 0xF0034306 "Switch to UART3";
+        chdev_usb1    = 0xF0034506 "Switch to USB(1) (internal transceiver)";
+        chdev_ulpi    = 0xF0034606 "Switch to USB-ULPI";
+        chdev_usb2    = 0xF0034706 "Switch to USB(2) (internal transceiver)";
+    };
+};
index 1fd0ab0..5da1d10 100644 (file)
@@ -605,7 +605,7 @@ let bin_rcce_lu = [ "/sbin/" ++ f | f <- [
 
     boot "usbboot_panda" [ "armv7" ] [
       In BuildTree "tools" "/bin/usbboot",
-      NStr "0x80000000:", In BuildTree "root" "/armv7_pandaboard_image.bin"
+      In BuildTree "root" "/armv7_pandaboard_image"
     ]
     "Boot Barrelfish on a Pandaboard, over a local USB cable"
 
index efbf55b..677d83e 100644 (file)
@@ -29,7 +29,6 @@ let arch = "armv7"
         "libc/raise.c",
         "aboot.c",
         "board_panda.c",
-        "boot.c",
         "misc.c"
         ]
 
@@ -97,9 +96,12 @@ in [
             Str "-g", Str "-O2", Str "-Wall", Str "-Werror",
             Str "-o", Out "tools" "/bin/usbboot",
             Str "-I/usr/include/libusb-1.0",
+            Str "-I/usr/include/freebsd",
             Str "-I", NoDep SrcTree "src" "include",
+            Str "-I", NoDep BuildTree "root" "/",
             In SrcTree "src" "usbboot.c",
-            In SrcTree "src" "usb-linux.c",
             In BuildTree arch "2ndstage.o",
-            Str "-lusb-1.0" ])
+            Str "-lusb-1.0", Str "-lelf-freebsd", Str "-lrt",
+            Dep BuildTree arch $ mackerelDevHdrPath "omap/omap44xx_boot"
+          ])
 ]
index 46327d2..d2d29a5 100644 (file)
 #include <omap4/omap4_rom.h>
 #include "protocol.h"
 
-#define WITH_MEMORY_TEST       0
-#define WITH_FLASH_BOOT                0
-#define WITH_SIGNATURE_CHECK   0
-
 #define min(a,b) ( ((a) < (b)) ? (a) : (b) )
 
-#if WITH_MEMORY_TEST
-void memtest(void *x, unsigned count) {
-       unsigned *w = x;
-       unsigned n;
-       count /= 4;
-
-       printf("memtest write - %d\n",count);
-       for (n = 0; n < count; n++) {
-               unsigned chk = 0xa5a5a5a5 ^ n;
-               w[n] = chk;
-       }
-       printf("memtest read\n");
-       for (n = 0; n < count; n++) {
-               unsigned chk = 0xa5a5a5a5 ^ n;
-               if (w[n] != chk) {
-                       printf("ERROR @ %x (%x != %x)\n", 
-                               (unsigned) (w+n), w[n], chk);
-                       return;
-               }
-       }
-       printf("OK!\n");
-}
-#endif
-
 struct usb usb;
 
 unsigned cfg_machine_type = 2791;
 
-#if 0
-static void dump(unsigned char *address, unsigned len, char *text)
-{
-       unsigned i, j, l;
-
-       printf("\n\n%s\n", text);
-
-       l = len % 16;
-       if (l)
-               l = len + 16 - l;
-       else
-               l = len;
-
-       for (i = 0; i < l; i += 16) {
-
-               printf("%08X: ", address + i);
-
-               for (j = i; j < i + 16; j ++ ) {
-                       if (j < l)
-                               printf("%02X ", address[j]);
-                       else
-                               printf("   ");
-                       if (j == i + 8)
-                               printf ("-");
-               }
-
-               printf(" | ");
-
-               for (j = i; j < i + 16; j ++ ) {
-                       if (j < l)
-                               printf("%c", address[j] >= 32 ? address[j] : '.');
-                       else
-                               printf(" ");
-                       if (j == i + 8)
-                               printf ("-");
-               }
-
-               printf("\n");
-       }
-}
-#endif
-
-#if WITH_SIGNATURE_CHECK
-unsigned call_trusted(unsigned appid, unsigned procid, unsigned flag, void *args);
-
-int verify(void *data, unsigned len, void *signature, unsigned rights) {
-       struct {
-               unsigned count;
-               void *data;
-               unsigned len;
-               void *signature;
-               unsigned rights;
-       } args;
-       args.count = 4;
-       args.data = data;
-       args.len = len;
-       args.signature = signature;
-       args.rights = rights;
-       return call_trusted(12, 0, 0, &args);
-}
-#endif
-
-#if WITH_FLASH_BOOT
-int load_image(unsigned device, unsigned start, unsigned count, void *data)
-{
-       int (*rom_get_mem_driver)(struct mem_driver **io, u32 type);
-       struct mem_driver *io = 0;
-       struct mem_device local_md_device, *md = 0;
-       struct read_desc rd;
-       u16 options;
-       u32 base;
-       int z;
-
-       if (get_omap_rev() >= OMAP_4460_ES1_DOT_0)
-               base = PUBLIC_API_BASE_4460;
-       else
-               base = PUBLIC_API_BASE_4430;
-
-       rom_get_mem_driver = API(base + PUBLIC_GET_DRIVER_MEM_OFFSET);
-       z = rom_get_mem_driver(&io, device);
-       if (z)
-               return -1;
-
-       md = &local_md_device;
-       memset(md, 0, sizeof(struct mem_device));
-       options = 0; // 1 = init phoenix pmic?
-       md->initialized   = 0;
-       md->device_type   = device;
-       md->xip_device    = 0;
-       md->search_size   = 0;
-       md->base_address  = 0;
-       md->hs_toc_mask   = 0;
-       md->gp_toc_mask   = 0;
-       md->boot_options  = &options;
-       md->device_data   = (void*) 0x80000000;
-       memset(md->device_data, 0, 2500);
-
-       z = io->init(md);
-       if (z)
-               return -1;
-
-       rd.sector_start = start;
-       rd.sector_count = count;
-       rd.destination = data;
-       z = io->read(md, &rd);
-
-       return 0;
-}
-
-int load_from_mmc(unsigned device, unsigned *len)
-{
-       load_image(device, 512, 512, (void*) CONFIG_ADDR_DOWNLOAD);
-       *len = 256 * 1024;
-       return 0;
-}
-#endif
-
 int load_from_usb(unsigned *_len, unsigned *_addr)
 {
        u32 len, addr, msg;
@@ -234,11 +89,19 @@ int load_from_usb(unsigned *_len, unsigned *_addr)
        return 0;
 }
 
-void aboot(unsigned *info)
+static void __attribute__((noreturn))
+boot_image(unsigned machtype, unsigned image, unsigned len)
 {
-#if WITH_FLASH_BOOT
-       unsigned bootdevice;
-#endif
+       void (*entry)(unsigned, unsigned, unsigned);
+
+       printf("jumping to 0x%x...\n", image);
+       entry = (void*)image;
+       entry(0, cfg_machine_type, CONFIG_ADDR_ATAGS);
+       for (;;);
+}
+
+void __attribute__((noreturn))
+aboot(unsigned *info) {
     unsigned n, len, addr = CONFIG_ADDR_DOWNLOAD;
 
        board_mux_init();
@@ -254,58 +117,11 @@ void aboot(unsigned *info)
 
        serial_puts("\n[ aboot second-stage loader ]\n\n");
 
-       printf("MSV=%08x\n",*((unsigned*) 0x4A00213C));
-
-#if WITH_MEMORY_TEST
-       printf("Memory test, pass 1");
-       memtest(0x82000000, 8*1024*1024);
-       printf("Memory test, pass 2");
-       memtest(0xA0208000, 8*1024*1024);
-#endif
-
-       printf("Memory test complete\n");
-#if !WITH_FLASH_BOOT
        n = load_from_usb(&len, &addr);
-#else
-       if (info) {
-               bootdevice = info[2] & 0xFF;
-       } else {
-               bootdevice = 0x45;
-       }
-
-       switch (bootdevice) {
-       case 0x45: /* USB */
-               serial_puts("boot device: USB\n\n");
-               n = load_from_usb(&len);
-               break;
-       case 0x05:
-       case 0x06:
-               serial_puts("boot device: MMC\n\n");
-               n = load_from_mmc(bootdevice, &len);
-               break;
-       default:
-               serial_puts("boot device: unknown\n");
-               for (;;) ;
-       }
-#endif
        printf("load complete\n");
        if (n) {
                serial_puts("*** IO ERROR ***\n");
        } else {
-#if WITH_SIGNATURE_CHECK
-               void *data = (void*) (addr);
-               void *sign = (void*) (addr + len - 280);
-               if ((len < 281) || (len > (32*1024*1024)))
-                       goto fail_verify;
-               len -= 280;
-
-               n = verify(data, len, sign, 2);
-               if (n != 0) {
-               fail_verify:
-                       serial_puts("*** SIGNATURE VERIFICATION FAILED ***\n");
-                       for (;;) ;
-               }
-#endif
                printf("starting!\n");
                boot_image(cfg_machine_type, addr, len);
                serial_puts("*** BOOT FAILED ***\n");
diff --git a/tools/usbboot/boot.c b/tools/usbboot/boot.c
deleted file mode 100644 (file)
index 56d998c..0000000
+++ /dev/null
@@ -1,129 +0,0 @@
-/*
- * Copyright (C) 2011 The Android Open Source Project
- * All rights reserved.
- *
- * Redistribution and use in source and binary forms, with or without
- * modification, are permitted provided that the following conditions
- * are met:
- *  * Redistributions of source code must retain the above copyright
- *    notice, this list of conditions and the following disclaimer.
- *  * Redistributions in binary form must reproduce the above copyright
- *    notice, this list of conditions and the following disclaimer in
- *    the documentation and/or other materials provided with the 
- *    distribution.
- *
- * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
- * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
- * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
- * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE
- * COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
- * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
- * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS
- * OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED 
- * AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
- * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT
- * OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
- * SUCH DAMAGE.
- */
-
-#include <aboot/aboot.h>
-#include <aboot/bootimg.h>
-
-static void boot_image_android(unsigned machtype, unsigned image, unsigned len)
-{
-       void (*entry)(unsigned, unsigned, unsigned);
-       struct boot_img_hdr *hdr = (void*) image;
-       unsigned psize, pmask, kactual;
-       unsigned *tag = (void*) CONFIG_ADDR_ATAGS;
-
-       if (len < sizeof(*hdr))
-               return;
-
-       psize = hdr->page_size;
-       pmask = hdr->page_size - 1;
-
-       if ((psize != 1024) && (psize != 2048) && (psize != 4096))
-               return;
-
-       if (len < psize)
-               return;
-
-       kactual = (hdr->kernel_size + pmask) & (~pmask);
-
-       /* CORE */
-       *tag++ = 2;
-       *tag++ = 0x54410001;
-
-       if (hdr->ramdisk_size) {
-               *tag++ = 4;
-               *tag++ = 0x54420005;
-               *tag++ = image + psize + kactual;
-               *tag++ = hdr->ramdisk_size;
-       }
-
-       if (hdr->cmdline && hdr->cmdline[0]) {
-               /* include terminating 0 and word align */
-               unsigned n = (strlen((void*) hdr->cmdline) + 4) & (~3);
-               *tag++ = (n / 4) + 2;
-               *tag++ = 0x54410009;
-               memcpy(tag, hdr->cmdline, n);
-               tag += (n / 4);
-       }
-
-       /* END */
-       *tag++ = 0;
-       *tag++ = 0;
-
-       /* need to move the kernel away from the ramdisk-in-bootimg
-        * otherwise the ramdisk gets clobbered before it can be
-        * uncompressed.
-        */
-       memcpy((void*) CONFIG_ADDR_KERNEL, (void *)image + psize, kactual);
-       entry = (void*) CONFIG_ADDR_KERNEL;
-
-       printf("kernel:   0x%x (%d bytes)\n",
-              CONFIG_ADDR_KERNEL, hdr->kernel_size);
-       printf("ramdisk:  0x%x (%d bytes)\n",
-              image + psize + kactual, hdr->ramdisk_size);
-       printf("atags:    0x%x\n", CONFIG_ADDR_ATAGS);
-       printf("cmdline:  %s\n", hdr->cmdline);
-       printf("machtype: %d\n", machtype);
-
-       serial_puts("\nbooting...\n");
-       entry(0, machtype, CONFIG_ADDR_ATAGS);
-
-       serial_puts("\nreturned from kernel?\n");
-       for (;;) ;
-}
-
-static void __attribute__((noreturn)) boot_image_binary(unsigned machtype, unsigned image, unsigned len)
-{
-       void (*entry)(unsigned, unsigned, unsigned);
-
-       printf("jumping to 0x%x...\n", image);
-       entry = (void*)image;
-       entry(0, cfg_machine_type, CONFIG_ADDR_ATAGS);
-       for (;;);
-}
-
-void boot_image(unsigned machtype, unsigned image, unsigned len)
-{
-       unsigned n;
-       char *x = (void*) image;
-
-       /* is it android image ? */
-       for (n = 0; n < 8; n++)
-               if (x[n] != "ANDROID!"[n]) 
-                       break;
-       if (n == 8)
-               return boot_image_android(machtype, image, len);
-
-       /* may be, is it uImage ? */
-       
-       /* .... */
-
-       /* no, plain binary */
-       boot_image_binary(machtype, image, len);
-
-       return /* :) */;
-}
index b47f8ac..61338b9 100644 (file)
@@ -66,7 +66,6 @@ extern void prcm_init(void);
 extern void gpmc_init(void);
 extern void board_late_init(void);
 extern void prcm_init(void);
-extern void boot_image(unsigned machtype, unsigned image, unsigned len);
 extern void configure_core_dpll_no_lock(void);
 extern void lock_core_dpll_shadow(void);
 
diff --git a/tools/usbboot/include/omap4/boot.h b/tools/usbboot/include/omap4/boot.h
new file mode 100644 (file)
index 0000000..deccad0
--- /dev/null
@@ -0,0 +1,50 @@
+#ifndef __OMAP44XX_BOOT
+#define __OMAP44XX_BOOT
+
+#define OMAP44xx_bootmsg_periphboot 0xF0030002
+#define OMAP44xx_bootmsg_getid      0xF0030003
+#define OMAP44xx_subblock_id        0x01
+#define OMAP44xx_subblock_checksum  0x15
+#define OMAP44xx_ch_enabled         0x07
+#define OMAP44xx_ch_disabled        0x17
+#define OMAP44xx_vid                0x0451
+#define OMAP44xx_pid                0xd010
+#define OMAP44xx_bulk_out           0x01
+#define OMAP44xx_bulk_in            0x81
+
+struct omap44xx_subblock_header {
+    uint8_t subblock_id;
+    uint8_t subblock_size;
+    uint8_t fixed;
+} __attribute__((packed));
+
+struct omap44xx_subblock_id {
+    uint8_t subblock_id;
+    uint8_t subblock_size;
+    uint8_t fixed;
+    uint8_t device[2];
+    uint8_t ch;
+    uint8_t rom_revision;
+} __attribute__((packed));
+
+struct omap44xx_subblock_checksum {
+    uint8_t subblock_id;
+    uint8_t subblock_size;
+    uint8_t fixed;
+    uint8_t rom_crc[4];
+    uint8_t unused[4];
+} __attribute__((packed));
+
+struct omap44xx_id {
+    uint8_t items;
+
+    struct omap44xx_subblock_id id;
+
+    uint8_t reserved1[4];
+    uint8_t reserved2[23];
+    uint8_t reserved3[35];
+
+    struct omap44xx_subblock_checksum checksum;
+} __attribute__((packed));
+
+#endif /* __OMAP44XX_BOOT */
index e3492a1..131e39a 100644 (file)
@@ -1,6 +1,14 @@
 #include <stdio.h>
+#include <stdlib.h>
+
 #include <libusb.h>
 
+static void
+fail_usb(const char *str, int e) {
+       fprintf(stderr, "%s: %s\n", str, libusb_strerror(e));
+    exit(EXIT_FAILURE);
+}
+
 static struct libusb_context *ctx = NULL;
 
 int linux_usb_init(void)
@@ -8,8 +16,7 @@ int linux_usb_init(void)
        int r;
 
        r = libusb_init(&ctx);
-       if (r != 0)
-               return r;
+    if(r) fail_usb("libusb_init", r);
        libusb_set_debug(ctx,0x1);
     return 0;
 }
@@ -27,13 +34,12 @@ int linux_usb_open(unsigned vendor, unsigned device, void **result)
 
        dev = libusb_open_device_with_vid_pid(ctx, vendor, device);
        if (dev) {
-               (void)libusb_detach_kernel_driver(dev, 0);
+               r= libusb_set_auto_detach_kernel_driver(dev, 1);
+        if(r) fail_usb("libusb_detach_kernel_driver", r);
                r = libusb_set_configuration(dev, 1);
-               if (r != 0)
-                       return r;
+        if(r) fail_usb("libusb_set_configuration", r);
                r = libusb_claim_interface(dev, 0);
-               if (r != 0)
-                       return r;
+        if(r) fail_usb("libusb_claim_interface", r);
        }
        *result = dev;
        return 0;
index bfdc7a8..af80de3 100644 (file)
  * SUCH DAMAGE.
  */
 
-#include <stdio.h>
-#include <stdlib.h>
-#include <unistd.h>
 #include <sys/stat.h>
-#include <stdint.h>
+
+#include <assert.h>
 #include <inttypes.h>
 #include <fcntl.h>
+#include <stdarg.h>
+#include <stdint.h>
+#include <stdio.h>
+#include <stdlib.h>
 #include <string.h>
+#include <time.h>
+#include <unistd.h>
+
+#include <libelf.h>
+#include <libusb.h>
+
+/* XXX - make this work! */
+#if 0
+#include <armv7/include/dev/omap/omap44xx_boot_dev.h>
+#endif
 
 // #include "usb.h"
-#include <usb-linux.h>
+//#include <usb-linux.h>
+#include <omap4/boot.h>
 #include <protocol.h>
 
 #define min(a,b) (((a) < (b)) ? (a): (b))
 
-static int print_error(int r)
-{
-       fprintf(stderr, "failed: %s\n", strerror(r));
-       return r;
+void
+fail(const char *fmt, ...) {
+    va_list ap;
+    va_start(ap, fmt);
+    vfprintf(stderr, fmt, ap);
+    va_end(ap);
+    exit(EXIT_FAILURE);
 }
 
-#define CHECK_ERROR(r) do { if (r) { return print_error((r)); } } while(0)
+static void
+fail_usb(const char *str, int e) {
+    fprintf(stderr, "%s: %s\n", str, libusb_strerror(e));
+    exit(EXIT_FAILURE);
+}
+
+static void
+fail_errno(const char *fmt, ...) {
+    char s[1024];
 
-#define USBBOOT_MAX_CHUNKS 20
+    va_list ap;
+    va_start(ap, fmt);
+    vsnprintf(s, 1024, fmt, ap);
+    va_end(ap);
+
+    perror(s);
+    exit(EXIT_FAILURE);
+}
+
+static void
+fail_elf(const char *s) {
+    fprintf(stderr, "%s: %s\n", s, elf_errmsg(elf_errno()));
+    exit(EXIT_FAILURE);
+}
 
 struct usb_load_chunk {
-       uint32_t address;
-       void *data;
-       unsigned size;
+    uint32_t address;
+    void *data;
+    unsigned size;
 };
 
-int usb_boot(usb_handle usb, struct usb_load_chunk *chunks)
-{
-       uint32_t msg_boot = 0xF0030002;
-       uint32_t msg_getid = 0xF0030003;
-       uint32_t msg;
-       uint8_t id[81];
-       int i;
-       int r;
-
-#define OFF_CHIP       0x04
-#define OFF_ID         0x0F
-#define OFF_MPKH       0x26
-       memset(id, 0xee, 81);
-       fprintf(stderr,"reading ASIC ID\n");
-       r = linux_usb_write(usb, &msg_getid, sizeof(msg_getid));
-       CHECK_ERROR(r);
-
-       r = linux_usb_read(usb, id, sizeof(id));
-       CHECK_ERROR(r);
-
-       fprintf(stderr,"CHIP: %02x%02x\n", id[OFF_CHIP+0], id[OFF_CHIP+1]);
-       fprintf(stderr,"IDEN: ");
-       for (i = 0; i < 20; i++)
-               fprintf(stderr,"%02x", id[OFF_ID+i]);
-       fprintf(stderr,"\nMPKH: ");
-       for (i = 0; i < 32; i++)
-               fprintf(stderr,"%02x", id[OFF_MPKH+i]);
-       fprintf(stderr,"\nCRC0: %02x%02x%02x%02x\n",
-               id[73], id[74], id[75], id[76]);
-       fprintf(stderr,"CRC1: %02x%02x%02x%02x\n",
-               id[77], id[78], id[79], id[80]);
-
-       fprintf(stderr,"sending 2ndstage to target... %08x\n",msg_boot);
-       r = linux_usb_write(usb, &msg_boot, sizeof(msg_boot));
-       CHECK_ERROR(r);
-        usleep(1);
-       r = linux_usb_write(usb, &chunks[0].size, sizeof(chunks[0].size));
-       CHECK_ERROR(r);
-        usleep(1);
-       r = linux_usb_write(usb, chunks[0].data, chunks[0].size);
-       CHECK_ERROR(r);
-
-        // sleep to make stuff work
-        sleep(2);
-
-       msg = 0;
-       fprintf(stderr,"waiting for 2ndstage response...\n");
-       r = linux_usb_read(usb, &msg, sizeof(msg));
-       CHECK_ERROR(r);
-
-       fprintf(stderr, "response is %x\n", msg);
-       if (msg != ABOOT_IS_READY) {
-               fprintf(stderr,"unexpected 2ndstage response\n");
-               return -1;
-       }
-
-       sleep(1);
-
-       for (i = 1; chunks[i].address; i ++) {
-
-               if (i != 1)
-                       printf("\n");
-
-               fprintf(stderr, "sending size = %d, ", chunks[i].size);
-               r = linux_usb_write(usb, &chunks[i].size, sizeof(chunks[i].size));
-               CHECK_ERROR(r);
-
-               fprintf(stderr, "sending address = 0x%08X, ", chunks[i].address);
-               r = linux_usb_write(usb, &chunks[i].address, sizeof(chunks[i].address));
-               CHECK_ERROR(r);
-
-               fprintf(stderr, "sending image ");
-               for (;;) {
-                       r = linux_usb_write(usb, chunks[i].data, min(chunks[i].size, CHUNK_SIZE));
-                       CHECK_ERROR(r);
-                       if (chunks[i].size < CHUNK_SIZE)
-                               break;
-                       chunks[i].data += CHUNK_SIZE;
-                       chunks[i].size -= CHUNK_SIZE;
-                       usleep(1);
-               }
-               CHECK_ERROR(r);
-
-               sleep(1);
-       }
-
-       fprintf(stderr, "\nstarting chunk at 0x%"PRIx32"\n", chunks[1].address);
-       msg = ABOOT_NO_MORE_DATA;
-       r = linux_usb_write(usb, &msg, sizeof(msg));
-       CHECK_ERROR(r);
-       
-       return 0;
+extern unsigned char aboot_data[];
+extern unsigned aboot_size;
+
+static void
+usb_write(struct libusb_device_handle *usbdev, void *data, int len) {
+    while(len > 0) {
+        int transferred;
+        int r= libusb_bulk_transfer(usbdev, OMAP44xx_bulk_out,
+                                    data, min(len, CHUNK_SIZE),
+                                    &transferred, 0);
+        if(r < 0) fail_usb("libusb_bulk_transfer", r);
+
+        assert(transferred <= len);
+        len-=  transferred;
+        data+= transferred;
+    }
 }
 
+static void
+usb_read(struct libusb_device_handle *usbdev, void *data, int len) {
+    while(len > 0) {
+        int transferred;
+        int r= libusb_bulk_transfer(usbdev, OMAP44xx_bulk_in,
+                                    data, min(len, CHUNK_SIZE),
+                                    &transferred, 0);
+        if(r < 0) fail_usb("libusb_bulk_transfer", r);
+
+        assert(transferred <= len);
+        len-=  transferred;
+        data+= transferred;
+    }
+}
 
-void *load_file(const char *file, unsigned *sz)
-{
-       void *data;
-       struct stat s;
-       int fd;
-       
-       fd = open(file, O_RDONLY);
-       if (fd < 0)
-               goto fail;
-
-       if (fstat(fd, &s))
-               goto fail;
-       
-       data = malloc(s.st_size);
-       if (!data)
-               goto fail;
-       
-       if (read(fd, data, s.st_size) != s.st_size) {
-               free(data);
-               goto fail;
-       }
-       
-       close(fd);
-       *sz = s.st_size;
-       return data;
-       
-fail:
-       fprintf(stderr, "Cannot read file '%s'\n", file);
-       if (fd >= 0)
-               close(fd);
-       return 0;
+void
+send_word(libusb_device_handle *usb, uint32_t msg) {
+    usb_write(usb, &msg, sizeof(msg));
 }
 
-extern unsigned char aboot_data[];
-extern unsigned aboot_size;
+int
+usb_boot(libusb_device_handle *usb, void *image_data,
+         size_t image_size, uint32_t load_address) {
+    uint32_t msg;
+
+    fprintf(stderr,"Reading ASIC ID\n");
+    send_word(usb, OMAP44xx_bootmsg_getid);
+
+    struct omap44xx_id id;
+    usb_read(usb, &id, sizeof(id));
+
+    assert(id.items == 5);
+    assert(id.id.subblock_id = 0x01);
+    assert(id.checksum.subblock_id = 0x15);
+
+    printf("Chip reports itself to be an OMAP%02x%02x\n",
+           id.id.device[0], id.id.device[1]);
+
+    if(id.id.ch == OMAP44xx_ch_enabled)
+        printf("Configuration header (CH) loading enabled.\n");
+    else if(id.id.ch == OMAP44xx_ch_disabled)
+        printf("Configuration header (CH) loading disabled.\n");
+    else
+        printf("Unrecognised or corrupted CH setting: %02x\n", id.id.ch);
+
+    printf("ROM revision %02x\n", id.id.rom_revision);
+    printf("ROM CRC: %02x%02x%02x%02x\n",
+           id.checksum.rom_crc[0], id.checksum.rom_crc[1],
+           id.checksum.rom_crc[2], id.checksum.rom_crc[3]);
+
+    printf("Sending second stage bootloader... \n");
+    send_word(usb, OMAP44xx_bootmsg_periphboot);
+    usleep(1);
+    send_word(usb, aboot_size);
+    usleep(1);
+    usb_write(usb, aboot_data, aboot_size);
+
+    // sleep to make stuff work
+    sleep(1);
+
+    msg = 0;
+    printf("Waiting for second stage response...\n");
+    usb_read(usb, &msg, sizeof(msg));
+
+    printf("Response is \"%x\"\n", msg);
+    if (msg != ABOOT_IS_READY) fail("Unexpected second stage response\n");
+
+    usleep(500);
+
+    printf("Sending size = %zu, ", image_size);
+    send_word(usb, image_size);
+
+    printf("Sending address = 0x%08X, ", load_address);
+    send_word(usb, load_address);
+
+    struct timespec start, end;
+    printf("Sending image... ");
+    fflush(stdout);
+    if(clock_gettime(CLOCK_REALTIME, &start)) fail_errno("clock_gettime");
+    usb_write(usb, image_data, image_size);
+    if(clock_gettime(CLOCK_REALTIME, &end)) fail_errno("clock_gettime");
+    printf("done.\n");
+
+    double tstart= start.tv_sec + start.tv_nsec * 1e-9;
+    double tend=   end.tv_sec   + end.tv_nsec   * 1e-9;
+    double elapsed= tend - tstart;
+
+    printf("Transferred %zuB in %.2fs at %.2fMB/s\n",
+           image_size, elapsed, (image_size / elapsed) / 1024 / 1024);
+
+    sleep(1);
+
+    printf("Starting chunk at 0x%"PRIx32"\n", load_address);
+    send_word(usb, ABOOT_NO_MORE_DATA);
+    
+    return 0;
+}
+
+void *
+load_file(const char *file, size_t *sz, uint32_t *load_address) {
+    int fd= open(file, O_RDONLY);
+    if(fd < 0) fail_errno("open");
+
+    struct stat stat;
+    if(fstat(fd, &stat)) fail_errno("fstat");
+    size_t elfsize= stat.st_size;
+
+    void *elfdata= malloc(elfsize);
+    if(!elfdata) fail_errno("malloc");
+
+    /* Read the raw file data. */
+    {
+        size_t to_read= elfsize;
+        do {
+            size_t bytes_read= read(fd, elfdata, to_read);
+            if(bytes_read < 0) fail_errno("read");
+            assert(bytes_read <= to_read);
+            to_read -= bytes_read;
+        } while(to_read > 0);
+    }
+
+    Elf *elf= elf_memory(elfdata, elfsize);
+    if(!elf) fail_elf("elf_begin");
+
+    const char *elf_ident= elf_getident(elf, NULL);
+    if(!elf_ident) fail_elf("elf_getident");
+
+    if(elf_ident[EI_CLASS] != ELFCLASS32 ||
+       elf_ident[EI_DATA] != ELFDATA2LSB) {
+        fail("Not a 32-bit little-endian image.\n");
+    }
+
+    Elf32_Ehdr *ehdr= elf32_getehdr(elf);
+    if(!ehdr) fail_elf("elf32_getehdr");
+
+    if(ehdr->e_type != ET_EXEC) fail("Not an executable.\n");
+    if(ehdr->e_machine != EM_ARM) fail("Not an ARM binary.\n");
+
+    if(ehdr->e_phnum == 0) fail("No loadable segment.\n");
+    if(ehdr->e_phnum  > 1) fail("More than one loadable segment.\n");
+
+    Elf32_Phdr *phdr= elf32_getphdr(elf);
+    if(!phdr) fail_elf("elf32_getphdr");
+
+    printf("Loadable segment at offset %08x, size %u\n",
+           phdr->p_offset, phdr->p_filesz);
+    printf("Load address %08x, loaded size %u\n",
+           phdr->p_vaddr, phdr->p_memsz);
+
+    void *image_base= elfdata + phdr->p_offset;
+    *sz= phdr->p_filesz;
+    *load_address= phdr->p_vaddr;
+
+    if(elf_end(elf)) fail_elf("elf_end");
+
+    return image_base;
+}
 
 int main(int argc, char **argv)
 {
-       usb_handle usb;
-       int once = 1, i;
-       int r;
-       struct usb_load_chunk chunks[USBBOOT_MAX_CHUNKS], *current;
-       char *p;
-       char *aboot_cmdline = "--aboot=";
-       int aboot_cmdline_sz = strlen(aboot_cmdline);
-
-       memset(chunks, 0, sizeof(chunks));
-
-       chunks[ 0 ].data = aboot_data;
-       chunks[ 0 ].size = aboot_size;
-
-       if (argc < 2) {
-               fprintf(stderr,"usage: usbboot [ <2ndstage> ] <image>\n");
-               return 0;
-       }
-
-       for (i = 1, current = chunks + 1;
-            i < argc && current - chunks < USBBOOT_MAX_CHUNKS;
-            i ++) {
-
-               /* check if argument is 2nd stage bootloader name */
-               if (strcmp(argv[i], "-a") == 0) {
-                       chunks[0].data = load_file(argv[i + 1], &chunks[0].size);
-                       i++;
-                       if (chunks[0].data == NULL)
-                               break;
-                       continue;
-               }
-
-               if (strncmp(argv[i], aboot_cmdline, aboot_cmdline_sz) == 0) {
-                       chunks[0].data = load_file(argv[i] + aboot_cmdline_sz, &chunks[0].size);
-                       if (chunks[0].data == NULL)
-                               break;
-                       continue;
-               }
-                       
-               p = strchr(argv[i], '=');
-               if (p == NULL)
-                       p = strchr(argv[i], ':');
-               if (p == NULL) {
-                       current->address = 0x82000000;
-                       fprintf(stderr, "Warning: using %x for '%s'\n", current->address, argv[i]);
-                       p = argv[i];
-               }
-               else {
-                       *p = '\0';
-                       current->address = strtoul(argv[i], NULL, 0);
-                       p++;    /* skip the ':' or '=' */
-               }
-               current->data = load_file(p, &current->size);
-               if (current->data == NULL)
-                       break;
-               current ++;
-       }
-
-       r = linux_usb_init();
-       CHECK_ERROR(r);
-
-       for (i = 0; i < USBBOOT_MAX_CHUNKS; i ++) {
-               if (i && !chunks[i].address)
-                       break;
-               printf("Chunk %d:\n", i);
-               printf("\taddress = 0x%08X\n", chunks[i].address);
-               printf("\tdata    = %p\n", chunks[i].data);
-               printf("\tsize    = %d\n", chunks[i].size);
-       }
-
-       for (;;) {
-               r = linux_usb_open(0x0451, 0xd010, &usb);
-               if (r == 0 && usb) {
-                       r = usb_boot(usb, chunks);
-                       linux_usb_close(usb);
-                       break;
-               }
-               if (once) {
-                       once = 0;
-                       fprintf(stderr,"waiting for OMAP44xx device...\n");
-               }
-               usleep(250);
-       }
-
-       linux_usb_fini();
-
-       return r;
+    struct libusb_context *usb;
+    struct libusb_device_handle *usbdev;
+    void *image_data;
+    size_t image_size;
+    uint32_t load_address;
+    int r;
+
+    if(elf_version(EV_CURRENT) == EV_NONE)
+        fail("ELF library version out of date");;
+
+    if (argc < 2)fail("usage: %s <image>\n", argv[0]);
+    image_data= load_file(argv[1], &image_size, &load_address);
+
+    r = libusb_init(&usb);
+    if(r) fail_usb("libusb_init", r);
+    libusb_set_debug(usb, LIBUSB_LOG_LEVEL_WARNING);
+
+    int once= 1;
+    for (;;) {
+        usbdev= libusb_open_device_with_vid_pid(usb,
+                    OMAP44xx_vid, OMAP44xx_pid);
+        if(usbdev) {
+            r= libusb_reset_device(usbdev);
+            if(r) fail_usb("libusb_reset_device", r);
+
+            r= libusb_set_auto_detach_kernel_driver(usbdev, 1);
+            if(r) fail_usb("libusb_detach_kernel_driver", r);
+
+            r = libusb_set_configuration(usbdev, 1);
+            if(r) fail_usb("libusb_set_configuration", r);
+
+            r = libusb_claim_interface(usbdev, 0);
+            if(r) fail_usb("libusb_claim_interface", r);
+
+            struct libusb_device *dev= libusb_get_device(usbdev);
+            int speed= libusb_get_device_speed(dev);
+            if(speed < 0) fail_usb("libusb_get_device_speed", speed);
+            printf("Connected at ");
+            switch(speed) {
+                case LIBUSB_SPEED_LOW:
+                    printf("1.5Mb/s\n");
+                    break;
+                case LIBUSB_SPEED_FULL:
+                    printf("12Mb/s.\n");
+                    break;
+                case LIBUSB_SPEED_HIGH:
+                    printf("480Mb/s.\n");
+                    break;
+                case LIBUSB_SPEED_SUPER:
+                    printf("5000Mb/s.\n");
+                    break;
+                default:
+                    printf("unknown speed.\n");
+                    break;
+            }
+        }
+
+        if (r == 0 && usbdev) {
+            r = usb_boot(usbdev, image_data, image_size, load_address);
+            libusb_release_interface(usbdev, 0);
+            libusb_close(usbdev);
+            break;
+        }
+
+        if (once) {
+            once = 0;
+            fprintf(stderr,"Waiting for OMAP44xx device...\n");
+        }
+
+        usleep(250);
+    }
+
+    libusb_exit(usb);
+
+    return r;
 }