summaryrefslogtreecommitdiff
path: root/sys/compat/linux
diff options
context:
space:
mode:
authorchristos <christos@NetBSD.org>2002-12-06 00:02:59 +0000
committerchristos <christos@NetBSD.org>2002-12-06 00:02:59 +0000
commitef042d8e23f2ca0c9024cffece459b250e96a1ab (patch)
tree67acb3bc1bc0c9fa126480d9c95557ced0ccb593 /sys/compat/linux
parentc363ae66f11426d14edb1779a46555a167825300 (diff)
add a linux_rt_sigframe to support SA_SIGINFO, and use it when SA_SIGINFO
is requested. This appears to be how linuxthreads decides which signal handler to use.
Diffstat (limited to 'sys/compat/linux')
-rw-r--r--sys/compat/linux/arch/i386/linux_machdep.c195
-rw-r--r--sys/compat/linux/arch/i386/linux_machdep.h49
2 files changed, 196 insertions, 48 deletions
diff --git a/sys/compat/linux/arch/i386/linux_machdep.c b/sys/compat/linux/arch/i386/linux_machdep.c
index d4dd5de2b52..f4be0a8e52d 100644
--- a/sys/compat/linux/arch/i386/linux_machdep.c
+++ b/sys/compat/linux/arch/i386/linux_machdep.c
@@ -1,4 +1,4 @@
-/* $NetBSD: linux_machdep.c,v 1.82 2002/11/26 18:42:38 christos Exp $ */
+/* $NetBSD: linux_machdep.c,v 1.83 2002/12/06 00:02:59 christos Exp $ */
/*-
* Copyright (c) 1995, 2000 The NetBSD Foundation, Inc.
@@ -37,7 +37,7 @@
*/
#include <sys/cdefs.h>
-__KERNEL_RCSID(0, "$NetBSD: linux_machdep.c,v 1.82 2002/11/26 18:42:38 christos Exp $");
+__KERNEL_RCSID(0, "$NetBSD: linux_machdep.c,v 1.83 2002/12/06 00:02:59 christos Exp $");
#if defined(_KERNEL_OPT)
#include "opt_vm86.h"
@@ -119,7 +119,12 @@ int linux_write_ldt __P((struct proc *, struct linux_sys_modify_ldt_args *,
static struct biosdisk_info *fd2biosinfo __P((struct proc *, struct file *));
extern struct disklist *i386_alldisks;
+static void linux_savecontext __P((struct proc *, struct trapframe *,
+ sigset_t *, struct linux_sigcontext *));
+static void linux_rt_sendsig __P((int, sigset_t *, u_long));
+static void linux_old_sendsig __P((int, sigset_t *, u_long));
+extern char linux_sigcode[], linux_rt_sigcode[];
/*
* Deal with some i386-specific things in the Linux emulation code.
*/
@@ -187,9 +192,70 @@ linux_sendsig(sig, mask, code)
sigset_t *mask;
u_long code;
{
+ if (SIGACTION(curproc, sig).sa_flags & SA_SIGINFO)
+ linux_rt_sendsig(sig, mask, code);
+ else
+ linux_old_sendsig(sig, mask, code);
+}
+
+
+static void
+linux_savecontext(p, tf, mask, sc)
+ struct proc *p;
+ struct trapframe *tf;
+ sigset_t *mask;
+ struct linux_sigcontext *sc;
+{
+ /* Save register context. */
+#ifdef VM86
+ if (tf->tf_eflags & PSL_VM) {
+ sc->sc_gs = tf->tf_vm86_gs;
+ sc->sc_fs = tf->tf_vm86_fs;
+ sc->sc_es = tf->tf_vm86_es;
+ sc->sc_ds = tf->tf_vm86_ds;
+ sc->sc_eflags = get_vflags(p);
+ } else
+#endif
+ {
+ sc->sc_gs = tf->tf_gs;
+ sc->sc_fs = tf->tf_fs;
+ sc->sc_es = tf->tf_es;
+ sc->sc_ds = tf->tf_ds;
+ sc->sc_eflags = tf->tf_eflags;
+ }
+ sc->sc_edi = tf->tf_edi;
+ sc->sc_esi = tf->tf_esi;
+ sc->sc_esp = tf->tf_esp;
+ sc->sc_ebp = tf->tf_ebp;
+ sc->sc_ebx = tf->tf_ebx;
+ sc->sc_edx = tf->tf_edx;
+ sc->sc_ecx = tf->tf_ecx;
+ sc->sc_eax = tf->tf_eax;
+ sc->sc_eip = tf->tf_eip;
+ sc->sc_cs = tf->tf_cs;
+ sc->sc_esp_at_signal = tf->tf_esp;
+ sc->sc_ss = tf->tf_ss;
+ sc->sc_err = tf->tf_err;
+ sc->sc_trapno = tf->tf_trapno;
+ sc->sc_cr2 = p->p_addr->u_pcb.pcb_cr2;
+ sc->sc_387 = NULL;
+
+ /* Save signal stack. */
+ /* Linux doesn't save the onstack flag in sigframe */
+
+ /* Save signal mask. */
+ native_to_linux_old_sigset(&sc->sc_mask, mask);
+}
+
+static void
+linux_rt_sendsig(sig, mask, code)
+ int sig;
+ sigset_t *mask;
+ u_long code;
+{
struct proc *p = curproc;
struct trapframe *tf;
- struct linux_sigframe *fp, frame;
+ struct linux_rt_sigframe *fp, frame;
int onstack;
sig_t catcher = SIGACTION(p, sig).sa_handler;
struct sigaltstack *sas = &p->p_sigctx.ps_sigstk;
@@ -200,61 +266,95 @@ linux_sendsig(sig, mask, code)
onstack = (sas->ss_flags & (SS_DISABLE | SS_ONSTACK)) == 0 &&
(SIGACTION(p, sig).sa_flags & SA_ONSTACK) != 0;
+
/* Allocate space for the signal handler context. */
if (onstack)
- fp = (struct linux_sigframe *) ((caddr_t)sas->ss_sp +
- sas->ss_size);
+ fp = (struct linux_rt_sigframe *)((caddr_t)sas->ss_sp +
+ sas->ss_size);
else
- fp = (struct linux_sigframe *)tf->tf_esp;
+ fp = (struct linux_rt_sigframe *)tf->tf_esp;
fp--;
+ DPRINTF(("rt: onstack = %d, fp = %p sig = %d eip = 0x%x\n", onstack, fp,
+ sig, tf->tf_eip));
+
/* Build stack frame for signal trampoline. */
frame.sf_handler = catcher;
frame.sf_sig = native_to_linux_signo[sig];
frame.sf_sip = &fp->sf_si;
frame.sf_scp = &fp->sf_sc;
+
/*
* XXX: zero siginfo out until we provide more info.
*/
(void)memset(&frame.sf_si, 0, sizeof(frame.sf_si));
/* Save register context. */
-#ifdef VM86
- if (tf->tf_eflags & PSL_VM) {
- frame.sf_sc.sc_gs = tf->tf_vm86_gs;
- frame.sf_sc.sc_fs = tf->tf_vm86_fs;
- frame.sf_sc.sc_es = tf->tf_vm86_es;
- frame.sf_sc.sc_ds = tf->tf_vm86_ds;
- frame.sf_sc.sc_eflags = get_vflags(p);
- } else
-#endif
- {
- frame.sf_sc.sc_gs = tf->tf_gs;
- frame.sf_sc.sc_fs = tf->tf_fs;
- frame.sf_sc.sc_es = tf->tf_es;
- frame.sf_sc.sc_ds = tf->tf_ds;
- frame.sf_sc.sc_eflags = tf->tf_eflags;
+ linux_savecontext(p, tf, mask, &frame.sf_sc);
+
+ if (copyout(&frame, fp, sizeof(frame)) != 0) {
+ /*
+ * Process has trashed its stack; give it an illegal
+ * instruction to halt it in its tracks.
+ */
+ sigexit(p, SIGILL);
+ /* NOTREACHED */
}
- frame.sf_sc.sc_edi = tf->tf_edi;
- frame.sf_sc.sc_esi = tf->tf_esi;
- frame.sf_sc.sc_ebp = tf->tf_ebp;
- frame.sf_sc.sc_ebx = tf->tf_ebx;
- frame.sf_sc.sc_edx = tf->tf_edx;
- frame.sf_sc.sc_ecx = tf->tf_ecx;
- frame.sf_sc.sc_eax = tf->tf_eax;
- frame.sf_sc.sc_eip = tf->tf_eip;
- frame.sf_sc.sc_cs = tf->tf_cs;
- frame.sf_sc.sc_esp_at_signal = tf->tf_esp;
- frame.sf_sc.sc_ss = tf->tf_ss;
- frame.sf_sc.sc_err = tf->tf_err;
- frame.sf_sc.sc_trapno = tf->tf_trapno;
- frame.sf_sc.sc_cr2 = p->p_addr->u_pcb.pcb_cr2;
- /* Save signal stack. */
- /* Linux doesn't save the onstack flag in sigframe */
+ /*
+ * Build context to run handler in.
+ */
+ tf->tf_gs = GSEL(GUDATA_SEL, SEL_UPL);
+ tf->tf_fs = GSEL(GUDATA_SEL, SEL_UPL);
+ tf->tf_es = GSEL(GUDATA_SEL, SEL_UPL);
+ tf->tf_ds = GSEL(GUDATA_SEL, SEL_UPL);
+ tf->tf_eip = ((int)p->p_sigctx.ps_sigcode) +
+ (linux_rt_sigcode - linux_sigcode);
+ tf->tf_cs = GSEL(GUCODE_SEL, SEL_UPL);
+ tf->tf_eflags &= ~(PSL_T|PSL_VM|PSL_AC);
+ tf->tf_esp = (int)fp;
+ tf->tf_ss = GSEL(GUDATA_SEL, SEL_UPL);
- /* Save signal mask. */
- native_to_linux_old_sigset(&frame.sf_sc.sc_mask, mask);
+ /* Remember that we're now on the signal stack. */
+ if (onstack)
+ sas->ss_flags |= SS_ONSTACK;
+}
+
+static void
+linux_old_sendsig(sig, mask, code)
+ int sig;
+ sigset_t *mask;
+ u_long code;
+{
+ struct proc *p = curproc;
+ struct trapframe *tf;
+ struct linux_sigframe *fp, frame;
+ int onstack;
+ sig_t catcher = SIGACTION(p, sig).sa_handler;
+ struct sigaltstack *sas = &p->p_sigctx.ps_sigstk;
+
+ tf = p->p_md.md_regs;
+
+ /* Do we need to jump onto the signal stack? */
+ onstack = (sas->ss_flags & (SS_DISABLE | SS_ONSTACK)) == 0 &&
+ (SIGACTION(p, sig).sa_flags & SA_ONSTACK) != 0;
+
+ /* Allocate space for the signal handler context. */
+ if (onstack)
+ fp = (struct linux_sigframe *) ((caddr_t)sas->ss_sp +
+ sas->ss_size);
+ else
+ fp = (struct linux_sigframe *)tf->tf_esp;
+ fp--;
+
+ DPRINTF((uprintf("old: onstack = %d, fp = %p sig = %d eip = 0x%x\n",
+ onstack, fp, sig, tf->tf_eip));
+
+ /* Build stack frame for signal trampoline. */
+ frame.sf_handler = catcher;
+ frame.sf_sig = native_to_linux_signo[sig];
+
+ linux_savecontext(p, tf, mask, &frame.sf_sc);
if (copyout(&frame, fp, sizeof(frame)) != 0) {
/*
@@ -325,17 +425,22 @@ linux_sys_sigreturn(p, v, retval)
*/
scp = SCARG(uap, scp);
if (copyin((caddr_t)scp, &context, sizeof(*scp)) != 0)
- return (EFAULT);
+ return EFAULT;
/* Restore register context. */
tf = p->p_md.md_regs;
+
+ DPRINTF(("sigreturn enter esp=%x eip=%x\n", tf->tf_esp, tf->tf_eip));
#ifdef VM86
if (context.sc_eflags & PSL_VM) {
+ void syscall_vm86 __P((struct trapframe));
+
tf->tf_vm86_gs = context.sc_gs;
tf->tf_vm86_fs = context.sc_fs;
tf->tf_vm86_es = context.sc_es;
tf->tf_vm86_ds = context.sc_ds;
set_vflags(p, context.sc_eflags);
+ p->p_md.md_syscall = syscall_vm86;
} else
#endif
{
@@ -347,12 +452,16 @@ linux_sys_sigreturn(p, v, retval)
*/
if (((context.sc_eflags ^ tf->tf_eflags) & PSL_USERSTATIC) != 0 ||
!USERMODE(context.sc_cs, context.sc_eflags))
- return (EINVAL);
+ return EINVAL;
tf->tf_gs = context.sc_gs;
tf->tf_fs = context.sc_fs;
tf->tf_es = context.sc_es;
tf->tf_ds = context.sc_ds;
+#ifdef VM86
+ if (tf->tf_eflags & PSL_VM)
+ (*p->p_emul->e_syscall_intern)(p);
+#endif
tf->tf_eflags = context.sc_eflags;
}
tf->tf_edi = context.sc_edi;
@@ -382,8 +491,8 @@ linux_sys_sigreturn(p, v, retval)
/* Restore signal mask. */
linux_old_to_native_sigset(&mask, &context.sc_mask);
(void) sigprocmask1(p, SIG_SETMASK, &mask, 0);
-
- return (EJUSTRETURN);
+ DPRINTF(("sigreturn exit esp=%x eip=%x\n", tf->tf_esp, tf->tf_eip));
+ return EJUSTRETURN;
}
#ifdef USER_LDT
diff --git a/sys/compat/linux/arch/i386/linux_machdep.h b/sys/compat/linux/arch/i386/linux_machdep.h
index f79422bad21..2264ad6d0e1 100644
--- a/sys/compat/linux/arch/i386/linux_machdep.h
+++ b/sys/compat/linux/arch/i386/linux_machdep.h
@@ -1,4 +1,4 @@
-/* $NetBSD: linux_machdep.h,v 1.24 2002/11/26 18:42:38 christos Exp $ */
+/* $NetBSD: linux_machdep.h,v 1.25 2002/12/06 00:02:59 christos Exp $ */
/*-
* Copyright (c) 1995, 2000 The NetBSD Foundation, Inc.
@@ -46,6 +46,40 @@
/*
* The Linux sigcontext, pretty much a standard 386 trapframe.
*/
+struct linux_fpreg {
+ uint16_t mant[4];
+ uint16_t expo;
+};
+
+struct linux_fpxreg {
+ uint16_t mant[4];
+ uint16_t expo;
+ uint16_t pad[3];
+};
+
+struct linux_xmmreg {
+ uint32_t reg[4];
+};
+
+struct linux_fpstate {
+ uint32_t cw;
+ uint32_t sw;
+ uint32_t tag;
+ uint32_t ipoff;
+ uint32_t cssel;
+ uint32_t dataoff;
+ uint32_t datasel;
+ struct linux_fpreg st[8];
+ uint16_t status;
+ uint16_t magic;
+ uint32_t fxsr_env[6];
+ uint32_t mxcsr;
+ uint32_t reserved;
+ struct linux_fpxreg fxsr_st[8];
+ struct linux_xmmreg xmm[8];
+ uint32_t padding[56];
+};
+
struct linux_sigcontext {
int sc_gs;
@@ -67,7 +101,7 @@ struct linux_sigcontext {
int sc_eflags;
int sc_esp_at_signal;
int sc_ss;
- int sc_387;
+ struct linux_fpstate *sc_387;
/* XXX check this */
linux_old_sigset_t sc_mask;
int sc_cr2;
@@ -79,14 +113,19 @@ struct linux_sigcontext {
* This means that we need to pass the pointer to the handler too.
* It is appended to the frame to not interfere with the rest of it.
*/
-
-struct linux_sigframe {
+struct linux_rt_sigframe {
int sf_sig;
struct linux_siginfo *sf_sip;
struct linux_sigcontext *sf_scp;
- sig_t sf_handler;
struct linux_siginfo sf_si;
struct linux_sigcontext sf_sc;
+ sig_t sf_handler;
+};
+
+struct linux_sigframe {
+ int sf_sig;
+ struct linux_sigcontext sf_sc;
+ sig_t sf_handler;
};
#ifdef _KERNEL