1 /* $Id: signal.c,v 1.6 2000/08/29 07:01: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>
10 #include <asm/uaccess.h>
12 #include <asm/string.h>
17 #define _S(nr) (1L<<((nr)-1))
19 #define _BLOCKABLE (~(_S(SIGKILL) | _S(SIGSTOP)))
21 long linux_to_solaris_signals
[] = {
23 SOLARIS_SIGHUP
, SOLARIS_SIGINT
,
24 SOLARIS_SIGQUIT
, SOLARIS_SIGILL
,
25 SOLARIS_SIGTRAP
, SOLARIS_SIGIOT
,
26 SOLARIS_SIGEMT
, SOLARIS_SIGFPE
,
27 SOLARIS_SIGKILL
, SOLARIS_SIGBUS
,
28 SOLARIS_SIGSEGV
, SOLARIS_SIGSYS
,
29 SOLARIS_SIGPIPE
, SOLARIS_SIGALRM
,
30 SOLARIS_SIGTERM
, SOLARIS_SIGURG
,
31 SOLARIS_SIGSTOP
, SOLARIS_SIGTSTP
,
32 SOLARIS_SIGCONT
, SOLARIS_SIGCLD
,
33 SOLARIS_SIGTTIN
, SOLARIS_SIGTTOU
,
34 SOLARIS_SIGPOLL
, SOLARIS_SIGXCPU
,
35 SOLARIS_SIGXFSZ
, SOLARIS_SIGVTALRM
,
36 SOLARIS_SIGPROF
, SOLARIS_SIGWINCH
,
37 SOLARIS_SIGUSR1
, SOLARIS_SIGUSR1
,
41 long solaris_to_linux_signals
[] = {
43 SIGHUP
, SIGINT
, SIGQUIT
, SIGILL
,
44 SIGTRAP
, SIGIOT
, SIGEMT
, SIGFPE
,
45 SIGKILL
, SIGBUS
, SIGSEGV
, SIGSYS
,
46 SIGPIPE
, SIGALRM
, SIGTERM
, SIGUSR1
,
47 SIGUSR2
, SIGCHLD
, -1, SIGWINCH
,
48 SIGURG
, SIGPOLL
, SIGSTOP
, SIGTSTP
,
49 SIGCONT
, SIGTTIN
, SIGTTOU
, SIGVTALRM
,
50 SIGPROF
, SIGXCPU
, SIGXFSZ
, -1,
56 static inline long mapsig(long sig
)
58 if ((unsigned long)sig
> SOLARIS_NSIGNALS
)
60 return solaris_to_linux_signals
[sig
];
63 asmlinkage
int solaris_kill(int pid
, int sig
)
65 int (*sys_kill
)(int,int) =
66 (int (*)(int,int))SYS(kill
);
70 return sys_kill(pid
, s
);
73 static long sig_handler(int sig
, u32 arg
, int one_shot
)
75 struct sigaction sa
, old
;
77 mm_segment_t old_fs
= get_fs();
78 int (*sys_sigaction
)(int,struct sigaction
*,struct sigaction
*) =
79 (int (*)(int,struct sigaction
*,struct sigaction
*))SYS(sigaction
);
81 sigemptyset(&sa
.sa_mask
);
82 sa
.sa_restorer
= NULL
;
83 sa
.sa_handler
= (__sighandler_t
)A(arg
);
85 if (one_shot
) sa
.sa_flags
= SA_ONESHOT
| SA_NOMASK
;
87 ret
= sys_sigaction(sig
, &sa
, &old
);
89 if (ret
< 0) return ret
;
90 return (u32
)(long)old
.sa_handler
;
93 static inline long solaris_signal(int sig
, u32 arg
)
95 return sig_handler (sig
, arg
, 1);
98 static long solaris_sigset(int sig
, u32 arg
)
100 if (arg
!= 2) /* HOLD */ {
101 spin_lock_irq(¤t
->sigmask_lock
);
102 sigdelsetmask(¤t
->blocked
, _S(sig
));
103 recalc_sigpending(current
);
104 spin_unlock_irq(¤t
->sigmask_lock
);
105 return sig_handler (sig
, arg
, 0);
107 spin_lock_irq(¤t
->sigmask_lock
);
108 sigaddsetmask(¤t
->blocked
, (_S(sig
) & ~_BLOCKABLE
));
109 recalc_sigpending(current
);
110 spin_unlock_irq(¤t
->sigmask_lock
);
115 static inline long solaris_sighold(int sig
)
117 return solaris_sigset(sig
, 2);
120 static inline long solaris_sigrelse(int sig
)
122 spin_lock_irq(¤t
->sigmask_lock
);
123 sigdelsetmask(¤t
->blocked
, _S(sig
));
124 recalc_sigpending(current
);
125 spin_unlock_irq(¤t
->sigmask_lock
);
129 static inline long solaris_sigignore(int sig
)
131 return sig_handler (sig
, (u32
)SIG_IGN
, 0);
134 static inline long solaris_sigpause(int sig
)
136 printk ("Need to support solaris sigpause\n");
140 asmlinkage
long solaris_sigfunc(int sig
, u32 arg
)
142 int func
= sig
& ~0xff;
144 sig
= mapsig(sig
& 0xff);
145 if (sig
< 0) return sig
;
147 case 0: return solaris_signal(sig
, arg
);
148 case 0x100: return solaris_sigset(sig
, arg
);
149 case 0x200: return solaris_sighold(sig
);
150 case 0x400: return solaris_sigrelse(sig
);
151 case 0x800: return solaris_sigignore(sig
);
152 case 0x1000: return solaris_sigpause(sig
);
161 static inline int mapin(u32
*p
, sigset_t
*q
)
169 for (i
= 1; i
<= SOLARIS_NSIGNALS
; i
++) {
171 sig
= solaris_to_linux_signals
[i
];
174 sigaddsetmask(q
, (1L << (sig
- 1)));
183 static inline int mapout(sigset_t
*q
, u32
*p
)
190 for (i
= 1; i
<= 32; i
++) {
191 if (sigismember(q
, sigmask(i
))) {
192 sig
= linux_to_solaris_signals
[i
];
196 p
[1] |= 1L << (sig
- 33);
198 p
[0] |= 1L << (sig
- 1);
204 asmlinkage
int solaris_sigprocmask(int how
, u32 in
, u32 out
)
206 sigset_t in_s
, *ins
, out_s
, *outs
;
207 mm_segment_t old_fs
= get_fs();
209 int (*sys_sigprocmask
)(int,sigset_t
*,sigset_t
*) =
210 (int (*)(int,sigset_t
*,sigset_t
*))SYS(sigprocmask
);
212 ins
= NULL
; outs
= NULL
;
216 if (copy_from_user (tmp
, (sol_sigset_t
*)A(in
), 2*sizeof(u32
)))
219 if (mapin (tmp
, ins
)) return -EINVAL
;
221 if (out
) outs
= &out_s
;
223 ret
= sys_sigprocmask((how
== 3) ? SIG_SETMASK
: how
, ins
, outs
);
229 tmp
[2] = 0; tmp
[3] = 0;
230 if (mapout (outs
, tmp
)) return -EINVAL
;
231 if (copy_to_user((sol_sigset_t
*)A(out
), tmp
, 4*sizeof(u32
)))
237 asmlinkage
long do_sol_sigsuspend(u32 mask
)
242 if (copy_from_user (tmp
, (sol_sigset_t
*)A(mask
), 2*sizeof(u32
)))
244 if (mapin (tmp
, &s
)) return -EINVAL
;
245 return (long)s
.sig
[0];
248 struct sol_sigaction
{
255 asmlinkage
int solaris_sigaction(int sig
, u32 act
, u32 old
)
258 struct sigaction s
, s2
;
260 mm_segment_t old_fs
= get_fs();
261 int (*sys_sigaction
)(int,struct sigaction
*,struct sigaction
*) =
262 (int (*)(int,struct sigaction
*,struct sigaction
*))SYS(sigaction
);
266 /* We cheat a little bit for Solaris only signals */
267 if (old
&& clear_user((struct sol_sigaction
*)A(old
), sizeof(struct sol_sigaction
)))
272 if (get_user (tmp
, &((struct sol_sigaction
*)A(act
))->sa_flags
))
275 if (tmp
& SOLARIS_SA_ONSTACK
) s
.sa_flags
|= SA_STACK
;
276 if (tmp
& SOLARIS_SA_RESTART
) s
.sa_flags
|= SA_RESTART
;
277 if (tmp
& SOLARIS_SA_NODEFER
) s
.sa_flags
|= SA_NOMASK
;
278 if (tmp
& SOLARIS_SA_RESETHAND
) s
.sa_flags
|= SA_ONESHOT
;
279 if (tmp
& SOLARIS_SA_NOCLDSTOP
) s
.sa_flags
|= SA_NOCLDSTOP
;
280 if (get_user (tmp
, &((struct sol_sigaction
*)A(act
))->sa_handler
) ||
281 copy_from_user (tmp2
, &((struct sol_sigaction
*)A(act
))->sa_mask
, 2*sizeof(u32
)))
283 s
.sa_handler
= (__sighandler_t
)A(tmp
);
284 if (mapin (tmp2
, &s
.sa_mask
)) return -EINVAL
;
288 ret
= sys_sigaction(sig
, act
? &s
: NULL
, old
? &s2
: NULL
);
292 if (mapout (&s2
.sa_mask
, tmp2
)) return -EINVAL
;
293 tmp
= 0; tmp2
[2] = 0; tmp2
[3] = 0;
294 if (s2
.sa_flags
& SA_STACK
) tmp
|= SOLARIS_SA_ONSTACK
;
295 if (s2
.sa_flags
& SA_RESTART
) tmp
|= SOLARIS_SA_RESTART
;
296 if (s2
.sa_flags
& SA_NOMASK
) tmp
|= SOLARIS_SA_NODEFER
;
297 if (s2
.sa_flags
& SA_ONESHOT
) tmp
|= SOLARIS_SA_RESETHAND
;
298 if (s2
.sa_flags
& SA_NOCLDSTOP
) tmp
|= SOLARIS_SA_NOCLDSTOP
;
299 if (put_user (tmp
, &((struct sol_sigaction
*)A(old
))->sa_flags
) ||
300 __put_user ((u32
)(long)s2
.sa_handler
, &((struct sol_sigaction
*)A(old
))->sa_handler
) ||
301 copy_to_user (&((struct sol_sigaction
*)A(old
))->sa_mask
, tmp2
, 4*sizeof(u32
)))
307 asmlinkage
int solaris_sigpending(int which
, u32 set
)
312 case 1: /* sigpending */
313 spin_lock_irq(¤t
->sigmask_lock
);
314 sigandsets(&s
, ¤t
->blocked
, ¤t
->signal
);
315 recalc_sigpending(current
);
316 spin_unlock_irq(¤t
->sigmask_lock
);
318 case 2: /* sigfillset - I just set signals which have linux equivalents */
321 default: return -EINVAL
;
323 if (mapout (&s
, tmp
)) return -EINVAL
;
324 tmp
[2] = 0; tmp
[3] = 0;
325 if (copy_to_user ((u32
*)A(set
), tmp
, sizeof(tmp
)))
330 asmlinkage
int solaris_wait(u32 stat_loc
)
332 int (*sys_wait4
)(pid_t
,unsigned int *, int, struct rusage
*) =
333 (int (*)(pid_t
,unsigned int *, int, struct rusage
*))SYS(wait4
);
336 ret
= sys_wait4(-1, (unsigned int *)A(stat_loc
), WUNTRACED
, NULL
);
337 if (ret
>= 0 && stat_loc
) {
338 if (get_user (status
, (unsigned int *)A(stat_loc
)))
340 if (((status
- 1) & 0xffff) < 0xff)
341 status
= linux_to_solaris_signals
[status
& 0x7f] & 0x7f;
342 else if ((status
& 0xff) == 0x7f)
343 status
= (linux_to_solaris_signals
[(status
>> 8) & 0xff] << 8) | 0x7f;
344 if (__put_user (status
, (unsigned int *)A(stat_loc
)))
350 asmlinkage
int solaris_waitid(int idtype
, s32 pid
, u32 info
, int options
)
352 int (*sys_wait4
)(pid_t
,unsigned int *, int, struct rusage
*) =
353 (int (*)(pid_t
,unsigned int *, int, struct rusage
*))SYS(wait4
);
354 int opts
, status
, ret
;
357 case 0: /* P_PID */ break;
358 case 1: /* P_PGID */ pid
= -pid
; break;
359 case 7: /* P_ALL */ pid
= -1; break;
360 default: return -EINVAL
;
363 if (options
& SOLARIS_WUNTRACED
) opts
|= WUNTRACED
;
364 if (options
& SOLARIS_WNOHANG
) opts
|= WNOHANG
;
365 current
->state
= TASK_RUNNING
;
366 ret
= sys_wait4(pid
, (unsigned int *)A(info
), opts
, NULL
);
367 if (ret
< 0) return ret
;
369 struct sol_siginfo
*s
= (struct sol_siginfo
*)A(info
);
371 if (get_user (status
, (unsigned int *)A(info
)))
374 if (__put_user (SOLARIS_SIGCLD
, &s
->si_signo
) ||
375 __put_user (ret
, &s
->_data
._proc
._pid
))
378 switch (status
& 0xff) {
379 case 0: ret
= SOLARIS_CLD_EXITED
;
380 status
= (status
>> 8) & 0xff;
383 status
= (status
>> 8) & 0xff;
386 case SIGTSTP
: ret
= SOLARIS_CLD_STOPPED
;
387 default: ret
= SOLARIS_CLD_EXITED
;
389 status
= linux_to_solaris_signals
[status
];
392 if (status
& 0x80) ret
= SOLARIS_CLD_DUMPED
;
393 else ret
= SOLARIS_CLD_KILLED
;
394 status
= linux_to_solaris_signals
[status
& 0x7f];
398 if (__put_user (ret
, &s
->si_code
) ||
399 __put_user (status
, &s
->_data
._proc
._pdata
._cld
._status
))
405 extern int svr4_setcontext(svr4_ucontext_t
*c
, struct pt_regs
*regs
);
406 extern int svr4_getcontext(svr4_ucontext_t
*c
, struct pt_regs
*regs
);
408 asmlinkage
int solaris_context(struct pt_regs
*regs
)
410 switch ((unsigned)regs
->u_regs
[UREG_I0
]) {
411 case 0: /* getcontext */
412 return svr4_getcontext((svr4_ucontext_t
*)(long)(u32
)regs
->u_regs
[UREG_I1
], regs
);
413 case 1: /* setcontext */
414 return svr4_setcontext((svr4_ucontext_t
*)(long)(u32
)regs
->u_regs
[UREG_I1
], regs
);
421 asmlinkage
int solaris_sigaltstack(u32 ss
, u32 oss
)
423 /* XXX Implement this soon */