/* 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 *regsLines 1–500 of 1134. Load more
/* 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 1f 0: .endif mov_l r0, generic_handle_arch_irq bl call_with_stack 1: .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_invalid ENDPROC(__pabt_invalid) __dabt_invalid: inv_entry BAD_DATA b common_invalid ENDPROC(__dabt_invalid) __irq_invalid: inv_entry BAD_IRQ b common_invalid ENDPROC(__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_mode ENDPROC(__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_PREEMPTION svc_preempt: mov r8, lr 1: 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_undefinstr ENDPROC(__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 ARM 0: 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