blob: 6a5c16e93f01f99c160499d3c70a6e6aa91d5766 [file] [log] [blame]
// SPDX-License-Identifier: GPL-2.0+
/*
* Copyright 2019 NXP
*/
#include <asm/mach-imx/sys_proto.h>
#include <fb_fsl.h>
#include <fastboot.h>
#include <fastboot-internal.h>
#include <mmc.h>
#include <android_image.h>
#include <asm/bootm.h>
#include <nand.h>
#include <part.h>
#include <sparse_format.h>
#include <image-sparse.h>
#include <image.h>
#include <asm/mach-imx/boot_mode.h>
#include <asm/arch/sys_proto.h>
#include <asm/setup.h>
#include <environment.h>
#ifdef CONFIG_ANDROID_RECOVERY
#include <recovery.h>
#endif
#ifdef CONFIG_BCB_SUPPORT
#include "bcb.h"
#endif
#ifdef CONFIG_AVB_SUPPORT
#include <dt_table.h>
#include <fsl_avb.h>
#endif
#ifdef CONFIG_ANDROID_THINGS_SUPPORT
#include <asm-generic/gpio.h>
#include <asm/mach-imx/gpio.h>
#include "../lib/avb/fsl/fsl_avbkey.h"
#include "../arch/arm/include/asm/mach-imx/hab.h"
#endif
#if defined(CONFIG_FASTBOOT_LOCK)
#include "fastboot_lock_unlock.h"
#endif
#ifdef CONFIG_IMX_TRUSTY_OS
#include "u-boot/sha256.h"
#include <trusty/libtipc.h>
#endif
#define EP_BUFFER_SIZE 4096
/**
* 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;
#if defined(CONFIG_AVB_SUPPORT) && defined(CONFIG_MMC)
static AvbABOps fsl_avb_ab_ops = {
.read_ab_metadata = fsl_read_ab_metadata,
.write_ab_metadata = fsl_write_ab_metadata,
.ops = NULL
};
#ifdef CONFIG_AVB_ATX
static AvbAtxOps fsl_avb_atx_ops = {
.ops = NULL,
.read_permanent_attributes = fsl_read_permanent_attributes,
.read_permanent_attributes_hash = fsl_read_permanent_attributes_hash,
#ifdef CONFIG_IMX_TRUSTY_OS
.set_key_version = fsl_write_rollback_index_rpmb,
#else
.set_key_version = fsl_set_key_version,
#endif
.get_random = fsl_get_random
};
#endif
static AvbOps fsl_avb_ops = {
.ab_ops = &fsl_avb_ab_ops,
#ifdef CONFIG_AVB_ATX
.atx_ops = &fsl_avb_atx_ops,
#endif
.read_from_partition = fsl_read_from_partition_multi,
.write_to_partition = fsl_write_to_partition,
#ifdef CONFIG_AVB_ATX
.validate_vbmeta_public_key = avb_atx_validate_vbmeta_public_key,
#else
.validate_vbmeta_public_key = fsl_validate_vbmeta_public_key_rpmb,
#endif
.read_rollback_index = fsl_read_rollback_index_rpmb,
.write_rollback_index = fsl_write_rollback_index_rpmb,
.read_is_device_unlocked = fsl_read_is_device_unlocked,
.get_unique_guid_for_partition = fsl_get_unique_guid_for_partition,
.get_size_of_partition = fsl_get_size_of_partition
};
#endif
/* Write the bcb with fastboot bootloader commands */
static void enable_fastboot_command(void)
{
#ifdef CONFIG_BCB_SUPPORT
char fastboot_command[32] = {0};
strncpy(fastboot_command, FASTBOOT_BCB_CMD, 31);
bcb_write_command(fastboot_command);
#endif
}
/* Get the Boot mode from BCB cmd or Key pressed */
static FbBootMode fastboot_get_bootmode(void)
{
int boot_mode = BOOTMODE_NORMAL;
#ifdef CONFIG_ANDROID_RECOVERY
if(is_recovery_key_pressing()) {
boot_mode = BOOTMODE_RECOVERY_KEY_PRESSED;
return boot_mode;
}
#endif
#ifdef CONFIG_BCB_SUPPORT
int ret = 0;
char command[32];
ret = bcb_read_command(command);
if (ret < 0) {
printf("read command failed\n");
return boot_mode;
}
if (!strcmp(command, FASTBOOT_BCB_CMD)) {
boot_mode = BOOTMODE_FASTBOOT_BCB_CMD;
}
#ifdef CONFIG_ANDROID_RECOVERY
else if (!strcmp(command, RECOVERY_BCB_CMD)) {
boot_mode = BOOTMODE_RECOVERY_BCB_CMD;
}
#endif
/* Clean the mode once its read out,
no matter what in the mode string */
memset(command, 0, 32);
bcb_write_command(command);
#endif
return boot_mode;
}
/* export to lib_arm/board.c */
void fastboot_run_bootmode(void)
{
FbBootMode boot_mode = fastboot_get_bootmode();
switch(boot_mode){
case BOOTMODE_FASTBOOT_BCB_CMD:
/* Make the boot into fastboot mode*/
puts("Fastboot: Got bootloader commands!\n");
run_command("fastboot 0", 0);
break;
#ifdef CONFIG_ANDROID_RECOVERY
case BOOTMODE_RECOVERY_BCB_CMD:
case BOOTMODE_RECOVERY_KEY_PRESSED:
/* Make the boot into recovery mode */
puts("Fastboot: Got Recovery key pressing or recovery commands!\n");
board_recovery_setup();
break;
#endif
default:
/* skip special mode boot*/
puts("Fastboot: Normal\n");
break;
}
}
/**
* 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);
}
/**
* 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)
{
enable_fastboot_command();
if (fastboot_set_reboot_flag())
fastboot_fail("Cannot set reboot flag", response);
else
fastboot_okay(NULL, response);
}
static void upload(char *cmd_parameter, char *response)
{
if (!fastboot_bytes_received || fastboot_bytes_received > (EP_BUFFER_SIZE * 32)) {
fastboot_fail("", response);
return;
}
printf("Will upload %d bytes.\n", fastboot_bytes_received);
snprintf(response, FASTBOOT_RESPONSE_LEN, "DATA%08x", fastboot_bytes_received);
fastboot_tx_write_more(response);
fastboot_tx_write((const char *)(fastboot_buf_addr), fastboot_bytes_received);
snprintf(response,FASTBOOT_RESPONSE_LEN, "OKAY");
fastboot_tx_write_more(response);
fastboot_none_resp(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)
{
if (fastboot_bytes_received >= fastboot_bytes_expected)
return 0;
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);
env_set_hex("filesize", fastboot_bytes_received);
env_set_hex("fastboot_bytes", fastboot_bytes_received);
fastboot_bytes_expected = 0;
}
#if defined(CONFIG_FASTBOOT_LOCK)
static int partition_table_valid(void)
{
int status, mmc_no;
struct blk_desc *dev_desc;
#if defined(CONFIG_IMX_TRUSTY_OS) && !defined(CONFIG_ARM64)
/* Prevent other partition accessing when no TOS flashed. */
if (!tos_flashed)
return 0;
#endif
disk_partition_t info;
mmc_no = fastboot_devinfo.dev_id;
dev_desc = blk_get_dev("mmc", mmc_no);
if (dev_desc)
status = part_get_info(dev_desc, 1, &info);
else
status = -1;
return (status == 0);
}
static void wipe_all_userdata(void)
{
char response[FASTBOOT_RESPONSE_LEN];
/* Erase all user data */
printf("Start userdata wipe process....\n");
/* Erase /data partition */
fastboot_wipe_data_partition();
#if defined (CONFIG_ANDROID_SUPPORT) || defined (CONFIG_ANDROID_AUTO_SUPPORT)
/* Erase the misc partition. */
process_erase_mmc(FASTBOOT_PARTITION_MISC, response);
#endif
#ifndef CONFIG_ANDROID_AB_SUPPORT
/* Erase the cache partition for legacy imx6/7 */
process_erase_mmc(FASTBOOT_PARTITION_CACHE, response);
#endif
/* The unlock permissive flag is set by user and should be wiped here. */
set_fastboot_lock_disable();
#if defined(AVB_RPMB) && !defined(CONFIG_IMX_TRUSTY_OS)
printf("Start stored_rollback_index wipe process....\n");
rbkidx_erase();
printf("Wipe stored_rollback_index completed.\n");
#endif
printf("Wipe userdata completed.\n");
}
static FbLockState do_fastboot_unlock(bool force)
{
int status;
if (fastboot_get_lock_stat() == FASTBOOT_UNLOCK) {
printf("The device is already unlocked\n");
return FASTBOOT_UNLOCK;
}
if ((fastboot_lock_enable() == FASTBOOT_UL_ENABLE) || force) {
printf("It is able to unlock device. %d\n",fastboot_lock_enable());
status = fastboot_set_lock_stat(FASTBOOT_UNLOCK);
if (status < 0)
return FASTBOOT_LOCK_ERROR;
wipe_all_userdata();
} else {
printf("It is not able to unlock device.");
return FASTBOOT_LOCK_ERROR;
}
return FASTBOOT_UNLOCK;
}
static FbLockState do_fastboot_lock(void)
{
int status;
if (fastboot_get_lock_stat() == FASTBOOT_LOCK) {
printf("The device is already locked\n");
return FASTBOOT_LOCK;
}
status = fastboot_set_lock_stat(FASTBOOT_LOCK);
if (status < 0)
return FASTBOOT_LOCK_ERROR;
wipe_all_userdata();
return FASTBOOT_LOCK;
}
static bool endswith(char* s, char* subs) {
if (!s || !subs)
return false;
uint32_t len = strlen(s);
uint32_t sublen = strlen(subs);
if (len < sublen) {
return false;
}
if (strncmp(s + len - sublen, subs, sublen)) {
return false;
}
return true;
}
static void flashing(char *cmd, char *response)
{
FbLockState status;
FbLockEnableResult result;
if (endswith(cmd, "lock_critical")) {
strcpy(response, "OKAY");
}
#ifdef CONFIG_AVB_ATX
else if (endswith(cmd, FASTBOOT_AVB_AT_PERM_ATTR)) {
if (avb_atx_fuse_perm_attr(fastboot_buf_addr, fastboot_bytes_received))
strcpy(response, "FAILInternal error!");
else
strcpy(response, "OKAY");
} else if (endswith(cmd, FASTBOOT_AT_GET_UNLOCK_CHALLENGE)) {
if (avb_atx_get_unlock_challenge(fsl_avb_ops.atx_ops,
fastboot_buf_addr, &fastboot_bytes_received))
strcpy(response, "FAILInternal error!");
else
strcpy(response, "OKAY");
} else if (endswith(cmd, FASTBOOT_AT_UNLOCK_VBOOT)) {
if (at_unlock_vboot_is_disabled()) {
printf("unlock vboot already disabled, can't unlock the device!\n");
strcpy(response, "FAILunlock vboot already disabled!.");
} else {
#ifdef CONFIG_AT_AUTHENTICATE_UNLOCK
if (avb_atx_verify_unlock_credential(fsl_avb_ops.atx_ops,
fastboot_buf_addr))
strcpy(response, "FAILIncorrect unlock credential!");
else {
#endif
status = do_fastboot_unlock(true);
if (status != FASTBOOT_LOCK_ERROR)
strcpy(response, "OKAY");
else
strcpy(response, "FAILunlock device failed.");
#ifdef CONFIG_AT_AUTHENTICATE_UNLOCK
}
#endif
}
} else if (endswith(cmd, FASTBOOT_AT_LOCK_VBOOT)) {
if (perm_attr_are_fused()) {
status = do_fastboot_lock();
if (status != FASTBOOT_LOCK_ERROR)
strcpy(response, "OKAY");
else
strcpy(response, "FAILlock device failed.");
} else
strcpy(response, "FAILpermanent attributes not fused!");
} else if (endswith(cmd, FASTBOOT_AT_DISABLE_UNLOCK_VBOOT)) {
/* This command can only be called after 'oem at-lock-vboot' */
status = fastboot_get_lock_stat();
if (status == FASTBOOT_LOCK) {
if (at_unlock_vboot_is_disabled()) {
printf("unlock vboot already disabled!\n");
strcpy(response, "OKAY");
}
else {
if (!at_disable_vboot_unlock())
strcpy(response, "OKAY");
else
strcpy(response, "FAILdisable unlock vboot fail!");
}
} else
strcpy(response, "FAILplease lock the device first!");
}
#endif /* CONFIG_AVB_ATX */
#ifdef CONFIG_ANDROID_THINGS_SUPPORT
else if (endswith(cmd, FASTBOOT_BOOTLOADER_VBOOT_KEY)) {
strcpy(response, "OKAY");
}
#endif /* CONFIG_ANDROID_THINGS_SUPPORT */
#ifdef CONFIG_IMX_TRUSTY_OS
else if (endswith(cmd, FASTBOOT_GET_CA_REQ)) {
uint8_t *ca_output;
uint32_t ca_length, cp_length;
if (trusty_atap_get_ca_request(fastboot_buf_addr, fastboot_bytes_received,
&(ca_output), &ca_length)) {
printf("ERROR get_ca_request failed!\n");
strcpy(response, "FAILInternal error!");
} else {
cp_length = min((uint32_t)CONFIG_FASTBOOT_BUF_SIZE, ca_length);
memcpy(fastboot_buf_addr, ca_output, cp_length);
fastboot_bytes_received = ca_length;
strcpy(response, "OKAY");
}
} else if (endswith(cmd, FASTBOOT_SET_CA_RESP)) {
if (trusty_atap_set_ca_response(fastboot_buf_addr, fastboot_bytes_received)) {
printf("ERROR set_ca_response failed!\n");
strcpy(response, "FAILInternal error!");
} else
strcpy(response, "OKAY");
} else if (endswith(cmd, FASTBOOT_SET_RSA_ATTESTATION_KEY)) {
if (trusty_set_attestation_key(fastboot_buf_addr,
fastboot_bytes_received,
KM_ALGORITHM_RSA)) {
printf("ERROR set rsa attestation key failed!\n");
strcpy(response, "FAILInternal error!");
} else {
printf("Set rsa attestation key successfully!\n");
strcpy(response, "OKAY");
}
} else if (endswith(cmd, FASTBOOT_SET_EC_ATTESTATION_KEY)) {
if (trusty_set_attestation_key(fastboot_buf_addr,
fastboot_bytes_received,
KM_ALGORITHM_EC)) {
printf("ERROR set ec attestation key failed!\n");
strcpy(response, "FAILInternal error!");
} else {
printf("Set ec attestation key successfully!\n");
strcpy(response, "OKAY");
}
} else if (endswith(cmd, FASTBOOT_APPEND_RSA_ATTESTATION_CERT)) {
if (trusty_append_attestation_cert_chain(fastboot_buf_addr,
fastboot_bytes_received,
KM_ALGORITHM_RSA)) {
printf("ERROR append rsa attestation cert chain failed!\n");
strcpy(response, "FAILInternal error!");
} else {
printf("Append rsa attestation key successfully!\n");
strcpy(response, "OKAY");
}
} else if (endswith(cmd, FASTBOOT_APPEND_EC_ATTESTATION_CERT)) {
if (trusty_append_attestation_cert_chain(fastboot_buf_addr,
fastboot_bytes_received,
KM_ALGORITHM_EC)) {
printf("ERROR append ec attestation cert chain failed!\n");
strcpy(response, "FAILInternal error!");
} else {
printf("Append ec attestation key successfully!\n");
strcpy(response, "OKAY");
}
}
#ifndef CONFIG_AVB_ATX
else if (endswith(cmd, FASTBOOT_SET_RPMB_KEY)) {
if (fastboot_set_rpmb_key(fastboot_buf_addr, fastboot_bytes_received)) {
printf("ERROR set rpmb key failed!\n");
strcpy(response, "FAILset rpmb key failed!");
} else
strcpy(response, "OKAY");
} else if (endswith(cmd, FASTBOOT_SET_RPMB_RANDOM_KEY)) {
if (fastboot_set_rpmb_random_key()) {
printf("ERROR set rpmb random key failed!\n");
strcpy(response, "FAILset rpmb random key failed!");
} else
strcpy(response, "OKAY");
} else if (endswith(cmd, FASTBOOT_SET_VBMETA_PUBLIC_KEY)) {
if (avb_set_public_key(fastboot_buf_addr,
fastboot_bytes_received))
strcpy(response, "FAILcan't set public key!");
else
strcpy(response, "OKAY");
}
#endif /* !CONFIG_AVB_ATX */
#endif /* CONFIG_IMX_TRUSTY_OS */
else if (endswith(cmd, "unlock_critical")) {
strcpy(response, "OKAY");
} else if (endswith(cmd, "unlock")) {
printf("flashing unlock.\n");
#ifdef CONFIG_AVB_ATX
/* We should do nothing here For Android Things which
* enables the authenticated unlock feature.
*/
strcpy(response, "OKAY");
#else
status = do_fastboot_unlock(false);
if (status != FASTBOOT_LOCK_ERROR)
strcpy(response, "OKAY");
else
strcpy(response, "FAILunlock device failed.");
#endif
} else if (endswith(cmd, "lock")) {
#ifdef CONFIG_AVB_ATX
/* We should do nothing here For Android Things which
* enables the at-lock-vboot feature.
*/
strcpy(response, "OKAY");
#else
printf("flashing lock.\n");
status = do_fastboot_lock();
if (status != FASTBOOT_LOCK_ERROR)
strcpy(response, "OKAY");
else
strcpy(response, "FAILlock device failed.");
#endif
} else if (endswith(cmd, "get_unlock_ability")) {
result = fastboot_lock_enable();
if (result == FASTBOOT_UL_ENABLE) {
fastboot_tx_write_more("INFO1");
strcpy(response, "OKAY");
} else if (result == FASTBOOT_UL_DISABLE) {
fastboot_tx_write_more("INFO0");
strcpy(response, "OKAY");
} else {
printf("flashing get_unlock_ability fail!\n");
strcpy(response, "FAILget unlock ability failed.");
}
} else {
printf("Unknown flashing command:%s\n", cmd);
strcpy(response, "FAILcommand not defined");
}
fastboot_tx_write_more(response);
/* Must call fastboot_none_resp before returning from the dispatch function
* which uses fastboot_tx_write_more
*/
fastboot_none_resp(response);
}
#endif /* CONFIG_FASTBOOT_LOCK */
#ifdef CONFIG_AVB_SUPPORT
static void set_active_avb(char *cmd, char *response)
{
AvbIOResult ret;
int slot = 0;
if (!cmd) {
pr_err("missing slot suffix\n");
fastboot_fail("missing slot suffix", response);
return;
}
slot = slotidx_from_suffix(cmd);
if (slot < 0) {
fastboot_fail("err slot suffix", response);
return;
}
ret = avb_ab_mark_slot_active(&fsl_avb_ab_ops, slot);
if (ret != AVB_IO_RESULT_OK)
fastboot_fail("avb IO error", response);
else
fastboot_okay(NULL, response);
return;
}
#endif /*CONFIG_AVB_SUPPORT*/
#if CONFIG_IS_ENABLED(FASTBOOT_FLASH)
static void flash(char *cmd, char *response)
{
if (!cmd) {
pr_err("missing partition name");
fastboot_fail("missing partition name", response);
return;
}
/* Always enable image flash for Android Things. */
#if defined(CONFIG_FASTBOOT_LOCK) && !defined(CONFIG_AVB_ATX)
int status;
status = fastboot_get_lock_stat();
if (status == FASTBOOT_LOCK) {
pr_err("device is LOCKed!\n");
fastboot_fail("device is locked.", response);
return;
} else if (status == FASTBOOT_LOCK_ERROR) {
pr_err("write lock status into device!\n");
fastboot_set_lock_stat(FASTBOOT_LOCK);
fastboot_fail("device is locked.", response);
return;
}
#endif
fastboot_process_flash(cmd, fastboot_buf_addr,
fastboot_bytes_received, response);
#if defined(CONFIG_FASTBOOT_LOCK)
if (strncmp(cmd, "gpt", 3) == 0) {
int gpt_valid = 0;
gpt_valid = partition_table_valid();
/* If gpt is valid, load partitons table into memory.
So if the next command is "fastboot reboot bootloader",
it can find the "misc" partition to r/w. */
if(gpt_valid) {
fastboot_load_partitions();
/* Unlock device if the gpt is valid */
do_fastboot_unlock(true);
}
}
#endif
}
static void erase(char *cmd, char *response)
{
if (!cmd) {
pr_err("missing partition name");
fastboot_fail("missing partition name", response);
return;
}
#if defined(CONFIG_FASTBOOT_LOCK) && !defined(CONFIG_AVB_ATX)
FbLockState status;
status = fastboot_get_lock_stat();
if (status == FASTBOOT_LOCK) {
pr_err("device is LOCKed!\n");
fastboot_fail("device is locked.", response);
return;
} else if (status == FASTBOOT_LOCK_ERROR) {
pr_err("write lock status into device!\n");
fastboot_set_lock_stat(FASTBOOT_LOCK);
fastboot_fail("device is locked.", response);
return;
}
#endif
fastboot_process_erase(cmd, response);
}
#endif
#if CONFIG_IS_ENABLED(FASTBOOT_UUU_SUPPORT)
/**
* run_ucmd() - Execute the UCmd command
*
* @cmd_parameter: Pointer to command parameter
* @response: Pointer to fastboot response buffer
*/
static void run_ucmd(char *cmd_parameter, char *response)
{
if (!cmd_parameter) {
pr_err("missing slot suffix\n");
fastboot_fail("missing command", response);
return;
}
if(run_command(cmd_parameter, 0)) {
fastboot_fail("", response);
} else {
fastboot_okay(NULL, response);
/* cmd may impact fastboot related environment*/
fastboot_setup();
}
}
static char g_a_cmd_buff[64];
void fastboot_acmd_complete(void)
{
run_command(g_a_cmd_buff, 0);
}
/**
* run_acmd() - Execute the ACmd command
*
* @cmd_parameter: Pointer to command parameter
* @response: Pointer to fastboot response buffer
*/
static void run_acmd(char *cmd_parameter, char *response)
{
if (!cmd_parameter) {
pr_err("missing slot suffix\n");
fastboot_fail("missing command", response);
return;
}
strcpy(g_a_cmd_buff, cmd_parameter);
fastboot_okay(NULL, response);
}
#endif
static const struct {
const char *command;
void (*dispatch)(char *cmd_parameter, char *response);
} commands[FASTBOOT_COMMAND_COUNT] = {
[FASTBOOT_COMMAND_REBOOT_BOOTLOADER] = {
.command = "reboot-bootloader",
.dispatch = reboot_bootloader,
},
[FASTBOOT_COMMAND_UPLOAD] = {
.command = "upload",
.dispatch = upload,
},
[FASTBOOT_COMMAND_GETSTAGED] = {
.command = "get_staged",
.dispatch = upload,
},
#if defined(CONFIG_FASTBOOT_LOCK)
[FASTBOOT_COMMAND_FLASHING] = {
.command = "flashing",
.dispatch = flashing,
},
[FASTBOOT_COMMAND_OEM] = {
.command = "oem",
.dispatch = flashing,
},
#endif
#ifdef CONFIG_AVB_SUPPORT
[FASTBOOT_COMMAND_SETACTIVE] = {
.command = "set_active",
.dispatch = set_active_avb,
},
#endif
#if CONFIG_IS_ENABLED(FASTBOOT_UUU_SUPPORT)
[FASTBOOT_COMMAND_UCMD] = {
.command = "UCmd",
.dispatch = run_ucmd,
},
[FASTBOOT_COMMAND_ACMD] = {
.command ="ACmd",
.dispatch = run_acmd,
},
#endif
[FASTBOOT_COMMAND_REBOOT] = {
.command = "reboot",
.dispatch = okay,
},
[FASTBOOT_COMMAND_GETVAR] = {
.command = "getvar",
.dispatch = getvar,
},
[FASTBOOT_COMMAND_DOWNLOAD] = {
.command = "download",
.dispatch = download,
},
[FASTBOOT_COMMAND_BOOT] = {
.command = "boot",
.dispatch = okay,
},
[FASTBOOT_COMMAND_CONTINUE] = {
.command = "continue",
.dispatch = okay,
},
#ifdef CONFIG_FASTBOOT_FLASH
[FASTBOOT_COMMAND_FLASH] = {
.command = "flash",
.dispatch = flash,
},
[FASTBOOT_COMMAND_ERASE] = {
.command = "erase",
.dispatch = erase,
},
#endif
#ifdef CONFIG_AVB_ATX
[FASTBOOT_COMMAND_STAGE] = {
.command = "stage",
.dispatch = download,
},
#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 < ARRAY_SIZE(commands); i++) {
if (commands[i].command != NULL &&
!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;
}