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 */ 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 */ 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 */ 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 */ 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 */ 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 */ 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 */ 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 */ 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 */ 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 */ 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 */ 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