1
Fork 0
mirror of https://github.com/RGBCube/serenity synced 2025-07-27 02:07:36 +00:00

Kernel: Fix GenericInterruptHandler problems with virtual functions

Because registering and unregistering interrupt handlers triggers
calls to virtual functions, we can't do this in the constructor
and destructor.

Fixes #5539
This commit is contained in:
Tom 2021-02-26 17:17:57 -07:00 committed by Andreas Kling
parent 183ebaee91
commit 32d9534c67
11 changed files with 112 additions and 39 deletions

View file

@ -87,7 +87,8 @@ public:
static void initialize(u8 interrupt_number)
{
new APICIPIInterruptHandler(interrupt_number);
auto* handler = new APICIPIInterruptHandler(interrupt_number);
handler->register_interrupt_handler();
}
virtual void handle_interrupt(const RegisterState&) override;
@ -117,7 +118,8 @@ public:
static void initialize(u8 interrupt_number)
{
new APICErrInterruptHandler(interrupt_number);
auto* handler = new APICErrInterruptHandler(interrupt_number);
handler->register_interrupt_handler();
}
virtual void handle_interrupt(const RegisterState&) override;

View file

@ -40,25 +40,50 @@ GenericInterruptHandler::GenericInterruptHandler(u8 interrupt_number, bool disab
: m_interrupt_number(interrupt_number)
, m_disable_remap(disable_remap)
{
// NOTE: We cannot register or unregister the handler while the object
// is being constructed or deconstructed!
}
void GenericInterruptHandler::will_be_destroyed()
{
// This will be called for RefCounted interrupt handlers before the
// object is being destroyed. As soon as the destructor is invoked
// it is no longer advisable to unregister the handler (which causes
// calls to virtual functions), so let's do this right before
// invoking it
unregister_interrupt_handler();
}
void GenericInterruptHandler::register_interrupt_handler()
{
if (m_registered)
return;
if (m_disable_remap)
register_generic_interrupt_handler(m_interrupt_number, *this);
else
register_generic_interrupt_handler(InterruptManagement::acquire_mapped_interrupt_number(m_interrupt_number), *this);
m_registered = true;
}
GenericInterruptHandler::~GenericInterruptHandler()
void GenericInterruptHandler::unregister_interrupt_handler()
{
if (!m_registered)
return;
if (m_disable_remap)
unregister_generic_interrupt_handler(m_interrupt_number, *this);
else
unregister_generic_interrupt_handler(InterruptManagement::acquire_mapped_interrupt_number(m_interrupt_number), *this);
m_registered = false;
}
void GenericInterruptHandler::change_interrupt_number(u8 number)
{
VERIFY_INTERRUPTS_DISABLED();
VERIFY(!m_disable_remap);
unregister_generic_interrupt_handler(InterruptManagement::acquire_mapped_interrupt_number(interrupt_number()), *this);
if (m_registered) {
unregister_generic_interrupt_handler(InterruptManagement::acquire_mapped_interrupt_number(interrupt_number()), *this);
m_registered = false;
}
m_interrupt_number = number;
register_generic_interrupt_handler(InterruptManagement::acquire_mapped_interrupt_number(interrupt_number()), *this);
}

View file

@ -43,9 +43,17 @@ enum class HandlerType : u8 {
class GenericInterruptHandler {
public:
static GenericInterruptHandler& from(u8 interrupt_number);
virtual ~GenericInterruptHandler();
virtual ~GenericInterruptHandler()
{
VERIFY(!m_registered);
}
virtual void handle_interrupt(const RegisterState& regs) = 0;
void will_be_destroyed();
bool is_registered() const { return m_registered; }
void register_interrupt_handler();
void unregister_interrupt_handler();
u8 interrupt_number() const { return m_interrupt_number; }
size_t get_invoking_count() const { return m_invoking_count; }
@ -74,5 +82,6 @@ private:
Atomic<u32, AK::MemoryOrder::memory_order_relaxed> m_invoking_count { 0 };
u8 m_interrupt_number { 0 };
bool m_disable_remap { false };
bool m_registered { false };
};
}

View file

@ -56,6 +56,8 @@ bool IRQHandler::eoi()
void IRQHandler::enable_irq()
{
dbgln_if(IRQ_DEBUG, "Enable IRQ {}", interrupt_number());
if (!is_registered())
register_interrupt_handler();
m_enabled = true;
if (!m_shared_with_others)
m_responsible_irq_controller->enable(*this);

View file

@ -36,7 +36,9 @@ namespace Kernel {
UNMAP_AFTER_INIT void SharedIRQHandler::initialize(u8 interrupt_number)
{
new SharedIRQHandler(interrupt_number);
auto* handler = new SharedIRQHandler(interrupt_number);
handler->register_interrupt_handler();
handler->disable_interrupt_vector();
}
void SharedIRQHandler::register_handler(GenericInterruptHandler& handler)
@ -71,7 +73,6 @@ SharedIRQHandler::SharedIRQHandler(u8 irq)
#if INTERRUPT_DEBUG
klog() << "Shared Interrupt Handler registered @ " << interrupt_number();
#endif
disable_interrupt_vector();
}
SharedIRQHandler::~SharedIRQHandler()

View file

@ -31,7 +31,8 @@ namespace Kernel {
UNMAP_AFTER_INIT void SpuriousInterruptHandler::initialize(u8 interrupt_number)
{
new SpuriousInterruptHandler(interrupt_number);
auto* handler = new SpuriousInterruptHandler(interrupt_number);
handler->register_interrupt_handler();
}
void SpuriousInterruptHandler::register_handler(GenericInterruptHandler& handler)