From 28d353d9891c28496e366bebe4e65233f59ad1f6 Mon Sep 17 00:00:00 2001 From: Al Viro Date: Sun, 19 Aug 2012 14:41:00 +1200 Subject: alpha: take kernel_execve() out of entry.S Signed-off-by: Al Viro Signed-off-by: Michael Cree Acked-by: Matt Turner Signed-off-by: Linus Torvalds --- arch/alpha/kernel/process.c | 19 +++++++++++++++++++ 1 file changed, 19 insertions(+) (limited to 'arch/alpha/kernel/process.c') diff --git a/arch/alpha/kernel/process.c b/arch/alpha/kernel/process.c index 153d3fce3e8..d6fde98b74b 100644 --- a/arch/alpha/kernel/process.c +++ b/arch/alpha/kernel/process.c @@ -455,3 +455,22 @@ get_wchan(struct task_struct *p) } return pc; } + +int kernel_execve(const char *path, const char *const argv[], const char *const envp[]) +{ + /* Avoid the HAE being gratuitously wrong, which would cause us + to do the whole turn off interrupts thing and restore it. */ + struct pt_regs regs = {.hae = alpha_mv.hae_cache}; + int err = do_execve(path, argv, envp, ®s); + if (!err) { + struct pt_regs *p = current_pt_regs(); + /* copy regs to normal position and off to userland we go... */ + *p = regs; + __asm__ __volatile__ ( + "mov %0, $sp;" + "br $31, ret_from_sys_call" + : : "r"(p)); + } + return err; +} +EXPORT_SYMBOL(kernel_execve); -- cgit v1.2.3 From 6a6c0272f17cc80a8286d915f2ddf31557c2d559 Mon Sep 17 00:00:00 2001 From: Frederic Weisbecker Date: Thu, 23 Aug 2012 14:11:25 +0200 Subject: alpha: Fix preemption handling in idle loop cpu_idle() is called on the boot CPU by the init code with preemption disabled. But the cpu_idle() function in alpha doesn't handle this when it calls schedule() directly. Fix it by converting it into schedule_preempt_disabled(). Also disable preemption before calling cpu_idle() from secondary CPU entry code to stay consistent with this state. Signed-off-by: Frederic Weisbecker Tested-by: Michael Cree Cc: Richard Henderson Cc: Ivan Kokshaysky Cc: Matt Turner Cc: alpha Cc: Paul E. McKenney Reviewed-by: Josh Triplett --- arch/alpha/kernel/process.c | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) (limited to 'arch/alpha/kernel/process.c') diff --git a/arch/alpha/kernel/process.c b/arch/alpha/kernel/process.c index d6fde98b74b..db56f31dbf7 100644 --- a/arch/alpha/kernel/process.c +++ b/arch/alpha/kernel/process.c @@ -56,7 +56,8 @@ cpu_idle(void) while (!need_resched()) cpu_relax(); - schedule(); + + schedule_preempt_disabled(); } } -- cgit v1.2.3 From 4c94cada48f7c660eca582be6032427a5e367117 Mon Sep 17 00:00:00 2001 From: Frederic Weisbecker Date: Wed, 22 Aug 2012 17:27:34 +0200 Subject: alpha: Add missing RCU idle APIs on idle loop In the old times, the whole idle task was considered as an RCU quiescent state. But as RCU became more and more successful overtime, some RCU read side critical section have been added even in the code of some architectures idle tasks, for tracing for example. So nowadays, rcu_idle_enter() and rcu_idle_exit() must be called by the architecture to tell RCU about the part in the idle loop that doesn't make use of rcu read side critical sections, typically the part that puts the CPU in low power mode. This is necessary for RCU to find the quiescent states in idle in order to complete grace periods. Add this missing pair of calls in the Alpha's idle loop. Reported-by: Paul E. McKenney Signed-off-by: Frederic Weisbecker Tested-by: Michael Cree Cc: Richard Henderson Cc: Ivan Kokshaysky Cc: Matt Turner Cc: alpha Cc: Paul E. McKenney Cc: # 3.3+ Reviewed-by: Josh Triplett --- arch/alpha/kernel/process.c | 3 +++ 1 file changed, 3 insertions(+) (limited to 'arch/alpha/kernel/process.c') diff --git a/arch/alpha/kernel/process.c b/arch/alpha/kernel/process.c index db56f31dbf7..83638aa096d 100644 --- a/arch/alpha/kernel/process.c +++ b/arch/alpha/kernel/process.c @@ -28,6 +28,7 @@ #include #include #include +#include #include #include @@ -54,9 +55,11 @@ cpu_idle(void) /* FIXME -- EV6 and LCA45 know how to power down the CPU. */ + rcu_idle_enter(); while (!need_resched()) cpu_relax(); + rcu_idle_exit(); schedule_preempt_disabled(); } } -- cgit v1.2.3 From 756144f8ea2e4fccbbf1a5644f3e1e889a48f765 Mon Sep 17 00:00:00 2001 From: Al Viro Date: Thu, 2 Aug 2012 12:53:03 +0400 Subject: alpha: switch to generic sys_execve() get rid of sys_execve() wrapper, while we are at it Signed-off-by: Al Viro --- arch/alpha/kernel/process.c | 21 --------------------- 1 file changed, 21 deletions(-) (limited to 'arch/alpha/kernel/process.c') diff --git a/arch/alpha/kernel/process.c b/arch/alpha/kernel/process.c index d6fde98b74b..14547390919 100644 --- a/arch/alpha/kernel/process.c +++ b/arch/alpha/kernel/process.c @@ -381,27 +381,6 @@ dump_elf_task_fp(elf_fpreg_t *dest, struct task_struct *task) } EXPORT_SYMBOL(dump_elf_task_fp); -/* - * sys_execve() executes a new program. - */ -asmlinkage int -do_sys_execve(const char __user *ufilename, - const char __user *const __user *argv, - const char __user *const __user *envp, struct pt_regs *regs) -{ - int error; - char *filename; - - filename = getname(ufilename); - error = PTR_ERR(filename); - if (IS_ERR(filename)) - goto out; - error = do_execve(filename, argv, envp, regs); - putname(filename); -out: - return error; -} - /* * Return saved PC of a blocked thread. This assumes the frame * pointer is the 6th saved long on the kernel stack and that the -- cgit v1.2.3 From cba1ec7e88a0257eb13e84d170a93cd52b702562 Mon Sep 17 00:00:00 2001 From: Al Viro Date: Sun, 9 Sep 2012 22:03:42 -0400 Subject: alpha: switch to generic kernel_thread() Signed-off-by: Al Viro --- arch/alpha/kernel/process.c | 39 ++++++++++++++++++++------------------- 1 file changed, 20 insertions(+), 19 deletions(-) (limited to 'arch/alpha/kernel/process.c') diff --git a/arch/alpha/kernel/process.c b/arch/alpha/kernel/process.c index 14547390919..6b33ecdbc53 100644 --- a/arch/alpha/kernel/process.c +++ b/arch/alpha/kernel/process.c @@ -259,33 +259,35 @@ alpha_vfork(struct pt_regs *regs) /* * Copy an alpha thread.. - * - * Note the "stack_offset" stuff: when returning to kernel mode, we need - * to have some extra stack-space for the kernel stack that still exists - * after the "ret_from_fork". When returning to user mode, we only want - * the space needed by the syscall stack frame (ie "struct pt_regs"). - * Use the passed "regs" pointer to determine how much space we need - * for a kernel fork(). */ int copy_thread(unsigned long clone_flags, unsigned long usp, - unsigned long unused, + unsigned long arg, struct task_struct * p, struct pt_regs * regs) { extern void ret_from_fork(void); + extern void ret_from_kernel_thread(void); struct thread_info *childti = task_thread_info(p); - struct pt_regs * childregs; - struct switch_stack * childstack, *stack; - unsigned long stack_offset, settls; - - stack_offset = PAGE_SIZE - sizeof(struct pt_regs); - if (!(regs->ps & 8)) - stack_offset = (PAGE_SIZE-1) & (unsigned long) regs; - childregs = (struct pt_regs *) - (stack_offset + PAGE_SIZE + task_stack_page(p)); - + struct pt_regs *childregs = task_pt_regs(p); + struct switch_stack *childstack, *stack; + unsigned long settls; + + childstack = ((struct switch_stack *) childregs) - 1; + if (unlikely(!regs)) { + /* kernel thread */ + memset(childstack, 0, + sizeof(struct switch_stack) + sizeof(struct pt_regs)); + childstack->r26 = (unsigned long) ret_from_kernel_thread; + childstack->r9 = usp; /* function */ + childstack->r10 = arg; + childregs->hae = alpha_mv.hae_cache, + childti->pcb.usp = 0; + childti->pcb.ksp = (unsigned long) childstack; + childti->pcb.flags = 1; /* set FEN, clear everything else */ + return 0; + } *childregs = *regs; settls = regs->r20; childregs->r0 = 0; @@ -293,7 +295,6 @@ copy_thread(unsigned long clone_flags, unsigned long usp, childregs->r20 = 1; /* OSF/1 has some strange fork() semantics. */ regs->r20 = 0; stack = ((struct switch_stack *) regs) - 1; - childstack = ((struct switch_stack *) childregs) - 1; *childstack = *stack; childstack->r26 = (unsigned long) ret_from_fork; childti->pcb.usp = usp; -- cgit v1.2.3 From 44f4b56b54d2ab5d06c1726f2cde8ca15c8fac47 Mon Sep 17 00:00:00 2001 From: Al Viro Date: Thu, 31 May 2012 22:22:52 -0400 Subject: alpha: introduce ret_from_kernel_execve(), switch to generic kernel_execve() Signed-off-by: Al Viro --- arch/alpha/kernel/process.c | 19 ------------------- 1 file changed, 19 deletions(-) (limited to 'arch/alpha/kernel/process.c') diff --git a/arch/alpha/kernel/process.c b/arch/alpha/kernel/process.c index 6b33ecdbc53..f47d764eaa1 100644 --- a/arch/alpha/kernel/process.c +++ b/arch/alpha/kernel/process.c @@ -435,22 +435,3 @@ get_wchan(struct task_struct *p) } return pc; } - -int kernel_execve(const char *path, const char *const argv[], const char *const envp[]) -{ - /* Avoid the HAE being gratuitously wrong, which would cause us - to do the whole turn off interrupts thing and restore it. */ - struct pt_regs regs = {.hae = alpha_mv.hae_cache}; - int err = do_execve(path, argv, envp, ®s); - if (!err) { - struct pt_regs *p = current_pt_regs(); - /* copy regs to normal position and off to userland we go... */ - *p = regs; - __asm__ __volatile__ ( - "mov %0, $sp;" - "br $31, ret_from_sys_call" - : : "r"(p)); - } - return err; -} -EXPORT_SYMBOL(kernel_execve); -- cgit v1.2.3 From 3185bd26188223195dc2e659a3d00219cad71a0f Mon Sep 17 00:00:00 2001 From: Al Viro Date: Sat, 20 Oct 2012 15:52:23 +0100 Subject: alpha: separate thread-synchronous flags ... and fix the race in updating unaligned control ones Signed-off-by: Al Viro Signed-off-by: Linus Torvalds --- arch/alpha/kernel/process.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'arch/alpha/kernel/process.c') diff --git a/arch/alpha/kernel/process.c b/arch/alpha/kernel/process.c index 4054e0ffe2b..51987dcf79b 100644 --- a/arch/alpha/kernel/process.c +++ b/arch/alpha/kernel/process.c @@ -49,7 +49,7 @@ EXPORT_SYMBOL(pm_power_off); void cpu_idle(void) { - set_thread_flag(TIF_POLLING_NRFLAG); + current_thread_info()->status |= TS_POLLING; while (1) { /* FIXME -- EV6 and LCA45 know how to power down -- cgit v1.2.3 From e0e431aa45416982eb3fddf34cedc72f1c3b3ce3 Mon Sep 17 00:00:00 2001 From: Al Viro Date: Thu, 18 Oct 2012 01:11:58 -0400 Subject: alpha: simplify fork and friends * no need to restore everything from switch_stack when we only need $26 * no need to pass current_pt_regs() manually, we can just as easily calculate it in alpha_clone/alpha_vfork ($8 + constant) * interpretation of zero usp as "use the parent's" is simpler in copy_thread(); let fork and vfork just pass 0. Signed-off-by: Al Viro --- arch/alpha/kernel/process.c | 16 +++++++--------- 1 file changed, 7 insertions(+), 9 deletions(-) (limited to 'arch/alpha/kernel/process.c') diff --git a/arch/alpha/kernel/process.c b/arch/alpha/kernel/process.c index 51987dcf79b..ad86c099b6f 100644 --- a/arch/alpha/kernel/process.c +++ b/arch/alpha/kernel/process.c @@ -246,19 +246,17 @@ release_thread(struct task_struct *dead_task) int alpha_clone(unsigned long clone_flags, unsigned long usp, int __user *parent_tid, int __user *child_tid, - unsigned long tls_value, struct pt_regs *regs) + unsigned long tls_value) { - if (!usp) - usp = rdusp(); - - return do_fork(clone_flags, usp, regs, 0, parent_tid, child_tid); + return do_fork(clone_flags, usp, current_pt_regs(), 0, + parent_tid, child_tid); } int -alpha_vfork(struct pt_regs *regs) +alpha_vfork(void) { - return do_fork(CLONE_VFORK | CLONE_VM | SIGCHLD, rdusp(), - regs, 0, NULL, NULL); + return do_fork(CLONE_VFORK | CLONE_VM | SIGCHLD, 0, + current_pt_regs(), 0, NULL, NULL); } /* @@ -301,7 +299,7 @@ copy_thread(unsigned long clone_flags, unsigned long usp, stack = ((struct switch_stack *) regs) - 1; *childstack = *stack; childstack->r26 = (unsigned long) ret_from_fork; - childti->pcb.usp = usp; + childti->pcb.usp = usp ?: rdusp(); childti->pcb.ksp = (unsigned long) childstack; childti->pcb.flags = 1; /* set FEN, clear everything else */ -- cgit v1.2.3 From 25906730ec01be664534c9439d7cf5a373e8a4e4 Mon Sep 17 00:00:00 2001 From: Al Viro Date: Sun, 21 Oct 2012 15:52:04 -0400 Subject: alpha: reorganize copy_process(), prepare to saner fork_idle() Signed-off-by: Al Viro --- arch/alpha/kernel/process.c | 35 ++++++++++++++--------------------- 1 file changed, 14 insertions(+), 21 deletions(-) (limited to 'arch/alpha/kernel/process.c') diff --git a/arch/alpha/kernel/process.c b/arch/alpha/kernel/process.c index ad86c099b6f..a4dc79ba030 100644 --- a/arch/alpha/kernel/process.c +++ b/arch/alpha/kernel/process.c @@ -266,18 +266,22 @@ alpha_vfork(void) int copy_thread(unsigned long clone_flags, unsigned long usp, unsigned long arg, - struct task_struct * p, struct pt_regs * regs) + struct task_struct *p, struct pt_regs *wontuse) { extern void ret_from_fork(void); extern void ret_from_kernel_thread(void); struct thread_info *childti = task_thread_info(p); struct pt_regs *childregs = task_pt_regs(p); + struct pt_regs *regs = current_pt_regs(); struct switch_stack *childstack, *stack; unsigned long settls; childstack = ((struct switch_stack *) childregs) - 1; - if (unlikely(!regs)) { + childti->pcb.ksp = (unsigned long) childstack; + childti->pcb.flags = 1; /* set FEN, clear everything else */ + + if (unlikely(p->flags & PF_KTHREAD)) { /* kernel thread */ memset(childstack, 0, sizeof(struct switch_stack) + sizeof(struct pt_regs)); @@ -286,12 +290,17 @@ copy_thread(unsigned long clone_flags, unsigned long usp, childstack->r10 = arg; childregs->hae = alpha_mv.hae_cache, childti->pcb.usp = 0; - childti->pcb.ksp = (unsigned long) childstack; - childti->pcb.flags = 1; /* set FEN, clear everything else */ return 0; } + /* Note: if CLONE_SETTLS is not set, then we must inherit the + value from the parent, which will have been set by the block + copy in dup_task_struct. This is non-intuitive, but is + required for proper operation in the case of a threaded + application calling fork. */ + if (clone_flags & CLONE_SETTLS) + childti->pcb.unique = regs->r20; + childti->pcb.usp = usp ?: rdusp(); *childregs = *regs; - settls = regs->r20; childregs->r0 = 0; childregs->r19 = 0; childregs->r20 = 1; /* OSF/1 has some strange fork() semantics. */ @@ -299,22 +308,6 @@ copy_thread(unsigned long clone_flags, unsigned long usp, stack = ((struct switch_stack *) regs) - 1; *childstack = *stack; childstack->r26 = (unsigned long) ret_from_fork; - childti->pcb.usp = usp ?: rdusp(); - childti->pcb.ksp = (unsigned long) childstack; - childti->pcb.flags = 1; /* set FEN, clear everything else */ - - /* Set a new TLS for the child thread? Peek back into the - syscall arguments that we saved on syscall entry. Oops, - except we'd have clobbered it with the parent/child set - of r20. Read the saved copy. */ - /* Note: if CLONE_SETTLS is not set, then we must inherit the - value from the parent, which will have been set by the block - copy in dup_task_struct. This is non-intuitive, but is - required for proper operation in the case of a threaded - application calling fork. */ - if (clone_flags & CLONE_SETTLS) - childti->pcb.unique = settls; - return 0; } -- cgit v1.2.3 From dfe09ae0e5fe40679af05b1ba810d469844c97b3 Mon Sep 17 00:00:00 2001 From: Al Viro Date: Fri, 26 Oct 2012 09:54:47 -0400 Subject: alpha: switch to generic fork/vfork/clone Signed-off-by: Al Viro --- arch/alpha/kernel/process.c | 25 ------------------------- 1 file changed, 25 deletions(-) (limited to 'arch/alpha/kernel/process.c') diff --git a/arch/alpha/kernel/process.c b/arch/alpha/kernel/process.c index a4dc79ba030..e9705bcc96f 100644 --- a/arch/alpha/kernel/process.c +++ b/arch/alpha/kernel/process.c @@ -234,31 +234,6 @@ release_thread(struct task_struct *dead_task) { } -/* - * "alpha_clone()".. By the time we get here, the - * non-volatile registers have also been saved on the - * stack. We do some ugly pointer stuff here.. (see - * also copy_thread) - * - * Notice that "fork()" is implemented in terms of clone, - * with parameters (SIGCHLD, 0). - */ -int -alpha_clone(unsigned long clone_flags, unsigned long usp, - int __user *parent_tid, int __user *child_tid, - unsigned long tls_value) -{ - return do_fork(clone_flags, usp, current_pt_regs(), 0, - parent_tid, child_tid); -} - -int -alpha_vfork(void) -{ - return do_fork(CLONE_VFORK | CLONE_VM | SIGCHLD, 0, - current_pt_regs(), 0, NULL, NULL); -} - /* * Copy an alpha thread.. */ -- cgit v1.2.3 From afa86fc426ff7e7f5477f15da9c405d08d5cf790 Mon Sep 17 00:00:00 2001 From: Al Viro Date: Mon, 22 Oct 2012 22:51:14 -0400 Subject: flagday: don't pass regs to copy_thread() Signed-off-by: Al Viro --- arch/alpha/kernel/process.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'arch/alpha/kernel/process.c') diff --git a/arch/alpha/kernel/process.c b/arch/alpha/kernel/process.c index e9705bcc96f..b5d0d092369 100644 --- a/arch/alpha/kernel/process.c +++ b/arch/alpha/kernel/process.c @@ -241,7 +241,7 @@ release_thread(struct task_struct *dead_task) int copy_thread(unsigned long clone_flags, unsigned long usp, unsigned long arg, - struct task_struct *p, struct pt_regs *wontuse) + struct task_struct *p) { extern void ret_from_fork(void); extern void ret_from_kernel_thread(void); -- cgit v1.2.3