diff --git a/arch/x86_64/src/common/x86_64_internal.h b/arch/x86_64/src/common/x86_64_internal.h index 16f569a6d7368..04830cd09a266 100644 --- a/arch/x86_64/src/common/x86_64_internal.h +++ b/arch/x86_64/src/common/x86_64_internal.h @@ -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 diff --git a/arch/x86_64/src/common/x86_64_switchcontext.c b/arch/x86_64/src/common/x86_64_switchcontext.c index b3f314e4f76da..6b13ba6e75dc6 100644 --- a/arch/x86_64/src/common/x86_64_switchcontext.c +++ b/arch/x86_64/src/common/x86_64_switchcontext.c @@ -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 diff --git a/arch/x86_64/src/intel64/intel64_handlers.c b/arch/x86_64/src/intel64/intel64_handlers.c index 86735bbeaf4d3..d737c84b2fd61 100644 --- a/arch/x86_64/src/intel64/intel64_handlers.c +++ b/arch/x86_64/src/intel64/intel64_handlers.c @@ -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(); + + /* 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 - regs = (uint64_t *)up_current_regs(); + /* 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 } diff --git a/arch/x86_64/src/intel64/intel64_schedulesigaction.c b/arch/x86_64/src/intel64/intel64_schedulesigaction.c index 23bac186f88e1..797c9f3a69db0 100644 --- a/arch/x86_64/src/intel64/intel64_schedulesigaction.c +++ b/arch/x86_64/src/intel64/intel64_schedulesigaction.c @@ -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 */ diff --git a/arch/x86_64/src/intel64/intel64_smpcall.c b/arch/x86_64/src/intel64/intel64_smpcall.c index 8767c5b8e568d..b45dad2856fef 100644 --- a/arch/x86_64/src/intel64/intel64_smpcall.c +++ b/arch/x86_64/src/intel64/intel64_smpcall.c @@ -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; }