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