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