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