1/*
2 * Copyright (C) 2010 The Android Open Source Project
3 * All rights reserved.
4 *
5 * Redistribution and use in source and binary forms, with or without
6 * modification, are permitted provided that the following conditions
7 * are met:
8 *  * Redistributions of source code must retain the above copyright
9 *    notice, this list of conditions and the following disclaimer.
10 *  * Redistributions in binary form must reproduce the above copyright
11 *    notice, this list of conditions and the following disclaimer in
12 *    the documentation and/or other materials provided with the
13 *    distribution.
14 *
15 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
16 * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
17 * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
18 * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE
19 * COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
20 * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
21 * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS
22 * OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED
23 * AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
24 * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT
25 * OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
26 * SUCH DAMAGE.
27 */
28
29#include <sys/stat.h>
30
31#include <assert.h>
32#include <inttypes.h>
33#include <fcntl.h>
34#include <stdarg.h>
35#include <stdint.h>
36#include <stdio.h>
37#include <stdlib.h>
38#include <string.h>
39#include <time.h>
40#include <unistd.h>
41
42#include <libelf.h>
43#include <libusb.h>
44
45/* XXX - make this work! */
46#if 0
47#include <armv7/include/dev/omap/omap44xx_boot_dev.h>
48#endif
49
50// #include "usb.h"
51//#include <usb-linux.h>
52#include <omap4/boot.h>
53#include <protocol.h>
54
55#define min(a,b) (((a) < (b)) ? (a): (b))
56
57void
58fail(const char *fmt, ...) {
59    va_list ap;
60    va_start(ap, fmt);
61    vfprintf(stderr, fmt, ap);
62    va_end(ap);
63    exit(EXIT_FAILURE);
64}
65
66static void
67fail_usb(const char *str, int e) {
68    fprintf(stderr, "%s: %s\n", str, libusb_strerror(e));
69    exit(EXIT_FAILURE);
70}
71
72static void
73fail_errno(const char *fmt, ...) {
74    char s[1024];
75
76    va_list ap;
77    va_start(ap, fmt);
78    vsnprintf(s, 1024, fmt, ap);
79    va_end(ap);
80
81    perror(s);
82    exit(EXIT_FAILURE);
83}
84
85static void
86fail_elf(const char *s) {
87    fprintf(stderr, "%s: %s\n", s, elf_errmsg(elf_errno()));
88    exit(EXIT_FAILURE);
89}
90
91struct usb_load_chunk {
92    uint32_t address;
93    void *data;
94    unsigned size;
95};
96
97extern unsigned char aboot_data[];
98extern unsigned aboot_size;
99
100static void
101usb_write(struct libusb_device_handle *usbdev, void *data, int len) {
102    while(len > 0) {
103        int transferred;
104        int r= libusb_bulk_transfer(usbdev, OMAP44xx_bulk_out,
105                                    data, len, &transferred, 0);
106        if(r < 0) fail_usb("libusb_bulk_transfer", r);
107
108        assert(transferred <= len);
109        len-=  transferred;
110        data+= transferred;
111    }
112}
113
114static int
115usb_read_nofail(struct libusb_device_handle *usbdev, void *data, int len,
116                int timeout) {
117    while(len > 0) {
118        int transferred;
119        int r= libusb_bulk_transfer(usbdev, OMAP44xx_bulk_in,
120                                    data, len, &transferred, timeout);
121        if(r < 0) return r;
122
123        assert(transferred <= len);
124        len-=  transferred;
125        data+= transferred;
126    }
127
128    return 0;
129}
130
131static void
132usb_read(struct libusb_device_handle *usbdev, void *data, int len) {
133    int r= usb_read_nofail(usbdev, data, len, 0);
134    if(r < 0) fail_usb("libusb_bulk_transfer", r);
135}
136
137void
138send_word(libusb_device_handle *usb, uint32_t msg) {
139    usb_write(usb, &msg, sizeof(msg));
140}
141
142uint32_t
143read_word(libusb_device_handle *usb) {
144    uint32_t msg;
145    usb_read(usb, &msg, sizeof(msg));
146    return msg;
147}
148
149#define READ_TIMEOUT 1000
150
151int
152usb_boot(libusb_device_handle *usb, void *image_data,
153         size_t image_size, uint32_t load_address, uint32_t entry_point) {
154    uint32_t msg;
155
156    printf("Reading ASIC ID\n");
157    send_word(usb, OMAP44xx_bootmsg_getid);
158
159    struct omap44xx_id id;
160    int r= usb_read_nofail(usb, &id, sizeof(id), READ_TIMEOUT);
161    if(r == LIBUSB_ERROR_TIMEOUT) {
162        fail("Timed out while reading ASID ID.\n"
163             "This probably means the Pandaboard has hung in the\n"
164             "ROM bootloader - try a hard reset.\n");
165    }
166    else if(r < 0) fail_usb("libusb_bulk_transfer", r);
167
168    assert(id.items == 5);
169    assert(id.id.subblock_id == 0x01);
170    assert(id.checksum.subblock_id == 0x15);
171
172    printf("Chip reports itself to be an OMAP%02x%02x\n",
173           id.id.device[0], id.id.device[1]);
174
175    if(id.id.ch == OMAP44xx_ch_enabled)
176        printf("Configuration header (CH) loading enabled.\n");
177    else if(id.id.ch == OMAP44xx_ch_disabled)
178        printf("Configuration header (CH) loading disabled.\n");
179    else
180        printf("Unrecognised or corrupted CH setting: %02x\n", id.id.ch);
181
182    printf("ROM revision %02x\n", id.id.rom_revision);
183    printf("ROM CRC: %02x%02x%02x%02x\n",
184           id.checksum.rom_crc[0], id.checksum.rom_crc[1],
185           id.checksum.rom_crc[2], id.checksum.rom_crc[3]);
186
187    printf("Sending second stage bootloader... \n");
188    send_word(usb, OMAP44xx_bootmsg_periphboot);
189    usleep(1); /* The ROM code is slow. */
190    send_word(usb, aboot_size);
191    usleep(1);
192    usb_write(usb, aboot_data, aboot_size);
193
194    /* The bootloader takes a while, before it starts handling USB traffic.
195     * If we start talking to it too soon, it'll lock up. 100ms seems to do
196     * the trick. */
197    usleep(100 * 1000);
198
199    msg = 0;
200    printf("Waiting for second stage response...\n");
201    usb_read(usb, &msg, sizeof(msg));
202
203    printf("Response is \"%x\"\n", msg);
204    if (msg != ABOOT_IS_READY) fail("Unexpected second stage response\n");
205
206    printf("Sending size = %zu\n", image_size);
207    send_word(usb, image_size);
208
209    usleep(1);
210
211    printf("Sending load address = 0x%08x\n", load_address);
212    send_word(usb, load_address);
213
214    usleep(1);
215
216    printf("Sending entry point = 0x%08x\n", entry_point);
217    send_word(usb, entry_point);
218
219    struct timespec start, end;
220    printf("Sending image... ");
221    fflush(stdout);
222    if(clock_gettime(CLOCK_REALTIME, &start)) fail_errno("clock_gettime");
223
224    /* Send the image in chunks. */
225    size_t to_send= image_size;
226    void *send_ptr= image_data;
227    size_t chunk= 0;
228    while(to_send > 0) {
229        size_t this_chunk= min(to_send, CHUNK_SIZE);
230
231        /* Write a chunk. */
232        usb_write(usb, send_ptr, this_chunk);
233        to_send-=  this_chunk;
234        send_ptr+= this_chunk;
235
236        /* Wait for the acknowledgement. */
237        size_t ack_chunk= read_word(usb);
238        if(ack_chunk != chunk) {
239            fail("Chunk synchronisation failed after %zuB\n",
240                 image_size - to_send);
241        }
242        chunk++;
243    }
244
245    if(clock_gettime(CLOCK_REALTIME, &end)) fail_errno("clock_gettime");
246    printf("done.\n");
247
248    double tstart= start.tv_sec + start.tv_nsec * 1e-9;
249    double tend=   end.tv_sec   + end.tv_nsec   * 1e-9;
250    double elapsed= tend - tstart;
251
252    printf("Transferred %zuB in %.2fs at %.2fMB/s\n",
253           image_size, elapsed, (image_size / elapsed) / 1024 / 1024);
254
255    printf("Starting image at 0x%"PRIx32"\n", load_address);
256    send_word(usb, ABOOT_NO_MORE_DATA);
257
258    return 0;
259}
260
261void *
262load_file(const char *file, size_t *sz, uint32_t *load_address,
263          uint32_t *entry_point) {
264    int fd= open(file, O_RDONLY);
265    if(fd < 0) fail_errno("open");
266
267    struct stat stat;
268    if(fstat(fd, &stat)) fail_errno("fstat");
269    size_t elfsize= stat.st_size;
270
271    void *elfdata= malloc(elfsize);
272    if(!elfdata) fail_errno("malloc");
273
274    /* Read the raw file data. */
275    {
276        size_t to_read= elfsize;
277        do {
278            size_t bytes_read= read(fd, elfdata, to_read);
279            if(bytes_read < 0) fail_errno("read");
280            assert(bytes_read <= to_read);
281            to_read -= bytes_read;
282        } while(to_read > 0);
283    }
284
285    Elf *elf= elf_memory(elfdata, elfsize);
286    if(!elf) fail_elf("elf_begin");
287
288    const char *elf_ident= elf_getident(elf, NULL);
289    if(!elf_ident) fail_elf("elf_getident");
290
291    if(elf_ident[EI_CLASS] != ELFCLASS32 ||
292       elf_ident[EI_DATA] != ELFDATA2LSB) {
293        fail("Not a 32-bit little-endian image.\n");
294    }
295
296    Elf32_Ehdr *ehdr= elf32_getehdr(elf);
297    if(!ehdr) fail_elf("elf32_getehdr");
298
299    if(ehdr->e_type != ET_EXEC) fail("Not an executable.\n");
300    if(ehdr->e_machine != EM_ARM) fail("Not an ARM binary.\n");
301
302    if(ehdr->e_phnum == 0) fail("No loadable segment.\n");
303    if(ehdr->e_phnum  > 1) fail("More than one loadable segment.\n");
304
305    Elf32_Phdr *phdr= elf32_getphdr(elf);
306    if(!phdr) fail_elf("elf32_getphdr");
307
308    printf("Loadable segment at offset %08x, size %u\n",
309           phdr->p_offset, phdr->p_filesz);
310    printf("Load address %08x, loaded size %u\n",
311           phdr->p_vaddr, phdr->p_memsz);
312    printf("Entry point %08x\n",
313           ehdr->e_entry);
314
315    void *image_base= elfdata + phdr->p_offset;
316    *sz= phdr->p_filesz;
317    *load_address= phdr->p_vaddr;
318    *entry_point= ehdr->e_entry;
319
320    if(elf_end(elf)) fail_elf("elf_end");
321
322    return image_base;
323}
324
325int main(int argc, char **argv)
326{
327    struct libusb_context *usb;
328    struct libusb_device_handle *usbdev;
329    void *image_data;
330    size_t image_size;
331    uint32_t load_address, entry_point;
332    int r;
333
334    if(elf_version(EV_CURRENT) == EV_NONE)
335        fail("ELF library version out of date");;
336
337    if (argc < 2)fail("usage: %s <image>\n", argv[0]);
338    image_data= load_file(argv[1], &image_size, &load_address, &entry_point);
339
340    r = libusb_init(&usb);
341    if(r) fail_usb("libusb_init", r);
342    libusb_set_debug(usb, LIBUSB_LOG_LEVEL_WARNING);
343
344    int once= 1;
345    for (;;) {
346        usbdev= libusb_open_device_with_vid_pid(usb,
347                    OMAP44xx_vid, OMAP44xx_pid);
348        if(usbdev) {
349            r= libusb_reset_device(usbdev);
350            if(r) fail_usb("libusb_reset_device", r);
351
352            r= libusb_set_auto_detach_kernel_driver(usbdev, 1);
353            if(r) fail_usb("libusb_detach_kernel_driver", r);
354
355            r = libusb_set_configuration(usbdev, 1);
356            if(r) fail_usb("libusb_set_configuration", r);
357
358            r = libusb_claim_interface(usbdev, 0);
359            if(r) fail_usb("libusb_claim_interface", r);
360
361            struct libusb_device *dev= libusb_get_device(usbdev);
362            int speed= libusb_get_device_speed(dev);
363            if(speed < 0) fail_usb("libusb_get_device_speed", speed);
364            printf("Connected at ");
365            switch(speed) {
366                case LIBUSB_SPEED_LOW:
367                    printf("1.5Mb/s\n");
368                    break;
369                case LIBUSB_SPEED_FULL:
370                    printf("12Mb/s.\n");
371                    break;
372                case LIBUSB_SPEED_HIGH:
373                    printf("480Mb/s.\n");
374                    break;
375                case LIBUSB_SPEED_SUPER:
376                    printf("5000Mb/s.\n");
377                    break;
378                default:
379                    printf("unknown speed.\n");
380                    break;
381            }
382        }
383
384        if (r == 0 && usbdev) {
385            r = usb_boot(usbdev, image_data, image_size, load_address,
386                         entry_point);
387            libusb_release_interface(usbdev, 0);
388            libusb_close(usbdev);
389            break;
390        }
391
392        if (once) {
393            once = 0;
394            fprintf(stderr,"Waiting for OMAP44xx device...\n");
395        }
396
397        usleep(1000000);
398    }
399
400    libusb_exit(usb);
401
402    return r;
403}
404