a0b1a5baac63de1085d7147f595c2ef2f5049f13
[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 "bop.h"
22
23 #include "bios/bios.h"
24
25 /* Extra PSDK/NDK Headers */
26 #include <ndk/obtypes.h>
27
28 /* PRIVATE VARIABLES **********************************************************/
29
30 /**/extern BYTE CurrentDrive;/**/
31
32 /* DEFINES ********************************************************************/
33
34 /* BOP Identifiers */
35 #define BOP_DOS 0x50 // DOS System BOP (for NTIO.SYS and NTDOS.SYS)
36 #define BOP_CMD 0x54 // DOS Command Interpreter BOP (for COMMAND.COM)
37
38 /* PRIVATE FUNCTIONS **********************************************************/
39
40 static VOID WINAPI DosSystemBop(LPWORD Stack)
41 {
42 /* Get the Function Number and skip it */
43 BYTE FuncNum = *(PBYTE)SEG_OFF_TO_PTR(getCS(), getIP());
44 setIP(getIP() + 1);
45
46 switch (FuncNum)
47 {
48 case 0x11: // Load the DOS kernel
49 {
50 BOOLEAN Success;
51 HANDLE hDosKernel;
52 ULONG ulDosKernelSize = 0;
53
54 DPRINT1("You are loading Windows NT DOS!\n");
55
56 /* Open the DOS kernel file */
57 hDosKernel = FileOpen("ntdos.sys", &ulDosKernelSize);
58
59 /* If we failed, bail out */
60 if (hDosKernel == NULL) goto Quit;
61
62 /*
63 * Attempt to load the DOS kernel into memory.
64 * The segment where to load the DOS kernel is defined
65 * by the DOS BIOS and is found in DI:0000 .
66 */
67 Success = FileLoadByHandle(hDosKernel,
68 REAL_TO_PHYS(TO_LINEAR(getDI(), 0x0000)),
69 ulDosKernelSize,
70 &ulDosKernelSize);
71
72 DPRINT1("Windows NT DOS loading %s at 0x%04X:0x%04X, size 0x%x ; GetLastError() = %u\n",
73 (Success ? "succeeded" : "failed"),
74 getDI(), 0x0000,
75 ulDosKernelSize,
76 GetLastError());
77
78 /* Close the DOS kernel file */
79 FileClose(hDosKernel);
80
81 Quit:
82 if (!Success)
83 {
84 /* We failed everything, stop the VDM */
85 EmulatorTerminate();
86 }
87
88 break;
89 }
90
91 default:
92 {
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 // Result &= DosKRNLInitialize();
238
239 return Result;
240 }
241 }
242
243 /* PUBLIC EXPORTED APIS *******************************************************/
244
245 // demLFNCleanup
246 // demLFNGetCurrentDirectory
247
248 // demGetFileTimeByHandle_WOW
249 // demWOWLFNAllocateSearchHandle
250 // demWOWLFNCloseSearchHandle
251 // demWOWLFNEntry
252 // demWOWLFNGetSearchHandle
253 // demWOWLFNInit
254
255 DWORD
256 WINAPI
257 demClientErrorEx(IN HANDLE FileHandle,
258 IN CHAR Unknown,
259 IN BOOL Flag)
260 {
261 UNIMPLEMENTED;
262 return GetLastError();
263 }
264
265 DWORD
266 WINAPI
267 demFileDelete(IN LPCSTR FileName)
268 {
269 if (DeleteFileA(FileName)) SetLastError(ERROR_SUCCESS);
270
271 return GetLastError();
272 }
273
274 DWORD
275 WINAPI
276 demFileFindFirst(OUT PVOID lpFindFileData,
277 IN LPCSTR FileName,
278 IN WORD AttribMask)
279 {
280 BOOLEAN Success = TRUE;
281 WIN32_FIND_DATAA FindData;
282 PDOS_FIND_FILE_BLOCK FindFileBlock = (PDOS_FIND_FILE_BLOCK)lpFindFileData;
283
284 /* Fill the block */
285 FindFileBlock->DriveLetter = CurrentDrive + 'A';
286 FindFileBlock->AttribMask = AttribMask;
287 FindFileBlock->SearchHandle = FindFirstFileA(FileName, &FindData);
288 if (FindFileBlock->SearchHandle == INVALID_HANDLE_VALUE) return GetLastError();
289
290 do
291 {
292 /* Check the attributes */
293 if (!((FindData.dwFileAttributes & (FILE_ATTRIBUTE_HIDDEN |
294 FILE_ATTRIBUTE_SYSTEM |
295 FILE_ATTRIBUTE_DIRECTORY))
296 & ~AttribMask))
297 {
298 break;
299 }
300 }
301 while ((Success = FindNextFileA(FindFileBlock->SearchHandle, &FindData)));
302
303 if (!Success) return GetLastError();
304
305 FindFileBlock->Attributes = LOBYTE(FindData.dwFileAttributes);
306 FileTimeToDosDateTime(&FindData.ftLastWriteTime,
307 &FindFileBlock->FileDate,
308 &FindFileBlock->FileTime);
309 FindFileBlock->FileSize = FindData.nFileSizeHigh ? 0xFFFFFFFF
310 : FindData.nFileSizeLow;
311 strcpy(FindFileBlock->FileName, FindData.cAlternateFileName);
312
313 return ERROR_SUCCESS;
314 }
315
316 DWORD
317 WINAPI
318 demFileFindNext(OUT PVOID lpFindFileData)
319 {
320 WIN32_FIND_DATAA FindData;
321 PDOS_FIND_FILE_BLOCK FindFileBlock = (PDOS_FIND_FILE_BLOCK)lpFindFileData;
322
323 do
324 {
325 if (!FindNextFileA(FindFileBlock->SearchHandle, &FindData))
326 return GetLastError();
327
328 /* Update the block */
329 FindFileBlock->Attributes = LOBYTE(FindData.dwFileAttributes);
330 FileTimeToDosDateTime(&FindData.ftLastWriteTime,
331 &FindFileBlock->FileDate,
332 &FindFileBlock->FileTime);
333 FindFileBlock->FileSize = FindData.nFileSizeHigh ? 0xFFFFFFFF
334 : FindData.nFileSizeLow;
335 strcpy(FindFileBlock->FileName, FindData.cAlternateFileName);
336 }
337 while((FindData.dwFileAttributes & (FILE_ATTRIBUTE_HIDDEN |
338 FILE_ATTRIBUTE_SYSTEM |
339 FILE_ATTRIBUTE_DIRECTORY))
340 & ~FindFileBlock->AttribMask);
341
342 return ERROR_SUCCESS;
343 }
344
345 UCHAR
346 WINAPI
347 demGetPhysicalDriveType(IN UCHAR DriveNumber)
348 {
349 UNIMPLEMENTED;
350 return DOSDEVICE_DRIVE_UNKNOWN;
351 }
352
353 BOOL
354 WINAPI
355 demIsShortPathName(IN LPCSTR Path,
356 IN BOOL Unknown)
357 {
358 UNIMPLEMENTED;
359 return FALSE;
360 }
361
362 DWORD
363 WINAPI
364 demSetCurrentDirectoryGetDrive(IN LPCSTR CurrentDirectory,
365 OUT PUCHAR DriveNumber)
366 {
367 UNIMPLEMENTED;
368 return ERROR_SUCCESS;
369 }
370
371 /* EOF */