2 * COPYRIGHT: GPL - See COPYING in the top level directory
3 * PROJECT: ReactOS Virtual DOS Machine
4 * FILE: dos/dos32krnl/dos.c
5 * PURPOSE: DOS32 Kernel
6 * PROGRAMMERS: Aleksandar Andrejevic <theflash AT sdf DOT lonestar DOT org>
7 * Hermes Belusca-Maito (hermes.belusca@sfr.fr)
10 /* INCLUDES *******************************************************************/
28 #include "bios/bios.h"
31 #include "hardware/ps2.h"
35 /* PRIVATE VARIABLES **********************************************************/
37 #define INDOS_POINTER MAKELONG(0x00FE, 0x0070)
39 CALLBACK16 DosContext
;
41 /*static*/ BYTE CurrentDrive
;
42 static CHAR LastDrive
= 'E';
43 static CHAR CurrentDirectories
[NUM_DRIVES
][DOS_DIR_LENGTH
];
46 /* PUBLIC VARIABLES ***********************************************************/
50 /* Echo state for INT 21h, AH = 01h and AH = 3Fh */
51 BOOLEAN DoEcho
= FALSE
;
53 DWORD DiskTransferArea
;
54 WORD DosErrorLevel
= 0x0000;
55 WORD DosLastError
= 0;
57 /* PRIVATE FUNCTIONS **********************************************************/
59 static BOOLEAN
DosChangeDrive(BYTE Drive
)
61 WCHAR DirectoryPath
[DOS_CMDLINE_LENGTH
];
63 /* Make sure the drive exists */
64 if (Drive
> (LastDrive
- 'A')) return FALSE
;
66 /* Find the path to the new current directory */
67 swprintf(DirectoryPath
, L
"%c\\%S", Drive
+ 'A', CurrentDirectories
[Drive
]);
69 /* Change the current directory of the process */
70 if (!SetCurrentDirectory(DirectoryPath
)) return FALSE
;
72 /* Set the current drive */
79 static BOOLEAN
DosChangeDirectory(LPSTR Directory
)
85 /* Make sure the directory path is not too long */
86 if (strlen(Directory
) >= DOS_DIR_LENGTH
)
88 DosLastError
= ERROR_PATH_NOT_FOUND
;
92 /* Get the drive number */
93 DriveNumber
= Directory
[0] - 'A';
95 /* Make sure the drive exists */
96 if (DriveNumber
> (LastDrive
- 'A'))
98 DosLastError
= ERROR_PATH_NOT_FOUND
;
102 /* Get the file attributes */
103 Attributes
= GetFileAttributesA(Directory
);
105 /* Make sure the path exists and is a directory */
106 if ((Attributes
== INVALID_FILE_ATTRIBUTES
)
107 || !(Attributes
& FILE_ATTRIBUTE_DIRECTORY
))
109 DosLastError
= ERROR_PATH_NOT_FOUND
;
113 /* Check if this is the current drive */
114 if (DriveNumber
== CurrentDrive
)
116 /* Change the directory */
117 if (!SetCurrentDirectoryA(Directory
))
119 DosLastError
= LOWORD(GetLastError());
124 /* Get the directory part of the path */
125 Path
= strchr(Directory
, '\\');
128 /* Skip the backslash */
132 /* Set the directory for the drive */
135 strncpy(CurrentDirectories
[DriveNumber
], Path
, DOS_DIR_LENGTH
);
139 CurrentDirectories
[DriveNumber
][0] = '\0';
146 static BOOLEAN
DosControlBreak(VOID
)
150 /* Call interrupt 0x23 */
151 Int32Call(&DosContext
, 0x23);
155 DosTerminateProcess(CurrentPsp
, 0, 0);
162 /* PUBLIC FUNCTIONS ***********************************************************/
164 VOID
DosInitializePsp(WORD PspSegment
,
170 PDOS_PSP PspBlock
= SEGMENT_TO_PSP(PspSegment
);
171 LPDWORD IntVecTable
= (LPDWORD
)((ULONG_PTR
)BaseAddress
);
173 RtlZeroMemory(PspBlock
, sizeof(*PspBlock
));
175 /* Set the exit interrupt */
176 PspBlock
->Exit
[0] = 0xCD; // int 0x20
177 PspBlock
->Exit
[1] = 0x20;
179 /* Set the number of the last paragraph */
180 PspBlock
->LastParagraph
= PspSegment
+ ProgramSize
- 1;
182 /* Save the interrupt vectors */
183 PspBlock
->TerminateAddress
= ReturnAddress
;
184 PspBlock
->BreakAddress
= IntVecTable
[0x23];
185 PspBlock
->CriticalAddress
= IntVecTable
[0x24];
187 /* Set the parent PSP */
188 PspBlock
->ParentPsp
= CurrentPsp
;
190 /* Copy the parent handle table */
191 DosCopyHandleTable(PspBlock
->HandleTable
);
193 /* Set the environment block */
194 PspBlock
->EnvBlock
= Environment
;
196 /* Set the handle table pointers to the internal handle table */
197 PspBlock
->HandleTableSize
= 20;
198 PspBlock
->HandleTablePtr
= MAKELONG(0x18, PspSegment
);
200 /* Set the DOS version */
201 PspBlock
->DosVersion
= DOS_VERSION
;
203 /* Set the far call opcodes */
204 PspBlock
->FarCall
[0] = 0xCD; // int 0x21
205 PspBlock
->FarCall
[1] = 0x21;
206 PspBlock
->FarCall
[2] = 0xCB; // retf
210 /* Set the command line */
211 PspBlock
->CommandLineSize
= (BYTE
)min(strlen(CommandLine
), DOS_CMDLINE_LENGTH
- 1);
212 RtlCopyMemory(PspBlock
->CommandLine
, CommandLine
, PspBlock
->CommandLineSize
);
213 PspBlock
->CommandLine
[PspBlock
->CommandLineSize
] = '\r';
217 VOID WINAPI
DosInt20h(LPWORD Stack
)
219 /* This is the exit interrupt */
220 DosTerminateProcess(Stack
[STACK_CS
], 0, 0);
223 VOID WINAPI
DosInt21h(LPWORD Stack
)
226 SYSTEMTIME SystemTime
;
228 PDOS_INPUT_BUFFER InputBuffer
;
229 PDOS_COUNTRY_CODE_BUFFER CountryCodeBuffer
;
234 /* Check the value in the AH register */
237 /* Terminate Program */
240 DosTerminateProcess(Stack
[STACK_CS
], 0, 0);
244 /* Read Character from STDIN with Echo */
247 DPRINT("INT 21h, AH = 01h\n");
249 // FIXME: Under DOS 2+, input / output handle may be redirected!!!!
251 Character
= DosReadCharacter(DOS_INPUT_HANDLE
);
254 // FIXME: Check whether Ctrl-C / Ctrl-Break is pressed, and call INT 23h if so.
255 // Check also Ctrl-P and set echo-to-printer flag.
256 // Ctrl-Z is not interpreted.
262 /* Write Character to STDOUT */
265 // FIXME: Under DOS 2+, output handle may be redirected!!!!
267 DosPrintCharacter(DOS_OUTPUT_HANDLE
, Character
);
270 * We return the output character (DOS 2.1+).
271 * Also, if we're going to output a TAB, then
272 * don't return a TAB but a SPACE instead.
273 * See Ralf Brown: http://www.ctyme.com/intr/rb-2554.htm
274 * for more information.
276 setAL(Character
== '\t' ? ' ' : Character
);
280 /* Read Character from STDAUX */
283 // FIXME: Really read it from STDAUX!
284 DPRINT1("INT 16h, 03h: Read character from STDAUX is HALFPLEMENTED\n");
285 // setAL(DosReadCharacter());
289 /* Write Character to STDAUX */
292 // FIXME: Really write it to STDAUX!
293 DPRINT1("INT 16h, 04h: Write character to STDAUX is HALFPLEMENTED\n");
294 // DosPrintCharacter(getDL());
298 /* Write Character to Printer */
301 // FIXME: Really write it to printer!
302 DPRINT1("INT 16h, 05h: Write character to printer is HALFPLEMENTED -\n\n");
303 DPRINT1("0x%p\n", getDL());
304 DPRINT1("\n\n-----------\n\n");
308 /* Direct Console I/O */
313 // FIXME: Under DOS 2+, output handle may be redirected!!!!
315 if (Character
!= 0xFF)
318 DosPrintCharacter(DOS_OUTPUT_HANDLE
, Character
);
321 * We return the output character (DOS 2.1+).
322 * See Ralf Brown: http://www.ctyme.com/intr/rb-2558.htm
323 * for more information.
332 Stack
[STACK_FLAGS
] &= ~EMULATOR_FLAG_ZF
;
333 setAL(DosReadCharacter(DOS_INPUT_HANDLE
));
337 /* No character available */
338 Stack
[STACK_FLAGS
] |= EMULATOR_FLAG_ZF
;
346 /* Character Input without Echo */
350 DPRINT("Char input without echo\n");
352 Character
= DosReadCharacter(DOS_INPUT_HANDLE
);
354 // FIXME: For 0x07, do not check Ctrl-C/Break.
355 // For 0x08, do check those control sequences and if needed,
362 /* Write string to STDOUT */
365 String
= (PCHAR
)SEG_OFF_TO_PTR(getDS(), getDX());
367 while (*String
!= '$')
369 DosPrintCharacter(DOS_OUTPUT_HANDLE
, *String
);
374 * We return the terminating character (DOS 2.1+).
375 * See Ralf Brown: http://www.ctyme.com/intr/rb-2562.htm
376 * for more information.
378 setAL('$'); // *String
382 /* Read Buffered Input */
386 InputBuffer
= (PDOS_INPUT_BUFFER
)SEG_OFF_TO_PTR(getDS(), getDX());
388 DPRINT("Read Buffered Input\n");
390 while (Count
< InputBuffer
->MaxLength
)
392 /* Try to read a character (wait) */
393 Character
= DosReadCharacter(DOS_INPUT_HANDLE
);
397 /* Extended character */
400 /* Read the scancode */
401 DosReadCharacter(DOS_INPUT_HANDLE
);
408 DosPrintCharacter(DOS_OUTPUT_HANDLE
, '^');
409 DosPrintCharacter(DOS_OUTPUT_HANDLE
, 'C');
411 if (DosControlBreak())
413 /* Set the character to a newline to exit the loop */
427 /* Erase the character */
428 DosPrintCharacter(DOS_OUTPUT_HANDLE
, '\b');
429 DosPrintCharacter(DOS_OUTPUT_HANDLE
, ' ');
430 DosPrintCharacter(DOS_OUTPUT_HANDLE
, '\b');
438 /* Append it to the buffer */
439 InputBuffer
->Buffer
[Count
] = Character
;
441 /* Check if this is a special character */
442 if (Character
< 0x20 && Character
!= 0x0A && Character
!= 0x0D)
444 DosPrintCharacter(DOS_OUTPUT_HANDLE
, '^');
445 Character
+= 'A' - 1;
448 /* Echo the character */
449 DosPrintCharacter(DOS_OUTPUT_HANDLE
, Character
);
453 if (Character
== '\r') break;
454 Count
++; /* Carriage returns are NOT counted */
457 /* Update the length */
458 InputBuffer
->Length
= Count
;
463 /* Get STDIN Status */
466 setAL(DosCheckInput() ? 0xFF : 0x00);
470 /* Flush Buffer and Read STDIN */
473 BYTE InputFunction
= getAL();
475 /* Flush STDIN buffer */
476 DosFlushFileBuffers(DOS_INPUT_HANDLE
);
479 * If the input function number contained in AL is valid, i.e.
480 * AL == 0x01 or 0x06 or 0x07 or 0x08 or 0x0A, call ourselves
481 * recursively with AL == AH.
483 if (InputFunction
== 0x01 || InputFunction
== 0x06 ||
484 InputFunction
== 0x07 || InputFunction
== 0x08 ||
485 InputFunction
== 0x0A)
487 /* Call ourselves recursively */
488 setAH(InputFunction
);
497 PDOS_PSP PspBlock
= SEGMENT_TO_PSP(CurrentPsp
);
499 // TODO: Flush what's needed.
500 DPRINT1("INT 21h, 0Dh is UNIMPLEMENTED\n");
502 /* Clear CF in DOS 6 only */
503 if (PspBlock
->DosVersion
== 0x0006)
504 Stack
[STACK_FLAGS
] &= ~EMULATOR_FLAG_CF
;
509 /* Set Default Drive */
512 DosChangeDrive(getDL());
513 setAL(LastDrive
- 'A' + 1);
517 /* NULL Function for CP/M Compatibility */
521 * This function corresponds to the CP/M BDOS function
522 * "get bit map of logged drives", which is meaningless
525 * For: PTS-DOS 6.51 & S/DOS 1.0 - EXTENDED RENAME FILE USING FCB
526 * See Ralf Brown: http://www.ctyme.com/intr/rb-2584.htm
527 * for more information.
533 /* Get Default Drive */
540 /* Set Disk Transfer Area */
543 DiskTransferArea
= MAKELONG(getDX(), getDS());
547 /* NULL Function for CP/M Compatibility */
552 * Function 0x1D corresponds to the CP/M BDOS function
553 * "get bit map of read-only drives", which is meaningless
555 * See Ralf Brown: http://www.ctyme.com/intr/rb-2592.htm
556 * for more information.
558 * Function 0x1E corresponds to the CP/M BDOS function
559 * "set file attributes", which was meaningless under MS-DOS 1.x.
560 * See Ralf Brown: http://www.ctyme.com/intr/rb-2593.htm
561 * for more information.
567 /* NULL Function for CP/M Compatibility */
571 * This function corresponds to the CP/M BDOS function
572 * "get/set default user (sublibrary) number", which is meaningless
575 * For: S/DOS 1.0+ & PTS-DOS 6.51+ - GET OEM REVISION
576 * See Ralf Brown: http://www.ctyme.com/intr/rb-2596.htm
577 * for more information.
583 /* Set Interrupt Vector */
586 ULONG FarPointer
= MAKELONG(getDX(), getDS());
587 DPRINT1("Setting interrupt 0x%02X to %04X:%04X ...\n",
588 getAL(), HIWORD(FarPointer
), LOWORD(FarPointer
));
590 /* Write the new far pointer to the IDT */
591 ((PULONG
)BaseAddress
)[getAL()] = FarPointer
;
598 DosClonePsp(getDX(), getCS());
602 /* Parse Filename into FCB */
605 PCHAR FileName
= (PCHAR
)SEG_OFF_TO_PTR(getDS(), getSI());
606 PDOS_FCB Fcb
= (PDOS_FCB
)SEG_OFF_TO_PTR(getES(), getDI());
607 BYTE Options
= getAL();
611 if (FileName
[1] == ':')
613 /* Set the drive number */
614 Fcb
->DriveNumber
= RtlUpperChar(FileName
[0]) - 'A' + 1;
616 /* Skip to the file name part */
621 /* No drive number specified */
622 if (Options
& (1 << 1)) Fcb
->DriveNumber
= CurrentDrive
+ 1;
623 else Fcb
->DriveNumber
= 0;
626 /* Parse the file name */
628 while ((*FileName
> 0x20) && (i
< 8))
630 if (*FileName
== '.') break;
631 else if (*FileName
== '*')
637 Fcb
->FileName
[i
++] = RtlUpperChar(*FileName
++);
640 /* Fill the whole field with blanks only if bit 2 is not set */
641 if ((FillChar
!= ' ') || (i
!= 0) || !(Options
& (1 << 2)))
643 for (; i
< 8; i
++) Fcb
->FileName
[i
] = FillChar
;
646 /* Skip to the extension part */
647 while (*FileName
> 0x20 && *FileName
!= '.') FileName
++;
648 if (*FileName
== '.') FileName
++;
650 /* Now parse the extension */
654 while ((*FileName
> 0x20) && (i
< 3))
656 if (*FileName
== '*')
662 Fcb
->FileExt
[i
++] = RtlUpperChar(*FileName
++);
665 /* Fill the whole field with blanks only if bit 3 is not set */
666 if ((FillChar
!= ' ') || (i
!= 0) || !(Options
& (1 << 3)))
668 for (; i
< 3; i
++) Fcb
->FileExt
[i
] = FillChar
;
674 /* Get System Date */
677 GetLocalTime(&SystemTime
);
678 setCX(SystemTime
.wYear
);
679 setDX(MAKEWORD(SystemTime
.wDay
, SystemTime
.wMonth
));
680 setAL(SystemTime
.wDayOfWeek
);
684 /* Set System Date */
687 GetLocalTime(&SystemTime
);
688 SystemTime
.wYear
= getCX();
689 SystemTime
.wMonth
= getDH();
690 SystemTime
.wDay
= getDL();
692 /* Return success or failure */
693 setAL(SetLocalTime(&SystemTime
) ? 0x00 : 0xFF);
697 /* Get System Time */
700 GetLocalTime(&SystemTime
);
701 setCX(MAKEWORD(SystemTime
.wMinute
, SystemTime
.wHour
));
702 setDX(MAKEWORD(SystemTime
.wMilliseconds
/ 10, SystemTime
.wSecond
));
706 /* Set System Time */
709 GetLocalTime(&SystemTime
);
710 SystemTime
.wHour
= getCH();
711 SystemTime
.wMinute
= getCL();
712 SystemTime
.wSecond
= getDH();
713 SystemTime
.wMilliseconds
= getDL() * 10; // In hundredths of seconds
715 /* Return success or failure */
716 setAL(SetLocalTime(&SystemTime
) ? 0x00 : 0xFF);
720 /* Get Disk Transfer Area */
723 setES(HIWORD(DiskTransferArea
));
724 setBX(LOWORD(DiskTransferArea
));
728 /* Get DOS Version */
731 PDOS_PSP PspBlock
= SEGMENT_TO_PSP(CurrentPsp
);
734 * DOS 2+ - GET DOS VERSION
735 * See Ralf Brown: http://www.ctyme.com/intr/rb-2711.htm
736 * for more information.
739 if (LOBYTE(PspBlock
->DosVersion
) < 5 || getAL() == 0x00)
742 * Return DOS OEM number:
743 * 0x00 for IBM PC-DOS
744 * 0x02 for packaged MS-DOS
750 if (LOBYTE(PspBlock
->DosVersion
) >= 5 && getAL() == 0x01)
753 * Return version flag:
754 * 1 << 3 if DOS is in ROM,
755 * 0 (reserved) if not.
760 /* Return DOS 24-bit user serial number in BL:CX */
765 * Return DOS version: Minor:Major in AH:AL
766 * The Windows NT DOS box returns version 5.00, subject to SETVER.
768 setAX(PspBlock
->DosVersion
);
773 /* Terminate and Stay Resident */
776 DPRINT1("Process going resident: %u paragraphs kept\n", getDX());
777 DosTerminateProcess(CurrentPsp
, getAL(), getDX());
781 /* Extended functionalities */
787 * DOS 5+ - GET TRUE VERSION NUMBER
788 * This function always returns the true version number, unlike
789 * AH=30h, whose return value may be changed with SETVER.
790 * See Ralf Brown: http://www.ctyme.com/intr/rb-2730.htm
791 * for more information.
795 * Return the true DOS version: Minor:Major in BH:BL
796 * The Windows NT DOS box returns BX=3205h (version 5.50).
798 setBX(NTDOS_VERSION
);
808 // /* Invalid subfunction */
815 /* Get Address of InDOS flag */
818 setES(HIWORD(INDOS_POINTER
));
819 setBX(LOWORD(INDOS_POINTER
));
824 /* Get Interrupt Vector */
827 DWORD FarPointer
= ((PDWORD
)BaseAddress
)[getAL()];
829 /* Read the address from the IDT into ES:BX */
830 setES(HIWORD(FarPointer
));
831 setBX(LOWORD(FarPointer
));
835 /* Get Free Disk Space */
838 CHAR RootPath
[3] = "X:\\";
839 DWORD SectorsPerCluster
;
840 DWORD BytesPerSector
;
841 DWORD NumberOfFreeClusters
;
842 DWORD TotalNumberOfClusters
;
844 if (getDL() == 0) RootPath
[0] = 'A' + CurrentDrive
;
845 else RootPath
[0] = 'A' + getDL() - 1;
847 if (GetDiskFreeSpaceA(RootPath
,
850 &NumberOfFreeClusters
,
851 &TotalNumberOfClusters
))
853 setAX(LOWORD(SectorsPerCluster
));
854 setCX(LOWORD(BytesPerSector
));
855 setBX(LOWORD(NumberOfFreeClusters
));
856 setDX(LOWORD(TotalNumberOfClusters
));
867 /* SWITCH character - AVAILDEV */
873 * DOS 2+ - "SWITCHAR" - GET SWITCH CHARACTER
874 * This setting is ignored by MS-DOS 4.0+.
875 * MS-DOS 5+ always return AL=00h/DL=2Fh.
876 * See Ralf Brown: http://www.ctyme.com/intr/rb-2752.htm
877 * for more information.
882 else if (getAL() == 0x01)
885 * DOS 2+ - "SWITCHAR" - SET SWITCH CHARACTER
886 * This setting is ignored by MS-DOS 5+.
887 * See Ralf Brown: http://www.ctyme.com/intr/rb-2753.htm
888 * for more information.
893 else if (getAL() == 0x02)
896 * DOS 2.x and 3.3+ only - "AVAILDEV" - SPECIFY \DEV\ PREFIX USE
897 * See Ralf Brown: http://www.ctyme.com/intr/rb-2754.htm
898 * for more information.
903 else if (getAL() == 0x03)
906 * DOS 2.x and 3.3+ only - "AVAILDEV" - SPECIFY \DEV\ PREFIX USE
907 * See Ralf Brown: http://www.ctyme.com/intr/rb-2754.htm
908 * for more information.
915 /* Invalid subfunction */
922 /* Get/Set Country-dependent Information */
925 CountryCodeBuffer
= (PDOS_COUNTRY_CODE_BUFFER
)SEG_OFF_TO_PTR(getDS(), getDX());
930 Return
= GetLocaleInfo(LOCALE_USER_DEFAULT
, LOCALE_IDATE
,
931 &CountryCodeBuffer
->TimeFormat
,
932 sizeof(CountryCodeBuffer
->TimeFormat
) / sizeof(TCHAR
));
935 Stack
[STACK_FLAGS
] |= EMULATOR_FLAG_CF
;
936 setAX(LOWORD(GetLastError()));
940 Return
= GetLocaleInfo(LOCALE_USER_DEFAULT
, LOCALE_SCURRENCY
,
941 &CountryCodeBuffer
->CurrencySymbol
,
942 sizeof(CountryCodeBuffer
->CurrencySymbol
) / sizeof(TCHAR
));
945 Stack
[STACK_FLAGS
] |= EMULATOR_FLAG_CF
;
946 setAX(LOWORD(GetLastError()));
950 Return
= GetLocaleInfo(LOCALE_USER_DEFAULT
, LOCALE_STHOUSAND
,
951 &CountryCodeBuffer
->ThousandSep
,
952 sizeof(CountryCodeBuffer
->ThousandSep
) / sizeof(TCHAR
));
955 Stack
[STACK_FLAGS
] |= EMULATOR_FLAG_CF
;
956 setAX(LOWORD(GetLastError()));
960 Return
= GetLocaleInfo(LOCALE_USER_DEFAULT
, LOCALE_SDECIMAL
,
961 &CountryCodeBuffer
->DecimalSep
,
962 sizeof(CountryCodeBuffer
->DecimalSep
) / sizeof(TCHAR
));
965 Stack
[STACK_FLAGS
] |= EMULATOR_FLAG_CF
;
966 setAX(LOWORD(GetLastError()));
970 Stack
[STACK_FLAGS
] &= ~EMULATOR_FLAG_CF
;
974 // TODO: NOT IMPLEMENTED
981 /* Create Directory */
984 String
= (PCHAR
)SEG_OFF_TO_PTR(getDS(), getDX());
986 if (CreateDirectoryA(String
, NULL
))
988 Stack
[STACK_FLAGS
] &= ~EMULATOR_FLAG_CF
;
992 Stack
[STACK_FLAGS
] |= EMULATOR_FLAG_CF
;
993 setAX(LOWORD(GetLastError()));
999 /* Remove Directory */
1002 String
= (PCHAR
)SEG_OFF_TO_PTR(getDS(), getDX());
1004 if (RemoveDirectoryA(String
))
1006 Stack
[STACK_FLAGS
] &= ~EMULATOR_FLAG_CF
;
1010 Stack
[STACK_FLAGS
] |= EMULATOR_FLAG_CF
;
1011 setAX(LOWORD(GetLastError()));
1017 /* Set Current Directory */
1020 String
= (PCHAR
)SEG_OFF_TO_PTR(getDS(), getDX());
1022 if (DosChangeDirectory(String
))
1024 Stack
[STACK_FLAGS
] &= ~EMULATOR_FLAG_CF
;
1028 Stack
[STACK_FLAGS
] |= EMULATOR_FLAG_CF
;
1029 setAX(DosLastError
);
1035 /* Create or Truncate File */
1039 WORD ErrorCode
= DosCreateFile(&FileHandle
,
1040 (LPCSTR
)SEG_OFF_TO_PTR(getDS(), getDX()),
1044 if (ErrorCode
== ERROR_SUCCESS
)
1046 Stack
[STACK_FLAGS
] &= ~EMULATOR_FLAG_CF
;
1051 Stack
[STACK_FLAGS
] |= EMULATOR_FLAG_CF
;
1058 /* Open File or Device */
1062 LPCSTR FileName
= (LPCSTR
)SEG_OFF_TO_PTR(getDS(), getDX());
1063 WORD ErrorCode
= DosOpenFile(&FileHandle
, FileName
, getAL());
1065 if (ErrorCode
== ERROR_SUCCESS
)
1067 Stack
[STACK_FLAGS
] &= ~EMULATOR_FLAG_CF
;
1072 Stack
[STACK_FLAGS
] |= EMULATOR_FLAG_CF
;
1079 /* Close File or Device */
1082 if (DosCloseHandle(getBX()))
1084 Stack
[STACK_FLAGS
] &= ~EMULATOR_FLAG_CF
;
1088 Stack
[STACK_FLAGS
] |= EMULATOR_FLAG_CF
;
1089 setAX(ERROR_INVALID_HANDLE
);
1095 /* Read from File or Device */
1101 DPRINT("DosReadFile(0x%04X)\n", getBX());
1104 ErrorCode
= DosReadFile(getBX(),
1105 MAKELONG(getDX(), getDS()),
1110 if (ErrorCode
== ERROR_SUCCESS
)
1112 Stack
[STACK_FLAGS
] &= ~EMULATOR_FLAG_CF
;
1115 else if (ErrorCode
!= ERROR_NOT_READY
)
1117 Stack
[STACK_FLAGS
] |= EMULATOR_FLAG_CF
;
1124 /* Write to File or Device */
1127 WORD BytesWritten
= 0;
1128 WORD ErrorCode
= DosWriteFile(getBX(),
1129 MAKELONG(getDX(), getDS()),
1133 if (ErrorCode
== ERROR_SUCCESS
)
1135 Stack
[STACK_FLAGS
] &= ~EMULATOR_FLAG_CF
;
1136 setAX(BytesWritten
);
1140 Stack
[STACK_FLAGS
] |= EMULATOR_FLAG_CF
;
1150 LPSTR FileName
= (LPSTR
)SEG_OFF_TO_PTR(getDS(), getDX());
1152 if (demFileDelete(FileName
) == ERROR_SUCCESS
)
1154 Stack
[STACK_FLAGS
] &= ~EMULATOR_FLAG_CF
;
1156 * See Ralf Brown: http://www.ctyme.com/intr/rb-2797.htm
1157 * "AX destroyed (DOS 3.3) AL seems to be drive of deleted file."
1159 setAL(FileName
[0] - 'A');
1163 Stack
[STACK_FLAGS
] |= EMULATOR_FLAG_CF
;
1164 setAX(GetLastError());
1174 WORD ErrorCode
= DosSeekFile(getBX(),
1175 MAKELONG(getDX(), getCX()),
1179 if (ErrorCode
== ERROR_SUCCESS
)
1181 Stack
[STACK_FLAGS
] &= ~EMULATOR_FLAG_CF
;
1183 /* Return the new offset in DX:AX */
1184 setDX(HIWORD(NewLocation
));
1185 setAX(LOWORD(NewLocation
));
1189 Stack
[STACK_FLAGS
] |= EMULATOR_FLAG_CF
;
1196 /* Get/Set File Attributes */
1200 LPSTR FileName
= (LPSTR
)SEG_OFF_TO_PTR(getDS(), getDX());
1202 if (getAL() == 0x00)
1204 /* Get the attributes */
1205 Attributes
= GetFileAttributesA(FileName
);
1207 /* Check if it failed */
1208 if (Attributes
== INVALID_FILE_ATTRIBUTES
)
1210 Stack
[STACK_FLAGS
] |= EMULATOR_FLAG_CF
;
1211 setAX(GetLastError());
1215 /* Return the attributes that DOS can understand */
1216 Stack
[STACK_FLAGS
] &= ~EMULATOR_FLAG_CF
;
1217 setCX(Attributes
& 0x00FF);
1220 else if (getAL() == 0x01)
1222 /* Try to set the attributes */
1223 if (SetFileAttributesA(FileName
, getCL()))
1225 Stack
[STACK_FLAGS
] &= ~EMULATOR_FLAG_CF
;
1229 Stack
[STACK_FLAGS
] |= EMULATOR_FLAG_CF
;
1230 setAX(GetLastError());
1235 Stack
[STACK_FLAGS
] |= EMULATOR_FLAG_CF
;
1236 setAX(ERROR_INVALID_FUNCTION
);
1245 WORD Length
= getCX();
1247 if (DosDeviceIoControl(getBX(), getAL(), MAKELONG(getDX(), getDS()), &Length
))
1249 Stack
[STACK_FLAGS
] &= ~EMULATOR_FLAG_CF
;
1254 Stack
[STACK_FLAGS
] |= EMULATOR_FLAG_CF
;
1255 setAX(DosLastError
);
1261 /* Duplicate Handle */
1264 WORD NewHandle
= DosDuplicateHandle(getBX());
1266 if (NewHandle
!= INVALID_DOS_HANDLE
)
1269 Stack
[STACK_FLAGS
] &= ~EMULATOR_FLAG_CF
;
1273 Stack
[STACK_FLAGS
] |= EMULATOR_FLAG_CF
;
1274 setAX(DosLastError
);
1280 /* Force Duplicate Handle */
1283 if (DosForceDuplicateHandle(getBX(), getCX()))
1285 Stack
[STACK_FLAGS
] &= ~EMULATOR_FLAG_CF
;
1289 Stack
[STACK_FLAGS
] |= EMULATOR_FLAG_CF
;
1290 setAX(ERROR_INVALID_HANDLE
);
1296 /* Get Current Directory */
1299 BYTE DriveNumber
= getDL();
1300 String
= (PCHAR
)SEG_OFF_TO_PTR(getDS(), getSI());
1302 /* Get the real drive number */
1303 if (DriveNumber
== 0)
1305 DriveNumber
= CurrentDrive
;
1309 /* Decrement DriveNumber since it was 1-based */
1313 if (DriveNumber
<= LastDrive
- 'A')
1316 * Copy the current directory into the target buffer.
1317 * It doesn't contain the drive letter and the backslash.
1319 strncpy(String
, CurrentDirectories
[DriveNumber
], DOS_DIR_LENGTH
);
1320 Stack
[STACK_FLAGS
] &= ~EMULATOR_FLAG_CF
;
1321 setAX(0x0100); // Undocumented, see Ralf Brown: http://www.ctyme.com/intr/rb-2933.htm
1325 Stack
[STACK_FLAGS
] |= EMULATOR_FLAG_CF
;
1326 setAX(ERROR_INVALID_DRIVE
);
1332 /* Allocate Memory */
1335 WORD MaxAvailable
= 0;
1336 WORD Segment
= DosAllocateMemory(getBX(), &MaxAvailable
);
1340 Stack
[STACK_FLAGS
] &= ~EMULATOR_FLAG_CF
;
1345 Stack
[STACK_FLAGS
] |= EMULATOR_FLAG_CF
;
1346 setAX(DosLastError
);
1347 setBX(MaxAvailable
);
1356 if (DosFreeMemory(getES()))
1358 Stack
[STACK_FLAGS
] &= ~EMULATOR_FLAG_CF
;
1362 Stack
[STACK_FLAGS
] |= EMULATOR_FLAG_CF
;
1363 setAX(ERROR_ARENA_TRASHED
);
1369 /* Resize Memory Block */
1374 if (DosResizeMemory(getES(), getBX(), &Size
))
1376 Stack
[STACK_FLAGS
] &= ~EMULATOR_FLAG_CF
;
1380 Stack
[STACK_FLAGS
] |= EMULATOR_FLAG_CF
;
1381 setAX(DosLastError
);
1391 DOS_EXEC_TYPE LoadType
= (DOS_EXEC_TYPE
)getAL();
1392 LPSTR ProgramName
= SEG_OFF_TO_PTR(getDS(), getDX());
1393 PDOS_EXEC_PARAM_BLOCK ParamBlock
= SEG_OFF_TO_PTR(getES(), getBX());
1394 DWORD ReturnAddress
= MAKELONG(Stack
[STACK_IP
], Stack
[STACK_CS
]);
1398 if (LoadType
== DOS_LOAD_AND_EXECUTE
)
1400 /* Create a new process */
1401 ErrorCode
= DosCreateProcess(ProgramName
, ParamBlock
, ReturnAddress
);
1408 /* Just load an executable */
1409 ErrorCode
= DosLoadExecutable(LoadType
,
1417 if (ErrorCode
== ERROR_SUCCESS
)
1419 Stack
[STACK_FLAGS
] &= ~EMULATOR_FLAG_CF
;
1423 Stack
[STACK_FLAGS
] |= EMULATOR_FLAG_CF
;
1430 /* Terminate With Return Code */
1433 DosTerminateProcess(CurrentPsp
, getAL(), 0);
1437 /* Get Return Code (ERRORLEVEL) */
1441 * According to Ralf Brown: http://www.ctyme.com/intr/rb-2976.htm
1442 * DosErrorLevel is cleared after being read by this function.
1444 Stack
[STACK_FLAGS
] &= ~EMULATOR_FLAG_CF
;
1445 setAX(DosErrorLevel
);
1446 DosErrorLevel
= 0x0000; // Clear it
1450 /* Find First File */
1453 WORD Result
= (WORD
)demFileFindFirst(FAR_POINTER(DiskTransferArea
),
1454 SEG_OFF_TO_PTR(getDS(), getDX()),
1459 if (Result
== ERROR_SUCCESS
)
1460 Stack
[STACK_FLAGS
] &= ~EMULATOR_FLAG_CF
;
1462 Stack
[STACK_FLAGS
] |= EMULATOR_FLAG_CF
;
1467 /* Find Next File */
1470 WORD Result
= (WORD
)demFileFindNext(FAR_POINTER(DiskTransferArea
));
1474 if (Result
== ERROR_SUCCESS
)
1475 Stack
[STACK_FLAGS
] &= ~EMULATOR_FLAG_CF
;
1477 Stack
[STACK_FLAGS
] |= EMULATOR_FLAG_CF
;
1482 /* Internal - Set Current Process ID (Set PSP Address) */
1485 DosSetProcessContext(getBX());
1489 /* Internal - Get Current Process ID (Get PSP Address) */
1491 /* Get Current PSP Address */
1495 * Undocumented AH=51h is identical to the documented AH=62h.
1496 * See Ralf Brown: http://www.ctyme.com/intr/rb-2982.htm
1497 * and http://www.ctyme.com/intr/rb-3140.htm
1498 * for more information.
1504 /* Internal - Get "List of lists" (SYSVARS) */
1508 * On return, ES points at the DOS data segment (see also INT 2F/AX=1203h).
1509 * See Ralf Brown: http://www.ctyme.com/intr/rb-2983.htm
1510 * for more information.
1513 /* Return the DOS "list of lists" in ES:BX */
1514 setES(DOS_DATA_SEGMENT
);
1515 setBX(FIELD_OFFSET(DOS_SYSVARS
, FirstDpb
));
1520 /* Create Child PSP */
1523 DosCreatePsp(getDX(), getSI());
1530 LPSTR ExistingFileName
= (LPSTR
)SEG_OFF_TO_PTR(getDS(), getDX());
1531 LPSTR NewFileName
= (LPSTR
)SEG_OFF_TO_PTR(getES(), getDI());
1534 * See Ralf Brown: http://www.ctyme.com/intr/rb-2990.htm
1535 * for more information.
1538 if (MoveFileA(ExistingFileName
, NewFileName
))
1540 Stack
[STACK_FLAGS
] &= ~EMULATOR_FLAG_CF
;
1544 Stack
[STACK_FLAGS
] |= EMULATOR_FLAG_CF
;
1545 setAX(GetLastError());
1551 /* Get/Set Memory Management Options */
1554 if (getAL() == 0x00)
1556 /* Get allocation strategy */
1557 Stack
[STACK_FLAGS
] &= ~EMULATOR_FLAG_CF
;
1558 setAX(DosAllocStrategy
);
1560 else if (getAL() == 0x01)
1562 /* Set allocation strategy */
1564 if ((getBL() & (DOS_ALLOC_HIGH
| DOS_ALLOC_HIGH_LOW
))
1565 == (DOS_ALLOC_HIGH
| DOS_ALLOC_HIGH_LOW
))
1567 /* Can't set both */
1568 Stack
[STACK_FLAGS
] |= EMULATOR_FLAG_CF
;
1569 setAX(ERROR_INVALID_PARAMETER
);
1573 if ((getBL() & 0x3F) > DOS_ALLOC_LAST_FIT
)
1575 /* Invalid allocation strategy */
1576 Stack
[STACK_FLAGS
] |= EMULATOR_FLAG_CF
;
1577 setAX(ERROR_INVALID_PARAMETER
);
1581 DosAllocStrategy
= getBL();
1582 Stack
[STACK_FLAGS
] &= ~EMULATOR_FLAG_CF
;
1584 else if (getAL() == 0x02)
1586 /* Get UMB link state */
1587 Stack
[STACK_FLAGS
] &= ~EMULATOR_FLAG_CF
;
1588 setAL(DosUmbLinked
? 0x01 : 0x00);
1590 else if (getAL() == 0x03)
1592 /* Set UMB link state */
1593 if (getBX()) DosLinkUmb();
1594 else DosUnlinkUmb();
1595 Stack
[STACK_FLAGS
] &= ~EMULATOR_FLAG_CF
;
1599 /* Invalid or unsupported function */
1600 Stack
[STACK_FLAGS
] |= EMULATOR_FLAG_CF
;
1601 setAX(ERROR_INVALID_FUNCTION
);
1607 /* Get Extended Error Information */
1610 DPRINT1("INT 21h, AH = 59h, BX = %04Xh - Get Extended Error Information is UNIMPLEMENTED\n",
1615 /* Create Temporary File */
1618 LPSTR PathName
= (LPSTR
)SEG_OFF_TO_PTR(getDS(), getDX());
1619 LPSTR FileName
= PathName
; // The buffer for the path and the full file name is the same.
1625 * See Ralf Brown: http://www.ctyme.com/intr/rb-3014.htm
1626 * for more information.
1629 // FIXME: Check for buffer validity?
1630 // It should be a ASCIZ path ending with a '\' + 13 zero bytes
1631 // to receive the generated filename.
1633 /* First create the temporary file */
1634 uRetVal
= GetTempFileNameA(PathName
, NULL
, 0, FileName
);
1637 Stack
[STACK_FLAGS
] |= EMULATOR_FLAG_CF
;
1638 setAX(GetLastError());
1642 /* Now try to open it in read/write access */
1643 ErrorCode
= DosOpenFile(&FileHandle
, FileName
, 2);
1644 if (ErrorCode
== ERROR_SUCCESS
)
1646 Stack
[STACK_FLAGS
] &= ~EMULATOR_FLAG_CF
;
1651 Stack
[STACK_FLAGS
] |= EMULATOR_FLAG_CF
;
1658 /* Create New File */
1662 WORD ErrorCode
= DosCreateFile(&FileHandle
,
1663 (LPCSTR
)SEG_OFF_TO_PTR(getDS(), getDX()),
1667 if (ErrorCode
== ERROR_SUCCESS
)
1669 Stack
[STACK_FLAGS
] &= ~EMULATOR_FLAG_CF
;
1674 Stack
[STACK_FLAGS
] |= EMULATOR_FLAG_CF
;
1681 /* Lock/Unlock Region of File */
1684 if (getAL() == 0x00)
1686 /* Lock region of file */
1687 if (DosLockFile(getBX(), MAKELONG(getCX(), getDX()), MAKELONG(getSI(), getDI())))
1689 Stack
[STACK_FLAGS
] &= ~EMULATOR_FLAG_CF
;
1693 Stack
[STACK_FLAGS
] |= EMULATOR_FLAG_CF
;
1694 setAX(DosLastError
);
1697 else if (getAL() == 0x01)
1699 /* Unlock region of file */
1700 if (DosUnlockFile(getBX(), MAKELONG(getCX(), getDX()), MAKELONG(getSI(), getDI())))
1702 Stack
[STACK_FLAGS
] &= ~EMULATOR_FLAG_CF
;
1706 Stack
[STACK_FLAGS
] |= EMULATOR_FLAG_CF
;
1707 setAX(DosLastError
);
1712 /* Invalid subfunction */
1713 Stack
[STACK_FLAGS
] |= EMULATOR_FLAG_CF
;
1714 setAX(ERROR_INVALID_FUNCTION
);
1720 /* Canonicalize File Name or Path */
1724 * See Ralf Brown: http://www.ctyme.com/intr/rb-3137.htm
1725 * for more information.
1729 * We suppose that the DOS app gave to us a valid
1730 * 128-byte long buffer for the canonicalized name.
1732 DWORD dwRetVal
= GetFullPathNameA(SEG_OFF_TO_PTR(getDS(), getSI()),
1734 SEG_OFF_TO_PTR(getES(), getDI()),
1738 Stack
[STACK_FLAGS
] |= EMULATOR_FLAG_CF
;
1739 setAX(GetLastError());
1743 Stack
[STACK_FLAGS
] &= ~EMULATOR_FLAG_CF
;
1747 // FIXME: Convert the full path name into short version.
1748 // We cannot reliably use GetShortPathName, because it fails
1749 // if the path name given doesn't exist. However this DOS
1750 // function AH=60h should be able to work even for non-existing
1751 // path and file names.
1756 /* Set Handle Count */
1759 if (!DosResizeHandleTable(getBX()))
1761 Stack
[STACK_FLAGS
] |= EMULATOR_FLAG_CF
;
1762 setAX(DosLastError
);
1764 else Stack
[STACK_FLAGS
] &= ~EMULATOR_FLAG_CF
;
1774 * Function 6Ah is identical to function 68h,
1775 * and sets AH to 68h if success.
1776 * See Ralf Brown: http://www.ctyme.com/intr/rb-3176.htm
1777 * for more information.
1781 if (DosFlushFileBuffers(getBX()))
1783 Stack
[STACK_FLAGS
] &= ~EMULATOR_FLAG_CF
;
1787 Stack
[STACK_FLAGS
] |= EMULATOR_FLAG_CF
;
1788 setAX(GetLastError());
1794 /* Extended Open/Create */
1798 WORD CreationStatus
;
1801 /* Check for AL == 00 */
1802 if (getAL() != 0x00)
1804 Stack
[STACK_FLAGS
] |= EMULATOR_FLAG_CF
;
1805 setAX(ERROR_INVALID_FUNCTION
);
1810 * See Ralf Brown: http://www.ctyme.com/intr/rb-3179.htm
1811 * for the full detailed description.
1813 * WARNING: BH contains some extended flags that are NOT SUPPORTED.
1816 ErrorCode
= DosCreateFileEx(&FileHandle
,
1818 (LPCSTR
)SEG_OFF_TO_PTR(getDS(), getSI()),
1823 if (ErrorCode
== ERROR_SUCCESS
)
1825 Stack
[STACK_FLAGS
] &= ~EMULATOR_FLAG_CF
;
1826 setCX(CreationStatus
);
1831 Stack
[STACK_FLAGS
] |= EMULATOR_FLAG_CF
;
1841 DPRINT1("DOS Function INT 0x21, AH = %xh, AL = %xh NOT IMPLEMENTED!\n",
1844 setAL(0); // Some functions expect AL to be 0 when it's not supported.
1845 Stack
[STACK_FLAGS
] |= EMULATOR_FLAG_CF
;
1852 VOID WINAPI
DosBreakInterrupt(LPWORD Stack
)
1854 /* Set CF to terminate the running process */
1855 Stack
[STACK_FLAGS
] |= EMULATOR_FLAG_CF
;
1858 VOID WINAPI
DosFastConOut(LPWORD Stack
)
1861 * This is the DOS 2+ Fast Console Output Interrupt.
1862 * The default handler under DOS 2.x and 3.x simply calls INT 10h/AH=0Eh.
1864 * See Ralf Brown: http://www.ctyme.com/intr/rb-4124.htm
1865 * for more information.
1868 /* Save AX and BX */
1869 USHORT AX
= getAX();
1870 USHORT BX
= getBX();
1873 * Set the parameters:
1874 * AL contains the character to print (already set),
1875 * BL contains the character attribute,
1876 * BH contains the video page to use.
1878 setBL(DOS_CHAR_ATTRIBUTE
);
1879 setBH(Bda
->VideoPage
);
1881 /* Call the BIOS INT 10h, AH=0Eh "Teletype Output" */
1883 Int32Call(&DosContext
, BIOS_VIDEO_INTERRUPT
);
1885 /* Restore AX and BX */
1890 VOID WINAPI
DosInt2Fh(LPWORD Stack
)
1894 /* Extended Memory Specification */
1898 if (!XmsGetDriverEntry(&DriverEntry
)) break;
1900 if (getAL() == 0x00)
1902 /* The driver is loaded */
1905 else if (getAL() == 0x10)
1907 setES(HIWORD(DriverEntry
));
1908 setBX(LOWORD(DriverEntry
));
1912 DPRINT1("Unknown DOS XMS Function: INT 0x2F, AH = 43h, AL = %xh\n", getAL());
1920 DPRINT1("DOS Internal System Function INT 0x2F, AH = %xh, AL = %xh NOT IMPLEMENTED!\n",
1922 Stack
[STACK_FLAGS
] |= EMULATOR_FLAG_CF
;
1927 BOOLEAN
DosKRNLInitialize(VOID
)
1932 CHAR CurrentDirectory
[MAX_PATH
];
1933 CHAR DosDirectory
[DOS_DIR_LENGTH
];
1937 const BYTE NullDriverRoutine
[] = {
1938 /* Strategy routine entry */
1939 0x26, // mov [Request.Status], DOS_DEVSTAT_DONE
1942 FIELD_OFFSET(DOS_REQUEST_HEADER
, Status
),
1943 LOBYTE(DOS_DEVSTAT_DONE
),
1944 HIBYTE(DOS_DEVSTAT_DONE
),
1946 /* Interrupt routine entry */
1953 /* Setup the InDOS flag */
1954 InDos
= (PBYTE
)FAR_POINTER(INDOS_POINTER
);
1957 /* Clear the current directory buffer */
1958 RtlZeroMemory(CurrentDirectories
, sizeof(CurrentDirectories
));
1960 /* Get the current directory */
1961 if (!GetCurrentDirectoryA(MAX_PATH
, CurrentDirectory
))
1963 // TODO: Use some kind of default path?
1967 /* Convert that to a DOS path */
1968 if (!GetShortPathNameA(CurrentDirectory
, DosDirectory
, DOS_DIR_LENGTH
))
1970 // TODO: Use some kind of default path?
1975 CurrentDrive
= DosDirectory
[0] - 'A';
1977 /* Get the directory part of the path */
1978 Path
= strchr(DosDirectory
, '\\');
1981 /* Skip the backslash */
1985 /* Set the directory */
1988 strncpy(CurrentDirectories
[CurrentDrive
], Path
, DOS_DIR_LENGTH
);
1991 /* Read CONFIG.SYS */
1992 Stream
= _wfopen(DOS_CONFIG_PATH
, L
"r");
1995 while (fgetws(Buffer
, 256, Stream
))
1997 // TODO: Parse the line
2002 /* Initialize the list of lists */
2003 SysVars
= (PDOS_SYSVARS
)SEG_OFF_TO_PTR(DOS_DATA_SEGMENT
, 0);
2004 RtlZeroMemory(SysVars
, sizeof(DOS_SYSVARS
));
2005 SysVars
->FirstMcb
= FIRST_MCB_SEGMENT
;
2006 SysVars
->FirstSft
= MAKELONG(MASTER_SFT_OFFSET
, DOS_DATA_SEGMENT
);
2008 /* Initialize the NUL device driver */
2009 SysVars
->NullDevice
.Link
= 0xFFFFFFFF;
2010 SysVars
->NullDevice
.DeviceAttributes
= DOS_DEVATTR_NUL
| DOS_DEVATTR_CHARACTER
;
2011 SysVars
->NullDevice
.StrategyRoutine
= FIELD_OFFSET(DOS_SYSVARS
, NullDriverRoutine
);
2012 SysVars
->NullDevice
.InterruptRoutine
= SysVars
->NullDevice
.StrategyRoutine
+ 6;
2013 RtlFillMemory(SysVars
->NullDevice
.DeviceName
,
2014 sizeof(SysVars
->NullDevice
.DeviceName
),
2016 RtlCopyMemory(SysVars
->NullDevice
.DeviceName
, "NUL", strlen("NUL"));
2017 RtlCopyMemory(SysVars
->NullDriverRoutine
,
2019 sizeof(NullDriverRoutine
));
2021 /* Initialize the SFT */
2022 Sft
= (PDOS_SFT
)FAR_POINTER(SysVars
->FirstSft
);
2023 Sft
->Link
= 0xFFFFFFFF;
2024 Sft
->NumDescriptors
= DOS_SFT_SIZE
;
2026 for (i
= 0; i
< Sft
->NumDescriptors
; i
++)
2028 /* Clear the file descriptor entry */
2029 RtlZeroMemory(&Sft
->FileDescriptors
[i
], sizeof(DOS_FILE_DESCRIPTOR
));
2034 /* Initialize the callback context */
2035 InitializeContext(&DosContext
, 0x0070, 0x0000);
2037 /* Register the DOS 32-bit Interrupts */
2038 RegisterDosInt32(0x20, DosInt20h
);
2039 RegisterDosInt32(0x21, DosInt21h
);
2040 // RegisterDosInt32(0x22, DosInt22h ); // Termination
2041 RegisterDosInt32(0x23, DosBreakInterrupt
); // Ctrl-C / Ctrl-Break
2042 // RegisterDosInt32(0x24, DosInt24h ); // Critical Error
2043 RegisterDosInt32(0x29, DosFastConOut
); // DOS 2+ Fast Console Output
2044 RegisterDosInt32(0x2F, DosInt2Fh
);
2046 /* Load the EMS driver */
2047 if (!EmsDrvInitialize(EMS_TOTAL_PAGES
))
2049 DPRINT1("Could not initialize EMS. EMS will not be available.\n"
2050 "Try reducing the number of EMS pages.\n");
2053 /* Load the XMS driver (HIMEM) */
2056 /* Load the CON driver */