Author: mmlr Date: 2011-05-10 11:29:57 +0200 (Tue, 10 May 2011) New Revision: 41415 Changeset: https://dev.haiku-os.org/changeset/41415 Modified: haiku/trunk/src/system/kernel/arch/x86/arch_int.cpp haiku/trunk/src/system/kernel/arch/x86/irq_routing_table.cpp haiku/trunk/src/system/kernel/arch/x86/irq_routing_table.h Log: Check hardwired and chosen IRQs against the maximum we can address. Try to fail gracefully in such cases (resulting in the IO-APIC not being used). Modified: haiku/trunk/src/system/kernel/arch/x86/arch_int.cpp =================================================================== --- haiku/trunk/src/system/kernel/arch/x86/arch_int.cpp 2011-05-10 08:50:57 UTC (rev 41414) +++ haiku/trunk/src/system/kernel/arch/x86/arch_int.cpp 2011-05-10 09:29:57 UTC (rev 41415) @@ -651,7 +651,8 @@ } IRQRoutingTable table; - status = read_irq_routing_table(acpiModule, &table); + status = read_irq_routing_table(acpiModule, &table, + sIOAPICMaxRedirectionEntry + 1); if (status != B_OK) { dprintf("reading IRQ routing table failed, not configuring ioapic.\n"); acpi_set_interrupt_model(acpiModule, ACPI_INTERRUPT_MODEL_PIC); Modified: haiku/trunk/src/system/kernel/arch/x86/irq_routing_table.cpp =================================================================== --- haiku/trunk/src/system/kernel/arch/x86/irq_routing_table.cpp 2011-05-10 08:50:57 UTC (rev 41414) +++ haiku/trunk/src/system/kernel/arch/x86/irq_routing_table.cpp 2011-05-10 09:29:57 UTC (rev 41415) @@ -254,6 +254,11 @@ uint16 bestIRQUsage = UINT16_MAX; for (int j = 0; j < link->possible_irqs.Count(); j++) { irq_descriptor& possibleIRQ = link->possible_irqs.ElementAt(j); + if (possibleIRQ.irq >= maxIRQCount) { + // we can't address this pin + continue; + } + if (possibleIRQ.irq < kMaxISAInterrupts && (validForPCI & (1 << possibleIRQ.irq)) == 0) { // better avoid that if possible @@ -269,6 +274,12 @@ // pick that one and update the counts irq_descriptor& chosenDescriptor = link->possible_irqs.ElementAt(bestIRQIndex); + if (chosenDescriptor.irq >= maxIRQCount) { + panic("chosen irq %u is not addressable (max %lu)", + chosenDescriptor.irq, maxIRQCount); + return B_ERROR; + } + irqUsage[chosenDescriptor.irq] += link->used_by.Count(); status_t status = set_current_irq(acpi, link->handle, chosenDescriptor); @@ -368,10 +379,10 @@ } -static void +static status_t read_irq_routing_table_recursive(acpi_module_info* acpi, pci_module_info* pci, acpi_handle device, const pci_address& parentAddress, - IRQRoutingTable* table, bool rootBridge) + IRQRoutingTable* table, bool rootBridge, uint32 maxIRQCount) { acpi_data buffer; buffer.pointer = NULL; @@ -379,7 +390,7 @@ status_t status = acpi->get_irq_routing_table(device, &buffer); if (status != B_OK) { // simply not a bridge - return; + return B_OK; } TRACE("found irq routing table\n"); @@ -401,7 +412,7 @@ pciAddress.device, pciAddress.function, PCI_secondary_bus, 1); if (secondaryBus == 255) { // The bus below this bridge is inactive, nothing to do. - return; + return B_OK; } // The secondary bus cannot be the same as the current one. @@ -409,7 +420,7 @@ dprintf("invalid secondary bus %u on primary bus %u," " can't configure irq routing of devices below\n", secondaryBus, parentAddress.bus); - return; + return B_ERROR; } // Everything below is now on the secondary bus. @@ -421,8 +432,16 @@ irq_routing_entry irqEntry; status = handle_routing_table_entry(acpi, pci, acpiTable, pciAddress, irqEntry); - if (status == B_OK) + if (status == B_OK) { + if (irqEntry.source == NULL && irqEntry.irq >= maxIRQCount) { + dprintf("hardwired irq %u not addressable (max %lu)\n", + irqEntry.irq, maxIRQCount); + free(buffer.pointer); + return B_ERROR; + } + table->PushBack(irqEntry); + } acpiTable = (acpi_pci_routing_table*)((uint8*)acpiTable + acpiTable->Length); @@ -434,9 +453,10 @@ acpi_data pathBuffer; pathBuffer.pointer = NULL; pathBuffer.length = ACPI_ALLOCATE_BUFFER; - if (acpi->ns_handle_to_pathname(device, &pathBuffer) != B_OK) { + status = acpi->ns_handle_to_pathname(device, &pathBuffer); + if (status != B_OK) { dprintf("failed to resolve handle to path\n"); - return; + return status; } char childName[255]; @@ -448,20 +468,24 @@ status = acpi->get_handle(NULL, childName, &childHandle); if (status != B_OK) { dprintf("failed to get handle to child \"%s\"\n", childName); - continue; + break; } TRACE("recursing down to child \"%s\"\n", childName); - read_irq_routing_table_recursive(acpi, pci, childHandle, pciAddress, - table, false); + status = read_irq_routing_table_recursive(acpi, pci, childHandle, + pciAddress, table, false, maxIRQCount); + if (status != B_OK) + break; } free(pathBuffer.pointer); + return status; } status_t -read_irq_routing_table(acpi_module_info* acpi, IRQRoutingTable* table) +read_irq_routing_table(acpi_module_info* acpi, IRQRoutingTable* table, + uint32 maxIRQCount) { char rootPciName[255]; acpi_handle rootPciHandle; @@ -494,10 +518,14 @@ return status; } - read_irq_routing_table_recursive(acpi, pci, rootPciHandle, rootPciAddress, - table, true); + status = read_irq_routing_table_recursive(acpi, pci, rootPciHandle, + rootPciAddress, table, true, maxIRQCount); put_module(B_PCI_MODULE_NAME); + + if (status != B_OK) + return status; + return table->Count() > 0 ? B_OK : B_ERROR; } Modified: haiku/trunk/src/system/kernel/arch/x86/irq_routing_table.h =================================================================== --- haiku/trunk/src/system/kernel/arch/x86/irq_routing_table.h 2011-05-10 08:50:57 UTC (rev 41414) +++ haiku/trunk/src/system/kernel/arch/x86/irq_routing_table.h 2011-05-10 09:29:57 UTC (rev 41415) @@ -71,7 +71,8 @@ void print_irq_routing_table(IRQRoutingTable* table); -status_t read_irq_routing_table(acpi_module_info* acpi, IRQRoutingTable* table); +status_t read_irq_routing_table(acpi_module_info* acpi, IRQRoutingTable* table, + uint32 maxIRQCount); status_t enable_irq_routing(acpi_module_info* acpi, IRQRoutingTable& routingTable, uint32 maxIRQCount);