336 lines
		
	
	
		
			8.4 KiB
		
	
	
	
		
			C
		
	
	
	
			
		
		
	
	
			336 lines
		
	
	
		
			8.4 KiB
		
	
	
	
		
			C
		
	
	
	
// SPDX-License-Identifier: BSD-2-Clause
 | 
						|
/*
 | 
						|
 * Copyright (C) 2016 The Android Open Source Project
 | 
						|
 */
 | 
						|
 | 
						|
#include <common.h>
 | 
						|
#include <fastboot.h>
 | 
						|
#include <fastboot-internal.h>
 | 
						|
#include <fb_mmc.h>
 | 
						|
#include <fb_nand.h>
 | 
						|
#include <part.h>
 | 
						|
#include <stdlib.h>
 | 
						|
 | 
						|
/**
 | 
						|
 * image_size - final fastboot image size
 | 
						|
 */
 | 
						|
static u32 image_size;
 | 
						|
 | 
						|
/**
 | 
						|
 * fastboot_bytes_received - number of bytes received in the current download
 | 
						|
 */
 | 
						|
static u32 fastboot_bytes_received;
 | 
						|
 | 
						|
/**
 | 
						|
 * fastboot_bytes_expected - number of bytes expected in the current download
 | 
						|
 */
 | 
						|
static u32 fastboot_bytes_expected;
 | 
						|
 | 
						|
static void okay(char *, char *);
 | 
						|
static void getvar(char *, char *);
 | 
						|
static void download(char *, char *);
 | 
						|
#if CONFIG_IS_ENABLED(FASTBOOT_FLASH)
 | 
						|
static void flash(char *, char *);
 | 
						|
static void erase(char *, char *);
 | 
						|
#endif
 | 
						|
static void reboot_bootloader(char *, char *);
 | 
						|
#if CONFIG_IS_ENABLED(FASTBOOT_CMD_OEM_FORMAT)
 | 
						|
static void oem_format(char *, char *);
 | 
						|
#endif
 | 
						|
 | 
						|
static const struct {
 | 
						|
	const char *command;
 | 
						|
	void (*dispatch)(char *cmd_parameter, char *response);
 | 
						|
} commands[FASTBOOT_COMMAND_COUNT] = {
 | 
						|
	[FASTBOOT_COMMAND_GETVAR] = {
 | 
						|
		.command = "getvar",
 | 
						|
		.dispatch = getvar
 | 
						|
	},
 | 
						|
	[FASTBOOT_COMMAND_DOWNLOAD] = {
 | 
						|
		.command = "download",
 | 
						|
		.dispatch = download
 | 
						|
	},
 | 
						|
#if CONFIG_IS_ENABLED(FASTBOOT_FLASH)
 | 
						|
	[FASTBOOT_COMMAND_FLASH] =  {
 | 
						|
		.command = "flash",
 | 
						|
		.dispatch = flash
 | 
						|
	},
 | 
						|
	[FASTBOOT_COMMAND_ERASE] =  {
 | 
						|
		.command = "erase",
 | 
						|
		.dispatch = erase
 | 
						|
	},
 | 
						|
#endif
 | 
						|
	[FASTBOOT_COMMAND_BOOT] =  {
 | 
						|
		.command = "boot",
 | 
						|
		.dispatch = okay
 | 
						|
	},
 | 
						|
	[FASTBOOT_COMMAND_CONTINUE] =  {
 | 
						|
		.command = "continue",
 | 
						|
		.dispatch = okay
 | 
						|
	},
 | 
						|
	[FASTBOOT_COMMAND_REBOOT] =  {
 | 
						|
		.command = "reboot",
 | 
						|
		.dispatch = okay
 | 
						|
	},
 | 
						|
	[FASTBOOT_COMMAND_REBOOT_BOOTLOADER] =  {
 | 
						|
		.command = "reboot-bootloader",
 | 
						|
		.dispatch = reboot_bootloader
 | 
						|
	},
 | 
						|
	[FASTBOOT_COMMAND_SET_ACTIVE] =  {
 | 
						|
		.command = "set_active",
 | 
						|
		.dispatch = okay
 | 
						|
	},
 | 
						|
#if CONFIG_IS_ENABLED(FASTBOOT_CMD_OEM_FORMAT)
 | 
						|
	[FASTBOOT_COMMAND_OEM_FORMAT] = {
 | 
						|
		.command = "oem format",
 | 
						|
		.dispatch = oem_format,
 | 
						|
	},
 | 
						|
#endif
 | 
						|
};
 | 
						|
 | 
						|
/**
 | 
						|
 * fastboot_handle_command - Handle fastboot command
 | 
						|
 *
 | 
						|
 * @cmd_string: Pointer to command string
 | 
						|
 * @response: Pointer to fastboot response buffer
 | 
						|
 *
 | 
						|
 * Return: Executed command, or -1 if not recognized
 | 
						|
 */
 | 
						|
int fastboot_handle_command(char *cmd_string, char *response)
 | 
						|
{
 | 
						|
	int i;
 | 
						|
	char *cmd_parameter;
 | 
						|
 | 
						|
	cmd_parameter = cmd_string;
 | 
						|
	strsep(&cmd_parameter, ":");
 | 
						|
 | 
						|
	for (i = 0; i < FASTBOOT_COMMAND_COUNT; i++) {
 | 
						|
		if (!strcmp(commands[i].command, cmd_string)) {
 | 
						|
			if (commands[i].dispatch) {
 | 
						|
				commands[i].dispatch(cmd_parameter,
 | 
						|
							response);
 | 
						|
				return i;
 | 
						|
			} else {
 | 
						|
				break;
 | 
						|
			}
 | 
						|
		}
 | 
						|
	}
 | 
						|
 | 
						|
	pr_err("command %s not recognized.\n", cmd_string);
 | 
						|
	fastboot_fail("unrecognized command", response);
 | 
						|
	return -1;
 | 
						|
}
 | 
						|
 | 
						|
/**
 | 
						|
 * okay() - Send bare OKAY response
 | 
						|
 *
 | 
						|
 * @cmd_parameter: Pointer to command parameter
 | 
						|
 * @response: Pointer to fastboot response buffer
 | 
						|
 *
 | 
						|
 * Send a bare OKAY fastboot response. This is used where the command is
 | 
						|
 * valid, but all the work is done after the response has been sent (e.g.
 | 
						|
 * boot, reboot etc.)
 | 
						|
 */
 | 
						|
static void okay(char *cmd_parameter, char *response)
 | 
						|
{
 | 
						|
	fastboot_okay(NULL, response);
 | 
						|
}
 | 
						|
 | 
						|
/**
 | 
						|
 * getvar() - Read a config/version variable
 | 
						|
 *
 | 
						|
 * @cmd_parameter: Pointer to command parameter
 | 
						|
 * @response: Pointer to fastboot response buffer
 | 
						|
 */
 | 
						|
static void getvar(char *cmd_parameter, char *response)
 | 
						|
{
 | 
						|
	fastboot_getvar(cmd_parameter, response);
 | 
						|
}
 | 
						|
 | 
						|
/**
 | 
						|
 * fastboot_download() - Start a download transfer from the client
 | 
						|
 *
 | 
						|
 * @cmd_parameter: Pointer to command parameter
 | 
						|
 * @response: Pointer to fastboot response buffer
 | 
						|
 */
 | 
						|
static void download(char *cmd_parameter, char *response)
 | 
						|
{
 | 
						|
	char *tmp;
 | 
						|
 | 
						|
	if (!cmd_parameter) {
 | 
						|
		fastboot_fail("Expected command parameter", response);
 | 
						|
		return;
 | 
						|
	}
 | 
						|
	fastboot_bytes_received = 0;
 | 
						|
	fastboot_bytes_expected = simple_strtoul(cmd_parameter, &tmp, 16);
 | 
						|
	if (fastboot_bytes_expected == 0) {
 | 
						|
		fastboot_fail("Expected nonzero image size", response);
 | 
						|
		return;
 | 
						|
	}
 | 
						|
	/*
 | 
						|
	 * Nothing to download yet. Response is of the form:
 | 
						|
	 * [DATA|FAIL]$cmd_parameter
 | 
						|
	 *
 | 
						|
	 * where cmd_parameter is an 8 digit hexadecimal number
 | 
						|
	 */
 | 
						|
	if (fastboot_bytes_expected > fastboot_buf_size) {
 | 
						|
		fastboot_fail(cmd_parameter, response);
 | 
						|
	} else {
 | 
						|
		printf("Starting download of %d bytes\n",
 | 
						|
		       fastboot_bytes_expected);
 | 
						|
		fastboot_response("DATA", response, "%s", cmd_parameter);
 | 
						|
	}
 | 
						|
}
 | 
						|
 | 
						|
/**
 | 
						|
 * fastboot_data_remaining() - return bytes remaining in current transfer
 | 
						|
 *
 | 
						|
 * Return: Number of bytes left in the current download
 | 
						|
 */
 | 
						|
u32 fastboot_data_remaining(void)
 | 
						|
{
 | 
						|
	return fastboot_bytes_expected - fastboot_bytes_received;
 | 
						|
}
 | 
						|
 | 
						|
/**
 | 
						|
 * fastboot_data_download() - Copy image data to fastboot_buf_addr.
 | 
						|
 *
 | 
						|
 * @fastboot_data: Pointer to received fastboot data
 | 
						|
 * @fastboot_data_len: Length of received fastboot data
 | 
						|
 * @response: Pointer to fastboot response buffer
 | 
						|
 *
 | 
						|
 * Copies image data from fastboot_data to fastboot_buf_addr. Writes to
 | 
						|
 * response. fastboot_bytes_received is updated to indicate the number
 | 
						|
 * of bytes that have been transferred.
 | 
						|
 *
 | 
						|
 * On completion sets image_size and ${filesize} to the total size of the
 | 
						|
 * downloaded image.
 | 
						|
 */
 | 
						|
void fastboot_data_download(const void *fastboot_data,
 | 
						|
			    unsigned int fastboot_data_len,
 | 
						|
			    char *response)
 | 
						|
{
 | 
						|
#define BYTES_PER_DOT	0x20000
 | 
						|
	u32 pre_dot_num, now_dot_num;
 | 
						|
 | 
						|
	if (fastboot_data_len == 0 ||
 | 
						|
	    (fastboot_bytes_received + fastboot_data_len) >
 | 
						|
	    fastboot_bytes_expected) {
 | 
						|
		fastboot_fail("Received invalid data length",
 | 
						|
			      response);
 | 
						|
		return;
 | 
						|
	}
 | 
						|
	/* Download data to fastboot_buf_addr */
 | 
						|
	memcpy(fastboot_buf_addr + fastboot_bytes_received,
 | 
						|
	       fastboot_data, fastboot_data_len);
 | 
						|
 | 
						|
	pre_dot_num = fastboot_bytes_received / BYTES_PER_DOT;
 | 
						|
	fastboot_bytes_received += fastboot_data_len;
 | 
						|
	now_dot_num = fastboot_bytes_received / BYTES_PER_DOT;
 | 
						|
 | 
						|
	if (pre_dot_num != now_dot_num) {
 | 
						|
		putc('.');
 | 
						|
		if (!(now_dot_num % 74))
 | 
						|
			putc('\n');
 | 
						|
	}
 | 
						|
	*response = '\0';
 | 
						|
}
 | 
						|
 | 
						|
/**
 | 
						|
 * fastboot_data_complete() - Mark current transfer complete
 | 
						|
 *
 | 
						|
 * @response: Pointer to fastboot response buffer
 | 
						|
 *
 | 
						|
 * Set image_size and ${filesize} to the total size of the downloaded image.
 | 
						|
 */
 | 
						|
void fastboot_data_complete(char *response)
 | 
						|
{
 | 
						|
	/* Download complete. Respond with "OKAY" */
 | 
						|
	fastboot_okay(NULL, response);
 | 
						|
	printf("\ndownloading of %d bytes finished\n", fastboot_bytes_received);
 | 
						|
	image_size = fastboot_bytes_received;
 | 
						|
	env_set_hex("filesize", image_size);
 | 
						|
	fastboot_bytes_expected = 0;
 | 
						|
	fastboot_bytes_received = 0;
 | 
						|
}
 | 
						|
 | 
						|
#if CONFIG_IS_ENABLED(FASTBOOT_FLASH)
 | 
						|
/**
 | 
						|
 * flash() - write the downloaded image to the indicated partition.
 | 
						|
 *
 | 
						|
 * @cmd_parameter: Pointer to partition name
 | 
						|
 * @response: Pointer to fastboot response buffer
 | 
						|
 *
 | 
						|
 * Writes the previously downloaded image to the partition indicated by
 | 
						|
 * cmd_parameter. Writes to response.
 | 
						|
 */
 | 
						|
static void flash(char *cmd_parameter, char *response)
 | 
						|
{
 | 
						|
#if CONFIG_IS_ENABLED(FASTBOOT_FLASH_MMC)
 | 
						|
	fastboot_mmc_flash_write(cmd_parameter, fastboot_buf_addr, image_size,
 | 
						|
				 response);
 | 
						|
#endif
 | 
						|
#if CONFIG_IS_ENABLED(FASTBOOT_FLASH_NAND)
 | 
						|
	fastboot_nand_flash_write(cmd_parameter, fastboot_buf_addr, image_size,
 | 
						|
				  response);
 | 
						|
#endif
 | 
						|
}
 | 
						|
 | 
						|
/**
 | 
						|
 * erase() - erase the indicated partition.
 | 
						|
 *
 | 
						|
 * @cmd_parameter: Pointer to partition name
 | 
						|
 * @response: Pointer to fastboot response buffer
 | 
						|
 *
 | 
						|
 * Erases the partition indicated by cmd_parameter (clear to 0x00s). Writes
 | 
						|
 * to response.
 | 
						|
 */
 | 
						|
static void erase(char *cmd_parameter, char *response)
 | 
						|
{
 | 
						|
#if CONFIG_IS_ENABLED(FASTBOOT_FLASH_MMC)
 | 
						|
	fastboot_mmc_erase(cmd_parameter, response);
 | 
						|
#endif
 | 
						|
#if CONFIG_IS_ENABLED(FASTBOOT_FLASH_NAND)
 | 
						|
	fastboot_nand_erase(cmd_parameter, response);
 | 
						|
#endif
 | 
						|
}
 | 
						|
#endif
 | 
						|
 | 
						|
/**
 | 
						|
 * reboot_bootloader() - Sets reboot bootloader flag.
 | 
						|
 *
 | 
						|
 * @cmd_parameter: Pointer to command parameter
 | 
						|
 * @response: Pointer to fastboot response buffer
 | 
						|
 */
 | 
						|
static void reboot_bootloader(char *cmd_parameter, char *response)
 | 
						|
{
 | 
						|
	if (fastboot_set_reboot_flag())
 | 
						|
		fastboot_fail("Cannot set reboot flag", response);
 | 
						|
	else
 | 
						|
		fastboot_okay(NULL, response);
 | 
						|
}
 | 
						|
 | 
						|
#if CONFIG_IS_ENABLED(FASTBOOT_CMD_OEM_FORMAT)
 | 
						|
/**
 | 
						|
 * oem_format() - Execute the OEM format command
 | 
						|
 *
 | 
						|
 * @cmd_parameter: Pointer to command parameter
 | 
						|
 * @response: Pointer to fastboot response buffer
 | 
						|
 */
 | 
						|
static void oem_format(char *cmd_parameter, char *response)
 | 
						|
{
 | 
						|
	char cmdbuf[32];
 | 
						|
 | 
						|
	if (!env_get("partitions")) {
 | 
						|
		fastboot_fail("partitions not set", response);
 | 
						|
	} else {
 | 
						|
		sprintf(cmdbuf, "gpt write mmc %x $partitions",
 | 
						|
			CONFIG_FASTBOOT_FLASH_MMC_DEV);
 | 
						|
		if (run_command(cmdbuf, 0))
 | 
						|
			fastboot_fail("", response);
 | 
						|
		else
 | 
						|
			fastboot_okay(NULL, response);
 | 
						|
	}
 | 
						|
}
 | 
						|
#endif
 |