Deleted Added
full compact
npx.c (190426) npx.c (208833)
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:

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

26 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
27 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
28 * SUCH DAMAGE.
29 *
30 * from: @(#)npx.c 7.2 (Berkeley) 5/12/91
31 */
32
33#include <sys/cdefs.h>
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:

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

26 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
27 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
28 * SUCH DAMAGE.
29 *
30 * from: @(#)npx.c 7.2 (Berkeley) 5/12/91
31 */
32
33#include <sys/cdefs.h>
34__FBSDID("$FreeBSD: head/sys/i386/isa/npx.c 190426 2009-03-25 22:08:30Z jhb $");
34__FBSDID("$FreeBSD: head/sys/i386/isa/npx.c 208833 2010-06-05 15:59:59Z kib $");
35
36#include "opt_cpu.h"
37#include "opt_isa.h"
38#include "opt_npx.h"
39
40#include <sys/param.h>
41#include <sys/systm.h>
42#include <sys/bus.h>

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

130void start_emulating(void);
131void stop_emulating(void);
132
133#endif /* __GNUCLIKE_ASM && !lint */
134
135#ifdef CPU_ENABLE_SSE
136#define GET_FPU_CW(thread) \
137 (cpu_fxsr ? \
35
36#include "opt_cpu.h"
37#include "opt_isa.h"
38#include "opt_npx.h"
39
40#include <sys/param.h>
41#include <sys/systm.h>
42#include <sys/bus.h>

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

130void start_emulating(void);
131void stop_emulating(void);
132
133#endif /* __GNUCLIKE_ASM && !lint */
134
135#ifdef CPU_ENABLE_SSE
136#define GET_FPU_CW(thread) \
137 (cpu_fxsr ? \
138 (thread)->td_pcb->pcb_save.sv_xmm.sv_env.en_cw : \
139 (thread)->td_pcb->pcb_save.sv_87.sv_env.en_cw)
138 (thread)->td_pcb->pcb_save->sv_xmm.sv_env.en_cw : \
139 (thread)->td_pcb->pcb_save->sv_87.sv_env.en_cw)
140#define GET_FPU_SW(thread) \
141 (cpu_fxsr ? \
140#define GET_FPU_SW(thread) \
141 (cpu_fxsr ? \
142 (thread)->td_pcb->pcb_save.sv_xmm.sv_env.en_sw : \
143 (thread)->td_pcb->pcb_save.sv_87.sv_env.en_sw)
142 (thread)->td_pcb->pcb_save->sv_xmm.sv_env.en_sw : \
143 (thread)->td_pcb->pcb_save->sv_87.sv_env.en_sw)
144#define SET_FPU_CW(savefpu, value) do { \
145 if (cpu_fxsr) \
146 (savefpu)->sv_xmm.sv_env.en_cw = (value); \
147 else \
148 (savefpu)->sv_87.sv_env.en_cw = (value); \
149} while (0)
150#else /* CPU_ENABLE_SSE */
151#define GET_FPU_CW(thread) \
144#define SET_FPU_CW(savefpu, value) do { \
145 if (cpu_fxsr) \
146 (savefpu)->sv_xmm.sv_env.en_cw = (value); \
147 else \
148 (savefpu)->sv_87.sv_env.en_cw = (value); \
149} while (0)
150#else /* CPU_ENABLE_SSE */
151#define GET_FPU_CW(thread) \
152 (thread->td_pcb->pcb_save.sv_87.sv_env.en_cw)
152 (thread->td_pcb->pcb_save->sv_87.sv_env.en_cw)
153#define GET_FPU_SW(thread) \
153#define GET_FPU_SW(thread) \
154 (thread->td_pcb->pcb_save.sv_87.sv_env.en_sw)
154 (thread->td_pcb->pcb_save->sv_87.sv_env.en_sw)
155#define SET_FPU_CW(savefpu, value) \
156 (savefpu)->sv_87.sv_env.en_cw = (value)
157#endif /* CPU_ENABLE_SSE */
158
159typedef u_char bool_t;
160
161#ifdef CPU_ENABLE_SSE
162static void fpu_clean_state(void);

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

497void
498npxexit(td)
499 struct thread *td;
500{
501 register_t savecrit;
502
503 savecrit = intr_disable();
504 if (curthread == PCPU_GET(fpcurthread))
155#define SET_FPU_CW(savefpu, value) \
156 (savefpu)->sv_87.sv_env.en_cw = (value)
157#endif /* CPU_ENABLE_SSE */
158
159typedef u_char bool_t;
160
161#ifdef CPU_ENABLE_SSE
162static void fpu_clean_state(void);

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

497void
498npxexit(td)
499 struct thread *td;
500{
501 register_t savecrit;
502
503 savecrit = intr_disable();
504 if (curthread == PCPU_GET(fpcurthread))
505 npxsave(&PCPU_GET(curpcb)->pcb_save);
505 npxsave(PCPU_GET(curpcb)->pcb_save);
506 intr_restore(savecrit);
507#ifdef NPX_DEBUG
508 if (npx_exists) {
509 u_int masked_exceptions;
510
511 masked_exceptions = GET_FPU_CW(td) & GET_FPU_SW(td) & 0x7f;
512 /*
513 * Log exceptions that would have trapped with the old

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

804 * This is the first time this thread has used the FPU or
805 * the PCB doesn't contain a clean FPU state. Explicitly
806 * load an initial state.
807 */
808 fpurstor(&npx_initialstate);
809 if (pcb->pcb_initial_npxcw != __INITIAL_NPXCW__)
810 fldcw(&pcb->pcb_initial_npxcw);
811 pcb->pcb_flags |= PCB_NPXINITDONE;
506 intr_restore(savecrit);
507#ifdef NPX_DEBUG
508 if (npx_exists) {
509 u_int masked_exceptions;
510
511 masked_exceptions = GET_FPU_CW(td) & GET_FPU_SW(td) & 0x7f;
512 /*
513 * Log exceptions that would have trapped with the old

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

804 * This is the first time this thread has used the FPU or
805 * the PCB doesn't contain a clean FPU state. Explicitly
806 * load an initial state.
807 */
808 fpurstor(&npx_initialstate);
809 if (pcb->pcb_initial_npxcw != __INITIAL_NPXCW__)
810 fldcw(&pcb->pcb_initial_npxcw);
811 pcb->pcb_flags |= PCB_NPXINITDONE;
812 if (PCB_USER_FPU(pcb))
813 pcb->pcb_flags |= PCB_NPXUSERINITDONE;
812 } else {
813 /*
814 * The following fpurstor() may cause an IRQ13 when the
815 * state being restored has a pending error. The error will
816 * appear to have been triggered by the current (npx) user
817 * instruction even when that instruction is a no-wait
818 * instruction that should not trigger an error (e.g.,
819 * fnclex). On at least one 486 system all of the no-wait
820 * instructions are broken the same as frstor, so our
821 * treatment does not amplify the breakage. On at least
822 * one 386/Cyrix 387 system, fnclex works correctly while
823 * frstor and fnsave are broken, so our treatment breaks
824 * fnclex if it is the first FPU instruction after a context
825 * switch.
826 */
814 } else {
815 /*
816 * The following fpurstor() may cause an IRQ13 when the
817 * state being restored has a pending error. The error will
818 * appear to have been triggered by the current (npx) user
819 * instruction even when that instruction is a no-wait
820 * instruction that should not trigger an error (e.g.,
821 * fnclex). On at least one 486 system all of the no-wait
822 * instructions are broken the same as frstor, so our
823 * treatment does not amplify the breakage. On at least
824 * one 386/Cyrix 387 system, fnclex works correctly while
825 * frstor and fnsave are broken, so our treatment breaks
826 * fnclex if it is the first FPU instruction after a context
827 * switch.
828 */
827 fpurstor(&pcb->pcb_save);
829 fpurstor(pcb->pcb_save);
828 }
829 intr_restore(s);
830
831 return (1);
832}
833
834/*
835 * Wrapper for fnsave instruction, partly to handle hardware bugs. When npx

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

890 start_emulating();
891}
892
893/*
894 * Get the state of the FPU without dropping ownership (if possible).
895 * It returns the FPU ownership status.
896 */
897int
830 }
831 intr_restore(s);
832
833 return (1);
834}
835
836/*
837 * Wrapper for fnsave instruction, partly to handle hardware bugs. When npx

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

892 start_emulating();
893}
894
895/*
896 * Get the state of the FPU without dropping ownership (if possible).
897 * It returns the FPU ownership status.
898 */
899int
898npxgetregs(td, addr)
899 struct thread *td;
900 union savefpu *addr;
900npxgetregs(struct thread *td, union savefpu *addr)
901{
901{
902 struct pcb *pcb;
902 register_t s;
903
904 if (!npx_exists)
905 return (_MC_FPOWNED_NONE);
906
903 register_t s;
904
905 if (!npx_exists)
906 return (_MC_FPOWNED_NONE);
907
907 if ((td->td_pcb->pcb_flags & PCB_NPXINITDONE) == 0) {
908 pcb = td->td_pcb;
909 if ((pcb->pcb_flags & PCB_NPXINITDONE) == 0) {
908 bcopy(&npx_initialstate, addr, sizeof(npx_initialstate));
910 bcopy(&npx_initialstate, addr, sizeof(npx_initialstate));
909 SET_FPU_CW(addr, td->td_pcb->pcb_initial_npxcw);
911 SET_FPU_CW(addr, pcb->pcb_initial_npxcw);
910 return (_MC_FPOWNED_NONE);
911 }
912 s = intr_disable();
913 if (td == PCPU_GET(fpcurthread)) {
914 fpusave(addr);
915#ifdef CPU_ENABLE_SSE
916 if (!cpu_fxsr)
917#endif
918 /*
919 * fnsave initializes the FPU and destroys whatever
920 * context it contains. Make sure the FPU owner
921 * starts with a clean state next time.
922 */
923 npxdrop();
924 intr_restore(s);
925 return (_MC_FPOWNED_FPU);
926 } else {
927 intr_restore(s);
912 return (_MC_FPOWNED_NONE);
913 }
914 s = intr_disable();
915 if (td == PCPU_GET(fpcurthread)) {
916 fpusave(addr);
917#ifdef CPU_ENABLE_SSE
918 if (!cpu_fxsr)
919#endif
920 /*
921 * fnsave initializes the FPU and destroys whatever
922 * context it contains. Make sure the FPU owner
923 * starts with a clean state next time.
924 */
925 npxdrop();
926 intr_restore(s);
927 return (_MC_FPOWNED_FPU);
928 } else {
929 intr_restore(s);
928 bcopy(&td->td_pcb->pcb_save, addr, sizeof(*addr));
930 bcopy(pcb->pcb_save, addr, sizeof(*addr));
929 return (_MC_FPOWNED_PCB);
930 }
931}
932
931 return (_MC_FPOWNED_PCB);
932 }
933}
934
935int
936npxgetuserregs(struct thread *td, union savefpu *addr)
937{
938 struct pcb *pcb;
939 register_t s;
940
941 if (!npx_exists)
942 return (_MC_FPOWNED_NONE);
943
944 pcb = td->td_pcb;
945 if ((pcb->pcb_flags & PCB_NPXUSERINITDONE) == 0) {
946 bcopy(&npx_initialstate, addr, sizeof(npx_initialstate));
947 SET_FPU_CW(addr, pcb->pcb_initial_npxcw);
948 return (_MC_FPOWNED_NONE);
949 }
950 s = intr_disable();
951 if (td == PCPU_GET(fpcurthread) && PCB_USER_FPU(pcb)) {
952 fpusave(addr);
953#ifdef CPU_ENABLE_SSE
954 if (!cpu_fxsr)
955#endif
956 /*
957 * fnsave initializes the FPU and destroys whatever
958 * context it contains. Make sure the FPU owner
959 * starts with a clean state next time.
960 */
961 npxdrop();
962 intr_restore(s);
963 return (_MC_FPOWNED_FPU);
964 } else {
965 intr_restore(s);
966 bcopy(&pcb->pcb_user_save, addr, sizeof(*addr));
967 return (_MC_FPOWNED_PCB);
968 }
969}
970
933/*
934 * Set the state of the FPU.
935 */
936void
971/*
972 * Set the state of the FPU.
973 */
974void
937npxsetregs(td, addr)
938 struct thread *td;
939 union savefpu *addr;
975npxsetregs(struct thread *td, union savefpu *addr)
940{
976{
977 struct pcb *pcb;
941 register_t s;
942
943 if (!npx_exists)
944 return;
945
978 register_t s;
979
980 if (!npx_exists)
981 return;
982
983 pcb = td->td_pcb;
946 s = intr_disable();
947 if (td == PCPU_GET(fpcurthread)) {
948#ifdef CPU_ENABLE_SSE
949 if (!cpu_fxsr)
950#endif
951 fnclex(); /* As in npxdrop(). */
952 fpurstor(addr);
953 intr_restore(s);
954 } else {
955 intr_restore(s);
984 s = intr_disable();
985 if (td == PCPU_GET(fpcurthread)) {
986#ifdef CPU_ENABLE_SSE
987 if (!cpu_fxsr)
988#endif
989 fnclex(); /* As in npxdrop(). */
990 fpurstor(addr);
991 intr_restore(s);
992 } else {
993 intr_restore(s);
956 bcopy(addr, &td->td_pcb->pcb_save, sizeof(*addr));
994 bcopy(addr, pcb->pcb_save, sizeof(*addr));
957 }
995 }
958 curthread->td_pcb->pcb_flags |= PCB_NPXINITDONE;
996 if (PCB_USER_FPU(pcb))
997 pcb->pcb_flags |= PCB_NPXUSERINITDONE;
998 pcb->pcb_flags |= PCB_NPXINITDONE;
959}
960
999}
1000
1001void
1002npxsetuserregs(struct thread *td, union savefpu *addr)
1003{
1004 struct pcb *pcb;
1005 register_t s;
1006
1007 if (!npx_exists)
1008 return;
1009
1010 pcb = td->td_pcb;
1011 s = intr_disable();
1012 if (td == PCPU_GET(fpcurthread) && PCB_USER_FPU(pcb)) {
1013#ifdef CPU_ENABLE_SSE
1014 if (!cpu_fxsr)
1015#endif
1016 fnclex(); /* As in npxdrop(). */
1017 fpurstor(addr);
1018 intr_restore(s);
1019 pcb->pcb_flags |= PCB_NPXUSERINITDONE | PCB_NPXINITDONE;
1020 } else {
1021 intr_restore(s);
1022 bcopy(addr, &pcb->pcb_user_save, sizeof(*addr));
1023 if (PCB_USER_FPU(pcb))
1024 pcb->pcb_flags |= PCB_NPXINITDONE;
1025 pcb->pcb_flags |= PCB_NPXUSERINITDONE;
1026 }
1027}
1028
961static void
962fpusave(addr)
963 union savefpu *addr;
964{
965
966#ifdef CPU_ENABLE_SSE
967 if (cpu_fxsr)
968 fxsave(addr);

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

1119
1120static devclass_t npxisa_devclass;
1121
1122DRIVER_MODULE(npxisa, isa, npxisa_driver, npxisa_devclass, 0, 0);
1123#ifndef PC98
1124DRIVER_MODULE(npxisa, acpi, npxisa_driver, npxisa_devclass, 0, 0);
1125#endif
1126#endif /* DEV_ISA */
1029static void
1030fpusave(addr)
1031 union savefpu *addr;
1032{
1033
1034#ifdef CPU_ENABLE_SSE
1035 if (cpu_fxsr)
1036 fxsave(addr);

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

1187
1188static devclass_t npxisa_devclass;
1189
1190DRIVER_MODULE(npxisa, isa, npxisa_driver, npxisa_devclass, 0, 0);
1191#ifndef PC98
1192DRIVER_MODULE(npxisa, acpi, npxisa_driver, npxisa_devclass, 0, 0);
1193#endif
1194#endif /* DEV_ISA */
1195
1196int
1197fpu_kern_enter(struct thread *td, struct fpu_kern_ctx *ctx, u_int flags)
1198{
1199 struct pcb *pcb;
1200
1201 pcb = td->td_pcb;
1202 KASSERT(!PCB_USER_FPU(pcb) || pcb->pcb_save == &pcb->pcb_user_save,
1203 ("mangled pcb_save"));
1204 ctx->flags = 0;
1205 if ((pcb->pcb_flags & PCB_NPXINITDONE) != 0)
1206 ctx->flags |= FPU_KERN_CTX_NPXINITDONE;
1207 npxexit(td);
1208 ctx->prev = pcb->pcb_save;
1209 pcb->pcb_save = &ctx->hwstate;
1210 pcb->pcb_flags |= PCB_KERNNPX;
1211 pcb->pcb_flags &= ~PCB_NPXINITDONE;
1212 return (0);
1213}
1214
1215int
1216fpu_kern_leave(struct thread *td, struct fpu_kern_ctx *ctx)
1217{
1218 struct pcb *pcb;
1219 register_t savecrit;
1220
1221 pcb = td->td_pcb;
1222 savecrit = intr_disable();
1223 if (curthread == PCPU_GET(fpcurthread))
1224 npxdrop();
1225 intr_restore(savecrit);
1226 pcb->pcb_save = ctx->prev;
1227 if (pcb->pcb_save == &pcb->pcb_user_save) {
1228 if ((pcb->pcb_flags & PCB_NPXUSERINITDONE) != 0)
1229 pcb->pcb_flags |= PCB_NPXINITDONE;
1230 else
1231 pcb->pcb_flags &= ~PCB_NPXINITDONE;
1232 pcb->pcb_flags &= ~PCB_KERNNPX;
1233 } else {
1234 if ((ctx->flags & FPU_KERN_CTX_NPXINITDONE) != 0)
1235 pcb->pcb_flags |= PCB_NPXINITDONE;
1236 else
1237 pcb->pcb_flags &= ~PCB_NPXINITDONE;
1238 KASSERT(!PCB_USER_FPU(pcb), ("unpaired fpu_kern_leave"));
1239 }
1240 return (0);
1241}
1242
1243int
1244fpu_kern_thread(u_int flags)
1245{
1246 struct pcb *pcb;
1247
1248 pcb = PCPU_GET(curpcb);
1249 KASSERT((curthread->td_pflags & TDP_KTHREAD) != 0,
1250 ("Only kthread may use fpu_kern_thread"));
1251 KASSERT(pcb->pcb_save == &pcb->pcb_user_save, ("mangled pcb_save"));
1252 KASSERT(PCB_USER_FPU(pcb), ("recursive call"));
1253
1254 pcb->pcb_flags |= PCB_KERNNPX;
1255 return (0);
1256}
1257
1258int
1259is_fpu_kern_thread(u_int flags)
1260{
1261
1262 if ((curthread->td_pflags & TDP_KTHREAD) == 0)
1263 return (0);
1264 return ((PCPU_GET(curpcb)->pcb_flags & PCB_KERNNPX) != 0);
1265}