blob: 41fc8d7904d7e559c9341860ed3bb046e5bc48bd [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
52static const struct {
53 const char *command;
54 void (*dispatch)(char *cmd_parameter, char *response);
55} commands[FASTBOOT_COMMAND_COUNT] = {
56 [FASTBOOT_COMMAND_GETVAR] = {
57 .command = "getvar",
58 .dispatch = getvar
59 },
60 [FASTBOOT_COMMAND_DOWNLOAD] = {
61 .command = "download",
62 .dispatch = download
63 },
64#if CONFIG_IS_ENABLED(FASTBOOT_FLASH)
65 [FASTBOOT_COMMAND_FLASH] = {
66 .command = "flash",
67 .dispatch = flash
68 },
69 [FASTBOOT_COMMAND_ERASE] = {
70 .command = "erase",
71 .dispatch = erase
72 },
73#endif
74 [FASTBOOT_COMMAND_BOOT] = {
75 .command = "boot",
76 .dispatch = okay
77 },
78 [FASTBOOT_COMMAND_CONTINUE] = {
79 .command = "continue",
80 .dispatch = okay
81 },
82 [FASTBOOT_COMMAND_REBOOT] = {
83 .command = "reboot",
84 .dispatch = okay
85 },
86 [FASTBOOT_COMMAND_REBOOT_BOOTLOADER] = {
87 .command = "reboot-bootloader",
88 .dispatch = reboot_bootloader
89 },
Roman Kovalivskyib30b97b2020-07-28 23:35:33 +030090 [FASTBOOT_COMMAND_REBOOT_FASTBOOTD] = {
91 .command = "reboot-fastboot",
92 .dispatch = reboot_fastbootd
93 },
94 [FASTBOOT_COMMAND_REBOOT_RECOVERY] = {
95 .command = "reboot-recovery",
96 .dispatch = reboot_recovery
97 },
Alex Kiernand5aa57c2018-05-29 15:30:53 +000098 [FASTBOOT_COMMAND_SET_ACTIVE] = {
99 .command = "set_active",
100 .dispatch = okay
101 },
Alex Kiernanc86cde92018-05-29 15:30:54 +0000102#if CONFIG_IS_ENABLED(FASTBOOT_CMD_OEM_FORMAT)
103 [FASTBOOT_COMMAND_OEM_FORMAT] = {
104 .command = "oem format",
105 .dispatch = oem_format,
106 },
107#endif
Patrick Delaunay61687702021-01-27 14:46:48 +0100108#if CONFIG_IS_ENABLED(FASTBOOT_CMD_OEM_PARTCONF)
109 [FASTBOOT_COMMAND_OEM_PARTCONF] = {
110 .command = "oem partconf",
111 .dispatch = oem_partconf,
112 },
113#endif
Patrick Delaunay67af29a2021-01-27 14:46:49 +0100114#if CONFIG_IS_ENABLED(FASTBOOT_CMD_OEM_BOOTBUS)
115 [FASTBOOT_COMMAND_OEM_BOOTBUS] = {
116 .command = "oem bootbus",
117 .dispatch = oem_bootbus,
118 },
119#endif
Alex Kiernand5aa57c2018-05-29 15:30:53 +0000120};
121
122/**
123 * fastboot_handle_command - Handle fastboot command
124 *
125 * @cmd_string: Pointer to command string
126 * @response: Pointer to fastboot response buffer
127 *
128 * Return: Executed command, or -1 if not recognized
129 */
130int fastboot_handle_command(char *cmd_string, char *response)
131{
132 int i;
133 char *cmd_parameter;
134
135 cmd_parameter = cmd_string;
136 strsep(&cmd_parameter, ":");
137
138 for (i = 0; i < FASTBOOT_COMMAND_COUNT; i++) {
139 if (!strcmp(commands[i].command, cmd_string)) {
140 if (commands[i].dispatch) {
141 commands[i].dispatch(cmd_parameter,
142 response);
143 return i;
144 } else {
145 break;
146 }
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;
196 fastboot_bytes_expected = simple_strtoul(cmd_parameter, &tmp, 16);
197 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
288#if CONFIG_IS_ENABLED(FASTBOOT_FLASH)
289/**
290 * flash() - write the downloaded image to the indicated partition.
291 *
292 * @cmd_parameter: Pointer to partition name
293 * @response: Pointer to fastboot response buffer
294 *
295 * Writes the previously downloaded image to the partition indicated by
296 * cmd_parameter. Writes to response.
297 */
298static void flash(char *cmd_parameter, char *response)
299{
300#if CONFIG_IS_ENABLED(FASTBOOT_FLASH_MMC)
301 fastboot_mmc_flash_write(cmd_parameter, fastboot_buf_addr, image_size,
302 response);
303#endif
304#if CONFIG_IS_ENABLED(FASTBOOT_FLASH_NAND)
305 fastboot_nand_flash_write(cmd_parameter, fastboot_buf_addr, image_size,
306 response);
307#endif
308}
309
310/**
311 * erase() - erase the indicated partition.
312 *
313 * @cmd_parameter: Pointer to partition name
314 * @response: Pointer to fastboot response buffer
315 *
316 * Erases the partition indicated by cmd_parameter (clear to 0x00s). Writes
317 * to response.
318 */
319static void erase(char *cmd_parameter, char *response)
320{
321#if CONFIG_IS_ENABLED(FASTBOOT_FLASH_MMC)
322 fastboot_mmc_erase(cmd_parameter, response);
323#endif
324#if CONFIG_IS_ENABLED(FASTBOOT_FLASH_NAND)
325 fastboot_nand_erase(cmd_parameter, response);
326#endif
327}
328#endif
329
330/**
331 * reboot_bootloader() - Sets reboot bootloader flag.
332 *
333 * @cmd_parameter: Pointer to command parameter
334 * @response: Pointer to fastboot response buffer
335 */
336static void reboot_bootloader(char *cmd_parameter, char *response)
337{
Roman Kovalivskyi1bb13422020-07-28 23:35:32 +0300338 if (fastboot_set_reboot_flag(FASTBOOT_REBOOT_REASON_BOOTLOADER))
Alex Kiernand5aa57c2018-05-29 15:30:53 +0000339 fastboot_fail("Cannot set reboot flag", response);
340 else
341 fastboot_okay(NULL, response);
342}
Alex Kiernanc86cde92018-05-29 15:30:54 +0000343
Roman Kovalivskyib30b97b2020-07-28 23:35:33 +0300344/**
345 * reboot_fastbootd() - Sets reboot fastboot flag.
346 *
347 * @cmd_parameter: Pointer to command parameter
348 * @response: Pointer to fastboot response buffer
349 */
350static void reboot_fastbootd(char *cmd_parameter, char *response)
351{
352 if (fastboot_set_reboot_flag(FASTBOOT_REBOOT_REASON_FASTBOOTD))
353 fastboot_fail("Cannot set fastboot flag", response);
354 else
355 fastboot_okay(NULL, response);
356}
357
358/**
359 * reboot_recovery() - Sets reboot recovery flag.
360 *
361 * @cmd_parameter: Pointer to command parameter
362 * @response: Pointer to fastboot response buffer
363 */
364static void reboot_recovery(char *cmd_parameter, char *response)
365{
366 if (fastboot_set_reboot_flag(FASTBOOT_REBOOT_REASON_RECOVERY))
367 fastboot_fail("Cannot set recovery flag", response);
368 else
369 fastboot_okay(NULL, response);
370}
371
Alex Kiernanc86cde92018-05-29 15:30:54 +0000372#if CONFIG_IS_ENABLED(FASTBOOT_CMD_OEM_FORMAT)
373/**
374 * oem_format() - Execute the OEM format command
375 *
376 * @cmd_parameter: Pointer to command parameter
377 * @response: Pointer to fastboot response buffer
378 */
379static void oem_format(char *cmd_parameter, char *response)
380{
381 char cmdbuf[32];
382
383 if (!env_get("partitions")) {
384 fastboot_fail("partitions not set", response);
385 } else {
386 sprintf(cmdbuf, "gpt write mmc %x $partitions",
387 CONFIG_FASTBOOT_FLASH_MMC_DEV);
388 if (run_command(cmdbuf, 0))
389 fastboot_fail("", response);
390 else
391 fastboot_okay(NULL, response);
392 }
393}
394#endif
Patrick Delaunay61687702021-01-27 14:46:48 +0100395
396#if CONFIG_IS_ENABLED(FASTBOOT_CMD_OEM_PARTCONF)
397/**
398 * oem_partconf() - Execute the OEM partconf command
399 *
400 * @cmd_parameter: Pointer to command parameter
401 * @response: Pointer to fastboot response buffer
402 */
403static void oem_partconf(char *cmd_parameter, char *response)
404{
405 char cmdbuf[32];
406
407 if (!cmd_parameter) {
408 fastboot_fail("Expected command parameter", response);
409 return;
410 }
411
412 /* execute 'mmc partconfg' command with cmd_parameter arguments*/
413 snprintf(cmdbuf, sizeof(cmdbuf), "mmc partconf %x %s 0",
414 CONFIG_FASTBOOT_FLASH_MMC_DEV, cmd_parameter);
415 printf("Execute: %s\n", cmdbuf);
416 if (run_command(cmdbuf, 0))
417 fastboot_fail("Cannot set oem partconf", response);
418 else
419 fastboot_okay(NULL, response);
420}
421#endif
Patrick Delaunay67af29a2021-01-27 14:46:49 +0100422
423#if CONFIG_IS_ENABLED(FASTBOOT_CMD_OEM_BOOTBUS)
424/**
425 * oem_bootbus() - Execute the OEM bootbus command
426 *
427 * @cmd_parameter: Pointer to command parameter
428 * @response: Pointer to fastboot response buffer
429 */
430static void oem_bootbus(char *cmd_parameter, char *response)
431{
432 char cmdbuf[32];
433
434 if (!cmd_parameter) {
435 fastboot_fail("Expected command parameter", response);
436 return;
437 }
438
439 /* execute 'mmc bootbus' command with cmd_parameter arguments*/
440 snprintf(cmdbuf, sizeof(cmdbuf), "mmc bootbus %x %s",
441 CONFIG_FASTBOOT_FLASH_MMC_DEV, cmd_parameter);
442 printf("Execute: %s\n", cmdbuf);
443 if (run_command(cmdbuf, 0))
444 fastboot_fail("Cannot set oem bootbus", response);
445 else
446 fastboot_okay(NULL, response);
447}
448#endif