Reserve the running BSP as kernel ID 0 before the MADT walk, so it
survives firmware that lists it later. Ignore duplicate LAPIC entries
and CPUs beyond NCPUS.
This uses the apic_add_cpu() return value and the cpu_lapic_list bound.
---
i386/i386at/acpi_parse_apic.c | 34 +++++++++++++++++++---------------
1 file changed, 19 insertions(+), 15 deletions(-)
diff --git a/i386/i386at/acpi_parse_apic.c b/i386/i386at/acpi_parse_apic.c
index 85123015..8304bee5 100644
--- a/i386/i386at/acpi_parse_apic.c
+++ b/i386/i386at/acpi_parse_apic.c
@@ -392,12 +392,23 @@ acpi_get_apic2(struct acpi_xsdt *xsdt, int acpi_xsdt_n)
static void
acpi_apic_add_lapic(struct acpi_apic_lapic *lapic_entry)
{
+ uint16_t apic_id;
+ int i;
+
/* If cpu flag is correct */
- if (lapic_entry->flags & (ACPI_LAPIC_FLAG_ENABLED |
ACPI_LAPIC_FLAG_CAPABLE)) {
- /* Add cpu to processors' list. */
- apic_add_cpu(lapic_entry->apic_id & apic_id_mask);
+ if (!(lapic_entry->flags & (ACPI_LAPIC_FLAG_ENABLED |
ACPI_LAPIC_FLAG_CAPABLE)))
+ return;
+
+ apic_id = lapic_entry->apic_id & apic_id_mask;
+
+ for (i = 0; i < apic_get_numcpus(); i++) {
+ if (apic_get_cpu_apic_id(i) == apic_id)
+ return;
}
+ if (apic_add_cpu(apic_id) != 0)
+ printf("APIC: ignoring LAPIC ID %#x: NCPUS=%d limit reached\n",
+ apic_id, NCPUS);
}
/*
@@ -462,7 +473,6 @@ acpi_apic_parse_table(struct acpi_apic *apic)
{
struct acpi_apic_dhdr *apic_entry = NULL;
vm_offset_t end = 0;
- uint8_t numcpus = 1;
/* Get the address of first APIC entry */
apic_entry = (struct acpi_apic_dhdr*) apic->entry;
@@ -472,9 +482,6 @@ acpi_apic_parse_table(struct acpi_apic *apic)
printf("APIC entry=0x%p end=0x%x\n", apic_entry, end);
- /* Initialize number of cpus */
- numcpus = apic_get_numcpus();
-
while ((vm_offset_t)apic_entry + sizeof(struct acpi_apic_dhdr) <= end) {
struct acpi_apic_lapic *lapic_entry;
struct acpi_apic_ioapic *ioapic_entry;
@@ -493,11 +500,8 @@ acpi_apic_parse_table(struct acpi_apic *apic)
/* If APIC entry is a CPU's Local APIC. */
case ACPI_APIC_ENTRY_LAPIC:
- if(numcpus < NCPUS) {
- /* Store Local APIC data. */
- lapic_entry = (struct acpi_apic_lapic*) apic_entry;
- acpi_apic_add_lapic(lapic_entry);
- }
+ lapic_entry = (struct acpi_apic_lapic*) apic_entry;
+ acpi_apic_add_lapic(lapic_entry);
break;
/* If APIC entry is an IOAPIC. */
@@ -534,9 +538,6 @@ acpi_apic_parse_table(struct acpi_apic *apic)
/* Get next APIC entry. */
apic_entry = (struct acpi_apic_dhdr*)((vm_offset_t) apic_entry
+ apic_entry->length);
-
- /* Update number of cpus. */
- numcpus = apic_get_numcpus();
}
return ACPI_SUCCESS;
@@ -575,6 +576,9 @@ acpi_apic_setup(struct acpi_apic *apic)
fix_apic_id_mask();
+ if (apic_add_cpu(apic_get_current_cpu()) != 0)
+ return ACPI_APIC_FAILURE;
+
acpi_apic_parse_table(apic);
ncpus = apic_get_numcpus();