ia32_signal.c 14.2 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
#define COPY(x)			{		\
192
	get_user_ex(regs->x, &sc->x);		\
L
Linus Torvalds 已提交
193 194
}

195 196
#define COPY_SEG_CPL3(seg)	{			\
		unsigned short tmp;			\
197
		get_user_ex(tmp, &sc->seg);		\
198
		regs->seg = tmp | 3;			\
L
Linus Torvalds 已提交
199 200
}

201 202
#define RELOAD_SEG(seg)		{		\
	unsigned int cur, pre;			\
203
	get_user_ex(pre, &sc->seg);		\
204 205 206 207 208
	savesegment(seg, cur);			\
	pre |= 3;				\
	if (pre != cur)				\
		loadsegment(seg, pre);		\
}
209 210 211

static int ia32_restore_sigcontext(struct pt_regs *regs,
				   struct sigcontext_ia32 __user *sc,
212
				   unsigned int *pax)
213 214
{
	unsigned int tmpflags, gs, oldgs, err = 0;
215
	void __user *buf;
216 217 218 219 220
	u32 tmp;

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

221 222 223 224 225 226 227 228 229 230 231 232 233 234 235 236 237 238 239 240 241 242 243 244 245 246 247 248 249 250 251 252 253 254 255 256
	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.
		 */
		get_user_ex(gs, &sc->gs);
		gs |= 3;
		savesegment(gs, oldgs);
		if (gs != oldgs)
			load_gs_index(gs);

		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 已提交
257 258 259 260 261
	return err;
}

asmlinkage long sys32_sigreturn(struct pt_regs *regs)
{
262
	struct sigframe_ia32 __user *frame = (struct sigframe_ia32 __user *)(regs->sp-8);
L
Linus Torvalds 已提交
263
	sigset_t set;
264
	unsigned int ax;
L
Linus Torvalds 已提交
265 266 267 268 269

	if (!access_ok(VERIFY_READ, frame, sizeof(*frame)))
		goto badframe;
	if (__get_user(set.sig[0], &frame->sc.oldmask)
	    || (_COMPAT_NSIG_WORDS > 1
270 271
		&& __copy_from_user((((char *) &set.sig) + 4),
				    &frame->extramask,
L
Linus Torvalds 已提交
272 273 274 275 276 277 278 279
				    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);
280

281
	if (ia32_restore_sigcontext(regs, &frame->sc, &ax))
L
Linus Torvalds 已提交
282
		goto badframe;
283
	return ax;
L
Linus Torvalds 已提交
284 285 286 287

badframe:
	signal_fault(regs, frame, "32bit sigreturn");
	return 0;
288
}
L
Linus Torvalds 已提交
289 290 291

asmlinkage long sys32_rt_sigreturn(struct pt_regs *regs)
{
292
	struct rt_sigframe_ia32 __user *frame;
L
Linus Torvalds 已提交
293
	sigset_t set;
294
	unsigned int ax;
L
Linus Torvalds 已提交
295 296
	struct pt_regs tregs;

297
	frame = (struct rt_sigframe_ia32 __user *)(regs->sp - 4);
L
Linus Torvalds 已提交
298 299 300 301 302 303 304 305 306 307 308

	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);
309

310
	if (ia32_restore_sigcontext(regs, &frame->uc.uc_mcontext, &ax))
L
Linus Torvalds 已提交
311 312 313 314 315 316
		goto badframe;

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

317
	return ax;
L
Linus Torvalds 已提交
318 319

badframe:
320
	signal_fault(regs, frame, "32bit rt sigreturn");
L
Linus Torvalds 已提交
321
	return 0;
322
}
L
Linus Torvalds 已提交
323 324 325 326 327

/*
 * Set up a signal frame.
 */

328
static int ia32_setup_sigcontext(struct sigcontext_ia32 __user *sc,
329
				 void __user *fpstate,
330
				 struct pt_regs *regs, unsigned int mask)
L
Linus Torvalds 已提交
331 332 333
{
	int tmp, err = 0;

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

		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 已提交
366 367 368 369 370 371 372

	return err;
}

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

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

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

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

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

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

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

416 417 418 419 420 421 422 423 424 425 426
	/* 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 */
	};

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

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

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

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

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

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

455 456 457 458 459 460 461 462 463 464
	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 已提交
465
	if (err)
466
		return -EFAULT;
L
Linus Torvalds 已提交
467 468

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

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

477 478
	loadsegment(ds, __USER32_DS);
	loadsegment(es, __USER32_DS);
L
Linus Torvalds 已提交
479

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

A
Andi Kleen 已提交
483
	return 0;
L
Linus Torvalds 已提交
484 485
}

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

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

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

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

512 513 514 515 516
	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 已提交
517

518 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
		/* 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 已提交
545 546

	if (err)
547
		return -EFAULT;
L
Linus Torvalds 已提交
548 549

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

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

558 559
	loadsegment(ds, __USER32_DS);
	loadsegment(es, __USER32_DS);
560 561 562

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

A
Andi Kleen 已提交
564
	return 0;
L
Linus Torvalds 已提交
565
}