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