DF-5431 / fix.diff
--- a/sys/platform/pc64/acpica/acpi_madt.c +++ b/sys/platform/pc64/acpica/acpi_madt.c @@ -570,6 +570,8 @@ struct madt_ioapic_probe_cbarg { int ioapic_cnt; int gsi_base0; + uint32_t ioapic_addrs[16]; /* IOAPIC_COUNT_MAX */ + uint32_t gsi_bases[16]; /* IOAPIC_COUNT_MAX */ }; static int @@ -615,10 +617,30 @@ } else if (ent->Type == ACPI_MADT_TYPE_IO_APIC) { const ACPI_MADT_IO_APIC *ioapic_ent; + int i; + ioapic_ent = (const ACPI_MADT_IO_APIC *)ent; if (ioapic_ent->Address == 0) { kprintf("madt_ioapic_probe: zero IOAPIC address\n"); return EINVAL; + } + if (arg->ioapic_cnt >= 16) { /* IOAPIC_COUNT_MAX */ + kprintf("madt_ioapic_probe: too many IOAPICs\n"); + return EINVAL; + } + for (i = 0; i < arg->ioapic_cnt; ++i) { + /* + * Two IO APICs sharing an address or a GSI base + * always overlap (every IO APIC has >= 1 pin); + * ioapic_add() would panic() on it later. + */ + if (ioapic_ent->Address == arg->ioapic_addrs[i] || + ioapic_ent->GlobalIrqBase == arg->gsi_bases[i]) { + kprintf("madt_ioapic_probe: IOAPIC %d overlaps " + "IOAPIC %d (addr/GSI base)\n", + arg->ioapic_cnt, i); + return EINVAL; + } } if (ioapic_ent->Id == APICID_MAX) { kprintf("madt_ioapic_probe: " @@ -627,6 +649,8 @@ return EINVAL; } + arg->ioapic_addrs[arg->ioapic_cnt] = ioapic_ent->Address; + arg->gsi_bases[arg->ioapic_cnt] = ioapic_ent->GlobalIrqBase; arg->ioapic_cnt++; if (ioapic_ent->GlobalIrqBase == 0) arg->gsi_base0 = 1; |