diff options
Diffstat (limited to 'arch/x86/ia32')
-rw-r--r-- | arch/x86/ia32/ia32_signal.c | 109 |
1 files changed, 38 insertions, 71 deletions
diff --git a/arch/x86/ia32/ia32_signal.c b/arch/x86/ia32/ia32_signal.c index 4bc02b23674b..b195f85526e3 100644 --- a/arch/x86/ia32/ia32_signal.c +++ b/arch/x86/ia32/ia32_signal.c | |||
@@ -32,6 +32,8 @@ | |||
32 | #include <asm/proto.h> | 32 | #include <asm/proto.h> |
33 | #include <asm/vdso.h> | 33 | #include <asm/vdso.h> |
34 | 34 | ||
35 | #include <asm/sigframe.h> | ||
36 | |||
35 | #define DEBUG_SIG 0 | 37 | #define DEBUG_SIG 0 |
36 | 38 | ||
37 | #define _BLOCKABLE (~(sigmask(SIGKILL) | sigmask(SIGSTOP))) | 39 | #define _BLOCKABLE (~(sigmask(SIGKILL) | sigmask(SIGSTOP))) |
@@ -41,7 +43,6 @@ | |||
41 | X86_EFLAGS_ZF | X86_EFLAGS_AF | X86_EFLAGS_PF | \ | 43 | X86_EFLAGS_ZF | X86_EFLAGS_AF | X86_EFLAGS_PF | \ |
42 | X86_EFLAGS_CF) | 44 | X86_EFLAGS_CF) |
43 | 45 | ||
44 | asmlinkage int do_signal(struct pt_regs *regs, sigset_t *oldset); | ||
45 | void signal_fault(struct pt_regs *regs, void __user *frame, char *where); | 46 | void signal_fault(struct pt_regs *regs, void __user *frame, char *where); |
46 | 47 | ||
47 | int copy_siginfo_to_user32(compat_siginfo_t __user *to, siginfo_t *from) | 48 | int copy_siginfo_to_user32(compat_siginfo_t __user *to, siginfo_t *from) |
@@ -173,47 +174,28 @@ asmlinkage long sys32_sigaltstack(const stack_ia32_t __user *uss_ptr, | |||
173 | /* | 174 | /* |
174 | * Do a signal return; undo the signal stack. | 175 | * Do a signal return; undo the signal stack. |
175 | */ | 176 | */ |
177 | #define COPY(x) { \ | ||
178 | err |= __get_user(regs->x, &sc->x); \ | ||
179 | } | ||
176 | 180 | ||
177 | struct sigframe | 181 | #define COPY_SEG_CPL3(seg) { \ |
178 | { | 182 | unsigned short tmp; \ |
179 | u32 pretcode; | 183 | err |= __get_user(tmp, &sc->seg); \ |
180 | int sig; | 184 | regs->seg = tmp | 3; \ |
181 | struct sigcontext_ia32 sc; | ||
182 | struct _fpstate_ia32 fpstate_unused; /* look at kernel/sigframe.h */ | ||
183 | unsigned int extramask[_COMPAT_NSIG_WORDS-1]; | ||
184 | char retcode[8]; | ||
185 | /* fp state follows here */ | ||
186 | }; | ||
187 | |||
188 | struct rt_sigframe | ||
189 | { | ||
190 | u32 pretcode; | ||
191 | int sig; | ||
192 | u32 pinfo; | ||
193 | u32 puc; | ||
194 | compat_siginfo_t info; | ||
195 | struct ucontext_ia32 uc; | ||
196 | char retcode[8]; | ||
197 | /* fp state follows here */ | ||
198 | }; | ||
199 | |||
200 | #define COPY(x) { \ | ||
201 | unsigned int reg; \ | ||
202 | err |= __get_user(reg, &sc->x); \ | ||
203 | regs->x = reg; \ | ||
204 | } | 185 | } |
205 | 186 | ||
206 | #define RELOAD_SEG(seg,mask) \ | 187 | #define RELOAD_SEG(seg) { \ |
207 | { unsigned int cur; \ | 188 | unsigned int cur, pre; \ |
208 | unsigned short pre; \ | 189 | err |= __get_user(pre, &sc->seg); \ |
209 | err |= __get_user(pre, &sc->seg); \ | 190 | savesegment(seg, cur); \ |
210 | savesegment(seg, cur); \ | 191 | pre |= 3; \ |
211 | pre |= mask; \ | 192 | if (pre != cur) \ |
212 | if (pre != cur) loadsegment(seg, pre); } | 193 | loadsegment(seg, pre); \ |
194 | } | ||
213 | 195 | ||
214 | static int ia32_restore_sigcontext(struct pt_regs *regs, | 196 | static int ia32_restore_sigcontext(struct pt_regs *regs, |
215 | struct sigcontext_ia32 __user *sc, | 197 | struct sigcontext_ia32 __user *sc, |
216 | unsigned int *peax) | 198 | unsigned int *pax) |
217 | { | 199 | { |
218 | unsigned int tmpflags, gs, oldgs, err = 0; | 200 | unsigned int tmpflags, gs, oldgs, err = 0; |
219 | void __user *buf; | 201 | void __user *buf; |
@@ -240,18 +222,16 @@ static int ia32_restore_sigcontext(struct pt_regs *regs, | |||
240 | if (gs != oldgs) | 222 | if (gs != oldgs) |
241 | load_gs_index(gs); | 223 | load_gs_index(gs); |
242 | 224 | ||
243 | RELOAD_SEG(fs, 3); | 225 | RELOAD_SEG(fs); |
244 | RELOAD_SEG(ds, 3); | 226 | RELOAD_SEG(ds); |
245 | RELOAD_SEG(es, 3); | 227 | RELOAD_SEG(es); |
246 | 228 | ||
247 | COPY(di); COPY(si); COPY(bp); COPY(sp); COPY(bx); | 229 | COPY(di); COPY(si); COPY(bp); COPY(sp); COPY(bx); |
248 | COPY(dx); COPY(cx); COPY(ip); | 230 | COPY(dx); COPY(cx); COPY(ip); |
249 | /* Don't touch extended registers */ | 231 | /* Don't touch extended registers */ |
250 | 232 | ||
251 | err |= __get_user(regs->cs, &sc->cs); | 233 | COPY_SEG_CPL3(cs); |
252 | regs->cs |= 3; | 234 | COPY_SEG_CPL3(ss); |
253 | err |= __get_user(regs->ss, &sc->ss); | ||
254 | regs->ss |= 3; | ||
255 | 235 | ||
256 | err |= __get_user(tmpflags, &sc->flags); | 236 | err |= __get_user(tmpflags, &sc->flags); |
257 | regs->flags = (regs->flags & ~FIX_EFLAGS) | (tmpflags & FIX_EFLAGS); | 237 | regs->flags = (regs->flags & ~FIX_EFLAGS) | (tmpflags & FIX_EFLAGS); |
@@ -262,15 +242,13 @@ static int ia32_restore_sigcontext(struct pt_regs *regs, | |||
262 | buf = compat_ptr(tmp); | 242 | buf = compat_ptr(tmp); |
263 | err |= restore_i387_xstate_ia32(buf); | 243 | err |= restore_i387_xstate_ia32(buf); |
264 | 244 | ||
265 | err |= __get_user(tmp, &sc->ax); | 245 | err |= __get_user(*pax, &sc->ax); |
266 | *peax = tmp; | ||
267 | |||
268 | return err; | 246 | return err; |
269 | } | 247 | } |
270 | 248 | ||
271 | asmlinkage long sys32_sigreturn(struct pt_regs *regs) | 249 | asmlinkage long sys32_sigreturn(struct pt_regs *regs) |
272 | { | 250 | { |
273 | struct sigframe __user *frame = (struct sigframe __user *)(regs->sp-8); | 251 | struct sigframe_ia32 __user *frame = (struct sigframe_ia32 __user *)(regs->sp-8); |
274 | sigset_t set; | 252 | sigset_t set; |
275 | unsigned int ax; | 253 | unsigned int ax; |
276 | 254 | ||
@@ -300,12 +278,12 @@ badframe: | |||
300 | 278 | ||
301 | asmlinkage long sys32_rt_sigreturn(struct pt_regs *regs) | 279 | asmlinkage long sys32_rt_sigreturn(struct pt_regs *regs) |
302 | { | 280 | { |
303 | struct rt_sigframe __user *frame; | 281 | struct rt_sigframe_ia32 __user *frame; |
304 | sigset_t set; | 282 | sigset_t set; |
305 | unsigned int ax; | 283 | unsigned int ax; |
306 | struct pt_regs tregs; | 284 | struct pt_regs tregs; |
307 | 285 | ||
308 | frame = (struct rt_sigframe __user *)(regs->sp - 4); | 286 | frame = (struct rt_sigframe_ia32 __user *)(regs->sp - 4); |
309 | 287 | ||
310 | if (!access_ok(VERIFY_READ, frame, sizeof(*frame))) | 288 | if (!access_ok(VERIFY_READ, frame, sizeof(*frame))) |
311 | goto badframe; | 289 | goto badframe; |
@@ -359,20 +337,15 @@ static int ia32_setup_sigcontext(struct sigcontext_ia32 __user *sc, | |||
359 | err |= __put_user(regs->dx, &sc->dx); | 337 | err |= __put_user(regs->dx, &sc->dx); |
360 | err |= __put_user(regs->cx, &sc->cx); | 338 | err |= __put_user(regs->cx, &sc->cx); |
361 | err |= __put_user(regs->ax, &sc->ax); | 339 | 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); | 340 | err |= __put_user(current->thread.trap_no, &sc->trapno); |
365 | err |= __put_user(current->thread.error_code, &sc->err); | 341 | err |= __put_user(current->thread.error_code, &sc->err); |
366 | err |= __put_user(regs->ip, &sc->ip); | 342 | err |= __put_user(regs->ip, &sc->ip); |
343 | err |= __put_user(regs->cs, (unsigned int __user *)&sc->cs); | ||
367 | err |= __put_user(regs->flags, &sc->flags); | 344 | err |= __put_user(regs->flags, &sc->flags); |
368 | err |= __put_user(regs->sp, &sc->sp_at_signal); | 345 | err |= __put_user(regs->sp, &sc->sp_at_signal); |
346 | err |= __put_user(regs->ss, (unsigned int __user *)&sc->ss); | ||
369 | 347 | ||
370 | tmp = save_i387_xstate_ia32(fpstate); | 348 | 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 | 349 | ||
377 | /* non-iBCS2 extensions.. */ | 350 | /* non-iBCS2 extensions.. */ |
378 | err |= __put_user(mask, &sc->oldmask); | 351 | err |= __put_user(mask, &sc->oldmask); |
@@ -400,7 +373,7 @@ static void __user *get_sigframe(struct k_sigaction *ka, struct pt_regs *regs, | |||
400 | } | 373 | } |
401 | 374 | ||
402 | /* This is the legacy signal stack switching. */ | 375 | /* This is the legacy signal stack switching. */ |
403 | else if ((regs->ss & 0xffff) != __USER_DS && | 376 | else if ((regs->ss & 0xffff) != __USER32_DS && |
404 | !(ka->sa.sa_flags & SA_RESTORER) && | 377 | !(ka->sa.sa_flags & SA_RESTORER) && |
405 | ka->sa.sa_restorer) | 378 | ka->sa.sa_restorer) |
406 | sp = (unsigned long) ka->sa.sa_restorer; | 379 | sp = (unsigned long) ka->sa.sa_restorer; |
@@ -408,6 +381,8 @@ static void __user *get_sigframe(struct k_sigaction *ka, struct pt_regs *regs, | |||
408 | if (used_math()) { | 381 | if (used_math()) { |
409 | sp = sp - sig_xstate_ia32_size; | 382 | sp = sp - sig_xstate_ia32_size; |
410 | *fpstate = (struct _fpstate_ia32 *) sp; | 383 | *fpstate = (struct _fpstate_ia32 *) sp; |
384 | if (save_i387_xstate_ia32(*fpstate) < 0) | ||
385 | return (void __user *) -1L; | ||
411 | } | 386 | } |
412 | 387 | ||
413 | sp -= frame_size; | 388 | sp -= frame_size; |
@@ -420,7 +395,7 @@ static void __user *get_sigframe(struct k_sigaction *ka, struct pt_regs *regs, | |||
420 | int ia32_setup_frame(int sig, struct k_sigaction *ka, | 395 | int ia32_setup_frame(int sig, struct k_sigaction *ka, |
421 | compat_sigset_t *set, struct pt_regs *regs) | 396 | compat_sigset_t *set, struct pt_regs *regs) |
422 | { | 397 | { |
423 | struct sigframe __user *frame; | 398 | struct sigframe_ia32 __user *frame; |
424 | void __user *restorer; | 399 | void __user *restorer; |
425 | int err = 0; | 400 | int err = 0; |
426 | void __user *fpstate = NULL; | 401 | void __user *fpstate = NULL; |
@@ -430,12 +405,10 @@ int ia32_setup_frame(int sig, struct k_sigaction *ka, | |||
430 | u16 poplmovl; | 405 | u16 poplmovl; |
431 | u32 val; | 406 | u32 val; |
432 | u16 int80; | 407 | u16 int80; |
433 | u16 pad; | ||
434 | } __attribute__((packed)) code = { | 408 | } __attribute__((packed)) code = { |
435 | 0xb858, /* popl %eax ; movl $...,%eax */ | 409 | 0xb858, /* popl %eax ; movl $...,%eax */ |
436 | __NR_ia32_sigreturn, | 410 | __NR_ia32_sigreturn, |
437 | 0x80cd, /* int $0x80 */ | 411 | 0x80cd, /* int $0x80 */ |
438 | 0, | ||
439 | }; | 412 | }; |
440 | 413 | ||
441 | frame = get_sigframe(ka, regs, sizeof(*frame), &fpstate); | 414 | frame = get_sigframe(ka, regs, sizeof(*frame), &fpstate); |
@@ -471,7 +444,7 @@ int ia32_setup_frame(int sig, struct k_sigaction *ka, | |||
471 | * These are actually not used anymore, but left because some | 444 | * These are actually not used anymore, but left because some |
472 | * gdb versions depend on them as a marker. | 445 | * gdb versions depend on them as a marker. |
473 | */ | 446 | */ |
474 | err |= __copy_to_user(frame->retcode, &code, 8); | 447 | err |= __put_user(*((u64 *)&code), (u64 *)frame->retcode); |
475 | if (err) | 448 | if (err) |
476 | return -EFAULT; | 449 | return -EFAULT; |
477 | 450 | ||
@@ -501,7 +474,7 @@ int ia32_setup_frame(int sig, struct k_sigaction *ka, | |||
501 | int ia32_setup_rt_frame(int sig, struct k_sigaction *ka, siginfo_t *info, | 474 | int ia32_setup_rt_frame(int sig, struct k_sigaction *ka, siginfo_t *info, |
502 | compat_sigset_t *set, struct pt_regs *regs) | 475 | compat_sigset_t *set, struct pt_regs *regs) |
503 | { | 476 | { |
504 | struct rt_sigframe __user *frame; | 477 | struct rt_sigframe_ia32 __user *frame; |
505 | void __user *restorer; | 478 | void __user *restorer; |
506 | int err = 0; | 479 | int err = 0; |
507 | void __user *fpstate = NULL; | 480 | void __user *fpstate = NULL; |
@@ -511,8 +484,7 @@ int ia32_setup_rt_frame(int sig, struct k_sigaction *ka, siginfo_t *info, | |||
511 | u8 movl; | 484 | u8 movl; |
512 | u32 val; | 485 | u32 val; |
513 | u16 int80; | 486 | u16 int80; |
514 | u16 pad; | 487 | u8 pad; |
515 | u8 pad2; | ||
516 | } __attribute__((packed)) code = { | 488 | } __attribute__((packed)) code = { |
517 | 0xb8, | 489 | 0xb8, |
518 | __NR_ia32_rt_sigreturn, | 490 | __NR_ia32_rt_sigreturn, |
@@ -559,7 +531,7 @@ int ia32_setup_rt_frame(int sig, struct k_sigaction *ka, siginfo_t *info, | |||
559 | * Not actually used anymore, but left because some gdb | 531 | * Not actually used anymore, but left because some gdb |
560 | * versions need it. | 532 | * versions need it. |
561 | */ | 533 | */ |
562 | err |= __copy_to_user(frame->retcode, &code, 8); | 534 | err |= __put_user(*((u64 *)&code), (u64 *)frame->retcode); |
563 | if (err) | 535 | if (err) |
564 | return -EFAULT; | 536 | return -EFAULT; |
565 | 537 | ||
@@ -572,11 +544,6 @@ int ia32_setup_rt_frame(int sig, struct k_sigaction *ka, siginfo_t *info, | |||
572 | regs->dx = (unsigned long) &frame->info; | 544 | regs->dx = (unsigned long) &frame->info; |
573 | regs->cx = (unsigned long) &frame->uc; | 545 | regs->cx = (unsigned long) &frame->uc; |
574 | 546 | ||
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); | 547 | loadsegment(ds, __USER32_DS); |
581 | loadsegment(es, __USER32_DS); | 548 | loadsegment(es, __USER32_DS); |
582 | 549 | ||