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*56513Sbostic * @(#)npx.c 7.5 (Berkeley) 10/11/92 945624Sbill */ 1045624Sbill #include "npx.h" 1149617Sbostic #if NNPX > 0 1245624Sbill 13*56513Sbostic #include <sys/param.h> 14*56513Sbostic #include <sys/systm.h> 15*56513Sbostic #include <sys/conf.h> 16*56513Sbostic #include <sys/file.h> 17*56513Sbostic #include <sys/proc.h> 18*56513Sbostic #include <sys/user.h> 19*56513Sbostic #include <sys/ioctl.h> 20*56513Sbostic 21*56513Sbostic #include <machine/cpu.h> 22*56513Sbostic #include <machine/trap.h> 23*56513Sbostic #include <machine/specialreg.h> 24*56513Sbostic #include <i386/isa/isa_device.h> 25*56513Sbostic #include <i386/isa/icu.h> 2645624Sbill /* 2745547Sbill * 387 and 287 Numeric Coprocessor Extension (NPX) Driver. 2845547Sbill */ 2945547Sbill 3045547Sbill int npxprobe(), npxattach(), npxintr(); 3145624Sbill struct isa_driver npxdriver = { 3245547Sbill npxprobe, npxattach, "npx", 3345547Sbill }; 3445547Sbill 3549694Swilliam struct proc *npxproc; /* process who owns device, otherwise zero */ 3649694Swilliam struct pcb *npxpcb; /* owners context 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 */ 5253642Sbostic load_cr0(rcr0() & ~CR0_EM); 5353642Sbostic 5445624Sbill asm(" fninit "); /* put device in known state */ 5545624Sbill 5645547Sbill /* check for a proper status of zero */ 5745547Sbill status = 0xa5a5; 5845624Sbill asm (" fnstsw %0 " : "=m" (status) : "m" (status) ); 5945547Sbill 6045547Sbill if (status == 0) { 6145547Sbill 6245547Sbill /* good, now check for a proper control word */ 6345547Sbill control = 0xa5a5; 6445624Sbill asm (" fnstcw %0 " : "=m" (control) : "m" (control)); 6545547Sbill 6645624Sbill if ((control&0x103f) == 0x3f) { 6745547Sbill /* then we have a numeric coprocessor */ 6845547Sbill /* XXX should force an exception here to generate an intr */ 6945547Sbill return (1); 7045547Sbill } 7145547Sbill } 7245547Sbill 7353642Sbostic /* insure EM bit on */ 7453642Sbostic load_cr0(rcr0() | CR0_EM); 7545547Sbill return (0); 7645547Sbill } 7745547Sbill 7845547Sbill /* 7945547Sbill * Attach routine - announce which it is, and wire into system 8045547Sbill */ 8145547Sbill npxattach(dvp) 8245624Sbill struct isa_device *dvp; 8345547Sbill { 8445547Sbill 8545624Sbill npxinit(0x262); 8645547Sbill /* check for ET bit to decide 387/287 */ 8749573Swilliam npxexists++; 8849573Swilliam npx0mask = dvp->id_irq; 8945547Sbill } 9045547Sbill 9145547Sbill /* 9245547Sbill * Initialize floating point unit, usually after an error 9345547Sbill */ 9445624Sbill npxinit(control) { 9545547Sbill 9649573Swilliam if (npxexists == 0) return; 9749573Swilliam 9849573Swilliam load_cr0(rcr0() & ~CR0_EM); /* stop emulating */ 9949573Swilliam #ifdef INTEL_COMPAT 10049573Swilliam asm (" finit"); 10145624Sbill asm(" fldcw %0" : : "g" (control)); 10249694Swilliam asm(" fnsave %0 " : : "g" (curpcb->pcb_savefpu) ); 10349573Swilliam #else 10449573Swilliam asm("fninit"); 10549694Swilliam asm(" fnsave %0 " : : "g" (curpcb->pcb_savefpu) ); 10649573Swilliam #endif 10749573Swilliam load_cr0(rcr0() | CR0_EM); /* start emulating */ 10845547Sbill 10945547Sbill } 11045547Sbill 11145547Sbill /* 11245547Sbill * Record information needed in processing an exception and clear status word 11345547Sbill */ 11453642Sbostic npxintr(frame) 11553642Sbostic struct intrframe frame; 11653642Sbostic { 11753642Sbostic if (npxexists == 0) { 11853642Sbostic printf ("stray npxintr\n"); 11953642Sbostic return; 12053642Sbostic } 12145547Sbill 12253642Sbostic outb(0xf0,0); /* reset coprocessor */ 12349573Swilliam 12449694Swilliam /* 12553642Sbostic * npxproc may be NULL, if this is a delayed interrupt from 12653642Sbostic * a process that just exited. 12749694Swilliam */ 12853642Sbostic if (npxproc) { 12953642Sbostic /* 13053642Sbostic * sync state in process context structure, in advance 13153642Sbostic * of debugger/process looking for it. 13253642Sbostic */ 13353642Sbostic asm("fnsave %0" :: "g" (npxproc->p_addr->u_pcb.pcb_savefpu)); 13453642Sbostic psignal(npxproc, SIGFPE); 13545547Sbill 13653642Sbostic /* clear the exception so we can catch others like it */ 13753642Sbostic asm (" fnclex"); 13853642Sbostic } 13945547Sbill } 14045547Sbill 14145547Sbill /* 14245547Sbill * Implement device not available (DNA) exception 14345547Sbill */ 14453642Sbostic npxdna() 14553642Sbostic { 14653642Sbostic if (npxexists == 0) 14753642Sbostic return(0); 14849573Swilliam 14953642Sbostic load_cr0(rcr0() & ~CR0_EM); /* stop emulating */ 15053642Sbostic if (npxproc != curproc) { 15151728Swilliam if (npxproc) 15253642Sbostic asm(" fnsave %0 "::"g" 15353642Sbostic (npxproc->p_addr->u_pcb.pcb_savefpu)); 15451728Swilliam asm(" frstor %0 " : : "g" (curpcb->pcb_savefpu)); 15551728Swilliam npxproc = curproc; 15651728Swilliam } 15751728Swilliam return (1); 15845547Sbill } 15945624Sbill #endif 160