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*51728Swilliam * @(#)npx.c 7.3 (Berkeley) 11/16/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" 1849694Swilliam #include "machine/cpu.h" 19*51728Swilliam #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 */ 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)); 10049694Swilliam asm(" fnsave %0 " : : "g" (curpcb->pcb_savefpu) ); 10149573Swilliam #else 10249573Swilliam asm("fninit"); 10349694Swilliam 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; 11649694Swilliam npxpcb = curpcb; 11749694Swilliam 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"); 12649694Swilliam 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 */ 13349694Swilliam npxintr(frame) struct intrframe frame; { 13449694Swilliam struct trapframe tf; 13545547Sbill 13649573Swilliam outb(0xf0,0); /* reset processor */ 13749573Swilliam 13849694Swilliam /* sync state in process context structure, in advance of debugger/process looking for it */ 13949573Swilliam if (npxproc == 0 || npxexists == 0) panic ("npxintr"); 140*51728Swilliam asm (" fnsave %0 " : : "g" (npxproc->p_addr->u_pcb.pcb_savefpu) ); 14149694Swilliam 14249694Swilliam /* 14349694Swilliam * Prepair a trap frame for our generic exception processing routine, trap() 14449694Swilliam */ 14549694Swilliam bcopy(&frame.if_es, &tf, sizeof(tf)); 14649694Swilliam tf.tf_trapno = T_ARITHTRAP; 14749573Swilliam #ifdef notyet 14849694Swilliam /* encode the appropriate code for detailed information on this exception */ 14949694Swilliam tf.tf_err = ???; 15049573Swilliam #endif 15149694Swilliam trap(tf); 15245547Sbill 15345547Sbill /* 15449694Swilliam * Restore with any changes to superior frame 15545547Sbill */ 15649694Swilliam 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*51728Swilliam if (npxproc == curproc) 169*51728Swilliam load_cr0(rcr0() & ~CR0_EM); /* stop emulating */ 170*51728Swilliam else { 171*51728Swilliam load_cr0(rcr0() & ~CR0_EM); /* stop emulating */ 172*51728Swilliam if (npxproc) 173*51728Swilliam asm(" fnsave %0 "::"g" (npxproc->p_addr->u_pcb.pcb_savefpu)); 174*51728Swilliam asm(" frstor %0 " : : "g" (curpcb->pcb_savefpu)); 175*51728Swilliam npxproc = curproc; 176*51728Swilliam } 177*51728Swilliam #ifdef garbage 17849694Swilliam if (!(curpcb->pcb_flags & FP_WASUSED) 17949694Swilliam ||(curpcb->pcb_flags & FP_NEEDSRESTORE)) { 18049573Swilliam load_cr0(rcr0() & ~CR0_EM); /* stop emulating */ 18149694Swilliam asm(" frstor %0 " : : "g" (curpcb->pcb_savefpu)); 18249694Swilliam curpcb->pcb_flags |= FP_WASUSED | FP_NEEDSSAVE; 18349694Swilliam curpcb->pcb_flags &= ~FP_NEEDSRESTORE; 18449573Swilliam npxproc = curproc; 18549694Swilliam npxpcb = curpcb; 18649573Swilliam } 187*51728Swilliam load_cr0(rcr0() & ~CR0_EM); /* stop emulating */ 188*51728Swilliam #endif 189*51728Swilliam return (1); 19045547Sbill } 19145624Sbill #endif 192