123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311 |
- /*
- * Copyright (c) 2020, Liav A. <liavalb@hotmail.co.il>
- *
- * SPDX-License-Identifier: BSD-2-Clause
- */
- #include <AK/Optional.h>
- #include <Kernel/Arch/InterruptDisabler.h>
- #include <Kernel/Debug.h>
- #include <Kernel/Interrupts/APIC.h>
- #include <Kernel/Interrupts/IOAPIC.h>
- #include <Kernel/Interrupts/InterruptManagement.h>
- #include <Kernel/Sections.h>
- #define IOAPIC_REDIRECTION_ENTRY_OFFSET 0x10
- namespace Kernel {
- enum DeliveryMode {
- Normal = 0,
- LowPriority = 1,
- SMI = 2,
- NMI = 3,
- INIT = 4,
- External = 7
- };
- UNMAP_AFTER_INIT IOAPIC::IOAPIC(PhysicalAddress address, u32 gsi_base)
- : m_address(address)
- , m_regs(Memory::map_typed_writable<ioapic_mmio_regs>(m_address).release_value_but_fixme_should_propagate_errors())
- , m_gsi_base(gsi_base)
- , m_id((read_register(0x0) >> 24) & 0xFF)
- , m_version(read_register(0x1) & 0xFF)
- , m_redirection_entries_count((read_register(0x1) >> 16) + 1)
- {
- InterruptDisabler disabler;
- dmesgln("IOAPIC ID: {:#x}", m_id);
- dmesgln("IOAPIC Version: {:#x}, redirection entries: {}", m_version, m_redirection_entries_count);
- dmesgln("IOAPIC Arbitration ID {:#x}", read_register(0x2));
- mask_all_redirection_entries();
- }
- UNMAP_AFTER_INIT void IOAPIC::initialize()
- {
- }
- void IOAPIC::map_interrupt_redirection(u8 interrupt_vector)
- {
- InterruptDisabler disabler;
- for (auto redirection_override : InterruptManagement::the().isa_overrides()) {
- if (redirection_override.source() != interrupt_vector)
- continue;
- bool active_low = false;
- // See ACPI spec Version 6.2, page 205 to learn more about Interrupt Overriding Flags.
- switch ((redirection_override.flags() & 0b11)) {
- case 0:
- active_low = false;
- break;
- case 1:
- active_low = false;
- break;
- case 2:
- VERIFY_NOT_REACHED(); // Reserved value
- case 3:
- active_low = true;
- break;
- }
- bool trigger_level_mode = false;
- // See ACPI spec Version 6.2, page 205 to learn more about Interrupt Overriding Flags.
- switch (((redirection_override.flags() >> 2) & 0b11)) {
- case 0:
- trigger_level_mode = false;
- break;
- case 1:
- trigger_level_mode = false;
- break;
- case 2:
- VERIFY_NOT_REACHED(); // Reserved value
- case 3:
- trigger_level_mode = true;
- break;
- }
- configure_redirection_entry(redirection_override.gsi() - gsi_base(), InterruptManagement::acquire_mapped_interrupt_number(redirection_override.source()) + IRQ_VECTOR_BASE, DeliveryMode::Normal, false, active_low, trigger_level_mode, true, 0);
- return;
- }
- isa_identity_map(interrupt_vector);
- }
- void IOAPIC::isa_identity_map(int index)
- {
- InterruptDisabler disabler;
- configure_redirection_entry(index, InterruptManagement::acquire_mapped_interrupt_number(index) + IRQ_VECTOR_BASE, DeliveryMode::Normal, false, false, false, true, 0);
- }
- void IOAPIC::map_pci_interrupts()
- {
- InterruptDisabler disabler;
- configure_redirection_entry(11, 11 + IRQ_VECTOR_BASE, DeliveryMode::Normal, false, false, true, true, 0);
- }
- bool IOAPIC::is_enabled() const
- {
- return !is_hard_disabled();
- }
- void IOAPIC::spurious_eoi(GenericInterruptHandler const& handler) const
- {
- InterruptDisabler disabler;
- VERIFY(handler.type() == HandlerType::SpuriousInterruptHandler);
- VERIFY(handler.interrupt_number() == APIC::spurious_interrupt_vector());
- dbgln("IOAPIC: Spurious interrupt");
- }
- void IOAPIC::map_isa_interrupts()
- {
- InterruptDisabler disabler;
- for (auto redirection_override : InterruptManagement::the().isa_overrides()) {
- if ((redirection_override.gsi() < gsi_base()) || (redirection_override.gsi() >= (gsi_base() + m_redirection_entries_count)))
- continue;
- bool active_low = false;
- // See ACPI spec Version 6.2, page 205 to learn more about Interrupt Overriding Flags.
- switch ((redirection_override.flags() & 0b11)) {
- case 0:
- active_low = false;
- break;
- case 1:
- active_low = false;
- break;
- case 2:
- VERIFY_NOT_REACHED();
- case 3:
- active_low = true;
- break;
- }
- bool trigger_level_mode = false;
- // See ACPI spec Version 6.2, page 205 to learn more about Interrupt Overriding Flags.
- switch (((redirection_override.flags() >> 2) & 0b11)) {
- case 0:
- trigger_level_mode = false;
- break;
- case 1:
- trigger_level_mode = false;
- break;
- case 2:
- VERIFY_NOT_REACHED();
- case 3:
- trigger_level_mode = true;
- break;
- }
- configure_redirection_entry(redirection_override.gsi() - gsi_base(), InterruptManagement::acquire_mapped_interrupt_number(redirection_override.source()) + IRQ_VECTOR_BASE, 0, false, active_low, trigger_level_mode, true, 0);
- }
- }
- void IOAPIC::reset_all_redirection_entries() const
- {
- InterruptDisabler disabler;
- for (size_t index = 0; index < m_redirection_entries_count; index++)
- reset_redirection_entry(index);
- }
- void IOAPIC::hard_disable()
- {
- InterruptDisabler disabler;
- reset_all_redirection_entries();
- IRQController::hard_disable();
- }
- void IOAPIC::reset_redirection_entry(int index) const
- {
- InterruptDisabler disabler;
- configure_redirection_entry(index, 0, 0, false, false, false, true, 0);
- }
- void IOAPIC::configure_redirection_entry(int index, u8 interrupt_vector, u8 delivery_mode, bool logical_destination, bool active_low, bool trigger_level_mode, bool masked, u8 destination) const
- {
- InterruptDisabler disabler;
- VERIFY((u32)index < m_redirection_entries_count);
- u32 redirection_entry1 = interrupt_vector | (delivery_mode & 0b111) << 8 | logical_destination << 11 | active_low << 13 | trigger_level_mode << 15 | masked << 16;
- u32 redirection_entry2 = destination << 24;
- write_register((index << 1) + IOAPIC_REDIRECTION_ENTRY_OFFSET, redirection_entry1);
- if constexpr (IOAPIC_DEBUG)
- dbgln("IOAPIC Value: {:#x}", read_register((index << 1) + IOAPIC_REDIRECTION_ENTRY_OFFSET));
- write_register((index << 1) + IOAPIC_REDIRECTION_ENTRY_OFFSET + 1, redirection_entry2);
- if constexpr (IOAPIC_DEBUG)
- dbgln("IOAPIC Value: {:#x}", read_register((index << 1) + 0x11));
- }
- void IOAPIC::mask_all_redirection_entries() const
- {
- InterruptDisabler disabler;
- for (size_t index = 0; index < m_redirection_entries_count; index++)
- mask_redirection_entry(index);
- }
- void IOAPIC::mask_redirection_entry(u8 index) const
- {
- VERIFY((u32)index < m_redirection_entries_count);
- u32 redirection_entry = read_register((index << 1) + IOAPIC_REDIRECTION_ENTRY_OFFSET);
- if (redirection_entry & (1 << 16))
- return;
- write_register((index << 1) + IOAPIC_REDIRECTION_ENTRY_OFFSET, redirection_entry | (1 << 16));
- }
- bool IOAPIC::is_redirection_entry_masked(u8 index) const
- {
- VERIFY((u32)index < m_redirection_entries_count);
- return (read_register((index << 1) + IOAPIC_REDIRECTION_ENTRY_OFFSET) & (1 << 16)) != 0;
- }
- void IOAPIC::unmask_redirection_entry(u8 index) const
- {
- VERIFY((u32)index < m_redirection_entries_count);
- u32 redirection_entry = read_register((index << 1) + IOAPIC_REDIRECTION_ENTRY_OFFSET);
- if (!(redirection_entry & (1 << 16)))
- return;
- write_register((index << 1) + IOAPIC_REDIRECTION_ENTRY_OFFSET, redirection_entry & ~(1 << 16));
- }
- bool IOAPIC::is_vector_enabled(u8 interrupt_vector) const
- {
- InterruptDisabler disabler;
- return is_redirection_entry_masked(interrupt_vector);
- }
- u8 IOAPIC::read_redirection_entry_vector(u8 index) const
- {
- VERIFY((u32)index < m_redirection_entries_count);
- return (read_register((index << 1) + IOAPIC_REDIRECTION_ENTRY_OFFSET) & 0xFF);
- }
- Optional<int> IOAPIC::find_redirection_entry_by_vector(u8 vector) const
- {
- InterruptDisabler disabler;
- for (size_t index = 0; index < m_redirection_entries_count; index++) {
- if (read_redirection_entry_vector(index) == (InterruptManagement::acquire_mapped_interrupt_number(vector) + IRQ_VECTOR_BASE))
- return index;
- }
- return {};
- }
- void IOAPIC::disable(GenericInterruptHandler const& handler)
- {
- InterruptDisabler disabler;
- VERIFY(!is_hard_disabled());
- u8 interrupt_vector = handler.interrupt_number();
- VERIFY(interrupt_vector >= gsi_base() && interrupt_vector < interrupt_vectors_count());
- auto found_index = find_redirection_entry_by_vector(interrupt_vector);
- if (!found_index.has_value()) {
- map_interrupt_redirection(interrupt_vector);
- found_index = find_redirection_entry_by_vector(interrupt_vector);
- }
- VERIFY(found_index.has_value());
- mask_redirection_entry(found_index.value());
- }
- void IOAPIC::enable(GenericInterruptHandler const& handler)
- {
- InterruptDisabler disabler;
- VERIFY(!is_hard_disabled());
- u8 interrupt_vector = handler.interrupt_number();
- VERIFY(interrupt_vector >= gsi_base() && interrupt_vector < interrupt_vectors_count());
- auto found_index = find_redirection_entry_by_vector(interrupt_vector);
- if (!found_index.has_value()) {
- map_interrupt_redirection(interrupt_vector);
- found_index = find_redirection_entry_by_vector(interrupt_vector);
- }
- VERIFY(found_index.has_value());
- unmask_redirection_entry(found_index.value());
- }
- void IOAPIC::eoi(GenericInterruptHandler const& handler) const
- {
- InterruptDisabler disabler;
- VERIFY(!is_hard_disabled());
- VERIFY(handler.interrupt_number() >= gsi_base() && handler.interrupt_number() < interrupt_vectors_count());
- VERIFY(handler.type() != HandlerType::SpuriousInterruptHandler);
- APIC::the().eoi();
- }
- u16 IOAPIC::get_isr() const
- {
- InterruptDisabler disabler;
- VERIFY_NOT_REACHED();
- }
- u16 IOAPIC::get_irr() const
- {
- InterruptDisabler disabler;
- VERIFY_NOT_REACHED();
- }
- void IOAPIC::write_register(u32 index, u32 value) const
- {
- InterruptDisabler disabler;
- m_regs->select = index;
- m_regs->window = value;
- dbgln_if(IOAPIC_DEBUG, "IOAPIC Writing, Value {:#x} @ offset {:#x}", (u32)m_regs->window, (u32)m_regs->select);
- }
- u32 IOAPIC::read_register(u32 index) const
- {
- InterruptDisabler disabler;
- m_regs->select = index;
- dbgln_if(IOAPIC_DEBUG, "IOAPIC Reading, Value {:#x} @ offset {:#x}", (u32)m_regs->window, (u32)m_regs->select);
- return m_regs->window;
- }
- }
|