diff options
author | Artur Grabowski <art@cvs.openbsd.org> | 2004-06-25 11:03:29 +0000 |
---|---|---|
committer | Artur Grabowski <art@cvs.openbsd.org> | 2004-06-25 11:03:29 +0000 |
commit | 1738a99caa862954a176f61a5b39322cb4d236a9 (patch) | |
tree | 8174d0a279102d74dc7834b5f2bbfeb6475e7664 /sys | |
parent | 553a08a83999f0198ea42221d73ef0c373884e6a (diff) |
SMP support. Big parts from NetBSD, but with some really serious debugging
done by me, niklas and others. Especially wrt. NXE support.
Still needs some polishing, especially in dmesg messages, but we're now
building kernel faster than ever.
Diffstat (limited to 'sys')
37 files changed, 3332 insertions, 230 deletions
diff --git a/sys/arch/amd64/amd64/apic.c b/sys/arch/amd64/amd64/apic.c new file mode 100644 index 00000000000..aa21491781b --- /dev/null +++ b/sys/arch/amd64/amd64/apic.c @@ -0,0 +1,79 @@ +/* $OpenBSD: apic.c,v 1.1 2004/06/25 11:03:27 art Exp $ */ +/* $NetBSD: apic.c,v 1.1 2003/02/26 21:26:11 fvdl Exp $ */ + +/*- + * Copyright (c) 2000 The NetBSD Foundation, Inc. + * All rights reserved. + * + * This code is derived from software contributed to The NetBSD Foundation + * by RedBack Networks Inc. + * + * Author: Bill Sommerfeld + * + * 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 the NetBSD + * Foundation, Inc. and its contributors. + * 4. Neither the name of The NetBSD Foundation 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 NETBSD FOUNDATION, INC. 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 FOUNDATION 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. + */ + +#include <sys/param.h> +#include <sys/systm.h> +#include <sys/lock.h> /* XXX */ + +#include <machine/i82489reg.h> +#include <machine/i82489var.h> +#include <machine/apicvar.h> + + +const char redirlofmt[] = "\177\20" + "f\0\10vector\0" + "f\10\3delmode\0" + "b\13logical\0" + "b\14pending\0" + "b\15actlo\0" + "b\16irrpending\0" + "b\17level\0" + "b\20masked\0" + "f\22\1dest\0" "=\1self" "=\2all" "=\3all-others"; + +const char redirhifmt[] = "\177\20" + "f\30\10target\0"; + +void +apic_format_redir(where1, where2, idx, redirhi, redirlo) + char *where1; + char *where2; + int idx; + u_int32_t redirhi; + u_int32_t redirlo; +{ + printf("%s: %s%d 0x%x", where1, where2, idx, redirlo); + + if ((redirlo & LAPIC_DEST_MASK) == 0) + printf(" 0x%x", redirhi); + + printf("\n"); +} diff --git a/sys/arch/amd64/amd64/cpu.c b/sys/arch/amd64/amd64/cpu.c index 5f71091cc7a..f415bcc5d31 100644 --- a/sys/arch/amd64/amd64/cpu.c +++ b/sys/arch/amd64/amd64/cpu.c @@ -1,4 +1,4 @@ -/* $OpenBSD: cpu.c,v 1.4 2004/06/24 19:35:23 tholo Exp $ */ +/* $OpenBSD: cpu.c,v 1.5 2004/06/25 11:03:27 art Exp $ */ /* $NetBSD: cpu.c,v 1.1 2003/04/26 18:39:26 fvdl Exp $ */ /*- @@ -347,6 +347,7 @@ cpu_attach(parent, self, aux) cpu_intr_init(ci); gdt_alloc_cpu(ci); cpu_start_secondary(ci); + ncpus++; if (ci->ci_flags & CPUF_PRESENT) { identifycpu(ci); ci->ci_next = cpu_info_list->ci_next; @@ -447,27 +448,11 @@ cpu_start_secondary (ci) { struct pcb *pcb; int i; - struct pmap *kmp = pmap_kernel(); - extern u_int64_t mp_pdirpa; - extern vaddr_t lo32_vaddr; - extern paddr_t lo32_paddr; - - /* - * The initial PML4 pointer must be below 4G, so if the - * current one isn't, use a "bounce buffer" - */ - if (kmp->pm_pdirpa > 0xffffffff) { - memcpy((void *)lo32_vaddr, kmp->pm_pdir, PAGE_SIZE); - mp_pdirpa = lo32_paddr; - } else - mp_pdirpa = kmp->pm_pdirpa; pcb = ci->ci_idle_pcb; ci->ci_flags |= CPUF_AP; - printf("%s: starting\n", ci->ci_dev->dv_xname); - CPU_STARTUP(ci); /* @@ -558,10 +543,6 @@ cpu_hatch(void *v) enable_intr(); printf("%s: CPU %u running\n",ci->ci_dev->dv_xname, ci->ci_cpuid); -#if defined(I586_CPU) || defined(I686_CPU) - if (ci->ci_feature_flags & CPUID_TSC) - cc_microset(ci); -#endif microuptime(&ci->ci_schedstate.spc_runtime); splx(s); } @@ -601,12 +582,30 @@ cpu_copy_trampoline() */ extern u_char cpu_spinup_trampoline[]; extern u_char cpu_spinup_trampoline_end[]; + + struct pmap *kmp = pmap_kernel(); + extern u_int32_t mp_pdirpa; + extern vaddr_t lo32_vaddr; + extern paddr_t lo32_paddr; + pmap_kenter_pa((vaddr_t)MP_TRAMPOLINE, /* virtual */ (paddr_t)MP_TRAMPOLINE, /* physical */ VM_PROT_ALL); /* protection */ memcpy((caddr_t)MP_TRAMPOLINE, cpu_spinup_trampoline, cpu_spinup_trampoline_end-cpu_spinup_trampoline); + + /* + * The initial PML4 pointer must be below 4G, so if the + * current one isn't, use a "bounce buffer" + * We need to patch this after we copy the trampoline, + * the symbol points into the copied trampoline. + */ + if (kmp->pm_pdirpa > 0xffffffff) { + memcpy((void *)lo32_vaddr, kmp->pm_pdir, PAGE_SIZE); + mp_pdirpa = lo32_paddr; + } else + mp_pdirpa = kmp->pm_pdirpa; } #endif @@ -635,9 +634,9 @@ mp_cpu_start(struct cpu_info *ci) dwordptr[0] = 0; dwordptr[1] = MP_TRAMPOLINE >> 4; - pmap_kenter_pa (0, 0, VM_PROT_READ|VM_PROT_WRITE); - memcpy ((u_int8_t *) 0x467, dwordptr, 4); - pmap_kremove (0, PAGE_SIZE); + pmap_kenter_pa(0, 0, VM_PROT_READ|VM_PROT_WRITE); + memcpy((u_int8_t *) 0x467, dwordptr, 4); + pmap_kremove(0, PAGE_SIZE); #if NLAPIC > 0 /* @@ -651,7 +650,6 @@ mp_cpu_start(struct cpu_info *ci) delay(10000); if (cpu_feature & CPUID_APIC) { - if ((error = x86_ipi(MP_TRAMPOLINE/PAGE_SIZE, ci->ci_apicid, LAPIC_DLMODE_STARTUP)) != 0) diff --git a/sys/arch/amd64/amd64/fpu.c b/sys/arch/amd64/amd64/fpu.c index 3c3298481b2..bd2ac4e4d3d 100644 --- a/sys/arch/amd64/amd64/fpu.c +++ b/sys/arch/amd64/amd64/fpu.c @@ -1,4 +1,4 @@ -/* $OpenBSD: fpu.c,v 1.4 2004/02/28 20:33:33 nordin Exp $ */ +/* $OpenBSD: fpu.c,v 1.5 2004/06/25 11:03:27 art Exp $ */ /* $NetBSD: fpu.c,v 1.1 2003/04/26 18:39:28 fvdl Exp $ */ /*- @@ -288,7 +288,7 @@ fpusave_proc(struct proc *p, int save) #ifdef DIAGNOSTIC spincount = 0; #endif - while (p->dpl_addr->u_pcb.pcb_fpcpu != NULL) + while (p->p_addr->u_pcb.pcb_fpcpu != NULL) #ifdef DIAGNOSTIC { spincount++; diff --git a/sys/arch/amd64/amd64/gdt.c b/sys/arch/amd64/amd64/gdt.c index 837c82b8e88..ded8e4a421e 100644 --- a/sys/arch/amd64/amd64/gdt.c +++ b/sys/arch/amd64/amd64/gdt.c @@ -1,4 +1,4 @@ -/* $OpenBSD: gdt.c,v 1.3 2004/05/20 21:06:46 nordin Exp $ */ +/* $OpenBSD: gdt.c,v 1.4 2004/06/25 11:03:27 art Exp $ */ /* $NetBSD: gdt.c,v 1.1 2003/04/26 18:39:28 fvdl Exp $ */ /*- @@ -81,15 +81,15 @@ void gdt_put_slot(int); static __inline void gdt_lock() { - - (void) lockmgr(&gdt_lock_store, LK_EXCLUSIVE, NULL, curproc); + if (curproc != NULL) /* XXX - ugh. needed for startup */ + (void) lockmgr(&gdt_lock_store, LK_EXCLUSIVE, NULL, curproc); } static __inline void gdt_unlock() { - - (void) lockmgr(&gdt_lock_store, LK_RELEASE, NULL, curproc); + if (curproc != NULL) + (void) lockmgr(&gdt_lock_store, LK_RELEASE, NULL, curproc); } void diff --git a/sys/arch/amd64/amd64/genassym.cf b/sys/arch/amd64/amd64/genassym.cf index 7061ce92c6b..43f25173c7f 100644 --- a/sys/arch/amd64/amd64/genassym.cf +++ b/sys/arch/amd64/amd64/genassym.cf @@ -1,4 +1,4 @@ -# $OpenBSD: genassym.cf,v 1.5 2004/06/22 01:16:50 art Exp $ +# $OpenBSD: genassym.cf,v 1.6 2004/06/25 11:03:27 art Exp $ # Written by Artur Grabowski art@openbsd.org, Public Domain @@ -15,6 +15,8 @@ include <machine/pmap.h> include <machine/pte.h> include <machine/vmparam.h> include <machine/intr.h> +include <machine/pic.h> +include <machine/i82093var.h> export SRUN export SONPROC @@ -105,6 +107,7 @@ member CPU_INFO_IDEPTH ci_idepth member CPU_INFO_ISOURCES ci_isources member CPU_INFO_IPENDING ci_ipending member CPU_INFO_IUNMASK ci_iunmask +member CPU_INFO_GDT ci_gdt struct intrsource member is_recurse @@ -123,6 +126,10 @@ member ih_arg member ih_next member ih_level +struct ioapic_softc +member IOAPIC_SC_REG sc_reg +member IOAPIC_SC_DATA sc_data + # pte fields export PG_V export PG_KR diff --git a/sys/arch/amd64/amd64/i8259.c b/sys/arch/amd64/amd64/i8259.c index 12b04b2a40b..4cea529bde2 100644 --- a/sys/arch/amd64/amd64/i8259.c +++ b/sys/arch/amd64/amd64/i8259.c @@ -1,4 +1,4 @@ -/* $OpenBSD: i8259.c,v 1.1 2004/01/28 01:39:38 mickey Exp $ */ +/* $OpenBSD: i8259.c,v 1.2 2004/06/25 11:03:27 art Exp $ */ /* $NetBSD: i8259.c,v 1.2 2003/03/02 18:27:15 fvdl Exp $ */ /* @@ -112,9 +112,7 @@ struct pic i8259_pic = { {0, {NULL}, NULL, 0, "pic0", NULL, 0, 0}, PIC_I8259, #ifdef MULTIPROCESSOR - __SIMPLELOCK_UNLOCKED, -#else - 0, + {}, #endif i8259_hwmask, i8259_hwunmask, diff --git a/sys/arch/amd64/amd64/identcpu.c b/sys/arch/amd64/amd64/identcpu.c index 2f8fda8d2f8..9b1596646e8 100644 --- a/sys/arch/amd64/amd64/identcpu.c +++ b/sys/arch/amd64/amd64/identcpu.c @@ -1,4 +1,4 @@ -/* $OpenBSD: identcpu.c,v 1.4 2004/02/28 18:12:21 deraadt Exp $ */ +/* $OpenBSD: identcpu.c,v 1.5 2004/06/25 11:03:27 art Exp $ */ /* $NetBSD: identcpu.c,v 1.1 2003/04/26 18:39:28 fvdl Exp $ */ /* @@ -163,11 +163,6 @@ identifycpu(struct cpu_info *ci) printf("\n"); x86_print_cacheinfo(ci); - - return; /* TODO - warning to fix this ifdef later */ -#ifdef notyet - microtime_func = cc_microtime; -#endif } void diff --git a/sys/arch/amd64/amd64/intr.c b/sys/arch/amd64/amd64/intr.c index a80798e3a44..f5f929cbbd2 100644 --- a/sys/arch/amd64/amd64/intr.c +++ b/sys/arch/amd64/amd64/intr.c @@ -1,4 +1,4 @@ -/* $OpenBSD: intr.c,v 1.1 2004/01/28 01:39:38 mickey Exp $ */ +/* $OpenBSD: intr.c,v 1.2 2004/06/25 11:03:27 art Exp $ */ /* $NetBSD: intr.c,v 1.3 2003/03/03 22:16:20 fvdl Exp $ */ /* @@ -69,9 +69,7 @@ struct pic softintr_pic = { {0, {NULL}, NULL, 0, "softintr_fakepic", NULL, 0, 0}, PIC_SOFT, #ifdef MULTIPROCESSOR - __SIMPLELOCK_UNLOCKED, -#else - 0, + {}, #endif NULL, NULL, @@ -544,7 +542,7 @@ struct intrhand fake_softserial_intrhand; struct intrhand fake_timer_intrhand; struct intrhand fake_ipi_intrhand; -#if NLAPIC > 0 && defined(MULTIPROCESSOR) +#if NLAPIC > 0 && defined(MULTIPROCESSOR) && 0 static char *x86_ipi_names[X86_NIPI] = X86_IPI_NAMES; #endif @@ -556,7 +554,7 @@ void cpu_intr_init(struct cpu_info *ci) { struct intrsource *isp; -#if NLAPIC > 0 && defined(MULTIPROCESSOR) +#if NLAPIC > 0 && defined(MULTIPROCESSOR) && 0 int i; #endif @@ -634,11 +632,13 @@ cpu_intr_init(struct cpu_info *ci) isp->is_pic = &local_pic; ci->ci_isources[LIR_IPI] = isp; +#ifdef notyet for (i = 0; i < X86_NIPI; i++) evcnt_attach_dynamic(&ci->ci_ipi_events[i], EVCNT_TYPE_INTR, NULL, ci->ci_dev->dv_xname, x86_ipi_names[i]); #endif #endif +#endif intr_calculatemasks(ci); @@ -649,26 +649,26 @@ void x86_intlock(struct intrframe iframe) { if (iframe.if_ppl < IPL_SCHED) - spinlockmgr(&kernel_lock, LK_EXCLUSIVE|LK_CANRECURSE, 0); + __mp_lock(&kernel_lock); } void x86_intunlock(struct intrframe iframe) { if (iframe.if_ppl < IPL_SCHED) - spinlockmgr(&kernel_lock, LK_RELEASE, 0); + __mp_unlock(&kernel_lock); } void x86_softintlock(void) { - spinlockmgr(&kernel_lock, LK_EXCLUSIVE|LK_CANRECURSE, 0); + __mp_lock(&kernel_lock); } void x86_softintunlock(void) { - spinlockmgr(&kernel_lock, LK_RELEASE, 0); + __mp_unlock(&kernel_lock); } #endif diff --git a/sys/arch/amd64/amd64/ioapic.c b/sys/arch/amd64/amd64/ioapic.c new file mode 100644 index 00000000000..77874bc243d --- /dev/null +++ b/sys/arch/amd64/amd64/ioapic.c @@ -0,0 +1,549 @@ +/* $OpenBSD: ioapic.c,v 1.1 2004/06/25 11:03:27 art Exp $ */ +/* $NetBSD: ioapic.c,v 1.6 2003/05/15 13:30:31 fvdl Exp $ */ + +/*- + * Copyright (c) 2000 The NetBSD Foundation, Inc. + * All rights reserved. + * + * This code is derived from software contributed to The NetBSD Foundation + * by RedBack Networks Inc. + * + * Author: Bill Sommerfeld + * + * 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 the NetBSD + * Foundation, Inc. and its contributors. + * 4. Neither the name of The NetBSD Foundation 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 NETBSD FOUNDATION, INC. 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 FOUNDATION 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. + */ + + +/* + * Copyright (c) 1999 Stefan Grefen + * + * 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 the NetBSD + * Foundation, Inc. and its contributors. + * 4. Neither the name of The NetBSD Foundation 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 AUTHOR 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 AUTHOR AND 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. + */ + +#include <sys/param.h> +#include <sys/systm.h> +#include <sys/device.h> +#include <sys/malloc.h> + +#include <machine/bus.h> +#include <machine/isa_machdep.h> /* XXX intrhand */ + +#include <uvm/uvm_extern.h> +#include <machine/i82093reg.h> +#include <machine/i82093var.h> + +#include <machine/i82489reg.h> +#include <machine/i82489var.h> + +#include <machine/pmap.h> + +#include <machine/mpbiosvar.h> + +#if !defined(MPBIOS) && !defined(MPACPI) +#error "ioapic needs at least one of the MPBIOS or MPACPI options" +#endif + +/* + * XXX locking + */ + +int ioapic_match(struct device *, void *, void *); +void ioapic_attach(struct device *, struct device *, void *); + +extern int x86_mem_add_mapping(bus_addr_t, bus_size_t, + int, bus_space_handle_t *); /* XXX XXX */ + +void ioapic_hwmask(struct pic *, int); +void ioapic_hwunmask(struct pic *, int); +void ioapic_addroute(struct pic *, struct cpu_info *, int, int, int); +void ioapic_delroute(struct pic *, struct cpu_info *, int, int, int); +void apic_set_redir(struct ioapic_softc *, int, int, struct cpu_info *); + +int apic_verbose = 0; + +int ioapic_bsp_id = 0; +int ioapic_cold = 1; + +struct ioapic_softc *ioapics; /* head of linked list */ +int nioapics = 0; /* number attached */ +static int ioapic_vecbase; + +static __inline u_long +ioapic_lock(struct ioapic_softc *sc) +{ + u_long flags; + + flags = read_psl(); + disable_intr(); + SIMPLE_LOCK(&sc->sc_pic.pic_lock); + return flags; +} + +static __inline void +ioapic_unlock(struct ioapic_softc *sc, u_long flags) +{ + SIMPLE_UNLOCK(&sc->sc_pic.pic_lock); + write_psl(flags); +} + +/* + * Register read/write routines. + */ +static __inline u_int32_t +ioapic_read_ul(struct ioapic_softc *sc,int regid) +{ + u_int32_t val; + + *(sc->sc_reg) = regid; + val = *sc->sc_data; + + return val; + +} + +static __inline void +ioapic_write_ul(struct ioapic_softc *sc,int regid, u_int32_t val) +{ + *(sc->sc_reg) = regid; + *(sc->sc_data) = val; +} + +static __inline u_int32_t +ioapic_read(struct ioapic_softc *sc, int regid) +{ + u_int32_t val; + u_long flags; + + flags = ioapic_lock(sc); + val = ioapic_read_ul(sc, regid); + ioapic_unlock(sc, flags); + return val; +} + +static __inline void +ioapic_write(struct ioapic_softc *sc,int regid, int val) +{ + u_long flags; + + flags = ioapic_lock(sc); + ioapic_write_ul(sc, regid, val); + ioapic_unlock(sc, flags); +} + +struct ioapic_softc * +ioapic_find(int apicid) +{ + struct ioapic_softc *sc; + + if (apicid == MPS_ALL_APICS) { /* XXX mpbios-specific */ + /* + * XXX kludge for all-ioapics interrupt support + * on single ioapic systems + */ + if (nioapics <= 1) + return ioapics; + panic("unsupported: all-ioapics interrupt with >1 ioapic"); + } + + for (sc = ioapics; sc != NULL; sc = sc->sc_next) + if (sc->sc_apicid == apicid) + return sc; + + return NULL; +} + +/* + * For the case the I/O APICs were configured using ACPI, there must + * be an option to match global ACPI interrupts with APICs. + */ +struct ioapic_softc * +ioapic_find_bybase(int vec) +{ + struct ioapic_softc *sc; + + for (sc = ioapics; sc != NULL; sc = sc->sc_next) { + if (vec >= sc->sc_apic_vecbase && + vec < (sc->sc_apic_vecbase + sc->sc_apic_sz)) + return sc; + } + + return NULL; +} + +static __inline void +ioapic_add(struct ioapic_softc *sc) +{ + sc->sc_next = ioapics; + ioapics = sc; + nioapics++; +} + +void +ioapic_print_redir (struct ioapic_softc *sc, char *why, int pin) +{ + u_int32_t redirlo = ioapic_read(sc, IOAPIC_REDLO(pin)); + u_int32_t redirhi = ioapic_read(sc, IOAPIC_REDHI(pin)); + + apic_format_redir(sc->sc_pic.pic_dev.dv_xname, why, pin, redirhi, + redirlo); +} + +struct cfattach ioapic_ca = { + sizeof(struct ioapic_softc), ioapic_match, ioapic_attach +}; + +struct cfdriver ioapic_cd = { + NULL, "ioapic", DV_DULL +}; + +int +ioapic_match(struct device *parent, void *v, void *aux) +{ + struct apic_attach_args *aaa = (struct apic_attach_args *) aux; + struct cfdata *match = v; + + if (strcmp(aaa->aaa_name, match->cf_driver->cd_name) == 0) + return 1; + return 0; +} + +/* + * can't use bus_space_xxx as we don't have a bus handle ... + */ +void +ioapic_attach(struct device *parent, struct device *self, void *aux) +{ + struct ioapic_softc *sc = (struct ioapic_softc *)self; + struct apic_attach_args *aaa = (struct apic_attach_args *) aux; + int apic_id; + bus_space_handle_t bh; + u_int32_t ver_sz; + int i; + + sc->sc_flags = aaa->flags; + sc->sc_apicid = aaa->apic_id; + + printf(" apid %d (I/O APIC)\n", aaa->apic_id); + + if (ioapic_find(aaa->apic_id) != NULL) { + printf("%s: duplicate apic id (ignored)\n", + sc->sc_pic.pic_dev.dv_xname); + return; + } + + ioapic_add(sc); + + printf("%s: pa 0x%lx", sc->sc_pic.pic_dev.dv_xname, aaa->apic_address); + + if (x86_mem_add_mapping(aaa->apic_address, PAGE_SIZE, 0, &bh) != 0) { + printf(": map failed\n"); + return; + } + sc->sc_reg = (volatile u_int32_t *)(bh + IOAPIC_REG); + sc->sc_data = (volatile u_int32_t *)(bh + IOAPIC_DATA); + + sc->sc_pic.pic_type = PIC_IOAPIC; + SIMPLE_LOCK_INIT(&sc->sc_pic.pic_lock); + sc->sc_pic.pic_hwmask = ioapic_hwmask; + sc->sc_pic.pic_hwunmask = ioapic_hwunmask; + sc->sc_pic.pic_addroute = ioapic_addroute; + sc->sc_pic.pic_delroute = ioapic_delroute; + sc->sc_pic.pic_edge_stubs = ioapic_edge_stubs; + sc->sc_pic.pic_level_stubs = ioapic_level_stubs; + + apic_id = (ioapic_read(sc,IOAPIC_ID)&IOAPIC_ID_MASK)>>IOAPIC_ID_SHIFT; + ver_sz = ioapic_read(sc, IOAPIC_VER); + + sc->sc_apic_vers = (ver_sz & IOAPIC_VER_MASK) >> IOAPIC_VER_SHIFT; + sc->sc_apic_sz = (ver_sz & IOAPIC_MAX_MASK) >> IOAPIC_MAX_SHIFT; + sc->sc_apic_sz++; + + if (aaa->apic_vecbase != -1) + sc->sc_apic_vecbase = aaa->apic_vecbase; + else { + /* + * XXX this assumes ordering of ioapics in the table. + * Only needed for broken BIOS workaround (see mpbios.c) + */ + sc->sc_apic_vecbase = ioapic_vecbase; + ioapic_vecbase += sc->sc_apic_sz; + } + + if (mp_verbose) { + printf(", %s mode", + aaa->flags & IOAPIC_PICMODE ? "PIC" : "virtual wire"); + } + + printf(", version %x, %d pins\n", sc->sc_apic_vers, sc->sc_apic_sz); + + sc->sc_pins = malloc(sizeof(struct ioapic_pin) * sc->sc_apic_sz, + M_DEVBUF, M_WAITOK); + + for (i=0; i<sc->sc_apic_sz; i++) { + sc->sc_pins[i].ip_next = NULL; + sc->sc_pins[i].ip_map = NULL; + sc->sc_pins[i].ip_vector = 0; + sc->sc_pins[i].ip_type = IST_NONE; + } + + /* + * In case the APIC is not initialized to the correct ID + * do it now. + * Maybe we should record the original ID for interrupt + * mapping later ... + */ + if (apic_id != sc->sc_apicid) { + printf("%s: misconfigured as apic %d\n", sc->sc_pic.pic_dev.dv_xname, apic_id); + + ioapic_write(sc,IOAPIC_ID, + (ioapic_read(sc,IOAPIC_ID)&~IOAPIC_ID_MASK) + |(sc->sc_apicid<<IOAPIC_ID_SHIFT)); + + apic_id = (ioapic_read(sc,IOAPIC_ID)&IOAPIC_ID_MASK)>>IOAPIC_ID_SHIFT; + + if (apic_id != sc->sc_apicid) { + printf("%s: can't remap to apid %d\n", + sc->sc_pic.pic_dev.dv_xname, + sc->sc_apicid); + } else { + printf("%s: remapped to apic %d\n", + sc->sc_pic.pic_dev.dv_xname, + sc->sc_apicid); + } + } +#if 0 + /* output of this was boring. */ + if (mp_verbose) + for (i=0; i<sc->sc_apic_sz; i++) + ioapic_print_redir(sc, "boot", i); +#endif +} + +void +apic_set_redir(struct ioapic_softc *sc, int pin, int idt_vec, + struct cpu_info *ci) +{ + u_int32_t redlo; + u_int32_t redhi = 0; + int delmode; + + struct ioapic_pin *pp; + struct mp_intr_map *map; + + pp = &sc->sc_pins[pin]; + map = pp->ip_map; + redlo = map == NULL ? IOAPIC_REDLO_MASK : map->redir; + delmode = (redlo & IOAPIC_REDLO_DEL_MASK) >> IOAPIC_REDLO_DEL_SHIFT; + + /* XXX magic numbers */ + if ((delmode != 0) && (delmode != 1)) + ; + else if (pp->ip_type == IST_NONE) { + redlo |= IOAPIC_REDLO_MASK; + } else { + redlo |= (idt_vec & 0xff); + redlo &= ~IOAPIC_REDLO_DEL_MASK; + redlo |= (IOAPIC_REDLO_DEL_FIXED<<IOAPIC_REDLO_DEL_SHIFT); + redlo &= ~IOAPIC_REDLO_DSTMOD; + + /* + * Destination: BSP CPU + * + * XXX will want to distribute interrupts across cpu's + * eventually. most likely, we'll want to vector each + * interrupt to a specific CPU and load-balance across + * cpu's. but there's no point in doing that until after + * most interrupts run without the kernel lock. + */ + redhi |= (ci->ci_apicid << IOAPIC_REDHI_DEST_SHIFT); + + /* XXX derive this bit from BIOS info */ + if (pp->ip_type == IST_LEVEL) + redlo |= IOAPIC_REDLO_LEVEL; + else + redlo &= ~IOAPIC_REDLO_LEVEL; + if (map != NULL && ((map->flags & 3) == MPS_INTPO_DEF)) { + if (pp->ip_type == IST_LEVEL) + redlo |= IOAPIC_REDLO_ACTLO; + else + redlo &= ~IOAPIC_REDLO_ACTLO; + } + } + ioapic_write(sc, IOAPIC_REDLO(pin), redlo); + ioapic_write(sc, IOAPIC_REDHI(pin), redhi); + if (mp_verbose) + ioapic_print_redir(sc, "int", pin); +} + +/* + * Throw the switch and enable interrupts.. + */ + +void +ioapic_enable(void) +{ + int p; + struct ioapic_softc *sc; + struct ioapic_pin *ip; + + ioapic_cold = 0; + + if (ioapics == NULL) + return; + + if (ioapics->sc_flags & IOAPIC_PICMODE) { + printf("%s: writing to IMCR to disable pics\n", + ioapics->sc_pic.pic_dev.dv_xname); + outb(IMCR_ADDR, IMCR_REGISTER); + outb(IMCR_DATA, IMCR_APIC); + } + + for (sc = ioapics; sc != NULL; sc = sc->sc_next) { + printf("%s: enabling\n", sc->sc_pic.pic_dev.dv_xname); + + for (p = 0; p < sc->sc_apic_sz; p++) { + ip = &sc->sc_pins[p]; + if (ip->ip_type != IST_NONE) + apic_set_redir(sc, p, ip->ip_vector, + ip->ip_cpu); + } + } +} + +void +ioapic_hwmask(struct pic *pic, int pin) +{ + u_int32_t redlo; + struct ioapic_softc *sc = (struct ioapic_softc *)pic; + u_long flags; + + if (ioapic_cold) + return; + flags = ioapic_lock(sc); + redlo = ioapic_read_ul(sc, IOAPIC_REDLO(pin)); + redlo |= IOAPIC_REDLO_MASK; + ioapic_write_ul(sc, IOAPIC_REDLO(pin), redlo); + ioapic_unlock(sc, flags); +} + +void +ioapic_hwunmask(struct pic *pic, int pin) +{ + u_int32_t redlo; + struct ioapic_softc *sc = (struct ioapic_softc *)pic; + u_long flags; + + if (ioapic_cold) { + return; + } + flags = ioapic_lock(sc); + redlo = ioapic_read_ul(sc, IOAPIC_REDLO(pin)); + redlo &= ~IOAPIC_REDLO_MASK; + ioapic_write_ul(sc, IOAPIC_REDLO(pin), redlo); + ioapic_unlock(sc, flags); +} + +void +ioapic_addroute(struct pic *pic, struct cpu_info *ci, int pin, + int idtvec, int type) + +{ + struct ioapic_softc *sc = (struct ioapic_softc *)pic; + struct ioapic_pin *pp; + + if (ioapic_cold) { + pp = &sc->sc_pins[pin]; + pp->ip_type = type; + pp->ip_vector = idtvec; + pp->ip_cpu = ci; + return; + } + apic_set_redir(sc, pin, idtvec, ci); +} + +void +ioapic_delroute(struct pic *pic, struct cpu_info *ci, int pin, + int idtvec, int type) +{ + struct ioapic_softc *sc = (struct ioapic_softc *)pic; + struct ioapic_pin *pp; + + if (ioapic_cold) { + pp = &sc->sc_pins[pin]; + pp->ip_type = IST_NONE; + return; + } + ioapic_hwmask(pic, pin); +} + +#ifdef DDB +void ioapic_dump(void); + +void +ioapic_dump(void) +{ + struct ioapic_softc *sc; + struct ioapic_pin *ip; + int p; + + for (sc = ioapics; sc != NULL; sc = sc->sc_next) { + for (p = 0; p < sc->sc_apic_sz; p++) { + ip = &sc->sc_pins[p]; + if (ip->ip_type != IST_NONE) + ioapic_print_redir(sc, "dump", p); + } + } +} +#endif diff --git a/sys/arch/amd64/amd64/ipi.c b/sys/arch/amd64/amd64/ipi.c new file mode 100644 index 00000000000..8cdecb60207 --- /dev/null +++ b/sys/arch/amd64/amd64/ipi.c @@ -0,0 +1,142 @@ +/* $OpenBSD: ipi.c,v 1.1 2004/06/25 11:03:27 art Exp $ */ +/* $NetBSD: ipi.c,v 1.2 2003/03/01 13:05:37 fvdl Exp $ */ + +/*- + * Copyright (c) 2000 The NetBSD Foundation, Inc. + * All rights reserved. + * + * This code is derived from software contributed to The NetBSD Foundation + * by RedBack Networks Inc. + * + * Author: Bill Sommerfeld + * + * 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 the NetBSD + * Foundation, Inc. and its contributors. + * 4. Neither the name of The NetBSD Foundation 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 NETBSD FOUNDATION, INC. 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 FOUNDATION 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. + */ + +#include <sys/cdefs.h> /* RCS ID & Copyright macro defns */ + +#include <sys/param.h> +#include <sys/device.h> +#include <sys/systm.h> + +#include <machine/intr.h> +#include <machine/atomic.h> +#include <machine/cpuvar.h> +#include <machine/i82093var.h> +#include <machine/i82489reg.h> +#include <machine/i82489var.h> + +int +x86_send_ipi(struct cpu_info *ci, int ipimask) +{ + int ret; + + x86_atomic_setbits_l(&ci->ci_ipis, ipimask); + + /* Don't send IPI to cpu which isn't (yet) running. */ + if (!(ci->ci_flags & CPUF_RUNNING)) + return ENOENT; + + ret = x86_ipi(LAPIC_IPI_VECTOR, ci->ci_apicid, LAPIC_DLMODE_FIXED); + if (ret != 0) { + printf("ipi of %x from %s to %s failed\n", + ipimask, + curcpu()->ci_dev->dv_xname, + ci->ci_dev->dv_xname); + } + + return ret; +} + +void +x86_self_ipi (int vector) +{ + i82489_writereg(LAPIC_ICRLO, + vector | LAPIC_DLMODE_FIXED | LAPIC_LVL_ASSERT | LAPIC_DEST_SELF); +} + + +void +x86_broadcast_ipi (int ipimask) +{ + struct cpu_info *ci, *self = curcpu(); + int count = 0; + + CPU_INFO_ITERATOR cii; + + for (CPU_INFO_FOREACH(cii, ci)) { + if (ci == self) + continue; + if ((ci->ci_flags & CPUF_RUNNING) == 0) + continue; + x86_atomic_setbits_l(&ci->ci_ipis, ipimask); + count++; + } + if (!count) + return; + + i82489_writereg(LAPIC_ICRLO, + LAPIC_IPI_VECTOR | LAPIC_DLMODE_FIXED | LAPIC_LVL_ASSERT | + LAPIC_DEST_ALLEXCL); +} + +void +x86_multicast_ipi(int cpumask, int ipimask) +{ + struct cpu_info *ci; + CPU_INFO_ITERATOR cii; + + cpumask &= ~(1U << cpu_number()); + if (cpumask == 0) + return; + + for (CPU_INFO_FOREACH(cii, ci)) { + if ((cpumask & (1U << ci->ci_cpuid)) == 0) + continue; + x86_send_ipi(ci, ipimask); + } +} + +void +x86_ipi_handler(void) +{ + struct cpu_info *ci = curcpu(); + u_int32_t pending; + int bit; + + pending = x86_atomic_testset_ul(&ci->ci_ipis, 0); + + for (bit = 0; bit < X86_NIPI && pending; bit++) { + if (pending & (1<<bit)) { + pending &= ~(1<<bit); + ci->ci_ipi_events[bit].ev_count++; + (*ipifunc[bit])(ci); + } + } +} diff --git a/sys/arch/amd64/amd64/ipifuncs.c b/sys/arch/amd64/amd64/ipifuncs.c new file mode 100644 index 00000000000..fea247d36fc --- /dev/null +++ b/sys/arch/amd64/amd64/ipifuncs.c @@ -0,0 +1,135 @@ +/* $OpenBSD: ipifuncs.c,v 1.1 2004/06/25 11:03:27 art Exp $ */ +/* $NetBSD: ipifuncs.c,v 1.1 2003/04/26 18:39:28 fvdl Exp $ */ + +/*- + * Copyright (c) 2000 The NetBSD Foundation, Inc. + * All rights reserved. + * + * This code is derived from software contributed to The NetBSD Foundation + * by RedBack Networks Inc. + * + * Author: Bill Sommerfeld + * + * 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 the NetBSD + * Foundation, Inc. and its contributors. + * 4. Neither the name of The NetBSD Foundation 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 NETBSD FOUNDATION, INC. 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 FOUNDATION 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. + */ + +#include <sys/cdefs.h> /* RCS ID & Copyright macro defns */ + +/* + * Interprocessor interrupt handlers. + */ + +#include <sys/param.h> +#include <sys/device.h> +#include <sys/systm.h> + +#include <uvm/uvm_extern.h> + +#include <machine/intr.h> +#include <machine/atomic.h> +#include <machine/cpuvar.h> +#include <machine/i82093var.h> +#include <machine/i82489reg.h> +#include <machine/i82489var.h> +#include <machine/mtrr.h> +#include <machine/gdt.h> +#include <machine/fpu.h> + +#include <ddb/db_output.h> + +void x86_64_ipi_halt(struct cpu_info *); + +void x86_64_ipi_synch_fpu(struct cpu_info *); +void x86_64_ipi_flush_fpu(struct cpu_info *); + +void x86_64_ipi_nop(struct cpu_info *); + +#ifdef MTRR +void x86_64_reload_mtrr(struct cpu_info *); +#else +#define x86_64_reload_mtrr NULL +#endif + +void (*ipifunc[X86_NIPI])(struct cpu_info *) = +{ + x86_64_ipi_halt, +#if 0 + cc_microset, +#else + x86_64_ipi_nop, +#endif + x86_64_ipi_flush_fpu, + x86_64_ipi_synch_fpu, + pmap_do_tlb_shootdown, + x86_64_reload_mtrr, + gdt_reload_cpu, +}; + +void +x86_64_ipi_nop(struct cpu_info *ci) +{ +} + +void +x86_64_ipi_halt(struct cpu_info *ci) +{ + disable_intr(); + + printf("%s: shutting down\n", ci->ci_dev->dv_xname); + for(;;) { + __asm __volatile("hlt"); + } +} + +void +x86_64_ipi_flush_fpu(struct cpu_info *ci) +{ + fpusave_cpu(ci, 0); +} + +void +x86_64_ipi_synch_fpu(struct cpu_info *ci) +{ + fpusave_cpu(ci, 1); +} + +#ifdef MTRR + +/* + * mtrr_reload_cpu() is a macro in mtrr.h which picks the appropriate + * function to use.. + */ + +void +x86_64_reload_mtrr(struct cpu_info *ci) +{ + if (mtrr_funcs != NULL) + mtrr_reload_cpu(ci); +} +#endif diff --git a/sys/arch/amd64/amd64/lapic.c b/sys/arch/amd64/amd64/lapic.c new file mode 100644 index 00000000000..dcf6df2a8c5 --- /dev/null +++ b/sys/arch/amd64/amd64/lapic.c @@ -0,0 +1,491 @@ +/* $OpenBSD: lapic.c,v 1.1 2004/06/25 11:03:27 art Exp $ */ +/* $NetBSD: lapic.c,v 1.2 2003/05/08 01:04:35 fvdl Exp $ */ + +/*- + * Copyright (c) 2000 The NetBSD Foundation, Inc. + * All rights reserved. + * + * This code is derived from software contributed to The NetBSD Foundation + * by RedBack Networks Inc. + * + * Author: Bill Sommerfeld + * + * 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 the NetBSD + * Foundation, Inc. and its contributors. + * 4. Neither the name of The NetBSD Foundation 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 NETBSD FOUNDATION, INC. 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 FOUNDATION 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. + */ + +#include <sys/param.h> +#include <sys/proc.h> +#include <sys/user.h> +#include <sys/systm.h> +#include <sys/device.h> + +#include <uvm/uvm_extern.h> + +#include <dev/ic/i8253reg.h> + +#include <machine/cpu.h> +#include <machine/cpufunc.h> +#include <machine/cpuvar.h> +#include <machine/pmap.h> +#include <machine/vmparam.h> +#include <machine/mpbiosvar.h> +#include <machine/pcb.h> +#include <machine/specialreg.h> +#include <machine/segments.h> + +#include <machine/apicvar.h> +#include <machine/i82489reg.h> +#include <machine/i82489var.h> + +void lapic_delay(int); +void lapic_microtime(struct timeval *); +static u_int32_t lapic_gettick(void); +void lapic_clockintr(void *, struct intrframe); +void lapic_map(paddr_t); + +void lapic_hwmask(struct pic *, int); +void lapic_hwunmask(struct pic *, int); +void lapic_setup(struct pic *, struct cpu_info *, int, int, int); + +extern char idt_allocmap[]; + +struct pic local_pic = { + {0, {NULL}, NULL, 0, "lapic", NULL, 0, 0}, + PIC_LAPIC, +#ifdef MULTIPROCESSOR + {}, +#endif + lapic_hwmask, + lapic_hwunmask, + lapic_setup, + lapic_setup, +}; + +void +lapic_map(lapic_base) + paddr_t lapic_base; +{ + int s; + pt_entry_t *pte; + vaddr_t va = (vaddr_t)&local_apic; + + disable_intr(); + s = lapic_tpr; + + /* + * Map local apic. If we have a local apic, it's safe to assume + * we're on a 486 or better and can use invlpg and non-cacheable PTE's + * + * Whap the PTE "by hand" rather than calling pmap_kenter_pa because + * the latter will attempt to invoke TLB shootdown code just as we + * might have changed the value of cpu_number().. + */ + + pte = kvtopte(va); + *pte = lapic_base | PG_RW | PG_V | PG_N | pmap_pg_g; + invlpg(va); + +#ifdef MULTIPROCESSOR + cpu_init_first(); /* catch up to changed cpu_number() */ +#endif + + lapic_tpr = s; + enable_intr(); +} + +/* + * enable local apic + */ +void +lapic_enable() +{ + i82489_writereg(LAPIC_SVR, LAPIC_SVR_ENABLE | LAPIC_SPURIOUS_VECTOR); +} + +void +lapic_set_lvt() +{ + struct cpu_info *ci = curcpu(); + int i; + struct mp_intr_map *mpi; + uint32_t lint0; + +#ifdef MULTIPROCESSOR + if (mp_verbose) { + apic_format_redir (ci->ci_dev->dv_xname, "prelint", 0, 0, + i82489_readreg(LAPIC_LVINT0)); + apic_format_redir (ci->ci_dev->dv_xname, "prelint", 1, 0, + i82489_readreg(LAPIC_LVINT1)); + } +#endif + + /* + * Disable ExtINT by default when using I/O APICs. + * XXX mp_nintr > 0 isn't quite the right test for this. + */ + if (mp_nintr > 0) { + lint0 = i82489_readreg(LAPIC_LVINT0); + lint0 |= LAPIC_LVT_MASKED; + i82489_writereg(LAPIC_LVINT0, lint0); + } + + for (i = 0; i < mp_nintr; i++) { + mpi = &mp_intrs[i]; + if (mpi->ioapic == NULL && (mpi->cpu_id == MPS_ALL_APICS + || mpi->cpu_id == ci->ci_apicid)) { +#ifdef DIAGNOSTIC + if (mpi->ioapic_pin > 1) + panic("lapic_set_lvt: bad pin value %d", + mpi->ioapic_pin); +#endif + if (mpi->ioapic_pin == 0) + i82489_writereg(LAPIC_LVINT0, mpi->redir); + else + i82489_writereg(LAPIC_LVINT1, mpi->redir); + } + } + +#ifdef MULTIPROCESSOR + if (mp_verbose) { + apic_format_redir (ci->ci_dev->dv_xname, "timer", 0, 0, + i82489_readreg(LAPIC_LVTT)); + apic_format_redir (ci->ci_dev->dv_xname, "pcint", 0, 0, + i82489_readreg(LAPIC_PCINT)); + apic_format_redir (ci->ci_dev->dv_xname, "lint", 0, 0, + i82489_readreg(LAPIC_LVINT0)); + apic_format_redir (ci->ci_dev->dv_xname, "lint", 1, 0, + i82489_readreg(LAPIC_LVINT1)); + apic_format_redir (ci->ci_dev->dv_xname, "err", 0, 0, + i82489_readreg(LAPIC_LVERR)); + } +#endif +} + +/* + * Initialize fixed idt vectors for use by local apic. + */ +void +lapic_boot_init(lapic_base) + paddr_t lapic_base; +{ + + lapic_map(lapic_base); + +#ifdef MULTIPROCESSOR + idt_allocmap[LAPIC_IPI_VECTOR] = 1; + idt_vec_set(LAPIC_IPI_VECTOR, Xintr_lapic_ipi); +#endif + idt_allocmap[LAPIC_SPURIOUS_VECTOR] = 1; + idt_vec_set(LAPIC_SPURIOUS_VECTOR, Xintrspurious); + + idt_allocmap[LAPIC_TIMER_VECTOR] = 1; + idt_vec_set(LAPIC_TIMER_VECTOR, Xintr_lapic_ltimer); +} + +static inline u_int32_t lapic_gettick() +{ + return i82489_readreg(LAPIC_CCR_TIMER); +} + +#include <sys/kernel.h> /* for hz */ + +int lapic_timer = 0; +u_int32_t lapic_tval; + +/* + * this gets us up to a 4GHz busclock.... + */ +u_int32_t lapic_per_second; +u_int32_t lapic_frac_usec_per_cycle; +u_int64_t lapic_frac_cycle_per_usec; +u_int32_t lapic_delaytab[26]; + +void +lapic_clockintr(void *arg, struct intrframe frame) +{ + + hardclock((struct clockframe *)&frame); +} + +void +lapic_initclocks() +{ + /* + * Start local apic countdown timer running, in repeated mode. + * + * Mask the clock interrupt and set mode, + * then set divisor, + * then unmask and set the vector. + */ + i82489_writereg (LAPIC_LVTT, LAPIC_LVTT_TM|LAPIC_LVTT_M); + i82489_writereg (LAPIC_DCR_TIMER, LAPIC_DCRT_DIV1); + i82489_writereg (LAPIC_ICR_TIMER, lapic_tval); + i82489_writereg (LAPIC_LVTT, LAPIC_LVTT_TM|LAPIC_TIMER_VECTOR); +} + +extern int gettick(void); /* XXX put in header file */ +extern u_long rtclock_tval; /* XXX put in header file */ +extern void (*initclock_func)(void); /* XXX put in header file */ + +/* + * Calibrate the local apic count-down timer (which is running at + * bus-clock speed) vs. the i8254 counter/timer (which is running at + * a fixed rate). + * + * The Intel MP spec says: "An MP operating system may use the IRQ8 + * real-time clock as a reference to determine the actual APIC timer clock + * speed." + * + * We're actually using the IRQ0 timer. Hmm. + */ +void +lapic_calibrate_timer(ci) + struct cpu_info *ci; +{ + unsigned int starttick, tick1, tick2, endtick; + unsigned int startapic, apic1, apic2, endapic; + u_int64_t dtick, dapic, tmp; + int i; + + printf("%s: calibrating local timer\n", ci->ci_dev->dv_xname); + + /* + * Configure timer to one-shot, interrupt masked, + * large positive number. + */ + i82489_writereg (LAPIC_LVTT, LAPIC_LVTT_M); + i82489_writereg (LAPIC_DCR_TIMER, LAPIC_DCRT_DIV1); + i82489_writereg (LAPIC_ICR_TIMER, 0x80000000); + + starttick = gettick(); + startapic = lapic_gettick(); + + for (i=0; i<hz; i++) { + DELAY(2); + do { + tick1 = gettick(); + apic1 = lapic_gettick(); + } while (tick1 < starttick); + DELAY(2); + do { + tick2 = gettick(); + apic2 = lapic_gettick(); + } while (tick2 > starttick); + } + + endtick = gettick(); + endapic = lapic_gettick(); + + dtick = hz * rtclock_tval + (starttick-endtick); + dapic = startapic-endapic; + + /* + * there are TIMER_FREQ ticks per second. + * in dtick ticks, there are dapic bus clocks. + */ + tmp = (TIMER_FREQ * dapic) / dtick; + + lapic_per_second = tmp; + + printf("%s: apic clock running at %lldHz\n", ci->ci_dev->dv_xname, tmp); + + if (lapic_per_second != 0) { + /* + * reprogram the apic timer to run in periodic mode. + * XXX need to program timer on other cpu's, too. + */ + lapic_tval = (lapic_per_second * 2) / hz; + lapic_tval = (lapic_tval / 2) + (lapic_tval & 0x1); + + i82489_writereg (LAPIC_LVTT, LAPIC_LVTT_TM|LAPIC_LVTT_M + |LAPIC_TIMER_VECTOR); + i82489_writereg (LAPIC_DCR_TIMER, LAPIC_DCRT_DIV1); + i82489_writereg (LAPIC_ICR_TIMER, lapic_tval); + + /* + * Compute fixed-point ratios between cycles and + * microseconds to avoid having to do any division + * in lapic_delay and lapic_microtime. + */ + + tmp = (1000000 * (u_int64_t)1<<32) / lapic_per_second; + lapic_frac_usec_per_cycle = tmp; + + tmp = (lapic_per_second * (u_int64_t)1<<32) / 1000000; + + lapic_frac_cycle_per_usec = tmp; + + /* + * Compute delay in cycles for likely short delays in usec. + */ + for (i=0; i<26; i++) + lapic_delaytab[i] = (lapic_frac_cycle_per_usec * i) >> + 32; + + /* + * Now that the timer's calibrated, use the apic timer routines + * for all our timing needs.. + */ + delay_func = lapic_delay; + initclock_func = lapic_initclocks; + } +} + +/* + * delay for N usec. + */ + +void +lapic_delay(usec) + int usec; +{ + int32_t tick, otick; + int64_t deltat; /* XXX may want to be 64bit */ + + otick = lapic_gettick(); + + if (usec <= 0) + return; + if (usec <= 25) + deltat = lapic_delaytab[usec]; + else + deltat = (lapic_frac_cycle_per_usec * usec) >> 32; + + while (deltat > 0) { + tick = lapic_gettick(); + if (tick > otick) + deltat -= lapic_tval - (tick - otick); + else + deltat -= otick - tick; + otick = tick; + + x86_pause(); + } +} + +/* + * XXX the following belong mostly or partly elsewhere.. + */ + +int +x86_ipi_init(target) + int target; +{ + unsigned j; + + if ((target&LAPIC_DEST_MASK)==0) { + i82489_writereg(LAPIC_ICRHI, target<<LAPIC_ID_SHIFT); + } + + i82489_writereg(LAPIC_ICRLO, (target & LAPIC_DEST_MASK) | + LAPIC_DLMODE_INIT | LAPIC_LVL_ASSERT ); + + for (j=100000; j > 0; j--) + if ((i82489_readreg(LAPIC_ICRLO) & LAPIC_DLSTAT_BUSY) == 0) + break; + + delay(10000); + + i82489_writereg(LAPIC_ICRLO, (target & LAPIC_DEST_MASK) | + LAPIC_DLMODE_INIT | LAPIC_LVL_TRIG | LAPIC_LVL_DEASSERT); + + for (j=100000; j > 0; j--) + if ((i82489_readreg(LAPIC_ICRLO) & LAPIC_DLSTAT_BUSY) == 0) + break; + + return (i82489_readreg(LAPIC_ICRLO) & LAPIC_DLSTAT_BUSY)?EBUSY:0; +} + +int +x86_ipi(vec,target,dl) + int vec,target,dl; +{ + unsigned j; + int result; + + for (j=100000; + j > 0 && (i82489_readreg(LAPIC_ICRLO) & LAPIC_DLSTAT_BUSY); + j--) + ; + + if ((target & LAPIC_DEST_MASK) == 0) + i82489_writereg(LAPIC_ICRHI, target << LAPIC_ID_SHIFT); + + i82489_writereg(LAPIC_ICRLO, + (target & LAPIC_DEST_MASK) | vec | dl | LAPIC_LVL_ASSERT); + + for (j=100000; + j > 0 && (i82489_readreg(LAPIC_ICRLO) & LAPIC_DLSTAT_BUSY); + j--) + ; + + result = (i82489_readreg(LAPIC_ICRLO) & LAPIC_DLSTAT_BUSY) ? EBUSY : 0; + + return result; +} + + +/* + * Using 'pin numbers' as: + * 0 - timer + * 1 - unused + * 2 - PCINT + * 3 - LVINT0 + * 4 - LVINT1 + * 5 - LVERR + */ + +void +lapic_hwmask(struct pic *pic, int pin) +{ + int reg; + u_int32_t val; + + reg = LAPIC_LVTT + (pin << 4); + val = i82489_readreg(reg); + val |= LAPIC_LVT_MASKED; + i82489_writereg(reg, val); +} + +void +lapic_hwunmask(struct pic *pic, int pin) +{ + int reg; + u_int32_t val; + + reg = LAPIC_LVTT + (pin << 4); + val = i82489_readreg(reg); + val &= ~LAPIC_LVT_MASKED; + i82489_writereg(reg, val); +} + +void +lapic_setup(struct pic *pic, struct cpu_info *ci, int pin, int idtvec, int type) +{ +} diff --git a/sys/arch/amd64/amd64/locore.S b/sys/arch/amd64/amd64/locore.S index a32e5de4edb..5270eb9df22 100644 --- a/sys/arch/amd64/amd64/locore.S +++ b/sys/arch/amd64/amd64/locore.S @@ -1,5 +1,4 @@ -/* $OpenBSD: locore.S,v 1.13 2004/06/22 01:16:50 art Exp $ */ -/* $NetBSD: locore.S,v 1.2 2003/04/26 19:34:45 fvdl Exp $ */ +/* $NetBSD: locore.S,v 1.13 2004/03/25 18:33:17 drochner Exp $ */ /* * Copyright-o-rama! @@ -92,11 +91,7 @@ * 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 the University of - * California, Berkeley and its contributors. - * 4. Neither the name of the University nor the names of its contributors + * 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. * @@ -184,7 +179,6 @@ _C_LABEL(lapic_isr): .globl _C_LABEL(proc0paddr),_C_LABEL(PTDpaddr) .globl _C_LABEL(biosbasemem),_C_LABEL(biosextmem) .globl _C_LABEL(bootapiver) - .globl _C_LABEL(gdtstore) _C_LABEL(cpu): .long 0 # are we 386, 386sx, or 486, # or Pentium, or.. _C_LABEL(cpu_id): .long 0 # saved from `cpuid' instruction @@ -544,7 +538,7 @@ compat: movl $RELOC(farjmp64),%eax ljmp *(%eax) - .code64 +.code64 longmode: /* * 6. @@ -583,7 +577,7 @@ longmode_hi: movq $NKL4_KIMG_ENTRIES,%rcx leaq (PROC0_PML4_OFF)(%rsi),%rbx # old, phys address of PML4 - addq %r8, %rbx # new, virtual adress of PML4 + addq %r8, %rbx # new, virtual address of PML4 1: movq $0,(%rbx) addq $8,%rbx loop 1b @@ -721,38 +715,7 @@ NENTRY(switch_error3) #endif /* DIAGNOSTIC */ /* - * When no processes are on the runq, cpu_switch() branches to here to wait for - * something to come ready. - */ -ENTRY(idle) -#if defined(MULTIPROCESSOR) || defined(LOCKDEBUG) - call _C_LABEL(sched_unlock_idle) -#endif - jmp idle_start -idle_zero: - sti - call _C_LABEL(uvm_pageidlezero) - jmp idle_start -idle_loop: - /* Try to zero some pages. */ - movl _C_LABEL(uvm)+UVM_PAGE_IDLE_ZERO(%rip),%ecx - testl %ecx,%ecx - jnz idle_zero - sti - hlt -NENTRY(mpidle) -idle_start: - cli - movl _C_LABEL(whichqs)(%rip),%ecx - testl %ecx, %ecx - jz idle_loop -#if defined(MULTIPROCESSOR) || defined(LOCKDEBUG) - call _C_LABEL(sched_lock_idle) -#endif - jmp sw1 - -/* - * void cpu_switch(struct proc *) + * int cpu_switch(struct proc *) * Find a runnable process and switch to it. Wait if necessary. If the new * proc is the same as the old one, we short-circuit the context save and * restore. @@ -764,8 +727,6 @@ ENTRY(cpu_switch) pushq %r13 pushq %r14 pushq %r15 - movl CPUVAR(ILEVEL), %ebx - pushq %rbx movq %rdi,%r13 @@ -776,10 +737,8 @@ ENTRY(cpu_switch) * below and changes the priority. (See corresponding comment in * userret()). */ - movq $0, CPUVAR(CURPROC) + movq $0,CPUVAR(CURPROC) - movl $IPL_NONE, %edi - call _C_LABEL(Xspllower) /* * First phase: find new proc. @@ -793,15 +752,111 @@ ENTRY(cpu_switch) * %r12 - new proc */ -switch_search: /* Look for new proc. */ cli # splhigh doesn't do a cli movl _C_LABEL(whichqs)(%rip),%ecx + bsfl %ecx,%r8d # find a full q + jnz switch_dequeue -sw1: bsfl %ecx,%r8d # find a full q - jz _C_LABEL(idle) + /* + * idling: save old context + * + * Registers: + * %rax, %rcx - scratch + * %r13 - old proc, then old pcb + * %r12 - idle pcb + */ + + /* old proc still in %rdi */ + call _C_LABEL(pmap_deactivate) + + movq P_ADDR(%r13),%r13 + + /* Save stack pointers */ + + movq %rsp,PCB_RSP(%r13) + movq %rbp,PCB_RBP(%r13) + + /* Find idle PCB for this CPU */ +#ifndef MULTIPROCESSOR + leaq _C_LABEL(proc0)(%rip),%rcx + movq P_ADDR(%rcx),%r12 + movl P_MD_TSS_SEL(%rcx),%edx +#else + movq CPUVAR(IDLE_PCB),%r12 + movl CPUVAR(IDLE_TSS_SEL),%edx +#endif + movq $0,CPUVAR(CURPROC) + + /* Restore the idle context (avoid interrupts) */ + cli + + /* Restore stack pointers. */ + movq PCB_RSP(%r12),%rsp + movq PCB_RBP(%r12),%rbp + + /* Switch address space. */ + movq PCB_CR3(%r12),%rcx + movq %rcx,%cr3 + +#ifdef MULTIPROCESSOR + movq CPUVAR(GDT),%rax +#else + movq _C_LABEL(gdtstore)(%rip),%rax +#endif + + /* Switch TSS. Reset "task busy" flag before */ + andl $~0x0200,4(%rax,%rdx, 1) + ltr %dx + + /* Restore cr0 (including FPU state). */ + movl PCB_CR0(%r12),%ecx + movq %rcx,%cr0 + + SET_CURPCB(%r12) + + xorq %r13,%r13 + sti +idle_unlock: +#if defined(MULTIPROCESSOR) || defined(LOCKDEBUG) + call _C_LABEL(sched_unlock_idle) +#endif + /* Interrupts are okay again. */ + movl $IPL_NONE,%edi + call _C_LABEL(Xspllower) + jmp idle_start +idle_zero: + sti + call _C_LABEL(uvm_pageidlezero) + cli + cmpl $0,_C_LABEL(whichqs)(%rip) + jnz idle_exit +idle_loop: + /* Try to zero some pages. */ + movl _C_LABEL(uvm)+UVM_PAGE_IDLE_ZERO(%rip),%ecx + testl %ecx,%ecx + jnz idle_zero + sti + hlt +NENTRY(mpidle) +idle_start: + cli + cmpl $0,_C_LABEL(whichqs)(%rip) + jz idle_loop +idle_exit: + movl $IPL_HIGH,CPUVAR(ILEVEL) + sti +#if defined(MULTIPROCESSOR) || defined(LOCKDEBUG) + call _C_LABEL(sched_lock_idle) +#endif +switch_search: + movl _C_LABEL(whichqs)(%rip),%ecx + bsfl %ecx,%r8d + jz idle_unlock switch_dequeue: + + sti movq %r8,%r9 shlq $4, %r9 @@ -842,10 +897,8 @@ switch_resume: movb $SONPROC,P_STAT(%r12) # p->p_stat = SONPROC SET_CURPROC(%r12,%rcx) - sti - /* Skip context switch if same proc. */ - movl $1,%eax + xorl %ebx,%ebx cmpq %r12,%r13 je switch_return @@ -862,6 +915,9 @@ switch_resume: * %r12 - new proc */ + movq %r13,%rdi + call pmap_deactivate + movq P_ADDR(%r13),%r13 /* Save stack pointers. */ @@ -900,16 +956,13 @@ switch_exited: #endif movl P_MD_TSS_SEL(%r12),%edx - /* Switch address space. */ - movq PCB_CR3(%r13),%rcx - movq %rcx,%cr3 - /* Switch TSS. Reset "task busy" flag before */ andl $~0x0200,4(%rax,%rdx, 1) ltr %dx - movq PCB_LDT_SEL(%r13),%rcx - lldt %cx + movq %r12,%rdi + call _C_LABEL(pmap_activate) + #if 0 switch_restored: #endif @@ -933,12 +986,12 @@ switch_return: #if defined(MULTIPROCESSOR) || defined(LOCKDEBUG) call _C_LABEL(sched_unlock_idle) #endif - /* - * Restore old cpl from stack. Note that this is always an increase, - * due to the spl0() on entry. - */ - popq %rbx - movl %ebx, CPUVAR(ILEVEL) + + movl $IPL_NONE,%edi + call _C_LABEL(Xspllower) + movl $IPL_HIGH,CPUVAR(ILEVEL) + + movl %ebx,%eax popq %r15 popq %r14 @@ -1027,7 +1080,7 @@ ENTRY(switch_exit) call *%rsi /* Jump into cpu_switch() with the right state. */ - xorq %r13, %r13 + xorq %r13,%r13 movq %r13, CPUVAR(CURPROC) jmp switch_search @@ -1083,6 +1136,7 @@ IDTVEC(syscall) movq CPUVAR(CURPROC),%r14 movq %rsp,P_MD_REGS(%r14) # save pointer to frame andl $~MDP_IRET,P_MD_FLAGS(%r14) + movq %rsp,%rdi call _C_LABEL(syscall) 1: /* Check for ASTs on exit to user mode. */ cli @@ -1092,6 +1146,7 @@ IDTVEC(syscall) CLEAR_ASTPENDING(%r11) sti /* Pushed T_ASTFLT into tf_trapno on entry. */ + movq %rsp,%rdi call _C_LABEL(trap) jmp 1b 2: @@ -1100,8 +1155,7 @@ IDTVEC(syscall) jne iret_return; syscall_return: #ifdef DIAGNOSTIC - movl CPUVAR(ILEVEL), %r8d - testl %r8d, %r8d + cmpl $IPL_NONE,CPUVAR(ILEVEL) jne 3f #endif /* @@ -1109,15 +1163,17 @@ syscall_return: */ cli swapgs - movw TF_GS(%rsp),%gs - movw TF_FS(%rsp),%fs movw TF_ES(%rsp),%es + movw TF_FS(%rsp),%fs + movw TF_GS(%rsp),%gs INTR_RESTORE_GPRS + movw $(LSEL(LUDATA_SEL, SEL_UPL)),%r11 + movw %r11,%ds addq $48,%rsp popq %rcx /* return rip */ addq $8,%rsp popq %r11 /* flags as set by sysret insn */ - movq (%rsp),%rsp + movq %ss:(%rsp),%rsp sysretq #ifdef DIAGNOSTIC @@ -1125,6 +1181,7 @@ syscall_return: movl TF_RAX(%rsp),%esi movl TF_RDI(%rsp),%edx movl %ebx,%ecx + movl CPUVAR(ILEVEL),%r8d xorq %rax,%rax call _C_LABEL(printf) #ifdef DDB @@ -1157,8 +1214,10 @@ NENTRY(child_trampoline) .globl _C_LABEL(osyscall_return) +/* XXX - can we zap the following two? */ + /* - * Old call gate entry for syscall. XXXfvdl: only needed if we're + * Old call gate entry for syscall. only needed if we're * going to support running old NetBSD or ibcs2 binaries, etc, * on NetBSD/amd64. */ @@ -1180,6 +1239,7 @@ osyscall1: sti movq CPUVAR(CURPROC),%rdx movq %rsp,P_MD_REGS(%rdx) # save pointer to frame + movq %rsp,%rdi call _C_LABEL(syscall) _C_LABEL(osyscall_return): 2: /* Check for ASTs on exit to user mode. */ @@ -1190,8 +1250,10 @@ _C_LABEL(osyscall_return): CLEAR_ASTPENDING(%r11) sti /* Pushed T_ASTFLT into tf_trapno on entry. */ + movq %rsp,%rdi call _C_LABEL(trap) jmp 2b + iret_return: #ifndef DIAGNOSTIC 1: INTRFASTEXIT diff --git a/sys/arch/amd64/amd64/machdep.c b/sys/arch/amd64/amd64/machdep.c index 7516289ac0b..e0caab7883e 100644 --- a/sys/arch/amd64/amd64/machdep.c +++ b/sys/arch/amd64/amd64/machdep.c @@ -1,4 +1,4 @@ -/* $OpenBSD: machdep.c,v 1.25 2004/06/22 01:16:50 art Exp $ */ +/* $OpenBSD: machdep.c,v 1.26 2004/06/25 11:03:27 art Exp $ */ /* $NetBSD: machdep.c,v 1.3 2003/05/07 22:58:18 fvdl Exp $ */ /*- @@ -201,6 +201,10 @@ pid_t sigpid = 0; extern paddr_t avail_start, avail_end; +void (*delay_func)(int) = i8254_delay; +void (*microtime_func)(struct timeval *) = i8254_microtime; +void (*initclock_func)(void) = i8254_initclocks; + struct mtrr_funcs *mtrr_funcs; /* @@ -1793,33 +1797,11 @@ cpu_dump_mempagecnt() return (n); } -#if 0 -extern void i8254_microtime(struct timeval *tv); - -/* - * XXXXXXX - * the simulator's 8254 seems to travel backward in time sometimes? - * work around this with this hideous code. Unacceptable for - * real hardware, but this is just a patch to stop the weird - * effects. SMP unsafe, etc. - */ void -microtime(struct timeval *tv) +cpu_initclocks(void) { - static struct timeval mtv; - - i8254_microtime(tv); - if (tv->tv_sec <= mtv.tv_sec && tv->tv_usec < mtv.tv_usec) { - mtv.tv_usec++; - if (mtv.tv_usec > 1000000) { - mtv.tv_sec++; - mtv.tv_usec = 0; - } - *tv = mtv; - } else - mtv = *tv; + (*initclock_func)(); } -#endif void need_resched(struct cpu_info *ci) diff --git a/sys/arch/amd64/amd64/microtime.S b/sys/arch/amd64/amd64/microtime.S index ce3c24f01e6..4e245266772 100644 --- a/sys/arch/amd64/amd64/microtime.S +++ b/sys/arch/amd64/amd64/microtime.S @@ -1,4 +1,4 @@ -/* $OpenBSD: microtime.S,v 1.3 2004/03/22 19:43:29 nordin Exp $ */ +/* $OpenBSD: microtime.S,v 1.4 2004/06/25 11:03:27 art Exp $ */ /* $NetBSD: microtime.S,v 1.1 2003/04/26 18:39:30 fvdl Exp $ */ /*- @@ -43,7 +43,7 @@ #define IRQ_BIT(irq_num) (1 << ((irq_num) & 7)) #define IRQ_BYTE(irq_num) ((irq_num) >> 3) -ENTRY(microtime) +ENTRY(i8254_microtime) # clear registers and do whatever we can up front xorl %edx,%edx movl $(TIMER_SEL0|TIMER_LATCH),%eax diff --git a/sys/arch/amd64/amd64/mpbios.c b/sys/arch/amd64/amd64/mpbios.c new file mode 100644 index 00000000000..e9b8cd67f86 --- /dev/null +++ b/sys/arch/amd64/amd64/mpbios.c @@ -0,0 +1,1108 @@ +/* $OpenBSD: mpbios.c,v 1.1 2004/06/25 11:03:27 art Exp $ */ +/* $NetBSD: mpbios.c,v 1.7 2003/05/15 16:32:50 fvdl Exp $ */ + +/*- + * Copyright (c) 2000 The NetBSD Foundation, Inc. + * All rights reserved. + * + * This code is derived from software contributed to The NetBSD Foundation + * by RedBack Networks Inc. + * + * Author: Bill Sommerfeld + * + * 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 the NetBSD + * Foundation, Inc. and its contributors. + * 4. Neither the name of The NetBSD Foundation 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 NETBSD FOUNDATION, INC. 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 FOUNDATION 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. + */ + +/* + * Copyright (c) 1999 Stefan Grefen + * + * 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 the NetBSD + * Foundation, Inc. and its contributors. + * 4. Neither the name of The NetBSD Foundation 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 AUTHOR 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 AUTHOR AND 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. + */ +/* + * Derived from FreeBSD's mp_machdep.c + */ +/* + * Copyright (c) 1996, by Steve Passe + * 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. The name of the developer 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 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 AUTHOR 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. + */ + +/* + * The Intel MP-stuff is just one way of x86 SMP systems + * so only Intel MP specific stuff is here. + */ + +#include <sys/param.h> +#include <sys/systm.h> +#include <sys/kernel.h> +#include <sys/device.h> +#include <sys/malloc.h> + +#include <uvm/uvm_extern.h> + +#include <machine/specialreg.h> +#include <machine/cpuvar.h> +#include <machine/bus.h> +#include <machine/mpbiosvar.h> + +#include <machine/i82093reg.h> +#include <machine/i82093var.h> +#include <machine/i82489reg.h> +#include <machine/i82489var.h> + +#include <dev/isa/isareg.h> + +#ifdef X86_MPBIOS_SUPPORT_EISA +#include <dev/eisa/eisavar.h> /* for ELCR* def'ns */ +#endif + + +static struct mpbios_ioapic default_ioapic = { + 2, 0, 1, IOAPICENTRY_FLAG_EN, (u_int32_t)IOAPIC_BASE_DEFAULT +}; + +/* descriptions of MP basetable entries */ +struct mpbios_baseentry { + u_int8_t type; + u_int8_t length; + u_int16_t count; + const char *name; +}; + +static const char *loc_where[] = { + "extended bios data area", + "last page of base memory", + "bios" +}; + +struct mp_map +{ + vaddr_t baseva; + int vsize; + paddr_t pa; + paddr_t pg; + int psize; +}; + +int mp_print(void *, const char *); +int mp_match(struct device *, void *,void *); +const void *mpbios_search(struct device *, paddr_t, int, struct mp_map *); +static __inline int mpbios_cksum(const void *,int); + +void mp_cfg_special_intr(const struct mpbios_int *, u_int32_t *); +void mp_print_special_intr(int intr); + +void mp_cfg_pci_intr(const struct mpbios_int *, u_int32_t *); +void mp_print_pci_intr(int intr); + +#ifdef X86_MPBIOS_SUPPORT_EISA +void mp_print_eisa_intr(int intr); +void mp_cfg_eisa_intr(const struct mpbios_int *, u_int32_t *); +#endif + +void mp_cfg_isa_intr(const struct mpbios_int *, u_int32_t *); +void mp_print_isa_intr (int intr); + +void mpbios_cpu(const u_int8_t *, struct device *); +void mpbios_bus(const u_int8_t *, struct device *); +void mpbios_ioapic(const u_int8_t *, struct device *); +void mpbios_int(const u_int8_t *, int, struct mp_intr_map *); + +const void *mpbios_map(paddr_t, int, struct mp_map *); +void mpbios_unmap(struct mp_map *); + +/* + * globals to help us bounce our way through parsing the config table. + */ + +static struct mp_map mp_cfg_table_map; +static struct mp_map mp_fp_map; +const struct mpbios_cth *mp_cth; +const struct mpbios_fps *mp_fps; + +int mpbios_scanned; + +int +mp_print(aux, pnp) + void *aux; + const char *pnp; +{ + struct cpu_attach_args * caa = (struct cpu_attach_args *) aux; + if (pnp) + printf("%s at %s:",caa->caa_name, pnp); + return (UNCONF); +} + +int +mp_match(parent, cfv, aux) + struct device *parent; + void *cfv; + void *aux; +{ + struct cfdata *cf = (struct cfdata *)cfv; + struct cpu_attach_args * caa = (struct cpu_attach_args *) aux; + if (strcmp(caa->caa_name, cf->cf_driver->cd_name)) + return 0; + + return ((*cf->cf_attach->ca_match)(parent, cf, aux)); +} + +/* + * Map a chunk of memory read-only and return an appropraitely + * const'ed pointer. + */ + +const void * +mpbios_map(pa, len, handle) + paddr_t pa; + int len; + struct mp_map *handle; +{ + paddr_t pgpa = x86_trunc_page(pa); + paddr_t endpa = x86_round_page(pa + len); + vaddr_t va = uvm_km_valloc(kernel_map, endpa - pgpa); + vaddr_t retva = va + (pa & PGOFSET); + + handle->pa = pa; + handle->pg = pgpa; + handle->psize = len; + handle->baseva = va; + handle->vsize = endpa-pgpa; + + do { + pmap_kenter_pa (va, pgpa, VM_PROT_READ); + va += PAGE_SIZE; + pgpa += PAGE_SIZE; + } while (pgpa < endpa); + + return (const void *)retva; +} + +void +mpbios_unmap(handle) + struct mp_map *handle; +{ + pmap_kremove (handle->baseva, handle->vsize); + uvm_km_free (kernel_map, handle->baseva, handle->vsize); +} + +/* + * Look for an Intel MP spec table, indicating SMP capable hardware. + */ +int +mpbios_probe(self) + struct device *self; +{ + paddr_t ebda, memtop; + + paddr_t cthpa; + int cthlen; + const u_int8_t *mpbios_page; + int scan_loc; + + struct mp_map t; + + /* see if EBDA exists */ + + mpbios_page = mpbios_map (0, PAGE_SIZE, &t); + + ebda = *(const u_int16_t *) (&mpbios_page[0x40e]); + ebda <<= 4; + + memtop = *(const u_int16_t *) (&mpbios_page[0x413]); + memtop <<= 10; + + mpbios_page = NULL; + mpbios_unmap(&t); + + scan_loc = 0; + + if (ebda && ebda < IOM_BEGIN ) { + mp_fps = mpbios_search(self, ebda, 1024, &mp_fp_map); + if (mp_fps != NULL) + goto found; + } + + scan_loc = 1; + + if (memtop && memtop <= IOM_BEGIN ) { + mp_fps = mpbios_search(self, memtop - 1024, 1024, &mp_fp_map); + if (mp_fps != NULL) + goto found; + } + + scan_loc = 2; + + mp_fps = mpbios_search(self, BIOS_BASE, BIOS_COUNT, &mp_fp_map); + if (mp_fps != NULL) + goto found; + + /* nothing found */ + return 0; + + found: + if (mp_verbose) + printf("%s: MP floating pointer found in %s at 0x%lx\n", + self->dv_xname, loc_where[scan_loc], mp_fp_map.pa); + + if (mp_fps->pap == 0) { + if (mp_fps->mpfb1 == 0) { + printf("%s: MP fps invalid: " + "no default config and no configuration table\n", + self->dv_xname); + + goto err; + } + printf("%s: MP default configuration %d\n", + self->dv_xname, mp_fps->mpfb1); + return 10; + } + + cthpa = mp_fps->pap; + + mp_cth = mpbios_map (cthpa, sizeof (*mp_cth), &mp_cfg_table_map); + cthlen = mp_cth->base_len; + mpbios_unmap(&mp_cfg_table_map); + + mp_cth = mpbios_map (cthpa, cthlen, &mp_cfg_table_map); + + if (mp_verbose) + printf("%s: MP config table at 0x%lx, %d bytes long\n", + self->dv_xname, cthpa, cthlen); + + if (mp_cth->signature != MP_CT_SIG) { + printf("%s: MP signature mismatch (%x vs %x)\n", + self->dv_xname, + MP_CT_SIG, mp_cth->signature); + goto err; + } + + if (mpbios_cksum(mp_cth, cthlen)) { + printf ("%s: MP Configuration Table checksum mismatch\n", + self->dv_xname); + goto err; + } + return 10; + err: + if (mp_fps) { + mp_fps = NULL; + mpbios_unmap(&mp_fp_map); + } + if (mp_cth) { + mp_cth = NULL; + mpbios_unmap(&mp_cfg_table_map); + } + return 0; +} + + +/* + * Simple byte checksum used on config tables. + */ + +static __inline int +mpbios_cksum (start, len) + const void *start; + int len; +{ + unsigned char res=0; + const char *p = start; + const char *end = p + len; + + while (p < end) + res += *p++; + + return res; +} + + +/* + * Look for the MP floating pointer signature in the given physical + * address range. + * + * We map the memory, scan through it, and unmap it. + * If we find it, remap the floating pointer structure and return it. + */ + +const void * +mpbios_search (self, start, count, map) + struct device *self; + paddr_t start; + int count; + struct mp_map *map; +{ + struct mp_map t; + + int i, len; + const struct mpbios_fps *m; + int end = count - sizeof(*m); + const u_int8_t *base = mpbios_map (start, count, &t); + + if (mp_verbose) + printf("%s: scanning 0x%lx to 0x%lx for MP signature\n", + self->dv_xname, start, start+count-sizeof(*m)); + + for (i = 0; i <= end; i += 4) { + m = (struct mpbios_fps *)&base[i]; + + if ((m->signature == MP_FP_SIG) && + ((len = m->length << 4) != 0) && + mpbios_cksum(m, (m->length << 4)) == 0) { + + mpbios_unmap (&t); + + return mpbios_map (start+i, len, map); + } + } + mpbios_unmap(&t); + + return 0; +} + +/* + * MP configuration table parsing. + */ + +static struct mpbios_baseentry mp_conf[] = +{ + {0, 20, 0, "cpu"}, + {1, 8, 0, "bus"}, + {2, 8, 0, "ioapic"}, + {3, 8, 0, "ioint"}, + {4, 8, 0, "lint"}, +}; + +static struct mp_bus extint_bus = { + "ExtINT", + -1, + mp_print_special_intr, + mp_cfg_special_intr, + 0 +}; +static struct mp_bus smi_bus = { + "SMI", + -1, + mp_print_special_intr, + mp_cfg_special_intr, + 0 +}; +static struct mp_bus nmi_bus = { + "NMI", + -1, + mp_print_special_intr, + mp_cfg_special_intr, + 0 +}; + + +/* + * 1st pass on BIOS's Intel MP specification table. + * + * initializes: + * mp_ncpus = 1 + * + * determines: + * cpu_apic_address (common to all CPUs) + * ioapic_address[N] + * mp_naps + * mp_nbusses + * mp_napics + * nintrs + */ +void +mpbios_scan(self) + struct device *self; +{ + const u_int8_t *position, *end; + int count; + int type; + int intr_cnt, cur_intr; + paddr_t lapic_base; + const struct mpbios_int *iep; + struct mpbios_int ie; + struct ioapic_softc *sc; + + printf ("%s: Intel MP Specification ", self->dv_xname); + + switch (mp_fps->spec_rev) { + case 1: + printf("(Version 1.1)"); + break; + case 4: + printf("(Version 1.4)"); + break; + default: + printf("(unrecognized rev %d)", mp_fps->spec_rev); + } + + /* + * looks like we've got a MP system. start setting up + * infrastructure.. + * XXX is this the right place?? + */ + + lapic_base = LAPIC_BASE; + if (mp_cth != NULL) + lapic_base = (paddr_t)mp_cth->apic_address; + + lapic_boot_init(lapic_base); + + /* check for use of 'default' configuration */ + if (mp_fps->mpfb1 != 0) { + struct mpbios_proc pe; + + printf("\n%s: MP default configuration %d\n", + self->dv_xname, mp_fps->mpfb1); + + /* use default addresses */ + pe.apic_id = lapic_cpu_number(); + pe.cpu_flags = PROCENTRY_FLAG_EN|PROCENTRY_FLAG_BP; + pe.cpu_signature = cpu_info_primary.ci_signature; + pe.feature_flags = cpu_info_primary.ci_feature_flags; + + mpbios_cpu((u_int8_t *)&pe, self); + + pe.apic_id = 1 - lapic_cpu_number(); + pe.cpu_flags = PROCENTRY_FLAG_EN; + + mpbios_cpu((u_int8_t *)&pe, self); + + mpbios_ioapic((u_int8_t *)&default_ioapic, self); + + /* XXX */ + printf("%s: WARNING: interrupts not configured\n", + self->dv_xname); + panic("lazy bum"); + return; + } else { + /* + * should not happen; mp_probe returns 0 in this case, + * but.. + */ + if (mp_cth == NULL) + panic ("mpbios_scan: no config (can't happen?)"); + + printf(" (%8.8s %12.12s)\n", + mp_cth->oem_id, mp_cth->product_id); + + /* + * Walk the table once, counting items + */ + position = (const u_int8_t *)(mp_cth); + end = position + mp_cth->base_len; + position += sizeof(*mp_cth); + + count = mp_cth->entry_count; + intr_cnt = 0; + + while ((count--) && (position < end)) { + type = *position; + if (type >= MPS_MCT_NTYPES) { + printf("%s: unknown entry type %x" + " in MP config table\n", + self->dv_xname, type); + break; + } + mp_conf[type].count++; + if (type == MPS_MCT_BUS) { + const struct mpbios_bus *bp = + (const struct mpbios_bus *)position; + if (bp->bus_id >= mp_nbus) + mp_nbus = bp->bus_id + 1; + } + /* + * Count actual interrupt instances. + * dst_apic_id of MPS_ALL_APICS means "wired to all + * apics of this type". + */ + if (type == MPS_MCT_IOINT) { + iep = (const struct mpbios_int *)position; + if (iep->dst_apic_id == MPS_ALL_APICS) + intr_cnt += + mp_conf[MPS_MCT_IOAPIC].count; + else + intr_cnt++; + } else if (type == MPS_MCT_LINT) + intr_cnt++; + position += mp_conf[type].length; + } + + mp_busses = malloc(sizeof(struct mp_bus)*mp_nbus, + M_DEVBUF, M_NOWAIT); + memset(mp_busses, 0, sizeof(struct mp_bus) * mp_nbus); + mp_intrs = malloc(sizeof(struct mp_intr_map)*intr_cnt, + M_DEVBUF, M_NOWAIT); + mp_nintr = intr_cnt; + + /* re-walk the table, recording info of interest */ + position = (const u_int8_t *) mp_cth + sizeof(*mp_cth); + count = mp_cth->entry_count; + cur_intr = 0; + + while ((count--) && (position < end)) { + switch (type = *(u_char *) position) { + case MPS_MCT_CPU: + mpbios_cpu(position, self); + break; + case MPS_MCT_BUS: + mpbios_bus(position, self); + break; + case MPS_MCT_IOAPIC: + mpbios_ioapic(position, self); + break; + case MPS_MCT_IOINT: + iep = (const struct mpbios_int *)position; + ie = *iep; + if (iep->dst_apic_id == MPS_ALL_APICS) { + for (sc = ioapics ; sc != NULL; + sc = sc->sc_next) { + ie.dst_apic_id = sc->sc_apicid; + mpbios_int((char *)&ie, type, + &mp_intrs[cur_intr++]); } + } else { + mpbios_int(position, type, + &mp_intrs[cur_intr++]); + } + break; + case MPS_MCT_LINT: + mpbios_int(position, type, + &mp_intrs[cur_intr]); + cur_intr++; + break; + default: + printf("%s: unknown entry type %x in MP config table\n", + self->dv_xname, type); + /* NOTREACHED */ + return; + } + + (u_char*)position += mp_conf[type].length; + } + if (mp_verbose && mp_cth->ext_len) + printf("%s: MP WARNING: %d bytes of extended entries not examined\n", + self->dv_xname, + mp_cth->ext_len); + } + /* Clean up. */ + mp_fps = NULL; + mpbios_unmap (&mp_fp_map); + if (mp_cth != NULL) { + mp_cth = NULL; + mpbios_unmap (&mp_cfg_table_map); + } + mpbios_scanned = 1; +} + +void +mpbios_cpu(ent, self) + const u_int8_t *ent; + struct device *self; +{ + const struct mpbios_proc *entry = (const struct mpbios_proc *)ent; + struct cpu_attach_args caa; + + /* XXX move this into the CPU attachment goo. */ + /* check for usability */ + if (!(entry->cpu_flags & PROCENTRY_FLAG_EN)) + return; + + /* check for BSP flag */ + if (entry->cpu_flags & PROCENTRY_FLAG_BP) + caa.cpu_role = CPU_ROLE_BP; + else + caa.cpu_role = CPU_ROLE_AP; + + caa.caa_name = "cpu"; + caa.cpu_number = entry->apic_id; + caa.cpu_func = &mp_cpu_funcs; + + config_found_sm(self, &caa, mp_print, mp_match); +} + +/* + * The following functions conspire to compute base ioapic redirection + * table entry for a given interrupt line. + * + * Fill in: trigger mode, polarity, and possibly delivery mode. + */ +void mp_cfg_special_intr (entry, redir) + const struct mpbios_int *entry; + u_int32_t *redir; +{ + + /* + * All of these require edge triggered, zero vector, + * appropriate delivery mode. + * see page 13 of the 82093AA datasheet. + */ + *redir &= ~IOAPIC_REDLO_DEL_MASK; + *redir &= ~IOAPIC_REDLO_VECTOR_MASK; + *redir &= ~IOAPIC_REDLO_LEVEL; + + switch (entry->int_type) { + case MPS_INTTYPE_NMI: + *redir |= (IOAPIC_REDLO_DEL_NMI<<IOAPIC_REDLO_DEL_SHIFT); + break; + + case MPS_INTTYPE_SMI: + *redir |= (IOAPIC_REDLO_DEL_SMI<<IOAPIC_REDLO_DEL_SHIFT); + break; + case MPS_INTTYPE_ExtINT: + /* + * We are using the ioapic in "native" mode. + * This indicates where the 8259 is wired to the ioapic + * and/or local apic.. + */ + *redir |= (IOAPIC_REDLO_DEL_EXTINT<<IOAPIC_REDLO_DEL_SHIFT); + *redir |= (IOAPIC_REDLO_MASK); + break; + default: + panic("unknown MPS interrupt type %d", entry->int_type); + } +} + +/* XXX too much duplicated code here. */ + +void mp_cfg_pci_intr (entry, redir) + const struct mpbios_int *entry; + u_int32_t *redir; +{ + int mpspo = entry->int_flags & 0x03; /* XXX magic */ + int mpstrig = (entry->int_flags >> 2) & 0x03; /* XXX magic */ + + *redir &= ~IOAPIC_REDLO_DEL_MASK; + switch (mpspo) { + case MPS_INTPO_ACTHI: + *redir &= ~IOAPIC_REDLO_ACTLO; + break; + case MPS_INTPO_DEF: + case MPS_INTPO_ACTLO: + *redir |= IOAPIC_REDLO_ACTLO; + break; + default: + panic("unknown MPS interrupt polarity %d", mpspo); + } + + if (entry->int_type != MPS_INTTYPE_INT) { + mp_cfg_special_intr(entry, redir); + return; + } + *redir |= (IOAPIC_REDLO_DEL_LOPRI<<IOAPIC_REDLO_DEL_SHIFT); + + switch (mpstrig) { + case MPS_INTTR_DEF: + case MPS_INTTR_LEVEL: + *redir |= IOAPIC_REDLO_LEVEL; + break; + case MPS_INTTR_EDGE: + *redir &= ~IOAPIC_REDLO_LEVEL; + break; + default: + panic("unknown MPS interrupt trigger %d", mpstrig); + } +} + +#ifdef X86_MPBIOS_SUPPORT_EISA +void mp_cfg_eisa_intr (entry, redir) + const struct mpbios_int *entry; + u_int32_t *redir; +{ + int mpspo = entry->int_flags & 0x03; /* XXX magic */ + int mpstrig = (entry->int_flags >> 2) & 0x03; /* XXX magic */ + + *redir &= ~IOAPIC_REDLO_DEL_MASK; + switch (mpspo) { + case MPS_INTPO_DEF: + case MPS_INTPO_ACTHI: + *redir &= ~IOAPIC_REDLO_ACTLO; + break; + case MPS_INTPO_ACTLO: + *redir |= IOAPIC_REDLO_ACTLO; + break; + default: + panic("unknown MPS interrupt polarity %d", mpspo); + } + + if (entry->int_type != MPS_INTTYPE_INT) { + mp_cfg_special_intr(entry, redir); + return; + } + *redir |= (IOAPIC_REDLO_DEL_LOPRI<<IOAPIC_REDLO_DEL_SHIFT); + + switch (mpstrig) { + case MPS_INTTR_LEVEL: + *redir |= IOAPIC_REDLO_LEVEL; + break; + case MPS_INTTR_EDGE: + *redir &= ~IOAPIC_REDLO_LEVEL; + break; + case MPS_INTTR_DEF: + /* + * Set "default" setting based on ELCR value snagged + * earlier. + */ + if (mp_busses[entry->src_bus_id].mb_data & + (1<<entry->src_bus_irq)) { + *redir |= IOAPIC_REDLO_LEVEL; + } else { + *redir &= ~IOAPIC_REDLO_LEVEL; + } + break; + default: + panic("unknown MPS interrupt trigger %d", mpstrig); + } +} +#endif + + +void mp_cfg_isa_intr (entry, redir) + const struct mpbios_int *entry; + u_int32_t *redir; +{ + int mpspo = entry->int_flags & 0x03; /* XXX magic */ + int mpstrig = (entry->int_flags >> 2) & 0x03; /* XXX magic */ + + *redir &= ~IOAPIC_REDLO_DEL_MASK; + switch (mpspo) { + case MPS_INTPO_DEF: + case MPS_INTPO_ACTHI: + *redir &= ~IOAPIC_REDLO_ACTLO; + break; + case MPS_INTPO_ACTLO: + *redir |= IOAPIC_REDLO_ACTLO; + break; + default: + panic("unknown MPS interrupt polarity %d", mpspo); + } + + if (entry->int_type != MPS_INTTYPE_INT) { + mp_cfg_special_intr(entry, redir); + return; + } + *redir |= (IOAPIC_REDLO_DEL_LOPRI<<IOAPIC_REDLO_DEL_SHIFT); + + switch (mpstrig) { + case MPS_INTTR_LEVEL: + *redir |= IOAPIC_REDLO_LEVEL; + break; + case MPS_INTTR_DEF: + case MPS_INTTR_EDGE: + *redir &= ~IOAPIC_REDLO_LEVEL; + break; + default: + panic("unknown MPS interrupt trigger %d", mpstrig); + } +} + +void +mp_print_special_intr (intr) + int intr; +{ +} + +void +mp_print_pci_intr (intr) + int intr; +{ + printf(" device %d INT_%c", (intr>>2)&0x1f, 'A' + (intr & 0x3)); +} + +void +mp_print_isa_intr (intr) + int intr; +{ + printf(" irq %d", intr); +} + +#ifdef X86_MPBIOS_SUPPORT_EISA +void +mp_print_eisa_intr (intr) + int intr; +{ + printf(" EISA irq %d", intr); +} +#endif + + + +#define TAB_UNIT 4 +#define TAB_ROUND(a) _TAB_ROUND(a, TAB_UNIT) + +#define _TAB_ROUND(a,u) (((a) + (u - 1)) & ~(u-1)) +#define EXTEND_TAB(a,u) (!(_TAB_ROUND(a,u) == _TAB_ROUND((a+1),u))) + +void +mpbios_bus(ent, self) + const u_int8_t *ent; + struct device *self; +{ + const struct mpbios_bus *entry = (const struct mpbios_bus *)ent; + int bus_id = entry->bus_id; + + printf("mpbios: bus %d is type %6.6s\n", bus_id, entry->bus_type); + +#ifdef DIAGNOSTIC + /* + * This "should not happen" unless the table changes out + * from underneath us + */ + if (bus_id >= mp_nbus) { + panic("mpbios: bus number %d out of range?? (type %6.6s)\n", + bus_id, entry->bus_type); + } +#endif + + mp_busses[bus_id].mb_intrs = NULL; + + if (memcmp(entry->bus_type, "PCI ", 6) == 0) { + mp_busses[bus_id].mb_name = "pci"; + mp_busses[bus_id].mb_idx = bus_id; + mp_busses[bus_id].mb_intr_print = mp_print_pci_intr; + mp_busses[bus_id].mb_intr_cfg = mp_cfg_pci_intr; +#ifdef X86_MPBIOS_SUPPORT_EISA + } else if (memcmp(entry->bus_type, "EISA ", 6) == 0) { + mp_busses[bus_id].mb_name = "eisa"; + mp_busses[bus_id].mb_idx = bus_id; + mp_busses[bus_id].mb_intr_print = mp_print_eisa_intr; + mp_busses[bus_id].mb_intr_cfg = mp_cfg_eisa_intr; + + mp_busses[bus_id].mb_data = + inb(ELCR0) | (inb(ELCR1) << 8); + + if (mp_eisa_bus != -1) + printf("oops: multiple isa busses?\n"); + else + mp_eisa_bus = bus_id; +#endif + + } else if (memcmp(entry->bus_type, "ISA ", 6) == 0) { + mp_busses[bus_id].mb_name = "isa"; + mp_busses[bus_id].mb_idx = 0; /* XXX */ + mp_busses[bus_id].mb_intr_print = mp_print_isa_intr; + mp_busses[bus_id].mb_intr_cfg = mp_cfg_isa_intr; + if (mp_isa_bus != -1) + printf("oops: multiple isa busses?\n"); + else + mp_isa_bus = bus_id; + } else { + printf("%s: unsupported bus type %6.6s\n", self->dv_xname, + entry->bus_type); + } +} + + +void +mpbios_ioapic(ent, self) + const u_int8_t *ent; + struct device *self; +{ + const struct mpbios_ioapic *entry = (const struct mpbios_ioapic *)ent; + struct apic_attach_args aaa; + + /* XXX let flags checking happen in ioapic driver.. */ + if (!(entry->apic_flags & IOAPICENTRY_FLAG_EN)) + return; + + aaa.aaa_name = "ioapic"; + aaa.apic_id = entry->apic_id; + aaa.apic_version = entry->apic_version; + aaa.apic_address = (paddr_t)entry->apic_address; + aaa.apic_vecbase = -1; + aaa.flags = (mp_fps->mpfb2 & 0x80) ? IOAPIC_PICMODE : IOAPIC_VWIRE; + + config_found_sm(self, &aaa, mp_print, mp_match); +} + +static const char inttype_fmt[] = "\177\020" + "f\0\2type\0" "=\1NMI\0" "=\2SMI\0" "=\3ExtINT\0"; + +static const char flagtype_fmt[] = "\177\020" + "f\0\2pol\0" "=\1Act Hi\0" "=\3Act Lo\0" + "f\2\2trig\0" "=\1Edge\0" "=\3Level\0"; + +void +mpbios_int(ent, enttype, mpi) + const u_int8_t *ent; + int enttype; + struct mp_intr_map *mpi; +{ + const struct mpbios_int *entry = (const struct mpbios_int *)ent; + struct ioapic_softc *sc = NULL, *sc2; + + struct mp_intr_map *altmpi; + struct mp_bus *mpb; + + u_int32_t id = entry->dst_apic_id; + u_int32_t pin = entry->dst_apic_int; + u_int32_t bus = entry->src_bus_id; + u_int32_t dev = entry->src_bus_irq; + u_int32_t type = entry->int_type; + u_int32_t flags = entry->int_flags; + + switch (type) { + case MPS_INTTYPE_INT: + mpb = &(mp_busses[bus]); + break; + case MPS_INTTYPE_ExtINT: + mpb = &extint_bus; + break; + case MPS_INTTYPE_SMI: + mpb = &smi_bus; + break; + case MPS_INTTYPE_NMI: + mpb = &nmi_bus; + break; + } + mpi->next = mpb->mb_intrs; + mpb->mb_intrs = mpi; + mpi->bus = mpb; + mpi->bus_pin = dev; + mpi->global_int = -1; + + mpi->type = type; + mpi->flags = flags; + mpi->redir = 0; + if (mpb->mb_intr_cfg == NULL) { + printf("mpbios: can't find bus %d for apic %d pin %d\n", + bus, id, pin); + return; + } + + (*mpb->mb_intr_cfg)(entry, &mpi->redir); + + if (enttype == MPS_MCT_IOINT) { + sc = ioapic_find(id); + if (sc == NULL) { + printf("mpbios: can't find ioapic %d\n", id); + return; + } + + /* + * XXX workaround for broken BIOSs that put the ACPI + * global interrupt number in the entry, not the pin + * number. + */ + if (pin >= sc->sc_apic_sz) { + sc2 = ioapic_find_bybase(pin); + if (sc2 != sc) { + printf("mpbios: bad pin %d for apic %d\n", + pin, id); + return; + } + printf("mpbios: WARNING: pin %d for apic %d too high; " + "assuming ACPI global int value\n", pin, id); + pin -= sc->sc_apic_vecbase; + } + + mpi->ioapic = sc; + mpi->ioapic_pin = pin; + + altmpi = sc->sc_pins[pin].ip_map; + + if (altmpi != NULL) { + if ((altmpi->type != type) || + (altmpi->flags != flags)) { + printf("%s: conflicting map entries for pin %d\n", + sc->sc_pic.pic_dev.dv_xname, pin); + } + } else { + sc->sc_pins[pin].ip_map = mpi; + } + } else { + if (pin >= 2) + printf("pin %d of local apic doesn't exist!\n", pin); + else { + mpi->ioapic = NULL; + mpi->ioapic_pin = pin; + mpi->cpu_id = id; + } + } + + mpi->ioapic_ih = APIC_INT_VIA_APIC | + ((id<<APIC_INT_APIC_SHIFT) | ((pin<<APIC_INT_PIN_SHIFT))); + + if (mp_verbose) { + + printf("%s: int%d attached to %s", + sc ? sc->sc_pic.pic_dev.dv_xname : "local apic", + pin, mpb->mb_name); + + if (mpb->mb_idx != -1) + printf("%d", mpb->mb_idx); + + (*(mpb->mb_intr_print))(dev); + + printf(" (type 0x%x flags 0x%x)\n", type, flags); + } +} diff --git a/sys/arch/amd64/amd64/mptramp.S b/sys/arch/amd64/amd64/mptramp.S new file mode 100644 index 00000000000..22d6a60c7f1 --- /dev/null +++ b/sys/arch/amd64/amd64/mptramp.S @@ -0,0 +1,239 @@ +/* $OpenBSD: mptramp.S,v 1.1 2004/06/25 11:03:27 art Exp $ */ +/* $NetBSD: mptramp.S,v 1.1 2003/04/26 18:39:30 fvdl Exp $ */ + +/*- + * Copyright (c) 2000 The NetBSD Foundation, Inc. + * All rights reserved. + * + * This code is derived from software contributed to The NetBSD Foundation + * by RedBack Networks Inc. + * + * Author: Bill Sommerfeld + * + * 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 the NetBSD + * Foundation, Inc. and its contributors. + * 4. Neither the name of The NetBSD Foundation 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 NETBSD FOUNDATION, INC. 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 FOUNDATION 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. + */ + +/* + * Copyright (c) 1999 Stefan Grefen + * + * 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 the NetBSD + * Foundation, Inc. and its contributors. + * 4. Neither the name of The NetBSD Foundation 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 AUTHOR 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 AUTHOR AND 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. + */ +/* + * MP startup ... + * the stuff from cpu_spinup_trampoline to mp_startup + * is copied into the first 640 KB + * + * We startup the processors now when the kthreads become ready. + * The steps are: + * 1) Get the processors running kernel-code from a special + * page-table and stack page, do chip identification. + * 2) halt the processors waiting for them to be enabled + * by a idle-thread + */ + +#include "assym.h" +#include <machine/param.h> +#include <machine/asm.h> +#include <machine/specialreg.h> +#include <machine/segments.h> +#include <machine/mpbiosvar.h> +#include <machine/i82489reg.h> +#include <machine/gdt.h> + +#define _RELOC(x) ((x) - KERNBASE) +#define RELOC(x) _RELOC(_C_LABEL(x)) + +#define _TRMP_LABEL(a) a = . - _C_LABEL(cpu_spinup_trampoline) + MP_TRAMPOLINE + + .globl _C_LABEL(mpidle) + .global _C_LABEL(cpu_spinup_trampoline) + .global _C_LABEL(cpu_spinup_trampoline_end) + .global _C_LABEL(cpu_hatch) + .global _C_LABEL(local_apic) + .global _C_LABEL(mp_pdirpa) + + .global gdt64 + +#define HALT 1: jmp 1b + + .text + .align 4,0x0 + .code16 +_C_LABEL(cpu_spinup_trampoline): + cli + xorw %ax,%ax + movw %ax, %ds + movw %ax, %es + movw %ax, %ss + data32 addr32 lgdt (mptramp_gdt32_desc) # load flat descriptor table + movl %cr0, %eax # get cr0 + orl $0x1, %eax # enable protected mode + movl %eax, %cr0 # doit + ljmpl $0x8, $mp_startup + +_TRMP_LABEL(mp_startup) + .code32 + + movl $0x10, %eax # data segment + movw %ax, %ds + movw %ax, %ss + movw %ax, %es + movw %ax, %fs + movw %ax, %gs + + movl $ (MP_TRAMPOLINE+NBPG-16),%esp # bootstrap stack end, + # with scratch space.. + + /* First, reset the PSL. */ + pushl $PSL_MBO + popfl + + movl %cr4,%eax + orl $(CR4_PAE|CR4_OSFXSR|CR4_OSXMMEXCPT),%eax + movl %eax,%cr4 + + movl $MSR_EFER,%ecx + rdmsr + movl %edx, %edi # %edx is needed by wrmsr below + + # Check if we need to enable NXE + movl $0x80000001, %eax + cpuid + andl $CPUID_NXE, %edx + xorl %eax,%eax + testl %edx, %edx + jz 1f + orl $EFER_NXE, %eax +1: + orl $(EFER_LME|EFER_SCE), %eax + + movl %edi, %edx # Restore saved %edx + movl $MSR_EFER,%ecx + wrmsr + + movl $mp_tramp_pdirpa, %ecx + movl (%ecx), %ecx + movl %ecx,%cr3 # load ptd addr into mmu + + movl $GSEL(GDATA_SEL, SEL_KPL),%eax #switch to new segment + movl %eax,%ds + movl %eax,%es + movl %eax,%ss + + movl $mptramp_gdt64_desc,%eax + lgdt (%eax) + movl $mptramp_jmp64,%eax + + movl %cr0,%ecx # get control word + orl $(CR0_PE|CR0_PG|CR0_NE|CR0_TS|CR0_MP|CR0_WP),%ecx + movl %ecx, %cr0 + + ljmp *(%eax) + +_TRMP_LABEL(mptramp_jmp64) + .long mptramp_longmode + .word GSEL(GCODE_SEL, SEL_KPL) + +_TRMP_LABEL(mptramp_gdt32) + .quad 0x0000000000000000 + .quad 0x00cf9f000000ffff + .quad 0x00cf93000000ffff +_TRMP_LABEL(mptramp_gdt32_desc) + .word 0x17 + .long mptramp_gdt32 + +_TRMP_LABEL(mptramp_gdt64) + .quad 0x0000000000000000 + .quad 0x00af9a000000ffff + .quad 0x00cf92000000ffff +_TRMP_LABEL(mptramp_gdt64_desc) + .word 0x17 + .long mptramp_gdt64 + + .global mp_pdirpa +_TRMP_LABEL(mp_pdirpa) +_TRMP_LABEL(mp_tramp_pdirpa) + .long 0 + +_TRMP_LABEL(mptramp_longmode) + .code64 + movabsq $_C_LABEL(cpu_spinup_trampoline_end),%rax + jmp *%rax + + + +_C_LABEL(cpu_spinup_trampoline_end): #end of code copied to MP_TRAMPOLINE + movl _C_LABEL(local_apic)+LAPIC_ID,%ecx + shrl $LAPIC_ID_SHIFT,%ecx + movq _C_LABEL(cpu_info)(,%rcx,8),%rdi + + movq CPU_INFO_IDLE_PCB(%rdi),%rsi + + movq PCB_RSP(%rsi),%rsp + movq PCB_RBP(%rsi),%rbp + + movq CPU_INFO_GDT(%rdi),%rax + movw $(MAXGDTSIZ-1),-10(%rsp) + movq %rax,-8(%rsp) + lgdt -10(%rsp) + + /* Switch address space. */ + movq PCB_CR3(%rsi),%rax + movq %rax,%cr3 + movl PCB_CR0(%rsi),%eax + movq %rax,%cr0 + call _C_LABEL(cpu_hatch) + xorq %r13,%r13 + jmp _C_LABEL(mpidle) diff --git a/sys/arch/amd64/amd64/pmap.c b/sys/arch/amd64/amd64/pmap.c index 30c65946713..f1bb906ba88 100644 --- a/sys/arch/amd64/amd64/pmap.c +++ b/sys/arch/amd64/amd64/pmap.c @@ -1,4 +1,4 @@ -/* $OpenBSD: pmap.c,v 1.3 2004/02/23 08:32:36 mickey Exp $ */ +/* $OpenBSD: pmap.c,v 1.4 2004/06/25 11:03:27 art Exp $ */ /* $NetBSD: pmap.c,v 1.3 2003/05/08 18:13:13 thorpej Exp $ */ /* @@ -288,7 +288,7 @@ pd_entry_t *alternate_pdes[] = APDES_INITIALIZER; struct simplelock pvalloc_lock; struct simplelock pmaps_lock; -#if defined(MULTIPROCESSOR) || defined(LOCKDEBUG) +#if (defined(MULTIPROCESSOR) || defined(LOCKDEBUG)) && 0 struct lock pmap_main_lock; #define PMAP_MAP_TO_HEAD_LOCK() \ (void) spinlockmgr(&pmap_main_lock, LK_SHARED, NULL) @@ -345,7 +345,7 @@ struct pmap_tlb_shootdown_q { TAILQ_HEAD(, pmap_tlb_shootdown_job) pq_head; int pq_pte; /* aggregate PTE bits */ int pq_count; /* number of pending requests */ - struct simplelock pq_slock; /* spin lock on queue */ + struct SIMPLELOCK pq_slock; /* spin lock on queue */ int pq_flushg; /* pending flush global */ int pq_flushu; /* pending flush user */ } pmap_tlb_shootdown_q[X86_MAXPROCS]; @@ -358,7 +358,7 @@ struct pmap_tlb_shootdown_job *pmap_tlb_shootdown_job_get void pmap_tlb_shootdown_job_put(struct pmap_tlb_shootdown_q *, struct pmap_tlb_shootdown_job *); -struct simplelock pmap_tlb_shootdown_job_lock; +struct SIMPLELOCK pmap_tlb_shootdown_job_lock; union pmap_tlb_shootdown_job_al *pj_page, *pj_free; /* @@ -661,11 +661,11 @@ pmap_apte_flush(struct pmap *pmap) pq = &pmap_tlb_shootdown_q[ci->ci_cpuid]; s = splipi(); #ifdef MULTIPROCESSOR - __cpu_simple_lock(&pq->pq_slock); + SIMPLE_LOCK(&pq->pq_slock); #endif pq->pq_flushu++; #ifdef MULTIPROCESSOR - __cpu_simple_unlock(&pq->pq_slock); + SIMPLE_UNLOCK(&pq->pq_slock); #endif splx(s); x86_send_ipi(ci, X86_IPI_TLB); @@ -1089,7 +1089,7 @@ pmap_bootstrap(kva_start) * init the static-global locks and global lists. */ -#if defined(MULTIPROCESSOR) || defined(LOCKDEBUG) +#if (defined(MULTIPROCESSOR) || defined(LOCKDEBUG)) && 0 spinlockinit(&pmap_main_lock, "pmaplk", 0); #endif simple_lock_init(&pvalloc_lock); @@ -1109,11 +1109,11 @@ pmap_bootstrap(kva_start) * Initialize the TLB shootdown queues. */ - simple_lock_init(&pmap_tlb_shootdown_job_lock); + SIMPLE_LOCK_INIT(&pmap_tlb_shootdown_job_lock); for (i = 0; i < X86_MAXPROCS; i++) { TAILQ_INIT(&pmap_tlb_shootdown_q[i].pq_head); - simple_lock_init(&pmap_tlb_shootdown_q[i].pq_slock); + SIMPLE_LOCK_INIT(&pmap_tlb_shootdown_q[i].pq_slock); } /* @@ -3560,7 +3560,7 @@ pmap_tlb_shootnow(int32_t cpumask) while (self->ci_tlb_ipi_mask != 0) #ifdef DIAGNOSTIC - if (count++ > 10000000) + if (count++ > 1000000000) panic("TLB IPI rendezvous failed (mask %x)", self->ci_tlb_ipi_mask); #else @@ -3611,7 +3611,7 @@ pmap_tlb_shootdown(pmap, va, pte, cpumaskp) continue; pq = &pmap_tlb_shootdown_q[ci->ci_cpuid]; #if defined(MULTIPROCESSOR) - simple_lock(&pq->pq_slock); + SIMPLE_LOCK(&pq->pq_slock); #endif /* @@ -3622,7 +3622,7 @@ pmap_tlb_shootdown(pmap, va, pte, cpumaskp) if (pq->pq_flushg > 0 || (pq->pq_flushu > 0 && (pte & pmap_pg_g) == 0)) { #if defined(MULTIPROCESSOR) - simple_unlock(&pq->pq_slock); + SIMPLE_UNLOCK(&pq->pq_slock); #endif continue; } @@ -3656,7 +3656,7 @@ pmap_tlb_shootdown(pmap, va, pte, cpumaskp) if (ci == self && pq->pq_count < PMAP_TLB_MAXJOBS) { pmap_update_pg(va); #if defined(MULTIPROCESSOR) - simple_unlock(&pq->pq_slock); + SIMPLE_LOCK(&pq->pq_slock); #endif continue; } else { @@ -3680,7 +3680,7 @@ pmap_tlb_shootdown(pmap, va, pte, cpumaskp) *cpumaskp |= 1U << ci->ci_cpuid; } #if defined(MULTIPROCESSOR) - simple_unlock(&pq->pq_slock); + SIMPLE_UNLOCK(&pq->pq_slock); #endif } splx(s); @@ -3706,7 +3706,7 @@ pmap_do_tlb_shootdown(struct cpu_info *self) s = splipi(); #ifdef MULTIPROCESSOR - simple_lock(&pq->pq_slock); + SIMPLE_LOCK(&pq->pq_slock); #endif if (pq->pq_flushg) { @@ -3741,7 +3741,7 @@ pmap_do_tlb_shootdown(struct cpu_info *self) for (CPU_INFO_FOREACH(cii, ci)) x86_atomic_clearbits_ul(&ci->ci_tlb_ipi_mask, (1U << cpu_id)); - simple_unlock(&pq->pq_slock); + SIMPLE_UNLOCK(&pq->pq_slock); #endif splx(s); @@ -3788,11 +3788,11 @@ pmap_tlb_shootdown_job_get(pq) return (NULL); #ifdef MULTIPROCESSOR - simple_lock(&pmap_tlb_shootdown_job_lock); + SIMPLE_LOCK(&pmap_tlb_shootdown_job_lock); #endif if (pj_free == NULL) { #ifdef MULTIPROCESSOR - simple_unlock(&pmap_tlb_shootdown_job_lock); + SIMPLE_UNLOCK(&pmap_tlb_shootdown_job_lock); #endif return NULL; } @@ -3800,7 +3800,7 @@ pmap_tlb_shootdown_job_get(pq) pj_free = (union pmap_tlb_shootdown_job_al *)pj_free->pja_job.pj_nextfree; #ifdef MULTIPROCESSOR - simple_unlock(&pmap_tlb_shootdown_job_lock); + SIMPLE_UNLOCK(&pmap_tlb_shootdown_job_lock); #endif pq->pq_count++; @@ -3825,12 +3825,12 @@ pmap_tlb_shootdown_job_put(pq, pj) panic("pmap_tlb_shootdown_job_put: queue length inconsistency"); #endif #ifdef MULTIPROCESSOR - simple_lock(&pmap_tlb_shootdown_job_lock); + SIMPLE_LOCK(&pmap_tlb_shootdown_job_lock); #endif pj->pj_nextfree = &pj_free->pja_job; pj_free = (union pmap_tlb_shootdown_job_al *)pj; #ifdef MULTIPROCESSOR - simple_unlock(&pmap_tlb_shootdown_job_lock); + SIMPLE_UNLOCK(&pmap_tlb_shootdown_job_lock); #endif pq->pq_count--; diff --git a/sys/arch/amd64/amd64/spl.S b/sys/arch/amd64/amd64/spl.S index c9b674ff648..7772f14205b 100644 --- a/sys/arch/amd64/amd64/spl.S +++ b/sys/arch/amd64/amd64/spl.S @@ -178,6 +178,7 @@ IDTVEC(doreti) sti movl $T_ASTFLT,TF_TRAPNO(%rsp) /* XXX undo later.. */ /* Pushed T_ASTFLT into tf_trapno on entry. */ + movq %rsp, %rdi call _C_LABEL(trap) cli jmp 5b diff --git a/sys/arch/amd64/amd64/vector.S b/sys/arch/amd64/amd64/vector.S index b2c3819dd2d..ddef85a0c43 100644 --- a/sys/arch/amd64/amd64/vector.S +++ b/sys/arch/amd64/amd64/vector.S @@ -1,4 +1,4 @@ -/* $OpenBSD: vector.S,v 1.1 2004/01/28 01:39:39 mickey Exp $ */ +/* $OpenBSD: vector.S,v 1.2 2004/06/25 11:03:27 art Exp $ */ /* $NetBSD: vector.S,v 1.2 2003/05/04 23:46:41 fvdl Exp $ */ /* @@ -223,6 +223,7 @@ calltrap: #ifdef DIAGNOSTIC movl CPUVAR(ILEVEL),%ebx #endif /* DIAGNOSTIC */ + movq %rsp, %rdi call _C_LABEL(trap) 2: /* Check for ASTs on exit to user mode. */ cli @@ -233,6 +234,7 @@ calltrap: 5: CLEAR_ASTPENDING(%r11) sti movl $T_ASTFLT,TF_TRAPNO(%rsp) + movq %rsp, %rdi call _C_LABEL(trap) jmp 2b #ifndef DIAGNOSTIC @@ -368,8 +370,8 @@ IDTVEC(intr_lapic_ltimer) #endif /* NLAPIC > 0 */ #ifdef MULTIPROCESSOR -#define LOCK_KERNEL call _C_LABEL(x86_intlock) -#define UNLOCK_KERNEL call _C_LABEL(x86_intunlock) +#define LOCK_KERNEL movq %rsp, %rdi; call _C_LABEL(x86_intlock) +#define UNLOCK_KERNEL movq %rsp, %rdi; call _C_LABEL(x86_intunlock) #else #define LOCK_KERNEL #define UNLOCK_KERNEL diff --git a/sys/arch/amd64/amd64/vm_machdep.c b/sys/arch/amd64/amd64/vm_machdep.c index 9e38904ac64..24f856f99d2 100644 --- a/sys/arch/amd64/amd64/vm_machdep.c +++ b/sys/arch/amd64/amd64/vm_machdep.c @@ -1,4 +1,4 @@ -/* $OpenBSD: vm_machdep.c,v 1.2 2004/05/13 20:20:24 sturm Exp $ */ +/* $OpenBSD: vm_machdep.c,v 1.3 2004/06/25 11:03:27 art Exp $ */ /* $NetBSD: vm_machdep.c,v 1.1 2003/04/26 18:39:33 fvdl Exp $ */ /*- @@ -144,7 +144,6 @@ cpu_fork(struct proc *p1, struct proc *p2, void *stack, size_t stacksize, tf->tf_rsp = (u_int64_t)stack + stacksize; sf = (struct switchframe *)tf - 1; - sf->sf_ppl = IPL_NONE; sf->sf_r12 = (u_int64_t)func; sf->sf_r13 = (u_int64_t)arg; if (func == child_return) diff --git a/sys/arch/amd64/compile/.cvsignore b/sys/arch/amd64/compile/.cvsignore index 0ff0325754e..4741f3d9201 100644 --- a/sys/arch/amd64/compile/.cvsignore +++ b/sys/arch/amd64/compile/.cvsignore @@ -1,3 +1,4 @@ GENERIC +GENERIC.MP RAMDISK RAMDISK_CD diff --git a/sys/arch/amd64/conf/GENERIC b/sys/arch/amd64/conf/GENERIC index 13182c94128..39f82697894 100644 --- a/sys/arch/amd64/conf/GENERIC +++ b/sys/arch/amd64/conf/GENERIC @@ -1,4 +1,4 @@ -# $OpenBSD: GENERIC,v 1.24 2004/06/06 04:50:57 pvalchev Exp $ +# $OpenBSD: GENERIC,v 1.25 2004/06/25 11:03:28 art Exp $ # # GENERIC -- everything that's currently supported # @@ -32,7 +32,7 @@ config bsd swap generic mainbus0 at root -cpu* at mainbus0 +cpu0 at mainbus? apid ? isa0 at mainbus0 #isa0 at pcib? pci* at mainbus0 bus ? diff --git a/sys/arch/amd64/conf/GENERIC.MP b/sys/arch/amd64/conf/GENERIC.MP new file mode 100644 index 00000000000..af4666420ca --- /dev/null +++ b/sys/arch/amd64/conf/GENERIC.MP @@ -0,0 +1,9 @@ +include "arch/amd64/conf/GENERIC" + +option MULTIPROCESSOR +option MPBIOS +option CPU + +cpu* at mainbus? apid ? +ioapic* at mainbus? apid ? +#aapic* at pci? dev ? function ? diff --git a/sys/arch/amd64/conf/RAMDISK b/sys/arch/amd64/conf/RAMDISK index b102eb0d808..73ee3071df9 100644 --- a/sys/arch/amd64/conf/RAMDISK +++ b/sys/arch/amd64/conf/RAMDISK @@ -1,4 +1,4 @@ -# $OpenBSD: RAMDISK,v 1.9 2004/06/06 04:50:57 pvalchev Exp $ +# $OpenBSD: RAMDISK,v 1.10 2004/06/25 11:03:28 art Exp $ machine amd64 # architecture, used by config; REQUIRED @@ -33,7 +33,7 @@ config bsd root on rd0a swap on rd0b and wd0b and sd0b mainbus0 at root -cpu* at mainbus0 +cpu* at mainbus0 apid ? isa0 at mainbus0 #isa0 at pcib? pci* at mainbus0 diff --git a/sys/arch/amd64/conf/RAMDISK_CD b/sys/arch/amd64/conf/RAMDISK_CD index 7c74b27a9a7..d41ff38451d 100644 --- a/sys/arch/amd64/conf/RAMDISK_CD +++ b/sys/arch/amd64/conf/RAMDISK_CD @@ -1,4 +1,4 @@ -# $OpenBSD: RAMDISK_CD,v 1.10 2004/06/06 04:50:57 pvalchev Exp $ +# $OpenBSD: RAMDISK_CD,v 1.11 2004/06/25 11:03:28 art Exp $ machine amd64 # architecture, used by config; REQUIRED @@ -33,7 +33,7 @@ config bsd root on rd0a swap on rd0b and wd0b and sd0b mainbus0 at root -cpu* at mainbus0 +cpu* at mainbus0 apid ? isa0 at mainbus0 #isa0 at pcib? pci* at mainbus0 diff --git a/sys/arch/amd64/conf/files.amd64 b/sys/arch/amd64/conf/files.amd64 index 9dcd8d58e06..b52a9083423 100644 --- a/sys/arch/amd64/conf/files.amd64 +++ b/sys/arch/amd64/conf/files.amd64 @@ -1,4 +1,4 @@ -# $OpenBSD: files.amd64,v 1.2 2004/02/25 00:16:41 deraadt Exp $ +# $OpenBSD: files.amd64,v 1.3 2004/06/25 11:03:28 art Exp $ maxpartitions 16 maxusers 2 16 128 @@ -26,6 +26,15 @@ file arch/amd64/amd64/intr.c file arch/amd64/amd64/bus_space.c file arch/amd64/amd64/bus_dma.c +file arch/amd64/amd64/mptramp.S multiprocessor +file arch/amd64/amd64/ipifuncs.c multiprocessor +file arch/amd64/amd64/ipi.c multiprocessor + +file arch/amd64/amd64/apic.c ioapic | lapic + +file arch/amd64/amd64/mpbios.c mpbios + + file arch/amd64/amd64/consinit.c file dev/cons.c file dev/cninit.c @@ -54,12 +63,12 @@ include "dev/i2o/files.i2o" include "dev/atapiscsi/files.atapiscsi" include "dev/ata/files.ata" -define mainbus { } +define mainbus { apid = -1 } device mainbus: isabus, pcibus, mainbus attach mainbus at root file arch/amd64/amd64/mainbus.c mainbus -define cpu { [apid = -1] } +define cpu { apid = -1 } device cpu attach cpu at mainbus file arch/amd64/amd64/cpu.c cpu diff --git a/sys/arch/amd64/include/cpu.h b/sys/arch/amd64/include/cpu.h index 4cd297e86b9..7c527d7d7cb 100644 --- a/sys/arch/amd64/include/cpu.h +++ b/sys/arch/amd64/include/cpu.h @@ -1,4 +1,4 @@ -/* $OpenBSD: cpu.h,v 1.8 2004/06/22 01:16:50 art Exp $ */ +/* $OpenBSD: cpu.h,v 1.9 2004/06/25 11:03:28 art Exp $ */ /* $NetBSD: cpu.h,v 1.1 2003/04/26 18:39:39 fvdl Exp $ */ /*- @@ -140,6 +140,8 @@ extern struct cpu_info *cpu_info_list; #define CPU_INFO_FOREACH(cii, ci) cii = 0, ci = cpu_info_list; \ ci != NULL; ci = ci->ci_next +#define CPU_INFO_UNIT(ci) ((ci)->ci_dev->dv_unit) + /* * Preempt the current process if in interrupt from user mode, * or after the current trap/syscall if in system mode. @@ -177,8 +179,6 @@ extern struct cpu_info cpu_info_primary; #endif -#include <machine/psl.h> - /* * definitions of cpu-dependent requirements * referenced in generic code @@ -188,6 +188,12 @@ extern struct cpu_info cpu_info_primary; #endif /* MULTIPROCESSOR */ +#include <machine/psl.h> + +#ifdef MULTIPROCESSOR +#include <sys/mplock.h> +#endif + #define aston(p) ((p)->p_md.md_astpending = 1) extern u_int32_t cpus_attached; @@ -223,11 +229,13 @@ extern u_int32_t cpus_attached; /* * We need a machine-independent name for this. */ -extern void delay(int); +extern void (*delay_func)(int); struct timeval; -extern void microtime(struct timeval *); +extern void (*microtime_func)(struct timeval *); -#define DELAY(x) delay(x) +#define DELAY(x) (*delay_func)(x) +#define delay(x) (*delay_func)(x) +#define microtime(tv) (*microtime_func)(tv) /* @@ -256,7 +264,6 @@ int cpu_amd64speed(int *); void cpu_probe_features(struct cpu_info *); /* machdep.c */ -void delay(int); void dumpconf(void); int cpu_maxproc(void); void cpu_reset(void); diff --git a/sys/arch/amd64/include/frame.h b/sys/arch/amd64/include/frame.h index d0fb538ceeb..7ab818494fa 100644 --- a/sys/arch/amd64/include/frame.h +++ b/sys/arch/amd64/include/frame.h @@ -1,4 +1,4 @@ -/* $OpenBSD: frame.h,v 1.1 2004/01/28 01:39:39 mickey Exp $ */ +/* $OpenBSD: frame.h,v 1.2 2004/06/25 11:03:28 art Exp $ */ /* $NetBSD: frame.h,v 1.1 2003/04/26 18:39:40 fvdl Exp $ */ /*- @@ -162,7 +162,6 @@ struct intrframe { * Stack frame inside cpu_switch() */ struct switchframe { - int64_t sf_ppl; int64_t sf_r15; int64_t sf_r14; int64_t sf_r13; diff --git a/sys/arch/amd64/include/i82093reg.h b/sys/arch/amd64/include/i82093reg.h index 91dc73bb1df..2259306db6a 100644 --- a/sys/arch/amd64/include/i82093reg.h +++ b/sys/arch/amd64/include/i82093reg.h @@ -1,4 +1,4 @@ -/* $OpenBSD: i82093reg.h,v 1.1 2004/01/28 01:39:39 mickey Exp $ */ +/* $OpenBSD: i82093reg.h,v 1.2 2004/06/25 11:03:28 art Exp $ */ /* $NetBSD: i82093reg.h,v 1.1 2003/02/26 21:26:10 fvdl Exp $ */ /*- @@ -119,3 +119,65 @@ #define IMCR_REGISTER 0x70 #define IMCR_PIC 0x00 #define IMCR_APIC 0x01 + +#ifdef _KERNEL + +#define ioapic_asm_ack(num) \ + movl $0,(_C_LABEL(local_apic)+LAPIC_EOI)(%rip) + +#ifdef MULTIPROCESSOR + +#ifdef notyet +#define ioapic_asm_lock(num) \ + movl $1,%esi ;\ +77: \ + xchgl %esi,PIC_LOCK(%rdi) ;\ + testl %esi,%esi ;\ + jne 77b + +#define ioapic_asm_unlock(num) \ + movl $0,PIC_LOCK(%rdi) +#else +#define ioapic_asm_lock(num) +#define ioapic_asm_unlock(num) +#endif + +#else + +#define ioapic_asm_lock(num) +#define ioapic_asm_unlock(num) + +#endif /* MULTIPROCESSOR */ + + +#define ioapic_mask(num) \ + movq IS_PIC(%r14),%rdi ;\ + ioapic_asm_lock(num) ;\ + movl IS_PIN(%r14),%esi ;\ + leaq 0x10(%rsi,%rsi,1),%rsi ;\ + movq IOAPIC_SC_REG(%rdi),%r15 ;\ + movl %esi, (%r15) ;\ + movq IOAPIC_SC_DATA(%rdi),%r15 ;\ + movl (%r15),%esi ;\ + orl $IOAPIC_REDLO_MASK,%esi ;\ + movl %esi,(%r15) ;\ + ioapic_asm_unlock(num) + +#define ioapic_unmask(num) \ + cmpq $IREENT_MAGIC,(TF_ERR+8)(%rsp) ;\ + jne 79f ;\ + movq IS_PIC(%r14),%rdi ;\ + ioapic_asm_lock(num) ;\ + movl IS_PIN(%r14),%esi ;\ + leaq 0x10(%rsi,%rsi,1),%rsi ;\ + movq IOAPIC_SC_REG(%rdi),%r15 ;\ + movq IOAPIC_SC_DATA(%rdi),%r13 ;\ + movl %esi, (%r15) ;\ + movl (%r13),%r12d ;\ + andl $~IOAPIC_REDLO_MASK,%r12d ;\ + movl %esi,(%r15) ;\ + movl %r12d,(%r13) ;\ + ioapic_asm_unlock(num) ;\ +79: + +#endif diff --git a/sys/arch/amd64/include/i82489var.h b/sys/arch/amd64/include/i82489var.h new file mode 100644 index 00000000000..22fdcb2edc5 --- /dev/null +++ b/sys/arch/amd64/include/i82489var.h @@ -0,0 +1,122 @@ +/* $NetBSD: i82489var.h,v 1.1 2003/02/26 21:26:10 fvdl Exp $ */ + +/*- + * Copyright (c) 1998 The NetBSD Foundation, Inc. + * All rights reserved. + * + * This code is derived from software contributed to The NetBSD Foundation + * by Frank van der Linden. + * + * 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 the NetBSD + * Foundation, Inc. and its contributors. + * 4. Neither the name of The NetBSD Foundation 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 NETBSD FOUNDATION, INC. 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 FOUNDATION 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. + */ + +#ifndef _X86_I82489REG_H_ +#define _X86_I82489REG_H_ + +/* + * Software definitions belonging to Local APIC driver. + */ + +static __inline__ u_int32_t i82489_readreg __P((int)); +static __inline__ void i82489_writereg __P((int, u_int32_t)); + +#ifdef _KERNEL +extern volatile u_int32_t local_apic[]; +extern volatile u_int32_t lapic_tpr; +#endif + +static __inline__ u_int32_t +i82489_readreg(reg) + int reg; +{ + return *((volatile u_int32_t *)(((volatile u_int8_t *)local_apic) + + reg)); +} + +static __inline__ void +i82489_writereg(reg, val) + int reg; + u_int32_t val; +{ + *((volatile u_int32_t *)(((volatile u_int8_t *)local_apic) + reg)) = val; +} + +#define lapic_cpu_number() (i82489_readreg(LAPIC_ID)>>LAPIC_ID_SHIFT) + +/* + * "spurious interrupt vector"; vector used by interrupt which was + * aborted because the CPU masked it after it happened but before it + * was delivered.. "Oh, sorry, i caught you at a bad time". + * Low-order 4 bits must be all ones. + */ +extern void Xintrspurious(void); +#define LAPIC_SPURIOUS_VECTOR 0xef + +/* + * Vector used for inter-processor interrupts. + */ +extern void Xintr_lapic_ipi(void); +extern void Xrecurse_lapic_ipi(void); +extern void Xresume_lapic_ipi(void); +#define LAPIC_IPI_VECTOR 0xe0 + +/* + * Vector used for local apic timer interrupts. + */ + +extern void Xintr_lapic_ltimer(void); +extern void Xresume_lapic_ltimer(void); +extern void Xrecurse_lapic_ltimer(void); +#define LAPIC_TIMER_VECTOR 0xc0 + +/* + * 'pin numbers' for local APIC + */ +#define LAPIC_PIN_TIMER 0 +#define LAPIC_PIN_PCINT 2 +#define LAPIC_PIN_LVINT0 3 +#define LAPIC_PIN_LVINT1 4 +#define LAPIC_PIN_LVERR 5 + +extern void Xintr_lapic0(void); +extern void Xintr_lapic2(void); +extern void Xintr_lapic3(void); +extern void Xintr_lapic4(void); +extern void Xintr_lapic5(void); + + +struct cpu_info; + +extern void lapic_boot_init __P((paddr_t)); +extern void lapic_set_lvt __P((void)); +extern void lapic_enable __P((void)); +extern void lapic_calibrate_timer __P((struct cpu_info *ci)); +extern void lapic_initclocks __P((void)); + +#endif diff --git a/sys/arch/amd64/include/intr.h b/sys/arch/amd64/include/intr.h index a9ba202472f..f468f1a0b27 100644 --- a/sys/arch/amd64/include/intr.h +++ b/sys/arch/amd64/include/intr.h @@ -1,4 +1,4 @@ -/* $OpenBSD: intr.h,v 1.2 2004/05/07 20:33:04 tedu Exp $ */ +/* $OpenBSD: intr.h,v 1.3 2004/06/25 11:03:28 art Exp $ */ /* $NetBSD: intr.h,v 1.2 2003/05/04 22:01:56 fvdl Exp $ */ /*- @@ -44,7 +44,6 @@ #ifndef _LOCORE #include <machine/cpu.h> -#include <machine/pic.h> /* * Struct describing an interrupt source for a CPU. struct cpu_info @@ -252,6 +251,8 @@ softintr(int sir) #define IPLSHIFT 4 /* The upper nibble of vectors is the IPL. */ #define IPL(level) ((level) >> IPLSHIFT) /* Extract the IPL. */ +#include <machine/pic.h> + /* * Stub declarations. */ diff --git a/sys/arch/amd64/include/lock.h b/sys/arch/amd64/include/lock.h new file mode 100644 index 00000000000..35b1974f910 --- /dev/null +++ b/sys/arch/amd64/include/lock.h @@ -0,0 +1,119 @@ +/* $OpenBSD: lock.h,v 1.1 2004/06/25 11:03:28 art Exp $ */ +/* $NetBSD: lock.h,v 1.1.2.2 2000/05/03 14:40:55 sommerfeld Exp $ */ + +/*- + * Copyright (c) 2000 The NetBSD Foundation, Inc. + * All rights reserved. + * + * This code is derived from software contributed to The NetBSD Foundation + * by Jason R. Thorpe. + * + * 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 the NetBSD + * Foundation, Inc. and its contributors. + * 4. Neither the name of The NetBSD Foundation 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 NETBSD FOUNDATION, INC. 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 FOUNDATION 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. + */ + +/* + * Machine-dependent spin lock operations. + */ + +#ifndef _AMD64_LOCK_H_ +#define _AMD64_LOCK_H_ + +typedef __volatile int __cpu_simple_lock_t; + +#define __SIMPLELOCK_LOCKED 1 +#define __SIMPLELOCK_UNLOCKED 0 + +/* + * compiler barrier: prevent reordering of instructions. + * XXX something similar will move to <sys/cdefs.h> + * or thereabouts. + * This prevents the compiler from reordering code around + * this "instruction", acting as a sequence point for code generation. + */ + +#define __lockbarrier() __asm __volatile("": : :"memory") + +#ifdef LOCKDEBUG + +extern void __cpu_simple_lock_init(__cpu_simple_lock_t *); +extern void __cpu_simple_lock(__cpu_simple_lock_t *); +extern int __cpu_simple_lock_try(__cpu_simple_lock_t *); +extern void __cpu_simple_unlock(__cpu_simple_lock_t *); + +#else + +#include <machine/atomic.h> + +static __inline void __cpu_simple_lock_init(__cpu_simple_lock_t *) + __attribute__((__unused__)); +static __inline void __cpu_simple_lock(__cpu_simple_lock_t *) + __attribute__((__unused__)); +static __inline int __cpu_simple_lock_try(__cpu_simple_lock_t *) + __attribute__((__unused__)); +static __inline void __cpu_simple_unlock(__cpu_simple_lock_t *) + __attribute__((__unused__)); + +static __inline void +__cpu_simple_lock_init(__cpu_simple_lock_t *lockp) +{ + *lockp = __SIMPLELOCK_UNLOCKED; + __lockbarrier(); +} + +static __inline void +__cpu_simple_lock(__cpu_simple_lock_t *lockp) +{ + while (x86_atomic_testset_i(lockp, __SIMPLELOCK_LOCKED) + == __SIMPLELOCK_LOCKED) { + continue; /* spin */ + } + __lockbarrier(); +} + +static __inline int +__cpu_simple_lock_try(__cpu_simple_lock_t *lockp) +{ + int r = (x86_atomic_testset_i(lockp, __SIMPLELOCK_LOCKED) + == __SIMPLELOCK_UNLOCKED); + + __lockbarrier(); + + return (r); +} + +static __inline void +__cpu_simple_unlock(__cpu_simple_lock_t *lockp) +{ + __lockbarrier(); + *lockp = __SIMPLELOCK_UNLOCKED; +} + +#endif /* !LOCKDEBUG */ + +#endif /* _AMD64_LOCK_H_ */ diff --git a/sys/arch/amd64/include/mpconfig.h b/sys/arch/amd64/include/mpconfig.h index 7c12822824c..54f340adfc9 100644 --- a/sys/arch/amd64/include/mpconfig.h +++ b/sys/arch/amd64/include/mpconfig.h @@ -1,4 +1,4 @@ -/* $NetBSD: mpconfig.h,v 1.1 2003/02/26 21:26:11 fvdl Exp $ */ +/* $NetBSD: mpconfig.h,v 1.2 2003/05/11 00:05:52 fvdl Exp $ */ /* * Definitions originally from the mpbios code, but now used for ACPI @@ -50,6 +50,7 @@ struct mp_intr_map int flags; /* from mp spec intr record */ u_int32_t redir; int cpu_id; + int global_int; /* ACPI global interrupt number */ }; #if defined(_KERNEL) diff --git a/sys/arch/amd64/include/pic.h b/sys/arch/amd64/include/pic.h index c9d9a5082a6..b6a222b2780 100644 --- a/sys/arch/amd64/include/pic.h +++ b/sys/arch/amd64/include/pic.h @@ -1,11 +1,15 @@ -/* $OpenBSD: pic.h,v 1.1 2004/01/28 01:39:39 mickey Exp $ */ +/* $OpenBSD: pic.h,v 1.2 2004/06/25 11:03:28 art Exp $ */ /* $NetBSD: pic.h,v 1.1 2003/02/26 21:26:11 fvdl Exp $ */ #ifndef _X86_PIC_H #define _X86_PIC_H #include <sys/device.h> +#ifdef MULTIPROCESSOR +#include <sys/mplock.h> +#else #include <sys/lock.h> +#endif struct cpu_info; @@ -15,7 +19,9 @@ struct cpu_info; struct pic { struct device pic_dev; int pic_type; - simple_lock_t pic_lock; +#ifdef MULTIPROCESSOR + struct SIMPLE_LOCK pic_lock; +#endif void (*pic_hwmask)(struct pic *, int); void (*pic_hwunmask)(struct pic *, int); void (*pic_addroute)(struct pic *, struct cpu_info *, int, int, int); diff --git a/sys/arch/amd64/isa/clock.c b/sys/arch/amd64/isa/clock.c index fcf6db666e5..2132a6e5b63 100644 --- a/sys/arch/amd64/isa/clock.c +++ b/sys/arch/amd64/isa/clock.c @@ -1,4 +1,4 @@ -/* $OpenBSD: clock.c,v 1.3 2004/03/22 19:43:29 nordin Exp $ */ +/* $OpenBSD: clock.c,v 1.4 2004/06/25 11:03:28 art Exp $ */ /* $NetBSD: clock.c,v 1.1 2003/04/26 18:39:50 fvdl Exp $ */ /*- @@ -184,7 +184,7 @@ mc146818_write(sc, reg, datum) DELAY(1); } -static u_long rtclock_tval; +u_long rtclock_tval; /* minimal initialization, enough for delay() */ void @@ -313,28 +313,7 @@ int clockintr(void *arg) { struct clockframe *frame = arg; -#if defined(I586_CPU) || defined(I686_CPU) - static int microset_iter; /* call cc_microset once/sec */ - struct cpu_info *ci = curcpu(); - - /* - * If we have a cycle counter, do the microset thing. - */ - if (ci->ci_feature_flags & CPUID_TSC) { - if ( -#if defined(MULTIPROCESSOR) - CPU_IS_PRIMARY(ci) && -#endif - (microset_iter--) == 0) { - cc_microset_time = time; - microset_iter = hz - 1; -#if defined(MULTIPROCESSOR) - x86_broadcast_ipi(X86_IPI_MICROSET); -#endif - cc_microset(ci); - } - } -#endif + hardclock(frame); return 1; @@ -383,7 +362,7 @@ gettick() * wave' mode counts at 2:1). */ void -delay(int n) +i8254_delay(int n) { int limit, tick, otick; static const int delaytab[26] = { @@ -518,7 +497,7 @@ rtcdrain(void *v) } void -cpu_initclocks() +i8254_initclocks() { static struct timeout rtcdrain_timeout; diff --git a/sys/arch/amd64/pci/pci_machdep.c b/sys/arch/amd64/pci/pci_machdep.c index 138afc1ba23..e1af0882118 100644 --- a/sys/arch/amd64/pci/pci_machdep.c +++ b/sys/arch/amd64/pci/pci_machdep.c @@ -1,4 +1,4 @@ -/* $OpenBSD: pci_machdep.c,v 1.1 2004/01/28 01:39:39 mickey Exp $ */ +/* $OpenBSD: pci_machdep.c,v 1.2 2004/06/25 11:03:28 art Exp $ */ /* $NetBSD: pci_machdep.c,v 1.3 2003/05/07 21:33:58 fvdl Exp $ */ /*- @@ -111,7 +111,7 @@ int pci_mode = -1; -#ifdef MULTIPROCESSOR +#if defined(MULTIPROCESSOR) && 0 struct simplelock pci_conf_slock = SIMPLELOCK_INITIALIZER; #else struct simplelock pci_conf_slock = { 0 }; |