Kernel: Acquire ISA interrupt overrides from Interrupt Management

Also, InterruptDisabler were added to prevent critical function from
being interrupted. In addition, the interrupt numbers are abstracted
from IDT offsets, thus, allowing to create a better routing scheme
when using IOAPICs for interrupt redirection.
This commit is contained in:
Liav A 2020-03-06 03:19:40 +02:00 committed by Andreas Kling
parent d9d792d37f
commit 30fc78bfaf
Notes: sideshowbarker 2024-07-19 08:53:01 +09:00
5 changed files with 54 additions and 21 deletions

View File

@ -39,20 +39,20 @@ GenericInterruptHandler& GenericInterruptHandler::from(u8 interrupt_number)
GenericInterruptHandler::GenericInterruptHandler(u8 interrupt_number)
: m_interrupt_number(interrupt_number)
{
register_generic_interrupt_handler(interrupt_number, *this);
register_generic_interrupt_handler(InterruptManagement::acquire_mapped_interrupt_number(m_interrupt_number), *this);
}
GenericInterruptHandler::~GenericInterruptHandler()
{
unregister_generic_interrupt_handler(m_interrupt_number, *this);
unregister_generic_interrupt_handler(InterruptManagement::acquire_mapped_interrupt_number(m_interrupt_number), *this);
}
void GenericInterruptHandler::change_interrupt_number(u8 number)
{
ASSERT_INTERRUPTS_ENABLED();
unregister_generic_interrupt_handler(interrupt_number(), *this);
unregister_generic_interrupt_handler(InterruptManagement::acquire_mapped_interrupt_number(interrupt_number()), *this);
m_interrupt_number = number;
register_generic_interrupt_handler(interrupt_number(), *this);
register_generic_interrupt_handler(InterruptManagement::acquire_mapped_interrupt_number(interrupt_number()), *this);
}
void GenericInterruptHandler::increment_invoking_counter()
{

View File

@ -42,15 +42,14 @@ enum DeliveryMode {
External = 7
};
IOAPIC::IOAPIC(ioapic_mmio_regs& regs, u32 gsi_base, Vector<RefPtr<ISAInterruptOverrideMetadata>>& isa_overrides, Vector<RefPtr<PCIInterruptOverrideMetadata>>& pci_overrides)
IOAPIC::IOAPIC(ioapic_mmio_regs& regs, u32 gsi_base)
: m_physical_access_registers(regs)
, m_gsi_base(gsi_base)
, m_id((read_register(0x0) >> 24) & 0xFF)
, m_version(read_register(0x1) & 0xFF)
, m_redirection_entries((read_register(0x1) >> 16) + 1)
, m_isa_interrupt_overrides(isa_overrides)
, m_pci_interrupt_overrides(pci_overrides)
{
InterruptDisabler disabler;
klog() << "IOAPIC ID: 0x" << String::format("%x", m_id);
klog() << "IOAPIC Version: 0x" << String::format("%x", m_version) << ", Redirection Entries count - " << m_redirection_entries;
klog() << "IOAPIC Arbitration ID 0x" << String::format("%x", read_register(0x2));
@ -63,11 +62,8 @@ void IOAPIC::initialize()
void IOAPIC::map_interrupt_redirection(u8 interrupt_vector)
{
if (interrupt_vector == 11) {
configure_redirection_entry(11, 11 + IRQ_VECTOR_BASE, DeliveryMode::LowPriority, false, true, true, true, 0);
return;
}
for (auto redirection_override : m_isa_interrupt_overrides) {
InterruptDisabler disabler;
for (auto redirection_override : InterruptManagement::the().isa_overrides()) {
ASSERT(!redirection_override.is_null());
if (redirection_override->source() != interrupt_vector)
continue;
@ -102,7 +98,7 @@ void IOAPIC::map_interrupt_redirection(u8 interrupt_vector)
trigger_level_mode = true;
break;
}
configure_redirection_entry(redirection_override->gsi(), redirection_override->source() + IRQ_VECTOR_BASE, DeliveryMode::LowPriority, false, active_low, trigger_level_mode, true, 0);
configure_redirection_entry(redirection_override->gsi(), 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);
@ -110,18 +106,20 @@ void IOAPIC::map_interrupt_redirection(u8 interrupt_vector)
void IOAPIC::isa_identity_map(int index)
{
configure_redirection_entry(index, index + IRQ_VECTOR_BASE, DeliveryMode::Normal, true, false, false, true, 1);
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);
}
void IOAPIC::map_isa_interrupts()
{
InterruptDisabler disabler;
for (auto redirection_override : m_isa_interrupt_overrides) {
for (auto redirection_override : InterruptManagement::the().isa_overrides()) {
ASSERT(!redirection_override.is_null());
bool active_low;
// See ACPI spec Version 6.2, page 205 to learn more about Interrupt Overriding Flags.
@ -154,7 +152,7 @@ void IOAPIC::map_isa_interrupts()
trigger_level_mode = true;
break;
}
configure_redirection_entry(redirection_override->gsi(), redirection_override->source() + IRQ_VECTOR_BASE, 0, false, active_low, trigger_level_mode, true, 0);
configure_redirection_entry(redirection_override->gsi(), InterruptManagement::acquire_mapped_interrupt_number(redirection_override->source()) + IRQ_VECTOR_BASE, 0, false, active_low, trigger_level_mode, true, 0);
}
}
@ -180,6 +178,7 @@ void IOAPIC::reset_redirection_entry(int index) const
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;
ASSERT((u32)index < m_redirection_entries);
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;
@ -236,7 +235,7 @@ int IOAPIC::find_redirection_entry_by_vector(u8 vector) const
{
InterruptDisabler disabler;
for (size_t index = 0; index < m_redirection_entries; index++) {
if (read_redirection_entry_vector(index) == (vector + IRQ_VECTOR_BASE))
if (read_redirection_entry_vector(index) == (InterruptManagement::acquire_mapped_interrupt_number(vector) + IRQ_VECTOR_BASE))
return index;
}
return -1;

View File

@ -41,7 +41,7 @@ class PCIInterruptOverrideMetadata;
class IOAPIC final : public IRQController {
public:
IOAPIC(ioapic_mmio_regs& regs, u32 gsi_base, Vector<RefPtr<ISAInterruptOverrideMetadata>>& overrides, Vector<RefPtr<PCIInterruptOverrideMetadata>>& pci_overrides);
IOAPIC(ioapic_mmio_regs& regs, u32 gsi_base);
virtual void enable(u8 number) override;
virtual void disable(u8 number) override;
virtual void hard_disable() override;
@ -81,7 +81,5 @@ private:
u8 m_id;
u8 m_version;
u32 m_redirection_entries;
Vector<RefPtr<ISAInterruptOverrideMetadata>> m_isa_interrupt_overrides;
Vector<RefPtr<PCIInterruptOverrideMetadata>> m_pci_interrupt_overrides;
};
}

View File

@ -27,11 +27,14 @@
#include <AK/FixedArray.h>
#include <Kernel/ACPI/MultiProcessorParser.h>
#include <Kernel/Arch/i386/CPU.h>
#include <Kernel/Interrupts/APIC.h>
#include <Kernel/Interrupts/IOAPIC.h>
#include <Kernel/Interrupts/InterruptManagement.h>
#include <Kernel/Interrupts/PIC.h>
#include <Kernel/Interrupts/SpuriousInterruptHandler.h>
#include <Kernel/Interrupts/UnhandledInterruptHandler.h>
#include <Kernel/VM/MemoryManager.h>
#include <LibBareMetal/IO.h>
#define PCAT_COMPAT_FLAG 0x1
@ -72,6 +75,26 @@ IRQController& InterruptManagement::get_interrupt_controller(int index)
return *m_interrupt_controllers[index];
}
Vector<RefPtr<ISAInterruptOverrideMetadata>> InterruptManagement::isa_overrides()
{
return m_isa_interrupt_overrides;
}
u8 InterruptManagement::acquire_mapped_interrupt_number(u8 number)
{
if (!InterruptManagement::initialized()) {
// This is necessary, because we install UnhandledInterruptHandlers before we actually initialize the Interrupt Management object...
return number;
}
return InterruptManagement::the().get_mapped_vector_number(number);
}
u8 InterruptManagement::get_mapped_vector_number(u8 original_vector)
{
// FIXME: For SMP configuration (with IOAPICs) use a better routing scheme to make redirections more efficient.
return original_vector;
}
RefPtr<IRQController> InterruptManagement::get_responsible_irq_controller(u8 interrupt_vector)
{
if (m_interrupt_controllers.size() == 1 && m_interrupt_controllers[0]->type() == IRQControllerType::i8259) {
@ -110,6 +133,8 @@ InterruptManagement::InterruptManagement()
void InterruptManagement::switch_to_pic_mode()
{
klog() << "Interrupts: Switch to Legacy PIC mode";
InterruptDisabler disabler;
m_smp_enabled = false;
SpuriousInterruptHandler::initialize(7);
SpuriousInterruptHandler::initialize(15);
for (auto& irq_controller : m_interrupt_controllers) {
@ -126,6 +151,8 @@ void InterruptManagement::switch_to_pic_mode()
void InterruptManagement::switch_to_ioapic_mode()
{
klog() << "Interrupts: Switch to IOAPIC mode";
InterruptDisabler disabler;
m_smp_enabled = true;
if (m_interrupt_controllers.size() == 1) {
if (get_interrupt_controller(0).type() == IRQControllerType::i8259) {
klog() << "Interrupts: NO IOAPIC detected, Reverting to PIC mode.";
@ -141,6 +168,9 @@ void InterruptManagement::switch_to_ioapic_mode()
dbg() << "Interrupts: Detected " << irq_controller->model();
}
}
APIC::init();
APIC::enable_bsp();
MultiProcessorParser::initialize();
}
void InterruptManagement::locate_apic_data()
@ -163,7 +193,7 @@ void InterruptManagement::locate_apic_data()
auto* ioapic_entry = (const ACPI::Structures::MADTEntries::IOAPIC*)madt_entry;
dbg() << "IOAPIC found @ MADT entry " << entry_index << ", MMIO Registers @ Px" << String::format("%x", ioapic_entry->ioapic_address);
m_interrupt_controllers.resize(1 + irq_controller_count);
m_interrupt_controllers[irq_controller_count] = adopt(*new IOAPIC(*(ioapic_mmio_regs*)ioapic_entry->ioapic_address, ioapic_entry->gsi_base, m_isa_interrupt_overrides, m_pci_interrupt_overrides));
m_interrupt_controllers[irq_controller_count] = adopt(*new IOAPIC(*(ioapic_mmio_regs*)ioapic_entry->ioapic_address, ioapic_entry->gsi_base));
irq_controller_count++;
}
if (madt_entry->type == (u8)ACPI::Structures::MADTEntryType::InterruptSourceOverride) {

View File

@ -47,11 +47,16 @@ public:
static InterruptManagement& the();
static void initialize();
static bool initialized();
static u8 acquire_mapped_interrupt_number(u8);
virtual void switch_to_pic_mode();
virtual void switch_to_ioapic_mode();
RefPtr<IRQController> get_responsible_irq_controller(u8 interrupt_vector);
Vector<RefPtr<ISAInterruptOverrideMetadata>> isa_overrides();
u8 get_mapped_vector_number(u8 original_vector);
void enumerate_interrupt_handlers(Function<void(GenericInterruptHandler&)>);
IRQController& get_interrupt_controller(int index);
@ -60,6 +65,7 @@ private:
PhysicalAddress search_for_madt();
void locate_apic_data();
void locate_pci_interrupt_overrides();
bool m_smp_enabled { false };
FixedArray<RefPtr<IRQController>> m_interrupt_controllers { 1 };
Vector<RefPtr<ISAInterruptOverrideMetadata>> m_isa_interrupt_overrides;
Vector<RefPtr<PCIInterruptOverrideMetadata>> m_pci_interrupt_overrides;