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 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 ? \ |
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 ? \ |
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) \ |
152 (thread->td_pcb->pcb_save->sv_87.sv_env.en_cw) |
153#define GET_FPU_SW(thread) \ |
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)) |
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; |
812 if (PCB_USER_FPU(pcb)) 813 pcb->pcb_flags |= PCB_NPXUSERINITDONE; |
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 */ |
829 fpurstor(pcb->pcb_save); |
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 |
900npxgetregs(struct thread *td, union savefpu *addr) |
901{ |
902 struct pcb *pcb; |
903 register_t s; 904 905 if (!npx_exists) 906 return (_MC_FPOWNED_NONE); 907 |
908 pcb = td->td_pcb; 909 if ((pcb->pcb_flags & PCB_NPXINITDONE) == 0) { |
910 bcopy(&npx_initialstate, addr, sizeof(npx_initialstate)); |
911 SET_FPU_CW(addr, pcb->pcb_initial_npxcw); |
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); |
930 bcopy(pcb->pcb_save, addr, sizeof(*addr)); |
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 |
971/* 972 * Set the state of the FPU. 973 */ 974void |
975npxsetregs(struct thread *td, union savefpu *addr) |
976{ |
977 struct pcb *pcb; |
978 register_t s; 979 980 if (!npx_exists) 981 return; 982 |
983 pcb = td->td_pcb; |
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); |
994 bcopy(addr, pcb->pcb_save, sizeof(*addr)); |
995 } |
996 if (PCB_USER_FPU(pcb)) 997 pcb->pcb_flags |= PCB_NPXUSERINITDONE; 998 pcb->pcb_flags |= PCB_NPXINITDONE; |
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 |
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} |