Home | History | Annotate | Download | only in usbloader
      1 /*
      2  * Copyright (C) 2008 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 <boot/boot.h>
     30 #include <boot/flash.h>
     31 #include <boot/board.h>
     32 #include <boot/usb.h>
     33 
     34 #include <boot/bootimg.h>
     35 #include <boot/tags.h>
     36 
     37 #include <boot/gpio.h>
     38 
     39 #define VERSION "0.5"
     40 
     41 #define REQUIRE_SIGNATURE 0
     42 
     43 #if REQUIRE_SIGNATURE
     44 unsigned key_engineering[2 + 64 + 64] = {
     45     64,0x5b022317,-60769447,648742897,-13657530,585562035,591851935,
     46     454860199,-1809625305,1868200692,-155297008,-1688439840,-1333607631,
     47     -483027189,-2051438457,1030069735,819944365,2133377257,-1978924214,
     48     2109678622,1974978919,-1811463608,765849268,1984092281,921245328,
     49     -1055062768,1487475997,1209618652,871985152,-611178965,-2057018571,
     50     335641539,-1196119550,1550548229,-356223887,1909799623,1281016007,
     51     957001635,1005656532,-1027634024,-1576447610,-1917246637,589192795,
     52     -1137386186,-1958135372,1933245070,64958951,-1820428322,-1577697840,
     53     1824253519,555306239,-1588272058,-1925773018,1205934271,-836584444,
     54     -1140961670,-185198349,1293769947,37045923,1516796974,-297288651,
     55     651582073,-1337054592,-543971216,-1706823885,-1040652818,-594113104,
     56     260093481,-1277656496,56493468,1577037283,773995876,244894933,
     57     -2075797967,783894843,880611008,-1433369702,380946504,-2081431477,
     58     1377832804,2089455451,-410001201,1245307237,-1228170341,-2062569137,
     59     -1327614308,-1671042654,1242248660,-418803721,40890010,-1806767460,
     60     -1468529145,-1058158532,1243817302,-527795003,175453645,-210650325,
     61     -827053868,-571422860,886300657,2129677324,846504590,-1413102805,
     62     -1287448511,-1991140134,56194155,1375685594,-129884114,1393568535,
     63     -1098719620,-935279550,1717137954,-1782544741,272581921,-669183778,
     64     584824755,1434974827,-1122387971,-810584927,-2147338547,-937541680,
     65     -313561073,5506366,-1594059648,-1744451574,1896015834,1496367069,
     66     1742853908,508461291,1905056764
     67 };
     68 #endif
     69 
     70 const char *get_fastboot_version(void)
     71 {
     72     return VERSION;
     73 }
     74 
     75 unsigned linux_type = 0;
     76 unsigned linux_tags = 0;
     77 
     78 unsigned ramdisk_addr = 0x10400000;
     79 unsigned ramdisk_size = 0;
     80 unsigned kernel_addr = 0x10008000;
     81 unsigned kernel_size = 0;
     82 
     83 static void fixup_tags(unsigned *tags, unsigned *out, const char *cmdline)
     84 {
     85     unsigned *newtags = (unsigned *) 0x10004000;
     86     unsigned *np = newtags;
     87     unsigned n;
     88     char *oldcmdline = "";
     89 
     90     if(cmdline == 0) cmdline = "";
     91 
     92         /* CORE */
     93     *np++ = 2;
     94     *np++ = 0x54410001;
     95 
     96     if(tags != 0) {
     97         while(*tags) {
     98             if(tags[1] == 0x54410001) {
     99                     /* skip core tag */
    100                 tags += tags[0];
    101             } else if((tags[1] == 0x54420005) && (ramdisk_size != 0)) {
    102                     /* skip ramdisk if we have one of our own */
    103                 tags += tags[0];
    104             } else if((tags[1] == 0x54410009) && (cmdline[0])) {
    105                     /* skip existing cmdline so we can replace it */
    106                 oldcmdline = (char*) (tags + 2);
    107                 tags += tags[0];
    108             } else {
    109                     /* copy any unknown tags */
    110                 n = tags[0];
    111                 while(n-- > 0) {
    112                     *np++ = *tags++;
    113                 }
    114             }
    115         }
    116     }
    117 
    118         /* create a ramdisk tag if we need to */
    119     if(ramdisk_size) {
    120         *np++ = 4;
    121         *np++ = 0x54420005;
    122         *np++ = ramdisk_addr;
    123         *np++ = ramdisk_size;
    124     }
    125 
    126     dprintf("cmdline: '%s'\n", oldcmdline);
    127     dprintf("cmdline: '%s'\n", cmdline);
    128 
    129         /* create a cmdline tag if we need to */
    130     if(cmdline[0]) {
    131         int len;
    132         char *str = (char*) (np + 2);
    133 
    134         len = strlen(oldcmdline);
    135         if(len) {
    136             memcpy(str, oldcmdline, len);
    137             str += len;
    138             *str++ = ' ';
    139         }
    140 
    141         len = strlen(cmdline);
    142         memcpy(str, cmdline, len);
    143         str += len;
    144         *str++ = 0;
    145 
    146             /* length in words */
    147         len = ((str - ((char*) (np + 2))) + 3) / 4;
    148 
    149         dprintf("CMDLINE: '%s'\n", ((char*) (np + 2)));
    150 
    151         *np++ = 2 + len;
    152         *np++ = 0x54410009;
    153 
    154         np += len;
    155     }
    156 
    157         /* add footer tag */
    158     *np++ = 0;
    159     *np++ = 0;
    160 
    161         /* copy it all back to the original tags area */
    162     while(newtags < np) {
    163         *out++ = *newtags++;
    164     }
    165 }
    166 
    167 static char cmdline[BOOT_ARGS_SIZE];
    168 
    169 static void boot_linux(void)
    170 {
    171     unsigned *tags = (unsigned*) 0x10000100;
    172     void (*entry)(unsigned,unsigned,unsigned) = (void*) kernel_addr;
    173 
    174     if(linux_type == 0) {
    175         linux_type = board_machtype();
    176     }
    177 
    178     fixup_tags((unsigned*) linux_tags, tags, cmdline);
    179 
    180     entry(0, linux_type, tags);
    181 
    182     for(;;);
    183 }
    184 
    185 /* convert a boot_image at kernel_addr into a kernel + ramdisk + tags */
    186 static int init_boot_linux(void)
    187 {
    188     boot_img_hdr *hdr = (void*) kernel_addr;
    189     unsigned page_mask = 2047;
    190     unsigned kernel_actual;
    191     unsigned ramdisk_actual;
    192     unsigned second_actual;
    193 
    194     if((kernel_size < 2048) || memcmp(hdr->magic, BOOT_MAGIC, BOOT_MAGIC_SIZE)){
    195         dprintf("bootimg: bad header\n");
    196         return -1;
    197     }
    198 
    199     if(hdr->page_size != 2048) {
    200         dprintf("bootimg: invalid page size\n");
    201         return -1;
    202     }
    203 
    204     kernel_actual = (hdr->kernel_size + page_mask) & (~page_mask);
    205     ramdisk_actual = (hdr->ramdisk_size + page_mask) & (~page_mask);
    206     second_actual = (hdr->second_size + page_mask) & (~page_mask);
    207 
    208     if(kernel_size != (kernel_actual + ramdisk_actual + second_actual + 2048)) {
    209         dprintf("bootimg: invalid image size");
    210         return -1;
    211     }
    212 
    213         /* XXX process commandline here */
    214     if(hdr->cmdline[0]){
    215         hdr->cmdline[BOOT_ARGS_SIZE - 1] = 0;
    216         memcpy(cmdline, hdr->cmdline, BOOT_ARGS_SIZE);
    217     }
    218 
    219         /* XXX how to validate addresses? */
    220     ramdisk_addr = hdr->ramdisk_addr;
    221     ramdisk_size = hdr->ramdisk_size;
    222 
    223     kernel_addr = hdr->kernel_addr;
    224     kernel_size = hdr->kernel_size;
    225 
    226     dprintf("bootimg: kernel addr=%x size=%x\n",
    227             kernel_addr, kernel_size);
    228     dprintf("bootimg: ramdisk addr=%x size=%x\n",
    229             ramdisk_addr, ramdisk_size);
    230 
    231     memcpy((void*) ramdisk_addr,
    232            hdr->magic + 2048 + kernel_actual,
    233            ramdisk_size);
    234 
    235     memcpy((void*) kernel_addr,
    236            hdr->magic + 2048,
    237            kernel_size);
    238 
    239     return 0;
    240 }
    241 
    242 static struct usb_endpoint *ep1in, *ep1out;
    243 static struct usb_request *rx_req, *tx_req;
    244 static unsigned rx_addr;
    245 static unsigned rx_length;
    246 
    247 static char *cmdbuf;
    248 
    249 static void usb_rx_cmd_complete(struct usb_request *req, unsigned actual, int status);
    250 static void usb_rx_data_complete(struct usb_request *req, unsigned actual, int status);
    251 
    252 static void rx_cmd(void)
    253 {
    254     struct usb_request *req = rx_req;
    255     req->buf = cmdbuf;
    256     req->length = 4096;
    257     req->complete = usb_rx_cmd_complete;
    258     usb_queue_req(ep1out, req);
    259 }
    260 
    261 static void rx_data(void)
    262 {
    263     struct usb_request *req = rx_req;
    264     req->buf = (void*) rx_addr;
    265     req->length = (rx_length > 4096) ? 4096 : rx_length;
    266     req->complete = usb_rx_data_complete;
    267     usb_queue_req(ep1out, req);
    268 }
    269 
    270 static void tx_status(const char *status)
    271 {
    272     struct usb_request *req = tx_req;
    273     int len = strlen(status);
    274 //    dprintf("tx_status('%s')\n", status);
    275     memcpy(req->buf, status, len);
    276     req->length = len;
    277     req->complete = 0;
    278     usb_queue_req(ep1in, req);
    279 }
    280 
    281 static void usb_rx_data_complete(struct usb_request *req, unsigned actual, int status)
    282 {
    283     if(status != 0) return;
    284 
    285     if(actual > rx_length) {
    286         actual = rx_length;
    287     }
    288 
    289     rx_addr += actual;
    290     rx_length -= actual;
    291 
    292     if(rx_length > 0) {
    293         rx_data();
    294     } else {
    295         tx_status("OKAY");
    296         rx_cmd();
    297     }
    298 }
    299 
    300 static unsigned hex2unsigned(char *x)
    301 {
    302     unsigned n = 0;
    303 
    304     while(*x) {
    305         switch(*x) {
    306         case '0': case '1': case '2': case '3': case '4':
    307         case '5': case '6': case '7': case '8': case '9':
    308             n = (n << 4) | (*x - '0');
    309             break;
    310         case 'a': case 'b': case 'c':
    311         case 'd': case 'e': case 'f':
    312             n = (n << 4) | (*x - 'a' + 10);
    313             break;
    314         case 'A': case 'B': case 'C':
    315         case 'D': case 'E': case 'F':
    316             n = (n << 4) | (*x - 'A' + 10);
    317             break;
    318         default:
    319             return n;
    320         }
    321         x++;
    322     }
    323 
    324     return n;
    325 }
    326 
    327 static void num_to_hex8(unsigned n, char *out)
    328 {
    329     static char tohex[16] = "0123456789abcdef";
    330     int i;
    331     for(i = 7; i >= 0; i--) {
    332         out[i] = tohex[n & 15];
    333         n >>= 4;
    334     }
    335     out[8] = 0;
    336 }
    337 
    338 extern char serialno[];
    339 
    340 static char signature[SIGNATURE_SIZE];
    341 
    342 static void usb_rx_cmd_complete(struct usb_request *req, unsigned actual, int status)
    343 {
    344     if(status != 0) return;
    345 
    346     if(actual > 4095) actual = 4095;
    347     cmdbuf[actual] = 0;
    348 
    349     dprintf("\n> %s\n",cmdbuf);
    350 
    351 //    dprintf("usb_rx_cmd_complete() '%s'\n", cmdbuf);
    352 
    353     if(memcmp(cmdbuf, "reboot", 6) == 0) {
    354         tx_status("OKAY");
    355         rx_cmd();
    356         mdelay(100);
    357         board_reboot();
    358     }
    359 #if 0
    360     if(memcmp(cmdbuf, "debug:", 6) == 0) {
    361         void debug(char *cmd, char *resp);
    362         memcpy(cmdbuf, "OKAY", 5);
    363         tx_status(cmdbuf);
    364         rx_cmd();
    365         mdelay(5000);
    366         dprintf("NOW!\n");
    367         debug(cmdbuf + 6, cmdbuf + 4);
    368         return;
    369     }
    370 #endif
    371     if(memcmp(cmdbuf, "getvar:", 7) == 0) {
    372         char response[64];
    373         strcpy(response,"OKAY");
    374 
    375         if(!strcmp(cmdbuf + 7, "version")) {
    376             strcpy(response + 4, VERSION);
    377         } else if(!strcmp(cmdbuf + 7, "product")) {
    378             strcpy(response + 4, PRODUCTNAME);
    379         } else if(!strcmp(cmdbuf + 7, "serialno")) {
    380             strcpy(response + 4, serialno);
    381         } else {
    382             board_getvar(cmdbuf + 7, response + 4);
    383         }
    384         tx_status(response);
    385         rx_cmd();
    386         return;
    387     }
    388 
    389     if(memcmp(cmdbuf, "download:", 9) == 0) {
    390         char status[16];
    391         rx_addr = kernel_addr;
    392         rx_length = hex2unsigned(cmdbuf + 9);
    393         if (rx_length > (64*1024*1024)) {
    394             tx_status("FAILdata too large");
    395             rx_cmd();
    396             return;
    397         }
    398         kernel_size = rx_length;
    399         dprintf("recv data addr=%x size=%x\n", rx_addr, rx_length);
    400         strcpy(status,"DATA");
    401         num_to_hex8(rx_length, status + 4);
    402         tx_status(status);
    403         rx_data();
    404         return;
    405     }
    406 
    407     if(memcmp(cmdbuf, "erase:", 6) == 0){
    408         struct ptentry *ptn;
    409         ptn = flash_find_ptn(cmdbuf + 6);
    410         if(ptn == 0) {
    411             tx_status("FAILpartition does not exist");
    412             rx_cmd();
    413             return;
    414         }
    415         dprintf("erasing '%s'\n", ptn->name);
    416         cprintf("erasing '%s'", ptn->name);
    417         if(flash_erase(ptn)) {
    418             tx_status("FAILfailed to erase partition");
    419             rx_cmd();
    420             cprintf(" - FAIL\n");
    421             return;
    422         } else {
    423             dprintf("partition '%s' erased\n", ptn->name);
    424             cprintf(" - OKAY\n");
    425         }
    426         tx_status("OKAY");
    427         rx_cmd();
    428         return;
    429     }
    430 
    431     if(memcmp(cmdbuf, "flash:", 6) == 0){
    432         struct ptentry *ptn;
    433         int extra = 0;
    434         ptn = flash_find_ptn(cmdbuf + 6);
    435         if(kernel_size == 0) {
    436             tx_status("FAILno image downloaded");
    437             rx_cmd();
    438             return;
    439         }
    440         if(ptn == 0) {
    441             tx_status("FAILpartition does not exist");
    442             rx_cmd();
    443             return;
    444         }
    445         if(!strcmp(ptn->name,"boot") || !strcmp(ptn->name,"recovery")) {
    446             if(memcmp((void*) kernel_addr, BOOT_MAGIC, BOOT_MAGIC_SIZE)) {
    447                 tx_status("FAILimage is not a boot image");
    448                 rx_cmd();
    449                 return;
    450             }
    451         }
    452 #if REQUIRE_SIGNATURE
    453         {
    454             unsigned char digest[DIGEST_SIZE];
    455             compute_digest((void*) kernel_addr, kernel_size, digest);
    456             if (is_signature_okay(digest, signature, key_engineering)) {
    457                 dprintf("verified by engineering key\n");
    458             } else {
    459                 tx_status("FAILsignature did not verify");
    460                 rx_cmd();
    461                 return;
    462             }
    463         }
    464 #endif
    465         if(!strcmp(ptn->name,"system") || !strcmp(ptn->name,"userdata")) {
    466             extra = 64;
    467         } else {
    468             kernel_size = (kernel_size + 2047) & (~2047);
    469         }
    470         dprintf("writing %d bytes to '%s'\n",
    471                 kernel_size, ptn->name);
    472         cprintf("writing '%s' (%d bytes)", ptn->name, kernel_size);
    473         if(flash_write(ptn, extra, (void*) kernel_addr, kernel_size)) {
    474             tx_status("FAILflash write failure");
    475             rx_cmd();
    476             cprintf(" - FAIL\n");
    477             return;
    478         } else {
    479             dprintf("partition '%s' updated\n", ptn->name);
    480             cprintf(" - OKAY\n");
    481         }
    482         tx_status("OKAY");
    483         rx_cmd();
    484         return;
    485     }
    486     if(memcmp(cmdbuf, "boot", 4) == 0) {
    487         if(init_boot_linux()) {
    488             tx_status("FAILinvalid boot image");
    489             rx_cmd();
    490             return;
    491         }
    492         dprintf("booting linux...\n");
    493         cprintf("\nbooting linux...\n");
    494         tx_status("OKAY");
    495         mdelay(10);
    496         usb_shutdown();
    497         boot_linux();
    498         return;
    499     }
    500     if(memcmp(cmdbuf, "signature", 9) == 0) {
    501         if (kernel_size != SIGNATURE_SIZE) {
    502             tx_status("FAILsignature not 256 bytes long");
    503             rx_cmd();
    504             return;
    505         }
    506         memcpy(signature, (void*)kernel_addr, SIGNATURE_SIZE);
    507         tx_status("OKAY");
    508         rx_cmd();
    509         return;
    510     }
    511 
    512     tx_status("FAILinvalid command");
    513     rx_cmd();
    514 }
    515 
    516 void usb_status(unsigned online, unsigned highspeed)
    517 {
    518     if(online) {
    519         dprintf("usb: online (%s)\n", highspeed ? "highspeed" : "fullspeed");
    520         rx_cmd();
    521     }
    522 }
    523 
    524 void usbloader_init(void)
    525 {
    526     usb_init();
    527 
    528     ep1out = usb_endpoint_alloc(1, 0, 512);
    529     ep1in = usb_endpoint_alloc(1, 1, 512);
    530     rx_req = usb_request_alloc(4096);
    531     tx_req = usb_request_alloc(4096);
    532     cmdbuf = rx_req->buf;
    533 
    534     boot_register_poll_func(usb_poll);
    535 }
    536