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*49694Swilliam * @(#)npx.c 7.2 (Berkeley) 05/12/91 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" 18*49694Swilliam #include "machine/cpu.h" 1949573Swilliam #include "machine/pcb.h" 20*49694Swilliam #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 34*49694Swilliam struct proc *npxproc; /* process who owns device, otherwise zero */ 35*49694Swilliam 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 */ 5145624Sbill asm(" fninit "); /* put device in known state */ 5245624Sbill 5345547Sbill /* check for a proper status of zero */ 5445547Sbill status = 0xa5a5; 5545624Sbill asm (" fnstsw %0 " : "=m" (status) : "m" (status) ); 5645547Sbill 5745547Sbill if (status == 0) { 5845547Sbill 5945547Sbill /* good, now check for a proper control word */ 6045547Sbill control = 0xa5a5; 6145624Sbill asm (" fnstcw %0 " : "=m" (control) : "m" (control)); 6245547Sbill 6345624Sbill if ((control&0x103f) == 0x3f) { 6445547Sbill /* then we have a numeric coprocessor */ 6545547Sbill /* XXX should force an exception here to generate an intr */ 6645547Sbill return (1); 6745547Sbill } 6845547Sbill } 6945547Sbill 7045547Sbill /* insure EM bit on */ 7145547Sbill return (0); 7245547Sbill } 7345547Sbill 7445547Sbill /* 7545547Sbill * Attach routine - announce which it is, and wire into system 7645547Sbill */ 7745547Sbill npxattach(dvp) 7845624Sbill struct isa_device *dvp; 7945547Sbill { 8045547Sbill 8145624Sbill npxinit(0x262); 8245547Sbill /* check for ET bit to decide 387/287 */ 8345547Sbill /*outb(0xb1,0); /* reset processor */ 8449573Swilliam npxexists++; 8549573Swilliam npx0mask = dvp->id_irq; 8645547Sbill } 8745547Sbill 8845547Sbill /* 8945547Sbill * Initialize floating point unit, usually after an error 9045547Sbill */ 9145624Sbill npxinit(control) { 9245547Sbill 9349573Swilliam if (npxexists == 0) return; 9449573Swilliam 9549573Swilliam 9649573Swilliam load_cr0(rcr0() & ~CR0_EM); /* stop emulating */ 9749573Swilliam #ifdef INTEL_COMPAT 9849573Swilliam asm (" finit"); 9945624Sbill asm(" fldcw %0" : : "g" (control)); 100*49694Swilliam asm(" fnsave %0 " : : "g" (curpcb->pcb_savefpu) ); 10149573Swilliam #else 10249573Swilliam asm("fninit"); 103*49694Swilliam asm(" fnsave %0 " : : "g" (curpcb->pcb_savefpu) ); 10449573Swilliam #endif 10549573Swilliam load_cr0(rcr0() | CR0_EM); /* start emulating */ 10645547Sbill 10745547Sbill } 10845547Sbill 10945547Sbill /* 11045547Sbill * Load floating point context and record ownership to suite 11145547Sbill */ 11245547Sbill npxload() { 11345547Sbill 11445547Sbill if (npxproc) panic ("npxload"); 11549573Swilliam npxproc = curproc; 116*49694Swilliam npxpcb = curpcb; 117*49694Swilliam asm(" frstor %0 " : : "g" (curpcb->pcb_savefpu) ); 11845547Sbill } 11945547Sbill 12045547Sbill /* 12145547Sbill * Unload floating point context and relinquish ownership 12245547Sbill */ 12345547Sbill npxunload() { 12445547Sbill 12545547Sbill if (npxproc == 0) panic ("npxunload"); 126*49694Swilliam asm(" fsave %0 " : : "g" (npxpcb->pcb_savefpu) ); 12745547Sbill npxproc = 0 ; 12845547Sbill } 12945547Sbill 13045547Sbill /* 13145547Sbill * Record information needed in processing an exception and clear status word 13245547Sbill */ 133*49694Swilliam npxintr(frame) struct intrframe frame; { 134*49694Swilliam struct trapframe tf; 13545547Sbill 13649573Swilliam outb(0xf0,0); /* reset processor */ 13749573Swilliam 138*49694Swilliam /* sync state in process context structure, in advance of debugger/process looking for it */ 13949573Swilliam if (npxproc == 0 || npxexists == 0) panic ("npxintr"); 140*49694Swilliam asm (" fnsave %0 " : : "g" (npxpcb->pcb_savefpu) ); 141*49694Swilliam 142*49694Swilliam /* 143*49694Swilliam * Prepair a trap frame for our generic exception processing routine, trap() 144*49694Swilliam */ 145*49694Swilliam bcopy(&frame.if_es, &tf, sizeof(tf)); 146*49694Swilliam tf.tf_trapno = T_ARITHTRAP; 14749573Swilliam #ifdef notyet 148*49694Swilliam /* encode the appropriate code for detailed information on this exception */ 149*49694Swilliam tf.tf_err = ???; 15049573Swilliam #endif 151*49694Swilliam trap(tf); 15245547Sbill 15345547Sbill /* 154*49694Swilliam * Restore with any changes to superior frame 15545547Sbill */ 156*49694Swilliam bcopy(&tf, &frame.if_es, sizeof(tf)); 15745547Sbill 15845547Sbill /* clear the exception so we can catch others like it */ 15945547Sbill asm (" fnclex"); 16045547Sbill } 16145547Sbill 16245547Sbill /* 16345547Sbill * Implement device not available (DNA) exception 16445547Sbill */ 16545547Sbill npxdna() { 16649573Swilliam 16749573Swilliam if (npxexists == 0) return(0); 168*49694Swilliam if (!(curpcb->pcb_flags & FP_WASUSED) 169*49694Swilliam ||(curpcb->pcb_flags & FP_NEEDSRESTORE)) { 17049573Swilliam load_cr0(rcr0() & ~CR0_EM); /* stop emulating */ 171*49694Swilliam asm(" frstor %0 " : : "g" (curpcb->pcb_savefpu)); 172*49694Swilliam curpcb->pcb_flags |= FP_WASUSED | FP_NEEDSSAVE; 173*49694Swilliam curpcb->pcb_flags &= ~FP_NEEDSRESTORE; 17449573Swilliam npxproc = curproc; 175*49694Swilliam npxpcb = curpcb; 17649573Swilliam 17749573Swilliam return(1); 17849573Swilliam } 17949573Swilliam return (0); 18045547Sbill } 18145624Sbill #endif 182