The Pedigree Project 0.1
hosted/IrqManager.cc
1/*
2 * Copyright (c) 2008-2014, Pedigree Developers
3 *
4 * Please see the CONTRIB file in the root of the source tree for a full
5 * list of contributors.
6 *
7 * Permission to use, copy, modify, and distribute this software for any
8 * purpose with or without fee is hereby granted, provided that the above
9 * copyright notice and this permission notice appear in all copies.
10 *
11 * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
12 * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
13 * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
14 * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
15 * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
16 * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
17 * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
18 */
19
20#include "IrqManager.h"
21#include "pedigree/kernel/Log.h"
22#include "pedigree/kernel/machine/IrqHandler.h"
23#include "pedigree/kernel/machine/SchedulerIrqHandler.h"
24#include "pedigree/kernel/processor/InterruptManager.h"
25#include "pedigree/kernel/processor/Processor.h"
26
27#include <signal.h>
28
29#include "system/kernel/core/processor/DeviceHardIrqContext.h"
30
31namespace {
32constexpr uint8_t TimerIrq = 0;
33constexpr uint8_t SchedulerIrq = 1;
34
35irq_id_t signalForIrq(uint8_t irq) {
36 if (irq == TimerIrq) {
37 return SIGUSR1;
38 }
39 if (irq == SchedulerIrq) {
40 return SIGUSR2;
41 }
42 return 0;
43}
44} // namespace
45
46HostedIrqManager HostedIrqManager::m_Instance;
47
49 return 0;
50}
51
55
57 const IrqPolicy& policy) {
58 if (irq != TimerIrq || !handler || policy != IrqPolicy::syntheticHard()) {
59 return 0;
60 }
61
62 HardIrqHandler* expected = nullptr;
63 if (!__atomic_compare_exchange_n(&m_TimerHandler, &expected, handler, false, __ATOMIC_RELEASE,
64 __ATOMIC_ACQUIRE)) {
65 return 0;
66 }
67 return signalForIrq(irq);
68}
69
73
75 const IrqPolicy& policy) {
76 if (irq != SchedulerIrq || !handler || policy != IrqPolicy::syntheticHard()) {
77 return 0;
78 }
79
80 SchedulerIrqHandler* expected = nullptr;
81 if (!__atomic_compare_exchange_n(&m_SchedulerHandler, &expected, handler, false, __ATOMIC_RELEASE,
82 __ATOMIC_ACQUIRE)) {
83 return 0;
84 }
85 return signalForIrq(irq);
86}
87
89 if (id != SIGUSR2 || !handler) {
90 return false;
91 }
92
93 SchedulerIrqHandler* expected = handler;
94 return __atomic_compare_exchange_n(&m_SchedulerHandler, &expected,
95 static_cast<SchedulerIrqHandler*>(nullptr), false,
96 __ATOMIC_ACQ_REL, __ATOMIC_ACQUIRE);
97}
98
100 if (id != SIGUSR1 || !handler) {
101 return false;
102 }
103
104 HardIrqHandler* expected = __atomic_load_n(&m_TimerHandler, __ATOMIC_ACQUIRE);
105 if (static_cast<IrqHandlerBase*>(expected) != handler) {
106 return false;
107 }
108 return __atomic_compare_exchange_n(&m_TimerHandler, &expected,
109 static_cast<HardIrqHandler*>(nullptr), false, __ATOMIC_ACQ_REL,
110 __ATOMIC_ACQUIRE);
111}
112
113bool HostedIrqManager::initialise() {
115 return manager.registerInterruptHandler(SIGUSR1, this) &&
116 manager.registerInterruptHandler(SIGUSR2, this);
117}
118
120 return false;
121}
122
123HostedIrqManager::HostedIrqManager() : m_TimerHandler(nullptr), m_SchedulerHandler(nullptr) {}
124
125void HostedIrqManager::interrupt(size_t interruptNumber, InterruptState& state) {
126 if (interruptNumber == SIGUSR1) {
127 HardIrqHandler* handler = __atomic_load_n(&m_TimerHandler, __ATOMIC_ACQUIRE);
128 if (!handler) {
129 return;
130 }
131
132 size_t previousDepth = 0;
133 bool restoreDepth = false;
134 DeviceHardIrqContext context(previousDepth, restoreDepth);
135 const HardIrqDisposition disposition = handler->irq(TimerIrq, state);
136 if (disposition != HardIrqDisposition::Handled) {
137 FATAL_NOLOCK("Hosted timer hard stage failed to publish its deferred work");
138 }
139 return;
140 }
141
142 if (interruptNumber == SIGUSR2) {
143 SchedulerIrqHandler* handler = __atomic_load_n(&m_SchedulerHandler, __ATOMIC_ACQUIRE);
144 if (handler) {
145 // This callback may abandon the signal frame and must stay the
146 // terminal action for the synthetic scheduler occurrence.
147 handler->schedulerIrq(SchedulerIrq, state);
148 }
149 }
150}
151
152#if HOSTED && PEDIGREE_HOSTED_SMOKE_TESTS
153SchedulerIrqHandler* HostedIrqManager::schedulerIrqHandlerForTest(uint8_t irq) {
154 if (irq != SchedulerIrq) {
155 return nullptr;
156 }
157 return __atomic_load_n(&m_Instance.m_SchedulerHandler, __ATOMIC_ACQUIRE);
158}
159#endif
virtual HardIrqDisposition irq(irq_id_t number, InterruptState &state)=0
irq_id_t registerSchedulerIrqHandler(uint8_t irq, SchedulerIrqHandler *handler, const IrqPolicy &policy) override
bool unregisterHandler(irq_id_t id, IrqHandlerBase *handler) override
irq_id_t registerIsaIrqHandler(uint8_t irq, IrqHandler *handler, const IrqPolicy &policy) override
irq_id_t registerHardPciIrqHandler(HardIrqHandler *handler, class Device *device, const IrqPolicy &policy) override
bool unregisterSchedulerIrqHandler(irq_id_t id, SchedulerIrqHandler *handler) override
irq_id_t registerPciIrqHandler(IrqHandler *handler, class Device *device, const IrqPolicy &policy) override
void interrupt(size_t interruptNumber, InterruptState &state) override
irq_id_t registerHardIsaIrqHandler(uint8_t irq, HardIrqHandler *handler, const IrqPolicy &policy) override
bool control(uint8_t irq, ControlCode code, size_t argument) override
Handles interrupts and interrupt registrations from kernel components.
static EXPORTED_PUBLIC InterruptManager & instance()
virtual bool registerInterruptHandler(size_t nInterruptNumber, InterruptHandler *pHandler)=0
HardIrqDisposition
Definition IrqHandler.h:44