diff --git a/arch/xtensa/include/irq.h b/arch/xtensa/include/irq.h index 8960754da2c..4eece4c34bf 100644 --- a/arch/xtensa/include/irq.h +++ b/arch/xtensa/include/irq.h @@ -157,7 +157,6 @@ struct xcptcontext /* These are saved copies of registers used during signal processing. */ uint32_t saved_pc; - uint32_t saved_cpsr; #endif /* Register save area */ diff --git a/arch/xtensa/src/common/xtensa.h b/arch/xtensa/src/common/xtensa.h index 7f193ab97c4..063edbe4735 100644 --- a/arch/xtensa/src/common/xtensa.h +++ b/arch/xtensa/src/common/xtensa.h @@ -248,15 +248,15 @@ void xtensa_dumpstate(void); uint32_t *xtensa_int_decode(uint32_t *regs); uint32_t *xtensa_irq_dispatch(int irq, uint32_t *regs); -void xtensa_context_save(uint32_t *regs); -void xtensa_full_context_save(uint32_t *regs); -void xtensa_context_restore(uint32_t *regs); -void xtensa_full_context_restore(uint32_t *regs); - /* Software interrupt handler */ int xtensa_swint(int irq, FAR void *context); +/* Synchronous context switching */ + +int xtensa_context_save(uint32_t *regs); +int xtensa_context_restore(uint32_t *regs); + /* Signals */ void xtensa_sigdeliver(void); diff --git a/arch/xtensa/src/common/xtensa_blocktask.c b/arch/xtensa/src/common/xtensa_blocktask.c new file mode 100644 index 00000000000..82eb5e30c9d --- /dev/null +++ b/arch/xtensa/src/common/xtensa_blocktask.c @@ -0,0 +1,175 @@ +/**************************************************************************** + * arch/xtensa/src/common/xtensa_blocktask.c + * + * Copyright (C) 2016 Gregory Nutt. All rights reserved. + * Author: Gregory Nutt + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in + * the documentation and/or other materials provided with the + * distribution. + * 3. Neither the name NuttX nor the names of its contributors may be + * used to endorse or promote products derived from this software + * without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS + * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE + * COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, + * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, + * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS + * OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED + * AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN + * ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE + * POSSIBILITY OF SUCH DAMAGE. + * + ****************************************************************************/ + +/**************************************************************************** + * Included Files + ****************************************************************************/ + +#include + +#include +#include +#include + +#include +#include + +#include "sched/sched.h" +#include "group/group.h" +#include "xtensa.h" + +/**************************************************************************** + * Public Functions + ****************************************************************************/ + +/**************************************************************************** + * Name: up_block_task + * + * Description: + * The currently executing task at the head of + * the ready to run list must be stopped. Save its context + * and move it to the inactive list specified by task_state. + * + * Inputs: + * tcb: Refers to a task in the ready-to-run list (normally + * the task at the head of the list). It most be + * stopped, its context saved and moved into one of the + * waiting task lists. It it was the task at the head + * of the ready-to-run list, then a context to the new + * ready to run task must be performed. + * task_state: Specifies which waiting task list should be + * hold the blocked task TCB. + * + ****************************************************************************/ + +void up_block_task(struct tcb_s *tcb, tstate_t task_state) +{ + struct tcb_s *rtcb = this_task(); + bool switch_needed; + + /* Verify that the context switch can be performed */ + + ASSERT((tcb->task_state >= FIRST_READY_TO_RUN_STATE) && + (tcb->task_state <= LAST_READY_TO_RUN_STATE)); + + /* Remove the tcb task from the ready-to-run list. If we + * are blocking the task at the head of the task list (the + * most likely case), then a context switch to the next + * ready-to-run task is needed. In this case, it should + * also be true that rtcb == tcb. + */ + + switch_needed = sched_removereadytorun(tcb); + + /* Add the task to the specified blocked task list */ + + sched_addblocked(tcb, (tstate_t)task_state); + + /* If there are any pending tasks, then add them to the ready-to-run + * task list now + */ + + if (g_pendingtasks.head) + { + switch_needed |= sched_mergepending(); + } + + /* Now, perform the context switch if one is needed */ + + if (switch_needed) + { + /* Update scheduler parameters */ + + sched_suspend_scheduler(rtcb); + + /* Are we in an interrupt handler? */ + + if (CURRENT_REGS) + { + /* Yes, then we have to do things differently. + * Just copy the CURRENT_REGS into the OLD rtcb. + */ + + xtensa_savestate(rtcb->xcp.regs); + + /* Restore the exception context of the rtcb at the (new) head + * of the ready-to-run task list. + */ + + rtcb = this_task(); + + /* Reset scheduler parameters */ + + sched_resume_scheduler(rtcb); + + /* Then switch contexts. Any necessary address environment + * changes will be made when the interrupt returns. + */ + + xtensa_restorestate(rtcb->xcp.regs); + } + + /* Copy the user C context into the TCB at the (old) head of the + * ready-to-run Task list. if up_saveusercontext returns a non-zero + * value, then this is really the previously running task restarting! + */ + + else if (!xtensa_context_save(rtcb->xcp.regs)) + { + /* Restore the exception context of the rtcb at the (new) head + * of the ready-to-run task list. + */ + + rtcb = this_task(); + +#ifdef CONFIG_ARCH_ADDRENV + /* Make sure that the address environment for the previously + * running task is closed down gracefully (data caches dump, + * MMU flushed) and set up the address environment for the new + * thread at the head of the ready-to-run list. + */ + + (void)group_addrenv(rtcb); +#endif + /* Reset scheduler parameters */ + + sched_resume_scheduler(rtcb); + + /* Then switch contexts */ + + xtensa_context_restore(rtcb->xcp.regs); + } + } +} diff --git a/arch/xtensa/src/common/xtensa_context.S b/arch/xtensa/src/common/xtensa_context.S index b1e7714d473..840620b4e52 100644 --- a/arch/xtensa/src/common/xtensa_context.S +++ b/arch/xtensa/src/common/xtensa_context.S @@ -76,95 +76,76 @@ .text /**************************************************************************** - * Name: xtensa_context_save - * xtensa_full_context_save + * Name: _xtensa_context_save * * Description: * * NOTE: MUST BE CALLED ONLY BY 'CALL0' INSTRUCTION! * - * These functions save Xtensa processor state: + * This function saves Xtensa processor state: xtensa_context_save + * saves all registers except PC, PS, A0, A1 (SP), and A2 * - * - xtensa_full_context_save saves all registers except PC, PS, A0, and - * A1 (SP) - * - xtensa_context_save, in addition, does not save A12-A15 which - * are preserved by the callee). + * This function is called directly by interrupt handling logic and from + * xtensa_context_save() below with interrupts disabled. In either calling + * context, caller saves saves PC, PS, A0, A1 (SP), and A2. This + * logic also executes indirectly from xtena_context_save() by falling + * through from above. * - * Caller is expected to have saved PC, PS, A0, and A1 (SP). - * - * The counterparts to these functions are xtensa_context_restore() and - * xtensa_full_context_restore(). + * The counterpart to this function is _xtensa_context_restore(). * * Entry Conditions: - * - A0 = Return address in caller. - * - A1 = Stack pointer of calling thread or interrupt handler. - * - Other processor state except PC, PS, A0, and A1 (SP) are as at + * - A0 = Return address to caller. + * - A2 = Pointer to the processor state save area + * - Other processor state except PC, PS, A0, A1 (SP), and A2 are as at * the point of interruption. - * - If windowed ABI, PS.EXCM = 1 (exceptions disabled). * - * Exit conditions: + * Exit conditions: * - A0 = Return address in caller. - * - A1 = Stack pointer of interrupted thread or handler ("interruptee"). - * - A12-A15 as at entry (preserved). + * - A2, A12-A15 as at entry (preserved). + * + * Assumptions: + * - Caller is expected to have saved PC, PS, A0, A1 (SP), and A2. * - If windowed ABI, PS.EXCM = 1 (exceptions disabled). * ****************************************************************************/ - .global xtensa_full_context_save - .global xtensa_context_save - .type xtensa_full_context_save, @function - .type xtensa_context_save, @function + .global _xtensa_context_save + .type _xtensa_context_save, @function .align 4 .literal_position .align 4 -xtensa_full_context_save: +_xtensa_context_save: -#ifndef CONFIG_XTENSA_CALL0_ABI - /* Save Call0 ABI callee-saved regs a12-15. */ + s32i a2, a2, (4 * REG_A2) + s32i a3, a2, (4 * REG_A3) + s32i a4, a2, (4 * REG_A4) + s32i a5, a2, (4 * REG_A5) + s32i a6, a2, (4 * REG_A6) + s32i a7, a2, (4 * REG_A7) + s32i a8, a2, (4 * REG_A8) + s32i a9, a2, (4 * REG_A9) + s32i a10, a2, (4 * REG_A10) + s32i a11, a2, (4 * REG_A11) - s32i a12, sp, (4 * REG_A12) - s32i a13, sp, (4 * REG_A13) - s32i a14, sp, (4 * REG_A14) - s32i a15, sp, (4 * REG_A15) -#endif + /* Call0 ABI callee-saved regs a12-15 */ -xtensa_context_save: - - s32i a2, sp, (4 * REG_A2) - s32i a3, sp, (4 * REG_A3) - s32i a4, sp, (4 * REG_A4) - s32i a5, sp, (4 * REG_A5) - s32i a6, sp, (4 * REG_A6) - s32i a7, sp, (4 * REG_A7) - s32i a8, sp, (4 * REG_A8) - s32i a9, sp, (4 * REG_A9) - s32i a10, sp, (4 * REG_A10) - s32i a11, sp, (4 * REG_A11) - - /* Call0 ABI callee-saved regs a12-15 do not need to be saved here. - * a12-13 are the caller's responsibility so it can use them as scratch. - * So only need to save a14-a15 here for Windowed ABI (not Call0). - */ - -#ifndef CONFIG_XTENSA_CALL0_ABI - s32i a12, sp, (4 * REG_A12) - s32i a13, sp, (4 * REG_A13) - s32i a14, sp, (4 * REG_A14) - s32i a15, sp, (4 * REG_A15) -#endif + s32i a12, a2, (4 * REG_A12) + s32i a13, a2, (4 * REG_A13) + s32i a14, a2, (4 * REG_A14) + s32i a15, a2, (4 * REG_A15) rsr a3, SAR - s32i a3, sp, (4 * REG_SAR) + s32i a3, a2, (4 * REG_SAR) #ifdef XTENSA_HAVE_LOOPS rsr a3, LBEG - s32i a3, sp, (4 * REG_LBEG) + s32i a3, a2, (4 * REG_LBEG) rsr a3, LEND - s32i a3, sp, (4 * REG_LEND) + s32i a3, a2, (4 * REG_LEND) rsr a3, LCOUNT - s32i a3, sp, (4 * REG_LCOUNT) + s32i a3, a2, (4 * REG_LCOUNT) #endif #ifdef CONFIG_XTENSA_USE_SWPRI @@ -172,7 +153,7 @@ xtensa_context_save: movi a3, _xtensa_vprimask l32i a3, a3, 0 - s32i a3, sp, (4 * REG_VPRI) + s32i a3, a2, (4 * REG_VPRI) #endif #if XTENSA_EXTRA_SA_SIZE > 0 || !defined(CONFIG_XTENSA_CALL0_ABI) @@ -187,9 +168,9 @@ xtensa_context_save: * disabled (assured by PS.EXCM == 1). */ - s32i a12, sp, (4 * REG_TMP0) /* Temp. save stuff in stack frame */ - s32i a13, sp, (4 * REG_TMP1) - s32i a9, sp, (4 * REG_TMP2) + s32i a12, a2, (4 * REG_TMP0) /* Temp. save stuff in stack frame */ + s32i a13, a2, (4 * REG_TMP1) + s32i a9, a2, (4 * REG_TMP2) /* Save the overlay state if we are supporting overlays. Since we just * saved three registers, we can conveniently use them here. Note that @@ -197,14 +178,16 @@ xtensa_context_save: */ #ifdef CONFIG_XTENSA_USE_OVLY - l32i a9, sp, (4 * REG_PC) /* Recover saved PC */ + l32i a9, a2, (4 * REG_PC) /* Recover saved PC */ _xt_overlay_get_state a9, a12, a13 - s32i a9, sp, (4 * REG_OVLY) /* Save overlay state */ + s32i a9, a2, (4 * REG_OVLY) /* Save overlay state */ #endif - l32i a12, sp, (4 * REG_A12) /* Recover original a9,12,13 */ - l32i a13, sp, (4 * REG_A13) - l32i a9, sp, (4 * REG_A9) + l32i a12, a2, (4 * REG_A12) /* Recover original a9,12,13 */ + l32i a13, a2, (4 * REG_A13) + l32i a9, a2, (4 * REG_A9) + +#warning REVISIT: The following is probably not correct due to changes in registers addi sp, sp, (4 * XCPTCONTEXT_SIZE) /* Restore the interruptee's SP */ call0 xthal_window_spill_nw /* Preserves only a4,5,8,9,12,13 */ addi sp, sp, -(4 * XCPTCONTEXT_SIZE) @@ -223,7 +206,7 @@ xtensa_context_save: * Future Xtensa tools releases might limit the regs that can be affected. */ - addi a2, sp, (4 * REG_EXTRA) /* Where to save it */ + addi a2, a2, (4 * REG_EXTRA) /* Where to save it */ #if XTENSA_EXTRA_SA_ALIGN > 16 movi a3, -XTENSA_EXTRA_SA_ALIGN and a2, a2, a3 /* Align dynamically >16 bytes */ @@ -238,58 +221,99 @@ xtensa_context_save: ret /**************************************************************************** - * Name: xtensa_context_restore - * xtensa_full_context_restore + * Name: xtensa_context_save + * + * Description: + * + * NOTE: MUST BE CALLED ONLY BY 'CALL0' INSTRUCTION! + * + * This functions implements the moral equivalent of setjmp(). It is + * called from user code (with interrupts disabled) to save the current + * state of the running thread. This function always returns zero. + * However, it sets the saved value of the return address (A2) to 1. + * If the thread is restarted via _xtensa_contest_restore or + * xtensa_context_restore, it will appear as a second return from + * xtensa_context_save but with the returned value of 1 to distinguish + * the two cases. + * + * The counterpart to this function is xtensa_context_restore(). + * + * Entry Conditions: + * - A0 = Return address to caller. + * - A2 = Pointer to the processor state save area + * + * Exit conditions: + * - A0 = Return address in caller. + * - A2 = 0 + * + * Assumptions: + * - Interrupts are disabled. + * + ****************************************************************************/ + + .global xtensa_context_save + .type xtensa_context_save, @function + + .align 4 + .literal_position + .align 4 + +xtensa_context_save: + + /* Set up for call to _xtensa_context_save() */ + + rsr a12, EPS_2 /* Save callee's PS */ + s32i a12, a2, (4 * REG_PS) + s32i a0, a2, (4 * REG_PC) /* Save Return address as PC */ + + s32i a0, a2, (4 * REG_A0) /* Save callee's a0 */ + s32i sp, a2, (4 * REG_A1) /* Save callee's SP */ + movi a12, 1 /* Set saved A2 to 1 */ + s32i a12, a2, (4 * REG_A2) + + /* Save the rest of the processor state */ + + call0 _xtensa_context_save /* Save full register state */ + + /* Recover the return address and return zero */ + + l32i a0, a2, (4 * REG_A0) /* Recover return addess */ + movi a2, 0 /* Return zero */ + ret + +/**************************************************************************** + * Name: _xtensa_context_restore * * Description: * * NOTE: MUST BE CALLED ONLY BY 'CALL0' INSTRUCTION! * * These functions restores Xtensa processor state and differ in which - * registers are saved: + * registers are saved: _xtensa_context_restore() restores all registers + * except PC, PS, and A0 * - * - xtensa_full_context_restore restores all registers except PC, PS, - * A0, and A1 (SP) - * - xtensa_context_restore, in addition, does not restore A12-A15 which - * are preserved by the callee). + * The caller is responsible for restoring PC, PS, and A0 in both cases. * - * The caller is responsible for restoring PC, PS, A0, A1 (SP) in both cases. - * - * xtensa_context_save and xtensa_full_context_save are the counterparts - * to these functions. + * _xtensa_context_save is the counterpart to this function. * * Entry Conditions: * - A0 = Return address in caller. - * - A1 = Stack pointer of calling thread or interrupt handler. + * - A2 = Pointer to the processor state save area * * Exit conditions: * - A0 = Return address in caller. - * - A1 = Stack pointer of calling thread or interrupt handler. - * - Other registers are restored as detailed above. + * - Other registers are restored as detailed above (including A1 and A2). * ****************************************************************************/ - .global xtensa_full_context_restore - .global xtensa_context_restore - .type xtensa_full_context_restore,@function - .type xtensa_context_restore,@function + .global _xtensa_context_restore + .type _xtensa_context_restore,@function .align 4 .literal_position .align 4 -xtensa_full_context_restore: - -#ifndef CONFIG_XTENSA_CALL0_ABI - /* Restore Call0 ABI callee-saved regs a12-15. */ - - l32i a12, sp, (4 * REG_A12) - l32i a13, sp, (4 * REG_A13) - l32i a14, sp, (4 * REG_A14) - l32i a15, sp, (4 * REG_A15) -#endif - -xtensa_context_restore: +_xtensa_context_restore: #if XTENSA_EXTRA_SA_SIZE > 0 /* NOTE: Normally the xthal_restore_extra_nw macro only affects address @@ -302,7 +326,7 @@ xtensa_context_restore: */ mov a13, a0 /* Preserve ret addr */ - addi a2, sp, (4 * REG_EXTRA) /* Where to find it */ + addi a2, a2, (4 * REG_EXTRA) /* Where to find it */ #if XTENSA_EXTRA_SA_ALIGN > 16 movi a3, -XTENSA_EXTRA_SA_ALIGN @@ -313,10 +337,10 @@ xtensa_context_restore: #endif #ifdef XTENSA_HAVE_LOOPS - l32i a2, sp, (4 * REG_LBEG) - l32i a3, sp, (4 * REG_LEND) + l32i a2, a2, (4 * REG_LBEG) + l32i a3, a2, (4 * REG_LEND) wsr a2, LBEG - l32i a2, sp, (4 * REG_LCOUNT) + l32i a2, a2, (4 * REG_LCOUNT) wsr a3, LEND wsr a2, LCOUNT #endif @@ -329,13 +353,13 @@ xtensa_context_restore: * to be restored. */ - l32i a2, sp, (4 * REG_PC) /* Retrieve PC */ - l32i a3, sp, (4 * REG_PS) /* Retrieve PS */ - l32i a4, sp, (4 * REG_OVLY) /* Retrieve overlay state */ - l32i a5, sp, (4 * REG_A1) /* Retrieve stack ptr */ + l32i a2, a2, (4 * REG_PC) /* Retrieve PC */ + l32i a3, a2, (4 * REG_PS) /* Retrieve PS */ + l32i a4, a2, (4 * REG_OVLY) /* Retrieve overlay state */ + l32i a5, a2, (4 * REG_A1) /* Retrieve stack ptr */ _xt_overlay_check_map a2, a3, a4, a5, a6 - s32i a2, sp, (4 * REG_PC) /* Save updated PC */ - s32i a3, sp, (4 * REG_PS) /* Save updated PS */ + s32i a2, a2, (4 * REG_PC) /* Save updated PC */ + s32i a3, a2, (4 * REG_PS) /* Save updated PS */ #endif #ifdef CONFIG_XTENSA_USE_SWPRI @@ -343,35 +367,96 @@ xtensa_context_restore: movi a3, _xtensa_intdata l32i a4, a3, 0 /* a4 = _xtensa_intenable */ - l32i a5, sp, (4 * REG_VPRI) /* a5 = saved _xtensa_vprimask */ + l32i a5, a2, (4 * REG_VPRI) /* a5 = saved _xtensa_vprimask */ and a4, a4, a5 wsr a4, INTENABLE /* Update INTENABLE */ s32i a5, a3, 4 /* Restore _xtensa_vprimask */ #endif - l32i a3, sp, (4 * REG_SAR) - l32i a2, sp, (4 * REG_A2) + l32i a3, a2, (4 * REG_SAR) + l32i sp, a2, (4 * REG_A1) wsr a3, SAR - l32i a3, sp, (4 * REG_A3) - l32i a4, sp, (4 * REG_A4) - l32i a5, sp, (4 * REG_A5) - l32i a6, sp, (4 * REG_A6) - l32i a7, sp, (4 * REG_A7) - l32i a8, sp, (4 * REG_A8) - l32i a9, sp, (4 * REG_A9) - l32i a10, sp, (4 * REG_A10) - l32i a11, sp, (4 * REG_A11) + l32i a3, a2, (4 * REG_A3) + l32i a4, a2, (4 * REG_A4) + l32i a5, a2, (4 * REG_A5) + l32i a6, a2, (4 * REG_A6) + l32i a7, a2, (4 * REG_A7) + l32i a8, a2, (4 * REG_A8) + l32i a9, a2, (4 * REG_A9) + l32i a10, a2, (4 * REG_A10) + l32i a11, a2, (4 * REG_A11) - /* Call0 ABI callee-saved regs a12-15 do not need to be restored here. - * However a12-13 were saved for scratch before XT_RTOS_INT_ENTER(), - * so need to be restored anyway, despite being callee-saved in Call0. - */ + /* Call0 ABI callee-saved regs a12-15 */ -#ifndef CONFIG_XTENSA_CALL0_ABI - l32i a12, sp, (4 * REG_A12) - l32i a13, sp, (4 * REG_A13) - l32i a14, sp, (4 * REG_A14) - l32i a15, sp, (4 * REG_A15) -#endif + l32i a12, a2, (4 * REG_A12) + l32i a13, a2, (4 * REG_A13) + l32i a14, a2, (4 * REG_A14) + l32i a15, a2, (4 * REG_A15) + + /* Finally, restore A2 with the correct value */ + + l32i a2, a2, (4 * REG_A2) ret + +/**************************************************************************** + * Name: xtensa_context_restore + * + * Description: + * + * NOTE: MUST BE CALLED ONLY BY 'CALL0' INSTRUCTION! + * + * This functions implements the moral equivalent of longjmp(). It is + * called from user code (with interrupts disabled) to restor the current + * state of the running thread. This function always returns 1 because + * the saved value of A2 was set to 1 in xtensa_context_save(). + * + * The counterpart to this function is xtensa_context_save(). + * + * Entry Conditions: + * - A0 = Return address to caller. + * - A2 = Pointer to the processor state save area + * + * Exit conditions: + * - A0 = Return address in caller. + * - A2 = 1 + * + * NOTE: That this function does NOT return to the caller but rather + * to a new threading context. + * + * Assumptions: + * - Interrupts are disabled. + * + ****************************************************************************/ + + .global xtensa_context_restore + .type xtensa_context_restore, @function + + .align 4 + .literal_position + .align 4 + +xtensa_context_restore: + + /* Restore the processor state */ + + call0 _xtensa_context_restore /* Restore full register state */ + + /* Restore PC, PS, and A0. */ + + s32i a0, sp, (4 * REG_PS) + + rsr a12, EPS_2 /* Save callee's PS */ + s32i a12, sp, (4 * REG_PS) + s32i a0, a2, (4 * REG_PC) /* Save Return address as PC */ + + s32i a0, a2, (4 * REG_A0) /* Save callee's a0 */ + s32i sp, a2, (4 * REG_A1) /* Save callee's SP */ + movi a12, 1 /* Set saved A2 to 1 */ + s32i a12, a2, (4 * REG_A2) + + + l32i a0, a2, (4 * REG_A0) /* Recover return addess */ + movi a2, 0 /* Return zero */ + ret + diff --git a/arch/xtensa/src/common/xtensa_copystate.c b/arch/xtensa/src/common/xtensa_copystate.c index ade771715d0..1e8cfa8c14a 100644 --- a/arch/xtensa/src/common/xtensa_copystate.c +++ b/arch/xtensa/src/common/xtensa_copystate.c @@ -49,7 +49,7 @@ ****************************************************************************/ /**************************************************************************** - * Name: up_copystate + * Name: xtensa_copystate ****************************************************************************/ /* A little faster than most memcpy's */ diff --git a/arch/xtensa/src/common/xtensa_inthandlers.S b/arch/xtensa/src/common/xtensa_inthandlers.S index cc48797c809..fbd3e6b08c2 100644 --- a/arch/xtensa/src/common/xtensa_inthandlers.S +++ b/arch/xtensa/src/common/xtensa_inthandlers.S @@ -272,7 +272,7 @@ * a CALL0 instruction. See "NOTES on the use of call0 ..." above. * * The corresponding handler sets up the appropriate stack frame, saves - * a few vector-specific registers and calls xtensa_full_context_save() + * a few vector-specific registers and calls _xtensa_context_save() * to save the rest of the interrupted context. It then calls the C * logic to decode the specific interrupt source and dispatch to the * appropriate C interrupt handler. @@ -283,7 +283,9 @@ .section .iram1,"ax" .type _xtensa_level2_handler,@function .align 4 + _xtensa_level2_handler: + mov a0, sp /* sp == a1 */ addi sp, sp, -(4 * XCPTCONTEXT_SIZE) /* Allocate interrupt stack frame */ s32i a0, sp, (4 * REG_A1) /* Save pre-interrupt SP */ @@ -296,7 +298,9 @@ _xtensa_level2_handler: /* Save rest of interrupt context and enter RTOS. */ - call0 xtensa_full_context_save /* Save full register state */ + s32i a2, sp, (4 * REG_A2) + movi a2, sp /* Address of state save on stack */ + call0 _xtensa_context_save /* Save full register state */ /* Set up PS for C, enable interrupts above this level and clear EXCM. */ @@ -317,16 +321,17 @@ _xtensa_level2_handler: /* Restore registers in preparation to return from interrupt */ - call0 _xtensa_int_exit + call0 _xtensa_context_restore /* Restore only level-specific regs (the rest were already restored) */ - l32i a0, sp, (4 * REG_PS) /* retrieve interruptee's PS */ + l32i a0, sp, (4 * REG_PS) /* Retrieve interruptee's PS */ wsr a0, EPS_2 - l32i a0, sp, (4 * REG_PC) /* retrieve interruptee's PC */ + l32i a0, sp, (4 * REG_PC) /* Retrieve interruptee's PC */ wsr a0, EPC_2 - l32i a0, sp, (4 * REG_A0) /* retrieve interruptee's A0 */ - l32i sp, sp, (4 * REG_A1) /* remove interrupt stack frame */ + l32i a0, sp, (4 * REG_A0) /* Retrieve interruptee's A0 */ + l32i a2, sp, (4 * REG_A2) /* Retrieve interruptee's A2 */ + l32i sp, sp, (4 * REG_A1) /* Remove interrupt stack frame */ rsync /* Ensure EPS and EPC written */ /* Return from interrupt. RFI restores the PS from EPS_2 and jumps to @@ -381,6 +386,7 @@ documentation: "Microprocessor Programmer's Guide". .section .iram1,"ax" .type _xtensa_level2_handler, @function .align 4 + _xtensa_level2_handler: #ifdef XT_INTEXC_HOOKS @@ -389,8 +395,11 @@ _xtensa_level2_handler: movi a0, _xt_intexc_hooks l32i a0, a0, 2<<2 beqz a0, 1f + .Ln_xtensa_level2_handler_call_hook: + callx0 a0 /* Must NOT disturb stack! */ + 1: #endif @@ -399,7 +408,7 @@ _xtensa_level2_handler: */ .align 4 -.L_xtensa_level2_handler_exit: + rsr a0, EXCSAVE_2 /* Restore a0 */ rfi 2 @@ -409,6 +418,7 @@ _xtensa_level2_handler: .section .iram1,"ax" .type _xtensa_level3_handler, @function .align 4 + _xtensa_level3_handler: #ifdef XT_INTEXC_HOOKS @@ -417,7 +427,9 @@ _xtensa_level3_handler: movi a0, _xt_intexc_hooks l32i a0, a0, 3<<2 beqz a0, 1f + .Ln_xtensa_level3_handler_call_hook: + callx0 a0 /* Must NOT disturb stack! */ 1: #endif @@ -427,7 +439,7 @@ _xtensa_level3_handler: */ .align 4 -.L_xtensa_level3_handler_exit: + rsr a0, EXCSAVE_3 /* Restore a0 */ rfi 3 @@ -437,6 +449,7 @@ _xtensa_level3_handler: .section .iram1,"ax" .type _xtensa_level4_handler,@function .align 4 + _xtensa_level4_handler: #ifdef XT_INTEXC_HOOKS @@ -445,7 +458,9 @@ _xtensa_level4_handler: movi a0, _xt_intexc_hooks l32i a0, a0, 4 << 2 beqz a0, 1f + .Ln_xtensa_level4_handler_call_hook: + callx0 a0 /* Must NOT disturb stack! */ 1: #endif @@ -455,7 +470,7 @@ _xtensa_level4_handler: */ .align 4 -.L_xtensa_level4_handler_exit: + rsr a0, EXCSAVE_4 /* Restore a0 */ rfi 4 @@ -465,6 +480,7 @@ _xtensa_level4_handler: .section .iram1,"ax" .type _xtensa_level5_handler,@function .align 4 + _xtensa_level5_handler: #ifdef XT_INTEXC_HOOKS @@ -473,7 +489,9 @@ _xtensa_level5_handler: movi a0, _xt_intexc_hooks l32i a0, a0, 5 << 2 beqz a0, 1f + .Ln_xtensa_level5_handler_call_hook: + callx0 a0 /* Must NOT disturb stack! */ 1: #endif @@ -482,8 +500,6 @@ _xtensa_level5_handler: * ADD HIGH PRIORITY LEVEL 5 INTERRUPT HANDLER CODE HERE. */ - .align 4 -.L_xtensa_level5_handler_exit: rsr a0, EXCSAVE_5 /* restore a0 */ rfi 5 @@ -493,6 +509,7 @@ _xtensa_level5_handler: .section .iram1,"ax" .type _xtensa_level6_handler, @function .align 4 + _xtensa_level6_handler: #ifdef XT_INTEXC_HOOKS @@ -501,7 +518,9 @@ _xtensa_level6_handler: movi a0, _xt_intexc_hooks l32i a0, a0, 6 << 2 beqz a0, 1f + .Ln_xtensa_level6_handler_call_hook: + callx0 a0 /* Must NOT disturb stack! */ 1: #endif @@ -510,8 +529,6 @@ _xtensa_level6_handler: * ADD HIGH PRIORITY LEVEL 6 INTERRUPT HANDLER CODE HERE. */ - .align 4 -.L_xtensa_level6_handler_exit: rsr a0, EXCSAVE_6 /* Restore a0 */ rfi 6 diff --git a/arch/xtensa/src/common/xtensa_releasepending.c b/arch/xtensa/src/common/xtensa_releasepending.c new file mode 100644 index 00000000000..99dc0c39b83 --- /dev/null +++ b/arch/xtensa/src/common/xtensa_releasepending.c @@ -0,0 +1,144 @@ +/**************************************************************************** + * arch/xtensa/src/common/arm_releasepending.c + * + * Copyright (C) 2016 Gregory Nutt. All rights reserved. + * Author: Gregory Nutt + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in + * the documentation and/or other materials provided with the + * distribution. + * 3. Neither the name NuttX nor the names of its contributors may be + * used to endorse or promote products derived from this software + * without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS + * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE + * COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, + * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, + * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS + * OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED + * AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN + * ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE + * POSSIBILITY OF SUCH DAMAGE. + * + ****************************************************************************/ + +/**************************************************************************** + * Included Files + ****************************************************************************/ + +#include + +#include +#include +#include +#include + +#include "sched/sched.h" +#include "group/group.h" +#include "xtensa.h" + +/**************************************************************************** + * Public Functions + ****************************************************************************/ + +/**************************************************************************** + * Name: up_release_pending + * + * Description: + * Release and ready-to-run tasks that have + * collected in the pending task list. This can call a + * context switch if a new task is placed at the head of + * the ready to run list. + * + ****************************************************************************/ + +void up_release_pending(void) +{ + struct tcb_s *rtcb = this_task(); + + sinfo("From TCB=%p\n", rtcb); + + /* Merge the g_pendingtasks list into the ready-to-run task list */ + + /* sched_lock(); */ + if (sched_mergepending()) + { + /* The currently active task has changed! We will need to + * switch contexts. + */ + + /* Update scheduler parameters */ + + sched_suspend_scheduler(rtcb); + + /* Are we operating in interrupt context? */ + + if (CURRENT_REGS) + { + /* Yes, then we have to do things differently. + * Just copy the CURRENT_REGS into the OLD rtcb. + */ + + xtensa_savestate(rtcb->xcp.regs); + + /* Restore the exception context of the rtcb at the (new) head + * of the ready-to-run task list. + */ + + rtcb = this_task(); + + /* Update scheduler parameters */ + + sched_resume_scheduler(rtcb); + + /* Then switch contexts. Any necessary address environment + * changes will be made when the interrupt returns. + */ + + xtensa_restorestate(rtcb->xcp.regs); + } + + /* Copy the exception context into the TCB of the task that + * was currently active. if up_saveusercontext returns a non-zero + * value, then this is really the previously running task + * restarting! + */ + + else if (!xtensa_context_save(rtcb->xcp.regs)) + { + /* Restore the exception context of the rtcb at the (new) head + * of the ready-to-run task list. + */ + + rtcb = this_task(); + +#ifdef CONFIG_ARCH_ADDRENV + /* Make sure that the address environment for the previously + * running task is closed down gracefully (data caches dump, + * MMU flushed) and set up the address environment for the new + * thread at the head of the ready-to-run list. + */ + + (void)group_addrenv(rtcb); +#endif + /* Update scheduler parameters */ + + sched_resume_scheduler(rtcb); + + /* Then switch contexts */ + + xtensa_context_restore(rtcb->xcp.regs); + } + } +} diff --git a/arch/xtensa/src/common/xtensa_reprioritizertr.c b/arch/xtensa/src/common/xtensa_reprioritizertr.c new file mode 100644 index 00000000000..3cc2978f478 --- /dev/null +++ b/arch/xtensa/src/common/xtensa_reprioritizertr.c @@ -0,0 +1,198 @@ +/**************************************************************************** + * arch/xtensa/src/common/arm_reprioritizertr.c + * + * Copyright (C) 2016 Gregory Nutt. All rights reserved. + * Author: Gregory Nutt + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in + * the documentation and/or other materials provided with the + * distribution. + * 3. Neither the name NuttX nor the names of its contributors may be + * used to endorse or promote products derived from this software + * without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS + * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE + * COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, + * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, + * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS + * OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED + * AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN + * ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE + * POSSIBILITY OF SUCH DAMAGE. + * + ****************************************************************************/ + +/**************************************************************************** + * Included Files + ****************************************************************************/ + +#include + +#include +#include +#include +#include +#include +#include + +#include "sched/sched.h" +#include "group/group.h" +#include "xtensa.h" + +/**************************************************************************** + * Public Functions + ****************************************************************************/ + +/**************************************************************************** + * Name: up_reprioritize_rtr + * + * Description: + * Called when the priority of a running or + * ready-to-run task changes and the reprioritization will + * cause a context switch. Two cases: + * + * 1) The priority of the currently running task drops and the next + * task in the ready to run list has priority. + * 2) An idle, ready to run task's priority has been raised above the + * the priority of the current, running task and it now has the + * priority. + * + * Inputs: + * tcb: The TCB of the task that has been reprioritized + * priority: The new task priority + * + ****************************************************************************/ + +void up_reprioritize_rtr(struct tcb_s *tcb, uint8_t priority) +{ + /* Verify that the caller is sane */ + + if (tcb->task_state < FIRST_READY_TO_RUN_STATE || + tcb->task_state > LAST_READY_TO_RUN_STATE +#if SCHED_PRIORITY_MIN > 0 + || priority < SCHED_PRIORITY_MIN +#endif +#if SCHED_PRIORITY_MAX < UINT8_MAX + || priority > SCHED_PRIORITY_MAX +#endif + ) + { + PANIC(); + } + else + { + struct tcb_s *rtcb = this_task(); + bool switch_needed; + + sinfo("TCB=%p PRI=%d\n", tcb, priority); + + /* Remove the tcb task from the ready-to-run list. + * sched_removereadytorun will return true if we just + * remove the head of the ready to run list. + */ + + switch_needed = sched_removereadytorun(tcb); + + /* Setup up the new task priority */ + + tcb->sched_priority = (uint8_t)priority; + + /* Return the task to the specified blocked task list. + * sched_addreadytorun will return true if the task was + * added to the new list. We will need to perform a context + * switch only if the EXCLUSIVE or of the two calls is non-zero + * (i.e., one and only one the calls changes the head of the + * ready-to-run list). + */ + + switch_needed ^= sched_addreadytorun(tcb); + + /* Now, perform the context switch if one is needed */ + + if (switch_needed) + { + /* If we are going to do a context switch, then now is the right + * time to add any pending tasks back into the ready-to-run list. + * task list now + */ + + if (g_pendingtasks.head) + { + sched_mergepending(); + } + + /* Update scheduler parameters */ + + sched_suspend_scheduler(rtcb); + + /* Are we in an interrupt handler? */ + + if (CURRENT_REGS) + { + /* Yes, then we have to do things differently. + * Just copy the CURRENT_REGS into the OLD rtcb. + */ + + xtensa_savestate(rtcb->xcp.regs); + + /* Restore the exception context of the rtcb at the (new) head + * of the ready-to-run task list. + */ + + rtcb = this_task(); + + /* Update scheduler parameters */ + + sched_resume_scheduler(rtcb); + + /* Then switch contexts. Any necessary address environment + * changes will be made when the interrupt returns. + */ + + xtensa_restorestate(rtcb->xcp.regs); + } + + /* Copy the exception context into the TCB at the (old) head of the + * ready-to-run Task list. if up_saveusercontext returns a non-zero + * value, then this is really the previously running task restarting! + */ + + else if (!xtensa_context_save(rtcb->xcp.regs)) + { + /* Restore the exception context of the rtcb at the (new) head + * of the ready-to-run task list. + */ + + rtcb = this_task(); + +#ifdef CONFIG_ARCH_ADDRENV + /* Make sure that the address environment for the previously + * running task is closed down gracefully (data caches dump, + * MMU flushed) and set up the address environment for the new + * thread at the head of the ready-to-run list. + */ + + (void)group_addrenv(rtcb); +#endif + /* Update scheduler parameters */ + + sched_resume_scheduler(rtcb); + + /* Then switch contexts */ + + xtensa_context_restore(rtcb->xcp.regs); + } + } + } +} diff --git a/arch/xtensa/src/common/xtensa_schedsigaction.c b/arch/xtensa/src/common/xtensa_schedsigaction.c new file mode 100644 index 00000000000..5f6b1cc5369 --- /dev/null +++ b/arch/xtensa/src/common/xtensa_schedsigaction.c @@ -0,0 +1,190 @@ +/**************************************************************************** + * arch/xtensa/src/common/arm_schedulesigaction.c + * + * Copyright (C) 2016 Gregory Nutt. All rights reserved. + * Author: Gregory Nutt + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in + * the documentation and/or other materials provided with the + * distribution. + * 3. Neither the name NuttX nor the names of its contributors may be + * used to endorse or promote products derived from this software + * without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS + * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE + * COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, + * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, + * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS + * OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED + * AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN + * ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE + * POSSIBILITY OF SUCH DAMAGE. + * + ****************************************************************************/ + +/**************************************************************************** + * Included Files + ****************************************************************************/ + +#include + +#include +#include +#include + +#include +#include + +#include "sched/sched.h" +#include "xtensa.h" + +#ifndef CONFIG_DISABLE_SIGNALS + +/**************************************************************************** + * Public Functions + ****************************************************************************/ + +/**************************************************************************** + * Name: up_schedule_sigaction + * + * Description: + * This function is called by the OS when one or more + * signal handling actions have been queued for execution. + * The architecture specific code must configure things so + * that the 'sigdeliver' callback is executed on the thread + * specified by 'tcb' as soon as possible. + * + * This function may be called from interrupt handling logic. + * + * This operation should not cause the task to be unblocked + * nor should it cause any immediate execution of sigdeliver. + * Typically, a few cases need to be considered: + * + * (1) This function may be called from an interrupt handler + * During interrupt processing, all xcptcontext structures + * should be valid for all tasks. That structure should + * be modified to invoke sigdeliver() either on return + * from (this) interrupt or on some subsequent context + * switch to the recipient task. + * (2) If not in an interrupt handler and the tcb is NOT + * the currently executing task, then again just modify + * the saved xcptcontext structure for the recipient + * task so it will invoke sigdeliver when that task is + * later resumed. + * (3) If not in an interrupt handler and the tcb IS the + * currently executing task -- just call the signal + * handler now. + * + ****************************************************************************/ + +void up_schedule_sigaction(struct tcb_s *tcb, sig_deliver_t sigdeliver) +{ + irqstate_t flags; + + sinfo("tcb=0x%p sigdeliver=0x%p\n", tcb, sigdeliver); + + /* Make sure that interrupts are disabled */ + + flags = enter_critical_section(); + + /* Refuse to handle nested signal actions */ + + if (!tcb->xcp.sigdeliver) + { + /* First, handle some special cases when the signal is being delivered + * to the currently executing task. + */ + + sinfo("rtcb=0x%p CURRENT_REGS=0x%p\n", this_task(), CURRENT_REGS); + + if (tcb == this_task()) + { + /* CASE 1: We are not in an interrupt handler and a task is + * signalling itself for some reason. + */ + + if (!CURRENT_REGS) + { + /* In this case just deliver the signal now. */ + + sigdeliver(tcb); + } + + /* CASE 2: We are in an interrupt handler AND the interrupted + * task is the same as the one that must receive the signal, then + * we will have to modify the return state as well as the state + * in the TCB. + * + * Hmmm... there looks like a latent bug here: The following logic + * would fail in the strange case where we are in an interrupt + * handler, the thread is signalling itself, but a context switch + * to another task has occurred so that CURRENT_REGS does not + * refer to the thread of this_task()! + */ + + else + { + /* Save the return lr and cpsr and one scratch register + * These will be restored by the signal trampoline after + * the signals have been delivered. + */ + + tcb->xcp.sigdeliver = sigdeliver; + tcb->xcp.saved_pc = CURRENT_REGS[REG_PC]; +#warning REVISIT: Missing logic... need to save interrupt state + + /* Then set up to vector to the trampoline with interrupts + * disabled + */ + + CURRENT_REGS[REG_PC] = (uint32_t)up_sigdeliver; +#warning REVISIT: Missing logic... need to set interrupt state with interrupts disabled + + /* And make sure that the saved context in the TCB is the same + * as the interrupt return context. + */ + + xtensa_savestate(tcb->xcp.regs); + } + } + + /* Otherwise, we are (1) signaling a task is not running from an + * interrupt handler or (2) we are not in an interrupt handler and the + * running task is signalling some non-running task. + */ + + else + { + /* Save the return lr and cpsr and one scratch register. These + * will be restored by the signal trampoline after the signals + * have been delivered. + */ + + tcb->xcp.sigdeliver = sigdeliver; + tcb->xcp.saved_pc = tcb->xcp.regs[REG_PC]; +#warning REVISIT: Missing logic... need to save interrupt state + + /* Then set up to vector to the trampoline with interrupts + * disabled + */ + + tcb->xcp.regs[REG_PC] = (uint32_t)up_sigdeliver; +#warning REVISIT: Missing logic... need to set interrupt state with interrupts disabled + } + } + + leave_critical_section(flags); +} + +#endif /* !CONFIG_DISABLE_SIGNALS */ diff --git a/arch/xtensa/src/common/xtensa_sigdeliver.c b/arch/xtensa/src/common/xtensa_sigdeliver.c new file mode 100644 index 00000000000..b28ed30d71f --- /dev/null +++ b/arch/xtensa/src/common/xtensa_sigdeliver.c @@ -0,0 +1,126 @@ +/**************************************************************************** + * arch/xtensa/src/common/arm_sigdeliver.c + * + * Copyright (C) 2016 Gregory Nutt. All rights reserved. + * Author: Gregory Nutt + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in + * the documentation and/or other materials provided with the + * distribution. + * 3. Neither the name NuttX nor the names of its contributors may be + * used to endorse or promote products derived from this software + * without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS + * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE + * COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, + * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, + * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS + * OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED + * AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN + * ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE + * POSSIBILITY OF SUCH DAMAGE. + * + ****************************************************************************/ + +/**************************************************************************** + * Included Files + ****************************************************************************/ + +#include + +#include +#include +#include + +#include +#include +#include +#include + +#include "sched/sched.h" +#include "xtensa.h" + +#ifndef CONFIG_DISABLE_SIGNALS + +/**************************************************************************** + * Public Functions + ****************************************************************************/ + +/**************************************************************************** + * Name: up_sigdeliver + * + * Description: + * This is the a signal handling trampoline. When a signal action was + * posted. The task context was mucked with and forced to branch to this + * location with interrupts disabled. + * + ****************************************************************************/ + +void up_sigdeliver(void) +{ + struct tcb_s *rtcb = this_task(); + uint32_t regs[XCPTCONTEXT_REGS]; + sig_deliver_t sigdeliver; + + /* Save the errno. This must be preserved throughout the signal handling + * so that the user code final gets the correct errno value (probably + * EINTR). + */ + + int saved_errno = rtcb->pterrno; + + board_autoled_on(LED_SIGNAL); + + sinfo("rtcb=%p sigdeliver=%p sigpendactionq.head=%p\n", + rtcb, rtcb->xcp.sigdeliver, rtcb->sigpendactionq.head); + ASSERT(rtcb->xcp.sigdeliver != NULL); + + /* Save the real return state on the stack. */ + + xtensa_copystate(regs, rtcb->xcp.regs); + regs[REG_PC] = rtcb->xcp.saved_pc; +#warbing Missing Logic... Need to restore the correct interrupt here + + /* Get a local copy of the sigdeliver function pointer. we do this so that + * we can nullify the sigdeliver function pointer in the TCB and accept + * more signal deliveries while processing the current pending signals. + */ + + sigdeliver = rtcb->xcp.sigdeliver; + rtcb->xcp.sigdeliver = NULL; + + /* Then restore the task interrupt state */ + + up_irq_restore(regs[REG_CPSR]); + + /* Deliver the signals */ + + sigdeliver(rtcb); + + /* Output any debug messages BEFORE restoring errno (because they may + * alter errno), then disable interrupts again and restore the original + * errno that is needed by the user logic (it is probably EINTR). + */ + + sinfo("Resuming\n"); + (void)up_irq_save(); + rtcb->pterrno = saved_errno; + + /* Then restore the correct state for this thread of execution. */ + + board_autoled_off(LED_SIGNAL); + xtensa_context_restore(regs); +} + +#endif /* !CONFIG_DISABLE_SIGNALS */ diff --git a/arch/xtensa/src/common/xtensa_unblocktask.c b/arch/xtensa/src/common/xtensa_unblocktask.c new file mode 100644 index 00000000000..e7a37ba4104 --- /dev/null +++ b/arch/xtensa/src/common/xtensa_unblocktask.c @@ -0,0 +1,159 @@ +/**************************************************************************** + * arch/xtensa/src/common/arm_unblocktask.c + * + * Copyright (C) 2016 Gregory Nutt. All rights reserved. + * Author: Gregory Nutt + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in + * the documentation and/or other materials provided with the + * distribution. + * 3. Neither the name NuttX nor the names of its contributors may be + * used to endorse or promote products derived from this software + * without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS + * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE + * COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, + * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, + * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS + * OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED + * AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN + * ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE + * POSSIBILITY OF SUCH DAMAGE. + * + ****************************************************************************/ + +/**************************************************************************** + * Included Files + ****************************************************************************/ + +#include + +#include +#include +#include +#include + +#include "sched/sched.h" +#include "group/group.h" +#include "clock/clock.h" +#include "xtensa.h" + +/**************************************************************************** + * Public Functions + ****************************************************************************/ + +/**************************************************************************** + * Name: up_unblock_task + * + * Description: + * A task is currently in an inactive task list + * but has been prepped to execute. Move the TCB to the + * ready-to-run list, restore its context, and start execution. + * + * Inputs: + * tcb: Refers to the tcb to be unblocked. This tcb is + * in one of the waiting tasks lists. It must be moved to + * the ready-to-run list and, if it is the highest priority + * ready to run task, executed. + * + ****************************************************************************/ + +void up_unblock_task(struct tcb_s *tcb) +{ + struct tcb_s *rtcb = this_task(); + + /* Verify that the context switch can be performed */ + + ASSERT((tcb->task_state >= FIRST_BLOCKED_STATE) && + (tcb->task_state <= LAST_BLOCKED_STATE)); + + /* Remove the task from the blocked task list */ + + sched_removeblocked(tcb); + + /* Add the task in the correct location in the prioritized + * ready-to-run task list + */ + + if (sched_addreadytorun(tcb)) + { + /* The currently active task has changed! We need to do + * a context switch to the new task. + */ + + /* Update scheduler parameters */ + + sched_suspend_scheduler(rtcb); + + /* Are we in an interrupt handler? */ + + if (CURRENT_REGS) + { + /* Yes, then we have to do things differently. + * Just copy the CURRENT_REGS into the OLD rtcb. + */ + + xtensa_savestate(rtcb->xcp.regs); + + /* Restore the exception context of the rtcb at the (new) head + * of the ready-to-run task list. + */ + + rtcb = this_task(); + + /* Update scheduler parameters */ + + sched_resume_scheduler(rtcb); + + /* Then switch contexts. Any necessary address environment + * changes will be made when the interrupt returns. + */ + + xtensa_restorestate(rtcb->xcp.regs); + } + + /* We are not in an interrupt handler. Copy the user C context + * into the TCB of the task that was previously active. if + * up_saveusercontext returns a non-zero value, then this is really the + * previously running task restarting! + */ + + else if (!xtensa_context_save(rtcb->xcp.regs)) + { + /* Restore the exception context of the new task that is ready to + * run (probably tcb). This is the new rtcb at the head of the + * ready-to-run task list. + */ + + rtcb = this_task(); + +#ifdef CONFIG_ARCH_ADDRENV + /* Make sure that the address environment for the previously + * running task is closed down gracefully (data caches dump, + * MMU flushed) and set up the address environment for the new + * thread at the head of the ready-to-run list. + */ + + (void)group_addrenv(rtcb); +#endif + /* Update scheduler parameters */ + + sched_resume_scheduler(rtcb); + + /* Then switch contexts */ + + xtensa_context_restore(rtcb->xcp.regs); + } + } +} diff --git a/arch/xtensa/src/esp32/Make.defs b/arch/xtensa/src/esp32/Make.defs index 8aef01a5067..c9f4ea0ae39 100644 --- a/arch/xtensa/src/esp32/Make.defs +++ b/arch/xtensa/src/esp32/Make.defs @@ -41,13 +41,15 @@ HEAD_CSRC = esp32_start.c # Common XTENSA files (arch/xtensa/src/common) CMN_ASRCS = xtensa_context.S xtensa_irq.S xtensa_intvectors.S -CMN_CSRCS = xtensa_assert.c xtensa_copystate.c +CMN_CSRCS = xtensa_assert.c xtensa_blocktask.c xtensa_copystate.c CMN_CSRCS += xtensa_createstack.c xtensa_exit.c xtensa_idle.c CMN_CSRCS += xtensa_initialize.c xtensa_initialstate.c CMN_CSRCS += xtensa_interruptcontext.c xtensa_irqdispatch.c xtensa_lowputs.c CMN_CSRCS += xtensa_mdelay.c xtensa_modifyreg8.c xtensa_modifyreg16.c -CMN_CSRCS += xtensa_modifyreg32.c xtensa_puts.c xtensa_releasestack.c -CMN_CSRCS += xtensa_stackframe.c xtensa_udelay.c xtensa_usestack.c +CMN_CSRCS += xtensa_modifyreg32.c xtensa_puts.c xtensa_releasepending.c +CMN_CSRCS += xtensa_releasestack.c xtensa_reprioritizertr.c +CMN_CSRCS += xtensa_schedsigaction.c xtensa_sigdeliver.c xtensa_stackframe.c +CMN_CSRCS += xtensa_udelay.c xtensa_unblocktask.c xtensa_usestack.c # Configuration-dependent common XTENSA files diff --git a/arch/xtensa/src/esp32/esp32_cpustart.c b/arch/xtensa/src/esp32/esp32_cpustart.c index c8e7cc66bba..01e0412c75d 100644 --- a/arch/xtensa/src/esp32/esp32_cpustart.c +++ b/arch/xtensa/src/esp32/esp32_cpustart.c @@ -137,7 +137,7 @@ int xtensa_start_handler(int irq, FAR void *context) * be the CPUs NULL task. */ - up_restorestate(tcb->xcp.regs); + xtensa_context_restore(tcb->xcp.regs); return OK; }