]>
Commit | Line | Data |
---|---|---|
f73a7df9 AK |
1 | // SPDX-License-Identifier: BSD-2-Clause |
2 | /* | |
3 | * Copyright (C) 2016 The Android Open Source Project | |
4 | */ | |
5 | ||
6 | #include <common.h> | |
288b29e4 | 7 | #include <command.h> |
c7694dd4 | 8 | #include <env.h> |
f73a7df9 AK |
9 | #include <fastboot.h> |
10 | #include <fastboot-internal.h> | |
11 | #include <fb_mmc.h> | |
12 | #include <fb_nand.h> | |
b79fdc76 | 13 | #include <flash.h> |
f73a7df9 AK |
14 | #include <part.h> |
15 | #include <stdlib.h> | |
16 | ||
17 | /** | |
18 | * image_size - final fastboot image size | |
19 | */ | |
20 | static u32 image_size; | |
21 | ||
22 | /** | |
23 | * fastboot_bytes_received - number of bytes received in the current download | |
24 | */ | |
25 | static u32 fastboot_bytes_received; | |
26 | ||
27 | /** | |
28 | * fastboot_bytes_expected - number of bytes expected in the current download | |
29 | */ | |
30 | static u32 fastboot_bytes_expected; | |
31 | ||
32 | static void okay(char *, char *); | |
33 | static void getvar(char *, char *); | |
34 | static void download(char *, char *); | |
35 | #if CONFIG_IS_ENABLED(FASTBOOT_FLASH) | |
36 | static void flash(char *, char *); | |
37 | static void erase(char *, char *); | |
38 | #endif | |
39 | static void reboot_bootloader(char *, char *); | |
3845b906 AK |
40 | #if CONFIG_IS_ENABLED(FASTBOOT_CMD_OEM_FORMAT) |
41 | static void oem_format(char *, char *); | |
42 | #endif | |
f73a7df9 AK |
43 | |
44 | static 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 | }, | |
3845b906 AK |
86 | #if CONFIG_IS_ENABLED(FASTBOOT_CMD_OEM_FORMAT) |
87 | [FASTBOOT_COMMAND_OEM_FORMAT] = { | |
88 | .command = "oem format", | |
89 | .dispatch = oem_format, | |
90 | }, | |
91 | #endif | |
f73a7df9 AK |
92 | }; |
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 | */ | |
102 | int 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 | */ | |
137 | static 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 | */ | |
148 | static 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 | */ | |
159 | static 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 | */ | |
193 | u32 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 | */ | |
212 | void 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 | */ | |
249 | void 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 | */ | |
270 | static 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 | */ | |
291 | static 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 | */ | |
308 | static 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 | } | |
3845b906 AK |
315 | |
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 | */ | |
323 | static 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 |