irixsig.c 20.5 KB
Newer Older
L
Linus Torvalds 已提交
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78
/*
 * irixsig.c: WHEEE, IRIX signals!  YOW, am I compatible or what?!?!
 *
 * Copyright (C) 1996 David S. Miller (dm@engr.sgi.com)
 * Copyright (C) 1997 - 2000 Ralf Baechle (ralf@gnu.org)
 * Copyright (C) 2000 Silicon Graphics, Inc.
 */
#include <linux/kernel.h>
#include <linux/sched.h>
#include <linux/mm.h>
#include <linux/errno.h>
#include <linux/smp.h>
#include <linux/smp_lock.h>
#include <linux/time.h>
#include <linux/ptrace.h>

#include <asm/ptrace.h>
#include <asm/uaccess.h>

#undef DEBUG_SIG

#define _S(nr) (1<<((nr)-1))

#define _BLOCKABLE (~(_S(SIGKILL) | _S(SIGSTOP)))

typedef struct {
	unsigned long sig[4];
} irix_sigset_t;

struct sigctx_irix5 {
	u32 rmask, cp0_status;
	u64 pc;
	u64 regs[32];
	u64 fpregs[32];
	u32 usedfp, fpcsr, fpeir, sstk_flags;
	u64 hi, lo;
	u64 cp0_cause, cp0_badvaddr, _unused0;
	irix_sigset_t sigset;
	u64 weird_fpu_thing;
	u64 _unused1[31];
};

#ifdef DEBUG_SIG
/* Debugging */
static inline void dump_irix5_sigctx(struct sigctx_irix5 *c)
{
	int i;

	printk("misc: rmask[%08lx] status[%08lx] pc[%08lx]\n",
	       (unsigned long) c->rmask,
	       (unsigned long) c->cp0_status,
	       (unsigned long) c->pc);
	printk("regs: ");
	for(i = 0; i < 16; i++)
		printk("[%d]<%08lx> ", i, (unsigned long) c->regs[i]);
	printk("\nregs: ");
	for(i = 16; i < 32; i++)
		printk("[%d]<%08lx> ", i, (unsigned long) c->regs[i]);
	printk("\nfpregs: ");
	for(i = 0; i < 16; i++)
		printk("[%d]<%08lx> ", i, (unsigned long) c->fpregs[i]);
	printk("\nfpregs: ");
	for(i = 16; i < 32; i++)
		printk("[%d]<%08lx> ", i, (unsigned long) c->fpregs[i]);
	printk("misc: usedfp[%d] fpcsr[%08lx] fpeir[%08lx] stk_flgs[%08lx]\n",
	       (int) c->usedfp, (unsigned long) c->fpcsr,
	       (unsigned long) c->fpeir, (unsigned long) c->sstk_flags);
	printk("misc: hi[%08lx] lo[%08lx] cause[%08lx] badvaddr[%08lx]\n",
	       (unsigned long) c->hi, (unsigned long) c->lo,
	       (unsigned long) c->cp0_cause, (unsigned long) c->cp0_badvaddr);
	printk("misc: sigset<0>[%08lx] sigset<1>[%08lx] sigset<2>[%08lx] "
	       "sigset<3>[%08lx]\n", (unsigned long) c->sigset.sig[0],
	       (unsigned long) c->sigset.sig[1],
	       (unsigned long) c->sigset.sig[2],
	       (unsigned long) c->sigset.sig[3]);
}
#endif

R
Ralf Baechle 已提交
79 80
static int setup_irix_frame(struct k_sigaction *ka, struct pt_regs *regs,
			    int signr, sigset_t *oldmask)
L
Linus Torvalds 已提交
81
{
R
Ralf Baechle 已提交
82
	struct sigctx_irix5 __user *ctx;
L
Linus Torvalds 已提交
83
	unsigned long sp;
R
Ralf Baechle 已提交
84
	int error, i;
L
Linus Torvalds 已提交
85 86 87 88

	sp = regs->regs[29];
	sp -= sizeof(struct sigctx_irix5);
	sp &= ~(0xf);
R
Ralf Baechle 已提交
89
	ctx = (struct sigctx_irix5 __user *) sp;
L
Linus Torvalds 已提交
90 91 92
	if (!access_ok(VERIFY_WRITE, ctx, sizeof(*ctx)))
		goto segv_and_exit;

R
Ralf Baechle 已提交
93 94 95
	error = __put_user(0, &ctx->weird_fpu_thing);
	error |= __put_user(~(0x00000001), &ctx->rmask);
	error |= __put_user(0, &ctx->regs[0]);
L
Linus Torvalds 已提交
96
	for(i = 1; i < 32; i++)
R
Ralf Baechle 已提交
97 98 99 100 101 102 103 104
		error |= __put_user((u64) regs->regs[i], &ctx->regs[i]);

	error |= __put_user((u64) regs->hi, &ctx->hi);
	error |= __put_user((u64) regs->lo, &ctx->lo);
	error |= __put_user((u64) regs->cp0_epc, &ctx->pc);
	error |= __put_user(!!used_math(), &ctx->usedfp);
	error |= __put_user((u64) regs->cp0_cause, &ctx->cp0_cause);
	error |= __put_user((u64) regs->cp0_badvaddr, &ctx->cp0_badvaddr);
L
Linus Torvalds 已提交
105

R
Ralf Baechle 已提交
106
	error |= __put_user(0, &ctx->sstk_flags); /* XXX sigstack unimp... todo... */
L
Linus Torvalds 已提交
107

R
Ralf Baechle 已提交
108
	error |= __copy_to_user(&ctx->sigset, oldmask, sizeof(irix_sigset_t)) ? -EFAULT : 0;
L
Linus Torvalds 已提交
109

R
Ralf Baechle 已提交
110 111
	if (error)
		goto segv_and_exit;
L
Linus Torvalds 已提交
112 113 114 115 116 117 118 119 120 121 122

#ifdef DEBUG_SIG
	dump_irix5_sigctx(ctx);
#endif

	regs->regs[4] = (unsigned long) signr;
	regs->regs[5] = 0; /* XXX sigcode XXX */
	regs->regs[6] = regs->regs[29] = sp;
	regs->regs[7] = (unsigned long) ka->sa.sa_handler;
	regs->regs[25] = regs->cp0_epc = (unsigned long) ka->sa_restorer;

R
Ralf Baechle 已提交
123
	return 1;
L
Linus Torvalds 已提交
124 125 126

segv_and_exit:
	force_sigsegv(signr, current);
R
Ralf Baechle 已提交
127
	return 0;
L
Linus Torvalds 已提交
128 129
}

R
Ralf Baechle 已提交
130
static int inline
L
Linus Torvalds 已提交
131 132 133 134 135 136 137
setup_irix_rt_frame(struct k_sigaction * ka, struct pt_regs *regs,
               int signr, sigset_t *oldmask, siginfo_t *info)
{
	printk("Aiee: setup_tr_frame wants to be written");
	do_exit(SIGSEGV);
}

R
Ralf Baechle 已提交
138
static inline int handle_signal(unsigned long sig, siginfo_t *info,
L
Linus Torvalds 已提交
139 140
	struct k_sigaction *ka, sigset_t *oldset, struct pt_regs * regs)
{
R
Ralf Baechle 已提交
141 142
	int ret;

L
Linus Torvalds 已提交
143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159
	switch(regs->regs[0]) {
	case ERESTARTNOHAND:
		regs->regs[2] = EINTR;
		break;
	case ERESTARTSYS:
		if(!(ka->sa.sa_flags & SA_RESTART)) {
			regs->regs[2] = EINTR;
			break;
		}
	/* fallthrough */
	case ERESTARTNOINTR:		/* Userland will reload $v0.  */
		regs->cp0_epc -= 8;
	}

	regs->regs[0] = 0;		/* Don't deal with this again.  */

	if (ka->sa.sa_flags & SA_SIGINFO)
R
Ralf Baechle 已提交
160
		ret = setup_irix_rt_frame(ka, regs, sig, oldset, info);
L
Linus Torvalds 已提交
161
	else
R
Ralf Baechle 已提交
162
		ret = setup_irix_frame(ka, regs, sig, oldset);
L
Linus Torvalds 已提交
163

164 165 166
	spin_lock_irq(&current->sighand->siglock);
	sigorsets(&current->blocked,&current->blocked,&ka->sa.sa_mask);
	if (!(ka->sa.sa_flags & SA_NODEFER))
L
Linus Torvalds 已提交
167
		sigaddset(&current->blocked,sig);
168 169
	recalc_sigpending();
	spin_unlock_irq(&current->sighand->siglock);
R
Ralf Baechle 已提交
170 171

	return ret;
L
Linus Torvalds 已提交
172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187
}

asmlinkage int do_irix_signal(sigset_t *oldset, struct pt_regs *regs)
{
	struct k_sigaction ka;
	siginfo_t info;
	int signr;

	/*
	 * We want the common case to go fast, which is why we may in certain
	 * cases get here from kernel mode. Just return without doing anything
	 * if so.
	 */
	if (!user_mode(regs))
		return 1;

188
	if (try_to_freeze())
L
Linus Torvalds 已提交
189 190 191 192 193 194
		goto no_signal;

	if (!oldset)
		oldset = &current->blocked;

	signr = get_signal_to_deliver(&info, &ka, regs, NULL);
R
Ralf Baechle 已提交
195 196
	if (signr > 0)
		return handle_signal(signr, &info, &ka, oldset, regs);
L
Linus Torvalds 已提交
197 198 199 200 201 202 203 204 205 206 207 208 209 210 211 212 213 214 215 216

no_signal:
	/*
	 * Who's code doesn't conform to the restartable syscall convention
	 * dies here!!!  The li instruction, a single machine instruction,
	 * must directly be followed by the syscall instruction.
	 */
	if (regs->regs[0]) {
		if (regs->regs[2] == ERESTARTNOHAND ||
		    regs->regs[2] == ERESTARTSYS ||
		    regs->regs[2] == ERESTARTNOINTR) {
			regs->cp0_epc -= 8;
		}
	}
	return 0;
}

asmlinkage void
irix_sigreturn(struct pt_regs *regs)
{
R
Ralf Baechle 已提交
217
	struct sigctx_irix5 __user *context, *magic;
L
Linus Torvalds 已提交
218 219
	unsigned long umask, mask;
	u64 *fregs;
R
Ralf Baechle 已提交
220 221
	u32 usedfp;
	int error, sig, i, base = 0;
L
Linus Torvalds 已提交
222 223 224 225 226 227 228 229
	sigset_t blocked;

	/* Always make any pending restarted system calls return -EINTR */
	current_thread_info()->restart_block.fn = do_no_restart_syscall;

	if (regs->regs[2] == 1000)
		base = 1;

R
Ralf Baechle 已提交
230 231
	context = (struct sigctx_irix5 __user *) regs->regs[base + 4];
	magic = (struct sigctx_irix5 __user *) regs->regs[base + 5];
L
Linus Torvalds 已提交
232 233 234 235 236 237 238 239 240 241 242 243 244 245
	sig = (int) regs->regs[base + 6];
#ifdef DEBUG_SIG
	printk("[%s:%d] IRIX sigreturn(scp[%p],ucp[%p],sig[%d])\n",
	       current->comm, current->pid, context, magic, sig);
#endif
	if (!context)
		context = magic;
	if (!access_ok(VERIFY_READ, context, sizeof(struct sigctx_irix5)))
		goto badframe;

#ifdef DEBUG_SIG
	dump_irix5_sigctx(context);
#endif

R
Ralf Baechle 已提交
246 247 248 249
	error = __get_user(regs->cp0_epc, &context->pc);
	error |= __get_user(umask, &context->rmask);

	mask = 2;
L
Linus Torvalds 已提交
250
	for (i = 1; i < 32; i++, mask <<= 1) {
R
Ralf Baechle 已提交
251 252
		if (umask & mask)
			error |= __get_user(regs->regs[i], &context->regs[i]);
L
Linus Torvalds 已提交
253
	}
R
Ralf Baechle 已提交
254 255
	error |= __get_user(regs->hi, &context->hi);
	error |= __get_user(regs->lo, &context->lo);
L
Linus Torvalds 已提交
256

R
Ralf Baechle 已提交
257 258
	error |= __get_user(usedfp, &context->usedfp);
	if ((umask & 1) && usedfp) {
L
Linus Torvalds 已提交
259
		fregs = (u64 *) &current->thread.fpu;
R
Ralf Baechle 已提交
260

L
Linus Torvalds 已提交
261
		for(i = 0; i < 32; i++)
R
Ralf Baechle 已提交
262 263
			error |= __get_user(fregs[i], &context->fpregs[i]);
		error |= __get_user(current->thread.fpu.hard.fcr31, &context->fpcsr);
L
Linus Torvalds 已提交
264 265 266 267
	}

	/* XXX do sigstack crapola here... XXX */

R
Ralf Baechle 已提交
268 269 270
	error |= __copy_from_user(&blocked, &context->sigset, sizeof(blocked)) ? -EFAULT : 0;

	if (error)
L
Linus Torvalds 已提交
271 272 273 274 275 276 277 278 279 280 281 282 283 284 285 286 287 288 289 290 291 292 293 294 295 296 297 298 299 300 301 302 303 304 305 306 307 308 309
		goto badframe;

	sigdelsetmask(&blocked, ~_BLOCKABLE);
	spin_lock_irq(&current->sighand->siglock);
	current->blocked = blocked;
	recalc_sigpending();
	spin_unlock_irq(&current->sighand->siglock);

	/*
	 * Don't let your children do this ...
	 */
	__asm__ __volatile__(
		"move\t$29,%0\n\t"
		"j\tsyscall_exit"
		:/* no outputs */
		:"r" (&regs));
		/* Unreached */

badframe:
	force_sig(SIGSEGV, current);
}

struct sigact_irix5 {
	int flags;
	void (*handler)(int);
	u32 sigset[4];
	int _unused0[2];
};

#ifdef DEBUG_SIG
static inline void dump_sigact_irix5(struct sigact_irix5 *p)
{
	printk("<f[%d] hndlr[%08lx] msk[%08lx]>", p->flags,
	       (unsigned long) p->handler,
	       (unsigned long) p->sigset[0]);
}
#endif

asmlinkage int
R
Ralf Baechle 已提交
310 311
irix_sigaction(int sig, const struct sigaction __user *act,
	      struct sigaction __user *oact, void __user *trampoline)
L
Linus Torvalds 已提交
312 313 314 315 316 317 318 319 320 321 322 323 324
{
	struct k_sigaction new_ka, old_ka;
	int ret;

#ifdef DEBUG_SIG
	printk(" (%d,%s,%s,%08lx) ", sig, (!new ? "0" : "NEW"),
	       (!old ? "0" : "OLD"), trampoline);
	if(new) {
		dump_sigact_irix5(new); printk(" ");
	}
#endif
	if (act) {
		sigset_t mask;
R
Ralf Baechle 已提交
325 326 327
		int err;

		if (!access_ok(VERIFY_READ, act, sizeof(*act)))
L
Linus Torvalds 已提交
328
			return -EFAULT;
R
Ralf Baechle 已提交
329 330
		err = __get_user(new_ka.sa.sa_handler, &act->sa_handler);
		err |= __get_user(new_ka.sa.sa_flags, &act->sa_flags);
L
Linus Torvalds 已提交
331

R
Ralf Baechle 已提交
332 333 334
		err |= __copy_from_user(&mask, &act->sa_mask, sizeof(sigset_t)) ? -EFAULT : 0;
		if (err)
			return err;
L
Linus Torvalds 已提交
335 336 337 338 339 340 341 342 343 344 345 346 347

		/*
		 * Hmmm... methinks IRIX libc always passes a valid trampoline
		 * value for all invocations of sigaction.  Will have to
		 * investigate.  POSIX POSIX, die die die...
		 */
		new_ka.sa_restorer = trampoline;
	}

/* XXX Implement SIG_SETMASK32 for IRIX compatibility */
	ret = do_sigaction(sig, act ? &new_ka : NULL, oact ? &old_ka : NULL);

	if (!ret && oact) {
R
Ralf Baechle 已提交
348 349 350 351 352 353 354 355 356 357
		int err;

		if (!access_ok(VERIFY_WRITE, oact, sizeof(*oact)))
			return -EFAULT;

		err = __put_user(old_ka.sa.sa_handler, &oact->sa_handler);
		err |= __put_user(old_ka.sa.sa_flags, &oact->sa_flags);
		err |= __copy_to_user(&oact->sa_mask, &old_ka.sa.sa_mask,
		               sizeof(sigset_t)) ? -EFAULT : 0;
		if (err)
L
Linus Torvalds 已提交
358 359 360 361 362 363
			return -EFAULT;
	}

	return ret;
}

R
Ralf Baechle 已提交
364
asmlinkage int irix_sigpending(irix_sigset_t __user *set)
L
Linus Torvalds 已提交
365 366 367 368
{
	return do_sigpending(set, sizeof(*set));
}

R
Ralf Baechle 已提交
369 370
asmlinkage int irix_sigprocmask(int how, irix_sigset_t __user *new,
	irix_sigset_t __user *old)
L
Linus Torvalds 已提交
371 372 373 374 375 376
{
	sigset_t oldbits, newbits;

	if (new) {
		if (!access_ok(VERIFY_READ, new, sizeof(*new)))
			return -EFAULT;
R
Ralf Baechle 已提交
377 378
		if (__copy_from_user(&newbits, new, sizeof(unsigned long)*4))
			return -EFAULT;
L
Linus Torvalds 已提交
379 380 381 382 383 384 385 386 387 388 389 390 391 392 393 394 395 396 397 398 399 400 401 402 403 404 405
		sigdelsetmask(&newbits, ~_BLOCKABLE);

		spin_lock_irq(&current->sighand->siglock);
		oldbits = current->blocked;

		switch(how) {
		case 1:
			sigorsets(&newbits, &oldbits, &newbits);
			break;

		case 2:
			sigandsets(&newbits, &oldbits, &newbits);
			break;

		case 3:
			break;

		case 256:
			siginitset(&newbits, newbits.sig[0]);
			break;

		default:
			return -EINVAL;
		}
		recalc_sigpending();
		spin_unlock_irq(&current->sighand->siglock);
	}
R
Ralf Baechle 已提交
406 407 408
	if (old)
		return copy_to_user(old, &current->blocked,
		                  sizeof(unsigned long)*4) ? -EFAULT : 0;
L
Linus Torvalds 已提交
409 410 411 412 413 414

	return 0;
}

asmlinkage int irix_sigsuspend(struct pt_regs *regs)
{
R
Ralf Baechle 已提交
415 416
	sigset_t saveset, newset;
	sigset_t __user *uset;
L
Linus Torvalds 已提交
417

R
Ralf Baechle 已提交
418
	uset = (sigset_t __user *) regs->regs[4];
L
Linus Torvalds 已提交
419 420 421 422 423 424 425 426 427 428 429 430 431 432 433 434 435 436 437 438 439 440 441 442 443 444 445 446 447 448 449 450 451 452 453 454 455 456 457 458 459 460 461 462 463
	if (copy_from_user(&newset, uset, sizeof(sigset_t)))
		return -EFAULT;
	sigdelsetmask(&newset, ~_BLOCKABLE);

	spin_lock_irq(&current->sighand->siglock);
	saveset = current->blocked;
	current->blocked = newset;
	recalc_sigpending();
	spin_unlock_irq(&current->sighand->siglock);

	regs->regs[2] = -EINTR;
	while (1) {
		current->state = TASK_INTERRUPTIBLE;
		schedule();
		if (do_irix_signal(&saveset, regs))
			return -EINTR;
	}
}

/* hate hate hate... */
struct irix5_siginfo {
	int sig, code, error;
	union {
		char unused[128 - (3 * 4)]; /* Safety net. */
		struct {
			int pid;
			union {
				int uid;
				struct {
					int utime, status, stime;
				} child;
			} procdata;
		} procinfo;

		unsigned long fault_addr;

		struct {
			int fd;
			long band;
		} fileinfo;

		unsigned long sigval;
	} stuff;
};

R
Ralf Baechle 已提交
464 465
asmlinkage int irix_sigpoll_sys(unsigned long __user *set,
	struct irix5_siginfo __user *info, struct timespec __user *tp)
L
Linus Torvalds 已提交
466 467 468 469
{
	long expire = MAX_SCHEDULE_TIMEOUT;
	sigset_t kset;
	int i, sig, error, timeo = 0;
R
Ralf Baechle 已提交
470
	struct timespec ktp;
L
Linus Torvalds 已提交
471 472 473 474 475 476 477 478 479 480

#ifdef DEBUG_SIG
	printk("[%s:%d] irix_sigpoll_sys(%p,%p,%p)\n",
	       current->comm, current->pid, set, info, tp);
#endif

	/* Must always specify the signal set. */
	if (!set)
		return -EINVAL;

R
Ralf Baechle 已提交
481 482
	if (copy_from_user(&kset, set, sizeof(set)))
		return -EFAULT;
L
Linus Torvalds 已提交
483 484 485 486 487 488 489

	if (info && clear_user(info, sizeof(*info))) {
		error = -EFAULT;
		goto out;
	}

	if (tp) {
R
Ralf Baechle 已提交
490
		if (copy_from_user(&ktp, tp, sizeof(*tp)))
L
Linus Torvalds 已提交
491
			return -EFAULT;
R
Ralf Baechle 已提交
492 493 494 495 496 497

		if (!ktp.tv_sec && !ktp.tv_nsec)
			return -EINVAL;

		expire = timespec_to_jiffies(&ktp) +
		         (ktp.tv_sec || ktp.tv_nsec);
L
Linus Torvalds 已提交
498 499 500 501 502
	}

	while(1) {
		long tmp = 0;

503
		expire = schedule_timeout_interruptible(expire);
L
Linus Torvalds 已提交
504 505 506 507 508 509 510 511 512 513 514 515 516 517 518 519

		for (i=0; i<=4; i++)
			tmp |= (current->pending.signal.sig[i] & kset.sig[i]);

		if (tmp)
			break;
		if (!expire) {
			timeo = 1;
			break;
		}
		if (signal_pending(current))
			return -EINTR;
	}
	if (timeo)
		return -EAGAIN;

R
Ralf Baechle 已提交
520
	for (sig = 1; i <= 65 /* IRIX_NSIG */; sig++) {
L
Linus Torvalds 已提交
521 522 523 524 525
		if (sigismember (&kset, sig))
			continue;
		if (sigismember (&current->pending.signal, sig)) {
			/* XXX need more than this... */
			if (info)
R
Ralf Baechle 已提交
526 527
				return copy_to_user(&info->sig, &sig, sizeof(sig));
			return 0;
L
Linus Torvalds 已提交
528 529 530 531 532 533 534 535 536 537 538 539 540 541 542 543 544 545 546 547 548 549 550 551 552
		}
	}

	/* Should not get here, but do something sane if we do. */
	error = -EINTR;

out:
	return error;
}

/* This is here because of irix5_siginfo definition. */
#define IRIX_P_PID    0
#define IRIX_P_PGID   2
#define IRIX_P_ALL    7

extern int getrusage(struct task_struct *, int, struct rusage __user *);

#define W_EXITED     1
#define W_TRAPPED    2
#define W_STOPPED    4
#define W_CONT       8
#define W_NOHANG    64

#define W_MASK      (W_EXITED | W_TRAPPED | W_STOPPED | W_CONT | W_NOHANG)

R
Ralf Baechle 已提交
553 554 555
asmlinkage int irix_waitsys(int type, int pid,
	struct irix5_siginfo __user *info, int options,
	struct rusage __user *ru)
L
Linus Torvalds 已提交
556 557 558 559 560 561 562
{
	int flag, retval;
	DECLARE_WAITQUEUE(wait, current);
	struct task_struct *tsk;
	struct task_struct *p;
	struct list_head *_p;

R
Ralf Baechle 已提交
563 564 565 566 567 568 569 570 571 572 573 574 575 576 577 578
	if (!info)
		return -EINVAL;

	if (!access_ok(VERIFY_WRITE, info, sizeof(*info)))
		return -EFAULT;

	if (ru)
		if (!access_ok(VERIFY_WRITE, ru, sizeof(*ru)))
			return -EFAULT;

	if (options & ~W_MASK)
		return -EINVAL;

	if (type != IRIX_P_PID && type != IRIX_P_PGID && type != IRIX_P_ALL)
		return -EINVAL;

L
Linus Torvalds 已提交
579 580 581 582 583 584 585 586 587 588 589 590 591 592 593 594 595 596 597 598 599 600 601 602 603 604 605 606 607 608
	add_wait_queue(&current->signal->wait_chldexit, &wait);
repeat:
	flag = 0;
	current->state = TASK_INTERRUPTIBLE;
	read_lock(&tasklist_lock);
	tsk = current;
	list_for_each(_p,&tsk->children) {
		p = list_entry(_p,struct task_struct,sibling);
		if ((type == IRIX_P_PID) && p->pid != pid)
			continue;
		if ((type == IRIX_P_PGID) && process_group(p) != pid)
			continue;
		if ((p->exit_signal != SIGCHLD))
			continue;
		flag = 1;
		switch (p->state) {
		case TASK_STOPPED:
			if (!p->exit_code)
				continue;
			if (!(options & (W_TRAPPED|W_STOPPED)) &&
			    !(p->ptrace & PT_PTRACED))
				continue;
			read_unlock(&tasklist_lock);

			/* move to end of parent's list to avoid starvation */
			write_lock_irq(&tasklist_lock);
			remove_parent(p);
			add_parent(p, p->parent);
			write_unlock_irq(&tasklist_lock);
			retval = ru ? getrusage(p, RUSAGE_BOTH, ru) : 0;
R
Ralf Baechle 已提交
609 610 611 612 613 614 615 616 617 618 619 620 621 622
			if (retval)
				goto end_waitsys;

			retval = __put_user(SIGCHLD, &info->sig);
			retval |= __put_user(0, &info->code);
			retval |= __put_user(p->pid, &info->stuff.procinfo.pid);
			retval |= __put_user((p->exit_code >> 8) & 0xff,
			           &info->stuff.procinfo.procdata.child.status);
			retval |= __put_user(p->utime, &info->stuff.procinfo.procdata.child.utime);
			retval |= __put_user(p->stime, &info->stuff.procinfo.procdata.child.stime);
			if (retval)
				goto end_waitsys;

			p->exit_code = 0;
L
Linus Torvalds 已提交
623 624 625 626 627 628 629
			goto end_waitsys;

		case EXIT_ZOMBIE:
			current->signal->cutime += p->utime + p->signal->cutime;
			current->signal->cstime += p->stime + p->signal->cstime;
			if (ru != NULL)
				getrusage(p, RUSAGE_BOTH, ru);
R
Ralf Baechle 已提交
630 631 632 633
			retval = __put_user(SIGCHLD, &info->sig);
			retval |= __put_user(1, &info->code);      /* CLD_EXITED */
			retval |= __put_user(p->pid, &info->stuff.procinfo.pid);
			retval |= __put_user((p->exit_code >> 8) & 0xff,
L
Linus Torvalds 已提交
634
			           &info->stuff.procinfo.procdata.child.status);
R
Ralf Baechle 已提交
635
			retval |= __put_user(p->utime,
L
Linus Torvalds 已提交
636
			           &info->stuff.procinfo.procdata.child.utime);
R
Ralf Baechle 已提交
637
			retval |= __put_user(p->stime,
L
Linus Torvalds 已提交
638
			           &info->stuff.procinfo.procdata.child.stime);
R
Ralf Baechle 已提交
639 640 641
			if (retval)
				return retval;

L
Linus Torvalds 已提交
642 643 644 645 646 647 648 649 650 651 652 653 654 655 656 657 658 659 660 661 662 663 664 665 666 667 668 669 670 671 672 673 674 675 676 677 678 679 680 681 682 683 684 685 686 687 688 689 690 691
			if (p->real_parent != p->parent) {
				write_lock_irq(&tasklist_lock);
				remove_parent(p);
				p->parent = p->real_parent;
				add_parent(p, p->parent);
				do_notify_parent(p, SIGCHLD);
				write_unlock_irq(&tasklist_lock);
			} else
				release_task(p);
			goto end_waitsys;
		default:
			continue;
		}
		tsk = next_thread(tsk);
	}
	read_unlock(&tasklist_lock);
	if (flag) {
		retval = 0;
		if (options & W_NOHANG)
			goto end_waitsys;
		retval = -ERESTARTSYS;
		if (signal_pending(current))
			goto end_waitsys;
		current->state = TASK_INTERRUPTIBLE;
		schedule();
		goto repeat;
	}
	retval = -ECHILD;
end_waitsys:
	current->state = TASK_RUNNING;
	remove_wait_queue(&current->signal->wait_chldexit, &wait);

	return retval;
}

struct irix5_context {
	u32 flags;
	u32 link;
	u32 sigmask[4];
	struct { u32 sp, size, flags; } stack;
	int regs[36];
	u32 fpregs[32];
	u32 fpcsr;
	u32 _unused0;
	u32 _unused1[47];
	u32 weird_graphics_thing;
};

asmlinkage int irix_getcontext(struct pt_regs *regs)
{
R
Ralf Baechle 已提交
692 693
	int error, i, base = 0;
	struct irix5_context __user *ctx;
L
Linus Torvalds 已提交
694 695 696 697
	unsigned long flags;

	if (regs->regs[2] == 1000)
		base = 1;
R
Ralf Baechle 已提交
698
	ctx = (struct irix5_context __user *) regs->regs[base + 4];
L
Linus Torvalds 已提交
699 700 701 702 703 704

#ifdef DEBUG_SIG
	printk("[%s:%d] irix_getcontext(%p)\n",
	       current->comm, current->pid, ctx);
#endif

R
Ralf Baechle 已提交
705
	if (!access_ok(VERIFY_WRITE, ctx, sizeof(*ctx)));
L
Linus Torvalds 已提交
706 707
		return -EFAULT;

R
Ralf Baechle 已提交
708
	error = __put_user(current->thread.irix_oldctx, &ctx->link);
L
Linus Torvalds 已提交
709

R
Ralf Baechle 已提交
710
	error |= __copy_to_user(&ctx->sigmask, &current->blocked, sizeof(irix_sigset_t)) ? -EFAULT : 0;
L
Linus Torvalds 已提交
711 712

	/* XXX Do sigstack stuff someday... */
R
Ralf Baechle 已提交
713 714 715
	error |= __put_user(0, &ctx->stack.sp);
	error |= __put_user(0, &ctx->stack.size);
	error |= __put_user(0, &ctx->stack.flags);
L
Linus Torvalds 已提交
716

R
Ralf Baechle 已提交
717 718
	error |= __put_user(0, &ctx->weird_graphics_thing);
	error |= __put_user(0, &ctx->regs[0]);
L
Linus Torvalds 已提交
719
	for (i = 1; i < 32; i++)
R
Ralf Baechle 已提交
720 721 722 723 724
		error |= __put_user(regs->regs[i], &ctx->regs[i]);
	error |= __put_user(regs->lo, &ctx->regs[32]);
	error |= __put_user(regs->hi, &ctx->regs[33]);
	error |= __put_user(regs->cp0_cause, &ctx->regs[34]);
	error |= __put_user(regs->cp0_epc, &ctx->regs[35]);
L
Linus Torvalds 已提交
725 726 727 728 729 730 731 732

	flags = 0x0f;
	if (!used_math()) {
		flags &= ~(0x08);
	} else {
		/* XXX wheee... */
		printk("Wheee, no code for saving IRIX FPU context yet.\n");
	}
R
Ralf Baechle 已提交
733
	error |= __put_user(flags, &ctx->flags);
L
Linus Torvalds 已提交
734

R
Ralf Baechle 已提交
735
	return error;
L
Linus Torvalds 已提交
736 737
}

R
Ralf Baechle 已提交
738
asmlinkage void irix_setcontext(struct pt_regs *regs)
L
Linus Torvalds 已提交
739
{
R
Ralf Baechle 已提交
740 741 742
	struct irix5_context __user *ctx;
	int err, base = 0;
	u32 flags;
L
Linus Torvalds 已提交
743

R
Ralf Baechle 已提交
744
	if (regs->regs[2] == 1000)
L
Linus Torvalds 已提交
745
		base = 1;
R
Ralf Baechle 已提交
746
	ctx = (struct irix5_context __user *) regs->regs[base + 4];
L
Linus Torvalds 已提交
747 748 749 750 751 752

#ifdef DEBUG_SIG
	printk("[%s:%d] irix_setcontext(%p)\n",
	       current->comm, current->pid, ctx);
#endif

R
Ralf Baechle 已提交
753 754
	if (!access_ok(VERIFY_READ, ctx, sizeof(*ctx)))
		goto segv_and_exit;
L
Linus Torvalds 已提交
755

R
Ralf Baechle 已提交
756 757
	err = __get_user(flags, &ctx->flags);
	if (flags & 0x02) {
L
Linus Torvalds 已提交
758 759 760 761
		/* XXX sigstack garbage, todo... */
		printk("Wheee, cannot do sigstack stuff in setcontext\n");
	}

R
Ralf Baechle 已提交
762
	if (flags & 0x04) {
L
Linus Torvalds 已提交
763 764 765
		int i;

		/* XXX extra control block stuff... todo... */
R
Ralf Baechle 已提交
766 767 768 769 770
		for (i = 1; i < 32; i++)
			err |= __get_user(regs->regs[i], &ctx->regs[i]);
		err |= __get_user(regs->lo, &ctx->regs[32]);
		err |= __get_user(regs->hi, &ctx->regs[33]);
		err |= __get_user(regs->cp0_epc, &ctx->regs[35]);
L
Linus Torvalds 已提交
771 772
	}

R
Ralf Baechle 已提交
773
	if (flags & 0x08)
L
Linus Torvalds 已提交
774
		/* XXX fpu context, blah... */
R
Ralf Baechle 已提交
775
		printk(KERN_ERR "Wheee, cannot restore FPU context yet...\n");
L
Linus Torvalds 已提交
776

R
Ralf Baechle 已提交
777 778 779 780 781 782 783 784 785 786 787 788 789 790 791 792
	err |= __get_user(current->thread.irix_oldctx, &ctx->link);
	if (err)
		goto segv_and_exit;

	/*
	 * Don't let your children do this ...
	 */
	__asm__ __volatile__(
		"move\t$29,%0\n\t"
		"j\tsyscall_exit"
		:/* no outputs */
		:"r" (&regs));
		/* Unreached */

segv_and_exit:
	force_sigsegv(SIGSEGV, current);
L
Linus Torvalds 已提交
793 794
}

R
Ralf Baechle 已提交
795 796 797 798
struct irix_sigstack {
	unsigned long sp;
	int status;
};
L
Linus Torvalds 已提交
799

R
Ralf Baechle 已提交
800 801
asmlinkage int irix_sigstack(struct irix_sigstack __user *new,
	struct irix_sigstack __user *old)
L
Linus Torvalds 已提交
802 803 804 805 806
{
#ifdef DEBUG_SIG
	printk("[%s:%d] irix_sigstack(%p,%p)\n",
	       current->comm, current->pid, new, old);
#endif
R
Ralf Baechle 已提交
807
	if (new) {
L
Linus Torvalds 已提交
808
		if (!access_ok(VERIFY_READ, new, sizeof(*new)))
R
Ralf Baechle 已提交
809
			return -EFAULT;
L
Linus Torvalds 已提交
810 811
	}

R
Ralf Baechle 已提交
812
	if (old) {
L
Linus Torvalds 已提交
813
		if (!access_ok(VERIFY_WRITE, old, sizeof(*old)))
R
Ralf Baechle 已提交
814
			return -EFAULT;
L
Linus Torvalds 已提交
815 816
	}

R
Ralf Baechle 已提交
817
	return 0;
L
Linus Torvalds 已提交
818 819 820 821
}

struct irix_sigaltstack { unsigned long sp; int size; int status; };

R
Ralf Baechle 已提交
822 823
asmlinkage int irix_sigaltstack(struct irix_sigaltstack __user *new,
				struct irix_sigaltstack __user *old)
L
Linus Torvalds 已提交
824 825 826 827 828
{
#ifdef DEBUG_SIG
	printk("[%s:%d] irix_sigaltstack(%p,%p)\n",
	       current->comm, current->pid, new, old);
#endif
R
Ralf Baechle 已提交
829
	if (new)
L
Linus Torvalds 已提交
830
		if (!access_ok(VERIFY_READ, new, sizeof(*new)))
R
Ralf Baechle 已提交
831
			return -EFAULT;
L
Linus Torvalds 已提交
832 833 834

	if (old) {
		if (!access_ok(VERIFY_WRITE, old, sizeof(*old)))
R
Ralf Baechle 已提交
835
			return -EFAULT;
L
Linus Torvalds 已提交
836 837
	}

R
Ralf Baechle 已提交
838
	return 0;
L
Linus Torvalds 已提交
839 840 841 842 843 844
}

struct irix_procset {
	int cmd, ltype, lid, rtype, rid;
};

R
Ralf Baechle 已提交
845
asmlinkage int irix_sigsendset(struct irix_procset __user *pset, int sig)
L
Linus Torvalds 已提交
846 847 848 849 850 851 852 853 854 855 856
{
	if (!access_ok(VERIFY_READ, pset, sizeof(*pset)))
		return -EFAULT;
#ifdef DEBUG_SIG
	printk("[%s:%d] irix_sigsendset([%d,%d,%d,%d,%d],%d)\n",
	       current->comm, current->pid,
	       pset->cmd, pset->ltype, pset->lid, pset->rtype, pset->rid,
	       sig);
#endif
	return -EINVAL;
}