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 *);
37 #if CONFIG_IS_ENABLED(FASTBOOT_CMD_OEM_FORMAT)
38 static void oem_format(char *, char *);
39 #endif
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 	},
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
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  */
fastboot_handle_command(char * cmd_string,char * response)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  */
okay(char * cmd_parameter,char * response)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  */
getvar(char * cmd_parameter,char * response)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  */
download(char * cmd_parameter,char * response)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  */
fastboot_data_remaining(void)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  */
fastboot_data_download(const void * fastboot_data,unsigned int fastboot_data_len,char * response)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  */
fastboot_data_complete(char * response)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  */
flash(char * cmd_parameter,char * response)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  */
erase(char * cmd_parameter,char * response)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  */
reboot_bootloader(char * cmd_parameter,char * response)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 }
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  */
oem_format(char * cmd_parameter,char * response)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
336