mirror of
https://github.com/espressif/esp-idf.git
synced 2025-07-29 18:27:20 +02:00
feat(esp_psram): Add the gap created due to alignment of XIP segments in heap
This commit is contained in:
@ -51,6 +51,14 @@
|
||||
#define PSRAM_EARLY_LOGI ESP_EARLY_LOGI
|
||||
#endif
|
||||
|
||||
#if CONFIG_SPIRAM_RODATA
|
||||
extern uint8_t _rodata_reserved_end;
|
||||
#endif /* CONFIG_SPIRAM_RODATA */
|
||||
|
||||
#if CONFIG_SPIRAM_FETCH_INSTRUCTIONS
|
||||
extern uint8_t _instruction_reserved_end;
|
||||
#endif /* CONFIG_SPIRAM_FETCH_INSTRUCTIONS */
|
||||
|
||||
#if CONFIG_SPIRAM_ALLOW_BSS_SEG_EXTERNAL_MEMORY
|
||||
extern uint8_t _ext_ram_bss_start;
|
||||
extern uint8_t _ext_ram_bss_end;
|
||||
@ -61,6 +69,8 @@ extern uint8_t _ext_ram_noinit_start;
|
||||
extern uint8_t _ext_ram_noinit_end;
|
||||
#endif //#if CONFIG_SPIRAM_ALLOW_NOINIT_SEG_EXTERNAL_MEMORY
|
||||
|
||||
#define ALIGN_UP_BY(num, align) (((num) + ((align) - 1)) & ~((align) - 1))
|
||||
|
||||
typedef struct {
|
||||
intptr_t vaddr_start;
|
||||
intptr_t vaddr_end;
|
||||
@ -401,6 +411,31 @@ esp_err_t esp_psram_extram_add_to_heap_allocator(void)
|
||||
ESP_EARLY_LOGI(TAG, "Adding pool of %dK of PSRAM memory to heap allocator",
|
||||
(s_psram_ctx.regions_to_heap[PSRAM_MEM_8BIT_ALIGNED].size + s_psram_ctx.regions_to_heap[PSRAM_MEM_32BIT_ALIGNED].size) / 1024);
|
||||
|
||||
// Here, SOC_MMU_DI_VADDR_SHARED is necessary because, for the targets that have separate data and instruction virtual address spaces,
|
||||
// the SPIRAM gap created due to the alignment needed while placing the instruction segment in the instruction virtual address space
|
||||
// cannot be added in heap because the region cannot be configured with write permissions.
|
||||
#if CONFIG_SPIRAM_FETCH_INSTRUCTIONS && SOC_MMU_DI_VADDR_SHARED
|
||||
if ((uint32_t)&_instruction_reserved_end & (CONFIG_MMU_PAGE_SIZE - 1)) {
|
||||
uint32_t instruction_alignment_gap_heap_start, instruction_alignment_gap_heap_end;
|
||||
mmu_psram_get_instruction_alignment_gap_info(&instruction_alignment_gap_heap_start, &instruction_alignment_gap_heap_end);
|
||||
ret = heap_caps_add_region_with_caps(byte_aligned_caps, instruction_alignment_gap_heap_start, instruction_alignment_gap_heap_end);
|
||||
if (ret == ESP_OK) {
|
||||
ESP_EARLY_LOGI(TAG, "Adding pool of %dK of PSRAM memory gap generated due to end address alignment of irom to the heap allocator", (instruction_alignment_gap_heap_end - instruction_alignment_gap_heap_start) / 1024);
|
||||
}
|
||||
}
|
||||
#endif /* CONFIG_SPIRAM_FETCH_INSTRUCTIONS */
|
||||
|
||||
// In the case of ESP32S2, the rodata is mapped to a read-only region (SOC_DROM0_ADDRESS_LOW - SOC_DROM0_ADDRESS_HIGH), thus we cannot add this region to the heap.
|
||||
#if CONFIG_SPIRAM_RODATA && !CONFIG_IDF_TARGET_ESP32S2
|
||||
if ((uint32_t)&_rodata_reserved_end & (CONFIG_MMU_PAGE_SIZE - 1)) {
|
||||
uint32_t rodata_alignment_gap_heap_start, rodata_alignment_gap_heap_end;
|
||||
mmu_psram_get_rodata_alignment_gap_info(&rodata_alignment_gap_heap_start, &rodata_alignment_gap_heap_end);
|
||||
ret = heap_caps_add_region_with_caps(byte_aligned_caps, rodata_alignment_gap_heap_start, rodata_alignment_gap_heap_end);
|
||||
if (ret == ESP_OK) {
|
||||
ESP_EARLY_LOGI(TAG, "Adding pool of %dK of PSRAM memory gap generated due to end address alignment of drom to the heap allocator", (rodata_alignment_gap_heap_end - rodata_alignment_gap_heap_start) / 1024);
|
||||
}
|
||||
}
|
||||
#endif /* CONFIG_SPIRAM_RODATA */
|
||||
return ESP_OK;
|
||||
}
|
||||
|
||||
@ -410,8 +445,24 @@ bool IRAM_ATTR esp_psram_check_ptr_addr(const void *p)
|
||||
return false;
|
||||
}
|
||||
|
||||
return ((intptr_t)p >= s_psram_ctx.mapped_regions[PSRAM_MEM_8BIT_ALIGNED].vaddr_start && (intptr_t)p < s_psram_ctx.mapped_regions[PSRAM_MEM_8BIT_ALIGNED].vaddr_end) ||
|
||||
((intptr_t)p >= s_psram_ctx.mapped_regions[PSRAM_MEM_32BIT_ALIGNED].vaddr_start && (intptr_t)p < s_psram_ctx.mapped_regions[PSRAM_MEM_32BIT_ALIGNED].vaddr_end);
|
||||
if (((intptr_t)p >= s_psram_ctx.mapped_regions[PSRAM_MEM_8BIT_ALIGNED].vaddr_start && (intptr_t)p < s_psram_ctx.mapped_regions[PSRAM_MEM_8BIT_ALIGNED].vaddr_end) ||
|
||||
((intptr_t)p >= s_psram_ctx.mapped_regions[PSRAM_MEM_32BIT_ALIGNED].vaddr_start && (intptr_t)p < s_psram_ctx.mapped_regions[PSRAM_MEM_32BIT_ALIGNED].vaddr_end)) {
|
||||
return true;
|
||||
}
|
||||
|
||||
#if CONFIG_SPIRAM_RODATA && !CONFIG_IDF_TARGET_ESP32S2
|
||||
if (mmu_psram_check_ptr_addr_in_rodata_alignment_gap(p)) {
|
||||
return true;
|
||||
}
|
||||
#endif /* CONFIG_SPIRAM_RODATA && !CONFIG_IDF_TARGET_ESP32S2 */
|
||||
|
||||
#if CONFIG_SPIRAM_FETCH_INSTRUCTIONS && SOC_MMU_DI_VADDR_SHARED
|
||||
if (mmu_psram_check_ptr_addr_in_instruction_alignment_gap(p)) {
|
||||
return true;
|
||||
}
|
||||
#endif /* CONFIG_SPIRAM_FETCH_INSTRUCTIONS && SOC_MMU_DI_VADDR_SHARED */
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
esp_err_t esp_psram_extram_reserve_dma_pool(size_t size)
|
||||
|
@ -47,6 +47,23 @@ extern "C" {
|
||||
*/
|
||||
size_t mmu_psram_get_text_segment_length(void);
|
||||
|
||||
/**
|
||||
* @brief Get the start and size of the instruction segment alignment gap
|
||||
*
|
||||
* @param[out] gap_start Start of the gap
|
||||
* @param[out] gap_size Size of the gap
|
||||
*/
|
||||
void mmu_psram_get_instruction_alignment_gap_info(uint32_t *gap_start, uint32_t *gap_size);
|
||||
|
||||
/**
|
||||
* @brief Check if the pointer is in the instruction alignment gap
|
||||
*
|
||||
* @param[in] p Pointer to check
|
||||
*
|
||||
* @return true if the pointer is in the instruction alignment gap, false otherwise
|
||||
*/
|
||||
bool mmu_psram_check_ptr_addr_in_instruction_alignment_gap(const void *p);
|
||||
|
||||
/**
|
||||
* @brief Copy Flash texts to PSRAM
|
||||
*
|
||||
@ -59,6 +76,14 @@ esp_err_t mmu_config_psram_text_segment(uint32_t start_page, uint32_t psram_size
|
||||
|
||||
#if CONFIG_SPIRAM_RODATA
|
||||
|
||||
/**
|
||||
* @brief Get the start and size of the rodata segment alignment gap
|
||||
*
|
||||
* @param[out] gap_start Start of the gap
|
||||
* @param[out] gap_size Size of the gap
|
||||
*/
|
||||
void mmu_psram_get_rodata_alignment_gap_info(uint32_t *gap_start, uint32_t *gap_size);
|
||||
|
||||
/**
|
||||
* @brief Calculates the size of memory that would be used for copying flash rodata into PSRAM (in bytes)
|
||||
*
|
||||
@ -74,6 +99,15 @@ size_t mmu_psram_get_rodata_segment_length(void);
|
||||
* @param[out] out_page Used pages
|
||||
*/
|
||||
esp_err_t mmu_config_psram_rodata_segment(uint32_t start_page, uint32_t psram_size, uint32_t *out_page);
|
||||
|
||||
/**
|
||||
* @brief Check if the pointer is in the rodata alignment gap
|
||||
*
|
||||
* @param[in] p Pointer to check
|
||||
*
|
||||
* @return true if the pointer is in the rodata alignment gap, false otherwise
|
||||
*/
|
||||
bool mmu_psram_check_ptr_addr_in_rodata_alignment_gap(const void *p);
|
||||
#endif //#if CONFIG_SPIRAM_RODATA
|
||||
|
||||
/*----------------------------------------------------------------------------
|
||||
|
@ -16,6 +16,7 @@
|
||||
* APIs in 2 will be refactored when MMU driver is ready
|
||||
*/
|
||||
|
||||
#include <stdbool.h>
|
||||
#include <sys/param.h>
|
||||
#include "sdkconfig.h"
|
||||
#include "esp_log.h"
|
||||
@ -31,6 +32,8 @@
|
||||
#include "esp32s3/rom/cache.h"
|
||||
#endif
|
||||
|
||||
#define ALIGN_UP_BY(num, align) (((num) + ((align) - 1)) & ~((align) - 1))
|
||||
|
||||
/*----------------------------------------------------------------------------
|
||||
Part 1 APIs (See @Backgrounds on top of this file)
|
||||
-------------------------------------------------------------------------------*/
|
||||
@ -44,6 +47,10 @@ static uint32_t page0_page = INVALID_PHY_PAGE;
|
||||
#endif //#if CONFIG_SPIRAM_FETCH_INSTRUCTIONS || CONFIG_SPIRAM_RODATA
|
||||
|
||||
#if CONFIG_SPIRAM_FETCH_INSTRUCTIONS
|
||||
extern char _instruction_reserved_end;
|
||||
#define INSTRUCTION_ALIGNMENT_GAP_START ALIGN_UP_BY((uint32_t)&_instruction_reserved_end, 4)
|
||||
#define INSTRUCTION_ALIGNMENT_GAP_END ALIGN_UP_BY((uint32_t)&_instruction_reserved_end, CONFIG_MMU_PAGE_SIZE)
|
||||
|
||||
size_t mmu_psram_get_text_segment_length(void)
|
||||
{
|
||||
uint32_t flash_pages = 0;
|
||||
@ -56,6 +63,22 @@ size_t mmu_psram_get_text_segment_length(void)
|
||||
return MMU_PAGE_TO_BYTES(flash_pages);
|
||||
}
|
||||
|
||||
void mmu_psram_get_instruction_alignment_gap_info(uint32_t *gap_start, uint32_t *gap_end)
|
||||
{
|
||||
// As we need the memory to start with word aligned address, max virtual space that could be wasted = 3 bytes
|
||||
// Or create a new region from (uint32_t)&_instruction_reserved_end to ALIGN_UP_BY((uint32_t)&_instruction_reserved_end, 4) as only byte-accessible
|
||||
*gap_start = INSTRUCTION_ALIGNMENT_GAP_START;
|
||||
*gap_end = INSTRUCTION_ALIGNMENT_GAP_END;
|
||||
}
|
||||
|
||||
bool IRAM_ATTR mmu_psram_check_ptr_addr_in_instruction_alignment_gap(const void *p)
|
||||
{
|
||||
if ((intptr_t)p >= INSTRUCTION_ALIGNMENT_GAP_START && (intptr_t)p < INSTRUCTION_ALIGNMENT_GAP_END) {
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
esp_err_t mmu_config_psram_text_segment(uint32_t start_page, uint32_t psram_size, uint32_t *out_page)
|
||||
{
|
||||
uint32_t page_id = start_page;
|
||||
@ -93,6 +116,10 @@ esp_err_t mmu_config_psram_text_segment(uint32_t start_page, uint32_t psram_size
|
||||
#endif //#if CONFIG_SPIRAM_FETCH_INSTRUCTIONS
|
||||
|
||||
#if CONFIG_SPIRAM_RODATA
|
||||
extern char _rodata_reserved_end;
|
||||
#define RODATA_ALIGNMENT_GAP_START ALIGN_UP_BY((uint32_t)&_rodata_reserved_end, 4)
|
||||
#define RODATA_ALIGNMENT_GAP_END ALIGN_UP_BY((uint32_t)&_rodata_reserved_end, CONFIG_MMU_PAGE_SIZE)
|
||||
|
||||
size_t mmu_psram_get_rodata_segment_length(void)
|
||||
{
|
||||
uint32_t flash_pages = 0;
|
||||
@ -107,6 +134,22 @@ size_t mmu_psram_get_rodata_segment_length(void)
|
||||
return MMU_PAGE_TO_BYTES(flash_pages);
|
||||
}
|
||||
|
||||
void mmu_psram_get_rodata_alignment_gap_info(uint32_t *gap_start, uint32_t *gap_end)
|
||||
{
|
||||
// As we need the memory to start with word aligned address, max virtual space that could be wasted = 3 bytes
|
||||
// Or create a new region from (uint32_t)&_rodata_reserved_end to ALIGN_UP_BY((uint32_t)&_rodata_reserved_end, 4) as only byte-accessible
|
||||
*gap_start = RODATA_ALIGNMENT_GAP_START;
|
||||
*gap_end = RODATA_ALIGNMENT_GAP_END;
|
||||
}
|
||||
|
||||
bool IRAM_ATTR mmu_psram_check_ptr_addr_in_rodata_alignment_gap(const void *p)
|
||||
{
|
||||
if ((intptr_t)p >= RODATA_ALIGNMENT_GAP_START && (intptr_t)p < RODATA_ALIGNMENT_GAP_END) {
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
esp_err_t mmu_config_psram_rodata_segment(uint32_t start_page, uint32_t psram_size, uint32_t *out_page)
|
||||
{
|
||||
uint32_t page_id = start_page;
|
||||
|
@ -10,6 +10,7 @@
|
||||
* The XIP PSRAM is done by CPU copy, v1(see mmu_psram_flash.c) is done by Cache copy
|
||||
*/
|
||||
|
||||
#include <stdbool.h>
|
||||
#include <sys/param.h>
|
||||
#include <string.h>
|
||||
#include "sdkconfig.h"
|
||||
@ -84,11 +85,32 @@ static uint32_t s_do_load_from_flash(uint32_t flash_paddr_start, uint32_t size,
|
||||
#endif //#if CONFIG_SPIRAM_FETCH_INSTRUCTIONS || CONFIG_SPIRAM_RODATA
|
||||
|
||||
#if CONFIG_SPIRAM_FETCH_INSTRUCTIONS
|
||||
/* As heap memory is allocated in 4-byte aligned manner, we need to align the instruction to 4-byte boundary */
|
||||
#define INSTRUCTION_ALIGNMENT_GAP_START ALIGN_UP_BY((uint32_t)&_instruction_reserved_end, 4)
|
||||
/* The end of the instruction is aligned to CONFIG_MMU_PAGE_SIZE boundary as the flash instruction is mapped to PSRAM */
|
||||
#define INSTRUCTION_ALIGNMENT_GAP_END ALIGN_UP_BY((uint32_t)&_instruction_reserved_end, CONFIG_MMU_PAGE_SIZE)
|
||||
|
||||
size_t mmu_psram_get_text_segment_length(void)
|
||||
{
|
||||
return ALIGN_UP_BY((uint32_t)&_instruction_reserved_end, CONFIG_MMU_PAGE_SIZE) - ALIGN_DOWN_BY((uint32_t)&_instruction_reserved_start, CONFIG_MMU_PAGE_SIZE);
|
||||
}
|
||||
|
||||
void mmu_psram_get_instruction_alignment_gap_info(uint32_t *gap_start, uint32_t *gap_end)
|
||||
{
|
||||
// As we need the memory to start with word aligned address, max virtual space that could be wasted = 3 bytes
|
||||
// Or create a new region from (uint32_t)&_instruction_reserved_end to ALIGN_UP_BY((uint32_t)&_instruction_reserved_end, 4) as only byte-accessible
|
||||
*gap_start = INSTRUCTION_ALIGNMENT_GAP_START;
|
||||
*gap_end = INSTRUCTION_ALIGNMENT_GAP_END;
|
||||
}
|
||||
|
||||
bool IRAM_ATTR mmu_psram_check_ptr_addr_in_instruction_alignment_gap(const void *p)
|
||||
{
|
||||
if ((intptr_t)p >= INSTRUCTION_ALIGNMENT_GAP_START && (intptr_t)p < INSTRUCTION_ALIGNMENT_GAP_END) {
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
esp_err_t mmu_config_psram_text_segment(uint32_t start_page, uint32_t psram_size, uint32_t *out_page)
|
||||
{
|
||||
s_irom_size = mmu_psram_get_text_segment_length();
|
||||
@ -129,6 +151,27 @@ size_t mmu_psram_get_rodata_segment_length(void)
|
||||
return ALIGN_UP_BY((uint32_t)&_rodata_reserved_end, CONFIG_MMU_PAGE_SIZE) - ALIGN_DOWN_BY((uint32_t)&_rodata_reserved_start, CONFIG_MMU_PAGE_SIZE);
|
||||
}
|
||||
|
||||
/* As heap memory is allocated in 4-byte aligned manner, we need to align the rodata to 4-byte boundary */
|
||||
#define RODATA_ALIGNMENT_GAP_START ALIGN_UP_BY((uint32_t)&_rodata_reserved_end, 4)
|
||||
/* The end of the rodata is aligned to CONFIG_MMU_PAGE_SIZE boundary as the flash rodata is mapped to PSRAM */
|
||||
#define RODATA_ALIGNMENT_GAP_END ALIGN_UP_BY((uint32_t)&_rodata_reserved_end, CONFIG_MMU_PAGE_SIZE)
|
||||
|
||||
void mmu_psram_get_rodata_alignment_gap_info(uint32_t *gap_start, uint32_t *gap_end)
|
||||
{
|
||||
// As we need the memory to start with word aligned address, max virtual space that could be wasted = 3 bytes
|
||||
// Or create a new region from (uint32_t)&_rodata_reserved_end to ALIGN_UP_BY((uint32_t)&_rodata_reserved_end, 4) as only byte-accessible
|
||||
*gap_start = RODATA_ALIGNMENT_GAP_START;
|
||||
*gap_end = RODATA_ALIGNMENT_GAP_END;
|
||||
}
|
||||
|
||||
bool IRAM_ATTR mmu_psram_check_ptr_addr_in_rodata_alignment_gap(const void *p)
|
||||
{
|
||||
if ((intptr_t)p >= RODATA_ALIGNMENT_GAP_START && (intptr_t)p < RODATA_ALIGNMENT_GAP_END) {
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
esp_err_t mmu_config_psram_rodata_segment(uint32_t start_page, uint32_t psram_size, uint32_t *out_page)
|
||||
{
|
||||
s_drom_size = mmu_psram_get_rodata_segment_length();
|
||||
|
Reference in New Issue
Block a user