blob: b4e4922572090131fc8b1a511c75f1de3c47038c [file] [log] [blame]
Brian Swetland9c4c0752009-01-25 16:23:50 -08001/*
2 * Copyright (c) 2009, Google Inc.
3 * All rights reserved.
4 *
Channagoud Kadabi526a9592014-04-07 17:56:05 -07005 * Copyright (c) 2013-2014, The Linux Foundation. All rights reserved.
Deepa Dinamani26bc2d32013-03-15 13:17:16 -07006 *
Brian Swetland9c4c0752009-01-25 16:23:50 -08007 * Redistribution and use in source and binary forms, with or without
8 * modification, are permitted provided that the following conditions
9 * are met:
Deepa Dinamani26bc2d32013-03-15 13:17:16 -070010 * * Redistributions of source code must retain the above copyright
11 * notice, this list of conditions and the following disclaimer.
12 * * Redistributions in binary form must reproduce the above copyright
Brian Swetland9c4c0752009-01-25 16:23:50 -080013 * notice, this list of conditions and the following disclaimer in
Deepa Dinamani26bc2d32013-03-15 13:17:16 -070014 * the documentation and/or other materials provided with the
Brian Swetland9c4c0752009-01-25 16:23:50 -080015 * distribution.
16 *
17 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
18 * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
19 * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
20 * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE
21 * COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
22 * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
23 * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS
Deepa Dinamani26bc2d32013-03-15 13:17:16 -070024 * OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED
Brian Swetland9c4c0752009-01-25 16:23:50 -080025 * AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
26 * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT
27 * OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
28 * SUCH DAMAGE.
29 */
30
31#include <debug.h>
32#include <string.h>
33#include <stdlib.h>
Deepa Dinamani0bf2f442012-10-19 11:41:06 -070034#include <platform.h>
Amol Jadi5edf3552013-07-23 14:15:34 -070035#include <target.h>
Brian Swetland9c4c0752009-01-25 16:23:50 -080036#include <kernel/thread.h>
37#include <kernel/event.h>
38#include <dev/udc.h>
Channagoud Kadabia0930b92013-04-16 15:14:37 -070039#include "fastboot.h"
Brian Swetland9c4c0752009-01-25 16:23:50 -080040
Hanumant Singh108cdc62012-12-11 16:48:49 -080041#define MAX_USBFS_BULK_SIZE (32 * 1024)
Shashank Mittal6a5609f2011-08-04 15:51:59 -070042
Brian Swetland9c4c0752009-01-25 16:23:50 -080043void boot_linux(void *bootimg, unsigned sz);
Amol Jadi5edf3552013-07-23 14:15:34 -070044static void fastboot_notify(struct udc_gadget *gadget, unsigned event);
45static struct udc_endpoint *fastboot_endpoints[2];
46
47static struct udc_device surf_udc_device = {
48 .vendor_id = 0x18d1,
49 .product_id = 0xD00D,
50 .version_id = 0x0100,
51 .manufacturer = "Google",
52 .product = "Android",
53};
54
55static struct udc_gadget fastboot_gadget = {
56 .notify = fastboot_notify,
57 .ifc_class = 0xff,
58 .ifc_subclass = 0x42,
59 .ifc_protocol = 0x03,
60 .ifc_endpoints = 2,
61 .ifc_string = "fastboot",
62 .ept = fastboot_endpoints,
63};
Brian Swetland9c4c0752009-01-25 16:23:50 -080064
65/* todo: give lk strtoul and nuke this */
66static unsigned hex2unsigned(const char *x)
67{
68 unsigned n = 0;
69
70 while(*x) {
71 switch(*x) {
72 case '0': case '1': case '2': case '3': case '4':
73 case '5': case '6': case '7': case '8': case '9':
74 n = (n << 4) | (*x - '0');
75 break;
76 case 'a': case 'b': case 'c':
77 case 'd': case 'e': case 'f':
78 n = (n << 4) | (*x - 'a' + 10);
79 break;
80 case 'A': case 'B': case 'C':
81 case 'D': case 'E': case 'F':
82 n = (n << 4) | (*x - 'A' + 10);
83 break;
84 default:
85 return n;
86 }
87 x++;
88 }
89
90 return n;
91}
92
93struct fastboot_cmd {
94 struct fastboot_cmd *next;
95 const char *prefix;
96 unsigned prefix_len;
97 void (*handle)(const char *arg, void *data, unsigned sz);
98};
99
100struct fastboot_var {
101 struct fastboot_var *next;
102 const char *name;
103 const char *value;
104};
Amol Jadi5edf3552013-07-23 14:15:34 -0700105
Brian Swetland9c4c0752009-01-25 16:23:50 -0800106static struct fastboot_cmd *cmdlist;
107
108void fastboot_register(const char *prefix,
109 void (*handle)(const char *arg, void *data, unsigned sz))
110{
111 struct fastboot_cmd *cmd;
112 cmd = malloc(sizeof(*cmd));
113 if (cmd) {
114 cmd->prefix = prefix;
115 cmd->prefix_len = strlen(prefix);
116 cmd->handle = handle;
117 cmd->next = cmdlist;
118 cmdlist = cmd;
119 }
120}
121
122static struct fastboot_var *varlist;
123
124void fastboot_publish(const char *name, const char *value)
125{
126 struct fastboot_var *var;
127 var = malloc(sizeof(*var));
128 if (var) {
129 var->name = name;
130 var->value = value;
131 var->next = varlist;
132 varlist = var;
133 }
134}
135
136
137static event_t usb_online;
138static event_t txn_done;
Brian Swetland9c4c0752009-01-25 16:23:50 -0800139static struct udc_endpoint *in, *out;
140static struct udc_request *req;
141int txn_status;
142
143static void *download_base;
144static unsigned download_max;
145static unsigned download_size;
146
147#define STATE_OFFLINE 0
148#define STATE_COMMAND 1
149#define STATE_COMPLETE 2
150#define STATE_ERROR 3
151
152static unsigned fastboot_state = STATE_OFFLINE;
153
154static void req_complete(struct udc_request *req, unsigned actual, int status)
155{
156 txn_status = status;
157 req->length = actual;
Hanumant Singh108cdc62012-12-11 16:48:49 -0800158
Brian Swetland9c4c0752009-01-25 16:23:50 -0800159 event_signal(&txn_done, 0);
160}
161
Amol Jadi5e52d722013-08-19 17:10:33 -0700162#ifdef USB30_SUPPORT
163static int usb_read(void *buf, unsigned len)
164{
165 int r;
166 struct udc_request req;
167
168 ASSERT(buf);
169 ASSERT(len);
170
171 if (fastboot_state == STATE_ERROR)
172 goto oops;
173
174 dprintf(SPEW, "usb_read(): len = %d\n", len);
175
176 req.buf = (void*) PA((addr_t)buf);
177 req.length = len;
178 req.complete = req_complete;
179
180 r = udc_request_queue(out, &req);
181 if (r < 0)
182 {
183 dprintf(CRITICAL, "usb_read() queue failed. r = %d\n", r);
184 goto oops;
185 }
186 event_wait(&txn_done);
187
188 if (txn_status < 0)
189 {
190 dprintf(CRITICAL, "usb_read() transaction failed. txn_status = %d\n",
191 txn_status);
192 goto oops;
193 }
194
195 /* note: req->length is update by callback to reflect the amount of data
196 * actually read.
197 */
198 dprintf(SPEW, "usb_read(): DONE. req.length = %d\n", req.length);
199
200 /* invalidate any cached buf data (controller updates main memory) */
201 arch_invalidate_cache_range((addr_t) buf, len);
202
203 return req.length;
204
205oops:
206 fastboot_state = STATE_ERROR;
207 dprintf(CRITICAL, "usb_read(): DONE: ERROR: len = %d\n", len);
208 return -1;
209}
210
211static int usb_write(void *buf, unsigned len)
212{
213 int r;
214 struct udc_request req;
215
216 ASSERT(buf);
217 ASSERT(len);
218
219 if (fastboot_state == STATE_ERROR)
220 goto oops;
221
222 dprintf(SPEW, "usb_write(): len = %d str = %s\n", len, (char *) buf);
223
224 /* flush buffer to main memory before giving to udc */
225 arch_clean_invalidate_cache_range((addr_t) buf, len);
226
227 req.buf = (void*) PA((addr_t)buf);
228 req.length = len;
229 req.complete = req_complete;
230
231 r = udc_request_queue(in, &req);
232 if (r < 0) {
233 dprintf(CRITICAL, "usb_write() queue failed. r = %d\n", r);
234 goto oops;
235 }
236 event_wait(&txn_done);
237
238 dprintf(SPEW, "usb_write(): DONE: len = %d req->length = %d str = %s\n",
239 len, req.length, (char *) buf);
240
241 if (txn_status < 0) {
242 dprintf(CRITICAL, "usb_write() transaction failed. txn_status = %d\n",
243 txn_status);
244 goto oops;
245 }
246
247 return req.length;
248
249oops:
250 fastboot_state = STATE_ERROR;
251 dprintf(CRITICAL, "usb_write(): DONE: ERROR: len = %d\n", len);
252 return -1;
253}
254
255#else
Brian Swetland9c4c0752009-01-25 16:23:50 -0800256static int usb_read(void *_buf, unsigned len)
257{
258 int r;
259 unsigned xfer;
260 unsigned char *buf = _buf;
261 int count = 0;
262
263 if (fastboot_state == STATE_ERROR)
264 goto oops;
265
266 while (len > 0) {
Shashank Mittal1cc65b02011-12-20 15:30:17 -0800267 xfer = (len > MAX_USBFS_BULK_SIZE) ? MAX_USBFS_BULK_SIZE : len;
Deepa Dinamani0bf2f442012-10-19 11:41:06 -0700268 req->buf = PA((addr_t)buf);
Brian Swetland9c4c0752009-01-25 16:23:50 -0800269 req->length = xfer;
270 req->complete = req_complete;
271 r = udc_request_queue(out, req);
272 if (r < 0) {
273 dprintf(INFO, "usb_read() queue failed\n");
274 goto oops;
275 }
276 event_wait(&txn_done);
277
278 if (txn_status < 0) {
279 dprintf(INFO, "usb_read() transaction failed\n");
280 goto oops;
281 }
282
283 count += req->length;
284 buf += req->length;
285 len -= req->length;
286
287 /* short transfer? */
288 if (req->length != xfer) break;
289 }
Hanumant Singh108cdc62012-12-11 16:48:49 -0800290 /*
291 * Force reload of buffer from memory
292 * since transaction is complete now.
293 */
294 arch_invalidate_cache_range(_buf, count);
Brian Swetland9c4c0752009-01-25 16:23:50 -0800295 return count;
296
297oops:
298 fastboot_state = STATE_ERROR;
299 return -1;
300}
301
302static int usb_write(void *buf, unsigned len)
303{
304 int r;
Channagoud Kadabi526a9592014-04-07 17:56:05 -0700305 uint32_t xfer;
306 unsigned char *_buf = buf;
307 int count = 0;
Brian Swetland9c4c0752009-01-25 16:23:50 -0800308
309 if (fastboot_state == STATE_ERROR)
310 goto oops;
311
Channagoud Kadabi526a9592014-04-07 17:56:05 -0700312 while (len > 0) {
313 xfer = (len > MAX_USBFS_BULK_SIZE) ? MAX_USBFS_BULK_SIZE : len;
314 req->buf = PA((addr_t)_buf);
315 req->length = xfer;
316 req->complete = req_complete;
317 r = udc_request_queue(in, req);
318 if (r < 0) {
319 dprintf(INFO, "usb_write() queue failed\n");
320 goto oops;
321 }
322 event_wait(&txn_done);
323 if (txn_status < 0) {
324 dprintf(INFO, "usb_write() transaction failed\n");
325 goto oops;
326 }
327
328 count += req->length;
329 _buf += req->length;
330 len -= req->length;
331
332 /* short transfer? */
333 if (req->length != xfer) break;
Brian Swetland9c4c0752009-01-25 16:23:50 -0800334 }
Channagoud Kadabi526a9592014-04-07 17:56:05 -0700335
336 return count;
Brian Swetland9c4c0752009-01-25 16:23:50 -0800337
338oops:
339 fastboot_state = STATE_ERROR;
340 return -1;
341}
Amol Jadi5e52d722013-08-19 17:10:33 -0700342#endif
Brian Swetland9c4c0752009-01-25 16:23:50 -0800343
344void fastboot_ack(const char *code, const char *reason)
345{
Deepa Dinamani26bc2d32013-03-15 13:17:16 -0700346 STACKBUF_DMA_ALIGN(response, MAX_RSP_SIZE);
Brian Swetland9c4c0752009-01-25 16:23:50 -0800347
348 if (fastboot_state != STATE_COMMAND)
349 return;
350
351 if (reason == 0)
352 reason = "";
353
Shashank Mittal6a5609f2011-08-04 15:51:59 -0700354 snprintf(response, MAX_RSP_SIZE, "%s%s", code, reason);
Brian Swetland9c4c0752009-01-25 16:23:50 -0800355 fastboot_state = STATE_COMPLETE;
356
357 usb_write(response, strlen(response));
358
359}
360
Shashank Mittal6a5609f2011-08-04 15:51:59 -0700361void fastboot_info(const char *reason)
362{
Deepa Dinamani26bc2d32013-03-15 13:17:16 -0700363 STACKBUF_DMA_ALIGN(response, MAX_RSP_SIZE);
Shashank Mittal6a5609f2011-08-04 15:51:59 -0700364
365 if (fastboot_state != STATE_COMMAND)
366 return;
367
368 if (reason == 0)
369 return;
370
371 snprintf(response, MAX_RSP_SIZE, "INFO%s", reason);
372
373 usb_write(response, strlen(response));
374}
375
Brian Swetland9c4c0752009-01-25 16:23:50 -0800376void fastboot_fail(const char *reason)
377{
378 fastboot_ack("FAIL", reason);
379}
380
381void fastboot_okay(const char *info)
382{
383 fastboot_ack("OKAY", info);
384}
385
386static void cmd_getvar(const char *arg, void *data, unsigned sz)
387{
388 struct fastboot_var *var;
389
390 for (var = varlist; var; var = var->next) {
391 if (!strcmp(var->name, arg)) {
392 fastboot_okay(var->value);
393 return;
394 }
395 }
396 fastboot_okay("");
397}
398
399static void cmd_download(const char *arg, void *data, unsigned sz)
400{
Deepa Dinamani26bc2d32013-03-15 13:17:16 -0700401 STACKBUF_DMA_ALIGN(response, MAX_RSP_SIZE);
Brian Swetland9c4c0752009-01-25 16:23:50 -0800402 unsigned len = hex2unsigned(arg);
403 int r;
404
405 download_size = 0;
406 if (len > download_max) {
407 fastboot_fail("data too large");
408 return;
409 }
410
Ajay Dudanif63d02f2011-10-01 08:29:53 -0700411 snprintf(response, MAX_RSP_SIZE, "DATA%08x", len);
Brian Swetland9c4c0752009-01-25 16:23:50 -0800412 if (usb_write(response, strlen(response)) < 0)
413 return;
414
415 r = usb_read(download_base, len);
Greg Griscod6250552011-06-29 14:40:23 -0700416 if ((r < 0) || ((unsigned) r != len)) {
Brian Swetland9c4c0752009-01-25 16:23:50 -0800417 fastboot_state = STATE_ERROR;
418 return;
419 }
420 download_size = len;
421 fastboot_okay("");
422}
423
424static void fastboot_command_loop(void)
425{
426 struct fastboot_cmd *cmd;
427 int r;
428 dprintf(INFO,"fastboot: processing commands\n");
429
Deepa Dinamani26bc2d32013-03-15 13:17:16 -0700430 uint8_t *buffer = (uint8_t *)memalign(CACHE_LINE, ROUNDUP(4096, CACHE_LINE));
431 if (!buffer)
432 {
433 dprintf(CRITICAL, "Could not allocate memory for fastboot buffer\n.");
434 ASSERT(0);
435 }
Brian Swetland9c4c0752009-01-25 16:23:50 -0800436again:
437 while (fastboot_state != STATE_ERROR) {
Amol Jadi5edf3552013-07-23 14:15:34 -0700438
439 /* Read buffer must be cleared first. If buffer is not cleared,
440 * the original data in buf trailing the received command is
441 * interpreted as part of the command.
442 */
443 memset(buffer, 0, MAX_RSP_SIZE);
444 arch_clean_invalidate_cache_range((addr_t) buffer, MAX_RSP_SIZE);
445
Shashank Mittal6a5609f2011-08-04 15:51:59 -0700446 r = usb_read(buffer, MAX_RSP_SIZE);
Brian Swetland9c4c0752009-01-25 16:23:50 -0800447 if (r < 0) break;
448 buffer[r] = 0;
449 dprintf(INFO,"fastboot: %s\n", buffer);
450
451 for (cmd = cmdlist; cmd; cmd = cmd->next) {
452 if (memcmp(buffer, cmd->prefix, cmd->prefix_len))
453 continue;
454 fastboot_state = STATE_COMMAND;
455 cmd->handle((const char*) buffer + cmd->prefix_len,
456 (void*) download_base, download_size);
457 if (fastboot_state == STATE_COMMAND)
458 fastboot_fail("unknown reason");
459 goto again;
460 }
461
462 fastboot_fail("unknown command");
Amol Jadi5edf3552013-07-23 14:15:34 -0700463
Brian Swetland9c4c0752009-01-25 16:23:50 -0800464 }
465 fastboot_state = STATE_OFFLINE;
466 dprintf(INFO,"fastboot: oops!\n");
Deepa Dinamani26bc2d32013-03-15 13:17:16 -0700467 free(buffer);
Brian Swetland9c4c0752009-01-25 16:23:50 -0800468}
469
470static int fastboot_handler(void *arg)
471{
472 for (;;) {
473 event_wait(&usb_online);
474 fastboot_command_loop();
475 }
476 return 0;
477}
478
479static void fastboot_notify(struct udc_gadget *gadget, unsigned event)
480{
481 if (event == UDC_EVENT_ONLINE) {
482 event_signal(&usb_online, 0);
483 }
484}
485
Brian Swetland9c4c0752009-01-25 16:23:50 -0800486int fastboot_init(void *base, unsigned size)
487{
Amol Jadi5edf3552013-07-23 14:15:34 -0700488 char sn_buf[13];
Brian Swetland9c4c0752009-01-25 16:23:50 -0800489 thread_t *thr;
490 dprintf(INFO, "fastboot_init()\n");
491
492 download_base = base;
493 download_max = size;
494
Amol Jadi5edf3552013-07-23 14:15:34 -0700495 /* target specific initialization before going into fastboot. */
496 target_fastboot_init();
497
498 /* setup serialno */
499 target_serialno((unsigned char *) sn_buf);
500 dprintf(SPEW,"serial number: %s\n",sn_buf);
501 surf_udc_device.serialno = sn_buf;
502
503 /* register udc device */
504 udc_init(&surf_udc_device);
505
Brian Swetland9c4c0752009-01-25 16:23:50 -0800506 event_init(&usb_online, 0, EVENT_FLAG_AUTOUNSIGNAL);
507 event_init(&txn_done, 0, EVENT_FLAG_AUTOUNSIGNAL);
508
509 in = udc_endpoint_alloc(UDC_TYPE_BULK_IN, 512);
510 if (!in)
511 goto fail_alloc_in;
512 out = udc_endpoint_alloc(UDC_TYPE_BULK_OUT, 512);
513 if (!out)
514 goto fail_alloc_out;
515
516 fastboot_endpoints[0] = in;
517 fastboot_endpoints[1] = out;
518
519 req = udc_request_alloc();
520 if (!req)
521 goto fail_alloc_req;
522
Amol Jadi5edf3552013-07-23 14:15:34 -0700523 /* register gadget */
Brian Swetland9c4c0752009-01-25 16:23:50 -0800524 if (udc_register_gadget(&fastboot_gadget))
525 goto fail_udc_register;
526
527 fastboot_register("getvar:", cmd_getvar);
528 fastboot_register("download:", cmd_download);
529 fastboot_publish("version", "0.5");
530
531 thr = thread_create("fastboot", fastboot_handler, 0, DEFAULT_PRIORITY, 4096);
neetid32ba8472011-12-07 16:34:06 -0800532 if (!thr)
533 {
534 goto fail_alloc_in;
535 }
Brian Swetland9c4c0752009-01-25 16:23:50 -0800536 thread_resume(thr);
Amol Jadi5edf3552013-07-23 14:15:34 -0700537
538 udc_start();
539
Brian Swetland9c4c0752009-01-25 16:23:50 -0800540 return 0;
541
542fail_udc_register:
543 udc_request_free(req);
544fail_alloc_req:
Amol Jadi5edf3552013-07-23 14:15:34 -0700545 udc_endpoint_free(out);
Brian Swetland9c4c0752009-01-25 16:23:50 -0800546fail_alloc_out:
547 udc_endpoint_free(in);
548fail_alloc_in:
549 return -1;
550}