mirror of
https://github.com/apache/nuttx.git
synced 2025-01-13 02:48:37 +08:00
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:
parent
8702fbef8d
commit
712e8d9cc7
19 changed files with 959 additions and 19 deletions
|
@ -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---
|
||||
|
|
|
@ -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.
|
||||
*/
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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)
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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
|
||||
|
|
121
arch/x86_64/src/common/crt0.c
Normal file
121
arch/x86_64/src/common/crt0.c
Normal 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 */
|
|
@ -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
|
||||
*
|
||||
|
|
|
@ -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;
|
||||
|
|
232
arch/x86_64/src/common/x86_64_pgalloc.c
Normal file
232
arch/x86_64/src/common/x86_64_pgalloc.c
Normal 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 */
|
77
arch/x86_64/src/common/x86_64_pthread_start.c
Normal file
77
arch/x86_64/src/common/x86_64_pthread_start.c
Normal 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 */
|
76
arch/x86_64/src/common/x86_64_signal_dispatch.c
Normal file
76
arch/x86_64/src/common/x86_64_signal_dispatch.c
Normal 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__ */
|
|
@ -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
|
||||
|
|
74
arch/x86_64/src/common/x86_64_task_start.c
Normal file
74
arch/x86_64/src/common/x86_64_task_start.c
Normal 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 */
|
|
@ -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
|
||||
|
|
|
@ -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.
|
||||
*/
|
||||
|
|
|
@ -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;
|
||||
}
|
||||
|
||||
/****************************************************************************
|
||||
|
|
|
@ -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
|
||||
|
|
130
boards/x86_64/intel64/qemu-intel64/scripts/qemu-kernel.ld
Normal file
130
boards/x86_64/intel64/qemu-intel64/scripts/qemu-kernel.ld
Normal 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) }
|
||||
}
|
Loading…
Reference in a new issue