]> CyberLeo.Net >> Repos - FreeBSD/FreeBSD.git/blob - sys/i386/linux/linux_signal.c
unfinished sblive driver, playback/mixer only for now - not enabled in
[FreeBSD/FreeBSD.git] / sys / i386 / linux / linux_signal.c
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  * $FreeBSD$
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/signalvar.h>
36
37 #include <i386/linux/linux.h>
38 #include <i386/linux/linux_proto.h>
39 #include <i386/linux/linux_util.h>
40
41 static void
42 linux_to_bsd_sigset(linux_sigset_t *lss, sigset_t *bss)
43 {
44         int b, l;
45
46         SIGEMPTYSET(*bss);
47         bss->__bits[0] = lss->__bits[0] & ~((1U << LINUX_SIGTBLSZ) - 1);
48         bss->__bits[1] = lss->__bits[1];
49         for (l = 1; l <= LINUX_SIGTBLSZ; l++) {
50                 if (LINUX_SIGISMEMBER(*lss, l)) {
51                         b = linux_to_bsd_signal[_SIG_IDX(l)];
52                         if (b)
53                                 SIGADDSET(*bss, b);
54                 }
55         }
56 }
57
58 static void
59 bsd_to_linux_sigset(sigset_t *bss, linux_sigset_t *lss)
60 {
61         int b, l;
62
63         LINUX_SIGEMPTYSET(*lss);
64         lss->__bits[0] = bss->__bits[0] & ~((1U << LINUX_SIGTBLSZ) - 1);
65         lss->__bits[1] = bss->__bits[1];
66         for (b = 1; b <= LINUX_SIGTBLSZ; b++) {
67                 if (SIGISMEMBER(*bss, b)) {
68                         l = bsd_to_linux_signal[_SIG_IDX(b)];
69                         if (l)
70                                 LINUX_SIGADDSET(*lss, l);
71                 }
72         }
73 }
74
75 static void
76 linux_to_bsd_sigaction(linux_sigaction_t *lsa, struct sigaction *bsa)
77 {
78
79         linux_to_bsd_sigset(&lsa->lsa_mask, &bsa->sa_mask);
80         bsa->sa_handler = lsa->lsa_handler;
81         bsa->sa_flags = 0;
82         if (lsa->lsa_flags & LINUX_SA_NOCLDSTOP)
83                 bsa->sa_flags |= SA_NOCLDSTOP;
84         if (lsa->lsa_flags & LINUX_SA_NOCLDWAIT)
85                 bsa->sa_flags |= SA_NOCLDWAIT;
86         if (lsa->lsa_flags & LINUX_SA_SIGINFO)
87                 bsa->sa_flags |= SA_SIGINFO;
88         if (lsa->lsa_flags & LINUX_SA_ONSTACK)
89                 bsa->sa_flags |= SA_ONSTACK;
90         if (lsa->lsa_flags & LINUX_SA_RESTART)
91                 bsa->sa_flags |= SA_RESTART;
92         if (lsa->lsa_flags & LINUX_SA_ONESHOT)
93                 bsa->sa_flags |= SA_RESETHAND;
94         if (lsa->lsa_flags & LINUX_SA_NOMASK)
95                 bsa->sa_flags |= SA_NODEFER;
96 }
97
98 static void
99 bsd_to_linux_sigaction(struct sigaction *bsa, linux_sigaction_t *lsa)
100 {
101
102         bsd_to_linux_sigset(&bsa->sa_mask, &lsa->lsa_mask);
103         lsa->lsa_handler = bsa->sa_handler;
104         lsa->lsa_restorer = NULL;       /* unsupported */
105         lsa->lsa_flags = 0;
106         if (bsa->sa_flags & SA_NOCLDSTOP)
107                 lsa->lsa_flags |= LINUX_SA_NOCLDSTOP;
108         if (bsa->sa_flags & SA_NOCLDWAIT)
109                 lsa->lsa_flags |= LINUX_SA_NOCLDWAIT;
110         if (bsa->sa_flags & SA_SIGINFO)
111                 lsa->lsa_flags |= LINUX_SA_SIGINFO;
112         if (bsa->sa_flags & SA_ONSTACK)
113                 lsa->lsa_flags |= LINUX_SA_ONSTACK;
114         if (bsa->sa_flags & SA_RESTART)
115                 lsa->lsa_flags |= LINUX_SA_RESTART;
116         if (bsa->sa_flags & SA_RESETHAND)
117                 lsa->lsa_flags |= LINUX_SA_ONESHOT;
118         if (bsa->sa_flags & SA_NODEFER)
119                 lsa->lsa_flags |= LINUX_SA_NOMASK;
120 }
121
122 static int
123 linux_do_sigaction(struct proc *p, int linux_sig, linux_sigaction_t *linux_nsa,
124                    linux_sigaction_t *linux_osa)
125 {
126         struct sigaction *nsa, *osa;
127         struct sigaction_args sa_args;
128         int error;
129         caddr_t sg = stackgap_init();
130
131         if (linux_sig <= 0 || linux_sig > LINUX_NSIG)
132                 return (EINVAL);
133
134         if (linux_osa != NULL)
135                 osa = stackgap_alloc(&sg, sizeof(struct sigaction));
136         else
137                 osa = NULL;
138
139         if (linux_nsa != NULL) {
140                 nsa = stackgap_alloc(&sg, sizeof(struct sigaction));
141                 linux_to_bsd_sigaction(linux_nsa, nsa);
142         }
143         else
144                 nsa = NULL;
145
146         if (linux_sig <= LINUX_SIGTBLSZ)
147                 sa_args.sig = linux_to_bsd_signal[_SIG_IDX(linux_sig)];
148         else
149                 sa_args.sig = linux_sig;
150
151         sa_args.act = nsa;
152         sa_args.oact = osa;
153         error = sigaction(p, &sa_args);
154         if (error)
155                 return (error);
156
157         if (linux_osa != NULL)
158                 bsd_to_linux_sigaction(osa, linux_osa);
159
160         return (0);
161 }
162
163 int
164 linux_sigaction(struct proc *p, struct linux_sigaction_args *args)
165 {
166         linux_osigaction_t osa;
167         linux_sigaction_t act, oact;
168         int error;
169
170 #ifdef DEBUG
171         printf("Linux-emul(%ld): sigaction(%d, %p, %p)\n", (long)p->p_pid,
172                args->sig, (void *)args->nsa, (void *)args->osa);
173 #endif
174
175         if (args->nsa != NULL) {
176                 error = copyin(args->nsa, &osa, sizeof(linux_osigaction_t));
177                 if (error)
178                         return (error);
179                 act.lsa_handler = osa.lsa_handler;
180                 act.lsa_flags = osa.lsa_flags;
181                 act.lsa_restorer = osa.lsa_restorer;
182                 LINUX_SIGEMPTYSET(act.lsa_mask);
183                 act.lsa_mask.__bits[0] = osa.lsa_mask;
184         }
185
186         error = linux_do_sigaction(p, args->sig,
187                                    args->nsa ? &act : NULL,
188                                    args->osa ? &oact : NULL);
189
190         if (args->osa != NULL && !error) {
191                 osa.lsa_handler = oact.lsa_handler;
192                 osa.lsa_flags = oact.lsa_flags;
193                 osa.lsa_restorer = oact.lsa_restorer;
194                 osa.lsa_mask = oact.lsa_mask.__bits[0];
195                 error = copyout(&osa, args->osa, sizeof(linux_osigaction_t));
196         }
197
198         return (error);
199 }
200
201 int
202 linux_signal(struct proc *p, struct linux_signal_args *args)
203 {
204         linux_sigaction_t nsa, osa;
205         int error;
206
207 #ifdef DEBUG
208         printf("Linux-emul(%ld): signal(%d, %p)\n",
209                (long)p->p_pid, args->sig, (void *)args->handler);
210 #endif
211
212         nsa.lsa_handler = args->handler;
213         nsa.lsa_flags = LINUX_SA_ONESHOT | LINUX_SA_NOMASK;
214         LINUX_SIGEMPTYSET(nsa.lsa_mask);
215
216         error = linux_do_sigaction(p, args->sig, &nsa, &osa);
217         p->p_retval[0] = (int)osa.lsa_handler;
218
219         return (error);
220 }
221
222 int
223 linux_rt_sigaction(struct proc *p, struct linux_rt_sigaction_args *args)
224 {
225         linux_sigaction_t nsa, osa;
226         int error;
227
228 #ifdef DEBUG
229         printf("Linux-emul(%ld): rt_sigaction(%d, %p, %p, %d)\n",
230                (long)p->p_pid, args->sig, (void *)args->act,
231                (void *)args->oact, args->sigsetsize);
232 #endif
233
234         if (args->sigsetsize != sizeof(linux_sigset_t))
235                 return (EINVAL);
236
237         if (args->act != NULL) {
238                 error = copyin(args->act, &nsa, sizeof(linux_sigaction_t));
239                 if (error)
240                         return (error);
241         }
242
243         error = linux_do_sigaction(p, args->sig,
244                                    args->act ? &nsa : NULL,
245                                    args->oact ? &osa : NULL);
246
247         if (args->oact != NULL && !error) {
248                 error = copyout(&osa, args->oact, sizeof(linux_sigaction_t));
249         }
250
251         return (error);
252 }
253
254 static int
255 linux_do_sigprocmask(struct proc *p, int how, linux_sigset_t *new,
256                      linux_sigset_t *old)
257 {
258         int error, s;
259         sigset_t mask;
260
261         error = 0;
262         p->p_retval[0] = 0;
263
264         if (old != NULL)
265                 bsd_to_linux_sigset(&p->p_sigmask, old);
266
267         if (new != NULL) {
268                 linux_to_bsd_sigset(new, &mask);
269
270                 s = splhigh();
271
272                 switch (how) {
273                 case LINUX_SIG_BLOCK:
274                         SIGSETOR(p->p_sigmask, mask);
275                         SIG_CANTMASK(p->p_sigmask);
276                         break;
277                 case LINUX_SIG_UNBLOCK:
278                         SIGSETNAND(p->p_sigmask, mask);
279                         break;
280                 case LINUX_SIG_SETMASK:
281                         p->p_sigmask = mask;
282                         SIG_CANTMASK(p->p_sigmask);
283                         break;
284                 default:
285                         error = EINVAL;
286                         break;
287                 }
288
289                 splx(s);
290         }
291
292         return (error);
293 }
294
295 int
296 linux_sigprocmask(struct proc *p, struct linux_sigprocmask_args *args)
297 {
298         linux_osigset_t mask;
299         linux_sigset_t set, oset;
300         int error;
301
302 #ifdef DEBUG
303         printf("Linux-emul(%d): sigprocmask(%d, *, *)\n", p->p_pid, args->how);
304 #endif
305
306         if (args->mask != NULL) {
307                 error = copyin(args->mask, &mask, sizeof(linux_osigset_t));
308                 if (error)
309                         return (error);
310                 LINUX_SIGEMPTYSET(set);
311                 set.__bits[0] = mask;
312         }
313
314         error = linux_do_sigprocmask(p, args->how,
315                                      args->mask ? &set : NULL,
316                                      args->omask ? &oset : NULL);
317
318         if (args->omask != NULL && !error) {
319                 mask = oset.__bits[0];
320                 error = copyout(&mask, args->omask, sizeof(linux_osigset_t));
321         }
322
323         return (error);
324 }
325
326 int
327 linux_rt_sigprocmask(struct proc *p, struct linux_rt_sigprocmask_args *args)
328 {
329         linux_sigset_t set, oset;
330         int error;
331
332 #ifdef DEBUG
333         printf("Linux-emul(%ld): rt_sigprocmask(%d, %p, %p, %d)\n",
334                (long)p->p_pid, args->how, (void *)args->mask,
335                (void *)args->omask, args->sigsetsize);
336 #endif
337
338         if (args->sigsetsize != sizeof(linux_sigset_t))
339                 return EINVAL;
340
341         if (args->mask != NULL) {
342                 error = copyin(args->mask, &set, sizeof(linux_sigset_t));
343                 if (error)
344                         return (error);
345         }
346
347         error = linux_do_sigprocmask(p, args->how,
348                                      args->mask ? &set : NULL,
349                                      args->omask ? &oset : NULL);
350
351         if (args->omask != NULL && !error) {
352                 error = copyout(&oset, args->omask, sizeof(linux_sigset_t));
353         }
354
355         return (error);
356 }
357
358 int
359 linux_siggetmask(struct proc *p, struct linux_siggetmask_args *args)
360 {
361         linux_sigset_t mask;
362
363 #ifdef DEBUG
364         printf("Linux-emul(%d): siggetmask()\n", p->p_pid);
365 #endif
366
367         bsd_to_linux_sigset(&p->p_sigmask, &mask);
368         p->p_retval[0] = mask.__bits[0];
369         return (0);
370 }
371
372 int
373 linux_sigsetmask(struct proc *p, struct linux_sigsetmask_args *args)
374 {
375         linux_sigset_t lset;
376         sigset_t bset;
377         int s;
378
379 #ifdef DEBUG
380         printf("Linux-emul(%ld): sigsetmask(%08lx)\n",
381                (long)p->p_pid, (unsigned long)args->mask);
382 #endif
383
384         bsd_to_linux_sigset(&p->p_sigmask, &lset);
385         p->p_retval[0] = lset.__bits[0];
386         LINUX_SIGEMPTYSET(lset);
387         lset.__bits[0] = args->mask;
388         linux_to_bsd_sigset(&lset, &bset);
389         s = splhigh();
390         p->p_sigmask = bset;
391         SIG_CANTMASK(p->p_sigmask);
392         splx(s);
393         return (0);
394 }
395
396 int
397 linux_sigpending(struct proc *p, struct linux_sigpending_args *args)
398 {
399         sigset_t bset;
400         linux_sigset_t lset;
401         linux_osigset_t mask;
402
403 #ifdef DEBUG
404         printf("Linux-emul(%d): sigpending(*)\n", p->p_pid);
405 #endif
406
407         bset = p->p_siglist;
408         SIGSETAND(bset, p->p_sigmask);
409         bsd_to_linux_sigset(&bset, &lset);
410         mask = lset.__bits[0];
411         return (copyout(&mask, args->mask, sizeof(mask)));
412 }
413
414 /*
415  * Linux has two extra args, restart and oldmask.  We dont use these,
416  * but it seems that "restart" is actually a context pointer that
417  * enables the signal to happen with a different register set.
418  */
419 int
420 linux_sigsuspend(struct proc *p, struct linux_sigsuspend_args *args)
421 {
422         struct sigsuspend_args bsd;
423         sigset_t *sigmask;
424         linux_sigset_t mask;
425         caddr_t sg = stackgap_init();
426
427 #ifdef DEBUG
428         printf("Linux-emul(%ld): sigsuspend(%08lx)\n",
429                (long)p->p_pid, (unsigned long)args->mask);
430 #endif
431
432         sigmask = stackgap_alloc(&sg, sizeof(sigset_t));
433         LINUX_SIGEMPTYSET(mask);
434         mask.__bits[0] = args->mask;
435         linux_to_bsd_sigset(&mask, sigmask);
436         bsd.sigmask = sigmask;
437         return (sigsuspend(p, &bsd));
438 }
439
440 int
441 linux_rt_sigsuspend(p, uap)
442         struct proc *p;
443         struct linux_rt_sigsuspend_args *uap;
444 {
445         linux_sigset_t lmask;
446         sigset_t *bmask;
447         struct sigsuspend_args bsd;
448         caddr_t sg = stackgap_init();
449         int error;
450
451 #ifdef DEBUG
452         printf("Linux-emul(%ld): rt_sigsuspend(%p, %d)\n", (long)p->p_pid,
453                (void *)uap->newset, uap->sigsetsize);
454 #endif
455
456         if (uap->sigsetsize != sizeof(linux_sigset_t))
457                 return (EINVAL);
458
459         error = copyin(uap->newset, &lmask, sizeof(linux_sigset_t));
460         if (error)
461                 return (error);
462
463         bmask = stackgap_alloc(&sg, sizeof(sigset_t));
464         linux_to_bsd_sigset(&lmask, bmask);
465         bsd.sigmask = bmask;
466         return (sigsuspend(p, &bsd));
467 }
468
469 int
470 linux_pause(struct proc *p, struct linux_pause_args *args)
471 {
472         struct sigsuspend_args bsd;
473         sigset_t *sigmask;
474         caddr_t sg = stackgap_init();
475
476 #ifdef DEBUG
477         printf("Linux-emul(%d): pause()\n", p->p_pid);
478 #endif
479
480         sigmask = stackgap_alloc(&sg, sizeof(sigset_t));
481         *sigmask = p->p_sigmask;
482         bsd.sigmask = sigmask;
483         return sigsuspend(p, &bsd);
484 }
485
486 int
487 linux_kill(struct proc *p, struct linux_kill_args *args)
488 {
489         struct kill_args /* {
490             int pid;
491             int signum;
492         } */ tmp;
493
494 #ifdef DEBUG
495         printf("Linux-emul(%d): kill(%d, %d)\n",
496                p->p_pid, args->pid, args->signum);
497 #endif
498
499         /*
500          * Allow signal 0 as a means to check for privileges
501          */
502         if (args->signum < 0 || args->signum > LINUX_NSIG)
503                 return EINVAL;
504
505         if (args->signum > 0 && args->signum <= LINUX_SIGTBLSZ)
506                 tmp.signum = linux_to_bsd_signal[_SIG_IDX(args->signum)];
507         else
508                 tmp.signum = args->signum;
509
510         tmp.pid = args->pid;
511         return (kill(p, &tmp));
512 }
513
514 int
515 linux_sigaltstack(p, uap)
516         struct proc *p;
517         struct linux_sigaltstack_args *uap;
518 {
519         struct sigaltstack_args bsd;
520         stack_t *ss, *oss;
521         linux_stack_t lss;
522         int error;
523         caddr_t sg = stackgap_init();
524
525 #ifdef DEBUG
526         printf("Linux-emul(%ld): sigaltstack(%p, %p)\n",
527             (long)p->p_pid, uap->uss, uap->uoss);
528 #endif
529
530         error = copyin(uap->uss, &lss, sizeof(linux_stack_t));
531         if (error)
532                 return (error);
533
534         ss = stackgap_alloc(&sg, sizeof(stack_t));
535         ss->ss_sp = lss.ss_sp;
536         ss->ss_size = lss.ss_size;
537         ss->ss_flags = lss.ss_flags;
538
539         oss = (uap->uoss != NULL)
540             ? stackgap_alloc(&sg, sizeof(stack_t))
541             : NULL;
542
543         bsd.ss = ss;
544         bsd.oss = oss;
545         error = sigaltstack(p, &bsd);
546
547         if (!error && oss != NULL) {
548                 lss.ss_sp = oss->ss_sp;
549                 lss.ss_size = oss->ss_size;
550                 lss.ss_flags = oss->ss_flags;
551                 error = copyout(&lss, uap->uoss, sizeof(linux_stack_t));
552         }
553
554         return (error);
555 }