]> git.karo-electronics.de Git - karo-tx-linux.git/commitdiff
arm: introduce ret_from_kernel_execve(), switch to generic kernel_execve()
authorAl Viro <viro@zeniv.linux.org.uk>
Thu, 2 Aug 2012 07:46:39 +0000 (11:46 +0400)
committerAl Viro <viro@zeniv.linux.org.uk>
Thu, 6 Sep 2012 17:57:22 +0000 (13:57 -0400)
ret_from_kernel_execve() is the asm tail of kernel_execve(), essentially;
the rest became shiny new generic implementation, right in fs/exec.c.
An architecture can provide ret_from_kernel_execve() and define
__ARCH_WANT_KERNEL_EXECVE; then it'll get the generic one.

Another new helper: current_pt_regs().  Default is task_pt_regs(current),
and it's perfectly fine to just leave it as is.  However, an architecture
might choose to provide an optimized variant in its thread_info.h

Signed-off-by: Al Viro <viro@zeniv.linux.org.uk>
arch/arm/include/asm/unistd.h
arch/arm/kernel/entry-common.S
arch/arm/kernel/sys_arm.c
fs/exec.c
include/linux/binfmts.h
include/linux/thread_info.h

index 0cab47d4a83ff97a23c7a9d2975cfb855a687e3e..2c9b7a87e64b1597f4a568b4f2429714360dae27 100644 (file)
 #define __ARCH_WANT_OLD_READDIR
 #define __ARCH_WANT_SYS_SOCKETCALL
 #endif
+#define __ARCH_WANT_KERNEL_EXECVE
 
 /*
  * "Conditional" syscalls
index 978eac57e04a783f8901a16986f6d88f96f125ba..08c682af5e52e290257f0675ea9c8a8762b55b6f 100644 (file)
@@ -91,6 +91,22 @@ ENTRY(ret_from_fork)
        b       ret_slow_syscall
 ENDPROC(ret_from_fork)
 
+/*
+ * turn a kernel thread into userland process
+ * use: ret_from_kernel_execve(struct pt_regs *normal, struct pt_regs *new)
+ */
+ENTRY(ret_from_kernel_execve)
+       mov     why, #0                 @ not a syscall
+       str     why, [r1, #S_R0]        @ ... and we want 0 in ->ARM_r0 as well
+       mov     r2, #S_FRAME_SIZE
+       bl      memmove                 @ copy regs to normal location; return
+                                       @ value is in r0 and it's the same as
+                                       @ the first argument, so r0 is unchanged.
+       get_thread_info tsk             @ thread structure
+       mov     sp, r0                  @ stack pointer just under pt_regs
+       b       ret_slow_syscall
+ENDPROC(ret_from_kernel_execve)
+
        .equ NR_syscalls,0
 #define CALL(x) .equ NR_syscalls,NR_syscalls+1
 #include "calls.S"
index 3ba62e3cd1a23e6d7350512c8e9846222bbcbcb4..c8e729efc1872cc3c5921334bca3531f9a68b7b6 100644 (file)
@@ -79,48 +79,6 @@ out:
        return error;
 }
 
-int kernel_execve(const char *filename,
-                 const char *const argv[],
-                 const char *const envp[])
-{
-       struct pt_regs regs;
-       int ret;
-
-       memset(&regs, 0, sizeof(struct pt_regs));
-       ret = do_execve(filename,
-                       (const char __user *const __user *)argv,
-                       (const char __user *const __user *)envp, &regs);
-       if (ret < 0)
-               goto out;
-
-       /*
-        * Save argc to the register structure for userspace.
-        */
-       regs.ARM_r0 = ret;
-
-       /*
-        * We were successful.  We won't be returning to our caller, but
-        * instead to user space by manipulating the kernel stack.
-        */
-       asm(    "add    r0, %0, %1\n\t"
-               "mov    r1, %2\n\t"
-               "mov    r2, %3\n\t"
-               "bl     memmove\n\t"    /* copy regs to top of stack */
-               "mov    r8, #0\n\t"     /* not a syscall */
-               "mov    r9, %0\n\t"     /* thread structure */
-               "mov    sp, r0\n\t"     /* reposition stack pointer */
-               "b      ret_to_user"
-               :
-               : "r" (current_thread_info()),
-                 "Ir" (THREAD_START_SP - sizeof(regs)),
-                 "r" (&regs),
-                 "Ir" (sizeof(regs))
-               : "r0", "r1", "r2", "r3", "r8", "r9", "ip", "lr", "memory");
-
- out:
-       return ret;
-}
-
 /*
  * Since loff_t is a 64 bit type we avoid a lot of ABI hassle
  * with a different argument ordering.
index d7f9e14f89778596c28850f4837ddae28b959135..85652ce1ecfe6e7d5624efc466bdb6767c72e9a3 100644 (file)
--- a/fs/exec.c
+++ b/fs/exec.c
@@ -2318,3 +2318,26 @@ int dump_seek(struct file *file, loff_t off)
        return ret;
 }
 EXPORT_SYMBOL(dump_seek);
+
+#ifdef __ARCH_WANT_KERNEL_EXECVE
+int kernel_execve(const char *filename,
+                 const char *const argv[],
+                 const char *const envp[])
+{
+       struct pt_regs regs;
+       int ret;
+
+       memset(&regs, 0, sizeof(struct pt_regs));
+       ret = do_execve(filename,
+                       (const char __user *const __user *)argv,
+                       (const char __user *const __user *)envp, &regs);
+       if (ret < 0)
+               return ret;
+
+       /*
+        * We were successful.  We won't be returning to our caller, but
+        * instead to user space by manipulating the kernel stack.
+        */
+       ret_from_kernel_execve(current_pt_regs(), &regs);
+}
+#endif
index 8938beabad7abbdfc9e914cb8e26797d89ebff3c..d708558d96bd83bf0d3442a027c752c25f5243cf 100644 (file)
@@ -19,6 +19,7 @@ struct pt_regs;
 
 #ifdef __KERNEL__
 #include <linux/sched.h>
+#include <linux/unistd.h>
 #include <asm/exec.h>
 
 #define CORENAME_MAX_SIZE 128
@@ -137,5 +138,10 @@ extern void do_coredump(long signr, int exit_code, struct pt_regs *regs);
 extern void set_binfmt(struct linux_binfmt *new);
 extern void free_bprm(struct linux_binprm *);
 
+#ifdef __ARCH_WANT_KERNEL_EXECVE
+extern void ret_from_kernel_execve(struct pt_regs *normal, struct pt_regs *new)
+       __noreturn;
+#endif
+
 #endif /* __KERNEL__ */
 #endif /* _LINUX_BINFMTS_H */
index ccc1899bd62e991e4649b72e7145010f93f948f9..f2de0d5db8989704519932bf55a2a12405532a32 100644 (file)
@@ -146,6 +146,10 @@ static inline bool test_and_clear_restore_sigmask(void)
 #error "no set_restore_sigmask() provided and default one won't work"
 #endif
 
+#ifndef current_pt_regs
+#define current_pt_regs() task_pt_regs(current)
+#endif
+
 #endif /* __KERNEL__ */
 
 #endif /* _LINUX_THREAD_INFO_H */