/**************************************************************************/ /* Copyright (c) Cadence Design Systems, Inc. */ /* */ /* Permission is hereby granted, free of charge, to any person obtaining */ /* a copy of this software and associated documentation files (the */ /* "Software"), to deal in the Software without restriction, including */ /* without limitation the rights to use, copy, modify, merge, publish, */ /* distribute, sublicense, and/or sell copies of the Software, and to */ /* permit persons to whom the Software is furnished to do so, subject to */ /* the following conditions: */ /* */ /* The above copyright notice and this permission notice shall be */ /* included in all copies or substantial portions of the Software. */ /* */ /* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, */ /* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF */ /* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. */ /* IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY */ /* CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, */ /* TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE */ /* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */ /**************************************************************************/ /**************************************************************************/ /* */ /* DESCRIPTION */ /* */ /* Xtensa coprocessor handling routines. This code is only active if */ /* one or more coprocessors are present. */ /* */ /* RELEASE HISTORY */ /* */ /* DATE NAME DESCRIPTION */ /* */ /* 12-31-2020 Cadence Design Systems Initial Version 6.1.3 */ /* */ /**************************************************************************/ #include #include #include "xtensa_context.h" #include "xtensa_rtos.h" #if XCHAL_CP_NUM > 0 //----------------------------------------------------------------------------- // Coprocessor related state and precomputed values. //----------------------------------------------------------------------------- // Table of coprocessor owners, identified by thread's CP save area pointer. // Zero means coprocessor is not owned. .data .global _xt_coproc_owner_sa .align 16,,XCHAL_CP_MAX << 2 // minimize crossing cache boundaries _xt_coproc_owner_sa: .rept XCHAL_CP_MAX .word 0 .endr // Bitmask table for CP n's enable bit, indexed by coprocessor number. .section .rodata, "a" .global _xt_coproc_mask .align 16,,8 // try to keep it all in one cache line .set i, 0 _xt_coproc_mask: .rept XCHAL_CP_MAX .long (i<<16) | (1<tx_thread_cp_state) : 0 ) movi a15, _tx_thread_system_state // check if interrupt state l32i a15, a15, 0 bnez a15, 1f movi a15, _tx_thread_current_ptr // check if thread running l32i a15, a15, 0 beqz a15, 2f // Return base address of current thread's co-prcoessor save area. addi a15, a15, tx_thread_cp_state ret 1: movi a15, 0 // return error 2: ret //----------------------------------------------------------------------------- // _xt_coproc_savecs // // If there is a current thread and it has a coprocessor state save area, then // save all callee-saved state into this area. This function is called from the // solicited context switch handler. It calls a system-specific function to get // the coprocessor save area base address. // // Entry conditions: // - The thread being switched out is still the current thread. // - CPENABLE state reflects which coprocessors are active. // - Registers have been saved/spilled already. // // Exit conditions: // - All necessary CP callee-saved state has been saved. // - Registers a7-a15 have been trashed. // // Must be called from assembly code only, using CALL0. //----------------------------------------------------------------------------- .global _xt_coproc_savecs .type _xt_coproc_savecs,@function .align 4 _xt_coproc_savecs: // At entry, CPENABLE should be showing which CPs are enabled. rsr a11, CPENABLE // a11 = which CPs are enabled beqz a11, .Ldone // quick exit if none mov a14, a0 // save return address call0 XT_RTOS_CP_STATE // get address of CP save area mov a0, a14 // restore return address beqz a15, .Ldone // if none then nothing to do l32i a14, a15, XT_CP_ASA // a14 = base of aligned save area beqz a14, .Ldone // no save area, nothing to do s16i a11, a15, XT_CP_CS_ST // save mask of CPs being stored movi a13, _xt_coproc_sa_offset // array of CP save offsets l32i a15, a15, XT_CP_ASA // a15 = base of aligned save area #if XCHAL_CP0_SA_SIZE bbci.l a11, 0, 2f // CP 0 not enabled l32i a14, a13, 0 // a14 = _xt_coproc_sa_offset[0] add a12, a14, a15 // a12 = save area for CP 0 xchal_cp0_store a12, a7, a8, a9, a10 continue=0 ofs=-1 select=XTHAL_SAS_TIE|XTHAL_SAS_NOCC|XTHAL_SAS_CALE alloc=XTHAL_SAS_ALL 2: #endif #if XCHAL_CP1_SA_SIZE bbci.l a11, 1, 2f // CP 1 not enabled l32i a14, a13, 4 // a14 = _xt_coproc_sa_offset[1] add a12, a14, a15 // a12 = save area for CP 1 xchal_cp1_store a12, a7, a8, a9, a10 continue=0 ofs=-1 select=XTHAL_SAS_TIE|XTHAL_SAS_NOCC|XTHAL_SAS_CALE alloc=XTHAL_SAS_ALL 2: #endif #if XCHAL_CP2_SA_SIZE bbci.l a11, 2, 2f l32i a14, a13, 8 add a12, a14, a15 xchal_cp2_store a12, a7, a8, a9, a10 continue=0 ofs=-1 select=XTHAL_SAS_TIE|XTHAL_SAS_NOCC|XTHAL_SAS_CALE alloc=XTHAL_SAS_ALL 2: #endif #if XCHAL_CP3_SA_SIZE bbci.l a11, 3, 2f l32i a14, a13, 12 add a12, a14, a15 xchal_cp3_store a12, a7, a8, a9, a10 continue=0 ofs=-1 select=XTHAL_SAS_TIE|XTHAL_SAS_NOCC|XTHAL_SAS_CALE alloc=XTHAL_SAS_ALL 2: #endif #if XCHAL_CP4_SA_SIZE bbci.l a11, 4, 2f l32i a14, a13, 16 add a12, a14, a15 xchal_cp4_store a12, a7, a8, a9, a10 continue=0 ofs=-1 select=XTHAL_SAS_TIE|XTHAL_SAS_NOCC|XTHAL_SAS_CALE alloc=XTHAL_SAS_ALL 2: #endif #if XCHAL_CP5_SA_SIZE bbci.l a11, 5, 2f l32i a14, a13, 20 add a12, a14, a15 xchal_cp5_store a12, a7, a8, a9, a10 continue=0 ofs=-1 select=XTHAL_SAS_TIE|XTHAL_SAS_NOCC|XTHAL_SAS_CALE alloc=XTHAL_SAS_ALL 2: #endif #if XCHAL_CP6_SA_SIZE bbci.l a11, 6, 2f l32i a14, a13, 24 add a12, a14, a15 xchal_cp6_store a12, a7, a8, a9, a10 continue=0 ofs=-1 select=XTHAL_SAS_TIE|XTHAL_SAS_NOCC|XTHAL_SAS_CALE alloc=XTHAL_SAS_ALL 2: #endif #if XCHAL_CP7_SA_SIZE bbci.l a11, 7, 2f l32i a14, a13, 28 add a12, a14, a15 xchal_cp7_store a12, a7, a8, a9, a10 continue=0 ofs=-1 select=XTHAL_SAS_TIE|XTHAL_SAS_NOCC|XTHAL_SAS_CALE alloc=XTHAL_SAS_ALL 2: #endif .Ldone: ret //----------------------------------------------------------------------------- // _xt_coproc_restorecs // // Restore any callee-saved coprocessor state for the incoming thread. // This function is called from coprocessor exception handling, when giving // ownership to a thread that solicited a context switch earlier. It calls a // system-specific function to get the coprocessor save area base address. // // Entry conditions: // - The incoming thread is set as the current thread. // - CPENABLE is set up correctly for all required coprocessors. // - a2 = mask of coprocessors to be restored. // // Exit conditions: // - All necessary CP callee-saved state has been restored. // - CPENABLE - unchanged. // - Registers a2, a8-a15 have been trashed. // // Must be called from assembly code only, using CALL0. //----------------------------------------------------------------------------- .global _xt_coproc_restorecs .type _xt_coproc_restorecs,@function .align 4 _xt_coproc_restorecs: mov a14, a0 // save return address call0 XT_RTOS_CP_STATE // get address of CP save area mov a0, a14 // restore return address beqz a15, .Ldone2 // if none then nothing to do l32i a14, a15, XT_CP_ASA // a14 = base of aligned save area beqz a14, .Ldone2 // no save area, nothing to do l16ui a13, a15, XT_CP_CS_ST // a13 = which CPs have been saved xor a13, a13, a2 // clear the ones being restored s16i a13, a15, XT_CP_CS_ST // update saved CP mask movi a13, _xt_coproc_sa_offset // array of CP save offsets l32i a15, a15, XT_CP_ASA // a15 = base of aligned save area #if XCHAL_CP0_SA_SIZE bbci.l a2, 0, 2f // CP 0 not enabled l32i a14, a13, 0 // a14 = _xt_coproc_sa_offset[0] add a12, a14, a15 // a12 = save area for CP 0 xchal_cp0_load a12, a8, a9, a10, a11 continue=0 ofs=-1 select=XTHAL_SAS_TIE|XTHAL_SAS_NOCC|XTHAL_SAS_CALE alloc=XTHAL_SAS_ALL 2: #endif #if XCHAL_CP1_SA_SIZE bbci.l a2, 1, 2f // CP 1 not enabled l32i a14, a13, 4 // a14 = _xt_coproc_sa_offset[1] add a12, a14, a15 // a12 = save area for CP 1 xchal_cp1_load a12, a8, a9, a10, a11 continue=0 ofs=-1 select=XTHAL_SAS_TIE|XTHAL_SAS_NOCC|XTHAL_SAS_CALE alloc=XTHAL_SAS_ALL 2: #endif #if XCHAL_CP2_SA_SIZE bbci.l a2, 2, 2f l32i a14, a13, 8 add a12, a14, a15 xchal_cp2_load a12, a8, a9, a10, a11 continue=0 ofs=-1 select=XTHAL_SAS_TIE|XTHAL_SAS_NOCC|XTHAL_SAS_CALE alloc=XTHAL_SAS_ALL 2: #endif #if XCHAL_CP3_SA_SIZE bbci.l a2, 3, 2f l32i a14, a13, 12 add a12, a14, a15 xchal_cp3_load a12, a8, a9, a10, a11 continue=0 ofs=-1 select=XTHAL_SAS_TIE|XTHAL_SAS_NOCC|XTHAL_SAS_CALE alloc=XTHAL_SAS_ALL 2: #endif #if XCHAL_CP4_SA_SIZE bbci.l a2, 4, 2f l32i a14, a13, 16 add a12, a14, a15 xchal_cp4_load a12, a8, a9, a10, a11 continue=0 ofs=-1 select=XTHAL_SAS_TIE|XTHAL_SAS_NOCC|XTHAL_SAS_CALE alloc=XTHAL_SAS_ALL 2: #endif #if XCHAL_CP5_SA_SIZE bbci.l a2, 5, 2f l32i a14, a13, 20 add a12, a14, a15 xchal_cp5_load a12, a8, a9, a10, a11 continue=0 ofs=-1 select=XTHAL_SAS_TIE|XTHAL_SAS_NOCC|XTHAL_SAS_CALE alloc=XTHAL_SAS_ALL 2: #endif #if XCHAL_CP6_SA_SIZE bbci.l a2, 6, 2f l32i a14, a13, 24 add a12, a14, a15 xchal_cp6_load a12, a8, a9, a10, a11 continue=0 ofs=-1 select=XTHAL_SAS_TIE|XTHAL_SAS_NOCC|XTHAL_SAS_CALE alloc=XTHAL_SAS_ALL 2: #endif #if XCHAL_CP7_SA_SIZE bbci.l a2, 7, 2f l32i a14, a13, 28 add a12, a14, a15 xchal_cp7_load a12, a8, a9, a10, a11 continue=0 ofs=-1 select=XTHAL_SAS_TIE|XTHAL_SAS_NOCC|XTHAL_SAS_CALE alloc=XTHAL_SAS_ALL 2: #endif .Ldone2: ret #if XCHAL_HAVE_XEA3 //----------------------------------------------------------------------------- // For XEA3, coprocessor exceptions come here. This is a wrapper function that // calls _xt_coproc_handler() to do the actual work. We don't want the handler // to be interrupted because that might cause a round-robin switch and leave // coprocessor context in a confused state. So interrupts are disabled before // calling the handler. They will be re-enabled on return from exception. //----------------------------------------------------------------------------- .text .global _xt_coproc_exc .type _xt_coproc_exc,@function .align 4 _xt_coproc_exc: #ifdef __XTENSA_CALL0_ABI__ addi a1, a1, -16 // reserve 16 bytes on stack s32i a0, a1, 0 // save return address s32i a15, a1, 8 // must save a15 (see dispatch) movi a3, PS_DI_MASK xps a3, a3 // Set PS.DI, disable interrupts l32i a3, a2, XT_STK_EXCCAUSE // a3 <- exccause extui a2, a3, 8, 4 // a2 <- CP index call0 _xt_coproc_handler l32i a0, a1, 0 // restore return address l32i a15, a1, 8 // restore a15 addi a1, a1, 16 ret #else entry a1, 48 // reserve 16 bytes on stack s32i a0, a1, 0 // save return address movi a3, PS_DI_MASK xps a3, a3 // Set PS.DI, disable interrupts l32i a3, a2, XT_STK_EXCCAUSE // a3 <- exccause extui a2, a3, 8, 4 // a2 <- CP index call0 _xt_coproc_handler l32i a0, a1, 0 // restore return address retw #endif #endif // XCHAL_HAVE_XEA3 #if XCHAL_HAVE_XEA2 //----------------------------------------------------------------------------- // XEA2 coprocessor exception dispatcher. Save enough state to be able to call // the coprocessor handler, then restore and return. //----------------------------------------------------------------------------- .text .global _xt_coproc_exc .type _xt_coproc_exc,@function .align 4 _xt_coproc_exc: mov a0, sp // Allocate stack frame addi sp, sp, -XT_STK_FRMSZ s32i a0, sp, XT_STK_A1 // save SP #if XCHAL_HAVE_WINDOWED s32e a0, sp, -12 // for debug backtrace #endif rsr a0, PS s32i a0, sp, XT_STK_PS // save PS rsr a0, EPC_1 s32i a0, sp, XT_STK_PC // save PC rsr a0, EXCSAVE_1 s32i a0, sp, XT_STK_A0 // retrieve and save a0 #if XCHAL_HAVE_WINDOWED s32e a0, sp, -16 // for debug backtrace #endif s32i a2, sp, XT_STK_A2 s32i a3, sp, XT_STK_A3 s32i a4, sp, XT_STK_A4 s32i a5, sp, XT_STK_A5 s32i a6, sp, XT_STK_A6 s32i a7, sp, XT_STK_A7 s32i a8, sp, XT_STK_A8 s32i a9, sp, XT_STK_A9 s32i a10, sp, XT_STK_A10 s32i a11, sp, XT_STK_A11 s32i a12, sp, XT_STK_A12 s32i a13, sp, XT_STK_A13 s32i a14, sp, XT_STK_A14 s32i a15, sp, XT_STK_A15 rsr a3, EXCCAUSE // a3 <- exccause addi a2, a3, -EXCCAUSE_CP0_DISABLED // a2 <- CP index call0 _xt_coproc_handler mov a0, a2 // save return value l32i a2, sp, XT_STK_A2 l32i a3, sp, XT_STK_A3 l32i a4, sp, XT_STK_A4 l32i a5, sp, XT_STK_A5 l32i a6, sp, XT_STK_A6 l32i a7, sp, XT_STK_A7 l32i a8, sp, XT_STK_A8 l32i a9, sp, XT_STK_A9 l32i a10, sp, XT_STK_A10 l32i a11, sp, XT_STK_A11 l32i a12, sp, XT_STK_A12 l32i a13, sp, XT_STK_A13 l32i a14, sp, XT_STK_A14 l32i a15, sp, XT_STK_A15 bnez a0, .Lfail // abort if failure l32i a0, sp, XT_STK_PC wsr a0, EPC_1 // restore PC l32i a0, sp, XT_STK_PS wsr a0, PS // restore PS l32i a0, sp, XT_STK_A0 addi a1, a1, XT_STK_FRMSZ // deallocate stack frame rfe .Lfail: call0 _xt_panic #endif // XCHAL_HAVE_XEA2 #endif // XCHAL_CP_NUM > 0