aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--arch/alpha/kernel/process.c35
1 files changed, 14 insertions, 21 deletions
diff --git a/arch/alpha/kernel/process.c b/arch/alpha/kernel/process.c
index ad86c099b6f5..a4dc79ba030f 100644
--- a/arch/alpha/kernel/process.c
+++ b/arch/alpha/kernel/process.c
@@ -266,18 +266,22 @@ alpha_vfork(void)
266int 266int
267copy_thread(unsigned long clone_flags, unsigned long usp, 267copy_thread(unsigned long clone_flags, unsigned long usp,
268 unsigned long arg, 268 unsigned long arg,
269 struct task_struct * p, struct pt_regs * regs) 269 struct task_struct *p, struct pt_regs *wontuse)
270{ 270{
271 extern void ret_from_fork(void); 271 extern void ret_from_fork(void);
272 extern void ret_from_kernel_thread(void); 272 extern void ret_from_kernel_thread(void);
273 273
274 struct thread_info *childti = task_thread_info(p); 274 struct thread_info *childti = task_thread_info(p);
275 struct pt_regs *childregs = task_pt_regs(p); 275 struct pt_regs *childregs = task_pt_regs(p);
276 struct pt_regs *regs = current_pt_regs();
276 struct switch_stack *childstack, *stack; 277 struct switch_stack *childstack, *stack;
277 unsigned long settls; 278 unsigned long settls;
278 279
279 childstack = ((struct switch_stack *) childregs) - 1; 280 childstack = ((struct switch_stack *) childregs) - 1;
280 if (unlikely(!regs)) { 281 childti->pcb.ksp = (unsigned long) childstack;
282 childti->pcb.flags = 1; /* set FEN, clear everything else */
283
284 if (unlikely(p->flags & PF_KTHREAD)) {
281 /* kernel thread */ 285 /* kernel thread */
282 memset(childstack, 0, 286 memset(childstack, 0,
283 sizeof(struct switch_stack) + sizeof(struct pt_regs)); 287 sizeof(struct switch_stack) + sizeof(struct pt_regs));
@@ -286,12 +290,17 @@ copy_thread(unsigned long clone_flags, unsigned long usp,
286 childstack->r10 = arg; 290 childstack->r10 = arg;
287 childregs->hae = alpha_mv.hae_cache, 291 childregs->hae = alpha_mv.hae_cache,
288 childti->pcb.usp = 0; 292 childti->pcb.usp = 0;
289 childti->pcb.ksp = (unsigned long) childstack;
290 childti->pcb.flags = 1; /* set FEN, clear everything else */
291 return 0; 293 return 0;
292 } 294 }
295 /* Note: if CLONE_SETTLS is not set, then we must inherit the
296 value from the parent, which will have been set by the block
297 copy in dup_task_struct. This is non-intuitive, but is
298 required for proper operation in the case of a threaded
299 application calling fork. */
300 if (clone_flags & CLONE_SETTLS)
301 childti->pcb.unique = regs->r20;
302 childti->pcb.usp = usp ?: rdusp();
293 *childregs = *regs; 303 *childregs = *regs;
294 settls = regs->r20;
295 childregs->r0 = 0; 304 childregs->r0 = 0;
296 childregs->r19 = 0; 305 childregs->r19 = 0;
297 childregs->r20 = 1; /* OSF/1 has some strange fork() semantics. */ 306 childregs->r20 = 1; /* OSF/1 has some strange fork() semantics. */
@@ -299,22 +308,6 @@ copy_thread(unsigned long clone_flags, unsigned long usp,
299 stack = ((struct switch_stack *) regs) - 1; 308 stack = ((struct switch_stack *) regs) - 1;
300 *childstack = *stack; 309 *childstack = *stack;
301 childstack->r26 = (unsigned long) ret_from_fork; 310 childstack->r26 = (unsigned long) ret_from_fork;
302 childti->pcb.usp = usp ?: rdusp();
303 childti->pcb.ksp = (unsigned long) childstack;
304 childti->pcb.flags = 1; /* set FEN, clear everything else */
305
306 /* Set a new TLS for the child thread? Peek back into the
307 syscall arguments that we saved on syscall entry. Oops,
308 except we'd have clobbered it with the parent/child set
309 of r20. Read the saved copy. */
310 /* Note: if CLONE_SETTLS is not set, then we must inherit the
311 value from the parent, which will have been set by the block
312 copy in dup_task_struct. This is non-intuitive, but is
313 required for proper operation in the case of a threaded
314 application calling fork. */
315 if (clone_flags & CLONE_SETTLS)
316 childti->pcb.unique = settls;
317
318 return 0; 311 return 0;
319} 312}
320 313