1
Fork 0
mirror of https://github.com/RGBCube/serenity synced 2025-06-01 02:38:13 +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

@ -384,64 +384,77 @@ static void unimp_trap()
GenericInterruptHandler& get_interrupt_handler(u8 interrupt_number)
{
VERIFY(s_interrupt_handler[interrupt_number] != nullptr);
return *s_interrupt_handler[interrupt_number];
auto*& handler_slot = s_interrupt_handler[interrupt_number];
VERIFY(handler_slot != nullptr);
return *handler_slot;
}
static void revert_to_unused_handler(u8 interrupt_number)
{
new UnhandledInterruptHandler(interrupt_number);
auto handler = new UnhandledInterruptHandler(interrupt_number);
handler->register_interrupt_handler();
}
void register_generic_interrupt_handler(u8 interrupt_number, GenericInterruptHandler& handler)
{
VERIFY(interrupt_number < GENERIC_INTERRUPT_HANDLERS_COUNT);
if (s_interrupt_handler[interrupt_number] != nullptr) {
if (s_interrupt_handler[interrupt_number]->type() == HandlerType::UnhandledInterruptHandler) {
s_interrupt_handler[interrupt_number] = &handler;
auto*& handler_slot = s_interrupt_handler[interrupt_number];
if (handler_slot != nullptr) {
if (handler_slot->type() == HandlerType::UnhandledInterruptHandler) {
if (handler_slot) {
auto* unhandled_handler = static_cast<UnhandledInterruptHandler*>(handler_slot);
unhandled_handler->unregister_interrupt_handler();
delete unhandled_handler;
}
handler_slot = &handler;
return;
}
if (s_interrupt_handler[interrupt_number]->is_shared_handler() && !s_interrupt_handler[interrupt_number]->is_sharing_with_others()) {
VERIFY(s_interrupt_handler[interrupt_number]->type() == HandlerType::SharedIRQHandler);
static_cast<SharedIRQHandler*>(s_interrupt_handler[interrupt_number])->register_handler(handler);
if (handler_slot->is_shared_handler() && !handler_slot->is_sharing_with_others()) {
VERIFY(handler_slot->type() == HandlerType::SharedIRQHandler);
static_cast<SharedIRQHandler*>(handler_slot)->register_handler(handler);
return;
}
if (!s_interrupt_handler[interrupt_number]->is_shared_handler()) {
if (s_interrupt_handler[interrupt_number]->type() == HandlerType::SpuriousInterruptHandler) {
static_cast<SpuriousInterruptHandler*>(s_interrupt_handler[interrupt_number])->register_handler(handler);
if (!handler_slot->is_shared_handler()) {
if (handler_slot->type() == HandlerType::SpuriousInterruptHandler) {
static_cast<SpuriousInterruptHandler*>(handler_slot)->register_handler(handler);
return;
}
VERIFY(s_interrupt_handler[interrupt_number]->type() == HandlerType::IRQHandler);
auto& previous_handler = *s_interrupt_handler[interrupt_number];
s_interrupt_handler[interrupt_number] = nullptr;
VERIFY(handler_slot->type() == HandlerType::IRQHandler);
auto& previous_handler = *handler_slot;
handler_slot = nullptr;
SharedIRQHandler::initialize(interrupt_number);
static_cast<SharedIRQHandler*>(s_interrupt_handler[interrupt_number])->register_handler(previous_handler);
static_cast<SharedIRQHandler*>(s_interrupt_handler[interrupt_number])->register_handler(handler);
VERIFY(handler_slot);
static_cast<SharedIRQHandler*>(handler_slot)->register_handler(previous_handler);
static_cast<SharedIRQHandler*>(handler_slot)->register_handler(handler);
return;
}
VERIFY_NOT_REACHED();
} else {
s_interrupt_handler[interrupt_number] = &handler;
handler_slot = &handler;
}
}
void unregister_generic_interrupt_handler(u8 interrupt_number, GenericInterruptHandler& handler)
{
VERIFY(s_interrupt_handler[interrupt_number] != nullptr);
if (s_interrupt_handler[interrupt_number]->type() == HandlerType::UnhandledInterruptHandler) {
auto*& handler_slot = s_interrupt_handler[interrupt_number];
VERIFY(handler_slot != nullptr);
if (handler_slot->type() == HandlerType::UnhandledInterruptHandler) {
dbgln("Trying to unregister unused handler (?)");
return;
}
if (s_interrupt_handler[interrupt_number]->is_shared_handler() && !s_interrupt_handler[interrupt_number]->is_sharing_with_others()) {
VERIFY(s_interrupt_handler[interrupt_number]->type() == HandlerType::SharedIRQHandler);
static_cast<SharedIRQHandler*>(s_interrupt_handler[interrupt_number])->unregister_handler(handler);
if (!static_cast<SharedIRQHandler*>(s_interrupt_handler[interrupt_number])->sharing_devices_count()) {
if (handler_slot->is_shared_handler() && !handler_slot->is_sharing_with_others()) {
VERIFY(handler_slot->type() == HandlerType::SharedIRQHandler);
auto* shared_handler = static_cast<SharedIRQHandler*>(handler_slot);
shared_handler->unregister_handler(handler);
if (!shared_handler->sharing_devices_count()) {
handler_slot = nullptr;
revert_to_unused_handler(interrupt_number);
}
return;
}
if (!s_interrupt_handler[interrupt_number]->is_shared_handler()) {
VERIFY(s_interrupt_handler[interrupt_number]->type() == HandlerType::IRQHandler);
if (!handler_slot->is_shared_handler()) {
VERIFY(handler_slot->type() == HandlerType::IRQHandler);
handler_slot = nullptr;
revert_to_unused_handler(interrupt_number);
return;
}
@ -671,7 +684,8 @@ UNMAP_AFTER_INIT static void idt_init()
dbgln("Installing Unhandled Handlers");
for (u8 i = 0; i < GENERIC_INTERRUPT_HANDLERS_COUNT; ++i) {
new UnhandledInterruptHandler(i);
auto* handler = new UnhandledInterruptHandler(i);
handler->register_interrupt_handler();
}
flush_idt();