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 <command.h>
8 #include <env.h>
9 #include <fastboot.h>
10 #include <fastboot-internal.h>
11 #include <fb_mmc.h>
12 #include <fb_nand.h>
13 #include <flash.h>
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 *);
40 static void reboot_fastbootd(char *, char *);
41 static void reboot_recovery(char *, char *);
42 #if CONFIG_IS_ENABLED(FASTBOOT_CMD_OEM_FORMAT)
43 static void oem_format(char *, char *);
44 #endif
45 #if CONFIG_IS_ENABLED(FASTBOOT_CMD_OEM_PARTCONF)
46 static void oem_partconf(char *, char *);
47 #endif
48 #if CONFIG_IS_ENABLED(FASTBOOT_CMD_OEM_BOOTBUS)
49 static void oem_bootbus(char *, char *);
50 #endif
51 
52 #if CONFIG_IS_ENABLED(FASTBOOT_UUU_SUPPORT)
53 static void run_ucmd(char *, char *);
54 static void run_acmd(char *, char *);
55 #endif
56 
57 static const struct {
58 	const char *command;
59 	void (*dispatch)(char *cmd_parameter, char *response);
60 } commands[FASTBOOT_COMMAND_COUNT] = {
61 	[FASTBOOT_COMMAND_GETVAR] = {
62 		.command = "getvar",
63 		.dispatch = getvar
64 	},
65 	[FASTBOOT_COMMAND_DOWNLOAD] = {
66 		.command = "download",
67 		.dispatch = download
68 	},
69 #if CONFIG_IS_ENABLED(FASTBOOT_FLASH)
70 	[FASTBOOT_COMMAND_FLASH] =  {
71 		.command = "flash",
72 		.dispatch = flash
73 	},
74 	[FASTBOOT_COMMAND_ERASE] =  {
75 		.command = "erase",
76 		.dispatch = erase
77 	},
78 #endif
79 	[FASTBOOT_COMMAND_BOOT] =  {
80 		.command = "boot",
81 		.dispatch = okay
82 	},
83 	[FASTBOOT_COMMAND_CONTINUE] =  {
84 		.command = "continue",
85 		.dispatch = okay
86 	},
87 	[FASTBOOT_COMMAND_REBOOT] =  {
88 		.command = "reboot",
89 		.dispatch = okay
90 	},
91 	[FASTBOOT_COMMAND_REBOOT_BOOTLOADER] =  {
92 		.command = "reboot-bootloader",
93 		.dispatch = reboot_bootloader
94 	},
95 	[FASTBOOT_COMMAND_REBOOT_FASTBOOTD] =  {
96 		.command = "reboot-fastboot",
97 		.dispatch = reboot_fastbootd
98 	},
99 	[FASTBOOT_COMMAND_REBOOT_RECOVERY] =  {
100 		.command = "reboot-recovery",
101 		.dispatch = reboot_recovery
102 	},
103 	[FASTBOOT_COMMAND_SET_ACTIVE] =  {
104 		.command = "set_active",
105 		.dispatch = okay
106 	},
107 #if CONFIG_IS_ENABLED(FASTBOOT_CMD_OEM_FORMAT)
108 	[FASTBOOT_COMMAND_OEM_FORMAT] = {
109 		.command = "oem format",
110 		.dispatch = oem_format,
111 	},
112 #endif
113 #if CONFIG_IS_ENABLED(FASTBOOT_CMD_OEM_PARTCONF)
114 	[FASTBOOT_COMMAND_OEM_PARTCONF] = {
115 		.command = "oem partconf",
116 		.dispatch = oem_partconf,
117 	},
118 #endif
119 #if CONFIG_IS_ENABLED(FASTBOOT_CMD_OEM_BOOTBUS)
120 	[FASTBOOT_COMMAND_OEM_BOOTBUS] = {
121 		.command = "oem bootbus",
122 		.dispatch = oem_bootbus,
123 	},
124 #endif
125 #if CONFIG_IS_ENABLED(FASTBOOT_UUU_SUPPORT)
126 	[FASTBOOT_COMMAND_UCMD] = {
127 		.command = "UCmd",
128 		.dispatch = run_ucmd,
129 	},
130 	[FASTBOOT_COMMAND_ACMD] = {
131 		.command = "ACmd",
132 		.dispatch = run_acmd,
133 	},
134 #endif
135 };
136 
137 /**
138  * fastboot_handle_command - Handle fastboot command
139  *
140  * @cmd_string: Pointer to command string
141  * @response: Pointer to fastboot response buffer
142  *
143  * Return: Executed command, or -1 if not recognized
144  */
fastboot_handle_command(char * cmd_string,char * response)145 int fastboot_handle_command(char *cmd_string, char *response)
146 {
147 	int i;
148 	char *cmd_parameter;
149 
150 	cmd_parameter = cmd_string;
151 	strsep(&cmd_parameter, ":");
152 
153 	for (i = 0; i < FASTBOOT_COMMAND_COUNT; i++) {
154 		if (!strcmp(commands[i].command, cmd_string)) {
155 			if (commands[i].dispatch) {
156 				commands[i].dispatch(cmd_parameter,
157 							response);
158 				return i;
159 			} else {
160 				break;
161 			}
162 		}
163 	}
164 
165 	pr_err("command %s not recognized.\n", cmd_string);
166 	fastboot_fail("unrecognized command", response);
167 	return -1;
168 }
169 
170 /**
171  * okay() - Send bare OKAY response
172  *
173  * @cmd_parameter: Pointer to command parameter
174  * @response: Pointer to fastboot response buffer
175  *
176  * Send a bare OKAY fastboot response. This is used where the command is
177  * valid, but all the work is done after the response has been sent (e.g.
178  * boot, reboot etc.)
179  */
okay(char * cmd_parameter,char * response)180 static void okay(char *cmd_parameter, char *response)
181 {
182 	fastboot_okay(NULL, response);
183 }
184 
185 /**
186  * getvar() - Read a config/version variable
187  *
188  * @cmd_parameter: Pointer to command parameter
189  * @response: Pointer to fastboot response buffer
190  */
getvar(char * cmd_parameter,char * response)191 static void getvar(char *cmd_parameter, char *response)
192 {
193 	fastboot_getvar(cmd_parameter, response);
194 }
195 
196 /**
197  * fastboot_download() - Start a download transfer from the client
198  *
199  * @cmd_parameter: Pointer to command parameter
200  * @response: Pointer to fastboot response buffer
201  */
download(char * cmd_parameter,char * response)202 static void download(char *cmd_parameter, char *response)
203 {
204 	char *tmp;
205 
206 	if (!cmd_parameter) {
207 		fastboot_fail("Expected command parameter", response);
208 		return;
209 	}
210 	fastboot_bytes_received = 0;
211 	fastboot_bytes_expected = hextoul(cmd_parameter, &tmp);
212 	if (fastboot_bytes_expected == 0) {
213 		fastboot_fail("Expected nonzero image size", response);
214 		return;
215 	}
216 	/*
217 	 * Nothing to download yet. Response is of the form:
218 	 * [DATA|FAIL]$cmd_parameter
219 	 *
220 	 * where cmd_parameter is an 8 digit hexadecimal number
221 	 */
222 	if (fastboot_bytes_expected > fastboot_buf_size) {
223 		fastboot_fail(cmd_parameter, response);
224 	} else {
225 		printf("Starting download of %d bytes\n",
226 		       fastboot_bytes_expected);
227 		fastboot_response("DATA", response, "%s", cmd_parameter);
228 	}
229 }
230 
231 /**
232  * fastboot_data_remaining() - return bytes remaining in current transfer
233  *
234  * Return: Number of bytes left in the current download
235  */
fastboot_data_remaining(void)236 u32 fastboot_data_remaining(void)
237 {
238 	return fastboot_bytes_expected - fastboot_bytes_received;
239 }
240 
241 /**
242  * fastboot_data_download() - Copy image data to fastboot_buf_addr.
243  *
244  * @fastboot_data: Pointer to received fastboot data
245  * @fastboot_data_len: Length of received fastboot data
246  * @response: Pointer to fastboot response buffer
247  *
248  * Copies image data from fastboot_data to fastboot_buf_addr. Writes to
249  * response. fastboot_bytes_received is updated to indicate the number
250  * of bytes that have been transferred.
251  *
252  * On completion sets image_size and ${filesize} to the total size of the
253  * downloaded image.
254  */
fastboot_data_download(const void * fastboot_data,unsigned int fastboot_data_len,char * response)255 void fastboot_data_download(const void *fastboot_data,
256 			    unsigned int fastboot_data_len,
257 			    char *response)
258 {
259 #define BYTES_PER_DOT	0x20000
260 	u32 pre_dot_num, now_dot_num;
261 
262 	if (fastboot_data_len == 0 ||
263 	    (fastboot_bytes_received + fastboot_data_len) >
264 	    fastboot_bytes_expected) {
265 		fastboot_fail("Received invalid data length",
266 			      response);
267 		return;
268 	}
269 	/* Download data to fastboot_buf_addr */
270 	memcpy(fastboot_buf_addr + fastboot_bytes_received,
271 	       fastboot_data, fastboot_data_len);
272 
273 	pre_dot_num = fastboot_bytes_received / BYTES_PER_DOT;
274 	fastboot_bytes_received += fastboot_data_len;
275 	now_dot_num = fastboot_bytes_received / BYTES_PER_DOT;
276 
277 	if (pre_dot_num != now_dot_num) {
278 		putc('.');
279 		if (!(now_dot_num % 74))
280 			putc('\n');
281 	}
282 	*response = '\0';
283 }
284 
285 /**
286  * fastboot_data_complete() - Mark current transfer complete
287  *
288  * @response: Pointer to fastboot response buffer
289  *
290  * Set image_size and ${filesize} to the total size of the downloaded image.
291  */
fastboot_data_complete(char * response)292 void fastboot_data_complete(char *response)
293 {
294 	/* Download complete. Respond with "OKAY" */
295 	fastboot_okay(NULL, response);
296 	printf("\ndownloading of %d bytes finished\n", fastboot_bytes_received);
297 	image_size = fastboot_bytes_received;
298 	env_set_hex("filesize", image_size);
299 	fastboot_bytes_expected = 0;
300 	fastboot_bytes_received = 0;
301 }
302 
303 #if CONFIG_IS_ENABLED(FASTBOOT_FLASH)
304 /**
305  * flash() - write the downloaded image to the indicated partition.
306  *
307  * @cmd_parameter: Pointer to partition name
308  * @response: Pointer to fastboot response buffer
309  *
310  * Writes the previously downloaded image to the partition indicated by
311  * cmd_parameter. Writes to response.
312  */
flash(char * cmd_parameter,char * response)313 static void flash(char *cmd_parameter, char *response)
314 {
315 #if CONFIG_IS_ENABLED(FASTBOOT_FLASH_MMC)
316 	fastboot_mmc_flash_write(cmd_parameter, fastboot_buf_addr, image_size,
317 				 response);
318 #endif
319 #if CONFIG_IS_ENABLED(FASTBOOT_FLASH_NAND)
320 	fastboot_nand_flash_write(cmd_parameter, fastboot_buf_addr, image_size,
321 				  response);
322 #endif
323 }
324 
325 /**
326  * erase() - erase the indicated partition.
327  *
328  * @cmd_parameter: Pointer to partition name
329  * @response: Pointer to fastboot response buffer
330  *
331  * Erases the partition indicated by cmd_parameter (clear to 0x00s). Writes
332  * to response.
333  */
erase(char * cmd_parameter,char * response)334 static void erase(char *cmd_parameter, char *response)
335 {
336 #if CONFIG_IS_ENABLED(FASTBOOT_FLASH_MMC)
337 	fastboot_mmc_erase(cmd_parameter, response);
338 #endif
339 #if CONFIG_IS_ENABLED(FASTBOOT_FLASH_NAND)
340 	fastboot_nand_erase(cmd_parameter, response);
341 #endif
342 }
343 #endif
344 
345 #if CONFIG_IS_ENABLED(FASTBOOT_UUU_SUPPORT)
346 /**
347  * run_ucmd() - Execute the UCmd command
348  *
349  * @cmd_parameter: Pointer to command parameter
350  * @response: Pointer to fastboot response buffer
351  */
run_ucmd(char * cmd_parameter,char * response)352 static void run_ucmd(char *cmd_parameter, char *response)
353 {
354 	if (!cmd_parameter) {
355 		pr_err("missing slot suffix\n");
356 		fastboot_fail("missing command", response);
357 		return;
358 	}
359 
360 	if (run_command(cmd_parameter, 0))
361 		fastboot_fail("", response);
362 	else
363 		fastboot_okay(NULL, response);
364 }
365 
366 static char g_a_cmd_buff[64];
367 
fastboot_acmd_complete(void)368 void fastboot_acmd_complete(void)
369 {
370 	run_command(g_a_cmd_buff, 0);
371 }
372 
373 /**
374  * run_acmd() - Execute the ACmd command
375  *
376  * @cmd_parameter: Pointer to command parameter
377  * @response: Pointer to fastboot response buffer
378  */
run_acmd(char * cmd_parameter,char * response)379 static void run_acmd(char *cmd_parameter, char *response)
380 {
381 	if (!cmd_parameter) {
382 		pr_err("missing slot suffix\n");
383 		fastboot_fail("missing command", response);
384 		return;
385 	}
386 
387 	if (strlen(cmd_parameter) > sizeof(g_a_cmd_buff)) {
388 		pr_err("too long command\n");
389 		fastboot_fail("too long command", response);
390 		return;
391 	}
392 
393 	strcpy(g_a_cmd_buff, cmd_parameter);
394 	fastboot_okay(NULL, response);
395 }
396 #endif
397 
398 /**
399  * reboot_bootloader() - Sets reboot bootloader flag.
400  *
401  * @cmd_parameter: Pointer to command parameter
402  * @response: Pointer to fastboot response buffer
403  */
reboot_bootloader(char * cmd_parameter,char * response)404 static void reboot_bootloader(char *cmd_parameter, char *response)
405 {
406 	if (fastboot_set_reboot_flag(FASTBOOT_REBOOT_REASON_BOOTLOADER))
407 		fastboot_fail("Cannot set reboot flag", response);
408 	else
409 		fastboot_okay(NULL, response);
410 }
411 
412 /**
413  * reboot_fastbootd() - Sets reboot fastboot flag.
414  *
415  * @cmd_parameter: Pointer to command parameter
416  * @response: Pointer to fastboot response buffer
417  */
reboot_fastbootd(char * cmd_parameter,char * response)418 static void reboot_fastbootd(char *cmd_parameter, char *response)
419 {
420 	if (fastboot_set_reboot_flag(FASTBOOT_REBOOT_REASON_FASTBOOTD))
421 		fastboot_fail("Cannot set fastboot flag", response);
422 	else
423 		fastboot_okay(NULL, response);
424 }
425 
426 /**
427  * reboot_recovery() - Sets reboot recovery flag.
428  *
429  * @cmd_parameter: Pointer to command parameter
430  * @response: Pointer to fastboot response buffer
431  */
reboot_recovery(char * cmd_parameter,char * response)432 static void reboot_recovery(char *cmd_parameter, char *response)
433 {
434 	if (fastboot_set_reboot_flag(FASTBOOT_REBOOT_REASON_RECOVERY))
435 		fastboot_fail("Cannot set recovery flag", response);
436 	else
437 		fastboot_okay(NULL, response);
438 }
439 
440 #if CONFIG_IS_ENABLED(FASTBOOT_CMD_OEM_FORMAT)
441 /**
442  * oem_format() - Execute the OEM format command
443  *
444  * @cmd_parameter: Pointer to command parameter
445  * @response: Pointer to fastboot response buffer
446  */
oem_format(char * cmd_parameter,char * response)447 static void oem_format(char *cmd_parameter, char *response)
448 {
449 	char cmdbuf[32];
450 
451 	if (!env_get("partitions")) {
452 		fastboot_fail("partitions not set", response);
453 	} else {
454 		sprintf(cmdbuf, "gpt write mmc %x $partitions",
455 			CONFIG_FASTBOOT_FLASH_MMC_DEV);
456 		if (run_command(cmdbuf, 0))
457 			fastboot_fail("", response);
458 		else
459 			fastboot_okay(NULL, response);
460 	}
461 }
462 #endif
463 
464 #if CONFIG_IS_ENABLED(FASTBOOT_CMD_OEM_PARTCONF)
465 /**
466  * oem_partconf() - Execute the OEM partconf command
467  *
468  * @cmd_parameter: Pointer to command parameter
469  * @response: Pointer to fastboot response buffer
470  */
oem_partconf(char * cmd_parameter,char * response)471 static void oem_partconf(char *cmd_parameter, char *response)
472 {
473 	char cmdbuf[32];
474 
475 	if (!cmd_parameter) {
476 		fastboot_fail("Expected command parameter", response);
477 		return;
478 	}
479 
480 	/* execute 'mmc partconfg' command with cmd_parameter arguments*/
481 	snprintf(cmdbuf, sizeof(cmdbuf), "mmc partconf %x %s 0",
482 		 CONFIG_FASTBOOT_FLASH_MMC_DEV, cmd_parameter);
483 	printf("Execute: %s\n", cmdbuf);
484 	if (run_command(cmdbuf, 0))
485 		fastboot_fail("Cannot set oem partconf", response);
486 	else
487 		fastboot_okay(NULL, response);
488 }
489 #endif
490 
491 #if CONFIG_IS_ENABLED(FASTBOOT_CMD_OEM_BOOTBUS)
492 /**
493  * oem_bootbus() - Execute the OEM bootbus command
494  *
495  * @cmd_parameter: Pointer to command parameter
496  * @response: Pointer to fastboot response buffer
497  */
oem_bootbus(char * cmd_parameter,char * response)498 static void oem_bootbus(char *cmd_parameter, char *response)
499 {
500 	char cmdbuf[32];
501 
502 	if (!cmd_parameter) {
503 		fastboot_fail("Expected command parameter", response);
504 		return;
505 	}
506 
507 	/* execute 'mmc bootbus' command with cmd_parameter arguments*/
508 	snprintf(cmdbuf, sizeof(cmdbuf), "mmc bootbus %x %s",
509 		 CONFIG_FASTBOOT_FLASH_MMC_DEV, cmd_parameter);
510 	printf("Execute: %s\n", cmdbuf);
511 	if (run_command(cmdbuf, 0))
512 		fastboot_fail("Cannot set oem bootbus", response);
513 	else
514 		fastboot_okay(NULL, response);
515 }
516 #endif
517