313 lines
7.9 KiB
C
313 lines
7.9 KiB
C
/* SPDX-License-Identifier: (GPL-2.0+ OR MIT) */
|
|
/*
|
|
* common/ramdump.c
|
|
*
|
|
* Copyright (C) 2020 Amlogic, Inc. All rights reserved.
|
|
*
|
|
*/
|
|
|
|
#include <common.h>
|
|
#include <asm/arch/bl31_apis.h>
|
|
#include <asm/reboot.h>
|
|
#include <asm/arch/secure_apb.h>
|
|
#include <ramdump.h>
|
|
#include <emmc_partitions.h>
|
|
#include <asm/cpu_id.h>
|
|
#include <cli.h>
|
|
|
|
#define DEBUG_RAMDUMP 0
|
|
#define _AML_MISC_INTERRUPT_KEY 0x09
|
|
|
|
unsigned long ramdump_base = 0;
|
|
unsigned long ramdump_size = 0;
|
|
unsigned int get_reboot_mode(void)
|
|
{
|
|
uint32_t reboot_mode_val = ((readl(AO_SEC_SD_CFG15) >> 12) & 0xf);
|
|
|
|
return reboot_mode_val;
|
|
}
|
|
|
|
void ramdump_init(void)
|
|
{
|
|
unsigned int data, reboot_mode;
|
|
|
|
ramdump_base = readl(P_AO_SEC_GP_CFG12);
|
|
ramdump_size = readl(P_AO_SEC_GP_CFG13);
|
|
#if defined(CONFIG_MDUMP_COMPRESS) && defined(CONFIG_COMPRESSED_ADDR)
|
|
printf("%s, ramdump_base(0x%08lx) is overwritten as 0x%08x\n",
|
|
__func__, ramdump_base, CONFIG_COMPRESSED_ADDR);
|
|
ramdump_base = (unsigned long)CONFIG_COMPRESSED_ADDR;
|
|
#endif
|
|
if (ramdump_base & 0x80) {
|
|
/* 0x80: The flag indicates that the addr exceeds 4G. */
|
|
/* real size = size[31:0] + addr[6:0]<<32 */
|
|
ramdump_size += (ramdump_base & 0x7f) << 32;
|
|
/* real addr = addr[31:8] << 8 */
|
|
ramdump_base = (ramdump_base & 0xffffff00) << 8;
|
|
}
|
|
|
|
data = readl(PREG_STICKY_REG8);
|
|
writel(data & ~RAMDUMP_STICKY_DATA_MASK, PREG_STICKY_REG8);
|
|
printf("%s, add:%lx, size:%lx\n", __func__, ramdump_base, ramdump_size);
|
|
|
|
reboot_mode = get_reboot_mode();
|
|
if ((reboot_mode == AMLOGIC_WATCHDOG_REBOOT ||
|
|
reboot_mode == AMLOGIC_KERNEL_PANIC)) {
|
|
if (ramdump_base && ramdump_size)
|
|
ramdump_save_compress_data();
|
|
}
|
|
}
|
|
|
|
#ifdef CONFIG_USB_STORAGE
|
|
static int wait_for_interrupt_key(const int tm/*timeout in ms*/)
|
|
{
|
|
int i;
|
|
unsigned long ts;
|
|
char str_input[5];
|
|
|
|
ts = get_timer(0);
|
|
for (i = 0; i < sizeof(str_input) - 1;) {
|
|
int c = 0;
|
|
|
|
while (!tstc()) {
|
|
if (get_timer(ts) >= tm)
|
|
return 0;
|
|
}
|
|
c = getc();
|
|
if (i == 0 && c == _AML_MISC_INTERRUPT_KEY) {//drop first duplicated ctrlI
|
|
printf("Wait y/yes input\n");
|
|
continue;
|
|
}
|
|
putc(c);
|
|
str_input[i++] = c;
|
|
if (c == '\r')
|
|
break;
|
|
}
|
|
|
|
str_input[i] = '\0';
|
|
putc('\n');
|
|
if (strcasecmp(str_input, "y\r") == 0 ||
|
|
strcasecmp(str_input, "yes\r") == 0) {
|
|
cli_init();
|
|
cli_loop();
|
|
panic("No CLI available");
|
|
}
|
|
|
|
return 0;
|
|
}
|
|
|
|
static void wait_usb_dev(void)
|
|
{
|
|
block_dev_desc_t *usb_dev;
|
|
int print_cnt = 0;
|
|
const char *env = getenv("ramdump_usb_timeout");
|
|
int timeout_minutes = env ? simple_strtoul(env, NULL, 10) : 0;
|
|
int max_attempts = (timeout_minutes > 0) ? (timeout_minutes * 60 / 20) : 0;
|
|
|
|
while (1) {
|
|
run_command("usb start", 1);
|
|
mdelay(2000);
|
|
run_command("usb reset", 1);
|
|
usb_dev = usb_stor_get_dev(0);
|
|
if (!usb_dev) {
|
|
print_cnt++;
|
|
if (max_attempts > 0 && print_cnt > max_attempts) {
|
|
printf("ramdump: Udisk not found after %d minutes. Exiting...\n",
|
|
timeout_minutes);
|
|
return;
|
|
}
|
|
printf("ramdump: can't find USB device, attempt %d.", print_cnt);
|
|
printf(" Please insert FAT32 Udisk!\n");
|
|
printf("Or you can input 'Ctrl I' to force stopped anyway ...\n\n\n");
|
|
wait_for_interrupt_key(18000);
|
|
} else {
|
|
run_command("usb dev", 1);
|
|
break;
|
|
}
|
|
}
|
|
}
|
|
#endif
|
|
/*
|
|
* NOTE: this is a default implementation for writing compressed ramdump data
|
|
* to /data/ partition for Android platform. You can read out dumpfile in
|
|
* path /data/crashdump-1.bin when enter Android for crash analyze.
|
|
* by default, /data/ partition for android is EXT4 fs.
|
|
*
|
|
* TODO:
|
|
* If you are using different fs or OS on your platform, implement compress
|
|
* data save command for your fs and OS in your board.c with same function
|
|
* name "ramdump_save_compress_data".
|
|
*/
|
|
__weak int ramdump_save_compress_data(void)
|
|
{
|
|
char *env;
|
|
int ret = 0;
|
|
#ifdef CONFIG_USB_STORAGE
|
|
char cmd[128] = {0};
|
|
char path[64] = "/";
|
|
int cnt = 0;
|
|
#endif
|
|
|
|
env = getenv("ramdump_location");
|
|
if (!env)
|
|
return 0;
|
|
|
|
printf("ramdump_location:%s\n", env);
|
|
/* currently we only support write to usb disk */
|
|
if (strncmp(env, "usb", 3)) {
|
|
printf("not supported location\n");
|
|
return 0;
|
|
}
|
|
#ifdef CONFIG_USB_STORAGE
|
|
wait_usb_dev();
|
|
|
|
env = getenv("ramdump_usb_path");
|
|
if (env) {
|
|
printf("ramdump_usb_path: %s\n", env);
|
|
snprintf(cmd, sizeof(cmd), "fatls usb 0 %s/", env);
|
|
ret = run_command(cmd, 0);
|
|
if (ret != 0)
|
|
printf("USB path '%s' does not exist, using default '/'.\n", env);
|
|
else
|
|
snprintf(path, sizeof(path), "%s/", env);
|
|
}
|
|
printf("\nPrepare to save crash file: base=0x%08lx, size=0x%08lx (%ld MB)\n",
|
|
ramdump_base, ramdump_size, ramdump_size / 1024 / 1024);
|
|
snprintf(cmd, sizeof(cmd), "fatwrite usb 0 %lx %scrashdump-1.bin %lx",
|
|
ramdump_base, path, ramdump_size);
|
|
printf("\nCMD: %s\n\n", cmd);
|
|
|
|
printf("It may take about 3 minutes, please wait...\n");
|
|
while (cnt < 3) {
|
|
ret = run_command(cmd, 0);
|
|
if (ret == 0) {
|
|
run_command("usb stop", 0);
|
|
printf("run fatwrite usb OK! (%scrashdump-1.bin)\n\n", path);
|
|
break;
|
|
}
|
|
printf("run fatwrite usb ERROR! Try again...\n");
|
|
cnt++;
|
|
run_command("usb stop", 0);
|
|
mdelay(1000);
|
|
run_command("usb start", 1);
|
|
mdelay(2000);
|
|
run_command("usb reset", 1);
|
|
run_command("usb dev", 1);
|
|
mdelay(1000);
|
|
}
|
|
if (cnt >= 3) {
|
|
printf("\n======================= fatwrite ERROR! (try 3 times) =============\n");
|
|
printf("= 1. Please check Udisk! (FAT32 type, and enough space.)\n");
|
|
printf("= 2. Try another Udisk! (Press Ctrl+i, then manually run fatwrite.)\n");
|
|
printf("====================================================================\n\n");
|
|
}
|
|
|
|
env = getenv("ramdump_usb_reboot");
|
|
if (env && strcmp(env, "1") == 0) {
|
|
printf("ramdump_usb_reboot: %s\n", env);
|
|
printf("Rebooting in 5 seconds ...\n\n\n");
|
|
mdelay(5000);
|
|
run_command("reboot", 1);
|
|
}
|
|
|
|
printf("\nRun fatwrite finished. Wait here forever!\n");
|
|
printf("\nAnd You can input 'Ctrl I' to force stopped anyway ...\n\n\n");
|
|
while (1) {
|
|
mdelay(1000);
|
|
wait_for_interrupt_key(100000);
|
|
}
|
|
#else
|
|
printf("CONFIG_USB_STORAGE is not defined! Could it be in PRODUCT mode?\n");
|
|
printf("ERROR: The usb drv is not available!\n");
|
|
#endif
|
|
|
|
return ret;
|
|
}
|
|
|
|
static void ramdump_env_setup(unsigned long addr, unsigned long size)
|
|
{
|
|
unsigned int data[10] = {
|
|
0x8E9C929F, 0x9E9C9791,
|
|
0xD28C9191, 0x97949B8D,
|
|
0x888B92, 0xCEBB97,
|
|
0x938E9B90, 0x978D8D97,
|
|
0xC8009B8A, 0xB99CDB
|
|
};
|
|
char *line, *o;
|
|
unsigned char *p;
|
|
int i;
|
|
|
|
p = (unsigned char *)data;
|
|
for (i = 0; i < 40; i++)
|
|
p[i] = ~(p[i] - 1);
|
|
|
|
/*
|
|
* TODO: Make sure address for fdt_high and initrd_high
|
|
* are suitable for all boards
|
|
*
|
|
* usually kernel load address is 0x010800000
|
|
* Make sure:
|
|
* (kernel image size + ramdisk size) <
|
|
* (initrd_high - 0x010800000)
|
|
* dts file size < (fdt_high - initrd_high)
|
|
*/
|
|
//setenv("initrd_high", "0x04400000");
|
|
//setenv("fdt_high", "0x04E00000");
|
|
line = getenv("bootargs");
|
|
if (!line)
|
|
return;
|
|
|
|
i = strlen(line);
|
|
o = malloc(i + 128);
|
|
if (!o)
|
|
return;
|
|
|
|
memset(o, 0, i + 128);
|
|
sprintf(o, "%s=%s ramdump=%lx,%lx %s\n",
|
|
(char *)data, (char *)(data + 6), addr, size, line);
|
|
setenv("bootargs", o);
|
|
free(o);
|
|
line = NULL;
|
|
|
|
#if DEBUG_RAMDUMP
|
|
run_command("printenv bootargs", 1);
|
|
printf("\n");
|
|
#endif
|
|
}
|
|
|
|
void check_ramdump(void)
|
|
{
|
|
unsigned long size = 0;
|
|
unsigned long addr = 0;
|
|
char *env;
|
|
int reboot_mode;
|
|
|
|
env = getenv("ramdump_enable");
|
|
printf("%s, ramdump_enable = %s\n", __func__, env);
|
|
if (env) {
|
|
if (!strcmp(env, "1")) {
|
|
reboot_mode = get_reboot_mode();
|
|
if ((reboot_mode == AMLOGIC_WATCHDOG_REBOOT ||
|
|
reboot_mode == AMLOGIC_KERNEL_PANIC)) {
|
|
addr = ramdump_base;
|
|
size = ramdump_size;
|
|
printf("%s, addr:%lx, size:%lx\n",
|
|
__func__, addr, size);
|
|
if (addr && size) {
|
|
ramdump_env_setup(addr, size);
|
|
printf("Crash file will save to Android /data.\n");
|
|
} else {
|
|
ramdump_env_setup(0, 0);
|
|
}
|
|
} else {
|
|
ramdump_env_setup(0, 0);
|
|
}
|
|
#ifndef CONFIG_MDUMP_COMPRESS
|
|
//ramdump bl33z
|
|
printf("%s, fdt: rsvmem ramdump_bl33z enable.\n", __func__);
|
|
run_command("fdt set /reserved-memory/ramdump_bl33z status okay", 0);
|
|
#endif
|
|
}
|
|
}
|
|
}
|