Serenity Operating System
1/*
2 * Copyright (c) 2020, Liav A. <liavalb@hotmail.co.il>
3 *
4 * SPDX-License-Identifier: BSD-2-Clause
5 */
6
7#include <Kernel/Arch/InterruptManagement.h>
8#include <Kernel/Arch/x86_64/Interrupts.h>
9#include <Kernel/Interrupts/SpuriousInterruptHandler.h>
10#include <Kernel/Sections.h>
11
12namespace Kernel {
13
14UNMAP_AFTER_INIT void SpuriousInterruptHandler::initialize(u8 interrupt_number)
15{
16 auto* handler = new SpuriousInterruptHandler(interrupt_number);
17 handler->register_interrupt_handler();
18}
19
20void SpuriousInterruptHandler::initialize_for_disabled_master_pic()
21{
22 auto* handler = new SpuriousInterruptHandler(7);
23 register_disabled_interrupt_handler(7, *handler);
24 handler->enable_interrupt_vector_for_disabled_pic();
25}
26
27void SpuriousInterruptHandler::initialize_for_disabled_slave_pic()
28{
29 auto* handler = new SpuriousInterruptHandler(15);
30 register_disabled_interrupt_handler(15, *handler);
31 handler->enable_interrupt_vector_for_disabled_pic();
32}
33
34void SpuriousInterruptHandler::register_handler(GenericInterruptHandler& handler)
35{
36 VERIFY(!m_real_handler);
37 m_real_handler = adopt_own_if_nonnull(&handler);
38}
39void SpuriousInterruptHandler::unregister_handler(GenericInterruptHandler&)
40{
41 TODO();
42}
43
44bool SpuriousInterruptHandler::eoi()
45{
46 // Actually check if IRQ7 or IRQ15 are spurious, and if not, call EOI with the correct interrupt number.
47 if (m_real_irq) {
48 m_responsible_irq_controller->eoi(*this);
49 m_real_irq = false; // return to default state!
50 return true;
51 }
52 m_responsible_irq_controller->spurious_eoi(*this);
53 return false;
54}
55
56StringView SpuriousInterruptHandler::purpose() const
57{
58 if (!m_real_handler)
59 return "Spurious Interrupt Handler"sv;
60 return m_real_handler->purpose();
61}
62
63SpuriousInterruptHandler::SpuriousInterruptHandler(u8 irq)
64 : GenericInterruptHandler(irq)
65 , m_responsible_irq_controller(InterruptManagement::the().get_responsible_irq_controller(irq))
66{
67}
68
69SpuriousInterruptHandler::~SpuriousInterruptHandler() = default;
70
71bool SpuriousInterruptHandler::handle_interrupt(RegisterState const& state)
72{
73 // Actually check if IRQ7 or IRQ15 are spurious, and if not, call the real handler to handle the IRQ.
74 if (m_responsible_irq_controller->get_isr() & (1 << interrupt_number())) {
75 m_real_irq = true; // remember that we had a real IRQ, when EOI later!
76 if (m_real_handler->handle_interrupt(state)) {
77 m_real_handler->increment_call_count();
78 return true;
79 }
80 return false;
81 }
82 dbgln("Spurious interrupt, vector {}", interrupt_number());
83 return true;
84}
85
86void SpuriousInterruptHandler::enable_interrupt_vector_for_disabled_pic()
87{
88 m_enabled = true;
89 m_responsible_irq_controller = InterruptManagement::the().get_responsible_irq_controller(IRQControllerType::i8259, interrupt_number());
90}
91
92void SpuriousInterruptHandler::enable_interrupt_vector()
93{
94 if (m_enabled)
95 return;
96 m_enabled = true;
97 m_responsible_irq_controller->enable(*this);
98}
99
100void SpuriousInterruptHandler::disable_interrupt_vector()
101{
102 VERIFY(!m_real_irq); // this flag should not be set when we call this method
103 if (!m_enabled)
104 return;
105 m_enabled = false;
106 m_responsible_irq_controller->disable(*this);
107}
108
109StringView SpuriousInterruptHandler::controller() const
110{
111 if (m_responsible_irq_controller->type() == IRQControllerType::i82093AA)
112 return ""sv;
113 return m_responsible_irq_controller->model();
114}
115}