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