int suword32_nowatch(void *addr, uint32_t value) { int watched, ret; watched = watch_disable_addr(addr, sizeof (value), S_WRITE); ret = suword32(addr, value); if (watched) watch_enable_addr(addr, sizeof (value), S_WRITE); return (ret); }
int fuword32_nowatch(const void *addr, uint32_t *value) { int watched, ret; watched = watch_disable_addr(addr, sizeof (*value), S_READ); ret = fuword32(addr, value); if (watched) watch_enable_addr(addr, sizeof (*value), S_READ); return (ret); }
int copyout_nowatch(const void *kaddr, void *uaddr, size_t len) { int watched, ret; watched = watch_disable_addr(uaddr, len, S_WRITE); ret = copyout(kaddr, uaddr, len); if (watched) watch_enable_addr(uaddr, len, S_WRITE); return (ret); }
int copyin_nowatch(const void *uaddr, void *kaddr, size_t len) { int watched, ret; watched = watch_disable_addr(uaddr, len, S_READ); ret = copyin(uaddr, kaddr, len); if (watched) watch_enable_addr(uaddr, len, S_READ); return (ret); }
/*ARGSUSED1*/ void xregrestore(klwp_t *lwp, int shared) { /* * If locals+ins were modified by /proc copy them out. * Also copy to the shared window, if necessary. */ if (lwp->lwp_pcb.pcb_xregstat == XREGMODIFIED) { struct machpcb *mpcb = lwptompcb(lwp); caddr_t sp = (caddr_t)lwptoregs(lwp)->r_sp; size_t rwinsize; caddr_t rwp; int is64; if (lwp_getdatamodel(lwp) == DATAMODEL_LP64) { rwinsize = sizeof (struct rwindow); rwp = sp + STACK_BIAS; is64 = 1; } else { rwinsize = sizeof (struct rwindow32); sp = (caddr_t)(uintptr_t)(caddr32_t)(uintptr_t)sp; rwp = sp; is64 = 0; } if (is64) (void) copyout_nowatch(&lwp->lwp_pcb.pcb_xregs, rwp, rwinsize); else { struct rwindow32 rwindow32; int watched; watched = watch_disable_addr(rwp, rwinsize, S_WRITE); rwindow_nto32(&lwp->lwp_pcb.pcb_xregs, &rwindow32); (void) copyout(&rwindow32, rwp, rwinsize); if (watched) watch_enable_addr(rwp, rwinsize, S_WRITE); } /* also copy to the user return window */ mpcb->mpcb_rsp[0] = sp; mpcb->mpcb_rsp[1] = NULL; bcopy(&lwp->lwp_pcb.pcb_xregs, &mpcb->mpcb_rwin[0], sizeof (lwp->lwp_pcb.pcb_xregs)); } lwp->lwp_pcb.pcb_xregstat = XREGNONE; }
int sendsig(int sig, k_siginfo_t *sip, void (*hdlr)()) { volatile int minstacksz; int newstack; label_t ljb; volatile caddr_t sp; caddr_t fp; struct regs *rp; volatile greg_t upc; volatile proc_t *p = ttoproc(curthread); klwp_t *lwp = ttolwp(curthread); ucontext_t *volatile tuc = NULL; ucontext_t *uc; siginfo_t *sip_addr; volatile int watched; rp = lwptoregs(lwp); upc = rp->r_pc; minstacksz = SA(sizeof (struct sigframe)) + SA(sizeof (*uc)); if (sip != NULL) minstacksz += SA(sizeof (siginfo_t)); ASSERT((minstacksz & (STACK_ALIGN - 1ul)) == 0); /* * Figure out whether we will be handling this signal on * an alternate stack specified by the user. Then allocate * and validate the stack requirements for the signal handler * context. on_fault will catch any faults. */ newstack = sigismember(&PTOU(curproc)->u_sigonstack, sig) && !(lwp->lwp_sigaltstack.ss_flags & (SS_ONSTACK|SS_DISABLE)); if (newstack) { fp = (caddr_t)(SA((uintptr_t)lwp->lwp_sigaltstack.ss_sp) + SA(lwp->lwp_sigaltstack.ss_size) - STACK_ALIGN); } else if ((rp->r_ss & 0xffff) != UDS_SEL) { user_desc_t *ldt; /* * If the stack segment selector is -not- pointing at * the UDS_SEL descriptor and we have an LDT entry for * it instead, add the base address to find the effective va. */ if ((ldt = p->p_ldt) != NULL) fp = (caddr_t)rp->r_sp + USEGD_GETBASE(&ldt[SELTOIDX(rp->r_ss)]); else fp = (caddr_t)rp->r_sp; } else fp = (caddr_t)rp->r_sp; /* * Force proper stack pointer alignment, even in the face of a * misaligned stack pointer from user-level before the signal. * Don't use the SA() macro because that rounds up, not down. */ fp = (caddr_t)((uintptr_t)fp & ~(STACK_ALIGN - 1ul)); sp = fp - minstacksz; /* * Make sure lwp hasn't trashed its stack. */ if (sp >= (caddr_t)USERLIMIT || fp >= (caddr_t)USERLIMIT) { #ifdef DEBUG printf("sendsig: bad signal stack cmd=%s, pid=%d, sig=%d\n", PTOU(p)->u_comm, p->p_pid, sig); printf("sigsp = 0x%p, action = 0x%p, upc = 0x%lx\n", (void *)sp, (void *)hdlr, (uintptr_t)upc); printf("sp above USERLIMIT\n"); #endif return (0); } watched = watch_disable_addr((caddr_t)sp, minstacksz, S_WRITE); if (on_fault(&ljb)) goto badstack; if (sip != NULL) { zoneid_t zoneid; fp -= SA(sizeof (siginfo_t)); uzero(fp, sizeof (siginfo_t)); if (SI_FROMUSER(sip) && (zoneid = p->p_zone->zone_id) != GLOBAL_ZONEID && zoneid != sip->si_zoneid) { k_siginfo_t sani_sip = *sip; sani_sip.si_pid = p->p_zone->zone_zsched->p_pid; sani_sip.si_uid = 0; sani_sip.si_ctid = -1; sani_sip.si_zoneid = zoneid; copyout_noerr(&sani_sip, fp, sizeof (sani_sip)); } else copyout_noerr(sip, fp, sizeof (*sip)); sip_addr = (siginfo_t *)fp; if (sig == SIGPROF && curthread->t_rprof != NULL && curthread->t_rprof->rp_anystate) { /* * We stand on our head to deal with * the real time profiling signal. * Fill in the stuff that doesn't fit * in a normal k_siginfo structure. */ int i = sip->si_nsysarg; while (--i >= 0) suword32_noerr(&(sip_addr->si_sysarg[i]), (uint32_t)lwp->lwp_arg[i]); copyout_noerr(curthread->t_rprof->rp_state, sip_addr->si_mstate, sizeof (curthread->t_rprof->rp_state)); } } else sip_addr = NULL; /* save the current context on the user stack */ fp -= SA(sizeof (*tuc)); uc = (ucontext_t *)fp; tuc = kmem_alloc(sizeof (*tuc), KM_SLEEP); savecontext(tuc, &lwp->lwp_sigoldmask); copyout_noerr(tuc, uc, sizeof (*tuc)); kmem_free(tuc, sizeof (*tuc)); tuc = NULL; lwp->lwp_oldcontext = (uintptr_t)uc; if (newstack) { lwp->lwp_sigaltstack.ss_flags |= SS_ONSTACK; if (lwp->lwp_ustack) copyout_noerr(&lwp->lwp_sigaltstack, (stack_t *)lwp->lwp_ustack, sizeof (stack_t)); } /* * Set up signal handler arguments */ { struct sigframe frame; frame.sip = sip_addr; frame.ucp = uc; frame.signo = sig; frame.retaddr = (void (*)())0xffffffff; /* never return! */ copyout_noerr(&frame, sp, sizeof (frame)); } no_fault(); if (watched) watch_enable_addr((caddr_t)sp, minstacksz, S_WRITE); rp->r_sp = (greg_t)sp; rp->r_pc = (greg_t)hdlr; rp->r_ps = PSL_USER | (rp->r_ps & PS_IOPL); if ((rp->r_cs & 0xffff) != UCS_SEL || (rp->r_ss & 0xffff) != UDS_SEL) { rp->r_cs = UCS_SEL; rp->r_ss = UDS_SEL; } /* * Don't set lwp_eosys here. sendsig() is called via psig() after * lwp_eosys is handled, so setting it here would affect the next * system call. */ return (1); badstack: no_fault(); if (watched) watch_enable_addr((caddr_t)sp, minstacksz, S_WRITE); if (tuc) kmem_free(tuc, sizeof (*tuc)); #ifdef DEBUG printf("sendsig: bad signal stack cmd=%s, pid=%d, sig=%d\n", PTOU(p)->u_comm, p->p_pid, sig); printf("on fault, sigsp = 0x%p, action = 0x%p, upc = 0x%lx\n", (void *)sp, (void *)hdlr, (uintptr_t)upc); #endif return (0); }
int sendsig(int sig, k_siginfo_t *sip, void (*hdlr)()) { volatile int minstacksz; int newstack; label_t ljb; volatile caddr_t sp; caddr_t fp; volatile struct regs *rp; volatile greg_t upc; volatile proc_t *p = ttoproc(curthread); struct as *as = p->p_as; klwp_t *lwp = ttolwp(curthread); ucontext_t *volatile tuc = NULL; ucontext_t *uc; siginfo_t *sip_addr; volatile int watched; /* * This routine is utterly dependent upon STACK_ALIGN being * 16 and STACK_ENTRY_ALIGN being 8. Let's just acknowledge * that and require it. */ #if STACK_ALIGN != 16 || STACK_ENTRY_ALIGN != 8 #error "sendsig() amd64 did not find the expected stack alignments" #endif rp = lwptoregs(lwp); upc = rp->r_pc; /* * Since we're setting up to run the signal handler we have to * arrange that the stack at entry to the handler is (only) * STACK_ENTRY_ALIGN (i.e. 8) byte aligned so that when the handler * executes its push of %rbp, the stack realigns to STACK_ALIGN * (i.e. 16) correctly. * * The new sp will point to the sigframe and the ucontext_t. The * above means that sp (and thus sigframe) will be 8-byte aligned, * but not 16-byte aligned. ucontext_t, however, contains %xmm regs * which must be 16-byte aligned. Because of this, for correct * alignment, sigframe must be a multiple of 8-bytes in length, but * not 16-bytes. This will place ucontext_t at a nice 16-byte boundary. */ /* LINTED: logical expression always true: op "||" */ ASSERT((sizeof (struct sigframe) % 16) == 8); minstacksz = sizeof (struct sigframe) + SA(sizeof (*uc)); if (sip != NULL) minstacksz += SA(sizeof (siginfo_t)); ASSERT((minstacksz & (STACK_ENTRY_ALIGN - 1ul)) == 0); /* * Figure out whether we will be handling this signal on * an alternate stack specified by the user. Then allocate * and validate the stack requirements for the signal handler * context. on_fault will catch any faults. */ newstack = sigismember(&PTOU(curproc)->u_sigonstack, sig) && !(lwp->lwp_sigaltstack.ss_flags & (SS_ONSTACK|SS_DISABLE)); if (newstack) { fp = (caddr_t)(SA((uintptr_t)lwp->lwp_sigaltstack.ss_sp) + SA(lwp->lwp_sigaltstack.ss_size) - STACK_ALIGN); } else { /* * Drop below the 128-byte reserved region of the stack frame * we're interrupting. */ fp = (caddr_t)rp->r_sp - STACK_RESERVE; } /* * Force proper stack pointer alignment, even in the face of a * misaligned stack pointer from user-level before the signal. */ fp = (caddr_t)((uintptr_t)fp & ~(STACK_ENTRY_ALIGN - 1ul)); /* * Most of the time during normal execution, the stack pointer * is aligned on a STACK_ALIGN (i.e. 16 byte) boundary. However, * (for example) just after a call instruction (which pushes * the return address), the callers stack misaligns until the * 'push %rbp' happens in the callee prolog. So while we should * expect the stack pointer to be always at least STACK_ENTRY_ALIGN * aligned, we should -not- expect it to always be STACK_ALIGN aligned. * We now adjust to ensure that the new sp is aligned to * STACK_ENTRY_ALIGN but not to STACK_ALIGN. */ sp = fp - minstacksz; if (((uintptr_t)sp & (STACK_ALIGN - 1ul)) == 0) { sp -= STACK_ENTRY_ALIGN; minstacksz = fp - sp; } /* * Now, make sure the resulting signal frame address is sane */ if (sp >= as->a_userlimit || fp >= as->a_userlimit) { #ifdef DEBUG printf("sendsig: bad signal stack cmd=%s, pid=%d, sig=%d\n", PTOU(p)->u_comm, p->p_pid, sig); printf("sigsp = 0x%p, action = 0x%p, upc = 0x%lx\n", (void *)sp, (void *)hdlr, (uintptr_t)upc); printf("sp above USERLIMIT\n"); #endif return (0); } watched = watch_disable_addr((caddr_t)sp, minstacksz, S_WRITE); if (on_fault(&ljb)) goto badstack; if (sip != NULL) { zoneid_t zoneid; fp -= SA(sizeof (siginfo_t)); uzero(fp, sizeof (siginfo_t)); if (SI_FROMUSER(sip) && (zoneid = p->p_zone->zone_id) != GLOBAL_ZONEID && zoneid != sip->si_zoneid) { k_siginfo_t sani_sip = *sip; sani_sip.si_pid = p->p_zone->zone_zsched->p_pid; sani_sip.si_uid = 0; sani_sip.si_ctid = -1; sani_sip.si_zoneid = zoneid; copyout_noerr(&sani_sip, fp, sizeof (sani_sip)); } else copyout_noerr(sip, fp, sizeof (*sip)); sip_addr = (siginfo_t *)fp; if (sig == SIGPROF && curthread->t_rprof != NULL && curthread->t_rprof->rp_anystate) { /* * We stand on our head to deal with * the real time profiling signal. * Fill in the stuff that doesn't fit * in a normal k_siginfo structure. */ int i = sip->si_nsysarg; while (--i >= 0) sulword_noerr( (ulong_t *)&(sip_addr->si_sysarg[i]), (ulong_t)lwp->lwp_arg[i]); copyout_noerr(curthread->t_rprof->rp_state, sip_addr->si_mstate, sizeof (curthread->t_rprof->rp_state)); } } else sip_addr = NULL; /* * save the current context on the user stack directly after the * sigframe. Since sigframe is 8-byte-but-not-16-byte aligned, * and since sizeof (struct sigframe) is 24, this guarantees * 16-byte alignment for ucontext_t and its %xmm registers. */ uc = (ucontext_t *)(sp + sizeof (struct sigframe)); tuc = kmem_alloc(sizeof (*tuc), KM_SLEEP); no_fault(); savecontext(tuc, &lwp->lwp_sigoldmask); if (on_fault(&ljb)) goto badstack; copyout_noerr(tuc, uc, sizeof (*tuc)); kmem_free(tuc, sizeof (*tuc)); tuc = NULL; lwp->lwp_oldcontext = (uintptr_t)uc; if (newstack) { lwp->lwp_sigaltstack.ss_flags |= SS_ONSTACK; if (lwp->lwp_ustack) copyout_noerr(&lwp->lwp_sigaltstack, (stack_t *)lwp->lwp_ustack, sizeof (stack_t)); } /* * Set up signal handler return and stack linkage */ { struct sigframe frame; /* * ensure we never return "normally" */ frame.retaddr = (caddr_t)(uintptr_t)-1L; frame.signo = sig; frame.sip = sip_addr; copyout_noerr(&frame, sp, sizeof (frame)); } no_fault(); if (watched) watch_enable_addr((caddr_t)sp, minstacksz, S_WRITE); /* * Set up user registers for execution of signal handler. */ rp->r_sp = (greg_t)sp; rp->r_pc = (greg_t)hdlr; rp->r_ps = PSL_USER | (rp->r_ps & PS_IOPL); rp->r_rdi = sig; rp->r_rsi = (uintptr_t)sip_addr; rp->r_rdx = (uintptr_t)uc; if ((rp->r_cs & 0xffff) != UCS_SEL || (rp->r_ss & 0xffff) != UDS_SEL) { /* * Try our best to deliver the signal. */ rp->r_cs = UCS_SEL; rp->r_ss = UDS_SEL; } /* * Don't set lwp_eosys here. sendsig() is called via psig() after * lwp_eosys is handled, so setting it here would affect the next * system call. */ return (1); badstack: no_fault(); if (watched) watch_enable_addr((caddr_t)sp, minstacksz, S_WRITE); if (tuc) kmem_free(tuc, sizeof (*tuc)); #ifdef DEBUG printf("sendsig: bad signal stack cmd=%s, pid=%d, sig=%d\n", PTOU(p)->u_comm, p->p_pid, sig); printf("on fault, sigsp = 0x%p, action = 0x%p, upc = 0x%lx\n", (void *)sp, (void *)hdlr, (uintptr_t)upc); #endif return (0); }