1*c2c66affSColin Finck /*
2*c2c66affSColin Finck  * PROJECT:         ReactOS kernel-mode tests
3*c2c66affSColin Finck  * LICENSE:         GPLv2+ - See COPYING in the top level directory
4*c2c66affSColin Finck  * PURPOSE:         Kernel-Mode Test Suite Deferred Procedure Call test
5*c2c66affSColin Finck  * PROGRAMMER:      Thomas Faber <thomas.faber@reactos.org>
6*c2c66affSColin Finck  */
7*c2c66affSColin Finck 
8*c2c66affSColin Finck #include <kmt_test.h>
9*c2c66affSColin Finck 
10*c2c66affSColin Finck //#define NDEBUG
11*c2c66affSColin Finck #include <debug.h>
12*c2c66affSColin Finck 
13*c2c66affSColin Finck /* TODO: DPC importance */
14*c2c66affSColin Finck 
15*c2c66affSColin Finck static volatile LONG DpcCount;
16*c2c66affSColin Finck static volatile UCHAR DpcImportance;
17*c2c66affSColin Finck 
18*c2c66affSColin Finck static KDEFERRED_ROUTINE DpcHandler;
19*c2c66affSColin Finck 
20*c2c66affSColin Finck static
21*c2c66affSColin Finck VOID
22*c2c66affSColin Finck NTAPI
DpcHandler(IN PRKDPC Dpc,IN PVOID DeferredContext,IN PVOID SystemArgument1,IN PVOID SystemArgument2)23*c2c66affSColin Finck DpcHandler(
24*c2c66affSColin Finck     IN PRKDPC Dpc,
25*c2c66affSColin Finck     IN PVOID DeferredContext,
26*c2c66affSColin Finck     IN PVOID SystemArgument1,
27*c2c66affSColin Finck     IN PVOID SystemArgument2)
28*c2c66affSColin Finck {
29*c2c66affSColin Finck     PKPRCB Prcb = KeGetCurrentPrcb();
30*c2c66affSColin Finck 
31*c2c66affSColin Finck     ok_irql(DISPATCH_LEVEL);
32*c2c66affSColin Finck     InterlockedIncrement(&DpcCount);
33*c2c66affSColin Finck     ok(DeferredContext == Dpc, "DeferredContext = %p, Dpc = %p, expected equal\n", DeferredContext, Dpc);
34*c2c66affSColin Finck     ok_eq_pointer(SystemArgument1, (PVOID)0xabc123);
35*c2c66affSColin Finck     ok_eq_pointer(SystemArgument2, (PVOID)0x5678);
36*c2c66affSColin Finck 
37*c2c66affSColin Finck     /* KDPC object contents */
38*c2c66affSColin Finck     ok_eq_uint(Dpc->Type, DpcObject);
39*c2c66affSColin Finck     ok_eq_uint(Dpc->Importance, DpcImportance);
40*c2c66affSColin Finck     ok_eq_uint(Dpc->Number, 0);
41*c2c66affSColin Finck     ok(Dpc->DpcListEntry.Blink != NULL, "\n");
42*c2c66affSColin Finck     ok(Dpc->DpcListEntry.Blink != &Dpc->DpcListEntry, "\n");
43*c2c66affSColin Finck     if (!skip(Dpc->DpcListEntry.Blink != NULL, "DpcListEntry.Blink == NULL\n"))
44*c2c66affSColin Finck         ok_eq_pointer(Dpc->DpcListEntry.Flink, Dpc->DpcListEntry.Blink->Flink);
45*c2c66affSColin Finck 
46*c2c66affSColin Finck     ok(Dpc->DpcListEntry.Flink != NULL, "\n");
47*c2c66affSColin Finck     ok(Dpc->DpcListEntry.Flink != &Dpc->DpcListEntry, "\n");
48*c2c66affSColin Finck     if (!skip(Dpc->DpcListEntry.Flink != NULL, "DpcListEntry.Flink == NULL\n"))
49*c2c66affSColin Finck         ok_eq_pointer(Dpc->DpcListEntry.Blink, Dpc->DpcListEntry.Flink->Blink);
50*c2c66affSColin Finck 
51*c2c66affSColin Finck     ok_eq_pointer(Dpc->DeferredRoutine, DpcHandler);
52*c2c66affSColin Finck     ok_eq_pointer(Dpc->DeferredContext, DeferredContext);
53*c2c66affSColin Finck     ok_eq_pointer(Dpc->SystemArgument1, SystemArgument1);
54*c2c66affSColin Finck     ok_eq_pointer(Dpc->SystemArgument2, SystemArgument2);
55*c2c66affSColin Finck     ok_eq_pointer(Dpc->DpcData, NULL);
56*c2c66affSColin Finck 
57*c2c66affSColin Finck     ok_eq_uint(Prcb->DpcRoutineActive, 1);
58*c2c66affSColin Finck     /* this DPC is not in the list anymore, but it was at the head! */
59*c2c66affSColin Finck     ok_eq_pointer(Prcb->DpcData[DPC_NORMAL].DpcListHead.Flink, Dpc->DpcListEntry.Flink);
60*c2c66affSColin Finck     ok_eq_pointer(Prcb->DpcData[DPC_NORMAL].DpcListHead.Blink, Dpc->DpcListEntry.Blink);
61*c2c66affSColin Finck }
62*c2c66affSColin Finck 
START_TEST(KeDpc)63*c2c66affSColin Finck START_TEST(KeDpc)
64*c2c66affSColin Finck {
65*c2c66affSColin Finck     NTSTATUS Status = STATUS_SUCCESS;
66*c2c66affSColin Finck     KDPC Dpc;
67*c2c66affSColin Finck     KIRQL Irql, Irql2, Irql3;
68*c2c66affSColin Finck     LONG ExpectedDpcCount = 0;
69*c2c66affSColin Finck     BOOLEAN Ret;
70*c2c66affSColin Finck     int i;
71*c2c66affSColin Finck 
72*c2c66affSColin Finck     DpcCount = 0;
73*c2c66affSColin Finck     DpcImportance = MediumImportance;
74*c2c66affSColin Finck 
75*c2c66affSColin Finck #define ok_dpccount() ok(DpcCount == ExpectedDpcCount, "DpcCount = %ld, expected %ld\n", DpcCount, ExpectedDpcCount);
76*c2c66affSColin Finck     trace("Dpc = %p\n", &Dpc);
77*c2c66affSColin Finck     memset(&Dpc, 0x55, sizeof Dpc);
78*c2c66affSColin Finck     KeInitializeDpc(&Dpc, DpcHandler, &Dpc);
79*c2c66affSColin Finck     /* check the Dpc object's fields */
80*c2c66affSColin Finck     ok_eq_uint(Dpc.Type, DpcObject);
81*c2c66affSColin Finck     ok_eq_uint(Dpc.Importance, DpcImportance);
82*c2c66affSColin Finck     ok_eq_uint(Dpc.Number, 0);
83*c2c66affSColin Finck     ok_eq_pointer(Dpc.DpcListEntry.Flink, (LIST_ENTRY *)0x5555555555555555LL);
84*c2c66affSColin Finck     ok_eq_pointer(Dpc.DpcListEntry.Blink, (LIST_ENTRY *)0x5555555555555555LL);
85*c2c66affSColin Finck     ok_eq_pointer(Dpc.DeferredRoutine, DpcHandler);
86*c2c66affSColin Finck     ok_eq_pointer(Dpc.DeferredContext, &Dpc);
87*c2c66affSColin Finck     ok_eq_pointer(Dpc.SystemArgument1, (PVOID)0x5555555555555555LL);
88*c2c66affSColin Finck     ok_eq_pointer(Dpc.SystemArgument2, (PVOID)0x5555555555555555LL);
89*c2c66affSColin Finck     ok_eq_pointer(Dpc.DpcData, NULL);
90*c2c66affSColin Finck 
91*c2c66affSColin Finck     /* simply run the Dpc a few times */
92*c2c66affSColin Finck     for (i = 0; i < 5; ++i)
93*c2c66affSColin Finck     {
94*c2c66affSColin Finck         ok_dpccount();
95*c2c66affSColin Finck         Ret = KeInsertQueueDpc(&Dpc, (PVOID)0xabc123, (PVOID)0x5678);
96*c2c66affSColin Finck         ok_bool_true(Ret, "KeInsertQueueDpc returned");
97*c2c66affSColin Finck         ++ExpectedDpcCount;
98*c2c66affSColin Finck         ok_dpccount();
99*c2c66affSColin Finck     }
100*c2c66affSColin Finck 
101*c2c66affSColin Finck     /* insert into queue at high irql
102*c2c66affSColin Finck      * -> should only run when lowered to APC_LEVEL,
103*c2c66affSColin Finck      *    inserting a second time should fail
104*c2c66affSColin Finck      */
105*c2c66affSColin Finck     KeRaiseIrql(APC_LEVEL, &Irql);
106*c2c66affSColin Finck     for (i = 0; i < 5; ++i)
107*c2c66affSColin Finck     {
108*c2c66affSColin Finck         KeRaiseIrql(DISPATCH_LEVEL, &Irql2);
109*c2c66affSColin Finck           ok_dpccount();
110*c2c66affSColin Finck           Ret = KeInsertQueueDpc(&Dpc, (PVOID)0xabc123, (PVOID)0x5678);
111*c2c66affSColin Finck           ok_bool_true(Ret, "KeInsertQueueDpc returned");
112*c2c66affSColin Finck           Ret = KeInsertQueueDpc(&Dpc, (PVOID)0xdef, (PVOID)0x123);
113*c2c66affSColin Finck           ok_bool_false(Ret, "KeInsertQueueDpc returned");
114*c2c66affSColin Finck           ok_dpccount();
115*c2c66affSColin Finck           KeRaiseIrql(HIGH_LEVEL, &Irql3);
116*c2c66affSColin Finck             ok_dpccount();
117*c2c66affSColin Finck           KeLowerIrql(Irql3);
118*c2c66affSColin Finck           ok_dpccount();
119*c2c66affSColin Finck         KeLowerIrql(Irql2);
120*c2c66affSColin Finck         ++ExpectedDpcCount;
121*c2c66affSColin Finck         ok_dpccount();
122*c2c66affSColin Finck     }
123*c2c66affSColin Finck     KeLowerIrql(Irql);
124*c2c66affSColin Finck 
125*c2c66affSColin Finck     /* now test removing from the queue */
126*c2c66affSColin Finck     KeRaiseIrql(APC_LEVEL, &Irql);
127*c2c66affSColin Finck     for (i = 0; i < 5; ++i)
128*c2c66affSColin Finck     {
129*c2c66affSColin Finck         KeRaiseIrql(DISPATCH_LEVEL, &Irql2);
130*c2c66affSColin Finck           ok_dpccount();
131*c2c66affSColin Finck           Ret = KeRemoveQueueDpc(&Dpc);
132*c2c66affSColin Finck           ok_bool_false(Ret, "KeRemoveQueueDpc returned");
133*c2c66affSColin Finck           Ret = KeInsertQueueDpc(&Dpc, (PVOID)0xabc123, (PVOID)0x5678);
134*c2c66affSColin Finck           ok_bool_true(Ret, "KeInsertQueueDpc returned");
135*c2c66affSColin Finck           ok_dpccount();
136*c2c66affSColin Finck           KeRaiseIrql(HIGH_LEVEL, &Irql3);
137*c2c66affSColin Finck             ok_dpccount();
138*c2c66affSColin Finck           KeLowerIrql(Irql3);
139*c2c66affSColin Finck           ok_dpccount();
140*c2c66affSColin Finck           Ret = KeRemoveQueueDpc(&Dpc);
141*c2c66affSColin Finck           ok_bool_true(Ret, "KeRemoveQueueDpc returned");
142*c2c66affSColin Finck         KeLowerIrql(Irql2);
143*c2c66affSColin Finck         ok_dpccount();
144*c2c66affSColin Finck     }
145*c2c66affSColin Finck     KeLowerIrql(Irql);
146*c2c66affSColin Finck 
147*c2c66affSColin Finck     /* parameter checks */
148*c2c66affSColin Finck     Status = STATUS_SUCCESS;
149*c2c66affSColin Finck     _SEH2_TRY {
150*c2c66affSColin Finck         KeInitializeDpc(&Dpc, NULL, NULL);
151*c2c66affSColin Finck     } _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER) {
152*c2c66affSColin Finck         Status = _SEH2_GetExceptionCode();
153*c2c66affSColin Finck     } _SEH2_END;
154*c2c66affSColin Finck     ok_eq_hex(Status, STATUS_SUCCESS);
155*c2c66affSColin Finck 
156*c2c66affSColin Finck     if (!skip(Status == STATUS_SUCCESS, "KeInitializeDpc failed\n"))
157*c2c66affSColin Finck     {
158*c2c66affSColin Finck         KeRaiseIrql(HIGH_LEVEL, &Irql);
159*c2c66affSColin Finck           Ret = KeInsertQueueDpc(&Dpc, NULL, NULL);
160*c2c66affSColin Finck           ok_bool_true(Ret, "KeInsertQueueDpc returned");
161*c2c66affSColin Finck           Ret = KeRemoveQueueDpc(&Dpc);
162*c2c66affSColin Finck           ok_bool_true(Ret, "KeRemoveQueueDpc returned");
163*c2c66affSColin Finck         KeLowerIrql(Irql);
164*c2c66affSColin Finck     }
165*c2c66affSColin Finck 
166*c2c66affSColin Finck     Status = STATUS_SUCCESS;
167*c2c66affSColin Finck     _SEH2_TRY {
168*c2c66affSColin Finck         KeInitializeDpc(NULL, NULL, NULL);
169*c2c66affSColin Finck     } _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER) {
170*c2c66affSColin Finck         Status = _SEH2_GetExceptionCode();
171*c2c66affSColin Finck     } _SEH2_END;
172*c2c66affSColin Finck     ok_eq_hex(Status, STATUS_ACCESS_VIOLATION);
173*c2c66affSColin Finck 
174*c2c66affSColin Finck     /* These result in IRQL_NOT_LESS_OR_EQUAL on 2k3 -- IRQLs 0x1f and 0xff (?)
175*c2c66affSColin Finck     Ret = KeInsertQueueDpc(NULL, NULL, NULL);
176*c2c66affSColin Finck     Ret = KeRemoveQueueDpc(NULL);*/
177*c2c66affSColin Finck 
178*c2c66affSColin Finck     ok_dpccount();
179*c2c66affSColin Finck     ok_irql(PASSIVE_LEVEL);
180*c2c66affSColin Finck     trace("Final Dpc count: %ld, expected %ld\n", DpcCount, ExpectedDpcCount);
181*c2c66affSColin Finck }
182