mirror of
https://github.com/apache/nuttx.git
synced 2025-01-12 22:08:35 +08:00
arch/x86_64:g_current_regs is only used to determine if we are in irq,
with other functionalities removed. Signed-off-by: liwenxiang1 <liwenxiang1@xiaomi.com>
This commit is contained in:
parent
ce920f9e93
commit
4612185cd6
5 changed files with 44 additions and 204 deletions
|
@ -122,13 +122,6 @@
|
|||
#define getreg32(p) inl(p)
|
||||
#define putreg32(v,p) outl(v,p)
|
||||
|
||||
/* Macros to handle saving and restore interrupt state. In the current
|
||||
* model, the state is copied from the stack to the TCB, but only a
|
||||
* referenced is passed to get the state from the TCB.
|
||||
*/
|
||||
|
||||
#define x86_64_restorestate(regs) (up_set_current_regs(regs))
|
||||
|
||||
/* ISR/IRQ stack size */
|
||||
|
||||
#if CONFIG_ARCH_INTERRUPTSTACK == 0
|
||||
|
|
|
@ -74,10 +74,6 @@ void up_switch_context(struct tcb_s *tcb, struct tcb_s *rtcb)
|
|||
/* Restore addition x86_64 state */
|
||||
|
||||
x86_64_restore_auxstate(tcb);
|
||||
|
||||
/* Update current regs to signal that we need context switch */
|
||||
|
||||
x86_64_restorestate(tcb->xcp.regs);
|
||||
}
|
||||
|
||||
/* We are not in an interrupt handler. Copy the user C context
|
||||
|
|
|
@ -81,6 +81,7 @@ static uint64_t *common_handler(int irq, uint64_t *regs)
|
|||
/* Deliver the IRQ */
|
||||
|
||||
irq_dispatch(irq, regs);
|
||||
tcb = this_task();
|
||||
|
||||
/* Check for a context switch. If a context switch occurred, then
|
||||
* g_current_regs will have a different value than it did on entry. If an
|
||||
|
@ -88,7 +89,7 @@ static uint64_t *common_handler(int irq, uint64_t *regs)
|
|||
* correct address environment before returning from the interrupt.
|
||||
*/
|
||||
|
||||
if (regs != up_current_regs())
|
||||
if (*running_task != tcb)
|
||||
{
|
||||
tcb = this_task();
|
||||
|
||||
|
@ -119,20 +120,12 @@ static uint64_t *common_handler(int irq, uint64_t *regs)
|
|||
restore_critical_section(tcb, this_cpu());
|
||||
}
|
||||
|
||||
/* If a context switch occurred while processing the interrupt then
|
||||
* g_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 = (uint64_t *)up_current_regs();
|
||||
|
||||
/* Set g_current_regs to NULL to indicate that we are no longer in an
|
||||
* interrupt handler.
|
||||
*/
|
||||
|
||||
up_set_current_regs(NULL);
|
||||
return regs;
|
||||
return tcb->xcp.regs;
|
||||
}
|
||||
#endif
|
||||
|
||||
|
@ -151,6 +144,7 @@ static uint64_t *common_handler(int irq, uint64_t *regs)
|
|||
uint64_t *isr_handler(uint64_t *regs, uint64_t irq)
|
||||
{
|
||||
struct tcb_s **running_task = &g_running_tasks[this_cpu()];
|
||||
struct tcb_s *tcb;
|
||||
|
||||
if (*running_task != NULL)
|
||||
{
|
||||
|
@ -196,16 +190,49 @@ uint64_t *isr_handler(uint64_t *regs, uint64_t irq)
|
|||
break;
|
||||
}
|
||||
|
||||
/* Maybe we need a context switch */
|
||||
tcb = this_task();
|
||||
|
||||
regs = (uint64_t *)up_current_regs();
|
||||
/* Check for a context switch. If a context switch occurred, then
|
||||
* g_current_regs will have a different value than it did on entry. If an
|
||||
* interrupt level context switch has occurred, then the establish the
|
||||
* correct address environment before returning from the interrupt.
|
||||
*/
|
||||
|
||||
if (*running_task != tcb)
|
||||
{
|
||||
#ifdef CONFIG_ARCH_ADDRENV
|
||||
/* Make sure that the address environment for the previously
|
||||
* running task is closed down gracefully (data caches dump,
|
||||
* MMU flushed) and set up the address environment for the new
|
||||
* thread at the head of the ready-to-run list.
|
||||
*/
|
||||
|
||||
addrenv_switch(NULL);
|
||||
#endif
|
||||
|
||||
/* Update scheduler parameters */
|
||||
|
||||
nxsched_suspend_scheduler(*running_task);
|
||||
nxsched_resume_scheduler(tcb);
|
||||
|
||||
/* Record the new "running" task when context switch occurred.
|
||||
* g_running_tasks[] is only used by assertion logic for reporting
|
||||
* crashes.
|
||||
*/
|
||||
|
||||
*running_task = tcb;
|
||||
|
||||
/* Restore the cpu lock */
|
||||
|
||||
restore_critical_section(tcb, this_cpu());
|
||||
}
|
||||
|
||||
/* Set g_current_regs to NULL to indicate that we are no longer in an
|
||||
* interrupt handler.
|
||||
*/
|
||||
|
||||
up_set_current_regs(NULL);
|
||||
return regs;
|
||||
return tcb->xcp.regs;
|
||||
#endif
|
||||
}
|
||||
|
||||
|
|
|
@ -72,185 +72,19 @@
|
|||
*
|
||||
****************************************************************************/
|
||||
|
||||
#ifndef CONFIG_SMP
|
||||
void up_schedule_sigaction(struct tcb_s *tcb)
|
||||
{
|
||||
sinfo("tcb=%p, rtcb=%p current_regs=%p\n", tcb,
|
||||
this_task(), up_current_regs());
|
||||
|
||||
/* First, handle some special cases when the signal is being delivered
|
||||
* to the currently executing task.
|
||||
*/
|
||||
|
||||
if (tcb == this_task())
|
||||
{
|
||||
/* CASE 1: We are not in an interrupt handler and a task is
|
||||
* signalling itself for some reason.
|
||||
*/
|
||||
|
||||
if (!up_current_regs())
|
||||
{
|
||||
/* In this case just deliver the signal with a function call
|
||||
* now.
|
||||
*/
|
||||
|
||||
(tcb->sigdeliver)(tcb);
|
||||
tcb->sigdeliver = NULL;
|
||||
}
|
||||
|
||||
/* CASE 2: We are in an interrupt handler AND the interrupted task
|
||||
* is the same as the one that must receive the signal, then we
|
||||
* will have to modify the return state as well as the state in the
|
||||
* TCB.
|
||||
*
|
||||
* Hmmm... there looks like a latent bug here: The following 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 current_regs does not
|
||||
* refer to the thread of this_task()!
|
||||
*/
|
||||
|
||||
else
|
||||
{
|
||||
/* Save the return lr and cpsr and one scratch register. These
|
||||
* will be restored by the signal trampoline after the signals
|
||||
* have been delivered.
|
||||
*/
|
||||
|
||||
tcb->xcp.saved_rip = up_current_regs()[REG_RIP];
|
||||
tcb->xcp.saved_rsp = up_current_regs()[REG_RSP];
|
||||
tcb->xcp.saved_rflags = up_current_regs()[REG_RFLAGS];
|
||||
|
||||
/* Then set up to vector to the trampoline with interrupts
|
||||
* disabled
|
||||
*/
|
||||
|
||||
up_current_regs()[REG_RIP] = (uint64_t)x86_64_sigdeliver;
|
||||
up_current_regs()[REG_RSP] = up_current_regs()[REG_RSP] - 8;
|
||||
up_current_regs()[REG_RFLAGS] = 0;
|
||||
|
||||
#ifdef CONFIG_ARCH_KERNEL_STACK
|
||||
/* Update segments to kernel segments */
|
||||
|
||||
up_current_regs()[REG_SS] = tcb->xcp.regs[REG_SS];
|
||||
up_current_regs()[REG_CS] = tcb->xcp.regs[REG_CS];
|
||||
up_current_regs()[REG_DS] = tcb->xcp.regs[REG_DS];
|
||||
|
||||
/* Update RSP to kernel stack */
|
||||
|
||||
up_current_regs()[REG_RSP] = (uint64_t)x86_64_get_ktopstk();
|
||||
#endif
|
||||
}
|
||||
}
|
||||
|
||||
/* 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 signalling
|
||||
* some non-running task.
|
||||
*/
|
||||
|
||||
else
|
||||
{
|
||||
/* Save the return lr and cpsr and one scratch register
|
||||
* These will be restored by the signal trampoline after
|
||||
* the signals have been delivered.
|
||||
*/
|
||||
|
||||
tcb->xcp.saved_rip = tcb->xcp.regs[REG_RIP];
|
||||
tcb->xcp.saved_rsp = tcb->xcp.regs[REG_RSP];
|
||||
tcb->xcp.saved_rflags = tcb->xcp.regs[REG_RFLAGS];
|
||||
|
||||
/* Then set up to vector to the trampoline with interrupts
|
||||
* disabled
|
||||
*/
|
||||
|
||||
tcb->xcp.regs[REG_RIP] = (uint64_t)x86_64_sigdeliver;
|
||||
tcb->xcp.regs[REG_RSP] = tcb->xcp.regs[REG_RSP] - 8;
|
||||
tcb->xcp.regs[REG_RFLAGS] = 0;
|
||||
}
|
||||
}
|
||||
#else /* !CONFIG_SMP */
|
||||
void up_schedule_sigaction(struct tcb_s *tcb)
|
||||
{
|
||||
int cpu;
|
||||
int me;
|
||||
|
||||
sinfo("tcb=%p, rtcb=%p current_regs=%p\n", tcb,
|
||||
this_task(), up_current_regs());
|
||||
this_task(), this_task()->xcp.regs);
|
||||
|
||||
/* First, handle some special cases when the signal is being delivered
|
||||
* to task that is currently executing on any CPU.
|
||||
*/
|
||||
|
||||
if (tcb->task_state == TSTATE_TASK_RUNNING)
|
||||
if (tcb == this_task() && !up_interrupt_context())
|
||||
{
|
||||
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 && !up_current_regs())
|
||||
{
|
||||
/* In this case just deliver the signal now.
|
||||
* REVISIT: Signal handler will run in a critical section!
|
||||
*/
|
||||
|
||||
(tcb->sigdeliver)(tcb);
|
||||
tcb->sigdeliver = NULL;
|
||||
}
|
||||
|
||||
/* 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
|
||||
{
|
||||
/* tcb is running on the same CPU */
|
||||
|
||||
/* Save the return lr and cpsr and one scratch register.
|
||||
* These will be restored by the signal trampoline after
|
||||
* the signals have been delivered.
|
||||
*/
|
||||
|
||||
tcb->xcp.saved_rip = up_current_regs()[REG_RIP];
|
||||
tcb->xcp.saved_rsp = up_current_regs()[REG_RSP];
|
||||
tcb->xcp.saved_rflags = up_current_regs()[REG_RFLAGS];
|
||||
|
||||
/* Then set up to vector to the trampoline with interrupts
|
||||
* disabled
|
||||
*/
|
||||
|
||||
up_current_regs()[REG_RIP] = (uint64_t)x86_64_sigdeliver;
|
||||
up_current_regs()[REG_RSP] = up_current_regs()[REG_RSP] - 8;
|
||||
up_current_regs()[REG_RFLAGS] = 0;
|
||||
|
||||
#ifdef CONFIG_ARCH_KERNEL_STACK
|
||||
/* Update segments to kernel segments */
|
||||
|
||||
up_current_regs()[REG_SS] = tcb->xcp.regs[REG_SS];
|
||||
up_current_regs()[REG_CS] = tcb->xcp.regs[REG_CS];
|
||||
up_current_regs()[REG_DS] = tcb->xcp.regs[REG_DS];
|
||||
|
||||
/* Update RSP to kernel stack */
|
||||
|
||||
up_current_regs()[REG_RSP] =
|
||||
(uint64_t)x86_64_get_ktopstk();
|
||||
#endif
|
||||
/* Mark that full context switch is necessary when we
|
||||
* return from interrupt handler.
|
||||
* In that case RIP, RSP and RFLAGS are changed, but
|
||||
* register area pointer remains the same, so we need an
|
||||
* additional variable to signal the need for full context switch
|
||||
*/
|
||||
|
||||
tcb->xcp.regs[REG_AUX] = REG_AUX_FULLCONTEXT;
|
||||
}
|
||||
(tcb->sigdeliver)(tcb);
|
||||
tcb->sigdeliver = NULL;
|
||||
}
|
||||
|
||||
/* Otherwise, we are (1) signaling a task is not running from an
|
||||
|
@ -278,4 +112,3 @@ void up_schedule_sigaction(struct tcb_s *tcb)
|
|||
tcb->xcp.regs[REG_RFLAGS] = 0;
|
||||
}
|
||||
}
|
||||
#endif /* CONFIG_SMP */
|
||||
|
|
|
@ -60,13 +60,7 @@
|
|||
|
||||
int x86_64_smp_call_handler(int irq, void *c, void *arg)
|
||||
{
|
||||
struct tcb_s *tcb;
|
||||
int cpu = this_cpu();
|
||||
|
||||
tcb = current_task(cpu);
|
||||
nxsched_smp_call_handler(irq, c, arg);
|
||||
tcb = current_task(cpu);
|
||||
x86_64_restorestate(tcb->xcp.regs);
|
||||
|
||||
return OK;
|
||||
}
|
||||
|
@ -93,12 +87,9 @@ int x86_64_smp_call_handler(int irq, void *c, void *arg)
|
|||
|
||||
int x86_64_smp_sched_handler(int irq, void *c, void *arg)
|
||||
{
|
||||
struct tcb_s *tcb;
|
||||
int cpu = this_cpu();
|
||||
|
||||
nxsched_process_delivered(cpu);
|
||||
tcb = current_task(cpu);
|
||||
x86_64_restorestate(tcb->xcp.regs);
|
||||
|
||||
return OK;
|
||||
}
|
||||
|
|
Loading…
Reference in a new issue