blob: 5d86e709c23c5c8f03cf2713126e42e16d337a48
1 | /* |
2 | * (C) Copyright 2008 - 2009 |
3 | * Windriver, <www.windriver.com> |
4 | * Tom Rix <Tom.Rix@windriver.com> |
5 | * |
6 | * Copyright 2011 Sebastian Andrzej Siewior <bigeasy@linutronix.de> |
7 | * |
8 | * Copyright 2014 Linaro, Ltd. |
9 | * Rob Herring <robh@kernel.org> |
10 | * |
11 | * SPDX-License-Identifier: GPL-2.0+ |
12 | */ |
13 | #include <config.h> |
14 | #include <common.h> |
15 | #include <errno.h> |
16 | #include <malloc.h> |
17 | #include <linux/usb/ch9.h> |
18 | #include <linux/usb/gadget.h> |
19 | #include <linux/usb/composite.h> |
20 | #include <linux/compiler.h> |
21 | #include <version.h> |
22 | #include <g_dnl.h> |
23 | #include <asm/arch/cpu.h> |
24 | #ifdef CONFIG_FASTBOOT_FLASH_MMC_DEV |
25 | #include <fb_mmc.h> |
26 | #include <fb_storage.h> |
27 | #include <fb_fastboot.h> |
28 | #include <emmc_partitions.h> |
29 | #endif |
30 | #ifdef CONFIG_FASTBOOT_FLASH_NAND_DEV |
31 | #include <fb_nand.h> |
32 | #endif |
33 | #include <partition_table.h> |
34 | #include <android_image.h> |
35 | #include <image.h> |
36 | #ifdef CONFIG_AML_ANTIROLLBACK |
37 | #include <anti-rollback.h> |
38 | #endif |
39 | |
40 | DECLARE_GLOBAL_DATA_PTR; |
41 | |
42 | #define FASTBOOT_VERSION "0.4" |
43 | |
44 | #define FASTBOOT_INTERFACE_CLASS 0xff |
45 | #define FASTBOOT_INTERFACE_SUB_CLASS 0x42 |
46 | #define FASTBOOT_INTERFACE_PROTOCOL 0x03 |
47 | |
48 | #define ENDPOINT_MAXIMUM_PACKET_SIZE_2_0 (0x0200) |
49 | |
50 | #ifdef CONFIG_DEVICE_PRODUCT |
51 | #define DEVICE_PRODUCT CONFIG_DEVICE_PRODUCT |
52 | #endif |
53 | #define DEVICE_SERIAL "1234567890" |
54 | |
55 | #define FB_ERR(fmt ...) printf("[ERR]%sL%d:", __func__, __LINE__),printf(fmt) |
56 | #define FB_MSG(fmt ...) printf("[MSG]"fmt) |
57 | #define FB_WRN(fmt ...) printf("[WRN]"fmt) |
58 | #define FB_DBG(...) |
59 | #define FB_HERE() printf("f(%s)L%d\n", __func__, __LINE__) |
60 | |
61 | extern void f_dwc_otg_pullup(int is_on); |
62 | |
63 | #ifdef CONFIG_BOOTLOADER_CONTROL_BLOCK |
64 | extern int is_partition_logical(char* parition_name); |
65 | #endif |
66 | |
67 | /* The 64 defined bytes plus \0 */ |
68 | |
69 | #define EP_BUFFER_SIZE 4096 |
70 | |
71 | struct f_fastboot { |
72 | struct usb_function usb_function; |
73 | |
74 | /* IN/OUT EP's and corresponding requests */ |
75 | struct usb_ep *in_ep, *out_ep; |
76 | struct usb_request *in_req, *out_req; |
77 | }; |
78 | |
79 | static inline struct f_fastboot *func_to_fastboot(struct usb_function *f) |
80 | { |
81 | return container_of(f, struct f_fastboot, usb_function); |
82 | } |
83 | |
84 | static struct f_fastboot *fastboot_func; |
85 | static unsigned int download_size; |
86 | static unsigned int download_bytes; |
87 | |
88 | |
89 | static struct usb_endpoint_descriptor ep_in = { |
90 | .bLength = USB_DT_ENDPOINT_SIZE, |
91 | .bDescriptorType = USB_DT_ENDPOINT, |
92 | .bEndpointAddress = USB_DIR_IN, |
93 | .bmAttributes = USB_ENDPOINT_XFER_BULK, |
94 | .wMaxPacketSize = ENDPOINT_MAXIMUM_PACKET_SIZE_2_0, |
95 | .bInterval = 0x00, |
96 | }; |
97 | |
98 | static struct usb_endpoint_descriptor ep_out = { |
99 | .bLength = USB_DT_ENDPOINT_SIZE, |
100 | .bDescriptorType = USB_DT_ENDPOINT, |
101 | .bEndpointAddress = USB_DIR_OUT, |
102 | .bmAttributes = USB_ENDPOINT_XFER_BULK, |
103 | .wMaxPacketSize = ENDPOINT_MAXIMUM_PACKET_SIZE_2_0, |
104 | .bInterval = 0x00, |
105 | }; |
106 | |
107 | static struct usb_interface_descriptor interface_desc = { |
108 | .bLength = USB_DT_INTERFACE_SIZE, |
109 | .bDescriptorType = USB_DT_INTERFACE, |
110 | .bInterfaceNumber = 0x00, |
111 | .bAlternateSetting = 0x00, |
112 | .bNumEndpoints = 0x02, |
113 | .bInterfaceClass = FASTBOOT_INTERFACE_CLASS, |
114 | .bInterfaceSubClass = FASTBOOT_INTERFACE_SUB_CLASS, |
115 | .bInterfaceProtocol = FASTBOOT_INTERFACE_PROTOCOL, |
116 | }; |
117 | |
118 | static struct usb_descriptor_header *fb_runtime_descs[] = { |
119 | (struct usb_descriptor_header *)&interface_desc, |
120 | (struct usb_descriptor_header *)&ep_in, |
121 | (struct usb_descriptor_header *)&ep_out, |
122 | NULL, |
123 | }; |
124 | |
125 | /* |
126 | * static strings, in UTF-8 |
127 | */ |
128 | static const char fastboot_name[] = "Android Fastboot"; |
129 | |
130 | static struct usb_string fastboot_string_defs[] = { |
131 | [0].s = fastboot_name, |
132 | { } /* end of list */ |
133 | }; |
134 | |
135 | static struct usb_gadget_strings stringtab_fastboot = { |
136 | .language = 0x0409, /* en-us */ |
137 | .strings = fastboot_string_defs, |
138 | }; |
139 | |
140 | static struct usb_gadget_strings *fastboot_strings[] = { |
141 | &stringtab_fastboot, |
142 | NULL, |
143 | }; |
144 | |
145 | #define DRAM_UBOOT_RESERVE 0x01000000 |
146 | unsigned int ddr_size_usable(unsigned int addr_start) |
147 | { |
148 | unsigned int ddr_size=0; |
149 | unsigned int free_size = 0; |
150 | int i; |
151 | |
152 | for (i = 0; i < CONFIG_NR_DRAM_BANKS; i++) |
153 | ddr_size += gd->bd->bi_dram[i].size; |
154 | |
155 | free_size = (ddr_size - DRAM_UBOOT_RESERVE - addr_start - CONFIG_SYS_MALLOC_LEN - CONFIG_SYS_MEM_TOP_HIDE); |
156 | #if defined CONFIG_FASTBOOT_MAX_DOWN_SIZE |
157 | if (free_size > CONFIG_FASTBOOT_MAX_DOWN_SIZE) |
158 | free_size = CONFIG_FASTBOOT_MAX_DOWN_SIZE; |
159 | #endif |
160 | return free_size; |
161 | } |
162 | |
163 | static void rx_handler_command(struct usb_ep *ep, struct usb_request *req); |
164 | |
165 | static char response_str[RESPONSE_LEN + 1]; |
166 | |
167 | void fastboot_fail(const char *s) |
168 | { |
169 | strncpy(response_str, "FAIL", 4); |
170 | if (s)strncat(response_str, s, RESPONSE_LEN - 4 - 1) ; |
171 | } |
172 | |
173 | void fastboot_okay(const char *s) |
174 | { |
175 | strncpy(response_str, "OKAY", 4); |
176 | if (s)strncat(response_str, s, RESPONSE_LEN - 4 - 1) ; |
177 | } |
178 | |
179 | void fastboot_busy(const char* s) |
180 | { |
181 | strncpy(response_str, "INFO", 4 + 1);//add terminated 0 |
182 | if (s)strncat(response_str, s, RESPONSE_LEN - 4 - 1) ; |
183 | } |
184 | int fastboot_is_busy(void) |
185 | { |
186 | return !strncmp("INFO", response_str, strlen("INFO")); |
187 | } |
188 | |
189 | //cb for bulk in_req->complete |
190 | static void fastboot_complete(struct usb_ep *ep, struct usb_request *req) |
191 | { |
192 | int status = req->status; |
193 | |
194 | if ( fastboot_is_busy() && fastboot_func) { |
195 | struct usb_ep* out_ep = fastboot_func->out_ep; |
196 | struct usb_request* out_req = fastboot_func->out_req; |
197 | rx_handler_command(out_ep, out_req); |
198 | return; |
199 | } |
200 | if (!status) |
201 | return; |
202 | printf("status: %d ep '%s' trans: %d\n", status, ep->name, req->actual); |
203 | } |
204 | |
205 | static int fastboot_bind(struct usb_configuration *c, struct usb_function *f) |
206 | { |
207 | int id; |
208 | struct usb_gadget *gadget = c->cdev->gadget; |
209 | struct f_fastboot *f_fb = func_to_fastboot(f); |
210 | |
211 | /* DYNAMIC interface numbers assignments */ |
212 | id = usb_interface_id(c, f); |
213 | if (id < 0) |
214 | return id; |
215 | interface_desc.bInterfaceNumber = id; |
216 | |
217 | id = usb_string_id(c->cdev); |
218 | if (id < 0) |
219 | return id; |
220 | fastboot_string_defs[0].id = id; |
221 | interface_desc.iInterface = id; |
222 | |
223 | f_fb->in_ep = usb_ep_autoconfig(gadget, &ep_in); |
224 | if (!f_fb->in_ep) |
225 | return -ENODEV; |
226 | f_fb->in_ep->driver_data = c->cdev; |
227 | |
228 | f_fb->out_ep = usb_ep_autoconfig(gadget, &ep_out); |
229 | if (!f_fb->out_ep) |
230 | return -ENODEV; |
231 | f_fb->out_ep->driver_data = c->cdev; |
232 | |
233 | return 0; |
234 | } |
235 | |
236 | static void fastboot_unbind(struct usb_configuration *c, struct usb_function *f) |
237 | { |
238 | memset(fastboot_func, 0, sizeof(*fastboot_func)); |
239 | } |
240 | |
241 | static void fastboot_disable(struct usb_function *f) |
242 | { |
243 | struct f_fastboot *f_fb = func_to_fastboot(f); |
244 | |
245 | usb_ep_disable(f_fb->out_ep); |
246 | usb_ep_disable(f_fb->in_ep); |
247 | |
248 | if (f_fb->out_req) { |
249 | free(f_fb->out_req->buf); |
250 | usb_ep_free_request(f_fb->out_ep, f_fb->out_req); |
251 | f_fb->out_req = NULL; |
252 | } |
253 | if (f_fb->in_req) { |
254 | free(f_fb->in_req->buf); |
255 | usb_ep_free_request(f_fb->in_ep, f_fb->in_req); |
256 | f_fb->in_req = NULL; |
257 | } |
258 | } |
259 | |
260 | static struct usb_request *fastboot_start_ep(struct usb_ep *ep) |
261 | { |
262 | struct usb_request *req; |
263 | |
264 | req = usb_ep_alloc_request(ep, 0); |
265 | if (!req) |
266 | return NULL; |
267 | |
268 | req->length = EP_BUFFER_SIZE; |
269 | req->buf = memalign(CONFIG_SYS_CACHELINE_SIZE, EP_BUFFER_SIZE); |
270 | if (!req->buf) { |
271 | usb_ep_free_request(ep, req); |
272 | return NULL; |
273 | } |
274 | |
275 | memset(req->buf, 0, req->length); |
276 | return req; |
277 | } |
278 | |
279 | static int fastboot_set_alt(struct usb_function *f, |
280 | unsigned interface, unsigned alt) |
281 | { |
282 | int ret; |
283 | struct f_fastboot *f_fb = func_to_fastboot(f); |
284 | |
285 | debug("%s: func: %s intf: %d alt: %d\n", |
286 | __func__, f->name, interface, alt); |
287 | |
288 | /* make sure we don't enable the ep twice */ |
289 | ret = usb_ep_enable(f_fb->out_ep, &ep_out); |
290 | if (ret) { |
291 | puts("failed to enable out ep\n"); |
292 | return ret; |
293 | } |
294 | |
295 | f_fb->out_req = fastboot_start_ep(f_fb->out_ep); |
296 | if (!f_fb->out_req) { |
297 | puts("failed to alloc out req\n"); |
298 | ret = -EINVAL; |
299 | goto err; |
300 | } |
301 | f_fb->out_req->complete = rx_handler_command; |
302 | |
303 | ret = usb_ep_enable(f_fb->in_ep, &ep_in); |
304 | if (ret) { |
305 | puts("failed to enable in ep\n"); |
306 | goto err; |
307 | } |
308 | |
309 | f_fb->in_req = fastboot_start_ep(f_fb->in_ep); |
310 | if (!f_fb->in_req) { |
311 | puts("failed alloc req in\n"); |
312 | ret = -EINVAL; |
313 | goto err; |
314 | } |
315 | f_fb->in_req->complete = fastboot_complete; |
316 | |
317 | ret = usb_ep_queue(f_fb->out_ep, f_fb->out_req, 0); |
318 | if (ret) |
319 | goto err; |
320 | |
321 | return 0; |
322 | err: |
323 | fastboot_disable(f); |
324 | return ret; |
325 | } |
326 | |
327 | static int fastboot_setup(struct usb_function *f, |
328 | const struct usb_ctrlrequest *ctrl) |
329 | { |
330 | int value = -EOPNOTSUPP; |
331 | struct f_fastboot *f_fb = func_to_fastboot(f); |
332 | |
333 | /* composite driver infrastructure handles everything; interface |
334 | * activation uses set_alt(). |
335 | */ |
336 | if (((ctrl->bRequestType & USB_RECIP_MASK) == USB_RECIP_ENDPOINT) |
337 | && (ctrl->bRequest == USB_REQ_CLEAR_FEATURE) |
338 | && (ctrl->wValue== USB_ENDPOINT_HALT)) { |
339 | switch (ctrl->wIndex & 0xfe) { |
340 | case USB_DIR_OUT: |
341 | value = ctrl->wLength; |
342 | usb_ep_clear_halt(f_fb->out_ep); |
343 | break; |
344 | |
345 | case USB_DIR_IN: |
346 | value = ctrl->wLength; |
347 | usb_ep_clear_halt(f_fb->in_ep); |
348 | break; |
349 | default: |
350 | printf("unknown usb_ctrlrequest\n"); |
351 | break; |
352 | } |
353 | } |
354 | |
355 | return value; |
356 | } |
357 | |
358 | static int fastboot_add(struct usb_configuration *c) |
359 | { |
360 | struct f_fastboot *f_fb = fastboot_func; |
361 | int status; |
362 | |
363 | if (!f_fb) { |
364 | f_fb = memalign(CONFIG_SYS_CACHELINE_SIZE, sizeof(*f_fb)); |
365 | if (!f_fb) |
366 | return -ENOMEM; |
367 | |
368 | fastboot_func = f_fb; |
369 | memset(f_fb, 0, sizeof(*f_fb)); |
370 | } |
371 | |
372 | f_fb->usb_function.name = "f_fastboot"; |
373 | f_fb->usb_function.hs_descriptors = fb_runtime_descs; |
374 | f_fb->usb_function.bind = fastboot_bind; |
375 | f_fb->usb_function.unbind = fastboot_unbind; |
376 | f_fb->usb_function.set_alt = fastboot_set_alt; |
377 | f_fb->usb_function.disable = fastboot_disable; |
378 | f_fb->usb_function.strings = fastboot_strings; |
379 | f_fb->usb_function.setup = fastboot_setup; |
380 | |
381 | status = usb_add_function(c, &f_fb->usb_function); |
382 | if (status) { |
383 | free(f_fb); |
384 | fastboot_func = f_fb; |
385 | } |
386 | |
387 | return status; |
388 | } |
389 | DECLARE_GADGET_BIND_CALLBACK(usb_dnl_fastboot, fastboot_add); |
390 | |
391 | static int fastboot_tx_write(const char *buffer, unsigned int buffer_size) |
392 | { |
393 | struct usb_request *in_req = fastboot_func->in_req; |
394 | int ret; |
395 | |
396 | memcpy(in_req->buf, buffer, buffer_size); |
397 | in_req->length = buffer_size; |
398 | ret = usb_ep_queue(fastboot_func->in_ep, in_req, 0); |
399 | if (ret) |
400 | printf("Error %d on queue\n", ret); |
401 | return 0; |
402 | } |
403 | |
404 | static int fastboot_tx_write_str(const char *buffer) |
405 | { |
406 | return fastboot_tx_write(buffer, strlen(buffer)); |
407 | } |
408 | |
409 | static void compl_do_reset(struct usb_ep *ep, struct usb_request *req) |
410 | { |
411 | do_reset(NULL, 0, 0, NULL); |
412 | } |
413 | |
414 | static void compl_do_reboot_bootloader(struct usb_ep *ep, struct usb_request *req) |
415 | { |
416 | if (dynamic_partition) |
417 | run_command("reboot bootloader", 0); |
418 | else |
419 | run_command("reboot fastboot", 0); |
420 | } |
421 | |
422 | static void compl_do_reboot_fastboot(struct usb_ep *ep, struct usb_request *req) |
423 | { |
424 | f_dwc_otg_pullup(0); |
425 | run_command("reboot fastboot", 0); |
426 | } |
427 | |
428 | static void cb_reboot(struct usb_ep *ep, struct usb_request *req) |
429 | { |
430 | char *cmd = req->buf; |
431 | |
432 | printf("cmd cb_reboot is %s\n", cmd); |
433 | |
434 | strsep(&cmd, "-"); |
435 | if (!cmd) { |
436 | fastboot_func->in_req->complete = compl_do_reset; |
437 | fastboot_tx_write_str("OKAY"); |
438 | return; |
439 | } |
440 | |
441 | printf("cmd cb_reboot is %s\n", cmd); |
442 | if (strcmp(cmd, "bootloader") == 0) |
443 | fastboot_func->in_req->complete = compl_do_reboot_bootloader; |
444 | else if (strcmp(cmd, "fastboot") == 0) |
445 | fastboot_func->in_req->complete = compl_do_reboot_fastboot; |
446 | |
447 | fastboot_tx_write_str("OKAY"); |
448 | } |
449 | |
450 | static int strcmp_l1(const char *s1, const char *s2) |
451 | { |
452 | if (!s1 || !s2) |
453 | return -1; |
454 | return strncmp(s1, s2, strlen(s1)); |
455 | } |
456 | |
457 | void dump_lock_info(LockData_t* info) |
458 | { |
459 | printf("info->version_major = %d\n", info->version_major); |
460 | printf("info->version_minor = %d\n", info->version_minor); |
461 | printf("info->lock_state = %d\n", info->lock_state); |
462 | printf("info->lock_critical_state = %d\n", info->lock_critical_state); |
463 | printf("info->lock_bootloader = %d\n", info->lock_bootloader); |
464 | } |
465 | |
466 | |
467 | static int check_lock(void) |
468 | { |
469 | char *lock_s; |
470 | LockData_t* info; |
471 | |
472 | lock_s = getenv("lock"); |
473 | if (!lock_s) { |
474 | printf("lock state is NULL \n"); |
475 | lock_s = "10000000"; |
476 | setenv("lock", "10000000"); |
477 | run_command("defenv_reserv; saveenv;", 0); |
478 | } |
479 | printf("lock state: %s\n", lock_s); |
480 | |
481 | info = (LockData_t*)malloc(sizeof(struct LockData)); |
482 | memset(info,0,LOCK_DATA_SIZE); |
483 | info->version_major = (int)(lock_s[0] - '0'); |
484 | info->version_minor = (int)(lock_s[1] - '0'); |
485 | info->lock_state = (int)(lock_s[4] - '0'); |
486 | info->lock_critical_state = (int)(lock_s[5] - '0'); |
487 | info->lock_bootloader = (int)(lock_s[6] - '0'); |
488 | |
489 | dump_lock_info(info); |
490 | |
491 | if (( info->lock_state == 1 ) || ( info->lock_critical_state == 1 )) |
492 | return 1; |
493 | else |
494 | return 0; |
495 | } |
496 | |
497 | static const char* getvar_list[] = { |
498 | "version-baseband", "version-bootloader", "version", "hw-revision", "max-download-size", |
499 | "serialno", "product", "off-mode-charge", "variant", "battery-soc-ok", |
500 | "battery-voltage", "partition-type:boot", "partition-size:boot", |
501 | "partition-type:system", "partition-size:system", "partition-type:vendor", "partition-size:vendor", |
502 | "partition-type:odm", "partition-size:odm", "partition-type:data", "partition-size:data", |
503 | "erase-block-size", "logical-block-size", "secure", "unlocked", |
504 | }; |
505 | |
506 | static const char* getvar_list_dynamic[] = { |
507 | "hw-revision", "battery-voltage", "is-userspace", "is-logical:data", |
508 | "is-logical:metadata", "is-logical:misc", "is-logical:super", "is-logical:boot", |
509 | "is-logical:system", "is-logical:vendor", "is-logical:product", "is-logical:odm", |
510 | "slot-count", "max-download-size", "serialno", "product", "unlocked", "has-slot:data", |
511 | "has-slot:metadata", "has-slot:misc", "has-slot:super", "has-slot:boot", |
512 | "has-slot:system", "has-slot:vendor", "has-slot:product", "has-slot:odm", |
513 | "secure", "super-partition-name", "version-baseband", "version-bootloader", |
514 | "partition-size:boot", "partition-size:metadata", "partition-size:misc", |
515 | "partition-size:super", "partition-size:data", "version", |
516 | }; |
517 | |
518 | static const char* getvar_list_ab[] = { |
519 | "version-baseband", "version-bootloader", "version", "hw-revision", "max-download-size", |
520 | "serialno", "product", "off-mode-charge", "variant", "battery-soc-ok", |
521 | "battery-voltage", "partition-type:boot", "partition-size:boot", |
522 | "partition-type:system", "partition-size:system", "partition-type:vendor", "partition-size:vendor", |
523 | "partition-type:odm", "partition-size:odm", "partition-type:data", "partition-size:data", |
524 | "partition-type:cache", "partition-size:cache", |
525 | "erase-block-size", "logical-block-size", "secure", "unlocked", |
526 | "slot-count", "slot-suffixes","current-slot", "has-slot:bootloader", "has-slot:boot", |
527 | "has-slot:system", "has-slot:vendor", "has-slot:odm", "has-slot:vbmeta", |
528 | "has-slot:metadata", "has-slot:product", "has-slot:dtbo", |
529 | "slot-successful:a", "slot-unbootable:a", "slot-retry-count:a", |
530 | "slot-successful:b", "slot-unbootable:b", "slot-retry-count:b", |
531 | }; |
532 | |
533 | static void cb_getvar(struct usb_ep *ep, struct usb_request *req) |
534 | { |
535 | char *cmd = req->buf; |
536 | char cmdBuf[RESPONSE_LEN]; |
537 | char* response = response_str; |
538 | char *s; |
539 | char *s1; |
540 | char *s2; |
541 | char *s3; |
542 | char s_version[24]; |
543 | size_t chars_left; |
544 | |
545 | run_command("get_valid_slot", 0); |
546 | |
547 | strcpy(response, "OKAY"); |
548 | chars_left = sizeof(response_str) - strlen(response) - 1; |
549 | |
550 | memcpy(cmdBuf, cmd, strnlen(cmd, RESPONSE_LEN-1)+1); |
551 | cmd = cmdBuf; |
552 | strsep(&cmd, ":"); |
553 | printf("cb_getvar: %s\n", cmd); |
554 | if (!cmd) { |
555 | error("missing variable\n"); |
556 | fastboot_tx_write_str("FAILmissing var"); |
557 | return; |
558 | } |
559 | if (!strncmp(cmd, "all", 3)) { |
560 | static int cmdIndex = 0; |
561 | int getvar_num; |
562 | if (has_boot_slot == 1) { |
563 | strcpy(cmd, getvar_list_ab[cmdIndex]); |
564 | getvar_num = (sizeof(getvar_list_ab) / sizeof(getvar_list_ab[0])); |
565 | } else if (dynamic_partition) { |
566 | strcpy(cmd, getvar_list_dynamic[cmdIndex]);//only support no-arg cmd |
567 | getvar_num = (sizeof(getvar_list_dynamic) / sizeof(getvar_list_dynamic[0])); |
568 | } else { |
569 | strcpy(cmd, getvar_list[cmdIndex]);//only support no-arg cmd |
570 | getvar_num = (sizeof(getvar_list) / sizeof(getvar_list[0])); |
571 | } |
572 | printf("getvar_num: %d\n", getvar_num); |
573 | if ( ++cmdIndex >= getvar_num) cmdIndex = 0; |
574 | else fastboot_busy(NULL); |
575 | FB_MSG("all cmd:%s\n", cmd); |
576 | strncat(response, cmd, chars_left); |
577 | strncat(response, ":", 1); |
578 | chars_left -= strlen(cmd) + 1; |
579 | } |
580 | |
581 | strcpy(s_version, "01.01."); |
582 | printf("U_BOOT_DATE_TIME: %s\n", U_BOOT_DATE_TIME); |
583 | strcat(s_version, U_BOOT_DATE_TIME); |
584 | printf("s_version: %s\n", s_version); |
585 | |
586 | if (!strcmp_l1("version-baseband", cmd)) { |
587 | strncat(response, "N/A", chars_left); |
588 | } else if (!strcmp_l1("version-bootloader", cmd)) { |
589 | strncat(response, s_version, chars_left); |
590 | } else if (!strcmp_l1("hw-revision", cmd)) { |
591 | strncat(response, "0", chars_left); |
592 | } else if (!strcmp_l1("version", cmd)) { |
593 | strncat(response, FASTBOOT_VERSION, chars_left); |
594 | } else if (!strcmp_l1("bootloader-version", cmd)) { |
595 | strncat(response, s_version, chars_left); |
596 | } else if (!strcmp_l1("off-mode-charge", cmd)) { |
597 | strncat(response, "0", chars_left); |
598 | } else if (!strcmp_l1("variant", cmd)) { |
599 | strncat(response, "US", chars_left); |
600 | } else if (!strcmp_l1("battery-soc-ok", cmd)) { |
601 | strncat(response, "yes", chars_left); |
602 | } else if (!strcmp_l1("battery-voltage", cmd)) { |
603 | strncat(response, "4", chars_left); |
604 | } else if (!strcmp_l1("is-userspace", cmd)) { |
605 | if (dynamic_partition) { |
606 | strncat(response, "no", chars_left); |
607 | } else { |
608 | error("unknown variable: %s\n", cmd); |
609 | strcpy(response, "FAILVariable not implemented"); |
610 | } |
611 | } else if (!strcmp_l1("is-logical", cmd)) { |
612 | strsep(&cmd, ":"); |
613 | printf("partition is %s\n", cmd); |
614 | if (!dynamic_partition) { |
615 | strncat(response, "no", chars_left); |
616 | } else { |
617 | #ifdef CONFIG_BOOTLOADER_CONTROL_BLOCK |
618 | if (is_partition_logical(cmd) == 0) { |
619 | error("%s is logic partition\n", cmd); |
620 | strncat(response, "yes", chars_left); |
621 | } else { |
622 | strncat(response, "no", chars_left); |
623 | } |
624 | #else |
625 | strncat(response, "no", chars_left); |
626 | #endif |
627 | } |
628 | } else if (!strcmp_l1("super-partition-name", cmd)) { |
629 | char *slot_name; |
630 | slot_name = getenv("slot-suffixes"); |
631 | if (has_boot_slot == 0) { |
632 | strncat(response, "super", chars_left); |
633 | } else { |
634 | printf("slot-suffixes: %s\n", slot_name); |
635 | if (strcmp(slot_name, "0") == 0) { |
636 | printf("active_slot is %s\n", "a"); |
637 | strncat(response, "super_a", chars_left); |
638 | } else if (strcmp(slot_name, "1") == 0) { |
639 | printf("active_slot is %s\n", "b"); |
640 | strncat(response, "super_b", chars_left); |
641 | } |
642 | } |
643 | } else if (!strcmp_l1("downloadsize", cmd) || |
644 | !strcmp_l1("max-download-size", cmd)) { |
645 | char str_num[12]; |
646 | |
647 | sprintf(str_num, "0x%08x", ddr_size_usable(CONFIG_USB_FASTBOOT_BUF_ADDR)); |
648 | strncat(response, str_num, chars_left); |
649 | } else if (!strcmp_l1("serialno", cmd)) { |
650 | //s = getenv("serial"); |
651 | s = get_usid_string(); |
652 | if (s) |
653 | strncat(response, s, chars_left); |
654 | else |
655 | strncat(response, DEVICE_SERIAL, chars_left); |
656 | } else if (!strcmp_l1("product", cmd)) { |
657 | #ifdef DEVICE_PRODUCT |
658 | s1 = DEVICE_PRODUCT; |
659 | printf("DEVICE_PRODUCT: %s\n", s1); |
660 | #else |
661 | s1 = getenv("device_product"); |
662 | printf("device_product: %s\n", s1); |
663 | #endif |
664 | strncat(response, s1, chars_left); |
665 | } else if (!strcmp_l1("slot-count", cmd)) { |
666 | if (has_boot_slot == 1) |
667 | strncat(response, "2", chars_left); |
668 | else |
669 | strncat(response, "0", chars_left); |
670 | } else if (!strcmp_l1("slot-suffixes", cmd)) { |
671 | s2 = getenv("slot-suffixes"); |
672 | printf("slot-suffixes: %s\n", s2); |
673 | if (s2) |
674 | strncat(response, s2, chars_left); |
675 | else |
676 | strncat(response, "0", chars_left); |
677 | } else if (!strcmp_l1("current-slot", cmd)) { |
678 | s3 = getenv("slot-suffixes"); |
679 | printf("slot-suffixes: %s\n", s3); |
680 | if (strcmp(s3, "0") == 0) { |
681 | printf("active_slot is %s\n", "a"); |
682 | strncat(response, "a", chars_left); |
683 | } else if (strcmp(s3, "1") == 0) { |
684 | printf("active_slot is %s\n", "b"); |
685 | strncat(response, "b", chars_left); |
686 | } |
687 | } else if (!strcmp_l1("has-slot:bootloader", cmd)) { |
688 | printf("do not has slot bootloader\n"); |
689 | strncat(response, "no", chars_left); |
690 | } else if (!strcmp_l1("has-slot:boot", cmd)) { |
691 | if (has_boot_slot == 1) { |
692 | printf("has boot slot\n"); |
693 | strncat(response, "yes", chars_left); |
694 | } else |
695 | strncat(response, "no", chars_left); |
696 | } else if (!strcmp_l1("has-slot:system", cmd)) { |
697 | if (dynamic_partition) { |
698 | strncat(response, "no", chars_left); |
699 | } else { |
700 | if (has_system_slot == 1) { |
701 | printf("has system slot\n"); |
702 | strncat(response, "yes", chars_left); |
703 | } else |
704 | strncat(response, "no", chars_left); |
705 | } |
706 | } else if (!strcmp_l1("has-slot:vendor", cmd)) { |
707 | if (dynamic_partition) { |
708 | strncat(response, "no", chars_left); |
709 | } else { |
710 | if (has_boot_slot == 1) { |
711 | printf("has vendor slot\n"); |
712 | strncat(response, "yes", chars_left); |
713 | } else |
714 | strncat(response, "no", chars_left); |
715 | } |
716 | } else if (!strcmp_l1("has-slot:vbmeta", cmd)) { |
717 | if (dynamic_partition) { |
718 | strncat(response, "no", chars_left); |
719 | } else { |
720 | if (has_boot_slot == 1) { |
721 | printf("has vbmeta slot\n"); |
722 | strncat(response, "yes", chars_left); |
723 | } else |
724 | strncat(response, "no", chars_left); |
725 | } |
726 | } else if (!strcmp_l1("has-slot:product", cmd)) { |
727 | if (dynamic_partition) { |
728 | strncat(response, "no", chars_left); |
729 | } else { |
730 | if (has_boot_slot == 1) { |
731 | printf("has product slot\n"); |
732 | strncat(response, "yes", chars_left); |
733 | } else |
734 | strncat(response, "no", chars_left); |
735 | } |
736 | } else if (!strcmp_l1("has-slot:super", cmd)) { |
737 | if (!dynamic_partition) { |
738 | strncat(response, "no", chars_left); |
739 | } else { |
740 | if (has_boot_slot == 1) { |
741 | printf("has product slot\n"); |
742 | strncat(response, "yes", chars_left); |
743 | } else |
744 | strncat(response, "no", chars_left); |
745 | } |
746 | } else if (!strcmp_l1("has-slot:metadata", cmd)) { |
747 | if (has_boot_slot == 1) { |
748 | printf("has metadata slot\n"); |
749 | strncat(response, "yes", chars_left); |
750 | } else |
751 | strncat(response, "no", chars_left); |
752 | } else if (!strcmp_l1("has-slot:dtbo", cmd)) { |
753 | if (has_boot_slot == 1) { |
754 | printf("has dtbo slot\n"); |
755 | strncat(response, "yes", chars_left); |
756 | } else |
757 | strncat(response, "no", chars_left); |
758 | } else if (!strcmp_l1("has-slot:data", cmd)) { |
759 | strncat(response, "no", chars_left); |
760 | } else if (!strcmp_l1("has-slot:misc", cmd)) { |
761 | strncat(response, "no", chars_left); |
762 | } else if (!strcmp_l1("has-slot:odm", cmd)) { |
763 | if (has_boot_slot == 1) { |
764 | printf("has odm slot\n"); |
765 | strncat(response, "yes", chars_left); |
766 | } else |
767 | strncat(response, "no", chars_left); |
768 | } else if (!strncmp("partition-size", cmd, strlen("partition-size"))) { |
769 | char str_num[20]; |
770 | struct partitions *pPartition; |
771 | uint64_t sz; |
772 | strsep(&cmd, ":"); |
773 | printf("partition is %s\n", cmd); |
774 | if (strcmp(cmd, "userdata") == 0) { |
775 | strcpy(cmd, "data"); |
776 | printf("partition is %s\n", cmd); |
777 | } |
778 | if (!strncmp("mbr", cmd, strlen("mbr"))) { |
779 | strcpy(response, "FAILVariable not implemented"); |
780 | } else { |
781 | if (!strncmp("bootloader-", cmd, strlen("bootloader-"))) { |
782 | strsep(&cmd, "-"); |
783 | mmc_boot_size(cmd, &sz); |
784 | printf("size:%016llx\n", sz); |
785 | sprintf(str_num, "%016llx", sz); |
786 | } else { |
787 | pPartition = find_mmc_partition_by_name(cmd); |
788 | if (pPartition) { |
789 | printf("size:%016llx\n", pPartition->size); |
790 | if (strcmp(cmd, "data") == 0) { |
791 | printf("reserve 0x4000 for fde data\n"); |
792 | sz = pPartition->size - 0x4000; |
793 | printf("data size :%016llx\n", sz); |
794 | sprintf(str_num, "%016llx", sz); |
795 | } else { |
796 | sprintf(str_num, "%016llx", pPartition->size); |
797 | } |
798 | } else { |
799 | printf("find_mmc_partition_by_name fail\n"); |
800 | sprintf(str_num, "get fail"); |
801 | } |
802 | } |
803 | strncat(response, str_num, chars_left); |
804 | } |
805 | } else if (!strcmp_l1("partition-type:cache", cmd)) { |
806 | if (has_boot_slot == 0) { |
807 | strncat(response, "ext4", chars_left); |
808 | } |
809 | } else if (!strcmp_l1("partition-type:data", cmd)) { |
810 | strncat(response, "ext4", chars_left); |
811 | } else if (!strcmp_l1("partition-type:userdata", cmd)) { |
812 | strncat(response, "ext4", chars_left); |
813 | } else if (!strcmp_l1("partition-type:system", cmd)) { |
814 | strncat(response, "ext4", chars_left); |
815 | } else if (!strcmp_l1("partition-type:vendor", cmd)) { |
816 | strncat(response, "ext4", chars_left); |
817 | } else if (!strcmp_l1("partition-type:odm", cmd)) { |
818 | strncat(response, "ext4", chars_left); |
819 | } else if (!strcmp_l1("partition-type:tee", cmd)) { |
820 | strncat(response, "ext4", chars_left); |
821 | } else if (!strcmp_l1("partition-type:param", cmd)) { |
822 | strncat(response, "ext4", chars_left); |
823 | } else if (!strcmp_l1("partition-type:product", cmd)) { |
824 | strncat(response, "ext4", chars_left); |
825 | } else if (!strcmp_l1("partition-type:metadata", cmd)) { |
826 | strncat(response, "ext4", chars_left); |
827 | } else if (!strncmp("partition-type", cmd, strlen("partition-type"))) { |
828 | strncat(response, "raw", chars_left); |
829 | } else if (!strcmp_l1("erase-block-size", cmd) || |
830 | !strcmp_l1("logical-block-size", cmd)) { |
831 | strncat(response, "2000", chars_left); |
832 | } else if (!strcmp_l1("secure", cmd)) { |
833 | if (check_lock()) { |
834 | strncat(response, "yes", chars_left); |
835 | } else { |
836 | strncat(response, "no", chars_left); |
837 | } |
838 | } else if (!strcmp_l1("unlocked", cmd)) { |
839 | if (check_lock()) { |
840 | strncat(response, "no", chars_left); |
841 | } else { |
842 | strncat(response, "yes", chars_left); |
843 | } |
844 | } else if (!strcmp_l1("slot-successful", cmd)) { |
845 | char str[128]; |
846 | strsep(&cmd, ":"); |
847 | printf("cmd is %s\n", cmd); |
848 | int ret; |
849 | if (has_boot_slot == 1) { |
850 | printf("has boot slot\n"); |
851 | sprintf(str, "get_slot_state %s successful", cmd); |
852 | printf("command: %s\n", str); |
853 | ret = run_command(str, 0); |
854 | printf("ret = %d\n", ret); |
855 | if (ret == 0) |
856 | strncat(response, "no", chars_left); |
857 | else |
858 | strncat(response, "yes", chars_left); |
859 | } else |
860 | strcpy(response, "FAILVariable not implemented in non ab mode"); |
861 | } else if (!strcmp_l1("slot-unbootable", cmd)) { |
862 | char str[128]; |
863 | strsep(&cmd, ":"); |
864 | printf("cmd is %s\n", cmd); |
865 | int ret; |
866 | if (has_boot_slot == 1) { |
867 | printf("has boot slot\n"); |
868 | sprintf(str, "get_slot_state %s unbootable", cmd); |
869 | printf("command: %s\n", str); |
870 | ret = run_command(str, 0); |
871 | printf("ret = %d\n", ret); |
872 | if (ret == 0) |
873 | strncat(response, "yes", chars_left); |
874 | else |
875 | strncat(response, "no", chars_left); |
876 | } else |
877 | strcpy(response, "FAILVariable not implemented in non ab mode"); |
878 | } else if (!strcmp_l1("slot-retry-count", cmd)) { |
879 | char str[128]; |
880 | strsep(&cmd, ":"); |
881 | printf("cmd is %s\n", cmd); |
882 | int ret; |
883 | if (has_boot_slot == 1) { |
884 | char str_num[12]; |
885 | printf("has boot slot\n"); |
886 | sprintf(str, "get_slot_state %s retry-count", cmd); |
887 | printf("command: %s\n", str); |
888 | ret = run_command(str, 0); |
889 | printf("ret = %d\n", ret); |
890 | sprintf(str_num, "%d", ret); |
891 | strncat(response, str_num, chars_left); |
892 | } else |
893 | strcpy(response, "FAILVariable not implemented in non ab mode"); |
894 | } else { |
895 | error("unknown variable: %s\n", cmd); |
896 | strcpy(response, "FAILVariable not implemented"); |
897 | } |
898 | |
899 | fastboot_tx_write_str(response); |
900 | } |
901 | |
902 | static unsigned int rx_bytes_expected(void) |
903 | { |
904 | int rx_remain = download_size - download_bytes; |
905 | if (rx_remain < 0) |
906 | return 0; |
907 | if (rx_remain > EP_BUFFER_SIZE) |
908 | return EP_BUFFER_SIZE; |
909 | return rx_remain; |
910 | } |
911 | |
912 | #define BYTES_PER_DOT 0x20000 |
913 | static void rx_handler_dl_image(struct usb_ep *ep, struct usb_request *req) |
914 | { |
915 | char response[RESPONSE_LEN]; |
916 | unsigned int transfer_size = download_size - download_bytes; |
917 | const unsigned char *buffer = req->buf; |
918 | unsigned int buffer_size = req->actual; |
919 | unsigned int pre_dot_num, now_dot_num; |
920 | |
921 | if (req->status != 0) { |
922 | printf("Bad status: %d\n", req->status); |
923 | return; |
924 | } |
925 | |
926 | if (buffer_size < transfer_size) |
927 | transfer_size = buffer_size; |
928 | |
929 | memcpy((void *)CONFIG_USB_FASTBOOT_BUF_ADDR + download_bytes, |
930 | buffer, transfer_size); |
931 | |
932 | pre_dot_num = download_bytes / BYTES_PER_DOT; |
933 | download_bytes += transfer_size; |
934 | now_dot_num = download_bytes / BYTES_PER_DOT; |
935 | |
936 | if (pre_dot_num != now_dot_num) { |
937 | putc('.'); |
938 | if (!(now_dot_num % 74)) |
939 | putc('\n'); |
940 | } |
941 | |
942 | /* Check if transfer is done */ |
943 | if (download_bytes >= download_size) { |
944 | /* |
945 | * Reset global transfer variable, keep download_bytes because |
946 | * it will be used in the next possible flashing command |
947 | */ |
948 | download_size = 0; |
949 | req->complete = rx_handler_command; |
950 | req->length = EP_BUFFER_SIZE; |
951 | |
952 | sprintf(response, "OKAY"); |
953 | fastboot_tx_write_str(response); |
954 | |
955 | printf("\ndownloading of %d bytes finished\n", download_bytes); |
956 | } else { |
957 | req->length = rx_bytes_expected(); |
958 | if (req->length < ep->maxpacket) |
959 | req->length = ep->maxpacket; |
960 | } |
961 | |
962 | req->actual = 0; |
963 | usb_ep_queue(ep, req, 0); |
964 | } |
965 | |
966 | static void cb_download(struct usb_ep *ep, struct usb_request *req) |
967 | { |
968 | char *cmd = req->buf; |
969 | char response[RESPONSE_LEN]; |
970 | |
971 | printf("cmd cb_download is %s\n", cmd); |
972 | |
973 | strsep(&cmd, ":"); |
974 | download_size = simple_strtoul(cmd, NULL, 16); |
975 | download_bytes = 0; |
976 | |
977 | printf("Starting download of %d bytes\n", download_size); |
978 | |
979 | if (0 == download_size) { |
980 | sprintf(response, "FAILdata invalid size"); |
981 | } else if (download_size > ddr_size_usable(CONFIG_USB_FASTBOOT_BUF_ADDR)) { |
982 | download_size = 0; |
983 | sprintf(response, "FAILdata too large"); |
984 | } else { |
985 | sprintf(response, "DATA%08x", download_size); |
986 | req->complete = rx_handler_dl_image; |
987 | req->length = rx_bytes_expected(); |
988 | if (req->length < ep->maxpacket) |
989 | req->length = ep->maxpacket; |
990 | } |
991 | fastboot_tx_write_str(response); |
992 | } |
993 | |
994 | typedef struct andr_img_hdr boot_img_hdr; |
995 | |
996 | static void do_bootm_on_complete(struct usb_ep *ep, struct usb_request *req) |
997 | { |
998 | char boot_addr_start[12]; |
999 | unsigned kernel_size; |
1000 | unsigned ramdisk_size; |
1001 | boot_img_hdr *hdr_addr = NULL; |
1002 | int genFmt = 0; |
1003 | unsigned actualBootImgSz = 0; |
1004 | unsigned dtbSz = 0; |
1005 | unsigned char* loadaddr = 0; |
1006 | |
1007 | puts("Booting kernel...\n"); |
1008 | |
1009 | sprintf(boot_addr_start, "bootm 0x%lx", load_addr); |
1010 | printf("boot_addr_start %s\n", boot_addr_start); |
1011 | |
1012 | loadaddr = (unsigned char*)CONFIG_USB_FASTBOOT_BUF_ADDR; |
1013 | hdr_addr = (boot_img_hdr*)loadaddr; |
1014 | |
1015 | genFmt = genimg_get_format(hdr_addr); |
1016 | if (IMAGE_FORMAT_ANDROID != genFmt) { |
1017 | printf("Fmt unsupported!genFmt 0x%x != 0x%x\n", genFmt, IMAGE_FORMAT_ANDROID); |
1018 | return; |
1019 | } |
1020 | |
1021 | kernel_size =(hdr_addr->kernel_size + (hdr_addr->page_size-1)+hdr_addr->page_size)&(~(hdr_addr->page_size -1)); |
1022 | ramdisk_size =(hdr_addr->ramdisk_size + (hdr_addr->page_size-1))&(~(hdr_addr->page_size -1)); |
1023 | dtbSz = hdr_addr->second_size; |
1024 | actualBootImgSz = kernel_size + ramdisk_size + dtbSz; |
1025 | printf("kernel_size 0x%x, page_size 0x%x, totalSz 0x%x\n", hdr_addr->kernel_size, hdr_addr->page_size, kernel_size); |
1026 | printf("ramdisk_size 0x%x, totalSz 0x%x\n", hdr_addr->ramdisk_size, ramdisk_size); |
1027 | printf("dtbSz 0x%x, Total actualBootImgSz 0x%x\n", dtbSz, actualBootImgSz); |
1028 | |
1029 | memcpy((void *)load_addr, (void *)CONFIG_USB_FASTBOOT_BUF_ADDR, actualBootImgSz); |
1030 | |
1031 | flush_cache(load_addr,(unsigned long)actualBootImgSz); |
1032 | |
1033 | run_command(boot_addr_start, 0); |
1034 | |
1035 | /* This only happens if image is somehow faulty so we start over */ |
1036 | do_reset(NULL, 0, 0, NULL); |
1037 | } |
1038 | |
1039 | static void cb_boot(struct usb_ep *ep, struct usb_request *req) |
1040 | { |
1041 | fastboot_func->in_req->complete = do_bootm_on_complete; |
1042 | fastboot_tx_write_str("OKAY"); |
1043 | } |
1044 | |
1045 | static void do_exit_on_complete(struct usb_ep *ep, struct usb_request *req) |
1046 | { |
1047 | puts("Booting kernel..\n"); |
1048 | run_command("run storeboot", 0); |
1049 | |
1050 | /* This only happens if image is somehow faulty so we start over */ |
1051 | do_reset(NULL, 0, 0, NULL); |
1052 | } |
1053 | |
1054 | |
1055 | static void cb_continue(struct usb_ep *ep, struct usb_request *req) |
1056 | { |
1057 | fastboot_func->in_req->complete = do_exit_on_complete; |
1058 | fastboot_tx_write_str("OKAY"); |
1059 | } |
1060 | |
1061 | static void cb_flashing(struct usb_ep *ep, struct usb_request *req) |
1062 | { |
1063 | char *cmd; |
1064 | char* response = response_str; |
1065 | char *lock_s; |
1066 | LockData_t* info; |
1067 | size_t chars_left; |
1068 | char lock_d[LOCK_DATA_SIZE]; |
1069 | static int cmd_index = -1; |
1070 | |
1071 | lock_s = getenv("lock"); |
1072 | if (!lock_s) { |
1073 | printf("lock state is NULL \n"); |
1074 | strcpy(lock_d, "10000000"); |
1075 | lock_s = "10000000"; |
1076 | setenv("lock", "10000000"); |
1077 | run_command("defenv_reserv; saveenv;", 0); |
1078 | } else { |
1079 | printf("lock state: %s\n", lock_s); |
1080 | strcpy(lock_d, lock_s); |
1081 | } |
1082 | |
1083 | info = (LockData_t*)malloc(sizeof(struct LockData)); |
1084 | memset(info,0,LOCK_DATA_SIZE); |
1085 | info->version_major = (int)(lock_d[0] - '0'); |
1086 | info->version_minor = (int)(lock_d[1] - '0'); |
1087 | info->lock_state = (int)(lock_d[4] - '0'); |
1088 | info->lock_critical_state = (int)(lock_d[5] - '0'); |
1089 | info->lock_bootloader = (int)(lock_d[6] - '0'); |
1090 | dump_lock_info(info); |
1091 | |
1092 | strcpy(response, "OKAY"); |
1093 | chars_left = sizeof(response_str) - strlen(response) - 1; |
1094 | cmd = req->buf; |
1095 | strsep(&cmd, " "); |
1096 | printf("cb_flashing: %s\n", cmd); |
1097 | if (!cmd) { |
1098 | if ( cmd_index == -1 ) { |
1099 | error("missing variable\n"); |
1100 | fastboot_tx_write_str("FAILmissing var"); |
1101 | return; |
1102 | } else { |
1103 | fastboot_tx_write_str(response); |
1104 | return; |
1105 | } |
1106 | } |
1107 | |
1108 | if (!strncmp(cmd, "get_unlock_ability", 18)) { |
1109 | cmd_index = 0; |
1110 | strcpy(cmd, "get_unlock_ability"); |
1111 | if ( ++cmd_index >= 2) cmd_index = 0; |
1112 | else fastboot_busy(NULL); |
1113 | FB_MSG("flashing cmd:%s\n", cmd); |
1114 | chars_left = sizeof(response_str) - strlen(response) - 1; |
1115 | strncat(response, cmd, chars_left); |
1116 | strncat(response, ":", 1); |
1117 | chars_left -= strlen(cmd) + 1; |
1118 | } |
1119 | |
1120 | if (!strncmp(cmd, "get_unlock_bootloader_nonce", 27)) { |
1121 | cmd_index = 0; |
1122 | strcpy(cmd, "get_unlock_bootloader_nonce"); |
1123 | if ( ++cmd_index >= 2) cmd_index = 0; |
1124 | else fastboot_busy(NULL); |
1125 | FB_MSG("flashing cmd:%s\n", cmd); |
1126 | chars_left = sizeof(response_str) - strlen(response) - 1; |
1127 | strncat(response, cmd, chars_left); |
1128 | strncat(response, ":", 1); |
1129 | chars_left -= strlen(cmd) + 1; |
1130 | } |
1131 | |
1132 | if (!strcmp_l1("unlock_critical", cmd)) { |
1133 | info->lock_critical_state = 0; |
1134 | } else if (!strcmp_l1("lock_critical", cmd)) { |
1135 | info->lock_critical_state = 1; |
1136 | } else if (!strcmp_l1("get_unlock_ability", cmd)) { |
1137 | char str_num[1]; |
1138 | sprintf(str_num, "%d", info->lock_state); |
1139 | strncat(response, str_num, chars_left); |
1140 | } else if (!strcmp_l1("get_unlock_bootloader_nonce", cmd)) { |
1141 | char str_num[1]; |
1142 | sprintf(str_num, "%d", info->lock_critical_state); |
1143 | strncat(response, str_num, chars_left); |
1144 | } else if (!strcmp_l1("unlock_bootloader", cmd)) { |
1145 | strncat(response, "please run flashing unlock & flashing unlock_critical before write", chars_left); |
1146 | } else if (!strcmp_l1("lock_bootloader", cmd)) { |
1147 | info->lock_bootloader = 1; |
1148 | } else if (!strcmp_l1("unlock", cmd)) { |
1149 | if (info->lock_state == 1 ) { |
1150 | char *avb_s; |
1151 | avb_s = getenv("avb2"); |
1152 | if (avb_s == NULL) { |
1153 | run_command("get_avb_mode;", 0); |
1154 | avb_s = getenv("avb2"); |
1155 | } |
1156 | printf("avb2: %s\n", avb_s); |
1157 | if (strcmp(avb_s, "1") == 0) { |
1158 | #ifdef CONFIG_AML_ANTIROLLBACK |
1159 | if (avb_unlock()) { |
1160 | printf("unlocking device. Erasing userdata partition!\n"); |
1161 | run_command("store erase partition data", 0); |
1162 | } else { |
1163 | printf("unlock failed!\n"); |
1164 | } |
1165 | #else |
1166 | printf("unlocking device. Erasing userdata partition!\n"); |
1167 | run_command("store erase partition data", 0); |
1168 | #endif |
1169 | } |
1170 | } |
1171 | info->lock_state = 0; |
1172 | info->lock_critical_state = 0; |
1173 | } else if (!strcmp_l1("lock", cmd)) { |
1174 | if (info->lock_state == 0 ) { |
1175 | char *avb_s; |
1176 | avb_s = getenv("avb2"); |
1177 | if (avb_s == NULL) { |
1178 | run_command("get_avb_mode;", 0); |
1179 | avb_s = getenv("avb2"); |
1180 | } |
1181 | printf("avb2: %s\n", avb_s); |
1182 | if (strcmp(avb_s, "1") == 0) { |
1183 | #ifdef CONFIG_AML_ANTIROLLBACK |
1184 | if (avb_lock()) { |
1185 | printf("lock failed!\n"); |
1186 | } else { |
1187 | printf("locking device. Erasing userdata partition!\n"); |
1188 | run_command("store erase partition data", 0); |
1189 | } |
1190 | #else |
1191 | printf("locking device. Erasing userdata partition!\n"); |
1192 | run_command("store erase partition data", 0); |
1193 | #endif |
1194 | } |
1195 | } |
1196 | info->lock_state = 1; |
1197 | } else { |
1198 | error("unknown variable: %s\n", cmd); |
1199 | strcpy(response, "FAILVariable not implemented"); |
1200 | } |
1201 | |
1202 | dump_lock_info(info); |
1203 | sprintf(lock_d, "%d%d00%d%d%d0", info->version_major, info->version_minor, info->lock_state, info->lock_critical_state, info->lock_bootloader); |
1204 | printf("lock_d state: %s\n", lock_d); |
1205 | setenv("lock", lock_d); |
1206 | run_command("defenv_reserv; saveenv;", 0); |
1207 | printf("response: %s\n", response); |
1208 | |
1209 | fastboot_tx_write_str(response); |
1210 | } |
1211 | |
1212 | |
1213 | #ifdef CONFIG_FASTBOOT_FLASH |
1214 | static void cb_flash(struct usb_ep *ep, struct usb_request *req) |
1215 | { |
1216 | char *cmd = req->buf; |
1217 | char* response = response_str; |
1218 | |
1219 | printf("cmd cb_flash is %s\n", cmd); |
1220 | |
1221 | strsep(&cmd, ":"); |
1222 | if (!cmd) { |
1223 | error("missing partition name\n"); |
1224 | fastboot_tx_write_str("FAILmissing partition name"); |
1225 | return; |
1226 | } |
1227 | |
1228 | if (check_lock()) { |
1229 | error("device is locked, can not run this cmd.Please flashing unlock & flashing unlock_critical\n"); |
1230 | fastboot_tx_write_str("FAILlocked device"); |
1231 | return; |
1232 | } |
1233 | |
1234 | #ifdef CONFIG_BOOTLOADER_CONTROL_BLOCK |
1235 | if (dynamic_partition) { |
1236 | if (is_partition_logical(cmd) == 0) { |
1237 | error("%s is logic partition, can not write here.......\n", cmd); |
1238 | fastboot_tx_write_str("FAILlogic partition"); |
1239 | return; |
1240 | } |
1241 | } |
1242 | #endif |
1243 | |
1244 | printf("partition is %s\n", cmd); |
1245 | if (strcmp(cmd, "userdata") == 0) { |
1246 | strcpy(cmd, "data"); |
1247 | printf("partition is %s\n", cmd); |
1248 | } |
1249 | |
1250 | if (strcmp(cmd, "dts") == 0) { |
1251 | strcpy(cmd, "dtb"); |
1252 | printf("partition is %s\n", cmd); |
1253 | } |
1254 | |
1255 | //strcpy(response, "FAILno flash device defined"); |
1256 | if (is_mainstorage_emmc()) { |
1257 | #ifdef CONFIG_FASTBOOT_FLASH_MMC_DEV |
1258 | fb_mmc_flash_write(cmd, (void *)CONFIG_USB_FASTBOOT_BUF_ADDR, |
1259 | download_bytes); |
1260 | #endif |
1261 | } else if (is_mainstorage_nand()) { |
1262 | #ifdef CONFIG_FASTBOOT_FLASH_NAND_DEV |
1263 | fb_nand_flash_write(cmd, (void *)CONFIG_USB_FASTBOOT_BUF_ADDR, |
1264 | download_bytes); |
1265 | #else |
1266 | fastboot_fail("not support nftl\n"); |
1267 | #endif |
1268 | } else { |
1269 | printf("error: no valid fastboot device\n"); |
1270 | fastboot_fail("no vaild device\n"); |
1271 | } |
1272 | fastboot_tx_write_str(response); |
1273 | } |
1274 | #endif |
1275 | |
1276 | static void cb_set_active(struct usb_ep *ep, struct usb_request *req) |
1277 | { |
1278 | char *cmd = req->buf; |
1279 | //char response[RESPONSE_LEN]; |
1280 | int ret = 0; |
1281 | char str[128]; |
1282 | |
1283 | printf("cmd cb_set_active is %s\n", cmd); |
1284 | strsep(&cmd, ":"); |
1285 | if (!cmd) { |
1286 | error("missing slot name\n"); |
1287 | fastboot_tx_write_str("FAILmissing slot name"); |
1288 | return; |
1289 | } |
1290 | |
1291 | if (check_lock()) { |
1292 | error("device is locked, can not run this cmd.Please flashing unlock & flashing unlock_critical\n"); |
1293 | fastboot_tx_write_str("FAILlocked device"); |
1294 | return; |
1295 | } |
1296 | |
1297 | sprintf(str, "set_active_slot %s", cmd); |
1298 | printf("command: %s\n", str); |
1299 | ret = run_command(str, 0); |
1300 | printf("ret = %d\n", ret); |
1301 | if (ret == 0) |
1302 | fastboot_tx_write_str("OKAY"); |
1303 | else |
1304 | fastboot_tx_write_str("FAILset slot error"); |
1305 | } |
1306 | |
1307 | static void cb_flashall(struct usb_ep *ep, struct usb_request *req) |
1308 | { |
1309 | char* response = response_str; |
1310 | char *cmd = req->buf; |
1311 | |
1312 | printf("cmd cb_flashall is %s\n", cmd); |
1313 | |
1314 | if (check_lock()) { |
1315 | error("device is locked, can not run this cmd.Please flashing unlock & flashing unlock_critical\n"); |
1316 | fastboot_tx_write_str("FAILlocked device"); |
1317 | return; |
1318 | } |
1319 | |
1320 | //strcpy(response, "FAILno flash device defined"); |
1321 | if (is_mainstorage_emmc()) { |
1322 | #ifdef CONFIG_FASTBOOT_FLASH_MMC_DEV |
1323 | fb_mmc_flash_write(cmd, (void *)CONFIG_USB_FASTBOOT_BUF_ADDR, |
1324 | download_bytes); |
1325 | #endif |
1326 | } else if (is_mainstorage_nand()) { |
1327 | #ifdef CONFIG_FASTBOOT_FLASH_NAND_DEV |
1328 | fb_nand_flash_write(cmd, (void *)CONFIG_USB_FASTBOOT_BUF_ADDR, |
1329 | download_bytes); |
1330 | #else |
1331 | fastboot_fail("not support nftl\n"); |
1332 | #endif |
1333 | } else { |
1334 | printf("error: no valid fastboot device\n"); |
1335 | fastboot_fail("no vaild device\n"); |
1336 | } |
1337 | fastboot_tx_write_str(response); |
1338 | } |
1339 | |
1340 | static void cb_erase(struct usb_ep *ep, struct usb_request *req) |
1341 | { |
1342 | char* response = response_str; |
1343 | char *cmd = req->buf; |
1344 | |
1345 | printf("cmd cb_erase is %s\n", cmd); |
1346 | |
1347 | strsep(&cmd, ":"); |
1348 | if (!cmd) { |
1349 | error("missing partition name\n"); |
1350 | fastboot_tx_write_str("FAILmissing partition name"); |
1351 | return; |
1352 | } |
1353 | |
1354 | if (check_lock()) { |
1355 | error("device is locked, can not run this cmd.Please flashing unlock & flashing unlock_critical\n"); |
1356 | fastboot_tx_write_str("FAILlocked device"); |
1357 | return; |
1358 | } |
1359 | |
1360 | printf("partition is %s\n", cmd); |
1361 | if (strcmp(cmd, "userdata") == 0) { |
1362 | strcpy(cmd, "data"); |
1363 | printf("partition is %s\n", cmd); |
1364 | } |
1365 | |
1366 | if (strcmp(cmd, "dts") == 0) { |
1367 | strcpy(cmd, "dtb"); |
1368 | printf("partition is %s\n", cmd); |
1369 | } |
1370 | |
1371 | //strcpy(response, "FAILno erase device defined"); |
1372 | if (is_mainstorage_emmc()) { |
1373 | #ifdef CONFIG_FASTBOOT_FLASH_MMC_DEV |
1374 | fb_mmc_erase_write(cmd, (void *)CONFIG_USB_FASTBOOT_BUF_ADDR); |
1375 | #endif |
1376 | } else if (is_mainstorage_nand()) { |
1377 | #ifdef CONFIG_FASTBOOT_FLASH_NAND_DEV |
1378 | fb_nand_erase(cmd, (void *)CONFIG_USB_FASTBOOT_BUF_ADDR); |
1379 | #else |
1380 | fastboot_fail("not support nftl\n"); |
1381 | #endif |
1382 | } else { |
1383 | printf("error: no valid fastboot device\n"); |
1384 | fastboot_fail("no vaild device\n"); |
1385 | } |
1386 | fastboot_tx_write_str(response); |
1387 | } |
1388 | |
1389 | static void cb_devices(struct usb_ep *ep, struct usb_request *req) |
1390 | { |
1391 | char response[RESPONSE_LEN]; |
1392 | char *cmd = req->buf; |
1393 | |
1394 | printf("cmd is %s\n", cmd); |
1395 | |
1396 | strcpy(response, "AMLOGIC"); |
1397 | |
1398 | fastboot_tx_write_str(response); |
1399 | } |
1400 | |
1401 | static void cb_oem_cmd(struct usb_ep *ep, struct usb_request *req) |
1402 | { |
1403 | char response[RESPONSE_LEN/2 + 1]; |
1404 | char* cmd = req->buf; |
1405 | printf("oem cmd[%s]\n", cmd); |
1406 | static int i = 0; |
1407 | |
1408 | memcpy(response, cmd, strnlen(cmd, RESPONSE_LEN/2)+1);//+1 to terminate str |
1409 | cmd = response; |
1410 | strsep(&cmd, " "); |
1411 | FB_MSG("To run cmd[%s]\n", cmd); |
1412 | run_command(cmd, 0); |
1413 | |
1414 | if (++i > 3) i = 0; |
1415 | |
1416 | i ? fastboot_busy("AMLOGIC") : fastboot_okay(response); |
1417 | fastboot_tx_write_str(response_str); |
1418 | return ; |
1419 | } |
1420 | |
1421 | struct cmd_dispatch_info { |
1422 | char *cmd; |
1423 | void (*cb)(struct usb_ep *ep, struct usb_request *req); |
1424 | }; |
1425 | |
1426 | static const struct cmd_dispatch_info cmd_dispatch_info[] = { |
1427 | { |
1428 | .cmd = "reboot", |
1429 | .cb = cb_reboot, |
1430 | }, { |
1431 | .cmd = "getvar:", |
1432 | .cb = cb_getvar, |
1433 | }, { |
1434 | .cmd = "download:", |
1435 | .cb = cb_download, |
1436 | }, { |
1437 | .cmd = "boot", |
1438 | .cb = cb_boot, |
1439 | }, { |
1440 | .cmd = "continue", |
1441 | .cb = cb_continue, |
1442 | }, { |
1443 | .cmd = "flashing", |
1444 | .cb = cb_flashing, |
1445 | }, |
1446 | #ifdef CONFIG_FASTBOOT_FLASH |
1447 | { |
1448 | .cmd = "flash", |
1449 | .cb = cb_flash, |
1450 | }, |
1451 | #endif |
1452 | { |
1453 | .cmd = "update", |
1454 | .cb = cb_download, |
1455 | }, |
1456 | { |
1457 | .cmd = "flashall", |
1458 | .cb = cb_flashall, |
1459 | }, |
1460 | { |
1461 | .cmd = "erase", |
1462 | .cb = cb_erase, |
1463 | }, |
1464 | { |
1465 | .cmd = "devices", |
1466 | .cb = cb_devices, |
1467 | }, |
1468 | { |
1469 | .cmd = "reboot-bootloader", |
1470 | .cb = cb_reboot, |
1471 | }, |
1472 | { |
1473 | .cmd = "reboot-fastboot", |
1474 | .cb = cb_reboot, |
1475 | }, |
1476 | { |
1477 | .cmd = "set_active", |
1478 | .cb = cb_set_active, |
1479 | }, |
1480 | { |
1481 | .cmd = "oem", |
1482 | .cb = cb_oem_cmd, |
1483 | } |
1484 | }; |
1485 | |
1486 | //cb for out_req->complete |
1487 | static void rx_handler_command(struct usb_ep *ep, struct usb_request *req) |
1488 | { |
1489 | char *cmdbuf = req->buf; |
1490 | void (*func_cb)(struct usb_ep *ep, struct usb_request *req) = NULL; |
1491 | int i; |
1492 | |
1493 | for (i = 0; i < ARRAY_SIZE(cmd_dispatch_info); i++) { |
1494 | if (!strcmp_l1(cmd_dispatch_info[i].cmd, cmdbuf)) { |
1495 | func_cb = cmd_dispatch_info[i].cb; |
1496 | break; |
1497 | } |
1498 | } |
1499 | |
1500 | if (!func_cb) { |
1501 | error("unknown command: %s\n", cmdbuf); |
1502 | fastboot_tx_write_str("FAILunknown command"); |
1503 | } else { |
1504 | if (req->actual < req->length) { |
1505 | u8 *buf = (u8 *)req->buf; |
1506 | buf[req->actual] = 0; |
1507 | func_cb(ep, req); |
1508 | } else { |
1509 | error("buffer overflow\n"); |
1510 | fastboot_tx_write_str("FAILbuffer overflow"); |
1511 | } |
1512 | } |
1513 | |
1514 | if (req->status == 0 && !fastboot_is_busy()) { |
1515 | *cmdbuf = '\0'; |
1516 | req->actual = 0; |
1517 | usb_ep_queue(ep, req, 0); |
1518 | } |
1519 | } |
1520 |