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