2016-06-17 13:09:40 -07:00
|
|
|
/*
|
|
|
|
* Copyright (c) 2016 Intel Corporation
|
|
|
|
*
|
|
|
|
* Licensed 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.
|
|
|
|
*/
|
|
|
|
|
|
|
|
#define _ASMLANGUAGE
|
|
|
|
#include <arch/nios2/asm.h>
|
|
|
|
#include <nano_private.h>
|
|
|
|
#include <offsets.h>
|
|
|
|
|
|
|
|
/* exports */
|
|
|
|
GTEXT(_Swap)
|
|
|
|
GTEXT(_thread_entry_wrapper)
|
|
|
|
|
2016-06-29 16:29:15 -07:00
|
|
|
/* imports */
|
|
|
|
GTEXT(_sys_k_event_logger_context_switch)
|
2016-10-25 11:47:52 -07:00
|
|
|
GTEXT(_get_next_ready_thread)
|
|
|
|
GTEXT(_k_neg_eagain)
|
2016-06-29 16:29:15 -07:00
|
|
|
|
2016-06-17 13:09:40 -07:00
|
|
|
/* unsigned int _Swap(unsigned int key)
|
|
|
|
*
|
|
|
|
* Always called with interrupts locked
|
|
|
|
*/
|
|
|
|
SECTION_FUNC(exception.other, _Swap)
|
|
|
|
|
|
|
|
/* Get a reference to _nanokernel in r10 */
|
|
|
|
movhi r10, %hi(_nanokernel)
|
|
|
|
ori r10, r10, %lo(_nanokernel)
|
|
|
|
|
|
|
|
/* Get the pointer to nanokernel->current */
|
|
|
|
ldw r11, __tNANO_current_OFFSET(r10)
|
|
|
|
|
|
|
|
/* Store all the callee saved registers. We either got here via
|
|
|
|
* an exception or from a cooperative invocation of _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, __tTCS_coopReg_OFFSET + __t_coop_r16_OFFSET(r11)
|
|
|
|
stw r17, __tTCS_coopReg_OFFSET + __t_coop_r17_OFFSET(r11)
|
|
|
|
stw r18, __tTCS_coopReg_OFFSET + __t_coop_r18_OFFSET(r11)
|
|
|
|
stw r19, __tTCS_coopReg_OFFSET + __t_coop_r19_OFFSET(r11)
|
|
|
|
stw r20, __tTCS_coopReg_OFFSET + __t_coop_r20_OFFSET(r11)
|
|
|
|
stw r21, __tTCS_coopReg_OFFSET + __t_coop_r21_OFFSET(r11)
|
|
|
|
stw r22, __tTCS_coopReg_OFFSET + __t_coop_r22_OFFSET(r11)
|
|
|
|
stw r23, __tTCS_coopReg_OFFSET + __t_coop_r23_OFFSET(r11)
|
|
|
|
stw r28, __tTCS_coopReg_OFFSET + __t_coop_r28_OFFSET(r11)
|
|
|
|
stw ra, __tTCS_coopReg_OFFSET + __t_coop_ra_OFFSET(r11)
|
|
|
|
stw sp, __tTCS_coopReg_OFFSET + __t_coop_sp_OFFSET(r11)
|
|
|
|
|
|
|
|
/* r4 has the 'key' argument which is the result of irq_lock()
|
|
|
|
* before this was called
|
|
|
|
*/
|
|
|
|
stw r4, __tTCS_coopReg_OFFSET + __t_coop_key_OFFSET(r11)
|
|
|
|
|
2016-10-25 11:47:52 -07:00
|
|
|
/* Populate default return value */
|
|
|
|
movhi r5, %hi(_k_neg_eagain)
|
|
|
|
ori r5, r5, %lo(_k_neg_eagain)
|
|
|
|
ldw r4, (r5)
|
|
|
|
stw r4, __tTCS_coopReg_OFFSET + __t_coop_retval_OFFSET(r11)
|
|
|
|
|
2016-06-29 16:29:15 -07:00
|
|
|
#if CONFIG_KERNEL_EVENT_LOGGER_CONTEXT_SWITCH
|
|
|
|
call _sys_k_event_logger_context_switch
|
2016-07-12 09:54:54 -07:00
|
|
|
/* Restore caller-saved r10. We could have stuck its value
|
|
|
|
* onto the stack, but less instructions to just use immediates
|
|
|
|
*/
|
|
|
|
movhi r10, %hi(_nanokernel)
|
|
|
|
ori r10, r10, %lo(_nanokernel)
|
2016-10-25 11:47:52 -07:00
|
|
|
#endif /* CONFIG_KERNEL_EVENT_LOGGER_CONTEXT_SWITCH */
|
2016-06-17 13:09:40 -07:00
|
|
|
|
2016-10-25 11:47:52 -07:00
|
|
|
/* Assign to _nanokernel.current the return value of
|
|
|
|
* _get_next_ready_thread()
|
|
|
|
*/
|
|
|
|
call _get_next_ready_thread
|
|
|
|
movhi r10, %hi(_nanokernel)
|
|
|
|
ori r10, r10, %lo(_nanokernel)
|
|
|
|
stw r2, __tNANO_current_OFFSET(r10)
|
|
|
|
|
|
|
|
/* At this point r2 points to the next thread to be swapped in */
|
2016-06-17 13:09:40 -07:00
|
|
|
|
|
|
|
/* Restore callee-saved registers and switch to the incoming
|
|
|
|
* thread's stack
|
|
|
|
*/
|
2016-10-25 11:47:52 -07:00
|
|
|
ldw r16, __tTCS_coopReg_OFFSET + __t_coop_r16_OFFSET(r2)
|
|
|
|
ldw r17, __tTCS_coopReg_OFFSET + __t_coop_r17_OFFSET(r2)
|
|
|
|
ldw r18, __tTCS_coopReg_OFFSET + __t_coop_r18_OFFSET(r2)
|
|
|
|
ldw r19, __tTCS_coopReg_OFFSET + __t_coop_r19_OFFSET(r2)
|
|
|
|
ldw r20, __tTCS_coopReg_OFFSET + __t_coop_r20_OFFSET(r2)
|
|
|
|
ldw r21, __tTCS_coopReg_OFFSET + __t_coop_r21_OFFSET(r2)
|
|
|
|
ldw r22, __tTCS_coopReg_OFFSET + __t_coop_r22_OFFSET(r2)
|
|
|
|
ldw r23, __tTCS_coopReg_OFFSET + __t_coop_r23_OFFSET(r2)
|
|
|
|
ldw r28, __tTCS_coopReg_OFFSET + __t_coop_r28_OFFSET(r2)
|
|
|
|
ldw ra, __tTCS_coopReg_OFFSET + __t_coop_ra_OFFSET(r2)
|
|
|
|
ldw sp, __tTCS_coopReg_OFFSET + __t_coop_sp_OFFSET(r2)
|
|
|
|
|
|
|
|
/* We need to irq_unlock(current->coopReg.key);
|
|
|
|
* key was supplied as argument to _Swap(). Fetch it.
|
|
|
|
*/
|
|
|
|
ldw r3, __tTCS_coopReg_OFFSET + __t_coop_key_OFFSET(r2)
|
|
|
|
|
|
|
|
/* Load return value into r2 (return value register). -EAGAIN
|
2016-06-23 20:10:01 -07:00
|
|
|
* unless someone previously called fiberRtnValueSet(). Do this
|
|
|
|
* before we potentially unlock interrupts.
|
|
|
|
*/
|
2016-10-25 11:47:52 -07:00
|
|
|
ldw r2, __tTCS_coopReg_OFFSET + __t_coop_retval_OFFSET(r2)
|
2016-06-23 20:10:01 -07:00
|
|
|
|
2016-10-25 11:47:52 -07:00
|
|
|
/* Now do irq_unlock(current->coopReg.key) */
|
2016-07-11 12:42:02 -07:00
|
|
|
#if (ALT_CPU_NUM_OF_SHADOW_REG_SETS > 0) || \
|
|
|
|
(defined ALT_CPU_EIC_PRESENT) || \
|
|
|
|
(defined ALT_CPU_MMU_PRESENT) || \
|
|
|
|
(defined ALT_CPU_MPU_PRESENT)
|
2016-06-23 20:10:01 -07:00
|
|
|
andi r3, r3, NIOS2_STATUS_PIE_MSK
|
2016-06-17 13:09:40 -07:00
|
|
|
beq r3, zero, no_unlock
|
|
|
|
rdctl r3, status
|
|
|
|
ori r3, r3, NIOS2_STATUS_PIE_MSK
|
|
|
|
wrctl status, r3
|
|
|
|
|
2016-08-18 09:25:00 -07:00
|
|
|
no_unlock:
|
2016-06-24 07:56:48 -07:00
|
|
|
#else
|
|
|
|
wrctl status, r3
|
|
|
|
#endif
|
2016-06-17 13:09:40 -07:00
|
|
|
ret
|
|
|
|
|
|
|
|
|
|
|
|
/* void _thread_entry_wrapper(void)
|
|
|
|
*/
|
|
|
|
SECTION_FUNC(TEXT, _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 apporpriate 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 _thread_entry
|
|
|
|
|