blob: 55ac1e96979fa8a4fdd27d14e6fa2e45c987f681 [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 Glassae4eb812023-12-14 21:19:04 -070013#include <mapmem.h>
Alex Kiernand5aa57c2018-05-29 15:30:53 +000014#include <part.h>
15#include <stdlib.h>
Simon Glassbdd5f812023-09-14 18:21:46 -060016#include <linux/printk.h>
Alex Kiernand5aa57c2018-05-29 15:30:53 +000017
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 *);
Alex Kiernand5aa57c2018-05-29 15:30:53 +000036static void flash(char *, char *);
37static void erase(char *, char *);
Alex Kiernand5aa57c2018-05-29 15:30:53 +000038static void reboot_bootloader(char *, char *);
Roman Kovalivskyib30b97b2020-07-28 23:35:33 +030039static void reboot_fastbootd(char *, char *);
40static void reboot_recovery(char *, char *);
Alex Kiernanc86cde92018-05-29 15:30:54 +000041static void oem_format(char *, char *);
Patrick Delaunay61687702021-01-27 14:46:48 +010042static void oem_partconf(char *, char *);
Patrick Delaunay67af29a2021-01-27 14:46:49 +010043static void oem_bootbus(char *, char *);
Heiko Schocher3a994482021-02-10 09:29:03 +010044static void run_ucmd(char *, char *);
45static void run_acmd(char *, char *);
Heiko Schocher3a994482021-02-10 09:29:03 +010046
Alex Kiernand5aa57c2018-05-29 15:30:53 +000047static 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 },
Alex Kiernand5aa57c2018-05-29 15:30:53 +000059 [FASTBOOT_COMMAND_FLASH] = {
60 .command = "flash",
Patrick Delaunayf82f9e42022-12-15 10:15:50 +010061 .dispatch = CONFIG_IS_ENABLED(FASTBOOT_FLASH, (flash), (NULL))
Alex Kiernand5aa57c2018-05-29 15:30:53 +000062 },
63 [FASTBOOT_COMMAND_ERASE] = {
64 .command = "erase",
Patrick Delaunayf82f9e42022-12-15 10:15:50 +010065 .dispatch = CONFIG_IS_ENABLED(FASTBOOT_FLASH, (erase), (NULL))
Alex Kiernand5aa57c2018-05-29 15:30:53 +000066 },
Alex Kiernand5aa57c2018-05-29 15:30:53 +000067 [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 },
Roman Kovalivskyib30b97b2020-07-28 23:35:33 +030083 [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 },
Alex Kiernand5aa57c2018-05-29 15:30:53 +000091 [FASTBOOT_COMMAND_SET_ACTIVE] = {
92 .command = "set_active",
93 .dispatch = okay
94 },
Alex Kiernanc86cde92018-05-29 15:30:54 +000095 [FASTBOOT_COMMAND_OEM_FORMAT] = {
96 .command = "oem format",
Patrick Delaunayf82f9e42022-12-15 10:15:50 +010097 .dispatch = CONFIG_IS_ENABLED(FASTBOOT_CMD_OEM_FORMAT, (oem_format), (NULL))
Alex Kiernanc86cde92018-05-29 15:30:54 +000098 },
Patrick Delaunay61687702021-01-27 14:46:48 +010099 [FASTBOOT_COMMAND_OEM_PARTCONF] = {
100 .command = "oem partconf",
Patrick Delaunayf82f9e42022-12-15 10:15:50 +0100101 .dispatch = CONFIG_IS_ENABLED(FASTBOOT_CMD_OEM_PARTCONF, (oem_partconf), (NULL))
Patrick Delaunay61687702021-01-27 14:46:48 +0100102 },
Patrick Delaunay67af29a2021-01-27 14:46:49 +0100103 [FASTBOOT_COMMAND_OEM_BOOTBUS] = {
104 .command = "oem bootbus",
Patrick Delaunayf82f9e42022-12-15 10:15:50 +0100105 .dispatch = CONFIG_IS_ENABLED(FASTBOOT_CMD_OEM_BOOTBUS, (oem_bootbus), (NULL))
Patrick Delaunay67af29a2021-01-27 14:46:49 +0100106 },
Sean Anderson421bec02022-12-16 13:20:16 -0500107 [FASTBOOT_COMMAND_OEM_RUN] = {
108 .command = "oem run",
109 .dispatch = CONFIG_IS_ENABLED(FASTBOOT_OEM_RUN, (run_ucmd), (NULL))
110 },
Heiko Schocher3a994482021-02-10 09:29:03 +0100111 [FASTBOOT_COMMAND_UCMD] = {
112 .command = "UCmd",
Patrick Delaunayf82f9e42022-12-15 10:15:50 +0100113 .dispatch = CONFIG_IS_ENABLED(FASTBOOT_UUU_SUPPORT, (run_ucmd), (NULL))
Heiko Schocher3a994482021-02-10 09:29:03 +0100114 },
115 [FASTBOOT_COMMAND_ACMD] = {
116 .command = "ACmd",
Patrick Delaunayf82f9e42022-12-15 10:15:50 +0100117 .dispatch = CONFIG_IS_ENABLED(FASTBOOT_UUU_SUPPORT, (run_acmd), (NULL))
Heiko Schocher3a994482021-02-10 09:29:03 +0100118 },
Alex Kiernand5aa57c2018-05-29 15:30:53 +0000119};
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 {
Patrick Delaunayf82f9e42022-12-15 10:15:50 +0100144 pr_err("command %s not supported.\n", cmd_string);
145 fastboot_fail("Unsupported command", response);
146 return -1;
Alex Kiernand5aa57c2018-05-29 15:30:53 +0000147 }
148 }
149 }
150
151 pr_err("command %s not recognized.\n", cmd_string);
152 fastboot_fail("unrecognized command", response);
153 return -1;
154}
155
156/**
157 * okay() - Send bare OKAY response
158 *
159 * @cmd_parameter: Pointer to command parameter
160 * @response: Pointer to fastboot response buffer
161 *
162 * Send a bare OKAY fastboot response. This is used where the command is
163 * valid, but all the work is done after the response has been sent (e.g.
164 * boot, reboot etc.)
165 */
166static void okay(char *cmd_parameter, char *response)
167{
168 fastboot_okay(NULL, response);
169}
170
171/**
172 * getvar() - Read a config/version variable
173 *
174 * @cmd_parameter: Pointer to command parameter
175 * @response: Pointer to fastboot response buffer
176 */
177static void getvar(char *cmd_parameter, char *response)
178{
179 fastboot_getvar(cmd_parameter, response);
180}
181
182/**
183 * fastboot_download() - Start a download transfer from the client
184 *
185 * @cmd_parameter: Pointer to command parameter
186 * @response: Pointer to fastboot response buffer
187 */
188static void download(char *cmd_parameter, char *response)
189{
190 char *tmp;
191
192 if (!cmd_parameter) {
193 fastboot_fail("Expected command parameter", response);
194 return;
195 }
196 fastboot_bytes_received = 0;
Simon Glass3ff49ec2021-07-24 09:03:29 -0600197 fastboot_bytes_expected = hextoul(cmd_parameter, &tmp);
Alex Kiernand5aa57c2018-05-29 15:30:53 +0000198 if (fastboot_bytes_expected == 0) {
199 fastboot_fail("Expected nonzero image size", response);
200 return;
201 }
202 /*
203 * Nothing to download yet. Response is of the form:
204 * [DATA|FAIL]$cmd_parameter
205 *
206 * where cmd_parameter is an 8 digit hexadecimal number
207 */
208 if (fastboot_bytes_expected > fastboot_buf_size) {
209 fastboot_fail(cmd_parameter, response);
210 } else {
211 printf("Starting download of %d bytes\n",
212 fastboot_bytes_expected);
213 fastboot_response("DATA", response, "%s", cmd_parameter);
214 }
215}
216
217/**
218 * fastboot_data_remaining() - return bytes remaining in current transfer
219 *
220 * Return: Number of bytes left in the current download
221 */
222u32 fastboot_data_remaining(void)
223{
224 return fastboot_bytes_expected - fastboot_bytes_received;
225}
226
227/**
228 * fastboot_data_download() - Copy image data to fastboot_buf_addr.
229 *
230 * @fastboot_data: Pointer to received fastboot data
231 * @fastboot_data_len: Length of received fastboot data
232 * @response: Pointer to fastboot response buffer
233 *
234 * Copies image data from fastboot_data to fastboot_buf_addr. Writes to
235 * response. fastboot_bytes_received is updated to indicate the number
236 * of bytes that have been transferred.
237 *
238 * On completion sets image_size and ${filesize} to the total size of the
239 * downloaded image.
240 */
241void fastboot_data_download(const void *fastboot_data,
242 unsigned int fastboot_data_len,
243 char *response)
244{
245#define BYTES_PER_DOT 0x20000
246 u32 pre_dot_num, now_dot_num;
Simon Glassae4eb812023-12-14 21:19:04 -0700247 void *buf;
Alex Kiernand5aa57c2018-05-29 15:30:53 +0000248
249 if (fastboot_data_len == 0 ||
250 (fastboot_bytes_received + fastboot_data_len) >
251 fastboot_bytes_expected) {
252 fastboot_fail("Received invalid data length",
253 response);
254 return;
255 }
256 /* Download data to fastboot_buf_addr */
Simon Glassae4eb812023-12-14 21:19:04 -0700257 buf = map_sysmem(fastboot_buf_addr, 0);
258 memcpy(buf + fastboot_bytes_received,
Alex Kiernand5aa57c2018-05-29 15:30:53 +0000259 fastboot_data, fastboot_data_len);
Simon Glassae4eb812023-12-14 21:19:04 -0700260 unmap_sysmem(buf);
Alex Kiernand5aa57c2018-05-29 15:30:53 +0000261
262 pre_dot_num = fastboot_bytes_received / BYTES_PER_DOT;
263 fastboot_bytes_received += fastboot_data_len;
264 now_dot_num = fastboot_bytes_received / BYTES_PER_DOT;
265
266 if (pre_dot_num != now_dot_num) {
267 putc('.');
268 if (!(now_dot_num % 74))
269 putc('\n');
270 }
271 *response = '\0';
272}
273
274/**
275 * fastboot_data_complete() - Mark current transfer complete
276 *
277 * @response: Pointer to fastboot response buffer
278 *
279 * Set image_size and ${filesize} to the total size of the downloaded image.
280 */
281void fastboot_data_complete(char *response)
282{
283 /* Download complete. Respond with "OKAY" */
284 fastboot_okay(NULL, response);
285 printf("\ndownloading of %d bytes finished\n", fastboot_bytes_received);
286 image_size = fastboot_bytes_received;
287 env_set_hex("filesize", image_size);
288 fastboot_bytes_expected = 0;
289 fastboot_bytes_received = 0;
290}
291
Alex Kiernand5aa57c2018-05-29 15:30:53 +0000292/**
293 * flash() - write the downloaded image to the indicated partition.
294 *
295 * @cmd_parameter: Pointer to partition name
296 * @response: Pointer to fastboot response buffer
297 *
298 * Writes the previously downloaded image to the partition indicated by
299 * cmd_parameter. Writes to response.
300 */
Patrick Delaunayf82f9e42022-12-15 10:15:50 +0100301static void __maybe_unused flash(char *cmd_parameter, char *response)
Alex Kiernand5aa57c2018-05-29 15:30:53 +0000302{
Simon Glassae4eb812023-12-14 21:19:04 -0700303 void *buf = map_sysmem(fastboot_buf_addr, 0);
304
Simon Glass091a0712023-02-05 17:54:12 -0700305 if (IS_ENABLED(CONFIG_FASTBOOT_FLASH_MMC))
Simon Glassae4eb812023-12-14 21:19:04 -0700306 fastboot_mmc_flash_write(cmd_parameter, buf, image_size,
307 response);
Patrick Delaunayf82f9e42022-12-15 10:15:50 +0100308
Simon Glass067995932023-02-05 17:54:13 -0700309 if (IS_ENABLED(CONFIG_FASTBOOT_FLASH_NAND))
Simon Glassae4eb812023-12-14 21:19:04 -0700310 fastboot_nand_flash_write(cmd_parameter, buf, image_size,
311 response);
312 unmap_sysmem(buf);
Alex Kiernand5aa57c2018-05-29 15:30:53 +0000313}
314
315/**
316 * erase() - erase the indicated partition.
317 *
318 * @cmd_parameter: Pointer to partition name
319 * @response: Pointer to fastboot response buffer
320 *
321 * Erases the partition indicated by cmd_parameter (clear to 0x00s). Writes
322 * to response.
323 */
Patrick Delaunayf82f9e42022-12-15 10:15:50 +0100324static void __maybe_unused erase(char *cmd_parameter, char *response)
Alex Kiernand5aa57c2018-05-29 15:30:53 +0000325{
Simon Glass091a0712023-02-05 17:54:12 -0700326 if (IS_ENABLED(CONFIG_FASTBOOT_FLASH_MMC))
Patrick Delaunayf82f9e42022-12-15 10:15:50 +0100327 fastboot_mmc_erase(cmd_parameter, response);
328
Simon Glass067995932023-02-05 17:54:13 -0700329 if (IS_ENABLED(CONFIG_FASTBOOT_FLASH_NAND))
Patrick Delaunayf82f9e42022-12-15 10:15:50 +0100330 fastboot_nand_erase(cmd_parameter, response);
Alex Kiernand5aa57c2018-05-29 15:30:53 +0000331}
Alex Kiernand5aa57c2018-05-29 15:30:53 +0000332
Heiko Schocher3a994482021-02-10 09:29:03 +0100333/**
334 * run_ucmd() - Execute the UCmd command
335 *
336 * @cmd_parameter: Pointer to command parameter
337 * @response: Pointer to fastboot response buffer
338 */
Patrick Delaunayf82f9e42022-12-15 10:15:50 +0100339static void __maybe_unused run_ucmd(char *cmd_parameter, char *response)
Heiko Schocher3a994482021-02-10 09:29:03 +0100340{
341 if (!cmd_parameter) {
342 pr_err("missing slot suffix\n");
343 fastboot_fail("missing command", response);
344 return;
345 }
346
347 if (run_command(cmd_parameter, 0))
348 fastboot_fail("", response);
349 else
350 fastboot_okay(NULL, response);
351}
352
353static char g_a_cmd_buff[64];
354
355void fastboot_acmd_complete(void)
356{
357 run_command(g_a_cmd_buff, 0);
358}
359
360/**
361 * run_acmd() - Execute the ACmd command
362 *
363 * @cmd_parameter: Pointer to command parameter
364 * @response: Pointer to fastboot response buffer
365 */
Patrick Delaunayf82f9e42022-12-15 10:15:50 +0100366static void __maybe_unused run_acmd(char *cmd_parameter, char *response)
Heiko Schocher3a994482021-02-10 09:29:03 +0100367{
368 if (!cmd_parameter) {
369 pr_err("missing slot suffix\n");
370 fastboot_fail("missing command", response);
371 return;
372 }
373
374 if (strlen(cmd_parameter) > sizeof(g_a_cmd_buff)) {
375 pr_err("too long command\n");
376 fastboot_fail("too long command", response);
377 return;
378 }
379
380 strcpy(g_a_cmd_buff, cmd_parameter);
381 fastboot_okay(NULL, response);
382}
Heiko Schocher3a994482021-02-10 09:29:03 +0100383
Alex Kiernand5aa57c2018-05-29 15:30:53 +0000384/**
385 * reboot_bootloader() - Sets reboot bootloader flag.
386 *
387 * @cmd_parameter: Pointer to command parameter
388 * @response: Pointer to fastboot response buffer
389 */
390static void reboot_bootloader(char *cmd_parameter, char *response)
391{
Roman Kovalivskyi1bb13422020-07-28 23:35:32 +0300392 if (fastboot_set_reboot_flag(FASTBOOT_REBOOT_REASON_BOOTLOADER))
Alex Kiernand5aa57c2018-05-29 15:30:53 +0000393 fastboot_fail("Cannot set reboot flag", response);
394 else
395 fastboot_okay(NULL, response);
396}
Alex Kiernanc86cde92018-05-29 15:30:54 +0000397
Roman Kovalivskyib30b97b2020-07-28 23:35:33 +0300398/**
399 * reboot_fastbootd() - Sets reboot fastboot flag.
400 *
401 * @cmd_parameter: Pointer to command parameter
402 * @response: Pointer to fastboot response buffer
403 */
404static void reboot_fastbootd(char *cmd_parameter, char *response)
405{
406 if (fastboot_set_reboot_flag(FASTBOOT_REBOOT_REASON_FASTBOOTD))
407 fastboot_fail("Cannot set fastboot flag", response);
408 else
409 fastboot_okay(NULL, response);
410}
411
412/**
413 * reboot_recovery() - Sets reboot recovery flag.
414 *
415 * @cmd_parameter: Pointer to command parameter
416 * @response: Pointer to fastboot response buffer
417 */
418static void reboot_recovery(char *cmd_parameter, char *response)
419{
420 if (fastboot_set_reboot_flag(FASTBOOT_REBOOT_REASON_RECOVERY))
421 fastboot_fail("Cannot set recovery flag", response);
422 else
423 fastboot_okay(NULL, response);
424}
425
Alex Kiernanc86cde92018-05-29 15:30:54 +0000426/**
427 * oem_format() - Execute the OEM format command
428 *
429 * @cmd_parameter: Pointer to command parameter
430 * @response: Pointer to fastboot response buffer
431 */
Patrick Delaunayf82f9e42022-12-15 10:15:50 +0100432static void __maybe_unused oem_format(char *cmd_parameter, char *response)
Alex Kiernanc86cde92018-05-29 15:30:54 +0000433{
434 char cmdbuf[32];
Patrick Delaunayf82f9e42022-12-15 10:15:50 +0100435 const int mmc_dev = config_opt_enabled(CONFIG_FASTBOOT_FLASH_MMC,
436 CONFIG_FASTBOOT_FLASH_MMC_DEV, -1);
Alex Kiernanc86cde92018-05-29 15:30:54 +0000437
438 if (!env_get("partitions")) {
439 fastboot_fail("partitions not set", response);
440 } else {
Patrick Delaunayf82f9e42022-12-15 10:15:50 +0100441 sprintf(cmdbuf, "gpt write mmc %x $partitions", mmc_dev);
Alex Kiernanc86cde92018-05-29 15:30:54 +0000442 if (run_command(cmdbuf, 0))
443 fastboot_fail("", response);
444 else
445 fastboot_okay(NULL, response);
446 }
447}
Patrick Delaunay61687702021-01-27 14:46:48 +0100448
Patrick Delaunay61687702021-01-27 14:46:48 +0100449/**
450 * oem_partconf() - Execute the OEM partconf command
451 *
452 * @cmd_parameter: Pointer to command parameter
453 * @response: Pointer to fastboot response buffer
454 */
Patrick Delaunayf82f9e42022-12-15 10:15:50 +0100455static void __maybe_unused oem_partconf(char *cmd_parameter, char *response)
Patrick Delaunay61687702021-01-27 14:46:48 +0100456{
457 char cmdbuf[32];
Patrick Delaunayf82f9e42022-12-15 10:15:50 +0100458 const int mmc_dev = config_opt_enabled(CONFIG_FASTBOOT_FLASH_MMC,
459 CONFIG_FASTBOOT_FLASH_MMC_DEV, -1);
Patrick Delaunay61687702021-01-27 14:46:48 +0100460
461 if (!cmd_parameter) {
462 fastboot_fail("Expected command parameter", response);
463 return;
464 }
465
466 /* execute 'mmc partconfg' command with cmd_parameter arguments*/
Patrick Delaunayf82f9e42022-12-15 10:15:50 +0100467 snprintf(cmdbuf, sizeof(cmdbuf), "mmc partconf %x %s 0", mmc_dev, cmd_parameter);
Patrick Delaunay61687702021-01-27 14:46:48 +0100468 printf("Execute: %s\n", cmdbuf);
469 if (run_command(cmdbuf, 0))
470 fastboot_fail("Cannot set oem partconf", response);
471 else
472 fastboot_okay(NULL, response);
473}
Patrick Delaunay67af29a2021-01-27 14:46:49 +0100474
Patrick Delaunay67af29a2021-01-27 14:46:49 +0100475/**
476 * oem_bootbus() - Execute the OEM bootbus command
477 *
478 * @cmd_parameter: Pointer to command parameter
479 * @response: Pointer to fastboot response buffer
480 */
Patrick Delaunayf82f9e42022-12-15 10:15:50 +0100481static void __maybe_unused oem_bootbus(char *cmd_parameter, char *response)
Patrick Delaunay67af29a2021-01-27 14:46:49 +0100482{
483 char cmdbuf[32];
Patrick Delaunayf82f9e42022-12-15 10:15:50 +0100484 const int mmc_dev = config_opt_enabled(CONFIG_FASTBOOT_FLASH_MMC,
485 CONFIG_FASTBOOT_FLASH_MMC_DEV, -1);
Patrick Delaunay67af29a2021-01-27 14:46:49 +0100486
487 if (!cmd_parameter) {
488 fastboot_fail("Expected command parameter", response);
489 return;
490 }
491
492 /* execute 'mmc bootbus' command with cmd_parameter arguments*/
Patrick Delaunayf82f9e42022-12-15 10:15:50 +0100493 snprintf(cmdbuf, sizeof(cmdbuf), "mmc bootbus %x %s", mmc_dev, cmd_parameter);
Patrick Delaunay67af29a2021-01-27 14:46:49 +0100494 printf("Execute: %s\n", cmdbuf);
495 if (run_command(cmdbuf, 0))
496 fastboot_fail("Cannot set oem bootbus", response);
497 else
498 fastboot_okay(NULL, response);
499}