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