blob: 5afb8294ee8030b27a09a3cdf98d3940b4df7247 [file] [log] [blame]
/*
* 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;
/* The 'key' actually represents the BASEPRI register
* prior to disabling interrupts via the BASEPRI mechanism.
*
* z_arch_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
* z_arm_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 z_arch_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 z_arm_pendsv exception.
*
* On ARMv6-M, the intlock key is represented by the PRIMASK register,
* as BASEPRI is not available.
*/
int z_arch_swap(unsigned 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)
z_arm_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;
}