8fecf3f7feb8d4f27fb5fef532ec131787677353
[reactos.git] / subsystems / mvdm / samples / testvdd / testvdd.c
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 */