149617Sbostic /*- 249617Sbostic * Copyright (c) 1990 William Jolitz. 349617Sbostic * Copyright (c) 1991 The Regents of the University of California. 449617Sbostic * All rights reserved. 549617Sbostic * 649617Sbostic * %sccs.include.redist.c% 749617Sbostic * 8*53642Sbostic * @(#)npx.c 7.4 (Berkeley) 05/20/92 945624Sbill */ 1045624Sbill #include "npx.h" 1149617Sbostic #if NNPX > 0 1245624Sbill 1345624Sbill #include "param.h" 1445624Sbill #include "systm.h" 1545624Sbill #include "conf.h" 1645624Sbill #include "file.h" 1749573Swilliam #include "proc.h" 1849694Swilliam #include "machine/cpu.h" 1951728Swilliam #include "user.h" 2049694Swilliam #include "machine/trap.h" 2145624Sbill #include "ioctl.h" 2249573Swilliam #include "machine/specialreg.h" 2349573Swilliam #include "i386/isa/isa_device.h" 2445624Sbill #include "icu.h" 2545624Sbill /* 2645547Sbill * 387 and 287 Numeric Coprocessor Extension (NPX) Driver. 2745547Sbill */ 2845547Sbill 2945547Sbill int npxprobe(), npxattach(), npxintr(); 3045624Sbill struct isa_driver npxdriver = { 3145547Sbill npxprobe, npxattach, "npx", 3245547Sbill }; 3345547Sbill 3449694Swilliam struct proc *npxproc; /* process who owns device, otherwise zero */ 3549694Swilliam struct pcb *npxpcb; /* owners context structure */ 3649573Swilliam static npxexists; 3749573Swilliam extern long npx0mask; 3845547Sbill 3945547Sbill /* 4045547Sbill * Probe routine - look device, otherwise set emulator bit 4145547Sbill */ 4245547Sbill npxprobe(dvp) 4345624Sbill struct isa_device *dvp; 4445624Sbill { static status, control; 4545547Sbill 4645547Sbill #ifdef lint 4745547Sbill npxintr(); 4845547Sbill #endif 4945547Sbill 5045624Sbill /* insure EM bit off */ 51*53642Sbostic load_cr0(rcr0() & ~CR0_EM); 52*53642Sbostic 5345624Sbill asm(" fninit "); /* put device in known state */ 5445624Sbill 5545547Sbill /* check for a proper status of zero */ 5645547Sbill status = 0xa5a5; 5745624Sbill asm (" fnstsw %0 " : "=m" (status) : "m" (status) ); 5845547Sbill 5945547Sbill if (status == 0) { 6045547Sbill 6145547Sbill /* good, now check for a proper control word */ 6245547Sbill control = 0xa5a5; 6345624Sbill asm (" fnstcw %0 " : "=m" (control) : "m" (control)); 6445547Sbill 6545624Sbill if ((control&0x103f) == 0x3f) { 6645547Sbill /* then we have a numeric coprocessor */ 6745547Sbill /* XXX should force an exception here to generate an intr */ 6845547Sbill return (1); 6945547Sbill } 7045547Sbill } 7145547Sbill 72*53642Sbostic /* insure EM bit on */ 73*53642Sbostic load_cr0(rcr0() | CR0_EM); 7445547Sbill return (0); 7545547Sbill } 7645547Sbill 7745547Sbill /* 7845547Sbill * Attach routine - announce which it is, and wire into system 7945547Sbill */ 8045547Sbill npxattach(dvp) 8145624Sbill struct isa_device *dvp; 8245547Sbill { 8345547Sbill 8445624Sbill npxinit(0x262); 8545547Sbill /* check for ET bit to decide 387/287 */ 8649573Swilliam npxexists++; 8749573Swilliam npx0mask = dvp->id_irq; 8845547Sbill } 8945547Sbill 9045547Sbill /* 9145547Sbill * Initialize floating point unit, usually after an error 9245547Sbill */ 9345624Sbill npxinit(control) { 9445547Sbill 9549573Swilliam if (npxexists == 0) return; 9649573Swilliam 9749573Swilliam load_cr0(rcr0() & ~CR0_EM); /* stop emulating */ 9849573Swilliam #ifdef INTEL_COMPAT 9949573Swilliam asm (" finit"); 10045624Sbill asm(" fldcw %0" : : "g" (control)); 10149694Swilliam asm(" fnsave %0 " : : "g" (curpcb->pcb_savefpu) ); 10249573Swilliam #else 10349573Swilliam asm("fninit"); 10449694Swilliam asm(" fnsave %0 " : : "g" (curpcb->pcb_savefpu) ); 10549573Swilliam #endif 10649573Swilliam load_cr0(rcr0() | CR0_EM); /* start emulating */ 10745547Sbill 10845547Sbill } 10945547Sbill 11045547Sbill /* 11145547Sbill * Record information needed in processing an exception and clear status word 11245547Sbill */ 113*53642Sbostic npxintr(frame) 114*53642Sbostic struct intrframe frame; 115*53642Sbostic { 116*53642Sbostic if (npxexists == 0) { 117*53642Sbostic printf ("stray npxintr\n"); 118*53642Sbostic return; 119*53642Sbostic } 12045547Sbill 121*53642Sbostic outb(0xf0,0); /* reset coprocessor */ 12249573Swilliam 12349694Swilliam /* 124*53642Sbostic * npxproc may be NULL, if this is a delayed interrupt from 125*53642Sbostic * a process that just exited. 12649694Swilliam */ 127*53642Sbostic if (npxproc) { 128*53642Sbostic /* 129*53642Sbostic * sync state in process context structure, in advance 130*53642Sbostic * of debugger/process looking for it. 131*53642Sbostic */ 132*53642Sbostic asm("fnsave %0" :: "g" (npxproc->p_addr->u_pcb.pcb_savefpu)); 133*53642Sbostic psignal(npxproc, SIGFPE); 13445547Sbill 135*53642Sbostic /* clear the exception so we can catch others like it */ 136*53642Sbostic asm (" fnclex"); 137*53642Sbostic } 13845547Sbill } 13945547Sbill 14045547Sbill /* 14145547Sbill * Implement device not available (DNA) exception 14245547Sbill */ 143*53642Sbostic npxdna() 144*53642Sbostic { 145*53642Sbostic if (npxexists == 0) 146*53642Sbostic return(0); 14749573Swilliam 148*53642Sbostic load_cr0(rcr0() & ~CR0_EM); /* stop emulating */ 149*53642Sbostic if (npxproc != curproc) { 15051728Swilliam if (npxproc) 151*53642Sbostic asm(" fnsave %0 "::"g" 152*53642Sbostic (npxproc->p_addr->u_pcb.pcb_savefpu)); 15351728Swilliam asm(" frstor %0 " : : "g" (curpcb->pcb_savefpu)); 15451728Swilliam npxproc = curproc; 15551728Swilliam } 15651728Swilliam return (1); 15745547Sbill } 15845624Sbill #endif 159