1 /*- 2 * Copyright (c) 1994-1995 S�ren Schmidt 3 * All rights reserved. 4 * 5 * Redistribution and use in source and binary forms, with or without 6 * modification, are permitted provided that the following conditions 7 * are met: 8 * 1. Redistributions of source code must retain the above copyright 9 * notice, this list of conditions and the following disclaimer 10 * in this position and unchanged. 11 * 2. Redistributions in binary form must reproduce the above copyright 12 * notice, this list of conditions and the following disclaimer in the 13 * documentation and/or other materials provided with the distribution. 14 * 3. The name of the author may not be used to endorse or promote products 15 * derived from this software withough specific prior written permission 16 * 17 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR 18 * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES 19 * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. 20 * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, 21 * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT 22 * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, 23 * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY 24 * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT 25 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF 26 * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 27 * 28 * $Id: linux_signal.c,v 1.5 1996/03/02 21:00:11 peter Exp $ 29 */ 30 31 #include <sys/param.h> 32 #include <sys/systm.h> 33 #include <sys/sysproto.h> 34 #include <sys/proc.h> 35 #include <sys/exec.h> 36 #include <sys/signal.h> 37 #include <sys/signalvar.h> 38 39 #include <i386/linux/linux.h> 40 #include <i386/linux/linux_proto.h> 41 #include <i386/linux/linux_util.h> 42 43 static sigset_t 44 linux_to_bsd_sigset(linux_sigset_t mask) { 45 int b, l; 46 sigset_t new = 0; 47 48 for (l = 1; l <= LINUX_NSIG; l++) { 49 if (mask & (1 << (l - 1))) { 50 if ((b = linux_to_bsd_signal[l])) 51 new |= (1 << (b - 1)); 52 } 53 } 54 return new; 55 } 56 57 static linux_sigset_t 58 bsd_to_linux_sigset(sigset_t mask) { 59 int b, l; 60 sigset_t new = 0; 61 62 for (b = 1; b <= NSIG; b++) { 63 if (mask & (1 << (b - 1))) { 64 if ((l = bsd_to_linux_signal[b])) 65 new |= (1 << (l - 1)); 66 } 67 } 68 return new; 69 } 70 71 static void 72 linux_to_bsd_sigaction(linux_sigaction_t *lsa, struct sigaction *bsa) 73 { 74 bsa->sa_mask = linux_to_bsd_sigset(lsa->sa_mask); 75 bsa->sa_handler = lsa->sa_handler; 76 bsa->sa_flags = 0; 77 if (lsa->sa_flags & LINUX_SA_NOCLDSTOP) 78 bsa->sa_flags |= SA_NOCLDSTOP; 79 if (lsa->sa_flags & LINUX_SA_ONSTACK) 80 bsa->sa_flags |= SA_ONSTACK; 81 if (lsa->sa_flags & LINUX_SA_RESTART) 82 bsa->sa_flags |= SA_RESTART; 83 if (lsa->sa_flags & LINUX_SA_ONESHOT) 84 bsa->sa_flags |= SA_RESETHAND; 85 if (lsa->sa_flags & LINUX_SA_NOMASK) 86 bsa->sa_flags |= SA_NODEFER; 87 } 88 89 static void 90 bsd_to_linux_sigaction(struct sigaction *bsa, linux_sigaction_t *lsa) 91 { 92 lsa->sa_handler = bsa->sa_handler; 93 lsa->sa_restorer = NULL; /* unsupported */ 94 lsa->sa_mask = bsd_to_linux_sigset(bsa->sa_mask); 95 lsa->sa_flags = 0; 96 if (bsa->sa_flags & SA_NOCLDSTOP) 97 lsa->sa_flags |= LINUX_SA_NOCLDSTOP; 98 if (bsa->sa_flags & SA_ONSTACK) 99 lsa->sa_flags |= LINUX_SA_ONSTACK; 100 if (bsa->sa_flags & SA_RESTART) 101 lsa->sa_flags |= LINUX_SA_RESTART; 102 if (bsa->sa_flags & SA_RESETHAND) 103 lsa->sa_flags |= LINUX_SA_ONESHOT; 104 if (bsa->sa_flags & SA_NODEFER) 105 lsa->sa_flags |= LINUX_SA_NOMASK; 106 } 107 108 int 109 linux_sigaction(struct proc *p, struct linux_sigaction_args *args, int *retval) 110 { 111 linux_sigaction_t linux_sa; 112 struct sigaction *nsa = NULL, *osa = NULL, bsd_sa; 113 struct sigaction_args sa; 114 int error; 115 caddr_t sg = stackgap_init(); 116 117 #ifdef DEBUG 118 printf("Linux-emul(%d): sigaction(%d, %08x, %08x)\n", p->p_pid, args->sig, 119 args->nsa, args->osa); 120 #endif 121 122 if (args->osa) 123 osa = (struct sigaction *)stackgap_alloc(&sg, sizeof(struct sigaction)); 124 125 if (args->nsa) { 126 nsa = (struct sigaction *)stackgap_alloc(&sg, sizeof(struct sigaction)); 127 if (error = copyin(args->nsa, &linux_sa, sizeof(linux_sigaction_t))) 128 return error; 129 linux_to_bsd_sigaction(&linux_sa, &bsd_sa); 130 if (error = copyout(&bsd_sa, nsa, sizeof(struct sigaction))) 131 return error; 132 } 133 sa.signum = linux_to_bsd_signal[args->sig]; 134 sa.nsa = nsa; 135 sa.osa = osa; 136 if ((error = sigaction(p, &sa, retval))) 137 return error; 138 139 if (args->osa) { 140 if (error = copyin(osa, &bsd_sa, sizeof(struct sigaction))) 141 return error; 142 bsd_to_linux_sigaction(&bsd_sa, &linux_sa); 143 if (error = copyout(&linux_sa, args->osa, sizeof(linux_sigaction_t))) 144 return error; 145 } 146 return 0; 147 } 148 149 int 150 linux_signal(struct proc *p, struct linux_signal_args *args, int *retval) 151 { 152 caddr_t sg; 153 struct sigaction_args sa_args; 154 struct sigaction *osa, *nsa, tmpsa; 155 int error; 156 157 #ifdef DEBUG 158 printf("Linux-emul(%d): signal(%d, %08x)\n", p->p_pid, 159 args->sig, args->handler); 160 #endif 161 sg = stackgap_init(); 162 nsa = stackgap_alloc(&sg, sizeof *nsa); 163 osa = stackgap_alloc(&sg, sizeof *osa); 164 165 tmpsa.sa_handler = args->handler; 166 tmpsa.sa_mask = (sigset_t) 0; 167 tmpsa.sa_flags = SA_RESETHAND | SA_NODEFER; 168 if ((error = copyout(&tmpsa, nsa, sizeof tmpsa))) 169 return error; 170 171 sa_args.signum = linux_to_bsd_signal[args->sig]; 172 sa_args.osa = osa; 173 sa_args.nsa = nsa; 174 if ((error = sigaction(p, &sa_args, retval))) 175 return error; 176 177 if ((error = copyin(osa, &tmpsa, sizeof *osa))) 178 return error; 179 180 *retval = (int)tmpsa.sa_handler; 181 182 return 0; 183 } 184 185 186 int 187 linux_sigprocmask(struct proc *p, struct linux_sigprocmask_args *args, 188 int *retval) 189 { 190 int error, s; 191 sigset_t mask; 192 sigset_t omask; 193 194 #ifdef DEBUG 195 printf("Linux-emul(%d): sigprocmask(%d, *, *)\n", p->p_pid, args->how); 196 #endif 197 198 *retval = 0; 199 200 if (args->omask != NULL) { 201 omask = bsd_to_linux_sigset(p->p_sigmask); 202 if (error = copyout(&omask, args->omask, sizeof(sigset_t))) 203 return error; 204 } 205 if (!(args->mask)) 206 return 0; 207 if (error = copyin(args->mask, &mask, sizeof(linux_sigset_t))) 208 return error; 209 210 mask = linux_to_bsd_sigset(mask); 211 s = splhigh(); 212 switch (args->how) { 213 case LINUX_SIG_BLOCK: 214 p->p_sigmask |= (mask & ~sigcantmask); 215 break; 216 case LINUX_SIG_UNBLOCK: 217 p->p_sigmask &= ~mask; 218 break; 219 case LINUX_SIG_SETMASK: 220 p->p_sigmask = (mask & ~sigcantmask); 221 break; 222 default: 223 error = EINVAL; 224 break; 225 } 226 splx(s); 227 return error; 228 } 229 230 int 231 linux_siggetmask(struct proc *p, struct linux_siggetmask_args *args, int *retval) 232 { 233 #ifdef DEBUG 234 printf("Linux-emul(%d): siggetmask()\n", p->p_pid); 235 #endif 236 *retval = bsd_to_linux_sigset(p->p_sigmask); 237 return 0; 238 } 239 240 int 241 linux_sigsetmask(struct proc *p, struct linux_sigsetmask_args *args,int *retval) 242 { 243 int s; 244 sigset_t mask; 245 246 #ifdef DEBUG 247 printf("Linux-emul(%d): sigsetmask(%08x)\n", p->p_pid, args->mask); 248 #endif 249 *retval = bsd_to_linux_sigset(p->p_sigmask); 250 251 mask = linux_to_bsd_sigset(args->mask); 252 s = splhigh(); 253 p->p_sigmask = mask & ~sigcantmask; 254 splx(s); 255 return 0; 256 } 257 258 int 259 linux_sigpending(struct proc *p, struct linux_sigpending_args *args,int *retval) 260 { 261 linux_sigset_t linux_sig; 262 263 #ifdef DEBUG 264 printf("Linux-emul(%d): sigpending(*)\n", p->p_pid); 265 #endif 266 linux_sig = bsd_to_linux_sigset(p->p_siglist & p->p_sigmask); 267 return copyout(&linux_sig, args->mask, sizeof(linux_sig)); 268 } 269 270 /* 271 * Linux has two extra args, restart and oldmask. We dont use these, 272 * but it seems that "restart" is actually a context pointer that 273 * enables the signal to happen with a different register set. 274 */ 275 int 276 linux_sigsuspend(struct proc *p, struct linux_sigsuspend_args *args,int *retval) 277 { 278 struct sigsuspend_args tmp; 279 280 #ifdef DEBUG 281 printf("Linux-emul(%d): sigsuspend(%08x)\n", p->p_pid, args->mask); 282 #endif 283 tmp.mask = linux_to_bsd_sigset(args->mask); 284 return sigsuspend(p, &tmp , retval); 285 } 286 287 int 288 linux_pause(struct proc *p, struct linux_pause_args *args,int *retval) 289 { 290 struct sigsuspend_args tmp; 291 292 #ifdef DEBUG 293 printf("Linux-emul(%d): pause()\n", p->p_pid); 294 #endif 295 tmp.mask = p->p_sigmask; 296 return sigsuspend(p, &tmp , retval); 297 } 298 299 int 300 linux_kill(struct proc *p, struct linux_kill_args *args, int *retval) 301 { 302 struct kill_args /* { 303 int pid; 304 int signum; 305 } */ tmp; 306 307 #ifdef DEBUG 308 printf("Linux-emul(%d): kill(%d, %d)\n", 309 p->p_pid, args->pid, args->signum); 310 #endif 311 tmp.pid = args->pid; 312 tmp.signum = linux_to_bsd_signal[args->signum]; 313 return kill(p, &tmp, retval); 314 } 315