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