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