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