1
0
Fork 0
mirror of https://github.com/LadybirdBrowser/ladybird.git synced 2025-06-12 10:40:39 +09:00

Kernel: Abstract IRQ controller handling from Interrupt handlers

Now we don't send raw numbers, but we let the IRQController object to
figure out the correct IRQ number.
This helps in a situation when we have 2 or more IOAPICs, so if IOAPIC
1 is assigned for IRQs 0-23 and IOAPIC 2 is assigned for IRQs 24-47,
if an IRQHandler of IRQ 25 invokes disable() for example, it will call
his responsible IRQController (IOAPIC 2), and the IRQController will
subtract the IRQ number with his assigned offset, and the result is that
the second redirection entry in IOAPIC 2 will be masked.
This commit is contained in:
Liav A 2020-03-08 12:47:33 +02:00 committed by Andreas Kling
parent 666990fbcb
commit f86be46c98
Notes: sideshowbarker 2024-07-19 08:09:21 +09:00
11 changed files with 97 additions and 45 deletions

View file

@ -157,6 +157,11 @@ void eoi()
write_register(APIC_REG_EOI, 0x0);
}
u8 spurious_interrupt_vector()
{
return IRQ_APIC_SPURIOUS;
}
bool init()
{
// FIXME: Use the ACPI MADT table

View file

@ -36,7 +36,7 @@ void enable_bsp();
void eoi();
bool init();
void enable(u32 cpu);
u8 spurious_interrupt_vector();
}
}

View file

@ -48,11 +48,11 @@ IOAPIC::IOAPIC(ioapic_mmio_regs& regs, u32 gsi_base)
, 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_redirection_entries_count((read_register(0x1) >> 16) + 1)
{
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 Version: 0x" << String::format("%x", m_version) << ", Redirection Entries count - " << m_redirection_entries_count;
klog() << "IOAPIC Arbitration ID 0x" << String::format("%x", read_register(0x2));
mask_all_redirection_entries();
}
@ -99,7 +99,7 @@ void IOAPIC::map_interrupt_redirection(u8 interrupt_vector)
trigger_level_mode = true;
break;
}
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);
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);
@ -117,11 +117,21 @@ void IOAPIC::map_pci_interrupts()
configure_redirection_entry(11, 11 + IRQ_VECTOR_BASE, DeliveryMode::Normal, false, false, true, true, 0);
}
void IOAPIC::spurious_eoi(const GenericInterruptHandler& handler) const
{
InterruptDisabler disabler;
ASSERT(handler.type() == HandlerType::SpuriousInterruptHandler);
ASSERT(handler.interrupt_number() == APIC::spurious_interrupt_vector());
klog() << "IOAPIC::spurious_eoi - Spurious Interrupt occurred";
}
void IOAPIC::map_isa_interrupts()
{
InterruptDisabler disabler;
for (auto redirection_override : InterruptManagement::the().isa_overrides()) {
ASSERT(!redirection_override.is_null());
if ((redirection_override->gsi() < gsi_base()) || (redirection_override->gsi() >= (gsi_base() + m_redirection_entries_count)))
continue;
bool active_low;
// See ACPI spec Version 6.2, page 205 to learn more about Interrupt Overriding Flags.
switch ((redirection_override->flags() & 0b11)) {
@ -153,14 +163,14 @@ void IOAPIC::map_isa_interrupts()
trigger_level_mode = true;
break;
}
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);
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; index++)
for (size_t index = 0; index < m_redirection_entries_count; index++)
reset_redirection_entry(index);
}
@ -180,7 +190,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);
ASSERT((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);
@ -196,26 +206,26 @@ void IOAPIC::configure_redirection_entry(int index, u8 interrupt_vector, u8 deli
void IOAPIC::mask_all_redirection_entries() const
{
InterruptDisabler disabler;
for (size_t index = 0; index < m_redirection_entries; index++)
for (size_t index = 0; index < m_redirection_entries_count; index++)
mask_redirection_entry(index);
}
void IOAPIC::mask_redirection_entry(u8 index) const
{
ASSERT((u32)index < m_redirection_entries);
ASSERT((u32)index < m_redirection_entries_count);
u32 redirection_entry = read_register((index << 1) + IOAPIC_REDIRECTION_ENTRY_OFFSET) | (1 << 16);
write_register((index << 1) + IOAPIC_REDIRECTION_ENTRY_OFFSET, redirection_entry);
}
bool IOAPIC::is_redirection_entry_masked(u8 index) const
{
ASSERT((u32)index < m_redirection_entries);
ASSERT((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
{
ASSERT((u32)index < m_redirection_entries);
ASSERT((u32)index < m_redirection_entries_count);
u32 redirection_entry = read_register((index << 1) + IOAPIC_REDIRECTION_ENTRY_OFFSET);
write_register((index << 1) + IOAPIC_REDIRECTION_ENTRY_OFFSET, redirection_entry & ~(1 << 16));
}
@ -228,24 +238,26 @@ bool IOAPIC::is_vector_enabled(u8 interrupt_vector) const
u8 IOAPIC::read_redirection_entry_vector(u8 index) const
{
ASSERT((u32)index < m_redirection_entries);
ASSERT((u32)index < m_redirection_entries_count);
return (read_register((index << 1) + IOAPIC_REDIRECTION_ENTRY_OFFSET) & 0xFF);
}
int IOAPIC::find_redirection_entry_by_vector(u8 vector) const
{
InterruptDisabler disabler;
for (size_t index = 0; index < m_redirection_entries; index++) {
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 -1;
}
void IOAPIC::disable(u8 interrupt_vector)
void IOAPIC::disable(const GenericInterruptHandler& handler)
{
InterruptDisabler disabler;
ASSERT(!is_hard_disabled());
u8 interrupt_vector = handler.interrupt_number();
ASSERT(interrupt_vector >= gsi_base() && interrupt_vector < interrupt_vectors_count());
int index = find_redirection_entry_by_vector(interrupt_vector);
if (index == (-1)) {
map_interrupt_redirection(interrupt_vector);
@ -255,10 +267,12 @@ void IOAPIC::disable(u8 interrupt_vector)
mask_redirection_entry(index);
}
void IOAPIC::enable(u8 interrupt_vector)
void IOAPIC::enable(const GenericInterruptHandler& handler)
{
InterruptDisabler disabler;
ASSERT(!is_hard_disabled());
u8 interrupt_vector = handler.interrupt_number();
ASSERT(interrupt_vector >= gsi_base() && interrupt_vector < interrupt_vectors_count());
int index = find_redirection_entry_by_vector(interrupt_vector);
if (index == (-1)) {
map_interrupt_redirection(interrupt_vector);
@ -268,10 +282,12 @@ void IOAPIC::enable(u8 interrupt_vector)
unmask_redirection_entry(index);
}
void IOAPIC::eoi(u8) const
void IOAPIC::eoi(const GenericInterruptHandler& handler) const
{
InterruptDisabler disabler;
ASSERT(!is_hard_disabled());
ASSERT(handler.interrupt_number() >= gsi_base() && handler.interrupt_number() < interrupt_vectors_count());
ASSERT(handler.type() != HandlerType::SpuriousInterruptHandler);
APIC::eoi();
}

View file

@ -42,14 +42,16 @@ class PCIInterruptOverrideMetadata;
class IOAPIC final : public IRQController {
public:
IOAPIC(ioapic_mmio_regs& regs, u32 gsi_base);
virtual void enable(u8 number) override;
virtual void disable(u8 number) override;
virtual void enable(const GenericInterruptHandler&) override;
virtual void disable(const GenericInterruptHandler&) override;
virtual void hard_disable() override;
virtual void eoi(u8 number) const override;
virtual void eoi(const GenericInterruptHandler&) const override;
virtual void spurious_eoi(const GenericInterruptHandler&) const override;
virtual bool is_vector_enabled(u8 number) const override;
virtual u16 get_isr() const override;
virtual u16 get_irr() const override;
virtual u32 get_gsi_base() const override { return m_gsi_base; }
virtual u32 gsi_base() const override { return m_gsi_base; }
virtual size_t interrupt_vectors_count() const { return m_redirection_entries_count; }
virtual const char* model() const override { return "IOAPIC"; };
virtual IRQControllerType type() const override { return IRQControllerType::i82093AA; }
@ -80,6 +82,6 @@ private:
u32 m_gsi_base;
u8 m_id;
u8 m_version;
u32 m_redirection_entries;
size_t m_redirection_entries_count;
};
}

View file

@ -41,14 +41,16 @@ class IRQController : public RefCounted<IRQController> {
public:
virtual ~IRQController() {}
virtual void enable(u8 number) = 0;
virtual void disable(u8 number) = 0;
virtual void enable(const GenericInterruptHandler&) = 0;
virtual void disable(const GenericInterruptHandler&) = 0;
virtual void hard_disable() { m_hard_disabled = true; }
virtual bool is_vector_enabled(u8 number) const = 0;
bool is_enabled() const { return m_enabled && !m_hard_disabled; }
bool is_hard_disabled() const { return m_hard_disabled; }
virtual void eoi(u8 number) const = 0;
virtual u32 get_gsi_base() const = 0;
virtual void eoi(const GenericInterruptHandler&) const = 0;
virtual void spurious_eoi(const GenericInterruptHandler&) 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 const char* model() const = 0;

View file

@ -49,7 +49,7 @@ bool IRQHandler::eoi()
#endif
if (!m_shared_with_others) {
ASSERT(!m_responsible_irq_controller.is_null());
m_responsible_irq_controller->eoi(interrupt_number());
m_responsible_irq_controller->eoi(*this);
return true;
}
return false;
@ -61,7 +61,7 @@ void IRQHandler::enable_irq()
dbg() << "Enable IRQ " << interrupt_number();
#endif
if (!m_shared_with_others)
m_responsible_irq_controller->enable(interrupt_number());
m_responsible_irq_controller->enable(*this);
else
m_enabled = true;
}
@ -72,7 +72,7 @@ void IRQHandler::disable_irq()
dbg() << "Disable IRQ " << interrupt_number();
#endif
if (!m_shared_with_others)
m_responsible_irq_controller->disable(interrupt_number());
m_responsible_irq_controller->disable(*this);
else
m_enabled = false;
}

View file

@ -114,7 +114,7 @@ RefPtr<IRQController> InterruptManagement::get_responsible_irq_controller(u8 int
return m_interrupt_controllers[0];
}
for (auto irq_controller : m_interrupt_controllers) {
if (irq_controller->get_gsi_base() <= interrupt_vector)
if (irq_controller->gsi_base() <= interrupt_vector)
if (!irq_controller->is_hard_disabled())
return irq_controller;
}

View file

@ -27,6 +27,7 @@
#include <AK/Assertions.h>
#include <AK/Types.h>
#include <Kernel/Arch/i386/CPU.h>
#include <Kernel/Interrupts/GenericInterruptHandler.h>
#include <Kernel/Interrupts/PIC.h>
#include <LibBareMetal/IO.h>
@ -58,10 +59,12 @@ bool inline static is_all_masked(u8 reg)
return reg == 0xFF;
}
void PIC::disable(u8 irq)
void PIC::disable(const GenericInterruptHandler& handler)
{
InterruptDisabler disabler;
ASSERT(!is_hard_disabled());
ASSERT(handler.interrupt_number() >= gsi_base() && handler.interrupt_number() < interrupt_vectors_count());
u8 irq = handler.interrupt_number();
u8 imr;
if (irq >= 8) {
imr = IO::in8(PIC1_CMD);
@ -82,6 +85,13 @@ PIC::PIC()
initialize();
}
void PIC::spurious_eoi(const GenericInterruptHandler& handler) const
{
ASSERT(handler.type() == HandlerType::SpuriousInterruptHandler);
if (handler.interrupt_number() == 15)
eoi_interrupt(7);
}
bool PIC::is_vector_enabled(u8 irq) const
{
u8 imr;
@ -95,7 +105,15 @@ bool PIC::is_vector_enabled(u8 irq) const
return imr != 0;
}
void PIC::enable(u8 irq)
void PIC::enable(const GenericInterruptHandler& handler)
{
InterruptDisabler disabler;
ASSERT(!is_hard_disabled());
ASSERT(handler.interrupt_number() >= gsi_base() && handler.interrupt_number() < interrupt_vectors_count());
enable_vector(handler.interrupt_number());
}
void PIC::enable_vector(u8 irq)
{
InterruptDisabler disabler;
ASSERT(!is_hard_disabled());
@ -112,10 +130,16 @@ void PIC::enable(u8 irq)
m_enabled = true;
}
void PIC::eoi(u8 irq) const
void PIC::eoi(const GenericInterruptHandler& handler) const
{
InterruptDisabler disabler;
ASSERT(!is_hard_disabled());
ASSERT(handler.interrupt_number() >= gsi_base() && handler.interrupt_number() < interrupt_vectors_count());
eoi_interrupt(handler.interrupt_number());
}
void PIC::eoi_interrupt(u8 irq) const
{
if (irq >= 8)
IO::out8(PIC1_CTL, 0x20);
IO::out8(PIC0_CTL, 0x20);
@ -159,7 +183,7 @@ void PIC::remap(u8 offset)
IO::out8(PIC1_CMD, 0xff);
// ...except IRQ2, since that's needed for the master to let through slave interrupts.
enable(2);
enable_vector(2);
}
void PIC::initialize()
@ -185,7 +209,7 @@ void PIC::initialize()
IO::out8(PIC1_CMD, 0xff);
// ...except IRQ2, since that's needed for the master to let through slave interrupts.
enable(2);
enable_vector(2);
klog() << "PIC(i8259): cascading mode, vectors 0x" << String::format("%x", IRQ_VECTOR_BASE) << "-0x" << String::format("%x", IRQ_VECTOR_BASE + 0xf);
}

View file

@ -33,18 +33,22 @@ namespace Kernel {
class PIC final : public IRQController {
public:
PIC();
virtual void enable(u8 number) override;
virtual void disable(u8 number) override;
virtual void enable(const GenericInterruptHandler&) override;
virtual void disable(const GenericInterruptHandler&) override;
virtual void hard_disable() override;
virtual void eoi(u8 number) const override;
virtual void eoi(const GenericInterruptHandler&) const override;
virtual bool is_vector_enabled(u8 number) const override;
virtual void spurious_eoi(const GenericInterruptHandler&) const override;
virtual u16 get_isr() const override;
virtual u16 get_irr() const override;
virtual u32 get_gsi_base() const override { return 0; }
virtual u32 gsi_base() const override { return 0; }
virtual size_t interrupt_vectors_count() const { return 16; }
virtual const char* model() const override { return "Dual i8259"; }
virtual IRQControllerType type() const override { return IRQControllerType::i8259; }
private:
void eoi_interrupt(u8 irq) const;
void enable_vector(u8 number);
void remap(u8 offset);
void complete_eoi() const;
virtual void initialize() override;

View file

@ -62,7 +62,7 @@ bool SharedIRQHandler::eoi()
#ifdef INTERRUPT_DEBUG
dbg() << "EOI IRQ " << interrupt_number();
#endif
m_responsible_irq_controller->eoi(interrupt_number());
m_responsible_irq_controller->eoi(*this);
return true;
}
@ -115,7 +115,7 @@ void SharedIRQHandler::enable_interrupt_vector()
if (m_enabled)
return;
m_enabled = true;
m_responsible_irq_controller->enable(interrupt_number());
m_responsible_irq_controller->enable(*this);
}
void SharedIRQHandler::disable_interrupt_vector()
@ -123,7 +123,7 @@ void SharedIRQHandler::disable_interrupt_vector()
if (!m_enabled)
return;
m_enabled = false;
m_responsible_irq_controller->disable(interrupt_number());
m_responsible_irq_controller->disable(*this);
}
}

View file

@ -44,8 +44,7 @@ void SpuriousInterruptHandler::unregister_handler(GenericInterruptHandler&)
bool SpuriousInterruptHandler::eoi()
{
// FIXME: Actually check if IRQ7 or IRQ15 are spurious, and if not, call EOI with the correct interrupt number.
if (interrupt_number() == 15)
m_responsible_irq_controller->eoi(7);
m_responsible_irq_controller->spurious_eoi(*this);
return false;
}
@ -70,7 +69,7 @@ void SpuriousInterruptHandler::enable_interrupt_vector()
if (m_enabled)
return;
m_enabled = true;
m_responsible_irq_controller->enable(interrupt_number());
m_responsible_irq_controller->enable(*this);
}
void SpuriousInterruptHandler::disable_interrupt_vector()
@ -78,7 +77,7 @@ void SpuriousInterruptHandler::disable_interrupt_vector()
if (!m_enabled)
return;
m_enabled = false;
m_responsible_irq_controller->disable(interrupt_number());
m_responsible_irq_controller->disable(*this);
}
const char* SpuriousInterruptHandler::controller() const