4 * This file is part of BeRTOS.
6 * Bertos is free software; you can redistribute it and/or modify
7 * it under the terms of the GNU General Public License as published by
8 * the Free Software Foundation; either version 2 of the License, or
9 * (at your option) any later version.
11 * This program is distributed in the hope that it will be useful,
12 * but WITHOUT ANY WARRANTY; without even the implied warranty of
13 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
14 * GNU General Public License for more details.
16 * You should have received a copy of the GNU General Public License
17 * along with this program; if not, write to the Free Software
18 * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
20 * As a special exception, you may use this file as part of a free software
21 * library without restriction. Specifically, if other files instantiate
22 * templates or use macros or inline functions from this file, or you compile
23 * this file and link it with other files to produce an executable, this
24 * file does not by itself cause the resulting executable to be covered by
25 * the GNU General Public License. This exception does not however
26 * invalidate any other reasons why the executable file might be covered by
27 * the GNU General Public License.
29 * Copyright 2008 Develer S.r.l. (http://www.develer.com/)
33 * \brief Kernel scheduler macros.
37 * \author Francesco Sacchi <batt@develer.com>
38 * \author Stefano Fedrigo <aleph@develer.com>
41 #ifndef CPU_ARM_HW_SWITCH_H
42 #define CPU_ARM_HW_SWITCH_H
44 #include <kern/proc_p.h>
47 * Interrupt entry point.
48 * Needed because AT91 uses an Interrupt Controller with auto-vectoring.
50 #define SCHEDULER_IRQ_ENTRY \
51 asm volatile("sub lr, lr, #4 \n\t" /* Adjust LR */ \
52 "stmfd sp!, {r0} \n\t" /* Save r0 */ \
53 "stmfd sp, {sp}^ \n\t" /* Save user SP */ \
54 "sub sp, sp, #4 \n\t" /* Decrement irq SP, writeback is illegal */ \
55 "ldmfd sp!, {r0} \n\t" /* Restore user SP immedately in r0 */ \
56 "stmfd r0!, {lr} \n\t" /* Store system LR in user stack */ \
57 "stmfd r0, {r1-r12,lr}^ \n\t" /* Store registers on user stack (user LR too) */ \
58 "sub r0, r0, #52 \n\t" /* Decrement r0, writeback is illegal */ \
59 "ldmfd sp!, {r1} \n\t" /* Restore r0 */ \
60 "stmfd r0!, {r1} \n\t" /* Store r0 in user stack too */ \
61 "mrs r1, spsr \n\t" /* Save SPSR... */ \
62 "stmfd r0!, {r1} \n\t" /* ... in user stack */ \
63 "ldr r1, =CurrentProcess \n\t" /* Load in r1 &CurrentProcess->stack */ \
64 "ldr r1, [r1, %0] \n\t" \
65 "str r0, [r1] \n\t" /* Store the process SP */ \
66 "sub fp, sp, #4 \n\t" /* Store the process SP */ \
68 : "n" (offsetof(Process, stack)) \
72 #define SCHEDULER_IRQ_EXIT \
73 asm volatile("ldr lr, =CurrentProcess \n\t" /* Load &CurrentProcess->stack */ \
74 "ldr lr, [lr, %0] \n\t" \
75 "ldr lr, [lr] \n\t" /* Load current process SP */ \
76 "ldr r0, =0xFFFFF000 \n\t" /* End of interrupt for AT91 */ \
77 "str r0, [r0, #0x130] \n\t" /* */ \
78 "ldmfd lr!, {r0} \n\t" /* Pop status reg */ \
79 "msr spsr, r0 \n\t" /* ... */ \
80 "ldmfd lr, {r0-r12,lr}^ \n\t" /* Restore user regs */ \
81 "add lr, lr, #56 \n\t" /* 52 + irq link register (extracted below) */ \
82 "stmfd sp!, {lr} \n\t" /* Push user stack pointer in irq stack */ \
83 "ldmfd sp, {sp}^ \n\t" /* Restore user SP */ \
84 "sub sp, sp, #4 \n\t" /* Align irq SP */ \
85 "ldmdb lr, {pc}^ \n\t" /* And return to user space (We use ldmdb cause lr is sp+4) */ \
87 : "n" (offsetof(Process, stack)) \
90 #endif /* CPU_ARM_HW_SWITCH_H */