Create a branch for Aleksandar Andrejevic for his work on NTVDM. See http://jira...
[reactos.git] / subsystems / ntvdm / ntvdm.c
1 /*
2 * COPYRIGHT: See COPYING in the top level directory
3 * PROJECT: ReactOS kernel
4 * FILE: subsys/ntvdm/ntvdm->c
5 * PURPOSE: Virtual DOS Machine
6 * PROGRAMMER: Robert Dickenson (robd@mok.lvcm.com)
7 * UPDATE HISTORY:
8 * Created 23/10/2002
9 */
10
11 /* INCLUDES *****************************************************************/
12
13 #include <stdarg.h>
14 #define WIN32_NO_STATUS
15 #include <windef.h>
16 #include <winbase.h>
17 #include <wincon.h>
18 #include <winuser.h>
19 #include <stdio.h>
20
21 #include "resource.h"
22
23 #define NDEBUG
24 #include <debug.h>
25
26 /* GLOBALS ******************************************************************/
27
28
29 /* FUNCTIONS *****************************************************************/
30
31 void PrintString(char* fmt,...)
32 {
33 char buffer[512];
34 va_list ap;
35
36 va_start(ap, fmt);
37 vsprintf(buffer, fmt, ap);
38 va_end(ap);
39
40 OutputDebugStringA(buffer);
41 }
42
43 /*
44 GetVersion
45 GetVolumeInformationW
46 GetWindowsDirectoryA
47 GlobalMemoryStatus
48 HeapAlloc
49 HeapCreate
50 HeapDestroy
51 HeapFree
52 HeapReAlloc
53
54 GetNextVDMCommand
55 ExitVDM
56 RegisterConsoleVDM
57 SetVDMCurrentDirectories
58 VDMConsoleOperation
59 WriteConsoleInputVDMW
60
61 NtSetLdtEntries
62 NtTerminateProcess
63
64 NtMapViewOfSection
65 NtUnmapViewOfSection
66
67 NtVdmControl
68 */
69 typedef struct tag_VDM_CONFIG {
70 int dos_options;
71 int files;
72 int buffers;
73 WCHAR** device_list;
74 //dos=high, umb
75 //device=%SystemRoot%\system32\himem.sys
76 //files=40
77 } VDM_CONFIG, *PVDM_CONFIG;
78
79 typedef struct tag_VDM_AUTOEXEC {
80 WCHAR** load_list;
81 //lh %SystemRoot%\system32\mscdexnt.exe
82 //lh %SystemRoot%\system32\redir
83 //lh %SystemRoot%\system32\dosx
84 } VDM_AUTOEXEC, *PVDM_AUTOEXEC;
85
86 typedef struct tag_VDM_CONTROL_BLOCK {
87 HANDLE hHeap;
88 PVOID ImageMem;
89 VDM_CONFIG vdmConfig;
90 VDM_AUTOEXEC vdmAutoexec;
91 PROCESS_INFORMATION ProcessInformation;
92 CHAR CommandLine[MAX_PATH];
93 CHAR CurrentDirectory[MAX_PATH];
94
95 } VDM_CONTROL_BLOCK, *PVDM_CONTROL_BLOCK;
96
97
98 BOOL
99 StartVDM(PVDM_CONTROL_BLOCK vdm)
100 {
101 BOOL Result;
102 STARTUPINFOA StartupInfo;
103
104 StartupInfo.cb = sizeof(StartupInfo);
105 StartupInfo.lpReserved = NULL;
106 StartupInfo.lpDesktop = NULL;
107 StartupInfo.lpTitle = NULL;
108 StartupInfo.dwFlags = 0;
109 StartupInfo.cbReserved2 = 0;
110 StartupInfo.lpReserved2 = 0;
111
112 Result = CreateProcessA(vdm->CommandLine,
113 NULL,
114 NULL,
115 NULL,
116 FALSE,
117 DETACHED_PROCESS,
118 NULL,
119 NULL,
120 &StartupInfo,
121 &vdm->ProcessInformation);
122 if (!Result) {
123 PrintString("VDM: Failed to execute target process\n");
124 return FALSE;
125 }
126 WaitForSingleObject(vdm->ProcessInformation.hProcess, INFINITE);
127 CloseHandle(vdm->ProcessInformation.hProcess);
128 CloseHandle(vdm->ProcessInformation.hThread);
129 return TRUE;
130 }
131
132 BOOL
133 ShutdownVDM(PVDM_CONTROL_BLOCK vdm)
134 {
135 BOOL result = TRUE;
136
137 return result;
138 }
139
140 BOOL ReadConfigForVDM(PVDM_CONTROL_BLOCK vdm)
141 {
142 BOOL result = TRUE;
143 DWORD dwError;
144 HANDLE hFile;
145
146 hFile = CreateFileW(L"\\system32\\config.nt",
147 GENERIC_READ,
148 FILE_SHARE_READ,
149 NULL,
150 OPEN_ALWAYS /*OPEN_EXISTING*/,
151 FILE_ATTRIBUTE_NORMAL,
152 0);
153 dwError = GetLastError();
154 if (hFile == INVALID_HANDLE_VALUE) {
155 // error with file path or system problem?
156 } else {
157 if (dwError == 0L) {
158 // we just created a new file, perhaps we should set/write some defaults?
159 }
160 if (dwError == ERROR_ALREADY_EXISTS) {
161 // read the line entries and cache in some struct...
162 }
163 CloseHandle(hFile);
164 }
165
166 hFile = CreateFileW(L"\\system32\\autoexec.nt",
167 GENERIC_READ,
168 FILE_SHARE_READ,
169 NULL,
170 OPEN_ALWAYS,
171 FILE_ATTRIBUTE_NORMAL,
172 0);
173 dwError = GetLastError();
174 if (hFile == INVALID_HANDLE_VALUE) {
175 // error with file path or system problem?
176 } else {
177 if (dwError == 0L) {
178 // we just created a new file, perhaps we should set/write some defaults?
179 }
180 if (dwError == ERROR_ALREADY_EXISTS) {
181 // read the line entries and cache in some struct...
182 }
183 CloseHandle(hFile);
184 }
185
186 return result;
187 }
188
189 BOOL
190 LoadConfigDriversForVDM(PVDM_CONFIG vdmConfig)
191 {
192 BOOL result = TRUE;
193
194 return result;
195 }
196
197 BOOL
198 SetConfigOptionsForVDM(PVDM_AUTOEXEC vdmAutoexec)
199 {
200 BOOL result = TRUE;
201
202 return result;
203 }
204
205 BOOL
206 CreateVDM(PVDM_CONTROL_BLOCK vdm)
207 {
208 // BOOL result = TRUE;
209 SYSTEM_INFO inf;
210 MEMORYSTATUS stat;
211
212
213 GlobalMemoryStatus(&stat);
214 if (stat.dwLength != sizeof(MEMORYSTATUS)) {
215 printf("WARNING: GlobalMemoryStatus() returned unknown structure version, size %ld, expected %d.\n", stat.dwLength, sizeof(stat));
216 } else {
217 printf("Memory Load: %ld percent in use.\n", stat.dwMemoryLoad);
218 printf("\t%ld total bytes physical memory.\n", stat.dwTotalPhys);
219 printf("\t%ld available physical memory.\n", stat.dwAvailPhys);
220 printf("\t%ld total bytes paging file.\n", stat.dwTotalPageFile);
221 printf("\t%ld available paging file.\n", stat.dwAvailPageFile);
222 printf("\t%lx total bytes virtual memory.\n", stat.dwTotalVirtual);
223 printf("\t%lx available bytes virtual memory.\n", stat.dwAvailVirtual);
224
225 #define OUT_OF_HEADROOM 90
226 if (stat.dwMemoryLoad > OUT_OF_HEADROOM) {
227 DPRINT("VDM: system resources deemed to low to start VDM.\n");
228 //SetLastError();
229 return FALSE;
230 }
231
232 }
233
234 GetSystemInfo(&inf);
235 vdm->hHeap = HeapCreate(0, inf.dwAllocationGranularity, 0);
236 if (vdm->hHeap == NULL) {
237 DPRINT("VDM: failed to create heap.\n");
238 return FALSE;
239 }
240
241 #define DEFAULT_VDM_IMAGE_SIZE 2000000
242 vdm->ImageMem = HeapAlloc(vdm->hHeap, 0, DEFAULT_VDM_IMAGE_SIZE);
243 if (vdm->ImageMem == NULL) {
244 DPRINT("VDM: failed to allocate image memory from heap %x.\n", vdm->hHeap);
245 HeapDestroy(vdm->hHeap);
246 vdm->hHeap = NULL;
247 return FALSE;
248 }
249 return TRUE;
250 }
251
252 BOOL
253 DestroyVDM(PVDM_CONTROL_BLOCK vdm)
254 {
255 BOOL result = TRUE;
256
257 if (vdm->ImageMem != NULL) {
258 if (HeapFree(vdm->hHeap, 0, vdm->ImageMem) != FALSE) {
259 DPRINT("VDM: failed to free memory from heap %x.\n", vdm->hHeap);
260 result = FALSE;
261 }
262 vdm->ImageMem = NULL;
263 }
264 if (vdm->hHeap != NULL) {
265 if (!HeapDestroy(vdm->hHeap)) {
266 DPRINT("VDM: failed to destroy heap %x.\n", vdm->hHeap);
267 result = FALSE;
268 }
269 vdm->hHeap = NULL;
270 }
271 return result;
272 }
273
274 int WINAPI
275 WinMain(HINSTANCE hInstance, HINSTANCE hPrevInstance, LPSTR lpCmdLine, int nShowCmd)
276 {
277 VDM_CONTROL_BLOCK VdmCB;
278 DWORD Result;
279 ULONG i;
280 BOOL vdmStarted = FALSE;
281
282 WCHAR WelcomeMsg[RC_STRING_MAX_SIZE];
283 WCHAR PromptMsg[RC_STRING_MAX_SIZE];
284 CHAR InputBuffer[255];
285
286 LoadStringW( GetModuleHandle(NULL), STRING_WelcomeMsg, WelcomeMsg,sizeof(WelcomeMsg) / sizeof(WelcomeMsg[0]));
287 LoadStringW( GetModuleHandle(NULL), STRING_PromptMsg, PromptMsg ,sizeof(PromptMsg) / sizeof(PromptMsg[0]));
288
289 AllocConsole();
290 SetConsoleTitleW(L"ntvdm");
291
292 WriteConsoleW(GetStdHandle(STD_OUTPUT_HANDLE),
293 WelcomeMsg, lstrlenW(WelcomeMsg), // wcslen(WelcomeMsg),
294 &Result, NULL);
295
296 if (!CreateVDM(&VdmCB)) {
297 DPRINT("VDM: failed to create VDM.\n");
298 //SetLastError();
299 return 2;
300 }
301
302 ReadConfigForVDM(&VdmCB);
303
304 if (!LoadConfigDriversForVDM(&(VdmCB.vdmConfig))) {
305 DPRINT("VDM: failed to load configuration drivers.\n");
306 //SetLastError();
307 return 2;
308 }
309 if (!SetConfigOptionsForVDM(&(VdmCB.vdmAutoexec))) {
310 DPRINT("VDM: failed to set configuration options.\n");
311 //SetLastError();
312 return 3;
313 }
314
315 GetSystemDirectoryA(VdmCB.CommandLine, MAX_PATH);
316 strcat(VdmCB.CommandLine, "\\hello.exe");
317 GetWindowsDirectoryA(VdmCB.CurrentDirectory, MAX_PATH);
318
319 for (;;) {
320 WriteConsoleW(GetStdHandle(STD_OUTPUT_HANDLE),
321 PromptMsg, lstrlenW(PromptMsg), // wcslen(PromptMsg),
322 &Result, NULL);
323 i = 0;
324 do {
325 ReadConsoleA(GetStdHandle(STD_INPUT_HANDLE),
326 &InputBuffer[i], 1,
327 &Result, NULL);
328 if (++i >= (sizeof(InputBuffer) - 1)) {
329 break;
330 }
331 } while (InputBuffer[i - 1] != '\n');
332 InputBuffer[i - 1] = '\0';
333
334 if (InputBuffer[0] == 'r' || InputBuffer[0] == 'R') {
335 if (!vdmStarted) {
336 if (StartVDM(&VdmCB)) {
337 vdmStarted = TRUE;
338 } else {
339 DPRINT("VDM: failed to start.\n");
340 }
341 } else {
342 DPRINT("VDM: already started.\n");
343 }
344 }
345 if (InputBuffer[0] == 's' || InputBuffer[0] == 'S') {
346 if (vdmStarted) {
347 if (ShutdownVDM(&VdmCB)) {
348 vdmStarted = FALSE;
349 } else {
350 DPRINT("VDM: failed to shutdown.\n");
351 }
352 } else {
353 DPRINT("VDM: not started.\n");
354 }
355 }
356 if (InputBuffer[0] == 'q' || InputBuffer[0] == 'Q') {
357 break;
358 }
359 }
360
361 if (!ShutdownVDM(&VdmCB)) {
362 DPRINT("VDM: failed to cleanly shutdown VDM.\n");
363 //SetLastError();
364 return 5;
365 }
366
367 if (!DestroyVDM(&VdmCB)) {
368 DPRINT("VDM: failed to cleanly destroy VDM.\n");
369 //SetLastError();
370 return 6;
371 }
372
373 ExitProcess(0);
374 return 0;
375 }