ia32_signal.c 14.4 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
/*
 *  linux/arch/x86_64/ia32/ia32_signal.c
 *
 *  Copyright (C) 1991, 1992  Linus Torvalds
 *
 *  1997-11-28  Modified for POSIX.1b signals by Richard Henderson
 *  2000-06-20  Pentium III FXSR, SSE support by Gareth Hughes
 *  2000-12-*   x86-64 compatibility mode signal handling by Andi Kleen
 */

#include <linux/sched.h>
#include <linux/mm.h>
#include <linux/smp.h>
#include <linux/kernel.h>
#include <linux/signal.h>
#include <linux/errno.h>
#include <linux/wait.h>
#include <linux/ptrace.h>
#include <linux/unistd.h>
#include <linux/stddef.h>
#include <linux/personality.h>
#include <linux/compat.h>
23
#include <linux/binfmts.h>
L
Linus Torvalds 已提交
24 25 26 27 28 29 30 31
#include <asm/ucontext.h>
#include <asm/uaccess.h>
#include <asm/i387.h>
#include <asm/ptrace.h>
#include <asm/ia32_unistd.h>
#include <asm/user32.h>
#include <asm/sigcontext32.h>
#include <asm/proto.h>
R
Roland McGrath 已提交
32
#include <asm/vdso.h>
33
#include <asm/sigframe.h>
34
#include <asm/sys_ia32.h>
35

L
Linus Torvalds 已提交
36 37
#define _BLOCKABLE (~(sigmask(SIGKILL) | sigmask(SIGSTOP)))

38 39 40 41 42
#define FIX_EFLAGS	(X86_EFLAGS_AC | X86_EFLAGS_OF | \
			 X86_EFLAGS_DF | X86_EFLAGS_TF | X86_EFLAGS_SF | \
			 X86_EFLAGS_ZF | X86_EFLAGS_AF | X86_EFLAGS_PF | \
			 X86_EFLAGS_CF)

L
Linus Torvalds 已提交
43 44 45 46
void signal_fault(struct pt_regs *regs, void __user *frame, char *where);

int copy_siginfo_to_user32(compat_siginfo_t __user *to, siginfo_t *from)
{
47
	int err = 0;
48 49

	if (!access_ok(VERIFY_WRITE, to, sizeof(compat_siginfo_t)))
L
Linus Torvalds 已提交
50 51
		return -EFAULT;

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 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99
	put_user_try {
		/* If you change siginfo_t structure, please make sure that
		   this code is fixed accordingly.
		   It should never copy any pad contained in the structure
		   to avoid security leaks, but must copy the generic
		   3 ints plus the relevant union member.  */
		put_user_ex(from->si_signo, &to->si_signo);
		put_user_ex(from->si_errno, &to->si_errno);
		put_user_ex((short)from->si_code, &to->si_code);

		if (from->si_code < 0) {
			put_user_ex(from->si_pid, &to->si_pid);
			put_user_ex(from->si_uid, &to->si_uid);
			put_user_ex(ptr_to_compat(from->si_ptr), &to->si_ptr);
		} else {
			/*
			 * First 32bits of unions are always present:
			 * si_pid === si_band === si_tid === si_addr(LS half)
			 */
			put_user_ex(from->_sifields._pad[0],
					  &to->_sifields._pad[0]);
			switch (from->si_code >> 16) {
			case __SI_FAULT >> 16:
				break;
			case __SI_CHLD >> 16:
				put_user_ex(from->si_utime, &to->si_utime);
				put_user_ex(from->si_stime, &to->si_stime);
				put_user_ex(from->si_status, &to->si_status);
				/* FALL THROUGH */
			default:
			case __SI_KILL >> 16:
				put_user_ex(from->si_uid, &to->si_uid);
				break;
			case __SI_POLL >> 16:
				put_user_ex(from->si_fd, &to->si_fd);
				break;
			case __SI_TIMER >> 16:
				put_user_ex(from->si_overrun, &to->si_overrun);
				put_user_ex(ptr_to_compat(from->si_ptr),
					    &to->si_ptr);
				break;
				 /* This is not generated by the kernel as of now.  */
			case __SI_RT >> 16:
			case __SI_MESGQ >> 16:
				put_user_ex(from->si_uid, &to->si_uid);
				put_user_ex(from->si_int, &to->si_int);
				break;
			}
L
Linus Torvalds 已提交
100
		}
101 102
	} put_user_catch(err);

L
Linus Torvalds 已提交
103 104 105 106 107
	return err;
}

int copy_siginfo_from_user32(siginfo_t *to, compat_siginfo_t __user *from)
{
108
	int err = 0;
L
Linus Torvalds 已提交
109
	u32 ptr32;
110 111

	if (!access_ok(VERIFY_READ, from, sizeof(compat_siginfo_t)))
L
Linus Torvalds 已提交
112 113
		return -EFAULT;

114 115 116 117
	get_user_try {
		get_user_ex(to->si_signo, &from->si_signo);
		get_user_ex(to->si_errno, &from->si_errno);
		get_user_ex(to->si_code, &from->si_code);
L
Linus Torvalds 已提交
118

119 120 121 122 123
		get_user_ex(to->si_pid, &from->si_pid);
		get_user_ex(to->si_uid, &from->si_uid);
		get_user_ex(ptr32, &from->si_ptr);
		to->si_ptr = compat_ptr(ptr32);
	} get_user_catch(err);
L
Linus Torvalds 已提交
124 125 126 127

	return err;
}

128
asmlinkage long sys32_sigsuspend(int history0, int history1, old_sigset_t mask)
L
Linus Torvalds 已提交
129 130 131
{
	mask &= _BLOCKABLE;
	spin_lock_irq(&current->sighand->siglock);
A
Andi Kleen 已提交
132
	current->saved_sigmask = current->blocked;
L
Linus Torvalds 已提交
133 134 135 136
	siginitset(&current->blocked, mask);
	recalc_sigpending();
	spin_unlock_irq(&current->sighand->siglock);

A
Andi Kleen 已提交
137 138
	current->state = TASK_INTERRUPTIBLE;
	schedule();
R
Roland McGrath 已提交
139
	set_restore_sigmask();
A
Andi Kleen 已提交
140
	return -ERESTARTNOHAND;
L
Linus Torvalds 已提交
141 142
}

143 144 145
asmlinkage long sys32_sigaltstack(const stack_ia32_t __user *uss_ptr,
				  stack_ia32_t __user *uoss_ptr,
				  struct pt_regs *regs)
L
Linus Torvalds 已提交
146
{
147
	stack_t uss, uoss;
148
	int ret, err = 0;
149 150 151
	mm_segment_t seg;

	if (uss_ptr) {
L
Linus Torvalds 已提交
152
		u32 ptr;
153 154

		memset(&uss, 0, sizeof(stack_t));
155 156 157 158 159 160 161 162 163 164
		if (!access_ok(VERIFY_READ, uss_ptr, sizeof(stack_ia32_t)))
			return -EFAULT;

		get_user_try {
			get_user_ex(ptr, &uss_ptr->ss_sp);
			get_user_ex(uss.ss_flags, &uss_ptr->ss_flags);
			get_user_ex(uss.ss_size, &uss_ptr->ss_size);
		} get_user_catch(err);

		if (err)
L
Linus Torvalds 已提交
165 166 167
			return -EFAULT;
		uss.ss_sp = compat_ptr(ptr);
	}
168 169
	seg = get_fs();
	set_fs(KERNEL_DS);
170
	ret = do_sigaltstack(uss_ptr ? &uss : NULL, &uoss, regs->sp);
171
	set_fs(seg);
L
Linus Torvalds 已提交
172
	if (ret >= 0 && uoss_ptr)  {
173 174 175 176 177 178 179 180 181 182
		if (!access_ok(VERIFY_WRITE, uoss_ptr, sizeof(stack_ia32_t)))
			return -EFAULT;

		put_user_try {
			put_user_ex(ptr_to_compat(uoss.ss_sp), &uoss_ptr->ss_sp);
			put_user_ex(uoss.ss_flags, &uoss_ptr->ss_flags);
			put_user_ex(uoss.ss_size, &uoss_ptr->ss_size);
		} put_user_catch(err);

		if (err)
L
Linus Torvalds 已提交
183
			ret = -EFAULT;
184 185
	}
	return ret;
L
Linus Torvalds 已提交
186 187 188 189 190
}

/*
 * Do a signal return; undo the signal stack.
 */
191 192 193 194 195 196 197 198
#define loadsegment_gs(v)	load_gs_index(v)
#define loadsegment_fs(v)	loadsegment(fs, v)
#define loadsegment_ds(v)	loadsegment(ds, v)
#define loadsegment_es(v)	loadsegment(es, v)

#define get_user_seg(seg)	({ unsigned int v; savesegment(seg, v); v; })
#define set_user_seg(seg, v)	loadsegment_##seg(v)

199
#define COPY(x)			{		\
200
	get_user_ex(regs->x, &sc->x);		\
L
Linus Torvalds 已提交
201 202
}

203 204 205 206 207 208 209 210 211
#define GET_SEG(seg)		({			\
	unsigned short tmp;				\
	get_user_ex(tmp, &sc->seg);			\
	tmp;						\
})

#define COPY_SEG_CPL3(seg)	do {			\
	regs->seg = GET_SEG(seg) | 3;			\
} while (0)
L
Linus Torvalds 已提交
212

213
#define RELOAD_SEG(seg)		{		\
214 215
	unsigned int pre = GET_SEG(seg);	\
	unsigned int cur = get_user_seg(seg);	\
216 217
	pre |= 3;				\
	if (pre != cur)				\
218
		set_user_seg(seg, pre);		\
219
}
220 221 222

static int ia32_restore_sigcontext(struct pt_regs *regs,
				   struct sigcontext_ia32 __user *sc,
223
				   unsigned int *pax)
224
{
225
	unsigned int tmpflags, err = 0;
226
	void __user *buf;
227 228 229 230 231
	u32 tmp;

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

232 233 234 235 236 237 238
	get_user_try {
		/*
		 * Reload fs and gs if they have changed in the signal
		 * handler.  This does not handle long fs/gs base changes in
		 * the handler, but does not clobber them at least in the
		 * normal case.
		 */
239
		RELOAD_SEG(gs);
240 241 242 243 244 245 246 247 248 249 250 251 252 253 254 255 256 257 258 259 260 261 262
		RELOAD_SEG(fs);
		RELOAD_SEG(ds);
		RELOAD_SEG(es);

		COPY(di); COPY(si); COPY(bp); COPY(sp); COPY(bx);
		COPY(dx); COPY(cx); COPY(ip);
		/* Don't touch extended registers */

		COPY_SEG_CPL3(cs);
		COPY_SEG_CPL3(ss);

		get_user_ex(tmpflags, &sc->flags);
		regs->flags = (regs->flags & ~FIX_EFLAGS) | (tmpflags & FIX_EFLAGS);
		/* disable syscall checks */
		regs->orig_ax = -1;

		get_user_ex(tmp, &sc->fpstate);
		buf = compat_ptr(tmp);
		err |= restore_i387_xstate_ia32(buf);

		get_user_ex(*pax, &sc->ax);
	} get_user_catch(err);

L
Linus Torvalds 已提交
263 264 265 266 267
	return err;
}

asmlinkage long sys32_sigreturn(struct pt_regs *regs)
{
268
	struct sigframe_ia32 __user *frame = (struct sigframe_ia32 __user *)(regs->sp-8);
L
Linus Torvalds 已提交
269
	sigset_t set;
270
	unsigned int ax;
L
Linus Torvalds 已提交
271 272 273 274 275

	if (!access_ok(VERIFY_READ, frame, sizeof(*frame)))
		goto badframe;
	if (__get_user(set.sig[0], &frame->sc.oldmask)
	    || (_COMPAT_NSIG_WORDS > 1
276 277
		&& __copy_from_user((((char *) &set.sig) + 4),
				    &frame->extramask,
L
Linus Torvalds 已提交
278 279 280 281 282 283 284 285
				    sizeof(frame->extramask))))
		goto badframe;

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

287
	if (ia32_restore_sigcontext(regs, &frame->sc, &ax))
L
Linus Torvalds 已提交
288
		goto badframe;
289
	return ax;
L
Linus Torvalds 已提交
290 291 292 293

badframe:
	signal_fault(regs, frame, "32bit sigreturn");
	return 0;
294
}
L
Linus Torvalds 已提交
295 296 297

asmlinkage long sys32_rt_sigreturn(struct pt_regs *regs)
{
298
	struct rt_sigframe_ia32 __user *frame;
L
Linus Torvalds 已提交
299
	sigset_t set;
300
	unsigned int ax;
L
Linus Torvalds 已提交
301 302
	struct pt_regs tregs;

303
	frame = (struct rt_sigframe_ia32 __user *)(regs->sp - 4);
L
Linus Torvalds 已提交
304 305 306 307 308 309 310 311 312 313 314

	if (!access_ok(VERIFY_READ, frame, sizeof(*frame)))
		goto badframe;
	if (__copy_from_user(&set, &frame->uc.uc_sigmask, sizeof(set)))
		goto badframe;

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

316
	if (ia32_restore_sigcontext(regs, &frame->uc.uc_mcontext, &ax))
L
Linus Torvalds 已提交
317 318 319 320 321 322
		goto badframe;

	tregs = *regs;
	if (sys32_sigaltstack(&frame->uc.uc_stack, NULL, &tregs) == -EFAULT)
		goto badframe;

323
	return ax;
L
Linus Torvalds 已提交
324 325

badframe:
326
	signal_fault(regs, frame, "32bit rt sigreturn");
L
Linus Torvalds 已提交
327
	return 0;
328
}
L
Linus Torvalds 已提交
329 330 331 332 333

/*
 * Set up a signal frame.
 */

334
static int ia32_setup_sigcontext(struct sigcontext_ia32 __user *sc,
335
				 void __user *fpstate,
336
				 struct pt_regs *regs, unsigned int mask)
L
Linus Torvalds 已提交
337
{
338
	int err = 0;
L
Linus Torvalds 已提交
339

340
	put_user_try {
341 342 343 344
		put_user_ex(get_user_seg(gs), (unsigned int __user *)&sc->gs);
		put_user_ex(get_user_seg(fs), (unsigned int __user *)&sc->fs);
		put_user_ex(get_user_seg(ds), (unsigned int __user *)&sc->ds);
		put_user_ex(get_user_seg(es), (unsigned int __user *)&sc->es);
345 346 347 348 349 350 351 352 353 354 355 356 357 358 359 360 361 362 363 364 365 366 367

		put_user_ex(regs->di, &sc->di);
		put_user_ex(regs->si, &sc->si);
		put_user_ex(regs->bp, &sc->bp);
		put_user_ex(regs->sp, &sc->sp);
		put_user_ex(regs->bx, &sc->bx);
		put_user_ex(regs->dx, &sc->dx);
		put_user_ex(regs->cx, &sc->cx);
		put_user_ex(regs->ax, &sc->ax);
		put_user_ex(current->thread.trap_no, &sc->trapno);
		put_user_ex(current->thread.error_code, &sc->err);
		put_user_ex(regs->ip, &sc->ip);
		put_user_ex(regs->cs, (unsigned int __user *)&sc->cs);
		put_user_ex(regs->flags, &sc->flags);
		put_user_ex(regs->sp, &sc->sp_at_signal);
		put_user_ex(regs->ss, (unsigned int __user *)&sc->ss);

		put_user_ex(ptr_to_compat(fpstate), &sc->fpstate);

		/* non-iBCS2 extensions.. */
		put_user_ex(mask, &sc->oldmask);
		put_user_ex(current->thread.cr2, &sc->cr2);
	} put_user_catch(err);
L
Linus Torvalds 已提交
368 369 370 371 372 373 374

	return err;
}

/*
 * Determine which stack to use..
 */
375
static void __user *get_sigframe(struct k_sigaction *ka, struct pt_regs *regs,
376
				 size_t frame_size,
377
				 void **fpstate)
L
Linus Torvalds 已提交
378
{
379
	unsigned long sp;
L
Linus Torvalds 已提交
380 381

	/* Default to using normal stack */
382
	sp = regs->sp;
L
Linus Torvalds 已提交
383 384 385

	/* This is the X/Open sanctioned signal stack switching.  */
	if (ka->sa.sa_flags & SA_ONSTACK) {
386 387
		if (sas_ss_flags(sp) == 0)
			sp = current->sas_ss_sp + current->sas_ss_size;
L
Linus Torvalds 已提交
388 389 390
	}

	/* This is the legacy signal stack switching. */
391
	else if ((regs->ss & 0xffff) != __USER32_DS &&
L
Linus Torvalds 已提交
392
		!(ka->sa.sa_flags & SA_RESTORER) &&
393
		 ka->sa.sa_restorer)
394
		sp = (unsigned long) ka->sa.sa_restorer;
L
Linus Torvalds 已提交
395

396 397 398
	if (used_math()) {
		sp = sp - sig_xstate_ia32_size;
		*fpstate = (struct _fpstate_ia32 *) sp;
399 400
		if (save_i387_xstate_ia32(*fpstate) < 0)
			return (void __user *) -1L;
401 402
	}

403
	sp -= frame_size;
404 405
	/* Align the stack pointer according to the i386 ABI,
	 * i.e. so that on function entry ((sp + 4) & 15) == 0. */
406 407
	sp = ((sp + 4) & -16ul) - 4;
	return (void __user *) sp;
L
Linus Torvalds 已提交
408 409
}

410
int ia32_setup_frame(int sig, struct k_sigaction *ka,
411
		     compat_sigset_t *set, struct pt_regs *regs)
L
Linus Torvalds 已提交
412
{
413
	struct sigframe_ia32 __user *frame;
414
	void __user *restorer;
L
Linus Torvalds 已提交
415
	int err = 0;
416
	void __user *fpstate = NULL;
L
Linus Torvalds 已提交
417

418 419 420 421 422 423 424 425 426 427 428
	/* copy_to_user optimizes that into a single 8 byte store */
	static const struct {
		u16 poplmovl;
		u32 val;
		u16 int80;
	} __attribute__((packed)) code = {
		0xb858,		 /* popl %eax ; movl $...,%eax */
		__NR_ia32_sigreturn,
		0x80cd,		/* int $0x80 */
	};

429
	frame = get_sigframe(ka, regs, sizeof(*frame), &fpstate);
L
Linus Torvalds 已提交
430 431

	if (!access_ok(VERIFY_WRITE, frame, sizeof(*frame)))
432
		return -EFAULT;
L
Linus Torvalds 已提交
433

434
	if (__put_user(sig, &frame->sig))
435
		return -EFAULT;
L
Linus Torvalds 已提交
436

437
	if (ia32_setup_sigcontext(&frame->sc, fpstate, regs, set->sig[0]))
438
		return -EFAULT;
L
Linus Torvalds 已提交
439 440

	if (_COMPAT_NSIG_WORDS > 1) {
441 442
		if (__copy_to_user(frame->extramask, &set->sig[1],
				   sizeof(frame->extramask)))
443
			return -EFAULT;
L
Linus Torvalds 已提交
444 445
	}

R
Roland McGrath 已提交
446
	if (ka->sa.sa_flags & SA_RESTORER) {
447
		restorer = ka->sa.sa_restorer;
R
Roland McGrath 已提交
448 449
	} else {
		/* Return stub is in 32bit vsyscall page */
450
		if (current->mm->context.vdso)
R
Roland McGrath 已提交
451 452 453
			restorer = VDSO32_SYMBOL(current->mm->context.vdso,
						 sigreturn);
		else
J
Jan Engelhardt 已提交
454
			restorer = &frame->retcode;
R
Roland McGrath 已提交
455
	}
456

457 458 459 460 461 462 463 464 465 466
	put_user_try {
		put_user_ex(ptr_to_compat(restorer), &frame->pretcode);

		/*
		 * These are actually not used anymore, but left because some
		 * gdb versions depend on them as a marker.
		 */
		put_user_ex(*((u64 *)&code), (u64 *)frame->retcode);
	} put_user_catch(err);

L
Linus Torvalds 已提交
467
	if (err)
468
		return -EFAULT;
L
Linus Torvalds 已提交
469 470

	/* Set up registers for signal handler */
471 472
	regs->sp = (unsigned long) frame;
	regs->ip = (unsigned long) ka->sa.sa_handler;
L
Linus Torvalds 已提交
473

474
	/* Make -mregparm=3 work */
475 476 477
	regs->ax = sig;
	regs->dx = 0;
	regs->cx = 0;
478

479 480
	loadsegment(ds, __USER32_DS);
	loadsegment(es, __USER32_DS);
L
Linus Torvalds 已提交
481

482 483
	regs->cs = __USER32_CS;
	regs->ss = __USER32_DS;
L
Linus Torvalds 已提交
484

A
Andi Kleen 已提交
485
	return 0;
L
Linus Torvalds 已提交
486 487
}

488
int ia32_setup_rt_frame(int sig, struct k_sigaction *ka, siginfo_t *info,
489
			compat_sigset_t *set, struct pt_regs *regs)
L
Linus Torvalds 已提交
490
{
491
	struct rt_sigframe_ia32 __user *frame;
R
Roland McGrath 已提交
492
	void __user *restorer;
L
Linus Torvalds 已提交
493
	int err = 0;
494
	void __user *fpstate = NULL;
L
Linus Torvalds 已提交
495

496 497 498 499 500
	/* __copy_to_user optimizes that into a single 8 byte store */
	static const struct {
		u8 movl;
		u32 val;
		u16 int80;
501
		u8  pad;
502 503 504 505 506 507 508
	} __attribute__((packed)) code = {
		0xb8,
		__NR_ia32_rt_sigreturn,
		0x80cd,
		0,
	};

509
	frame = get_sigframe(ka, regs, sizeof(*frame), &fpstate);
L
Linus Torvalds 已提交
510 511

	if (!access_ok(VERIFY_WRITE, frame, sizeof(*frame)))
512
		return -EFAULT;
L
Linus Torvalds 已提交
513

514 515 516 517 518
	put_user_try {
		put_user_ex(sig, &frame->sig);
		put_user_ex(ptr_to_compat(&frame->info), &frame->pinfo);
		put_user_ex(ptr_to_compat(&frame->uc), &frame->puc);
		err |= copy_siginfo_to_user32(&frame->info, info);
L
Linus Torvalds 已提交
519

520 521 522 523 524 525 526 527 528 529 530 531 532 533 534 535 536 537 538 539 540 541 542 543 544 545 546
		/* Create the ucontext.  */
		if (cpu_has_xsave)
			put_user_ex(UC_FP_XSTATE, &frame->uc.uc_flags);
		else
			put_user_ex(0, &frame->uc.uc_flags);
		put_user_ex(0, &frame->uc.uc_link);
		put_user_ex(current->sas_ss_sp, &frame->uc.uc_stack.ss_sp);
		put_user_ex(sas_ss_flags(regs->sp),
			    &frame->uc.uc_stack.ss_flags);
		put_user_ex(current->sas_ss_size, &frame->uc.uc_stack.ss_size);
		err |= ia32_setup_sigcontext(&frame->uc.uc_mcontext, fpstate,
					     regs, set->sig[0]);
		err |= __copy_to_user(&frame->uc.uc_sigmask, set, sizeof(*set));

		if (ka->sa.sa_flags & SA_RESTORER)
			restorer = ka->sa.sa_restorer;
		else
			restorer = VDSO32_SYMBOL(current->mm->context.vdso,
						 rt_sigreturn);
		put_user_ex(ptr_to_compat(restorer), &frame->pretcode);

		/*
		 * Not actually used anymore, but left because some gdb
		 * versions need it.
		 */
		put_user_ex(*((u64 *)&code), (u64 *)frame->retcode);
	} put_user_catch(err);
L
Linus Torvalds 已提交
547 548

	if (err)
549
		return -EFAULT;
L
Linus Torvalds 已提交
550 551

	/* Set up registers for signal handler */
552 553
	regs->sp = (unsigned long) frame;
	regs->ip = (unsigned long) ka->sa.sa_handler;
L
Linus Torvalds 已提交
554

555
	/* Make -mregparm=3 work */
556 557 558
	regs->ax = sig;
	regs->dx = (unsigned long) &frame->info;
	regs->cx = (unsigned long) &frame->uc;
559

560 561
	loadsegment(ds, __USER32_DS);
	loadsegment(es, __USER32_DS);
562 563 564

	regs->cs = __USER32_CS;
	regs->ss = __USER32_DS;
L
Linus Torvalds 已提交
565

A
Andi Kleen 已提交
566
	return 0;
L
Linus Torvalds 已提交
567
}