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