This is an automated email from the ASF dual-hosted git repository.

acassis pushed a commit to branch master
in repository https://gitbox.apache.org/repos/asf/nuttx.git

commit ce22c28e88b05ea0e77d43ad16b5069c5278a1f7
Author: p-szafonimateusz <[email protected]>
AuthorDate: Tue Jun 4 08:51:22 2024 +0200

    arch/x86_64: add kernel stack support
    
    arch/x86_64: add kernel stack support
    
    Signed-off-by: p-szafonimateusz <[email protected]>
---
 arch/x86_64/include/intel64/irq.h                  |  26 +++++
 arch/x86_64/include/irq.h                          |  18 +++-
 arch/x86_64/src/common/CMakeLists.txt              |   9 ++
 arch/x86_64/src/common/Make.defs                   |  13 ++-
 arch/x86_64/src/common/x86_64_addrenv_kstack.c     | 109 +++++++++++++++++++++
 arch/x86_64/src/common/x86_64_exit.c               |   6 ++
 arch/x86_64/src/common/x86_64_internal.h           |  22 ++++-
 arch/x86_64/src/common/x86_64_pthread_start.c      |  13 +++
 arch/x86_64/src/common/x86_64_switchcontext.c      |   6 ++
 arch/x86_64/src/common/x86_64_syscall.c            |  34 +++++++
 arch/x86_64/src/common/x86_64_task_start.c         |  13 +++
 arch/x86_64/src/intel64/intel64_cpu.c              |   3 +
 arch/x86_64/src/intel64/intel64_head.S             |  47 ++++++++-
 arch/x86_64/src/intel64/intel64_initialstate.c     |  52 ++++++++--
 .../x86_64/src/intel64/intel64_schedulesigaction.c |  24 +++++
 15 files changed, 377 insertions(+), 18 deletions(-)

diff --git a/arch/x86_64/include/intel64/irq.h 
b/arch/x86_64/include/intel64/irq.h
index c149604749..e1289e5558 100644
--- a/arch/x86_64/include/intel64/irq.h
+++ b/arch/x86_64/include/intel64/irq.h
@@ -528,6 +528,15 @@ struct xcptcontext
   uint64_t saved_rflags;
   uint64_t saved_rsp;
 
+#ifdef CONFIG_ARCH_KERNEL_STACK
+  /* For kernel stack enabled we can't use tcb->xcp.regs[REG_RSP] as it may
+   * point to kernel stack if signaled task is waiting now in
+   * up_switch_context()
+   */
+
+  uint64_t saved_ursp;
+#endif
+
   /* Register save area - allocated from stack in up_initial_state() */
 
   uint64_t *regs;
@@ -540,6 +549,23 @@ struct xcptcontext
   uint8_t nsyscalls;
   struct xcpt_syscall_s syscall[CONFIG_SYS_NNEST];
 #endif
+
+#ifdef CONFIG_ARCH_ADDRENV
+#  ifdef CONFIG_ARCH_KERNEL_STACK
+  /* In this configuration, all syscalls execute from an internal kernel
+   * stack.  Why?  Because when we instantiate and initialize the address
+   * environment of the new user process, we will temporarily lose the
+   * address environment of the old user process, including its stack
+   * contents.  The kernel C logic will crash immediately with no valid
+   * stack in place.
+   */
+
+  uintptr_t *ustkptr;  /* Saved user stack pointer */
+  uintptr_t *kstack;   /* Allocate base of the (aligned) kernel stack */
+  uintptr_t *ktopstk;  /* Top of kernel stack */
+  uintptr_t *kstkptr;  /* Saved kernel stack pointer */
+#  endif
+#endif
 };
 #endif
 
diff --git a/arch/x86_64/include/irq.h b/arch/x86_64/include/irq.h
index 92024a910f..f46544a1c8 100644
--- a/arch/x86_64/include/irq.h
+++ b/arch/x86_64/include/irq.h
@@ -49,8 +49,9 @@
  * Pre-processor Definitions
  ****************************************************************************/
 
-#define X86_64_CPUPRIV_USTACK_OFFSET  (16)
-#define X86_64_CPUPRIV_UVBASE_OFFSET  (24)
+#define X86_64_CPUPRIV_USTACK_OFFSET      (16)
+#define X86_64_CPUPRIV_UVBASE_OFFSET      (24)
+#define X86_64_CPUPRIV_KTOPSTK_OFFSET     (32)
 
 /****************************************************************************
  * Public Data
@@ -82,6 +83,19 @@ struct intel64_cpu_s
 
   uint64_t *uvbase;
 #endif
+
+#ifdef CONFIG_ARCH_KERNEL_STACK
+  /* Kernel stack pointer.
+   *
+   * We have to track the current kernel stack pointer to handle
+   * syscalls in kernel mode. All registers are occupied when entering
+   * syscall, so we cannot get this value from tcb in syscall handler.
+   * We keep referenve to kernel stack in CPU private data and update it
+   * at each context switch.
+   */
+
+  uint64_t *ktopstk;
+#endif
 };
 
 /****************************************************************************
diff --git a/arch/x86_64/src/common/CMakeLists.txt 
b/arch/x86_64/src/common/CMakeLists.txt
index 5a4334fbe3..5fb128f2ec 100644
--- a/arch/x86_64/src/common/CMakeLists.txt
+++ b/arch/x86_64/src/common/CMakeLists.txt
@@ -68,4 +68,13 @@ if(NOT CONFIG_ALARM_ARCH)
   list(APPEND SRCS x86_64_udelay.c x86_64_mdelay.c)
 endif()
 
+if(CONFIG_ARCH_KERNEL_STACK)
+  list(APPEND SRCS x86_64_addrenv_kstack.c)
+endif()
+
+if(NOT CONFIG_BUILD_FLAT)
+  list(APPEND SRCS x86_64_task_start.c x86_64_pthread_start.c
+       x86_64_signal_dispatch.c)
+endif()
+
 target_sources(arch PRIVATE ${SRCS})
diff --git a/arch/x86_64/src/common/Make.defs b/arch/x86_64/src/common/Make.defs
index bb18944627..429afc7647 100644
--- a/arch/x86_64/src/common/Make.defs
+++ b/arch/x86_64/src/common/Make.defs
@@ -58,7 +58,18 @@ CMN_CSRCS += x86_64_mmu.c
 endif
 
 ifeq ($(CONFIG_ARCH_ADDRENV),y)
-CMN_CSRCS += x86_64_addrenv.c x86_64_addrenv_perms.c
+CMN_CSRCS += x86_64_addrenv.c x86_64_pgalloc.c x86_64_addrenv_perms.c
+endif
+
+ifeq ($(CONFIG_ARCH_KERNEL_STACK),y)
+CMN_CSRCS += x86_64_addrenv_kstack.c
+endif
+
+ifneq ($(CONFIG_BUILD_FLAT),y)
+CMN_CSRCS  += x86_64_task_start.c
+CMN_CSRCS  += x86_64_pthread_start.c
+CMN_CSRCS  += x86_64_signal_dispatch.c
+CMN_UASRCS += x86_64_signal_handler.S
 endif
 
 ifndef CONFIG_ALARM_ARCH
diff --git a/arch/x86_64/src/common/x86_64_addrenv_kstack.c 
b/arch/x86_64/src/common/x86_64_addrenv_kstack.c
new file mode 100644
index 0000000000..6a56bf7ca6
--- /dev/null
+++ b/arch/x86_64/src/common/x86_64_addrenv_kstack.c
@@ -0,0 +1,109 @@
+/****************************************************************************
+ * arch/x86_64/src/common/x86_64_addrenv_kstack.c
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements.  See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.  The
+ * ASF licenses this file to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance with the
+ * License.  You may obtain a copy of the License at
+ *
+ *   http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
+ * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.  See the
+ * License for the specific language governing permissions and limitations
+ * under the License.
+ *
+ ****************************************************************************/
+
+/****************************************************************************
+ * Included Files
+ ****************************************************************************/
+
+#include <nuttx/config.h>
+
+#include <errno.h>
+#include <assert.h>
+#include <debug.h>
+
+#include <nuttx/sched.h>
+#include <nuttx/kmalloc.h>
+#include <nuttx/addrenv.h>
+#include <nuttx/arch.h>
+
+#include "addrenv.h"
+
+#if defined(CONFIG_ARCH_ADDRENV) && defined(CONFIG_ARCH_KERNEL_STACK)
+
+/****************************************************************************
+ * Public Functions
+ ****************************************************************************/
+
+/****************************************************************************
+ * Name: up_addrenv_kstackalloc
+ *
+ * Description:
+ *   This function is called when a new thread is created to allocate
+ *   the new thread's kernel stack.   This function may be called for certain
+ *   terminating threads which have no kernel stack.  It must be tolerant of
+ *   that case.
+ *
+ * Input Parameters:
+ *   tcb - The TCB of the thread that requires the kernel stack.
+ *
+ * Returned Value:
+ *   Zero (OK) on success; a negated errno value on failure.
+ *
+ ****************************************************************************/
+
+int up_addrenv_kstackalloc(struct tcb_s *tcb)
+{
+  DEBUGASSERT(tcb && tcb->xcp.kstack == NULL);
+
+  /* Allocate the kernel stack */
+
+  tcb->xcp.kstack = kmm_memalign(STACK_ALIGNMENT, ARCH_KERNEL_STACKSIZE);
+  if (!tcb->xcp.kstack)
+    {
+      berr("ERROR: Failed to allocate the kernel stack\n");
+      return -ENOMEM;
+    }
+
+  return OK;
+}
+
+/****************************************************************************
+ * Name: up_addrenv_kstackfree
+ *
+ * Description:
+ *   This function is called when any thread exits.  This function frees
+ *   the kernel stack.
+ *
+ * Input Parameters:
+ *   tcb - The TCB of the thread that no longer requires the kernel stack.
+ *
+ * Returned Value:
+ *   Zero (OK) on success; a negated errno value on failure.
+ *
+ ****************************************************************************/
+
+int up_addrenv_kstackfree(struct tcb_s *tcb)
+{
+  DEBUGASSERT(tcb);
+
+  /* Does the exiting thread have a kernel stack? */
+
+  if (tcb->xcp.kstack)
+    {
+      /* Yes.. Free the kernel stack */
+
+      kmm_free(tcb->xcp.kstack);
+      tcb->xcp.kstack = NULL;
+    }
+
+  return OK;
+}
+
+#endif /* CONFIG_ARCH_ADDRENV && CONFIG_ARCH_KERNEL_STACK */
diff --git a/arch/x86_64/src/common/x86_64_exit.c 
b/arch/x86_64/src/common/x86_64_exit.c
index 093f60fcac..eccaa89e2a 100644
--- a/arch/x86_64/src/common/x86_64_exit.c
+++ b/arch/x86_64/src/common/x86_64_exit.c
@@ -89,6 +89,12 @@ void up_exit(int status)
 
   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);
diff --git a/arch/x86_64/src/common/x86_64_internal.h 
b/arch/x86_64/src/common/x86_64_internal.h
index b1f972aefc..0d1bde0860 100644
--- a/arch/x86_64/src/common/x86_64_internal.h
+++ b/arch/x86_64/src/common/x86_64_internal.h
@@ -32,6 +32,7 @@
 #  include <nuttx/sched.h>
 #  include <stdint.h>
 #  include <arch/io.h>
+#  include <arch/irq.h>
 #  include <arch/multiboot2.h>
 #endif
 
@@ -191,15 +192,34 @@ extern uint8_t _stbss[];           /* Start of .tbss */
 extern uint8_t _etbss[];           /* End+1 of .tbss */
 #endif
 
+#ifndef __ASSEMBLY__
+
 /****************************************************************************
  * Inline Functions
  ****************************************************************************/
 
+#ifdef CONFIG_ARCH_KERNEL_STACK
+static inline_function uint64_t *x86_64_get_ktopstk(void)
+{
+  uint64_t *ktopstk;
+  __asm__ volatile("movq %%gs:(%c1), %0"
+                   : "=rm" (ktopstk)
+                   : "i" (offsetof(struct intel64_cpu_s, ktopstk)));
+  return ktopstk;
+}
+
+static inline_function void x86_64_set_ktopstk(uint64_t *ktopstk)
+{
+  __asm__ volatile("movq %0, %%gs:(%c1)"
+                   :: "r" (ktopstk), "i" (offsetof(struct intel64_cpu_s,
+                                                   ktopstk)));
+}
+#endif
+
 /****************************************************************************
  * Public Function Prototypes
  ****************************************************************************/
 
-#ifndef __ASSEMBLY__
 /* Atomic modification of registers */
 
 void modifyreg8(unsigned int addr, uint8_t clearbits, uint8_t setbits);
diff --git a/arch/x86_64/src/common/x86_64_pthread_start.c 
b/arch/x86_64/src/common/x86_64_pthread_start.c
index e24d06efcc..de09eef41b 100644
--- a/arch/x86_64/src/common/x86_64_pthread_start.c
+++ b/arch/x86_64/src/common/x86_64_pthread_start.c
@@ -27,6 +27,8 @@
 #include <nuttx/arch.h>
 #include <assert.h>
 
+#include "sched/sched.h"
+
 #include <arch/syscall.h>
 
 #include "x86_64_internal.h"
@@ -66,6 +68,17 @@
 void up_pthread_start(pthread_trampoline_t startup,
                       pthread_startroutine_t entrypt, pthread_addr_t arg)
 {
+#ifdef CONFIG_ARCH_KERNEL_STACK
+  struct tcb_s *tcb = this_task();
+
+  /* Make sure that kernel stack is set for current CPU */
+
+  if (x86_64_get_ktopstk() == NULL)
+    {
+      x86_64_set_ktopstk(tcb->xcp.ktopstk);
+    }
+#endif
+
   /* Let sys_call3() do all of the work */
 
   sys_call3(SYS_pthread_start, (uintptr_t)startup, (uintptr_t)entrypt,
diff --git a/arch/x86_64/src/common/x86_64_switchcontext.c 
b/arch/x86_64/src/common/x86_64_switchcontext.c
index cb461e8708..d7e0883b17 100644
--- a/arch/x86_64/src/common/x86_64_switchcontext.c
+++ b/arch/x86_64/src/common/x86_64_switchcontext.c
@@ -59,6 +59,12 @@ void up_switch_context(struct tcb_s *tcb, struct tcb_s *rtcb)
 {
   int cpu;
 
+#ifdef CONFIG_ARCH_KERNEL_STACK
+  /* Update kernel stack top pointer */
+
+  x86_64_set_ktopstk(tcb->xcp.ktopstk);
+#endif
+
   /* Are we in an interrupt handler? */
 
   if (up_interrupt_context())
diff --git a/arch/x86_64/src/common/x86_64_syscall.c 
b/arch/x86_64/src/common/x86_64_syscall.c
index cea1ad977d..1da8e300b7 100644
--- a/arch/x86_64/src/common/x86_64_syscall.c
+++ b/arch/x86_64/src/common/x86_64_syscall.c
@@ -218,6 +218,34 @@ uint64_t *x86_64_syscall(uint64_t *regs)
           regs[REG_RDX] = arg4; /* ucontext */
           regs[REG_R10] = arg1; /* sighand */
 
+#ifdef CONFIG_ARCH_KERNEL_STACK
+          /* If we are signalling a user process, then we must be operating
+           * on the kernel stack now.  We need to switch back to the user
+           * stack before dispatching the signal handler to the user code.
+           * The existence of an allocated kernel stack is sufficient
+           * information to make this decision.
+           */
+
+          if (rtcb->xcp.kstack != NULL)
+            {
+              uint64_t usp;
+
+              /* Copy "info" into user stack */
+
+              usp = rtcb->xcp.saved_ursp - 8;
+
+              /* Create a frame for info and copy the kernel info */
+
+              usp = usp - sizeof(siginfo_t);
+              memcpy((void *)usp, (void *)regs[REG_RSI], sizeof(siginfo_t));
+
+              /* Now set the updated SP and user copy of "info" to RSI */
+
+              regs[REG_RSP] = usp;
+              regs[REG_RSI] = usp;
+            }
+#endif
+
           break;
         }
 
@@ -276,6 +304,12 @@ uint64_t *x86_64_syscall(uint64_t *regs)
           rtcb->xcp.syscall[rtcb->xcp.nsyscalls].sysreturn = regs[REG_RCX];
           rtcb->xcp.nsyscalls += 1;
 
+#ifdef CONFIG_ARCH_KERNEL_STACK
+          /* Store reference to user RSP for signals */
+
+          rtcb->xcp.saved_ursp = regs[REG_RSP];
+#endif
+
           /* Call syscall function */
 
           ret = stub(nbr, arg1, arg2, arg3, arg4, arg5, arg6);
diff --git a/arch/x86_64/src/common/x86_64_task_start.c 
b/arch/x86_64/src/common/x86_64_task_start.c
index c70e999040..8e12802032 100644
--- a/arch/x86_64/src/common/x86_64_task_start.c
+++ b/arch/x86_64/src/common/x86_64_task_start.c
@@ -26,6 +26,8 @@
 #include <nuttx/arch.h>
 #include <assert.h>
 
+#include "sched/sched.h"
+
 #include <arch/syscall.h>
 
 #include "x86_64_internal.h"
@@ -63,6 +65,17 @@
 
 void up_task_start(main_t taskentry, int argc, char *argv[])
 {
+#ifdef CONFIG_ARCH_KERNEL_STACK
+  struct tcb_s *tcb = this_task();
+
+  /* Make sure that kernel stack is set for current CPU */
+
+  if (x86_64_get_ktopstk() == NULL)
+    {
+      x86_64_set_ktopstk(tcb->xcp.ktopstk);
+    }
+#endif
+
   /* Let sys_call3() do all of the work */
 
   sys_call3(SYS_task_start, (uintptr_t)taskentry, (uintptr_t)argc,
diff --git a/arch/x86_64/src/intel64/intel64_cpu.c 
b/arch/x86_64/src/intel64/intel64_cpu.c
index 2a6565d984..7ae497aaa1 100644
--- a/arch/x86_64/src/intel64/intel64_cpu.c
+++ b/arch/x86_64/src/intel64/intel64_cpu.c
@@ -246,6 +246,9 @@ void x86_64_cpu_init(void)
           g_cpu_priv[i].ustack    = NULL;
           g_cpu_priv[i].uvbase    = (uint64_t *)CONFIG_ARCH_TEXT_VBASE;
 #endif
+#ifdef CONFIG_ARCH_KERNEL_STACK
+          g_cpu_priv[i].ktopstk   = NULL;
+#endif
 
           /* Store private CPU in TSS */
 
diff --git a/arch/x86_64/src/intel64/intel64_head.S 
b/arch/x86_64/src/intel64/intel64_head.S
index b8174b503c..757879e7e9 100644
--- a/arch/x86_64/src/intel64/intel64_head.S
+++ b/arch/x86_64/src/intel64/intel64_head.S
@@ -552,10 +552,32 @@ x86_64_syscall_entry:
        /* Store current RSP on CPU private data first */
        movq   %rsp, %gs:X86_64_CPUPRIV_USTACK_OFFSET
 
-       /* Store return address - we need free register to store
-        * CPU context but at this point we don't have any.
+#ifdef CONFIG_ARCH_KERNEL_STACK
+       /* If current RSP is greater than kernel stack, we have to switch stack.
+        * Otherwise we are in nested syscall and we can't modify stack pointer
+        */
+       cmp    %gs:X86_64_CPUPRIV_UVBASE_OFFSET, %rsp
+       jb     no_kstack_switch
+
+       /* Change to kernel stack */
+       movq   %gs:X86_64_CPUPRIV_KTOPSTK_OFFSET, %rsp
+no_kstack_switch:
+#endif
+
+       /* Store some registers on stack.
+        * We need some free registers here to handle stored registers alignment
+        * and kernel stack for nested syscalls but at this point we don't have 
any
+        *
+        * RDI is needed only for CONFIG_ARCH_KERNEL_STACK=y but to simplify
+        * the logic here - we always release it.
         */
        pushq   %rcx
+       pushq   %rdi
+
+       /* Get original kernel stack for this call */
+
+       movq   %rsp, %rdi
+       add    $16, %rdi
 
        /* Get aligned registers area */
        movq   %rsp, %rcx
@@ -566,7 +588,6 @@ x86_64_syscall_entry:
 
        /* Syscall arguments */
        movq    %rax, (8*REG_RAX)(%rcx)
-       movq    %rdi, (8*REG_RDI)(%rcx)
        movq    %rsi, (8*REG_RSI)(%rcx)
        movq    %rdx, (8*REG_RDX)(%rcx)
        movq    %r10, (8*REG_R10)(%rcx)
@@ -602,16 +623,27 @@ x86_64_syscall_entry:
        xsave   (%rcx)
 #endif
 
-       /* Save RCX */
+       /* Save RDI and RCX which are on stack now */
+       popq    (8*REG_RDI)(%rcx)
        popq    (8*REG_RCX)(%rcx)
 
-       /* Store user stack pointer */
+       /* Store user stack pointer. We can't movq directly here.
+        * NOTE: for nested syscalls this value points to kernel stack.
+        */
        pushq   %gs:X86_64_CPUPRIV_USTACK_OFFSET
        popq    (8*REG_RSP)(%rcx)
 
        /* Move stack pointer after registers area */
        movq    %rcx, %rsp
 
+#ifdef CONFIG_ARCH_KERNEL_STACK
+       /* Update stored kernel stack */
+       movq    %rsp, %gs:X86_64_CPUPRIV_KTOPSTK_OFFSET
+
+       /* Store original kernel stack on stack which is now in RDI */
+       pushq   %rdi
+#endif
+
        /* Return value from syscall stored in rax */
        movq    %rcx, %rdi
        call    x86_64_syscall
@@ -626,6 +658,11 @@ x86_64_syscall_entry:
        xrstor  (%rdi)
 #endif
 
+#ifdef CONFIG_ARCH_KERNEL_STACK
+       /* Restore original kernel stack */
+       popq    %gs:X86_64_CPUPRIV_KTOPSTK_OFFSET
+#endif
+
        /* Restore original user RSP */
        movq    (8*REG_RSP)(%rdi), %rsp
 
diff --git a/arch/x86_64/src/intel64/intel64_initialstate.c 
b/arch/x86_64/src/intel64/intel64_initialstate.c
index b020174e03..81f324ec4b 100644
--- a/arch/x86_64/src/intel64/intel64_initialstate.c
+++ b/arch/x86_64/src/intel64/intel64_initialstate.c
@@ -45,6 +45,12 @@
 #  error XCPTCONTEXT_SIZE must be aligned to XCPTCONTEXT_ALIGN !
 #endif
 
+/* Aligned size of the kernel stack */
+
+#ifdef CONFIG_ARCH_KERNEL_STACK
+#  define ARCH_KERNEL_STACKSIZE STACK_ALIGN_UP(CONFIG_ARCH_KERNEL_STACKSIZE)
+#endif
+
 /****************************************************************************
  * Public Functions
  ****************************************************************************/
@@ -65,6 +71,10 @@
 void up_initial_state(struct tcb_s *tcb)
 {
   struct xcptcontext *xcp = &tcb->xcp;
+  uint64_t topstack;
+#ifdef CONFIG_ARCH_KERNEL_STACK
+  uintptr_t *kstack = xcp->kstack;
+#endif
 
   /* Initialize the idle thread stack */
 
@@ -102,11 +112,11 @@ void up_initial_state(struct tcb_s *tcb)
 #ifndef CONFIG_ARCH_X86_64_HAVE_XSAVE
   /* Set the FCW to 1f80 */
 
-  xcp->regs[1]          = (uint64_t)0x0000037f00000000;
+  xcp->regs[1] = (uint64_t)0x0000037f00000000;
 
   /* Set the MXCSR to 1f80 */
 
-  xcp->regs[3]          = (uint64_t)0x0000000000001f80;
+  xcp->regs[3] = (uint64_t)0x0000000000001f80;
 #else
   /* Initialize XSAVE region with a valid state */
 
@@ -116,25 +126,49 @@ void up_initial_state(struct tcb_s *tcb)
                    : "memory");
 #endif
 
+  topstack = (uint64_t)xcp->regs - 8;
+
   /* Save the initial stack pointer... the value of the stackpointer before
    * the "interrupt occurs."
    */
 
-  xcp->regs[REG_RSP]    = (uint64_t)xcp->regs - 8;
-  xcp->regs[REG_RBP]    = 0;
+  xcp->regs[REG_RSP] = topstack;
+  xcp->regs[REG_RBP] = 0;
+
+#ifdef CONFIG_ARCH_KERNEL_STACK
+  /* Use the process kernel stack to store context for user processes
+   * in syscalls.
+   */
+
+  if (kstack)
+    {
+      xcp->kstack  = kstack;
+      xcp->ustkptr = (uintptr_t *)topstack;
+      topstack     = (uintptr_t)kstack + ARCH_KERNEL_STACKSIZE;
+      xcp->ktopstk = (uintptr_t *)topstack;
+      xcp->kstkptr = xcp->ktopstk;
+
+      /* Initialize kernel stack top reference */
+
+      if (x86_64_get_ktopstk() == NULL)
+        {
+          x86_64_set_ktopstk(tcb->xcp.ktopstk);
+        }
+    }
+#endif
 
   /* Save the task entry point */
 
-  xcp->regs[REG_RIP]    = (uint64_t)tcb->start;
+  xcp->regs[REG_RIP] = (uint64_t)tcb->start;
 
   /* Set up the segment registers... assume the same segment as the caller.
    * That is not a good assumption in the long run.
    */
 
-  xcp->regs[REG_DS]     = up_getds();
-  xcp->regs[REG_CS]     = up_getcs();
-  xcp->regs[REG_SS]     = up_getss();
-  xcp->regs[REG_ES]     = up_getes();
+  xcp->regs[REG_DS] = up_getds();
+  xcp->regs[REG_CS] = up_getcs();
+  xcp->regs[REG_SS] = up_getss();
+  xcp->regs[REG_ES] = up_getes();
 
 /* FS used by for TLS
  * used by some libc for TLS and segment reference
diff --git a/arch/x86_64/src/intel64/intel64_schedulesigaction.c 
b/arch/x86_64/src/intel64/intel64_schedulesigaction.c
index c581165fc2..0a9bd0f279 100644
--- a/arch/x86_64/src/intel64/intel64_schedulesigaction.c
+++ b/arch/x86_64/src/intel64/intel64_schedulesigaction.c
@@ -126,6 +126,18 @@ void up_schedule_sigaction(struct tcb_s *tcb)
           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
         }
     }
 
@@ -216,6 +228,18 @@ void up_schedule_sigaction(struct tcb_s *tcb)
           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

Reply via email to