xref: /reactos/subsystems/mvdm/ntvdm/emulator.c (revision 3a49e26f)
1c2c66affSColin Finck /*
2c2c66affSColin Finck  * COPYRIGHT:       GPL - See COPYING in the top level directory
3c2c66affSColin Finck  * PROJECT:         ReactOS Virtual DOS Machine
4c2c66affSColin Finck  * FILE:            subsystems/mvdm/ntvdm/emulator.c
5c2c66affSColin Finck  * PURPOSE:         Minimal x86 machine emulator for the VDM
6c2c66affSColin Finck  * PROGRAMMERS:     Aleksandar Andrejevic <theflash AT sdf DOT lonestar DOT org>
7c2c66affSColin Finck  */
8c2c66affSColin Finck 
9c2c66affSColin Finck /* INCLUDES *******************************************************************/
10c2c66affSColin Finck 
11c2c66affSColin Finck #include "ntvdm.h"
12c2c66affSColin Finck 
13c2c66affSColin Finck #define NDEBUG
14c2c66affSColin Finck #include <debug.h>
15c2c66affSColin Finck 
16c2c66affSColin Finck #include "emulator.h"
17c2c66affSColin Finck #include "memory.h"
18c2c66affSColin Finck 
19c2c66affSColin Finck #include "cpu/callback.h"
20c2c66affSColin Finck #include "cpu/cpu.h"
21c2c66affSColin Finck #include "cpu/bop.h"
22c2c66affSColin Finck #include <isvbop.h>
23c2c66affSColin Finck 
24c2c66affSColin Finck #include "int32.h"
25c2c66affSColin Finck 
26c2c66affSColin Finck #include "clock.h"
27c2c66affSColin Finck #include "bios/rom.h"
28c2c66affSColin Finck #include "hardware/cmos.h"
29c2c66affSColin Finck #include "hardware/disk.h"
30c2c66affSColin Finck #include "hardware/dma.h"
31c2c66affSColin Finck #include "hardware/keyboard.h"
32c2c66affSColin Finck #include "hardware/mouse.h"
33c2c66affSColin Finck #include "hardware/pic.h"
34c2c66affSColin Finck #include "hardware/pit.h"
35c2c66affSColin Finck #include "hardware/ppi.h"
36c2c66affSColin Finck #include "hardware/ps2.h"
37c2c66affSColin Finck #include "hardware/sound/speaker.h"
38c2c66affSColin Finck #include "hardware/video/svga.h"
39c2c66affSColin Finck /**/
40c2c66affSColin Finck #include "./console/video.h"
41c2c66affSColin Finck /**/
42c2c66affSColin Finck 
43c2c66affSColin Finck #include "vddsup.h"
44c2c66affSColin Finck #include "io.h"
45c2c66affSColin Finck 
46c2c66affSColin Finck /* PRIVATE VARIABLES **********************************************************/
47c2c66affSColin Finck 
48c2c66affSColin Finck LPVOID  BaseAddress = NULL;
49c2c66affSColin Finck BOOLEAN VdmRunning  = TRUE;
50c2c66affSColin Finck 
51c2c66affSColin Finck HANDLE VdmTaskEvent = NULL;
52c2c66affSColin Finck static HANDLE InputThread = NULL;
53c2c66affSColin Finck 
54c2c66affSColin Finck LPCWSTR ExceptionName[] =
55c2c66affSColin Finck {
56c2c66affSColin Finck     L"Division By Zero",
57c2c66affSColin Finck     L"Debug",
58c2c66affSColin Finck     L"Unexpected Error",
59c2c66affSColin Finck     L"Breakpoint",
60c2c66affSColin Finck     L"Integer Overflow",
61c2c66affSColin Finck     L"Bound Range Exceeded",
62c2c66affSColin Finck     L"Invalid Opcode",
63c2c66affSColin Finck     L"FPU Not Available"
64c2c66affSColin Finck };
65c2c66affSColin Finck 
66c2c66affSColin Finck /* BOP Identifiers */
67c2c66affSColin Finck #define BOP_DEBUGGER    0x56    // Break into the debugger from a 16-bit app
68c2c66affSColin Finck 
69c2c66affSColin Finck /* PRIVATE FUNCTIONS **********************************************************/
70c2c66affSColin Finck 
EmulatorIntAcknowledge(PFAST486_STATE State)71c2c66affSColin Finck UCHAR FASTCALL EmulatorIntAcknowledge(PFAST486_STATE State)
72c2c66affSColin Finck {
73c2c66affSColin Finck     UNREFERENCED_PARAMETER(State);
74c2c66affSColin Finck 
75c2c66affSColin Finck     /* Get the interrupt number from the PIC */
76c2c66affSColin Finck     return PicGetInterrupt();
77c2c66affSColin Finck }
78c2c66affSColin Finck 
EmulatorFpu(PFAST486_STATE State)79c2c66affSColin Finck VOID FASTCALL EmulatorFpu(PFAST486_STATE State)
80c2c66affSColin Finck {
81c2c66affSColin Finck     /* The FPU is wired to IRQ 13 */
82c2c66affSColin Finck     PicInterruptRequest(13);
83c2c66affSColin Finck }
84c2c66affSColin Finck 
EmulatorException(BYTE ExceptionNumber,LPWORD Stack)85c2c66affSColin Finck VOID EmulatorException(BYTE ExceptionNumber, LPWORD Stack)
86c2c66affSColin Finck {
87c2c66affSColin Finck     WORD CodeSegment, InstructionPointer;
88c2c66affSColin Finck     PBYTE Opcode;
89c2c66affSColin Finck 
90c2c66affSColin Finck     ASSERT(ExceptionNumber < 8);
91c2c66affSColin Finck 
92c2c66affSColin Finck     /* Get the CS:IP */
93c2c66affSColin Finck     InstructionPointer = Stack[STACK_IP];
94c2c66affSColin Finck     CodeSegment = Stack[STACK_CS];
95c2c66affSColin Finck     Opcode = (PBYTE)SEG_OFF_TO_PTR(CodeSegment, InstructionPointer);
96c2c66affSColin Finck 
97c2c66affSColin Finck     /* Display a message to the user */
98c2c66affSColin Finck     DisplayMessage(L"Exception: %s occurred at %04X:%04X\n"
99c2c66affSColin Finck                    L"Opcode: %02X %02X %02X %02X %02X %02X %02X %02X %02X %02X",
100c2c66affSColin Finck                    ExceptionName[ExceptionNumber],
101c2c66affSColin Finck                    CodeSegment,
102c2c66affSColin Finck                    InstructionPointer,
103c2c66affSColin Finck                    Opcode[0],
104c2c66affSColin Finck                    Opcode[1],
105c2c66affSColin Finck                    Opcode[2],
106c2c66affSColin Finck                    Opcode[3],
107c2c66affSColin Finck                    Opcode[4],
108c2c66affSColin Finck                    Opcode[5],
109c2c66affSColin Finck                    Opcode[6],
110c2c66affSColin Finck                    Opcode[7],
111c2c66affSColin Finck                    Opcode[8],
112c2c66affSColin Finck                    Opcode[9]);
113c2c66affSColin Finck 
114c2c66affSColin Finck     Fast486DumpState(&EmulatorContext);
115c2c66affSColin Finck 
116c2c66affSColin Finck     /* Stop the VDM */
117c2c66affSColin Finck     EmulatorTerminate();
118c2c66affSColin Finck }
119c2c66affSColin Finck 
EmulatorInterruptSignal(VOID)120c2c66affSColin Finck VOID EmulatorInterruptSignal(VOID)
121c2c66affSColin Finck {
122c2c66affSColin Finck     /* Call the Fast486 API */
123c2c66affSColin Finck     Fast486InterruptSignal(&EmulatorContext);
124c2c66affSColin Finck }
125c2c66affSColin Finck 
EmulatorDebugBreakBop(LPWORD Stack)126c2c66affSColin Finck static VOID WINAPI EmulatorDebugBreakBop(LPWORD Stack)
127c2c66affSColin Finck {
128c2c66affSColin Finck     DPRINT1("NTVDM: BOP_DEBUGGER\n");
129c2c66affSColin Finck     DebugBreak();
130c2c66affSColin Finck }
131c2c66affSColin Finck 
PitChan0Out(LPVOID Param,BOOLEAN State)132c2c66affSColin Finck static VOID WINAPI PitChan0Out(LPVOID Param, BOOLEAN State)
133c2c66affSColin Finck {
134c2c66affSColin Finck     if (State)
135c2c66affSColin Finck     {
136c2c66affSColin Finck         DPRINT("PicInterruptRequest\n");
137c2c66affSColin Finck         PicInterruptRequest(0); // Raise IRQ 0
138c2c66affSColin Finck     }
139c2c66affSColin Finck     // else < Lower IRQ 0 >
140c2c66affSColin Finck }
141c2c66affSColin Finck 
PitChan1Out(LPVOID Param,BOOLEAN State)142c2c66affSColin Finck static VOID WINAPI PitChan1Out(LPVOID Param, BOOLEAN State)
143c2c66affSColin Finck {
144c2c66affSColin Finck #if 0
145c2c66affSColin Finck     if (State)
146c2c66affSColin Finck     {
147c2c66affSColin Finck         /* Set bit 4 of Port 61h */
148c2c66affSColin Finck         Port61hState |= 1 << 4;
149c2c66affSColin Finck     }
150c2c66affSColin Finck     else
151c2c66affSColin Finck     {
152c2c66affSColin Finck         /* Clear bit 4 of Port 61h */
153c2c66affSColin Finck         Port61hState &= ~(1 << 4);
154c2c66affSColin Finck     }
155c2c66affSColin Finck #else
156c2c66affSColin Finck     Port61hState = (Port61hState & 0xEF) | (State << 4);
157c2c66affSColin Finck #endif
158c2c66affSColin Finck }
159c2c66affSColin Finck 
PitChan2Out(LPVOID Param,BOOLEAN State)160c2c66affSColin Finck static VOID WINAPI PitChan2Out(LPVOID Param, BOOLEAN State)
161c2c66affSColin Finck {
162c2c66affSColin Finck     BYTE OldPort61hState = Port61hState;
163c2c66affSColin Finck 
164c2c66affSColin Finck #if 0
165c2c66affSColin Finck     if (State)
166c2c66affSColin Finck     {
167c2c66affSColin Finck         /* Set bit 5 of Port 61h */
168c2c66affSColin Finck         Port61hState |= 1 << 5;
169c2c66affSColin Finck     }
170c2c66affSColin Finck     else
171c2c66affSColin Finck     {
172c2c66affSColin Finck         /* Clear bit 5 of Port 61h */
173c2c66affSColin Finck         Port61hState &= ~(1 << 5);
174c2c66affSColin Finck     }
175c2c66affSColin Finck #else
176c2c66affSColin Finck     Port61hState = (Port61hState & 0xDF) | (State << 5);
177c2c66affSColin Finck #endif
178c2c66affSColin Finck 
179c2c66affSColin Finck     if ((OldPort61hState ^ Port61hState) & 0x20)
180c2c66affSColin Finck     {
181c2c66affSColin Finck         DPRINT("PitChan2Out -- Port61hState changed\n");
182c2c66affSColin Finck         SpeakerChange(Port61hState);
183c2c66affSColin Finck     }
184c2c66affSColin Finck }
185c2c66affSColin Finck 
186c2c66affSColin Finck 
187c2c66affSColin Finck static DWORD
188c2c66affSColin Finck WINAPI
ConsoleEventThread(LPVOID Parameter)189c2c66affSColin Finck ConsoleEventThread(LPVOID Parameter)
190c2c66affSColin Finck {
191c2c66affSColin Finck     HANDLE ConsoleInput = (HANDLE)Parameter;
192c2c66affSColin Finck     HANDLE WaitHandles[2];
193c2c66affSColin Finck     DWORD  WaitResult;
194c2c66affSColin Finck 
195c2c66affSColin Finck     /*
196c2c66affSColin Finck      * For optimization purposes, Windows (and hence ReactOS, too, for
197c2c66affSColin Finck      * compatibility reasons) uses a static buffer if no more than five
198c2c66affSColin Finck      * input records are read. Otherwise a new buffer is used.
199c2c66affSColin Finck      * The client-side expects that we know this behaviour.
200c2c66affSColin Finck      * See consrv/coninput.c
201c2c66affSColin Finck      *
202c2c66affSColin Finck      * We exploit here this optimization by also using a buffer of 5 records.
203c2c66affSColin Finck      */
204c2c66affSColin Finck     INPUT_RECORD InputRecords[5];
205c2c66affSColin Finck     ULONG NumRecords, i;
206c2c66affSColin Finck 
207c2c66affSColin Finck     WaitHandles[0] = VdmTaskEvent;
208c2c66affSColin Finck     WaitHandles[1] = GetConsoleInputWaitHandle();
209c2c66affSColin Finck 
210c2c66affSColin Finck     while (VdmRunning)
211c2c66affSColin Finck     {
212c2c66affSColin Finck         /* Make sure the task event is signaled */
213c2c66affSColin Finck         WaitResult = WaitForMultipleObjects(ARRAYSIZE(WaitHandles),
214c2c66affSColin Finck                                             WaitHandles,
215c2c66affSColin Finck                                             TRUE,
216c2c66affSColin Finck                                             INFINITE);
217c2c66affSColin Finck         switch (WaitResult)
218c2c66affSColin Finck         {
219c2c66affSColin Finck             case WAIT_OBJECT_0 + 0:
220c2c66affSColin Finck             case WAIT_OBJECT_0 + 1:
221c2c66affSColin Finck                 break;
222c2c66affSColin Finck             default:
223c2c66affSColin Finck                 return GetLastError();
224c2c66affSColin Finck         }
225c2c66affSColin Finck 
226c2c66affSColin Finck         /* Wait for an input record */
227c2c66affSColin Finck         if (!ReadConsoleInputExW(ConsoleInput,
228c2c66affSColin Finck                                  InputRecords,
229c2c66affSColin Finck                                  ARRAYSIZE(InputRecords),
230c2c66affSColin Finck                                  &NumRecords,
231*3a49e26fSHermès Bélusca-Maïto                                  CONSOLE_READ_NOWAIT))
232c2c66affSColin Finck         {
233c2c66affSColin Finck             DWORD LastError = GetLastError();
234c2c66affSColin Finck             DPRINT1("Error reading console input (0x%p, %lu) - Error %lu\n", ConsoleInput, NumRecords, LastError);
235c2c66affSColin Finck             return LastError;
236c2c66affSColin Finck         }
237c2c66affSColin Finck 
238c2c66affSColin Finck         // ASSERT(NumRecords != 0);
239c2c66affSColin Finck         if (NumRecords == 0)
240c2c66affSColin Finck         {
241c2c66affSColin Finck             DPRINT1("Got NumRecords == 0!\n");
242c2c66affSColin Finck             continue;
243c2c66affSColin Finck         }
244c2c66affSColin Finck 
245c2c66affSColin Finck         /* Dispatch the events */
246c2c66affSColin Finck         for (i = 0; i < NumRecords; i++)
247c2c66affSColin Finck         {
248c2c66affSColin Finck             /* Check the event type */
249c2c66affSColin Finck             switch (InputRecords[i].EventType)
250c2c66affSColin Finck             {
251c2c66affSColin Finck                 /*
252c2c66affSColin Finck                  * Hardware events
253c2c66affSColin Finck                  */
254c2c66affSColin Finck                 case KEY_EVENT:
255c2c66affSColin Finck                     KeyboardEventHandler(&InputRecords[i].Event.KeyEvent);
256c2c66affSColin Finck                     break;
257c2c66affSColin Finck 
258c2c66affSColin Finck                 case MOUSE_EVENT:
259c2c66affSColin Finck                     MouseEventHandler(&InputRecords[i].Event.MouseEvent);
260c2c66affSColin Finck                     break;
261c2c66affSColin Finck 
262c2c66affSColin Finck                 case WINDOW_BUFFER_SIZE_EVENT:
263c2c66affSColin Finck                     ScreenEventHandler(&InputRecords[i].Event.WindowBufferSizeEvent);
264c2c66affSColin Finck                     break;
265c2c66affSColin Finck 
266c2c66affSColin Finck                 /*
267c2c66affSColin Finck                  * Interface events
268c2c66affSColin Finck                  */
269c2c66affSColin Finck                 case MENU_EVENT:
270c2c66affSColin Finck                     MenuEventHandler(&InputRecords[i].Event.MenuEvent);
271c2c66affSColin Finck                     break;
272c2c66affSColin Finck 
273c2c66affSColin Finck                 case FOCUS_EVENT:
274c2c66affSColin Finck                     FocusEventHandler(&InputRecords[i].Event.FocusEvent);
275c2c66affSColin Finck                     break;
276c2c66affSColin Finck 
277c2c66affSColin Finck                 default:
278c2c66affSColin Finck                     DPRINT1("Unknown input event type 0x%04x\n", InputRecords[i].EventType);
279c2c66affSColin Finck                     break;
280c2c66affSColin Finck             }
281c2c66affSColin Finck         }
282c2c66affSColin Finck 
283c2c66affSColin Finck         /* Let the console subsystem queue some new events */
284c2c66affSColin Finck         Sleep(10);
285c2c66affSColin Finck     }
286c2c66affSColin Finck 
287c2c66affSColin Finck     return 0;
288c2c66affSColin Finck }
289c2c66affSColin Finck 
PauseEventThread(VOID)290c2c66affSColin Finck static VOID PauseEventThread(VOID)
291c2c66affSColin Finck {
292c2c66affSColin Finck     ResetEvent(VdmTaskEvent);
293c2c66affSColin Finck }
294c2c66affSColin Finck 
ResumeEventThread(VOID)295c2c66affSColin Finck static VOID ResumeEventThread(VOID)
296c2c66affSColin Finck {
297c2c66affSColin Finck     SetEvent(VdmTaskEvent);
298c2c66affSColin Finck }
299c2c66affSColin Finck 
300c2c66affSColin Finck 
301c2c66affSColin Finck /* PUBLIC FUNCTIONS ***********************************************************/
302c2c66affSColin Finck 
303c2c66affSColin Finck static VOID
DumpMemoryRaw(HANDLE hFile)304c2c66affSColin Finck DumpMemoryRaw(HANDLE hFile)
305c2c66affSColin Finck {
306c2c66affSColin Finck     PVOID  Buffer;
30780733143STimo Kreuzer     DWORD Size;
308c2c66affSColin Finck 
309c2c66affSColin Finck     /* Dump the VM memory */
310c2c66affSColin Finck     SetFilePointer(hFile, 0, NULL, FILE_BEGIN);
311c2c66affSColin Finck     Buffer = REAL_TO_PHYS(NULL);
312c2c66affSColin Finck     Size   = MAX_ADDRESS - (ULONG_PTR)(NULL);
313c2c66affSColin Finck     WriteFile(hFile, Buffer, Size, &Size, NULL);
314c2c66affSColin Finck }
315c2c66affSColin Finck 
316c2c66affSColin Finck static VOID
DumpMemoryTxt(HANDLE hFile)317c2c66affSColin Finck DumpMemoryTxt(HANDLE hFile)
318c2c66affSColin Finck {
319c2c66affSColin Finck #define LINE_SIZE   75 + 2
320c2c66affSColin Finck     ULONG  i;
321c2c66affSColin Finck     PBYTE  Ptr1, Ptr2;
322c2c66affSColin Finck     CHAR   LineBuffer[LINE_SIZE];
323c2c66affSColin Finck     PCHAR  Line;
32480733143STimo Kreuzer     DWORD LineSize;
325c2c66affSColin Finck 
326c2c66affSColin Finck     /* Dump the VM memory */
327c2c66affSColin Finck     SetFilePointer(hFile, 0, NULL, FILE_BEGIN);
328c2c66affSColin Finck     Ptr1 = Ptr2 = REAL_TO_PHYS(NULL);
329c2c66affSColin Finck     while (MAX_ADDRESS - (ULONG_PTR)PHYS_TO_REAL(Ptr1) > 0)
330c2c66affSColin Finck     {
331c2c66affSColin Finck         Ptr1 = Ptr2;
332c2c66affSColin Finck         Line = LineBuffer;
333c2c66affSColin Finck 
334c2c66affSColin Finck         /* Print the address */
33580733143STimo Kreuzer         Line += snprintf(Line, LINE_SIZE + LineBuffer - Line, "%08Ix ", (ULONG_PTR)PHYS_TO_REAL(Ptr1));
336c2c66affSColin Finck 
337c2c66affSColin Finck         /* Print up to 16 bytes... */
338c2c66affSColin Finck 
339c2c66affSColin Finck         /* ... in hexadecimal form first... */
340c2c66affSColin Finck         i = 0;
341c2c66affSColin Finck         while (i++ <= 0x0F && (MAX_ADDRESS - (ULONG_PTR)PHYS_TO_REAL(Ptr1) > 0))
342c2c66affSColin Finck         {
343c2c66affSColin Finck             Line += snprintf(Line, LINE_SIZE + LineBuffer - Line, " %02x", *Ptr1);
344c2c66affSColin Finck             ++Ptr1;
345c2c66affSColin Finck         }
346c2c66affSColin Finck 
347c2c66affSColin Finck         /* ... align with spaces if needed... */
348c2c66affSColin Finck         RtlFillMemory(Line, (0x0F + 2 - i) * 3 + 2, ' ');
349c2c66affSColin Finck         Line += (0x0F + 2 - i) * 3 + 2;
350c2c66affSColin Finck 
351c2c66affSColin Finck         /* ... then in character form. */
352c2c66affSColin Finck         i = 0;
353c2c66affSColin Finck         while (i++ <= 0x0F && (MAX_ADDRESS - (ULONG_PTR)PHYS_TO_REAL(Ptr2) > 0))
354c2c66affSColin Finck         {
355c2c66affSColin Finck             *Line++ = ((*Ptr2 >= 0x20 && *Ptr2 <= 0x7E) || (*Ptr2 >= 0x80 && *Ptr2 < 0xFF) ? *Ptr2 : '.');
356c2c66affSColin Finck             ++Ptr2;
357c2c66affSColin Finck         }
358c2c66affSColin Finck 
359c2c66affSColin Finck         /* Newline */
360c2c66affSColin Finck         *Line++ = '\r';
361c2c66affSColin Finck         *Line++ = '\n';
362c2c66affSColin Finck 
363c2c66affSColin Finck         /* Finally write the line to the file */
364c2c66affSColin Finck         LineSize = Line - LineBuffer;
365c2c66affSColin Finck         WriteFile(hFile, LineBuffer, LineSize, &LineSize, NULL);
366c2c66affSColin Finck     }
367c2c66affSColin Finck }
368c2c66affSColin Finck 
DumpMemory(BOOLEAN TextFormat)369c2c66affSColin Finck VOID DumpMemory(BOOLEAN TextFormat)
370c2c66affSColin Finck {
371c2c66affSColin Finck     static ULONG DumpNumber = 0;
372c2c66affSColin Finck 
373c2c66affSColin Finck     HANDLE hFile;
374c2c66affSColin Finck     WCHAR  FileName[MAX_PATH];
375c2c66affSColin Finck 
376c2c66affSColin Finck     /* Build a suitable file name */
377c2c66affSColin Finck     _snwprintf(FileName, MAX_PATH,
378c2c66affSColin Finck                L"memdump%lu.%s",
379c2c66affSColin Finck                DumpNumber,
380c2c66affSColin Finck                TextFormat ? L"txt" : L"dat");
381c2c66affSColin Finck     ++DumpNumber;
382c2c66affSColin Finck 
383c2c66affSColin Finck     DPRINT1("Creating memory dump file '%S'...\n", FileName);
384c2c66affSColin Finck 
385c2c66affSColin Finck     /* Always create the dump file */
386c2c66affSColin Finck     hFile = CreateFileW(FileName,
387c2c66affSColin Finck                         GENERIC_WRITE,
388c2c66affSColin Finck                         0,
389c2c66affSColin Finck                         NULL,
390c2c66affSColin Finck                         CREATE_ALWAYS,
391c2c66affSColin Finck                         FILE_ATTRIBUTE_NORMAL,
392c2c66affSColin Finck                         NULL);
393c2c66affSColin Finck 
394c2c66affSColin Finck     if (hFile == INVALID_HANDLE_VALUE)
395c2c66affSColin Finck     {
396c2c66affSColin Finck         DPRINT1("Error when creating '%S' for memory dumping, GetLastError() = %u\n",
397c2c66affSColin Finck                 FileName, GetLastError());
398c2c66affSColin Finck         return;
399c2c66affSColin Finck     }
400c2c66affSColin Finck 
401c2c66affSColin Finck     /* Dump the VM memory in the chosen format */
402c2c66affSColin Finck     if (TextFormat)
403c2c66affSColin Finck         DumpMemoryTxt(hFile);
404c2c66affSColin Finck     else
405c2c66affSColin Finck         DumpMemoryRaw(hFile);
406c2c66affSColin Finck 
407c2c66affSColin Finck     /* Close the file */
408c2c66affSColin Finck     CloseHandle(hFile);
409c2c66affSColin Finck 
410c2c66affSColin Finck     DPRINT1("Memory dump done\n");
411c2c66affSColin Finck }
412c2c66affSColin Finck 
MountFloppy(IN ULONG DiskNumber)413c2c66affSColin Finck VOID MountFloppy(IN ULONG DiskNumber)
414c2c66affSColin Finck {
415c2c66affSColin Finck // FIXME: This should be present in PSDK commdlg.h
416c2c66affSColin Finck //
417c2c66affSColin Finck // FlagsEx Values
418c2c66affSColin Finck #if (_WIN32_WINNT >= 0x0500)
419c2c66affSColin Finck #define  OFN_EX_NOPLACESBAR         0x00000001
420c2c66affSColin Finck #endif // (_WIN32_WINNT >= 0x0500)
421c2c66affSColin Finck 
422c2c66affSColin Finck     BOOLEAN Success;
423c2c66affSColin Finck     OPENFILENAMEW ofn;
424c2c66affSColin Finck     WCHAR szFile[MAX_PATH] = L"";
425c2c66affSColin Finck 
426c2c66affSColin Finck     ASSERT(DiskNumber < ARRAYSIZE(GlobalSettings.FloppyDisks));
427c2c66affSColin Finck 
428c2c66affSColin Finck     RtlZeroMemory(&ofn, sizeof(ofn));
429c2c66affSColin Finck     ofn.lStructSize  = sizeof(ofn);
430c2c66affSColin Finck     ofn.hwndOwner    = hConsoleWnd;
431c2c66affSColin Finck     ofn.lpstrTitle   = L"Select a virtual floppy image";
432c2c66affSColin Finck     ofn.Flags        = OFN_EXPLORER | OFN_ENABLESIZING | OFN_LONGNAMES | OFN_PATHMUSTEXIST | OFN_FILEMUSTEXIST;
433c2c66affSColin Finck //  ofn.FlagsEx      = OFN_EX_NOPLACESBAR;
434c2c66affSColin Finck     ofn.lpstrFilter  = L"Virtual floppy images (*.vfd;*.img;*.ima;*.dsk)\0*.vfd;*.img;*.ima;*.dsk\0All files (*.*)\0*.*\0\0";
435c2c66affSColin Finck     ofn.lpstrDefExt  = L"vfd";
436c2c66affSColin Finck     ofn.nFilterIndex = 0;
437c2c66affSColin Finck     ofn.lpstrFile    = szFile;
438c2c66affSColin Finck     ofn.nMaxFile     = ARRAYSIZE(szFile);
439c2c66affSColin Finck 
440c2c66affSColin Finck     if (!GetOpenFileNameW(&ofn))
441c2c66affSColin Finck     {
442c2c66affSColin Finck         DPRINT1("CommDlgExtendedError = %d\n", CommDlgExtendedError());
443c2c66affSColin Finck         return;
444c2c66affSColin Finck     }
445c2c66affSColin Finck 
446c2c66affSColin Finck     /* Free the old string */
447c2c66affSColin Finck     if (GlobalSettings.FloppyDisks[DiskNumber].Buffer)
448c2c66affSColin Finck         RtlFreeUnicodeString(&GlobalSettings.FloppyDisks[DiskNumber]);
449c2c66affSColin Finck 
450c2c66affSColin Finck     /* Reinitialize the string */
451c2c66affSColin Finck     Success = RtlCreateUnicodeString(&GlobalSettings.FloppyDisks[DiskNumber], szFile);
452c2c66affSColin Finck     ASSERT(Success);
453c2c66affSColin Finck 
454c2c66affSColin Finck     /* Mount the disk */
455c2c66affSColin Finck     if (!MountDisk(FLOPPY_DISK, DiskNumber, GlobalSettings.FloppyDisks[DiskNumber].Buffer, !!(ofn.Flags & OFN_READONLY)))
456c2c66affSColin Finck     {
457c2c66affSColin Finck         DisplayMessage(L"An error happened when mounting disk %d", DiskNumber);
458c2c66affSColin Finck         RtlFreeUnicodeString(&GlobalSettings.FloppyDisks[DiskNumber]);
459c2c66affSColin Finck         RtlInitEmptyUnicodeString(&GlobalSettings.FloppyDisks[DiskNumber], NULL, 0);
460c2c66affSColin Finck         return;
461c2c66affSColin Finck     }
462c2c66affSColin Finck 
463c2c66affSColin Finck     /* Refresh the menu state */
464c2c66affSColin Finck     UpdateVdmMenuDisks();
465c2c66affSColin Finck }
466c2c66affSColin Finck 
EjectFloppy(IN ULONG DiskNumber)467c2c66affSColin Finck VOID EjectFloppy(IN ULONG DiskNumber)
468c2c66affSColin Finck {
469c2c66affSColin Finck     ASSERT(DiskNumber < ARRAYSIZE(GlobalSettings.FloppyDisks));
470c2c66affSColin Finck 
471c2c66affSColin Finck     /* Unmount the disk */
472c2c66affSColin Finck     if (!UnmountDisk(FLOPPY_DISK, DiskNumber))
473c2c66affSColin Finck         DisplayMessage(L"An error happened when ejecting disk %d", DiskNumber);
474c2c66affSColin Finck 
475c2c66affSColin Finck     /* Free the old string */
476c2c66affSColin Finck     if (GlobalSettings.FloppyDisks[DiskNumber].Buffer)
477c2c66affSColin Finck     {
478c2c66affSColin Finck         RtlFreeUnicodeString(&GlobalSettings.FloppyDisks[DiskNumber]);
479c2c66affSColin Finck         RtlInitEmptyUnicodeString(&GlobalSettings.FloppyDisks[DiskNumber], NULL, 0);
480c2c66affSColin Finck     }
481c2c66affSColin Finck 
482c2c66affSColin Finck     /* Refresh the menu state */
483c2c66affSColin Finck     UpdateVdmMenuDisks();
484c2c66affSColin Finck }
485c2c66affSColin Finck 
486c2c66affSColin Finck 
EmulatorPause(VOID)487c2c66affSColin Finck VOID EmulatorPause(VOID)
488c2c66affSColin Finck {
489c2c66affSColin Finck     /* Pause the VDM */
490c2c66affSColin Finck     VDDBlockUserHook();
491c2c66affSColin Finck     VgaRefreshDisplay();
492c2c66affSColin Finck     PauseEventThread();
493c2c66affSColin Finck }
494c2c66affSColin Finck 
EmulatorResume(VOID)495c2c66affSColin Finck VOID EmulatorResume(VOID)
496c2c66affSColin Finck {
497c2c66affSColin Finck     /* Resume the VDM */
498c2c66affSColin Finck     ResumeEventThread();
499c2c66affSColin Finck     VgaRefreshDisplay();
500c2c66affSColin Finck     VDDResumeUserHook();
501c2c66affSColin Finck }
502c2c66affSColin Finck 
EmulatorTerminate(VOID)503c2c66affSColin Finck VOID EmulatorTerminate(VOID)
504c2c66affSColin Finck {
505c2c66affSColin Finck     /* Stop the VDM */
506c2c66affSColin Finck     CpuUnsimulate(); // Halt the CPU
507c2c66affSColin Finck     VdmRunning = FALSE;
508c2c66affSColin Finck }
509c2c66affSColin Finck 
EmulatorInitialize(HANDLE ConsoleInput,HANDLE ConsoleOutput)510c2c66affSColin Finck BOOLEAN EmulatorInitialize(HANDLE ConsoleInput, HANDLE ConsoleOutput)
511c2c66affSColin Finck {
512c2c66affSColin Finck     USHORT i;
513c2c66affSColin Finck 
514c2c66affSColin Finck     /* Initialize memory */
515c2c66affSColin Finck     if (!MemInitialize())
516c2c66affSColin Finck     {
517c2c66affSColin Finck         wprintf(L"Memory initialization failed.\n");
518c2c66affSColin Finck         return FALSE;
519c2c66affSColin Finck     }
520c2c66affSColin Finck 
521c2c66affSColin Finck     /* Initialize I/O ports */
522c2c66affSColin Finck     /* Initialize RAM */
523c2c66affSColin Finck 
524c2c66affSColin Finck     /* Initialize the CPU */
525c2c66affSColin Finck 
526c2c66affSColin Finck     /* Initialize the internal clock */
527c2c66affSColin Finck     if (!ClockInitialize())
528c2c66affSColin Finck     {
529c2c66affSColin Finck         wprintf(L"FATAL: Failed to initialize the clock\n");
530c2c66affSColin Finck         EmulatorCleanup();
531c2c66affSColin Finck         return FALSE;
532c2c66affSColin Finck     }
533c2c66affSColin Finck 
534c2c66affSColin Finck     /* Initialize the CPU */
535c2c66affSColin Finck     CpuInitialize();
536c2c66affSColin Finck 
537c2c66affSColin Finck     /* Initialize DMA */
538c2c66affSColin Finck     DmaInitialize();
539c2c66affSColin Finck 
540c2c66affSColin Finck     /* Initialize PIC, PIT, CMOS, PC Speaker and PS/2 */
541c2c66affSColin Finck     PicInitialize();
542c2c66affSColin Finck 
543c2c66affSColin Finck     PitInitialize();
544c2c66affSColin Finck     PitSetOutFunction(0, NULL, PitChan0Out);
545c2c66affSColin Finck     PitSetOutFunction(1, NULL, PitChan1Out);
546c2c66affSColin Finck     PitSetOutFunction(2, NULL, PitChan2Out);
547c2c66affSColin Finck 
548c2c66affSColin Finck     CmosInitialize();
549c2c66affSColin Finck     SpeakerInitialize();
550c2c66affSColin Finck     PpiInitialize();
551c2c66affSColin Finck 
552c2c66affSColin Finck     PS2Initialize();
553c2c66affSColin Finck 
554c2c66affSColin Finck     /* Initialize the keyboard and mouse and connect them to their PS/2 ports */
555c2c66affSColin Finck     KeyboardInit(0);
556c2c66affSColin Finck     MouseInit(1);
557c2c66affSColin Finck 
558c2c66affSColin Finck     /**************** ATTACH INPUT WITH CONSOLE *****************/
559c2c66affSColin Finck     /* Create the task event */
560c2c66affSColin Finck     VdmTaskEvent = CreateEventW(NULL, TRUE, FALSE, NULL);
561c2c66affSColin Finck     ASSERT(VdmTaskEvent != NULL);
562c2c66affSColin Finck 
563c2c66affSColin Finck     /* Start the input thread */
564c2c66affSColin Finck     InputThread = CreateThread(NULL, 0, &ConsoleEventThread, ConsoleInput, 0, NULL);
565c2c66affSColin Finck     if (InputThread == NULL)
566c2c66affSColin Finck     {
567c2c66affSColin Finck         wprintf(L"FATAL: Failed to create the console input thread.\n");
568c2c66affSColin Finck         EmulatorCleanup();
569c2c66affSColin Finck         return FALSE;
570c2c66affSColin Finck     }
571c2c66affSColin Finck     ResumeEventThread();
572c2c66affSColin Finck     /************************************************************/
573c2c66affSColin Finck 
574c2c66affSColin Finck     /* Initialize the VGA */
575c2c66affSColin Finck     if (!VgaInitialize(ConsoleOutput))
576c2c66affSColin Finck     {
577c2c66affSColin Finck         wprintf(L"FATAL: Failed to initialize VGA support.\n");
578c2c66affSColin Finck         EmulatorCleanup();
579c2c66affSColin Finck         return FALSE;
580c2c66affSColin Finck     }
581c2c66affSColin Finck 
582c2c66affSColin Finck     /* Initialize the disk controller */
583c2c66affSColin Finck     if (!DiskCtrlInitialize())
584c2c66affSColin Finck     {
585c2c66affSColin Finck         wprintf(L"FATAL: Failed to completely initialize the disk controller.\n");
586c2c66affSColin Finck         EmulatorCleanup();
587c2c66affSColin Finck         return FALSE;
588c2c66affSColin Finck     }
589c2c66affSColin Finck 
590c2c66affSColin Finck     /* Mount the available floppy disks */
591c2c66affSColin Finck     for (i = 0; i < ARRAYSIZE(GlobalSettings.FloppyDisks); ++i)
592c2c66affSColin Finck     {
593c2c66affSColin Finck         if (GlobalSettings.FloppyDisks[i].Length != 0 &&
594c2c66affSColin Finck             GlobalSettings.FloppyDisks[i].Buffer      &&
5955bfe6a53SAndrew Cook            *GlobalSettings.FloppyDisks[i].Buffer != L'\0')
596c2c66affSColin Finck         {
597c2c66affSColin Finck             if (!MountDisk(FLOPPY_DISK, i, GlobalSettings.FloppyDisks[i].Buffer, FALSE))
598c2c66affSColin Finck             {
599c2c66affSColin Finck                 DPRINT1("Failed to mount floppy disk file '%wZ'.\n", &GlobalSettings.FloppyDisks[i]);
600c2c66affSColin Finck                 RtlFreeUnicodeString(&GlobalSettings.FloppyDisks[i]);
601c2c66affSColin Finck                 RtlInitEmptyUnicodeString(&GlobalSettings.FloppyDisks[i], NULL, 0);
602c2c66affSColin Finck             }
603c2c66affSColin Finck         }
604c2c66affSColin Finck     }
605c2c66affSColin Finck 
606c2c66affSColin Finck     /*
607c2c66affSColin Finck      * Mount the available hard disks. Contrary to floppies, failing
608c2c66affSColin Finck      * mounting a hard disk is considered as an unrecoverable error.
609c2c66affSColin Finck      */
610c2c66affSColin Finck     for (i = 0; i < ARRAYSIZE(GlobalSettings.HardDisks); ++i)
611c2c66affSColin Finck     {
612c2c66affSColin Finck         if (GlobalSettings.HardDisks[i].Length != 0 &&
613c2c66affSColin Finck             GlobalSettings.HardDisks[i].Buffer      &&
6145bfe6a53SAndrew Cook            *GlobalSettings.HardDisks[i].Buffer != L'\0')
615c2c66affSColin Finck         {
616c2c66affSColin Finck             if (!MountDisk(HARD_DISK, i, GlobalSettings.HardDisks[i].Buffer, FALSE))
617c2c66affSColin Finck             {
618c2c66affSColin Finck                 wprintf(L"FATAL: Failed to mount hard disk file '%wZ'.\n", &GlobalSettings.HardDisks[i]);
619c2c66affSColin Finck                 EmulatorCleanup();
620c2c66affSColin Finck                 return FALSE;
621c2c66affSColin Finck             }
622c2c66affSColin Finck         }
623c2c66affSColin Finck     }
624c2c66affSColin Finck 
625c2c66affSColin Finck     /* Refresh the menu state */
626c2c66affSColin Finck     UpdateVdmMenuDisks();
627c2c66affSColin Finck 
628c2c66affSColin Finck     /* Initialize the software callback system and register the emulator BOPs */
629c2c66affSColin Finck     InitializeInt32();
630c2c66affSColin Finck     RegisterBop(BOP_DEBUGGER  , EmulatorDebugBreakBop);
631c2c66affSColin Finck     // RegisterBop(BOP_UNSIMULATE, CpuUnsimulateBop);
632c2c66affSColin Finck 
633c2c66affSColin Finck     /* Initialize VDD support */
634c2c66affSColin Finck     VDDSupInitialize();
635c2c66affSColin Finck 
636c2c66affSColin Finck     return TRUE;
637c2c66affSColin Finck }
638c2c66affSColin Finck 
EmulatorCleanup(VOID)639c2c66affSColin Finck VOID EmulatorCleanup(VOID)
640c2c66affSColin Finck {
641c2c66affSColin Finck     DiskCtrlCleanup();
642c2c66affSColin Finck 
643c2c66affSColin Finck     VgaCleanup();
644c2c66affSColin Finck 
645c2c66affSColin Finck     /* Close the input thread handle */
646c2c66affSColin Finck     if (InputThread != NULL) CloseHandle(InputThread);
647c2c66affSColin Finck     InputThread = NULL;
648c2c66affSColin Finck 
649c2c66affSColin Finck     /* Close the task event */
650c2c66affSColin Finck     if (VdmTaskEvent != NULL) CloseHandle(VdmTaskEvent);
651c2c66affSColin Finck     VdmTaskEvent = NULL;
652c2c66affSColin Finck 
653c2c66affSColin Finck     PS2Cleanup();
654c2c66affSColin Finck 
655c2c66affSColin Finck     SpeakerCleanup();
656c2c66affSColin Finck     CmosCleanup();
657c2c66affSColin Finck     // PitCleanup();
658c2c66affSColin Finck     // PicCleanup();
659c2c66affSColin Finck 
660c2c66affSColin Finck     // DmaCleanup();
661c2c66affSColin Finck 
662c2c66affSColin Finck     CpuCleanup();
663c2c66affSColin Finck     MemCleanup();
664c2c66affSColin Finck }
665c2c66affSColin Finck 
666c2c66affSColin Finck 
667c2c66affSColin Finck 
668c2c66affSColin Finck VOID
669c2c66affSColin Finck WINAPI
VDDSimulate16(VOID)670c2c66affSColin Finck VDDSimulate16(VOID)
671c2c66affSColin Finck {
672c2c66affSColin Finck     CpuSimulate();
673c2c66affSColin Finck }
674c2c66affSColin Finck 
675c2c66affSColin Finck VOID
676c2c66affSColin Finck WINAPI
VDDTerminateVDM(VOID)677c2c66affSColin Finck VDDTerminateVDM(VOID)
678c2c66affSColin Finck {
679c2c66affSColin Finck     /* Stop the VDM */
680c2c66affSColin Finck     EmulatorTerminate();
681c2c66affSColin Finck }
682c2c66affSColin Finck 
683c2c66affSColin Finck /* EOF */
684