1*49617Sbostic /*- 2*49617Sbostic * Copyright (c) 1990 William Jolitz. 3*49617Sbostic * Copyright (c) 1991 The Regents of the University of California. 4*49617Sbostic * All rights reserved. 5*49617Sbostic * 6*49617Sbostic * %sccs.include.redist.c% 7*49617Sbostic * 8*49617Sbostic * @(#)npx.c 7.1 (Berkeley) 05/09/91 945624Sbill */ 10*49617Sbostic 1145624Sbill #include "npx.h" 12*49617Sbostic #if NNPX > 0 1345624Sbill 1445624Sbill #include "param.h" 1545624Sbill #include "systm.h" 1645624Sbill #include "conf.h" 1745624Sbill #include "file.h" 1849573Swilliam #include "proc.h" 1949573Swilliam #include "machine/pcb.h" 2049573Swilliam #include "machine/pte.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 3449573Swilliam static struct proc *npxproc; /* process who owns device, otherwise zero */ 3545624Sbill extern struct user npxutl; /* owners user structure */ 3645624Sbill extern struct pte Npxmap[]; /* kernel ptes mapping owner's user structure */ 3749573Swilliam static npxexists; 3849573Swilliam extern long npx0mask; 3945547Sbill 4045547Sbill /* 4145547Sbill * Probe routine - look device, otherwise set emulator bit 4245547Sbill */ 4345547Sbill npxprobe(dvp) 4445624Sbill struct isa_device *dvp; 4545624Sbill { static status, control; 4645547Sbill 4745547Sbill #ifdef lint 4845547Sbill npxintr(); 4945547Sbill #endif 5045547Sbill 5145624Sbill /* insure EM bit off */ 5245624Sbill asm(" fninit "); /* put device in known state */ 5345624Sbill 5445547Sbill /* check for a proper status of zero */ 5545547Sbill status = 0xa5a5; 5645624Sbill asm (" fnstsw %0 " : "=m" (status) : "m" (status) ); 5745547Sbill 5845547Sbill if (status == 0) { 5945547Sbill 6045547Sbill /* good, now check for a proper control word */ 6145547Sbill control = 0xa5a5; 6245624Sbill asm (" fnstcw %0 " : "=m" (control) : "m" (control)); 6345547Sbill 6445624Sbill if ((control&0x103f) == 0x3f) { 6545547Sbill /* then we have a numeric coprocessor */ 6645547Sbill /* XXX should force an exception here to generate an intr */ 6745547Sbill return (1); 6845547Sbill } 6945547Sbill } 7045547Sbill 7145547Sbill /* insure EM bit on */ 7245547Sbill return (0); 7345547Sbill } 7445547Sbill 7545547Sbill /* 7645547Sbill * Attach routine - announce which it is, and wire into system 7745547Sbill */ 7845547Sbill npxattach(dvp) 7945624Sbill struct isa_device *dvp; 8045547Sbill { 8145547Sbill 8245624Sbill npxinit(0x262); 8345547Sbill /* check for ET bit to decide 387/287 */ 8445547Sbill /*outb(0xb1,0); /* reset processor */ 8549573Swilliam npxexists++; 8649573Swilliam npx0mask = dvp->id_irq; 8745547Sbill } 8845547Sbill 8945547Sbill /* 9045547Sbill * Initialize floating point unit, usually after an error 9145547Sbill */ 9245624Sbill npxinit(control) { 9345547Sbill 9449573Swilliam if (npxexists == 0) return; 9549573Swilliam 9649573Swilliam 9749573Swilliam load_cr0(rcr0() & ~CR0_EM); /* stop emulating */ 9849573Swilliam #ifdef INTEL_COMPAT 9949573Swilliam asm (" finit"); 10045624Sbill asm(" fldcw %0" : : "g" (control)); 10149573Swilliam asm(" fnsave %0 " : : "g" 10249573Swilliam (((struct pcb *)curproc->p_addr)->pcb_savefpu) ); 10349573Swilliam #else 10449573Swilliam asm("fninit"); 10549573Swilliam asm("fnsave %0" : : "g" 10649573Swilliam (((struct pcb *)curproc->p_addr)->pcb_savefpu) ); 10749573Swilliam #endif 10849573Swilliam load_cr0(rcr0() | CR0_EM); /* start emulating */ 10945547Sbill 11045547Sbill } 11145547Sbill 11249573Swilliam #ifdef notyet 11345547Sbill /* 11445547Sbill * Load floating point context and record ownership to suite 11545547Sbill */ 11645547Sbill npxload() { 11745547Sbill 11845547Sbill if (npxproc) panic ("npxload"); 11949573Swilliam npxproc = curproc; 12045547Sbill uaccess(npxproc, Npxmap, &npxutl); 12149573Swilliam asm(" frstor %0 " : : "g" 12249573Swilliam (((struct pcb *)curproc->p_addr)->pcb_savefpu) ); 12345547Sbill } 12445547Sbill 12545547Sbill /* 12645547Sbill * Unload floating point context and relinquish ownership 12745547Sbill */ 12845547Sbill npxunload() { 12945547Sbill 13045547Sbill if (npxproc == 0) panic ("npxunload"); 13145624Sbill asm(" fsave %0 " : : "g" (npxutl.u_pcb.pcb_savefpu) ); 13245547Sbill npxproc = 0 ; 13345547Sbill } 13445547Sbill 13549573Swilliam #endif 13645547Sbill /* 13745547Sbill * Record information needed in processing an exception and clear status word 13845547Sbill */ 13949573Swilliam npxintr() { 14045547Sbill 14149573Swilliam outb(0xf0,0); /* reset processor */ 14249573Swilliam 14345547Sbill /* save state in appropriate user structure */ 14449573Swilliam if (npxproc == 0 || npxexists == 0) panic ("npxintr"); 14549573Swilliam #ifdef notyet 14649573Swilliam asm (" fnsave %0 " : : "g" (npxutl.u_pcb.pcb_savefpu) ); 14749573Swilliam #endif 14845547Sbill 14945547Sbill /* 15045547Sbill * encode the appropriate u_code for detailed information 15145547Sbill * on this exception 15245547Sbill */ 15345547Sbill 15445547Sbill /* signal appropriate process */ 15545547Sbill psignal (npxproc, SIGFPE); 15645547Sbill 15745547Sbill /* clear the exception so we can catch others like it */ 15845547Sbill asm (" fnclex"); 15945547Sbill } 16045547Sbill 16145547Sbill /* 16245547Sbill * Implement device not available (DNA) exception 16345547Sbill */ 16445547Sbill npxdna() { 16549573Swilliam 16649573Swilliam if (npxexists == 0) return(0); 16749573Swilliam if (!(((struct pcb *) curproc->p_addr)->pcb_flags & FP_WASUSED) 16849573Swilliam ||(((struct pcb *) curproc->p_addr)->pcb_flags & FP_NEEDSRESTORE)) { 16949573Swilliam load_cr0(rcr0() & ~CR0_EM); /* stop emulating */ 17049573Swilliam asm(" frstor %0 " : : "g" (((struct pcb *) curproc->p_addr)->pcb_savefpu) ); 17149573Swilliam ((struct pcb *) curproc->p_addr)->pcb_flags |= FP_WASUSED | FP_NEEDSSAVE; 17249573Swilliam ((struct pcb *) curproc->p_addr)->pcb_flags &= ~FP_NEEDSRESTORE; 17349573Swilliam npxproc = curproc; 17449573Swilliam 17549573Swilliam return(1); 17649573Swilliam } 17749573Swilliam return (0); 17845547Sbill } 17945624Sbill #endif 180