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
;
151 /* Return the segment of the data portion of the block */
155 WORD
DosResizeMemory(WORD BlockData
, WORD NewSize
)
157 WORD Segment
= BlockData
- 1, ReturnSize
= 0, NextSegment
;
158 PDOS_MCB Mcb
= SEGMENT_TO_MCB(Segment
), NextMcb
;
160 /* Make sure this is a valid, allocated block */
161 if ((Mcb
->BlockType
!= 'M' && Mcb
->BlockType
!= 'Z') || Mcb
->OwnerPsp
== 0)
166 /* Check if need to expand or contract the block */
167 if (NewSize
> Mcb
->Size
)
169 /* We can't expand the last block */
170 if (Mcb
->BlockType
!= 'M') return Mcb
->Size
;
172 ReturnSize
= Mcb
->Size
;
174 /* Get the pointer and segment of the next MCB */
175 NextSegment
= Segment
+ Mcb
->Size
+ 1;
176 NextMcb
= SEGMENT_TO_MCB(NextSegment
);
178 /* Make sure the next segment is free */
179 if (NextMcb
->OwnerPsp
!= 0) return Mcb
->Size
;
181 /* Combine this free block with adjoining free blocks */
182 DosCombineFreeBlocks(NextSegment
);
184 /* Set the maximum possible size of the block */
185 ReturnSize
+= NextMcb
->Size
+ 1;
187 /* Maximize the current block */
188 Mcb
->Size
= ReturnSize
;
189 Mcb
->BlockType
= NextMcb
->BlockType
;
191 /* Invalidate the next block */
192 NextMcb
->BlockType
= 'I';
194 /* Check if the block is larger than requested */
195 if (Mcb
->Size
> NewSize
)
197 /* It is, split it into two blocks */
198 NextMcb
= SEGMENT_TO_MCB(Segment
+ NewSize
+ 1);
200 /* Initialize the new MCB structure */
201 NextMcb
->BlockType
= Mcb
->BlockType
;
202 NextMcb
->Size
= Mcb
->Size
- NewSize
- 1;
203 NextMcb
->OwnerPsp
= 0;
205 /* Update the current block */
206 Mcb
->BlockType
= 'M';
210 else if (NewSize
< Mcb
->Size
)
212 /* Just split the block */
213 NextMcb
= SEGMENT_TO_MCB(Segment
+ NewSize
+ 1);
214 NextMcb
->BlockType
= Mcb
->BlockType
;
215 NextMcb
->Size
= Mcb
->Size
- NewSize
- 1;
216 NextMcb
->OwnerPsp
= 0;
219 Mcb
->BlockType
= 'M';
226 BOOLEAN
DosFreeMemory(WORD BlockData
)
228 PDOS_MCB Mcb
= SEGMENT_TO_MCB(BlockData
- 1);
230 /* Make sure the MCB is valid */
231 if (Mcb
->BlockType
!= 'M' && Mcb
->BlockType
!= 'Z') return FALSE
;
233 /* Mark the block as free */
239 WORD
DosCreateFile(LPCSTR FilePath
)
241 // TODO: NOT IMPLEMENTED
245 WORD
DosOpenFile(LPCSTR FilePath
)
247 // TODO: NOT IMPLEMENTED
251 VOID
DosInitializePsp(WORD PspSegment
, LPCSTR CommandLine
, WORD ProgramSize
, WORD Environment
)
254 PDOS_PSP PspBlock
= SEGMENT_TO_PSP(PspSegment
);
255 LPDWORD IntVecTable
= (LPDWORD
)((ULONG_PTR
)BaseAddress
);
257 ZeroMemory(PspBlock
, sizeof(DOS_PSP
));
259 /* Set the exit interrupt */
260 PspBlock
->Exit
[0] = 0xCD; // int 0x20
261 PspBlock
->Exit
[1] = 0x20;
263 /* Set the program size */
264 PspBlock
->MemSize
= ProgramSize
;
266 /* Save the interrupt vectors */
267 PspBlock
->TerminateAddress
= IntVecTable
[0x22];
268 PspBlock
->BreakAddress
= IntVecTable
[0x23];
269 PspBlock
->CriticalAddress
= IntVecTable
[0x24];
271 /* Set the parent PSP */
272 PspBlock
->ParentPsp
= CurrentPsp
;
274 /* Initialize the handle table */
275 for (i
= 0; i
< 20; i
++) PspBlock
->HandleTable
[i
] = 0xFF;
277 /* Did we get an environment segment? */
280 /* No, copy the one from the parent */
281 Environment
= DosCopyEnvironmentBlock((CurrentPsp
!= SYSTEM_PSP
)
282 ? SEGMENT_TO_PSP(CurrentPsp
)->EnvBlock
286 PspBlock
->EnvBlock
= Environment
;
288 /* Set the handle table pointers to the internal handle table */
289 PspBlock
->HandleTableSize
= 20;
290 PspBlock
->HandleTablePtr
= MAKELONG(0x18, PspSegment
);
292 /* Set the DOS version */
293 PspBlock
->DosVersion
= DOS_VERSION
;
295 /* Set the far call opcodes */
296 PspBlock
->FarCall
[0] = 0xCD; // int 0x21
297 PspBlock
->FarCall
[1] = 0x21;
298 PspBlock
->FarCall
[2] = 0xCB; // retf
300 /* Set the command line */
301 PspBlock
->CommandLineSize
= strlen(CommandLine
);
302 RtlCopyMemory(PspBlock
->CommandLine
, CommandLine
, PspBlock
->CommandLineSize
);
303 PspBlock
->CommandLine
[PspBlock
->CommandLineSize
] = '\r';
306 BOOLEAN
DosCreateProcess(LPCSTR CommandLine
, WORD EnvBlock
)
308 BOOLEAN Success
= FALSE
;
309 HANDLE FileHandle
= INVALID_HANDLE_VALUE
, FileMapping
= NULL
;
310 LPBYTE Address
= NULL
;
311 LPSTR ProgramFilePath
, Parameters
[128];
312 CHAR CommandLineCopy
[128];
314 WORD i
, Segment
, FileSize
, ExeSize
;
315 PIMAGE_DOS_HEADER Header
;
316 PDWORD RelocationTable
;
319 /* Save a copy of the command line */
320 strcpy(CommandLineCopy
, CommandLine
);
322 /* Get the file name of the executable */
323 ProgramFilePath
= strtok(CommandLineCopy
, " \t");
325 /* Load the parameters in the local array */
326 while ((ParamCount
< 256)
327 && ((Parameters
[ParamCount
] = strtok(NULL
, " \t")) != NULL
))
332 /* Open a handle to the executable */
333 FileHandle
= CreateFileA(ProgramFilePath
,
338 FILE_ATTRIBUTE_NORMAL
,
340 if (FileHandle
== INVALID_HANDLE_VALUE
) goto Cleanup
;
342 /* Get the file size */
343 FileSize
= GetFileSize(FileHandle
, NULL
);
345 /* Create a mapping object for the file */
346 FileMapping
= CreateFileMapping(FileHandle
,
352 if (FileMapping
== NULL
) goto Cleanup
;
354 /* Map the file into memory */
355 Address
= (LPBYTE
)MapViewOfFile(FileMapping
, FILE_MAP_READ
, 0, 0, 0);
356 if (Address
== NULL
) goto Cleanup
;
358 /* Check if this is an EXE file or a COM file */
359 if (Address
[0] == 'M' && Address
[1] == 'Z')
363 /* Get the MZ header */
364 Header
= (PIMAGE_DOS_HEADER
)Address
;
366 // TODO: Verify checksum and executable!
368 /* Get the base size of the file, in paragraphs (rounded up) */
369 ExeSize
= (((Header
->e_cp
- 1) << 8) + Header
->e_cblp
+ 0x0F) >> 4;
371 /* Loop from the maximum to the minimum number of extra paragraphs */
372 for (i
= Header
->e_maxalloc
; i
>= Header
->e_minalloc
; i
--)
374 /* Try to allocate that much memory */
375 Segment
= DosAllocateMemory(ExeSize
+ (sizeof(DOS_PSP
) >> 4) + i
, NULL
);
376 if (Segment
!= 0) break;
379 /* Check if at least the lowest allocation was successful */
380 if (Segment
== 0) goto Cleanup
;
382 /* Initialize the PSP */
383 DosInitializePsp(Segment
,
384 CommandLine
, ExeSize
+ (sizeof(DOS_PSP
) >> 4) + i
,
387 /* Copy the program to Segment:0100 */
388 RtlCopyMemory((PVOID
)((ULONG_PTR
)BaseAddress
389 + TO_LINEAR(Segment
, 0x100)),
390 Address
+ (Header
->e_cparhdr
<< 4),
391 FileSize
- (Header
->e_cparhdr
<< 4));
393 /* Get the relocation table */
394 RelocationTable
= (PDWORD
)(Address
+ Header
->e_lfarlc
);
396 /* Perform relocations */
397 for (i
= 0; i
< Header
->e_crlc
; i
++)
399 /* Get a pointer to the word that needs to be patched */
400 RelocWord
= (PWORD
)((ULONG_PTR
)BaseAddress
401 + TO_LINEAR(Segment
+ HIWORD(RelocationTable
[i
]),
402 0x100 + LOWORD(RelocationTable
[i
])));
404 /* Add the number of the EXE segment to it */
405 *RelocWord
+= Segment
+ (sizeof(DOS_PSP
) >> 4);
408 /* Set the initial segment registers */
409 EmulatorSetRegister(EMULATOR_REG_DS
, Segment
);
410 EmulatorSetRegister(EMULATOR_REG_ES
, Segment
);
412 /* Set the stack to the location from the header */
413 EmulatorSetStack(Segment
+ (sizeof(DOS_PSP
) >> 4) + Header
->e_ss
,
417 CurrentPsp
= Segment
;
418 EmulatorExecute(Segment
+ Header
->e_cs
, sizeof(DOS_PSP
) + Header
->e_ip
);
426 /* Allocate memory for the whole program and the PSP */
427 Segment
= DosAllocateMemory((FileSize
+ sizeof(DOS_PSP
)) >> 4, NULL
);
428 if (Segment
== 0) goto Cleanup
;
430 /* Copy the program to Segment:0100 */
431 RtlCopyMemory((PVOID
)((ULONG_PTR
)BaseAddress
432 + TO_LINEAR(Segment
, 0x100)),
436 /* Initialize the PSP */
437 DosInitializePsp(Segment
,
439 (FileSize
+ sizeof(DOS_PSP
)) >> 4,
442 /* Set the initial segment registers */
443 EmulatorSetRegister(EMULATOR_REG_DS
, Segment
);
444 EmulatorSetRegister(EMULATOR_REG_ES
, Segment
);
446 /* Set the stack to the last word of the segment */
447 EmulatorSetStack(Segment
, 0xFFFE);
450 CurrentPsp
= Segment
;
451 EmulatorExecute(Segment
, 0x100);
458 if (Address
!= NULL
) UnmapViewOfFile(Address
);
460 /* Close the file mapping object */
461 if (FileMapping
!= NULL
) CloseHandle(FileMapping
);
463 /* Close the file handle */
464 if (FileHandle
!= INVALID_HANDLE_VALUE
) CloseHandle(FileHandle
);
469 VOID
DosTerminateProcess(WORD Psp
, BYTE ReturnCode
)
471 WORD McbSegment
= FIRST_MCB_SEGMENT
;
473 LPDWORD IntVecTable
= (LPDWORD
)((ULONG_PTR
)BaseAddress
);
474 PDOS_PSP PspBlock
= SEGMENT_TO_PSP(Psp
);
476 /* Check if this PSP is it's own parent */
477 if (PspBlock
->ParentPsp
== Psp
) goto Done
;
479 // TODO: Close all handles opened by the process
481 /* Free the memory used by the process */
484 /* Get a pointer to the MCB */
485 CurrentMcb
= SEGMENT_TO_MCB(McbSegment
);
487 /* Make sure the MCB is valid */
488 if (CurrentMcb
->BlockType
!= 'M' && CurrentMcb
->BlockType
!='Z') break;
490 /* If this block was allocated by the process, free it */
491 if (CurrentMcb
->OwnerPsp
== Psp
) DosFreeMemory(McbSegment
);
493 /* If this was the last block, quit */
494 if (CurrentMcb
->BlockType
== 'Z') break;
496 /* Update the segment and continue */
497 McbSegment
+= CurrentMcb
->Size
+ 1;
501 /* Restore the interrupt vectors */
502 IntVecTable
[0x22] = PspBlock
->TerminateAddress
;
503 IntVecTable
[0x23] = PspBlock
->BreakAddress
;
504 IntVecTable
[0x24] = PspBlock
->CriticalAddress
;
506 /* Update the current PSP */
507 if (Psp
== CurrentPsp
)
509 CurrentPsp
= PspBlock
->ParentPsp
;
510 if (CurrentPsp
== SYSTEM_PSP
) VdmRunning
= FALSE
;
513 /* Return control to the parent process */
514 EmulatorExecute(HIWORD(PspBlock
->TerminateAddress
),
515 LOWORD(PspBlock
->TerminateAddress
));
518 CHAR
DosReadCharacter()
520 // TODO: STDIN can be redirected under DOS 2.0+
524 VOID
DosPrintCharacter(CHAR Character
)
526 // TODO: STDOUT can be redirected under DOS 2.0+
527 if (Character
== '\r') Character
= '\n';
531 VOID
DosInt20h(WORD CodeSegment
)
533 /* This is the exit interrupt */
534 DosTerminateProcess(CodeSegment
, 0);
537 VOID
DosInt21h(WORD CodeSegment
)
541 SYSTEMTIME SystemTime
;
543 PDOS_INPUT_BUFFER InputBuffer
;
544 DWORD Eax
= EmulatorGetRegister(EMULATOR_REG_AX
);
545 DWORD Ecx
= EmulatorGetRegister(EMULATOR_REG_CX
);
546 DWORD Edx
= EmulatorGetRegister(EMULATOR_REG_DX
);
547 DWORD Ebx
= EmulatorGetRegister(EMULATOR_REG_BX
);
548 WORD DataSegment
= EmulatorGetRegister(EMULATOR_REG_DS
);
549 WORD ExtSegment
= EmulatorGetRegister(EMULATOR_REG_ES
);
551 /* Check the value in the AH register */
554 /* Terminate Program */
557 DosTerminateProcess(CodeSegment
, 0);
561 /* Read Character And Echo */
564 Character
= DosReadCharacter();
565 DosPrintCharacter(Character
);
566 EmulatorSetRegister(EMULATOR_REG_AX
, (Eax
& 0xFFFFFF00) | Character
);
570 /* Print Character */
573 DosPrintCharacter(LOBYTE(Edx
));
577 /* Read Character Without Echo */
580 EmulatorSetRegister(EMULATOR_REG_AX
,
581 (Eax
& 0xFFFFFF00) | DosReadCharacter());
588 String
= (PCHAR
)((ULONG_PTR
)BaseAddress
589 + TO_LINEAR(DataSegment
, LOWORD(Edx
)));
591 while ((*String
) != '$')
593 DosPrintCharacter(*String
);
600 /* Read Buffered Input */
603 InputBuffer
= (PDOS_INPUT_BUFFER
)((ULONG_PTR
)BaseAddress
604 + TO_LINEAR(DataSegment
,
607 InputBuffer
->Length
= 0;
608 for (i
= 0; i
< InputBuffer
->MaxLength
; i
++)
610 Character
= DosReadCharacter();
611 DosPrintCharacter(Character
);
612 InputBuffer
->Buffer
[InputBuffer
->Length
] = Character
;
613 if (Character
== '\r') break;
614 InputBuffer
->Length
++;
620 /* Get system date */
623 GetLocalTime(&SystemTime
);
624 EmulatorSetRegister(EMULATOR_REG_CX
,
625 (Ecx
& 0xFFFF0000) | SystemTime
.wYear
);
626 EmulatorSetRegister(EMULATOR_REG_DX
,
628 | (SystemTime
.wMonth
<< 8)
630 EmulatorSetRegister(EMULATOR_REG_AX
,
631 (Eax
& 0xFFFFFF00) | SystemTime
.wDayOfWeek
);
635 /* Set system date */
638 GetLocalTime(&SystemTime
);
639 SystemTime
.wYear
= LOWORD(Ecx
);
640 SystemTime
.wMonth
= HIBYTE(Edx
);
641 SystemTime
.wDay
= LOBYTE(Edx
);
643 if (SetLocalTime(&SystemTime
))
646 EmulatorSetRegister(EMULATOR_REG_AX
, Eax
& 0xFFFFFF00);
651 EmulatorSetRegister(EMULATOR_REG_AX
, Eax
| 0xFF);
657 /* Get system time */
660 GetLocalTime(&SystemTime
);
661 EmulatorSetRegister(EMULATOR_REG_CX
,
663 | (SystemTime
.wHour
<< 8)
664 | SystemTime
.wMinute
);
665 EmulatorSetRegister(EMULATOR_REG_DX
,
667 | (SystemTime
.wSecond
<< 8)
668 | (SystemTime
.wMilliseconds
/ 10));
672 /* Set system time */
675 GetLocalTime(&SystemTime
);
676 SystemTime
.wHour
= HIBYTE(Ecx
);
677 SystemTime
.wMinute
= LOBYTE(Ecx
);
678 SystemTime
.wSecond
= HIBYTE(Edx
);
679 SystemTime
.wMilliseconds
= LOBYTE(Edx
) * 10;
681 if (SetLocalTime(&SystemTime
))
684 EmulatorSetRegister(EMULATOR_REG_AX
, Eax
& 0xFFFFFF00);
689 EmulatorSetRegister(EMULATOR_REG_AX
, Eax
| 0xFF);
695 /* Create Directory */
698 String
= (PCHAR
)((ULONG_PTR
)BaseAddress
699 + TO_LINEAR(DataSegment
, LOWORD(Edx
)));
701 if (CreateDirectoryA(String
, NULL
))
703 EmulatorClearFlag(EMULATOR_FLAG_CF
);
707 EmulatorSetFlag(EMULATOR_FLAG_CF
);
708 EmulatorSetRegister(EMULATOR_REG_AX
,
709 (Eax
& 0xFFFF0000) | LOWORD(GetLastError()));
715 /* Remove Directory */
718 String
= (PCHAR
)((ULONG_PTR
)BaseAddress
719 + TO_LINEAR(DataSegment
, LOWORD(Edx
)));
721 if (RemoveDirectoryA(String
))
723 EmulatorClearFlag(EMULATOR_FLAG_CF
);
727 EmulatorSetFlag(EMULATOR_FLAG_CF
);
728 EmulatorSetRegister(EMULATOR_REG_AX
,
729 (Eax
& 0xFFFF0000) | LOWORD(GetLastError()));
736 /* Set Current Directory */
739 String
= (PCHAR
)((ULONG_PTR
)BaseAddress
740 + TO_LINEAR(DataSegment
, LOWORD(Edx
)));
742 if (SetCurrentDirectoryA(String
))
744 EmulatorClearFlag(EMULATOR_FLAG_CF
);
748 EmulatorSetFlag(EMULATOR_FLAG_CF
);
749 EmulatorSetRegister(EMULATOR_REG_AX
,
750 (Eax
& 0xFFFF0000) | LOWORD(GetLastError()));
756 /* Allocate Memory */
759 WORD MaxAvailable
= 0;
760 WORD Segment
= DosAllocateMemory(LOWORD(Ebx
), &MaxAvailable
);
764 EmulatorSetRegister(EMULATOR_REG_AX
, Segment
);
765 EmulatorSetRegister(EMULATOR_REG_BX
, MaxAvailable
);
766 EmulatorClearFlag(EMULATOR_FLAG_CF
);
768 else EmulatorSetFlag(EMULATOR_FLAG_CF
);
776 if (DosFreeMemory(ExtSegment
))
778 EmulatorClearFlag(EMULATOR_FLAG_CF
);
780 else EmulatorSetFlag(EMULATOR_FLAG_CF
);
785 /* Resize Memory Block */
788 WORD Size
= DosResizeMemory(ExtSegment
, LOWORD(Ebx
));
792 EmulatorSetRegister(EMULATOR_REG_BX
, Size
);
793 EmulatorClearFlag(EMULATOR_FLAG_CF
);
795 else EmulatorSetFlag(EMULATOR_FLAG_CF
);
800 /* Terminate With Return Code */
803 DosTerminateProcess(CurrentPsp
, LOBYTE(Eax
));
810 EmulatorSetFlag(EMULATOR_FLAG_CF
);
815 VOID
DosBreakInterrupt()
820 BOOLEAN
DosInitialize()
822 PDOS_MCB Mcb
= SEGMENT_TO_MCB(FIRST_MCB_SEGMENT
);
825 LPWSTR SourcePtr
, Environment
;
827 LPSTR DestPtr
= (LPSTR
)((ULONG_PTR
)BaseAddress
+ TO_LINEAR(SYSTEM_ENV_BLOCK
, 0));
830 /* Initialize the MCB */
831 Mcb
->BlockType
= 'Z';
832 Mcb
->Size
= (WORD
)USER_MEMORY_SIZE
;
835 /* Get the environment strings */
836 SourcePtr
= Environment
= GetEnvironmentStringsW();
837 if (Environment
== NULL
) return FALSE
;
839 /* Fill the DOS system environment block */
842 /* Get the size of the ASCII string */
843 AsciiSize
= WideCharToMultiByte(CP_ACP
,
852 /* Allocate memory for the ASCII string */
853 AsciiString
= HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY
, AsciiSize
);
854 if (AsciiString
== NULL
)
856 FreeEnvironmentStringsW(Environment
);
860 /* Convert to ASCII */
861 WideCharToMultiByte(CP_ACP
,
870 /* Copy the string into DOS memory */
871 strcpy(DestPtr
, AsciiString
);
873 /* Free the memory */
874 HeapFree(GetProcessHeap(), 0, AsciiString
);
876 /* Move to the next string */
877 SourcePtr
+= wcslen(SourcePtr
) + 1;
878 DestPtr
+= strlen(AsciiString
) + 1;
881 /* Free the memory allocated for environment strings */
882 FreeEnvironmentStringsW(Environment
);
884 /* Read CONFIG.SYS */
885 Stream
= _wfopen(DOS_CONFIG_PATH
, L
"r");
888 while (fgetws(Buffer
, 256, Stream
))
890 // TODO: Parse the line