fpu.c revision 122292
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: 9 * 1. Redistributions of source code must retain the above copyright 10 * notice, this list of conditions and the following disclaimer. 11 * 2. Redistributions in binary form must reproduce the above copyright 12 * notice, this list of conditions and the following disclaimer in the 13 * documentation and/or other materials provided with the distribution. 14 * 3. All advertising materials mentioning features or use of this software 15 * must display the following acknowledgement: 16 * This product includes software developed by the University of 17 * California, Berkeley and its contributors. 18 * 4. Neither the name of the University nor the names of its contributors 19 * may be used to endorse or promote products derived from this software 20 * without specific prior written permission. 21 * 22 * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND 23 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 24 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 25 * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE 26 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 27 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 28 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 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 31 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 32 * SUCH DAMAGE. 33 * 34 * @(#)npx.c 7.2 (Berkeley) 5/12/91 35 */ 36 37#include <sys/cdefs.h> 38__FBSDID("$FreeBSD: head/sys/amd64/amd64/fpu.c 122292 2003-11-08 03:33:38Z peter $"); 39 40#include "opt_isa.h" 41 42#include <sys/param.h> 43#include <sys/systm.h> 44#include <sys/bus.h> 45#include <sys/kernel.h> 46#include <sys/lock.h> 47#include <sys/malloc.h> 48#include <sys/module.h> 49#include <sys/mutex.h> 50#include <sys/mutex.h> 51#include <sys/proc.h> 52#include <sys/sysctl.h> 53#include <machine/bus.h> 54#include <sys/rman.h> 55#include <sys/signalvar.h> 56#include <sys/user.h> 57 58#include <machine/cputypes.h> 59#include <machine/frame.h> 60#include <machine/md_var.h> 61#include <machine/pcb.h> 62#include <machine/psl.h> 63#include <machine/resource.h> 64#include <machine/specialreg.h> 65#include <machine/segments.h> 66#include <machine/ucontext.h> 67 68#include <amd64/isa/intr_machdep.h> 69#ifdef DEV_ISA 70#include <isa/isavar.h> 71#endif 72 73/* 74 * Floating point support. 75 */ 76 77#if defined(__GNUC__) && !defined(lint) 78 79#define fldcw(addr) __asm("fldcw %0" : : "m" (*(addr))) 80#define fnclex() __asm("fnclex") 81#define fninit() __asm("fninit") 82#define fnstcw(addr) __asm __volatile("fnstcw %0" : "=m" (*(addr))) 83#define fnstsw(addr) __asm __volatile("fnstsw %0" : "=m" (*(addr))) 84#define fxrstor(addr) __asm("fxrstor %0" : : "m" (*(addr))) 85#define fxsave(addr) __asm __volatile("fxsave %0" : "=m" (*(addr))) 86#define start_emulating() __asm("smsw %%ax; orb %0,%%al; lmsw %%ax" \ 87 : : "n" (CR0_TS) : "ax") 88#define stop_emulating() __asm("clts") 89 90#else /* not __GNUC__ */ 91 92void fldcw(caddr_t addr); 93void fnclex(void); 94void fninit(void); 95void fnstcw(caddr_t addr); 96void fnstsw(caddr_t addr); 97void fxsave(caddr_t addr); 98void fxrstor(caddr_t addr); 99void start_emulating(void); 100void stop_emulating(void); 101 102#endif /* __GNUC__ */ 103 104#define GET_FPU_CW(thread) ((thread)->td_pcb->pcb_save.sv_env.en_cw) 105#define GET_FPU_SW(thread) ((thread)->td_pcb->pcb_save.sv_env.en_sw) 106 107typedef u_char bool_t; 108 109static int fpu_attach(device_t dev); 110static void fpu_identify(driver_t *driver, device_t parent); 111static int fpu_probe(device_t dev); 112 113int hw_float = 1; 114SYSCTL_INT(_hw,HW_FLOATINGPT, floatingpoint, 115 CTLFLAG_RD, &hw_float, 0, 116 "Floatingpoint instructions executed in hardware"); 117 118static struct savefpu fpu_cleanstate; 119static bool_t fpu_cleanstate_ready; 120 121/* 122 * Identify routine. Create a connection point on our parent for probing. 123 */ 124static void 125fpu_identify(driver_t *driver, device_t parent) 126{ 127 device_t child; 128 129 child = BUS_ADD_CHILD(parent, 0, "fpu", 0); 130 if (child == NULL) 131 panic("fpu_identify"); 132} 133 134/* 135 * Probe routine. Initialize cr0 to give correct behaviour for [f]wait 136 * whether the device exists or not (XXX should be elsewhere). 137 * Modify device struct if fpu doesn't need to use interrupts. 138 * Return 0 if device exists. 139 */ 140static int 141fpu_probe(device_t dev) 142{ 143 144 /* 145 * Prepare to trap all ESC (i.e., FPU) instructions and all WAIT 146 * instructions. We must set the CR0_MP bit and use the CR0_TS 147 * bit to control the trap, because setting the CR0_EM bit does 148 * not cause WAIT instructions to trap. It's important to trap 149 * WAIT instructions - otherwise the "wait" variants of no-wait 150 * control instructions would degenerate to the "no-wait" variants 151 * after FP context switches but work correctly otherwise. It's 152 * particularly important to trap WAITs when there is no FPU - 153 * otherwise the "wait" variants would always degenerate. 154 * 155 * Try setting CR0_NE to get correct error reporting on 486DX's. 156 * Setting it should fail or do nothing on lesser processors. 157 */ 158 load_cr0(rcr0() | CR0_MP | CR0_NE); 159 /* 160 * But don't trap while we're probing. 161 */ 162 stop_emulating(); 163 /* 164 * Finish resetting the coprocessor. 165 */ 166 fninit(); 167 168 device_set_desc(dev, "math processor"); 169 device_quiet(dev); 170 171 return (0); 172} 173 174/* 175 * Attach routine - announce which it is, and wire into system 176 */ 177static int 178fpu_attach(device_t dev) 179{ 180 register_t s; 181 182 fpuinit(__INITIAL_FPUCW__); 183 184 if (fpu_cleanstate_ready == 0) { 185 s = intr_disable(); 186 stop_emulating(); 187 fxsave(&fpu_cleanstate); 188 start_emulating(); 189 fpu_cleanstate_ready = 1; 190 intr_restore(s); 191 } 192 return (0); /* XXX unused */ 193} 194 195/* 196 * Initialize floating point unit. 197 */ 198void 199fpuinit(u_short control) 200{ 201 static struct savefpu dummy; 202 register_t savecrit; 203 204 /* 205 * fninit has the same h/w bugs as fnsave. Use the detoxified 206 * fnsave to throw away any junk in the fpu. fpusave() initializes 207 * the fpu and sets fpcurthread = NULL as important side effects. 208 */ 209 savecrit = intr_disable(); 210 fpusave(&dummy); 211 stop_emulating(); 212 /* XXX fpusave() doesn't actually initialize the fpu in the SSE case. */ 213 fninit(); 214 fldcw(&control); 215 start_emulating(); 216 intr_restore(savecrit); 217} 218 219/* 220 * Free coprocessor (if we have it). 221 */ 222void 223fpuexit(struct thread *td) 224{ 225 register_t savecrit; 226 227 savecrit = intr_disable(); 228 if (curthread == PCPU_GET(fpcurthread)) 229 fpusave(&PCPU_GET(curpcb)->pcb_save); 230 intr_restore(savecrit); 231} 232 233int 234fpuformat() 235{ 236 237 return (_MC_FPFMT_XMM); 238} 239 240/* 241 * The following mechanism is used to ensure that the FPE_... value 242 * that is passed as a trapcode to the signal handler of the user 243 * process does not have more than one bit set. 244 * 245 * Multiple bits may be set if the user process modifies the control 246 * word while a status word bit is already set. While this is a sign 247 * of bad coding, we have no choise than to narrow them down to one 248 * bit, since we must not send a trapcode that is not exactly one of 249 * the FPE_ macros. 250 * 251 * The mechanism has a static table with 127 entries. Each combination 252 * of the 7 FPU status word exception bits directly translates to a 253 * position in this table, where a single FPE_... value is stored. 254 * This FPE_... value stored there is considered the "most important" 255 * of the exception bits and will be sent as the signal code. The 256 * precedence of the bits is based upon Intel Document "Numerical 257 * Applications", Chapter "Special Computational Situations". 258 * 259 * The macro to choose one of these values does these steps: 1) Throw 260 * away status word bits that cannot be masked. 2) Throw away the bits 261 * currently masked in the control word, assuming the user isn't 262 * interested in them anymore. 3) Reinsert status word bit 7 (stack 263 * fault) if it is set, which cannot be masked but must be presered. 264 * 4) Use the remaining bits to point into the trapcode table. 265 * 266 * The 6 maskable bits in order of their preference, as stated in the 267 * above referenced Intel manual: 268 * 1 Invalid operation (FP_X_INV) 269 * 1a Stack underflow 270 * 1b Stack overflow 271 * 1c Operand of unsupported format 272 * 1d SNaN operand. 273 * 2 QNaN operand (not an exception, irrelavant here) 274 * 3 Any other invalid-operation not mentioned above or zero divide 275 * (FP_X_INV, FP_X_DZ) 276 * 4 Denormal operand (FP_X_DNML) 277 * 5 Numeric over/underflow (FP_X_OFL, FP_X_UFL) 278 * 6 Inexact result (FP_X_IMP) 279 */ 280static char fpetable[128] = { 281 0, 282 FPE_FLTINV, /* 1 - INV */ 283 FPE_FLTUND, /* 2 - DNML */ 284 FPE_FLTINV, /* 3 - INV | DNML */ 285 FPE_FLTDIV, /* 4 - DZ */ 286 FPE_FLTINV, /* 5 - INV | DZ */ 287 FPE_FLTDIV, /* 6 - DNML | DZ */ 288 FPE_FLTINV, /* 7 - INV | DNML | DZ */ 289 FPE_FLTOVF, /* 8 - OFL */ 290 FPE_FLTINV, /* 9 - INV | OFL */ 291 FPE_FLTUND, /* A - DNML | OFL */ 292 FPE_FLTINV, /* B - INV | DNML | OFL */ 293 FPE_FLTDIV, /* C - DZ | OFL */ 294 FPE_FLTINV, /* D - INV | DZ | OFL */ 295 FPE_FLTDIV, /* E - DNML | DZ | OFL */ 296 FPE_FLTINV, /* F - INV | DNML | DZ | OFL */ 297 FPE_FLTUND, /* 10 - UFL */ 298 FPE_FLTINV, /* 11 - INV | UFL */ 299 FPE_FLTUND, /* 12 - DNML | UFL */ 300 FPE_FLTINV, /* 13 - INV | DNML | UFL */ 301 FPE_FLTDIV, /* 14 - DZ | UFL */ 302 FPE_FLTINV, /* 15 - INV | DZ | UFL */ 303 FPE_FLTDIV, /* 16 - DNML | DZ | UFL */ 304 FPE_FLTINV, /* 17 - INV | DNML | DZ | UFL */ 305 FPE_FLTOVF, /* 18 - OFL | UFL */ 306 FPE_FLTINV, /* 19 - INV | OFL | UFL */ 307 FPE_FLTUND, /* 1A - DNML | OFL | UFL */ 308 FPE_FLTINV, /* 1B - INV | DNML | OFL | UFL */ 309 FPE_FLTDIV, /* 1C - DZ | OFL | UFL */ 310 FPE_FLTINV, /* 1D - INV | DZ | OFL | UFL */ 311 FPE_FLTDIV, /* 1E - DNML | DZ | OFL | UFL */ 312 FPE_FLTINV, /* 1F - INV | DNML | DZ | OFL | UFL */ 313 FPE_FLTRES, /* 20 - IMP */ 314 FPE_FLTINV, /* 21 - INV | IMP */ 315 FPE_FLTUND, /* 22 - DNML | IMP */ 316 FPE_FLTINV, /* 23 - INV | DNML | IMP */ 317 FPE_FLTDIV, /* 24 - DZ | IMP */ 318 FPE_FLTINV, /* 25 - INV | DZ | IMP */ 319 FPE_FLTDIV, /* 26 - DNML | DZ | IMP */ 320 FPE_FLTINV, /* 27 - INV | DNML | DZ | IMP */ 321 FPE_FLTOVF, /* 28 - OFL | IMP */ 322 FPE_FLTINV, /* 29 - INV | OFL | IMP */ 323 FPE_FLTUND, /* 2A - DNML | OFL | IMP */ 324 FPE_FLTINV, /* 2B - INV | DNML | OFL | IMP */ 325 FPE_FLTDIV, /* 2C - DZ | OFL | IMP */ 326 FPE_FLTINV, /* 2D - INV | DZ | OFL | IMP */ 327 FPE_FLTDIV, /* 2E - DNML | DZ | OFL | IMP */ 328 FPE_FLTINV, /* 2F - INV | DNML | DZ | OFL | IMP */ 329 FPE_FLTUND, /* 30 - UFL | IMP */ 330 FPE_FLTINV, /* 31 - INV | UFL | IMP */ 331 FPE_FLTUND, /* 32 - DNML | UFL | IMP */ 332 FPE_FLTINV, /* 33 - INV | DNML | UFL | IMP */ 333 FPE_FLTDIV, /* 34 - DZ | UFL | IMP */ 334 FPE_FLTINV, /* 35 - INV | DZ | UFL | IMP */ 335 FPE_FLTDIV, /* 36 - DNML | DZ | UFL | IMP */ 336 FPE_FLTINV, /* 37 - INV | DNML | DZ | UFL | IMP */ 337 FPE_FLTOVF, /* 38 - OFL | UFL | IMP */ 338 FPE_FLTINV, /* 39 - INV | OFL | UFL | IMP */ 339 FPE_FLTUND, /* 3A - DNML | OFL | UFL | IMP */ 340 FPE_FLTINV, /* 3B - INV | DNML | OFL | UFL | IMP */ 341 FPE_FLTDIV, /* 3C - DZ | OFL | UFL | IMP */ 342 FPE_FLTINV, /* 3D - INV | DZ | OFL | UFL | IMP */ 343 FPE_FLTDIV, /* 3E - DNML | DZ | OFL | UFL | IMP */ 344 FPE_FLTINV, /* 3F - INV | DNML | DZ | OFL | UFL | IMP */ 345 FPE_FLTSUB, /* 40 - STK */ 346 FPE_FLTSUB, /* 41 - INV | STK */ 347 FPE_FLTUND, /* 42 - DNML | STK */ 348 FPE_FLTSUB, /* 43 - INV | DNML | STK */ 349 FPE_FLTDIV, /* 44 - DZ | STK */ 350 FPE_FLTSUB, /* 45 - INV | DZ | STK */ 351 FPE_FLTDIV, /* 46 - DNML | DZ | STK */ 352 FPE_FLTSUB, /* 47 - INV | DNML | DZ | STK */ 353 FPE_FLTOVF, /* 48 - OFL | STK */ 354 FPE_FLTSUB, /* 49 - INV | OFL | STK */ 355 FPE_FLTUND, /* 4A - DNML | OFL | STK */ 356 FPE_FLTSUB, /* 4B - INV | DNML | OFL | STK */ 357 FPE_FLTDIV, /* 4C - DZ | OFL | STK */ 358 FPE_FLTSUB, /* 4D - INV | DZ | OFL | STK */ 359 FPE_FLTDIV, /* 4E - DNML | DZ | OFL | STK */ 360 FPE_FLTSUB, /* 4F - INV | DNML | DZ | OFL | STK */ 361 FPE_FLTUND, /* 50 - UFL | STK */ 362 FPE_FLTSUB, /* 51 - INV | UFL | STK */ 363 FPE_FLTUND, /* 52 - DNML | UFL | STK */ 364 FPE_FLTSUB, /* 53 - INV | DNML | UFL | STK */ 365 FPE_FLTDIV, /* 54 - DZ | UFL | STK */ 366 FPE_FLTSUB, /* 55 - INV | DZ | UFL | STK */ 367 FPE_FLTDIV, /* 56 - DNML | DZ | UFL | STK */ 368 FPE_FLTSUB, /* 57 - INV | DNML | DZ | UFL | STK */ 369 FPE_FLTOVF, /* 58 - OFL | UFL | STK */ 370 FPE_FLTSUB, /* 59 - INV | OFL | UFL | STK */ 371 FPE_FLTUND, /* 5A - DNML | OFL | UFL | STK */ 372 FPE_FLTSUB, /* 5B - INV | DNML | OFL | UFL | STK */ 373 FPE_FLTDIV, /* 5C - DZ | OFL | UFL | STK */ 374 FPE_FLTSUB, /* 5D - INV | DZ | OFL | UFL | STK */ 375 FPE_FLTDIV, /* 5E - DNML | DZ | OFL | UFL | STK */ 376 FPE_FLTSUB, /* 5F - INV | DNML | DZ | OFL | UFL | STK */ 377 FPE_FLTRES, /* 60 - IMP | STK */ 378 FPE_FLTSUB, /* 61 - INV | IMP | STK */ 379 FPE_FLTUND, /* 62 - DNML | IMP | STK */ 380 FPE_FLTSUB, /* 63 - INV | DNML | IMP | STK */ 381 FPE_FLTDIV, /* 64 - DZ | IMP | STK */ 382 FPE_FLTSUB, /* 65 - INV | DZ | IMP | STK */ 383 FPE_FLTDIV, /* 66 - DNML | DZ | IMP | STK */ 384 FPE_FLTSUB, /* 67 - INV | DNML | DZ | IMP | STK */ 385 FPE_FLTOVF, /* 68 - OFL | IMP | STK */ 386 FPE_FLTSUB, /* 69 - INV | OFL | IMP | STK */ 387 FPE_FLTUND, /* 6A - DNML | OFL | IMP | STK */ 388 FPE_FLTSUB, /* 6B - INV | DNML | OFL | IMP | STK */ 389 FPE_FLTDIV, /* 6C - DZ | OFL | IMP | STK */ 390 FPE_FLTSUB, /* 6D - INV | DZ | OFL | IMP | STK */ 391 FPE_FLTDIV, /* 6E - DNML | DZ | OFL | IMP | STK */ 392 FPE_FLTSUB, /* 6F - INV | DNML | DZ | OFL | IMP | STK */ 393 FPE_FLTUND, /* 70 - UFL | IMP | STK */ 394 FPE_FLTSUB, /* 71 - INV | UFL | IMP | STK */ 395 FPE_FLTUND, /* 72 - DNML | UFL | IMP | STK */ 396 FPE_FLTSUB, /* 73 - INV | DNML | UFL | IMP | STK */ 397 FPE_FLTDIV, /* 74 - DZ | UFL | IMP | STK */ 398 FPE_FLTSUB, /* 75 - INV | DZ | UFL | IMP | STK */ 399 FPE_FLTDIV, /* 76 - DNML | DZ | UFL | IMP | STK */ 400 FPE_FLTSUB, /* 77 - INV | DNML | DZ | UFL | IMP | STK */ 401 FPE_FLTOVF, /* 78 - OFL | UFL | IMP | STK */ 402 FPE_FLTSUB, /* 79 - INV | OFL | UFL | IMP | STK */ 403 FPE_FLTUND, /* 7A - DNML | OFL | UFL | IMP | STK */ 404 FPE_FLTSUB, /* 7B - INV | DNML | OFL | UFL | IMP | STK */ 405 FPE_FLTDIV, /* 7C - DZ | OFL | UFL | IMP | STK */ 406 FPE_FLTSUB, /* 7D - INV | DZ | OFL | UFL | IMP | STK */ 407 FPE_FLTDIV, /* 7E - DNML | DZ | OFL | UFL | IMP | STK */ 408 FPE_FLTSUB, /* 7F - INV | DNML | DZ | OFL | UFL | IMP | STK */ 409}; 410 411/* 412 * Preserve the FP status word, clear FP exceptions, then generate a SIGFPE. 413 * 414 * Clearing exceptions is necessary mainly to avoid IRQ13 bugs. We now 415 * depend on longjmp() restoring a usable state. Restoring the state 416 * or examining it might fail if we didn't clear exceptions. 417 * 418 * The error code chosen will be one of the FPE_... macros. It will be 419 * sent as the second argument to old BSD-style signal handlers and as 420 * "siginfo_t->si_code" (second argument) to SA_SIGINFO signal handlers. 421 * 422 * XXX the FP state is not preserved across signal handlers. So signal 423 * handlers cannot afford to do FP unless they preserve the state or 424 * longjmp() out. Both preserving the state and longjmp()ing may be 425 * destroyed by IRQ13 bugs. Clearing FP exceptions is not an acceptable 426 * solution for signals other than SIGFPE. 427 */ 428int 429fputrap() 430{ 431 register_t savecrit; 432 u_short control, status; 433 434 savecrit = intr_disable(); 435 436 /* 437 * Interrupt handling (for another interrupt) may have pushed the 438 * state to memory. Fetch the relevant parts of the state from 439 * wherever they are. 440 */ 441 if (PCPU_GET(fpcurthread) != curthread) { 442 control = GET_FPU_CW(curthread); 443 status = GET_FPU_SW(curthread); 444 } else { 445 fnstcw(&control); 446 fnstsw(&status); 447 } 448 449 if (PCPU_GET(fpcurthread) == curthread) 450 fnclex(); 451 intr_restore(savecrit); 452 return (fpetable[status & ((~control & 0x3f) | 0x40)]); 453} 454 455/* 456 * Implement device not available (DNA) exception 457 * 458 * It would be better to switch FP context here (if curthread != fpcurthread) 459 * and not necessarily for every context switch, but it is too hard to 460 * access foreign pcb's. 461 */ 462 463static int err_count = 0; 464 465int 466fpudna() 467{ 468 struct pcb *pcb; 469 register_t s; 470 u_short control; 471 472 if (PCPU_GET(fpcurthread) == curthread) { 473 printf("fpudna: fpcurthread == curthread %d times\n", 474 ++err_count); 475 stop_emulating(); 476 return (1); 477 } 478 if (PCPU_GET(fpcurthread) != NULL) { 479 printf("fpudna: fpcurthread = %p (%d), curthread = %p (%d)\n", 480 PCPU_GET(fpcurthread), 481 PCPU_GET(fpcurthread)->td_proc->p_pid, 482 curthread, curthread->td_proc->p_pid); 483 panic("fpudna"); 484 } 485 s = intr_disable(); 486 stop_emulating(); 487 /* 488 * Record new context early in case frstor causes a trap. 489 */ 490 PCPU_SET(fpcurthread, curthread); 491 pcb = PCPU_GET(curpcb); 492 493 if ((pcb->pcb_flags & PCB_FPUINITDONE) == 0) { 494 /* 495 * This is the first time this thread has used the FPU or 496 * the PCB doesn't contain a clean FPU state. Explicitly 497 * initialize the FPU and load the default control word. 498 */ 499 fninit(); 500 control = __INITIAL_FPUCW__; 501 fldcw(&control); 502 pcb->pcb_flags |= PCB_FPUINITDONE; 503 } else { 504 /* 505 * The following frstor may cause a trap when the state 506 * being restored has a pending error. The error will 507 * appear to have been triggered by the current (fpu) user 508 * instruction even when that instruction is a no-wait 509 * instruction that should not trigger an error (e.g., 510 * instructions are broken the same as frstor, so our 511 * treatment does not amplify the breakage. 512 */ 513 fxrstor(&pcb->pcb_save); 514 } 515 intr_restore(s); 516 517 return (1); 518} 519 520/* 521 * Wrapper for fnsave instruction. 522 * 523 * fpusave() must be called with interrupts disabled, so that it clears 524 * fpcurthread atomically with saving the state. We require callers to do the 525 * disabling, since most callers need to disable interrupts anyway to call 526 * fpusave() atomically with checking fpcurthread. 527 */ 528void 529fpusave(struct savefpu *addr) 530{ 531 532 stop_emulating(); 533 fxsave(addr); 534 start_emulating(); 535 PCPU_SET(fpcurthread, NULL); 536} 537 538/* 539 * This should be called with interrupts disabled and only when the owning 540 * FPU thread is non-null. 541 */ 542void 543fpudrop() 544{ 545 struct thread *td; 546 547 td = PCPU_GET(fpcurthread); 548 PCPU_SET(fpcurthread, NULL); 549 td->td_pcb->pcb_flags &= ~PCB_FPUINITDONE; 550 start_emulating(); 551} 552 553/* 554 * Get the state of the FPU without dropping ownership (if possible). 555 * It returns the FPU ownership status. 556 */ 557int 558fpugetregs(struct thread *td, struct savefpu *addr) 559{ 560 register_t s; 561 562 if ((td->td_pcb->pcb_flags & PCB_FPUINITDONE) == 0) { 563 if (fpu_cleanstate_ready) 564 bcopy(&fpu_cleanstate, addr, sizeof(fpu_cleanstate)); 565 else 566 bzero(addr, sizeof(*addr)); 567 return (_MC_FPOWNED_NONE); 568 } 569 s = intr_disable(); 570 if (td == PCPU_GET(fpcurthread)) { 571 fxsave(addr); 572 intr_restore(s); 573 return (_MC_FPOWNED_FPU); 574 } else { 575 intr_restore(s); 576 bcopy(&td->td_pcb->pcb_save, addr, sizeof(*addr)); 577 return (_MC_FPOWNED_PCB); 578 } 579} 580 581/* 582 * Set the state of the FPU. 583 */ 584void 585fpusetregs(struct thread *td, struct savefpu *addr) 586{ 587 register_t s; 588 589 s = intr_disable(); 590 if (td == PCPU_GET(fpcurthread)) { 591 fxrstor(addr); 592 intr_restore(s); 593 } else { 594 intr_restore(s); 595 bcopy(addr, &td->td_pcb->pcb_save, sizeof(*addr)); 596 } 597 curthread->td_pcb->pcb_flags |= PCB_FPUINITDONE; 598} 599 600static device_method_t fpu_methods[] = { 601 /* Device interface */ 602 DEVMETHOD(device_identify, fpu_identify), 603 DEVMETHOD(device_probe, fpu_probe), 604 DEVMETHOD(device_attach, fpu_attach), 605 DEVMETHOD(device_detach, bus_generic_detach), 606 DEVMETHOD(device_shutdown, bus_generic_shutdown), 607 DEVMETHOD(device_suspend, bus_generic_suspend), 608 DEVMETHOD(device_resume, bus_generic_resume), 609 610 { 0, 0 } 611}; 612 613static driver_t fpu_driver = { 614 "fpu", 615 fpu_methods, 616 1, /* no softc */ 617}; 618 619static devclass_t fpu_devclass; 620 621/* 622 * We prefer to attach to the root nexus so that the usual case (exception 16) 623 * doesn't describe the processor as being `on isa'. 624 */ 625DRIVER_MODULE(fpu, nexus, fpu_driver, fpu_devclass, 0, 0); 626 627#ifdef DEV_ISA 628/* 629 * This sucks up the legacy ISA support assignments from PNPBIOS/ACPI. 630 */ 631static struct isa_pnp_id fpuisa_ids[] = { 632 { 0x040cd041, "Legacy ISA coprocessor support" }, /* PNP0C04 */ 633 { 0 } 634}; 635 636static int 637fpuisa_probe(device_t dev) 638{ 639 int result; 640 641 result = ISA_PNP_PROBE(device_get_parent(dev), dev, fpuisa_ids); 642 if (result <= 0) 643 device_quiet(dev); 644 return (result); 645} 646 647static int 648fpuisa_attach(device_t dev) 649{ 650 651 return (0); 652} 653 654static device_method_t fpuisa_methods[] = { 655 /* Device interface */ 656 DEVMETHOD(device_probe, fpuisa_probe), 657 DEVMETHOD(device_attach, fpuisa_attach), 658 DEVMETHOD(device_detach, bus_generic_detach), 659 DEVMETHOD(device_shutdown, bus_generic_shutdown), 660 DEVMETHOD(device_suspend, bus_generic_suspend), 661 DEVMETHOD(device_resume, bus_generic_resume), 662 663 { 0, 0 } 664}; 665 666static driver_t fpuisa_driver = { 667 "fpuisa", 668 fpuisa_methods, 669 1, /* no softc */ 670}; 671 672static devclass_t fpuisa_devclass; 673 674DRIVER_MODULE(fpuisa, isa, fpuisa_driver, fpuisa_devclass, 0, 0); 675DRIVER_MODULE(fpuisa, acpi, fpuisa_driver, fpuisa_devclass, 0, 0); 676#endif /* DEV_ISA */ 677