2 * PROJECT: ReactOS kernel-mode tests
3 * LICENSE: GPLv2+ - See COPYING in the top level directory
4 * PURPOSE: Kernel-Mode Test Suite Example Test Driver
5 * PROGRAMMER: Thomas Faber <thfabba@gmx.de>
10 #include <ndk/ketypes.h>
12 #define KMT_DEFINE_TEST_FUNCTIONS
18 #include <kmt_public.h>
24 PDEVICE_OBJECT DeviceObject
;
25 PKMT_IRP_HANDLER IrpHandler
;
26 } KMT_IRP_HANDLER_ENTRY
, *PKMT_IRP_HANDLER_ENTRY
;
31 PDEVICE_OBJECT DeviceObject
;
32 PKMT_MESSAGE_HANDLER MessageHandler
;
33 } KMT_MESSAGE_HANDLER_ENTRY
, *PKMT_MESSAGE_HANDLER_ENTRY
;
36 DRIVER_INITIALIZE DriverEntry
;
37 static DRIVER_UNLOAD DriverUnload
;
38 static DRIVER_DISPATCH DriverDispatch
;
39 static KMT_IRP_HANDLER DeviceControlHandler
;
42 static PDEVICE_OBJECT TestDeviceObject
;
43 static PDEVICE_OBJECT KmtestDeviceObject
;
45 #define KMT_MAX_IRP_HANDLERS 256
46 static KMT_IRP_HANDLER_ENTRY IrpHandlers
[KMT_MAX_IRP_HANDLERS
] = { { 0 } };
47 #define KMT_MAX_MESSAGE_HANDLERS 256
48 static KMT_MESSAGE_HANDLER_ENTRY MessageHandlers
[KMT_MAX_MESSAGE_HANDLERS
] = { { 0 } };
58 * Driver Registry Path
65 IN PDRIVER_OBJECT DriverObject
,
66 IN PUNICODE_STRING RegistryPath
)
68 NTSTATUS Status
= STATUS_SUCCESS
;
69 WCHAR DeviceNameBuffer
[128] = L
"\\Device\\Kmtest-";
70 UNICODE_STRING KmtestDeviceName
;
71 PFILE_OBJECT KmtestFileObject
;
72 PKMT_DEVICE_EXTENSION KmtestDeviceExtension
;
73 UNICODE_STRING DeviceName
;
74 PCWSTR DeviceNameSuffix
;
81 DPRINT("DriverEntry\n");
83 Prcb
= KeGetCurrentPrcb();
84 KmtIsCheckedBuild
= (Prcb
->BuildType
& PRCB_BUILD_DEBUG
) != 0;
85 KmtIsMultiProcessorBuild
= (Prcb
->BuildType
& PRCB_BUILD_UNIPROCESSOR
) == 0;
87 /* get the Kmtest device, so that we get a ResultBuffer pointer */
88 RtlInitUnicodeString(&KmtestDeviceName
, KMTEST_DEVICE_DRIVER_PATH
);
89 Status
= IoGetDeviceObjectPointer(&KmtestDeviceName
, FILE_ALL_ACCESS
, &KmtestFileObject
, &KmtestDeviceObject
);
91 if (!NT_SUCCESS(Status
))
93 DPRINT1("Failed to get Kmtest device object pointer\n");
97 Status
= ObReferenceObjectByPointer(KmtestDeviceObject
, FILE_ALL_ACCESS
, NULL
, KernelMode
);
99 if (!NT_SUCCESS(Status
))
101 DPRINT1("Failed to reference Kmtest device object\n");
105 ObDereferenceObject(KmtestFileObject
);
106 KmtestFileObject
= NULL
;
107 KmtestDeviceExtension
= KmtestDeviceObject
->DeviceExtension
;
108 ResultBuffer
= KmtestDeviceExtension
->ResultBuffer
;
109 DPRINT("KmtestDeviceObject: %p\n", (PVOID
)KmtestDeviceObject
);
110 DPRINT("KmtestDeviceExtension: %p\n", (PVOID
)KmtestDeviceExtension
);
111 DPRINT("Setting ResultBuffer: %p\n", (PVOID
)ResultBuffer
);
114 RtlInitUnicodeString(&DeviceName
, DeviceNameBuffer
);
115 DeviceName
.MaximumLength
= sizeof DeviceNameBuffer
;
116 TestEntry(DriverObject
, RegistryPath
, &DeviceNameSuffix
, &Flags
);
118 /* create test device */
119 if (!(Flags
& TESTENTRY_NO_CREATE_DEVICE
))
121 RtlAppendUnicodeToString(&DeviceName
, DeviceNameSuffix
);
122 Status
= IoCreateDevice(DriverObject
, 0, &DeviceName
,
124 FILE_DEVICE_SECURE_OPEN
| FILE_READ_ONLY_DEVICE
,
125 TRUE
, &TestDeviceObject
);
127 if (!NT_SUCCESS(Status
))
129 DPRINT1("Could not create device object %wZ\n", &DeviceName
);
133 DPRINT("DriverEntry. Created DeviceObject %p\n",
137 /* initialize dispatch functions */
138 if (!(Flags
& TESTENTRY_NO_REGISTER_UNLOAD
))
139 DriverObject
->DriverUnload
= DriverUnload
;
140 if (!(Flags
& TESTENTRY_NO_REGISTER_DISPATCH
))
141 for (i
= 0; i
<= IRP_MJ_MAXIMUM_FUNCTION
; ++i
)
142 DriverObject
->MajorFunction
[i
] = DriverDispatch
;
145 if (TestDeviceObject
&& !NT_SUCCESS(Status
))
147 IoDeleteDevice(TestDeviceObject
);
148 TestDeviceObject
= NULL
;
151 if (KmtestDeviceObject
&& !NT_SUCCESS(Status
))
153 ObDereferenceObject(KmtestDeviceObject
);
154 KmtestDeviceObject
= NULL
;
155 if (KmtestFileObject
)
156 ObDereferenceObject(KmtestFileObject
);
165 * Driver cleanup funtion.
167 * @param DriverObject
174 IN PDRIVER_OBJECT DriverObject
)
178 UNREFERENCED_PARAMETER(DriverObject
);
180 DPRINT("DriverUnload\n");
182 TestUnload(DriverObject
);
184 if (TestDeviceObject
)
185 IoDeleteDevice(TestDeviceObject
);
187 if (KmtestDeviceObject
)
188 ObDereferenceObject(KmtestDeviceObject
);
192 * @name KmtRegisterIrpHandler
194 * Register a handler with the IRP Dispatcher.
195 * If multiple registered handlers match an IRP, it is unspecified which of
196 * them is called on IRP reception
198 * @param MajorFunction
199 * IRP major function code to be handled
200 * @param DeviceObject
201 * Device Object to handle IRPs for.
202 * Can be NULL to indicate any device object
204 * Handler function to register.
209 KmtRegisterIrpHandler(
210 IN UCHAR MajorFunction
,
211 IN PDEVICE_OBJECT DeviceObject OPTIONAL
,
212 IN PKMT_IRP_HANDLER IrpHandler
)
214 NTSTATUS Status
= STATUS_SUCCESS
;
217 if (MajorFunction
> IRP_MJ_MAXIMUM_FUNCTION
)
219 Status
= STATUS_INVALID_PARAMETER_1
;
223 if (IrpHandler
== NULL
)
225 Status
= STATUS_INVALID_PARAMETER_3
;
229 for (i
= 0; i
< sizeof IrpHandlers
/ sizeof IrpHandlers
[0]; ++i
)
230 if (IrpHandlers
[i
].IrpHandler
== NULL
)
232 IrpHandlers
[i
].MajorFunction
= MajorFunction
;
233 IrpHandlers
[i
].DeviceObject
= DeviceObject
;
234 IrpHandlers
[i
].IrpHandler
= IrpHandler
;
238 Status
= STATUS_ALLOTTED_SPACE_EXCEEDED
;
245 * @name KmtUnregisterIrpHandler
247 * Unregister a handler with the IRP Dispatcher.
248 * Parameters must be specified exactly as in the call to
249 * KmtRegisterIrpHandler. Only the first matching entry will be removed
252 * @param MajorFunction
253 * IRP major function code of the handler to be removed
254 * @param DeviceObject
255 * Device Object to of the handler to be removed
257 * Handler function of the handler to be removed
262 KmtUnregisterIrpHandler(
263 IN UCHAR MajorFunction
,
264 IN PDEVICE_OBJECT DeviceObject OPTIONAL
,
265 IN PKMT_IRP_HANDLER IrpHandler
)
267 NTSTATUS Status
= STATUS_SUCCESS
;
270 for (i
= 0; i
< sizeof IrpHandlers
/ sizeof IrpHandlers
[0]; ++i
)
271 if (IrpHandlers
[i
].MajorFunction
== MajorFunction
&&
272 IrpHandlers
[i
].DeviceObject
== DeviceObject
&&
273 IrpHandlers
[i
].IrpHandler
== IrpHandler
)
275 IrpHandlers
[i
].IrpHandler
= NULL
;
279 Status
= STATUS_NOT_FOUND
;
286 * @name DriverDispatch
288 * Driver Dispatch function
290 * @param DeviceObject
301 IN PDEVICE_OBJECT DeviceObject
,
304 NTSTATUS Status
= STATUS_SUCCESS
;
305 PIO_STACK_LOCATION IoStackLocation
;
310 IoStackLocation
= IoGetCurrentIrpStackLocation(Irp
);
312 DPRINT("DriverDispatch: Function=%s, Device=%p\n",
313 KmtMajorFunctionNames
[IoStackLocation
->MajorFunction
],
316 for (i
= 0; i
< sizeof IrpHandlers
/ sizeof IrpHandlers
[0]; ++i
)
318 if (IrpHandlers
[i
].MajorFunction
== IoStackLocation
->MajorFunction
&&
319 (IrpHandlers
[i
].DeviceObject
== NULL
|| IrpHandlers
[i
].DeviceObject
== DeviceObject
) &&
320 IrpHandlers
[i
].IrpHandler
!= NULL
)
321 return IrpHandlers
[i
].IrpHandler(DeviceObject
, Irp
, IoStackLocation
);
324 /* default handler for DeviceControl */
325 if (IoStackLocation
->MajorFunction
== IRP_MJ_DEVICE_CONTROL
||
326 IoStackLocation
->MajorFunction
== IRP_MJ_INTERNAL_DEVICE_CONTROL
)
327 return DeviceControlHandler(DeviceObject
, Irp
, IoStackLocation
);
329 /* default handler */
330 Irp
->IoStatus
.Status
= Status
;
331 Irp
->IoStatus
.Information
= 0;
333 IoCompleteRequest(Irp
, IO_NO_INCREMENT
);
339 * @name KmtRegisterMessageHandler
341 * Register a handler with the DeviceControl Dispatcher.
342 * If multiple registered handlers match a message, it is unspecified which of
343 * them is called on message reception.
344 * NOTE: message handlers registered with this function will not be called
345 * if a custom IRP handler matching the corresponding IRP is installed!
348 * Control code to be handled, as passed by the application.
349 * Can be 0 to indicate any control code
350 * @param DeviceObject
351 * Device Object to handle IRPs for.
352 * Can be NULL to indicate any device object
353 * @param MessageHandler
354 * Handler function to register.
359 KmtRegisterMessageHandler(
360 IN ULONG ControlCode OPTIONAL
,
361 IN PDEVICE_OBJECT DeviceObject OPTIONAL
,
362 IN PKMT_MESSAGE_HANDLER MessageHandler
)
364 NTSTATUS Status
= STATUS_SUCCESS
;
367 if (ControlCode
>= 0x400)
369 Status
= STATUS_INVALID_PARAMETER_1
;
373 if (MessageHandler
== NULL
)
375 Status
= STATUS_INVALID_PARAMETER_2
;
379 for (i
= 0; i
< sizeof MessageHandlers
/ sizeof MessageHandlers
[0]; ++i
)
380 if (MessageHandlers
[i
].MessageHandler
== NULL
)
382 MessageHandlers
[i
].ControlCode
= ControlCode
;
383 MessageHandlers
[i
].DeviceObject
= DeviceObject
;
384 MessageHandlers
[i
].MessageHandler
= MessageHandler
;
388 Status
= STATUS_ALLOTTED_SPACE_EXCEEDED
;
395 * @name KmtUnregisterMessageHandler
397 * Unregister a handler with the DeviceControl Dispatcher.
398 * Parameters must be specified exactly as in the call to
399 * KmtRegisterMessageHandler. Only the first matching entry will be removed
403 * Control code of the handler to be removed
404 * @param DeviceObject
405 * Device Object to of the handler to be removed
406 * @param MessageHandler
407 * Handler function of the handler to be removed
412 KmtUnregisterMessageHandler(
413 IN ULONG ControlCode OPTIONAL
,
414 IN PDEVICE_OBJECT DeviceObject OPTIONAL
,
415 IN PKMT_MESSAGE_HANDLER MessageHandler
)
417 NTSTATUS Status
= STATUS_SUCCESS
;
420 for (i
= 0; i
< sizeof MessageHandlers
/ sizeof MessageHandlers
[0]; ++i
)
421 if (MessageHandlers
[i
].ControlCode
== ControlCode
&&
422 MessageHandlers
[i
].DeviceObject
== DeviceObject
&&
423 MessageHandlers
[i
].MessageHandler
== MessageHandler
)
425 MessageHandlers
[i
].MessageHandler
= NULL
;
429 Status
= STATUS_NOT_FOUND
;
436 * @name DeviceControlHandler
438 * Default IRP_MJ_DEVICE_CONTROL/IRP_MJ_INTERNAL_DEVICE_CONTROL handler
440 * @param DeviceObject
442 * This is guaranteed not to have been touched by the dispatch function
443 * before the call to the IRP handler
446 * This is guaranteed not to have been touched by the dispatch function
447 * before the call to the IRP handler, except for passing it to
448 * IoGetCurrentStackLocation
449 * @param IoStackLocation
451 * This is guaranteed not to have been touched by the dispatch function
452 * before the call to the IRP handler
458 DeviceControlHandler(
459 IN PDEVICE_OBJECT DeviceObject
,
461 IN PIO_STACK_LOCATION IoStackLocation
)
463 NTSTATUS Status
= STATUS_SUCCESS
;
464 ULONG ControlCode
= (IoStackLocation
->Parameters
.DeviceIoControl
.IoControlCode
& 0x00000FFC) >> 2;
465 ULONG OutLength
= IoStackLocation
->Parameters
.DeviceIoControl
.OutputBufferLength
;
468 for (i
= 0; i
< sizeof MessageHandlers
/ sizeof MessageHandlers
[0]; ++i
)
470 if ((MessageHandlers
[i
].ControlCode
== 0 ||
471 MessageHandlers
[i
].ControlCode
== ControlCode
) &&
472 (MessageHandlers
[i
].DeviceObject
== NULL
|| MessageHandlers
[i
].DeviceObject
== DeviceObject
) &&
473 MessageHandlers
[i
].MessageHandler
!= NULL
)
475 Status
= MessageHandlers
[i
].MessageHandler(DeviceObject
, ControlCode
, Irp
->AssociatedIrp
.SystemBuffer
,
476 IoStackLocation
->Parameters
.DeviceIoControl
.InputBufferLength
,
482 Irp
->IoStatus
.Status
= Status
;
483 Irp
->IoStatus
.Information
= OutLength
;
485 IoCompleteRequest(Irp
, IO_NO_INCREMENT
);