diff --git a/sys/platform/pc64/conf/files b/sys/platform/pc64/conf/files index ea505b4..2247ca6 100644 --- a/sys/platform/pc64/conf/files +++ b/sys/platform/pc64/conf/files @@ -176,6 +176,7 @@ platform/pc64/x86_64/console.c standard platform/pc64/x86_64/ipl_funcs.c standard kern/syscalls.c standard platform/pc64/x86_64/mp_machdep.c optional smp +platform/pc64/x86_64/mp_madt.c optional smp dev/misc/atkbd/atkbd_isa.c optional atkbd dev/misc/atkbdc_layer/atkbdc_isa.c optional atkbdc dev/misc/ppc/ppc.c optional ppc diff --git a/sys/platform/pc64/include/smp.h b/sys/platform/pc64/include/smp.h index 804211e..4f30238 100644 --- a/sys/platform/pc64/include/smp.h +++ b/sys/platform/pc64/include/smp.h @@ -69,7 +69,6 @@ extern int bsp_apic_ready; extern int mp_naps; extern int mp_nbusses; extern int mp_napics; -extern int boot_cpu_id; extern vm_offset_t cpu_apic_address; extern vm_offset_t io_apic_address[]; extern u_int32_t cpu_apic_versions[]; @@ -90,9 +89,9 @@ extern struct pcb stoppcbs[]; /* functions in mp_machdep.c */ void *permanent_io_mapping(vm_paddr_t); u_int mp_bootaddress (u_int); -int mp_probe (void); void mp_start (void); void mp_announce (void); +void mp_set_cpuids (int, int); u_int isa_apic_mask (u_int); int isa_apic_irq (int); int pci_apic_irq (int, int, int); @@ -132,6 +131,11 @@ void io_apic_set_id (int, int); int io_apic_get_id (int); int ext_int_setup (int, int); +/* functions in mp_madt.c */ +vm_paddr_t madt_probe(void); +vm_offset_t madt_pass1(vm_paddr_t); +int madt_pass2(vm_paddr_t, int); + #if defined(READY) void clr_io_apic_mask24 (int, u_int32_t); void set_io_apic_mask24 (int, u_int32_t); diff --git a/sys/platform/pc64/x86_64/machdep.c b/sys/platform/pc64/x86_64/machdep.c index 955c217..b969681 100644 --- a/sys/platform/pc64/x86_64/machdep.c +++ b/sys/platform/pc64/x86_64/machdep.c @@ -172,6 +172,8 @@ SYSCTL_INT(_debug, OID_AUTO, tlb_flush_count, int physmem = 0; +u_long ebda_addr = 0; + static int sysctl_hw_physmem(SYSCTL_HANDLER_ARGS) { @@ -1409,8 +1411,9 @@ getmemsize(caddr_t kmdp, u_int64_t first) /* make hole for AP bootstrap code */ physmap[1] = mp_bootaddress(physmap[1] / 1024); - /* look for the MP hardware - needed for apic addresses */ - mp_probe(); + /* Save EBDA address, if any */ + ebda_addr = (u_long)(*(u_short *)(KERNBASE + 0x40e)); + ebda_addr <<= 4; #endif /* diff --git a/sys/platform/pc64/x86_64/mp_machdep.c b/sys/platform/pc64/x86_64/mp_machdep.c index cdcfa81..b729248 100644 --- a/sys/platform/pc64/x86_64/mp_machdep.c +++ b/sys/platform/pc64/x86_64/mp_machdep.c @@ -160,6 +160,12 @@ typedef struct BASETABLE_ENTRY { char name[16]; } basetable_entry; +struct mptable_pos { + mpfps_t mp_fps; + mpcth_t mp_cth; + vm_size_t mp_cth_mapsz; +}; + /* * this code MUST be enabled here and in mpboot.s. * it follows the very early stages of AP boot by placing values in CMOS ram. @@ -216,6 +222,9 @@ static int need_hyperthreading_fixup; static u_int logical_cpus; u_int logical_cpus_mask; +static int madt_probe_test; +TUNABLE_INT("hw.madt_probe_test", &madt_probe_test); + /** XXX FIXME: where does this really belong, isa.h/isa.c perhaps? */ int current_postcode; @@ -228,7 +237,6 @@ int mp_nbusses; /* # of busses */ #ifdef APIC_IO int mp_napics; /* # of IO APICs */ #endif -int boot_cpu_id; /* designated BSP */ vm_offset_t cpu_apic_address; #ifdef APIC_IO vm_offset_t io_apic_address[NAPICID]; /* NAPICID is more than enough */ @@ -240,6 +248,8 @@ u_int32_t cpu_apic_versions[MAXCPU]; int64_t tsc0_offset; extern int64_t tsc_offsets[]; +extern u_long ebda_addr; + #ifdef APIC_IO struct apic_intmapinfo int_to_apicintpin[APIC_INTMAPSIZE]; #endif @@ -277,20 +287,22 @@ extern inthand_t IDTVEC(fast_syscall), IDTVEC(fast_syscall32); * Local data and functions. */ -static int mp_capable; static u_int boot_address; static u_int base_memory; static int mp_finish; -static mpfps_t mpfps; -static long search_for_sig(u_int32_t target, int count); static void mp_enable(u_int boot_addr); +static int mptable_probe(void); +static long mptable_search_sig(u_int32_t target, int count); static void mptable_hyperthread_fixup(u_int id_mask); -static void mptable_pass1(void); -static int mptable_pass2(void); -static void default_mp_table(int type); -static void fix_mp_table(void); +static void mptable_pass1(struct mptable_pos *); +static int mptable_pass2(struct mptable_pos *); +static void mptable_default(int type); +static void mptable_fix(void); +static void mptable_map(struct mptable_pos *, vm_paddr_t); +static void mptable_unmap(struct mptable_pos *); + #ifdef APIC_IO static void setup_apic_irq_mapping(void); static int apic_int_is_bus_type(int intr, int bus_type); @@ -331,11 +343,10 @@ mp_bootaddress(u_int basemem) /* * Look for an Intel MP spec table (ie, SMP capable hardware). */ -int -mp_probe(void) +static int +mptable_probe(void) { long x; - u_long segment; u_int32_t target; /* @@ -347,39 +358,25 @@ mp_probe(void) POSTCODE(MP_PROBE_POST); /* see if EBDA exists */ - if ((segment = (u_long) * (u_short *) (KERNBASE + 0x40e)) != 0) { + if (ebda_addr != 0) { /* search first 1K of EBDA */ - target = (u_int32_t) (segment << 4); - if ((x = search_for_sig(target, 1024 / 4)) != -1L) - goto found; + target = (u_int32_t)ebda_addr; + if ((x = mptable_search_sig(target, 1024 / 4)) > 0) + return x; } else { /* last 1K of base memory, effective 'top of base' passed in */ - target = (u_int32_t) (base_memory - 0x400); - if ((x = search_for_sig(target, 1024 / 4)) != -1L) - goto found; + target = (u_int32_t)(base_memory - 0x400); + if ((x = mptable_search_sig(target, 1024 / 4)) > 0) + return x; } /* search the BIOS */ - target = (u_int32_t) BIOS_BASE; - if ((x = search_for_sig(target, BIOS_COUNT)) != -1L) - goto found; + target = (u_int32_t)BIOS_BASE; + if ((x = mptable_search_sig(target, BIOS_COUNT)) > 0) + return x; /* nothing found */ - mpfps = (mpfps_t)0; - mp_capable = 0; return 0; - -found: - /* - * Calculate needed resources. We can safely map physical - * memory into SMPpt after mptable_pass1() completes. - */ - mpfps = (mpfps_t)x; - mptable_pass1(); - - /* flag fact that we are running multiple processors */ - mp_capable = 1; - return 1; } @@ -390,12 +387,7 @@ void mp_start(void) { POSTCODE(MP_START_POST); - - /* look for MP capable motherboard */ - if (mp_capable) - mp_enable(boot_address); - else - panic("MP hardware not found!"); + mp_enable(boot_address); } @@ -547,29 +539,64 @@ mp_enable(u_int boot_addr) int apic; u_int ux; #endif /* APIC_IO */ + vm_paddr_t mpfps_paddr; POSTCODE(MP_ENABLE_POST); -#if 0 /* JGXXX */ - /* turn on 4MB of V == P addressing so we can get to MP table */ - *(int *)PTD = PG_V | PG_RW | ((uintptr_t)(void *)KPTphys & PG_FRAME); - cpu_invltlb(); -#endif + if (madt_probe_test) + mpfps_paddr = 0; + else + mpfps_paddr = mptable_probe(); - /* examine the MP table for needed info, uses physical addresses */ - x = mptable_pass2(); + if (mpfps_paddr) { + struct mptable_pos mpt; -#if 0 /* JGXXX */ - *(int *)PTD = 0; - cpu_invltlb(); -#endif /* 0 JGXXX */ + mptable_map(&mpt, mpfps_paddr); - /* can't process default configs till the CPU APIC is pmapped */ - if (x) - default_mp_table(x); + /* + * We can safely map physical memory into SMPpt after + * mptable_pass1() completes. + */ + mptable_pass1(&mpt); + + if (cpu_apic_address == 0) + panic("mp_enable: no local apic!\n"); + + /* examine the MP table for needed info */ + x = mptable_pass2(&mpt); + + mptable_unmap(&mpt); + + /* + * can't process default configs till the + * CPU APIC is pmapped + */ + if (x) + mptable_default(x); + + /* post scan cleanup */ + mptable_fix(); + } else { + vm_paddr_t madt_paddr; + int bsp_apic_id; + + madt_paddr = madt_probe(); + if (madt_paddr == 0) + panic("mp_enable: madt_probe failed\n"); + + cpu_apic_address = madt_pass1(madt_paddr); + if (cpu_apic_address == 0) + panic("mp_enable: no local apic (madt)!\n"); - /* post scan cleanup */ - fix_mp_table(); + /* + * XXX: where is the best place to set lapic? + */ + lapic = pmap_mapdev_uncacheable(cpu_apic_address, sizeof(struct LAPIC)); + + bsp_apic_id = (lapic->id & 0xff000000) >> 24; + if (madt_pass2(madt_paddr, bsp_apic_id)) + panic("mp_enable: madt_pass2 failed\n"); + } #if defined(APIC_IO) @@ -626,17 +653,28 @@ mp_enable(u_int boot_addr) #define MP_SIG 0x5f504d5f /* _MP_ */ #define NEXT(X) ((X) += 4) static long -search_for_sig(u_int32_t target, int count) +mptable_search_sig(u_int32_t target, int count) { - int x; - u_int32_t *addr = (u_int32_t *) (KERNBASE + target); + vm_size_t map_size; + u_int32_t *addr; + int x, ret; + + KKASSERT(target != 0); - for (x = 0; x < count; NEXT(x)) - if (addr[x] == MP_SIG) + map_size = count * sizeof(u_int32_t); + addr = pmap_mapdev((vm_paddr_t)target, map_size); + + ret = 0; + for (x = 0; x < count; NEXT(x)) { + if (addr[x] == MP_SIG) { /* make array index a byte index */ - return (long)(&addr[x]); + ret = target + (x * sizeof(u_int32_t)); + break; + } + } - return -1; + pmap_unmapdev((vm_offset_t)addr, map_size); + return ret; } @@ -726,9 +764,6 @@ static int lookup_bus_type (char *name); /* * 1st pass on motherboard's Intel MP specification table. * - * initializes: - * ncpus = 1 - * * determines: * cpu_apic_address (common to all CPUs) * io_apic_address[N] @@ -736,13 +771,16 @@ static int lookup_bus_type (char *name); * mp_nbusses * mp_napics * nintrs + * need_hyperthreading_fixup + * logical_cpus */ static void -mptable_pass1(void) +mptable_pass1(struct mptable_pos *mpt) { #ifdef APIC_IO int x; #endif + mpfps_t fps; mpcth_t cth; int totalSize; void* position; @@ -752,6 +790,9 @@ mptable_pass1(void) POSTCODE(MPTABLE_PASS1_POST); + fps = mpt->mp_fps; + KKASSERT(fps != NULL); + #ifdef APIC_IO /* clear various tables */ for (x = 0; x < NAPICID; ++x) { @@ -769,7 +810,7 @@ mptable_pass1(void) id_mask = 0; /* check for use of 'default' configuration */ - if (mpfps->mpfb1 != 0) { + if (fps->mpfb1 != 0) { /* use default addresses */ cpu_apic_address = DEFAULT_APIC_BASE; #ifdef APIC_IO @@ -778,16 +819,16 @@ mptable_pass1(void) /* fill in with defaults */ mp_naps = 2; /* includes BSP */ - mp_nbusses = default_data[mpfps->mpfb1 - 1][0]; + mp_nbusses = default_data[fps->mpfb1 - 1][0]; #if defined(APIC_IO) mp_napics = 1; nintrs = 16; #endif /* APIC_IO */ } else { - if (mpfps->pap == 0) + cth = mpt->mp_cth; + if (cth == NULL) panic("MP Configuration Table Header MISSING!"); - cth = (void *)PHYS_TO_DMAP(mpfps->pap); cpu_apic_address = (vm_offset_t) cth->apic_address; @@ -845,12 +886,6 @@ mptable_pass1(void) /* See if we need to fixup HT logical CPUs. */ mptable_hyperthread_fixup(id_mask); - - /* - * Count the BSP. - * This is also used as a counter while starting the APs. - */ - ncpus = 1; --mp_naps; /* subtract the BSP */ } @@ -860,7 +895,7 @@ mptable_pass1(void) * 2nd pass on motherboard's Intel MP specification table. * * sets: - * boot_cpu_id + * logical_cpus_mask * ID_TO_IO(N), phy APIC ID to log CPU/IO table * CPU_TO_ID(N), logical CPU to APIC ID table * IO_TO_ID(N), logical IO to APIC ID table @@ -868,10 +903,11 @@ mptable_pass1(void) * io_apic_ints[N] */ static int -mptable_pass2(void) +mptable_pass2(struct mptable_pos *mpt) { struct PROCENTRY proc; int x; + mpfps_t fps; mpcth_t cth; int totalSize; void* position; @@ -882,6 +918,9 @@ mptable_pass2(void) POSTCODE(MPTABLE_PASS2_POST); + fps = mpt->mp_fps; + KKASSERT(fps != NULL); + /* Initialize fake proc entry for use with HT fixup. */ bzero(&proc, sizeof(proc)); proc.type = 0; @@ -925,20 +964,17 @@ mptable_pass2(void) } #endif - /* setup the cpu/apic mapping arrays */ - boot_cpu_id = -1; - /* record whether PIC or virtual-wire mode */ - machintr_setvar_simple(MACHINTR_VAR_IMCR_PRESENT, mpfps->mpfb2 & 0x80); + machintr_setvar_simple(MACHINTR_VAR_IMCR_PRESENT, fps->mpfb2 & 0x80); /* check for use of 'default' configuration */ - if (mpfps->mpfb1 != 0) - return mpfps->mpfb1; /* return default configuration type */ + if (fps->mpfb1 != 0) + return fps->mpfb1; /* return default configuration type */ - if (mpfps->pap == 0) + cth = mpt->mp_cth; + if (cth == NULL) panic("MP Configuration Table Header MISSING!"); - cth = (void *)PHYS_TO_DMAP(mpfps->pap); /* walk the table, recording info of interest */ totalSize = cth->base_table_length - sizeof(struct MPCTH); position = (u_char *) cth + sizeof(struct MPCTH); @@ -995,13 +1031,14 @@ mptable_pass2(void) position = (uint8_t *)position + basetable_entry_types[type].length; } - if (boot_cpu_id == -1) + if (CPU_TO_ID(0) < 0) panic("NO BSP found!"); /* report fact that its NOT a default configuration */ return 0; } + /* * Check if we should perform a hyperthreading "fix-up" to * enumerate any logical CPU's that aren't already listed @@ -1051,6 +1088,48 @@ mptable_hyperthread_fixup(u_int id_mask) mp_naps *= logical_cpus; } +static void +mptable_map(struct mptable_pos *mpt, vm_paddr_t mpfps_paddr) +{ + mpfps_t fps = NULL; + mpcth_t cth = NULL; + vm_size_t cth_mapsz = 0; + + fps = pmap_mapdev(mpfps_paddr, sizeof(*fps)); + if (fps->pap != 0) { + /* + * Map configuration table header to get + * the base table size + */ + cth = pmap_mapdev(fps->pap, sizeof(*cth)); + cth_mapsz = cth->base_table_length; + pmap_unmapdev((vm_offset_t)cth, sizeof(*cth)); + + /* + * Map the base table + */ + cth = pmap_mapdev(fps->pap, cth_mapsz); + } + + mpt->mp_fps = fps; + mpt->mp_cth = cth; + mpt->mp_cth_mapsz = cth_mapsz; +} + +static void +mptable_unmap(struct mptable_pos *mpt) +{ + if (mpt->mp_cth != NULL) { + pmap_unmapdev((vm_offset_t)mpt->mp_cth, mpt->mp_cth_mapsz); + mpt->mp_cth = NULL; + mpt->mp_cth_mapsz = 0; + } + if (mpt->mp_fps != NULL) { + pmap_unmapdev((vm_offset_t)mpt->mp_fps, sizeof(*mpt->mp_fps)); + mpt->mp_fps = NULL; + } +} + #ifdef APIC_IO void @@ -1255,7 +1334,7 @@ io_apic_find_int_entry(int apic, int pin) * parse an Intel MP specification table */ static void -fix_mp_table(void) +mptable_fix(void) { int x; #ifdef APIC_IO @@ -1455,9 +1534,18 @@ setup_apic_irq_mapping(void) #endif +void +mp_set_cpuids(int cpu_id, int apic_id) +{ + CPU_TO_ID(cpu_id) = apic_id; + ID_TO_CPU(apic_id) = cpu_id; +} + static int processor_entry(proc_entry_ptr entry, int cpu) { + KKASSERT(cpu > 0); + /* check for usability */ if (!(entry->cpu_flags & PROCENTRY_FLAG_EN)) return 0; @@ -1466,16 +1554,13 @@ processor_entry(proc_entry_ptr entry, int cpu) panic("CPU APIC ID out of range (0..%d)", NAPICID - 1); /* check for BSP flag */ if (entry->cpu_flags & PROCENTRY_FLAG_BP) { - boot_cpu_id = entry->apic_id; - CPU_TO_ID(0) = entry->apic_id; - ID_TO_CPU(entry->apic_id) = 0; + mp_set_cpuids(0, entry->apic_id); return 0; /* its already been counted */ } /* add another AP to list, if less than max number of CPUs */ else if (cpu < MAXCPU) { - CPU_TO_ID(cpu) = entry->apic_id; - ID_TO_CPU(entry->apic_id) = cpu; + mp_set_cpuids(cpu, entry->apic_id); return 1; } @@ -1921,9 +2006,9 @@ apic_polarity(int apic, int pin) * FIXME: probably not complete yet... */ static void -default_mp_table(int type) +mptable_default(int type) { - int ap_cpu_id; + int ap_cpu_id, boot_cpu_id; #if defined(APIC_IO) int io_apic_id; int pin; diff --git a/sys/platform/pc64/x86_64/mp_madt.c b/sys/platform/pc64/x86_64/mp_madt.c new file mode 100644 index 0000000..fc98589 --- /dev/null +++ b/sys/platform/pc64/x86_64/mp_madt.c @@ -0,0 +1,474 @@ +/* + * Copyright (c) 2009 The DragonFly Project. All rights reserved. + * + * This code is derived from software contributed to The DragonFly Project + * by Sepherosa Ziehau + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in + * the documentation and/or other materials provided with the + * distribution. + * 3. Neither the name of The DragonFly Project 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 COPYRIGHT HOLDERS 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 + * COPYRIGHT HOLDERS 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 +#include + +#include +#include + +#define ACPI_RSDP_EBDA_MAPSZ 1024 +#define ACPI_RSDP_BIOS_MAPSZ 0x20000 +#define ACPI_RSDP_BIOS_MAPADDR 0xe0000 + +#define ACPI_RSDP_ALIGN 16 + +#define ACPI_RSDP_SIGLEN 8 +#define ACPI_RSDP_SIG "RSD PTR " + +#define ACPI_SDTH_SIGLEN 4 +#define ACPI_RSDT_SIG "RSDT" +#define ACPI_XSDT_SIG "XSDT" +#define ACPI_MADT_SIG "APIC" + +/* Root System Description Pointer */ +struct acpi_rsdp { + uint8_t rsdp_sig[ACPI_RSDP_SIGLEN]; + uint8_t rsdp_cksum; + uint8_t rsdp_oem_id[6]; + uint8_t rsdp_rev; + uint32_t rsdp_rsdt; + uint32_t rsdp_len; + uint64_t rsdp_xsdt; + uint8_t rsdp_ext_cksum; + uint8_t rsdp_rsvd[3]; +} __packed; + +/* System Description Table Header */ +struct acpi_sdth { + uint8_t sdth_sig[ACPI_SDTH_SIGLEN]; + uint32_t sdth_len; + uint8_t sdth_rev; + uint8_t sdth_cksum; + uint8_t sdth_oem_id[6]; + uint8_t sdth_oem_tbid[8]; + uint32_t sdth_oem_rev; + uint32_t sdth_crt_id; + uint32_t sdth_crt_rev; +} __packed; + +/* Extended System Description Table */ +struct acpi_xsdt { + struct acpi_sdth xsdt_hdr; + uint64_t xsdt_ents[1]; +} __packed; + +/* Root System Description Table */ +struct acpi_rsdt { + struct acpi_sdth rsdt_hdr; + uint32_t rsdt_ents[1]; +} __packed; + +/* Multiple APIC Description Table */ +struct acpi_madt { + struct acpi_sdth madt_hdr; + uint32_t madt_lapic_addr; + uint32_t madt_flags; + uint8_t madt_ents[1]; +} __packed; + +/* Common parts of MADT APIC structure */ +struct acpi_madt_ent { + uint8_t me_type; /* MADT_ENT_ */ + uint8_t me_len; +} __packed; + +#define MADT_ENT_LAPIC 0 + +/* MADT Processor Local APIC */ +struct acpi_madt_lapic { + struct acpi_madt_ent ml_hdr; + uint8_t ml_cpu_id; + uint8_t ml_apic_id; + uint32_t ml_flags; /* MADT_LAPIC_ */ +} __packed; + +#define MADT_LAPIC_ENABLED 0x1 + +typedef vm_paddr_t (*madt_search_t)(vm_paddr_t); + +static const struct acpi_rsdp *madt_rsdp_search(const uint8_t *, int); +static void *madt_sdth_map(vm_paddr_t); +static void madt_sdth_unmap(struct acpi_sdth *); +static vm_paddr_t madt_search_xsdt(vm_paddr_t); +static vm_paddr_t madt_search_rsdt(vm_paddr_t); +static int madt_check(vm_paddr_t); + +extern u_long ebda_addr; + +vm_paddr_t +madt_probe(void) +{ + const struct acpi_rsdp *rsdp; + madt_search_t search; + vm_paddr_t search_paddr, madt_paddr; + vm_size_t mapsz; + uint8_t *ptr; + + if (ebda_addr != 0) { + mapsz = ACPI_RSDP_EBDA_MAPSZ; + ptr = pmap_mapdev(ebda_addr, mapsz); + + rsdp = madt_rsdp_search(ptr, mapsz); + if (rsdp == NULL) { + kprintf("madt: RSDP not in EBDA\n"); + pmap_unmapdev((vm_offset_t)ptr, mapsz); + + ptr = NULL; + mapsz = 0; + } else { + kprintf("madt: RSDP in EBDA\n"); + goto found_rsdp; + } + } + + mapsz = ACPI_RSDP_BIOS_MAPSZ; + ptr = pmap_mapdev(ACPI_RSDP_BIOS_MAPADDR, mapsz); + + rsdp = madt_rsdp_search(ptr, mapsz); + if (rsdp == NULL) { + kprintf("madt_probe: no RSDP\n"); + pmap_unmapdev((vm_offset_t)ptr, mapsz); + return 0; + } else { + kprintf("madt: RSDP in BIOS mem\n"); + } + +found_rsdp: + if (rsdp->rsdp_rev != 2) { + search_paddr = rsdp->rsdp_rsdt; + search = madt_search_rsdt; + } else { + search_paddr = rsdp->rsdp_xsdt; + search = madt_search_xsdt; + } + pmap_unmapdev((vm_offset_t)ptr, mapsz); + + madt_paddr = search(search_paddr); + if (madt_paddr == 0) { + kprintf("madt_probe: can't locate MADT\n"); + return 0; + } + + /* Preliminary checks */ + if (madt_check(madt_paddr)) + return 0; + return madt_paddr; +} + +static const struct acpi_rsdp * +madt_rsdp_search(const uint8_t *target, int size) +{ + const struct acpi_rsdp *rsdp; + int i; + + KKASSERT(size > sizeof(*rsdp)); + + for (i = 0; i < size - sizeof(*rsdp); i += ACPI_RSDP_ALIGN) { + rsdp = (const struct acpi_rsdp *)&target[i]; + if (memcmp(rsdp->rsdp_sig, ACPI_RSDP_SIG, + ACPI_RSDP_SIGLEN) == 0) + return rsdp; + } + return NULL; +} + +static void * +madt_sdth_map(vm_paddr_t paddr) +{ + struct acpi_sdth *sdth; + vm_size_t mapsz; + + sdth = pmap_mapdev(paddr, sizeof(*sdth)); + mapsz = sdth->sdth_len; + pmap_unmapdev((vm_offset_t)sdth, sizeof(*sdth)); + + if (mapsz < sizeof(*sdth)) + return NULL; + + return pmap_mapdev(paddr, mapsz); +} + +static void +madt_sdth_unmap(struct acpi_sdth *sdth) +{ + pmap_unmapdev((vm_offset_t)sdth, sdth->sdth_len); +} + +static vm_paddr_t +madt_search_xsdt(vm_paddr_t xsdt_paddr) +{ + struct acpi_xsdt *xsdt; + vm_paddr_t madt_paddr = 0; + int i, nent; + + if (xsdt_paddr == 0) { + kprintf("madt_search_xsdt: XSDT paddr == 0\n"); + return 0; + } + + xsdt = madt_sdth_map(xsdt_paddr); + if (xsdt == NULL) { + kprintf("madt_search_xsdt: can't map XSDT\n"); + return 0; + } + + if (memcmp(xsdt->xsdt_hdr.sdth_sig, ACPI_XSDT_SIG, + ACPI_SDTH_SIGLEN) != 0) { + kprintf("madt_search_xsdt: not XSDT\n"); + goto back; + } + + if (xsdt->xsdt_hdr.sdth_rev != 1) { + kprintf("madt_search_xsdt: unsupported XSDT revision %d\n", + xsdt->xsdt_hdr.sdth_rev); + goto back; + } + + nent = (xsdt->xsdt_hdr.sdth_len - sizeof(xsdt->xsdt_hdr)) / + sizeof(xsdt->xsdt_ents[0]); + for (i = 0; i < nent; ++i) { + struct acpi_sdth *sdth; + + if (xsdt->xsdt_ents[i] == 0) + continue; + + sdth = madt_sdth_map(xsdt->xsdt_ents[i]); + if (sdth != NULL) { + int ret; + + ret = memcmp(sdth->sdth_sig, ACPI_MADT_SIG, + ACPI_SDTH_SIGLEN); + madt_sdth_unmap(sdth); + + if (ret == 0) { + kprintf("madt: MADT in XSDT\n"); + madt_paddr = xsdt->xsdt_ents[i]; + break; + } + } + } +back: + madt_sdth_unmap(&xsdt->xsdt_hdr); + return madt_paddr; +} + +static vm_paddr_t +madt_search_rsdt(vm_paddr_t rsdt_paddr) +{ + struct acpi_rsdt *rsdt; + vm_paddr_t madt_paddr = 0; + int i, nent; + + if (rsdt_paddr == 0) { + kprintf("madt_search_rsdt: RSDT paddr == 0\n"); + return 0; + } + + rsdt = madt_sdth_map(rsdt_paddr); + if (rsdt == NULL) { + kprintf("madt_search_rsdt: can't map RSDT\n"); + return 0; + } + + if (memcmp(rsdt->rsdt_hdr.sdth_sig, ACPI_RSDT_SIG, + ACPI_SDTH_SIGLEN) != 0) { + kprintf("madt_search_rsdt: not RSDT\n"); + goto back; + } + + if (rsdt->rsdt_hdr.sdth_rev != 1) { + kprintf("madt_search_rsdt: unsupported RSDT revision %d\n", + rsdt->rsdt_hdr.sdth_rev); + goto back; + } + + nent = (rsdt->rsdt_hdr.sdth_len - sizeof(rsdt->rsdt_hdr)) / + sizeof(rsdt->rsdt_ents[0]); + for (i = 0; i < nent; ++i) { + struct acpi_sdth *sdth; + + if (rsdt->rsdt_ents[i] == 0) + continue; + + sdth = madt_sdth_map(rsdt->rsdt_ents[i]); + if (sdth != NULL) { + int ret; + + ret = memcmp(sdth->sdth_sig, ACPI_MADT_SIG, + ACPI_SDTH_SIGLEN); + madt_sdth_unmap(sdth); + + if (ret == 0) { + kprintf("madt: MADT in RSDT\n"); + madt_paddr = rsdt->rsdt_ents[i]; + break; + } + } + } +back: + madt_sdth_unmap(&rsdt->rsdt_hdr); + return madt_paddr; +} + +vm_offset_t +madt_pass1(vm_paddr_t madt_paddr) +{ + struct acpi_madt *madt; + vm_offset_t lapic_addr; + + KKASSERT(madt_paddr != 0); + + madt = madt_sdth_map(madt_paddr); + KKASSERT(madt != NULL); + + kprintf("madt: LAPIC address 0x%08x, flags %#x\n", + madt->madt_lapic_addr, madt->madt_flags); + lapic_addr = madt->madt_lapic_addr; + + madt_sdth_unmap(&madt->madt_hdr); + + return lapic_addr; +} + +int +madt_pass2(vm_paddr_t madt_paddr, int bsp_apic_id) +{ + struct acpi_madt *madt; + int size, cur, error, cpu, found_bsp; + + kprintf("madt: BSP apic id %d\n", bsp_apic_id); + + KKASSERT(madt_paddr != 0); + + madt = madt_sdth_map(madt_paddr); + KKASSERT(madt != NULL); + + size = madt->madt_hdr.sdth_len - + (sizeof(*madt) - sizeof(madt->madt_ents)); + cur = 0; + error = 0; + found_bsp = 0; + cpu = 1; + + while (size - cur > sizeof(struct acpi_madt_ent)) { + const struct acpi_madt_ent *ent; + + ent = (const struct acpi_madt_ent *)&madt->madt_ents[cur]; + if (ent->me_len < sizeof(*ent)) { + kprintf("madt_pass2: invalid MADT entry len %d\n", + ent->me_len); + error = EINVAL; + break; + } + if (ent->me_len > (size - cur)) { + kprintf("madt_pass2: invalid MADT entry len %d, " + "> table length\n", ent->me_len); + error = EINVAL; + break; + } + + cur += ent->me_len; + + if (ent->me_type == MADT_ENT_LAPIC) { + const struct acpi_madt_lapic *lapic_ent; + + if (ent->me_len < sizeof(*lapic_ent)) { + kprintf("madt_pass2: invalid MADT lapic entry " + "len %d\n", ent->me_len); + error = EINVAL; + break; + } + lapic_ent = (const struct acpi_madt_lapic *)ent; + if (lapic_ent->ml_flags & MADT_LAPIC_ENABLED) { + kprintf("madt: cpu_id %d, apic_id %d\n", + lapic_ent->ml_cpu_id, + lapic_ent->ml_apic_id); + if (lapic_ent->ml_apic_id == bsp_apic_id) { + mp_set_cpuids(0, + lapic_ent->ml_apic_id); + found_bsp = 1; + } else { + mp_set_cpuids(cpu, + lapic_ent->ml_apic_id); + ++cpu; + } + } + } + } + if (!found_bsp) { + kprintf("madt_pass2: BSP is not found\n"); + error = EINVAL; + } + if (cpu == 1) { + kprintf("madt_pass2: no APs\n"); + error = EINVAL; + } + if (!error) + mp_naps = cpu - 1; + + madt_sdth_unmap(&madt->madt_hdr); + return error; +} + +static int +madt_check(vm_paddr_t madt_paddr) +{ + struct acpi_madt *madt; + int error = 0; + + KKASSERT(madt_paddr != 0); + + madt = madt_sdth_map(madt_paddr); + KKASSERT(madt != NULL); + + if (madt->madt_hdr.sdth_rev != 1 && madt->madt_hdr.sdth_rev != 2) { + kprintf("madt_check: unsupported MADT revision %d\n", + madt->madt_hdr.sdth_rev); + error = EOPNOTSUPP; + goto back; + } + + if (madt->madt_hdr.sdth_len < + sizeof(*madt) - sizeof(madt->madt_ents)) { + kprintf("madt_check: invalid MADT length %u\n", + madt->madt_hdr.sdth_len); + error = EINVAL; + } +back: + madt_sdth_unmap(&madt->madt_hdr); + return error; +} + + diff --git a/sys/platform/pc64/x86_64/pmap.c b/sys/platform/pc64/x86_64/pmap.c index 67d720d..dd5fea5 100644 --- a/sys/platform/pc64/x86_64/pmap.c +++ b/sys/platform/pc64/x86_64/pmap.c @@ -697,10 +697,6 @@ pmap_bootstrap(vm_paddr_t *firstaddr) #endif } #endif -#ifdef SMP - if (cpu_apic_address == 0) - panic("pmap_bootstrap: no local apic!"); -#endif /* * We need to finish setting up the globaldata page for the BSP.