Home | History | Annotate | Download | only in fastboot
      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