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