diff --git a/arch/x86_64/src/common/x86_64_exit.c b/arch/x86_64/src/common/x86_64_exit.c index 70b210a83c7..6070cc82a60 100644 --- a/arch/x86_64/src/common/x86_64_exit.c +++ b/arch/x86_64/src/common/x86_64_exit.c @@ -87,23 +87,19 @@ void up_exit(int status) x86_64_restore_auxstate(tcb); - /* Restore the cpu lock */ - - restore_critical_section(tcb, this_cpu()); - #ifdef CONFIG_ARCH_KERNEL_STACK /* Update kernel stack top pointer */ x86_64_set_ktopstk(tcb->xcp.ktopstk); #endif - /* Then switch contexts */ - - x86_64_fullcontextrestore(tcb->xcp.regs); - - /* x86_64_fullcontextrestore() should not return but could if the software - * interrupts are disabled. + /* Restore the cpu lock. This must come last and the final jump must + * not touch the stack (see up_switch_context()). */ - PANIC(); + restore_critical_section(tcb, this_cpu()); + + __asm__ volatile ("jmp x86_64_fullcontextrestore" + :: "D" (tcb->xcp.regs) : "memory"); + __builtin_unreachable(); } diff --git a/arch/x86_64/src/common/x86_64_switchcontext.c b/arch/x86_64/src/common/x86_64_switchcontext.c index 9ddf056f37a..721d005f40d 100644 --- a/arch/x86_64/src/common/x86_64_switchcontext.c +++ b/arch/x86_64/src/common/x86_64_switchcontext.c @@ -86,6 +86,7 @@ void up_switch_context(struct tcb_s *tcb, struct tcb_s *rtcb) else if (!up_saveusercontext(rtcb->xcp.regs)) { struct tcb_s **running_task; + cpu = this_cpu(); x86_64_restore_auxstate(tcb); @@ -101,10 +102,6 @@ void up_switch_context(struct tcb_s *tcb, struct tcb_s *rtcb) tcb = this_task(); #endif - /* Restore the cpu lock */ - - restore_critical_section(tcb, cpu); - /* Update scheduler parameters */ running_task = &g_running_tasks[cpu]; @@ -117,8 +114,16 @@ void up_switch_context(struct tcb_s *tcb, struct tcb_s *rtcb) *running_task = tcb; - /* Then switch contexts */ + /* Restore the cpu lock. This makes the outgoing task wakeable by + * other CPUs while this CPU still runs on the outgoing task's + * stack, so it must come last and the final jump must not touch + * the stack (a call would push the return address onto it). + */ - x86_64_fullcontextrestore(tcb->xcp.regs); + restore_critical_section(tcb, cpu); + + __asm__ volatile ("jmp x86_64_fullcontextrestore" + :: "D" (tcb->xcp.regs) : "memory"); + __builtin_unreachable(); } }