fpu.c (122269) | fpu.c (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: --- 21 unchanged lines hidden (view full) --- 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> | 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: --- 21 unchanged lines hidden (view full) --- 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 122269 2003-11-08 00:13:43Z peter $"); | 38__FBSDID("$FreeBSD: head/sys/amd64/amd64/fpu.c 122292 2003-11-08 03:33:38Z peter $"); |
39 | 39 |
40#include "opt_debug_npx.h" | |
41#include "opt_isa.h" 42 43#include <sys/param.h> 44#include <sys/systm.h> 45#include <sys/bus.h> 46#include <sys/kernel.h> 47#include <sys/lock.h> 48#include <sys/malloc.h> 49#include <sys/module.h> 50#include <sys/mutex.h> 51#include <sys/mutex.h> 52#include <sys/proc.h> 53#include <sys/sysctl.h> 54#include <machine/bus.h> 55#include <sys/rman.h> | 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> |
56#ifdef NPX_DEBUG 57#include <sys/syslog.h> 58#endif | |
59#include <sys/signalvar.h> 60#include <sys/user.h> 61 62#include <machine/cputypes.h> 63#include <machine/frame.h> 64#include <machine/md_var.h> 65#include <machine/pcb.h> 66#include <machine/psl.h> 67#include <machine/resource.h> 68#include <machine/specialreg.h> 69#include <machine/segments.h> 70#include <machine/ucontext.h> 71 72#include <amd64/isa/intr_machdep.h> 73#ifdef DEV_ISA 74#include <isa/isavar.h> 75#endif 76 77/* | 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/* |
78 * 387 and 287 Numeric Coprocessor Extension (NPX) Driver. | 74 * Floating point support. |
79 */ 80 81#if defined(__GNUC__) && !defined(lint) 82 83#define fldcw(addr) __asm("fldcw %0" : : "m" (*(addr))) 84#define fnclex() __asm("fnclex") 85#define fninit() __asm("fninit") 86#define fnstcw(addr) __asm __volatile("fnstcw %0" : "=m" (*(addr))) --- 18 unchanged lines hidden (view full) --- 105 106#endif /* __GNUC__ */ 107 108#define GET_FPU_CW(thread) ((thread)->td_pcb->pcb_save.sv_env.en_cw) 109#define GET_FPU_SW(thread) ((thread)->td_pcb->pcb_save.sv_env.en_sw) 110 111typedef u_char bool_t; 112 | 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))) --- 18 unchanged lines hidden (view full) --- 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 |
113static int npx_attach(device_t dev); 114static void npx_identify(driver_t *driver, device_t parent); 115static int npx_probe(device_t dev); | 109static int fpu_attach(device_t dev); 110static void fpu_identify(driver_t *driver, device_t parent); 111static int fpu_probe(device_t dev); |
116 117int hw_float = 1; 118SYSCTL_INT(_hw,HW_FLOATINGPT, floatingpoint, 119 CTLFLAG_RD, &hw_float, 0, 120 "Floatingpoint instructions executed in hardware"); 121 | 112 113int hw_float = 1; 114SYSCTL_INT(_hw,HW_FLOATINGPT, floatingpoint, 115 CTLFLAG_RD, &hw_float, 0, 116 "Floatingpoint instructions executed in hardware"); 117 |
122static struct savefpu npx_cleanstate; 123static bool_t npx_cleanstate_ready; | 118static struct savefpu fpu_cleanstate; 119static bool_t fpu_cleanstate_ready; |
124 125/* 126 * Identify routine. Create a connection point on our parent for probing. 127 */ 128static void | 120 121/* 122 * Identify routine. Create a connection point on our parent for probing. 123 */ 124static void |
129npx_identify(driver, parent) 130 driver_t *driver; 131 device_t parent; | 125fpu_identify(driver_t *driver, device_t parent) |
132{ 133 device_t child; 134 | 126{ 127 device_t child; 128 |
135 child = BUS_ADD_CHILD(parent, 0, "npx", 0); | 129 child = BUS_ADD_CHILD(parent, 0, "fpu", 0); |
136 if (child == NULL) | 130 if (child == NULL) |
137 panic("npx_identify"); | 131 panic("fpu_identify"); |
138} 139 140/* 141 * Probe routine. Initialize cr0 to give correct behaviour for [f]wait 142 * whether the device exists or not (XXX should be elsewhere). | 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). |
143 * Modify device struct if npx doesn't need to use interrupts. | 137 * Modify device struct if fpu doesn't need to use interrupts. |
144 * Return 0 if device exists. 145 */ 146static int | 138 * Return 0 if device exists. 139 */ 140static int |
147npx_probe(dev) 148 device_t dev; | 141fpu_probe(device_t dev) |
149{ 150 151 /* | 142{ 143 144 /* |
152 * Partially reset the coprocessor, if any. Some BIOS's don't reset 153 * it after a warm boot. 154 */ 155 outb(0xf1, 0); /* full reset on some systems, NOP on others */ 156 outb(0xf0, 0); /* clear BUSY# latch */ 157 /* 158 * Prepare to trap all ESC (i.e., NPX) instructions and all WAIT | 145 * Prepare to trap all ESC (i.e., FPU) instructions and all WAIT |
159 * instructions. We must set the CR0_MP bit and use the CR0_TS 160 * bit to control the trap, because setting the CR0_EM bit does 161 * not cause WAIT instructions to trap. It's important to trap 162 * WAIT instructions - otherwise the "wait" variants of no-wait 163 * control instructions would degenerate to the "no-wait" variants 164 * after FP context switches but work correctly otherwise. It's | 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 |
165 * particularly important to trap WAITs when there is no NPX - | 152 * particularly important to trap WAITs when there is no FPU - |
166 * otherwise the "wait" variants would always degenerate. 167 * 168 * Try setting CR0_NE to get correct error reporting on 486DX's. 169 * Setting it should fail or do nothing on lesser processors. 170 */ 171 load_cr0(rcr0() | CR0_MP | CR0_NE); 172 /* 173 * But don't trap while we're probing. 174 */ 175 stop_emulating(); 176 /* 177 * Finish resetting the coprocessor. 178 */ 179 fninit(); 180 181 device_set_desc(dev, "math processor"); | 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); |
|
182 183 return (0); 184} 185 186/* 187 * Attach routine - announce which it is, and wire into system 188 */ 189static int | 170 171 return (0); 172} 173 174/* 175 * Attach routine - announce which it is, and wire into system 176 */ 177static int |
190npx_attach(dev) 191 device_t dev; | 178fpu_attach(device_t dev) |
192{ 193 register_t s; 194 | 179{ 180 register_t s; 181 |
195 npxinit(__INITIAL_NPXCW__); | 182 fpuinit(__INITIAL_FPUCW__); |
196 | 183 |
197 if (npx_cleanstate_ready == 0) { | 184 if (fpu_cleanstate_ready == 0) { |
198 s = intr_disable(); 199 stop_emulating(); | 185 s = intr_disable(); 186 stop_emulating(); |
200 fxsave(&npx_cleanstate); | 187 fxsave(&fpu_cleanstate); |
201 start_emulating(); | 188 start_emulating(); |
202 npx_cleanstate_ready = 1; | 189 fpu_cleanstate_ready = 1; |
203 intr_restore(s); 204 } 205 return (0); /* XXX unused */ 206} 207 208/* 209 * Initialize floating point unit. 210 */ 211void | 190 intr_restore(s); 191 } 192 return (0); /* XXX unused */ 193} 194 195/* 196 * Initialize floating point unit. 197 */ 198void |
212npxinit(control) 213 u_short control; | 199fpuinit(u_short control) |
214{ 215 static struct savefpu dummy; 216 register_t savecrit; 217 218 /* 219 * fninit has the same h/w bugs as fnsave. Use the detoxified | 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 |
220 * fnsave to throw away any junk in the fpu. npxsave() initializes | 206 * fnsave to throw away any junk in the fpu. fpusave() initializes |
221 * the fpu and sets fpcurthread = NULL as important side effects. 222 */ 223 savecrit = intr_disable(); | 207 * the fpu and sets fpcurthread = NULL as important side effects. 208 */ 209 savecrit = intr_disable(); |
224 npxsave(&dummy); | 210 fpusave(&dummy); |
225 stop_emulating(); | 211 stop_emulating(); |
226 /* XXX npxsave() doesn't actually initialize the fpu in the SSE case. */ | 212 /* XXX fpusave() doesn't actually initialize the fpu in the SSE case. */ |
227 fninit(); 228 fldcw(&control); 229 start_emulating(); 230 intr_restore(savecrit); 231} 232 233/* 234 * Free coprocessor (if we have it). 235 */ 236void | 213 fninit(); 214 fldcw(&control); 215 start_emulating(); 216 intr_restore(savecrit); 217} 218 219/* 220 * Free coprocessor (if we have it). 221 */ 222void |
237npxexit(td) 238 struct thread *td; | 223fpuexit(struct thread *td) |
239{ | 224{ |
240#ifdef NPX_DEBUG 241 u_int masked_exceptions; 242#endif | |
243 register_t savecrit; 244 245 savecrit = intr_disable(); 246 if (curthread == PCPU_GET(fpcurthread)) | 225 register_t savecrit; 226 227 savecrit = intr_disable(); 228 if (curthread == PCPU_GET(fpcurthread)) |
247 npxsave(&PCPU_GET(curpcb)->pcb_save); | 229 fpusave(&PCPU_GET(curpcb)->pcb_save); |
248 intr_restore(savecrit); | 230 intr_restore(savecrit); |
249#ifdef NPX_DEBUG 250 masked_exceptions = GET_FPU_CW(td) & GET_FPU_SW(td) & 0x7f; 251 /* 252 * Log exceptions that would have trapped with the old 253 * control word (overflow, divide by 0, and invalid operand). 254 */ 255 if (masked_exceptions & 0x0d) 256 log(LOG_ERR, 257"pid %d (%s) exited with masked floating point exceptions 0x%02x\n", 258 td->td_proc->p_pid, td->td_proc->p_comm, 259 masked_exceptions); 260#endif | |
261} 262 263int | 231} 232 233int |
264npxformat() | 234fpuformat() |
265{ 266 267 return (_MC_FPFMT_XMM); 268} 269 270/* 271 * The following mechanism is used to ensure that the FPE_... value 272 * that is passed as a trapcode to the signal handler of the user --- 178 unchanged lines hidden (view full) --- 451 * 452 * XXX the FP state is not preserved across signal handlers. So signal 453 * handlers cannot afford to do FP unless they preserve the state or 454 * longjmp() out. Both preserving the state and longjmp()ing may be 455 * destroyed by IRQ13 bugs. Clearing FP exceptions is not an acceptable 456 * solution for signals other than SIGFPE. 457 */ 458int | 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 --- 178 unchanged lines hidden (view full) --- 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 |
459npxtrap() | 429fputrap() |
460{ 461 register_t savecrit; 462 u_short control, status; 463 464 savecrit = intr_disable(); 465 466 /* 467 * Interrupt handling (for another interrupt) may have pushed the --- 20 unchanged lines hidden (view full) --- 488 * It would be better to switch FP context here (if curthread != fpcurthread) 489 * and not necessarily for every context switch, but it is too hard to 490 * access foreign pcb's. 491 */ 492 493static int err_count = 0; 494 495int | 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 --- 20 unchanged lines hidden (view full) --- 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 |
496npxdna() | 466fpudna() |
497{ 498 struct pcb *pcb; 499 register_t s; 500 u_short control; 501 502 if (PCPU_GET(fpcurthread) == curthread) { | 467{ 468 struct pcb *pcb; 469 register_t s; 470 u_short control; 471 472 if (PCPU_GET(fpcurthread) == curthread) { |
503 printf("npxdna: fpcurthread == curthread %d times\n", | 473 printf("fpudna: fpcurthread == curthread %d times\n", |
504 ++err_count); 505 stop_emulating(); 506 return (1); 507 } 508 if (PCPU_GET(fpcurthread) != NULL) { | 474 ++err_count); 475 stop_emulating(); 476 return (1); 477 } 478 if (PCPU_GET(fpcurthread) != NULL) { |
509 printf("npxdna: fpcurthread = %p (%d), curthread = %p (%d)\n", | 479 printf("fpudna: fpcurthread = %p (%d), curthread = %p (%d)\n", |
510 PCPU_GET(fpcurthread), 511 PCPU_GET(fpcurthread)->td_proc->p_pid, 512 curthread, curthread->td_proc->p_pid); | 480 PCPU_GET(fpcurthread), 481 PCPU_GET(fpcurthread)->td_proc->p_pid, 482 curthread, curthread->td_proc->p_pid); |
513 panic("npxdna"); | 483 panic("fpudna"); |
514 } 515 s = intr_disable(); 516 stop_emulating(); 517 /* | 484 } 485 s = intr_disable(); 486 stop_emulating(); 487 /* |
518 * Record new context early in case frstor causes an IRQ13. | 488 * Record new context early in case frstor causes a trap. |
519 */ 520 PCPU_SET(fpcurthread, curthread); 521 pcb = PCPU_GET(curpcb); 522 | 489 */ 490 PCPU_SET(fpcurthread, curthread); 491 pcb = PCPU_GET(curpcb); 492 |
523 if ((pcb->pcb_flags & PCB_NPXINITDONE) == 0) { | 493 if ((pcb->pcb_flags & PCB_FPUINITDONE) == 0) { |
524 /* 525 * This is the first time this thread has used the FPU or 526 * the PCB doesn't contain a clean FPU state. Explicitly 527 * initialize the FPU and load the default control word. 528 */ 529 fninit(); | 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(); |
530 control = __INITIAL_NPXCW__; | 500 control = __INITIAL_FPUCW__; |
531 fldcw(&control); | 501 fldcw(&control); |
532 pcb->pcb_flags |= PCB_NPXINITDONE; | 502 pcb->pcb_flags |= PCB_FPUINITDONE; |
533 } else { 534 /* 535 * The following frstor may cause a trap when the state 536 * being restored has a pending error. The error will | 503 } else { 504 /* 505 * The following frstor may cause a trap when the state 506 * being restored has a pending error. The error will |
537 * appear to have been triggered by the current (npx) user | 507 * appear to have been triggered by the current (fpu) user |
538 * instruction even when that instruction is a no-wait 539 * instruction that should not trigger an error (e.g., 540 * instructions are broken the same as frstor, so our 541 * treatment does not amplify the breakage. 542 */ 543 fxrstor(&pcb->pcb_save); 544 } 545 intr_restore(s); 546 547 return (1); 548} 549 550/* | 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/* |
551 * Wrapper for fnsave instruction, partly to handle hardware bugs. When npx 552 * exceptions are reported via IRQ13, spurious IRQ13's may be triggered by 553 * no-wait npx instructions. See the Intel application note AP-578 for 554 * details. This doesn't cause any additional complications here. IRQ13's 555 * are inherently asynchronous unless the CPU is frozen to deliver them -- 556 * one that started in userland may be delivered many instructions later, 557 * after the process has entered the kernel. It may even be delivered after 558 * the fnsave here completes. A spurious IRQ13 for the fnsave is handled in 559 * the same way as a very-late-arriving non-spurious IRQ13 from user mode: 560 * it is normally ignored at first because we set fpcurthread to NULL; it is 561 * normally retriggered in npxdna() after return to user mode. | 521 * Wrapper for fnsave instruction. |
562 * | 522 * |
563 * npxsave() must be called with interrupts disabled, so that it clears | 523 * fpusave() must be called with interrupts disabled, so that it clears |
564 * fpcurthread atomically with saving the state. We require callers to do the 565 * disabling, since most callers need to disable interrupts anyway to call | 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 |
566 * npxsave() atomically with checking fpcurthread. 567 * 568 * A previous version of npxsave() went to great lengths to excecute fnsave 569 * with interrupts enabled in case executing it froze the CPU. This case 570 * can't happen, at least for Intel CPU/NPX's. Spurious IRQ13's don't imply 571 * spurious freezes. | 526 * fpusave() atomically with checking fpcurthread. |
572 */ 573void | 527 */ 528void |
574npxsave(addr) 575 struct savefpu *addr; | 529fpusave(struct savefpu *addr) |
576{ 577 578 stop_emulating(); 579 fxsave(addr); | 530{ 531 532 stop_emulating(); 533 fxsave(addr); |
580 | |
581 start_emulating(); 582 PCPU_SET(fpcurthread, NULL); 583} 584 585/* 586 * This should be called with interrupts disabled and only when the owning 587 * FPU thread is non-null. 588 */ 589void | 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 |
590npxdrop() | 543fpudrop() |
591{ 592 struct thread *td; 593 594 td = PCPU_GET(fpcurthread); 595 PCPU_SET(fpcurthread, NULL); | 544{ 545 struct thread *td; 546 547 td = PCPU_GET(fpcurthread); 548 PCPU_SET(fpcurthread, NULL); |
596 td->td_pcb->pcb_flags &= ~PCB_NPXINITDONE; | 549 td->td_pcb->pcb_flags &= ~PCB_FPUINITDONE; |
597 start_emulating(); 598} 599 600/* 601 * Get the state of the FPU without dropping ownership (if possible). 602 * It returns the FPU ownership status. 603 */ 604int | 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 |
605npxgetregs(td, addr) 606 struct thread *td; 607 struct savefpu *addr; | 558fpugetregs(struct thread *td, struct savefpu *addr) |
608{ 609 register_t s; 610 | 559{ 560 register_t s; 561 |
611 if ((td->td_pcb->pcb_flags & PCB_NPXINITDONE) == 0) { 612 if (npx_cleanstate_ready) 613 bcopy(&npx_cleanstate, addr, sizeof(npx_cleanstate)); | 562 if ((td->td_pcb->pcb_flags & PCB_FPUINITDONE) == 0) { 563 if (fpu_cleanstate_ready) 564 bcopy(&fpu_cleanstate, addr, sizeof(fpu_cleanstate)); |
614 else 615 bzero(addr, sizeof(*addr)); 616 return (_MC_FPOWNED_NONE); 617 } 618 s = intr_disable(); 619 if (td == PCPU_GET(fpcurthread)) { 620 fxsave(addr); 621 intr_restore(s); --- 4 unchanged lines hidden (view full) --- 626 return (_MC_FPOWNED_PCB); 627 } 628} 629 630/* 631 * Set the state of the FPU. 632 */ 633void | 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); --- 4 unchanged lines hidden (view full) --- 577 return (_MC_FPOWNED_PCB); 578 } 579} 580 581/* 582 * Set the state of the FPU. 583 */ 584void |
634npxsetregs(td, addr) 635 struct thread *td; 636 struct savefpu *addr; | 585fpusetregs(struct thread *td, struct savefpu *addr) |
637{ 638 register_t s; 639 640 s = intr_disable(); 641 if (td == PCPU_GET(fpcurthread)) { 642 fxrstor(addr); 643 intr_restore(s); 644 } else { 645 intr_restore(s); 646 bcopy(addr, &td->td_pcb->pcb_save, sizeof(*addr)); 647 } | 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 } |
648 curthread->td_pcb->pcb_flags |= PCB_NPXINITDONE; | 597 curthread->td_pcb->pcb_flags |= PCB_FPUINITDONE; |
649} 650 | 598} 599 |
651static device_method_t npx_methods[] = { | 600static device_method_t fpu_methods[] = { |
652 /* Device interface */ | 601 /* Device interface */ |
653 DEVMETHOD(device_identify, npx_identify), 654 DEVMETHOD(device_probe, npx_probe), 655 DEVMETHOD(device_attach, npx_attach), | 602 DEVMETHOD(device_identify, fpu_identify), 603 DEVMETHOD(device_probe, fpu_probe), 604 DEVMETHOD(device_attach, fpu_attach), |
656 DEVMETHOD(device_detach, bus_generic_detach), 657 DEVMETHOD(device_shutdown, bus_generic_shutdown), 658 DEVMETHOD(device_suspend, bus_generic_suspend), 659 DEVMETHOD(device_resume, bus_generic_resume), 660 661 { 0, 0 } 662}; 663 | 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 |
664static driver_t npx_driver = { 665 "npx", 666 npx_methods, | 613static driver_t fpu_driver = { 614 "fpu", 615 fpu_methods, |
667 1, /* no softc */ 668}; 669 | 616 1, /* no softc */ 617}; 618 |
670static devclass_t npx_devclass; | 619static devclass_t fpu_devclass; |
671 672/* 673 * We prefer to attach to the root nexus so that the usual case (exception 16) 674 * doesn't describe the processor as being `on isa'. 675 */ | 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 */ |
676DRIVER_MODULE(npx, nexus, npx_driver, npx_devclass, 0, 0); | 625DRIVER_MODULE(fpu, nexus, fpu_driver, fpu_devclass, 0, 0); |
677 678#ifdef DEV_ISA 679/* 680 * This sucks up the legacy ISA support assignments from PNPBIOS/ACPI. 681 */ | 626 627#ifdef DEV_ISA 628/* 629 * This sucks up the legacy ISA support assignments from PNPBIOS/ACPI. 630 */ |
682static struct isa_pnp_id npxisa_ids[] = { | 631static struct isa_pnp_id fpuisa_ids[] = { |
683 { 0x040cd041, "Legacy ISA coprocessor support" }, /* PNP0C04 */ 684 { 0 } 685}; 686 687static int | 632 { 0x040cd041, "Legacy ISA coprocessor support" }, /* PNP0C04 */ 633 { 0 } 634}; 635 636static int |
688npxisa_probe(device_t dev) | 637fpuisa_probe(device_t dev) |
689{ 690 int result; | 638{ 639 int result; |
691 if ((result = ISA_PNP_PROBE(device_get_parent(dev), dev, npxisa_ids)) <= 0) { | 640 641 result = ISA_PNP_PROBE(device_get_parent(dev), dev, fpuisa_ids); 642 if (result <= 0) |
692 device_quiet(dev); | 643 device_quiet(dev); |
693 } 694 return(result); | 644 return (result); |
695} 696 697static int | 645} 646 647static int |
698npxisa_attach(device_t dev) | 648fpuisa_attach(device_t dev) |
699{ | 649{ |
650 |
|
700 return (0); 701} 702 | 651 return (0); 652} 653 |
703static device_method_t npxisa_methods[] = { | 654static device_method_t fpuisa_methods[] = { |
704 /* Device interface */ | 655 /* Device interface */ |
705 DEVMETHOD(device_probe, npxisa_probe), 706 DEVMETHOD(device_attach, npxisa_attach), | 656 DEVMETHOD(device_probe, fpuisa_probe), 657 DEVMETHOD(device_attach, fpuisa_attach), |
707 DEVMETHOD(device_detach, bus_generic_detach), 708 DEVMETHOD(device_shutdown, bus_generic_shutdown), 709 DEVMETHOD(device_suspend, bus_generic_suspend), 710 DEVMETHOD(device_resume, bus_generic_resume), 711 712 { 0, 0 } 713}; 714 | 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 |
715static driver_t npxisa_driver = { 716 "npxisa", 717 npxisa_methods, | 666static driver_t fpuisa_driver = { 667 "fpuisa", 668 fpuisa_methods, |
718 1, /* no softc */ 719}; 720 | 669 1, /* no softc */ 670}; 671 |
721static devclass_t npxisa_devclass; | 672static devclass_t fpuisa_devclass; |
722 | 673 |
723DRIVER_MODULE(npxisa, isa, npxisa_driver, npxisa_devclass, 0, 0); 724DRIVER_MODULE(npxisa, acpi, npxisa_driver, npxisa_devclass, 0, 0); | 674DRIVER_MODULE(fpuisa, isa, fpuisa_driver, fpuisa_devclass, 0, 0); 675DRIVER_MODULE(fpuisa, acpi, fpuisa_driver, fpuisa_devclass, 0, 0); |
725#endif /* DEV_ISA */ | 676#endif /* DEV_ISA */ |