From be9fc59b079e522caffb41a9be273908d1d5e460 Mon Sep 17 00:00:00 2001 From: Gustavo Henrique Nihei Date: Wed, 11 May 2022 18:53:07 -0300 Subject: [PATCH] xtensa: Implement syscalls required for Protected Mode Signed-off-by: Gustavo Henrique Nihei --- arch/xtensa/include/irq.h | 17 + arch/xtensa/include/syscall.h | 3 - arch/xtensa/src/Makefile | 52 +++- arch/xtensa/src/common/xtensa.h | 6 + .../src/common/xtensa_dispatch_syscall.S | 104 +++++++ arch/xtensa/src/common/xtensa_pthread_start.c | 76 +++++ .../src/common/xtensa_signal_dispatch.c | 75 +++++ .../xtensa/src/common/xtensa_signal_handler.S | 86 ++++++ arch/xtensa/src/common/xtensa_swint.c | 291 ++++++++++++++++-- arch/xtensa/src/common/xtensa_task_start.c | 73 +++++ 10 files changed, 745 insertions(+), 38 deletions(-) create mode 100644 arch/xtensa/src/common/xtensa_dispatch_syscall.S create mode 100644 arch/xtensa/src/common/xtensa_pthread_start.c create mode 100644 arch/xtensa/src/common/xtensa_signal_dispatch.c create mode 100644 arch/xtensa/src/common/xtensa_signal_handler.S create mode 100644 arch/xtensa/src/common/xtensa_task_start.c diff --git a/arch/xtensa/include/irq.h b/arch/xtensa/include/irq.h index 3d4836ef88..8c4fdc8476 100644 --- a/arch/xtensa/include/irq.h +++ b/arch/xtensa/include/irq.h @@ -144,6 +144,15 @@ #ifndef __ASSEMBLY__ +#ifdef CONFIG_LIB_SYSCALL +/* This structure represents the return state from a system call */ + +struct xcpt_syscall_s +{ + uintptr_t sysreturn; /* The return PC */ +}; +#endif + /* This struct defines the way the registers are stored. */ struct xcptcontext @@ -168,6 +177,14 @@ struct xcptcontext uint32_t *regs; +#ifndef CONFIG_BUILD_FLAT + /* This is the saved address to use when returning from a user-space + * signal handler. + */ + + uintptr_t sigreturn; +#endif + #ifdef CONFIG_LIB_SYSCALL /* The following array holds the return address and the exc_return value * needed to return from each nested system call. diff --git a/arch/xtensa/include/syscall.h b/arch/xtensa/include/syscall.h index e93fb6f545..e05e2fb5f6 100644 --- a/arch/xtensa/include/syscall.h +++ b/arch/xtensa/include/syscall.h @@ -34,9 +34,6 @@ #ifndef __ASSEMBLY__ # include #endif -#ifdef CONFIG_LIB_SYSCALL -# include -#endif #include #include diff --git a/arch/xtensa/src/Makefile b/arch/xtensa/src/Makefile index b261df3ea7..b228c59eaf 100644 --- a/arch/xtensa/src/Makefile +++ b/arch/xtensa/src/Makefile @@ -53,6 +53,8 @@ HEAD_AOBJ = $(HEAD_ASRC:.S=$(OBJEXT)) HEAD_COBJ = $(HEAD_CSRC:.c=$(OBJEXT)) STARTUP_OBJS ?= $(HEAD_AOBJ) $(HEAD_COBJ) +# Flat build or kernel-mode objects + ASRCS = $(CHIP_ASRCS) $(CMN_ASRCS) AOBJS = $(ASRCS:.S=$(OBJEXT)) @@ -62,12 +64,34 @@ COBJS = $(CSRCS:.c=$(OBJEXT)) SRCS = $(ASRCS) $(CSRCS) OBJS = $(AOBJS) $(COBJS) +# User-mode objects + +UASRCS = $(CHIP_UASRCS) $(CMN_UASRCS) +UAOBJS = $(UASRCS:.S=$(OBJEXT)) + +UCSRCS = $(CHIP_UCSRCS) $(CMN_UCSRCS) +UCOBJS = $(UCSRCS:.c=$(OBJEXT)) + +USRCS = $(UASRCS) $(UCSRCS) +UOBJS = $(UAOBJS) $(UCOBJS) + +KBIN = libkarch$(LIBEXT) +BIN = libarch$(LIBEXT) + # Override in Make.defs if linker is not 'ld' -LDSTARTGROUP ?= --start-group -LDENDGROUP ?= --end-group LDFLAGS += $(addprefix -T,$(call CONVERT_PATH,$(ARCHSCRIPT))) $(EXTRALINKCMDS) +ifeq ($(LD),$(CC)) + LDSTARTGROUP ?= -Wl,--start-group + LDENDGROUP ?= -Wl,--end-group + LDFLAGS := $(addprefix -Xlinker ,$(LDFLAGS)) + LDFLAGS += $(CFLAGS) +else + LDSTARTGROUP ?= --start-group + LDENDGROUP ?= --end-group +endif + BOARDMAKE = $(if $(wildcard board$(DELIM)Makefile),y,) LIBPATHS += -L $(call CONVERT_PATH,$(TOPDIR)$(DELIM)staging) @@ -80,19 +104,30 @@ ifeq ($(BOARDMAKE),y) LDLIBS += -lboard endif -VPATH = chip:common:$(ARCH_SUBDIR) +VPATH += chip +VPATH += common +VPATH += $(ARCH_SUBDIR) +VPATH += $(CHIP_DIR) all: $(STARTUP_OBJS) libarch$(LIBEXT) .PHONY: board/libboard$(LIBEXT) -$(AOBJS) $(HEAD_AOBJ): %$(OBJEXT): %.S +$(AOBJS) $(UAOBJS) $(HEAD_AOBJ): %$(OBJEXT): %.S $(call ASSEMBLE, $<, $@) -$(COBJS) $(HEAD_COBJ): %$(OBJEXT): %.c +$(COBJS) $(UCOBJS) $(HEAD_COBJ): %$(OBJEXT): %.c $(call COMPILE, $<, $@) -libarch$(LIBEXT): $(OBJS) +ifeq ($(CONFIG_BUILD_FLAT),y) +$(BIN): $(OBJS) + $(call ARCHIVE, $@, $(OBJS)) +else +$(BIN): $(UOBJS) + $(call ARCHIVE, $@, $(UOBJS)) +endif + +$(KBIN): $(OBJS) $(call ARCHIVE, $@, $(OBJS)) board/libboard$(LIBEXT): @@ -147,7 +182,7 @@ makedepfile: $(CSRCS:.c=.ddc) $(ASRCS:.S=.dds) $(HEAD_CSRC:.c=.ddc) $(HEAD_ASRC: ifeq ($(BOARDMAKE),y) $(Q) $(MAKE) -C board depend endif - $(Q) $(MAKE) makedepfile DEPPATH="--dep-path chip --dep-path common --dep-path $(ARCH_SUBDIR)" + $(Q) $(MAKE) makedepfile DEPPATH="$(patsubst %,--dep-path %,$(subst :, ,$(VPATH)))" $(Q) touch $@ depend: .depend @@ -158,7 +193,8 @@ clean: ifeq ($(BOARDMAKE),y) $(Q) $(MAKE) -C board clean endif - $(call DELFILE, libarch$(LIBEXT)) + $(call DELFILE, $(KBIN)) + $(call DELFILE, $(BIN)) $(call CLEAN) distclean:: clean diff --git a/arch/xtensa/src/common/xtensa.h b/arch/xtensa/src/common/xtensa.h index 394fbbba81..16e59f6e84 100644 --- a/arch/xtensa/src/common/xtensa.h +++ b/arch/xtensa/src/common/xtensa.h @@ -289,6 +289,12 @@ void xtensa_pause_handler(void); void _xtensa_sig_trampoline(void); void xtensa_sig_deliver(void); +#ifdef CONFIG_LIB_SYSCALL +void xtensa_dispatch_syscall(unsigned int nbr, uintptr_t parm1, + uintptr_t parm2, uintptr_t parm3, + uintptr_t parm4, uintptr_t parm5); +#endif + /* Chip-specific functions **************************************************/ /* Chip specific functions defined in arch/xtensa/src/ */ diff --git a/arch/xtensa/src/common/xtensa_dispatch_syscall.S b/arch/xtensa/src/common/xtensa_dispatch_syscall.S new file mode 100644 index 0000000000..4af48cb21b --- /dev/null +++ b/arch/xtensa/src/common/xtensa_dispatch_syscall.S @@ -0,0 +1,104 @@ +/**************************************************************************** + * arch/xtensa/src/common/xtensa_dispatch_syscall.S + * + * 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 + +#include +#include + +#ifdef CONFIG_LIB_SYSCALL + +/**************************************************************************** + * File info + ****************************************************************************/ + + .file "xtensa_dispatch_syscall.S" + +/**************************************************************************** + * Private Functions + ****************************************************************************/ + +/**************************************************************************** + * Public Functions + ****************************************************************************/ + +/**************************************************************************** + * Name: xtensa_dispatch_syscall + * + * Description: + * Call the stub function corresponding to the system call. NOTE the non- + * standard parameter passing: + * + * A2 = SYS_ call number + * A3 = parm0 + * A4 = parm1 + * A5 = parm2 + * A6 = parm3 + * A7 = parm4 + * A8 = parm5 + * + ****************************************************************************/ + + .text + .global xtensa_dispatch_syscall + .type xtensa_dispatch_syscall, @function + .align 4 + +xtensa_dispatch_syscall: + /* Allocate parm5 in stack */ + + s32i a8, sp, LOCAL_OFFSET(0) + + mov a11, a7 /* Move parm4 into callee's a7 */ + mov a10, a6 /* Move parm3 into callee's a6 */ + mov a9, a5 /* Move parm2 into callee's a5 */ + mov a8, a4 /* Move parm1 into callee's a4 */ + mov a7, a3 /* Move parm0 into callee's a3 */ + mov a6, a2 /* Move SYS_ call number into callee's a2 */ + + /* Load the stub address into A3 */ + + movi a3, g_stublookup + slli a2, a2, 2 + add a3, a3, a2 + l32i a3, a3, 0 + + /* Call the stub */ + + callx4 a3 + + /* Move into A3 the return value from the stub */ + + mov a3, a6 + + /* Execute the SYS_signal_handler_return syscall (will not return) */ + + movi a2, SYS_syscall_return + movi a4, XCHAL_SWINT_CALL + wsr a4, INTSET + rsync + + .size xtensa_dispatch_syscall, .-xtensa_dispatch_syscall + +#endif /* CONFIG_LIB_SYSCALL */ diff --git a/arch/xtensa/src/common/xtensa_pthread_start.c b/arch/xtensa/src/common/xtensa_pthread_start.c new file mode 100644 index 0000000000..ed4779c87f --- /dev/null +++ b/arch/xtensa/src/common/xtensa_pthread_start.c @@ -0,0 +1,76 @@ +/**************************************************************************** + * arch/xtensa/src/common/xtensa_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 + +#include +#include + +#include +#include + +#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/xtensa/src/common/xtensa_signal_dispatch.c b/arch/xtensa/src/common/xtensa_signal_dispatch.c new file mode 100644 index 0000000000..5be4e0a204 --- /dev/null +++ b/arch/xtensa/src/common/xtensa_signal_dispatch.c @@ -0,0 +1,75 @@ +/**************************************************************************** + * arch/xtensa/src/common/xtensa_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 + +#include + +#include + +#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/xtensa/src/common/xtensa_signal_handler.c. 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/xtensa/src/common/xtensa_signal_handler.S b/arch/xtensa/src/common/xtensa_signal_handler.S new file mode 100644 index 0000000000..bdd69543c8 --- /dev/null +++ b/arch/xtensa/src/common/xtensa_signal_handler.S @@ -0,0 +1,86 @@ +/**************************************************************************** + * arch/xtensa/src/common/xtensa_signal_handler.S + * + * 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 + +#include + +#if defined(CONFIG_BUILD_PROTECTED) && !defined(__KERNEL__) + +/**************************************************************************** + * File info + ****************************************************************************/ + + .file "xtensa_signal_handler.S" + +/**************************************************************************** + * Private Functions + ****************************************************************************/ + +/**************************************************************************** + * Public 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. + * + * Input Parameters: + * a2 = sighand + * The address user-space signal handling function + * a3-a5 = 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 the SYS_signal_handler_return (see syscall.h) + * + ****************************************************************************/ + + .text + .global up_signal_handler + .type up_signal_handler, @function + .align 4 + +up_signal_handler: + /* Call the signal handler */ + + mov a6, a3 /* Move signo into callee's a2 */ + mov a7, a4 /* Move info into callee's a3 */ + mov a8, a5 /* Move ucontext into callee's a4 */ + callx4 a2 /* Call the signal handler */ + + /* Execute the SYS_signal_handler_return syscall (will not return) */ + + movi a2, SYS_signal_handler_return + movi a3, XCHAL_SWINT_CALL + wsr a3, INTSET + rsync + + .size up_signal_handler, .-up_signal_handler + +#endif /* CONFIG_BUILD_PROTECTED && !__KERNEL__ */ diff --git a/arch/xtensa/src/common/xtensa_swint.c b/arch/xtensa/src/common/xtensa_swint.c index 8d1715739d..731bf804c3 100644 --- a/arch/xtensa/src/common/xtensa_swint.c +++ b/arch/xtensa/src/common/xtensa_swint.c @@ -30,10 +30,33 @@ #include #include +#include +#include "signal/signal.h" #include "syscall.h" #include "xtensa.h" +/**************************************************************************** + * Private Functions + ****************************************************************************/ + +/**************************************************************************** + * Name: xtensa_registerdump + ****************************************************************************/ + +#ifdef CONFIG_DEBUG_SYSCALL_INFO +static void xtensa_registerdump(const uintptr_t *regs) +{ + svcinfo(" A0: %08x %08x %08x %08x %08x %08x %08x %08x\n", + regs[REG_A0], regs[REG_A1], regs[REG_A2], regs[REG_A3], + regs[REG_A4], regs[REG_A5], regs[REG_A6], regs[REG_A7]); + svcinfo(" A8: %08x %08x %08x %08x %08x %08x %08x %08x\n", + regs[REG_A8], regs[REG_A9], regs[REG_A10], regs[REG_A11], + regs[REG_A12], regs[REG_A13], regs[REG_A14], regs[REG_A15]); + svcinfo(" PC: %08x PS: %08x\n", regs[REG_PC], regs[REG_PS]); +} +#endif + /**************************************************************************** * Public Functions ****************************************************************************/ @@ -52,10 +75,11 @@ int xtensa_swint(int irq, void *context, void *arg) uint32_t *regs = (uint32_t *)context; uint32_t cmd; - DEBUGASSERT(regs && regs == CURRENT_REGS); + DEBUGASSERT(regs != NULL && regs == CURRENT_REGS); + cmd = regs[REG_A2]; - /* The SYSCall software interrupt is called with A2 = system call command + /* The syscall software interrupt is called with A2 = system call command * and A3..A9 = variable number of arguments depending on the system call. */ @@ -65,18 +89,11 @@ int xtensa_swint(int irq, void *context, void *arg) # endif { svcinfo("SYSCALL Entry: regs: %p cmd: %d\n", regs, cmd); - svcinfo(" A0: %08x %08x %08x %08x %08x %08x %08x %08x\n", - regs[REG_A0], regs[REG_A1], regs[REG_A2], regs[REG_A3], - regs[REG_A4], regs[REG_A5], regs[REG_A6], regs[REG_A7]); - svcinfo(" A8: %08x %08x %08x %08x %08x %08x %08x %08x\n", - regs[REG_A8], regs[REG_A9], regs[REG_A10], regs[REG_A11], - regs[REG_A12], regs[REG_A13], regs[REG_A14], regs[REG_A15]); - svcinfo(" PC: %08x PS: %08x\n", - regs[REG_PC], regs[REG_PS]); + xtensa_registerdump(regs); } #endif - /* Handle the SYSCall according to the command in A2 */ + /* Handle the syscall according to the command in A2 */ switch (cmd) { @@ -98,7 +115,6 @@ int xtensa_swint(int irq, void *context, void *arg) DEBUGASSERT(regs[REG_A3] != 0); memcpy((uint32_t *)regs[REG_A3], regs, XCPTCONTEXT_SIZE); } - break; /* A2=SYS_restore_context: This is a restore context command: @@ -123,7 +139,6 @@ int xtensa_swint(int irq, void *context, void *arg) DEBUGASSERT(regs[REG_A3] != 0); CURRENT_REGS = (uint32_t *)regs[REG_A3]; } - break; /* A2=SYS_switch_context: This is a switch context command: @@ -149,7 +164,240 @@ int xtensa_swint(int irq, void *context, void *arg) *(uint32_t **)regs[REG_A3] = regs; CURRENT_REGS = (uint32_t *)regs[REG_A4]; } + break; + /* A2=SYS_syscall_return: This is a syscall return command: + * + * void up_syscall_return(void); + * + * At this point, the following values are saved in context: + * + * A2 = SYS_syscall_return + * + * We need to restore the saved return address and return in + * unprivileged thread mode. + */ + +#ifdef CONFIG_LIB_SYSCALL + case SYS_syscall_return: + { + struct tcb_s *rtcb = nxsched_self(); + int index = (int)rtcb->xcp.nsyscalls - 1; + + /* Make sure that there is a saved syscall return address. */ + + DEBUGASSERT(index >= 0); + + /* Setup to return to the saved syscall return address in + * the original mode. + */ + + regs[REG_PC] = rtcb->xcp.syscall[index].sysreturn; + + /* The return value must be in A2-A5. + * xtensa_dispatch_syscall() temporarily moved the value into A3. + */ + + regs[REG_A2] = regs[REG_A3]; + + /* Save the new syscall nesting level */ + + rtcb->xcp.nsyscalls = index; + + /* Handle any signal actions that were deferred while processing + * the system call. + */ + + rtcb->flags &= ~TCB_FLAG_SYSCALL; + nxsig_unmask_pendingsignal(); + } + break; +#endif + + /* A2=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: + * + * A2 = SYS_task_start + * A3 = taskentry + * A4 = argc + * A5 = argv + */ + +#ifndef CONFIG_BUILD_FLAT + case SYS_task_start: + { + /* Set up to return to the user-space task start-up function in + * unprivileged mode. + */ + +#ifdef CONFIG_BUILD_PROTECTED + /* Use the nxtask_startup trampoline function */ + + regs[REG_PC] = (uintptr_t)USERSPACE->task_startup; + regs[REG_A6] = regs[REG_A3]; /* Task entry */ + regs[REG_A7] = regs[REG_A4]; /* argc */ + regs[REG_A8] = regs[REG_A5]; /* argv */ +#else + /* Start the user task directly */ + + regs[REG_PC] = (uintptr_t)regs[REG_A3]; + regs[REG_A6] = regs[REG_A4]; /* argc */ + regs[REG_A7] = regs[REG_A5]; /* argv */ +#endif + + /* User task rotates window, so pretend task was 'call4'd */ + + regs[REG_PS] = PS_UM | PS_WOE | PS_CALLINC(1); + } + break; +#endif + + /* A2=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: + * + * A2 = SYS_pthread_start + * A3 = startup + * A4 = entrypt + * A5 = arg + */ + +#if !defined(CONFIG_BUILD_FLAT) && !defined(CONFIG_DISABLE_PTHREAD) + case SYS_pthread_start: + { + /* Set up to return to the user-space pthread start-up function in + * unprivileged mode. + */ + + regs[REG_PC] = (uintptr_t)regs[REG_A3]; /* startup */ + + /* Change the parameter ordering to match the expectation of the + * user space pthread_startup: + */ + + regs[REG_A6] = regs[REG_A4]; /* pthread entry */ + regs[REG_A7] = regs[REG_A5]; /* arg */ + + /* Startup task rotates window, so pretend task was 'call4'd */ + + regs[REG_PS] = PS_UM | PS_WOE | PS_CALLINC(1); + } + break; +#endif + + /* A2=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: + * + * A2 = SYS_signal_handler + * A3 = sighand + * A4 = signo + * A5 = info + * A6 = ucontext + */ + +#ifndef CONFIG_BUILD_FLAT + 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_PC]; + + /* Set up to return to the user-space trampoline function in + * unprivileged mode. + */ + + regs[REG_PC] = (uintptr_t)USERSPACE->signal_handler; + + /* Change the parameter ordering to match the expectation of struct + * userpace_s signal_handler. + */ + + regs[REG_A2] = regs[REG_A3]; /* sighand */ + regs[REG_A3] = regs[REG_A4]; /* signal */ + regs[REG_A4] = regs[REG_A5]; /* info */ + regs[REG_A5] = regs[REG_A6]; /* ucontext */ + } + break; +#endif + + /* A2=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: + * + * A2 = SYS_signal_handler_return + */ + +#ifndef CONFIG_BUILD_FLAT + case SYS_signal_handler_return: + { + struct tcb_s *rtcb = nxsched_self(); + + /* Set up to return to the kernel-mode signal dispatching logic. */ + + DEBUGASSERT(rtcb->xcp.sigreturn != 0); + regs[REG_PC] = rtcb->xcp.sigreturn; + + rtcb->xcp.sigreturn = 0; + } + break; +#endif + + /* 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 default case. + */ + + default: + { +#ifdef CONFIG_LIB_SYSCALL + struct tcb_s *rtcb = nxsched_self(); + int index = rtcb->xcp.nsyscalls; + + /* Verify that the syscall number is within range */ + + DEBUGASSERT(cmd < SYS_maxsyscall); + + /* Make sure that we got here that there is a no saved syscall + * return address. We cannot yet handle nested system calls. + */ + + DEBUGASSERT(index < CONFIG_SYS_NNEST); + + /* Setup to return to xtensa_dispatch_syscall in privileged mode. */ + + rtcb->xcp.syscall[index].sysreturn = regs[REG_PC]; + + rtcb->xcp.nsyscalls = index + 1; + + regs[REG_PC] = (uintptr_t)xtensa_dispatch_syscall; + + /* Offset A2 to account for the reserved values */ + + regs[REG_A2] -= CONFIG_SYS_RESERVED; + + /* Indicate that we are in a syscall handler. */ + + rtcb->flags |= TCB_FLAG_SYSCALL; +#else + svcerr("ERROR: Bad SYSCALL: %" PRIu32 "\n", cmd); +#endif + } break; /* A2=SYS_flush_context: This flush windows to the stack: @@ -186,24 +434,13 @@ int xtensa_swint(int irq, void *context, void *arg) if (regs != CURRENT_REGS) # endif { - svcinfo("SYSCall Return:\n"); - svcinfo(" A0: %08x %08x %08x %08x %08x %08x %08x %08x\n", - CURRENT_REGS[REG_A0], CURRENT_REGS[REG_A1], - CURRENT_REGS[REG_A2], CURRENT_REGS[REG_A3], - CURRENT_REGS[REG_A4], CURRENT_REGS[REG_A5], - CURRENT_REGS[REG_A6], CURRENT_REGS[REG_A7]); - svcinfo(" R8: %08x %08x %08x %08x %08x %08x %08x %08x\n", - CURRENT_REGS[REG_A8], CURRENT_REGS[REG_A9], - CURRENT_REGS[REG_A10], CURRENT_REGS[REG_A11], - CURRENT_REGS[REG_A12], CURRENT_REGS[REG_A13], - CURRENT_REGS[REG_A14], CURRENT_REGS[REG_A15]); - svcinfo(" PC: %08x PS: %08x\n", - regs[REG_PC], regs[REG_PS]); + svcinfo("SYSCALL Return: Context switch!\n"); + xtensa_registerdump((const uintptr_t *)CURRENT_REGS); } # ifdef CONFIG_DEBUG_SYSCALL else { - svcinfo("SYSCall Return: %d\n", regs[REG_A2]); + svcinfo("SYSCALL Return: %" PRIu32 "\n", cmd); } # endif #endif diff --git a/arch/xtensa/src/common/xtensa_task_start.c b/arch/xtensa/src/common/xtensa_task_start.c new file mode 100644 index 0000000000..e06d42ae26 --- /dev/null +++ b/arch/xtensa/src/common/xtensa_task_start.c @@ -0,0 +1,73 @@ +/**************************************************************************** + * arch/xtensa/src/common/xtensa_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 + +#include + +#include +#include + +#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 */