mirror of
https://github.com/apache/nuttx.git
synced 2026-08-01 20:28:58 +00:00
armv7-m/armv8-m: honor SP modifications on signal return
On ARMv7-M/ARMv8-M, the hardware exception return determines the final SP from the physical location of the HW exception frame, ignoring any software modification to REG_R13 in the saved register context. This means signal handlers that adjust SP have their change silently discarded. Fix this by relocating the saved context in arm_sigdeliver before calling arm_fullcontextrestore. If the desired SP (regs[REG_R13]) differs from the implied SP, memmove the entire context frame so that the hardware exception return produces the correct final SP. The fix runs only in the signal return path, adding zero overhead to the normal exception return hot path. Signed-off-by: Andrew Au <cshung@gmail.com>
This commit is contained in:
parent
9704481224
commit
d79beefa54
2 changed files with 50 additions and 0 deletions
|
|
@ -27,6 +27,7 @@
|
|||
#include <nuttx/config.h>
|
||||
|
||||
#include <stdint.h>
|
||||
#include <string.h>
|
||||
#include <sched.h>
|
||||
#include <assert.h>
|
||||
|
||||
|
|
@ -57,6 +58,9 @@ void arm_sigdeliver(void)
|
|||
{
|
||||
struct tcb_s *rtcb = this_task();
|
||||
uint32_t *regs = rtcb->xcp.saved_regs;
|
||||
uint32_t *new_regs;
|
||||
uint32_t desired_sp;
|
||||
uint32_t implied_sp;
|
||||
|
||||
#ifdef CONFIG_SMP
|
||||
/* In the SMP case, we must terminate the critical section while the signal
|
||||
|
|
@ -163,6 +167,27 @@ retry:
|
|||
leave_critical_section(up_irq_save());
|
||||
#endif
|
||||
|
||||
/* If the signal handler modified SP (REG_R13), relocate the saved
|
||||
* context so that the hardware exception return produces the correct SP.
|
||||
*
|
||||
* On ARMv7-M, the exception return path sets PSP to the HW frame address
|
||||
* and hardware computes final SP = PSP + frame_size. The implied SP is
|
||||
* determined by the physical location of the context, not by REG_R13.
|
||||
* To honor a modified SP, we memmove the entire context frame to the
|
||||
* address where the end of the frame equals the desired SP.
|
||||
*/
|
||||
|
||||
desired_sp = regs[REG_R13];
|
||||
implied_sp = (uint32_t)regs + XCPTCONTEXT_SIZE;
|
||||
|
||||
if (desired_sp != implied_sp)
|
||||
{
|
||||
new_regs = (uint32_t *)(desired_sp - XCPTCONTEXT_SIZE);
|
||||
memmove(new_regs, regs, XCPTCONTEXT_SIZE);
|
||||
regs = new_regs;
|
||||
rtcb->xcp.saved_regs = new_regs;
|
||||
}
|
||||
|
||||
rtcb->xcp.regs = rtcb->xcp.saved_regs;
|
||||
arm_fullcontextrestore();
|
||||
UNUSED(regs);
|
||||
|
|
|
|||
|
|
@ -27,6 +27,7 @@
|
|||
#include <nuttx/config.h>
|
||||
|
||||
#include <stdint.h>
|
||||
#include <string.h>
|
||||
#include <sched.h>
|
||||
#include <assert.h>
|
||||
|
||||
|
|
@ -57,6 +58,9 @@ void arm_sigdeliver(void)
|
|||
{
|
||||
struct tcb_s *rtcb = this_task();
|
||||
uint32_t *regs = rtcb->xcp.saved_regs;
|
||||
uint32_t *new_regs;
|
||||
uint32_t desired_sp;
|
||||
uint32_t implied_sp;
|
||||
|
||||
#ifdef CONFIG_SMP
|
||||
/* In the SMP case, we must terminate the critical section while the signal
|
||||
|
|
@ -163,6 +167,27 @@ retry:
|
|||
leave_critical_section(up_irq_save());
|
||||
#endif
|
||||
|
||||
/* If the signal handler modified SP (REG_R13), relocate the saved
|
||||
* context so that the hardware exception return produces the correct SP.
|
||||
*
|
||||
* On ARMv8-M, the exception return path sets PSP to the HW frame address
|
||||
* and hardware computes final SP = PSP + frame_size. The implied SP is
|
||||
* determined by the physical location of the context, not by REG_R13.
|
||||
* To honor a modified SP, we memmove the entire context frame to the
|
||||
* address where the end of the frame equals the desired SP.
|
||||
*/
|
||||
|
||||
desired_sp = regs[REG_R13];
|
||||
implied_sp = (uint32_t)regs + XCPTCONTEXT_SIZE;
|
||||
|
||||
if (desired_sp != implied_sp)
|
||||
{
|
||||
new_regs = (uint32_t *)(desired_sp - XCPTCONTEXT_SIZE);
|
||||
memmove(new_regs, regs, XCPTCONTEXT_SIZE);
|
||||
regs = new_regs;
|
||||
rtcb->xcp.saved_regs = new_regs;
|
||||
}
|
||||
|
||||
rtcb->xcp.regs = rtcb->xcp.saved_regs;
|
||||
arm_fullcontextrestore();
|
||||
UNUSED(regs);
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue