From 431d0feffbaa4f5e66b1f9646d2bb780a99daf3f Mon Sep 17 00:00:00 2001 From: Matthew Dillon Date: Tue, 9 Jan 2007 23:34:06 +0000 Subject: [PATCH] Get floating point working in virtual kernels. Add a feature that allows the virtual kernel to request that the real kernel return a T_DNA fault if an emulated user context attempts to use the FP unit. --- sys/cpu/i386/include/npx.h | 5 +-- sys/cpu/i386/include/pmap.h | 15 +++++-- sys/cpu/i386/include/vframe.h | 9 +--- sys/platform/pc32/i386/bcopy.s | 5 ++- sys/platform/pc32/i386/trap.c | 43 +++++++++++++++++- sys/platform/pc32/include/md_var.h | 3 +- sys/platform/pc32/include/pcb.h | 3 +- sys/platform/pc32/isa/npx.c | 9 +--- sys/platform/vkernel/i386/npx.c | 16 +++---- sys/platform/vkernel/i386/trap.c | 60 ++++++++++++++++++++++++-- sys/platform/vkernel/i386/vm_machdep.c | 4 +- sys/platform/vkernel/include/md_var.h | 3 +- sys/platform/vkernel/include/pcb.h | 5 ++- sys/sys/systm.h | 3 +- sys/vm/vm_vmspace.c | 3 +- 15 files changed, 140 insertions(+), 46 deletions(-) diff --git a/sys/cpu/i386/include/npx.h b/sys/cpu/i386/include/npx.h index c7adee5bca..afbff239bd 100644 --- a/sys/cpu/i386/include/npx.h +++ b/sys/cpu/i386/include/npx.h @@ -35,7 +35,7 @@ * * from: @(#)npx.h 5.3 (Berkeley) 1/18/91 * $FreeBSD: src/sys/i386/include/npx.h,v 1.18.2.1 2001/08/15 01:23:52 peter Exp $ - * $DragonFly: src/sys/cpu/i386/include/npx.h,v 1.11 2007/01/08 03:33:37 dillon Exp $ + * $DragonFly: src/sys/cpu/i386/include/npx.h,v 1.12 2007/01/09 23:34:01 dillon Exp $ */ /* @@ -151,12 +151,11 @@ union savefpu { #ifdef _KERNEL struct proc; +struct trapframe; -int npxdna (void); void npxexit (void); void npxinit (u_short control); void npxsave (union savefpu *addr); -void npxsync (void); #endif #endif /* !_CPU_NPX_H_ */ diff --git a/sys/cpu/i386/include/pmap.h b/sys/cpu/i386/include/pmap.h index 796adc6633..0a0fb5d308 100644 --- a/sys/cpu/i386/include/pmap.h +++ b/sys/cpu/i386/include/pmap.h @@ -43,7 +43,7 @@ * from: hp300: @(#)pmap.h 7.2 (Berkeley) 12/16/90 * from: @(#)pmap.h 7.4 (Berkeley) 5/12/91 * $FreeBSD: src/sys/i386/include/pmap.h,v 1.65.2.3 2001/10/03 07:15:37 peter Exp $ - * $DragonFly: src/sys/cpu/i386/include/pmap.h,v 1.12 2006/11/07 06:43:22 dillon Exp $ + * $DragonFly: src/sys/cpu/i386/include/pmap.h,v 1.13 2007/01/09 23:34:01 dillon Exp $ */ #ifndef _CPU_PMAP_H_ @@ -76,11 +76,20 @@ #define PG_N (PG_NC_PWT|PG_NC_PCD) /* Non-cacheable */ /* - * Page Protection Exception bits + * Page Protection Exception bits, stored in tf_err on a real fault + * and in tf_xflags on a signal frame or virtual kernel's trap frame. + * These only apply to T_PAGEFLT faults. */ - #define PGEX_P 0x01 /* Protection violation vs. not present */ #define PGEX_W 0x02 /* during a Write cycle */ #define PGEX_U 0x04 /* access from User mode (UPL) */ +/* + * Virtual kernel bits, managed by software. + * + * FPEX_FAULT - Force the FP unit to generate a T_DNA fault if an emulated + * user process tried to use it. + */ +#define FPEX_FAULT 0x80 + #endif /* !_CPU_PMAP_H_ */ diff --git a/sys/cpu/i386/include/vframe.h b/sys/cpu/i386/include/vframe.h index f7ea20da52..ab1646204d 100644 --- a/sys/cpu/i386/include/vframe.h +++ b/sys/cpu/i386/include/vframe.h @@ -31,7 +31,7 @@ * OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF * SUCH DAMAGE. * - * $DragonFly: src/sys/cpu/i386/include/vframe.h,v 1.1 2007/01/08 16:34:10 dillon Exp $ + * $DragonFly: src/sys/cpu/i386/include/vframe.h,v 1.2 2007/01/09 23:34:01 dillon Exp $ */ #ifndef _CPU_VFRAME_H_ @@ -49,15 +49,8 @@ * addition to trapframe. */ struct vextframe { - int vx_features; /* enabled features */ - int vx_changes; /* changes made on control transfer */ - union savefpu vx_fpu; struct savetls vx_tls; }; -#define VXF_FP87 0x0001 -#define VXF_XMM 0x0002 -#define VXF_TLS 0x0004 - #endif diff --git a/sys/platform/pc32/i386/bcopy.s b/sys/platform/pc32/i386/bcopy.s index 3cdd48bbe1..7ba6a90a4d 100644 --- a/sys/platform/pc32/i386/bcopy.s +++ b/sys/platform/pc32/i386/bcopy.s @@ -31,7 +31,7 @@ * OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF * SUCH DAMAGE. * - * $DragonFly: src/sys/platform/pc32/i386/bcopy.s,v 1.8 2006/06/10 18:07:05 dillon Exp $ + * $DragonFly: src/sys/platform/pc32/i386/bcopy.s,v 1.9 2007/01/09 23:34:02 dillon Exp $ */ /* * bcopy(source:%esi, target:%edi, count:%ecx) @@ -337,6 +337,9 @@ ENTRY(asm_generic_bcopy) * critical section, because TS may get set by a preemptive * interrupt. However, we *can* race a load/set-ts/store against * an interrupt doing the same thing. + * + * WARNING! A Virtual kernel depends on CR0_TS remaining set after + * we use the FP unit if it asked it to be set. */ #define MMX_RESTORE_BLOCK \ diff --git a/sys/platform/pc32/i386/trap.c b/sys/platform/pc32/i386/trap.c index 52dfb64b37..a5be1fc928 100644 --- a/sys/platform/pc32/i386/trap.c +++ b/sys/platform/pc32/i386/trap.c @@ -36,7 +36,7 @@ * * from: @(#)trap.c 7.4 (Berkeley) 5/13/91 * $FreeBSD: src/sys/i386/i386/trap.c,v 1.147.2.11 2003/02/27 19:09:59 luoqi Exp $ - * $DragonFly: src/sys/platform/pc32/i386/trap.c,v 1.93 2007/01/09 07:03:32 dillon Exp $ + * $DragonFly: src/sys/platform/pc32/i386/trap.c,v 1.94 2007/01/09 23:34:02 dillon Exp $ */ /* @@ -87,6 +87,7 @@ #include #include #include +#include #include #include @@ -610,6 +611,24 @@ restart: break; case T_DNA: + /* + * Virtual kernel intercept - pass the DNA exception + * to the virtual kernel if it asked to handle it. + * This occurs when the virtual kernel is holding + * onto the FP context for a different emulated + * process then the one currently running. + * + * We must still call npxdna() since we may have + * saved FP state that the virtual kernel needs + * to hand over to a different emulated process. + */ + if (p->p_vkernel && p->p_vkernel->vk_current && + (td->td_pcb->pcb_flags & FP_VIRTFP) + ) { + npxdna(); + break; + } + #if NNPX > 0 /* * The kernel may have switched out the FP unit's @@ -1437,3 +1456,25 @@ fork_return(struct lwp *lp, struct trapframe frame) rel_mplock(); #endif } + +/* + * If FPEX_FAULT is set then set FP_VIRTFP in the PCB to force a T_DNA + * fault (which is then passed back to the virtual kernel) if an attempt is + * made to use the FP unit. + * + * XXX this is a fairly big hack. + */ +void +set_vkernel_fp(struct trapframe *frame) +{ + struct thread *td = curthread; + + if (frame->tf_xflags & FPEX_FAULT) { + td->td_pcb->pcb_flags |= FP_VIRTFP; + if (mdcpu->gd_npxthread == td) + npxexit(); + } else { + td->td_pcb->pcb_flags &= ~FP_VIRTFP; + } +} + diff --git a/sys/platform/pc32/include/md_var.h b/sys/platform/pc32/include/md_var.h index 0417f33bc6..bef1113405 100644 --- a/sys/platform/pc32/include/md_var.h +++ b/sys/platform/pc32/include/md_var.h @@ -27,7 +27,7 @@ * SUCH DAMAGE. * * $FreeBSD: src/sys/i386/include/md_var.h,v 1.35.2.4 2003/01/22 20:14:53 jhb Exp $ - * $DragonFly: src/sys/platform/pc32/include/md_var.h,v 1.24 2007/01/08 03:33:42 dillon Exp $ + * $DragonFly: src/sys/platform/pc32/include/md_var.h,v 1.25 2007/01/09 23:34:03 dillon Exp $ */ #ifndef _MACHINE_MD_VAR_H_ @@ -112,5 +112,6 @@ void setidt (int idx, alias_for_inthand_t *func, int typ, int dpl, int selec); void userconfig (void); int user_dbreg_trap (void); +int npxdna(void); #endif /* !_MACHINE_MD_VAR_H_ */ diff --git a/sys/platform/pc32/include/pcb.h b/sys/platform/pc32/include/pcb.h index 3e401807da..c0aabf1d07 100644 --- a/sys/platform/pc32/include/pcb.h +++ b/sys/platform/pc32/include/pcb.h @@ -35,7 +35,7 @@ * * from: @(#)pcb.h 5.10 (Berkeley) 5/12/91 * $FreeBSD: src/sys/i386/include/pcb.h,v 1.32.2.1 2001/08/15 01:23:52 peter Exp $ - * $DragonFly: src/sys/platform/pc32/include/pcb.h,v 1.11 2007/01/08 03:33:42 dillon Exp $ + * $DragonFly: src/sys/platform/pc32/include/pcb.h,v 1.12 2007/01/09 23:34:03 dillon Exp $ */ #ifndef _MACHINE_PCB_H_ @@ -67,6 +67,7 @@ struct pcb { u_char pcb_flags; #define FP_SOFTFP 0x01 /* process using software fltng pnt emulator */ #define PCB_DBREGS 0x02 /* process using debug registers */ +#define FP_VIRTFP 0x04 /* virtual kernel wants exception */ caddr_t pcb_onfault; /* copyin/out fault recovery */ int pcb_unused; struct pcb_ext *pcb_ext; /* optional pcb extension */ diff --git a/sys/platform/pc32/isa/npx.c b/sys/platform/pc32/isa/npx.c index b2482cd837..5d534f48e3 100644 --- a/sys/platform/pc32/isa/npx.c +++ b/sys/platform/pc32/isa/npx.c @@ -33,7 +33,7 @@ * * from: @(#)npx.c 7.2 (Berkeley) 5/12/91 * $FreeBSD: src/sys/i386/isa/npx.c,v 1.80.2.3 2001/10/20 19:04:38 tegge Exp $ - * $DragonFly: src/sys/platform/pc32/isa/npx.c,v 1.39 2007/01/08 03:33:43 dillon Exp $ + * $DragonFly: src/sys/platform/pc32/isa/npx.c,v 1.40 2007/01/09 23:34:04 dillon Exp $ */ #include "opt_cpu.h" @@ -975,13 +975,6 @@ fpusave(union savefpu *addr) fnsave(addr); } -void -npxsync(void) -{ - if (curthread == mdcpu->gd_npxthread) - npxsave(curthread->td_savefpu); -} - #ifndef CPU_DISABLE_SSE /* * On AuthenticAMD processors, the fxrstor instruction does not restore diff --git a/sys/platform/vkernel/i386/npx.c b/sys/platform/vkernel/i386/npx.c index c462d29265..5d5124fdca 100644 --- a/sys/platform/vkernel/i386/npx.c +++ b/sys/platform/vkernel/i386/npx.c @@ -36,7 +36,7 @@ * * from: @(#)npx.c 7.2 (Berkeley) 5/12/91 * $FreeBSD: src/sys/i386/isa/npx.c,v 1.80.2.3 2001/10/20 19:04:38 tegge Exp $ - * $DragonFly: src/sys/platform/vkernel/i386/npx.c,v 1.3 2007/01/08 03:33:43 dillon Exp $ + * $DragonFly: src/sys/platform/vkernel/i386/npx.c,v 1.4 2007/01/09 23:34:05 dillon Exp $ */ #include "opt_debug_npx.h" @@ -102,7 +102,6 @@ static void fpu_clean_state(void); int cpu_fxsr = 0; static int npx_attach (device_t dev); - void npx_intr (void *); static void fpusave (union savefpu *); static void fpurstor (union savefpu *); @@ -326,6 +325,8 @@ static char fpetable[128] = { FPE_FLTSUB, /* 7F - INV | DNML | DZ | OFL | UFL | IMP | STK */ }; +#if 0 + /* * Preserve the FP status word, clear FP exceptions, then generate a SIGFPE. * @@ -441,6 +442,8 @@ npx_intr(void *dummy) crit_exit(); } +#endif + /* * Implement the device not available (DNA) exception. gd_npxthread had * better be NULL. Restore the current thread's FP state and set gd_npxthread @@ -450,7 +453,7 @@ npx_intr(void *dummy) * section to stabilize the FP state. */ int -npxdna(void) +npxdna(struct trapframe *frame) { u_long *exstat; @@ -533,13 +536,6 @@ fpusave(union savefpu *addr) fnsave(addr); } -void -npxsync(void) -{ - if (curthread == mdcpu->gd_npxthread) - npxsave(curthread->td_savefpu); -} - #ifndef CPU_DISABLE_SSE /* * On AuthenticAMD processors, the fxrstor instruction does not restore diff --git a/sys/platform/vkernel/i386/trap.c b/sys/platform/vkernel/i386/trap.c index e998226e66..649ac6c504 100644 --- a/sys/platform/vkernel/i386/trap.c +++ b/sys/platform/vkernel/i386/trap.c @@ -36,7 +36,7 @@ * * from: @(#)trap.c 7.4 (Berkeley) 5/13/91 * $FreeBSD: src/sys/i386/i386/trap.c,v 1.147.2.11 2003/02/27 19:09:59 luoqi Exp $ - * $DragonFly: src/sys/platform/vkernel/i386/trap.c,v 1.7 2007/01/09 07:23:02 dillon Exp $ + * $DragonFly: src/sys/platform/vkernel/i386/trap.c,v 1.8 2007/01/09 23:34:05 dillon Exp $ */ /* @@ -533,6 +533,23 @@ restart: break; case T_DNA: + /* + * Virtual kernel intercept - pass the DNA exception + * to the (emulated) virtual kernel if it asked to handle + * it. This occurs when the virtual kernel is holding + * onto the FP context for a different emulated + * process then the one currently running. + * + * We must still call npxdna() since we may have + * saved FP state that the (emulated) virtual kernel + * needs to hand over to a different emulated process. + */ + if (p->p_vkernel && p->p_vkernel->vk_current && + (td->td_pcb->pcb_flags & FP_VIRTFP) + ) { + npxdna(frame); + break; + } #if NNPX > 0 /* * The kernel may have switched out the FP unit's @@ -540,7 +557,7 @@ restart: * when it tries to use the FP unit. Restore the * state here */ - if (npxdna()) + if (npxdna(frame)) goto out; #endif if (!pmath_emulate) { @@ -677,7 +694,8 @@ kernel_trap: * The kernel may be using npx for copying or other * purposes. */ - if (npxdna()) + panic("kernel NPX should not happen"); + if (npxdna(frame)) goto out2; #endif break; @@ -1391,6 +1409,20 @@ go_user(struct trapframe frame) &curproc->p_vmspace->vm_pmap, curproc->p_pid, curproc->p_comm, sigblock(0)); #endif + + /* + * Tell the real kernel whether it is ok to use the FP + * unit or not. + */ + if (mdcpu->gd_npxthread == curthread) { + frame.tf_xflags &= ~FPEX_FAULT; + } else { + frame.tf_xflags |= FPEX_FAULT; + } + + /* + * Run emulated user process context + */ r = vmspace_ctl(&curproc->p_vmspace->vm_pmap, VMSPACE_CTL_RUN, &frame, &curthread->td_savevext); if (r < 0) @@ -1415,3 +1447,25 @@ go_user(struct trapframe frame) } } +/* + * If FPEX_FAULT is set then set FP_VIRTFP in the PCB to force a T_DNA + * fault (which is then passed back to the virtual kernel) if an attempt is + * made to use the FP unit. + * + * XXX this is a fairly big hack. + */ +void +set_vkernel_fp(struct trapframe *frame) +{ + struct thread *td = curthread; + + panic("set_vkernel_fp: vkernel-within-vkernel not yet supported"); + if (frame->tf_xflags & FPEX_FAULT) { + td->td_pcb->pcb_flags |= FP_VIRTFP; + if (mdcpu->gd_npxthread == td) + npxexit(); + } else { + td->td_pcb->pcb_flags &= ~FP_VIRTFP; + } +} + diff --git a/sys/platform/vkernel/i386/vm_machdep.c b/sys/platform/vkernel/i386/vm_machdep.c index 1e2a08abe0..977a3ec2d4 100644 --- a/sys/platform/vkernel/i386/vm_machdep.c +++ b/sys/platform/vkernel/i386/vm_machdep.c @@ -39,7 +39,7 @@ * from: @(#)vm_machdep.c 7.3 (Berkeley) 5/13/91 * Utah $Hdr: vm_machdep.c 1.16.1.1 89/06/23$ * $FreeBSD: src/sys/i386/i386/vm_machdep.c,v 1.132.2.9 2003/01/25 19:02:23 dillon Exp $ - * $DragonFly: src/sys/platform/vkernel/i386/vm_machdep.c,v 1.3 2007/01/08 03:33:43 dillon Exp $ + * $DragonFly: src/sys/platform/vkernel/i386/vm_machdep.c,v 1.4 2007/01/09 23:34:05 dillon Exp $ */ #include "use_npx.h" @@ -156,7 +156,7 @@ cpu_fork(struct lwp *lp1, struct lwp *lp2, int flags) * Set registers for trampoline to user mode. Leave space for the * return address on stack. These are the kernel mode register values. */ - pcb2->pcb_cr3 = vtophys(vmspace_pmap(lp2->lwp_proc->p_vmspace)->pm_pdir); + pcb2->pcb_unused01 = 0; pcb2->pcb_edi = 0; pcb2->pcb_esi = (int)fork_return; /* fork_trampoline argument */ pcb2->pcb_ebp = 0; diff --git a/sys/platform/vkernel/include/md_var.h b/sys/platform/vkernel/include/md_var.h index 36721c61a3..d4637ce9b7 100644 --- a/sys/platform/vkernel/include/md_var.h +++ b/sys/platform/vkernel/include/md_var.h @@ -31,7 +31,7 @@ * OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF * SUCH DAMAGE. * - * $DragonFly: src/sys/platform/vkernel/include/md_var.h,v 1.10 2007/01/09 00:20:19 dillon Exp $ + * $DragonFly: src/sys/platform/vkernel/include/md_var.h,v 1.11 2007/01/09 23:34:05 dillon Exp $ */ #ifndef _MACHINE_MD_VAR_H_ @@ -77,6 +77,7 @@ void kern_trap(struct trapframe *); void user_trap(struct trapframe *); void syscall2 (struct trapframe *); void vcons_set_mode(int); +int npxdna(struct trapframe *); #endif diff --git a/sys/platform/vkernel/include/pcb.h b/sys/platform/vkernel/include/pcb.h index d4939a2f37..48e64a56f4 100644 --- a/sys/platform/vkernel/include/pcb.h +++ b/sys/platform/vkernel/include/pcb.h @@ -35,7 +35,7 @@ * * from: @(#)pcb.h 5.10 (Berkeley) 5/12/91 * $FreeBSD: src/sys/i386/include/pcb.h,v 1.32.2.1 2001/08/15 01:23:52 peter Exp $ - * $DragonFly: src/sys/platform/vkernel/include/pcb.h,v 1.2 2007/01/08 03:33:43 dillon Exp $ + * $DragonFly: src/sys/platform/vkernel/include/pcb.h,v 1.3 2007/01/09 23:34:05 dillon Exp $ */ #ifndef _MACHINE_PCB_H_ @@ -47,7 +47,7 @@ #include struct pcb { - int pcb_cr3; + int pcb_unused01; int pcb_edi; int pcb_esi; int pcb_ebp; @@ -67,6 +67,7 @@ struct pcb { u_char pcb_flags; #define FP_SOFTFP 0x01 /* process using software fltng pnt emulator */ #define PCB_DBREGS 0x02 /* process using debug registers */ +#define FP_VIRTFP 0x04 /* virtual kernel wants exception */ caddr_t pcb_onfault; /* copyin/out fault recovery */ int pcb_unused; struct pcb_ext *pcb_ext; /* optional pcb extension */ diff --git a/sys/sys/systm.h b/sys/sys/systm.h index 59d4738047..337861ed0f 100644 --- a/sys/sys/systm.h +++ b/sys/sys/systm.h @@ -37,7 +37,7 @@ * * @(#)systm.h 8.7 (Berkeley) 3/29/95 * $FreeBSD: src/sys/sys/systm.h,v 1.111.2.18 2002/12/17 18:04:02 sam Exp $ - * $DragonFly: src/sys/sys/systm.h,v 1.60 2007/01/08 03:33:43 dillon Exp $ + * $DragonFly: src/sys/sys/systm.h,v 1.61 2007/01/09 23:34:05 dillon Exp $ */ #ifndef _SYS_SYSTM_H_ @@ -148,6 +148,7 @@ void cpu_rootconf (void); void cpu_vmspace_alloc(struct vmspace *); void cpu_vmspace_free(struct vmspace *); void set_user_TLS(void); +void set_vkernel_fp(struct trapframe *); vm_paddr_t kvtop(void *addr); int is_physical_memory (vm_offset_t addr); diff --git a/sys/vm/vm_vmspace.c b/sys/vm/vm_vmspace.c index b89f03a2ec..acd321c3c1 100644 --- a/sys/vm/vm_vmspace.c +++ b/sys/vm/vm_vmspace.c @@ -31,7 +31,7 @@ * OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF * SUCH DAMAGE. * - * $DragonFly: src/sys/vm/vm_vmspace.c,v 1.8 2007/01/08 03:33:43 dillon Exp $ + * $DragonFly: src/sys/vm/vm_vmspace.c,v 1.9 2007/01/09 23:34:06 dillon Exp $ */ #include "opt_ddb.h" @@ -194,6 +194,7 @@ sys_vmspace_ctl(struct vmspace_ctl_args *uap) p->p_vmspace = ve->vmspace; pmap_activate(p); set_user_TLS(); + set_vkernel_fp(uap->sysmsg_frame); error = EJUSTRETURN; } break; -- 2.41.0