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