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