2 * COPYRIGHT: GPL - See COPYING in the top level directory
3 * PROJECT: ReactOS Virtual DOS Machine
5 * PURPOSE: Virtual DOS Machine
6 * PROGRAMMERS: Aleksandar Andrejevic <theflash AT sdf DOT lonestar DOT org>
9 /* INCLUDES *******************************************************************/
16 #include "bios/bios.h"
18 #include "hardware/cmos.h"
19 #include "hardware/ps2.h"
20 #include "hardware/timer.h"
21 #include "hardware/vga.h"
24 * Activate this line if you want to be able to test NTVDM with:
31 /* PUBLIC VARIABLES ***********************************************************/
33 static HANDLE ConsoleInput
= INVALID_HANDLE_VALUE
;
34 static HANDLE ConsoleOutput
= INVALID_HANDLE_VALUE
;
35 static DWORD OrgConsoleInputMode
, OrgConsoleOutputMode
;
36 static CONSOLE_CURSOR_INFO OrgConsoleCursorInfo
;
37 static CONSOLE_SCREEN_BUFFER_INFO OrgConsoleBufferInfo
;
39 /* PUBLIC FUNCTIONS ***********************************************************/
41 VOID
DisplayMessage(LPCWSTR Format
, ...)
46 va_start(Parameters
, Format
);
47 _vsnwprintf(Buffer
, 256, Format
, Parameters
);
48 DPRINT1("\n\nNTVDM Subsystem\n%S\n\n", Buffer
);
49 MessageBoxW(NULL
, Buffer
, L
"NTVDM Subsystem", MB_OK
);
53 BOOL WINAPI
ConsoleCtrlHandler(DWORD ControlType
)
58 case CTRL_BREAK_EVENT
:
61 EmulatorInterrupt(0x23);
66 /* Stop the VDM if the user logs out or closes the console */
73 BOOL
ConsoleInit(VOID
)
75 /* Set the handler routine */
76 SetConsoleCtrlHandler(ConsoleCtrlHandler
, TRUE
);
78 /* Get the input handle to the real console, and check for success */
79 ConsoleInput
= CreateFileW(L
"CONIN$",
80 GENERIC_READ
| GENERIC_WRITE
,
81 FILE_SHARE_READ
| FILE_SHARE_WRITE
,
86 if (ConsoleInput
== INVALID_HANDLE_VALUE
)
88 wprintf(L
"FATAL: Cannot retrieve a handle to the console input\n");
92 /* Get the output handle to the real console, and check for success */
93 ConsoleOutput
= CreateFileW(L
"CONOUT$",
94 GENERIC_READ
| GENERIC_WRITE
,
95 FILE_SHARE_READ
| FILE_SHARE_WRITE
,
100 if (ConsoleOutput
== INVALID_HANDLE_VALUE
)
102 CloseHandle(ConsoleInput
);
103 wprintf(L
"FATAL: Cannot retrieve a handle to the console output\n");
107 /* Save the original input and output console modes */
108 if (!GetConsoleMode(ConsoleInput
, &OrgConsoleInputMode
) ||
109 !GetConsoleMode(ConsoleOutput
, &OrgConsoleOutputMode
))
111 CloseHandle(ConsoleOutput
);
112 CloseHandle(ConsoleInput
);
113 wprintf(L
"FATAL: Cannot save console in/out modes\n");
117 /* Save the original cursor and console screen buffer information */
118 if (!GetConsoleCursorInfo(ConsoleOutput
, &OrgConsoleCursorInfo
) ||
119 !GetConsoleScreenBufferInfo(ConsoleOutput
, &OrgConsoleBufferInfo
))
121 CloseHandle(ConsoleOutput
);
122 CloseHandle(ConsoleInput
);
123 wprintf(L
"FATAL: Cannot save console cursor/screen-buffer info\n");
130 VOID
ConsoleCleanup(VOID
)
133 CONSOLE_SCREEN_BUFFER_INFO ConsoleInfo
;
135 /* Restore the old screen buffer */
136 SetConsoleActiveScreenBuffer(ConsoleOutput
);
138 /* Restore the original console size */
139 GetConsoleScreenBufferInfo(ConsoleOutput
, &ConsoleInfo
);
140 ConRect
.Left
= 0; // OrgConsoleBufferInfo.srWindow.Left;
141 // ConRect.Top = ConsoleInfo.dwCursorPosition.Y / (OrgConsoleBufferInfo.srWindow.Bottom - OrgConsoleBufferInfo.srWindow.Top + 1);
142 // ConRect.Top *= (OrgConsoleBufferInfo.srWindow.Bottom - OrgConsoleBufferInfo.srWindow.Top + 1);
143 ConRect
.Top
= ConsoleInfo
.dwCursorPosition
.Y
;
144 ConRect
.Right
= ConRect
.Left
+ OrgConsoleBufferInfo
.srWindow
.Right
- OrgConsoleBufferInfo
.srWindow
.Left
;
145 ConRect
.Bottom
= ConRect
.Top
+ OrgConsoleBufferInfo
.srWindow
.Bottom
- OrgConsoleBufferInfo
.srWindow
.Top
;
146 /* See the following trick explanation in vga.c:VgaEnterTextMode() */
147 SetConsoleScreenBufferSize(ConsoleOutput
, OrgConsoleBufferInfo
.dwSize
);
148 SetConsoleWindowInfo(ConsoleOutput
, TRUE
, &ConRect
);
149 // SetConsoleWindowInfo(ConsoleOutput, TRUE, &OrgConsoleBufferInfo.srWindow);
150 SetConsoleScreenBufferSize(ConsoleOutput
, OrgConsoleBufferInfo
.dwSize
);
152 /* Restore the original cursor shape */
153 SetConsoleCursorInfo(ConsoleOutput
, &OrgConsoleCursorInfo
);
155 /* Restore the original input and output console modes */
156 SetConsoleMode(ConsoleOutput
, OrgConsoleOutputMode
);
157 SetConsoleMode(ConsoleInput
, OrgConsoleInputMode
);
159 /* Close the console handles */
160 if (ConsoleOutput
!= INVALID_HANDLE_VALUE
) CloseHandle(ConsoleOutput
);
161 if (ConsoleInput
!= INVALID_HANDLE_VALUE
) CloseHandle(ConsoleInput
);
164 INT
wmain(INT argc
, WCHAR
*argv
[])
167 CHAR CommandLine
[DOS_CMDLINE_LENGTH
];
168 LARGE_INTEGER StartPerfCount
;
169 LARGE_INTEGER Frequency
, LastTimerTick
, LastRtcTick
, Counter
;
171 DWORD StartTickCount
, CurrentTickCount
;
172 DWORD LastClockUpdate
;
173 DWORD LastVerticalRefresh
;
175 DWORD LastCyclePrintout
;
178 INT KeyboardIntCounter
= 0;
181 UNREFERENCED_PARAMETER(argc
);
182 UNREFERENCED_PARAMETER(argv
);
184 /* The DOS command line must be ASCII */
185 WideCharToMultiByte(CP_ACP
, 0, GetCommandLine(), -1, CommandLine
, sizeof(CommandLine
), NULL
, NULL
);
187 if (argc
== 2 && argv
[1] != NULL
)
189 WideCharToMultiByte(CP_ACP
, 0, argv
[1], -1, CommandLine
, sizeof(CommandLine
), NULL
, NULL
);
193 wprintf(L
"\nReactOS Virtual DOS Machine\n\n"
194 L
"Usage: NTVDM <executable>\n");
199 DPRINT1("\n\n\nNTVDM - Starting '%s'...\n\n\n", CommandLine
);
201 /* Initialize the console */
204 wprintf(L
"FATAL: A problem occurred when trying to initialize the console\n");
208 /* Initialize the emulator */
209 if (!EmulatorInitialize(ConsoleInput
, ConsoleOutput
))
211 wprintf(L
"FATAL: Failed to initialize the emulator\n");
215 /* Initialize the performance counter (needed for hardware timers) */
216 if (!QueryPerformanceFrequency(&Frequency
))
218 wprintf(L
"FATAL: Performance counter not available\n");
222 /* Initialize the system BIOS */
223 if (!BiosInitialize(ConsoleInput
, ConsoleOutput
))
225 wprintf(L
"FATAL: Failed to initialize the VDM BIOS.\n");
229 /* Initialize the VDM DOS kernel */
230 if (!DosInitialize(NULL
))
232 wprintf(L
"FATAL: Failed to initialize the VDM DOS kernel.\n");
236 /* Start the process from the command line */
237 if (!DosCreateProcess(CommandLine
, 0))
239 DisplayMessage(L
"Could not start program: %S", CommandLine
);
243 /* Find the starting performance and tick count */
244 StartTickCount
= GetTickCount();
245 QueryPerformanceCounter(&StartPerfCount
);
247 /* Set the different last counts to the starting count */
248 LastClockUpdate
= LastVerticalRefresh
=
254 /* Set the last timer ticks to the current time */
255 LastTimerTick
= LastRtcTick
= StartPerfCount
;
260 DWORD PitResolution
= PitGetResolution();
261 DWORD RtcFrequency
= RtcGetTicksPerSecond();
263 /* Get the current number of ticks */
264 CurrentTickCount
= GetTickCount();
266 if ((PitResolution
<= 1000) && (RtcFrequency
<= 1000))
268 /* Calculate the approximate performance counter value instead */
269 Counter
.QuadPart
= StartPerfCount
.QuadPart
270 + (CurrentTickCount
- StartTickCount
)
271 * (Frequency
.QuadPart
/ 1000);
275 /* Get the current performance counter value */
276 QueryPerformanceCounter(&Counter
);
279 /* Get the number of PIT ticks that have passed */
280 TimerTicks
= ((Counter
.QuadPart
- LastTimerTick
.QuadPart
)
281 * PIT_BASE_FREQUENCY
) / Frequency
.QuadPart
;
286 PitClock(TimerTicks
);
287 LastTimerTick
= Counter
;
290 /* Check for RTC update */
291 if ((CurrentTickCount
- LastClockUpdate
) >= 1000)
294 LastClockUpdate
= CurrentTickCount
;
297 /* Check for RTC periodic tick */
298 if ((Counter
.QuadPart
- LastRtcTick
.QuadPart
)
299 >= (Frequency
.QuadPart
/ (LONGLONG
)RtcFrequency
))
302 LastRtcTick
= Counter
;
305 /* Check for vertical retrace */
306 if ((CurrentTickCount
- LastVerticalRefresh
) >= 15)
309 LastVerticalRefresh
= CurrentTickCount
;
312 KeyboardIntCounter
++;
313 if (KeyboardIntCounter
== KBD_INT_CYCLES
)
315 GenerateKeyboardInterrupts();
316 KeyboardIntCounter
= 0;
319 /* Horizontal retrace occurs as fast as possible */
320 VgaHorizontalRetrace();
322 /* Continue CPU emulation */
323 for (i
= 0; (i
< STEPS_PER_CYCLE
) && VdmRunning
; i
++)
332 if ((CurrentTickCount
- LastCyclePrintout
) >= 1000)
334 DPRINT1("NTVDM: %lu Instructions Per Second\n", Cycles
);
335 LastCyclePrintout
= CurrentTickCount
;
341 /* Perform another screen refresh */
349 DPRINT1("\n\n\nNTVDM - Exiting...\n\n\n");