diff --git a/components/esp32/ld/esp32.project.ld.in b/components/esp32/ld/esp32.project.ld.in index cc6538c423..dd734b32c1 100644 --- a/components/esp32/ld/esp32.project.ld.in +++ b/components/esp32/ld/esp32.project.ld.in @@ -232,7 +232,6 @@ SECTIONS ASSERT(((_bss_end - ORIGIN(dram0_0_seg)) <= LENGTH(dram0_0_seg)), "DRAM segment data does not fit.") - /* When modifying the alignment, update tls_section_alignment in pxPortInitialiseStack */ .flash.appdesc : ALIGN(0x10) { _rodata_start = ABSOLUTE(.); @@ -248,6 +247,8 @@ SECTIONS .flash.rodata : ALIGN(0x10) { + _flash_rodata_start = ABSOLUTE(.); + mapping[flash_rodata] @@ -305,6 +306,8 @@ SECTIONS . = ALIGN(4); } >default_rodata_seg + _flash_rodata_align = ALIGNOF(.flash.rodata); + .flash.text : { _stext = .; diff --git a/components/esp32c3/ld/esp32c3.project.ld.in b/components/esp32c3/ld/esp32c3.project.ld.in index 86eb34d2d8..58f27c9e19 100644 --- a/components/esp32c3/ld/esp32c3.project.ld.in +++ b/components/esp32c3/ld/esp32c3.project.ld.in @@ -262,7 +262,6 @@ SECTIONS _rodata_reserved_start = .; } > default_rodata_seg - /* When modifying the alignment, don't forget to update tls_section_alignment in pxPortInitialiseStack */ .flash.appdesc : ALIGN(0x10) { _rodata_start = ABSOLUTE(.); @@ -278,6 +277,8 @@ SECTIONS .flash.rodata : ALIGN(0x10) { + _flash_rodata_start = ABSOLUTE(.); + mapping[flash_rodata] *(.irom1.text) /* catch stray ICACHE_RODATA_ATTR */ diff --git a/components/esp32s2/ld/esp32s2.project.ld.in b/components/esp32s2/ld/esp32s2.project.ld.in index 0928694458..fb942d5ac9 100644 --- a/components/esp32s2/ld/esp32s2.project.ld.in +++ b/components/esp32s2/ld/esp32s2.project.ld.in @@ -251,7 +251,6 @@ SECTIONS _bss_end = ABSOLUTE(.); } > dram0_0_seg - /* When modifying the alignment, update tls_section_alignment in pxPortInitialiseStack */ .flash.appdesc : ALIGN(0x10) { _rodata_reserved_start = ABSOLUTE(.); @@ -268,6 +267,8 @@ SECTIONS .flash.rodata : ALIGN(0x10) { + _flash_rodata_start = ABSOLUTE(.); + mapping[flash_rodata] *(.irom1.text) /* catch stray ICACHE_RODATA_ATTR */ @@ -324,6 +325,8 @@ SECTIONS . = ALIGN(4); } >default_rodata_seg + _flash_rodata_align = ALIGNOF(.flash.rodata); + .flash.text : { _stext = .; diff --git a/components/esp32s3/ld/esp32s3.project.ld.in b/components/esp32s3/ld/esp32s3.project.ld.in index b3d0d25177..d420afb646 100644 --- a/components/esp32s3/ld/esp32s3.project.ld.in +++ b/components/esp32s3/ld/esp32s3.project.ld.in @@ -293,7 +293,6 @@ SECTIONS _rodata_reserved_start = .; } > default_rodata_seg - /* When modifying the alignment, don't forget to update tls_section_alignment in pxPortInitialiseStack */ .flash.appdesc : ALIGN(0x10) { _rodata_start = ABSOLUTE(.); @@ -309,6 +308,8 @@ SECTIONS .flash.rodata : ALIGN(0x10) { + _flash_rodata_start = ABSOLUTE(.); + mapping[flash_rodata] *(.irom1.text) /* catch stray ICACHE_RODATA_ATTR */ @@ -362,6 +363,8 @@ SECTIONS . = ALIGN(4); } > default_rodata_seg + _flash_rodata_align = ALIGNOF(.flash.rodata); + /* Marks the end of IRAM code segment */ .iram0.text_end (NOLOAD) : { diff --git a/components/freertos/port/riscv/port.c b/components/freertos/port/riscv/port.c index f464b37811..0ea7ce0d33 100644 --- a/components/freertos/port/riscv/port.c +++ b/components/freertos/port/riscv/port.c @@ -224,18 +224,58 @@ StackType_t *pxPortInitialiseStack(StackType_t *pxTopOfStack, TaskFunction_t pxC extern uint32_t __global_pointer$; uint8_t* task_thread_local_start; uint8_t* threadptr; - extern char _thread_local_start, _thread_local_end, _rodata_start; + extern char _thread_local_start, _thread_local_end, _flash_rodata_start; /* Byte pointer, so that subsequent calculations don't depend on sizeof(StackType_t). */ uint8_t* sp = (uint8_t*) pxTopOfStack; - /* Set up TLS area */ + /* Set up TLS area. + * The following diagram illustrates the layout of link-time and run-time + * TLS sections. + * + * +-------------+ + * |Section: | Linker symbols: + * |.flash.rodata| --------------- + * 0x0+-------------+ <-- _flash_rodata_start + * ^ | | + * | | Other data | + * | | ... | + * | +-------------+ <-- _thread_local_start + * | |.tbss | ^ + * v | | | + * 0xNNNN|int example; | | (thread_local_size) + * |.tdata | v + * +-------------+ <-- _thread_local_end + * | Other data | + * | ... | + * | | + * +-------------+ + * + * Local variables of + * pxPortInitialiseStack + * ----------------------- + * +-------------+ <-- pxTopOfStack + * |.tdata (*) | ^ + * ^ |int example; | |(thread_local_size + * | | | | + * | |.tbss (*) | v + * | +-------------+ <-- task_thread_local_start + * 0xNNNN | | | ^ + * | | | | + * | | | |_thread_local_start - _rodata_start + * | | | | + * | | | v + * v +-------------+ <-- threadptr + * + * (*) The stack grows downward! + */ + uint32_t thread_local_sz = (uint32_t) (&_thread_local_end - &_thread_local_start); thread_local_sz = ALIGNUP(0x10, thread_local_sz); sp -= thread_local_sz; task_thread_local_start = sp; memcpy(task_thread_local_start, &_thread_local_start, thread_local_sz); - threadptr = task_thread_local_start - (&_thread_local_start - &_rodata_start); + threadptr = task_thread_local_start - (&_thread_local_start - &_flash_rodata_start); /* Simulate the stack frame as it would be created by a context switch interrupt. */ sp -= RV_STK_FRMSZ; diff --git a/components/freertos/port/xtensa/port.c b/components/freertos/port/xtensa/port.c index 033d6cc25a..286a5ebbd8 100644 --- a/components/freertos/port/xtensa/port.c +++ b/components/freertos/port/xtensa/port.c @@ -189,7 +189,7 @@ StackType_t *pxPortInitialiseStack( StackType_t *pxTopOfStack, TaskFunction_t px #endif uint32_t *threadptr; void *task_thread_local_start; - extern int _thread_local_start, _thread_local_end, _rodata_start; + extern int _thread_local_start, _thread_local_end, _flash_rodata_start, _flash_rodata_align; // TODO: check that TLS area fits the stack uint32_t thread_local_sz = (uint8_t *)&_thread_local_end - (uint8_t *)&_thread_local_start; @@ -248,24 +248,25 @@ StackType_t *pxPortInitialiseStack( StackType_t *pxTopOfStack, TaskFunction_t px frame->vpri = 0xFFFFFFFF; #endif - /* Init threadptr reg and TLS vars */ + /* Init threadptr register and set up TLS run-time area. + * The diagram in port/riscv/port.c illustrates the calculations below. + */ task_thread_local_start = (void *)(((uint32_t)pxTopOfStack - XT_CP_SIZE - thread_local_sz) & ~0xf); memcpy(task_thread_local_start, &_thread_local_start, thread_local_sz); threadptr = (uint32_t *)(sp + XT_STK_EXTRA); - /* Calculate THREADPTR value: + /* Calculate THREADPTR value. * The generated code will add THREADPTR value to a constant value determined at link time, * to get the address of the TLS variable. * The constant value is calculated by the linker as follows * (search for 'tpoff' in elf32-xtensa.c in BFD): * offset = address - tls_section_vma + align_up(TCB_SIZE, tls_section_alignment) - * where TCB_SIZE is hardcoded to 8. There doesn't seem to be a way to propagate - * the section alignment value from the ld script into the code, so it is hardcoded - * in both places. + * where TCB_SIZE is hardcoded to 8. + * Note this is slightly different compared to the RISC-V port, where offset = address - tls_section_vma. */ - const uint32_t tls_section_alignment = 0x10; /* has to be in sync with ALIGN value of .flash.rodata section */ + const uint32_t tls_section_alignment = (uint32_t) &_flash_rodata_align; /* ALIGN value of .flash.rodata section */ const uint32_t tcb_size = 8; /* Unrelated to FreeRTOS, this is the constant from BFD */ const uint32_t base = (tcb_size + tls_section_alignment - 1) & (~(tls_section_alignment - 1)); - *threadptr = (uint32_t)task_thread_local_start - ((uint32_t)&_thread_local_start - (uint32_t)&_rodata_start) - base; + *threadptr = (uint32_t)task_thread_local_start - ((uint32_t)&_thread_local_start - (uint32_t)&_flash_rodata_start) - base; #if XCHAL_CP_NUM > 0 /* Init the coprocessor save area (see xtensa_context.h) */