Skip to content

Commit 22399e6

Browse files
committed
Fix Cortex-R5 SVC stack init for VFP alignment
Critical bugs discovered: 1. SVC stack was never initialized, causing potential alignment faults for VFP double-precision operations (VSTMDB/VLDMIA in SVC mode) 2. Wrong base pointer: loaded _sp (DDR) instead of _stack_top (ATCM) Result: Stacks placed in external memory, not TCM 3. Wrong initialization order: assembly didn't match linker layout Result: Stack overlap and memory corruption 4. Conditional bug: When TX_ENABLE_IRQ_NESTING disabled, code skipped SYS region, placing FIQ/IRQ in wrong memory regions 5. ARM compliance issues: Full CPSR writes, missing ISB barriers Fixes applied: Assembly (tx_initialize_low_level.S): - Changed base from _sp to _stack_top (ATCM) - Reordered initialization: SVC → SYS → FIQ → IRQ (matches linker) - Added SVC_STACK_SIZE = 1024 and SVC stack initialization - Added #else clause to always subtract SYS_STACK_SIZE (maintain layout) - Changed MSR CPSR to MSR CPSR_c (control field only) - Added ISB after each mode change (ARMv7-R best practice) - Removed unnecessary SUB #1 before BIC eclipse-threadx#7 Linker (sample_threadx_tcm.ld): - Added .stack_svc section (1KB, ALIGN(8), in ATCM) - Added SVC_STACK_SIZE constant - Exported _sp_svc symbol ARM Reference: ARMv7-R Architecture Manual DDI 0406C - Section A8.8.383: VSTM alignment requirements (8-byte for D0-D15) - Section B1.3.3: Processor modes and banked SP registers - Section A3.8.3: ISB instruction synchronization barrier
1 parent f5ef2b5 commit 22399e6

2 files changed

Lines changed: 57 additions & 16 deletions

File tree

ports/cortex_r5/gnu/example_build/sample_threadx_tcm.ld

Lines changed: 17 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -37,12 +37,14 @@ OUTPUT_ARCH(arm)
3737
* Adjust these based on your application requirements:
3838
* - FIQ_STACK_SIZE: Fast Interrupt stack (typically 512-1024 bytes)
3939
* - IRQ_STACK_SIZE: Standard interrupt stack (typically 1024-2048 bytes)
40+
* - SVC_STACK_SIZE: Supervisor mode stack for VFP preemption (1024 bytes minimum)
4041
* - SYS_STACK_SIZE: System mode stack for nested interrupts (1024-2048 bytes)
4142
*
42-
* Total ATCM requirement: ~2560 bytes for stacks + critical data
43+
* Total ATCM requirement: ~3584 bytes for stacks + critical data
4344
*/
4445
FIQ_STACK_SIZE = 512;
4546
IRQ_STACK_SIZE = 1024;
47+
SVC_STACK_SIZE = 1024; /* CRITICAL: Required for VFP context save/restore alignment */
4648
SYS_STACK_SIZE = 1024; /* Only used if TX_ENABLE_IRQ_NESTING is defined */
4749

4850
/*
@@ -113,12 +115,25 @@ SECTIONS
113115
_stack_sys_end = .;
114116
} > ATCM
115117

118+
/* SVC Stack - Used for interrupt preemption with VFP context switching
119+
* CRITICAL: Must be 8-byte aligned for VSTMDB/VLDMIA double-precision VFP operations
120+
* Context save in tx_thread_context_restore.S:205 switches to SVC mode and uses this stack
121+
* Size: 1KB minimum for nested preemption with full VFP context (200 bytes per frame)
122+
*/
123+
.stack_svc (NOLOAD) : ALIGN(8)
124+
{
125+
_stack_svc_start = .;
126+
. += SVC_STACK_SIZE;
127+
_stack_svc_end = .;
128+
} > ATCM
129+
116130
/* Export stack pointers for use in tx_initialize_low_level.S */
117131
_sp_irq = _stack_irq_end;
118132
_sp_fiq = _stack_fiq_end;
133+
_sp_svc = _stack_svc_end;
119134
_sp_sys = _stack_sys_end;
120135
_stack_bottom = _stack_irq_start;
121-
_stack_top = _stack_sys_end;
136+
_stack_top = _stack_svc_end;
122137

123138
/*
124139
* Code Sections in DDR

ports/cortex_r5/gnu/example_build/tx_initialize_low_level.S

Lines changed: 40 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -38,6 +38,7 @@ FIQ_MODE = 0xD1 @ Disable IRQ/FIQ FIQ mode
3838
SYS_MODE = 0xDF @ Disable IRQ/FIQ SYS mode
3939
FIQ_STACK_SIZE = 512 @ FIQ stack size
4040
IRQ_STACK_SIZE = 1024 @ IRQ stack size
41+
SVC_STACK_SIZE = 1024 @ SVC stack size (for VFP preemption)
4142
SYS_STACK_SIZE = 1024 @ System stack size
4243
@
4344
@
@@ -122,38 +123,63 @@ _tx_initialize_low_level:
122123
@ /* We must be in SVC mode at this point! */
123124
@
124125
@ /* Setup various stack pointers. */
126+
@ /* CRITICAL: Initialize top-to-bottom to match linker script memory layout */
127+
@ /* Memory layout (ATCM): IRQ (low) → FIQ → SYS → SVC (high) */
128+
@ /* Initialization order: SVC (high) → SYS → FIQ → IRQ (low) */
125129
@
126-
LDR r1, =_sp @ Get pointer to stack area
130+
LDR r1, =_stack_top @ Start at top of ATCM (SVC end)
131+
@
132+
@ /* Setup SVC stack (highest address) - CRITICAL for VFP alignment */
133+
@
134+
LDR r2, =SVC_STACK_SIZE @ Pickup SVC stack size
135+
MOV r0, #SVC_MODE @ Build SVC mode CPSR
136+
MSR CPSR_c, r0 @ Enter SVC mode (control field only)
137+
ISB @ Instruction barrier after mode change
138+
BIC r1, r1, #7 @ Ensure 8-byte alignment for VFP operations
139+
MOV sp, r1 @ Setup SVC stack pointer (CRITICAL for VFP)
140+
SUB r1, r1, r2 @ Move down to SYS top
127141

128-
#ifdef TX_ENABLE_IRQ_NESTING
142+
#ifdef TX_ENABLE_IRQ_NESTING
129143
@
130144
@ /* Setup the system mode stack for nested interrupt support */
131145
@
132146
LDR r2, =SYS_STACK_SIZE @ Pickup stack size
133147
MOV r3, #SYS_MODE @ Build SYS mode CPSR
134-
MSR CPSR_c, r3 @ Enter SYS mode
135-
SUB r1, r1, #1 @ Backup 1 byte
148+
MSR CPSR_c, r3 @ Enter SYS mode (control field only)
149+
ISB @ Instruction barrier after mode change
136150
BIC r1, r1, #7 @ Ensure 8-byte alignment
137151
MOV sp, r1 @ Setup SYS stack pointer
138-
SUB r1, r1, r2 @ Calculate start of next stack
152+
SUB r1, r1, r2 @ Move down to FIQ top
153+
#else
154+
@
155+
@ /* Skip SYS stack setup but reserve space to match linker layout */
156+
@
157+
LDR r2, =SYS_STACK_SIZE @ Pickup stack size
158+
SUB r1, r1, r2 @ Skip over SYS region (maintain layout)
139159
#endif
140-
160+
@
161+
@ /* Setup FIQ stack */
162+
@
141163
LDR r2, =FIQ_STACK_SIZE @ Pickup stack size
142164
MOV r0, #FIQ_MODE @ Build FIQ mode CPSR
143-
MSR CPSR, r0 @ Enter FIQ mode
144-
SUB r1, r1, #1 @ Backup 1 byte
165+
MSR CPSR_c, r0 @ Enter FIQ mode (control field only)
166+
ISB @ Instruction barrier after mode change
145167
BIC r1, r1, #7 @ Ensure 8-byte alignment
146168
MOV sp, r1 @ Setup FIQ stack pointer
147-
SUB r1, r1, r2 @ Calculate start of next stack
169+
SUB r1, r1, r2 @ Move down to IRQ top
170+
@
171+
@ /* Setup IRQ stack (lowest address) */
172+
@
148173
LDR r2, =IRQ_STACK_SIZE @ Pickup IRQ stack size
149174
MOV r0, #IRQ_MODE @ Build IRQ mode CPSR
150-
MSR CPSR, r0 @ Enter IRQ mode
151-
SUB r1, r1, #1 @ Backup 1 byte
175+
MSR CPSR_c, r0 @ Enter IRQ mode (control field only)
176+
ISB @ Instruction barrier after mode change
152177
BIC r1, r1, #7 @ Ensure 8-byte alignment
153178
MOV sp, r1 @ Setup IRQ stack pointer
154-
SUB r3, r1, r2 @ Calculate end of IRQ stack
155-
MOV r0, #SVC_MODE @ Build SVC mode CPSR
156-
MSR CPSR, r0 @ Enter SVC mode
179+
SUB r3, r1, r2 @ Calculate bottom of IRQ stack
180+
@
181+
@ /* Verify stack does not overflow into other memory. */
182+
@
157183
LDR r2, =_stack_bottom @ Pickup stack bottom
158184
CMP r3, r2 @ Compare the current stack end with the bottom
159185
_stack_error_loop:

0 commit comments

Comments
 (0)