diff options
author | Ralf Baechle <ralf@linux-mips.org> | 2008-07-15 13:44:30 -0400 |
---|---|---|
committer | Ralf Baechle <ralf@linux-mips.org> | 2008-07-15 13:44:30 -0400 |
commit | 2957c9e61ee9c37e7ebf2c8acab03e073fe942fd (patch) | |
tree | 50b4baea3b130ed3e1ef95a9c0f2d2761dd88693 /arch/mips/kernel/irixsig.c | |
parent | 997288517ec839b7639fcba77111256b13a66000 (diff) |
[MIPS] IRIX: Goodbye and thanks for all the fish
Never terribly functional or popular, plagued by hard to fix bugs the time
to say goodbye has more than arrived.
Signed-off-by: Ralf Baechle <ralf@linux-mips.org>
Diffstat (limited to 'arch/mips/kernel/irixsig.c')
-rw-r--r-- | arch/mips/kernel/irixsig.c | 888 |
1 files changed, 0 insertions, 888 deletions
diff --git a/arch/mips/kernel/irixsig.c b/arch/mips/kernel/irixsig.c deleted file mode 100644 index 0215c805a592..000000000000 --- a/arch/mips/kernel/irixsig.c +++ /dev/null | |||
@@ -1,888 +0,0 @@ | |||
1 | /* | ||
2 | * irixsig.c: WHEEE, IRIX signals! YOW, am I compatible or what?!?! | ||
3 | * | ||
4 | * Copyright (C) 1996 David S. Miller (dm@engr.sgi.com) | ||
5 | * Copyright (C) 1997 - 2000 Ralf Baechle (ralf@gnu.org) | ||
6 | * Copyright (C) 2000 Silicon Graphics, Inc. | ||
7 | */ | ||
8 | #include <linux/kernel.h> | ||
9 | #include <linux/sched.h> | ||
10 | #include <linux/mm.h> | ||
11 | #include <linux/errno.h> | ||
12 | #include <linux/smp.h> | ||
13 | #include <linux/time.h> | ||
14 | #include <linux/ptrace.h> | ||
15 | #include <linux/resource.h> | ||
16 | |||
17 | #include <asm/ptrace.h> | ||
18 | #include <asm/uaccess.h> | ||
19 | #include <asm/unistd.h> | ||
20 | |||
21 | #undef DEBUG_SIG | ||
22 | |||
23 | #define _S(nr) (1<<((nr)-1)) | ||
24 | |||
25 | #define _BLOCKABLE (~(_S(SIGKILL) | _S(SIGSTOP))) | ||
26 | |||
27 | #define _IRIX_NSIG 128 | ||
28 | #define _IRIX_NSIG_BPW BITS_PER_LONG | ||
29 | #define _IRIX_NSIG_WORDS (_IRIX_NSIG / _IRIX_NSIG_BPW) | ||
30 | |||
31 | typedef struct { | ||
32 | unsigned long sig[_IRIX_NSIG_WORDS]; | ||
33 | } irix_sigset_t; | ||
34 | |||
35 | struct sigctx_irix5 { | ||
36 | u32 rmask, cp0_status; | ||
37 | u64 pc; | ||
38 | u64 regs[32]; | ||
39 | u64 fpregs[32]; | ||
40 | u32 usedfp, fpcsr, fpeir, sstk_flags; | ||
41 | u64 hi, lo; | ||
42 | u64 cp0_cause, cp0_badvaddr, _unused0; | ||
43 | irix_sigset_t sigset; | ||
44 | u64 weird_fpu_thing; | ||
45 | u64 _unused1[31]; | ||
46 | }; | ||
47 | |||
48 | #ifdef DEBUG_SIG | ||
49 | /* Debugging */ | ||
50 | static inline void dump_irix5_sigctx(struct sigctx_irix5 *c) | ||
51 | { | ||
52 | int i; | ||
53 | |||
54 | printk("misc: rmask[%08lx] status[%08lx] pc[%08lx]\n", | ||
55 | (unsigned long) c->rmask, | ||
56 | (unsigned long) c->cp0_status, | ||
57 | (unsigned long) c->pc); | ||
58 | printk("regs: "); | ||
59 | for(i = 0; i < 16; i++) | ||
60 | printk("[%d]<%08lx> ", i, (unsigned long) c->regs[i]); | ||
61 | printk("\nregs: "); | ||
62 | for(i = 16; i < 32; i++) | ||
63 | printk("[%d]<%08lx> ", i, (unsigned long) c->regs[i]); | ||
64 | printk("\nfpregs: "); | ||
65 | for(i = 0; i < 16; i++) | ||
66 | printk("[%d]<%08lx> ", i, (unsigned long) c->fpregs[i]); | ||
67 | printk("\nfpregs: "); | ||
68 | for(i = 16; i < 32; i++) | ||
69 | printk("[%d]<%08lx> ", i, (unsigned long) c->fpregs[i]); | ||
70 | printk("misc: usedfp[%d] fpcsr[%08lx] fpeir[%08lx] stk_flgs[%08lx]\n", | ||
71 | (int) c->usedfp, (unsigned long) c->fpcsr, | ||
72 | (unsigned long) c->fpeir, (unsigned long) c->sstk_flags); | ||
73 | printk("misc: hi[%08lx] lo[%08lx] cause[%08lx] badvaddr[%08lx]\n", | ||
74 | (unsigned long) c->hi, (unsigned long) c->lo, | ||
75 | (unsigned long) c->cp0_cause, (unsigned long) c->cp0_badvaddr); | ||
76 | printk("misc: sigset<0>[%08lx] sigset<1>[%08lx] sigset<2>[%08lx] " | ||
77 | "sigset<3>[%08lx]\n", (unsigned long) c->sigset.sig[0], | ||
78 | (unsigned long) c->sigset.sig[1], | ||
79 | (unsigned long) c->sigset.sig[2], | ||
80 | (unsigned long) c->sigset.sig[3]); | ||
81 | } | ||
82 | #endif | ||
83 | |||
84 | static int setup_irix_frame(struct k_sigaction *ka, struct pt_regs *regs, | ||
85 | int signr, sigset_t *oldmask) | ||
86 | { | ||
87 | struct sigctx_irix5 __user *ctx; | ||
88 | unsigned long sp; | ||
89 | int error, i; | ||
90 | |||
91 | sp = regs->regs[29]; | ||
92 | sp -= sizeof(struct sigctx_irix5); | ||
93 | sp &= ~(0xf); | ||
94 | ctx = (struct sigctx_irix5 __user *) sp; | ||
95 | if (!access_ok(VERIFY_WRITE, ctx, sizeof(*ctx))) | ||
96 | goto segv_and_exit; | ||
97 | |||
98 | error = __put_user(0, &ctx->weird_fpu_thing); | ||
99 | error |= __put_user(~(0x00000001), &ctx->rmask); | ||
100 | error |= __put_user(0, &ctx->regs[0]); | ||
101 | for(i = 1; i < 32; i++) | ||
102 | error |= __put_user((u64) regs->regs[i], &ctx->regs[i]); | ||
103 | |||
104 | error |= __put_user((u64) regs->hi, &ctx->hi); | ||
105 | error |= __put_user((u64) regs->lo, &ctx->lo); | ||
106 | error |= __put_user((u64) regs->cp0_epc, &ctx->pc); | ||
107 | error |= __put_user(!!used_math(), &ctx->usedfp); | ||
108 | error |= __put_user((u64) regs->cp0_cause, &ctx->cp0_cause); | ||
109 | error |= __put_user((u64) regs->cp0_badvaddr, &ctx->cp0_badvaddr); | ||
110 | |||
111 | error |= __put_user(0, &ctx->sstk_flags); /* XXX sigstack unimp... todo... */ | ||
112 | |||
113 | error |= __copy_to_user(&ctx->sigset, oldmask, sizeof(irix_sigset_t)) ? -EFAULT : 0; | ||
114 | |||
115 | if (error) | ||
116 | goto segv_and_exit; | ||
117 | |||
118 | #ifdef DEBUG_SIG | ||
119 | dump_irix5_sigctx(ctx); | ||
120 | #endif | ||
121 | |||
122 | regs->regs[4] = (unsigned long) signr; | ||
123 | regs->regs[5] = 0; /* XXX sigcode XXX */ | ||
124 | regs->regs[6] = regs->regs[29] = sp; | ||
125 | regs->regs[7] = (unsigned long) ka->sa.sa_handler; | ||
126 | regs->regs[25] = regs->cp0_epc = (unsigned long) ka->sa_restorer; | ||
127 | |||
128 | return 1; | ||
129 | |||
130 | segv_and_exit: | ||
131 | force_sigsegv(signr, current); | ||
132 | return 0; | ||
133 | } | ||
134 | |||
135 | static int inline | ||
136 | setup_irix_rt_frame(struct k_sigaction * ka, struct pt_regs *regs, | ||
137 | int signr, sigset_t *oldmask, siginfo_t *info) | ||
138 | { | ||
139 | printk("Aiee: setup_tr_frame wants to be written"); | ||
140 | do_exit(SIGSEGV); | ||
141 | } | ||
142 | |||
143 | static inline int handle_signal(unsigned long sig, siginfo_t *info, | ||
144 | struct k_sigaction *ka, sigset_t *oldset, struct pt_regs * regs) | ||
145 | { | ||
146 | int ret; | ||
147 | |||
148 | switch(regs->regs[0]) { | ||
149 | case ERESTARTNOHAND: | ||
150 | regs->regs[2] = EINTR; | ||
151 | break; | ||
152 | case ERESTARTSYS: | ||
153 | if(!(ka->sa.sa_flags & SA_RESTART)) { | ||
154 | regs->regs[2] = EINTR; | ||
155 | break; | ||
156 | } | ||
157 | /* fallthrough */ | ||
158 | case ERESTARTNOINTR: /* Userland will reload $v0. */ | ||
159 | regs->cp0_epc -= 8; | ||
160 | } | ||
161 | |||
162 | regs->regs[0] = 0; /* Don't deal with this again. */ | ||
163 | |||
164 | if (ka->sa.sa_flags & SA_SIGINFO) | ||
165 | ret = setup_irix_rt_frame(ka, regs, sig, oldset, info); | ||
166 | else | ||
167 | ret = setup_irix_frame(ka, regs, sig, oldset); | ||
168 | |||
169 | spin_lock_irq(¤t->sighand->siglock); | ||
170 | sigorsets(¤t->blocked, ¤t->blocked, &ka->sa.sa_mask); | ||
171 | if (!(ka->sa.sa_flags & SA_NODEFER)) | ||
172 | sigaddset(¤t->blocked, sig); | ||
173 | recalc_sigpending(); | ||
174 | spin_unlock_irq(¤t->sighand->siglock); | ||
175 | |||
176 | return ret; | ||
177 | } | ||
178 | |||
179 | void do_irix_signal(struct pt_regs *regs) | ||
180 | { | ||
181 | struct k_sigaction ka; | ||
182 | siginfo_t info; | ||
183 | int signr; | ||
184 | sigset_t *oldset; | ||
185 | |||
186 | /* | ||
187 | * We want the common case to go fast, which is why we may in certain | ||
188 | * cases get here from kernel mode. Just return without doing anything | ||
189 | * if so. | ||
190 | */ | ||
191 | if (!user_mode(regs)) | ||
192 | return; | ||
193 | |||
194 | if (test_thread_flag(TIF_RESTORE_SIGMASK)) | ||
195 | oldset = ¤t->saved_sigmask; | ||
196 | else | ||
197 | oldset = ¤t->blocked; | ||
198 | |||
199 | signr = get_signal_to_deliver(&info, &ka, regs, NULL); | ||
200 | if (signr > 0) { | ||
201 | /* Whee! Actually deliver the signal. */ | ||
202 | if (handle_signal(signr, &info, &ka, oldset, regs) == 0) { | ||
203 | /* a signal was successfully delivered; the saved | ||
204 | * sigmask will have been stored in the signal frame, | ||
205 | * and will be restored by sigreturn, so we can simply | ||
206 | * clear the TIF_RESTORE_SIGMASK flag */ | ||
207 | if (test_thread_flag(TIF_RESTORE_SIGMASK)) | ||
208 | clear_thread_flag(TIF_RESTORE_SIGMASK); | ||
209 | } | ||
210 | |||
211 | return; | ||
212 | } | ||
213 | |||
214 | /* | ||
215 | * Who's code doesn't conform to the restartable syscall convention | ||
216 | * dies here!!! The li instruction, a single machine instruction, | ||
217 | * must directly be followed by the syscall instruction. | ||
218 | */ | ||
219 | if (regs->regs[0]) { | ||
220 | if (regs->regs[2] == ERESTARTNOHAND || | ||
221 | regs->regs[2] == ERESTARTSYS || | ||
222 | regs->regs[2] == ERESTARTNOINTR) { | ||
223 | regs->cp0_epc -= 8; | ||
224 | } | ||
225 | if (regs->regs[2] == ERESTART_RESTARTBLOCK) { | ||
226 | regs->regs[2] = __NR_restart_syscall; | ||
227 | regs->regs[7] = regs->regs[26]; | ||
228 | regs->cp0_epc -= 4; | ||
229 | } | ||
230 | regs->regs[0] = 0; /* Don't deal with this again. */ | ||
231 | } | ||
232 | |||
233 | /* | ||
234 | * If there's no signal to deliver, we just put the saved sigmask | ||
235 | * back | ||
236 | */ | ||
237 | if (test_thread_flag(TIF_RESTORE_SIGMASK)) { | ||
238 | clear_thread_flag(TIF_RESTORE_SIGMASK); | ||
239 | sigprocmask(SIG_SETMASK, ¤t->saved_sigmask, NULL); | ||
240 | } | ||
241 | } | ||
242 | |||
243 | asmlinkage void | ||
244 | irix_sigreturn(struct pt_regs *regs) | ||
245 | { | ||
246 | struct sigctx_irix5 __user *context, *magic; | ||
247 | unsigned long umask, mask; | ||
248 | u64 *fregs; | ||
249 | u32 usedfp; | ||
250 | int error, sig, i, base = 0; | ||
251 | sigset_t blocked; | ||
252 | |||
253 | /* Always make any pending restarted system calls return -EINTR */ | ||
254 | current_thread_info()->restart_block.fn = do_no_restart_syscall; | ||
255 | |||
256 | if (regs->regs[2] == 1000) | ||
257 | base = 1; | ||
258 | |||
259 | context = (struct sigctx_irix5 __user *) regs->regs[base + 4]; | ||
260 | magic = (struct sigctx_irix5 __user *) regs->regs[base + 5]; | ||
261 | sig = (int) regs->regs[base + 6]; | ||
262 | #ifdef DEBUG_SIG | ||
263 | printk("[%s:%d] IRIX sigreturn(scp[%p],ucp[%p],sig[%d])\n", | ||
264 | current->comm, current->pid, context, magic, sig); | ||
265 | #endif | ||
266 | if (!context) | ||
267 | context = magic; | ||
268 | if (!access_ok(VERIFY_READ, context, sizeof(struct sigctx_irix5))) | ||
269 | goto badframe; | ||
270 | |||
271 | #ifdef DEBUG_SIG | ||
272 | dump_irix5_sigctx(context); | ||
273 | #endif | ||
274 | |||
275 | error = __get_user(regs->cp0_epc, &context->pc); | ||
276 | error |= __get_user(umask, &context->rmask); | ||
277 | |||
278 | mask = 2; | ||
279 | for (i = 1; i < 32; i++, mask <<= 1) { | ||
280 | if (umask & mask) | ||
281 | error |= __get_user(regs->regs[i], &context->regs[i]); | ||
282 | } | ||
283 | error |= __get_user(regs->hi, &context->hi); | ||
284 | error |= __get_user(regs->lo, &context->lo); | ||
285 | |||
286 | error |= __get_user(usedfp, &context->usedfp); | ||
287 | if ((umask & 1) && usedfp) { | ||
288 | fregs = (u64 *) ¤t->thread.fpu; | ||
289 | |||
290 | for(i = 0; i < 32; i++) | ||
291 | error |= __get_user(fregs[i], &context->fpregs[i]); | ||
292 | error |= __get_user(current->thread.fpu.fcr31, &context->fpcsr); | ||
293 | } | ||
294 | |||
295 | /* XXX do sigstack crapola here... XXX */ | ||
296 | |||
297 | error |= __copy_from_user(&blocked, &context->sigset, sizeof(blocked)) ? -EFAULT : 0; | ||
298 | |||
299 | if (error) | ||
300 | goto badframe; | ||
301 | |||
302 | sigdelsetmask(&blocked, ~_BLOCKABLE); | ||
303 | spin_lock_irq(¤t->sighand->siglock); | ||
304 | current->blocked = blocked; | ||
305 | recalc_sigpending(); | ||
306 | spin_unlock_irq(¤t->sighand->siglock); | ||
307 | |||
308 | /* | ||
309 | * Don't let your children do this ... | ||
310 | */ | ||
311 | __asm__ __volatile__( | ||
312 | "move\t$29,%0\n\t" | ||
313 | "j\tsyscall_exit" | ||
314 | :/* no outputs */ | ||
315 | :"r" (®s)); | ||
316 | /* Unreached */ | ||
317 | |||
318 | badframe: | ||
319 | force_sig(SIGSEGV, current); | ||
320 | } | ||
321 | |||
322 | struct sigact_irix5 { | ||
323 | int flags; | ||
324 | void (*handler)(int); | ||
325 | u32 sigset[4]; | ||
326 | int _unused0[2]; | ||
327 | }; | ||
328 | |||
329 | #define SIG_SETMASK32 256 /* Goodie from SGI for BSD compatibility: | ||
330 | set only the low 32 bit of the sigset. */ | ||
331 | |||
332 | #ifdef DEBUG_SIG | ||
333 | static inline void dump_sigact_irix5(struct sigact_irix5 *p) | ||
334 | { | ||
335 | printk("<f[%d] hndlr[%08lx] msk[%08lx]>", p->flags, | ||
336 | (unsigned long) p->handler, | ||
337 | (unsigned long) p->sigset[0]); | ||
338 | } | ||
339 | #endif | ||
340 | |||
341 | asmlinkage int | ||
342 | irix_sigaction(int sig, const struct sigaction __user *act, | ||
343 | struct sigaction __user *oact, void __user *trampoline) | ||
344 | { | ||
345 | struct k_sigaction new_ka, old_ka; | ||
346 | int ret; | ||
347 | |||
348 | #ifdef DEBUG_SIG | ||
349 | printk(" (%d,%s,%s,%08lx) ", sig, (!new ? "0" : "NEW"), | ||
350 | (!old ? "0" : "OLD"), trampoline); | ||
351 | if(new) { | ||
352 | dump_sigact_irix5(new); printk(" "); | ||
353 | } | ||
354 | #endif | ||
355 | if (act) { | ||
356 | sigset_t mask; | ||
357 | int err; | ||
358 | |||
359 | if (!access_ok(VERIFY_READ, act, sizeof(*act))) | ||
360 | return -EFAULT; | ||
361 | err = __get_user(new_ka.sa.sa_handler, &act->sa_handler); | ||
362 | err |= __get_user(new_ka.sa.sa_flags, &act->sa_flags); | ||
363 | |||
364 | err |= __copy_from_user(&mask, &act->sa_mask, sizeof(sigset_t)) ? -EFAULT : 0; | ||
365 | if (err) | ||
366 | return err; | ||
367 | |||
368 | /* | ||
369 | * Hmmm... methinks IRIX libc always passes a valid trampoline | ||
370 | * value for all invocations of sigaction. Will have to | ||
371 | * investigate. POSIX POSIX, die die die... | ||
372 | */ | ||
373 | new_ka.sa_restorer = trampoline; | ||
374 | } | ||
375 | |||
376 | /* XXX Implement SIG_SETMASK32 for IRIX compatibility */ | ||
377 | ret = do_sigaction(sig, act ? &new_ka : NULL, oact ? &old_ka : NULL); | ||
378 | |||
379 | if (!ret && oact) { | ||
380 | int err; | ||
381 | |||
382 | if (!access_ok(VERIFY_WRITE, oact, sizeof(*oact))) | ||
383 | return -EFAULT; | ||
384 | |||
385 | err = __put_user(old_ka.sa.sa_handler, &oact->sa_handler); | ||
386 | err |= __put_user(old_ka.sa.sa_flags, &oact->sa_flags); | ||
387 | err |= __copy_to_user(&oact->sa_mask, &old_ka.sa.sa_mask, | ||
388 | sizeof(sigset_t)) ? -EFAULT : 0; | ||
389 | if (err) | ||
390 | return -EFAULT; | ||
391 | } | ||
392 | |||
393 | return ret; | ||
394 | } | ||
395 | |||
396 | asmlinkage int irix_sigpending(irix_sigset_t __user *set) | ||
397 | { | ||
398 | return do_sigpending(set, sizeof(*set)); | ||
399 | } | ||
400 | |||
401 | asmlinkage int irix_sigprocmask(int how, irix_sigset_t __user *new, | ||
402 | irix_sigset_t __user *old) | ||
403 | { | ||
404 | sigset_t oldbits, newbits; | ||
405 | |||
406 | if (new) { | ||
407 | if (!access_ok(VERIFY_READ, new, sizeof(*new))) | ||
408 | return -EFAULT; | ||
409 | if (__copy_from_user(&newbits, new, sizeof(unsigned long)*4)) | ||
410 | return -EFAULT; | ||
411 | sigdelsetmask(&newbits, ~_BLOCKABLE); | ||
412 | |||
413 | spin_lock_irq(¤t->sighand->siglock); | ||
414 | oldbits = current->blocked; | ||
415 | |||
416 | switch(how) { | ||
417 | case 1: | ||
418 | sigorsets(&newbits, &oldbits, &newbits); | ||
419 | break; | ||
420 | |||
421 | case 2: | ||
422 | sigandsets(&newbits, &oldbits, &newbits); | ||
423 | break; | ||
424 | |||
425 | case 3: | ||
426 | break; | ||
427 | |||
428 | case 256: | ||
429 | siginitset(&newbits, newbits.sig[0]); | ||
430 | break; | ||
431 | |||
432 | default: | ||
433 | spin_unlock_irq(¤t->sighand->siglock); | ||
434 | return -EINVAL; | ||
435 | } | ||
436 | recalc_sigpending(); | ||
437 | spin_unlock_irq(¤t->sighand->siglock); | ||
438 | } | ||
439 | if (old) | ||
440 | return copy_to_user(old, ¤t->blocked, | ||
441 | sizeof(unsigned long)*4) ? -EFAULT : 0; | ||
442 | |||
443 | return 0; | ||
444 | } | ||
445 | |||
446 | asmlinkage int irix_sigsuspend(struct pt_regs *regs) | ||
447 | { | ||
448 | sigset_t newset; | ||
449 | sigset_t __user *uset; | ||
450 | |||
451 | uset = (sigset_t __user *) regs->regs[4]; | ||
452 | if (copy_from_user(&newset, uset, sizeof(sigset_t))) | ||
453 | return -EFAULT; | ||
454 | sigdelsetmask(&newset, ~_BLOCKABLE); | ||
455 | |||
456 | spin_lock_irq(¤t->sighand->siglock); | ||
457 | current->saved_sigmask = current->blocked; | ||
458 | current->blocked = newset; | ||
459 | recalc_sigpending(); | ||
460 | spin_unlock_irq(¤t->sighand->siglock); | ||
461 | |||
462 | current->state = TASK_INTERRUPTIBLE; | ||
463 | schedule(); | ||
464 | set_thread_flag(TIF_RESTORE_SIGMASK); | ||
465 | return -ERESTARTNOHAND; | ||
466 | } | ||
467 | |||
468 | /* hate hate hate... */ | ||
469 | struct irix5_siginfo { | ||
470 | int sig, code, error; | ||
471 | union { | ||
472 | char unused[128 - (3 * 4)]; /* Safety net. */ | ||
473 | struct { | ||
474 | int pid; | ||
475 | union { | ||
476 | int uid; | ||
477 | struct { | ||
478 | int utime, status, stime; | ||
479 | } child; | ||
480 | } procdata; | ||
481 | } procinfo; | ||
482 | |||
483 | unsigned long fault_addr; | ||
484 | |||
485 | struct { | ||
486 | int fd; | ||
487 | long band; | ||
488 | } fileinfo; | ||
489 | |||
490 | unsigned long sigval; | ||
491 | } stuff; | ||
492 | }; | ||
493 | |||
494 | asmlinkage int irix_sigpoll_sys(unsigned long __user *set, | ||
495 | struct irix5_siginfo __user *info, struct timespec __user *tp) | ||
496 | { | ||
497 | long expire = MAX_SCHEDULE_TIMEOUT; | ||
498 | sigset_t kset; | ||
499 | int i, sig, error, timeo = 0; | ||
500 | struct timespec ktp; | ||
501 | |||
502 | #ifdef DEBUG_SIG | ||
503 | printk("[%s:%d] irix_sigpoll_sys(%p,%p,%p)\n", | ||
504 | current->comm, current->pid, set, info, tp); | ||
505 | #endif | ||
506 | |||
507 | /* Must always specify the signal set. */ | ||
508 | if (!set) | ||
509 | return -EINVAL; | ||
510 | |||
511 | if (copy_from_user(&kset, set, sizeof(set))) | ||
512 | return -EFAULT; | ||
513 | |||
514 | if (info && clear_user(info, sizeof(*info))) { | ||
515 | error = -EFAULT; | ||
516 | goto out; | ||
517 | } | ||
518 | |||
519 | if (tp) { | ||
520 | if (copy_from_user(&ktp, tp, sizeof(*tp))) | ||
521 | return -EFAULT; | ||
522 | |||
523 | if (!ktp.tv_sec && !ktp.tv_nsec) | ||
524 | return -EINVAL; | ||
525 | |||
526 | expire = timespec_to_jiffies(&ktp) + | ||
527 | (ktp.tv_sec || ktp.tv_nsec); | ||
528 | } | ||
529 | |||
530 | while(1) { | ||
531 | long tmp = 0; | ||
532 | |||
533 | expire = schedule_timeout_interruptible(expire); | ||
534 | |||
535 | for (i=0; i < _IRIX_NSIG_WORDS; i++) | ||
536 | tmp |= (current->pending.signal.sig[i] & kset.sig[i]); | ||
537 | |||
538 | if (tmp) | ||
539 | break; | ||
540 | if (!expire) { | ||
541 | timeo = 1; | ||
542 | break; | ||
543 | } | ||
544 | if (signal_pending(current)) | ||
545 | return -EINTR; | ||
546 | } | ||
547 | if (timeo) | ||
548 | return -EAGAIN; | ||
549 | |||
550 | for (sig = 1; i <= 65 /* IRIX_NSIG */; sig++) { | ||
551 | if (sigismember (&kset, sig)) | ||
552 | continue; | ||
553 | if (sigismember (¤t->pending.signal, sig)) { | ||
554 | /* XXX need more than this... */ | ||
555 | if (info) | ||
556 | return copy_to_user(&info->sig, &sig, sizeof(sig)); | ||
557 | return 0; | ||
558 | } | ||
559 | } | ||
560 | |||
561 | /* Should not get here, but do something sane if we do. */ | ||
562 | error = -EINTR; | ||
563 | |||
564 | out: | ||
565 | return error; | ||
566 | } | ||
567 | |||
568 | /* This is here because of irix5_siginfo definition. */ | ||
569 | #define IRIX_P_PID 0 | ||
570 | #define IRIX_P_PGID 2 | ||
571 | #define IRIX_P_ALL 7 | ||
572 | |||
573 | #define W_EXITED 1 | ||
574 | #define W_TRAPPED 2 | ||
575 | #define W_STOPPED 4 | ||
576 | #define W_CONT 8 | ||
577 | #define W_NOHANG 64 | ||
578 | |||
579 | #define W_MASK (W_EXITED | W_TRAPPED | W_STOPPED | W_CONT | W_NOHANG) | ||
580 | |||
581 | asmlinkage int irix_waitsys(int type, int upid, | ||
582 | struct irix5_siginfo __user *info, int options, | ||
583 | struct rusage __user *ru) | ||
584 | { | ||
585 | struct pid *pid = NULL; | ||
586 | int flag, retval; | ||
587 | DECLARE_WAITQUEUE(wait, current); | ||
588 | struct task_struct *tsk; | ||
589 | struct task_struct *p; | ||
590 | struct list_head *_p; | ||
591 | |||
592 | if (!info) | ||
593 | return -EINVAL; | ||
594 | |||
595 | if (!access_ok(VERIFY_WRITE, info, sizeof(*info))) | ||
596 | return -EFAULT; | ||
597 | |||
598 | if (ru) | ||
599 | if (!access_ok(VERIFY_WRITE, ru, sizeof(*ru))) | ||
600 | return -EFAULT; | ||
601 | |||
602 | if (options & ~W_MASK) | ||
603 | return -EINVAL; | ||
604 | |||
605 | if (type != IRIX_P_PID && type != IRIX_P_PGID && type != IRIX_P_ALL) | ||
606 | return -EINVAL; | ||
607 | |||
608 | if (type != IRIX_P_ALL) | ||
609 | pid = find_get_pid(upid); | ||
610 | add_wait_queue(¤t->signal->wait_chldexit, &wait); | ||
611 | repeat: | ||
612 | flag = 0; | ||
613 | current->state = TASK_INTERRUPTIBLE; | ||
614 | read_lock(&tasklist_lock); | ||
615 | tsk = current; | ||
616 | list_for_each(_p, &tsk->children) { | ||
617 | p = list_entry(_p, struct task_struct, sibling); | ||
618 | if ((type == IRIX_P_PID) && task_pid(p) != pid) | ||
619 | continue; | ||
620 | if ((type == IRIX_P_PGID) && task_pgrp(p) != pid) | ||
621 | continue; | ||
622 | if ((p->exit_signal != SIGCHLD)) | ||
623 | continue; | ||
624 | flag = 1; | ||
625 | switch (p->state) { | ||
626 | case TASK_STOPPED: | ||
627 | if (!p->exit_code) | ||
628 | continue; | ||
629 | if (!(options & (W_TRAPPED|W_STOPPED)) && | ||
630 | !(p->ptrace & PT_PTRACED)) | ||
631 | continue; | ||
632 | read_unlock(&tasklist_lock); | ||
633 | |||
634 | /* move to end of parent's list to avoid starvation */ | ||
635 | write_lock_irq(&tasklist_lock); | ||
636 | remove_parent(p); | ||
637 | add_parent(p); | ||
638 | write_unlock_irq(&tasklist_lock); | ||
639 | retval = ru ? getrusage(p, RUSAGE_BOTH, ru) : 0; | ||
640 | if (retval) | ||
641 | goto end_waitsys; | ||
642 | |||
643 | retval = __put_user(SIGCHLD, &info->sig); | ||
644 | retval |= __put_user(0, &info->code); | ||
645 | retval |= __put_user(task_pid_vnr(p), &info->stuff.procinfo.pid); | ||
646 | retval |= __put_user((p->exit_code >> 8) & 0xff, | ||
647 | &info->stuff.procinfo.procdata.child.status); | ||
648 | retval |= __put_user(p->utime, &info->stuff.procinfo.procdata.child.utime); | ||
649 | retval |= __put_user(p->stime, &info->stuff.procinfo.procdata.child.stime); | ||
650 | if (retval) | ||
651 | goto end_waitsys; | ||
652 | |||
653 | p->exit_code = 0; | ||
654 | goto end_waitsys; | ||
655 | |||
656 | case EXIT_ZOMBIE: | ||
657 | current->signal->cutime += p->utime + p->signal->cutime; | ||
658 | current->signal->cstime += p->stime + p->signal->cstime; | ||
659 | if (ru != NULL) | ||
660 | getrusage(p, RUSAGE_BOTH, ru); | ||
661 | retval = __put_user(SIGCHLD, &info->sig); | ||
662 | retval |= __put_user(1, &info->code); /* CLD_EXITED */ | ||
663 | retval |= __put_user(task_pid_vnr(p), &info->stuff.procinfo.pid); | ||
664 | retval |= __put_user((p->exit_code >> 8) & 0xff, | ||
665 | &info->stuff.procinfo.procdata.child.status); | ||
666 | retval |= __put_user(p->utime, | ||
667 | &info->stuff.procinfo.procdata.child.utime); | ||
668 | retval |= __put_user(p->stime, | ||
669 | &info->stuff.procinfo.procdata.child.stime); | ||
670 | if (retval) | ||
671 | goto end_waitsys; | ||
672 | |||
673 | if (p->real_parent != p->parent) { | ||
674 | write_lock_irq(&tasklist_lock); | ||
675 | remove_parent(p); | ||
676 | p->parent = p->real_parent; | ||
677 | add_parent(p); | ||
678 | do_notify_parent(p, SIGCHLD); | ||
679 | write_unlock_irq(&tasklist_lock); | ||
680 | } else | ||
681 | release_task(p); | ||
682 | goto end_waitsys; | ||
683 | default: | ||
684 | continue; | ||
685 | } | ||
686 | tsk = next_thread(tsk); | ||
687 | } | ||
688 | read_unlock(&tasklist_lock); | ||
689 | if (flag) { | ||
690 | retval = 0; | ||
691 | if (options & W_NOHANG) | ||
692 | goto end_waitsys; | ||
693 | retval = -ERESTARTSYS; | ||
694 | if (signal_pending(current)) | ||
695 | goto end_waitsys; | ||
696 | current->state = TASK_INTERRUPTIBLE; | ||
697 | schedule(); | ||
698 | goto repeat; | ||
699 | } | ||
700 | retval = -ECHILD; | ||
701 | end_waitsys: | ||
702 | current->state = TASK_RUNNING; | ||
703 | remove_wait_queue(¤t->signal->wait_chldexit, &wait); | ||
704 | put_pid(pid); | ||
705 | |||
706 | return retval; | ||
707 | } | ||
708 | |||
709 | struct irix5_context { | ||
710 | u32 flags; | ||
711 | u32 link; | ||
712 | u32 sigmask[4]; | ||
713 | struct { u32 sp, size, flags; } stack; | ||
714 | int regs[36]; | ||
715 | u32 fpregs[32]; | ||
716 | u32 fpcsr; | ||
717 | u32 _unused0; | ||
718 | u32 _unused1[47]; | ||
719 | u32 weird_graphics_thing; | ||
720 | }; | ||
721 | |||
722 | asmlinkage int irix_getcontext(struct pt_regs *regs) | ||
723 | { | ||
724 | int error, i, base = 0; | ||
725 | struct irix5_context __user *ctx; | ||
726 | unsigned long flags; | ||
727 | |||
728 | if (regs->regs[2] == 1000) | ||
729 | base = 1; | ||
730 | ctx = (struct irix5_context __user *) regs->regs[base + 4]; | ||
731 | |||
732 | #ifdef DEBUG_SIG | ||
733 | printk("[%s:%d] irix_getcontext(%p)\n", | ||
734 | current->comm, current->pid, ctx); | ||
735 | #endif | ||
736 | |||
737 | if (!access_ok(VERIFY_WRITE, ctx, sizeof(*ctx))) | ||
738 | return -EFAULT; | ||
739 | |||
740 | error = __put_user(current->thread.irix_oldctx, &ctx->link); | ||
741 | |||
742 | error |= __copy_to_user(&ctx->sigmask, ¤t->blocked, sizeof(irix_sigset_t)) ? -EFAULT : 0; | ||
743 | |||
744 | /* XXX Do sigstack stuff someday... */ | ||
745 | error |= __put_user(0, &ctx->stack.sp); | ||
746 | error |= __put_user(0, &ctx->stack.size); | ||
747 | error |= __put_user(0, &ctx->stack.flags); | ||
748 | |||
749 | error |= __put_user(0, &ctx->weird_graphics_thing); | ||
750 | error |= __put_user(0, &ctx->regs[0]); | ||
751 | for (i = 1; i < 32; i++) | ||
752 | error |= __put_user(regs->regs[i], &ctx->regs[i]); | ||
753 | error |= __put_user(regs->lo, &ctx->regs[32]); | ||
754 | error |= __put_user(regs->hi, &ctx->regs[33]); | ||
755 | error |= __put_user(regs->cp0_cause, &ctx->regs[34]); | ||
756 | error |= __put_user(regs->cp0_epc, &ctx->regs[35]); | ||
757 | |||
758 | flags = 0x0f; | ||
759 | if (!used_math()) { | ||
760 | flags &= ~(0x08); | ||
761 | } else { | ||
762 | /* XXX wheee... */ | ||
763 | printk("Wheee, no code for saving IRIX FPU context yet.\n"); | ||
764 | } | ||
765 | error |= __put_user(flags, &ctx->flags); | ||
766 | |||
767 | return error; | ||
768 | } | ||
769 | |||
770 | asmlinkage void irix_setcontext(struct pt_regs *regs) | ||
771 | { | ||
772 | struct irix5_context __user *ctx; | ||
773 | int err, base = 0; | ||
774 | u32 flags; | ||
775 | |||
776 | if (regs->regs[2] == 1000) | ||
777 | base = 1; | ||
778 | ctx = (struct irix5_context __user *) regs->regs[base + 4]; | ||
779 | |||
780 | #ifdef DEBUG_SIG | ||
781 | printk("[%s:%d] irix_setcontext(%p)\n", | ||
782 | current->comm, current->pid, ctx); | ||
783 | #endif | ||
784 | |||
785 | if (!access_ok(VERIFY_READ, ctx, sizeof(*ctx))) | ||
786 | goto segv_and_exit; | ||
787 | |||
788 | err = __get_user(flags, &ctx->flags); | ||
789 | if (flags & 0x02) { | ||
790 | /* XXX sigstack garbage, todo... */ | ||
791 | printk("Wheee, cannot do sigstack stuff in setcontext\n"); | ||
792 | } | ||
793 | |||
794 | if (flags & 0x04) { | ||
795 | int i; | ||
796 | |||
797 | /* XXX extra control block stuff... todo... */ | ||
798 | for (i = 1; i < 32; i++) | ||
799 | err |= __get_user(regs->regs[i], &ctx->regs[i]); | ||
800 | err |= __get_user(regs->lo, &ctx->regs[32]); | ||
801 | err |= __get_user(regs->hi, &ctx->regs[33]); | ||
802 | err |= __get_user(regs->cp0_epc, &ctx->regs[35]); | ||
803 | } | ||
804 | |||
805 | if (flags & 0x08) | ||
806 | /* XXX fpu context, blah... */ | ||
807 | printk(KERN_ERR "Wheee, cannot restore FPU context yet...\n"); | ||
808 | |||
809 | err |= __get_user(current->thread.irix_oldctx, &ctx->link); | ||
810 | if (err) | ||
811 | goto segv_and_exit; | ||
812 | |||
813 | /* | ||
814 | * Don't let your children do this ... | ||
815 | */ | ||
816 | __asm__ __volatile__( | ||
817 | "move\t$29,%0\n\t" | ||
818 | "j\tsyscall_exit" | ||
819 | :/* no outputs */ | ||
820 | :"r" (®s)); | ||
821 | /* Unreached */ | ||
822 | |||
823 | segv_and_exit: | ||
824 | force_sigsegv(SIGSEGV, current); | ||
825 | } | ||
826 | |||
827 | struct irix_sigstack { | ||
828 | unsigned long sp; | ||
829 | int status; | ||
830 | }; | ||
831 | |||
832 | asmlinkage int irix_sigstack(struct irix_sigstack __user *new, | ||
833 | struct irix_sigstack __user *old) | ||
834 | { | ||
835 | #ifdef DEBUG_SIG | ||
836 | printk("[%s:%d] irix_sigstack(%p,%p)\n", | ||
837 | current->comm, current->pid, new, old); | ||
838 | #endif | ||
839 | if (new) { | ||
840 | if (!access_ok(VERIFY_READ, new, sizeof(*new))) | ||
841 | return -EFAULT; | ||
842 | } | ||
843 | |||
844 | if (old) { | ||
845 | if (!access_ok(VERIFY_WRITE, old, sizeof(*old))) | ||
846 | return -EFAULT; | ||
847 | } | ||
848 | |||
849 | return 0; | ||
850 | } | ||
851 | |||
852 | struct irix_sigaltstack { unsigned long sp; int size; int status; }; | ||
853 | |||
854 | asmlinkage int irix_sigaltstack(struct irix_sigaltstack __user *new, | ||
855 | struct irix_sigaltstack __user *old) | ||
856 | { | ||
857 | #ifdef DEBUG_SIG | ||
858 | printk("[%s:%d] irix_sigaltstack(%p,%p)\n", | ||
859 | current->comm, current->pid, new, old); | ||
860 | #endif | ||
861 | if (new) | ||
862 | if (!access_ok(VERIFY_READ, new, sizeof(*new))) | ||
863 | return -EFAULT; | ||
864 | |||
865 | if (old) { | ||
866 | if (!access_ok(VERIFY_WRITE, old, sizeof(*old))) | ||
867 | return -EFAULT; | ||
868 | } | ||
869 | |||
870 | return 0; | ||
871 | } | ||
872 | |||
873 | struct irix_procset { | ||
874 | int cmd, ltype, lid, rtype, rid; | ||
875 | }; | ||
876 | |||
877 | asmlinkage int irix_sigsendset(struct irix_procset __user *pset, int sig) | ||
878 | { | ||
879 | if (!access_ok(VERIFY_READ, pset, sizeof(*pset))) | ||
880 | return -EFAULT; | ||
881 | #ifdef DEBUG_SIG | ||
882 | printk("[%s:%d] irix_sigsendset([%d,%d,%d,%d,%d],%d)\n", | ||
883 | current->comm, current->pid, | ||
884 | pset->cmd, pset->ltype, pset->lid, pset->rtype, pset->rid, | ||
885 | sig); | ||
886 | #endif | ||
887 | return -EINVAL; | ||
888 | } | ||