armv6/7/8m: use pendsv to handle context switch
This PR support Nested interrupt in armv6/7/8m: There are two types of nested interrupt model: Zero latency nested interrupt Interrupt Priority Note Data abort Highest SVC 0x50 High irq1 0x60 ISR can't access system API irq_save() 0x70 High irq2 0x80 ISR can't access system API normal irq3 0xB0 We have already support this mode before this PR Nested interrupt which interrupt level lower than up_irq_save() Interrupt Priority Note Data abort Highest SVC 0x70 irq_save() 0x80 High irq1 0x90 ISR can access system API High irq2 0xA0 ISR can access system API normal irq3 0xB0 Now, this PR can support this mode Signed-off-by: ligd <liguiding1@xiaomi.com>
This commit is contained in:
parent
064415a765
commit
8b8a2610ab
@ -35,11 +35,25 @@
|
||||
|
||||
#include "arm_internal.h"
|
||||
#include "exc_return.h"
|
||||
#include "nvic.h"
|
||||
|
||||
/****************************************************************************
|
||||
* Public Functions
|
||||
****************************************************************************/
|
||||
|
||||
void exception_direct(void)
|
||||
{
|
||||
int irq = getipsr();
|
||||
|
||||
arm_ack_irq(irq);
|
||||
irq_dispatch(irq, NULL);
|
||||
|
||||
if (g_running_tasks[this_cpu()] != this_task())
|
||||
{
|
||||
up_trigger_irq(NVIC_IRQ_PENDSV, 0);
|
||||
}
|
||||
}
|
||||
|
||||
uint32_t *arm_doirq(int irq, uint32_t *regs)
|
||||
{
|
||||
struct tcb_s *tcb = this_task();
|
||||
@ -49,19 +63,20 @@ uint32_t *arm_doirq(int irq, uint32_t *regs)
|
||||
PANIC();
|
||||
#else
|
||||
|
||||
if (regs[REG_EXC_RETURN] & EXC_RETURN_THREAD_MODE)
|
||||
{
|
||||
tcb->xcp.regs = regs;
|
||||
up_set_current_regs(regs);
|
||||
}
|
||||
|
||||
/* Acknowledge the interrupt */
|
||||
|
||||
arm_ack_irq(irq);
|
||||
|
||||
/* Deliver the IRQ */
|
||||
|
||||
if (irq == NVIC_IRQ_PENDSV)
|
||||
{
|
||||
up_irq_save();
|
||||
g_running_tasks[this_cpu()]->xcp.regs = regs;
|
||||
}
|
||||
else
|
||||
{
|
||||
tcb->xcp.regs = regs;
|
||||
irq_dispatch(irq, regs);
|
||||
}
|
||||
|
||||
/* If a context switch occurred while processing the interrupt then
|
||||
* current_regs may have change value. If we return any value different
|
||||
@ -69,12 +84,8 @@ uint32_t *arm_doirq(int irq, uint32_t *regs)
|
||||
* switch occurred during interrupt processing.
|
||||
*/
|
||||
|
||||
if (regs[REG_EXC_RETURN] & EXC_RETURN_THREAD_MODE)
|
||||
{
|
||||
tcb = this_task();
|
||||
|
||||
if (regs != tcb->xcp.regs)
|
||||
{
|
||||
/* Update scheduler parameters */
|
||||
|
||||
nxsched_suspend_scheduler(g_running_tasks[this_cpu()]);
|
||||
@ -87,12 +98,6 @@ uint32_t *arm_doirq(int irq, uint32_t *regs)
|
||||
|
||||
g_running_tasks[this_cpu()] = tcb;
|
||||
regs = tcb->xcp.regs;
|
||||
}
|
||||
|
||||
/* Update the current_regs to NULL. */
|
||||
|
||||
up_set_current_regs(NULL);
|
||||
}
|
||||
#endif
|
||||
|
||||
board_autoled_off(LED_INIRQ);
|
||||
|
@ -121,7 +121,6 @@ int arm_svcall(int irq, void *context, void *arg)
|
||||
uint32_t *regs = (uint32_t *)context;
|
||||
uint32_t cmd;
|
||||
|
||||
DEBUGASSERT(regs && regs == up_current_regs());
|
||||
cmd = regs[REG_R0];
|
||||
|
||||
/* The SVCall software interrupt is called with R0 = system call command
|
||||
|
@ -45,6 +45,8 @@
|
||||
|
||||
#include "chip.h"
|
||||
#include "arm_internal.h"
|
||||
#include "ram_vectors.h"
|
||||
#include "nvic.h"
|
||||
|
||||
/****************************************************************************
|
||||
* Pre-processor Definitions
|
||||
@ -81,6 +83,7 @@ static void start(void)
|
||||
/* Common exception entrypoint */
|
||||
|
||||
extern void exception_common(void);
|
||||
extern void exception_direct(void);
|
||||
|
||||
/****************************************************************************
|
||||
* Public data
|
||||
@ -92,7 +95,7 @@ extern void exception_common(void);
|
||||
* As all exceptions (interrupts) are routed via exception_common, we just
|
||||
* need to fill this array with pointers to it.
|
||||
*
|
||||
* Note that the [ ... ] designated initialiser is a GCC extension.
|
||||
* Note that the [ ... ] designated initializer is a GCC extension.
|
||||
*/
|
||||
|
||||
const void * const _vectors[] locate_data(".vectors") =
|
||||
@ -107,5 +110,7 @@ const void * const _vectors[] locate_data(".vectors") =
|
||||
|
||||
/* Vectors 2 - n point directly at the generic handler */
|
||||
|
||||
[2 ... (15 + ARMV6M_PERIPHERAL_INTERRUPTS)] = exception_common
|
||||
[2 ... NVIC_IRQ_PENDSV] = &exception_common,
|
||||
[(NVIC_IRQ_PENDSV + 1) ... (15 + ARMV6M_PERIPHERAL_INTERRUPTS)]
|
||||
= &exception_direct
|
||||
};
|
||||
|
@ -35,11 +35,25 @@
|
||||
|
||||
#include "arm_internal.h"
|
||||
#include "exc_return.h"
|
||||
#include "nvic.h"
|
||||
|
||||
/****************************************************************************
|
||||
* Public Functions
|
||||
****************************************************************************/
|
||||
|
||||
void exception_direct(void)
|
||||
{
|
||||
int irq = getipsr();
|
||||
|
||||
arm_ack_irq(irq);
|
||||
irq_dispatch(irq, NULL);
|
||||
|
||||
if (g_running_tasks[this_cpu()] != this_task())
|
||||
{
|
||||
up_trigger_irq(NVIC_IRQ_PENDSV, 0);
|
||||
}
|
||||
}
|
||||
|
||||
uint32_t *arm_doirq(int irq, uint32_t *regs)
|
||||
{
|
||||
struct tcb_s *tcb = this_task();
|
||||
@ -49,19 +63,20 @@ uint32_t *arm_doirq(int irq, uint32_t *regs)
|
||||
PANIC();
|
||||
#else
|
||||
|
||||
if (regs[REG_EXC_RETURN] & EXC_RETURN_THREAD_MODE)
|
||||
{
|
||||
tcb->xcp.regs = regs;
|
||||
up_set_current_regs(regs);
|
||||
}
|
||||
|
||||
/* Acknowledge the interrupt */
|
||||
|
||||
arm_ack_irq(irq);
|
||||
|
||||
/* Deliver the IRQ */
|
||||
|
||||
if (irq == NVIC_IRQ_PENDSV)
|
||||
{
|
||||
up_irq_save();
|
||||
g_running_tasks[this_cpu()]->xcp.regs = regs;
|
||||
}
|
||||
else
|
||||
{
|
||||
tcb->xcp.regs = regs;
|
||||
irq_dispatch(irq, regs);
|
||||
}
|
||||
|
||||
/* If a context switch occurred while processing the interrupt then
|
||||
* current_regs may have change value. If we return any value different
|
||||
@ -69,12 +84,8 @@ uint32_t *arm_doirq(int irq, uint32_t *regs)
|
||||
* switch occurred during interrupt processing.
|
||||
*/
|
||||
|
||||
if (regs[REG_EXC_RETURN] & EXC_RETURN_THREAD_MODE)
|
||||
{
|
||||
tcb = this_task();
|
||||
|
||||
if (regs != tcb->xcp.regs)
|
||||
{
|
||||
/* Update scheduler parameters */
|
||||
|
||||
nxsched_suspend_scheduler(g_running_tasks[this_cpu()]);
|
||||
@ -87,12 +98,6 @@ uint32_t *arm_doirq(int irq, uint32_t *regs)
|
||||
|
||||
g_running_tasks[this_cpu()] = tcb;
|
||||
regs = tcb->xcp.regs;
|
||||
}
|
||||
|
||||
/* Update the current_regs to NULL. */
|
||||
|
||||
up_set_current_regs(NULL);
|
||||
}
|
||||
#endif
|
||||
|
||||
board_autoled_off(LED_INIRQ);
|
||||
|
@ -129,7 +129,6 @@ int arm_svcall(int irq, void *context, void *arg)
|
||||
uint32_t *regs = (uint32_t *)context;
|
||||
uint32_t cmd;
|
||||
|
||||
DEBUGASSERT(regs && regs == up_current_regs());
|
||||
cmd = regs[REG_R0];
|
||||
|
||||
/* The SVCall software interrupt is called with R0 = system call command
|
||||
@ -299,8 +298,9 @@ int arm_svcall(int irq, void *context, void *arg)
|
||||
* At this point, the following values are saved in context:
|
||||
*
|
||||
* R0 = SYS_pthread_start
|
||||
* R1 = entrypt
|
||||
* R2 = arg
|
||||
* R1 = startup (trampoline)
|
||||
* R2 = entrypt
|
||||
* R3 = arg
|
||||
*/
|
||||
|
||||
#if !defined(CONFIG_BUILD_FLAT) && !defined(CONFIG_DISABLE_PTHREAD)
|
||||
|
@ -41,6 +41,7 @@
|
||||
#include "chip.h"
|
||||
#include "arm_internal.h"
|
||||
#include "ram_vectors.h"
|
||||
#include "nvic.h"
|
||||
|
||||
/****************************************************************************
|
||||
* Pre-processor Definitions
|
||||
@ -71,6 +72,7 @@ static void start(void)
|
||||
/* Common exception entrypoint */
|
||||
|
||||
extern void exception_common(void);
|
||||
extern void exception_direct(void);
|
||||
|
||||
/****************************************************************************
|
||||
* Public data
|
||||
@ -98,5 +100,7 @@ const void * const _vectors[] locate_data(".vectors")
|
||||
|
||||
/* Vectors 2 - n point directly at the generic handler */
|
||||
|
||||
[2 ... (15 + ARMV7M_PERIPHERAL_INTERRUPTS)] = exception_common
|
||||
[2 ... NVIC_IRQ_PENDSV] = &exception_common,
|
||||
[(NVIC_IRQ_PENDSV + 1) ... (15 + ARMV7M_PERIPHERAL_INTERRUPTS)]
|
||||
= &exception_direct
|
||||
};
|
||||
|
@ -35,60 +35,25 @@
|
||||
|
||||
#include "arm_internal.h"
|
||||
#include "exc_return.h"
|
||||
|
||||
/****************************************************************************
|
||||
* Inline Functions
|
||||
****************************************************************************/
|
||||
|
||||
/****************************************************************************
|
||||
* Name: arm_from_thread
|
||||
*
|
||||
* Description:
|
||||
* If not defined CONFIG_ARCH_HAVE_TRUSTZONE
|
||||
* Return true if interrupt return to thread mode, false otherwise.
|
||||
*
|
||||
* If defined CONFIG_ARCH_HAVE_TRUSTZONE
|
||||
* Return true if interrupt return to thread mode, or if it is the first
|
||||
* interrupt from TEE to REE, or REE to TEE, false otherwise.
|
||||
*
|
||||
* Interrupt nesting between TEE and REE can be determined based
|
||||
* on the S and ES bits of EXC_RETURN
|
||||
* If TEE interrupts REE, then EXC_RETURN.S=0, EXC_RETURN.ES=1;
|
||||
* Conversely, EXC_RETURN.S=1, EXC_RETURN.ES=0.
|
||||
*
|
||||
* But only one level nesting between TEE and REE is supported, and
|
||||
* recursive nesting between TEE and REE is not supported.
|
||||
*
|
||||
****************************************************************************/
|
||||
|
||||
static inline bool arm_from_thread(uint32_t excret)
|
||||
{
|
||||
if (excret & EXC_RETURN_THREAD_MODE)
|
||||
{
|
||||
return true;
|
||||
}
|
||||
|
||||
#if defined(CONFIG_ARCH_TRUSTZONE_SECURE)
|
||||
if (!(excret & EXC_RETURN_SECURE_STACK) &&
|
||||
(excret & EXC_RETURN_EXC_SECURE))
|
||||
{
|
||||
return true;
|
||||
}
|
||||
|
||||
if (!(excret & EXC_RETURN_EXC_SECURE) &&
|
||||
(excret & EXC_RETURN_SECURE_STACK))
|
||||
{
|
||||
return true;
|
||||
}
|
||||
#endif
|
||||
|
||||
return false;
|
||||
}
|
||||
#include "nvic.h"
|
||||
|
||||
/****************************************************************************
|
||||
* Public Functions
|
||||
****************************************************************************/
|
||||
|
||||
void exception_direct(void)
|
||||
{
|
||||
int irq = getipsr();
|
||||
|
||||
arm_ack_irq(irq);
|
||||
irq_dispatch(irq, NULL);
|
||||
|
||||
if (g_running_tasks[this_cpu()] != this_task())
|
||||
{
|
||||
up_trigger_irq(NVIC_IRQ_PENDSV, 0);
|
||||
}
|
||||
}
|
||||
|
||||
uint32_t *arm_doirq(int irq, uint32_t *regs)
|
||||
{
|
||||
struct tcb_s *tcb = this_task();
|
||||
@ -98,19 +63,20 @@ uint32_t *arm_doirq(int irq, uint32_t *regs)
|
||||
PANIC();
|
||||
#else
|
||||
|
||||
if (arm_from_thread(regs[REG_EXC_RETURN]))
|
||||
{
|
||||
tcb->xcp.regs = regs;
|
||||
up_set_current_regs(regs);
|
||||
}
|
||||
|
||||
/* Acknowledge the interrupt */
|
||||
|
||||
arm_ack_irq(irq);
|
||||
|
||||
/* Deliver the IRQ */
|
||||
|
||||
if (irq == NVIC_IRQ_PENDSV)
|
||||
{
|
||||
up_irq_save();
|
||||
g_running_tasks[this_cpu()]->xcp.regs = regs;
|
||||
}
|
||||
else
|
||||
{
|
||||
tcb->xcp.regs = regs;
|
||||
irq_dispatch(irq, regs);
|
||||
}
|
||||
|
||||
/* If a context switch occurred while processing the interrupt then
|
||||
* current_regs may have change value. If we return any value different
|
||||
@ -118,12 +84,8 @@ uint32_t *arm_doirq(int irq, uint32_t *regs)
|
||||
* switch occurred during interrupt processing.
|
||||
*/
|
||||
|
||||
if (arm_from_thread(regs[REG_EXC_RETURN]))
|
||||
{
|
||||
tcb = this_task();
|
||||
|
||||
if (regs != tcb->xcp.regs)
|
||||
{
|
||||
/* Update scheduler parameters */
|
||||
|
||||
nxsched_suspend_scheduler(g_running_tasks[this_cpu()]);
|
||||
@ -136,12 +98,6 @@ uint32_t *arm_doirq(int irq, uint32_t *regs)
|
||||
|
||||
g_running_tasks[this_cpu()] = tcb;
|
||||
regs = tcb->xcp.regs;
|
||||
}
|
||||
|
||||
/* Update the current_regs to NULL. */
|
||||
|
||||
up_set_current_regs(NULL);
|
||||
}
|
||||
#endif
|
||||
|
||||
board_autoled_off(LED_INIRQ);
|
||||
|
@ -24,6 +24,7 @@
|
||||
|
||||
#include <nuttx/config.h>
|
||||
|
||||
#include <inttypes.h>
|
||||
#include <stdint.h>
|
||||
#include <string.h>
|
||||
#include <assert.h>
|
||||
@ -128,7 +129,6 @@ int arm_svcall(int irq, void *context, void *arg)
|
||||
uint32_t *regs = (uint32_t *)context;
|
||||
uint32_t cmd;
|
||||
|
||||
DEBUGASSERT(regs && regs == up_current_regs());
|
||||
cmd = regs[REG_R0];
|
||||
|
||||
/* The SVCall software interrupt is called with R0 = system call command
|
||||
@ -398,7 +398,6 @@ int arm_svcall(int irq, void *context, void *arg)
|
||||
/* Return privileged mode */
|
||||
|
||||
regs[REG_CONTROL] = getcontrol() & ~CONTROL_NPRIV;
|
||||
|
||||
rtcb->xcp.sigreturn = 0;
|
||||
}
|
||||
break;
|
||||
@ -447,7 +446,7 @@ int arm_svcall(int irq, void *context, void *arg)
|
||||
|
||||
rtcb->flags |= TCB_FLAG_SYSCALL;
|
||||
#else
|
||||
svcerr("ERROR: Bad SYS call: %d\n", (int)regs[REG_R0]);
|
||||
svcerr("ERROR: Bad SYS call: %" PRId32 "\n", regs[REG_R0]);
|
||||
#endif
|
||||
}
|
||||
break;
|
||||
|
@ -40,6 +40,8 @@
|
||||
|
||||
#include "chip.h"
|
||||
#include "arm_internal.h"
|
||||
#include "ram_vectors.h"
|
||||
#include "nvic.h"
|
||||
|
||||
/****************************************************************************
|
||||
* Pre-processor Definitions
|
||||
@ -74,12 +76,13 @@ static void start(void)
|
||||
/* Common exception entrypoint */
|
||||
|
||||
extern void exception_common(void);
|
||||
extern void exception_direct(void);
|
||||
|
||||
/****************************************************************************
|
||||
* Public data
|
||||
****************************************************************************/
|
||||
|
||||
/* The v7m vector table consists of an array of function pointers, with the
|
||||
/* The v8m vector table consists of an array of function pointers, with the
|
||||
* first slot (vector zero) used to hold the initial stack pointer.
|
||||
*
|
||||
* As all exceptions (interrupts) are routed via exception_common, we just
|
||||
@ -100,5 +103,7 @@ const void * const _vectors[] locate_data(".vectors") =
|
||||
|
||||
/* Vectors 2 - n point directly at the generic handler */
|
||||
|
||||
[2 ... (15 + ARMV8M_PERIPHERAL_INTERRUPTS)] = &exception_common
|
||||
[2 ... NVIC_IRQ_PENDSV] = &exception_common,
|
||||
[(NVIC_IRQ_PENDSV + 1) ... (15 + ARMV8M_PERIPHERAL_INTERRUPTS)]
|
||||
= &exception_direct
|
||||
};
|
||||
|
Loading…
Reference in New Issue
Block a user