diff -ur o13/include/asm-x86_64/sigcontext.h linux-2.6.13.3/include/asm-x86_64/sigcontext.h --- o13/include/asm-x86_64/sigcontext.h 2005-10-03 19:27:35.000000000 -0400 +++ linux-2.6.13.3/include/asm-x86_64/sigcontext.h 2005-10-05 12:06:59.000000000 -0400 @@ -43,7 +43,7 @@ unsigned short cs; unsigned short gs; unsigned short fs; - unsigned short __pad0; + unsigned short ss; unsigned long err; unsigned long trapno; unsigned long oldmask; diff -ur o13/arch/x86_64/kernel/signal.c linux-2.6.13.3/arch/x86_64/kernel/signal.c --- o13/arch/x86_64/kernel/signal.c 2005-10-03 19:27:35.000000000 -0400 +++ linux-2.6.13.3/arch/x86_64/kernel/signal.c 2005-10-05 12:13:22.000000000 -0400 @@ -110,6 +110,15 @@ COPY(r14); COPY(r15); + /* Kernel saves and restores only CS and DS segments on signals, + * which are the bare essentials needed to allow mixed 32/64-bit code. + * App's signal handler can save/restore other segments if needed. */ + unsigned short cs, ss; + err |= __get_user(cs, &sc->cs); + err |= __get_user(ss, &sc->ss); + regs->cs = cs | 3; /* Force into user mode */ + regs->ss = ss | 3; + { unsigned int tmpflags; err |= __get_user(tmpflags, &sc->eflags); @@ -187,6 +196,8 @@ { int err = 0; + err |= __put_user(regs->cs, &sc->cs); + err |= __put_user(regs->ss, &sc->ss); err |= __put_user(0, &sc->gs); err |= __put_user(0, &sc->fs); @@ -318,7 +329,15 @@ regs->rsp = (unsigned long)frame; + /* Set up segment registers to run signal handlers in 64-bit mode, + even if the handler happens to be interrupting 32-bit code. */ + regs->cs = __USER_CS; + regs->ss = __USER_DS; + + /* This, by contrast, has nothing to do with segment registers - + see include/asm-x86_64/uaccess.h for details. */ set_fs(USER_DS); + regs->eflags &= ~TF_MASK; if (test_thread_flag(TIF_SINGLESTEP)) ptrace_notify(SIGTRAP);