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