1 /* $NetBSD: sig_machdep.c,v 1.38 2011/01/18 01:02:55 matt 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.38 2011/01/18 01:02:55 matt 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 47 #include <uvm/uvm_extern.h> 48 49 #include <powerpc/fpu.h> 50 #include <powerpc/altivec.h> 51 #include <powerpc/pcb.h> 52 53 /* 54 * Send a signal to process. 55 */ 56 void 57 sendsig_siginfo(const ksiginfo_t *ksi, const sigset_t *mask) 58 { 59 struct lwp * const l = curlwp; 60 struct proc * const p = l->l_proc; 61 struct trapframe * const tf = trapframe(l); 62 struct sigaltstack *ss = &l->l_sigstk; 63 const struct sigact_sigdesc *sd = 64 &p->p_sigacts->sa_sigdesc[ksi->ksi_signo]; 65 ucontext_t uc; 66 vaddr_t sp, sip, ucp; 67 int onstack, error; 68 69 /* Do we need to jump onto the signal stack? */ 70 onstack = (ss->ss_flags & (SS_DISABLE | SS_ONSTACK)) == 0 && 71 (sd->sd_sigact.sa_flags & SA_ONSTACK) != 0; 72 73 /* Find top of stack. */ 74 sp = (onstack ? (vaddr_t)ss->ss_sp + ss->ss_size : tf->tf_fixreg[1]); 75 sp &= ~(CALLFRAMELEN-1); 76 77 /* Allocate space for the ucontext. */ 78 sp -= sizeof(ucontext_t); 79 ucp = sp; 80 81 /* Allocate space for the siginfo. */ 82 sp -= sizeof(siginfo_t); 83 sip = sp; 84 85 sp &= ~(CALLFRAMELEN-1); 86 87 /* Save register context. */ 88 uc.uc_flags = _UC_SIGMASK; 89 uc.uc_sigmask = *mask; 90 uc.uc_link = l->l_ctxlink; 91 memset(&uc.uc_stack, 0, sizeof(uc.uc_stack)); 92 sendsig_reset(l, ksi->ksi_signo); 93 mutex_exit(p->p_lock); 94 cpu_getmcontext(l, &uc.uc_mcontext, &uc.uc_flags); 95 96 /* 97 * Copy the siginfo and ucontext onto the user's stack. 98 */ 99 error = (copyout(&ksi->ksi_info, (void *)sip, sizeof(ksi->ksi_info)) != 0 || 100 copyout(&uc, (void *)ucp, sizeof(uc)) != 0); 101 mutex_enter(p->p_lock); 102 103 if (error) { 104 /* 105 * Process has trashed its stack; give it an illegal 106 * instruction to halt it in its tracks. 107 */ 108 sigexit(l, SIGILL); 109 /* NOTREACHED */ 110 } 111 112 /* 113 * Build context to run handler in. Note the trampoline version 114 * numbers are coordinated with machine-dependent code in libc. 115 */ 116 switch (sd->sd_vers) { 117 case 2: /* siginfo sigtramp */ 118 tf->tf_fixreg[1] = (register_t)sp - CALLFRAMELEN; 119 tf->tf_fixreg[3] = (register_t)ksi->ksi_signo; 120 tf->tf_fixreg[4] = (register_t)sip; 121 tf->tf_fixreg[5] = (register_t)ucp; 122 /* Preserve ucp across call to signal function */ 123 tf->tf_fixreg[30] = (register_t)ucp; 124 tf->tf_lr = (register_t)sd->sd_tramp; 125 tf->tf_srr0 = (register_t)sd->sd_sigact.sa_handler; 126 break; 127 128 default: 129 goto nosupport; 130 } 131 132 /* Remember that we're now on the signal stack. */ 133 if (onstack) 134 ss->ss_flags |= SS_ONSTACK; 135 return; 136 137 nosupport: 138 /* Don't know what trampoline version; kill it. */ 139 printf("sendsig_siginfo(sig %d): bad version %d\n", 140 ksi->ksi_signo, sd->sd_vers); 141 sigexit(l, SIGILL); 142 /* NOTREACHED */ 143 } 144 145 void 146 cpu_getmcontext(struct lwp *l, mcontext_t *mcp, unsigned int *flagp) 147 { 148 const struct trapframe * const tf = trapframe(l); 149 __greg_t * const gr = mcp->__gregs; 150 #if defined(PPC_HAVE_FPU) 151 struct pcb * const pcb = lwp_getpcb(l); 152 #endif 153 154 /* Save GPR context. */ 155 (void)memcpy(gr, &tf->tf_fixreg, 32 * sizeof (gr[0])); /* GR0-31 */ 156 gr[_REG_CR] = tf->tf_cr; 157 gr[_REG_LR] = tf->tf_lr; 158 gr[_REG_PC] = tf->tf_srr0; 159 gr[_REG_MSR] = tf->tf_srr1 & PSL_USERSRR1; 160 #ifdef PPC_HAVE_FPU 161 gr[_REG_MSR] |= pcb->pcb_flags & (PCB_FE0|PCB_FE1); 162 #endif 163 gr[_REG_CTR] = tf->tf_ctr; 164 gr[_REG_XER] = tf->tf_xer; 165 #ifdef PPC_OEA 166 gr[_REG_MQ] = tf->tf_mq; 167 #else 168 gr[_REG_MQ] = 0; 169 #endif 170 171 *flagp |= _UC_CPU; 172 173 #ifdef PPC_HAVE_FPU 174 /* Save FPU context, if any. */ 175 if (!fpu_save_to_mcontext(l, mcp, flagp)) 176 #endif 177 memset(&mcp->__fpregs, 0, sizeof(mcp->__fpregs)); 178 179 #if defined(ALTIVEC) || defined(PPC_HAVE_SPE) 180 /* Save vector context, if any. */ 181 if (!vec_save_to_mcontext(l, mcp, flagp)) 182 #endif 183 memset(&mcp->__vrf, 0, sizeof (mcp->__vrf)); 184 } 185 186 int 187 cpu_setmcontext(struct lwp *l, const mcontext_t *mcp, unsigned int flags) 188 { 189 struct trapframe * const tf = trapframe(l); 190 const __greg_t * const gr = mcp->__gregs; 191 192 /* Restore GPR context, if any. */ 193 if (flags & _UC_CPU) { 194 #ifdef PPC_HAVE_FPU 195 /* 196 * Always save the FP exception mode in the PCB. 197 */ 198 struct pcb * const pcb = lwp_getpcb(l); 199 pcb->pcb_flags &= ~(PCB_FE0|PCB_FE1); 200 pcb->pcb_flags |= gr[_REG_MSR] & (PCB_FE0|PCB_FE1); 201 #endif 202 203 (void)memcpy(&tf->tf_fixreg, gr, 32 * sizeof (gr[0])); 204 tf->tf_cr = gr[_REG_CR]; 205 tf->tf_lr = gr[_REG_LR]; 206 tf->tf_srr0 = gr[_REG_PC]; 207 /* 208 * Accept all user-settable bits without complaint; 209 * userland should not need to know the machine-specific 210 * MSR value. 211 */ 212 tf->tf_srr1 = (gr[_REG_MSR] & PSL_USERMOD) | PSL_USERSET; 213 tf->tf_ctr = gr[_REG_CTR]; 214 tf->tf_xer = gr[_REG_XER]; 215 #ifdef PPC_OEA 216 tf->tf_mq = gr[_REG_MQ]; 217 #endif 218 } 219 220 #ifdef PPC_HAVE_FPU 221 /* Restore FPU context, if any. */ 222 if (flags & _UC_FPU) 223 fpu_restore_from_mcontext(l, mcp); 224 #endif 225 226 #ifdef ALTIVEC 227 /* Restore AltiVec context, if any. */ 228 if (flags & _UC_POWERPC_VEC) 229 vec_restore_from_mcontext(l, mcp); 230 #endif 231 232 #ifdef PPC_HAVE_SPE 233 /* Restore SPE context, if any. */ 234 if (flags & _UC_POWERPC_SPE) 235 vec_restore_from_mcontext(l, mcp); 236 #endif 237 238 return (0); 239 } 240