patch-2.4.21 linux-2.4.21/arch/x86_64/ia32/ia32_signal.c
Next file: linux-2.4.21/arch/x86_64/ia32/ia32entry.S
Previous file: linux-2.4.21/arch/x86_64/ia32/ia32_ioctl.c
Back to the patch index
Back to the overall index
- Lines: 186
- Date:
2003-06-13 07:51:32.000000000 -0700
- Orig file:
linux-2.4.20/arch/x86_64/ia32/ia32_signal.c
- Orig date:
2002-11-28 15:53:12.000000000 -0800
diff -urN linux-2.4.20/arch/x86_64/ia32/ia32_signal.c linux-2.4.21/arch/x86_64/ia32/ia32_signal.c
@@ -7,7 +7,7 @@
* 2000-06-20 Pentium III FXSR, SSE support by Gareth Hughes
* 2000-12-* x86-64 compatibility mode signal handling by Andi Kleen
*
- * $Id: ia32_signal.c,v 1.22 2002/07/29 10:34:03 ak Exp $
+ * $Id: ia32_signal.c,v 1.31 2003/03/12 08:22:12 ak Exp $
*/
#include <linux/sched.h>
@@ -33,6 +33,7 @@
#include <asm/fpu32.h>
#define ptr_to_u32(x) ((u32)(u64)(x)) /* avoid gcc warning */
+#define u32_to_ptr(x) ((void *)(u64)(x))
#define DEBUG_SIG 0
@@ -45,9 +46,16 @@
{
if (!access_ok (VERIFY_WRITE, to, sizeof(siginfo_t)))
return -EFAULT;
- if (from->si_code < 0)
- return __copy_to_user(to, from, sizeof(siginfo_t));
- else {
+ if (from->si_code < 0) {
+ /* the only field that's different is the alignment
+ of the pointer in sigval_t. Move that 4 bytes down including
+ padding. */
+ memmove(&((siginfo_t32 *)&from)->si_int,
+ &from->si_int,
+ sizeof(siginfo_t) - offsetof(siginfo_t, si_int));
+ /* last 4 bytes stay the same */
+ return __copy_to_user(to, from, sizeof(siginfo_t32));
+ } else {
int err;
/* If you change siginfo_t structure, please be sure
@@ -57,7 +65,7 @@
3 ints plus the relevant union member. */
err = __put_user(from->si_signo, &to->si_signo);
err |= __put_user(from->si_errno, &to->si_errno);
- err |= __put_user((short)from->si_code, &to->si_code);
+ err |= __put_user(from->si_code, &to->si_code);
/* First 32bits of unions are always present. */
err |= __put_user(from->si_pid, &to->si_pid);
switch (from->si_code >> 16) {
@@ -76,7 +84,7 @@
}
}
-asmlinkage int
+asmlinkage long
sys32_sigsuspend(int history0, int history1, old_sigset_t mask, struct pt_regs regs)
{
sigset_t saveset;
@@ -97,27 +105,32 @@
}
}
-asmlinkage int
+asmlinkage long
sys32_sigaltstack(const stack_ia32_t *uss_ptr, stack_ia32_t *uoss_ptr,
struct pt_regs regs)
{
stack_t uss,uoss;
int ret;
mm_segment_t seg;
+ if (uss_ptr) {
+ u32 val32;
+ memset(&uss, 0, sizeof(stack_t));
if (!access_ok(VERIFY_READ,uss_ptr,sizeof(stack_ia32_t)) ||
- __get_user(ptr_to_u32(uss.ss_sp), &uss_ptr->ss_sp) ||
- __get_user((u32)uss.ss_flags, &uss_ptr->ss_flags) ||
- __get_user((u32)uss.ss_size, &uss_ptr->ss_size))
+ __get_user(val32, &uss_ptr->ss_sp) ||
+ __get_user(uss.ss_flags, &uss_ptr->ss_flags) ||
+ __get_user(uss.ss_size, &uss_ptr->ss_size))
return -EFAULT;
+ uss.ss_sp = u32_to_ptr(val32);
+ }
seg = get_fs();
set_fs(KERNEL_DS);
- ret = do_sigaltstack(&uss, &uoss, regs.rsp);
+ ret = do_sigaltstack(uss_ptr ? &uss : NULL, &uoss, regs.rsp);
set_fs(seg);
if (ret >= 0 && uoss_ptr) {
- if (!access_ok(VERIFY_WRITE,uss_ptr,sizeof(stack_ia32_t)) ||
- __put_user(ptr_to_u32(uss.ss_sp), &uss_ptr->ss_sp) ||
- __put_user((u32)uss.ss_flags, &uss_ptr->ss_flags) ||
- __put_user((u32)uss.ss_size, &uss_ptr->ss_size))
+ if (!access_ok(VERIFY_WRITE,uoss_ptr,sizeof(stack_ia32_t)) ||
+ __put_user(ptr_to_u32(uoss.ss_sp), &uoss_ptr->ss_sp) ||
+ __put_user((u32)uoss.ss_flags, &uoss_ptr->ss_flags) ||
+ __put_user((u32)uoss.ss_size, &uoss_ptr->ss_size))
ret = -EFAULT;
}
return ret;
@@ -173,31 +186,29 @@
if (pre != cur) loadsegment(seg,pre); }
/* 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. */
+ This does not handle long gs base changes in the handler, but
+ does not clobber it at least in the normal case. */
{
unsigned short gs;
+ unsigned int curgs;
err |= __get_user(gs, &sc->gs);
- load_gs_index(gs);
+ asm volatile("movl %%gs,%0" : "=r" (curgs));
+ if (gs != curgs)
+ load_gs_index(gs | 3);
}
- RELOAD_SEG(fs,0);
- RELOAD_SEG(ds,0);
- RELOAD_SEG(es,0);
+ RELOAD_SEG(fs,3);
+ RELOAD_SEG(ds,3);
+ RELOAD_SEG(es,3);
COPY(di); COPY(si); COPY(bp); COPY(sp); COPY(bx);
COPY(dx); COPY(cx); COPY(ip);
/* Don't touch extended registers */
-#if 1 /* not ready for this yet */
err |= __get_user(regs->cs, &sc->cs);
- regs->cs |= 2;
+ regs->cs |= 3;
err |= __get_user(regs->ss, &sc->ss);
- regs->ss |= 2;
-#else
- regs->cs = __USER32_CS;
- regs->ss = __USER32_DS;
-#endif
+ regs->ss |= 3;
{
unsigned int tmpflags;
@@ -213,7 +224,7 @@
buf = (struct _fpstate_ia32 *) (u64)tmp;
if (buf) {
if (verify_area(VERIFY_READ, buf, sizeof(*buf)))
- goto badframe;
+ return 1;
err |= restore_i387_ia32(current, buf, 0);
}
}
@@ -224,12 +235,9 @@
*peax = tmp;
}
return err;
-
-badframe:
- return 1;
}
-asmlinkage int sys32_sigreturn(struct pt_regs regs)
+asmlinkage long sys32_sigreturn(struct pt_regs regs)
{
struct sigframe *frame = (struct sigframe *)(regs.rsp - 8);
sigset_t set;
@@ -258,7 +266,7 @@
return 0;
}
-asmlinkage int sys32_rt_sigreturn(struct pt_regs regs)
+asmlinkage long sys32_rt_sigreturn(struct pt_regs regs)
{
struct rt_sigframe *frame = (struct rt_sigframe *)(regs.rsp - 4);
sigset_t set;
@@ -336,8 +344,12 @@
tmp = save_i387_ia32(current, fpstate, regs, 0);
if (tmp < 0)
err = -EFAULT;
- else
+ else {
+ /* trigger finit in signal handler */
+ current->used_math = 0;
+ stts();
err |= __put_user((u32)(u64)(tmp ? fpstate : NULL), &sc->fpstate);
+ }
/* non-iBCS2 extensions.. */
err |= __put_user(mask, &sc->oldmask);
FUNET's LINUX-ADM group, linux-adm@nic.funet.fi
TCL-scripts by Sam Shen (who was at: slshen@lbl.gov)