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