Rev 2355 | Rev 2408 | Go to most recent revision | Show entire file | Ignore whitespace | Details | Blame | Last modification | View Log | RSS feed
Rev 2355 | Rev 2407 | ||
---|---|---|---|
Line 42... | Line 42... | ||
42 | #include <arch/machine.h> |
42 | #include <arch/machine.h> |
43 | #include <arch/mm/page_fault.h> |
43 | #include <arch/mm/page_fault.h> |
44 | #include <print.h> |
44 | #include <print.h> |
45 | #include <syscall/syscall.h> |
45 | #include <syscall/syscall.h> |
46 | 46 | ||
- | 47 | /** Offset used in calculation of exception handler's relative address. |
|
47 | 48 | * |
|
- | 49 | * @see install_handler() |
|
- | 50 | */ |
|
48 | #define PREFETCH_OFFSET 0x8 |
51 | #define PREFETCH_OFFSET 0x8 |
- | 52 | ||
49 | #define BRANCH_OPCODE 0xea000000 |
53 | /** LDR instruction's code */ |
50 | #define LDR_OPCODE 0xe59ff000 |
54 | #define LDR_OPCODE 0xe59ff000 |
51 | #define VALID_BRANCH_MASK 0xff000000 |
- | |
52 | #define EXC_VECTORS_SIZE 0x20 |
- | |
53 | #define EXC_VECTORS 0x8 |
- | |
54 | 55 | ||
- | 56 | /** Number of exception vectors. */ |
|
- | 57 | #define EXC_VECTORS 8 |
|
55 | 58 | ||
- | 59 | /** Size of memory block occupied by exception vectors. */ |
|
- | 60 | #define EXC_VECTORS_SIZE (EXC_VECTORS * 4) |
|
- | 61 | ||
- | 62 | ||
- | 63 | /** Kernel stack pointer. |
|
- | 64 | * |
|
- | 65 | * It is set when thread switches to user mode, |
|
- | 66 | * and then used for exception handling. |
|
- | 67 | */ |
|
56 | extern uintptr_t supervisor_sp; |
68 | extern uintptr_t supervisor_sp; |
- | 69 | ||
- | 70 | /** Temporary exception stack pointer. |
|
- | 71 | * |
|
- | 72 | * Temporary stack is used in exceptions handling routines |
|
- | 73 | * before switching to thread's kernel stack. |
|
- | 74 | */ |
|
57 | extern uintptr_t exc_stack; |
75 | extern uintptr_t exc_stack; |
58 | 76 | ||
- | 77 | ||
59 | /** Switches to kernel stack and saves all registers there. |
78 | /** Switches to kernel stack and saves all registers there. |
60 | * |
79 | * |
61 | * Temporary exception stack is used to save a few registers |
80 | * Temporary exception stack is used to save a few registers |
62 | * before stack switch takes place. |
81 | * before stack switch takes place. |
63 | */ |
82 | */ |
Line 111... | Line 130... | ||
111 | mov r13, r1 \n\ |
130 | mov r13, r1 \n\ |
112 | 2:" |
131 | 2:" |
113 | ); |
132 | ); |
114 | } |
133 | } |
115 | 134 | ||
- | 135 | ||
116 | /** Returns from exception mode. |
136 | /** Returns from exception mode. |
117 | * |
137 | * |
118 | * Previously saved state of registers (including control register) |
138 | * Previously saved state of registers (including control register) |
119 | * is restored from the stack. |
139 | * is restored from the stack. |
120 | */ |
140 | */ |
Line 146... | Line 166... | ||
146 | @actual return \n\ |
166 | @actual return \n\ |
147 | 4: ldmfd r13, {r0-r12, pc}^" |
167 | 4: ldmfd r13, {r0-r12, pc}^" |
148 | ); |
168 | ); |
149 | } |
169 | } |
150 | 170 | ||
- | 171 | /** Switch CPU to mode in which interrupts are serviced (currently it |
|
- | 172 | * is Undefined mode). |
|
- | 173 | * |
|
- | 174 | * The default mode for interrupt servicing (Interrupt Mode) |
|
- | 175 | * can not be used because of nested interrupts (which can occur |
|
- | 176 | * because interrupt are enabled in higher levels of interrupt handler). |
|
- | 177 | */ |
|
- | 178 | inline static void switchToIrqServicingMode() |
|
- | 179 | { |
|
- | 180 | /* switch to Undefined mode */ |
|
- | 181 | asm volatile( |
|
- | 182 | /* save regs used during switching */ |
|
- | 183 | "stmfd sp!, {r0-r3} \n" |
|
- | 184 | ||
- | 185 | /* save stack pointer and link register to r1, r2 */ |
|
- | 186 | "mov r1, sp \n" |
|
- | 187 | "mov r2, lr \n" |
|
- | 188 | ||
- | 189 | /* mode switch */ |
|
- | 190 | "mrs r0, cpsr \n" |
|
- | 191 | "bic r0, r0, #0x1f \n" |
|
- | 192 | "orr r0, r0, #0x1b \n" |
|
- | 193 | "msr cpsr_c, r0 \n" |
|
- | 194 | ||
- | 195 | /* restore saved sp and lr */ |
|
- | 196 | "mov sp, r1 \n" |
|
- | 197 | "mov lr, r2 \n" |
|
- | 198 | ||
- | 199 | /* restore original regs */ |
|
- | 200 | "ldmfd sp!, {r0-r3} \n" |
|
- | 201 | ); |
|
- | 202 | } |
|
- | 203 | ||
151 | /** Calls exception dispatch routine. */ |
204 | /** Calls exception dispatch routine. */ |
152 | #define CALL_EXC_DISPATCH(exception) \ |
205 | #define CALL_EXC_DISPATCH(exception) \ |
153 | asm("mov r0, %0" : : "i" (exception)); \ |
206 | asm("mov r0, %0" : : "i" (exception)); \ |
154 | asm("mov r1, r13"); \ |
207 | asm("mov r1, r13"); \ |
155 | asm("bl exc_dispatch"); |
208 | asm("bl exc_dispatch"); |
156 | 209 | ||
157 | 210 | ||
158 | /** General exception handler. |
211 | /** General exception handler. |
159 | * |
212 | * |
160 | * Stores registers, dispatches the exception, |
213 | * Stores registers, dispatches the exception, |
161 | * and finally restores registers and returns from exception processing. |
214 | * and finally restores registers and returns from exception processing. |
162 | * |
215 | * |
Line 240... | Line 293... | ||
240 | */ |
293 | */ |
241 | static void irq_exception_entry() |
294 | static void irq_exception_entry() |
242 | { |
295 | { |
243 | asm("sub lr, lr, #4"); |
296 | asm("sub lr, lr, #4"); |
244 | setup_stack_and_save_regs(); |
297 | setup_stack_and_save_regs(); |
245 | 298 | ||
246 | /* switch to Undefined mode */ |
299 | switchToIrqServicingMode(); |
247 | asm("stmfd sp!, {r0-r3}"); |
- | |
248 | asm("mov r1, sp"); |
- | |
249 | asm("mov r2, lr"); |
- | |
250 | asm("mrs r0, cpsr"); |
- | |
251 | asm("bic r0, r0, #0x1f"); |
- | |
252 | asm("orr r0, r0, #0x1b"); |
- | |
253 | asm("msr cpsr_c, r0"); |
- | |
254 | asm("mov sp, r1"); |
- | |
255 | asm("mov lr, r2"); |
- | |
256 | asm("ldmfd sp!, {r0-r3}"); |
- | |
257 | 300 | ||
258 | CALL_EXC_DISPATCH(EXC_IRQ) |
301 | CALL_EXC_DISPATCH(EXC_IRQ) |
259 | 302 | ||
260 | load_regs(); |
303 | load_regs(); |
261 | } |
304 | } |
262 | 305 |