blob: 319248c6a9e2507561fefab4bd28e9b37640ea28 [file] [log] [blame]
/*
* Copyright (c) 2016 Cadence Design Systems, Inc.
* SPDX-License-Identifier: Apache-2.0
*/
/**
* @file
* @brief kernel swapper code for Xtensa
*
* This module implements the __swap() routine for the Xtensa architecture.
*/
#include <xtensa_context.h>
#include <kernel_arch_data.h>
#include <offsets_short.h>
.extern _kernel
/* unsigned int __swap (unsigned int basepri); */
.globl __swap
.type __swap,@function
.align 4
__swap:
#ifdef __XTENSA_CALL0_ABI__
addi sp, sp, -XT_SOL_FRMSZ
#else
entry sp, XT_SOL_FRMSZ
#endif
s32i a0, sp, XT_SOL_pc
s32i a2, sp, XT_SOL_ps
#ifdef __XTENSA_CALL0_ABI__
s32i a12, sp, XT_SOL_a12 /* save callee-saved registers */
s32i a13, sp, XT_SOL_a13
s32i a14, sp, XT_SOL_a14
s32i a15, sp, XT_SOL_a15
#else
/* Spill register windows. Calling xthal_window_spill() causes extra
* spills and reloads, so we will set things up to call the _nw version
* instead to save cycles.
*/
/* spills a4-a7 if needed */
movi a6, ~(PS_WOE_MASK|PS_INTLEVEL_MASK)
and a2, a2, a6 /* clear WOE, INTLEVEL */
addi a2, a2, XCHAL_EXCM_LEVEL /* set INTLEVEL */
wsr a2, PS
rsync
call0 xthal_window_spill_nw
l32i a2, sp, XT_SOL_ps /* restore PS */
addi a2, a2, XCHAL_EXCM_LEVEL
wsr a2, PS
#endif
#if XCHAL_CP_NUM > 0
/* Save coprocessor callee-saved state (if any). At this point CPENABLE
* should still reflect which CPs were in use (enabled).
*/
call0 _xt_coproc_savecs
#endif
movi a2, _kernel
movi a3, 0
l32i a4, a2, KERNEL_OFFSET(current) /* a4 := _kernel->current */
s32i a3, sp, XT_SOL_exit /* 0 to flag as solicited frame */
s32i sp, a4, THREAD_OFFSET(sp) /* current->arch.topOfStack := sp */
/*
* Set __swap()'s default return code to -EAGAIN. This eliminates the
* need for the timeout code to set it itself.
*/
movi a3, -11 /* a3 := -EAGAIN. TODO: Use a macro here insted of 11 */
s32i a3, a4, THREAD_OFFSET(retval) /* current->arch.retval := -EAGAIN */
#if XCHAL_CP_NUM > 0
/* Clear CPENABLE, also in task's co-processor state save area. */
movi a3, 0
/* a4 = _kernel->current */
wsr a3, CPENABLE
s16i a3, a4, THREAD_OFFSET(cpEnable) /* clear saved cpenable */
#endif
#ifdef CONFIG_KERNEL_EVENT_LOGGER_CONTEXT_SWITCH
/* Register the context switch */
#ifdef __XTENSA_CALL0_ABI__
call0 _sys_k_event_logger_context_switch
#else
call4 _sys_k_event_logger_context_switch
#endif
#endif
/* _thread := _kernel.ready_q.cache */
l32i a3, a2, KERNEL_OFFSET(ready_q_cache)
/*
* Swap threads if any is to be swapped in.
*/
call0 _zxt_dispatch /* (_kernel@a2, _thread@a3) */
/* Never reaches here. */