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