aboutsummaryrefslogtreecommitdiffstats
path: root/arch/avr32/kernel/entry-avr32b.S
diff options
context:
space:
mode:
authorHaavard Skinnemoen <hskinnemoen@atmel.com>2006-09-26 02:32:13 -0400
committerLinus Torvalds <torvalds@g5.osdl.org>2006-09-26 11:48:54 -0400
commit5f97f7f9400de47ae837170bb274e90ad3934386 (patch)
tree514451e6dc6b46253293a00035d375e77b1c65ed /arch/avr32/kernel/entry-avr32b.S
parent53e62d3aaa60590d4a69b4e07c29f448b5151047 (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.S678
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
40exception_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
88itlb_miss:
89 tlbmiss_save
90 rjmp tlb_miss_common
91
92 .section .tlbr.ex.text,"ax",@progbits
93dtlb_miss_read:
94 tlbmiss_save
95 rjmp tlb_miss_common
96
97 .section .tlbw.ex.text,"ax",@progbits
98dtlb_miss_write:
99 tlbmiss_save
100
101 .global tlb_miss_common
102tlb_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 */
111pgtbl_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 */
1461: 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
157handle_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
167system_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
181syscall_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
191syscall_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
204syscall_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
213syscall_table_addr:
214 .long sys_call_table
215
216syscall_badsys:
217 mov r12, -ENOSYS
218 rjmp syscall_return
219
220 .global ret_from_fork
221ret_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
231syscall_trace_enter:
232 pushm r8-r12
233 rcall syscall_trace
234 popm r8-r12
235 rjmp syscall_trace_cont
236
237syscall_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
2451: 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
2532: 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
2643: 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 */
278page_table_not_present:
279page_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 */
290save_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
2971: pushm r11, r12 /* PC and SR */
298 unmask_exceptions
299 ret r12
300
3012: 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 */
306handle_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... */
315bad_return:
316 sub r12, pc, (. - 1f)
317 bral panic
318 .align 2
3191: .asciz "Return from critical exception!"
320
321 .align 1
322do_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
329do_bus_error_read:
330 sub sp, 4
331 stmts --sp, r0-lr
332 rcall save_full_context_ex
333 mov r11, 0
3341: mfsr r12, SYSREG_BEAR
335 mov r10, sp
336 rcall do_bus_error
337 rjmp ret_from_exception
338
339 .align 1
340do_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
350handle_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
359handle_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
369do_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
378do_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
406do_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
416ret_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
427fault_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
436fault_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
4491:
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
463irq_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
473fault_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
4821: 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
4932: 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 */
506handle_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 */
549handle_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
566debug_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
575debug_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
5831: 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
5912: 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
6023: 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
620irq_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
6451: 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
6532:
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