1/* $Id: signal.c,v 1.1.1.1 2008/10/15 03:26:19 james26_jang 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/smp_lock.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 *,struct sigaction *) = 79 (int (*)(int,struct sigaction *,struct sigaction *))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, &sa, &old); 88 set_fs (old_fs); 89 if (ret < 0) return ret; 90 return (u32)(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->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); 106 } else { 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); 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->sigmask_lock); 123 sigdelsetmask(¤t->blocked, _S(sig)); 124 recalc_sigpending(current); 125 spin_unlock_irq(¤t->sigmask_lock); 126 return 0; 127} 128 129static inline long solaris_sigignore(int sig) 130{ 131 return sig_handler (sig, (u32)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 *,sigset_t *) = 210 (int (*)(int,sigset_t *,sigset_t *))SYS(sigprocmask); 211 212 ins = NULL; outs = NULL; 213 if (in) { 214 u32 tmp[2]; 215 216 if (copy_from_user (tmp, (sol_sigset_t *)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, ins, outs); 224 set_fs (old_fs); 225 if (ret) return ret; 226 if (out) { 227 u32 tmp[4]; 228 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))) 232 return -EFAULT; 233 } 234 return 0; 235} 236 237asmlinkage long do_sol_sigsuspend(u32 mask) 238{ 239 sigset_t s; 240 u32 tmp[2]; 241 242 if (copy_from_user (tmp, (sol_sigset_t *)A(mask), 2*sizeof(u32))) 243 return -EFAULT; 244 if (mapin (tmp, &s)) return -EINVAL; 245 return (long)s.sig[0]; 246} 247 248struct sol_sigaction { 249 int sa_flags; 250 u32 sa_handler; 251 u32 sa_mask[4]; 252 int sa_resv[2]; 253}; 254 255asmlinkage int solaris_sigaction(int sig, u32 act, u32 old) 256{ 257 u32 tmp, tmp2[4]; 258 struct sigaction s, s2; 259 int ret; 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); 263 264 sig = mapsig(sig); 265 if (sig < 0) { 266 /* We cheat a little bit for Solaris only signals */ 267 if (old && clear_user((struct sol_sigaction *)A(old), sizeof(struct sol_sigaction))) 268 return -EFAULT; 269 return 0; 270 } 271 if (act) { 272 if (get_user (tmp, &((struct sol_sigaction *)A(act))->sa_flags)) 273 return -EFAULT; 274 s.sa_flags = 0; 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))) 282 return -EFAULT; 283 s.sa_handler = (__sighandler_t)A(tmp); 284 if (mapin (tmp2, &s.sa_mask)) return -EINVAL; 285 s.sa_restorer = 0; 286 } 287 set_fs(KERNEL_DS); 288 ret = sys_sigaction(sig, act ? &s : NULL, old ? &s2 : NULL); 289 set_fs(old_fs); 290 if (ret) return ret; 291 if (old) { 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))) 302 return -EFAULT; 303 } 304 return 0; 305} 306 307asmlinkage int solaris_sigpending(int which, u32 set) 308{ 309 sigset_t s; 310 u32 tmp[4]; 311 switch (which) { 312 case 1: /* sigpending */ 313 spin_lock_irq(¤t->sigmask_lock); 314 sigandsets(&s, ¤t->blocked, ¤t->pending.signal); 315 recalc_sigpending(current); 316 spin_unlock_irq(¤t->sigmask_lock); 317 break; 318 case 2: /* sigfillset - I just set signals which have linux equivalents */ 319 sigfillset(&s); 320 break; 321 default: return -EINVAL; 322 } 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))) 326 return -EFAULT; 327 return 0; 328} 329 330asmlinkage int solaris_wait(u32 stat_loc) 331{ 332 int (*sys_wait4)(pid_t,unsigned int *, int, struct rusage *) = 333 (int (*)(pid_t,unsigned int *, int, struct rusage *))SYS(wait4); 334 int ret, status; 335 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))) 339 return -EFAULT; 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))) 345 return -EFAULT; 346 } 347 return ret; 348} 349 350asmlinkage int solaris_waitid(int idtype, s32 pid, u32 info, int options) 351{ 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; 355 356 switch (idtype) { 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; 361 } 362 opts = 0; 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; 368 if (info) { 369 struct sol_siginfo *s = (struct sol_siginfo *)A(info); 370 371 if (get_user (status, (unsigned int *)A(info))) 372 return -EFAULT; 373 374 if (__put_user (SOLARIS_SIGCLD, &s->si_signo) || 375 __put_user (ret, &s->_data._proc._pid)) 376 return -EFAULT; 377 378 switch (status & 0xff) { 379 case 0: ret = SOLARIS_CLD_EXITED; 380 status = (status >> 8) & 0xff; 381 break; 382 case 0x7f: 383 status = (status >> 8) & 0xff; 384 switch (status) { 385 case SIGSTOP: 386 case SIGTSTP: ret = SOLARIS_CLD_STOPPED; 387 default: ret = SOLARIS_CLD_EXITED; 388 } 389 status = linux_to_solaris_signals[status]; 390 break; 391 default: 392 if (status & 0x80) ret = SOLARIS_CLD_DUMPED; 393 else ret = SOLARIS_CLD_KILLED; 394 status = linux_to_solaris_signals[status & 0x7f]; 395 break; 396 } 397 398 if (__put_user (ret, &s->si_code) || 399 __put_user (status, &s->_data._proc._pdata._cld._status)) 400 return -EFAULT; 401 } 402 return 0; 403} 404 405extern int svr4_setcontext(svr4_ucontext_t *c, struct pt_regs *regs); 406extern int svr4_getcontext(svr4_ucontext_t *c, struct pt_regs *regs); 407 408asmlinkage int solaris_context(struct pt_regs *regs) 409{ 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); 415 default: 416 return -EINVAL; 417 418 } 419} 420 421asmlinkage int solaris_sigaltstack(u32 ss, u32 oss) 422{ 423 return 0; 424} 425