blob: ae4a7dc7fb823eb3f86e7a6efb6e9417c8019851 [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>
Simon Glassb79fdc72020-05-10 11:39:54 -060013#include <flash.h>
Alex Kiernanf73a7df2018-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 Kovalivskyi2b2a7712020-07-28 23:35:33 +030040static void reboot_fastbootd(char *, char *);
41static void reboot_recovery(char *, char *);
Alex Kiernan3845b902018-05-29 15:30:54 +000042#if CONFIG_IS_ENABLED(FASTBOOT_CMD_OEM_FORMAT)
43static void oem_format(char *, char *);
44#endif
Patrick Delaunayb2f6b972021-01-27 14:46:48 +010045#if CONFIG_IS_ENABLED(FASTBOOT_CMD_OEM_PARTCONF)
46static void oem_partconf(char *, char *);
47#endif
Alex Kiernanf73a7df2018-05-29 15:30:53 +000048
49static const struct {
50 const char *command;
51 void (*dispatch)(char *cmd_parameter, char *response);
52} commands[FASTBOOT_COMMAND_COUNT] = {
53 [FASTBOOT_COMMAND_GETVAR] = {
54 .command = "getvar",
55 .dispatch = getvar
56 },
57 [FASTBOOT_COMMAND_DOWNLOAD] = {
58 .command = "download",
59 .dispatch = download
60 },
61#if CONFIG_IS_ENABLED(FASTBOOT_FLASH)
62 [FASTBOOT_COMMAND_FLASH] = {
63 .command = "flash",
64 .dispatch = flash
65 },
66 [FASTBOOT_COMMAND_ERASE] = {
67 .command = "erase",
68 .dispatch = erase
69 },
70#endif
71 [FASTBOOT_COMMAND_BOOT] = {
72 .command = "boot",
73 .dispatch = okay
74 },
75 [FASTBOOT_COMMAND_CONTINUE] = {
76 .command = "continue",
77 .dispatch = okay
78 },
79 [FASTBOOT_COMMAND_REBOOT] = {
80 .command = "reboot",
81 .dispatch = okay
82 },
83 [FASTBOOT_COMMAND_REBOOT_BOOTLOADER] = {
84 .command = "reboot-bootloader",
85 .dispatch = reboot_bootloader
86 },
Roman Kovalivskyi2b2a7712020-07-28 23:35:33 +030087 [FASTBOOT_COMMAND_REBOOT_FASTBOOTD] = {
88 .command = "reboot-fastboot",
89 .dispatch = reboot_fastbootd
90 },
91 [FASTBOOT_COMMAND_REBOOT_RECOVERY] = {
92 .command = "reboot-recovery",
93 .dispatch = reboot_recovery
94 },
Alex Kiernanf73a7df2018-05-29 15:30:53 +000095 [FASTBOOT_COMMAND_SET_ACTIVE] = {
96 .command = "set_active",
97 .dispatch = okay
98 },
Alex Kiernan3845b902018-05-29 15:30:54 +000099#if CONFIG_IS_ENABLED(FASTBOOT_CMD_OEM_FORMAT)
100 [FASTBOOT_COMMAND_OEM_FORMAT] = {
101 .command = "oem format",
102 .dispatch = oem_format,
103 },
104#endif
Patrick Delaunayb2f6b972021-01-27 14:46:48 +0100105#if CONFIG_IS_ENABLED(FASTBOOT_CMD_OEM_PARTCONF)
106 [FASTBOOT_COMMAND_OEM_PARTCONF] = {
107 .command = "oem partconf",
108 .dispatch = oem_partconf,
109 },
110#endif
Alex Kiernanf73a7df2018-05-29 15:30:53 +0000111};
112
113/**
114 * fastboot_handle_command - Handle fastboot command
115 *
116 * @cmd_string: Pointer to command string
117 * @response: Pointer to fastboot response buffer
118 *
119 * Return: Executed command, or -1 if not recognized
120 */
121int fastboot_handle_command(char *cmd_string, char *response)
122{
123 int i;
124 char *cmd_parameter;
125
126 cmd_parameter = cmd_string;
127 strsep(&cmd_parameter, ":");
128
129 for (i = 0; i < FASTBOOT_COMMAND_COUNT; i++) {
130 if (!strcmp(commands[i].command, cmd_string)) {
131 if (commands[i].dispatch) {
132 commands[i].dispatch(cmd_parameter,
133 response);
134 return i;
135 } else {
136 break;
137 }
138 }
139 }
140
141 pr_err("command %s not recognized.\n", cmd_string);
142 fastboot_fail("unrecognized command", response);
143 return -1;
144}
145
146/**
147 * okay() - Send bare OKAY response
148 *
149 * @cmd_parameter: Pointer to command parameter
150 * @response: Pointer to fastboot response buffer
151 *
152 * Send a bare OKAY fastboot response. This is used where the command is
153 * valid, but all the work is done after the response has been sent (e.g.
154 * boot, reboot etc.)
155 */
156static void okay(char *cmd_parameter, char *response)
157{
158 fastboot_okay(NULL, response);
159}
160
161/**
162 * getvar() - Read a config/version variable
163 *
164 * @cmd_parameter: Pointer to command parameter
165 * @response: Pointer to fastboot response buffer
166 */
167static void getvar(char *cmd_parameter, char *response)
168{
169 fastboot_getvar(cmd_parameter, response);
170}
171
172/**
173 * fastboot_download() - Start a download transfer from the client
174 *
175 * @cmd_parameter: Pointer to command parameter
176 * @response: Pointer to fastboot response buffer
177 */
178static void download(char *cmd_parameter, char *response)
179{
180 char *tmp;
181
182 if (!cmd_parameter) {
183 fastboot_fail("Expected command parameter", response);
184 return;
185 }
186 fastboot_bytes_received = 0;
187 fastboot_bytes_expected = simple_strtoul(cmd_parameter, &tmp, 16);
188 if (fastboot_bytes_expected == 0) {
189 fastboot_fail("Expected nonzero image size", response);
190 return;
191 }
192 /*
193 * Nothing to download yet. Response is of the form:
194 * [DATA|FAIL]$cmd_parameter
195 *
196 * where cmd_parameter is an 8 digit hexadecimal number
197 */
198 if (fastboot_bytes_expected > fastboot_buf_size) {
199 fastboot_fail(cmd_parameter, response);
200 } else {
201 printf("Starting download of %d bytes\n",
202 fastboot_bytes_expected);
203 fastboot_response("DATA", response, "%s", cmd_parameter);
204 }
205}
206
207/**
208 * fastboot_data_remaining() - return bytes remaining in current transfer
209 *
210 * Return: Number of bytes left in the current download
211 */
212u32 fastboot_data_remaining(void)
213{
214 return fastboot_bytes_expected - fastboot_bytes_received;
215}
216
217/**
218 * fastboot_data_download() - Copy image data to fastboot_buf_addr.
219 *
220 * @fastboot_data: Pointer to received fastboot data
221 * @fastboot_data_len: Length of received fastboot data
222 * @response: Pointer to fastboot response buffer
223 *
224 * Copies image data from fastboot_data to fastboot_buf_addr. Writes to
225 * response. fastboot_bytes_received is updated to indicate the number
226 * of bytes that have been transferred.
227 *
228 * On completion sets image_size and ${filesize} to the total size of the
229 * downloaded image.
230 */
231void fastboot_data_download(const void *fastboot_data,
232 unsigned int fastboot_data_len,
233 char *response)
234{
235#define BYTES_PER_DOT 0x20000
236 u32 pre_dot_num, now_dot_num;
237
238 if (fastboot_data_len == 0 ||
239 (fastboot_bytes_received + fastboot_data_len) >
240 fastboot_bytes_expected) {
241 fastboot_fail("Received invalid data length",
242 response);
243 return;
244 }
245 /* Download data to fastboot_buf_addr */
246 memcpy(fastboot_buf_addr + fastboot_bytes_received,
247 fastboot_data, fastboot_data_len);
248
249 pre_dot_num = fastboot_bytes_received / BYTES_PER_DOT;
250 fastboot_bytes_received += fastboot_data_len;
251 now_dot_num = fastboot_bytes_received / BYTES_PER_DOT;
252
253 if (pre_dot_num != now_dot_num) {
254 putc('.');
255 if (!(now_dot_num % 74))
256 putc('\n');
257 }
258 *response = '\0';
259}
260
261/**
262 * fastboot_data_complete() - Mark current transfer complete
263 *
264 * @response: Pointer to fastboot response buffer
265 *
266 * Set image_size and ${filesize} to the total size of the downloaded image.
267 */
268void fastboot_data_complete(char *response)
269{
270 /* Download complete. Respond with "OKAY" */
271 fastboot_okay(NULL, response);
272 printf("\ndownloading of %d bytes finished\n", fastboot_bytes_received);
273 image_size = fastboot_bytes_received;
274 env_set_hex("filesize", image_size);
275 fastboot_bytes_expected = 0;
276 fastboot_bytes_received = 0;
277}
278
279#if CONFIG_IS_ENABLED(FASTBOOT_FLASH)
280/**
281 * flash() - write the downloaded image to the indicated partition.
282 *
283 * @cmd_parameter: Pointer to partition name
284 * @response: Pointer to fastboot response buffer
285 *
286 * Writes the previously downloaded image to the partition indicated by
287 * cmd_parameter. Writes to response.
288 */
289static void flash(char *cmd_parameter, char *response)
290{
291#if CONFIG_IS_ENABLED(FASTBOOT_FLASH_MMC)
292 fastboot_mmc_flash_write(cmd_parameter, fastboot_buf_addr, image_size,
293 response);
294#endif
295#if CONFIG_IS_ENABLED(FASTBOOT_FLASH_NAND)
296 fastboot_nand_flash_write(cmd_parameter, fastboot_buf_addr, image_size,
297 response);
298#endif
299}
300
301/**
302 * erase() - erase the indicated partition.
303 *
304 * @cmd_parameter: Pointer to partition name
305 * @response: Pointer to fastboot response buffer
306 *
307 * Erases the partition indicated by cmd_parameter (clear to 0x00s). Writes
308 * to response.
309 */
310static void erase(char *cmd_parameter, char *response)
311{
312#if CONFIG_IS_ENABLED(FASTBOOT_FLASH_MMC)
313 fastboot_mmc_erase(cmd_parameter, response);
314#endif
315#if CONFIG_IS_ENABLED(FASTBOOT_FLASH_NAND)
316 fastboot_nand_erase(cmd_parameter, response);
317#endif
318}
319#endif
320
321/**
322 * reboot_bootloader() - Sets reboot bootloader flag.
323 *
324 * @cmd_parameter: Pointer to command parameter
325 * @response: Pointer to fastboot response buffer
326 */
327static void reboot_bootloader(char *cmd_parameter, char *response)
328{
Roman Kovalivskyi851737a2020-07-28 23:35:32 +0300329 if (fastboot_set_reboot_flag(FASTBOOT_REBOOT_REASON_BOOTLOADER))
Alex Kiernanf73a7df2018-05-29 15:30:53 +0000330 fastboot_fail("Cannot set reboot flag", response);
331 else
332 fastboot_okay(NULL, response);
333}
Alex Kiernan3845b902018-05-29 15:30:54 +0000334
Roman Kovalivskyi2b2a7712020-07-28 23:35:33 +0300335/**
336 * reboot_fastbootd() - Sets reboot fastboot flag.
337 *
338 * @cmd_parameter: Pointer to command parameter
339 * @response: Pointer to fastboot response buffer
340 */
341static void reboot_fastbootd(char *cmd_parameter, char *response)
342{
343 if (fastboot_set_reboot_flag(FASTBOOT_REBOOT_REASON_FASTBOOTD))
344 fastboot_fail("Cannot set fastboot flag", response);
345 else
346 fastboot_okay(NULL, response);
347}
348
349/**
350 * reboot_recovery() - Sets reboot recovery flag.
351 *
352 * @cmd_parameter: Pointer to command parameter
353 * @response: Pointer to fastboot response buffer
354 */
355static void reboot_recovery(char *cmd_parameter, char *response)
356{
357 if (fastboot_set_reboot_flag(FASTBOOT_REBOOT_REASON_RECOVERY))
358 fastboot_fail("Cannot set recovery flag", response);
359 else
360 fastboot_okay(NULL, response);
361}
362
Alex Kiernan3845b902018-05-29 15:30:54 +0000363#if CONFIG_IS_ENABLED(FASTBOOT_CMD_OEM_FORMAT)
364/**
365 * oem_format() - Execute the OEM format command
366 *
367 * @cmd_parameter: Pointer to command parameter
368 * @response: Pointer to fastboot response buffer
369 */
370static void oem_format(char *cmd_parameter, char *response)
371{
372 char cmdbuf[32];
373
374 if (!env_get("partitions")) {
375 fastboot_fail("partitions not set", response);
376 } else {
377 sprintf(cmdbuf, "gpt write mmc %x $partitions",
378 CONFIG_FASTBOOT_FLASH_MMC_DEV);
379 if (run_command(cmdbuf, 0))
380 fastboot_fail("", response);
381 else
382 fastboot_okay(NULL, response);
383 }
384}
385#endif
Patrick Delaunayb2f6b972021-01-27 14:46:48 +0100386
387#if CONFIG_IS_ENABLED(FASTBOOT_CMD_OEM_PARTCONF)
388/**
389 * oem_partconf() - Execute the OEM partconf command
390 *
391 * @cmd_parameter: Pointer to command parameter
392 * @response: Pointer to fastboot response buffer
393 */
394static void oem_partconf(char *cmd_parameter, char *response)
395{
396 char cmdbuf[32];
397
398 if (!cmd_parameter) {
399 fastboot_fail("Expected command parameter", response);
400 return;
401 }
402
403 /* execute 'mmc partconfg' command with cmd_parameter arguments*/
404 snprintf(cmdbuf, sizeof(cmdbuf), "mmc partconf %x %s 0",
405 CONFIG_FASTBOOT_FLASH_MMC_DEV, cmd_parameter);
406 printf("Execute: %s\n", cmdbuf);
407 if (run_command(cmdbuf, 0))
408 fastboot_fail("Cannot set oem partconf", response);
409 else
410 fastboot_okay(NULL, response);
411}
412#endif