blob: 5fcadcdf503d98f2f2b622ea0b124b03497af556 [file] [log] [blame]
Alex Kiernanf73a7df2018-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 Glass288b29e2019-11-14 12:57:43 -07007#include <command.h>
Simon Glassc7694dd2019-08-01 09:46:46 -06008#include <env.h>
Alex Kiernanf73a7df2018-05-29 15:30:53 +00009#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>
Simon Glass1e94b462023-09-14 18:21:46 -060015#include <linux/printk.h>
Alex Kiernanf73a7df2018-05-29 15:30:53 +000016
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 *);
Alex Kiernanf73a7df2018-05-29 15:30:53 +000035static void flash(char *, char *);
36static void erase(char *, char *);
Alex Kiernanf73a7df2018-05-29 15:30:53 +000037static void reboot_bootloader(char *, char *);
Roman Kovalivskyi2b2a7712020-07-28 23:35:33 +030038static void reboot_fastbootd(char *, char *);
39static void reboot_recovery(char *, char *);
Alex Kiernan3845b902018-05-29 15:30:54 +000040static void oem_format(char *, char *);
Patrick Delaunayb2f6b972021-01-27 14:46:48 +010041static void oem_partconf(char *, char *);
Patrick Delaunay0c0394b2021-01-27 14:46:49 +010042static void oem_bootbus(char *, char *);
Heiko Schocherbc820d52021-02-10 09:29:03 +010043static void run_ucmd(char *, char *);
44static void run_acmd(char *, char *);
Heiko Schocherbc820d52021-02-10 09:29:03 +010045
Alex Kiernanf73a7df2018-05-29 15:30:53 +000046static const struct {
47 const char *command;
48 void (*dispatch)(char *cmd_parameter, char *response);
49} commands[FASTBOOT_COMMAND_COUNT] = {
50 [FASTBOOT_COMMAND_GETVAR] = {
51 .command = "getvar",
52 .dispatch = getvar
53 },
54 [FASTBOOT_COMMAND_DOWNLOAD] = {
55 .command = "download",
56 .dispatch = download
57 },
Alex Kiernanf73a7df2018-05-29 15:30:53 +000058 [FASTBOOT_COMMAND_FLASH] = {
59 .command = "flash",
Patrick Delaunayd0379902022-12-15 10:15:50 +010060 .dispatch = CONFIG_IS_ENABLED(FASTBOOT_FLASH, (flash), (NULL))
Alex Kiernanf73a7df2018-05-29 15:30:53 +000061 },
62 [FASTBOOT_COMMAND_ERASE] = {
63 .command = "erase",
Patrick Delaunayd0379902022-12-15 10:15:50 +010064 .dispatch = CONFIG_IS_ENABLED(FASTBOOT_FLASH, (erase), (NULL))
Alex Kiernanf73a7df2018-05-29 15:30:53 +000065 },
Alex Kiernanf73a7df2018-05-29 15:30:53 +000066 [FASTBOOT_COMMAND_BOOT] = {
67 .command = "boot",
68 .dispatch = okay
69 },
70 [FASTBOOT_COMMAND_CONTINUE] = {
71 .command = "continue",
72 .dispatch = okay
73 },
74 [FASTBOOT_COMMAND_REBOOT] = {
75 .command = "reboot",
76 .dispatch = okay
77 },
78 [FASTBOOT_COMMAND_REBOOT_BOOTLOADER] = {
79 .command = "reboot-bootloader",
80 .dispatch = reboot_bootloader
81 },
Roman Kovalivskyi2b2a7712020-07-28 23:35:33 +030082 [FASTBOOT_COMMAND_REBOOT_FASTBOOTD] = {
83 .command = "reboot-fastboot",
84 .dispatch = reboot_fastbootd
85 },
86 [FASTBOOT_COMMAND_REBOOT_RECOVERY] = {
87 .command = "reboot-recovery",
88 .dispatch = reboot_recovery
89 },
Alex Kiernanf73a7df2018-05-29 15:30:53 +000090 [FASTBOOT_COMMAND_SET_ACTIVE] = {
91 .command = "set_active",
92 .dispatch = okay
93 },
Alex Kiernan3845b902018-05-29 15:30:54 +000094 [FASTBOOT_COMMAND_OEM_FORMAT] = {
95 .command = "oem format",
Patrick Delaunayd0379902022-12-15 10:15:50 +010096 .dispatch = CONFIG_IS_ENABLED(FASTBOOT_CMD_OEM_FORMAT, (oem_format), (NULL))
Alex Kiernan3845b902018-05-29 15:30:54 +000097 },
Patrick Delaunayb2f6b972021-01-27 14:46:48 +010098 [FASTBOOT_COMMAND_OEM_PARTCONF] = {
99 .command = "oem partconf",
Patrick Delaunayd0379902022-12-15 10:15:50 +0100100 .dispatch = CONFIG_IS_ENABLED(FASTBOOT_CMD_OEM_PARTCONF, (oem_partconf), (NULL))
Patrick Delaunayb2f6b972021-01-27 14:46:48 +0100101 },
Patrick Delaunay0c0394b2021-01-27 14:46:49 +0100102 [FASTBOOT_COMMAND_OEM_BOOTBUS] = {
103 .command = "oem bootbus",
Patrick Delaunayd0379902022-12-15 10:15:50 +0100104 .dispatch = CONFIG_IS_ENABLED(FASTBOOT_CMD_OEM_BOOTBUS, (oem_bootbus), (NULL))
Patrick Delaunay0c0394b2021-01-27 14:46:49 +0100105 },
Sean Andersonf3d914c2022-12-16 13:20:16 -0500106 [FASTBOOT_COMMAND_OEM_RUN] = {
107 .command = "oem run",
108 .dispatch = CONFIG_IS_ENABLED(FASTBOOT_OEM_RUN, (run_ucmd), (NULL))
109 },
Heiko Schocherbc820d52021-02-10 09:29:03 +0100110 [FASTBOOT_COMMAND_UCMD] = {
111 .command = "UCmd",
Patrick Delaunayd0379902022-12-15 10:15:50 +0100112 .dispatch = CONFIG_IS_ENABLED(FASTBOOT_UUU_SUPPORT, (run_ucmd), (NULL))
Heiko Schocherbc820d52021-02-10 09:29:03 +0100113 },
114 [FASTBOOT_COMMAND_ACMD] = {
115 .command = "ACmd",
Patrick Delaunayd0379902022-12-15 10:15:50 +0100116 .dispatch = CONFIG_IS_ENABLED(FASTBOOT_UUU_SUPPORT, (run_acmd), (NULL))
Heiko Schocherbc820d52021-02-10 09:29:03 +0100117 },
Alex Kiernanf73a7df2018-05-29 15:30:53 +0000118};
119
120/**
121 * fastboot_handle_command - Handle fastboot command
122 *
123 * @cmd_string: Pointer to command string
124 * @response: Pointer to fastboot response buffer
125 *
126 * Return: Executed command, or -1 if not recognized
127 */
128int fastboot_handle_command(char *cmd_string, char *response)
129{
130 int i;
131 char *cmd_parameter;
132
133 cmd_parameter = cmd_string;
134 strsep(&cmd_parameter, ":");
135
136 for (i = 0; i < FASTBOOT_COMMAND_COUNT; i++) {
137 if (!strcmp(commands[i].command, cmd_string)) {
138 if (commands[i].dispatch) {
139 commands[i].dispatch(cmd_parameter,
140 response);
141 return i;
142 } else {
Patrick Delaunayd0379902022-12-15 10:15:50 +0100143 pr_err("command %s not supported.\n", cmd_string);
144 fastboot_fail("Unsupported command", response);
145 return -1;
Alex Kiernanf73a7df2018-05-29 15:30:53 +0000146 }
147 }
148 }
149
150 pr_err("command %s not recognized.\n", cmd_string);
151 fastboot_fail("unrecognized command", response);
152 return -1;
153}
154
155/**
156 * okay() - Send bare OKAY response
157 *
158 * @cmd_parameter: Pointer to command parameter
159 * @response: Pointer to fastboot response buffer
160 *
161 * Send a bare OKAY fastboot response. This is used where the command is
162 * valid, but all the work is done after the response has been sent (e.g.
163 * boot, reboot etc.)
164 */
165static void okay(char *cmd_parameter, char *response)
166{
167 fastboot_okay(NULL, response);
168}
169
170/**
171 * getvar() - Read a config/version variable
172 *
173 * @cmd_parameter: Pointer to command parameter
174 * @response: Pointer to fastboot response buffer
175 */
176static void getvar(char *cmd_parameter, char *response)
177{
178 fastboot_getvar(cmd_parameter, response);
179}
180
181/**
182 * fastboot_download() - Start a download transfer from the client
183 *
184 * @cmd_parameter: Pointer to command parameter
185 * @response: Pointer to fastboot response buffer
186 */
187static void download(char *cmd_parameter, char *response)
188{
189 char *tmp;
190
191 if (!cmd_parameter) {
192 fastboot_fail("Expected command parameter", response);
193 return;
194 }
195 fastboot_bytes_received = 0;
Simon Glass7e5f4602021-07-24 09:03:29 -0600196 fastboot_bytes_expected = hextoul(cmd_parameter, &tmp);
Alex Kiernanf73a7df2018-05-29 15:30:53 +0000197 if (fastboot_bytes_expected == 0) {
198 fastboot_fail("Expected nonzero image size", response);
199 return;
200 }
201 /*
202 * Nothing to download yet. Response is of the form:
203 * [DATA|FAIL]$cmd_parameter
204 *
205 * where cmd_parameter is an 8 digit hexadecimal number
206 */
207 if (fastboot_bytes_expected > fastboot_buf_size) {
208 fastboot_fail(cmd_parameter, response);
209 } else {
210 printf("Starting download of %d bytes\n",
211 fastboot_bytes_expected);
212 fastboot_response("DATA", response, "%s", cmd_parameter);
213 }
214}
215
216/**
217 * fastboot_data_remaining() - return bytes remaining in current transfer
218 *
219 * Return: Number of bytes left in the current download
220 */
221u32 fastboot_data_remaining(void)
222{
223 return fastboot_bytes_expected - fastboot_bytes_received;
224}
225
226/**
227 * fastboot_data_download() - Copy image data to fastboot_buf_addr.
228 *
229 * @fastboot_data: Pointer to received fastboot data
230 * @fastboot_data_len: Length of received fastboot data
231 * @response: Pointer to fastboot response buffer
232 *
233 * Copies image data from fastboot_data to fastboot_buf_addr. Writes to
234 * response. fastboot_bytes_received is updated to indicate the number
235 * of bytes that have been transferred.
236 *
237 * On completion sets image_size and ${filesize} to the total size of the
238 * downloaded image.
239 */
240void fastboot_data_download(const void *fastboot_data,
241 unsigned int fastboot_data_len,
242 char *response)
243{
244#define BYTES_PER_DOT 0x20000
245 u32 pre_dot_num, now_dot_num;
246
247 if (fastboot_data_len == 0 ||
248 (fastboot_bytes_received + fastboot_data_len) >
249 fastboot_bytes_expected) {
250 fastboot_fail("Received invalid data length",
251 response);
252 return;
253 }
254 /* Download data to fastboot_buf_addr */
255 memcpy(fastboot_buf_addr + fastboot_bytes_received,
256 fastboot_data, fastboot_data_len);
257
258 pre_dot_num = fastboot_bytes_received / BYTES_PER_DOT;
259 fastboot_bytes_received += fastboot_data_len;
260 now_dot_num = fastboot_bytes_received / BYTES_PER_DOT;
261
262 if (pre_dot_num != now_dot_num) {
263 putc('.');
264 if (!(now_dot_num % 74))
265 putc('\n');
266 }
267 *response = '\0';
268}
269
270/**
271 * fastboot_data_complete() - Mark current transfer complete
272 *
273 * @response: Pointer to fastboot response buffer
274 *
275 * Set image_size and ${filesize} to the total size of the downloaded image.
276 */
277void fastboot_data_complete(char *response)
278{
279 /* Download complete. Respond with "OKAY" */
280 fastboot_okay(NULL, response);
281 printf("\ndownloading of %d bytes finished\n", fastboot_bytes_received);
282 image_size = fastboot_bytes_received;
283 env_set_hex("filesize", image_size);
284 fastboot_bytes_expected = 0;
285 fastboot_bytes_received = 0;
286}
287
Alex Kiernanf73a7df2018-05-29 15:30:53 +0000288/**
289 * flash() - write the downloaded image to the indicated partition.
290 *
291 * @cmd_parameter: Pointer to partition name
292 * @response: Pointer to fastboot response buffer
293 *
294 * Writes the previously downloaded image to the partition indicated by
295 * cmd_parameter. Writes to response.
296 */
Patrick Delaunayd0379902022-12-15 10:15:50 +0100297static void __maybe_unused flash(char *cmd_parameter, char *response)
Alex Kiernanf73a7df2018-05-29 15:30:53 +0000298{
Simon Glass7cb10e52023-02-05 17:54:12 -0700299 if (IS_ENABLED(CONFIG_FASTBOOT_FLASH_MMC))
Patrick Delaunayd0379902022-12-15 10:15:50 +0100300 fastboot_mmc_flash_write(cmd_parameter, fastboot_buf_addr,
301 image_size, response);
302
Simon Glassc6228ed2023-02-05 17:54:13 -0700303 if (IS_ENABLED(CONFIG_FASTBOOT_FLASH_NAND))
Patrick Delaunayd0379902022-12-15 10:15:50 +0100304 fastboot_nand_flash_write(cmd_parameter, fastboot_buf_addr,
305 image_size, response);
Alex Kiernanf73a7df2018-05-29 15:30:53 +0000306}
307
308/**
309 * erase() - erase the indicated partition.
310 *
311 * @cmd_parameter: Pointer to partition name
312 * @response: Pointer to fastboot response buffer
313 *
314 * Erases the partition indicated by cmd_parameter (clear to 0x00s). Writes
315 * to response.
316 */
Patrick Delaunayd0379902022-12-15 10:15:50 +0100317static void __maybe_unused erase(char *cmd_parameter, char *response)
Alex Kiernanf73a7df2018-05-29 15:30:53 +0000318{
Simon Glass7cb10e52023-02-05 17:54:12 -0700319 if (IS_ENABLED(CONFIG_FASTBOOT_FLASH_MMC))
Patrick Delaunayd0379902022-12-15 10:15:50 +0100320 fastboot_mmc_erase(cmd_parameter, response);
Alex Kiernanf73a7df2018-05-29 15:30:53 +0000321
Simon Glassc6228ed2023-02-05 17:54:13 -0700322 if (IS_ENABLED(CONFIG_FASTBOOT_FLASH_NAND))
Patrick Delaunayd0379902022-12-15 10:15:50 +0100323 fastboot_nand_erase(cmd_parameter, response);
324}
325
Heiko Schocherbc820d52021-02-10 09:29:03 +0100326/**
327 * run_ucmd() - Execute the UCmd command
328 *
329 * @cmd_parameter: Pointer to command parameter
330 * @response: Pointer to fastboot response buffer
331 */
Patrick Delaunayd0379902022-12-15 10:15:50 +0100332static void __maybe_unused run_ucmd(char *cmd_parameter, char *response)
Heiko Schocherbc820d52021-02-10 09:29:03 +0100333{
334 if (!cmd_parameter) {
335 pr_err("missing slot suffix\n");
336 fastboot_fail("missing command", response);
337 return;
338 }
339
340 if (run_command(cmd_parameter, 0))
341 fastboot_fail("", response);
342 else
343 fastboot_okay(NULL, response);
344}
345
346static char g_a_cmd_buff[64];
347
348void fastboot_acmd_complete(void)
349{
350 run_command(g_a_cmd_buff, 0);
351}
352
353/**
354 * run_acmd() - Execute the ACmd command
355 *
356 * @cmd_parameter: Pointer to command parameter
357 * @response: Pointer to fastboot response buffer
358 */
Patrick Delaunayd0379902022-12-15 10:15:50 +0100359static void __maybe_unused run_acmd(char *cmd_parameter, char *response)
Heiko Schocherbc820d52021-02-10 09:29:03 +0100360{
361 if (!cmd_parameter) {
362 pr_err("missing slot suffix\n");
363 fastboot_fail("missing command", response);
364 return;
365 }
366
367 if (strlen(cmd_parameter) > sizeof(g_a_cmd_buff)) {
368 pr_err("too long command\n");
369 fastboot_fail("too long command", response);
370 return;
371 }
372
373 strcpy(g_a_cmd_buff, cmd_parameter);
374 fastboot_okay(NULL, response);
375}
Heiko Schocherbc820d52021-02-10 09:29:03 +0100376
Alex Kiernanf73a7df2018-05-29 15:30:53 +0000377/**
378 * reboot_bootloader() - Sets reboot bootloader flag.
379 *
380 * @cmd_parameter: Pointer to command parameter
381 * @response: Pointer to fastboot response buffer
382 */
383static void reboot_bootloader(char *cmd_parameter, char *response)
384{
Roman Kovalivskyi851737a2020-07-28 23:35:32 +0300385 if (fastboot_set_reboot_flag(FASTBOOT_REBOOT_REASON_BOOTLOADER))
Alex Kiernanf73a7df2018-05-29 15:30:53 +0000386 fastboot_fail("Cannot set reboot flag", response);
387 else
388 fastboot_okay(NULL, response);
389}
Alex Kiernan3845b902018-05-29 15:30:54 +0000390
Roman Kovalivskyi2b2a7712020-07-28 23:35:33 +0300391/**
392 * reboot_fastbootd() - Sets reboot fastboot flag.
393 *
394 * @cmd_parameter: Pointer to command parameter
395 * @response: Pointer to fastboot response buffer
396 */
397static void reboot_fastbootd(char *cmd_parameter, char *response)
398{
399 if (fastboot_set_reboot_flag(FASTBOOT_REBOOT_REASON_FASTBOOTD))
400 fastboot_fail("Cannot set fastboot flag", response);
401 else
402 fastboot_okay(NULL, response);
403}
404
405/**
406 * reboot_recovery() - Sets reboot recovery flag.
407 *
408 * @cmd_parameter: Pointer to command parameter
409 * @response: Pointer to fastboot response buffer
410 */
411static void reboot_recovery(char *cmd_parameter, char *response)
412{
413 if (fastboot_set_reboot_flag(FASTBOOT_REBOOT_REASON_RECOVERY))
414 fastboot_fail("Cannot set recovery flag", response);
415 else
416 fastboot_okay(NULL, response);
417}
418
Alex Kiernan3845b902018-05-29 15:30:54 +0000419/**
420 * oem_format() - Execute the OEM format command
421 *
422 * @cmd_parameter: Pointer to command parameter
423 * @response: Pointer to fastboot response buffer
424 */
Patrick Delaunayd0379902022-12-15 10:15:50 +0100425static void __maybe_unused oem_format(char *cmd_parameter, char *response)
Alex Kiernan3845b902018-05-29 15:30:54 +0000426{
427 char cmdbuf[32];
Patrick Delaunayd0379902022-12-15 10:15:50 +0100428 const int mmc_dev = config_opt_enabled(CONFIG_FASTBOOT_FLASH_MMC,
429 CONFIG_FASTBOOT_FLASH_MMC_DEV, -1);
Alex Kiernan3845b902018-05-29 15:30:54 +0000430
431 if (!env_get("partitions")) {
432 fastboot_fail("partitions not set", response);
433 } else {
Patrick Delaunayd0379902022-12-15 10:15:50 +0100434 sprintf(cmdbuf, "gpt write mmc %x $partitions", mmc_dev);
Alex Kiernan3845b902018-05-29 15:30:54 +0000435 if (run_command(cmdbuf, 0))
436 fastboot_fail("", response);
437 else
438 fastboot_okay(NULL, response);
439 }
440}
Patrick Delaunayb2f6b972021-01-27 14:46:48 +0100441
Patrick Delaunayb2f6b972021-01-27 14:46:48 +0100442/**
443 * oem_partconf() - Execute the OEM partconf command
444 *
445 * @cmd_parameter: Pointer to command parameter
446 * @response: Pointer to fastboot response buffer
447 */
Patrick Delaunayd0379902022-12-15 10:15:50 +0100448static void __maybe_unused oem_partconf(char *cmd_parameter, char *response)
Patrick Delaunayb2f6b972021-01-27 14:46:48 +0100449{
450 char cmdbuf[32];
Patrick Delaunayd0379902022-12-15 10:15:50 +0100451 const int mmc_dev = config_opt_enabled(CONFIG_FASTBOOT_FLASH_MMC,
452 CONFIG_FASTBOOT_FLASH_MMC_DEV, -1);
Patrick Delaunayb2f6b972021-01-27 14:46:48 +0100453
454 if (!cmd_parameter) {
455 fastboot_fail("Expected command parameter", response);
456 return;
457 }
458
459 /* execute 'mmc partconfg' command with cmd_parameter arguments*/
Patrick Delaunayd0379902022-12-15 10:15:50 +0100460 snprintf(cmdbuf, sizeof(cmdbuf), "mmc partconf %x %s 0", mmc_dev, cmd_parameter);
Patrick Delaunayb2f6b972021-01-27 14:46:48 +0100461 printf("Execute: %s\n", cmdbuf);
462 if (run_command(cmdbuf, 0))
463 fastboot_fail("Cannot set oem partconf", response);
464 else
465 fastboot_okay(NULL, response);
466}
Patrick Delaunay0c0394b2021-01-27 14:46:49 +0100467
Patrick Delaunay0c0394b2021-01-27 14:46:49 +0100468/**
469 * oem_bootbus() - Execute the OEM bootbus command
470 *
471 * @cmd_parameter: Pointer to command parameter
472 * @response: Pointer to fastboot response buffer
473 */
Patrick Delaunayd0379902022-12-15 10:15:50 +0100474static void __maybe_unused oem_bootbus(char *cmd_parameter, char *response)
Patrick Delaunay0c0394b2021-01-27 14:46:49 +0100475{
476 char cmdbuf[32];
Patrick Delaunayd0379902022-12-15 10:15:50 +0100477 const int mmc_dev = config_opt_enabled(CONFIG_FASTBOOT_FLASH_MMC,
478 CONFIG_FASTBOOT_FLASH_MMC_DEV, -1);
Patrick Delaunay0c0394b2021-01-27 14:46:49 +0100479
480 if (!cmd_parameter) {
481 fastboot_fail("Expected command parameter", response);
482 return;
483 }
484
485 /* execute 'mmc bootbus' command with cmd_parameter arguments*/
Patrick Delaunayd0379902022-12-15 10:15:50 +0100486 snprintf(cmdbuf, sizeof(cmdbuf), "mmc bootbus %x %s", mmc_dev, cmd_parameter);
Patrick Delaunay0c0394b2021-01-27 14:46:49 +0100487 printf("Execute: %s\n", cmdbuf);
488 if (run_command(cmdbuf, 0))
489 fastboot_fail("Cannot set oem bootbus", response);
490 else
491 fastboot_okay(NULL, response);
492}