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