1 /*
2  * PROJECT:     ReactOS kernel-mode tests
3  * LICENSE:     GPL-2.0-or-later (https://spdx.org/licenses/GPL-2.0-or-later)
4  * PURPOSE:     Kernel-Mode Test Suite Spin lock test
5  * COPYRIGHT:   Copyright 2011-2023 Thomas Faber (thomas.faber@reactos.org)
6  * COPYRIGHT:   Copyright 2021 Jérôme Gardou (jerome.gardou@reactos.org)
7  */
8 
9 #ifndef _WIN64
10 __declspec(dllimport) void __stdcall KeAcquireSpinLock(unsigned long *, unsigned char *);
11 __declspec(dllimport) void __stdcall KeReleaseSpinLock(unsigned long *, unsigned char);
12 __declspec(dllimport) void __stdcall KeAcquireSpinLockAtDpcLevel(unsigned long *);
13 __declspec(dllimport) void __stdcall KeReleaseSpinLockFromDpcLevel(unsigned long *);
14 #endif
15 
16 /* this define makes KeInitializeSpinLock not use the inlined version */
17 #define WIN9X_COMPAT_SPINLOCK
18 #include <kmt_test.h>
19 #include <limits.h>
20 
21 //#define NDEBUG
22 #include <debug.h>
23 
24 static
25 _Must_inspect_result_
26 _IRQL_requires_min_(DISPATCH_LEVEL)
27 _Post_satisfies_(return == 1 || return == 0)
28 BOOLEAN
29 (FASTCALL
30 *pKeTryToAcquireSpinLockAtDpcLevel)(
31     _Inout_ _Requires_lock_not_held_(*_Curr_)
32     _When_(return!=0, _Acquires_lock_(*_Curr_))
33         PKSPIN_LOCK SpinLock);
34 
35 static
36 VOID
37 (FASTCALL
38 *pKeAcquireInStackQueuedSpinLockForDpc)(
39   IN OUT PKSPIN_LOCK SpinLock,
40   OUT PKLOCK_QUEUE_HANDLE LockHandle);
41 
42 static
43 VOID
44 (FASTCALL
45 *pKeReleaseInStackQueuedSpinLockForDpc)(
46   IN PKLOCK_QUEUE_HANDLE LockHandle);
47 
48 static
49 _Must_inspect_result_
50 BOOLEAN
51 (FASTCALL
52 *pKeTestSpinLock)(
53   _In_ PKSPIN_LOCK SpinLock);
54 
55 /* TODO: multiprocessor testing */
56 
57 struct _CHECK_DATA;
58 typedef struct _CHECK_DATA CHECK_DATA, *PCHECK_DATA;
59 
60 typedef VOID (*PACQUIRE_FUNCTION)(PKSPIN_LOCK, PCHECK_DATA);
61 typedef VOID (*PRELEASE_FUNCTION)(PKSPIN_LOCK, PCHECK_DATA);
62 typedef BOOLEAN (*PTRY_FUNCTION)(PKSPIN_LOCK, PCHECK_DATA);
63 
64 struct _CHECK_DATA
65 {
66     enum
67     {
68         CheckQueueHandle,
69         CheckQueue,
70         CheckLock
71     } Check;
72     KIRQL IrqlWhenAcquired;
73     PACQUIRE_FUNCTION Acquire;
74     PRELEASE_FUNCTION Release;
75     PTRY_FUNCTION TryAcquire;
76     PACQUIRE_FUNCTION AcquireNoRaise;
77     PRELEASE_FUNCTION ReleaseNoLower;
78     PTRY_FUNCTION TryAcquireNoRaise;
79     KSPIN_LOCK_QUEUE_NUMBER QueueNumber;
80     BOOLEAN TryRetOnFailure;
81     KIRQL OriginalIrql;
82     BOOLEAN IsAcquired;
83     _ANONYMOUS_UNION union
84     {
85         KLOCK_QUEUE_HANDLE QueueHandle;
86         PKSPIN_LOCK_QUEUE Queue;
87         KIRQL Irql;
88     } DUMMYUNIONNAME;
89     PVOID UntouchedValue;
90 };
91 
92 #define DEFINE_ACQUIRE(LocalName, SetIsAcquired, DoCall)            \
93 static VOID LocalName(PKSPIN_LOCK SpinLock, PCHECK_DATA CheckData)  \
94 {                                                                   \
95     ASSERT(!CheckData->IsAcquired);                                 \
96     DoCall;                                                         \
97     if (SetIsAcquired) CheckData->IsAcquired = TRUE;                \
98 }
99 
100 #define DEFINE_RELEASE(LocalName, SetIsAcquired, DoCall)            \
101 static VOID LocalName(PKSPIN_LOCK SpinLock, PCHECK_DATA CheckData)  \
102 {                                                                   \
103     DoCall;                                                         \
104     if (SetIsAcquired) CheckData->IsAcquired = FALSE;               \
105 }
106 
107 DEFINE_ACQUIRE(AcquireNormal,         TRUE,  KeAcquireSpinLock(SpinLock, &CheckData->Irql))
108 DEFINE_RELEASE(ReleaseNormal,         TRUE,  KeReleaseSpinLock(SpinLock, CheckData->Irql))
109 #ifdef _X86_
110 DEFINE_ACQUIRE(AcquireExp,            TRUE,  (KeAcquireSpinLock)(SpinLock, &CheckData->Irql))
111 DEFINE_RELEASE(ReleaseExp,            TRUE,  (KeReleaseSpinLock)(SpinLock, CheckData->Irql))
112 #else
113 DEFINE_ACQUIRE(AcquireExp,            TRUE,  KeAcquireSpinLock(SpinLock, &CheckData->Irql))
114 DEFINE_RELEASE(ReleaseExp,            TRUE,  KeReleaseSpinLock(SpinLock, CheckData->Irql))
115 #endif
116 DEFINE_ACQUIRE(AcquireSynch,          TRUE,  CheckData->Irql = KeAcquireSpinLockRaiseToSynch(SpinLock))
117 
118 DEFINE_ACQUIRE(AcquireInStackQueued,  TRUE,  KeAcquireInStackQueuedSpinLock(SpinLock, &CheckData->QueueHandle))
119 DEFINE_ACQUIRE(AcquireInStackSynch,   TRUE,  KeAcquireInStackQueuedSpinLockRaiseToSynch(SpinLock, &CheckData->QueueHandle))
120 DEFINE_RELEASE(ReleaseInStackQueued,  TRUE,  KeReleaseInStackQueuedSpinLock(&CheckData->QueueHandle))
121 
122 DEFINE_ACQUIRE(AcquireQueued,         TRUE,  CheckData->Irql = KeAcquireQueuedSpinLock(CheckData->QueueNumber))
123 DEFINE_ACQUIRE(AcquireQueuedSynch,    TRUE,  CheckData->Irql = KeAcquireQueuedSpinLockRaiseToSynch(CheckData->QueueNumber))
124 DEFINE_RELEASE(ReleaseQueued,         TRUE,  KeReleaseQueuedSpinLock(CheckData->QueueNumber, CheckData->Irql))
125 
126 DEFINE_ACQUIRE(AcquireNoRaise,        FALSE, KeAcquireSpinLockAtDpcLevel(SpinLock))
127 DEFINE_RELEASE(ReleaseNoLower,        FALSE, KeReleaseSpinLockFromDpcLevel(SpinLock))
128 DEFINE_ACQUIRE(AcquireExpNoRaise,     FALSE, (KeAcquireSpinLockAtDpcLevel)(SpinLock))
129 DEFINE_RELEASE(ReleaseExpNoLower,     FALSE, (KeReleaseSpinLockFromDpcLevel)(SpinLock))
130 
131 DEFINE_ACQUIRE(AcquireInStackNoRaise, FALSE, KeAcquireInStackQueuedSpinLockAtDpcLevel(SpinLock, &CheckData->QueueHandle))
132 DEFINE_RELEASE(ReleaseInStackNoRaise, FALSE, KeReleaseInStackQueuedSpinLockFromDpcLevel(&CheckData->QueueHandle))
133 
134 /* TODO: test these functions. They behave weirdly, though */
135 #if 0
136 DEFINE_ACQUIRE(AcquireForDpc,         TRUE,  CheckData->Irql = KeAcquireSpinLockForDpc(SpinLock))
137 DEFINE_RELEASE(ReleaseForDpc,         TRUE,  KeReleaseSpinLockForDpc(SpinLock, CheckData->Irql))
138 #endif
139 
140 DEFINE_ACQUIRE(AcquireInStackForDpc,  FALSE, pKeAcquireInStackQueuedSpinLockForDpc(SpinLock, &CheckData->QueueHandle))
141 DEFINE_RELEASE(ReleaseInStackForDpc,  FALSE, pKeReleaseInStackQueuedSpinLockForDpc(&CheckData->QueueHandle))
142 
143 #ifdef _X86_
144 DEFINE_ACQUIRE(AcquireInt,            FALSE, KiAcquireSpinLock(SpinLock))
145 DEFINE_RELEASE(ReleaseInt,            FALSE, KiReleaseSpinLock(SpinLock))
146 #else
147 DEFINE_ACQUIRE(AcquireInt,            TRUE,  KeAcquireSpinLock(SpinLock, &CheckData->Irql))
148 DEFINE_RELEASE(ReleaseInt,            TRUE,  KeReleaseSpinLock(SpinLock, CheckData->Irql))
149 #endif
150 
151 BOOLEAN TryQueued(PKSPIN_LOCK SpinLock, PCHECK_DATA CheckData) {
152     LOGICAL Ret = KeTryToAcquireQueuedSpinLock(CheckData->QueueNumber, &CheckData->Irql);
153     CheckData->IsAcquired = TRUE;
154     ASSERT(Ret == FALSE || Ret == TRUE);
155     return (BOOLEAN)Ret;
156 }
157 BOOLEAN TryQueuedSynch(PKSPIN_LOCK SpinLock, PCHECK_DATA CheckData) {
158     BOOLEAN Ret = KeTryToAcquireQueuedSpinLockRaiseToSynch(CheckData->QueueNumber, &CheckData->Irql);
159     CheckData->IsAcquired = TRUE;
160     return Ret;
161 }
162 BOOLEAN TryNoRaise(PKSPIN_LOCK SpinLock, PCHECK_DATA CheckData) {
163     BOOLEAN Ret = pKeTryToAcquireSpinLockAtDpcLevel(SpinLock);
164     return Ret;
165 }
166 
167 #define CheckSpinLockLock(SpinLock, CheckData, Value) do                            \
168 {                                                                                   \
169     PKTHREAD Thread = KeGetCurrentThread();                                         \
170     (VOID)Thread;                                                                   \
171     if (KmtIsMultiProcessorBuild || KmtIsCheckedBuild)                              \
172     {                                                                               \
173         ok_eq_bool(Ret, (Value) == 0);                                              \
174         if (SpinLock)                                                               \
175         {                                                                           \
176             if (KmtIsCheckedBuild)                                                  \
177                 ok_eq_ulongptr(*(SpinLock), (Value) ? (ULONG_PTR)Thread | 1 : 0);   \
178             else                                                                    \
179                 ok_eq_ulongptr(*(SpinLock), (Value) ? 1 : 0);                       \
180         }                                                                           \
181     }                                                                               \
182     else                                                                            \
183     {                                                                               \
184         ok_bool_true(Ret, "KeTestSpinLock returned");                               \
185         if (SpinLock)                                                               \
186             ok_eq_ulongptr(*(SpinLock), 0);                                         \
187     }                                                                               \
188     ok_eq_uint((CheckData)->Irql, (CheckData)->OriginalIrql);                       \
189 } while (0)
190 
191 #define CheckSpinLockQueue(SpinLock, CheckData, Value) do                           \
192 {                                                                                   \
193     ok_eq_pointer((CheckData)->Queue->Next, NULL);                                  \
194     ok_eq_pointer((CheckData)->Queue->Lock, NULL);                                  \
195     ok_eq_uint((CheckData)->Irql, (CheckData)->OriginalIrql);                       \
196 } while (0)
197 
198 #define CheckSpinLockQueueHandle(SpinLock, CheckData, Value) do                     \
199 {                                                                                   \
200     if (KmtIsMultiProcessorBuild || KmtIsCheckedBuild)                              \
201     {                                                                               \
202         ok_eq_bool(Ret, (Value) == 0);                                              \
203         if (SpinLock)                                                               \
204             ok_eq_ulongptr(*(SpinLock),                                             \
205                         (Value) ? &(CheckData)->QueueHandle : 0);                   \
206         ok_eq_pointer((CheckData)->QueueHandle.LockQueue.Next, NULL);               \
207         ok_eq_pointer((CheckData)->QueueHandle.LockQueue.Lock,                      \
208                 (PVOID)((ULONG_PTR)SpinLock | ((Value) ? 2 : 0)));                  \
209     }                                                                               \
210     else                                                                            \
211     {                                                                               \
212         ok_bool_true(Ret, "KeTestSpinLock returned");                               \
213         if (SpinLock)                                                               \
214             ok_eq_ulongptr(*(SpinLock), 0);                                         \
215         ok_eq_pointer((CheckData)->QueueHandle.LockQueue.Next, (CheckData)->UntouchedValue);                \
216         ok_eq_pointer((CheckData)->QueueHandle.LockQueue.Lock, (CheckData)->UntouchedValue);                \
217     }                                                                               \
218     ok_eq_uint((CheckData)->QueueHandle.OldIrql, (CheckData)->OriginalIrql);        \
219 } while (0)
220 
221 #define CheckSpinLock(SpinLock, CheckData, Value) do                                \
222 {                                                                                   \
223     BOOLEAN Ret = SpinLock && pKeTestSpinLock ? pKeTestSpinLock(SpinLock) : TRUE;   \
224     KIRQL ExpectedIrql = (CheckData)->OriginalIrql;                                 \
225                                                                                     \
226     switch ((CheckData)->Check)                                                     \
227     {                                                                               \
228         case CheckLock:                                                             \
229             CheckSpinLockLock(SpinLock, CheckData, Value);                          \
230             break;                                                                  \
231         case CheckQueue:                                                            \
232             CheckSpinLockQueue(SpinLock, CheckData, Value);                         \
233             break;                                                                  \
234         case CheckQueueHandle:                                                      \
235             CheckSpinLockQueueHandle(SpinLock, CheckData, Value);                   \
236             break;                                                                  \
237     }                                                                               \
238                                                                                     \
239     if ((CheckData)->IsAcquired)                                                    \
240         ExpectedIrql = (CheckData)->IrqlWhenAcquired;                               \
241     ok_irql(ExpectedIrql);                                                          \
242     ok_bool_false(KeAreApcsDisabled(), "KeAreApcsDisabled returned");               \
243     ok_bool_true(KmtAreInterruptsEnabled(), "Interrupts enabled:");                 \
244 } while (0)
245 
246 static
247 VOID
248 TestSpinLock(
249     PKSPIN_LOCK SpinLock,
250     PCHECK_DATA CheckData)
251 {
252     static INT Run = 0;
253     trace("Test SpinLock run %d\n", Run++);
254 
255     ok_irql(CheckData->OriginalIrql);
256 
257     if (SpinLock)
258         ok_eq_ulongptr(*SpinLock, 0);
259     CheckData->Acquire(SpinLock, CheckData);
260     CheckSpinLock(SpinLock, CheckData, 1);
261     CheckData->Release(SpinLock, CheckData);
262     CheckSpinLock(SpinLock, CheckData, 0);
263 
264     if (CheckData->TryAcquire)
265     {
266         CheckSpinLock(SpinLock, CheckData, 0);
267         ok_bool_true(CheckData->TryAcquire(SpinLock, CheckData), "TryAcquire returned");
268         CheckSpinLock(SpinLock, CheckData, 1);
269         /* A second TryToAcquire results in SPINLOCK_ALREADY_OWNED on checked builds */
270         if (!KmtIsCheckedBuild)
271         {
272             if (KmtIsMultiProcessorBuild)
273             {
274                 /* In MP, this fails as you would expect */
275                 ok_bool_false(CheckData->TryAcquire(SpinLock, CheckData), "TryAcquire returned");
276             }
277             else
278             {
279                 /* In UP, this always succeeds: recursive acquires are illegal and parallel processors don't exist */
280                 ok_bool_true(CheckData->TryAcquire(SpinLock, CheckData), "TryAcquire returned");
281                 ok_eq_uint(CheckData->Irql, CheckData->IrqlWhenAcquired);
282                 CheckData->Irql = CheckData->OriginalIrql;
283             }
284             CheckSpinLock(SpinLock, CheckData, 1);
285         }
286         CheckData->Release(SpinLock, CheckData);
287         CheckSpinLock(SpinLock, CheckData, 0);
288     }
289 
290     if (CheckData->AcquireNoRaise &&
291         (CheckData->OriginalIrql >= DISPATCH_LEVEL || !KmtIsCheckedBuild) &&
292         (CheckData->AcquireNoRaise != AcquireInStackForDpc ||
293          !skip(pKeAcquireInStackQueuedSpinLockForDpc &&
294                pKeReleaseInStackQueuedSpinLockForDpc, "No DPC spinlock functions\n")))
295     {
296         /* acquire/release without irql change */
297         CheckData->AcquireNoRaise(SpinLock, CheckData);
298         CheckSpinLock(SpinLock, CheckData, 1);
299         CheckData->ReleaseNoLower(SpinLock, CheckData);
300         CheckSpinLock(SpinLock, CheckData, 0);
301 
302         /* acquire without raise, but normal release */
303         CheckData->AcquireNoRaise(SpinLock, CheckData);
304         CheckSpinLock(SpinLock, CheckData, 1);
305         CheckData->Release(SpinLock, CheckData);
306         CheckSpinLock(SpinLock, CheckData, 0);
307 
308         /* acquire normally but release without lower */
309         CheckData->Acquire(SpinLock, CheckData);
310         CheckSpinLock(SpinLock, CheckData, 1);
311         CheckData->ReleaseNoLower(SpinLock, CheckData);
312         CheckSpinLock(SpinLock, CheckData, 0);
313         CheckData->IsAcquired = FALSE;
314         KmtSetIrql(CheckData->OriginalIrql);
315 
316         if (CheckData->TryAcquireNoRaise &&
317             !skip(pKeTryToAcquireSpinLockAtDpcLevel != NULL, "KeTryToAcquireSpinLockAtDpcLevel unavailable\n"))
318         {
319             CheckSpinLock(SpinLock, CheckData, 0);
320             ok_bool_true(CheckData->TryAcquireNoRaise(SpinLock, CheckData), "TryAcquireNoRaise returned");
321             CheckSpinLock(SpinLock, CheckData, 1);
322             if (!KmtIsCheckedBuild)
323             {
324                 if (KmtIsMultiProcessorBuild)
325                 {
326                     /* In MP, this fails as you would expect */
327                     ok_bool_false(CheckData->TryAcquireNoRaise(SpinLock, CheckData), "TryAcquireNoRaise returned");
328                 }
329                 else
330                 {
331                     /* In UP, this always succeeds: recursive acquires are illegal and parallel processors don't exist */
332                     ok_bool_true(CheckData->TryAcquireNoRaise(SpinLock, CheckData), "TryAcquireNoRaise returned");
333                 }
334                 CheckSpinLock(SpinLock, CheckData, 1);
335             }
336             CheckData->ReleaseNoLower(SpinLock, CheckData);
337             CheckSpinLock(SpinLock, CheckData, 0);
338         }
339     }
340 
341     ok_irql(CheckData->OriginalIrql);
342     /* make sure we survive this in case of error */
343     KmtSetIrql(CheckData->OriginalIrql);
344 }
345 
346 START_TEST(KeSpinLock)
347 {
348     KSPIN_LOCK SpinLock = (KSPIN_LOCK)0x5555555555555555LL;
349     PKSPIN_LOCK pSpinLock = &SpinLock;
350     KIRQL Irql, SynchIrql = KmtIsMultiProcessorBuild ? IPI_LEVEL - 2 : DISPATCH_LEVEL;
351     KIRQL OriginalIrqls[] = { PASSIVE_LEVEL, APC_LEVEL, DISPATCH_LEVEL, HIGH_LEVEL };
352     CHECK_DATA TestData[] =
353     {
354         { CheckLock,        DISPATCH_LEVEL, AcquireNormal,        ReleaseNormal,        NULL,           AcquireNoRaise,        ReleaseNoLower,        TryNoRaise },
355         { CheckLock,        DISPATCH_LEVEL, AcquireExp,           ReleaseExp,           NULL,           AcquireExpNoRaise,     ReleaseExpNoLower,     NULL },
356         /* TODO: this one is just weird!
357         { CheckLock,        DISPATCH_LEVEL, AcquireNormal,        ReleaseNormal,        NULL,           AcquireForDpc,         ReleaseForDpc,         NULL },*/
358         { CheckLock,        DISPATCH_LEVEL, AcquireNormal,        ReleaseNormal,        NULL,           AcquireInt,            ReleaseInt,            NULL },
359         { CheckLock,        SynchIrql,      AcquireSynch,         ReleaseNormal,        NULL,           NULL,                  NULL,                  NULL },
360         { CheckQueueHandle, DISPATCH_LEVEL, AcquireInStackQueued, ReleaseInStackQueued, NULL,           AcquireInStackNoRaise, ReleaseInStackNoRaise, NULL },
361         { CheckQueueHandle, SynchIrql,      AcquireInStackSynch,  ReleaseInStackQueued, NULL,           NULL,                  NULL,                  NULL },
362         { CheckQueueHandle, DISPATCH_LEVEL, AcquireInStackQueued, ReleaseInStackQueued, NULL,           AcquireInStackForDpc,  ReleaseInStackForDpc,  NULL },
363         { CheckQueue,       DISPATCH_LEVEL, AcquireQueued,        ReleaseQueued,        TryQueued,      NULL,                  NULL,                  NULL,       LockQueuePfnLock },
364         { CheckQueue,       SynchIrql,      AcquireQueuedSynch,   ReleaseQueued,        TryQueuedSynch, NULL,                  NULL,                  NULL,       LockQueuePfnLock },
365     };
366     int i, iIrql;
367     PKPRCB Prcb;
368 
369     pKeTryToAcquireSpinLockAtDpcLevel = KmtGetSystemRoutineAddress(L"KeTryToAcquireSpinLockAtDpcLevel");
370     pKeAcquireInStackQueuedSpinLockForDpc = KmtGetSystemRoutineAddress(L"KeAcquireInStackQueuedSpinLockForDpc");
371     pKeReleaseInStackQueuedSpinLockForDpc = KmtGetSystemRoutineAddress(L"KeReleaseInStackQueuedSpinLockForDpc");
372     pKeTestSpinLock = KmtGetSystemRoutineAddress(L"KeTestSpinLock");
373 
374     Prcb = KeGetCurrentPrcb();
375 
376     /* KeInitializeSpinLock */
377     memset(&SpinLock, 0x55, sizeof SpinLock);
378     KeInitializeSpinLock(&SpinLock);
379     ok_eq_ulongptr(SpinLock, 0);
380 
381     /* KeTestSpinLock */
382     if (!skip(pKeTestSpinLock != NULL, "KeTestSpinLock unavailable\n"))
383     {
384         ok_bool_true(pKeTestSpinLock(&SpinLock), "KeTestSpinLock returned");
385         SpinLock = 1;
386         ok_bool_false(pKeTestSpinLock(&SpinLock), "KeTestSpinLock returned");
387         SpinLock = 2;
388         ok_bool_false(pKeTestSpinLock(&SpinLock), "KeTestSpinLock returned");
389         SpinLock = (ULONG_PTR)-1;
390         ok_bool_false(pKeTestSpinLock(&SpinLock), "KeTestSpinLock returned");
391         SpinLock = (ULONG_PTR)1 << (sizeof(ULONG_PTR) * CHAR_BIT - 1);
392         ok_bool_false(pKeTestSpinLock(&SpinLock), "KeTestSpinLock returned");
393         SpinLock = 0;
394         ok_bool_true(pKeTestSpinLock(&SpinLock), "KeTestSpinLock returned");
395     }
396 
397     /* on UP none of the following functions actually looks at the spinlock! */
398     if (!KmtIsMultiProcessorBuild && !KmtIsCheckedBuild)
399         pSpinLock = NULL;
400 
401     for (i = 0; i < sizeof TestData / sizeof TestData[0]; ++i)
402     {
403         memset(&SpinLock, 0x55, sizeof SpinLock);
404         KeInitializeSpinLock(&SpinLock);
405         if (TestData[i].Check == CheckQueueHandle)
406             memset(&TestData[i].QueueHandle, 0x55, sizeof TestData[i].QueueHandle);
407         if (TestData[i].Check == CheckQueue)
408         {
409             TestData[i].Queue = &Prcb->LockQueue[TestData[i].QueueNumber];
410             TestData[i].UntouchedValue = NULL;
411         }
412         else
413             TestData[i].UntouchedValue = (PVOID)0x5555555555555555LL;
414 
415         for (iIrql = 0; iIrql < sizeof OriginalIrqls / sizeof OriginalIrqls[0]; ++iIrql)
416         {
417             if (KmtIsCheckedBuild && OriginalIrqls[iIrql] > DISPATCH_LEVEL)
418                 continue;
419             KeRaiseIrql(OriginalIrqls[iIrql], &Irql);
420             TestData[i].OriginalIrql = OriginalIrqls[iIrql];
421             TestData[i].IsAcquired = FALSE;
422             TestSpinLock(pSpinLock, &TestData[i]);
423             KeLowerIrql(Irql);
424         }
425     }
426 
427     KmtSetIrql(PASSIVE_LEVEL);
428 }
429