GNU Linux-libre 4.14.332-gnu1
[releases.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)