|
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.80 2000/01/29 16:17:36 peter Exp $ |
35 |
* $FreeBSD: src/sys/i386/isa/npx.c,v 1.80 2000/01/29 16:17:36 peter 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/malloc.h> |
46 |
#include <sys/malloc.h> |
| 46 |
#include <sys/module.h> |
47 |
#include <sys/module.h> |
|
Lines 90-134
Link Here
|
| 90 |
#define fldcw(addr) __asm("fldcw %0" : : "m" (*(addr))) |
91 |
#define fldcw(addr) __asm("fldcw %0" : : "m" (*(addr))) |
| 91 |
#define fnclex() __asm("fnclex") |
92 |
#define fnclex() __asm("fnclex") |
| 92 |
#define fninit() __asm("fninit") |
93 |
#define fninit() __asm("fninit") |
| 93 |
#define fnop() __asm("fnop") |
94 |
#define fnop() __asm("fnop") |
| 94 |
#define fnsave(addr) __asm __volatile("fnsave %0" : "=m" (*(addr))) |
95 |
#define fnsave(addr) __asm __volatile("fnsave %0" : "=m" (*(addr))) |
| 95 |
#define fnstcw(addr) __asm __volatile("fnstcw %0" : "=m" (*(addr))) |
96 |
#define fnstcw(addr) __asm __volatile("fnstcw %0" : "=m" (*(addr))) |
| 96 |
#define fnstsw(addr) __asm __volatile("fnstsw %0" : "=m" (*(addr))) |
97 |
#define fnstsw(addr) __asm __volatile("fnstsw %0" : "=m" (*(addr))) |
| 97 |
#define fp_divide_by_0() __asm("fldz; fld1; fdiv %st,%st(1); fnop") |
98 |
#define fp_divide_by_0() __asm("fldz; fld1; fdiv %st,%st(1); fnop") |
| 98 |
#define frstor(addr) __asm("frstor %0" : : "m" (*(addr))) |
99 |
#define frstor(addr) __asm("frstor %0" : : "m" (*(addr))) |
|
|
100 |
#define fxrstor(addr) __asm("fxrstor %0" : : "m" (*(addr))) |
| 101 |
#define fxsave(addr) __asm __volatile("fxsave %0" : "=m" (*(addr))) |
| 99 |
#define start_emulating() __asm("smsw %%ax; orb %0,%%al; lmsw %%ax" \ |
102 |
#define start_emulating() __asm("smsw %%ax; orb %0,%%al; lmsw %%ax" \ |
| 100 |
: : "n" (CR0_TS) : "ax") |
103 |
: : "n" (CR0_TS) : "ax") |
| 101 |
#define stop_emulating() __asm("clts") |
104 |
#define stop_emulating() __asm("clts") |
| 102 |
|
105 |
|
| 103 |
#else /* not __GNUC__ */ |
106 |
#else /* not __GNUC__ */ |
| 104 |
|
107 |
|
| 105 |
void fldcw __P((caddr_t addr)); |
108 |
void fldcw __P((caddr_t addr)); |
| 106 |
void fnclex __P((void)); |
109 |
void fnclex __P((void)); |
| 107 |
void fninit __P((void)); |
110 |
void fninit __P((void)); |
| 108 |
void fnop __P((void)); |
111 |
void fnop __P((void)); |
| 109 |
void fnsave __P((caddr_t addr)); |
112 |
void fnsave __P((caddr_t addr)); |
| 110 |
void fnstcw __P((caddr_t addr)); |
113 |
void fnstcw __P((caddr_t addr)); |
| 111 |
void fnstsw __P((caddr_t addr)); |
114 |
void fnstsw __P((caddr_t addr)); |
| 112 |
void fp_divide_by_0 __P((void)); |
115 |
void fp_divide_by_0 __P((void)); |
| 113 |
void frstor __P((caddr_t addr)); |
116 |
void frstor __P((caddr_t addr)); |
|
|
117 |
void fxsave __P((caddr_t addr)); |
| 118 |
void fxrstor __P((caddr_t addr)); |
| 114 |
void start_emulating __P((void)); |
119 |
void start_emulating __P((void)); |
| 115 |
void stop_emulating __P((void)); |
120 |
void stop_emulating __P((void)); |
| 116 |
|
121 |
|
| 117 |
#endif /* __GNUC__ */ |
122 |
#endif /* __GNUC__ */ |
| 118 |
|
123 |
|
|
|
124 |
#ifdef CPU_ENABLE_SSE |
| 125 |
#define FPU_STATUS_EX(pcb) \ |
| 126 |
(cpu_fxsr ? \ |
| 127 |
&(pcb)->pcb_save.sv_xmm.sv_ex_sw : \ |
| 128 |
&(pcb)->pcb_save.sv_87.sv_ex_sw) |
| 129 |
#else /* CPU_ENABLE_SSE */ |
| 130 |
#define FPU_STATUS_EX(pcb) (&(pcb)->pcb_save.sv_87.sv_ex_sw) |
| 131 |
#endif /* CPU_ENABLE_SSE */ |
| 132 |
|
| 119 |
typedef u_char bool_t; |
133 |
typedef u_char bool_t; |
| 120 |
|
134 |
|
| 121 |
static int npx_attach __P((device_t dev)); |
135 |
static int npx_attach __P((device_t dev)); |
| 122 |
void npx_intr __P((void *)); |
136 |
void npx_intr __P((void *)); |
| 123 |
static void npx_identify __P((driver_t *driver, device_t parent)); |
137 |
static void npx_identify __P((driver_t *driver, device_t parent)); |
| 124 |
static int npx_probe __P((device_t dev)); |
138 |
static int npx_probe __P((device_t dev)); |
| 125 |
static int npx_probe1 __P((device_t dev)); |
139 |
static int npx_probe1 __P((device_t dev)); |
|
|
140 |
static void fpusave __P((union savefpu *)); |
| 141 |
static void fpurstor __P((union savefpu *)); |
| 126 |
#ifdef I586_CPU |
142 |
#ifdef I586_CPU |
| 127 |
static long timezero __P((const char *funcname, |
143 |
static long timezero __P((const char *funcname, |
| 128 |
void (*func)(void *buf, size_t len))); |
144 |
void (*func)(void *buf, size_t len))); |
| 129 |
#endif /* I586_CPU */ |
145 |
#endif /* I586_CPU */ |
| 130 |
|
146 |
|
| 131 |
int hw_float; /* XXX currently just alias for npx_exists */ |
147 |
int hw_float; /* XXX currently just alias for npx_exists */ |
| 132 |
|
148 |
|
| 133 |
SYSCTL_INT(_hw,HW_FLOATINGPT, floatingpoint, |
149 |
SYSCTL_INT(_hw,HW_FLOATINGPT, floatingpoint, |
| 134 |
CTLFLAG_RD, &hw_float, 0, |
150 |
CTLFLAG_RD, &hw_float, 0, |
|
Lines 468-512
Link Here
|
| 468 |
} |
484 |
} |
| 469 |
|
485 |
|
| 470 |
/* |
486 |
/* |
| 471 |
* Initialize floating point unit. |
487 |
* Initialize floating point unit. |
| 472 |
*/ |
488 |
*/ |
| 473 |
void |
489 |
void |
| 474 |
npxinit(control) |
490 |
npxinit(control) |
| 475 |
u_short control; |
491 |
u_short control; |
| 476 |
{ |
492 |
{ |
| 477 |
struct save87 dummy; |
493 |
union savefpu dummy; |
| 478 |
|
494 |
|
| 479 |
if (!npx_exists) |
495 |
if (!npx_exists) |
| 480 |
return; |
496 |
return; |
| 481 |
/* |
497 |
/* |
| 482 |
* fninit has the same h/w bugs as fnsave. Use the detoxified |
498 |
* fninit has the same h/w bugs as fnsave. Use the detoxified |
| 483 |
* fnsave to throw away any junk in the fpu. npxsave() initializes |
499 |
* fnsave to throw away any junk in the fpu. npxsave() initializes |
| 484 |
* the fpu and sets npxproc = NULL as important side effects. |
500 |
* the fpu and sets npxproc = NULL as important side effects. |
| 485 |
*/ |
501 |
*/ |
| 486 |
npxsave(&dummy); |
502 |
npxsave(&dummy); |
| 487 |
stop_emulating(); |
503 |
stop_emulating(); |
| 488 |
fldcw(&control); |
504 |
fldcw(&control); |
| 489 |
if (curpcb != NULL) |
505 |
if (curpcb != NULL) |
| 490 |
fnsave(&curpcb->pcb_savefpu); |
506 |
fpusave(&curpcb->pcb_save); |
| 491 |
start_emulating(); |
507 |
start_emulating(); |
| 492 |
} |
508 |
} |
| 493 |
|
509 |
|
| 494 |
/* |
510 |
/* |
| 495 |
* Free coprocessor (if we have it). |
511 |
* Free coprocessor (if we have it). |
| 496 |
*/ |
512 |
*/ |
| 497 |
void |
513 |
void |
| 498 |
npxexit(p) |
514 |
npxexit(p) |
| 499 |
struct proc *p; |
515 |
struct proc *p; |
| 500 |
{ |
516 |
{ |
| 501 |
|
517 |
|
| 502 |
if (p == npxproc) |
518 |
if (p == npxproc) |
| 503 |
npxsave(&curpcb->pcb_savefpu); |
519 |
npxsave(&curpcb->pcb_save); |
| 504 |
#ifdef NPX_DEBUG |
520 |
#ifdef NPX_DEBUG |
| 505 |
if (npx_exists) { |
521 |
if (npx_exists) { |
| 506 |
u_int masked_exceptions; |
522 |
u_int masked_exceptions; |
| 507 |
|
523 |
|
| 508 |
masked_exceptions = curpcb->pcb_savefpu.sv_env.en_cw |
524 |
masked_exceptions = curpcb->pcb_savefpu.sv_env.en_cw |
| 509 |
& curpcb->pcb_savefpu.sv_env.en_sw & 0x7f; |
525 |
& curpcb->pcb_savefpu.sv_env.en_sw & 0x7f; |
| 510 |
/* |
526 |
/* |
| 511 |
* Log exceptions that would have trapped with the old |
527 |
* Log exceptions that would have trapped with the old |
| 512 |
* control word (overflow, divide by 0, and invalid operand). |
528 |
* control word (overflow, divide by 0, and invalid operand). |
|
Lines 708-739
Link Here
|
| 708 |
* solution for signals other than SIGFPE. |
724 |
* solution for signals other than SIGFPE. |
| 709 |
*/ |
725 |
*/ |
| 710 |
void |
726 |
void |
| 711 |
npx_intr(dummy) |
727 |
npx_intr(dummy) |
| 712 |
void *dummy; |
728 |
void *dummy; |
| 713 |
{ |
729 |
{ |
| 714 |
int code; |
730 |
int code; |
| 715 |
u_short control; |
731 |
u_short control; |
| 716 |
struct intrframe *frame; |
732 |
struct intrframe *frame; |
|
|
733 |
u_long *pstatus; |
| 717 |
|
734 |
|
| 718 |
if (npxproc == NULL || !npx_exists) { |
735 |
if (npxproc == NULL || !npx_exists) { |
| 719 |
printf("npxintr: npxproc = %p, curproc = %p, npx_exists = %d\n", |
736 |
printf("npxintr: npxproc = %p, curproc = %p, npx_exists = %d\n", |
| 720 |
npxproc, curproc, npx_exists); |
737 |
npxproc, curproc, npx_exists); |
| 721 |
panic("npxintr from nowhere"); |
738 |
panic("npxintr from nowhere"); |
| 722 |
} |
739 |
} |
| 723 |
if (npxproc != curproc) { |
740 |
if (npxproc != curproc) { |
| 724 |
printf("npxintr: npxproc = %p, curproc = %p, npx_exists = %d\n", |
741 |
printf("npxintr: npxproc = %p, curproc = %p, npx_exists = %d\n", |
| 725 |
npxproc, curproc, npx_exists); |
742 |
npxproc, curproc, npx_exists); |
| 726 |
panic("npxintr from non-current process"); |
743 |
panic("npxintr from non-current process"); |
| 727 |
} |
744 |
} |
| 728 |
|
745 |
|
|
|
746 |
pstatus = FPU_STATUS_EX(curpcb); |
| 747 |
|
| 729 |
outb(0xf0, 0); |
748 |
outb(0xf0, 0); |
| 730 |
fnstsw(&curpcb->pcb_savefpu.sv_ex_sw); |
749 |
fnstsw(pstatus); |
| 731 |
fnstcw(&control); |
750 |
fnstcw(&control); |
| 732 |
fnclex(); |
751 |
fnclex(); |
| 733 |
|
752 |
|
| 734 |
/* |
753 |
/* |
| 735 |
* Pass exception to process. |
754 |
* Pass exception to process. |
| 736 |
*/ |
755 |
*/ |
| 737 |
frame = (struct intrframe *)&dummy; /* XXX */ |
756 |
frame = (struct intrframe *)&dummy; /* XXX */ |
| 738 |
if ((ISPL(frame->if_cs) == SEL_UPL) || (frame->if_eflags & PSL_VM)) { |
757 |
if ((ISPL(frame->if_cs) == SEL_UPL) || (frame->if_eflags & PSL_VM)) { |
| 739 |
/* |
758 |
/* |
|
Lines 747-766
Link Here
|
| 747 |
* in doreti, and the frame for that could easily be set up |
766 |
* in doreti, and the frame for that could easily be set up |
| 748 |
* just before it is used). |
767 |
* just before it is used). |
| 749 |
*/ |
768 |
*/ |
| 750 |
curproc->p_md.md_regs = INTR_TO_TRAPFRAME(frame); |
769 |
curproc->p_md.md_regs = INTR_TO_TRAPFRAME(frame); |
| 751 |
/* |
770 |
/* |
| 752 |
* Encode the appropriate code for detailed information on |
771 |
* Encode the appropriate code for detailed information on |
| 753 |
* this exception. |
772 |
* this exception. |
| 754 |
*/ |
773 |
*/ |
| 755 |
code = |
774 |
code = |
| 756 |
fpetable[(curpcb->pcb_savefpu.sv_ex_sw & ~control & 0x3f) | |
775 |
fpetable[(*pstatus & ~control & 0x3f) | (*pstatus & 0x40)]; |
| 757 |
(curpcb->pcb_savefpu.sv_ex_sw & 0x40)]; |
|
|
| 758 |
trapsignal(curproc, SIGFPE, code); |
776 |
trapsignal(curproc, SIGFPE, code); |
| 759 |
} else { |
777 |
} else { |
| 760 |
/* |
778 |
/* |
| 761 |
* Nested interrupt. These losers occur when: |
779 |
* Nested interrupt. These losers occur when: |
| 762 |
* o an IRQ13 is bogusly generated at a bogus time, e.g.: |
780 |
* o an IRQ13 is bogusly generated at a bogus time, e.g.: |
| 763 |
* o immediately after an fnsave or frstor of an |
781 |
* o immediately after an fnsave or frstor of an |
| 764 |
* error state. |
782 |
* error state. |
| 765 |
* o a couple of 386 instructions after |
783 |
* o a couple of 386 instructions after |
| 766 |
* "fstpl _memvar" causes a stack overflow. |
784 |
* "fstpl _memvar" causes a stack overflow. |
|
Lines 779-847
Link Here
|
| 779 |
* Implement device not available (DNA) exception |
797 |
* Implement device not available (DNA) exception |
| 780 |
* |
798 |
* |
| 781 |
* It would be better to switch FP context here (if curproc != npxproc) |
799 |
* It would be better to switch FP context here (if curproc != npxproc) |
| 782 |
* and not necessarily for every context switch, but it is too hard to |
800 |
* and not necessarily for every context switch, but it is too hard to |
| 783 |
* access foreign pcb's. |
801 |
* access foreign pcb's. |
| 784 |
*/ |
802 |
*/ |
| 785 |
int |
803 |
int |
| 786 |
npxdna() |
804 |
npxdna() |
| 787 |
{ |
805 |
{ |
|
|
806 |
u_long *pstatus; |
| 807 |
|
| 788 |
if (!npx_exists) |
808 |
if (!npx_exists) |
| 789 |
return (0); |
809 |
return (0); |
| 790 |
if (npxproc != NULL) { |
810 |
if (npxproc != NULL) { |
| 791 |
printf("npxdna: npxproc = %p, curproc = %p\n", |
811 |
printf("npxdna: npxproc = %p, curproc = %p\n", |
| 792 |
npxproc, curproc); |
812 |
npxproc, curproc); |
| 793 |
panic("npxdna"); |
813 |
panic("npxdna"); |
| 794 |
} |
814 |
} |
| 795 |
stop_emulating(); |
815 |
stop_emulating(); |
| 796 |
/* |
816 |
/* |
| 797 |
* Record new context early in case frstor causes an IRQ13. |
817 |
* Record new context early in case frstor causes an IRQ13. |
| 798 |
*/ |
818 |
*/ |
| 799 |
npxproc = curproc; |
819 |
npxproc = curproc; |
| 800 |
curpcb->pcb_savefpu.sv_ex_sw = 0; |
820 |
|
|
|
821 |
pstatus = FPU_STATUS_EX(curpcb); |
| 822 |
*pstatus = 0; |
| 823 |
|
| 801 |
/* |
824 |
/* |
| 802 |
* The following frstor may cause an IRQ13 when the state being |
825 |
* The following frstor may cause an IRQ13 when the state being |
| 803 |
* restored has a pending error. The error will appear to have been |
826 |
* restored has a pending error. The error will appear to have been |
| 804 |
* triggered by the current (npx) user instruction even when that |
827 |
* triggered by the current (npx) user instruction even when that |
| 805 |
* instruction is a no-wait instruction that should not trigger an |
828 |
* instruction is a no-wait instruction that should not trigger an |
| 806 |
* error (e.g., fnclex). On at least one 486 system all of the |
829 |
* error (e.g., fnclex). On at least one 486 system all of the |
| 807 |
* no-wait instructions are broken the same as frstor, so our |
830 |
* no-wait instructions are broken the same as frstor, so our |
| 808 |
* treatment does not amplify the breakage. On at least one |
831 |
* treatment does not amplify the breakage. On at least one |
| 809 |
* 386/Cyrix 387 system, fnclex works correctly while frstor and |
832 |
* 386/Cyrix 387 system, fnclex works correctly while frstor and |
| 810 |
* fnsave are broken, so our treatment breaks fnclex if it is the |
833 |
* fnsave are broken, so our treatment breaks fnclex if it is the |
| 811 |
* first FPU instruction after a context switch. |
834 |
* first FPU instruction after a context switch. |
| 812 |
*/ |
835 |
*/ |
| 813 |
frstor(&curpcb->pcb_savefpu); |
836 |
fpurstor(&curpcb->pcb_save); |
| 814 |
|
837 |
|
| 815 |
return (1); |
838 |
return (1); |
| 816 |
} |
839 |
} |
| 817 |
|
840 |
|
| 818 |
/* |
841 |
/* |
| 819 |
* Wrapper for fnsave instruction to handle h/w bugs. If there is an error |
842 |
* Wrapper for fnsave instruction to handle h/w bugs. If there is an error |
| 820 |
* pending, then fnsave generates a bogus IRQ13 on some systems. Force |
843 |
* pending, then fnsave generates a bogus IRQ13 on some systems. Force |
| 821 |
* any IRQ13 to be handled immediately, and then ignore it. This routine is |
844 |
* any IRQ13 to be handled immediately, and then ignore it. This routine is |
| 822 |
* often called at splhigh so it must not use many system services. In |
845 |
* often called at splhigh so it must not use many system services. In |
| 823 |
* particular, it's much easier to install a special handler than to |
846 |
* particular, it's much easier to install a special handler than to |
| 824 |
* guarantee that it's safe to use npxintr() and its supporting code. |
847 |
* guarantee that it's safe to use npxintr() and its supporting code. |
| 825 |
*/ |
848 |
*/ |
| 826 |
void |
849 |
void |
| 827 |
npxsave(addr) |
850 |
npxsave(addr) |
| 828 |
struct save87 *addr; |
851 |
union savefpu *addr; |
| 829 |
{ |
852 |
{ |
| 830 |
#ifdef SMP |
853 |
#if defined(SMP) || defined(CPU_ENABLE_SSE) |
| 831 |
|
|
|
| 832 |
stop_emulating(); |
854 |
stop_emulating(); |
| 833 |
fnsave(addr); |
855 |
fpusave(addr); |
| 834 |
/* fnop(); */ |
856 |
/* fnop(); */ |
| 835 |
start_emulating(); |
857 |
start_emulating(); |
| 836 |
npxproc = NULL; |
858 |
npxproc = NULL; |
| 837 |
|
859 |
|
| 838 |
#else /* SMP */ |
860 |
#else /* SMP or CPU_ENABLE_SSE */ |
| 839 |
|
861 |
|
| 840 |
u_char icu1_mask; |
862 |
u_char icu1_mask; |
| 841 |
u_char icu2_mask; |
863 |
u_char icu2_mask; |
| 842 |
u_char old_icu1_mask; |
864 |
u_char old_icu1_mask; |
| 843 |
u_char old_icu2_mask; |
865 |
u_char old_icu2_mask; |
| 844 |
struct gate_descriptor save_idt_npxintr; |
866 |
struct gate_descriptor save_idt_npxintr; |
| 845 |
|
867 |
|
| 846 |
disable_intr(); |
868 |
disable_intr(); |
| 847 |
old_icu1_mask = inb(IO_ICU1 + 1); |
869 |
old_icu1_mask = inb(IO_ICU1 + 1); |
|
Lines 862-879
Link Here
|
| 862 |
outb(IO_ICU1 + 1, |
884 |
outb(IO_ICU1 + 1, |
| 863 |
(icu1_mask & ~npx0_imask) | (old_icu1_mask & npx0_imask)); |
885 |
(icu1_mask & ~npx0_imask) | (old_icu1_mask & npx0_imask)); |
| 864 |
outb(IO_ICU2 + 1, |
886 |
outb(IO_ICU2 + 1, |
| 865 |
(icu2_mask & ~(npx0_imask >> 8)) |
887 |
(icu2_mask & ~(npx0_imask >> 8)) |
| 866 |
| (old_icu2_mask & (npx0_imask >> 8))); |
888 |
| (old_icu2_mask & (npx0_imask >> 8))); |
| 867 |
idt[npx_intrno] = save_idt_npxintr; |
889 |
idt[npx_intrno] = save_idt_npxintr; |
| 868 |
enable_intr(); /* back to usual state */ |
890 |
enable_intr(); /* back to usual state */ |
| 869 |
|
891 |
|
| 870 |
#endif /* SMP */ |
892 |
#endif /* SMP */ |
|
|
893 |
} |
| 894 |
|
| 895 |
static void |
| 896 |
fpusave(addr) |
| 897 |
union savefpu *addr; |
| 898 |
{ |
| 899 |
#ifdef CPU_ENABLE_SSE |
| 900 |
static struct savexmm svxmm __attribute__((aligned(16))); |
| 901 |
|
| 902 |
if (cpu_fxsr) { |
| 903 |
fxsave(&svxmm); |
| 904 |
bcopy(&svxmm, addr, sizeof(struct savexmm)); |
| 905 |
return; |
| 906 |
} |
| 907 |
#endif /* CPU_ENABLE_SSE */ |
| 908 |
fnsave(addr); |
| 909 |
} |
| 910 |
|
| 911 |
static void |
| 912 |
fpurstor(addr) |
| 913 |
union savefpu *addr; |
| 914 |
{ |
| 915 |
#ifdef CPU_ENABLE_SSE |
| 916 |
static struct savexmm svxmm __attribute__((aligned(16))); |
| 917 |
|
| 918 |
if (cpu_fxsr) { |
| 919 |
bcopy(addr, &svxmm, sizeof (struct savexmm)); |
| 920 |
fxrstor(&svxmm); |
| 921 |
return; |
| 922 |
} |
| 923 |
#endif /* CPU_ENABLE_SSE */ |
| 924 |
frstor(addr); |
| 871 |
} |
925 |
} |
| 872 |
|
926 |
|
| 873 |
#ifdef I586_CPU |
927 |
#ifdef I586_CPU |
| 874 |
static long |
928 |
static long |
| 875 |
timezero(funcname, func) |
929 |
timezero(funcname, func) |
| 876 |
const char *funcname; |
930 |
const char *funcname; |
| 877 |
void (*func) __P((void *buf, size_t len)); |
931 |
void (*func) __P((void *buf, size_t len)); |
| 878 |
|
932 |
|
| 879 |
{ |
933 |
{ |