Change i386 to use x86/fpu.c instead of i386/isa/npx.c trunk
authordsl <dsl@NetBSD.org>
Wed, 12 Feb 2014 23:24:09 +0000
branchtrunk
changeset 224530 75d5da5d2e86
parent 224529 a8622b1650b0
child 224531 f77d89987307
Change i386 to use x86/fpu.c instead of i386/isa/npx.c This changes the trap10 and trap13 code to call directly into fpu.c, removing all the code for T_ARITHTRAP, T_XMM and T_FPUNDA from i386/trap.c Not all of the code thate appeared to handle fpu traps was ever called! Most of the changes just replace the include of machine/npx.h with x86/fpu.h (or remove it entirely).
distrib/sets/lists/comp/md.i386
sys/arch/amd64/amd64/cpufunc.S
sys/arch/i386/conf/files.i386
sys/arch/i386/i386/autoconf.c
sys/arch/i386/i386/cpufunc.S
sys/arch/i386/i386/freebsd_machdep.c
sys/arch/i386/i386/i386_trap.S
sys/arch/i386/i386/ibcs2_machdep.c
sys/arch/i386/i386/trap.c
sys/arch/i386/include/Makefile
sys/arch/i386/include/freebsd_machdep.h
sys/arch/i386/include/npx.h
sys/arch/i386/include/pcb.h
sys/arch/i386/isa/npx.c
sys/arch/x86/include/cpu.h
sys/arch/x86/include/cpu_extended_state.h
sys/arch/x86/include/cpufunc.h
sys/arch/x86/include/fpu.h
sys/arch/x86/x86/convert_xmm_s87.c
sys/arch/x86/x86/fpu.c
sys/arch/x86/x86/procfs_machdep.c
sys/arch/xen/conf/files.xen
sys/arch/xen/x86/cpu.c
sys/arch/xen/x86/xen_ipi.c
--- a/distrib/sets/lists/comp/md.i386	Wed Feb 12 23:04:43 2014 +0000
+++ b/distrib/sets/lists/comp/md.i386	Wed Feb 12 23:24:09 2014 +0000
@@ -1,4 +1,4 @@
-# $NetBSD: md.i386,v 1.144 2014/02/11 22:48:25 dsl Exp $
+# $NetBSD: md.i386,v 1.145 2014/02/12 23:24:09 dsl Exp $
 ./usr/include/clang-3.0/avx2intrin.h		comp-obsolete		obsolete
 ./usr/include/clang-3.0/avxintrin.h		comp-obsolete		obsolete
 ./usr/include/clang-3.0/bmi2intrin.h		comp-obsolete		obsolete
@@ -259,7 +259,7 @@
 ./usr/include/i386/mtrr.h			comp-c-include
 ./usr/include/i386/multiboot.h			comp-c-include
 ./usr/include/i386/mutex.h			comp-c-include
-./usr/include/i386/npx.h			comp-c-include
+./usr/include/i386/npx.h			comp-c-include		obsolete
 ./usr/include/i386/param.h			comp-c-include
 ./usr/include/i386/pcb.h			comp-c-include
 ./usr/include/i386/pccons.h			comp-obsolete		obsolete
--- a/sys/arch/amd64/amd64/cpufunc.S	Wed Feb 12 23:04:43 2014 +0000
+++ b/sys/arch/amd64/amd64/cpufunc.S	Wed Feb 12 23:24:09 2014 +0000
@@ -1,4 +1,4 @@
-/*	$NetBSD: cpufunc.S,v 1.24 2014/02/09 19:42:04 dsl Exp $	*/
+/*	$NetBSD: cpufunc.S,v 1.25 2014/02/12 23:24:09 dsl Exp $	*/
 
 /*-
  * Copyright (c) 1998, 2007, 2008 The NetBSD Foundation, Inc.
@@ -441,6 +441,10 @@
 	fnstcw	(%rdi)
 	ret
 
+ENTRY(fngetsw)
+	fnstsw	%ax
+	ret
+
 ENTRY(fnstsw)
 	fnstsw	(%rdi)
 	ret
@@ -480,7 +484,7 @@
 
 ENTRY(fldummy)
 	ffree	%st(7)
-	flds	(%rdi)
+	fldz
 	ret
 
 ENTRY(xsave)
--- a/sys/arch/i386/conf/files.i386	Wed Feb 12 23:04:43 2014 +0000
+++ b/sys/arch/i386/conf/files.i386	Wed Feb 12 23:24:09 2014 +0000
@@ -1,4 +1,4 @@
-#	$NetBSD: files.i386,v 1.373 2014/02/07 22:40:22 dsl Exp $
+#	$NetBSD: files.i386,v 1.374 2014/02/12 23:24:09 dsl Exp $
 #
 # new style config file for i386 architecture
 #
@@ -82,7 +82,7 @@
 file	arch/x86/x86/convert_xmm_s87.c
 file	arch/i386/i386/trap.c
 file	dev/cons.c
-file	arch/i386/isa/npx.c
+file	arch/x86/x86/fpu.c
 
 file	arch/i386/i386/mptramp.S	multiprocessor
 
--- a/sys/arch/i386/i386/autoconf.c	Wed Feb 12 23:04:43 2014 +0000
+++ b/sys/arch/i386/i386/autoconf.c	Wed Feb 12 23:24:09 2014 +0000
@@ -1,4 +1,4 @@
-/*	$NetBSD: autoconf.c,v 1.99 2014/01/26 19:16:17 dsl Exp $	*/
+/*	$NetBSD: autoconf.c,v 1.100 2014/02/12 23:24:09 dsl Exp $	*/
 
 /*-
  * Copyright (c) 1990 The Regents of the University of California.
@@ -46,7 +46,7 @@
  */
 
 #include <sys/cdefs.h>
-__KERNEL_RCSID(0, "$NetBSD: autoconf.c,v 1.99 2014/01/26 19:16:17 dsl Exp $");
+__KERNEL_RCSID(0, "$NetBSD: autoconf.c,v 1.100 2014/02/12 23:24:09 dsl Exp $");
 
 #include "opt_compat_oldboot.h"
 #include "opt_intrdebug.h"
@@ -64,7 +64,7 @@
 #include <machine/intr.h>
 #include <machine/pcb.h>
 #include <machine/cpufunc.h>
-#include <machine/npx.h>
+#include <x86/fpu.h>
 
 #include "ioapic.h"
 #include "lapic.h"
--- a/sys/arch/i386/i386/cpufunc.S	Wed Feb 12 23:04:43 2014 +0000
+++ b/sys/arch/i386/i386/cpufunc.S	Wed Feb 12 23:24:09 2014 +0000
@@ -1,4 +1,4 @@
-/*	$NetBSD: cpufunc.S,v 1.17 2011/09/24 21:24:52 jym Exp $	*/
+/*	$NetBSD: cpufunc.S,v 1.18 2014/02/12 23:24:09 dsl Exp $	*/
 
 /*-
  * Copyright (c) 1998, 2007 The NetBSD Foundation, Inc.
@@ -38,7 +38,7 @@
 #include <sys/errno.h>
 
 #include <machine/asm.h>
-__KERNEL_RCSID(0, "$NetBSD: cpufunc.S,v 1.17 2011/09/24 21:24:52 jym Exp $");
+__KERNEL_RCSID(0, "$NetBSD: cpufunc.S,v 1.18 2014/02/12 23:24:09 dsl Exp $");
 
 #include "opt_xen.h"
 
@@ -332,6 +332,11 @@
 	ret
 END(fnstcw)
 
+ENTRY(fngetsw)
+	fnstsw	%ax
+	ret
+END(fngetsw)
+
 ENTRY(fnstsw)
 	movl	4(%esp), %eax
 	fnstsw	(%eax)
@@ -384,10 +389,19 @@
 	ret
 END(fxrstor)
 
-ENTRY(fldummy)
+ENTRY(x86_stmxcsr)
+	movl	4(%esp), %eax
+	stmxcsr	(%eax)
+	ret
+
+ENTRY(x86_ldmxcsr)
 	movl	4(%esp), %eax
+	ldmxcsr	(%eax)
+	ret
+
+ENTRY(fldummy)
 	ffree	%st(7)
-	flds	(%eax)
+	fldz
 	ret
 END(fldummy)
 
--- a/sys/arch/i386/i386/freebsd_machdep.c	Wed Feb 12 23:04:43 2014 +0000
+++ b/sys/arch/i386/i386/freebsd_machdep.c	Wed Feb 12 23:24:09 2014 +0000
@@ -1,4 +1,4 @@
-/*	$NetBSD: freebsd_machdep.c,v 1.58 2014/01/19 14:30:37 dsl Exp $	*/
+/*	$NetBSD: freebsd_machdep.c,v 1.59 2014/02/12 23:24:09 dsl Exp $	*/
 
 /*-
  * Copyright (c) 1998, 2000 The NetBSD Foundation, Inc.
@@ -30,7 +30,7 @@
  */
 
 #include <sys/cdefs.h>
-__KERNEL_RCSID(0, "$NetBSD: freebsd_machdep.c,v 1.58 2014/01/19 14:30:37 dsl Exp $");
+__KERNEL_RCSID(0, "$NetBSD: freebsd_machdep.c,v 1.59 2014/02/12 23:24:09 dsl Exp $");
 
 #if defined(_KERNEL_OPT)
 #include "opt_vm86.h"
@@ -46,7 +46,7 @@
 #include <compat/sys/signal.h>
 
 #include <machine/cpufunc.h>
-#include <machine/npx.h>
+#include <x86/fpu.h>
 #include <machine/reg.h>
 #include <machine/vm86.h>
 #include <machine/vmparam.h>
--- a/sys/arch/i386/i386/i386_trap.S	Wed Feb 12 23:04:43 2014 +0000
+++ b/sys/arch/i386/i386/i386_trap.S	Wed Feb 12 23:24:09 2014 +0000
@@ -1,4 +1,4 @@
-/*	$NetBSD: i386_trap.S,v 1.4 2014/02/04 21:09:23 dsl Exp $	*/
+/*	$NetBSD: i386_trap.S,v 1.5 2014/02/12 23:24:09 dsl Exp $	*/
 
 /*
  * Copyright 2002 (c) Wasabi Systems, Inc.
@@ -66,7 +66,7 @@
 
 #if 0
 #include <machine/asm.h>
-__KERNEL_RCSID(0, "$NetBSD: i386_trap.S,v 1.4 2014/02/04 21:09:23 dsl Exp $");
+__KERNEL_RCSID(0, "$NetBSD: i386_trap.S,v 1.5 2014/02/12 23:24:09 dsl Exp $");
 #endif
 
 /*
@@ -162,7 +162,7 @@
 #ifdef DIAGNOSTIC
 	movl	CPUVAR(ILEVEL),%ebx
 #endif
-	pushl	CPUVAR(SELF)
+	pushl	%esp
 	call	_C_LABEL(fpudna)
 	addl	$4,%esp
 	jmp	_C_LABEL(trapreturn)
@@ -231,30 +231,30 @@
 	 * this is difficult for nested interrupts.
 	 */
 	pushl	$0			# dummy error code
-	pushl	$T_ASTFLT
+	pushl	$T_ARITHTRAP
+.Ldo_fputrap:
 	INTRENTRY
 	movl	CPUVAR(ILEVEL),%ebx
-	pushl	%ebx
 	pushl	%esp
-	pushl	$0			# dummy arg
 	addl	$1,CPUVAR(NTRAP)	# statistical info
 	adcl	$0,CPUVAR(NTRAP)+4
-	call	_C_LABEL(npxintr)
-	addl	$12,%esp
+	call	_C_LABEL(fputrap)
+	addl	$4,%esp
 	jmp	_C_LABEL(trapreturn)
 IDTVEC_END(trap10)
 IDTVEC(trap11)
 	TRAP(T_ALIGNFLT)
 IDTVEC_END(trap11)
-#ifdef XEN
-IDTVEC(trap12)
-IDTVEC(trap13)
-#else
+
 IDTVEC(trap12)
 	ZTRAP(T_MCA)
+IDTVEC_END(trap12)
 IDTVEC(trap13)
-	ZTRAP(T_XMM)
-#endif
+	pushl	$0			# dummy error code
+	pushl	$T_XMM
+	jmp	.Ldo_fputrap
+IDTVEC_END(trap13)
+
 IDTVEC(trap14)
 IDTVEC(trap15)
 IDTVEC(trap16)
--- a/sys/arch/i386/i386/ibcs2_machdep.c	Wed Feb 12 23:04:43 2014 +0000
+++ b/sys/arch/i386/i386/ibcs2_machdep.c	Wed Feb 12 23:24:09 2014 +0000
@@ -1,4 +1,4 @@
-/*	$NetBSD: ibcs2_machdep.c,v 1.42 2014/01/19 14:30:37 dsl Exp $	*/
+/*	$NetBSD: ibcs2_machdep.c,v 1.43 2014/02/12 23:24:09 dsl Exp $	*/
 
 /*-
  * Copyright (c) 1997, 2000 The NetBSD Foundation, Inc.
@@ -30,7 +30,7 @@
  */
 
 #include <sys/cdefs.h>
-__KERNEL_RCSID(0, "$NetBSD: ibcs2_machdep.c,v 1.42 2014/01/19 14:30:37 dsl Exp $");
+__KERNEL_RCSID(0, "$NetBSD: ibcs2_machdep.c,v 1.43 2014/02/12 23:24:09 dsl Exp $");
 
 #if defined(_KERNEL_OPT)
 #include "opt_vm86.h"
@@ -47,7 +47,7 @@
 #include <machine/cpu.h>
 #include <machine/cpufunc.h>
 #include <machine/psl.h>
-#include <machine/npx.h>
+#include <x86/fpu.h>
 #include <machine/reg.h>
 #include <machine/vmparam.h>
 #include <machine/ibcs2_machdep.h>
--- a/sys/arch/i386/i386/trap.c	Wed Feb 12 23:04:43 2014 +0000
+++ b/sys/arch/i386/i386/trap.c	Wed Feb 12 23:24:09 2014 +0000
@@ -1,4 +1,4 @@
-/*	$NetBSD: trap.c,v 1.270 2014/02/07 19:32:50 dsl Exp $	*/
+/*	$NetBSD: trap.c,v 1.271 2014/02/12 23:24:09 dsl Exp $	*/
 
 /*-
  * Copyright (c) 1998, 2000, 2005, 2006, 2007, 2008 The NetBSD Foundation, Inc.
@@ -68,7 +68,7 @@
  */
 
 #include <sys/cdefs.h>
-__KERNEL_RCSID(0, "$NetBSD: trap.c,v 1.270 2014/02/07 19:32:50 dsl Exp $");
+__KERNEL_RCSID(0, "$NetBSD: trap.c,v 1.271 2014/02/12 23:24:09 dsl Exp $");
 
 #include "opt_ddb.h"
 #include "opt_kgdb.h"
@@ -126,7 +126,6 @@
 #endif
 
 
-static inline int xmm_si_code(struct lwp *);
 void trap(struct trapframe *);
 void trap_tss(struct i386tss *, int, int);
 void trap_return_fault_return(struct trapframe *) __dead;
@@ -188,44 +187,6 @@
 	trap(&tf);
 }
 
-static inline int
-xmm_si_code(struct lwp *l)
-{
-	struct pcb *pcb;
-	uint32_t mxcsr, mask;
-
-	if (!i386_use_fxsave) {
-#ifdef DIAGNOSTIC
-		panic("SSE FP Exception, but no SSE");
-#endif
-		return 0;
-	}
-	pcb = lwp_getpcb(l);
-	mxcsr = pcb->pcb_savefpu.sv_xmm.fx_mxcsr;
-
-	/*
-         * Since we only have a single status and control register,
-	 * we use the exception mask bits to mask disabled exceptions
-	 */
-	mask = ~((mxcsr & __INITIAL_MXCSR__) >> 7) & 0xff;
-        switch (mask & mxcsr) {
-	case EN_SW_INVOP:
-		return FPE_FLTINV;
-	case EN_SW_DENORM:
-	case EN_SW_PRECLOSS:
-		return FPE_FLTRES;
-	case EN_SW_ZERODIV:
-		return FPE_FLTDIV;
-	case EN_SW_OVERFLOW:
-		return FPE_FLTOVF;
-	case EN_SW_UNDERFLOW:
-		return FPE_FLTUND;
-	case 0:
-	default:
-		return 0;
-	}
-}
-
 static void *
 onfault_handler(const struct pcb *pcb, const struct trapframe *tf)
 {
@@ -552,27 +513,13 @@
 		}
 		goto out;
 
-	case T_DNA|T_USER: {
-		KSI_INIT_TRAP(&ksi);
-		ksi.ksi_signo = SIGKILL;
-		ksi.ksi_addr = (void *)frame->tf_eip;
-		printf("pid %d killed due to lack of floating point\n",
-		    p->p_pid);
-		goto trapsignal;
-	}
-
-	case T_XMM|T_USER:
 	case T_BOUND|T_USER:
 	case T_OFLOW|T_USER:
 	case T_DIVIDE|T_USER:
-	case T_ARITHTRAP|T_USER:
 		KSI_INIT_TRAP(&ksi);
 		ksi.ksi_signo = SIGFPE;
 		ksi.ksi_addr = (void *)frame->tf_eip;
 		switch (type) {
-		case T_XMM|T_USER:
-			ksi.ksi_code = xmm_si_code(l);
-			break;
 		case T_BOUND|T_USER:
 			ksi.ksi_code = FPE_FLTSUB;
 			break;
@@ -582,9 +529,6 @@
 		case T_DIVIDE|T_USER:
 			ksi.ksi_code = FPE_INTDIV;
 			break;
-		case T_ARITHTRAP|T_USER:
-			ksi.ksi_code = npxtrap(l);
-			break;
 		default:
 			ksi.ksi_code = 0;
 			break;
--- a/sys/arch/i386/include/Makefile	Wed Feb 12 23:04:43 2014 +0000
+++ b/sys/arch/i386/include/Makefile	Wed Feb 12 23:24:09 2014 +0000
@@ -1,4 +1,4 @@
-#	$NetBSD: Makefile,v 1.41 2012/11/05 00:57:42 alnsn Exp $
+#	$NetBSD: Makefile,v 1.42 2014/02/12 23:24:09 dsl Exp $
 
 INCSDIR= /usr/include/i386
 
@@ -16,7 +16,6 @@
 	kcore.h \
 	limits.h lock.h \
 	math.h mcontext.h mutex.h mtrr.h multiboot.h \
-	npx.h \
 	param.h pcb.h pio.h pmap.h pmc.h proc.h profile.h psl.h \
 	pte.h ptrace.h \
 	reg.h rwlock.h \
--- a/sys/arch/i386/include/freebsd_machdep.h	Wed Feb 12 23:04:43 2014 +0000
+++ b/sys/arch/i386/include/freebsd_machdep.h	Wed Feb 12 23:24:09 2014 +0000
@@ -1,4 +1,4 @@
-/*	$NetBSD: freebsd_machdep.h,v 1.12 2014/01/19 13:35:58 dsl Exp $	*/
+/*	$NetBSD: freebsd_machdep.h,v 1.13 2014/02/12 23:24:09 dsl Exp $	*/
 
 /*
  * Copyright (c) 1986, 1989, 1991, 1993
@@ -41,7 +41,6 @@
 #define _FREEBSD_MACHDEP_H
 
 #include <compat/sys/sigtypes.h>
-#include <machine/npx.h>
 
 /*
  * signal support
--- a/sys/arch/i386/include/npx.h	Wed Feb 12 23:04:43 2014 +0000
+++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
@@ -1,17 +0,0 @@
-/*	$NetBSD: npx.h,v 1.35 2014/02/07 22:40:22 dsl Exp $	*/
-
-#ifndef	_I386_NPX_H_
-#define	_I386_NPX_H_
-
-#include <x86/cpu_extended_state.h>
-
-#ifdef _KERNEL
-
-int	npx586bug1(int, int);
-void 	fpuinit(struct cpu_info *);
-struct lwp;
-int	npxtrap(struct lwp *);
-
-#endif
-
-#endif /* !_I386_NPX_H_ */
--- a/sys/arch/i386/include/pcb.h	Wed Feb 12 23:04:43 2014 +0000
+++ b/sys/arch/i386/include/pcb.h	Wed Feb 12 23:24:09 2014 +0000
@@ -1,4 +1,4 @@
-/*	$NetBSD: pcb.h,v 1.51 2014/01/19 10:30:19 dsl Exp $	*/
+/*	$NetBSD: pcb.h,v 1.52 2014/02/12 23:24:09 dsl Exp $	*/
 
 /*-
  * Copyright (c) 1998, 2009 The NetBSD Foundation, Inc.
@@ -78,7 +78,7 @@
 
 #include <machine/segments.h>
 #include <machine/tss.h>
-#include <i386/npx.h>
+#include <x86/fpu.h>
 #include <i386/sysarch.h>
 
 struct pcb {
--- a/sys/arch/i386/isa/npx.c	Wed Feb 12 23:04:43 2014 +0000
+++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
@@ -1,665 +0,0 @@
-/*	$NetBSD: npx.c,v 1.153 2014/02/09 22:47:04 dsl Exp $	*/
-
-/*-
- * Copyright (c) 2008 The NetBSD Foundation, Inc.
- * All rights reserved.
- *
- * This code is derived from software developed for The NetBSD Foundation
- * by Andrew Doran.
- *
- * Redistribution and use in source and binary forms, with or without
- * modification, are permitted provided that the following conditions
- * are met:
- * 1. Redistributions of source code must retain the above copyright
- *    notice, this list of conditions and the following disclaimer.
- * 2. Redistributions in binary form must reproduce the above copyright
- *    notice, this list of conditions and the following disclaimer in the
- *    documentation and/or other materials provided with the distribution.
- *
- * THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND CONTRIBUTORS
- * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
- * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
- * PURPOSE ARE DISCLAIMED.  IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS
- * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
- * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
- * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
- * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
- * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
- * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
- * POSSIBILITY OF SUCH DAMAGE.
- */
-
-/*-
- * Copyright (c) 1991 The Regents of the University of California.
- * All rights reserved.
- *
- * Redistribution and use in source and binary forms, with or without
- * modification, are permitted provided that the following conditions
- * are met:
- * 1. Redistributions of source code must retain the above copyright
- *    notice, this list of conditions and the following disclaimer.
- * 2. Redistributions in binary form must reproduce the above copyright
- *    notice, this list of conditions and the following disclaimer in the
- *    documentation and/or other materials provided with the distribution.
- * 3. Neither the name of the University nor the names of its contributors
- *    may be used to endorse or promote products derived from this software
- *    without specific prior written permission.
- *
- * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
- * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
- * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
- * ARE DISCLAIMED.  IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
- * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
- * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
- * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
- * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
- * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
- * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
- * SUCH DAMAGE.
- *
- *	@(#)npx.c	7.2 (Berkeley) 5/12/91
- */
-
-/*-
- * Copyright (c) 1994, 1995, 1998 Charles M. Hannum.  All rights reserved.
- * Copyright (c) 1990 William Jolitz.
- *
- * Redistribution and use in source and binary forms, with or without
- * modification, are permitted provided that the following conditions
- * are met:
- * 1. Redistributions of source code must retain the above copyright
- *    notice, this list of conditions and the following disclaimer.
- * 2. Redistributions in binary form must reproduce the above copyright
- *    notice, this list of conditions and the following disclaimer in the
- *    documentation and/or other materials provided with the distribution.
- * 3. All advertising materials mentioning features or use of this software
- *    must display the following acknowledgement:
- *	This product includes software developed by the University of
- *	California, Berkeley and its contributors.
- * 4. Neither the name of the University nor the names of its contributors
- *    may be used to endorse or promote products derived from this software
- *    without specific prior written permission.
- *
- * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
- * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
- * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
- * ARE DISCLAIMED.  IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
- * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
- * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
- * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
- * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
- * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
- * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
- * SUCH DAMAGE.
- *
- *	@(#)npx.c	7.2 (Berkeley) 5/12/91
- */
-
-#include <sys/cdefs.h>
-__KERNEL_RCSID(0, "$NetBSD: npx.c,v 1.153 2014/02/09 22:47:04 dsl Exp $");
-
-#include "opt_multiprocessor.h"
-#include "opt_xen.h"
-
-#include <sys/param.h>
-#include <sys/systm.h>
-#include <sys/conf.h>
-#include <sys/cpu.h>
-#include <sys/kernel.h>
-#include <sys/cpu.h>
-
-#include <machine/cpufunc.h>
-#include <machine/cpuvar.h>
-#include <machine/pcb.h>
-#include <machine/specialreg.h>
-
-
-/*
- * 387 Numeric Coprocessor Extension (NPX) Driver.
- *
- * Note that we only support 486 and later cpus, these do not support
- * an external fpu, only the one that is part of the cpu fabric.
- * A 486 might not have an fpu, but the 487 is a full 486.
- *
- * Since we set CR0.NE a FP exception can only happen when a user process
- * executes a FP instruction. The DNA exception takes precedence, so
- * the execption can only happen when the lwp already owns the fpu.
- * In particular the exceptions won't happen in-kernel while saving state.
- *
- * We do lazy initialization and switching using the TS bit in cr0 and the
- * MDL_USEDFPU bit in mdlwp.
- *
- * DNA exceptions are handled like this:
- *
- * 1) If there is no NPX, we ought to kill the process.
- * 2) If someone else has used the NPX, save its state into that process's PCB.
- * 3a) If MDL_USEDFPU is not set, set it and initialize the NPX.
- * 3b) Otherwise, reload the process's previous NPX state.
- *
- * When a process is created or exec()s, its saved cr0 image has the TS bit
- * set and the MDL_USEDFPU bit clear.  The MDL_USEDFPU bit is set when the
- * process first gets a DNA and the NPX is initialized.  The TS bit is turned
- * off when the NPX is used, and turned on again later when the process's NPX
- * state is saved.
- */
-
-static int	x86fpflags_to_ksiginfo(uint32_t flags);
-/* Called directly from i386_trap.S */
-void	fpudna(struct cpu_info *);
-
-#ifdef XEN
-#define	clts() HYPERVISOR_fpu_taskswitch(0)
-#define	stts() HYPERVISOR_fpu_taskswitch(1)
-#endif
-
-extern int i386_fpu_present;
-extern int i386_fpu_fdivbug;
-
-struct npx_softc		*npx_softc;
-
-#ifndef XEN
-/* Initialise fpu, might be boot cpu or a later cpu coming online */
-void
-fpuinit(struct cpu_info *ci)
-{
-	uint16_t control;
-
-	/* The default cr0 has the fpu enabled */
-	clts();
-	fninit();
-
-	/* Read the default control word */
-	fnstcw(&control);
-
-	if (control != __INITIAL_NPXCW__) {
-		/* Must be a 486SX, trap FP instructions */
-		lcr0((rcr0() & ~CR0_MP) | CR0_EM);
-		aprint_normal_dev(ci->ci_dev, "no fpu (control %x)\n", control);
-		i386_fpu_present = 0;
-		return;
-	}
-
-	if (npx586bug1(4195835, 3145727) != 0) {
-		/* NB 120+MHz cpus are not affected */
-		i386_fpu_fdivbug = 1;
-		aprint_normal_dev(ci->ci_dev,
-		    "WARNING: Pentium FDIV bug detected!\n");
-	}
-
-	/* Set TS so first fp instruction faults */
-	stts();
-}
-#endif
-
-/*
- * Record the FPU state and reinitialize it all except for the control word.
- * Then generate a SIGFPE.
- *
- * Reinitializing the state allows naive SIGFPE handlers to longjmp without
- * doing any fixups.
- *
- * XXX there is currently no way to pass the full error state to signal
- * handlers, and if this is a nested interrupt there is no way to pass even
- * a status code!  So there is no way to have a non-naive SIGFPE handler.  At
- * best a handler could do an fninit followed by an fldcw of a static value.
- * fnclex would be of little use because it would leave junk on the FPU stack.
- *
- * Only called directly from i386_trap.S (with interrupts disabled)
- *
- * Since we have CR0.NE set this can only happen as a result of
- * executing an FP instruction (and after CR0.TS has been checked).
- * This means this must be from userspace on the current lwp.
- */
-int npxintr(void *, struct intrframe *);
-int
-npxintr(void *arg, struct intrframe *frame)
-{
-	struct cpu_info *ci = curcpu();
-	struct lwp *l = ci->ci_fpcurlwp;
-	union savefpu *addr;
-	struct pcb *pcb;
-	uint32_t statbits;
-	ksiginfo_t ksi;
-
-	if (!USERMODE(frame->if_cs, frame->if_eflags))
-		panic("fpu trap from kernel\n");
-
-	kpreempt_disable();
-#ifndef XEN
-	KASSERT((x86_read_psl() & PSL_I) == 0);
-	x86_enable_intr();
-#endif
-
-	/*
-	 * At this point, fpcurlwp should be curlwp.  If it wasn't, the TS
-	 * bit should be set, and we should have gotten a DNA exception.
-	 */
-	if (l != curlwp || !i386_fpu_present) {
-		printf("npxintr: l = %p, curproc = %p, fpu_present = %d\n",
-		    l, curproc, i386_fpu_present);
-		printf("npxintr: came from nowhere");
-		kpreempt_enable();
-		return 1;
-	}
-
-	/* Find the address of fpcurproc's saved FPU state. */
-	pcb = lwp_getpcb(l);
-	addr = &pcb->pcb_savefpu;
-
-	/*
-	 * XXX: (dsl) I think this is all borked.
-	 * We need to save the status word (which contains the cause)
-	 * of the fault, and clear the relevant error bits so that
-	 * the fp instruction doesn't trap again when the signal handler
-	 * returns (or if the signal is ignored).
-	 * What the code actually does is to reset the FPU, this clears
-	 * the FP stack pointer so I suspect the code then gets the
-	 * wrong register values for an later operations.
-	 * Any code that enabled the stack under/overflow traps is doomed.
-	 *
-	 * I think this code should just save the status word and clear
-	 * the pending errors.
-	 * If the signal is generated then the FP state can be saved in
-	 * the context stashed on the user stack, and restrored from
-	 * there later. So this code need not do a fsave or finit.
-	 */
-	if (i386_use_fxsave) {
-		fxsave(&addr->sv_xmm);
-		/* FXSAVE doesn't FNINIT like FNSAVE does -- so do it here. */
-		fninit();
-		fwait();
-		fldcw(&addr->sv_xmm.fx_cw);
-		/*
-		 * FNINIT doesn't affect MXCSR or the XMM registers;
-		 * no need to re-load MXCSR here.
-		 */
-		statbits = addr->sv_xmm.fx_sw;
-	} else {
-		fnsave(&addr->sv_87);
-		/* fnsave has done an fninit() */
-		fwait();
-		fldcw(&addr->sv_87.s87_cw);
-		statbits = addr->sv_87.s87_sw;
-	}
-	fwait();
-
-	/*
-	 * Pass exception to process.
-	 */
-
-	/*
-	 * Interrupt is essentially a trap, so we can afford to call
-	 * the SIGFPE handler (if any) as soon as the interrupt
-	 * returns.
-	 *
-	 * XXX little or nothing is gained from this, and plenty is
-	 * lost - the interrupt frame has to contain the trap frame
-	 * (this is otherwise only necessary for the rescheduling trap
-	 * in doreti, and the frame for that could easily be set up
-	 * just before it is used).
-	 */
-	l->l_md.md_regs = (struct trapframe *)&frame->if_gs;
-
-	KSI_INIT_TRAP(&ksi);
-	ksi.ksi_signo = SIGFPE;
-	ksi.ksi_addr = (void *)frame->if_eip;
-
-	/*
-	 * Encode the appropriate code for detailed information on
-	 * this exception.
-	 */
-
-	ksi.ksi_code = x86fpflags_to_ksiginfo(statbits);
-	ksi.ksi_trap = statbits;
-
-	trapsignal(l, &ksi);
-
-	kpreempt_enable();
-	return (1);
-}
-
-/* map x86 fp flags to ksiginfo fp codes 		*/
-/* see table 8-4 of the IA-32 Intel Architecture	*/
-/* Software Developer's Manual, Volume 1		*/
-/* XXX punting on the stack fault with FLTINV		*/
-static int
-x86fpflags_to_ksiginfo(uint32_t flags)
-{
-	int i;
-	static int x86fp_ksiginfo_table[] = {
-		FPE_FLTINV, /* bit 0 - invalid operation */
-		FPE_FLTRES, /* bit 1 - denormal operand */
-		FPE_FLTDIV, /* bit 2 - divide by zero	*/
-		FPE_FLTOVF, /* bit 3 - fp overflow	*/
-		FPE_FLTUND, /* bit 4 - fp underflow	*/ 
-		FPE_FLTRES, /* bit 5 - fp precision	*/
-		FPE_FLTINV, /* bit 6 - stack fault	*/
-	};
-					     
-	for(i=0;i < sizeof(x86fp_ksiginfo_table)/sizeof(int); i++) {
-		if (flags & (1 << i))
-			return(x86fp_ksiginfo_table[i]);
-	}
-	/* punt if flags not set */
-	return(0);
-}
-
-/*
- * Implement device not available (DNA) exception
- *
- * Called directly from i386_trap.S with interrupts still disabled
- *
- * If we were the last lwp to use the FPU, we can simply return.
- * Otherwise, we save the previous state, if necessary, and restore
- * our last saved state.
- */
-void
-fpudna(struct cpu_info *ci)
-{
-	struct lwp *l, *fl;
-	struct pcb *pcb;
-	int s;
-
-	/* XXX generate signal if no fpu */
-
-	/* Lock out IPIs and disable preemption. */
-	s = splhigh();
-#ifndef XEN
-	x86_enable_intr();
-#endif
-	/* Save state on current CPU. */
-	l = ci->ci_curlwp;
-	pcb = lwp_getpcb(l);
-
-	fl = ci->ci_fpcurlwp;
-	if (fl != NULL) {
-		/*
-		 * It seems we can get here on Xen even if we didn't
-		 * switch lwp.  In this case do nothing
-		 */
-		if (fl == l) {
-			KASSERT(pcb->pcb_fpcpu == ci);
-			ci->ci_fpused = 1;
-			clts();
-			splx(s);
-			return;
-		}
-		KASSERT(fl != l);
-		fpusave_cpu(true);
-		KASSERT(ci->ci_fpcurlwp == NULL);
-	}
-
-	/* Save our state if on a remote CPU. */
-	if (pcb->pcb_fpcpu != NULL) {
-		/* Explicitly disable preemption before dropping spl. */
-		KPREEMPT_DISABLE(l);
-		splx(s);
-		fpusave_lwp(l, true);
-		KASSERT(pcb->pcb_fpcpu == NULL);
-		s = splhigh();
-		KPREEMPT_ENABLE(l);
-	}
-
-	/*
-	 * Restore state on this CPU, or initialize.  Ensure that
-	 * the entire update is atomic with respect to FPU-sync IPIs.
-	 */
-	clts();
-	ci->ci_fpcurlwp = l;
-	pcb->pcb_fpcpu = ci;
-	ci->ci_fpused = 1;
-
-	if ((l->l_md.md_flags & MDL_USEDFPU) == 0) {
-		fninit();
-		if (i386_use_fxsave) {
-			fldcw(&pcb->pcb_savefpu.sv_xmm.fx_cw);
-		} else {
-			fldcw(&pcb->pcb_savefpu.sv_87.s87_cw);
-		}
-		l->l_md.md_flags |= MDL_USEDFPU;
-	} else if (i386_use_fxsave) {
-		/*
-		 * AMD FPU's do not restore FIP, FDP, and FOP on fxrstor,
-		 * leaking other process's execution history. Clear them
-		 * manually.
-		 */
-		static const double zero = 0.0;
-		uint16_t status;
-		/*
-		 * Clear the ES bit in the x87 status word if it is currently
-		 * set, in order to avoid causing a fault in the upcoming load.
-		 */
-		fnstsw(&status);
-		if (status & 0x80)
-			fnclex();
-		/*
-		 * Load the dummy variable into the x87 stack.  This mangles
-		 * the x87 stack, but we don't care since we're about to call
-		 * fxrstor() anyway.
-		 */
-		fldummy(&zero);
-		fxrstor(&pcb->pcb_savefpu.sv_xmm);
-	} else {
-		frstor(&pcb->pcb_savefpu.sv_87);
-	}
-
-	KASSERT(ci == curcpu());
-	splx(s);
-}
-
-/*
- * Save current CPU's FPU state.  Must be called at IPL_HIGH.
- */
-void
-fpusave_cpu(bool save)
-{
-	struct cpu_info *ci;
-	struct lwp *l;
-	struct pcb *pcb;
-
-	KASSERT(curcpu()->ci_ilevel == IPL_HIGH);
-
-	ci = curcpu();
-	l = ci->ci_fpcurlwp;
-	if (l == NULL)
-		return;
-
-	pcb = lwp_getpcb(l);
-
-	if (save) {
-		clts();
-		if (i386_use_fxsave) {
-			fxsave(&pcb->pcb_savefpu.sv_xmm);
-		} else {
-			fnsave(&pcb->pcb_savefpu.sv_87);
-		}
-	}
-
-	stts();
-	pcb->pcb_fpcpu = NULL;
-	ci->ci_fpcurlwp = NULL;
-	ci->ci_fpused = 1;
-}
-
-/*
- * Save l's FPU state, which may be on this processor or another processor.
- * It may take some time, so we avoid disabling preemption where possible.
- * Caller must know that the target LWP is stopped, otherwise this routine
- * may race against it.
- */
-void
-fpusave_lwp(struct lwp *l, bool save)
-{
-	struct cpu_info *oci;
-	struct pcb *pcb;
-	int s, spins, ticks;
-
-	spins = 0;
-	ticks = hardclock_ticks;
-	for (;;) {
-		s = splhigh();
-		pcb = lwp_getpcb(l);
-		oci = pcb->pcb_fpcpu;
-		if (oci == NULL) {
-			splx(s);
-			break;
-		}
-		if (oci == curcpu()) {
-			KASSERT(oci->ci_fpcurlwp == l);
-			fpusave_cpu(save);
-			splx(s);
-			break;
-		}
-		splx(s);
-#ifdef XEN
-		if (xen_send_ipi(oci, XEN_IPI_SYNCH_FPU) != 0) {
-			panic("xen_send_ipi(%s, XEN_IPI_SYNCH_FPU) failed.",
-			    cpu_name(oci));
-		}
-#else /* XEN */
-		x86_send_ipi(oci, X86_IPI_SYNCH_FPU);
-#endif
-		while (pcb->pcb_fpcpu == oci && ticks == hardclock_ticks) {
-			x86_pause();
-			spins++;
-		}
-		if (spins > 100000000) {
-			panic("fpusave_lwp: did not");
-		}
-	}
-
-	if (!save) {
-		/* Ensure we restart with a clean slate. */
-	 	l->l_md.md_flags &= ~MDL_USEDFPU;
-	}
-}
-
-/* 
- * The following mechanism is used to ensure that the FPE_... value
- * that is passed as a trapcode to the signal handler of the user
- * process does not have more than one bit set.
- * 
- * Multiple bits may be set if the user process modifies the control
- * word while a status word bit is already set.  While this is a sign
- * of bad coding, we have no choise than to narrow them down to one
- * bit, since we must not send a trapcode that is not exactly one of
- * the FPE_ macros.
- *
- * The mechanism has a static table with 127 entries.  Each combination
- * of the 7 FPU status word exception bits directly translates to a
- * position in this table, where a single FPE_... value is stored.
- * This FPE_... value stored there is considered the "most important"
- * of the exception bits and will be sent as the signal code.  The
- * precedence of the bits is based upon Intel Document "Numerical
- * Applications", Chapter "Special Computational Situations".
- *
- * The macro to choose one of these values does these steps: 1) Throw
- * away status word bits that cannot be masked.  2) Throw away the bits
- * currently masked in the control word, assuming the user isn't
- * interested in them anymore.  3) Reinsert status word bit 7 (stack
- * fault) if it is set, which cannot be masked but must be presered.
- * 4) Use the remaining bits to point into the trapcode table.
- *
- * The 6 maskable bits in order of their preference, as stated in the
- * above referenced Intel manual:
- * 1  Invalid operation (FP_X_INV)
- * 1a   Stack underflow
- * 1b   Stack overflow
- * 1c   Operand of unsupported format
- * 1d   SNaN operand.
- * 2  QNaN operand (not an exception, irrelavant here)
- * 3  Any other invalid-operation not mentioned above or zero divide
- *      (FP_X_INV, FP_X_DZ)
- * 4  Denormal operand (FP_X_DNML)
- * 5  Numeric over/underflow (FP_X_OFL, FP_X_UFL)
- * 6  Inexact result (FP_X_IMP) 
- *
- * NB: the above seems to mix up the mxscr error bits and the x87 ones.
- * They are in the same order, but there is no EN_SW_STACK_FAULT in the mmx
- * status.
- *
- * The table is nearly, but not quite, in bit order (ZERODIV and DENORM
- * are swapped).
- *
- * This table assumes that any stack fault is cleared - so that an INVOP
- * fault will only be reported as FLTSUB once.
- * This might not happen if the mask is being changed.
- */
-#define FPE_xxx1(f) (f & EN_SW_INVOP \
-		? (f & EN_SW_STACK_FAULT ? FPE_FLTSUB : FPE_FLTINV) \
-	: f & EN_SW_ZERODIV ? FPE_FLTDIV \
-	: f & EN_SW_DENORM ? FPE_FLTUND \
-	: f & EN_SW_OVERFLOW ? FPE_FLTOVF \
-	: f & EN_SW_UNDERFLOW ? FPE_FLTUND \
-	: f & EN_SW_PRECLOSS ? FPE_FLTRES \
-	: f & EN_SW_STACK_FAULT ? FPE_FLTSUB : 0)
-#define	FPE_xxx2(f)	FPE_xxx1(f),	FPE_xxx1((f + 1))
-#define	FPE_xxx4(f)	FPE_xxx2(f),	FPE_xxx2((f + 2))
-#define	FPE_xxx8(f)	FPE_xxx4(f),	FPE_xxx4((f + 4))
-#define	FPE_xxx16(f)	FPE_xxx8(f),	FPE_xxx8((f + 8))
-#define	FPE_xxx32(f)	FPE_xxx16(f),	FPE_xxx16((f + 16))
-static const uint8_t fpetable[128] = {
-	FPE_xxx32(0), FPE_xxx32(32), FPE_xxx32(64), FPE_xxx32(96)
-};
-#undef FPE_xxx1
-#undef FPE_xxx2
-#undef FPE_xxx4
-#undef FPE_xxx8
-#undef FPE_xxx16
-#undef FPE_xxx32
-
-/*
- * Preserve the FP status word, clear FP exceptions, then generate a SIGFPE.
- *
- * Clearing exceptions is necessary mainly to avoid IRQ13 bugs.  We now
- * depend on longjmp() restoring a usable state.  Restoring the state
- * or examining it might fail if we didn't clear exceptions.
- *
- * The error code chosen will be one of the FPE_... macros. It will be
- * sent as the second argument to old BSD-style signal handlers and as
- * "siginfo_t->si_code" (second argument) to SA_SIGINFO signal handlers.
- *
- * XXX the FP state is not preserved across signal handlers.  So signal
- * handlers cannot afford to do FP unless they preserve the state or
- * longjmp() out.  Both preserving the state and longjmp()ing may be
- * destroyed by IRQ13 bugs.  Clearing FP exceptions is not an acceptable
- * solution for signals other than SIGFPE.
- */
-int
-npxtrap(struct lwp *l)
-{
-	u_short control, status;
-	struct cpu_info *ci = curcpu();
-	struct lwp *fl = ci->ci_fpcurlwp;
-
-	if (!i386_fpu_present) {
-		printf("%s: fpcurthread = %p, curthread = %p\n",
-		    __func__, fl, l);
-		panic("npxtrap from nowhere");
-	}
-	kpreempt_disable();
-
-	/*
-	 * Interrupt handling (for another interrupt) may have pushed the
-	 * state to memory.  Fetch the relevant parts of the state from
-	 * wherever they are.
-	 */
-	if (fl != l) {
-		struct pcb *pcb = lwp_getpcb(l);
-		if (i386_use_fxsave) {
-			control = pcb->pcb_savefpu.sv_xmm.fx_cw;
-			status = pcb->pcb_savefpu.sv_xmm.fx_sw;
-		} else {
-			control = pcb->pcb_savefpu.sv_87.s87_cw;
-			status = pcb->pcb_savefpu.sv_87.s87_sw;
-		}
-	} else {
-		fnstcw(&control);
-		fnstsw(&status);
-	}
-
-	if (fl == l)
-		fnclex();
-	kpreempt_enable();
-	return fpetable[status & ((~control & 0x3f) | 0x40)];
-}
--- a/sys/arch/x86/include/cpu.h	Wed Feb 12 23:04:43 2014 +0000
+++ b/sys/arch/x86/include/cpu.h	Wed Feb 12 23:24:09 2014 +0000
@@ -1,4 +1,4 @@
-/*	$NetBSD: cpu.h,v 1.60 2014/02/04 21:09:24 dsl Exp $	*/
+/*	$NetBSD: cpu.h,v 1.61 2014/02/12 23:24:09 dsl Exp $	*/
 
 /*-
  * Copyright (c) 1990 The Regents of the University of California.
@@ -101,8 +101,7 @@
 	struct cpu_info *ci_next;	/* next cpu */
 	struct lwp *ci_curlwp;		/* current owner of the processor */
 	struct lwp *ci_fpcurlwp;	/* current owner of the FPU */
-	int	_unused1;
-	int	ci_fpused;		/* XEN: FPU was used by curlwp */
+	int	_unused1[2];
 	cpuid_t ci_cpuid;		/* our CPU ID */
 	int	_unused;
 	uint32_t ci_acpiid;		/* our ACPI/MADT ID */
@@ -365,9 +364,20 @@
 extern char cpu_brand_string[];
 extern int use_pae;
 
+#ifdef __i386__
+extern int i386_fpu_present;
+int npx586bug1(int, int);
+extern int i386_fpu_fdivbug;
 extern int i386_use_fxsave;
 extern int i386_has_sse;
 extern int i386_has_sse2;
+#else
+#define	i386_fpu_present	1
+#define	i386_fpu_fdivbug	0
+#define	i386_use_fxsave		1
+#define	i386_has_sse		1
+#define	i386_has_sse2		1
+#endif
 
 extern void (*x86_cpu_idle)(void);
 #define	cpu_idle() (*x86_cpu_idle)()
--- a/sys/arch/x86/include/cpu_extended_state.h	Wed Feb 12 23:04:43 2014 +0000
+++ b/sys/arch/x86/include/cpu_extended_state.h	Wed Feb 12 23:24:09 2014 +0000
@@ -1,4 +1,4 @@
-/*	$NetBSD: cpu_extended_state.h,v 1.4 2014/02/09 14:44:42 dsl Exp $	*/
+/*	$NetBSD: cpu_extended_state.h,v 1.5 2014/02/12 23:24:09 dsl Exp $	*/
 
 #ifndef _X86_CPU_EXTENDED_STATE_H_
 #define _X86_CPU_EXTENDED_STATE_H_
@@ -248,10 +248,4 @@
 #define	__INITIAL_MXCSR__	0x1f80
 #define	__INITIAL_MXCSR_MASK__	0xffbf
 
-#ifdef _KERNEL
-void process_xmm_to_s87(const struct fxsave *, struct save87 *);
-void process_s87_to_xmm(const struct save87 *, struct fxsave *);
-#endif
-
-
 #endif /* _X86_CPU_EXTENDED_STATE_H_ */
--- a/sys/arch/x86/include/cpufunc.h	Wed Feb 12 23:04:43 2014 +0000
+++ b/sys/arch/x86/include/cpufunc.h	Wed Feb 12 23:24:09 2014 +0000
@@ -1,4 +1,4 @@
-/*	$NetBSD: cpufunc.h,v 1.15 2014/02/09 17:07:41 dsl Exp $	*/
+/*	$NetBSD: cpufunc.h,v 1.16 2014/02/12 23:24:09 dsl Exp $	*/
 
 /*-
  * Copyright (c) 1998, 2007 The NetBSD Foundation, Inc.
@@ -81,13 +81,14 @@
 void	fninit(void);
 void	fnsave(void *);
 void	fnstcw(uint16_t *);
-void	fnstsw(void *);
+uint16_t fngetsw(void);
+void	fnstsw(uint16_t *);
 void	fp_divide_by_0(void);
 void	frstor(void *);
 void	fwait(void);
 void	clts(void);
 void	stts(void);
-void	fldummy(const double *);
+void	fldummy(void);
 void	fxsave(void *);
 void	fxrstor(void *);
 void	x86_monitor(const void *, uint32_t, uint32_t);
--- a/sys/arch/x86/include/fpu.h	Wed Feb 12 23:04:43 2014 +0000
+++ b/sys/arch/x86/include/fpu.h	Wed Feb 12 23:24:09 2014 +0000
@@ -1,25 +1,25 @@
-/*	$NetBSD: fpu.h,v 1.1 2014/02/11 20:17:16 dsl Exp $	*/
+/*	$NetBSD: fpu.h,v 1.2 2014/02/12 23:24:09 dsl Exp $	*/
 
-#ifndef	_AMD64_FPU_H_
-#define	_AMD64_FPU_H_
+#ifndef	_X86_FPU_H_
+#define	_X86_FPU_H_
 
 #include <x86/cpu_extended_state.h>
 
 #ifdef _KERNEL
-/*
- * XXX
- */
+
 struct trapframe;
 struct cpu_info;
 
 void fpuinit(struct cpu_info *);
-void fpudrop(void);
-void fpusave(struct lwp *);
-void fpudiscard(struct lwp *);
-void fputrap(struct trapframe *);
 void fpusave_lwp(struct lwp *, bool);
 void fpusave_cpu(bool);
 
+void fputrap(struct trapframe *);
+void fpudna(struct trapframe *);
+
+void process_xmm_to_s87(const struct fxsave *, struct save87 *);
+void process_s87_to_xmm(const struct save87 *, struct fxsave *);
+
 #endif
 
-#endif /* _AMD64_FPU_H_ */
+#endif /* _X86_FPU_H_ */
--- a/sys/arch/x86/x86/convert_xmm_s87.c	Wed Feb 12 23:04:43 2014 +0000
+++ b/sys/arch/x86/x86/convert_xmm_s87.c	Wed Feb 12 23:24:09 2014 +0000
@@ -1,4 +1,4 @@
-/*	$NetBSD: convert_xmm_s87.c,v 1.1 2014/02/07 22:40:22 dsl Exp $	*/
+/*	$NetBSD: convert_xmm_s87.c,v 1.2 2014/02/12 23:24:09 dsl Exp $	*/
 
 /*-
  * Copyright (c) 1998, 2000, 2001, 2008 The NetBSD Foundation, Inc.
@@ -30,12 +30,12 @@
  */
 
 #include <sys/cdefs.h>
-__KERNEL_RCSID(0, "$NetBSD: convert_xmm_s87.c,v 1.1 2014/02/07 22:40:22 dsl Exp $");
+__KERNEL_RCSID(0, "$NetBSD: convert_xmm_s87.c,v 1.2 2014/02/12 23:24:09 dsl Exp $");
 
 
 #include <sys/param.h>
 #include <sys/systm.h>
-#include <x86/cpu_extended_state.h>
+#include <x86/fpu.h>
 
 void
 process_xmm_to_s87(const struct fxsave *sxmm, struct save87 *s87)
--- a/sys/arch/x86/x86/fpu.c	Wed Feb 12 23:04:43 2014 +0000
+++ b/sys/arch/x86/x86/fpu.c	Wed Feb 12 23:24:09 2014 +0000
@@ -1,4 +1,4 @@
-/*	$NetBSD: fpu.c,v 1.2 2014/02/12 19:53:49 dsl Exp $	*/
+/*	$NetBSD: fpu.c,v 1.3 2014/02/12 23:24:09 dsl Exp $	*/
 
 /*-
  * Copyright (c) 2008 The NetBSD Foundation, Inc.  All
@@ -100,7 +100,7 @@
  */
 
 #include <sys/cdefs.h>
-__KERNEL_RCSID(0, "$NetBSD: fpu.c,v 1.2 2014/02/12 19:53:49 dsl Exp $");
+__KERNEL_RCSID(0, "$NetBSD: fpu.c,v 1.3 2014/02/12 23:24:09 dsl Exp $");
 
 #include "opt_multiprocessor.h"
 
@@ -118,8 +118,12 @@
 #include <machine/pcb.h>
 #include <machine/trap.h>
 #include <machine/specialreg.h>
+#include <x86/cpu.h>
 #include <x86/fpu.h>
 
+/* Check some duplicate definitions match */
+#include <machine/fenv.h>
+
 #ifdef XEN
 #define clts() HYPERVISOR_fpu_taskswitch(0)
 #define stts() HYPERVISOR_fpu_taskswitch(1)
@@ -131,7 +135,7 @@
  *
  * DNA exceptions are handled like this:
  *
- * 1) If there is no FPU, return and go to the emulator.
+ * 1) If there is no FPU, send SIGILL.
  * 2) If someone else has used the FPU, save its state into that lwp's PCB.
  * 3a) If MDL_USEDFPU is not set, set it and initialize the FPU.
  * 3b) Otherwise, reload the lwp's previous FPU state.
@@ -143,8 +147,6 @@
  * state is saved.
  */
 
-void fpudna(struct trapframe *frame);
-
 /* 
  * The following table is used to ensure that the FPE_... value
  * that is passed as a trapcode to the signal handler of the user
@@ -224,15 +226,58 @@
 
 /*
  * Init the FPU.
+ *
+ * This might not be structly necessary since it will be initialised
+ * for each process.  However it does no harm.
  */
 void
 fpuinit(struct cpu_info *ci)
 {
 	clts();
 	fninit();
+
+#if defined(__i386__) && !defined(XEN)
+	{
+		uint16_t control;
+
+		/* Read the default control word */
+		fnstcw(&control); 
+
+		if (control != __INITIAL_NPXCW__) {
+			/* Must be a 486SX, trap FP instructions */
+			lcr0((rcr0() & ~CR0_MP) | CR0_EM);
+			aprint_normal_dev(ci->ci_dev, "no fpu (control %x)\n",
+			    control);
+			i386_fpu_present = 0;
+			return;
+		}
+
+		if (npx586bug1(4195835, 3145727) != 0) {
+			/* NB 120+MHz cpus are not affected */
+			i386_fpu_fdivbug = 1;
+			aprint_normal_dev(ci->ci_dev,
+			    "WARNING: Pentium FDIV bug detected!\n");
+		}
+	}
+#endif
+
 	stts();
 }
 
+static void
+send_sigill(void *rip)
+{
+	/* No fpu (486SX) - send SIGILL */
+	ksiginfo_t ksi;
+
+	x86_enable_intr();
+	KSI_INIT_TRAP(&ksi);
+	ksi.ksi_signo = SIGILL;
+	ksi.ksi_addr = rip;
+	(*curlwp->l_proc->p_emul->e_trapsignal)(curlwp, &ksi);
+	return;
+}
+
 /*
  * This is a synchronous trap on either an x87 instruction (due to an
  * unmasked error on the previous x87 instruction) or on an SSE/SSE2 etc
@@ -268,6 +313,11 @@
 	if (!USERMODE(frame->tf_cs, frame->tf_eflags))
 		panic("fpu trap from kernel, trapframe %p\n", frame);
 
+	if (i386_fpu_present == 0) {
+		send_sigill((void *)X86_TF_RIP(frame));
+		return;
+	}
+
 	/*
 	 * At this point, fpcurlwp should be curlwp.  If it wasn't, the TS bit
 	 * should be set, and we should have gotten a DNA exception.
@@ -303,7 +353,7 @@
 
 	KSI_INIT_TRAP(&ksi);
 	ksi.ksi_signo = SIGFPE;
-	ksi.ksi_addr = (void *)frame->tf_rip;
+	ksi.ksi_addr = (void *)X86_TF_RIP(frame);
 	ksi.ksi_code = fpetable[statbits & 0x7f];
 	ksi.ksi_trap = statbits;
 	(*curlwp->l_proc->p_emul->e_trapsignal)(curlwp, &ksi);
@@ -322,14 +372,18 @@
 fpudna(struct trapframe *frame)
 {
 	struct cpu_info *ci;
-	uint16_t cw;
-	uint32_t mxcsr;
 	struct lwp *l, *fl;
 	struct pcb *pcb;
 	int s;
 
 	if (!USERMODE(frame->tf_cs, frame->tf_eflags))
-		panic("fpudna from kernel, trapframe %p\n", frame);
+		panic("fpudna from kernel, ip %p, trapframe %p\n",
+		    (void *)X86_TF_RIP(frame), frame);
+
+	if (i386_fpu_present == 0) {
+		send_sigill((void *)X86_TF_RIP(frame));
+		return;
+	}
 
 	ci = curcpu();
 
@@ -378,35 +432,35 @@
 	pcb->pcb_fpcpu = ci;
 	if ((l->l_md.md_flags & MDL_USEDFPU) == 0) {
 		fninit();
-		cw = pcb->pcb_savefpu.sv_xmm.fx_cw;
-		fldcw(&cw);
-		mxcsr = pcb->pcb_savefpu.sv_xmm.fx_mxcsr;
-		x86_ldmxcsr(&mxcsr);
+		if (i386_use_fxsave) {
+			fldcw(&pcb->pcb_savefpu.sv_xmm.fx_cw);
+			x86_ldmxcsr(&pcb->pcb_savefpu.sv_xmm.fx_mxcsr);
+		} else {
+			fldcw(&pcb->pcb_savefpu.sv_87.s87_cw);
+		}
 		l->l_md.md_flags |= MDL_USEDFPU;
-	} else {
+	} else if (i386_use_fxsave) {
 		/*
 		 * AMD FPU's do not restore FIP, FDP, and FOP on fxrstor,
 		 * leaking other process's execution history. Clear them
 		 * manually.
 		 */
-		static const double zero = 0.0;
-		uint16_t status;
 
 		/*
 		 * Clear the ES bit in the x87 status word if it is currently
 		 * set, in order to avoid causing a fault in the upcoming load.
 		 */
-		fnstsw(&status);
-		if (status & 0x80)
+		if (fngetsw() & 0x80)
 			fnclex();
 
 		/*
-		 * Load the dummy variable into the x87 stack.  This mangles
-		 * the x87 stack, but we don't care since we're about to call
-		 * fxrstor() anyway.
+		 * Load a zero into the x87 stack.  This mangles the x87 stack,
+		 * but we don't care since we're about to call fxrstor() anyway.
 		 */
-		fldummy(&zero);
+		fldummy();
 		fxrstor(&pcb->pcb_savefpu);
+	} else {
+		frstor(&pcb->pcb_savefpu.sv_87);
 	}
 
 	KASSERT(ci == curcpu());
@@ -434,7 +488,11 @@
 
 	if (save) {
 		clts();
-		fxsave(&pcb->pcb_savefpu);
+		if (i386_use_fxsave) {
+			fxsave(&pcb->pcb_savefpu);
+		} else {
+			fnsave(&pcb->pcb_savefpu.sv_87);
+		}
 	}
 
 	stts();
--- a/sys/arch/x86/x86/procfs_machdep.c	Wed Feb 12 23:04:43 2014 +0000
+++ b/sys/arch/x86/x86/procfs_machdep.c	Wed Feb 12 23:24:09 2014 +0000
@@ -1,4 +1,4 @@
-/*	$NetBSD: procfs_machdep.c,v 1.2 2014/02/02 22:41:20 dsl Exp $ */
+/*	$NetBSD: procfs_machdep.c,v 1.3 2014/02/12 23:24:09 dsl Exp $ */
 
 /*
  * Copyright (c) 2001 Wasabi Systems, Inc.
@@ -42,7 +42,7 @@
  */
 
 #include <sys/cdefs.h>
-__KERNEL_RCSID(0, "$NetBSD: procfs_machdep.c,v 1.2 2014/02/02 22:41:20 dsl Exp $");
+__KERNEL_RCSID(0, "$NetBSD: procfs_machdep.c,v 1.3 2014/02/12 23:24:09 dsl Exp $");
 
 #include <sys/param.h>
 #include <sys/systm.h>
@@ -56,7 +56,6 @@
 #include <machine/reg.h>
 #include <machine/specialreg.h>
 
-extern int	i386_fpu_present, i386_fpu_fdivbug;
 extern char	cpu_model[];
 
 static const char * const x86_features[] = {
@@ -214,13 +213,8 @@
 	    "cpuid level\t: %d\n"
 	    "wp\t\t: %s\n"
 	    "flags\t\t: %s\n",
-#ifdef __x86_64__
-	    "no",	/* XXX */
-	    "yes",	/* XXX */
-#else
-	    i386_fpu_fdivbug ? "yes" : "no",
-	    i386_fpu_present ? "yes" : "no",
-#endif
+	    i386_fpu_fdivbug ? "yes" : "no",	/* an old pentium */
+	    i386_fpu_present ? "yes" : "no",	/* not a 486SX */
 	    cpuid_level,
 	    (rcr0() & CR0_WP) ? "yes" : "no",
 	    featurebuf
--- a/sys/arch/xen/conf/files.xen	Wed Feb 12 23:04:43 2014 +0000
+++ b/sys/arch/xen/conf/files.xen	Wed Feb 12 23:24:09 2014 +0000
@@ -1,4 +1,4 @@
-#	$NetBSD: files.xen,v 1.132 2014/02/11 20:17:16 dsl Exp $
+#	$NetBSD: files.xen,v 1.133 2014/02/12 23:24:09 dsl Exp $
 #	NetBSD: files.x86,v 1.10 2003/10/08 17:30:00 bouyer Exp 
 #	NetBSD: files.i386,v 1.254 2004/03/25 23:32:10 jmc Exp 
 
@@ -55,9 +55,6 @@
 file	arch/i386/i386/trap.c
 file	arch/i386/i386/lock_stubs.S
 
-file	arch/i386/isa/npx.c
-
-
 file	arch/i386/i386/pmc.c			perfctrs
 
 file	crypto/des/arch/i386/des_enc.S		des
@@ -79,7 +76,6 @@
 file	arch/amd64/amd64/machdep.c
 file	arch/amd64/amd64/process_machdep.c
 file	arch/amd64/amd64/trap.c
-file	arch/x86/x86/fpu.c
 file	arch/amd64/amd64/lock_stubs.S
 endif
 
@@ -87,6 +83,7 @@
 file	arch/x86/x86/convert_xmm_s87.c
 file	arch/x86/x86/db_memrw.c		ddb | kgdb
 file	arch/x86/x86/db_trace.c		ddb
+file	arch/x86/x86/fpu.c
 file	arch/xen/x86/hypervisor_machdep.c
 # file 	arch/x86/x86/mtrr_i686.c	mtrr
 file	arch/x86/x86/syscall.c
--- a/sys/arch/xen/x86/cpu.c	Wed Feb 12 23:04:43 2014 +0000
+++ b/sys/arch/xen/x86/cpu.c	Wed Feb 12 23:24:09 2014 +0000
@@ -1,4 +1,4 @@
-/*	$NetBSD: cpu.c,v 1.97 2014/02/11 20:17:16 dsl Exp $	*/
+/*	$NetBSD: cpu.c,v 1.98 2014/02/12 23:24:09 dsl Exp $	*/
 /* NetBSD: cpu.c,v 1.18 2004/02/20 17:35:01 yamt Exp  */
 
 /*-
@@ -66,7 +66,7 @@
  */
 
 #include <sys/cdefs.h>
-__KERNEL_RCSID(0, "$NetBSD: cpu.c,v 1.97 2014/02/11 20:17:16 dsl Exp $");
+__KERNEL_RCSID(0, "$NetBSD: cpu.c,v 1.98 2014/02/12 23:24:09 dsl Exp $");
 
 #include "opt_ddb.h"
 #include "opt_multiprocessor.h"
@@ -102,11 +102,7 @@
 #include <machine/mtrr.h>
 #include <machine/pio.h>
 
-#ifdef i386
-#include <machine/npx.h>
-#else
 #include <x86/fpu.h>
-#endif
 
 #include <xen/xen.h>
 #include <xen/xen-public/vcpu.h>
--- a/sys/arch/xen/x86/xen_ipi.c	Wed Feb 12 23:04:43 2014 +0000
+++ b/sys/arch/xen/x86/xen_ipi.c	Wed Feb 12 23:24:09 2014 +0000
@@ -1,4 +1,4 @@
-/* $NetBSD: xen_ipi.c,v 1.16 2014/02/11 20:17:16 dsl Exp $ */
+/* $NetBSD: xen_ipi.c,v 1.17 2014/02/12 23:24:09 dsl Exp $ */
 
 /*-
  * Copyright (c) 2011 The NetBSD Foundation, Inc.
@@ -33,10 +33,10 @@
 
 /* 
  * Based on: x86/ipi.c
- * __KERNEL_RCSID(0, "$NetBSD: xen_ipi.c,v 1.16 2014/02/11 20:17:16 dsl Exp $"); 
+ * __KERNEL_RCSID(0, "$NetBSD: xen_ipi.c,v 1.17 2014/02/12 23:24:09 dsl Exp $"); 
  */
 
-__KERNEL_RCSID(0, "$NetBSD: xen_ipi.c,v 1.16 2014/02/11 20:17:16 dsl Exp $");
+__KERNEL_RCSID(0, "$NetBSD: xen_ipi.c,v 1.17 2014/02/12 23:24:09 dsl Exp $");
 
 #include <sys/types.h>
 
@@ -48,11 +48,7 @@
 #include <sys/errno.h>
 #include <sys/systm.h>
 
-#ifdef __x86_64__
 #include <x86/fpu.h>
-#else
-#include <machine/npx.h>
-#endif /* __x86_64__ */
 #include <machine/frame.h>
 #include <machine/segments.h>