149617Sbostic /*-
249617Sbostic * Copyright (c) 1990 William Jolitz.
3*63364Sbostic * Copyright (c) 1991, 1993
4*63364Sbostic * The Regents of the University of California. All rights reserved.
549617Sbostic *
649617Sbostic * %sccs.include.redist.c%
749617Sbostic *
8*63364Sbostic * @(#)npx.c 8.1 (Berkeley) 06/11/93
945624Sbill */
1045624Sbill #include "npx.h"
1149617Sbostic #if NNPX > 0
1245624Sbill
1356513Sbostic #include <sys/param.h>
1456513Sbostic #include <sys/systm.h>
1556513Sbostic #include <sys/conf.h>
1656513Sbostic #include <sys/file.h>
1756513Sbostic #include <sys/proc.h>
1856513Sbostic #include <sys/user.h>
1956513Sbostic #include <sys/ioctl.h>
2056513Sbostic
2156513Sbostic #include <machine/cpu.h>
2256513Sbostic #include <machine/trap.h>
2356513Sbostic #include <machine/specialreg.h>
2456513Sbostic #include <i386/isa/isa_device.h>
2556513Sbostic #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 */
npxinit(control)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 */
npxdna()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