blob: fa1cd597bc463ce224a217f280805386b584244c [file] [log] [blame]
/*
* Copyright (c) 2016 Intel Corporation
*
* SPDX-License-Identifier: Apache-2.0
*/
#include <zephyr/toolchain.h>
#include <zephyr/linker/sections.h>
#include <offsets_short.h>
/* exports */
GTEXT(arch_swap)
GTEXT(z_thread_entry_wrapper)
/* imports */
GTEXT(_k_neg_eagain)
/* unsigned int arch_swap(unsigned int key)
*
* Always called with interrupts locked
*/
SECTION_FUNC(exception.other, arch_swap)
#if defined(CONFIG_INSTRUMENT_THREAD_SWITCHING)
/* Need to preserve r4 as it has the function argument. */
addi sp, sp, -12
stw ra, 8(sp)
stw fp, 4(sp)
stw r4, 0(sp)
call z_thread_mark_switched_out
ldw r4, 0(sp)
ldw fp, 4(sp)
ldw ra, 8(sp)
addi sp, sp, 12
#endif
/* Get a reference to _kernel in r10 */
movhi r10, %hi(_kernel)
ori r10, r10, %lo(_kernel)
/* Get the pointer to kernel->current */
ldw r11, _kernel_offset_to_current(r10)
/* Store all the callee saved registers. We either got here via
* an exception or from a cooperative invocation of arch_swap() from C
* domain, so all the caller-saved registers have already been
* saved by the exception asm or the calling C code already.
*/
stw r16, _thread_offset_to_r16(r11)
stw r17, _thread_offset_to_r17(r11)
stw r18, _thread_offset_to_r18(r11)
stw r19, _thread_offset_to_r19(r11)
stw r20, _thread_offset_to_r20(r11)
stw r21, _thread_offset_to_r21(r11)
stw r22, _thread_offset_to_r22(r11)
stw r23, _thread_offset_to_r23(r11)
stw r28, _thread_offset_to_r28(r11)
stw ra, _thread_offset_to_ra(r11)
stw sp, _thread_offset_to_sp(r11)
/* r4 has the 'key' argument which is the result of irq_lock()
* before this was called
*/
stw r4, _thread_offset_to_key(r11)
/* Populate default return value */
movhi r5, %hi(_k_neg_eagain)
ori r5, r5, %lo(_k_neg_eagain)
ldw r4, (r5)
stw r4, _thread_offset_to_retval(r11)
/* get cached thread to run */
ldw r2, _kernel_offset_to_ready_q_cache(r10)
/* At this point r2 points to the next thread to be swapped in */
/* the thread to be swapped in is now the current thread */
stw r2, _kernel_offset_to_current(r10)
/* Restore callee-saved registers and switch to the incoming
* thread's stack
*/
ldw r16, _thread_offset_to_r16(r2)
ldw r17, _thread_offset_to_r17(r2)
ldw r18, _thread_offset_to_r18(r2)
ldw r19, _thread_offset_to_r19(r2)
ldw r20, _thread_offset_to_r20(r2)
ldw r21, _thread_offset_to_r21(r2)
ldw r22, _thread_offset_to_r22(r2)
ldw r23, _thread_offset_to_r23(r2)
ldw r28, _thread_offset_to_r28(r2)
ldw ra, _thread_offset_to_ra(r2)
ldw sp, _thread_offset_to_sp(r2)
/* We need to irq_unlock(current->coopReg.key);
* key was supplied as argument to arch_swap(). Fetch it.
*/
ldw r3, _thread_offset_to_key(r2)
/*
* Load return value into r2 (return value register). -EAGAIN unless
* someone previously called arch_thread_return_value_set(). Do this
* before we potentially unlock interrupts.
*/
ldw r2, _thread_offset_to_retval(r2)
/* Now do irq_unlock(current->coopReg.key) */
#if (ALT_CPU_NUM_OF_SHADOW_REG_SETS > 0) || \
(defined ALT_CPU_EIC_PRESENT) || \
(defined ALT_CPU_MMU_PRESENT) || \
(defined ALT_CPU_MPU_PRESENT)
andi r3, r3, NIOS2_STATUS_PIE_MSK
beq r3, zero, no_unlock
rdctl r3, status
ori r3, r3, NIOS2_STATUS_PIE_MSK
wrctl status, r3
no_unlock:
#else
wrctl status, r3
#endif
#if defined(CONFIG_INSTRUMENT_THREAD_SWITCHING)
/* Also need to preserve r2, r3 as return values */
addi sp, sp, -20
stw ra, 16(sp)
stw fp, 12(sp)
stw r4, 8(sp)
stw r3, 4(sp)
stw r2, 0(sp)
call z_thread_mark_switched_in
ldw r2, 0(sp)
ldw r3, 4(sp)
ldw r4, 8(sp)
ldw fp, 12(sp)
ldw ra, 16(sp)
addi sp, sp, 20
#endif
ret
/* void z_thread_entry_wrapper(void)
*/
SECTION_FUNC(TEXT, z_thread_entry_wrapper)
/* This all corresponds to struct init_stack_frame defined in
* thread.c. We need to take this stuff off the stack and put
* it in the appropriate registers
*/
/* Can't return from here, just put NULL in ra */
movi ra, 0
/* Calling convention has first 4 arguments in registers r4-r7. */
ldw r4, 0(sp)
ldw r5, 4(sp)
ldw r6, 8(sp)
ldw r7, 12(sp)
/* pop all the stuff that we just loaded into registers */
addi sp, sp, 16
call z_thread_entry