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 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 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 StringCbCopyW(DevicePath, sizeof(DevicePath), L"\\\\.\\Global\\GLOBALROOT\\Device\\"); 180 StringCbCatW(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 } 340