173 lines
4.7 KiB
C
173 lines
4.7 KiB
C
/*
|
|
* Copyright (c) 2024 Espressif Systems (Shanghai) Co., Ltd.
|
|
*
|
|
* SPDX-License-Identifier: Apache-2.0
|
|
*/
|
|
|
|
#include <zephyr/device.h>
|
|
#include <zephyr/kernel.h>
|
|
#include <zephyr/spinlock.h>
|
|
#include <zephyr/kernel_structs.h>
|
|
#include <zephyr/storage/flash_map.h>
|
|
#include <zephyr/drivers/interrupt_controller/intc_esp32.h>
|
|
|
|
#include <soc.h>
|
|
#include <esp_cpu.h>
|
|
#include "esp_rom_uart.h"
|
|
|
|
#include "esp_mcuboot_image.h"
|
|
#include "esp_memory_utils.h"
|
|
|
|
#ifdef CONFIG_SOC_ENABLE_APPCPU
|
|
|
|
#include "bootloader_flash_priv.h"
|
|
|
|
#define sys_mmap bootloader_mmap
|
|
#define sys_munmap bootloader_munmap
|
|
|
|
void esp_appcpu_start(void *entry_point)
|
|
{
|
|
esp_cpu_unstall(1);
|
|
|
|
if (!REG_GET_BIT(SYSTEM_CORE_1_CONTROL_0_REG, SYSTEM_CONTROL_CORE_1_CLKGATE_EN)) {
|
|
REG_SET_BIT(SYSTEM_CORE_1_CONTROL_0_REG, SYSTEM_CONTROL_CORE_1_CLKGATE_EN);
|
|
REG_CLR_BIT(SYSTEM_CORE_1_CONTROL_0_REG, SYSTEM_CONTROL_CORE_1_RUNSTALL);
|
|
REG_SET_BIT(SYSTEM_CORE_1_CONTROL_0_REG, SYSTEM_CONTROL_CORE_1_RESETTING);
|
|
REG_CLR_BIT(SYSTEM_CORE_1_CONTROL_0_REG, SYSTEM_CONTROL_CORE_1_RESETTING);
|
|
}
|
|
|
|
esp_rom_ets_set_appcpu_boot_addr((void *)entry_point);
|
|
|
|
esp_cpu_reset(1);
|
|
}
|
|
|
|
static int load_segment(uint32_t src_addr, uint32_t src_len, uint32_t dst_addr)
|
|
{
|
|
const uint32_t *data = (const uint32_t *)sys_mmap(src_addr, src_len);
|
|
|
|
if (!data) {
|
|
ets_printf("%s: mmap failed", __func__);
|
|
return -1;
|
|
}
|
|
|
|
volatile uint32_t *dst = (volatile uint32_t *)dst_addr;
|
|
|
|
for (int i = 0; i < src_len / 4; i++) {
|
|
dst[i] = data[i];
|
|
}
|
|
|
|
sys_munmap(data);
|
|
|
|
return 0;
|
|
}
|
|
|
|
int IRAM_ATTR esp_appcpu_image_load(unsigned int hdr_offset, unsigned int *entry_addr)
|
|
{
|
|
const uint32_t img_off = FIXED_PARTITION_OFFSET(slot0_appcpu_partition);
|
|
const uint32_t fa_size = FIXED_PARTITION_SIZE(slot0_appcpu_partition);
|
|
const uint8_t fa_id = FIXED_PARTITION_ID(slot0_appcpu_partition);
|
|
int rc = 0;
|
|
|
|
if (entry_addr == NULL) {
|
|
ets_printf("Can't return the entry address. Aborting!\n");
|
|
abort();
|
|
return -1;
|
|
}
|
|
|
|
ets_printf("Loading appcpu image, area id: %d, offset: 0x%x, hdr.off: 0x%x, size: %d kB\n",
|
|
fa_id, img_off, hdr_offset, fa_size / 1024);
|
|
|
|
uint32_t mcuboot_header[8] = {0};
|
|
esp_image_load_header_t image_header = {0};
|
|
|
|
const uint32_t *data = (const uint32_t *)sys_mmap(img_off, 0x40);
|
|
|
|
memcpy((void *)&mcuboot_header, data, sizeof(mcuboot_header));
|
|
memcpy((void *)&image_header, data + (hdr_offset / sizeof(uint32_t)),
|
|
sizeof(esp_image_load_header_t));
|
|
|
|
sys_munmap(data);
|
|
|
|
if (image_header.header_magic == ESP_LOAD_HEADER_MAGIC) {
|
|
ets_printf("MCUboot image format\n");
|
|
} else if ((image_header.header_magic & 0xff) == 0xE9) {
|
|
ets_printf("ESP image format is not supported\n");
|
|
abort();
|
|
} else {
|
|
ets_printf("Unknown or empty image detected. Aborting!\n");
|
|
abort();
|
|
}
|
|
|
|
if (!esp_ptr_in_iram((void *)image_header.iram_dest_addr) ||
|
|
!esp_ptr_in_iram((void *)(image_header.iram_dest_addr + image_header.iram_size))) {
|
|
ets_printf("IRAM region in load header is not valid. Aborting");
|
|
abort();
|
|
}
|
|
|
|
if (!esp_ptr_in_dram((void *)image_header.dram_dest_addr) ||
|
|
!esp_ptr_in_dram((void *)(image_header.dram_dest_addr + image_header.dram_size))) {
|
|
ets_printf("DRAM region in load header is not valid. Aborting");
|
|
abort();
|
|
}
|
|
|
|
if (!esp_ptr_in_iram((void *)image_header.entry_addr)) {
|
|
ets_printf("Application entry point (%xh) is not in IRAM. Aborting",
|
|
image_header.entry_addr);
|
|
abort();
|
|
}
|
|
|
|
ets_printf("IRAM segment: paddr=%08xh, vaddr=%08xh, size=%05xh (%6d) load\n",
|
|
(img_off + image_header.iram_flash_offset), image_header.iram_dest_addr,
|
|
image_header.iram_size, image_header.iram_size);
|
|
|
|
load_segment(img_off + image_header.iram_flash_offset, image_header.iram_size,
|
|
image_header.iram_dest_addr);
|
|
|
|
ets_printf("DRAM segment: paddr=%08xh, vaddr=%08xh, size=%05xh (%6d) load\n",
|
|
(img_off + image_header.dram_flash_offset), image_header.dram_dest_addr,
|
|
image_header.dram_size, image_header.dram_size);
|
|
|
|
load_segment(img_off + image_header.dram_flash_offset, image_header.dram_size,
|
|
image_header.dram_dest_addr);
|
|
|
|
ets_printf("Application start=%xh\n", image_header.entry_addr);
|
|
esp_rom_uart_tx_wait_idle(0);
|
|
|
|
assert(entry_addr != NULL);
|
|
*entry_addr = image_header.entry_addr;
|
|
|
|
return rc;
|
|
}
|
|
|
|
void esp_appcpu_image_stop(void)
|
|
{
|
|
esp_cpu_stall(1);
|
|
}
|
|
|
|
void esp_appcpu_image_start(unsigned int hdr_offset)
|
|
{
|
|
static int started;
|
|
unsigned int entry_addr = 0;
|
|
|
|
if (started) {
|
|
printk("APPCPU already started.\r\n");
|
|
return;
|
|
}
|
|
|
|
/* Input image meta header, output appcpu entry point */
|
|
esp_appcpu_image_load(hdr_offset, &entry_addr);
|
|
|
|
esp_appcpu_start((void *)entry_addr);
|
|
}
|
|
|
|
int esp_appcpu_init(void)
|
|
{
|
|
/* Load APPCPU image using image header offset
|
|
* (skipping the MCUBoot header)
|
|
*/
|
|
esp_appcpu_image_start(0x20);
|
|
|
|
return 0;
|
|
}
|
|
#endif /* CONFIG_SOC_ENABLE_APPCPU */
|