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