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/errno.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 __user
*,struct sigaction __user
*) =
79 (int (*)(int,struct sigaction __user
*,struct sigaction __user
*))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
, (void __user
*)&sa
, (void __user
*)&old
);
89 if (ret
< 0) return ret
;
90 return (u32
)(unsigned 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
->sighand
->siglock
);
102 sigdelsetmask(¤t
->blocked
, _S(sig
));
104 spin_unlock_irq(¤t
->sighand
->siglock
);
105 return sig_handler (sig
, arg
, 0);
107 spin_lock_irq(¤t
->sighand
->siglock
);
108 sigaddsetmask(¤t
->blocked
, (_S(sig
) & ~_BLOCKABLE
));
110 spin_unlock_irq(¤t
->sighand
->siglock
);
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
->sighand
->siglock
);
123 sigdelsetmask(¤t
->blocked
, _S(sig
));
125 spin_unlock_irq(¤t
->sighand
->siglock
);
129 static inline long solaris_sigignore(int sig
)
131 return sig_handler(sig
, (u32
)(unsigned long)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 __user
*,sigset_t __user
*) =
210 (int (*)(int,sigset_t __user
*,sigset_t __user
*))SYS(sigprocmask
);
212 ins
= NULL
; outs
= NULL
;
216 if (copy_from_user (tmp
, (void __user
*)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
,
224 (void __user
*)ins
, (void __user
*)outs
);
230 tmp
[2] = 0; tmp
[3] = 0;
231 if (mapout (outs
, tmp
)) return -EINVAL
;
232 if (copy_to_user((void __user
*)A(out
), tmp
, 4*sizeof(u32
)))
238 asmlinkage
long do_sol_sigsuspend(u32 mask
)
243 if (copy_from_user (tmp
, (sol_sigset_t __user
*)A(mask
), 2*sizeof(u32
)))
245 if (mapin (tmp
, &s
)) return -EINVAL
;
246 return (long)s
.sig
[0];
249 struct sol_sigaction
{
256 asmlinkage
int solaris_sigaction(int sig
, u32 act
, u32 old
)
259 struct sigaction s
, s2
;
261 mm_segment_t old_fs
= get_fs();
262 struct sol_sigaction __user
*p
= (void __user
*)A(old
);
263 int (*sys_sigaction
)(int,struct sigaction __user
*,struct sigaction __user
*) =
264 (int (*)(int,struct sigaction __user
*,struct sigaction __user
*))SYS(sigaction
);
268 /* We cheat a little bit for Solaris only signals */
269 if (old
&& clear_user(p
, sizeof(struct sol_sigaction
)))
274 if (get_user (tmp
, &p
->sa_flags
))
277 if (tmp
& SOLARIS_SA_ONSTACK
) s
.sa_flags
|= SA_STACK
;
278 if (tmp
& SOLARIS_SA_RESTART
) s
.sa_flags
|= SA_RESTART
;
279 if (tmp
& SOLARIS_SA_NODEFER
) s
.sa_flags
|= SA_NOMASK
;
280 if (tmp
& SOLARIS_SA_RESETHAND
) s
.sa_flags
|= SA_ONESHOT
;
281 if (tmp
& SOLARIS_SA_NOCLDSTOP
) s
.sa_flags
|= SA_NOCLDSTOP
;
282 if (get_user (tmp
, &p
->sa_handler
) ||
283 copy_from_user (tmp2
, &p
->sa_mask
, 2*sizeof(u32
)))
285 s
.sa_handler
= (__sighandler_t
)A(tmp
);
286 if (mapin (tmp2
, &s
.sa_mask
)) return -EINVAL
;
287 s
.sa_restorer
= NULL
;
290 ret
= sys_sigaction(sig
, act
? (void __user
*)&s
: NULL
,
291 old
? (void __user
*)&s2
: NULL
);
295 if (mapout (&s2
.sa_mask
, tmp2
)) return -EINVAL
;
296 tmp
= 0; tmp2
[2] = 0; tmp2
[3] = 0;
297 if (s2
.sa_flags
& SA_STACK
) tmp
|= SOLARIS_SA_ONSTACK
;
298 if (s2
.sa_flags
& SA_RESTART
) tmp
|= SOLARIS_SA_RESTART
;
299 if (s2
.sa_flags
& SA_NOMASK
) tmp
|= SOLARIS_SA_NODEFER
;
300 if (s2
.sa_flags
& SA_ONESHOT
) tmp
|= SOLARIS_SA_RESETHAND
;
301 if (s2
.sa_flags
& SA_NOCLDSTOP
) tmp
|= SOLARIS_SA_NOCLDSTOP
;
302 if (put_user (tmp
, &p
->sa_flags
) ||
303 __put_user ((u32
)(unsigned long)s2
.sa_handler
, &p
->sa_handler
) ||
304 copy_to_user (&p
->sa_mask
, tmp2
, 4*sizeof(u32
)))
310 asmlinkage
int solaris_sigpending(int which
, u32 set
)
315 case 1: /* sigpending */
316 spin_lock_irq(¤t
->sighand
->siglock
);
317 sigandsets(&s
, ¤t
->blocked
, ¤t
->pending
.signal
);
319 spin_unlock_irq(¤t
->sighand
->siglock
);
321 case 2: /* sigfillset - I just set signals which have linux equivalents */
324 default: return -EINVAL
;
326 if (mapout (&s
, tmp
)) return -EINVAL
;
327 tmp
[2] = 0; tmp
[3] = 0;
328 if (copy_to_user ((u32 __user
*)A(set
), tmp
, sizeof(tmp
)))
333 asmlinkage
int solaris_wait(u32 stat_loc
)
335 unsigned __user
*p
= (unsigned __user
*)A(stat_loc
);
336 int (*sys_wait4
)(pid_t
,unsigned __user
*, int, struct rusage __user
*) =
337 (int (*)(pid_t
,unsigned __user
*, int, struct rusage __user
*))SYS(wait4
);
340 ret
= sys_wait4(-1, p
, WUNTRACED
, NULL
);
341 if (ret
>= 0 && stat_loc
) {
342 if (get_user (status
, p
))
344 if (((status
- 1) & 0xffff) < 0xff)
345 status
= linux_to_solaris_signals
[status
& 0x7f] & 0x7f;
346 else if ((status
& 0xff) == 0x7f)
347 status
= (linux_to_solaris_signals
[(status
>> 8) & 0xff] << 8) | 0x7f;
348 if (__put_user (status
, p
))
354 asmlinkage
int solaris_waitid(int idtype
, s32 pid
, u32 info
, int options
)
356 int (*sys_wait4
)(pid_t
,unsigned __user
*, int, struct rusage __user
*) =
357 (int (*)(pid_t
,unsigned __user
*, int, struct rusage __user
*))SYS(wait4
);
358 int opts
, status
, ret
;
361 case 0: /* P_PID */ break;
362 case 1: /* P_PGID */ pid
= -pid
; break;
363 case 7: /* P_ALL */ pid
= -1; break;
364 default: return -EINVAL
;
367 if (options
& SOLARIS_WUNTRACED
) opts
|= WUNTRACED
;
368 if (options
& SOLARIS_WNOHANG
) opts
|= WNOHANG
;
369 current
->state
= TASK_RUNNING
;
370 ret
= sys_wait4(pid
, (unsigned int __user
*)A(info
), opts
, NULL
);
371 if (ret
< 0) return ret
;
373 struct sol_siginfo __user
*s
= (void __user
*)A(info
);
375 if (get_user (status
, (unsigned int __user
*)A(info
)))
378 if (__put_user (SOLARIS_SIGCLD
, &s
->si_signo
) ||
379 __put_user (ret
, &s
->_data
._proc
._pid
))
382 switch (status
& 0xff) {
383 case 0: ret
= SOLARIS_CLD_EXITED
;
384 status
= (status
>> 8) & 0xff;
387 status
= (status
>> 8) & 0xff;
390 case SIGTSTP
: ret
= SOLARIS_CLD_STOPPED
;
391 default: ret
= SOLARIS_CLD_EXITED
;
393 status
= linux_to_solaris_signals
[status
];
396 if (status
& 0x80) ret
= SOLARIS_CLD_DUMPED
;
397 else ret
= SOLARIS_CLD_KILLED
;
398 status
= linux_to_solaris_signals
[status
& 0x7f];
402 if (__put_user (ret
, &s
->si_code
) ||
403 __put_user (status
, &s
->_data
._proc
._pdata
._cld
._status
))
409 extern int svr4_setcontext(svr4_ucontext_t
*c
, struct pt_regs
*regs
);
410 extern int svr4_getcontext(svr4_ucontext_t
*c
, struct pt_regs
*regs
);
412 asmlinkage
int solaris_context(struct pt_regs
*regs
)
414 switch ((unsigned)regs
->u_regs
[UREG_I0
]) {
415 case 0: /* getcontext */
416 return svr4_getcontext((svr4_ucontext_t
*)(long)(u32
)regs
->u_regs
[UREG_I1
], regs
);
417 case 1: /* setcontext */
418 return svr4_setcontext((svr4_ucontext_t
*)(long)(u32
)regs
->u_regs
[UREG_I1
], regs
);
425 asmlinkage
int solaris_sigaltstack(u32 ss
, u32 oss
)
427 /* XXX Implement this soon */