2 * COPYRIGHT: GPL - See COPYING in the top level directory
3 * PROJECT: ReactOS Virtual DOS Machine
5 * PURPOSE: VDM DOS Kernel
6 * PROGRAMMERS: Aleksandar Andrejevic <theflash AT sdf DOT lonestar DOT org>
11 WORD CurrentPsp
= SYSTEM_PSP
, LastError
= 0;
13 static VOID
DosCombineFreeBlocks(WORD StartBlock
)
15 PDOS_MCB CurrentMcb
= SEGMENT_TO_MCB(StartBlock
), NextMcb
;
17 /* If this is the last block or it's not free, quit */
18 if (CurrentMcb
->BlockType
== 'Z' || CurrentMcb
->OwnerPsp
!= 0) return;
22 /* Get a pointer to the next MCB */
23 NextMcb
= SEGMENT_TO_MCB(StartBlock
+ CurrentMcb
->Size
+ 1);
25 /* Check if the next MCB is free */
26 if (NextMcb
->OwnerPsp
== 0)
29 CurrentMcb
->Size
+= NextMcb
->Size
+ 1;
30 CurrentMcb
->BlockType
= NextMcb
->BlockType
;
31 NextMcb
->BlockType
= 'I';
35 /* No more adjoining free blocks */
41 static WORD
DosCopyEnvironmentBlock(WORD SourceSegment
)
43 PCHAR Ptr
, SourceBuffer
, DestBuffer
= NULL
;
47 Ptr
= SourceBuffer
= (PCHAR
)((ULONG_PTR
)BaseAddress
+ TO_LINEAR(SourceSegment
, 0));
49 /* Calculate the size of the environment block */
52 TotalSize
+= strlen(Ptr
) + 1;
53 Ptr
+= strlen(Ptr
) + 1;
57 /* Allocate the memory for the environment block */
58 DestSegment
= DosAllocateMemory((TotalSize
+ 0x0F) >> 4, NULL
);
59 if (!DestSegment
) return 0;
63 DestBuffer
= (PCHAR
)((ULONG_PTR
)BaseAddress
+ TO_LINEAR(DestSegment
, 0));
67 strcpy(DestBuffer
, Ptr
);
69 /* Advance to the next string */
70 Ptr
+= strlen(Ptr
) + 1;
71 DestBuffer
+= strlen(Ptr
) + 1;
74 /* Set the final zero */
80 WORD
DosAllocateMemory(WORD Size
, WORD
*MaxAvailable
)
82 WORD Result
= 0, Segment
= FIRST_MCB_SEGMENT
, MaxSize
= 0;
83 PDOS_MCB CurrentMcb
, NextMcb
;
87 /* Get a pointer to the MCB */
88 CurrentMcb
= SEGMENT_TO_MCB(Segment
);
90 /* Make sure it's valid */
91 if (CurrentMcb
->BlockType
!= 'M' && CurrentMcb
->BlockType
!= 'Z')
96 /* Only check free blocks */
97 if (CurrentMcb
->OwnerPsp
!= 0) goto Next
;
99 /* Combine this free block with adjoining free blocks */
100 DosCombineFreeBlocks(Segment
);
102 /* Update the maximum block size */
103 if (CurrentMcb
->Size
> MaxSize
) MaxSize
= CurrentMcb
->Size
;
105 /* Check if this block is big enough */
106 if (CurrentMcb
->Size
< Size
) goto Next
;
108 /* It is, update the smallest found so far */
109 if ((Result
== 0) || (CurrentMcb
->Size
< SEGMENT_TO_MCB(Result
)->Size
))
115 /* If this was the last MCB in the chain, quit */
116 if (CurrentMcb
->BlockType
== 'Z') break;
118 /* Otherwise, update the segment and continue */
119 Segment
+= CurrentMcb
->Size
+ 1;
122 /* If we didn't find a free block, return 0 */
125 if (MaxAvailable
) *MaxAvailable
= MaxSize
;
129 /* Get a pointer to the MCB */
130 CurrentMcb
= SEGMENT_TO_MCB(Result
);
132 /* Check if the block is larger than requested */
133 if (CurrentMcb
->Size
> Size
)
135 /* It is, split it into two blocks */
136 NextMcb
= SEGMENT_TO_MCB(Result
+ Size
+ 1);
138 /* Initialize the new MCB structure */
139 NextMcb
->BlockType
= CurrentMcb
->BlockType
;
140 NextMcb
->Size
= CurrentMcb
->Size
- Size
- 1;
141 NextMcb
->OwnerPsp
= 0;
143 /* Update the current block */
144 CurrentMcb
->BlockType
= 'M';
145 CurrentMcb
->Size
= Size
;
148 /* Take ownership of the block */
149 CurrentMcb
->OwnerPsp
= CurrentPsp
;
154 WORD
DosResizeMemory(WORD Segment
, WORD NewSize
)
156 WORD ReturnSize
= 0, NextSegment
;
157 PDOS_MCB Mcb
= SEGMENT_TO_MCB(Segment
), NextMcb
;
159 /* Make sure this is a valid, allocated block */
160 if ((Mcb
->BlockType
!= 'M' && Mcb
->BlockType
!= 'Z') || Mcb
->OwnerPsp
== 0)
165 /* Check if need to expand or contract the block */
166 if (NewSize
> Mcb
->Size
)
168 /* We can't expand the last block */
169 if (Mcb
->BlockType
!= 'M') return Mcb
->Size
;
171 ReturnSize
= Mcb
->Size
;
173 /* Get the pointer and segment of the next MCB */
174 NextSegment
= Segment
+ Mcb
->Size
+ 1;
175 NextMcb
= SEGMENT_TO_MCB(NextSegment
);
177 /* Make sure the next segment is free */
178 if (NextMcb
->OwnerPsp
!= 0) return Mcb
->Size
;
180 /* Combine this free block with adjoining free blocks */
181 DosCombineFreeBlocks(NextSegment
);
183 /* Set the maximum possible size of the block */
184 ReturnSize
+= NextMcb
->Size
+ 1;
186 /* Maximize the current block */
187 Mcb
->Size
= ReturnSize
;
188 Mcb
->BlockType
= NextMcb
->BlockType
;
190 /* Invalidate the next block */
191 NextMcb
->BlockType
= 'I';
193 /* Check if the block is larger than requested */
194 if (Mcb
->Size
> NewSize
)
196 /* It is, split it into two blocks */
197 NextMcb
= SEGMENT_TO_MCB(Segment
+ NewSize
+ 1);
199 /* Initialize the new MCB structure */
200 NextMcb
->BlockType
= Mcb
->BlockType
;
201 NextMcb
->Size
= Mcb
->Size
- NewSize
- 1;
202 NextMcb
->OwnerPsp
= 0;
204 /* Update the current block */
205 Mcb
->BlockType
= 'M';
209 else if (NewSize
< Mcb
->Size
)
211 /* Just split the block */
212 NextMcb
= SEGMENT_TO_MCB(Segment
+ NewSize
+ 1);
213 NextMcb
->BlockType
= Mcb
->BlockType
;
214 NextMcb
->Size
= Mcb
->Size
- NewSize
- 1;
215 NextMcb
->OwnerPsp
= 0;
218 Mcb
->BlockType
= 'M';
225 BOOLEAN
DosFreeMemory(WORD Segment
)
227 PDOS_MCB Mcb
= SEGMENT_TO_MCB(Segment
);
229 /* Make sure the MCB is valid */
230 if (Mcb
->BlockType
!= 'M' && Mcb
->BlockType
!= 'Z') return FALSE
;
232 /* Mark the block as free */
238 WORD
DosCreateFile(LPCSTR FilePath
)
240 // TODO: NOT IMPLEMENTED
244 WORD
DosOpenFile(LPCSTR FilePath
)
246 // TODO: NOT IMPLEMENTED
250 VOID
DosInitializePsp(WORD PspSegment
, LPCSTR CommandLine
, WORD ProgramSize
, WORD Environment
)
253 PDOS_PSP PspBlock
= SEGMENT_TO_PSP(PspSegment
);
254 LPDWORD IntVecTable
= (LPDWORD
)((ULONG_PTR
)BaseAddress
);
256 ZeroMemory(PspBlock
, sizeof(DOS_PSP
));
258 /* Set the exit interrupt */
259 PspBlock
->Exit
[0] = 0xCD; // int 0x20
260 PspBlock
->Exit
[1] = 0x20;
262 /* Set the program size */
263 PspBlock
->MemSize
= ProgramSize
;
265 /* Save the interrupt vectors */
266 PspBlock
->TerminateAddress
= IntVecTable
[0x22];
267 PspBlock
->BreakAddress
= IntVecTable
[0x23];
268 PspBlock
->CriticalAddress
= IntVecTable
[0x24];
270 /* Set the parent PSP */
271 PspBlock
->ParentPsp
= CurrentPsp
;
273 /* Initialize the handle table */
274 for (i
= 0; i
< 20; i
++) PspBlock
->HandleTable
[i
] = 0xFF;
276 /* Did we get an environment segment? */
279 /* No, copy the one from the parent */
280 Environment
= DosCopyEnvironmentBlock((CurrentPsp
!= SYSTEM_PSP
)
281 ? SEGMENT_TO_PSP(CurrentPsp
)->EnvBlock
285 PspBlock
->EnvBlock
= Environment
;
287 /* Set the handle table pointers to the internal handle table */
288 PspBlock
->HandleTableSize
= 20;
289 PspBlock
->HandleTablePtr
= MAKELONG(0x18, PspSegment
);
291 /* Set the DOS version */
292 PspBlock
->DosVersion
= DOS_VERSION
;
294 /* Set the far call opcodes */
295 PspBlock
->FarCall
[0] = 0xCD; // int 0x21
296 PspBlock
->FarCall
[1] = 0x21;
297 PspBlock
->FarCall
[2] = 0xCB; // retf
299 /* Set the command line */
300 PspBlock
->CommandLineSize
= strlen(CommandLine
);
301 RtlCopyMemory(PspBlock
->CommandLine
, CommandLine
, PspBlock
->CommandLineSize
);
302 PspBlock
->CommandLine
[PspBlock
->CommandLineSize
] = '\r';
305 BOOLEAN
DosCreateProcess(LPCSTR CommandLine
, WORD EnvBlock
)
307 BOOLEAN Success
= FALSE
;
308 HANDLE FileHandle
= INVALID_HANDLE_VALUE
, FileMapping
= NULL
;
309 LPBYTE Address
= NULL
;
310 LPSTR ProgramFilePath
, Parameters
[128];
311 CHAR CommandLineCopy
[128];
313 WORD i
, Segment
, FileSize
, ExeSize
;
314 PIMAGE_DOS_HEADER Header
;
315 PDWORD RelocationTable
;
318 /* Save a copy of the command line */
319 strcpy(CommandLineCopy
, CommandLine
);
321 /* Get the file name of the executable */
322 ProgramFilePath
= strtok(CommandLineCopy
, " \t");
324 /* Load the parameters in the local array */
325 while ((ParamCount
< 256)
326 && ((Parameters
[ParamCount
] = strtok(NULL
, " \t")) != NULL
))
331 /* Open a handle to the executable */
332 FileHandle
= CreateFileA(ProgramFilePath
,
337 FILE_ATTRIBUTE_NORMAL
,
339 if (FileHandle
== INVALID_HANDLE_VALUE
) goto Cleanup
;
341 /* Get the file size */
342 FileSize
= GetFileSize(FileHandle
, NULL
);
344 /* Create a mapping object for the file */
345 FileMapping
= CreateFileMapping(FileHandle
,
351 if (FileMapping
== NULL
) goto Cleanup
;
353 /* Map the file into memory */
354 Address
= (LPBYTE
)MapViewOfFile(FileMapping
, FILE_MAP_READ
, 0, 0, 0);
355 if (Address
== NULL
) goto Cleanup
;
357 /* Check if this is an EXE file or a COM file */
358 if (Address
[0] == 'M' && Address
[1] == 'Z')
362 /* Get the MZ header */
363 Header
= (PIMAGE_DOS_HEADER
)Address
;
365 // TODO: Verify checksum and executable!
367 /* Get the base size of the file, in paragraphs (rounded up) */
368 ExeSize
= (((Header
->e_cp
- 1) << 8) + Header
->e_cblp
+ 0x0F) >> 4;
370 /* Loop from the maximum to the minimum number of extra paragraphs */
371 for (i
= Header
->e_maxalloc
; i
>= Header
->e_minalloc
; i
--)
373 /* Try to allocate that much memory */
374 Segment
= DosAllocateMemory(ExeSize
+ (sizeof(DOS_PSP
) >> 4) + i
, NULL
);
375 if (Segment
!= 0) break;
378 /* Check if at least the lowest allocation was successful */
379 if (Segment
== 0) goto Cleanup
;
381 /* Initialize the PSP */
382 DosInitializePsp(Segment
,
383 CommandLine
, ExeSize
+ (sizeof(DOS_PSP
) >> 4) + i
,
386 /* Copy the program to Segment:0100 */
387 RtlCopyMemory((PVOID
)((ULONG_PTR
)BaseAddress
388 + TO_LINEAR(Segment
, 0x100)),
389 Address
+ (Header
->e_cparhdr
<< 4),
390 FileSize
- (Header
->e_cparhdr
<< 4));
392 /* Get the relocation table */
393 RelocationTable
= (PDWORD
)(Address
+ Header
->e_lfarlc
);
395 /* Perform relocations */
396 for (i
= 0; i
< Header
->e_crlc
; i
++)
398 /* Get a pointer to the word that needs to be patched */
399 RelocWord
= (PWORD
)((ULONG_PTR
)BaseAddress
400 + TO_LINEAR(Segment
+ HIWORD(RelocationTable
[i
]),
401 0x100 + LOWORD(RelocationTable
[i
])));
403 /* Add the number of the EXE segment to it */
404 *RelocWord
+= Segment
+ (sizeof(DOS_PSP
) >> 4);
407 /* Set the initial segment registers */
408 EmulatorSetRegister(EMULATOR_REG_DS
, Segment
);
409 EmulatorSetRegister(EMULATOR_REG_ES
, Segment
);
411 /* Set the stack to the location from the header */
412 EmulatorSetStack(Segment
+ (sizeof(DOS_PSP
) >> 4) + Header
->e_ss
,
416 CurrentPsp
= Segment
;
417 EmulatorExecute(Segment
+ Header
->e_cs
, sizeof(DOS_PSP
) + Header
->e_ip
);
425 /* Allocate memory for the whole program and the PSP */
426 Segment
= DosAllocateMemory((FileSize
+ sizeof(DOS_PSP
)) >> 4, NULL
);
427 if (Segment
== 0) goto Cleanup
;
429 /* Copy the program to Segment:0100 */
430 RtlCopyMemory((PVOID
)((ULONG_PTR
)BaseAddress
431 + TO_LINEAR(Segment
, 0x100)),
435 /* Initialize the PSP */
436 DosInitializePsp(Segment
,
438 (FileSize
+ sizeof(DOS_PSP
)) >> 4,
441 /* Set the initial segment registers */
442 EmulatorSetRegister(EMULATOR_REG_DS
, Segment
);
443 EmulatorSetRegister(EMULATOR_REG_ES
, Segment
);
445 /* Set the stack to the last word of the segment */
446 EmulatorSetStack(Segment
, 0xFFFE);
449 CurrentPsp
= Segment
;
450 EmulatorExecute(Segment
, 0x100);
457 if (Address
!= NULL
) UnmapViewOfFile(Address
);
459 /* Close the file mapping object */
460 if (FileMapping
!= NULL
) CloseHandle(FileMapping
);
462 /* Close the file handle */
463 if (FileHandle
!= INVALID_HANDLE_VALUE
) CloseHandle(FileHandle
);
468 VOID
DosTerminateProcess(WORD Psp
, BYTE ReturnCode
)
470 WORD McbSegment
= FIRST_MCB_SEGMENT
;
472 LPDWORD IntVecTable
= (LPDWORD
)((ULONG_PTR
)BaseAddress
);
473 PDOS_PSP PspBlock
= SEGMENT_TO_PSP(Psp
);
475 /* Check if this PSP is it's own parent */
476 if (PspBlock
->ParentPsp
== Psp
) goto Done
;
478 // TODO: Close all handles opened by the process
480 /* Free the memory used by the process */
483 /* Get a pointer to the MCB */
484 CurrentMcb
= SEGMENT_TO_MCB(McbSegment
);
486 /* Make sure the MCB is valid */
487 if (CurrentMcb
->BlockType
!= 'M' && CurrentMcb
->BlockType
!='Z') break;
489 /* If this block was allocated by the process, free it */
490 if (CurrentMcb
->OwnerPsp
== Psp
) DosFreeMemory(McbSegment
);
492 /* If this was the last block, quit */
493 if (CurrentMcb
->BlockType
== 'Z') break;
495 /* Update the segment and continue */
496 McbSegment
+= CurrentMcb
->Size
+ 1;
500 /* Restore the interrupt vectors */
501 IntVecTable
[0x22] = PspBlock
->TerminateAddress
;
502 IntVecTable
[0x23] = PspBlock
->BreakAddress
;
503 IntVecTable
[0x24] = PspBlock
->CriticalAddress
;
505 /* Update the current PSP */
506 if (Psp
== CurrentPsp
)
508 CurrentPsp
= PspBlock
->ParentPsp
;
509 if (CurrentPsp
== SYSTEM_PSP
) VdmRunning
= FALSE
;
512 /* Return control to the parent process */
513 EmulatorExecute(HIWORD(PspBlock
->TerminateAddress
),
514 LOWORD(PspBlock
->TerminateAddress
));
517 CHAR
DosReadCharacter()
519 // TODO: STDIN can be redirected under DOS 2.0+
523 VOID
DosPrintCharacter(CHAR Character
)
525 // TODO: STDOUT can be redirected under DOS 2.0+
526 if (Character
== '\r') Character
= '\n';
530 VOID
DosInt20h(WORD CodeSegment
)
532 /* This is the exit interrupt */
533 DosTerminateProcess(CodeSegment
, 0);
536 VOID
DosInt21h(WORD CodeSegment
)
540 SYSTEMTIME SystemTime
;
542 PDOS_INPUT_BUFFER InputBuffer
;
543 DWORD Eax
= EmulatorGetRegister(EMULATOR_REG_AX
);
544 DWORD Ecx
= EmulatorGetRegister(EMULATOR_REG_CX
);
545 DWORD Edx
= EmulatorGetRegister(EMULATOR_REG_DX
);
546 DWORD Ebx
= EmulatorGetRegister(EMULATOR_REG_BX
);
547 WORD DataSegment
= EmulatorGetRegister(EMULATOR_REG_DS
);
548 WORD ExtSegment
= EmulatorGetRegister(EMULATOR_REG_ES
);
550 /* Check the value in the AH register */
553 /* Terminate Program */
556 DosTerminateProcess(CodeSegment
, 0);
560 /* Read Character And Echo */
563 Character
= DosReadCharacter();
564 DosPrintCharacter(Character
);
565 EmulatorSetRegister(EMULATOR_REG_AX
, (Eax
& 0xFFFFFF00) | Character
);
569 /* Print Character */
572 DosPrintCharacter(LOBYTE(Edx
));
576 /* Read Character Without Echo */
579 EmulatorSetRegister(EMULATOR_REG_AX
,
580 (Eax
& 0xFFFFFF00) | DosReadCharacter());
587 String
= (PCHAR
)((ULONG_PTR
)BaseAddress
588 + TO_LINEAR(DataSegment
, LOWORD(Edx
)));
590 while ((*String
) != '$')
592 DosPrintCharacter(*String
);
599 /* Read Buffered Input */
602 InputBuffer
= (PDOS_INPUT_BUFFER
)((ULONG_PTR
)BaseAddress
603 + TO_LINEAR(DataSegment
,
606 InputBuffer
->Length
= 0;
607 for (i
= 0; i
< InputBuffer
->MaxLength
; i
++)
609 Character
= DosReadCharacter();
610 DosPrintCharacter(Character
);
611 InputBuffer
->Buffer
[InputBuffer
->Length
] = Character
;
612 if (Character
== '\r') break;
613 InputBuffer
->Length
++;
619 /* Get system date */
622 GetLocalTime(&SystemTime
);
623 EmulatorSetRegister(EMULATOR_REG_CX
,
624 (Ecx
& 0xFFFF0000) | SystemTime
.wYear
);
625 EmulatorSetRegister(EMULATOR_REG_DX
,
627 | (SystemTime
.wMonth
<< 8)
629 EmulatorSetRegister(EMULATOR_REG_AX
,
630 (Eax
& 0xFFFFFF00) | SystemTime
.wDayOfWeek
);
634 /* Set system date */
637 GetLocalTime(&SystemTime
);
638 SystemTime
.wYear
= LOWORD(Ecx
);
639 SystemTime
.wMonth
= HIBYTE(Edx
);
640 SystemTime
.wDay
= LOBYTE(Edx
);
642 if (SetLocalTime(&SystemTime
))
645 EmulatorSetRegister(EMULATOR_REG_AX
, Eax
& 0xFFFFFF00);
650 EmulatorSetRegister(EMULATOR_REG_AX
, Eax
| 0xFF);
656 /* Get system time */
659 GetLocalTime(&SystemTime
);
660 EmulatorSetRegister(EMULATOR_REG_CX
,
662 | (SystemTime
.wHour
<< 8)
663 | SystemTime
.wMinute
);
664 EmulatorSetRegister(EMULATOR_REG_DX
,
666 | (SystemTime
.wSecond
<< 8)
667 | (SystemTime
.wMilliseconds
/ 10));
671 /* Set system time */
674 GetLocalTime(&SystemTime
);
675 SystemTime
.wHour
= HIBYTE(Ecx
);
676 SystemTime
.wMinute
= LOBYTE(Ecx
);
677 SystemTime
.wSecond
= HIBYTE(Edx
);
678 SystemTime
.wMilliseconds
= LOBYTE(Edx
) * 10;
680 if (SetLocalTime(&SystemTime
))
683 EmulatorSetRegister(EMULATOR_REG_AX
, Eax
& 0xFFFFFF00);
688 EmulatorSetRegister(EMULATOR_REG_AX
, Eax
| 0xFF);
694 /* Create Directory */
697 String
= (PCHAR
)((ULONG_PTR
)BaseAddress
698 + TO_LINEAR(DataSegment
, LOWORD(Edx
)));
700 if (CreateDirectoryA(String
, NULL
))
702 EmulatorClearFlag(EMULATOR_FLAG_CF
);
706 EmulatorSetFlag(EMULATOR_FLAG_CF
);
707 EmulatorSetRegister(EMULATOR_REG_AX
,
708 (Eax
& 0xFFFF0000) | LOWORD(GetLastError()));
714 /* Remove Directory */
717 String
= (PCHAR
)((ULONG_PTR
)BaseAddress
718 + TO_LINEAR(DataSegment
, LOWORD(Edx
)));
720 if (RemoveDirectoryA(String
))
722 EmulatorClearFlag(EMULATOR_FLAG_CF
);
726 EmulatorSetFlag(EMULATOR_FLAG_CF
);
727 EmulatorSetRegister(EMULATOR_REG_AX
,
728 (Eax
& 0xFFFF0000) | LOWORD(GetLastError()));
735 /* Set Current Directory */
738 String
= (PCHAR
)((ULONG_PTR
)BaseAddress
739 + TO_LINEAR(DataSegment
, LOWORD(Edx
)));
741 if (SetCurrentDirectoryA(String
))
743 EmulatorClearFlag(EMULATOR_FLAG_CF
);
747 EmulatorSetFlag(EMULATOR_FLAG_CF
);
748 EmulatorSetRegister(EMULATOR_REG_AX
,
749 (Eax
& 0xFFFF0000) | LOWORD(GetLastError()));
755 /* Allocate Memory */
758 WORD MaxAvailable
= 0;
759 WORD Segment
= DosAllocateMemory(LOWORD(Ebx
), &MaxAvailable
);
763 EmulatorSetRegister(EMULATOR_REG_AX
, Segment
);
764 EmulatorSetRegister(EMULATOR_REG_BX
, MaxAvailable
);
765 EmulatorClearFlag(EMULATOR_FLAG_CF
);
767 else EmulatorSetFlag(EMULATOR_FLAG_CF
);
775 if (DosFreeMemory(ExtSegment
))
777 EmulatorClearFlag(EMULATOR_FLAG_CF
);
779 else EmulatorSetFlag(EMULATOR_FLAG_CF
);
784 /* Resize Memory Block */
787 WORD Size
= DosResizeMemory(ExtSegment
, LOWORD(Ebx
));
791 EmulatorSetRegister(EMULATOR_REG_BX
, Size
);
792 EmulatorClearFlag(EMULATOR_FLAG_CF
);
794 else EmulatorSetFlag(EMULATOR_FLAG_CF
);
799 /* Terminate With Return Code */
802 DosTerminateProcess(CurrentPsp
, LOBYTE(Eax
));
809 EmulatorSetFlag(EMULATOR_FLAG_CF
);
814 VOID
DosBreakInterrupt()
819 BOOLEAN
DosInitialize()
821 PDOS_MCB Mcb
= SEGMENT_TO_MCB(FIRST_MCB_SEGMENT
);
824 LPWSTR SourcePtr
, Environment
;
826 LPSTR DestPtr
= (LPSTR
)((ULONG_PTR
)BaseAddress
+ TO_LINEAR(SYSTEM_ENV_BLOCK
, 0));
829 /* Initialize the MCB */
830 Mcb
->BlockType
= 'Z';
831 Mcb
->Size
= (WORD
)USER_MEMORY_SIZE
;
834 /* Get the environment strings */
835 SourcePtr
= Environment
= GetEnvironmentStringsW();
836 if (Environment
== NULL
) return FALSE
;
838 /* Fill the DOS system environment block */
841 /* Get the size of the ASCII string */
842 AsciiSize
= WideCharToMultiByte(CP_ACP
,
851 /* Allocate memory for the ASCII string */
852 AsciiString
= HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY
, AsciiSize
);
853 if (AsciiString
== NULL
)
855 FreeEnvironmentStringsW(Environment
);
859 /* Convert to ASCII */
860 WideCharToMultiByte(CP_ACP
,
869 /* Copy the string into DOS memory */
870 strcpy(DestPtr
, AsciiString
);
872 /* Free the memory */
873 HeapFree(GetProcessHeap(), 0, AsciiString
);
875 /* Move to the next string */
876 SourcePtr
+= wcslen(SourcePtr
) + 1;
877 DestPtr
+= strlen(AsciiString
) + 1;
880 /* Free the memory allocated for environment strings */
881 FreeEnvironmentStringsW(Environment
);
883 /* Read CONFIG.SYS */
884 Stream
= _wfopen(DOS_CONFIG_PATH
, L
"r");
887 while (fgetws(Buffer
, 256, Stream
))
889 // TODO: Parse the line