diff --git a/headers/private/kernel/arch/x86/arch_int.h b/headers/private/kernel/arch/x86/arch_int.h index c745551c81..2768b396c9 100644 --- a/headers/private/kernel/arch/x86/arch_int.h +++ b/headers/private/kernel/arch/x86/arch_int.h @@ -57,4 +57,17 @@ arch_int_are_interrupts_enabled_inline(void) arch_int_are_interrupts_enabled_inline() +typedef struct interrupt_controller_s { + const char *name; + void (*enable_io_interrupt)(int32 num); + void (*disable_io_interrupt)(int32 num); + void (*configure_io_interrupt)(int32 num, uint32 config); + bool (*is_spurious_interrupt)(int32 num); + bool (*is_level_triggered_interrupt)(int32 num); + bool (*end_of_interrupt)(int32 num); +} interrupt_controller; + + +void arch_int_set_interrupt_controller(const interrupt_controller &controller); + #endif /* _KERNEL_ARCH_x86_INT_H */ diff --git a/headers/private/kernel/arch/x86/ioapic.h b/headers/private/kernel/arch/x86/ioapic.h new file mode 100644 index 0000000000..b0195d0b38 --- /dev/null +++ b/headers/private/kernel/arch/x86/ioapic.h @@ -0,0 +1,13 @@ +/* + * Copyright 2011, Michael Lotz, mmlr@mlotz.ch. + * Distributed under the terms of the MIT License. + */ +#ifndef _KERNEL_ARCH_x86_IOAPIC_H +#define _KERNEL_ARCH_x86_IOAPIC_H + +struct kernel_args; + +void ioapic_map(kernel_args* args); +void ioapic_init(kernel_args* args); + +#endif // _KERNEL_ARCH_x86_IOAPIC_H diff --git a/headers/private/kernel/arch/x86/pic.h b/headers/private/kernel/arch/x86/pic.h new file mode 100644 index 0000000000..8943454bcd --- /dev/null +++ b/headers/private/kernel/arch/x86/pic.h @@ -0,0 +1,11 @@ +/* + * Copyright 2011, Michael Lotz, mmlr@mlotz.ch. + * Distributed under the terms of the MIT License. + */ +#ifndef _KERNEL_ARCH_x86_PIC_H +#define _KERNEL_ARCH_x86_PIC_H + +void pic_init(); +void pic_disable(); + +#endif // _KERNEL_ARCH_x86_PIC_H diff --git a/src/system/kernel/arch/x86/Jamfile b/src/system/kernel/arch/x86/Jamfile index 1c1891ac2c..7c3d75a491 100644 --- a/src/system/kernel/arch/x86/Jamfile +++ b/src/system/kernel/arch/x86/Jamfile @@ -39,8 +39,10 @@ KernelMergeObject kernel_arch_x86.o : apm.cpp bios.cpp cpuid.S + ioapic.cpp irq_routing_table.cpp msi.cpp + pic.cpp syscall.S vm86.cpp diff --git a/src/system/kernel/arch/x86/arch_int.cpp b/src/system/kernel/arch/x86/arch_int.cpp index 8b1563b042..17ffabd692 100644 --- a/src/system/kernel/arch/x86/arch_int.cpp +++ b/src/system/kernel/arch/x86/arch_int.cpp @@ -31,14 +31,13 @@ #include #include "interrupts.h" -#include "irq_routing_table.h" -#include -#include -#include -#include #include +// interrupt controllers +#include +#include + //#define TRACE_ARCH_INT #ifdef TRACE_ARCH_INT @@ -48,108 +47,6 @@ #endif -// Definitions for the PIC 8259 controller -// (this is not a complete list, only what we're actually using) - -#define PIC_MASTER_CONTROL 0x20 -#define PIC_MASTER_MASK 0x21 -#define PIC_SLAVE_CONTROL 0xa0 -#define PIC_SLAVE_MASK 0xa1 -#define PIC_MASTER_INIT1 PIC_MASTER_CONTROL -#define PIC_MASTER_INIT2 PIC_MASTER_MASK -#define PIC_MASTER_INIT3 PIC_MASTER_MASK -#define PIC_MASTER_INIT4 PIC_MASTER_MASK -#define PIC_SLAVE_INIT1 PIC_SLAVE_CONTROL -#define PIC_SLAVE_INIT2 PIC_SLAVE_MASK -#define PIC_SLAVE_INIT3 PIC_SLAVE_MASK -#define PIC_SLAVE_INIT4 PIC_SLAVE_MASK - -// the edge/level trigger control registers -#define PIC_MASTER_TRIGGER_MODE 0x4d0 -#define PIC_SLAVE_TRIGGER_MODE 0x4d1 - -#define PIC_INIT1 0x10 -#define PIC_INIT1_SEND_INIT4 0x01 -#define PIC_INIT3_IR2_IS_SLAVE 0x04 -#define PIC_INIT3_SLAVE_ID2 0x02 -#define PIC_INIT4_x86_MODE 0x01 - -#define PIC_CONTROL3 0x08 -#define PIC_CONTROL3_READ_ISR 0x03 -#define PIC_CONTROL3_READ_IRR 0x02 - -#define PIC_NON_SPECIFIC_EOI 0x20 - -#define PIC_SLAVE_INT_BASE 8 -#define PIC_NUM_INTS 0x0f - - -// ACPI interrupt models -#define ACPI_INTERRUPT_MODEL_PIC 0 -#define ACPI_INTERRUPT_MODEL_APIC 1 -#define ACPI_INTERRUPT_MODEL_SAPIC 2 - - -// Definitions for a 82093AA IO APIC controller -#define IO_APIC_IDENTIFICATION 0x00 -#define IO_APIC_VERSION 0x01 -#define IO_APIC_ARBITRATION 0x02 -#define IO_APIC_REDIRECTION_TABLE 0x10 // entry = base + 2 * index - -// Fields for the version register -#define IO_APIC_VERSION_SHIFT 0 -#define IO_APIC_VERSION_MASK 0xff -#define IO_APIC_MAX_REDIRECTION_ENTRY_SHIFT 16 -#define IO_APIC_MAX_REDIRECTION_ENTRY_MASK 0xff - -// Fields of each redirection table entry -#define IO_APIC_DESTINATION_FIELD_SHIFT 56 -#define IO_APIC_DESTINATION_FIELD_MASK 0x0f -#define IO_APIC_INTERRUPT_MASK_SHIFT 16 -#define IO_APIC_INTERRUPT_MASKED 1 -#define IO_APIC_INTERRUPT_UNMASKED 0 -#define IO_APIC_TRIGGER_MODE_SHIFT 15 -#define IO_APIC_TRIGGER_MODE_EDGE 0 -#define IO_APIC_TRIGGER_MODE_LEVEL 1 -#define IO_APIC_REMOTE_IRR_SHIFT 14 -#define IO_APIC_PIN_POLARITY_SHIFT 13 -#define IO_APIC_PIN_POLARITY_HIGH_ACTIVE 0 -#define IO_APIC_PIN_POLARITY_LOW_ACTIVE 1 -#define IO_APIC_DELIVERY_STATUS_SHIFT 12 -#define IO_APIC_DELIVERY_STATUS_IDLE 0 -#define IO_APIC_DELIVERY_STATUS_PENDING 1 -#define IO_APIC_DESTINATION_MODE_SHIFT 11 -#define IO_APIC_DESTINATION_MODE_PHYSICAL 0 -#define IO_APIC_DESTINATION_MODE_LOGICAL 1 -#define IO_APIC_DELIVERY_MODE_SHIFT 8 -#define IO_APIC_DELIVERY_MODE_MASK 0x07 -#define IO_APIC_DELIVERY_MODE_FIXED 0 -#define IO_APIC_DELIVERY_MODE_LOWEST_PRIO 1 -#define IO_APIC_DELIVERY_MODE_SMI 2 -#define IO_APIC_DELIVERY_MODE_NMI 4 -#define IO_APIC_DELIVERY_MODE_INIT 5 -#define IO_APIC_DELIVERY_MODE_EXT_INT 7 -#define IO_APIC_INTERRUPT_VECTOR_SHIFT 0 -#define IO_APIC_INTERRUPT_VECTOR_MASK 0xff - -typedef struct ioapic_s { - volatile uint32 io_register_select; - uint32 reserved[3]; - volatile uint32 io_window_register; -} ioapic; - -static ioapic *sIOAPIC = NULL; -static uint32 sIOAPICMaxRedirectionEntry = 23; - -typedef struct interrupt_controller_s { - const char *name; - void (*enable_io_interrupt)(int32 num); - void (*disable_io_interrupt)(int32 num); - void (*configure_io_interrupt)(int32 num, uint32 config); - bool (*is_spurious_interrupt)(int32 num); - bool (*end_of_interrupt)(int32 num); -} interrupt_controller; - static const interrupt_controller *sCurrentPIC = NULL; static const char *kInterruptNames[] = { @@ -183,9 +80,6 @@ typedef struct { } desc_table; static desc_table* sIDTs[B_MAX_CPU_COUNT]; -static uint32 sLevelTriggeredInterrupts = 0; - // binary mask: 1 level, 0 edge - // table with functions handling respective interrupts typedef void interrupt_handler_function(struct iframe* frame); #define INTERRUPT_HANDLER_TABLE_SIZE 256 @@ -256,476 +150,6 @@ x86_get_idt(int32 cpu) } -// #pragma mark - PIC - - -/*! Tests if the interrupt in-service register of the responsible - PIC is set for interrupts 7 and 15, and if that's not the case, - it must assume it's a spurious interrupt. -*/ -static bool -pic_is_spurious_interrupt(int32 num) -{ - if (num != 7) - return false; - - // Note, detecting spurious interrupts on line 15 obviously doesn't - // work correctly - and since those are extremely rare, anyway, we - // just ignore them - - out8(PIC_CONTROL3 | PIC_CONTROL3_READ_ISR, PIC_MASTER_CONTROL); - int32 isr = in8(PIC_MASTER_CONTROL); - out8(PIC_CONTROL3 | PIC_CONTROL3_READ_IRR, PIC_MASTER_CONTROL); - - return (isr & 0x80) == 0; -} - - -/*! Sends a non-specified EOI (end of interrupt) notice to the PIC in - question (or both of them). - This clears the PIC interrupt in-service bit. -*/ -static bool -pic_end_of_interrupt(int32 num) -{ - if (num < 0 || num > PIC_NUM_INTS) - return false; - - // PIC 8259 controlled interrupt - if (num >= PIC_SLAVE_INT_BASE) - out8(PIC_NON_SPECIFIC_EOI, PIC_SLAVE_CONTROL); - - // we always need to acknowledge the master PIC - out8(PIC_NON_SPECIFIC_EOI, PIC_MASTER_CONTROL); - return true; -} - - -static void -pic_enable_io_interrupt(int32 num) -{ - // interrupt is specified "normalized" - if (num < 0 || num > PIC_NUM_INTS) - return; - - // enable PIC 8259 controlled interrupt - - TRACE(("pic_enable_io_interrupt: irq %ld\n", num)); - - if (num < PIC_SLAVE_INT_BASE) - out8(in8(PIC_MASTER_MASK) & ~(1 << num), PIC_MASTER_MASK); - else - out8(in8(PIC_SLAVE_MASK) & ~(1 << (num - PIC_SLAVE_INT_BASE)), PIC_SLAVE_MASK); -} - - -static void -pic_disable_io_interrupt(int32 num) -{ - // interrupt is specified "normalized" - // never disable slave pic line IRQ 2 - if (num < 0 || num > PIC_NUM_INTS || num == 2) - return; - - // disable PIC 8259 controlled interrupt - - TRACE(("pic_disable_io_interrupt: irq %ld\n", num)); - - if (num < PIC_SLAVE_INT_BASE) - out8(in8(PIC_MASTER_MASK) | (1 << num), PIC_MASTER_MASK); - else - out8(in8(PIC_SLAVE_MASK) | (1 << (num - PIC_SLAVE_INT_BASE)), PIC_SLAVE_MASK); -} - - -static void -pic_configure_io_interrupt(int32 num, uint32 config) -{ - uint8 value; - int32 localBit; - if (num < 0 || num > PIC_NUM_INTS || num == 2) - return; - - TRACE(("pic_configure_io_interrupt: irq %ld; config 0x%08lx\n", num, config)); - - if (num < PIC_SLAVE_INT_BASE) { - value = in8(PIC_MASTER_TRIGGER_MODE); - localBit = num; - } else { - value = in8(PIC_SLAVE_TRIGGER_MODE); - localBit = num - PIC_SLAVE_INT_BASE; - } - - if (config & B_LEVEL_TRIGGERED) - value |= 1 << localBit; - else - value &= ~(1 << localBit); - - if (num < PIC_SLAVE_INT_BASE) - out8(value, PIC_MASTER_TRIGGER_MODE); - else - out8(value, PIC_SLAVE_TRIGGER_MODE); - - sLevelTriggeredInterrupts = in8(PIC_MASTER_TRIGGER_MODE) - | (in8(PIC_SLAVE_TRIGGER_MODE) << 8); -} - - -static void -pic_init(void) -{ - static interrupt_controller picController = { - "8259 PIC", - &pic_enable_io_interrupt, - &pic_disable_io_interrupt, - &pic_configure_io_interrupt, - &pic_is_spurious_interrupt, - &pic_end_of_interrupt - }; - - // Start initialization sequence for the master and slave PICs - out8(PIC_INIT1 | PIC_INIT1_SEND_INIT4, PIC_MASTER_INIT1); - out8(PIC_INIT1 | PIC_INIT1_SEND_INIT4, PIC_SLAVE_INIT1); - - // Set start of interrupts to 0x20 for master, 0x28 for slave - out8(ARCH_INTERRUPT_BASE, PIC_MASTER_INIT2); - out8(ARCH_INTERRUPT_BASE + PIC_SLAVE_INT_BASE, PIC_SLAVE_INIT2); - - // Specify cascading through interrupt 2 - out8(PIC_INIT3_IR2_IS_SLAVE, PIC_MASTER_INIT3); - out8(PIC_INIT3_SLAVE_ID2, PIC_SLAVE_INIT3); - - // Set both to operate in 8086 mode - out8(PIC_INIT4_x86_MODE, PIC_MASTER_INIT4); - out8(PIC_INIT4_x86_MODE, PIC_SLAVE_INIT4); - - out8(0xfb, PIC_MASTER_MASK); // Mask off all interrupts (except slave pic line IRQ 2). - out8(0xff, PIC_SLAVE_MASK); // Mask off interrupts on the slave. - - // determine which interrupts are level or edge triggered - -#if 0 - // should set everything possible to level triggered - out8(0xf8, PIC_MASTER_TRIGGER_MODE); - out8(0xde, PIC_SLAVE_TRIGGER_MODE); -#endif - - sLevelTriggeredInterrupts = in8(PIC_MASTER_TRIGGER_MODE) - | (in8(PIC_SLAVE_TRIGGER_MODE) << 8); - - TRACE(("PIC level trigger mode: 0x%08lx\n", sLevelTriggeredInterrupts)); - - // make the pic controller the current one - sCurrentPIC = &picController; -} - - -static void -pic_disable() -{ - // Mask off all interrupts on master and slave - out8(0xff, PIC_MASTER_MASK); - out8(0xff, PIC_SLAVE_MASK); -} - - -// #pragma mark - I/O APIC - - -static inline uint32 -ioapic_read_32(uint8 registerSelect) -{ - sIOAPIC->io_register_select = registerSelect; - return sIOAPIC->io_window_register; -} - - -static inline void -ioapic_write_32(uint8 registerSelect, uint32 value) -{ - sIOAPIC->io_register_select = registerSelect; - sIOAPIC->io_window_register = value; -} - - -static inline uint64 -ioapic_read_64(uint8 registerSelect) -{ - sIOAPIC->io_register_select = registerSelect + 1; - uint64 result = sIOAPIC->io_window_register; - result <<= 32; - sIOAPIC->io_register_select = registerSelect; - result |= sIOAPIC->io_window_register; - return result; -} - - -static inline void -ioapic_write_64(uint8 registerSelect, uint64 value) -{ - sIOAPIC->io_register_select = registerSelect; - sIOAPIC->io_window_register = (uint32)value; - sIOAPIC->io_register_select = registerSelect + 1; - sIOAPIC->io_window_register = (uint32)(value >> 32); -} - - -static bool -ioapic_is_spurious_interrupt(int32 num) -{ - // the spurious interrupt vector is initialized to the max value in smp - return num == 0xff - ARCH_INTERRUPT_BASE; -} - - -static bool -ioapic_end_of_interrupt(int32 num) -{ - apic_end_of_interrupt(); - return true; -} - - -static void -ioapic_enable_io_interrupt(int32 pin) -{ - if (pin < 0 || pin > (int32)sIOAPICMaxRedirectionEntry) - return; - - TRACE(("ioapic_enable_io_interrupt: pin %ld\n", pin)); - - uint64 entry = ioapic_read_64(IO_APIC_REDIRECTION_TABLE + pin * 2); - entry &= ~(1 << IO_APIC_INTERRUPT_MASK_SHIFT); - entry |= IO_APIC_INTERRUPT_UNMASKED << IO_APIC_INTERRUPT_MASK_SHIFT; - ioapic_write_64(IO_APIC_REDIRECTION_TABLE + pin * 2, entry); -} - - -static void -ioapic_disable_io_interrupt(int32 pin) -{ - if (pin < 0 || pin > (int32)sIOAPICMaxRedirectionEntry) - return; - - TRACE(("ioapic_disable_io_interrupt: pin %ld\n", pin)); - - uint64 entry = ioapic_read_64(IO_APIC_REDIRECTION_TABLE + pin * 2); - entry &= ~(1 << IO_APIC_INTERRUPT_MASK_SHIFT); - entry |= IO_APIC_INTERRUPT_MASKED << IO_APIC_INTERRUPT_MASK_SHIFT; - ioapic_write_64(IO_APIC_REDIRECTION_TABLE + pin * 2, entry); -} - - -static void -ioapic_configure_io_interrupt(int32 pin, uint32 config) -{ - if (pin < 0 || pin > (int32)sIOAPICMaxRedirectionEntry) - return; - - TRACE(("ioapic_configure_io_interrupt: pin %ld; config 0x%08lx\n", pin, - config)); - - uint64 entry = ioapic_read_64(IO_APIC_REDIRECTION_TABLE + pin * 2); - entry &= ~((1 << IO_APIC_TRIGGER_MODE_SHIFT) - | (1 << IO_APIC_PIN_POLARITY_SHIFT) - | (IO_APIC_INTERRUPT_VECTOR_MASK << IO_APIC_INTERRUPT_VECTOR_SHIFT)); - - if (config & B_LEVEL_TRIGGERED) { - entry |= (IO_APIC_TRIGGER_MODE_LEVEL << IO_APIC_TRIGGER_MODE_SHIFT); - sLevelTriggeredInterrupts |= (1 << pin); - } else { - entry |= (IO_APIC_TRIGGER_MODE_EDGE << IO_APIC_TRIGGER_MODE_SHIFT); - sLevelTriggeredInterrupts &= ~(1 << pin); - } - - if (config & B_LOW_ACTIVE_POLARITY) - entry |= (IO_APIC_PIN_POLARITY_LOW_ACTIVE << IO_APIC_PIN_POLARITY_SHIFT); - else - entry |= (IO_APIC_PIN_POLARITY_HIGH_ACTIVE << IO_APIC_PIN_POLARITY_SHIFT); - - entry |= (pin + ARCH_INTERRUPT_BASE) << IO_APIC_INTERRUPT_VECTOR_SHIFT; - ioapic_write_64(IO_APIC_REDIRECTION_TABLE + pin * 2, entry); -} - - -static void -ioapic_map(kernel_args* args) -{ - if (args->arch_args.apic == NULL) { - dprintf("no local apic available\n"); - return; - } - - if (args->arch_args.ioapic == NULL) { - dprintf("no ioapic available, not using ioapics for interrupt routing\n"); - return; - } - - // map in the ioapic - sIOAPIC = (ioapic *)args->arch_args.ioapic; - if (vm_map_physical_memory(B_SYSTEM_TEAM, "ioapic", (void**)&sIOAPIC, - B_EXACT_ADDRESS, B_PAGE_SIZE, - B_KERNEL_READ_AREA | B_KERNEL_WRITE_AREA, - args->arch_args.ioapic_phys, true) < 0) { - panic("mapping the ioapic failed"); - return; - } -} - - -static status_t -acpi_set_interrupt_model(acpi_module_info* acpiModule, uint32 interruptModel) -{ - acpi_object_type model; - model.object_type = ACPI_TYPE_INTEGER; - model.data.integer = interruptModel; - - acpi_objects parameter; - parameter.count = 1; - parameter.pointer = &model; - - dprintf("setting ACPI interrupt model to %s\n", - interruptModel == 0 ? "PIC" - : (interruptModel == 1 ? "APIC" - : (interruptModel == 2 ? "SAPIC" - : "unknown"))); - - return acpiModule->evaluate_method(NULL, "\\_PIC", ¶meter, NULL); -} - - -static void -ioapic_init(kernel_args* args) -{ - static const interrupt_controller ioapicController = { - "82093AA IOAPIC", - &ioapic_enable_io_interrupt, - &ioapic_disable_io_interrupt, - &ioapic_configure_io_interrupt, - &ioapic_is_spurious_interrupt, - &ioapic_end_of_interrupt - }; - - if (sIOAPIC == NULL) - return; - -#if 0 - if (get_safemode_boolean(B_SAFEMODE_DISABLE_IOAPIC, false)) { - dprintf("ioapic explicitly disabled, not using ioapics for interrupt " - "routing\n"); - return; - } -#else - // TODO: This can be removed once IO-APIC code is broadly tested - if (!get_safemode_boolean(B_SAFEMODE_ENABLE_IOAPIC, false)) { - dprintf("ioapic not enabled, not using ioapics for interrupt " - "routing\n"); - return; - } -#endif - - uint32 version = ioapic_read_32(IO_APIC_VERSION); - if (version == 0xffffffff) { - dprintf("ioapic seems inaccessible, not using it\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 ioapic\n"); - return; - } - BPrivate::CObjectDeleter - acpiModulePutter(B_ACPI_MODULE_NAME, put_module); - - // switch to the APIC interrupt model before retrieving the irq routing - // table as it will return different settings depending on the model - status = acpi_set_interrupt_model(acpiModule, ACPI_INTERRUPT_MODEL_APIC); - if (status != B_OK) { - dprintf("failed to put ACPI into APIC interrupt model, ignoring\n"); - // don't abort, as the _PIC method is optional and as long as there - // aren't different routings based on it this is non-fatal - } - - sLevelTriggeredInterrupts = 0; - sIOAPICMaxRedirectionEntry - = ((version >> IO_APIC_MAX_REDIRECTION_ENTRY_SHIFT) - & IO_APIC_MAX_REDIRECTION_ENTRY_MASK); - - TRACE(("ioapic has %lu entries\n", sIOAPICMaxRedirectionEntry + 1)); - - IRQRoutingTable table; - status = prepare_irq_routing(acpiModule, table, - sIOAPICMaxRedirectionEntry + 1); - if (status != B_OK) { - dprintf("IRQ routing preparation failed, not configuring ioapic.\n"); - acpi_set_interrupt_model(acpiModule, ACPI_INTERRUPT_MODEL_PIC); - // revert to PIC interrupt model just in case - return; - } - - print_irq_routing_table(table); - - 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; - } - - // use the boot CPU as the target for all interrupts - uint64 targetAPIC = args->arch_args.cpu_apic_id[0]; - - // program the interrupt vectors of the ioapic - for (uint32 i = 0; i <= sIOAPICMaxRedirectionEntry; i++) { - // initialize everything to deliver to the boot CPU in physical mode - // and masked until explicitly enabled through enable_io_interrupt() - uint64 entry = (targetAPIC << IO_APIC_DESTINATION_FIELD_SHIFT) - | (IO_APIC_INTERRUPT_MASKED << IO_APIC_INTERRUPT_MASK_SHIFT) - | (IO_APIC_DESTINATION_MODE_PHYSICAL << IO_APIC_DESTINATION_MODE_SHIFT) - | ((i + ARCH_INTERRUPT_BASE) << IO_APIC_INTERRUPT_VECTOR_SHIFT); - - if (i == 0) { - // make redirection entry 0 into an external interrupt - entry |= (IO_APIC_TRIGGER_MODE_EDGE << IO_APIC_TRIGGER_MODE_SHIFT) - | (IO_APIC_PIN_POLARITY_HIGH_ACTIVE << IO_APIC_PIN_POLARITY_SHIFT) - | (IO_APIC_DELIVERY_MODE_EXT_INT << IO_APIC_DELIVERY_MODE_SHIFT); - } else if (i < 16) { - // make 1-15 ISA interrupts - entry |= (IO_APIC_TRIGGER_MODE_EDGE << IO_APIC_TRIGGER_MODE_SHIFT) - | (IO_APIC_PIN_POLARITY_HIGH_ACTIVE << IO_APIC_PIN_POLARITY_SHIFT) - | (IO_APIC_DELIVERY_MODE_FIXED << IO_APIC_DELIVERY_MODE_SHIFT); - } else { - // and the rest are PCI interrupts - entry |= (IO_APIC_TRIGGER_MODE_LEVEL << IO_APIC_TRIGGER_MODE_SHIFT) - | (IO_APIC_PIN_POLARITY_LOW_ACTIVE << IO_APIC_PIN_POLARITY_SHIFT) - | (IO_APIC_DELIVERY_MODE_FIXED << IO_APIC_DELIVERY_MODE_SHIFT); - sLevelTriggeredInterrupts |= (1 << i); - } - - ioapic_write_64(IO_APIC_REDIRECTION_TABLE + 2 * i, entry); - } - - // 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); - } - - // disable the legacy PIC - pic_disable(); - - // prefer the ioapic over the normal pic - dprintf("using ioapic for interrupt routing\n"); - sCurrentPIC = &ioapicController; -} - - // #pragma mark - @@ -1057,8 +481,7 @@ hardware_interrupt(struct iframe* frame) return; } - if (vector < 32) - levelTriggered = (sLevelTriggeredInterrupts & (1 << vector)) != 0; + levelTriggered = sCurrentPIC->is_level_triggered_interrupt(vector); if (!levelTriggered) { // if it's not handled by the current pic then it's an apic generated @@ -1452,3 +875,10 @@ arch_int_init_post_device_manager(struct kernel_args *args) { return B_OK; } + + +void +arch_int_set_interrupt_controller(const interrupt_controller &controller) +{ + sCurrentPIC = &controller; +} diff --git a/src/system/kernel/arch/x86/ioapic.cpp b/src/system/kernel/arch/x86/ioapic.cpp new file mode 100644 index 0000000000..2f255a7efa --- /dev/null +++ b/src/system/kernel/arch/x86/ioapic.cpp @@ -0,0 +1,399 @@ +/* + * Copyright 2008-2011, Michael Lotz, mmlr@mlotz.ch. + * Distributed under the terms of the MIT License. + */ + +#include + +#include +#include + +#include "irq_routing_table.h" + +#include +#include +#include +#include +#include + +#include +#include +#include + + +//#define TRACE_IOAPIC +#ifdef TRACE_IOAPIC +# define TRACE(x) dprintf x +#else +# define TRACE(x) ; +#endif + + +// ACPI interrupt models +#define ACPI_INTERRUPT_MODEL_PIC 0 +#define ACPI_INTERRUPT_MODEL_APIC 1 +#define ACPI_INTERRUPT_MODEL_SAPIC 2 + + +// Definitions for a 82093AA IO APIC controller +#define IO_APIC_IDENTIFICATION 0x00 +#define IO_APIC_VERSION 0x01 +#define IO_APIC_ARBITRATION 0x02 +#define IO_APIC_REDIRECTION_TABLE 0x10 // entry = base + 2 * index + +// Fields for the version register +#define IO_APIC_VERSION_SHIFT 0 +#define IO_APIC_VERSION_MASK 0xff +#define IO_APIC_MAX_REDIRECTION_ENTRY_SHIFT 16 +#define IO_APIC_MAX_REDIRECTION_ENTRY_MASK 0xff + +// Fields of each redirection table entry +#define IO_APIC_DESTINATION_FIELD_SHIFT 56 +#define IO_APIC_DESTINATION_FIELD_MASK 0x0f +#define IO_APIC_INTERRUPT_MASK_SHIFT 16 +#define IO_APIC_INTERRUPT_MASKED 1 +#define IO_APIC_INTERRUPT_UNMASKED 0 +#define IO_APIC_TRIGGER_MODE_SHIFT 15 +#define IO_APIC_TRIGGER_MODE_EDGE 0 +#define IO_APIC_TRIGGER_MODE_LEVEL 1 +#define IO_APIC_REMOTE_IRR_SHIFT 14 +#define IO_APIC_PIN_POLARITY_SHIFT 13 +#define IO_APIC_PIN_POLARITY_HIGH_ACTIVE 0 +#define IO_APIC_PIN_POLARITY_LOW_ACTIVE 1 +#define IO_APIC_DELIVERY_STATUS_SHIFT 12 +#define IO_APIC_DELIVERY_STATUS_IDLE 0 +#define IO_APIC_DELIVERY_STATUS_PENDING 1 +#define IO_APIC_DESTINATION_MODE_SHIFT 11 +#define IO_APIC_DESTINATION_MODE_PHYSICAL 0 +#define IO_APIC_DESTINATION_MODE_LOGICAL 1 +#define IO_APIC_DELIVERY_MODE_SHIFT 8 +#define IO_APIC_DELIVERY_MODE_MASK 0x07 +#define IO_APIC_DELIVERY_MODE_FIXED 0 +#define IO_APIC_DELIVERY_MODE_LOWEST_PRIO 1 +#define IO_APIC_DELIVERY_MODE_SMI 2 +#define IO_APIC_DELIVERY_MODE_NMI 4 +#define IO_APIC_DELIVERY_MODE_INIT 5 +#define IO_APIC_DELIVERY_MODE_EXT_INT 7 +#define IO_APIC_INTERRUPT_VECTOR_SHIFT 0 +#define IO_APIC_INTERRUPT_VECTOR_MASK 0xff + + +typedef struct ioapic_s { + volatile uint32 io_register_select; + uint32 reserved[3]; + volatile uint32 io_window_register; +} ioapic; + +static ioapic *sIOAPIC = NULL; +static uint32 sIOAPICMaxRedirectionEntry = 23; + +static uint64 sLevelTriggeredInterrupts = 0; + // binary mask: 1 level, 0 edge + + +// #pragma mark - I/O APIC + + +static inline uint32 +ioapic_read_32(uint8 registerSelect) +{ + sIOAPIC->io_register_select = registerSelect; + return sIOAPIC->io_window_register; +} + + +static inline void +ioapic_write_32(uint8 registerSelect, uint32 value) +{ + sIOAPIC->io_register_select = registerSelect; + sIOAPIC->io_window_register = value; +} + + +static inline uint64 +ioapic_read_64(uint8 registerSelect) +{ + sIOAPIC->io_register_select = registerSelect + 1; + uint64 result = sIOAPIC->io_window_register; + result <<= 32; + sIOAPIC->io_register_select = registerSelect; + result |= sIOAPIC->io_window_register; + return result; +} + + +static inline void +ioapic_write_64(uint8 registerSelect, uint64 value) +{ + sIOAPIC->io_register_select = registerSelect; + sIOAPIC->io_window_register = (uint32)value; + sIOAPIC->io_register_select = registerSelect + 1; + sIOAPIC->io_window_register = (uint32)(value >> 32); +} + + +static bool +ioapic_is_spurious_interrupt(int32 num) +{ + // the spurious interrupt vector is initialized to the max value in smp + return num == 0xff - ARCH_INTERRUPT_BASE; +} + + +static bool +ioapic_is_level_triggered_interrupt(int32 pin) +{ + if (pin < 0 || pin > (int32)sIOAPICMaxRedirectionEntry) + return false; + + return (sLevelTriggeredInterrupts & (1 << pin)) != 0; +} + + +static bool +ioapic_end_of_interrupt(int32 num) +{ + apic_end_of_interrupt(); + return true; +} + + +static void +ioapic_enable_io_interrupt(int32 pin) +{ + if (pin < 0 || pin > (int32)sIOAPICMaxRedirectionEntry) + return; + + TRACE(("ioapic_enable_io_interrupt: pin %ld\n", pin)); + + uint64 entry = ioapic_read_64(IO_APIC_REDIRECTION_TABLE + pin * 2); + entry &= ~(1 << IO_APIC_INTERRUPT_MASK_SHIFT); + entry |= IO_APIC_INTERRUPT_UNMASKED << IO_APIC_INTERRUPT_MASK_SHIFT; + ioapic_write_64(IO_APIC_REDIRECTION_TABLE + pin * 2, entry); +} + + +static void +ioapic_disable_io_interrupt(int32 pin) +{ + if (pin < 0 || pin > (int32)sIOAPICMaxRedirectionEntry) + return; + + TRACE(("ioapic_disable_io_interrupt: pin %ld\n", pin)); + + uint64 entry = ioapic_read_64(IO_APIC_REDIRECTION_TABLE + pin * 2); + entry &= ~(1 << IO_APIC_INTERRUPT_MASK_SHIFT); + entry |= IO_APIC_INTERRUPT_MASKED << IO_APIC_INTERRUPT_MASK_SHIFT; + ioapic_write_64(IO_APIC_REDIRECTION_TABLE + pin * 2, entry); +} + + +static void +ioapic_configure_io_interrupt(int32 pin, uint32 config) +{ + if (pin < 0 || pin > (int32)sIOAPICMaxRedirectionEntry) + return; + + TRACE(("ioapic_configure_io_interrupt: pin %ld; config 0x%08lx\n", pin, + config)); + + uint64 entry = ioapic_read_64(IO_APIC_REDIRECTION_TABLE + pin * 2); + entry &= ~((1 << IO_APIC_TRIGGER_MODE_SHIFT) + | (1 << IO_APIC_PIN_POLARITY_SHIFT) + | (IO_APIC_INTERRUPT_VECTOR_MASK << IO_APIC_INTERRUPT_VECTOR_SHIFT)); + + if (config & B_LEVEL_TRIGGERED) { + entry |= (IO_APIC_TRIGGER_MODE_LEVEL << IO_APIC_TRIGGER_MODE_SHIFT); + sLevelTriggeredInterrupts |= (1 << pin); + } else { + entry |= (IO_APIC_TRIGGER_MODE_EDGE << IO_APIC_TRIGGER_MODE_SHIFT); + sLevelTriggeredInterrupts &= ~(1 << pin); + } + + if (config & B_LOW_ACTIVE_POLARITY) + entry |= (IO_APIC_PIN_POLARITY_LOW_ACTIVE << IO_APIC_PIN_POLARITY_SHIFT); + else + entry |= (IO_APIC_PIN_POLARITY_HIGH_ACTIVE << IO_APIC_PIN_POLARITY_SHIFT); + + entry |= (pin + ARCH_INTERRUPT_BASE) << IO_APIC_INTERRUPT_VECTOR_SHIFT; + ioapic_write_64(IO_APIC_REDIRECTION_TABLE + pin * 2, entry); +} + + +static status_t +acpi_set_interrupt_model(acpi_module_info* acpiModule, uint32 interruptModel) +{ + acpi_object_type model; + model.object_type = ACPI_TYPE_INTEGER; + model.data.integer = interruptModel; + + acpi_objects parameter; + parameter.count = 1; + parameter.pointer = &model; + + dprintf("setting ACPI interrupt model to %s\n", + interruptModel == 0 ? "PIC" + : (interruptModel == 1 ? "APIC" + : (interruptModel == 2 ? "SAPIC" + : "unknown"))); + + return acpiModule->evaluate_method(NULL, "\\_PIC", ¶meter, NULL); +} + + +void +ioapic_map(kernel_args* args) +{ + if (args->arch_args.apic == NULL) { + dprintf("no local apic available\n"); + return; + } + + if (args->arch_args.ioapic == NULL) { + dprintf("no ioapic available, not using ioapics for interrupt routing\n"); + return; + } + + // map in the (first) IO-APIC + sIOAPIC = (ioapic *)args->arch_args.ioapic; + if (vm_map_physical_memory(B_SYSTEM_TEAM, "ioapic", (void**)&sIOAPIC, + B_EXACT_ADDRESS, B_PAGE_SIZE, + B_KERNEL_READ_AREA | B_KERNEL_WRITE_AREA, + args->arch_args.ioapic_phys, true) < 0) { + panic("mapping the ioapic failed"); + return; + } +} + + +void +ioapic_init(kernel_args* args) +{ + static const interrupt_controller ioapicController = { + "82093AA IOAPIC", + &ioapic_enable_io_interrupt, + &ioapic_disable_io_interrupt, + &ioapic_configure_io_interrupt, + &ioapic_is_spurious_interrupt, + &ioapic_is_level_triggered_interrupt, + &ioapic_end_of_interrupt + }; + + if (sIOAPIC == NULL) + return; + +#if 0 + if (get_safemode_boolean(B_SAFEMODE_DISABLE_IOAPIC, false)) { + dprintf("ioapic explicitly disabled, not using ioapics for interrupt " + "routing\n"); + return; + } +#else + // TODO: This can be removed once IO-APIC code is broadly tested + if (!get_safemode_boolean(B_SAFEMODE_ENABLE_IOAPIC, false)) { + dprintf("ioapic not enabled, not using ioapics for interrupt " + "routing\n"); + return; + } +#endif + + uint32 version = ioapic_read_32(IO_APIC_VERSION); + if (version == 0xffffffff) { + dprintf("ioapic seems inaccessible, not using it\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 ioapic\n"); + return; + } + BPrivate::CObjectDeleter + acpiModulePutter(B_ACPI_MODULE_NAME, put_module); + + // switch to the APIC interrupt model before retrieving the irq routing + // table as it will return different settings depending on the model + status = acpi_set_interrupt_model(acpiModule, ACPI_INTERRUPT_MODEL_APIC); + if (status != B_OK) { + dprintf("failed to put ACPI into APIC interrupt model, ignoring\n"); + // don't abort, as the _PIC method is optional and as long as there + // aren't different routings based on it this is non-fatal + } + + sLevelTriggeredInterrupts = 0; + sIOAPICMaxRedirectionEntry + = ((version >> IO_APIC_MAX_REDIRECTION_ENTRY_SHIFT) + & IO_APIC_MAX_REDIRECTION_ENTRY_MASK); + + TRACE(("ioapic has %lu entries\n", sIOAPICMaxRedirectionEntry + 1)); + + IRQRoutingTable table; + status = prepare_irq_routing(acpiModule, table, + sIOAPICMaxRedirectionEntry + 1); + if (status != B_OK) { + dprintf("IRQ routing preparation failed, not configuring ioapic.\n"); + acpi_set_interrupt_model(acpiModule, ACPI_INTERRUPT_MODEL_PIC); + // revert to PIC interrupt model just in case + return; + } + + print_irq_routing_table(table); + + 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; + } + + // use the boot CPU as the target for all interrupts + uint64 targetAPIC = args->arch_args.cpu_apic_id[0]; + + // program the interrupt vectors of the ioapic + for (uint32 i = 0; i <= sIOAPICMaxRedirectionEntry; i++) { + // initialize everything to deliver to the boot CPU in physical mode + // and masked until explicitly enabled through enable_io_interrupt() + uint64 entry = (targetAPIC << IO_APIC_DESTINATION_FIELD_SHIFT) + | (IO_APIC_INTERRUPT_MASKED << IO_APIC_INTERRUPT_MASK_SHIFT) + | (IO_APIC_DESTINATION_MODE_PHYSICAL << IO_APIC_DESTINATION_MODE_SHIFT) + | ((i + ARCH_INTERRUPT_BASE) << IO_APIC_INTERRUPT_VECTOR_SHIFT); + + if (i == 0) { + // make redirection entry 0 into an external interrupt + entry |= (IO_APIC_TRIGGER_MODE_EDGE << IO_APIC_TRIGGER_MODE_SHIFT) + | (IO_APIC_PIN_POLARITY_HIGH_ACTIVE << IO_APIC_PIN_POLARITY_SHIFT) + | (IO_APIC_DELIVERY_MODE_EXT_INT << IO_APIC_DELIVERY_MODE_SHIFT); + } else if (i < 16) { + // make 1-15 ISA interrupts + entry |= (IO_APIC_TRIGGER_MODE_EDGE << IO_APIC_TRIGGER_MODE_SHIFT) + | (IO_APIC_PIN_POLARITY_HIGH_ACTIVE << IO_APIC_PIN_POLARITY_SHIFT) + | (IO_APIC_DELIVERY_MODE_FIXED << IO_APIC_DELIVERY_MODE_SHIFT); + } else { + // and the rest are PCI interrupts + entry |= (IO_APIC_TRIGGER_MODE_LEVEL << IO_APIC_TRIGGER_MODE_SHIFT) + | (IO_APIC_PIN_POLARITY_LOW_ACTIVE << IO_APIC_PIN_POLARITY_SHIFT) + | (IO_APIC_DELIVERY_MODE_FIXED << IO_APIC_DELIVERY_MODE_SHIFT); + sLevelTriggeredInterrupts |= (1 << i); + } + + ioapic_write_64(IO_APIC_REDIRECTION_TABLE + 2 * i, entry); + } + + // 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); + } + + // disable the legacy PIC + pic_disable(); + + // prefer the ioapic over the normal pic + dprintf("using ioapic for interrupt routing\n"); + arch_int_set_interrupt_controller(ioapicController); +} diff --git a/src/system/kernel/arch/x86/pic.cpp b/src/system/kernel/arch/x86/pic.cpp new file mode 100644 index 0000000000..e54e02052d --- /dev/null +++ b/src/system/kernel/arch/x86/pic.cpp @@ -0,0 +1,243 @@ +/* + * Copyright 2002-2005, Axel Dörfler, axeld@pinc-software.de. + * Distributed under the terms of the MIT License. + * + * Copyright 2001, Travis Geiselbrecht. All rights reserved. + * Distributed under the terms of the NewOS License. + */ + +#include + +#include +#include + +#include + + +//#define TRACE_PIC +#ifdef TRACE_PIC +# define TRACE(x) dprintf x +#else +# define TRACE(x) ; +#endif + + +// Definitions for the PIC 8259 controller +// (this is not a complete list, only what we're actually using) + +#define PIC_MASTER_CONTROL 0x20 +#define PIC_MASTER_MASK 0x21 +#define PIC_SLAVE_CONTROL 0xa0 +#define PIC_SLAVE_MASK 0xa1 +#define PIC_MASTER_INIT1 PIC_MASTER_CONTROL +#define PIC_MASTER_INIT2 PIC_MASTER_MASK +#define PIC_MASTER_INIT3 PIC_MASTER_MASK +#define PIC_MASTER_INIT4 PIC_MASTER_MASK +#define PIC_SLAVE_INIT1 PIC_SLAVE_CONTROL +#define PIC_SLAVE_INIT2 PIC_SLAVE_MASK +#define PIC_SLAVE_INIT3 PIC_SLAVE_MASK +#define PIC_SLAVE_INIT4 PIC_SLAVE_MASK + +// the edge/level trigger control registers +#define PIC_MASTER_TRIGGER_MODE 0x4d0 +#define PIC_SLAVE_TRIGGER_MODE 0x4d1 + +#define PIC_INIT1 0x10 +#define PIC_INIT1_SEND_INIT4 0x01 +#define PIC_INIT3_IR2_IS_SLAVE 0x04 +#define PIC_INIT3_SLAVE_ID2 0x02 +#define PIC_INIT4_x86_MODE 0x01 + +#define PIC_CONTROL3 0x08 +#define PIC_CONTROL3_READ_ISR 0x03 +#define PIC_CONTROL3_READ_IRR 0x02 + +#define PIC_NON_SPECIFIC_EOI 0x20 + +#define PIC_SLAVE_INT_BASE 8 +#define PIC_NUM_INTS 0x0f + + +static uint16 sLevelTriggeredInterrupts = 0; + // binary mask: 1 level, 0 edge + + +/*! Tests if the interrupt in-service register of the responsible + PIC is set for interrupts 7 and 15, and if that's not the case, + it must assume it's a spurious interrupt. +*/ +static bool +pic_is_spurious_interrupt(int32 num) +{ + if (num != 7) + return false; + + // Note, detecting spurious interrupts on line 15 obviously doesn't + // work correctly - and since those are extremely rare, anyway, we + // just ignore them + + out8(PIC_CONTROL3 | PIC_CONTROL3_READ_ISR, PIC_MASTER_CONTROL); + int32 isr = in8(PIC_MASTER_CONTROL); + out8(PIC_CONTROL3 | PIC_CONTROL3_READ_IRR, PIC_MASTER_CONTROL); + + return (isr & 0x80) == 0; +} + + +static bool +pic_is_level_triggered_interrupt(int32 num) +{ + if (num < 0 || num > PIC_NUM_INTS) + return false; + + return (sLevelTriggeredInterrupts & (1 << num)) != 0; +} + + +/*! Sends a non-specified EOI (end of interrupt) notice to the PIC in + question (or both of them). + This clears the PIC interrupt in-service bit. +*/ +static bool +pic_end_of_interrupt(int32 num) +{ + if (num < 0 || num > PIC_NUM_INTS) + return false; + + // PIC 8259 controlled interrupt + if (num >= PIC_SLAVE_INT_BASE) + out8(PIC_NON_SPECIFIC_EOI, PIC_SLAVE_CONTROL); + + // we always need to acknowledge the master PIC + out8(PIC_NON_SPECIFIC_EOI, PIC_MASTER_CONTROL); + return true; +} + + +static void +pic_enable_io_interrupt(int32 num) +{ + // interrupt is specified "normalized" + if (num < 0 || num > PIC_NUM_INTS) + return; + + // enable PIC 8259 controlled interrupt + + TRACE(("pic_enable_io_interrupt: irq %ld\n", num)); + + if (num < PIC_SLAVE_INT_BASE) + out8(in8(PIC_MASTER_MASK) & ~(1 << num), PIC_MASTER_MASK); + else + out8(in8(PIC_SLAVE_MASK) & ~(1 << (num - PIC_SLAVE_INT_BASE)), PIC_SLAVE_MASK); +} + + +static void +pic_disable_io_interrupt(int32 num) +{ + // interrupt is specified "normalized" + // never disable slave pic line IRQ 2 + if (num < 0 || num > PIC_NUM_INTS || num == 2) + return; + + // disable PIC 8259 controlled interrupt + + TRACE(("pic_disable_io_interrupt: irq %ld\n", num)); + + if (num < PIC_SLAVE_INT_BASE) + out8(in8(PIC_MASTER_MASK) | (1 << num), PIC_MASTER_MASK); + else + out8(in8(PIC_SLAVE_MASK) | (1 << (num - PIC_SLAVE_INT_BASE)), PIC_SLAVE_MASK); +} + + +static void +pic_configure_io_interrupt(int32 num, uint32 config) +{ + uint8 value; + int32 localBit; + if (num < 0 || num > PIC_NUM_INTS || num == 2) + return; + + TRACE(("pic_configure_io_interrupt: irq %ld; config 0x%08lx\n", num, config)); + + if (num < PIC_SLAVE_INT_BASE) { + value = in8(PIC_MASTER_TRIGGER_MODE); + localBit = num; + } else { + value = in8(PIC_SLAVE_TRIGGER_MODE); + localBit = num - PIC_SLAVE_INT_BASE; + } + + if (config & B_LEVEL_TRIGGERED) + value |= 1 << localBit; + else + value &= ~(1 << localBit); + + if (num < PIC_SLAVE_INT_BASE) + out8(value, PIC_MASTER_TRIGGER_MODE); + else + out8(value, PIC_SLAVE_TRIGGER_MODE); + + sLevelTriggeredInterrupts = in8(PIC_MASTER_TRIGGER_MODE) + | (in8(PIC_SLAVE_TRIGGER_MODE) << 8); +} + + +void +pic_init() +{ + static const interrupt_controller picController = { + "8259 PIC", + &pic_enable_io_interrupt, + &pic_disable_io_interrupt, + &pic_configure_io_interrupt, + &pic_is_spurious_interrupt, + &pic_is_level_triggered_interrupt, + &pic_end_of_interrupt + }; + + // Start initialization sequence for the master and slave PICs + out8(PIC_INIT1 | PIC_INIT1_SEND_INIT4, PIC_MASTER_INIT1); + out8(PIC_INIT1 | PIC_INIT1_SEND_INIT4, PIC_SLAVE_INIT1); + + // Set start of interrupts to 0x20 for master, 0x28 for slave + out8(ARCH_INTERRUPT_BASE, PIC_MASTER_INIT2); + out8(ARCH_INTERRUPT_BASE + PIC_SLAVE_INT_BASE, PIC_SLAVE_INIT2); + + // Specify cascading through interrupt 2 + out8(PIC_INIT3_IR2_IS_SLAVE, PIC_MASTER_INIT3); + out8(PIC_INIT3_SLAVE_ID2, PIC_SLAVE_INIT3); + + // Set both to operate in 8086 mode + out8(PIC_INIT4_x86_MODE, PIC_MASTER_INIT4); + out8(PIC_INIT4_x86_MODE, PIC_SLAVE_INIT4); + + out8(0xfb, PIC_MASTER_MASK); // Mask off all interrupts (except slave pic line IRQ 2). + out8(0xff, PIC_SLAVE_MASK); // Mask off interrupts on the slave. + + // determine which interrupts are level or edge triggered + +#if 0 + // should set everything possible to level triggered + out8(0xf8, PIC_MASTER_TRIGGER_MODE); + out8(0xde, PIC_SLAVE_TRIGGER_MODE); +#endif + + sLevelTriggeredInterrupts = in8(PIC_MASTER_TRIGGER_MODE) + | (in8(PIC_SLAVE_TRIGGER_MODE) << 8); + + TRACE(("PIC level trigger mode: 0x%08lx\n", sLevelTriggeredInterrupts)); + + // make the pic controller the current one + arch_int_set_interrupt_controller(picController); +} + + +void +pic_disable() +{ + // Mask off all interrupts on master and slave + out8(0xff, PIC_MASTER_MASK); + out8(0xff, PIC_SLAVE_MASK); +}