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