Kernel/Interrupts: Initialize two spurious handlers when PIC is disabled

Even if the PIC was disabled it can still generate noise (spurious IRQs)
so we need to register two handlers for handling such cases.

Also, we declare interrupt service routine offset 0x20 to 0x2f as
reserved, so when the PIC is disabled, we can handle spurious IRQs from
the PIC at separate handlers.
This commit is contained in:
Liav A 2022-01-28 18:18:14 +02:00 committed by Idan Horowitz
parent 7028a64997
commit 88c5992e0b
Notes: sideshowbarker 2024-07-17 19:58:55 +09:00
8 changed files with 169 additions and 5 deletions

View file

@ -11,6 +11,54 @@
#include <AK/Platform.h>
VALIDATE_IS_X86()
GENERATE_GENERIC_INTERRUPT_HANDLER_ASM_ENTRY(32)
GENERATE_GENERIC_INTERRUPT_HANDLER_ASM_ENTRY(33)
GENERATE_GENERIC_INTERRUPT_HANDLER_ASM_ENTRY(34)
GENERATE_GENERIC_INTERRUPT_HANDLER_ASM_ENTRY(35)
GENERATE_GENERIC_INTERRUPT_HANDLER_ASM_ENTRY(36)
GENERATE_GENERIC_INTERRUPT_HANDLER_ASM_ENTRY(37)
GENERATE_GENERIC_INTERRUPT_HANDLER_ASM_ENTRY(38)
GENERATE_GENERIC_INTERRUPT_HANDLER_ASM_ENTRY(39)
GENERATE_GENERIC_INTERRUPT_HANDLER_ASM_ENTRY(40)
GENERATE_GENERIC_INTERRUPT_HANDLER_ASM_ENTRY(41)
GENERATE_GENERIC_INTERRUPT_HANDLER_ASM_ENTRY(42)
GENERATE_GENERIC_INTERRUPT_HANDLER_ASM_ENTRY(43)
GENERATE_GENERIC_INTERRUPT_HANDLER_ASM_ENTRY(44)
GENERATE_GENERIC_INTERRUPT_HANDLER_ASM_ENTRY(45)
GENERATE_GENERIC_INTERRUPT_HANDLER_ASM_ENTRY(46)
GENERATE_GENERIC_INTERRUPT_HANDLER_ASM_ENTRY(47)
GENERATE_GENERIC_INTERRUPT_HANDLER_ASM_ENTRY(48)
GENERATE_GENERIC_INTERRUPT_HANDLER_ASM_ENTRY(49)
GENERATE_GENERIC_INTERRUPT_HANDLER_ASM_ENTRY(50)
GENERATE_GENERIC_INTERRUPT_HANDLER_ASM_ENTRY(51)
GENERATE_GENERIC_INTERRUPT_HANDLER_ASM_ENTRY(52)
GENERATE_GENERIC_INTERRUPT_HANDLER_ASM_ENTRY(53)
GENERATE_GENERIC_INTERRUPT_HANDLER_ASM_ENTRY(54)
GENERATE_GENERIC_INTERRUPT_HANDLER_ASM_ENTRY(55)
GENERATE_GENERIC_INTERRUPT_HANDLER_ASM_ENTRY(56)
GENERATE_GENERIC_INTERRUPT_HANDLER_ASM_ENTRY(57)
GENERATE_GENERIC_INTERRUPT_HANDLER_ASM_ENTRY(58)
GENERATE_GENERIC_INTERRUPT_HANDLER_ASM_ENTRY(59)
GENERATE_GENERIC_INTERRUPT_HANDLER_ASM_ENTRY(60)
GENERATE_GENERIC_INTERRUPT_HANDLER_ASM_ENTRY(61)
GENERATE_GENERIC_INTERRUPT_HANDLER_ASM_ENTRY(62)
GENERATE_GENERIC_INTERRUPT_HANDLER_ASM_ENTRY(63)
GENERATE_GENERIC_INTERRUPT_HANDLER_ASM_ENTRY(64)
GENERATE_GENERIC_INTERRUPT_HANDLER_ASM_ENTRY(65)
GENERATE_GENERIC_INTERRUPT_HANDLER_ASM_ENTRY(66)
GENERATE_GENERIC_INTERRUPT_HANDLER_ASM_ENTRY(67)
GENERATE_GENERIC_INTERRUPT_HANDLER_ASM_ENTRY(68)
GENERATE_GENERIC_INTERRUPT_HANDLER_ASM_ENTRY(69)
GENERATE_GENERIC_INTERRUPT_HANDLER_ASM_ENTRY(70)
GENERATE_GENERIC_INTERRUPT_HANDLER_ASM_ENTRY(71)
GENERATE_GENERIC_INTERRUPT_HANDLER_ASM_ENTRY(72)
GENERATE_GENERIC_INTERRUPT_HANDLER_ASM_ENTRY(73)
GENERATE_GENERIC_INTERRUPT_HANDLER_ASM_ENTRY(74)
GENERATE_GENERIC_INTERRUPT_HANDLER_ASM_ENTRY(75)
GENERATE_GENERIC_INTERRUPT_HANDLER_ASM_ENTRY(76)
GENERATE_GENERIC_INTERRUPT_HANDLER_ASM_ENTRY(77)
GENERATE_GENERIC_INTERRUPT_HANDLER_ASM_ENTRY(78)
GENERATE_GENERIC_INTERRUPT_HANDLER_ASM_ENTRY(79)
GENERATE_GENERIC_INTERRUPT_HANDLER_ASM_ENTRY(80)
GENERATE_GENERIC_INTERRUPT_HANDLER_ASM_ENTRY(81)
GENERATE_GENERIC_INTERRUPT_HANDLER_ASM_ENTRY(82)

View file

@ -44,6 +44,7 @@ void register_interrupt_handler(u8 number, void (*handler)());
void register_user_callable_interrupt_handler(u8 number, void (*handler)());
GenericInterruptHandler& get_interrupt_handler(u8 interrupt_number);
void register_generic_interrupt_handler(u8 number, GenericInterruptHandler&);
void register_disabled_interrupt_handler(u8 number, GenericInterruptHandler& handler);
void unregister_generic_interrupt_handler(u8 number, GenericInterruptHandler&);
void idt_init();

View file

@ -8,6 +8,7 @@
#include <AK/Types.h>
#include <Kernel/Interrupts/GenericInterruptHandler.h>
#include <Kernel/Interrupts/PIC.h>
#include <Kernel/Interrupts/SharedIRQHandler.h>
#include <Kernel/Interrupts/SpuriousInterruptHandler.h>
#include <Kernel/Interrupts/UnhandledInterruptHandler.h>
@ -42,6 +43,7 @@ READONLY_AFTER_INIT static DescriptorTablePointer s_idtr;
READONLY_AFTER_INIT static IDTEntry s_idt[256];
static GenericInterruptHandler* s_interrupt_handler[GENERIC_INTERRUPT_HANDLERS_COUNT];
static GenericInterruptHandler* s_disabled_interrupt_handler[2];
static EntropySource s_entropy_source_interrupts { EntropySource::Static::Interrupts };
@ -496,10 +498,24 @@ void handle_interrupt(TrapFrame* trap)
{
clac();
auto& regs = *trap->regs;
VERIFY(regs.isr_number >= IRQ_VECTOR_BASE && regs.isr_number <= (IRQ_VECTOR_BASE + GENERIC_INTERRUPT_HANDLERS_COUNT));
u8 irq = (u8)(regs.isr_number - 0x50);
s_entropy_source_interrupts.add_random_event(irq);
auto* handler = s_interrupt_handler[irq];
GenericInterruptHandler* handler = nullptr;
// Note: we declare interrupt service routine offset 0x20 to 0x2f as
// reserved for when the PIC is disabled, so we can still route spurious
// IRQs to a different interrupt handlers at different location.
if (regs.isr_number >= pic_disabled_vector_base && regs.isr_number <= pic_disabled_vector_end) {
u8 irq = (u8)(regs.isr_number - pic_disabled_vector_base);
if (irq == 7) {
handler = s_disabled_interrupt_handler[0];
} else if (irq == 15) {
handler = s_disabled_interrupt_handler[1];
}
} else {
VERIFY(regs.isr_number >= IRQ_VECTOR_BASE && regs.isr_number <= (IRQ_VECTOR_BASE + GENERIC_INTERRUPT_HANDLERS_COUNT));
u8 irq = (u8)(regs.isr_number - IRQ_VECTOR_BASE);
s_entropy_source_interrupts.add_random_event(irq);
handler = s_interrupt_handler[irq];
}
VERIFY(handler);
handler->increment_invoking_counter();
handler->handle_interrupt(regs);
@ -529,6 +545,18 @@ static void revert_to_unused_handler(u8 interrupt_number)
handler->register_interrupt_handler();
}
void register_disabled_interrupt_handler(u8 number, GenericInterruptHandler& handler)
{
if (number == 15) {
s_disabled_interrupt_handler[0] = &handler;
return;
} else if (number == 7) {
s_disabled_interrupt_handler[1] = &handler;
return;
}
VERIFY_NOT_REACHED();
}
void register_generic_interrupt_handler(u8 interrupt_number, GenericInterruptHandler& handler)
{
VERIFY(interrupt_number < GENERIC_INTERRUPT_HANDLERS_COUNT);
@ -637,10 +665,58 @@ UNMAP_AFTER_INIT void idt_init()
register_interrupt_handler(0x0f, _exception15);
register_interrupt_handler(0x10, _exception16);
for (u8 i = 0x11; i < 0x50; i++)
for (u8 i = 0x11; i < 0x20; i++)
register_interrupt_handler(i, unimp_trap);
dbgln("Initializing unhandled interrupt handlers");
register_interrupt_handler(0x20, interrupt_32_asm_entry);
register_interrupt_handler(0x21, interrupt_33_asm_entry);
register_interrupt_handler(0x22, interrupt_34_asm_entry);
register_interrupt_handler(0x23, interrupt_35_asm_entry);
register_interrupt_handler(0x24, interrupt_36_asm_entry);
register_interrupt_handler(0x25, interrupt_37_asm_entry);
register_interrupt_handler(0x26, interrupt_38_asm_entry);
register_interrupt_handler(0x27, interrupt_39_asm_entry);
register_interrupt_handler(0x28, interrupt_40_asm_entry);
register_interrupt_handler(0x29, interrupt_41_asm_entry);
register_interrupt_handler(0x2a, interrupt_42_asm_entry);
register_interrupt_handler(0x2b, interrupt_43_asm_entry);
register_interrupt_handler(0x2c, interrupt_44_asm_entry);
register_interrupt_handler(0x2d, interrupt_45_asm_entry);
register_interrupt_handler(0x2e, interrupt_46_asm_entry);
register_interrupt_handler(0x2f, interrupt_47_asm_entry);
register_interrupt_handler(0x30, interrupt_48_asm_entry);
register_interrupt_handler(0x31, interrupt_49_asm_entry);
register_interrupt_handler(0x32, interrupt_50_asm_entry);
register_interrupt_handler(0x33, interrupt_51_asm_entry);
register_interrupt_handler(0x34, interrupt_52_asm_entry);
register_interrupt_handler(0x35, interrupt_53_asm_entry);
register_interrupt_handler(0x36, interrupt_54_asm_entry);
register_interrupt_handler(0x37, interrupt_55_asm_entry);
register_interrupt_handler(0x38, interrupt_56_asm_entry);
register_interrupt_handler(0x39, interrupt_57_asm_entry);
register_interrupt_handler(0x3a, interrupt_58_asm_entry);
register_interrupt_handler(0x3b, interrupt_59_asm_entry);
register_interrupt_handler(0x3c, interrupt_60_asm_entry);
register_interrupt_handler(0x3d, interrupt_61_asm_entry);
register_interrupt_handler(0x3e, interrupt_62_asm_entry);
register_interrupt_handler(0x3f, interrupt_63_asm_entry);
register_interrupt_handler(0x40, interrupt_64_asm_entry);
register_interrupt_handler(0x41, interrupt_65_asm_entry);
register_interrupt_handler(0x42, interrupt_66_asm_entry);
register_interrupt_handler(0x43, interrupt_67_asm_entry);
register_interrupt_handler(0x44, interrupt_68_asm_entry);
register_interrupt_handler(0x45, interrupt_69_asm_entry);
register_interrupt_handler(0x46, interrupt_70_asm_entry);
register_interrupt_handler(0x47, interrupt_71_asm_entry);
register_interrupt_handler(0x48, interrupt_72_asm_entry);
register_interrupt_handler(0x49, interrupt_73_asm_entry);
register_interrupt_handler(0x4a, interrupt_74_asm_entry);
register_interrupt_handler(0x4b, interrupt_75_asm_entry);
register_interrupt_handler(0x4c, interrupt_76_asm_entry);
register_interrupt_handler(0x4d, interrupt_77_asm_entry);
register_interrupt_handler(0x4e, interrupt_78_asm_entry);
register_interrupt_handler(0x4f, interrupt_79_asm_entry);
register_interrupt_handler(0x50, interrupt_80_asm_entry);
register_interrupt_handler(0x51, interrupt_81_asm_entry);
register_interrupt_handler(0x52, interrupt_82_asm_entry);

View file

@ -98,6 +98,15 @@ u8 InterruptManagement::get_irq_vector(u8 mapped_interrupt_vector)
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) {
@ -173,6 +182,8 @@ UNMAP_AFTER_INIT void InterruptManagement::switch_to_ioapic_mode()
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());
}

View file

@ -54,6 +54,7 @@ public:
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);
const Vector<ISAInterruptOverrideMetadata>& isa_overrides() const { return m_isa_interrupt_overrides; }

View file

@ -12,6 +12,7 @@
namespace Kernel {
static constexpr size_t pic_disabled_vector_base = 0x20;
static constexpr size_t pic_disabled_vector_end = 0x2f;
class PIC final : public IRQController {
public:

View file

@ -4,7 +4,9 @@
* SPDX-License-Identifier: BSD-2-Clause
*/
#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>
@ -16,6 +18,20 @@ UNMAP_AFTER_INIT void SpuriousInterruptHandler::initialize(u8 interrupt_number)
handler->register_interrupt_handler();
}
void SpuriousInterruptHandler::initialize_for_disabled_master_pic()
{
auto* handler = new SpuriousInterruptHandler(7);
register_disabled_interrupt_handler(7, *handler);
handler->enable_interrupt_vector_for_disabled_pic();
}
void SpuriousInterruptHandler::initialize_for_disabled_slave_pic()
{
auto* handler = new SpuriousInterruptHandler(15);
register_disabled_interrupt_handler(15, *handler);
handler->enable_interrupt_vector_for_disabled_pic();
}
void SpuriousInterruptHandler::register_handler(GenericInterruptHandler& handler)
{
VERIFY(!m_real_handler);
@ -70,6 +86,12 @@ bool SpuriousInterruptHandler::handle_interrupt(const RegisterState& state)
return true;
}
void SpuriousInterruptHandler::enable_interrupt_vector_for_disabled_pic()
{
m_enabled = true;
m_responsible_irq_controller = InterruptManagement::the().get_responsible_irq_controller(IRQControllerType::i8259, interrupt_number());
}
void SpuriousInterruptHandler::enable_interrupt_vector()
{
if (m_enabled)

View file

@ -16,6 +16,8 @@ namespace Kernel {
class SpuriousInterruptHandler final : public GenericInterruptHandler {
public:
static void initialize(u8 interrupt_number);
static void initialize_for_disabled_master_pic();
static void initialize_for_disabled_slave_pic();
virtual ~SpuriousInterruptHandler();
virtual bool handle_interrupt(const RegisterState& regs) override;
@ -32,6 +34,8 @@ public:
virtual StringView purpose() const override;
virtual StringView controller() const override;
void enable_interrupt_vector_for_disabled_pic();
private:
void enable_interrupt_vector();
void disable_interrupt_vector();