示例#1
0
文件: locore_c.c 项目: ryo/netbsd-src
/*
 * Prepare kernel stack PTE table.  sh4_switch_resume wires these PTEs.
 */
void
sh4_switch_setup(struct lwp *l)
{
	struct md_upte *md_upte;
	uint32_t vpn;
	pt_entry_t *pte;
	int i, e;

	md_upte = l->l_md.md_upte;
	vpn = sh3_trunc_page(uvm_lwp_getuarea(l));
	e = SH4_UTLB_ENTRY - UPAGES;

	for (i = 0; i < UPAGES; ++i) {
		pte = __pmap_kpte_lookup(vpn);
		KDASSERT(pte && *pte != 0);

		/* Address array */
		md_upte->addr = SH4_UTLB_AA | (e << SH4_UTLB_E_SHIFT);
		md_upte->data = vpn | SH4_UTLB_AA_D | SH4_UTLB_AA_V;
		++md_upte;

		/* Data array */
		md_upte->addr = SH4_UTLB_DA1 | (e << SH4_UTLB_E_SHIFT);
		md_upte->data = (*pte & PG_HW_BITS) |
		    SH4_UTLB_DA1_D | SH4_UTLB_DA1_V;
		++md_upte;

		vpn += PAGE_SIZE;
		++e;
	}
}
/*
 * Finish a fork operation, with process p2 nearly set up.
 * Copy and update the pcb and trap frame, making the child ready to run.
 * 
 * Rig the child's kernel stack so that it will start out in
 * proc_trampoline() and call child_return() with p2 as an
 * argument. This causes the newly-created child process to go
 * directly to user level with an apparent return value of 0 from
 * fork(), while the parent process returns normally.
 *
 * p1 is the process being forked; if p1 == &proc0, we are creating
 * a kernel thread, and the return path and argument are specified with
 * `func' and `arg'.
 *
 * If an alternate user-level stack is requested (with non-zero values
 * in both the stack and stacksize args), set up the user stack pointer
 * accordingly.
 */
void
cpu_lwp_fork(struct lwp *l1, struct lwp *l2, void *stack, size_t stacksize,
    void (*func)(void *), void *arg)
{
	struct pcb *pcb1, *pcb2;
	struct trapframe *tf;

	pcb1 = lwp_getpcb(l1);
	pcb2 = lwp_getpcb(l2);

	/* Copy pcb from lwp l1 to l2. */
	if (l1 == curlwp) {
		/* Sync the PCB before we copy it. */
		savectx(pcb1);
#if 0
		/* ia64_highfp_save(???); */
#endif
	} else {
		KASSERT(l1 == &lwp0);
	}

	*pcb2 = *pcb1;

	l2->l_md.md_flags = l1->l_md.md_flags;
	l2->l_md.md_tf = (struct trapframe *)(uvm_lwp_getuarea(l2) + USPACE) - 1;
	l2->l_md.md_astpending = 0;

        /*
	 * Copy the trapframe.
	 */
	tf = l2->l_md.md_tf;
	*tf = *l1->l_md.md_tf;

        /*
	 * If specified, give the child a different stack.
	 */
	if (stack != NULL)
		tf->tf_special.sp = (unsigned long)stack + stacksize;

	/* Set-up the return values as expected by the fork() libc stub. */
	if (tf->tf_special.psr & IA64_PSR_IS) {
		tf->tf_scratch.gr8 = 0;
		tf->tf_scratch.gr10 = 1;
	} else {
		tf->tf_scratch.gr8 = 0;
		tf->tf_scratch.gr9 = 1;
		tf->tf_scratch.gr10 = 0;
	}

	tf->tf_scratch.gr2 = (unsigned long)FDESC_FUNC(func);
	tf->tf_scratch.gr3 = (unsigned long)arg;
	pcb2->pcb_special.sp = (unsigned long)tf - 16;
	pcb2->pcb_special.rp = (unsigned long)FDESC_FUNC(lwp_trampoline);
	pcb2->pcb_special.pfs = 0;

	return;
}
示例#3
0
/*
 * XXX do kernacc call if safe, otherwise attempt
 * to simulate by simple bounds-checking.
 */
int
kgdb_acc(void *addr, int len, int rw)
{
    extern char kstack[];	/* XXX */
    extern char *kernel_map;		/* XXX! */

    if (kernel_map != NULL)
        return (kernacc(addr, len, rw));
    if (addr < uvm_lwp_getuarea(&lwp0) + USPACE  ||
            kstack <= addr && addr < kstack + USPACE)
        return (1);
    return (0);
}
/*
 * Finish a fork operation, with process l2 nearly set up.
 * Copy and update the pcb and trap frame, making the child ready to run.
 *
 * Rig the child's kernel stack so that it will start out in
 * lwp_trampoline() and call child_return() with l2 as an
 * argument. This causes the newly-created child process to go
 * directly to user level with an apparent return value of 0 from
 * fork(), while the parent process returns normally.
 *
 * l1 is the process being forked; if l1 == &lwp0, we are creating
 * a kernel thread, and the return path and argument are specified with
 * `func' and `arg'.
 *
 * If an alternate user-level stack is requested (with non-zero values
 * in both the stack and stacksize args), set up the user stack pointer
 * accordingly.
 */
void
cpu_lwp_fork(struct lwp *l1, struct lwp *l2, void *stack, size_t stacksize,
    void (*func)(void *), void *arg)
{
	struct pcb *pcb1, *pcb2;
	struct trapframe *tf;
	struct switchframe *sf;

	pcb1 = lwp_getpcb(l1);
	pcb2 = lwp_getpcb(l2);

	l2->l_md.md_flags = l1->l_md.md_flags;

	/* Copy pcb from lwp l1 to l2. */
	if (l1 == curlwp) {
		/* Sync the PCB before we copy it. */
		savectx(curpcb);
	} else {
		KASSERT(l1 == &lwp0);
	}

	*pcb2 = *pcb1;

	/*
	 * Copy the trap frame.
	 */
	tf = (struct trapframe *)(uvm_lwp_getuarea(l2) + USPACE) - 1;
	l2->l_md.md_regs = (int *)tf;
	*tf = *(struct trapframe *)l1->l_md.md_regs;

	/*
	 * If specified, give the child a different stack.
	 */
	if (stack != NULL)
		tf->tf_regs[15] = (u_int)stack + stacksize;

	sf = (struct switchframe *)tf - 1;
	sf->sf_pc = (u_int)lwp_trampoline;
	pcb2->pcb_regs[6] = (int)func;		/* A2 */
	pcb2->pcb_regs[7] = (int)arg;		/* A3 */
	pcb2->pcb_regs[8] = (int)l2;		/* A4 */
	pcb2->pcb_regs[11] = (int)sf;		/* SSP */
	pcb2->pcb_ps = PSL_LOWIPL;		/* start kthreads at IPL 0 */
}
void
cpu_lwp_fork(struct lwp *l1, struct lwp *l2, void *stack, size_t stacksize,
    void (*func)(void *), void *arg)
{
	struct pcb *pcb1, *pcb2;
	struct trapframe *tf;
	struct switchframe *sf;

#if 0
	printf("cpu_lwp_fork: %p -> %p\n", p1, p2);
#endif
	pcb1 = lwp_getpcb(l1);
	pcb2 = lwp_getpcb(l2);

	/* Copy the pcb */
	*pcb2 = *pcb1;

	/* pmap_activate(l2); XXX Other ports do.  Why?  */

	/* Set up the kernel stack */
	tf = (struct trapframe *)(uvm_lwp_getuarea(l2) + USPACE) - 1;
	sf = (struct switchframe *)tf - 1;
	/* Duplicate old process's trapframe (if it had one) */
	if (lwp_trapframe(l1) == NULL)
		memset(tf, 0, sizeof(*tf));
	else
		*tf = *lwp_trapframe(l1);
	/* If specified, give the child a different stack. */
	if (stack != NULL)
		tf->tf_usr_sp = (u_int)stack + stacksize;
	lwp_settrapframe(l2, tf);
	/* Fabricate a new switchframe */
	memset(sf, 0, sizeof(*sf));

	sf->sf_r13 = (register_t)tf; /* Initial stack pointer */
	sf->sf_pc  = (register_t)lwp_trampoline | R15_MODE_SVC;

	lwp_settrapframe(l2, tf);
	pcb2->pcb_sf = sf;
	pcb2->pcb_onfault = NULL;
	sf->sf_r4 = (register_t)func;
	sf->sf_r5 = (register_t)arg;
}
示例#6
0
/*
 * cpu_lwp_fork: Finish a fork operation, with lwp l2 nearly set up.
 * Copy and update the pcb and trapframe, making the child ready to run.
 *
 * First LWP (l1) is the lwp being forked.  If it is &lwp0, then we are
 * creating a kthread, where return path and argument are specified
 * with `func' and `arg'.
 *
 * Rig the child's kernel stack so that it will start out in lwp_trampoline()
 * and call child_return() with l2 as an argument. This causes the
 * newly-created child process to go directly to user level with an apparent
 * return value of 0 from fork(), while the parent process returns normally.
 *
 * If an alternate user-level stack is requested (with non-zero values
 * in both the stack and stacksize arguments), then set up the user stack
 * pointer accordingly.
 */
void
cpu_lwp_fork(struct lwp *l1, struct lwp *l2, void *stack, size_t stacksize,
    void (*func)(void *), void *arg)
{
	struct pcb * const pcb1 = lwp_getpcb(l1);
	struct pcb * const pcb2 = lwp_getpcb(l2);
	struct trapframe *tf;

	KASSERT(l1 == curlwp || l1 == &lwp0);

	l2->l_md.md_ss_addr = 0;
	l2->l_md.md_ss_instr = 0;
	l2->l_md.md_astpending = 0;

	/* Copy the PCB from parent. */
	*pcb2 = *pcb1;

	/*
	 * Copy the trapframe from parent, so that return to userspace
	 * will be to right address, with correct registers.
	 */
	vaddr_t ua2 = uvm_lwp_getuarea(l2);
	tf = (struct trapframe *)(ua2 + USPACE) - 1;
	*tf = *l1->l_md.md_utf;

	/* If specified, set a different user stack for a child. */
	if (stack != NULL)
		tf->tf_regs[_R_SP] = (intptr_t)stack + stacksize;

	l2->l_md.md_utf = tf;
#if USPACE > PAGE_SIZE
	bool direct_mapped_p = MIPS_KSEG0_P(ua2);
#ifdef _LP64
	direct_mapped_p = direct_mapped_p || MIPS_XKPHYS_P(ua2);
#endif
	if (!direct_mapped_p) {
		pt_entry_t * const pte = kvtopte(ua2);
		const uint32_t x = (MIPS_HAS_R4K_MMU) ?
		    (MIPS3_PG_G | MIPS3_PG_RO | MIPS3_PG_WIRED) : MIPS1_PG_G;

		for (u_int i = 0; i < UPAGES; i++) {
			l2->l_md.md_upte[i] = pte[i].pt_entry &~ x;
		}
	}
#endif
	/*
	 * Rig kernel stack so that it would start out in lwp_trampoline()
	 * and call child_return() with l as an argument.  This causes the
	 * newly-created child process to go directly to user level with a
	 * parent return value of 0 from fork(), while the parent process
	 * returns normally.
	 */

	pcb2->pcb_context.val[_L_S0] = (intptr_t)func;			/* S0 */
	pcb2->pcb_context.val[_L_S1] = (intptr_t)arg;			/* S1 */
	pcb2->pcb_context.val[MIPS_CURLWP_LABEL] = (intptr_t)l2;	/* T8 */
	pcb2->pcb_context.val[_L_SP] = (intptr_t)tf;			/* SP */
	pcb2->pcb_context.val[_L_RA] =
	   mips_locore_jumpvec.ljv_lwp_trampoline;			/* RA */
#ifdef _LP64
	KASSERT(pcb2->pcb_context.val[_L_SR] & MIPS_SR_KX);
#endif
	KASSERT(pcb2->pcb_context.val[_L_SR] & MIPS_SR_INT_IE);
}
示例#7
0
void
cpu_lwp_fork(struct lwp *l1, struct lwp *l2, void *stack, size_t stacksize,
    void (*func)(void *), void *arg)
{
	struct pcb *pcb1, *pcb2;
	struct trapframe *tf;
	register_t sp, osp;
	vaddr_t uv;

	KASSERT(round_page(sizeof(struct pcb)) <= PAGE_SIZE);

	pcb1 = lwp_getpcb(l1);
	pcb2 = lwp_getpcb(l2);

	l2->l_md.md_astpending = 0;
	l2->l_md.md_flags = 0;

	/* Flush the parent LWP out of the FPU. */
	hppa_fpu_flush(l1);

	/* Now copy the parent PCB into the child. */
	memcpy(pcb2, pcb1, sizeof(struct pcb));

	pcb2->pcb_fpregs = pool_get(&hppa_fppl, PR_WAITOK);
	*pcb2->pcb_fpregs = *pcb1->pcb_fpregs;

	/* reset any of the pending FPU exceptions from parent */
	pcb2->pcb_fpregs->fpr_regs[0] =
	    HPPA_FPU_FORK(pcb2->pcb_fpregs->fpr_regs[0]);
	pcb2->pcb_fpregs->fpr_regs[1] = 0;
	pcb2->pcb_fpregs->fpr_regs[2] = 0;
	pcb2->pcb_fpregs->fpr_regs[3] = 0;

	l2->l_md.md_bpva = l1->l_md.md_bpva;
	l2->l_md.md_bpsave[0] = l1->l_md.md_bpsave[0];
	l2->l_md.md_bpsave[1] = l1->l_md.md_bpsave[1];

	uv = uvm_lwp_getuarea(l2);
	sp = (register_t)uv + PAGE_SIZE;
	l2->l_md.md_regs = tf = (struct trapframe *)sp;
	sp += sizeof(struct trapframe);

	/* copy the l1's trapframe to l2 */
	memcpy(tf, l1->l_md.md_regs, sizeof(*tf));

	/* Fill out all the PAs we are going to need in locore. */
	cpu_activate_pcb(l2);

	if (__predict_true(l2->l_proc->p_vmspace != NULL)) {
		struct proc *p = l2->l_proc;
		pmap_t pmap = p->p_vmspace->vm_map.pmap;
		pa_space_t space = pmap->pm_space;

		/* Load all of the user's space registers. */
		tf->tf_sr0 = tf->tf_sr1 = tf->tf_sr3 = tf->tf_sr2 = 
		tf->tf_sr4 = tf->tf_sr5 = tf->tf_sr6 = space;
		tf->tf_iisq_head = tf->tf_iisq_tail = space;

		/* Load the protection registers */
		tf->tf_pidr1 = tf->tf_pidr2 = pmap->pm_pid;

		/*
		 * theoretically these could be inherited from the father,
		 * but just in case.
		 */
		tf->tf_sr7 = HPPA_SID_KERNEL;
		mfctl(CR_EIEM, tf->tf_eiem);
		tf->tf_ipsw = PSW_C | PSW_Q | PSW_P | PSW_D | PSW_I /* | PSW_L */ |
		    (curcpu()->ci_psw & PSW_O);
	}

	/*
	 * Set up return value registers as libc:fork() expects
	 */
	tf->tf_ret0 = l1->l_proc->p_pid;
	tf->tf_ret1 = 1;	/* ischild */
	tf->tf_t1 = 0;		/* errno */

	/*
	 * If specified, give the child a different stack.
	 */
	if (stack != NULL)
		tf->tf_sp = (register_t)stack;

	/*
	 * Build stack frames for the cpu_switchto & co.
	 */
	osp = sp;

	/* lwp_trampoline's frame */
	sp += HPPA_FRAME_SIZE;

	*(register_t *)(sp) = 0;	/* previous frame pointer */
	*(register_t *)(sp + HPPA_FRAME_PSP) = osp;
	*(register_t *)(sp + HPPA_FRAME_CRP) = (register_t)lwp_trampoline;

	*HPPA_FRAME_CARG(2, sp) = KERNMODE(func);
	*HPPA_FRAME_CARG(3, sp) = (register_t)arg;

	/*
	 * cpu_switchto's frame
	 * 	stack usage is std frame + callee-save registers
	 */
	sp += HPPA_FRAME_SIZE + 16*4;
	pcb2->pcb_ksp = sp;
	fdcache(HPPA_SID_KERNEL, uv, sp - uv);
}
/*
 * cpu_lwp_fork: finish a new LWP (l2) operation.
 *
 * First LWP (l1) is the process being forked.  If it is &lwp0, then we
 * are creating a kthread, where return path and argument are specified
 * with `func' and `arg'.
 *
 * If an alternate user-level stack is requested (with non-zero values
 * in both the stack and stacksize arguments), then set up the user stack
 * pointer accordingly.
 */
void
cpu_lwp_fork(struct lwp *l1, struct lwp *l2, void *stack, size_t stacksize,
    void (*func)(void *), void *arg)
{
	struct pcb *pcb1, *pcb2;
	struct trapframe *tf;
	struct switchframe *sf;
	vaddr_t uv;

	pcb1 = lwp_getpcb(l1);
	pcb2 = lwp_getpcb(l2);

	/*
	 * If parent LWP was using FPU, then we have to save the FPU h/w
	 * state to PCB so that we can copy it.
	 */
	if (pcb1->pcb_fpcpu != NULL) {
		fpusave_lwp(l1, true);
	}

	/*
	 * Sync the PCB before we copy it.
	 */
	if (l1 == curlwp) {
		KASSERT(pcb1 == curpcb);
		savectx(pcb1);
	} else {
		KASSERT(l1 == &lwp0);
	}

	/* Copy the PCB from parent. */
	memcpy(pcb2, pcb1, sizeof(struct pcb));

#if defined(XEN)
	pcb2->pcb_iopl = SEL_KPL;
#endif

	/*
	 * Set the kernel stack address (from the address to uarea) and
	 * trapframe address for child.
	 *
	 * Rig kernel stack so that it would start out in lwp_trampoline()
	 * and call child_return() with l2 as an argument.  This causes the
	 * newly-created child process to go directly to user level with a
	 * parent return value of 0 from fork(), while the parent process
	 * returns normally.
	 */
	uv = uvm_lwp_getuarea(l2);

#ifdef __x86_64__
	pcb2->pcb_rsp0 = (uv + KSTACK_SIZE - 16) & ~0xf;
	tf = (struct trapframe *)pcb2->pcb_rsp0 - 1;
#else
	pcb2->pcb_esp0 = (uv + KSTACK_SIZE - 16);
	tf = (struct trapframe *)pcb2->pcb_esp0 - 1;

	pcb2->pcb_iomap = NULL;
#endif
	l2->l_md.md_regs = tf;

	/*
	 * Copy the trapframe from parent, so that return to userspace
	 * will be to right address, with correct registers.
	 */
	memcpy(tf, l1->l_md.md_regs, sizeof(struct trapframe));

	/* Child LWP might get aston() before returning to userspace. */
	tf->tf_trapno = T_ASTFLT;

#if 0 /* DIAGNOSTIC */
	/* Set a red zone in the kernel stack after the uarea. */
	pmap_kremove(uv, PAGE_SIZE);
	pmap_update(pmap_kernel());
#endif

	/* If specified, set a different user stack for a child. */
	if (stack != NULL) {
#ifdef __x86_64__
		tf->tf_rsp = (uint64_t)stack + stacksize;
#else
		tf->tf_esp = (uint32_t)stack + stacksize;
#endif
	}

	l2->l_md.md_flags = l1->l_md.md_flags;
	l2->l_md.md_astpending = 0;

	sf = (struct switchframe *)tf - 1;

#ifdef __x86_64__
	sf->sf_r12 = (uint64_t)func;
	sf->sf_r13 = (uint64_t)arg;
	sf->sf_rip = (uint64_t)lwp_trampoline;
	pcb2->pcb_rsp = (uint64_t)sf;
	pcb2->pcb_rbp = (uint64_t)l2;
#else
	sf->sf_esi = (int)func;
	sf->sf_ebx = (int)arg;
	sf->sf_eip = (int)lwp_trampoline;
	pcb2->pcb_esp = (int)sf;
	pcb2->pcb_ebp = (int)l2;
#endif
}
/*
 * Finish a fork operation, with LWP l2 nearly set up.
 *
 * Copy and update the pcb and trapframe, making the child ready to run.
 *
 * Rig the child's kernel stack so that it will start out in
 * lwp_trampoline() which will call the specified func with the argument arg.
 *
 * If an alternate user-level stack is requested (with non-zero values
 * in both the stack and stacksize args), set up the user stack pointer
 * accordingly.
 */
void
cpu_lwp_fork(struct lwp *l1, struct lwp *l2, void *stack, size_t stacksize,
    void (*func)(void *), void *arg)
{
	struct switchframe *sf;
	vaddr_t uv;

	const struct pcb * const pcb1 = lwp_getpcb(l1);
	struct pcb * const pcb2 = lwp_getpcb(l2);

#ifdef PMAP_DEBUG
	if (pmap_debug_level > 0)
		printf("cpu_lwp_fork: %p %p %p %p\n", l1, l2, curlwp, &lwp0);
#endif	/* PMAP_DEBUG */

	/* Copy the pcb */
	*pcb2 = *pcb1;

#ifdef FPU_VFP
	/*
	 * Disable the VFP for a newly created LWP but remember if the
	 * VFP state is valid.
	 */
	pcb2->pcb_vfp.vfp_fpexc &= ~VFP_FPEXC_EN;
#endif

	/*
	 * Set up the kernel stack for the process.
	 * Note: this stack is not in use if we are forking from p1
	 */
	uv = uvm_lwp_getuarea(l2);
	pcb2->pcb_ksp = uv + USPACE_SVC_STACK_TOP;

#ifdef STACKCHECKS
	/* Fill the kernel stack with a known pattern */
	memset((void *)(uv + USPACE_SVC_STACK_BOTTOM), 0xdd,
	    (USPACE_SVC_STACK_TOP - USPACE_SVC_STACK_BOTTOM));
#endif	/* STACKCHECKS */

#ifdef PMAP_DEBUG
	if (pmap_debug_level > 0) {
		printf("l1: pcb=%p pid=%d pmap=%p\n",
		    pcb1, l1->l_lid, l1->l_proc->p_vmspace->vm_map.pmap);
		printf("l2: pcb=%p pid=%d pmap=%p\n",
		    pcb2, l2->l_lid, l2->l_proc->p_vmspace->vm_map.pmap);
	}
#endif	/* PMAP_DEBUG */

	struct trapframe *tf = (struct trapframe *)pcb2->pcb_ksp - 1;
	lwp_settrapframe(l2, tf);
	*tf = *lwp_trapframe(l1);

	/*
	 * If specified, give the child a different stack (make sure
	 * it's 8-byte aligned).
	 */
	if (stack != NULL)
		tf->tf_usr_sp = ((vaddr_t)(stack) + stacksize) & -8;

	sf = (struct switchframe *)tf - 1;
	sf->sf_r4 = (u_int)func;
	sf->sf_r5 = (u_int)arg;
	sf->sf_r7 = PSR_USR32_MODE;		/* for returning to userspace */
	sf->sf_sp = (u_int)tf;
	sf->sf_pc = (u_int)lwp_trampoline;
	pcb2->pcb_ksp = (u_int)sf;
}
示例#10
0
/*
 * cpu_lwp_fork: Finish a fork operation, with lwp l2 nearly set up.
 * Copy and update the pcb and trapframe, making the child ready to run.
 *
 * First LWP (l1) is the lwp being forked.  If it is &lwp0, then we are
 * creating a kthread, where return path and argument are specified
 * with `func' and `arg'.
 *
 * Rig the child's kernel stack so that it will start out in lwp_trampoline()
 * and call child_return() with l2 as an argument. This causes the
 * newly-created child process to go directly to user level with an apparent
 * return value of 0 from fork(), while the parent process returns normally.
 *
 * If an alternate user-level stack is requested (with non-zero values
 * in both the stack and stacksize arguments), then set up the user stack
 * pointer accordingly.
 */
void
cpu_lwp_fork(struct lwp *l1, struct lwp *l2, void *stack, size_t stacksize,
    void (*func)(void *), void *arg)
{
	struct pcb * const pcb1 = lwp_getpcb(l1);
	struct pcb * const pcb2 = lwp_getpcb(l2);
	struct trapframe *tf;

	KASSERT(l1 == curlwp || l1 == &lwp0);

	l2->l_md.md_ss_addr = 0;
	l2->l_md.md_ss_instr = 0;
	l2->l_md.md_astpending = 0;

	/* Copy the PCB from parent. */
	*pcb2 = *pcb1;

	/*
	 * Copy the trapframe from parent, so that return to userspace
	 * will be to right address, with correct registers.
	 */
	vaddr_t ua2 = uvm_lwp_getuarea(l2);
	tf = (struct trapframe *)(ua2 + USPACE) - 1;
	*tf = *l1->l_md.md_utf;

	/* If specified, set a different user stack for a child. */
	if (stack != NULL)
		tf->tf_regs[_R_SP] = (intptr_t)stack + stacksize;

	l2->l_md.md_utf = tf;
#if (USPACE > PAGE_SIZE) || !defined(_LP64)
	CTASSERT(__arraycount(l2->l_md.md_upte) >= UPAGES);
	for (u_int i = 0; i < __arraycount(l2->l_md.md_upte); i++) {
		l2->l_md.md_upte[i] = 0;
	}
	if (!pmap_md_direct_mapped_vaddr_p(ua2)) {
		CTASSERT((PGSHIFT == 12) == (UPAGES == 2));
		pt_entry_t * const pte = pmap_pte_lookup(pmap_kernel(), ua2);
		const uint32_t x = MIPS_HAS_R4K_MMU
		    ? (MIPS3_PG_RO | MIPS3_PG_WIRED)
		    : 0;

		for (u_int i = 0; i < UPAGES; i++) {
			KASSERT(pte_valid_p(pte[i]));
			l2->l_md.md_upte[i] = pte[i] & ~x;
		}
	}
#else
	KASSERT(pmap_md_direct_mapped_vaddr_p(ua2));
#endif
	/*
	 * Rig kernel stack so that it would start out in lwp_trampoline()
	 * and call child_return() with l as an argument.  This causes the
	 * newly-created child process to go directly to user level with a
	 * parent return value of 0 from fork(), while the parent process
	 * returns normally.
	 */

	pcb2->pcb_context.val[_L_S0] = (intptr_t)func;			/* S0 */
	pcb2->pcb_context.val[_L_S1] = (intptr_t)arg;			/* S1 */
	pcb2->pcb_context.val[MIPS_CURLWP_LABEL] = (intptr_t)l2;	/* T8 */
	pcb2->pcb_context.val[_L_SP] = (intptr_t)tf;			/* SP */
	pcb2->pcb_context.val[_L_RA] =
	   mips_locore_jumpvec.ljv_lwp_trampoline;			/* RA */
#if defined(_LP64) || defined(__mips_n32)
	KASSERT(tf->tf_regs[_R_SR] & MIPS_SR_KX);
	KASSERT(pcb2->pcb_context.val[_L_SR] & MIPS_SR_KX);
#endif
	KASSERTMSG(pcb2->pcb_context.val[_L_SR] & MIPS_SR_INT_IE,
	    "%d.%d %#"PRIxREGISTER,
	    l1->l_proc->p_pid, l1->l_lid,
	    pcb2->pcb_context.val[_L_SR]);
}
示例#11
0
/*
 * void cpu_startup(void)
 *
 * Machine dependent startup code. 
 *
 */
void
cpu_startup(void)
{
	vaddr_t minaddr;
	vaddr_t maxaddr;
	char pbuf[9];

	/*
	 * Until we better locking, we have to live under the kernel lock.
	 */
	//KERNEL_LOCK(1, NULL);

	/* Set the CPU control register */
	cpu_setup(boot_args);

#ifndef ARM_HAS_VBAR
	/* Lock down zero page */
	vector_page_setprot(VM_PROT_READ);
#endif

	/*
	 * Give pmap a chance to set up a few more things now the vm
	 * is initialised
	 */
	pmap_postinit();

	/*
	 * Initialize error message buffer (at end of core).
	 */

	/* msgbufphys was setup during the secondary boot strap */
	if (!pmap_extract(pmap_kernel(), (vaddr_t)msgbufaddr, NULL)) {
		for (u_int loop = 0; loop < btoc(MSGBUFSIZE); ++loop) {
			pmap_kenter_pa((vaddr_t)msgbufaddr + loop * PAGE_SIZE,
			    msgbufphys + loop * PAGE_SIZE,
			    VM_PROT_READ|VM_PROT_WRITE, 0);
		}
	}
	pmap_update(pmap_kernel());
	initmsgbuf(msgbufaddr, round_page(MSGBUFSIZE));

	/*
	 * Identify ourselves for the msgbuf (everything printed earlier will
	 * not be buffered).
	 */
	printf("%s%s", copyright, version);

	format_bytes(pbuf, sizeof(pbuf), arm_ptob(physmem));
	printf("total memory = %s\n", pbuf);

	minaddr = 0;

	/*
	 * Allocate a submap for physio
	 */
	phys_map = uvm_km_suballoc(kernel_map, &minaddr, &maxaddr,
				   VM_PHYS_SIZE, 0, false, NULL);

	format_bytes(pbuf, sizeof(pbuf), ptoa(uvmexp.free));
	printf("avail memory = %s\n", pbuf);

	struct lwp * const l = &lwp0;
	struct pcb * const pcb = lwp_getpcb(l);
	pcb->pcb_ksp = uvm_lwp_getuarea(l) + USPACE_SVC_STACK_TOP;
	lwp_settrapframe(l, (struct trapframe *)pcb->pcb_ksp - 1);
}
/*
 * Finish a fork operation, with thread l2 nearly set up.
 * Copy and update the pcb and trap frame, making the child ready to run.
 *
 * Rig the child's kernel stack so that it will start out in
 * lwp_trampoline() and call child_return() with l2 as an
 * argument. This causes the newly-created child thread to go
 * directly to user level with an apparent return value of 0 from
 * fork(), while the parent process returns normally.
 *
 * l1 is the thread being forked; if l1 == &lwp0, we are creating
 * a kernel thread, and the return path and argument are specified with
 * `func' and `arg'.
 *
 * If an alternate user-level stack is requested (with non-zero values
 * in both the stack and stacksize args), set up the user stack pointer
 * accordingly.
 */
void
cpu_lwp_fork(struct lwp *l1, struct lwp *l2, void *stack, size_t stacksize,
    void (*func)(void *), void *arg)
{
	struct pcb *pcb1, *pcb2;
	extern void lwp_trampoline(void);

	pcb1 = lwp_getpcb(l1);
	pcb2 = lwp_getpcb(l2);

	l2->l_md.md_tf = l1->l_md.md_tf;
	l2->l_md.md_flags = l1->l_md.md_flags & MDLWP_FP_C;
	l2->l_md.md_astpending = 0;

	/*
	 * Cache the physical address of the pcb, so we can
	 * swap to it easily.
	 */
	l2->l_md.md_pcbpaddr = (void *)vtophys((vaddr_t)pcb2);

	/*
	 * Copy pcb and user stack pointer from proc p1 to p2.
	 * If specificed, give the child a different stack.
	 * Floating point state from the FP chip has already been saved.
	 */
	*pcb2 = *pcb1;
	if (stack != NULL)
		pcb2->pcb_hw.apcb_usp = (u_long)stack + stacksize;
	else
		pcb2->pcb_hw.apcb_usp = alpha_pal_rdusp();

	/*
	 * Arrange for a non-local goto when the new process
	 * is started, to resume here, returning nonzero from setjmp.
	 */
#ifdef DIAGNOSTIC
	/*
	 * If l1 != curlwp && l1 == &lwp0, we are creating a kernel
	 * thread.
	 */
	if (l1 != curlwp && l1 != &lwp0)
		panic("cpu_lwp_fork: curlwp");
#endif

	/*
	 * create the child's kernel stack, from scratch.
	 */
	{
		struct trapframe *l2tf;

		/*
		 * Pick a stack pointer, leaving room for a trapframe;
		 * copy trapframe from parent so return to user mode
		 * will be to right address, with correct registers.
		 */
		l2tf = l2->l_md.md_tf = (struct trapframe *)
		    (uvm_lwp_getuarea(l2) + USPACE - sizeof(struct trapframe));
		memcpy(l2->l_md.md_tf, l1->l_md.md_tf,
		    sizeof(struct trapframe));

		/*
		 * Set up return-value registers as fork() libc stub expects.
		 */
		l2tf->tf_regs[FRAME_V0] = l1->l_proc->p_pid; /* parent's pid */
		l2tf->tf_regs[FRAME_A3] = 0;		/* no error */
		l2tf->tf_regs[FRAME_A4] = 1;		/* is child */

		pcb2->pcb_hw.apcb_ksp =
		    (uint64_t)l2->l_md.md_tf;
		pcb2->pcb_context[0] =
		    (uint64_t)func;			/* s0: pc */
		pcb2->pcb_context[1] =
		    (uint64_t)exception_return;		/* s1: ra */
		pcb2->pcb_context[2] =
		    (uint64_t)arg;			/* s2: arg */
		pcb2->pcb_context[3] =
		    (uint64_t)l2;			/* s3: lwp */
		pcb2->pcb_context[7] =
		    (uint64_t)lwp_trampoline;		/* ra: assembly magic */
	}
}