[NTVDM]
[reactos.git] / reactos / subsystems / ntvdm / dos / dem.c
1 /*
2 * COPYRIGHT: GPL - See COPYING in the top level directory
3 * PROJECT: ReactOS Virtual DOS Machine
4 * FILE: dem.c
5 * PURPOSE: DOS 32-bit Emulation Support Library -
6 * This library is used by the built-in NTVDM DOS32 and by
7 * the NT 16-bit DOS in Windows (via BOPs). It also exposes
8 * exported functions that can be used by VDDs.
9 * PROGRAMMERS: Aleksandar Andrejevic <theflash AT sdf DOT lonestar DOT org>
10 * Hermes Belusca-Maito (hermes.belusca@sfr.fr)
11 */
12
13 /* INCLUDES *******************************************************************/
14
15 #define NDEBUG
16
17 #include "emulator.h"
18 #include "utils.h"
19
20 #include "dem.h"
21 #include "cpu/bop.h"
22
23 #include "bios/bios.h"
24 #include "mouse32.h"
25
26 /* Extra PSDK/NDK Headers */
27 #include <ndk/obtypes.h>
28
29 /* PRIVATE VARIABLES **********************************************************/
30
31 /**/extern BYTE CurrentDrive;/**/
32
33 /* DEFINES ********************************************************************/
34
35 /* BOP Identifiers */
36 #define BOP_DOS 0x50 // DOS System BOP (for NTIO.SYS and NTDOS.SYS)
37 #define BOP_CMD 0x54 // DOS Command Interpreter BOP (for COMMAND.COM)
38
39 /* PRIVATE FUNCTIONS **********************************************************/
40
41 static VOID WINAPI DosSystemBop(LPWORD Stack)
42 {
43 /* Get the Function Number and skip it */
44 BYTE FuncNum = *(PBYTE)SEG_OFF_TO_PTR(getCS(), getIP());
45 setIP(getIP() + 1);
46
47 switch (FuncNum)
48 {
49 case 0x11: // Load the DOS kernel
50 {
51 BOOLEAN Success = FALSE;
52 HANDLE hDosKernel;
53 ULONG ulDosKernelSize = 0;
54
55 DPRINT1("You are loading Windows NT DOS!\n");
56
57 /* Open the DOS kernel file */
58 hDosKernel = FileOpen("ntdos.sys", &ulDosKernelSize);
59
60 /* If we failed, bail out */
61 if (hDosKernel == NULL) goto Quit;
62
63 /*
64 * Attempt to load the DOS kernel into memory.
65 * The segment where to load the DOS kernel is defined
66 * by the DOS BIOS and is found in DI:0000 .
67 */
68 Success = FileLoadByHandle(hDosKernel,
69 REAL_TO_PHYS(TO_LINEAR(getDI(), 0x0000)),
70 ulDosKernelSize,
71 &ulDosKernelSize);
72
73 DPRINT1("Windows NT DOS loading %s at 0x%04X:0x%04X, size 0x%x ; GetLastError() = %u\n",
74 (Success ? "succeeded" : "failed"),
75 getDI(), 0x0000,
76 ulDosKernelSize,
77 GetLastError());
78
79 /* Close the DOS kernel file */
80 FileClose(hDosKernel);
81
82 Quit:
83 if (!Success)
84 {
85 /* We failed everything, stop the VDM */
86 EmulatorTerminate();
87 }
88
89 break;
90 }
91
92 default:
93 {
94 DPRINT1("Unknown DOS System BOP Function: 0x%02X\n", FuncNum);
95 // setCF(1); // Disable, otherwise we enter an infinite loop
96 break;
97 }
98 }
99 }
100
101 static VOID WINAPI DosCmdInterpreterBop(LPWORD Stack)
102 {
103 /* Get the Function Number and skip it */
104 BYTE FuncNum = *(PBYTE)SEG_OFF_TO_PTR(getCS(), getIP());
105 setIP(getIP() + 1);
106
107 switch (FuncNum)
108 {
109 case 0x08: // Launch external command
110 {
111 #define CMDLINE_LENGTH 1024
112
113 BOOL Result;
114 DWORD dwExitCode;
115
116 LPSTR Command = (LPSTR)SEG_OFF_TO_PTR(getDS(), getSI());
117 LPSTR CmdPtr = Command;
118 CHAR CommandLine[CMDLINE_LENGTH] = "";
119 STARTUPINFOA StartupInfo;
120 PROCESS_INFORMATION ProcessInformation;
121
122 /* NULL-terminate the command line by removing the return carriage character */
123 while (*CmdPtr && *CmdPtr != '\r') CmdPtr++;
124 *CmdPtr = '\0';
125
126 DPRINT1("CMD Run Command '%s'\n", Command);
127
128 /* Spawn a user-defined 32-bit command preprocessor */
129
130 /* Build the command line */
131 // FIXME: Use COMSPEC env var!!
132 strcpy(CommandLine, "cmd.exe /c ");
133 strcat(CommandLine, Command);
134
135 ZeroMemory(&StartupInfo, sizeof(StartupInfo));
136 ZeroMemory(&ProcessInformation, sizeof(ProcessInformation));
137
138 StartupInfo.cb = sizeof(StartupInfo);
139
140 VidBiosDetachFromConsole();
141
142 Result = CreateProcessA(NULL,
143 CommandLine,
144 NULL,
145 NULL,
146 TRUE,
147 0,
148 NULL,
149 NULL,
150 &StartupInfo,
151 &ProcessInformation);
152 if (Result)
153 {
154 DPRINT1("Command '%s' launched successfully\n", Command);
155
156 /* Wait for process termination */
157 WaitForSingleObject(ProcessInformation.hProcess, INFINITE);
158
159 /* Get the exit code */
160 GetExitCodeProcess(ProcessInformation.hProcess, &dwExitCode);
161
162 /* Close handles */
163 CloseHandle(ProcessInformation.hThread);
164 CloseHandle(ProcessInformation.hProcess);
165 }
166 else
167 {
168 DPRINT1("Failed when launched command '%s'\n");
169 dwExitCode = GetLastError();
170 }
171
172 VidBiosAttachToConsole();
173
174 setAL((UCHAR)dwExitCode);
175
176 break;
177 }
178
179 default:
180 {
181 DPRINT1("Unknown DOS CMD Interpreter BOP Function: 0x%02X\n", FuncNum);
182 // setCF(1); // Disable, otherwise we enter an infinite loop
183 break;
184 }
185 }
186 }
187
188 /* PUBLIC FUNCTIONS ***********************************************************/
189
190 BOOLEAN DosInitialize(IN LPCSTR DosKernelFileName)
191 {
192 /* Register the DOS BOPs */
193 RegisterBop(BOP_DOS, DosSystemBop );
194 RegisterBop(BOP_CMD, DosCmdInterpreterBop);
195
196 if (DosKernelFileName)
197 {
198 BOOLEAN Success;
199 HANDLE hDosBios;
200 ULONG ulDosBiosSize = 0;
201
202 /* Open the DOS BIOS file */
203 hDosBios = FileOpen(DosKernelFileName, &ulDosBiosSize);
204
205 /* If we failed, bail out */
206 if (hDosBios == NULL) return FALSE;
207
208 /* Attempt to load the DOS BIOS into memory */
209 Success = FileLoadByHandle(hDosBios,
210 REAL_TO_PHYS(TO_LINEAR(0x0070, 0x0000)),
211 ulDosBiosSize,
212 &ulDosBiosSize);
213
214 DPRINT1("DOS BIOS loading %s at 0x%04X:0x%04X, size 0x%x ; GetLastError() = %u\n",
215 (Success ? "succeeded" : "failed"),
216 0x0070, 0x0000,
217 ulDosBiosSize,
218 GetLastError());
219
220 /* Close the DOS BIOS file */
221 FileClose(hDosBios);
222
223 if (Success)
224 {
225 /* Position execution pointers and return */
226 setCS(0x0070);
227 setIP(0x0000);
228 }
229
230 return Success;
231 }
232 else
233 {
234 BOOLEAN Result;
235
236 Result = DosBIOSInitialize();
237 DosMouseInitialize(); // FIXME: Should be done by the DOS BIOS
238 // Result &= DosKRNLInitialize();
239
240 return Result;
241 }
242 }
243
244 /* PUBLIC EXPORTED APIS *******************************************************/
245
246 // demLFNCleanup
247 // demLFNGetCurrentDirectory
248
249 // demGetFileTimeByHandle_WOW
250 // demWOWLFNAllocateSearchHandle
251 // demWOWLFNCloseSearchHandle
252 // demWOWLFNEntry
253 // demWOWLFNGetSearchHandle
254 // demWOWLFNInit
255
256 DWORD
257 WINAPI
258 demClientErrorEx(IN HANDLE FileHandle,
259 IN CHAR Unknown,
260 IN BOOL Flag)
261 {
262 UNIMPLEMENTED;
263 return GetLastError();
264 }
265
266 DWORD
267 WINAPI
268 demFileDelete(IN LPCSTR FileName)
269 {
270 if (DeleteFileA(FileName)) SetLastError(ERROR_SUCCESS);
271
272 return GetLastError();
273 }
274
275 DWORD
276 WINAPI
277 demFileFindFirst(OUT PVOID lpFindFileData,
278 IN LPCSTR FileName,
279 IN WORD AttribMask)
280 {
281 BOOLEAN Success = TRUE;
282 WIN32_FIND_DATAA FindData;
283 PDOS_FIND_FILE_BLOCK FindFileBlock = (PDOS_FIND_FILE_BLOCK)lpFindFileData;
284
285 /* Fill the block */
286 FindFileBlock->DriveLetter = CurrentDrive + 'A';
287 FindFileBlock->AttribMask = AttribMask;
288 FindFileBlock->SearchHandle = FindFirstFileA(FileName, &FindData);
289 if (FindFileBlock->SearchHandle == INVALID_HANDLE_VALUE) return GetLastError();
290
291 do
292 {
293 /* Check the attributes */
294 if (!((FindData.dwFileAttributes & (FILE_ATTRIBUTE_HIDDEN |
295 FILE_ATTRIBUTE_SYSTEM |
296 FILE_ATTRIBUTE_DIRECTORY))
297 & ~AttribMask))
298 {
299 break;
300 }
301 }
302 while ((Success = FindNextFileA(FindFileBlock->SearchHandle, &FindData)));
303
304 if (!Success) return GetLastError();
305
306 FindFileBlock->Attributes = LOBYTE(FindData.dwFileAttributes);
307 FileTimeToDosDateTime(&FindData.ftLastWriteTime,
308 &FindFileBlock->FileDate,
309 &FindFileBlock->FileTime);
310 FindFileBlock->FileSize = FindData.nFileSizeHigh ? 0xFFFFFFFF
311 : FindData.nFileSizeLow;
312 strcpy(FindFileBlock->FileName, FindData.cAlternateFileName);
313
314 return ERROR_SUCCESS;
315 }
316
317 DWORD
318 WINAPI
319 demFileFindNext(OUT PVOID lpFindFileData)
320 {
321 WIN32_FIND_DATAA FindData;
322 PDOS_FIND_FILE_BLOCK FindFileBlock = (PDOS_FIND_FILE_BLOCK)lpFindFileData;
323
324 do
325 {
326 if (!FindNextFileA(FindFileBlock->SearchHandle, &FindData))
327 return GetLastError();
328
329 /* Update the block */
330 FindFileBlock->Attributes = LOBYTE(FindData.dwFileAttributes);
331 FileTimeToDosDateTime(&FindData.ftLastWriteTime,
332 &FindFileBlock->FileDate,
333 &FindFileBlock->FileTime);
334 FindFileBlock->FileSize = FindData.nFileSizeHigh ? 0xFFFFFFFF
335 : FindData.nFileSizeLow;
336 strcpy(FindFileBlock->FileName, FindData.cAlternateFileName);
337 }
338 while((FindData.dwFileAttributes & (FILE_ATTRIBUTE_HIDDEN |
339 FILE_ATTRIBUTE_SYSTEM |
340 FILE_ATTRIBUTE_DIRECTORY))
341 & ~FindFileBlock->AttribMask);
342
343 return ERROR_SUCCESS;
344 }
345
346 UCHAR
347 WINAPI
348 demGetPhysicalDriveType(IN UCHAR DriveNumber)
349 {
350 UNIMPLEMENTED;
351 return DOSDEVICE_DRIVE_UNKNOWN;
352 }
353
354 BOOL
355 WINAPI
356 demIsShortPathName(IN LPCSTR Path,
357 IN BOOL Unknown)
358 {
359 UNIMPLEMENTED;
360 return FALSE;
361 }
362
363 DWORD
364 WINAPI
365 demSetCurrentDirectoryGetDrive(IN LPCSTR CurrentDirectory,
366 OUT PUCHAR DriveNumber)
367 {
368 UNIMPLEMENTED;
369 return ERROR_SUCCESS;
370 }
371
372 /* EOF */