arch/x86_64: add kernel build support

arch/x86_64: add kernel build support

Signed-off-by: p-szafonimateusz <p-szafonimateusz@xiaomi.com>
This commit is contained in:
p-szafonimateusz 2024-07-20 11:59:00 +02:00 committed by Alan C. Assis
parent 8702fbef8d
commit 712e8d9cc7
19 changed files with 959 additions and 19 deletions

View file

@ -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---

View file

@ -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.
*/

View file

@ -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

View file

@ -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)

View file

@ -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

View file

@ -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

View file

@ -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 */

View file

@ -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
*

View file

@ -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;

View file

@ -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 */

View file

@ -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 */

View file

@ -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__ */

View file

@ -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

View file

@ -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 */

View file

@ -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

View file

@ -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.
*/

View file

@ -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;
}
/****************************************************************************

View file

@ -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
ifeq ($(CONFIG_BUILD_KERNEL),y)
ARCHSCRIPT += $(BOARD_DIR)$(DELIM)scripts$(DELIM)qemu-kernel.ld
else
ARCHSCRIPT += $(BOARD_DIR)$(DELIM)scripts$(DELIM)qemu.ld
endif

View file

@ -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) }
}