aboutsummaryrefslogtreecommitdiffstats
path: root/arch/arm
diff options
context:
space:
mode:
Diffstat (limited to 'arch/arm')
-rw-r--r--arch/arm/Kconfig1
-rw-r--r--arch/arm/include/asm/processor.h5
-rw-r--r--arch/arm/include/asm/ptrace.h5
-rw-r--r--arch/arm/include/asm/system.h1
-rw-r--r--arch/arm/include/asm/unistd.h2
-rw-r--r--arch/arm/kernel/calls.S2
-rw-r--r--arch/arm/kernel/entry-common.S29
-rw-r--r--arch/arm/kernel/process.c75
-rw-r--r--arch/arm/kernel/sys_arm.c63
9 files changed, 46 insertions, 137 deletions
diff --git a/arch/arm/Kconfig b/arch/arm/Kconfig
index 2867a774230..e40eefb5d32 100644
--- a/arch/arm/Kconfig
+++ b/arch/arm/Kconfig
@@ -52,6 +52,7 @@ config ARM
52 select GENERIC_STRNCPY_FROM_USER 52 select GENERIC_STRNCPY_FROM_USER
53 select GENERIC_STRNLEN_USER 53 select GENERIC_STRNLEN_USER
54 select DCACHE_WORD_ACCESS if (CPU_V6 || CPU_V6K || CPU_V7) && !CPU_BIG_ENDIAN 54 select DCACHE_WORD_ACCESS if (CPU_V6 || CPU_V6K || CPU_V7) && !CPU_BIG_ENDIAN
55 select GENERIC_KERNEL_THREAD
55 help 56 help
56 The ARM series is a line of low-power-consumption RISC chip designs 57 The ARM series is a line of low-power-consumption RISC chip designs
57 licensed by ARM Ltd and targeted at embedded applications and 58 licensed by ARM Ltd and targeted at embedded applications and
diff --git a/arch/arm/include/asm/processor.h b/arch/arm/include/asm/processor.h
index 99afa749826..06e7d509eaa 100644
--- a/arch/arm/include/asm/processor.h
+++ b/arch/arm/include/asm/processor.h
@@ -85,11 +85,6 @@ unsigned long get_wchan(struct task_struct *p);
85#define cpu_relax() barrier() 85#define cpu_relax() barrier()
86#endif 86#endif
87 87
88/*
89 * Create a new kernel thread
90 */
91extern int kernel_thread(int (*fn)(void *), void *arg, unsigned long flags);
92
93#define task_pt_regs(p) \ 88#define task_pt_regs(p) \
94 ((struct pt_regs *)(THREAD_START_SP + task_stack_page(p)) - 1) 89 ((struct pt_regs *)(THREAD_START_SP + task_stack_page(p)) - 1)
95 90
diff --git a/arch/arm/include/asm/ptrace.h b/arch/arm/include/asm/ptrace.h
index 355ece523f4..44fe998269d 100644
--- a/arch/arm/include/asm/ptrace.h
+++ b/arch/arm/include/asm/ptrace.h
@@ -254,6 +254,11 @@ static inline unsigned long user_stack_pointer(struct pt_regs *regs)
254 return regs->ARM_sp; 254 return regs->ARM_sp;
255} 255}
256 256
257#define current_pt_regs(void) ({ \
258 register unsigned long sp asm ("sp"); \
259 (struct pt_regs *)((sp | (THREAD_SIZE - 1)) - 7) - 1; \
260})
261
257#endif /* __KERNEL__ */ 262#endif /* __KERNEL__ */
258 263
259#endif /* __ASSEMBLY__ */ 264#endif /* __ASSEMBLY__ */
diff --git a/arch/arm/include/asm/system.h b/arch/arm/include/asm/system.h
index 74542c52f9b..368165e33c1 100644
--- a/arch/arm/include/asm/system.h
+++ b/arch/arm/include/asm/system.h
@@ -2,7 +2,6 @@
2#include <asm/barrier.h> 2#include <asm/barrier.h>
3#include <asm/compiler.h> 3#include <asm/compiler.h>
4#include <asm/cmpxchg.h> 4#include <asm/cmpxchg.h>
5#include <asm/exec.h>
6#include <asm/switch_to.h> 5#include <asm/switch_to.h>
7#include <asm/system_info.h> 6#include <asm/system_info.h>
8#include <asm/system_misc.h> 7#include <asm/system_misc.h>
diff --git a/arch/arm/include/asm/unistd.h b/arch/arm/include/asm/unistd.h
index d9ff5cc3a50..f259921edfe 100644
--- a/arch/arm/include/asm/unistd.h
+++ b/arch/arm/include/asm/unistd.h
@@ -478,6 +478,8 @@
478#define __ARCH_WANT_OLD_READDIR 478#define __ARCH_WANT_OLD_READDIR
479#define __ARCH_WANT_SYS_SOCKETCALL 479#define __ARCH_WANT_SYS_SOCKETCALL
480#endif 480#endif
481#define __ARCH_WANT_SYS_EXECVE
482#define __ARCH_WANT_KERNEL_EXECVE
481 483
482/* 484/*
483 * "Conditional" syscalls 485 * "Conditional" syscalls
diff --git a/arch/arm/kernel/calls.S b/arch/arm/kernel/calls.S
index e337879595e..831cd38c8d9 100644
--- a/arch/arm/kernel/calls.S
+++ b/arch/arm/kernel/calls.S
@@ -20,7 +20,7 @@
20 CALL(sys_creat) 20 CALL(sys_creat)
21 CALL(sys_link) 21 CALL(sys_link)
22/* 10 */ CALL(sys_unlink) 22/* 10 */ CALL(sys_unlink)
23 CALL(sys_execve_wrapper) 23 CALL(sys_execve)
24 CALL(sys_chdir) 24 CALL(sys_chdir)
25 CALL(OBSOLETE(sys_time)) /* used by libc4 */ 25 CALL(OBSOLETE(sys_time)) /* used by libc4 */
26 CALL(sys_mknod) 26 CALL(sys_mknod)
diff --git a/arch/arm/kernel/entry-common.S b/arch/arm/kernel/entry-common.S
index f45987037bf..e340fa1db20 100644
--- a/arch/arm/kernel/entry-common.S
+++ b/arch/arm/kernel/entry-common.S
@@ -91,6 +91,30 @@ ENTRY(ret_from_fork)
91 b ret_slow_syscall 91 b ret_slow_syscall
92ENDPROC(ret_from_fork) 92ENDPROC(ret_from_fork)
93 93
94ENTRY(ret_from_kernel_thread)
95 UNWIND(.fnstart)
96 UNWIND(.cantunwind)
97 bl schedule_tail
98 mov r0, r4
99 adr lr, BSYM(1f) @ kernel threads should not exit
100 mov pc, r5
1011: bl do_exit
102 nop
103 UNWIND(.fnend)
104ENDPROC(ret_from_kernel_thread)
105
106/*
107 * turn a kernel thread into userland process
108 * use: ret_from_kernel_execve(struct pt_regs *normal)
109 */
110ENTRY(ret_from_kernel_execve)
111 mov why, #0 @ not a syscall
112 str why, [r0, #S_R0] @ ... and we want 0 in ->ARM_r0 as well
113 get_thread_info tsk @ thread structure
114 mov sp, r0 @ stack pointer just under pt_regs
115 b ret_slow_syscall
116ENDPROC(ret_from_kernel_execve)
117
94 .equ NR_syscalls,0 118 .equ NR_syscalls,0
95#define CALL(x) .equ NR_syscalls,NR_syscalls+1 119#define CALL(x) .equ NR_syscalls,NR_syscalls+1
96#include "calls.S" 120#include "calls.S"
@@ -517,11 +541,6 @@ sys_vfork_wrapper:
517 b sys_vfork 541 b sys_vfork
518ENDPROC(sys_vfork_wrapper) 542ENDPROC(sys_vfork_wrapper)
519 543
520sys_execve_wrapper:
521 add r3, sp, #S_OFF
522 b sys_execve
523ENDPROC(sys_execve_wrapper)
524
525sys_clone_wrapper: 544sys_clone_wrapper:
526 add ip, sp, #S_OFF 545 add ip, sp, #S_OFF
527 str ip, [sp, #4] 546 str ip, [sp, #4]
diff --git a/arch/arm/kernel/process.c b/arch/arm/kernel/process.c
index 04eea22d795..f98c17ff195 100644
--- a/arch/arm/kernel/process.c
+++ b/arch/arm/kernel/process.c
@@ -373,6 +373,7 @@ void release_thread(struct task_struct *dead_task)
373} 373}
374 374
375asmlinkage void ret_from_fork(void) __asm__("ret_from_fork"); 375asmlinkage void ret_from_fork(void) __asm__("ret_from_fork");
376asmlinkage void ret_from_kernel_thread(void) __asm__("ret_from_kernel_thread");
376 377
377int 378int
378copy_thread(unsigned long clone_flags, unsigned long stack_start, 379copy_thread(unsigned long clone_flags, unsigned long stack_start,
@@ -381,13 +382,20 @@ copy_thread(unsigned long clone_flags, unsigned long stack_start,
381 struct thread_info *thread = task_thread_info(p); 382 struct thread_info *thread = task_thread_info(p);
382 struct pt_regs *childregs = task_pt_regs(p); 383 struct pt_regs *childregs = task_pt_regs(p);
383 384
384 *childregs = *regs;
385 childregs->ARM_r0 = 0;
386 childregs->ARM_sp = stack_start;
387
388 memset(&thread->cpu_context, 0, sizeof(struct cpu_context_save)); 385 memset(&thread->cpu_context, 0, sizeof(struct cpu_context_save));
386
387 if (likely(regs)) {
388 *childregs = *regs;
389 childregs->ARM_r0 = 0;
390 childregs->ARM_sp = stack_start;
391 thread->cpu_context.pc = (unsigned long)ret_from_fork;
392 } else {
393 thread->cpu_context.r4 = stk_sz;
394 thread->cpu_context.r5 = stack_start;
395 thread->cpu_context.pc = (unsigned long)ret_from_kernel_thread;
396 childregs->ARM_cpsr = SVC_MODE;
397 }
389 thread->cpu_context.sp = (unsigned long)childregs; 398 thread->cpu_context.sp = (unsigned long)childregs;
390 thread->cpu_context.pc = (unsigned long)ret_from_fork;
391 399
392 clear_ptrace_hw_breakpoint(p); 400 clear_ptrace_hw_breakpoint(p);
393 401
@@ -423,63 +431,6 @@ int dump_fpu (struct pt_regs *regs, struct user_fp *fp)
423} 431}
424EXPORT_SYMBOL(dump_fpu); 432EXPORT_SYMBOL(dump_fpu);
425 433
426/*
427 * Shuffle the argument into the correct register before calling the
428 * thread function. r4 is the thread argument, r5 is the pointer to
429 * the thread function, and r6 points to the exit function.
430 */
431extern void kernel_thread_helper(void);
432asm( ".pushsection .text\n"
433" .align\n"
434" .type kernel_thread_helper, #function\n"
435"kernel_thread_helper:\n"
436#ifdef CONFIG_TRACE_IRQFLAGS
437" bl trace_hardirqs_on\n"
438#endif
439" msr cpsr_c, r7\n"
440" mov r0, r4\n"
441" mov lr, r6\n"
442" mov pc, r5\n"
443" .size kernel_thread_helper, . - kernel_thread_helper\n"
444" .popsection");
445
446#ifdef CONFIG_ARM_UNWIND
447extern void kernel_thread_exit(long code);
448asm( ".pushsection .text\n"
449" .align\n"
450" .type kernel_thread_exit, #function\n"
451"kernel_thread_exit:\n"
452" .fnstart\n"
453" .cantunwind\n"
454" bl do_exit\n"
455" nop\n"
456" .fnend\n"
457" .size kernel_thread_exit, . - kernel_thread_exit\n"
458" .popsection");
459#else
460#define kernel_thread_exit do_exit
461#endif
462
463/*
464 * Create a kernel thread.
465 */
466pid_t kernel_thread(int (*fn)(void *), void *arg, unsigned long flags)
467{
468 struct pt_regs regs;
469
470 memset(&regs, 0, sizeof(regs));
471
472 regs.ARM_r4 = (unsigned long)arg;
473 regs.ARM_r5 = (unsigned long)fn;
474 regs.ARM_r6 = (unsigned long)kernel_thread_exit;
475 regs.ARM_r7 = SVC_MODE | PSR_ENDSTATE | PSR_ISETSTATE;
476 regs.ARM_pc = (unsigned long)kernel_thread_helper;
477 regs.ARM_cpsr = regs.ARM_r7 | PSR_I_BIT;
478
479 return do_fork(flags|CLONE_VM|CLONE_UNTRACED, 0, &regs, 0, NULL, NULL);
480}
481EXPORT_SYMBOL(kernel_thread);
482
483unsigned long get_wchan(struct task_struct *p) 434unsigned long get_wchan(struct task_struct *p)
484{ 435{
485 struct stackframe frame; 436 struct stackframe frame;
diff --git a/arch/arm/kernel/sys_arm.c b/arch/arm/kernel/sys_arm.c
index 76cbb055dd0..c2a898aa57a 100644
--- a/arch/arm/kernel/sys_arm.c
+++ b/arch/arm/kernel/sys_arm.c
@@ -59,69 +59,6 @@ asmlinkage int sys_vfork(struct pt_regs *regs)
59 return do_fork(CLONE_VFORK | CLONE_VM | SIGCHLD, regs->ARM_sp, regs, 0, NULL, NULL); 59 return do_fork(CLONE_VFORK | CLONE_VM | SIGCHLD, regs->ARM_sp, regs, 0, NULL, NULL);
60} 60}
61 61
62/* sys_execve() executes a new program.
63 * This is called indirectly via a small wrapper
64 */
65asmlinkage int sys_execve(const char __user *filenamei,
66 const char __user *const __user *argv,
67 const char __user *const __user *envp, struct pt_regs *regs)
68{
69 int error;
70 char * filename;
71
72 filename = getname(filenamei);
73 error = PTR_ERR(filename);
74 if (IS_ERR(filename))
75 goto out;
76 error = do_execve(filename, argv, envp, regs);
77 putname(filename);
78out:
79 return error;
80}
81
82int kernel_execve(const char *filename,
83 const char *const argv[],
84 const char *const envp[])
85{
86 struct pt_regs regs;
87 int ret;
88
89 memset(&regs, 0, sizeof(struct pt_regs));
90 ret = do_execve(filename,
91 (const char __user *const __user *)argv,
92 (const char __user *const __user *)envp, &regs);
93 if (ret < 0)
94 goto out;
95
96 /*
97 * Save argc to the register structure for userspace.
98 */
99 regs.ARM_r0 = ret;
100
101 /*
102 * We were successful. We won't be returning to our caller, but
103 * instead to user space by manipulating the kernel stack.
104 */
105 asm( "add r0, %0, %1\n\t"
106 "mov r1, %2\n\t"
107 "mov r2, %3\n\t"
108 "bl memmove\n\t" /* copy regs to top of stack */
109 "mov r8, #0\n\t" /* not a syscall */
110 "mov r9, %0\n\t" /* thread structure */
111 "mov sp, r0\n\t" /* reposition stack pointer */
112 "b ret_to_user"
113 :
114 : "r" (current_thread_info()),
115 "Ir" (THREAD_START_SP - sizeof(regs)),
116 "r" (&regs),
117 "Ir" (sizeof(regs))
118 : "r0", "r1", "r2", "r3", "r8", "r9", "ip", "lr", "memory");
119
120 out:
121 return ret;
122}
123EXPORT_SYMBOL(kernel_execve);
124
125/* 62/*
126 * Since loff_t is a 64 bit type we avoid a lot of ABI hassle 63 * Since loff_t is a 64 bit type we avoid a lot of ABI hassle
127 * with a different argument ordering. 64 * with a different argument ordering.