[PATCH] ARM: Move signal return code into vector page
authorRussell King <rmk@dyn-67.arm.linux.org.uk>
Wed, 22 Jun 2005 19:26:05 +0000 (20:26 +0100)
committerRussell King <rmk@dyn-67.arm.linux.org.uk>
Wed, 22 Jun 2005 19:26:05 +0000 (20:26 +0100)
Move the signal return code into the vector page instead of placing
it on the user mode stack, which will allow us to avoid flushing
the instruction cache on signals, as well as eventually allowing
non-exec stack.

Signed-off-by: Russell King <rmk+kernel@arm.linux.org.uk>
arch/arm/kernel/signal.c
arch/arm/kernel/signal.h [new file with mode: 0644]
arch/arm/kernel/traps.c

index 931919fd5121200e6c8a8cb80f696ab4dc265ae3..07ddeed61766559c1a6d12b1fb70f92608f31c8c 100644 (file)
@@ -19,6 +19,7 @@
 #include <asm/unistd.h>
 
 #include "ptrace.h"
+#include "signal.h"
 
 #define _BLOCKABLE (~(sigmask(SIGKILL) | sigmask(SIGSTOP)))
 
@@ -35,7 +36,7 @@
 #define SWI_THUMB_SIGRETURN    (0xdf00 << 16 | 0x2700 | (__NR_sigreturn - __NR_SYSCALL_BASE))
 #define SWI_THUMB_RT_SIGRETURN (0xdf00 << 16 | 0x2700 | (__NR_rt_sigreturn - __NR_SYSCALL_BASE))
 
-static const unsigned long retcodes[4] = {
+const unsigned long sigreturn_codes[4] = {
        SWI_SYS_SIGRETURN,      SWI_THUMB_SIGRETURN,
        SWI_SYS_RT_SIGRETURN,   SWI_THUMB_RT_SIGRETURN
 };
@@ -500,17 +501,25 @@ setup_return(struct pt_regs *regs, struct k_sigaction *ka,
                if (ka->sa.sa_flags & SA_SIGINFO)
                        idx += 2;
 
-               if (__put_user(retcodes[idx], rc))
+               if (__put_user(sigreturn_codes[idx], rc))
                        return 1;
 
-               /*
-                * Ensure that the instruction cache sees
-                * the return code written onto the stack.
-                */
-               flush_icache_range((unsigned long)rc,
-                                  (unsigned long)(rc + 1));
-
-               retcode = ((unsigned long)rc) + thumb;
+               if (cpsr & MODE32_BIT) {
+                       /*
+                        * 32-bit code can use the new high-page
+                        * signal return code support.
+                        */
+                       retcode = KERN_SIGRETURN_CODE + (idx << 2) + thumb;
+               } else {
+                       /*
+                        * Ensure that the instruction cache sees
+                        * the return code written onto the stack.
+                        */
+                       flush_icache_range((unsigned long)rc,
+                                          (unsigned long)(rc + 1));
+
+                       retcode = ((unsigned long)rc) + thumb;
+               }
        }
 
        regs->ARM_r0 = usig;
diff --git a/arch/arm/kernel/signal.h b/arch/arm/kernel/signal.h
new file mode 100644 (file)
index 0000000..91d26fa
--- /dev/null
@@ -0,0 +1,12 @@
+/*
+ *  linux/arch/arm/kernel/signal.h
+ *
+ *  Copyright (C) 2005 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    0xffff0500
+
+extern const unsigned long sigreturn_codes[4];
index 45d2a032d8900f4f4f4d12c97ed0da021a4aa233..2fb0a4cfb37a4af48c2365d500608ef871197e1a 100644 (file)
@@ -30,6 +30,7 @@
 #include <asm/traps.h>
 
 #include "ptrace.h"
+#include "signal.h"
 
 const char *processor_modes[]=
 { "USER_26", "FIQ_26" , "IRQ_26" , "SVC_26" , "UK4_26" , "UK5_26" , "UK6_26" , "UK7_26" ,
@@ -683,6 +684,14 @@ void __init trap_init(void)
        memcpy((void *)0xffff0000, __vectors_start, __vectors_end - __vectors_start);
        memcpy((void *)0xffff0200, __stubs_start, __stubs_end - __stubs_start);
        memcpy((void *)0xffff1000 - kuser_sz, __kuser_helper_start, kuser_sz);
+
+       /*
+        * Copy signal return handlers into the vector page, and
+        * set sigreturn to be a pointer to these.
+        */
+       memcpy((void *)KERN_SIGRETURN_CODE, sigreturn_codes,
+              sizeof(sigreturn_codes));
+
        flush_icache_range(0xffff0000, 0xffff0000 + PAGE_SIZE);
        modify_domain(DOMAIN_USER, DOMAIN_CLIENT);
 }