/* * 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; }
/* * 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; }
/* * 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); }
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; }
/* * 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]); }
/* * 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 */ } }