| 
									
										
										
										
											2011-01-15 18:15:45 +08:00
										 |  |  | /* | 
					
						
							|  |  |  |  * linux/arch/unicore32/kernel/entry.S | 
					
						
							|  |  |  |  * | 
					
						
							|  |  |  |  * Code specific to PKUnity SoC and UniCore ISA | 
					
						
							|  |  |  |  * | 
					
						
							|  |  |  |  * Copyright (C) 2001-2010 GUAN Xue-tao | 
					
						
							|  |  |  |  * | 
					
						
							|  |  |  |  * This program is free software; you can redistribute it and/or modify
 | 
					
						
							|  |  |  |  * it under the terms of the GNU General Public License version 2 as | 
					
						
							|  |  |  |  * published by the Free Software Foundation. | 
					
						
							|  |  |  |  * | 
					
						
							|  |  |  |  *  Low-level vector interface routines | 
					
						
							|  |  |  |  */ | 
					
						
							|  |  |  | #include <linux/init.h> | 
					
						
							|  |  |  | #include <linux/linkage.h> | 
					
						
							|  |  |  | #include <asm/assembler.h> | 
					
						
							|  |  |  | #include <asm/errno.h> | 
					
						
							|  |  |  | #include <asm/thread_info.h> | 
					
						
							|  |  |  | #include <asm/memory.h> | 
					
						
							|  |  |  | #include <asm/unistd.h> | 
					
						
							|  |  |  | #include <generated/asm-offsets.h> | 
					
						
							|  |  |  | #include "debug-macro.S" | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | @
 | 
					
						
							|  |  |  | @ Most of the stack format comes from struct pt_regs, but with
 | 
					
						
							|  |  |  | @ the addition of 8 bytes for storing syscall args 5 and 6.
 | 
					
						
							|  |  |  | @
 | 
					
						
							|  |  |  | #define S_OFF		8 | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | /* | 
					
						
							|  |  |  |  * The SWI code relies on the fact that R0 is at the bottom of the stack | 
					
						
							|  |  |  |  * (due to slow/fast restore user regs). | 
					
						
							|  |  |  |  */ | 
					
						
							|  |  |  | #if S_R0 != 0 | 
					
						
							|  |  |  | #error "Please fix" | 
					
						
							|  |  |  | #endif | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	.macro	zero_fp
 | 
					
						
							|  |  |  | #ifdef CONFIG_FRAME_POINTER | 
					
						
							|  |  |  | 	mov	fp, #0 | 
					
						
							|  |  |  | #endif | 
					
						
							|  |  |  | 	.endm | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	.macro	alignment_trap, rtemp | 
					
						
							|  |  |  | #ifdef CONFIG_ALIGNMENT_TRAP | 
					
						
							|  |  |  | 	ldw	\rtemp, .LCcralign | 
					
						
							|  |  |  | 	ldw	\rtemp, [\rtemp] | 
					
						
							|  |  |  | 	movc	p0.c1, \rtemp, #0 | 
					
						
							|  |  |  | #endif | 
					
						
							|  |  |  | 	.endm | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	.macro	load_user_sp_lr, rd, rtemp, offset = 0 | 
					
						
							|  |  |  | 	mov	\rtemp, asr | 
					
						
							|  |  |  | 	xor	\rtemp, \rtemp, #(PRIV_MODE ^ SUSR_MODE) | 
					
						
							|  |  |  | 	mov.a	asr, \rtemp			@ switch to the SUSR mode
 | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	ldw	sp, [\rd+], #\offset		@ load sp_user | 
					
						
							|  |  |  | 	ldw	lr, [\rd+], #\offset + 4	@ load lr_user
 | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	xor	\rtemp, \rtemp, #(PRIV_MODE ^ SUSR_MODE) | 
					
						
							|  |  |  | 	mov.a	asr, \rtemp			@ switch back to the PRIV mode
 | 
					
						
							|  |  |  | 	.endm | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	.macro	priv_exit, rpsr | 
					
						
							|  |  |  | 	mov.a	bsr, \rpsr | 
					
						
							|  |  |  | 	ldm.w	(r0 - r15), [sp]+ | 
					
						
							|  |  |  | 	ldm.b	(r16 - pc), [sp]+		@ load r0 - pc, asr
 | 
					
						
							|  |  |  | 	.endm | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	.macro	restore_user_regs, fast = 0, offset = 0 | 
					
						
							|  |  |  | 	ldw	r1, [sp+], #\offset + S_PSR	@ get calling asr | 
					
						
							|  |  |  | 	ldw	lr, [sp+], #\offset + S_PC	@ get pc | 
					
						
							|  |  |  | 	mov.a	bsr, r1				@ save in bsr_priv
 | 
					
						
							|  |  |  | 	.if	\fast | 
					
						
							|  |  |  | 	add	sp, sp, #\offset + S_R1		@ r0 is syscall return value
 | 
					
						
							|  |  |  | 	ldm.w	(r1 - r15), [sp]+		@ get calling r1 - r15
 | 
					
						
							|  |  |  | 	ldur	(r16 - lr), [sp]+		@ get calling r16 - lr
 | 
					
						
							|  |  |  | 	.else | 
					
						
							|  |  |  | 	ldm.w	(r0 - r15), [sp]+		@ get calling r0 - r15
 | 
					
						
							|  |  |  | 	ldur	(r16 - lr), [sp]+		@ get calling r16 - lr
 | 
					
						
							|  |  |  | 	.endif | 
					
						
							|  |  |  | 	nop | 
					
						
							|  |  |  | 	add	sp, sp, #S_FRAME_SIZE - S_R16 | 
					
						
							|  |  |  | 	mov.a	pc, lr				@ return
 | 
					
						
							|  |  |  | 						@ and move bsr_priv into asr
 | 
					
						
							|  |  |  | 	.endm | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	.macro	get_thread_info, rd | 
					
						
							|  |  |  | 	mov	\rd, sp >> #13 | 
					
						
							|  |  |  | 	mov	\rd, \rd << #13 | 
					
						
							|  |  |  | 	.endm | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	.macro	get_irqnr_and_base, irqnr, irqstat, base, tmp | 
					
						
							| 
									
										
										
										
											2011-03-04 18:07:48 +08:00
										 |  |  | 	ldw	\base, =(PKUNITY_INTC_BASE) | 
					
						
							| 
									
										
										
										
											2011-01-15 18:15:45 +08:00
										 |  |  | 	ldw	\irqstat, [\base+], #0xC	@ INTC_ICIP
 | 
					
						
							|  |  |  | 	ldw	\tmp,	  [\base+], #0x4	@ INTC_ICMR
 | 
					
						
							|  |  |  | 	and.a	\irqstat, \irqstat, \tmp | 
					
						
							|  |  |  | 	beq	1001f | 
					
						
							|  |  |  | 	cntlz	\irqnr, \irqstat | 
					
						
							|  |  |  | 	rsub	\irqnr, \irqnr, #31 | 
					
						
							|  |  |  | 1001:	/* EQ will be set if no irqs pending */ | 
					
						
							|  |  |  | 	.endm | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | #ifdef CONFIG_DEBUG_LL | 
					
						
							|  |  |  | 	.macro	printreg, reg, temp | 
					
						
							|  |  |  | 		adr	\temp, 901f | 
					
						
							|  |  |  | 		stm	(r0-r3), [\temp]+ | 
					
						
							|  |  |  | 		stw	lr, [\temp+], #0x10 | 
					
						
							|  |  |  | 		mov	r0, \reg | 
					
						
							|  |  |  | 		b.l	printhex8 | 
					
						
							|  |  |  | 		mov	r0, #':' | 
					
						
							|  |  |  | 		b.l	printch | 
					
						
							|  |  |  | 		mov	r0, pc | 
					
						
							|  |  |  | 		b.l	printhex8 | 
					
						
							|  |  |  | 		adr	r0, 902f | 
					
						
							|  |  |  | 		b.l	printascii | 
					
						
							|  |  |  | 		adr	\temp, 901f | 
					
						
							|  |  |  | 		ldm	(r0-r3), [\temp]+ | 
					
						
							|  |  |  | 		ldw	lr, [\temp+], #0x10 | 
					
						
							|  |  |  | 		b	903f | 
					
						
							|  |  |  | 901:	.word	0, 0, 0, 0, 0	@ r0-r3, lr
 | 
					
						
							|  |  |  | 902:	.asciz	": epip4d\n" | 
					
						
							|  |  |  | 	.align | 
					
						
							|  |  |  | 903: | 
					
						
							|  |  |  | 	.endm | 
					
						
							|  |  |  | #endif | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | /* | 
					
						
							|  |  |  |  * These are the registers used in the syscall handler, and allow us to | 
					
						
							|  |  |  |  * have in theory up to 7 arguments to a function - r0 to r6. | 
					
						
							|  |  |  |  * | 
					
						
							|  |  |  |  * Note that tbl == why is intentional. | 
					
						
							|  |  |  |  * | 
					
						
							|  |  |  |  * We must set at least "tsk" and "why" when calling ret_with_reschedule. | 
					
						
							|  |  |  |  */ | 
					
						
							|  |  |  | scno	.req	r21		@ syscall number
 | 
					
						
							|  |  |  | tbl	.req	r22		@ syscall table pointer
 | 
					
						
							|  |  |  | why	.req	r22		@ Linux syscall (!= 0)
 | 
					
						
							|  |  |  | tsk	.req	r23		@ current thread_info
 | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | /* | 
					
						
							|  |  |  |  * Interrupt handling.  Preserves r17, r18, r19 | 
					
						
							|  |  |  |  */ | 
					
						
							|  |  |  | 	.macro	intr_handler
 | 
					
						
							|  |  |  | 1:	get_irqnr_and_base r0, r6, r5, lr | 
					
						
							|  |  |  | 	beq	2f | 
					
						
							|  |  |  | 	mov	r1, sp | 
					
						
							|  |  |  | 	@
 | 
					
						
							|  |  |  | 	@ routine called with r0 = irq number, r1 = struct pt_regs *
 | 
					
						
							|  |  |  | 	@
 | 
					
						
							|  |  |  | 	adr	lr, 1b | 
					
						
							|  |  |  | 	b	asm_do_IRQ | 
					
						
							|  |  |  | 2: | 
					
						
							|  |  |  | 	.endm | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | /* | 
					
						
							|  |  |  |  * PRIV mode handlers | 
					
						
							|  |  |  |  */ | 
					
						
							|  |  |  | 	.macro	priv_entry
 | 
					
						
							|  |  |  | 	sub	sp, sp, #(S_FRAME_SIZE - 4) | 
					
						
							|  |  |  | 	stm	(r1 - r15), [sp]+ | 
					
						
							|  |  |  | 	add	r5, sp, #S_R15 | 
					
						
							|  |  |  | 	stm	(r16 - r28), [r5]+ | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	ldm	(r1 - r3), [r0]+ | 
					
						
							|  |  |  | 	add	r5, sp, #S_SP - 4	@ here for interlock avoidance
 | 
					
						
							|  |  |  | 	mov	r4, #-1			@  ""  ""      ""       ""
 | 
					
						
							|  |  |  | 	add	r0, sp, #(S_FRAME_SIZE - 4) | 
					
						
							|  |  |  | 	stw.w	r1, [sp+], #-4		@ save the "real" r0 copied
 | 
					
						
							|  |  |  | 					@ from the exception stack
 | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	mov	r1, lr | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	@
 | 
					
						
							|  |  |  | 	@ We are now ready to fill in the remaining blanks on the stack:
 | 
					
						
							|  |  |  | 	@
 | 
					
						
							|  |  |  | 	@  r0 - sp_priv
 | 
					
						
							|  |  |  | 	@  r1 - lr_priv
 | 
					
						
							|  |  |  | 	@  r2 - lr_<exception>, already fixed up for correct return/restart
 | 
					
						
							|  |  |  | 	@  r3 - bsr_<exception>
 | 
					
						
							|  |  |  | 	@  r4 - orig_r0 (see pt_regs definition in ptrace.h)
 | 
					
						
							|  |  |  | 	@
 | 
					
						
							|  |  |  | 	stm	(r0 - r4), [r5]+ | 
					
						
							|  |  |  | 	.endm | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | /* | 
					
						
							|  |  |  |  * User mode handlers | 
					
						
							|  |  |  |  * | 
					
						
							|  |  |  |  */ | 
					
						
							|  |  |  | 	.macro	user_entry
 | 
					
						
							|  |  |  | 	sub	sp, sp, #S_FRAME_SIZE | 
					
						
							|  |  |  | 	stm	(r1 - r15), [sp+] | 
					
						
							|  |  |  | 	add	r4, sp, #S_R16 | 
					
						
							|  |  |  | 	stm	(r16 - r28), [r4]+ | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	ldm	(r1 - r3), [r0]+ | 
					
						
							|  |  |  | 	add	r0, sp, #S_PC		@ here for interlock avoidance | 
					
						
							|  |  |  | 	mov	r4, #-1			@  ""  ""     ""        ""
 | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	stw	r1, [sp]		@ save the "real" r0 copied
 | 
					
						
							|  |  |  | 					@ from the exception stack
 | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	@
 | 
					
						
							|  |  |  | 	@ We are now ready to fill in the remaining blanks on the stack:
 | 
					
						
							|  |  |  | 	@
 | 
					
						
							|  |  |  | 	@  r2 - lr_<exception>, already fixed up for correct return/restart
 | 
					
						
							|  |  |  | 	@  r3 - bsr_<exception>
 | 
					
						
							|  |  |  | 	@  r4 - orig_r0 (see pt_regs definition in ptrace.h)
 | 
					
						
							|  |  |  | 	@
 | 
					
						
							|  |  |  | 	@ Also, separately save sp_user and lr_user
 | 
					
						
							|  |  |  | 	@
 | 
					
						
							|  |  |  | 	stm	(r2 - r4), [r0]+ | 
					
						
							|  |  |  | 	stur	(sp, lr), [r0-] | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	@
 | 
					
						
							|  |  |  | 	@ Enable the alignment trap while in kernel mode
 | 
					
						
							|  |  |  | 	@
 | 
					
						
							|  |  |  | 	alignment_trap r0 | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	@
 | 
					
						
							|  |  |  | 	@ Clear FP to mark the first stack frame
 | 
					
						
							|  |  |  | 	@
 | 
					
						
							|  |  |  | 	zero_fp | 
					
						
							|  |  |  | 	.endm | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	.text | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | @
 | 
					
						
							|  |  |  | @ __invalid - generic code for failed exception
 | 
					
						
							|  |  |  | @			(re-entrant version of handlers)
 | 
					
						
							|  |  |  | @
 | 
					
						
							|  |  |  | __invalid: | 
					
						
							|  |  |  | 	sub	sp, sp, #S_FRAME_SIZE | 
					
						
							|  |  |  | 	stm	(r1 - r15), [sp+] | 
					
						
							|  |  |  | 	add	r1, sp, #S_R16 | 
					
						
							|  |  |  | 	stm	(r16 - r28, sp, lr), [r1]+ | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	zero_fp | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	ldm	(r4 - r6), [r0]+ | 
					
						
							|  |  |  | 	add	r0, sp, #S_PC		@ here for interlock avoidance | 
					
						
							|  |  |  | 	mov	r7, #-1			@  ""   ""    ""        ""
 | 
					
						
							|  |  |  | 	stw	r4, [sp]		@ save preserved r0
 | 
					
						
							|  |  |  | 	stm	(r5 - r7), [r0]+	@ lr_<exception>,
 | 
					
						
							|  |  |  | 					@ asr_<exception>, "old_r0"
 | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	mov	r0, sp | 
					
						
							|  |  |  | 	mov	r1, asr | 
					
						
							|  |  |  | 	b	bad_mode | 
					
						
							|  |  |  | ENDPROC(__invalid) | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	.align	5
 | 
					
						
							|  |  |  | __dabt_priv: | 
					
						
							|  |  |  | 	priv_entry | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	@
 | 
					
						
							|  |  |  | 	@ get ready to re-enable interrupts if appropriate
 | 
					
						
							|  |  |  | 	@
 | 
					
						
							|  |  |  | 	mov	r17, asr | 
					
						
							|  |  |  | 	cand.a	r3, #PSR_I_BIT | 
					
						
							|  |  |  | 	bne	1f | 
					
						
							|  |  |  | 	andn	r17, r17, #PSR_I_BIT | 
					
						
							|  |  |  | 1: | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	@
 | 
					
						
							|  |  |  | 	@ Call the processor-specific abort handler:
 | 
					
						
							|  |  |  | 	@
 | 
					
						
							|  |  |  | 	@  r2 - aborted context pc
 | 
					
						
							|  |  |  | 	@  r3 - aborted context asr
 | 
					
						
							|  |  |  | 	@
 | 
					
						
							|  |  |  | 	@ The abort handler must return the aborted address in r0, and
 | 
					
						
							|  |  |  | 	@ the fault status register in r1.
 | 
					
						
							|  |  |  | 	@
 | 
					
						
							|  |  |  | 	movc	r1, p0.c3, #0		@ get FSR
 | 
					
						
							|  |  |  | 	movc	r0, p0.c4, #0		@ get FAR
 | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	@
 | 
					
						
							|  |  |  | 	@ set desired INTR state, then call main handler
 | 
					
						
							|  |  |  | 	@
 | 
					
						
							|  |  |  | 	mov.a	asr, r17 | 
					
						
							|  |  |  | 	mov	r2, sp | 
					
						
							|  |  |  | 	b.l	do_DataAbort | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	@
 | 
					
						
							|  |  |  | 	@ INTRs off again before pulling preserved data off the stack
 | 
					
						
							|  |  |  | 	@
 | 
					
						
							|  |  |  | 	disable_irq r0 | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	@
 | 
					
						
							|  |  |  | 	@ restore BSR and restart the instruction
 | 
					
						
							|  |  |  | 	@
 | 
					
						
							|  |  |  | 	ldw	r2, [sp+], #S_PSR | 
					
						
							|  |  |  | 	priv_exit r2				@ return from exception
 | 
					
						
							|  |  |  | ENDPROC(__dabt_priv) | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	.align	5
 | 
					
						
							|  |  |  | __intr_priv: | 
					
						
							|  |  |  | 	priv_entry | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	intr_handler | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	mov	r0, #0				@ epip4d
 | 
					
						
							|  |  |  | 	movc	p0.c5, r0, #14 | 
					
						
							|  |  |  | 	nop; nop; nop; nop; nop; nop; nop; nop
 | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	ldw	r4, [sp+], #S_PSR		@ irqs are already disabled | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	priv_exit r4				@ return from exception
 | 
					
						
							|  |  |  | ENDPROC(__intr_priv) | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	.ltorg | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	.align	5
 | 
					
						
							|  |  |  | __extn_priv: | 
					
						
							|  |  |  | 	priv_entry | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	mov	r0, sp				@ struct pt_regs *regs
 | 
					
						
							|  |  |  | 	mov	r1, asr | 
					
						
							|  |  |  | 	b	bad_mode			@ not supported
 | 
					
						
							|  |  |  | ENDPROC(__extn_priv) | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	.align	5
 | 
					
						
							|  |  |  | __pabt_priv: | 
					
						
							|  |  |  | 	priv_entry | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	@
 | 
					
						
							|  |  |  | 	@ re-enable interrupts if appropriate
 | 
					
						
							|  |  |  | 	@
 | 
					
						
							|  |  |  | 	mov	r17, asr | 
					
						
							|  |  |  | 	cand.a	r3, #PSR_I_BIT | 
					
						
							|  |  |  | 	bne	1f | 
					
						
							|  |  |  | 	andn	r17, r17, #PSR_I_BIT | 
					
						
							|  |  |  | 1: | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	@
 | 
					
						
							|  |  |  | 	@ set args, then call main handler
 | 
					
						
							|  |  |  | 	@
 | 
					
						
							|  |  |  | 	@  r0 - address of faulting instruction
 | 
					
						
							|  |  |  | 	@  r1 - pointer to registers on stack
 | 
					
						
							|  |  |  | 	@
 | 
					
						
							|  |  |  | 	mov	r0, r2			@ pass address of aborted instruction
 | 
					
						
							|  |  |  | 	mov	r1, #5 | 
					
						
							|  |  |  | 	mov.a	asr, r17 | 
					
						
							|  |  |  | 	mov	r2, sp			@ regs
 | 
					
						
							|  |  |  | 	b.l	do_PrefetchAbort	@ call abort handler
 | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	@
 | 
					
						
							|  |  |  | 	@ INTRs off again before pulling preserved data off the stack
 | 
					
						
							|  |  |  | 	@
 | 
					
						
							|  |  |  | 	disable_irq r0 | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	@
 | 
					
						
							|  |  |  | 	@ restore BSR and restart the instruction
 | 
					
						
							|  |  |  | 	@
 | 
					
						
							|  |  |  | 	ldw	r2, [sp+], #S_PSR | 
					
						
							|  |  |  | 	priv_exit r2			@ return from exception
 | 
					
						
							|  |  |  | ENDPROC(__pabt_priv) | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	.align	5
 | 
					
						
							|  |  |  | .LCcralign: | 
					
						
							|  |  |  | 	.word	cr_alignment
 | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	.align	5
 | 
					
						
							|  |  |  | __dabt_user: | 
					
						
							|  |  |  | 	user_entry | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | #ifdef CONFIG_UNICORE_FPU_F64 | 
					
						
							|  |  |  | 	cff	ip, s31 | 
					
						
							|  |  |  | 	cand.a	ip, #0x08000000		@ FPU execption traps?
 | 
					
						
							|  |  |  | 	beq	209f | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	ldw	ip, [sp+], #S_PC | 
					
						
							|  |  |  | 	add	ip, ip, #4 | 
					
						
							|  |  |  | 	stw	ip, [sp+], #S_PC | 
					
						
							|  |  |  | 	@
 | 
					
						
							|  |  |  | 	@ fall through to the emulation code, which returns using r19 if
 | 
					
						
							|  |  |  | 	@ it has emulated the instruction, or the more conventional lr
 | 
					
						
							|  |  |  | 	@ if we are to treat this as a real extended instruction
 | 
					
						
							|  |  |  | 	@
 | 
					
						
							|  |  |  | 	@  r0 - instruction
 | 
					
						
							|  |  |  | 	@
 | 
					
						
							|  |  |  | 1:	ldw.u	r0, [r2] | 
					
						
							|  |  |  | 	adr	r19, ret_from_exception | 
					
						
							|  |  |  | 	adr	lr, 209f | 
					
						
							|  |  |  | 	@
 | 
					
						
							|  |  |  | 	@ fallthrough to call do_uc_f64
 | 
					
						
							|  |  |  | 	@
 | 
					
						
							|  |  |  | /* | 
					
						
							|  |  |  |  * Check whether the instruction is a co-processor instruction. | 
					
						
							|  |  |  |  * If yes, we need to call the relevant co-processor handler. | 
					
						
							|  |  |  |  * | 
					
						
							|  |  |  |  * Note that we don't do a full check here for the co-processor | 
					
						
							|  |  |  |  * instructions; all instructions with bit 27 set are well
 | 
					
						
							|  |  |  |  * defined.  The only instructions that should fault are the | 
					
						
							|  |  |  |  * co-processor instructions. | 
					
						
							|  |  |  |  * | 
					
						
							|  |  |  |  * Emulators may wish to make use of the following registers: | 
					
						
							|  |  |  |  *  r0  = instruction opcode. | 
					
						
							|  |  |  |  *  r2  = PC | 
					
						
							|  |  |  |  *  r19 = normal "successful" return address | 
					
						
							|  |  |  |  *  r20 = this threads thread_info structure. | 
					
						
							|  |  |  |  *  lr  = unrecognised instruction return address | 
					
						
							|  |  |  |  */ | 
					
						
							|  |  |  | 	get_thread_info r20			@ get current thread
 | 
					
						
							|  |  |  | 	and	r8, r0, #0x00003c00		@ mask out CP number
 | 
					
						
							|  |  |  | 	mov	r7, #1 | 
					
						
							|  |  |  | 	stb	r7, [r20+], #TI_USED_CP + 2	@ set appropriate used_cp[]
 | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	@ F64 hardware support entry point.
 | 
					
						
							|  |  |  | 	@  r0  = faulted instruction
 | 
					
						
							|  |  |  | 	@  r19 = return address
 | 
					
						
							|  |  |  | 	@  r20 = fp_state
 | 
					
						
							|  |  |  | 	enable_irq r4 | 
					
						
							|  |  |  | 	add	r20, r20, #TI_FPSTATE	@ r20 = workspace | 
					
						
							|  |  |  | 	cff	r1, s31			@ get fpu FPSCR
 | 
					
						
							|  |  |  | 	andn    r2, r1, #0x08000000 | 
					
						
							|  |  |  | 	ctf     r2, s31			@ clear 27 bit
 | 
					
						
							|  |  |  | 	mov	r2, sp			@ nothing stacked - regdump is at TOS
 | 
					
						
							|  |  |  | 	mov	lr, r19			@ setup for a return to the user code
 | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	@ Now call the C code to package up the bounce to the support code
 | 
					
						
							|  |  |  | 	@   r0 holds the trigger instruction
 | 
					
						
							|  |  |  | 	@   r1 holds the FPSCR value
 | 
					
						
							|  |  |  | 	@   r2 pointer to register dump
 | 
					
						
							|  |  |  | 	b	ucf64_exchandler | 
					
						
							|  |  |  | 209: | 
					
						
							|  |  |  | #endif | 
					
						
							|  |  |  | 	@
 | 
					
						
							|  |  |  | 	@ Call the processor-specific abort handler:
 | 
					
						
							|  |  |  | 	@
 | 
					
						
							|  |  |  | 	@  r2 - aborted context pc
 | 
					
						
							|  |  |  | 	@  r3 - aborted context asr
 | 
					
						
							|  |  |  | 	@
 | 
					
						
							|  |  |  | 	@ The abort handler must return the aborted address in r0, and
 | 
					
						
							|  |  |  | 	@ the fault status register in r1.
 | 
					
						
							|  |  |  | 	@
 | 
					
						
							|  |  |  | 	movc	r1, p0.c3, #0		@ get FSR
 | 
					
						
							|  |  |  | 	movc	r0, p0.c4, #0		@ get FAR
 | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	@
 | 
					
						
							|  |  |  | 	@ INTRs on, then call the main handler
 | 
					
						
							|  |  |  | 	@
 | 
					
						
							|  |  |  | 	enable_irq r2 | 
					
						
							|  |  |  | 	mov	r2, sp | 
					
						
							|  |  |  | 	adr	lr, ret_from_exception | 
					
						
							|  |  |  | 	b	do_DataAbort | 
					
						
							|  |  |  | ENDPROC(__dabt_user) | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	.align	5
 | 
					
						
							|  |  |  | __intr_user: | 
					
						
							|  |  |  | 	user_entry | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	get_thread_info tsk | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	intr_handler | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	mov	why, #0 | 
					
						
							|  |  |  | 	b	ret_to_user | 
					
						
							|  |  |  | ENDPROC(__intr_user) | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	.ltorg | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	.align	5
 | 
					
						
							|  |  |  | __extn_user: | 
					
						
							|  |  |  | 	user_entry | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	mov	r0, sp | 
					
						
							|  |  |  | 	mov	r1, asr | 
					
						
							|  |  |  | 	b	bad_mode | 
					
						
							|  |  |  | ENDPROC(__extn_user) | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	.align	5
 | 
					
						
							|  |  |  | __pabt_user: | 
					
						
							|  |  |  | 	user_entry | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	mov	r0, r2			@ pass address of aborted instruction.
 | 
					
						
							|  |  |  | 	mov	r1, #5 | 
					
						
							|  |  |  | 	enable_irq r1			@ Enable interrupts
 | 
					
						
							|  |  |  | 	mov	r2, sp			@ regs
 | 
					
						
							|  |  |  | 	b.l	do_PrefetchAbort	@ call abort handler
 | 
					
						
							|  |  |  | 	/* fall through */ | 
					
						
							|  |  |  | /* | 
					
						
							|  |  |  |  * This is the return code to user mode for abort handlers | 
					
						
							|  |  |  |  */ | 
					
						
							|  |  |  | ENTRY(ret_from_exception) | 
					
						
							|  |  |  | 	get_thread_info tsk | 
					
						
							|  |  |  | 	mov	why, #0 | 
					
						
							|  |  |  | 	b	ret_to_user | 
					
						
							|  |  |  | ENDPROC(__pabt_user) | 
					
						
							|  |  |  | ENDPROC(ret_from_exception) | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | /* | 
					
						
							|  |  |  |  * Register switch for UniCore V2 processors | 
					
						
							|  |  |  |  * r0 = previous task_struct, r1 = previous thread_info, r2 = next thread_info | 
					
						
							|  |  |  |  * previous and next are guaranteed not to be the same. | 
					
						
							|  |  |  |  */ | 
					
						
							|  |  |  | ENTRY(__switch_to) | 
					
						
							|  |  |  | 	add	ip, r1, #TI_CPU_SAVE | 
					
						
							|  |  |  | 	stm.w	(r4 - r15), [ip]+ | 
					
						
							|  |  |  | 	stm.w	(r16 - r27, sp, lr), [ip]+ | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | #ifdef	CONFIG_UNICORE_FPU_F64 | 
					
						
							|  |  |  | 	add	ip, r1, #TI_FPSTATE | 
					
						
							|  |  |  | 	sfm.w	(f0  - f7 ), [ip]+ | 
					
						
							|  |  |  | 	sfm.w	(f8  - f15), [ip]+ | 
					
						
							|  |  |  | 	sfm.w	(f16 - f23), [ip]+ | 
					
						
							|  |  |  | 	sfm.w	(f24 - f31), [ip]+ | 
					
						
							|  |  |  | 	cff	r4, s31 | 
					
						
							|  |  |  | 	stw	r4, [ip] | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	add	ip, r2, #TI_FPSTATE | 
					
						
							|  |  |  | 	lfm.w	(f0  - f7 ), [ip]+ | 
					
						
							|  |  |  | 	lfm.w	(f8  - f15), [ip]+ | 
					
						
							|  |  |  | 	lfm.w	(f16 - f23), [ip]+ | 
					
						
							|  |  |  | 	lfm.w	(f24 - f31), [ip]+ | 
					
						
							|  |  |  | 	ldw	r4, [ip] | 
					
						
							|  |  |  | 	ctf	r4, s31 | 
					
						
							|  |  |  | #endif | 
					
						
							|  |  |  | 	add	ip, r2, #TI_CPU_SAVE | 
					
						
							|  |  |  | 	ldm.w	(r4 - r15), [ip]+ | 
					
						
							|  |  |  | 	ldm	(r16 - r27, sp, pc), [ip]+	@ Load all regs saved previously
 | 
					
						
							|  |  |  | ENDPROC(__switch_to) | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	.align	5
 | 
					
						
							|  |  |  | /* | 
					
						
							|  |  |  |  * This is the fast syscall return path.  We do as little as | 
					
						
							|  |  |  |  * possible here, and this includes saving r0 back into the PRIV | 
					
						
							|  |  |  |  * stack. | 
					
						
							|  |  |  |  */ | 
					
						
							|  |  |  | ret_fast_syscall: | 
					
						
							|  |  |  | 	disable_irq r1				@ disable interrupts
 | 
					
						
							|  |  |  | 	ldw	r1, [tsk+], #TI_FLAGS | 
					
						
							|  |  |  | 	cand.a	r1, #_TIF_WORK_MASK | 
					
						
							|  |  |  | 	bne	fast_work_pending | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	@ fast_restore_user_regs
 | 
					
						
							|  |  |  | 	restore_user_regs fast = 1, offset = S_OFF | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | /* | 
					
						
							|  |  |  |  * Ok, we need to do extra processing, enter the slow path. | 
					
						
							|  |  |  |  */ | 
					
						
							|  |  |  | fast_work_pending: | 
					
						
							|  |  |  | 	stw.w	r0, [sp+], #S_R0+S_OFF		@ returned r0
 | 
					
						
							|  |  |  | work_pending: | 
					
						
							|  |  |  | 	cand.a	r1, #_TIF_NEED_RESCHED | 
					
						
							|  |  |  | 	bne	work_resched | 
					
						
							|  |  |  | 	mov	r0, sp				@ 'regs'
 | 
					
						
							|  |  |  | 	mov	r2, why				@ 'syscall'
 | 
					
						
							|  |  |  | 	cand.a	r1, #_TIF_SIGPENDING		@ delivering a signal? | 
					
						
							|  |  |  | 	cmovne	why, #0				@ prevent further restarts
 | 
					
						
							|  |  |  | 	b.l	do_notify_resume | 
					
						
							|  |  |  | 	b	ret_slow_syscall		@ Check work again
 | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | work_resched: | 
					
						
							|  |  |  | 	b.l	schedule | 
					
						
							|  |  |  | /* | 
					
						
							|  |  |  |  * "slow" syscall return path.  "why" tells us if this was a real syscall. | 
					
						
							|  |  |  |  */ | 
					
						
							|  |  |  | ENTRY(ret_to_user) | 
					
						
							|  |  |  | ret_slow_syscall: | 
					
						
							|  |  |  | 	disable_irq r1				@ disable interrupts
 | 
					
						
							|  |  |  | 	get_thread_info tsk			@ epip4d, one path error?!
 | 
					
						
							|  |  |  | 	ldw	r1, [tsk+], #TI_FLAGS | 
					
						
							|  |  |  | 	cand.a	r1, #_TIF_WORK_MASK | 
					
						
							|  |  |  | 	bne	work_pending | 
					
						
							|  |  |  | no_work_pending: | 
					
						
							|  |  |  | 	@ slow_restore_user_regs
 | 
					
						
							|  |  |  | 	restore_user_regs fast = 0, offset = 0 | 
					
						
							|  |  |  | ENDPROC(ret_to_user) | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | /* | 
					
						
							|  |  |  |  * This is how we return from a fork. | 
					
						
							|  |  |  |  */ | 
					
						
							|  |  |  | ENTRY(ret_from_fork) | 
					
						
							|  |  |  | 	b.l	schedule_tail | 
					
						
							|  |  |  | 	b	ret_slow_syscall | 
					
						
							|  |  |  | ENDPROC(ret_from_fork) | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2012-10-13 17:35:21 -04:00
										 |  |  | ENTRY(ret_from_kernel_thread) | 
					
						
							|  |  |  | 	b.l	schedule_tail | 
					
						
							|  |  |  | 	mov	r0, r5 | 
					
						
							|  |  |  | 	adr	lr, ret_slow_syscall | 
					
						
							|  |  |  | 	mov	pc, r4 | 
					
						
							|  |  |  | ENDPROC(ret_from_kernel_thread) | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2011-01-15 18:15:45 +08:00
										 |  |  | /*============================================================================= | 
					
						
							|  |  |  |  * SWI handler | 
					
						
							|  |  |  |  *----------------------------------------------------------------------------- | 
					
						
							|  |  |  |  */ | 
					
						
							|  |  |  | 	.align	5
 | 
					
						
							|  |  |  | ENTRY(vector_swi) | 
					
						
							|  |  |  | 	sub	sp, sp, #S_FRAME_SIZE | 
					
						
							|  |  |  | 	stm	(r0 - r15), [sp]+		@ Calling r0 - r15
 | 
					
						
							|  |  |  | 	add	r8, sp, #S_R16 | 
					
						
							|  |  |  | 	stm	(r16 - r28), [r8]+		@ Calling r16 - r28
 | 
					
						
							|  |  |  | 	add	r8, sp, #S_PC | 
					
						
							|  |  |  | 	stur	(sp, lr), [r8-]			@ Calling sp, lr
 | 
					
						
							|  |  |  | 	mov	r8, bsr				@ called from non-REAL mode
 | 
					
						
							|  |  |  | 	stw	lr, [sp+], #S_PC		@ Save calling PC | 
					
						
							|  |  |  | 	stw	r8, [sp+], #S_PSR		@ Save ASR | 
					
						
							|  |  |  | 	stw	r0, [sp+], #S_OLD_R0		@ Save OLD_R0
 | 
					
						
							|  |  |  | 	zero_fp | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	/* | 
					
						
							|  |  |  | 	 * Get the system call number. | 
					
						
							|  |  |  | 	 */ | 
					
						
							|  |  |  | 	sub	ip, lr, #4 | 
					
						
							|  |  |  | 	ldw.u	scno, [ip]			@ get SWI instruction
 | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | #ifdef CONFIG_ALIGNMENT_TRAP | 
					
						
							|  |  |  | 	ldw	ip, __cr_alignment | 
					
						
							|  |  |  | 	ldw	ip, [ip] | 
					
						
							|  |  |  | 	movc	p0.c1, ip, #0                   @ update control register
 | 
					
						
							|  |  |  | #endif | 
					
						
							|  |  |  | 	enable_irq ip | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	get_thread_info tsk | 
					
						
							|  |  |  | 	ldw	tbl, =sys_call_table		@ load syscall table pointer
 | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	andn	scno, scno, #0xff000000		@ mask off SWI op-code
 | 
					
						
							|  |  |  | 	andn	scno, scno, #0x00ff0000		@ mask off SWI op-code
 | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	stm.w	(r4, r5), [sp-]			@ push fifth and sixth args
 | 
					
						
							|  |  |  | 	ldw	ip, [tsk+], #TI_FLAGS		@ check for syscall tracing | 
					
						
							|  |  |  | 	cand.a	ip, #_TIF_SYSCALL_TRACE		@ are we tracing syscalls? | 
					
						
							|  |  |  | 	bne	__sys_trace | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	csub.a	scno, #__NR_syscalls		@ check upper syscall limit | 
					
						
							|  |  |  | 	adr	lr, ret_fast_syscall		@ return address
 | 
					
						
							|  |  |  | 	bea	1f | 
					
						
							|  |  |  | 	ldw	pc, [tbl+], scno << #2		@ call sys_* routine
 | 
					
						
							|  |  |  | 1: | 
					
						
							|  |  |  | 	add	r1, sp, #S_OFF | 
					
						
							|  |  |  | 2:	mov	why, #0				@ no longer a real syscall
 | 
					
						
							|  |  |  | 	b	sys_ni_syscall			@ not private func
 | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	/* | 
					
						
							|  |  |  | 	 * This is the really slow path.  We're going to be doing | 
					
						
							|  |  |  | 	 * context switches, and waiting for our parent to respond. | 
					
						
							|  |  |  | 	 */ | 
					
						
							|  |  |  | __sys_trace: | 
					
						
							|  |  |  | 	mov	r2, scno | 
					
						
							|  |  |  | 	add	r1, sp, #S_OFF | 
					
						
							|  |  |  | 	mov	r0, #0				@ trace entry [IP = 0]
 | 
					
						
							|  |  |  | 	b.l	syscall_trace | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	adr	lr, __sys_trace_return		@ return address
 | 
					
						
							|  |  |  | 	mov	scno, r0			@ syscall number (possibly new)
 | 
					
						
							|  |  |  | 	add	r1, sp, #S_R0 + S_OFF		@ pointer to regs
 | 
					
						
							|  |  |  | 	csub.a	scno, #__NR_syscalls		@ check upper syscall limit | 
					
						
							|  |  |  | 	bea	2b | 
					
						
							|  |  |  | 	ldm	(r0 - r3), [r1]+		@ have to reload r0 - r3
 | 
					
						
							|  |  |  | 	ldw	pc, [tbl+], scno << #2		@ call sys_* routine
 | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | __sys_trace_return: | 
					
						
							|  |  |  | 	stw.w	r0, [sp+], #S_R0 + S_OFF	@ save returned r0
 | 
					
						
							|  |  |  | 	mov	r2, scno | 
					
						
							|  |  |  | 	mov	r1, sp | 
					
						
							|  |  |  | 	mov	r0, #1				@ trace exit [IP = 1]
 | 
					
						
							|  |  |  | 	b.l	syscall_trace | 
					
						
							|  |  |  | 	b	ret_slow_syscall | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	.align	5
 | 
					
						
							|  |  |  | #ifdef CONFIG_ALIGNMENT_TRAP | 
					
						
							|  |  |  | 	.type	__cr_alignment, #object | 
					
						
							|  |  |  | __cr_alignment: | 
					
						
							|  |  |  | 	.word	cr_alignment
 | 
					
						
							|  |  |  | #endif | 
					
						
							|  |  |  | 	.ltorg | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | ENTRY(sys_rt_sigreturn) | 
					
						
							|  |  |  | 		add	r0, sp, #S_OFF | 
					
						
							|  |  |  | 		mov	why, #0		@ prevent syscall restart handling
 | 
					
						
							|  |  |  | 		b	__sys_rt_sigreturn | 
					
						
							|  |  |  | ENDPROC(sys_rt_sigreturn) | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	__INIT | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | /* | 
					
						
							|  |  |  |  * Vector stubs. | 
					
						
							|  |  |  |  * | 
					
						
							|  |  |  |  * This code is copied to 0xffff0200 so we can use branches in the | 
					
						
							|  |  |  |  * vectors, rather than ldr's.  Note that this code must not | 
					
						
							|  |  |  |  * exceed 0x300 bytes. | 
					
						
							|  |  |  |  * | 
					
						
							|  |  |  |  * Common stub entry macro: | 
					
						
							|  |  |  |  *   Enter in INTR mode, bsr = PRIV/USER ASR, lr = PRIV/USER PC | 
					
						
							|  |  |  |  * | 
					
						
							|  |  |  |  * SP points to a minimal amount of processor-private memory, the address | 
					
						
							|  |  |  |  * of which is copied into r0 for the mode specific abort handler. | 
					
						
							|  |  |  |  */ | 
					
						
							|  |  |  | 	.macro	vector_stub, name, mode | 
					
						
							|  |  |  | 	.align	5
 | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | vector_\name: | 
					
						
							|  |  |  | 	@
 | 
					
						
							|  |  |  | 	@ Save r0, lr_<exception> (parent PC) and bsr_<exception>
 | 
					
						
							|  |  |  | 	@ (parent ASR)
 | 
					
						
							|  |  |  | 	@
 | 
					
						
							|  |  |  | 	stw	r0, [sp] | 
					
						
							|  |  |  | 	stw	lr, [sp+], #4		@ save r0, lr
 | 
					
						
							|  |  |  | 	mov	lr, bsr | 
					
						
							|  |  |  | 	stw	lr, [sp+], #8		@ save bsr
 | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	@
 | 
					
						
							|  |  |  | 	@ Prepare for PRIV mode.  INTRs remain disabled.
 | 
					
						
							|  |  |  | 	@
 | 
					
						
							|  |  |  | 	mov	r0, asr | 
					
						
							|  |  |  | 	xor	r0, r0, #(\mode ^ PRIV_MODE) | 
					
						
							|  |  |  | 	mov.a	bsr, r0 | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	@
 | 
					
						
							|  |  |  | 	@ the branch table must immediately follow this code
 | 
					
						
							|  |  |  | 	@
 | 
					
						
							|  |  |  | 	and	lr, lr, #0x03 | 
					
						
							|  |  |  | 	add	lr, lr, #1 | 
					
						
							|  |  |  | 	mov	r0, sp | 
					
						
							|  |  |  | 	ldw	lr, [pc+], lr << #2 | 
					
						
							|  |  |  | 	mov.a	pc, lr			@ branch to handler in PRIV mode
 | 
					
						
							|  |  |  | ENDPROC(vector_\name) | 
					
						
							|  |  |  | 	.align	2
 | 
					
						
							|  |  |  | 	@ handler addresses follow this label
 | 
					
						
							|  |  |  | 	.endm | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	.globl	__stubs_start
 | 
					
						
							|  |  |  | __stubs_start: | 
					
						
							|  |  |  | /* | 
					
						
							|  |  |  |  * Interrupt dispatcher | 
					
						
							|  |  |  |  */ | 
					
						
							|  |  |  | 	vector_stub	intr, INTR_MODE | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	.long	__intr_user			@  0  (USER)
 | 
					
						
							|  |  |  | 	.long	__invalid			@  1
 | 
					
						
							|  |  |  | 	.long	__invalid			@  2
 | 
					
						
							|  |  |  | 	.long	__intr_priv			@  3  (PRIV)
 | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | /* | 
					
						
							|  |  |  |  * Data abort dispatcher | 
					
						
							|  |  |  |  * Enter in ABT mode, bsr = USER ASR, lr = USER PC | 
					
						
							|  |  |  |  */ | 
					
						
							|  |  |  | 	vector_stub	dabt, ABRT_MODE | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	.long	__dabt_user			@  0  (USER)
 | 
					
						
							|  |  |  | 	.long	__invalid			@  1
 | 
					
						
							|  |  |  | 	.long	__invalid			@  2  (INTR)
 | 
					
						
							|  |  |  | 	.long	__dabt_priv			@  3  (PRIV)
 | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | /* | 
					
						
							|  |  |  |  * Prefetch abort dispatcher | 
					
						
							|  |  |  |  * Enter in ABT mode, bsr = USER ASR, lr = USER PC | 
					
						
							|  |  |  |  */ | 
					
						
							|  |  |  | 	vector_stub	pabt, ABRT_MODE | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	.long	__pabt_user			@  0 (USER)
 | 
					
						
							|  |  |  | 	.long	__invalid			@  1
 | 
					
						
							|  |  |  | 	.long	__invalid			@  2 (INTR)
 | 
					
						
							|  |  |  | 	.long	__pabt_priv			@  3 (PRIV)
 | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | /* | 
					
						
							|  |  |  |  * Undef instr entry dispatcher | 
					
						
							|  |  |  |  * Enter in EXTN mode, bsr = PRIV/USER ASR, lr = PRIV/USER PC | 
					
						
							|  |  |  |  */ | 
					
						
							|  |  |  | 	vector_stub	extn, EXTN_MODE | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	.long	__extn_user			@  0 (USER)
 | 
					
						
							|  |  |  | 	.long	__invalid			@  1
 | 
					
						
							|  |  |  | 	.long	__invalid			@  2 (INTR)
 | 
					
						
							|  |  |  | 	.long	__extn_priv			@  3 (PRIV)
 | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | /* | 
					
						
							|  |  |  |  * We group all the following data together to optimise | 
					
						
							|  |  |  |  * for CPUs with separate I & D caches. | 
					
						
							|  |  |  |  */ | 
					
						
							|  |  |  | 	.align	5
 | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | .LCvswi: | 
					
						
							|  |  |  | 	.word	vector_swi
 | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	.globl	__stubs_end
 | 
					
						
							|  |  |  | __stubs_end: | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	.equ	stubs_offset, __vectors_start + 0x200 - __stubs_start | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	.globl	__vectors_start
 | 
					
						
							|  |  |  | __vectors_start: | 
					
						
							|  |  |  | 	jepriv	SYS_ERROR0 | 
					
						
							|  |  |  | 	b	vector_extn + stubs_offset | 
					
						
							|  |  |  | 	ldw	pc, .LCvswi + stubs_offset | 
					
						
							|  |  |  | 	b	vector_pabt + stubs_offset | 
					
						
							|  |  |  | 	b	vector_dabt + stubs_offset | 
					
						
							|  |  |  | 	jepriv	SYS_ERROR0 | 
					
						
							|  |  |  | 	b	vector_intr + stubs_offset | 
					
						
							|  |  |  | 	jepriv	SYS_ERROR0 | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	.globl	__vectors_end
 | 
					
						
							|  |  |  | __vectors_end: | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	.data | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	.globl	cr_alignment
 | 
					
						
							|  |  |  | 	.globl	cr_no_alignment
 | 
					
						
							|  |  |  | cr_alignment: | 
					
						
							|  |  |  | 	.space	4
 | 
					
						
							|  |  |  | cr_no_alignment: | 
					
						
							|  |  |  | 	.space	4
 |