aboutsummaryrefslogtreecommitdiffstats
path: root/arch/alpha
diff options
context:
space:
mode:
authorLinus Torvalds <torvalds@linux-foundation.org>2012-10-09 23:02:25 -0400
committerLinus Torvalds <torvalds@linux-foundation.org>2012-10-09 23:02:25 -0400
commit42859eea96ba6beabfb0369a1eeffa3c7d2bd9cb (patch)
treefa38aeda0d6e7a4c48a882b166b8643594a1ad50 /arch/alpha
parentf59b51fe3d3092c08d7d554ecb40db24011b2ebc (diff)
parentf322220d6159455da2b5a8a596d802c8695fed30 (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/Kconfig1
-rw-r--r--arch/alpha/include/asm/Kbuild1
-rw-r--r--arch/alpha/include/asm/exec.h6
-rw-r--r--arch/alpha/include/asm/processor.h3
-rw-r--r--arch/alpha/include/asm/unistd.h2
-rw-r--r--arch/alpha/kernel/alpha_ksyms.c3
-rw-r--r--arch/alpha/kernel/entry.S69
-rw-r--r--arch/alpha/kernel/process.c79
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
10header-y += reg.h 10header-y += reg.h
11header-y += regdef.h 11header-y += regdef.h
12header-y += sysinfo.h 12header-y += sysinfo.h
13generic-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. */
50extern void release_thread(struct task_struct *); 50extern void release_thread(struct task_struct *);
51 51
52/* Create a kernel thread without removing it from tasklists. */
53extern long kernel_thread(int (*fn)(void *), void *arg, unsigned long flags);
54
55unsigned long get_wchan(struct task_struct *p); 52unsigned 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);
50EXPORT_SYMBOL(alpha_write_fp_reg); 50EXPORT_SYMBOL(alpha_write_fp_reg);
51EXPORT_SYMBOL(alpha_write_fp_reg_s); 51EXPORT_SYMBOL(alpha_write_fp_reg_s);
52 52
53/* entry.S */
54EXPORT_SYMBOL(kernel_thread);
55
56/* Networking helper routines. */ 53/* Networking helper routines. */
57EXPORT_SYMBOL(csum_tcpudp_magic); 54EXPORT_SYMBOL(csum_tcpudp_magic);
58EXPORT_SYMBOL(ip_compute_csum); 55EXPORT_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
617kernel_thread: 617ret_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
6371: ret /* in parent. */ 629 .globl ret_from_kernel_execve
638 630 .align 4
639 .align 4 631 .ent ret_from_kernel_execve
6402: /* Fake a system call stack frame, as we can't do system calls 632ret_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
750sys_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
759alpha_ni_syscall: 726alpha_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
275int 268int
276copy_thread(unsigned long clone_flags, unsigned long usp, 269copy_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)
386EXPORT_SYMBOL(dump_elf_task_fp); 387EXPORT_SYMBOL(dump_elf_task_fp);
387 388
388/* 389/*
389 * sys_execve() executes a new program.
390 */
391asmlinkage int
392do_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);
405out:
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
463int 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, &regs);
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}
480EXPORT_SYMBOL(kernel_execve);