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