Index: head/sys/x86/acpica/madt.c =================================================================== --- head/sys/x86/acpica/madt.c +++ head/sys/x86/acpica/madt.c @@ -59,7 +59,7 @@ static struct lapic_info { u_int la_enabled; u_int la_acpi_id; -} lapics[MAX_APIC_ID + 1]; +} *lapics; int madt_found_sci_override; static ACPI_TABLE_MADT *madt; @@ -141,8 +141,6 @@ int user_x2apic; bool bios_x2apic; - madt = pmap_mapbios(madt_physaddr, madt_length); - madt_walk_table(madt_setup_cpus_handler, NULL); if ((cpu_feature2 & CPUID2_X2APIC) != 0) { reason = NULL; @@ -214,6 +212,11 @@ } } + madt = pmap_mapbios(madt_physaddr, madt_length); + lapics = malloc(sizeof(*lapics) * (max_apic_id + 1), M_MADT, + M_WAITOK | M_ZERO); + madt_walk_table(madt_setup_cpus_handler, NULL); + lapic_init(madt->Address); printf("ACPI APIC Table: <%.*s %.*s>\n", (int)sizeof(madt->Header.OemId), madt->Header.OemId, @@ -236,6 +239,8 @@ u_int pin; int i; + KASSERT(lapics != NULL, ("local APICs not initialized")); + /* Try to initialize ACPI so that we can access the FADT. */ i = acpi_Startup(); if (ACPI_FAILURE(i)) { @@ -282,6 +287,10 @@ free(ioapics, M_MADT); ioapics = NULL; + /* NB: this is the last use of the lapics array. */ + free(lapics, M_MADT); + lapics = NULL; + return (0); } @@ -332,7 +341,7 @@ "enabled" : "disabled"); if (!(flags & ACPI_MADT_ENABLED)) return; - if (apic_id > MAX_APIC_ID) { + if (apic_id > max_apic_id) { printf("MADT: Ignoring local APIC ID %u (too high)\n", apic_id); return; @@ -471,7 +480,7 @@ { int i; - for (i = 0; i <= MAX_APIC_ID; i++) { + for (i = 0; i <= max_apic_id; i++) { if (!lapics[i].la_enabled) continue; if (lapics[i].la_acpi_id != acpi_id) @@ -723,6 +732,9 @@ if (madt == NULL) return; + + KASSERT(lapics != NULL, ("local APICs not initialized")); + CPU_FOREACH(i) { pc = pcpu_find(i); KASSERT(pc != NULL, ("no pcpu data for CPU %u", i)); Index: head/sys/x86/acpica/srat.c =================================================================== --- head/sys/x86/acpica/srat.c +++ head/sys/x86/acpica/srat.c @@ -55,11 +55,11 @@ #include #if MAXMEMDOM > 1 -struct cpu_info { +static struct cpu_info { int enabled:1; int has_memory:1; int domain; -} cpus[MAX_APIC_ID + 1]; +} *cpus; struct mem_affinity mem_info[VM_PHYSSEG_MAX + 1]; int num_mem; @@ -204,7 +204,7 @@ "enabled" : "disabled"); if (!(cpu->Flags & ACPI_SRAT_CPU_ENABLED)) break; - if (cpu->ApicId > MAX_APIC_ID) { + if (cpu->ApicId > max_apic_id) { printf("SRAT: Ignoring local APIC ID %u (too high)\n", cpu->ApicId); break; @@ -228,7 +228,7 @@ "enabled" : "disabled"); if (!(x2apic->Flags & ACPI_SRAT_CPU_ENABLED)) break; - if (x2apic->ApicId > MAX_APIC_ID) { + if (x2apic->ApicId > max_apic_id) { printf("SRAT: Ignoring local APIC ID %u (too high)\n", x2apic->ApicId); break; @@ -294,7 +294,7 @@ for (i = 0; i < num_mem; i++) { found = 0; - for (j = 0; j <= MAX_APIC_ID; j++) + for (j = 0; j <= max_apic_id; j++) if (cpus[j].enabled && cpus[j].domain == mem_info[i].domain) { cpus[j].has_memory = 1; @@ -306,7 +306,7 @@ return (ENXIO); } } - for (i = 0; i <= MAX_APIC_ID; i++) + for (i = 0; i <= max_apic_id; i++) if (cpus[i].enabled && !cpus[i].has_memory) { printf("SRAT: No memory found for CPU %d\n", i); return (ENXIO); @@ -401,7 +401,7 @@ for (j = 0; j < num_mem; j++) if (mem_info[j].domain == domain_pxm[i]) mem_info[j].domain = i; - for (j = 0; j <= MAX_APIC_ID; j++) + for (j = 0; j <= max_apic_id; j++) if (cpus[j].enabled && cpus[j].domain == domain_pxm[i]) cpus[j].domain = i; } @@ -415,6 +415,8 @@ static int parse_srat(void) { + unsigned int idx, size; + vm_paddr_t addr; int error; if (resource_disabled("srat", 0)) @@ -423,6 +425,25 @@ srat_physaddr = acpi_find_table(ACPI_SIG_SRAT); if (srat_physaddr == 0) return (-1); + + /* + * Allocate data structure: + * + * Find the last physical memory region and steal some memory from + * it. This is done because at this point in the boot process + * malloc is still not usable. + */ + for (idx = 0; phys_avail[idx + 1] != 0; idx += 2); + KASSERT(idx != 0, ("phys_avail is empty!")); + idx -= 2; + + size = sizeof(*cpus) * (max_apic_id + 1); + addr = trunc_page(phys_avail[idx + 1] - size); + KASSERT(addr >= phys_avail[idx], + ("Not enough memory for SRAT table items")); + phys_avail[idx + 1] = addr - 1; + + cpus = (struct cpu_info *)PHYS_TO_DMAP(addr); /* * Make a pass over the table to populate the cpus[] and Index: head/sys/x86/include/apicvar.h =================================================================== --- head/sys/x86/include/apicvar.h +++ head/sys/x86/include/apicvar.h @@ -182,7 +182,7 @@ IDTVEC(spuriousint), IDTVEC(timerint); extern vm_paddr_t lapic_paddr; -extern int apic_cpuids[]; +extern int *apic_cpuids; void apic_register_enumerator(struct apic_enumerator *enumerator); void *ioapic_create(vm_paddr_t addr, int32_t apic_id, int intbase); Index: head/sys/x86/include/x86_smp.h =================================================================== --- head/sys/x86/include/x86_smp.h +++ head/sys/x86/include/x86_smp.h @@ -54,7 +54,7 @@ int cpu_disabled:1; int cpu_hyperthread:1; }; -extern struct cpu_info cpu_info[]; +extern struct cpu_info *cpu_info; #ifdef COUNT_IPIS extern u_long *ipi_invltlb_counts[MAXCPU]; Index: head/sys/x86/x86/local_apic.c =================================================================== --- head/sys/x86/x86/local_apic.c +++ head/sys/x86/x86/local_apic.c @@ -44,6 +44,7 @@ #include #include #include +#include #include #include #include @@ -83,6 +84,8 @@ #define GSEL_APIC GSEL(GCODE_SEL, SEL_KPL) #endif +static MALLOC_DEFINE(M_LAPIC, "local_apic", "Local APIC items"); + /* Sanity checks on IDT vectors. */ CTASSERT(APIC_IO_INTS + APIC_NUM_IOINTS == APIC_TIMER_INT); CTASSERT(APIC_TIMER_INT < APIC_LOCAL_INTS); @@ -134,7 +137,7 @@ uint32_t lvt_timer_last; /* Include IDT_SYSCALL to make indexing easier. */ int la_ioint_irqs[APIC_NUM_IOINTS + 1]; -} static lapics[MAX_APIC_ID + 1]; +} static *lapics; /* Global defaults for local APIC LVT entries. */ static struct lvt lvts[APIC_LVT_MAX + 1] = { @@ -601,7 +604,7 @@ { int i; - if (apic_id > MAX_APIC_ID) { + if (apic_id > max_apic_id) { printf("APIC: Ignoring local APIC with ID %d\n", apic_id); if (boot_cpu) panic("Can't ignore BSP"); @@ -1661,7 +1664,7 @@ verbose = 1; else verbose = 0; - for (apic_id = 0; apic_id <= MAX_APIC_ID; apic_id++) { + for (apic_id = 0; apic_id <= max_apic_id; apic_id++) { if (lapics[apic_id].la_present == 0) continue; db_printf("Interrupts bound to lapic %u\n", apic_id); @@ -1861,6 +1864,9 @@ if (best_enum == NULL) return; + + lapics = malloc(sizeof(*lapics) * (max_apic_id + 1), M_LAPIC, + M_WAITOK | M_ZERO); /* Initialize the local APIC. */ retval = best_enum->apic_setup_local(); Index: head/sys/x86/x86/mp_x86.c =================================================================== --- head/sys/x86/x86/mp_x86.c +++ head/sys/x86/x86/mp_x86.c @@ -84,6 +84,8 @@ #define BIOS_RESET (0x0f) #define BIOS_WARM (0x0a) +static MALLOC_DEFINE(M_CPUS, "cpus", "CPU items"); + /* lock region used by kernel profiling */ int mcount_lock; @@ -132,8 +134,8 @@ * Store data from cpu_add() until later in the boot when we actually setup * the APs. */ -struct cpu_info cpu_info[MAX_APIC_ID + 1]; -int apic_cpuids[MAX_APIC_ID + 1]; +struct cpu_info *cpu_info; +int *apic_cpuids; int cpu_apic_ids[MAXCPU]; /* Holds pending bitmap based IPIs per CPU */ @@ -546,7 +548,7 @@ nlayers++; topo_init_root(&topo_root); - for (i = 0; i <= MAX_APIC_ID; ++i) { + for (i = 0; i <= max_apic_id; ++i) { if (!cpu_info[i].cpu_present) continue; @@ -803,6 +805,19 @@ return (cg_root); } +static void +cpu_alloc(void *dummy __unused) +{ + /* + * Dynamically allocate the arrays that depend on the + * maximum APIC ID. + */ + cpu_info = malloc(sizeof(*cpu_info) * (max_apic_id + 1), M_CPUS, + M_WAITOK | M_ZERO); + apic_cpuids = malloc(sizeof(*apic_cpuids) * (max_apic_id + 1), M_CPUS, + M_WAITOK | M_ZERO); +} +SYSINIT(cpu_alloc, SI_SUB_CPU, SI_ORDER_FIRST, cpu_alloc, NULL); /* * Add a logical CPU to the topology. @@ -811,7 +826,7 @@ cpu_add(u_int apic_id, char boot_cpu) { - if (apic_id > MAX_APIC_ID) { + if (apic_id > max_apic_id) { panic("SMP: APIC ID %d too high", apic_id); return; }