1 // SPDX-License-Identifier: BSD-2-Clause
2 /*
3 * Copyright (C) 2016 The Android Open Source Project
4 */
5
6 #include <command.h>
7 #include <console.h>
8 #include <env.h>
9 #include <fastboot.h>
10 #include <fastboot-internal.h>
11 #include <fb_mmc.h>
12 #include <fb_nand.h>
13 #include <fb_spi_flash.h>
14 #include <part.h>
15 #include <stdlib.h>
16 #include <vsprintf.h>
17 #include <linux/printk.h>
18
19 /**
20 * image_size - final fastboot image size
21 */
22 static u32 image_size;
23
24 /**
25 * fastboot_bytes_received - number of bytes received in the current download
26 */
27 static u32 fastboot_bytes_received;
28
29 /**
30 * fastboot_bytes_expected - number of bytes expected in the current download
31 */
32 static u32 fastboot_bytes_expected;
33
34 static void okay(char *, char *);
35 static void getvar(char *, char *);
36 static void download(char *, char *);
37 static void flash(char *, char *);
38 static void erase(char *, char *);
39 static void reboot_bootloader(char *, char *);
40 static void reboot_fastbootd(char *, char *);
41 static void reboot_recovery(char *, char *);
42 static void oem_format(char *, char *);
43 static void oem_partconf(char *, char *);
44 static void oem_bootbus(char *, char *);
45 static void oem_console(char *, char *);
46 static void oem_board(char *, char *);
47 static void run_ucmd(char *, char *);
48 static void run_acmd(char *, char *);
49
50 static const struct {
51 const char *command;
52 void (*dispatch)(char *cmd_parameter, char *response);
53 } commands[FASTBOOT_COMMAND_COUNT] = {
54 [FASTBOOT_COMMAND_GETVAR] = {
55 .command = "getvar",
56 .dispatch = getvar
57 },
58 [FASTBOOT_COMMAND_DOWNLOAD] = {
59 .command = "download",
60 .dispatch = download
61 },
62 [FASTBOOT_COMMAND_FLASH] = {
63 .command = "flash",
64 .dispatch = CONFIG_IS_ENABLED(FASTBOOT_FLASH, (flash), (NULL))
65 },
66 [FASTBOOT_COMMAND_ERASE] = {
67 .command = "erase",
68 .dispatch = CONFIG_IS_ENABLED(FASTBOOT_FLASH, (erase), (NULL))
69 },
70 [FASTBOOT_COMMAND_BOOT] = {
71 .command = "boot",
72 .dispatch = okay
73 },
74 [FASTBOOT_COMMAND_CONTINUE] = {
75 .command = "continue",
76 .dispatch = okay
77 },
78 [FASTBOOT_COMMAND_REBOOT] = {
79 .command = "reboot",
80 .dispatch = okay
81 },
82 [FASTBOOT_COMMAND_REBOOT_BOOTLOADER] = {
83 .command = "reboot-bootloader",
84 .dispatch = reboot_bootloader
85 },
86 [FASTBOOT_COMMAND_REBOOT_FASTBOOTD] = {
87 .command = "reboot-fastboot",
88 .dispatch = reboot_fastbootd
89 },
90 [FASTBOOT_COMMAND_REBOOT_RECOVERY] = {
91 .command = "reboot-recovery",
92 .dispatch = reboot_recovery
93 },
94 [FASTBOOT_COMMAND_SET_ACTIVE] = {
95 .command = "set_active",
96 .dispatch = okay
97 },
98 [FASTBOOT_COMMAND_OEM_FORMAT] = {
99 .command = "oem format",
100 .dispatch = CONFIG_IS_ENABLED(FASTBOOT_CMD_OEM_FORMAT, (oem_format), (NULL))
101 },
102 [FASTBOOT_COMMAND_OEM_PARTCONF] = {
103 .command = "oem partconf",
104 .dispatch = CONFIG_IS_ENABLED(FASTBOOT_CMD_OEM_PARTCONF, (oem_partconf), (NULL))
105 },
106 [FASTBOOT_COMMAND_OEM_BOOTBUS] = {
107 .command = "oem bootbus",
108 .dispatch = CONFIG_IS_ENABLED(FASTBOOT_CMD_OEM_BOOTBUS, (oem_bootbus), (NULL))
109 },
110 [FASTBOOT_COMMAND_OEM_RUN] = {
111 .command = "oem run",
112 .dispatch = CONFIG_IS_ENABLED(FASTBOOT_OEM_RUN, (run_ucmd), (NULL))
113 },
114 [FASTBOOT_COMMAND_OEM_CONSOLE] = {
115 .command = "oem console",
116 .dispatch = CONFIG_IS_ENABLED(FASTBOOT_CMD_OEM_CONSOLE, (oem_console), (NULL))
117 },
118 [FASTBOOT_COMMAND_OEM_BOARD] = {
119 .command = "oem board",
120 .dispatch = CONFIG_IS_ENABLED(FASTBOOT_OEM_BOARD, (oem_board), (NULL))
121 },
122 [FASTBOOT_COMMAND_UCMD] = {
123 .command = "UCmd",
124 .dispatch = CONFIG_IS_ENABLED(FASTBOOT_UUU_SUPPORT, (run_ucmd), (NULL))
125 },
126 [FASTBOOT_COMMAND_ACMD] = {
127 .command = "ACmd",
128 .dispatch = CONFIG_IS_ENABLED(FASTBOOT_UUU_SUPPORT, (run_acmd), (NULL))
129 },
130 };
131
132 /**
133 * fastboot_handle_command - Handle fastboot command
134 *
135 * @cmd_string: Pointer to command string
136 * @response: Pointer to fastboot response buffer
137 *
138 * Return: Executed command, or -1 if not recognized
139 */
fastboot_handle_command(char * cmd_string,char * response)140 int fastboot_handle_command(char *cmd_string, char *response)
141 {
142 int i;
143 char *cmd_parameter;
144
145 cmd_parameter = cmd_string;
146 strsep(&cmd_parameter, ":");
147
148 for (i = 0; i < FASTBOOT_COMMAND_COUNT; i++) {
149 if (!strcmp(commands[i].command, cmd_string)) {
150 if (commands[i].dispatch) {
151 commands[i].dispatch(cmd_parameter,
152 response);
153 return i;
154 } else {
155 pr_err("command %s not supported.\n", cmd_string);
156 fastboot_fail("Unsupported command", response);
157 return -1;
158 }
159 }
160 }
161
162 pr_err("command %s not recognized.\n", cmd_string);
163 fastboot_fail("unrecognized command", response);
164 return -1;
165 }
166
fastboot_multiresponse(int cmd,char * response)167 void fastboot_multiresponse(int cmd, char *response)
168 {
169 switch (cmd) {
170 case FASTBOOT_COMMAND_GETVAR:
171 fastboot_getvar_all(response);
172 break;
173 case FASTBOOT_COMMAND_OEM_CONSOLE:
174 if (CONFIG_IS_ENABLED(FASTBOOT_CMD_OEM_CONSOLE)) {
175 char buf[FASTBOOT_RESPONSE_LEN] = { 0 };
176
177 if (console_record_isempty()) {
178 console_record_reset();
179 fastboot_okay(NULL, response);
180 } else {
181 int ret = console_record_readline(buf, sizeof(buf) - 5);
182
183 if (ret < 0)
184 fastboot_fail("Error reading console", response);
185 else
186 fastboot_response("INFO", response, "%s", buf);
187 }
188 break;
189 }
190 fallthrough;
191 default:
192 fastboot_fail("Unknown multiresponse command", response);
193 break;
194 }
195 }
196
197 /**
198 * okay() - Send bare OKAY response
199 *
200 * @cmd_parameter: Pointer to command parameter
201 * @response: Pointer to fastboot response buffer
202 *
203 * Send a bare OKAY fastboot response. This is used where the command is
204 * valid, but all the work is done after the response has been sent (e.g.
205 * boot, reboot etc.)
206 */
okay(char * cmd_parameter,char * response)207 static void okay(char *cmd_parameter, char *response)
208 {
209 fastboot_okay(NULL, response);
210 }
211
212 /**
213 * getvar() - Read a config/version variable
214 *
215 * @cmd_parameter: Pointer to command parameter
216 * @response: Pointer to fastboot response buffer
217 */
getvar(char * cmd_parameter,char * response)218 static void getvar(char *cmd_parameter, char *response)
219 {
220 fastboot_getvar(cmd_parameter, response);
221 }
222
223 /**
224 * fastboot_download() - Start a download transfer from the client
225 *
226 * @cmd_parameter: Pointer to command parameter
227 * @response: Pointer to fastboot response buffer
228 */
download(char * cmd_parameter,char * response)229 static void download(char *cmd_parameter, char *response)
230 {
231 char *tmp;
232
233 if (!cmd_parameter) {
234 fastboot_fail("Expected command parameter", response);
235 return;
236 }
237 fastboot_bytes_received = 0;
238 fastboot_bytes_expected = hextoul(cmd_parameter, &tmp);
239 if (fastboot_bytes_expected == 0) {
240 fastboot_fail("Expected nonzero image size", response);
241 return;
242 }
243 /*
244 * Nothing to download yet. Response is of the form:
245 * [DATA|FAIL]$cmd_parameter
246 *
247 * where cmd_parameter is an 8 digit hexadecimal number
248 */
249 if (fastboot_bytes_expected > fastboot_buf_size) {
250 fastboot_fail(cmd_parameter, response);
251 } else {
252 printf("Starting download of %d bytes\n",
253 fastboot_bytes_expected);
254 fastboot_response("DATA", response, "%s", cmd_parameter);
255 }
256 }
257
258 /**
259 * fastboot_data_remaining() - return bytes remaining in current transfer
260 *
261 * Return: Number of bytes left in the current download
262 */
fastboot_data_remaining(void)263 u32 fastboot_data_remaining(void)
264 {
265 return fastboot_bytes_expected - fastboot_bytes_received;
266 }
267
268 /**
269 * fastboot_data_download() - Copy image data to fastboot_buf_addr.
270 *
271 * @fastboot_data: Pointer to received fastboot data
272 * @fastboot_data_len: Length of received fastboot data
273 * @response: Pointer to fastboot response buffer
274 *
275 * Copies image data from fastboot_data to fastboot_buf_addr. Writes to
276 * response. fastboot_bytes_received is updated to indicate the number
277 * of bytes that have been transferred.
278 *
279 * On completion sets image_size and ${filesize} to the total size of the
280 * downloaded image.
281 */
fastboot_data_download(const void * fastboot_data,unsigned int fastboot_data_len,char * response)282 void fastboot_data_download(const void *fastboot_data,
283 unsigned int fastboot_data_len,
284 char *response)
285 {
286 #define BYTES_PER_DOT 0x20000
287 u32 pre_dot_num, now_dot_num;
288
289 if (fastboot_data_len == 0 ||
290 (fastboot_bytes_received + fastboot_data_len) >
291 fastboot_bytes_expected) {
292 fastboot_fail("Received invalid data length",
293 response);
294 return;
295 }
296 /* Download data to fastboot_buf_addr */
297 memcpy(fastboot_buf_addr + fastboot_bytes_received,
298 fastboot_data, fastboot_data_len);
299
300 pre_dot_num = fastboot_bytes_received / BYTES_PER_DOT;
301 fastboot_bytes_received += fastboot_data_len;
302 now_dot_num = fastboot_bytes_received / BYTES_PER_DOT;
303
304 if (pre_dot_num != now_dot_num) {
305 putc('.');
306 if (!(now_dot_num % 74))
307 putc('\n');
308 }
309 *response = '\0';
310 }
311
312 /**
313 * fastboot_data_complete() - Mark current transfer complete
314 *
315 * @response: Pointer to fastboot response buffer
316 *
317 * Set image_size and ${filesize} to the total size of the downloaded image.
318 */
fastboot_data_complete(char * response)319 void fastboot_data_complete(char *response)
320 {
321 /* Download complete. Respond with "OKAY" */
322 fastboot_okay(NULL, response);
323 printf("\ndownloading of %d bytes finished\n", fastboot_bytes_received);
324 image_size = fastboot_bytes_received;
325 env_set_hex("filesize", image_size);
326 fastboot_bytes_expected = 0;
327 fastboot_bytes_received = 0;
328 }
329
330 /**
331 * flash() - write the downloaded image to the indicated partition.
332 *
333 * @cmd_parameter: Pointer to partition name
334 * @response: Pointer to fastboot response buffer
335 *
336 * Writes the previously downloaded image to the partition indicated by
337 * cmd_parameter. Writes to response.
338 */
flash(char * cmd_parameter,char * response)339 static void __maybe_unused flash(char *cmd_parameter, char *response)
340 {
341 if (IS_ENABLED(CONFIG_FASTBOOT_FLASH_MMC))
342 fastboot_mmc_flash_write(cmd_parameter, fastboot_buf_addr,
343 image_size, response);
344
345 if (IS_ENABLED(CONFIG_FASTBOOT_FLASH_NAND))
346 fastboot_nand_flash_write(cmd_parameter, fastboot_buf_addr,
347 image_size, response);
348
349 if (IS_ENABLED(CONFIG_FASTBOOT_FLASH_SPI))
350 fastboot_spi_flash_write(cmd_parameter, fastboot_buf_addr,
351 image_size, response);
352 }
353
354 /**
355 * erase() - erase the indicated partition.
356 *
357 * @cmd_parameter: Pointer to partition name
358 * @response: Pointer to fastboot response buffer
359 *
360 * Erases the partition indicated by cmd_parameter (clear to 0x00s). Writes
361 * to response.
362 */
erase(char * cmd_parameter,char * response)363 static void __maybe_unused erase(char *cmd_parameter, char *response)
364 {
365 if (IS_ENABLED(CONFIG_FASTBOOT_FLASH_MMC))
366 fastboot_mmc_erase(cmd_parameter, response);
367
368 if (IS_ENABLED(CONFIG_FASTBOOT_FLASH_NAND))
369 fastboot_nand_erase(cmd_parameter, response);
370
371 if (IS_ENABLED(CONFIG_FASTBOOT_FLASH_SPI))
372 fastboot_spi_flash_erase(cmd_parameter, response);
373 }
374
375 /**
376 * run_ucmd() - Execute the UCmd command
377 *
378 * @cmd_parameter: Pointer to command parameter
379 * @response: Pointer to fastboot response buffer
380 */
run_ucmd(char * cmd_parameter,char * response)381 static void __maybe_unused run_ucmd(char *cmd_parameter, char *response)
382 {
383 if (!cmd_parameter) {
384 pr_err("missing slot suffix\n");
385 fastboot_fail("missing command", response);
386 return;
387 }
388
389 if (run_command(cmd_parameter, 0))
390 fastboot_fail("", response);
391 else
392 fastboot_okay(NULL, response);
393 }
394
395 static char g_a_cmd_buff[64];
396
fastboot_acmd_complete(void)397 void fastboot_acmd_complete(void)
398 {
399 run_command(g_a_cmd_buff, 0);
400 }
401
402 /**
403 * run_acmd() - Execute the ACmd command
404 *
405 * @cmd_parameter: Pointer to command parameter
406 * @response: Pointer to fastboot response buffer
407 */
run_acmd(char * cmd_parameter,char * response)408 static void __maybe_unused run_acmd(char *cmd_parameter, char *response)
409 {
410 if (!cmd_parameter) {
411 pr_err("missing slot suffix\n");
412 fastboot_fail("missing command", response);
413 return;
414 }
415
416 if (strlen(cmd_parameter) >= sizeof(g_a_cmd_buff)) {
417 pr_err("too long command\n");
418 fastboot_fail("too long command", response);
419 return;
420 }
421
422 strcpy(g_a_cmd_buff, cmd_parameter);
423 fastboot_okay(NULL, response);
424 }
425
426 /**
427 * reboot_bootloader() - Sets reboot bootloader flag.
428 *
429 * @cmd_parameter: Pointer to command parameter
430 * @response: Pointer to fastboot response buffer
431 */
reboot_bootloader(char * cmd_parameter,char * response)432 static void reboot_bootloader(char *cmd_parameter, char *response)
433 {
434 if (fastboot_set_reboot_flag(FASTBOOT_REBOOT_REASON_BOOTLOADER))
435 fastboot_fail("Cannot set reboot flag", response);
436 else
437 fastboot_okay(NULL, response);
438 }
439
440 /**
441 * reboot_fastbootd() - Sets reboot fastboot flag.
442 *
443 * @cmd_parameter: Pointer to command parameter
444 * @response: Pointer to fastboot response buffer
445 */
reboot_fastbootd(char * cmd_parameter,char * response)446 static void reboot_fastbootd(char *cmd_parameter, char *response)
447 {
448 if (fastboot_set_reboot_flag(FASTBOOT_REBOOT_REASON_FASTBOOTD))
449 fastboot_fail("Cannot set fastboot flag", response);
450 else
451 fastboot_okay(NULL, response);
452 }
453
454 /**
455 * reboot_recovery() - Sets reboot recovery flag.
456 *
457 * @cmd_parameter: Pointer to command parameter
458 * @response: Pointer to fastboot response buffer
459 */
reboot_recovery(char * cmd_parameter,char * response)460 static void reboot_recovery(char *cmd_parameter, char *response)
461 {
462 if (fastboot_set_reboot_flag(FASTBOOT_REBOOT_REASON_RECOVERY))
463 fastboot_fail("Cannot set recovery flag", response);
464 else
465 fastboot_okay(NULL, response);
466 }
467
468 /**
469 * oem_format() - Execute the OEM format command
470 *
471 * @cmd_parameter: Pointer to command parameter
472 * @response: Pointer to fastboot response buffer
473 */
oem_format(char * cmd_parameter,char * response)474 static void __maybe_unused oem_format(char *cmd_parameter, char *response)
475 {
476 char cmdbuf[32];
477 const int mmc_dev = config_opt_enabled(CONFIG_FASTBOOT_FLASH_MMC,
478 CONFIG_FASTBOOT_FLASH_MMC_DEV, -1);
479
480 if (!env_get("partitions")) {
481 fastboot_fail("partitions not set", response);
482 } else {
483 sprintf(cmdbuf, "gpt write mmc %x $partitions", mmc_dev);
484 if (run_command(cmdbuf, 0))
485 fastboot_fail("", response);
486 else
487 fastboot_okay(NULL, response);
488 }
489 }
490
491 /**
492 * oem_partconf() - Execute the OEM partconf command
493 *
494 * @cmd_parameter: Pointer to command parameter
495 * @response: Pointer to fastboot response buffer
496 */
oem_partconf(char * cmd_parameter,char * response)497 static void __maybe_unused oem_partconf(char *cmd_parameter, char *response)
498 {
499 char cmdbuf[32];
500 const int mmc_dev = config_opt_enabled(CONFIG_FASTBOOT_FLASH_MMC,
501 CONFIG_FASTBOOT_FLASH_MMC_DEV, -1);
502
503 if (!cmd_parameter) {
504 fastboot_fail("Expected command parameter", response);
505 return;
506 }
507
508 /* execute 'mmc partconfg' command with cmd_parameter arguments*/
509 snprintf(cmdbuf, sizeof(cmdbuf), "mmc partconf %x %s 0", mmc_dev, cmd_parameter);
510 printf("Execute: %s\n", cmdbuf);
511 if (run_command(cmdbuf, 0))
512 fastboot_fail("Cannot set oem partconf", response);
513 else
514 fastboot_okay(NULL, response);
515 }
516
517 /**
518 * oem_bootbus() - Execute the OEM bootbus command
519 *
520 * @cmd_parameter: Pointer to command parameter
521 * @response: Pointer to fastboot response buffer
522 */
oem_bootbus(char * cmd_parameter,char * response)523 static void __maybe_unused oem_bootbus(char *cmd_parameter, char *response)
524 {
525 char cmdbuf[32];
526 const int mmc_dev = config_opt_enabled(CONFIG_FASTBOOT_FLASH_MMC,
527 CONFIG_FASTBOOT_FLASH_MMC_DEV, -1);
528
529 if (!cmd_parameter) {
530 fastboot_fail("Expected command parameter", response);
531 return;
532 }
533
534 /* execute 'mmc bootbus' command with cmd_parameter arguments*/
535 snprintf(cmdbuf, sizeof(cmdbuf), "mmc bootbus %x %s", mmc_dev, cmd_parameter);
536 printf("Execute: %s\n", cmdbuf);
537 if (run_command(cmdbuf, 0))
538 fastboot_fail("Cannot set oem bootbus", response);
539 else
540 fastboot_okay(NULL, response);
541 }
542
543 /**
544 * oem_console() - Execute the OEM console command
545 *
546 * @cmd_parameter: Pointer to command parameter
547 * @response: Pointer to fastboot response buffer
548 */
oem_console(char * cmd_parameter,char * response)549 static void __maybe_unused oem_console(char *cmd_parameter, char *response)
550 {
551 if (cmd_parameter)
552 console_in_puts(cmd_parameter);
553
554 if (console_record_isempty())
555 fastboot_fail("Empty console", response);
556 else
557 fastboot_response(FASTBOOT_MULTIRESPONSE_START, response, NULL);
558 }
559
560 /**
561 * fastboot_oem_board() - Execute the OEM board command. This is default
562 * weak implementation, which may be overwritten in board/ files.
563 *
564 * @cmd_parameter: Pointer to command parameter
565 * @data: Pointer to fastboot input buffer
566 * @size: Size of the fastboot input buffer
567 * @response: Pointer to fastboot response buffer
568 */
fastboot_oem_board(char * cmd_parameter,void * data,u32 size,char * response)569 void __weak fastboot_oem_board(char *cmd_parameter, void *data, u32 size, char *response)
570 {
571 fastboot_fail("oem board function not defined", response);
572 }
573
574 /**
575 * oem_board() - Execute the OEM board command
576 *
577 * @cmd_parameter: Pointer to command parameter
578 * @response: Pointer to fastboot response buffer
579 */
oem_board(char * cmd_parameter,char * response)580 static void __maybe_unused oem_board(char *cmd_parameter, char *response)
581 {
582 fastboot_oem_board(cmd_parameter, (void *)fastboot_buf_addr, image_size, response);
583 }
584