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