• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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
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
139ENTRY(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
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
164resume_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
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
187	bl	preempt_schedule_irq
188	bra	need_resched
189#endif
190
191	; system call handler stub
192ENTRY(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
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:
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
219restore_all:
220	RESTORE_ALL
221
222	# perform work that needs to be done immediately before resumption
223	# r9 : flags
224	ALIGN
225work_pending:
226	and3	r4, r9, #_TIF_NEED_RESCHED
227	beqz	r4, work_notifysig
228work_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
240work_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
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
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
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)
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
3250:
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
3401:
341	addi	sp, #4
342	bra	restore_all
343	.fillinsn
3442:
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
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
367	slli	r0, #21
368	srli	r0, #27				; ISN
369	add3	r0, r0, #(M32R_INT0ICU_IRQ_BASE)
370	bra	check_end
371	.fillinsn
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
379	slli	r0, #21
380	srli	r0, #27				; ISN
381	add3	r0, r0, #(M32R_INT2ICU_IRQ_BASE)
382	; bra	check_end
383	.fillinsn
3845:
385#endif /* CONFIG_PLAT_HAS_INT2ICU */
386
387check_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
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
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)
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
483error_code:
484	bra	ret_from_exception
485
486ENTRY(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
495ENTRY(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
504ENTRY(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
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
525ENTRY(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
553syscall_table_size=(.-sys_call_table)
554