diff options
Diffstat (limited to 'usbloader/usbloader.c')
-rw-r--r-- | usbloader/usbloader.c | 535 |
1 files changed, 0 insertions, 535 deletions
diff --git a/usbloader/usbloader.c b/usbloader/usbloader.c deleted file mode 100644 index ca7b4fa..0000000 --- a/usbloader/usbloader.c +++ /dev/null @@ -1,535 +0,0 @@ -/* - * Copyright (C) 2008 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 <boot/boot.h> -#include <boot/flash.h> -#include <boot/board.h> -#include <boot/usb.h> - -#include <boot/bootimg.h> -#include <boot/tags.h> - -#include <boot/gpio.h> - -#define VERSION "0.5" - -#define REQUIRE_SIGNATURE 0 - -#if REQUIRE_SIGNATURE -unsigned key_engineering[2 + 64 + 64] = { - 64,0x5b022317,-60769447,648742897,-13657530,585562035,591851935, - 454860199,-1809625305,1868200692,-155297008,-1688439840,-1333607631, - -483027189,-2051438457,1030069735,819944365,2133377257,-1978924214, - 2109678622,1974978919,-1811463608,765849268,1984092281,921245328, - -1055062768,1487475997,1209618652,871985152,-611178965,-2057018571, - 335641539,-1196119550,1550548229,-356223887,1909799623,1281016007, - 957001635,1005656532,-1027634024,-1576447610,-1917246637,589192795, - -1137386186,-1958135372,1933245070,64958951,-1820428322,-1577697840, - 1824253519,555306239,-1588272058,-1925773018,1205934271,-836584444, - -1140961670,-185198349,1293769947,37045923,1516796974,-297288651, - 651582073,-1337054592,-543971216,-1706823885,-1040652818,-594113104, - 260093481,-1277656496,56493468,1577037283,773995876,244894933, - -2075797967,783894843,880611008,-1433369702,380946504,-2081431477, - 1377832804,2089455451,-410001201,1245307237,-1228170341,-2062569137, - -1327614308,-1671042654,1242248660,-418803721,40890010,-1806767460, - -1468529145,-1058158532,1243817302,-527795003,175453645,-210650325, - -827053868,-571422860,886300657,2129677324,846504590,-1413102805, - -1287448511,-1991140134,56194155,1375685594,-129884114,1393568535, - -1098719620,-935279550,1717137954,-1782544741,272581921,-669183778, - 584824755,1434974827,-1122387971,-810584927,-2147338547,-937541680, - -313561073,5506366,-1594059648,-1744451574,1896015834,1496367069, - 1742853908,508461291,1905056764 -}; -#endif - -const char *get_fastboot_version(void) -{ - return VERSION; -} - -unsigned linux_type = 0; -unsigned linux_tags = 0; - -unsigned ramdisk_addr = 0x10400000; -unsigned ramdisk_size = 0; -unsigned kernel_addr = 0x10008000; -unsigned kernel_size = 0; - -static void fixup_tags(unsigned *tags, unsigned *out, const char *cmdline) -{ - unsigned *newtags = (unsigned *) 0x10004000; - unsigned *np = newtags; - unsigned n; - char *oldcmdline = ""; - - if(cmdline == 0) cmdline = ""; - - /* CORE */ - *np++ = 2; - *np++ = 0x54410001; - - if(tags != 0) { - while(*tags) { - if(tags[1] == 0x54410001) { - /* skip core tag */ - tags += tags[0]; - } else if((tags[1] == 0x54420005) && (ramdisk_size != 0)) { - /* skip ramdisk if we have one of our own */ - tags += tags[0]; - } else if((tags[1] == 0x54410009) && (cmdline[0])) { - /* skip existing cmdline so we can replace it */ - oldcmdline = (char*) (tags + 2); - tags += tags[0]; - } else { - /* copy any unknown tags */ - n = tags[0]; - while(n-- > 0) { - *np++ = *tags++; - } - } - } - } - - /* create a ramdisk tag if we need to */ - if(ramdisk_size) { - *np++ = 4; - *np++ = 0x54420005; - *np++ = ramdisk_addr; - *np++ = ramdisk_size; - } - - dprintf("cmdline: '%s'\n", oldcmdline); - dprintf("cmdline: '%s'\n", cmdline); - - /* create a cmdline tag if we need to */ - if(cmdline[0]) { - int len; - char *str = (char*) (np + 2); - - len = strlen(oldcmdline); - if(len) { - memcpy(str, oldcmdline, len); - str += len; - *str++ = ' '; - } - - len = strlen(cmdline); - memcpy(str, cmdline, len); - str += len; - *str++ = 0; - - /* length in words */ - len = ((str - ((char*) (np + 2))) + 3) / 4; - - dprintf("CMDLINE: '%s'\n", ((char*) (np + 2))); - - *np++ = 2 + len; - *np++ = 0x54410009; - - np += len; - } - - /* add footer tag */ - *np++ = 0; - *np++ = 0; - - /* copy it all back to the original tags area */ - while(newtags < np) { - *out++ = *newtags++; - } -} - -static char cmdline[BOOT_ARGS_SIZE]; - -static void boot_linux(void) -{ - unsigned *tags = (unsigned*) 0x10000100; - void (*entry)(unsigned,unsigned,unsigned) = (void*) kernel_addr; - - if(linux_type == 0) { - linux_type = board_machtype(); - } - - fixup_tags((unsigned*) linux_tags, tags, cmdline); - - entry(0, linux_type, tags); - - for(;;); -} - -/* convert a boot_image at kernel_addr into a kernel + ramdisk + tags */ -static int init_boot_linux(void) -{ - boot_img_hdr *hdr = (void*) kernel_addr; - unsigned page_mask = 2047; - unsigned kernel_actual; - unsigned ramdisk_actual; - unsigned second_actual; - - if((kernel_size < 2048) || memcmp(hdr->magic, BOOT_MAGIC, BOOT_MAGIC_SIZE)){ - dprintf("bootimg: bad header\n"); - return -1; - } - - if(hdr->page_size != 2048) { - dprintf("bootimg: invalid page size\n"); - return -1; - } - - kernel_actual = (hdr->kernel_size + page_mask) & (~page_mask); - ramdisk_actual = (hdr->ramdisk_size + page_mask) & (~page_mask); - second_actual = (hdr->second_size + page_mask) & (~page_mask); - - if(kernel_size != (kernel_actual + ramdisk_actual + second_actual + 2048)) { - dprintf("bootimg: invalid image size"); - return -1; - } - - /* XXX process commandline here */ - if(hdr->cmdline[0]){ - hdr->cmdline[BOOT_ARGS_SIZE - 1] = 0; - memcpy(cmdline, hdr->cmdline, BOOT_ARGS_SIZE); - } - - /* XXX how to validate addresses? */ - ramdisk_addr = hdr->ramdisk_addr; - ramdisk_size = hdr->ramdisk_size; - - kernel_addr = hdr->kernel_addr; - kernel_size = hdr->kernel_size; - - dprintf("bootimg: kernel addr=%x size=%x\n", - kernel_addr, kernel_size); - dprintf("bootimg: ramdisk addr=%x size=%x\n", - ramdisk_addr, ramdisk_size); - - memcpy((void*) ramdisk_addr, - hdr->magic + 2048 + kernel_actual, - ramdisk_size); - - memcpy((void*) kernel_addr, - hdr->magic + 2048, - kernel_size); - - return 0; -} - -static struct usb_endpoint *ep1in, *ep1out; -static struct usb_request *rx_req, *tx_req; -static unsigned rx_addr; -static unsigned rx_length; - -static char *cmdbuf; - -static void usb_rx_cmd_complete(struct usb_request *req, unsigned actual, int status); -static void usb_rx_data_complete(struct usb_request *req, unsigned actual, int status); - -static void rx_cmd(void) -{ - struct usb_request *req = rx_req; - req->buf = cmdbuf; - req->length = 4096; - req->complete = usb_rx_cmd_complete; - usb_queue_req(ep1out, req); -} - -static void rx_data(void) -{ - struct usb_request *req = rx_req; - req->buf = (void*) rx_addr; - req->length = (rx_length > 4096) ? 4096 : rx_length; - req->complete = usb_rx_data_complete; - usb_queue_req(ep1out, req); -} - -static void tx_status(const char *status) -{ - struct usb_request *req = tx_req; - int len = strlen(status); -// dprintf("tx_status('%s')\n", status); - memcpy(req->buf, status, len); - req->length = len; - req->complete = 0; - usb_queue_req(ep1in, req); -} - -static void usb_rx_data_complete(struct usb_request *req, unsigned actual, int status) -{ - if(status != 0) return; - - if(actual > rx_length) { - actual = rx_length; - } - - rx_addr += actual; - rx_length -= actual; - - if(rx_length > 0) { - rx_data(); - } else { - tx_status("OKAY"); - rx_cmd(); - } -} - -static unsigned hex2unsigned(char *x) -{ - unsigned n = 0; - - while(*x) { - switch(*x) { - case '0': case '1': case '2': case '3': case '4': - case '5': case '6': case '7': case '8': case '9': - n = (n << 4) | (*x - '0'); - break; - case 'a': case 'b': case 'c': - case 'd': case 'e': case 'f': - n = (n << 4) | (*x - 'a' + 10); - break; - case 'A': case 'B': case 'C': - case 'D': case 'E': case 'F': - n = (n << 4) | (*x - 'A' + 10); - break; - default: - return n; - } - x++; - } - - return n; -} - -static void num_to_hex8(unsigned n, char *out) -{ - static char tohex[16] = "0123456789abcdef"; - int i; - for(i = 7; i >= 0; i--) { - out[i] = tohex[n & 15]; - n >>= 4; - } - out[8] = 0; -} - -extern char serialno[]; - -static char signature[SIGNATURE_SIZE]; - -static void usb_rx_cmd_complete(struct usb_request *req, unsigned actual, int status) -{ - if(status != 0) return; - - if(actual > 4095) actual = 4095; - cmdbuf[actual] = 0; - - dprintf("\n> %s\n",cmdbuf); - -// dprintf("usb_rx_cmd_complete() '%s'\n", cmdbuf); - - if(memcmp(cmdbuf, "reboot", 6) == 0) { - tx_status("OKAY"); - rx_cmd(); - mdelay(100); - board_reboot(); - } -#if 0 - if(memcmp(cmdbuf, "debug:", 6) == 0) { - void debug(char *cmd, char *resp); - memcpy(cmdbuf, "OKAY", 5); - tx_status(cmdbuf); - rx_cmd(); - mdelay(5000); - dprintf("NOW!\n"); - debug(cmdbuf + 6, cmdbuf + 4); - return; - } -#endif - if(memcmp(cmdbuf, "getvar:", 7) == 0) { - char response[64]; - strcpy(response,"OKAY"); - - if(!strcmp(cmdbuf + 7, "version")) { - strcpy(response + 4, VERSION); - } else if(!strcmp(cmdbuf + 7, "product")) { - strcpy(response + 4, PRODUCTNAME); - } else if(!strcmp(cmdbuf + 7, "serialno")) { - strcpy(response + 4, serialno); - } else { - board_getvar(cmdbuf + 7, response + 4); - } - tx_status(response); - rx_cmd(); - return; - } - - if(memcmp(cmdbuf, "download:", 9) == 0) { - char status[16]; - rx_addr = kernel_addr; - rx_length = hex2unsigned(cmdbuf + 9); - if (rx_length > (64*1024*1024)) { - tx_status("FAILdata too large"); - rx_cmd(); - return; - } - kernel_size = rx_length; - dprintf("recv data addr=%x size=%x\n", rx_addr, rx_length); - strcpy(status,"DATA"); - num_to_hex8(rx_length, status + 4); - tx_status(status); - rx_data(); - return; - } - - if(memcmp(cmdbuf, "erase:", 6) == 0){ - struct ptentry *ptn; - ptn = flash_find_ptn(cmdbuf + 6); - if(ptn == 0) { - tx_status("FAILpartition does not exist"); - rx_cmd(); - return; - } - dprintf("erasing '%s'\n", ptn->name); - cprintf("erasing '%s'", ptn->name); - if(flash_erase(ptn)) { - tx_status("FAILfailed to erase partition"); - rx_cmd(); - cprintf(" - FAIL\n"); - return; - } else { - dprintf("partition '%s' erased\n", ptn->name); - cprintf(" - OKAY\n"); - } - tx_status("OKAY"); - rx_cmd(); - return; - } - - if(memcmp(cmdbuf, "flash:", 6) == 0){ - struct ptentry *ptn; - int extra = 0; - ptn = flash_find_ptn(cmdbuf + 6); - if(kernel_size == 0) { - tx_status("FAILno image downloaded"); - rx_cmd(); - return; - } - if(ptn == 0) { - tx_status("FAILpartition does not exist"); - rx_cmd(); - return; - } - if(!strcmp(ptn->name,"boot") || !strcmp(ptn->name,"recovery")) { - if(memcmp((void*) kernel_addr, BOOT_MAGIC, BOOT_MAGIC_SIZE)) { - tx_status("FAILimage is not a boot image"); - rx_cmd(); - return; - } - } -#if REQUIRE_SIGNATURE - { - unsigned char digest[DIGEST_SIZE]; - compute_digest((void*) kernel_addr, kernel_size, digest); - if (is_signature_okay(digest, signature, key_engineering)) { - dprintf("verified by engineering key\n"); - } else { - tx_status("FAILsignature did not verify"); - rx_cmd(); - return; - } - } -#endif - if(!strcmp(ptn->name,"system") || !strcmp(ptn->name,"userdata")) { - extra = 64; - } else { - kernel_size = (kernel_size + 2047) & (~2047); - } - dprintf("writing %d bytes to '%s'\n", - kernel_size, ptn->name); - cprintf("writing '%s' (%d bytes)", ptn->name, kernel_size); - if(flash_write(ptn, extra, (void*) kernel_addr, kernel_size)) { - tx_status("FAILflash write failure"); - rx_cmd(); - cprintf(" - FAIL\n"); - return; - } else { - dprintf("partition '%s' updated\n", ptn->name); - cprintf(" - OKAY\n"); - } - tx_status("OKAY"); - rx_cmd(); - return; - } - if(memcmp(cmdbuf, "boot", 4) == 0) { - if(init_boot_linux()) { - tx_status("FAILinvalid boot image"); - rx_cmd(); - return; - } - dprintf("booting linux...\n"); - cprintf("\nbooting linux...\n"); - tx_status("OKAY"); - mdelay(10); - usb_shutdown(); - boot_linux(); - return; - } - if(memcmp(cmdbuf, "signature", 9) == 0) { - if (kernel_size != SIGNATURE_SIZE) { - tx_status("FAILsignature not 256 bytes long"); - rx_cmd(); - return; - } - memcpy(signature, (void*)kernel_addr, SIGNATURE_SIZE); - tx_status("OKAY"); - rx_cmd(); - return; - } - - tx_status("FAILinvalid command"); - rx_cmd(); -} - -void usb_status(unsigned online, unsigned highspeed) -{ - if(online) { - dprintf("usb: online (%s)\n", highspeed ? "highspeed" : "fullspeed"); - rx_cmd(); - } -} - -void usbloader_init(void) -{ - usb_init(); - - ep1out = usb_endpoint_alloc(1, 0, 512); - ep1in = usb_endpoint_alloc(1, 1, 512); - rx_req = usb_request_alloc(4096); - tx_req = usb_request_alloc(4096); - cmdbuf = rx_req->buf; - - boot_register_poll_func(usb_poll); -} |