1 /* $Id: signal.c,v 1.7 2000/09/05 21:44:54 davem Exp $
2 * signal.c: Signal emulation for Solaris
4 * Copyright (C) 1997 Jakub Jelinek (jj@sunsite.mff.cuni.cz)
7 #include <linux/types.h>
8 #include <linux/smp_lock.h>
9 #include <linux/errno.h>
11 #include <asm/uaccess.h>
13 #include <asm/string.h>
18 #define _S(nr) (1L<<((nr)-1))
20 #define _BLOCKABLE (~(_S(SIGKILL) | _S(SIGSTOP)))
22 long linux_to_solaris_signals
[] = {
24 SOLARIS_SIGHUP
, SOLARIS_SIGINT
,
25 SOLARIS_SIGQUIT
, SOLARIS_SIGILL
,
26 SOLARIS_SIGTRAP
, SOLARIS_SIGIOT
,
27 SOLARIS_SIGEMT
, SOLARIS_SIGFPE
,
28 SOLARIS_SIGKILL
, SOLARIS_SIGBUS
,
29 SOLARIS_SIGSEGV
, SOLARIS_SIGSYS
,
30 SOLARIS_SIGPIPE
, SOLARIS_SIGALRM
,
31 SOLARIS_SIGTERM
, SOLARIS_SIGURG
,
32 SOLARIS_SIGSTOP
, SOLARIS_SIGTSTP
,
33 SOLARIS_SIGCONT
, SOLARIS_SIGCLD
,
34 SOLARIS_SIGTTIN
, SOLARIS_SIGTTOU
,
35 SOLARIS_SIGPOLL
, SOLARIS_SIGXCPU
,
36 SOLARIS_SIGXFSZ
, SOLARIS_SIGVTALRM
,
37 SOLARIS_SIGPROF
, SOLARIS_SIGWINCH
,
38 SOLARIS_SIGUSR1
, SOLARIS_SIGUSR1
,
42 long solaris_to_linux_signals
[] = {
44 SIGHUP
, SIGINT
, SIGQUIT
, SIGILL
,
45 SIGTRAP
, SIGIOT
, SIGEMT
, SIGFPE
,
46 SIGKILL
, SIGBUS
, SIGSEGV
, SIGSYS
,
47 SIGPIPE
, SIGALRM
, SIGTERM
, SIGUSR1
,
48 SIGUSR2
, SIGCHLD
, -1, SIGWINCH
,
49 SIGURG
, SIGPOLL
, SIGSTOP
, SIGTSTP
,
50 SIGCONT
, SIGTTIN
, SIGTTOU
, SIGVTALRM
,
51 SIGPROF
, SIGXCPU
, SIGXFSZ
, -1,
57 static inline long mapsig(long sig
)
59 if ((unsigned long)sig
> SOLARIS_NSIGNALS
)
61 return solaris_to_linux_signals
[sig
];
64 asmlinkage
int solaris_kill(int pid
, int sig
)
66 int (*sys_kill
)(int,int) =
67 (int (*)(int,int))SYS(kill
);
71 return sys_kill(pid
, s
);
74 static long sig_handler(int sig
, u32 arg
, int one_shot
)
76 struct sigaction sa
, old
;
78 mm_segment_t old_fs
= get_fs();
79 int (*sys_sigaction
)(int,struct sigaction __user
*,struct sigaction __user
*) =
80 (int (*)(int,struct sigaction __user
*,struct sigaction __user
*))SYS(sigaction
);
82 sigemptyset(&sa
.sa_mask
);
83 sa
.sa_restorer
= NULL
;
84 sa
.sa_handler
= (__sighandler_t
)A(arg
);
86 if (one_shot
) sa
.sa_flags
= SA_ONESHOT
| SA_NOMASK
;
88 ret
= sys_sigaction(sig
, (void __user
*)&sa
, (void __user
*)&old
);
90 if (ret
< 0) return ret
;
91 return (u32
)(unsigned long)old
.sa_handler
;
94 static inline long solaris_signal(int sig
, u32 arg
)
96 return sig_handler (sig
, arg
, 1);
99 static long solaris_sigset(int sig
, u32 arg
)
101 if (arg
!= 2) /* HOLD */ {
102 spin_lock_irq(¤t
->sighand
->siglock
);
103 sigdelsetmask(¤t
->blocked
, _S(sig
));
105 spin_unlock_irq(¤t
->sighand
->siglock
);
106 return sig_handler (sig
, arg
, 0);
108 spin_lock_irq(¤t
->sighand
->siglock
);
109 sigaddsetmask(¤t
->blocked
, (_S(sig
) & ~_BLOCKABLE
));
111 spin_unlock_irq(¤t
->sighand
->siglock
);
116 static inline long solaris_sighold(int sig
)
118 return solaris_sigset(sig
, 2);
121 static inline long solaris_sigrelse(int sig
)
123 spin_lock_irq(¤t
->sighand
->siglock
);
124 sigdelsetmask(¤t
->blocked
, _S(sig
));
126 spin_unlock_irq(¤t
->sighand
->siglock
);
130 static inline long solaris_sigignore(int sig
)
132 return sig_handler(sig
, (u32
)(unsigned long)SIG_IGN
, 0);
135 static inline long solaris_sigpause(int sig
)
137 printk ("Need to support solaris sigpause\n");
141 asmlinkage
long solaris_sigfunc(int sig
, u32 arg
)
143 int func
= sig
& ~0xff;
145 sig
= mapsig(sig
& 0xff);
146 if (sig
< 0) return sig
;
148 case 0: return solaris_signal(sig
, arg
);
149 case 0x100: return solaris_sigset(sig
, arg
);
150 case 0x200: return solaris_sighold(sig
);
151 case 0x400: return solaris_sigrelse(sig
);
152 case 0x800: return solaris_sigignore(sig
);
153 case 0x1000: return solaris_sigpause(sig
);
162 static inline int mapin(u32
*p
, sigset_t
*q
)
170 for (i
= 1; i
<= SOLARIS_NSIGNALS
; i
++) {
172 sig
= solaris_to_linux_signals
[i
];
175 sigaddsetmask(q
, (1L << (sig
- 1)));
184 static inline int mapout(sigset_t
*q
, u32
*p
)
191 for (i
= 1; i
<= 32; i
++) {
192 if (sigismember(q
, sigmask(i
))) {
193 sig
= linux_to_solaris_signals
[i
];
197 p
[1] |= 1L << (sig
- 33);
199 p
[0] |= 1L << (sig
- 1);
205 asmlinkage
int solaris_sigprocmask(int how
, u32 in
, u32 out
)
207 sigset_t in_s
, *ins
, out_s
, *outs
;
208 mm_segment_t old_fs
= get_fs();
210 int (*sys_sigprocmask
)(int,sigset_t __user
*,sigset_t __user
*) =
211 (int (*)(int,sigset_t __user
*,sigset_t __user
*))SYS(sigprocmask
);
213 ins
= NULL
; outs
= NULL
;
217 if (copy_from_user (tmp
, (void __user
*)A(in
), 2*sizeof(u32
)))
220 if (mapin (tmp
, ins
)) return -EINVAL
;
222 if (out
) outs
= &out_s
;
224 ret
= sys_sigprocmask((how
== 3) ? SIG_SETMASK
: how
,
225 (void __user
*)ins
, (void __user
*)outs
);
231 tmp
[2] = 0; tmp
[3] = 0;
232 if (mapout (outs
, tmp
)) return -EINVAL
;
233 if (copy_to_user((void __user
*)A(out
), tmp
, 4*sizeof(u32
)))
239 asmlinkage
long do_sol_sigsuspend(u32 mask
)
244 if (copy_from_user (tmp
, (sol_sigset_t __user
*)A(mask
), 2*sizeof(u32
)))
246 if (mapin (tmp
, &s
)) return -EINVAL
;
247 return (long)s
.sig
[0];
250 struct sol_sigaction
{
257 asmlinkage
int solaris_sigaction(int sig
, u32 act
, u32 old
)
260 struct sigaction s
, s2
;
262 mm_segment_t old_fs
= get_fs();
263 struct sol_sigaction __user
*p
= (void __user
*)A(old
);
264 int (*sys_sigaction
)(int,struct sigaction __user
*,struct sigaction __user
*) =
265 (int (*)(int,struct sigaction __user
*,struct sigaction __user
*))SYS(sigaction
);
269 /* We cheat a little bit for Solaris only signals */
270 if (old
&& clear_user(p
, sizeof(struct sol_sigaction
)))
275 if (get_user (tmp
, &p
->sa_flags
))
278 if (tmp
& SOLARIS_SA_ONSTACK
) s
.sa_flags
|= SA_STACK
;
279 if (tmp
& SOLARIS_SA_RESTART
) s
.sa_flags
|= SA_RESTART
;
280 if (tmp
& SOLARIS_SA_NODEFER
) s
.sa_flags
|= SA_NOMASK
;
281 if (tmp
& SOLARIS_SA_RESETHAND
) s
.sa_flags
|= SA_ONESHOT
;
282 if (tmp
& SOLARIS_SA_NOCLDSTOP
) s
.sa_flags
|= SA_NOCLDSTOP
;
283 if (get_user (tmp
, &p
->sa_handler
) ||
284 copy_from_user (tmp2
, &p
->sa_mask
, 2*sizeof(u32
)))
286 s
.sa_handler
= (__sighandler_t
)A(tmp
);
287 if (mapin (tmp2
, &s
.sa_mask
)) return -EINVAL
;
288 s
.sa_restorer
= NULL
;
291 ret
= sys_sigaction(sig
, act
? (void __user
*)&s
: NULL
,
292 old
? (void __user
*)&s2
: NULL
);
296 if (mapout (&s2
.sa_mask
, tmp2
)) return -EINVAL
;
297 tmp
= 0; tmp2
[2] = 0; tmp2
[3] = 0;
298 if (s2
.sa_flags
& SA_STACK
) tmp
|= SOLARIS_SA_ONSTACK
;
299 if (s2
.sa_flags
& SA_RESTART
) tmp
|= SOLARIS_SA_RESTART
;
300 if (s2
.sa_flags
& SA_NOMASK
) tmp
|= SOLARIS_SA_NODEFER
;
301 if (s2
.sa_flags
& SA_ONESHOT
) tmp
|= SOLARIS_SA_RESETHAND
;
302 if (s2
.sa_flags
& SA_NOCLDSTOP
) tmp
|= SOLARIS_SA_NOCLDSTOP
;
303 if (put_user (tmp
, &p
->sa_flags
) ||
304 __put_user ((u32
)(unsigned long)s2
.sa_handler
, &p
->sa_handler
) ||
305 copy_to_user (&p
->sa_mask
, tmp2
, 4*sizeof(u32
)))
311 asmlinkage
int solaris_sigpending(int which
, u32 set
)
316 case 1: /* sigpending */
317 spin_lock_irq(¤t
->sighand
->siglock
);
318 sigandsets(&s
, ¤t
->blocked
, ¤t
->pending
.signal
);
320 spin_unlock_irq(¤t
->sighand
->siglock
);
322 case 2: /* sigfillset - I just set signals which have linux equivalents */
325 default: return -EINVAL
;
327 if (mapout (&s
, tmp
)) return -EINVAL
;
328 tmp
[2] = 0; tmp
[3] = 0;
329 if (copy_to_user ((u32 __user
*)A(set
), tmp
, sizeof(tmp
)))
334 asmlinkage
int solaris_wait(u32 stat_loc
)
336 unsigned __user
*p
= (unsigned __user
*)A(stat_loc
);
337 int (*sys_wait4
)(pid_t
,unsigned __user
*, int, struct rusage __user
*) =
338 (int (*)(pid_t
,unsigned __user
*, int, struct rusage __user
*))SYS(wait4
);
341 ret
= sys_wait4(-1, p
, WUNTRACED
, NULL
);
342 if (ret
>= 0 && stat_loc
) {
343 if (get_user (status
, p
))
345 if (((status
- 1) & 0xffff) < 0xff)
346 status
= linux_to_solaris_signals
[status
& 0x7f] & 0x7f;
347 else if ((status
& 0xff) == 0x7f)
348 status
= (linux_to_solaris_signals
[(status
>> 8) & 0xff] << 8) | 0x7f;
349 if (__put_user (status
, p
))
355 asmlinkage
int solaris_waitid(int idtype
, s32 pid
, u32 info
, int options
)
357 int (*sys_wait4
)(pid_t
,unsigned __user
*, int, struct rusage __user
*) =
358 (int (*)(pid_t
,unsigned __user
*, int, struct rusage __user
*))SYS(wait4
);
359 int opts
, status
, ret
;
362 case 0: /* P_PID */ break;
363 case 1: /* P_PGID */ pid
= -pid
; break;
364 case 7: /* P_ALL */ pid
= -1; break;
365 default: return -EINVAL
;
368 if (options
& SOLARIS_WUNTRACED
) opts
|= WUNTRACED
;
369 if (options
& SOLARIS_WNOHANG
) opts
|= WNOHANG
;
370 current
->state
= TASK_RUNNING
;
371 ret
= sys_wait4(pid
, (unsigned int __user
*)A(info
), opts
, NULL
);
372 if (ret
< 0) return ret
;
374 struct sol_siginfo __user
*s
= (void __user
*)A(info
);
376 if (get_user (status
, (unsigned int __user
*)A(info
)))
379 if (__put_user (SOLARIS_SIGCLD
, &s
->si_signo
) ||
380 __put_user (ret
, &s
->_data
._proc
._pid
))
383 switch (status
& 0xff) {
384 case 0: ret
= SOLARIS_CLD_EXITED
;
385 status
= (status
>> 8) & 0xff;
388 status
= (status
>> 8) & 0xff;
391 case SIGTSTP
: ret
= SOLARIS_CLD_STOPPED
;
392 default: ret
= SOLARIS_CLD_EXITED
;
394 status
= linux_to_solaris_signals
[status
];
397 if (status
& 0x80) ret
= SOLARIS_CLD_DUMPED
;
398 else ret
= SOLARIS_CLD_KILLED
;
399 status
= linux_to_solaris_signals
[status
& 0x7f];
403 if (__put_user (ret
, &s
->si_code
) ||
404 __put_user (status
, &s
->_data
._proc
._pdata
._cld
._status
))
410 extern int svr4_setcontext(svr4_ucontext_t
*c
, struct pt_regs
*regs
);
411 extern int svr4_getcontext(svr4_ucontext_t
*c
, struct pt_regs
*regs
);
413 asmlinkage
int solaris_context(struct pt_regs
*regs
)
415 switch ((unsigned)regs
->u_regs
[UREG_I0
]) {
416 case 0: /* getcontext */
417 return svr4_getcontext((svr4_ucontext_t
*)(long)(u32
)regs
->u_regs
[UREG_I1
], regs
);
418 case 1: /* setcontext */
419 return svr4_setcontext((svr4_ucontext_t
*)(long)(u32
)regs
->u_regs
[UREG_I1
], regs
);
426 asmlinkage
int solaris_sigaltstack(u32 ss
, u32 oss
)
428 /* XXX Implement this soon */