1134 lines · 27.8 KB · Assembly
RawDownload
/* SPDX-License-Identifier: GPL-2.0-only *//* *  linux/arch/arm/kernel/entry-armv.S * *  Copyright (C) 1996,1997,1998 Russell King. *  ARM700 fix by Matthew Godbolt (linux-user@willothewisp.demon.co.uk) *  nommu support by Hyok S. Choi (hyok.choi@samsung.com) * *  Low-level vector interface routines * *  Note:  there is a StrongARM bug in the STMIA rn, {regs}^ instruction *  that causes it to save wrong values...  Be aware! */ #include <linux/init.h> #include <asm/assembler.h>#include <asm/page.h>#include <asm/glue-df.h>#include <asm/glue-pf.h>#include <asm/vfpmacros.h>#include <asm/thread_notify.h>#include <asm/unwind.h>#include <asm/unistd.h>#include <asm/tls.h>#include <asm/system_info.h>#include <asm/uaccess-asm.h>#include <asm/kasan_def.h> #include "entry-header.S"#include <asm/probes.h> #ifdef CONFIG_HAVE_LD_DEAD_CODE_DATA_ELIMINATION#define RELOC_TEXT_NONE .reloc  .text, R_ARM_NONE, .#else#define RELOC_TEXT_NONE#endif /* * Interrupt handling. */	.macro	irq_handler, from_user:req	mov	r1, sp	ldr_this_cpu r2, irq_stack_ptr, r2, r3	.if	\from_user == 0	@	@ If we took the interrupt while running in the kernel, we may already	@ be using the IRQ stack, so revert to the original value in that case.	@	subs	r3, r2, r1		@ SP above bottom of IRQ stack?	rsbscs	r3, r3, #THREAD_SIZE	@ ... and below the top?#ifdef CONFIG_VMAP_STACK	ldr_va	r3, high_memory, cc	@ End of the linear region	cmpcc	r3, r1			@ Stack pointer was below it?#endif	bcc	0f			@ If not, switch to the IRQ stack	mov	r0, r1	bl	generic_handle_arch_irq	b	1f0:	.endif 	mov_l	r0, generic_handle_arch_irq	bl	call_with_stack1:	.endm 	.macro	pabt_helper	@ PABORT handler takes pt_regs in r2, fault address in r4 and psr in r5#ifdef MULTI_PABORT	ldr_va	ip, processor, offset=PROCESSOR_PABT_FUNC	bl_r	ip#else	bl	CPU_PABORT_HANDLER#endif	.endm 	.macro	dabt_helper 	@	@ Call the processor-specific abort handler:	@	@  r2 - pt_regs	@  r4 - aborted context pc	@  r5 - aborted context psr	@	@ The abort handler must return the aborted address in r0, and	@ the fault status register in r1.  r9 must be preserved.	@#ifdef MULTI_DABORT	ldr_va	ip, processor, offset=PROCESSOR_DABT_FUNC	bl_r	ip#else	bl	CPU_DABORT_HANDLER#endif	.endm 	.section	.entry.text,"ax",%progbits /* * Invalid mode handlers */	.macro	inv_entry, reason	sub	sp, sp, #PT_REGS_SIZE ARM(	stmib	sp, {r1 - lr}		) THUMB(	stmia	sp, {r0 - r12}		) THUMB(	str	sp, [sp, #S_SP]		) THUMB(	str	lr, [sp, #S_LR]		)	mov	r1, #\reason	.endm __pabt_invalid:	inv_entry BAD_PREFETCH	b	common_invalidENDPROC(__pabt_invalid) __dabt_invalid:	inv_entry BAD_DATA	b	common_invalidENDPROC(__dabt_invalid) __irq_invalid:	inv_entry BAD_IRQ	b	common_invalidENDPROC(__irq_invalid) __und_invalid:	inv_entry BAD_UNDEFINSTR 	@	@ XXX fall through to common_invalid	@ @@ common_invalid - generic code for failed exception (re-entrant version of handlers)@common_invalid:	zero_fp 	ldmia	r0, {r4 - r6}	add	r0, sp, #S_PC		@ here for interlock avoidance	mov	r7, #-1			@  ""   ""    ""        ""	str	r4, [sp]		@ save preserved r0	stmia	r0, {r5 - r7}		@ lr_<exception>,					@ cpsr_<exception>, "old_r0" 	mov	r0, sp	b	bad_modeENDPROC(__und_invalid) /* * SVC mode handlers */ #if defined(CONFIG_AEABI) && (__LINUX_ARM_ARCH__ >= 5)#define SPFIX(code...) code#else#define SPFIX(code...)#endif 	.macro	svc_entry, stack_hole=0, trace=1, uaccess=1, overflow_check=1 UNWIND(.fnstart		)	sub	sp, sp, #(SVC_REGS_SIZE + \stack_hole) THUMB(	add	sp, r1		)	@ get SP in a GPR without THUMB(	sub	r1, sp, r1	)	@ using a temp register 	.if	\overflow_check UNWIND(.save	{r0 - pc}	)	do_overflow_check (SVC_REGS_SIZE + \stack_hole)	.endif #ifdef CONFIG_THUMB2_KERNEL	tst	r1, #4			@ test stack pointer alignment	sub	r1, sp, r1		@ restore original R1	sub	sp, r1			@ restore original SP#else SPFIX(	tst	sp, #4		)#endif SPFIX(	subne	sp, sp, #4	)  ARM(	stmib	sp, {r1 - r12}	) THUMB(	stmia	sp, {r0 - r12}	)	@ No STMIB in Thumb-2 	ldmia	r0, {r3 - r5}	add	r7, sp, #S_SP		@ here for interlock avoidance	mov	r6, #-1			@  ""  ""      ""       ""	add	r2, sp, #(SVC_REGS_SIZE + \stack_hole) SPFIX(	addne	r2, r2, #4	)	str	r3, [sp]		@ save the "real" r0 copied					@ from the exception stack 	mov	r3, lr 	@	@ We are now ready to fill in the remaining blanks on the stack:	@	@  r2 - sp_svc	@  r3 - lr_svc	@  r4 - lr_<exception>, already fixed up for correct return/restart	@  r5 - spsr_<exception>	@  r6 - orig_r0 (see pt_regs definition in ptrace.h)	@	stmia	r7, {r2 - r6} 	get_thread_info tsk	uaccess_entry tsk, r0, r1, r2, \uaccess 	.if \trace#ifdef CONFIG_TRACE_IRQFLAGS	bl	trace_hardirqs_off#endif	.endif	.endm 	.align	5__dabt_svc:	svc_entry uaccess=0	mov	r2, sp	dabt_helper THUMB(	ldr	r5, [sp, #S_PSR]	)	@ potentially updated CPSR	svc_exit r5				@ return from exception UNWIND(.fnend		)ENDPROC(__dabt_svc) 	.align	5__irq_svc:	svc_entry	irq_handler from_user=0 #ifdef CONFIG_PREEMPTION	ldr	r8, [tsk, #TI_PREEMPT]		@ get preempt count	ldr	r0, [tsk, #TI_FLAGS]		@ get flags	teq	r8, #0				@ if preempt count != 0	movne	r0, #0				@ force flags to 0	tst	r0, #_TIF_NEED_RESCHED	blne	svc_preempt#endif 	svc_exit r5, irq = 1			@ return from exception UNWIND(.fnend		)ENDPROC(__irq_svc) 	.ltorg #ifdef CONFIG_PREEMPTIONsvc_preempt:	mov	r8, lr1:	bl	preempt_schedule_irq		@ irq en/disable is done inside	ldr	r0, [tsk, #TI_FLAGS]		@ get new tasks TI_FLAGS	tst	r0, #_TIF_NEED_RESCHED	reteq	r8				@ go again	b	1b#endif __und_fault:	@ Correct the PC such that it is pointing at the instruction	@ which caused the fault.  If the faulting instruction was ARM	@ the PC will be pointing at the next instruction, and have to	@ subtract 4.  Otherwise, it is Thumb, and the PC will be	@ pointing at the second half of the Thumb instruction.  We	@ have to subtract 2.	ldr	r2, [r0, #S_PC]	sub	r2, r2, r1	str	r2, [r0, #S_PC]	b	do_undefinstrENDPROC(__und_fault) 	.align	5__und_svc:#ifdef CONFIG_KPROBES	@ If a kprobe is about to simulate a "stmdb sp..." instruction,	@ it obviously needs free stack space which then will belong to	@ the saved context.	svc_entry MAX_STACK_SIZE#else	svc_entry#endif 	mov	r1, #4				@ PC correction to apply THUMB(	tst	r5, #PSR_T_BIT		)	@ exception taken in Thumb mode? THUMB(	movne	r1, #2			)	@ if so, fix up PC correction	mov	r0, sp				@ struct pt_regs *regs	bl	__und_fault __und_svc_finish:	get_thread_info tsk	ldr	r5, [sp, #S_PSR]		@ Get SVC cpsr	svc_exit r5				@ return from exception UNWIND(.fnend		)ENDPROC(__und_svc) 	.align	5__pabt_svc:	svc_entry	mov	r2, sp				@ regs	pabt_helper	svc_exit r5				@ return from exception UNWIND(.fnend		)ENDPROC(__pabt_svc) 	.align	5__fiq_svc:	svc_entry trace=0	mov	r0, sp				@ struct pt_regs *regs	bl	handle_fiq_as_nmi	svc_exit_via_fiq UNWIND(.fnend		)ENDPROC(__fiq_svc) /* * Abort mode handlers */ @@ Taking a FIQ in abort mode is similar to taking a FIQ in SVC mode@ and reuses the same macros. However in abort mode we must also@ save/restore lr_abt and spsr_abt to make nested aborts safe.@	.align 5__fiq_abt:	svc_entry trace=0  ARM(	msr	cpsr_c, #ABT_MODE | PSR_I_BIT | PSR_F_BIT ) THUMB( mov	r0, #ABT_MODE | PSR_I_BIT | PSR_F_BIT ) THUMB( msr	cpsr_c, r0 )	mov	r1, lr		@ Save lr_abt	mrs	r2, spsr	@ Save spsr_abt, abort is now safe ARM(	msr	cpsr_c, #SVC_MODE | PSR_I_BIT | PSR_F_BIT ) THUMB( mov	r0, #SVC_MODE | PSR_I_BIT | PSR_F_BIT ) THUMB( msr	cpsr_c, r0 )	stmfd	sp!, {r1 - r2} 	add	r0, sp, #8			@ struct pt_regs *regs	bl	handle_fiq_as_nmi 	ldmfd	sp!, {r1 - r2} ARM(	msr	cpsr_c, #ABT_MODE | PSR_I_BIT | PSR_F_BIT ) THUMB( mov	r0, #ABT_MODE | PSR_I_BIT | PSR_F_BIT ) THUMB( msr	cpsr_c, r0 )	mov	lr, r1		@ Restore lr_abt, abort is unsafe	msr	spsr_cxsf, r2	@ Restore spsr_abt ARM(	msr	cpsr_c, #SVC_MODE | PSR_I_BIT | PSR_F_BIT ) THUMB( mov	r0, #SVC_MODE | PSR_I_BIT | PSR_F_BIT ) THUMB( msr	cpsr_c, r0 ) 	svc_exit_via_fiq UNWIND(.fnend		)ENDPROC(__fiq_abt) /* * User mode handlers * * EABI note: sp_svc is always 64-bit aligned here, so should PT_REGS_SIZE */ #if defined(CONFIG_AEABI) && (__LINUX_ARM_ARCH__ >= 5) && (PT_REGS_SIZE & 7)#error "sizeof(struct pt_regs) must be a multiple of 8"#endif 	.macro	usr_entry, trace=1, uaccess=1 UNWIND(.fnstart	) UNWIND(.cantunwind	)	@ don't unwind the user space	sub	sp, sp, #PT_REGS_SIZE ARM(	stmib	sp, {r1 - r12}	) THUMB(	stmia	sp, {r0 - r12}	)  ATRAP(	mrc	p15, 0, r7, c1, c0, 0) ATRAP(	ldr_va	r8, cr_alignment) 	ldmia	r0, {r3 - r5}	add	r0, sp, #S_PC		@ here for interlock avoidance	mov	r6, #-1			@  ""  ""     ""        "" 	str	r3, [sp]		@ save the "real" r0 copied					@ from the exception stack 	@	@ We are now ready to fill in the remaining blanks on the stack:	@	@  r4 - lr_<exception>, already fixed up for correct return/restart	@  r5 - spsr_<exception>	@  r6 - orig_r0 (see pt_regs definition in ptrace.h)	@	@ Also, separately save sp_usr and lr_usr	@	stmia	r0, {r4 - r6} ARM(	stmdb	r0, {sp, lr}^			) THUMB(	store_user_sp_lr r0, r1, S_SP - S_PC	) 	.if \uaccess	uaccess_disable ip	.endif 	@ Enable the alignment trap while in kernel mode ATRAP(	teq	r8, r7) ATRAP( mcrne	p15, 0, r8, c1, c0, 0) 	reload_current r7, r8 	@	@ Clear FP to mark the first stack frame	@	zero_fp 	.if	\trace#ifdef CONFIG_TRACE_IRQFLAGS	bl	trace_hardirqs_off#endif	ct_user_exit save = 0	.endif	.endm 	.macro	kuser_cmpxchg_check#if !defined(CONFIG_CPU_32v6K) && defined(CONFIG_KUSER_HELPERS)#ifndef CONFIG_MMU#warning "NPTL on non MMU needs fixing"#else	@ Make sure our user space atomic helper is restarted	@ if it was interrupted in a critical region.  Here we	@ perform a quick test inline since it should be false	@ 99.9999% of the time.  The rest is done out of line.	ldr	r0, =TASK_SIZE	cmp	r4, r0	blhs	kuser_cmpxchg64_fixup#endif#endif	.endm 	.align	5__dabt_usr:	usr_entry uaccess=0	kuser_cmpxchg_check	mov	r2, sp	dabt_helper	b	ret_from_exception UNWIND(.fnend		)ENDPROC(__dabt_usr) 	.align	5__irq_usr:	usr_entry	kuser_cmpxchg_check	irq_handler from_user=1	get_thread_info tsk	mov	why, #0	b	ret_to_user_from_irq UNWIND(.fnend		)ENDPROC(__irq_usr) 	.ltorg 	.align	5__und_usr:	usr_entry uaccess=0 	@ IRQs must be enabled before attempting to read the instruction from	@ user space since that could cause a page/translation fault if the	@ page table was modified by another CPU.	enable_irq 	tst	r5, #PSR_T_BIT			@ Thumb mode?	mov	r1, #2				@ set insn size to 2 for Thumb	bne	0f				@ handle as Thumb undef exception#ifdef CONFIG_FPE_NWFPE	adr	r9, ret_from_exception	bl	call_fpe			@ returns via R9 on success#endif	mov	r1, #4				@ set insn size to 4 for ARM0:	mov	r0, sp	uaccess_disable ip	bl	__und_fault	b	ret_from_exception UNWIND(.fnend)ENDPROC(__und_usr) 	.align	5__pabt_usr:	usr_entry	mov	r2, sp				@ regs	pabt_helper UNWIND(.fnend		)	/* fall through *//* * This is the return code to user mode for abort handlers */ENTRY(ret_from_exception) UNWIND(.fnstart	) UNWIND(.cantunwind	)	get_thread_info tsk	mov	why, #0	b	ret_to_user UNWIND(.fnend		)ENDPROC(__pabt_usr)ENDPROC(ret_from_exception) 	.align	5__fiq_usr:	usr_entry trace=0	kuser_cmpxchg_check	mov	r0, sp				@ struct pt_regs *regs

Lines 1–500 of 1134.

Keyboard shortcuts

General

Show keyboard shortcuts
?
Focus the current search
/

Issues and pull requests

Open filters
f

Issues, pull requests and Inbox

Select next item
j↓
Select previous item
k↑
Open selected item
Enter
Dismiss filters or clear selection
Esc

Repository code

Go to file
t