summaryrefslogtreecommitdiffstats
path: root/arch/arm/kernel
diff options
context:
space:
mode:
Diffstat (limited to 'arch/arm/kernel')
-rw-r--r--arch/arm/kernel/entry-armv.S7
-rw-r--r--arch/arm/kernel/head-common.S2
-rw-r--r--arch/arm/kernel/signal.c45
-rw-r--r--arch/arm/kernel/signal.h4
-rw-r--r--arch/arm/kernel/smp_scu.c4
-rw-r--r--arch/arm/kernel/traps.c8
-rw-r--r--arch/arm/kernel/unwind.c9
7 files changed, 47 insertions, 32 deletions
diff --git a/arch/arm/kernel/entry-armv.S b/arch/arm/kernel/entry-armv.S
index 0022b4d57f8b8..d2903e3bc8611 100644
--- a/arch/arm/kernel/entry-armv.S
+++ b/arch/arm/kernel/entry-armv.S
@@ -21,6 +21,7 @@
#include <mach/entry-macro.S>
#include <asm/thread_notify.h>
#include <asm/unwind.h>
+#include <asm/unistd.h>
#include "entry-header.S"
@@ -908,10 +909,10 @@ __kuser_cmpxchg: @ 0xffff0fc0
* A special ghost syscall is used for that (see traps.c).
*/
stmfd sp!, {r7, lr}
- mov r7, #0xff00 @ 0xfff0 into r7 for EABI
- orr r7, r7, #0xf0
- swi #0x9ffff0
+ ldr r7, =1f @ it's 20 bits
+ swi __ARM_NR_cmpxchg
ldmfd sp!, {r7, pc}
+1: .word __ARM_NR_cmpxchg
#elif __LINUX_ARM_ARCH__ < 6
diff --git a/arch/arm/kernel/head-common.S b/arch/arm/kernel/head-common.S
index 885a7214418d8..b9505aa267c00 100644
--- a/arch/arm/kernel/head-common.S
+++ b/arch/arm/kernel/head-common.S
@@ -97,7 +97,7 @@ __error_a:
bl printhex8
adr r0, str_a2
bl printascii
- adr r3, 3f
+ adr r3, 4f
ldmia r3, {r4, r5, r6} @ get machine desc list
sub r4, r3, r4 @ get offset between virt&phys
add r5, r5, r4 @ convert virt addresses to
diff --git a/arch/arm/kernel/signal.c b/arch/arm/kernel/signal.c
index 1423a3419789c..e7714f367eb83 100644
--- a/arch/arm/kernel/signal.c
+++ b/arch/arm/kernel/signal.c
@@ -1,7 +1,7 @@
/*
* linux/arch/arm/kernel/signal.c
*
- * Copyright (C) 1995-2002 Russell King
+ * Copyright (C) 1995-2009 Russell King
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License version 2 as
@@ -29,6 +29,7 @@
*/
#define SWI_SYS_SIGRETURN (0xef000000|(__NR_sigreturn)|(__NR_OABI_SYSCALL_BASE))
#define SWI_SYS_RT_SIGRETURN (0xef000000|(__NR_rt_sigreturn)|(__NR_OABI_SYSCALL_BASE))
+#define SWI_SYS_RESTART (0xef000000|__NR_restart_syscall|__NR_OABI_SYSCALL_BASE)
/*
* With EABI, the syscall number has to be loaded into r7.
@@ -49,6 +50,18 @@ const unsigned long sigreturn_codes[7] = {
};
/*
+ * Either we support OABI only, or we have EABI with the OABI
+ * compat layer enabled. In the later case we don't know if
+ * user space is EABI or not, and if not we must not clobber r7.
+ * Always using the OABI syscall solves that issue and works for
+ * all those cases.
+ */
+const unsigned long syscall_restart_code[2] = {
+ SWI_SYS_RESTART, /* swi __NR_restart_syscall */
+ 0xe49df004, /* ldr pc, [sp], #4 */
+};
+
+/*
* atomically swap in the new signal mask, and wait for a signal.
*/
asmlinkage int sys_sigsuspend(int restart, unsigned long oldmask, old_sigset_t mask)
@@ -645,32 +658,16 @@ static void do_signal(struct pt_regs *regs, int syscall)
regs->ARM_pc -= 4;
#else
u32 __user *usp;
- u32 swival = __NR_restart_syscall;
- regs->ARM_sp -= 12;
+ regs->ARM_sp -= 4;
usp = (u32 __user *)regs->ARM_sp;
- /*
- * Either we supports OABI only, or we have
- * EABI with the OABI compat layer enabled.
- * In the later case we don't know if user
- * space is EABI or not, and if not we must
- * not clobber r7. Always using the OABI
- * syscall solves that issue and works for
- * all those cases.
- */
- swival = swival - __NR_SYSCALL_BASE + __NR_OABI_SYSCALL_BASE;
-
- put_user(regs->ARM_pc, &usp[0]);
- /* swi __NR_restart_syscall */
- put_user(0xef000000 | swival, &usp[1]);
- /* ldr pc, [sp], #12 */
- put_user(0xe49df00c, &usp[2]);
-
- flush_icache_range((unsigned long)usp,
- (unsigned long)(usp + 3));
-
- regs->ARM_pc = regs->ARM_sp + 4;
+ if (put_user(regs->ARM_pc, usp) == 0) {
+ regs->ARM_pc = KERN_RESTART_CODE;
+ } else {
+ regs->ARM_sp += 4;
+ force_sigsegv(0, current);
+ }
#endif
}
}
diff --git a/arch/arm/kernel/signal.h b/arch/arm/kernel/signal.h
index 27beece155026..6fcfe8398aa47 100644
--- a/arch/arm/kernel/signal.h
+++ b/arch/arm/kernel/signal.h
@@ -1,12 +1,14 @@
/*
* linux/arch/arm/kernel/signal.h
*
- * Copyright (C) 2005 Russell King.
+ * Copyright (C) 2005-2009 Russell King.
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License version 2 as
* published by the Free Software Foundation.
*/
#define KERN_SIGRETURN_CODE (CONFIG_VECTORS_BASE + 0x00000500)
+#define KERN_RESTART_CODE (KERN_SIGRETURN_CODE + sizeof(sigreturn_codes))
extern const unsigned long sigreturn_codes[7];
+extern const unsigned long syscall_restart_code[2];
diff --git a/arch/arm/kernel/smp_scu.c b/arch/arm/kernel/smp_scu.c
index d3831f616ee9f..9ab4149bd9830 100644
--- a/arch/arm/kernel/smp_scu.c
+++ b/arch/arm/kernel/smp_scu.c
@@ -37,6 +37,10 @@ void __init scu_enable(void __iomem *scu_base)
u32 scu_ctrl;
scu_ctrl = __raw_readl(scu_base + SCU_CTRL);
+ /* already enabled? */
+ if (scu_ctrl & 1)
+ return;
+
scu_ctrl |= 1;
__raw_writel(scu_ctrl, scu_base + SCU_CTRL);
diff --git a/arch/arm/kernel/traps.c b/arch/arm/kernel/traps.c
index f838f36eb7027..3f361a783f43a 100644
--- a/arch/arm/kernel/traps.c
+++ b/arch/arm/kernel/traps.c
@@ -1,7 +1,7 @@
/*
* linux/arch/arm/kernel/traps.c
*
- * Copyright (C) 1995-2002 Russell King
+ * Copyright (C) 1995-2009 Russell King
* Fragments that appear the same as linux/arch/i386/kernel/traps.c (C) Linus Torvalds
*
* This program is free software; you can redistribute it and/or modify
@@ -528,7 +528,7 @@ asmlinkage int arm_syscall(int no, struct pt_regs *regs)
* __kuser_cmpxchg code in entry-armv.S should be aware of its
* existence. Don't ever use this from user code.
*/
- case 0xfff0:
+ case NR(cmpxchg):
for (;;) {
extern void do_DataAbort(unsigned long addr, unsigned int fsr,
struct pt_regs *regs);
@@ -573,7 +573,7 @@ asmlinkage int arm_syscall(int no, struct pt_regs *regs)
if not implemented, rather than raising SIGILL. This
way the calling program can gracefully determine whether
a feature is supported. */
- if (no <= 0x7ff)
+ if ((no & 0xffff) <= 0x7ff)
return -ENOSYS;
break;
}
@@ -751,6 +751,8 @@ void __init early_trap_init(void)
*/
memcpy((void *)KERN_SIGRETURN_CODE, sigreturn_codes,
sizeof(sigreturn_codes));
+ memcpy((void *)KERN_RESTART_CODE, syscall_restart_code,
+ sizeof(syscall_restart_code));
flush_icache_range(vectors, vectors + PAGE_SIZE);
modify_domain(DOMAIN_USER, DOMAIN_CLIENT);
diff --git a/arch/arm/kernel/unwind.c b/arch/arm/kernel/unwind.c
index 39baf1128bfa1..786ac2b6914ae 100644
--- a/arch/arm/kernel/unwind.c
+++ b/arch/arm/kernel/unwind.c
@@ -26,6 +26,15 @@
* http://infocenter.arm.com/help/topic/com.arm.doc.subset.swdev.abi/index.html
*/
+#if !defined (__ARM_EABI__)
+#warning Your compiler does not have EABI support.
+#warning ARM unwind is known to compile only with EABI compilers.
+#warning Change compiler or disable ARM_UNWIND option.
+#elif (__GNUC__ == 4 && __GNUC_MINOR__ <= 2)
+#warning Your compiler is too buggy; it is known to not compile ARM unwind support.
+#warning Change compiler or disable ARM_UNWIND option.
+#endif
+
#include <linux/kernel.h>
#include <linux/init.h>
#include <linux/module.h>