diff options
Diffstat (limited to 'arch/arm/kernel')
-rw-r--r-- | arch/arm/kernel/Makefile | 7 | ||||
-rw-r--r-- | arch/arm/kernel/asm-offsets.c | 3 | ||||
-rw-r--r-- | arch/arm/kernel/entry-armv.S | 523 | ||||
-rw-r--r-- | arch/arm/kernel/entry-header.S | 31 | ||||
-rw-r--r-- | arch/arm/kernel/head-nommu.S | 8 | ||||
-rw-r--r-- | arch/arm/kernel/head.S | 8 | ||||
-rw-r--r-- | arch/arm/kernel/hw_breakpoint.c | 12 | ||||
-rw-r--r-- | arch/arm/kernel/irq.c | 51 | ||||
-rw-r--r-- | arch/arm/kernel/kprobes-arm.c | 999 | ||||
-rw-r--r-- | arch/arm/kernel/kprobes-common.c | 577 | ||||
-rw-r--r-- | arch/arm/kernel/kprobes-decode.c | 1670 | ||||
-rw-r--r-- | arch/arm/kernel/kprobes-thumb.c | 1462 | ||||
-rw-r--r-- | arch/arm/kernel/kprobes.c | 222 | ||||
-rw-r--r-- | arch/arm/kernel/kprobes.h | 420 | ||||
-rw-r--r-- | arch/arm/kernel/perf_event.c | 10 | ||||
-rw-r--r-- | arch/arm/kernel/perf_event_v7.c | 344 | ||||
-rw-r--r-- | arch/arm/kernel/pmu.c | 87 | ||||
-rw-r--r-- | arch/arm/kernel/ptrace.c | 28 | ||||
-rw-r--r-- | arch/arm/kernel/setup.c | 109 | ||||
-rw-r--r-- | arch/arm/kernel/sleep.S | 84 | ||||
-rw-r--r-- | arch/arm/kernel/smp.c | 11 | ||||
-rw-r--r-- | arch/arm/kernel/smp_scu.c | 2 | ||||
-rw-r--r-- | arch/arm/kernel/tcm.c | 68 | ||||
-rw-r--r-- | arch/arm/kernel/traps.c | 17 | ||||
-rw-r--r-- | arch/arm/kernel/vmlinux.lds.S | 126 |
25 files changed, 4580 insertions, 2299 deletions
diff --git a/arch/arm/kernel/Makefile b/arch/arm/kernel/Makefile index a5b31af5c2b..f7887dc53c1 100644 --- a/arch/arm/kernel/Makefile +++ b/arch/arm/kernel/Makefile @@ -37,7 +37,12 @@ obj-$(CONFIG_HAVE_ARM_TWD) += smp_twd.o obj-$(CONFIG_DYNAMIC_FTRACE) += ftrace.o obj-$(CONFIG_FUNCTION_GRAPH_TRACER) += ftrace.o obj-$(CONFIG_KEXEC) += machine_kexec.o relocate_kernel.o -obj-$(CONFIG_KPROBES) += kprobes.o kprobes-decode.o +obj-$(CONFIG_KPROBES) += kprobes.o kprobes-common.o +ifdef CONFIG_THUMB2_KERNEL +obj-$(CONFIG_KPROBES) += kprobes-thumb.o +else +obj-$(CONFIG_KPROBES) += kprobes-arm.o +endif obj-$(CONFIG_ATAGS_PROC) += atags.o obj-$(CONFIG_OABI_COMPAT) += sys_oabi-compat.o obj-$(CONFIG_ARM_THUMBEE) += thumbee.o diff --git a/arch/arm/kernel/asm-offsets.c b/arch/arm/kernel/asm-offsets.c index 927522cfc12..16baba2e436 100644 --- a/arch/arm/kernel/asm-offsets.c +++ b/arch/arm/kernel/asm-offsets.c @@ -59,6 +59,9 @@ int main(void) DEFINE(TI_TP_VALUE, offsetof(struct thread_info, tp_value)); DEFINE(TI_FPSTATE, offsetof(struct thread_info, fpstate)); DEFINE(TI_VFPSTATE, offsetof(struct thread_info, vfpstate)); +#ifdef CONFIG_SMP + DEFINE(VFP_CPU, offsetof(union vfp_state, hard.cpu)); +#endif #ifdef CONFIG_ARM_THUMBEE DEFINE(TI_THUMBEE_STATE, offsetof(struct thread_info, thumbee_state)); #endif diff --git a/arch/arm/kernel/entry-armv.S b/arch/arm/kernel/entry-armv.S index 90c62cd51ca..a87cbf889ff 100644 --- a/arch/arm/kernel/entry-armv.S +++ b/arch/arm/kernel/entry-armv.S @@ -29,21 +29,53 @@ #include <asm/entry-macro-multi.S> /* - * Interrupt handling. Preserves r7, r8, r9 + * Interrupt handling. */ .macro irq_handler #ifdef CONFIG_MULTI_IRQ_HANDLER - ldr r5, =handle_arch_irq + ldr r1, =handle_arch_irq mov r0, sp - ldr r5, [r5] + ldr r1, [r1] adr lr, BSYM(9997f) - teq r5, #0 - movne pc, r5 + teq r1, #0 + movne pc, r1 #endif arch_irq_handler_default 9997: .endm + .macro pabt_helper + @ PABORT handler takes pt_regs in r2, fault address in r4 and psr in r5 +#ifdef MULTI_PABORT + ldr ip, .LCprocfns + mov lr, pc + ldr pc, [ip, #PROCESSOR_PABT_FUNC] +#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 ip, .LCprocfns + mov lr, pc + ldr pc, [ip, #PROCESSOR_DABT_FUNC] +#else + bl CPU_DABORT_HANDLER +#endif + .endm + #ifdef CONFIG_KPROBES .section .kprobes.text,"ax",%progbits #else @@ -126,106 +158,74 @@ ENDPROC(__und_invalid) SPFIX( subeq sp, sp, #4 ) stmia sp, {r1 - r12} - ldmia r0, {r1 - r3} - add r5, sp, #S_SP - 4 @ here for interlock avoidance - mov r4, #-1 @ "" "" "" "" - add r0, sp, #(S_FRAME_SIZE + \stack_hole - 4) - SPFIX( addeq r0, r0, #4 ) - str r1, [sp, #-4]! @ save the "real" r0 copied + ldmia r0, {r3 - r5} + add r7, sp, #S_SP - 4 @ here for interlock avoidance + mov r6, #-1 @ "" "" "" "" + add r2, sp, #(S_FRAME_SIZE + \stack_hole - 4) + SPFIX( addeq r2, r2, #4 ) + str r3, [sp, #-4]! @ save the "real" r0 copied @ from the exception stack - mov r1, lr + mov r3, lr @ @ We are now ready to fill in the remaining blanks on the stack: @ - @ r0 - sp_svc - @ r1 - lr_svc - @ r2 - lr_<exception>, already fixed up for correct return/restart - @ r3 - spsr_<exception> - @ r4 - orig_r0 (see pt_regs definition in ptrace.h) + @ 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 r5, {r0 - r4} + stmia r7, {r2 - r6} + +#ifdef CONFIG_TRACE_IRQFLAGS + bl trace_hardirqs_off +#endif .endm .align 5 __dabt_svc: svc_entry - - @ - @ get ready to re-enable interrupts if appropriate - @ - mrs r9, cpsr - tst r3, #PSR_I_BIT - biceq r9, r9, #PSR_I_BIT - - @ - @ Call the processor-specific abort handler: - @ - @ r2 - aborted context pc - @ r3 - aborted context cpsr - @ - @ 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 r4, .LCprocfns - mov lr, pc - ldr pc, [r4, #PROCESSOR_DABT_FUNC] -#else - bl CPU_DABORT_HANDLER -#endif - - @ - @ set desired IRQ state, then call main handler - @ - debug_entry r1 - msr cpsr_c, r9 mov r2, sp - bl do_DataAbort + dabt_helper @ @ IRQs off again before pulling preserved data off the stack @ disable_irq_notrace - @ - @ restore SPSR and restart the instruction - @ - ldr r2, [sp, #S_PSR] - svc_exit r2 @ return from exception +#ifdef CONFIG_TRACE_IRQFLAGS + tst r5, #PSR_I_BIT + bleq trace_hardirqs_on + tst r5, #PSR_I_BIT + blne trace_hardirqs_off +#endif + svc_exit r5 @ return from exception UNWIND(.fnend ) ENDPROC(__dabt_svc) .align 5 __irq_svc: svc_entry + irq_handler -#ifdef CONFIG_TRACE_IRQFLAGS - bl trace_hardirqs_off -#endif #ifdef CONFIG_PREEMPT get_thread_info tsk ldr r8, [tsk, #TI_PREEMPT] @ get preempt count - add r7, r8, #1 @ increment it - str r7, [tsk, #TI_PREEMPT] -#endif - - irq_handler -#ifdef CONFIG_PREEMPT - str r8, [tsk, #TI_PREEMPT] @ restore 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 - ldr r4, [sp, #S_PSR] @ irqs are already disabled + #ifdef CONFIG_TRACE_IRQFLAGS - tst r4, #PSR_I_BIT - bleq trace_hardirqs_on + @ The parent context IRQs must have been enabled to get here in + @ the first place, so there's no point checking the PSR I bit. + bl trace_hardirqs_on #endif - svc_exit r4 @ return from exception + svc_exit r5 @ return from exception UNWIND(.fnend ) ENDPROC(__irq_svc) @@ -251,7 +251,6 @@ __und_svc: #else svc_entry #endif - @ @ call emulation code, which returns using r9 if it has emulated @ the instruction, or the more conventional lr if we are to treat @@ -260,15 +259,16 @@ __und_svc: @ r0 - instruction @ #ifndef CONFIG_THUMB2_KERNEL - ldr r0, [r2, #-4] + ldr r0, [r4, #-4] #else - ldrh r0, [r2, #-2] @ Thumb instruction at LR - 2 + ldrh r0, [r4, #-2] @ Thumb instruction at LR - 2 and r9, r0, #0xf800 cmp r9, #0xe800 @ 32-bit instruction if xx >= 0 - ldrhhs r9, [r2] @ bottom 16 bits + ldrhhs r9, [r4] @ bottom 16 bits orrhs r0, r9, r0, lsl #16 #endif adr r9, BSYM(1f) + mov r2, r4 bl call_fpe mov r0, sp @ struct pt_regs *regs @@ -282,45 +282,35 @@ __und_svc: @ @ restore SPSR and restart the instruction @ - ldr r2, [sp, #S_PSR] @ Get SVC cpsr - svc_exit r2 @ return from exception + ldr r5, [sp, #S_PSR] @ Get SVC cpsr +#ifdef CONFIG_TRACE_IRQFLAGS + tst r5, #PSR_I_BIT + bleq trace_hardirqs_on + tst r5, #PSR_I_BIT + blne trace_hardirqs_off +#endif + svc_exit r5 @ return from exception UNWIND(.fnend ) ENDPROC(__und_svc) .align 5 __pabt_svc: svc_entry - - @ - @ re-enable interrupts if appropriate - @ - mrs r9, cpsr - tst r3, #PSR_I_BIT - biceq r9, r9, #PSR_I_BIT - - mov r0, r2 @ pass address of aborted instruction. -#ifdef MULTI_PABORT - ldr r4, .LCprocfns - mov lr, pc - ldr pc, [r4, #PROCESSOR_PABT_FUNC] -#else - bl CPU_PABORT_HANDLER -#endif - debug_entry r1 - msr cpsr_c, r9 @ Maybe enable interrupts mov r2, sp @ regs - bl do_PrefetchAbort @ call abort handler + pabt_helper @ @ IRQs off again before pulling preserved data off the stack @ disable_irq_notrace - @ - @ restore SPSR and restart the instruction - @ - ldr r2, [sp, #S_PSR] - svc_exit r2 @ return from exception +#ifdef CONFIG_TRACE_IRQFLAGS + tst r5, #PSR_I_BIT + bleq trace_hardirqs_on + tst r5, #PSR_I_BIT + blne trace_hardirqs_off +#endif + svc_exit r5 @ return from exception UNWIND(.fnend ) ENDPROC(__pabt_svc) @@ -351,23 +341,23 @@ ENDPROC(__pabt_svc) ARM( stmib sp, {r1 - r12} ) THUMB( stmia sp, {r0 - r12} ) - ldmia r0, {r1 - r3} + ldmia r0, {r3 - r5} add r0, sp, #S_PC @ here for interlock avoidance - mov r4, #-1 @ "" "" "" "" + mov r6, #-1 @ "" "" "" "" - str r1, [sp] @ save the "real" r0 copied + 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: @ - @ r2 - lr_<exception>, already fixed up for correct return/restart - @ r3 - spsr_<exception> - @ r4 - orig_r0 (see pt_regs definition in ptrace.h) + @ 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, {r2 - r4} + stmia r0, {r4 - r6} ARM( stmdb r0, {sp, lr}^ ) THUMB( store_user_sp_lr r0, r1, S_SP - S_PC ) @@ -380,10 +370,14 @@ ENDPROC(__pabt_svc) @ Clear FP to mark the first stack frame @ zero_fp + +#ifdef CONFIG_IRQSOFF_TRACER + bl trace_hardirqs_off +#endif .endm .macro kuser_cmpxchg_check -#if __LINUX_ARM_ARCH__ < 6 && !defined(CONFIG_NEEDS_SYSCALL_FOR_CMPXCHG) +#if !defined(CONFIG_CPU_32v6K) && !defined(CONFIG_NEEDS_SYSCALL_FOR_CMPXCHG) #ifndef CONFIG_MMU #warning "NPTL on non MMU needs fixing" #else @@ -391,8 +385,8 @@ ENDPROC(__pabt_svc) @ 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. - cmp r2, #TASK_SIZE - blhs kuser_cmpxchg_fixup + cmp r4, #TASK_SIZE + blhs kuser_cmpxchg64_fixup #endif #endif .endm @@ -401,32 +395,9 @@ ENDPROC(__pabt_svc) __dabt_usr: usr_entry kuser_cmpxchg_check - - @ - @ Call the processor-specific abort handler: - @ - @ r2 - aborted context pc - @ r3 - aborted context cpsr - @ - @ The abort handler must return the aborted address in r0, and - @ the fault status register in r1. - @ -#ifdef MULTI_DABORT - ldr r4, .LCprocfns - mov lr, pc - ldr pc, [r4, #PROCESSOR_DABT_FUNC] -#else - bl CPU_DABORT_HANDLER -#endif - - @ - @ IRQs on, then call the main handler - @ - debug_entry r1 - enable_irq mov r2, sp - adr lr, BSYM(ret_from_exception) - b do_DataAbort + dabt_helper + b ret_from_exception UNWIND(.fnend ) ENDPROC(__dabt_usr) @@ -434,28 +405,8 @@ ENDPROC(__dabt_usr) __irq_usr: usr_entry kuser_cmpxchg_check - -#ifdef CONFIG_IRQSOFF_TRACER - bl trace_hardirqs_off -#endif - - get_thread_info tsk -#ifdef CONFIG_PREEMPT - ldr r8, [tsk, #TI_PREEMPT] @ get preempt count - add r7, r8, #1 @ increment it - str r7, [tsk, #TI_PREEMPT] -#endif - irq_handler -#ifdef CONFIG_PREEMPT - ldr r0, [tsk, #TI_PREEMPT] - str r8, [tsk, #TI_PREEMPT] - teq r0, r7 - ARM( strne r0, [r0, -r0] ) - THUMB( movne r0, #0 ) - THUMB( strne r0, [r0] ) -#endif - + get_thread_info tsk mov why, #0 b ret_to_user_from_irq UNWIND(.fnend ) @@ -467,6 +418,9 @@ ENDPROC(__irq_usr) __und_usr: usr_entry + mov r2, r4 + mov r3, r5 + @ @ fall through to the emulation code, which returns using r9 if @ it has emulated the instruction, or the more conventional lr @@ -682,19 +636,8 @@ ENDPROC(__und_usr_unknown) .align 5 __pabt_usr: usr_entry - - mov r0, r2 @ pass address of aborted instruction. -#ifdef MULTI_PABORT - ldr r4, .LCprocfns - mov lr, pc - ldr pc, [r4, #PROCESSOR_PABT_FUNC] -#else - bl CPU_PABORT_HANDLER -#endif - debug_entry r1 - enable_irq @ Enable interrupts mov r2, sp @ regs - bl do_PrefetchAbort @ call abort handler + pabt_helper UNWIND(.fnend ) /* fall through */ /* @@ -758,31 +701,12 @@ ENDPROC(__switch_to) /* * User helpers. * - * These are segment of kernel provided user code reachable from user space - * at a fixed address in kernel memory. This is used to provide user space - * with some operations which require kernel help because of unimplemented - * native feature and/or instructions in many ARM CPUs. The idea is for - * this code to be executed directly in user mode for best efficiency but - * which is too intimate with the kernel counter part to be left to user - * libraries. In fact this code might even differ from one CPU to another - * depending on the available instruction set and restrictions like on - * SMP systems. In other words, the kernel reserves the right to change - * this code as needed without warning. Only the entry points and their - * results are guaranteed to be stable. - * * Each segment is 32-byte aligned and will be moved to the top of the high * vector page. New segments (if ever needed) must be added in front of * existing ones. This mechanism should be used only for things that are * really small and justified, and not be abused freely. * - * User space is expected to implement those things inline when optimizing - * for a processor that has the necessary native support, but only if such - * resulting binaries are already to be incompatible with earlier ARM - * processors due to the use of unsupported instructions other than what - * is provided here. In other words don't make binaries unable to run on - * earlier processors just for the sake of not using these kernel helpers - * if your compiled code is not going to use the new instructions for other - * purpose. + * See Documentation/arm/kernel_user_helpers.txt for formal definitions. */ THUMB( .arm ) @@ -799,96 +723,103 @@ ENDPROC(__switch_to) __kuser_helper_start: /* - * Reference prototype: - * - * void __kernel_memory_barrier(void) - * - * Input: - * - * lr = return address - * - * Output: - * - * none - * - * Clobbered: - * - * none - * - * Definition and user space usage example: - * - * typedef void (__kernel_dmb_t)(void); - * #define __kernel_dmb (*(__kernel_dmb_t *)0xffff0fa0) - * - * Apply any needed memory barrier to preserve consistency with data modified - * manually and __kuser_cmpxchg usage. - * - * This could be used as follows: - * - * #define __kernel_dmb() \ - * asm volatile ( "mov r0, #0xffff0fff; mov lr, pc; sub pc, r0, #95" \ - * : : : "r0", "lr","cc" ) + * Due to the length of some sequences, __kuser_cmpxchg64 spans 2 regular + * kuser "slots", therefore 0xffff0f80 is not used as a valid entry point. */ -__kuser_memory_barrier: @ 0xffff0fa0 +__kuser_cmpxchg64: @ 0xffff0f60 + +#if defined(CONFIG_NEEDS_SYSCALL_FOR_CMPXCHG) + + /* + * Poor you. No fast solution possible... + * The kernel itself must perform the operation. + * A special ghost syscall is used for that (see traps.c). + */ + stmfd sp!, {r7, lr} + ldr r7, 1f @ it's 20 bits + swi __ARM_NR_cmpxchg64 + ldmfd sp!, {r7, pc} +1: .word __ARM_NR_cmpxchg64 + +#elif defined(CONFIG_CPU_32v6K) + + stmfd sp!, {r4, r5, r6, r7} + ldrd r4, r5, [r0] @ load old val + ldrd r6, r7, [r1] @ load new val + smp_dmb arm +1: ldrexd r0, r1, [r2] @ load current val + eors r3, r0, r4 @ compare with oldval (1) + eoreqs r3, r1, r5 @ compare with oldval (2) + strexdeq r3, r6, r7, [r2] @ store newval if eq + teqeq r3, #1 @ success? + beq 1b @ if no then retry smp_dmb arm + rsbs r0, r3, #0 @ set returned val and C flag + ldmfd sp!, {r4, r5, r6, r7} + bx lr + +#elif !defined(CONFIG_SMP) + +#ifdef CONFIG_MMU + + /* + * The only thing that can break atomicity in this cmpxchg64 + * implementation is either an IRQ or a data abort exception + * causing another process/thread to be scheduled in the middle of + * the critical sequence. The same strategy as for cmpxchg is used. + */ + stmfd sp!, {r4, r5, r6, lr} + ldmia r0, {r4, r5} @ load old val + ldmia r1, {r6, lr} @ load new val +1: ldmia r2, {r0, r1} @ load current val + eors r3, r0, r4 @ compare with oldval (1) + eoreqs r3, r1, r5 @ compare with oldval (2) +2: stmeqia r2, {r6, lr} @ store newval if eq + rsbs r0, r3, #0 @ set return val and C flag + ldmfd sp!, {r4, r5, r6, pc} + + .text +kuser_cmpxchg64_fixup: + @ Called from kuser_cmpxchg_fixup. + @ r4 = address of interrupted insn (must be preserved). + @ sp = saved regs. r7 and r8 are clobbered. + @ 1b = first critical insn, 2b = last critical insn. + @ If r4 >= 1b and r4 <= 2b then saved pc_usr is set to 1b. + mov r7, #0xffff0fff + sub r7, r7, #(0xffff0fff - (0xffff0f60 + (1b - __kuser_cmpxchg64))) + subs r8, r4, r7 + rsbcss r8, r8, #(2b - 1b) + strcs r7, [sp, #S_PC] +#if __LINUX_ARM_ARCH__ < 6 + bcc kuser_cmpxchg32_fixup +#endif + mov pc, lr + .previous + +#else +#warning "NPTL on non MMU needs fixing" + mov r0, #-1 + adds r0, r0, #0 usr_ret lr +#endif + +#else +#error "incoherent kernel configuration" +#endif + + /* pad to next slot */ + .rept (16 - (. - __kuser_cmpxchg64)/4) + .word 0 + .endr .align 5 -/* - * Reference prototype: - * - * int __kernel_cmpxchg(int oldval, int newval, int *ptr) - * - * Input: - * - * r0 = oldval - * r1 = newval - * r2 = ptr - * lr = return address - * - * Output: - * - * r0 = returned value (zero or non-zero) - * C flag = set if r0 == 0, clear if r0 != 0 - * - * Clobbered: - * - * r3, ip, flags - * - * Definition and user space usage example: - * - * typedef int (__kernel_cmpxchg_t)(int oldval, int newval, int *ptr); - * #define __kernel_cmpxchg (*(__kernel_cmpxchg_t *)0xffff0fc0) - * - * Atomically store newval in *ptr if *ptr is equal to oldval for user space. - * Return zero if *ptr was changed or non-zero if no exchange happened. - * The C flag is also set if *ptr was changed to allow for assembly - * optimization in the calling code. - * - * Notes: - * - * - This routine already includes memory barriers as needed. - * - * For example, a user space atomic_add implementation could look like this: - * - * #define atomic_add(ptr, val) \ - * ({ register unsigned int *__ptr asm("r2") = (ptr); \ - * register unsigned int __result asm("r1"); \ - * asm volatile ( \ - * "1: @ atomic_add\n\t" \ - * "ldr r0, [r2]\n\t" \ - * "mov r3, #0xffff0fff\n\t" \ - * "add lr, pc, #4\n\t" \ - * "add r1, r0, %2\n\t" \ - * "add pc, r3, #(0xffff0fc0 - 0xffff0fff)\n\t" \ - * "bcc 1b" \ - * : "=&r" (__result) \ - * : "r" (__ptr), "rIL" (val) \ - * : "r0","r3","ip","lr","cc","memory" ); \ - * __result; }) - */ +__kuser_memory_barrier: @ 0xffff0fa0 + smp_dmb arm + usr_ret lr + + .align 5 __kuser_cmpxchg: @ 0xffff0fc0 @@ -925,15 +856,15 @@ __kuser_cmpxchg: @ 0xffff0fc0 usr_ret lr .text -kuser_cmpxchg_fixup: +kuser_cmpxchg32_fixup: @ Called from kuser_cmpxchg_check macro. - @ r2 = address of interrupted insn (must be preserved). + @ r4 = address of interrupted insn (must be preserved). @ sp = saved regs. r7 and r8 are clobbered. @ 1b = first critical insn, 2b = last critical insn. - @ If r2 >= 1b and r2 <= 2b then saved pc_usr is set to 1b. + @ If r4 >= 1b and r4 <= 2b then saved pc_usr is set to 1b. mov r7, #0xffff0fff sub r7, r7, #(0xffff0fff - (0xffff0fc0 + (1b - __kuser_cmpxchg))) - subs r8, r2, r7 + subs r8, r4, r7 rsbcss r8, r8, #(2b - 1b) strcs r7, [sp, #S_PC] mov pc, lr @@ -963,39 +894,6 @@ kuser_cmpxchg_fixup: .align 5 -/* - * Reference prototype: - * - * int __kernel_get_tls(void) - * - * Input: - * - * lr = return address - * - * Output: - * - * r0 = TLS value - * - * Clobbered: - * - * none - * - * Definition and user space usage example: - * - * typedef int (__kernel_get_tls_t)(void); - * #define __kernel_get_tls (*(__kernel_get_tls_t *)0xffff0fe0) - * - * Get the TLS value as previously set via the __ARM_NR_set_tls syscall. - * - * This could be used as follows: - * - * #define __kernel_get_tls() \ - * ({ register unsigned int __val asm("r0"); \ - * asm( "mov r0, #0xffff0fff; mov lr, pc; sub pc, r0, #31" \ - * : "=r" (__val) : : "lr","cc" ); \ - * __val; }) - */ - __kuser_get_tls: @ 0xffff0fe0 ldr r0, [pc, #(16 - 8)] @ read TLS, set in kuser_get_tls_init usr_ret lr @@ -1004,19 +902,6 @@ __kuser_get_tls: @ 0xffff0fe0 .word 0 @ 0xffff0ff0 software TLS value, then .endr @ pad up to __kuser_helper_version -/* - * Reference declaration: - * - * extern unsigned int __kernel_helper_version; - * - * Definition and user space usage example: - * - * #define __kernel_helper_version (*(unsigned int *)0xffff0ffc) - * - * User space may read this to determine the curent number of helpers - * available. - */ - __kuser_helper_version: @ 0xffff0ffc .word ((__kuser_helper_end - __kuser_helper_start) >> 5) diff --git a/arch/arm/kernel/entry-header.S b/arch/arm/kernel/entry-header.S index 051166c2a93..9a8531eadd3 100644 --- a/arch/arm/kernel/entry-header.S +++ b/arch/arm/kernel/entry-header.S @@ -121,15 +121,13 @@ .endm #else /* CONFIG_THUMB2_KERNEL */ .macro svc_exit, rpsr + ldr lr, [sp, #S_SP] @ top of the stack + ldrd r0, r1, [sp, #S_LR] @ calling lr and pc clrex @ clear the exclusive monitor - ldr r0, [sp, #S_SP] @ top of the stack - ldr r1, [sp, #S_PC] @ return address - tst r0, #4 @ orig stack 8-byte aligned? - stmdb r0, {r1, \rpsr} @ rfe context + stmdb lr!, {r0, r1, \rpsr} @ calling lr and rfe context ldmia sp, {r0 - r12} - ldr lr, [sp, #S_LR] - addeq sp, sp, #S_FRAME_SIZE - 8 @ aligned - addne sp, sp, #S_FRAME_SIZE - 4 @ not aligned + mov sp, lr + ldr lr, [sp], #4 rfeia sp! .endm @@ -165,25 +163,6 @@ .endm #endif /* !CONFIG_THUMB2_KERNEL */ - @ - @ Debug exceptions are taken as prefetch or data aborts. - @ We must disable preemption during the handler so that - @ we can access the debug registers safely. - @ - .macro debug_entry, fsr -#if defined(CONFIG_HAVE_HW_BREAKPOINT) && defined(CONFIG_PREEMPT) - ldr r4, =0x40f @ mask out fsr.fs - and r5, r4, \fsr - cmp r5, #2 @ debug exception - bne 1f - get_thread_info r10 - ldr r6, [r10, #TI_PREEMPT] @ get preempt count - add r11, r6, #1 @ increment it - str r11, [r10, #TI_PREEMPT] -1: -#endif - .endm - /* * 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. diff --git a/arch/arm/kernel/head-nommu.S b/arch/arm/kernel/head-nommu.S index 6b1e0ad9ec3..d46f25968be 100644 --- a/arch/arm/kernel/head-nommu.S +++ b/arch/arm/kernel/head-nommu.S @@ -32,8 +32,16 @@ * numbers for r1. * */ + .arm + __HEAD ENTRY(stext) + + THUMB( adr r9, BSYM(1f) ) @ Kernel is always entered in ARM. + THUMB( bx r9 ) @ If this is a Thumb-2 kernel, + THUMB( .thumb ) @ switch to Thumb now. + THUMB(1: ) + setmode PSR_F_BIT | PSR_I_BIT | SVC_MODE, r9 @ ensure svc mode @ and irqs disabled #ifndef CONFIG_CPU_CP15 diff --git a/arch/arm/kernel/head.S b/arch/arm/kernel/head.S index 278c1b0ebb2..742b6108a00 100644 --- a/arch/arm/kernel/head.S +++ b/arch/arm/kernel/head.S @@ -71,8 +71,16 @@ * crap here - that's what the boot loader (or in extreme, well justified * circumstances, zImage) is for. */ + .arm + __HEAD ENTRY(stext) + + THUMB( adr r9, BSYM(1f) ) @ Kernel is always entered in ARM. + THUMB( bx r9 ) @ If this is a Thumb-2 kernel, + THUMB( .thumb ) @ switch to Thumb now. + THUMB(1: ) + setmode PSR_F_BIT | PSR_I_BIT | SVC_MODE, r9 @ ensure svc mode @ and irqs disabled mrc p15, 0, r9, c0, c0 @ get processor id diff --git a/arch/arm/kernel/hw_breakpoint.c b/arch/arm/kernel/hw_breakpoint.c index 87acc25d7a3..a927ca1f556 100644 --- a/arch/arm/kernel/hw_breakpoint.c +++ b/arch/arm/kernel/hw_breakpoint.c @@ -796,7 +796,7 @@ unlock: /* * Called from either the Data Abort Handler [watchpoint] or the - * Prefetch Abort Handler [breakpoint] with preemption disabled. + * Prefetch Abort Handler [breakpoint] with interrupts disabled. */ static int hw_breakpoint_pending(unsigned long addr, unsigned int fsr, struct pt_regs *regs) @@ -804,8 +804,10 @@ static int hw_breakpoint_pending(unsigned long addr, unsigned int fsr, int ret = 0; u32 dscr; - /* We must be called with preemption disabled. */ - WARN_ON(preemptible()); + preempt_disable(); + + if (interrupts_enabled(regs)) + local_irq_enable(); /* We only handle watchpoints and hardware breakpoints. */ ARM_DBG_READ(c1, 0, dscr); @@ -824,10 +826,6 @@ static int hw_breakpoint_pending(unsigned long addr, unsigned int fsr, ret = 1; /* Unhandled fault. */ } - /* - * Re-enable preemption after it was disabled in the - * low-level exception handling code. - */ preempt_enable(); return ret; diff --git a/arch/arm/kernel/irq.c b/arch/arm/kernel/irq.c index 83bbad03fcc..0f928a131af 100644 --- a/arch/arm/kernel/irq.c +++ b/arch/arm/kernel/irq.c @@ -131,54 +131,63 @@ int __init arch_probe_nr_irqs(void) #ifdef CONFIG_HOTPLUG_CPU -static bool migrate_one_irq(struct irq_data *d) +static bool migrate_one_irq(struct irq_desc *desc) { - unsigned int cpu = cpumask_any_and(d->affinity, cpu_online_mask); + struct irq_data *d = irq_desc_get_irq_data(desc); + const struct cpumask *affinity = d->affinity; + struct irq_chip *c; bool ret = false; - if (cpu >= nr_cpu_ids) { - cpu = cpumask_any(cpu_online_mask); + /* + * If this is a per-CPU interrupt, or the affinity does not + * include this CPU, then we have nothing to do. + */ + if (irqd_is_per_cpu(d) || !cpumask_test_cpu(smp_processor_id(), affinity)) + return false; + + if (cpumask_any_and(affinity, cpu_online_mask) >= nr_cpu_ids) { + affinity = cpu_online_mask; ret = true; } - pr_debug("IRQ%u: moving from cpu%u to cpu%u\n", d->irq, d->node, cpu); - - d->chip->irq_set_affinity(d, cpumask_of(cpu), true); + c = irq_data_get_irq_chip(d); + if (c->irq_set_affinity) + c->irq_set_affinity(d, affinity, true); + else + pr_debug("IRQ%u: unable to set affinity\n", d->irq); return ret; } /* - * The CPU has been marked offline. Migrate IRQs off this CPU. If - * the affinity settings do not allow other CPUs, force them onto any + * The current CPU has been marked offline. Migrate IRQs off this CPU. + * If the affinity settings do not allow other CPUs, force them onto any * available CPU. + * + * Note: we must iterate over all IRQs, whether they have an attached + * action structure or not, as we need to get chained interrupts too. */ void migrate_irqs(void) { - unsigned int i, cpu = smp_processor_id(); + unsigned int i; struct irq_desc *desc; unsigned long flags; local_irq_save(flags); for_each_irq_desc(i, desc) { - struct irq_data *d = &desc->irq_data; bool affinity_broken = false; - raw_spin_lock(&desc->lock); - do { - if (desc->action == NULL) - break; - - if (d->node != cpu) - break; + if (!desc) + continue; - affinity_broken = migrate_one_irq(d); - } while (0); + raw_spin_lock(&desc->lock); + affinity_broken = migrate_one_irq(desc); raw_spin_unlock(&desc->lock); if (affinity_broken && printk_ratelimit()) - pr_warning("IRQ%u no longer affine to CPU%u\n", i, cpu); + pr_warning("IRQ%u no longer affine to CPU%u\n", i, + smp_processor_id()); |