1dc14d97bSMichael Lotz /* 2dc14d97bSMichael Lotz * Copyright 2008-2011, Michael Lotz, mmlr@mlotz.ch. 3dc14d97bSMichael Lotz * Distributed under the terms of the MIT License. 4dc14d97bSMichael Lotz */ 5dc14d97bSMichael Lotz 6dc14d97bSMichael Lotz #include <arch/x86/ioapic.h> 7dc14d97bSMichael Lotz 8dc14d97bSMichael Lotz #include <int.h> 9dc14d97bSMichael Lotz #include <vm/vm.h> 10dc14d97bSMichael Lotz 11dc14d97bSMichael Lotz #include "irq_routing_table.h" 12dc14d97bSMichael Lotz 13dc14d97bSMichael Lotz #include <ACPI.h> 14dc14d97bSMichael Lotz #include <AutoDeleter.h> 15dc14d97bSMichael Lotz #include <safemode.h> 16dc14d97bSMichael Lotz #include <string.h> 17dc14d97bSMichael Lotz #include <stdio.h> 18dc14d97bSMichael Lotz 19dc14d97bSMichael Lotz #include <arch/x86/apic.h> 20dc14d97bSMichael Lotz #include <arch/x86/arch_int.h> 21dc14d97bSMichael Lotz #include <arch/x86/pic.h> 22dc14d97bSMichael Lotz 23d11e32a8SMichael Lotz // to gain access to the ACPICA types 24d11e32a8SMichael Lotz #include "acpi.h" 25d11e32a8SMichael Lotz 26dc14d97bSMichael Lotz 27dc14d97bSMichael Lotz //#define TRACE_IOAPIC 28dc14d97bSMichael Lotz #ifdef TRACE_IOAPIC 29dc14d97bSMichael Lotz # define TRACE(x) dprintf x 30dc14d97bSMichael Lotz #else 31dc14d97bSMichael Lotz # define TRACE(x) ; 32dc14d97bSMichael Lotz #endif 33dc14d97bSMichael Lotz 34dc14d97bSMichael Lotz 35dc14d97bSMichael Lotz // ACPI interrupt models 36dc14d97bSMichael Lotz #define ACPI_INTERRUPT_MODEL_PIC 0 37dc14d97bSMichael Lotz #define ACPI_INTERRUPT_MODEL_APIC 1 38dc14d97bSMichael Lotz #define ACPI_INTERRUPT_MODEL_SAPIC 2 39dc14d97bSMichael Lotz 40dc14d97bSMichael Lotz 41dc14d97bSMichael Lotz // Definitions for a 82093AA IO APIC controller 420f91697fSMichael Lotz #define IO_APIC_ID 0x00 43dc14d97bSMichael Lotz #define IO_APIC_VERSION 0x01 44dc14d97bSMichael Lotz #define IO_APIC_ARBITRATION 0x02 45dc14d97bSMichael Lotz #define IO_APIC_REDIRECTION_TABLE 0x10 // entry = base + 2 * index 46dc14d97bSMichael Lotz 470f91697fSMichael Lotz // Fields for the id register 480f91697fSMichael Lotz #define IO_APIC_ID_SHIFT 24 4963475256SMichael Lotz #define IO_APIC_ID_MASK 0xff 500f91697fSMichael Lotz 51dc14d97bSMichael Lotz // Fields for the version register 52dc14d97bSMichael Lotz #define IO_APIC_VERSION_SHIFT 0 53dc14d97bSMichael Lotz #define IO_APIC_VERSION_MASK 0xff 54dc14d97bSMichael Lotz #define IO_APIC_MAX_REDIRECTION_ENTRY_SHIFT 16 55dc14d97bSMichael Lotz #define IO_APIC_MAX_REDIRECTION_ENTRY_MASK 0xff 56dc14d97bSMichael Lotz 57dc14d97bSMichael Lotz // Fields of each redirection table entry 58dc14d97bSMichael Lotz #define IO_APIC_DESTINATION_FIELD_SHIFT 56 59f91cbddeSMichael Lotz #define IO_APIC_DESTINATION_FIELD_MASK 0xff 60dc14d97bSMichael Lotz #define IO_APIC_INTERRUPT_MASK_SHIFT 16 61dc14d97bSMichael Lotz #define IO_APIC_INTERRUPT_MASKED 1 62dc14d97bSMichael Lotz #define IO_APIC_INTERRUPT_UNMASKED 0 63dc14d97bSMichael Lotz #define IO_APIC_TRIGGER_MODE_SHIFT 15 64dc14d97bSMichael Lotz #define IO_APIC_TRIGGER_MODE_EDGE 0 65dc14d97bSMichael Lotz #define IO_APIC_TRIGGER_MODE_LEVEL 1 66dc14d97bSMichael Lotz #define IO_APIC_REMOTE_IRR_SHIFT 14 67dc14d97bSMichael Lotz #define IO_APIC_PIN_POLARITY_SHIFT 13 68dc14d97bSMichael Lotz #define IO_APIC_PIN_POLARITY_HIGH_ACTIVE 0 69dc14d97bSMichael Lotz #define IO_APIC_PIN_POLARITY_LOW_ACTIVE 1 70dc14d97bSMichael Lotz #define IO_APIC_DELIVERY_STATUS_SHIFT 12 71dc14d97bSMichael Lotz #define IO_APIC_DELIVERY_STATUS_IDLE 0 72dc14d97bSMichael Lotz #define IO_APIC_DELIVERY_STATUS_PENDING 1 73dc14d97bSMichael Lotz #define IO_APIC_DESTINATION_MODE_SHIFT 11 74dc14d97bSMichael Lotz #define IO_APIC_DESTINATION_MODE_PHYSICAL 0 75dc14d97bSMichael Lotz #define IO_APIC_DESTINATION_MODE_LOGICAL 1 76dc14d97bSMichael Lotz #define IO_APIC_DELIVERY_MODE_SHIFT 8 77dc14d97bSMichael Lotz #define IO_APIC_DELIVERY_MODE_MASK 0x07 78dc14d97bSMichael Lotz #define IO_APIC_DELIVERY_MODE_FIXED 0 79dc14d97bSMichael Lotz #define IO_APIC_DELIVERY_MODE_LOWEST_PRIO 1 80dc14d97bSMichael Lotz #define IO_APIC_DELIVERY_MODE_SMI 2 81dc14d97bSMichael Lotz #define IO_APIC_DELIVERY_MODE_NMI 4 82dc14d97bSMichael Lotz #define IO_APIC_DELIVERY_MODE_INIT 5 83dc14d97bSMichael Lotz #define IO_APIC_DELIVERY_MODE_EXT_INT 7 84dc14d97bSMichael Lotz #define IO_APIC_INTERRUPT_VECTOR_SHIFT 0 85dc14d97bSMichael Lotz #define IO_APIC_INTERRUPT_VECTOR_MASK 0xff 86dc14d97bSMichael Lotz 87*fb5a1727SMichael Lotz #define ISA_INTERRUPT_COUNT 16 88*fb5a1727SMichael Lotz 89dc14d97bSMichael Lotz 905d01e61aSMichael Lotz struct ioapic_registers { 91dc14d97bSMichael Lotz volatile uint32 io_register_select; 92dc14d97bSMichael Lotz uint32 reserved[3]; 93dc14d97bSMichael Lotz volatile uint32 io_window_register; 945d01e61aSMichael Lotz }; 95dc14d97bSMichael Lotz 96dc14d97bSMichael Lotz 975d01e61aSMichael Lotz struct ioapic { 985d01e61aSMichael Lotz uint8 number; 9963475256SMichael Lotz uint8 apic_id; 10063475256SMichael Lotz uint32 version; 1015d01e61aSMichael Lotz uint8 max_redirection_entry; 1025d01e61aSMichael Lotz uint8 global_interrupt_base; 1035d01e61aSMichael Lotz uint8 global_interrupt_last; 1045d01e61aSMichael Lotz uint64 level_triggered_mask; 1055d01e61aSMichael Lotz 1065d01e61aSMichael Lotz area_id register_area; 1075d01e61aSMichael Lotz ioapic_registers* registers; 1085d01e61aSMichael Lotz 1095d01e61aSMichael Lotz ioapic* next; 1105d01e61aSMichael Lotz }; 1115d01e61aSMichael Lotz 1125d01e61aSMichael Lotz 1138908aef9SMichael Lotz static ioapic* sIOAPICs = NULL; 114*fb5a1727SMichael Lotz static int32 sSourceOverrides[ISA_INTERRUPT_COUNT]; 115dc14d97bSMichael Lotz 116dc14d97bSMichael Lotz 117dc14d97bSMichael Lotz // #pragma mark - I/O APIC 118dc14d97bSMichael Lotz 119dc14d97bSMichael Lotz 12063475256SMichael Lotz static void 12163475256SMichael Lotz print_ioapic(struct ioapic& ioapic) 12263475256SMichael Lotz { 12363475256SMichael Lotz dprintf("io-apic %u has range %u-%u, %u entries, version 0x%08lx, " 12463475256SMichael Lotz "apic-id %u\n", ioapic.number, ioapic.global_interrupt_base, 12563475256SMichael Lotz ioapic.global_interrupt_last, ioapic.max_redirection_entry + 1, 12663475256SMichael Lotz ioapic.version, ioapic.apic_id); 12763475256SMichael Lotz } 12863475256SMichael Lotz 12963475256SMichael Lotz 1305d01e61aSMichael Lotz static inline struct ioapic* 1315d01e61aSMichael Lotz find_ioapic(int32 gsi) 132dc14d97bSMichael Lotz { 1335d01e61aSMichael Lotz if (gsi < 0) 1345d01e61aSMichael Lotz return NULL; 1355d01e61aSMichael Lotz 1368908aef9SMichael Lotz struct ioapic* current = sIOAPICs; 1375d01e61aSMichael Lotz while (current != NULL) { 1385d01e61aSMichael Lotz if (gsi >= current->global_interrupt_base 1395d01e61aSMichael Lotz && gsi <= current->global_interrupt_last) { 1405d01e61aSMichael Lotz return current; 1415d01e61aSMichael Lotz } 1425d01e61aSMichael Lotz 1435d01e61aSMichael Lotz current = current->next; 1445d01e61aSMichael Lotz } 1455d01e61aSMichael Lotz 1465d01e61aSMichael Lotz return NULL; 1475d01e61aSMichael Lotz } 1485d01e61aSMichael Lotz 1495d01e61aSMichael Lotz 1505d01e61aSMichael Lotz static inline uint32 1515d01e61aSMichael Lotz ioapic_read_32(struct ioapic& ioapic, uint8 registerSelect) 1525d01e61aSMichael Lotz { 1535d01e61aSMichael Lotz ioapic.registers->io_register_select = registerSelect; 1545d01e61aSMichael Lotz return ioapic.registers->io_window_register; 155dc14d97bSMichael Lotz } 156dc14d97bSMichael Lotz 157dc14d97bSMichael Lotz 158dc14d97bSMichael Lotz static inline void 1595d01e61aSMichael Lotz ioapic_write_32(struct ioapic& ioapic, uint8 registerSelect, uint32 value) 160dc14d97bSMichael Lotz { 1615d01e61aSMichael Lotz ioapic.registers->io_register_select = registerSelect; 1625d01e61aSMichael Lotz ioapic.registers->io_window_register = value; 163dc14d97bSMichael Lotz } 164dc14d97bSMichael Lotz 165dc14d97bSMichael Lotz 166dc14d97bSMichael Lotz static inline uint64 1675d01e61aSMichael Lotz ioapic_read_64(struct ioapic& ioapic, uint8 registerSelect) 168dc14d97bSMichael Lotz { 1695d01e61aSMichael Lotz ioapic.registers->io_register_select = registerSelect + 1; 1705d01e61aSMichael Lotz uint64 result = ioapic.registers->io_window_register; 171dc14d97bSMichael Lotz result <<= 32; 1725d01e61aSMichael Lotz ioapic.registers->io_register_select = registerSelect; 1735d01e61aSMichael Lotz result |= ioapic.registers->io_window_register; 174dc14d97bSMichael Lotz return result; 175dc14d97bSMichael Lotz } 176dc14d97bSMichael Lotz 177dc14d97bSMichael Lotz 178dc14d97bSMichael Lotz static inline void 1790798779aSMichael Lotz ioapic_write_64(struct ioapic& ioapic, uint8 registerSelect, uint64 value, 1800798779aSMichael Lotz bool maskFirst) 181dc14d97bSMichael Lotz { 1820798779aSMichael Lotz ioapic.registers->io_register_select 1830798779aSMichael Lotz = registerSelect + (maskFirst ? 0 : 1); 1840798779aSMichael Lotz ioapic.registers->io_window_register 1850798779aSMichael Lotz = (uint32)(value >> (maskFirst ? 0 : 32)); 1860798779aSMichael Lotz ioapic.registers->io_register_select 1870798779aSMichael Lotz = registerSelect + (maskFirst ? 1 : 0); 1880798779aSMichael Lotz ioapic.registers->io_window_register 1890798779aSMichael Lotz = (uint32)(value >> (maskFirst ? 32 : 0)); 190dc14d97bSMichael Lotz } 191dc14d97bSMichael Lotz 192dc14d97bSMichael Lotz 193dc14d97bSMichael Lotz static bool 194eda74390SMichael Lotz ioapic_is_spurious_interrupt(int32 gsi) 195dc14d97bSMichael Lotz { 196dc14d97bSMichael Lotz // the spurious interrupt vector is initialized to the max value in smp 197eda74390SMichael Lotz return gsi == 0xff - ARCH_INTERRUPT_BASE; 198dc14d97bSMichael Lotz } 199dc14d97bSMichael Lotz 200dc14d97bSMichael Lotz 201dc14d97bSMichael Lotz static bool 2025d01e61aSMichael Lotz ioapic_is_level_triggered_interrupt(int32 gsi) 203dc14d97bSMichael Lotz { 2045d01e61aSMichael Lotz struct ioapic* ioapic = find_ioapic(gsi); 2055d01e61aSMichael Lotz if (ioapic == NULL) 206dc14d97bSMichael Lotz return false; 207dc14d97bSMichael Lotz 2085d01e61aSMichael Lotz uint8 pin = gsi - ioapic->global_interrupt_base; 209f91cbddeSMichael Lotz return (ioapic->level_triggered_mask & ((uint64)1 << pin)) != 0; 210dc14d97bSMichael Lotz } 211dc14d97bSMichael Lotz 212dc14d97bSMichael Lotz 213dc14d97bSMichael Lotz static bool 214dc14d97bSMichael Lotz ioapic_end_of_interrupt(int32 num) 215dc14d97bSMichael Lotz { 216dc14d97bSMichael Lotz apic_end_of_interrupt(); 217dc14d97bSMichael Lotz return true; 218dc14d97bSMichael Lotz } 219dc14d97bSMichael Lotz 220dc14d97bSMichael Lotz 221dc14d97bSMichael Lotz static void 2225d01e61aSMichael Lotz ioapic_enable_io_interrupt(int32 gsi) 223dc14d97bSMichael Lotz { 224*fb5a1727SMichael Lotz // If enabling an overriden source is attempted, enable the override entry 225*fb5a1727SMichael Lotz // instead. An interrupt handler was installed at the override GSI to rely 226*fb5a1727SMichael Lotz // interrupts to the overriden source. 227*fb5a1727SMichael Lotz if (gsi < ISA_INTERRUPT_COUNT && sSourceOverrides[gsi] != 0) 228*fb5a1727SMichael Lotz gsi = sSourceOverrides[gsi]; 229*fb5a1727SMichael Lotz 2305d01e61aSMichael Lotz struct ioapic* ioapic = find_ioapic(gsi); 2315d01e61aSMichael Lotz if (ioapic == NULL) 232dc14d97bSMichael Lotz return; 233dc14d97bSMichael Lotz 2345d01e61aSMichael Lotz uint8 pin = gsi - ioapic->global_interrupt_base; 2355d01e61aSMichael Lotz TRACE(("ioapic_enable_io_interrupt: gsi %ld -> io-apic %u pin %u\n", 2365d01e61aSMichael Lotz gsi, ioapic->number, pin)); 237dc14d97bSMichael Lotz 2385d01e61aSMichael Lotz uint64 entry = ioapic_read_64(*ioapic, IO_APIC_REDIRECTION_TABLE + pin * 2); 239dc14d97bSMichael Lotz entry &= ~(1 << IO_APIC_INTERRUPT_MASK_SHIFT); 240dc14d97bSMichael Lotz entry |= IO_APIC_INTERRUPT_UNMASKED << IO_APIC_INTERRUPT_MASK_SHIFT; 2410798779aSMichael Lotz ioapic_write_64(*ioapic, IO_APIC_REDIRECTION_TABLE + pin * 2, entry, false); 242dc14d97bSMichael Lotz } 243dc14d97bSMichael Lotz 244dc14d97bSMichael Lotz 245dc14d97bSMichael Lotz static void 2465d01e61aSMichael Lotz ioapic_disable_io_interrupt(int32 gsi) 247dc14d97bSMichael Lotz { 2485d01e61aSMichael Lotz struct ioapic* ioapic = find_ioapic(gsi); 2495d01e61aSMichael Lotz if (ioapic == NULL) 250dc14d97bSMichael Lotz return; 251dc14d97bSMichael Lotz 2525d01e61aSMichael Lotz uint8 pin = gsi - ioapic->global_interrupt_base; 2535d01e61aSMichael Lotz TRACE(("ioapic_disable_io_interrupt: gsi %ld -> io-apic %u pin %u\n", 2545d01e61aSMichael Lotz gsi, ioapic->number, pin)); 255dc14d97bSMichael Lotz 2565d01e61aSMichael Lotz uint64 entry = ioapic_read_64(*ioapic, IO_APIC_REDIRECTION_TABLE + pin * 2); 257dc14d97bSMichael Lotz entry &= ~(1 << IO_APIC_INTERRUPT_MASK_SHIFT); 258dc14d97bSMichael Lotz entry |= IO_APIC_INTERRUPT_MASKED << IO_APIC_INTERRUPT_MASK_SHIFT; 2590798779aSMichael Lotz ioapic_write_64(*ioapic, IO_APIC_REDIRECTION_TABLE + pin * 2, entry, true); 260dc14d97bSMichael Lotz } 261dc14d97bSMichael Lotz 262dc14d97bSMichael Lotz 263dc14d97bSMichael Lotz static void 2645d01e61aSMichael Lotz ioapic_configure_io_interrupt(int32 gsi, uint32 config) 265dc14d97bSMichael Lotz { 2665d01e61aSMichael Lotz struct ioapic* ioapic = find_ioapic(gsi); 2675d01e61aSMichael Lotz if (ioapic == NULL) 268dc14d97bSMichael Lotz return; 269dc14d97bSMichael Lotz 2705d01e61aSMichael Lotz uint8 pin = gsi - ioapic->global_interrupt_base; 2715d01e61aSMichael Lotz TRACE(("ioapic_configure_io_interrupt: gsi %ld -> io-apic %u pin %u; " 2725d01e61aSMichael Lotz "config 0x%08lx\n", gsi, ioapic->number, pin, config)); 273dc14d97bSMichael Lotz 2745d01e61aSMichael Lotz uint64 entry = ioapic_read_64(*ioapic, IO_APIC_REDIRECTION_TABLE + pin * 2); 275dc14d97bSMichael Lotz entry &= ~((1 << IO_APIC_TRIGGER_MODE_SHIFT) 276dc14d97bSMichael Lotz | (1 << IO_APIC_PIN_POLARITY_SHIFT) 277dc14d97bSMichael Lotz | (IO_APIC_INTERRUPT_VECTOR_MASK << IO_APIC_INTERRUPT_VECTOR_SHIFT)); 278dc14d97bSMichael Lotz 279dc14d97bSMichael Lotz if (config & B_LEVEL_TRIGGERED) { 280dc14d97bSMichael Lotz entry |= (IO_APIC_TRIGGER_MODE_LEVEL << IO_APIC_TRIGGER_MODE_SHIFT); 281f91cbddeSMichael Lotz ioapic->level_triggered_mask |= ((uint64)1 << pin); 282dc14d97bSMichael Lotz } else { 283dc14d97bSMichael Lotz entry |= (IO_APIC_TRIGGER_MODE_EDGE << IO_APIC_TRIGGER_MODE_SHIFT); 284f91cbddeSMichael Lotz ioapic->level_triggered_mask &= ~((uint64)1 << pin); 285dc14d97bSMichael Lotz } 286dc14d97bSMichael Lotz 287dc14d97bSMichael Lotz if (config & B_LOW_ACTIVE_POLARITY) 288dc14d97bSMichael Lotz entry |= (IO_APIC_PIN_POLARITY_LOW_ACTIVE << IO_APIC_PIN_POLARITY_SHIFT); 289dc14d97bSMichael Lotz else 290dc14d97bSMichael Lotz entry |= (IO_APIC_PIN_POLARITY_HIGH_ACTIVE << IO_APIC_PIN_POLARITY_SHIFT); 291dc14d97bSMichael Lotz 292ca00b28eSMichael Lotz entry |= (gsi + ARCH_INTERRUPT_BASE) << IO_APIC_INTERRUPT_VECTOR_SHIFT; 2930798779aSMichael Lotz ioapic_write_64(*ioapic, IO_APIC_REDIRECTION_TABLE + pin * 2, entry, true); 2945d01e61aSMichael Lotz } 2955d01e61aSMichael Lotz 2965d01e61aSMichael Lotz 2975d01e61aSMichael Lotz static status_t 2985d01e61aSMichael Lotz ioapic_map_ioapic(struct ioapic& ioapic, phys_addr_t physicalAddress) 2995d01e61aSMichael Lotz { 3005d01e61aSMichael Lotz ioapic.register_area = vm_map_physical_memory(B_SYSTEM_TEAM, "io-apic", 3015d01e61aSMichael Lotz (void**)&ioapic.registers, ioapic.registers != NULL ? B_EXACT_ADDRESS 3025d01e61aSMichael Lotz : B_ANY_KERNEL_ADDRESS, B_PAGE_SIZE, B_KERNEL_READ_AREA 303d11e32a8SMichael Lotz | B_KERNEL_WRITE_AREA, physicalAddress, ioapic.registers != NULL); 3045d01e61aSMichael Lotz if (ioapic.register_area < 0) { 3055d01e61aSMichael Lotz panic("mapping io-apic %u failed", ioapic.number); 3065d01e61aSMichael Lotz return ioapic.register_area; 3075d01e61aSMichael Lotz } 3085d01e61aSMichael Lotz 309d11e32a8SMichael Lotz dprintf("mapped io-apic %u to %p\n", ioapic.number, ioapic.registers); 310d11e32a8SMichael Lotz 31163475256SMichael Lotz ioapic.version = ioapic_read_32(ioapic, IO_APIC_VERSION); 31263475256SMichael Lotz if (ioapic.version == 0xffffffff) { 3135d01e61aSMichael Lotz dprintf("io-apic %u seems inaccessible, not using it\n", 3145d01e61aSMichael Lotz ioapic.number); 3155d01e61aSMichael Lotz vm_delete_area(B_SYSTEM_TEAM, ioapic.register_area, true); 3165d01e61aSMichael Lotz ioapic.register_area = -1; 3175d01e61aSMichael Lotz ioapic.registers = NULL; 3185d01e61aSMichael Lotz return B_ERROR; 3195d01e61aSMichael Lotz } 3205d01e61aSMichael Lotz 3215d01e61aSMichael Lotz ioapic.max_redirection_entry 32263475256SMichael Lotz = ((ioapic.version >> IO_APIC_MAX_REDIRECTION_ENTRY_SHIFT) 3235d01e61aSMichael Lotz & IO_APIC_MAX_REDIRECTION_ENTRY_MASK); 3245d01e61aSMichael Lotz 3255d01e61aSMichael Lotz ioapic.global_interrupt_last 3265d01e61aSMichael Lotz = ioapic.global_interrupt_base + ioapic.max_redirection_entry; 3275d01e61aSMichael Lotz 3285d01e61aSMichael Lotz return B_OK; 3295d01e61aSMichael Lotz } 3305d01e61aSMichael Lotz 3315d01e61aSMichael Lotz 3325d01e61aSMichael Lotz static status_t 33363475256SMichael Lotz ioapic_initialize_ioapic(struct ioapic& ioapic, uint8 targetAPIC) 3345d01e61aSMichael Lotz { 33563475256SMichael Lotz // program the APIC ID 33663475256SMichael Lotz ioapic_write_32(ioapic, IO_APIC_ID, ioapic.apic_id << IO_APIC_ID_SHIFT); 33763475256SMichael Lotz 3385d01e61aSMichael Lotz // program the interrupt vectors of the io-apic 3395d01e61aSMichael Lotz ioapic.level_triggered_mask = 0; 340e9d55697SMichael Lotz uint8 gsi = ioapic.global_interrupt_base; 341e9d55697SMichael Lotz for (uint8 i = 0; i <= ioapic.max_redirection_entry; i++, gsi++) { 3425d01e61aSMichael Lotz // initialize everything to deliver to the boot CPU in physical mode 3435d01e61aSMichael Lotz // and masked until explicitly enabled through enable_io_interrupt() 34463475256SMichael Lotz uint64 entry = ((uint64)targetAPIC << IO_APIC_DESTINATION_FIELD_SHIFT) 3455d01e61aSMichael Lotz | (IO_APIC_INTERRUPT_MASKED << IO_APIC_INTERRUPT_MASK_SHIFT) 3465d01e61aSMichael Lotz | (IO_APIC_DESTINATION_MODE_PHYSICAL << IO_APIC_DESTINATION_MODE_SHIFT) 3477a8ce431SMichael Lotz | ((gsi + ARCH_INTERRUPT_BASE) << IO_APIC_INTERRUPT_VECTOR_SHIFT); 3485d01e61aSMichael Lotz 349e9d55697SMichael Lotz if (gsi == 0) { 350e9d55697SMichael Lotz // make GSI 0 into an external interrupt 3515d01e61aSMichael Lotz entry |= (IO_APIC_TRIGGER_MODE_EDGE << IO_APIC_TRIGGER_MODE_SHIFT) 3525d01e61aSMichael Lotz | (IO_APIC_PIN_POLARITY_HIGH_ACTIVE << IO_APIC_PIN_POLARITY_SHIFT) 3535d01e61aSMichael Lotz | (IO_APIC_DELIVERY_MODE_EXT_INT << IO_APIC_DELIVERY_MODE_SHIFT); 354*fb5a1727SMichael Lotz } else if (gsi < ISA_INTERRUPT_COUNT) { 355*fb5a1727SMichael Lotz // identity map the legacy ISA interrupts 3565d01e61aSMichael Lotz entry |= (IO_APIC_TRIGGER_MODE_EDGE << IO_APIC_TRIGGER_MODE_SHIFT) 3575d01e61aSMichael Lotz | (IO_APIC_PIN_POLARITY_HIGH_ACTIVE << IO_APIC_PIN_POLARITY_SHIFT) 3585d01e61aSMichael Lotz | (IO_APIC_DELIVERY_MODE_FIXED << IO_APIC_DELIVERY_MODE_SHIFT); 3595d01e61aSMichael Lotz } else { 3605d01e61aSMichael Lotz // and the rest are PCI interrupts 3615d01e61aSMichael Lotz entry |= (IO_APIC_TRIGGER_MODE_LEVEL << IO_APIC_TRIGGER_MODE_SHIFT) 3625d01e61aSMichael Lotz | (IO_APIC_PIN_POLARITY_LOW_ACTIVE << IO_APIC_PIN_POLARITY_SHIFT) 3635d01e61aSMichael Lotz | (IO_APIC_DELIVERY_MODE_FIXED << IO_APIC_DELIVERY_MODE_SHIFT); 364f91cbddeSMichael Lotz ioapic.level_triggered_mask |= ((uint64)1 << i); 3655d01e61aSMichael Lotz } 3665d01e61aSMichael Lotz 3670798779aSMichael Lotz ioapic_write_64(ioapic, IO_APIC_REDIRECTION_TABLE + 2 * i, entry, true); 3685d01e61aSMichael Lotz } 3695d01e61aSMichael Lotz 3705d01e61aSMichael Lotz return B_OK; 371dc14d97bSMichael Lotz } 372dc14d97bSMichael Lotz 373dc14d97bSMichael Lotz 374*fb5a1727SMichael Lotz static int32 375*fb5a1727SMichael Lotz ioapic_source_override_handler(void* data) 376d11e32a8SMichael Lotz { 377*fb5a1727SMichael Lotz int32 vector = (int32)data; 378*fb5a1727SMichael Lotz bool levelTriggered = ioapic_is_level_triggered_interrupt(vector); 379*fb5a1727SMichael Lotz return int_io_interrupt_handler(vector, levelTriggered); 380d11e32a8SMichael Lotz } 381d11e32a8SMichael Lotz 382*fb5a1727SMichael Lotz 383*fb5a1727SMichael Lotz static status_t 384*fb5a1727SMichael Lotz acpi_enumerate_ioapics(acpi_table_madt* madt) 385*fb5a1727SMichael Lotz { 3868908aef9SMichael Lotz struct ioapic* lastIOAPIC = sIOAPICs; 387d11e32a8SMichael Lotz 388d11e32a8SMichael Lotz acpi_subtable_header* apicEntry 389d11e32a8SMichael Lotz = (acpi_subtable_header*)((uint8*)madt + sizeof(acpi_table_madt)); 390d11e32a8SMichael Lotz void* end = ((uint8*)madt + madt->Header.Length); 391d11e32a8SMichael Lotz while (apicEntry < end) { 392d11e32a8SMichael Lotz switch (apicEntry->Type) { 393d11e32a8SMichael Lotz case ACPI_MADT_TYPE_IO_APIC: 394d11e32a8SMichael Lotz { 395d11e32a8SMichael Lotz acpi_madt_io_apic* info = (acpi_madt_io_apic*)apicEntry; 39663475256SMichael Lotz dprintf("found io-apic with address 0x%08lx, global " 39763475256SMichael Lotz "interrupt base %lu, apic-id %u\n", (uint32)info->Address, 39863475256SMichael Lotz (uint32)info->GlobalIrqBase, info->Id); 399d11e32a8SMichael Lotz 400d11e32a8SMichael Lotz struct ioapic* ioapic 401d11e32a8SMichael Lotz = (struct ioapic*)malloc(sizeof(struct ioapic)); 402d11e32a8SMichael Lotz if (ioapic == NULL) { 403d11e32a8SMichael Lotz dprintf("ran out of memory while allocating io-apic " 404d11e32a8SMichael Lotz "structure\n"); 405d11e32a8SMichael Lotz return B_NO_MEMORY; 406d11e32a8SMichael Lotz } 407d11e32a8SMichael Lotz 4088908aef9SMichael Lotz ioapic->number 4098908aef9SMichael Lotz = lastIOAPIC != NULL ? lastIOAPIC->number + 1 : 0; 41063475256SMichael Lotz ioapic->apic_id = info->Id; 411d11e32a8SMichael Lotz ioapic->global_interrupt_base = info->GlobalIrqBase; 412d11e32a8SMichael Lotz ioapic->registers = NULL; 413d11e32a8SMichael Lotz ioapic->next = NULL; 414d11e32a8SMichael Lotz 415d11e32a8SMichael Lotz dprintf("mapping io-apic %u at physical address %p\n", 416d11e32a8SMichael Lotz ioapic->number, (void*)info->Address); 417d11e32a8SMichael Lotz status_t status = ioapic_map_ioapic(*ioapic, info->Address); 41863475256SMichael Lotz if (status != B_OK) { 41963475256SMichael Lotz free(ioapic); 42063475256SMichael Lotz break; 42163475256SMichael Lotz } 42263475256SMichael Lotz 42363475256SMichael Lotz print_ioapic(*ioapic); 4248908aef9SMichael Lotz 4258908aef9SMichael Lotz if (lastIOAPIC == NULL) 4268908aef9SMichael Lotz sIOAPICs = ioapic; 4278908aef9SMichael Lotz else 428d11e32a8SMichael Lotz lastIOAPIC->next = ioapic; 4298908aef9SMichael Lotz 430d11e32a8SMichael Lotz lastIOAPIC = ioapic; 431d11e32a8SMichael Lotz break; 432d11e32a8SMichael Lotz } 433*fb5a1727SMichael Lotz } 434*fb5a1727SMichael Lotz 435*fb5a1727SMichael Lotz apicEntry 436*fb5a1727SMichael Lotz = (acpi_subtable_header*)((uint8*)apicEntry + apicEntry->Length); 437*fb5a1727SMichael Lotz } 438*fb5a1727SMichael Lotz 439*fb5a1727SMichael Lotz return B_OK; 440*fb5a1727SMichael Lotz } 441*fb5a1727SMichael Lotz 442*fb5a1727SMichael Lotz 443*fb5a1727SMichael Lotz static void 444*fb5a1727SMichael Lotz acpi_configure_source_overrides(acpi_table_madt* madt) 445*fb5a1727SMichael Lotz { 446*fb5a1727SMichael Lotz acpi_subtable_header* apicEntry 447*fb5a1727SMichael Lotz = (acpi_subtable_header*)((uint8*)madt + sizeof(acpi_table_madt)); 448*fb5a1727SMichael Lotz void* end = ((uint8*)madt + madt->Header.Length); 449*fb5a1727SMichael Lotz while (apicEntry < end) { 450*fb5a1727SMichael Lotz switch (apicEntry->Type) { 451*fb5a1727SMichael Lotz case ACPI_MADT_TYPE_INTERRUPT_OVERRIDE: 452*fb5a1727SMichael Lotz { 453*fb5a1727SMichael Lotz acpi_madt_interrupt_override* info 454*fb5a1727SMichael Lotz = (acpi_madt_interrupt_override*)apicEntry; 455*fb5a1727SMichael Lotz dprintf("found interrupt override for bus %u, source irq %u, " 456*fb5a1727SMichael Lotz "global irq %lu, flags 0x%08lx\n", info->Bus, 457*fb5a1727SMichael Lotz info->SourceIrq, (uint32)info->GlobalIrq, 458*fb5a1727SMichael Lotz (uint32)info->IntiFlags); 459*fb5a1727SMichael Lotz 460*fb5a1727SMichael Lotz if (info->SourceIrq >= ISA_INTERRUPT_COUNT) { 461*fb5a1727SMichael Lotz dprintf("source override exceeds isa interrupt count\n"); 462*fb5a1727SMichael Lotz break; 463*fb5a1727SMichael Lotz } 464*fb5a1727SMichael Lotz 465*fb5a1727SMichael Lotz if (info->SourceIrq != info->GlobalIrq) { 466*fb5a1727SMichael Lotz // we need a vector mapping 467*fb5a1727SMichael Lotz install_io_interrupt_handler(info->GlobalIrq, 468*fb5a1727SMichael Lotz &ioapic_source_override_handler, (void*)info->SourceIrq, 469*fb5a1727SMichael Lotz B_NO_ENABLE_COUNTER); 470*fb5a1727SMichael Lotz 471*fb5a1727SMichael Lotz sSourceOverrides[info->SourceIrq] = info->GlobalIrq; 472*fb5a1727SMichael Lotz } 473*fb5a1727SMichael Lotz 474*fb5a1727SMichael Lotz // configure non-standard polarity/trigger modes 475*fb5a1727SMichael Lotz uint32 config = 0; 476*fb5a1727SMichael Lotz switch (info->IntiFlags & ACPI_MADT_POLARITY_MASK) { 477*fb5a1727SMichael Lotz case ACPI_MADT_POLARITY_ACTIVE_LOW: 478*fb5a1727SMichael Lotz config = B_LOW_ACTIVE_POLARITY; 479*fb5a1727SMichael Lotz break; 480*fb5a1727SMichael Lotz default: 481*fb5a1727SMichael Lotz dprintf("invalid polarity in source override\n"); 482*fb5a1727SMichael Lotz // fall through and assume active high 483*fb5a1727SMichael Lotz case ACPI_MADT_POLARITY_ACTIVE_HIGH: 484*fb5a1727SMichael Lotz case ACPI_MADT_POLARITY_CONFORMS: 485*fb5a1727SMichael Lotz config = B_HIGH_ACTIVE_POLARITY; 486*fb5a1727SMichael Lotz break; 487*fb5a1727SMichael Lotz } 488*fb5a1727SMichael Lotz 489*fb5a1727SMichael Lotz switch (info->IntiFlags & ACPI_MADT_TRIGGER_MASK) { 490*fb5a1727SMichael Lotz case ACPI_MADT_TRIGGER_LEVEL: 491*fb5a1727SMichael Lotz config |= B_LEVEL_TRIGGERED; 492*fb5a1727SMichael Lotz break; 493*fb5a1727SMichael Lotz default: 494*fb5a1727SMichael Lotz dprintf("invalid trigger mode in source override\n"); 495*fb5a1727SMichael Lotz // fall through and assume edge triggered 496*fb5a1727SMichael Lotz case ACPI_MADT_TRIGGER_CONFORMS: 497*fb5a1727SMichael Lotz case ACPI_MADT_TRIGGER_EDGE: 498*fb5a1727SMichael Lotz config |= B_EDGE_TRIGGERED; 499*fb5a1727SMichael Lotz break; 500*fb5a1727SMichael Lotz } 501*fb5a1727SMichael Lotz 502*fb5a1727SMichael Lotz ioapic_configure_io_interrupt(info->GlobalIrq, config); 503*fb5a1727SMichael Lotz break; 504*fb5a1727SMichael Lotz } 5050414a203SMichael Lotz 5060414a203SMichael Lotz #ifdef TRACE_IOAPIC 5070414a203SMichael Lotz case ACPI_MADT_TYPE_LOCAL_APIC: 5080414a203SMichael Lotz { 5090414a203SMichael Lotz // purely informational 5100414a203SMichael Lotz acpi_madt_local_apic* info = (acpi_madt_local_apic*)apicEntry; 5110414a203SMichael Lotz dprintf("found local apic with id %u, processor id %u, " 5120414a203SMichael Lotz "flags 0x%08lx\n", info->Id, info->ProcessorId, 5130414a203SMichael Lotz (uint32)info->LapicFlags); 5140414a203SMichael Lotz break; 5150414a203SMichael Lotz } 5160414a203SMichael Lotz 5170414a203SMichael Lotz case ACPI_MADT_TYPE_NMI_SOURCE: 5180414a203SMichael Lotz { 5190414a203SMichael Lotz // TODO: take these into account 5200414a203SMichael Lotz acpi_madt_nmi_source* info 5210414a203SMichael Lotz = (acpi_madt_nmi_source*)apicEntry; 5220414a203SMichael Lotz dprintf("found nmi source global irq %lu, flags 0x%04x\n", 5230414a203SMichael Lotz (uint32)info->GlobalIrq, (uint16)info->IntiFlags); 5240414a203SMichael Lotz break; 5250414a203SMichael Lotz } 5260414a203SMichael Lotz 5270414a203SMichael Lotz case ACPI_MADT_TYPE_LOCAL_APIC_NMI: 5280414a203SMichael Lotz { 5290414a203SMichael Lotz // TODO: take these into account, but at apic.cpp 5300414a203SMichael Lotz acpi_madt_local_apic_nmi* info 5310414a203SMichael Lotz = (acpi_madt_local_apic_nmi*)apicEntry; 5320414a203SMichael Lotz dprintf("found local apic nmi source for processor %u, " 5330414a203SMichael Lotz "flags 0x%04x, local int %u\n", info->ProcessorId, 5340414a203SMichael Lotz (uint16)info->IntiFlags, info->Lint); 5350414a203SMichael Lotz break; 5360414a203SMichael Lotz } 5370414a203SMichael Lotz 5380414a203SMichael Lotz case ACPI_MADT_TYPE_LOCAL_APIC_OVERRIDE: 5390414a203SMichael Lotz { 5400414a203SMichael Lotz // TODO: take these into account, but at apic.cpp 5410414a203SMichael Lotz acpi_madt_local_apic_override* info 5420414a203SMichael Lotz = (acpi_madt_local_apic_override*)apicEntry; 5430414a203SMichael Lotz dprintf("found local apic override with address 0x%016llx\n", 5440414a203SMichael Lotz (uint64)info->Address); 5450414a203SMichael Lotz break; 5460414a203SMichael Lotz } 5470414a203SMichael Lotz 5480414a203SMichael Lotz default: 5490414a203SMichael Lotz dprintf("found unhandled subtable of type %u length %u\n", 5500414a203SMichael Lotz apicEntry->Type, apicEntry->Length); 5510414a203SMichael Lotz break; 5520414a203SMichael Lotz #endif 553d11e32a8SMichael Lotz } 554d11e32a8SMichael Lotz 555d11e32a8SMichael Lotz apicEntry 556d11e32a8SMichael Lotz = (acpi_subtable_header*)((uint8*)apicEntry + apicEntry->Length); 557d11e32a8SMichael Lotz } 558d11e32a8SMichael Lotz } 559d11e32a8SMichael Lotz 560d11e32a8SMichael Lotz 561d11e32a8SMichael Lotz static status_t 562dc14d97bSMichael Lotz acpi_set_interrupt_model(acpi_module_info* acpiModule, uint32 interruptModel) 563dc14d97bSMichael Lotz { 564dc14d97bSMichael Lotz acpi_object_type model; 565dc14d97bSMichael Lotz model.object_type = ACPI_TYPE_INTEGER; 566dc14d97bSMichael Lotz model.data.integer = interruptModel; 567dc14d97bSMichael Lotz 568dc14d97bSMichael Lotz acpi_objects parameter; 569dc14d97bSMichael Lotz parameter.count = 1; 570dc14d97bSMichael Lotz parameter.pointer = &model; 571dc14d97bSMichael Lotz 572dc14d97bSMichael Lotz dprintf("setting ACPI interrupt model to %s\n", 573dc14d97bSMichael Lotz interruptModel == 0 ? "PIC" 574dc14d97bSMichael Lotz : (interruptModel == 1 ? "APIC" 575dc14d97bSMichael Lotz : (interruptModel == 2 ? "SAPIC" 576dc14d97bSMichael Lotz : "unknown"))); 577dc14d97bSMichael Lotz 578dc14d97bSMichael Lotz return acpiModule->evaluate_method(NULL, "\\_PIC", ¶meter, NULL); 579dc14d97bSMichael Lotz } 580dc14d97bSMichael Lotz 581dc14d97bSMichael Lotz 582a56cbb2aSMichael Lotz bool 583a56cbb2aSMichael Lotz ioapic_is_interrupt_available(int32 gsi) 584a56cbb2aSMichael Lotz { 585a56cbb2aSMichael Lotz return find_ioapic(gsi) != NULL; 586a56cbb2aSMichael Lotz } 587a56cbb2aSMichael Lotz 588a56cbb2aSMichael Lotz 589dc14d97bSMichael Lotz void 590dc14d97bSMichael Lotz ioapic_init(kernel_args* args) 591dc14d97bSMichael Lotz { 592dc14d97bSMichael Lotz static const interrupt_controller ioapicController = { 593dc14d97bSMichael Lotz "82093AA IOAPIC", 594dc14d97bSMichael Lotz &ioapic_enable_io_interrupt, 595dc14d97bSMichael Lotz &ioapic_disable_io_interrupt, 596dc14d97bSMichael Lotz &ioapic_configure_io_interrupt, 597dc14d97bSMichael Lotz &ioapic_is_spurious_interrupt, 598dc14d97bSMichael Lotz &ioapic_is_level_triggered_interrupt, 599dc14d97bSMichael Lotz &ioapic_end_of_interrupt 600dc14d97bSMichael Lotz }; 601dc14d97bSMichael Lotz 6028908aef9SMichael Lotz if (args->arch_args.apic == NULL) 603dc14d97bSMichael Lotz return; 604dc14d97bSMichael Lotz 6058908aef9SMichael Lotz if (args->arch_args.ioapic_phys == 0) { 6068908aef9SMichael Lotz dprintf("no io-apics available, not using io-apics for interrupt " 6078908aef9SMichael Lotz "routing\n"); 6088908aef9SMichael Lotz return; 6098908aef9SMichael Lotz } 6108908aef9SMichael Lotz 611dc14d97bSMichael Lotz if (get_safemode_boolean(B_SAFEMODE_DISABLE_IOAPIC, false)) { 6125d01e61aSMichael Lotz dprintf("io-apics explicitly disabled, not using io-apics for " 6135d01e61aSMichael Lotz "interrupt routing\n"); 614dc14d97bSMichael Lotz return; 615dc14d97bSMichael Lotz } 616dc14d97bSMichael Lotz 617dc14d97bSMichael Lotz // load acpi module 618dc14d97bSMichael Lotz status_t status; 619dc14d97bSMichael Lotz acpi_module_info* acpiModule; 620dc14d97bSMichael Lotz status = get_module(B_ACPI_MODULE_NAME, (module_info**)&acpiModule); 621dc14d97bSMichael Lotz if (status != B_OK) { 6225d01e61aSMichael Lotz dprintf("acpi module not available, not configuring io-apics\n"); 623dc14d97bSMichael Lotz return; 624dc14d97bSMichael Lotz } 625dc14d97bSMichael Lotz BPrivate::CObjectDeleter<const char, status_t> 626dc14d97bSMichael Lotz acpiModulePutter(B_ACPI_MODULE_NAME, put_module); 627dc14d97bSMichael Lotz 628*fb5a1727SMichael Lotz acpi_table_madt* madt = NULL; 629*fb5a1727SMichael Lotz if (acpiModule->get_table(ACPI_SIG_MADT, 0, (void**)&madt) != B_OK) { 630*fb5a1727SMichael Lotz dprintf("failed to get MADT from ACPI, not configuring io-apics\n"); 631*fb5a1727SMichael Lotz return; 632*fb5a1727SMichael Lotz } 633*fb5a1727SMichael Lotz 634*fb5a1727SMichael Lotz status = acpi_enumerate_ioapics(madt); 635d11e32a8SMichael Lotz if (status != B_OK) { 636ca67ddb3SMichael Lotz // We don't treat this case as fatal just yet. If we are able to 637ca67ddb3SMichael Lotz // route everything with the available IO-APICs we're fine, if not 638ca67ddb3SMichael Lotz // we will fail at the routing preparation stage further down. 639ca67ddb3SMichael Lotz dprintf("failed to enumerate all io-apics, working with what we got\n"); 640d11e32a8SMichael Lotz } 641d11e32a8SMichael Lotz 642d11e32a8SMichael Lotz // switch to the APIC interrupt model before retrieving the IRQ routing 643dc14d97bSMichael Lotz // table as it will return different settings depending on the model 644dc14d97bSMichael Lotz status = acpi_set_interrupt_model(acpiModule, ACPI_INTERRUPT_MODEL_APIC); 645dc14d97bSMichael Lotz if (status != B_OK) { 646dc14d97bSMichael Lotz dprintf("failed to put ACPI into APIC interrupt model, ignoring\n"); 647dc14d97bSMichael Lotz // don't abort, as the _PIC method is optional and as long as there 648dc14d97bSMichael Lotz // aren't different routings based on it this is non-fatal 649dc14d97bSMichael Lotz } 650dc14d97bSMichael Lotz 651dc14d97bSMichael Lotz IRQRoutingTable table; 652dc14d97bSMichael Lotz status = prepare_irq_routing(acpiModule, table, 653eda74390SMichael Lotz &ioapic_is_interrupt_available); 654dc14d97bSMichael Lotz if (status != B_OK) { 6555d01e61aSMichael Lotz dprintf("IRQ routing preparation failed, not configuring io-apics\n"); 656dc14d97bSMichael Lotz acpi_set_interrupt_model(acpiModule, ACPI_INTERRUPT_MODEL_PIC); 657dc14d97bSMichael Lotz // revert to PIC interrupt model just in case 658dc14d97bSMichael Lotz return; 659dc14d97bSMichael Lotz } 660dc14d97bSMichael Lotz 661dc14d97bSMichael Lotz print_irq_routing_table(table); 662dc14d97bSMichael Lotz 6635d01e61aSMichael Lotz // use the boot CPU as the target for all interrupts 66463475256SMichael Lotz uint8 targetAPIC = args->arch_args.cpu_apic_id[0]; 6655d01e61aSMichael Lotz 6668908aef9SMichael Lotz struct ioapic* current = sIOAPICs; 6675d01e61aSMichael Lotz while (current != NULL) { 6685d01e61aSMichael Lotz status = ioapic_initialize_ioapic(*current, targetAPIC); 6695d01e61aSMichael Lotz if (status != B_OK) { 6705d01e61aSMichael Lotz panic("failed to initialize io-apic %u", current->number); 6715d01e61aSMichael Lotz acpi_set_interrupt_model(acpiModule, ACPI_INTERRUPT_MODEL_PIC); 6725d01e61aSMichael Lotz return; 6735d01e61aSMichael Lotz } 6745d01e61aSMichael Lotz 6755d01e61aSMichael Lotz current = current->next; 6765d01e61aSMichael Lotz } 6775d01e61aSMichael Lotz 678dc14d97bSMichael Lotz status = enable_irq_routing(acpiModule, table); 679dc14d97bSMichael Lotz if (status != B_OK) { 680dc14d97bSMichael Lotz panic("failed to enable IRQ routing"); 681dc14d97bSMichael Lotz // if it failed early on it might still work in PIC mode 682dc14d97bSMichael Lotz acpi_set_interrupt_model(acpiModule, ACPI_INTERRUPT_MODEL_PIC); 683dc14d97bSMichael Lotz return; 684dc14d97bSMichael Lotz } 685dc14d97bSMichael Lotz 686*fb5a1727SMichael Lotz // configure the source overrides, but let the PCI config below override it 687*fb5a1727SMichael Lotz acpi_configure_source_overrides(madt); 688*fb5a1727SMichael Lotz 6895d01e61aSMichael Lotz // configure IO-APIC interrupts from PCI routing table 690dc14d97bSMichael Lotz for (int i = 0; i < table.Count(); i++) { 691dc14d97bSMichael Lotz irq_routing_entry& entry = table.ElementAt(i); 692dc14d97bSMichael Lotz ioapic_configure_io_interrupt(entry.irq, 693dc14d97bSMichael Lotz entry.polarity | entry.trigger_mode); 694dc14d97bSMichael Lotz } 695dc14d97bSMichael Lotz 696a56cbb2aSMichael Lotz // kill the local ints on the local APIC 697a56cbb2aSMichael Lotz apic_disable_local_ints(); 698a56cbb2aSMichael Lotz // TODO: This uses the assumption that our init is running on the 699a56cbb2aSMichael Lotz // boot CPU and only the boot CPU has the local ints configured 700a56cbb2aSMichael Lotz // because it was running in legacy PIC mode. Possibly the other 701a56cbb2aSMichael Lotz // local APICs of the other CPUs have them configured as well. It 702a56cbb2aSMichael Lotz // shouldn't really harm, but should eventually be corrected. 703a56cbb2aSMichael Lotz 704dc14d97bSMichael Lotz // disable the legacy PIC 705*fb5a1727SMichael Lotz uint16 legacyInterrupts; 706*fb5a1727SMichael Lotz pic_disable(legacyInterrupts); 707*fb5a1727SMichael Lotz 708*fb5a1727SMichael Lotz // enable previsouly enabled legacy interrupts 709*fb5a1727SMichael Lotz for (uint8 i = 0; i < 16; i++) { 710*fb5a1727SMichael Lotz if ((legacyInterrupts & (1 << i)) != 0) 711*fb5a1727SMichael Lotz ioapic_enable_io_interrupt(i); 712*fb5a1727SMichael Lotz } 713dc14d97bSMichael Lotz 714dc14d97bSMichael Lotz // prefer the ioapic over the normal pic 7155d01e61aSMichael Lotz dprintf("using io-apics for interrupt routing\n"); 716dc14d97bSMichael Lotz arch_int_set_interrupt_controller(ioapicController); 717dc14d97bSMichael Lotz } 718