Files
BPI-CM9-Linux/aml-comp/uboot/bl33/v2019/cmd/amlogic/cmd_bcb.c
T

592 lines
17 KiB
C

// SPDX-License-Identifier: (GPL-2.0+ OR MIT)
/*
* Copyright (c) 2019 Amlogic, Inc. All rights reserved.
*/
#include <common.h>
#include <command.h>
#include <environment.h>
#include <malloc.h>
#include <asm/byteorder.h>
#include <config.h>
#include <asm/arch/io.h>
#include <amlogic/storage.h>
#include <stdlib.h>
#include <amlogic/store_wrapper.h>
#ifdef CONFIG_BOOTLOADER_CONTROL_BLOCK
#define COMMANDBUF_SIZE 32
#define STATUSBUF_SIZE 32
#define RECOVERYBUF_SIZE 768
#define BOOTINFO_OFFSET 864
#define RESERVED_OFFSET 896
#define SLOTBUF_SIZE 32
#define MISCBUF_SIZE 1088
#define CMD_WIPE_DATA "wipe_data"
#define CMD_SYSTEM_CRASH "system_crash"
#define CMD_RUN_RECOVERY "boot-recovery"
#define CMD_RESIZE_DATA "resize2fs_data"
#define CMD_FOR_RECOVERY "recovery_"
#define CMD_FASTBOOTD "fastbootd"
#define CMD_RECOVERY_WIPE "prompt_and_wipe_data"
#define CMD_FACTORY "factory"
#define CMD_BIST "bist"
static const char * const temp_for_compile[] = {"__test1", "__test2", "__test3", NULL};
extern const char * const _env_list_execute_[0] __attribute__((weak, alias("temp_for_compile")));
struct bootloader_message {
char command[32];
char status[32];
char recovery[768];
// The 'recovery' field used to be 1024 bytes. It has only ever
// been used to store the recovery command line, so 768 bytes
// should be plenty. We carve off the last 256 bytes to store the
// stage string (for multistage packages) and possible future
// expansion.
char stage[32];
char slot_suffix[32];
char reserved[192];
};
#ifdef CONFIG_CMD_BCB
static bool env_command_check(const char *cmd)
{
int index = 0;
int envListNum = 0;
char *s = NULL;
char *v = NULL;
char *strcopy = NULL;
const char **envListArr = (const char **)_env_list_execute_;
const char **pArr = (const char **)envListArr;
while (*pArr++) {
++envListNum;
}
printf("envListNum = %d\n", envListNum);
if (envListNum == 0) {
return false;
}
strcopy = strdup(cmd);
if (!strcopy) {
return false;
}
s = strcopy;
while ((v = strsep(&s, ";")) != NULL) {
char *p = v;
strsep(&p, " ");
for (index = 0; index < envListNum; index++) {
if (!strcmp(envListArr[index], v)) {
break;
}
}
if (index == envListNum) {
printf("%s not in the white list.\n", v);
free(strcopy);
strcopy = NULL;
return false;
}
}
free(strcopy);
strcopy = NULL;
return true;
}
#endif
/**
* @usage: write data to storage device for nand flash
*
* @name: partition name, when it's null the target
* will regards as whole device.
* @off: offset to the 0 address of partition/device
* @size: the amount of bytes to write
* @buf: pointer of source buffer
*
* @return: result of the operation
* 0 = success
* other = fail
*/
int nand_store_write(const char *name, loff_t off, size_t size, void *buf)
{
int ret = -1;
u64 rc = 0;
unsigned char *buffer = NULL;
u64 sz = 0;
rc = store_logic_cap(name);
if (rc == 1) {
printf("Failed to get partition[%s] size\n", name);
return ret;
}
sz = rc;// save the size
buffer = (unsigned char *)malloc(rc);
if (!buffer) {
printf("ERROR! fail to allocate memory ...\n");
goto exit;
}
memset(buffer, 0, rc);
/* 1. read all data from the partition table */
if (store_read(name, 0, rc, buffer) < 0) {
printf("Fail to read %s partition\n", name);
goto exit;
}
/* 2. update buffer data */
memcpy(buffer + off, buf, size);
/* 3. erase partition */
rc = store_erase(name, 0, 0, 0);
if (rc) {
printf("Fail erase partition %s\n", name);
goto exit;
}
// here the rc is 0, should use sz instead
/* 4.write data back to the partitioned table */
if (store_write((const char *)name, 0, sz, (unsigned char *)buffer) < 0) {
printf("failed to write data to %s.\n", name);
goto exit;
} else {
ret = 0;
}
exit:
if (buffer)
free(buffer);
return ret;
}
static int clear_misc_partition(char *clearbuf, int size)
{
char *partition = "misc";
memset(clearbuf, 0, size);
if (store_get_type() == BOOT_SNAND || store_get_type() == BOOT_NAND_MTD) {
if (nand_store_write((const char *)partition, 0,
size, (unsigned char *)clearbuf) < 0) {
printf("failed to clear %s for nand flash.\n", partition);
return -1;
}
} else {
if (store_write((const char *)partition,
0, size, (unsigned char *)clearbuf) < 0) {
printf("failed to clear %s.\n", partition);
return -1;
}
}
return 0;
}
static int my_atoi(const char *str)
{
int result = 0;
int signal = 1;
if ((*str >= '0' && *str <= '9') || *str == '-' || *str == '+') {
if (*str == '-' || *str == '+') {
if (*str == '-')
signal = -1;
str++;
}
} else {
return 0;
}
while (*str >= '0' && *str <= '9')
result = result * 10 + (*str++ - '0');
return signal * result;
}
static int do_RunBcbCommand(
cmd_tbl_t * cmdtp,
int flag,
int argc,
char * const argv[])
{
int i = 0;
char command[COMMANDBUF_SIZE] = {0};
char status[STATUSBUF_SIZE] = {0};
char recovery[RECOVERYBUF_SIZE] = {0};
char miscbuf[MISCBUF_SIZE] = {0};
char clearbuf[COMMANDBUF_SIZE+STATUSBUF_SIZE+RECOVERYBUF_SIZE] = {0};
char* RebootMode;
char *Powermode;
int remain_time = 0;
if (argc != 2) {
return cmd_usage(cmdtp);
}
printf("Command: ");
for (i = 0; i < argc; i++) {
printf("%s ", argv[i]);
}
printf("\n");
char *partition = "misc";
char *command_mark = (char *)argv[1];
if (strlen(command_mark) > sizeof(command)) {
//printf("Bcb command mark range out of length(%d > %d).\n",
//strlen(command_mark), sizeof(command));
goto ERR;
}
if (!memcmp(command_mark, CMD_WIPE_DATA, strlen(command_mark))) {
printf("Start to write --wipe_data to %s\n", partition);
memcpy(miscbuf, CMD_RUN_RECOVERY, sizeof(CMD_RUN_RECOVERY));
memcpy(miscbuf+sizeof(command)+sizeof(status), "recovery\n--wipe_data", sizeof("recovery\n--wipe_data"));
if (store_get_type() == BOOT_SNAND || store_get_type() == BOOT_NAND_MTD) {
nand_store_write((const char *)partition, 0, sizeof(miscbuf),
(unsigned char *)miscbuf);
} else {
store_write((const char *)partition, 0, sizeof(miscbuf),
(unsigned char *)miscbuf);
}
} else if (!memcmp(command_mark, CMD_SYSTEM_CRASH, strlen(command_mark))) {
printf("Start to write --system_crash to %s\n", partition);
memcpy(miscbuf, CMD_RUN_RECOVERY, sizeof(CMD_RUN_RECOVERY));
memcpy(miscbuf+sizeof(command)+sizeof(status), "recovery\n--system_crash", sizeof("recovery\n--system_crash"));
if (store_get_type() == BOOT_SNAND || store_get_type() == BOOT_NAND_MTD) {
nand_store_write((const char *)partition, 0, sizeof(miscbuf),
(unsigned char *)miscbuf);
} else {
store_write((const char *)partition, 0, sizeof(miscbuf),
(unsigned char *)miscbuf);
}
} else if (!memcmp(command_mark, CMD_RESIZE_DATA, strlen(command_mark))) {
printf("Start to write --resize2fs_data to %s\n", partition);
memcpy(miscbuf, CMD_RUN_RECOVERY, sizeof(CMD_RUN_RECOVERY));
memcpy(miscbuf+sizeof(command)+sizeof(status), "recovery\n--resize2fs_data", sizeof("recovery\n--resize2fs_data"));
if (store_get_type() == BOOT_SNAND || store_get_type() == BOOT_NAND_MTD) {
nand_store_write((const char *)partition, 0, sizeof(miscbuf),
(unsigned char *)miscbuf);
} else {
store_write((const char *)partition, 0, sizeof(miscbuf),
(unsigned char *)miscbuf);
}
} else if (!memcmp(command_mark, CMD_FOR_RECOVERY, strlen(CMD_FOR_RECOVERY))) {
memcpy(miscbuf, CMD_RUN_RECOVERY, sizeof(CMD_RUN_RECOVERY));
sprintf(recovery, "%s%s", "recovery\n--", command_mark);
memcpy(miscbuf+sizeof(command)+sizeof(status), recovery, strlen(recovery));
if (store_get_type() == BOOT_SNAND || store_get_type() == BOOT_NAND_MTD) {
nand_store_write((const char *)partition, 0, sizeof(miscbuf),
(unsigned char *)miscbuf);
} else {
store_write((const char *)partition, 0, sizeof(miscbuf),
(unsigned char *)miscbuf);
}
return 0;
} else if (!memcmp(command_mark, CMD_FASTBOOTD, strlen(command_mark))) {
printf("write cmd to enter fastbootd \n");
memcpy(miscbuf, CMD_RUN_RECOVERY, sizeof(CMD_RUN_RECOVERY));
memcpy(miscbuf+sizeof(command)+sizeof(status), "recovery\n--fastboot", sizeof("recovery\n--fastboot"));
if (store_get_type() == BOOT_SNAND || store_get_type() == BOOT_NAND_MTD) {
nand_store_write((const char *)partition, 0, sizeof(miscbuf),
(unsigned char *)miscbuf);
} else {
store_write((const char *)partition, 0, sizeof(miscbuf),
(unsigned char *)miscbuf);
}
return 0;
} else if (IS_ENABLED(CONFIG_FACTORY_BURN_MODE) &&
!memcmp(command_mark, CMD_FACTORY, strlen(command_mark))) {
printf("write cmd to enter factory mode\n");
memcpy(miscbuf, CMD_RUN_RECOVERY, sizeof(CMD_RUN_RECOVERY));
memcpy(miscbuf + sizeof(command) + sizeof(status),
"recovery\n--factory", sizeof("recovery\n--factory"));
if (store_get_type() == BOOT_SNAND || store_get_type() == BOOT_NAND_MTD) {
nand_store_write((const char *)partition, 0, sizeof(miscbuf),
(unsigned char *)miscbuf);
} else {
store_write((const char *)partition, 0, sizeof(miscbuf),
(unsigned char *)miscbuf);
}
env_set("factory_mode", "1");
#if CONFIG_IS_ENABLED(AML_UPDATE_ENV)
run_command("update_env_part -p factory_mode;", 0);
#else
run_command("saveenv;", 0);
#endif
run_command("reboot factory;", 0);
} else if (IS_ENABLED(CONFIG_BIST_MODE) &&
!memcmp(command_mark, CMD_BIST, strlen(command_mark))) {
printf("write cmd to enter bist mode\n");
memcpy(miscbuf, CMD_RUN_RECOVERY, sizeof(CMD_RUN_RECOVERY));
memcpy(miscbuf + sizeof(command) + sizeof(status),
"recovery\n--bist", sizeof("recovery\n--bist"));
if (store_get_type() == BOOT_SNAND || store_get_type() == BOOT_NAND_MTD) {
nand_store_write((const char *)partition, 0, sizeof(miscbuf),
(unsigned char *)miscbuf);
} else {
store_write((const char *)partition, 0, sizeof(miscbuf),
(unsigned char *)miscbuf);
}
env_set("bist_mode", "1");
#if CONFIG_IS_ENABLED(AML_UPDATE_ENV)
run_command("update_env_part -p bist_mode;", 0);
#else
run_command("saveenv;", 0);
#endif
run_command("reboot Diagnostic;", 0);
}
printf("Start read %s partition datas!\n", partition);
if (store_read((const char *)partition,
0, sizeof(miscbuf), (unsigned char *)miscbuf) < 0) {
printf("failed to store read %s.\n", partition);
goto ERR;
}
#ifdef CONFIG_BOOTLOADER_SHOW_ERRCODE
char rsvbuf[64];
memset(rsvbuf, 0, 64);
strncpy(rsvbuf, miscbuf + RESERVED_OFFSET, 63);
if (strlen(rsvbuf)) {
char cmdbuf[256];
sprintf(cmdbuf, "errcode mode '%s'", rsvbuf);
printf("cmdbuf:%s\n", cmdbuf);
run_command(cmdbuf, 0);
}
#endif
// judge misc partition whether has datas
char tmpbuf[MISCBUF_SIZE];
memset(tmpbuf, 0, sizeof(tmpbuf));
if (!memcmp(tmpbuf, miscbuf, strlen(miscbuf))) {
env_set("retry_recovery_times", "7");
#if CONFIG_IS_ENABLED(AML_UPDATE_ENV)
run_command("update_env_part -p retry_recovery_times;", 0);
#else
run_command("saveenv;", 0);
#endif
printf("BCB hasn't any datas,exit!\n");
return 0;
}
memcpy(command, miscbuf, sizeof(command));
memcpy(status, miscbuf+sizeof(command), sizeof(status));
memcpy(recovery, miscbuf+sizeof(command)+sizeof(status), sizeof(recovery));
memcpy(clearbuf, miscbuf, sizeof(clearbuf));
printf("get bootloader message from misc partition:\n");
printf("[command:%s]\n[status:%s]\n[recovery:%s]\n",
command, status, recovery);
run_command("get_rebootmode", 0);
RebootMode = env_get("reboot_mode");
if (RebootMode && strstr(RebootMode, "quiescent")) {
printf("quiescent mode.\n");
run_command("run storeargs", 0);
run_command("setenv bootconfig ${bootconfig} androidboot.quiescent=1;", 0);
}
Powermode = env_get("powermode");
if (RebootMode && !strcmp(RebootMode, "cold_boot")) {
if (Powermode && !strcmp(Powermode, "standby")) {
printf("cold_boot default standby, ignore recovery mode\n");
return 0;
}
}
if (!memcmp(command, CMD_RUN_RECOVERY, strlen(CMD_RUN_RECOVERY))) {
char *retry_times;
char *retest_times;
retry_times = env_get("retry_recovery_times");
if (retry_times) {
printf("retry_time: %s\n", retry_times);
remain_time = my_atoi(retry_times);
printf("retry_time remain_time = %d\n", remain_time);
}
if (remain_time == 0) {
printf("clear recovery cmds in misc\n");
if (clear_misc_partition(clearbuf, sizeof(clearbuf)) < 0) {
printf("clear misc partition failed.\n");
goto ERR;
}
env_set("retry_recovery_times", "7");
#if CONFIG_IS_ENABLED(AML_UPDATE_ENV)
run_command("update_env_part -p retry_recovery_times;", 0);
#else
run_command("saveenv;", 0);
#endif
run_command("run enter_fastboot", 0);
}
if (IS_ENABLED(CONFIG_FACTORY_BURN_MODE)) {
char *factory_mode;
factory_mode = env_get("factory_mode");
if (factory_mode && !strcmp(factory_mode, "1")) {
printf("clear recovery cmds for factory mode\n");
if (clear_misc_partition(clearbuf, sizeof(clearbuf)) < 0) {
printf("clear misc partition failed.\n");
goto ERR;
}
}
}
if (IS_ENABLED(CONFIG_BIST_MODE)) {
char *bist_mode;
bist_mode = env_get("bist_mode");
if (bist_mode && !strcmp(bist_mode, "1")) {
printf("clear recovery cmds for bist mode\n");
if (clear_misc_partition(clearbuf, sizeof(clearbuf)) < 0) {
printf("clear misc partition failed.\n");
goto ERR;
}
}
}
if (retry_times && remain_time > 0) {
sprintf(retry_times, "%d", remain_time - 1);
printf("retry_time: %s\n", retry_times);
env_set("retry_recovery_times", retry_times);
#if CONFIG_IS_ENABLED(AML_UPDATE_ENV)
run_command("update_env_part -p retry_recovery_times;", 0);
#else
run_command("saveenv;", 0);
#endif
}
retest_times = env_get("retest_times");
if (strstr(recovery, CMD_RECOVERY_WIPE) &&
retest_times && (strcmp(retest_times, "2") == 0)) {
char *rebootmode = env_get("reboot_mode");
printf("enter recovery first time, try again\n");
if (clear_misc_partition(clearbuf, sizeof(clearbuf)) < 0) {
printf("clear misc partition failed.\n");
goto ERR;
}
run_command("set_retest_times 1;", 0);
if (rebootmode && (strcmp(rebootmode, "quiescent") == 0))
run_command("reboot quiescent", 0);
else
run_command("reboot", 0);
return 0;
}
#ifdef CONFIG_BOOTLOADER_SHOW_ERRCODE
char cmdbuf[256];
char *reason = strstr(recovery, "reason");
if (reason) {
sprintf(cmdbuf, "errcode misc %s", reason);
run_command(cmdbuf, 0);
}
#endif
if (run_command("run recovery_from_flash", 0) < 0) {
printf("run_command for cmd:run recovery_from_flash failed.\n");
return -1;
}
printf("run command:run recovery_from_flash successful.\n");
return 0;
}
#ifdef CONFIG_CMD_BCB
//uboot-command only valid once, not matter success or not
if (clear_misc_partition(clearbuf, sizeof(clearbuf)) < 0) {
printf("clear misc partition failed.\n");
goto ERR;
}
if (!memcmp(command_mark, command, strlen(command_mark))) {
printf("%s\n", recovery);
if (run_command((char *)recovery, 0) < 0) {
printf("run_command for cmd:%s failed.\n", recovery);
goto ERR;
}
printf("run command successful.\n");
} else if (!strncmp(command_mark, "uboot-command", strlen("uboot-command"))) {
printf("uboot-command: %s\n", command);
if (!env_command_check(command)) {
printf("not all uboot-command in white-list\n");
goto ERR;
}
if (run_command((char *)command, 0) < 0) {
printf("run_command for cmd:%s failed.\n", command);
goto ERR;
}
printf("run uboot-command successful.\n");
} else {
printf("command mark(%s) not match %s,don't execute.\n",
command_mark, command);
}
#endif
return 0;
ERR:
return -1;
}
#else
static int do_RunBcbCommand(
cmd_tbl_t * cmdtp,
int flag,
int argc,
char * const argv[])
{
if (argc != 2) {
return cmd_usage(cmdtp);
}
// Do-Nothing!
return 0;
}
#endif /* CONFIG_BOOTLOADER_CONTROL_BLOCK */
// BCB: Bootloader Control Block
U_BOOT_CMD(
bcb, 2, 0, do_RunBcbCommand,
"bcb",
"\nThis command will run some commands which saved in misc\n"
"partition by mark to decide whether execute command!\n"
"Command format:\n"
" bcb bcb_mark\n"
"Example:\n"
" /dev/block/misc partition is saved some contents:\n"
" uboot-command\n" // command mark
" N/A\n"
" setenv aa 11;setenv bb 22;setenv cc 33;saveenv;\n" // command
"So you can execute command: bcb uboot-command"
);