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