1 /*
2  * PROJECT:         ReactOS kernel-mode tests
3  * LICENSE:         GPLv2+ - See COPYING in the top level directory
4  * PURPOSE:         Kernel-Mode Test Suite Interrupt test
5  * PROGRAMMER:      Thomas Faber <thomas.faber@reactos.org>
6  */
7 
8 #include <kmt_test.h>
9 
10 #define NDEBUG
11 #include <debug.h>
12 
13 #define CheckSpinLock(Lock, Locked) do                  \
14 {                                                       \
15     if (KmtIsMultiProcessorBuild)                       \
16         ok_eq_ulongptr(*(Lock), (Locked) != 0);         \
17     else if (KmtIsCheckedBuild)                         \
18         ok_eq_bool(*(Lock) != 0, (Locked) != 0);        \
19     else                                                \
20         ok_eq_ulongptr(*(Lock), 0);                     \
21 } while (0)
22 
23 typedef struct
24 {
25     BOOLEAN ReturnValue;
26     KIRQL ExpectedIrql;
27     PKINTERRUPT Interrupt;
28 } TEST_CONTEXT, *PTEST_CONTEXT;
29 
30 static KSYNCHRONIZE_ROUTINE SynchronizeRoutine;
31 
32 static
33 BOOLEAN
34 NTAPI
35 SynchronizeRoutine(
36     IN PVOID Context)
37 {
38     PTEST_CONTEXT TestContext = Context;
39 
40     ok_irql(TestContext->ExpectedIrql);
41 
42     CheckSpinLock(TestContext->Interrupt->ActualLock, TRUE);
43 
44     return TestContext->ReturnValue;
45 }
46 
47 static
48 VOID
49 TestSynchronizeExecution(VOID)
50 {
51     KINTERRUPT Interrupt;
52     TEST_CONTEXT TestContext;
53     KIRQL SynchIrql;
54     KIRQL OriginalIrql;
55     KIRQL Irql;
56     KSPIN_LOCK ActualLock;
57     BOOLEAN Ret;
58 
59     RtlFillMemory(&Interrupt, sizeof Interrupt, 0x55);
60     Interrupt.ActualLock = &ActualLock;
61     KeInitializeSpinLock(Interrupt.ActualLock);
62     CheckSpinLock(Interrupt.ActualLock, FALSE);
63 
64     TestContext.Interrupt = &Interrupt;
65     TestContext.ReturnValue = TRUE;
66 
67     for (TestContext.ReturnValue = 0; TestContext.ReturnValue <= 2; ++TestContext.ReturnValue)
68     {
69         for (OriginalIrql = PASSIVE_LEVEL; OriginalIrql <= HIGH_LEVEL; ++OriginalIrql)
70         {
71             /* TODO: don't hardcode this :| */
72             if (OriginalIrql == 3 || (OriginalIrql >= 11 && OriginalIrql <= 26) || OriginalIrql == 30)
73                 continue;
74             KeRaiseIrql(OriginalIrql, &Irql);
75             for (SynchIrql = max(DISPATCH_LEVEL, OriginalIrql); SynchIrql <= HIGH_LEVEL; ++SynchIrql)
76             {
77                 if (SynchIrql == 3 || (SynchIrql >= 11 && SynchIrql <= 26) || SynchIrql == 30)
78                     continue;
79                 Interrupt.SynchronizeIrql = SynchIrql;
80                 ok_irql(OriginalIrql);
81                 CheckSpinLock(Interrupt.ActualLock, FALSE);
82                 TestContext.ExpectedIrql = SynchIrql;
83                 Ret = KeSynchronizeExecution(&Interrupt, SynchronizeRoutine, &TestContext);
84                 ok_eq_int(Ret, TestContext.ReturnValue);
85                 ok_irql(OriginalIrql);
86                 CheckSpinLock(Interrupt.ActualLock, FALSE);
87                 /* TODO: Check that all other fields of the interrupt are untouched */
88             }
89             KeLowerIrql(Irql);
90         }
91     }
92 }
93 
94 START_TEST(IoInterrupt)
95 {
96     TestSynchronizeExecution();
97 }
98