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