Serenity Operating System
1/*
2 * Copyright (c) 2020, Liav A. <liavalb@hotmail.co.il>
3 * All rights reserved.
4 *
5 * Redistribution and use in source and binary forms, with or without
6 * modification, are permitted provided that the following conditions are met:
7 *
8 * 1. Redistributions of source code must retain the above copyright notice, this
9 * list of conditions and the following disclaimer.
10 *
11 * 2. Redistributions in binary form must reproduce the above copyright notice,
12 * this list of conditions and the following disclaimer in the documentation
13 * and/or other materials provided with the distribution.
14 *
15 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
16 * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
17 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
18 * DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE
19 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
20 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
21 * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
22 * CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
23 * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
24 * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
25 */
26
27#include <Kernel/Arch/i386/CPU.h>
28#include <Kernel/Assertions.h>
29#include <Kernel/Interrupts/IRQHandler.h>
30#include <Kernel/Interrupts/InterruptManagement.h>
31#include <Kernel/Interrupts/PIC.h>
32#include <Kernel/Interrupts/SharedIRQHandler.h>
33
34//#define INTERRUPT_DEBUG
35namespace Kernel {
36
37void SharedIRQHandler::initialize(u8 interrupt_number)
38{
39 new SharedIRQHandler(interrupt_number);
40}
41
42void SharedIRQHandler::register_handler(GenericInterruptHandler& handler)
43{
44#ifdef INTERRUPT_DEBUG
45 klog() << "Interrupt Handler registered @ Shared Interrupt Handler " << m_interrupt_number;
46#endif
47 m_handlers.set(&handler);
48 enable_interrupt_vector();
49}
50void SharedIRQHandler::unregister_handler(GenericInterruptHandler& handler)
51{
52#ifdef INTERRUPT_DEBUG
53 klog() << "Interrupt Handler unregistered @ Shared Interrupt Handler " << m_interrupt_number;
54#endif
55 m_handlers.remove(&handler);
56 if (m_handlers.is_empty())
57 disable_interrupt_vector();
58}
59
60bool SharedIRQHandler::eoi()
61{
62#ifdef INTERRUPT_DEBUG
63 dbg() << "EOI IRQ " << interrupt_number();
64#endif
65 m_responsible_irq_controller->eoi(*this);
66 return true;
67}
68
69SharedIRQHandler::SharedIRQHandler(u8 irq)
70 : GenericInterruptHandler(irq)
71 , m_responsible_irq_controller(InterruptManagement::the().get_responsible_irq_controller(irq))
72{
73#ifdef INTERRUPT_DEBUG
74 klog() << "Shared Interrupt Handler registered @ " << m_interrupt_number;
75#endif
76 disable_interrupt_vector();
77}
78
79SharedIRQHandler::~SharedIRQHandler()
80{
81#ifdef INTERRUPT_DEBUG
82 klog() << "Shared Interrupt Handler unregistered @ " << interrupt_number();
83#endif
84 disable_interrupt_vector();
85}
86
87void SharedIRQHandler::handle_interrupt(const RegisterState& regs)
88{
89 ASSERT_INTERRUPTS_DISABLED();
90 increment_invoking_counter();
91#ifdef INTERRUPT_DEBUG
92 dbg() << "Interrupt @ " << interrupt_number();
93 dbg() << "Interrupt Handlers registered - " << m_handlers.size();
94#endif
95 int i = 0;
96 for (auto* handler : m_handlers) {
97#ifdef INTERRUPT_DEBUG
98 dbg() << "Going for Interrupt Handling @ " << i << ", Shared Interrupt " << interrupt_number();
99#endif
100 ASSERT(handler != nullptr);
101 if (handler->is_enabled()) {
102 handler->increment_invoking_counter();
103 handler->handle_interrupt(regs);
104 }
105
106#ifdef INTERRUPT_DEBUG
107 dbg() << "Going for Interrupt Handling @ " << i << ", Shared Interrupt " << interrupt_number() << " - End";
108#endif
109 i++;
110 }
111}
112
113void SharedIRQHandler::enable_interrupt_vector()
114{
115 if (m_enabled)
116 return;
117 m_enabled = true;
118 m_responsible_irq_controller->enable(*this);
119}
120
121void SharedIRQHandler::disable_interrupt_vector()
122{
123 if (!m_enabled)
124 return;
125 m_enabled = false;
126 m_responsible_irq_controller->disable(*this);
127}
128
129}