]>
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> | |
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 | */ | |
17 | static u32 image_size; | |
18 | ||
19 | /** | |
20 | * fastboot_bytes_received - number of bytes received in the current download | |
21 | */ | |
22 | static u32 fastboot_bytes_received; | |
23 | ||
24 | /** | |
25 | * fastboot_bytes_expected - number of bytes expected in the current download | |
26 | */ | |
27 | static u32 fastboot_bytes_expected; | |
28 | ||
29 | static void okay(char *, char *); | |
30 | static void getvar(char *, char *); | |
31 | static void download(char *, char *); | |
32 | #if CONFIG_IS_ENABLED(FASTBOOT_FLASH) | |
33 | static void flash(char *, char *); | |
34 | static void erase(char *, char *); | |
35 | #endif | |
36 | static void reboot_bootloader(char *, char *); | |
3845b906 AK |
37 | #if CONFIG_IS_ENABLED(FASTBOOT_CMD_OEM_FORMAT) |
38 | static void oem_format(char *, char *); | |
39 | #endif | |
f73a7df9 AK |
40 | |
41 | static 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 | }, | |
3845b906 AK |
83 | #if CONFIG_IS_ENABLED(FASTBOOT_CMD_OEM_FORMAT) |
84 | [FASTBOOT_COMMAND_OEM_FORMAT] = { | |
85 | .command = "oem format", | |
86 | .dispatch = oem_format, | |
87 | }, | |
88 | #endif | |
f73a7df9 AK |
89 | }; |
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 | */ | |
99 | int 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 | */ | |
134 | static 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 | */ | |
145 | static 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 | */ | |
156 | static 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 | */ | |
190 | u32 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 | */ | |
209 | void 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 | */ | |
246 | void 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 | */ | |
267 | static 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 | */ | |
288 | static 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 | */ | |
305 | static 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 | } | |
3845b906 AK |
312 | |
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 | */ | |
320 | static 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 |