[KERNEL32]
[reactos.git] / subsystems / ntvdm / ntvdm.c
1 /*
2 * COPYRIGHT: GPL - See COPYING in the top level directory
3 * PROJECT: ReactOS Virtual DOS Machine
4 * FILE: ntvdm.c
5 * PURPOSE: Virtual DOS Machine
6 * PROGRAMMERS: Aleksandar Andrejevic <theflash AT sdf DOT lonestar DOT org>
7 */
8
9 #include "ntvdm.h"
10
11 BOOLEAN VdmRunning = TRUE;
12 LPVOID BaseAddress = NULL;
13 LPCWSTR ExceptionName[] =
14 {
15 L"Division By Zero",
16 L"Debug",
17 L"Unexpected Error",
18 L"Breakpoint",
19 L"Integer Overflow",
20 L"Bound Range Exceeded",
21 L"Invalid Opcode",
22 L"FPU Not Available"
23 };
24
25 VOID DisplayMessage(LPCWSTR Format, ...)
26 {
27 WCHAR Buffer[256];
28 va_list Parameters;
29
30 va_start(Parameters, Format);
31 _vsnwprintf(Buffer, 256, Format, Parameters);
32 MessageBox(NULL, Buffer, L"NTVDM Subsystem", MB_OK);
33 va_end(Parameters);
34 }
35
36 BOOL WINAPI ConsoleCtrlHandler(DWORD ControlType)
37 {
38 switch (ControlType)
39 {
40 case CTRL_C_EVENT:
41 case CTRL_BREAK_EVENT:
42 {
43 /* Perform interrupt 0x23 */
44 EmulatorInterrupt(0x23);
45 }
46 default:
47 {
48 /* Stop the VDM if the user logs out or closes the console */
49 VdmRunning = FALSE;
50 }
51 }
52 return TRUE;
53 }
54
55 INT wmain(INT argc, WCHAR *argv[])
56 {
57 INT i;
58 CHAR CommandLine[128];
59 DWORD CurrentTickCount, LastTickCount = 0, Cycles = 0, LastCyclePrintout = 0;
60 LARGE_INTEGER Frequency, LastTimerTick, Counter;
61 LONGLONG TimerTicks;
62
63 /* Set the handler routine */
64 SetConsoleCtrlHandler(ConsoleCtrlHandler, TRUE);
65
66 /* The DOS command line must be ASCII */
67 WideCharToMultiByte(CP_ACP, 0, GetCommandLine(), -1, CommandLine, 128, NULL, NULL);
68
69 if (!EmulatorInitialize()) return 1;
70
71 /* Initialize the performance counter (needed for hardware timers) */
72 if (!QueryPerformanceFrequency(&Frequency))
73 {
74 wprintf(L"FATAL: Performance counter not available\n");
75 goto Cleanup;
76 }
77
78 /* Initialize the system BIOS */
79 if (!BiosInitialize())
80 {
81 wprintf(L"FATAL: Failed to initialize the VDM BIOS.\n");
82 goto Cleanup;
83 }
84
85 /* Initialize the VDM DOS kernel */
86 if (!DosInitialize())
87 {
88 wprintf(L"FATAL: Failed to initialize the VDM DOS kernel.\n");
89 goto Cleanup;
90 }
91
92 /* Start the process from the command line */
93 if (!DosCreateProcess(CommandLine, 0))
94 {
95 DisplayMessage(L"Could not start program: %S", CommandLine);
96 return -1;
97 }
98
99 /* Set the last timer tick to the current time */
100 QueryPerformanceCounter(&LastTimerTick);
101
102 /* Main loop */
103 while (VdmRunning)
104 {
105 /* Get the current number of ticks */
106 CurrentTickCount = GetTickCount();
107
108 /* Get the current performance counter value */
109 QueryPerformanceCounter(&Counter);
110
111 /* Get the number of PIT ticks that have passed */
112 TimerTicks = ((Counter.QuadPart - LastTimerTick.QuadPart)
113 * PIT_BASE_FREQUENCY) / Frequency.QuadPart;
114
115 /* Update the PIT */
116 for (i = 0; i < TimerTicks; i++) PitDecrementCount();
117 LastTimerTick = Counter;
118
119 /* Check for console input events every millisecond */
120 if (CurrentTickCount != LastTickCount)
121 {
122 CheckForInputEvents();
123 LastTickCount = CurrentTickCount;
124 }
125
126 /* Continue CPU emulation */
127 for (i = 0; i < STEPS_PER_CYCLE; i++) EmulatorStep();
128
129 Cycles += STEPS_PER_CYCLE;
130 if ((CurrentTickCount - LastCyclePrintout) >= 1000)
131 {
132 DPRINT1("NTVDM: %d Instructions Per Second\n", Cycles);
133 LastCyclePrintout = CurrentTickCount;
134 Cycles = 0;
135 }
136 }
137
138 Cleanup:
139 EmulatorCleanup();
140
141 return 0;
142 }
143
144 /* EOF */