1
Fork 0
mirror of https://github.com/RGBCube/serenity synced 2025-05-14 09:24:57 +00:00

Kernel: Move IRQController and InterruptManagement to Arch directory

These 2 classes currently contain much code that is x86(_64) specific.
Move them to the architecture specific directory. This also allows for a
simpler implementation for aarch64.
This commit is contained in:
Timon Kruiper 2022-05-30 09:04:37 +02:00 committed by Linus Groh
parent 63ee2781fb
commit f085903f62
22 changed files with 106 additions and 19 deletions

View file

@ -4,10 +4,10 @@
* SPDX-License-Identifier: BSD-2-Clause
*/
#include <Kernel/Arch/InterruptManagement.h>
#include <Kernel/Arch/Interrupts.h>
#include <Kernel/Assertions.h>
#include <Kernel/Interrupts/GenericInterruptHandler.h>
#include <Kernel/Interrupts/InterruptManagement.h>
namespace Kernel {
GenericInterruptHandler& GenericInterruptHandler::from(u8 interrupt_number)

View file

@ -6,10 +6,10 @@
#include <AK/Optional.h>
#include <Kernel/Arch/InterruptDisabler.h>
#include <Kernel/Arch/x86/InterruptManagement.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

View file

@ -6,7 +6,7 @@
#pragma once
#include <Kernel/Interrupts/IRQController.h>
#include <Kernel/Arch/x86/IRQController.h>
#include <Kernel/Memory/TypedMapping.h>
namespace Kernel {

View file

@ -1,43 +0,0 @@
/*
* Copyright (c) 2020, Liav A. <liavalb@hotmail.co.il>
*
* SPDX-License-Identifier: BSD-2-Clause
*/
#pragma once
#include <AK/RefCounted.h>
#include <AK/Types.h>
namespace Kernel {
enum class IRQControllerType {
i8259 = 1, /* Intel 8259 Dual PIC */
i82093AA = 2 /* Intel 82093AA I/O ADVANCED PROGRAMMABLE INTERRUPT CONTROLLER (IOAPIC) */
};
class IRQController : public RefCounted<IRQController> {
public:
virtual ~IRQController() = default;
virtual void enable(GenericInterruptHandler const&) = 0;
virtual void disable(GenericInterruptHandler const&) = 0;
virtual void hard_disable() { m_hard_disabled = true; }
virtual bool is_vector_enabled(u8 number) const = 0;
virtual bool is_enabled() const = 0;
bool is_hard_disabled() const { return m_hard_disabled; }
virtual void eoi(GenericInterruptHandler const&) const = 0;
virtual void spurious_eoi(GenericInterruptHandler const&) const = 0;
virtual size_t interrupt_vectors_count() const = 0;
virtual u32 gsi_base() const = 0;
virtual u16 get_isr() const = 0;
virtual u16 get_irr() const = 0;
virtual StringView model() const = 0;
virtual IRQControllerType type() const = 0;
protected:
IRQController() = default;
virtual void initialize() = 0;
bool m_hard_disabled { false };
};
}

View file

@ -5,9 +5,9 @@
*/
#include <Kernel/Arch/InterruptDisabler.h>
#include <Kernel/Arch/InterruptManagement.h>
#include <Kernel/Debug.h>
#include <Kernel/Interrupts/IRQHandler.h>
#include <Kernel/Interrupts/InterruptManagement.h>
namespace Kernel {

View file

@ -8,8 +8,8 @@
#include <AK/RefPtr.h>
#include <AK/Types.h>
#include <Kernel/Arch/IRQController.h>
#include <Kernel/Interrupts/GenericInterruptHandler.h>
#include <Kernel/Interrupts/IRQController.h>
namespace Kernel {

View file

@ -1,245 +0,0 @@
/*
* Copyright (c) 2020, Liav A. <liavalb@hotmail.co.il>
*
* SPDX-License-Identifier: BSD-2-Clause
*/
#include <AK/ByteReader.h>
#include <Kernel/API/Syscall.h>
#include <Kernel/Arch/InterruptDisabler.h>
#include <Kernel/Arch/Interrupts.h>
#include <Kernel/CommandLine.h>
#include <Kernel/Firmware/MultiProcessor/Parser.h>
#include <Kernel/Interrupts/APIC.h>
#include <Kernel/Interrupts/IOAPIC.h>
#include <Kernel/Interrupts/InterruptManagement.h>
#include <Kernel/Interrupts/PIC.h>
#include <Kernel/Interrupts/SharedIRQHandler.h>
#include <Kernel/Interrupts/SpuriousInterruptHandler.h>
#include <Kernel/Memory/TypedMapping.h>
#include <Kernel/Sections.h>
#define PCAT_COMPAT_FLAG 0x1
namespace Kernel {
static InterruptManagement* s_interrupt_management;
bool InterruptManagement::initialized()
{
return (s_interrupt_management != nullptr);
}
InterruptManagement& InterruptManagement::the()
{
VERIFY(InterruptManagement::initialized());
return *s_interrupt_management;
}
UNMAP_AFTER_INIT void InterruptManagement::initialize()
{
VERIFY(!InterruptManagement::initialized());
s_interrupt_management = new InterruptManagement();
if (!kernel_command_line().is_smp_enabled_without_ioapic_enabled()) {
dbgln("Can't enable SMP mode without IOAPIC mode being enabled");
}
if (!kernel_command_line().is_ioapic_enabled() && !kernel_command_line().is_smp_enabled())
InterruptManagement::the().switch_to_pic_mode();
else
InterruptManagement::the().switch_to_ioapic_mode();
}
void InterruptManagement::enumerate_interrupt_handlers(Function<void(GenericInterruptHandler&)> callback)
{
for (int i = 0; i < GENERIC_INTERRUPT_HANDLERS_COUNT; i++) {
auto& handler = get_interrupt_handler(i);
if (handler.type() == HandlerType::SharedIRQHandler) {
static_cast<SharedIRQHandler&>(handler).enumerate_handlers(callback);
continue;
}
if (handler.type() != HandlerType::UnhandledInterruptHandler)
callback(handler);
}
}
IRQController& InterruptManagement::get_interrupt_controller(int index)
{
VERIFY(index >= 0);
VERIFY(!m_interrupt_controllers[index].is_null());
return *m_interrupt_controllers[index];
}
u8 InterruptManagement::acquire_mapped_interrupt_number(u8 original_irq)
{
if (!InterruptManagement::initialized()) {
// This is necessary, because we install UnhandledInterruptHandlers before we actually initialize the Interrupt Management object...
return original_irq;
}
return InterruptManagement::the().get_mapped_interrupt_vector(original_irq);
}
u8 InterruptManagement::acquire_irq_number(u8 mapped_interrupt_vector)
{
VERIFY(InterruptManagement::initialized());
return InterruptManagement::the().get_irq_vector(mapped_interrupt_vector);
}
u8 InterruptManagement::get_mapped_interrupt_vector(u8 original_irq)
{
// FIXME: For SMP configuration (with IOAPICs) use a better routing scheme to make redirections more efficient.
// FIXME: Find a better way to handle conflict with Syscall interrupt gate.
VERIFY((original_irq + IRQ_VECTOR_BASE) != syscall_vector);
return original_irq;
}
u8 InterruptManagement::get_irq_vector(u8 mapped_interrupt_vector)
{
// FIXME: For SMP configuration (with IOAPICs) use a better routing scheme to make redirections more efficient.
return mapped_interrupt_vector;
}
RefPtr<IRQController> InterruptManagement::get_responsible_irq_controller(IRQControllerType controller_type, u8 interrupt_vector)
{
for (auto& irq_controller : m_interrupt_controllers) {
if (irq_controller->gsi_base() <= interrupt_vector && irq_controller->type() == controller_type)
return irq_controller;
}
VERIFY_NOT_REACHED();
}
RefPtr<IRQController> InterruptManagement::get_responsible_irq_controller(u8 interrupt_vector)
{
if (m_interrupt_controllers.size() == 1 && m_interrupt_controllers[0]->type() == IRQControllerType::i8259) {
return m_interrupt_controllers[0];
}
for (auto& irq_controller : m_interrupt_controllers) {
if (irq_controller->gsi_base() <= interrupt_vector)
if (!irq_controller->is_hard_disabled())
return irq_controller;
}
VERIFY_NOT_REACHED();
}
UNMAP_AFTER_INIT PhysicalAddress InterruptManagement::search_for_madt()
{
dbgln("Early access to ACPI tables for interrupt setup");
auto rsdp = ACPI::StaticParsing::find_rsdp();
if (!rsdp.has_value())
return {};
auto apic = ACPI::StaticParsing::find_table(rsdp.value(), "APIC");
if (!apic.has_value())
return {};
return apic.value();
}
UNMAP_AFTER_INIT InterruptManagement::InterruptManagement()
: m_madt(search_for_madt())
{
m_interrupt_controllers.resize(1);
}
UNMAP_AFTER_INIT void InterruptManagement::switch_to_pic_mode()
{
dmesgln("Interrupts: Switch to Legacy PIC mode");
InterruptDisabler disabler;
m_smp_enabled = false;
m_interrupt_controllers[0] = adopt_ref(*new PIC());
SpuriousInterruptHandler::initialize(7);
SpuriousInterruptHandler::initialize(15);
for (auto& irq_controller : m_interrupt_controllers) {
VERIFY(irq_controller);
if (irq_controller->type() == IRQControllerType::i82093AA) {
irq_controller->hard_disable();
dbgln("Interrupts: Detected {} - Disabled", irq_controller->model());
} else {
dbgln("Interrupts: Detected {}", irq_controller->model());
}
}
}
UNMAP_AFTER_INIT void InterruptManagement::switch_to_ioapic_mode()
{
dmesgln("Interrupts: Switch to IOAPIC mode");
InterruptDisabler disabler;
if (m_madt.is_null()) {
dbgln("Interrupts: ACPI MADT is not available, reverting to PIC mode");
switch_to_pic_mode();
return;
}
dbgln("Interrupts: MADT @ P {}", m_madt.as_ptr());
locate_apic_data();
m_smp_enabled = true;
if (m_interrupt_controllers.size() == 1) {
if (get_interrupt_controller(0).type() == IRQControllerType::i8259) {
dmesgln("Interrupts: NO IOAPIC detected, Reverting to PIC mode.");
return;
}
}
for (auto& irq_controller : m_interrupt_controllers) {
VERIFY(irq_controller);
if (irq_controller->type() == IRQControllerType::i8259) {
irq_controller->hard_disable();
dbgln("Interrupts: Detected {} - Disabled", irq_controller->model());
SpuriousInterruptHandler::initialize_for_disabled_master_pic();
SpuriousInterruptHandler::initialize_for_disabled_slave_pic();
} else {
dbgln("Interrupts: Detected {}", irq_controller->model());
}
}
if (auto mp_parser = MultiProcessorParser::autodetect()) {
m_pci_interrupt_overrides = mp_parser->get_pci_interrupt_redirections();
}
APIC::initialize();
APIC::the().init_bsp();
}
UNMAP_AFTER_INIT void InterruptManagement::locate_apic_data()
{
VERIFY(!m_madt.is_null());
auto madt = Memory::map_typed<ACPI::Structures::MADT>(m_madt).release_value_but_fixme_should_propagate_errors();
int irq_controller_count = 0;
if (madt->flags & PCAT_COMPAT_FLAG) {
m_interrupt_controllers[0] = adopt_ref(*new PIC());
irq_controller_count++;
}
size_t entry_index = 0;
size_t entries_length = madt->h.length - sizeof(ACPI::Structures::MADT);
auto* madt_entry = madt->entries;
while (entries_length > 0) {
size_t entry_length = madt_entry->length;
if (madt_entry->type == (u8)ACPI::Structures::MADTEntryType::IOAPIC) {
auto* ioapic_entry = (const ACPI::Structures::MADTEntries::IOAPIC*)madt_entry;
dbgln("IOAPIC found @ MADT entry {}, MMIO Registers @ {}", entry_index, PhysicalAddress(ioapic_entry->ioapic_address));
m_interrupt_controllers.resize(1 + irq_controller_count);
m_interrupt_controllers[irq_controller_count] = adopt_ref(*new IOAPIC(PhysicalAddress(ioapic_entry->ioapic_address), ioapic_entry->gsi_base));
irq_controller_count++;
}
if (madt_entry->type == (u8)ACPI::Structures::MADTEntryType::InterruptSourceOverride) {
auto* interrupt_override_entry = (const ACPI::Structures::MADTEntries::InterruptSourceOverride*)madt_entry;
u32 global_system_interrupt = 0;
ByteReader::load<u32>(reinterpret_cast<u8 const*>(&interrupt_override_entry->global_system_interrupt), global_system_interrupt);
u16 flags = 0;
ByteReader::load<u16>(reinterpret_cast<u8 const*>(&interrupt_override_entry->flags), flags);
MUST(m_isa_interrupt_overrides.try_empend(
interrupt_override_entry->bus,
interrupt_override_entry->source,
global_system_interrupt,
flags));
dbgln("Interrupts: Overriding INT {:#x} with GSI {}, for bus {:#x}",
interrupt_override_entry->source,
global_system_interrupt,
interrupt_override_entry->bus);
}
madt_entry = (ACPI::Structures::MADTEntryHeader*)(VirtualAddress(madt_entry).offset(entry_length).get());
entries_length -= entry_length;
entry_index++;
}
}
}

View file

@ -1,81 +0,0 @@
/*
* Copyright (c) 2020, Liav A. <liavalb@hotmail.co.il>
*
* SPDX-License-Identifier: BSD-2-Clause
*/
#pragma once
#include <AK/Function.h>
#include <AK/NonnullOwnPtr.h>
#include <AK/OwnPtr.h>
#include <AK/RefCounted.h>
#include <AK/RefPtr.h>
#include <AK/Types.h>
#include <Kernel/Firmware/ACPI/Definitions.h>
#include <Kernel/Interrupts/GenericInterruptHandler.h>
#include <Kernel/Interrupts/IOAPIC.h>
#include <Kernel/Interrupts/IRQController.h>
namespace Kernel {
class ISAInterruptOverrideMetadata {
public:
ISAInterruptOverrideMetadata(u8 bus, u8 source, u32 global_system_interrupt, u16 flags)
: m_bus(bus)
, m_source(source)
, m_global_system_interrupt(global_system_interrupt)
, m_flags(flags)
{
}
u8 bus() const { return m_bus; }
u8 source() const { return m_source; }
u32 gsi() const { return m_global_system_interrupt; }
u16 flags() const { return m_flags; }
private:
const u8 m_bus;
const u8 m_source;
const u32 m_global_system_interrupt;
const u16 m_flags;
};
class InterruptManagement {
public:
static InterruptManagement& the();
static void initialize();
static bool initialized();
static u8 acquire_mapped_interrupt_number(u8 original_irq);
static u8 acquire_irq_number(u8 mapped_interrupt_vector);
virtual void switch_to_pic_mode();
virtual void switch_to_ioapic_mode();
bool smp_enabled() const { return m_smp_enabled; }
RefPtr<IRQController> get_responsible_irq_controller(u8 interrupt_vector);
RefPtr<IRQController> get_responsible_irq_controller(IRQControllerType controller_type, u8 interrupt_vector);
Vector<ISAInterruptOverrideMetadata> const& isa_overrides() const { return m_isa_interrupt_overrides; }
u8 get_mapped_interrupt_vector(u8 original_irq);
u8 get_irq_vector(u8 mapped_interrupt_vector);
void enumerate_interrupt_handlers(Function<void(GenericInterruptHandler&)>);
IRQController& get_interrupt_controller(int index);
protected:
virtual ~InterruptManagement() = default;
private:
InterruptManagement();
PhysicalAddress search_for_madt();
void locate_apic_data();
bool m_smp_enabled { false };
Vector<RefPtr<IRQController>> m_interrupt_controllers;
Vector<ISAInterruptOverrideMetadata> m_isa_interrupt_overrides;
Vector<PCIInterruptOverrideMetadata> m_pci_interrupt_overrides;
PhysicalAddress m_madt;
};
}

View file

@ -7,7 +7,7 @@
#pragma once
#include <AK/Types.h>
#include <Kernel/Interrupts/IRQController.h>
#include <Kernel/Arch/x86/IRQController.h>
namespace Kernel {

View file

@ -4,11 +4,10 @@
* SPDX-License-Identifier: BSD-2-Clause
*/
#include <Kernel/Arch/InterruptManagement.h>
#include <Kernel/Assertions.h>
#include <Kernel/Debug.h>
#include <Kernel/Interrupts/IRQHandler.h>
#include <Kernel/Interrupts/InterruptManagement.h>
#include <Kernel/Interrupts/PIC.h>
#include <Kernel/Interrupts/SharedIRQHandler.h>
#include <Kernel/Sections.h>

View file

@ -9,8 +9,8 @@
#include <AK/NonnullOwnPtr.h>
#include <AK/RefPtr.h>
#include <AK/Types.h>
#include <Kernel/Arch/IRQController.h>
#include <Kernel/Interrupts/GenericInterruptHandler.h>
#include <Kernel/Interrupts/IRQController.h>
namespace Kernel {
class IRQHandler;

View file

@ -4,8 +4,8 @@
* SPDX-License-Identifier: BSD-2-Clause
*/
#include <Kernel/Arch/InterruptManagement.h>
#include <Kernel/Arch/x86/Interrupts.h>
#include <Kernel/Interrupts/InterruptManagement.h>
#include <Kernel/Interrupts/PIC.h>
#include <Kernel/Interrupts/SpuriousInterruptHandler.h>
#include <Kernel/Sections.h>

View file

@ -8,8 +8,8 @@
#include <AK/OwnPtr.h>
#include <AK/Types.h>
#include <Kernel/Arch/IRQController.h>
#include <Kernel/Interrupts/GenericInterruptHandler.h>
#include <Kernel/Interrupts/IRQController.h>
namespace Kernel {