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/kernel | |
| 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/kernel')
| -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 |
3 files changed, 38 insertions, 113 deletions
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); | ||
