This is an automated email from the ASF dual-hosted git repository. jerpelea pushed a commit to branch master in repository https://gitbox.apache.org/repos/asf/nuttx.git
commit 3fd1801c1292de6c6c161789a063e57313c077e9 Author: Marco Casaroli <[email protected]> AuthorDate: Sun Nov 1 00:28:09 2026 +0100 arch/x86_64: Keep the registers of a user thread on its kernel stack. up_initial_state() put the register area of each thread (xcp.regs) at the top of its stack, and the exception code saves the registers of the thread that runs there. For a user thread that is user memory, in the address environment that is selected at the exception: - While a thread loads a new program (exec()), it selects the address environment of the new program. An interrupt then wrote the registers of the thread into the memory of the new program at the address of the stack of the thread, and read them from there. - User code can change the saved registers (another thread of the process), also CS, SS and RFLAGS that iretq loads. A thread with a kernel stack now has its register area at the top of the kernel stack, under which the kernel stack starts. The user stack starts at the top of the stack. fork() copies the stack up to its top. Kernel threads keep the register area at the top of their stack. Assisted-by: Claude Code:claude-opus-5-5 Signed-off-by: Marco Casaroli <[email protected]> --- arch/x86_64/src/common/x86_64_fork.c | 17 ++++++++++++++--- arch/x86_64/src/intel64/intel64_initialstate.c | 26 ++++++++++++++++++++------ 2 files changed, 34 insertions(+), 9 deletions(-) diff --git a/arch/x86_64/src/common/x86_64_fork.c b/arch/x86_64/src/common/x86_64_fork.c index fd8fd9061c4..7240e9af82e 100644 --- a/arch/x86_64/src/common/x86_64_fork.c +++ b/arch/x86_64/src/common/x86_64_fork.c @@ -51,9 +51,10 @@ * * Description: * The high end of the part of a task's stack that a fork copies: the - * bottom of the register save area that up_initial_state() reserved at the - * very top of the stack. The save area itself is not stack and must not - * be copied over -- it is where the child's own resume frame is built. + * top of the stack of a task with a kernel stack, else the bottom of the + * register save area that up_initial_state() reserved at the very top of + * the stack. The save area itself is not stack and must not be copied + * over -- it is where the child's own resume frame is built. * * Input Parameters: * tcb - The task whose stack is in question @@ -65,6 +66,16 @@ static uint64_t x86_64_fork_stacktop(struct tcb_s *tcb) { +#ifdef CONFIG_ARCH_KERNEL_STACK + /* The register area is on the kernel stack: copy up to the top */ + + if (tcb->xcp.kstack != NULL) + { + return ((uintptr_t)tcb->stack_base_ptr + tcb->adj_stack_size) & + ~(uint64_t)15; + } +#endif + return (uint64_t)XCP_ALIGN_DOWN((uintptr_t)tcb->stack_base_ptr + tcb->adj_stack_size - XCPTCONTEXT_SIZE); } diff --git a/arch/x86_64/src/intel64/intel64_initialstate.c b/arch/x86_64/src/intel64/intel64_initialstate.c index 548836cdc4f..9cac270f68e 100644 --- a/arch/x86_64/src/intel64/intel64_initialstate.c +++ b/arch/x86_64/src/intel64/intel64_initialstate.c @@ -100,11 +100,25 @@ void up_initial_state(struct tcb_s *tcb) memset(xcp, 0, sizeof(struct xcptcontext)); - /* Allocate area for XCPTCONTEXT */ + /* Allocate area for XCPTCONTEXT. A thread with a kernel stack has it at + * the top of the kernel stack: user code must not reach it. + */ - xcp->regs = (uint64_t *)XCP_ALIGN_DOWN((uintptr_t)tcb->stack_base_ptr + - tcb->adj_stack_size - - XCPTCONTEXT_SIZE); + topstack = (uintptr_t)tcb->stack_base_ptr + tcb->adj_stack_size; +#ifdef CONFIG_ARCH_KERNEL_STACK + if (kstack) + { + xcp->regs = (uint64_t *)XCP_ALIGN_DOWN((uintptr_t)kstack + + ARCH_KERNEL_STACKSIZE - + XCPTCONTEXT_SIZE); + topstack &= ~(uint64_t)15; + } + else +#endif + { + xcp->regs = (uint64_t *)XCP_ALIGN_DOWN(topstack - XCPTCONTEXT_SIZE); + topstack = (uint64_t)xcp->regs; + } /* Reset the xcp registers */ @@ -127,7 +141,7 @@ void up_initial_state(struct tcb_s *tcb) : "memory"); #endif - topstack = (uint64_t)xcp->regs - 8; + topstack -= 8; /* Save the initial stack pointer... the value of the stackpointer before * the "interrupt occurs." @@ -145,7 +159,7 @@ void up_initial_state(struct tcb_s *tcb) { xcp->kstack = kstack; xcp->ustkptr = (uintptr_t *)topstack; - topstack = (uintptr_t)kstack + ARCH_KERNEL_STACKSIZE; + topstack = (uintptr_t)xcp->regs; xcp->ktopstk = (uintptr_t *)topstack; xcp->kstkptr = xcp->ktopstk;
