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                                                \
18         ok_eq_ulongptr(*(Lock), 0);                     \
19 } while (0)
20 
21 typedef struct
22 {
23     BOOLEAN ReturnValue;
24     KIRQL ExpectedIrql;
25     PKINTERRUPT Interrupt;
26 } TEST_CONTEXT, *PTEST_CONTEXT;
27 
28 static KSYNCHRONIZE_ROUTINE SynchronizeRoutine;
29 
30 static
31 BOOLEAN
32 NTAPI
33 SynchronizeRoutine(
34     IN PVOID Context)
35 {
36     PTEST_CONTEXT TestContext = Context;
37 
38     ok_irql(TestContext->ExpectedIrql);
39 
40     CheckSpinLock(TestContext->Interrupt->ActualLock, TRUE);
41 
42     return TestContext->ReturnValue;
43 }
44 
45 static
46 VOID
47 TestSynchronizeExecution(VOID)
48 {
49     KINTERRUPT Interrupt;
50     TEST_CONTEXT TestContext;
51     KIRQL SynchIrql;
52     KIRQL OriginalIrql;
53     KIRQL Irql;
54     KSPIN_LOCK ActualLock;
55     BOOLEAN Ret;
56 
57     RtlFillMemory(&Interrupt, sizeof Interrupt, 0x55);
58     Interrupt.ActualLock = &ActualLock;
59     KeInitializeSpinLock(Interrupt.ActualLock);
60     CheckSpinLock(Interrupt.ActualLock, FALSE);
61 
62     TestContext.Interrupt = &Interrupt;
63     TestContext.ReturnValue = TRUE;
64 
65     for (TestContext.ReturnValue = 0; TestContext.ReturnValue <= 2; ++TestContext.ReturnValue)
66     {
67         for (OriginalIrql = PASSIVE_LEVEL; OriginalIrql <= HIGH_LEVEL; ++OriginalIrql)
68         {
69             /* TODO: don't hardcode this :| */
70             if (OriginalIrql == 3 || (OriginalIrql >= 11 && OriginalIrql <= 26) || OriginalIrql == 30)
71                 continue;
72             KeRaiseIrql(OriginalIrql, &Irql);
73             for (SynchIrql = max(DISPATCH_LEVEL, OriginalIrql); SynchIrql <= HIGH_LEVEL; ++SynchIrql)
74             {
75                 if (SynchIrql == 3 || (SynchIrql >= 11 && SynchIrql <= 26) || SynchIrql == 30)
76                     continue;
77                 Interrupt.SynchronizeIrql = SynchIrql;
78                 ok_irql(OriginalIrql);
79                 CheckSpinLock(Interrupt.ActualLock, FALSE);
80                 TestContext.ExpectedIrql = SynchIrql;
81                 Ret = KeSynchronizeExecution(&Interrupt, SynchronizeRoutine, &TestContext);
82                 ok_eq_int(Ret, TestContext.ReturnValue);
83                 ok_irql(OriginalIrql);
84                 CheckSpinLock(Interrupt.ActualLock, FALSE);
85                 /* TODO: Check that all other fields of the interrupt are untouched */
86             }
87             KeLowerIrql(Irql);
88         }
89     }
90 }
91 
92 START_TEST(IoInterrupt)
93 {
94     TestSynchronizeExecution();
95 }
96