sig_machdep.c revision 1.34
1/* $NetBSD: sig_machdep.c,v 1.34 2008/11/21 20:22:30 he Exp $ */ 2 3/* 4 * Copyright (C) 1995, 1996 Wolfgang Solfrank. 5 * Copyright (C) 1995, 1996 TooLs GmbH. 6 * All rights reserved. 7 * 8 * Redistribution and use in source and binary forms, with or without 9 * modification, are permitted provided that the following conditions 10 * are met: 11 * 1. Redistributions of source code must retain the above copyright 12 * notice, this list of conditions and the following disclaimer. 13 * 2. Redistributions in binary form must reproduce the above copyright 14 * notice, this list of conditions and the following disclaimer in the 15 * documentation and/or other materials provided with the distribution. 16 * 3. All advertising materials mentioning features or use of this software 17 * must display the following acknowledgement: 18 * This product includes software developed by TooLs GmbH. 19 * 4. The name of TooLs GmbH may not be used to endorse or promote products 20 * derived from this software without specific prior written permission. 21 * 22 * THIS SOFTWARE IS PROVIDED BY TOOLS GMBH ``AS IS'' AND ANY EXPRESS OR 23 * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES 24 * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. 25 * IN NO EVENT SHALL TOOLS GMBH BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, 26 * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, 27 * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; 28 * OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, 29 * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR 30 * OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF 31 * ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 32 */ 33 34#include <sys/cdefs.h> 35__KERNEL_RCSID(0, "$NetBSD: sig_machdep.c,v 1.34 2008/11/21 20:22:30 he Exp $"); 36 37#include "opt_ppcarch.h" 38#include "opt_altivec.h" 39 40#include <sys/param.h> 41#include <sys/mount.h> 42#include <sys/proc.h> 43#include <sys/syscallargs.h> 44#include <sys/systm.h> 45#include <sys/ucontext.h> 46#include <sys/user.h> 47 48#include <powerpc/fpu.h> 49#include <powerpc/altivec.h> 50 51/* 52 * Send a signal to process. 53 */ 54void 55sendsig_siginfo(const ksiginfo_t *ksi, const sigset_t *mask) 56{ 57 struct lwp * const l = curlwp; 58 struct proc * const p = l->l_proc; 59 struct trapframe * const tf = trapframe(l); 60 struct sigaltstack *ss = &l->l_sigstk; 61 const struct sigact_sigdesc *sd = 62 &p->p_sigacts->sa_sigdesc[ksi->ksi_signo]; 63 ucontext_t uc; 64 vaddr_t sp, sip, ucp; 65 int onstack, error; 66 67 /* Do we need to jump onto the signal stack? */ 68 onstack = (ss->ss_flags & (SS_DISABLE | SS_ONSTACK)) == 0 && 69 (sd->sd_sigact.sa_flags & SA_ONSTACK) != 0; 70 71 /* Find top of stack. */ 72 sp = (onstack ? (vaddr_t)ss->ss_sp + ss->ss_size : tf->fixreg[1]); 73 sp &= ~(CALLFRAMELEN-1); 74 75 /* Allocate space for the ucontext. */ 76 sp -= sizeof(ucontext_t); 77 ucp = sp; 78 79 /* Allocate space for the siginfo. */ 80 sp -= sizeof(siginfo_t); 81 sip = sp; 82 83 sp &= ~(CALLFRAMELEN-1); 84 85 /* Save register context. */ 86 uc.uc_flags = _UC_SIGMASK; 87 uc.uc_sigmask = *mask; 88 uc.uc_link = l->l_ctxlink; 89 memset(&uc.uc_stack, 0, sizeof(uc.uc_stack)); 90 sendsig_reset(l, ksi->ksi_signo); 91 mutex_exit(p->p_lock); 92 cpu_getmcontext(l, &uc.uc_mcontext, &uc.uc_flags); 93 94 /* 95 * Copy the siginfo and ucontext onto the user's stack. 96 */ 97 error = (copyout(&ksi->ksi_info, (void *)sip, sizeof(ksi->ksi_info)) != 0 || 98 copyout(&uc, (void *)ucp, sizeof(uc)) != 0); 99 mutex_enter(p->p_lock); 100 101 if (error) { 102 /* 103 * Process has trashed its stack; give it an illegal 104 * instruction to halt it in its tracks. 105 */ 106 sigexit(l, SIGILL); 107 /* NOTREACHED */ 108 } 109 110 /* 111 * Build context to run handler in. Note the trampoline version 112 * numbers are coordinated with machine-dependent code in libc. 113 */ 114 switch (sd->sd_vers) { 115 case 2: /* siginfo sigtramp */ 116 tf->fixreg[1] = (register_t)sp - CALLFRAMELEN; 117 tf->fixreg[3] = (register_t)ksi->ksi_signo; 118 tf->fixreg[4] = (register_t)sip; 119 tf->fixreg[5] = (register_t)ucp; 120 /* Preserve ucp across call to signal function */ 121 tf->fixreg[30] = (register_t)ucp; 122 tf->lr = (register_t)sd->sd_tramp; 123 tf->srr0 = (register_t)sd->sd_sigact.sa_handler; 124 break; 125 126 default: 127 goto nosupport; 128 } 129 130 /* Remember that we're now on the signal stack. */ 131 if (onstack) 132 ss->ss_flags |= SS_ONSTACK; 133 return; 134 135 nosupport: 136 /* Don't know what trampoline version; kill it. */ 137 printf("sendsig_siginfo(sig %d): bad version %d\n", 138 ksi->ksi_signo, sd->sd_vers); 139 sigexit(l, SIGILL); 140 /* NOTREACHED */ 141} 142 143void 144cpu_getmcontext(struct lwp *l, mcontext_t *mcp, unsigned int *flagp) 145{ 146 const struct trapframe *tf = trapframe(l); 147 __greg_t *gr = mcp->__gregs; 148#if defined(PPC_HAVE_FPU) || defined(ALTIVEC) 149 struct pcb *pcb = &l->l_addr->u_pcb; 150#endif 151 152 /* Save GPR context. */ 153 (void)memcpy(gr, &tf->fixreg, 32 * sizeof (gr[0])); /* GR0-31 */ 154 gr[_REG_CR] = tf->cr; 155 gr[_REG_LR] = tf->lr; 156 gr[_REG_PC] = tf->srr0; 157 gr[_REG_MSR] = tf->srr1 & PSL_USERSRR1; 158#ifdef PPC_HAVE_FPU 159 gr[_REG_MSR] |= pcb->pcb_flags & (PCB_FE0|PCB_FE1); 160#endif 161#ifdef ALTIVEC 162 gr[_REG_MSR] |= pcb->pcb_flags & PCB_ALTIVEC ? PSL_VEC : 0; 163#endif 164 gr[_REG_CTR] = tf->ctr; 165 gr[_REG_XER] = tf->xer; 166#ifdef PPC_OEA 167 gr[_REG_MQ] = tf->tf_xtra[TF_MQ]; 168#else 169 gr[_REG_MQ] = 0; 170#endif 171 *flagp |= _UC_CPU; 172 173#ifdef PPC_HAVE_FPU 174 /* Save FPR context, if any. */ 175 if ((pcb->pcb_flags & PCB_FPU) != 0) { 176 /* If we're the FPU owner, dump its context to the PCB first. */ 177 if (pcb->pcb_fpcpu) 178 save_fpu_lwp(l, FPU_SAVE); 179 (void)memcpy(mcp->__fpregs.__fpu_regs, pcb->pcb_fpu.fpreg, 180 sizeof (mcp->__fpregs.__fpu_regs)); 181 mcp->__fpregs.__fpu_fpscr = 182 ((int *)&pcb->pcb_fpu.fpscr)[_QUAD_LOWWORD]; 183 mcp->__fpregs.__fpu_valid = 1; 184 *flagp |= _UC_FPU; 185 } else 186#endif 187 memset(&mcp->__fpregs, 0, sizeof(mcp->__fpregs)); 188 189#ifdef ALTIVEC 190 /* Save AltiVec context, if any. */ 191 if ((pcb->pcb_flags & PCB_ALTIVEC) != 0) { 192 /* 193 * If we're the AltiVec owner, dump its context 194 * to the PCB first. 195 */ 196 if (pcb->pcb_veccpu) 197 save_vec_lwp(l, ALTIVEC_SAVE); 198 (void)memcpy(mcp->__vrf.__vrs, pcb->pcb_vr.vreg, 199 sizeof (mcp->__vrf.__vrs)); 200 mcp->__vrf.__vscr = pcb->pcb_vr.vscr; 201 mcp->__vrf.__vrsave = pcb->pcb_vr.vrsave; 202 *flagp |= _UC_POWERPC_VEC; 203 } else 204#endif 205 memset(&mcp->__vrf, 0, sizeof (mcp->__vrf)); 206} 207 208int 209cpu_setmcontext(struct lwp *l, const mcontext_t *mcp, unsigned int flags) 210{ 211 struct trapframe *tf = trapframe(l); 212 const __greg_t *gr = mcp->__gregs; 213#ifdef PPC_HAVE_FPU 214 struct pcb *pcb = &l->l_addr->u_pcb; 215#endif 216 217 /* Restore GPR context, if any. */ 218 if (flags & _UC_CPU) { 219#ifdef PPC_HAVE_FPU 220 /* 221 * Always save the FP exception mode in the PCB. 222 */ 223 pcb->pcb_flags &= ~(PCB_FE0|PCB_FE1); 224 pcb->pcb_flags |= gr[_REG_MSR] & (PCB_FE0|PCB_FE1); 225#endif 226 227 (void)memcpy(&tf->fixreg, gr, 32 * sizeof (gr[0])); 228 tf->cr = gr[_REG_CR]; 229 tf->lr = gr[_REG_LR]; 230 tf->srr0 = gr[_REG_PC]; 231 /* 232 * Accept all user-settable bits without complaint; 233 * userland should not need to know the machine-specific 234 * MSR value. 235 */ 236 tf->srr1 = (gr[_REG_MSR] & PSL_USERMOD) | PSL_USERSET; 237 tf->ctr = gr[_REG_CTR]; 238 tf->xer = gr[_REG_XER]; 239#ifdef PPC_OEA 240 tf->tf_xtra[TF_MQ] = gr[_REG_MQ]; 241#endif 242 } 243 244#ifdef PPC_HAVE_FPU /* Restore FPR context, if any. */ 245 if ((flags & _UC_FPU) && mcp->__fpregs.__fpu_valid != 0) { 246 /* we don't need to save the state, just drop it */ 247 save_fpu_lwp(l, FPU_DISCARD); 248 (void)memcpy(&pcb->pcb_fpu.fpreg, &mcp->__fpregs.__fpu_regs, 249 sizeof (pcb->pcb_fpu.fpreg)); 250 ((int *)&pcb->pcb_fpu.fpscr)[_QUAD_LOWWORD] = 251 mcp->__fpregs.__fpu_fpscr; 252 } 253#endif 254 255#ifdef ALTIVEC 256 /* Restore AltiVec context, if any. */ 257 if (flags & _UC_POWERPC_VEC) { 258 /* we don't need to save the state, just drop it */ 259 save_vec_lwp(l, ALTIVEC_DISCARD); 260 (void)memcpy(pcb->pcb_vr.vreg, &mcp->__vrf.__vrs, 261 sizeof (pcb->pcb_vr.vreg)); 262 pcb->pcb_vr.vscr = mcp->__vrf.__vscr; 263 pcb->pcb_vr.vrsave = mcp->__vrf.__vrsave; 264 } 265#endif 266 267 return (0); 268} 269