diff --git a/arch/x86_64/src/common/x86_64_syscall.c b/arch/x86_64/src/common/x86_64_syscall.c index 196453f5d6ae8..a3a7f26f448ac 100644 --- a/arch/x86_64/src/common/x86_64_syscall.c +++ b/arch/x86_64/src/common/x86_64_syscall.c @@ -39,6 +39,14 @@ #include "x86_64_internal.h" +/**************************************************************************** + * Pre-processor Definitions + ****************************************************************************/ + +/* Red zone the System V AMD64 ABI reserves below the user stack pointer */ + +#define X86_64_ABI_RED_ZONE 128 + /**************************************************************************** * Private Types ****************************************************************************/ @@ -247,16 +255,24 @@ uint64_t *x86_64_syscall(uint64_t *regs) { uint64_t usp; - /* Copy "info" into user stack */ + /* Save the kernel stack pointer to restore on handler + * return + */ - usp = rtcb->xcp.saved_ursp - 8; + rtcb->xcp.kstkptr = (uintptr_t *)regs[REG_RSP]; - /* Create a frame for info and copy the kernel info */ + /* Create a 16 byte aligned frame for info below the red + * zone of the interrupted user code + */ - usp = usp - sizeof(siginfo_t); + usp = (rtcb->xcp.saved_ursp - X86_64_ABI_RED_ZONE - + sizeof(siginfo_t)) & ~0x0f; memcpy((void *)usp, (void *)regs[REG_RSI], sizeof(siginfo_t)); - /* Now set the updated SP and user copy of "info" to RSI */ + /* Set the new SP and the user copy of "info" to RSI. + * The naked trampoline is entered with SP 16 byte + * aligned; its call provides the return address slot. + */ regs[REG_RSP] = usp; regs[REG_RSI] = usp; @@ -290,12 +306,21 @@ uint64_t *x86_64_syscall(uint64_t *regs) DEBUGASSERT(rtcb->xcp.sigreturn != 0); regs[REG_RCX] = rtcb->xcp.sigreturn; - regs[REG_RSP] = rtcb->xcp.saved_rsp; rtcb->xcp.sigreturn = 0; - /* For kernel mode, we should be already on a correct kernel stack - * which was recovered in x86_64_syscall_entry. - */ +#ifdef CONFIG_ARCH_KERNEL_STACK + if (rtcb->xcp.kstack != NULL) + { + /* Return to the kernel stack saved at dispatch */ + + regs[REG_RSP] = (uint64_t)rtcb->xcp.kstkptr; + rtcb->xcp.kstkptr = rtcb->xcp.ktopstk; + } + else +#endif + { + regs[REG_RSP] = rtcb->xcp.saved_rsp; + } break; } diff --git a/arch/x86_64/src/intel64/intel64_schedulesigaction.c b/arch/x86_64/src/intel64/intel64_schedulesigaction.c index 2bd5cc52e53f7..7b8fae360b5eb 100644 --- a/arch/x86_64/src/intel64/intel64_schedulesigaction.c +++ b/arch/x86_64/src/intel64/intel64_schedulesigaction.c @@ -74,6 +74,8 @@ void up_schedule_sigaction(struct tcb_s *tcb) { + uint64_t sp = tcb->xcp.regs[REG_RSP]; + sinfo("tcb=%p, rtcb=%p current_regs=%p\n", tcb, this_task(), this_task()->xcp.regs); @@ -83,7 +85,7 @@ void up_schedule_sigaction(struct tcb_s *tcb) */ tcb->xcp.saved_rip = tcb->xcp.regs[REG_RIP]; - tcb->xcp.saved_rsp = tcb->xcp.regs[REG_RSP]; + tcb->xcp.saved_rsp = sp; tcb->xcp.saved_rflags = tcb->xcp.regs[REG_RFLAGS]; /* Then set up to vector to the trampoline with interrupts @@ -91,6 +93,21 @@ void up_schedule_sigaction(struct tcb_s *tcb) */ 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; + +#ifdef CONFIG_ARCH_KERNEL_STACK + /* Run the trampoline on the thread kernel stack when the thread was + * interrupted in user mode: the signal handler runs on the user + * stack and would overwrite the trampoline frame there. + */ + + if (tcb->xcp.kstack != NULL && + (sp < (uint64_t)tcb->xcp.kstack || sp > (uint64_t)tcb->xcp.ktopstk)) + { + tcb->xcp.saved_ursp = sp; + sp = (uint64_t)tcb->xcp.ktopstk; + } +#endif + + tcb->xcp.regs[REG_RSP] = sp - 8; }