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