diff options
| author | christos <christos@NetBSD.org> | 2002-12-06 00:02:59 +0000 |
|---|---|---|
| committer | christos <christos@NetBSD.org> | 2002-12-06 00:02:59 +0000 |
| commit | ef042d8e23f2ca0c9024cffece459b250e96a1ab (patch) | |
| tree | 67acb3bc1bc0c9fa126480d9c95557ced0ccb593 /sys/compat/linux | |
| parent | c363ae66f11426d14edb1779a46555a167825300 (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.c | 195 | ||||
| -rw-r--r-- | sys/compat/linux/arch/i386/linux_machdep.h | 49 |
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 |
