35c35
< * $Id: npx.c,v 1.16 1994/11/06 00:58:06 bde Exp $
---
> * $Id: npx.c,v 1.17 1994/11/14 14:59:06 bde Exp $
67c67
< #define fldcw(addr) __asm("fldcw %0" : : "m" (*addr))
---
> #define fldcw(addr) __asm("fldcw %0" : : "m" (*(addr)))
70,75c70,75
< #define fnsave(addr) __asm("fnsave %0" : "=m" (*addr) : "0" (*addr))
< #define fnstcw(addr) __asm("fnstcw %0" : "=m" (*addr) : "0" (*addr))
< #define fnstsw(addr) __asm("fnstsw %0" : "=m" (*addr) : "0" (*addr))
< #define fp_divide_by_0() __asm("fldz; fld1; fdiv %st,%st(1); fwait")
< #define frstor(addr) __asm("frstor %0" : : "m" (*addr))
< #define fwait() __asm("fwait")
---
> #define fnop() __asm("fnop")
> #define fnsave(addr) __asm("fnsave %0" : "=m" (*(addr)))
> #define fnstcw(addr) __asm("fnstcw %0" : "=m" (*(addr)))
> #define fnstsw(addr) __asm("fnstsw %0" : "=m" (*(addr)))
> #define fp_divide_by_0() __asm("fldz; fld1; fdiv %st,%st(1); fnop")
> #define frstor(addr) __asm("frstor %0" : : "m" (*(addr)))
84a85
> void fnop __P((void));
90d90
< void fwait __P((void));
105a106
> int hw_float; /* XXX currently just alias for npx_exists */
111d111
< int hw_float;
121c121
< * latch stuff in probintr() can be moved to npxprobe().
---
> * latch stuff in probeintr() can be moved to npxprobe().
133c133
< outb %al,$0x20 #IO_ICU1
---
> outb %al,$0x20 # IO_ICU1
201,205c201,203
< int control;
< int status;
< #ifdef lint
< npxintr();
< #endif
---
> u_short control;
> u_short status;
>
238c236,237
< DELAY(1000); /* wait for any IRQ13 (fwait might hang) */
---
> fnop(); /* wait for fninit (fwait might hang) */
> DELAY(1000); /* wait for any IRQ13 */
285c284,287
< npx0_imask = dvp->id_irq; /* npxattach too late */
---
> /*
> * npxattach would be too late to set npx0_imask.
> */
> npx0_imask |= dvp->id_irq;
312c314
< DC_UNKNOWN, /* not supported */
---
> DC_BUSY,
319,323c321,328
< if(id->id_unit)
< kdc_npx[id->id_unit] = kdc_npx[0];
< kdc_npx[id->id_unit].kdc_unit = id->id_unit;
< kdc_npx[id->id_unit].kdc_isa = id;
< dev_attach(&kdc_npx[id->id_unit]);
---
> int unit;
>
> unit = id->id_unit;
> if (unit != 0)
> kdc_npx[unit] = kdc_npx[0];
> kdc_npx[unit].kdc_unit = unit;
> kdc_npx[unit].kdc_isa = id;
> dev_attach(&kdc_npx[unit]);
333,340c338,352
< if (!npx_ex16 && !npx_irq13) {
< if (npx_exists) {
< printf("npx%d: Error reporting broken, using 387 emulator\n",dvp->id_unit);
< hw_float = npx_exists = 0;
< } else {
< printf("npx%d: 387 Emulator\n",dvp->id_unit);
< }
< }
---
> printf("npx%d: ", dvp->id_unit);
> if (npx_ex16)
> printf("INT 16 interface\n");
> else if (npx_irq13)
> printf("IRQ 13 interface\n");
> #if defined(MATH_EMULATE) || defined(GPL_MATH_EMULATE)
> else if (npx_exists) {
> printf("error reporting broken; using 387 emulator\n");
> npx_exists = 0;
> } else
> printf("387 emulator\n");
> #else
> else
> printf("no 387 emulator in kernel!\n");
> #endif
342c354,355
< npx_registerdev(dvp);
---
> if (npx_exists)
> npx_registerdev(dvp);
351c364
< u_int control;
---
> u_short control;
359c372
< * fnsave to throw away any junk in the fpu. fnsave initializes
---
> * fnsave to throw away any junk in the fpu. npxsave() initializes
397,398c410
< * Record the FPU state and reinitialize it all except for the control word.
< * Then generate a SIGFPE.
---
> * Preserve the FP status word, clear FP exceptions, then generate a SIGFPE.
400,401c412,414
< * Reinitializing the state allows naive SIGFPE handlers to longjmp without
< * doing any fixups.
---
> * Clearing exceptions is necessary mainly to avoid IRQ13 bugs. We now
> * depend on longjmp() restoring a usable state. Restoring the state
> * or examining it might fail if we didn't clear exceptions.
403,409c416,428
< * XXX there is currently no way to pass the full error state to signal
< * handlers, and if this is a nested interrupt there is no way to pass even
< * a status code! So there is no way to have a non-naive SIGFPE handler. At
< * best a handler could do an fninit followed by an fldcw of a static value.
< * fnclex would be of little use because it would leave junk on the FPU stack.
< * Returning from the handler would be even less safe than usual because
< * IRQ13 exception handling makes exceptions even less precise than usual.
---
> * XXX there is no standard way to tell SIGFPE handlers about the error
> * state. The old interface:
> *
> * void handler(int sig, int code, struct sigcontext *scp);
> *
> * is broken because it is non-ANSI and because the FP state is not in
> * struct sigcontext.
> *
> * XXX the FP state is not preserved across signal handlers. So signal
> * handlers cannot afford to do FP unless they preserve the state or
> * longjmp() out. Both preserving the state and longjmp()ing may be
> * destroyed by IRQ13 bugs. Clearing FP exceptions is not an acceptable
> * solution for signals other than SIGFPE.
418,420c437,438
< /* XXX no %p in stand/printf.c. Cast to quiet gcc -Wall. */
< printf("npxintr: npxproc = %lx, curproc = %lx, npx_exists = %d\n",
< (u_long) npxproc, (u_long) curproc, npx_exists);
---
> printf("npxintr: npxproc = %p, curproc = %p, npx_exists = %d\n",
> npxproc, curproc, npx_exists);
424,425c442,443
< printf("npxintr: npxproc = %lx, curproc = %lx, npx_exists = %d\n",
< (u_long) npxproc, (u_long) curproc, npx_exists);
---
> printf("npxintr: npxproc = %p, curproc = %p, npx_exists = %d\n",
> npxproc, curproc, npx_exists);
428,431c446,448
< /*
< * Save state. This does an implied fninit. It had better not halt
< * the cpu or we'll hang.
< */
---
>
> fnstsw(&curpcb->pcb_savefpu.sv_ex_sw);
> fnclex();
433,449d449
< fnsave(&curpcb->pcb_savefpu);
< fwait();
< /*
< * Restore control word (was clobbered by fnsave).
< */
< fldcw(&curpcb->pcb_savefpu.sv_env.en_cw);
< fwait();
< /*
< * Remember the exception status word and tag word. The current
< * (almost fninit'ed) fpu state is in the fpu and the exception
< * state just saved will soon be junk. However, the implied fninit
< * doesn't change the error pointers or register contents, and we
< * preserved the control word and will copy the status and tag
< * words, so the complete exception state can be recovered.
< */
< curpcb->pcb_savefpu.sv_ex_sw = curpcb->pcb_savefpu.sv_env.en_sw;
< curpcb->pcb_savefpu.sv_ex_tw = curpcb->pcb_savefpu.sv_env.en_tw;
492c492
< psignal(npxproc, SIGFPE);
---
> psignal(curproc, SIGFPE);
499,500c499,501
< * It would be better to switch FP context here (only). This would require
< * saving the state in the proc table instead of in the pcb.
---
> * It would be better to switch FP context here (if curproc != npxproc)
> * and not necessarily for every context switch, but it is too hard to
> * access foreign pcb's.
508,509c509,510
< printf("npxdna: npxproc = %lx, curproc = %lx\n",
< (u_long) npxproc, (u_long) curproc);
---
> printf("npxdna: npxproc = %p, curproc = %p\n",
> npxproc, curproc);
516a518
> curpcb->pcb_savefpu.sv_ex_sw = 0;
562c564,565
< fwait();
---
> fnop();
> outb(0xf0, 0);
< * $Id: npx.c,v 1.16 1994/11/06 00:58:06 bde Exp $
---
> * $Id: npx.c,v 1.17 1994/11/14 14:59:06 bde Exp $
67c67
< #define fldcw(addr) __asm("fldcw %0" : : "m" (*addr))
---
> #define fldcw(addr) __asm("fldcw %0" : : "m" (*(addr)))
70,75c70,75
< #define fnsave(addr) __asm("fnsave %0" : "=m" (*addr) : "0" (*addr))
< #define fnstcw(addr) __asm("fnstcw %0" : "=m" (*addr) : "0" (*addr))
< #define fnstsw(addr) __asm("fnstsw %0" : "=m" (*addr) : "0" (*addr))
< #define fp_divide_by_0() __asm("fldz; fld1; fdiv %st,%st(1); fwait")
< #define frstor(addr) __asm("frstor %0" : : "m" (*addr))
< #define fwait() __asm("fwait")
---
> #define fnop() __asm("fnop")
> #define fnsave(addr) __asm("fnsave %0" : "=m" (*(addr)))
> #define fnstcw(addr) __asm("fnstcw %0" : "=m" (*(addr)))
> #define fnstsw(addr) __asm("fnstsw %0" : "=m" (*(addr)))
> #define fp_divide_by_0() __asm("fldz; fld1; fdiv %st,%st(1); fnop")
> #define frstor(addr) __asm("frstor %0" : : "m" (*(addr)))
84a85
> void fnop __P((void));
90d90
< void fwait __P((void));
105a106
> int hw_float; /* XXX currently just alias for npx_exists */
111d111
< int hw_float;
121c121
< * latch stuff in probintr() can be moved to npxprobe().
---
> * latch stuff in probeintr() can be moved to npxprobe().
133c133
< outb %al,$0x20 #IO_ICU1
---
> outb %al,$0x20 # IO_ICU1
201,205c201,203
< int control;
< int status;
< #ifdef lint
< npxintr();
< #endif
---
> u_short control;
> u_short status;
>
238c236,237
< DELAY(1000); /* wait for any IRQ13 (fwait might hang) */
---
> fnop(); /* wait for fninit (fwait might hang) */
> DELAY(1000); /* wait for any IRQ13 */
285c284,287
< npx0_imask = dvp->id_irq; /* npxattach too late */
---
> /*
> * npxattach would be too late to set npx0_imask.
> */
> npx0_imask |= dvp->id_irq;
312c314
< DC_UNKNOWN, /* not supported */
---
> DC_BUSY,
319,323c321,328
< if(id->id_unit)
< kdc_npx[id->id_unit] = kdc_npx[0];
< kdc_npx[id->id_unit].kdc_unit = id->id_unit;
< kdc_npx[id->id_unit].kdc_isa = id;
< dev_attach(&kdc_npx[id->id_unit]);
---
> int unit;
>
> unit = id->id_unit;
> if (unit != 0)
> kdc_npx[unit] = kdc_npx[0];
> kdc_npx[unit].kdc_unit = unit;
> kdc_npx[unit].kdc_isa = id;
> dev_attach(&kdc_npx[unit]);
333,340c338,352
< if (!npx_ex16 && !npx_irq13) {
< if (npx_exists) {
< printf("npx%d: Error reporting broken, using 387 emulator\n",dvp->id_unit);
< hw_float = npx_exists = 0;
< } else {
< printf("npx%d: 387 Emulator\n",dvp->id_unit);
< }
< }
---
> printf("npx%d: ", dvp->id_unit);
> if (npx_ex16)
> printf("INT 16 interface\n");
> else if (npx_irq13)
> printf("IRQ 13 interface\n");
> #if defined(MATH_EMULATE) || defined(GPL_MATH_EMULATE)
> else if (npx_exists) {
> printf("error reporting broken; using 387 emulator\n");
> npx_exists = 0;
> } else
> printf("387 emulator\n");
> #else
> else
> printf("no 387 emulator in kernel!\n");
> #endif
342c354,355
< npx_registerdev(dvp);
---
> if (npx_exists)
> npx_registerdev(dvp);
351c364
< u_int control;
---
> u_short control;
359c372
< * fnsave to throw away any junk in the fpu. fnsave initializes
---
> * fnsave to throw away any junk in the fpu. npxsave() initializes
397,398c410
< * Record the FPU state and reinitialize it all except for the control word.
< * Then generate a SIGFPE.
---
> * Preserve the FP status word, clear FP exceptions, then generate a SIGFPE.
400,401c412,414
< * Reinitializing the state allows naive SIGFPE handlers to longjmp without
< * doing any fixups.
---
> * Clearing exceptions is necessary mainly to avoid IRQ13 bugs. We now
> * depend on longjmp() restoring a usable state. Restoring the state
> * or examining it might fail if we didn't clear exceptions.
403,409c416,428
< * XXX there is currently no way to pass the full error state to signal
< * handlers, and if this is a nested interrupt there is no way to pass even
< * a status code! So there is no way to have a non-naive SIGFPE handler. At
< * best a handler could do an fninit followed by an fldcw of a static value.
< * fnclex would be of little use because it would leave junk on the FPU stack.
< * Returning from the handler would be even less safe than usual because
< * IRQ13 exception handling makes exceptions even less precise than usual.
---
> * XXX there is no standard way to tell SIGFPE handlers about the error
> * state. The old interface:
> *
> * void handler(int sig, int code, struct sigcontext *scp);
> *
> * is broken because it is non-ANSI and because the FP state is not in
> * struct sigcontext.
> *
> * XXX the FP state is not preserved across signal handlers. So signal
> * handlers cannot afford to do FP unless they preserve the state or
> * longjmp() out. Both preserving the state and longjmp()ing may be
> * destroyed by IRQ13 bugs. Clearing FP exceptions is not an acceptable
> * solution for signals other than SIGFPE.
418,420c437,438
< /* XXX no %p in stand/printf.c. Cast to quiet gcc -Wall. */
< printf("npxintr: npxproc = %lx, curproc = %lx, npx_exists = %d\n",
< (u_long) npxproc, (u_long) curproc, npx_exists);
---
> printf("npxintr: npxproc = %p, curproc = %p, npx_exists = %d\n",
> npxproc, curproc, npx_exists);
424,425c442,443
< printf("npxintr: npxproc = %lx, curproc = %lx, npx_exists = %d\n",
< (u_long) npxproc, (u_long) curproc, npx_exists);
---
> printf("npxintr: npxproc = %p, curproc = %p, npx_exists = %d\n",
> npxproc, curproc, npx_exists);
428,431c446,448
< /*
< * Save state. This does an implied fninit. It had better not halt
< * the cpu or we'll hang.
< */
---
>
> fnstsw(&curpcb->pcb_savefpu.sv_ex_sw);
> fnclex();
433,449d449
< fnsave(&curpcb->pcb_savefpu);
< fwait();
< /*
< * Restore control word (was clobbered by fnsave).
< */
< fldcw(&curpcb->pcb_savefpu.sv_env.en_cw);
< fwait();
< /*
< * Remember the exception status word and tag word. The current
< * (almost fninit'ed) fpu state is in the fpu and the exception
< * state just saved will soon be junk. However, the implied fninit
< * doesn't change the error pointers or register contents, and we
< * preserved the control word and will copy the status and tag
< * words, so the complete exception state can be recovered.
< */
< curpcb->pcb_savefpu.sv_ex_sw = curpcb->pcb_savefpu.sv_env.en_sw;
< curpcb->pcb_savefpu.sv_ex_tw = curpcb->pcb_savefpu.sv_env.en_tw;
492c492
< psignal(npxproc, SIGFPE);
---
> psignal(curproc, SIGFPE);
499,500c499,501
< * It would be better to switch FP context here (only). This would require
< * saving the state in the proc table instead of in the pcb.
---
> * It would be better to switch FP context here (if curproc != npxproc)
> * and not necessarily for every context switch, but it is too hard to
> * access foreign pcb's.
508,509c509,510
< printf("npxdna: npxproc = %lx, curproc = %lx\n",
< (u_long) npxproc, (u_long) curproc);
---
> printf("npxdna: npxproc = %p, curproc = %p\n",
> npxproc, curproc);
516a518
> curpcb->pcb_savefpu.sv_ex_sw = 0;
562c564,565
< fwait();
---
> fnop();
> outb(0xf0, 0);