805 lines · 17.2 KB · Assembly
RawDownload
/* * 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	ldw	\base, =(PKUNITY_INTC_BASE)	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, #311001:	/* 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	903f901:	.word	0, 0, 0, 0, 0	@ r0-r3, lr902:	.asciz	": epip4d\n"	.align903:	.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 numbertbl	.req	r22		@ syscall table pointerwhy	.req	r22		@ Linux syscall (!= 0)tsk	.req	r23		@ current thread_info /* * Interrupt handling.  Preserves r17, r18, r19 */	.macro	intr_handler1:	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_IRQ2:	.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_modeENDPROC(__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_BIT1: 	@	@ 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 exceptionENDPROC(__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 exceptionENDPROC(__intr_priv) 	.ltorg 	.align	5__extn_priv:	priv_entry 	mov	r0, sp				@ struct pt_regs *regs	mov	r1, asr	b	bad_mode			@ not supportedENDPROC(__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_BIT1: 	@	@ 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 exceptionENDPROC(__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_exchandler209:#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_DataAbortENDPROC(__dabt_user) 	.align	5__intr_user:	user_entry 	get_thread_info tsk 	intr_handler 	mov	why, #0	b	ret_to_userENDPROC(__intr_user) 	.ltorg 	.align	5__extn_user:	user_entry 	mov	r0, sp	mov	r1, asr	b	bad_modeENDPROC(__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_userENDPROC(__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]+

Lines 1–500 of 805.