You can not select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
73 lines
2.3 KiB
73 lines
2.3 KiB
/* |
|
* Copyright (c) 2018 Linaro, Limited |
|
* |
|
* SPDX-License-Identifier: Apache-2.0 |
|
*/ |
|
|
|
#include <kernel.h> |
|
#include <toolchain.h> |
|
#include <kernel_structs.h> |
|
|
|
#ifdef CONFIG_EXECUTION_BENCHMARKING |
|
extern void read_timer_start_of_swap(void); |
|
#endif |
|
extern const int _k_neg_eagain; |
|
|
|
/** |
|
* |
|
* @brief Initiate a cooperative context switch |
|
* |
|
* The __swap() routine is invoked by various kernel services to effect |
|
* a cooperative context context switch. Prior to invoking __swap(), the caller |
|
* disables interrupts via irq_lock() and the return 'key' is passed as a |
|
* parameter to __swap(). The 'key' actually represents the BASEPRI register |
|
* prior to disabling interrupts via the BASEPRI mechanism. |
|
* |
|
* __swap() itself does not do much. |
|
* |
|
* It simply stores the intlock key (the BASEPRI value) parameter into |
|
* current->basepri, and then triggers a PendSV exception, which does |
|
* the heavy lifting of context switching. |
|
|
|
* This is the only place we have to save BASEPRI since the other paths to |
|
* __pendsv all come from handling an interrupt, which means we know the |
|
* interrupts were not locked: in that case the BASEPRI value is 0. |
|
* |
|
* Given that __swap() is called to effect a cooperative context switch, |
|
* only the caller-saved integer registers need to be saved in the thread of the |
|
* outgoing thread. This is all performed by the hardware, which stores it in |
|
* its exception stack frame, created when handling the __pendsv exception. |
|
* |
|
* On ARMv6-M, the intlock key is represented by the PRIMASK register, |
|
* as BASEPRI is not available. |
|
* |
|
* @return -EAGAIN, or a return value set by a call to |
|
* z_arch_thread_return_value_set() |
|
* |
|
*/ |
|
int __swap(int key) |
|
{ |
|
#ifdef CONFIG_EXECUTION_BENCHMARKING |
|
read_timer_start_of_swap(); |
|
#endif |
|
|
|
/* store off key and return value */ |
|
_current->arch.basepri = key; |
|
_current->arch.swap_return_value = _k_neg_eagain; |
|
|
|
#if defined(CONFIG_CPU_CORTEX_M) |
|
/* set pending bit to make sure we will take a PendSV exception */ |
|
SCB->ICSR |= SCB_ICSR_PENDSVSET_Msk; |
|
|
|
/* clear mask or enable all irqs to take a pendsv */ |
|
irq_unlock(0); |
|
#elif defined(CONFIG_CPU_CORTEX_R) |
|
cortex_r_svc(); |
|
irq_unlock(key); |
|
#endif |
|
|
|
/* Context switch is performed here. Returning implies the |
|
* thread has been context-switched-in again. |
|
*/ |
|
return _current->arch.swap_return_value; |
|
}
|
|
|