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:
parent
63ee2781fb
commit
f085903f62
22 changed files with 106 additions and 19 deletions
|
@ -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)
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -6,7 +6,7 @@
|
|||
|
||||
#pragma once
|
||||
|
||||
#include <Kernel/Interrupts/IRQController.h>
|
||||
#include <Kernel/Arch/x86/IRQController.h>
|
||||
#include <Kernel/Memory/TypedMapping.h>
|
||||
|
||||
namespace Kernel {
|
||||
|
|
|
@ -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 };
|
||||
};
|
||||
}
|
|
@ -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 {
|
||||
|
||||
|
|
|
@ -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 {
|
||||
|
||||
|
|
|
@ -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++;
|
||||
}
|
||||
}
|
||||
|
||||
}
|
|
@ -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;
|
||||
};
|
||||
|
||||
}
|
|
@ -7,7 +7,7 @@
|
|||
#pragma once
|
||||
|
||||
#include <AK/Types.h>
|
||||
#include <Kernel/Interrupts/IRQController.h>
|
||||
#include <Kernel/Arch/x86/IRQController.h>
|
||||
|
||||
namespace Kernel {
|
||||
|
||||
|
|
|
@ -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>
|
||||
|
||||
|
|
|
@ -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;
|
||||
|
|
|
@ -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>
|
||||
|
|
|
@ -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 {
|
||||
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue