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