402 lines
12 KiB
C
402 lines
12 KiB
C
/* SPDX-License-Identifier: (GPL-2.0+ OR MIT) */
|
|
/*
|
|
* common/cmd_bcb.c
|
|
*
|
|
* Copyright (C) 2020 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>
|
|
|
|
#ifdef CONFIG_BOOTLOADER_CONTROL_BLOCK
|
|
extern int store_read_ops(
|
|
unsigned char *partition_name,
|
|
unsigned char * buf, uint64_t off, uint64_t size);
|
|
extern int store_write_ops(
|
|
unsigned char *partition_name,
|
|
unsigned char * buf, uint64_t off, uint64_t size);
|
|
|
|
#define COMMANDBUF_SIZE 32
|
|
#define STATUSBUF_SIZE 32
|
|
#define RECOVERYBUF_SIZE 768
|
|
|
|
#define BOOTINFO_OFFSET 864
|
|
#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"
|
|
|
|
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];
|
|
};
|
|
|
|
static int clear_misc_partition(char *clearbuf, int size)
|
|
{
|
|
char *partition = "misc";
|
|
|
|
memset(clearbuf, 0, size);
|
|
if (store_write_ops((unsigned char *)partition,
|
|
(unsigned char *)clearbuf, 0, size) < 0) {
|
|
printf("failed to clear %s.\n", partition);
|
|
return -1;
|
|
}
|
|
|
|
return 0;
|
|
}
|
|
|
|
static int my_atoi(const char *str)
|
|
{
|
|
int ret = 0;
|
|
|
|
if (!str)
|
|
return ret;
|
|
|
|
while (*str != '\0') {
|
|
if (('0' <= *str) && (*str <= '9')) {
|
|
ret = ret * 10 + (*str++ - '0');
|
|
} else {
|
|
ret = 0;
|
|
break;
|
|
}
|
|
}
|
|
|
|
return ret;
|
|
}
|
|
|
|
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;
|
|
char* ActiveSlot;
|
|
int remain_time = -1;
|
|
char *bootconfig;
|
|
|
|
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"));
|
|
store_write_ops((unsigned char *)partition, (unsigned char *)miscbuf, 0, sizeof(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"));
|
|
store_write_ops((unsigned char *)partition, (unsigned char *)miscbuf, 0, sizeof(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"));
|
|
store_write_ops((unsigned char *)partition, (unsigned char *)miscbuf, 0, sizeof(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));
|
|
store_write_ops((unsigned char *)partition, (unsigned char *)miscbuf, 0, sizeof(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"));
|
|
store_write_ops((unsigned char *)partition, (unsigned char *)miscbuf, 0, sizeof(miscbuf));
|
|
return 0;
|
|
}
|
|
|
|
printf("Start read %s partition datas!\n", partition);
|
|
if (store_read_ops((unsigned char *)partition,
|
|
(unsigned char *)miscbuf, 0, sizeof(miscbuf)) < 0) {
|
|
printf("failed to store read %s.\n", partition);
|
|
goto ERR;
|
|
}
|
|
|
|
// judge misc partition whether has datas
|
|
char tmpbuf[MISCBUF_SIZE];
|
|
memset(tmpbuf, 0, sizeof(tmpbuf));
|
|
if (!memcmp(tmpbuf, miscbuf, strlen(miscbuf))) {
|
|
setenv("retry_recovery_times", "7");
|
|
run_command("saveenv;", 0);
|
|
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 = getenv("reboot_mode");
|
|
if (RebootMode && (strstr(RebootMode, "quiescent") != NULL)) {
|
|
printf("quiescent mode.\n");
|
|
run_command("run storeargs", 0);
|
|
run_command("setenv bootconfig ${bootconfig} androidboot.quiescent=1;", 0);
|
|
}
|
|
|
|
powermode = getenv("powermode");
|
|
if (RebootMode && !strcmp(RebootMode, "cold_boot")) {
|
|
if (powermode && !strcmp(powermode, "standby")) {
|
|
printf("cold_boot default standby, ignore recovery mode\n");
|
|
return 0;
|
|
}
|
|
}
|
|
|
|
ActiveSlot = getenv("active_slot");
|
|
if (!ActiveSlot) {
|
|
run_command("get_valid_slot", 0);
|
|
ActiveSlot = getenv("active_slot");
|
|
}
|
|
if (ActiveSlot && !strstr(ActiveSlot, "normal")) {
|
|
printf("ab update mode\n");
|
|
bootconfig = getenv("bootconfig");
|
|
if (bootconfig) {
|
|
run_command("setenv bootconfig ${bootconfig} "\
|
|
"androidboot.slot_suffix=${active_slot};", 0);
|
|
} else {
|
|
run_command("setenv bootargs ${bootargs} "\
|
|
"androidboot.slot_suffix=${active_slot};", 0);
|
|
}
|
|
}
|
|
|
|
setenv("recovery_mode", "false");
|
|
|
|
if (!memcmp(command, CMD_RUN_RECOVERY, strlen(CMD_RUN_RECOVERY))) {
|
|
char *retry_times;
|
|
|
|
retry_times = getenv("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);
|
|
} else {
|
|
setenv("retry_recovery_times", "7");
|
|
run_command("saveenv;", 0);
|
|
remain_time = 7;
|
|
}
|
|
|
|
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;
|
|
}
|
|
setenv("retry_recovery_times", "7");
|
|
run_command("saveenv;", 0);
|
|
run_command("fastboot", 0);
|
|
}
|
|
|
|
if (retry_times && remain_time > 0) {
|
|
sprintf(retry_times, "%d", remain_time - 1);
|
|
printf("retry_time: %s\n", retry_times);
|
|
setenv("retry_recovery_times", retry_times);
|
|
run_command("saveenv;", 0);
|
|
}
|
|
|
|
setenv("recovery_mode", "true");
|
|
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
|
|
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");
|
|
|
|
if (clear_misc_partition(clearbuf, sizeof(clearbuf)) < 0) {
|
|
printf("clear misc partition failed.\n");
|
|
goto ERR;
|
|
} else {
|
|
printf("clear misc partition successful.\n");
|
|
}
|
|
} else {
|
|
printf("command mark(%s) not match %s,don't execute.\n",
|
|
command_mark, command);
|
|
}
|
|
#endif
|
|
|
|
return 0;
|
|
|
|
ERR:
|
|
return -1;
|
|
}
|
|
|
|
static int do_RunAmlBcbCommand(
|
|
cmd_tbl_t * cmdtp,
|
|
int flag,
|
|
int argc,
|
|
char * const argv[]) {
|
|
if (argc != 1) {
|
|
return cmd_usage(cmdtp);
|
|
}
|
|
|
|
static int status = 0;
|
|
static int f_init;
|
|
char *partition = "misc";
|
|
char recovery[RECOVERYBUF_SIZE] = {0};
|
|
char miscbuf[MISCBUF_SIZE] = {0};
|
|
unsigned long long cmdaddr;
|
|
|
|
if (f_init == 1) {
|
|
if (status == 1)
|
|
setenv("reboot_mode", "update");
|
|
return 0;
|
|
}
|
|
|
|
printf("Start read %s partition datas!\n", partition);
|
|
if (store_read_ops((unsigned char *)partition,
|
|
(unsigned char *)miscbuf, 0, sizeof(miscbuf)) < 0) {
|
|
printf("failed to store read %s.\n", partition);
|
|
return 0;
|
|
}
|
|
|
|
// judge misc partition whether has datas
|
|
char tmpbuf[MISCBUF_SIZE];
|
|
memset(tmpbuf, 0, sizeof(tmpbuf));
|
|
if (!memcmp(tmpbuf, miscbuf, strlen(miscbuf))) {
|
|
printf("BCB hasn't any datas,exit!\n");
|
|
} else {
|
|
memcpy(recovery, miscbuf+COMMANDBUF_SIZE+STATUSBUF_SIZE, sizeof(recovery));
|
|
if (strstr(recovery, CMD_WIPE_DATA)) {
|
|
f_init = 1;
|
|
return 0;
|
|
}
|
|
}
|
|
|
|
int ret = run_command("ext4load mmc 1:2 ${loadaddr} /recovery/command 100", 1);
|
|
if (ret != 0) {
|
|
ret = run_command("ext4load mmc 1:2 ${loadaddr} /recovery/command", 1);
|
|
}
|
|
|
|
if (ret == 0) {
|
|
const char *paddr = getenv("loadaddr");
|
|
if (paddr != NULL) {
|
|
cmdaddr = getenv_hex("loadaddr", 0);
|
|
char *command = (char *)map_sysmem(cmdaddr, 0);
|
|
if (command && strstr(command, CMD_WIPE_DATA)) {
|
|
unmap_sysmem(command);
|
|
f_init = 1;
|
|
return 0;
|
|
}
|
|
unmap_sysmem(command);
|
|
}
|
|
}
|
|
|
|
printf("run recovery, but not factory reset.\n");
|
|
setenv("reboot_mode","update");
|
|
f_init = 1;
|
|
status = 1;
|
|
// Do-Nothing!
|
|
return 0;
|
|
}
|
|
#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;
|
|
}
|
|
|
|
static int do_RunAmlBcbCommand(
|
|
cmd_tbl_t * cmdtp,
|
|
int flag,
|
|
int argc,
|
|
char * const argv[]) {
|
|
if (argc != 1) {
|
|
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"
|
|
);
|
|
|
|
U_BOOT_CMD(
|
|
aml_bcb, 1, 0, do_RunAmlBcbCommand,
|
|
"aml_bcb",
|
|
"\nThis command will change reboot_mode from factory_reset\n"
|
|
"to update if not contain wipe_data !"
|
|
);
|