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