|
@@ -259,33 +259,35 @@ alpha_vfork(struct pt_regs *regs)
|
|
|
|
|
|
/*
|
|
/*
|
|
* Copy an alpha thread..
|
|
* 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
|
|
int
|
|
copy_thread(unsigned long clone_flags, unsigned long usp,
|
|
copy_thread(unsigned long clone_flags, unsigned long usp,
|
|
- unsigned long unused,
|
|
|
|
|
|
+ unsigned long arg,
|
|
struct task_struct * p, struct pt_regs * regs)
|
|
struct task_struct * p, struct pt_regs * regs)
|
|
{
|
|
{
|
|
extern void ret_from_fork(void);
|
|
extern void ret_from_fork(void);
|
|
|
|
+ extern void ret_from_kernel_thread(void);
|
|
|
|
|
|
struct thread_info *childti = task_thread_info(p);
|
|
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;
|
|
*childregs = *regs;
|
|
settls = regs->r20;
|
|
settls = regs->r20;
|
|
childregs->r0 = 0;
|
|
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. */
|
|
childregs->r20 = 1; /* OSF/1 has some strange fork() semantics. */
|
|
regs->r20 = 0;
|
|
regs->r20 = 0;
|
|
stack = ((struct switch_stack *) regs) - 1;
|
|
stack = ((struct switch_stack *) regs) - 1;
|
|
- childstack = ((struct switch_stack *) childregs) - 1;
|
|
|
|
*childstack = *stack;
|
|
*childstack = *stack;
|
|
childstack->r26 = (unsigned long) ret_from_fork;
|
|
childstack->r26 = (unsigned long) ret_from_fork;
|
|
childti->pcb.usp = usp;
|
|
childti->pcb.usp = usp;
|