[NTVDM]
[reactos.git] / reactos / subsystems / ntvdm / emulator.c
1 /*
2 * COPYRIGHT: GPL - See COPYING in the top level directory
3 * PROJECT: ReactOS Virtual DOS Machine
4 * FILE: emulator.c
5 * PURPOSE: Minimal x86 machine emulator for the VDM
6 * PROGRAMMERS: Aleksandar Andrejevic <theflash AT sdf DOT lonestar DOT org>
7 */
8
9 /* INCLUDES *******************************************************************/
10
11 #define NDEBUG
12
13 #include "emulator.h"
14
15 #include "cpu/callback.h"
16 #include "cpu/cpu.h"
17 #include "cpu/bop.h"
18 #include <isvbop.h>
19
20 #include "int32.h"
21
22 #include "clock.h"
23 #include "bios/rom.h"
24 #include "hardware/cmos.h"
25 #include "hardware/keyboard.h"
26 #include "hardware/mouse.h"
27 #include "hardware/pic.h"
28 #include "hardware/ps2.h"
29 #include "hardware/sound/speaker.h"
30 #include "hardware/pit.h"
31 #include "hardware/video/vga.h"
32
33 #include "vddsup.h"
34 #include "io.h"
35
36 /* Extra PSDK/NDK Headers */
37 #include <ndk/psfuncs.h>
38 #include <ndk/mmfuncs.h>
39
40 /* PRIVATE VARIABLES **********************************************************/
41
42 LPVOID BaseAddress = NULL;
43 BOOLEAN VdmRunning = TRUE;
44
45 static BOOLEAN A20Line = FALSE;
46 static BYTE Port61hState = 0x00;
47
48 static HANDLE InputThread = NULL;
49
50 LPCWSTR ExceptionName[] =
51 {
52 L"Division By Zero",
53 L"Debug",
54 L"Unexpected Error",
55 L"Breakpoint",
56 L"Integer Overflow",
57 L"Bound Range Exceeded",
58 L"Invalid Opcode",
59 L"FPU Not Available"
60 };
61
62 /* BOP Identifiers */
63 #define BOP_DEBUGGER 0x56 // Break into the debugger from a 16-bit app
64
65 /* PRIVATE FUNCTIONS **********************************************************/
66
67 static inline VOID
68 EmulatorMoveMemory(OUT VOID UNALIGNED *Destination,
69 IN const VOID UNALIGNED *Source,
70 IN SIZE_T Length)
71 {
72 #if 1
73 /*
74 * We use a switch here to detect small moves of memory, as these
75 * constitute the bulk of our moves.
76 * Using RtlMoveMemory for all these small moves would be slow otherwise.
77 */
78 switch (Length)
79 {
80 case 0:
81 return;
82
83 case sizeof(UCHAR):
84 *(PUCHAR)Destination = *(PUCHAR)Source;
85 return;
86
87 case sizeof(USHORT):
88 *(PUSHORT)Destination = *(PUSHORT)Source;
89 return;
90
91 case sizeof(ULONG):
92 *(PULONG)Destination = *(PULONG)Source;
93 return;
94
95 case sizeof(ULONGLONG):
96 *(PULONGLONG)Destination = *(PULONGLONG)Source;
97 return;
98
99 default:
100 #if defined(__GNUC__)
101 __builtin_memmove(Destination, Source, Length);
102 #else
103 RtlMoveMemory(Destination, Source, Length);
104 #endif
105 }
106
107 #else // defined(_MSC_VER)
108
109 PUCHAR Dest = (PUCHAR)Destination;
110 PUCHAR Src = (PUCHAR)Source;
111
112 SIZE_T Count, NewSize = Length;
113
114 /* Move dword */
115 Count = NewSize >> 2; // NewSize / sizeof(ULONG);
116 NewSize = NewSize & 3; // NewSize % sizeof(ULONG);
117 __movsd(Dest, Src, Count);
118 Dest += Count << 2; // Count * sizeof(ULONG);
119 Src += Count << 2;
120
121 /* Move word */
122 Count = NewSize >> 1; // NewSize / sizeof(USHORT);
123 NewSize = NewSize & 1; // NewSize % sizeof(USHORT);
124 __movsw(Dest, Src, Count);
125 Dest += Count << 1; // Count * sizeof(USHORT);
126 Src += Count << 1;
127
128 /* Move byte */
129 Count = NewSize; // NewSize / sizeof(UCHAR);
130 // NewSize = NewSize; // NewSize % sizeof(UCHAR);
131 __movsb(Dest, Src, Count);
132
133 #endif
134 }
135
136 VOID WINAPI EmulatorReadMemory(PFAST486_STATE State, ULONG Address, PVOID Buffer, ULONG Size)
137 {
138 UNREFERENCED_PARAMETER(State);
139
140 // BIG HACK!!!! To make BIOS images working correctly,
141 // until Aleksander rewrites memory management!!
142 if (Address >= 0xFFFFFFF0) Address -= 0xFFF00000;
143
144 /* If the A20 line is disabled, mask bit 20 */
145 if (!A20Line) Address &= ~(1 << 20);
146
147 /* Make sure the requested address is valid */
148 if ((Address + Size) >= MAX_ADDRESS) return;
149
150 /*
151 * Check if we are going to read the VGA memory and
152 * copy it into the virtual address space if needed.
153 */
154 if (((Address + Size) >= VgaGetVideoBaseAddress())
155 && (Address < VgaGetVideoLimitAddress()))
156 {
157 DWORD VgaAddress = max(Address, VgaGetVideoBaseAddress());
158 DWORD ActualSize = min(Address + Size - 1, VgaGetVideoLimitAddress())
159 - VgaAddress + 1;
160 LPBYTE DestBuffer = (LPBYTE)REAL_TO_PHYS(VgaAddress);
161
162 /* Read from the VGA memory */
163 VgaReadMemory(VgaAddress, DestBuffer, ActualSize);
164 }
165
166 /* Read the data from the virtual address space and store it in the buffer */
167 EmulatorMoveMemory(Buffer, REAL_TO_PHYS(Address), Size);
168 }
169
170 VOID WINAPI EmulatorWriteMemory(PFAST486_STATE State, ULONG Address, PVOID Buffer, ULONG Size)
171 {
172 UNREFERENCED_PARAMETER(State);
173
174 // BIG HACK!!!! To make BIOS images working correctly,
175 // until Aleksander rewrites memory management!!
176 if (Address >= 0xFFFFFFF0) Address -= 0xFFF00000;
177
178 /* If the A20 line is disabled, mask bit 20 */
179 if (!A20Line) Address &= ~(1 << 20);
180
181 /* Make sure the requested address is valid */
182 if ((Address + Size) >= MAX_ADDRESS) return;
183
184 /* Make sure we don't write to the ROM area */
185 if ((Address + Size) >= ROM_AREA_START && (Address < ROM_AREA_END)) return;
186
187 /* Read the data from the buffer and store it in the virtual address space */
188 EmulatorMoveMemory(REAL_TO_PHYS(Address), Buffer, Size);
189
190 /*
191 * Check if we modified the VGA memory.
192 */
193 if (((Address + Size) >= VgaGetVideoBaseAddress())
194 && (Address < VgaGetVideoLimitAddress()))
195 {
196 DWORD VgaAddress = max(Address, VgaGetVideoBaseAddress());
197 DWORD ActualSize = min(Address + Size - 1, VgaGetVideoLimitAddress())
198 - VgaAddress + 1;
199 LPBYTE SrcBuffer = (LPBYTE)REAL_TO_PHYS(VgaAddress);
200
201 /* Write to the VGA memory */
202 VgaWriteMemory(VgaAddress, SrcBuffer, ActualSize);
203 }
204 }
205
206 UCHAR WINAPI EmulatorIntAcknowledge(PFAST486_STATE State)
207 {
208 UNREFERENCED_PARAMETER(State);
209
210 /* Get the interrupt number from the PIC */
211 return PicGetInterrupt();
212 }
213
214 VOID EmulatorException(BYTE ExceptionNumber, LPWORD Stack)
215 {
216 WORD CodeSegment, InstructionPointer;
217 PBYTE Opcode;
218
219 ASSERT(ExceptionNumber < 8);
220
221 /* Get the CS:IP */
222 InstructionPointer = Stack[STACK_IP];
223 CodeSegment = Stack[STACK_CS];
224 Opcode = (PBYTE)SEG_OFF_TO_PTR(CodeSegment, InstructionPointer);
225
226 /* Display a message to the user */
227 DisplayMessage(L"Exception: %s occured at %04X:%04X\n"
228 L"Opcode: %02X %02X %02X %02X %02X %02X %02X %02X %02X %02X",
229 ExceptionName[ExceptionNumber],
230 CodeSegment,
231 InstructionPointer,
232 Opcode[0],
233 Opcode[1],
234 Opcode[2],
235 Opcode[3],
236 Opcode[4],
237 Opcode[5],
238 Opcode[6],
239 Opcode[7],
240 Opcode[8],
241 Opcode[9]);
242
243 Fast486DumpState(&EmulatorContext);
244
245 /* Stop the VDM */
246 EmulatorTerminate();
247 return;
248 }
249
250 VOID EmulatorTerminate(VOID)
251 {
252 /* Stop the VDM */
253 CpuUnsimulate(); // Halt the CPU
254 VdmRunning = FALSE;
255 }
256
257 VOID EmulatorInterruptSignal(VOID)
258 {
259 /* Call the Fast486 API */
260 Fast486InterruptSignal(&EmulatorContext);
261 }
262
263 VOID EmulatorSetA20(BOOLEAN Enabled)
264 {
265 A20Line = Enabled;
266 }
267
268 static VOID WINAPI EmulatorDebugBreakBop(LPWORD Stack)
269 {
270 DPRINT1("NTVDM: BOP_DEBUGGER\n");
271 DebugBreak();
272 }
273
274 static BYTE WINAPI Port61hRead(USHORT Port)
275 {
276 return Port61hState;
277 }
278
279 static VOID WINAPI Port61hWrite(USHORT Port, BYTE Data)
280 {
281 // BOOLEAN SpeakerStateChange = FALSE;
282 BYTE OldPort61hState = Port61hState;
283
284 /* Only the four lowest bytes can be written */
285 Port61hState = (Port61hState & 0xF0) | (Data & 0x0F);
286
287 if ((OldPort61hState ^ Port61hState) & 0x01)
288 {
289 DPRINT("PIT 2 Gate %s\n", Port61hState & 0x01 ? "on" : "off");
290 PitSetGate(2, !!(Port61hState & 0x01));
291 // SpeakerStateChange = TRUE;
292 }
293
294 if ((OldPort61hState ^ Port61hState) & 0x02)
295 {
296 /* There were some change for the speaker... */
297 DPRINT("Speaker %s\n", Port61hState & 0x02 ? "on" : "off");
298 // SpeakerStateChange = TRUE;
299 }
300 // if (SpeakerStateChange) SpeakerChange(Port61hState);
301 SpeakerChange(Port61hState);
302 }
303
304 static VOID WINAPI PitChan0Out(LPVOID Param, BOOLEAN State)
305 {
306 if (State)
307 {
308 DPRINT("PicInterruptRequest\n");
309 PicInterruptRequest(0); // Raise IRQ 0
310 }
311 // else < Lower IRQ 0 >
312 }
313
314 static VOID WINAPI PitChan1Out(LPVOID Param, BOOLEAN State)
315 {
316 #if 0
317 if (State)
318 {
319 /* Set bit 4 of Port 61h */
320 Port61hState |= 1 << 4;
321 }
322 else
323 {
324 /* Clear bit 4 of Port 61h */
325 Port61hState &= ~(1 << 4);
326 }
327 #else
328 Port61hState = (Port61hState & 0xEF) | (State << 4);
329 #endif
330 }
331
332 static VOID WINAPI PitChan2Out(LPVOID Param, BOOLEAN State)
333 {
334 BYTE OldPort61hState = Port61hState;
335
336 #if 0
337 if (State)
338 {
339 /* Set bit 5 of Port 61h */
340 Port61hState |= 1 << 5;
341 }
342 else
343 {
344 /* Clear bit 5 of Port 61h */
345 Port61hState &= ~(1 << 5);
346 }
347 #else
348 Port61hState = (Port61hState & 0xDF) | (State << 5);
349 #endif
350
351 if ((OldPort61hState ^ Port61hState) & 0x20)
352 {
353 DPRINT("PitChan2Out -- Port61hState changed\n");
354 SpeakerChange(Port61hState);
355 }
356 }
357
358
359 static DWORD
360 WINAPI
361 PumpConsoleInput(LPVOID Parameter)
362 {
363 HANDLE ConsoleInput = (HANDLE)Parameter;
364 INPUT_RECORD InputRecord;
365 DWORD Count;
366
367 while (VdmRunning)
368 {
369 /* Make sure the task event is signaled */
370 WaitForSingleObject(VdmTaskEvent, INFINITE);
371
372 /* Wait for an input record */
373 if (!ReadConsoleInput(ConsoleInput, &InputRecord, 1, &Count))
374 {
375 DWORD LastError = GetLastError();
376 DPRINT1("Error reading console input (0x%p, %lu) - Error %lu\n", ConsoleInput, Count, LastError);
377 return LastError;
378 }
379
380 ASSERT(Count != 0);
381
382 /* Check the event type */
383 switch (InputRecord.EventType)
384 {
385 /*
386 * Hardware events
387 */
388 case KEY_EVENT:
389 KeyboardEventHandler(&InputRecord.Event.KeyEvent);
390 break;
391
392 case MOUSE_EVENT:
393 MouseEventHandler(&InputRecord.Event.MouseEvent);
394 break;
395
396 case WINDOW_BUFFER_SIZE_EVENT:
397 ScreenEventHandler(&InputRecord.Event.WindowBufferSizeEvent);
398 break;
399
400 /*
401 * Interface events
402 */
403 case MENU_EVENT:
404 MenuEventHandler(&InputRecord.Event.MenuEvent);
405 break;
406
407 case FOCUS_EVENT:
408 FocusEventHandler(&InputRecord.Event.FocusEvent);
409 break;
410
411 default:
412 break;
413 }
414 }
415
416 return 0;
417 }
418
419 static VOID EnableExtraHardware(HANDLE ConsoleInput)
420 {
421 DWORD ConInMode;
422
423 if (GetConsoleMode(ConsoleInput, &ConInMode))
424 {
425 #if 0
426 // GetNumberOfConsoleMouseButtons();
427 // GetSystemMetrics(SM_CMOUSEBUTTONS);
428 // GetSystemMetrics(SM_MOUSEPRESENT);
429 if (MousePresent)
430 {
431 #endif
432 /* Support mouse input events if there is a mouse on the system */
433 ConInMode |= ENABLE_MOUSE_INPUT;
434 #if 0
435 }
436 else
437 {
438 /* Do not support mouse input events if there is no mouse on the system */
439 ConInMode &= ~ENABLE_MOUSE_INPUT;
440 }
441 #endif
442
443 SetConsoleMode(ConsoleInput, ConInMode);
444 }
445 }
446
447 /* PUBLIC FUNCTIONS ***********************************************************/
448
449 static VOID
450 DumpMemoryRaw(HANDLE hFile)
451 {
452 PVOID Buffer;
453 SIZE_T Size;
454
455 /* Dump the VM memory */
456 SetFilePointer(hFile, 0, NULL, FILE_BEGIN);
457 Buffer = REAL_TO_PHYS(NULL);
458 Size = MAX_ADDRESS - (ULONG_PTR)(NULL);
459 WriteFile(hFile, Buffer, Size, &Size, NULL);
460 }
461
462 static VOID
463 DumpMemoryTxt(HANDLE hFile)
464 {
465 #define LINE_SIZE 75 + 2
466 ULONG i;
467 PBYTE Ptr1, Ptr2;
468 CHAR LineBuffer[LINE_SIZE];
469 PCHAR Line;
470 SIZE_T LineSize;
471
472 /* Dump the VM memory */
473 SetFilePointer(hFile, 0, NULL, FILE_BEGIN);
474 Ptr1 = Ptr2 = REAL_TO_PHYS(NULL);
475 while (MAX_ADDRESS - (ULONG_PTR)PHYS_TO_REAL(Ptr1) > 0)
476 {
477 Ptr1 = Ptr2;
478 Line = LineBuffer;
479
480 /* Print the address */
481 Line += snprintf(Line, LINE_SIZE + LineBuffer - Line, "%08x ", PHYS_TO_REAL(Ptr1));
482
483 /* Print up to 16 bytes... */
484
485 /* ... in hexadecimal form first... */
486 i = 0;
487 while (i++ <= 0x0F && (MAX_ADDRESS - (ULONG_PTR)PHYS_TO_REAL(Ptr1) > 0))
488 {
489 Line += snprintf(Line, LINE_SIZE + LineBuffer - Line, " %02x", *Ptr1);
490 ++Ptr1;
491 }
492
493 /* ... align with spaces if needed... */
494 RtlFillMemory(Line, 0x0F + 4 - i, ' ');
495 Line += 0x0F + 4 - i;
496
497 /* ... then in character form. */
498 i = 0;
499 while (i++ <= 0x0F && (MAX_ADDRESS - (ULONG_PTR)PHYS_TO_REAL(Ptr2) > 0))
500 {
501 *Line++ = ((*Ptr2 >= 0x20 && *Ptr2 <= 0x7E) || (*Ptr2 >= 0x80 && *Ptr2 < 0xFF) ? *Ptr2 : '.');
502 ++Ptr2;
503 }
504
505 /* Newline */
506 *Line++ = '\r';
507 *Line++ = '\n';
508
509 /* Finally write the line to the file */
510 LineSize = Line - LineBuffer;
511 WriteFile(hFile, LineBuffer, LineSize, &LineSize, NULL);
512 }
513 }
514
515 VOID DumpMemory(BOOLEAN TextFormat)
516 {
517 static ULONG DumpNumber = 0;
518
519 HANDLE hFile;
520 WCHAR FileName[MAX_PATH];
521
522 /* Build a suitable file name */
523 _snwprintf(FileName, MAX_PATH,
524 L"memdump%lu.%s",
525 DumpNumber,
526 TextFormat ? L"txt" : L"dat");
527 ++DumpNumber;
528
529 DPRINT1("Creating memory dump file '%S'...\n", FileName);
530
531 /* Always create the dump file */
532 hFile = CreateFileW(FileName,
533 GENERIC_WRITE,
534 0,
535 NULL,
536 CREATE_ALWAYS,
537 FILE_ATTRIBUTE_NORMAL,
538 NULL);
539
540 if (hFile == INVALID_HANDLE_VALUE)
541 {
542 DPRINT1("Error when creating '%S' for memory dumping, GetLastError() = %u\n",
543 FileName, GetLastError());
544 return;
545 }
546
547 /* Dump the VM memory in the chosen format */
548 if (TextFormat)
549 DumpMemoryTxt(hFile);
550 else
551 DumpMemoryRaw(hFile);
552
553 /* Close the file */
554 CloseHandle(hFile);
555
556 DPRINT1("Memory dump done\n");
557 }
558
559 BOOLEAN EmulatorInitialize(HANDLE ConsoleInput, HANDLE ConsoleOutput)
560 {
561 #ifdef STANDALONE
562
563 /* Allocate 16 MB memory for the 16-bit address space */
564 BaseAddress = HeapAlloc(GetProcessHeap(), /*HEAP_ZERO_MEMORY*/ 0, MAX_ADDRESS);
565 if (BaseAddress == NULL)
566 {
567 wprintf(L"FATAL: Failed to allocate VDM memory.\n");
568 return FALSE;
569 }
570
571 #else
572
573 NTSTATUS Status;
574 SIZE_T MemorySize = MAX_ADDRESS; // See: kernel32/client/vdm.c!BaseGetVdmConfigInfo
575
576 /*
577 * The reserved region starts from the very first page.
578 * We need to commit the reserved first 16 MB virtual address.
579 */
580 BaseAddress = (PVOID)1; // NULL has another signification for NtAllocateVirtualMemory
581
582 /*
583 * Since to get NULL, we allocated from 0x1, account for this.
584 * See also: kernel32/client/proc.c!CreateProcessInternalW
585 */
586 MemorySize -= 1;
587
588 /* Commit the reserved memory */
589 Status = NtAllocateVirtualMemory(NtCurrentProcess(),
590 &BaseAddress,
591 0,
592 &MemorySize,
593 MEM_COMMIT,
594 PAGE_EXECUTE_READWRITE);
595 if (!NT_SUCCESS(Status))
596 {
597 wprintf(L"FATAL: Failed to commit VDM memory, Status 0x%08lx\n", Status);
598 return FALSE;
599 }
600
601 ASSERT(BaseAddress == NULL);
602
603 #endif
604
605 /*
606 * For diagnostics purposes, we fill the memory with INT 0x03 codes
607 * so that if a program wants to execute random code in memory, we can
608 * retrieve the exact CS:IP where the problem happens.
609 */
610 RtlFillMemory(BaseAddress, MAX_ADDRESS, 0xCC);
611
612 /* Initialize I/O ports */
613 /* Initialize RAM */
614
615 /* Initialize the CPU */
616
617 /* Initialize the internal clock */
618 if (!ClockInitialize())
619 {
620 wprintf(L"FATAL: Failed to initialize the clock\n");
621 EmulatorCleanup();
622 return FALSE;
623 }
624
625 /* Initialize the CPU */
626 CpuInitialize();
627
628 /* Initialize DMA */
629
630 /* Initialize the PIC, the PIT, the CMOS and the PC Speaker */
631 PicInitialize();
632 PitInitialize();
633 CmosInitialize();
634 SpeakerInitialize();
635
636 /* Set output functions */
637 PitSetOutFunction(0, NULL, PitChan0Out);
638 PitSetOutFunction(1, NULL, PitChan1Out);
639 PitSetOutFunction(2, NULL, PitChan2Out);
640
641 /* Register the I/O Ports */
642 RegisterIoPort(CONTROL_SYSTEM_PORT61H, Port61hRead, Port61hWrite);
643
644 /* Set the console input mode */
645 // FIXME: Activate ENABLE_WINDOW_INPUT when we will want to perform actions
646 // upon console window events (screen buffer resize, ...).
647 SetConsoleMode(ConsoleInput, ENABLE_PROCESSED_INPUT /* | ENABLE_WINDOW_INPUT */);
648 // SetConsoleMode(ConsoleOutput, ENABLE_PROCESSED_OUTPUT | ENABLE_WRAP_AT_EOL_OUTPUT);
649
650 /**/EnableExtraHardware(ConsoleInput);/**/
651
652 /* Initialize the PS/2 port */
653 PS2Initialize();
654
655 /* Initialize the keyboard and mouse and connect them to their PS/2 ports */
656 KeyboardInit(0);
657 MouseInit(1);
658
659 /**************** ATTACH INPUT WITH CONSOLE *****************/
660 /* Start the input thread */
661 InputThread = CreateThread(NULL, 0, &PumpConsoleInput, ConsoleInput, 0, NULL);
662 if (InputThread == NULL)
663 {
664 DisplayMessage(L"Failed to create the console input thread.");
665 EmulatorCleanup();
666 return FALSE;
667 }
668 /************************************************************/
669
670 /* Initialize the VGA */
671 if (!VgaInitialize(ConsoleOutput))
672 {
673 DisplayMessage(L"Failed to initialize VGA support.");
674 EmulatorCleanup();
675 return FALSE;
676 }
677
678 /* Initialize the software callback system and register the emulator BOPs */
679 InitializeInt32();
680 RegisterBop(BOP_DEBUGGER , EmulatorDebugBreakBop);
681 // RegisterBop(BOP_UNSIMULATE, CpuUnsimulateBop);
682
683 /* Initialize VDD support */
684 VDDSupInitialize();
685
686 return TRUE;
687 }
688
689 VOID EmulatorCleanup(VOID)
690 {
691 #ifndef STANDALONE
692 NTSTATUS Status;
693 SIZE_T MemorySize = MAX_ADDRESS;
694 #endif
695
696 VgaCleanup();
697
698 /* Close the input thread handle */
699 if (InputThread != NULL) CloseHandle(InputThread);
700 InputThread = NULL;
701
702 PS2Cleanup();
703
704 SpeakerCleanup();
705 CmosCleanup();
706 // PitCleanup();
707 // PicCleanup();
708
709 CpuCleanup();
710
711 #ifdef STANDALONE
712
713 /* Free the memory allocated for the 16-bit address space */
714 if (BaseAddress != NULL) HeapFree(GetProcessHeap(), 0, BaseAddress);
715
716 #else
717
718 /* The reserved region starts from the very first page */
719 // BaseAddress = (PVOID)1;
720
721 /* Since to get NULL, we allocated from 0x1, account for this */
722 MemorySize -= 1;
723
724 Status = NtFreeVirtualMemory(NtCurrentProcess(),
725 &BaseAddress,
726 &MemorySize,
727 MEM_DECOMMIT);
728 if (!NT_SUCCESS(Status))
729 {
730 DPRINT1("NTVDM: Failed to decommit VDM memory, Status 0x%08lx\n", Status);
731 }
732 #endif
733 }
734
735
736
737 VOID
738 WINAPI
739 VDDSimulate16(VOID)
740 {
741 CpuSimulate();
742 }
743
744 VOID
745 WINAPI
746 VDDTerminateVDM(VOID)
747 {
748 /* Stop the VDM */
749 EmulatorTerminate();
750 }
751
752 PBYTE
753 WINAPI
754 Sim32pGetVDMPointer(IN ULONG Address,
755 IN BOOLEAN ProtectedMode)
756 {
757 // FIXME
758 UNREFERENCED_PARAMETER(ProtectedMode);
759
760 /*
761 * HIWORD(Address) == Segment (if ProtectedMode == FALSE)
762 * or Selector (if ProtectedMode == TRUE )
763 * LOWORD(Address) == Offset
764 */
765 return (PBYTE)FAR_POINTER(Address);
766 }
767
768 PBYTE
769 WINAPI
770 MGetVdmPointer(IN ULONG Address,
771 IN ULONG Size,
772 IN BOOLEAN ProtectedMode)
773 {
774 UNREFERENCED_PARAMETER(Size);
775 return Sim32pGetVDMPointer(Address, ProtectedMode);
776 }
777
778 PVOID
779 WINAPI
780 VdmMapFlat(IN USHORT Segment,
781 IN ULONG Offset,
782 IN VDM_MODE Mode)
783 {
784 // FIXME
785 UNREFERENCED_PARAMETER(Mode);
786
787 return SEG_OFF_TO_PTR(Segment, Offset);
788 }
789
790 BOOL
791 WINAPI
792 VdmFlushCache(IN USHORT Segment,
793 IN ULONG Offset,
794 IN ULONG Size,
795 IN VDM_MODE Mode)
796 {
797 // FIXME
798 UNIMPLEMENTED;
799 return TRUE;
800 }
801
802 BOOL
803 WINAPI
804 VdmUnmapFlat(IN USHORT Segment,
805 IN ULONG Offset,
806 IN PVOID Buffer,
807 IN VDM_MODE Mode)
808 {
809 // FIXME
810 UNIMPLEMENTED;
811 return TRUE;
812 }
813
814 /* EOF */