Home | History | Annotate | Download | only in fastboot
      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 <stdio.h>
     30 #include <stdlib.h>
     31 #include <stdarg.h>
     32 #include <string.h>
     33 #include <errno.h>
     34 #include <fcntl.h>
     35 #include <unistd.h>
     36 #include <limits.h>
     37 #include <ctype.h>
     38 
     39 #include <sys/time.h>
     40 #include <bootimg.h>
     41 #include <zipfile/zipfile.h>
     42 
     43 #include "fastboot.h"
     44 
     45 void bootimg_set_cmdline(boot_img_hdr *h, const char *cmdline);
     46 
     47 boot_img_hdr *mkbootimg(void *kernel, unsigned kernel_size,
     48                         void *ramdisk, unsigned ramdisk_size,
     49                         void *second, unsigned second_size,
     50                         unsigned page_size, unsigned base,
     51                         unsigned *bootimg_size);
     52 
     53 static usb_handle *usb = 0;
     54 static const char *serial = 0;
     55 static const char *product = 0;
     56 static const char *cmdline = 0;
     57 static int wipe_data = 0;
     58 static unsigned short vendor_id = 0;
     59 
     60 static unsigned base_addr = 0x10000000;
     61 
     62 void die(const char *fmt, ...)
     63 {
     64     va_list ap;
     65     va_start(ap, fmt);
     66     fprintf(stderr,"error: ");
     67     vfprintf(stderr, fmt, ap);
     68     fprintf(stderr,"\n");
     69     va_end(ap);
     70     exit(1);
     71 }
     72 
     73 void get_my_path(char *path);
     74 
     75 char *find_item(const char *item, const char *product)
     76 {
     77     char *dir;
     78     char *fn;
     79     char path[PATH_MAX + 128];
     80 
     81     if(!strcmp(item,"boot")) {
     82         fn = "boot.img";
     83     } else if(!strcmp(item,"recovery")) {
     84         fn = "recovery.img";
     85     } else if(!strcmp(item,"system")) {
     86         fn = "system.img";
     87     } else if(!strcmp(item,"userdata")) {
     88         fn = "userdata.img";
     89     } else if(!strcmp(item,"info")) {
     90         fn = "android-info.txt";
     91     } else {
     92         fprintf(stderr,"unknown partition '%s'\n", item);
     93         return 0;
     94     }
     95 
     96     if(product) {
     97         get_my_path(path);
     98         sprintf(path + strlen(path),
     99                 "../../../target/product/%s/%s", product, fn);
    100         return strdup(path);
    101     }
    102 
    103     dir = getenv("ANDROID_PRODUCT_OUT");
    104     if((dir == 0) || (dir[0] == 0)) {
    105         die("neither -p product specified nor ANDROID_PRODUCT_OUT set");
    106         return 0;
    107     }
    108 
    109     sprintf(path, "%s/%s", dir, fn);
    110     return strdup(path);
    111 }
    112 
    113 #ifdef _WIN32
    114 void *load_file(const char *fn, unsigned *_sz);
    115 #else
    116 void *load_file(const char *fn, unsigned *_sz)
    117 {
    118     char *data;
    119     int sz;
    120     int fd;
    121 
    122     data = 0;
    123     fd = open(fn, O_RDONLY);
    124     if(fd < 0) return 0;
    125 
    126     sz = lseek(fd, 0, SEEK_END);
    127     if(sz < 0) goto oops;
    128 
    129     if(lseek(fd, 0, SEEK_SET) != 0) goto oops;
    130 
    131     data = (char*) malloc(sz);
    132     if(data == 0) goto oops;
    133 
    134     if(read(fd, data, sz) != sz) goto oops;
    135     close(fd);
    136 
    137     if(_sz) *_sz = sz;
    138     return data;
    139 
    140 oops:
    141     close(fd);
    142     if(data != 0) free(data);
    143     return 0;
    144 }
    145 #endif
    146 
    147 int match_fastboot(usb_ifc_info *info)
    148 {
    149     if(!(vendor_id && (info->dev_vendor == vendor_id)) &&
    150        (info->dev_vendor != 0x18d1) &&  // Google
    151        (info->dev_vendor != 0x0451) &&
    152        (info->dev_vendor != 0x0502) &&
    153        (info->dev_vendor != 0x22b8) &&  // Motorola
    154        (info->dev_vendor != 0x0955) &&  // Nvidia
    155        (info->dev_vendor != 0x413c) &&  // DELL
    156        (info->dev_vendor != 0x0bb4))    // HTC
    157             return -1;
    158     if(info->ifc_class != 0xff) return -1;
    159     if(info->ifc_subclass != 0x42) return -1;
    160     if(info->ifc_protocol != 0x03) return -1;
    161     // require matching serial number if a serial number is specified
    162     // at the command line with the -s option.
    163     if (serial && strcmp(serial, info->serial_number) != 0) return -1;
    164     return 0;
    165 }
    166 
    167 int list_devices_callback(usb_ifc_info *info)
    168 {
    169     if (match_fastboot(info) == 0) {
    170         char* serial = info->serial_number;
    171         if (!info->writable) {
    172             serial = "no permissions"; // like "adb devices"
    173         }
    174         if (!serial[0]) {
    175             serial = "????????????";
    176         }
    177         // output compatible with "adb devices"
    178         printf("%s\tfastboot\n", serial);
    179     }
    180 
    181     return -1;
    182 }
    183 
    184 usb_handle *open_device(void)
    185 {
    186     static usb_handle *usb = 0;
    187     int announce = 1;
    188 
    189     if(usb) return usb;
    190 
    191     for(;;) {
    192         usb = usb_open(match_fastboot);
    193         if(usb) return usb;
    194         if(announce) {
    195             announce = 0;
    196             fprintf(stderr,"< waiting for device >\n");
    197         }
    198         sleep(1);
    199     }
    200 }
    201 
    202 void list_devices(void) {
    203     // We don't actually open a USB device here,
    204     // just getting our callback called so we can
    205     // list all the connected devices.
    206     usb_open(list_devices_callback);
    207 }
    208 
    209 void usage(void)
    210 {
    211     fprintf(stderr,
    212 /*           1234567890123456789012345678901234567890123456789012345678901234567890123456 */
    213             "usage: fastboot [ <option> ] <command>\n"
    214             "\n"
    215             "commands:\n"
    216             "  update <filename>                        reflash device from update.zip\n"
    217             "  flashall                                 flash boot + recovery + system\n"
    218             "  flash <partition> [ <filename> ]         write a file to a flash partition\n"
    219             "  erase <partition>                        erase a flash partition\n"
    220             "  getvar <variable>                        display a bootloader variable\n"
    221             "  boot <kernel> [ <ramdisk> ]              download and boot kernel\n"
    222             "  flash:raw boot <kernel> [ <ramdisk> ]    create bootimage and flash it\n"
    223             "  devices                                  list all connected devices\n"
    224             "  reboot                                   reboot device normally\n"
    225             "  reboot-bootloader                        reboot device into bootloader\n"
    226             "\n"
    227             "options:\n"
    228             "  -w                                       erase userdata and cache\n"
    229             "  -s <serial number>                       specify device serial number\n"
    230             "  -p <product>                             specify product name\n"
    231             "  -c <cmdline>                             override kernel commandline\n"
    232             "  -i <vendor id>                           specify a custom USB vendor id\n"
    233             "  -b <base_addr>                           specify a custom kernel base address\n"
    234             "  -n <page size>                           specify the nand page size. default: 2048\n"
    235         );
    236     exit(1);
    237 }
    238 
    239 void *load_bootable_image(unsigned page_size, const char *kernel, const char *ramdisk,
    240                           unsigned *sz, const char *cmdline)
    241 {
    242     void *kdata = 0, *rdata = 0;
    243     unsigned ksize = 0, rsize = 0;
    244     void *bdata;
    245     unsigned bsize;
    246 
    247     if(kernel == 0) {
    248         fprintf(stderr, "no image specified\n");
    249         return 0;
    250     }
    251 
    252     kdata = load_file(kernel, &ksize);
    253     if(kdata == 0) {
    254         fprintf(stderr, "cannot load '%s'\n", kernel);
    255         return 0;
    256     }
    257 
    258         /* is this actually a boot image? */
    259     if(!memcmp(kdata, BOOT_MAGIC, BOOT_MAGIC_SIZE)) {
    260         if(cmdline) bootimg_set_cmdline((boot_img_hdr*) kdata, cmdline);
    261 
    262         if(ramdisk) {
    263             fprintf(stderr, "cannot boot a boot.img *and* ramdisk\n");
    264             return 0;
    265         }
    266 
    267         *sz = ksize;
    268         return kdata;
    269     }
    270 
    271     if(ramdisk) {
    272         rdata = load_file(ramdisk, &rsize);
    273         if(rdata == 0) {
    274             fprintf(stderr,"cannot load '%s'\n", ramdisk);
    275             return  0;
    276         }
    277     }
    278 
    279     fprintf(stderr,"creating boot image...\n");
    280     bdata = mkbootimg(kdata, ksize, rdata, rsize, 0, 0, page_size, base_addr, &bsize);
    281     if(bdata == 0) {
    282         fprintf(stderr,"failed to create boot.img\n");
    283         return 0;
    284     }
    285     if(cmdline) bootimg_set_cmdline((boot_img_hdr*) bdata, cmdline);
    286     fprintf(stderr,"creating boot image - %d bytes\n", bsize);
    287     *sz = bsize;
    288 
    289     return bdata;
    290 }
    291 
    292 void *unzip_file(zipfile_t zip, const char *name, unsigned *sz)
    293 {
    294     void *data;
    295     zipentry_t entry;
    296     unsigned datasz;
    297 
    298     entry = lookup_zipentry(zip, name);
    299     if (entry == NULL) {
    300         fprintf(stderr, "archive does not contain '%s'\n", name);
    301         return 0;
    302     }
    303 
    304     *sz = get_zipentry_size(entry);
    305 
    306     datasz = *sz * 1.001;
    307     data = malloc(datasz);
    308 
    309     if(data == 0) {
    310         fprintf(stderr, "failed to allocate %d bytes\n", *sz);
    311         return 0;
    312     }
    313 
    314     if (decompress_zipentry(entry, data, datasz)) {
    315         fprintf(stderr, "failed to unzip '%s' from archive\n", name);
    316         free(data);
    317         return 0;
    318     }
    319 
    320     return data;
    321 }
    322 
    323 static char *strip(char *s)
    324 {
    325     int n;
    326     while(*s && isspace(*s)) s++;
    327     n = strlen(s);
    328     while(n-- > 0) {
    329         if(!isspace(s[n])) break;
    330         s[n] = 0;
    331     }
    332     return s;
    333 }
    334 
    335 #define MAX_OPTIONS 32
    336 static int setup_requirement_line(char *name)
    337 {
    338     char *val[MAX_OPTIONS];
    339     const char **out;
    340     unsigned n, count;
    341     char *x;
    342     int invert = 0;
    343 
    344     if (!strncmp(name, "reject ", 7)) {
    345         name += 7;
    346         invert = 1;
    347     } else if (!strncmp(name, "require ", 8)) {
    348         name += 8;
    349         invert = 0;
    350     }
    351 
    352     x = strchr(name, '=');
    353     if (x == 0) return 0;
    354     *x = 0;
    355     val[0] = x + 1;
    356 
    357     for(count = 1; count < MAX_OPTIONS; count++) {
    358         x = strchr(val[count - 1],'|');
    359         if (x == 0) break;
    360         *x = 0;
    361         val[count] = x + 1;
    362     }
    363 
    364     name = strip(name);
    365     for(n = 0; n < count; n++) val[n] = strip(val[n]);
    366 
    367     name = strip(name);
    368     if (name == 0) return -1;
    369 
    370         /* work around an unfortunate name mismatch */
    371     if (!strcmp(name,"board")) name = "product";
    372 
    373     out = malloc(sizeof(char*) * count);
    374     if (out == 0) return -1;
    375 
    376     for(n = 0; n < count; n++) {
    377         out[n] = strdup(strip(val[n]));
    378         if (out[n] == 0) return -1;
    379     }
    380 
    381     fb_queue_require(name, invert, n, out);
    382     return 0;
    383 }
    384 
    385 static void setup_requirements(char *data, unsigned sz)
    386 {
    387     char *s;
    388 
    389     s = data;
    390     while (sz-- > 0) {
    391         if(*s == '\n') {
    392             *s++ = 0;
    393             if (setup_requirement_line(data)) {
    394                 die("out of memory");
    395             }
    396             data = s;
    397         } else {
    398             s++;
    399         }
    400     }
    401 }
    402 
    403 void queue_info_dump(void)
    404 {
    405     fb_queue_notice("--------------------------------------------");
    406     fb_queue_display("version-bootloader", "Bootloader Version...");
    407     fb_queue_display("version-baseband",   "Baseband Version.....");
    408     fb_queue_display("serialno",           "Serial Number........");
    409     fb_queue_notice("--------------------------------------------");
    410 }
    411 
    412 void do_update_signature(zipfile_t zip, char *fn)
    413 {
    414     void *data;
    415     unsigned sz;
    416     data = unzip_file(zip, fn, &sz);
    417     if (data == 0) return;
    418     fb_queue_download("signature", data, sz);
    419     fb_queue_command("signature", "installing signature");
    420 }
    421 
    422 void do_update(char *fn)
    423 {
    424     void *zdata;
    425     unsigned zsize;
    426     void *data;
    427     unsigned sz;
    428     zipfile_t zip;
    429 
    430     queue_info_dump();
    431 
    432     zdata = load_file(fn, &zsize);
    433     if (zdata == 0) die("failed to load '%s'", fn);
    434 
    435     zip = init_zipfile(zdata, zsize);
    436     if(zip == 0) die("failed to access zipdata in '%s'");
    437 
    438     data = unzip_file(zip, "android-info.txt", &sz);
    439     if (data == 0) {
    440         char *tmp;
    441             /* fallback for older zipfiles */
    442         data = unzip_file(zip, "android-product.txt", &sz);
    443         if ((data == 0) || (sz < 1)) {
    444             die("update package has no android-info.txt or android-product.txt");
    445         }
    446         tmp = malloc(sz + 128);
    447         if (tmp == 0) die("out of memory");
    448         sprintf(tmp,"board=%sversion-baseband=0.66.04.19\n",(char*)data);
    449         data = tmp;
    450         sz = strlen(tmp);
    451     }
    452 
    453     setup_requirements(data, sz);
    454 
    455     data = unzip_file(zip, "boot.img", &sz);
    456     if (data == 0) die("update package missing boot.img");
    457     do_update_signature(zip, "boot.sig");
    458     fb_queue_flash("boot", data, sz);
    459 
    460     data = unzip_file(zip, "recovery.img", &sz);
    461     if (data != 0) {
    462         do_update_signature(zip, "recovery.sig");
    463         fb_queue_flash("recovery", data, sz);
    464     }
    465 
    466     data = unzip_file(zip, "system.img", &sz);
    467     if (data == 0) die("update package missing system.img");
    468     do_update_signature(zip, "system.sig");
    469     fb_queue_flash("system", data, sz);
    470 }
    471 
    472 void do_send_signature(char *fn)
    473 {
    474     void *data;
    475     unsigned sz;
    476     char *xtn;
    477 
    478     xtn = strrchr(fn, '.');
    479     if (!xtn) return;
    480     if (strcmp(xtn, ".img")) return;
    481 
    482     strcpy(xtn,".sig");
    483     data = load_file(fn, &sz);
    484     strcpy(xtn,".img");
    485     if (data == 0) return;
    486     fb_queue_download("signature", data, sz);
    487     fb_queue_command("signature", "installing signature");
    488 }
    489 
    490 void do_flashall(void)
    491 {
    492     char *fname;
    493     void *data;
    494     unsigned sz;
    495 
    496     queue_info_dump();
    497 
    498     fname = find_item("info", product);
    499     if (fname == 0) die("cannot find android-info.txt");
    500     data = load_file(fname, &sz);
    501     if (data == 0) die("could not load android-info.txt");
    502     setup_requirements(data, sz);
    503 
    504     fname = find_item("boot", product);
    505     data = load_file(fname, &sz);
    506     if (data == 0) die("could not load boot.img");
    507     do_send_signature(fname);
    508     fb_queue_flash("boot", data, sz);
    509 
    510     fname = find_item("recovery", product);
    511     data = load_file(fname, &sz);
    512     if (data != 0) {
    513         do_send_signature(fname);
    514         fb_queue_flash("recovery", data, sz);
    515     }
    516 
    517     fname = find_item("system", product);
    518     data = load_file(fname, &sz);
    519     if (data == 0) die("could not load system.img");
    520     do_send_signature(fname);
    521     fb_queue_flash("system", data, sz);
    522 }
    523 
    524 #define skip(n) do { argc -= (n); argv += (n); } while (0)
    525 #define require(n) do { if (argc < (n)) usage(); } while (0)
    526 
    527 int do_oem_command(int argc, char **argv)
    528 {
    529     int i;
    530     char command[256];
    531     if (argc <= 1) return 0;
    532 
    533     command[0] = 0;
    534     while(1) {
    535         strcat(command,*argv);
    536         skip(1);
    537         if(argc == 0) break;
    538         strcat(command," ");
    539     }
    540 
    541     fb_queue_command(command,"");
    542     return 0;
    543 }
    544 
    545 int main(int argc, char **argv)
    546 {
    547     int wants_wipe = 0;
    548     int wants_reboot = 0;
    549     int wants_reboot_bootloader = 0;
    550     void *data;
    551     unsigned sz;
    552     unsigned page_size = 2048;
    553 
    554     skip(1);
    555     if (argc == 0) {
    556         usage();
    557         return 0;
    558     }
    559 
    560     if (!strcmp(*argv, "devices")) {
    561         list_devices();
    562         return 0;
    563     }
    564 
    565     serial = getenv("ANDROID_SERIAL");
    566 
    567     while (argc > 0) {
    568         if(!strcmp(*argv, "-w")) {
    569             wants_wipe = 1;
    570             skip(1);
    571         } else if(!strcmp(*argv, "-b")) {
    572             require(2);
    573             base_addr = strtoul(argv[1], 0, 16);
    574             skip(2);
    575         } else if(!strcmp(*argv, "-n")) {
    576             require(2);
    577             page_size = (unsigned)strtoul(argv[1], NULL, 0);
    578             if (!page_size) die("invalid page size");
    579             skip(2);
    580         } else if(!strcmp(*argv, "-s")) {
    581             require(2);
    582             serial = argv[1];
    583             skip(2);
    584         } else if(!strcmp(*argv, "-p")) {
    585             require(2);
    586             product = argv[1];
    587             skip(2);
    588         } else if(!strcmp(*argv, "-c")) {
    589             require(2);
    590             cmdline = argv[1];
    591             skip(2);
    592         } else if(!strcmp(*argv, "-i")) {
    593             char *endptr = NULL;
    594             unsigned long val;
    595 
    596             require(2);
    597             val = strtoul(argv[1], &endptr, 0);
    598             if (!endptr || *endptr != '\0' || (val & ~0xffff))
    599                 die("invalid vendor id '%s'", argv[1]);
    600             vendor_id = (unsigned short)val;
    601             skip(2);
    602         } else if(!strcmp(*argv, "getvar")) {
    603             require(2);
    604             fb_queue_display(argv[1], argv[1]);
    605             skip(2);
    606         } else if(!strcmp(*argv, "erase")) {
    607             require(2);
    608             fb_queue_erase(argv[1]);
    609             skip(2);
    610         } else if(!strcmp(*argv, "signature")) {
    611             require(2);
    612             data = load_file(argv[1], &sz);
    613             if (data == 0) die("could not load '%s'", argv[1]);
    614             if (sz != 256) die("signature must be 256 bytes");
    615             fb_queue_download("signature", data, sz);
    616             fb_queue_command("signature", "installing signature");
    617             skip(2);
    618         } else if(!strcmp(*argv, "reboot")) {
    619             wants_reboot = 1;
    620             skip(1);
    621         } else if(!strcmp(*argv, "reboot-bootloader")) {
    622             wants_reboot_bootloader = 1;
    623             skip(1);
    624         } else if (!strcmp(*argv, "continue")) {
    625             fb_queue_command("continue", "resuming boot");
    626             skip(1);
    627         } else if(!strcmp(*argv, "boot")) {
    628             char *kname = 0;
    629             char *rname = 0;
    630             skip(1);
    631             if (argc > 0) {
    632                 kname = argv[0];
    633                 skip(1);
    634             }
    635             if (argc > 0) {
    636                 rname = argv[0];
    637                 skip(1);
    638             }
    639             data = load_bootable_image(page_size, kname, rname, &sz, cmdline);
    640             if (data == 0) return 1;
    641             fb_queue_download("boot.img", data, sz);
    642             fb_queue_command("boot", "booting");
    643         } else if(!strcmp(*argv, "flash")) {
    644             char *pname = argv[1];
    645             char *fname = 0;
    646             require(2);
    647             if (argc > 2) {
    648                 fname = argv[2];
    649                 skip(3);
    650             } else {
    651                 fname = find_item(pname, product);
    652                 skip(2);
    653             }
    654             if (fname == 0) die("cannot determine image filename for '%s'", pname);
    655             data = load_file(fname, &sz);
    656             if (data == 0) die("cannot load '%s'\n", fname);
    657             fb_queue_flash(pname, data, sz);
    658         } else if(!strcmp(*argv, "flash:raw")) {
    659             char *pname = argv[1];
    660             char *kname = argv[2];
    661             char *rname = 0;
    662             require(3);
    663             if(argc > 3) {
    664                 rname = argv[3];
    665                 skip(4);
    666             } else {
    667                 skip(3);
    668             }
    669             data = load_bootable_image(page_size, kname, rname, &sz, cmdline);
    670             if (data == 0) die("cannot load bootable image");
    671             fb_queue_flash(pname, data, sz);
    672         } else if(!strcmp(*argv, "flashall")) {
    673             skip(1);
    674             do_flashall();
    675             wants_reboot = 1;
    676         } else if(!strcmp(*argv, "update")) {
    677             if (argc > 1) {
    678                 do_update(argv[1]);
    679                 skip(2);
    680             } else {
    681                 do_update("update.zip");
    682                 skip(1);
    683             }
    684             wants_reboot = 1;
    685         } else if(!strcmp(*argv, "oem")) {
    686             argc = do_oem_command(argc, argv);
    687         } else {
    688             usage();
    689         }
    690     }
    691 
    692     if (wants_wipe) {
    693         fb_queue_erase("userdata");
    694         fb_queue_erase("cache");
    695     }
    696     if (wants_reboot) {
    697         fb_queue_reboot();
    698     } else if (wants_reboot_bootloader) {
    699         fb_queue_command("reboot-bootloader", "rebooting into bootloader");
    700     }
    701 
    702     usb = open_device();
    703 
    704     fb_execute_queue(usb);
    705     return 0;
    706 }
    707