kernel
Loading...
Searching...
No Matches
irql.c
Go to the documentation of this file.
1/*
2 * PROJECT: MatanelOS Kernel
3 * LICENSE: GPLv3
4 * PURPOSE: IRQL Implementation (Fixed with Dispatch Level scheduling toggle)
5 */
6
7#include "../../includes/me.h"
10#include <stdatomic.h>
11
12static inline bool interrupts_enabled(void) {
13 unsigned long flags;
14 __asm__ __volatile__("pushfq; popq %0" : "=r"(flags));
15 return (flags & (1UL << 9)) != 0; // IF is bit 9
16}
17
18static void update_apic_irqs(IRQL newLevel) {
19 uint8_t tpr = 0;
20
21 switch (newLevel) {
22 case HIGH_LEVEL:
23 case POWER_LEVEL:
24 tpr = TPR_HIGH; // 15
25 break;
26
27 case IPI_LEVEL:
28 tpr = TPR_IPI; // 14
29 break;
30
31 case CLOCK_LEVEL:
32 tpr = TPR_CLOCK; // 13
33 break;
34
35 case DISPATCH_LEVEL:
36 tpr = TPR_DPC; // 4 - Blocks DPC (0x40) and APC (0x30)
37 break;
38
39 case APC_LEVEL:
40 tpr = TPR_APC; // 3 - Blocks APC (0x30)
41 break;
42
43 case PASSIVE_LEVEL:
44 default:
45 tpr = TPR_PASSIVE; // 0
46 break;
47 }
48
49 __write_cr8((unsigned long)tpr);
50}
51
52static inline void toggle_scheduler(void) {
53 // schedulerEnabled should be true only at IRQL < DISPATCH_LEVEL
54 if (!InterlockedFetchU32(&MeGetCurrentProcessor()->SchedulerLock.locked)) {
56 }
57}
58
59// PUBLIC API
60
61void
63 IN IRQL NewIrql,
64 OUT PIRQL OldIrql
65)
66
67/*++
68
69 Routine description : This function raises the current IRQL of the CPU to the specified 'NewIrql', and updates IRQL rules along with it (scheduler, APIC masks...).
70
71 Arguments:
72
73 [IN] IRQL NewIrql: The new IRQL to set.
74 [OUT] PIRQL OldIrql: The old IRQL variable address.
75
76 Return Values:
77
78 None.
79
80--*/
81
82{
83 bool prev_if = interrupts_enabled();
84 __cli();
85
86 if (OldIrql) {
88 }
89
90 IRQL curr = MeGetCurrentIrql();
91 if (NewIrql < curr) {
93 }
94
96 toggle_scheduler();
97 update_apic_irqs(NewIrql);
98 if (prev_if) __sti();
99}
100
101void
103 IN IRQL NewIrql
104)
105
106/*++
107
108 Routine description :
109
110 This function lowers the current IRQL of the CPU to the specified 'NewIrql', and updates IRQL rules along with it (scheduler, APIC masks...).
111
112 N.B: The function checks if a software interrupt is pending AND that the interrupt IRQL pending is LOWER or EQUAL to current IRQL,
113 if so, it will generate the interrupt, even on interrupts disabled.
114
115 Arguments:
116
117 [IN] IRQL NewIrql: The new IRQL to set.
118
119 Return Values:
120
121 None.
122
123--*/
124
125{
126 bool prev_if = interrupts_enabled();
127 __cli();
128
129 IRQL curr = MeGetCurrentIrql();
130 if (NewIrql > curr) {
132 }
133
135
136 toggle_scheduler();
137 update_apic_irqs(NewIrql);
138
141
142 // First check for DPC Interrupts.
143
144 if (prev_if && cpu->DpcInterruptRequested && !cpu->DpcRoutineActive && NewIrql <= DISPATCH_LEVEL) {
146 }
147
148 // Now APC Interrupts.
149 if (prev_if && cpu->ApcInterruptRequested && !cpu->ApcRoutineActive && NewIrql <= APC_LEVEL) {
151 }
152
153 if (prev_if) __sti();
154}
155
156// This function should be used sparingly, only during initialization.
157void
159 IN IRQL NewIrql
160)
161
162/*++
163
164 Routine description : This function forcefully SETS (ignores bugcheck rules) the current IRQL of the CPU to the specified 'NewIrql', and updates IRQL rules along with it (scheduler, APIC masks...).
165
166 Arguments:
167
168 [IN] IRQL NewIrql: The new IRQL to set.
169
170 Return Values:
171
172 None.
173
174 Notes:
175
176 Use sparingly, this function ignores bugcheck IRQL rules.
177
178--*/
179
180{
181 bool prev_if = interrupts_enabled();
182 __cli();
183
185 toggle_scheduler();
186 update_apic_irqs(NewIrql);
187
190 if (prev_if && cpu->DpcInterruptRequested && !cpu->DpcRoutineActive && NewIrql <= DISPATCH_LEVEL) {
192 }
193
194 // Now APC Interrupts.
195 if (prev_if && cpu->ApcInterruptRequested && !cpu->ApcRoutineActive && NewIrql <= APC_LEVEL) {
197 }
198
199 if (prev_if) __sti();
200}
201
202bool
204 void
205)
206
207// Short Desc: Will disable interrupts, and returns if interrupts were enabled before.
208
209{
210 bool prev_if = interrupts_enabled();
211 __cli();
212 return prev_if;
213}
214
215void
217 IN bool EnabledBefore
218)
219
220// Short Desc: Will enable interrupts ONLY if EnabledBefore is true. (given from return value of MeDisableInterrupts)
221
222{
223 if (EnabledBefore) __sti();
224}
225
226bool
228 void
229)
230
231// Short Desc: Will return if interrupts are currently enabled on the processor.
232
233{
234 return interrupts_enabled();
235}
#define IN
Definition annotations.h:8
#define OUT
Definition annotations.h:9
void MhRequestSoftwareInterrupt(IN IRQL RequestIrql)
Definition apic.c:199
FORCEINLINE uint32_t InterlockedFetchU32(volatile uint32_t *target)
Definition atomic.h:220
NORETURN void MeBugCheck(IN enum _BUGCHECK_CODES BugCheckCode)
Definition bugcheck.c:220
@ HIGH_LEVEL
Definition core.h:22
@ APC_LEVEL
Definition core.h:16
@ DISPATCH_LEVEL
Definition core.h:17
@ IPI_LEVEL
Definition core.h:20
@ CLOCK_LEVEL
Definition core.h:19
@ PASSIVE_LEVEL
Definition core.h:15
@ POWER_LEVEL
Definition core.h:21
PROCESSOR * PPROCESSOR
Definition core.h:48
enum _IRQL IRQL
enum _IRQL * PIRQL
FORCEINLINE void __sti(void)
Definition intrin.h:59
FORCEINLINE void __write_cr8(unsigned long val)
Definition intrin.h:118
FORCEINLINE void __cli(void)
Definition intrin.h:43
bool MeDisableInterrupts(void)
Definition irql.c:203
void MeRaiseIrql(IN IRQL NewIrql, OUT PIRQL OldIrql)
Definition irql.c:62
bool MeAreInterruptsEnabled(void)
Definition irql.c:227
void MeEnableInterrupts(IN bool EnabledBefore)
Definition irql.c:216
void _MeSetIrql(IN IRQL NewIrql)
Definition irql.c:158
void MeLowerIrql(IN IRQL NewIrql)
Definition irql.c:102
@ IRQL_NOT_GREATER_OR_EQUAL
Definition me.h:98
@ IRQL_NOT_LESS_OR_EQUAL
Definition me.h:97
FORCEINLINE IRQL MeGetCurrentIrql(void)
Definition me.h:415
FORCEINLINE PPROCESSOR MeGetCurrentProcessor(void)
Definition me.h:369
#define TPR_HIGH
Definition mh.h:47
#define TPR_APC
Definition mh.h:43
uint32_t flags
Definition mh.h:2
#define TPR_IPI
Definition mh.h:46
#define TPR_CLOCK
Definition mh.h:45
#define TPR_DPC
Definition mh.h:44
#define TPR_PASSIVE
Definition mh.h:42
#define MmFullBarrier()
Definition mm.h:250
volatile bool schedulerEnabled
Definition me.h:284
enum _IRQL currentIrql
Definition me.h:283
volatile bool DpcRoutineActive
Definition me.h:313
volatile bool DpcInterruptRequested
Definition me.h:326
volatile bool ApcRoutineActive
Definition me.h:318
volatile bool ApcInterruptRequested
Definition me.h:327