1 /* 2 * PROJECT: ReactOS Virtual DOS Machine 3 * LICENSE: GPL-2.0+ (https://spdx.org/licenses/GPL-2.0+) 4 * PURPOSE: Testing VDD for NTVDM 5 * COPYRIGHT: Copyright 2015-2018 Hermes Belusca-Maito 6 */ 7 8 /* INCLUDES *******************************************************************/ 9 10 #include <stdio.h> 11 12 #include <windows.h> 13 #include <vddsvc.h> 14 15 #define NDEBUG 16 #include <debug.h> 17 18 19 /* DEBUGGING HELPERS **********************************************************/ 20 21 // Enable this define to use DPRINT1 instead of MessageBox 22 // #define DBG_SILENT 23 24 #ifdef DBG_SILENT 25 26 #define VDD_DBG(...) \ 27 do { \ 28 DPRINT1(__VA_ARGS__); \ 29 DbgPrint("\n"); \ 30 } while(0) 31 32 #else 33 34 static VOID 35 VddDbgMsg(LPCSTR Format, ...) 36 { 37 #ifndef WIN2K_COMPLIANT 38 CHAR StaticBuffer[256]; 39 LPSTR Buffer = StaticBuffer; // Use the static buffer by default. 40 #else 41 CHAR Buffer[2048]; // Large enough. If not, increase it by hand. 42 #endif 43 size_t MsgLen; 44 va_list Parameters; 45 46 va_start(Parameters, Format); 47 48 #ifndef WIN2K_COMPLIANT 49 /* 50 * Retrieve the message length and if it is too long, allocate 51 * an auxiliary buffer; otherwise use the static buffer. 52 */ 53 MsgLen = _vscprintf(Format, Parameters) + 1; // NULL-terminated 54 if (MsgLen > ARRAYSIZE(StaticBuffer)) 55 { 56 Buffer = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, MsgLen * sizeof(WCHAR)); 57 if (Buffer == NULL) 58 { 59 /* Allocation failed, use the static buffer and display a suitable error message */ 60 Buffer = StaticBuffer; 61 Format = "DisplayMessage()\nOriginal message is too long and allocating an auxiliary buffer failed."; 62 MsgLen = strlen(Format); 63 } 64 } 65 #else 66 MsgLen = ARRAYSIZE(Buffer); 67 #endif 68 69 /* Display the message */ 70 _vsnprintf(Buffer, MsgLen, Format, Parameters); 71 MessageBoxA(NULL, Buffer, "Test VDD", MB_OK); 72 73 #ifndef WIN2K_COMPLIANT 74 /* Free the buffer if needed */ 75 if (Buffer != StaticBuffer) HeapFree(GetProcessHeap(), 0, Buffer); 76 #endif 77 78 va_end(Parameters); 79 } 80 81 #define VDD_DBG VddDbgMsg 82 #endif 83 84 85 /* GLOBALS ********************************************************************/ 86 87 HANDLE hVdd = NULL; 88 89 90 /* VDD I/O PORTS TESTING ******************************************************/ 91 92 /* 93 * Port hooks (serial ports) -- Each port range is for testing different port handlers. 94 */ 95 #define NUM_PORTS 4 96 97 VDD_IO_PORTRANGE PortDefs[NUM_PORTS] = 98 { 99 {0x3F8, 0x3FF}, 100 {0x2F8, 0x2FF}, 101 {0x3E8, 0x3EF}, 102 {0x2E8, 0x2EF} 103 }; 104 105 VOID 106 WINAPI 107 PortInB(IN USHORT Port, 108 OUT PUCHAR Data) 109 { 110 *Data = 0; 111 VDD_DBG("0x%08x (BYTE 0x%02x) <-- Port 0x%04x", Data, *Data, Port); 112 } 113 114 VOID 115 WINAPI 116 PortOutB(IN USHORT Port, 117 IN UCHAR Data) 118 { 119 VDD_DBG("(BYTE 0x%02x) --> Port 0x%04x", Data, Port); 120 } 121 122 VOID 123 WINAPI 124 PortInW(IN USHORT Port, 125 OUT PUSHORT Data) 126 { 127 *Data = 0; 128 VDD_DBG("0x%08x (WORD 0x%04x) <-- Port 0x%04x", Data, *Data, Port); 129 } 130 131 VOID 132 WINAPI 133 PortOutW(IN USHORT Port, 134 IN USHORT Data) 135 { 136 VDD_DBG("(WORD 0x%04x) --> Port 0x%04x", Data, Port); 137 } 138 139 140 VOID 141 WINAPI 142 PortInsB(IN USHORT Port, 143 OUT PUCHAR Data, 144 IN USHORT Count) 145 { 146 VDD_DBG("0x%08x (BYTESTR[%u]) <-- Port 0x%04x", Data, Count, Port); 147 while (Count--) *Data++ = 0; 148 } 149 150 VOID 151 WINAPI 152 PortOutsB(IN USHORT Port, 153 IN PUCHAR Data, 154 IN USHORT Count) 155 { 156 VDD_DBG("0x%08x (BYTESTR[%u]) --> Port 0x%04x", Data, Count, Port); 157 } 158 159 VOID 160 WINAPI 161 PortInsW(IN USHORT Port, 162 OUT PUSHORT Data, 163 IN USHORT Count) 164 { 165 VDD_DBG("0x%08x (WORDSTR[%u]) <-- Port 0x%04x", Data, Count, Port); 166 while (Count--) *Data++ = 0; 167 } 168 169 VOID 170 WINAPI 171 PortOutsW(IN USHORT Port, 172 IN PUSHORT Data, 173 IN USHORT Count) 174 { 175 VDD_DBG("0x%08x (WORDSTR[%u]) --> Port 0x%04x", Data, Count, Port); 176 } 177 178 179 VDD_IO_HANDLERS PortHandlers[NUM_PORTS] = 180 { 181 {PortInB, NULL , NULL , NULL , PortOutB, NULL , NULL , NULL }, 182 {PortInB, PortInW, NULL , NULL , PortOutB, PortOutW, NULL , NULL }, 183 {PortInB, NULL , PortInsB, NULL , PortOutB, NULL , PortOutsB, NULL }, 184 {PortInB, NULL , NULL , PortInsW, PortOutB, NULL , NULL , PortOutsW}, 185 }; 186 187 188 /* VDD MEMORY HOOKS TESTING ***************************************************/ 189 190 /* 191 * Everything should be page-rounded. 192 */ 193 194 #ifndef PAGE_SIZE 195 #define PAGE_SIZE 0x1000 196 #endif 197 198 #ifndef PAGE_ROUND_DOWN 199 #define PAGE_ROUND_DOWN(x) \ 200 ( ((ULONG_PTR)(x)) & (~(PAGE_SIZE-1)) ) 201 #endif 202 203 #ifndef PAGE_ROUND_UP 204 #define PAGE_ROUND_UP(x) \ 205 ( (((ULONG_PTR)(x)) + PAGE_SIZE-1) & (~(PAGE_SIZE-1)) ) 206 #endif 207 208 #define MEM_SEG_START 0x0000 209 #define MEM_SIZE PAGE_SIZE 210 211 USHORT HookedSegment = 0x0000; 212 ULONG HookedOffset = 0x0000; 213 PVOID HookedAddress = NULL; 214 215 VOID 216 WINAPI 217 MemoryHandler(IN PVOID FaultAddress, 218 IN ULONG RWMode) 219 { 220 BOOLEAN Success = FALSE; 221 222 VDD_DBG("MemoryHandler(0x%08x, %s)", FaultAddress, (RWMode == 1) ? "Write" : "Read"); 223 // VDDTerminateVDM(); 224 225 Success = VDDAllocMem(hVdd, HookedAddress, MEM_SIZE); 226 if (!Success) VDD_DBG("Unable to allocate memory"); 227 } 228 229 PVOID 230 FindHookableMemory(IN USHORT StartSegment, 231 IN ULONG StartOffset, 232 OUT PUSHORT HookedSegment, 233 OUT PULONG HookedOffset) 234 { 235 BOOLEAN Success; 236 PVOID PhysMemStart = NULL; 237 USHORT Segment = StartSegment; 238 ULONG Offset = PAGE_ROUND_DOWN(StartOffset); 239 240 *HookedSegment = 0x0000; 241 *HookedOffset = 0x0000; 242 243 while (Segment <= 0xF000) 244 { 245 // PhysMemStart = GetVDMPointer(GetVDMAddress(Segment, Offset), MEM_SIZE, (getMSW() & MSW_PE)); 246 PhysMemStart = VdmMapFlat(Segment, Offset, getMODE()); 247 248 /* Try to hook this memory area... */ 249 Success = VDDInstallMemoryHook(hVdd, PhysMemStart, MEM_SIZE, MemoryHandler); 250 if (!Success) 251 { 252 /* ... it didn't work. Free PhysMemStart, increase segment/offset and try again. */ 253 DPRINT1("%04lX:%08lX hooking failed, continue...\n", Segment, Offset); 254 255 VdmUnmapFlat(Segment, Offset, PhysMemStart, getMODE()); 256 // FreeVDMPointer(GetVDMAddress(Segment, Offset), MEM_SIZE, PhysMemStart, (getMSW() & MSW_PE)); 257 PhysMemStart = NULL; 258 259 Offset += MEM_SIZE; 260 if (Offset + MEM_SIZE > 0xFFFF) 261 { 262 Segment += 0x1000; 263 Offset = 0x0000; 264 } 265 } 266 else 267 { 268 /* ... it worked. We'll free PhysMemStart later on. */ 269 DPRINT1("%04lX:%08lX hooking succeeded!\n", Segment, Offset); 270 break; 271 } 272 } 273 274 if (PhysMemStart) 275 { 276 VDD_DBG("We hooked at %04lX:%08lX (0x%p)", Segment, Offset, PhysMemStart); 277 *HookedSegment = Segment; 278 *HookedOffset = Offset; 279 } 280 else 281 { 282 VDD_DBG("Hooking attempt failed!"); 283 } 284 285 return PhysMemStart; 286 } 287 288 289 /* VDD USER HOOKS TESTING *****************************************************/ 290 291 VOID 292 WINAPI 293 Create1Handler(USHORT DosPDB) 294 { 295 VDD_DBG("Create1Handler(0x%04x)", DosPDB); 296 } 297 298 VOID 299 WINAPI 300 Create2Handler(USHORT DosPDB) 301 { 302 VDD_DBG("Create2Handler(0x%04x)", DosPDB); 303 } 304 305 VOID 306 WINAPI 307 Terminate1Handler(USHORT DosPDB) 308 { 309 VDD_DBG("Terminate1Handler(0x%04x)", DosPDB); 310 } 311 312 VOID 313 WINAPI 314 Terminate2Handler(USHORT DosPDB) 315 { 316 VDD_DBG("Terminate2Handler(0x%04x)", DosPDB); 317 } 318 319 VOID 320 WINAPI 321 Block1Handler(VOID) 322 { 323 VDD_DBG("Block1Handler"); 324 } 325 326 VOID 327 WINAPI 328 Block2Handler(VOID) 329 { 330 VDD_DBG("Block2Handler"); 331 } 332 333 VOID 334 WINAPI 335 Resume1Handler(VOID) 336 { 337 VDD_DBG("Resume1Handler"); 338 } 339 340 VOID 341 WINAPI 342 Resume2Handler(VOID) 343 { 344 VDD_DBG("Resume2Handler"); 345 } 346 347 348 /* VDD INITIALIZATION AND REGISTRATION ****************************************/ 349 350 VOID 351 WINAPI 352 TestVDDRegister(VOID) 353 { 354 VDD_DBG("TestVDDRegister"); 355 356 /* Clear the Carry Flag: success */ 357 setCF(0); 358 } 359 360 VOID 361 WINAPI 362 TestVDDUnRegister(VOID) 363 { 364 VDD_DBG("TestVDDUnRegister"); 365 366 /* Clear the Carry Flag: success */ 367 setCF(0); 368 } 369 370 VOID 371 WINAPI 372 TestVDDDispatch(VOID) 373 { 374 VDD_DBG("TestVDDDispatch"); 375 376 /* Clear the Carry Flag: success */ 377 setCF(0); 378 } 379 380 BOOLEAN 381 RegisterVDD(BOOLEAN Register) 382 { 383 BOOLEAN Success = FALSE; 384 385 if (Register) 386 { 387 /* Hook some IO ports */ 388 VDD_DBG("VDDInstallIOHook"); 389 Success = VDDInstallIOHook(hVdd, NUM_PORTS, PortDefs, PortHandlers); 390 if (!Success) 391 { 392 VDD_DBG("Unable to hook IO ports, terminate..."); 393 VDDTerminateVDM(); 394 } 395 396 /* Add a memory handler */ 397 VDD_DBG("FindHookableMemory"); 398 HookedAddress = FindHookableMemory(MEM_SEG_START, 0x0000, 399 &HookedSegment, &HookedOffset); 400 if (HookedAddress == NULL) 401 { 402 VDD_DBG("Unable to install memory handler, terminate..."); 403 VDDTerminateVDM(); 404 } 405 406 /* Add some user hooks -- Test order of initialization and calling */ 407 VDD_DBG("VDDInstallUserHook (1)"); 408 Success = VDDInstallUserHook(hVdd, 409 Create1Handler, 410 Terminate1Handler, 411 Block1Handler, 412 Resume1Handler); 413 if (!Success) 414 { 415 VDD_DBG("Unable to install user hooks (1)..."); 416 } 417 418 VDD_DBG("VDDInstallUserHook (2)"); 419 Success = VDDInstallUserHook(hVdd, 420 Create2Handler, 421 Terminate2Handler, 422 Block2Handler, 423 Resume2Handler); 424 if (!Success) 425 { 426 VDD_DBG("Unable to install user hooks (2)..."); 427 } 428 429 /* We have finished! */ 430 VDD_DBG("Initialization finished!"); 431 } 432 else 433 { 434 /* Remove the user hooks */ 435 VDD_DBG("VDDDeInstallUserHook (1)"); 436 Success = VDDDeInstallUserHook(hVdd); 437 if (!Success) VDD_DBG("Unable to uninstall user hooks (1)"); 438 439 // TODO: See which hooks are still existing there... 440 441 VDD_DBG("VDDDeInstallUserHook (2)"); 442 Success = VDDDeInstallUserHook(hVdd); 443 if (!Success) VDD_DBG("Unable to uninstall user hooks (2)"); 444 445 VDD_DBG("VDDDeInstallUserHook (3)"); 446 Success = VDDDeInstallUserHook(hVdd); 447 if (!Success) VDD_DBG("EXPECTED ERROR: Unable to uninstall user hooks (3)"); 448 else VDD_DBG("UNEXPECTED ERROR: Uninstalling user hooks (3) succeeded?!"); 449 450 /* Uninstall the memory handler */ 451 Success = VDDFreeMem(hVdd, HookedAddress, MEM_SIZE); 452 if (!Success) VDD_DBG("Unable to free memory"); 453 454 VDD_DBG("VDDDeInstallMemoryHook"); 455 Success = VDDDeInstallMemoryHook(hVdd, HookedAddress, MEM_SIZE); 456 if (!Success) VDD_DBG("Memory handler uninstall failed"); 457 458 VDD_DBG("VdmUnmapFlat"); 459 Success = VdmUnmapFlat(HookedSegment, HookedOffset, HookedAddress, getMODE()); 460 // FreeVDMPointer(GetVDMAddress(HookedSegment, HookedOffset), MEM_SIZE, HookedAddress, (getMSW() & MSW_PE)); 461 if (!Success) VDD_DBG("VdmUnmapFlat failed!"); 462 463 /* Deregister the hooked IO ports */ 464 VDD_DBG("VDDDeInstallIOHook"); 465 VDDDeInstallIOHook(hVdd, NUM_PORTS, PortDefs); 466 467 VDD_DBG("Cleanup finished!"); 468 Success = TRUE; 469 } 470 471 return Success; 472 } 473 474 BOOL 475 WINAPI // VDDInitialize 476 DllMain(IN HINSTANCE hInstanceDll, 477 IN DWORD dwReason, 478 IN LPVOID lpReserved) 479 { 480 BOOLEAN Success; 481 482 UNREFERENCED_PARAMETER(lpReserved); 483 484 switch (dwReason) 485 { 486 case DLL_PROCESS_ATTACH: 487 { 488 VDD_DBG("DLL_PROCESS_ATTACH"); 489 490 /* Save our global VDD handle */ 491 hVdd = hInstanceDll; 492 493 /* Register VDD */ 494 Success = RegisterVDD(TRUE); 495 if (!Success) VDD_DBG("Failed to register the VDD..."); 496 497 break; 498 } 499 500 case DLL_PROCESS_DETACH: 501 { 502 VDD_DBG("DLL_PROCESS_DETACH"); 503 504 /* Unregister VDD */ 505 Success = RegisterVDD(FALSE); 506 if (!Success) VDD_DBG("Failed to unregister the VDD..."); 507 508 break; 509 } 510 511 case DLL_THREAD_ATTACH: 512 case DLL_THREAD_DETACH: 513 default: 514 break; 515 } 516 517 return TRUE; 518 } 519 520 /* EOF */ 521