void userret(struct lwp *l) { #if defined(__PROG32) && defined(ARM_MMU_EXTENDED) /* * If our ASID got released, access via TTBR0 will have been disabled. * So if it is disabled, activate the lwp again to get a new ASID. */ #ifdef __HAVE_PREEMPTION kpreempt_disable(); #endif KASSERT(curcpu()->ci_pmap_cur == l->l_proc->p_vmspace->vm_map.pmap); if (__predict_false(armreg_ttbcr_read() & TTBCR_S_PD0)) { pmap_activate(l); } KASSERT(!(armreg_ttbcr_read() & TTBCR_S_PD0)); #ifdef __HAVE_PREEMPTION kpreempt_enable(); #endif #endif /* Invoke MI userret code */ mi_userret(l); #if defined(__PROG32) && defined(DIAGNOSTIC) KASSERT(VALID_R15_PSR(lwp_trapframe(l)->tf_pc, lwp_trapframe(l)->tf_spsr)); #endif }
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; }
int compat_13_sys_sigreturn(struct lwp *l, const struct compat_13_sys_sigreturn_args *uap, register_t *retval) { /* { syscallarg(struct sigcontext13 *) sigcntxp; } */ struct sigcontext13 *scp, context; struct trapframe * const tf = lwp_trapframe(l); struct proc * const p = l->l_proc; sigset_t mask; /* * The trampoline code hands us the context. * It is unsafe to keep track of it ourselves, in the event that a * program jumps out of a signal handler. */ scp = SCARG(uap, sigcntxp); if (copyin((void *)scp, &context, sizeof(*scp)) != 0) return (EFAULT); /* * Make sure the processor mode has not been tampered with and * interrupts have not been disabled. */ if (!VALID_R15_PSR(context.sc_pc, context.sc_spsr)) return EINVAL; /* Restore register context. */ tf->tf_r0 = context.sc_r0; tf->tf_r1 = context.sc_r1; tf->tf_r2 = context.sc_r2; tf->tf_r3 = context.sc_r3; tf->tf_r4 = context.sc_r4; tf->tf_r5 = context.sc_r5; tf->tf_r6 = context.sc_r6; tf->tf_r7 = context.sc_r7; tf->tf_r8 = context.sc_r8; tf->tf_r9 = context.sc_r9; tf->tf_r10 = context.sc_r10; tf->tf_r11 = context.sc_r11; tf->tf_r12 = context.sc_r12; tf->tf_usr_sp = context.sc_usr_sp; tf->tf_usr_lr = context.sc_usr_lr; tf->tf_svc_lr = context.sc_svc_lr; tf->tf_pc = context.sc_pc; tf->tf_spsr = context.sc_spsr; mutex_enter(p->p_lock); /* Restore signal stack. */ if (context.sc_onstack & SS_ONSTACK) l->l_sigstk.ss_flags |= SS_ONSTACK; else l->l_sigstk.ss_flags &= ~SS_ONSTACK; /* Restore signal mask. */ native_sigset13_to_sigset(&context.sc_mask, &mask); (void) sigprocmask1(l, SIG_SETMASK, &mask, 0); mutex_exit(p->p_lock); return (EJUSTRETURN); }
/* * 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; }