388c840c64c7da866ef459e8439056a8d225295b
[reactos.git] / rostests / kmtests / ntos_io / IoDeviceObject_drv.c
1 /*
2 * PROJECT: ReactOS kernel-mode tests
3 * LICENSE: GPLv2+ - See COPYING in the top level directory
4 * PURPOSE: Kernel-Mode Test Suite Driver Object Test Driver
5 * PROGRAMMER: Michael Martin <martinmnet@hotmail.com>
6 * Thomas Faber <thomas.faber@reactos.org>
7 */
8
9 #include <kmt_test.h>
10
11 //#define NDEBUG
12 #include <debug.h>
13
14 typedef enum
15 {
16 DriverEntry,
17 DriverIrp,
18 DriverUnload
19 } DRIVER_STATUS;
20
21 static DRIVER_DISPATCH TestDispatch;
22 static VOID TestDriverObject(IN PDRIVER_OBJECT DriverObject, IN DRIVER_STATUS DriverStatus);
23 static BOOLEAN TestZwLoad(IN PDRIVER_OBJECT DriverObject, IN PCUNICODE_STRING DriverRegistryPath, IN PWCHAR NewDriverRegPath);
24 static BOOLEAN TestZwUnload(IN PDRIVER_OBJECT DriverObject, IN PCUNICODE_STRING DriverRegistryPath, IN PWCHAR NewDriverRegPath);
25 static VOID TestLowerDeviceKernelAPI(IN PDEVICE_OBJECT DeviceObject);
26 static VOID TestDeviceCreated(IN PDEVICE_OBJECT DeviceObject, IN BOOLEAN ExclusiveAccess);
27 static VOID TestDeviceDeletion(IN PDEVICE_OBJECT DeviceObject, IN BOOLEAN Lower, IN BOOLEAN Attached);
28 static VOID TestDeviceCreateDelete(IN PDRIVER_OBJECT DriverObject);
29 static VOID TestAttachDevice(IN PDEVICE_OBJECT DeviceObject, IN PWCHAR NewDriverRegPath);
30 static VOID TestDetachDevice(IN PDEVICE_OBJECT AttachedDevice);
31
32 static PDEVICE_OBJECT MainDeviceObject;
33 static PDEVICE_OBJECT AttachDeviceObject;
34 static PDRIVER_OBJECT ThisDriverObject;
35
36 NTSTATUS
37 TestEntry(
38 IN PDRIVER_OBJECT DriverObject,
39 IN PCUNICODE_STRING RegistryPath,
40 OUT PCWSTR *DeviceName,
41 IN OUT INT *Flags)
42 {
43 NTSTATUS Status = STATUS_SUCCESS;
44 BOOLEAN Ret;
45 INT i;
46
47 PAGED_CODE();
48
49 UNREFERENCED_PARAMETER(DeviceName);
50
51 *Flags = TESTENTRY_NO_CREATE_DEVICE | TESTENTRY_NO_REGISTER_DISPATCH;
52
53 ThisDriverObject = DriverObject;
54
55 TestDriverObject(DriverObject, DriverEntry);
56
57 /* Create and delete device, on return MainDeviceObject has been created */
58 TestDeviceCreateDelete(DriverObject);
59
60 /* Make sure a device object was created */
61 if (!skip(MainDeviceObject != NULL, "Device object creation failed\n"))
62 {
63 PWCHAR LowerDriverRegPath = L"\\Registry\\Machine\\System\\CurrentControlSet\\Services\\Kmtest-IoHelper";
64
65 /* Load driver test and load the lower driver */
66 Ret = TestZwLoad(DriverObject, RegistryPath, LowerDriverRegPath);
67 if (!skip(Ret, "Failed to load helper driver\n"))
68 {
69 TestAttachDevice(MainDeviceObject, L"\\Device\\Kmtest-IoHelper");
70 if (!skip(AttachDeviceObject != NULL, "No attached device object\n"))
71 TestLowerDeviceKernelAPI(MainDeviceObject);
72
73 /* Unload lower driver without detaching from its device */
74 TestZwUnload(DriverObject, RegistryPath, LowerDriverRegPath);
75 TestLowerDeviceKernelAPI(MainDeviceObject);
76 }
77 }
78
79 for (i = 0; i <= IRP_MJ_MAXIMUM_FUNCTION; ++i)
80 DriverObject->MajorFunction[i] = NULL;
81 DriverObject->MajorFunction[IRP_MJ_CREATE] = TestDispatch;
82 DriverObject->MajorFunction[IRP_MJ_CLOSE] = TestDispatch;
83 DriverObject->MajorFunction[IRP_MJ_DEVICE_CONTROL] = TestDispatch;
84
85 return Status;
86 }
87
88 VOID
89 TestUnload(
90 IN PDRIVER_OBJECT DriverObject)
91 {
92 PAGED_CODE();
93
94 if (!skip(AttachDeviceObject != NULL, "no attached device object\n"))
95 {
96 TestDeviceDeletion(MainDeviceObject, FALSE, TRUE);
97 TestDeviceDeletion(AttachDeviceObject, TRUE, FALSE);
98 TestDetachDevice(AttachDeviceObject);
99 }
100
101 TestDeviceDeletion(MainDeviceObject, FALSE, FALSE);
102 TestDriverObject(DriverObject, DriverUnload);
103
104 if (MainDeviceObject)
105 IoDeleteDevice(MainDeviceObject);
106 }
107
108 static
109 NTSTATUS
110 NTAPI
111 TestDispatch(
112 IN PDEVICE_OBJECT DeviceObject,
113 IN PIRP Irp)
114 {
115 NTSTATUS Status = STATUS_SUCCESS;
116 PIO_STACK_LOCATION IoStackLocation;
117
118 PAGED_CODE();
119
120 IoStackLocation = IoGetCurrentIrpStackLocation(Irp);
121
122 DPRINT("TestIrpHandler. Function=%s, DeviceObject=%p, AttachDeviceObject=%p\n",
123 KmtMajorFunctionNames[IoStackLocation->MajorFunction],
124 DeviceObject,
125 AttachDeviceObject);
126
127 if (AttachDeviceObject)
128 {
129 IoSkipCurrentIrpStackLocation(Irp);
130 Status = IoCallDriver(AttachDeviceObject, Irp);
131 return Status;
132 }
133
134 TestDriverObject(DeviceObject->DriverObject, DriverIrp);
135
136 Irp->IoStatus.Status = Status;
137 Irp->IoStatus.Information = 0;
138
139 IoCompleteRequest(Irp, IO_NO_INCREMENT);
140
141 return Status;
142 }
143
144 static
145 VOID
146 TestDriverObject(
147 IN PDRIVER_OBJECT DriverObject,
148 IN DRIVER_STATUS DriverStatus)
149 {
150 BOOLEAN CheckThisDispatchRoutine;
151 PVOID FirstMajorFunc;
152 int i;
153
154 ok(DriverObject->Size == sizeof(DRIVER_OBJECT), "Size does not match, got %x\n",DriverObject->Size);
155 ok(DriverObject->Type == 4, "Type does not match 4. got %d\n", DriverObject->Type);
156
157 if (DriverStatus == DriverEntry)
158 {
159 ok(DriverObject->DeviceObject == NULL, "Expected DeviceObject pointer to be 0, got %p\n",
160 DriverObject->DeviceObject);
161 ok (DriverObject->Flags == DRVO_LEGACY_DRIVER,
162 "Expected Flags to be DRVO_LEGACY_DRIVER, got %lu\n",
163 DriverObject->Flags);
164 }
165 else if (DriverStatus == DriverIrp)
166 {
167 ok(DriverObject->DeviceObject != NULL, "Expected DeviceObject pointer to non null\n");
168 ok (DriverObject->Flags == (DRVO_LEGACY_DRIVER | DRVO_INITIALIZED),
169 "Expected Flags to be DRVO_LEGACY_DRIVER | DRVO_INITIALIZED, got %lu\n",
170 DriverObject->Flags);
171 }
172 else if (DriverStatus == DriverUnload)
173 {
174 ok(DriverObject->DeviceObject != NULL, "Expected DeviceObject pointer to non null\n");
175 ok (DriverObject->Flags == (DRVO_LEGACY_DRIVER | DRVO_INITIALIZED | DRVO_UNLOAD_INVOKED),
176 "Expected Flags to be DRVO_LEGACY_DRIVER | DRVO_INITIALIZED | DRVO_UNLOAD_INVOKED, got %lu\n",
177 DriverObject->Flags);
178 }
179 else
180 ASSERT(FALSE);
181
182 /* Select a routine that was not changed */
183 FirstMajorFunc = DriverObject->MajorFunction[1];
184 ok(FirstMajorFunc != 0, "Expected MajorFunction[1] to be non NULL\n");
185
186 if (!skip(FirstMajorFunc != NULL, "First major function not set!\n"))
187 {
188 for (i = 0; i <= IRP_MJ_MAXIMUM_FUNCTION; i++)
189 {
190 if (DriverStatus > 0) CheckThisDispatchRoutine = (i > 3) && (i != 14);
191 else CheckThisDispatchRoutine = TRUE;
192
193 if (CheckThisDispatchRoutine)
194 {
195 ok(DriverObject->MajorFunction[i] == FirstMajorFunc, "Expected MajorFunction[%d] to match %p\n",
196 i, FirstMajorFunc);
197 }
198 }
199 }
200 }
201
202 static
203 BOOLEAN
204 TestZwLoad(
205 IN PDRIVER_OBJECT DriverObject,
206 IN PCUNICODE_STRING DriverRegistryPath,
207 IN PWCHAR NewDriverRegPath)
208 {
209 UNICODE_STRING RegPath;
210 NTSTATUS Status;
211
212 /* Try to load ourself */
213 Status = ZwLoadDriver((PUNICODE_STRING)DriverRegistryPath);
214 ok (Status == STATUS_IMAGE_ALREADY_LOADED, "Expected NTSTATUS STATUS_IMAGE_ALREADY_LOADED, got 0x%lX\n", Status);
215
216 if (Status != STATUS_IMAGE_ALREADY_LOADED)
217 {
218 DbgPrint("WARNING: Loading this a second time will cause BUGCHECK!\n");
219 }
220
221 /* Try to load with a Registry Path that doesnt exist */
222 RtlInitUnicodeString(&RegPath, L"\\Registry\\Machine\\System\\CurrentControlSet\\Services\\deadbeef");
223 Status = ZwLoadDriver(&RegPath);
224 ok (Status == STATUS_OBJECT_NAME_NOT_FOUND, "Expected NTSTATUS STATUS_OBJECT_NAME_NOT_FOUND, got 0x%lX\n", Status);
225
226 /* Load the driver */
227 RtlInitUnicodeString(&RegPath, NewDriverRegPath);
228 Status = ZwLoadDriver(&RegPath);
229 ok(Status == STATUS_SUCCESS, "Expected STATUS_SUCCESS, got 0x%lX\n", Status);
230
231 return NT_SUCCESS(Status);
232 }
233
234 static
235 BOOLEAN
236 TestZwUnload(
237 IN PDRIVER_OBJECT DriverObject,
238 IN PCUNICODE_STRING DriverRegistryPath,
239 IN PWCHAR NewDriverRegPath)
240 {
241 UNICODE_STRING RegPath;
242 NTSTATUS Status;
243
244 /* Try to unload ourself, which should fail as our Unload routine hasnt been set yet. */
245 Status = ZwUnloadDriver((PUNICODE_STRING)DriverRegistryPath);
246 ok (Status == STATUS_INVALID_DEVICE_REQUEST, "Expected NTSTATUS STATUS_INVALID_DEVICE_REQUEST, got 0x%lX\n", Status);
247
248 /* Try to unload with a Registry Path that doesnt exist */
249 RtlInitUnicodeString(&RegPath, L"\\Registry\\Machine\\System\\CurrentControlSet\\Services\\deadbeef");
250 Status = ZwUnloadDriver(&RegPath);
251 ok (Status == STATUS_OBJECT_NAME_NOT_FOUND, "Expected NTSTATUS STATUS_OBJECT_NAME_NOT_FOUND, got 0x%lX\n", Status);
252
253 /* Unload the driver */
254 RtlInitUnicodeString(&RegPath, NewDriverRegPath);
255 Status = ZwUnloadDriver(&RegPath);
256 ok(Status == STATUS_SUCCESS, "Expected STATUS_SUCCESS, got 0x%lX\n", Status);
257
258 return NT_SUCCESS(Status);
259 }
260
261 static
262 VOID
263 TestLowerDeviceKernelAPI(
264 IN PDEVICE_OBJECT DeviceObject)
265 {
266 PDEVICE_OBJECT RetObject;
267
268 RetObject = IoGetLowerDeviceObject(DeviceObject);
269
270 ok(RetObject == AttachDeviceObject,
271 "Expected an Attached DeviceObject %p, got %p\n", AttachDeviceObject, RetObject);
272
273 if (RetObject)
274 {
275 ObDereferenceObject(RetObject);
276 }
277
278 RetObject = IoGetDeviceAttachmentBaseRef(DeviceObject);
279 ok(RetObject == AttachDeviceObject,
280 "Expected an Attached DeviceObject %p, got %p\n", AttachDeviceObject, RetObject);
281
282 if (RetObject)
283 {
284 ObDereferenceObject(RetObject);
285 }
286
287 }
288
289 static
290 VOID
291 TestDeviceCreated(
292 IN PDEVICE_OBJECT DeviceObject,
293 IN BOOLEAN ExclusiveAccess)
294 {
295 PEXTENDED_DEVOBJ_EXTENSION extdev;
296
297 /* Check the device object members */
298 ok(DeviceObject->Type == 3, "Expected Type = 3, got %x\n", DeviceObject->Type);
299 ok(DeviceObject->Size == 0xb8, "Expected Size = 0xb8, got %x\n", DeviceObject->Size);
300 ok(DeviceObject->ReferenceCount == 0, "Expected ReferenceCount = 0, got %lu\n",
301 DeviceObject->ReferenceCount);
302 ok(DeviceObject->DriverObject == ThisDriverObject,
303 "Expected DriverObject member to match this DriverObject %p, got %p\n",
304 ThisDriverObject, DeviceObject->DriverObject);
305 ok(DeviceObject->NextDevice == NULL, "Expected NextDevice to be NULL, got %p\n", DeviceObject->NextDevice);
306 ok(DeviceObject->AttachedDevice == NULL, "Expected AttachDevice to be NULL, got %p\n", DeviceObject->AttachedDevice);
307 ok(DeviceObject->Characteristics == 0, "Expected Characteristics to be 0\n");
308 if (ExclusiveAccess)
309 {
310 ok((DeviceObject->Flags == (DO_DEVICE_HAS_NAME | DO_DEVICE_INITIALIZING | DO_EXCLUSIVE)),
311 "Expected Flags DO_DEVICE_HAS_NAME | DO_DEVICE_INITIALIZING | DO_EXCLUSIVE, got %lu\n", DeviceObject->Flags);
312 }
313 else
314 {
315 ok((DeviceObject->Flags == (DO_DEVICE_HAS_NAME | DO_DEVICE_INITIALIZING)),
316 "Expected Flags DO_DEVICE_HAS_NAME | DO_DEVICE_INITIALIZING, got %lu\n", DeviceObject->Flags);
317 }
318 ok(DeviceObject->DeviceType == FILE_DEVICE_UNKNOWN,
319 "Expected DeviceType to match creation parameter FILE_DEVICE_UNKNWOWN, got %lu\n",
320 DeviceObject->DeviceType);
321 ok(DeviceObject->ActiveThreadCount == 0, "Expected ActiveThreadCount = 0, got %lu\n", DeviceObject->ActiveThreadCount);
322
323 /* Check the extended extension */
324 extdev = (PEXTENDED_DEVOBJ_EXTENSION)DeviceObject->DeviceObjectExtension;
325 ok(extdev->ExtensionFlags == 0, "Expected Extended ExtensionFlags to be 0, got %lu\n", extdev->ExtensionFlags);
326 ok (extdev->Type == 13, "Expected Type of 13, got %d\n", extdev->Type);
327 ok (extdev->Size == 0, "Expected Size of 0, got %d\n", extdev->Size);
328 ok (extdev->DeviceObject == DeviceObject, "Expected DeviceOject to match newly created device %p, got %p\n",
329 DeviceObject, extdev->DeviceObject);
330 ok(extdev->AttachedTo == NULL, "Expected AttachTo to be NULL, got %p\n", extdev->AttachedTo);
331 ok(extdev->StartIoCount == 0, "Expected StartIoCount = 0, got %lu\n", extdev->StartIoCount);
332 ok(extdev->StartIoKey == 0, "Expected StartIoKey = 0, got %lu\n", extdev->StartIoKey);
333 ok(extdev->StartIoFlags == 0, "Expected StartIoFlags = 0, got %lu\n", extdev->StartIoFlags);
334 }
335
336 static
337 VOID
338 TestDeviceDeletion(
339 IN PDEVICE_OBJECT DeviceObject,
340 IN BOOLEAN Lower,
341 IN BOOLEAN Attached)
342 {
343 PEXTENDED_DEVOBJ_EXTENSION extdev;
344
345 /* Check the device object members */
346 ok(DeviceObject->Type == 3, "Expected Type = 3, got %d\n", DeviceObject->Type);
347 ok(DeviceObject->Size == 0xb8, "Expected Size = 0xb8, got %d\n", DeviceObject->Size);
348 ok(DeviceObject->ReferenceCount == 0, "Expected ReferenceCount = 0, got %lu\n",
349 DeviceObject->ReferenceCount);
350 if (!Lower)
351 {
352 ok(DeviceObject->DriverObject == ThisDriverObject,
353 "Expected DriverObject member to match this DriverObject %p, got %p\n",
354 ThisDriverObject, DeviceObject->DriverObject);
355 }
356 ok(DeviceObject->NextDevice == NULL, "Expected NextDevice to be NULL, got %p\n", DeviceObject->NextDevice);
357
358 if (Lower)
359 {
360 ok(DeviceObject->AttachedDevice == MainDeviceObject,
361 "Expected AttachDevice to be %p, got %p\n", MainDeviceObject, DeviceObject->AttachedDevice);
362 }
363 else
364 {
365 ok(DeviceObject->AttachedDevice == NULL, "Expected AttachDevice to be NULL, got %p\n", DeviceObject->AttachedDevice);
366 }
367
368 ok(DeviceObject->Flags == (DO_DEVICE_HAS_NAME | (Lower ? DO_EXCLUSIVE : 0)),
369 "Expected Flags DO_DEVICE_HAS_NAME, got %lu\n", DeviceObject->Flags);
370 ok(DeviceObject->DeviceType == FILE_DEVICE_UNKNOWN,
371 "Expected DeviceType to match creation parameter FILE_DEVICE_UNKNWOWN, got %lu\n",
372 DeviceObject->DeviceType);
373 ok(DeviceObject->ActiveThreadCount == 0, "Expected ActiveThreadCount = 0, got %lu\n", DeviceObject->ActiveThreadCount);
374
375 /*Check the extended extension */
376 extdev = (PEXTENDED_DEVOBJ_EXTENSION)DeviceObject->DeviceObjectExtension;
377 ok(extdev->ExtensionFlags == DOE_UNLOAD_PENDING,
378 "Expected Extended ExtensionFlags to be DOE_UNLOAD_PENDING, got %lu\n", extdev->ExtensionFlags);
379 ok (extdev->Type == 13, "Expected Type of 13, got %d\n", extdev->Type);
380 ok (extdev->Size == 0, "Expected Size of 0, got %d\n", extdev->Size);
381 ok (extdev->DeviceObject == DeviceObject, "Expected DeviceOject to match newly created device %p, got %p\n",
382 DeviceObject, extdev->DeviceObject);
383 if (Lower || !Attached)
384 {
385 ok(extdev->AttachedTo == NULL, "Expected AttachTo to be NULL, got %p\n", extdev->AttachedTo);
386 }
387 else
388 {
389 ok(extdev->AttachedTo == AttachDeviceObject, "Expected AttachTo to %p, got %p\n", AttachDeviceObject, extdev->AttachedTo);
390 }
391 ok(extdev->StartIoCount == 0, "Expected StartIoCount = 0, got %lu\n", extdev->StartIoCount);
392 ok(extdev->StartIoKey == 0, "Expected StartIoKey = 0, got %lu\n", extdev->StartIoKey);
393 ok(extdev->StartIoFlags == 0, "Expected StartIoFlags = 0, got %lu\n", extdev->StartIoFlags);
394 }
395
396 static
397 VOID
398 TestDeviceCreateDelete(
399 IN PDRIVER_OBJECT DriverObject)
400 {
401 NTSTATUS Status;
402 UNICODE_STRING DeviceString;
403 PDEVICE_OBJECT DeviceObject;
404
405 /* Create using wrong directory */
406 RtlInitUnicodeString(&DeviceString, L"\\Device1\\Kmtest-IoDeviceObject");
407 Status = IoCreateDevice(DriverObject,
408 0,
409 &DeviceString,
410 FILE_DEVICE_UNKNOWN,
411 0,
412 FALSE,
413 &DeviceObject);
414 ok(Status == STATUS_OBJECT_PATH_NOT_FOUND, "Expected STATUS_OBJECT_PATH_NOT_FOUND, got 0x%lX\n", Status);
415
416 /* Create using correct params with exclusice access */
417 RtlInitUnicodeString(&DeviceString, L"\\Device\\Kmtest-IoDeviceObject");
418 Status = IoCreateDevice(DriverObject,
419 0,
420 &DeviceString,
421 FILE_DEVICE_UNKNOWN,
422 0,
423 TRUE,
424 &DeviceObject);
425 ok(Status == STATUS_SUCCESS, "Expected STATUS_SUCCESS, got 0x%lX\n", Status);
426
427 TestDeviceCreated(DeviceObject, TRUE);
428
429 /* Delete the device */
430 if (NT_SUCCESS(Status))
431 {
432 IoDeleteDevice(DeviceObject);
433 ok(DriverObject->DeviceObject == 0, "Expected DriverObject->DeviceObject to be NULL, got %p\n",
434 DriverObject->DeviceObject);
435 }
436
437 /* Create using correct params without exclusice access */
438 Status = IoCreateDevice(DriverObject,
439 0,
440 &DeviceString,
441 FILE_DEVICE_UNKNOWN,
442 0,
443 FALSE,
444 &DeviceObject);
445 ok(Status == STATUS_SUCCESS, "Expected STATUS_SUCCESS, got 0x%lX\n", Status);
446
447 TestDeviceCreated(DeviceObject, FALSE);
448
449 /* Delete the device */
450 if (NT_SUCCESS(Status))
451 {
452 IoDeleteDevice(DeviceObject);
453 ok(DriverObject->DeviceObject == 0, "Expected DriverObject->DeviceObject to be NULL, got %p\n",
454 DriverObject->DeviceObject);
455 }
456
457 /* Recreate device */
458 Status = IoCreateDevice(DriverObject,
459 0,
460 &DeviceString,
461 FILE_DEVICE_UNKNOWN,
462 0,
463 FALSE,
464 &DeviceObject);
465 ok(Status == STATUS_SUCCESS, "Expected STATUS_SUCCESS, got 0x%lX\n", Status);
466
467 if (NT_SUCCESS(Status))
468 MainDeviceObject = DeviceObject;
469 }
470
471 static
472 VOID
473 TestAttachDevice(
474 IN PDEVICE_OBJECT DeviceObject,
475 IN PWCHAR NewDriverRegPath)
476 {
477 NTSTATUS Status;
478 UNICODE_STRING LowerDeviceName;
479
480 RtlInitUnicodeString(&LowerDeviceName, NewDriverRegPath);
481 Status = IoAttachDevice(DeviceObject, &LowerDeviceName, &AttachDeviceObject);
482 ok_eq_hex(Status, STATUS_SUCCESS);
483
484 /* TODO: Add more tests */
485 }
486
487 static
488 VOID
489 TestDetachDevice(
490 IN PDEVICE_OBJECT AttachedDevice)
491 {
492 IoDetachDevice(AttachedDevice);
493
494 /* TODO: Add more tests */
495 }