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