arch/sparc change common file to support SMP

This commit is contained in:
zouboan 2022-10-27 15:42:36 +08:00 committed by Masayuki Ishikawa
parent 488a56280a
commit b3ff4ce301
19 changed files with 410 additions and 72 deletions

View file

@ -32,6 +32,19 @@ config ARCH_CHIP_BM3823
---help---
Microchip BM3823 (ARCH_SPARC_V8)
config ARCH_CHIP_S698PM
bool "S698PM"
select ARCH_SPARC_V8
select ARCH_HAVE_MATH_H
select ARCH_HAVE_IRQPRIO
select ARCH_VECNOTIRQ
select ARCH_HAVE_RAMFUNCS
select ARCH_HAVE_MULTICPU
select ARCH_HAVE_TESTSET
select ARCH_HAVE_SERIAL_TERMIOS
---help---
Microchip S698PM (ARCH_SPARC_V8)
endchoice
config ARCH_SPARC_V8
@ -47,9 +60,11 @@ config ARCH_CHIP
string
default "bm3803" if ARCH_CHIP_BM3803
default "bm3823" if ARCH_CHIP_BM3823
default "s698pm" if ARCH_CHIP_S698PM
source arch/sparc/src/sparc_v8/Kconfig
source arch/sparc/src/bm3803/Kconfig
source arch/sparc/src/bm3823/Kconfig
source arch/sparc/src/s698pm/Kconfig
endif

View file

@ -92,11 +92,18 @@ static inline uint32_t up_getsp(void)
* Public Data
****************************************************************************/
/* This holds a references to the current interrupt level register storage
* structure. If is non-NULL only during interrupt processing.
/* g_current_regs[] holds a references to the current interrupt level
* register storage structure. If is non-NULL only during interrupt
* processing. Access to g_current_regs[] must be through the macro
* CURRENT_REGS for portability.
*/
EXTERN volatile uint32_t *g_current_regs;
/* For the case of architectures with multiple CPUs, then there must be one
* such value for each processor that can receive an interrupt.
*/
EXTERN volatile uint32_t *g_current_regs[CONFIG_SMP_NCPUS];
#define CURRENT_REGS (g_current_regs[up_cpu_index()])
/****************************************************************************
* Public Function Prototypes
@ -118,7 +125,11 @@ EXTERN volatile uint32_t *g_current_regs;
*
****************************************************************************/
#define up_cpu_index() (0)
#ifdef CONFIG_SMP
int up_cpu_index(void);
#else
# define up_cpu_index() (0)
#endif
/****************************************************************************
* Inline functions
@ -133,7 +144,20 @@ EXTERN volatile uint32_t *g_current_regs;
*
****************************************************************************/
#define up_interrupt_context() (g_current_regs != NULL)
static inline bool up_interrupt_context(void)
{
#ifdef CONFIG_SMP
irqstate_t flags = up_irq_save();
#endif
bool ret = CURRENT_REGS != NULL;
#ifdef CONFIG_SMP
up_irq_restore(flags);
#endif
return ret;
}
/****************************************************************************
* Public Function Prototypes

View file

@ -71,7 +71,7 @@ static void _up_assert(int errorcode)
/* Are we in an interrupt handler or the idle task? */
if (g_current_regs || running_task()->flink == NULL)
if (CURRENT_REGS || running_task()->flink == NULL)
{
#if CONFIG_BOARD_RESET_ON_ASSERT >= 1
board_reset(CONFIG_BOARD_ASSERT_RESET_VALUE);

View file

@ -218,10 +218,10 @@ ssize_t up_check_stack_remain(void)
return up_check_tcbstack_remain(running_task());
}
#if CONFIG_ARCH_INTERRUPTSTACK > 3
#if CONFIG_ARCH_INTERRUPTSTACK > 7
size_t up_check_intstack(void)
{
return sparc_stack_check((uintptr_t)g_intstackalloc,
return sparc_stack_check((void *)up_intstack_alloc(),
STACK_ALIGN_DOWN(CONFIG_ARCH_INTERRUPTSTACK));
}

View file

@ -75,7 +75,17 @@
* Public Data
****************************************************************************/
volatile uint32_t *g_current_regs;
/* g_current_regs[] holds a reference 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.
*/
/* For the case of architectures with multiple CPUs, then there must be one
* such value for each processor that can receive an interrupt.
*/
volatile uint32_t *g_current_regs[CONFIG_SMP_NCPUS];
/****************************************************************************
* Private Functions
@ -90,15 +100,15 @@ volatile uint32_t *g_current_regs;
*
****************************************************************************/
#if defined(CONFIG_STACK_COLORATION) && CONFIG_ARCH_INTERRUPTSTACK > 3
#if defined(CONFIG_STACK_COLORATION) && CONFIG_ARCH_INTERRUPTSTACK > 7
static inline void up_color_intstack(void)
{
uint8_t *ptr = g_intstackalloc;
uint32_t *ptr = (uint32_t *)up_intstack_alloc();
ssize_t size;
for (size = (CONFIG_ARCH_INTERRUPTSTACK & ~3);
for (size = ((CONFIG_ARCH_INTERRUPTSTACK & ~7) * CONFIG_SMP_NCPUS);
size > 0;
size -= sizeof(uint8_t))
size -= sizeof(uint32_t))
{
*ptr++ = INTSTACK_COLOR;
}
@ -130,6 +140,19 @@ static inline void up_color_intstack(void)
void up_initialize(void)
{
#ifdef CONFIG_SMP
int i;
/* Initialize global variables */
for (i = 0; i < CONFIG_SMP_NCPUS; i++)
{
g_current_regs[i] = NULL;
}
#else
CURRENT_REGS = NULL;
#endif
/* Colorize the interrupt stack */
up_color_intstack();

View file

@ -80,6 +80,8 @@
# define CONFIG_ARCH_INTERRUPTSTACK 0
#endif
#define INTSTACK_SIZE (CONFIG_ARCH_INTERRUPTSTACK & ~STACK_ALIGN_MASK)
/* sparc requires at least a 4-byte stack alignment. For floating point use,
* however, the stack must be aligned to 8-byte addresses.
*/
@ -129,8 +131,9 @@ extern uint32_t g_idle_topstack;
/* Address of the saved user stack pointer */
#if CONFIG_ARCH_INTERRUPTSTACK > 3
extern void g_intstackbase;
#if CONFIG_ARCH_INTERRUPTSTACK > 7
extern uint8_t g_intstackalloc[]; /* Allocated stack base */
extern uint8_t g_intstacktop[]; /* Initial top of interrupt stack */
#endif
/* These symbols are setup by the linker script. */
@ -200,6 +203,14 @@ int up_swint1(int irq, void *context, void *arg);
void up_sigdeliver(void);
/* Interrupt handling *******************************************************/
#if CONFIG_ARCH_INTERRUPTSTACK > 7
uintptr_t up_intstack_alloc(void);
uintptr_t up_intstack_top(void);
#endif
/* Chip-specific functions **************************************************/
/* Chip specific functions defined in arch/sparc/src/<chip> */

View file

@ -52,6 +52,8 @@ ifeq ($(CONFIG_ARCH_CHIP_BM3803),y)
ARCHCPUFLAGS += -mcpu=leon
else ifeq ($(CONFIG_ARCH_CHIP_BM3823),y)
ARCHCPUFLAGS += -mcpu=leon -mflat
else ifeq ($(CONFIG_ARCH_CHIP_S698PM),y)
ARCHCPUFLAGS += -mcpu=leon3
endif
ifeq ($(CONFIG_DEBUG_CUSTOMOPT),y)

View file

@ -41,9 +41,9 @@
* state from the TCB.
*/
#define up_restorestate(regs) (g_current_regs = regs)
#define up_restorestate(regs) (CURRENT_REGS = regs)
#define up_savestate(regs) trap_flush_task(regs, (uint32_t*)g_current_regs)
#define up_savestate(regs) trap_flush_task(regs, (uint32_t*)CURRENT_REGS)
/****************************************************************************
* Public Types

View file

@ -103,10 +103,10 @@ void up_block_task(struct tcb_s *tcb, tstate_t task_state)
/* Are we in an interrupt handler? */
if (g_current_regs)
if (CURRENT_REGS)
{
/* Yes, then we have to do things differently.
* Just copy the g_current_regs into the OLD rtcb.
* Just copy the CURRENT_REGS into the OLD rtcb.
*/
up_savestate(rtcb->xcp.regs);

View file

@ -71,7 +71,7 @@ void up_copystate(uint32_t *dest, uint32_t *src)
void task_flush_trap(uint32_t *trap, uint32_t *task)
{
g_current_regs = task;
CURRENT_REGS = task;
}
void trap_flush_task(uint32_t *task, uint32_t *trap)

View file

@ -63,13 +63,13 @@ uint32_t *up_doirq(int irq, uint32_t *regs)
#else
regs = (uint32_t *)((uint32_t)regs + CPU_MINIMUM_STACK_FRAME_SIZE);
/* Current regs non-zero indicates that we are processing an interrupt;
* g_current_regs is also used to manage interrupt level context switches.
* CURRENT_REGS is also used to manage interrupt level context switches.
*
* Nested interrupts are not supported.
*/
DEBUGASSERT(g_current_regs == NULL);
g_current_regs = regs;
DEBUGASSERT(CURRENT_REGS == NULL);
CURRENT_REGS = regs;
/* Deliver the IRQ */
@ -77,18 +77,18 @@ uint32_t *up_doirq(int irq, uint32_t *regs)
#if defined(CONFIG_ARCH_FPU) || defined(CONFIG_ARCH_ADDRENV)
/* Check for a context switch. If a context switch occurred, then
* g_current_regs will have a different value than it did on entry.
* CURRENT_REGS will have a different value than it did on entry.
* If an interrupt level context switch has occurred, then restore
* the floating point state and the establish the correct address
* environment before returning from the interrupt.
*/
if (regs != g_current_regs)
if (regs != CURRENT_REGS)
{
#ifdef CONFIG_ARCH_FPU
/* Restore floating point registers */
up_restorefpu((uint32_t *)g_current_regs);
up_restorefpu((uint32_t *)CURRENT_REGS);
#endif
#ifdef CONFIG_ARCH_ADDRENV
@ -104,19 +104,26 @@ uint32_t *up_doirq(int irq, uint32_t *regs)
#endif
/* If a context switch occurred while processing the interrupt then
* g_current_regs may have change value. If we return any value different
* 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.
*/
regs = (uint32_t *)((uint32_t)g_current_regs -
regs = (uint32_t *)((uint32_t)CURRENT_REGS -
CPU_MINIMUM_STACK_FRAME_SIZE);
/* Set g_current_regs to NULL to indicate that we are no longer in
* an interrupt handler.
/* Restore the cpu lock */
if (regs != CURRENT_REGS)
{
restore_critical_section();
}
/* Set CURRENT_REGS to NULL to indicate that we are no longer in an
* interrupt handler.
*/
g_current_regs = NULL;
CURRENT_REGS = NULL;
#endif
board_autoled_off(LED_INIRQ);
return regs;

View file

@ -65,25 +65,27 @@ static void up_stackdump(uint32_t sp, uint32_t stack_base)
static inline void up_registerdump(void)
{
uint32_t *regs = (uint32_t *)CURRENT_REGS; /* Don't need volatile here */
/* Are user registers available from interrupt processing? */
if (g_current_regs)
if (regs)
{
_alert("R%d: %08x %08x %08x %08x %08x %08x %08x %08x\n",
0,
g_current_regs[REG_R16], g_current_regs[REG_R17],
g_current_regs[REG_R18], g_current_regs[REG_R19],
g_current_regs[REG_R20], g_current_regs[REG_R21],
g_current_regs[REG_R22], g_current_regs[REG_R23]);
regs[REG_R16], regs[REG_R17],
regs[REG_R18], regs[REG_R19],
regs[REG_R20], regs[REG_R21],
regs[REG_R22], regs[REG_R23]);
_alert("R%d: %08x %08x %08x %08x %08x %08x %08x %08x\n",
8,
g_current_regs[REG_R24], g_current_regs[REG_R25],
g_current_regs[REG_R26], g_current_regs[REG_R27],
g_current_regs[REG_R28], g_current_regs[REG_R29],
g_current_regs[REG_R30], g_current_regs[REG_R31]);
regs[REG_R24], regs[REG_R25],
regs[REG_R26], regs[REG_R27],
regs[REG_R28], regs[REG_R29],
regs[REG_R30], regs[REG_R31]);
_alert("SR: %08x\n", g_current_regs[REG_R14]);
_alert("SR: %08x\n", regs[REG_R14]);
}
}
@ -102,6 +104,12 @@ void up_dumpstate(void)
uint32_t istacksize;
#endif
#ifdef CONFIG_SMP
/* Show the CPU number */
_alert("CPU%d:\n", up_cpu_index());
#endif
/* Dump the registers (if available) */
up_registerdump();
@ -122,7 +130,7 @@ void up_dumpstate(void)
/* Get the limits on the interrupt stack memory */
#if CONFIG_ARCH_INTERRUPTSTACK > 3
istackbase = (uint32_t)g_intstackbase;
istackbase = (uint32_t)up_intstack_alloc();
istacksize = (CONFIG_ARCH_INTERRUPTSTACK & ~3) - 4;
/* Show interrupt stack info */
@ -145,7 +153,7 @@ void up_dumpstate(void)
up_stackdump(sp, istackbase);
}
else if (g_current_regs)
else if (CURRENT_REGS)
{
_alert("ERROR: Stack pointer is not within the interrupt stack\n");
up_stackdump(istackbase - istacksize, istackbase);
@ -156,9 +164,9 @@ void up_dumpstate(void)
* pointer (and the above range check should have failed).
*/
if (g_current_regs)
if (CURRENT_REGS)
{
sp = g_current_regs[REG_I6];
sp = CURRENT_REGS[REG_I6];
_alert("sp: %08x\n", sp);
}

View file

@ -71,7 +71,7 @@ void up_initial_state(struct tcb_s *tcb)
if (tcb->pid == IDLE_PROCESS_ID)
{
tcb->stack_alloc_ptr = (void *)(g_idle_topstack -
CONFIG_IDLETHREAD_STACKSIZE);
(CONFIG_SMP_NCPUS * CONFIG_IDLETHREAD_STACKSIZE));
tcb->stack_base_ptr = tcb->stack_alloc_ptr;
tcb->adj_stack_size = CONFIG_IDLETHREAD_STACKSIZE;

View file

@ -68,10 +68,10 @@ void up_release_pending(void)
nxsched_suspend_scheduler(rtcb);
if (g_current_regs)
if (CURRENT_REGS)
{
/* Yes, then we have to do things differently.
* Just copy the g_current_regs into the OLD rtcb.
* Just copy the CURRENT_REGS into the OLD rtcb.
*/
up_savestate(rtcb->xcp.regs);

View file

@ -124,10 +124,10 @@ void up_reprioritize_rtr(struct tcb_s *tcb, uint8_t priority)
/* Are we in an interrupt handler? */
if (g_current_regs)
if (CURRENT_REGS)
{
/* Yes, then we have to do things differently.
* Just copy the g_current_regs into the OLD rtcb.
* Just copy the CURRENT_REGS into the OLD rtcb.
*/
up_savestate(rtcb->xcp.regs);

View file

@ -71,6 +71,7 @@
*
****************************************************************************/
#ifndef CONFIG_SMP
void up_schedule_sigaction(struct tcb_s *tcb, sig_deliver_t sigdeliver)
{
irqstate_t flags;
@ -89,8 +90,7 @@ void up_schedule_sigaction(struct tcb_s *tcb, sig_deliver_t sigdeliver)
* being delivered to the currently executing task.
*/
sinfo("rtcb=%p g_current_regs=%p\n",
this_task(), g_current_regs);
sinfo("rtcb=%p CURRENT_REGS=%p\n", this_task(), CURRENT_REGS);
if (tcb == this_task())
{
@ -98,7 +98,7 @@ void up_schedule_sigaction(struct tcb_s *tcb, sig_deliver_t sigdeliver)
* a task is signalling itself for some reason.
*/
if (!g_current_regs)
if (!CURRENT_REGS)
{
/* In this case just deliver the signal now. */
@ -114,7 +114,7 @@ void up_schedule_sigaction(struct tcb_s *tcb, sig_deliver_t sigdeliver)
* logic would fail in the strange case where we are in an
* interrupt handler, the thread is signalling itself, but
* a context switch to another task has occurred so that
* g_current_regs does not refer to the thread of this_task()!
* CURRENT_REGS does not refer to the thread of this_task()!
*/
else
@ -125,17 +125,17 @@ void up_schedule_sigaction(struct tcb_s *tcb, sig_deliver_t sigdeliver)
*/
tcb->xcp.sigdeliver = sigdeliver;
tcb->xcp.saved_pc = g_current_regs[REG_PC];
tcb->xcp.saved_npc = g_current_regs[REG_NPC];
tcb->xcp.saved_status = g_current_regs[REG_PSR];
tcb->xcp.saved_pc = CURRENT_REGS[REG_PC];
tcb->xcp.saved_npc = CURRENT_REGS[REG_NPC];
tcb->xcp.saved_status = CURRENT_REGS[REG_PSR];
/* Then set up to vector to the trampoline with interrupts
* disabled
*/
g_current_regs[REG_PC] = (uint32_t)up_sigdeliver;
g_current_regs[REG_NPC] = (uint32_t)up_sigdeliver + 4;
g_current_regs[REG_PSR] |= SPARC_PSR_ET_MASK;
CURRENT_REGS[REG_PC] = (uint32_t)up_sigdeliver;
CURRENT_REGS[REG_NPC] = (uint32_t)up_sigdeliver + 4;
CURRENT_REGS[REG_PSR] |= SPARC_PSR_ET_MASK;
/* And make sure that the saved context in the TCB
* is the same as the interrupt return context.
@ -175,3 +175,184 @@ void up_schedule_sigaction(struct tcb_s *tcb, sig_deliver_t sigdeliver)
leave_critical_section(flags);
}
#endif /* !CONFIG_SMP */
#ifdef CONFIG_SMP
void up_schedule_sigaction(struct tcb_s *tcb, sig_deliver_t sigdeliver)
{
irqstate_t flags;
int cpu;
int me;
sinfo("tcb=0x%p sigdeliver=0x%p\n", tcb, sigdeliver);
/* Make sure that interrupts are disabled */
flags = enter_critical_section();
/* Refuse to handle nested signal actions */
if (!tcb->xcp.sigdeliver)
{
/* First, handle some special cases when the signal is being delivered
* to task that is currently executing on any CPU.
*/
sinfo("rtcb=0x%p CURRENT_REGS=0x%p\n", this_task(), CURRENT_REGS);
if (tcb->task_state == TSTATE_TASK_RUNNING)
{
me = this_cpu();
cpu = tcb->cpu;
/* CASE 1: We are not in an interrupt handler and a task is
* signaling itself for some reason.
*/
if (cpu == me && !CURRENT_REGS)
{
/* In this case just deliver the signal now.
* REVISIT: Signal handler will run in a critical section!
*/
sigdeliver(tcb);
}
/* CASE 2: The task that needs to receive the signal is running.
* This could happen if the task is running on another CPU OR if
* we are in an interrupt handler and the task is running on this
* CPU. In the former case, we will have to PAUSE the other CPU
* first. But in either case, we will have to modify the return
* state as well as the state in the TCB.
*/
else
{
/* If we signaling a task running on the other CPU, we have
* to PAUSE the other CPU.
*/
if (cpu != me)
{
/* Pause the CPU */
up_cpu_pause(cpu);
/* Wait while the pause request is pending */
while (up_cpu_pausereq(cpu))
{
}
/* Now tcb on the other CPU can be accessed safely */
/* Copy tcb->xcp.regs to tcp.xcp.saved. These will be
* restored by the signal trampoline after the signal has
* been delivered.
*/
tcb->xcp.sigdeliver = (FAR void *)sigdeliver;
tcb->xcp.saved_pc = tcb->xcp.regs[REG_PC];
tcb->xcp.saved_npc = tcb->xcp.regs[REG_NPC];
tcb->xcp.saved_status = tcb->xcp.regs[REG_PSR];
/* Then set up vector to the trampoline with interrupts
* disabled. We must already be in privileged thread mode
* to be here.
*/
tcb->xcp.regs[REG_PC] = (uint32_t)up_sigdeliver;
tcb->xcp.regs[REG_NPC] = (uint32_t)up_sigdeliver + 4;
tcb->xcp.regs[REG_PSR] |= SPARC_PSR_ET_MASK;
}
else
{
/* tcb is running on the same CPU */
/* Save registers that must be protected while the signal
* handler runs. These will be restored by the signal
* trampoline after the signal(s) have been delivered.
*/
tcb->xcp.sigdeliver = (FAR void *)sigdeliver;
tcb->xcp.saved_pc = CURRENT_REGS[REG_PC];
tcb->xcp.saved_npc = CURRENT_REGS[REG_NPC];
tcb->xcp.saved_status = CURRENT_REGS[REG_PSR];
/* Then set up vector to the trampoline with interrupts
* disabled. The kernel-space trampoline must run in
* privileged thread mode.
*/
CURRENT_REGS[REG_PC] = (uint32_t)up_sigdeliver;
CURRENT_REGS[REG_NPC] = (uint32_t)up_sigdeliver + 4;
CURRENT_REGS[REG_PSR] |= SPARC_PSR_ET_MASK;
/* And make sure that the saved context in the TCB is the
* same as the interrupt return context.
*/
up_savestate(tcb->xcp.regs);
}
/* Increment the IRQ lock count so that when the task is
* restarted, it will hold the IRQ spinlock.
*/
DEBUGASSERT(tcb->irqcount < INT16_MAX);
tcb->irqcount++;
/* NOTE: If the task runs on another CPU(cpu), adjusting
* global IRQ controls will be done in the pause handler
* on the CPU(cpu) by taking a critical section.
* If the task is scheduled on this CPU(me), do nothing
* because this CPU already took a critical section
*/
/* RESUME the other CPU if it was PAUSED */
if (cpu != me)
{
up_cpu_resume(cpu);
}
}
}
/* Otherwise, we are (1) signaling a task is not running from an
* interrupt handler or (2) we are not in an interrupt handler and the
* running task is signaling some other non-running task.
*/
else
{
/* Save registers that must be protected while the signal
* handler runs. These will be restored by the signal
* trampoline after the signal(s) have been delivered.
*/
tcb->xcp.sigdeliver = (FAR void *)sigdeliver;
tcb->xcp.saved_pc = CURRENT_REGS[REG_PC];
tcb->xcp.saved_npc = CURRENT_REGS[REG_NPC];
tcb->xcp.saved_status = CURRENT_REGS[REG_PSR];
/* Increment the IRQ lock count so that when the task is restarted,
* it will hold the IRQ spinlock.
*/
DEBUGASSERT(tcb->irqcount < INT16_MAX);
tcb->irqcount++;
/* Then set up to vector to the trampoline with interrupts
* disabled. We must already be in privileged thread mode to be
* here.
*/
tcb->xcp.regs[REG_PC] = (uint32_t)up_sigdeliver;
tcb->xcp.regs[REG_NPC] = (uint32_t)up_sigdeliver + 4;
tcb->xcp.regs[REG_PSR] |= SPARC_PSR_ET_MASK;
}
}
leave_critical_section(flags);
}
#endif /* CONFIG_SMP */

View file

@ -63,6 +63,17 @@ void up_sigdeliver(void)
* EINTR).
*/
int saved_errno = get_errno();
#ifdef CONFIG_SMP
/* In the SMP case, we must terminate the critical section while the signal
* handler executes, but we also need to restore the irqcount when the
* we resume the main thread of the task.
*/
int16_t saved_irqcount;
#endif
board_autoled_on(LED_SIGNAL);
sinfo("rtcb=%p sigdeliver=%p sigpendactionq.head=%p\n",
@ -73,6 +84,26 @@ void up_sigdeliver(void)
up_copystate(regs, rtcb->xcp.regs);
#ifdef CONFIG_SMP
/* In the SMP case, up_schedule_sigaction(0) will have incremented
* 'irqcount' in order to force us into a critical section. Save the
* pre-incremented irqcount.
*/
saved_irqcount = rtcb->irqcount - 1;
DEBUGASSERT(saved_irqcount >= 0);
/* Now we need call leave_critical_section() repeatedly to get the irqcount
* to zero, freeing all global spinlocks that enforce the critical section.
*/
do
{
leave_critical_section((regs[REG_PSR]));
}
while (rtcb->irqcount > 0);
#endif /* CONFIG_SMP */
#ifndef CONFIG_SUPPRESS_INTERRUPTS
/* Then make sure that interrupts are enabled. Signal handlers must always
* run with interrupts enabled.
@ -91,7 +122,27 @@ void up_sigdeliver(void)
*/
sinfo("Resuming\n");
/* Call enter_critical_section() to disable local interrupts before
* restoring local context.
*
* Here, we should not use up_irq_save() in SMP mode.
* For example, if we call up_irq_save() here and another CPU might
* have called up_cpu_pause() to this cpu, hence g_cpu_irqlock has
* been locked by the cpu, in this case, we would see a deadlock in
* later call of enter_critical_section() to restore irqcount.
* To avoid this situation, we need to call enter_critical_section().
*/
#ifdef CONFIG_SMP
enter_critical_section();
#else
up_irq_save();
#endif
/* Restore the saved errno value */
set_errno(saved_errno);
/* Modify the saved return state with the actual saved values in the
* TCB. This depends on the fact that nested signal handling is
@ -108,6 +159,22 @@ void up_sigdeliver(void)
regs[REG_PSR] = rtcb->xcp.saved_status;
rtcb->xcp.sigdeliver = NULL; /* Allows next handler to be scheduled */
#ifdef CONFIG_SMP
/* Restore the saved 'irqcount' and recover the critical section
* spinlocks.
*
* REVISIT: irqcount should be one from the above call to
* enter_critical_section(). Could the saved_irqcount be zero? That
* would be a problem.
*/
DEBUGASSERT(rtcb->irqcount == 1);
while (rtcb->irqcount < saved_irqcount)
{
enter_critical_section();
}
#endif
/* Then restore the correct state for this thread of execution. This is an
* unusual case that must be handled by up_fullcontextresore. This case is
* unusal in two ways:

View file

@ -85,7 +85,7 @@ int up_swint1(int irq, void *context, void *arg)
{
uint32_t *regs = (uint32_t *)context;
DEBUGASSERT(regs && regs == g_current_regs);
DEBUGASSERT(regs && regs == CURRENT_REGS);
/* Software interrupt 0 is invoked with REG_A0 (REG_R4) = system call
* command and REG_A1-3 and REG_T0-2 (REG_R5-10) = variable number of
@ -110,7 +110,7 @@ int up_swint1(int irq, void *context, void *arg)
* A0 = SYS_restore_context
* A1 = restoreregs
*
* In this case, we simply need to set g_current_regs to restore
* In this case, we simply need to set CURRENT_REGS to restore
* register area referenced in the saved R1. context == g_current
* regs is the normal exception return. By setting g_current
* regs = context[R1], we force the return to the saved context
@ -120,7 +120,7 @@ int up_swint1(int irq, void *context, void *arg)
case SYS_restore_context:
{
DEBUGASSERT(regs[REG_I1] != 0);
g_current_regs = (uint32_t *)regs[REG_I1];
CURRENT_REGS = (uint32_t *)regs[REG_I1];
}
break;
@ -136,7 +136,7 @@ int up_swint1(int irq, void *context, void *arg)
*
* In this case, we save the context registers to the save register
* area referenced by the saved contents of R5 and then set
* g_current_regs to the save register area referenced by the saved
* CURRENT_REGS to the save register area referenced by the saved
* contents of R6.
*/
@ -147,7 +147,7 @@ int up_swint1(int irq, void *context, void *arg)
/* task_flush_trap(regs,(uint32_t *)regs[REG_I2]); */
g_current_regs = (uint32_t *)regs[REG_I2];
CURRENT_REGS = (uint32_t *)regs[REG_I2];
}
break;
@ -177,7 +177,7 @@ int up_swint1(int irq, void *context, void *arg)
* the original mode.
*/
g_current_regs[REG_I7] = rtcb->xcp.syscall[index].sysreturn;
CURRENT_REGS[REG_I7] = rtcb->xcp.syscall[index].sysreturn;
#error "Missing logic -- need to restore the original mode"
rtcb->xcp.nsyscalls = index;
}
@ -192,7 +192,7 @@ int up_swint1(int irq, void *context, void *arg)
/* Verify that the SYS call number is within range */
DEBUGASSERT(g_current_regs[REG_I1] < SYS_maxsyscall);
DEBUGASSERT(CURRENT_REGS[REG_I1] < SYS_maxsyscall);
/* Make sure that we got here that there is a no saved syscall
* return address. We cannot yet handle nested system calls.
@ -211,7 +211,7 @@ int up_swint1(int irq, void *context, void *arg)
/* Offset R0 to account for the reserved values */
/* g_current_regs[REG_R0] -= CONFIG_SYS_RESERVED; *//*zouboan*/
/* CURRENT_REGS[REG_R0] -= CONFIG_SYS_RESERVED; *//*zouboan*/
#else
svcerr("ERROR: Bad SYS call: %d\n", regs[REG_I1]);
#endif
@ -224,10 +224,10 @@ int up_swint1(int irq, void *context, void *arg)
*/
#ifdef CONFIG_DEBUG_SYSCALL_INFO
if (regs != g_current_regs)
if (regs != CURRENT_REGS)
{
svcinfo("SWInt Return: Context switch!\n");
up_registerdump((const uint32_t *)g_current_regs);
up_registerdump((const uint32_t *)CURRENT_REGS);
}
else
{

View file

@ -86,10 +86,10 @@ void up_unblock_task(struct tcb_s *tcb)
/* Are we in an interrupt handler? */
if (g_current_regs)
if (CURRENT_REGS)
{
/* Yes, then we have to do things differently.
* Just copy the g_current_regs into the OLD rtcb.
* Just copy the CURRENT_REGS into the OLD rtcb.
*/
up_savestate(rtcb->xcp.regs);