[KMTEST]
[reactos.git] / rostests / drivers / kmtest / kmtest.c
1 /*
2 * Kernel Mode regression Test
3 * Driver Core
4 *
5 * Copyright 2004 Filip Navara <xnavara@volny.cz>
6 *
7 * This library is free software; you can redistribute it and/or
8 * modify it under the terms of the GNU Library General Public
9 * License as published by the Free Software Foundation; either
10 * version 2 of the License, or (at your option) any later version.
11 *
12 * This library is distributed in the hope that it will be useful,
13 * but WITHOUT ANY WARRANTY; without even the implied warranty of
14 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
15 * Library General Public License for more details.
16 *
17 * You should have received a copy of the GNU Library General Public
18 * License along with this library; see the file COPYING.LIB.
19 * If not, write to the Free Software Foundation,
20 * 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
21 */
22
23 /* INCLUDES *******************************************************************/
24
25 #include <ddk/ntddk.h>
26 #include "kmtest.h"
27
28 #define NDEBUG
29 #include <debug.h>
30
31 LONG successes;
32 LONG failures;
33 LONG skipped;
34 tls_data glob_data;
35
36 /* PRIVATE FUNCTIONS ***********************************************************/
37 VOID
38 StartTest()
39 {
40 successes = 0;
41 failures = 0;
42 skipped = 0;
43 }
44
45 VOID
46 FinishTest(HANDLE KeyHandle, LPWSTR TestName)
47 {
48 WCHAR KeyName[100];
49 LONG total = successes + failures;
50 UNICODE_STRING KeyNameU;
51
52 wcscpy(KeyName, TestName);
53 wcscat(KeyName, L"SuccessCount");
54 RtlInitUnicodeString(&KeyNameU, KeyName);
55
56 ZwSetValueKey(KeyHandle,
57 &KeyNameU,
58 0,
59 REG_DWORD,
60 &successes,
61 sizeof(ULONG));
62
63 wcscpy(KeyName, TestName);
64 wcscat(KeyName, L"FailureCount");
65 RtlInitUnicodeString(&KeyNameU, KeyName);
66
67 ZwSetValueKey(KeyHandle,
68 &KeyNameU,
69 0,
70 REG_DWORD,
71 &failures,
72 sizeof(ULONG));
73
74 wcscpy(KeyName, TestName);
75 wcscat(KeyName, L"TotalCount");
76 RtlInitUnicodeString(&KeyNameU, KeyName);
77
78 ZwSetValueKey(KeyHandle,
79 &KeyNameU,
80 0,
81 REG_DWORD,
82 &total,
83 sizeof(ULONG));
84
85 wcscpy(KeyName, TestName);
86 wcscat(KeyName, L"SkipCount");
87 RtlInitUnicodeString(&KeyNameU, KeyName);
88
89 ZwSetValueKey(KeyHandle,
90 &KeyNameU,
91 0,
92 REG_DWORD,
93 &skipped,
94 sizeof(ULONG));
95
96 DbgPrint("%S: %d test executed (0 marked as todo, %d failures), %d skipped.\n", TestName, total, failures, skipped);
97 }
98
99 void kmtest_set_location(const char* file, int line)
100 {
101 glob_data.current_file=strrchr(file,'/');
102 if (glob_data.current_file==NULL)
103 glob_data.current_file=strrchr(file,'\\');
104 if (glob_data.current_file==NULL)
105 glob_data.current_file=file;
106 else
107 glob_data.current_file++;
108 glob_data.current_line=line;
109 }
110
111 /*
112 * Checks condition.
113 * Parameters:
114 * - condition - condition to check;
115 * - msg test description;
116 * - file - test application source code file name of the check
117 * - line - test application source code file line number of the check
118 * Return:
119 * 0 if condition does not have the expected value, 1 otherwise
120 */
121 int kmtest_ok(int condition, const char *msg, ... )
122 {
123 va_list valist;
124
125 if (!condition)
126 {
127 if (msg[0])
128 {
129 char string[1024];
130 va_start(valist, msg);
131 vsprintf(string, msg, valist);
132 DbgPrint( "%s:%d: Test failed: %s\n",
133 glob_data.current_file, glob_data.current_line, string );
134 va_end(valist);
135 }
136 else
137 {
138 DbgPrint( "%s:%d: Test failed\n",
139 glob_data.current_file, glob_data.current_line );
140 }
141 InterlockedIncrement(&failures);
142 return 0;
143 }
144 else
145 {/*
146 if (report_success)
147 fprintf( stdout, "%s:%d: Test succeeded\n",
148 glob_data.current_file, glob_data.current_line);*/
149 InterlockedIncrement(&successes);
150 }
151 return 1;
152 }
153
154 /* PUBLIC FUNCTIONS ***********************************************************/
155
156 PWCHAR CreateLowerDeviceRegistryKey(PUNICODE_STRING RegistryPath, PWCHAR NewDriver);
157
158 /*
159 * Test Declarations
160 */
161 VOID RegisterDI_Test(HANDLE KeyHandle);
162 VOID NtoskrnlIoMdlTest(HANDLE KeyHandle);
163 VOID NtoskrnlIoIrpTest(HANDLE KeyHandle);
164 VOID NtoskrnlObTest(HANDLE KeyHandle);
165 VOID ExTimerTest(HANDLE KeyHandle);
166 VOID PoolsTest(HANDLE KeyHandle);
167 VOID PoolsCorruption(HANDLE KeyHandle);
168 VOID KeStallTest(HANDLE KeyHandle);
169 VOID DriverObjectTest(PDRIVER_OBJECT, int);
170 VOID DeviceCreateDeleteTest(PDRIVER_OBJECT);
171 VOID DeviceObjectTest(PDEVICE_OBJECT);
172 BOOLEAN ZwLoadTest(PDRIVER_OBJECT, PUNICODE_STRING, PWCHAR);
173 BOOLEAN ZwUnloadTest(PDRIVER_OBJECT, PUNICODE_STRING, PWCHAR);
174 BOOLEAN DetachDeviceTest(PDEVICE_OBJECT);
175 BOOLEAN AttachDeviceTest(PDEVICE_OBJECT, PWCHAR);
176 VOID LowerDeviceKernelAPITest(PDEVICE_OBJECT, BOOLEAN);
177
178 typedef enum {
179 TestStageExTimer = 0,
180 TestStageIoMdl,
181 TestStageIoDi,
182 TestStageIoIrp,
183 TestStageMmPoolTest,
184 TestStageMmPoolCorruption,
185 TestStageOb,
186 TestStageKeStall,
187 TestStageDrv,
188 TestStageMax
189 } TEST_STAGE;
190
191 /*
192 * KmtestDispatch
193 */
194 NTSTATUS
195 NTAPI
196 KmtestDispatch(IN PDEVICE_OBJECT DeviceObject, IN PIRP Irp)
197
198 {
199 NTSTATUS Status = STATUS_SUCCESS;
200
201 if (AttachDeviceObject)
202 {
203 IoSkipCurrentIrpStackLocation(Irp);
204 Status = IoCallDriver(AttachDeviceObject, Irp);
205 return Status;
206 }
207
208 Irp->IoStatus.Status = Status;
209 Irp->IoStatus.Information = 0;
210 IoCompleteRequest(Irp, IO_NO_INCREMENT);
211 return Status;
212 }
213
214 /*
215 * KmtestCreateClose
216 */
217 NTSTATUS
218 NTAPI
219 KmtestCreateClose(IN PDEVICE_OBJECT DeviceObject, IN PIRP Irp)
220 {
221 NTSTATUS Status = STATUS_SUCCESS;
222
223 if (AttachDeviceObject)
224 {
225 IoSkipCurrentIrpStackLocation(Irp);
226 Status = IoCallDriver(AttachDeviceObject, Irp);
227 return Status;
228 }
229
230 /* Do DriverObject Test with Driver Initialized */
231 DriverObjectTest(DeviceObject->DriverObject, 1);
232
233 Irp->IoStatus.Status = STATUS_SUCCESS;
234 Irp->IoStatus.Information=0;
235
236 IoCompleteRequest(Irp, IO_NO_INCREMENT);
237 return STATUS_SUCCESS;
238 }
239
240 /*
241 * KmtestUnload
242 */
243 VOID
244 NTAPI
245 KmtestUnload(IN PDRIVER_OBJECT DriverObject)
246 {
247 UNICODE_STRING DosDeviceString;
248
249 if(AttachDeviceObject)
250 {
251 IoDetachDevice(AttachDeviceObject);
252 }
253
254 /* Do DriverObject Test for Unload */
255 DriverObjectTest(DriverObject, 2);
256
257 if (MainDeviceObject)
258 {
259 RtlInitUnicodeString(&DosDeviceString, L"\\DosDevices\\Kmtest");
260 IoDeleteSymbolicLink(&DosDeviceString);
261
262 IoDeleteDevice(MainDeviceObject);
263 }
264 }
265
266 static
267 PKEY_VALUE_PARTIAL_INFORMATION
268 NTAPI
269 ReadRegistryValue(HANDLE KeyHandle, PWCHAR ValueName)
270 {
271 NTSTATUS Status;
272 PKEY_VALUE_PARTIAL_INFORMATION InformationBuffer = NULL;
273 ULONG AllocatedLength = 0, RequiredLength = 0;
274 UNICODE_STRING ValueNameU;
275
276 RtlInitUnicodeString(&ValueNameU, ValueName);
277
278 Status = ZwQueryValueKey(KeyHandle,
279 &ValueNameU,
280 KeyValuePartialInformation,
281 NULL,
282 0,
283 &RequiredLength);
284 if (Status == STATUS_BUFFER_TOO_SMALL || Status == STATUS_BUFFER_OVERFLOW)
285 {
286 InformationBuffer = ExAllocatePool(PagedPool, RequiredLength);
287 AllocatedLength = RequiredLength;
288 if (!InformationBuffer) return NULL;
289
290 Status = ZwQueryValueKey(KeyHandle,
291 &ValueNameU,
292 KeyValuePartialInformation,
293 InformationBuffer,
294 AllocatedLength,
295 &RequiredLength);
296 }
297
298 if (!NT_SUCCESS(Status))
299 {
300 DPRINT1("Failed to read %S (0x%x)\n", ValueName, Status);
301 if (InformationBuffer != NULL)
302 ExFreePool(InformationBuffer);
303 return NULL;
304 }
305
306 return InformationBuffer;
307 }
308
309 static
310 VOID
311 RunKernelModeTest(PDRIVER_OBJECT DriverObject,
312 PUNICODE_STRING RegistryPath,
313 HANDLE KeyHandle,
314 TEST_STAGE Stage)
315 {
316 UNICODE_STRING KeyName = RTL_CONSTANT_STRING(L"CurrentStage");
317 PWCHAR LowerDriverRegPath;
318
319 DPRINT1("Running stage %d test...\n", Stage);
320
321 ZwSetValueKey(KeyHandle,
322 &KeyName,
323 0,
324 REG_DWORD,
325 &Stage,
326 sizeof(ULONG));
327
328 switch (Stage)
329 {
330 case TestStageExTimer:
331 ExTimerTest(KeyHandle);
332 break;
333
334 case TestStageIoMdl:
335 NtoskrnlIoMdlTest(KeyHandle);
336 break;
337
338 case TestStageIoDi:
339 RegisterDI_Test(KeyHandle);
340 break;
341
342 case TestStageIoIrp:
343 NtoskrnlIoIrpTest(KeyHandle);
344 break;
345
346 case TestStageMmPoolTest:
347 PoolsTest(KeyHandle);
348 break;
349
350 case TestStageMmPoolCorruption:
351 PoolsCorruption(KeyHandle);
352 break;
353
354 case TestStageOb:
355 NtoskrnlObTest(KeyHandle);
356 break;
357
358 case TestStageKeStall:
359 KeStallTest(KeyHandle);
360 break;
361
362 case TestStageDrv:
363 /* Start the tests for the driver routines */
364 StartTest();
365
366 /* Do DriverObject Test for Driver Entry */
367 DriverObjectTest(DriverObject, 0);
368
369 /* Create and delete device, on return MainDeviceObject has been created */
370 DeviceCreateDeleteTest(DriverObject);
371
372 /* Make sure a device object was created */
373 if (MainDeviceObject)
374 {
375 LowerDriverRegPath = CreateLowerDeviceRegistryKey(RegistryPath, L"kmtestassist");
376
377 if (LowerDriverRegPath)
378 {
379 /* Load driver test and load the lower driver */
380 if (ZwLoadTest(DriverObject, RegistryPath, LowerDriverRegPath))
381 {
382 AttachDeviceTest(MainDeviceObject, L"kmtestassists");
383 if (AttachDeviceObject)
384 {
385 LowerDeviceKernelAPITest(MainDeviceObject, FALSE);
386 }
387
388 /* Unload lower driver without detaching from its device */
389 ZwUnloadTest(DriverObject, RegistryPath, LowerDriverRegPath);
390 LowerDeviceKernelAPITest(MainDeviceObject, TRUE);
391 }
392 else
393 {
394 DbgPrint("Failed to load kmtestassist driver\n");
395 }
396 }
397 }
398
399 FinishTest(KeyHandle, L"DriverTest");
400 break;
401
402 default:
403 ASSERT(FALSE);
404 break;
405 }
406 }
407
408 /*
409 * DriverEntry
410 */
411 NTSTATUS
412 NTAPI
413 DriverEntry(PDRIVER_OBJECT DriverObject,
414 PUNICODE_STRING RegistryPath)
415 {
416 int i;
417 NTSTATUS Status;
418 OBJECT_ATTRIBUTES ObjectAttributes;
419 UNICODE_STRING ParameterKeyName = RTL_CONSTANT_STRING(L"Parameters");
420 PKEY_VALUE_PARTIAL_INFORMATION KeyInfo;
421 PULONG KeyValue;
422 TEST_STAGE CurrentStage;
423 HANDLE DriverKeyHandle, ParameterKeyHandle;
424
425 DbgPrint("\n===============================================\n");
426 DbgPrint("Kernel Mode Regression Driver Test starting...\n");
427 DbgPrint("===============================================\n");
428
429 InitializeObjectAttributes(&ObjectAttributes,
430 RegistryPath,
431 OBJ_CASE_INSENSITIVE,
432 0,
433 NULL);
434
435 Status = ZwOpenKey(&DriverKeyHandle,
436 KEY_CREATE_SUB_KEY | KEY_ENUMERATE_SUB_KEYS,
437 &ObjectAttributes);
438 if (!NT_SUCCESS(Status))
439 {
440 DPRINT1("Failed to open %wZ\n", RegistryPath);
441 return Status;
442 }
443
444 InitializeObjectAttributes(&ObjectAttributes,
445 &ParameterKeyName,
446 OBJ_OPENIF | OBJ_CASE_INSENSITIVE,
447 DriverKeyHandle,
448 NULL);
449 Status = ZwCreateKey(&ParameterKeyHandle,
450 KEY_SET_VALUE | KEY_QUERY_VALUE,
451 &ObjectAttributes,
452 0,
453 NULL,
454 REG_OPTION_NON_VOLATILE,
455 NULL);
456 ZwClose(DriverKeyHandle);
457 if (!NT_SUCCESS(Status))
458 {
459 DPRINT1("Failed to create %wZ\\%wZ\n", RegistryPath, &ParameterKeyName);
460 return Status;
461 }
462
463 KeyInfo = ReadRegistryValue(ParameterKeyHandle, L"CurrentStage");
464 if (KeyInfo)
465 {
466 if (KeyInfo->DataLength != sizeof(ULONG))
467 {
468 DPRINT1("Invalid data length for CurrentStage: %d\n", KeyInfo->DataLength);
469 ExFreePool(KeyInfo);
470 return STATUS_UNSUCCESSFUL;
471 }
472
473 KeyValue = (PULONG)KeyInfo->Data;
474
475 if ((*KeyValue) + 1 < TestStageMax)
476 {
477 DPRINT1("Resuming testing after a crash at stage %d\n", (*KeyValue));
478
479 CurrentStage = (TEST_STAGE)((*KeyValue) + 1);
480 }
481 else
482 {
483 DPRINT1("Testing was completed on a previous boot\n");
484 ExFreePool(KeyInfo);
485 return STATUS_UNSUCCESSFUL;
486 }
487
488 ExFreePool(KeyInfo);
489 }
490 else
491 {
492 DPRINT1("Starting a fresh test\n");
493 CurrentStage = (TEST_STAGE)0;
494 }
495
496 /* Run the tests */
497 while (CurrentStage < TestStageMax)
498 {
499 RunKernelModeTest(DriverObject,
500 RegistryPath,
501 ParameterKeyHandle,
502 CurrentStage);
503 CurrentStage++;
504 }
505
506 DPRINT1("Testing is complete!\n");
507 ZwClose(ParameterKeyHandle);
508
509 /* Set all MajorFunctions to NULL to verify that kernel fixes them */
510 for (i = 1; i <= IRP_MJ_MAXIMUM_FUNCTION; i++)
511 DriverObject->MajorFunction[i] = NULL;
512
513 /* Set necessary routines */
514 DriverObject->DriverUnload = KmtestUnload;
515 DriverObject->MajorFunction[IRP_MJ_DEVICE_CONTROL] = KmtestDispatch;
516 DriverObject->MajorFunction[IRP_MJ_CREATE] = KmtestCreateClose;
517 DriverObject->MajorFunction[IRP_MJ_CLOSE] = KmtestCreateClose;
518
519 return STATUS_SUCCESS;
520 }