Merge git://oss.sgi.com:8090/xfs/xfs-2.6
[linux-2.6] / arch / avr32 / kernel / entry-avr32b.S
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_TLBEAR
104         mfsr    r1, SYSREG_PTBR
105
106         /* Is it the vmalloc space? */
107         bld     r0, 31
108         brcs    handle_vmalloc_miss
109
110         /* First level lookup */
111 pgtbl_lookup:
112         lsr     r2, r0, PGDIR_SHIFT
113         ld.w    r3, r1[r2 << 2]
114         bfextu  r1, r0, PAGE_SHIFT, PGDIR_SHIFT - PAGE_SHIFT
115         bld     r3, _PAGE_BIT_PRESENT
116         brcc    page_table_not_present
117
118         /* Translate to virtual address in P1. */
119         andl    r3, 0xf000
120         sbr     r3, 31
121
122         /* Second level lookup */
123         ld.w    r2, r3[r1 << 2]
124         mfsr    r0, SYSREG_TLBARLO
125         bld     r2, _PAGE_BIT_PRESENT
126         brcc    page_not_present
127
128         /* Mark the page as accessed */
129         sbr     r2, _PAGE_BIT_ACCESSED
130         st.w    r3[r1 << 2], r2
131
132         /* Drop software flags */
133         andl    r2, _PAGE_FLAGS_HARDWARE_MASK & 0xffff
134         mtsr    SYSREG_TLBELO, r2
135
136         /* Figure out which entry we want to replace */
137         mfsr    r1, SYSREG_MMUCR
138         clz     r2, r0
139         brcc    1f
140         mov     r3, -1                  /* All entries have been accessed, */
141         mov     r2, 0                   /* so start at 0 */
142         mtsr    SYSREG_TLBARLO, r3      /* and reset TLBAR */
143
144 1:      bfins   r1, r2, SYSREG_DRP_OFFSET, SYSREG_DRP_SIZE
145         mtsr    SYSREG_MMUCR, r1
146         tlbw
147
148         tlbmiss_restore
149         rete
150
151 handle_vmalloc_miss:
152         /* Simply do the lookup in init's page table */
153         mov     r1, lo(swapper_pg_dir)
154         orh     r1, hi(swapper_pg_dir)
155         rjmp    pgtbl_lookup
156
157
158         /* ---                    System Call                    --- */
159
160         .section .scall.text,"ax",@progbits
161 system_call:
162         pushm   r12             /* r12_orig */
163         stmts   --sp, r0-lr
164         zero_fp
165         mfsr    r0, SYSREG_RAR_SUP
166         mfsr    r1, SYSREG_RSR_SUP
167         stm     --sp, r0-r1
168
169         /* check for syscall tracing */
170         get_thread_info r0
171         ld.w    r1, r0[TI_flags]
172         bld     r1, TIF_SYSCALL_TRACE
173         brcs    syscall_trace_enter
174
175 syscall_trace_cont:
176         cp.w    r8, NR_syscalls
177         brhs    syscall_badsys
178
179         lddpc   lr, syscall_table_addr
180         ld.w    lr, lr[r8 << 2]
181         mov     r8, r5          /* 5th argument (6th is pushed by stub) */
182         icall   lr
183
184         .global syscall_return
185 syscall_return:
186         get_thread_info r0
187         mask_interrupts         /* make sure we don't miss an interrupt
188                                    setting need_resched or sigpending
189                                    between sampling and the rets */
190
191         /* Store the return value so that the correct value is loaded below */
192         stdsp   sp[REG_R12], r12
193
194         ld.w    r1, r0[TI_flags]
195         andl    r1, _TIF_ALLWORK_MASK, COH
196         brne    syscall_exit_work
197
198 syscall_exit_cont:
199         popm    r8-r9
200         mtsr    SYSREG_RAR_SUP, r8
201         mtsr    SYSREG_RSR_SUP, r9
202         ldmts   sp++, r0-lr
203         sub     sp, -4          /* r12_orig */
204         rets
205
206         .align  2
207 syscall_table_addr:
208         .long   sys_call_table
209
210 syscall_badsys:
211         mov     r12, -ENOSYS
212         rjmp    syscall_return
213
214         .global ret_from_fork
215 ret_from_fork:
216         rcall   schedule_tail
217
218         /* check for syscall tracing */
219         get_thread_info r0
220         ld.w    r1, r0[TI_flags]
221         andl    r1, _TIF_ALLWORK_MASK, COH
222         brne    syscall_exit_work
223         rjmp    syscall_exit_cont
224
225 syscall_trace_enter:
226         pushm   r8-r12
227         rcall   syscall_trace
228         popm    r8-r12
229         rjmp    syscall_trace_cont
230
231 syscall_exit_work:
232         bld     r1, TIF_SYSCALL_TRACE
233         brcc    1f
234         unmask_interrupts
235         rcall   syscall_trace
236         mask_interrupts
237         ld.w    r1, r0[TI_flags]
238
239 1:      bld     r1, TIF_NEED_RESCHED
240         brcc    2f
241         unmask_interrupts
242         rcall   schedule
243         mask_interrupts
244         ld.w    r1, r0[TI_flags]
245         rjmp    1b
246
247 2:      mov     r2, _TIF_SIGPENDING | _TIF_RESTORE_SIGMASK
248         tst     r1, r2
249         breq    3f
250         unmask_interrupts
251         mov     r12, sp
252         mov     r11, r0
253         rcall   do_notify_resume
254         mask_interrupts
255         ld.w    r1, r0[TI_flags]
256         rjmp    1b
257
258 3:      bld     r1, TIF_BREAKPOINT
259         brcc    syscall_exit_cont
260         mfsr    r3, SYSREG_TLBEHI
261         lddsp   r2, sp[REG_PC]
262         andl    r3, 0xff, COH
263         lsl     r3, 1
264         sbr     r3, 30
265         sbr     r3, 0
266         mtdr    DBGREG_BWA2A, r2
267         mtdr    DBGREG_BWC2A, r3
268         rjmp    syscall_exit_cont
269
270
271         /* The slow path of the TLB miss handler */
272 page_table_not_present:
273 page_not_present:
274         tlbmiss_restore
275         sub     sp, 4
276         stmts   --sp, r0-lr
277         rcall   save_full_context_ex
278         mfsr    r12, SYSREG_ECR
279         mov     r11, sp
280         rcall   do_page_fault
281         rjmp    ret_from_exception
282
283         /* This function expects to find offending PC in SYSREG_RAR_EX */
284 save_full_context_ex:
285         mfsr    r8, SYSREG_RSR_EX
286         mov     r12, r8
287         andh    r8, (MODE_MASK >> 16), COH
288         mfsr    r11, SYSREG_RAR_EX
289         brne    2f
290
291 1:      pushm   r11, r12        /* PC and SR */
292         unmask_exceptions
293         ret     r12
294
295 2:      sub     r10, sp, -(FRAME_SIZE_FULL - REG_LR)
296         stdsp   sp[4], r10      /* replace saved SP */
297         rjmp    1b
298
299         /* Low-level exception handlers */
300 handle_critical:
301         pushm   r12
302         pushm   r0-r12
303         rcall   save_full_context_ex
304         mfsr    r12, SYSREG_ECR
305         mov     r11, sp
306         rcall   do_critical_exception
307
308         /* We should never get here... */
309 bad_return:
310         sub     r12, pc, (. - 1f)
311         bral    panic
312         .align  2
313 1:      .asciz  "Return from critical exception!"
314
315         .align  1
316 do_bus_error_write:
317         sub     sp, 4
318         stmts   --sp, r0-lr
319         rcall   save_full_context_ex
320         mov     r11, 1
321         rjmp    1f
322
323 do_bus_error_read:
324         sub     sp, 4
325         stmts   --sp, r0-lr
326         rcall   save_full_context_ex
327         mov     r11, 0
328 1:      mfsr    r12, SYSREG_BEAR
329         mov     r10, sp
330         rcall   do_bus_error
331         rjmp    ret_from_exception
332
333         .align  1
334 do_nmi_ll:
335         sub     sp, 4
336         stmts   --sp, r0-lr
337         mfsr    r9, SYSREG_RSR_NMI
338         mfsr    r8, SYSREG_RAR_NMI
339         bfextu  r0, r9, MODE_SHIFT, 3
340         brne    2f
341
342 1:      pushm   r8, r9  /* PC and SR */
343         mfsr    r12, SYSREG_ECR
344         mov     r11, sp
345         rcall   do_nmi
346         popm    r8-r9
347         mtsr    SYSREG_RAR_NMI, r8
348         tst     r0, r0
349         mtsr    SYSREG_RSR_NMI, r9
350         brne    3f
351
352         ldmts   sp++, r0-lr
353         sub     sp, -4          /* skip r12_orig */
354         rete
355
356 2:      sub     r10, sp, -(FRAME_SIZE_FULL - REG_LR)
357         stdsp   sp[4], r10      /* replace saved SP */
358         rjmp    1b
359
360 3:      popm    lr
361         sub     sp, -4          /* skip sp */
362         popm    r0-r12
363         sub     sp, -4          /* skip r12_orig */
364         rete
365
366 handle_address_fault:
367         sub     sp, 4
368         stmts   --sp, r0-lr
369         rcall   save_full_context_ex
370         mfsr    r12, SYSREG_ECR
371         mov     r11, sp
372         rcall   do_address_exception
373         rjmp    ret_from_exception
374
375 handle_protection_fault:
376         sub     sp, 4
377         stmts   --sp, r0-lr
378         rcall   save_full_context_ex
379         mfsr    r12, SYSREG_ECR
380         mov     r11, sp
381         rcall   do_page_fault
382         rjmp    ret_from_exception
383
384         .align  1
385 do_illegal_opcode_ll:
386         sub     sp, 4
387         stmts   --sp, r0-lr
388         rcall   save_full_context_ex
389         mfsr    r12, SYSREG_ECR
390         mov     r11, sp
391         rcall   do_illegal_opcode
392         rjmp    ret_from_exception
393
394 do_dtlb_modified:
395         pushm   r0-r3
396         mfsr    r1, SYSREG_TLBEAR
397         mfsr    r0, SYSREG_PTBR
398         lsr     r2, r1, PGDIR_SHIFT
399         ld.w    r0, r0[r2 << 2]
400         lsl     r1, (32 - PGDIR_SHIFT)
401         lsr     r1, (32 - PGDIR_SHIFT) + PAGE_SHIFT
402
403         /* Translate to virtual address in P1 */
404         andl    r0, 0xf000
405         sbr     r0, 31
406         add     r2, r0, r1 << 2
407         ld.w    r3, r2[0]
408         sbr     r3, _PAGE_BIT_DIRTY
409         mov     r0, r3
410         st.w    r2[0], r3
411
412         /* The page table is up-to-date. Update the TLB entry as well */
413         andl    r0, lo(_PAGE_FLAGS_HARDWARE_MASK)
414         mtsr    SYSREG_TLBELO, r0
415
416         /* MMUCR[DRP] is updated automatically, so let's go... */
417         tlbw
418
419         popm    r0-r3
420         rete
421
422 do_fpe_ll:
423         sub     sp, 4
424         stmts   --sp, r0-lr
425         rcall   save_full_context_ex
426         unmask_interrupts
427         mov     r12, 26
428         mov     r11, sp
429         rcall   do_fpe
430         rjmp    ret_from_exception
431
432 ret_from_exception:
433         mask_interrupts
434         lddsp   r4, sp[REG_SR]
435         andh    r4, (MODE_MASK >> 16), COH
436         brne    fault_resume_kernel
437
438         get_thread_info r0
439         ld.w    r1, r0[TI_flags]
440         andl    r1, _TIF_WORK_MASK, COH
441         brne    fault_exit_work
442
443 fault_resume_user:
444         popm    r8-r9
445         mask_exceptions
446         mtsr    SYSREG_RAR_EX, r8
447         mtsr    SYSREG_RSR_EX, r9
448         ldmts   sp++, r0-lr
449         sub     sp, -4
450         rete
451
452 fault_resume_kernel:
453 #ifdef CONFIG_PREEMPT
454         get_thread_info r0
455         ld.w    r2, r0[TI_preempt_count]
456         cp.w    r2, 0
457         brne    1f
458         ld.w    r1, r0[TI_flags]
459         bld     r1, TIF_NEED_RESCHED
460         brcc    1f
461         lddsp   r4, sp[REG_SR]
462         bld     r4, SYSREG_GM_OFFSET
463         brcs    1f
464         rcall   preempt_schedule_irq
465 1:
466 #endif
467
468         popm    r8-r9
469         mask_exceptions
470         mfsr    r1, SYSREG_SR
471         mtsr    SYSREG_RAR_EX, r8
472         mtsr    SYSREG_RSR_EX, r9
473         popm    lr
474         sub     sp, -4          /* ignore SP */
475         popm    r0-r12
476         sub     sp, -4          /* ignore r12_orig */
477         rete
478
479 irq_exit_work:
480         /* Switch to exception mode so that we can share the same code. */
481         mfsr    r8, SYSREG_SR
482         cbr     r8, SYSREG_M0_OFFSET
483         orh     r8, hi(SYSREG_BIT(M1) | SYSREG_BIT(M2))
484         mtsr    SYSREG_SR, r8
485         sub     pc, -2
486         get_thread_info r0
487         ld.w    r1, r0[TI_flags]
488
489 fault_exit_work:
490         bld     r1, TIF_NEED_RESCHED
491         brcc    1f
492         unmask_interrupts
493         rcall   schedule
494         mask_interrupts
495         ld.w    r1, r0[TI_flags]
496         rjmp    fault_exit_work
497
498 1:      mov     r2, _TIF_SIGPENDING | _TIF_RESTORE_SIGMASK
499         tst     r1, r2
500         breq    2f
501         unmask_interrupts
502         mov     r12, sp
503         mov     r11, r0
504         rcall   do_notify_resume
505         mask_interrupts
506         ld.w    r1, r0[TI_flags]
507         rjmp    fault_exit_work
508
509 2:      bld     r1, TIF_BREAKPOINT
510         brcc    fault_resume_user
511         mfsr    r3, SYSREG_TLBEHI
512         lddsp   r2, sp[REG_PC]
513         andl    r3, 0xff, COH
514         lsl     r3, 1
515         sbr     r3, 30
516         sbr     r3, 0
517         mtdr    DBGREG_BWA2A, r2
518         mtdr    DBGREG_BWC2A, r3
519         rjmp    fault_resume_user
520
521         /* If we get a debug trap from privileged context we end up here */
522 handle_debug_priv:
523         /* Fix up LR and SP in regs. r11 contains the mode we came from */
524         mfsr    r8, SYSREG_SR
525         mov     r9, r8
526         andh    r8, hi(~MODE_MASK)
527         or      r8, r11
528         mtsr    SYSREG_SR, r8
529         sub     pc, -2
530         stdsp   sp[REG_LR], lr
531         mtsr    SYSREG_SR, r9
532         sub     pc, -2
533         sub     r10, sp, -FRAME_SIZE_FULL
534         stdsp   sp[REG_SP], r10
535         mov     r12, sp
536         rcall   do_debug_priv
537
538         /* Now, put everything back */
539         ssrf    SR_EM_BIT
540         popm    r10, r11
541         mtsr    SYSREG_RAR_DBG, r10
542         mtsr    SYSREG_RSR_DBG, r11
543         mfsr    r8, SYSREG_SR
544         mov     r9, r8
545         andh    r8, hi(~MODE_MASK)
546         andh    r11, hi(MODE_MASK)
547         or      r8, r11
548         mtsr    SYSREG_SR, r8
549         sub     pc, -2
550         popm    lr
551         mtsr    SYSREG_SR, r9
552         sub     pc, -2
553         sub     sp, -4          /* skip SP */
554         popm    r0-r12
555         sub     sp, -4
556         retd
557
558         /*
559          * At this point, everything is masked, that is, interrupts,
560          * exceptions and debugging traps. We might get called from
561          * interrupt or exception context in some rare cases, but this
562          * will be taken care of by do_debug(), so we're not going to
563          * do a 100% correct context save here.
564          */
565 handle_debug:
566         sub     sp, 4           /* r12_orig */
567         stmts   --sp, r0-lr
568         mfsr    r10, SYSREG_RAR_DBG
569         mfsr    r11, SYSREG_RSR_DBG
570         unmask_exceptions
571         pushm   r10,r11
572         andh    r11, (MODE_MASK >> 16), COH
573         brne    handle_debug_priv
574
575         mov     r12, sp
576         rcall   do_debug
577
578         lddsp   r10, sp[REG_SR]
579         andh    r10, (MODE_MASK >> 16), COH
580         breq    debug_resume_user
581
582 debug_restore_all:
583         popm    r10,r11
584         mask_exceptions
585         mtsr    SYSREG_RSR_DBG, r11
586         mtsr    SYSREG_RAR_DBG, r10
587         ldmts   sp++, r0-lr
588         sub     sp, -4
589         retd
590
591 debug_resume_user:
592         get_thread_info r0
593         mask_interrupts
594
595         ld.w    r1, r0[TI_flags]
596         andl    r1, _TIF_DBGWORK_MASK, COH
597         breq    debug_restore_all
598
599 1:      bld     r1, TIF_NEED_RESCHED
600         brcc    2f
601         unmask_interrupts
602         rcall   schedule
603         mask_interrupts
604         ld.w    r1, r0[TI_flags]
605         rjmp    1b
606
607 2:      mov     r2, _TIF_SIGPENDING | _TIF_RESTORE_SIGMASK
608         tst     r1, r2
609         breq    3f
610         unmask_interrupts
611         mov     r12, sp
612         mov     r11, r0
613         rcall   do_notify_resume
614         mask_interrupts
615         ld.w    r1, r0[TI_flags]
616         rjmp    1b
617
618 3:      bld     r1, TIF_SINGLE_STEP
619         brcc    debug_restore_all
620         mfdr    r2, DBGREG_DC
621         sbr     r2, DC_SS_BIT
622         mtdr    DBGREG_DC, r2
623         rjmp    debug_restore_all
624
625         .set    rsr_int0,       SYSREG_RSR_INT0
626         .set    rsr_int1,       SYSREG_RSR_INT1
627         .set    rsr_int2,       SYSREG_RSR_INT2
628         .set    rsr_int3,       SYSREG_RSR_INT3
629         .set    rar_int0,       SYSREG_RAR_INT0
630         .set    rar_int1,       SYSREG_RAR_INT1
631         .set    rar_int2,       SYSREG_RAR_INT2
632         .set    rar_int3,       SYSREG_RAR_INT3
633
634         .macro  IRQ_LEVEL level
635         .type   irq_level\level, @function
636 irq_level\level:
637         sub     sp, 4           /* r12_orig */
638         stmts   --sp,r0-lr
639         mfsr    r8, rar_int\level
640         mfsr    r9, rsr_int\level
641         pushm   r8-r9
642
643         mov     r11, sp
644         mov     r12, \level
645
646         rcall   do_IRQ
647
648         lddsp   r4, sp[REG_SR]
649         bfextu  r4, r4, SYSREG_M0_OFFSET, 3
650         cp.w    r4, MODE_SUPERVISOR >> SYSREG_M0_OFFSET
651         breq    2f
652         cp.w    r4, MODE_USER >> SYSREG_M0_OFFSET
653 #ifdef CONFIG_PREEMPT
654         brne    3f
655 #else
656         brne    1f
657 #endif
658
659         get_thread_info r0
660         ld.w    r1, r0[TI_flags]
661         andl    r1, _TIF_WORK_MASK, COH
662         brne    irq_exit_work
663
664 1:      popm    r8-r9
665         mtsr    rar_int\level, r8
666         mtsr    rsr_int\level, r9
667         ldmts   sp++,r0-lr
668         sub     sp, -4          /* ignore r12_orig */
669         rete
670
671 2:      get_thread_info r0
672         ld.w    r1, r0[TI_flags]
673         bld     r1, TIF_CPU_GOING_TO_SLEEP
674 #ifdef CONFIG_PREEMPT
675         brcc    3f
676 #else
677         brcc    1b
678 #endif
679         sub     r1, pc, . - cpu_idle_skip_sleep
680         stdsp   sp[REG_PC], r1
681 #ifdef CONFIG_PREEMPT
682 3:      get_thread_info r0
683         ld.w    r2, r0[TI_preempt_count]
684         cp.w    r2, 0
685         brne    1b
686         ld.w    r1, r0[TI_flags]
687         bld     r1, TIF_NEED_RESCHED
688         brcc    1b
689         lddsp   r4, sp[REG_SR]
690         bld     r4, SYSREG_GM_OFFSET
691         brcs    1b
692         rcall   preempt_schedule_irq
693 #endif
694         rjmp    1b
695         .endm
696
697         .section .irq.text,"ax",@progbits
698
699 .global cpu_idle_sleep
700 cpu_idle_sleep:
701         mask_interrupts
702         get_thread_info r8
703         ld.w    r9, r8[TI_flags]
704         bld     r9, TIF_NEED_RESCHED
705         brcs    cpu_idle_enable_int_and_exit
706         sbr     r9, TIF_CPU_GOING_TO_SLEEP
707         st.w    r8[TI_flags], r9
708         unmask_interrupts
709         sleep 0
710 cpu_idle_skip_sleep:
711         mask_interrupts
712         ld.w    r9, r8[TI_flags]
713         cbr     r9, TIF_CPU_GOING_TO_SLEEP
714         st.w    r8[TI_flags], r9
715 cpu_idle_enable_int_and_exit:
716         unmask_interrupts
717         retal   r12
718
719         .global irq_level0
720         .global irq_level1
721         .global irq_level2
722         .global irq_level3
723         IRQ_LEVEL 0
724         IRQ_LEVEL 1
725         IRQ_LEVEL 2
726         IRQ_LEVEL 3