blob: 62223322502f668323b4211a61fc5028195257fa [file] [log] [blame]
/****************************************************************************
* arch/xtensa/src/common/espressif/esp_loader.c
*
* SPDX-License-Identifier: Apache-2.0
*
* Licensed to the Apache Software Foundation (ASF) under one or more
* contributor license agreements. See the NOTICE file distributed with
* this work for additional information regarding copyright ownership. The
* ASF licenses this file to you under the Apache License, Version 2.0 (the
* "License"); you may not use this file except in compliance with the
* License. You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
* WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
* License for the specific language governing permissions and limitations
* under the License.
*
****************************************************************************/
/****************************************************************************
* Included Files
****************************************************************************/
#include <nuttx/config.h>
#include <stdint.h>
#include <string.h>
#include "xtensa.h"
#include "esp_attr.h"
#include "hal/mmu_hal.h"
#include "hal/mmu_types.h"
#include "hal/cache_types.h"
#include "hal/cache_ll.h"
#include "hal/cache_hal.h"
#include "rom/cache.h"
#include "spi_flash_mmap.h"
#ifndef CONFIG_ARCH_CHIP_ESP32
# include "soc/extmem_reg.h"
#endif
# include "bootloader_flash_priv.h"
#ifdef CONFIG_ESPRESSIF_SIMPLE_BOOT
# include "bootloader_init.h"
# include "esp_rom_uart.h"
# include "esp_rom_sys.h"
# include "esp_app_format.h"
#endif
/****************************************************************************
* Pre-processor Definitions
****************************************************************************/
#define HDR_ATTR __attribute__((section(".entry_addr"))) \
__attribute__((used))
#define MMU_BLOCK_SIZE 0x00010000 /* 64 KB */
#define CACHE_REG EXTMEM_ICACHE_CTRL1_REG
#define CACHE_MASK (EXTMEM_ICACHE_SHUT_IBUS_M | \
EXTMEM_ICACHE_SHUT_DBUS_M)
#define CHECKSUM_ALIGN 16
#define IS_PADD(addr) (addr == 0)
#define IS_DRAM(addr) (addr >= SOC_DRAM_LOW && addr < SOC_DRAM_HIGH)
#define IS_IRAM(addr) (addr >= SOC_IRAM_LOW && addr < SOC_IRAM_HIGH)
#define IS_IROM(addr) (addr >= SOC_IROM_LOW && addr < SOC_IROM_HIGH)
#define IS_DROM(addr) (addr >= SOC_DROM_LOW && addr < SOC_DROM_HIGH)
#define IS_SRAM(addr) (IS_IRAM(addr) || IS_DRAM(addr))
#define IS_MMAP(addr) (IS_IROM(addr) || IS_DROM(addr))
#ifdef SOC_RTC_FAST_MEM_SUPPORTED
# define IS_RTC_FAST_IRAM(addr) \
(addr >= SOC_RTC_IRAM_LOW && addr < SOC_RTC_IRAM_HIGH)
# define IS_RTC_FAST_DRAM(addr) \
(addr >= SOC_RTC_DRAM_LOW && addr < SOC_RTC_DRAM_HIGH)
#else
# define IS_RTC_FAST_IRAM(addr) 0
# define IS_RTC_FAST_DRAM(addr) 0
#endif
#ifdef SOC_RTC_SLOW_MEM_SUPPORTED
# define IS_RTC_SLOW_DRAM(addr) \
(addr >= SOC_RTC_DATA_LOW && addr < SOC_RTC_DATA_HIGH)
#else
# define IS_RTC_SLOW_DRAM(addr) 0
#endif
#define IS_NONE(addr) (!IS_IROM(addr) && !IS_DROM(addr) \
&& !IS_IRAM(addr) && !IS_DRAM(addr) \
&& !IS_RTC_FAST_IRAM(addr) && !IS_RTC_FAST_DRAM(addr) \
&& !IS_RTC_SLOW_DRAM(addr) && !IS_PADD(addr))
#define IS_MAPPING(addr) IS_IROM(addr) || IS_DROM(addr)
/****************************************************************************
* Private Types
****************************************************************************/
extern uint8_t _image_irom_vma[];
extern uint8_t _image_irom_lma[];
extern uint8_t _image_irom_size[];
extern uint8_t _image_drom_vma[];
extern uint8_t _image_drom_lma[];
extern uint8_t _image_drom_size[];
/****************************************************************************
* ROM Function Prototypes
****************************************************************************/
extern int ets_printf(const char *fmt, ...) printf_like(1, 2);
#ifdef CONFIG_ARCH_CHIP_ESP32
extern void cache_read_enable(int cpu);
extern void cache_read_disable(int cpu);
extern void cache_flush(int cpu);
extern unsigned int cache_flash_mmu_set(int cpu_no, int pid,
unsigned int vaddr,
unsigned int paddr,
int psize, int num);
#endif
/****************************************************************************
* Private Functions
****************************************************************************/
/****************************************************************************
* Public Functions
****************************************************************************/
/****************************************************************************
* Name: map_rom_segments
*
* Description:
* Configure the MMU and Cache peripherals for accessing ROM code and data.
*
* Input Parameters:
* None.
*
* Returned Value:
* None.
*
****************************************************************************/
int map_rom_segments(uint32_t app_drom_start, uint32_t app_drom_vaddr,
uint32_t app_drom_size, uint32_t app_irom_start,
uint32_t app_irom_vaddr, uint32_t app_irom_size)
{
uint32_t rc = 0;
uint32_t actual_mapped_len = 0;
uint32_t app_irom_start_aligned = app_irom_start & MMU_FLASH_MASK;
uint32_t app_irom_vaddr_aligned = app_irom_vaddr & MMU_FLASH_MASK;
uint32_t app_drom_start_aligned = app_drom_start & MMU_FLASH_MASK;
uint32_t app_drom_vaddr_aligned = app_drom_vaddr & MMU_FLASH_MASK;
#ifdef CONFIG_ARCH_CHIP_ESP32
uint32_t drom_page_count = 0;
uint32_t irom_page_count = 0;
#endif
#ifdef CONFIG_ESPRESSIF_SIMPLE_BOOT
esp_image_header_t image_header; /* Header for entire image */
esp_image_segment_header_t WORD_ALIGNED_ATTR segment_hdr;
bool padding_checksum = false;
unsigned int segments = 0;
unsigned int ram_segments = 0;
unsigned int rom_segments = 0;
size_t offset = CONFIG_BOOTLOADER_OFFSET_IN_FLASH;
/* Read image header */
if (bootloader_flash_read(offset, &image_header,
sizeof(esp_image_header_t),
true) != ESP_OK)
{
ets_printf("Failed to load image header!\n");
abort();
}
offset += sizeof(esp_image_header_t);
/* Iterate for segment information parsing */
while (segments++ < 16 && rom_segments < 2)
{
/* Read segment header */
if (bootloader_flash_read(offset, &segment_hdr,
sizeof(esp_image_segment_header_t),
true) != ESP_OK)
{
ets_printf("failed to read segment header at %x\n", offset);
abort();
}
if (IS_NONE(segment_hdr.load_addr))
{
break;
}
if (IS_RTC_FAST_IRAM(segment_hdr.load_addr) ||
IS_RTC_FAST_DRAM(segment_hdr.load_addr) ||
IS_RTC_SLOW_DRAM(segment_hdr.load_addr))
{
/* RTC segment is loaded by ROM bootloader */
ram_segments++;
}
ets_printf("%s: lma 0x%08x vma 0x%08" PRIx32 " len 0x%-6" PRIx32 ""
" (%" PRIu32 ")\n",
IS_NONE(segment_hdr.load_addr) ? "???" :
IS_RTC_FAST_IRAM(segment_hdr.load_addr) ||
IS_RTC_FAST_DRAM(segment_hdr.load_addr) ||
IS_RTC_SLOW_DRAM(segment_hdr.load_addr) ? "rtc" :
IS_MMAP(segment_hdr.load_addr) ?
IS_IROM(segment_hdr.load_addr) ? "imap" : "dmap" :
IS_PADD(segment_hdr.load_addr) ? "padd" :
IS_DRAM(segment_hdr.load_addr) ? "dram" : "iram",
offset + sizeof(esp_image_segment_header_t),
segment_hdr.load_addr, segment_hdr.data_len,
segment_hdr.data_len);
/* Fix drom and irom produced be the linker, as this
* is later invalidated by the elf2image command.
*/
if (IS_DROM(segment_hdr.load_addr) &&
segment_hdr.load_addr == (uint32_t)_image_drom_vma)
{
app_drom_start = offset + sizeof(esp_image_segment_header_t);
app_drom_start_aligned = app_drom_start & MMU_FLASH_MASK;
rom_segments++;
}
if (IS_IROM(segment_hdr.load_addr) &&
segment_hdr.load_addr == (uint32_t)_image_irom_vma)
{
app_irom_start = offset + sizeof(esp_image_segment_header_t);
app_irom_start_aligned = app_irom_start & MMU_FLASH_MASK;
rom_segments++;
}
if (IS_SRAM(segment_hdr.load_addr))
{
ram_segments++;
}
offset += sizeof(esp_image_segment_header_t) + segment_hdr.data_len;
if (ram_segments == image_header.segment_count && !padding_checksum)
{
offset += (CHECKSUM_ALIGN - 1) - (offset % CHECKSUM_ALIGN) + 1;
padding_checksum = true;
}
}
if (segments == 0 || segments == 16)
{
ets_printf("Error parsing segments\n");
}
ets_printf("total segments stored %d\n", segments - 1);
#endif
#if defined (CONFIG_ESP32S2_APP_FORMAT_MCUBOOT) || \
defined (CONFIG_ESP32S3_APP_FORMAT_MCUBOOT) || \
defined (CONFIG_ESP32_APP_FORMAT_MCUBOOT)
ets_printf("IROM segment aligned lma 0x%08" PRIx32 " vma 0x%08" PRIx32 ""
" len 0x%06" PRIx32 " "\
"(%" PRIu32 ")\n", app_irom_start_aligned,
app_irom_vaddr_aligned, app_irom_size, app_irom_size);
ets_printf("DROM segment aligned lma 0x%08" PRIx32 " vma 0x%08" PRIx32 ""
" len 0x%06" PRIx32 " "\
"(%" PRIu32 ")\n", app_drom_start_aligned,
app_drom_vaddr_aligned, app_drom_size, app_drom_size);
#endif
#ifdef CONFIG_ARCH_CHIP_ESP32
cache_read_disable(PRO_CPU_NUM);
cache_flush(PRO_CPU_NUM);
# ifdef CONFIG_SMP
cache_flush(APP_CPU_NUM);
cache_read_enable(APP_CPU_NUM);
# endif
#else
cache_hal_disable(CACHE_LL_LEVEL_EXT_MEM, CACHE_TYPE_ALL);
#endif
/* Clear the MMU entries that are already set up,
* so the new app only has the mappings it creates.
*/
mmu_hal_unmap_all();
#ifdef CONFIG_ARCH_CHIP_ESP32
drom_page_count = (app_drom_size + SPI_FLASH_MMU_PAGE_SIZE - 1) /
SPI_FLASH_MMU_PAGE_SIZE;
rc = cache_flash_mmu_set(0, 0, app_drom_vaddr_aligned,
app_drom_start_aligned, 64,
(int)drom_page_count);
rc |= cache_flash_mmu_set(1, 0, app_drom_vaddr_aligned,
app_drom_start_aligned, 64,
(int)drom_page_count);
irom_page_count = (app_irom_size + SPI_FLASH_MMU_PAGE_SIZE - 1) /
SPI_FLASH_MMU_PAGE_SIZE;
rc |= cache_flash_mmu_set(0, 0, app_irom_vaddr_aligned,
app_irom_start_aligned, 64,
(int)irom_page_count);
rc |= cache_flash_mmu_set(1, 0, app_irom_vaddr_aligned,
app_irom_start_aligned, 64,
(int)irom_page_count);
#else
mmu_hal_map_region(0, MMU_TARGET_FLASH0,
app_drom_vaddr_aligned, app_drom_start_aligned,
app_drom_size, &actual_mapped_len);
mmu_hal_map_region(0, MMU_TARGET_FLASH0,
app_irom_vaddr_aligned, app_irom_start_aligned,
app_irom_size, &actual_mapped_len);
#endif
/* ------------------Enable corresponding buses--------------------- */
cache_bus_mask_t bus_mask = cache_ll_l1_get_bus(0, app_drom_vaddr_aligned,
app_drom_size);
cache_ll_l1_enable_bus(0, bus_mask);
bus_mask = cache_ll_l1_get_bus(0, app_irom_vaddr_aligned, app_irom_size);
cache_ll_l1_enable_bus(0, bus_mask);
#if CONFIG_ESPRESSIF_NUM_CPUS > 1
bus_mask = cache_ll_l1_get_bus(1, app_drom_vaddr_aligned, app_drom_size);
cache_ll_l1_enable_bus(1, bus_mask);
bus_mask = cache_ll_l1_get_bus(1, app_irom_vaddr_aligned, app_irom_size);
cache_ll_l1_enable_bus(1, bus_mask);
#endif
/* ------------------Enable Cache----------------------------------- */
#ifdef CONFIG_ARCH_CHIP_ESP32
cache_read_enable(0);
#else
cache_hal_enable(CACHE_LL_LEVEL_EXT_MEM, CACHE_TYPE_ALL);
#endif
return (int)rc;
}