1
0
mirror of https://github.com/RIOT-OS/RIOT.git synced 2025-12-25 14:33:52 +01:00

cpu/msp430_common: fix thread_yield_higher() when called in isr

This commit is contained in:
Kaspar Schleiser 2020-07-27 22:58:17 +02:00
parent 22e9ba12a3
commit 1d46cf70eb

View File

@ -14,23 +14,49 @@
#include "thread.h"
/*
* we must prevent the compiler to generate a prologue or an epilogue
* for thread_yield_higher(), since we rely on the RETI instruction at the end
* of its execution, in the inlined __restore_context() sub-function
* This function can both be called from ISR and from thread context.
*
* In both cases, the caller will use "CALL", which pushes the return
* address on the stack before executing the function's first instruction.
*
* If called within ISR, just set sched_context_switch_request and
* directly return to the call site. A regular function return does this.
*
* If called from stack context, it needs to prepare the stack so it looks exactly
* as if the thread had been interrupted by an ISR, which requires the SR to be on
* stack right after the return address. So we do this manually.
* __save_context() will then save the remaining registers, then store the stack
* pointer in the thread's thread_t.
*
* At this point, the thread context is properly saved. sched_run (possibly) changes
* the currently active thread, which __restore_context() then restores, resuming
* execution at the call site using reti.
*
*/
__attribute__((naked)) void thread_yield_higher(void)
void thread_yield_higher(void)
{
__asm__("push r2"); /* save SR */
irq_disable();
if (irq_is_in()) {
sched_context_switch_request = 1;
}
else {
__asm__ volatile (
"push r2" "\n\t" /* save SR */
"dint" "\n\t" /* reti will restore SR, and thus, IRQ state */
"nop" "\n\t" /* dint takes an additional CPU cycle to take into effect */
: /* no outputs */
: /* no inputs */
: /* no clobbers */
);
__save_context();
__save_context();
/* have sched_active_thread point to the next thread */
sched_run();
/* have sched_active_thread point to the next thread */
sched_run();
__restore_context();
__restore_context();
UNREACHABLE();
UNREACHABLE();
}
}
/* This function calculates the ISR_usage */