1200 lines
30 KiB
C
1200 lines
30 KiB
C
// SPDX-License-Identifier: (GPL-2.0+ OR MIT)
|
|
/*
|
|
* Copyright (c) 2019 Amlogic, Inc. All rights reserved.
|
|
*/
|
|
|
|
#include <common.h>
|
|
#include <asm/io.h>
|
|
#include <malloc.h>
|
|
#include <errno.h>
|
|
#include <cli.h>
|
|
#include <exports.h>
|
|
#include <asm/amlogic/arch/secure_apb.h>
|
|
#include <abuf.h>
|
|
#include <version.h>
|
|
#include <amlogic/aml_v3_burning.h>
|
|
#include <amlogic/aml_v2_burning.h>
|
|
#include <command.h>
|
|
#include <amlogic/board.h>
|
|
#include <amlogic/cpu_id.h>
|
|
#include <asm-generic/u-boot.h>
|
|
#include <amlogic/aml_profile.h>
|
|
#ifdef CONFIG_AML_CVBS
|
|
#include <amlogic/media/vout/aml_cvbs.h>
|
|
#endif
|
|
#ifdef CONFIG_AML_VPU
|
|
#include <amlogic/media/vpu/vpu.h>
|
|
#endif
|
|
#ifdef CONFIG_AML_VPP
|
|
#include <amlogic/media/vpp/vpp.h>
|
|
#endif
|
|
#ifdef CONFIG_AML_LCD
|
|
#include <amlogic/media/vout/lcd/lcd_vout.h>
|
|
#endif
|
|
#ifdef CONFIG_RX_RTERM
|
|
#include <amlogic/aml_hdmirx.h>
|
|
#endif
|
|
#ifdef CONFIG_AML_VOUT
|
|
#include <amlogic/media/vout/aml_vout.h>
|
|
#endif
|
|
#ifdef CONFIG_ARMV8_MULTIENTRY
|
|
#include <asm/arch-meson/smp.h>
|
|
#endif
|
|
#ifdef CONFIG_AMLOGIC_AMFC
|
|
#include <amlogic/amfc.h>
|
|
#endif
|
|
|
|
#ifdef CONFIG_DDR_FASTBOOT
|
|
#include <amlogic/aml_mmc.h>
|
|
#endif
|
|
|
|
#include <part.h>
|
|
|
|
#include <amlogic/aml_efuse.h>
|
|
#include <amlogic/storage.h>
|
|
#include <asm/amlogic/arch/efuse.h>
|
|
#include <amlogic/emmc_partitions.h>
|
|
#include <amlogic/keyunify.h>
|
|
#include <amlogic/store_wrapper.h>
|
|
#include <u-boot/sha1.h>
|
|
#include <asm/amlogic/arch/bl31_apis.h>
|
|
#ifdef CONFIG_BURN_KEY
|
|
extern efuse_obj_field_t efuse_field;
|
|
#include <hexdump.h>
|
|
#define MAX_LINE_LENGTH 256
|
|
#define MAX_COMMAND_LENGTH 256
|
|
#define HASH_LENGTH 64
|
|
#define MAX_KEY_LENGTH 64
|
|
char command[MAX_COMMAND_LENGTH];
|
|
#endif
|
|
#if defined(CONFIG_AML_ANTIROLLBACK) || defined(CONFIG_AML_AVB2_ANTIROLLBACK)
|
|
#include <amlogic/anti-rollback.h>
|
|
#endif
|
|
|
|
DECLARE_GLOBAL_DATA_PTR;
|
|
#define UNUSED(x) (void)(x)
|
|
|
|
#ifdef CONFIG_MISC_INIT_R
|
|
#define _AML_MISC_INTERRUPT_KEY 0x09
|
|
static int _aml_interrupt_key_pressed;
|
|
static int ctrli(void)
|
|
{
|
|
if (1/*gd->have_console*/) {
|
|
if (tstc()) {
|
|
switch (getchar()) {
|
|
case _AML_MISC_INTERRUPT_KEY:/* ^I - Control I */
|
|
_aml_interrupt_key_pressed = 1;
|
|
printf("Detect Ctrl I...\t\nInput yes to force stopped anyway:\t");
|
|
return 1;
|
|
default:
|
|
break;
|
|
}
|
|
}
|
|
}
|
|
|
|
return 0;
|
|
}
|
|
|
|
static int aml_misc_confirm_yesno(const int tm/*timeout in ms*/)
|
|
{
|
|
int i;
|
|
unsigned long ts;
|
|
char str_input[5];
|
|
|
|
_aml_interrupt_key_pressed = 0;
|
|
if (!ctrli()) {//not detect ctrl-I when bootup
|
|
return 0;
|
|
}
|
|
ts = get_timer(0);
|
|
|
|
for (i = 0; i < sizeof(str_input);) {
|
|
int c = 0;
|
|
|
|
while (!tstc()) {
|
|
if (get_timer(ts) >= tm) {
|
|
printf("Input timeout\n");
|
|
return 0;
|
|
}
|
|
}
|
|
c = getchar();
|
|
if (i == 0 && c == _AML_MISC_INTERRUPT_KEY) {//drop first duplicated ctrlI
|
|
printf("Wait YES/y input\n");
|
|
continue;
|
|
}
|
|
putc(c);
|
|
str_input[i++] = c;
|
|
if (c == '\r')
|
|
break;
|
|
}
|
|
putc('\n');
|
|
if (strncmp(str_input, "y\r", 2) == 0 ||
|
|
strncmp(str_input, "Y\r", 2) == 0 ||
|
|
strncmp(str_input, "yes\r", 4) == 0 ||
|
|
strncmp(str_input, "YES\r", 4) == 0)
|
|
return 1;
|
|
return 0;
|
|
}
|
|
|
|
int misc_init_r(void)
|
|
{
|
|
printf("board common misc_init\n");
|
|
#if defined(CONFIG_MDUMP_COMPRESS) || \
|
|
((defined CONFIG_SUPPORT_BL33Z) && \
|
|
(defined CONFIG_FULL_RAMDUMP))
|
|
extern void ramdump_init(void);
|
|
ramdump_init();
|
|
#endif
|
|
if (!aml_misc_confirm_yesno(5000))
|
|
return 0;
|
|
|
|
cli_init();
|
|
cli_loop();
|
|
panic("No CLI available");
|
|
return 0;
|
|
}
|
|
#endif // #ifdef CONFIG_MISC_INIT_R
|
|
|
|
#ifdef CONFIG_DDR_FASTBOOT
|
|
typedef struct __ddr_savedparams {
|
|
uint8_t d1[16];
|
|
uint32_t data[3072 / 4 - 16 / 4 - 32 / 4];
|
|
uint8_t d2[32];
|
|
} ddr_savedparams_t;
|
|
|
|
static void ddr_save_fastboot_para(void)
|
|
{
|
|
unsigned long addr = 0x2000000UL;
|
|
|
|
if (!memcmp((void *)addr, "DDRPARAMS", 8)) { // match tag
|
|
mmc_write_rsv(MMC_DDR_PARAMETER_NAME, sizeof(ddr_savedparams_t),
|
|
(void *)(addr + 8));
|
|
printf("Saved ddr fastboot\n");
|
|
}
|
|
}
|
|
#endif //CONFIG_DDR_FASTBOOT
|
|
|
|
#ifdef CONFIG_BOARD_LATE_INIT
|
|
int aml_board_late_init_front(void *arg)
|
|
{
|
|
UNUSED(arg);
|
|
printf("init front\n");
|
|
run_command("aml_update_env", 0);
|
|
/* ****************************************************
|
|
* 1.setup bootup resource
|
|
* ****************************************************
|
|
*/
|
|
|
|
#ifdef CONFIG_DDR_FASTBOOT
|
|
ddr_save_fastboot_para();
|
|
#endif
|
|
|
|
board_init_mem();
|
|
run_command("run bcb_cmd", 0);
|
|
|
|
#if CONFIG_IS_ENABLED(AMLOGIC_BT_USB) || CONFIG_IS_ENABLED(AMLOGIC_WIFI_USB2T)
|
|
printf("run usb wifi_start\n");
|
|
run_command("usb wifi_start", 0);
|
|
#endif
|
|
|
|
#ifndef CONFIG_SYSTEM_RTOS //prue rtos not need dtb
|
|
PUSH_TIME_TE("load dtb", BL33_LOAD_DTB_s);
|
|
if (run_command("run common_dtb_load", 0)) {
|
|
printf("Fail in load dtb with cmd[%s], try _aml_dtb\n", env_get("common_dtb_load"));
|
|
//load dtb here then users can directly use 'fdt' command
|
|
run_command("echo reboot_mode ${reboot_mode}; "
|
|
"imgread dtb _aml_dtb ${dtb_mem_addr}; fi;", 0);
|
|
}
|
|
PUSH_TIME_TE("load dtb", BL33_LOAD_DTB_e);
|
|
run_command("if fdt addr ${dtb_mem_addr}; then else echo no dtb at ${dtb_mem_addr};fi;", 0);
|
|
|
|
#ifdef CONFIG_CMD_AML_MODEL
|
|
run_command("check_dtbo", 0);
|
|
#endif
|
|
|
|
#ifdef CONFIG_OF_LIBFDT_OVERLAY
|
|
/*overlay dtbo after selecting dtb*/
|
|
run_command("overlay_dtbo",0);
|
|
#endif
|
|
|
|
/* load unifykey */
|
|
run_command("keyman init 0x1234", 0);
|
|
#endif//#ifndef CONFIG_SYSTEM_RTOS //prue rtos not need dtb
|
|
|
|
#ifdef CONFIG_DIAG_MODE
|
|
u64 rc;
|
|
char diag_state_buf[200] = {0x0};
|
|
int ret = 0;
|
|
|
|
rc = store_part_size("diag_vendor_boot");
|
|
if (rc != -1) {
|
|
printf("diag mode, try dtb from diag again\n");
|
|
if (key_unify_read("diag_state", diag_state_buf, sizeof(diag_state_buf)) != 0) {
|
|
printf("init diag_state to test\n");
|
|
strcpy(diag_state_buf, "Test");
|
|
ret = key_unify_write("diag_state", diag_state_buf, sizeof(diag_state_buf));
|
|
}
|
|
if (strcmp(diag_state_buf, "Test") == 0) {
|
|
printf("reload dtb from diag_vendor_boot\n");
|
|
run_command("run common_dtb_load", 0);
|
|
}
|
|
}
|
|
#endif
|
|
|
|
return 0;
|
|
}
|
|
|
|
#if !defined(SYSCTRL_SEC_STICKY_REG2) && defined(P_PREG_STICKY_REG2)
|
|
#define SYSCTRL_SEC_STICKY_REG2 P_PREG_STICKY_REG2
|
|
#endif//#if !defined(SYSCTRL_SEC_STICKY_REG2) && defined(P_PREG_STICKY_REG2)
|
|
|
|
#ifdef CONFIG_BURN_KEY
|
|
int extract_hash_from_memory(const char *loadaddr, const char *hash_type, char *hash_value)
|
|
{
|
|
const char *current = loadaddr;
|
|
const char *line_start = loadaddr;
|
|
char search_pattern[64];
|
|
|
|
snprintf(search_pattern, sizeof(search_pattern), "HASH_%s_DEVICE_ROOTCERT", hash_type);
|
|
|
|
while (*current != '\0') {
|
|
if (*current == '\n' || *current == '\r') {
|
|
size_t line_length = current - line_start;
|
|
|
|
if (line_length > strlen(search_pattern) &&
|
|
strstr(line_start, search_pattern)) {
|
|
const char *hash_start = strstr(line_start, search_pattern);
|
|
|
|
if (hash_start) {
|
|
hash_start += strlen(search_pattern);
|
|
|
|
while (*hash_start != '\0' && isspace(*hash_start))
|
|
hash_start++;
|
|
|
|
if (strlen(hash_start) >= HASH_LENGTH) {
|
|
memcpy(hash_value, hash_start, HASH_LENGTH);
|
|
hash_value[HASH_LENGTH] = '\0';
|
|
return 1;
|
|
}
|
|
}
|
|
}
|
|
|
|
line_start = current + 1;
|
|
|
|
while (*line_start == '\n' || *line_start == '\r')
|
|
line_start++;
|
|
current = line_start;
|
|
} else {
|
|
current++;
|
|
}
|
|
}
|
|
|
|
return 0;
|
|
}
|
|
|
|
int extract_key_value(const char *loadaddr, char *value)
|
|
{
|
|
const char *current = loadaddr;
|
|
int id_length = 0;
|
|
|
|
while (*current != '\0' && isspace(*current))
|
|
current++;
|
|
|
|
while (*current != '\0' && !isspace(*current) && id_length < MAX_KEY_LENGTH)
|
|
value[id_length++] = *current++;
|
|
|
|
value[id_length] = '\0';
|
|
|
|
return (id_length == MAX_KEY_LENGTH) ? 1 : 0;
|
|
}
|
|
|
|
int aml_burnkey(void)
|
|
{
|
|
int reboot_flag = 0;
|
|
char *rpmb_flag = env_get("rpmb_state");
|
|
int ret = -1;
|
|
unsigned char *loadaddr = 0;
|
|
char hash_value[HASH_LENGTH + 1];
|
|
|
|
loadaddr = (unsigned char *)simple_strtoul(env_get("loadaddr"), NULL, 16);
|
|
#ifdef CONFIG_READ_KEY_FROM_PARAM
|
|
const int partIndex = get_partition_num_by_name("param");
|
|
|
|
env_set_hex("paramPart", partIndex);
|
|
env_set_hex("paramLoadAddr", (ulong)loadaddr);
|
|
#else
|
|
#ifdef CONFIG_READ_KEY_FROM_UDISK
|
|
env_set_hex("udiskLoadAddr", (ulong)loadaddr);
|
|
#endif
|
|
#endif
|
|
|
|
debug("start to burn key\n");
|
|
if (rpmb_flag) {
|
|
if (!strcmp(rpmb_flag, "0")) {
|
|
printf("Do rpmb_init\n");
|
|
run_command("rpmb_init", 0);
|
|
reboot_flag = 1;
|
|
} else {
|
|
printf("RPMB already init\n");
|
|
}
|
|
} else {
|
|
printf("Get RPMB state failed\n");
|
|
}
|
|
|
|
run_command("efuse_obj get_lock HASH_NORMAL_DEVICE_ROOTCERT", 0);
|
|
if (*efuse_field.data == 0) {
|
|
printf("Need burn HASH_NORMAL_DEVICE_ROOTCERT\n");
|
|
#ifdef CONFIG_READ_KEY_FROM_PARAM
|
|
env_set("ext4paramLoadCmd",
|
|
"ext4load mmc 1:${paramPart} ${paramLoadAddr} /pattern.efuse");
|
|
ret = run_command("run ext4paramLoadCmd", 0);
|
|
#else
|
|
#ifdef CONFIG_READ_KEY_FROM_UDISK
|
|
env_set("udiskparamLoadCmd",
|
|
"fatload usb 0 ${udiskLoadAddr} pattern.efuse");
|
|
ret = run_command("run udiskparamLoadCmd", 0);
|
|
#endif
|
|
#endif
|
|
|
|
if (extract_hash_from_memory(loadaddr, "NORMAL", hash_value)) {
|
|
snprintf(command, MAX_COMMAND_LENGTH,
|
|
"efuse_obj set HASH_NORMAL_DEVICE_ROOTCERT %s",
|
|
hash_value);
|
|
printf("command is %s\n", command);
|
|
ret = run_command(command, 0);
|
|
if (ret == 0)
|
|
ret = run_command("efuse_obj lock HASH_NORMAL_DEVICE_ROOTCERT", 0);
|
|
else
|
|
return -1;
|
|
} else {
|
|
printf("read HASH_NORMAL_DEVICE_ROOTCERT error\n");
|
|
return -1;
|
|
}
|
|
}
|
|
|
|
run_command("efuse_obj get_lock HASH_DFU_DEVICE_ROOTCERT", 0);
|
|
if (*efuse_field.data == 0) {
|
|
printf("Need burn HASH_DFU_DEVICE_ROOTCERT\n");
|
|
#ifdef CONFIG_READ_KEY_FROM_PARAM
|
|
env_set("ext4paramLoadCmd",
|
|
"ext4load mmc 1:${paramPart} ${paramLoadAddr} /pattern.efuse");
|
|
ret = run_command("run ext4paramLoadCmd", 0);
|
|
#else
|
|
#ifdef CONFIG_READ_KEY_FROM_UDISK
|
|
env_set("udiskparamLoadCmd",
|
|
"fatload usb 0 ${udiskLoadAddr} pattern.efuse");
|
|
ret = run_command("run udiskparamLoadCmd", 0);
|
|
#endif
|
|
#endif
|
|
|
|
if (extract_hash_from_memory(loadaddr, "DFU", hash_value)) {
|
|
snprintf(command, MAX_COMMAND_LENGTH,
|
|
"efuse_obj set HASH_NORMAL_DEVICE_ROOTCERT %s",
|
|
hash_value);
|
|
debug("command is %s\n", command);
|
|
ret = run_command(command, 0);
|
|
if (ret == 0)
|
|
ret = run_command("efuse_obj lock HASH_DFU_DEVICE_ROOTCERT", 0);
|
|
else
|
|
return -1;
|
|
} else {
|
|
printf("read HASH_NORMAL_DEVICE_ROOTCERT error\n");
|
|
return -1;
|
|
}
|
|
}
|
|
|
|
ret = run_command("ampk regen_enc_key", 0);
|
|
debug("ampk regen_enc_key ret = %d\n", ret);
|
|
|
|
run_command("efuse_obj get_lock AUDIO_VENDOR_ID", 0);
|
|
if (*efuse_field.data == 0) {
|
|
printf("Need burn AUDIO_VENDOR_ID\n");
|
|
char audio_id[MAX_KEY_LENGTH + 1];
|
|
#ifdef CONFIG_READ_KEY_FROM_PARAM
|
|
env_set("ext4paramLoadCmd",
|
|
"ext4load mmc 1:${paramPart} ${paramLoadAddr} /eaudio_id.txt");
|
|
ret = run_command("run ext4paramLoadCmd", 0);
|
|
#else
|
|
#ifdef CONFIG_READ_KEY_FROM_UDISK
|
|
env_set("udiskparamLoadCmd",
|
|
"fatload usb 0 ${udiskLoadAddr} eaudio_id.txt");
|
|
ret = run_command("run udiskparamLoadCmd", 0);
|
|
#endif
|
|
#endif
|
|
|
|
if (extract_key_value(loadaddr, audio_id)) {
|
|
snprintf(command, sizeof(command),
|
|
"efuse_obj set_enc AUDIO_VENDOR_ID %s", audio_id);
|
|
debug("command is %s\n", command);
|
|
ret = run_command(command, 0);
|
|
if (ret == 0) {
|
|
printf("Lock AUDIO_VENDOR_ID\n");
|
|
ret = run_command("efuse_obj lock AUDIO_VENDOR_ID", 0);
|
|
if (ret == 0) {
|
|
reboot_flag = 1;
|
|
} else {
|
|
printf("Lock AUDIO_VENDOR_ID error\n");
|
|
return -1;
|
|
}
|
|
} else {
|
|
printf("burn AUDIO_VENDOR_ID error\n");
|
|
return -1;
|
|
}
|
|
} else {
|
|
printf("read AUDIO_VENDOR_ID error\n");
|
|
return -1;
|
|
}
|
|
} else {
|
|
printf("AUDIO_VENDOR_ID already set\n");
|
|
}
|
|
|
|
run_command("efuse_obj get_lock DGPK1", 0);
|
|
if (*efuse_field.data == 0) {
|
|
printf("Need burn DGPK1\n");
|
|
char dgpk_value[MAX_KEY_LENGTH + 1];
|
|
#ifdef CONFIG_READ_KEY_FROM_PARAM
|
|
env_set("ext4paramLoadCmd",
|
|
"ext4load mmc 1:${paramPart} ${paramLoadAddr} /edgpk1.txt");
|
|
ret = run_command("run ext4paramLoadCmd", 0);
|
|
#else
|
|
#ifdef CONFIG_READ_KEY_FROM_UDISK
|
|
env_set("udiskparamLoadCmd",
|
|
"fatload usb 0 ${udiskLoadAddr} edgpk1.txt");
|
|
ret = run_command("run udiskparamLoadCmd", 0);
|
|
#endif
|
|
#endif
|
|
|
|
if (extract_key_value(loadaddr, dgpk_value)) {
|
|
snprintf(command, sizeof(command),
|
|
"efuse_obj set_enc DGPK1 %s", dgpk_value);
|
|
debug("command is %s\n", command);
|
|
ret = run_command(command, 0);
|
|
if (ret == 0) {
|
|
printf("Lock DGPK1\n");
|
|
ret = run_command("efuse_obj lock DGPK1", 0);
|
|
if (ret == 0) {
|
|
reboot_flag = 1;
|
|
} else {
|
|
printf("Lock DGPK1 error\n");
|
|
return -1;
|
|
}
|
|
} else {
|
|
printf("burn DGPK1 error\n");
|
|
return -1;
|
|
}
|
|
} else {
|
|
printf("read DGPK1 error\n");
|
|
return -1;
|
|
}
|
|
} else {
|
|
printf("DGPK1 already set\n");
|
|
}
|
|
|
|
if (reboot_flag) {
|
|
printf("Need reboot\n");
|
|
#ifdef CONFIG_FACTORY_BURN_MODE
|
|
run_command("bcb factory", 0);
|
|
#else
|
|
#ifdef CONFIG_DIAG_MODE
|
|
run_command("reboot", 0);
|
|
#endif
|
|
#endif
|
|
}
|
|
|
|
return 0;
|
|
}
|
|
#endif
|
|
|
|
#ifdef CONFIG_DIAG_MODE
|
|
static void set_userdata_size(void)
|
|
{
|
|
#ifdef CONFIG_MMC_MESON_GX
|
|
char userdata_size_str[128] = {0};
|
|
unsigned long userdata_size = 0;
|
|
struct blk_desc *dev_desc;
|
|
disk_partition_t part_info;
|
|
int r;
|
|
char name[32] = {0};
|
|
u64 rc = 0;
|
|
|
|
memset(userdata_size_str, 0, 32);
|
|
dev_desc = blk_get_dev("mmc", 1);
|
|
if (!dev_desc || dev_desc->type == DEV_TYPE_UNKNOWN) {
|
|
printf("invalid mmc device\n");
|
|
goto exit;
|
|
}
|
|
|
|
rc = store_part_size("userdata");
|
|
if (-1 == rc)
|
|
strcpy(name, "data");
|
|
else
|
|
strcpy(name, "userdata");
|
|
|
|
r = part_get_info_by_name(dev_desc, name, &part_info);
|
|
if (r < 0) {
|
|
printf("partition not found\n");
|
|
goto exit;
|
|
}
|
|
|
|
userdata_size = part_info.size / 2;
|
|
sprintf(userdata_size_str, "%ldK", userdata_size);
|
|
debug("userdata_size_str = %s\n", userdata_size_str);
|
|
env_set("userdata_size", userdata_size_str);
|
|
return;
|
|
#endif
|
|
|
|
exit:
|
|
env_set("userdata_size", "0");
|
|
}
|
|
|
|
int aml_diag_lock(int state)
|
|
{
|
|
char *rpmb_flag = env_get("rpmb_state");
|
|
|
|
if (rpmb_flag && strcmp(rpmb_flag, "0")) {
|
|
char *lock_s = env_get("lock");
|
|
LockData_t info = { 0 };
|
|
int erase_flag = 0;
|
|
char lock_d[LOCK_DATA_SIZE];
|
|
|
|
memset(&info, 0, sizeof(struct LockData));
|
|
info.version_major = (int)(lock_s[0] - '0');
|
|
info.version_minor = (int)(lock_s[1] - '0');
|
|
info.unlock_ability = (int)(lock_s[2] - '0');
|
|
info.lock_state = (int)(lock_s[4] - '0');
|
|
info.lock_critical_state = (int)(lock_s[5] - '0');
|
|
info.lock_bootloader = (int)(lock_s[6] - '0');
|
|
|
|
#if defined(CONFIG_AML_ANTIROLLBACK) || defined(CONFIG_AML_AVB2_ANTIROLLBACK)
|
|
uint32_t lock_state = 0;
|
|
|
|
debug("avb arb mode\n");
|
|
if (is_avb_arb_available()) {
|
|
if (get_avb_lock_state(&lock_state)) {
|
|
if (state == 0 &&
|
|
(info.lock_state == 1 || lock_state == 1)) {
|
|
debug("device is locked, need unlock\n");
|
|
if (avb_unlock())
|
|
erase_flag = 1;
|
|
} else if (state == 1 &&
|
|
(info.lock_state == 0 || lock_state == 0)) {
|
|
debug("device is unlocked, need lock\n");
|
|
if (avb_lock())
|
|
erase_flag = 1;
|
|
}
|
|
}
|
|
}
|
|
#endif
|
|
|
|
if (state == 0 && info.lock_state == 1) {
|
|
debug("device is locked, need unlock\n");
|
|
info.lock_state = 0;
|
|
info.lock_critical_state = 0;
|
|
erase_flag = 1;
|
|
env_set("lock_state", "green");
|
|
sprintf(lock_d, "%d%d%d0%d%d%d0", info.version_major, info.version_minor,
|
|
info.unlock_ability, info.lock_state, info.lock_critical_state,
|
|
info.lock_bootloader);
|
|
debug("lock_d state: %s\n", lock_d);
|
|
env_set("lock", lock_d);
|
|
#if CONFIG_IS_ENABLED(AML_UPDATE_ENV)
|
|
run_command("update_env_part -p lock;", 0);
|
|
#else
|
|
run_command("defenv_reserv; saveenv;", 0);
|
|
#endif
|
|
} else if (state == 1 && info.lock_state == 0) {
|
|
debug("device is unlocked, need lock\n");
|
|
info.lock_state = 1;
|
|
erase_flag = 1;
|
|
env_set("lock_state", "orange");
|
|
sprintf(lock_d, "%d%d%d0%d%d%d0", info.version_major, info.version_minor,
|
|
info.unlock_ability, info.lock_state, info.lock_critical_state,
|
|
info.lock_bootloader);
|
|
debug("lock_d state: %s\n", lock_d);
|
|
env_set("lock", lock_d);
|
|
#if CONFIG_IS_ENABLED(AML_UPDATE_ENV)
|
|
run_command("update_env_part -p lock;", 0);
|
|
#else
|
|
run_command("defenv_reserv; saveenv;", 0);
|
|
#endif
|
|
}
|
|
|
|
if (erase_flag == 1)
|
|
run_command("store erase metadata 0 0", 0);
|
|
}
|
|
return 0;
|
|
}
|
|
|
|
int aml_diag_burn(void)
|
|
{
|
|
const int bootCpyIndex = store_bootup_bootidx("bootloader");
|
|
|
|
if (!IS_FEAT_BOOT_VERIFY() &&
|
|
bootCpyIndex == 1) {
|
|
//aml_burnkey();
|
|
run_command("provision_dgpk1 1", 0);
|
|
}
|
|
|
|
aml_diag_lock(0);
|
|
|
|
return 0;
|
|
}
|
|
|
|
static bool find_partition(const char *name, const char **parts, int num)
|
|
{
|
|
for (int i = 0; i < num; i++) {
|
|
if (strncmp(name, parts[i], PART_NAME_LEN) == 0)
|
|
return true;
|
|
}
|
|
return false;
|
|
}
|
|
|
|
static int remove_diag_partitions(void)
|
|
{
|
|
const char * diag_parts[] = {"diag_boot", "diag_vendor_boot", "diag_super", "diag_userdata"};
|
|
int num = 0;
|
|
int valid_parts = 0, p, ret = 0;
|
|
disk_partition_t info;
|
|
struct blk_desc *dev_desc = NULL;
|
|
disk_partition_t *parts = NULL;
|
|
char disk_guid[UUID_STR_LEN + 1] = {0};
|
|
char cmds[32];
|
|
|
|
num = sizeof(diag_parts) / sizeof(char *);
|
|
|
|
for (int i = 0; i < num; i++) {
|
|
snprintf(cmds, 32, "amlmmc erase %s", diag_parts[i]);
|
|
ret += run_command(cmds, 0);
|
|
}
|
|
if (ret)
|
|
printf("Erase Diag partitions error\n");
|
|
|
|
dev_desc = blk_get_dev("mmc", 1);
|
|
if (!dev_desc) {
|
|
printf("%s: %s dev %d NOT available\n", __func__, "mmc", 1);
|
|
return -ENODEV;
|
|
}
|
|
get_disk_guid(dev_desc, disk_guid);
|
|
|
|
/* allocate memory for partitions */
|
|
parts = calloc(sizeof(disk_partition_t), MAX_SEARCH_PARTITIONS);
|
|
if (!parts)
|
|
return -ENOMEM;
|
|
|
|
for (p = 1; p <= MAX_SEARCH_PARTITIONS; p++) {
|
|
ret = part_get_info(dev_desc, p, &info);
|
|
if (ret)
|
|
continue;
|
|
if (find_partition(info.name, diag_parts, num)) {
|
|
printf("remove partition name:%s\n", info.name);
|
|
continue;
|
|
}
|
|
if (strncmp(info.name, "userdata", PART_NAME_LEN) == 0) {
|
|
debug("name:%s, start:0x%lx, dev_desc->lba:%lx\n",
|
|
info.name, info.start, dev_desc->lba);
|
|
/*follow up caculate method in write_mbr_and_gpt_partitions which is used in 'flash' gpt bin*/
|
|
__le64 last_usable_lba = cpu_to_le64(dev_desc->lba - 34);
|
|
__le64 ending_lba = ((last_usable_lba >> 12) << 12) - 1;
|
|
info.size = ending_lba - info.start + 1;
|
|
if (info.size < 0) {
|
|
info.size = 0;
|
|
}
|
|
}
|
|
memcpy(&parts[valid_parts], &info, sizeof(disk_partition_t));
|
|
valid_parts++;
|
|
}
|
|
if (valid_parts == 0) {
|
|
printf("** No valid partitions found **\n");
|
|
free(parts);
|
|
return -ENODEV;
|
|
}
|
|
|
|
/* save partitions layout to disk */
|
|
debug("partitions num:%d\n", valid_parts);
|
|
ret = gpt_restore(dev_desc, disk_guid, parts, valid_parts);
|
|
if (ret)
|
|
printf("update gpt failed:%d\n", ret);
|
|
free(parts);
|
|
|
|
return ret;
|
|
}
|
|
#endif
|
|
|
|
#ifdef CONFIG_FACTORY_BURN_MODE
|
|
int aml_factory_burn(void)
|
|
{
|
|
char *factorytest = env_get("factorytest");
|
|
const int bootCpyIndex = store_bootup_bootidx("bootloader");
|
|
char *rebootmode = env_get("reboot_mode");
|
|
//char *rpmb_flag = env_get("rpmb_state");
|
|
|
|
debug("bootCpyIndex is %d\n", bootCpyIndex);
|
|
if (bootCpyIndex == 2 &&
|
|
factorytest && (strcmp(factorytest, "1") == 0)) {
|
|
printf("bootup from boot1, copy boot1 to boot0\n");
|
|
run_command("copy_slot_bootable 2 1", 0);
|
|
env_set("factorytest", "0");
|
|
#if CONFIG_IS_ENABLED(AML_UPDATE_ENV)
|
|
run_command("update_env_part -p factorytest;", 0);
|
|
#else
|
|
run_command("defenv_reserv; saveenv;", 0);
|
|
#endif
|
|
if (rebootmode && (strcmp(rebootmode, "quiescent") == 0))
|
|
run_command("reboot quiescent", 0);
|
|
else
|
|
run_command("reboot", 0);
|
|
}
|
|
|
|
if ((!factorytest || (factorytest && strcmp(factorytest, "1"))) &&
|
|
!IS_FEAT_BOOT_VERIFY()) {
|
|
printf("normal mode, set factorytest 1\n");
|
|
factorytest = "1";
|
|
env_set("factorytest", "1");
|
|
#if CONFIG_IS_ENABLED(AML_UPDATE_ENV)
|
|
run_command("update_env_part -p factorytest;", 0);
|
|
#else
|
|
run_command("defenv_reserv; saveenv;", 0);
|
|
#endif
|
|
}
|
|
|
|
if (factorytest && (strcmp(factorytest, "1") == 0) &&
|
|
!IS_FEAT_BOOT_VERIFY() &&
|
|
bootCpyIndex == 1)
|
|
aml_burnkey();
|
|
|
|
return 0;
|
|
}
|
|
|
|
int hexstr_to_bin(const char *hexstr, u_char *bin, int bin_len)
|
|
{
|
|
int i, len = strlen(hexstr);
|
|
int bytes = len / 2;
|
|
|
|
if (bytes > bin_len)
|
|
return -1;
|
|
|
|
for (i = 0; i < bytes; i++) {
|
|
char high = hexstr[2 * i];
|
|
char low = hexstr[2 * i + 1];
|
|
|
|
bin[i] = (hex_to_bin(high) << 4) | hex_to_bin(low);
|
|
}
|
|
|
|
return bytes;
|
|
}
|
|
|
|
int ascii_hex_to_bin(u_char *ascii_hex, u_char *bin, int max_len, int bin_len)
|
|
{
|
|
if (bin_len > max_len) {
|
|
printf("Error: Binary buffer too small for data length\n");
|
|
return -1;
|
|
}
|
|
|
|
for (int i = 0; i < bin_len; i++) {
|
|
char high = ascii_hex[i * 2];
|
|
char low = ascii_hex[i * 2 + 1];
|
|
|
|
int high_val = hex_to_bin(high);
|
|
int low_val = hex_to_bin(low);
|
|
|
|
if (high_val < 0 || low_val < 0) {
|
|
printf("Error: Invalid hex character at position %d\n", i * 2);
|
|
return -1;
|
|
}
|
|
|
|
bin[i] = (high_val << 4) | low_val;
|
|
}
|
|
|
|
return bin_len;
|
|
}
|
|
|
|
int verify_loaded_data(ulong loadaddr, const char *expected_str)
|
|
{
|
|
u_char expected_bin[256];
|
|
u_char loaded_bin[256];
|
|
u_char *loaded_ascii = (u_char *)loadaddr;
|
|
int expected_len, loaded_len;
|
|
int i;
|
|
|
|
expected_len = hexstr_to_bin(expected_str, expected_bin, sizeof(expected_bin));
|
|
if (expected_len < 0) {
|
|
printf("Invalid expected hex string\n");
|
|
return -1;
|
|
}
|
|
|
|
loaded_len = ascii_hex_to_bin(loaded_ascii, loaded_bin, sizeof(loaded_bin), expected_len);
|
|
if (loaded_len < 0) {
|
|
printf("Failed to convert loaded ASCII hex to binary\n");
|
|
return -1;
|
|
}
|
|
|
|
if (loaded_len != expected_len) {
|
|
printf("Data length mismatch: expected %d, loaded %d\n",
|
|
expected_len, loaded_len);
|
|
return -1;
|
|
}
|
|
|
|
if (memcmp(loaded_bin, expected_bin, expected_len) == 0) {
|
|
printf("Data verification succeeded!\n");
|
|
return 0;
|
|
}
|
|
|
|
printf("Data verification failed!\n");
|
|
|
|
for (i = 0; i < loaded_len; i++) {
|
|
if (loaded_bin[i] != expected_bin[i]) {
|
|
printf("Mismatch at offset %d: loaded=0x%02x, expected=0x%02x\n",
|
|
i, loaded_bin[i], expected_bin[i]);
|
|
break;
|
|
}
|
|
}
|
|
|
|
return -1;
|
|
}
|
|
#endif
|
|
|
|
int aml_board_late_init_tail(void *arg)
|
|
{
|
|
unsigned char chipid[16];
|
|
char con_str[128], env_str[128];
|
|
int con_len = 0;
|
|
|
|
PUSH_TIME_TE("tail init", BL33_TAIL_INIT_s);
|
|
UNUSED(arg);
|
|
printf("init tail\n");
|
|
|
|
#ifdef CONFIG_REPLACE_TV_MODE
|
|
run_command("udisk_burn", 0);
|
|
#endif
|
|
|
|
run_command("amlsecurecheck", 0);
|
|
|
|
#ifdef CONFIG_FACTORY_BURN_MODE
|
|
char *rebootmode = env_get("reboot_mode");
|
|
|
|
if (rebootmode && strcmp(rebootmode, "fastboot") &&
|
|
strcmp(rebootmode, "factory_reset")) {
|
|
int rc = 0;
|
|
#ifdef CONFIG_READ_KEY_FROM_UDISK
|
|
ulong loadaddr;
|
|
char cmd[128];
|
|
|
|
loadaddr = (ulong)env_get_hex("loadaddr", 0x4000);
|
|
|
|
run_command("usb start 0", 0);
|
|
sprintf(cmd, "fatload usb 0 %lx edgpk1.txt", loadaddr);
|
|
rc = run_command(cmd, 0);
|
|
|
|
if (rc) {
|
|
printf("Fail in read efuse file from udisk\n");
|
|
} else {
|
|
printf("read efuse file from udisk ok\n");
|
|
rc = aml_factory_burn();
|
|
/*rc = verify_loaded_data(loadaddr, AML_DGPK1);
|
|
if (rc == 0) {
|
|
printf("verify data ok\n");
|
|
rc = aml_factory_burn();
|
|
}*/
|
|
}
|
|
#else
|
|
#ifdef CONFIG_READ_KEY_FROM_PARAM
|
|
if (!IS_FEAT_BOOT_VERIFY())
|
|
rc = aml_factory_burn();
|
|
#endif
|
|
#endif
|
|
if (rc == 0) {
|
|
printf("enter factory_boot mode\n");
|
|
env_set("factory_mode", "1");
|
|
env_set("EnableSelinux", "permissive");
|
|
run_command("run init_display", 0);
|
|
run_command("run storeargs", 0);
|
|
run_command("run recovery_from_flash", 0);
|
|
}
|
|
}
|
|
#else
|
|
#ifdef CONFIG_DIAG_MODE
|
|
char diag_state_buf[200] = {0x0};
|
|
u64 rc_diag = -1;
|
|
int ret;
|
|
|
|
rc_diag = store_part_size("diag_vendor_boot");
|
|
ret = key_unify_read("diag_state", diag_state_buf,
|
|
sizeof(diag_state_buf));
|
|
|
|
if (ret == 0 &&
|
|
(strcmp(diag_state_buf, "Test") == 0) &&
|
|
(rc_diag != -1) &&
|
|
!IS_FEAT_BOOT_VERIFY()) {
|
|
printf("diag mode, check key burn\n");
|
|
env_set("factorytest", "1");
|
|
aml_diag_burn();
|
|
} else if (ret == 0 &&
|
|
(strcmp(diag_state_buf, "Clean") == 0) &&
|
|
rc_diag != -1) {
|
|
const int bootCpyIndex = store_bootup_bootidx("bootloader");
|
|
char *rebootmode = env_get("reboot_mode");
|
|
|
|
printf("bootCpyIndex in diag Clean is %d\n", bootCpyIndex);
|
|
if (!IS_FEAT_BOOT_VERIFY() &&
|
|
bootCpyIndex == 1) {
|
|
printf("enable secure boot\n");
|
|
run_command("secureboot_enable 0", 0);
|
|
}
|
|
|
|
if (bootCpyIndex == 2) {
|
|
printf("bootup from boot1, copy boot1 to boot0\n");
|
|
run_command("copy_slot_bootable 2 1", 0);
|
|
if (rebootmode && (strcmp(rebootmode, "quiescent") == 0))
|
|
run_command("reboot quiescent", 0);
|
|
else
|
|
run_command("reboot", 0);
|
|
}
|
|
|
|
printf("clean partition table\n");
|
|
ret = remove_diag_partitions();
|
|
|
|
if (ret == 0) {
|
|
aml_diag_lock(1);
|
|
run_command("store erase metadata 0 0", 0);
|
|
run_command("store erase userdata 0 0", 0);
|
|
|
|
printf("write diag_state to Normal\n");
|
|
strcpy(diag_state_buf, "Normal");
|
|
key_unify_write("diag_state", diag_state_buf, sizeof(diag_state_buf));
|
|
run_command("reboot", 0);
|
|
}
|
|
} else if (ret == 0 &&
|
|
(strcmp(diag_state_buf, "Normal") == 0)) {
|
|
printf("normal mode, set userdata size\n");
|
|
set_userdata_size();
|
|
}
|
|
#endif
|
|
#endif
|
|
|
|
run_command("update_tries", 0);
|
|
|
|
//Need save outputmode/connector_type to flash if changed after display drv init
|
|
if (env_get("outputmode"))
|
|
con_len = sprintf(con_str, "outputmode");
|
|
if (env_get("connector0_type"))
|
|
con_len += sprintf(con_str + con_len, " connector0_type");
|
|
if (env_get("connector1_type"))
|
|
con_len += sprintf(con_str + con_len, " connector1_type");
|
|
if (env_get("connector2_type"))
|
|
con_len += sprintf(con_str + con_len, " connector2_type");
|
|
if (con_len) {
|
|
sprintf(env_str, "printenv %s", con_str);
|
|
run_command(env_str, 0);
|
|
sprintf(env_str, "update_env_part -p -f %s", con_str);
|
|
run_command(env_str, 0);
|
|
}
|
|
|
|
memset(chipid, 0, 16);
|
|
env_set("cpu_id", "1234567890");
|
|
if (get_chip_id(chipid, 16) != -1) {
|
|
char chipid_str[32];
|
|
char chipid_env[32];
|
|
int i, j;
|
|
char buf_tmp[4];
|
|
|
|
memset(chipid_str, 0, 32);
|
|
memset(chipid_env, 0, 32);
|
|
|
|
char *buff = &chipid_str[0];
|
|
char *buff2 = &chipid_env[0];
|
|
|
|
for (i = 0, j = 0; i < 12; ++i) {
|
|
sprintf(&buf_tmp[0], "%02x", chipid[15 - i]);
|
|
if (strcmp(buf_tmp, "00") != 0) {
|
|
sprintf(buff + j, "%02x", chipid[15 - i]);
|
|
j = j + 2;
|
|
}
|
|
}
|
|
|
|
for (i = 0, j = 0; i < 12; ++i) {
|
|
sprintf(buff2 + j, "%02x", chipid[15 - i]);
|
|
j = j + 2;
|
|
}
|
|
|
|
env_set("cpuid_env", chipid_env);
|
|
env_set("cpu_id", chipid_str);
|
|
printf("buff: %s\n", buff);
|
|
}
|
|
|
|
//auto enter usb mode after board_late_init if 'adnl.exe setvar burnsteps 0x1b8ec003'
|
|
#if defined(CONFIG_AML_V3_FACTORY_BURN) && defined(CONFIG_AML_V3_USB_TOOl)
|
|
if (readl(SYSCTRL_SEC_STICKY_REG2) == 0x1b8ec003)
|
|
aml_v3_factory_usb_burning(0, gd->bd);
|
|
#endif//#if defined(CONFIG_AML_V3_FACTORY_BURN) && defined(CONFIG_AML_V3_USB_TOOl)
|
|
#ifdef CONFIG_AML_FACTORY_BURN_LOCAL_UPGRADE //try auto upgrade from ext-sdcard
|
|
aml_try_factory_sdcard_burning(0, gd->bd);
|
|
#endif//#ifdef CONFIG_AML_FACTORY_BURN_LOCAL_UPGRADE
|
|
PUSH_TIME_TE("tail init", BL33_TAIL_INIT_e);
|
|
|
|
return 0;
|
|
}
|
|
#endif//#ifdef CONFIG_BOARD_LATE_INIT
|
|
|
|
#ifdef CONFIG_DEBUG_UART_BOARD_INIT
|
|
void board_debug_uart_init(void)
|
|
{
|
|
}
|
|
#endif
|
|
|
|
#ifdef CONFIG_SAVE_UBOOT_LOG
|
|
int uboot_log_replace_addr_with_fdt(void)
|
|
{
|
|
int nodeoffset, err;
|
|
char *pfdtaddr = env_get("fdtaddr");
|
|
long fdt_addr;
|
|
struct fdt_resource res;
|
|
long addr, size;
|
|
int subnode;
|
|
|
|
char *blob;
|
|
|
|
fdt_addr = 0x1000000;
|
|
if (pfdtaddr)
|
|
fdt_addr = simple_strtoul(pfdtaddr, NULL, 16);
|
|
|
|
blob = (char *)fdt_addr;
|
|
nodeoffset = fdt_path_offset(blob, "/reserved-memory/linux,log");
|
|
if (nodeoffset > 0) {
|
|
subnode = nodeoffset;
|
|
err = fdt_get_resource(blob, subnode, "reg", 0, &res);
|
|
if (err >= 0) {
|
|
addr = res.start;
|
|
size = res.end - res.start + 1;
|
|
uboot_log_use_new_addr(addr, size);
|
|
} else {
|
|
printf("%s:%d, %s nodeoffset=%x\n", __func__, __LINE__,
|
|
"/reserved-memory/linux,log", nodeoffset);
|
|
}
|
|
}
|
|
return 0;
|
|
}
|
|
#endif
|
|
|
|
void aml_board_display_env_handler(void)
|
|
{
|
|
char *bootup_display;
|
|
#ifdef CONFIG_AML_LCD
|
|
char lcd_init_str[8];
|
|
#endif
|
|
|
|
run_command("get_rebootmode", 0);
|
|
printf("reboot_mode: %s\n", env_get("reboot_mode"));
|
|
|
|
#ifdef CONFIG_REPLACE_TV_MODE
|
|
run_command("udisk_check", 0);
|
|
#endif
|
|
|
|
run_command("run check_display", 0);
|
|
bootup_display = env_get("bootup_display");
|
|
if (!bootup_display)
|
|
return;
|
|
|
|
printf("bootup_display: %s\n", bootup_display);
|
|
#ifdef CONFIG_AML_LCD
|
|
if (strcmp(bootup_display, "on") == 0)
|
|
snprintf(lcd_init_str, 8, "%d", LCD_INIT_LEVEL_NORMAL);
|
|
else if (strcmp(bootup_display, "preboot") == 0)
|
|
snprintf(lcd_init_str, 8, "%d", LCD_INIT_LEVEL_PREBOOT);
|
|
else
|
|
snprintf(lcd_init_str, 8, "%d", LCD_INIT_LEVEL_PWR_OFF);
|
|
|
|
env_set("lcd_init_level", lcd_init_str);
|
|
//printf("lcd_init_level: %s\n", env_get("lcd_init_level"));
|
|
#endif
|
|
}
|
|
|
|
unsigned int random(void)
|
|
{
|
|
volatile unsigned int val;
|
|
|
|
#ifdef CONFIG_HW_RNG_OLD
|
|
val = readl(RNG_USR_DATA);
|
|
#else
|
|
do {} while (readl(RNG_REE_READY) & 0x1);
|
|
do {} while (readl(RNG_REE_CFG) & 0x1);
|
|
writel(readl(RNG_REE_CFG) | (1 << 31), RNG_REE_CFG);
|
|
do {} while (readl(RNG_REE_CFG) >> 31);
|
|
|
|
val = readl(RNG_REE_OUT0);
|
|
writel(0x1, RNG_REE_READY);
|
|
#endif
|
|
return val;
|
|
}
|
|
|
|
void get_rng_hw(unsigned char *buf, unsigned int size)
|
|
{
|
|
unsigned int *p = (unsigned int *)buf;
|
|
unsigned int cnt, ncnt;
|
|
unsigned int i;
|
|
unsigned int rng;
|
|
|
|
cnt = (size >> 2);
|
|
ncnt = size & 0x3;
|
|
|
|
for (i = 0; i < cnt; i++)
|
|
p[i] = random();
|
|
|
|
if (ncnt) {
|
|
rng = random();
|
|
for (i = 0; i < ncnt; i++)
|
|
buf[cnt * 4 + i] = ((rng >> (i * 8)) & 0xff);
|
|
}
|
|
}
|
|
|
|
int board_rng_seed(struct abuf *buf)
|
|
{
|
|
abuf_init(buf);
|
|
abuf_realloc(buf, 128);
|
|
if (buf->data)
|
|
get_rng_hw(buf->data, buf->size);
|
|
|
|
return 0;
|
|
}
|
|
|
|
#ifdef CONFIG_AML_DEFENV
|
|
const char * const _aml_env_reserv_array[] = {
|
|
"lock",
|
|
"upgrade_step",
|
|
"bootloader_version",
|
|
"hdmimode",
|
|
"is.bestmode",
|
|
"user_frac_rate",
|
|
"dts_to_gpt",
|
|
"fastboot_step",
|
|
"reboot_status",
|
|
"expect_index",
|
|
"recovery_check_part",
|
|
"factorytest",
|
|
"need_erase_key",
|
|
"total_boot_time",
|
|
"usb_burn_state",
|
|
"udisk_burn_state",
|
|
"defenv_para", //set in board_late_init
|
|
"rollback_reason",
|
|
#ifndef CONFIG_CMD_CAR_PARAMS
|
|
"outputmode",
|
|
"connector0_type",
|
|
#endif
|
|
"sw_version", //linux swupdate version
|
|
NULL//Keep NULL be last to tell END
|
|
};
|
|
|
|
const char * const _aml_env_reserv_array1[] = {
|
|
"lock",
|
|
"upgrade_step",
|
|
"bootloader_version",
|
|
"dts_to_gpt",
|
|
"fastboot_step",
|
|
"reboot_status",
|
|
"expect_index",
|
|
"recovery_check_part",
|
|
"defenv_para", //set in board_late_init
|
|
NULL//Keep NULL be last to tell END
|
|
};
|
|
#endif//#ifdef CONFIG_AML_DEFENV
|
|
|