irixsig.c 21.3 KB
Newer Older
L
Linus Torvalds 已提交
1 2 3 4 5 6 7 8 9 10 11 12 13 14
/*
 * 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/time.h>
#include <linux/ptrace.h>
A
Adrian Bunk 已提交
15
#include <linux/resource.h>
L
Linus Torvalds 已提交
16 17 18

#include <asm/ptrace.h>
#include <asm/uaccess.h>
R
Ralf Baechle 已提交
19
#include <asm/unistd.h>
L
Linus Torvalds 已提交
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 79

#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 已提交
80 81
static int setup_irix_frame(struct k_sigaction *ka, struct pt_regs *regs,
			    int signr, sigset_t *oldmask)
L
Linus Torvalds 已提交
82
{
R
Ralf Baechle 已提交
83
	struct sigctx_irix5 __user *ctx;
L
Linus Torvalds 已提交
84
	unsigned long sp;
R
Ralf Baechle 已提交
85
	int error, i;
L
Linus Torvalds 已提交
86 87 88 89

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

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

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

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

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

#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 已提交
124
	return 1;
L
Linus Torvalds 已提交
125 126 127

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

R
Ralf Baechle 已提交
131
static int inline
L
Linus Torvalds 已提交
132 133 134 135 136 137 138
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 已提交
139
static inline int handle_signal(unsigned long sig, siginfo_t *info,
L
Linus Torvalds 已提交
140 141
	struct k_sigaction *ka, sigset_t *oldset, struct pt_regs * regs)
{
R
Ralf Baechle 已提交
142 143
	int ret;

L
Linus Torvalds 已提交
144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160
	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 已提交
161
		ret = setup_irix_rt_frame(ka, regs, sig, oldset, info);
L
Linus Torvalds 已提交
162
	else
R
Ralf Baechle 已提交
163
		ret = setup_irix_frame(ka, regs, sig, oldset);
L
Linus Torvalds 已提交
164

165 166 167
	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 已提交
168
		sigaddset(&current->blocked,sig);
169 170
	recalc_sigpending();
	spin_unlock_irq(&current->sighand->siglock);
R
Ralf Baechle 已提交
171 172

	return ret;
L
Linus Torvalds 已提交
173 174
}

R
Ralf Baechle 已提交
175
void do_irix_signal(struct pt_regs *regs)
L
Linus Torvalds 已提交
176 177 178 179
{
	struct k_sigaction ka;
	siginfo_t info;
	int signr;
R
Ralf Baechle 已提交
180
	sigset_t *oldset;
L
Linus Torvalds 已提交
181 182 183 184 185 186 187

	/*
	 * 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))
R
Ralf Baechle 已提交
188
		return;
L
Linus Torvalds 已提交
189

R
Ralf Baechle 已提交
190 191 192
	if (test_thread_flag(TIF_RESTORE_SIGMASK))
		oldset = &current->saved_sigmask;
	else
L
Linus Torvalds 已提交
193 194 195
		oldset = &current->blocked;

	signr = get_signal_to_deliver(&info, &ka, regs, NULL);
R
Ralf Baechle 已提交
196 197 198 199 200 201 202 203 204 205 206 207 208
	if (signr > 0) {
		/* Whee!  Actually deliver the signal.  */
		if (handle_signal(signr, &info, &ka, oldset, regs) == 0) {
			/* a signal was successfully delivered; the saved
			 * sigmask will have been stored in the signal frame,
			 * and will be restored by sigreturn, so we can simply
			 * clear the TIF_RESTORE_SIGMASK flag */
			if (test_thread_flag(TIF_RESTORE_SIGMASK))
				clear_thread_flag(TIF_RESTORE_SIGMASK);
		}

		return;
	}
L
Linus Torvalds 已提交
209 210 211 212 213 214 215 216 217 218 219 220

	/*
	 * 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;
		}
R
Ralf Baechle 已提交
221 222 223 224 225
		if (regs->regs[2] == ERESTART_RESTARTBLOCK) {
			regs->regs[2] = __NR_restart_syscall;
			regs->regs[7] = regs->regs[26];
			regs->cp0_epc -= 4;
		}
226
		regs->regs[0] = 0;	/* Don't deal with this again.  */
R
Ralf Baechle 已提交
227 228 229 230 231 232 233 234 235
	}

	/*
	* If there's no signal to deliver, we just put the saved sigmask
	* back
	*/
	if (test_thread_flag(TIF_RESTORE_SIGMASK)) {
		clear_thread_flag(TIF_RESTORE_SIGMASK);
		sigprocmask(SIG_SETMASK, &current->saved_sigmask, NULL);
L
Linus Torvalds 已提交
236 237 238 239 240 241
	}
}

asmlinkage void
irix_sigreturn(struct pt_regs *regs)
{
R
Ralf Baechle 已提交
242
	struct sigctx_irix5 __user *context, *magic;
L
Linus Torvalds 已提交
243 244
	unsigned long umask, mask;
	u64 *fregs;
R
Ralf Baechle 已提交
245 246
	u32 usedfp;
	int error, sig, i, base = 0;
L
Linus Torvalds 已提交
247 248 249 250 251 252 253 254
	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 已提交
255 256
	context = (struct sigctx_irix5 __user *) regs->regs[base + 4];
	magic = (struct sigctx_irix5 __user *) regs->regs[base + 5];
L
Linus Torvalds 已提交
257 258 259 260 261 262 263 264 265 266 267 268 269 270
	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 已提交
271 272 273 274
	error = __get_user(regs->cp0_epc, &context->pc);
	error |= __get_user(umask, &context->rmask);

	mask = 2;
L
Linus Torvalds 已提交
275
	for (i = 1; i < 32; i++, mask <<= 1) {
R
Ralf Baechle 已提交
276 277
		if (umask & mask)
			error |= __get_user(regs->regs[i], &context->regs[i]);
L
Linus Torvalds 已提交
278
	}
R
Ralf Baechle 已提交
279 280
	error |= __get_user(regs->hi, &context->hi);
	error |= __get_user(regs->lo, &context->lo);
L
Linus Torvalds 已提交
281

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

L
Linus Torvalds 已提交
286
		for(i = 0; i < 32; i++)
R
Ralf Baechle 已提交
287
			error |= __get_user(fregs[i], &context->fpregs[i]);
288
		error |= __get_user(current->thread.fpu.fcr31, &context->fpcsr);
L
Linus Torvalds 已提交
289 290 291 292
	}

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

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

	if (error)
L
Linus Torvalds 已提交
296 297 298 299 300 301 302 303 304 305 306 307 308 309 310 311 312 313 314 315 316 317 318 319 320 321 322 323 324
		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];
};

325 326 327
#define SIG_SETMASK32	256	/* Goodie from SGI for BSD compatibility:
				   set only the low 32 bit of the sigset.  */

L
Linus Torvalds 已提交
328 329 330 331 332 333 334 335 336 337
#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 已提交
338 339
irix_sigaction(int sig, const struct sigaction __user *act,
	      struct sigaction __user *oact, void __user *trampoline)
L
Linus Torvalds 已提交
340 341 342 343 344 345 346 347 348 349 350 351 352
{
	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 已提交
353 354 355
		int err;

		if (!access_ok(VERIFY_READ, act, sizeof(*act)))
L
Linus Torvalds 已提交
356
			return -EFAULT;
R
Ralf Baechle 已提交
357 358
		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 已提交
359

R
Ralf Baechle 已提交
360 361 362
		err |= __copy_from_user(&mask, &act->sa_mask, sizeof(sigset_t)) ? -EFAULT : 0;
		if (err)
			return err;
L
Linus Torvalds 已提交
363 364 365 366 367 368 369 370 371 372 373 374 375

		/*
		 * 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 已提交
376 377 378 379 380 381 382 383 384 385
		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 已提交
386 387 388 389 390 391
			return -EFAULT;
	}

	return ret;
}

R
Ralf Baechle 已提交
392
asmlinkage int irix_sigpending(irix_sigset_t __user *set)
L
Linus Torvalds 已提交
393 394 395 396
{
	return do_sigpending(set, sizeof(*set));
}

R
Ralf Baechle 已提交
397 398
asmlinkage int irix_sigprocmask(int how, irix_sigset_t __user *new,
	irix_sigset_t __user *old)
L
Linus Torvalds 已提交
399 400 401 402 403 404
{
	sigset_t oldbits, newbits;

	if (new) {
		if (!access_ok(VERIFY_READ, new, sizeof(*new)))
			return -EFAULT;
R
Ralf Baechle 已提交
405 406
		if (__copy_from_user(&newbits, new, sizeof(unsigned long)*4))
			return -EFAULT;
L
Linus Torvalds 已提交
407 408 409 410 411 412 413 414 415 416 417 418 419 420 421 422 423 424 425 426 427 428 429 430 431 432 433
		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 已提交
434 435 436
	if (old)
		return copy_to_user(old, &current->blocked,
		                  sizeof(unsigned long)*4) ? -EFAULT : 0;
L
Linus Torvalds 已提交
437 438 439 440 441 442

	return 0;
}

asmlinkage int irix_sigsuspend(struct pt_regs *regs)
{
R
Ralf Baechle 已提交
443
	sigset_t newset;
R
Ralf Baechle 已提交
444
	sigset_t __user *uset;
L
Linus Torvalds 已提交
445

R
Ralf Baechle 已提交
446
	uset = (sigset_t __user *) regs->regs[4];
L
Linus Torvalds 已提交
447 448 449 450 451
	if (copy_from_user(&newset, uset, sizeof(sigset_t)))
		return -EFAULT;
	sigdelsetmask(&newset, ~_BLOCKABLE);

	spin_lock_irq(&current->sighand->siglock);
R
Ralf Baechle 已提交
452
	current->saved_sigmask = current->blocked;
L
Linus Torvalds 已提交
453 454 455 456
	current->blocked = newset;
	recalc_sigpending();
	spin_unlock_irq(&current->sighand->siglock);

R
Ralf Baechle 已提交
457 458 459 460
	current->state = TASK_INTERRUPTIBLE;
	schedule();
	set_thread_flag(TIF_RESTORE_SIGMASK);
	return -ERESTARTNOHAND;
L
Linus Torvalds 已提交
461 462 463 464 465 466 467 468 469 470 471 472 473 474 475 476 477 478 479 480 481 482 483 484 485 486 487 488
}

/* 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 已提交
489 490
asmlinkage int irix_sigpoll_sys(unsigned long __user *set,
	struct irix5_siginfo __user *info, struct timespec __user *tp)
L
Linus Torvalds 已提交
491 492 493 494
{
	long expire = MAX_SCHEDULE_TIMEOUT;
	sigset_t kset;
	int i, sig, error, timeo = 0;
R
Ralf Baechle 已提交
495
	struct timespec ktp;
L
Linus Torvalds 已提交
496 497 498 499 500 501 502 503 504 505

#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 已提交
506 507
	if (copy_from_user(&kset, set, sizeof(set)))
		return -EFAULT;
L
Linus Torvalds 已提交
508 509 510 511 512 513 514

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

	if (tp) {
R
Ralf Baechle 已提交
515
		if (copy_from_user(&ktp, tp, sizeof(*tp)))
L
Linus Torvalds 已提交
516
			return -EFAULT;
R
Ralf Baechle 已提交
517 518 519 520 521 522

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

		expire = timespec_to_jiffies(&ktp) +
		         (ktp.tv_sec || ktp.tv_nsec);
L
Linus Torvalds 已提交
523 524 525 526 527
	}

	while(1) {
		long tmp = 0;

528
		expire = schedule_timeout_interruptible(expire);
L
Linus Torvalds 已提交
529 530 531 532 533 534 535 536 537 538 539 540 541 542 543 544

		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 已提交
545
	for (sig = 1; i <= 65 /* IRIX_NSIG */; sig++) {
L
Linus Torvalds 已提交
546 547 548 549 550
		if (sigismember (&kset, sig))
			continue;
		if (sigismember (&current->pending.signal, sig)) {
			/* XXX need more than this... */
			if (info)
R
Ralf Baechle 已提交
551 552
				return copy_to_user(&info->sig, &sig, sizeof(sig));
			return 0;
L
Linus Torvalds 已提交
553 554 555 556 557 558 559 560 561 562 563 564 565 566 567 568 569 570 571 572 573 574 575
		}
	}

	/* 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

#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 已提交
576 577 578
asmlinkage int irix_waitsys(int type, int pid,
	struct irix5_siginfo __user *info, int options,
	struct rusage __user *ru)
L
Linus Torvalds 已提交
579 580 581 582 583 584 585
{
	int flag, retval;
	DECLARE_WAITQUEUE(wait, current);
	struct task_struct *tsk;
	struct task_struct *p;
	struct list_head *_p;

R
Ralf Baechle 已提交
586 587 588 589 590 591 592 593 594 595 596 597 598 599 600 601
	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 已提交
602 603 604 605 606 607 608 609 610 611 612 613 614 615 616 617 618 619 620 621 622 623 624 625 626 627 628
	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);
629
			add_parent(p);
L
Linus Torvalds 已提交
630 631
			write_unlock_irq(&tasklist_lock);
			retval = ru ? getrusage(p, RUSAGE_BOTH, ru) : 0;
R
Ralf Baechle 已提交
632 633 634 635 636 637 638 639 640 641 642 643 644 645
			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 已提交
646 647 648 649 650 651 652
			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 已提交
653 654 655 656
			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 已提交
657
			           &info->stuff.procinfo.procdata.child.status);
R
Ralf Baechle 已提交
658
			retval |= __put_user(p->utime,
L
Linus Torvalds 已提交
659
			           &info->stuff.procinfo.procdata.child.utime);
R
Ralf Baechle 已提交
660
			retval |= __put_user(p->stime,
L
Linus Torvalds 已提交
661
			           &info->stuff.procinfo.procdata.child.stime);
R
Ralf Baechle 已提交
662 663 664
			if (retval)
				return retval;

L
Linus Torvalds 已提交
665 666 667 668
			if (p->real_parent != p->parent) {
				write_lock_irq(&tasklist_lock);
				remove_parent(p);
				p->parent = p->real_parent;
669
				add_parent(p);
L
Linus Torvalds 已提交
670 671 672 673 674 675 676 677 678 679 680 681 682 683 684 685 686 687 688 689 690 691 692 693 694 695 696 697 698 699 700 701 702 703 704 705 706 707 708 709 710 711 712 713 714
				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 已提交
715 716
	int error, i, base = 0;
	struct irix5_context __user *ctx;
L
Linus Torvalds 已提交
717 718 719 720
	unsigned long flags;

	if (regs->regs[2] == 1000)
		base = 1;
R
Ralf Baechle 已提交
721
	ctx = (struct irix5_context __user *) regs->regs[base + 4];
L
Linus Torvalds 已提交
722 723 724 725 726 727

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

728
	if (!access_ok(VERIFY_WRITE, ctx, sizeof(*ctx)))
L
Linus Torvalds 已提交
729 730
		return -EFAULT;

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

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

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

R
Ralf Baechle 已提交
740 741
	error |= __put_user(0, &ctx->weird_graphics_thing);
	error |= __put_user(0, &ctx->regs[0]);
L
Linus Torvalds 已提交
742
	for (i = 1; i < 32; i++)
R
Ralf Baechle 已提交
743 744 745 746 747
		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 已提交
748 749 750 751 752 753 754 755

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

R
Ralf Baechle 已提交
758
	return error;
L
Linus Torvalds 已提交
759 760
}

R
Ralf Baechle 已提交
761
asmlinkage void irix_setcontext(struct pt_regs *regs)
L
Linus Torvalds 已提交
762
{
R
Ralf Baechle 已提交
763 764 765
	struct irix5_context __user *ctx;
	int err, base = 0;
	u32 flags;
L
Linus Torvalds 已提交
766

R
Ralf Baechle 已提交
767
	if (regs->regs[2] == 1000)
L
Linus Torvalds 已提交
768
		base = 1;
R
Ralf Baechle 已提交
769
	ctx = (struct irix5_context __user *) regs->regs[base + 4];
L
Linus Torvalds 已提交
770 771 772 773 774 775

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

R
Ralf Baechle 已提交
776 777
	if (!access_ok(VERIFY_READ, ctx, sizeof(*ctx)))
		goto segv_and_exit;
L
Linus Torvalds 已提交
778

R
Ralf Baechle 已提交
779 780
	err = __get_user(flags, &ctx->flags);
	if (flags & 0x02) {
L
Linus Torvalds 已提交
781 782 783 784
		/* XXX sigstack garbage, todo... */
		printk("Wheee, cannot do sigstack stuff in setcontext\n");
	}

R
Ralf Baechle 已提交
785
	if (flags & 0x04) {
L
Linus Torvalds 已提交
786 787 788
		int i;

		/* XXX extra control block stuff... todo... */
R
Ralf Baechle 已提交
789 790 791 792 793
		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 已提交
794 795
	}

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

R
Ralf Baechle 已提交
800 801 802 803 804 805 806 807 808 809 810 811 812 813 814 815
	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 已提交
816 817
}

R
Ralf Baechle 已提交
818 819 820 821
struct irix_sigstack {
	unsigned long sp;
	int status;
};
L
Linus Torvalds 已提交
822

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

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

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

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

R
Ralf Baechle 已提交
845 846
asmlinkage int irix_sigaltstack(struct irix_sigaltstack __user *new,
				struct irix_sigaltstack __user *old)
L
Linus Torvalds 已提交
847 848 849 850 851
{
#ifdef DEBUG_SIG
	printk("[%s:%d] irix_sigaltstack(%p,%p)\n",
	       current->comm, current->pid, new, old);
#endif
R
Ralf Baechle 已提交
852
	if (new)
L
Linus Torvalds 已提交
853
		if (!access_ok(VERIFY_READ, new, sizeof(*new)))
R
Ralf Baechle 已提交
854
			return -EFAULT;
L
Linus Torvalds 已提交
855 856 857

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

R
Ralf Baechle 已提交
861
	return 0;
L
Linus Torvalds 已提交
862 863 864 865 866 867
}

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

R
Ralf Baechle 已提交
868
asmlinkage int irix_sigsendset(struct irix_procset __user *pset, int sig)
L
Linus Torvalds 已提交
869 870 871 872 873 874 875 876 877 878 879
{
	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;
}