My Project
Loading...
Searching...
No Matches
dpc.c
Go to the documentation of this file.
1/*
2 * PROJECT: MatanelOS Kernel
3 * LICENSE: GPLv3
4 * PURPOSE: DPC Implementation.
5 */
6
7#include "../../includes/me.h"
8#include "../../includes/mg.h"
9#include "../../includes/ps.h"
10#include "../../includes/mh.h"
11#include "../../assert.h"
12#include "../../includes/ob.h"
13
14//Statically made DPC Routines.
15
16extern volatile void* ObpReaperList;
17
18void ReapOb(DPC* dpc, void* DeferredContext, void* SystemArgument1, void* SystemArgument2) {
19 /*
20 DeferredContext - Ignored
21 SystemArgument1 - Ignored
22 SystemArgument2 - Ignored
23 */
24
25 POBJECT_HEADER head, cur;
26
27 UNREFERENCED_PARAMETER(DeferredContext);
28 UNREFERENCED_PARAMETER(SystemArgument1);
29 UNREFERENCED_PARAMETER(SystemArgument2);
30 UNREFERENCED_PARAMETER(dpc); // Switched to global, freeing this would cause in MEMORY_CORRUPT_HEADER.
31
32 // Atomically take the list
34
35 // Walk the captured chain and free each header
36 while (head) {
37 cur = head;
38 head = (POBJECT_HEADER)head->NextToFree;
39 MmFreePool(cur); // Free the header (frees object as well, header + sizeof(header) = object)
40 }
41
42}
43
44//End
45
46bool
48 IN PDPC Dpc,
49 IN void* SystemArgument1,
50 IN void* SystemArgument2
51)
52
53/*++
54
55 Routine description:
56
57 This function inserts the DPC object into the DPC queue.
58 If the DPC object is already in the queue, nothing is performed.
59 Else, the DPC Object is inserted in the queue, and a software interrupt is generated based on the DPC priority & current depth.
60
61 For setting a certain CPU to run this DPC, use the MeSetTargetProcessorDpc function before calling this one.
62
63 Arguments:
64
65 [IN] PDPC Dpc - The DPC Object to queue.
66 [IN] void* SystemArgument1 - Optional Argument for the DPC to receive.
67 [IN] void* SystemArgument2 - Optional Argument for the DPC to receive.
68
69 Return Values:
70
71 If the DPC objeect is already in the queue, false is returned.
72 Otherwise, true is returned.
73
74--*/
75
76{
77 // Declarations
78 PDPC_DATA DpcData;
79 PPROCESSOR Cpu;
80 bool Inserted = false;
81 IRQL OldIrql;
82
83 if (!Dpc->DeferredRoutine) {
84#ifdef DEBUG
86 (void*)(uintptr_t)RETADDR(0),
87 (void*)Dpc,
88 NULL,
89 NULL
90 );
91#else
93 (void*)Dpc,
94 NULL,
95 NULL,
96 NULL
97 );
98#endif
99 }
100
101 // Raise IRQL to HIGH_LEVEL to prevent all interrupts while we touch the processor DPC queue. (prevent corruption)
102 MeRaiseIrql(HIGH_LEVEL, &OldIrql);
103
104 if (Dpc->CpuNumber < MeGetActiveProcessorCount()) {
105 Cpu = MeGetProcessorBlock(Dpc->CpuNumber);
106 }
107 else {
108 Cpu = MeGetCurrentProcessor();
109 }
110
111 DpcData = &Cpu->DpcData;
112
113 // Acquire the DpcData lock for the current processor.
115
116 // Atomic operation to check if this DPC is already queued.
117 if (InterlockedCompareExchangePointer(&Dpc->DpcData, DpcData, NULL) == NULL) {
118
119 // Success: It was not queued.
120 DpcData->DpcQueueDepth += 1;
121 DpcData->DpcCount += 1;
122 Dpc->SystemArgument1 = SystemArgument1;
123 Dpc->SystemArgument2 = SystemArgument2;
124
125 // Insert Head (High Priority) or Tail (Normal)
126 if (Dpc->priority == HIGH_PRIORITY) {
127 InsertHeadList(&DpcData->DpcListHead, &Dpc->DpcListEntry);
128 }
129 else {
130 InsertTailList(&DpcData->DpcListHead, &Dpc->DpcListEntry);
131 }
132
133 Inserted = true;
134 // Increment request rate
135 Cpu->DpcRequestRate++;
136
137 // Check if we need to request an interurpt
138 // We only request if a DPC isnt currently running.
139 // And we haven't already requested an interrupt for a DPC.
140 if ((Cpu->DpcRoutineActive == false) &&
141 (Cpu->DpcInterruptRequested == false)) {
142
143 // If the DPC priority is higher than lowest, or we are to deep in the queue depth, retire DPCs immediately.
144 if ((Dpc->priority != LOW_PRIORITY) ||
145 (DpcData->DpcQueueDepth >= Cpu->MaximumDpcQueueDepth)) {
146
147 // Always mark that an interrupt is needed eventually
148 Cpu->DpcInterruptRequested = true;
149
150 // Cannot request an interrupt on DISPATCH_LEVEL already.
152 // Request an interrupt from HAL.
154 }
155 }
156 }
157 }
158
159 // Release Lock and Restore IRQL
161 MeLowerIrql(OldIrql);
162
163 return Inserted;
164}
165
166bool
168 IN PDPC Dpc
169)
170
171/*++
172
173 Routine description:
174
175 This function removes the Dpc object from the DPC Queue.
176 If the DPC object is NOT in the DPC queue, nothing is performed.
177 Otherwise, the DPC object is removed from the queue, and its inserted state (DpcData), is NULL (false).
178
179 Arguments:
180
181 [IN] PDPC Dpc - The DPC Object to remove from queue.
182
183 Return Values:
184
185 If the DPC object is not in the queue, false is returned.
186 Otherwise, true is returned.
187
188--*/
189
190{
191 PDPC_DATA DpcData;
192 bool Enable;
193 bool Removed = false;
194
195 // Disable interrupts manually since we aren't raising IRQL yet
196 Enable = MeDisableInterrupts();
197
198 DpcData = (PDPC_DATA)Dpc->DpcData;
199
200 if (DpcData != NULL) {
201 // Acquire Lock
203
204 // Check if still queued
205 if (DpcData == Dpc->DpcData) {
206 DpcData->DpcQueueDepth -= 1;
207 RemoveEntryList(&Dpc->DpcListEntry);
208 Dpc->DpcData = NULL; // Mark as not queued
209 Removed = true;
210 }
211
212 // Release Lock
214 }
215
216 // Restore Interrupts
217 MeEnableInterrupts(Enable);
218 return Removed;
219}
220
221void
223 void
224)
225
226/*++
227
228 Routine description:
229
230 This function retires the DPC list for the current processor, and also processes timer expiration (first).
231
232 Arguments:
233
234 None.
235
236 Return Values:
237
238 None.
239
240 Notes:
241
242 This function is entered with interrupts disabled ( __cli() ), and exits with interrupts disabled.
243
244--*/
245
246{
247#ifdef DEBUG
248 gop_printf(COLOR_WHITE, "Retiring DPCs!\n");
249#endif
250 // Few assertions.
252 assert(MeAreInterruptsEnabled() == false);
253
254 // Declarations
255 PDPC Dpc;
256 PDPC_DATA DpcData;
258 PDEFERRED_ROUTINE DeferredRoutine;
259 void* DeferredContext;
260 void* SystemArgument1;
261 void* SystemArgument2;
262 uintptr_t TimerHand;
264
265 DpcData = &Cpu->DpcData;
266
267 // Outer Loop: Process until queue is empty
268 do {
269 Cpu->DpcRoutineActive = true;
270
271 // Process Timer Expiration -- Unused for now, until we introduce MsWaitForSingleObject (will replace MsWaitForEvent n stuff), and also MeDelayExecutionThread
272 /*
273 if (Cpu->TimerRequest != 0) {
274 TimerHand = Cpu->TimerHand;
275 Cpu->TimerRequest = 0;
276
277 __sti(); // Enable interrupts for timer processing
278 MeTimerExpiration(TimerHand);
279 __cli(); // Disable again
280 }
281 */
282 UNREFERENCED_PARAMETER(TimerHand);
283
284 // Process DPC Queue
285 if (DpcData->DpcQueueDepth != 0) {
286
287 // Inner Loop: Pop one, run one
288 do {
289 // Lock
291
292 Entry = DpcData->DpcListHead.Flink;
293
294 if (Entry != &DpcData->DpcListHead) {
295 // Remove from List
296 RemoveEntryList(Entry);
297 Dpc = CONTAINING_RECORD(Entry, DPC, DpcListEntry);
298 // Capture Context
299 DeferredRoutine = Dpc->DeferredRoutine;
300 DeferredContext = Dpc->DeferredContext;
301 SystemArgument1 = Dpc->SystemArgument1;
302 SystemArgument2 = Dpc->SystemArgument2;
303
304 // Changes must be set before others can modify.
306
307 // Clear DpcData so it can be re-queued inside its own routine
308 Dpc->DpcData = NULL;
309 DpcData->DpcQueueDepth -= 1;
310
311 // Release Lock
313
314 // Enable Interrupts for execution
315 __sti();
316
317 // Execute
318 Cpu->CurrentDeferredRoutine = Dpc;
319#ifdef DEBUG
320 gop_printf(COLOR_WHITE, "I'm about to execute DPC %p | Routine: %p | SysArg1: %p | SysArg2: %p | Priority: %d\n", Dpc, Dpc->DeferredRoutine, Dpc->SystemArgument1, Dpc->SystemArgument2, Dpc->priority);
321#endif
322 DeferredRoutine(Dpc, DeferredContext, SystemArgument1, SystemArgument2);
323 Cpu->CurrentDeferredRoutine = NULL;
324
325 // Assertion, incase the DPC changed the IRQL level.
327
328 // Disable Interrupts for next loop iteration
329 __cli();
330
331 }
332 else {
333 // List was empty
335 }
336
337 } while (DpcData->DpcQueueDepth != 0);
338 }
339
340 Cpu->DpcRoutineActive = false;
341 Cpu->DpcInterruptRequested = false;
342
343 } while (DpcData->DpcQueueDepth != 0);
344
345 // Return statement, assert that interrupts are disabled.
346 assert(MeAreInterruptsEnabled() == false, "Interrupts must not enabled at DPC Retirement exit");
347}
348
349void
351 IN PDPC Dpc,
352 IN uint32_t CpuNumber
353)
354
355/*++
356
357 Routine description:
358
359 This function ensures that the DPC executes only on the CPU
360 corresponding to the supplied LAPIC ID.
361
362 Arguments:
363
364 [IN] PDPC DpcAllocated - Pointer to DPC allocated in resident memory (e.g, pool alloc)
365 [IN] uint32_t CpuNumber - LAPIC ID Of the certain CPU Core to be ran on.
366
367 Return Values:
368
369 None.
370
371 Notes:
372
373 This function call must be made before MeInsertQueueDpc.
374
375--*/
376
377{
378 assert(CpuNumber < MeGetActiveProcessorCount());
379
380 Dpc->CpuNumber = CpuNumber;
381}
382
383void
385 IN PDPC DpcAllocated,
386 IN PDEFERRED_ROUTINE DeferredRoutine,
387 IN void* DeferredContext,
388 IN DPC_PRIORITY DeferredPriority
389)
390
391/*++
392
393 Routine description:
394
395 This function initializes a DPC to be used for queueing.
396
397 Arguments:
398
399 [IN] PDPC DpcAllocated - Pointer to DPC allocated in resident memory (e.g, pool alloc)
400 [IN] PDEFERRED_ROUTINE DeferredRoutine - Pointer to deferred routine for the DPC to execute.
401 [IN] void* DeferredContext - Opaque pointer to deferred context, passed to the DeferredRoutine function as a parameter.
402 [IN] DPC_PRIORITY DeferredPriority - Supplies the priority of the DPC. A DPC of LOW_PRIORITY will not be executed at queue time unless the depth is full, or a software interrupt occurs.
403
404 Return Values:
405
406 None.
407
408--*/
409
410{
411 // Initialize standard DPC headers.
412 DpcAllocated->priority = DeferredPriority;
413
414 // Initialize address of routine and context param.
415 DpcAllocated->DeferredRoutine = DeferredRoutine;
416 DpcAllocated->DeferredContext = DeferredContext;
417 DpcAllocated->DpcData = NULL;
418
419 // Set to current CPU. (the driver can modify his CPU)
420 DpcAllocated->CpuNumber = DPC_TARGET_CURRENT;
421
422 // Initialize list head for DPC.
423 InitializeListHead(&DpcAllocated->DpcListEntry);
424}
#define IN
Definition annotations.h:7
void MhRequestSoftwareInterrupt(IN IRQL RequestIrql)
Definition apic.c:199
#define assert(...)
Definition assert.h:57
FORCEINLINE void * InterlockedCompareExchangePointer(volatile void *volatile *target, void *value, void *comparand)
Definition atomic.h:171
FORCEINLINE void * InterlockedExchangePointer(volatile void *volatile *target, void *value)
Definition atomic.h:170
NORETURN void MeBugCheckEx(IN enum _BUGCHECK_CODES BugCheckCode, IN void *BugCheckParameter1, IN void *BugCheckParameter2, IN void *BugCheckParameter3, IN void *BugCheckParameter4)
Definition bugcheck.c:305
struct _DOUBLY_LINKED_LIST * PDOUBLY_LINKED_LIST
@ HIGH_LEVEL
Definition core.h:20
@ DISPATCH_LEVEL
Definition core.h:15
PROCESSOR * PPROCESSOR
Definition core.h:46
enum _IRQL IRQL
void MeRetireDPCs(void)
Definition dpc.c:222
bool MeRemoveQueueDpc(IN PDPC Dpc)
Definition dpc.c:167
bool MeInsertQueueDpc(IN PDPC Dpc, IN void *SystemArgument1, IN void *SystemArgument2)
Definition dpc.c:47
volatile void * ObpReaperList
Definition ob.c:28
void MeInitializeDpc(IN PDPC DpcAllocated, IN PDEFERRED_ROUTINE DeferredRoutine, IN void *DeferredContext, IN DPC_PRIORITY DeferredPriority)
Definition dpc.c:384
void MeSetTargetProcessorDpc(IN PDPC Dpc, IN uint32_t CpuNumber)
Definition dpc.c:350
void ReapOb(DPC *dpc, void *DeferredContext, void *SystemArgument1, void *SystemArgument2)
Definition dpc.c:18
void gop_printf(uint32_t color, const char *fmt,...)
Definition gop.c:694
FORCEINLINE void __sti(void)
Definition intrin.h:44
#define UNREFERENCED_PARAMETER(x)
Definition intrin.h:24
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 MeLowerIrql(IN IRQL NewIrql)
Definition irql.c:97
#define CONTAINING_RECORD(ptr, type, member)
Definition macros.h:11
#define RETADDR(level)
Definition macros.h:38
@ DPC_NOT_INITIALIZED
Definition me.h:132
FORCEINLINE IRQL MeGetCurrentIrql(void)
Definition me.h:402
enum _DPC_PRIORITY DPC_PRIORITY
struct _DPC_DATA * PDPC_DATA
DEFERRED_ROUTINE * PDEFERRED_ROUTINE
Definition me.h:195
@ HIGH_PRIORITY
Definition me.h:61
@ LOW_PRIORITY
Definition me.h:59
struct _DPC DPC
FORCEINLINE uint8_t MeGetActiveProcessorCount(void)
Definition me.h:394
FORCEINLINE PPROCESSOR MeGetCurrentProcessor(void)
Definition me.h:356
#define DPC_TARGET_CURRENT
Definition me.h:26
struct _DPC * PDPC
#define COLOR_WHITE
Definition mg.h:32
#define MmFullBarrier()
Definition mm.h:226
FORCEINLINE void InitializeListHead(PDOUBLY_LINKED_LIST Head)
Definition ms.h:166
FORCEINLINE void InsertTailList(PDOUBLY_LINKED_LIST Head, PDOUBLY_LINKED_LIST Entry)
Definition ms.h:179
FORCEINLINE void InsertHeadList(PDOUBLY_LINKED_LIST Head, PDOUBLY_LINKED_LIST Entry)
Definition ms.h:196
FORCEINLINE void RemoveEntryList(PDOUBLY_LINKED_LIST Entry)
Definition ms.h:240
struct _OBJECT_HEADER * POBJECT_HEADER
Definition ob.h:64
void MmFreePool(IN void *buf)
Definition pool.c:586
PPROCESSOR MeGetProcessorBlock(uint8_t ProcessorNumber)
Definition smp.c:196
void MsReleaseSpinlockFromDpcLevel(IN PSPINLOCK Lock)
Definition spinlock.c:100
void MsAcquireSpinlockAtDpcLevel(IN PSPINLOCK Lock)
Definition spinlock.c:74
struct _DOUBLY_LINKED_LIST * Flink
Definition core.h:29
volatile uint32_t DpcQueueDepth
Definition me.h:229
SPINLOCK DpcLock
Definition me.h:228
DOUBLY_LINKED_LIST DpcListHead
Definition me.h:227
volatile uint32_t DpcCount
Definition me.h:230
void * SystemArgument1
Definition me.h:204
volatile void * DpcData
Definition me.h:209
void * DeferredContext
Definition me.h:203
void * SystemArgument2
Definition me.h:205
enum _DPC_PRIORITY priority
Definition me.h:212
PDEFERRED_ROUTINE DeferredRoutine
Definition me.h:202
uint32_t DpcRequestRate
Definition me.h:315
struct _DPC * CurrentDeferredRoutine
Definition me.h:290
volatile bool DpcRoutineActive
Definition me.h:305
uint32_t MaximumDpcQueueDepth
Definition me.h:313
volatile bool DpcInterruptRequested
Definition me.h:318
DPC_DATA DpcData
Definition me.h:304