From 446a5a8b1eb91a6990e5c8fe29f14e7a95b69132 Mon Sep 17 00:00:00 2001 From: Will Deacon Date: Fri, 2 Jul 2010 16:41:52 +0100 Subject: ARM: 6205/1: perf: ensure counter delta is treated as unsigned Hardware performance counters on ARM are 32-bits wide but atomic64_t variables are used to represent counter data in the hw_perf_event structure. The armpmu_event_update function right-shifts a signed 64-bit delta variable and adds the result to the event count. This can lead to shifting in sign-bits if the MSB of the 32-bit counter value is set. This results in perf output such as: Performance counter stats for 'sleep 20': 18446744073460670464 cycles <-- 0xFFFFFFFFF12A6000 7783773 instructions # 0.000 IPC 465 context-switches 161 page-faults 1172393 branches 20.154242147 seconds time elapsed This patch ensures that the delta value is treated as unsigned so that the right shift sets the upper bits to zero. Cc: Acked-by: Jamie Iles Signed-off-by: Will Deacon Signed-off-by: Russell King --- arch/arm/kernel/perf_event.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'arch/arm/kernel') diff --git a/arch/arm/kernel/perf_event.c b/arch/arm/kernel/perf_event.c index c457686..de12536 100644 --- a/arch/arm/kernel/perf_event.c +++ b/arch/arm/kernel/perf_event.c @@ -201,7 +201,7 @@ armpmu_event_update(struct perf_event *event, { int shift = 64 - 32; s64 prev_raw_count, new_raw_count; - s64 delta; + u64 delta; again: prev_raw_count = atomic64_read(&hwc->prev_count); -- cgit v1.1 From ac78884e6d89714d18b32b5b7d574116ecfb7c88 Mon Sep 17 00:00:00 2001 From: Russell King Date: Sat, 10 Jul 2010 10:10:18 +0100 Subject: ARM: lockdep: fix unannotated irqs-on CPU: Testing write buffer coherency: ok ------------[ cut here ]------------ WARNING: at kernel/lockdep.c:3145 check_flags+0xcc/0x1dc() Modules linked in: [] (unwind_backtrace+0x0/0xf8) from [] (dump_stack+0x20/0x24) [] (dump_stack+0x20/0x24) from [] (warn_slowpath_common+0x58/0x70) [] (warn_slowpath_common+0x58/0x70) from [] (warn_slowpath_null+0x20/0x24) [] (warn_slowpath_null+0x20/0x24) from [] (check_flags+0xcc/0x1dc) [] (check_flags+0xcc/0x1dc) from [] (lock_acquire+0x50/0x140) [] (lock_acquire+0x50/0x140) from [] (_raw_spin_lock+0x50/0x88) [] (_raw_spin_lock+0x50/0x88) from [] (set_task_comm+0x2c/0x60) [] (set_task_comm+0x2c/0x60) from [] (kthreadd+0x30/0x108) [] (kthreadd+0x30/0x108) from [] (kernel_thread_exit+0x0/0x8) ---[ end trace 1b75b31a2719ed1c ]--- possible reason: unannotated irqs-on. irq event stamp: 3 hardirqs last enabled at (2): [] finish_task_switch+0x48/0xb0 hardirqs last disabled at (3): [] ret_slow_syscall+0xc/0x1c softirqs last enabled at (0): [] copy_process+0x394/0xe5c softirqs last disabled at (0): [<(null)>] (null) Fix this by ensuring that the lockdep interrupt state is manipulated in the appropriate places. We essentially treat userspace as an entirely separate environment which isn't relevant to lockdep (lockdep doesn't monitor userspace.) We don't tell lockdep that IRQs will be enabled in that environment. Instead, when creating kernel threads (which is a rare event compared to entering/leaving userspace) we have to update the lockdep state. Do this by starting threads with IRQs disabled, and in the kthread helper, tell lockdep that IRQs are enabled, and enable them. This provides lockdep with a consistent view of the current IRQ state in kernel space. This also revert portions of 0d928b0b616d1c5c5fe76019a87cba171ca91633 which didn't fix the problem. Tested-by: Ming Lei Signed-off-by: Russell King --- arch/arm/kernel/entry-armv.S | 16 ++++++---------- arch/arm/kernel/process.c | 23 ++++++++++++++--------- 2 files changed, 20 insertions(+), 19 deletions(-) (limited to 'arch/arm/kernel') diff --git a/arch/arm/kernel/entry-armv.S b/arch/arm/kernel/entry-armv.S index 7ee48e7..3fd7861 100644 --- a/arch/arm/kernel/entry-armv.S +++ b/arch/arm/kernel/entry-armv.S @@ -162,8 +162,6 @@ ENDPROC(__und_invalid) @ r4 - orig_r0 (see pt_regs definition in ptrace.h) @ stmia r5, {r0 - r4} - - asm_trace_hardirqs_off .endm .align 5 @@ -204,7 +202,7 @@ __dabt_svc: @ @ IRQs off again before pulling preserved data off the stack @ - disable_irq + disable_irq_notrace @ @ restore SPSR and restart the instruction @@ -218,6 +216,9 @@ ENDPROC(__dabt_svc) __irq_svc: svc_entry +#ifdef CONFIG_TRACE_IRQFLAGS + bl trace_hardirqs_off +#endif #ifdef CONFIG_PREEMPT get_thread_info tsk ldr r8, [tsk, #TI_PREEMPT] @ get preempt count @@ -291,7 +292,7 @@ __und_svc: @ @ IRQs off again before pulling preserved data off the stack @ -1: disable_irq +1: disable_irq_notrace @ @ restore SPSR and restart the instruction @@ -327,7 +328,7 @@ __pabt_svc: @ @ IRQs off again before pulling preserved data off the stack @ - disable_irq + disable_irq_notrace @ @ restore SPSR and restart the instruction @@ -393,8 +394,6 @@ ENDPROC(__pabt_svc) @ Clear FP to mark the first stack frame @ zero_fp - - asm_trace_hardirqs_off .endm .macro kuser_cmpxchg_check @@ -465,9 +464,6 @@ __irq_usr: THUMB( movne r0, #0 ) THUMB( strne r0, [r0] ) #endif -#ifdef CONFIG_TRACE_IRQFLAGS - bl trace_hardirqs_on -#endif mov why, #0 b ret_to_user diff --git a/arch/arm/kernel/process.c b/arch/arm/kernel/process.c index acf5e6f..a4a9cc8 100644 --- a/arch/arm/kernel/process.c +++ b/arch/arm/kernel/process.c @@ -351,17 +351,21 @@ EXPORT_SYMBOL(dump_fpu); /* * Shuffle the argument into the correct register before calling the - * thread function. r1 is the thread argument, r2 is the pointer to - * the thread function, and r3 points to the exit function. + * thread function. r4 is the thread argument, r5 is the pointer to + * the thread function, and r6 points to the exit function. */ extern void kernel_thread_helper(void); asm( ".pushsection .text\n" " .align\n" " .type kernel_thread_helper, #function\n" "kernel_thread_helper:\n" -" mov r0, r1\n" -" mov lr, r3\n" -" mov pc, r2\n" +#ifdef CONFIG_TRACE_IRQFLAGS +" bl trace_hardirqs_on\n" +#endif +" msr cpsr_c, r7\n" +" mov r0, r4\n" +" mov lr, r6\n" +" mov pc, r5\n" " .size kernel_thread_helper, . - kernel_thread_helper\n" " .popsection"); @@ -391,11 +395,12 @@ pid_t kernel_thread(int (*fn)(void *), void *arg, unsigned long flags) memset(®s, 0, sizeof(regs)); - regs.ARM_r1 = (unsigned long)arg; - regs.ARM_r2 = (unsigned long)fn; - regs.ARM_r3 = (unsigned long)kernel_thread_exit; + regs.ARM_r4 = (unsigned long)arg; + regs.ARM_r5 = (unsigned long)fn; + regs.ARM_r6 = (unsigned long)kernel_thread_exit; + regs.ARM_r7 = SVC_MODE | PSR_ENDSTATE | PSR_ISETSTATE; regs.ARM_pc = (unsigned long)kernel_thread_helper; - regs.ARM_cpsr = SVC_MODE | PSR_ENDSTATE | PSR_ISETSTATE; + regs.ARM_cpsr = regs.ARM_r7 | PSR_I_BIT; return do_fork(flags|CLONE_VM|CLONE_UNTRACED, 0, ®s, 0, NULL, NULL); } -- cgit v1.1 From 0ebe25f90cd99bb1bcf622ec8a841421d48380d6 Mon Sep 17 00:00:00 2001 From: Nicolas Pitre Date: Wed, 14 Jul 2010 05:21:22 +0100 Subject: ARM: 6226/1: fix kprobe bug in ldr instruction emulation From: Bin Yang Cc: stable@kernel.org Signed-off-by: Bin Yang Signed-off-by: Nicolas Pitre Signed-off-by: Russell King --- arch/arm/kernel/kprobes-decode.c | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) (limited to 'arch/arm/kernel') diff --git a/arch/arm/kernel/kprobes-decode.c b/arch/arm/kernel/kprobes-decode.c index da1f949..8bccbfa 100644 --- a/arch/arm/kernel/kprobes-decode.c +++ b/arch/arm/kernel/kprobes-decode.c @@ -583,13 +583,14 @@ static void __kprobes emulate_ldr(struct kprobe *p, struct pt_regs *regs) { insn_llret_3arg_fn_t *i_fn = (insn_llret_3arg_fn_t *)&p->ainsn.insn[0]; kprobe_opcode_t insn = p->opcode; + long ppc = (long)p->addr + 8; union reg_pair fnr; int rd = (insn >> 12) & 0xf; int rn = (insn >> 16) & 0xf; int rm = insn & 0xf; long rdv; - long rnv = regs->uregs[rn]; - long rmv = regs->uregs[rm]; /* rm/rmv may be invalid, don't care. */ + long rnv = (rn == 15) ? ppc : regs->uregs[rn]; + long rmv = (rm == 15) ? ppc : regs->uregs[rm]; long cpsr = regs->ARM_cpsr; fnr.dr = insnslot_llret_3arg_rflags(rnv, 0, rmv, cpsr, i_fn); -- cgit v1.1