• 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
121ENTRY(ret_from_fork)
122	pop	r0
123	bl	schedule_tail
124	GET_THREAD_INFO(r8)
125	bra	syscall_exit
126
127/*
128 * Return to user mode is not as complex as all this looks,
129 * but we want the default path for a system call return to
130 * go as quickly as possible which is why some of this is
131 * less clear than it otherwise should be.
132 */
133
134	; userspace resumption stub bypassing syscall exit tracing
135	ALIGN
136ret_from_exception:
137	preempt_stop(r4)
138ret_from_intr:
139	ld	r4, PSW(sp)
140#ifdef CONFIG_ISA_M32R2
141	and3	r4, r4, #0x8800		; check BSM and BPM bits
142#else
143	and3	r4, r4, #0x8000		; check BSM bit
144#endif
145	beqz	r4, resume_kernel
146resume_userspace:
147	DISABLE_INTERRUPTS(r4)		; make sure we don't miss an interrupt
148					; setting need_resched or sigpending
149					; between sampling and the iret
150	GET_THREAD_INFO(r8)
151	ld	r9, @(TI_FLAGS, r8)
152	and3	r4, r9, #_TIF_WORK_MASK	; is there any work to be done on
153					; int/exception return?
154	bnez	r4, work_pending
155	bra	restore_all
156
157#ifdef CONFIG_PREEMPT
158ENTRY(resume_kernel)
159	GET_THREAD_INFO(r8)
160	ld	r9, @(TI_PRE_COUNT, r8)	; non-zero preempt_count ?
161	bnez	r9, restore_all
162need_resched:
163	ld	r9, @(TI_FLAGS, r8)	; need_resched set ?
164	and3	r4, r9, #_TIF_NEED_RESCHED
165	beqz	r4, restore_all
166	ld	r4, PSW(sp)		; interrupts off (exception path) ?
167	and3	r4, r4, #0x4000
168	beqz	r4, restore_all
169	LDIMM	(r4, PREEMPT_ACTIVE)
170	st	r4, @(TI_PRE_COUNT, r8)
171	ENABLE_INTERRUPTS(r4)
172	bl	schedule
173	ldi	r4, #0
174	st	r4, @(TI_PRE_COUNT, r8)
175	DISABLE_INTERRUPTS(r4)
176	bra	need_resched
177#endif
178
179	; system call handler stub
180ENTRY(system_call)
181	SWITCH_TO_KERNEL_STACK
182	SAVE_ALL
183	ENABLE_INTERRUPTS(r4)		; Enable interrupt
184	st	sp, PTREGS(sp)		; implicit pt_regs parameter
185	cmpui	r7, #NR_syscalls
186	bnc	syscall_badsys
187	st	r7, SYSCALL_NR(sp)	; syscall_nr
188					; system call tracing in operation
189	GET_THREAD_INFO(r8)
190	ld	r9, @(TI_FLAGS, r8)
191	and3	r4, r9, #_TIF_SYSCALL_TRACE
192	bnez	r4, syscall_trace_entry
193syscall_call:
194	slli	r7, #2			; table jump for the system call
195	LDIMM	(r4, sys_call_table)
196	add	r7, r4
197	ld	r7, @r7
198	jl	r7			; execute system call
199	st	r0, R0(sp)		; save the return value
200syscall_exit:
201	DISABLE_INTERRUPTS(r4)		; make sure we don't miss an interrupt
202					; setting need_resched or sigpending
203					; between sampling and the iret
204	ld	r9, @(TI_FLAGS, r8)
205	and3	r4, r9, #_TIF_ALLWORK_MASK	; current->work
206	bnez	r4, syscall_exit_work
207restore_all:
208	RESTORE_ALL
209
210	# perform work that needs to be done immediately before resumption
211	# r9 : flags
212	ALIGN
213work_pending:
214	and3	r4, r9, #_TIF_NEED_RESCHED
215	beqz	r4, work_notifysig
216work_resched:
217	bl	schedule
218	DISABLE_INTERRUPTS(r4)		; make sure we don't miss an interrupt
219					; setting need_resched or sigpending
220					; between sampling and the iret
221	ld	r9, @(TI_FLAGS, r8)
222	and3	r4, r9, #_TIF_WORK_MASK	; is there any work to be done other
223					; than syscall tracing?
224	beqz	r4, restore_all
225	and3	r4, r4, #_TIF_NEED_RESCHED
226	bnez	r4, work_resched
227
228work_notifysig:				; deal with pending signals and
229					; notify-resume requests
230	mv	r0, sp			; arg1 : struct pt_regs *regs
231	ldi	r1, #0			; arg2 : sigset_t *oldset
232	mv	r2, r9			; arg3 : __u32 thread_info_flags
233	bl	do_notify_resume
234	bra	restore_all
235
236	; perform syscall exit tracing
237	ALIGN
238syscall_trace_entry:
239	ldi	r4, #-ENOSYS
240	st	r4, R0(sp)
241	bl	do_syscall_trace
242	ld	r0, ORIG_R0(sp)
243	ld	r1, R1(sp)
244	ld	r2, R2(sp)
245	ld	r3, R3(sp)
246	ld	r4, R4(sp)
247	ld	r5, R5(sp)
248	ld	r6, R6(sp)
249	ld	r7, SYSCALL_NR(sp)
250	cmpui	r7, #NR_syscalls
251	bc	syscall_call
252	bra	syscall_exit
253
254	; perform syscall exit tracing
255	ALIGN
256syscall_exit_work:
257	ld	r9, @(TI_FLAGS, r8)
258	and3	r4, r9, #_TIF_SYSCALL_TRACE
259	beqz	r4, work_pending
260	ENABLE_INTERRUPTS(r4)		; could let do_syscall_trace() call
261					; schedule() instead
262	bl	do_syscall_trace
263	bra	resume_userspace
264
265	ALIGN
266syscall_fault:
267	SAVE_ALL
268	GET_THREAD_INFO(r8)
269	ldi	r4, #-EFAULT
270	st	r4, R0(sp)
271	bra	resume_userspace
272
273	ALIGN
274syscall_badsys:
275	ldi	r4, #-ENOSYS
276	st	r4, R0(sp)
277	bra	resume_userspace
278
279	.global	eit_vector
280
281	.equ ei_vec_table, eit_vector + 0x0200
282
283/*
284 * EI handler routine
285 */
286ENTRY(ei_handler)
287#if defined(CONFIG_CHIP_M32700)
288	; WORKAROUND: force to clear SM bit and use the kernel stack (SPI).
289	SWITCH_TO_KERNEL_STACK
290#endif
291	SAVE_ALL
292	mv	r1, sp			; arg1(regs)
293	; get ICU status
294	seth	r0, #shigh(M32R_ICU_ISTS_ADDR)
295	ld	r0, @(low(M32R_ICU_ISTS_ADDR),r0)
296	push	r0
297#if defined(CONFIG_SMP)
298	/*
299	 * If IRQ == 0      --> Nothing to do,  Not write IMASK
300	 * If IRQ == IPI    --> Do IPI handler, Not write IMASK
301	 * If IRQ != 0, IPI --> Do do_IRQ(),    Write IMASK
302	 */
303	slli	r0, #4
304	srli	r0, #24			; r0(irq_num<<2)
305	;; IRQ exist check
306#if defined(CONFIG_CHIP_M32700)
307	/* WORKAROUND: IMASK bug M32700-TS1, TS2 chip. */
308	bnez	r0, 0f
309	ld24	r14, #0x00070000
310	seth	r0, #shigh(M32R_ICU_IMASK_ADDR)
311	st	r14, @(low(M32R_ICU_IMASK_ADDR),r0)
312	bra	1f
313	.fillinsn
3140:
315#endif /* CONFIG_CHIP_M32700 */
316	beqz	r0, 1f			; if (!irq_num) goto exit
317	;; IPI check
318	cmpi	r0, #(M32R_IRQ_IPI0<<2)	; ISN < IPI0 check
319	bc	2f
320	cmpi	r0, #((M32R_IRQ_IPI7+1)<<2)	; ISN > IPI7 check
321	bnc	2f
322	LDIMM	(r2, ei_vec_table)
323	add	r2, r0
324	ld	r2, @r2
325	beqz	r2, 1f			; if (no IPI handler) goto exit
326	mv	r0, r1			; arg0(regs)
327	jl	r2
328	.fillinsn
3291:
330	addi	sp, #4
331	bra	restore_all
332	.fillinsn
3332:
334	srli	r0, #2
335#else /* not CONFIG_SMP */
336	srli	r0, #22			; r0(irq)
337#endif /* not CONFIG_SMP */
338
339#if defined(CONFIG_PLAT_HAS_INT1ICU)
340	add3	r2, r0, #-(M32R_IRQ_INT1)	; INT1# interrupt
341	bnez	r2, 3f
342	seth	r0, #shigh(M32R_INT1ICU_ISTS)
343	lduh	r0, @(low(M32R_INT1ICU_ISTS),r0)	; bit10-6 : ISN
344	slli	r0, #21
345	srli	r0, #27				; ISN
346	addi	r0, #(M32R_INT1ICU_IRQ_BASE)
347	bra	check_end
348	.fillinsn
3493:
350#endif /* CONFIG_PLAT_HAS_INT1ICU */
351#if defined(CONFIG_PLAT_HAS_INT0ICU)
352	add3	r2, r0, #-(M32R_IRQ_INT0)	; INT0# interrupt
353	bnez	r2, 4f
354	seth	r0, #shigh(M32R_INT0ICU_ISTS)
355	lduh	r0, @(low(M32R_INT0ICU_ISTS),r0)	; bit10-6 : ISN
356	slli	r0, #21
357	srli	r0, #27				; ISN
358	add3	r0, r0, #(M32R_INT0ICU_IRQ_BASE)
359	bra	check_end
360	.fillinsn
3614:
362#endif /* CONFIG_PLAT_HAS_INT0ICU */
363#if defined(CONFIG_PLAT_HAS_INT2ICU)
364	add3	r2, r0, #-(M32R_IRQ_INT2)	; INT2# interrupt
365	bnez	r2, 5f
366	seth	r0, #shigh(M32R_INT2ICU_ISTS)
367	lduh	r0, @(low(M32R_INT2ICU_ISTS),r0)	; bit10-6 : ISN
368	slli	r0, #21
369	srli	r0, #27				; ISN
370	add3	r0, r0, #(M32R_INT2ICU_IRQ_BASE)
371	; bra	check_end
372	.fillinsn
3735:
374#endif /* CONFIG_PLAT_HAS_INT2ICU */
375
376check_end:
377	bl	do_IRQ
378	pop	r14
379	seth	r0, #shigh(M32R_ICU_IMASK_ADDR)
380	st	r14, @(low(M32R_ICU_IMASK_ADDR),r0)
381	bra  ret_from_intr
382
383/*
384 * Default EIT handler
385 */
386	ALIGN
387int_msg:
388	.asciz  "Unknown interrupt\n"
389	.byte	0
390
391ENTRY(default_eit_handler)
392	push	r0
393	mvfc	r0, psw
394	push	r1
395	push	r2
396	push	r3
397	push	r0
398	LDIMM	(r0, __KERNEL_DS)
399	mv	r0, r1
400	mv	r0, r2
401	LDIMM	(r0, int_msg)
402	bl	printk
403	pop	r0
404	pop	r3
405	pop	r2
406	pop	r1
407	mvtc	r0, psw
408	pop	r0
409infinit:
410	bra	infinit
411
412#ifdef CONFIG_MMU
413/*
414 * Access Exception handler
415 */
416ENTRY(ace_handler)
417	SWITCH_TO_KERNEL_STACK
418	SAVE_ALL
419
420	seth	r2, #shigh(MMU_REG_BASE)	/* Check status register */
421	ld	r4, @(low(MESTS_offset),r2)
422	st	r4, @(low(MESTS_offset),r2)
423	srl3	r1, r4, #4
424#ifdef CONFIG_CHIP_M32700
425	and3	r1, r1, #0x0000ffff
426	; WORKAROUND: ignore TME bit for the M32700(TS1).
427#endif /* CONFIG_CHIP_M32700 */
428	beqz	r1, inst
429oprand:
430	ld	r2, @(low(MDEVA_offset),r2)	; set address
431	srli	r1, #1
432	bra	1f
433inst:
434	and3	r1, r4, #2
435	srli	r1, #1
436	or3	r1, r1, #8
437	mvfc	r2, bpc				; set address
438	.fillinsn
4391:
440	mvfc	r3, psw
441	mv	r0, sp
442	and3	r3, r3, 0x800
443	srli	r3, #9
444	or	r1, r3
445	/*
446	 * do_page_fault():
447	 *    r0 : struct pt_regs *regs
448	 *    r1 : unsigned long error-code
449	 *    r2 : unsigned long address
450	 * error-code:
451	 *    +------+------+------+------+
452	 *    | bit3 | bit2 | bit1 | bit0 |
453	 *    +------+------+------+------+
454	 *    bit 3 == 0:means data,          1:means instruction
455	 *    bit 2 == 0:means kernel,        1:means user-mode
456	 *    bit 1 == 0:means read,          1:means write
457	 *    bit 0 == 0:means no page found  1:means protection fault
458	 *
459	 */
460	bl	do_page_fault
461	bra	ret_from_intr
462#endif  /* CONFIG_MMU */
463
464
465ENTRY(alignment_check)
466	/* void alignment_check(int error_code) */
467	SWITCH_TO_KERNEL_STACK
468	SAVE_ALL
469	ldi	r1, #0x30			; error_code
470	mv	r0, sp				; pt_regs
471	bl	do_alignment_check
472error_code:
473	bra	ret_from_exception
474
475ENTRY(rie_handler)
476	/* void rie_handler(int error_code) */
477	SWITCH_TO_KERNEL_STACK
478	SAVE_ALL
479	ldi	r1, #0x20			; error_code
480	mv	r0, sp				; pt_regs
481	bl	do_rie_handler
482	bra	error_code
483
484ENTRY(pie_handler)
485	/* void pie_handler(int error_code) */
486	SWITCH_TO_KERNEL_STACK
487	SAVE_ALL
488	ldi	r1, #0				; error_code ; FIXME
489	mv	r0, sp				; pt_regs
490	bl	do_pie_handler
491	bra	error_code
492
493ENTRY(debug_trap)
494	/* void debug_trap(void) */
495	.global	withdraw_debug_trap
496	SWITCH_TO_KERNEL_STACK
497	SAVE_ALL
498	mv	r0, sp				; pt_regs
499	bl	withdraw_debug_trap
500	ldi	r1, #0				; error_code
501	mv	r0, sp				; pt_regs
502	bl	do_debug_trap
503	bra	error_code
504
505ENTRY(ill_trap)
506	/* void ill_trap(void) */
507	SWITCH_TO_KERNEL_STACK
508	SAVE_ALL
509	ldi	r1, #0				; error_code ; FIXME
510	mv	r0, sp				; pt_regs
511	bl	do_ill_trap
512	bra	error_code
513
514ENTRY(cache_flushing_handler)
515	/* void _flush_cache_all(void); */
516	.global	_flush_cache_all
517	SWITCH_TO_KERNEL_STACK
518	push	r0
519	push	r1
520	push	r2
521	push	r3
522	push	r4
523	push	r5
524	push	r6
525	push	r7
526	push	lr
527	bl	_flush_cache_all
528	pop	lr
529	pop	r7
530	pop	r6
531	pop	r5
532	pop	r4
533	pop	r3
534	pop	r2
535	pop	r1
536	pop	r0
537	rte
538
539	.section .rodata,"a"
540#include "syscall_table.S"
541
542syscall_table_size=(.-sys_call_table)
543