* Determine if an FPU is present and how to use it. */
| 224 | * Determine if an FPU is present and how to use it. |
| 225 | */ |
| 226 | static int |
| 227 | npx_probe(void) |
| 228 | { |
| 229 | struct gate_descriptor save_idt_npxtrap; |
| 230 | u_short control, status; |
| 231 | |
| 232 | /* |
| 233 | * Modern CPUs all have an FPU that uses the INT16 interface |
| 234 | * and provide a simple way to verify that, so handle the |
| 235 | * common case right away. |
| 236 | */ |
| 237 | if (cpu_feature & CPUID_FPU) { |
| 238 | hw_float = 1; |
| 239 | return (1); |
| 240 | } |
| 241 | |
| 242 | save_idt_npxtrap = idt[IDT_MF]; |
| 243 | setidt(IDT_MF, probetrap, SDT_SYS386TGT, SEL_KPL, |
| 244 | GSEL(GCODE_SEL, SEL_KPL)); |
| 245 | |
| 246 | /* |
| 247 | * Don't trap while we're probing. |
| 248 | */ |
| 249 | stop_emulating(); |
| 250 | |
| 251 | /* |
| 252 | * Finish resetting the coprocessor, if any. If there is an error |
| 253 | * pending, then we may get a bogus IRQ13, but npx_intr() will handle |
| 254 | * it OK. Bogus halts have never been observed, but we enabled |
| 255 | * IRQ13 and cleared the BUSY# latch early to handle them anyway. |
| 256 | */ |
| 257 | fninit(); |
| 258 | |
| 259 | /* |
| 260 | * Don't use fwait here because it might hang. |
| 261 | * Don't use fnop here because it usually hangs if there is no FPU. |
| 262 | */ |
| 263 | DELAY(1000); /* wait for any IRQ13 */ |
| 264 | #ifdef DIAGNOSTIC |
| 265 | if (npx_traps_while_probing != 0) |
| 266 | printf("fninit caused %u bogus npx trap(s)\n", |
| 267 | npx_traps_while_probing); |
| 268 | #endif |
| 269 | /* |
| 270 | * Check for a status of mostly zero. |
| 271 | */ |
| 272 | status = 0x5a5a; |
| 273 | fnstsw(&status); |
| 274 | if ((status & 0xb8ff) == 0) { |
| 275 | /* |
| 276 | * Good, now check for a proper control word. |
| 277 | */ |
| 278 | control = 0x5a5a; |
| 279 | fnstcw(&control); |
| 280 | if ((control & 0x1f3f) == 0x033f) { |
| 281 | /* |
| 282 | * We have an npx, now divide by 0 to see if exception |
| 283 | * 16 works. |