From 4a9cb360197684a861bc06f06d33d5fcc8ffcbf5 Mon Sep 17 00:00:00 2001 From: Russell King Date: Thu, 10 Feb 2011 15:25:18 +0000 Subject: ARM: fixup SMP alternatives in modules With certain configurations, we inline the unlock functions in modules, which results in SMP alternatives being created in modules. We need to fix those up when loading a module to prevent undefined instruction faults. Signed-off-by: Russell King --- arch/arm/kernel/head.S | 38 ++++++++++++++++++++++++++------------ arch/arm/kernel/module.c | 22 +++++++++++++++++++++- 2 files changed, 47 insertions(+), 13 deletions(-) (limited to 'arch/arm/kernel') diff --git a/arch/arm/kernel/head.S b/arch/arm/kernel/head.S index c0225da3fb21..f06ff9feb0db 100644 --- a/arch/arm/kernel/head.S +++ b/arch/arm/kernel/head.S @@ -391,6 +391,7 @@ ENDPROC(__turn_mmu_on) #ifdef CONFIG_SMP_ON_UP + __INIT __fixup_smp: and r3, r9, #0x000f0000 @ architecture version teq r3, #0x000f0000 @ CPU ID supported? @@ -415,18 +416,7 @@ __fixup_smp_on_up: sub r3, r0, r3 add r4, r4, r3 add r5, r5, r3 -2: cmp r4, r5 - movhs pc, lr - ldmia r4!, {r0, r6} - ARM( str r6, [r0, r3] ) - THUMB( add r0, r0, r3 ) -#ifdef __ARMEB__ - THUMB( mov r6, r6, ror #16 ) @ Convert word order for big-endian. -#endif - THUMB( strh r6, [r0], #2 ) @ For Thumb-2, store as two halfwords - THUMB( mov r6, r6, lsr #16 ) @ to be robust against misaligned r3. - THUMB( strh r6, [r0] ) - b 2b + b __do_fixup_smp_on_up ENDPROC(__fixup_smp) .align @@ -440,7 +430,31 @@ smp_on_up: ALT_SMP(.long 1) ALT_UP(.long 0) .popsection +#endif + .text +__do_fixup_smp_on_up: + cmp r4, r5 + movhs pc, lr + ldmia r4!, {r0, r6} + ARM( str r6, [r0, r3] ) + THUMB( add r0, r0, r3 ) +#ifdef __ARMEB__ + THUMB( mov r6, r6, ror #16 ) @ Convert word order for big-endian. #endif + THUMB( strh r6, [r0], #2 ) @ For Thumb-2, store as two halfwords + THUMB( mov r6, r6, lsr #16 ) @ to be robust against misaligned r3. + THUMB( strh r6, [r0] ) + b __do_fixup_smp_on_up +ENDPROC(__do_fixup_smp_on_up) + +ENTRY(fixup_smp) + stmfd sp!, {r4 - r6, lr} + mov r4, r0 + add r5, r0, r1 + mov r3, #0 + bl __do_fixup_smp_on_up + ldmfd sp!, {r4 - r6, pc} +ENDPROC(fixup_smp) #include "head-common.S" diff --git a/arch/arm/kernel/module.c b/arch/arm/kernel/module.c index 2cfe8161b478..6d4105e6872f 100644 --- a/arch/arm/kernel/module.c +++ b/arch/arm/kernel/module.c @@ -22,6 +22,7 @@ #include #include +#include #include #ifdef CONFIG_XIP_KERNEL @@ -268,12 +269,28 @@ struct mod_unwind_map { const Elf_Shdr *txt_sec; }; +static const Elf_Shdr *find_mod_section(const Elf32_Ehdr *hdr, + const Elf_Shdr *sechdrs, const char *name) +{ + const Elf_Shdr *s, *se; + const char *secstrs = (void *)hdr + sechdrs[hdr->e_shstrndx].sh_offset; + + for (s = sechdrs, se = sechdrs + hdr->e_shnum; s < se; s++) + if (strcmp(name, secstrs + s->sh_name) == 0) + return s; + + return NULL; +} + +extern void fixup_smp(const void *, unsigned long); + int module_finalize(const Elf32_Ehdr *hdr, const Elf_Shdr *sechdrs, struct module *mod) { + const Elf_Shdr * __maybe_unused s = NULL; #ifdef CONFIG_ARM_UNWIND const char *secstrs = (void *)hdr + sechdrs[hdr->e_shstrndx].sh_offset; - const Elf_Shdr *s, *sechdrs_end = sechdrs + hdr->e_shnum; + const Elf_Shdr *sechdrs_end = sechdrs + hdr->e_shnum; struct mod_unwind_map maps[ARM_SEC_MAX]; int i; @@ -315,6 +332,9 @@ int module_finalize(const Elf32_Ehdr *hdr, const Elf_Shdr *sechdrs, maps[i].txt_sec->sh_addr, maps[i].txt_sec->sh_size); #endif + s = find_mod_section(hdr, sechdrs, ".alt.smp.init"); + if (s && !is_smp()) + fixup_smp((void *)s->sh_addr, s->sh_size); return 0; } -- cgit From cb06199b1df492fcfbaedd2256b5054f944b664f Mon Sep 17 00:00:00 2001 From: Rabin Vincent Date: Wed, 9 Feb 2011 11:35:12 +0100 Subject: ARM: 6654/1: perf/oprofile: fix off-by-one in stack check Since tail is the previous fp - 1, we need to compare the new fp with tail + 1 to ensure that we don't end up passing in the same tail again, in order to avoid a potential infinite loop in the perf interrupt handler (which has been observed to occur). A similar fix seems to be needed in the OProfile code. Acked-by: Will Deacon Signed-off-by: Rabin Vincent 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 5efa2647a2fb..d150ad1ccb5d 100644 --- a/arch/arm/kernel/perf_event.c +++ b/arch/arm/kernel/perf_event.c @@ -700,7 +700,7 @@ user_backtrace(struct frame_tail __user *tail, * Frame pointers should strictly progress back up the stack * (towards higher addresses). */ - if (tail >= buftail.fp) + if (tail + 1 >= buftail.fp) return NULL; return buftail.fp - 1; -- cgit From ed19b739c5c76ad241d30f6c6a5ee96fb284f4cf Mon Sep 17 00:00:00 2001 From: Will Deacon Date: Fri, 11 Feb 2011 15:55:12 +0100 Subject: ARM: 6656/1: hw_breakpoint: avoid UNPREDICTABLE behaviour when reading DBGDSCR Reading baseline CP14 registers, other than DBGDIDR, when the OS Lock is set leads to UNPREDICTABLE behaviour. This patch ensures that we clear the OS lock before accessing anything other than the DBGDIDR, thereby avoiding this behaviour. Signed-off-by: Will Deacon Signed-off-by: Russell King --- arch/arm/kernel/hw_breakpoint.c | 26 +++++++++++++------------- 1 file changed, 13 insertions(+), 13 deletions(-) (limited to 'arch/arm/kernel') diff --git a/arch/arm/kernel/hw_breakpoint.c b/arch/arm/kernel/hw_breakpoint.c index c9f3f0467570..ab02d8aadb77 100644 --- a/arch/arm/kernel/hw_breakpoint.c +++ b/arch/arm/kernel/hw_breakpoint.c @@ -834,11 +834,11 @@ static void reset_ctrl_regs(void *unused) /* * v7 debug contains save and restore registers so that debug state - * can be maintained across low-power modes without leaving - * the debug logic powered up. It is IMPLEMENTATION DEFINED whether - * we can write to the debug registers out of reset, so we must - * unlock the OS Lock Access Register to avoid taking undefined - * instruction exceptions later on. + * can be maintained across low-power modes without leaving the debug + * logic powered up. It is IMPLEMENTATION DEFINED whether we can access + * the debug registers out of reset, so we must unlock the OS Lock + * Access Register to avoid taking undefined instruction exceptions + * later on. */ if (debug_arch >= ARM_DEBUG_ARCH_V7_ECP14) { /* @@ -899,18 +899,18 @@ static int __init arch_hw_breakpoint_init(void) pr_info("%d breakpoint(s) reserved for watchpoint " "single-step.\n", core_num_reserved_brps); + /* + * Reset the breakpoint resources. We assume that a halting + * debugger will leave the world in a nice state for us. + */ + on_each_cpu(reset_ctrl_regs, NULL, 1); + ARM_DBG_READ(c1, 0, dscr); if (dscr & ARM_DSCR_HDBGEN) { + max_watchpoint_len = 4; pr_warning("halting debug mode enabled. Assuming maximum " - "watchpoint size of 4 bytes."); + "watchpoint size of %u bytes.", max_watchpoint_len); } else { - /* - * Reset the breakpoint resources. We assume that a halting - * debugger will leave the world in a nice state for us. - */ - smp_call_function(reset_ctrl_regs, NULL, 1); - reset_ctrl_regs(NULL); - /* Work out the maximum supported watchpoint length. */ max_watchpoint_len = get_max_wp_len(); pr_info("maximum watchpoint size is %u bytes.\n", -- cgit From 66e1cfe6d52c69d317e9df76ebc8538a34af0d51 Mon Sep 17 00:00:00 2001 From: Will Deacon Date: Fri, 11 Feb 2011 16:01:42 +0100 Subject: ARM: 6657/1: hw_breakpoint: fix ptrace breakpoint advertising on unsupported arch The ptrace debug information register was advertising breakpoint and watchpoint resources for unsupported debug architectures. This meant that setting breakpoints on these architectures would appear to succeed, although they would never fire in reality. This patch fixes the breakpoint slot probing so that it returns 0 when running on an unsupported debug architecture. Reported-by: Ulrich Weigand Signed-off-by: Will Deacon Signed-off-by: Russell King --- arch/arm/kernel/hw_breakpoint.c | 18 +++++++++++++----- 1 file changed, 13 insertions(+), 5 deletions(-) (limited to 'arch/arm/kernel') diff --git a/arch/arm/kernel/hw_breakpoint.c b/arch/arm/kernel/hw_breakpoint.c index ab02d8aadb77..d600bd350704 100644 --- a/arch/arm/kernel/hw_breakpoint.c +++ b/arch/arm/kernel/hw_breakpoint.c @@ -137,11 +137,10 @@ static u8 get_debug_arch(void) u32 didr; /* Do we implement the extended CPUID interface? */ - if (((read_cpuid_id() >> 16) & 0xf) != 0xf) { - pr_warning("CPUID feature registers not supported. " - "Assuming v6 debug is present.\n"); + if (WARN_ONCE((((read_cpuid_id() >> 16) & 0xf) != 0xf), + "CPUID feature registers not supported. " + "Assuming v6 debug is present.\n")) return ARM_DEBUG_ARCH_V6; - } ARM_DBG_READ(c0, 0, didr); return (didr >> 16) & 0xf; @@ -152,6 +151,12 @@ u8 arch_get_debug_arch(void) return debug_arch; } +static int debug_arch_supported(void) +{ + u8 arch = get_debug_arch(); + return arch >= ARM_DEBUG_ARCH_V6 && arch <= ARM_DEBUG_ARCH_V7_ECP14; +} + /* Determine number of BRP register available. */ static int get_num_brp_resources(void) { @@ -268,6 +273,9 @@ out: int hw_breakpoint_slots(int type) { + if (!debug_arch_supported()) + return 0; + /* * We can be called early, so don't rely on * our static variables being initialised. @@ -882,7 +890,7 @@ static int __init arch_hw_breakpoint_init(void) debug_arch = get_debug_arch(); - if (debug_arch > ARM_DEBUG_ARCH_V7_ECP14) { + if (!debug_arch_supported()) { pr_info("debug architecture 0x%x unsupported.\n", debug_arch); return 0; } -- cgit From 71efb063f4a145ae420be054f5a91dcf7c19b375 Mon Sep 17 00:00:00 2001 From: Will Deacon Date: Fri, 18 Feb 2011 16:21:06 +0100 Subject: ARM: 6742/1: pmu: avoid setting IRQ affinity on UP systems Now that we can execute a CONFIG_SMP kernel on a uniprocessor system, extra care has to be taken in the PMU IRQ affinity setting code to ensure that we don't always fail to initialise. This patch changes the CPU PMU initialisation code so that when we only have a single IRQ, whose affinity can not be changed at the controller, we report success (0) rather than -EINVAL. Reported-by: Avik Sil Acked-by: Jamie Iles Signed-off-by: Will Deacon Signed-off-by: Russell King --- arch/arm/kernel/pmu.c | 22 ++++++++++++++-------- 1 file changed, 14 insertions(+), 8 deletions(-) (limited to 'arch/arm/kernel') diff --git a/arch/arm/kernel/pmu.c b/arch/arm/kernel/pmu.c index b8af96ea62e6..2c79eec19262 100644 --- a/arch/arm/kernel/pmu.c +++ b/arch/arm/kernel/pmu.c @@ -97,28 +97,34 @@ set_irq_affinity(int irq, irq, cpu); return err; #else - return 0; + return -EINVAL; #endif } static int init_cpu_pmu(void) { - int i, err = 0; + int i, irqs, err = 0; struct platform_device *pdev = pmu_devices[ARM_PMU_DEVICE_CPU]; - if (!pdev) { - err = -ENODEV; - goto out; - } + if (!pdev) + return -ENODEV; + + irqs = pdev->num_resources; + + /* + * If we have a single PMU interrupt that we can't shift, assume that + * we're running on a uniprocessor machine and continue. + */ + if (irqs == 1 && !irq_can_set_affinity(platform_get_irq(pdev, 0))) + return 0; - for (i = 0; i < pdev->num_resources; ++i) { + for (i = 0; i < irqs; ++i) { err = set_irq_affinity(platform_get_irq(pdev, i), i); if (err) break; } -out: return err; } -- cgit From 315cfe7835c9a3fe27f15519bdeee8bf0a293e33 Mon Sep 17 00:00:00 2001 From: Catalin Marinas Date: Tue, 15 Feb 2011 18:06:57 +0100 Subject: ARM: 6676/1: Correct the cpu_architecture() function for ARMv7 If ID_MMFR0[3:0] >= 3, the architecture version is ARMv7. The code was currently only testing for ID_MMFR0[3:0] == 3. Signed-off-by: Catalin Marinas Signed-off-by: Russell King --- arch/arm/kernel/setup.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) (limited to 'arch/arm/kernel') diff --git a/arch/arm/kernel/setup.c b/arch/arm/kernel/setup.c index 420b8d6485d6..5ea4fb718b97 100644 --- a/arch/arm/kernel/setup.c +++ b/arch/arm/kernel/setup.c @@ -226,8 +226,8 @@ int cpu_architecture(void) * Register 0 and check for VMSAv7 or PMSAv7 */ asm("mrc p15, 0, %0, c0, c1, 4" : "=r" (mmfr0)); - if ((mmfr0 & 0x0000000f) == 0x00000003 || - (mmfr0 & 0x000000f0) == 0x00000030) + if ((mmfr0 & 0x0000000f) >= 0x00000003 || + (mmfr0 & 0x000000f0) >= 0x00000030) cpu_arch = CPU_ARCH_ARMv7; else if ((mmfr0 & 0x0000000f) == 0x00000002 || (mmfr0 & 0x000000f0) == 0x00000020) -- cgit From dc810efb0ca5702c9d96782b99282d4b4383e877 Mon Sep 17 00:00:00 2001 From: Pawel Moll Date: Wed, 16 Feb 2011 18:54:01 +0100 Subject: ARM: 6740/1: Place correctly notes section in the linker script Commit 18991197b4b588255ccabf472ebc84db7b66a19c added --build-id linker option when toolchain supports it. ARM one does, but for some reason places the section at 0 when linker script doesn't mention it explicitly. The 1e621a8e3752367d4aae78a8ab00a18fb2793f34 worked around the problem removing this section from binary image with explicit objcopy options, but it still exists in vmlinux, confusing tools like debuggers and perf. This problem was discussed here: http://lists.infradead.org/pipermail/linux-arm-kernel/2010-May/015994.html http://lists.infradead.org/pipermail/linux-arm-kernel/2010-May/015994.html but the proposed changes to the linker script were substantial. This patch simply places NOTES (36 bytes long, at least when compiled with CodeSourcery toolchain) between data and bss, which seem to be the right place (and suggested by the sample linker script in include/asm-generic/vmlinux.lds.h). It is enough to place it correctly in vmlinux (so debuggers are happy): Section Headers: [11] .data PROGBITS c07ce000 7ce000 020fc0 00 WA 0 0 32 [12] .notes NOTE c07eefc0 7eefc0 000024 00 AX 0 0 4 [13] .bss NOBITS c07ef000 7eefe4 01e628 00 WA 0 0 32 Program Headers: LOAD 0x008000 0xc0008000 0xc0008000 0x7e6fe4 0x805628 RWE 0x8000 NOTE 0x7eefc0 0xc07eefc0 0xc07eefc0 0x00024 0x00024 R E 0x4 Section to Segment mapping: Segment Sections... 00 <...> .data .notes .bss 01 .notes and to get it exposed as /sys/kernel/notes used by perf tools. Signed-off-by: Pawel Moll Signed-off-by: Russell King --- arch/arm/kernel/vmlinux.lds.S | 2 ++ 1 file changed, 2 insertions(+) (limited to 'arch/arm/kernel') diff --git a/arch/arm/kernel/vmlinux.lds.S b/arch/arm/kernel/vmlinux.lds.S index 86b66f3f2031..558bd81a4fce 100644 --- a/arch/arm/kernel/vmlinux.lds.S +++ b/arch/arm/kernel/vmlinux.lds.S @@ -247,6 +247,8 @@ SECTIONS } #endif + NOTES + BSS_SECTION(0, 0, 0) _end = .; -- cgit From 53399053eb505cf541b2405bd9d9bca5ecfb96fb Mon Sep 17 00:00:00 2001 From: Russell King Date: Sun, 20 Feb 2011 12:22:52 +0000 Subject: ARM: Ensure predictable endian state on signal handler entry Ensure a predictable endian state when entering signal handlers. This avoids programs which use SETEND to momentarily switch their endian state from having their signal handlers entered with an unpredictable endian state. Cc: Acked-by: Dave Martin Signed-off-by: Russell King --- arch/arm/kernel/signal.c | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) (limited to 'arch/arm/kernel') diff --git a/arch/arm/kernel/signal.c b/arch/arm/kernel/signal.c index 907d5a620bca..abaf8445ce25 100644 --- a/arch/arm/kernel/signal.c +++ b/arch/arm/kernel/signal.c @@ -474,7 +474,9 @@ setup_return(struct pt_regs *regs, struct k_sigaction *ka, unsigned long handler = (unsigned long)ka->sa.sa_handler; unsigned long retcode; int thumb = 0; - unsigned long cpsr = regs->ARM_cpsr & ~PSR_f; + unsigned long cpsr = regs->ARM_cpsr & ~(PSR_f | PSR_E_BIT); + + cpsr |= PSR_ENDSTATE; /* * Maybe we need to deliver a 32-bit signal to a 26-bit task. -- cgit From a9ad21fed09cb95d34af9474be0831525b30c4c6 Mon Sep 17 00:00:00 2001 From: Russell King Date: Mon, 21 Feb 2011 10:13:36 +0000 Subject: ARM: Keep exit text/data around for SMP_ON_UP When SMP_ON_UP is used and the spinlocks are inlined, we end up with inline spinlocks in the exit code, with references from the SMP alternatives section to the exit sections. This causes link time errors. Avoid this by placing the exit sections in the init-discarded region. Cc: Tested-by: Dave Martin Signed-off-by: Russell King --- arch/arm/kernel/vmlinux.lds.S | 9 +++++++++ 1 file changed, 9 insertions(+) (limited to 'arch/arm/kernel') diff --git a/arch/arm/kernel/vmlinux.lds.S b/arch/arm/kernel/vmlinux.lds.S index 558bd81a4fce..61462790757f 100644 --- a/arch/arm/kernel/vmlinux.lds.S +++ b/arch/arm/kernel/vmlinux.lds.S @@ -21,6 +21,12 @@ #define ARM_CPU_KEEP(x) #endif +#if defined(CONFIG_SMP_ON_UP) && !defined(CONFIG_DEBUG_SPINLOCK) +#define ARM_EXIT_KEEP(x) x +#else +#define ARM_EXIT_KEEP(x) +#endif + OUTPUT_ARCH(arm) ENTRY(stext) @@ -43,6 +49,7 @@ SECTIONS _sinittext = .; HEAD_TEXT INIT_TEXT + ARM_EXIT_KEEP(EXIT_TEXT) _einittext = .; ARM_CPU_DISCARD(PROC_INFO) __arch_info_begin = .; @@ -67,6 +74,7 @@ SECTIONS #ifndef CONFIG_XIP_KERNEL __init_begin = _stext; INIT_DATA + ARM_EXIT_KEEP(EXIT_DATA) #endif } @@ -162,6 +170,7 @@ SECTIONS . = ALIGN(PAGE_SIZE); __init_begin = .; INIT_DATA + ARM_EXIT_KEEP(EXIT_DATA) . = ALIGN(PAGE_SIZE); __init_end = .; #endif -- cgit From 5a5af730536fbf15fc354980cba2a0400afa6b76 Mon Sep 17 00:00:00 2001 From: Nicolas Pitre Date: Mon, 21 Feb 2011 04:37:20 +0100 Subject: ARM: 6745/1: kprobes insn decoding fix Marcin Slusarz says: > In arch/arm/kernel/kprobes-decode.c there's a function > arm_kprobe_decode_insn which does: > > } else if ((insn & 0x0e000000) == 0x0c400000) { > ... > > This is always false, so code below is dead. > I found this bug by coccinelle (http://coccinelle.lip6.fr/). Reported-by: Marcin Slusarz Signed-off-by: Nicolas Pitre Signed-off-by: Russell King --- arch/arm/kernel/kprobes-decode.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'arch/arm/kernel') diff --git a/arch/arm/kernel/kprobes-decode.c b/arch/arm/kernel/kprobes-decode.c index 2c1f0050c9c4..8f6ed43861f1 100644 --- a/arch/arm/kernel/kprobes-decode.c +++ b/arch/arm/kernel/kprobes-decode.c @@ -1437,7 +1437,7 @@ arm_kprobe_decode_insn(kprobe_opcode_t insn, struct arch_specific_insn *asi) return space_cccc_1100_010x(insn, asi); - } else if ((insn & 0x0e000000) == 0x0c400000) { + } else if ((insn & 0x0e000000) == 0x0c000000) { return space_cccc_110x(insn, asi); -- cgit