arch: use up_current_regs/up_set_current_regs replace CURRENT_REGS

reason:
1 On different architectures, we can utilize more optimized strategies
  to implement up_current_regs/up_set_current_regs.
eg. use interrupt registersor percpu registers.

code size
before
    text    data     bss     dec     hex filename
 262848   49985   63893  376726   5bf96 nuttx

after
       text    data     bss     dec     hex filename
 262844   49985   63893  376722   5bf92 nuttx

size change -4

Configuring NuttX and compile:
$ ./tools/configure.sh -l qemu-armv8a:nsh_smp
$ make
Running with qemu
$ qemu-system-aarch64 -cpu cortex-a53 -smp 4 -nographic \
   -machine virt,virtualization=on,gic-version=3 \
   -net none -chardev stdio,id=con,mux=on -serial chardev:con \
   -mon chardev=con,mode=readline -kernel ./nuttx

Signed-off-by: hujun5 <hujun5@xiaomi.com>
This commit is contained in:
hujun5
2024-09-13 10:57:38 +08:00
committed by Xiang Xiao
parent 222840e135
commit 908df725ad
207 changed files with 1304 additions and 1134 deletions
+14 -5
View File
@@ -94,9 +94,9 @@ extern "C"
#endif
/* g_current_regs[] holds a references to the current interrupt level
* register storage structure. It is non-NULL only during interrupt
* processing. Access to g_current_regs[] must be through the macro
* CURRENT_REGS for portability.
* register storage structure. If is non-NULL only during interrupt
* processing. Access to g_current_regs[] must be through the
* [get/set]_current_regs for portability.
*/
/* For the case of architectures with multiple CPUs, then there must be one
@@ -104,7 +104,6 @@ extern "C"
*/
EXTERN uint32_t *volatile g_current_regs[CONFIG_SMP_NCPUS];
#define CURRENT_REGS (g_current_regs[up_cpu_index()])
/****************************************************************************
* Public Function Prototypes
@@ -136,6 +135,16 @@ int up_cpu_index(void);
* Inline functions
****************************************************************************/
static inline_function uint32_t *up_current_regs(void)
{
return (uint32_t *)g_current_regs[up_cpu_index()];
}
static inline_function void up_set_current_regs(uint32_t *regs)
{
g_current_regs[up_cpu_index()] = regs;
}
/****************************************************************************
* Name: up_interrupt_context
*
@@ -150,7 +159,7 @@ static inline bool up_interrupt_context(void)
#ifdef CONFIG_SMP
irqstate_t flags = up_irq_save();
#endif
bool ret = CURRENT_REGS != NULL;
bool ret = up_current_regs() != NULL;
#ifdef CONFIG_SMP
up_irq_restore(flags);
+11 -12
View File
@@ -34,9 +34,9 @@
****************************************************************************/
/* g_current_regs[] holds a references to the current interrupt level
* register storage structure. It is non-NULL only during interrupt
* processing. Access to g_current_regs[] must be through the macro
* CURRENT_REGS for portability.
* register storage structure. If is non-NULL only during interrupt
* processing. Access to g_current_regs[] must be through the
* [get/set]_current_regs for portability.
*/
uint32_t *volatile g_current_regs[CONFIG_SMP_NCPUS];
@@ -49,7 +49,7 @@ uint32_t *ceva_doirq(int irq, uint32_t *regs)
{
/* Is it the outermost interrupt? */
if (CURRENT_REGS != NULL)
if (up_current_regs() != NULL)
{
/* No, simply deliver the IRQ because only the outermost nested
* interrupt can result in a context switch.
@@ -60,23 +60,23 @@ uint32_t *ceva_doirq(int irq, uint32_t *regs)
else
{
/* Current regs non-zero indicates that we are processing an interrupt;
* CURRENT_REGS is also used to manage interrupt level context
* current_regs is also used to manage interrupt level context
* switches.
*/
CURRENT_REGS = regs;
up_set_current_regs(regs);
/* Deliver the IRQ */
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
* current_regs may have change value. If we return any value
* different from the input regs, then the lower level will know that
* a context switch occurred during interrupt processing.
*/
if (regs != CURRENT_REGS)
if (regs != up_current_regs())
{
/* Record the new "running" task when context switch occurred.
* g_running_tasks[] is only used by assertion logic for reporting
@@ -84,16 +84,15 @@ uint32_t *ceva_doirq(int irq, uint32_t *regs)
*/
g_running_tasks[this_cpu()] = this_task();
regs = CURRENT_REGS;
regs = up_current_regs();
}
/* Restore the previous value of CURRENT_REGS. NULL would indicate
/* Restore the previous value of current_regs. NULL would indicate
* that we are no longer in an interrupt handler.
* It will be non-NULL if we are returning from a nested interrupt.
*/
CURRENT_REGS = NULL;
up_set_current_regs(NULL);
if (regs != (uint32_t *)regs[REG_SP])
{
+1 -1
View File
@@ -51,7 +51,7 @@ uintptr_t up_getusrsp(void *regs)
void up_dump_register(void *dumpregs)
{
volatile uint32_t *regs = dumpregs ? dumpregs : CURRENT_REGS;
volatile uint32_t *regs = dumpregs ? dumpregs : up_current_regs();
int rx;
/* Dump the interrupt registers */
@@ -87,7 +87,7 @@ void up_schedule_sigaction(struct tcb_s *tcb, sig_deliver_t sigdeliver)
* to task that is currently executing on any CPU.
*/
sinfo("rtcb=%p CURRENT_REGS=%p\n", this_task(), CURRENT_REGS);
sinfo("rtcb=%p current_regs=%p\n", this_task(), up_current_regs());
if (tcb->task_state == TSTATE_TASK_RUNNING)
{
@@ -102,7 +102,7 @@ void up_schedule_sigaction(struct tcb_s *tcb, sig_deliver_t sigdeliver)
* signaling itself for some reason.
*/
if (cpu == me && !CURRENT_REGS)
if (cpu == me && !up_current_regs())
{
/* In this case just deliver the signal now. */
@@ -137,28 +137,28 @@ void up_schedule_sigaction(struct tcb_s *tcb, sig_deliver_t sigdeliver)
/* Save the current register context location */
tcb->xcp.saved_regs = g_current_regs[cpu];
tcb->xcp.saved_regs = up_current_regs();
/* Duplicate the register context. These will be
* restored by the signal trampoline after the signal has been
* delivered.
*/
g_current_regs[cpu] -= XCPTCONTEXT_REGS;
memcpy(g_current_regs[cpu], g_current_regs[cpu] +
up_current_regs() -= XCPTCONTEXT_REGS;
memcpy(up_current_regs(), up_current_regs() +
XCPTCONTEXT_REGS, XCPTCONTEXT_SIZE);
g_current_regs[cpu][REG_SP] = (uint32_t)g_current_regs[cpu];
up_current_regs()[REG_SP] = (uint32_t)up_current_regs();
/* Then set up to vector to the trampoline with interrupts
* unchanged. We must already be in privileged thread mode
* to be here.
*/
g_current_regs[cpu][REG_PC] = (uint32_t)ceva_sigdeliver;
up_current_regs()[REG_PC] = (uint32_t)ceva_sigdeliver;
#ifdef REG_OM
g_current_regs[cpu][REG_OM] &= ~REG_OM_MASK;
g_current_regs[cpu][REG_OM] |= REG_OM_KERNEL;
up_current_regs()[REG_OM] &= ~REG_OM_MASK;
up_current_regs()[REG_OM] |= REG_OM_KERNEL;
#endif
#ifdef CONFIG_SMP
+15 -15
View File
@@ -52,7 +52,7 @@ int ceva_svcall(int irq, void *context, void *arg)
uint32_t *regs = (uint32_t *)context;
uint32_t cmd;
DEBUGASSERT(regs && regs == CURRENT_REGS);
DEBUGASSERT(regs && regs == up_current_regs());
cmd = regs[REG_A0];
/* The SVCall software interrupt is called with A0 = system call command
@@ -112,16 +112,16 @@ int ceva_svcall(int irq, void *context, void *arg)
* A0 = SYS_restore_context
* A1 = restoreregs
*
* In this case, we simply need to set CURRENT_REGS to restore register
* area referenced in the saved A1. context == CURRENT_REGS is the
* noraml exception return. By setting CURRENT_REGS = context[A1],
* In this case, we simply need to set current_regs to restore register
* area referenced in the saved A1. context == current_regs is the
* noraml exception return. By setting current_regs = context[A1],
* we force the return to the saved context referenced in A1.
*/
case SYS_restore_context:
{
DEBUGASSERT(regs[REG_A1] != 0);
CURRENT_REGS = (uint32_t *)regs[REG_A1];
up_set_current_regs((uint32_t *)regs[REG_A1]);
}
break;
@@ -138,7 +138,7 @@ int ceva_svcall(int irq, void *context, void *arg)
*
* In this case, we do both: We save the context registers to the save
* register area reference by the saved contents of A1 and then set
* CURRENT_REGS to to the save register area referenced by the saved
* current_regs to to the save register area referenced by the saved
* contents of A2.
*/
@@ -146,7 +146,7 @@ int ceva_svcall(int irq, void *context, void *arg)
{
DEBUGASSERT(regs[REG_A1] != 0 && regs[REG_A2] != 0);
*(uint32_t **)regs[REG_A1] = regs;
CURRENT_REGS = (uint32_t *)regs[REG_A2];
up_set_current_regs((uint32_t *)regs[REG_A2]);
}
break;
@@ -384,20 +384,20 @@ int ceva_svcall(int irq, void *context, void *arg)
# ifndef CONFIG_DEBUG_SVCALL
if (cmd > SYS_switch_context)
# else
if (regs != CURRENT_REGS)
if (regs != up_current_regs())
# endif
{
svcinfo("SVCall Return:\n");
svcinfo("A0: %08x %08x %08x %08x %08x %08x %08x\n",
CURRENT_REGS[REG_A0], CURRENT_REGS[REG_A1],
CURRENT_REGS[REG_A2], CURRENT_REGS[REG_A3],
CURRENT_REGS[REG_A4], CURRENT_REGS[REG_A5],
CURRENT_REGS[REG_A6]);
up_current_regs()[REG_A0], up_current_regs()[REG_A1],
up_current_regs()[REG_A2], up_current_regs()[REG_A3],
up_current_regs()[REG_A4], up_current_regs()[REG_A5],
up_current_regs()[REG_A6]);
svcinfo("FP: %08x LR: %08x PC: %08x IRQ: %08x OM: %08x\n",
CURRENT_REGS[REG_FP], CURRENT_REGS[REG_LR],
CURRENT_REGS[REG_PC], CURRENT_REGS[REG_IRQ],
up_current_regs()[REG_FP], up_current_regs()[REG_LR],
up_current_regs()[REG_PC], up_current_regs()[REG_IRQ],
# ifdef REG_OM
CURRENT_REGS[REG_OM]
up_current_regs()[REG_OM]
#else
0x00000000
#endif
+4 -4
View File
@@ -75,13 +75,13 @@ void up_switch_context(struct tcb_s *tcb, struct tcb_s *rtcb)
/* Are we in an interrupt handler? */
if (CURRENT_REGS)
if (up_current_regs())
{
/* Yes, then we have to do things differently.
* Just copy the CURRENT_REGS into the OLD rtcb.
* Just copy the current_regs into the OLD rtcb.
*/
rtcb->xcp.regs = CURRENT_REGS;
rtcb->xcp.regs = up_current_regs();
/* Update scheduler parameters */
@@ -89,7 +89,7 @@ void up_switch_context(struct tcb_s *tcb, struct tcb_s *rtcb)
/* Then switch contexts */
CURRENT_REGS = tcb->xcp.regs;
up_set_current_regs(tcb->xcp.regs);
}
/* No, then we will need to perform the user context switch */