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
VddDbgMsg(LPCSTR Format,...)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
PortInB(IN USHORT Port,OUT PUCHAR Data)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
PortOutB(IN USHORT Port,IN UCHAR Data)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
PortInW(IN USHORT Port,OUT PUSHORT Data)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
PortOutW(IN USHORT Port,IN USHORT Data)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
PortInsB(IN USHORT Port,OUT PUCHAR Data,IN USHORT Count)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
PortOutsB(IN USHORT Port,IN PUCHAR Data,IN USHORT Count)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
PortInsW(IN USHORT Port,OUT PUSHORT Data,IN USHORT Count)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
PortOutsW(IN USHORT Port,IN PUSHORT Data,IN USHORT Count)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
MemoryHandler(IN PVOID FaultAddress,IN ULONG RWMode)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
FindHookableMemory(IN USHORT StartSegment,IN ULONG StartOffset,OUT PUSHORT HookedSegment,OUT PULONG HookedOffset)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
Create1Handler(USHORT DosPDB)293 Create1Handler(USHORT DosPDB)
294 {
295 VDD_DBG("Create1Handler(0x%04x)", DosPDB);
296 }
297
298 VOID
299 WINAPI
Create2Handler(USHORT DosPDB)300 Create2Handler(USHORT DosPDB)
301 {
302 VDD_DBG("Create2Handler(0x%04x)", DosPDB);
303 }
304
305 VOID
306 WINAPI
Terminate1Handler(USHORT DosPDB)307 Terminate1Handler(USHORT DosPDB)
308 {
309 VDD_DBG("Terminate1Handler(0x%04x)", DosPDB);
310 }
311
312 VOID
313 WINAPI
Terminate2Handler(USHORT DosPDB)314 Terminate2Handler(USHORT DosPDB)
315 {
316 VDD_DBG("Terminate2Handler(0x%04x)", DosPDB);
317 }
318
319 VOID
320 WINAPI
Block1Handler(VOID)321 Block1Handler(VOID)
322 {
323 VDD_DBG("Block1Handler");
324 }
325
326 VOID
327 WINAPI
Block2Handler(VOID)328 Block2Handler(VOID)
329 {
330 VDD_DBG("Block2Handler");
331 }
332
333 VOID
334 WINAPI
Resume1Handler(VOID)335 Resume1Handler(VOID)
336 {
337 VDD_DBG("Resume1Handler");
338 }
339
340 VOID
341 WINAPI
Resume2Handler(VOID)342 Resume2Handler(VOID)
343 {
344 VDD_DBG("Resume2Handler");
345 }
346
347
348 /* VDD INITIALIZATION AND REGISTRATION ****************************************/
349
350 VOID
351 WINAPI
TestVDDRegister(VOID)352 TestVDDRegister(VOID)
353 {
354 VDD_DBG("TestVDDRegister");
355
356 /* Clear the Carry Flag: success */
357 setCF(0);
358 }
359
360 VOID
361 WINAPI
TestVDDUnRegister(VOID)362 TestVDDUnRegister(VOID)
363 {
364 VDD_DBG("TestVDDUnRegister");
365
366 /* Clear the Carry Flag: success */
367 setCF(0);
368 }
369
370 VOID
371 WINAPI
TestVDDDispatch(VOID)372 TestVDDDispatch(VOID)
373 {
374 VDD_DBG("TestVDDDispatch");
375
376 /* Clear the Carry Flag: success */
377 setCF(0);
378 }
379
380 BOOLEAN
RegisterVDD(BOOLEAN Register)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
DllMain(IN HINSTANCE hInstanceDll,IN DWORD dwReason,IN LPVOID lpReserved)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