• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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 #if CONFIG_IS_ENABLED(FASTBOOT_FLASH)
35 static void flash(char *, char *);
36 static void erase(char *, char *);
37 #endif
38 static void reboot_bootloader(char *, char *);
39 #if CONFIG_IS_ENABLED(FASTBOOT_CMD_OEM_FORMAT)
40 static void oem_format(char *, char *);
41 #endif
42 
43 static const struct {
44 	const char *command;
45 	void (*dispatch)(char *cmd_parameter, char *response);
46 } commands[FASTBOOT_COMMAND_COUNT] = {
47 	[FASTBOOT_COMMAND_GETVAR] = {
48 		.command = "getvar",
49 		.dispatch = getvar
50 	},
51 	[FASTBOOT_COMMAND_DOWNLOAD] = {
52 		.command = "download",
53 		.dispatch = download
54 	},
55 #if CONFIG_IS_ENABLED(FASTBOOT_FLASH)
56 	[FASTBOOT_COMMAND_FLASH] =  {
57 		.command = "flash",
58 		.dispatch = flash
59 	},
60 	[FASTBOOT_COMMAND_ERASE] =  {
61 		.command = "erase",
62 		.dispatch = erase
63 	},
64 #endif
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_SET_ACTIVE] =  {
82 		.command = "set_active",
83 		.dispatch = okay
84 	},
85 #if CONFIG_IS_ENABLED(FASTBOOT_CMD_OEM_FORMAT)
86 	[FASTBOOT_COMMAND_OEM_FORMAT] = {
87 		.command = "oem format",
88 		.dispatch = oem_format,
89 	},
90 #endif
91 };
92 
93 /**
94  * fastboot_handle_command - Handle fastboot command
95  *
96  * @cmd_string: Pointer to command string
97  * @response: Pointer to fastboot response buffer
98  *
99  * Return: Executed command, or -1 if not recognized
100  */
fastboot_handle_command(char * cmd_string,char * response)101 int fastboot_handle_command(char *cmd_string, char *response)
102 {
103 	int i;
104 	char *cmd_parameter;
105 
106 	cmd_parameter = cmd_string;
107 	strsep(&cmd_parameter, ":");
108 
109 	for (i = 0; i < FASTBOOT_COMMAND_COUNT; i++) {
110 		if (!strcmp(commands[i].command, cmd_string)) {
111 			if (commands[i].dispatch) {
112 				commands[i].dispatch(cmd_parameter,
113 							response);
114 				return i;
115 			} else {
116 				break;
117 			}
118 		}
119 	}
120 
121 	pr_err("command %s not recognized.\n", cmd_string);
122 	fastboot_fail("unrecognized command", response);
123 	return -1;
124 }
125 
126 /**
127  * okay() - Send bare OKAY response
128  *
129  * @cmd_parameter: Pointer to command parameter
130  * @response: Pointer to fastboot response buffer
131  *
132  * Send a bare OKAY fastboot response. This is used where the command is
133  * valid, but all the work is done after the response has been sent (e.g.
134  * boot, reboot etc.)
135  */
okay(char * cmd_parameter,char * response)136 static void okay(char *cmd_parameter, char *response)
137 {
138 	fastboot_okay(NULL, response);
139 }
140 
141 /**
142  * getvar() - Read a config/version variable
143  *
144  * @cmd_parameter: Pointer to command parameter
145  * @response: Pointer to fastboot response buffer
146  */
getvar(char * cmd_parameter,char * response)147 static void getvar(char *cmd_parameter, char *response)
148 {
149 	fastboot_getvar(cmd_parameter, response);
150 }
151 
152 /**
153  * fastboot_download() - Start a download transfer from the client
154  *
155  * @cmd_parameter: Pointer to command parameter
156  * @response: Pointer to fastboot response buffer
157  */
download(char * cmd_parameter,char * response)158 static void download(char *cmd_parameter, char *response)
159 {
160 	char *tmp;
161 
162 	if (!cmd_parameter) {
163 		fastboot_fail("Expected command parameter", response);
164 		return;
165 	}
166 	fastboot_bytes_received = 0;
167 	fastboot_bytes_expected = simple_strtoul(cmd_parameter, &tmp, 16);
168 	if (fastboot_bytes_expected == 0) {
169 		fastboot_fail("Expected nonzero image size", response);
170 		return;
171 	}
172 	/*
173 	 * Nothing to download yet. Response is of the form:
174 	 * [DATA|FAIL]$cmd_parameter
175 	 *
176 	 * where cmd_parameter is an 8 digit hexadecimal number
177 	 */
178 	if (fastboot_bytes_expected > fastboot_buf_size) {
179 		fastboot_fail(cmd_parameter, response);
180 	} else {
181 		printf("Starting download of %d bytes\n",
182 		       fastboot_bytes_expected);
183 		fastboot_response("DATA", response, "%s", cmd_parameter);
184 	}
185 }
186 
187 /**
188  * fastboot_data_remaining() - return bytes remaining in current transfer
189  *
190  * Return: Number of bytes left in the current download
191  */
fastboot_data_remaining(void)192 u32 fastboot_data_remaining(void)
193 {
194 	return fastboot_bytes_expected - fastboot_bytes_received;
195 }
196 
197 /**
198  * fastboot_data_download() - Copy image data to fastboot_buf_addr.
199  *
200  * @fastboot_data: Pointer to received fastboot data
201  * @fastboot_data_len: Length of received fastboot data
202  * @response: Pointer to fastboot response buffer
203  *
204  * Copies image data from fastboot_data to fastboot_buf_addr. Writes to
205  * response. fastboot_bytes_received is updated to indicate the number
206  * of bytes that have been transferred.
207  *
208  * On completion sets image_size and ${filesize} to the total size of the
209  * downloaded image.
210  */
fastboot_data_download(const void * fastboot_data,unsigned int fastboot_data_len,char * response)211 void fastboot_data_download(const void *fastboot_data,
212 			    unsigned int fastboot_data_len,
213 			    char *response)
214 {
215 #define BYTES_PER_DOT	0x20000
216 	u32 pre_dot_num, now_dot_num;
217 
218 	if (fastboot_data_len == 0 ||
219 	    (fastboot_bytes_received + fastboot_data_len) >
220 	    fastboot_bytes_expected) {
221 		fastboot_fail("Received invalid data length",
222 			      response);
223 		return;
224 	}
225 	/* Download data to fastboot_buf_addr */
226 	memcpy(fastboot_buf_addr + fastboot_bytes_received,
227 	       fastboot_data, fastboot_data_len);
228 
229 	pre_dot_num = fastboot_bytes_received / BYTES_PER_DOT;
230 	fastboot_bytes_received += fastboot_data_len;
231 	now_dot_num = fastboot_bytes_received / BYTES_PER_DOT;
232 
233 	if (pre_dot_num != now_dot_num) {
234 		putc('.');
235 		if (!(now_dot_num % 74))
236 			putc('\n');
237 	}
238 	*response = '\0';
239 }
240 
241 /**
242  * fastboot_data_complete() - Mark current transfer complete
243  *
244  * @response: Pointer to fastboot response buffer
245  *
246  * Set image_size and ${filesize} to the total size of the downloaded image.
247  */
fastboot_data_complete(char * response)248 void fastboot_data_complete(char *response)
249 {
250 	/* Download complete. Respond with "OKAY" */
251 	fastboot_okay(NULL, response);
252 	printf("\ndownloading of %d bytes finished\n", fastboot_bytes_received);
253 	image_size = fastboot_bytes_received;
254 	env_set_hex("filesize", image_size);
255 	fastboot_bytes_expected = 0;
256 	fastboot_bytes_received = 0;
257 }
258 
259 #if CONFIG_IS_ENABLED(FASTBOOT_FLASH)
260 /**
261  * flash() - write the downloaded image to the indicated partition.
262  *
263  * @cmd_parameter: Pointer to partition name
264  * @response: Pointer to fastboot response buffer
265  *
266  * Writes the previously downloaded image to the partition indicated by
267  * cmd_parameter. Writes to response.
268  */
flash(char * cmd_parameter,char * response)269 static void flash(char *cmd_parameter, char *response)
270 {
271 #if CONFIG_IS_ENABLED(FASTBOOT_FLASH_MMC)
272 	fastboot_mmc_flash_write(cmd_parameter, fastboot_buf_addr, image_size,
273 				 response);
274 #endif
275 #if CONFIG_IS_ENABLED(FASTBOOT_FLASH_NAND)
276 	fastboot_nand_flash_write(cmd_parameter, fastboot_buf_addr, image_size,
277 				  response);
278 #endif
279 }
280 
281 /**
282  * erase() - erase the indicated partition.
283  *
284  * @cmd_parameter: Pointer to partition name
285  * @response: Pointer to fastboot response buffer
286  *
287  * Erases the partition indicated by cmd_parameter (clear to 0x00s). Writes
288  * to response.
289  */
erase(char * cmd_parameter,char * response)290 static void erase(char *cmd_parameter, char *response)
291 {
292 #if CONFIG_IS_ENABLED(FASTBOOT_FLASH_MMC)
293 	fastboot_mmc_erase(cmd_parameter, response);
294 #endif
295 #if CONFIG_IS_ENABLED(FASTBOOT_FLASH_NAND)
296 	fastboot_nand_erase(cmd_parameter, response);
297 #endif
298 }
299 #endif
300 
301 /**
302  * reboot_bootloader() - Sets reboot bootloader flag.
303  *
304  * @cmd_parameter: Pointer to command parameter
305  * @response: Pointer to fastboot response buffer
306  */
reboot_bootloader(char * cmd_parameter,char * response)307 static void reboot_bootloader(char *cmd_parameter, char *response)
308 {
309 	if (fastboot_set_reboot_flag())
310 		fastboot_fail("Cannot set reboot flag", response);
311 	else
312 		fastboot_okay(NULL, response);
313 }
314 
315 #if CONFIG_IS_ENABLED(FASTBOOT_CMD_OEM_FORMAT)
316 /**
317  * oem_format() - Execute the OEM format command
318  *
319  * @cmd_parameter: Pointer to command parameter
320  * @response: Pointer to fastboot response buffer
321  */
oem_format(char * cmd_parameter,char * response)322 static void oem_format(char *cmd_parameter, char *response)
323 {
324 	char cmdbuf[32];
325 
326 	if (!env_get("partitions")) {
327 		fastboot_fail("partitions not set", response);
328 	} else {
329 		sprintf(cmdbuf, "gpt write mmc %x $partitions",
330 			CONFIG_FASTBOOT_FLASH_MMC_DEV);
331 		if (run_command(cmdbuf, 0))
332 			fastboot_fail("", response);
333 		else
334 			fastboot_okay(NULL, response);
335 	}
336 }
337 #endif
338