Summary
The ARMv8-A ThreadX ports require the application to run with SPSel = 0, so that SP_EL0 is used for thread stacks and for the system stack. This requirement is not stated anywhere in prose. It is only implied by the example startup.S and vectors.S files, which most users replace with their own board bring-up code.
Background
Two different conventions coexist in the tree:
ports/cortex_a5x targets EL3, never touches SPSel, stays on SP_ELx, and builds the initial SPSR with M[0] set (0x5/0x9/0xD, i.e. ELxh).
- Every later ARMv8-A port — A34, A35, A53, A55, A57, the A6x and A7x families, plus the SMP and module variants — runs with
SPSel = 0 and builds the initial SPSR with M[0] clear (0x4/0x8/0xC, i.e. ELxt). SP_ELx is only a transient exception-entry stack.
The second convention is enforced in three places that must agree: startup.S executes MSR SPSel, #0 before entering ThreadX, irqFirstLevelHandler in vectors.S executes MSR SPSel, 0 before calling _tx_thread_context_save, and _tx_thread_schedule restores the thread stack with a plain MOV sp, x4, which writes SP_EL0.
If an application enters ThreadX with SPSel = 1, or with SP_EL0 uninitialised, the ERET that launches the first thread switches to an invalid stack and the target faults immediately. The failure is hard to diagnose because nothing in the kernel sources hints at the constraint.
What should be done
- Document, for the ARMv8-A ports, that the application must initialise
SP_EL0 and enter ThreadX with SPSel = 0, and that the interrupt entry path must switch to SP_EL0 before calling _tx_thread_context_save.
- Explain why
cortex_a5x differs, so nobody tries to propagate its SPSR values into the other ports.
- Ideally, add a short comment to
tx_thread_stack_build.S at the point where the initial SPSR is built, pointing at the same contract.
Credit
This came out of #194, reported by @rodfrazer, and had already been raised in #161 by @xjbwd. Both were closed without the underlying documentation gap being addressed.
Summary
The ARMv8-A ThreadX ports require the application to run with
SPSel = 0, so thatSP_EL0is used for thread stacks and for the system stack. This requirement is not stated anywhere in prose. It is only implied by the examplestartup.Sandvectors.Sfiles, which most users replace with their own board bring-up code.Background
Two different conventions coexist in the tree:
ports/cortex_a5xtargets EL3, never touchesSPSel, stays onSP_ELx, and builds the initial SPSR withM[0]set (0x5/0x9/0xD, i.e.ELxh).SPSel = 0and builds the initial SPSR withM[0]clear (0x4/0x8/0xC, i.e.ELxt).SP_ELxis only a transient exception-entry stack.The second convention is enforced in three places that must agree:
startup.SexecutesMSR SPSel, #0before entering ThreadX,irqFirstLevelHandlerinvectors.SexecutesMSR SPSel, 0before calling_tx_thread_context_save, and_tx_thread_schedulerestores the thread stack with a plainMOV sp, x4, which writesSP_EL0.If an application enters ThreadX with
SPSel = 1, or withSP_EL0uninitialised, theERETthat launches the first thread switches to an invalid stack and the target faults immediately. The failure is hard to diagnose because nothing in the kernel sources hints at the constraint.What should be done
SP_EL0and enter ThreadX withSPSel = 0, and that the interrupt entry path must switch toSP_EL0before calling_tx_thread_context_save.cortex_a5xdiffers, so nobody tries to propagate its SPSR values into the other ports.tx_thread_stack_build.Sat the point where the initial SPSR is built, pointing at the same contract.Credit
This came out of #194, reported by @rodfrazer, and had already been raised in #161 by @xjbwd. Both were closed without the underlying documentation gap being addressed.