PatchworkOS  c9fea19
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 */
63typedef struct
64{
68 void* private;
70
71/**
72 * @brief Callback function type for IRQs.
73 */
75
76/**
77 * @brief Structure to hold an IRQ function and its data.
78 */
79typedef struct
80{
83 void* private;
86
87/**
88 * @brief IRQ flags.
89 * @enum irq_flags_t
90 *
91 * Specifies the expected behaviour of an IRQ to a IRQ chip.
92 */
93typedef enum
94{
95 IRQ_POLARITY_HIGH = 0 << 0, ///< If set, the IRQ is active high.
96 IRQ_POLARITY_LOW = 1 << 0, ///< If set, the IRQ is active low. Otherwise, active high.
97 IRQ_TRIGGER_LEVEL = 0 << 1, ///< If set, the IRQ is level triggered.
98 IRQ_TRIGGER_EDGE = 1 << 1, ///< If set, the IRQ is edge triggered. Otherwise, level triggered.
99 IRQ_EXCLUSIVE = 0 << 2, ///< If set, the IRQ is exclusive (not shared).
100 IRQ_SHARED = 1 << 2, ///< If set, the IRQ is shared.
102
103/**
104 * @brief IRQ structure.
105 * @struct irq_t
106 *
107 * Represents a single virtual IRQ mapped to a physical IRQ.
108 */
109typedef struct irq
110{
114 cpu_t* cpu; ///< The CPU with affinity for this IRQ, may be `NULL`.
119} irq_t;
120
121/**
122 * @brief IRQ domain structure.
123 * @struct irq_domain_t
124 *
125 * Represents a range of physical IRQs managed by a specific IRQ chip.
126 */
127typedef struct irq_domain
128{
131 void* private;
132 irq_phys_t start; ///< Inclusive
133 irq_phys_t end; ///< Exclusive
135
136/**
137 * @brief IRQ chip structure.
138 * @struct irq_chip_t
139 *
140 * Represents a implemented hardware IRQ controller, such as the IOAPIC.
141 */
142typedef struct irq_chip
143{
144 const char* name;
145 uint64_t (*enable)(irq_t* irq); ///< Enable the given IRQ, must be defined.
146 void (*disable)(irq_t* irq); ///< Disable the given IRQ, must be defined.
147 void (*ack)(irq_t* irq); ///< Send a acknowledge for the given IRQ.
148 void (*eoi)(irq_t* irq); ///< Send End-Of-Interrupt for the given IRQ.
149} irq_chip_t;
150
151/**
152 * @brief Initialize the IRQ subsystem.
153 */
154void irq_init(void);
155
156/**
157 * @brief Dispatch an IRQ.
158 *
159 * This function is called from `interrupt_handler()` when an IRQ is received. It will call all registered handlers
160 * for the IRQ and handle acknowledging and EOI as needed.
161 *
162 * Should not be called for exceptions.
163 *
164 * Will panic on failure.
165 *
166 * @param frame The interrupt frame of the IRQ.
167 * @param self The CPU on which the IRQ was received.
168 */
169void irq_dispatch(interrupt_frame_t* frame, cpu_t* self);
170
171/**
172 * @brief Allocate a virtual IRQ mapped to the given physical IRQ.
173 *
174 * Will return an existing virtual IRQ if the physical IRQ is already allocated with the same flags and is shared. In
175 * this case its reference count will be incremented.
176 *
177 * Will succeed even if no IRQ chip is registered for the given physical IRQ, in such a case, the IRQ will be enabled
178 * only when a appropriate IRQ chip is registered.
179 *
180 * @note The IRQ will only be enabled if there are registered handlers for it, otherwise it will remain disabled until a
181 * handler is registered.
182 *
183 * @todo CPU load balancing?
184 *
185 * @param out Pointer to store the allocated virtual IRQ.
186 * @param phys The physical IRQ number.
187 * @param flags The IRQ flags.
188 * @param cpu The target CPU for the IRQ, or `NULL` for the current CPU.
189 * @return On success, `0`. On failure, `ERR` and `errno` is set to:
190 * - `EINVAL`: Invalid parameters.
191 * - `EBUSY`: The IRQ is already allocated with incompatible flags, or is exclusive.
192 * - `ENOSPC`: No more virtual IRQs can be allocated.
193 * - Other errors as returned by the IRQ chip's `enable` function.
194 */
196
197/**
198 * @brief Free a previously allocated virtual IRQ.
199 *
200 * The IRQ will be disabled and its handlers freed only when no more references to it exists.
201 *
202 * @param virt The virtual IRQ to free.
203 */
204void irq_virt_free(irq_virt_t virt);
205
206/**
207 * @brief Change the CPU responsible for an IRQ.
208 *
209 * @param virt The virtual IRQ to set the affinity for.
210 * @param cpu The target CPU for the IRQ.
211 * @return On success, `0`. On failure, `ERR` and `errno` is set to:
212 * - `EINVAL`: Invalid parameters.
213 * - `ENOENT`: The given virtual IRQ is not a external vector.
214 * - `ENODEV`: The IRQ has no associated IRQ chip.
215 * - Other errors as returned by the IRQ chip's `enable` functions.
216 */
218
219/**
220 * @brief Register an IRQ chip for a range of physical IRQs.
221 *
222 * The same chip can be registered multiple times for ranges that do not overlap.
223 *
224 * @param chip The IRQ chip to register.
225 * @param start The start of the physical IRQ range.
226 * @param end The end of the physical IRQ range.
227 * @param private Private data for the IRQ chip, will be found in `irq_t->domain->private`.
228 * @return On success, `0`. On failure, `ERR` and `errno` is set to:
229 * - `EINVAL`: Invalid parameters.
230 * - `EEXIST`: A chip with a domain overlapping the given range is already registered.
231 * - `ENOMEM`: Memory allocation failed.
232 * - Other errors as returned by the IRQ chip's `enable` function.
233 */
235
236/**
237 * @brief Unregister all instances of the given IRQ chip within the specified range.
238 *
239 * Will NOT free any IRQs or handlers associated with the chip(s), but it will disable them. If another chip is
240 * registered in the same range, the IRQs will be remapped to that chip.
241 *
242 * @param chip The IRQ chip to unregister, or `NULL` for no-op.
243 * @param start The start of the physical IRQ range.
244 * @param end The end of the physical IRQ range.
245 */
247
248/**
249 * @brief Get the number of registered IRQ chips.
250 *
251 * @return The number of registered IRQ chips.
252 */
254
255/**
256 * @brief Register an IRQ handler for a virtual IRQ.
257 *
258 * If this is the first handler for the IRQ, the IRQ will be enabled.
259 *
260 * @param virt The virtual IRQ to register the handler for.
261 * @param func The handler function to register.
262 * @param private The private data to pass to the handler function.
263 * @return On success, `0`. On failure, `ERR` and `errno` is set to:
264 * - `EINVAL`: Invalid parameters.
265 * - `ENOENT`: The given virtual IRQ is not a external vector.
266 * - `EEXIST`: The given handler is already registered for the given virtual IRQ.
267 * - `ENOMEM`: Memory allocation failed.
268 * - Other errors as returned by the IRQ chip's `enable` function.
269 */
270uint64_t irq_handler_register(irq_virt_t virt, irq_func_t func, void* private);
271
272/**
273 * @brief Unregister an IRQ handler.
274 *
275 * If there are no more handlers registered for the IRQ, it will be disabled.
276 *
277 * @param func The handler function to unregister, or `NULL` for no-op.
278 * @param virt The virtual IRQ to unregister the handler from.
279 */
281
282/**
283 * @brief Invoke the given virtual IRQ.
284 *
285 * @warning Even tho its technically possible to use the `int` instruction with interrupts disabled, doing so will cause
286 * a panic in the interrupt handler as a sanity check. Therefore only use this macro with interrupts enabled.
287 *
288 * @param virt The virtual IRQ to invoke.
289 */
290#define IRQ_INVOKE(virt) asm volatile("int %0" : : "i"(virt));
291
292/** @} */
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:374
void irq_virt_free(irq_virt_t virt)
Free a previously allocated virtual IRQ.
Definition irq.c:253
void irq_handler_unregister(irq_func_t func, irq_virt_t virt)
Unregister an IRQ handler.
Definition irq.c:474
void irq_init(void)
Initialize the IRQ subsystem.
Definition irq.c:111
uint64_t irq_virt_set_affinity(irq_virt_t virt, cpu_t *cpu)
Change the CPU responsible for an IRQ.
Definition irq.c:291
uint32_t irq_phys_t
Physical IRQ numbers.
Definition irq.h:46
irq_flags_t
IRQ flags.
Definition irq.h:94
uint64_t irq_handler_register(irq_virt_t virt, irq_func_t func, void *private)
Register an IRQ handler for a virtual IRQ.
Definition irq.c:425
uint64_t irq_chip_amount(void)
Get the number of registered IRQ chips.
Definition irq.c:419
void(* irq_func_t)(irq_func_data_t *data)
Callback function type for IRQs.
Definition irq.h:74
void irq_dispatch(interrupt_frame_t *frame, cpu_t *self)
Dispatch an IRQ.
Definition irq.c:127
uint64_t irq_chip_register(irq_chip_t *chip, irq_phys_t start, irq_phys_t end, void *private)
Register an IRQ chip for a range of physical IRQs.
Definition irq.c:330
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:171
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:98
@ IRQ_POLARITY_HIGH
If set, the IRQ is active high.
Definition irq.h:95
@ IRQ_SHARED
If set, the IRQ is shared.
Definition irq.h:100
@ IRQ_TRIGGER_LEVEL
If set, the IRQ is level triggered.
Definition irq.h:97
@ IRQ_POLARITY_LOW
If set, the IRQ is active low. Otherwise, active high.
Definition irq.h:96
@ IRQ_EXCLUSIVE
If set, the IRQ is exclusive (not shared).
Definition irq.h:99
static const path_flag_t flags[]
Definition path.c:42
static void start()
Definition main.c:542
__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:122
Trap Frame Structure.
Definition interrupt.h:146
IRQ chip structure.
Definition irq.h:143
const char * name
Definition irq.h:144
IRQ domain structure.
Definition irq.h:128
irq_phys_t start
Inclusive.
Definition irq.h:132
irq_chip_t * chip
Definition irq.h:130
list_entry_t entry
Definition irq.h:129
irq_phys_t end
Exclusive.
Definition irq.h:133
Data passed to IRQ functions.
Definition irq.h:64
interrupt_frame_t * frame
Definition irq.h:65
irq_virt_t virt
Definition irq.h:67
cpu_t * self
Definition irq.h:66
Structure to hold an IRQ function and its data.
Definition irq.h:80
irq_func_t func
Definition irq.h:82
list_entry_t entry
Definition irq.h:81
irq_virt_t virt
Definition irq.h:84
IRQ structure.
Definition irq.h:110
irq_virt_t virt
Definition irq.h:112
irq_domain_t * domain
Definition irq.h:115
irq_phys_t phys
Definition irq.h:111
uint64_t refCount
Definition irq.h:116
list_t handlers
Definition irq.h:117
irq_flags_t flags
Definition irq.h:113
cpu_t * cpu
The CPU with affinity for this IRQ, may be NULL.
Definition irq.h:114
rwlock_t lock
Definition irq.h:118
A entry in a doubly linked list.
Definition list.h:36
A doubly linked list.
Definition list.h:49
Read-Write Ticket Lock structure.
Definition rwlock.h:61