sdk-hwV1.3/lichee/brandy-2.0/spl/nboot/main/load_image.c

466 lines
17 KiB
C

/*
* (C) Copyright 2018-2020
* Allwinner Technology Co., Ltd. <www.allwinnertech.com>
* wangwei <wangwei@allwinnertech.com>
*
*/
#include <common.h>
#include <spare_head.h>
#include <nand_boot0.h>
#include <private_toc.h>
#include <private_boot0.h>
#include <private_uboot.h>
#include <private_tee.h>
#include <private_atf.h>
#include <u-boot/zlib.h>
#include <lzma/LzmaTools.h>
#include <u-boot/lz4.h>
#include <boot_param.h>
#ifdef CFG_SUNXI_FDT_ADDR
#ifdef CFG_RESERVE_FDT_SIZE
#include <libfdt.h>
#include <cache_align.h>
#endif
#endif
#define TOC1_HEAD_NAME "sunxi-secure"
static unsigned int card_work_mode;
typedef struct _sunxi_image_head
{
unsigned int jump_instruction;
unsigned char magic[MAGIC_SIZE];
unsigned int res1;
unsigned int res2;
unsigned int res3;
unsigned int res4;
unsigned char res5[8];
unsigned char res6[8];
int run_addr;
}sunxi_image_head;
__attribute__((section(".data"))) struct fdt_header *working_fdt;
extern const boot0_file_head_t BT0_head;
static void update_opensbi_param(void *image_base)
{
struct private_atf_head *opensbi_head = (struct private_atf_head *)image_base;
if (strncmp((const char *)opensbi_head->magic, "opensbi", 7) == 0) {
memcpy(opensbi_head->platform, &BT0_head.prvt_head.jtag_gpio[4], 8);
}
}
int toc1_flash_read(u32 start_sector, u32 blkcnt, void *buff)
{
void __iomem *addr = sunxi_get_iobase(CONFIG_BOOTPKG_BASE + 512 * start_sector);
memcpy(buff, (addr), 512 * blkcnt);
return blkcnt;
}
phys_addr_t toc1_get_image_addr(u32 start_sector)
{
sunxi_image_head *image_head = (sunxi_image_head *)(sunxi_get_iobase(CONFIG_BOOTPKG_BASE + 512 * start_sector));
return image_head->run_addr;
}
unsigned int get_card_work_mode(void)
{
return card_work_mode;
}
static void set_card_work_mode(unsigned int mode)
{
card_work_mode = mode;
}
int load_image(phys_addr_t *uboot_base, phys_addr_t *optee_base, \
phys_addr_t *monitor_base, phys_addr_t *rtos_base, phys_addr_t *opensbi_base,
phys_addr_t *cpus_rtos_base)
{
int i;
//int len;
__maybe_unused void *dram_para_addr = (void *)sunxi_bootparam_get_dram_buf();
phys_addr_t image_base;
void __iomem *bootpkg_base = sunxi_get_iobase(CONFIG_BOOTPKG_BASE);
struct sbrom_toc1_head_info *toc1_head = NULL;
struct sbrom_toc1_item_info *item_head = NULL;
struct sbrom_toc1_item_info *toc1_item = NULL;
toc1_head = (struct sbrom_toc1_head_info *)bootpkg_base;
item_head = (struct sbrom_toc1_item_info *)(bootpkg_base + sizeof(struct sbrom_toc1_head_info));
#ifdef BOOT_DEBUG
printf("*******************TOC1 Head Message*************************\n");
printf("Toc_name = %s\n", toc1_head->name);
printf("Toc_magic = 0x%x\n", toc1_head->magic);
printf("Toc_add_sum = 0x%x\n", toc1_head->add_sum);
printf("Toc_serial_num = 0x%x\n", toc1_head->serial_num);
printf("Toc_status = 0x%x\n", toc1_head->status);
printf("Toc_items_nr = 0x%x\n", toc1_head->items_nr);
printf("Toc_valid_len = 0x%x\n", toc1_head->valid_len);
printf("TOC_MAIN_END = 0x%x\n", toc1_head->end);
printf("***************************************************************\n\n");
#endif
//init
toc1_item = item_head;
set_card_work_mode(NOUSE_CARDMODE);
if (!strncmp(toc1_head->name, TOC1_HEAD_NAME, strlen(TOC1_HEAD_NAME))) {
//only nboot + secure toc1
set_card_work_mode(WORK_MODE_CARD_PRODUCT);
}
for(i=0;i<toc1_head->items_nr;i++,toc1_item++)
{
#ifdef BOOT_DEBUG
printf("\n*******************TOC1 Item Message*************************\n");
printf("Entry_name = %s\n", toc1_item->name);
printf("Entry_data_offset = 0x%x\n", toc1_item->data_offset);
printf("Entry_data_len = 0x%x\n", toc1_item->data_len);
printf("encrypt = 0x%x\n", toc1_item->encrypt);
printf("Entry_type = 0x%x\n", toc1_item->type);
printf("run_addr = 0x%x\n", toc1_item->run_addr);
printf("index = 0x%x\n", toc1_item->index);
printf("Entry_end = 0x%x\n", toc1_item->end);
printf("***************************************************************\n\n");
#endif
printf("Entry_name = %s\n", toc1_item->name);
if (toc1_item->type != 3) {
//skip
continue;
}
image_base = toc1_get_image_addr(toc1_item->data_offset/512);
if (strncmp(toc1_item->name, ITEM_UBOOT_NAME, strlen(toc1_item->name)) == 0) {
*uboot_base = image_base;
toc1_flash_read(toc1_item->data_offset/512, (toc1_item->data_len+511)/512, (void *)image_base);
}
#ifdef CFG_SUNXI_GUNZIP
else if ((strncmp(toc1_item->name, ITEM_UBOOT_GZ_NAME, strlen(toc1_item->name)) == 0)) {
void *dst = (void *)0x40000000; /* hardcode here, as we can't get image_base from gz header */
int dstlen = *(unsigned long *)((unsigned char *)CONFIG_BOOTPKG_BASE + toc1_item->data_offset + toc1_item->data_len - 4);
unsigned char *src = (unsigned char *)(CONFIG_BOOTPKG_BASE) + toc1_item->data_offset;
unsigned long srclen = toc1_item->data_len;
unsigned long *lenp = &srclen;
unsigned int l, m, h;
int ret = gunzip(dst, dstlen, src, lenp);
if (ret) {
printf("Error: gunzip returned %d\n", ret);
return -1;
}
sunxi_image_head *image_head = (sunxi_image_head *)dst;
image_base = image_head->run_addr;
/* dst cant in [image_base - dstlen, image_base + dstlen] */
l = (long)(image_base - dstlen);
m = (long)dst;
h = (long)(image_base + dstlen);
if ((m > l) && (m < h)) {
memcpy((void *)(image_base + dstlen), dst, dstlen);
memcpy((void *)image_base, (void *)(image_base + dstlen), dstlen);
} else {
memcpy((void *)image_base, dst, dstlen);
}
*uboot_base = image_base;
}
#endif
#ifdef CFG_SUNXI_LZ4
else if ((strncmp(toc1_item->name, ITEM_UBOOT_LZ4_NAME, strlen(toc1_item->name)) == 0)) {
void *dst = (void *)0x40000000; /* hardcode here, as we can't get image_base from lz4 header */
unsigned int dstlen = 0x800000;
unsigned char *src = (unsigned char *)(CONFIG_BOOTPKG_BASE) + toc1_item->data_offset;
unsigned long srclen = toc1_item->data_len;
int ret = ulz4fn(src, srclen, dst, (size_t *)&dstlen);
unsigned int l, m, h;
if (ret) {
printf("Error: ulz4fn returned %d\n", ret);
return -1;
}
sunxi_image_head *image_head = (sunxi_image_head *)dst;
image_base = image_head->run_addr;
printf("uboot run addr:%x \n", (void *)image_base);
/* dst cant in [image_base - dstlen, image_base + dstlen] */
l = (long)(image_base - dstlen);
m = (long)dst;
h = (long)(image_base + dstlen);
if ((m > l) && (m < h)) {
memcpy((void *)(image_base + dstlen), dst, dstlen);
memcpy((void *)image_base, (void *)(image_base + dstlen), dstlen);
} else {
memcpy((void *)image_base, dst, dstlen);
}
*uboot_base = image_base;
}
#endif
#ifdef CFG_SUNXI_LZMA
else if (strncmp(toc1_item->name, ITEM_UBOOT_LZMA_NAME, strlen(toc1_item->name)) == 0) {
void *dst = (void *)0x40000000; /* hardcode here, as we can't get image_base from gz header */
size_t srclen = ~0U, dstlen = ~0U;
srclen = toc1_item->data_len;
unsigned char *src = (unsigned char *)(CONFIG_BOOTPKG_BASE) + toc1_item->data_offset;
unsigned int l, m, h;
int ret = lzmaBuffToBuffDecompress(dst, &dstlen, src, srclen);
if (ret) {
printf("Error: lzmaBuffToBuffDecompress returned %d\n", ret);
return -1;
}
sunxi_image_head *image_head = (sunxi_image_head *)dst;
image_base = image_head->run_addr;
printf("uboot run addr:%x \n", (void *)image_base);
/* dst cant in [image_base - dstlen, image_base + dstlen] */
l = (long)(image_base - dstlen);
m = (long)dst;
h = (long)(image_base + dstlen);
if ((m > l) && (m < h)) {
memcpy((void *)(image_base + dstlen), dst, dstlen);
memcpy((void *)image_base, (void *)(image_base + dstlen), dstlen);
} else {
memcpy((void *)image_base, dst, dstlen);
}
*uboot_base = image_base;
}
#endif
else if (strncmp(toc1_item->name, ITEM_OPTEE_NAME, sizeof(ITEM_OPTEE_NAME)) == 0) {
*optee_base = image_base;
toc1_flash_read(toc1_item->data_offset/512, (toc1_item->data_len+511)/512, (void *)image_base);
struct spare_optee_head *tee_head = (struct spare_optee_head *)image_base;
memcpy(tee_head->dram_para, sunxi_bootparam_get_dram_buf(), 32*sizeof(int));
memcpy(tee_head->chipinfo, &BT0_head.prvt_head.jtag_gpio[4], 8);
}
else if(strncmp(toc1_item->name, ITEM_MONITOR_NAME, sizeof(ITEM_MONITOR_NAME)) == 0) {
*monitor_base = image_base;
toc1_flash_read(toc1_item->data_offset/512, (toc1_item->data_len+511)/512, (void *)image_base);
struct private_atf_head *atf_head = (struct private_atf_head *)image_base;
memcpy(atf_head->dram_para, sunxi_bootparam_get_dram_buf(), 32 * sizeof(int));
memcpy(atf_head->platform, &BT0_head.prvt_head.jtag_gpio[4], 8);
#ifdef CFG_LOAD_DTB_FROM_KERNEL
atf_head->dtb_base = CFG_SUNXI_FDT_ADDR;
#endif
}
else if(strncmp(toc1_item->name, ITEM_SCP_NAME, sizeof(ITEM_SCP_NAME)) == 0) {
#ifdef SCP_SRAM_BASE
#ifdef SCP_DTS_BASE
struct sbrom_toc1_item_info *toc1_item_scp_dts = item_head;
int scp_j;
for (scp_j = 0; scp_j < toc1_head->items_nr; scp_j++, toc1_item_scp_dts++) {
if (strncmp(toc1_item_scp_dts->name, ITEM_DTB_NAME, sizeof(ITEM_DTB_NAME)) == 0) {
if (toc1_item_scp_dts->data_len > SCP_DTS_SIZE) {
printf("error: dtb size larger than scp dts size\n");
} else {
toc1_flash_read(toc1_item_scp_dts->data_offset/512, (toc1_item_scp_dts->data_len+511)/512, (void *)SCP_DTS_BASE);
}
break;
}
}
if (scp_j == toc1_head->items_nr)
printf("error: dtb not found for scp\n");
#endif
#ifdef SCP_DEASSERT_BY_MONITOR
toc1_flash_read(toc1_item->data_offset / 512,
(SCP_SRAM_SIZE + SCP_DRAM_SIZE + 511) / 512,
(void *)SCP_TEMP_STORE_BASE);
#else
sunxi_assert_arisc();
toc1_flash_read(toc1_item->data_offset / 512,
(SCP_SRAM_SIZE + 511) / 512,
(void *)SCP_SRAM_BASE);
toc1_flash_read((toc1_item->data_offset +
SCP_CODE_DRAM_OFFSET) /
512,
(SCP_DRAM_SIZE + 511) / 512,
(void *)SCP_DRAM_BASE);
memcpy((void *)(SCP_SRAM_BASE + HEADER_OFFSET +
SCP_DRAM_PARA_OFFSET),
dram_para_addr, SCP_DARM_PARA_NUM * sizeof(int));
sunxi_deassert_arisc();
#endif
#endif
} else if (strncmp(toc1_item->name, ITEM_DTB_NAME, sizeof(toc1_item->name)) == 0) {
#ifndef CFG_LOAD_DTB_FROM_KERNEL
/* note , uboot must be less than 2M*/
#ifdef CFG_SUNXI_FDT_ADDR
image_base = CFG_SUNXI_FDT_ADDR;
#else
image_base = *uboot_base + 2*1024*1024;
#endif
working_fdt = (struct fdt_header *)image_base;
struct private_atf_head *atf_head = (struct private_atf_head *)(sunxi_get_iobase(*monitor_base));
atf_head->dtb_base = image_base;
toc1_flash_read(toc1_item->data_offset/512, (toc1_item->data_len+511)/512, (void *)image_base);
#ifdef CFG_SUNXI_FDT_ADDR
#ifdef CFG_RESERVE_FDT_SIZE
u32 fdt_ext_size = ALIGN(CFG_RESERVE_FDT_SIZE, 32);
u32 new_fdt_totalsize = fdt_totalsize(working_fdt);
if (new_fdt_totalsize > fdt_ext_size) {
printf("new fdt(0x%08x) biger than now fdt(0x%08x)\n",
new_fdt_totalsize, fdt_ext_size);
} else {
fdt_set_totalsize(working_fdt, fdt_ext_size);
}
#endif
#endif
#endif //CFG_LOAD_DTB_FROM_KERNEL
}
#ifdef CFG_SUNXI_LZMA
else if (strncmp(toc1_item->name, ITEM_DTB_LZMA_NAME, strlen(ITEM_DTB_LZMA_NAME)) == 0) {
image_base = *uboot_base + 2*1024*1024;
size_t srclen = ~0U, dstlen = ~0U;
srclen = toc1_item->data_len;
unsigned char *src = (unsigned char *)(CONFIG_BOOTPKG_BASE) + toc1_item->data_offset;
struct private_atf_head *atf_head = (struct private_atf_head *)(*monitor_base);
atf_head->dtb_base = image_base;
printf("boot0 lzma dtb\n");
int ret = lzmaBuffToBuffDecompress((void *)image_base, &dstlen, src, srclen);
if (ret) {
printf("Error: lzmaBuffToBuffDecompress returned %d\n", ret);
return -1;
}
}
#endif
#ifdef CFG_SUNXI_LZ4
else if ((strncmp(toc1_item->name, ITEM_DTB_LZ4_NAME, strlen(ITEM_DTB_LZ4_NAME)) == 0)) {
image_base = *uboot_base + 2*1024*1024;
unsigned int dstlen = 0x800000;
unsigned char *src = (unsigned char *)(CONFIG_BOOTPKG_BASE) + toc1_item->data_offset;
unsigned long srclen = toc1_item->data_len;
int ret = ulz4fn(src, srclen, (void *)image_base, (size_t *)&dstlen);
if (ret) {
printf("Error: ulz4fn returned %d\n", ret);
return -1;
}
}
#endif
#ifdef CFG_SUNXI_GUNZIP
else if ((strncmp(toc1_item->name, ITEM_DTB_GZ_NAME, strlen(ITEM_DTB_GZ_NAME)) == 0)) {
image_base = *uboot_base + 2*1024*1024;
int dstlen = *(unsigned long *)((unsigned char *)CONFIG_BOOTPKG_BASE + toc1_item->data_offset + toc1_item->data_len - 4);
unsigned char *src = (unsigned char *)(CONFIG_BOOTPKG_BASE) + toc1_item->data_offset;
unsigned long srclen = toc1_item->data_len;
unsigned long *lenp = &srclen;
int ret = gunzip((void *)image_base, dstlen, src, lenp);
if (ret) {
printf("Error: gunzip returned %d\n", ret);
return -1;
}
}
#endif
else if (strncmp(toc1_item->name, ITEM_DTBO_NAME, sizeof(ITEM_DTBO_NAME)) == 0) {
image_base = *uboot_base + 1*1024*1024;
toc1_flash_read(toc1_item->data_offset/512, (toc1_item->data_len+511)/512, (void *)image_base);
#ifdef CFG_BOOT0_LOGO_TO_KERNEL
} else if (strncmp(toc1_item->name, ITEM_LOGO_NAME,
sizeof(ITEM_LOGO_NAME)) == 0) {
image_base = *uboot_base + 3 * 1024 * 1024;
*(uint *)(image_base) = toc1_item->data_len;
toc1_flash_read(toc1_item->data_offset / 512,
(toc1_item->data_len + 511) / 512,
(void *)(image_base));
printf("load logo to kernel\n");
#else
} else if (strncmp(toc1_item->name, ITEM_LOGO_NAME,
sizeof(ITEM_LOGO_NAME)) == 0) {
image_base = *uboot_base + 3 * 1024 * 1024;
*(uint *)(image_base) = toc1_item->data_len;
toc1_flash_read(toc1_item->data_offset / 512,
(toc1_item->data_len + 511) / 512,
(void *)(image_base + 16));
set_uboot_func_mask(UBOOT_FUNC_MASK_BIT_BOOTLOGO);
#endif
} else if (strncmp(toc1_item->name, ITEM_OPENSBI_NAME, sizeof(ITEM_OPENSBI_NAME)) == 0) {
*opensbi_base = image_base;
toc1_flash_read(toc1_item->data_offset/512, (toc1_item->data_len+511)/512, (void *)image_base);
update_opensbi_param((void *)image_base);
} else if (strncmp(toc1_item->name, ITEM_RTOS_NAME, sizeof(ITEM_RTOS_NAME)) == 0 ||
strncmp(toc1_item->name, ITEM_MELIS_NAME, sizeof(ITEM_MELIS_NAME)) == 0) {
*rtos_base = image_base;
toc1_flash_read(toc1_item->data_offset/512, (toc1_item->data_len+511)/512, (void *)image_base);
} else if (strncmp(toc1_item->name, ITEM_MELIS_CONFIG_NAME, sizeof(ITEM_MELIS_CONFIG_NAME)) == 0) {
image_base = 0x43000000; /* hardcode here, as we can't get image_base from gz header */
printf("image_base:%x\n", image_base);
memcpy((void *)image_base, &toc1_item->data_len, sizeof(toc1_item->data_len));
toc1_flash_read(toc1_item->data_offset/512, (toc1_item->data_len+511)/512, (void *)image_base + 512);
#ifdef CFG_RISCV_E907
} else if (strncmp(toc1_item->name, ITEM_MELIS_ELF_NAME, sizeof(ITEM_MELIS_ELF_NAME)) == 0) {
#ifdef CFG_MELISELF_LOAD_ADDR
image_base = CFG_MELISELF_LOAD_ADDR; /* hardcode here, as we can't get image_base from gz header */
#else
image_base = *uboot_base + 4*1024*1024;
#endif
/* printf("e907_base:%x\n", image_base); */
*cpus_rtos_base = image_base;
//memcpy((void *)image_base, &toc1_item->data_len, sizeof(toc1_item->data_len));
toc1_flash_read(toc1_item->data_offset/512, (toc1_item->data_len+511)/512, (void *)image_base);
#endif
}
#ifdef CFG_SUNXI_GUNZIP
else if ((strncmp(toc1_item->name, ITEM_MELIS_GZ_NAME, sizeof(ITEM_MELIS_GZ_NAME)) == 0) || (strncmp(toc1_item->name, ITEM_RTOS_GZ_NAME, sizeof(ITEM_RTOS_GZ_NAME)) == 0)) {
image_base = 0x40000000; /* hardcode here, as we can't get image_base from gz header */
*rtos_base = image_base;
void *dst = (void *)image_base;
int dstlen = *(unsigned long *)((unsigned char *)CONFIG_BOOTPKG_BASE + toc1_item->data_offset + toc1_item->data_len - 4);
unsigned char *src = (unsigned char *)(CONFIG_BOOTPKG_BASE) + toc1_item->data_offset;
unsigned long srclen = toc1_item->data_len;
unsigned long *lenp = &srclen;
int ret = gunzip(dst, dstlen, src, lenp);
if (ret) {
printf("Error: gunzip returned %d\n", ret);
return -1;
}
update_opensbi_param(dst);
}
#endif
#ifdef CFG_SUNXI_LZ4
else if ((strncmp(toc1_item->name, ITEM_MELIS_LZ4_NAME, sizeof(ITEM_MELIS_LZ4_NAME)) == 0) || (strncmp(toc1_item->name, ITEM_RTOS_LZ4_NAME, sizeof(ITEM_RTOS_LZ4_NAME)) == 0)) {
image_base = 0x40000000; /* hardcode here, as we can't get image_base from lz4 header */
*rtos_base = image_base;
void *dst = (void *)image_base;
unsigned int dstlen = 0x800000;
unsigned char *src = (unsigned char *)(CONFIG_BOOTPKG_BASE) + toc1_item->data_offset;
unsigned long srclen = toc1_item->data_len;
int ret = ulz4fn(src, srclen, dst, (size_t *)&dstlen);
if (ret) {
printf("Error: ulz4fn returned %d\n", ret);
return -1;
}
update_opensbi_param(dst);
}
#endif
#ifdef CFG_SUNXI_LZMA
else if (strncmp(toc1_item->name, ITEM_MELIS_LZMA_NAME, sizeof(ITEM_MELIS_LZMA_NAME)) == 0 || (strncmp(toc1_item->name, ITEM_RTOS_LZMA_NAME, sizeof(ITEM_RTOS_LZMA_NAME)) == 0)) {
image_base = 0x40000000; /* hardcode here, as we can't get image_base from gz header */
*rtos_base = image_base;
size_t src_len = ~0U, dst_len = ~0U;
void *dst = (void *)image_base;
unsigned char *src = (unsigned char *)(CONFIG_BOOTPKG_BASE) + toc1_item->data_offset;
int ret = lzmaBuffToBuffDecompress(dst, &src_len, src, dst_len);
if (ret) {
printf("Error: lzmaBuffToBuffDecompress returned %d\n", ret);
return -1;
}
update_opensbi_param(dst);
}
#endif
}
return 0;
}