Merge git://git.kernel.org/pub/scm/linux/kernel/git/lethal/sh-2.6
[pandora-kernel.git] / arch / m32r / kernel / entry.S
1 /*
2  *  linux/arch/m32r/kernel/entry.S
3  *
4  *  Copyright (c) 2001, 2002  Hirokazu Takata, Hitoshi Yamamoto, H. Kondo
5  *  Copyright (c) 2003  Hitoshi Yamamoto
6  *  Copyright (c) 2004  Hirokazu Takata <takata at linux-m32r.org>
7  *
8  *  Taken from i386 version.
9  *    Copyright (C) 1991, 1992  Linus Torvalds
10  */
11
12 /*
13  * entry.S contains the system-call and fault low-level handling routines.
14  * This also contains the timer-interrupt handler, as well as all interrupts
15  * and faults that can result in a task-switch.
16  *
17  * NOTE: This code handles signal-recognition, which happens every time
18  * after a timer-interrupt and after each system call.
19  *
20  * Stack layout in 'ret_from_system_call':
21  *      ptrace needs to have all regs on the stack.
22  *      if the order here is changed, it needs to be
23  *      updated in fork.c:copy_thread, signal.c:do_signal,
24  *      ptrace.c and ptrace.h
25  *
26  * M32R/M32Rx/M32R2
27  *       @(sp)      - r4
28  *       @(0x04,sp) - r5
29  *       @(0x08,sp) - r6
30  *       @(0x0c,sp) - *pt_regs
31  *       @(0x10,sp) - r0
32  *       @(0x14,sp) - r1
33  *       @(0x18,sp) - r2
34  *       @(0x1c,sp) - r3
35  *       @(0x20,sp) - r7
36  *       @(0x24,sp) - r8
37  *       @(0x28,sp) - r9
38  *       @(0x2c,sp) - r10
39  *       @(0x30,sp) - r11
40  *       @(0x34,sp) - r12
41  *       @(0x38,sp) - syscall_nr
42  *       @(0x3c,sp) - acc0h
43  *       @(0x40,sp) - acc0l
44  *       @(0x44,sp) - acc1h             ; ISA_DSP_LEVEL2 only
45  *       @(0x48,sp) - acc1l             ; ISA_DSP_LEVEL2 only
46  *       @(0x4c,sp) - psw
47  *       @(0x50,sp) - bpc
48  *       @(0x54,sp) - bbpsw
49  *       @(0x58,sp) - bbpc
50  *       @(0x5c,sp) - spu (cr3)
51  *       @(0x60,sp) - fp (r13)
52  *       @(0x64,sp) - lr (r14)
53  *       @(0x68,sp) - spi (cr2)
54  *       @(0x6c,sp) - orig_r0
55  */
56
57 #include <linux/linkage.h>
58 #include <asm/irq.h>
59 #include <asm/unistd.h>
60 #include <asm/assembler.h>
61 #include <asm/thread_info.h>
62 #include <asm/errno.h>
63 #include <asm/segment.h>
64 #include <asm/smp.h>
65 #include <asm/page.h>
66 #include <asm/m32r.h>
67 #include <asm/mmu_context.h>
68
69 #if !defined(CONFIG_MMU)
70 #define sys_madvise             sys_ni_syscall
71 #define sys_readahead           sys_ni_syscall
72 #define sys_mprotect            sys_ni_syscall
73 #define sys_msync               sys_ni_syscall
74 #define sys_mlock               sys_ni_syscall
75 #define sys_munlock             sys_ni_syscall
76 #define sys_mlockall            sys_ni_syscall
77 #define sys_munlockall          sys_ni_syscall
78 #define sys_mremap              sys_ni_syscall
79 #define sys_mincore             sys_ni_syscall
80 #define sys_remap_file_pages    sys_ni_syscall
81 #endif /* CONFIG_MMU */
82
83 #define R4(reg)                 @reg
84 #define R5(reg)                 @(0x04,reg)
85 #define R6(reg)                 @(0x08,reg)
86 #define PTREGS(reg)             @(0x0C,reg)
87 #define R0(reg)                 @(0x10,reg)
88 #define R1(reg)                 @(0x14,reg)
89 #define R2(reg)                 @(0x18,reg)
90 #define R3(reg)                 @(0x1C,reg)
91 #define R7(reg)                 @(0x20,reg)
92 #define R8(reg)                 @(0x24,reg)
93 #define R9(reg)                 @(0x28,reg)
94 #define R10(reg)                @(0x2C,reg)
95 #define R11(reg)                @(0x30,reg)
96 #define R12(reg)                @(0x34,reg)
97 #define SYSCALL_NR(reg)         @(0x38,reg)
98 #define ACC0H(reg)              @(0x3C,reg)
99 #define ACC0L(reg)              @(0x40,reg)
100 #define ACC1H(reg)              @(0x44,reg)
101 #define ACC1L(reg)              @(0x48,reg)
102 #define PSW(reg)                @(0x4C,reg)
103 #define BPC(reg)                @(0x50,reg)
104 #define BBPSW(reg)              @(0x54,reg)
105 #define BBPC(reg)               @(0x58,reg)
106 #define SPU(reg)                @(0x5C,reg)
107 #define FP(reg)                 @(0x60,reg)  /* FP = R13 */
108 #define LR(reg)                 @(0x64,reg)
109 #define SP(reg)                 @(0x68,reg)
110 #define ORIG_R0(reg)            @(0x6C,reg)
111
112 #define nr_syscalls ((syscall_table_size)/4)
113
114 #ifdef CONFIG_PREEMPT
115 #define preempt_stop(x)         DISABLE_INTERRUPTS(x)
116 #else
117 #define preempt_stop(x)
118 #define resume_kernel           restore_all
119 #endif
120
121 /* how to get the thread information struct from ASM */
122 #define GET_THREAD_INFO(reg)    GET_THREAD_INFO reg
123         .macro GET_THREAD_INFO reg
124         ldi     \reg, #-THREAD_SIZE
125         and     \reg, sp
126         .endm
127
128 ENTRY(ret_from_fork)
129         pop     r0
130         bl      schedule_tail
131         GET_THREAD_INFO(r8)
132         bra     syscall_exit
133
134 /*
135  * Return to user mode is not as complex as all this looks,
136  * but we want the default path for a system call return to
137  * go as quickly as possible which is why some of this is
138  * less clear than it otherwise should be.
139  */
140
141         ; userspace resumption stub bypassing syscall exit tracing
142         ALIGN
143 ret_from_exception:
144         preempt_stop(r4)
145 ret_from_intr:
146         ld      r4, PSW(sp)
147 #ifdef CONFIG_ISA_M32R2
148         and3    r4, r4, #0x8800         ; check BSM and BPM bits
149 #else
150         and3    r4, r4, #0x8000         ; check BSM bit
151 #endif
152         beqz    r4, resume_kernel
153 resume_userspace:
154         DISABLE_INTERRUPTS(r4)          ; make sure we don't miss an interrupt
155                                         ; setting need_resched or sigpending
156                                         ; between sampling and the iret
157         GET_THREAD_INFO(r8)
158         ld      r9, @(TI_FLAGS, r8)
159         and3    r4, r9, #_TIF_WORK_MASK ; is there any work to be done on
160                                         ; int/exception return?
161         bnez    r4, work_pending
162         bra     restore_all
163
164 #ifdef CONFIG_PREEMPT
165 ENTRY(resume_kernel)
166         GET_THREAD_INFO(r8)
167         ld      r9, @(TI_PRE_COUNT, r8) ; non-zero preempt_count ?
168         bnez    r9, restore_all
169 need_resched:
170         ld      r9, @(TI_FLAGS, r8)     ; need_resched set ?
171         and3    r4, r9, #_TIF_NEED_RESCHED
172         beqz    r4, restore_all
173         ld      r4, PSW(sp)             ; interrupts off (exception path) ?
174         and3    r4, r4, #0x4000
175         beqz    r4, restore_all
176         LDIMM   (r4, PREEMPT_ACTIVE)
177         st      r4, @(TI_PRE_COUNT, r8)
178         ENABLE_INTERRUPTS(r4)
179         bl      schedule
180         ldi     r4, #0
181         st      r4, @(TI_PRE_COUNT, r8)
182         DISABLE_INTERRUPTS(r4)
183         bra     need_resched
184 #endif
185
186         ; system call handler stub
187 ENTRY(system_call)
188         SWITCH_TO_KERNEL_STACK
189         SAVE_ALL
190         ENABLE_INTERRUPTS(r4)           ; Enable interrupt
191         st      sp, PTREGS(sp)          ; implicit pt_regs parameter
192         cmpui   r7, #NR_syscalls
193         bnc     syscall_badsys
194         st      r7, SYSCALL_NR(sp)      ; syscall_nr
195                                         ; system call tracing in operation
196         GET_THREAD_INFO(r8)
197         ld      r9, @(TI_FLAGS, r8)
198         and3    r4, r9, #_TIF_SYSCALL_TRACE
199         bnez    r4, syscall_trace_entry
200 syscall_call:
201         slli    r7, #2                  ; table jump for the system call
202         LDIMM   (r4, sys_call_table)
203         add     r7, r4
204         ld      r7, @r7
205         jl      r7                      ; execute system call
206         st      r0, R0(sp)              ; save the return value
207 syscall_exit:
208         DISABLE_INTERRUPTS(r4)          ; make sure we don't miss an interrupt
209                                         ; setting need_resched or sigpending
210                                         ; between sampling and the iret
211         ld      r9, @(TI_FLAGS, r8)
212         and3    r4, r9, #_TIF_ALLWORK_MASK      ; current->work
213         bnez    r4, syscall_exit_work
214 restore_all:
215         RESTORE_ALL
216
217         # perform work that needs to be done immediately before resumption
218         # r9 : flags
219         ALIGN
220 work_pending:
221         and3    r4, r9, #_TIF_NEED_RESCHED
222         beqz    r4, work_notifysig
223 work_resched:
224         bl      schedule
225         DISABLE_INTERRUPTS(r4)          ; make sure we don't miss an interrupt
226                                         ; setting need_resched or sigpending
227                                         ; between sampling and the iret
228         ld      r9, @(TI_FLAGS, r8)
229         and3    r4, r9, #_TIF_WORK_MASK ; is there any work to be done other
230                                         ; than syscall tracing?
231         beqz    r4, restore_all
232         and3    r4, r4, #_TIF_NEED_RESCHED
233         bnez    r4, work_resched
234
235 work_notifysig:                         ; deal with pending signals and
236                                         ; notify-resume requests
237         mv      r0, sp                  ; arg1 : struct pt_regs *regs
238         mv      r1, r9                  ; arg2 : __u32 thread_info_flags
239         bl      do_notify_resume
240         bra     resume_userspace
241
242         ; perform syscall exit tracing
243         ALIGN
244 syscall_trace_entry:
245         ldi     r4, #-ENOSYS
246         st      r4, R0(sp)
247         bl      do_syscall_trace
248         ld      r0, ORIG_R0(sp)
249         ld      r1, R1(sp)
250         ld      r2, R2(sp)
251         ld      r3, R3(sp)
252         ld      r4, R4(sp)
253         ld      r5, R5(sp)
254         ld      r6, R6(sp)
255         ld      r7, SYSCALL_NR(sp)
256         cmpui   r7, #NR_syscalls
257         bc      syscall_call
258         bra     syscall_exit
259
260         ; perform syscall exit tracing
261         ALIGN
262 syscall_exit_work:
263         ld      r9, @(TI_FLAGS, r8)
264         and3    r4, r9, #_TIF_SYSCALL_TRACE
265         beqz    r4, work_pending
266         ENABLE_INTERRUPTS(r4)           ; could let do_syscall_trace() call
267                                         ; schedule() instead
268         bl      do_syscall_trace
269         bra     resume_userspace
270
271         ALIGN
272 syscall_fault:
273         SAVE_ALL
274         GET_THREAD_INFO(r8)
275         ldi     r4, #-EFAULT
276         st      r4, R0(sp)
277         bra     resume_userspace
278
279         ALIGN
280 syscall_badsys:
281         ldi     r4, #-ENOSYS
282         st      r4, R0(sp)
283         bra     resume_userspace
284
285         .global eit_vector
286
287         .equ ei_vec_table, eit_vector + 0x0200
288
289 /*
290  * EI handler routine
291  */
292 ENTRY(ei_handler)
293 #if defined(CONFIG_CHIP_M32700)
294         ; WORKAROUND: force to clear SM bit and use the kernel stack (SPI).
295         SWITCH_TO_KERNEL_STACK
296 #endif
297         SAVE_ALL
298         mv      r1, sp                  ; arg1(regs)
299         ; get ICU status
300         seth    r0, #shigh(M32R_ICU_ISTS_ADDR)
301         ld      r0, @(low(M32R_ICU_ISTS_ADDR),r0)
302         push    r0
303 #if defined(CONFIG_SMP)
304         /*
305          * If IRQ == 0      --> Nothing to do,  Not write IMASK
306          * If IRQ == IPI    --> Do IPI handler, Not write IMASK
307          * If IRQ != 0, IPI --> Do do_IRQ(),    Write IMASK
308          */
309         slli    r0, #4
310         srli    r0, #24                 ; r0(irq_num<<2)
311         ;; IRQ exist check
312 #if defined(CONFIG_CHIP_M32700)
313         /* WORKAROUND: IMASK bug M32700-TS1, TS2 chip. */
314         bnez    r0, 0f
315         ld24    r14, #0x00070000
316         seth    r0, #shigh(M32R_ICU_IMASK_ADDR)
317         st      r14, @(low(M32R_ICU_IMASK_ADDR),r0)
318         bra     1f
319         .fillinsn
320 0:
321 #endif /* CONFIG_CHIP_M32700 */
322         beqz    r0, 1f                  ; if (!irq_num) goto exit
323         ;; IPI check
324         cmpi    r0, #(M32R_IRQ_IPI0<<2) ; ISN < IPI0 check
325         bc      2f
326         cmpi    r0, #((M32R_IRQ_IPI7+1)<<2)     ; ISN > IPI7 check
327         bnc     2f
328         LDIMM   (r2, ei_vec_table)
329         add     r2, r0
330         ld      r2, @r2
331         beqz    r2, 1f                  ; if (no IPI handler) goto exit
332         mv      r0, r1                  ; arg0(regs)
333         jl      r2
334         .fillinsn
335 1:
336         addi    sp, #4
337         bra     restore_all
338         .fillinsn
339 2:
340         srli    r0, #2
341 #else /* not CONFIG_SMP */
342         srli    r0, #22                 ; r0(irq)
343 #endif /* not CONFIG_SMP */
344
345 #if defined(CONFIG_PLAT_HAS_INT1ICU)
346         add3    r2, r0, #-(M32R_IRQ_INT1)       ; INT1# interrupt
347         bnez    r2, 3f
348         seth    r0, #shigh(M32R_INT1ICU_ISTS)
349         lduh    r0, @(low(M32R_INT1ICU_ISTS),r0)        ; bit10-6 : ISN
350         slli    r0, #21
351         srli    r0, #27                         ; ISN
352         addi    r0, #(M32R_INT1ICU_IRQ_BASE)
353         bra     check_end
354         .fillinsn
355 3:
356 #endif /* CONFIG_PLAT_HAS_INT1ICU */
357 #if defined(CONFIG_PLAT_HAS_INT0ICU)
358         add3    r2, r0, #-(M32R_IRQ_INT0)       ; INT0# interrupt
359         bnez    r2, 4f
360         seth    r0, #shigh(M32R_INT0ICU_ISTS)
361         lduh    r0, @(low(M32R_INT0ICU_ISTS),r0)        ; bit10-6 : ISN
362         slli    r0, #21
363         srli    r0, #27                         ; ISN
364         add3    r0, r0, #(M32R_INT0ICU_IRQ_BASE)
365         bra     check_end
366         .fillinsn
367 4:
368 #endif /* CONFIG_PLAT_HAS_INT0ICU */
369 #if defined(CONFIG_PLAT_HAS_INT2ICU)
370         add3    r2, r0, #-(M32R_IRQ_INT2)       ; INT2# interrupt
371         bnez    r2, 5f
372         seth    r0, #shigh(M32R_INT2ICU_ISTS)
373         lduh    r0, @(low(M32R_INT2ICU_ISTS),r0)        ; bit10-6 : ISN
374         slli    r0, #21
375         srli    r0, #27                         ; ISN
376         add3    r0, r0, #(M32R_INT2ICU_IRQ_BASE)
377         ; bra   check_end
378         .fillinsn
379 5:
380 #endif /* CONFIG_PLAT_HAS_INT2ICU */
381
382 check_end:
383         bl      do_IRQ
384         pop     r14
385         seth    r0, #shigh(M32R_ICU_IMASK_ADDR)
386         st      r14, @(low(M32R_ICU_IMASK_ADDR),r0)
387         bra  ret_from_intr
388
389 /*
390  * Default EIT handler
391  */
392         ALIGN
393 int_msg:
394         .asciz  "Unknown interrupt\n"
395         .byte   0
396
397 ENTRY(default_eit_handler)
398         push    r0
399         mvfc    r0, psw
400         push    r1
401         push    r2
402         push    r3
403         push    r0
404         LDIMM   (r0, __KERNEL_DS)
405         mv      r0, r1
406         mv      r0, r2
407         LDIMM   (r0, int_msg)
408         bl      printk
409         pop     r0
410         pop     r3
411         pop     r2
412         pop     r1
413         mvtc    r0, psw
414         pop     r0
415 infinit:
416         bra     infinit
417
418 #ifdef CONFIG_MMU
419 /*
420  * Access Exception handler
421  */
422 ENTRY(ace_handler)
423         SWITCH_TO_KERNEL_STACK
424         SAVE_ALL
425
426         seth    r2, #shigh(MMU_REG_BASE)        /* Check status register */
427         ld      r4, @(low(MESTS_offset),r2)
428         st      r4, @(low(MESTS_offset),r2)
429         srl3    r1, r4, #4
430 #ifdef CONFIG_CHIP_M32700
431         and3    r1, r1, #0x0000ffff
432         ; WORKAROUND: ignore TME bit for the M32700(TS1).
433 #endif /* CONFIG_CHIP_M32700 */
434         beqz    r1, inst
435 oprand:
436         ld      r2, @(low(MDEVA_offset),r2)     ; set address
437         srli    r1, #1
438         bra     1f
439 inst:
440         and3    r1, r4, #2
441         srli    r1, #1
442         or3     r1, r1, #8
443         mvfc    r2, bpc                         ; set address
444         .fillinsn
445 1:
446         mvfc    r3, psw
447         mv      r0, sp
448         and3    r3, r3, 0x800
449         srli    r3, #9
450         or      r1, r3
451         /*
452          * do_page_fault():
453          *    r0 : struct pt_regs *regs
454          *    r1 : unsigned long error-code
455          *    r2 : unsigned long address
456          * error-code:
457          *    +------+------+------+------+
458          *    | bit3 | bit2 | bit1 | bit0 |
459          *    +------+------+------+------+
460          *    bit 3 == 0:means data,          1:means instruction
461          *    bit 2 == 0:means kernel,        1:means user-mode
462          *    bit 1 == 0:means read,          1:means write
463          *    bit 0 == 0:means no page found  1:means protection fault
464          *
465          */
466         bl      do_page_fault
467         bra     ret_from_intr
468 #endif  /* CONFIG_MMU */
469
470
471 ENTRY(alignment_check)
472         /* void alignment_check(int error_code) */
473         SWITCH_TO_KERNEL_STACK
474         SAVE_ALL
475         ldi     r1, #0x30                       ; error_code
476         mv      r0, sp                          ; pt_regs
477         bl      do_alignment_check
478 error_code:
479         bra     ret_from_exception
480
481 ENTRY(rie_handler)
482         /* void rie_handler(int error_code) */
483         SWITCH_TO_KERNEL_STACK
484         SAVE_ALL
485         ldi     r1, #0x20                       ; error_code
486         mv      r0, sp                          ; pt_regs
487         bl      do_rie_handler
488         bra     error_code
489
490 ENTRY(pie_handler)
491         /* void pie_handler(int error_code) */
492         SWITCH_TO_KERNEL_STACK
493         SAVE_ALL
494         ldi     r1, #0                          ; error_code ; FIXME
495         mv      r0, sp                          ; pt_regs
496         bl      do_pie_handler
497         bra     error_code
498
499 ENTRY(debug_trap)
500         /* void debug_trap(void) */
501         .global withdraw_debug_trap
502         SWITCH_TO_KERNEL_STACK
503         SAVE_ALL
504         mv      r0, sp                          ; pt_regs
505         bl      withdraw_debug_trap
506         ldi     r1, #0                          ; error_code
507         mv      r0, sp                          ; pt_regs
508         bl      do_debug_trap
509         bra     error_code
510
511 ENTRY(ill_trap)
512         /* void ill_trap(void) */
513         SWITCH_TO_KERNEL_STACK
514         SAVE_ALL
515         ldi     r1, #0                          ; error_code ; FIXME
516         mv      r0, sp                          ; pt_regs
517         bl      do_ill_trap
518         bra     error_code
519
520 ENTRY(cache_flushing_handler)
521         /* void _flush_cache_all(void); */
522         .global _flush_cache_all
523         SWITCH_TO_KERNEL_STACK
524         push    r0
525         push    r1
526         push    r2
527         push    r3
528         push    r4
529         push    r5
530         push    r6
531         push    r7
532         push    lr
533         bl      _flush_cache_all
534         pop     lr
535         pop     r7
536         pop     r6
537         pop     r5
538         pop     r4
539         pop     r3
540         pop     r2
541         pop     r1
542         pop     r0
543         rte
544
545         .section .rodata,"a"
546 #include "syscall_table.S"
547
548 syscall_table_size=(.-sys_call_table)