]> git.proxmox.com Git - mirror_ubuntu-jammy-kernel.git/blame - arch/m32r/kernel/entry.S
License cleanup: add SPDX GPL-2.0 license identifier to files with no license
[mirror_ubuntu-jammy-kernel.git] / arch / m32r / kernel / entry.S
CommitLineData
b2441318 1/* SPDX-License-Identifier: GPL-2.0 */
1da177e4
LT
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
8e8ff02c 24 * updated in fork.c:copy_thread, signal.c:do_signal,
1da177e4
LT
25 * ptrace.c and ptrace.h
26 *
8b03a632
HT
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
1da177e4
LT
56 */
57
1da177e4
LT
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>
37f078ff 69#include <asm/asm-offsets.h>
1da177e4
LT
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)
1da177e4
LT
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)
1da177e4 113
9990b48a
HT
114#define nr_syscalls ((syscall_table_size)/4)
115
1da177e4 116#ifdef CONFIG_PREEMPT
7071b291 117#define preempt_stop(x) DISABLE_INTERRUPTS(x)
1da177e4
LT
118#else
119#define preempt_stop(x)
120#define resume_kernel restore_all
121#endif
122
00b01b24
TA
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
ea4a1da9
AV
130ENTRY(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
1da177e4 139ENTRY(ret_from_fork)
4127272c 140 pop r0
1da177e4
LT
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
154ret_from_exception:
155 preempt_stop(r4)
156ret_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
81e48073 164resume_userspace:
7071b291 165 DISABLE_INTERRUPTS(r4) ; make sure we don't miss an interrupt
1da177e4
LT
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
176ENTRY(resume_kernel)
177 GET_THREAD_INFO(r8)
178 ld r9, @(TI_PRE_COUNT, r8) ; non-zero preempt_count ?
179 bnez r9, restore_all
180need_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
650e4dc2 187 bl preempt_schedule_irq
1da177e4
LT
188 bra need_resched
189#endif
190
191 ; system call handler stub
192ENTRY(system_call)
193 SWITCH_TO_KERNEL_STACK
194 SAVE_ALL
7071b291 195 ENABLE_INTERRUPTS(r4) ; Enable interrupt
1da177e4
LT
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
205syscall_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
212syscall_exit:
7071b291 213 DISABLE_INTERRUPTS(r4) ; make sure we don't miss an interrupt
1da177e4
LT
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
219restore_all:
220 RESTORE_ALL
221
222 # perform work that needs to be done immediately before resumption
8e8ff02c 223 # r9 : flags
1da177e4
LT
224 ALIGN
225work_pending:
226 and3 r4, r9, #_TIF_NEED_RESCHED
227 beqz r4, work_notifysig
228work_resched:
229 bl schedule
7071b291 230 DISABLE_INTERRUPTS(r4) ; make sure we don't miss an interrupt
1da177e4
LT
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
240work_notifysig: ; deal with pending signals and
241 ; notify-resume requests
242 mv r0, sp ; arg1 : struct pt_regs *regs
a7481024 243 mv r1, r9 ; arg2 : __u32 thread_info_flags
1da177e4 244 bl do_notify_resume
a7481024 245 bra resume_userspace
1da177e4
LT
246
247 ; perform syscall exit tracing
248 ALIGN
249syscall_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
267syscall_exit_work:
268 ld r9, @(TI_FLAGS, r8)
269 and3 r4, r9, #_TIF_SYSCALL_TRACE
270 beqz r4, work_pending
7071b291 271 ENABLE_INTERRUPTS(r4) ; could let do_syscall_trace() call
1da177e4
LT
272 ; schedule() instead
273 bl do_syscall_trace
274 bra resume_userspace
275
276 ALIGN
277syscall_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
285syscall_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 */
297ENTRY(ei_handler)
298#if defined(CONFIG_CHIP_M32700)
1da177e4 299 ; WORKAROUND: force to clear SM bit and use the kernel stack (SPI).
5171b100 300 SWITCH_TO_KERNEL_STACK
1da177e4
LT
301#endif
302 SAVE_ALL
303 mv r1, sp ; arg1(regs)
de2232ed 304 ; get ICU status
1da177e4
LT
305 seth r0, #shigh(M32R_ICU_ISTS_ADDR)
306 ld r0, @(low(M32R_ICU_ISTS_ADDR),r0)
4127272c 307 push r0
1da177e4
LT
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. */
5171b100
HT
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
3250:
326#endif /* CONFIG_CHIP_M32700 */
1da177e4 327 beqz r0, 1f ; if (!irq_num) goto exit
1da177e4
LT
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
3401:
341 addi sp, #4
abd0a782 342 bra restore_all
1da177e4
LT
343 .fillinsn
3442:
345 srli r0, #2
5171b100 346#else /* not CONFIG_SMP */
1da177e4 347 srli r0, #22 ; r0(irq)
5171b100
HT
348#endif /* not CONFIG_SMP */
349
350#if defined(CONFIG_PLAT_HAS_INT1ICU)
1da177e4 351 add3 r2, r0, #-(M32R_IRQ_INT1) ; INT1# interrupt
5171b100
HT
352 bnez r2, 3f
353 seth r0, #shigh(M32R_INT1ICU_ISTS)
354 lduh r0, @(low(M32R_INT1ICU_ISTS),r0) ; bit10-6 : ISN
1da177e4
LT
355 slli r0, #21
356 srli r0, #27 ; ISN
5171b100 357 addi r0, #(M32R_INT1ICU_IRQ_BASE)
1da177e4
LT
358 bra check_end
359 .fillinsn
5171b100
HT
3603:
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
1da177e4 367 slli r0, #21
5171b100 368 srli r0, #27 ; ISN
33205613 369 add3 r0, r0, #(M32R_INT0ICU_IRQ_BASE)
1da177e4
LT
370 bra check_end
371 .fillinsn
5171b100
HT
3724:
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
9287d95e 379 slli r0, #21
5171b100 380 srli r0, #27 ; ISN
33205613 381 add3 r0, r0, #(M32R_INT2ICU_IRQ_BASE)
5171b100 382 ; bra check_end
9287d95e 383 .fillinsn
5171b100
HT
3845:
385#endif /* CONFIG_PLAT_HAS_INT2ICU */
de2232ed 386
9287d95e 387check_end:
1da177e4 388 bl do_IRQ
4127272c 389 pop r14
1da177e4
LT
390 seth r0, #shigh(M32R_ICU_IMASK_ADDR)
391 st r14, @(low(M32R_ICU_IMASK_ADDR),r0)
1da177e4
LT
392 bra ret_from_intr
393
394/*
395 * Default EIT handler
396 */
397 ALIGN
398int_msg:
399 .asciz "Unknown interrupt\n"
400 .byte 0
401
402ENTRY(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
420infinit:
421 bra infinit
422
423#ifdef CONFIG_MMU
424/*
425 * Access Exception handler
426 */
427ENTRY(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
440oprand:
441 ld r2, @(low(MDEVA_offset),r2) ; set address
1da177e4
LT
442 srli r1, #1
443 bra 1f
444inst:
445 and3 r1, r4, #2
446 srli r1, #1
447 or3 r1, r1, #8
448 mvfc r2, bpc ; set address
449 .fillinsn
4501:
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
476ENTRY(alignment_check)
de2232ed 477 /* void alignment_check(int error_code) */
1da177e4
LT
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
483error_code:
484 bra ret_from_exception
485
486ENTRY(rie_handler)
de2232ed 487 /* void rie_handler(int error_code) */
1da177e4
LT
488 SWITCH_TO_KERNEL_STACK
489 SAVE_ALL
1da177e4
LT
490 ldi r1, #0x20 ; error_code
491 mv r0, sp ; pt_regs
492 bl do_rie_handler
493 bra error_code
494
495ENTRY(pie_handler)
de2232ed 496 /* void pie_handler(int error_code) */
1da177e4
LT
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
504ENTRY(debug_trap)
1da177e4 505 /* void debug_trap(void) */
de2232ed 506 .global withdraw_debug_trap
1da177e4
LT
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
9de11aab
HT
516ENTRY(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
1da177e4 525ENTRY(cache_flushing_handler)
1da177e4 526 /* void _flush_cache_all(void); */
de2232ed 527 .global _flush_cache_all
1da177e4
LT
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
9990b48a
HT
550 .section .rodata,"a"
551#include "syscall_table.S"
1da177e4
LT
552
553syscall_table_size=(.-sys_call_table)