From 51805ac6d3e64d3c0f95fa2b86981c214cf94b3c Mon Sep 17 00:00:00 2001 From: John Davis Date: Thu, 5 Mar 2026 20:20:03 -0600 Subject: [PATCH] kernel/x86: Fix IO-APIC initialization on non-PCI systems Currently the IO-APIC is fully initialized after PCI initialization resulting in the IO-APIC not being initialized on systems without a PCI bus (i.e. Hyper-V Gen2 VMs). This change moves IO-APIC initialization to occur during early init, deferring PCI interrupt enumeration and routing until after PCI initialization has been completed. Change-Id: I00be0be05d2e7668c3c6bc7af3afc4ff8d04a129 Reviewed-on: https://review.haiku-os.org/c/haiku/+/10414 Reviewed-by: waddlesplash Reviewed-by: X512 X512 Tested-by: Commit checker robot --- headers/private/kernel/arch/x86/ioapic.h | 4 +- .../busses/pci/x86/X86PCIController.cpp | 2 +- src/system/kernel/arch/x86/arch_int.cpp | 2 +- src/system/kernel/arch/x86/ioapic.cpp | 103 ++++++++++-------- 4 files changed, 62 insertions(+), 49 deletions(-) diff --git a/headers/private/kernel/arch/x86/ioapic.h b/headers/private/kernel/arch/x86/ioapic.h index d08ebf8ad4..2db6e5a663 100644 --- a/headers/private/kernel/arch/x86/ioapic.h +++ b/headers/private/kernel/arch/x86/ioapic.h @@ -11,7 +11,7 @@ struct kernel_args; bool ioapic_is_interrupt_available(int32 gsi); -void ioapic_preinit(kernel_args* args); -void ioapic_init(); +void ioapic_init(kernel_args* args); +void ioapic_routing_init(); #endif // _KERNEL_ARCH_x86_IOAPIC_H diff --git a/src/add-ons/kernel/busses/pci/x86/X86PCIController.cpp b/src/add-ons/kernel/busses/pci/x86/X86PCIController.cpp index 76c471a09e..f7c8f2a3f3 100644 --- a/src/add-ons/kernel/busses/pci/x86/X86PCIController.cpp +++ b/src/add-ons/kernel/busses/pci/x86/X86PCIController.cpp @@ -161,7 +161,7 @@ X86PCIController::GetRange(uint32 index, pci_resource_range* range) status_t X86PCIController::Finalize() { - ioapic_init(); + ioapic_routing_init(); return B_OK; } diff --git a/src/system/kernel/arch/x86/arch_int.cpp b/src/system/kernel/arch/x86/arch_int.cpp index dddb542e21..e9cda21f00 100644 --- a/src/system/kernel/arch/x86/arch_int.cpp +++ b/src/system/kernel/arch/x86/arch_int.cpp @@ -488,7 +488,7 @@ status_t arch_int_init_io(kernel_args* args) { msi_init(args); - ioapic_preinit(args); + ioapic_init(args); return B_OK; } diff --git a/src/system/kernel/arch/x86/ioapic.cpp b/src/system/kernel/arch/x86/ioapic.cpp index ae520f71e0..5fab87c231 100644 --- a/src/system/kernel/arch/x86/ioapic.cpp +++ b/src/system/kernel/arch/x86/ioapic.cpp @@ -677,16 +677,7 @@ ioapic_is_interrupt_available(int32 gsi) void -ioapic_preinit(kernel_args* args) -{ - sIOAPICPhys = args->arch_args.ioapic_phys; - - // The real IO-APIC initialization occurs after PCI initialization. -} - - -void -ioapic_init() +ioapic_init(kernel_args* args) { static const interrupt_controller ioapicController = { "82093AA IOAPIC", @@ -702,7 +693,7 @@ ioapic_init() if (!apic_available()) return; - if (sIOAPICPhys == 0) { + if (args->arch_args.ioapic_phys == 0) { dprintf("no io-apics available, not using io-apics for interrupt " "routing\n"); return; @@ -748,16 +739,6 @@ ioapic_init() // aren't different routings based on it this is non-fatal } - IRQRoutingTable table; - status = prepare_irq_routing(acpiModule, table, - &ioapic_is_interrupt_available); - if (status != B_OK) { - dprintf("IRQ routing preparation failed, not configuring io-apics\n"); - acpi_set_interrupt_model(acpiModule, ACPI_INTERRUPT_MODEL_PIC); - // revert to PIC interrupt model just in case - return; - } - // use the boot CPU as the target for all interrupts uint8 targetAPIC = x86_get_cpu_apic_id(0); @@ -773,31 +754,9 @@ ioapic_init() current = current->next; } -#ifdef TRACE_IOAPIC - dprintf("trying interrupt routing:\n"); - print_irq_routing_table(table); -#endif - - status = enable_irq_routing(acpiModule, table); - if (status != B_OK) { - panic("failed to enable IRQ routing"); - // if it failed early on it might still work in PIC mode - acpi_set_interrupt_model(acpiModule, ACPI_INTERRUPT_MODEL_PIC); - return; - } - - print_irq_routing_table(table); - - // configure the source overrides, but let the PCI config below override it + // configure the source overrides, but let the PCI config later override it acpi_configure_source_overrides(madt); - // configure IO-APIC interrupts from PCI routing table - for (int i = 0; i < table.Count(); i++) { - irq_routing_entry& entry = table.ElementAt(i); - ioapic_configure_io_interrupt(entry.irq, - entry.polarity | entry.trigger_mode); - } - // kill the local ints on the local APIC apic_disable_local_ints(); // TODO: This uses the assumption that our init is running on the @@ -810,7 +769,7 @@ ioapic_init() uint16 legacyInterrupts; pic_disable(legacyInterrupts); - // enable previsouly enabled legacy interrupts + // enable previously enabled legacy interrupts for (uint8 i = 0; i < 16; i++) { if ((legacyInterrupts & (1 << i)) != 0) ioapic_enable_io_interrupt(i); @@ -830,7 +789,61 @@ ioapic_init() current = current->next; } + // IO-APIC interrupt routing occurs after PCI initialization. + sIOAPICPhys = args->arch_args.ioapic_phys; + // prefer the ioapic over the normal pic dprintf("using io-apics for interrupt routing\n"); arch_int_set_interrupt_controller(ioapicController); } + + +void +ioapic_routing_init() +{ + if (sIOAPICPhys == 0) { + dprintf("no io-apics available, not using io-apics for interrupt routing\n"); + return; + } + + // load ACPI module + status_t status; + acpi_module_info* acpiModule; + status = get_module(B_ACPI_MODULE_NAME, (module_info**)&acpiModule); + if (status != B_OK) { + dprintf("ACPI module not available, not configuring io-apics\n"); + return; + } + BPrivate::CObjectDeleter + acpiModulePutter(B_ACPI_MODULE_NAME); + + IRQRoutingTable table; + status = prepare_irq_routing(acpiModule, table, &ioapic_is_interrupt_available); + if (status != B_OK) { + dprintf("IRQ routing preparation failed, not configuring io-apics\n"); + // revert to PIC interrupt model just in case + acpi_set_interrupt_model(acpiModule, ACPI_INTERRUPT_MODEL_PIC); + return; + } + +#ifdef TRACE_IOAPIC + dprintf("trying interrupt routing:\n"); + print_irq_routing_table(table); +#endif + + status = enable_irq_routing(acpiModule, table); + if (status != B_OK) { + panic("failed to enable IRQ routing"); + // if it failed early on it might still work in PIC mode + acpi_set_interrupt_model(acpiModule, ACPI_INTERRUPT_MODEL_PIC); + return; + } + + print_irq_routing_table(table); + + // configure IO-APIC interrupts from PCI routing table + for (int i = 0; i < table.Count(); i++) { + irq_routing_entry& entry = table.ElementAt(i); + ioapic_configure_io_interrupt(entry.irq, entry.polarity | entry.trigger_mode); + } +}