|
Lines 29-46
Link Here
|
| 29 |
* HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT |
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 |
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 |
31 |
* OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF |
| 32 |
* SUCH DAMAGE. |
32 |
* SUCH DAMAGE. |
| 33 |
* |
33 |
* |
| 34 |
* from: @(#)npx.c 7.2 (Berkeley) 5/12/91 |
34 |
* from: @(#)npx.c 7.2 (Berkeley) 5/12/91 |
| 35 |
* $FreeBSD: src/sys/i386/isa/npx.c,v 1.101 2001/05/22 21:20:49 bde Exp $ |
35 |
* $FreeBSD: src/sys/i386/isa/npx.c,v 1.101 2001/05/22 21:20:49 bde Exp $ |
| 36 |
*/ |
36 |
*/ |
| 37 |
|
37 |
|
|
|
38 |
#include "opt_cpu.h" |
| 38 |
#include "opt_debug_npx.h" |
39 |
#include "opt_debug_npx.h" |
| 39 |
#include "opt_math_emulate.h" |
40 |
#include "opt_math_emulate.h" |
| 40 |
|
41 |
|
| 41 |
#include <sys/param.h> |
42 |
#include <sys/param.h> |
| 42 |
#include <sys/systm.h> |
43 |
#include <sys/systm.h> |
| 43 |
#include <sys/bus.h> |
44 |
#include <sys/bus.h> |
| 44 |
#include <sys/kernel.h> |
45 |
#include <sys/kernel.h> |
| 45 |
#include <sys/lock.h> |
46 |
#include <sys/lock.h> |
| 46 |
#include <sys/malloc.h> |
47 |
#include <sys/malloc.h> |
|
Lines 93-138
Link Here
|
| 93 |
|
94 |
|
| 94 |
#define fldcw(addr) __asm("fldcw %0" : : "m" (*(addr))) |
95 |
#define fldcw(addr) __asm("fldcw %0" : : "m" (*(addr))) |
| 95 |
#define fnclex() __asm("fnclex") |
96 |
#define fnclex() __asm("fnclex") |
| 96 |
#define fninit() __asm("fninit") |
97 |
#define fninit() __asm("fninit") |
| 97 |
#define fnsave(addr) __asm __volatile("fnsave %0" : "=m" (*(addr))) |
98 |
#define fnsave(addr) __asm __volatile("fnsave %0" : "=m" (*(addr))) |
| 98 |
#define fnstcw(addr) __asm __volatile("fnstcw %0" : "=m" (*(addr))) |
99 |
#define fnstcw(addr) __asm __volatile("fnstcw %0" : "=m" (*(addr))) |
| 99 |
#define fnstsw(addr) __asm __volatile("fnstsw %0" : "=m" (*(addr))) |
100 |
#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 fp_divide_by_0() __asm("fldz; fld1; fdiv %st,%st(1); fnop") |
| 101 |
#define frstor(addr) __asm("frstor %0" : : "m" (*(addr))) |
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" \ |
105 |
#define start_emulating() __asm("smsw %%ax; orb %0,%%al; lmsw %%ax" \ |
| 103 |
: : "n" (CR0_TS) : "ax") |
106 |
: : "n" (CR0_TS) : "ax") |
| 104 |
#define stop_emulating() __asm("clts") |
107 |
#define stop_emulating() __asm("clts") |
| 105 |
|
108 |
|
| 106 |
#else /* not __GNUC__ */ |
109 |
#else /* not __GNUC__ */ |
| 107 |
|
110 |
|
| 108 |
void fldcw __P((caddr_t addr)); |
111 |
void fldcw __P((caddr_t addr)); |
| 109 |
void fnclex __P((void)); |
112 |
void fnclex __P((void)); |
| 110 |
void fninit __P((void)); |
113 |
void fninit __P((void)); |
| 111 |
void fnsave __P((caddr_t addr)); |
114 |
void fnsave __P((caddr_t addr)); |
| 112 |
void fnstcw __P((caddr_t addr)); |
115 |
void fnstcw __P((caddr_t addr)); |
| 113 |
void fnstsw __P((caddr_t addr)); |
116 |
void fnstsw __P((caddr_t addr)); |
| 114 |
void fp_divide_by_0 __P((void)); |
117 |
void fp_divide_by_0 __P((void)); |
| 115 |
void frstor __P((caddr_t addr)); |
118 |
void frstor __P((caddr_t addr)); |
|
|
119 |
void fxsave __P((caddr_t addr)); |
| 120 |
void fxrstor __P((caddr_t addr)); |
| 116 |
void start_emulating __P((void)); |
121 |
void start_emulating __P((void)); |
| 117 |
void stop_emulating __P((void)); |
122 |
void stop_emulating __P((void)); |
| 118 |
|
123 |
|
| 119 |
#endif /* __GNUC__ */ |
124 |
#endif /* __GNUC__ */ |
| 120 |
|
125 |
|
|
|
126 |
#ifdef CPU_ENABLE_SSE |
| 127 |
#define FPU_STATUS_EX(pcb) \ |
| 128 |
(cpu_fxsr ? \ |
| 129 |
&(pcb)->pcb_save.sv_xmm.sv_ex_sw : \ |
| 130 |
&(pcb)->pcb_save.sv_87.sv_ex_sw) |
| 131 |
#else /* CPU_ENABLE_SSE */ |
| 132 |
#define FPU_STATUS_EX(pcb) (&(pcb)->pcb_save.sv_87.sv_ex_sw) |
| 133 |
#endif /* CPU_ENABLE_SSE */ |
| 134 |
|
| 121 |
typedef u_char bool_t; |
135 |
typedef u_char bool_t; |
| 122 |
|
136 |
|
| 123 |
static int npx_attach __P((device_t dev)); |
137 |
static int npx_attach __P((device_t dev)); |
| 124 |
static void npx_identify __P((driver_t *driver, device_t parent)); |
138 |
static void npx_identify __P((driver_t *driver, device_t parent)); |
| 125 |
#ifndef SMP |
139 |
#ifndef SMP |
| 126 |
static void npx_intr __P((void *)); |
140 |
static void npx_intr __P((void *)); |
| 127 |
#endif |
141 |
#endif |
| 128 |
static int npx_probe __P((device_t dev)); |
142 |
static int npx_probe __P((device_t dev)); |
| 129 |
static int npx_probe1 __P((device_t dev)); |
143 |
static int npx_probe1 __P((device_t dev)); |
|
|
144 |
static void fpusave __P((union savefpu *)); |
| 145 |
static void fpurstor __P((union savefpu *)); |
| 130 |
#ifdef I586_CPU |
146 |
#ifdef I586_CPU |
| 131 |
static long timezero __P((const char *funcname, |
147 |
static long timezero __P((const char *funcname, |
| 132 |
void (*func)(void *buf, size_t len))); |
148 |
void (*func)(void *buf, size_t len))); |
| 133 |
#endif /* I586_CPU */ |
149 |
#endif /* I586_CPU */ |
| 134 |
|
150 |
|
| 135 |
int hw_float; /* XXX currently just alias for npx_exists */ |
151 |
int hw_float; /* XXX currently just alias for npx_exists */ |
| 136 |
|
152 |
|
| 137 |
SYSCTL_INT(_hw,HW_FLOATINGPT, floatingpoint, |
153 |
SYSCTL_INT(_hw,HW_FLOATINGPT, floatingpoint, |
| 138 |
CTLFLAG_RD, &hw_float, 0, |
154 |
CTLFLAG_RD, &hw_float, 0, |
|
Lines 197-214
Link Here
|
| 197 |
|
213 |
|
| 198 |
child = BUS_ADD_CHILD(parent, 0, "npx", 0); |
214 |
child = BUS_ADD_CHILD(parent, 0, "npx", 0); |
| 199 |
if (child == NULL) |
215 |
if (child == NULL) |
| 200 |
panic("npx_identify"); |
216 |
panic("npx_identify"); |
| 201 |
} |
217 |
} |
| 202 |
|
218 |
|
| 203 |
#ifndef SMP |
219 |
#ifndef SMP |
| 204 |
/* |
220 |
/* |
| 205 |
* Do minimal handling of npx interrupts to convert them to traps. |
221 |
* Do minimal handling of npx interrupts to convert them to traps. |
|
|
222 |
* |
| 223 |
* (2001/06/10) kaz@kobe1995 TODO: FPU STATUS |
| 206 |
*/ |
224 |
*/ |
| 207 |
static void |
225 |
static void |
| 208 |
npx_intr(dummy) |
226 |
npx_intr(dummy) |
| 209 |
void *dummy; |
227 |
void *dummy; |
| 210 |
{ |
228 |
{ |
| 211 |
struct proc *p; |
229 |
struct proc *p; |
| 212 |
|
230 |
|
| 213 |
/* |
231 |
/* |
| 214 |
* The BUSY# latch must be cleared in all cases so that the next |
232 |
* The BUSY# latch must be cleared in all cases so that the next |
|
Lines 523-579
Link Here
|
| 523 |
} |
541 |
} |
| 524 |
|
542 |
|
| 525 |
/* |
543 |
/* |
| 526 |
* Initialize floating point unit. |
544 |
* Initialize floating point unit. |
| 527 |
*/ |
545 |
*/ |
| 528 |
void |
546 |
void |
| 529 |
npxinit(control) |
547 |
npxinit(control) |
| 530 |
u_short control; |
548 |
u_short control; |
| 531 |
{ |
549 |
{ |
| 532 |
struct save87 dummy; |
550 |
union savefpu dummy; |
| 533 |
critical_t savecrit; |
551 |
critical_t savecrit; |
| 534 |
|
552 |
|
| 535 |
if (!npx_exists) |
553 |
if (!npx_exists) |
| 536 |
return; |
554 |
return; |
| 537 |
/* |
555 |
/* |
| 538 |
* fninit has the same h/w bugs as fnsave. Use the detoxified |
556 |
* fninit has the same h/w bugs as fnsave. Use the detoxified |
| 539 |
* fnsave to throw away any junk in the fpu. npxsave() initializes |
557 |
* fnsave to throw away any junk in the fpu. npxsave() initializes |
| 540 |
* the fpu and sets npxproc = NULL as important side effects. |
558 |
* the fpu and sets npxproc = NULL as important side effects. |
| 541 |
*/ |
559 |
*/ |
| 542 |
savecrit = critical_enter(); |
560 |
savecrit = critical_enter(); |
| 543 |
npxsave(&dummy); |
561 |
npxsave(&dummy); |
| 544 |
stop_emulating(); |
562 |
stop_emulating(); |
| 545 |
fldcw(&control); |
563 |
fldcw(&control); |
| 546 |
if (PCPU_GET(curpcb) != NULL) |
564 |
if (PCPU_GET(curpcb) != NULL) |
| 547 |
fnsave(&PCPU_GET(curpcb)->pcb_savefpu); |
565 |
fpusave(&PCPU_GET(curpcb)->pcb_save); |
| 548 |
start_emulating(); |
566 |
start_emulating(); |
| 549 |
critical_exit(savecrit); |
567 |
critical_exit(savecrit); |
| 550 |
} |
568 |
} |
| 551 |
|
569 |
|
| 552 |
/* |
570 |
/* |
| 553 |
* Free coprocessor (if we have it). |
571 |
* Free coprocessor (if we have it). |
| 554 |
*/ |
572 |
*/ |
| 555 |
void |
573 |
void |
| 556 |
npxexit(p) |
574 |
npxexit(p) |
| 557 |
struct proc *p; |
575 |
struct proc *p; |
| 558 |
{ |
576 |
{ |
| 559 |
critical_t savecrit; |
577 |
critical_t savecrit; |
| 560 |
|
578 |
|
| 561 |
savecrit = critical_enter(); |
579 |
savecrit = critical_enter(); |
| 562 |
if (p == PCPU_GET(npxproc)) |
580 |
if (p == PCPU_GET(npxproc)) |
| 563 |
npxsave(&PCPU_GET(curpcb)->pcb_savefpu); |
581 |
npxsave(&PCPU_GET(curpcb)->pcb_save); |
| 564 |
critical_exit(savecrit); |
582 |
critical_exit(savecrit); |
| 565 |
#ifdef NPX_DEBUG |
583 |
#ifdef NPX_DEBUG |
| 566 |
if (npx_exists) { |
584 |
if (npx_exists) { |
| 567 |
u_int masked_exceptions; |
585 |
u_int masked_exceptions; |
| 568 |
|
586 |
|
| 569 |
masked_exceptions = PCPU_GET(curpcb)->pcb_savefpu.sv_env.en_cw |
587 |
masked_exceptions = PCPU_GET(curpcb)->pcb_save.sv_env.en_cw |
| 570 |
& PCPU_GET(curpcb)->pcb_savefpu.sv_env.en_sw & 0x7f; |
588 |
& PCPU_GET(curpcb)->pcb_save.sv_env.en_sw & 0x7f; |
| 571 |
/* |
589 |
/* |
| 572 |
* Log exceptions that would have trapped with the old |
590 |
* Log exceptions that would have trapped with the old |
| 573 |
* control word (overflow, divide by 0, and invalid operand). |
591 |
* control word (overflow, divide by 0, and invalid operand). |
| 574 |
*/ |
592 |
*/ |
| 575 |
if (masked_exceptions & 0x0d) |
593 |
if (masked_exceptions & 0x0d) |
| 576 |
log(LOG_ERR, |
594 |
log(LOG_ERR, |
| 577 |
"pid %d (%s) exited with masked floating point exceptions 0x%02x\n", |
595 |
"pid %d (%s) exited with masked floating point exceptions 0x%02x\n", |
| 578 |
p->p_pid, p->p_comm, masked_exceptions); |
596 |
p->p_pid, p->p_comm, masked_exceptions); |
| 579 |
} |
597 |
} |
|
Lines 807-853
Link Here
|
| 807 |
* Implement device not available (DNA) exception |
825 |
* Implement device not available (DNA) exception |
| 808 |
* |
826 |
* |
| 809 |
* It would be better to switch FP context here (if curproc != npxproc) |
827 |
* 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 |
828 |
* and not necessarily for every context switch, but it is too hard to |
| 811 |
* access foreign pcb's. |
829 |
* access foreign pcb's. |
| 812 |
*/ |
830 |
*/ |
| 813 |
int |
831 |
int |
| 814 |
npxdna() |
832 |
npxdna() |
| 815 |
{ |
833 |
{ |
|
|
834 |
/* u_long *pstatus; kaz@kobe1995 */ |
| 816 |
critical_t s; |
835 |
critical_t s; |
| 817 |
|
836 |
|
| 818 |
if (!npx_exists) |
837 |
if (!npx_exists) |
| 819 |
return (0); |
838 |
return (0); |
| 820 |
if (PCPU_GET(npxproc) != NULL) { |
839 |
if (PCPU_GET(npxproc) != NULL) { |
| 821 |
printf("npxdna: npxproc = %p, curproc = %p\n", |
840 |
printf("npxdna: npxproc = %p, curproc = %p\n", |
| 822 |
PCPU_GET(npxproc), curproc); |
841 |
PCPU_GET(npxproc), curproc); |
| 823 |
panic("npxdna"); |
842 |
panic("npxdna"); |
| 824 |
} |
843 |
} |
| 825 |
s = critical_enter(); |
844 |
s = critical_enter(); |
| 826 |
stop_emulating(); |
845 |
stop_emulating(); |
| 827 |
/* |
846 |
/* |
| 828 |
* Record new context early in case frstor causes an IRQ13. |
847 |
* Record new context early in case frstor causes an IRQ13. |
| 829 |
*/ |
848 |
*/ |
| 830 |
PCPU_SET(npxproc, CURPROC); |
849 |
PCPU_SET(npxproc, CURPROC); |
| 831 |
PCPU_GET(curpcb)->pcb_savefpu.sv_ex_sw = 0; |
850 |
PCPU_GET(curpcb)->pcb_savefpu.sv_ex_sw = 0; /* kaz@kobe1995 */ |
|
|
851 |
/* pstatus = FPU_STATUS_EX(curpcb); |
| 852 |
*pstatus = 0; kaz@kobe1995 */ |
| 853 |
|
| 832 |
/* |
854 |
/* |
| 833 |
* The following frstor may cause an IRQ13 when the state being |
855 |
* The following frstor may cause an IRQ13 when the state being |
| 834 |
* restored has a pending error. The error will appear to have been |
856 |
* restored has a pending error. The error will appear to have been |
| 835 |
* triggered by the current (npx) user instruction even when that |
857 |
* triggered by the current (npx) user instruction even when that |
| 836 |
* instruction is a no-wait instruction that should not trigger an |
858 |
* 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 |
859 |
* 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 |
860 |
* no-wait instructions are broken the same as frstor, so our |
| 839 |
* treatment does not amplify the breakage. On at least one |
861 |
* treatment does not amplify the breakage. On at least one |
| 840 |
* 386/Cyrix 387 system, fnclex works correctly while frstor and |
862 |
* 386/Cyrix 387 system, fnclex works correctly while frstor and |
| 841 |
* fnsave are broken, so our treatment breaks fnclex if it is the |
863 |
* fnsave are broken, so our treatment breaks fnclex if it is the |
| 842 |
* first FPU instruction after a context switch. |
864 |
* first FPU instruction after a context switch. |
| 843 |
*/ |
865 |
*/ |
| 844 |
frstor(&PCPU_GET(curpcb)->pcb_savefpu); |
866 |
fpurstor(&PCPU_GET(curpcb)->pcb_save); |
| 845 |
critical_exit(s); |
867 |
critical_exit(s); |
| 846 |
|
868 |
|
| 847 |
return (1); |
869 |
return (1); |
| 848 |
} |
870 |
} |
| 849 |
|
871 |
|
| 850 |
/* |
872 |
/* |
| 851 |
* Wrapper for fnsave instruction, partly to handle hardware bugs. When npx |
873 |
* Wrapper for fnsave instruction, partly to handle hardware bugs. When npx |
| 852 |
* exceptions are reported via IRQ13, spurious IRQ13's may be triggered by |
874 |
* exceptions are reported via IRQ13, spurious IRQ13's may be triggered by |
| 853 |
* no-wait npx instructions. See the Intel application note AP-578 for |
875 |
* no-wait npx instructions. See the Intel application note AP-578 for |
|
Lines 866-890
Link Here
|
| 866 |
* npxsave() atomically with checking npxproc. |
888 |
* npxsave() atomically with checking npxproc. |
| 867 |
* |
889 |
* |
| 868 |
* A previous version of npxsave() went to great lengths to excecute fnsave |
890 |
* 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 |
891 |
* 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 |
892 |
* can't happen, at least for Intel CPU/NPX's. Spurious IRQ13's don't imply |
| 871 |
* spurious freezes. |
893 |
* spurious freezes. |
| 872 |
*/ |
894 |
*/ |
| 873 |
void |
895 |
void |
| 874 |
npxsave(addr) |
896 |
npxsave(addr) |
| 875 |
struct save87 *addr; |
897 |
union savefpu *addr; |
| 876 |
{ |
898 |
{ |
| 877 |
|
899 |
|
| 878 |
stop_emulating(); |
900 |
stop_emulating(); |
| 879 |
fnsave(addr); |
901 |
fpusave(addr); |
| 880 |
start_emulating(); |
902 |
start_emulating(); |
| 881 |
PCPU_SET(npxproc, NULL); |
903 |
PCPU_SET(npxproc, NULL); |
|
|
904 |
} |
| 905 |
|
| 906 |
static void |
| 907 |
fpusave(addr) |
| 908 |
union savefpu *addr; |
| 909 |
{ |
| 910 |
#ifdef CPU_ENABLE_SSE |
| 911 |
static struct savexmm svxmm __attribute__((aligned(16))); |
| 912 |
|
| 913 |
if (cpu_fxsr) { |
| 914 |
fxsave(&svxmm); |
| 915 |
bcopy(&svxmm, addr, sizeof(struct savexmm)); |
| 916 |
return; |
| 917 |
} |
| 918 |
#endif /* CPU_ENABLE_SSE */ |
| 919 |
fnsave(addr); |
| 920 |
} |
| 921 |
|
| 922 |
static void |
| 923 |
fpurstor(addr) |
| 924 |
union savefpu *addr; |
| 925 |
{ |
| 926 |
#ifdef CPU_ENABLE_SSE |
| 927 |
static struct savexmm svxmm __attribute__((aligned(16))); |
| 928 |
|
| 929 |
if (cpu_fxsr) { |
| 930 |
bcopy(addr, &svxmm, sizeof (struct savexmm)); |
| 931 |
fxrstor(&svxmm); |
| 932 |
return; |
| 933 |
} |
| 934 |
#endif /* CPU_ENABLE_SSE */ |
| 935 |
frstor(addr); |
| 882 |
} |
936 |
} |
| 883 |
|
937 |
|
| 884 |
#ifdef I586_CPU |
938 |
#ifdef I586_CPU |
| 885 |
static long |
939 |
static long |
| 886 |
timezero(funcname, func) |
940 |
timezero(funcname, func) |
| 887 |
const char *funcname; |
941 |
const char *funcname; |
| 888 |
void (*func) __P((void *buf, size_t len)); |
942 |
void (*func) __P((void *buf, size_t len)); |
| 889 |
|
943 |
|
| 890 |
{ |
944 |
{ |
| 891 |
- |
|
|