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>
9 /* INCLUDES *******************************************************************/
17 /* PRIVATE VARIABLES **********************************************************/
19 static WORD CurrentPsp
= SYSTEM_PSP
;
20 static WORD DosLastError
= 0;
21 static DWORD DiskTransferArea
;
22 static HANDLE DosSystemFileTable
[DOS_SFT_SIZE
];
23 static WORD DosSftRefCount
[DOS_SFT_SIZE
];
24 static BYTE DosAllocStrategy
= DOS_ALLOC_BEST_FIT
;
25 static BOOLEAN DosUmbLinked
= FALSE
;
27 /* PRIVATE FUNCTIONS **********************************************************/
29 static VOID
DosCombineFreeBlocks(WORD StartBlock
)
31 PDOS_MCB CurrentMcb
= SEGMENT_TO_MCB(StartBlock
), NextMcb
;
33 /* If this is the last block or it's not free, quit */
34 if (CurrentMcb
->BlockType
== 'Z' || CurrentMcb
->OwnerPsp
!= 0) return;
38 /* Get a pointer to the next MCB */
39 NextMcb
= SEGMENT_TO_MCB(StartBlock
+ CurrentMcb
->Size
+ 1);
41 /* Check if the next MCB is free */
42 if (NextMcb
->OwnerPsp
== 0)
45 CurrentMcb
->Size
+= NextMcb
->Size
+ 1;
46 CurrentMcb
->BlockType
= NextMcb
->BlockType
;
47 NextMcb
->BlockType
= 'I';
51 /* No more adjoining free blocks */
57 static WORD
DosCopyEnvironmentBlock(WORD SourceSegment
)
59 PCHAR Ptr
, SourceBuffer
, DestBuffer
= NULL
;
63 Ptr
= SourceBuffer
= (PCHAR
)((ULONG_PTR
)BaseAddress
+ TO_LINEAR(SourceSegment
, 0));
65 /* Calculate the size of the environment block */
68 TotalSize
+= strlen(Ptr
) + 1;
69 Ptr
+= strlen(Ptr
) + 1;
73 /* Allocate the memory for the environment block */
74 DestSegment
= DosAllocateMemory((TotalSize
+ 0x0F) >> 4, NULL
);
75 if (!DestSegment
) return 0;
79 DestBuffer
= (PCHAR
)((ULONG_PTR
)BaseAddress
+ TO_LINEAR(DestSegment
, 0));
83 strcpy(DestBuffer
, Ptr
);
85 /* Advance to the next string */
86 DestBuffer
+= strlen(Ptr
);
87 Ptr
+= strlen(Ptr
) + 1;
89 /* Put a zero after the string */
93 /* Set the final zero */
99 static VOID
DosChangeMemoryOwner(WORD Segment
, WORD NewOwner
)
101 PDOS_MCB Mcb
= SEGMENT_TO_MCB(Segment
- 1);
103 /* Just set the owner */
104 Mcb
->OwnerPsp
= NewOwner
;
107 static WORD
DosOpenHandle(HANDLE Handle
)
114 /* The system PSP has no handle table */
115 if (CurrentPsp
== SYSTEM_PSP
) return INVALID_DOS_HANDLE
;
117 /* Get a pointer to the handle table */
118 PspBlock
= SEGMENT_TO_PSP(CurrentPsp
);
119 HandleTable
= (LPBYTE
)FAR_POINTER(PspBlock
->HandleTablePtr
);
121 /* Find a free entry in the JFT */
122 for (DosHandle
= 0; DosHandle
< PspBlock
->HandleTableSize
; DosHandle
++)
124 if (HandleTable
[DosHandle
] == 0xFF) break;
127 /* If there are no free entries, fail */
128 if (DosHandle
== PspBlock
->HandleTableSize
) return INVALID_DOS_HANDLE
;
130 /* Check if the handle is already in the SFT */
131 for (i
= 0; i
< DOS_SFT_SIZE
; i
++)
133 /* Check if this is the same handle */
134 if (DosSystemFileTable
[i
] != Handle
) continue;
136 /* Already in the table, reference it */
139 /* Set the JFT entry to that SFT index */
140 HandleTable
[DosHandle
] = i
;
142 /* Return the new handle */
146 /* Add the handle to the SFT */
147 for (i
= 0; i
< DOS_SFT_SIZE
; i
++)
149 /* Make sure this is an empty table entry */
150 if (DosSystemFileTable
[i
] != INVALID_HANDLE_VALUE
) continue;
152 /* Initialize the empty table entry */
153 DosSystemFileTable
[i
] = Handle
;
154 DosSftRefCount
[i
] = 1;
156 /* Set the JFT entry to that SFT index */
157 HandleTable
[DosHandle
] = i
;
159 /* Return the new handle */
163 /* The SFT is full */
164 return INVALID_DOS_HANDLE
;
167 static HANDLE
DosGetRealHandle(WORD DosHandle
)
172 /* The system PSP has no handle table */
173 if (CurrentPsp
== SYSTEM_PSP
) return INVALID_HANDLE_VALUE
;
175 /* Get a pointer to the handle table */
176 PspBlock
= SEGMENT_TO_PSP(CurrentPsp
);
177 HandleTable
= (LPBYTE
)FAR_POINTER(PspBlock
->HandleTablePtr
);
179 /* Make sure the handle is open */
180 if (HandleTable
[DosHandle
] == 0xFF) return INVALID_HANDLE_VALUE
;
182 /* Return the Win32 handle */
183 return DosSystemFileTable
[HandleTable
[DosHandle
]];
186 static VOID
DosCopyHandleTable(LPBYTE DestinationTable
)
192 /* Clear the table first */
193 for (i
= 0; i
< 20; i
++) DestinationTable
[i
] = 0xFF;
195 /* Check if this is the initial process */
196 if (CurrentPsp
== SYSTEM_PSP
)
198 /* Set up the standard I/O devices */
199 for (i
= 0; i
<= 2; i
++)
201 /* Set the index in the SFT */
202 DestinationTable
[i
] = i
;
204 /* Increase the reference count */
212 /* Get the parent PSP block and handle table */
213 PspBlock
= SEGMENT_TO_PSP(CurrentPsp
);
214 SourceTable
= (LPBYTE
)FAR_POINTER(PspBlock
->HandleTablePtr
);
216 /* Copy the first 20 handles into the new table */
217 for (i
= 0; i
< 20; i
++)
219 DestinationTable
[i
] = SourceTable
[i
];
221 /* Increase the reference count */
222 DosSftRefCount
[SourceTable
[i
]]++;
226 /* PUBLIC FUNCTIONS ***********************************************************/
228 WORD
DosAllocateMemory(WORD Size
, WORD
*MaxAvailable
)
230 WORD Result
= 0, Segment
= FIRST_MCB_SEGMENT
, MaxSize
= 0;
231 PDOS_MCB CurrentMcb
, NextMcb
;
232 BOOLEAN SearchUmb
= FALSE
;
234 DPRINT("DosAllocateMemory: Size 0x%04X\n", Size
);
236 if (DosUmbLinked
&& (DosAllocStrategy
& (DOS_ALLOC_HIGH
| DOS_ALLOC_HIGH_LOW
)))
238 /* Search UMB first */
239 Segment
= UMB_START_SEGMENT
;
245 /* Get a pointer to the MCB */
246 CurrentMcb
= SEGMENT_TO_MCB(Segment
);
248 /* Make sure it's valid */
249 if (CurrentMcb
->BlockType
!= 'M' && CurrentMcb
->BlockType
!= 'Z')
251 DPRINT("The DOS memory arena is corrupted!\n");
252 DosLastError
= ERROR_ARENA_TRASHED
;
256 /* Only check free blocks */
257 if (CurrentMcb
->OwnerPsp
!= 0) goto Next
;
259 /* Combine this free block with adjoining free blocks */
260 DosCombineFreeBlocks(Segment
);
262 /* Update the maximum block size */
263 if (CurrentMcb
->Size
> MaxSize
) MaxSize
= CurrentMcb
->Size
;
265 /* Check if this block is big enough */
266 if (CurrentMcb
->Size
< Size
) goto Next
;
268 switch (DosAllocStrategy
& 0x3F)
270 case DOS_ALLOC_FIRST_FIT
:
272 /* For first fit, stop immediately */
277 case DOS_ALLOC_BEST_FIT
:
279 /* For best fit, update the smallest block found so far */
280 if ((Result
== 0) || (CurrentMcb
->Size
< SEGMENT_TO_MCB(Result
)->Size
))
288 case DOS_ALLOC_LAST_FIT
:
290 /* For last fit, make the current block the result, but keep searching */
297 /* If this was the last MCB in the chain, quit */
298 if (CurrentMcb
->BlockType
== 'Z')
300 /* Check if nothing was found while searching through UMBs */
301 if ((Result
== 0) && SearchUmb
&& (DosAllocStrategy
& DOS_ALLOC_HIGH_LOW
))
303 /* Search low memory */
304 Segment
= FIRST_MCB_SEGMENT
;
311 /* Otherwise, update the segment and continue */
312 Segment
+= CurrentMcb
->Size
+ 1;
317 /* If we didn't find a free block, return 0 */
320 DosLastError
= ERROR_NOT_ENOUGH_MEMORY
;
321 if (MaxAvailable
) *MaxAvailable
= MaxSize
;
325 /* Get a pointer to the MCB */
326 CurrentMcb
= SEGMENT_TO_MCB(Result
);
328 /* Check if the block is larger than requested */
329 if (CurrentMcb
->Size
> Size
)
331 /* It is, split it into two blocks */
332 NextMcb
= SEGMENT_TO_MCB(Result
+ Size
+ 1);
334 /* Initialize the new MCB structure */
335 NextMcb
->BlockType
= CurrentMcb
->BlockType
;
336 NextMcb
->Size
= CurrentMcb
->Size
- Size
- 1;
337 NextMcb
->OwnerPsp
= 0;
339 /* Update the current block */
340 CurrentMcb
->BlockType
= 'M';
341 CurrentMcb
->Size
= Size
;
344 /* Take ownership of the block */
345 CurrentMcb
->OwnerPsp
= CurrentPsp
;
347 /* Return the segment of the data portion of the block */
351 BOOLEAN
DosResizeMemory(WORD BlockData
, WORD NewSize
, WORD
*MaxAvailable
)
353 BOOLEAN Success
= TRUE
;
354 WORD Segment
= BlockData
- 1, ReturnSize
= 0, NextSegment
;
355 PDOS_MCB Mcb
= SEGMENT_TO_MCB(Segment
), NextMcb
;
357 DPRINT("DosResizeMemory: BlockData 0x%04X, NewSize 0x%04X\n",
361 /* Make sure this is a valid, allocated block */
362 if ((Mcb
->BlockType
!= 'M' && Mcb
->BlockType
!= 'Z') || Mcb
->OwnerPsp
== 0)
365 DosLastError
= ERROR_INVALID_HANDLE
;
369 ReturnSize
= Mcb
->Size
;
371 /* Check if we need to expand or contract the block */
372 if (NewSize
> Mcb
->Size
)
374 /* We can't expand the last block */
375 if (Mcb
->BlockType
!= 'M')
381 /* Get the pointer and segment of the next MCB */
382 NextSegment
= Segment
+ Mcb
->Size
+ 1;
383 NextMcb
= SEGMENT_TO_MCB(NextSegment
);
385 /* Make sure the next segment is free */
386 if (NextMcb
->OwnerPsp
!= 0)
388 DPRINT("Cannot expand memory block: next segment is not free!\n");
389 DosLastError
= ERROR_NOT_ENOUGH_MEMORY
;
394 /* Combine this free block with adjoining free blocks */
395 DosCombineFreeBlocks(NextSegment
);
397 /* Set the maximum possible size of the block */
398 ReturnSize
+= NextMcb
->Size
+ 1;
400 /* Maximize the current block */
401 Mcb
->Size
= ReturnSize
;
402 Mcb
->BlockType
= NextMcb
->BlockType
;
404 /* Invalidate the next block */
405 NextMcb
->BlockType
= 'I';
407 /* Check if the block is larger than requested */
408 if (Mcb
->Size
> NewSize
)
410 DPRINT("Block too large, reducing size from 0x%04X to 0x%04X\n",
414 /* It is, split it into two blocks */
415 NextMcb
= SEGMENT_TO_MCB(Segment
+ NewSize
+ 1);
417 /* Initialize the new MCB structure */
418 NextMcb
->BlockType
= Mcb
->BlockType
;
419 NextMcb
->Size
= Mcb
->Size
- NewSize
- 1;
420 NextMcb
->OwnerPsp
= 0;
422 /* Update the current block */
423 Mcb
->BlockType
= 'M';
427 else if (NewSize
< Mcb
->Size
)
429 DPRINT("Shrinking block from 0x%04X to 0x%04X\n",
433 /* Just split the block */
434 NextMcb
= SEGMENT_TO_MCB(Segment
+ NewSize
+ 1);
435 NextMcb
->BlockType
= Mcb
->BlockType
;
436 NextMcb
->Size
= Mcb
->Size
- NewSize
- 1;
437 NextMcb
->OwnerPsp
= 0;
440 Mcb
->BlockType
= 'M';
445 /* Check if the operation failed */
448 DPRINT("DosResizeMemory FAILED. Maximum available: 0x%04X\n",
451 /* Return the maximum possible size */
452 if (MaxAvailable
) *MaxAvailable
= ReturnSize
;
458 BOOLEAN
DosFreeMemory(WORD BlockData
)
460 PDOS_MCB Mcb
= SEGMENT_TO_MCB(BlockData
- 1);
462 DPRINT("DosFreeMemory: BlockData 0x%04X\n", BlockData
);
464 /* Make sure the MCB is valid */
465 if (Mcb
->BlockType
!= 'M' && Mcb
->BlockType
!= 'Z')
467 DPRINT("MCB block type '%c' not valid!\n", Mcb
->BlockType
);
471 /* Mark the block as free */
477 BOOLEAN
DosLinkUmb(VOID
)
479 DWORD Segment
= FIRST_MCB_SEGMENT
;
480 PDOS_MCB Mcb
= SEGMENT_TO_MCB(Segment
);
482 DPRINT("Linking UMB\n");
484 /* Check if UMBs are already linked */
485 if (DosUmbLinked
) return FALSE
;
487 /* Find the last block */
488 while ((Mcb
->BlockType
== 'M') && (Segment
<= 0xFFFF))
490 Segment
+= Mcb
->Size
+ 1;
491 Mcb
= SEGMENT_TO_MCB(Segment
);
494 /* Make sure it's valid */
495 if (Mcb
->BlockType
!= 'Z') return FALSE
;
497 /* Connect the MCB with the UMB chain */
498 Mcb
->BlockType
= 'M';
504 BOOLEAN
DosUnlinkUmb(VOID
)
506 DWORD Segment
= FIRST_MCB_SEGMENT
;
507 PDOS_MCB Mcb
= SEGMENT_TO_MCB(Segment
);
509 DPRINT("Unlinking UMB\n");
511 /* Check if UMBs are already unlinked */
512 if (!DosUmbLinked
) return FALSE
;
514 /* Find the block preceding the MCB that links it with the UMB chain */
515 while (Segment
<= 0xFFFF)
517 if ((Segment
+ Mcb
->Size
) == (FIRST_MCB_SEGMENT
+ USER_MEMORY_SIZE
))
519 /* This is the last non-UMB segment */
523 /* Advance to the next MCB */
524 Segment
+= Mcb
->Size
+ 1;
525 Mcb
= SEGMENT_TO_MCB(Segment
);
528 /* Mark the MCB as the last MCB */
529 Mcb
->BlockType
= 'Z';
531 DosUmbLinked
= FALSE
;
535 WORD
DosCreateFile(LPWORD Handle
, LPCSTR FilePath
, WORD Attributes
)
540 DPRINT("DosCreateFile: FilePath \"%s\", Attributes 0x%04X\n",
544 /* Create the file */
545 FileHandle
= CreateFileA(FilePath
,
546 GENERIC_READ
| GENERIC_WRITE
,
547 FILE_SHARE_READ
| FILE_SHARE_WRITE
| FILE_SHARE_DELETE
,
553 if (FileHandle
== INVALID_HANDLE_VALUE
)
555 /* Return the error code */
556 return GetLastError();
559 /* Open the DOS handle */
560 DosHandle
= DosOpenHandle(FileHandle
);
562 if (DosHandle
== INVALID_DOS_HANDLE
)
564 /* Close the handle */
565 CloseHandle(FileHandle
);
567 /* Return the error code */
568 return ERROR_TOO_MANY_OPEN_FILES
;
571 /* It was successful */
573 return ERROR_SUCCESS
;
576 WORD
DosOpenFile(LPWORD Handle
, LPCSTR FilePath
, BYTE AccessMode
)
579 ACCESS_MASK Access
= 0;
582 DPRINT("DosOpenFile: FilePath \"%s\", AccessMode 0x%04X\n",
586 /* Parse the access mode */
587 switch (AccessMode
& 3)
592 Access
= GENERIC_READ
;
599 Access
= GENERIC_WRITE
;
606 Access
= GENERIC_READ
| GENERIC_WRITE
;
613 return ERROR_INVALID_PARAMETER
;
618 FileHandle
= CreateFileA(FilePath
,
620 FILE_SHARE_READ
| FILE_SHARE_WRITE
| FILE_SHARE_DELETE
,
623 FILE_ATTRIBUTE_NORMAL
,
626 if (FileHandle
== INVALID_HANDLE_VALUE
)
628 /* Return the error code */
629 return GetLastError();
632 /* Open the DOS handle */
633 DosHandle
= DosOpenHandle(FileHandle
);
635 if (DosHandle
== INVALID_DOS_HANDLE
)
637 /* Close the handle */
638 CloseHandle(FileHandle
);
640 /* Return the error code */
641 return ERROR_TOO_MANY_OPEN_FILES
;
644 /* It was successful */
646 return ERROR_SUCCESS
;
649 WORD
DosReadFile(WORD FileHandle
, LPVOID Buffer
, WORD Count
, LPWORD BytesRead
)
651 WORD Result
= ERROR_SUCCESS
;
652 DWORD BytesRead32
= 0;
653 HANDLE Handle
= DosGetRealHandle(FileHandle
);
655 DPRINT("DosReadFile: FileHandle 0x%04X, Count 0x%04X\n", FileHandle
, Count
);
657 /* Make sure the handle is valid */
658 if (Handle
== INVALID_HANDLE_VALUE
) return ERROR_INVALID_HANDLE
;
661 if (!ReadFile(Handle
, Buffer
, Count
, &BytesRead32
, NULL
))
663 /* Store the error code */
664 Result
= GetLastError();
667 /* The number of bytes read is always 16-bit */
668 *BytesRead
= LOWORD(BytesRead32
);
670 /* Return the error code */
674 WORD
DosWriteFile(WORD FileHandle
, LPVOID Buffer
, WORD Count
, LPWORD BytesWritten
)
676 WORD Result
= ERROR_SUCCESS
;
677 DWORD BytesWritten32
= 0;
678 HANDLE Handle
= DosGetRealHandle(FileHandle
);
680 DPRINT("DosWriteFile: FileHandle 0x%04X, Count 0x%04X\n",
684 /* Make sure the handle is valid */
685 if (Handle
== INVALID_HANDLE_VALUE
) return ERROR_INVALID_HANDLE
;
688 if (!WriteFile(Handle
, Buffer
, Count
, &BytesWritten32
, NULL
))
690 /* Store the error code */
691 Result
= GetLastError();
694 /* The number of bytes written is always 16-bit */
695 *BytesWritten
= LOWORD(BytesWritten32
);
697 /* Return the error code */
701 BOOLEAN
DosCloseHandle(WORD DosHandle
)
707 DPRINT("DosCloseHandle: DosHandle 0x%04X\n", DosHandle
);
709 /* The system PSP has no handle table */
710 if (CurrentPsp
== SYSTEM_PSP
) return FALSE
;
712 /* Get a pointer to the handle table */
713 PspBlock
= SEGMENT_TO_PSP(CurrentPsp
);
714 HandleTable
= (LPBYTE
)FAR_POINTER(PspBlock
->HandleTablePtr
);
716 /* Make sure the handle is open */
717 if (HandleTable
[DosHandle
] == 0xFF) return FALSE
;
719 /* Decrement the reference count of the SFT entry */
720 SftIndex
= HandleTable
[DosHandle
];
721 DosSftRefCount
[SftIndex
]--;
723 /* Check if the reference count fell to zero */
724 if (!DosSftRefCount
[SftIndex
])
726 /* Close the file, it's no longer needed */
727 CloseHandle(DosSystemFileTable
[SftIndex
]);
729 /* Clear the handle */
730 DosSystemFileTable
[SftIndex
] = INVALID_HANDLE_VALUE
;
736 VOID
DosInitializePsp(WORD PspSegment
, LPCSTR CommandLine
, WORD ProgramSize
, WORD Environment
)
738 PDOS_PSP PspBlock
= SEGMENT_TO_PSP(PspSegment
);
739 LPDWORD IntVecTable
= (LPDWORD
)((ULONG_PTR
)BaseAddress
);
741 ZeroMemory(PspBlock
, sizeof(DOS_PSP
));
743 /* Set the exit interrupt */
744 PspBlock
->Exit
[0] = 0xCD; // int 0x20
745 PspBlock
->Exit
[1] = 0x20;
747 /* Set the number of the last paragraph */
748 PspBlock
->LastParagraph
= PspSegment
+ ProgramSize
- 1;
750 /* Save the interrupt vectors */
751 PspBlock
->TerminateAddress
= IntVecTable
[0x22];
752 PspBlock
->BreakAddress
= IntVecTable
[0x23];
753 PspBlock
->CriticalAddress
= IntVecTable
[0x24];
755 /* Set the parent PSP */
756 PspBlock
->ParentPsp
= CurrentPsp
;
758 /* Copy the parent handle table */
759 DosCopyHandleTable(PspBlock
->HandleTable
);
761 /* Set the environment block */
762 PspBlock
->EnvBlock
= Environment
;
764 /* Set the handle table pointers to the internal handle table */
765 PspBlock
->HandleTableSize
= 20;
766 PspBlock
->HandleTablePtr
= MAKELONG(0x18, PspSegment
);
768 /* Set the DOS version */
769 PspBlock
->DosVersion
= DOS_VERSION
;
771 /* Set the far call opcodes */
772 PspBlock
->FarCall
[0] = 0xCD; // int 0x21
773 PspBlock
->FarCall
[1] = 0x21;
774 PspBlock
->FarCall
[2] = 0xCB; // retf
776 /* Set the command line */
777 PspBlock
->CommandLineSize
= strlen(CommandLine
);
778 RtlCopyMemory(PspBlock
->CommandLine
, CommandLine
, PspBlock
->CommandLineSize
);
779 PspBlock
->CommandLine
[PspBlock
->CommandLineSize
] = '\r';
782 BOOLEAN
DosCreateProcess(LPCSTR CommandLine
, WORD EnvBlock
)
784 BOOLEAN Success
= FALSE
, AllocatedEnvBlock
= FALSE
;
785 HANDLE FileHandle
= INVALID_HANDLE_VALUE
, FileMapping
= NULL
;
786 LPBYTE Address
= NULL
;
787 LPSTR ProgramFilePath
, Parameters
[128];
788 CHAR CommandLineCopy
[128];
792 DWORD i
, FileSize
, ExeSize
;
793 PIMAGE_DOS_HEADER Header
;
794 PDWORD RelocationTable
;
797 DPRINT("DosCreateProcess: CommandLine \"%s\", EnvBlock 0x%04X\n",
801 /* Save a copy of the command line */
802 strcpy(CommandLineCopy
, CommandLine
);
804 /* Get the file name of the executable */
805 ProgramFilePath
= strtok(CommandLineCopy
, " \t");
807 /* Load the parameters in the local array */
808 while ((ParamCount
< 256)
809 && ((Parameters
[ParamCount
] = strtok(NULL
, " \t")) != NULL
))
814 /* Open a handle to the executable */
815 FileHandle
= CreateFileA(ProgramFilePath
,
820 FILE_ATTRIBUTE_NORMAL
,
822 if (FileHandle
== INVALID_HANDLE_VALUE
) goto Cleanup
;
824 /* Get the file size */
825 FileSize
= GetFileSize(FileHandle
, NULL
);
827 /* Create a mapping object for the file */
828 FileMapping
= CreateFileMapping(FileHandle
,
834 if (FileMapping
== NULL
) goto Cleanup
;
836 /* Map the file into memory */
837 Address
= (LPBYTE
)MapViewOfFile(FileMapping
, FILE_MAP_READ
, 0, 0, 0);
838 if (Address
== NULL
) goto Cleanup
;
840 /* Did we get an environment segment? */
843 /* Set a flag to know if the environment block was allocated here */
844 AllocatedEnvBlock
= TRUE
;
846 /* No, copy the one from the parent */
847 EnvBlock
= DosCopyEnvironmentBlock((CurrentPsp
!= SYSTEM_PSP
)
848 ? SEGMENT_TO_PSP(CurrentPsp
)->EnvBlock
852 /* Check if this is an EXE file or a COM file */
853 if (Address
[0] == 'M' && Address
[1] == 'Z')
857 /* Get the MZ header */
858 Header
= (PIMAGE_DOS_HEADER
)Address
;
860 /* Get the base size of the file, in paragraphs (rounded up) */
861 ExeSize
= (((Header
->e_cp
- 1) * 512) + Header
->e_cblp
+ 0x0F) >> 4;
863 /* Add the PSP size, in paragraphs */
864 ExeSize
+= sizeof(DOS_PSP
) >> 4;
866 /* Add the maximum size that should be allocated */
867 ExeSize
+= Header
->e_maxalloc
;
869 /* Make sure it does not pass 0xFFFF */
870 if (ExeSize
> 0xFFFF) ExeSize
= 0xFFFF;
872 /* Reduce the size one by one until the allocation is successful */
873 for (i
= Header
->e_maxalloc
; i
>= Header
->e_minalloc
; i
--, ExeSize
--)
875 /* Try to allocate that much memory */
876 Segment
= DosAllocateMemory(ExeSize
, NULL
);
877 if (Segment
!= 0) break;
880 /* Check if at least the lowest allocation was successful */
881 if (Segment
== 0) goto Cleanup
;
883 /* Initialize the PSP */
884 DosInitializePsp(Segment
,
889 /* The process owns its own memory */
890 DosChangeMemoryOwner(Segment
, Segment
);
891 DosChangeMemoryOwner(EnvBlock
, Segment
);
893 /* Copy the program to Segment:0100 */
894 RtlCopyMemory((PVOID
)((ULONG_PTR
)BaseAddress
895 + TO_LINEAR(Segment
, 0x100)),
896 Address
+ (Header
->e_cparhdr
<< 4),
897 min(FileSize
- (Header
->e_cparhdr
<< 4),
898 (ExeSize
<< 4) - sizeof(DOS_PSP
)));
900 /* Get the relocation table */
901 RelocationTable
= (PDWORD
)(Address
+ Header
->e_lfarlc
);
903 /* Perform relocations */
904 for (i
= 0; i
< Header
->e_crlc
; i
++)
906 /* Get a pointer to the word that needs to be patched */
907 RelocWord
= (PWORD
)((ULONG_PTR
)BaseAddress
908 + TO_LINEAR(Segment
+ HIWORD(RelocationTable
[i
]),
909 0x100 + LOWORD(RelocationTable
[i
])));
911 /* Add the number of the EXE segment to it */
912 *RelocWord
+= Segment
+ (sizeof(DOS_PSP
) >> 4);
915 /* Set the initial segment registers */
916 EmulatorSetRegister(EMULATOR_REG_DS
, Segment
);
917 EmulatorSetRegister(EMULATOR_REG_ES
, Segment
);
919 /* Set the stack to the location from the header */
920 EmulatorSetStack(Segment
+ (sizeof(DOS_PSP
) >> 4) + Header
->e_ss
,
924 CurrentPsp
= Segment
;
925 DiskTransferArea
= MAKELONG(0x80, Segment
);
926 EmulatorExecute(Segment
+ Header
->e_cs
+ (sizeof(DOS_PSP
) >> 4),
935 /* Find the maximum amount of memory that can be allocated */
936 DosAllocateMemory(0xFFFF, &MaxAllocSize
);
938 /* Make sure it's enough for the whole program and the PSP */
939 if ((MaxAllocSize
<< 4) < (FileSize
+ sizeof(DOS_PSP
))) goto Cleanup
;
941 /* Allocate all of it */
942 Segment
= DosAllocateMemory(MaxAllocSize
, NULL
);
943 if (Segment
== 0) goto Cleanup
;
945 /* The process owns its own memory */
946 DosChangeMemoryOwner(Segment
, Segment
);
947 DosChangeMemoryOwner(EnvBlock
, Segment
);
949 /* Copy the program to Segment:0100 */
950 RtlCopyMemory((PVOID
)((ULONG_PTR
)BaseAddress
951 + TO_LINEAR(Segment
, 0x100)),
955 /* Initialize the PSP */
956 DosInitializePsp(Segment
,
958 (FileSize
+ sizeof(DOS_PSP
)) >> 4,
961 /* Set the initial segment registers */
962 EmulatorSetRegister(EMULATOR_REG_DS
, Segment
);
963 EmulatorSetRegister(EMULATOR_REG_ES
, Segment
);
965 /* Set the stack to the last word of the segment */
966 EmulatorSetStack(Segment
, 0xFFFE);
969 CurrentPsp
= Segment
;
970 DiskTransferArea
= MAKELONG(0x80, Segment
);
971 EmulatorExecute(Segment
, 0x100);
979 /* It was not successful, cleanup the DOS memory */
980 if (AllocatedEnvBlock
) DosFreeMemory(EnvBlock
);
981 if (Segment
) DosFreeMemory(Segment
);
985 if (Address
!= NULL
) UnmapViewOfFile(Address
);
987 /* Close the file mapping object */
988 if (FileMapping
!= NULL
) CloseHandle(FileMapping
);
990 /* Close the file handle */
991 if (FileHandle
!= INVALID_HANDLE_VALUE
) CloseHandle(FileHandle
);
996 VOID
DosTerminateProcess(WORD Psp
, BYTE ReturnCode
)
999 WORD McbSegment
= FIRST_MCB_SEGMENT
;
1000 PDOS_MCB CurrentMcb
;
1001 LPDWORD IntVecTable
= (LPDWORD
)((ULONG_PTR
)BaseAddress
);
1002 PDOS_PSP PspBlock
= SEGMENT_TO_PSP(Psp
);
1004 DPRINT("DosTerminateProcess: Psp 0x%04X, ReturnCode 0x%02X\n",
1008 /* Check if this PSP is it's own parent */
1009 if (PspBlock
->ParentPsp
== Psp
) goto Done
;
1011 for (i
= 0; i
< PspBlock
->HandleTableSize
; i
++)
1013 /* Close the handle */
1017 /* Free the memory used by the process */
1020 /* Get a pointer to the MCB */
1021 CurrentMcb
= SEGMENT_TO_MCB(McbSegment
);
1023 /* Make sure the MCB is valid */
1024 if (CurrentMcb
->BlockType
!= 'M' && CurrentMcb
->BlockType
!='Z') break;
1026 /* If this block was allocated by the process, free it */
1027 if (CurrentMcb
->OwnerPsp
== Psp
) DosFreeMemory(McbSegment
);
1029 /* If this was the last block, quit */
1030 if (CurrentMcb
->BlockType
== 'Z') break;
1032 /* Update the segment and continue */
1033 McbSegment
+= CurrentMcb
->Size
+ 1;
1037 /* Restore the interrupt vectors */
1038 IntVecTable
[0x22] = PspBlock
->TerminateAddress
;
1039 IntVecTable
[0x23] = PspBlock
->BreakAddress
;
1040 IntVecTable
[0x24] = PspBlock
->CriticalAddress
;
1042 /* Update the current PSP */
1043 if (Psp
== CurrentPsp
)
1045 CurrentPsp
= PspBlock
->ParentPsp
;
1046 if (CurrentPsp
== SYSTEM_PSP
) VdmRunning
= FALSE
;
1049 /* Return control to the parent process */
1050 EmulatorExecute(HIWORD(PspBlock
->TerminateAddress
),
1051 LOWORD(PspBlock
->TerminateAddress
));
1054 CHAR
DosReadCharacter(VOID
)
1056 CHAR Character
= '\0';
1059 /* Use the file reading function */
1060 DosReadFile(DOS_INPUT_HANDLE
, &Character
, sizeof(CHAR
), &BytesRead
);
1065 VOID
DosPrintCharacter(CHAR Character
)
1069 /* Use the file writing function */
1070 DosWriteFile(DOS_OUTPUT_HANDLE
, &Character
, sizeof(CHAR
), &BytesWritten
);
1073 VOID
DosHandleIoctl(BYTE ControlCode
, WORD FileHandle
)
1075 HANDLE Handle
= DosGetRealHandle(FileHandle
);
1077 if (Handle
== INVALID_HANDLE_VALUE
)
1080 EmulatorSetFlag(EMULATOR_FLAG_CF
);
1081 EmulatorSetRegister(EMULATOR_REG_AX
, ERROR_FILE_NOT_FOUND
);
1084 switch (ControlCode
)
1086 /* Get Device Information */
1091 if (Handle
== DosSystemFileTable
[0])
1096 else if (Handle
== DosSystemFileTable
[1])
1098 /* Console output */
1102 /* It is a character device */
1105 /* Return the device information word */
1106 EmulatorClearFlag(EMULATOR_FLAG_CF
);
1107 EmulatorSetRegister(EMULATOR_REG_DX
, InfoWord
);
1112 /* Unsupported control code */
1115 DPRINT1("Unsupported IOCTL: 0x%02X\n", ControlCode
);
1117 EmulatorSetFlag(EMULATOR_FLAG_CF
);
1118 EmulatorSetRegister(EMULATOR_REG_AX
, ERROR_INVALID_PARAMETER
);
1123 VOID
DosInt20h(WORD CodeSegment
)
1125 /* This is the exit interrupt */
1126 DosTerminateProcess(CodeSegment
, 0);
1129 VOID
DosInt21h(WORD CodeSegment
)
1133 SYSTEMTIME SystemTime
;
1135 PDOS_INPUT_BUFFER InputBuffer
;
1136 DWORD Eax
= EmulatorGetRegister(EMULATOR_REG_AX
);
1137 DWORD Ecx
= EmulatorGetRegister(EMULATOR_REG_CX
);
1138 DWORD Edx
= EmulatorGetRegister(EMULATOR_REG_DX
);
1139 DWORD Ebx
= EmulatorGetRegister(EMULATOR_REG_BX
);
1140 WORD DataSegment
= EmulatorGetRegister(EMULATOR_REG_DS
);
1141 WORD ExtSegment
= EmulatorGetRegister(EMULATOR_REG_ES
);
1143 /* Check the value in the AH register */
1144 switch (HIBYTE(Eax
))
1146 /* Terminate Program */
1149 DosTerminateProcess(CodeSegment
, 0);
1153 /* Read Character And Echo */
1156 Character
= DosReadCharacter();
1157 DosPrintCharacter(Character
);
1158 EmulatorSetRegister(EMULATOR_REG_AX
, (Eax
& 0xFFFFFF00) | Character
);
1162 /* Print Character */
1165 DosPrintCharacter(LOBYTE(Edx
));
1169 /* Read Character Without Echo */
1173 EmulatorSetRegister(EMULATOR_REG_AX
,
1174 (Eax
& 0xFFFFFF00) | DosReadCharacter());
1181 String
= (PCHAR
)((ULONG_PTR
)BaseAddress
1182 + TO_LINEAR(DataSegment
, LOWORD(Edx
)));
1184 while ((*String
) != '$')
1186 DosPrintCharacter(*String
);
1193 /* Read Buffered Input */
1196 InputBuffer
= (PDOS_INPUT_BUFFER
)((ULONG_PTR
)BaseAddress
1197 + TO_LINEAR(DataSegment
,
1200 InputBuffer
->Length
= 0;
1201 for (i
= 0; i
< InputBuffer
->MaxLength
; i
++)
1203 Character
= DosReadCharacter();
1204 DosPrintCharacter(Character
);
1205 InputBuffer
->Buffer
[InputBuffer
->Length
] = Character
;
1206 if (Character
== '\r') break;
1207 InputBuffer
->Length
++;
1213 /* Set Disk Transfer Area */
1216 DiskTransferArea
= MAKELONG(LOWORD(Edx
), DataSegment
);
1220 /* Set Interrupt Vector */
1223 DWORD FarPointer
= MAKELONG(LOWORD(Edx
), DataSegment
);
1225 /* Write the new far pointer to the IDT */
1226 ((PDWORD
)BaseAddress
)[LOBYTE(Eax
)] = FarPointer
;
1231 /* Get system date */
1234 GetLocalTime(&SystemTime
);
1235 EmulatorSetRegister(EMULATOR_REG_CX
,
1236 (Ecx
& 0xFFFF0000) | SystemTime
.wYear
);
1237 EmulatorSetRegister(EMULATOR_REG_DX
,
1239 | (SystemTime
.wMonth
<< 8)
1241 EmulatorSetRegister(EMULATOR_REG_AX
,
1242 (Eax
& 0xFFFFFF00) | SystemTime
.wDayOfWeek
);
1246 /* Set system date */
1249 GetLocalTime(&SystemTime
);
1250 SystemTime
.wYear
= LOWORD(Ecx
);
1251 SystemTime
.wMonth
= HIBYTE(Edx
);
1252 SystemTime
.wDay
= LOBYTE(Edx
);
1254 if (SetLocalTime(&SystemTime
))
1256 /* Return success */
1257 EmulatorSetRegister(EMULATOR_REG_AX
, Eax
& 0xFFFFFF00);
1261 /* Return failure */
1262 EmulatorSetRegister(EMULATOR_REG_AX
, Eax
| 0xFF);
1268 /* Get system time */
1271 GetLocalTime(&SystemTime
);
1272 EmulatorSetRegister(EMULATOR_REG_CX
,
1274 | (SystemTime
.wHour
<< 8)
1275 | SystemTime
.wMinute
);
1276 EmulatorSetRegister(EMULATOR_REG_DX
,
1278 | (SystemTime
.wSecond
<< 8)
1279 | (SystemTime
.wMilliseconds
/ 10));
1283 /* Set system time */
1286 GetLocalTime(&SystemTime
);
1287 SystemTime
.wHour
= HIBYTE(Ecx
);
1288 SystemTime
.wMinute
= LOBYTE(Ecx
);
1289 SystemTime
.wSecond
= HIBYTE(Edx
);
1290 SystemTime
.wMilliseconds
= LOBYTE(Edx
) * 10;
1292 if (SetLocalTime(&SystemTime
))
1294 /* Return success */
1295 EmulatorSetRegister(EMULATOR_REG_AX
, Eax
& 0xFFFFFF00);
1299 /* Return failure */
1300 EmulatorSetRegister(EMULATOR_REG_AX
, Eax
| 0xFF);
1306 /* Get Disk Transfer Area */
1309 EmulatorSetRegister(EMULATOR_REG_ES
, HIWORD(DiskTransferArea
));
1310 EmulatorSetRegister(EMULATOR_REG_BX
, LOWORD(DiskTransferArea
));
1315 /* Get DOS Version */
1318 PDOS_PSP PspBlock
= SEGMENT_TO_PSP(CurrentPsp
);
1320 EmulatorSetRegister(EMULATOR_REG_AX
, PspBlock
->DosVersion
);
1324 /* Get Interrupt Vector */
1327 DWORD FarPointer
= ((PDWORD
)BaseAddress
)[LOBYTE(Eax
)];
1329 /* Read the address from the IDT into ES:BX */
1330 EmulatorSetRegister(EMULATOR_REG_ES
, HIWORD(FarPointer
));
1331 EmulatorSetRegister(EMULATOR_REG_BX
, LOWORD(FarPointer
));
1336 /* Create Directory */
1339 String
= (PCHAR
)((ULONG_PTR
)BaseAddress
1340 + TO_LINEAR(DataSegment
, LOWORD(Edx
)));
1342 if (CreateDirectoryA(String
, NULL
))
1344 EmulatorClearFlag(EMULATOR_FLAG_CF
);
1348 EmulatorSetFlag(EMULATOR_FLAG_CF
);
1349 EmulatorSetRegister(EMULATOR_REG_AX
,
1350 (Eax
& 0xFFFF0000) | LOWORD(GetLastError()));
1356 /* Remove Directory */
1359 String
= (PCHAR
)((ULONG_PTR
)BaseAddress
1360 + TO_LINEAR(DataSegment
, LOWORD(Edx
)));
1362 if (RemoveDirectoryA(String
))
1364 EmulatorClearFlag(EMULATOR_FLAG_CF
);
1368 EmulatorSetFlag(EMULATOR_FLAG_CF
);
1369 EmulatorSetRegister(EMULATOR_REG_AX
,
1370 (Eax
& 0xFFFF0000) | LOWORD(GetLastError()));
1377 /* Set Current Directory */
1380 String
= (PCHAR
)((ULONG_PTR
)BaseAddress
1381 + TO_LINEAR(DataSegment
, LOWORD(Edx
)));
1383 if (SetCurrentDirectoryA(String
))
1385 EmulatorClearFlag(EMULATOR_FLAG_CF
);
1389 EmulatorSetFlag(EMULATOR_FLAG_CF
);
1390 EmulatorSetRegister(EMULATOR_REG_AX
,
1391 (Eax
& 0xFFFF0000) | LOWORD(GetLastError()));
1401 WORD ErrorCode
= DosCreateFile(&FileHandle
,
1402 (LPCSTR
)(ULONG_PTR
)BaseAddress
1403 + TO_LINEAR(DataSegment
, LOWORD(Edx
)),
1409 EmulatorClearFlag(EMULATOR_FLAG_CF
);
1411 /* Return the handle in AX */
1412 EmulatorSetRegister(EMULATOR_REG_AX
,
1413 (Eax
& 0xFFFF0000) | FileHandle
);
1418 EmulatorSetFlag(EMULATOR_FLAG_CF
);
1420 /* Return the error code in AX */
1421 EmulatorSetRegister(EMULATOR_REG_AX
,
1422 (Eax
& 0xFFFF0000) | ErrorCode
);
1432 WORD ErrorCode
= DosCreateFile(&FileHandle
,
1433 (LPCSTR
)(ULONG_PTR
)BaseAddress
1434 + TO_LINEAR(DataSegment
, LOWORD(Edx
)),
1440 EmulatorClearFlag(EMULATOR_FLAG_CF
);
1442 /* Return the handle in AX */
1443 EmulatorSetRegister(EMULATOR_REG_AX
,
1444 (Eax
& 0xFFFF0000) | FileHandle
);
1449 EmulatorSetFlag(EMULATOR_FLAG_CF
);
1451 /* Return the error code in AX */
1452 EmulatorSetRegister(EMULATOR_REG_AX
,
1453 (Eax
& 0xFFFF0000) | ErrorCode
);
1462 if (DosCloseHandle(LOWORD(Ebx
)))
1465 EmulatorClearFlag(EMULATOR_FLAG_CF
);
1470 EmulatorSetFlag(EMULATOR_FLAG_CF
);
1472 /* Return the error code in AX */
1473 EmulatorSetRegister(EMULATOR_REG_AX
,
1474 (Eax
& 0xFFFF0000) | ERROR_INVALID_HANDLE
);
1484 WORD ErrorCode
= DosReadFile(LOWORD(Ebx
),
1485 (LPVOID
)((ULONG_PTR
)BaseAddress
1486 + TO_LINEAR(DataSegment
, LOWORD(Edx
))),
1493 EmulatorClearFlag(EMULATOR_FLAG_CF
);
1495 /* Return the number of bytes read in AX */
1496 EmulatorSetRegister(EMULATOR_REG_AX
,
1497 (Eax
& 0xFFFF0000) | BytesRead
);
1502 EmulatorSetFlag(EMULATOR_FLAG_CF
);
1504 /* Return the error code in AX */
1505 EmulatorSetRegister(EMULATOR_REG_AX
,
1506 (Eax
& 0xFFFF0000) | ErrorCode
);
1514 WORD BytesWritten
= 0;
1515 WORD ErrorCode
= DosWriteFile(LOWORD(Ebx
),
1516 (LPVOID
)((ULONG_PTR
)BaseAddress
1517 + TO_LINEAR(DataSegment
, LOWORD(Edx
))),
1524 EmulatorClearFlag(EMULATOR_FLAG_CF
);
1526 /* Return the number of bytes written in AX */
1527 EmulatorSetRegister(EMULATOR_REG_AX
,
1528 (Eax
& 0xFFFF0000) | BytesWritten
);
1533 EmulatorSetFlag(EMULATOR_FLAG_CF
);
1535 /* Return the error code in AX */
1536 EmulatorSetRegister(EMULATOR_REG_AX
,
1537 (Eax
& 0xFFFF0000) | ErrorCode
);
1546 DosHandleIoctl(LOBYTE(Eax
), LOWORD(Ebx
));
1551 /* Allocate Memory */
1554 WORD MaxAvailable
= 0;
1555 WORD Segment
= DosAllocateMemory(LOWORD(Ebx
), &MaxAvailable
);
1559 EmulatorSetRegister(EMULATOR_REG_AX
, Segment
);
1560 EmulatorClearFlag(EMULATOR_FLAG_CF
);
1564 EmulatorSetRegister(EMULATOR_REG_AX
, DosLastError
);
1565 EmulatorSetRegister(EMULATOR_REG_BX
, MaxAvailable
);
1566 EmulatorSetFlag(EMULATOR_FLAG_CF
);
1575 if (DosFreeMemory(ExtSegment
))
1577 EmulatorClearFlag(EMULATOR_FLAG_CF
);
1581 EmulatorSetRegister(EMULATOR_REG_AX
, ERROR_ARENA_TRASHED
);
1582 EmulatorSetFlag(EMULATOR_FLAG_CF
);
1588 /* Resize Memory Block */
1593 if (DosResizeMemory(ExtSegment
, LOWORD(Ebx
), &Size
))
1595 EmulatorClearFlag(EMULATOR_FLAG_CF
);
1599 EmulatorSetRegister(EMULATOR_REG_AX
, DosLastError
);
1600 EmulatorSetFlag(EMULATOR_FLAG_CF
);
1601 EmulatorSetRegister(EMULATOR_REG_BX
, Size
);
1607 /* Terminate With Return Code */
1610 DosTerminateProcess(CurrentPsp
, LOBYTE(Eax
));
1614 /* Get/Set Memory Management Options */
1617 if (LOBYTE(Eax
) == 0x00)
1619 /* Get allocation strategy */
1621 EmulatorSetRegister(EMULATOR_REG_AX
, DosAllocStrategy
);
1622 EmulatorClearFlag(EMULATOR_FLAG_CF
);
1624 else if (LOBYTE(Eax
) == 0x01)
1626 /* Set allocation strategy */
1628 if ((LOBYTE(Ebx
) & (DOS_ALLOC_HIGH
| DOS_ALLOC_HIGH_LOW
))
1629 == (DOS_ALLOC_HIGH
| DOS_ALLOC_HIGH_LOW
))
1631 /* Can't set both */
1632 EmulatorSetRegister(EMULATOR_REG_AX
, ERROR_INVALID_PARAMETER
);
1633 EmulatorSetFlag(EMULATOR_FLAG_CF
);
1637 if ((LOBYTE(Ebx
) & 0x3F) > DOS_ALLOC_LAST_FIT
)
1639 /* Invalid allocation strategy */
1640 EmulatorSetRegister(EMULATOR_REG_AX
, ERROR_INVALID_PARAMETER
);
1641 EmulatorSetFlag(EMULATOR_FLAG_CF
);
1645 DosAllocStrategy
= LOBYTE(Ebx
);
1646 EmulatorClearFlag(EMULATOR_FLAG_CF
);
1648 else if (LOBYTE(Eax
) == 0x02)
1650 /* Get UMB link state */
1653 if (DosUmbLinked
) Eax
|= 1;
1654 EmulatorSetRegister(EMULATOR_REG_AX
, Eax
);
1655 EmulatorClearFlag(EMULATOR_FLAG_CF
);
1657 else if (LOBYTE(Eax
) == 0x03)
1659 /* Set UMB link state */
1661 if (Ebx
) DosLinkUmb();
1662 else DosUnlinkUmb();
1663 EmulatorClearFlag(EMULATOR_FLAG_CF
);
1667 /* Invalid or unsupported function */
1669 EmulatorSetFlag(EMULATOR_FLAG_CF
);
1670 EmulatorSetRegister(EMULATOR_REG_AX
, ERROR_INVALID_FUNCTION
);
1679 DPRINT1("DOS Function INT 0x21, AH = 0x%02X NOT IMPLEMENTED!\n", HIBYTE(Eax
));
1680 EmulatorSetFlag(EMULATOR_FLAG_CF
);
1685 VOID
DosBreakInterrupt(VOID
)
1690 BOOLEAN
DosInitialize(VOID
)
1693 PDOS_MCB Mcb
= SEGMENT_TO_MCB(FIRST_MCB_SEGMENT
);
1696 LPWSTR SourcePtr
, Environment
;
1698 LPSTR DestPtr
= (LPSTR
)((ULONG_PTR
)BaseAddress
+ TO_LINEAR(SYSTEM_ENV_BLOCK
, 0));
1701 /* Initialize the MCB */
1702 Mcb
->BlockType
= 'Z';
1703 Mcb
->Size
= USER_MEMORY_SIZE
;
1706 /* Initialize the link MCB to the UMB area */
1707 Mcb
= SEGMENT_TO_MCB(FIRST_MCB_SEGMENT
+ USER_MEMORY_SIZE
+ 1);
1708 Mcb
->BlockType
= 'M';
1709 Mcb
->Size
= UMB_START_SEGMENT
- FIRST_MCB_SEGMENT
- USER_MEMORY_SIZE
- 2;
1710 Mcb
->OwnerPsp
= SYSTEM_PSP
;
1712 /* Initialize the UMB area */
1713 Mcb
= SEGMENT_TO_MCB(UMB_START_SEGMENT
);
1714 Mcb
->BlockType
= 'Z';
1715 Mcb
->Size
= UMB_END_SEGMENT
- UMB_START_SEGMENT
;
1718 /* Get the environment strings */
1719 SourcePtr
= Environment
= GetEnvironmentStringsW();
1720 if (Environment
== NULL
) return FALSE
;
1722 /* Fill the DOS system environment block */
1725 /* Get the size of the ASCII string */
1726 AsciiSize
= WideCharToMultiByte(CP_ACP
,
1735 /* Allocate memory for the ASCII string */
1736 AsciiString
= HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY
, AsciiSize
);
1737 if (AsciiString
== NULL
)
1739 FreeEnvironmentStringsW(Environment
);
1743 /* Convert to ASCII */
1744 WideCharToMultiByte(CP_ACP
,
1753 /* Copy the string into DOS memory */
1754 strcpy(DestPtr
, AsciiString
);
1756 /* Move to the next string */
1757 SourcePtr
+= wcslen(SourcePtr
) + 1;
1758 DestPtr
+= strlen(AsciiString
);
1761 /* Free the memory */
1762 HeapFree(GetProcessHeap(), 0, AsciiString
);
1766 /* Free the memory allocated for environment strings */
1767 FreeEnvironmentStringsW(Environment
);
1769 /* Read CONFIG.SYS */
1770 Stream
= _wfopen(DOS_CONFIG_PATH
, L
"r");
1773 while (fgetws(Buffer
, 256, Stream
))
1775 // TODO: Parse the line
1780 /* Initialize the SFT */
1781 for (i
= 0; i
< DOS_SFT_SIZE
; i
++)
1783 DosSystemFileTable
[i
] = INVALID_HANDLE_VALUE
;
1784 DosSftRefCount
[i
] = 0;
1787 /* Get handles to standard I/O devices */
1788 DosSystemFileTable
[0] = GetStdHandle(STD_INPUT_HANDLE
);
1789 DosSystemFileTable
[1] = GetStdHandle(STD_OUTPUT_HANDLE
);
1790 DosSystemFileTable
[2] = GetStdHandle(STD_ERROR_HANDLE
);