Full support for Ginger Console
[linux-ginger.git] / arch / m32r / kernel / entry.S
blob403869833b98fe6c95fd360d80cd762f3a5008e2
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 /* 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
128 ENTRY(ret_from_fork)
129         pop     r0
130         bl      schedule_tail
131         GET_THREAD_INFO(r8)
132         bra     syscall_exit
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  */
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
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
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
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
235 work_notifysig:                         ; deal with pending signals and
236                                         ; notify-resume requests
237         mv      r0, sp                  ; arg1 : struct pt_regs *regs
238         ldi     r1, #0                  ; arg2 : sigset_t *oldset
239         mv      r2, r9                  ; arg3 : __u32 thread_info_flags
240         bl      do_notify_resume
241         bra     restore_all
243         ; perform syscall exit tracing
244         ALIGN
245 syscall_trace_entry:
246         ldi     r4, #-ENOSYS
247         st      r4, R0(sp)
248         bl      do_syscall_trace
249         ld      r0, ORIG_R0(sp)
250         ld      r1, R1(sp)
251         ld      r2, R2(sp)
252         ld      r3, R3(sp)
253         ld      r4, R4(sp)
254         ld      r5, R5(sp)
255         ld      r6, R6(sp)
256         ld      r7, SYSCALL_NR(sp)
257         cmpui   r7, #NR_syscalls
258         bc      syscall_call
259         bra     syscall_exit
261         ; perform syscall exit tracing
262         ALIGN
263 syscall_exit_work:
264         ld      r9, @(TI_FLAGS, r8)
265         and3    r4, r9, #_TIF_SYSCALL_TRACE
266         beqz    r4, work_pending
267         ENABLE_INTERRUPTS(r4)           ; could let do_syscall_trace() call
268                                         ; schedule() instead
269         bl      do_syscall_trace
270         bra     resume_userspace
272         ALIGN
273 syscall_fault:
274         SAVE_ALL
275         GET_THREAD_INFO(r8)
276         ldi     r4, #-EFAULT
277         st      r4, R0(sp)
278         bra     resume_userspace
280         ALIGN
281 syscall_badsys:
282         ldi     r4, #-ENOSYS
283         st      r4, R0(sp)
284         bra     resume_userspace
286         .global eit_vector
288         .equ ei_vec_table, eit_vector + 0x0200
291  * EI handler routine
292  */
293 ENTRY(ei_handler)
294 #if defined(CONFIG_CHIP_M32700)
295         ; WORKAROUND: force to clear SM bit and use the kernel stack (SPI).
296         SWITCH_TO_KERNEL_STACK
297 #endif
298         SAVE_ALL
299         mv      r1, sp                  ; arg1(regs)
300         ; get ICU status
301         seth    r0, #shigh(M32R_ICU_ISTS_ADDR)
302         ld      r0, @(low(M32R_ICU_ISTS_ADDR),r0)
303         push    r0
304 #if defined(CONFIG_SMP)
305         /*
306          * If IRQ == 0      --> Nothing to do,  Not write IMASK
307          * If IRQ == IPI    --> Do IPI handler, Not write IMASK
308          * If IRQ != 0, IPI --> Do do_IRQ(),    Write IMASK
309          */
310         slli    r0, #4
311         srli    r0, #24                 ; r0(irq_num<<2)
312         ;; IRQ exist check
313 #if defined(CONFIG_CHIP_M32700)
314         /* WORKAROUND: IMASK bug M32700-TS1, TS2 chip. */
315         bnez    r0, 0f
316         ld24    r14, #0x00070000
317         seth    r0, #shigh(M32R_ICU_IMASK_ADDR)
318         st      r14, @(low(M32R_ICU_IMASK_ADDR),r0)
319         bra     1f
320         .fillinsn
322 #endif /* CONFIG_CHIP_M32700 */
323         beqz    r0, 1f                  ; if (!irq_num) goto exit
324         ;; IPI check
325         cmpi    r0, #(M32R_IRQ_IPI0<<2) ; ISN < IPI0 check
326         bc      2f
327         cmpi    r0, #((M32R_IRQ_IPI7+1)<<2)     ; ISN > IPI7 check
328         bnc     2f
329         LDIMM   (r2, ei_vec_table)
330         add     r2, r0
331         ld      r2, @r2
332         beqz    r2, 1f                  ; if (no IPI handler) goto exit
333         mv      r0, r1                  ; arg0(regs)
334         jl      r2
335         .fillinsn
337         addi    sp, #4
338         bra     restore_all
339         .fillinsn
341         srli    r0, #2
342 #else /* not CONFIG_SMP */
343         srli    r0, #22                 ; r0(irq)
344 #endif /* not CONFIG_SMP */
346 #if defined(CONFIG_PLAT_HAS_INT1ICU)
347         add3    r2, r0, #-(M32R_IRQ_INT1)       ; INT1# interrupt
348         bnez    r2, 3f
349         seth    r0, #shigh(M32R_INT1ICU_ISTS)
350         lduh    r0, @(low(M32R_INT1ICU_ISTS),r0)        ; bit10-6 : ISN
351         slli    r0, #21
352         srli    r0, #27                         ; ISN
353         addi    r0, #(M32R_INT1ICU_IRQ_BASE)
354         bra     check_end
355         .fillinsn
357 #endif /* CONFIG_PLAT_HAS_INT1ICU */
358 #if defined(CONFIG_PLAT_HAS_INT0ICU)
359         add3    r2, r0, #-(M32R_IRQ_INT0)       ; INT0# interrupt
360         bnez    r2, 4f
361         seth    r0, #shigh(M32R_INT0ICU_ISTS)
362         lduh    r0, @(low(M32R_INT0ICU_ISTS),r0)        ; bit10-6 : ISN
363         slli    r0, #21
364         srli    r0, #27                         ; ISN
365         add3    r0, r0, #(M32R_INT0ICU_IRQ_BASE)
366         bra     check_end
367         .fillinsn
369 #endif /* CONFIG_PLAT_HAS_INT0ICU */
370 #if defined(CONFIG_PLAT_HAS_INT2ICU)
371         add3    r2, r0, #-(M32R_IRQ_INT2)       ; INT2# interrupt
372         bnez    r2, 5f
373         seth    r0, #shigh(M32R_INT2ICU_ISTS)
374         lduh    r0, @(low(M32R_INT2ICU_ISTS),r0)        ; bit10-6 : ISN
375         slli    r0, #21
376         srli    r0, #27                         ; ISN
377         add3    r0, r0, #(M32R_INT2ICU_IRQ_BASE)
378         ; bra   check_end
379         .fillinsn
381 #endif /* CONFIG_PLAT_HAS_INT2ICU */
383 check_end:
384         bl      do_IRQ
385         pop     r14
386         seth    r0, #shigh(M32R_ICU_IMASK_ADDR)
387         st      r14, @(low(M32R_ICU_IMASK_ADDR),r0)
388         bra  ret_from_intr
391  * Default EIT handler
392  */
393         ALIGN
394 int_msg:
395         .asciz  "Unknown interrupt\n"
396         .byte   0
398 ENTRY(default_eit_handler)
399         push    r0
400         mvfc    r0, psw
401         push    r1
402         push    r2
403         push    r3
404         push    r0
405         LDIMM   (r0, __KERNEL_DS)
406         mv      r0, r1
407         mv      r0, r2
408         LDIMM   (r0, int_msg)
409         bl      printk
410         pop     r0
411         pop     r3
412         pop     r2
413         pop     r1
414         mvtc    r0, psw
415         pop     r0
416 infinit:
417         bra     infinit
419 #ifdef CONFIG_MMU
421  * Access Exception handler
422  */
423 ENTRY(ace_handler)
424         SWITCH_TO_KERNEL_STACK
425         SAVE_ALL
427         seth    r2, #shigh(MMU_REG_BASE)        /* Check status register */
428         ld      r4, @(low(MESTS_offset),r2)
429         st      r4, @(low(MESTS_offset),r2)
430         srl3    r1, r4, #4
431 #ifdef CONFIG_CHIP_M32700
432         and3    r1, r1, #0x0000ffff
433         ; WORKAROUND: ignore TME bit for the M32700(TS1).
434 #endif /* CONFIG_CHIP_M32700 */
435         beqz    r1, inst
436 oprand:
437         ld      r2, @(low(MDEVA_offset),r2)     ; set address
438         srli    r1, #1
439         bra     1f
440 inst:
441         and3    r1, r4, #2
442         srli    r1, #1
443         or3     r1, r1, #8
444         mvfc    r2, bpc                         ; set address
445         .fillinsn
447         mvfc    r3, psw
448         mv      r0, sp
449         and3    r3, r3, 0x800
450         srli    r3, #9
451         or      r1, r3
452         /*
453          * do_page_fault():
454          *    r0 : struct pt_regs *regs
455          *    r1 : unsigned long error-code
456          *    r2 : unsigned long address
457          * error-code:
458          *    +------+------+------+------+
459          *    | bit3 | bit2 | bit1 | bit0 |
460          *    +------+------+------+------+
461          *    bit 3 == 0:means data,          1:means instruction
462          *    bit 2 == 0:means kernel,        1:means user-mode
463          *    bit 1 == 0:means read,          1:means write
464          *    bit 0 == 0:means no page found  1:means protection fault
465          *
466          */
467         bl      do_page_fault
468         bra     ret_from_intr
469 #endif  /* CONFIG_MMU */
472 ENTRY(alignment_check)
473         /* void alignment_check(int error_code) */
474         SWITCH_TO_KERNEL_STACK
475         SAVE_ALL
476         ldi     r1, #0x30                       ; error_code
477         mv      r0, sp                          ; pt_regs
478         bl      do_alignment_check
479 error_code:
480         bra     ret_from_exception
482 ENTRY(rie_handler)
483         /* void rie_handler(int error_code) */
484         SWITCH_TO_KERNEL_STACK
485         SAVE_ALL
486         ldi     r1, #0x20                       ; error_code
487         mv      r0, sp                          ; pt_regs
488         bl      do_rie_handler
489         bra     error_code
491 ENTRY(pie_handler)
492         /* void pie_handler(int error_code) */
493         SWITCH_TO_KERNEL_STACK
494         SAVE_ALL
495         ldi     r1, #0                          ; error_code ; FIXME
496         mv      r0, sp                          ; pt_regs
497         bl      do_pie_handler
498         bra     error_code
500 ENTRY(debug_trap)
501         /* void debug_trap(void) */
502         .global withdraw_debug_trap
503         SWITCH_TO_KERNEL_STACK
504         SAVE_ALL
505         mv      r0, sp                          ; pt_regs
506         bl      withdraw_debug_trap
507         ldi     r1, #0                          ; error_code
508         mv      r0, sp                          ; pt_regs
509         bl      do_debug_trap
510         bra     error_code
512 ENTRY(ill_trap)
513         /* void ill_trap(void) */
514         SWITCH_TO_KERNEL_STACK
515         SAVE_ALL
516         ldi     r1, #0                          ; error_code ; FIXME
517         mv      r0, sp                          ; pt_regs
518         bl      do_ill_trap
519         bra     error_code
521 ENTRY(cache_flushing_handler)
522         /* void _flush_cache_all(void); */
523         .global _flush_cache_all
524         SWITCH_TO_KERNEL_STACK
525         push    r0
526         push    r1
527         push    r2
528         push    r3
529         push    r4
530         push    r5
531         push    r6
532         push    r7
533         push    lr
534         bl      _flush_cache_all
535         pop     lr
536         pop     r7
537         pop     r6
538         pop     r5
539         pop     r4
540         pop     r3
541         pop     r2
542         pop     r1
543         pop     r0
544         rte
546         .section .rodata,"a"
547 #include "syscall_table.S"
549 syscall_table_size=(.-sys_call_table)