Deleted Added
full compact
npx.c (78260) npx.c (79609)
1/*-
2 * Copyright (c) 1990 William Jolitz.
3 * Copyright (c) 1991 The Regents of the University of California.
4 * All rights reserved.
5 *
6 * Redistribution and use in source and binary forms, with or without
7 * modification, are permitted provided that the following conditions
8 * are met:

--- 18 unchanged lines hidden (view full) ---

27 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
28 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
29 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
30 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
31 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
32 * SUCH DAMAGE.
33 *
34 * from: @(#)npx.c 7.2 (Berkeley) 5/12/91
1/*-
2 * Copyright (c) 1990 William Jolitz.
3 * Copyright (c) 1991 The Regents of the University of California.
4 * All rights reserved.
5 *
6 * Redistribution and use in source and binary forms, with or without
7 * modification, are permitted provided that the following conditions
8 * are met:

--- 18 unchanged lines hidden (view full) ---

27 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
28 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
29 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
30 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
31 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
32 * SUCH DAMAGE.
33 *
34 * from: @(#)npx.c 7.2 (Berkeley) 5/12/91
35 * $FreeBSD: head/sys/i386/isa/npx.c 78260 2001-06-15 07:53:20Z peter $
35 * $FreeBSD: head/sys/i386/isa/npx.c 79609 2001-07-12 06:32:51Z peter $
36 */
37
36 */
37
38#include "opt_cpu.h"
38#include "opt_debug_npx.h"
39#include "opt_math_emulate.h"
40
41#include <sys/param.h>
42#include <sys/systm.h>
43#include <sys/bus.h>
44#include <sys/kernel.h>
45#include <sys/lock.h>

--- 48 unchanged lines hidden (view full) ---

94#define fldcw(addr) __asm("fldcw %0" : : "m" (*(addr)))
95#define fnclex() __asm("fnclex")
96#define fninit() __asm("fninit")
97#define fnsave(addr) __asm __volatile("fnsave %0" : "=m" (*(addr)))
98#define fnstcw(addr) __asm __volatile("fnstcw %0" : "=m" (*(addr)))
99#define fnstsw(addr) __asm __volatile("fnstsw %0" : "=m" (*(addr)))
100#define fp_divide_by_0() __asm("fldz; fld1; fdiv %st,%st(1); fnop")
101#define frstor(addr) __asm("frstor %0" : : "m" (*(addr)))
39#include "opt_debug_npx.h"
40#include "opt_math_emulate.h"
41
42#include <sys/param.h>
43#include <sys/systm.h>
44#include <sys/bus.h>
45#include <sys/kernel.h>
46#include <sys/lock.h>

--- 48 unchanged lines hidden (view full) ---

95#define fldcw(addr) __asm("fldcw %0" : : "m" (*(addr)))
96#define fnclex() __asm("fnclex")
97#define fninit() __asm("fninit")
98#define fnsave(addr) __asm __volatile("fnsave %0" : "=m" (*(addr)))
99#define fnstcw(addr) __asm __volatile("fnstcw %0" : "=m" (*(addr)))
100#define fnstsw(addr) __asm __volatile("fnstsw %0" : "=m" (*(addr)))
101#define fp_divide_by_0() __asm("fldz; fld1; fdiv %st,%st(1); fnop")
102#define frstor(addr) __asm("frstor %0" : : "m" (*(addr)))
103#define fxrstor(addr) __asm("fxrstor %0" : : "m" (*(addr)))
104#define fxsave(addr) __asm __volatile("fxsave %0" : "=m" (*(addr)))
102#define start_emulating() __asm("smsw %%ax; orb %0,%%al; lmsw %%ax" \
103 : : "n" (CR0_TS) : "ax")
104#define stop_emulating() __asm("clts")
105
106#else /* not __GNUC__ */
107
108void fldcw __P((caddr_t addr));
109void fnclex __P((void));
110void fninit __P((void));
111void fnsave __P((caddr_t addr));
112void fnstcw __P((caddr_t addr));
113void fnstsw __P((caddr_t addr));
114void fp_divide_by_0 __P((void));
115void frstor __P((caddr_t addr));
105#define start_emulating() __asm("smsw %%ax; orb %0,%%al; lmsw %%ax" \
106 : : "n" (CR0_TS) : "ax")
107#define stop_emulating() __asm("clts")
108
109#else /* not __GNUC__ */
110
111void fldcw __P((caddr_t addr));
112void fnclex __P((void));
113void fninit __P((void));
114void fnsave __P((caddr_t addr));
115void fnstcw __P((caddr_t addr));
116void fnstsw __P((caddr_t addr));
117void fp_divide_by_0 __P((void));
118void frstor __P((caddr_t addr));
119void fxsave __P((caddr_t addr));
120void fxrstor __P((caddr_t addr));
116void start_emulating __P((void));
117void stop_emulating __P((void));
118
119#endif /* __GNUC__ */
120
121void start_emulating __P((void));
122void stop_emulating __P((void));
123
124#endif /* __GNUC__ */
125
126#ifdef CPU_ENABLE_SSE
127#define GET_FPU_CW(proc) \
128 (cpu_fxsr ? \
129 (proc)->p_addr->u_pcb.pcb_save.sv_xmm.sv_env.en_cw : \
130 (proc)->p_addr->u_pcb.pcb_save.sv_87.sv_env.en_cw)
131#define GET_FPU_SW(proc) \
132 (cpu_fxsr ? \
133 (proc)->p_addr->u_pcb.pcb_save.sv_xmm.sv_env.en_sw : \
134 (proc)->p_addr->u_pcb.pcb_save.sv_87.sv_env.en_sw)
135#define MASK_FPU_SW(proc, mask) \
136 (cpu_fxsr ? \
137 (proc)->p_addr->u_pcb.pcb_save.sv_xmm.sv_env.en_sw & (mask) : \
138 (proc)->p_addr->u_pcb.pcb_save.sv_87.sv_env.en_sw & (mask))
139#define GET_FPU_EXSW_PTR(pcb) \
140 (cpu_fxsr ? \
141 &(pcb)->pcb_save.sv_xmm.sv_ex_sw : \
142 &(pcb)->pcb_save.sv_87.sv_ex_sw)
143#else /* CPU_ENABLE_SSE */
144#define GET_FPU_CW(proc) \
145 (proc->p_addr->u_pcb.pcb_save.sv_87.sv_env.en_cw)
146#define GET_FPU_SW(proc) \
147 (proc->p_addr->u_pcb.pcb_save.sv_87.sv_env.en_sw)
148#define MASK_FPU_SW(proc, mask) \
149 ((proc)->p_addr->u_pcb.pcb_save.sv_87.sv_env.en_sw & (mask))
150#define GET_FPU_EXSW_PTR(pcb) \
151 (&(pcb)->pcb_save.sv_87.sv_ex_sw)
152#endif /* CPU_ENABLE_SSE */
153
121typedef u_char bool_t;
122
123static int npx_attach __P((device_t dev));
124static void npx_identify __P((driver_t *driver, device_t parent));
125#ifndef SMP
126static void npx_intr __P((void *));
127#endif
128static int npx_probe __P((device_t dev));
129static int npx_probe1 __P((device_t dev));
154typedef u_char bool_t;
155
156static int npx_attach __P((device_t dev));
157static void npx_identify __P((driver_t *driver, device_t parent));
158#ifndef SMP
159static void npx_intr __P((void *));
160#endif
161static int npx_probe __P((device_t dev));
162static int npx_probe1 __P((device_t dev));
163static void fpusave __P((union savefpu *, u_char));
164static void fpurstor __P((union savefpu *, u_char));
130#ifdef I586_CPU_XXX
131static long timezero __P((const char *funcname,
132 void (*func)(void *buf, size_t len)));
133#endif /* I586_CPU */
134
135int hw_float; /* XXX currently just alias for npx_exists */
136
137SYSCTL_INT(_hw,HW_FLOATINGPT, floatingpoint,

--- 386 unchanged lines hidden (view full) ---

524
525/*
526 * Initialize floating point unit.
527 */
528void
529npxinit(control)
530 u_short control;
531{
165#ifdef I586_CPU_XXX
166static long timezero __P((const char *funcname,
167 void (*func)(void *buf, size_t len)));
168#endif /* I586_CPU */
169
170int hw_float; /* XXX currently just alias for npx_exists */
171
172SYSCTL_INT(_hw,HW_FLOATINGPT, floatingpoint,

--- 386 unchanged lines hidden (view full) ---

559
560/*
561 * Initialize floating point unit.
562 */
563void
564npxinit(control)
565 u_short control;
566{
532 struct save87 dummy;
567 union savefpu dummy;
533 critical_t savecrit;
534
535 if (!npx_exists)
536 return;
537 /*
538 * fninit has the same h/w bugs as fnsave. Use the detoxified
539 * fnsave to throw away any junk in the fpu. npxsave() initializes
540 * the fpu and sets npxproc = NULL as important side effects.
541 */
542 savecrit = critical_enter();
543 npxsave(&dummy);
544 stop_emulating();
545 fldcw(&control);
546 if (PCPU_GET(curpcb) != NULL)
568 critical_t savecrit;
569
570 if (!npx_exists)
571 return;
572 /*
573 * fninit has the same h/w bugs as fnsave. Use the detoxified
574 * fnsave to throw away any junk in the fpu. npxsave() initializes
575 * the fpu and sets npxproc = NULL as important side effects.
576 */
577 savecrit = critical_enter();
578 npxsave(&dummy);
579 stop_emulating();
580 fldcw(&control);
581 if (PCPU_GET(curpcb) != NULL)
547 fnsave(&PCPU_GET(curpcb)->pcb_savefpu);
582 fpusave(&PCPU_GET(curpcb)->pcb_save, curproc->p_oncpu);
548 start_emulating();
549 critical_exit(savecrit);
550}
551
552/*
553 * Free coprocessor (if we have it).
554 */
555void
556npxexit(p)
557 struct proc *p;
558{
559 critical_t savecrit;
560
561 savecrit = critical_enter();
562 if (p == PCPU_GET(npxproc))
583 start_emulating();
584 critical_exit(savecrit);
585}
586
587/*
588 * Free coprocessor (if we have it).
589 */
590void
591npxexit(p)
592 struct proc *p;
593{
594 critical_t savecrit;
595
596 savecrit = critical_enter();
597 if (p == PCPU_GET(npxproc))
563 npxsave(&PCPU_GET(curpcb)->pcb_savefpu);
598 npxsave(&PCPU_GET(curpcb)->pcb_save);
564 critical_exit(savecrit);
565#ifdef NPX_DEBUG
566 if (npx_exists) {
567 u_int masked_exceptions;
568
569 masked_exceptions = PCPU_GET(curpcb)->pcb_savefpu.sv_env.en_cw
570 & PCPU_GET(curpcb)->pcb_savefpu.sv_env.en_sw & 0x7f;
571 /*

--- 196 unchanged lines hidden (view full) ---

768 * destroyed by IRQ13 bugs. Clearing FP exceptions is not an acceptable
769 * solution for signals other than SIGFPE.
770 */
771int
772npxtrap()
773{
774 critical_t savecrit;
775 u_short control, status;
599 critical_exit(savecrit);
600#ifdef NPX_DEBUG
601 if (npx_exists) {
602 u_int masked_exceptions;
603
604 masked_exceptions = PCPU_GET(curpcb)->pcb_savefpu.sv_env.en_cw
605 & PCPU_GET(curpcb)->pcb_savefpu.sv_env.en_sw & 0x7f;
606 /*

--- 196 unchanged lines hidden (view full) ---

803 * destroyed by IRQ13 bugs. Clearing FP exceptions is not an acceptable
804 * solution for signals other than SIGFPE.
805 */
806int
807npxtrap()
808{
809 critical_t savecrit;
810 u_short control, status;
811 u_long *exstat;
776
777 if (!npx_exists) {
778 printf("npxtrap: npxproc = %p, curproc = %p, npx_exists = %d\n",
779 PCPU_GET(npxproc), curproc, npx_exists);
780 panic("npxtrap from nowhere");
781 }
782 savecrit = critical_enter();
783
784 /*
785 * Interrupt handling (for another interrupt) may have pushed the
786 * state to memory. Fetch the relevant parts of the state from
787 * wherever they are.
788 */
789 if (PCPU_GET(npxproc) != curproc) {
812
813 if (!npx_exists) {
814 printf("npxtrap: npxproc = %p, curproc = %p, npx_exists = %d\n",
815 PCPU_GET(npxproc), curproc, npx_exists);
816 panic("npxtrap from nowhere");
817 }
818 savecrit = critical_enter();
819
820 /*
821 * Interrupt handling (for another interrupt) may have pushed the
822 * state to memory. Fetch the relevant parts of the state from
823 * wherever they are.
824 */
825 if (PCPU_GET(npxproc) != curproc) {
790 control = curproc->p_addr->u_pcb.pcb_savefpu.sv_env.en_cw;
791 status = curproc->p_addr->u_pcb.pcb_savefpu.sv_env.en_sw;
826 control = GET_FPU_CW(curproc);
827 status = GET_FPU_SW(curproc);
792 } else {
793 fnstcw(&control);
794 fnstsw(&status);
795 }
796
828 } else {
829 fnstcw(&control);
830 fnstsw(&status);
831 }
832
797 curproc->p_addr->u_pcb.pcb_savefpu.sv_ex_sw = status;
833 exstat = GET_FPU_EXSW_PTR(&curproc->p_addr->u_pcb);
834 *exstat = status;
798 if (PCPU_GET(npxproc) != curproc)
835 if (PCPU_GET(npxproc) != curproc)
799 curproc->p_addr->u_pcb.pcb_savefpu.sv_env.en_sw &= ~0x80bf;
836 MASK_FPU_SW(curproc, ~0x80bf);
800 else
801 fnclex();
802 critical_exit(savecrit);
803 return (fpetable[status & ((~control & 0x3f) | 0x40)]);
804}
805
806/*
807 * Implement device not available (DNA) exception
808 *
809 * It would be better to switch FP context here (if curproc != npxproc)
810 * and not necessarily for every context switch, but it is too hard to
811 * access foreign pcb's.
812 */
813int
814npxdna()
815{
837 else
838 fnclex();
839 critical_exit(savecrit);
840 return (fpetable[status & ((~control & 0x3f) | 0x40)]);
841}
842
843/*
844 * Implement device not available (DNA) exception
845 *
846 * It would be better to switch FP context here (if curproc != npxproc)
847 * and not necessarily for every context switch, but it is too hard to
848 * access foreign pcb's.
849 */
850int
851npxdna()
852{
853 u_long *exstat;
816 critical_t s;
817
818 if (!npx_exists)
819 return (0);
820 if (PCPU_GET(npxproc) != NULL) {
821 printf("npxdna: npxproc = %p, curproc = %p\n",
822 PCPU_GET(npxproc), curproc);
823 panic("npxdna");
824 }
825 s = critical_enter();
826 stop_emulating();
827 /*
828 * Record new context early in case frstor causes an IRQ13.
829 */
830 PCPU_SET(npxproc, CURPROC);
854 critical_t s;
855
856 if (!npx_exists)
857 return (0);
858 if (PCPU_GET(npxproc) != NULL) {
859 printf("npxdna: npxproc = %p, curproc = %p\n",
860 PCPU_GET(npxproc), curproc);
861 panic("npxdna");
862 }
863 s = critical_enter();
864 stop_emulating();
865 /*
866 * Record new context early in case frstor causes an IRQ13.
867 */
868 PCPU_SET(npxproc, CURPROC);
831 PCPU_GET(curpcb)->pcb_savefpu.sv_ex_sw = 0;
869
870 exstat = GET_FPU_EXSW_PTR(PCPU_GET(curpcb));
871 *exstat = 0;
832 /*
833 * The following frstor may cause an IRQ13 when the state being
834 * restored has a pending error. The error will appear to have been
835 * triggered by the current (npx) user instruction even when that
836 * instruction is a no-wait instruction that should not trigger an
837 * error (e.g., fnclex). On at least one 486 system all of the
838 * no-wait instructions are broken the same as frstor, so our
839 * treatment does not amplify the breakage. On at least one
840 * 386/Cyrix 387 system, fnclex works correctly while frstor and
841 * fnsave are broken, so our treatment breaks fnclex if it is the
842 * first FPU instruction after a context switch.
843 */
872 /*
873 * The following frstor may cause an IRQ13 when the state being
874 * restored has a pending error. The error will appear to have been
875 * triggered by the current (npx) user instruction even when that
876 * instruction is a no-wait instruction that should not trigger an
877 * error (e.g., fnclex). On at least one 486 system all of the
878 * no-wait instructions are broken the same as frstor, so our
879 * treatment does not amplify the breakage. On at least one
880 * 386/Cyrix 387 system, fnclex works correctly while frstor and
881 * fnsave are broken, so our treatment breaks fnclex if it is the
882 * first FPU instruction after a context switch.
883 */
844 frstor(&PCPU_GET(curpcb)->pcb_savefpu);
884 fpurstor(&PCPU_GET(curpcb)->pcb_save, curproc->p_oncpu);
845 critical_exit(s);
846
847 return (1);
848}
849
850/*
851 * Wrapper for fnsave instruction, partly to handle hardware bugs. When npx
852 * exceptions are reported via IRQ13, spurious IRQ13's may be triggered by

--- 14 unchanged lines hidden (view full) ---

867 *
868 * A previous version of npxsave() went to great lengths to excecute fnsave
869 * with interrupts enabled in case executing it froze the CPU. This case
870 * can't happen, at least for Intel CPU/NPX's. Spurious IRQ13's don't imply
871 * spurious freezes.
872 */
873void
874npxsave(addr)
885 critical_exit(s);
886
887 return (1);
888}
889
890/*
891 * Wrapper for fnsave instruction, partly to handle hardware bugs. When npx
892 * exceptions are reported via IRQ13, spurious IRQ13's may be triggered by

--- 14 unchanged lines hidden (view full) ---

907 *
908 * A previous version of npxsave() went to great lengths to excecute fnsave
909 * with interrupts enabled in case executing it froze the CPU. This case
910 * can't happen, at least for Intel CPU/NPX's. Spurious IRQ13's don't imply
911 * spurious freezes.
912 */
913void
914npxsave(addr)
875 struct save87 *addr;
915 union savefpu *addr;
876{
877
878 stop_emulating();
916{
917
918 stop_emulating();
879 fnsave(addr);
919 fpusave(addr, curproc->p_oncpu);
920
880 start_emulating();
881 PCPU_SET(npxproc, NULL);
882}
883
921 start_emulating();
922 PCPU_SET(npxproc, NULL);
923}
924
925static void
926fpusave(addr, oncpu)
927 union savefpu *addr;
928 u_char oncpu;
929{
930 static struct savexmm svxmm[MAXCPU];
931
932 if (!cpu_fxsr)
933 fnsave(addr);
934 else {
935 fxsave(&svxmm[oncpu]);
936 bcopy(&svxmm[oncpu], addr, sizeof(struct savexmm));
937 }
938}
939
940static void
941fpurstor(addr, oncpu)
942 union savefpu *addr;
943 u_char oncpu;
944{
945 static struct savexmm svxmm[MAXCPU];
946
947 if (!cpu_fxsr)
948 frstor(addr);
949 else {
950 bcopy(addr, &svxmm[oncpu], sizeof (struct savexmm));
951 fxrstor(&svxmm[oncpu]);
952 }
953}
954
884#ifdef I586_CPU_XXX
885static long
886timezero(funcname, func)
887 const char *funcname;
888 void (*func) __P((void *buf, size_t len));
889
890{
891 void *buf;

--- 95 unchanged lines hidden ---
955#ifdef I586_CPU_XXX
956static long
957timezero(funcname, func)
958 const char *funcname;
959 void (*func) __P((void *buf, size_t len));
960
961{
962 void *buf;

--- 95 unchanged lines hidden ---