1/* @title: IRQs */
2#pragma once
3#include <console/crash.h>
4#include <kassert.h>
5#include <smp/core.h>
6#include <stdbool.h>
7#include <stdint.h>
8#include <structures/cpu_mask.h>
9#include <structures/list.h>
10#include <types/types.h>
11
12#define IRQ_DIV_BY_Z 0x0
13#define IRQ_DEBUG 0x1
14#define IRQ_NMI 0x2
15#define IRQ_BREAKPOINT 0x3
16#define IRQ_DBF 0x8
17#define IRQ_SSF 0xC
18#define IRQ_GPF 0xD
19#define IRQ_PAGE_FAULT 0xE
20#define IRQ_TIMER 0x20
21#define IRQ_SCHEDULER IRQ_TIMER
22#define IRQ_TLB_SHOOTDOWN 0x22
23#define IRQ_NOP 0x24
24#define IRQ_DPC 0x25
25#define IRQ_EXCEPTION_COUNT 32
26
27struct irq_context;
28struct irq_desc;
29
30enum irq_result {
31 IRQ_NONE = 0,
32 IRQ_HANDLED = 1,
33};
34
35typedef enum irq_result (*irq_handler_t)(void *ctx, uint8_t vector,
36 struct irq_context *ictx);
37
38enum irq_flags {
39 IRQ_FLAG_SHARED = 1, /* IRQ is shared between things */
40 IRQ_FLAG_LEVEL_TRIGGERED = 1 << 1,
41 IRQ_FLAG_EDGE_TRIGGERED = 1 << 2,
42 IRQ_FLAG_NONE = 0,
43};
44
45struct irq_action {
46 irq_handler_t handler;
47 void *data;
48 struct list_head list;
49};
50
51struct irq_chip {
52 const char *name;
53
54 void (*mask)(struct irq_desc *);
55 void (*unmask)(struct irq_desc *);
56 void (*eoi)(struct irq_desc *);
57
58 void (*set_affinity)(struct irq_desc *, struct cpu_mask *);
59 int (*set_rate_limit)(struct irq_desc *, time_us_t interval);
60};
61
62struct irq_desc {
63 uint8_t vector;
64 enum irq_flags flags;
65
66 const char *name;
67
68 struct irq_chip *chip;
69 void *chip_data;
70
71 struct list_head actions;
72
73 struct cpu_mask affinity;
74 struct cpu_mask masked_cpus;
75
76 bool present; /* Have we set handlers? */
77 bool allocated; /* Has this been allocated? */
78 bool enabled;
79};
80
81struct irq_context {
82 uint64_t rax;
83 uint64_t rbx;
84 uint64_t rcx;
85 uint64_t rdx;
86 uint64_t rbp;
87 uint64_t rdi;
88 uint64_t rsi;
89 uint64_t r8;
90 uint64_t r9;
91 uint64_t r10;
92 uint64_t r11;
93 uint64_t r12;
94 uint64_t r13;
95 uint64_t r14;
96 uint64_t r15;
97 uint64_t error_code;
98 uint64_t rip;
99 uint64_t cs;
100 uint64_t rflags;
101 uint64_t rsp;
102 uint64_t ss;
103};
104
105static inline void irq_context_to_crash_regs(const struct irq_context *ictx,
106 struct crash_regs *out) {
107 if (!ictx || !out)
108 return;
109 out->rip = ictx->rip;
110 out->rflags = ictx->rflags;
111 __asm__ volatile("mov %%cr2, %0" : "=r"(out->cr2));
112 __asm__ volatile("mov %%cr3, %0" : "=r"(out->cr3));
113 out->rax = ictx->rax;
114 out->rbx = ictx->rbx;
115 out->rcx = ictx->rcx;
116 out->rdx = ictx->rdx;
117 out->rbp = ictx->rbp;
118 out->rdi = ictx->rdi;
119 out->rsi = ictx->rsi;
120 out->r8 = ictx->r8;
121 out->r9 = ictx->r9;
122 out->r10 = ictx->r10;
123 out->r11 = ictx->r11;
124 out->r12 = ictx->r12;
125 out->r13 = ictx->r13;
126 out->r14 = ictx->r14;
127 out->r15 = ictx->r15;
128 out->rsp = ictx->rsp;
129}
130
131void irq_register(char *name, uint8_t vector, irq_handler_t handler, void *ctx,
132 enum irq_flags flags);
133void irq_register_full(struct irq_desc *d);
134void irq_set_chip(uint8_t vector, struct irq_chip *chip, void *data);
135
136/* We DO NOT set _IRQ here because _NONE is used as
137 * this set of functions will set the flags _NONE checks */
138static inline uint32_t irq_mark_self_in_interrupt(bool new) {
139 uint32_t old = smp_ctx_irq_count(smp_ctx: smp_ctx(c: TOPC_NONE));
140 if (new)
141 smp_ctx_add(c: TOPC_NONE, SMP_CTX_IRQ_ONE, SMP_CTX_IRQ_MASK);
142 else
143 smp_ctx_sub(c: TOPC_NONE, SMP_CTX_IRQ_ONE, SMP_CTX_IRQ_MASK);
144 return old;
145}
146
147static inline uint32_t irq_mark_self_in_nmi(bool new) {
148 uint32_t old = smp_ctx_nmi_count(smp_ctx: smp_ctx(c: TOPC_NONE));
149 if (new)
150 smp_ctx_add(c: TOPC_NONE, SMP_CTX_NMI_ONE, SMP_CTX_NMI_MASK);
151 else
152 smp_ctx_sub(c: TOPC_NONE, SMP_CTX_NMI_ONE, SMP_CTX_NMI_MASK);
153 return old;
154}
155
156/* These are called from the verification logic,
157 * they are simple reads */
158static inline bool irq_in_nmi(void) {
159 return (smp_ctx(c: TOPC_NONE) & SMP_CTX_NMI_MASK) != 0;
160}
161
162static inline bool irq_in_interrupt(void) {
163 return (smp_ctx(c: TOPC_NONE) & SMP_CTX_IRQ_MASK) != 0;
164}
165
166static inline bool irq_not_in_interrupt(void) {
167 return (smp_ctx(c: TOPC_NONE) & SMP_CTX_IN_INTERRUPT_MASK) == 0;
168}
169
170static inline bool irq_vector_is_exception(uint8_t vector) {
171 return vector < IRQ_EXCEPTION_COUNT;
172}
173
174void ipi_send(uint32_t apic_id, uint8_t vector);
175void nmi_send(uint32_t apic_id);
176
177void irq_set_alloc(int32_t entry, bool used);
178int32_t irq_alloc_entry(void);
179void irq_free_entry(int32_t entry);
180bool irq_is_installed(int32_t entry);
181void irq_free_entry(int32_t entry);
182void irq_disable(irq_t irq);
183void irq_enable(irq_t irq);
184