diff options
author | Haavard Skinnemoen <hskinnemoen@atmel.com> | 2006-09-26 02:32:13 -0400 |
---|---|---|
committer | Linus Torvalds <torvalds@g5.osdl.org> | 2006-09-26 11:48:54 -0400 |
commit | 5f97f7f9400de47ae837170bb274e90ad3934386 (patch) | |
tree | 514451e6dc6b46253293a00035d375e77b1c65ed /arch/avr32/kernel/entry-avr32b.S | |
parent | 53e62d3aaa60590d4a69b4e07c29f448b5151047 (diff) |
[PATCH] avr32 architecture
This adds support for the Atmel AVR32 architecture as well as the AT32AP7000
CPU and the AT32STK1000 development board.
AVR32 is a new high-performance 32-bit RISC microprocessor core, designed for
cost-sensitive embedded applications, with particular emphasis on low power
consumption and high code density. The AVR32 architecture is not binary
compatible with earlier 8-bit AVR architectures.
The AVR32 architecture, including the instruction set, is described by the
AVR32 Architecture Manual, available from
http://www.atmel.com/dyn/resources/prod_documents/doc32000.pdf
The Atmel AT32AP7000 is the first CPU implementing the AVR32 architecture. It
features a 7-stage pipeline, 16KB instruction and data caches and a full
Memory Management Unit. It also comes with a large set of integrated
peripherals, many of which are shared with the AT91 ARM-based controllers from
Atmel.
Full data sheet is available from
http://www.atmel.com/dyn/resources/prod_documents/doc32003.pdf
while the CPU core implementation including caches and MMU is documented by
the AVR32 AP Technical Reference, available from
http://www.atmel.com/dyn/resources/prod_documents/doc32001.pdf
Information about the AT32STK1000 development board can be found at
http://www.atmel.com/dyn/products/tools_card.asp?tool_id=3918
including a BSP CD image with an earlier version of this patch, development
tools (binaries and source/patches) and a root filesystem image suitable for
booting from SD card.
Alternatively, there's a preliminary "getting started" guide available at
http://avr32linux.org/twiki/bin/view/Main/GettingStarted which provides links
to the sources and patches you will need in order to set up a cross-compiling
environment for avr32-linux.
This patch, as well as the other patches included with the BSP and the
toolchain patches, is actively supported by Atmel Corporation.
[dmccr@us.ibm.com: Fix more pxx_page macro locations]
[bunk@stusta.de: fix `make defconfig']
Signed-off-by: Haavard Skinnemoen <hskinnemoen@atmel.com>
Signed-off-by: Adrian Bunk <bunk@stusta.de>
Signed-off-by: Dave McCracken <dmccr@us.ibm.com>
Signed-off-by: Andrew Morton <akpm@osdl.org>
Signed-off-by: Linus Torvalds <torvalds@osdl.org>
Diffstat (limited to 'arch/avr32/kernel/entry-avr32b.S')
-rw-r--r-- | arch/avr32/kernel/entry-avr32b.S | 678 |
1 files changed, 678 insertions, 0 deletions
diff --git a/arch/avr32/kernel/entry-avr32b.S b/arch/avr32/kernel/entry-avr32b.S new file mode 100644 index 000000000000..eeb66792bc37 --- /dev/null +++ b/arch/avr32/kernel/entry-avr32b.S | |||
@@ -0,0 +1,678 @@ | |||
1 | /* | ||
2 | * Copyright (C) 2004-2006 Atmel Corporation | ||
3 | * | ||
4 | * This program is free software; you can redistribute it and/or modify | ||
5 | * it under the terms of the GNU General Public License version 2 as | ||
6 | * published by the Free Software Foundation. | ||
7 | */ | ||
8 | |||
9 | /* | ||
10 | * This file contains the low-level entry-points into the kernel, that is, | ||
11 | * exception handlers, debug trap handlers, interrupt handlers and the | ||
12 | * system call handler. | ||
13 | */ | ||
14 | #include <linux/errno.h> | ||
15 | |||
16 | #include <asm/asm.h> | ||
17 | #include <asm/hardirq.h> | ||
18 | #include <asm/irq.h> | ||
19 | #include <asm/ocd.h> | ||
20 | #include <asm/page.h> | ||
21 | #include <asm/pgtable.h> | ||
22 | #include <asm/ptrace.h> | ||
23 | #include <asm/sysreg.h> | ||
24 | #include <asm/thread_info.h> | ||
25 | #include <asm/unistd.h> | ||
26 | |||
27 | #ifdef CONFIG_PREEMPT | ||
28 | # define preempt_stop mask_interrupts | ||
29 | #else | ||
30 | # define preempt_stop | ||
31 | # define fault_resume_kernel fault_restore_all | ||
32 | #endif | ||
33 | |||
34 | #define __MASK(x) ((1 << (x)) - 1) | ||
35 | #define IRQ_MASK ((__MASK(SOFTIRQ_BITS) << SOFTIRQ_SHIFT) | \ | ||
36 | (__MASK(HARDIRQ_BITS) << HARDIRQ_SHIFT)) | ||
37 | |||
38 | .section .ex.text,"ax",@progbits | ||
39 | .align 2 | ||
40 | exception_vectors: | ||
41 | bral handle_critical | ||
42 | .align 2 | ||
43 | bral handle_critical | ||
44 | .align 2 | ||
45 | bral do_bus_error_write | ||
46 | .align 2 | ||
47 | bral do_bus_error_read | ||
48 | .align 2 | ||
49 | bral do_nmi_ll | ||
50 | .align 2 | ||
51 | bral handle_address_fault | ||
52 | .align 2 | ||
53 | bral handle_protection_fault | ||
54 | .align 2 | ||
55 | bral handle_debug | ||
56 | .align 2 | ||
57 | bral do_illegal_opcode_ll | ||
58 | .align 2 | ||
59 | bral do_illegal_opcode_ll | ||
60 | .align 2 | ||
61 | bral do_illegal_opcode_ll | ||
62 | .align 2 | ||
63 | bral do_fpe_ll | ||
64 | .align 2 | ||
65 | bral do_illegal_opcode_ll | ||
66 | .align 2 | ||
67 | bral handle_address_fault | ||
68 | .align 2 | ||
69 | bral handle_address_fault | ||
70 | .align 2 | ||
71 | bral handle_protection_fault | ||
72 | .align 2 | ||
73 | bral handle_protection_fault | ||
74 | .align 2 | ||
75 | bral do_dtlb_modified | ||
76 | |||
77 | /* | ||
78 | * r0 : PGD/PT/PTE | ||
79 | * r1 : Offending address | ||
80 | * r2 : Scratch register | ||
81 | * r3 : Cause (5, 12 or 13) | ||
82 | */ | ||
83 | #define tlbmiss_save pushm r0-r3 | ||
84 | #define tlbmiss_restore popm r0-r3 | ||
85 | |||
86 | .section .tlbx.ex.text,"ax",@progbits | ||
87 | .global itlb_miss | ||
88 | itlb_miss: | ||
89 | tlbmiss_save | ||
90 | rjmp tlb_miss_common | ||
91 | |||
92 | .section .tlbr.ex.text,"ax",@progbits | ||
93 | dtlb_miss_read: | ||
94 | tlbmiss_save | ||
95 | rjmp tlb_miss_common | ||
96 | |||
97 | .section .tlbw.ex.text,"ax",@progbits | ||
98 | dtlb_miss_write: | ||
99 | tlbmiss_save | ||
100 | |||
101 | .global tlb_miss_common | ||
102 | tlb_miss_common: | ||
103 | mfsr r0, SYSREG_PTBR | ||
104 | mfsr r1, SYSREG_TLBEAR | ||
105 | |||
106 | /* Is it the vmalloc space? */ | ||
107 | bld r1, 31 | ||
108 | brcs handle_vmalloc_miss | ||
109 | |||
110 | /* First level lookup */ | ||
111 | pgtbl_lookup: | ||
112 | lsr r2, r1, PGDIR_SHIFT | ||
113 | ld.w r0, r0[r2 << 2] | ||
114 | bld r0, _PAGE_BIT_PRESENT | ||
115 | brcc page_table_not_present | ||
116 | |||
117 | /* TODO: Check access rights on page table if necessary */ | ||
118 | |||
119 | /* Translate to virtual address in P1. */ | ||
120 | andl r0, 0xf000 | ||
121 | sbr r0, 31 | ||
122 | |||
123 | /* Second level lookup */ | ||
124 | lsl r1, (32 - PGDIR_SHIFT) | ||
125 | lsr r1, (32 - PGDIR_SHIFT) + PAGE_SHIFT | ||
126 | add r2, r0, r1 << 2 | ||
127 | ld.w r1, r2[0] | ||
128 | bld r1, _PAGE_BIT_PRESENT | ||
129 | brcc page_not_present | ||
130 | |||
131 | /* Mark the page as accessed */ | ||
132 | sbr r1, _PAGE_BIT_ACCESSED | ||
133 | st.w r2[0], r1 | ||
134 | |||
135 | /* Drop software flags */ | ||
136 | andl r1, _PAGE_FLAGS_HARDWARE_MASK & 0xffff | ||
137 | mtsr SYSREG_TLBELO, r1 | ||
138 | |||
139 | /* Figure out which entry we want to replace */ | ||
140 | mfsr r0, SYSREG_TLBARLO | ||
141 | clz r2, r0 | ||
142 | brcc 1f | ||
143 | mov r1, -1 /* All entries have been accessed, */ | ||
144 | mtsr SYSREG_TLBARLO, r1 /* so reset TLBAR */ | ||
145 | mov r2, 0 /* and start at 0 */ | ||
146 | 1: mfsr r1, SYSREG_MMUCR | ||
147 | lsl r2, 14 | ||
148 | andl r1, 0x3fff, COH | ||
149 | or r1, r2 | ||
150 | mtsr SYSREG_MMUCR, r1 | ||
151 | |||
152 | tlbw | ||
153 | |||
154 | tlbmiss_restore | ||
155 | rete | ||
156 | |||
157 | handle_vmalloc_miss: | ||
158 | /* Simply do the lookup in init's page table */ | ||
159 | mov r0, lo(swapper_pg_dir) | ||
160 | orh r0, hi(swapper_pg_dir) | ||
161 | rjmp pgtbl_lookup | ||
162 | |||
163 | |||
164 | /* --- System Call --- */ | ||
165 | |||
166 | .section .scall.text,"ax",@progbits | ||
167 | system_call: | ||
168 | pushm r12 /* r12_orig */ | ||
169 | stmts --sp, r0-lr | ||
170 | zero_fp | ||
171 | mfsr r0, SYSREG_RAR_SUP | ||
172 | mfsr r1, SYSREG_RSR_SUP | ||
173 | stm --sp, r0-r1 | ||
174 | |||
175 | /* check for syscall tracing */ | ||
176 | get_thread_info r0 | ||
177 | ld.w r1, r0[TI_flags] | ||
178 | bld r1, TIF_SYSCALL_TRACE | ||
179 | brcs syscall_trace_enter | ||
180 | |||
181 | syscall_trace_cont: | ||
182 | cp.w r8, NR_syscalls | ||
183 | brhs syscall_badsys | ||
184 | |||
185 | lddpc lr, syscall_table_addr | ||
186 | ld.w lr, lr[r8 << 2] | ||
187 | mov r8, r5 /* 5th argument (6th is pushed by stub) */ | ||
188 | icall lr | ||
189 | |||
190 | .global syscall_return | ||
191 | syscall_return: | ||
192 | get_thread_info r0 | ||
193 | mask_interrupts /* make sure we don't miss an interrupt | ||
194 | setting need_resched or sigpending | ||
195 | between sampling and the rets */ | ||
196 | |||
197 | /* Store the return value so that the correct value is loaded below */ | ||
198 | stdsp sp[REG_R12], r12 | ||
199 | |||
200 | ld.w r1, r0[TI_flags] | ||
201 | andl r1, _TIF_ALLWORK_MASK, COH | ||
202 | brne syscall_exit_work | ||
203 | |||
204 | syscall_exit_cont: | ||
205 | popm r8-r9 | ||
206 | mtsr SYSREG_RAR_SUP, r8 | ||
207 | mtsr SYSREG_RSR_SUP, r9 | ||
208 | ldmts sp++, r0-lr | ||
209 | sub sp, -4 /* r12_orig */ | ||
210 | rets | ||
211 | |||
212 | .align 2 | ||
213 | syscall_table_addr: | ||
214 | .long sys_call_table | ||
215 | |||
216 | syscall_badsys: | ||
217 | mov r12, -ENOSYS | ||
218 | rjmp syscall_return | ||
219 | |||
220 | .global ret_from_fork | ||
221 | ret_from_fork: | ||
222 | rcall schedule_tail | ||
223 | |||
224 | /* check for syscall tracing */ | ||
225 | get_thread_info r0 | ||
226 | ld.w r1, r0[TI_flags] | ||
227 | andl r1, _TIF_ALLWORK_MASK, COH | ||
228 | brne syscall_exit_work | ||
229 | rjmp syscall_exit_cont | ||
230 | |||
231 | syscall_trace_enter: | ||
232 | pushm r8-r12 | ||
233 | rcall syscall_trace | ||
234 | popm r8-r12 | ||
235 | rjmp syscall_trace_cont | ||
236 | |||
237 | syscall_exit_work: | ||
238 | bld r1, TIF_SYSCALL_TRACE | ||
239 | brcc 1f | ||
240 | unmask_interrupts | ||
241 | rcall syscall_trace | ||
242 | mask_interrupts | ||
243 | ld.w r1, r0[TI_flags] | ||
244 | |||
245 | 1: bld r1, TIF_NEED_RESCHED | ||
246 | brcc 2f | ||
247 | unmask_interrupts | ||
248 | rcall schedule | ||
249 | mask_interrupts | ||
250 | ld.w r1, r0[TI_flags] | ||
251 | rjmp 1b | ||
252 | |||
253 | 2: mov r2, _TIF_SIGPENDING | _TIF_RESTORE_SIGMASK | ||
254 | tst r1, r2 | ||
255 | breq 3f | ||
256 | unmask_interrupts | ||
257 | mov r12, sp | ||
258 | mov r11, r0 | ||
259 | rcall do_notify_resume | ||
260 | mask_interrupts | ||
261 | ld.w r1, r0[TI_flags] | ||
262 | rjmp 1b | ||
263 | |||
264 | 3: bld r1, TIF_BREAKPOINT | ||
265 | brcc syscall_exit_cont | ||
266 | mfsr r3, SYSREG_TLBEHI | ||
267 | lddsp r2, sp[REG_PC] | ||
268 | andl r3, 0xff, COH | ||
269 | lsl r3, 1 | ||
270 | sbr r3, 30 | ||
271 | sbr r3, 0 | ||
272 | mtdr DBGREG_BWA2A, r2 | ||
273 | mtdr DBGREG_BWC2A, r3 | ||
274 | rjmp syscall_exit_cont | ||
275 | |||
276 | |||
277 | /* The slow path of the TLB miss handler */ | ||
278 | page_table_not_present: | ||
279 | page_not_present: | ||
280 | tlbmiss_restore | ||
281 | sub sp, 4 | ||
282 | stmts --sp, r0-lr | ||
283 | rcall save_full_context_ex | ||
284 | mfsr r12, SYSREG_ECR | ||
285 | mov r11, sp | ||
286 | rcall do_page_fault | ||
287 | rjmp ret_from_exception | ||
288 | |||
289 | /* This function expects to find offending PC in SYSREG_RAR_EX */ | ||
290 | save_full_context_ex: | ||
291 | mfsr r8, SYSREG_RSR_EX | ||
292 | mov r12, r8 | ||
293 | andh r8, (MODE_MASK >> 16), COH | ||
294 | mfsr r11, SYSREG_RAR_EX | ||
295 | brne 2f | ||
296 | |||
297 | 1: pushm r11, r12 /* PC and SR */ | ||
298 | unmask_exceptions | ||
299 | ret r12 | ||
300 | |||
301 | 2: sub r10, sp, -(FRAME_SIZE_FULL - REG_LR) | ||
302 | stdsp sp[4], r10 /* replace saved SP */ | ||
303 | rjmp 1b | ||
304 | |||
305 | /* Low-level exception handlers */ | ||
306 | handle_critical: | ||
307 | pushm r12 | ||
308 | pushm r0-r12 | ||
309 | rcall save_full_context_ex | ||
310 | mfsr r12, SYSREG_ECR | ||
311 | mov r11, sp | ||
312 | rcall do_critical_exception | ||
313 | |||
314 | /* We should never get here... */ | ||
315 | bad_return: | ||
316 | sub r12, pc, (. - 1f) | ||
317 | bral panic | ||
318 | .align 2 | ||
319 | 1: .asciz "Return from critical exception!" | ||
320 | |||
321 | .align 1 | ||
322 | do_bus_error_write: | ||
323 | sub sp, 4 | ||
324 | stmts --sp, r0-lr | ||
325 | rcall save_full_context_ex | ||
326 | mov r11, 1 | ||
327 | rjmp 1f | ||
328 | |||
329 | do_bus_error_read: | ||
330 | sub sp, 4 | ||
331 | stmts --sp, r0-lr | ||
332 | rcall save_full_context_ex | ||
333 | mov r11, 0 | ||
334 | 1: mfsr r12, SYSREG_BEAR | ||
335 | mov r10, sp | ||
336 | rcall do_bus_error | ||
337 | rjmp ret_from_exception | ||
338 | |||
339 | .align 1 | ||
340 | do_nmi_ll: | ||
341 | sub sp, 4 | ||
342 | stmts --sp, r0-lr | ||
343 | /* FIXME: Make sure RAR_NMI and RSR_NMI are pushed instead of *_EX */ | ||
344 | rcall save_full_context_ex | ||
345 | mfsr r12, SYSREG_ECR | ||
346 | mov r11, sp | ||
347 | rcall do_nmi | ||
348 | rjmp bad_return | ||
349 | |||
350 | handle_address_fault: | ||
351 | sub sp, 4 | ||
352 | stmts --sp, r0-lr | ||
353 | rcall save_full_context_ex | ||
354 | mfsr r12, SYSREG_ECR | ||
355 | mov r11, sp | ||
356 | rcall do_address_exception | ||
357 | rjmp ret_from_exception | ||
358 | |||
359 | handle_protection_fault: | ||
360 | sub sp, 4 | ||
361 | stmts --sp, r0-lr | ||
362 | rcall save_full_context_ex | ||
363 | mfsr r12, SYSREG_ECR | ||
364 | mov r11, sp | ||
365 | rcall do_page_fault | ||
366 | rjmp ret_from_exception | ||
367 | |||
368 | .align 1 | ||
369 | do_illegal_opcode_ll: | ||
370 | sub sp, 4 | ||
371 | stmts --sp, r0-lr | ||
372 | rcall save_full_context_ex | ||
373 | mfsr r12, SYSREG_ECR | ||
374 | mov r11, sp | ||
375 | rcall do_illegal_opcode | ||
376 | rjmp ret_from_exception | ||
377 | |||
378 | do_dtlb_modified: | ||
379 | pushm r0-r3 | ||
380 | mfsr r1, SYSREG_TLBEAR | ||
381 | mfsr r0, SYSREG_PTBR | ||
382 | lsr r2, r1, PGDIR_SHIFT | ||
383 | ld.w r0, r0[r2 << 2] | ||
384 | lsl r1, (32 - PGDIR_SHIFT) | ||
385 | lsr r1, (32 - PGDIR_SHIFT) + PAGE_SHIFT | ||
386 | |||
387 | /* Translate to virtual address in P1 */ | ||
388 | andl r0, 0xf000 | ||
389 | sbr r0, 31 | ||
390 | add r2, r0, r1 << 2 | ||
391 | ld.w r3, r2[0] | ||
392 | sbr r3, _PAGE_BIT_DIRTY | ||
393 | mov r0, r3 | ||
394 | st.w r2[0], r3 | ||
395 | |||
396 | /* The page table is up-to-date. Update the TLB entry as well */ | ||
397 | andl r0, lo(_PAGE_FLAGS_HARDWARE_MASK) | ||
398 | mtsr SYSREG_TLBELO, r0 | ||
399 | |||
400 | /* MMUCR[DRP] is updated automatically, so let's go... */ | ||
401 | tlbw | ||
402 | |||
403 | popm r0-r3 | ||
404 | rete | ||
405 | |||
406 | do_fpe_ll: | ||
407 | sub sp, 4 | ||
408 | stmts --sp, r0-lr | ||
409 | rcall save_full_context_ex | ||
410 | unmask_interrupts | ||
411 | mov r12, 26 | ||
412 | mov r11, sp | ||
413 | rcall do_fpe | ||
414 | rjmp ret_from_exception | ||
415 | |||
416 | ret_from_exception: | ||
417 | mask_interrupts | ||
418 | lddsp r4, sp[REG_SR] | ||
419 | andh r4, (MODE_MASK >> 16), COH | ||
420 | brne fault_resume_kernel | ||
421 | |||
422 | get_thread_info r0 | ||
423 | ld.w r1, r0[TI_flags] | ||
424 | andl r1, _TIF_WORK_MASK, COH | ||
425 | brne fault_exit_work | ||
426 | |||
427 | fault_resume_user: | ||
428 | popm r8-r9 | ||
429 | mask_exceptions | ||
430 | mtsr SYSREG_RAR_EX, r8 | ||
431 | mtsr SYSREG_RSR_EX, r9 | ||
432 | ldmts sp++, r0-lr | ||
433 | sub sp, -4 | ||
434 | rete | ||
435 | |||
436 | fault_resume_kernel: | ||
437 | #ifdef CONFIG_PREEMPT | ||
438 | get_thread_info r0 | ||
439 | ld.w r2, r0[TI_preempt_count] | ||
440 | cp.w r2, 0 | ||
441 | brne 1f | ||
442 | ld.w r1, r0[TI_flags] | ||
443 | bld r1, TIF_NEED_RESCHED | ||
444 | brcc 1f | ||
445 | lddsp r4, sp[REG_SR] | ||
446 | bld r4, SYSREG_GM_OFFSET | ||
447 | brcs 1f | ||
448 | rcall preempt_schedule_irq | ||
449 | 1: | ||
450 | #endif | ||
451 | |||
452 | popm r8-r9 | ||
453 | mask_exceptions | ||
454 | mfsr r1, SYSREG_SR | ||
455 | mtsr SYSREG_RAR_EX, r8 | ||
456 | mtsr SYSREG_RSR_EX, r9 | ||
457 | popm lr | ||
458 | sub sp, -4 /* ignore SP */ | ||
459 | popm r0-r12 | ||
460 | sub sp, -4 /* ignore r12_orig */ | ||
461 | rete | ||
462 | |||
463 | irq_exit_work: | ||
464 | /* Switch to exception mode so that we can share the same code. */ | ||
465 | mfsr r8, SYSREG_SR | ||
466 | cbr r8, SYSREG_M0_OFFSET | ||
467 | orh r8, hi(SYSREG_BIT(M1) | SYSREG_BIT(M2)) | ||
468 | mtsr SYSREG_SR, r8 | ||
469 | sub pc, -2 | ||
470 | get_thread_info r0 | ||
471 | ld.w r1, r0[TI_flags] | ||
472 | |||
473 | fault_exit_work: | ||
474 | bld r1, TIF_NEED_RESCHED | ||
475 | brcc 1f | ||
476 | unmask_interrupts | ||
477 | rcall schedule | ||
478 | mask_interrupts | ||
479 | ld.w r1, r0[TI_flags] | ||
480 | rjmp fault_exit_work | ||
481 | |||
482 | 1: mov r2, _TIF_SIGPENDING | _TIF_RESTORE_SIGMASK | ||
483 | tst r1, r2 | ||
484 | breq 2f | ||
485 | unmask_interrupts | ||
486 | mov r12, sp | ||
487 | mov r11, r0 | ||
488 | rcall do_notify_resume | ||
489 | mask_interrupts | ||
490 | ld.w r1, r0[TI_flags] | ||
491 | rjmp fault_exit_work | ||
492 | |||
493 | 2: bld r1, TIF_BREAKPOINT | ||
494 | brcc fault_resume_user | ||
495 | mfsr r3, SYSREG_TLBEHI | ||
496 | lddsp r2, sp[REG_PC] | ||
497 | andl r3, 0xff, COH | ||
498 | lsl r3, 1 | ||
499 | sbr r3, 30 | ||
500 | sbr r3, 0 | ||
501 | mtdr DBGREG_BWA2A, r2 | ||
502 | mtdr DBGREG_BWC2A, r3 | ||
503 | rjmp fault_resume_user | ||
504 | |||
505 | /* If we get a debug trap from privileged context we end up here */ | ||
506 | handle_debug_priv: | ||
507 | /* Fix up LR and SP in regs. r11 contains the mode we came from */ | ||
508 | mfsr r8, SYSREG_SR | ||
509 | mov r9, r8 | ||
510 | andh r8, hi(~MODE_MASK) | ||
511 | or r8, r11 | ||
512 | mtsr SYSREG_SR, r8 | ||
513 | sub pc, -2 | ||
514 | stdsp sp[REG_LR], lr | ||
515 | mtsr SYSREG_SR, r9 | ||
516 | sub pc, -2 | ||
517 | sub r10, sp, -FRAME_SIZE_FULL | ||
518 | stdsp sp[REG_SP], r10 | ||
519 | mov r12, sp | ||
520 | rcall do_debug_priv | ||
521 | |||
522 | /* Now, put everything back */ | ||
523 | ssrf SR_EM_BIT | ||
524 | popm r10, r11 | ||
525 | mtsr SYSREG_RAR_DBG, r10 | ||
526 | mtsr SYSREG_RSR_DBG, r11 | ||
527 | mfsr r8, SYSREG_SR | ||
528 | mov r9, r8 | ||
529 | andh r8, hi(~MODE_MASK) | ||
530 | andh r11, hi(MODE_MASK) | ||
531 | or r8, r11 | ||
532 | mtsr SYSREG_SR, r8 | ||
533 | sub pc, -2 | ||
534 | popm lr | ||
535 | mtsr SYSREG_SR, r9 | ||
536 | sub pc, -2 | ||
537 | sub sp, -4 /* skip SP */ | ||
538 | popm r0-r12 | ||
539 | sub sp, -4 | ||
540 | retd | ||
541 | |||
542 | /* | ||
543 | * At this point, everything is masked, that is, interrupts, | ||
544 | * exceptions and debugging traps. We might get called from | ||
545 | * interrupt or exception context in some rare cases, but this | ||
546 | * will be taken care of by do_debug(), so we're not going to | ||
547 | * do a 100% correct context save here. | ||
548 | */ | ||
549 | handle_debug: | ||
550 | sub sp, 4 /* r12_orig */ | ||
551 | stmts --sp, r0-lr | ||
552 | mfsr r10, SYSREG_RAR_DBG | ||
553 | mfsr r11, SYSREG_RSR_DBG | ||
554 | unmask_exceptions | ||
555 | pushm r10,r11 | ||
556 | andh r11, (MODE_MASK >> 16), COH | ||
557 | brne handle_debug_priv | ||
558 | |||
559 | mov r12, sp | ||
560 | rcall do_debug | ||
561 | |||
562 | lddsp r10, sp[REG_SR] | ||
563 | andh r10, (MODE_MASK >> 16), COH | ||
564 | breq debug_resume_user | ||
565 | |||
566 | debug_restore_all: | ||
567 | popm r10,r11 | ||
568 | mask_exceptions | ||
569 | mtsr SYSREG_RSR_DBG, r11 | ||
570 | mtsr SYSREG_RAR_DBG, r10 | ||
571 | ldmts sp++, r0-lr | ||
572 | sub sp, -4 | ||
573 | retd | ||
574 | |||
575 | debug_resume_user: | ||
576 | get_thread_info r0 | ||
577 | mask_interrupts | ||
578 | |||
579 | ld.w r1, r0[TI_flags] | ||
580 | andl r1, _TIF_DBGWORK_MASK, COH | ||
581 | breq debug_restore_all | ||
582 | |||
583 | 1: bld r1, TIF_NEED_RESCHED | ||
584 | brcc 2f | ||
585 | unmask_interrupts | ||
586 | rcall schedule | ||
587 | mask_interrupts | ||
588 | ld.w r1, r0[TI_flags] | ||
589 | rjmp 1b | ||
590 | |||
591 | 2: mov r2, _TIF_SIGPENDING | _TIF_RESTORE_SIGMASK | ||
592 | tst r1, r2 | ||
593 | breq 3f | ||
594 | unmask_interrupts | ||
595 | mov r12, sp | ||
596 | mov r11, r0 | ||
597 | rcall do_notify_resume | ||
598 | mask_interrupts | ||
599 | ld.w r1, r0[TI_flags] | ||
600 | rjmp 1b | ||
601 | |||
602 | 3: bld r1, TIF_SINGLE_STEP | ||
603 | brcc debug_restore_all | ||
604 | mfdr r2, DBGREG_DC | ||
605 | sbr r2, DC_SS_BIT | ||
606 | mtdr DBGREG_DC, r2 | ||
607 | rjmp debug_restore_all | ||
608 | |||
609 | .set rsr_int0, SYSREG_RSR_INT0 | ||
610 | .set rsr_int1, SYSREG_RSR_INT1 | ||
611 | .set rsr_int2, SYSREG_RSR_INT2 | ||
612 | .set rsr_int3, SYSREG_RSR_INT3 | ||
613 | .set rar_int0, SYSREG_RAR_INT0 | ||
614 | .set rar_int1, SYSREG_RAR_INT1 | ||
615 | .set rar_int2, SYSREG_RAR_INT2 | ||
616 | .set rar_int3, SYSREG_RAR_INT3 | ||
617 | |||
618 | .macro IRQ_LEVEL level | ||
619 | .type irq_level\level, @function | ||
620 | irq_level\level: | ||
621 | sub sp, 4 /* r12_orig */ | ||
622 | stmts --sp,r0-lr | ||
623 | mfsr r8, rar_int\level | ||
624 | mfsr r9, rsr_int\level | ||
625 | pushm r8-r9 | ||
626 | |||
627 | mov r11, sp | ||
628 | mov r12, \level | ||
629 | |||
630 | rcall do_IRQ | ||
631 | |||
632 | lddsp r4, sp[REG_SR] | ||
633 | andh r4, (MODE_MASK >> 16), COH | ||
634 | #ifdef CONFIG_PREEMPT | ||
635 | brne 2f | ||
636 | #else | ||
637 | brne 1f | ||
638 | #endif | ||
639 | |||
640 | get_thread_info r0 | ||
641 | ld.w r1, r0[TI_flags] | ||
642 | andl r1, _TIF_WORK_MASK, COH | ||
643 | brne irq_exit_work | ||
644 | |||
645 | 1: popm r8-r9 | ||
646 | mtsr rar_int\level, r8 | ||
647 | mtsr rsr_int\level, r9 | ||
648 | ldmts sp++,r0-lr | ||
649 | sub sp, -4 /* ignore r12_orig */ | ||
650 | rete | ||
651 | |||
652 | #ifdef CONFIG_PREEMPT | ||
653 | 2: | ||
654 | get_thread_info r0 | ||
655 | ld.w r2, r0[TI_preempt_count] | ||
656 | cp.w r2, 0 | ||
657 | brne 1b | ||
658 | ld.w r1, r0[TI_flags] | ||
659 | bld r1, TIF_NEED_RESCHED | ||
660 | brcc 1b | ||
661 | lddsp r4, sp[REG_SR] | ||
662 | bld r4, SYSREG_GM_OFFSET | ||
663 | brcs 1b | ||
664 | rcall preempt_schedule_irq | ||
665 | rjmp 1b | ||
666 | #endif | ||
667 | .endm | ||
668 | |||
669 | .section .irq.text,"ax",@progbits | ||
670 | |||
671 | .global irq_level0 | ||
672 | .global irq_level1 | ||
673 | .global irq_level2 | ||
674 | .global irq_level3 | ||
675 | IRQ_LEVEL 0 | ||
676 | IRQ_LEVEL 1 | ||
677 | IRQ_LEVEL 2 | ||
678 | IRQ_LEVEL 3 | ||