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