This is an automated email from the ASF dual-hosted git repository.
acassis pushed a commit to branch master
in repository https://gitbox.apache.org/repos/asf/nuttx.git
The following commit(s) were added to refs/heads/master by this push:
new 5f5991a0f25 arch/arm: redirect an M-profile thread to its signal
action once
5f5991a0f25 is described below
commit 5f5991a0f256c497332d8e93473a4e1f3da97a8d
Author: Royyan Zahir <[email protected]>
AuthorDate: Thu Oct 8 19:41:36 2026 +0400
arch/arm: redirect an M-profile thread to its signal action once
A signal action queued at syscall return pends PendSV for the running
thread, but the same SVC can switch to another thread first. PendSV then
saw that thread, the redirect was lost and the handler did not run until
a later PendSV landed on the target, which could happen while it was
already in arm_sigdeliver: the second redirect overwrote saved_regs, the
inner delivery cleared sigdeliver and the outer one branched to address
0. ostest sighand and signest hard faulted in a protected build.
The redirect is now checked against the thread being switched in, and a
thread already redirected is left alone until arm_sigdeliver restores
its context.
Signed-off-by: Royyan Zahir <[email protected]>
---
arch/arm/src/armv6-m/arm_doirq.c | 16 +++++++---------
arch/arm/src/armv6-m/arm_schedulesigaction.c | 5 +++++
arch/arm/src/armv6-m/arm_sigdeliver.c | 1 +
arch/arm/src/armv7-m/arm_doirq.c | 16 +++++++---------
arch/arm/src/armv7-m/arm_schedulesigaction.c | 5 +++++
arch/arm/src/armv7-m/arm_sigdeliver.c | 1 +
arch/arm/src/armv8-m/arm_doirq.c | 16 +++++++---------
arch/arm/src/armv8-m/arm_schedulesigaction.c | 5 +++++
arch/arm/src/armv8-m/arm_sigdeliver.c | 1 +
9 files changed, 39 insertions(+), 27 deletions(-)
diff --git a/arch/arm/src/armv6-m/arm_doirq.c b/arch/arm/src/armv6-m/arm_doirq.c
index 4ee54a70bcf..b1a7e39e880 100644
--- a/arch/arm/src/armv6-m/arm_doirq.c
+++ b/arch/arm/src/armv6-m/arm_doirq.c
@@ -85,15 +85,6 @@ uint32_t *arm_doirq(int irq, uint32_t *regs)
/* Dispatch the PendSV interrupt */
irq_dispatch(irq, regs);
-#endif
-#ifdef CONFIG_ENABLE_ALL_SIGNALS
- if (tcb->sigdeliver)
- {
- /* Pendsv able to access running tcb with no critical section */
-
- up_schedule_sigaction(tcb);
- }
-
#endif
up_irq_save();
}
@@ -104,6 +95,13 @@ uint32_t *arm_doirq(int irq, uint32_t *regs)
tcb = this_task();
+#ifdef CONFIG_ENABLE_ALL_SIGNALS
+ if (tcb->sigdeliver)
+ {
+ up_schedule_sigaction(tcb);
+ }
+#endif
+
/* Update scheduler parameters.
* The arm-m architecture svc call will trigger an interrupt,
* and the actual context switch is executed after doirq is completed,
diff --git a/arch/arm/src/armv6-m/arm_schedulesigaction.c
b/arch/arm/src/armv6-m/arm_schedulesigaction.c
index 0e51f0c5bcd..69cb9bd5c73 100644
--- a/arch/arm/src/armv6-m/arm_schedulesigaction.c
+++ b/arch/arm/src/armv6-m/arm_schedulesigaction.c
@@ -86,6 +86,11 @@ void up_schedule_sigaction(struct tcb_s *tcb)
struct tcb_s *rtcb = running_task();
uint32_t ipsr = getipsr();
+ if (tcb->xcp.saved_regs != NULL)
+ {
+ return;
+ }
+
/* First, handle some special cases when the signal is
* being delivered to the currently executing task.
*/
diff --git a/arch/arm/src/armv6-m/arm_sigdeliver.c
b/arch/arm/src/armv6-m/arm_sigdeliver.c
index f61d216c6e7..ce43e27fff7 100644
--- a/arch/arm/src/armv6-m/arm_sigdeliver.c
+++ b/arch/arm/src/armv6-m/arm_sigdeliver.c
@@ -165,6 +165,7 @@ retry:
g_running_tasks[this_cpu()] = NULL;
rtcb->xcp.regs = rtcb->xcp.saved_regs;
+ rtcb->xcp.saved_regs = NULL;
arm_fullcontextrestore();
UNUSED(regs);
}
diff --git a/arch/arm/src/armv7-m/arm_doirq.c b/arch/arm/src/armv7-m/arm_doirq.c
index 9d22058ea0a..a70e909c167 100644
--- a/arch/arm/src/armv7-m/arm_doirq.c
+++ b/arch/arm/src/armv7-m/arm_doirq.c
@@ -85,15 +85,6 @@ uint32_t *arm_doirq(int irq, uint32_t *regs)
/* Dispatch the PendSV interrupt */
irq_dispatch(irq, regs);
-#endif
-#ifdef CONFIG_ENABLE_ALL_SIGNALS
- if (tcb->sigdeliver)
- {
- /* Pendsv able to access running tcb with no critical section */
-
- up_schedule_sigaction(tcb);
- }
-
#endif
up_irq_save();
@@ -105,6 +96,13 @@ uint32_t *arm_doirq(int irq, uint32_t *regs)
tcb = this_task();
+#ifdef CONFIG_ENABLE_ALL_SIGNALS
+ if (tcb->sigdeliver)
+ {
+ up_schedule_sigaction(tcb);
+ }
+#endif
+
/* Update scheduler parameters.
* The arm-m architecture svc call will trigger an interrupt,
* and the actual context switch is executed after doirq is completed,
diff --git a/arch/arm/src/armv7-m/arm_schedulesigaction.c
b/arch/arm/src/armv7-m/arm_schedulesigaction.c
index db570847049..75e8783ff25 100644
--- a/arch/arm/src/armv7-m/arm_schedulesigaction.c
+++ b/arch/arm/src/armv7-m/arm_schedulesigaction.c
@@ -87,6 +87,11 @@ void up_schedule_sigaction(struct tcb_s *tcb)
struct tcb_s *rtcb = running_task();
uint32_t ipsr = getipsr();
+ if (tcb->xcp.saved_regs != NULL)
+ {
+ return;
+ }
+
/* First, handle some special cases when the signal is
* being delivered to the currently executing task.
*/
diff --git a/arch/arm/src/armv7-m/arm_sigdeliver.c
b/arch/arm/src/armv7-m/arm_sigdeliver.c
index 02b17525288..2ac5aeada24 100644
--- a/arch/arm/src/armv7-m/arm_sigdeliver.c
+++ b/arch/arm/src/armv7-m/arm_sigdeliver.c
@@ -189,6 +189,7 @@ retry:
}
rtcb->xcp.regs = rtcb->xcp.saved_regs;
+ rtcb->xcp.saved_regs = NULL;
arm_fullcontextrestore();
UNUSED(regs);
}
diff --git a/arch/arm/src/armv8-m/arm_doirq.c b/arch/arm/src/armv8-m/arm_doirq.c
index a327eeabd7a..e5ca07a4438 100644
--- a/arch/arm/src/armv8-m/arm_doirq.c
+++ b/arch/arm/src/armv8-m/arm_doirq.c
@@ -97,15 +97,6 @@ uint32_t *arm_doirq(int irq, uint32_t *regs)
/* Dispatch the PendSV interrupt */
irq_dispatch(irq, regs);
-#endif
-#ifdef CONFIG_ENABLE_ALL_SIGNALS
- if (tcb->sigdeliver)
- {
- /* Pendsv able to access running tcb with no critical section */
-
- up_schedule_sigaction(tcb);
- }
-
#endif
up_irq_save();
@@ -117,6 +108,13 @@ uint32_t *arm_doirq(int irq, uint32_t *regs)
tcb = this_task();
+#ifdef CONFIG_ENABLE_ALL_SIGNALS
+ if (tcb->sigdeliver)
+ {
+ up_schedule_sigaction(tcb);
+ }
+#endif
+
/* Update scheduler parameters.
* The arm-m architecture svc call will trigger an interrupt,
* and the actual context switch is executed after doirq is completed,
diff --git a/arch/arm/src/armv8-m/arm_schedulesigaction.c
b/arch/arm/src/armv8-m/arm_schedulesigaction.c
index a24d8fb8f12..8a166eff217 100644
--- a/arch/arm/src/armv8-m/arm_schedulesigaction.c
+++ b/arch/arm/src/armv8-m/arm_schedulesigaction.c
@@ -87,6 +87,11 @@ void up_schedule_sigaction(struct tcb_s *tcb)
struct tcb_s *rtcb = running_task();
uint32_t ipsr = getipsr();
+ if (tcb->xcp.saved_regs != NULL)
+ {
+ return;
+ }
+
/* First, handle some special cases when the signal is
* being delivered to the currently executing task.
*/
diff --git a/arch/arm/src/armv8-m/arm_sigdeliver.c
b/arch/arm/src/armv8-m/arm_sigdeliver.c
index 39e1b0d3be9..5904b4e028e 100644
--- a/arch/arm/src/armv8-m/arm_sigdeliver.c
+++ b/arch/arm/src/armv8-m/arm_sigdeliver.c
@@ -189,6 +189,7 @@ retry:
}
rtcb->xcp.regs = rtcb->xcp.saved_regs;
+ rtcb->xcp.saved_regs = NULL;
arm_fullcontextrestore();
UNUSED(regs);
}