From af3c159cffc13e933c6a89f85f9342272d24bc9a Mon Sep 17 00:00:00 2001 From: buxiasen Date: Wed, 4 Dec 2024 14:08:51 +0800 Subject: [PATCH] arm-v6/7/8m: sigaction forward to pendsv For exception directly, tcb->xcp.regs should not be used. Signed-off-by: buxiasen --- arch/arm/src/armv6-m/arm_doirq.c | 10 ++++++++-- arch/arm/src/armv6-m/arm_schedulesigaction.c | 16 +++++++++++++--- arch/arm/src/armv7-m/arm_doirq.c | 10 ++++++++-- arch/arm/src/armv7-m/arm_schedulesigaction.c | 16 +++++++++++++--- arch/arm/src/armv8-m/arm_doirq.c | 10 ++++++++-- arch/arm/src/armv8-m/arm_schedulesigaction.c | 16 +++++++++++++--- 6 files changed, 63 insertions(+), 15 deletions(-) diff --git a/arch/arm/src/armv6-m/arm_doirq.c b/arch/arm/src/armv6-m/arm_doirq.c index e3e6383e48..ae928c8e0e 100644 --- a/arch/arm/src/armv6-m/arm_doirq.c +++ b/arch/arm/src/armv6-m/arm_doirq.c @@ -57,7 +57,7 @@ void exception_direct(void) uint32_t *arm_doirq(int irq, uint32_t *regs) { struct tcb_s **running_task = &g_running_tasks[this_cpu()]; - FAR struct tcb_s *tcb; + struct tcb_s *tcb = *running_task; /* This judgment proves that (*running_task)->xcp.regs * is invalid, and we can safely overwrite it. @@ -65,7 +65,7 @@ uint32_t *arm_doirq(int irq, uint32_t *regs) if (!(NVIC_IRQ_SVCALL == irq && regs[REG_R0] == SYS_restore_context)) { - (*running_task)->xcp.regs = regs; + tcb->xcp.regs = regs; } board_autoled_on(LED_INIRQ); @@ -84,6 +84,12 @@ uint32_t *arm_doirq(int irq, uint32_t *regs) irq_dispatch(irq, regs); #endif + if (tcb->sigdeliver) + { + /* Pendsv able to access running tcb with no critical section */ + + up_schedule_sigaction(tcb); + } up_irq_save(); } diff --git a/arch/arm/src/armv6-m/arm_schedulesigaction.c b/arch/arm/src/armv6-m/arm_schedulesigaction.c index 7020982141..9702814cdb 100644 --- a/arch/arm/src/armv6-m/arm_schedulesigaction.c +++ b/arch/arm/src/armv6-m/arm_schedulesigaction.c @@ -37,6 +37,7 @@ #include "sched/sched.h" #include "arm_internal.h" #include "irq/irq.h" +#include "nvic.h" /**************************************************************************** * Public Functions @@ -80,13 +81,14 @@ void up_schedule_sigaction(struct tcb_s *tcb) { - FAR struct tcb_s *rtcb = running_task(); + struct tcb_s *rtcb = running_task(); + uint32_t ipsr = getipsr(); /* First, handle some special cases when the signal is * being delivered to the currently executing task. */ - if (tcb == rtcb && !up_interrupt_context()) + if (tcb == rtcb && ipsr == 0) { /* In this case just deliver the signal now. * REVISIT: Signal handle will run in a critical section! @@ -95,7 +97,15 @@ void up_schedule_sigaction(struct tcb_s *tcb) (tcb->sigdeliver)(tcb); tcb->sigdeliver = NULL; } - else + else if (tcb == rtcb && ipsr != NVIC_IRQ_PENDSV) + { + /* Context switch should be done in pendsv, for exception directly + * last regs is not saved tcb->xcp.regs. + */ + + up_trigger_irq(NVIC_IRQ_PENDSV, 0); + } + else /* ipsr == NVIC_IRQ_PENDSV || tcb != rtcb */ { /* Save the return PC, CPSR and either the BASEPRI or PRIMASK * registers (and perhaps also the LR). These will be restored diff --git a/arch/arm/src/armv7-m/arm_doirq.c b/arch/arm/src/armv7-m/arm_doirq.c index dcbdd9dc12..8313073ffb 100644 --- a/arch/arm/src/armv7-m/arm_doirq.c +++ b/arch/arm/src/armv7-m/arm_doirq.c @@ -57,7 +57,7 @@ void exception_direct(void) uint32_t *arm_doirq(int irq, uint32_t *regs) { struct tcb_s **running_task = &g_running_tasks[this_cpu()]; - FAR struct tcb_s *tcb; + struct tcb_s *tcb = *running_task; /* This judgment proves that (*running_task)->xcp.regs * is invalid, and we can safely overwrite it. @@ -65,7 +65,7 @@ uint32_t *arm_doirq(int irq, uint32_t *regs) if (!(NVIC_IRQ_SVCALL == irq && regs[REG_R0] == SYS_restore_context)) { - (*running_task)->xcp.regs = regs; + tcb->xcp.regs = regs; } board_autoled_on(LED_INIRQ); @@ -84,6 +84,12 @@ uint32_t *arm_doirq(int irq, uint32_t *regs) irq_dispatch(irq, regs); #endif + if (tcb->sigdeliver) + { + /* Pendsv able to access running tcb with no critical section */ + + up_schedule_sigaction(tcb); + } up_irq_save(); } diff --git a/arch/arm/src/armv7-m/arm_schedulesigaction.c b/arch/arm/src/armv7-m/arm_schedulesigaction.c index 8987c36b3c..1825242110 100644 --- a/arch/arm/src/armv7-m/arm_schedulesigaction.c +++ b/arch/arm/src/armv7-m/arm_schedulesigaction.c @@ -38,6 +38,7 @@ #include "sched/sched.h" #include "arm_internal.h" #include "irq/irq.h" +#include "nvic.h" /**************************************************************************** * Public Functions @@ -81,13 +82,14 @@ void up_schedule_sigaction(struct tcb_s *tcb) { - FAR struct tcb_s *rtcb = running_task(); + struct tcb_s *rtcb = running_task(); + uint32_t ipsr = getipsr(); /* First, handle some special cases when the signal is * being delivered to the currently executing task. */ - if (tcb == rtcb && !up_interrupt_context()) + if (tcb == rtcb && ipsr == 0) { /* In this case just deliver the signal now. * REVISIT: Signal handle will run in a critical section! @@ -96,7 +98,15 @@ void up_schedule_sigaction(struct tcb_s *tcb) (tcb->sigdeliver)(tcb); tcb->sigdeliver = NULL; } - else + else if (tcb == rtcb && ipsr != NVIC_IRQ_PENDSV) + { + /* Context switch should be done in pendsv, for exception directly + * last regs is not saved tcb->xcp.regs. + */ + + up_trigger_irq(NVIC_IRQ_PENDSV, 0); + } + else /* ipsr == NVIC_IRQ_PENDSV || tcb != rtcb */ { /* Save the return PC, CPSR and either the BASEPRI or PRIMASK * registers (and perhaps also the LR). These will be restored diff --git a/arch/arm/src/armv8-m/arm_doirq.c b/arch/arm/src/armv8-m/arm_doirq.c index 55183573a5..77cef0bde6 100644 --- a/arch/arm/src/armv8-m/arm_doirq.c +++ b/arch/arm/src/armv8-m/arm_doirq.c @@ -68,7 +68,7 @@ void exception_direct(void) uint32_t *arm_doirq(int irq, uint32_t *regs) { struct tcb_s **running_task = &g_running_tasks[this_cpu()]; - FAR struct tcb_s *tcb; + struct tcb_s *tcb = *running_task; /* This judgment proves that (*running_task)->xcp.regs * is invalid, and we can safely overwrite it. @@ -76,7 +76,7 @@ uint32_t *arm_doirq(int irq, uint32_t *regs) if (!(NVIC_IRQ_SVCALL == irq && regs[REG_R0] == SYS_restore_context)) { - (*running_task)->xcp.regs = regs; + tcb->xcp.regs = regs; } board_autoled_on(LED_INIRQ); @@ -95,6 +95,12 @@ uint32_t *arm_doirq(int irq, uint32_t *regs) irq_dispatch(irq, regs); #endif + if (tcb->sigdeliver) + { + /* Pendsv able to access running tcb with no critical section */ + + up_schedule_sigaction(tcb); + } up_irq_save(); } diff --git a/arch/arm/src/armv8-m/arm_schedulesigaction.c b/arch/arm/src/armv8-m/arm_schedulesigaction.c index 230f374eae..2983b2470a 100644 --- a/arch/arm/src/armv8-m/arm_schedulesigaction.c +++ b/arch/arm/src/armv8-m/arm_schedulesigaction.c @@ -38,6 +38,7 @@ #include "sched/sched.h" #include "arm_internal.h" #include "irq/irq.h" +#include "nvic.h" /**************************************************************************** * Public Functions @@ -81,13 +82,14 @@ void up_schedule_sigaction(struct tcb_s *tcb) { - FAR struct tcb_s *rtcb = running_task(); + struct tcb_s *rtcb = running_task(); + uint32_t ipsr = getipsr(); /* First, handle some special cases when the signal is * being delivered to the currently executing task. */ - if (tcb == rtcb && !up_interrupt_context()) + if (tcb == rtcb && ipsr == 0) { /* In this case just deliver the signal now. * REVISIT: Signal handle will run in a critical section! @@ -96,7 +98,15 @@ void up_schedule_sigaction(struct tcb_s *tcb) (tcb->sigdeliver)(tcb); tcb->sigdeliver = NULL; } - else + else if (tcb == rtcb && ipsr != NVIC_IRQ_PENDSV) + { + /* Context switch should be done in pendsv, for exception directly + * last regs is not saved tcb->xcp.regs. + */ + + up_trigger_irq(NVIC_IRQ_PENDSV, 0); + } + else /* ipsr == NVIC_IRQ_PENDSV || tcb != rtcb */ { /* Save the return PC, CPSR and either the BASEPRI or PRIMASK * registers (and perhaps also the LR). These will be restored