/* * Set to mcontext specified. * Return to previous pc and psl as specified by * context left by sendsig. Check carefully to * make sure that the user has not modified the * psl to gain improper privileges or to cause * a machine fault. * This is almost like sigreturn() and it shows. */ int svr4_32_setmcontext(struct lwp *l, struct svr4_32_mcontext *mc, netbsd32_u_long flags) { register struct trapframe64 *tf; svr4_32_greg_t *r = mc->greg; #ifdef FPU_CONTEXT svr4_32_fregset_t *f = &mc->freg; struct fpstate64 *fps = p->p_md.md_fpstate; #endif #ifdef DEBUG_SVR4 svr4_32_printmcontext("setmcontext", uc); #endif write_user_windows(); if (rwindow_save(l)) { #ifdef DEBUG printf("svr4_32_setcontext: rwindow_save(%p) failed, sending SIGILL\n", l); #ifdef DDB Debugger(); #endif #endif mutex_enter(l->l_proc->p_lock); sigexit(l, SIGILL); } #ifdef DEBUG if (sigdebug & SDB_FOLLOW) printf("svr4_32_setmcontext: %s[%d], svr4_32_mcontext %p\n", l->l_proc->p_comm, l->l_proc->p_pid, mc); #endif if (flags & SVR4_UC_CPU) { /* Restore register context. */ tf = (struct trapframe64 *)l->l_md.md_tf; /* * Only the icc bits in the psr are used, so it need not be * verified. pc and npc must be multiples of 4. This is all * that is required; if it holds, just do it. */ if (((r[SVR4_SPARC_PC] | r[SVR4_SPARC_nPC]) & 3) != 0) { printf("pc or npc are not multiples of 4!\n"); return EINVAL; } /* take only psr ICC field */ tf->tf_tstate = (tf->tf_tstate & ~TSTATE_CCR) | PSRCC_TO_TSTATE(r[SVR4_SPARC_PSR]); tf->tf_pc = r[SVR4_SPARC_PC]; tf->tf_npc = r[SVR4_SPARC_nPC]; tf->tf_y = r[SVR4_SPARC_Y]; /* Restore everything */ tf->tf_global[1] = r[SVR4_SPARC_G1]; tf->tf_global[2] = r[SVR4_SPARC_G2]; tf->tf_global[3] = r[SVR4_SPARC_G3]; tf->tf_global[4] = r[SVR4_SPARC_G4]; tf->tf_global[5] = r[SVR4_SPARC_G5]; tf->tf_global[6] = r[SVR4_SPARC_G6]; tf->tf_global[7] = r[SVR4_SPARC_G7]; tf->tf_out[0] = r[SVR4_SPARC_O0]; tf->tf_out[1] = r[SVR4_SPARC_O1]; tf->tf_out[2] = r[SVR4_SPARC_O2]; tf->tf_out[3] = r[SVR4_SPARC_O3]; tf->tf_out[4] = r[SVR4_SPARC_O4]; tf->tf_out[5] = r[SVR4_SPARC_O5]; tf->tf_out[6] = r[SVR4_SPARC_O6]; tf->tf_out[7] = r[SVR4_SPARC_O7]; } #ifdef FPU_CONTEXT if (flags & SVR4_UC_FPU) { /* * Set the floating point registers */ int error; size_t sz = f->fp_nqel * f->fp_nqsize; if (sz > sizeof(fps->fs_queue)) { #ifdef DIAGNOSTIC printf("setmcontext: fp_queue too large\n"); #endif return EINVAL; } /* Note: touches only pre-v9 floating point registers. */ memcpy(fps->fs_regs, f->fpu_regs, sizeof(f->fpu_regs)); fps->fs_qsize = f->fp_nqel; fps->fs_fsr = f->fp_fsr; if (f->fp_q != 0) { if ((error = copyin((void *)(u_long)f->fp_q, fps->fs_queue, f->fp_nqel * f->fp_nqsize)) != 0) { #ifdef DIAGNOSTIC printf("setmcontext: fp_queue copy failed\n"); #endif return error; } } } #endif return 0; }
void * svr4_32_getmcontext(struct lwp *l, struct svr4_32_mcontext *mc, netbsd32_u_long *flags) { struct trapframe64 *tf = (struct trapframe64 *)l->l_md.md_tf; svr4_32_greg_t *r = mc->greg; #ifdef FPU_CONTEXT svr4_32_fregset_t *f = &mc->freg; struct fpstate *fps = l->l_md.md_fpstate; #endif write_user_windows(); if (rwindow_save(l)) { #ifdef DEBUG printf("svr4_32_getcontext: rwindow_save(%p) failed, sending SIGILL\n", l); #ifdef DDB Debugger(); #endif #endif mutex_enter(l->l_proc->p_lock); sigexit(l, SIGILL); } /* * Get the general purpose registers */ r[SVR4_SPARC_PSR] = TSTATECCR_TO_PSR(tf->tf_tstate); r[SVR4_SPARC_PC] = tf->tf_pc; r[SVR4_SPARC_nPC] = tf->tf_npc; r[SVR4_SPARC_Y] = tf->tf_y; r[SVR4_SPARC_G1] = tf->tf_global[1]; r[SVR4_SPARC_G2] = tf->tf_global[2]; r[SVR4_SPARC_G3] = tf->tf_global[3]; r[SVR4_SPARC_G4] = tf->tf_global[4]; r[SVR4_SPARC_G5] = tf->tf_global[5]; r[SVR4_SPARC_G6] = tf->tf_global[6]; r[SVR4_SPARC_G7] = tf->tf_global[7]; r[SVR4_SPARC_O0] = tf->tf_out[0]; r[SVR4_SPARC_O1] = tf->tf_out[1]; r[SVR4_SPARC_O2] = tf->tf_out[2]; r[SVR4_SPARC_O3] = tf->tf_out[3]; r[SVR4_SPARC_O4] = tf->tf_out[4]; r[SVR4_SPARC_O5] = tf->tf_out[5]; r[SVR4_SPARC_O6] = tf->tf_out[6]; r[SVR4_SPARC_O7] = tf->tf_out[7]; *flags |= SVR4_UC_CPU; #ifdef FPU_CONTEXT /* * Get the floating point registers */ /* Note: copies only pre-v9 floating point registers. */ memcpy(f->fpu_regs, fps->fs_regs, sizeof(f->fpu_regs)); f->fp_nqsize = sizeof(struct fp_qentry); f->fp_nqel = fps->fs_qsize; f->fp_fsr = fps->fs_fsr; if (f->fp_q != NULL) { size_t sz = f->fp_nqel * f->fp_nqsize; if (sz > sizeof(fps->fs_queue)) { #ifdef DIAGNOSTIC printf("getcontext: fp_queue too large\n"); #endif return; } if (copyout(fps->fs_queue, (void *)(u_long)f->fp_q, sz) != 0) { #ifdef DIAGNOSTIC printf("getcontext: copy of fp_queue failed %d\n", error); #endif return; } } f->fp_busy = 0; /* XXX: How do we determine that? */ *flags |= SVR4_UC_FPU; #endif #ifdef DEBUG_SVR4 svr4_32_printmcontext("getmcontext", mc); #endif return (void *)(u_long)tf->tf_out[6]; }
int sunos32_sys_sigreturn(struct lwp *l, const struct sunos32_sys_sigreturn_args *uap, register_t *retval) { /* { syscallarg(netbsd32_sigcontextp_t) sigcntxp; } */ struct proc *p = l->l_proc; struct sunos32_sigcontext sc, *scp; sigset_t mask; struct trapframe64 *tf; /* First ensure consistent stack state (see sendsig). */ write_user_windows(); if (rwindow_save(l)) { mutex_enter(p->p_lock); sigexit(l, SIGILL); } #ifdef DEBUG if (sigdebug & SDB_FOLLOW) { printf("sunos32_sigreturn: %s[%d], sigcntxp %p\n", p->p_comm, p->p_pid, (void *)(u_long)SCARG(uap, sigcntxp)); #ifdef DDB if (sigdebug & SDB_DDB) Debugger(); #endif } #endif scp = (struct sunos32_sigcontext *)(u_long)SCARG(uap, sigcntxp); if ((vaddr_t)scp & 3 || (copyin((void *)scp, &sc, sizeof sc) != 0)) return (EFAULT); scp = ≻ tf = l->l_md.md_tf; /* * Only the icc bits in the psr are used, so it need not be * verified. pc and npc must be multiples of 4. This is all * that is required; if it holds, just do it. */ if (((scp->sc_pc | scp->sc_npc) & 3) != 0 || scp->sc_pc == 0 || scp->sc_npc == 0) { #ifdef DEBUG printf("sunos32_sigreturn: pc %x or npc %x invalid\n", scp->sc_pc, scp->sc_npc); #ifdef DDB Debugger(); #endif #endif return (EINVAL); } /* take only psr ICC field */ tf->tf_tstate = (int64_t)(tf->tf_tstate & ~TSTATE_CCR) | PSRCC_TO_TSTATE(scp->sc_psr); tf->tf_pc = scp->sc_pc; tf->tf_npc = scp->sc_npc; tf->tf_global[1] = scp->sc_g1; tf->tf_out[0] = scp->sc_o0; tf->tf_out[6] = scp->sc_sp; #ifdef DEBUG if (sigdebug & SDB_FOLLOW) { printf("sunos32_sigreturn: return trapframe pc=%p sp=%p tstate=%llx\n", (void *)(u_long)tf->tf_pc, (void *)(u_long)tf->tf_out[6], (unsigned long long)tf->tf_tstate); #ifdef DDB if (sigdebug & SDB_DDB) Debugger(); #endif } #endif mutex_enter(p->p_lock); if (scp->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(&scp->sc_mask, &mask); (void) sigprocmask1(l, SIG_SETMASK, &mask, 0); mutex_exit(p->p_lock); return (EJUSTRETURN); }
void sunos32_sendsig(const ksiginfo_t *ksi, const sigset_t *mask) { int sig = ksi->ksi_signo; struct lwp *l = curlwp; /* XXX */ struct proc *p = l->l_proc; struct sunos32_sigframe *fp; struct trapframe64 *tf; struct rwindow32 *oldsp, *newsp; struct sunos32_sigframe sf; struct sunos32_sigcontext *scp; uint32_t addr, oldsp32; int onstack, error; sig_t catcher = SIGACTION(p, sig).sa_handler; tf = l->l_md.md_tf; /* Need to attempt to zero extend this 32-bit pointer */ oldsp = (struct rwindow32 *)(u_long)(u_int)tf->tf_out[6]; oldsp32 = (uint32_t)(u_long)oldsp; /* * Compute new user stack addresses, subtract off * one signal frame, and align. */ onstack = (l->l_sigstk.ss_flags & (SS_DISABLE | SS_ONSTACK)) == 0 && (SIGACTION(p, sig).sa_flags & SA_ONSTACK) != 0; if (onstack) fp = (struct sunos32_sigframe *) ((char *)l->l_sigstk.ss_sp + l->l_sigstk.ss_size); else fp = (struct sunos32_sigframe *)oldsp; fp = (struct sunos32_sigframe *)((u_long)(fp - 1) & ~7); #ifdef DEBUG sigpid = p->p_pid; if ((sigdebug & SDB_KSTACK) && p->p_pid == sigpid) { mutex_exit(p->p_lock); printf("sunos32_sendsig: %s[%d] sig %d newusp %p scp %p oldsp %p\n", p->p_comm, p->p_pid, sig, fp, &fp->sf_sc, oldsp); #ifdef DDB if (sigdebug & SDB_DDB) Debugger(); #endif mutex_enter(p->p_lock); } #endif /* * Now set up the signal frame. We build it in kernel space * and then copy it out. We probably ought to just build it * directly in user space.... */ sf.sf_signo = sig; sf.sf_code = (uint32_t)ksi->ksi_trap; scp = &fp->sf_sc; if ((u_long)scp >= 0x100000000) printf("sunos32_sendsig: sf_scp overflow %p > 0x100000000\n", scp); sf.sf_scp = (uint32_t)(u_long)scp; sf.sf_addr = 0; /* XXX */ /* * Build the signal context to be used by sigreturn. */ sf.sf_sc.sc_onstack = l->l_sigstk.ss_flags & SS_ONSTACK; native_sigset_to_sigset13(mask, &sf.sf_sc.sc_mask); sf.sf_sc.sc_sp = (u_int)(u_long)oldsp; sf.sf_sc.sc_pc = tf->tf_pc; sf.sf_sc.sc_npc = tf->tf_npc; sf.sf_sc.sc_psr = TSTATECCR_TO_PSR(tf->tf_tstate); /* XXX */ sf.sf_sc.sc_g1 = tf->tf_global[1]; sf.sf_sc.sc_o0 = tf->tf_out[0]; /* * Put the stack in a consistent state before we whack away * at it. Note that write_user_windows may just dump the * registers into the pcb; we need them in the process's memory. * We also need to make sure that when we start the signal handler, * its %i6 (%fp), which is loaded from the newly allocated stack area, * joins seamlessly with the frame it was in when the signal occurred, * so that the debugger and _longjmp code can back up through it. */ sendsig_reset(l, sig); mutex_exit(p->p_lock); newsp = (struct rwindow32 *)((long)fp - sizeof(struct rwindow32)); write_user_windows(); #ifdef DEBUG if ((sigdebug & SDB_KSTACK)) printf("sunos32_sendsig: saving sf to %p, setting stack pointer %p to %p\n", fp, &(((struct rwindow32 *)newsp)->rw_in[6]), oldsp); #endif error = (rwindow_save(l) || copyout((void *)&sf, (void *)fp, sizeof sf) || copyout((void *)&oldsp32, &(((struct rwindow32 *)newsp)->rw_in[6]), sizeof oldsp32)); mutex_enter(p->p_lock); if (error) { /* * Process has trashed its stack; give it an illegal * instruction to halt it in its tracks. */ #ifdef DEBUG mutex_exit(p->p_lock); if ((sigdebug & SDB_KSTACK) && p->p_pid == sigpid) printf("sunos32_sendsig: window save or copyout error\n"); printf("sunos32_sendsig: stack was trashed trying to send sig %d, sending SIGILL\n", sig); #ifdef DDB if (sigdebug & SDB_DDB) Debugger(); #endif mutex_enter(p->p_lock); #endif sigexit(l, SIGILL); /* NOTREACHED */ } #ifdef DEBUG if ((sigdebug & SDB_FOLLOW)) { printf("sunos32_sendsig: %s[%d] sig %d scp %p\n", p->p_comm, p->p_pid, sig, &fp->sf_sc); } #endif /* * Arrange to continue execution at the code copied out in exec(). * It needs the function to call in %g1, and a new stack pointer. */ addr = (uint32_t)(u_long)catcher; /* user does his own trampolining */ tf->tf_pc = addr; tf->tf_npc = addr + 4; tf->tf_out[6] = (uint64_t)(u_int)(u_long)newsp; #ifdef DEBUG if ((sigdebug & SDB_KSTACK) && p->p_pid == sigpid) { mutex_exit(p->p_lock); printf("sunos32_sendsig: about to return to catcher %p thru %p\n", catcher, (void *)(u_long)addr); #ifdef DDB if (sigdebug & SDB_DDB) Debugger(); #endif mutex_enter(p->p_lock); } #endif }
/* * Send an interrupt to process. * * Stack is set up to allow sigcode stored * in u. to call routine. After the handler is * done svr4 will call setcontext for us * with the user context we just set up, and we * will return to the user pc, psl. */ void svr4_32_sendsig(const ksiginfo_t *ksi, const sigset_t *mask) { int sig = ksi->ksi_signo; register struct lwp *l = curlwp; struct proc *p = l->l_proc; register struct trapframe64 *tf; struct svr4_32_sigframe *fp, frame; int onstack, error; vaddr_t oldsp, newsp, addr; sig_t catcher = SIGACTION(p, sig).sa_handler; sigset_t tmask; tf = (struct trapframe64 *)l->l_md.md_tf; oldsp = tf->tf_out[6]; /* Do we need to jump onto the signal stack? */ onstack = (l->l_sigstk.ss_flags & (SS_DISABLE | SS_ONSTACK)) == 0 && (SIGACTION(p, sig).sa_flags & SA_ONSTACK) != 0; /* * Allocate space for the signal handler context. */ if (onstack) fp = (struct svr4_32_sigframe *)((char *)l->l_sigstk.ss_sp + l->l_sigstk.ss_size); else fp = (struct svr4_32_sigframe *)oldsp; fp = (struct svr4_32_sigframe *) ((long) (fp - 1) & ~7); #ifdef DEBUG sigpid = p->p_pid; if ((sigdebug & SDB_KSTACK) && p->p_pid == sigpid) { printf("svr4_32_sendsig: %s[%d] sig %d newusp %p scp %p oldsp %p\n", p->p_comm, p->p_pid, sig, fp, &fp->sf_uc, (void *)(u_long)oldsp); #ifdef DDB if (sigdebug & SDB_DDB) Debugger(); #endif } #endif /* * Build the argument list for the signal handler. */ svr4_32_getsiginfo(&frame.sf_si, sig, ksi->ksi_trap, (void *)(u_long)tf->tf_pc); /* Build stack frame for signal trampoline. */ frame.sf_signum = frame.sf_si.si_signo; NETBSD32PTR32(frame.sf_sip, &fp->sf_si); NETBSD32PTR32(frame.sf_ucp, &fp->sf_uc); frame.sf_handler = catcher; DPRINTF(("svr4_32_sendsig signum=%d si = %p uc = %p handler = %p\n", frame.sf_signum, frame.sf_sip, frame.sf_ucp, frame.sf_handler)); /* * Modify the signal context to be used by sigreturn. */ tmask = *mask; sendsig_reset(l, sig); frame.sf_uc.uc_mcontext.greg[SVR4_SPARC_SP] = oldsp; newsp = (u_long)fp - sizeof(struct rwindow32); mutex_exit(p->p_lock); svr4_32_getcontext(l, &frame.sf_uc, &tmask); write_user_windows(); #ifdef DEBUG if ((sigdebug & SDB_KSTACK)) printf("svr4_32_sendsig: saving sf to %p, setting stack pointer %p to %p\n", fp, &(((struct rwindow32 *)newsp)->rw_in[6]), (void *)(u_long)oldsp); #endif error = (rwindow_save(l) || copyout(&frame, fp, sizeof(frame)) != 0 || copyout(&oldsp, &((struct rwindow32 *)newsp)->rw_in[6], sizeof(oldsp))); mutex_enter(p->p_lock); if (error) { /* * Process has trashed its stack; give it an illegal * instruction to halt it in its tracks. */ #ifdef DEBUG mutex_exit(p->p_lock); if ((sigdebug & SDB_KSTACK) && p->p_pid == sigpid) printf("svr4_32_sendsig: window save or copyout error\n"); printf("svr4_32_sendsig: stack was trashed trying to send sig %d, sending SIGILL\n", sig); #ifdef DDB Debugger(); #endif mutex_enter(p->p_lock); #endif sigexit(l, SIGILL); /* NOTREACHED */ } #ifdef DEBUG if (sigdebug & SDB_FOLLOW) { printf("svr4_32_sendsig: %s[%d] sig %d scp %p\n", p->p_comm, p->p_pid, sig, &fp->sf_uc); } #endif /* * Build context to run handler in. */ addr = (vaddr_t)p->p_sigctx.ps_sigcode; tf->tf_pc = addr; tf->tf_npc = addr + 4; tf->tf_global[1] = (vaddr_t)catcher; tf->tf_out[6] = newsp; /* Remember that we're now on the signal stack. */ if (onstack) l->l_sigstk.ss_flags |= SS_ONSTACK; #ifdef DEBUG if ((sigdebug & SDB_KSTACK) && p->p_pid == sigpid) { mutex_exit(p->p_lock); printf("svr4_32_sendsig: about to return to catcher %p thru %p\n", catcher, (void *)(u_long)addr); #ifdef DDB if (sigdebug & SDB_DDB) Debugger(); #endif mutex_enter(p->p_lock); } #endif }
void cpu_lwp_fork(register struct lwp *l1, register struct lwp *l2, void *stack, size_t stacksize, void (*func)(void *), void *arg) { struct pcb *opcb = lwp_getpcb(l1); struct pcb *npcb = lwp_getpcb(l2); struct trapframe *tf2; struct rwindow *rp; /* * Save all user registers to l1's stack or, in the case of * user registers and invalid stack pointers, to opcb. * We then copy the whole pcb to l2; when switch() selects l2 * to run, it will run at the `lwp_trampoline' stub, rather * than returning at the copying code below. * * If process l1 has an FPU state, we must copy it. If it is * the FPU user, we must save the FPU state first. */ #ifdef NOTDEF_DEBUG printf("cpu_lwp_fork()\n"); #endif if (l1 == curlwp) { write_user_windows(); /* * We're in the kernel, so we don't really care about * %ccr or %asi. We do want to duplicate %pstate and %cwp. */ opcb->pcb_pstate = getpstate(); opcb->pcb_cwp = getcwp(); } #ifdef DIAGNOSTIC else if (l1 != &lwp0) panic("cpu_lwp_fork: curlwp"); #endif #ifdef DEBUG /* prevent us from having NULL lastcall */ opcb->lastcall = cpu_forkname; #else opcb->lastcall = NULL; #endif memcpy(npcb, opcb, sizeof(struct pcb)); if (l1->l_md.md_fpstate) { fpusave_lwp(l1, true); l2->l_md.md_fpstate = pool_cache_get(fpstate_cache, PR_WAITOK); memcpy(l2->l_md.md_fpstate, l1->l_md.md_fpstate, sizeof(struct fpstate64)); } else l2->l_md.md_fpstate = NULL; /* * Setup (kernel) stack frame that will by-pass the child * out of the kernel. (The trap frame invariably resides at * the tippity-top of the u. area.) */ tf2 = l2->l_md.md_tf = (struct trapframe *) ((long)npcb + USPACE - sizeof(*tf2)); /* Copy parent's trapframe */ *tf2 = *(struct trapframe *)((long)opcb + USPACE - sizeof(*tf2)); /* * If specified, give the child a different stack. */ if (stack != NULL) tf2->tf_out[6] = (uint64_t)(u_long)stack + stacksize; /* * Set return values in child mode and clear condition code, * in case we end up running a signal handler before returning * to userland. */ tf2->tf_out[0] = 0; tf2->tf_out[1] = 1; tf2->tf_tstate &= ~TSTATE_CCR; /* Construct kernel frame to return to in cpu_switch() */ rp = (struct rwindow *)((u_long)npcb + TOPFRAMEOFF); *rp = *(struct rwindow *)((u_long)opcb + TOPFRAMEOFF); rp->rw_local[0] = (long)func; /* Function to call */ rp->rw_local[1] = (long)arg; /* and its argument */ rp->rw_local[2] = (long)l2; /* new lwp */ npcb->pcb_pc = (long)lwp_trampoline - 8; npcb->pcb_sp = (long)rp - STACK_OFFSET; }