diff options
author | Linus Torvalds <torvalds@linux-foundation.org> | 2012-10-09 23:02:25 -0400 |
---|---|---|
committer | Linus Torvalds <torvalds@linux-foundation.org> | 2012-10-09 23:02:25 -0400 |
commit | 42859eea96ba6beabfb0369a1eeffa3c7d2bd9cb (patch) | |
tree | fa38aeda0d6e7a4c48a882b166b8643594a1ad50 /arch/alpha | |
parent | f59b51fe3d3092c08d7d554ecb40db24011b2ebc (diff) | |
parent | f322220d6159455da2b5a8a596d802c8695fed30 (diff) |
Merge branch 'for-linus' of git://git.kernel.org/pub/scm/linux/kernel/git/viro/signal
Pull generic execve() changes from Al Viro:
"This introduces the generic kernel_thread() and kernel_execve()
functions, and switches x86, arm, alpha, um and s390 over to them."
* 'for-linus' of git://git.kernel.org/pub/scm/linux/kernel/git/viro/signal: (26 commits)
s390: convert to generic kernel_execve()
s390: switch to generic kernel_thread()
s390: fold kernel_thread_helper() into ret_from_fork()
s390: fold execve_tail() into start_thread(), convert to generic sys_execve()
um: switch to generic kernel_thread()
x86, um/x86: switch to generic sys_execve and kernel_execve
x86: split ret_from_fork
alpha: introduce ret_from_kernel_execve(), switch to generic kernel_execve()
alpha: switch to generic kernel_thread()
alpha: switch to generic sys_execve()
arm: get rid of execve wrapper, switch to generic execve() implementation
arm: optimized current_pt_regs()
arm: introduce ret_from_kernel_execve(), switch to generic kernel_execve()
arm: split ret_from_fork, simplify kernel_thread() [based on patch by rmk]
generic sys_execve()
generic kernel_execve()
new helper: current_pt_regs()
preparation for generic kernel_thread()
um: kill thread->forking
um: let signal_delivered() do SIGTRAP on singlestepping into handler
...
Diffstat (limited to 'arch/alpha')
-rw-r--r-- | arch/alpha/Kconfig | 1 | ||||
-rw-r--r-- | arch/alpha/include/asm/Kbuild | 1 | ||||
-rw-r--r-- | arch/alpha/include/asm/exec.h | 6 | ||||
-rw-r--r-- | arch/alpha/include/asm/processor.h | 3 | ||||
-rw-r--r-- | arch/alpha/include/asm/unistd.h | 2 | ||||
-rw-r--r-- | arch/alpha/kernel/alpha_ksyms.c | 3 | ||||
-rw-r--r-- | arch/alpha/kernel/entry.S | 69 | ||||
-rw-r--r-- | arch/alpha/kernel/process.c | 79 |
8 files changed, 42 insertions, 122 deletions
diff --git a/arch/alpha/Kconfig b/arch/alpha/Kconfig index 9944dedee5b1..7da91246e279 100644 --- a/arch/alpha/Kconfig +++ b/arch/alpha/Kconfig | |||
@@ -20,6 +20,7 @@ config ALPHA | |||
20 | select GENERIC_CMOS_UPDATE | 20 | select GENERIC_CMOS_UPDATE |
21 | select GENERIC_STRNCPY_FROM_USER | 21 | select GENERIC_STRNCPY_FROM_USER |
22 | select GENERIC_STRNLEN_USER | 22 | select GENERIC_STRNLEN_USER |
23 | select GENERIC_KERNEL_THREAD | ||
23 | help | 24 | help |
24 | The Alpha is a 64-bit general-purpose processor designed and | 25 | The Alpha is a 64-bit general-purpose processor designed and |
25 | marketed by the Digital Equipment Corporation of blessed memory, | 26 | marketed by the Digital Equipment Corporation of blessed memory, |
diff --git a/arch/alpha/include/asm/Kbuild b/arch/alpha/include/asm/Kbuild index d97d66334e6f..64ffc9e9e548 100644 --- a/arch/alpha/include/asm/Kbuild +++ b/arch/alpha/include/asm/Kbuild | |||
@@ -10,3 +10,4 @@ header-y += pal.h | |||
10 | header-y += reg.h | 10 | header-y += reg.h |
11 | header-y += regdef.h | 11 | header-y += regdef.h |
12 | header-y += sysinfo.h | 12 | header-y += sysinfo.h |
13 | generic-y += exec.h | ||
diff --git a/arch/alpha/include/asm/exec.h b/arch/alpha/include/asm/exec.h deleted file mode 100644 index 4a5a41f30779..000000000000 --- a/arch/alpha/include/asm/exec.h +++ /dev/null | |||
@@ -1,6 +0,0 @@ | |||
1 | #ifndef __ALPHA_EXEC_H | ||
2 | #define __ALPHA_EXEC_H | ||
3 | |||
4 | #define arch_align_stack(x) (x) | ||
5 | |||
6 | #endif /* __ALPHA_EXEC_H */ | ||
diff --git a/arch/alpha/include/asm/processor.h b/arch/alpha/include/asm/processor.h index e37b887b3d9f..6cb7fe85c4b5 100644 --- a/arch/alpha/include/asm/processor.h +++ b/arch/alpha/include/asm/processor.h | |||
@@ -49,9 +49,6 @@ extern void start_thread(struct pt_regs *, unsigned long, unsigned long); | |||
49 | /* Free all resources held by a thread. */ | 49 | /* Free all resources held by a thread. */ |
50 | extern void release_thread(struct task_struct *); | 50 | extern void release_thread(struct task_struct *); |
51 | 51 | ||
52 | /* Create a kernel thread without removing it from tasklists. */ | ||
53 | extern long kernel_thread(int (*fn)(void *), void *arg, unsigned long flags); | ||
54 | |||
55 | unsigned long get_wchan(struct task_struct *p); | 52 | unsigned long get_wchan(struct task_struct *p); |
56 | 53 | ||
57 | #define KSTK_EIP(tsk) (task_pt_regs(tsk)->pc) | 54 | #define KSTK_EIP(tsk) (task_pt_regs(tsk)->pc) |
diff --git a/arch/alpha/include/asm/unistd.h b/arch/alpha/include/asm/unistd.h index a31a78eac9b9..3cb6c1188984 100644 --- a/arch/alpha/include/asm/unistd.h +++ b/arch/alpha/include/asm/unistd.h | |||
@@ -481,6 +481,8 @@ | |||
481 | #define __ARCH_WANT_SYS_OLDUMOUNT | 481 | #define __ARCH_WANT_SYS_OLDUMOUNT |
482 | #define __ARCH_WANT_SYS_SIGPENDING | 482 | #define __ARCH_WANT_SYS_SIGPENDING |
483 | #define __ARCH_WANT_SYS_RT_SIGSUSPEND | 483 | #define __ARCH_WANT_SYS_RT_SIGSUSPEND |
484 | #define __ARCH_WANT_SYS_EXECVE | ||
485 | #define __ARCH_WANT_KERNEL_EXECVE | ||
484 | 486 | ||
485 | /* "Conditional" syscalls. What we want is | 487 | /* "Conditional" syscalls. What we want is |
486 | 488 | ||
diff --git a/arch/alpha/kernel/alpha_ksyms.c b/arch/alpha/kernel/alpha_ksyms.c index 15fa821d09cd..89566b346c0f 100644 --- a/arch/alpha/kernel/alpha_ksyms.c +++ b/arch/alpha/kernel/alpha_ksyms.c | |||
@@ -50,9 +50,6 @@ EXPORT_SYMBOL(alpha_read_fp_reg_s); | |||
50 | EXPORT_SYMBOL(alpha_write_fp_reg); | 50 | EXPORT_SYMBOL(alpha_write_fp_reg); |
51 | EXPORT_SYMBOL(alpha_write_fp_reg_s); | 51 | EXPORT_SYMBOL(alpha_write_fp_reg_s); |
52 | 52 | ||
53 | /* entry.S */ | ||
54 | EXPORT_SYMBOL(kernel_thread); | ||
55 | |||
56 | /* Networking helper routines. */ | 53 | /* Networking helper routines. */ |
57 | EXPORT_SYMBOL(csum_tcpudp_magic); | 54 | EXPORT_SYMBOL(csum_tcpudp_magic); |
58 | EXPORT_SYMBOL(ip_compute_csum); | 55 | EXPORT_SYMBOL(ip_compute_csum); |
diff --git a/arch/alpha/kernel/entry.S b/arch/alpha/kernel/entry.S index ec0da0567ab5..7e43e1156d10 100644 --- a/arch/alpha/kernel/entry.S +++ b/arch/alpha/kernel/entry.S | |||
@@ -609,59 +609,35 @@ ret_from_fork: | |||
609 | .end ret_from_fork | 609 | .end ret_from_fork |
610 | 610 | ||
611 | /* | 611 | /* |
612 | * kernel_thread(fn, arg, clone_flags) | 612 | * ... and new kernel threads - here |
613 | */ | 613 | */ |
614 | .align 4 | 614 | .align 4 |
615 | .globl kernel_thread | 615 | .globl ret_from_kernel_thread |
616 | .ent kernel_thread | 616 | .ent ret_from_kernel_thread |
617 | kernel_thread: | 617 | ret_from_kernel_thread: |
618 | /* We can be called from a module. */ | 618 | mov $17, $16 |
619 | ldgp $gp, 0($27) | 619 | jsr $26, schedule_tail |
620 | .prologue 1 | 620 | mov $9, $27 |
621 | subq $sp, SP_OFF+6*8, $sp | 621 | mov $10, $16 |
622 | br $1, 2f /* load start address */ | 622 | jsr $26, ($9) |
623 | |||
624 | /* We've now "returned" from a fake system call. */ | ||
625 | unop | ||
626 | blt $0, 1f /* error? */ | ||
627 | ldi $1, 0x3fff | ||
628 | beq $20, 1f /* parent or child? */ | ||
629 | |||
630 | bic $sp, $1, $8 /* in child. */ | ||
631 | jsr $26, ($27) | ||
632 | ldgp $gp, 0($26) | 623 | ldgp $gp, 0($26) |
633 | mov $0, $16 | 624 | mov $0, $16 |
634 | mov $31, $26 | 625 | mov $31, $26 |
635 | jmp $31, sys_exit | 626 | jmp $31, sys_exit |
627 | .end ret_from_kernel_thread | ||
636 | 628 | ||
637 | 1: ret /* in parent. */ | 629 | .globl ret_from_kernel_execve |
638 | 630 | .align 4 | |
639 | .align 4 | 631 | .ent ret_from_kernel_execve |
640 | 2: /* Fake a system call stack frame, as we can't do system calls | 632 | ret_from_kernel_execve: |
641 | from kernel space. Note that we store FN and ARG as they | 633 | mov $16, $sp |
642 | need to be set up in the child for the call. Also store $8 | ||
643 | and $26 for use in the parent. */ | ||
644 | stq $31, SP_OFF($sp) /* ps */ | ||
645 | stq $1, SP_OFF+8($sp) /* pc */ | ||
646 | stq $gp, SP_OFF+16($sp) /* gp */ | ||
647 | stq $16, 136($sp) /* $27; FN for child */ | ||
648 | stq $17, SP_OFF+24($sp) /* $16; ARG for child */ | ||
649 | stq $8, 64($sp) /* $8 */ | ||
650 | stq $26, 128($sp) /* $26 */ | ||
651 | /* Avoid the HAE being gratuitously wrong, to avoid restoring it. */ | 634 | /* Avoid the HAE being gratuitously wrong, to avoid restoring it. */ |
652 | ldq $2, alpha_mv+HAE_CACHE | 635 | ldq $2, alpha_mv+HAE_CACHE |
653 | stq $2, 152($sp) /* HAE */ | 636 | stq $2, 152($sp) /* HAE */ |
637 | mov $31, $19 /* to disable syscall restarts */ | ||
638 | br $31, ret_to_user | ||
654 | 639 | ||
655 | /* Shuffle FLAGS to the front; add CLONE_VM. */ | 640 | .end ret_from_kernel_execve |
656 | ldi $1, CLONE_VM|CLONE_UNTRACED | ||
657 | or $18, $1, $16 | ||
658 | bsr $26, sys_clone | ||
659 | |||
660 | /* We don't actually care for a3 success widgetry in the kernel. | ||
661 | Not for positive errno values. */ | ||
662 | stq $0, 0($sp) /* $0 */ | ||
663 | br ret_to_kernel | ||
664 | .end kernel_thread | ||
665 | 641 | ||
666 | 642 | ||
667 | /* | 643 | /* |
@@ -745,15 +721,6 @@ sys_rt_sigreturn: | |||
745 | .end sys_rt_sigreturn | 721 | .end sys_rt_sigreturn |
746 | 722 | ||
747 | .align 4 | 723 | .align 4 |
748 | .globl sys_execve | ||
749 | .ent sys_execve | ||
750 | sys_execve: | ||
751 | .prologue 0 | ||
752 | mov $sp, $19 | ||
753 | jmp $31, do_sys_execve | ||
754 | .end sys_execve | ||
755 | |||
756 | .align 4 | ||
757 | .globl alpha_ni_syscall | 724 | .globl alpha_ni_syscall |
758 | .ent alpha_ni_syscall | 725 | .ent alpha_ni_syscall |
759 | alpha_ni_syscall: | 726 | alpha_ni_syscall: |
diff --git a/arch/alpha/kernel/process.c b/arch/alpha/kernel/process.c index 83638aa096d5..4054e0ffe2b2 100644 --- a/arch/alpha/kernel/process.c +++ b/arch/alpha/kernel/process.c | |||
@@ -263,33 +263,35 @@ alpha_vfork(struct pt_regs *regs) | |||
263 | 263 | ||
264 | /* | 264 | /* |
265 | * Copy an alpha thread.. | 265 | * Copy an alpha thread.. |
266 | * | ||
267 | * Note the "stack_offset" stuff: when returning to kernel mode, we need | ||
268 | * to have some extra stack-space for the kernel stack that still exists | ||
269 | * after the "ret_from_fork". When returning to user mode, we only want | ||
270 | * the space needed by the syscall stack frame (ie "struct pt_regs"). | ||
271 | * Use the passed "regs" pointer to determine how much space we need | ||
272 | * for a kernel fork(). | ||
273 | */ | 266 | */ |
274 | 267 | ||
275 | int | 268 | int |
276 | copy_thread(unsigned long clone_flags, unsigned long usp, | 269 | copy_thread(unsigned long clone_flags, unsigned long usp, |
277 | unsigned long unused, | 270 | unsigned long arg, |
278 | struct task_struct * p, struct pt_regs * regs) | 271 | struct task_struct * p, struct pt_regs * regs) |
279 | { | 272 | { |
280 | extern void ret_from_fork(void); | 273 | extern void ret_from_fork(void); |
274 | extern void ret_from_kernel_thread(void); | ||
281 | 275 | ||
282 | struct thread_info *childti = task_thread_info(p); | 276 | struct thread_info *childti = task_thread_info(p); |
283 | struct pt_regs * childregs; | 277 | struct pt_regs *childregs = task_pt_regs(p); |
284 | struct switch_stack * childstack, *stack; | 278 | struct switch_stack *childstack, *stack; |
285 | unsigned long stack_offset, settls; | 279 | unsigned long settls; |
286 | 280 | ||
287 | stack_offset = PAGE_SIZE - sizeof(struct pt_regs); | 281 | childstack = ((struct switch_stack *) childregs) - 1; |
288 | if (!(regs->ps & 8)) | 282 | if (unlikely(!regs)) { |
289 | stack_offset = (PAGE_SIZE-1) & (unsigned long) regs; | 283 | /* kernel thread */ |
290 | childregs = (struct pt_regs *) | 284 | memset(childstack, 0, |
291 | (stack_offset + PAGE_SIZE + task_stack_page(p)); | 285 | sizeof(struct switch_stack) + sizeof(struct pt_regs)); |
292 | 286 | childstack->r26 = (unsigned long) ret_from_kernel_thread; | |
287 | childstack->r9 = usp; /* function */ | ||
288 | childstack->r10 = arg; | ||
289 | childregs->hae = alpha_mv.hae_cache, | ||
290 | childti->pcb.usp = 0; | ||
291 | childti->pcb.ksp = (unsigned long) childstack; | ||
292 | childti->pcb.flags = 1; /* set FEN, clear everything else */ | ||
293 | return 0; | ||
294 | } | ||
293 | *childregs = *regs; | 295 | *childregs = *regs; |
294 | settls = regs->r20; | 296 | settls = regs->r20; |
295 | childregs->r0 = 0; | 297 | childregs->r0 = 0; |
@@ -297,7 +299,6 @@ copy_thread(unsigned long clone_flags, unsigned long usp, | |||
297 | childregs->r20 = 1; /* OSF/1 has some strange fork() semantics. */ | 299 | childregs->r20 = 1; /* OSF/1 has some strange fork() semantics. */ |
298 | regs->r20 = 0; | 300 | regs->r20 = 0; |
299 | stack = ((struct switch_stack *) regs) - 1; | 301 | stack = ((struct switch_stack *) regs) - 1; |
300 | childstack = ((struct switch_stack *) childregs) - 1; | ||
301 | *childstack = *stack; | 302 | *childstack = *stack; |
302 | childstack->r26 = (unsigned long) ret_from_fork; | 303 | childstack->r26 = (unsigned long) ret_from_fork; |
303 | childti->pcb.usp = usp; | 304 | childti->pcb.usp = usp; |
@@ -386,27 +387,6 @@ dump_elf_task_fp(elf_fpreg_t *dest, struct task_struct *task) | |||
386 | EXPORT_SYMBOL(dump_elf_task_fp); | 387 | EXPORT_SYMBOL(dump_elf_task_fp); |
387 | 388 | ||
388 | /* | 389 | /* |
389 | * sys_execve() executes a new program. | ||
390 | */ | ||
391 | asmlinkage int | ||
392 | do_sys_execve(const char __user *ufilename, | ||
393 | const char __user *const __user *argv, | ||
394 | const char __user *const __user *envp, struct pt_regs *regs) | ||
395 | { | ||
396 | int error; | ||
397 | char *filename; | ||
398 | |||
399 | filename = getname(ufilename); | ||
400 | error = PTR_ERR(filename); | ||
401 | if (IS_ERR(filename)) | ||
402 | goto out; | ||
403 | error = do_execve(filename, argv, envp, regs); | ||
404 | putname(filename); | ||
405 | out: | ||
406 | return error; | ||
407 | } | ||
408 | |||
409 | /* | ||
410 | * Return saved PC of a blocked thread. This assumes the frame | 390 | * Return saved PC of a blocked thread. This assumes the frame |
411 | * pointer is the 6th saved long on the kernel stack and that the | 391 | * pointer is the 6th saved long on the kernel stack and that the |
412 | * saved return address is the first long in the frame. This all | 392 | * saved return address is the first long in the frame. This all |
@@ -459,22 +439,3 @@ get_wchan(struct task_struct *p) | |||
459 | } | 439 | } |
460 | return pc; | 440 | return pc; |
461 | } | 441 | } |
462 | |||
463 | int kernel_execve(const char *path, const char *const argv[], const char *const envp[]) | ||
464 | { | ||
465 | /* Avoid the HAE being gratuitously wrong, which would cause us | ||
466 | to do the whole turn off interrupts thing and restore it. */ | ||
467 | struct pt_regs regs = {.hae = alpha_mv.hae_cache}; | ||
468 | int err = do_execve(path, argv, envp, ®s); | ||
469 | if (!err) { | ||
470 | struct pt_regs *p = current_pt_regs(); | ||
471 | /* copy regs to normal position and off to userland we go... */ | ||
472 | *p = regs; | ||
473 | __asm__ __volatile__ ( | ||
474 | "mov %0, $sp;" | ||
475 | "br $31, ret_from_sys_call" | ||
476 | : : "r"(p)); | ||
477 | } | ||
478 | return err; | ||
479 | } | ||
480 | EXPORT_SYMBOL(kernel_execve); | ||