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 <thomas.faber@reactos.org>
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 Flags
& TESTENTRY_NO_EXCLUSIVE_DEVICE
? FALSE
: TRUE
,
128 if (!NT_SUCCESS(Status
))
130 DPRINT1("Could not create device object %wZ\n", &DeviceName
);
134 DPRINT("DriverEntry. Created DeviceObject %p\n",
138 /* initialize dispatch functions */
139 if (!(Flags
& TESTENTRY_NO_REGISTER_UNLOAD
))
140 DriverObject
->DriverUnload
= DriverUnload
;
141 if (!(Flags
& TESTENTRY_NO_REGISTER_DISPATCH
))
142 for (i
= 0; i
<= IRP_MJ_MAXIMUM_FUNCTION
; ++i
)
143 DriverObject
->MajorFunction
[i
] = DriverDispatch
;
146 if (TestDeviceObject
&& !NT_SUCCESS(Status
))
148 IoDeleteDevice(TestDeviceObject
);
149 TestDeviceObject
= NULL
;
152 if (KmtestDeviceObject
&& !NT_SUCCESS(Status
))
154 ObDereferenceObject(KmtestDeviceObject
);
155 KmtestDeviceObject
= NULL
;
156 if (KmtestFileObject
)
157 ObDereferenceObject(KmtestFileObject
);
166 * Driver cleanup funtion.
168 * @param DriverObject
175 IN PDRIVER_OBJECT DriverObject
)
179 UNREFERENCED_PARAMETER(DriverObject
);
181 DPRINT("DriverUnload\n");
183 TestUnload(DriverObject
);
185 if (TestDeviceObject
)
186 IoDeleteDevice(TestDeviceObject
);
188 if (KmtestDeviceObject
)
189 ObDereferenceObject(KmtestDeviceObject
);
193 * @name KmtRegisterIrpHandler
195 * Register a handler with the IRP Dispatcher.
196 * If multiple registered handlers match an IRP, it is unspecified which of
197 * them is called on IRP reception
199 * @param MajorFunction
200 * IRP major function code to be handled
201 * @param DeviceObject
202 * Device Object to handle IRPs for.
203 * Can be NULL to indicate any device object
205 * Handler function to register.
210 KmtRegisterIrpHandler(
211 IN UCHAR MajorFunction
,
212 IN PDEVICE_OBJECT DeviceObject OPTIONAL
,
213 IN PKMT_IRP_HANDLER IrpHandler
)
215 NTSTATUS Status
= STATUS_SUCCESS
;
218 if (MajorFunction
> IRP_MJ_MAXIMUM_FUNCTION
)
220 Status
= STATUS_INVALID_PARAMETER_1
;
224 if (IrpHandler
== NULL
)
226 Status
= STATUS_INVALID_PARAMETER_3
;
230 for (i
= 0; i
< sizeof IrpHandlers
/ sizeof IrpHandlers
[0]; ++i
)
231 if (IrpHandlers
[i
].IrpHandler
== NULL
)
233 IrpHandlers
[i
].MajorFunction
= MajorFunction
;
234 IrpHandlers
[i
].DeviceObject
= DeviceObject
;
235 IrpHandlers
[i
].IrpHandler
= IrpHandler
;
239 Status
= STATUS_ALLOTTED_SPACE_EXCEEDED
;
246 * @name KmtUnregisterIrpHandler
248 * Unregister a handler with the IRP Dispatcher.
249 * Parameters must be specified exactly as in the call to
250 * KmtRegisterIrpHandler. Only the first matching entry will be removed
253 * @param MajorFunction
254 * IRP major function code of the handler to be removed
255 * @param DeviceObject
256 * Device Object to of the handler to be removed
258 * Handler function of the handler to be removed
263 KmtUnregisterIrpHandler(
264 IN UCHAR MajorFunction
,
265 IN PDEVICE_OBJECT DeviceObject OPTIONAL
,
266 IN PKMT_IRP_HANDLER IrpHandler
)
268 NTSTATUS Status
= STATUS_SUCCESS
;
271 for (i
= 0; i
< sizeof IrpHandlers
/ sizeof IrpHandlers
[0]; ++i
)
272 if (IrpHandlers
[i
].MajorFunction
== MajorFunction
&&
273 IrpHandlers
[i
].DeviceObject
== DeviceObject
&&
274 IrpHandlers
[i
].IrpHandler
== IrpHandler
)
276 IrpHandlers
[i
].IrpHandler
= NULL
;
280 Status
= STATUS_NOT_FOUND
;
287 * @name DriverDispatch
289 * Driver Dispatch function
291 * @param DeviceObject
302 IN PDEVICE_OBJECT DeviceObject
,
305 NTSTATUS Status
= STATUS_SUCCESS
;
306 PIO_STACK_LOCATION IoStackLocation
;
311 IoStackLocation
= IoGetCurrentIrpStackLocation(Irp
);
313 DPRINT("DriverDispatch: Function=%s, Device=%p\n",
314 KmtMajorFunctionNames
[IoStackLocation
->MajorFunction
],
317 for (i
= 0; i
< sizeof IrpHandlers
/ sizeof IrpHandlers
[0]; ++i
)
319 if (IrpHandlers
[i
].MajorFunction
== IoStackLocation
->MajorFunction
&&
320 (IrpHandlers
[i
].DeviceObject
== NULL
|| IrpHandlers
[i
].DeviceObject
== DeviceObject
) &&
321 IrpHandlers
[i
].IrpHandler
!= NULL
)
322 return IrpHandlers
[i
].IrpHandler(DeviceObject
, Irp
, IoStackLocation
);
325 /* default handler for DeviceControl */
326 if (IoStackLocation
->MajorFunction
== IRP_MJ_DEVICE_CONTROL
||
327 IoStackLocation
->MajorFunction
== IRP_MJ_INTERNAL_DEVICE_CONTROL
)
328 return DeviceControlHandler(DeviceObject
, Irp
, IoStackLocation
);
330 /* default handler */
331 Irp
->IoStatus
.Status
= Status
;
332 Irp
->IoStatus
.Information
= 0;
334 IoCompleteRequest(Irp
, IO_NO_INCREMENT
);
340 * @name KmtRegisterMessageHandler
342 * Register a handler with the DeviceControl Dispatcher.
343 * If multiple registered handlers match a message, it is unspecified which of
344 * them is called on message reception.
345 * NOTE: message handlers registered with this function will not be called
346 * if a custom IRP handler matching the corresponding IRP is installed!
349 * Control code to be handled, as passed by the application.
350 * Can be 0 to indicate any control code
351 * @param DeviceObject
352 * Device Object to handle IRPs for.
353 * Can be NULL to indicate any device object
354 * @param MessageHandler
355 * Handler function to register.
360 KmtRegisterMessageHandler(
361 IN ULONG ControlCode OPTIONAL
,
362 IN PDEVICE_OBJECT DeviceObject OPTIONAL
,
363 IN PKMT_MESSAGE_HANDLER MessageHandler
)
365 NTSTATUS Status
= STATUS_SUCCESS
;
368 if (ControlCode
>= 0x400)
370 Status
= STATUS_INVALID_PARAMETER_1
;
374 if (MessageHandler
== NULL
)
376 Status
= STATUS_INVALID_PARAMETER_2
;
380 for (i
= 0; i
< sizeof MessageHandlers
/ sizeof MessageHandlers
[0]; ++i
)
381 if (MessageHandlers
[i
].MessageHandler
== NULL
)
383 MessageHandlers
[i
].ControlCode
= ControlCode
;
384 MessageHandlers
[i
].DeviceObject
= DeviceObject
;
385 MessageHandlers
[i
].MessageHandler
= MessageHandler
;
389 Status
= STATUS_ALLOTTED_SPACE_EXCEEDED
;
396 * @name KmtUnregisterMessageHandler
398 * Unregister a handler with the DeviceControl Dispatcher.
399 * Parameters must be specified exactly as in the call to
400 * KmtRegisterMessageHandler. Only the first matching entry will be removed
404 * Control code of the handler to be removed
405 * @param DeviceObject
406 * Device Object to of the handler to be removed
407 * @param MessageHandler
408 * Handler function of the handler to be removed
413 KmtUnregisterMessageHandler(
414 IN ULONG ControlCode OPTIONAL
,
415 IN PDEVICE_OBJECT DeviceObject OPTIONAL
,
416 IN PKMT_MESSAGE_HANDLER MessageHandler
)
418 NTSTATUS Status
= STATUS_SUCCESS
;
421 for (i
= 0; i
< sizeof MessageHandlers
/ sizeof MessageHandlers
[0]; ++i
)
422 if (MessageHandlers
[i
].ControlCode
== ControlCode
&&
423 MessageHandlers
[i
].DeviceObject
== DeviceObject
&&
424 MessageHandlers
[i
].MessageHandler
== MessageHandler
)
426 MessageHandlers
[i
].MessageHandler
= NULL
;
430 Status
= STATUS_NOT_FOUND
;
437 * @name DeviceControlHandler
439 * Default IRP_MJ_DEVICE_CONTROL/IRP_MJ_INTERNAL_DEVICE_CONTROL handler
441 * @param DeviceObject
443 * This is guaranteed not to have been touched by the dispatch function
444 * before the call to the IRP handler
447 * This is guaranteed not to have been touched by the dispatch function
448 * before the call to the IRP handler, except for passing it to
449 * IoGetCurrentStackLocation
450 * @param IoStackLocation
452 * This is guaranteed not to have been touched by the dispatch function
453 * before the call to the IRP handler
459 DeviceControlHandler(
460 IN PDEVICE_OBJECT DeviceObject
,
462 IN PIO_STACK_LOCATION IoStackLocation
)
464 NTSTATUS Status
= STATUS_SUCCESS
;
465 ULONG ControlCode
= (IoStackLocation
->Parameters
.DeviceIoControl
.IoControlCode
& 0x00000FFC) >> 2;
466 SIZE_T OutLength
= IoStackLocation
->Parameters
.DeviceIoControl
.OutputBufferLength
;
469 for (i
= 0; i
< sizeof MessageHandlers
/ sizeof MessageHandlers
[0]; ++i
)
471 if ((MessageHandlers
[i
].ControlCode
== 0 ||
472 MessageHandlers
[i
].ControlCode
== ControlCode
) &&
473 (MessageHandlers
[i
].DeviceObject
== NULL
|| MessageHandlers
[i
].DeviceObject
== DeviceObject
) &&
474 MessageHandlers
[i
].MessageHandler
!= NULL
)
476 Status
= MessageHandlers
[i
].MessageHandler(DeviceObject
, ControlCode
, Irp
->AssociatedIrp
.SystemBuffer
,
477 IoStackLocation
->Parameters
.DeviceIoControl
.InputBufferLength
,
483 Irp
->IoStatus
.Status
= Status
;
484 Irp
->IoStatus
.Information
= OutLength
;
486 IoCompleteRequest(Irp
, IO_NO_INCREMENT
);