summaryrefslogtreecommitdiff
path: root/usbloader/usbloader.c
diff options
context:
space:
mode:
Diffstat (limited to 'usbloader/usbloader.c')
-rw-r--r--usbloader/usbloader.c535
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);
-}