PatchworkOS  19e446b
A non-POSIX operating system.
Loading...
Searching...
No Matches
irq.h
Go to the documentation of this file.
1#pragma once
2
5
6#include <stdbool.h>
7#include <stdint.h>
8#include <sys/list.h>
9
10typedef struct cpu cpu_t;
11
12typedef struct irq_chip irq_chip_t;
13typedef struct irq_domain irq_domain_t;
14typedef struct irq irq_t;
15
16/**
17 * @brief Interrupt Requests (IRQs)
18 * @defgroup kernel_cpu_irq IRQ
19 * @ingroup kernel_cpu
20 *
21 * The IRQ system is responsible for managing external interrupts in the system (as in vectors [`VECTOR_EXTERNAL_START`,
22 * `VECTOR_EXTERNAL_END`)), where the hardware trigger a physical IRQ (`irq_phys_t`) which is then mapped to a virtual
23 * IRQ (`irq_virt_t`) using a `irq_chip_t`.
24 *
25 * ## Physical vs Virtual IRQs
26 *
27 * The IRQ chips are usually implemented in a driver and they are responsible for the actual physical to virtual
28 * mapping.
29 *
30 * Note that physical to virtual mapping might not be 1:1 and that there could be multiple `irq_chip_t`s in the system.
31 *
32 * So, for example, say we receive a physical IRQ 1, which is usually the ps2 keyboard interrupt. Lets also say we have
33 * a single IRQ chip, the IOAPIC, which is configured to map physical IRQ 1 to virtual IRQ 0x21 on CPU 0. We would then
34 * see all handlers registered for virtual IRQ 0x21 being called on CPU 0.
35 *
36 * @todo Currently, this system is still simplistic. For example, it cant handle trees of IRQ chips, or multiple chips
37 * handling the same physical IRQs. This should be fixed in the future as needed.
38 *
39 * @{
40 */
41
42/**
43 * @brief Physical IRQ numbers.
44 * @typedef irq_phys_t
45 */
47
48/**
49 * @brief Constant representing no physical IRQ.
50 */
51#define IRQ_PHYS_NONE UINT32_MAX
52
53/**
54 * @brief Virtual IRQ numbers.
55 * @typedef irq_virt_t
56 */
58
59/**
60 * @brief Data passed to IRQ functions.
61 * @struct irq_func_data_t
62 */
69
70/**
71 * @brief Callback function type for IRQs.
72 */
74
75/**
76 * @brief Structure to hold an IRQ function and its data.
77 */
85
86/**
87 * @brief IRQ flags.
88 * @enum irq_flags_t
89 *
90 * Specifies the expected behaviour of an IRQ to a IRQ chip.
91 */
92typedef enum
93{
94 IRQ_POLARITY_HIGH = 0 << 0, ///< If set, the IRQ is active high.
95 IRQ_POLARITY_LOW = 1 << 0, ///< If set, the IRQ is active low. Otherwise, active high.
96 IRQ_TRIGGER_LEVEL = 0 << 1, ///< If set, the IRQ is level triggered.
97 IRQ_TRIGGER_EDGE = 1 << 1, ///< If set, the IRQ is edge triggered. Otherwise, level triggered.
98 IRQ_EXCLUSIVE = 0 << 2, ///< If set, the IRQ is exclusive (not shared).
99 IRQ_SHARED = 1 << 2, ///< If set, the IRQ is shared.
101
102/**
103 * @brief IRQ structure.
104 * @struct irq_t
105 *
106 * Represents a single virtual IRQ mapped to a physical IRQ.
107 */
108typedef struct irq
109{
113 cpu_t* cpu; ///< The CPU with affinity for this IRQ, may be `NULL`.
118} irq_t;
119
120/**
121 * @brief IRQ domain structure.
122 * @struct irq_domain_t
123 *
124 * Represents a range of physical IRQs managed by a specific IRQ chip.
125 */
126typedef struct irq_domain
127{
130 void* data;
131 irq_phys_t start; ///< Inclusive
132 irq_phys_t end; ///< Exclusive
134
135/**
136 * @brief IRQ chip structure.
137 * @struct irq_chip_t
138 *
139 * Represents a implemented hardware IRQ controller, such as the IOAPIC.
140 */
141typedef struct irq_chip
142{
143 const char* name;
144 uint64_t (*enable)(irq_t* irq); ///< Enable the given IRQ, must be defined.
145 void (*disable)(irq_t* irq); ///< Disable the given IRQ, must be defined.
146 void (*ack)(irq_t* irq); ///< Send a acknowledge for the given IRQ.
147 void (*eoi)(irq_t* irq); ///< Send End-Of-Interrupt for the given IRQ.
148} irq_chip_t;
149
150/**
151 * @brief Initialize the IRQ subsystem.
152 */
153void irq_init(void);
154
155/**
156 * @brief Dispatch an IRQ.
157 *
158 * This function is called from `interrupt_handler()` when an IRQ is received. It will call all registered handlers
159 * for the IRQ and handle acknowledging and EOI as needed.
160 *
161 * Should not be called for exceptions.
162 *
163 * Will panic on failure.
164 *
165 * @param frame The interrupt frame of the IRQ.
166 */
168
169/**
170 * @brief Allocate a virtual IRQ mapped to the given physical IRQ.
171 *
172 * Will return an existing virtual IRQ if the physical IRQ is already allocated with the same flags and is shared. In
173 * this case its reference count will be incremented.
174 *
175 * Will succeed even if no IRQ chip is registered for the given physical IRQ, in such a case, the IRQ will be enabled
176 * only when a appropriate IRQ chip is registered.
177 *
178 * @note The IRQ will only be enabled if there are registered handlers for it, otherwise it will remain disabled until a
179 * handler is registered.
180 *
181 * @todo CPU load balancing?
182 *
183 * @param out Pointer to store the allocated virtual IRQ.
184 * @param phys The physical IRQ number.
185 * @param flags The IRQ flags.
186 * @param cpu The target CPU for the IRQ, or `NULL` for the current CPU.
187 * @return On success, `0`. On failure, `ERR` and `errno` is set to:
188 * - `EINVAL`: Invalid parameters.
189 * - `EBUSY`: The IRQ is already allocated with incompatible flags, or is exclusive.
190 * - `ENOSPC`: No more virtual IRQs can be allocated.
191 * - Other errors as returned by the IRQ chip's `enable` function.
192 */
194
195/**
196 * @brief Free a previously allocated virtual IRQ.
197 *
198 * The IRQ will be disabled and its handlers freed only when no more references to it exists.
199 *
200 * @param virt The virtual IRQ to free.
201 */
202void irq_virt_free(irq_virt_t virt);
203
204/**
205 * @brief Change the CPU responsible for an IRQ.
206 *
207 * @param virt The virtual IRQ to set the affinity for.
208 * @param cpu The target CPU for the IRQ.
209 * @return On success, `0`. On failure, `ERR` and `errno` is set to:
210 * - `EINVAL`: Invalid parameters.
211 * - `ENOENT`: The given virtual IRQ is not a external vector.
212 * - `ENODEV`: The IRQ has no associated IRQ chip.
213 * - Other errors as returned by the IRQ chip's `enable` functions.
214 */
216
217/**
218 * @brief Register an IRQ chip for a range of physical IRQs.
219 *
220 * The same chip can be registered multiple times for ranges that do not overlap.
221 *
222 * @param chip The IRQ chip to register.
223 * @param start The start of the physical IRQ range.
224 * @param end The end of the physical IRQ range.
225 * @param private Private data for the IRQ chip, will be found in `irq_t->domain->data`.
226 * @return On success, `0`. On failure, `ERR` and `errno` is set to:
227 * - `EINVAL`: Invalid parameters.
228 * - `EEXIST`: A chip with a domain overlapping the given range is already registered.
229 * - `ENOMEM`: Memory allocation failed.
230 * - Other errors as returned by the IRQ chip's `enable` function.
231 */
233
234/**
235 * @brief Unregister all instances of the given IRQ chip within the specified range.
236 *
237 * Will NOT free any IRQs or handlers associated with the chip(s), but it will disable them. If another chip is
238 * registered in the same range, the IRQs will be remapped to that chip.
239 *
240 * @param chip The IRQ chip to unregister, or `NULL` for no-op.
241 * @param start The start of the physical IRQ range.
242 * @param end The end of the physical IRQ range.
243 */
245
246/**
247 * @brief Get the number of registered IRQ chips.
248 *
249 * @return The number of registered IRQ chips.
250 */
252
253/**
254 * @brief Register an IRQ handler for a virtual IRQ.
255 *
256 * If this is the first handler for the IRQ, the IRQ will be enabled.
257 *
258 * @param virt The virtual IRQ to register the handler for.
259 * @param func The handler function to register.
260 * @param private The private data to pass to the handler function.
261 * @return On success, `0`. On failure, `ERR` and `errno` is set to:
262 * - `EINVAL`: Invalid parameters.
263 * - `ENOENT`: The given virtual IRQ is not a external vector.
264 * - `EEXIST`: The given handler is already registered for the given virtual IRQ.
265 * - `ENOMEM`: Memory allocation failed.
266 * - Other errors as returned by the IRQ chip's `enable` function.
267 */
269
270/**
271 * @brief Unregister an IRQ handler.
272 *
273 * If there are no more handlers registered for the IRQ, it will be disabled.
274 *
275 * @param func The handler function to unregister, or `NULL` for no-op.
276 * @param virt The virtual IRQ to unregister the handler from.
277 */
279
280/**
281 * @brief Invoke the given virtual IRQ.
282 *
283 * @warning Even tho its technically possible to use the `int` instruction with interrupts disabled, doing so will cause
284 * a panic in the interrupt handler as a sanity check. Therefore only use this macro with interrupts enabled.
285 *
286 * @param virt The virtual IRQ to invoke.
287 */
288#define IRQ_INVOKE(virt) ASM("int %0" : : "i"(virt));
289
290/** @} */
static void start()
Definition main.c:542
static fd_t data
Definition dwm.c:21
void irq_chip_unregister(irq_chip_t *chip, irq_phys_t start, irq_phys_t end)
Unregister all instances of the given IRQ chip within the specified range.
Definition irq.c:372
void irq_virt_free(irq_virt_t virt)
Free a previously allocated virtual IRQ.
Definition irq.c:252
void irq_handler_unregister(irq_func_t func, irq_virt_t virt)
Unregister an IRQ handler.
Definition irq.c:472
void irq_init(void)
Initialize the IRQ subsystem.
Definition irq.c:112
uint64_t irq_virt_set_affinity(irq_virt_t virt, cpu_t *cpu)
Change the CPU responsible for an IRQ.
Definition irq.c:289
uint32_t irq_phys_t
Physical IRQ numbers.
Definition irq.h:46
uint64_t irq_handler_register(irq_virt_t virt, irq_func_t func, void *data)
Register an IRQ handler for a virtual IRQ.
Definition irq.c:423
irq_flags_t
IRQ flags.
Definition irq.h:93
uint64_t irq_chip_register(irq_chip_t *chip, irq_phys_t start, irq_phys_t end, void *data)
Register an IRQ chip for a range of physical IRQs.
Definition irq.c:328
void irq_dispatch(interrupt_frame_t *frame)
Dispatch an IRQ.
Definition irq.c:128
uint64_t irq_chip_amount(void)
Get the number of registered IRQ chips.
Definition irq.c:417
void(* irq_func_t)(irq_func_data_t *data)
Callback function type for IRQs.
Definition irq.h:73
uint64_t irq_virt_alloc(irq_virt_t *out, irq_phys_t phys, irq_flags_t flags, cpu_t *cpu)
Allocate a virtual IRQ mapped to the given physical IRQ.
Definition irq.c:170
uint8_t irq_virt_t
Virtual IRQ numbers.
Definition irq.h:57
@ IRQ_TRIGGER_EDGE
If set, the IRQ is edge triggered. Otherwise, level triggered.
Definition irq.h:97
@ IRQ_POLARITY_HIGH
If set, the IRQ is active high.
Definition irq.h:94
@ IRQ_SHARED
If set, the IRQ is shared.
Definition irq.h:99
@ IRQ_TRIGGER_LEVEL
If set, the IRQ is level triggered.
Definition irq.h:96
@ IRQ_POLARITY_LOW
If set, the IRQ is active low. Otherwise, active high.
Definition irq.h:95
@ IRQ_EXCLUSIVE
If set, the IRQ is exclusive (not shared).
Definition irq.h:98
static const path_flag_t flags[]
Definition path.c:47
__UINT32_TYPE__ uint32_t
Definition stdint.h:15
__UINT64_TYPE__ uint64_t
Definition stdint.h:17
__UINT8_TYPE__ uint8_t
Definition stdint.h:11
CPU structure.
Definition cpu.h:84
Trap Frame Structure.
Definition interrupt.h:195
IRQ chip structure.
Definition irq.h:142
const char * name
Definition irq.h:143
IRQ domain structure.
Definition irq.h:127
irq_phys_t start
Inclusive.
Definition irq.h:131
irq_chip_t * chip
Definition irq.h:129
list_entry_t entry
Definition irq.h:128
void * data
Definition irq.h:130
irq_phys_t end
Exclusive.
Definition irq.h:132
Data passed to IRQ functions.
Definition irq.h:64
interrupt_frame_t * frame
Definition irq.h:65
void * data
Definition irq.h:67
irq_virt_t virt
Definition irq.h:66
Structure to hold an IRQ function and its data.
Definition irq.h:79
irq_func_t func
Definition irq.h:81
void * data
Definition irq.h:82
list_entry_t entry
Definition irq.h:80
irq_virt_t virt
Definition irq.h:83
IRQ structure.
Definition irq.h:109
irq_virt_t virt
Definition irq.h:111
irq_domain_t * domain
Definition irq.h:114
irq_phys_t phys
Definition irq.h:110
uint64_t refCount
Definition irq.h:115
list_t handlers
Definition irq.h:116
irq_flags_t flags
Definition irq.h:112
cpu_t * cpu
The CPU with affinity for this IRQ, may be NULL.
Definition irq.h:113
rwlock_t lock
Definition irq.h:117
A entry in a doubly linked list.
Definition list.h:37
A doubly linked list.
Definition list.h:46
Read-Write Ticket Lock structure.
Definition rwlock.h:66