diff options
Diffstat (limited to 'arch/x86/ia32')
-rw-r--r-- | arch/x86/ia32/ia32_signal.c | 68 |
1 files changed, 29 insertions, 39 deletions
diff --git a/arch/x86/ia32/ia32_signal.c b/arch/x86/ia32/ia32_signal.c index 4bc02b23674b..9ddf2fa0129d 100644 --- a/arch/x86/ia32/ia32_signal.c +++ b/arch/x86/ia32/ia32_signal.c | |||
@@ -197,23 +197,28 @@ struct rt_sigframe | |||
197 | /* fp state follows here */ | 197 | /* fp state follows here */ |
198 | }; | 198 | }; |
199 | 199 | ||
200 | #define COPY(x) { \ | 200 | #define COPY(x) { \ |
201 | unsigned int reg; \ | 201 | err |= __get_user(regs->x, &sc->x); \ |
202 | err |= __get_user(reg, &sc->x); \ | ||
203 | regs->x = reg; \ | ||
204 | } | 202 | } |
205 | 203 | ||
206 | #define RELOAD_SEG(seg,mask) \ | 204 | #define COPY_SEG_CPL3(seg) { \ |
207 | { unsigned int cur; \ | 205 | unsigned short tmp; \ |
208 | unsigned short pre; \ | 206 | err |= __get_user(tmp, &sc->seg); \ |
209 | err |= __get_user(pre, &sc->seg); \ | 207 | regs->seg = tmp | 3; \ |
210 | savesegment(seg, cur); \ | 208 | } |
211 | pre |= mask; \ | 209 | |
212 | if (pre != cur) loadsegment(seg, pre); } | 210 | #define RELOAD_SEG(seg) { \ |
211 | unsigned int cur, pre; \ | ||
212 | err |= __get_user(pre, &sc->seg); \ | ||
213 | savesegment(seg, cur); \ | ||
214 | pre |= 3; \ | ||
215 | if (pre != cur) \ | ||
216 | loadsegment(seg, pre); \ | ||
217 | } | ||
213 | 218 | ||
214 | static int ia32_restore_sigcontext(struct pt_regs *regs, | 219 | static int ia32_restore_sigcontext(struct pt_regs *regs, |
215 | struct sigcontext_ia32 __user *sc, | 220 | struct sigcontext_ia32 __user *sc, |
216 | unsigned int *peax) | 221 | unsigned int *pax) |
217 | { | 222 | { |
218 | unsigned int tmpflags, gs, oldgs, err = 0; | 223 | unsigned int tmpflags, gs, oldgs, err = 0; |
219 | void __user *buf; | 224 | void __user *buf; |
@@ -240,18 +245,16 @@ static int ia32_restore_sigcontext(struct pt_regs *regs, | |||
240 | if (gs != oldgs) | 245 | if (gs != oldgs) |
241 | load_gs_index(gs); | 246 | load_gs_index(gs); |
242 | 247 | ||
243 | RELOAD_SEG(fs, 3); | 248 | RELOAD_SEG(fs); |
244 | RELOAD_SEG(ds, 3); | 249 | RELOAD_SEG(ds); |
245 | RELOAD_SEG(es, 3); | 250 | RELOAD_SEG(es); |
246 | 251 | ||
247 | COPY(di); COPY(si); COPY(bp); COPY(sp); COPY(bx); | 252 | COPY(di); COPY(si); COPY(bp); COPY(sp); COPY(bx); |
248 | COPY(dx); COPY(cx); COPY(ip); | 253 | COPY(dx); COPY(cx); COPY(ip); |
249 | /* Don't touch extended registers */ | 254 | /* Don't touch extended registers */ |
250 | 255 | ||
251 | err |= __get_user(regs->cs, &sc->cs); | 256 | COPY_SEG_CPL3(cs); |
252 | regs->cs |= 3; | 257 | COPY_SEG_CPL3(ss); |
253 | err |= __get_user(regs->ss, &sc->ss); | ||
254 | regs->ss |= 3; | ||
255 | 258 | ||
256 | err |= __get_user(tmpflags, &sc->flags); | 259 | err |= __get_user(tmpflags, &sc->flags); |
257 | regs->flags = (regs->flags & ~FIX_EFLAGS) | (tmpflags & FIX_EFLAGS); | 260 | regs->flags = (regs->flags & ~FIX_EFLAGS) | (tmpflags & FIX_EFLAGS); |
@@ -262,9 +265,7 @@ static int ia32_restore_sigcontext(struct pt_regs *regs, | |||
262 | buf = compat_ptr(tmp); | 265 | buf = compat_ptr(tmp); |
263 | err |= restore_i387_xstate_ia32(buf); | 266 | err |= restore_i387_xstate_ia32(buf); |
264 | 267 | ||
265 | err |= __get_user(tmp, &sc->ax); | 268 | err |= __get_user(*pax, &sc->ax); |
266 | *peax = tmp; | ||
267 | |||
268 | return err; | 269 | return err; |
269 | } | 270 | } |
270 | 271 | ||
@@ -359,20 +360,15 @@ static int ia32_setup_sigcontext(struct sigcontext_ia32 __user *sc, | |||
359 | err |= __put_user(regs->dx, &sc->dx); | 360 | err |= __put_user(regs->dx, &sc->dx); |
360 | err |= __put_user(regs->cx, &sc->cx); | 361 | err |= __put_user(regs->cx, &sc->cx); |
361 | err |= __put_user(regs->ax, &sc->ax); | 362 | err |= __put_user(regs->ax, &sc->ax); |
362 | err |= __put_user(regs->cs, &sc->cs); | ||
363 | err |= __put_user(regs->ss, &sc->ss); | ||
364 | err |= __put_user(current->thread.trap_no, &sc->trapno); | 363 | err |= __put_user(current->thread.trap_no, &sc->trapno); |
365 | err |= __put_user(current->thread.error_code, &sc->err); | 364 | err |= __put_user(current->thread.error_code, &sc->err); |
366 | err |= __put_user(regs->ip, &sc->ip); | 365 | err |= __put_user(regs->ip, &sc->ip); |
366 | err |= __put_user(regs->cs, (unsigned int __user *)&sc->cs); | ||
367 | err |= __put_user(regs->flags, &sc->flags); | 367 | err |= __put_user(regs->flags, &sc->flags); |
368 | err |= __put_user(regs->sp, &sc->sp_at_signal); | 368 | err |= __put_user(regs->sp, &sc->sp_at_signal); |
369 | err |= __put_user(regs->ss, (unsigned int __user *)&sc->ss); | ||
369 | 370 | ||
370 | tmp = save_i387_xstate_ia32(fpstate); | 371 | err |= __put_user(ptr_to_compat(fpstate), &sc->fpstate); |
371 | if (tmp < 0) | ||
372 | err = -EFAULT; | ||
373 | else | ||
374 | err |= __put_user(ptr_to_compat(tmp ? fpstate : NULL), | ||
375 | &sc->fpstate); | ||
376 | 372 | ||
377 | /* non-iBCS2 extensions.. */ | 373 | /* non-iBCS2 extensions.. */ |
378 | err |= __put_user(mask, &sc->oldmask); | 374 | err |= __put_user(mask, &sc->oldmask); |
@@ -408,6 +404,8 @@ static void __user *get_sigframe(struct k_sigaction *ka, struct pt_regs *regs, | |||
408 | if (used_math()) { | 404 | if (used_math()) { |
409 | sp = sp - sig_xstate_ia32_size; | 405 | sp = sp - sig_xstate_ia32_size; |
410 | *fpstate = (struct _fpstate_ia32 *) sp; | 406 | *fpstate = (struct _fpstate_ia32 *) sp; |
407 | if (save_i387_xstate_ia32(*fpstate) < 0) | ||
408 | return (void __user *) -1L; | ||
411 | } | 409 | } |
412 | 410 | ||
413 | sp -= frame_size; | 411 | sp -= frame_size; |
@@ -430,12 +428,10 @@ int ia32_setup_frame(int sig, struct k_sigaction *ka, | |||
430 | u16 poplmovl; | 428 | u16 poplmovl; |
431 | u32 val; | 429 | u32 val; |
432 | u16 int80; | 430 | u16 int80; |
433 | u16 pad; | ||
434 | } __attribute__((packed)) code = { | 431 | } __attribute__((packed)) code = { |
435 | 0xb858, /* popl %eax ; movl $...,%eax */ | 432 | 0xb858, /* popl %eax ; movl $...,%eax */ |
436 | __NR_ia32_sigreturn, | 433 | __NR_ia32_sigreturn, |
437 | 0x80cd, /* int $0x80 */ | 434 | 0x80cd, /* int $0x80 */ |
438 | 0, | ||
439 | }; | 435 | }; |
440 | 436 | ||
441 | frame = get_sigframe(ka, regs, sizeof(*frame), &fpstate); | 437 | frame = get_sigframe(ka, regs, sizeof(*frame), &fpstate); |
@@ -511,8 +507,7 @@ int ia32_setup_rt_frame(int sig, struct k_sigaction *ka, siginfo_t *info, | |||
511 | u8 movl; | 507 | u8 movl; |
512 | u32 val; | 508 | u32 val; |
513 | u16 int80; | 509 | u16 int80; |
514 | u16 pad; | 510 | u8 pad; |
515 | u8 pad2; | ||
516 | } __attribute__((packed)) code = { | 511 | } __attribute__((packed)) code = { |
517 | 0xb8, | 512 | 0xb8, |
518 | __NR_ia32_rt_sigreturn, | 513 | __NR_ia32_rt_sigreturn, |
@@ -572,11 +567,6 @@ int ia32_setup_rt_frame(int sig, struct k_sigaction *ka, siginfo_t *info, | |||
572 | regs->dx = (unsigned long) &frame->info; | 567 | regs->dx = (unsigned long) &frame->info; |
573 | regs->cx = (unsigned long) &frame->uc; | 568 | regs->cx = (unsigned long) &frame->uc; |
574 | 569 | ||
575 | /* Make -mregparm=3 work */ | ||
576 | regs->ax = sig; | ||
577 | regs->dx = (unsigned long) &frame->info; | ||
578 | regs->cx = (unsigned long) &frame->uc; | ||
579 | |||
580 | loadsegment(ds, __USER32_DS); | 570 | loadsegment(ds, __USER32_DS); |
581 | loadsegment(es, __USER32_DS); | 571 | loadsegment(es, __USER32_DS); |
582 | 572 | ||