Răsfoiți Sursa

Merge branch 'bugfix/esp32s2_freertos_tls' into 'master'

esp32s2: fix THREADPTR calculation, re-enable FreeRTOS TLS tests

Closes IDF-1239

See merge request espressif/esp-idf!7403
Ivan Grokhotkov 6 ani în urmă
părinte
comite
81f0e7d90f

+ 2 - 1
components/esp32/ld/esp32.project.ld.in

@@ -249,7 +249,8 @@ SECTIONS
   ASSERT(((_bss_end - ORIGIN(dram0_0_seg)) <= LENGTH(dram0_0_seg)),
           "DRAM segment data does not fit.")
 
-  .flash.rodata :
+  /* When modifying the alignment, update tls_section_alignment in pxPortInitialiseStack */
+  .flash.rodata : ALIGN(0x10)
   {
     _rodata_start = ABSOLUTE(.);
 

+ 2 - 1
components/esp32s2/ld/esp32s2.project.ld.in

@@ -246,7 +246,8 @@ SECTIONS
   ASSERT(((_bss_end - ORIGIN(dram0_0_seg)) <= LENGTH(dram0_0_seg)),
           "DRAM segment data does not fit.")
 
-  .flash.rodata :
+  /* When modifying the alignment, update tls_section_alignment in pxPortInitialiseStack */
+  .flash.rodata : ALIGN(0x10)
   {
     _rodata_start = ABSOLUTE(.);
 

+ 14 - 3
components/freertos/port.c

@@ -227,9 +227,20 @@ StackType_t *pxPortInitialiseStack( StackType_t *pxTopOfStack, TaskFunction_t px
 	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);
-	/* shift threadptr by the offset of _thread_local_start from DROM start;
-	   need to take into account extra 16 bytes offset */
-	*threadptr = (uint32_t)task_thread_local_start - ((uint32_t)&_thread_local_start - (uint32_t)&_rodata_start) - 0x10;
+	/* 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.
+	 */
+	const uint32_t tls_section_alignment = 0x10;  /* has to be in sync with 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;
 
 	#if XCHAL_CP_NUM > 0
 	/* Init the coprocessor save area (see xtensa_context.h) */

+ 0 - 2
components/freertos/test/test_thread_local.c

@@ -11,7 +11,6 @@
 #include "test_utils.h"
 #include "sdkconfig.h"
 
-#if !TEMPORARY_DISABLED_FOR_TARGETS(ESP32S2)
 
 static __thread int tl_test_var1;
 static __thread uint8_t tl_test_var2 = 55;
@@ -109,5 +108,4 @@ TEST_CASE("TLS test", "[freertos]")
     }
     vTaskDelay(10); /* Make sure idle task can clean up s_task, before it goes out of scope */
 }
-#endif