diff options
author | Niklas Hallqvist <niklas@cvs.openbsd.org> | 2004-06-13 21:49:30 +0000 |
---|---|---|
committer | Niklas Hallqvist <niklas@cvs.openbsd.org> | 2004-06-13 21:49:30 +0000 |
commit | 2dd254afa61a7c0cc5ae920b463d3d4266852804 (patch) | |
tree | 7adbebef3be24ba910fd83ee1ba09e1577ae21a8 /sys/arch/i386/isa | |
parent | 4d62e331dcde739b4067d712dd602c0927ce11b3 (diff) |
debranch SMP, have fun
Diffstat (limited to 'sys/arch/i386/isa')
-rw-r--r-- | sys/arch/i386/isa/clock.c | 6 | ||||
-rw-r--r-- | sys/arch/i386/isa/icu.h | 71 | ||||
-rw-r--r-- | sys/arch/i386/isa/icu.s | 60 | ||||
-rw-r--r-- | sys/arch/i386/isa/isa_machdep.c | 114 | ||||
-rw-r--r-- | sys/arch/i386/isa/mms.c | 2 | ||||
-rw-r--r-- | sys/arch/i386/isa/npx.c | 361 | ||||
-rw-r--r-- | sys/arch/i386/isa/vector.s | 295 |
7 files changed, 384 insertions, 525 deletions
diff --git a/sys/arch/i386/isa/clock.c b/sys/arch/i386/isa/clock.c index 2d932ad788f..fa18701776d 100644 --- a/sys/arch/i386/isa/clock.c +++ b/sys/arch/i386/isa/clock.c @@ -1,4 +1,4 @@ -/* $OpenBSD: clock.c,v 1.31 2004/02/27 21:07:49 grange Exp $ */ +/* $OpenBSD: clock.c,v 1.32 2004/06/13 21:49:16 niklas Exp $ */ /* $NetBSD: clock.c,v 1.39 1996/05/12 23:11:54 mycroft Exp $ */ /*- @@ -331,7 +331,7 @@ gettick() * wave' mode counts at 2:1). */ void -delay(n) +i8254_delay(n) int n; { int limit, tick, otick; @@ -458,7 +458,7 @@ calibrate_cyclecounter() #endif void -cpu_initclocks() +i8254_initclocks() { static struct timeout rtcdrain_timeout; stathz = 128; diff --git a/sys/arch/i386/isa/icu.h b/sys/arch/i386/isa/icu.h deleted file mode 100644 index 9b68025526b..00000000000 --- a/sys/arch/i386/isa/icu.h +++ /dev/null @@ -1,71 +0,0 @@ -/* $OpenBSD: icu.h,v 1.8 2003/06/02 23:27:47 millert Exp $ */ -/* $NetBSD: icu.h,v 1.19 1996/02/01 22:31:21 mycroft Exp $ */ - -/*- - * Copyright (c) 1990 The Regents of the University of California. - * All rights reserved. - * - * This code is derived from software contributed to Berkeley by - * William Jolitz. - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions - * are met: - * 1. Redistributions of source code must retain the above copyright - * notice, this list of conditions and the following disclaimer. - * 2. Redistributions in binary form must reproduce the above copyright - * notice, this list of conditions and the following disclaimer in the - * documentation and/or other materials provided with the distribution. - * 3. Neither the name of the University nor the names of its contributors - * may be used to endorse or promote products derived from this software - * without specific prior written permission. - * - * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND - * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE - * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE - * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE - * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL - * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS - * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) - * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT - * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY - * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF - * SUCH DAMAGE. - * - * @(#)icu.h 5.6 (Berkeley) 5/9/91 - */ - -/* - * AT/386 Interrupt Control constants - * W. Jolitz 8/89 - */ - -#ifndef _I386_ISA_ICU_H_ -#define _I386_ISA_ICU_H_ - -#ifndef _LOCORE - -/* - * Interrupt "level" mechanism variables, masks, and macros - */ -extern unsigned imen; /* interrupt mask enable */ - -#define SET_ICUS() (outb(IO_ICU1 + 1, imen), outb(IO_ICU2 + 1, imen >> 8)) - -#endif /* !_LOCORE */ - -/* - * Interrupt enable bits -- in order of priority - */ -#define IRQ_SLAVE 2 - -/* - * Interrupt Control offset into Interrupt descriptor table (IDT) - * XXX ICU_OFFSET is actually a property of our architecture not of the ICU - * XXX and therefore ought to use the architecture manifest constant IDTVECOFF - * XXX for its definition instead. - */ -#define ICU_OFFSET 32 /* 0-31 are processor exceptions */ -#define ICU_LEN 16 /* 32-47 are ISA interrupts */ - -#endif /* !_I386_ISA_ICU_H_ */ diff --git a/sys/arch/i386/isa/icu.s b/sys/arch/i386/isa/icu.s index 8bd2af133ca..d3f749b4a05 100644 --- a/sys/arch/i386/isa/icu.s +++ b/sys/arch/i386/isa/icu.s @@ -1,4 +1,4 @@ -/* $OpenBSD: icu.s,v 1.20 2003/11/06 21:09:34 mickey Exp $ */ +/* $OpenBSD: icu.s,v 1.21 2004/06/13 21:49:16 niklas Exp $ */ /* $NetBSD: icu.s,v 1.45 1996/01/07 03:59:34 mycroft Exp $ */ /*- @@ -33,10 +33,11 @@ #include <net/netisr.h> .data - .globl _C_LABEL(imen), _C_LABEL(cpl), _C_LABEL(ipending) - .globl _C_LABEL(astpending), _C_LABEL(netisr) + .globl _C_LABEL(imen),_C_LABEL(ipending),_C_LABEL(netisr) _C_LABEL(imen): .long 0xffff # interrupt mask enable (all off) +_C_LABEL(ipending): + .long 0 # interupts pending _C_LABEL(netisr): .long 0 # scheduling bits for network @@ -48,13 +49,13 @@ _C_LABEL(netisr): ALIGN_TEXT _C_LABEL(splhigh): movl $IPL_HIGH,%eax - xchgl %eax,_C_LABEL(cpl) + xchgl %eax,CPL ret ALIGN_TEXT _C_LABEL(splx): movl 4(%esp),%eax - movl %eax,_C_LABEL(cpl) + movl %eax,CPL testl %eax,%eax jnz _C_LABEL(Xspllower) ret @@ -72,12 +73,12 @@ IDTVEC(spllower) pushl %ebx pushl %esi pushl %edi - movl _C_LABEL(cpl),%ebx # save priority + movl CPL,%ebx # save priority movl $1f,%esi # address to resume loop at 1: movl %ebx,%eax # get cpl shrl $4,%eax # find its mask. movl _C_LABEL(iunmask)(,%eax,4),%eax - andl _C_LABEL(ipending),%eax + andl _C_LABEL(ipending),%eax # any non-masked bits left? jz 2f bsfl %eax,%eax btrl %eax,_C_LABEL(ipending) @@ -98,10 +99,10 @@ IDTVEC(spllower) */ IDTVEC(doreti) popl %ebx # get previous priority - movl %ebx,_C_LABEL(cpl) + movl %ebx,CPL movl $1f,%esi # address to resume loop at -1: movl %ebx,%eax # get cpl - shrl $4,%eax # find its mask +1: movl %ebx,%eax + shrl $4,%eax movl _C_LABEL(iunmask)(,%eax,4),%eax andl _C_LABEL(ipending),%eax jz 2f @@ -111,8 +112,8 @@ IDTVEC(doreti) cli jmp *_C_LABEL(Xresume)(,%eax,4) 2: /* Check for ASTs on exit to user mode. */ + CHECK_ASTPENDING(%ecx) cli - cmpb $0,_C_LABEL(astpending) je 3f testb $SEL_RPL,TF_CS(%esp) #ifdef VM86 @@ -120,10 +121,12 @@ IDTVEC(doreti) testl $PSL_VM,TF_EFLAGS(%esp) #endif jz 3f -4: movb $0,_C_LABEL(astpending) +4: CLEAR_ASTPENDING(%ecx) sti + movl $T_ASTFLT,TF_TRAPNO(%esp) /* XXX undo later. */ /* Pushed T_ASTFLT into tf_trapno on entry. */ call _C_LABEL(trap) + cli jmp 2b 3: INTRFASTEXIT @@ -137,9 +140,16 @@ IDTVEC(doreti) IDTVEC(softtty) #if NPCCOM > 0 movl $IPL_SOFTTTY,%eax - movl %eax,_C_LABEL(cpl) + movl %eax,CPL + sti +#ifdef MULTIPROCESSOR + call _C_LABEL(i386_softintlock) +#endif call _C_LABEL(comsoft) - movl %ebx,_C_LABEL(cpl) +#ifdef MULTIPROCESSOR + call _C_LABEL(i386_softintunlock) +#endif + movl %ebx,CPL #endif jmp *%esi @@ -152,18 +162,32 @@ IDTVEC(softtty) IDTVEC(softnet) movl $IPL_SOFTNET,%eax - movl %eax,_C_LABEL(cpl) + movl %eax,CPL + sti +#ifdef MULTIPROCESSOR + call _C_LABEL(i386_softintlock) +#endif xorl %edi,%edi xchgl _C_LABEL(netisr),%edi #include <net/netisr_dispatch.h> - movl %ebx,_C_LABEL(cpl) +#ifdef MULTIPROCESSOR + call _C_LABEL(i386_softintunlock) +#endif + movl %ebx,CPL jmp *%esi #undef DONETISR IDTVEC(softclock) movl $IPL_SOFTCLOCK,%eax - movl %eax,_C_LABEL(cpl) + movl %eax,CPL + sti +#ifdef MULTIPROCESSOR + call _C_LABEL(i386_softintlock) +#endif call _C_LABEL(softclock) - movl %ebx,_C_LABEL(cpl) +#ifdef MULTIPROCESSOR + call _C_LABEL(i386_softintunlock) +#endif + movl %ebx,CPL jmp *%esi diff --git a/sys/arch/i386/isa/isa_machdep.c b/sys/arch/i386/isa/isa_machdep.c index 0a8b580c6f4..0df077cdb19 100644 --- a/sys/arch/i386/isa/isa_machdep.c +++ b/sys/arch/i386/isa/isa_machdep.c @@ -1,4 +1,4 @@ -/* $OpenBSD: isa_machdep.c,v 1.48 2003/06/02 23:27:47 millert Exp $ */ +/* $OpenBSD: isa_machdep.c,v 1.49 2004/06/13 21:49:16 niklas Exp $ */ /* $NetBSD: isa_machdep.c,v 1.22 1997/06/12 23:57:32 thorpej Exp $ */ #define ISA_DMA_STATS @@ -122,18 +122,25 @@ #include <uvm/uvm_extern.h> +#include "ioapic.h" + +#if NIOAPIC > 0 +#include <machine/i82093var.h> +#include <machine/mpbiosvar.h> +#endif + #define _I386_BUS_DMA_PRIVATE #include <machine/bus.h> #include <machine/intr.h> #include <machine/pio.h> #include <machine/cpufunc.h> +#include <machine/i8259.h> #include <dev/isa/isareg.h> #include <dev/isa/isavar.h> #include <dev/isa/isadmavar.h> #include <i386/isa/isa_machdep.h> -#include <i386/isa/icu.h> #include "isadma.h" @@ -250,6 +257,16 @@ isa_defaultirq() outb(IO_ICU2, 0x0a); /* Read IRR by default. */ } +void +isa_nodefaultirq() +{ + int i; + + /* icu vectors */ + for (i = 0; i < ICU_LEN; i++) + unsetgate(&idt[ICU_OFFSET + i]); +} + /* * Handle a NMI, possibly a machine check. * return true to panic system, false to ignore. @@ -286,6 +303,9 @@ int intrtype[ICU_LEN], intrmask[ICU_LEN], intrlevel[ICU_LEN]; int iminlevel[ICU_LEN], imaxlevel[ICU_LEN]; struct intrhand *intrhand[ICU_LEN]; +int imask[NIPL]; /* Bitmask telling what interrupts are blocked. */ +int iunmask[NIPL]; /* Bitmask telling what interrupts are accepted. */ + /* * Recalculate the interrupt masks from scratch. * We could code special registry and deregistry versions of this function that @@ -295,24 +315,27 @@ struct intrhand *intrhand[ICU_LEN]; void intr_calculatemasks() { - int irq, level; + int irq, level, unusedirqs; struct intrhand *q; /* First, figure out which levels each IRQ uses. */ + unusedirqs = 0xffff; for (irq = 0; irq < ICU_LEN; irq++) { - register int levels = 0; + int levels = 0; for (q = intrhand[irq]; q; q = q->ih_next) levels |= 1 << IPL(q->ih_level); intrlevel[irq] = levels; + if (levels) + unusedirqs &= ~(1 << irq); } /* Then figure out which IRQs use each level. */ for (level = 0; level < NIPL; level++) { - register int irqs = 0; + int irqs = 0; for (irq = 0; irq < ICU_LEN; irq++) if (intrlevel[irq] & (1 << level)) irqs |= 1 << irq; - imask[level] = irqs; + imask[level] = irqs | unusedirqs; } /* @@ -331,25 +354,40 @@ intr_calculatemasks() /* And eventually calculate the complete masks. */ for (irq = 0; irq < ICU_LEN; irq++) { - register int irqs = 1 << irq; + int irqs = 1 << irq; int minlevel = IPL_NONE; int maxlevel = IPL_NONE; - for (q = intrhand[irq]; q; q = q->ih_next) { - irqs |= IMASK(q->ih_level); - if (minlevel == IPL_NONE || q->ih_level < minlevel) - minlevel = q->ih_level; - if (q->ih_level > maxlevel) - maxlevel = q->ih_level; + if (intrhand[irq] == NULL) { + maxlevel = IPL_HIGH; + irqs = IMASK(IPL_HIGH); + } else { + for (q = intrhand[irq]; q; q = q->ih_next) { + irqs |= IMASK(q->ih_level); + if (minlevel == IPL_NONE || + q->ih_level < minlevel) + minlevel = q->ih_level; + if (q->ih_level > maxlevel) + maxlevel = q->ih_level; + } } + if (irqs != IMASK(maxlevel)) + panic("irq %d level %x mask mismatch: %x vs %x", irq, + maxlevel, irqs, IMASK(maxlevel)); + intrmask[irq] = irqs; iminlevel[irq] = minlevel; imaxlevel[irq] = maxlevel; + +#if 0 + printf("irq %d: level %x, mask 0x%x (%x)\n", irq, + imaxlevel[irq], intrmask[irq], IMASK(imaxlevel[irq])); +#endif } /* Lastly, determine which IRQs are actually in use. */ { - register int irqs = 0; + int irqs = 0; for (irq = 0; irq < ICU_LEN; irq++) if (intrhand[irq]) irqs |= 1 << irq; @@ -496,17 +534,48 @@ isa_intr_establish(ic, irq, type, level, ih_fun, ih_arg, ih_what) struct intrhand **p, *q, *ih; static struct intrhand fakehand = {fakeintr}; +#if NIOAPIC > 0 + struct mp_intr_map *mip; + + if (mp_busses != NULL) { + int mpspec_pin = irq; + int bus = mp_isa_bus; + int airq; + + for (mip = mp_busses[bus].mb_intrs; mip != NULL; + mip = mip->next) { + if (mip->bus_pin == mpspec_pin) { + airq = mip->ioapic_ih | irq; + break; + } + } + if (mip == NULL && mp_eisa_bus != -1) { + for (mip = mp_busses[mp_eisa_bus].mb_intrs; + mip != NULL; mip=mip->next) { + if (mip->bus_pin == mpspec_pin) { + airq = mip->ioapic_ih | irq; + break; + } + } + } + if (mip == NULL) + printf("isa_intr_establish: no MP mapping found\n"); + else + return (apic_intr_establish(airq, type, level, ih_fun, + ih_arg, ih_what)); + } +#endif /* no point in sleeping unless someone can free memory. */ ih = malloc(sizeof *ih, M_DEVBUF, cold ? M_NOWAIT : M_WAITOK); if (ih == NULL) { printf("%s: isa_intr_establish: can't malloc handler info\n", ih_what); - return NULL; + return (NULL); } if (!LEGAL_IRQ(irq) || type == IST_NONE) { - printf("%s: intr_establish: bogus irq or type\n", ih_what); - return NULL; + printf("%s: isa_intr_establish: bogus irq or type\n", ih_what); + return (NULL); } switch (intrtype[irq]) { case IST_NONE: @@ -521,7 +590,7 @@ isa_intr_establish(ic, irq, type, level, ih_fun, ih_arg, ih_what) /*printf("%s: intr_establish: can't share %s with %s, irq %d\n", ih_what, isa_intr_typename(intrtype[irq]), isa_intr_typename(type), irq);*/ - return NULL; + return (NULL); } break; } @@ -571,8 +640,15 @@ isa_intr_disestablish(ic, arg) int irq = ih->ih_irq; struct intrhand **p, *q; +#if NIOAPIC > 0 + if (irq & APIC_INT_VIA_APIC) { + apic_intr_disestablish(arg); + return; + } +#endif + if (!LEGAL_IRQ(irq)) - panic("intr_disestablish: bogus irq"); + panic("intr_disestablish: bogus irq %d", irq); /* * Remove the handler from the chain. diff --git a/sys/arch/i386/isa/mms.c b/sys/arch/i386/isa/mms.c index 1b84aecf965..137c18384a5 100644 --- a/sys/arch/i386/isa/mms.c +++ b/sys/arch/i386/isa/mms.c @@ -1,4 +1,4 @@ -/* $OpenBSD: mms.c,v 1.16 2002/03/14 01:26:33 millert Exp $ */ +/* $OpenBSD: mms.c,v 1.17 2004/06/13 21:49:16 niklas Exp $ */ /* $NetBSD: mms.c,v 1.35 2000/01/08 02:57:25 takemura Exp $ */ /*- diff --git a/sys/arch/i386/isa/npx.c b/sys/arch/i386/isa/npx.c index b56a17f3875..4111ba0ab90 100644 --- a/sys/arch/i386/isa/npx.c +++ b/sys/arch/i386/isa/npx.c @@ -1,10 +1,10 @@ -/* $OpenBSD: npx.c,v 1.31 2004/02/01 19:05:21 deraadt Exp $ */ +/* $OpenBSD: npx.c,v 1.32 2004/06/13 21:49:16 niklas Exp $ */ /* $NetBSD: npx.c,v 1.57 1996/05/12 23:12:24 mycroft Exp $ */ #if 0 -#define iprintf(x) printf x +#define IPRINTF(x) printf x #else -#define iprintf(x) +#define IPRINTF(x) #endif /*- @@ -54,21 +54,16 @@ #include <machine/cpu.h> #include <machine/intr.h> +#include <machine/npx.h> #include <machine/pio.h> #include <machine/cpufunc.h> #include <machine/pcb.h> #include <machine/trap.h> #include <machine/specialreg.h> +#include <machine/i8259.h> #include <dev/isa/isareg.h> #include <dev/isa/isavar.h> -#include <i386/isa/icu.h> - -#if 0 -#define IPRINTF(x) printf x -#else -#define IPRINTF(x) -#endif /* * 387 and 287 Numeric Coprocessor Extension (NPX) Driver. @@ -104,7 +99,6 @@ int npxintr(void *); static int npxprobe1(struct isa_attach_args *); -static void npxsave1(void); struct npx_softc { struct device sc_dev; @@ -129,10 +123,7 @@ enum npx_type { NPX_BROKEN, }; -struct proc *npxproc; - static enum npx_type npx_type; -static int npx_nointr; static volatile u_int npx_intrs_while_probing; static volatile u_int npx_traps_while_probing; @@ -160,15 +151,15 @@ fpu_save(union savefpu *addr) } static int -npxdna_notset(struct proc *p) +npxdna_notset(struct cpu_info *ci) { panic("npxdna vector not initialized"); } -int (*npxdna_func)(struct proc *) = npxdna_notset; -int npxdna_s87(struct proc *); +int (*npxdna_func)(struct cpu_info *) = npxdna_notset; +int npxdna_s87(struct cpu_info *); #ifdef I686_CPU -int npxdna_xmm(struct proc *); +int npxdna_xmm(struct cpu_info *); #endif /* I686_CPU */ void npxexit(void); @@ -350,6 +341,19 @@ asm (".text\n\t" "popl %eax\n\t" "ret\n\t"); +void +npxinit(struct cpu_info *ci) +{ + lcr0(rcr0() & ~(CR0_EM|CR0_TS)); + fninit(); + if (npx586bug1(4195835, 3145727) != 0) { + i386_fpu_fdivbug = 1; + printf("%s: WARNING: Pentium FDIV bug detected!\n", + ci->ci_dev.dv_xname); + } + lcr0(rcr0() | (CR0_TS)); +} + /* * Attach routine - announce which it is, and wire into system */ @@ -379,13 +383,7 @@ npxattach(parent, self, aux) return; } - lcr0(rcr0() & ~(CR0_EM|CR0_TS)); - fninit(); - if (npx586bug1(4195835, 3145727) != 0) { - i386_fpu_fdivbug = 1; - printf("WARNING: Pentium FDIV bug detected!\n"); - } - lcr0(rcr0() | (CR0_TS)); + npxinit(&cpu_info_primary); i386_fpu_present = 1; #ifdef I686_CPU @@ -415,16 +413,17 @@ int npxintr(arg) void *arg; { - register struct proc *p = npxproc; + struct cpu_info *ci = curcpu(); + struct proc *p = ci->ci_fpcurproc; union savefpu *addr; struct intrframe *frame = arg; int code; union sigval sv; uvmexp.traps++; - iprintf(("Intr")); + IPRINTF(("%s: fp intr\n", ci->ci_dev.dv_xname)); - if (p == 0 || npx_type == NPX_NONE) { + if (p == NULL || npx_type == NPX_NONE) { /* XXX no %p in stand/printf.c. Cast to quiet gcc -Wall. */ printf("npxintr: p = %lx, curproc = %lx, npx_type = %d\n", (u_long) p, (u_long) curproc, npx_type); @@ -438,11 +437,21 @@ npxintr(arg) * If we're saving, ignore the interrupt. The FPU will happily * generate another one when we restore the state later. */ - if (npx_nointr != 0) + if (ci->ci_fpsaving) return (1); + +#ifdef DIAGNOSTIC /* - * Find the address of npxproc's savefpu. This is not necessarily - * the one in curpcb. + * At this point, fpcurproc should be curproc. If it wasn't, the TS + * bit should be set, and we should have gotten a DNA exception. + */ + if (p != curproc) + panic("npxintr: wrong process"); +#endif + + /* + * Find the address of fpcurproc's saved FPU state. (Given the + * invariant above, this is always the one in curpcb.) */ addr = &p->p_addr->u_pcb.pcb_savefpu; /* @@ -504,7 +513,7 @@ npxintr(arg) if (addr->sv_87.sv_ex_sw & EN_SW_IE) code = FPE_FLTINV; #ifdef notyet - else if (addr->sv_ex_sw & EN_SW_DE) + else if (addr->sv_87.sv_ex_sw & EN_SW_DE) code = FPE_FLTDEN; #endif else if (addr->sv_87.sv_ex_sw & EN_SW_ZE) @@ -541,115 +550,147 @@ npxintr(arg) } /* - * Wrapper for fnsave instruction to handle h/w bugs. If there is an error - * pending, then fnsave generates a bogus IRQ13 on some systems. Force any - * IRQ13 to be handled immediately, and then ignore it. - * - * This routine is always called at spl0. If it might called with the NPX - * interrupt masked, it would be necessary to forcibly unmask the NPX interrupt - * so that it could succeed. - */ -static __inline void -npxsave1(void) -{ - register struct pcb *pcb; - - npx_nointr = 1; - pcb = &npxproc->p_addr->u_pcb; - fpu_save(&pcb->pcb_savefpu); - pcb->pcb_cr0 |= CR0_TS; - fwait(); - npx_nointr = 0; -} - -/* * Implement device not available (DNA) exception * - * If the we were the last process to use the FPU, we can simply return. + * If we were the last process to use the FPU, we can simply return. * Otherwise, we save the previous state, if necessary, and restore our last * saved state. */ + +/* + * XXX It is unclear if the code below is correct in the multiprocessor + * XXX case. Check the NetBSD sources once again to be sure. + */ #ifdef I686_CPU int -npxdna_xmm(struct proc *p) +npxdna_xmm(struct cpu_info *ci) { + struct proc *p; + int s; -#ifdef DIAGNOSTIC - if (cpl != 0 || npx_nointr != 0) - panic("npxdna: masked"); + if (ci->ci_fpsaving) { + printf("recursive npx trap; cr0=%x\n", rcr0()); + return (0); + } + + s = splipi(); /* lock out IPI's while we clean house.. */ + +#ifdef MULTIPROCESSOR + p = ci->ci_curproc; +#else + p = curproc; #endif - p->p_addr->u_pcb.pcb_cr0 &= ~CR0_TS; - clts(); + IPRINTF(("%s: dna for %lx%s\n", ci->ci_dev.dv_xname, (u_long)p, + (p->p_md.md_flags & MDP_USEDFPU) ? " (used fpu)" : "")); /* + * XXX should have a fast-path here when no save/restore is necessary + */ + /* * Initialize the FPU state to clear any exceptions. If someone else * was using the FPU, save their state (which does an implicit * initialization). */ - npx_nointr = 1; - if (npxproc != 0 && npxproc != p) { - IPRINTF(("Save")); - npxsave1(); + if (ci->ci_fpcurproc != NULL) { + IPRINTF(("%s: fp save %lx\n", ci->ci_dev.dv_xname, + (u_long)ci->ci_fpcurproc)); + npxsave_cpu(ci, 1); } else { - IPRINTF(("Init")); - fninit(); - fwait(); + clts(); + IPRINTF(("%s: fp init\n", ci->ci_dev.dv_xname)); + fninit(); + fwait(); + stts(); } - npx_nointr = 0; - npxproc = p; + splx(s); + + IPRINTF(("%s: done saving\n", ci->ci_dev.dv_xname)); + KDASSERT(ci->ci_fpcurproc == NULL); +#ifndef MULTIPROCESSOR + KDASSERT(p->p_addr->u_pcb.pcb_fpcpu == NULL); +#else + if (p->p_addr->u_pcb.pcb_fpcpu != NULL) + npxsave_proc(p, 1); +#endif + p->p_addr->u_pcb.pcb_cr0 &= ~CR0_TS; + clts(); + s = splipi(); + ci->ci_fpcurproc = p; + p->p_addr->u_pcb.pcb_fpcpu = ci; + splx(s); if ((p->p_md.md_flags & MDP_USEDFPU) == 0) { fldcw(&p->p_addr->u_pcb.pcb_savefpu.sv_xmm.sv_env.en_cw); p->p_md.md_flags |= MDP_USEDFPU; - } else + } else { fxrstor(&p->p_addr->u_pcb.pcb_savefpu.sv_xmm); + } return (1); } #endif /* I686_CPU */ int -npxdna_s87(struct proc *p) +npxdna_s87(struct cpu_info *ci) { - static u_short control = __INITIAL_NPXCW__; + struct proc *p; + int s; + + KDASSERT(i386_use_fxsave == 0); - if (npx_type == NPX_NONE) { - iprintf(("Emul")); + if (ci->ci_fpsaving) { + printf("recursive npx trap; cr0=%x\n", rcr0()); return (0); } -#ifdef DIAGNOSTIC - if (cpl != IPL_NONE || npx_nointr != 0) - panic("npxdna: masked"); + s = splipi(); /* lock out IPI's while we clean house.. */ +#ifdef MULTIPROCESSOR + p = ci->ci_curproc; +#else + p = curproc; #endif + IPRINTF(("%s: dna for %lx%s\n", ci->ci_dev.dv_xname, (u_long)p, + (p->p_md.md_flags & MDP_USEDFPU) ? " (used fpu)" : "")); + + /* + * If someone else was using our FPU, save their state (which does an + * implicit initialization); otherwise, initialize the FPU state to + * clear any exceptions. + */ + if (ci->ci_fpcurproc != NULL) { + IPRINTF(("%s: fp save %lx\n", ci->ci_dev.dv_xname, + (u_long)ci->ci_fpcurproc)); + npxsave_cpu(ci, 1); + } else { + clts(); + IPRINTF(("%s: fp init\n", ci->ci_dev.dv_xname)); + fninit(); + fwait(); + stts(); + } + splx(s); + + IPRINTF(("%s: done saving\n", ci->ci_dev.dv_xname)); + KDASSERT(ci->ci_fpcurproc == NULL); +#ifndef MULTIPROCESSOR + KDASSERT(p->p_addr->u_pcb.pcb_fpcpu == NULL); +#else + if (p->p_addr->u_pcb.pcb_fpcpu != NULL) + npxsave_proc(p, 1); +#endif p->p_addr->u_pcb.pcb_cr0 &= ~CR0_TS; clts(); + s = splipi(); + ci->ci_fpcurproc = p; + p->p_addr->u_pcb.pcb_fpcpu = ci; + splx(s); if ((p->p_md.md_flags & MDP_USEDFPU) == 0) { + fldcw(&p->p_addr->u_pcb.pcb_savefpu.sv_87.sv_env.en_cw); p->p_md.md_flags |= MDP_USEDFPU; - iprintf(("Init")); - if (npxproc != 0 && npxproc != p) - npxsave1(); - else { - npx_nointr = 1; - fninit(); - fwait(); - npx_nointr = 0; - } - npxproc = p; - fldcw(&control); } else { - if (npxproc != 0) { -#ifdef DIAGNOSTIC - if (npxproc == p) - panic("npxdna: same process"); -#endif - iprintf(("Save")); - npxsave1(); - } - npxproc = p; /* * The following frstor may cause an IRQ13 when the state being * restored has a pending error. The error will appear to have @@ -670,37 +711,121 @@ npxdna_s87(struct proc *p) } /* - * Drop the current FPU state on the floor. + * The FNSAVE instruction clears the FPU state. Rather than reloading the FPU + * immediately, we clear fpcurproc and turn on CR0_TS to force a DNA and a + * reload of the FPU state the next time we try to use it. This routine + * is only called when forking, core dumping, or debugging, or swapping, + * so the lazy reload at worst forces us to trap once per fork(), and at best + * saves us a reload once per fork(). */ void -npxdrop() +npxsave_cpu(struct cpu_info *ci, int save) { + struct proc *p; + int s; + + KDASSERT(ci == curcpu()); + + p = ci->ci_fpcurproc; + if (p == NULL) + return; + + IPRINTF(("%s: fp cpu %s %lx\n", ci->ci_dev.dv_xname, + save ? "save" : "flush", (u_long)p)); + + if (save) { +#ifdef DIAGNOSTIC + if (ci->ci_fpsaving != 0) + panic("npxsave_cpu: recursive save!"); +#endif + /* + * Set ci->ci_fpsaving, so that any pending exception will be + * thrown away. (It will be caught again if/when the FPU + * state is restored.) + * + * XXX on i386 and earlier, this routine should always be + * called at spl0; if it might called with the NPX interrupt + * masked, it would be necessary to forcibly unmask the NPX + * interrupt so that it could succeed. + * XXX this is irrelevant on 486 and above (systems + * which report FP failures via traps rather than irq13). + * XXX punting for now.. + */ + clts(); + ci->ci_fpsaving = 1; + fpu_save(&p->p_addr->u_pcb.pcb_savefpu); + ci->ci_fpsaving = 0; + /* It is unclear if this is needed. */ + fwait(); + } + /* + * We set the TS bit in the saved CR0 for this process, so that it + * will get a DNA exception on any FPU instruction and force a reload. + */ stts(); - npxproc->p_addr->u_pcb.pcb_cr0 |= CR0_TS; - npxproc = 0; + p->p_addr->u_pcb.pcb_cr0 |= CR0_TS; + + s = splipi(); + p->p_addr->u_pcb.pcb_fpcpu = NULL; + ci->ci_fpcurproc = NULL; + splx(s); } /* - * Save npxproc's FPU state. - * - * The FNSAVE instruction clears the FPU state. Rather than reloading the FPU - * immediately, we clear npxproc and turn on CR0_TS to force a DNA and a reload - * of the FPU state the next time we try to use it. This routine is only - * called when forking or core dump, so this algorithm at worst forces us to - * trap once per fork(), and at best saves us a reload once per fork(). + * Save p's FPU state, which may be on this processor or another processor. */ -void -npxsave() + void +npxsave_proc(struct proc *p, int save) { + struct cpu_info *ci = curcpu(); + struct cpu_info *oci; + + KDASSERT(p->p_addr != NULL); + KDASSERT(p->p_flag & P_INMEM); + oci = p->p_addr->u_pcb.pcb_fpcpu; + if (oci == NULL) + return; + + IPRINTF(("%s: fp proc %s %lx\n", ci->ci_dev.dv_xname, + save ? "save" : "flush", (u_long)p)); + +#if defined(MULTIPROCESSOR) + if (oci == ci) { + int s = splipi(); + npxsave_cpu(ci, save); + splx(s); + } else { #ifdef DIAGNOSTIC - if (cpl != IPL_NONE || npx_nointr != 0) - panic("npxsave: masked"); + int spincount; +#endif + + IPRINTF(("%s: fp ipi to %s %s %lx\n", ci->ci_dev.dv_xname, + oci->ci_dev.dv_xname, save ? "save" : "flush", (u_long)p)); + + i386_send_ipi(oci, + save ? I386_IPI_SYNCH_FPU : I386_IPI_FLUSH_FPU); + +#ifdef DIAGNOSTIC + spincount = 0; +#endif + while (p->p_addr->u_pcb.pcb_fpcpu != NULL) +#ifdef DIAGNOSTIC + { + spincount++; + if (spincount > 100000000) { + panic("fp_save ipi didn't"); + } + } +#else + __splbarrier(); /* XXX replace by generic barrier */ + ; +#endif + } +#else + KASSERT(ci->ci_fpcurproc == p); + npxsave_cpu(ci, save); #endif - iprintf(("Fork")); - clts(); - npxsave1(); - stts(); - npxproc = 0; } + diff --git a/sys/arch/i386/isa/vector.s b/sys/arch/i386/isa/vector.s deleted file mode 100644 index 93a7bab51da..00000000000 --- a/sys/arch/i386/isa/vector.s +++ /dev/null @@ -1,295 +0,0 @@ -/* $OpenBSD: vector.s,v 1.16 2003/04/17 03:42:14 drahn Exp $ */ -/* $NetBSD: vector.s,v 1.32 1996/01/07 21:29:47 mycroft Exp $ */ - -/* - * Copyright (c) 1993, 1994, 1995 Charles M. Hannum. All rights reserved. - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions - * are met: - * 1. Redistributions of source code must retain the above copyright - * notice, this list of conditions and the following disclaimer. - * 2. Redistributions in binary form must reproduce the above copyright - * notice, this list of conditions and the following disclaimer in the - * documentation and/or other materials provided with the distribution. - * 3. All advertising materials mentioning features or use of this software - * must display the following acknowledgement: - * This product includes software developed by Charles M. Hannum. - * 4. The name of the author may not be used to endorse or promote products - * derived from this software without specific prior written permission. - * - * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR - * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES - * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. - * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, - * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT - * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, - * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY - * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT - * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF - * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - */ - -#include <i386/isa/icu.h> -#include <dev/isa/isareg.h> - -#define ICU_HARDWARE_MASK - -#define MY_COUNT _C_LABEL(uvmexp) - -/* - * These macros are fairly self explanatory. If ICU_SPECIAL_MASK_MODE is - * defined, we try to take advantage of the ICU's `special mask mode' by only - * EOIing the interrupts on return. This avoids the requirement of masking and - * unmasking. We can't do this without special mask mode, because the ICU - * would also hold interrupts that it thinks are of lower priority. - * - * Many machines do not support special mask mode, so by default we don't try - * to use it. - */ - -#define IRQ_BIT(irq_num) (1 << ((irq_num) % 8)) -#define IRQ_BYTE(irq_num) ((irq_num) / 8) - -#ifdef ICU_SPECIAL_MASK_MODE - -#define ACK1(irq_num) -#define ACK2(irq_num) \ - movb $(0x60|IRQ_SLAVE),%al /* specific EOI for IRQ2 */ ;\ - outb %al,$IO_ICU1 -#define MASK(irq_num, icu) -#define UNMASK(irq_num, icu) \ - movb $(0x60|(irq_num%8)),%al /* specific EOI */ ;\ - outb %al,$icu - -#else /* ICU_SPECIAL_MASK_MODE */ - -#ifndef AUTO_EOI_1 -#define ACK1(irq_num) \ - movb $(0x60|(irq_num%8)),%al /* specific EOI */ ;\ - outb %al,$IO_ICU1 -#else -#define ACK1(irq_num) -#endif - -#ifndef AUTO_EOI_2 -#define ACK2(irq_num) \ - movb $(0x60|(irq_num%8)),%al /* specific EOI */ ;\ - outb %al,$IO_ICU2 /* do the second ICU first */ ;\ - movb $(0x60|IRQ_SLAVE),%al /* specific EOI for IRQ2 */ ;\ - outb %al,$IO_ICU1 -#else -#define ACK2(irq_num) -#endif - -#ifdef ICU_HARDWARE_MASK - -#define MASK(irq_num, icu) \ - movb _C_LABEL(imen) + IRQ_BYTE(irq_num),%al ;\ - orb $IRQ_BIT(irq_num),%al ;\ - movb %al,_C_LABEL(imen) + IRQ_BYTE(irq_num) ;\ - FASTER_NOP ;\ - outb %al,$(icu+1) -#define UNMASK(irq_num, icu) \ - cli ;\ - movb _C_LABEL(imen) + IRQ_BYTE(irq_num),%al ;\ - andb $~IRQ_BIT(irq_num),%al ;\ - movb %al,_C_LABEL(imen) + IRQ_BYTE(irq_num) ;\ - FASTER_NOP ;\ - outb %al,$(icu+1) ;\ - sti - -#else /* ICU_HARDWARE_MASK */ - -#define MASK(irq_num, icu) -#define UNMASK(irq_num, icu) - -#endif /* ICU_HARDWARE_MASK */ - -#endif /* ICU_SPECIAL_MASK_MODE */ - -/* - * Macros for interrupt entry, call to handler, and exit. - * - * XXX - * The interrupt frame is set up to look like a trap frame. This may be a - * waste. The only handler which needs a frame is the clock handler, and it - * only needs a few bits. Xdoreti() needs a trap frame for handling ASTs, but - * it could easily convert the frame on demand. - * - * The direct costs of setting up a trap frame are two pushl's (error code and - * trap number), an addl to get rid of these, and pushing and popping the - * callee-saved registers %esi, %edi, %ebx, and %ebp twice. - * - * If the interrupt frame is made more flexible, INTR can push %eax first and - * decide the ipending case with less overhead, e.g., by avoiding loading the - * segment registers. - * - * XXX - * Should we do a cld on every system entry to avoid the requirement for - * scattered cld's? - */ - - .globl _C_LABEL(isa_strayintr) - -/* - * Normal vectors. - * - * We cdr down the intrhand chain, calling each handler with its appropriate - * argument (0 meaning a pointer to the frame, for clock interrupts). - * - * The handler returns one of three values: - * 0 - This interrupt wasn't for me. - * 1 - This interrupt was for me. - * -1 - This interrupt might have been for me, but I don't know. - * If there are no handlers, or they all return 0, we flags it as a `stray' - * interrupt. On a system with level-triggered interrupts, we could terminate - * immediately when one of them returns 1; but this is a PC. - * - * On exit, we jump to Xdoreti(), to process soft interrupts and ASTs. - */ -#define INTR(irq_num, icu, ack) \ -IDTVEC(recurse/**/irq_num) ;\ - pushfl ;\ - pushl %cs ;\ - pushl %esi ;\ - cli ;\ -_C_LABEL(Xintr)/**/irq_num/**/: ;\ - pushl $0 /* dummy error code */ ;\ - pushl $T_ASTFLT /* trap # for doing ASTs */ ;\ - INTRENTRY ;\ - MAKE_FRAME ;\ - MASK(irq_num, icu) /* mask it in hardware */ ;\ - ack(irq_num) /* and allow other intrs */ ;\ - incl MY_COUNT+V_INTR /* statistical info */ ;\ - movl _C_LABEL(iminlevel) + (irq_num) * 4, %eax ;\ - movzbl _C_LABEL(cpl),%ebx ;\ - cmpl %eax,%ebx ;\ - jae _C_LABEL(Xhold/**/irq_num)/* currently masked; hold it */;\ -_C_LABEL(Xresume)/**/irq_num/**/: ;\ - movzbl _C_LABEL(cpl),%eax /* cpl to restore on exit */ ;\ - pushl %eax ;\ - movl _C_LABEL(imaxlevel) + (irq_num) * 4,%eax ;\ - movl %eax,_C_LABEL(cpl) /* block enough for this irq */ ;\ - sti /* safe to take intrs now */ ;\ - movl _C_LABEL(intrhand) + (irq_num) * 4,%ebx /* head of chain */ ;\ - testl %ebx,%ebx ;\ - jz _C_LABEL(Xstray)/**/irq_num /* no handlears; we're stray */ ;\ - STRAY_INITIALIZE /* nobody claimed it yet */ ;\ -7: movl IH_ARG(%ebx),%eax /* get handler arg */ ;\ - testl %eax,%eax ;\ - jnz 4f ;\ - movl %esp,%eax /* 0 means frame pointer */ ;\ -4: pushl %eax ;\ - call *IH_FUN(%ebx) /* call it */ ;\ - addl $4,%esp /* toss the arg */ ;\ - STRAY_INTEGRATE /* maybe he claimed it */ ;\ - orl %eax,%eax /* should it be counted? */ ;\ - jz 5f /* no, skip it */ ;\ - incl IH_COUNT(%ebx) /* count the intrs */ ;\ -5: movl IH_NEXT(%ebx),%ebx /* next handler in chain */ ;\ - testl %ebx,%ebx ;\ - jnz 7b ;\ - STRAY_TEST /* see if it's a stray */ ;\ -6: UNMASK(irq_num, icu) /* unmask it in hardware */ ;\ - jmp _C_LABEL(Xdoreti) /* lower spl and do ASTs */ ;\ -IDTVEC(stray/**/irq_num) ;\ - pushl $irq_num ;\ - call _C_LABEL(isa_strayintr) ;\ - addl $4,%esp ;\ - jmp 6b ;\ -IDTVEC(hold/**/irq_num) ;\ - orb $IRQ_BIT(irq_num),_C_LABEL(ipending) + IRQ_BYTE(irq_num) ;\ - INTRFASTEXIT - -#if defined(DEBUG) && defined(notdef) -#define STRAY_INITIALIZE \ - xorl %esi,%esi -#define STRAY_INTEGRATE \ - orl %eax,%esi -#define STRAY_TEST \ - testl %esi,%esi ;\ - jz _C_LABEL(Xstray)/**/irq_num -#else /* !DEBUG */ -#define STRAY_INITIALIZE -#define STRAY_INTEGRATE -#define STRAY_TEST -#endif /* DEBUG */ - -#ifdef DDB -#define MAKE_FRAME \ - leal -8(%esp),%ebp -#else /* !DDB */ -#define MAKE_FRAME -#endif /* DDB */ - -INTR(0, IO_ICU1, ACK1) -INTR(1, IO_ICU1, ACK1) -INTR(2, IO_ICU1, ACK1) -INTR(3, IO_ICU1, ACK1) -INTR(4, IO_ICU1, ACK1) -INTR(5, IO_ICU1, ACK1) -INTR(6, IO_ICU1, ACK1) -INTR(7, IO_ICU1, ACK1) -INTR(8, IO_ICU2, ACK2) -INTR(9, IO_ICU2, ACK2) -INTR(10, IO_ICU2, ACK2) -INTR(11, IO_ICU2, ACK2) -INTR(12, IO_ICU2, ACK2) -INTR(13, IO_ICU2, ACK2) -INTR(14, IO_ICU2, ACK2) -INTR(15, IO_ICU2, ACK2) - -/* - * These tables are used by the ISA configuration code. - */ -/* interrupt service routine entry points */ -IDTVEC(intr) - .long _C_LABEL(Xintr0), _C_LABEL(Xintr1), _C_LABEL(Xintr2) - .long _C_LABEL(Xintr3), _C_LABEL(Xintr4), _C_LABEL(Xintr5) - .long _C_LABEL(Xintr6), _C_LABEL(Xintr7), _C_LABEL(Xintr8) - .long _C_LABEL(Xintr9), _C_LABEL(Xintr10), _C_LABEL(Xintr11) - .long _C_LABEL(Xintr12), _C_LABEL(Xintr13) - .long _C_LABEL(Xintr14), _C_LABEL(Xintr15) - -/* - * These tables are used by Xdoreti() and Xspllower(). - */ -/* resume points for suspended interrupts */ -IDTVEC(resume) - .long _C_LABEL(Xresume0), _C_LABEL(Xresume1) - .long _C_LABEL(Xresume2), _C_LABEL(Xresume3) - .long _C_LABEL(Xresume4), _C_LABEL(Xresume5) - .long _C_LABEL(Xresume6), _C_LABEL(Xresume7) - .long _C_LABEL(Xresume8), _C_LABEL(Xresume9) - .long _C_LABEL(Xresume10), _C_LABEL(Xresume11) - .long _C_LABEL(Xresume12), _C_LABEL(Xresume13) - .long _C_LABEL(Xresume14), _C_LABEL(Xresume15) - /* for soft interrupts */ - .long 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 - .long _C_LABEL(Xsofttty), _C_LABEL(Xsoftnet) - .long _C_LABEL(Xsoftclock) -/* fake interrupts to resume from splx() */ -IDTVEC(recurse) - .long _C_LABEL(Xrecurse0), _C_LABEL(Xrecurse1) - .long _C_LABEL(Xrecurse2), _C_LABEL(Xrecurse3) - .long _C_LABEL(Xrecurse4), _C_LABEL(Xrecurse5) - .long _C_LABEL(Xrecurse6), _C_LABEL(Xrecurse7) - .long _C_LABEL(Xrecurse8), _C_LABEL(Xrecurse9) - .long _C_LABEL(Xrecurse10), _C_LABEL(Xrecurse11) - .long _C_LABEL(Xrecurse12), _C_LABEL(Xrecurse13) - .long _C_LABEL(Xrecurse14), _C_LABEL(Xrecurse15) - /* for soft interrupts */ - .long 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 - .long _C_LABEL(Xsofttty), _C_LABEL(Xsoftnet) - .long _C_LABEL(Xsoftclock) - -/* Some bogus data, to keep vmstat happy, for now. */ - .globl _C_LABEL(intrnames), _C_LABEL(eintrnames) - .globl _C_LABEL(intrcnt), _C_LABEL(eintrcnt) -_C_LABEL(intrnames): - .long 0 -_C_LABEL(eintrnames): -_C_LABEL(intrcnt): - .long 0 -_C_LABEL(eintrcnt): |