[NTVDM]: Load a BIOS image in case its name is given in BiosInitialize.
[reactos.git] / subsystems / win / basesrv / vdm.c
1 /*
2 * COPYRIGHT: See COPYING in the top level directory
3 * PROJECT: ReactOS Base API Server DLL
4 * FILE: subsystems/win/basesrv/vdm.c
5 * PURPOSE: Virtual DOS Machines (VDM) Support
6 * PROGRAMMERS: Hermes Belusca-Maito (hermes.belusca@sfr.fr)
7 * Aleksandar Andrejevic <theflash AT sdf DOT lonestar DOT org>
8 */
9
10 /* INCLUDES *******************************************************************/
11
12 #include "basesrv.h"
13 #include "vdm.h"
14
15 #define NDEBUG
16 #include <debug.h>
17
18 /* GLOBALS ********************************************************************/
19
20 BOOLEAN FirstVDM = TRUE;
21 LIST_ENTRY VDMConsoleListHead;
22 RTL_CRITICAL_SECTION DosCriticalSection;
23 RTL_CRITICAL_SECTION WowCriticalSection;
24
25 /* FUNCTIONS ******************************************************************/
26
27 NTSTATUS NTAPI BaseSrvGetConsoleRecord(HANDLE ConsoleHandle, PVDM_CONSOLE_RECORD *Record)
28 {
29 PLIST_ENTRY i;
30 PVDM_CONSOLE_RECORD CurrentRecord = NULL;
31
32 /* Search for a record that has the same console handle */
33 for (i = VDMConsoleListHead.Flink; i != &VDMConsoleListHead; i = i->Flink)
34 {
35 CurrentRecord = CONTAINING_RECORD(i, VDM_CONSOLE_RECORD, Entry);
36 if (CurrentRecord->ConsoleHandle == ConsoleHandle) break;
37 }
38
39 *Record = CurrentRecord;
40 return CurrentRecord ? STATUS_SUCCESS : STATUS_NOT_FOUND;
41 }
42
43 ULONG NTAPI GetNextDosSesId(VOID)
44 {
45 ULONG SessionId;
46 PLIST_ENTRY i;
47 PVDM_CONSOLE_RECORD CurrentRecord = NULL;
48 BOOLEAN Found;
49
50 /* Search for an available session ID */
51 for (SessionId = 1; SessionId != 0; SessionId++)
52 {
53 Found = FALSE;
54
55 /* Check if the ID is already in use */
56 for (i = VDMConsoleListHead.Flink; i != &VDMConsoleListHead; i = i->Flink)
57 {
58 CurrentRecord = CONTAINING_RECORD(i, VDM_CONSOLE_RECORD, Entry);
59 if (CurrentRecord->SessionId == SessionId) Found = TRUE;
60 }
61
62 /* If not, we found one */
63 if (!Found) break;
64 }
65
66 ASSERT(SessionId != 0);
67
68 /* Return the session ID */
69 return SessionId;
70 }
71
72 VOID NTAPI BaseInitializeVDM(VOID)
73 {
74 /* Initialize the list head */
75 InitializeListHead(&VDMConsoleListHead);
76
77 /* Initialize the critical section */
78 RtlInitializeCriticalSection(&DosCriticalSection);
79 RtlInitializeCriticalSection(&WowCriticalSection);
80 }
81
82 /* PUBLIC SERVER APIS *********************************************************/
83
84 CSR_API(BaseSrvCheckVDM)
85 {
86 NTSTATUS Status;
87 PBASE_CHECK_VDM CheckVdmRequest = &((PBASE_API_MESSAGE)ApiMessage)->Data.CheckVDMRequest;
88 PRTL_CRITICAL_SECTION CriticalSection = NULL;
89 PVDM_CONSOLE_RECORD ConsoleRecord = NULL;
90
91 /* Validate the message buffers */
92 if (!CsrValidateMessageBuffer(ApiMessage,
93 (PVOID*)&CheckVdmRequest->CmdLine,
94 CheckVdmRequest->CmdLen,
95 sizeof(*CheckVdmRequest->CmdLine))
96 || !CsrValidateMessageBuffer(ApiMessage,
97 (PVOID*)&CheckVdmRequest->AppName,
98 CheckVdmRequest->AppLen,
99 sizeof(*CheckVdmRequest->AppName))
100 || !CsrValidateMessageBuffer(ApiMessage,
101 (PVOID*)&CheckVdmRequest->PifFile,
102 CheckVdmRequest->PifLen,
103 sizeof(*CheckVdmRequest->PifFile))
104 || !CsrValidateMessageBuffer(ApiMessage,
105 (PVOID*)&CheckVdmRequest->CurDirectory,
106 CheckVdmRequest->CurDirectoryLen,
107 sizeof(*CheckVdmRequest->CurDirectory))
108 || !CsrValidateMessageBuffer(ApiMessage,
109 (PVOID*)&CheckVdmRequest->Desktop,
110 CheckVdmRequest->DesktopLen,
111 sizeof(*CheckVdmRequest->Desktop))
112 || !CsrValidateMessageBuffer(ApiMessage,
113 (PVOID*)&CheckVdmRequest->Title,
114 CheckVdmRequest->TitleLen,
115 sizeof(*CheckVdmRequest->Title))
116 || !CsrValidateMessageBuffer(ApiMessage,
117 (PVOID*)&CheckVdmRequest->Reserved,
118 CheckVdmRequest->ReservedLen,
119 sizeof(*CheckVdmRequest->Reserved)))
120 {
121 return STATUS_INVALID_PARAMETER;
122 }
123
124 CriticalSection = (CheckVdmRequest->BinaryType != BINARY_TYPE_SEPARATE_WOW)
125 ? &DosCriticalSection
126 : &WowCriticalSection;
127
128 /* Enter the critical section */
129 RtlEnterCriticalSection(CriticalSection);
130
131 /* Check if this is a DOS or WOW VDM */
132 if (CheckVdmRequest->BinaryType != BINARY_TYPE_SEPARATE_WOW)
133 {
134 /* Get the console record */
135 Status = BaseSrvGetConsoleRecord(CheckVdmRequest->ConsoleHandle,
136 &ConsoleRecord);
137
138 if (!NT_SUCCESS(Status))
139 {
140 /* Allocate a new console record */
141 ConsoleRecord = (PVDM_CONSOLE_RECORD)RtlAllocateHeap(BaseSrvHeap,
142 HEAP_ZERO_MEMORY,
143 sizeof(VDM_CONSOLE_RECORD));
144 if (ConsoleRecord == NULL)
145 {
146 Status = STATUS_NO_MEMORY;
147 goto Cleanup;
148 }
149
150 /* Initialize the console record */
151 ConsoleRecord->ConsoleHandle = CheckVdmRequest->ConsoleHandle;
152 ConsoleRecord->CurrentDirs = NULL;
153 ConsoleRecord->CurDirsLength = 0;
154 ConsoleRecord->SessionId = GetNextDosSesId();
155 InitializeListHead(&ConsoleRecord->DosListHead);
156
157 /* Add the console record */
158 InsertTailList(&VDMConsoleListHead, &ConsoleRecord->Entry);
159 }
160
161 // TODO: NOT IMPLEMENTED
162 UNIMPLEMENTED;
163 return STATUS_NOT_IMPLEMENTED;
164 }
165 else
166 {
167 // TODO: NOT IMPLEMENTED
168 UNIMPLEMENTED;
169 return STATUS_NOT_IMPLEMENTED;
170 }
171
172 Cleanup:
173 /* Leave the critical section */
174 RtlLeaveCriticalSection(CriticalSection);
175
176 return Status;
177 }
178
179 CSR_API(BaseSrvUpdateVDMEntry)
180 {
181 DPRINT1("%s not yet implemented\n", __FUNCTION__);
182 return STATUS_NOT_IMPLEMENTED;
183 }
184
185 CSR_API(BaseSrvGetNextVDMCommand)
186 {
187 DPRINT1("%s not yet implemented\n", __FUNCTION__);
188 return STATUS_NOT_IMPLEMENTED;
189 }
190
191 CSR_API(BaseSrvExitVDM)
192 {
193 DPRINT1("%s not yet implemented\n", __FUNCTION__);
194 return STATUS_NOT_IMPLEMENTED;
195 }
196
197 CSR_API(BaseSrvIsFirstVDM)
198 {
199 PBASE_IS_FIRST_VDM IsFirstVDMRequest = &((PBASE_API_MESSAGE)ApiMessage)->Data.IsFirstVDMRequest;
200
201 /* Return the result */
202 IsFirstVDMRequest->FirstVDM = FirstVDM;
203
204 /* Clear the first VDM flag */
205 FirstVDM = FALSE;
206
207 return STATUS_SUCCESS;
208 }
209
210 CSR_API(BaseSrvGetVDMExitCode)
211 {
212 DPRINT1("%s not yet implemented\n", __FUNCTION__);
213 return STATUS_NOT_IMPLEMENTED;
214 }
215
216 CSR_API(BaseSrvSetReenterCount)
217 {
218 DPRINT1("%s not yet implemented\n", __FUNCTION__);
219 return STATUS_NOT_IMPLEMENTED;
220 }
221
222 CSR_API(BaseSrvSetVDMCurDirs)
223 {
224 NTSTATUS Status;
225 PBASE_GETSET_VDM_CURDIRS VDMCurrentDirsRequest = &((PBASE_API_MESSAGE)ApiMessage)->Data.VDMCurrentDirsRequest;
226 PVDM_CONSOLE_RECORD ConsoleRecord;
227 PCHAR Buffer = NULL;
228
229 /* Validate the input buffer */
230 if (!CsrValidateMessageBuffer(ApiMessage,
231 (PVOID*)&VDMCurrentDirsRequest->lpszzCurDirs,
232 VDMCurrentDirsRequest->cchCurDirs,
233 sizeof(*VDMCurrentDirsRequest->lpszzCurDirs)))
234 {
235 return STATUS_INVALID_PARAMETER;
236 }
237
238 /* Enter the critical section */
239 RtlEnterCriticalSection(&DosCriticalSection);
240
241 /* Find the console record */
242 Status = BaseSrvGetConsoleRecord(VDMCurrentDirsRequest->ConsoleHandle, &ConsoleRecord);
243 if (!NT_SUCCESS(Status)) goto Cleanup;
244
245 if (ConsoleRecord->CurrentDirs == NULL)
246 {
247 /* Allocate memory for the current directory information */
248 Buffer = RtlAllocateHeap(BaseSrvHeap,
249 HEAP_ZERO_MEMORY,
250 VDMCurrentDirsRequest->cchCurDirs);
251 }
252 else
253 {
254 /* Resize the amount of allocated memory */
255 Buffer = RtlReAllocateHeap(BaseSrvHeap,
256 HEAP_ZERO_MEMORY,
257 ConsoleRecord->CurrentDirs,
258 VDMCurrentDirsRequest->cchCurDirs);
259 }
260
261 if (Buffer == NULL)
262 {
263 /* Allocation failed */
264 Status = STATUS_NO_MEMORY;
265 goto Cleanup;
266 }
267
268 /* Update the console record */
269 ConsoleRecord->CurrentDirs = Buffer;
270 ConsoleRecord->CurDirsLength = VDMCurrentDirsRequest->cchCurDirs;
271
272 /* Copy the data */
273 RtlMoveMemory(ConsoleRecord->CurrentDirs,
274 VDMCurrentDirsRequest->lpszzCurDirs,
275 VDMCurrentDirsRequest->cchCurDirs);
276
277 Cleanup:
278 /* Leave the critical section */
279 RtlLeaveCriticalSection(&DosCriticalSection);
280
281 return Status;
282 }
283
284 CSR_API(BaseSrvGetVDMCurDirs)
285 {
286 NTSTATUS Status;
287 PBASE_GETSET_VDM_CURDIRS VDMCurrentDirsRequest = &((PBASE_API_MESSAGE)ApiMessage)->Data.VDMCurrentDirsRequest;
288 PVDM_CONSOLE_RECORD ConsoleRecord;
289
290 /* Validate the output buffer */
291 if (!CsrValidateMessageBuffer(ApiMessage,
292 (PVOID*)&VDMCurrentDirsRequest->lpszzCurDirs,
293 VDMCurrentDirsRequest->cchCurDirs,
294 sizeof(*VDMCurrentDirsRequest->lpszzCurDirs)))
295 {
296 return STATUS_INVALID_PARAMETER;
297 }
298
299 /* Enter the critical section */
300 RtlEnterCriticalSection(&DosCriticalSection);
301
302 /* Find the console record */
303 Status = BaseSrvGetConsoleRecord(VDMCurrentDirsRequest->ConsoleHandle, &ConsoleRecord);
304 if (!NT_SUCCESS(Status)) goto Cleanup;
305
306 /* Return the actual size of the current directory information */
307 VDMCurrentDirsRequest->cchCurDirs = ConsoleRecord->CurDirsLength;
308
309 /* Check if the buffer is large enough */
310 if (VDMCurrentDirsRequest->cchCurDirs < ConsoleRecord->CurDirsLength)
311 {
312 Status = STATUS_BUFFER_TOO_SMALL;
313 goto Cleanup;
314 }
315
316 /* Copy the data */
317 RtlMoveMemory(VDMCurrentDirsRequest->lpszzCurDirs,
318 ConsoleRecord->CurrentDirs,
319 ConsoleRecord->CurDirsLength);
320
321 Cleanup:
322 /* Leave the critical section */
323 RtlLeaveCriticalSection(&DosCriticalSection);
324
325 return Status;
326 }
327
328 CSR_API(BaseSrvBatNotification)
329 {
330 DPRINT1("%s not yet implemented\n", __FUNCTION__);
331 return STATUS_NOT_IMPLEMENTED;
332 }
333
334 CSR_API(BaseSrvRegisterWowExec)
335 {
336 DPRINT1("%s not yet implemented\n", __FUNCTION__);
337 return STATUS_NOT_IMPLEMENTED;
338 }
339
340 CSR_API(BaseSrvRefreshIniFileMapping)
341 {
342 DPRINT1("%s not yet implemented\n", __FUNCTION__);
343 return STATUS_NOT_IMPLEMENTED;
344 }
345
346 /* EOF */