2 * linux/arch/m32r/kernel/entry.S
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>
8 * Taken from i386 version.
9 * Copyright (C) 1991, 1992 Linus Torvalds
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.
17 * NOTE: This code handles signal-recognition, which happens every time
18 * after a timer-interrupt and after each system call.
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
30 * @(0x0c,sp) - *pt_regs
41 * @(0x38,sp) - syscall_nr
44 * @(0x44,sp) - acc1h ; ISA_DSP_LEVEL2 only
45 * @(0x48,sp) - acc1l ; ISA_DSP_LEVEL2 only
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
57 #include <linux/linkage.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>
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 */
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)
117 #define preempt_stop(x)
118 #define resume_kernel restore_all
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
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.
141 ; userspace resumption stub bypassing syscall exit tracing
147 #ifdef CONFIG_ISA_M32R2
148 and3 r4, r4, #0x8800 ; check BSM and BPM bits
150 and3 r4, r4, #0x8000 ; check BSM bit
152 beqz r4, resume_kernel
154 DISABLE_INTERRUPTS(r4) ; make sure we don't miss an interrupt
155 ; setting need_resched or sigpending
156 ; between sampling and the iret
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
164 #ifdef CONFIG_PREEMPT
167 ld r9, @(TI_PRE_COUNT, r8) ; non-zero preempt_count ?
170 ld r9, @(TI_FLAGS, r8) ; need_resched set ?
171 and3 r4, r9, #_TIF_NEED_RESCHED
173 ld r4, PSW(sp) ; interrupts off (exception path) ?
176 LDIMM (r4, PREEMPT_ACTIVE)
177 st r4, @(TI_PRE_COUNT, r8)
178 ENABLE_INTERRUPTS(r4)
181 st r4, @(TI_PRE_COUNT, r8)
182 DISABLE_INTERRUPTS(r4)
186 ; system call handler stub
188 SWITCH_TO_KERNEL_STACK
190 ENABLE_INTERRUPTS(r4) ; Enable interrupt
191 st sp, PTREGS(sp) ; implicit pt_regs parameter
192 cmpui r7, #NR_syscalls
194 st r7, SYSCALL_NR(sp) ; syscall_nr
195 ; system call tracing in operation
197 ld r9, @(TI_FLAGS, r8)
198 and3 r4, r9, #_TIF_SYSCALL_TRACE
199 bnez r4, syscall_trace_entry
201 slli r7, #2 ; table jump for the system call
202 LDIMM (r4, sys_call_table)
205 jl r7 ; execute system call
206 st r0, R0(sp) ; save the return value
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
217 # perform work that needs to be done immediately before resumption
221 and3 r4, r9, #_TIF_NEED_RESCHED
222 beqz r4, work_notifysig
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?
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
243 ; perform syscall exit tracing
256 ld r7, SYSCALL_NR(sp)
257 cmpui r7, #NR_syscalls
261 ; perform syscall exit tracing
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
288 .equ ei_vec_table, eit_vector + 0x0200
294 #if defined(CONFIG_CHIP_M32700)
295 ; WORKAROUND: force to clear SM bit and use the kernel stack (SPI).
296 SWITCH_TO_KERNEL_STACK
299 mv r1, sp ; arg1(regs)
301 seth r0, #shigh(M32R_ICU_ISTS_ADDR)
302 ld r0, @(low(M32R_ICU_ISTS_ADDR),r0)
304 #if defined(CONFIG_SMP)
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
311 srli r0, #24 ; r0(irq_num<<2)
313 #if defined(CONFIG_CHIP_M32700)
314 /* WORKAROUND: IMASK bug M32700-TS1, TS2 chip. */
316 ld24 r14, #0x00070000
317 seth r0, #shigh(M32R_ICU_IMASK_ADDR)
318 st r14, @(low(M32R_ICU_IMASK_ADDR),r0)
322 #endif /* CONFIG_CHIP_M32700 */
323 beqz r0, 1f ; if (!irq_num) goto exit
325 cmpi r0, #(M32R_IRQ_IPI0<<2) ; ISN < IPI0 check
327 cmpi r0, #((M32R_IRQ_IPI7+1)<<2) ; ISN > IPI7 check
329 LDIMM (r2, ei_vec_table)
332 beqz r2, 1f ; if (no IPI handler) goto exit
333 mv r0, r1 ; arg0(regs)
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
349 seth r0, #shigh(M32R_INT1ICU_ISTS)
350 lduh r0, @(low(M32R_INT1ICU_ISTS),r0) ; bit10-6 : ISN
353 addi r0, #(M32R_INT1ICU_IRQ_BASE)
357 #endif /* CONFIG_PLAT_HAS_INT1ICU */
358 #if defined(CONFIG_PLAT_HAS_INT0ICU)
359 add3 r2, r0, #-(M32R_IRQ_INT0) ; INT0# interrupt
361 seth r0, #shigh(M32R_INT0ICU_ISTS)
362 lduh r0, @(low(M32R_INT0ICU_ISTS),r0) ; bit10-6 : ISN
365 add3 r0, r0, #(M32R_INT0ICU_IRQ_BASE)
369 #endif /* CONFIG_PLAT_HAS_INT0ICU */
370 #if defined(CONFIG_PLAT_HAS_INT2ICU)
371 add3 r2, r0, #-(M32R_IRQ_INT2) ; INT2# interrupt
373 seth r0, #shigh(M32R_INT2ICU_ISTS)
374 lduh r0, @(low(M32R_INT2ICU_ISTS),r0) ; bit10-6 : ISN
377 add3 r0, r0, #(M32R_INT2ICU_IRQ_BASE)
381 #endif /* CONFIG_PLAT_HAS_INT2ICU */
386 seth r0, #shigh(M32R_ICU_IMASK_ADDR)
387 st r14, @(low(M32R_ICU_IMASK_ADDR),r0)
391 * Default EIT handler
395 .asciz "Unknown interrupt\n"
398 ENTRY(default_eit_handler)
405 LDIMM (r0, __KERNEL_DS)
421 * Access Exception handler
424 SWITCH_TO_KERNEL_STACK
427 seth r2, #shigh(MMU_REG_BASE) /* Check status register */
428 ld r4, @(low(MESTS_offset),r2)
429 st r4, @(low(MESTS_offset),r2)
431 #ifdef CONFIG_CHIP_M32700
432 and3 r1, r1, #0x0000ffff
433 ; WORKAROUND: ignore TME bit for the M32700(TS1).
434 #endif /* CONFIG_CHIP_M32700 */
437 ld r2, @(low(MDEVA_offset),r2) ; set address
444 mvfc r2, bpc ; set address
454 * r0 : struct pt_regs *regs
455 * r1 : unsigned long error-code
456 * r2 : unsigned long address
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
469 #endif /* CONFIG_MMU */
472 ENTRY(alignment_check)
473 /* void alignment_check(int error_code) */
474 SWITCH_TO_KERNEL_STACK
476 ldi r1, #0x30 ; error_code
478 bl do_alignment_check
480 bra ret_from_exception
483 /* void rie_handler(int error_code) */
484 SWITCH_TO_KERNEL_STACK
486 ldi r1, #0x20 ; error_code
492 /* void pie_handler(int error_code) */
493 SWITCH_TO_KERNEL_STACK
495 ldi r1, #0 ; error_code ; FIXME
501 /* void debug_trap(void) */
502 .global withdraw_debug_trap
503 SWITCH_TO_KERNEL_STACK
506 bl withdraw_debug_trap
507 ldi r1, #0 ; error_code
513 /* void ill_trap(void) */
514 SWITCH_TO_KERNEL_STACK
516 ldi r1, #0 ; error_code ; FIXME
521 ENTRY(cache_flushing_handler)
522 /* void _flush_cache_all(void); */
523 .global _flush_cache_all
524 SWITCH_TO_KERNEL_STACK
547 #include "syscall_table.S"
549 syscall_table_size=(.-sys_call_table)