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 712e8d9cc7e158faa177fb84e2507a96e2013b75
Author: p-szafonimateusz <[email protected]>
AuthorDate: Sat Jul 20 11:59:00 2024 +0200

    arch/x86_64: add kernel build support
    
    arch/x86_64: add kernel build support
    
    Signed-off-by: p-szafonimateusz <[email protected]>
---
 arch/Kconfig                                       |   2 +-
 arch/x86_64/include/intel64/irq.h                  |   8 +
 arch/x86_64/include/syscall.h                      |  44 +++-
 arch/x86_64/src/common/CMakeLists.txt              |   7 +-
 arch/x86_64/src/common/Make.defs                   |   7 +
 arch/x86_64/src/common/Toolchain.defs              |   2 +-
 arch/x86_64/src/common/crt0.c                      | 121 +++++++++++
 arch/x86_64/src/common/pgalloc.h                   |  22 ++
 arch/x86_64/src/common/x86_64_allocateheap.c       |   4 +
 arch/x86_64/src/common/x86_64_pgalloc.c            | 232 +++++++++++++++++++++
 arch/x86_64/src/common/x86_64_pthread_start.c      |  77 +++++++
 arch/x86_64/src/common/x86_64_signal_dispatch.c    |  76 +++++++
 arch/x86_64/src/common/x86_64_syscall.c            | 138 ++++++++++++
 arch/x86_64/src/common/x86_64_task_start.c         |  74 +++++++
 arch/x86_64/src/intel64/intel64_head.S             |  10 +
 arch/x86_64/src/intel64/intel64_initialstate.c     |  11 -
 arch/x86_64/src/intel64/intel64_irq.c              |   7 +-
 .../x86_64/intel64/qemu-intel64/scripts/Make.defs  |   6 +-
 .../intel64/qemu-intel64/scripts/qemu-kernel.ld    | 130 ++++++++++++
 19 files changed, 959 insertions(+), 19 deletions(-)

diff --git a/arch/Kconfig b/arch/Kconfig
index 3f805ab1dd..978a2e2901 100644
--- a/arch/Kconfig
+++ b/arch/Kconfig
@@ -145,7 +145,7 @@ config ARCH_X86_64
        select LIBC_ARCH_ELF_64BIT if LIBC_ARCH_ELF
        select ARCH_TOOLCHAIN_GNU
        select ARCH_HAVE_BACKTRACE
-       select ARCH_HAVE_FORK
+       select ARCH_HAVE_FORK if !BUILD_KERNEL
        select ARCH_HAVE_SETJMP
        select ARCH_HAVE_PERF_EVENTS
        ---help---
diff --git a/arch/x86_64/include/intel64/irq.h 
b/arch/x86_64/include/intel64/irq.h
index 7dcb0e102e..c149604749 100644
--- a/arch/x86_64/include/intel64/irq.h
+++ b/arch/x86_64/include/intel64/irq.h
@@ -512,6 +512,14 @@ struct xcpt_syscall_s
 
 struct xcptcontext
 {
+#ifdef CONFIG_BUILD_KERNEL
+  /* This is the saved address to use when returning from a user-space
+   * signal handler.
+   */
+
+  uintptr_t sigreturn;
+#endif
+
   /* These are saved copies of instruction pointer and EFLAGS used during
    * signal processing.
    */
diff --git a/arch/x86_64/include/syscall.h b/arch/x86_64/include/syscall.h
index 5e27629991..7fc567b105 100644
--- a/arch/x86_64/include/syscall.h
+++ b/arch/x86_64/include/syscall.h
@@ -38,7 +38,49 @@
 
 /* Configuration ************************************************************/
 
-#define CONFIG_SYS_RESERVED 0
+#ifndef CONFIG_BUILD_FLAT
+#  define CONFIG_SYS_RESERVED 4
+#else
+#  define CONFIG_SYS_RESERVED 0
+#endif
+
+/* system calls */
+
+#ifndef CONFIG_BUILD_FLAT
+/* SYS call 0:
+ *
+ * void up_task_start(main_t taskentry, int argc, char *argv[])
+ *        noreturn_function;
+ */
+
+#  define SYS_task_start            (0)
+
+/* SYS call 1:
+ *
+ * void up_pthread_start((pthread_startroutine_t startup,
+ *                        pthread_startroutine_t entrypt, pthread_addr_t arg)
+ *        noreturn_function
+ */
+
+#  define SYS_pthread_start         (1)
+
+/* SYS call 2:
+ *
+ * void signal_handler(_sa_sigaction_t sighand,
+ *                     int signo, siginfo_t *info,
+ *                     void *ucontext);
+ */
+
+#  define SYS_signal_handler        (2)
+
+/* SYS call 3:
+ *
+ * void signal_handler_return(void);
+ */
+
+#  define SYS_signal_handler_return (3)
+
+#endif /* !CONFIG_BUILD_FLAT */
 
 /****************************************************************************
  * Public Types
diff --git a/arch/x86_64/src/common/CMakeLists.txt 
b/arch/x86_64/src/common/CMakeLists.txt
index 8e11fb3fa3..5a4334fbe3 100644
--- a/arch/x86_64/src/common/CMakeLists.txt
+++ b/arch/x86_64/src/common/CMakeLists.txt
@@ -56,7 +56,12 @@ if(CONFIG_ARCH_USE_MMU)
 endif()
 
 if(CONFIG_ARCH_ADDRENV)
-  list(APPEND SRCS x86_64_addrenv.c x86_64_addrenv_perms.c)
+  list(APPEND SRCS x86_64_addrenv.c x86_64_pgalloc.c x86_64_addrenv_perms.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()
 
 if(NOT CONFIG_ALARM_ARCH)
diff --git a/arch/x86_64/src/common/Make.defs b/arch/x86_64/src/common/Make.defs
index a13057704e..bb18944627 100644
--- a/arch/x86_64/src/common/Make.defs
+++ b/arch/x86_64/src/common/Make.defs
@@ -18,6 +18,13 @@
 #
 ############################################################################
 
+ifeq ($(CONFIG_BUILD_KERNEL),y)
+crt0$(OBJEXT): crt0.c
+       $(CC) $(CFLAGS) -c common$(DELIM)crt0.c -o crt0$(OBJEXT)
+
+STARTUP_OBJS = crt0$(OBJEXT)
+endif
+
 # Common x86_64 files
 
 CMN_CSRCS += x86_64_allocateheap.c x86_64_copystate.c x86_64_exit.c
diff --git a/arch/x86_64/src/common/Toolchain.defs 
b/arch/x86_64/src/common/Toolchain.defs
index 77ecc2825c..5a57c77529 100644
--- a/arch/x86_64/src/common/Toolchain.defs
+++ b/arch/x86_64/src/common/Toolchain.defs
@@ -241,7 +241,7 @@ LDMODULEFLAGS = -r -T $(call 
CONVERT_PATH,$(TOPDIR)/libs/libc/modlib/gnu-elf.ld)
 CELFFLAGS = $(CFLAGS) -fvisibility=hidden
 CXXELFFLAGS = $(CXXFLAGS) -fvisibility=hidden
 
-LDELFFLAGS = -r -e main --gc-sections
+LDELFFLAGS = -r -e main
 LDELFFLAGS += -T $(call 
CONVERT_PATH,$(TOPDIR)$(DELIM)libs$(DELIM)libc$(DELIM)modlib$(DELIM)gnu-elf.ld)
 
 # -fno-pic to avoid GOT relocations
diff --git a/arch/x86_64/src/common/crt0.c b/arch/x86_64/src/common/crt0.c
new file mode 100644
index 0000000000..cdd3321e76
--- /dev/null
+++ b/arch/x86_64/src/common/crt0.c
@@ -0,0 +1,121 @@
+/****************************************************************************
+ * arch/x86_64/src/common/crt0.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 <sys/types.h>
+#include <stdlib.h>
+
+#include <nuttx/addrenv.h>
+
+#include <arch/syscall.h>
+
+#ifdef CONFIG_BUILD_KERNEL
+
+/****************************************************************************
+ * Public Function Prototypes
+ ****************************************************************************/
+
+int main(int argc, char *argv[]);
+
+/****************************************************************************
+ * Private Functions
+ ****************************************************************************/
+
+/****************************************************************************
+ * Name: up_signal_handler
+ *
+ * Description:
+ *   This function is the user-space, signal handler trampoline function.  It
+ *   is called from up_signal_dispatch() in user-mode.
+ *
+ * Returned Value:
+ *   None.  This function does not return in the normal sense.  It returns
+ *   via the SYS_signal_handler_return (see syscall.h)
+ *
+ ****************************************************************************/
+
+static void sig_trampoline(void) naked_function;
+static void sig_trampoline(void)
+{
+  /* RDI = signal
+   * RSI = info
+   * RDX = ucontext
+   * R10 = sighand
+   * RAX = syscall ID
+   */
+
+  __asm__ volatile
+  (
+    "call *%%r10\n"
+    "movq %0, %%rax\n"
+    "syscall\n"
+    :: "i"(SYS_signal_handler_return)
+  );
+}
+
+/****************************************************************************
+ * Public Functions
+ ****************************************************************************/
+
+/****************************************************************************
+ * Name: __start
+ *
+ * Description:
+ *   This function is the low level entry point into the main thread of
+ *   execution of a task.  It receives initial control when the task is
+ *   started and calls main entry point of the newly started task.
+ *
+ * Input Parameters:
+ *   argc - The number of parameters being passed.
+ *   argv - The parameters being passed. These lie in kernel-space memory
+ *     and will have to be reallocated  in user-space memory.
+ *
+ * Returned Value:
+ *   This function should not return.  It should call the user-mode start-up
+ *   main() function.  If that function returns, this function will call
+ *   exit.
+ *
+ ****************************************************************************/
+
+void __start(int argc, char *argv[])
+{
+  int ret;
+
+  /* Initialize the reserved area at the beginning of the .bss/.data region
+   * that is visible to the RTOS.
+   */
+
+  ARCH_DATA_RESERVE->ar_sigtramp = (addrenv_sigtramp_t)sig_trampoline;
+
+  /* Call the main() entry point passing argc and argv. */
+
+  ret = main(argc, argv);
+
+  /* Call exit() if/when the main() returns */
+
+  exit(ret);
+}
+
+#endif /* CONFIG_BUILD_KERNEL */
diff --git a/arch/x86_64/src/common/pgalloc.h b/arch/x86_64/src/common/pgalloc.h
index e85d4ee8b5..e1f7531b5a 100644
--- a/arch/x86_64/src/common/pgalloc.h
+++ b/arch/x86_64/src/common/pgalloc.h
@@ -93,6 +93,28 @@ static inline uintptr_t x86_64_pgpaddr(uintptr_t vaddr)
   return 0;
 }
 
+/****************************************************************************
+ * Name: x86_64_uservaddr
+ *
+ * Description:
+ *   Return true if the virtual address, vaddr, lies in the user address
+ *   space.
+ *
+ ****************************************************************************/
+
+static inline bool x86_64_uservaddr(uintptr_t vaddr)
+{
+  /* Check if this address is within the range of the virtualized .bss/.data,
+   * heap, or stack regions.
+   */
+
+  return ((vaddr >= ARCH_ADDRENV_VBASE && vaddr < ARCH_ADDRENV_VEND)
+#ifdef CONFIG_ARCH_VMA_MAPPING
+          || (vaddr >= CONFIG_ARCH_SHM_VBASE && vaddr < ARCH_SHM_VEND)
+#endif
+    );
+}
+
 /****************************************************************************
  * Name: x86_64_pgwipe
  *
diff --git a/arch/x86_64/src/common/x86_64_allocateheap.c 
b/arch/x86_64/src/common/x86_64_allocateheap.c
index 0dbfc9a7f9..0623f8fe39 100644
--- a/arch/x86_64/src/common/x86_64_allocateheap.c
+++ b/arch/x86_64/src/common/x86_64_allocateheap.c
@@ -93,7 +93,11 @@ const uintptr_t g_idle_topstack[CONFIG_SMP_NCPUS] =
  *
  ****************************************************************************/
 
+#ifdef CONFIG_BUILD_KERNEL
+void up_allocate_kheap(void **heap_start, size_t *heap_size)
+#else
 void up_allocate_heap(void **heap_start, size_t *heap_size)
+#endif /* CONFIG_BUILD_KERNEL */
 {
   uintptr_t hstart;
   uintptr_t topstack;
diff --git a/arch/x86_64/src/common/x86_64_pgalloc.c 
b/arch/x86_64/src/common/x86_64_pgalloc.c
new file mode 100644
index 0000000000..75db0cbe70
--- /dev/null
+++ b/arch/x86_64/src/common/x86_64_pgalloc.c
@@ -0,0 +1,232 @@
+/****************************************************************************
+ * arch/x86_64/src/common/x86_64_pgalloc.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 <string.h>
+#include <assert.h>
+#include <errno.h>
+#include <debug.h>
+
+#include <nuttx/irq.h>
+#include <nuttx/sched.h>
+#include <nuttx/arch.h>
+#include <nuttx/addrenv.h>
+#include <nuttx/pgalloc.h>
+#include <nuttx/spinlock.h>
+
+#include "addrenv.h"
+#include "pgalloc.h"
+#include "x86_64_mmu.h"
+
+#ifdef CONFIG_BUILD_KERNEL
+
+/****************************************************************************
+ * Pre-processor Definitions
+ ****************************************************************************/
+
+/* Last PGT level */
+
+#define PGT_LAST    (X86_MMU_PT_LEVELS)
+
+/****************************************************************************
+ * Private Functions
+ ****************************************************************************/
+
+/****************************************************************************
+ * Name: x86_64_get_pgtable
+ *
+ * Description:
+ *   Get the physical address of the final level page table corresponding to
+ *   'vaddr'. If one does not exist, it will be allocated.
+ *
+ * Input Parameters:
+ *   addrenv - Pointer to a structure describing the address environment
+ *   vaddr - Virtual address to query for
+ *
+ * Returned Value:
+ *   The physical address of the corresponding final level page table, or
+ *   NULL if one does not exist, and there is no free memory to allocate one
+ *
+ ****************************************************************************/
+
+uintptr_t x86_64_get_pgtable(arch_addrenv_t *addrenv, uintptr_t vaddr)
+{
+  uintptr_t paddr;
+  uintptr_t ptprev;
+  uint32_t  ptlevel;
+  uint32_t  flags;
+
+  /* Get the current level MAX_LEVELS-1 entry corresponding to this vaddr */
+
+  ptlevel = ARCH_SPGTS;
+  ptprev  = x86_64_pgvaddr(addrenv->spgtables[ARCH_SPGTS - 1]);
+  if (!ptprev)
+    {
+      /* Something is very wrong */
+
+      return 0;
+    }
+
+  /* Find the physical address of the final level page table */
+
+  paddr = mmu_pte_to_paddr(mmu_ln_getentry(ptlevel, ptprev, vaddr));
+  if (!paddr)
+    {
+      /* No page table has been allocated... allocate one now */
+
+      paddr = mm_pgalloc(1);
+      if (paddr)
+        {
+          /* Determine page table flags */
+
+          if (x86_64_uservaddr(vaddr))
+            {
+              flags = MMU_UPGT_FLAGS;
+            }
+          else
+            {
+              flags = MMU_KPGT_FLAGS;
+            }
+
+          /* Wipe the page and assign it */
+
+          x86_64_pgwipe(paddr);
+          mmu_ln_setentry(ptlevel, ptprev, paddr, vaddr, flags);
+        }
+    }
+
+  /* Flush the data cache, so the changes are committed to memory */
+
+  SP_DMB();
+
+  return paddr;
+}
+
+/****************************************************************************
+ * Public Functions
+ ****************************************************************************/
+
+/****************************************************************************
+ * Name: pgalloc
+ *
+ * Description:
+ *   If there is a page allocator in the configuration and if and MMU is
+ *   available to map physical addresses to virtual address, then function
+ *   must be provided by the platform-specific code.  This is part of the
+ *   implementation of sbrk().  This function will allocate the requested
+ *   number of pages using the page allocator and map them into consecutive
+ *   virtual addresses beginning with 'brkaddr'
+ *
+ *   NOTE:  This function does not use the up_ naming standard because it
+ *   is indirectly callable from user-space code via a system trap.
+ *   Therefore, it is a system interface and follows a different naming
+ *   convention.
+ *
+ * Input Parameters:
+ *   brkaddr - The heap break address.  The next page will be allocated and
+ *     mapped to this address.  Must be page aligned.  If the memory manager
+ *     has not yet been initialized and this is the first block requested for
+ *     the heap, then brkaddr should be zero.  pgalloc will then assigned the
+ *     well-known virtual address of the beginning of the heap.
+ *   npages - The number of pages to allocate and map.  Mapping of pages
+ *     will be contiguous beginning beginning at 'brkaddr'
+ *
+ * Returned Value:
+ *   The (virtual) base address of the mapped page will returned on success.
+ *   Normally this will be the same as the 'brkaddr' input. However, if
+ *   the 'brkaddr' input was zero, this will be the virtual address of the
+ *   beginning of the heap.  Zero is returned on any failure.
+ *
+ ****************************************************************************/
+
+uintptr_t pgalloc(uintptr_t brkaddr, unsigned int npages)
+{
+  struct tcb_s          *tcb = nxsched_self();
+  struct arch_addrenv_s *addrenv;
+  uintptr_t              ptlast;
+  uintptr_t              paddr;
+  uintptr_t              vaddr;
+
+  DEBUGASSERT(tcb && tcb->addrenv_own);
+  addrenv = &tcb->addrenv_own->addrenv;
+
+  /* The current implementation only supports extending the user heap
+   * region as part of the implementation of user sbrk().  This function
+   * needs to be expanded to also handle (1) extending the user stack
+   * space and (2) extending the kernel memory regions as well.
+   */
+
+  /* brkaddr = 0 means that no heap has yet been allocated */
+
+  if (!brkaddr)
+    {
+      brkaddr = addrenv->heapvbase;
+    }
+
+  /* Start mapping from the old heap break address */
+
+  vaddr = brkaddr;
+
+  /* Sanity checks */
+
+  DEBUGASSERT(brkaddr >= addrenv->heapvbase);
+  DEBUGASSERT(MM_ISALIGNED(brkaddr));
+
+  for (; npages > 0; npages--)
+    {
+      /* Get the address of the last level page table */
+
+      ptlast = x86_64_pgvaddr(x86_64_get_pgtable(addrenv, vaddr));
+      if (!ptlast)
+        {
+          return 0;
+        }
+
+      /* Allocate physical memory for the new heap */
+
+      paddr = mm_pgalloc(1);
+      if (!paddr)
+        {
+          return 0;
+        }
+
+      /* Wipe the memory */
+
+      x86_64_pgwipe(paddr);
+
+      /* Then add the reference */
+
+      mmu_ln_setentry(PGT_LAST, ptlast, paddr, vaddr, MMU_UDATA_FLAGS);
+      vaddr += MM_PGSIZE;
+    }
+
+  /* Flush the data cache, so the changes are committed to memory */
+
+  SP_DMB();
+
+  return brkaddr;
+}
+
+#endif /* CONFIG_BUILD_KERNEL */
diff --git a/arch/x86_64/src/common/x86_64_pthread_start.c 
b/arch/x86_64/src/common/x86_64_pthread_start.c
new file mode 100644
index 0000000000..e24d06efcc
--- /dev/null
+++ b/arch/x86_64/src/common/x86_64_pthread_start.c
@@ -0,0 +1,77 @@
+/****************************************************************************
+ * arch/x86_64/src/common/x86_64_pthread_start.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 <pthread.h>
+#include <nuttx/arch.h>
+#include <assert.h>
+
+#include <arch/syscall.h>
+
+#include "x86_64_internal.h"
+
+#if !defined(CONFIG_BUILD_FLAT) && defined(__KERNEL__) && \
+    !defined(CONFIG_DISABLE_PTHREAD)
+
+/****************************************************************************
+ * Public Functions
+ ****************************************************************************/
+
+/****************************************************************************
+ * Name: up_pthread_start
+ *
+ * Description:
+ *   In this kernel mode build, this function will be called to execute a
+ *   pthread in user-space.  When the pthread is first started, a kernel-mode
+ *   stub will first run to perform some housekeeping functions.  This
+ *   kernel-mode stub will then be called transfer control to the user-mode
+ *   pthread.
+ *
+ *   Normally the a user-mode start-up stub will also execute before the
+ *   pthread actually starts.  See libc/pthread/pthread_create.c
+ *
+ * Input Parameters:
+ *   startup - The user-space pthread startup function
+ *   entrypt - The user-space address of the pthread entry point
+ *   arg     - Standard argument for the pthread entry point
+ *
+ * Returned Value:
+ *   This function should not return.  It should call the user-mode start-up
+ *   stub and that stub should call pthread_exit if/when the user pthread
+ *   terminates.
+ *
+ ****************************************************************************/
+
+void up_pthread_start(pthread_trampoline_t startup,
+                      pthread_startroutine_t entrypt, pthread_addr_t arg)
+{
+  /* Let sys_call3() do all of the work */
+
+  sys_call3(SYS_pthread_start, (uintptr_t)startup, (uintptr_t)entrypt,
+            (uintptr_t)arg);
+
+  PANIC();
+}
+
+#endif /* !CONFIG_BUILD_FLAT && __KERNEL__ && !CONFIG_DISABLE_PTHREAD */
diff --git a/arch/x86_64/src/common/x86_64_signal_dispatch.c 
b/arch/x86_64/src/common/x86_64_signal_dispatch.c
new file mode 100644
index 0000000000..3a5bcc12bd
--- /dev/null
+++ b/arch/x86_64/src/common/x86_64_signal_dispatch.c
@@ -0,0 +1,76 @@
+/****************************************************************************
+ * arch/x86_64/src/common/x86_64_signal_dispatch.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 <nuttx/arch.h>
+
+#include <arch/syscall.h>
+
+#include "x86_64_internal.h"
+
+#if !defined(CONFIG_BUILD_FLAT) && defined(__KERNEL__)
+
+/****************************************************************************
+ * Public Functions
+ ****************************************************************************/
+
+/****************************************************************************
+ * Name: up_signal_dispatch
+ *
+ * Description:
+ *   In the kernel mode build, this function will be called to execute a
+ *   a signal handler in user-space.  When the signal is delivered, a
+ *   kernel-mode stub will first run to perform some housekeeping functions.
+ *   This kernel-mode stub will then be called transfer control to the user
+ *   mode signal handler by calling this function.
+ *
+ *   Normally the user-mode signaling handling stub will also execute
+ *   before the ultimate signal handler is called.  See
+ *   arch/x86_64/src/common/x86_64_signal_handler.S.  This function is the
+ *   user-space, signal handler trampoline function.  It is called from
+ *   up_signal_dispatch() in user-mode.
+ *
+ * Input Parameters:
+ *   sighand - The address user-space signal handling function
+ *   signo, info, and ucontext - Standard arguments to be passed to the
+ *     signal handling function.
+ *
+ * Returned Value:
+ *   None.  This function does not return in the normal sense.  It returns
+ *   via an architecture specific system call made by up_signal_handler().
+ *   However, this will look like a normal return by the caller of
+ *   up_signal_dispatch.
+ *
+ ****************************************************************************/
+
+void up_signal_dispatch(_sa_sigaction_t sighand, int signo,
+                        siginfo_t *info, void *ucontext)
+{
+  /* Let sys_call4() do all of the work */
+
+  sys_call4(SYS_signal_handler, (uintptr_t)sighand, (uintptr_t)signo,
+            (uintptr_t)info, (uintptr_t)ucontext);
+}
+
+#endif /* !CONFIG_BUILD_FLAT && __KERNEL__ */
diff --git a/arch/x86_64/src/common/x86_64_syscall.c 
b/arch/x86_64/src/common/x86_64_syscall.c
index 5e52b5347c..cea1ad977d 100644
--- a/arch/x86_64/src/common/x86_64_syscall.c
+++ b/arch/x86_64/src/common/x86_64_syscall.c
@@ -118,6 +118,144 @@ uint64_t *x86_64_syscall(uint64_t *regs)
 
   switch (cmd)
     {
+#ifdef CONFIG_BUILD_KERNEL
+      /* cmd=SYS_task_start:  This a user task start
+       *
+       *   void up_task_start(main_t taskentry, int argc, char *argv[])
+       *     noreturn_function;
+       *
+       * At this point, the following values are saved in context:
+       *
+       *   cmd  = SYS_task_start
+       *   arg1 = taskentry
+       *   arg2 = argc
+       *   arg3 = argv
+       */
+
+      case SYS_task_start:
+        {
+          /* Set up to return to the user-space _start function in
+           * unprivileged mode.  We need:
+           *
+           *   RDI = argc
+           *   RSI = argv
+           *   RCX = taskentry (SYSRETQ return address)
+           *
+           */
+
+          regs[REG_RDI] = arg2;
+          regs[REG_RSI] = arg3;
+          regs[REG_RCX] = arg1;
+
+          break;
+        }
+
+      /* cmd=SYS_pthread_start:  This a user pthread start
+       *
+       *   void up_pthread_start(pthread_startroutine_t entrypt,
+       *                         pthread_addr_t arg) noreturn_function;
+       *
+       * At this point, the following values are saved in context:
+       *
+       *   cmd  = SYS_pthread_start
+       *   arg1 = startup
+       *   arg2 = entrypt
+       *   arg3 = arg
+       */
+
+      case SYS_pthread_start:
+        {
+          /* Set up to enter the user-space pthread start-up function in
+           * unprivileged mode. We need:
+           *
+           *   RDI   = entrypt
+           *   RSI   = arg
+           *   RCX   = startup (SYSRETQ return address)
+           */
+
+          regs[REG_RDI] = arg2;
+          regs[REG_RSI] = arg3;
+          regs[REG_RCX] = arg1;
+
+          break;
+        }
+
+      /* cmd=SYS_signal_handler:  This a user signal handler callback
+       *
+       * void signal_handler(_sa_sigaction_t sighand, int signo,
+       *                     siginfo_t *info, void *ucontext);
+       *
+       * At this point, the following values are saved in context:
+       *
+       *   cmd  = SYS_signal_handler
+       *   arg1 = sighand
+       *   arg2 = signo
+       *   arg3 = info
+       *   arg4 = ucontext (on the stack)
+       */
+
+      case SYS_signal_handler:
+        {
+          struct tcb_s *rtcb = nxsched_self();
+
+          /* Remember the caller's return address */
+
+          DEBUGASSERT(rtcb->xcp.sigreturn == 0);
+          rtcb->xcp.sigreturn = regs[REG_RCX];
+
+          /* Set up to return to the user-space trampoline function in
+           * unprivileged mode.
+           */
+
+          regs[REG_RCX] = (uint64_t)ARCH_DATA_RESERVE->ar_sigtramp;
+
+          /* Change the parameter ordering to match the expectation of struct
+           * userpace_s signal_handler.
+           */
+
+          regs[REG_RDI] = arg2; /* signal */
+          regs[REG_RSI] = arg3; /* info */
+          regs[REG_RDX] = arg4; /* ucontext */
+          regs[REG_R10] = arg1; /* sighand */
+
+          break;
+        }
+
+      /* cmd=SYS_signal_handler_return:  This a user signal handler callback
+       *
+       *   void signal_handler_return(void);
+       *
+       * At this point, the following values are saved in context:
+       *
+       *   cmd = SYS_signal_handler_return
+       */
+
+      case SYS_signal_handler_return:
+        {
+          /* Set up to return to the user-space. We need:
+           *
+           *   RCX = taskentry (SYSRETQ return address)
+           *
+           */
+
+          struct tcb_s *rtcb = nxsched_self();
+
+          /* Set up to return to the kernel-mode signal dispatching logic. */
+
+          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.
+           */
+
+          break;
+        }
+#endif  /* CONFIG_BUILD_KERNEL */
+
       /* This is not an architecture-specific system call.  If NuttX is
        * built as a standalone kernel with a system call interface, then
        * all of the additional system calls must be handled as in the
diff --git a/arch/x86_64/src/common/x86_64_task_start.c 
b/arch/x86_64/src/common/x86_64_task_start.c
new file mode 100644
index 0000000000..c70e999040
--- /dev/null
+++ b/arch/x86_64/src/common/x86_64_task_start.c
@@ -0,0 +1,74 @@
+/****************************************************************************
+ * arch/x86_64/src/common/x86_64_task_start.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 <nuttx/arch.h>
+#include <assert.h>
+
+#include <arch/syscall.h>
+
+#include "x86_64_internal.h"
+
+#ifndef CONFIG_BUILD_FLAT
+
+/****************************************************************************
+ * Public Functions
+ ****************************************************************************/
+
+/****************************************************************************
+ * Name: up_task_start
+ *
+ * Description:
+ *   In this kernel mode build, this function will be called to execute a
+ *   task in user-space.  When the task is first started, a kernel-mode
+ *   stub will first run to perform some housekeeping functions.  This
+ *   kernel-mode stub will then be called transfer control to the user-mode
+ *   task.
+ *
+ *   Normally the a user-mode start-up stub will also execute before the
+ *   task actually starts.  See libc/sched/task_startup.c
+ *
+ * Input Parameters:
+ *   taskentry - The user-space entry point of the task.
+ *   argc - The number of parameters being passed.
+ *   argv - The parameters being passed. These lie in kernel-space memory
+ *     and will have to be reallocated  in user-space memory.
+ *
+ * Returned Value:
+ *   This function should not return.  It should call the user-mode start-up
+ *   stub and that stub should call exit if/when the user task terminates.
+ *
+ ****************************************************************************/
+
+void up_task_start(main_t taskentry, int argc, char *argv[])
+{
+  /* Let sys_call3() do all of the work */
+
+  sys_call3(SYS_task_start, (uintptr_t)taskentry, (uintptr_t)argc,
+            (uintptr_t)argv);
+
+  PANIC();
+}
+
+#endif /* !CONFIG_BUILD_FLAT */
diff --git a/arch/x86_64/src/intel64/intel64_head.S 
b/arch/x86_64/src/intel64/intel64_head.S
index d07bcdd482..b8174b503c 100644
--- a/arch/x86_64/src/intel64/intel64_head.S
+++ b/arch/x86_64/src/intel64/intel64_head.S
@@ -647,6 +647,16 @@ x86_64_syscall_entry:
        movq    (8*REG_R11)(%rdi), %r11
        movq    (8*REG_RDI)(%rdi), %rdi
 
+#  ifdef CONFIG_BUILD_KERNEL
+       /* Do not return to RING3 if this is nested syscall */
+       cmp %gs:X86_64_CPUPRIV_UVBASE_OFFSET, %rcx
+       jb syscall_no_ring3
+
+       /* Return to user code pointed in RCX */
+       sysretq
+
+syscall_no_ring3:
+#  endif
        /* Return to address pointed in RCX - must be on stack */
        pushq   %rcx
        ret
diff --git a/arch/x86_64/src/intel64/intel64_initialstate.c 
b/arch/x86_64/src/intel64/intel64_initialstate.c
index 0b0ad138f5..b020174e03 100644
--- a/arch/x86_64/src/intel64/intel64_initialstate.c
+++ b/arch/x86_64/src/intel64/intel64_initialstate.c
@@ -156,17 +156,6 @@ void up_initial_state(struct tcb_s *tcb)
 
   xcp->regs[REG_GS]     = 0;
 
-  /* Set supervisor- or user-mode, depending on how NuttX is configured and
-   * what kind of thread is being started.  Disable FIQs in any event
-   *
-   * If the kernel build is not selected, then all threads run in
-   * supervisor-mode.
-   */
-
-#ifdef CONFIG_BUILD_KERNEL
-#  error "Missing logic for the CONFIG_BUILD_KERNEL build"
-#endif
-
   /* Enable or disable interrupts, based on user configuration.  If the IF
    * bit is set, maskable interrupts will be enabled.
    */
diff --git a/arch/x86_64/src/intel64/intel64_irq.c 
b/arch/x86_64/src/intel64/intel64_irq.c
index a8e8cd345d..657dec1cd6 100644
--- a/arch/x86_64/src/intel64/intel64_irq.c
+++ b/arch/x86_64/src/intel64/intel64_irq.c
@@ -344,11 +344,12 @@ static void up_idtentry(unsigned int index, uint64_t 
base, uint16_t sel,
   entry->sel     = sel;
   entry->zero    = 0;
 
-  /* We must uncomment the OR below when we get to using user-mode. It sets
-   * the interrupt gate's privilege level to 3.
+  /* We don't use software interrupts from user-space (INT) so DPL level
+   * can be set to privilage level 0. DPL bits have no effect on hardware
+   * interrupts.
    */
 
-  entry->flags  = flags; /* | 0x60 */
+  entry->flags   = flags;
 }
 
 /****************************************************************************
diff --git a/boards/x86_64/intel64/qemu-intel64/scripts/Make.defs 
b/boards/x86_64/intel64/qemu-intel64/scripts/Make.defs
index 2b2d675e37..ed40ccf546 100644
--- a/boards/x86_64/intel64/qemu-intel64/scripts/Make.defs
+++ b/boards/x86_64/intel64/qemu-intel64/scripts/Make.defs
@@ -24,4 +24,8 @@ include $(TOPDIR)/.config
 include $(TOPDIR)/tools/Config.mk
 include $(TOPDIR)/arch/x86_64/src/intel64/Toolchain.defs
 
-ARCHSCRIPT += $(BOARD_DIR)$(DELIM)scripts$(DELIM)qemu.ld
\ No newline at end of file
+ifeq ($(CONFIG_BUILD_KERNEL),y)
+ARCHSCRIPT += $(BOARD_DIR)$(DELIM)scripts$(DELIM)qemu-kernel.ld
+else
+ARCHSCRIPT += $(BOARD_DIR)$(DELIM)scripts$(DELIM)qemu.ld
+endif
diff --git a/boards/x86_64/intel64/qemu-intel64/scripts/qemu-kernel.ld 
b/boards/x86_64/intel64/qemu-intel64/scripts/qemu-kernel.ld
new file mode 100644
index 0000000000..341bc0c44e
--- /dev/null
+++ b/boards/x86_64/intel64/qemu-intel64/scripts/qemu-kernel.ld
@@ -0,0 +1,130 @@
+/****************************************************************************
+ * boards/x86_64/intel64/qemu-intel64/scripts/qemu-kernel.ld
+ *
+ * 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.
+ *
+ ****************************************************************************/
+
+OUTPUT_ARCH(i386:x86-64)
+ENTRY(__pmode_entry)
+SECTIONS
+{
+
+    . = 0x0;
+
+    .realmode : {
+        . = ALIGN(8);
+        KEEP(*(.multiboot))
+        *(.realmode)
+    }
+
+    . = 0x1M;
+    _kernel_physical_start = .;
+
+    .loader.text : {
+        . = ALIGN(8);
+        *(.loader.text)
+    }
+
+    .loader.rodata : {
+        *(.loader.rodata)
+    }
+
+    .loader.data : {
+        *(.loader.data)
+    }
+
+    .loader.bss : {
+        *(.loader.bss)
+    }
+
+    . = ALIGN(0x1000);
+      _boot_end = .;
+
+    . += 0x100000000;
+    _kernel_virtual_start = .;
+
+    .text : AT(_boot_end)
+    {
+        _stext = ABSOLUTE(.);
+        . = ALIGN(8);
+        KEEP(*(.multiboot))
+        *(.text .text.*)
+        *(.gnu.linkonce.t.*)
+        _etext = ABSOLUTE(.);
+    }
+
+    .rodata ALIGN(0x1000) :
+    {
+        _srodata = ABSOLUTE(.);
+        *(.rodata .rodata.*)
+        *(.fixup)
+        *(.gnu.warning)
+        *(.glue_7)
+        *(.glue_7t)
+        *(.got)
+        *(.gcc_except_table)
+        *(.gnu.linkonce.r.*)
+        *(.eh_frame)
+        *(.note.gnu.*)
+        _erodata = ABSOLUTE(.);
+    }
+
+    .data ALIGN(0x1000) :
+    {
+        _sdata = ABSOLUTE(.);
+        *(.data .data.*)
+        *(.gnu.linkonce.d.*)
+        CONSTRUCTORS
+        . = ALIGN(4);
+        _edata = ABSOLUTE(.);
+    }
+
+    .pgheap ALIGN(0x1000) :
+    {
+        __pgheap_start = ABSOLUTE(.);
+        . = ALIGN(0x1000);
+        __pgheap_size = ABSOLUTE(.);
+    }
+
+    .bss ALIGN(0x1000) :
+    {
+        _sbss = ABSOLUTE(.);
+        *(.bss .bss.*)
+        *(.gnu.linkonce.b.*)
+        *(COMMON)
+        . = ALIGN(16);
+        _ebss = ABSOLUTE(.);
+    }
+
+    _kernel_virtual_end = .;
+
+    _kernel_physical_end = (LOADADDR (.bss) + SIZEOF (.bss) + 0xFFF) & 
0xFFFFFFFFFFFFF000;
+
+    /* Stabs debugging sections */
+    .stab 0 : { *(.stab) }
+    .stabstr 0 : { *(.stabstr) }
+    .stab.excl 0 : { *(.stab.excl) }
+    .stab.exclstr 0 : { *(.stab.exclstr) }
+    .stab.index 0 : { *(.stab.index) }
+    .stab.indexstr 0 : { *(.stab.indexstr) }
+    .comment 0 : { *(.comment) }
+    .debug_abbrev 0 : { *(.debug_abbrev) }
+    .debug_info 0 : { *(.debug_info) }
+    .debug_line 0 : { *(.debug_line) }
+    .debug_pubnames 0 : { *(.debug_pubnames) }
+    .debug_aranges 0 : { *(.debug_aranges) }
+}


Reply via email to