kernels/linux-2.4.0/arch/ia64/kernel/process.c
/*
 * Copy the state of an ia-64 thread.
 *
 * We get here through the following  call chain:
 *
 *	<clone syscall>
 *	sys_clone
 *	do_fork
 *	copy_thread
 *
 * This means that the stack layout is as follows:
 *
 *	+---------------------+ (highest addr)
 *	|   struct pt_regs    |
 *	+---------------------+
 *	| struct switch_stack |
 *	+---------------------+
 *	|                     |
 *	|    memory stack     |
 *	|                     | <-- sp (lowest addr)
 *	+---------------------+
 *
 * Note: if we get called through kernel_thread() then the memory
 * above "(highest addr)" is valid kernel stack memory that needs to
 * be copied as well.
 *
 * Observe that we copy the unat values that are in pt_regs and
 * switch_stack.  Spilling an integer to address X causes bit N in
 * ar.unat to be set to the NaT bit of the register, with N=(X &
 * 0x1ff)/8.  Thus, copying the unat value preserves the NaT bits ONLY
 * if the pt_regs structure in the parent is congruent to that of the
 * child, modulo 512.  Since the stack is page aligned and the page
 * size is at least 4KB, this is always the case, so there is nothing
 * to worry about.
 */
Copy the state of an ia-64 thread.
We get here through the following  call chain.



This means that the stack layout is as follows.



if we get called through kernel_thread() then the memory
above "(highest addr)" is valid kernel stack memory that needs to
be copied as well.

Observe that we copy the unat values that are in pt_regs and
switch_stack.  Spilling an integer to address X causes bit N in
ar.unat to be set to the NaT bit of the register, with N=(X &
0x1ff)/8.  Thus, copying the unat value preserves the NaT bits ONLY
if the pt_regs structure in the parent is congruent to that of the
child, modulo 512.  Since the stack is page aligned and the page
size is at least 4KB, this is always the case, so there is nothing
to worry about.
Copy the state of an ia - 64 thread . We get here through the following call chain . This means that the stack layout is as follows . if we get called through kernel_thread () then the memory above " ( highest addr ) " is valid kernel stack memory that needs to be copied as well . Observe that we copy the unat values that are in pt_regs and switch_stack . Spilling an integer to address X causes bit N in ar . unat to be set to the NaT bit of the register with N = ( X & 0x1ff ) / 8 . Thus copying the unat value preserves the NaT bits ONLY if the pt_regs structure in the parent is congruent to that of the child modulo 512 . Since the stack is page aligned and the page size is at least 4KB this is always the case so there is nothing to worry about .
int
copy_thread (int nr, unsigned long clone_flags,
	     unsigned long user_stack_base, unsigned long user_stack_size,
	     struct task_struct *p, struct pt_regs *regs)
{
	unsigned long rbs, child_rbs, rbs_size, stack_offset, stack_top, stack_used;
	struct switch_stack *child_stack, *stack;
	extern char ia64_ret_from_clone;
	struct pt_regs *child_ptregs;
#ifdef CONFIG_SMP
	if (!regs)
		return 0;
#endif
	stack_top = (unsigned long) current + IA64_STK_OFFSET;
	stack = ((struct switch_stack *) regs) - 1;
	stack_used = stack_top - (unsigned long) stack;
	stack_offset = IA64_STK_OFFSET - stack_used;
	child_stack = (struct switch_stack *) ((unsigned long) p + stack_offset);
	child_ptregs = (struct pt_regs *) (child_stack + 1);
	memcpy(child_stack, stack, stack_used);
	rbs = (unsigned long) current + IA64_RBS_OFFSET;
	child_rbs = (unsigned long) p + IA64_RBS_OFFSET;
	rbs_size = stack->ar_bspstore - rbs;
	memcpy((void *) child_rbs, (void *) rbs, rbs_size);
	if (user_mode(child_ptregs)) {
		if (user_stack_base) {
			child_ptregs->r12 = user_stack_base + user_stack_size;
			child_ptregs->ar_bspstore = user_stack_base;
			child_ptregs->ar_rnat = 0;
			child_ptregs->loadrs = 0;
		}
	} else {
		child_ptregs->r12 = (unsigned long) (child_ptregs + 1); 
		child_ptregs->r13 = (unsigned long) p;		
	}
	child_stack->b0 = (unsigned long) &ia64_ret_from_clone;
	child_stack->ar_bspstore = child_rbs + rbs_size;
	p->thread.ksp = (unsigned long) child_stack - 16;
#	define THREAD_FLAGS_TO_CLEAR	(IA64_THREAD_FPH_VALID | IA64_THREAD_DBG_VALID \
					 | IA64_THREAD_PM_VALID)
#	define THREAD_FLAGS_TO_SET	0
	p->thread.flags = ((current->thread.flags & ~THREAD_FLAGS_TO_CLEAR)
			   | THREAD_FLAGS_TO_SET);
#ifdef CONFIG_IA32_SUPPORT
	if (IS_IA32_PROCESS(ia64_task_regs(current)))
		ia32_save_state(&p->thread);
#endif
	return 0;
}
int copy_thread ( int nr , unsigned long clone_flags , unsigned long user_stack_base , unsigned long user_stack_size , struct task_struct * p , struct pt_regs * regs ) { unsigned long rbs , child_rbs , rbs_size , stack_offset , stack_top , stack_used ; struct switch_stack * child_stack , * stack ; extern char ia64_ret_from_clone ; struct pt_regs * child_ptregs ; #ifdef CONFIG_SMP if ( ! regs ) return 0 ; #endif stack_top = ( unsigned long ) current + IA64_STK_OFFSET ; stack = ( ( struct switch_stack * ) regs ) - 1 ; stack_used = stack_top - ( unsigned long ) stack ; stack_offset = IA64_STK_OFFSET - stack_used ; child_stack = ( struct switch_stack * ) ( ( unsigned long ) p + stack_offset ) ; child_ptregs = ( struct pt_regs * ) ( child_stack + 1 ) ; memcpy ( child_stack , stack , stack_used ) ; rbs = ( unsigned long ) current + IA64_RBS_OFFSET ; child_rbs = ( unsigned long ) p + IA64_RBS_OFFSET ; rbs_size = stack -> ar_bspstore - rbs ; memcpy ( ( void * ) child_rbs , ( void * ) rbs , rbs_size ) ; if ( user_mode ( child_ptregs ) ) { if ( user_stack_base ) { child_ptregs -> r12 = user_stack_base + user_stack_size ; child_ptregs -> ar_bspstore = user_stack_base ; child_ptregs -> ar_rnat = 0 ; child_ptregs -> loadrs = 0 ; } } else { child_ptregs -> r12 = ( unsigned long ) ( child_ptregs + 1 ) ; child_ptregs -> r13 = ( unsigned long ) p ; } child_stack -> b0 = ( unsigned long ) & ia64_ret_from_clone ; child_stack -> ar_bspstore = child_rbs + rbs_size ; p -> thread . ksp = ( unsigned long ) child_stack - 16 ; #	define THREAD_FLAGS_TO_CLEAR 	(IA64_THREAD_FPH_VALID | IA64_THREAD_DBG_VALID \
					 | IA64_THREAD_PM_VALID) #	define THREAD_FLAGS_TO_SET 	0 p -> thread . flags = ( ( current -> thread . flags & ~ THREAD_FLAGS_TO_CLEAR ) | THREAD_FLAGS_TO_SET ) ; #ifdef CONFIG_IA32_SUPPORT if ( IS_IA32_PROCESS ( ia64_task_regs ( current ) ) ) ia32_save_state ( & p -> thread ) ; #endif return 0 ; }
Copy the state of an ia-64 thread.
Copy the state of an ia - 64 thread .
/*
	 * For SMP idle threads, fork_by_hand() calls do_fork with
	 * NULL regs.
	 */ /* copy parent's switch_stack & pt_regs to child: */ /* copy the parent's register backing store to the child: */ /*
		 * Note: we simply preserve the relative position of
		 * the stack pointer here.  There is no need to
		 * allocate a scratch area here, since that will have
		 * been taken care of by the caller of sys_clone()
		 * already.
		 */ /* kernel sp */ /* set `current' pointer */ /* copy parts of thread_struct: */ /*
	 * NOTE: The calling convention considers all floating point
	 * registers in the high partition (fph) to be scratch.  Since
	 * the only way to get to this point is through a system call,
	 * we know that the values in fph are all dead.  Hence, there
	 * is no need to inherit the fph state from the parent to the
	 * child and all we have to do is to make sure that
	 * IA64_THREAD_FPH_VALID is cleared in the child.
	 *
	 * XXX We could push this optimization a bit further by
	 * clearing IA64_THREAD_FPH_VALID on ANY system call.
	 * However, it's not clear this is worth doing.  Also, it
	 * would be a slight deviation from the normal Linux system
	 * call behavior where scratch registers are preserved across
	 * system calls (unless used by the system call itself).
	 */ /*
	 * If we're cloning an IA32 task then save the IA32 extra
	 * state from the current task to the new task
	 */