[KMTESTS]
[reactos.git] / rostests / kmtests / kmtest_drv / kmtest_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
5 * PROGRAMMER: Thomas Faber <thfabba@gmx.de>
6 */
7
8 #include <ntddk.h>
9 #include <ntifs.h>
10 #include <ndk/ketypes.h>
11 #include <ntstrsafe.h>
12 #include <limits.h>
13 #include <pseh/pseh2.h>
14
15 //#define NDEBUG
16 #include <debug.h>
17
18 #include <kmt_public.h>
19 #define KMT_DEFINE_TEST_FUNCTIONS
20 #include <kmt_test.h>
21
22 /* Prototypes */
23 DRIVER_INITIALIZE DriverEntry;
24 static DRIVER_UNLOAD DriverUnload;
25 __drv_dispatchType(IRP_MJ_CREATE)
26 static DRIVER_DISPATCH DriverCreate;
27 __drv_dispatchType(IRP_MJ_CLEANUP)
28 static DRIVER_DISPATCH DriverCleanup;
29 __drv_dispatchType(IRP_MJ_CLOSE)
30 static DRIVER_DISPATCH DriverClose;
31 __drv_dispatchType(IRP_MJ_DEVICE_CONTROL)
32 static DRIVER_DISPATCH DriverIoControl;
33
34 /* Globals */
35 static PDEVICE_OBJECT MainDeviceObject;
36 PDRIVER_OBJECT KmtDriverObject = NULL;
37
38 /* Entry */
39 /**
40 * @name DriverEntry
41 *
42 * Driver Entry point.
43 *
44 * @param DriverObject
45 * Driver Object
46 * @param RegistryPath
47 * Driver Registry Path
48 *
49 * @return Status
50 */
51 NTSTATUS
52 NTAPI
53 DriverEntry(
54 IN PDRIVER_OBJECT DriverObject,
55 IN PUNICODE_STRING RegistryPath)
56 {
57 NTSTATUS Status = STATUS_SUCCESS;
58 UNICODE_STRING DeviceName;
59 PKMT_DEVICE_EXTENSION DeviceExtension;
60 PKPRCB Prcb;
61
62 PAGED_CODE();
63
64 UNREFERENCED_PARAMETER(RegistryPath);
65
66 DPRINT("DriverEntry\n");
67
68 Prcb = KeGetCurrentPrcb();
69 KmtIsCheckedBuild = (Prcb->BuildType & PRCB_BUILD_DEBUG) != 0;
70 KmtIsMultiProcessorBuild = (Prcb->BuildType & PRCB_BUILD_UNIPROCESSOR) == 0;
71 KmtDriverObject = DriverObject;
72
73 RtlInitUnicodeString(&DeviceName, KMTEST_DEVICE_DRIVER_PATH);
74 Status = IoCreateDevice(DriverObject, sizeof(KMT_DEVICE_EXTENSION),
75 &DeviceName,
76 FILE_DEVICE_UNKNOWN,
77 FILE_DEVICE_SECURE_OPEN | FILE_READ_ONLY_DEVICE,
78 FALSE, &MainDeviceObject);
79
80 if (!NT_SUCCESS(Status))
81 goto cleanup;
82
83 DPRINT("DriverEntry. Created DeviceObject %p. DeviceExtension %p\n",
84 MainDeviceObject, MainDeviceObject->DeviceExtension);
85 DeviceExtension = MainDeviceObject->DeviceExtension;
86 DeviceExtension->ResultBuffer = NULL;
87 DeviceExtension->Mdl = NULL;
88
89 DriverObject->DriverUnload = DriverUnload;
90 DriverObject->MajorFunction[IRP_MJ_CREATE] = DriverCreate;
91 DriverObject->MajorFunction[IRP_MJ_CLEANUP] = DriverCleanup;
92 DriverObject->MajorFunction[IRP_MJ_CLOSE] = DriverClose;
93 DriverObject->MajorFunction[IRP_MJ_DEVICE_CONTROL] = DriverIoControl;
94
95 cleanup:
96 if (MainDeviceObject && !NT_SUCCESS(Status))
97 {
98 IoDeleteDevice(MainDeviceObject);
99 MainDeviceObject = NULL;
100 }
101
102 return Status;
103 }
104
105 /* Dispatch functions */
106 /**
107 * @name DriverUnload
108 *
109 * Driver cleanup funtion.
110 *
111 * @param DriverObject
112 * Driver Object
113 */
114 static
115 VOID
116 NTAPI
117 DriverUnload(
118 IN PDRIVER_OBJECT DriverObject)
119 {
120 PAGED_CODE();
121
122 UNREFERENCED_PARAMETER(DriverObject);
123
124 DPRINT("DriverUnload\n");
125
126 if (MainDeviceObject)
127 {
128 PKMT_DEVICE_EXTENSION DeviceExtension = MainDeviceObject->DeviceExtension;
129 ASSERT(!DeviceExtension->Mdl);
130 ASSERT(!DeviceExtension->ResultBuffer);
131 ASSERT(!ResultBuffer);
132 IoDeleteDevice(MainDeviceObject);
133 }
134 }
135
136 /**
137 * @name DriverCreate
138 *
139 * Driver Dispatch function for IRP_MJ_CREATE
140 *
141 * @param DeviceObject
142 * Device Object
143 * @param Irp
144 * I/O request packet
145 *
146 * @return Status
147 */
148 static
149 NTSTATUS
150 NTAPI
151 DriverCreate(
152 IN PDEVICE_OBJECT DeviceObject,
153 IN PIRP Irp)
154 {
155 NTSTATUS Status = STATUS_SUCCESS;
156 PIO_STACK_LOCATION IoStackLocation;
157
158 PAGED_CODE();
159
160 IoStackLocation = IoGetCurrentIrpStackLocation(Irp);
161
162 DPRINT("DriverCreate. DeviceObject=%p, RequestorMode=%d, FileObject=%p, FsContext=%p, FsContext2=%p\n",
163 DeviceObject, Irp->RequestorMode, IoStackLocation->FileObject,
164 IoStackLocation->FileObject->FsContext, IoStackLocation->FileObject->FsContext2);
165
166 Irp->IoStatus.Status = Status;
167 Irp->IoStatus.Information = 0;
168
169 IoCompleteRequest(Irp, IO_NO_INCREMENT);
170
171 return Status;
172 }
173
174 /**
175 * @name DriverCleanup
176 *
177 * Driver Dispatch function for IRP_MJ_CLEANUP
178 *
179 * @param DeviceObject
180 * Device Object
181 * @param Irp
182 * I/O request packet
183 *
184 * @return Status
185 */
186 static
187 NTSTATUS
188 NTAPI
189 DriverCleanup(
190 IN PDEVICE_OBJECT DeviceObject,
191 IN PIRP Irp)
192 {
193 NTSTATUS Status = STATUS_SUCCESS;
194 PIO_STACK_LOCATION IoStackLocation;
195 PKMT_DEVICE_EXTENSION DeviceExtension;
196
197 PAGED_CODE();
198
199 IoStackLocation = IoGetCurrentIrpStackLocation(Irp);
200
201 DPRINT("DriverCleanup. DeviceObject=%p, RequestorMode=%d, FileObject=%p, FsContext=%p, FsContext2=%p\n",
202 DeviceObject, Irp->RequestorMode, IoStackLocation->FileObject,
203 IoStackLocation->FileObject->FsContext, IoStackLocation->FileObject->FsContext2);
204
205 ASSERT(IoStackLocation->FileObject->FsContext2 == NULL);
206 DeviceExtension = DeviceObject->DeviceExtension;
207 if (DeviceExtension->Mdl && IoStackLocation->FileObject->FsContext == DeviceExtension->Mdl)
208 {
209 MmUnlockPages(DeviceExtension->Mdl);
210 IoFreeMdl(DeviceExtension->Mdl);
211 DeviceExtension->Mdl = NULL;
212 ResultBuffer = DeviceExtension->ResultBuffer = NULL;
213 }
214 else
215 {
216 ASSERT(IoStackLocation->FileObject->FsContext == NULL);
217 }
218
219 Irp->IoStatus.Status = Status;
220 Irp->IoStatus.Information = 0;
221
222 IoCompleteRequest(Irp, IO_NO_INCREMENT);
223
224 return Status;
225 }
226
227 /**
228 * @name DriverClose
229 *
230 * Driver Dispatch function for IRP_MJ_CLOSE
231 *
232 * @param DeviceObject
233 * Device Object
234 * @param Irp
235 * I/O request packet
236 *
237 * @return Status
238 */
239 static
240 NTSTATUS
241 NTAPI
242 DriverClose(
243 IN PDEVICE_OBJECT DeviceObject,
244 IN PIRP Irp)
245 {
246 NTSTATUS Status = STATUS_SUCCESS;
247
248 PAGED_CODE();
249
250 DPRINT("DriverClose. DeviceObject=%p, RequestorMode=%d\n",
251 DeviceObject, Irp->RequestorMode);
252
253 Irp->IoStatus.Status = Status;
254 Irp->IoStatus.Information = 0;
255
256 IoCompleteRequest(Irp, IO_NO_INCREMENT);
257
258 return Status;
259 }
260
261 /**
262 * @name DriverIoControl
263 *
264 * Driver Dispatch function for IRP_MJ_DEVICE_CONTROL
265 *
266 * @param DeviceObject
267 * Device Object
268 * @param Irp
269 * I/O request packet
270 *
271 * @return Status
272 */
273 static
274 NTSTATUS
275 NTAPI
276 DriverIoControl(
277 IN PDEVICE_OBJECT DeviceObject,
278 IN PIRP Irp)
279 {
280 NTSTATUS Status = STATUS_SUCCESS;
281 PIO_STACK_LOCATION IoStackLocation;
282 SIZE_T Length = 0;
283
284 PAGED_CODE();
285
286 IoStackLocation = IoGetCurrentIrpStackLocation(Irp);
287
288 DPRINT("DriverIoControl. Code=0x%08X, DeviceObject=%p, FileObject=%p, FsContext=%p, FsContext2=%p\n",
289 IoStackLocation->Parameters.DeviceIoControl.IoControlCode,
290 DeviceObject, IoStackLocation->FileObject,
291 IoStackLocation->FileObject->FsContext, IoStackLocation->FileObject->FsContext2);
292
293 switch (IoStackLocation->Parameters.DeviceIoControl.IoControlCode)
294 {
295 case IOCTL_KMTEST_GET_TESTS:
296 {
297 PCKMT_TEST TestEntry;
298 LPSTR OutputBuffer = Irp->AssociatedIrp.SystemBuffer;
299 size_t Remaining = IoStackLocation->Parameters.DeviceIoControl.OutputBufferLength;
300
301 DPRINT("DriverIoControl. IOCTL_KMTEST_GET_TESTS, outlen=%lu\n",
302 IoStackLocation->Parameters.DeviceIoControl.OutputBufferLength);
303
304 for (TestEntry = TestList; TestEntry->TestName; ++TestEntry)
305 {
306 RtlStringCbCopyExA(OutputBuffer, Remaining, TestEntry->TestName, &OutputBuffer, &Remaining, 0);
307 if (Remaining)
308 {
309 *OutputBuffer++ = '\0';
310 --Remaining;
311 }
312 }
313 if (Remaining)
314 {
315 *OutputBuffer++ = '\0';
316 --Remaining;
317 }
318 Length = IoStackLocation->Parameters.DeviceIoControl.OutputBufferLength - Remaining;
319 break;
320 }
321 case IOCTL_KMTEST_RUN_TEST:
322 {
323 ANSI_STRING TestName;
324 PCKMT_TEST TestEntry;
325
326 DPRINT("DriverIoControl. IOCTL_KMTEST_RUN_TEST, inlen=%lu, outlen=%lu\n",
327 IoStackLocation->Parameters.DeviceIoControl.InputBufferLength,
328 IoStackLocation->Parameters.DeviceIoControl.OutputBufferLength);
329 TestName.Length = TestName.MaximumLength = (USHORT)min(IoStackLocation->Parameters.DeviceIoControl.InputBufferLength, USHRT_MAX);
330 TestName.Buffer = Irp->AssociatedIrp.SystemBuffer;
331 DPRINT("DriverIoControl. Run test: %Z\n", &TestName);
332
333 for (TestEntry = TestList; TestEntry->TestName; ++TestEntry)
334 {
335 ANSI_STRING EntryName;
336 if (TestEntry->TestName[0] == '-')
337 RtlInitAnsiString(&EntryName, TestEntry->TestName + 1);
338 else
339 RtlInitAnsiString(&EntryName, TestEntry->TestName);
340
341 if (!RtlCompareString(&TestName, &EntryName, FALSE))
342 {
343 DPRINT1("DriverIoControl. Starting test %Z\n", &EntryName);
344 TestEntry->TestFunction();
345 DPRINT1("DriverIoControl. Finished test %Z\n", &EntryName);
346 break;
347 }
348 }
349
350 if (!TestEntry->TestName)
351 Status = STATUS_OBJECT_NAME_INVALID;
352
353 break;
354 }
355 case IOCTL_KMTEST_SET_RESULTBUFFER:
356 {
357 PKMT_DEVICE_EXTENSION DeviceExtension = DeviceObject->DeviceExtension;
358
359 DPRINT("DriverIoControl. IOCTL_KMTEST_SET_RESULTBUFFER, buffer=%p, inlen=%lu, outlen=%lu\n",
360 IoStackLocation->Parameters.DeviceIoControl.Type3InputBuffer,
361 IoStackLocation->Parameters.DeviceIoControl.InputBufferLength,
362 IoStackLocation->Parameters.DeviceIoControl.OutputBufferLength);
363
364 if (DeviceExtension->Mdl)
365 {
366 if (IoStackLocation->FileObject->FsContext != DeviceExtension->Mdl)
367 {
368 Status = STATUS_ACCESS_DENIED;
369 break;
370 }
371 MmUnlockPages(DeviceExtension->Mdl);
372 IoFreeMdl(DeviceExtension->Mdl);
373 IoStackLocation->FileObject->FsContext = NULL;
374 ResultBuffer = DeviceExtension->ResultBuffer = NULL;
375 }
376
377 DeviceExtension->Mdl = IoAllocateMdl(IoStackLocation->Parameters.DeviceIoControl.Type3InputBuffer,
378 IoStackLocation->Parameters.DeviceIoControl.InputBufferLength,
379 FALSE, FALSE, NULL);
380 if (!DeviceExtension->Mdl)
381 {
382 Status = STATUS_INSUFFICIENT_RESOURCES;
383 break;
384 }
385
386 _SEH2_TRY
387 {
388 MmProbeAndLockPages(DeviceExtension->Mdl, UserMode, IoModifyAccess);
389 }
390 _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER)
391 {
392 Status = _SEH2_GetExceptionCode();
393 IoFreeMdl(DeviceExtension->Mdl);
394 DeviceExtension->Mdl = NULL;
395 break;
396 } _SEH2_END;
397
398 ResultBuffer = DeviceExtension->ResultBuffer = MmGetSystemAddressForMdlSafe(DeviceExtension->Mdl, NormalPagePriority);
399 IoStackLocation->FileObject->FsContext = DeviceExtension->Mdl;
400
401 DPRINT("DriverIoControl. ResultBuffer: %ld %ld %ld %ld\n",
402 ResultBuffer->Successes, ResultBuffer->Failures,
403 ResultBuffer->LogBufferLength, ResultBuffer->LogBufferMaxLength);
404 break;
405 }
406 default:
407 DPRINT1("DriverIoControl. Invalid IoCtl code 0x%08X\n",
408 IoStackLocation->Parameters.DeviceIoControl.IoControlCode);
409 Status = STATUS_INVALID_DEVICE_REQUEST;
410 break;
411 }
412
413 Irp->IoStatus.Status = Status;
414 Irp->IoStatus.Information = Length;
415
416 IoCompleteRequest(Irp, IO_NO_INCREMENT);
417
418 return Status;
419 }