Reactos
1/*
2 * PROJECT: ReactOS kernel-mode tests
3 * LICENSE: LGPL-2.1+ (https://spdx.org/licenses/LGPL-2.1+)
4 * PURPOSE: Kernel-Mode Test Suite user-mode support routines
5 * COPYRIGHT: Copyright 2011-2020 Thomas Faber <thomas.faber@reactos.org>
6 * Copyright 2013 Nikolay Borisov <nib9@aber.ac.uk>
7 * Copyright 2018 Serge Gautherie <reactos-git_serge_171003@gautherie.fr>
8 */
9
10#include <kmt_test.h>
11
12#include "kmtest.h"
13#include <kmt_public.h>
14
15#include <assert.h>
16#include <debug.h>
17
18extern HANDLE KmtestHandle;
19
20/**
21 * @name KmtUserCallbackThread
22 *
23 * Thread routine which awaits callback requests from kernel-mode
24 *
25 * @return Win32 error code
26 */
27DWORD
28WINAPI
29KmtUserCallbackThread(
30 PVOID Parameter)
31{
32 DWORD Error = ERROR_SUCCESS;
33 /* TODO: RequestPacket? */
34 KMT_CALLBACK_REQUEST_PACKET RequestPacket;
35 KMT_RESPONSE Response;
36 DWORD BytesReturned;
37 HANDLE LocalKmtHandle;
38
39 UNREFERENCED_PARAMETER(Parameter);
40
41 /* concurrent IoCtls on the same (non-overlapped) handle aren't possible,
42 * so open a separate one.
43 * For more info http://www.osronline.com/showthread.cfm?link=230782 */
44 LocalKmtHandle = CreateFile(KMTEST_DEVICE_PATH, GENERIC_READ | GENERIC_WRITE, 0, NULL, OPEN_EXISTING, 0, NULL);
45 if (LocalKmtHandle == INVALID_HANDLE_VALUE)
46 error_goto(Error, cleanup);
47
48 while (1)
49 {
50 if (!DeviceIoControl(LocalKmtHandle, IOCTL_KMTEST_USERMODE_AWAIT_REQ, NULL, 0, &RequestPacket, sizeof(RequestPacket), &BytesReturned, NULL))
51 error_goto(Error, cleanup);
52 ASSERT(BytesReturned == sizeof(RequestPacket));
53
54 switch (RequestPacket.OperationClass)
55 {
56 case QueryVirtualMemory:
57 {
58 SIZE_T InfoBufferSize = VirtualQuery(RequestPacket.Parameters, &Response.MemInfo, sizeof(Response.MemInfo));
59 /* FIXME: an error is a valid result. That should go as a response to kernel mode instead of terminating the thread */
60 if (InfoBufferSize == 0)
61 error_goto(Error, cleanup);
62
63 if (!DeviceIoControl(LocalKmtHandle, IOCTL_KMTEST_USERMODE_SEND_RESPONSE, &RequestPacket.RequestId, sizeof(RequestPacket.RequestId), &Response, sizeof(Response), &BytesReturned, NULL))
64 error_goto(Error, cleanup);
65 ASSERT(BytesReturned == 0);
66
67 break;
68 }
69 default:
70 DPRINT1("Unrecognized user-mode callback request\n");
71 break;
72 }
73 }
74
75cleanup:
76 if (LocalKmtHandle != INVALID_HANDLE_VALUE)
77 CloseHandle(LocalKmtHandle);
78
79 DPRINT("Callback handler dying! Error code %lu", Error);
80 return Error;
81}
82
83
84/**
85 * @name KmtRunKernelTest
86 *
87 * Run the specified kernel-mode test part
88 *
89 * @param TestName
90 * Name of the test to run
91 *
92 * @return Win32 error code as returned by DeviceIoControl
93 */
94DWORD
95KmtRunKernelTest(
96 IN PCSTR TestName)
97{
98 HANDLE CallbackThread;
99 DWORD Error = ERROR_SUCCESS;
100 DWORD BytesRead;
101
102 CallbackThread = CreateThread(NULL, 0, KmtUserCallbackThread, NULL, 0, NULL);
103
104 if (!DeviceIoControl(KmtestHandle, IOCTL_KMTEST_RUN_TEST, (PVOID)TestName, (DWORD)strlen(TestName), NULL, 0, &BytesRead, NULL))
105 error(Error);
106
107 if (CallbackThread != NULL)
108 CloseHandle(CallbackThread);
109
110 return Error;
111}
112
113static WCHAR TestServiceName[MAX_PATH];
114static SC_HANDLE TestServiceHandle;
115static HANDLE TestDeviceHandle;
116
117/**
118 * @name KmtLoadDriver
119 *
120 * Load the specified special-purpose driver (create/start the service)
121 *
122 * @param ServiceName
123 * Name of the driver service (Kmtest- prefix will be added automatically)
124 * @param RestartIfRunning
125 * TRUE to stop and restart the service if it is already running
126 */
127DWORD
128KmtLoadDriver(
129 IN PCWSTR ServiceName,
130 IN BOOLEAN RestartIfRunning)
131{
132 WCHAR ServicePath[MAX_PATH];
133
134 StringCbCopyW(ServicePath, sizeof(ServicePath), ServiceName);
135 StringCbCatW(ServicePath, sizeof(ServicePath), L"_drv.sys");
136
137 StringCbCopyW(TestServiceName, sizeof(TestServiceName), L"Kmtest-");
138 StringCbCatW(TestServiceName, sizeof(TestServiceName), ServiceName);
139
140 return KmtCreateAndStartService(TestServiceName, ServicePath, NULL, &TestServiceHandle, RestartIfRunning);
141}
142
143/**
144 * @name KmtUnloadDriverKeepService
145 *
146 * Unload special-purpose driver (stop the service only)
147 */
148VOID
149KmtUnloadDriverKeepService(VOID)
150{
151 DWORD Error;
152
153 Error = KmtStopService(TestServiceName, &TestServiceHandle);
154
155 if (Error)
156 {
157 fprintf(stderr, "Failed to stop %ls service with error 0x%lx\n", TestServiceName, Error);
158 }
159}
160
161/**
162 * @name KmtUnloadDriver
163 *
164 * Unload special-purpose driver (stop and delete the service)
165 */
166VOID
167KmtUnloadDriver(VOID)
168{
169 DWORD Error;
170
171 Error = KmtStopService(TestServiceName, &TestServiceHandle);
172
173 if (Error)
174 {
175 fprintf(stderr, "Failed to stop %ls service with error 0x%lx\n", TestServiceName, Error);
176 }
177
178 Error = KmtDeleteService(TestServiceName, &TestServiceHandle);
179
180 if (Error)
181 {
182 fprintf(stderr, "Failed to delete %ls service with error 0x%lx\n", TestServiceName, Error);
183 }
184}
185
186/**
187 * @name KmtOpenDriver
188 *
189 * Open special-purpose driver (acquire a device handle)
190 */
191DWORD
192KmtOpenDriver(VOID)
193{
194 DWORD Error = ERROR_SUCCESS;
195 WCHAR DevicePath[MAX_PATH];
196
197 StringCbCopyW(DevicePath, sizeof(DevicePath), L"\\\\.\\Global\\GLOBALROOT\\Device\\");
198 StringCbCatW(DevicePath, sizeof(DevicePath), TestServiceName);
199
200 TestDeviceHandle = CreateFile(DevicePath, GENERIC_READ | GENERIC_WRITE, 0, NULL, OPEN_EXISTING, 0, NULL);
201 if (TestDeviceHandle == INVALID_HANDLE_VALUE)
202 error(Error);
203
204 return Error;
205}
206
207/**
208 * @name KmtOpenDriver
209 *
210 * Load and open special-purpose driver (acquire a device handle)
211 */
212DWORD
213KmtLoadAndOpenDriver(
214 IN PCWSTR ServiceName,
215 IN BOOLEAN RestartIfRunning)
216{
217 DWORD Error;
218
219 Error = KmtLoadDriver(ServiceName, RestartIfRunning);
220 if (Error)
221 return Error;
222
223 Error = KmtOpenDriver();
224 if (Error)
225 return Error;
226
227 return ERROR_SUCCESS;
228}
229
230/**
231 * @name KmtCloseDriver
232 *
233 * Close special-purpose driver (close device handle)
234 */
235VOID
236KmtCloseDriver(VOID)
237{
238 DWORD Error = ERROR_SUCCESS;
239
240 if (TestDeviceHandle && !CloseHandle(TestDeviceHandle))
241 error(Error);
242
243 if (Error)
244 {
245 DPRINT1("CloseHandle failed: 0x%lx\n", Error);
246 }
247}
248
249/**
250 * @name KmtSendToDriver
251 *
252 * Send an I/O control message with no arguments to the driver opened with KmtOpenDriver
253 *
254 * @param ControlCode
255 *
256 * @return Win32 error code as returned by DeviceIoControl
257 */
258DWORD
259KmtSendToDriver(
260 IN DWORD ControlCode)
261{
262 DWORD BytesRead;
263
264 assert(ControlCode < 0x400);
265
266 if (!DeviceIoControl(TestDeviceHandle, KMT_MAKE_CODE(ControlCode), NULL, 0, NULL, 0, &BytesRead, NULL))
267 return GetLastError();
268
269 return ERROR_SUCCESS;
270}
271
272/**
273 * @name KmtSendStringToDriver
274 *
275 * Send an I/O control message with a string argument to the driver opened with KmtOpenDriver
276 *
277 * @param ControlCode
278 * @param String
279 *
280 * @return Win32 error code as returned by DeviceIoControl
281 */
282DWORD
283KmtSendStringToDriver(
284 IN DWORD ControlCode,
285 IN PCSTR String)
286{
287 DWORD BytesRead;
288
289 assert(ControlCode < 0x400);
290
291 if (!DeviceIoControl(TestDeviceHandle, KMT_MAKE_CODE(ControlCode), (PVOID)String, (DWORD)strlen(String), NULL, 0, &BytesRead, NULL))
292 return GetLastError();
293
294 return ERROR_SUCCESS;
295}
296
297/**
298 * @name KmtSendWStringToDriver
299 *
300 * Send an I/O control message with a wide string argument to the driver opened with KmtOpenDriver
301 *
302 * @param ControlCode
303 * @param String
304 *
305 * @return Win32 error code as returned by DeviceIoControl
306 */
307DWORD
308KmtSendWStringToDriver(
309 IN DWORD ControlCode,
310 IN PCWSTR String)
311{
312 DWORD BytesRead;
313
314 assert(ControlCode < 0x400);
315
316 if (!DeviceIoControl(TestDeviceHandle, KMT_MAKE_CODE(ControlCode), (PVOID)String, (DWORD)wcslen(String) * sizeof(WCHAR), NULL, 0, &BytesRead, NULL))
317 return GetLastError();
318
319 return ERROR_SUCCESS;
320}
321
322/**
323 * @name KmtSendUlongToDriver
324 *
325 * Send an I/O control message with an integer argument to the driver opened with KmtOpenDriver
326 *
327 * @param ControlCode
328 * @param Value
329 *
330 * @return Win32 error code as returned by DeviceIoControl
331 */
332DWORD
333KmtSendUlongToDriver(
334 IN DWORD ControlCode,
335 IN DWORD Value)
336{
337 DWORD BytesRead;
338
339 assert(ControlCode < 0x400);
340
341 if (!DeviceIoControl(TestDeviceHandle, KMT_MAKE_CODE(ControlCode), &Value, sizeof(Value), NULL, 0, &BytesRead, NULL))
342 return GetLastError();
343
344 return ERROR_SUCCESS;
345}
346
347/**
348 * @name KmtSendBufferToDriver
349 *
350 * Send an I/O control message with the specified arguments to the driver opened with KmtOpenDriver
351 *
352 * @param ControlCode
353 * @param Buffer
354 * @param InLength
355 * @param OutLength
356 *
357 * @return Win32 error code as returned by DeviceIoControl
358 */
359DWORD
360KmtSendBufferToDriver(
361 IN DWORD ControlCode,
362 IN OUT PVOID Buffer OPTIONAL,
363 IN DWORD InLength,
364 IN OUT PDWORD OutLength)
365{
366 assert(OutLength);
367 assert(Buffer || (!InLength && !*OutLength));
368 assert(ControlCode < 0x400);
369
370 if (!DeviceIoControl(TestDeviceHandle, KMT_MAKE_CODE(ControlCode), Buffer, InLength, Buffer, *OutLength, OutLength, NULL))
371 return GetLastError();
372
373 return ERROR_SUCCESS;
374}