• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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)
552