[NTVDM] Fix PCH w.r.t. using the debug routines. The PCH use here in itself could...
[reactos.git] / reactos / subsystems / mvdm / ntvdm / dos / dos32krnl / bios.c
1 /*
2 * COPYRIGHT: GPL - See COPYING in the top level directory
3 * PROJECT: ReactOS Virtual DOS Machine
4 * FILE: subsystems/mvdm/ntvdm/dos/dos32krnl/bios.c
5 * PURPOSE: DOS32 Bios
6 * PROGRAMMERS: Aleksandar Andrejevic <theflash AT sdf DOT lonestar DOT org>
7 */
8
9 /* INCLUDES *******************************************************************/
10
11 #include "ntvdm.h"
12
13 #define NDEBUG
14 #include <debug.h>
15
16 #include "emulator.h"
17 #include "int32.h"
18
19 #include "../dem.h"
20 #include "dos.h"
21 #include "dosfiles.h"
22 #include "handle.h"
23 #include "memory.h"
24 #include "bios/bios.h"
25
26 // This is needed because on UNICODE this symbol is redirected to
27 // GetEnvironmentStringsW whereas on ANSI it corresponds to the real
28 // "ANSI" function (and GetEnvironmentStringsA is aliased to it).
29 #undef GetEnvironmentStrings
30
31 // Symmetrize the dumbness of the previous symbol: on UNICODE
32 // FreeEnvironmentStrings aliases to FreeEnvironmentStringsW but
33 // on "ANSI" FreeEnvironmentStrings aliases to FreeEnvironmentStringsA
34 #undef FreeEnvironmentStrings
35 #define FreeEnvironmentStrings FreeEnvironmentStringsA
36
37 /* PRIVATE VARIABLES **********************************************************/
38
39 /* PUBLIC VARIABLES ***********************************************************/
40
41 /* Global DOS BIOS data area */
42 PBIOS_DATA BiosData;
43
44 /* PRIVATE FUNCTIONS **********************************************************/
45
46 /* PUBLIC FUNCTIONS ***********************************************************/
47
48 VOID DosEchoCharacter(CHAR Character)
49 {
50 switch (Character)
51 {
52 case '\0':
53 {
54 /* Nothing */
55 break;
56 }
57
58 case '\b':
59 {
60 /* Erase the character */
61 DosPrintCharacter(DOS_OUTPUT_HANDLE, '\b');
62 DosPrintCharacter(DOS_OUTPUT_HANDLE, ' ');
63 DosPrintCharacter(DOS_OUTPUT_HANDLE, '\b');
64 break;
65 }
66
67 default:
68 {
69 /*
70 * Check if this is a special character
71 * NOTE: \r and \n are handled by the underlying driver!
72 */
73 if (Character < 0x20 && Character != '\r' && Character != '\n')
74 {
75 DosPrintCharacter(DOS_OUTPUT_HANDLE, '^');
76 Character += 'A' - 1;
77 }
78
79 /* Echo the character */
80 DosPrintCharacter(DOS_OUTPUT_HANDLE, Character);
81 }
82 }
83 }
84
85 CHAR DosReadCharacter(WORD FileHandle, BOOLEAN Echo)
86 {
87 WORD BytesRead;
88 PDOS_FILE_DESCRIPTOR Descriptor = NULL;
89 WORD OldDeviceInfo;
90
91 /* Find the standard input descriptor and switch it to binary mode */
92 Descriptor = DosGetHandleFileDescriptor(FileHandle);
93 if (Descriptor)
94 {
95 OldDeviceInfo = Descriptor->DeviceInfo;
96 Descriptor->DeviceInfo |= FILE_INFO_BINARY;
97 }
98
99 Sda->ByteBuffer = '\0';
100 DPRINT("DosReadCharacter\n");
101
102 /* Use the file reading function */
103 DosReadFile(FileHandle,
104 MAKELONG(DOS_DATA_OFFSET(Sda.ByteBuffer), DOS_DATA_SEGMENT),
105 1,
106 &BytesRead);
107
108 /* Check if we should echo and the file is actually the CON device */
109 if (Echo && Descriptor && Descriptor->DeviceInfo & FILE_INFO_DEVICE)
110 {
111 /* Echo the character */
112 DosEchoCharacter(Sda->ByteBuffer);
113 }
114
115 /* Restore the old mode and return the character */
116 if (Descriptor) Descriptor->DeviceInfo = OldDeviceInfo;
117 return Sda->ByteBuffer;
118 }
119
120 BOOLEAN DosCheckInput(VOID)
121 {
122 PDOS_FILE_DESCRIPTOR Descriptor = DosGetHandleFileDescriptor(DOS_INPUT_HANDLE);
123
124 if (Descriptor == NULL)
125 {
126 /* Invalid handle */
127 Sda->LastErrorCode = ERROR_INVALID_HANDLE; // ERROR_FILE_NOT_FOUND
128 return FALSE;
129 }
130
131 if (Descriptor->DeviceInfo & FILE_INFO_DEVICE)
132 {
133 WORD Result;
134 PDOS_DEVICE_NODE Node = DosGetDriverNode(Descriptor->DevicePointer);
135
136 if (!Node->InputStatusRoutine) return FALSE;
137
138 Result = Node->InputStatusRoutine(Node);
139 return !(Result & DOS_DEVSTAT_BUSY);
140 }
141 else
142 {
143 DWORD FileSizeHigh;
144 DWORD FileSize = GetFileSize(Descriptor->Win32Handle, &FileSizeHigh);
145 LONG LocationHigh = 0;
146 DWORD Location = SetFilePointer(Descriptor->Win32Handle, 0, &LocationHigh, FILE_CURRENT);
147
148 return ((Location != FileSize) || (LocationHigh != FileSizeHigh));
149 }
150 }
151
152 VOID DosPrintCharacter(WORD FileHandle, CHAR Character)
153 {
154 WORD BytesWritten;
155
156 Sda->ByteBuffer = Character;
157
158 /* Use the file writing function */
159 DosWriteFile(FileHandle,
160 MAKELONG(DOS_DATA_OFFSET(Sda.ByteBuffer), DOS_DATA_SEGMENT),
161 1,
162 &BytesWritten);
163 }
164
165 BOOLEAN DosBuildSysEnvBlock(VOID)
166 {
167 LPSTR SourcePtr, Environment;
168 LPSTR DestPtr = (LPSTR)SEG_OFF_TO_PTR(SYSTEM_ENV_BLOCK, 0);
169
170 /*
171 * Get the environment strings
172 *
173 * NOTE: On non-STANDALONE builds, this corresponds to the VDM environment
174 * as created by BaseVDM for NTVDM. On STANDALONE builds this is the Win32
175 * environment. In this last case we need to convert it to a proper VDM env.
176 */
177 SourcePtr = Environment = GetEnvironmentStrings();
178 if (Environment == NULL) return FALSE;
179
180 /* Fill the DOS system environment block */
181 while (*SourcePtr)
182 {
183 /*
184 * - Ignore environment strings starting with a '=',
185 * they describe current directories.
186 * - Ignore also the WINDIR environment variable since
187 * DOS apps should ignore that we started from ReactOS.
188 * - Upper-case the environment names, not their values.
189 */
190 if (*SourcePtr != '=' && _strnicmp(SourcePtr, "WINDIR", 6) != 0)
191 {
192 PCHAR Delim = NULL;
193
194 /* Copy the environment string */
195 strcpy(DestPtr, SourcePtr);
196
197 /* Upper-case the environment name */
198 Delim = strchr(DestPtr, '='); // Find the '=' delimiter
199 if (Delim) *Delim = '\0'; // Temporarily replace it by NULL
200 _strupr(DestPtr); // Upper-case
201 if (Delim) *Delim = '='; // Restore the delimiter
202
203 DestPtr += strlen(SourcePtr);
204
205 /* NULL-terminate the environment string */
206 *(DestPtr++) = '\0';
207 }
208
209 /* Move to the next string */
210 SourcePtr += strlen(SourcePtr) + 1;
211 }
212 /* NULL-terminate the environment block */
213 *DestPtr = '\0';
214
215 /* Free the memory allocated for environment strings */
216 FreeEnvironmentStrings(Environment);
217
218 return TRUE;
219 }
220
221 BOOLEAN DosBIOSInitialize(VOID)
222 {
223 FILE *Stream;
224 WCHAR Buffer[256];
225
226 /* Set the data segment */
227 setDS(BIOS_DATA_SEGMENT);
228
229 /* Initialize the global DOS BIOS data area */
230 BiosData = (PBIOS_DATA)SEG_OFF_TO_PTR(BIOS_DATA_SEGMENT, 0x0000);
231
232 /* Initialize the DOS BIOS stack */
233 // FIXME: Add a block of fixed size for the stack in BIOS/DOS_DATA instead!
234 setSS(0x0F00);
235 setSP(0x0FF0);
236 /// setBP(0x091E); // DOS base stack pointer relic value
237
238 /*
239 * Initialize the INT 13h (BIOS Disk Services) handler chain support.
240 *
241 * The INT 13h handler chain is some functionality that allows DOS
242 * to insert disk filter drivers in between the (hooked) INT 13h handler
243 * and its original handler.
244 * Typically, those are:
245 * - filter for detecting disk changes (for floppy disks),
246 * - filter for tracking formatting calls and correcting DMA boundary errors,
247 * - a possible filter to work around a bug in a particular version of PC-AT's
248 * IBM's ROM BIOS (on systems with model byte FCh and BIOS date "01/10/84" only)
249 * (see http://www.ctyme.com/intr/rb-4453.htm for more details).
250 *
251 * This functionality is known to be used by some legitimate programs,
252 * by Windows 3.x, as well as some illegitimate ones (aka. virii).
253 *
254 * See extra information about this support in dos.h
255 */
256 // FIXME: Should be done by the DOS BIOS
257 BiosData->RomBiosInt13 = ((PULONG)BaseAddress)[0x13];
258 BiosData->PrevInt13 = BiosData->RomBiosInt13;
259 // RegisterDosInt32(0x13, DosInt13h); // Unused at the moment!
260
261 //
262 // HERE: Do all hardware initialization needed for DOS
263 //
264
265 /*
266 * SysInit part...
267 */
268
269 /* Initialize the DOS kernel (DosInit) */
270 if (!DosKRNLInitialize())
271 {
272 BiosDisplayMessage("Failed to load the DOS kernel! Exiting...\n");
273 return FALSE;
274 }
275
276 /* DOS kernel loading succeeded, we can finish the initialization */
277
278 /* Build the system master (pre-) environment block (inherited by the shell) */
279 if (!DosBuildSysEnvBlock())
280 {
281 DosDisplayMessage("An error occurred when setting up the system environment block.\n");
282 }
283
284 /* TODO: Read CONFIG.NT/SYS */
285 Stream = _wfopen(DOS_CONFIG_PATH, L"r");
286 if (Stream != NULL)
287 {
288 while (fgetws(Buffer, ARRAYSIZE(Buffer), Stream))
289 {
290 // TODO: Parse the line
291 }
292 fclose(Stream);
293 }
294
295 return TRUE;
296 }
297
298 /* EOF */