blob: 950c2450d089c1a744cd729decfb6292b91c9da4
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", 5); |
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", 5); |
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; |
361 | int status; |
362 | |
363 | if (fastboot_func == NULL) { |
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 | } else { |
371 | f_fb = fastboot_func; |
372 | } |
373 | |
374 | f_fb->usb_function.name = "f_fastboot"; |
375 | f_fb->usb_function.hs_descriptors = fb_runtime_descs; |
376 | f_fb->usb_function.bind = fastboot_bind; |
377 | f_fb->usb_function.unbind = fastboot_unbind; |
378 | f_fb->usb_function.set_alt = fastboot_set_alt; |
379 | f_fb->usb_function.disable = fastboot_disable; |
380 | f_fb->usb_function.strings = fastboot_strings; |
381 | f_fb->usb_function.setup = fastboot_setup; |
382 | |
383 | status = usb_add_function(c, &f_fb->usb_function); |
384 | if (status) { |
385 | free(f_fb); |
386 | fastboot_func = NULL; |
387 | } |
388 | |
389 | return status; |
390 | } |
391 | DECLARE_GADGET_BIND_CALLBACK(usb_dnl_fastboot, fastboot_add); |
392 | |
393 | static int fastboot_tx_write(const char *buffer, unsigned int buffer_size) |
394 | { |
395 | struct usb_request *in_req = fastboot_func->in_req; |
396 | int ret; |
397 | |
398 | memcpy(in_req->buf, buffer, buffer_size); |
399 | in_req->length = buffer_size; |
400 | ret = usb_ep_queue(fastboot_func->in_ep, in_req, 0); |
401 | if (ret) |
402 | printf("Error %d on queue\n", ret); |
403 | return 0; |
404 | } |
405 | |
406 | static int fastboot_tx_write_str(const char *buffer) |
407 | { |
408 | return fastboot_tx_write(buffer, strlen(buffer)); |
409 | } |
410 | |
411 | static void compl_do_reset(struct usb_ep *ep, struct usb_request *req) |
412 | { |
413 | do_reset(NULL, 0, 0, NULL); |
414 | } |
415 | |
416 | static void compl_do_reboot_bootloader(struct usb_ep *ep, struct usb_request *req) |
417 | { |
418 | if (dynamic_partition) |
419 | run_command("reboot bootloader", 0); |
420 | else |
421 | run_command("reboot fastboot", 0); |
422 | } |
423 | |
424 | static void compl_do_reboot_fastboot(struct usb_ep *ep, struct usb_request *req) |
425 | { |
426 | f_dwc_otg_pullup(0); |
427 | run_command("reboot fastboot", 0); |
428 | } |
429 | |
430 | static void cb_reboot(struct usb_ep *ep, struct usb_request *req) |
431 | { |
432 | char *cmd = req->buf; |
433 | |
434 | printf("cmd cb_reboot is %s\n", cmd); |
435 | |
436 | strsep(&cmd, "-"); |
437 | if (!cmd) { |
438 | fastboot_func->in_req->complete = compl_do_reset; |
439 | fastboot_tx_write_str("OKAY"); |
440 | return; |
441 | } |
442 | |
443 | printf("cmd cb_reboot is %s\n", cmd); |
444 | if (strcmp(cmd, "bootloader") == 0) |
445 | fastboot_func->in_req->complete = compl_do_reboot_bootloader; |
446 | else if (strcmp(cmd, "fastboot") == 0) |
447 | fastboot_func->in_req->complete = compl_do_reboot_fastboot; |
448 | |
449 | fastboot_tx_write_str("OKAY"); |
450 | } |
451 | |
452 | static int strcmp_l1(const char *s1, const char *s2) |
453 | { |
454 | if (!s1 || !s2) |
455 | return -1; |
456 | return strncmp(s1, s2, strlen(s1)); |
457 | } |
458 | |
459 | void dump_lock_info(LockData_t* info) |
460 | { |
461 | printf("info->version_major = %d\n", info->version_major); |
462 | printf("info->version_minor = %d\n", info->version_minor); |
463 | printf("info->lock_state = %d\n", info->lock_state); |
464 | printf("info->lock_critical_state = %d\n", info->lock_critical_state); |
465 | printf("info->lock_bootloader = %d\n", info->lock_bootloader); |
466 | } |
467 | |
468 | |
469 | static int check_lock(void) |
470 | { |
471 | char *lock_s; |
472 | LockData_t* info; |
473 | |
474 | lock_s = getenv("lock"); |
475 | if (!lock_s) { |
476 | printf("lock state is NULL \n"); |
477 | lock_s = "10000000"; |
478 | setenv("lock", "10000000"); |
479 | run_command("defenv_reserv; saveenv;", 0); |
480 | } |
481 | printf("lock state: %s\n", lock_s); |
482 | |
483 | info = malloc(sizeof(struct LockData)); |
484 | if (info) { |
485 | memset(info,0,LOCK_DATA_SIZE); |
486 | info->version_major = (int)(lock_s[0] - '0'); |
487 | info->version_minor = (int)(lock_s[1] - '0'); |
488 | info->lock_state = (int)(lock_s[4] - '0'); |
489 | info->lock_critical_state = (int)(lock_s[5] - '0'); |
490 | info->lock_bootloader = (int)(lock_s[6] - '0'); |
491 | |
492 | dump_lock_info(info); |
493 | } else |
494 | return 0; |
495 | |
496 | if ((info->lock_state == 1 ) || ( info->lock_critical_state == 1 )) { |
497 | free (info); |
498 | return 1; |
499 | } |
500 | else { |
501 | free (info); |
502 | return 0; |
503 | } |
504 | } |
505 | |
506 | static const char* getvar_list[] = { |
507 | "version-baseband", "version-bootloader", "version", "hw-revision", "max-download-size", |
508 | "serialno", "product", "off-mode-charge", "variant", "battery-soc-ok", |
509 | "battery-voltage", "partition-type:boot", "partition-size:boot", |
510 | "partition-type:system", "partition-size:system", "partition-type:vendor", "partition-size:vendor", |
511 | "partition-type:odm", "partition-size:odm", "partition-type:data", "partition-size:data", |
512 | "erase-block-size", "logical-block-size", "secure", "unlocked", |
513 | }; |
514 | |
515 | static const char* getvar_list_dynamic[] = { |
516 | "hw-revision", "battery-voltage", "is-userspace", "is-logical:data", |
517 | "is-logical:metadata", "is-logical:misc", "is-logical:super", "is-logical:boot", |
518 | "is-logical:system", "is-logical:vendor", "is-logical:product", "is-logical:odm", |
519 | "slot-count", "max-download-size", "serialno", "product", "unlocked", "has-slot:data", |
520 | "has-slot:metadata", "has-slot:misc", "has-slot:super", "has-slot:boot", |
521 | "has-slot:system", "has-slot:vendor", "has-slot:product", "has-slot:odm", |
522 | "secure", "super-partition-name", "version-baseband", "version-bootloader", |
523 | "partition-size:boot", "partition-size:metadata", "partition-size:misc", |
524 | "partition-size:super", "partition-size:data", "version", |
525 | }; |
526 | |
527 | static const char* getvar_list_ab[] = { |
528 | "version-baseband", "version-bootloader", "version", "hw-revision", "max-download-size", |
529 | "serialno", "product", "off-mode-charge", "variant", "battery-soc-ok", |
530 | "battery-voltage", "partition-type:boot", "partition-size:boot", |
531 | "partition-type:system", "partition-size:system", "partition-type:vendor", "partition-size:vendor", |
532 | "partition-type:odm", "partition-size:odm", "partition-type:data", "partition-size:data", |
533 | "partition-type:cache", "partition-size:cache", |
534 | "erase-block-size", "logical-block-size", "secure", "unlocked", |
535 | "slot-count", "slot-suffixes","current-slot", "has-slot:bootloader", "has-slot:boot", |
536 | "has-slot:system", "has-slot:vendor", "has-slot:odm", "has-slot:vbmeta", |
537 | "has-slot:metadata", "has-slot:product", "has-slot:dtbo", |
538 | "slot-successful:a", "slot-unbootable:a", "slot-retry-count:a", |
539 | "slot-successful:b", "slot-unbootable:b", "slot-retry-count:b", |
540 | }; |
541 | |
542 | static void cb_getvar(struct usb_ep *ep, struct usb_request *req) |
543 | { |
544 | char *cmd = req->buf; |
545 | char cmdBuf[RESPONSE_LEN]; |
546 | char* response = response_str; |
547 | char *s; |
548 | char *s1; |
549 | char *s2; |
550 | char *s3; |
551 | char s_version[24]; |
552 | size_t chars_left; |
553 | |
554 | run_command("get_valid_slot", 0); |
555 | |
556 | strcpy(response, "OKAY"); |
557 | chars_left = sizeof(response_str) - strlen(response) - 1; |
558 | |
559 | memcpy(cmdBuf, cmd, strnlen(cmd, RESPONSE_LEN-1)+1); |
560 | cmd = cmdBuf; |
561 | strsep(&cmd, ":"); |
562 | printf("cb_getvar: %s\n", cmd); |
563 | if (!cmd) { |
564 | error("missing variable\n"); |
565 | fastboot_tx_write_str("FAILmissing var"); |
566 | return; |
567 | } |
568 | if (!strncmp(cmd, "all", 3)) { |
569 | static int cmdIndex = 0; |
570 | int getvar_num = 0; |
571 | if (has_boot_slot == 1 && strlen(getvar_list_ab[cmdIndex]) < 64) { |
572 | strcpy(cmd, getvar_list_ab[cmdIndex]); |
573 | getvar_num = (sizeof(getvar_list_ab) / sizeof(getvar_list_ab[0])); |
574 | } else if (dynamic_partition && strlen(getvar_list_dynamic[cmdIndex]) < 64) { |
575 | strcpy(cmd, getvar_list_dynamic[cmdIndex]);//only support no-arg cmd |
576 | getvar_num = (sizeof(getvar_list_dynamic) / sizeof(getvar_list_dynamic[0])); |
577 | } else if (strlen(getvar_list[cmdIndex]) < 64) { |
578 | strcpy(cmd, getvar_list[cmdIndex]);//only support no-arg cmd |
579 | getvar_num = (sizeof(getvar_list) / sizeof(getvar_list[0])); |
580 | } |
581 | printf("getvar_num: %d\n", getvar_num); |
582 | if ( ++cmdIndex >= getvar_num) cmdIndex = 0; |
583 | else fastboot_busy(NULL); |
584 | FB_MSG("all cmd:%s\n", cmd); |
585 | strncat(response, cmd, chars_left); |
586 | strncat(response, ":", 1); |
587 | chars_left -= strlen(cmd) + 1; |
588 | } |
589 | |
590 | strcpy(s_version, "01.01."); |
591 | printf("U_BOOT_DATE_TIME: %s\n", U_BOOT_DATE_TIME); |
592 | strcat(s_version, U_BOOT_DATE_TIME); |
593 | printf("s_version: %s\n", s_version); |
594 | |
595 | if (!strcmp_l1("version-baseband", cmd)) { |
596 | strncat(response, "N/A", chars_left); |
597 | } else if (!strcmp_l1("version-bootloader", cmd)) { |
598 | strncat(response, s_version, chars_left); |
599 | } else if (!strcmp_l1("hw-revision", cmd)) { |
600 | strncat(response, "0", chars_left); |
601 | } else if (!strcmp_l1("version", cmd)) { |
602 | strncat(response, FASTBOOT_VERSION, chars_left); |
603 | } else if (!strcmp_l1("bootloader-version", cmd)) { |
604 | strncat(response, s_version, chars_left); |
605 | } else if (!strcmp_l1("off-mode-charge", cmd)) { |
606 | strncat(response, "0", chars_left); |
607 | } else if (!strcmp_l1("variant", cmd)) { |
608 | strncat(response, "US", chars_left); |
609 | } else if (!strcmp_l1("battery-soc-ok", cmd)) { |
610 | strncat(response, "yes", chars_left); |
611 | } else if (!strcmp_l1("battery-voltage", cmd)) { |
612 | strncat(response, "4", chars_left); |
613 | } else if (!strcmp_l1("is-userspace", cmd)) { |
614 | if (dynamic_partition) { |
615 | strncat(response, "no", chars_left); |
616 | } else { |
617 | error("unknown variable: %s\n", cmd); |
618 | strcpy(response, "FAILVariable not implemented"); |
619 | } |
620 | } else if (!strcmp_l1("is-logical", cmd)) { |
621 | strsep(&cmd, ":"); |
622 | printf("partition is %s\n", cmd); |
623 | if (!dynamic_partition) { |
624 | strncat(response, "no", chars_left); |
625 | } else { |
626 | #ifdef CONFIG_BOOTLOADER_CONTROL_BLOCK |
627 | if (is_partition_logical(cmd) == 0) { |
628 | error("%s is logic partition\n", cmd); |
629 | strncat(response, "yes", chars_left); |
630 | } else { |
631 | strncat(response, "no", chars_left); |
632 | } |
633 | #else |
634 | strncat(response, "no", chars_left); |
635 | #endif |
636 | } |
637 | } else if (!strcmp_l1("super-partition-name", cmd)) { |
638 | char *slot_name; |
639 | slot_name = getenv("slot-suffixes"); |
640 | if (has_boot_slot == 0) { |
641 | strncat(response, "super", chars_left); |
642 | } else { |
643 | printf("slot-suffixes: %s\n", slot_name); |
644 | if (strcmp(slot_name, "0") == 0) { |
645 | printf("active_slot is %s\n", "a"); |
646 | strncat(response, "super_a", chars_left); |
647 | } else if (strcmp(slot_name, "1") == 0) { |
648 | printf("active_slot is %s\n", "b"); |
649 | strncat(response, "super_b", chars_left); |
650 | } |
651 | } |
652 | } else if (!strcmp_l1("downloadsize", cmd) || |
653 | !strcmp_l1("max-download-size", cmd)) { |
654 | char str_num[12]; |
655 | |
656 | sprintf(str_num, "0x%08x", ddr_size_usable(CONFIG_USB_FASTBOOT_BUF_ADDR)); |
657 | strncat(response, str_num, chars_left); |
658 | } else if (!strcmp_l1("serialno", cmd)) { |
659 | //s = getenv("serial"); |
660 | s = get_usid_string(); |
661 | if (s) |
662 | strncat(response, s, chars_left); |
663 | else |
664 | strncat(response, DEVICE_SERIAL, chars_left); |
665 | } else if (!strcmp_l1("product", cmd)) { |
666 | #ifdef DEVICE_PRODUCT |
667 | s1 = DEVICE_PRODUCT; |
668 | printf("DEVICE_PRODUCT: %s\n", s1); |
669 | #else |
670 | s1 = getenv("device_product"); |
671 | printf("device_product: %s\n", s1); |
672 | #endif |
673 | strncat(response, s1, chars_left); |
674 | } else if (!strcmp_l1("slot-count", cmd)) { |
675 | if (has_boot_slot == 1) |
676 | strncat(response, "2", chars_left); |
677 | else |
678 | strncat(response, "0", chars_left); |
679 | } else if (!strcmp_l1("slot-suffixes", cmd)) { |
680 | s2 = getenv("slot-suffixes"); |
681 | printf("slot-suffixes: %s\n", s2); |
682 | if (s2) |
683 | strncat(response, s2, chars_left); |
684 | else |
685 | strncat(response, "0", chars_left); |
686 | } else if (!strcmp_l1("current-slot", cmd)) { |
687 | s3 = getenv("slot-suffixes"); |
688 | printf("slot-suffixes: %s\n", s3); |
689 | if (strcmp(s3, "0") == 0) { |
690 | printf("active_slot is %s\n", "a"); |
691 | strncat(response, "a", chars_left); |
692 | } else if (strcmp(s3, "1") == 0) { |
693 | printf("active_slot is %s\n", "b"); |
694 | strncat(response, "b", chars_left); |
695 | } |
696 | } else if (!strcmp_l1("has-slot:bootloader", cmd)) { |
697 | printf("do not has slot bootloader\n"); |
698 | strncat(response, "no", chars_left); |
699 | } else if (!strcmp_l1("has-slot:boot", cmd)) { |
700 | if (has_boot_slot == 1) { |
701 | printf("has boot slot\n"); |
702 | strncat(response, "yes", chars_left); |
703 | } else |
704 | strncat(response, "no", chars_left); |
705 | } else if (!strcmp_l1("has-slot:system", cmd)) { |
706 | if (dynamic_partition) { |
707 | strncat(response, "no", chars_left); |
708 | } else { |
709 | if (has_system_slot == 1) { |
710 | printf("has system slot\n"); |
711 | strncat(response, "yes", chars_left); |
712 | } else |
713 | strncat(response, "no", chars_left); |
714 | } |
715 | } else if (!strcmp_l1("has-slot:vendor", cmd)) { |
716 | if (dynamic_partition) { |
717 | strncat(response, "no", chars_left); |
718 | } else { |
719 | if (has_boot_slot == 1) { |
720 | printf("has vendor slot\n"); |
721 | strncat(response, "yes", chars_left); |
722 | } else |
723 | strncat(response, "no", chars_left); |
724 | } |
725 | } else if (!strcmp_l1("has-slot:vbmeta", cmd)) { |
726 | if (dynamic_partition) { |
727 | strncat(response, "no", chars_left); |
728 | } else { |
729 | if (has_boot_slot == 1) { |
730 | printf("has vbmeta slot\n"); |
731 | strncat(response, "yes", chars_left); |
732 | } else |
733 | strncat(response, "no", chars_left); |
734 | } |
735 | } else if (!strcmp_l1("has-slot:product", cmd)) { |
736 | if (dynamic_partition) { |
737 | strncat(response, "no", chars_left); |
738 | } else { |
739 | if (has_boot_slot == 1) { |
740 | printf("has product slot\n"); |
741 | strncat(response, "yes", chars_left); |
742 | } else |
743 | strncat(response, "no", chars_left); |
744 | } |
745 | } else if (!strcmp_l1("has-slot:super", cmd)) { |
746 | if (!dynamic_partition) { |
747 | strncat(response, "no", chars_left); |
748 | } else { |
749 | if (has_boot_slot == 1) { |
750 | printf("has product slot\n"); |
751 | strncat(response, "yes", chars_left); |
752 | } else |
753 | strncat(response, "no", chars_left); |
754 | } |
755 | } else if (!strcmp_l1("has-slot:metadata", cmd)) { |
756 | if (has_boot_slot == 1) { |
757 | printf("has metadata slot\n"); |
758 | strncat(response, "yes", chars_left); |
759 | } else |
760 | strncat(response, "no", chars_left); |
761 | } else if (!strcmp_l1("has-slot:dtbo", cmd)) { |
762 | if (has_boot_slot == 1) { |
763 | printf("has dtbo slot\n"); |
764 | strncat(response, "yes", chars_left); |
765 | } else |
766 | strncat(response, "no", chars_left); |
767 | } else if (!strcmp_l1("has-slot:data", cmd)) { |
768 | strncat(response, "no", chars_left); |
769 | } else if (!strcmp_l1("has-slot:misc", cmd)) { |
770 | strncat(response, "no", chars_left); |
771 | } else if (!strcmp_l1("has-slot:odm", cmd)) { |
772 | if (has_boot_slot == 1) { |
773 | printf("has odm slot\n"); |
774 | strncat(response, "yes", chars_left); |
775 | } else |
776 | strncat(response, "no", chars_left); |
777 | } else if (!strncmp("partition-size", cmd, strlen("partition-size"))) { |
778 | char str_num[20]; |
779 | struct partitions *pPartition; |
780 | uint64_t sz; |
781 | strsep(&cmd, ":"); |
782 | printf("partition is %s\n", cmd); |
783 | if (strcmp(cmd, "userdata") == 0) { |
784 | strcpy(cmd, "data"); |
785 | printf("partition is %s\n", cmd); |
786 | } |
787 | if (!strncmp("mbr", cmd, strlen("mbr"))) { |
788 | strcpy(response, "FAILVariable not implemented"); |
789 | } else { |
790 | if (!strncmp("bootloader-", cmd, strlen("bootloader-"))) { |
791 | strsep(&cmd, "-"); |
792 | mmc_boot_size(cmd, &sz); |
793 | printf("size:%016llx\n", sz); |
794 | sprintf(str_num, "%016llx", sz); |
795 | } else { |
796 | pPartition = find_mmc_partition_by_name(cmd); |
797 | if (pPartition) { |
798 | printf("size:%016llx\n", pPartition->size); |
799 | if (strcmp(cmd, "data") == 0) { |
800 | printf("reserve 0x4000 for fde data\n"); |
801 | sz = pPartition->size - 0x4000; |
802 | printf("data size :%016llx\n", sz); |
803 | sprintf(str_num, "%016llx", sz); |
804 | } else { |
805 | sprintf(str_num, "%016llx", pPartition->size); |
806 | } |
807 | } else { |
808 | printf("find_mmc_partition_by_name fail\n"); |
809 | sprintf(str_num, "get fail"); |
810 | } |
811 | } |
812 | strncat(response, str_num, chars_left); |
813 | } |
814 | } else if (!strcmp_l1("partition-type:cache", cmd)) { |
815 | if (has_boot_slot == 0) { |
816 | strncat(response, "ext4", chars_left); |
817 | } |
818 | } else if (!strcmp_l1("partition-type:data", cmd)) { |
819 | strncat(response, "ext4", chars_left); |
820 | } else if (!strcmp_l1("partition-type:userdata", cmd)) { |
821 | strncat(response, "ext4", chars_left); |
822 | } else if (!strcmp_l1("partition-type:system", cmd)) { |
823 | strncat(response, "ext4", chars_left); |
824 | } else if (!strcmp_l1("partition-type:vendor", cmd)) { |
825 | strncat(response, "ext4", chars_left); |
826 | } else if (!strcmp_l1("partition-type:odm", cmd)) { |
827 | strncat(response, "ext4", chars_left); |
828 | } else if (!strcmp_l1("partition-type:tee", cmd)) { |
829 | strncat(response, "ext4", chars_left); |
830 | } else if (!strcmp_l1("partition-type:param", cmd)) { |
831 | strncat(response, "ext4", chars_left); |
832 | } else if (!strcmp_l1("partition-type:product", cmd)) { |
833 | strncat(response, "ext4", chars_left); |
834 | } else if (!strcmp_l1("partition-type:metadata", cmd)) { |
835 | strncat(response, "ext4", chars_left); |
836 | } else if (!strncmp("partition-type", cmd, strlen("partition-type"))) { |
837 | strncat(response, "raw", chars_left); |
838 | } else if (!strcmp_l1("erase-block-size", cmd) || |
839 | !strcmp_l1("logical-block-size", cmd)) { |
840 | strncat(response, "2000", chars_left); |
841 | } else if (!strcmp_l1("secure", cmd)) { |
842 | if (check_lock()) { |
843 | strncat(response, "yes", chars_left); |
844 | } else { |
845 | strncat(response, "no", chars_left); |
846 | } |
847 | } else if (!strcmp_l1("unlocked", cmd)) { |
848 | if (check_lock()) { |
849 | strncat(response, "no", chars_left); |
850 | } else { |
851 | strncat(response, "yes", chars_left); |
852 | } |
853 | } else if (!strcmp_l1("slot-successful", cmd)) { |
854 | char str[128]; |
855 | strsep(&cmd, ":"); |
856 | printf("cmd is %s\n", cmd); |
857 | int ret; |
858 | if (has_boot_slot == 1) { |
859 | printf("has boot slot\n"); |
860 | sprintf(str, "get_slot_state %s successful", cmd); |
861 | printf("command: %s\n", str); |
862 | ret = run_command(str, 0); |
863 | printf("ret = %d\n", ret); |
864 | if (ret == 0) |
865 | strncat(response, "no", chars_left); |
866 | else |
867 | strncat(response, "yes", chars_left); |
868 | } else |
869 | strcpy(response, "FAILVariable not implemented in non ab mode"); |
870 | } else if (!strcmp_l1("slot-unbootable", cmd)) { |
871 | char str[128]; |
872 | strsep(&cmd, ":"); |
873 | printf("cmd is %s\n", cmd); |
874 | int ret; |
875 | if (has_boot_slot == 1) { |
876 | printf("has boot slot\n"); |
877 | sprintf(str, "get_slot_state %s unbootable", cmd); |
878 | printf("command: %s\n", str); |
879 | ret = run_command(str, 0); |
880 | printf("ret = %d\n", ret); |
881 | if (ret == 0) |
882 | strncat(response, "yes", chars_left); |
883 | else |
884 | strncat(response, "no", chars_left); |
885 | } else |
886 | strcpy(response, "FAILVariable not implemented in non ab mode"); |
887 | } else if (!strcmp_l1("slot-retry-count", cmd)) { |
888 | char str[128]; |
889 | strsep(&cmd, ":"); |
890 | printf("cmd is %s\n", cmd); |
891 | int ret; |
892 | if (has_boot_slot == 1) { |
893 | char str_num[12]; |
894 | printf("has boot slot\n"); |
895 | sprintf(str, "get_slot_state %s retry-count", cmd); |
896 | printf("command: %s\n", str); |
897 | ret = run_command(str, 0); |
898 | printf("ret = %d\n", ret); |
899 | sprintf(str_num, "%d", ret); |
900 | strncat(response, str_num, chars_left); |
901 | } else |
902 | strcpy(response, "FAILVariable not implemented in non ab mode"); |
903 | } else { |
904 | error("unknown variable: %s\n", cmd); |
905 | strcpy(response, "FAILVariable not implemented"); |
906 | } |
907 | |
908 | fastboot_tx_write_str(response); |
909 | } |
910 | |
911 | static unsigned int rx_bytes_expected(void) |
912 | { |
913 | int rx_remain = download_size - download_bytes; |
914 | if (rx_remain < 0) |
915 | return 0; |
916 | if (rx_remain > EP_BUFFER_SIZE) |
917 | return EP_BUFFER_SIZE; |
918 | return rx_remain; |
919 | } |
920 | |
921 | #define BYTES_PER_DOT 0x20000 |
922 | static void rx_handler_dl_image(struct usb_ep *ep, struct usb_request *req) |
923 | { |
924 | char response[RESPONSE_LEN]; |
925 | unsigned int transfer_size = download_size - download_bytes; |
926 | const unsigned char *buffer = req->buf; |
927 | unsigned int buffer_size = req->actual; |
928 | unsigned int pre_dot_num, now_dot_num; |
929 | |
930 | if (req->status != 0) { |
931 | printf("Bad status: %d\n", req->status); |
932 | return; |
933 | } |
934 | |
935 | if (buffer_size < transfer_size) |
936 | transfer_size = buffer_size; |
937 | |
938 | memcpy((void *)CONFIG_USB_FASTBOOT_BUF_ADDR + download_bytes, |
939 | buffer, transfer_size); |
940 | |
941 | pre_dot_num = download_bytes / BYTES_PER_DOT; |
942 | download_bytes += transfer_size; |
943 | now_dot_num = download_bytes / BYTES_PER_DOT; |
944 | |
945 | if (pre_dot_num != now_dot_num) { |
946 | putc('.'); |
947 | if (!(now_dot_num % 74)) |
948 | putc('\n'); |
949 | } |
950 | |
951 | /* Check if transfer is done */ |
952 | if (download_bytes >= download_size) { |
953 | /* |
954 | * Reset global transfer variable, keep download_bytes because |
955 | * it will be used in the next possible flashing command |
956 | */ |
957 | download_size = 0; |
958 | req->complete = rx_handler_command; |
959 | req->length = EP_BUFFER_SIZE; |
960 | |
961 | sprintf(response, "OKAY"); |
962 | fastboot_tx_write_str(response); |
963 | |
964 | printf("\ndownloading of %d bytes finished\n", download_bytes); |
965 | } else { |
966 | req->length = rx_bytes_expected(); |
967 | if (req->length < ep->maxpacket) |
968 | req->length = ep->maxpacket; |
969 | } |
970 | |
971 | req->actual = 0; |
972 | usb_ep_queue(ep, req, 0); |
973 | } |
974 | |
975 | static void cb_download(struct usb_ep *ep, struct usb_request *req) |
976 | { |
977 | char *cmd = req->buf; |
978 | char response[RESPONSE_LEN]; |
979 | |
980 | printf("cmd cb_download is %s\n", cmd); |
981 | |
982 | strsep(&cmd, ":"); |
983 | download_size = simple_strtoul(cmd, NULL, 16); |
984 | download_bytes = 0; |
985 | |
986 | printf("Starting download of %d bytes\n", download_size); |
987 | |
988 | if (0 == download_size) { |
989 | sprintf(response, "FAILdata invalid size"); |
990 | } else if (download_size > ddr_size_usable(CONFIG_USB_FASTBOOT_BUF_ADDR)) { |
991 | download_size = 0; |
992 | sprintf(response, "FAILdata too large"); |
993 | } else { |
994 | sprintf(response, "DATA%08x", download_size); |
995 | req->complete = rx_handler_dl_image; |
996 | req->length = rx_bytes_expected(); |
997 | if (req->length < ep->maxpacket) |
998 | req->length = ep->maxpacket; |
999 | } |
1000 | fastboot_tx_write_str(response); |
1001 | } |
1002 | |
1003 | typedef struct andr_img_hdr boot_img_hdr; |
1004 | |
1005 | static void do_bootm_on_complete(struct usb_ep *ep, struct usb_request *req) |
1006 | { |
1007 | char boot_addr_start[12]; |
1008 | unsigned kernel_size; |
1009 | unsigned ramdisk_size; |
1010 | boot_img_hdr *hdr_addr = NULL; |
1011 | int genFmt = 0; |
1012 | unsigned actualBootImgSz = 0; |
1013 | unsigned dtbSz = 0; |
1014 | unsigned char* loadaddr = 0; |
1015 | |
1016 | puts("Booting kernel...\n"); |
1017 | |
1018 | sprintf(boot_addr_start, "bootm 0x%lx", load_addr); |
1019 | printf("boot_addr_start %s\n", boot_addr_start); |
1020 | |
1021 | loadaddr = (unsigned char*)CONFIG_USB_FASTBOOT_BUF_ADDR; |
1022 | hdr_addr = (boot_img_hdr*)loadaddr; |
1023 | |
1024 | genFmt = genimg_get_format(hdr_addr); |
1025 | if (IMAGE_FORMAT_ANDROID != genFmt) { |
1026 | printf("Fmt unsupported!genFmt 0x%x != 0x%x\n", genFmt, IMAGE_FORMAT_ANDROID); |
1027 | return; |
1028 | } |
1029 | |
1030 | kernel_size =(hdr_addr->kernel_size + (hdr_addr->page_size-1)+hdr_addr->page_size)&(~(hdr_addr->page_size -1)); |
1031 | ramdisk_size =(hdr_addr->ramdisk_size + (hdr_addr->page_size-1))&(~(hdr_addr->page_size -1)); |
1032 | dtbSz = hdr_addr->second_size; |
1033 | actualBootImgSz = kernel_size + ramdisk_size + dtbSz; |
1034 | printf("kernel_size 0x%x, page_size 0x%x, totalSz 0x%x\n", hdr_addr->kernel_size, hdr_addr->page_size, kernel_size); |
1035 | printf("ramdisk_size 0x%x, totalSz 0x%x\n", hdr_addr->ramdisk_size, ramdisk_size); |
1036 | printf("dtbSz 0x%x, Total actualBootImgSz 0x%x\n", dtbSz, actualBootImgSz); |
1037 | |
1038 | memcpy((void *)load_addr, (void *)CONFIG_USB_FASTBOOT_BUF_ADDR, actualBootImgSz); |
1039 | |
1040 | flush_cache(load_addr,(unsigned long)actualBootImgSz); |
1041 | |
1042 | run_command(boot_addr_start, 0); |
1043 | |
1044 | /* This only happens if image is somehow faulty so we start over */ |
1045 | do_reset(NULL, 0, 0, NULL); |
1046 | } |
1047 | |
1048 | static void cb_boot(struct usb_ep *ep, struct usb_request *req) |
1049 | { |
1050 | fastboot_func->in_req->complete = do_bootm_on_complete; |
1051 | fastboot_tx_write_str("OKAY"); |
1052 | } |
1053 | |
1054 | static void do_exit_on_complete(struct usb_ep *ep, struct usb_request *req) |
1055 | { |
1056 | puts("Booting kernel..\n"); |
1057 | run_command("run storeboot", 0); |
1058 | |
1059 | /* This only happens if image is somehow faulty so we start over */ |
1060 | do_reset(NULL, 0, 0, NULL); |
1061 | } |
1062 | |
1063 | |
1064 | static void cb_continue(struct usb_ep *ep, struct usb_request *req) |
1065 | { |
1066 | fastboot_func->in_req->complete = do_exit_on_complete; |
1067 | fastboot_tx_write_str("OKAY"); |
1068 | } |
1069 | |
1070 | static void cb_flashing(struct usb_ep *ep, struct usb_request *req) |
1071 | { |
1072 | char *cmd; |
1073 | char* response = response_str; |
1074 | char* lock_s; |
1075 | LockData_t* info; |
1076 | size_t chars_left; |
1077 | char lock_d[LOCK_DATA_SIZE]; |
1078 | |
1079 | lock_s = getenv("lock"); |
1080 | if (!lock_s) { |
1081 | printf("lock state is NULL \n"); |
1082 | strcpy(lock_d, "10000000"); |
1083 | lock_s = "10000000"; |
1084 | setenv("lock", "10000000"); |
1085 | run_command("defenv_reserv; saveenv;", 0); |
1086 | } else { |
1087 | printf("lock state: %s\n", lock_s); |
1088 | if (strlen(lock_s) > 15) |
1089 | strncpy(lock_d, lock_s, 15); |
1090 | else |
1091 | strncpy(lock_d, lock_s, strlen(lock_s)); |
1092 | } |
1093 | |
1094 | info = malloc(sizeof(struct LockData)); |
1095 | if (!info) { |
1096 | error("malloc error\n"); |
1097 | fastboot_tx_write_str("FAILmalloc error"); |
1098 | return; |
1099 | } |
1100 | memset(info,0,LOCK_DATA_SIZE); |
1101 | info->version_major = (int)(lock_d[0] - '0'); |
1102 | info->version_minor = (int)(lock_d[1] - '0'); |
1103 | info->lock_state = (int)(lock_d[4] - '0'); |
1104 | info->lock_critical_state = (int)(lock_d[5] - '0'); |
1105 | info->lock_bootloader = (int)(lock_d[6] - '0'); |
1106 | dump_lock_info(info); |
1107 | |
1108 | strcpy(response, "OKAY"); |
1109 | chars_left = sizeof(response_str) - strlen(response) - 1; |
1110 | cmd = req->buf; |
1111 | strsep(&cmd, " "); |
1112 | printf("cb_flashing: %s\n", cmd); |
1113 | if (!cmd) { |
1114 | error("missing variable\n"); |
1115 | fastboot_tx_write_str("FAILmissing var"); |
1116 | free(info); |
1117 | return; |
1118 | } |
1119 | |
1120 | if (!strcmp_l1("unlock_critical", cmd)) { |
1121 | info->lock_critical_state = 0; |
1122 | } else if (!strcmp_l1("lock_critical", cmd)) { |
1123 | info->lock_critical_state = 1; |
1124 | } else if (!strcmp_l1("get_unlock_ability", cmd)) { |
1125 | char str_num[8]; |
1126 | sprintf(str_num, "%d", info->lock_state); |
1127 | strncat(response, str_num, chars_left); |
1128 | } else if (!strcmp_l1("get_unlock_bootloader_nonce", cmd)) { |
1129 | char str_num[8]; |
1130 | sprintf(str_num, "%d", info->lock_critical_state); |
1131 | strncat(response, str_num, chars_left); |
1132 | } else if (!strcmp_l1("unlock_bootloader", cmd)) { |
1133 | strncat(response, "please run flashing unlock & flashing unlock_critical before write", chars_left); |
1134 | } else if (!strcmp_l1("lock_bootloader", cmd)) { |
1135 | info->lock_bootloader = 1; |
1136 | } else if (!strcmp_l1("unlock", cmd)) { |
1137 | if (info->lock_state == 1 ) { |
1138 | char *avb_s; |
1139 | avb_s = getenv("avb2"); |
1140 | if (avb_s == NULL) { |
1141 | run_command("get_avb_mode;", 0); |
1142 | avb_s = getenv("avb2"); |
1143 | } |
1144 | printf("avb2: %s\n", avb_s); |
1145 | if (strcmp(avb_s, "1") == 0) { |
1146 | #ifdef CONFIG_AML_ANTIROLLBACK |
1147 | if (avb_unlock()) { |
1148 | printf("unlocking device. Erasing userdata partition!\n"); |
1149 | run_command("store erase partition data", 0); |
1150 | } else { |
1151 | printf("unlock failed!\n"); |
1152 | } |
1153 | #else |
1154 | printf("unlocking device. Erasing userdata partition!\n"); |
1155 | run_command("store erase partition data", 0); |
1156 | #endif |
1157 | } |
1158 | } |
1159 | info->lock_state = 0; |
1160 | info->lock_critical_state = 0; |
1161 | } else if (!strcmp_l1("lock", cmd)) { |
1162 | if (info->lock_state == 0 ) { |
1163 | char *avb_s; |
1164 | avb_s = getenv("avb2"); |
1165 | if (avb_s == NULL) { |
1166 | run_command("get_avb_mode;", 0); |
1167 | avb_s = getenv("avb2"); |
1168 | } |
1169 | printf("avb2: %s\n", avb_s); |
1170 | if (strcmp(avb_s, "1") == 0) { |
1171 | #ifdef CONFIG_AML_ANTIROLLBACK |
1172 | if (avb_lock()) { |
1173 | printf("lock failed!\n"); |
1174 | } else { |
1175 | printf("locking device. Erasing userdata partition!\n"); |
1176 | run_command("store erase partition data", 0); |
1177 | } |
1178 | #else |
1179 | printf("locking device. Erasing userdata partition!\n"); |
1180 | run_command("store erase partition data", 0); |
1181 | #endif |
1182 | } |
1183 | } |
1184 | info->lock_state = 1; |
1185 | } else { |
1186 | error("unknown variable: %s\n", cmd); |
1187 | strcpy(response, "FAILVariable not implemented"); |
1188 | } |
1189 | |
1190 | dump_lock_info(info); |
1191 | sprintf(lock_d, "%d%d00%d%d%d0", info->version_major, info->version_minor, info->lock_state, info->lock_critical_state, info->lock_bootloader); |
1192 | printf("lock_d state: %s\n", lock_d); |
1193 | setenv("lock", lock_d); |
1194 | run_command("defenv_reserv; saveenv;", 0); |
1195 | printf("response: %s\n", response); |
1196 | free(info); |
1197 | fastboot_tx_write_str(response); |
1198 | } |
1199 | |
1200 | |
1201 | #ifdef CONFIG_FASTBOOT_FLASH |
1202 | static void cb_flash(struct usb_ep *ep, struct usb_request *req) |
1203 | { |
1204 | char *cmd = req->buf; |
1205 | char* response = response_str; |
1206 | |
1207 | printf("cmd cb_flash is %s\n", cmd); |
1208 | |
1209 | strsep(&cmd, ":"); |
1210 | if (!cmd) { |
1211 | error("missing partition name\n"); |
1212 | fastboot_tx_write_str("FAILmissing partition name"); |
1213 | return; |
1214 | } |
1215 | |
1216 | if (check_lock()) { |
1217 | error("device is locked, can not run this cmd.Please flashing unlock & flashing unlock_critical\n"); |
1218 | fastboot_tx_write_str("FAILlocked device"); |
1219 | return; |
1220 | } |
1221 | |
1222 | #ifdef CONFIG_BOOTLOADER_CONTROL_BLOCK |
1223 | if (dynamic_partition) { |
1224 | if (is_partition_logical(cmd) == 0) { |
1225 | error("%s is logic partition, can not write here.......\n", cmd); |
1226 | fastboot_tx_write_str("FAILlogic partition"); |
1227 | return; |
1228 | } |
1229 | } |
1230 | #endif |
1231 | |
1232 | printf("partition is %s\n", cmd); |
1233 | if (strcmp(cmd, "userdata") == 0) { |
1234 | strcpy(cmd, "data"); |
1235 | printf("partition is %s\n", cmd); |
1236 | } |
1237 | |
1238 | if (strcmp(cmd, "dts") == 0) { |
1239 | strcpy(cmd, "dtb"); |
1240 | printf("partition is %s\n", cmd); |
1241 | } |
1242 | |
1243 | //strcpy(response, "FAILno flash device defined"); |
1244 | if (is_mainstorage_emmc()) { |
1245 | #ifdef CONFIG_FASTBOOT_FLASH_MMC_DEV |
1246 | fb_mmc_flash_write(cmd, (void *)CONFIG_USB_FASTBOOT_BUF_ADDR, |
1247 | download_bytes); |
1248 | #endif |
1249 | } else if (is_mainstorage_nand()) { |
1250 | #ifdef CONFIG_FASTBOOT_FLASH_NAND_DEV |
1251 | fb_nand_flash_write(cmd, (void *)CONFIG_USB_FASTBOOT_BUF_ADDR, |
1252 | download_bytes); |
1253 | #else |
1254 | fastboot_fail("not support nftl\n"); |
1255 | #endif |
1256 | } else { |
1257 | printf("error: no valid fastboot device\n"); |
1258 | fastboot_fail("no vaild device\n"); |
1259 | } |
1260 | fastboot_tx_write_str(response); |
1261 | } |
1262 | #endif |
1263 | |
1264 | static void cb_set_active(struct usb_ep *ep, struct usb_request *req) |
1265 | { |
1266 | char *cmd = req->buf; |
1267 | //char response[RESPONSE_LEN]; |
1268 | int ret = 0; |
1269 | char str[128]; |
1270 | |
1271 | printf("cmd cb_set_active is %s\n", cmd); |
1272 | strsep(&cmd, ":"); |
1273 | if (!cmd) { |
1274 | error("missing slot name\n"); |
1275 | fastboot_tx_write_str("FAILmissing slot name"); |
1276 | return; |
1277 | } |
1278 | |
1279 | if (check_lock()) { |
1280 | error("device is locked, can not run this cmd.Please flashing unlock & flashing unlock_critical\n"); |
1281 | fastboot_tx_write_str("FAILlocked device"); |
1282 | return; |
1283 | } |
1284 | |
1285 | sprintf(str, "set_active_slot %s", cmd); |
1286 | printf("command: %s\n", str); |
1287 | ret = run_command(str, 0); |
1288 | printf("ret = %d\n", ret); |
1289 | if (ret == 0) |
1290 | fastboot_tx_write_str("OKAY"); |
1291 | else |
1292 | fastboot_tx_write_str("FAILset slot error"); |
1293 | } |
1294 | |
1295 | static void cb_flashall(struct usb_ep *ep, struct usb_request *req) |
1296 | { |
1297 | char* response = response_str; |
1298 | char *cmd = req->buf; |
1299 | |
1300 | printf("cmd cb_flashall is %s\n", cmd); |
1301 | |
1302 | if (check_lock()) { |
1303 | error("device is locked, can not run this cmd.Please flashing unlock & flashing unlock_critical\n"); |
1304 | fastboot_tx_write_str("FAILlocked device"); |
1305 | return; |
1306 | } |
1307 | |
1308 | //strcpy(response, "FAILno flash device defined"); |
1309 | if (is_mainstorage_emmc()) { |
1310 | #ifdef CONFIG_FASTBOOT_FLASH_MMC_DEV |
1311 | fb_mmc_flash_write(cmd, (void *)CONFIG_USB_FASTBOOT_BUF_ADDR, |
1312 | download_bytes); |
1313 | #endif |
1314 | } else if (is_mainstorage_nand()) { |
1315 | #ifdef CONFIG_FASTBOOT_FLASH_NAND_DEV |
1316 | fb_nand_flash_write(cmd, (void *)CONFIG_USB_FASTBOOT_BUF_ADDR, |
1317 | download_bytes); |
1318 | #else |
1319 | fastboot_fail("not support nftl\n"); |
1320 | #endif |
1321 | } else { |
1322 | printf("error: no valid fastboot device\n"); |
1323 | fastboot_fail("no vaild device\n"); |
1324 | } |
1325 | fastboot_tx_write_str(response); |
1326 | } |
1327 | |
1328 | static void cb_erase(struct usb_ep *ep, struct usb_request *req) |
1329 | { |
1330 | char* response = response_str; |
1331 | char *cmd = req->buf; |
1332 | |
1333 | printf("cmd cb_erase is %s\n", cmd); |
1334 | |
1335 | strsep(&cmd, ":"); |
1336 | if (!cmd) { |
1337 | error("missing partition name\n"); |
1338 | fastboot_tx_write_str("FAILmissing partition name"); |
1339 | return; |
1340 | } |
1341 | |
1342 | if (check_lock()) { |
1343 | error("device is locked, can not run this cmd.Please flashing unlock & flashing unlock_critical\n"); |
1344 | fastboot_tx_write_str("FAILlocked device"); |
1345 | return; |
1346 | } |
1347 | |
1348 | printf("partition is %s\n", cmd); |
1349 | if (strcmp(cmd, "userdata") == 0) { |
1350 | strcpy(cmd, "data"); |
1351 | printf("partition is %s\n", cmd); |
1352 | } |
1353 | |
1354 | if (strcmp(cmd, "dts") == 0) { |
1355 | strcpy(cmd, "dtb"); |
1356 | printf("partition is %s\n", cmd); |
1357 | } |
1358 | |
1359 | //strcpy(response, "FAILno erase device defined"); |
1360 | if (is_mainstorage_emmc()) { |
1361 | #ifdef CONFIG_FASTBOOT_FLASH_MMC_DEV |
1362 | fb_mmc_erase_write(cmd, (void *)CONFIG_USB_FASTBOOT_BUF_ADDR); |
1363 | #endif |
1364 | } else if (is_mainstorage_nand()) { |
1365 | #ifdef CONFIG_FASTBOOT_FLASH_NAND_DEV |
1366 | fb_nand_erase(cmd, (void *)CONFIG_USB_FASTBOOT_BUF_ADDR); |
1367 | #else |
1368 | fastboot_fail("not support nftl\n"); |
1369 | #endif |
1370 | } else { |
1371 | printf("error: no valid fastboot device\n"); |
1372 | fastboot_fail("no vaild device\n"); |
1373 | } |
1374 | fastboot_tx_write_str(response); |
1375 | } |
1376 | |
1377 | static void cb_devices(struct usb_ep *ep, struct usb_request *req) |
1378 | { |
1379 | char response[RESPONSE_LEN]; |
1380 | char *cmd = req->buf; |
1381 | |
1382 | printf("cmd is %s\n", cmd); |
1383 | |
1384 | strcpy(response, "AMLOGIC"); |
1385 | |
1386 | fastboot_tx_write_str(response); |
1387 | } |
1388 | |
1389 | static void cb_oem_cmd(struct usb_ep *ep, struct usb_request *req) |
1390 | { |
1391 | char response[RESPONSE_LEN/2 + 1]; |
1392 | char* cmd = req->buf; |
1393 | printf("oem cmd[%s]\n", cmd); |
1394 | static int i = 0; |
1395 | |
1396 | memcpy(response, cmd, strnlen(cmd, RESPONSE_LEN/2)+1);//+1 to terminate str |
1397 | cmd = response; |
1398 | strsep(&cmd, " "); |
1399 | FB_MSG("To run cmd[%s]\n", cmd); |
1400 | run_command(cmd, 0); |
1401 | |
1402 | if (++i > 3) i = 0; |
1403 | |
1404 | i ? fastboot_busy("AMLOGIC") : fastboot_okay(response); |
1405 | fastboot_tx_write_str(response_str); |
1406 | return ; |
1407 | } |
1408 | |
1409 | struct cmd_dispatch_info { |
1410 | char *cmd; |
1411 | void (*cb)(struct usb_ep *ep, struct usb_request *req); |
1412 | }; |
1413 | |
1414 | static const struct cmd_dispatch_info cmd_dispatch_info[] = { |
1415 | { |
1416 | .cmd = "reboot", |
1417 | .cb = cb_reboot, |
1418 | }, { |
1419 | .cmd = "getvar:", |
1420 | .cb = cb_getvar, |
1421 | }, { |
1422 | .cmd = "download:", |
1423 | .cb = cb_download, |
1424 | }, { |
1425 | .cmd = "boot", |
1426 | .cb = cb_boot, |
1427 | }, { |
1428 | .cmd = "continue", |
1429 | .cb = cb_continue, |
1430 | }, { |
1431 | .cmd = "flashing", |
1432 | .cb = cb_flashing, |
1433 | }, |
1434 | #ifdef CONFIG_FASTBOOT_FLASH |
1435 | { |
1436 | .cmd = "flash", |
1437 | .cb = cb_flash, |
1438 | }, |
1439 | #endif |
1440 | { |
1441 | .cmd = "update", |
1442 | .cb = cb_download, |
1443 | }, |
1444 | { |
1445 | .cmd = "flashall", |
1446 | .cb = cb_flashall, |
1447 | }, |
1448 | { |
1449 | .cmd = "erase", |
1450 | .cb = cb_erase, |
1451 | }, |
1452 | { |
1453 | .cmd = "devices", |
1454 | .cb = cb_devices, |
1455 | }, |
1456 | { |
1457 | .cmd = "reboot-bootloader", |
1458 | .cb = cb_reboot, |
1459 | }, |
1460 | { |
1461 | .cmd = "reboot-fastboot", |
1462 | .cb = cb_reboot, |
1463 | }, |
1464 | { |
1465 | .cmd = "set_active", |
1466 | .cb = cb_set_active, |
1467 | }, |
1468 | { |
1469 | .cmd = "oem", |
1470 | .cb = cb_oem_cmd, |
1471 | } |
1472 | }; |
1473 | |
1474 | //cb for out_req->complete |
1475 | static void rx_handler_command(struct usb_ep *ep, struct usb_request *req) |
1476 | { |
1477 | char *cmdbuf = req->buf; |
1478 | void (*func_cb)(struct usb_ep *ep, struct usb_request *req) = NULL; |
1479 | int i; |
1480 | |
1481 | for (i = 0; i < ARRAY_SIZE(cmd_dispatch_info); i++) { |
1482 | if (!strcmp_l1(cmd_dispatch_info[i].cmd, cmdbuf)) { |
1483 | func_cb = cmd_dispatch_info[i].cb; |
1484 | break; |
1485 | } |
1486 | } |
1487 | |
1488 | if (!func_cb) { |
1489 | error("unknown command: %s\n", cmdbuf); |
1490 | fastboot_tx_write_str("FAILunknown command"); |
1491 | } else { |
1492 | if (req->actual < req->length) { |
1493 | u8 *buf = (u8 *)req->buf; |
1494 | buf[req->actual] = 0; |
1495 | func_cb(ep, req); |
1496 | } else { |
1497 | error("buffer overflow\n"); |
1498 | fastboot_tx_write_str("FAILbuffer overflow"); |
1499 | } |
1500 | } |
1501 | |
1502 | if (req->status == 0 && !fastboot_is_busy()) { |
1503 | *cmdbuf = '\0'; |
1504 | req->actual = 0; |
1505 | usb_ep_queue(ep, req, 0); |
1506 | } |
1507 | } |
1508 |