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 --- |