1/* $Id: signal.c,v 1.1.1.1 2007/08/03 18:52:19 Exp $ 2 * signal.c: Signal emulation for Solaris 3 * 4 * Copyright (C) 1997 Jakub Jelinek (jj@sunsite.mff.cuni.cz) 5 */ 6 7#include <linux/types.h> 8#include <linux/errno.h> 9 10#include <asm/uaccess.h> 11#include <asm/svr4.h> 12#include <asm/string.h> 13 14#include "conv.h" 15#include "signal.h" 16 17#define _S(nr) (1L<<((nr)-1)) 18 19#define _BLOCKABLE (~(_S(SIGKILL) | _S(SIGSTOP))) 20 21long linux_to_solaris_signals[] = { 22 0, 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, 38 SOLARIS_SIGUSR2, -1, 39}; 40 41long solaris_to_linux_signals[] = { 42 0, 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, 51 -1, -1, -1, -1, 52 -1, -1, -1, -1, 53 -1, -1, -1, -1, 54}; 55 56static inline long mapsig(long sig) 57{ 58 if ((unsigned long)sig > SOLARIS_NSIGNALS) 59 return -EINVAL; 60 return solaris_to_linux_signals[sig]; 61} 62 63asmlinkage int solaris_kill(int pid, int sig) 64{ 65 int (*sys_kill)(int,int) = 66 (int (*)(int,int))SYS(kill); 67 int s = mapsig(sig); 68 69 if (s < 0) return s; 70 return sys_kill(pid, s); 71} 72 73static long sig_handler(int sig, u32 arg, int one_shot) 74{ 75 struct sigaction sa, old; 76 int ret; 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); 80 81 sigemptyset(&sa.sa_mask); 82 sa.sa_restorer = NULL; 83 sa.sa_handler = (__sighandler_t)A(arg); 84 sa.sa_flags = 0; 85 if (one_shot) sa.sa_flags = SA_ONESHOT | SA_NOMASK; 86 set_fs (KERNEL_DS); 87 ret = sys_sigaction(sig, (void __user *)&sa, (void __user *)&old); 88 set_fs (old_fs); 89 if (ret < 0) return ret; 90 return (u32)(unsigned long)old.sa_handler; 91} 92 93static inline long solaris_signal(int sig, u32 arg) 94{ 95 return sig_handler (sig, arg, 1); 96} 97 98static long solaris_sigset(int sig, u32 arg) 99{ 100 if (arg != 2) /* HOLD */ { 101 spin_lock_irq(¤t->sighand->siglock); 102 sigdelsetmask(¤t->blocked, _S(sig)); 103 recalc_sigpending(); 104 spin_unlock_irq(¤t->sighand->siglock); 105 return sig_handler (sig, arg, 0); 106 } else { 107 spin_lock_irq(¤t->sighand->siglock); 108 sigaddsetmask(¤t->blocked, (_S(sig) & ~_BLOCKABLE)); 109 recalc_sigpending(); 110 spin_unlock_irq(¤t->sighand->siglock); 111 return 0; 112 } 113} 114 115static inline long solaris_sighold(int sig) 116{ 117 return solaris_sigset(sig, 2); 118} 119 120static inline long solaris_sigrelse(int sig) 121{ 122 spin_lock_irq(¤t->sighand->siglock); 123 sigdelsetmask(¤t->blocked, _S(sig)); 124 recalc_sigpending(); 125 spin_unlock_irq(¤t->sighand->siglock); 126 return 0; 127} 128 129static inline long solaris_sigignore(int sig) 130{ 131 return sig_handler(sig, (u32)(unsigned long)SIG_IGN, 0); 132} 133 134static inline long solaris_sigpause(int sig) 135{ 136 printk ("Need to support solaris sigpause\n"); 137 return -ENOSYS; 138} 139 140asmlinkage long solaris_sigfunc(int sig, u32 arg) 141{ 142 int func = sig & ~0xff; 143 144 sig = mapsig(sig & 0xff); 145 if (sig < 0) return sig; 146 switch (func) { 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); 153 } 154 return -EINVAL; 155} 156 157typedef struct { 158 u32 __sigbits[4]; 159} sol_sigset_t; 160 161static inline int mapin(u32 *p, sigset_t *q) 162{ 163 int i; 164 u32 x; 165 int sig; 166 167 sigemptyset(q); 168 x = p[0]; 169 for (i = 1; i <= SOLARIS_NSIGNALS; i++) { 170 if (x & 1) { 171 sig = solaris_to_linux_signals[i]; 172 if (sig == -1) 173 return -EINVAL; 174 sigaddsetmask(q, (1L << (sig - 1))); 175 } 176 x >>= 1; 177 if (i == 32) 178 x = p[1]; 179 } 180 return 0; 181} 182 183static inline int mapout(sigset_t *q, u32 *p) 184{ 185 int i; 186 int sig; 187 188 p[0] = 0; 189 p[1] = 0; 190 for (i = 1; i <= 32; i++) { 191 if (sigismember(q, sigmask(i))) { 192 sig = linux_to_solaris_signals[i]; 193 if (sig == -1) 194 return -EINVAL; 195 if (sig > 32) 196 p[1] |= 1L << (sig - 33); 197 else 198 p[0] |= 1L << (sig - 1); 199 } 200 } 201 return 0; 202} 203 204asmlinkage int solaris_sigprocmask(int how, u32 in, u32 out) 205{ 206 sigset_t in_s, *ins, out_s, *outs; 207 mm_segment_t old_fs = get_fs(); 208 int ret; 209 int (*sys_sigprocmask)(int,sigset_t __user *,sigset_t __user *) = 210 (int (*)(int,sigset_t __user *,sigset_t __user *))SYS(sigprocmask); 211 212 ins = NULL; outs = NULL; 213 if (in) { 214 u32 tmp[2]; 215 216 if (copy_from_user (tmp, (void __user *)A(in), 2*sizeof(u32))) 217 return -EFAULT; 218 ins = &in_s; 219 if (mapin (tmp, ins)) return -EINVAL; 220 } 221 if (out) outs = &out_s; 222 set_fs (KERNEL_DS); 223 ret = sys_sigprocmask((how == 3) ? SIG_SETMASK : how, 224 (void __user *)ins, (void __user *)outs); 225 set_fs (old_fs); 226 if (ret) return ret; 227 if (out) { 228 u32 tmp[4]; 229 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))) 233 return -EFAULT; 234 } 235 return 0; 236} 237 238asmlinkage long do_sol_sigsuspend(u32 mask) 239{ 240 sigset_t s; 241 u32 tmp[2]; 242 243 if (copy_from_user (tmp, (sol_sigset_t __user *)A(mask), 2*sizeof(u32))) 244 return -EFAULT; 245 if (mapin (tmp, &s)) return -EINVAL; 246 return (long)s.sig[0]; 247} 248 249struct sol_sigaction { 250 int sa_flags; 251 u32 sa_handler; 252 u32 sa_mask[4]; 253 int sa_resv[2]; 254}; 255 256asmlinkage int solaris_sigaction(int sig, u32 act, u32 old) 257{ 258 u32 tmp, tmp2[4]; 259 struct sigaction s, s2; 260 int ret; 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); 265 266 sig = mapsig(sig); 267 if (sig < 0) { 268 /* We cheat a little bit for Solaris only signals */ 269 if (old && clear_user(p, sizeof(struct sol_sigaction))) 270 return -EFAULT; 271 return 0; 272 } 273 if (act) { 274 if (get_user (tmp, &p->sa_flags)) 275 return -EFAULT; 276 s.sa_flags = 0; 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))) 284 return -EFAULT; 285 s.sa_handler = (__sighandler_t)A(tmp); 286 if (mapin (tmp2, &s.sa_mask)) return -EINVAL; 287 s.sa_restorer = NULL; 288 } 289 set_fs(KERNEL_DS); 290 ret = sys_sigaction(sig, act ? (void __user *)&s : NULL, 291 old ? (void __user *)&s2 : NULL); 292 set_fs(old_fs); 293 if (ret) return ret; 294 if (old) { 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))) 305 return -EFAULT; 306 } 307 return 0; 308} 309 310asmlinkage int solaris_sigpending(int which, u32 set) 311{ 312 sigset_t s; 313 u32 tmp[4]; 314 switch (which) { 315 case 1: /* sigpending */ 316 spin_lock_irq(¤t->sighand->siglock); 317 sigandsets(&s, ¤t->blocked, ¤t->pending.signal); 318 recalc_sigpending(); 319 spin_unlock_irq(¤t->sighand->siglock); 320 break; 321 case 2: /* sigfillset - I just set signals which have linux equivalents */ 322 sigfillset(&s); 323 break; 324 default: return -EINVAL; 325 } 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))) 329 return -EFAULT; 330 return 0; 331} 332 333asmlinkage int solaris_wait(u32 stat_loc) 334{ 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); 338 int ret, status; 339 340 ret = sys_wait4(-1, p, WUNTRACED, NULL); 341 if (ret >= 0 && stat_loc) { 342 if (get_user (status, p)) 343 return -EFAULT; 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)) 349 return -EFAULT; 350 } 351 return ret; 352} 353 354asmlinkage int solaris_waitid(int idtype, s32 pid, u32 info, int options) 355{ 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; 359 360 switch (idtype) { 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; 365 } 366 opts = 0; 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; 372 if (info) { 373 struct sol_siginfo __user *s = (void __user *)A(info); 374 375 if (get_user (status, (unsigned int __user *)A(info))) 376 return -EFAULT; 377 378 if (__put_user (SOLARIS_SIGCLD, &s->si_signo) || 379 __put_user (ret, &s->_data._proc._pid)) 380 return -EFAULT; 381 382 switch (status & 0xff) { 383 case 0: ret = SOLARIS_CLD_EXITED; 384 status = (status >> 8) & 0xff; 385 break; 386 case 0x7f: 387 status = (status >> 8) & 0xff; 388 switch (status) { 389 case SIGSTOP: 390 case SIGTSTP: ret = SOLARIS_CLD_STOPPED; 391 default: ret = SOLARIS_CLD_EXITED; 392 } 393 status = linux_to_solaris_signals[status]; 394 break; 395 default: 396 if (status & 0x80) ret = SOLARIS_CLD_DUMPED; 397 else ret = SOLARIS_CLD_KILLED; 398 status = linux_to_solaris_signals[status & 0x7f]; 399 break; 400 } 401 402 if (__put_user (ret, &s->si_code) || 403 __put_user (status, &s->_data._proc._pdata._cld._status)) 404 return -EFAULT; 405 } 406 return 0; 407} 408 409extern int svr4_setcontext(svr4_ucontext_t *c, struct pt_regs *regs); 410extern int svr4_getcontext(svr4_ucontext_t *c, struct pt_regs *regs); 411 412asmlinkage int solaris_context(struct pt_regs *regs) 413{ 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); 419 default: 420 return -EINVAL; 421 422 } 423} 424 425asmlinkage int solaris_sigaltstack(u32 ss, u32 oss) 426{ 427 return 0; 428} 429