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