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