diff options
author | nyan <nyan@FreeBSD.org> | 2001-06-02 05:00:08 +0000 |
---|---|---|
committer | nyan <nyan@FreeBSD.org> | 2001-06-02 05:00:08 +0000 |
commit | 69fcd429613095182395f09ed46525b4141df150 (patch) | |
tree | 849ac6e683b3523b0bad937a9c9a35cee48419c8 /sys/pc98 | |
parent | 17345a630936bb1a413e4ee478318ce03dba111d (diff) | |
download | FreeBSD-src-69fcd429613095182395f09ed46525b4141df150.zip FreeBSD-src-69fcd429613095182395f09ed46525b4141df150.tar.gz |
Merged from sys/i386/isa/npx.c revision 1.101.
Diffstat (limited to 'sys/pc98')
-rw-r--r-- | sys/pc98/pc98/npx.c | 164 |
1 files changed, 85 insertions, 79 deletions
diff --git a/sys/pc98/pc98/npx.c b/sys/pc98/pc98/npx.c index 9b070a4..5930ff5 100644 --- a/sys/pc98/pc98/npx.c +++ b/sys/pc98/pc98/npx.c @@ -126,8 +126,10 @@ void stop_emulating __P((void)); typedef u_char bool_t; static int npx_attach __P((device_t dev)); - void npx_intr __P((void *)); static void npx_identify __P((driver_t *driver, device_t parent)); +#ifndef SMP +static void npx_intr __P((void *)); +#endif static int npx_probe __P((device_t dev)); static int npx_probe1 __P((device_t dev)); #ifdef I586_CPU @@ -212,6 +214,55 @@ npx_identify(driver, parent) panic("npx_identify"); } +#ifndef SMP +/* + * Do minimal handling of npx interrupts to convert them to traps. + */ +static void +npx_intr(dummy) + void *dummy; +{ + struct proc *p; + + /* + * The BUSY# latch must be cleared in all cases so that the next + * unmasked npx exception causes an interrupt. + */ +#ifdef PC98 + outb(0xf8, 0); +#else + outb(0xf0, 0); +#endif + + /* + * npxproc is normally non-null here. In that case, schedule an + * AST to finish the exception handling in the correct context + * (this interrupt may occur after the process has entered the + * kernel via a syscall or an interrupt). Otherwise, the npx + * state of the process that caused this interrupt must have been + * pushed to the process' pcb, and clearing of the busy latch + * above has finished the (essentially null) handling of this + * interrupt. Control will eventually return to the instruction + * that caused it and it will repeat. We will eventually (usually + * soon) win the race to handle the interrupt properly. + */ + p = PCPU_GET(npxproc); + if (p != NULL) { + p->p_addr->u_pcb.pcb_flags |= PCB_NPXTRAP; + mtx_lock_spin(&sched_lock); + aston(p); + mtx_unlock_spin(&sched_lock); + } +} + +/* + * XXX these "local" variables of npx_probe() are non-local so that + * npxprobe1() can abuse them. + */ +static int npx_intrno; +static struct gate_descriptor save_idt_npxintr; +#endif /* !SMP */ + /* * Probe routine. Initialize cr0 to give correct behaviour for [f]wait * whether the device exists or not (XXX should be elsewhere). Set flags @@ -234,12 +285,10 @@ npx_probe(dev) #else /* SMP */ - int npx_intrno; int result; critical_t savecrit; u_char save_icu1_mask; u_char save_icu2_mask; - struct gate_descriptor save_idt_npxintr; struct gate_descriptor save_idt_npxtrap; /* * This routine is now just a wrapper for npxprobe1(), to install @@ -432,11 +481,20 @@ npx_probe1(dev) panic("npx: can't get IRQ"); BUS_SETUP_INTR(device_get_parent(dev), dev, r, - INTR_TYPE_MISC | INTR_MPSAFE, + INTR_TYPE_MISC | INTR_FAST, npx_intr, 0, &intr); if (intr == 0) panic("npx: can't create intr"); + /* + * XXX BUS_SETUP_INTR() has changed + * idt[npx_intrno] to point to Xfastintr0 + * instead of Xfastintr0. Adjust + * save_idt_npxintr so that npxprobe() + * doesn't undo this. + */ + save_idt_npxintr = idt[npx_intrno]; + return (0); } /* @@ -763,91 +821,39 @@ static char fpetable[128] = { * destroyed by IRQ13 bugs. Clearing FP exceptions is not an acceptable * solution for signals other than SIGFPE. */ -void -npx_intr(dummy) - void *dummy; +int +npxtrap() { - int code; - u_short control; - struct intrframe *frame; + critical_t savecrit; + u_short control, status; if (!npx_exists) { - printf("npxintr: npxproc = %p, curproc = %p, npx_exists = %d\n", + printf("npxtrap: npxproc = %p, curproc = %p, npx_exists = %d\n", PCPU_GET(npxproc), curproc, npx_exists); - panic("npxintr from nowhere"); + panic("npxtrap from nowhere"); } -#ifdef PC98 - outb(0xf8, 0); -#else - outb(0xf0, 0); -#endif - mtx_lock_spin(&sched_lock); - if (PCPU_GET(npxproc) != curproc) { - /* - * Interrupt handling (for this or another interrupt) has - * switched npxproc from underneath us before we managed - * to handle this interrupt. Just ignore this interrupt. - * Control will eventually return to the instruction that - * caused it and it will repeat. In the npx_ex16 case, - * then we will eventually (usually soon) win the race. - * In the npx_irq13 case, we will always lose the race - * because we have switched to the IRQ13 thread. This will - * be fixed later. - */ - mtx_unlock_spin(&sched_lock); - return; - } - fnstsw(&PCPU_GET(curpcb)->pcb_savefpu.sv_ex_sw); - fnstcw(&control); - fnclex(); - mtx_unlock_spin(&sched_lock); + savecrit = critical_enter(); /* - * Pass exception to process. + * Interrupt handling (for another interrupt) may have pushed the + * state to memory. Fetch the relevant parts of the state from + * wherever they are. */ - mtx_lock(&Giant); - frame = (struct intrframe *)&dummy; /* XXX */ - if ((ISPL(frame->if_cs) == SEL_UPL) || (frame->if_eflags & PSL_VM)) { - /* - * Interrupt is essentially a trap, so we can afford to call - * the SIGFPE handler (if any) as soon as the interrupt - * returns. - * - * XXX little or nothing is gained from this, and plenty is - * lost - the interrupt frame has to contain the trap frame - * (this is otherwise only necessary for the rescheduling trap - * in doreti, and the frame for that could easily be set up - * just before it is used). - */ - curproc->p_md.md_regs = INTR_TO_TRAPFRAME(frame); - /* - * Encode the appropriate code for detailed information on - * this exception. - */ - code = - fpetable[(PCPU_GET(curpcb)->pcb_savefpu.sv_ex_sw & ~control & 0x3f) | - (PCPU_GET(curpcb)->pcb_savefpu.sv_ex_sw & 0x40)]; - trapsignal(curproc, SIGFPE, code); + if (PCPU_GET(npxproc) != curproc) { + control = curproc->p_addr->u_pcb.pcb_savefpu.sv_env.en_cw; + status = curproc->p_addr->u_pcb.pcb_savefpu.sv_env.en_sw; } else { - /* - * Nested interrupt. These losers occur when: - * o an IRQ13 is bogusly generated at a bogus time, e.g.: - * o immediately after an fnsave or frstor of an - * error state. - * o a couple of 386 instructions after - * "fstpl _memvar" causes a stack overflow. - * These are especially nasty when combined with a - * trace trap. - * o an IRQ13 occurs at the same time as another higher- - * priority interrupt. - * - * Treat them like a true async interrupt. - */ - PROC_LOCK(curproc); - psignal(curproc, SIGFPE); - PROC_UNLOCK(curproc); + fnstcw(&control); + fnstsw(&status); } - mtx_unlock(&Giant); + + curproc->p_addr->u_pcb.pcb_savefpu.sv_ex_sw = status; + if (PCPU_GET(npxproc) != curproc) + curproc->p_addr->u_pcb.pcb_savefpu.sv_env.en_sw &= ~0x80bf; + else + fnclex(); + critical_exit(savecrit); + return (fpetable[status & ((~control & 0x3f) | 0x40)]); } /* |