1 // SPDX-License-Identifier: BSD-2-Clause
3 * Copyright (C) 2016 The Android Open Source Project
10 #include <fastboot-internal.h>
17 * image_size - final fastboot image size
19 static u32 image_size;
22 * fastboot_bytes_received - number of bytes received in the current download
24 static u32 fastboot_bytes_received;
27 * fastboot_bytes_expected - number of bytes expected in the current download
29 static u32 fastboot_bytes_expected;
31 static void okay(char *, char *);
32 static void getvar(char *, char *);
33 static void download(char *, char *);
34 #if CONFIG_IS_ENABLED(FASTBOOT_FLASH)
35 static void flash(char *, char *);
36 static void erase(char *, char *);
38 static void reboot_bootloader(char *, char *);
39 static void reboot_fastbootd(char *, char *);
40 static void reboot_recovery(char *, char *);
41 #if CONFIG_IS_ENABLED(FASTBOOT_CMD_OEM_FORMAT)
42 static void oem_format(char *, char *);
44 #if CONFIG_IS_ENABLED(FASTBOOT_CMD_OEM_PARTCONF)
45 static void oem_partconf(char *, char *);
47 #if CONFIG_IS_ENABLED(FASTBOOT_CMD_OEM_BOOTBUS)
48 static void oem_bootbus(char *, char *);
51 #if CONFIG_IS_ENABLED(FASTBOOT_UUU_SUPPORT)
52 static void run_ucmd(char *, char *);
53 static void run_acmd(char *, char *);
58 void (*dispatch)(char *cmd_parameter, char *response);
59 } commands[FASTBOOT_COMMAND_COUNT] = {
60 [FASTBOOT_COMMAND_GETVAR] = {
64 [FASTBOOT_COMMAND_DOWNLOAD] = {
65 .command = "download",
68 #if CONFIG_IS_ENABLED(FASTBOOT_FLASH)
69 [FASTBOOT_COMMAND_FLASH] = {
73 [FASTBOOT_COMMAND_ERASE] = {
78 [FASTBOOT_COMMAND_BOOT] = {
82 [FASTBOOT_COMMAND_CONTINUE] = {
83 .command = "continue",
86 [FASTBOOT_COMMAND_REBOOT] = {
90 [FASTBOOT_COMMAND_REBOOT_BOOTLOADER] = {
91 .command = "reboot-bootloader",
92 .dispatch = reboot_bootloader
94 [FASTBOOT_COMMAND_REBOOT_FASTBOOTD] = {
95 .command = "reboot-fastboot",
96 .dispatch = reboot_fastbootd
98 [FASTBOOT_COMMAND_REBOOT_RECOVERY] = {
99 .command = "reboot-recovery",
100 .dispatch = reboot_recovery
102 [FASTBOOT_COMMAND_SET_ACTIVE] = {
103 .command = "set_active",
106 #if CONFIG_IS_ENABLED(FASTBOOT_CMD_OEM_FORMAT)
107 [FASTBOOT_COMMAND_OEM_FORMAT] = {
108 .command = "oem format",
109 .dispatch = oem_format,
112 #if CONFIG_IS_ENABLED(FASTBOOT_CMD_OEM_PARTCONF)
113 [FASTBOOT_COMMAND_OEM_PARTCONF] = {
114 .command = "oem partconf",
115 .dispatch = oem_partconf,
118 #if CONFIG_IS_ENABLED(FASTBOOT_CMD_OEM_BOOTBUS)
119 [FASTBOOT_COMMAND_OEM_BOOTBUS] = {
120 .command = "oem bootbus",
121 .dispatch = oem_bootbus,
124 #if CONFIG_IS_ENABLED(FASTBOOT_UUU_SUPPORT)
125 [FASTBOOT_COMMAND_UCMD] = {
127 .dispatch = run_ucmd,
129 [FASTBOOT_COMMAND_ACMD] = {
131 .dispatch = run_acmd,
137 * fastboot_handle_command - Handle fastboot command
139 * @cmd_string: Pointer to command string
140 * @response: Pointer to fastboot response buffer
142 * Return: Executed command, or -1 if not recognized
144 int fastboot_handle_command(char *cmd_string, char *response)
149 cmd_parameter = cmd_string;
150 strsep(&cmd_parameter, ":");
152 for (i = 0; i < FASTBOOT_COMMAND_COUNT; i++) {
153 if (!strcmp(commands[i].command, cmd_string)) {
154 if (commands[i].dispatch) {
155 commands[i].dispatch(cmd_parameter,
164 pr_err("command %s not recognized.\n", cmd_string);
165 fastboot_fail("unrecognized command", response);
170 * okay() - Send bare OKAY response
172 * @cmd_parameter: Pointer to command parameter
173 * @response: Pointer to fastboot response buffer
175 * Send a bare OKAY fastboot response. This is used where the command is
176 * valid, but all the work is done after the response has been sent (e.g.
179 static void okay(char *cmd_parameter, char *response)
181 fastboot_okay(NULL, response);
185 * getvar() - Read a config/version variable
187 * @cmd_parameter: Pointer to command parameter
188 * @response: Pointer to fastboot response buffer
190 static void getvar(char *cmd_parameter, char *response)
192 fastboot_getvar(cmd_parameter, response);
196 * fastboot_download() - Start a download transfer from the client
198 * @cmd_parameter: Pointer to command parameter
199 * @response: Pointer to fastboot response buffer
201 static void download(char *cmd_parameter, char *response)
205 if (!cmd_parameter) {
206 fastboot_fail("Expected command parameter", response);
209 fastboot_bytes_received = 0;
210 fastboot_bytes_expected = hextoul(cmd_parameter, &tmp);
211 if (fastboot_bytes_expected == 0) {
212 fastboot_fail("Expected nonzero image size", response);
216 * Nothing to download yet. Response is of the form:
217 * [DATA|FAIL]$cmd_parameter
219 * where cmd_parameter is an 8 digit hexadecimal number
221 if (fastboot_bytes_expected > fastboot_buf_size) {
222 fastboot_fail(cmd_parameter, response);
224 printf("Starting download of %d bytes\n",
225 fastboot_bytes_expected);
226 fastboot_response("DATA", response, "%s", cmd_parameter);
231 * fastboot_data_remaining() - return bytes remaining in current transfer
233 * Return: Number of bytes left in the current download
235 u32 fastboot_data_remaining(void)
237 return fastboot_bytes_expected - fastboot_bytes_received;
241 * fastboot_data_download() - Copy image data to fastboot_buf_addr.
243 * @fastboot_data: Pointer to received fastboot data
244 * @fastboot_data_len: Length of received fastboot data
245 * @response: Pointer to fastboot response buffer
247 * Copies image data from fastboot_data to fastboot_buf_addr. Writes to
248 * response. fastboot_bytes_received is updated to indicate the number
249 * of bytes that have been transferred.
251 * On completion sets image_size and ${filesize} to the total size of the
254 void fastboot_data_download(const void *fastboot_data,
255 unsigned int fastboot_data_len,
258 #define BYTES_PER_DOT 0x20000
259 u32 pre_dot_num, now_dot_num;
261 if (fastboot_data_len == 0 ||
262 (fastboot_bytes_received + fastboot_data_len) >
263 fastboot_bytes_expected) {
264 fastboot_fail("Received invalid data length",
268 /* Download data to fastboot_buf_addr */
269 memcpy(fastboot_buf_addr + fastboot_bytes_received,
270 fastboot_data, fastboot_data_len);
272 pre_dot_num = fastboot_bytes_received / BYTES_PER_DOT;
273 fastboot_bytes_received += fastboot_data_len;
274 now_dot_num = fastboot_bytes_received / BYTES_PER_DOT;
276 if (pre_dot_num != now_dot_num) {
278 if (!(now_dot_num % 74))
285 * fastboot_data_complete() - Mark current transfer complete
287 * @response: Pointer to fastboot response buffer
289 * Set image_size and ${filesize} to the total size of the downloaded image.
291 void fastboot_data_complete(char *response)
293 /* Download complete. Respond with "OKAY" */
294 fastboot_okay(NULL, response);
295 printf("\ndownloading of %d bytes finished\n", fastboot_bytes_received);
296 image_size = fastboot_bytes_received;
297 env_set_hex("filesize", image_size);
298 fastboot_bytes_expected = 0;
299 fastboot_bytes_received = 0;
302 #if CONFIG_IS_ENABLED(FASTBOOT_FLASH)
304 * flash() - write the downloaded image to the indicated partition.
306 * @cmd_parameter: Pointer to partition name
307 * @response: Pointer to fastboot response buffer
309 * Writes the previously downloaded image to the partition indicated by
310 * cmd_parameter. Writes to response.
312 static void flash(char *cmd_parameter, char *response)
314 #if CONFIG_IS_ENABLED(FASTBOOT_FLASH_MMC)
315 fastboot_mmc_flash_write(cmd_parameter, fastboot_buf_addr, image_size,
318 #if CONFIG_IS_ENABLED(FASTBOOT_FLASH_NAND)
319 fastboot_nand_flash_write(cmd_parameter, fastboot_buf_addr, image_size,
325 * erase() - erase the indicated partition.
327 * @cmd_parameter: Pointer to partition name
328 * @response: Pointer to fastboot response buffer
330 * Erases the partition indicated by cmd_parameter (clear to 0x00s). Writes
333 static void erase(char *cmd_parameter, char *response)
335 #if CONFIG_IS_ENABLED(FASTBOOT_FLASH_MMC)
336 fastboot_mmc_erase(cmd_parameter, response);
338 #if CONFIG_IS_ENABLED(FASTBOOT_FLASH_NAND)
339 fastboot_nand_erase(cmd_parameter, response);
344 #if CONFIG_IS_ENABLED(FASTBOOT_UUU_SUPPORT)
346 * run_ucmd() - Execute the UCmd command
348 * @cmd_parameter: Pointer to command parameter
349 * @response: Pointer to fastboot response buffer
351 static void run_ucmd(char *cmd_parameter, char *response)
353 if (!cmd_parameter) {
354 pr_err("missing slot suffix\n");
355 fastboot_fail("missing command", response);
359 if (run_command(cmd_parameter, 0))
360 fastboot_fail("", response);
362 fastboot_okay(NULL, response);
365 static char g_a_cmd_buff[64];
367 void fastboot_acmd_complete(void)
369 run_command(g_a_cmd_buff, 0);
373 * run_acmd() - Execute the ACmd command
375 * @cmd_parameter: Pointer to command parameter
376 * @response: Pointer to fastboot response buffer
378 static void run_acmd(char *cmd_parameter, char *response)
380 if (!cmd_parameter) {
381 pr_err("missing slot suffix\n");
382 fastboot_fail("missing command", response);
386 if (strlen(cmd_parameter) > sizeof(g_a_cmd_buff)) {
387 pr_err("too long command\n");
388 fastboot_fail("too long command", response);
392 strcpy(g_a_cmd_buff, cmd_parameter);
393 fastboot_okay(NULL, response);
398 * reboot_bootloader() - Sets reboot bootloader flag.
400 * @cmd_parameter: Pointer to command parameter
401 * @response: Pointer to fastboot response buffer
403 static void reboot_bootloader(char *cmd_parameter, char *response)
405 if (fastboot_set_reboot_flag(FASTBOOT_REBOOT_REASON_BOOTLOADER))
406 fastboot_fail("Cannot set reboot flag", response);
408 fastboot_okay(NULL, response);
412 * reboot_fastbootd() - Sets reboot fastboot flag.
414 * @cmd_parameter: Pointer to command parameter
415 * @response: Pointer to fastboot response buffer
417 static void reboot_fastbootd(char *cmd_parameter, char *response)
419 if (fastboot_set_reboot_flag(FASTBOOT_REBOOT_REASON_FASTBOOTD))
420 fastboot_fail("Cannot set fastboot flag", response);
422 fastboot_okay(NULL, response);
426 * reboot_recovery() - Sets reboot recovery flag.
428 * @cmd_parameter: Pointer to command parameter
429 * @response: Pointer to fastboot response buffer
431 static void reboot_recovery(char *cmd_parameter, char *response)
433 if (fastboot_set_reboot_flag(FASTBOOT_REBOOT_REASON_RECOVERY))
434 fastboot_fail("Cannot set recovery flag", response);
436 fastboot_okay(NULL, response);
439 #if CONFIG_IS_ENABLED(FASTBOOT_CMD_OEM_FORMAT)
441 * oem_format() - Execute the OEM format command
443 * @cmd_parameter: Pointer to command parameter
444 * @response: Pointer to fastboot response buffer
446 static void oem_format(char *cmd_parameter, char *response)
450 if (!env_get("partitions")) {
451 fastboot_fail("partitions not set", response);
453 sprintf(cmdbuf, "gpt write mmc %x $partitions",
454 CONFIG_FASTBOOT_FLASH_MMC_DEV);
455 if (run_command(cmdbuf, 0))
456 fastboot_fail("", response);
458 fastboot_okay(NULL, response);
463 #if CONFIG_IS_ENABLED(FASTBOOT_CMD_OEM_PARTCONF)
465 * oem_partconf() - Execute the OEM partconf command
467 * @cmd_parameter: Pointer to command parameter
468 * @response: Pointer to fastboot response buffer
470 static void oem_partconf(char *cmd_parameter, char *response)
474 if (!cmd_parameter) {
475 fastboot_fail("Expected command parameter", response);
479 /* execute 'mmc partconfg' command with cmd_parameter arguments*/
480 snprintf(cmdbuf, sizeof(cmdbuf), "mmc partconf %x %s 0",
481 CONFIG_FASTBOOT_FLASH_MMC_DEV, cmd_parameter);
482 printf("Execute: %s\n", cmdbuf);
483 if (run_command(cmdbuf, 0))
484 fastboot_fail("Cannot set oem partconf", response);
486 fastboot_okay(NULL, response);
490 #if CONFIG_IS_ENABLED(FASTBOOT_CMD_OEM_BOOTBUS)
492 * oem_bootbus() - Execute the OEM bootbus command
494 * @cmd_parameter: Pointer to command parameter
495 * @response: Pointer to fastboot response buffer
497 static void oem_bootbus(char *cmd_parameter, char *response)
501 if (!cmd_parameter) {
502 fastboot_fail("Expected command parameter", response);
506 /* execute 'mmc bootbus' command with cmd_parameter arguments*/
507 snprintf(cmdbuf, sizeof(cmdbuf), "mmc bootbus %x %s",
508 CONFIG_FASTBOOT_FLASH_MMC_DEV, cmd_parameter);
509 printf("Execute: %s\n", cmdbuf);
510 if (run_command(cmdbuf, 0))
511 fastboot_fail("Cannot set oem bootbus", response);
513 fastboot_okay(NULL, response);