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