2 * PROJECT: ReactOS kernel-mode tests
3 * LICENSE: LGPL-2.1+ (https://spdx.org/licenses/LGPL-2.1+)
4 * PURPOSE: Kernel-Mode Test Suite standalone driver routines
5 * COPYRIGHT: Copyright 2011-2018 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
|
125 (Flags
& TESTENTRY_NO_READONLY_DEVICE
? 0 : FILE_READ_ONLY_DEVICE
),
126 Flags
& TESTENTRY_NO_EXCLUSIVE_DEVICE
? FALSE
: TRUE
,
129 if (!NT_SUCCESS(Status
))
131 DPRINT1("Could not create device object %wZ\n", &DeviceName
);
135 if (Flags
& TESTENTRY_BUFFERED_IO_DEVICE
)
136 TestDeviceObject
->Flags
|= DO_BUFFERED_IO
;
138 DPRINT("DriverEntry. Created DeviceObject %p\n",
142 /* initialize dispatch functions */
143 if (!(Flags
& TESTENTRY_NO_REGISTER_UNLOAD
))
144 DriverObject
->DriverUnload
= DriverUnload
;
145 if (!(Flags
& TESTENTRY_NO_REGISTER_DISPATCH
))
146 for (i
= 0; i
<= IRP_MJ_MAXIMUM_FUNCTION
; ++i
)
147 DriverObject
->MajorFunction
[i
] = DriverDispatch
;
150 if (TestDeviceObject
&& !NT_SUCCESS(Status
))
152 IoDeleteDevice(TestDeviceObject
);
153 TestDeviceObject
= NULL
;
156 if (KmtestDeviceObject
&& !NT_SUCCESS(Status
))
158 ObDereferenceObject(KmtestDeviceObject
);
159 KmtestDeviceObject
= NULL
;
160 if (KmtestFileObject
)
161 ObDereferenceObject(KmtestFileObject
);
170 * Driver cleanup funtion.
172 * @param DriverObject
179 IN PDRIVER_OBJECT DriverObject
)
183 UNREFERENCED_PARAMETER(DriverObject
);
185 DPRINT("DriverUnload\n");
187 TestUnload(DriverObject
);
189 if (TestDeviceObject
)
190 IoDeleteDevice(TestDeviceObject
);
192 if (KmtestDeviceObject
)
193 ObDereferenceObject(KmtestDeviceObject
);
197 * @name KmtRegisterIrpHandler
199 * Register a handler with the IRP Dispatcher.
200 * If multiple registered handlers match an IRP, it is unspecified which of
201 * them is called on IRP reception
203 * @param MajorFunction
204 * IRP major function code to be handled
205 * @param DeviceObject
206 * Device Object to handle IRPs for.
207 * Can be NULL to indicate any device object
209 * Handler function to register.
214 KmtRegisterIrpHandler(
215 IN UCHAR MajorFunction
,
216 IN PDEVICE_OBJECT DeviceObject OPTIONAL
,
217 IN PKMT_IRP_HANDLER IrpHandler
)
219 NTSTATUS Status
= STATUS_SUCCESS
;
222 if (MajorFunction
> IRP_MJ_MAXIMUM_FUNCTION
)
224 Status
= STATUS_INVALID_PARAMETER_1
;
228 if (IrpHandler
== NULL
)
230 Status
= STATUS_INVALID_PARAMETER_3
;
234 for (i
= 0; i
< sizeof IrpHandlers
/ sizeof IrpHandlers
[0]; ++i
)
235 if (IrpHandlers
[i
].IrpHandler
== NULL
)
237 IrpHandlers
[i
].MajorFunction
= MajorFunction
;
238 IrpHandlers
[i
].DeviceObject
= DeviceObject
;
239 IrpHandlers
[i
].IrpHandler
= IrpHandler
;
243 Status
= STATUS_ALLOTTED_SPACE_EXCEEDED
;
250 * @name KmtUnregisterIrpHandler
252 * Unregister a handler with the IRP Dispatcher.
253 * Parameters must be specified exactly as in the call to
254 * KmtRegisterIrpHandler. Only the first matching entry will be removed
257 * @param MajorFunction
258 * IRP major function code of the handler to be removed
259 * @param DeviceObject
260 * Device Object to of the handler to be removed
262 * Handler function of the handler to be removed
267 KmtUnregisterIrpHandler(
268 IN UCHAR MajorFunction
,
269 IN PDEVICE_OBJECT DeviceObject OPTIONAL
,
270 IN PKMT_IRP_HANDLER IrpHandler
)
272 NTSTATUS Status
= STATUS_SUCCESS
;
275 for (i
= 0; i
< sizeof IrpHandlers
/ sizeof IrpHandlers
[0]; ++i
)
276 if (IrpHandlers
[i
].MajorFunction
== MajorFunction
&&
277 IrpHandlers
[i
].DeviceObject
== DeviceObject
&&
278 IrpHandlers
[i
].IrpHandler
== IrpHandler
)
280 IrpHandlers
[i
].IrpHandler
= NULL
;
284 Status
= STATUS_NOT_FOUND
;
291 * @name DriverDispatch
293 * Driver Dispatch function
295 * @param DeviceObject
306 IN PDEVICE_OBJECT DeviceObject
,
309 NTSTATUS Status
= STATUS_INVALID_DEVICE_REQUEST
;
310 PIO_STACK_LOCATION IoStackLocation
;
313 IoStackLocation
= IoGetCurrentIrpStackLocation(Irp
);
315 DPRINT("DriverDispatch: Function=%s, Device=%p\n",
316 KmtMajorFunctionNames
[IoStackLocation
->MajorFunction
],
319 for (i
= 0; i
< sizeof IrpHandlers
/ sizeof IrpHandlers
[0]; ++i
)
321 if (IrpHandlers
[i
].MajorFunction
== IoStackLocation
->MajorFunction
&&
322 (IrpHandlers
[i
].DeviceObject
== NULL
|| IrpHandlers
[i
].DeviceObject
== DeviceObject
) &&
323 IrpHandlers
[i
].IrpHandler
!= NULL
)
324 return IrpHandlers
[i
].IrpHandler(DeviceObject
, Irp
, IoStackLocation
);
327 /* default handler for DeviceControl */
328 if (IoStackLocation
->MajorFunction
== IRP_MJ_DEVICE_CONTROL
||
329 IoStackLocation
->MajorFunction
== IRP_MJ_INTERNAL_DEVICE_CONTROL
)
330 return DeviceControlHandler(DeviceObject
, Irp
, IoStackLocation
);
332 /* Return success for create, close, and cleanup */
333 if (IoStackLocation
->MajorFunction
== IRP_MJ_CREATE
||
334 IoStackLocation
->MajorFunction
== IRP_MJ_CLOSE
||
335 IoStackLocation
->MajorFunction
== IRP_MJ_CLEANUP
)
336 Status
= STATUS_SUCCESS
;
338 /* default handler */
339 Irp
->IoStatus
.Status
= Status
;
340 Irp
->IoStatus
.Information
= 0;
342 IoCompleteRequest(Irp
, IO_NO_INCREMENT
);
348 * @name KmtRegisterMessageHandler
350 * Register a handler with the DeviceControl Dispatcher.
351 * If multiple registered handlers match a message, it is unspecified which of
352 * them is called on message reception.
353 * NOTE: message handlers registered with this function will not be called
354 * if a custom IRP handler matching the corresponding IRP is installed!
357 * Control code to be handled, as passed by the application.
358 * Can be 0 to indicate any control code
359 * @param DeviceObject
360 * Device Object to handle IRPs for.
361 * Can be NULL to indicate any device object
362 * @param MessageHandler
363 * Handler function to register.
368 KmtRegisterMessageHandler(
369 IN ULONG ControlCode OPTIONAL
,
370 IN PDEVICE_OBJECT DeviceObject OPTIONAL
,
371 IN PKMT_MESSAGE_HANDLER MessageHandler
)
373 NTSTATUS Status
= STATUS_SUCCESS
;
376 if (ControlCode
>= 0x400)
378 Status
= STATUS_INVALID_PARAMETER_1
;
382 if (MessageHandler
== NULL
)
384 Status
= STATUS_INVALID_PARAMETER_2
;
388 for (i
= 0; i
< sizeof MessageHandlers
/ sizeof MessageHandlers
[0]; ++i
)
389 if (MessageHandlers
[i
].MessageHandler
== NULL
)
391 MessageHandlers
[i
].ControlCode
= ControlCode
;
392 MessageHandlers
[i
].DeviceObject
= DeviceObject
;
393 MessageHandlers
[i
].MessageHandler
= MessageHandler
;
397 Status
= STATUS_ALLOTTED_SPACE_EXCEEDED
;
404 * @name KmtUnregisterMessageHandler
406 * Unregister a handler with the DeviceControl Dispatcher.
407 * Parameters must be specified exactly as in the call to
408 * KmtRegisterMessageHandler. Only the first matching entry will be removed
412 * Control code of the handler to be removed
413 * @param DeviceObject
414 * Device Object to of the handler to be removed
415 * @param MessageHandler
416 * Handler function of the handler to be removed
421 KmtUnregisterMessageHandler(
422 IN ULONG ControlCode OPTIONAL
,
423 IN PDEVICE_OBJECT DeviceObject OPTIONAL
,
424 IN PKMT_MESSAGE_HANDLER MessageHandler
)
426 NTSTATUS Status
= STATUS_SUCCESS
;
429 for (i
= 0; i
< sizeof MessageHandlers
/ sizeof MessageHandlers
[0]; ++i
)
430 if (MessageHandlers
[i
].ControlCode
== ControlCode
&&
431 MessageHandlers
[i
].DeviceObject
== DeviceObject
&&
432 MessageHandlers
[i
].MessageHandler
== MessageHandler
)
434 MessageHandlers
[i
].MessageHandler
= NULL
;
438 Status
= STATUS_NOT_FOUND
;
445 * @name DeviceControlHandler
447 * Default IRP_MJ_DEVICE_CONTROL/IRP_MJ_INTERNAL_DEVICE_CONTROL handler
449 * @param DeviceObject
451 * This is guaranteed not to have been touched by the dispatch function
452 * before the call to the IRP handler
455 * This is guaranteed not to have been touched by the dispatch function
456 * before the call to the IRP handler, except for passing it to
457 * IoGetCurrentStackLocation
458 * @param IoStackLocation
460 * This is guaranteed not to have been touched by the dispatch function
461 * before the call to the IRP handler
467 DeviceControlHandler(
468 IN PDEVICE_OBJECT DeviceObject
,
470 IN PIO_STACK_LOCATION IoStackLocation
)
472 NTSTATUS Status
= STATUS_SUCCESS
;
473 ULONG ControlCode
= (IoStackLocation
->Parameters
.DeviceIoControl
.IoControlCode
& 0x00000FFC) >> 2;
474 SIZE_T OutLength
= IoStackLocation
->Parameters
.DeviceIoControl
.OutputBufferLength
;
477 for (i
= 0; i
< sizeof MessageHandlers
/ sizeof MessageHandlers
[0]; ++i
)
479 if ((MessageHandlers
[i
].ControlCode
== 0 ||
480 MessageHandlers
[i
].ControlCode
== ControlCode
) &&
481 (MessageHandlers
[i
].DeviceObject
== NULL
|| MessageHandlers
[i
].DeviceObject
== DeviceObject
) &&
482 MessageHandlers
[i
].MessageHandler
!= NULL
)
484 Status
= MessageHandlers
[i
].MessageHandler(DeviceObject
, ControlCode
, Irp
->AssociatedIrp
.SystemBuffer
,
485 IoStackLocation
->Parameters
.DeviceIoControl
.InputBufferLength
,
491 Irp
->IoStatus
.Status
= Status
;
492 Irp
->IoStatus
.Information
= OutLength
;
494 IoCompleteRequest(Irp
, IO_NO_INCREMENT
);