• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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 
get_fastboot_version(void)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 
fixup_tags(unsigned * tags,unsigned * out,const char * cmdline)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 
boot_linux(void)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 */
init_boot_linux(void)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 
rx_cmd(void)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 
rx_data(void)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 
tx_status(const char * status)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 
usb_rx_data_complete(struct usb_request * req,unsigned actual,int status)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 
hex2unsigned(char * x)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 
num_to_hex8(unsigned n,char * out)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 
usb_rx_cmd_complete(struct usb_request * req,unsigned actual,int status)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 
usb_status(unsigned online,unsigned highspeed)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 
usbloader_init(void)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