Linux 2.6.25-rc4
[linux-2.6/next.git] / arch / m32r / kernel / entry.S
blobd4eaa2fd1818fea9b90e7c8bbdbe2bd7757ca99b
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  */
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  */
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>
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 */
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)
112 #define nr_syscalls ((syscall_table_size)/4)
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
121 ENTRY(ret_from_fork)
122         pop     r0
123         bl      schedule_tail
124         GET_THREAD_INFO(r8)
125         bra     syscall_exit
128  * Return to user mode is not as complex as all this looks,
129  * but we want the default path for a system call return to
130  * go as quickly as possible which is why some of this is
131  * less clear than it otherwise should be.
132  */
134         ; userspace resumption stub bypassing syscall exit tracing
135         ALIGN
136 ret_from_exception:
137         preempt_stop(r4)
138 ret_from_intr:
139         ld      r4, PSW(sp)
140 #ifdef CONFIG_ISA_M32R2
141         and3    r4, r4, #0x8800         ; check BSM and BPM bits
142 #else
143         and3    r4, r4, #0x8000         ; check BSM bit
144 #endif
145         beqz    r4, resume_kernel
146 ENTRY(resume_userspace)
147         DISABLE_INTERRUPTS(r4)          ; make sure we don't miss an interrupt
148                                         ; setting need_resched or sigpending
149                                         ; between sampling and the iret
150         GET_THREAD_INFO(r8)
151         ld      r9, @(TI_FLAGS, r8)
152         and3    r4, r9, #_TIF_WORK_MASK ; is there any work to be done on
153                                         ; int/exception return?
154         bnez    r4, work_pending
155         bra     restore_all
157 #ifdef CONFIG_PREEMPT
158 ENTRY(resume_kernel)
159         GET_THREAD_INFO(r8)
160         ld      r9, @(TI_PRE_COUNT, r8) ; non-zero preempt_count ?
161         bnez    r9, restore_all
162 need_resched:
163         ld      r9, @(TI_FLAGS, r8)     ; need_resched set ?
164         and3    r4, r9, #_TIF_NEED_RESCHED
165         beqz    r4, restore_all
166         ld      r4, PSW(sp)             ; interrupts off (exception path) ?
167         and3    r4, r4, #0x4000
168         beqz    r4, restore_all
169         LDIMM   (r4, PREEMPT_ACTIVE)
170         st      r4, @(TI_PRE_COUNT, r8)
171         ENABLE_INTERRUPTS(r4)
172         bl      schedule
173         ldi     r4, #0
174         st      r4, @(TI_PRE_COUNT, r8)
175         DISABLE_INTERRUPTS(r4)
176         bra     need_resched
177 #endif
179         ; system call handler stub
180 ENTRY(system_call)
181         SWITCH_TO_KERNEL_STACK
182         SAVE_ALL
183         ENABLE_INTERRUPTS(r4)           ; Enable interrupt
184         st      sp, PTREGS(sp)          ; implicit pt_regs parameter
185         cmpui   r7, #NR_syscalls
186         bnc     syscall_badsys
187         st      r7, SYSCALL_NR(sp)      ; syscall_nr
188                                         ; system call tracing in operation
189         GET_THREAD_INFO(r8)
190         ld      r9, @(TI_FLAGS, r8)
191         and3    r4, r9, #_TIF_SYSCALL_TRACE
192         bnez    r4, syscall_trace_entry
193 syscall_call:
194         slli    r7, #2                  ; table jump for the system call
195         LDIMM   (r4, sys_call_table)
196         add     r7, r4
197         ld      r7, @r7
198         jl      r7                      ; execute system call
199         st      r0, R0(sp)              ; save the return value
200 syscall_exit:
201         DISABLE_INTERRUPTS(r4)          ; make sure we don't miss an interrupt
202                                         ; setting need_resched or sigpending
203                                         ; between sampling and the iret
204         ld      r9, @(TI_FLAGS, r8)
205         and3    r4, r9, #_TIF_ALLWORK_MASK      ; current->work
206         bnez    r4, syscall_exit_work
207 restore_all:
208         RESTORE_ALL
210         # perform work that needs to be done immediately before resumption
211         # r9 : flags
212         ALIGN
213 work_pending:
214         and3    r4, r9, #_TIF_NEED_RESCHED
215         beqz    r4, work_notifysig
216 work_resched:
217         bl      schedule
218         DISABLE_INTERRUPTS(r4)          ; make sure we don't miss an interrupt
219                                         ; setting need_resched or sigpending
220                                         ; between sampling and the iret
221         ld      r9, @(TI_FLAGS, r8)
222         and3    r4, r9, #_TIF_WORK_MASK ; is there any work to be done other
223                                         ; than syscall tracing?
224         beqz    r4, restore_all
225         and3    r4, r4, #_TIF_NEED_RESCHED
226         bnez    r4, work_resched
228 work_notifysig:                         ; deal with pending signals and
229                                         ; notify-resume requests
230         mv      r0, sp                  ; arg1 : struct pt_regs *regs
231         ldi     r1, #0                  ; arg2 : sigset_t *oldset
232         mv      r2, r9                  ; arg3 : __u32 thread_info_flags
233         bl      do_notify_resume
234         bra     restore_all
236         ; perform syscall exit tracing
237         ALIGN
238 syscall_trace_entry:
239         ldi     r4, #-ENOSYS
240         st      r4, R0(sp)
241         bl      do_syscall_trace
242         ld      r0, ORIG_R0(sp)
243         ld      r1, R1(sp)
244         ld      r2, R2(sp)
245         ld      r3, R3(sp)
246         ld      r4, R4(sp)
247         ld      r5, R5(sp)
248         ld      r6, R6(sp)
249         ld      r7, SYSCALL_NR(sp)
250         cmpui   r7, #NR_syscalls
251         bc      syscall_call
252         bra     syscall_exit
254         ; perform syscall exit tracing
255         ALIGN
256 syscall_exit_work:
257         ld      r9, @(TI_FLAGS, r8)
258         and3    r4, r9, #_TIF_SYSCALL_TRACE
259         beqz    r4, work_pending
260         ENABLE_INTERRUPTS(r4)           ; could let do_syscall_trace() call
261                                         ; schedule() instead
262         bl      do_syscall_trace
263         bra     resume_userspace
265         ALIGN
266 syscall_fault:
267         SAVE_ALL
268         GET_THREAD_INFO(r8)
269         ldi     r4, #-EFAULT
270         st      r4, R0(sp)
271         bra     resume_userspace
273         ALIGN
274 syscall_badsys:
275         ldi     r4, #-ENOSYS
276         st      r4, R0(sp)
277         bra     resume_userspace
279         .global eit_vector
281         .equ ei_vec_table, eit_vector + 0x0200
284  * EI handler routine
285  */
286 ENTRY(ei_handler)
287 #if defined(CONFIG_CHIP_M32700)
288         ; WORKAROUND: force to clear SM bit and use the kernel stack (SPI).
289         SWITCH_TO_KERNEL_STACK
290 #endif
291         SAVE_ALL
292         mv      r1, sp                  ; arg1(regs)
293         ; get ICU status
294         seth    r0, #shigh(M32R_ICU_ISTS_ADDR)
295         ld      r0, @(low(M32R_ICU_ISTS_ADDR),r0)
296         push    r0
297 #if defined(CONFIG_SMP)
298         /*
299          * If IRQ == 0      --> Nothing to do,  Not write IMASK
300          * If IRQ == IPI    --> Do IPI handler, Not write IMASK
301          * If IRQ != 0, IPI --> Do do_IRQ(),    Write IMASK
302          */
303         slli    r0, #4
304         srli    r0, #24                 ; r0(irq_num<<2)
305         ;; IRQ exist check
306 #if defined(CONFIG_CHIP_M32700)
307         /* WORKAROUND: IMASK bug M32700-TS1, TS2 chip. */
308         bnez    r0, 0f
309         ld24    r14, #0x00070000
310         seth    r0, #shigh(M32R_ICU_IMASK_ADDR)
311         st      r14, @(low(M32R_ICU_IMASK_ADDR),r0)
312         bra     1f
313         .fillinsn
315 #endif /* CONFIG_CHIP_M32700 */
316         beqz    r0, 1f                  ; if (!irq_num) goto exit
317         ;; IPI check
318         cmpi    r0, #(M32R_IRQ_IPI0<<2) ; ISN < IPI0 check
319         bc      2f
320         cmpi    r0, #((M32R_IRQ_IPI7+1)<<2)     ; ISN > IPI7 check
321         bnc     2f
322         LDIMM   (r2, ei_vec_table)
323         add     r2, r0
324         ld      r2, @r2
325         beqz    r2, 1f                  ; if (no IPI handler) goto exit
326         mv      r0, r1                  ; arg0(regs)
327         jl      r2
328         .fillinsn
330         addi    sp, #4
331         bra     restore_all
332         .fillinsn
334         srli    r0, #2
335 #else /* not CONFIG_SMP */
336         srli    r0, #22                 ; r0(irq)
337 #endif /* not CONFIG_SMP */
339 #if defined(CONFIG_PLAT_HAS_INT1ICU)
340         add3    r2, r0, #-(M32R_IRQ_INT1)       ; INT1# interrupt
341         bnez    r2, 3f
342         seth    r0, #shigh(M32R_INT1ICU_ISTS)
343         lduh    r0, @(low(M32R_INT1ICU_ISTS),r0)        ; bit10-6 : ISN
344         slli    r0, #21
345         srli    r0, #27                         ; ISN
346         addi    r0, #(M32R_INT1ICU_IRQ_BASE)
347         bra     check_end
348         .fillinsn
350 #endif /* CONFIG_PLAT_HAS_INT1ICU */
351 #if defined(CONFIG_PLAT_HAS_INT0ICU)
352         add3    r2, r0, #-(M32R_IRQ_INT0)       ; INT0# interrupt
353         bnez    r2, 4f
354         seth    r0, #shigh(M32R_INT0ICU_ISTS)
355         lduh    r0, @(low(M32R_INT0ICU_ISTS),r0)        ; bit10-6 : ISN
356         slli    r0, #21
357         srli    r0, #27                         ; ISN
358         add3    r0, r0, #(M32R_INT0ICU_IRQ_BASE)
359         bra     check_end
360         .fillinsn
362 #endif /* CONFIG_PLAT_HAS_INT0ICU */
363 #if defined(CONFIG_PLAT_HAS_INT2ICU)
364         add3    r2, r0, #-(M32R_IRQ_INT2)       ; INT2# interrupt
365         bnez    r2, 5f
366         seth    r0, #shigh(M32R_INT2ICU_ISTS)
367         lduh    r0, @(low(M32R_INT2ICU_ISTS),r0)        ; bit10-6 : ISN
368         slli    r0, #21
369         srli    r0, #27                         ; ISN
370         add3    r0, r0, #(M32R_INT2ICU_IRQ_BASE)
371         ; bra   check_end
372         .fillinsn
374 #endif /* CONFIG_PLAT_HAS_INT2ICU */
376 check_end:
377         bl      do_IRQ
378         pop     r14
379         seth    r0, #shigh(M32R_ICU_IMASK_ADDR)
380         st      r14, @(low(M32R_ICU_IMASK_ADDR),r0)
381         bra  ret_from_intr
384  * Default EIT handler
385  */
386         ALIGN
387 int_msg:
388         .asciz  "Unknown interrupt\n"
389         .byte   0
391 ENTRY(default_eit_handler)
392         push    r0
393         mvfc    r0, psw
394         push    r1
395         push    r2
396         push    r3
397         push    r0
398         LDIMM   (r0, __KERNEL_DS)
399         mv      r0, r1
400         mv      r0, r2
401         LDIMM   (r0, int_msg)
402         bl      printk
403         pop     r0
404         pop     r3
405         pop     r2
406         pop     r1
407         mvtc    r0, psw
408         pop     r0
409 infinit:
410         bra     infinit
412 #ifdef CONFIG_MMU
414  * Access Exception handler
415  */
416 ENTRY(ace_handler)
417         SWITCH_TO_KERNEL_STACK
418         SAVE_ALL
420         seth    r2, #shigh(MMU_REG_BASE)        /* Check status register */
421         ld      r4, @(low(MESTS_offset),r2)
422         st      r4, @(low(MESTS_offset),r2)
423         srl3    r1, r4, #4
424 #ifdef CONFIG_CHIP_M32700
425         and3    r1, r1, #0x0000ffff
426         ; WORKAROUND: ignore TME bit for the M32700(TS1).
427 #endif /* CONFIG_CHIP_M32700 */
428         beqz    r1, inst
429 oprand:
430         ld      r2, @(low(MDEVA_offset),r2)     ; set address
431         srli    r1, #1
432         bra     1f
433 inst:
434         and3    r1, r4, #2
435         srli    r1, #1
436         or3     r1, r1, #8
437         mvfc    r2, bpc                         ; set address
438         .fillinsn
440         mvfc    r3, psw
441         mv      r0, sp
442         and3    r3, r3, 0x800
443         srli    r3, #9
444         or      r1, r3
445         /*
446          * do_page_fault():
447          *    r0 : struct pt_regs *regs
448          *    r1 : unsigned long error-code
449          *    r2 : unsigned long address
450          * error-code:
451          *    +------+------+------+------+
452          *    | bit3 | bit2 | bit1 | bit0 |
453          *    +------+------+------+------+
454          *    bit 3 == 0:means data,          1:means instruction
455          *    bit 2 == 0:means kernel,        1:means user-mode
456          *    bit 1 == 0:means read,          1:means write
457          *    bit 0 == 0:means no page found  1:means protection fault
458          *
459          */
460         bl      do_page_fault
461         bra     ret_from_intr
462 #endif  /* CONFIG_MMU */
465 ENTRY(alignment_check)
466         /* void alignment_check(int error_code) */
467         SWITCH_TO_KERNEL_STACK
468         SAVE_ALL
469         ldi     r1, #0x30                       ; error_code
470         mv      r0, sp                          ; pt_regs
471         bl      do_alignment_check
472 error_code:
473         bra     ret_from_exception
475 ENTRY(rie_handler)
476         /* void rie_handler(int error_code) */
477         SWITCH_TO_KERNEL_STACK
478         SAVE_ALL
479         ldi     r1, #0x20                       ; error_code
480         mv      r0, sp                          ; pt_regs
481         bl      do_rie_handler
482         bra     error_code
484 ENTRY(pie_handler)
485         /* void pie_handler(int error_code) */
486         SWITCH_TO_KERNEL_STACK
487         SAVE_ALL
488         ldi     r1, #0                          ; error_code ; FIXME
489         mv      r0, sp                          ; pt_regs
490         bl      do_pie_handler
491         bra     error_code
493 ENTRY(debug_trap)
494         /* void debug_trap(void) */
495         .global withdraw_debug_trap
496         SWITCH_TO_KERNEL_STACK
497         SAVE_ALL
498         mv      r0, sp                          ; pt_regs
499         bl      withdraw_debug_trap
500         ldi     r1, #0                          ; error_code
501         mv      r0, sp                          ; pt_regs
502         bl      do_debug_trap
503         bra     error_code
505 ENTRY(ill_trap)
506         /* void ill_trap(void) */
507         SWITCH_TO_KERNEL_STACK
508         SAVE_ALL
509         ldi     r1, #0                          ; error_code ; FIXME
510         mv      r0, sp                          ; pt_regs
511         bl      do_ill_trap
512         bra     error_code
514 ENTRY(cache_flushing_handler)
515         /* void _flush_cache_all(void); */
516         .global _flush_cache_all
517         SWITCH_TO_KERNEL_STACK
518         push    r0
519         push    r1
520         push    r2
521         push    r3
522         push    r4
523         push    r5
524         push    r6
525         push    r7
526         push    lr
527         bl      _flush_cache_all
528         pop     lr
529         pop     r7
530         pop     r6
531         pop     r5
532         pop     r4
533         pop     r3
534         pop     r2
535         pop     r1
536         pop     r0
537         rte
539         .section .rodata,"a"
540 #include "syscall_table.S"
542 syscall_table_size=(.-sys_call_table)