My Project
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 case IPI_LEVEL:
25 tpr = 15; // block everything
26 break;
27
28 case CLOCK_LEVEL:
29 case PROFILE_LEVEL:
30 tpr = TPR_PROFILE; // 10
31 break;
32
33 case DISPATCH_LEVEL:
34 tpr = TPR_DPC; // 6
35 break;
36 case APC_LEVEL:
37 tpr = TPR_APC; // 3
38 break;
39
40 case PASSIVE_LEVEL:
41 default:
42 tpr = TPR_PASSIVE; // allow everything.
43 break;
44 }
45
46 __write_cr8((unsigned long)tpr);
47}
48
49static inline void toggle_scheduler(void) {
50 // schedulerEnabled should be true only at IRQL < DISPATCH_LEVEL
52}
53
54// PUBLIC API
55
56void
58 IN IRQL NewIrql,
59 OUT PIRQL OldIrql
60)
61
62/*++
63
64 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...).
65
66 Arguments:
67
68 [IN] IRQL NewIrql: The new IRQL to set.
69 [OUT] PIRQL OldIrql: The old IRQL variable address.
70
71 Return Values:
72
73 None.
74
75--*/
76
77{
78 bool prev_if = interrupts_enabled();
79 __cli();
80
81 if (OldIrql) {
83 }
84
85 IRQL curr = MeGetCurrentIrql();
86 if (NewIrql < curr) {
88 }
89
91 toggle_scheduler();
92 update_apic_irqs(NewIrql);
93 if (prev_if) __sti();
94}
95
96void
98 IN IRQL NewIrql
99)
100
101/*++
102
103 Routine description :
104
105 This function lowers the current IRQL of the CPU to the specified 'NewIrql', and updates IRQL rules along with it (scheduler, APIC masks...).
106
107 N.B: The function checks if a software interrupt is pending AND that the interrupt IRQL pending is LOWER or EQUAL to current IRQL,
108 if so, it will generate the interrupt, even on interrupts disabled.
109
110 Arguments:
111
112 [IN] IRQL NewIrql: The new IRQL to set.
113
114 Return Values:
115
116 None.
117
118--*/
119
120{
121 bool prev_if = interrupts_enabled();
122 __cli();
123
124 IRQL curr = MeGetCurrentIrql();
125 if (NewIrql > curr) {
127 }
128
130
131 toggle_scheduler();
132 update_apic_irqs(NewIrql);
133
136
137 // First check for DPC Interrupts.
138
139 if (prev_if && cpu->DpcInterruptRequested && !cpu->DpcRoutineActive && NewIrql <= DISPATCH_LEVEL) {
141 }
142
143 // Now APC Interrupts.
144 if (prev_if && cpu->ApcInterruptRequested && !cpu->ApcRoutineActive && NewIrql <= APC_LEVEL) {
146 }
147
148 if (prev_if) __sti();
149}
150
151// This function should be used sparingly, only during initialization.
152void
154 IN IRQL NewIrql
155)
156
157/*++
158
159 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...).
160
161 Arguments:
162
163 [IN] IRQL NewIrql: The new IRQL to set.
164
165 Return Values:
166
167 None.
168
169 Notes:
170
171 Use sparingly, this function ignores bugcheck IRQL rules.
172
173--*/
174
175{
176 bool prev_if = interrupts_enabled();
177 __cli();
178
180 toggle_scheduler();
181 update_apic_irqs(NewIrql);
182 if (prev_if) __sti();
183}
184
185bool
187 void
188)
189
190// Short Desc: Will disable interrupts, and returns if interrupts were enabled before.
191
192{
193 bool prev_if = interrupts_enabled();
194 __cli();
195 return prev_if;
196}
197
198void
200 IN bool EnabledBefore
201)
202
203// Short Desc: Will enable interrupts ONLY if EnabledBefore is true. (given from return value of MeDisableInterrupts)
204
205{
206 if (EnabledBefore) __sti();
207}
208
209bool
211 void
212)
213
214// Short Desc: Will return if interrupts are currently enabled on the processor.
215
216{
217 return interrupts_enabled();
218}
#define IN
Definition annotations.h:7
#define OUT
Definition annotations.h:8
void MhRequestSoftwareInterrupt(IN IRQL RequestIrql)
Definition apic.c:199
NORETURN void MeBugCheck(IN enum _BUGCHECK_CODES BugCheckCode)
Definition bugcheck.c:214
@ HIGH_LEVEL
Definition core.h:20
@ APC_LEVEL
Definition core.h:14
@ DISPATCH_LEVEL
Definition core.h:15
@ PROFILE_LEVEL
Definition core.h:16
@ IPI_LEVEL
Definition core.h:18
@ CLOCK_LEVEL
Definition core.h:17
@ PASSIVE_LEVEL
Definition core.h:13
@ POWER_LEVEL
Definition core.h:19
PROCESSOR * PPROCESSOR
Definition core.h:46
enum _IRQL IRQL
enum _IRQL * PIRQL
FORCEINLINE void __sti(void)
Definition intrin.h:44
FORCEINLINE void __write_cr8(unsigned long val)
Definition intrin.h:103
FORCEINLINE void __cli(void)
Definition intrin.h:38
bool MeDisableInterrupts(void)
Definition irql.c:186
void MeRaiseIrql(IN IRQL NewIrql, OUT PIRQL OldIrql)
Definition irql.c:57
bool MeAreInterruptsEnabled(void)
Definition irql.c:210
void MeEnableInterrupts(IN bool EnabledBefore)
Definition irql.c:199
void _MeSetIrql(IN IRQL NewIrql)
Definition irql.c:153
void MeLowerIrql(IN IRQL NewIrql)
Definition irql.c:97
@ 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:402
FORCEINLINE PPROCESSOR MeGetCurrentProcessor(void)
Definition me.h:356
#define TPR_APC
Definition mh.h:38
uint32_t flags
Definition mh.h:2
#define TPR_PROFILE
Definition mh.h:40
#define TPR_DPC
Definition mh.h:39
#define TPR_PASSIVE
Definition mh.h:37
#define MmFullBarrier()
Definition mm.h:226
volatile bool schedulerEnabled
Definition me.h:277
enum _IRQL currentIrql
Definition me.h:276
volatile bool DpcRoutineActive
Definition me.h:305
volatile bool DpcInterruptRequested
Definition me.h:318
volatile bool ApcRoutineActive
Definition me.h:310
volatile bool ApcInterruptRequested
Definition me.h:319