diff --git a/cpu/msp430-common/cpu.c b/cpu/msp430-common/cpu.c index 6442f873e2..b332d2b46b 100644 --- a/cpu/msp430-common/cpu.c +++ b/cpu/msp430-common/cpu.c @@ -1,12 +1,14 @@ /* - * Copyright (C) 2013, Freie Universitaet Berlin (FUB). All rights reserved. - + * Copyright (C) 2014, Freie Universitaet Berlin (FUB) & INRIA. + * All rights reserved. + * * This file is subject to the terms and conditions of the GNU Lesser * General Public License v2.1. See the file LICENSE in the top level * directory for more details. */ #include "cpu.h" +#include "irq.h" #include "kernel.h" #include "kernel_internal.h" #include "sched.h" @@ -16,16 +18,27 @@ volatile int __inISR = 0; char __isr_stack[MSP430_ISR_STACK_SIZE]; -void thread_yield(void) +/* + * we must prevent the compiler to generate a prologue or an epilogue + * for thread_yield(), since we rely on the RETI instruction at the end + * of its execution, in the inlined __restore_context() sub-function + */ +__attribute__((naked)) void thread_yield(void) { + /* + * disable IRQ, remembering if they are + * to be reactivated after context switch + */ + unsigned int irqen = disableIRQ(); + __save_context(); - dINT(); /* have sched_active_thread point to the next thread */ sched_run(); - eINT(); - __restore_context(); + __restore_context(irqen); + + UNREACHABLE(); } NORETURN void cpu_switch_context_exit(void) @@ -33,7 +46,7 @@ NORETURN void cpu_switch_context_exit(void) sched_active_thread = sched_threads[0]; sched_run(); - __restore_context(); + __restore_context(GIE); UNREACHABLE(); } diff --git a/cpu/msp430-common/include/cpu.h b/cpu/msp430-common/include/cpu.h index d8e304fd75..c2c8fef269 100644 --- a/cpu/msp430-common/include/cpu.h +++ b/cpu/msp430-common/include/cpu.h @@ -1,5 +1,6 @@ /* - * Copyright (C) 2013, Freie Universitaet Berlin (FUB). All rights reserved. + * Copyright (C) 2014, Freie Universitaet Berlin (FUB) & INRIA. + * All rights reserved. * * This file is subject to the terms and conditions of the GNU Lesser * General Public License v2.1. See the file LICENSE in the top level @@ -99,9 +100,22 @@ inline void __save_context(void) __save_context_isr(); } -inline void __restore_context(void) +inline void __restore_context(unsigned int irqen) { __restore_context_isr(); + + /* + * we want to enable appropriate IRQs *just after* + * quitting the interrupt handler; to that end, + * we change the GIE bit in the value to be restored + * in R2 (a.k.a. SR) by the next RETI instruction + */ + if (irqen) { + __asm__("bis.w #8, 0(r1)"); + } else { + __asm__("bic.w #8, 0(r1)"); + } + __asm__("reti"); }