190 lines
5.3 KiB
C
190 lines
5.3 KiB
C
/*
|
|
* Copyright (c) LOTUS. All rights reserved.
|
|
*/
|
|
|
|
#define pr_fmt(fmt) "%s: " fmt, "BOOT BL31"
|
|
|
|
#include <common.h>
|
|
#include <image.h>
|
|
#include <linux/compiler.h>
|
|
#include <bootm.h>
|
|
#include <asm/io.h>
|
|
#include <linux/kernel.h>
|
|
#include <asm/mach-types.h>
|
|
#include <linux/libfdt.h>
|
|
#include <mapmem.h>
|
|
#include <serial.h>
|
|
#include <linux/lotus/flash_read.h>
|
|
#include <linux/lotus/timestamp.h>
|
|
#include <linux/lotus/atf.h>
|
|
|
|
#define OPTEE_MAGIC 0x4554504f
|
|
|
|
extern int cleanup_before_linux(void);
|
|
|
|
struct optee_header {
|
|
uint32_t magic;
|
|
uint8_t version;
|
|
uint8_t arch;
|
|
uint16_t flags;
|
|
uint32_t init_size;
|
|
uint32_t init_load_addr_hi;
|
|
uint32_t init_load_addr_lo;
|
|
uint32_t init_mem_usage;
|
|
uint32_t paged_size;
|
|
};
|
|
|
|
int do_load_optee_os(ulong addr, uint32_t *rtos_load_addr, uint32_t *aarch_mode)
|
|
{
|
|
struct optee_header *imgheader = (struct optee_header *)addr;
|
|
char *src = (char *)(addr + sizeof(struct optee_header)), *dst = (char *)imgheader->init_load_addr_lo;
|
|
uint32_t loadaddr, img_size;
|
|
|
|
printf("## OpenTEE OS Image:\n");
|
|
printf(" version: 0x%X\n", imgheader->version);
|
|
printf(" arch: %s\n", ((imgheader->version) ? "arm32" : "arm64"));
|
|
printf(" init_size: 0x%X\n", imgheader->init_size);
|
|
printf(" load_addr_hi: 0x%x (%u KB)\n", imgheader->init_load_addr_hi, imgheader->init_load_addr_hi >> 10);
|
|
printf(" load_addr_lo: 0x%x (%u KB)\n", imgheader->init_load_addr_lo, imgheader->init_load_addr_lo >> 10);
|
|
printf(" init_mem_usage: %d\n", imgheader->init_mem_usage);
|
|
printf(" Tpaged_size: 0x%X (%u KB)\n", imgheader->paged_size, imgheader->paged_size >> 10);
|
|
|
|
if (aarch_mode)
|
|
*aarch_mode = (imgheader->version == 1 ? MODE_RW_32 : MODE_RW_64);
|
|
|
|
loadaddr = imgheader->init_load_addr_lo;
|
|
img_size = imgheader->init_size;
|
|
|
|
memmove(dst, src, img_size);
|
|
|
|
if (rtos_load_addr)
|
|
*rtos_load_addr = (uint32_t)imgheader->init_load_addr_lo;
|
|
|
|
printf(" succeed to load Optee-OS to :0x%x\n", loadaddr);
|
|
|
|
return 0;
|
|
}
|
|
|
|
int is_optee_img(char *buf)
|
|
{
|
|
struct optee_header *hdr = (struct optee_header *)buf;
|
|
|
|
if (hdr->magic != OPTEE_MAGIC)
|
|
return 0;
|
|
|
|
return 1;
|
|
}
|
|
|
|
void run_bl31(bootm_headers_t *bootm_hdr, uint32_t machid)
|
|
{
|
|
uint32_t arch;
|
|
image_header_t *hdr = NULL;
|
|
image_info_t os;
|
|
entry_point_info_t bl32_ep;
|
|
entry_point_info_t bl33_ep;
|
|
bl31_params_t bl31_p;
|
|
ulong bl31_pc = 0;
|
|
u32 val = 0;
|
|
void *image_buf;
|
|
ulong image_size;
|
|
char *show_timestamp;
|
|
|
|
if (!bootm_hdr) {
|
|
pr_err("Invalid params for %s\n", __func__);
|
|
return;
|
|
}
|
|
|
|
hdr = &(bootm_hdr->legacy_hdr_os_copy);
|
|
os = bootm_hdr->os;
|
|
image_size = os.image_len;
|
|
image_buf = map_sysmem(os.image_start, image_size);
|
|
|
|
pr_info("Image addr 0x%lX, len 0x%lX\n", (ulong)image_buf, image_size);
|
|
|
|
memset(&bl31_p, 0, sizeof(bl31_params_t));
|
|
memset(&bl32_ep, 0, sizeof(entry_point_info_t));
|
|
memset(&bl33_ep, 0, sizeof(entry_point_info_t));
|
|
bl31_p.bl32_ep_info = (uint64_t)((uint32_t)&bl32_ep);
|
|
bl31_p.bl33_ep_info = (uint64_t)((uint32_t)&bl33_ep);
|
|
|
|
if (image_get_arch(hdr) == IH_ARCH_ARM) {
|
|
arch = BL33_IMG_ARM32;
|
|
pr_info("Start bl31 with aarch32 bl33...\n");
|
|
} else if (image_check_arch(hdr, IH_ARCH_ARM64)) {
|
|
arch = BL33_IMG_ARM64;
|
|
pr_info("Start bl31 with aarch64 bl33...\n");
|
|
} else {
|
|
pr_err("Invalid ARCH Type!\n");
|
|
return;
|
|
}
|
|
|
|
if(arch == BL33_IMG_ARM64) {
|
|
bl33_ep.pc = (uint64_t)(image_get_ep(hdr));
|
|
memmove((char *)CONFIG_DTB_BASE, (char *)(image_buf + image_size), CONFIG_DTB_MAX_SIZE);
|
|
bl33_ep.args.arg0 = (uint64_t)(CONFIG_DTB_BASE);
|
|
bl33_ep.args.arg1 = 0;
|
|
bl33_ep.args.arg2 = 0;
|
|
bl33_ep.args.arg3 = 0;
|
|
bl33_ep.spsr = spsr_64(MODE_EL1,MODE_SP_ELX, DISABLE_ALL_EXCEPTIONS);
|
|
} else if (arch == BL33_IMG_ARM32) {
|
|
bl33_ep.pc = (uint64_t)(image_get_ep(hdr));
|
|
memmove((char *)CONFIG_DTB_BASE, (char *)(image_buf + image_size), CONFIG_DTB_MAX_SIZE);
|
|
bl33_ep.args.arg0 = 0;
|
|
bl33_ep.args.arg1 = (uint64_t)(machid);
|
|
bl33_ep.args.arg2 = (uint64_t)(CONFIG_DTB_BASE);
|
|
bl33_ep.spsr = spsr_mode32(MODE32_SVC, 0x0 , EP_EE_LITTLE, DISABLE_ALL_EXCEPTIONS);
|
|
}
|
|
|
|
if (is_optee_img((char *)CONFIG_BL32_BASE)) {
|
|
uint32_t rtos_load_addr;
|
|
uint32_t aarch_mode;
|
|
|
|
do_load_optee_os(CONFIG_BL32_BASE, &rtos_load_addr, &aarch_mode);
|
|
|
|
bl32_ep.pc = rtos_load_addr;
|
|
bl32_ep.args.arg0 = aarch_mode;
|
|
bl32_ep.args.arg1 = 0;
|
|
bl32_ep.spsr = 0;
|
|
}
|
|
|
|
pr_info("BL33 SPSR: 0x%X\n", bl33_ep.spsr);
|
|
pr_info("DTB: 0x%llX\n", bl33_ep.args.arg0);
|
|
|
|
TIME_STAMP(0);
|
|
stopwatch_trigger();
|
|
show_timestamp = env_get("timestamp");
|
|
if (*show_timestamp == 'y') {
|
|
serial_enable_output(true);
|
|
timestamp_print(0);
|
|
stopwatch_print();
|
|
}
|
|
|
|
bl31_pc = CONFIG_BL31_BASE;
|
|
|
|
writel((u32)(bl31_pc >> 2 & 0xFFFFFFFF), REG_SYS_RVBAR_ADDR0);
|
|
writel(0, REG_SYS_RVBAR_ADDR1);
|
|
writel(readl(REG_SYS_CPU_AARCH_MODE) | (0x3 << 14), REG_SYS_CPU_AARCH_MODE);
|
|
|
|
(*(volatile uint64_t *)0) = (uint64_t)((uintptr_t)&bl31_p);
|
|
(*(volatile uint64_t *)8) = (uint64_t)((uint32_t)NULL);
|
|
|
|
/* __asm__ __volatile__("b ."); */
|
|
|
|
pr_info("Start Warm Reseting\n");
|
|
|
|
cleanup_before_linux();
|
|
|
|
/* warm reseting */
|
|
__asm__ __volatile__("isb\n\r"
|
|
"dsb\n\r"
|
|
"mrc p15, 0, %0, c12, c0, 2\n\r"
|
|
"orr %0, %0, #0x3\n\r"
|
|
"mcr p15, 0, %0, c12, c0, 2\n\r"
|
|
"isb\n\r"
|
|
"wfi":"=r"(val)::"cc");
|
|
pr_err("Fail to warm resetting...\n");
|
|
hang();
|
|
|
|
}
|
|
|