Skip to content

Commit 49f2533

Browse files
committed
feat(esp_psram): Add the gap created due to alignment of XIP segments in heap
1 parent 0f62849 commit 49f2533

File tree

4 files changed

+173
-2
lines changed

4 files changed

+173
-2
lines changed

components/esp_psram/system_layer/esp_psram.c

Lines changed: 53 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -61,6 +61,14 @@
6161
#define PSRAM_EARLY_LOGI ESP_EARLY_LOGI
6262
#endif
6363

64+
#if CONFIG_SPIRAM_RODATA
65+
extern uint8_t _rodata_reserved_end;
66+
#endif /* CONFIG_SPIRAM_RODATA */
67+
68+
#if CONFIG_SPIRAM_FETCH_INSTRUCTIONS
69+
extern uint8_t _instruction_reserved_end;
70+
#endif /* CONFIG_SPIRAM_FETCH_INSTRUCTIONS */
71+
6472
#if CONFIG_SPIRAM_ALLOW_BSS_SEG_EXTERNAL_MEMORY
6573
extern uint8_t _ext_ram_bss_start;
6674
extern uint8_t _ext_ram_bss_end;
@@ -71,6 +79,8 @@ extern uint8_t _ext_ram_noinit_start;
7179
extern uint8_t _ext_ram_noinit_end;
7280
#endif //#if CONFIG_SPIRAM_ALLOW_NOINIT_SEG_EXTERNAL_MEMORY
7381

82+
#define ALIGN_UP_BY(num, align) (((num) + ((align) - 1)) & ~((align) - 1))
83+
7484
typedef struct {
7585
intptr_t vaddr_start;
7686
intptr_t vaddr_end;
@@ -506,6 +516,31 @@ esp_err_t esp_psram_extram_add_to_heap_allocator(void)
506516
ESP_EARLY_LOGI(TAG, "Adding pool of %dK of PSRAM memory to heap allocator",
507517
(s_psram_ctx.regions_to_heap[PSRAM_MEM_8BIT_ALIGNED].size + s_psram_ctx.regions_to_heap[PSRAM_MEM_32BIT_ALIGNED].size) / 1024);
508518

519+
// Here, SOC_MMU_DI_VADDR_SHARED is necessary because, for the targets that have separate data and instruction virtual address spaces,
520+
// the SPIRAM gap created due to the alignment needed while placing the instruction segment in the instruction virtual address space
521+
// cannot be added in heap because the region cannot be configured with write permissions.
522+
#if CONFIG_SPIRAM_FETCH_INSTRUCTIONS && SOC_MMU_DI_VADDR_SHARED
523+
if ((uint32_t)&_instruction_reserved_end & (CONFIG_MMU_PAGE_SIZE - 1)) {
524+
uint32_t instruction_alignment_gap_heap_start, instruction_alignment_gap_heap_end;
525+
mmu_psram_get_instruction_alignment_gap_info(&instruction_alignment_gap_heap_start, &instruction_alignment_gap_heap_end);
526+
ret = heap_caps_add_region_with_caps(byte_aligned_caps, instruction_alignment_gap_heap_start, instruction_alignment_gap_heap_end);
527+
if (ret == ESP_OK) {
528+
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);
529+
}
530+
}
531+
#endif /* CONFIG_SPIRAM_FETCH_INSTRUCTIONS */
532+
533+
// 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.
534+
#if CONFIG_SPIRAM_RODATA && !CONFIG_IDF_TARGET_ESP32S2
535+
if ((uint32_t)&_rodata_reserved_end & (CONFIG_MMU_PAGE_SIZE - 1)) {
536+
uint32_t rodata_alignment_gap_heap_start, rodata_alignment_gap_heap_end;
537+
mmu_psram_get_rodata_alignment_gap_info(&rodata_alignment_gap_heap_start, &rodata_alignment_gap_heap_end);
538+
ret = heap_caps_add_region_with_caps(byte_aligned_caps, rodata_alignment_gap_heap_start, rodata_alignment_gap_heap_end);
539+
if (ret == ESP_OK) {
540+
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);
541+
}
542+
}
543+
#endif /* CONFIG_SPIRAM_RODATA */
509544
return ESP_OK;
510545
}
511546

@@ -515,8 +550,24 @@ bool IRAM_ATTR esp_psram_check_ptr_addr(const void *p)
515550
return false;
516551
}
517552

518-
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) ||
519-
((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);
553+
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) ||
554+
((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)) {
555+
return true;
556+
}
557+
558+
#if CONFIG_SPIRAM_RODATA && !CONFIG_IDF_TARGET_ESP32S2
559+
if (mmu_psram_check_ptr_addr_in_rodata_alignment_gap(p)) {
560+
return true;
561+
}
562+
#endif /* CONFIG_SPIRAM_RODATA && !CONFIG_IDF_TARGET_ESP32S2 */
563+
564+
#if CONFIG_SPIRAM_FETCH_INSTRUCTIONS && SOC_MMU_DI_VADDR_SHARED
565+
if (mmu_psram_check_ptr_addr_in_instruction_alignment_gap(p)) {
566+
return true;
567+
}
568+
#endif /* CONFIG_SPIRAM_FETCH_INSTRUCTIONS && SOC_MMU_DI_VADDR_SHARED */
569+
570+
return false;
520571
}
521572

522573
esp_err_t esp_psram_extram_reserve_dma_pool(size_t size)

components/esp_psram/xip_impl/include/esp_private/mmu_psram_flash.h

Lines changed: 34 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -47,6 +47,23 @@ extern "C" {
4747
*/
4848
size_t mmu_psram_get_text_segment_length(void);
4949

50+
/**
51+
* @brief Get the start and size of the instruction segment alignment gap
52+
*
53+
* @param[out] gap_start Start of the gap
54+
* @param[out] gap_size Size of the gap
55+
*/
56+
void mmu_psram_get_instruction_alignment_gap_info(uint32_t *gap_start, uint32_t *gap_size);
57+
58+
/**
59+
* @brief Check if the pointer is in the instruction alignment gap
60+
*
61+
* @param[in] p Pointer to check
62+
*
63+
* @return true if the pointer is in the instruction alignment gap, false otherwise
64+
*/
65+
bool mmu_psram_check_ptr_addr_in_instruction_alignment_gap(const void *p);
66+
5067
/**
5168
* @brief Copy Flash texts to PSRAM
5269
*
@@ -59,6 +76,14 @@ esp_err_t mmu_config_psram_text_segment(uint32_t start_page, uint32_t psram_size
5976

6077
#if CONFIG_SPIRAM_RODATA
6178

79+
/**
80+
* @brief Get the start and size of the rodata segment alignment gap
81+
*
82+
* @param[out] gap_start Start of the gap
83+
* @param[out] gap_size Size of the gap
84+
*/
85+
void mmu_psram_get_rodata_alignment_gap_info(uint32_t *gap_start, uint32_t *gap_size);
86+
6287
/**
6388
* @brief Calculates the size of memory that would be used for copying flash rodata into PSRAM (in bytes)
6489
*
@@ -74,6 +99,15 @@ size_t mmu_psram_get_rodata_segment_length(void);
7499
* @param[out] out_page Used pages
75100
*/
76101
esp_err_t mmu_config_psram_rodata_segment(uint32_t start_page, uint32_t psram_size, uint32_t *out_page);
102+
103+
/**
104+
* @brief Check if the pointer is in the rodata alignment gap
105+
*
106+
* @param[in] p Pointer to check
107+
*
108+
* @return true if the pointer is in the rodata alignment gap, false otherwise
109+
*/
110+
bool mmu_psram_check_ptr_addr_in_rodata_alignment_gap(const void *p);
77111
#endif //#if CONFIG_SPIRAM_RODATA
78112

79113
/*----------------------------------------------------------------------------

components/esp_psram/xip_impl/mmu_psram_flash.c

Lines changed: 43 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -16,6 +16,7 @@
1616
* APIs in 2 will be refactored when MMU driver is ready
1717
*/
1818

19+
#include <stdbool.h>
1920
#include <sys/param.h>
2021
#include "sdkconfig.h"
2122
#include "esp_log.h"
@@ -31,6 +32,8 @@
3132
#include "esp32s3/rom/cache.h"
3233
#endif
3334

35+
#define ALIGN_UP_BY(num, align) (((num) + ((align) - 1)) & ~((align) - 1))
36+
3437
/*----------------------------------------------------------------------------
3538
Part 1 APIs (See @Backgrounds on top of this file)
3639
-------------------------------------------------------------------------------*/
@@ -44,6 +47,10 @@ static uint32_t page0_page = INVALID_PHY_PAGE;
4447
#endif //#if CONFIG_SPIRAM_FETCH_INSTRUCTIONS || CONFIG_SPIRAM_RODATA
4548

4649
#if CONFIG_SPIRAM_FETCH_INSTRUCTIONS
50+
extern char _instruction_reserved_end;
51+
#define INSTRUCTION_ALIGNMENT_GAP_START ALIGN_UP_BY((uint32_t)&_instruction_reserved_end, 4)
52+
#define INSTRUCTION_ALIGNMENT_GAP_END ALIGN_UP_BY((uint32_t)&_instruction_reserved_end, CONFIG_MMU_PAGE_SIZE)
53+
4754
size_t mmu_psram_get_text_segment_length(void)
4855
{
4956
uint32_t flash_pages = 0;
@@ -56,6 +63,22 @@ size_t mmu_psram_get_text_segment_length(void)
5663
return MMU_PAGE_TO_BYTES(flash_pages);
5764
}
5865

66+
void mmu_psram_get_instruction_alignment_gap_info(uint32_t *gap_start, uint32_t *gap_end)
67+
{
68+
// As we need the memory to start with word aligned address, max virtual space that could be wasted = 3 bytes
69+
// 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
70+
*gap_start = INSTRUCTION_ALIGNMENT_GAP_START;
71+
*gap_end = INSTRUCTION_ALIGNMENT_GAP_END;
72+
}
73+
74+
bool IRAM_ATTR mmu_psram_check_ptr_addr_in_instruction_alignment_gap(const void *p)
75+
{
76+
if ((intptr_t)p >= INSTRUCTION_ALIGNMENT_GAP_START && (intptr_t)p < INSTRUCTION_ALIGNMENT_GAP_END) {
77+
return true;
78+
}
79+
return false;
80+
}
81+
5982
esp_err_t mmu_config_psram_text_segment(uint32_t start_page, uint32_t psram_size, uint32_t *out_page)
6083
{
6184
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
93116
#endif //#if CONFIG_SPIRAM_FETCH_INSTRUCTIONS
94117

95118
#if CONFIG_SPIRAM_RODATA
119+
extern char _rodata_reserved_end;
120+
#define RODATA_ALIGNMENT_GAP_START ALIGN_UP_BY((uint32_t)&_rodata_reserved_end, 4)
121+
#define RODATA_ALIGNMENT_GAP_END ALIGN_UP_BY((uint32_t)&_rodata_reserved_end, CONFIG_MMU_PAGE_SIZE)
122+
96123
size_t mmu_psram_get_rodata_segment_length(void)
97124
{
98125
uint32_t flash_pages = 0;
@@ -107,6 +134,22 @@ size_t mmu_psram_get_rodata_segment_length(void)
107134
return MMU_PAGE_TO_BYTES(flash_pages);
108135
}
109136

137+
void mmu_psram_get_rodata_alignment_gap_info(uint32_t *gap_start, uint32_t *gap_end)
138+
{
139+
// As we need the memory to start with word aligned address, max virtual space that could be wasted = 3 bytes
140+
// 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
141+
*gap_start = RODATA_ALIGNMENT_GAP_START;
142+
*gap_end = RODATA_ALIGNMENT_GAP_END;
143+
}
144+
145+
bool IRAM_ATTR mmu_psram_check_ptr_addr_in_rodata_alignment_gap(const void *p)
146+
{
147+
if ((intptr_t)p >= RODATA_ALIGNMENT_GAP_START && (intptr_t)p < RODATA_ALIGNMENT_GAP_END) {
148+
return true;
149+
}
150+
return false;
151+
}
152+
110153
esp_err_t mmu_config_psram_rodata_segment(uint32_t start_page, uint32_t psram_size, uint32_t *out_page)
111154
{
112155
uint32_t page_id = start_page;

components/esp_psram/xip_impl/mmu_psram_flash_v2.c

Lines changed: 43 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -10,6 +10,7 @@
1010
* The XIP PSRAM is done by CPU copy, v1(see mmu_psram_flash.c) is done by Cache copy
1111
*/
1212

13+
#include <stdbool.h>
1314
#include <sys/param.h>
1415
#include <string.h>
1516
#include "sdkconfig.h"
@@ -84,11 +85,32 @@ static uint32_t s_do_load_from_flash(uint32_t flash_paddr_start, uint32_t size,
8485
#endif //#if CONFIG_SPIRAM_FETCH_INSTRUCTIONS || CONFIG_SPIRAM_RODATA
8586

8687
#if CONFIG_SPIRAM_FETCH_INSTRUCTIONS
88+
/* As heap memory is allocated in 4-byte aligned manner, we need to align the instruction to 4-byte boundary */
89+
#define INSTRUCTION_ALIGNMENT_GAP_START ALIGN_UP_BY((uint32_t)&_instruction_reserved_end, 4)
90+
/* The end of the instruction is aligned to CONFIG_MMU_PAGE_SIZE boundary as the flash instruction is mapped to PSRAM */
91+
#define INSTRUCTION_ALIGNMENT_GAP_END ALIGN_UP_BY((uint32_t)&_instruction_reserved_end, CONFIG_MMU_PAGE_SIZE)
92+
8793
size_t mmu_psram_get_text_segment_length(void)
8894
{
8995
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);
9096
}
9197

98+
void mmu_psram_get_instruction_alignment_gap_info(uint32_t *gap_start, uint32_t *gap_end)
99+
{
100+
// As we need the memory to start with word aligned address, max virtual space that could be wasted = 3 bytes
101+
// 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
102+
*gap_start = INSTRUCTION_ALIGNMENT_GAP_START;
103+
*gap_end = INSTRUCTION_ALIGNMENT_GAP_END;
104+
}
105+
106+
bool IRAM_ATTR mmu_psram_check_ptr_addr_in_instruction_alignment_gap(const void *p)
107+
{
108+
if ((intptr_t)p >= INSTRUCTION_ALIGNMENT_GAP_START && (intptr_t)p < INSTRUCTION_ALIGNMENT_GAP_END) {
109+
return true;
110+
}
111+
return false;
112+
}
113+
92114
esp_err_t mmu_config_psram_text_segment(uint32_t start_page, uint32_t psram_size, uint32_t *out_page)
93115
{
94116
s_irom_size = mmu_psram_get_text_segment_length();
@@ -129,6 +151,27 @@ size_t mmu_psram_get_rodata_segment_length(void)
129151
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);
130152
}
131153

154+
/* As heap memory is allocated in 4-byte aligned manner, we need to align the rodata to 4-byte boundary */
155+
#define RODATA_ALIGNMENT_GAP_START ALIGN_UP_BY((uint32_t)&_rodata_reserved_end, 4)
156+
/* The end of the rodata is aligned to CONFIG_MMU_PAGE_SIZE boundary as the flash rodata is mapped to PSRAM */
157+
#define RODATA_ALIGNMENT_GAP_END ALIGN_UP_BY((uint32_t)&_rodata_reserved_end, CONFIG_MMU_PAGE_SIZE)
158+
159+
void mmu_psram_get_rodata_alignment_gap_info(uint32_t *gap_start, uint32_t *gap_end)
160+
{
161+
// As we need the memory to start with word aligned address, max virtual space that could be wasted = 3 bytes
162+
// 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
163+
*gap_start = RODATA_ALIGNMENT_GAP_START;
164+
*gap_end = RODATA_ALIGNMENT_GAP_END;
165+
}
166+
167+
bool IRAM_ATTR mmu_psram_check_ptr_addr_in_rodata_alignment_gap(const void *p)
168+
{
169+
if ((intptr_t)p >= RODATA_ALIGNMENT_GAP_START && (intptr_t)p < RODATA_ALIGNMENT_GAP_END) {
170+
return true;
171+
}
172+
return false;
173+
}
174+
132175
esp_err_t mmu_config_psram_rodata_segment(uint32_t start_page, uint32_t psram_size, uint32_t *out_page)
133176
{
134177
s_drom_size = mmu_psram_get_rodata_segment_length();

0 commit comments

Comments
 (0)