mirror of
https://github.com/LadybirdBrowser/ladybird.git
synced 2024-11-26 01:20:25 +00:00
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:
parent
7028a64997
commit
88c5992e0b
Notes:
sideshowbarker
2024-07-17 19:58:55 +09:00
Author: https://github.com/supercomputer7 Commit: https://github.com/SerenityOS/serenity/commit/88c5992e0bb Pull-request: https://github.com/SerenityOS/serenity/pull/12182 Issue: https://github.com/SerenityOS/serenity/issues/12134 Reviewed-by: https://github.com/IdanHo ✅ Reviewed-by: https://github.com/Panky-codes
8 changed files with 169 additions and 5 deletions
|
@ -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)
|
||||
|
|
|
@ -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();
|
||||
|
|
|
@ -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);
|
||||
|
|
|
@ -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());
|
||||
}
|
||||
|
|
|
@ -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; }
|
||||
|
||||
|
|
|
@ -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:
|
||||
|
|
|
@ -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)
|
||||
|
|
|
@ -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();
|
||||
|
|
Loading…
Reference in a new issue