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 *******************************************************************/
29 #include "bios/bios.h"
32 #include "hardware/ps2.h"
36 /* PRIVATE VARIABLES **********************************************************/
38 CALLBACK16 DosContext
;
40 /* PUBLIC VARIABLES ***********************************************************/
42 /* Global DOS data area contained in guest memory */
44 /* Easy accessors to useful DOS data area parts */
48 /* Echo state for INT 21h, AH = 01h and AH = 3Fh */
49 BOOLEAN DoEcho
= FALSE
;
51 /* PRIVATE FUNCTIONS **********************************************************/
53 static BOOLEAN
DosChangeDrive(BYTE Drive
)
55 CHAR DirectoryPath
[DOS_CMDLINE_LENGTH
+ 1];
57 /* Make sure the drive exists */
58 if (Drive
>= SysVars
->NumLocalDrives
) return FALSE
;
60 RtlZeroMemory(DirectoryPath
, sizeof(DirectoryPath
));
62 /* Find the path to the new current directory */
63 snprintf(DirectoryPath
,
67 DosData
->CurrentDirectories
[Drive
]);
69 /* Change the current directory of the process */
70 if (!SetCurrentDirectoryA(DirectoryPath
)) return FALSE
;
72 /* Set the current drive */
73 Sda
->CurrentDrive
= Drive
;
79 static BOOLEAN
DosChangeDirectory(LPSTR Directory
)
84 CHAR CurrentDirectory
[MAX_PATH
];
85 CHAR DosDirectory
[DOS_DIR_LENGTH
];
87 /* Make sure the directory path is not too long */
88 if (strlen(Directory
) >= DOS_DIR_LENGTH
)
90 Sda
->LastErrorCode
= ERROR_PATH_NOT_FOUND
;
94 /* Check whether the directory string is of format "?:..." */
95 if (strlen(Directory
) >= 2 && Directory
[1] == ':')
97 /* Get the drive number */
98 DriveNumber
= RtlUpperChar(Directory
[0]) - 'A';
100 /* Make sure the drive exists */
101 if (DriveNumber
>= SysVars
->NumLocalDrives
)
103 Sda
->LastErrorCode
= ERROR_PATH_NOT_FOUND
;
109 /* Keep the current drive number */
110 DriveNumber
= Sda
->CurrentDrive
;
113 /* Get the file attributes */
114 Attributes
= GetFileAttributesA(Directory
);
116 /* Make sure the path exists and is a directory */
117 if ((Attributes
== INVALID_FILE_ATTRIBUTES
)
118 || !(Attributes
& FILE_ATTRIBUTE_DIRECTORY
))
120 Sda
->LastErrorCode
= ERROR_PATH_NOT_FOUND
;
124 /* Check if this is the current drive */
125 if (DriveNumber
== Sda
->CurrentDrive
)
127 /* Change the directory */
128 if (!SetCurrentDirectoryA(Directory
))
130 Sda
->LastErrorCode
= LOWORD(GetLastError());
135 /* Get the (possibly new) current directory (needed if we specified a relative directory) */
136 if (!GetCurrentDirectoryA(sizeof(CurrentDirectory
), CurrentDirectory
))
138 // TODO: Use some kind of default path?
142 /* Convert it to a DOS path */
143 if (!GetShortPathNameA(CurrentDirectory
, DosDirectory
, sizeof(DosDirectory
)))
145 // TODO: Use some kind of default path?
149 /* Get the directory part of the path */
150 Path
= strchr(DosDirectory
, '\\');
153 /* Skip the backslash */
157 /* Set the directory for the drive */
160 strncpy(DosData
->CurrentDirectories
[DriveNumber
], Path
, DOS_DIR_LENGTH
);
164 DosData
->CurrentDirectories
[DriveNumber
][0] = '\0';
171 static BOOLEAN
DosControlBreak(VOID
)
175 /* Call interrupt 0x23 */
176 Int32Call(&DosContext
, 0x23);
180 DosTerminateProcess(Sda
->CurrentPsp
, 0, 0);
187 /* PUBLIC FUNCTIONS ***********************************************************/
189 VOID WINAPI
DosInt20h(LPWORD Stack
)
191 /* This is the exit interrupt */
192 DosTerminateProcess(Stack
[STACK_CS
], 0, 0);
195 VOID WINAPI
DosInt21h(LPWORD Stack
)
198 SYSTEMTIME SystemTime
;
200 PDOS_INPUT_BUFFER InputBuffer
;
204 /* Save the value of SS:SP on entry in the PSP */
205 SEGMENT_TO_PSP(Sda
->CurrentPsp
)->LastStack
=
206 MAKELONG(getSP() + (STACK_FLAGS
+ 1) * 2, getSS());
208 /* Check the value in the AH register */
211 /* Terminate Program */
214 DosTerminateProcess(Stack
[STACK_CS
], 0, 0);
218 /* Read Character from STDIN with Echo */
221 DPRINT("INT 21h, AH = 01h\n");
223 // FIXME: Under DOS 2+, input / output handle may be redirected!!!!
225 Character
= DosReadCharacter(DOS_INPUT_HANDLE
);
228 // FIXME: Check whether Ctrl-C / Ctrl-Break is pressed, and call INT 23h if so.
229 // Check also Ctrl-P and set echo-to-printer flag.
230 // Ctrl-Z is not interpreted.
236 /* Write Character to STDOUT */
239 // FIXME: Under DOS 2+, output handle may be redirected!!!!
241 DosPrintCharacter(DOS_OUTPUT_HANDLE
, Character
);
244 * We return the output character (DOS 2.1+).
245 * Also, if we're going to output a TAB, then
246 * don't return a TAB but a SPACE instead.
247 * See Ralf Brown: http://www.ctyme.com/intr/rb-2554.htm
248 * for more information.
250 setAL(Character
== '\t' ? ' ' : Character
);
254 /* Read Character from STDAUX */
257 // FIXME: Really read it from STDAUX!
258 DPRINT1("INT 16h, 03h: Read character from STDAUX is HALFPLEMENTED\n");
259 // setAL(DosReadCharacter());
263 /* Write Character to STDAUX */
266 // FIXME: Really write it to STDAUX!
267 DPRINT1("INT 16h, 04h: Write character to STDAUX is HALFPLEMENTED\n");
268 // DosPrintCharacter(getDL());
272 /* Write Character to Printer */
275 // FIXME: Really write it to printer!
276 DPRINT1("INT 16h, 05h: Write character to printer is HALFPLEMENTED -\n\n");
277 DPRINT1("0x%p\n", getDL());
278 DPRINT1("\n\n-----------\n\n");
282 /* Direct Console I/O */
287 // FIXME: Under DOS 2+, output handle may be redirected!!!!
289 if (Character
!= 0xFF)
292 DosPrintCharacter(DOS_OUTPUT_HANDLE
, Character
);
295 * We return the output character (DOS 2.1+).
296 * See Ralf Brown: http://www.ctyme.com/intr/rb-2558.htm
297 * for more information.
306 Stack
[STACK_FLAGS
] &= ~EMULATOR_FLAG_ZF
;
307 setAL(DosReadCharacter(DOS_INPUT_HANDLE
));
311 /* No character available */
312 Stack
[STACK_FLAGS
] |= EMULATOR_FLAG_ZF
;
320 /* Character Input without Echo */
324 DPRINT("Char input without echo\n");
326 Character
= DosReadCharacter(DOS_INPUT_HANDLE
);
328 // FIXME: For 0x07, do not check Ctrl-C/Break.
329 // For 0x08, do check those control sequences and if needed,
336 /* Write String to STDOUT */
339 String
= (PCHAR
)SEG_OFF_TO_PTR(getDS(), getDX());
341 while (*String
!= '$')
343 DosPrintCharacter(DOS_OUTPUT_HANDLE
, *String
);
348 * We return the terminating character (DOS 2.1+).
349 * See Ralf Brown: http://www.ctyme.com/intr/rb-2562.htm
350 * for more information.
352 setAL('$'); // *String
356 /* Read Buffered Input */
360 InputBuffer
= (PDOS_INPUT_BUFFER
)SEG_OFF_TO_PTR(getDS(), getDX());
362 DPRINT("Read Buffered Input\n");
364 while (Count
< InputBuffer
->MaxLength
)
366 /* Try to read a character (wait) */
367 Character
= DosReadCharacter(DOS_INPUT_HANDLE
);
371 /* Extended character */
374 /* Read the scancode */
375 DosReadCharacter(DOS_INPUT_HANDLE
);
382 DosPrintCharacter(DOS_OUTPUT_HANDLE
, '^');
383 DosPrintCharacter(DOS_OUTPUT_HANDLE
, 'C');
385 if (DosControlBreak())
387 /* Set the character to a newline to exit the loop */
401 /* Erase the character */
402 DosPrintCharacter(DOS_OUTPUT_HANDLE
, '\b');
403 DosPrintCharacter(DOS_OUTPUT_HANDLE
, ' ');
404 DosPrintCharacter(DOS_OUTPUT_HANDLE
, '\b');
412 /* Append it to the buffer */
413 InputBuffer
->Buffer
[Count
] = Character
;
415 /* Check if this is a special character */
416 if (Character
< 0x20 && Character
!= 0x0A && Character
!= 0x0D)
418 DosPrintCharacter(DOS_OUTPUT_HANDLE
, '^');
419 Character
+= 'A' - 1;
422 /* Echo the character */
423 DosPrintCharacter(DOS_OUTPUT_HANDLE
, Character
);
427 if (Character
== '\r') break;
428 if (Character
== '\b') continue;
429 Count
++; /* Carriage returns are NOT counted */
432 /* Update the length */
433 InputBuffer
->Length
= Count
;
438 /* Get STDIN Status */
441 setAL(DosCheckInput() ? 0xFF : 0x00);
445 /* Flush Buffer and Read STDIN */
448 BYTE InputFunction
= getAL();
450 /* Flush STDIN buffer */
451 DosFlushFileBuffers(DOS_INPUT_HANDLE
);
454 * If the input function number contained in AL is valid, i.e.
455 * AL == 0x01 or 0x06 or 0x07 or 0x08 or 0x0A, call ourselves
456 * recursively with AL == AH.
458 if (InputFunction
== 0x01 || InputFunction
== 0x06 ||
459 InputFunction
== 0x07 || InputFunction
== 0x08 ||
460 InputFunction
== 0x0A)
462 /* Call ourselves recursively */
463 setAH(InputFunction
);
472 PDOS_PSP PspBlock
= SEGMENT_TO_PSP(Sda
->CurrentPsp
);
474 // TODO: Flush what's needed.
475 DPRINT1("INT 21h, 0Dh is UNIMPLEMENTED\n");
477 /* Clear CF in DOS 6 only */
478 if (PspBlock
->DosVersion
== 0x0006)
479 Stack
[STACK_FLAGS
] &= ~EMULATOR_FLAG_CF
;
484 /* Set Default Drive */
487 DosChangeDrive(getDL());
488 setAL(SysVars
->NumLocalDrives
);
492 /* NULL Function for CP/M Compatibility */
496 * This function corresponds to the CP/M BDOS function
497 * "get bit map of logged drives", which is meaningless
500 * For: PTS-DOS 6.51 & S/DOS 1.0 - EXTENDED RENAME FILE USING FCB
501 * See Ralf Brown: http://www.ctyme.com/intr/rb-2584.htm
502 * for more information.
508 /* Get Default Drive */
511 setAL(Sda
->CurrentDrive
);
515 /* Set Disk Transfer Area */
518 Sda
->DiskTransferArea
= MAKELONG(getDX(), getDS());
522 /* NULL Function for CP/M Compatibility */
527 * Function 0x1D corresponds to the CP/M BDOS function
528 * "get bit map of read-only drives", which is meaningless
530 * See Ralf Brown: http://www.ctyme.com/intr/rb-2592.htm
531 * for more information.
533 * Function 0x1E corresponds to the CP/M BDOS function
534 * "set file attributes", which was meaningless under MS-DOS 1.x.
535 * See Ralf Brown: http://www.ctyme.com/intr/rb-2593.htm
536 * for more information.
542 /* NULL Function for CP/M Compatibility */
546 * This function corresponds to the CP/M BDOS function
547 * "get/set default user (sublibrary) number", which is meaningless
550 * For: S/DOS 1.0+ & PTS-DOS 6.51+ - GET OEM REVISION
551 * See Ralf Brown: http://www.ctyme.com/intr/rb-2596.htm
552 * for more information.
558 /* Set Interrupt Vector */
561 ULONG FarPointer
= MAKELONG(getDX(), getDS());
562 DPRINT1("Setting interrupt 0x%02X to %04X:%04X ...\n",
563 getAL(), HIWORD(FarPointer
), LOWORD(FarPointer
));
565 /* Write the new far pointer to the IDT */
566 ((PULONG
)BaseAddress
)[getAL()] = FarPointer
;
573 DosClonePsp(getDX(), getCS());
577 /* Parse Filename into FCB */
580 PCHAR FileName
= (PCHAR
)SEG_OFF_TO_PTR(getDS(), getSI());
581 PDOS_FCB Fcb
= (PDOS_FCB
)SEG_OFF_TO_PTR(getES(), getDI());
582 BYTE Options
= getAL();
586 if (FileName
[1] == ':')
588 /* Set the drive number */
589 Fcb
->DriveNumber
= RtlUpperChar(FileName
[0]) - 'A' + 1;
591 /* Skip to the file name part */
596 /* No drive number specified */
597 if (Options
& (1 << 1)) Fcb
->DriveNumber
= Sda
->CurrentDrive
+ 1;
598 else Fcb
->DriveNumber
= 0;
601 /* Parse the file name */
603 while ((*FileName
> 0x20) && (i
< 8))
605 if (*FileName
== '.') break;
606 else if (*FileName
== '*')
612 Fcb
->FileName
[i
++] = RtlUpperChar(*FileName
++);
615 /* Fill the whole field with blanks only if bit 2 is not set */
616 if ((FillChar
!= ' ') || (i
!= 0) || !(Options
& (1 << 2)))
618 for (; i
< 8; i
++) Fcb
->FileName
[i
] = FillChar
;
621 /* Skip to the extension part */
622 while (*FileName
> 0x20 && *FileName
!= '.') FileName
++;
623 if (*FileName
== '.') FileName
++;
625 /* Now parse the extension */
629 while ((*FileName
> 0x20) && (i
< 3))
631 if (*FileName
== '*')
637 Fcb
->FileExt
[i
++] = RtlUpperChar(*FileName
++);
640 /* Fill the whole field with blanks only if bit 3 is not set */
641 if ((FillChar
!= ' ') || (i
!= 0) || !(Options
& (1 << 3)))
643 for (; i
< 3; i
++) Fcb
->FileExt
[i
] = FillChar
;
649 /* Get System Date */
652 GetLocalTime(&SystemTime
);
653 setCX(SystemTime
.wYear
);
654 setDX(MAKEWORD(SystemTime
.wDay
, SystemTime
.wMonth
));
655 setAL(SystemTime
.wDayOfWeek
);
659 /* Set System Date */
662 GetLocalTime(&SystemTime
);
663 SystemTime
.wYear
= getCX();
664 SystemTime
.wMonth
= getDH();
665 SystemTime
.wDay
= getDL();
667 /* Return success or failure */
668 setAL(SetLocalTime(&SystemTime
) ? 0x00 : 0xFF);
672 /* Get System Time */
675 GetLocalTime(&SystemTime
);
676 setCX(MAKEWORD(SystemTime
.wMinute
, SystemTime
.wHour
));
677 setDX(MAKEWORD(SystemTime
.wMilliseconds
/ 10, SystemTime
.wSecond
));
681 /* Set System Time */
684 GetLocalTime(&SystemTime
);
685 SystemTime
.wHour
= getCH();
686 SystemTime
.wMinute
= getCL();
687 SystemTime
.wSecond
= getDH();
688 SystemTime
.wMilliseconds
= getDL() * 10; // In hundredths of seconds
690 /* Return success or failure */
691 setAL(SetLocalTime(&SystemTime
) ? 0x00 : 0xFF);
695 /* Get Disk Transfer Area */
698 setES(HIWORD(Sda
->DiskTransferArea
));
699 setBX(LOWORD(Sda
->DiskTransferArea
));
703 /* Get DOS Version */
706 PDOS_PSP PspBlock
= SEGMENT_TO_PSP(Sda
->CurrentPsp
);
709 * DOS 2+ - GET DOS VERSION
710 * See Ralf Brown: http://www.ctyme.com/intr/rb-2711.htm
711 * for more information.
714 if (LOBYTE(PspBlock
->DosVersion
) < 5 || getAL() == 0x00)
717 * Return DOS OEM number:
718 * 0x00 for IBM PC-DOS
719 * 0x02 for packaged MS-DOS
725 if (LOBYTE(PspBlock
->DosVersion
) >= 5 && getAL() == 0x01)
728 * Return version flag:
729 * 1 << 3 if DOS is in ROM,
730 * 0 (reserved) if not.
735 /* Return DOS 24-bit user serial number in BL:CX */
740 * Return DOS version: Minor:Major in AH:AL
741 * The Windows NT DOS box returns version 5.00, subject to SETVER.
743 setAX(PspBlock
->DosVersion
);
748 /* Terminate and Stay Resident */
751 DPRINT1("Process going resident: %u paragraphs kept\n", getDX());
752 DosTerminateProcess(Sda
->CurrentPsp
, getAL(), getDX());
756 /* Extended functionalities */
762 * DOS 4+ - GET BOOT DRIVE
766 setDL(SysVars
->BootDrive
);
771 * DOS 5+ - GET TRUE VERSION NUMBER
772 * This function always returns the true version number, unlike
773 * AH=30h, whose return value may be changed with SETVER.
774 * See Ralf Brown: http://www.ctyme.com/intr/rb-2730.htm
775 * for more information.
780 * Return the true DOS version: Minor:Major in BH:BL
781 * The Windows NT DOS box returns BX=3205h (version 5.50).
783 setBX(NTDOS_VERSION
);
796 DPRINT1("INT 21h, AH = 33h, subfunction AL = %Xh NOT IMPLEMENTED\n",
804 /* Get Address of InDOS flag */
807 setES(DOS_DATA_SEGMENT
);
808 setBX(DOS_DATA_OFFSET(Sda
.InDos
));
812 /* Get Interrupt Vector */
815 ULONG FarPointer
= ((PULONG
)BaseAddress
)[getAL()];
817 /* Read the address from the IDT into ES:BX */
818 setES(HIWORD(FarPointer
));
819 setBX(LOWORD(FarPointer
));
823 /* Get Free Disk Space */
826 CHAR RootPath
[] = "?:\\";
827 DWORD SectorsPerCluster
;
828 DWORD BytesPerSector
;
829 DWORD NumberOfFreeClusters
;
830 DWORD TotalNumberOfClusters
;
832 if (getDL() == 0x00) RootPath
[0] = 'A' + Sda
->CurrentDrive
;
833 else RootPath
[0] = 'A' + getDL() - 1;
835 if (GetDiskFreeSpaceA(RootPath
,
838 &NumberOfFreeClusters
,
839 &TotalNumberOfClusters
))
841 setAX(LOWORD(SectorsPerCluster
));
842 setCX(LOWORD(BytesPerSector
));
843 setBX(min(NumberOfFreeClusters
, 0xFFFF));
844 setDX(min(TotalNumberOfClusters
, 0xFFFF));
855 /* SWITCH character - AVAILDEV */
861 * DOS 2+ - "SWITCHAR" - GET SWITCH CHARACTER
862 * This setting is ignored by MS-DOS 4.0+.
863 * MS-DOS 5+ always return AL=00h/DL=2Fh.
864 * See Ralf Brown: http://www.ctyme.com/intr/rb-2752.htm
865 * for more information.
873 * DOS 2+ - "SWITCHAR" - SET SWITCH CHARACTER
874 * This setting is ignored by MS-DOS 5+.
875 * See Ralf Brown: http://www.ctyme.com/intr/rb-2753.htm
876 * for more information.
884 * DOS 2.x and 3.3+ only - "AVAILDEV" - SPECIFY \DEV\ PREFIX USE
885 * See Ralf Brown: http://www.ctyme.com/intr/rb-2754.htm
886 * for more information.
894 * DOS 2.x and 3.3+ only - "AVAILDEV" - SPECIFY \DEV\ PREFIX USE
895 * See Ralf Brown: http://www.ctyme.com/intr/rb-2754.htm
896 * for more information.
903 /* Invalid subfunction */
912 /* Get/Set Country-dependent Information */
915 WORD CountryId
= getAL() < 0xFF ? getAL() : getBX();
918 ErrorCode
= DosGetCountryInfo(&CountryId
,
919 (PDOS_COUNTRY_INFO
)SEG_OFF_TO_PTR(getDS(), getDX()));
921 if (ErrorCode
== ERROR_SUCCESS
)
923 Stack
[STACK_FLAGS
] &= ~EMULATOR_FLAG_CF
;
928 Stack
[STACK_FLAGS
] |= EMULATOR_FLAG_CF
;
935 /* Create Directory */
938 String
= (PCHAR
)SEG_OFF_TO_PTR(getDS(), getDX());
940 if (CreateDirectoryA(String
, NULL
))
942 Stack
[STACK_FLAGS
] &= ~EMULATOR_FLAG_CF
;
946 Stack
[STACK_FLAGS
] |= EMULATOR_FLAG_CF
;
947 setAX(LOWORD(GetLastError()));
953 /* Remove Directory */
956 String
= (PCHAR
)SEG_OFF_TO_PTR(getDS(), getDX());
958 if (RemoveDirectoryA(String
))
960 Stack
[STACK_FLAGS
] &= ~EMULATOR_FLAG_CF
;
964 Stack
[STACK_FLAGS
] |= EMULATOR_FLAG_CF
;
965 setAX(LOWORD(GetLastError()));
971 /* Set Current Directory */
974 String
= (PCHAR
)SEG_OFF_TO_PTR(getDS(), getDX());
976 if (DosChangeDirectory(String
))
978 Stack
[STACK_FLAGS
] &= ~EMULATOR_FLAG_CF
;
982 Stack
[STACK_FLAGS
] |= EMULATOR_FLAG_CF
;
983 setAX(Sda
->LastErrorCode
);
989 /* Create or Truncate File */
993 WORD ErrorCode
= DosCreateFile(&FileHandle
,
994 (LPCSTR
)SEG_OFF_TO_PTR(getDS(), getDX()),
998 if (ErrorCode
== ERROR_SUCCESS
)
1000 Stack
[STACK_FLAGS
] &= ~EMULATOR_FLAG_CF
;
1005 Stack
[STACK_FLAGS
] |= EMULATOR_FLAG_CF
;
1012 /* Open File or Device */
1016 LPCSTR FileName
= (LPCSTR
)SEG_OFF_TO_PTR(getDS(), getDX());
1017 WORD ErrorCode
= DosOpenFile(&FileHandle
, FileName
, getAL());
1019 if (ErrorCode
== ERROR_SUCCESS
)
1021 Stack
[STACK_FLAGS
] &= ~EMULATOR_FLAG_CF
;
1026 Stack
[STACK_FLAGS
] |= EMULATOR_FLAG_CF
;
1033 /* Close File or Device */
1036 if (DosCloseHandle(getBX()))
1038 Stack
[STACK_FLAGS
] &= ~EMULATOR_FLAG_CF
;
1042 Stack
[STACK_FLAGS
] |= EMULATOR_FLAG_CF
;
1043 setAX(ERROR_INVALID_HANDLE
);
1049 /* Read from File or Device */
1055 DPRINT("DosReadFile(0x%04X)\n", getBX());
1058 ErrorCode
= DosReadFile(getBX(),
1059 MAKELONG(getDX(), getDS()),
1064 if (ErrorCode
== ERROR_SUCCESS
)
1066 Stack
[STACK_FLAGS
] &= ~EMULATOR_FLAG_CF
;
1069 else if (ErrorCode
!= ERROR_NOT_READY
)
1071 Stack
[STACK_FLAGS
] |= EMULATOR_FLAG_CF
;
1078 /* Write to File or Device */
1081 WORD BytesWritten
= 0;
1082 WORD ErrorCode
= DosWriteFile(getBX(),
1083 MAKELONG(getDX(), getDS()),
1087 if (ErrorCode
== ERROR_SUCCESS
)
1089 Stack
[STACK_FLAGS
] &= ~EMULATOR_FLAG_CF
;
1090 setAX(BytesWritten
);
1094 Stack
[STACK_FLAGS
] |= EMULATOR_FLAG_CF
;
1104 LPSTR FileName
= (LPSTR
)SEG_OFF_TO_PTR(getDS(), getDX());
1106 if (demFileDelete(FileName
) == ERROR_SUCCESS
)
1108 Stack
[STACK_FLAGS
] &= ~EMULATOR_FLAG_CF
;
1110 * See Ralf Brown: http://www.ctyme.com/intr/rb-2797.htm
1111 * "AX destroyed (DOS 3.3) AL seems to be drive of deleted file."
1113 setAL(FileName
[0] - 'A');
1117 Stack
[STACK_FLAGS
] |= EMULATOR_FLAG_CF
;
1118 setAX(GetLastError());
1128 WORD ErrorCode
= DosSeekFile(getBX(),
1129 MAKELONG(getDX(), getCX()),
1133 if (ErrorCode
== ERROR_SUCCESS
)
1135 Stack
[STACK_FLAGS
] &= ~EMULATOR_FLAG_CF
;
1137 /* Return the new offset in DX:AX */
1138 setDX(HIWORD(NewLocation
));
1139 setAX(LOWORD(NewLocation
));
1143 Stack
[STACK_FLAGS
] |= EMULATOR_FLAG_CF
;
1150 /* Get/Set File Attributes */
1154 LPSTR FileName
= (LPSTR
)SEG_OFF_TO_PTR(getDS(), getDX());
1156 if (getAL() == 0x00)
1158 /* Get the attributes */
1159 Attributes
= GetFileAttributesA(FileName
);
1161 /* Check if it failed */
1162 if (Attributes
== INVALID_FILE_ATTRIBUTES
)
1164 Stack
[STACK_FLAGS
] |= EMULATOR_FLAG_CF
;
1165 setAX(GetLastError());
1169 /* Return the attributes that DOS can understand */
1170 Stack
[STACK_FLAGS
] &= ~EMULATOR_FLAG_CF
;
1171 setCX(Attributes
& 0x00FF);
1174 else if (getAL() == 0x01)
1176 /* Try to set the attributes */
1177 if (SetFileAttributesA(FileName
, getCL()))
1179 Stack
[STACK_FLAGS
] &= ~EMULATOR_FLAG_CF
;
1183 Stack
[STACK_FLAGS
] |= EMULATOR_FLAG_CF
;
1184 setAX(GetLastError());
1189 Stack
[STACK_FLAGS
] |= EMULATOR_FLAG_CF
;
1190 setAX(ERROR_INVALID_FUNCTION
);
1199 WORD Length
= getCX();
1201 if (DosDeviceIoControl(getBX(), getAL(), MAKELONG(getDX(), getDS()), &Length
))
1203 Stack
[STACK_FLAGS
] &= ~EMULATOR_FLAG_CF
;
1208 Stack
[STACK_FLAGS
] |= EMULATOR_FLAG_CF
;
1209 setAX(Sda
->LastErrorCode
);
1215 /* Duplicate Handle */
1218 WORD NewHandle
= DosDuplicateHandle(getBX());
1220 if (NewHandle
!= INVALID_DOS_HANDLE
)
1223 Stack
[STACK_FLAGS
] &= ~EMULATOR_FLAG_CF
;
1227 Stack
[STACK_FLAGS
] |= EMULATOR_FLAG_CF
;
1228 setAX(Sda
->LastErrorCode
);
1234 /* Force Duplicate Handle */
1237 if (DosForceDuplicateHandle(getBX(), getCX()))
1239 Stack
[STACK_FLAGS
] &= ~EMULATOR_FLAG_CF
;
1243 Stack
[STACK_FLAGS
] |= EMULATOR_FLAG_CF
;
1244 setAX(ERROR_INVALID_HANDLE
);
1250 /* Get Current Directory */
1253 BYTE DriveNumber
= getDL();
1254 String
= (PCHAR
)SEG_OFF_TO_PTR(getDS(), getSI());
1256 /* Get the real drive number */
1257 if (DriveNumber
== 0)
1259 DriveNumber
= Sda
->CurrentDrive
;
1263 /* Decrement DriveNumber since it was 1-based */
1267 if (DriveNumber
< SysVars
->NumLocalDrives
)
1270 * Copy the current directory into the target buffer.
1271 * It doesn't contain the drive letter and the backslash.
1273 strncpy(String
, DosData
->CurrentDirectories
[DriveNumber
], DOS_DIR_LENGTH
);
1274 Stack
[STACK_FLAGS
] &= ~EMULATOR_FLAG_CF
;
1275 setAX(0x0100); // Undocumented, see Ralf Brown: http://www.ctyme.com/intr/rb-2933.htm
1279 Stack
[STACK_FLAGS
] |= EMULATOR_FLAG_CF
;
1280 setAX(ERROR_INVALID_DRIVE
);
1286 /* Allocate Memory */
1289 WORD MaxAvailable
= 0;
1290 WORD Segment
= DosAllocateMemory(getBX(), &MaxAvailable
);
1294 Stack
[STACK_FLAGS
] &= ~EMULATOR_FLAG_CF
;
1299 Stack
[STACK_FLAGS
] |= EMULATOR_FLAG_CF
;
1300 setAX(Sda
->LastErrorCode
);
1301 setBX(MaxAvailable
);
1310 if (DosFreeMemory(getES()))
1312 Stack
[STACK_FLAGS
] &= ~EMULATOR_FLAG_CF
;
1316 Stack
[STACK_FLAGS
] |= EMULATOR_FLAG_CF
;
1317 setAX(ERROR_ARENA_TRASHED
);
1323 /* Resize Memory Block */
1328 if (DosResizeMemory(getES(), getBX(), &Size
))
1330 Stack
[STACK_FLAGS
] &= ~EMULATOR_FLAG_CF
;
1334 Stack
[STACK_FLAGS
] |= EMULATOR_FLAG_CF
;
1335 setAX(Sda
->LastErrorCode
);
1345 BYTE OrgAL
= getAL();
1346 LPSTR ProgramName
= SEG_OFF_TO_PTR(getDS(), getDX());
1347 PDOS_EXEC_PARAM_BLOCK ParamBlock
= SEG_OFF_TO_PTR(getES(), getBX());
1350 if (OrgAL
<= DOS_LOAD_OVERLAY
)
1352 DOS_EXEC_TYPE LoadType
= (DOS_EXEC_TYPE
)OrgAL
;
1355 if (LoadType
== DOS_LOAD_AND_EXECUTE
)
1357 /* Create a new process */
1358 ErrorCode
= DosCreateProcess(ProgramName
,
1360 MAKELONG(Stack
[STACK_IP
], Stack
[STACK_CS
]));
1365 /* Just load an executable */
1366 ErrorCode
= DosLoadExecutable(LoadType
,
1371 MAKELONG(Stack
[STACK_IP
], Stack
[STACK_CS
]));
1374 else if (OrgAL
== 0x05)
1376 // http://www.ctyme.com/intr/rb-2942.htm
1377 DPRINT1("Set execution state is UNIMPLEMENTED\n");
1378 ErrorCode
= ERROR_CALL_NOT_IMPLEMENTED
;
1382 ErrorCode
= ERROR_INVALID_FUNCTION
;
1385 if (ErrorCode
== ERROR_SUCCESS
)
1387 Stack
[STACK_FLAGS
] &= ~EMULATOR_FLAG_CF
;
1391 Stack
[STACK_FLAGS
] |= EMULATOR_FLAG_CF
;
1398 /* Terminate with Return Code */
1401 DosTerminateProcess(Sda
->CurrentPsp
, getAL(), 0);
1405 /* Get Return Code (ERRORLEVEL) */
1409 * According to Ralf Brown: http://www.ctyme.com/intr/rb-2976.htm
1410 * DosErrorLevel is cleared after being read by this function.
1412 Stack
[STACK_FLAGS
] &= ~EMULATOR_FLAG_CF
;
1413 setAX(Sda
->ErrorLevel
);
1414 Sda
->ErrorLevel
= 0x0000; // Clear it
1418 /* Find First File */
1421 WORD Result
= (WORD
)demFileFindFirst(FAR_POINTER(Sda
->DiskTransferArea
),
1422 SEG_OFF_TO_PTR(getDS(), getDX()),
1427 if (Result
== ERROR_SUCCESS
)
1428 Stack
[STACK_FLAGS
] &= ~EMULATOR_FLAG_CF
;
1430 Stack
[STACK_FLAGS
] |= EMULATOR_FLAG_CF
;
1435 /* Find Next File */
1438 WORD Result
= (WORD
)demFileFindNext(FAR_POINTER(Sda
->DiskTransferArea
));
1442 if (Result
== ERROR_SUCCESS
)
1443 Stack
[STACK_FLAGS
] &= ~EMULATOR_FLAG_CF
;
1445 Stack
[STACK_FLAGS
] |= EMULATOR_FLAG_CF
;
1450 /* Internal - Set Current Process ID (Set PSP Address) */
1453 DosSetProcessContext(getBX());
1457 /* Internal - Get Current Process ID (Get PSP Address) */
1459 /* Get Current PSP Address */
1463 * Undocumented AH=51h is identical to the documented AH=62h.
1464 * See Ralf Brown: http://www.ctyme.com/intr/rb-2982.htm
1465 * and http://www.ctyme.com/intr/rb-3140.htm
1466 * for more information.
1468 setBX(Sda
->CurrentPsp
);
1472 /* Internal - Get "List of lists" (SYSVARS) */
1476 * On return, ES points at the DOS data segment (see also INT 2F/AX=1203h).
1477 * See Ralf Brown: http://www.ctyme.com/intr/rb-2983.htm
1478 * for more information.
1481 /* Return the DOS "list of lists" in ES:BX */
1482 setES(DOS_DATA_SEGMENT
);
1483 setBX(DOS_DATA_OFFSET(SysVars
.FirstDpb
));
1487 /* Create Child PSP */
1490 DosCreatePsp(getDX(), getSI());
1491 DosSetProcessContext(getDX());
1498 LPSTR ExistingFileName
= (LPSTR
)SEG_OFF_TO_PTR(getDS(), getDX());
1499 LPSTR NewFileName
= (LPSTR
)SEG_OFF_TO_PTR(getES(), getDI());
1502 * See Ralf Brown: http://www.ctyme.com/intr/rb-2990.htm
1503 * for more information.
1506 if (MoveFileA(ExistingFileName
, NewFileName
))
1508 Stack
[STACK_FLAGS
] &= ~EMULATOR_FLAG_CF
;
1512 Stack
[STACK_FLAGS
] |= EMULATOR_FLAG_CF
;
1513 setAX(GetLastError());
1519 /* Get/Set Memory Management Options */
1522 if (getAL() == 0x00)
1524 /* Get allocation strategy */
1525 Stack
[STACK_FLAGS
] &= ~EMULATOR_FLAG_CF
;
1526 setAX(Sda
->AllocStrategy
);
1528 else if (getAL() == 0x01)
1530 /* Set allocation strategy */
1532 if ((getBL() & (DOS_ALLOC_HIGH
| DOS_ALLOC_HIGH_LOW
))
1533 == (DOS_ALLOC_HIGH
| DOS_ALLOC_HIGH_LOW
))
1535 /* Can't set both */
1536 Stack
[STACK_FLAGS
] |= EMULATOR_FLAG_CF
;
1537 setAX(ERROR_INVALID_PARAMETER
);
1541 if ((getBL() & 0x3F) > DOS_ALLOC_LAST_FIT
)
1543 /* Invalid allocation strategy */
1544 Stack
[STACK_FLAGS
] |= EMULATOR_FLAG_CF
;
1545 setAX(ERROR_INVALID_PARAMETER
);
1549 Sda
->AllocStrategy
= getBL();
1550 Stack
[STACK_FLAGS
] &= ~EMULATOR_FLAG_CF
;
1552 else if (getAL() == 0x02)
1554 /* Get UMB link state */
1555 Stack
[STACK_FLAGS
] &= ~EMULATOR_FLAG_CF
;
1556 setAL(DosUmbLinked
? 0x01 : 0x00);
1558 else if (getAL() == 0x03)
1560 /* Set UMB link state */
1561 if (getBX()) DosLinkUmb();
1562 else DosUnlinkUmb();
1563 Stack
[STACK_FLAGS
] &= ~EMULATOR_FLAG_CF
;
1567 /* Invalid or unsupported function */
1568 Stack
[STACK_FLAGS
] |= EMULATOR_FLAG_CF
;
1569 setAX(ERROR_INVALID_FUNCTION
);
1575 /* Get Extended Error Information */
1578 DPRINT1("INT 21h, AH = 59h, BX = %04Xh - Get Extended Error Information is UNIMPLEMENTED\n",
1583 /* Create Temporary File */
1586 LPSTR PathName
= (LPSTR
)SEG_OFF_TO_PTR(getDS(), getDX());
1587 LPSTR FileName
= PathName
; // The buffer for the path and the full file name is the same.
1593 * See Ralf Brown: http://www.ctyme.com/intr/rb-3014.htm
1594 * for more information.
1597 // FIXME: Check for buffer validity?
1598 // It should be a ASCIIZ path ending with a '\' + 13 zero bytes
1599 // to receive the generated filename.
1601 /* First create the temporary file */
1602 uRetVal
= GetTempFileNameA(PathName
, NULL
, 0, FileName
);
1605 Stack
[STACK_FLAGS
] |= EMULATOR_FLAG_CF
;
1606 setAX(GetLastError());
1610 /* Now try to open it in read/write access */
1611 ErrorCode
= DosOpenFile(&FileHandle
, FileName
, 2);
1612 if (ErrorCode
== ERROR_SUCCESS
)
1614 Stack
[STACK_FLAGS
] &= ~EMULATOR_FLAG_CF
;
1619 Stack
[STACK_FLAGS
] |= EMULATOR_FLAG_CF
;
1626 /* Create New File */
1630 WORD ErrorCode
= DosCreateFile(&FileHandle
,
1631 (LPCSTR
)SEG_OFF_TO_PTR(getDS(), getDX()),
1635 if (ErrorCode
== ERROR_SUCCESS
)
1637 Stack
[STACK_FLAGS
] &= ~EMULATOR_FLAG_CF
;
1642 Stack
[STACK_FLAGS
] |= EMULATOR_FLAG_CF
;
1649 /* Lock/Unlock Region of File */
1652 if (getAL() == 0x00)
1654 /* Lock region of file */
1655 if (DosLockFile(getBX(), MAKELONG(getDX(), getCX()), MAKELONG(getDI(), getSI())))
1657 Stack
[STACK_FLAGS
] &= ~EMULATOR_FLAG_CF
;
1661 Stack
[STACK_FLAGS
] |= EMULATOR_FLAG_CF
;
1662 setAX(Sda
->LastErrorCode
);
1665 else if (getAL() == 0x01)
1667 /* Unlock region of file */
1668 if (DosUnlockFile(getBX(), MAKELONG(getDX(), getCX()), MAKELONG(getDI(), getSI())))
1670 Stack
[STACK_FLAGS
] &= ~EMULATOR_FLAG_CF
;
1674 Stack
[STACK_FLAGS
] |= EMULATOR_FLAG_CF
;
1675 setAX(Sda
->LastErrorCode
);
1680 /* Invalid subfunction */
1681 Stack
[STACK_FLAGS
] |= EMULATOR_FLAG_CF
;
1682 setAX(ERROR_INVALID_FUNCTION
);
1688 /* Canonicalize File Name or Path */
1692 * See Ralf Brown: http://www.ctyme.com/intr/rb-3137.htm
1693 * for more information.
1697 * We suppose that the DOS app gave to us a valid
1698 * 128-byte long buffer for the canonicalized name.
1700 DWORD dwRetVal
= GetFullPathNameA(SEG_OFF_TO_PTR(getDS(), getSI()),
1702 SEG_OFF_TO_PTR(getES(), getDI()),
1706 Stack
[STACK_FLAGS
] |= EMULATOR_FLAG_CF
;
1707 setAX(GetLastError());
1711 Stack
[STACK_FLAGS
] &= ~EMULATOR_FLAG_CF
;
1715 // FIXME: Convert the full path name into short version.
1716 // We cannot reliably use GetShortPathName, because it fails
1717 // if the path name given doesn't exist. However this DOS
1718 // function AH=60h should be able to work even for non-existing
1719 // path and file names.
1724 /* Miscellaneous Internal Functions */
1729 /* Get Swappable Data Area */
1732 setDS(DOS_DATA_SEGMENT
);
1733 setSI(DOS_DATA_OFFSET(Sda
.ErrorMode
));
1734 setCX(sizeof(DOS_SDA
));
1735 setDX(FIELD_OFFSET(DOS_SDA
, LastAX
));
1737 Stack
[STACK_FLAGS
] &= ~EMULATOR_FLAG_CF
;
1743 DPRINT1("INT 21h, AH = 5Dh, subfunction AL = %Xh NOT IMPLEMENTED\n",
1751 /* Extended Country Information */
1756 case 0x01: case 0x02: case 0x03:
1757 case 0x04: case 0x05: case 0x06:
1760 WORD BufferSize
= getCX();
1762 ErrorCode
= DosGetCountryInfoEx(getAL(),
1765 (PDOS_COUNTRY_INFO_2
)SEG_OFF_TO_PTR(getES(), getDI()),
1767 if (ErrorCode
== ERROR_SUCCESS
)
1769 Stack
[STACK_FLAGS
] &= ~EMULATOR_FLAG_CF
;
1774 Stack
[STACK_FLAGS
] |= EMULATOR_FLAG_CF
;
1781 /* Country-dependent Character Capitalization -- Character */
1783 /* Country-dependent Filename Capitalization -- Character */
1786 setDL(DosToUpper(getDL()));
1787 Stack
[STACK_FLAGS
] &= ~EMULATOR_FLAG_CF
;
1788 // setAX(ERROR_SUCCESS);
1792 /* Country-dependent Character Capitalization -- Counted ASCII String */
1794 /* Country-dependent Filename Capitalization -- Counted ASCII String */
1797 PCHAR Str
= (PCHAR
)SEG_OFF_TO_PTR(getDS(), getDX());
1798 // FIXME: Check for NULL ptr!!
1799 DosToUpperStrN(Str
, Str
, getCX());
1800 Stack
[STACK_FLAGS
] &= ~EMULATOR_FLAG_CF
;
1801 // setAX(ERROR_SUCCESS);
1805 /* Country-dependent Character Capitalization -- ASCIIZ String */
1807 /* Country-dependent Filename Capitalization -- ASCIIZ String */
1810 PSTR Str
= (PSTR
)SEG_OFF_TO_PTR(getDS(), getDX());
1811 // FIXME: Check for NULL ptr!!
1812 DosToUpperStrZ(Str
, Str
);
1813 Stack
[STACK_FLAGS
] &= ~EMULATOR_FLAG_CF
;
1814 // setAX(ERROR_SUCCESS);
1818 /* Determine if Character represents YES/NO Response */
1821 setAX(DosIfCharYesNo(MAKEWORD(getDL(), getDH())));
1822 Stack
[STACK_FLAGS
] &= ~EMULATOR_FLAG_CF
;
1828 DPRINT1("INT 21h, AH = 65h, subfunction AL = %Xh NOT IMPLEMENTED\n",
1836 /* Set Handle Count */
1839 if (!DosResizeHandleTable(getBX()))
1841 Stack
[STACK_FLAGS
] |= EMULATOR_FLAG_CF
;
1842 setAX(Sda
->LastErrorCode
);
1844 else Stack
[STACK_FLAGS
] &= ~EMULATOR_FLAG_CF
;
1854 * Function 6Ah is identical to function 68h,
1855 * and sets AH to 68h if success.
1856 * See Ralf Brown: http://www.ctyme.com/intr/rb-3176.htm
1857 * for more information.
1861 if (DosFlushFileBuffers(getBX()))
1863 Stack
[STACK_FLAGS
] &= ~EMULATOR_FLAG_CF
;
1867 Stack
[STACK_FLAGS
] |= EMULATOR_FLAG_CF
;
1868 setAX(GetLastError());
1874 /* Extended Open/Create */
1878 WORD CreationStatus
;
1881 /* Check for AL == 00 */
1882 if (getAL() != 0x00)
1884 Stack
[STACK_FLAGS
] |= EMULATOR_FLAG_CF
;
1885 setAX(ERROR_INVALID_FUNCTION
);
1890 * See Ralf Brown: http://www.ctyme.com/intr/rb-3179.htm
1891 * for the full detailed description.
1893 * WARNING: BH contains some extended flags that are NOT SUPPORTED.
1896 ErrorCode
= DosCreateFileEx(&FileHandle
,
1898 (LPCSTR
)SEG_OFF_TO_PTR(getDS(), getSI()),
1903 if (ErrorCode
== ERROR_SUCCESS
)
1905 Stack
[STACK_FLAGS
] &= ~EMULATOR_FLAG_CF
;
1906 setCX(CreationStatus
);
1911 Stack
[STACK_FLAGS
] |= EMULATOR_FLAG_CF
;
1921 DPRINT1("DOS Function INT 0x21, AH = %xh, AL = %xh NOT IMPLEMENTED!\n",
1924 setAL(0); // Some functions expect AL to be 0 when it's not supported.
1925 Stack
[STACK_FLAGS
] |= EMULATOR_FLAG_CF
;
1932 VOID WINAPI
DosBreakInterrupt(LPWORD Stack
)
1934 /* Set CF to terminate the running process */
1935 Stack
[STACK_FLAGS
] |= EMULATOR_FLAG_CF
;
1938 VOID WINAPI
DosAbsoluteRead(LPWORD Stack
)
1941 * This call should leave the flags on the stack for some reason,
1942 * so move the stack by one word.
1943 * See: http://www.techhelpmanual.com/565-int_25h_26h__absolute_disk_read_write.html
1945 Stack
[STACK_INT_NUM
] = Stack
[STACK_IP
];
1946 Stack
[STACK_IP
] = Stack
[STACK_CS
];
1947 Stack
[STACK_CS
] = Stack
[STACK_FLAGS
];
1948 setSP(LOWORD(getSP() - 2));
1950 // TODO: NOT IMPLEMENTED;
1953 /* General failure */
1955 Stack
[STACK_FLAGS
- 1] |= EMULATOR_FLAG_CF
;
1958 VOID WINAPI
DosAbsoluteWrite(LPWORD Stack
)
1961 * This call should leave the flags on the stack for some reason,
1962 * so move the stack by one word.
1963 * See: http://www.techhelpmanual.com/565-int_25h_26h__absolute_disk_read_write.html
1965 Stack
[STACK_INT_NUM
] = Stack
[STACK_IP
];
1966 Stack
[STACK_IP
] = Stack
[STACK_CS
];
1967 Stack
[STACK_CS
] = Stack
[STACK_FLAGS
];
1968 setSP(LOWORD(getSP() - 2));
1970 // TODO: NOT IMPLEMENTED;
1973 /* General failure */
1975 Stack
[STACK_FLAGS
- 1] |= EMULATOR_FLAG_CF
;
1978 VOID WINAPI
DosInt27h(LPWORD Stack
)
1980 DosTerminateProcess(getCS(), 0, (getDX() + 0x0F) >> 4);
1983 VOID WINAPI
DosIdle(LPWORD Stack
)
1986 * This will set the carry flag on the first call (to repeat the BOP),
1987 * and clear it in the next, so that exactly one HLT occurs.
1992 VOID WINAPI
DosFastConOut(LPWORD Stack
)
1995 * This is the DOS 2+ Fast Console Output Interrupt.
1996 * The default handler under DOS 2.x and 3.x simply calls INT 10h/AH=0Eh.
1998 * See Ralf Brown: http://www.ctyme.com/intr/rb-4124.htm
1999 * for more information.
2002 /* Save AX and BX */
2003 USHORT AX
= getAX();
2004 USHORT BX
= getBX();
2007 * Set the parameters:
2008 * AL contains the character to print (already set),
2009 * BL contains the character attribute,
2010 * BH contains the video page to use.
2012 setBL(DOS_CHAR_ATTRIBUTE
);
2013 setBH(Bda
->VideoPage
);
2015 /* Call the BIOS INT 10h, AH=0Eh "Teletype Output" */
2017 Int32Call(&DosContext
, BIOS_VIDEO_INTERRUPT
);
2019 /* Restore AX and BX */
2024 VOID WINAPI
DosInt2Fh(LPWORD Stack
)
2028 /* Extended Memory Specification */
2032 if (!XmsGetDriverEntry(&DriverEntry
)) break;
2036 /* Installation Check */
2039 /* The driver is loaded */
2044 /* Get Driver Address */
2047 setES(HIWORD(DriverEntry
));
2048 setBX(LOWORD(DriverEntry
));
2053 DPRINT1("Unknown DOS XMS Function: INT 0x2F, AH = 43h, AL = %xh\n", getAL());
2062 DPRINT1("DOS Internal System Function INT 0x2F, AH = %xh, AL = %xh NOT IMPLEMENTED!\n",
2064 Stack
[STACK_FLAGS
] |= EMULATOR_FLAG_CF
;
2069 BOOLEAN
DosKRNLInitialize(VOID
)
2076 CHAR CurrentDirectory
[MAX_PATH
];
2077 CHAR DosDirectory
[DOS_DIR_LENGTH
];
2079 const BYTE NullDriverRoutine
[] = {
2080 /* Strategy routine entry */
2081 0x26, // mov [Request.Status], DOS_DEVSTAT_DONE
2084 FIELD_OFFSET(DOS_REQUEST_HEADER
, Status
),
2085 LOBYTE(DOS_DEVSTAT_DONE
),
2086 HIBYTE(DOS_DEVSTAT_DONE
),
2088 /* Interrupt routine entry */
2095 /* Initialize the global DOS data area */
2096 DosData
= (PDOS_DATA
)SEG_OFF_TO_PTR(DOS_DATA_SEGMENT
, 0x0000);
2097 RtlZeroMemory(DosData
, sizeof(*DosData
));
2099 /* Initialize the list of lists */
2100 SysVars
= &DosData
->SysVars
;
2101 RtlZeroMemory(SysVars
, sizeof(*SysVars
));
2102 SysVars
->FirstMcb
= FIRST_MCB_SEGMENT
;
2103 SysVars
->FirstSft
= MAKELONG(DOS_DATA_OFFSET(Sft
), DOS_DATA_SEGMENT
);
2104 SysVars
->CurrentDirs
= MAKELONG(DOS_DATA_OFFSET(CurrentDirectories
),
2106 /* The last drive can be redefined with the LASTDRIVE command. At the moment, set the real maximum possible, 'Z'. */
2107 SysVars
->NumLocalDrives
= 'Z' - 'A' + 1;
2109 /* The boot drive is initialized to the %SYSTEMDRIVE% value */
2110 // NOTE: Using the NtSystemRoot system variable might be OS-specific...
2111 SysVars
->BootDrive
= SharedUserData
->NtSystemRoot
[0] - 'A' + 1;
2113 /* Initialize the NUL device driver */
2114 SysVars
->NullDevice
.Link
= 0xFFFFFFFF;
2115 SysVars
->NullDevice
.DeviceAttributes
= DOS_DEVATTR_NUL
| DOS_DEVATTR_CHARACTER
;
2116 SysVars
->NullDevice
.StrategyRoutine
= FIELD_OFFSET(DOS_SYSVARS
, NullDriverRoutine
);
2117 SysVars
->NullDevice
.InterruptRoutine
= SysVars
->NullDevice
.StrategyRoutine
+ 6;
2118 RtlFillMemory(SysVars
->NullDevice
.DeviceName
,
2119 sizeof(SysVars
->NullDevice
.DeviceName
),
2121 RtlCopyMemory(SysVars
->NullDevice
.DeviceName
, "NUL", strlen("NUL"));
2122 RtlCopyMemory(SysVars
->NullDriverRoutine
,
2124 sizeof(NullDriverRoutine
));
2126 /* Initialize the swappable data area */
2127 Sda
= &DosData
->Sda
;
2128 RtlZeroMemory(Sda
, sizeof(*Sda
));
2130 /* Get the current directory */
2131 if (!GetCurrentDirectoryA(sizeof(CurrentDirectory
), CurrentDirectory
))
2133 // TODO: Use some kind of default path?
2137 /* Convert it to a DOS path */
2138 if (!GetShortPathNameA(CurrentDirectory
, DosDirectory
, sizeof(DosDirectory
)))
2140 // TODO: Use some kind of default path?
2145 Sda
->CurrentDrive
= RtlUpperChar(DosDirectory
[0]) - 'A';
2147 /* Get the directory part of the path */
2148 Path
= strchr(DosDirectory
, '\\');
2151 /* Skip the backslash */
2155 /* Set the directory */
2158 strncpy(DosData
->CurrentDirectories
[Sda
->CurrentDrive
], Path
, DOS_DIR_LENGTH
);
2161 /* Set the current PSP to the system PSP */
2162 Sda
->CurrentPsp
= SYSTEM_PSP
;
2164 /* Set the initial allocation strategy to "best fit" */
2165 Sda
->AllocStrategy
= DOS_ALLOC_BEST_FIT
;
2167 /* Initialize the SFT */
2168 Sft
= (PDOS_SFT
)FAR_POINTER(SysVars
->FirstSft
);
2169 Sft
->Link
= 0xFFFFFFFF;
2170 Sft
->NumDescriptors
= DOS_SFT_SIZE
;
2172 for (i
= 0; i
< Sft
->NumDescriptors
; i
++)
2174 /* Clear the file descriptor entry */
2175 RtlZeroMemory(&Sft
->FileDescriptors
[i
], sizeof(DOS_FILE_DESCRIPTOR
));
2178 /* Read CONFIG.SYS */
2179 Stream
= _wfopen(DOS_CONFIG_PATH
, L
"r");
2182 while (fgetws(Buffer
, 256, Stream
))
2184 // TODO: Parse the line
2191 /* Initialize the callback context */
2192 InitializeContext(&DosContext
, DOS_CODE_SEGMENT
, 0x0000);
2194 /* Register the DOS 32-bit Interrupts */
2195 RegisterDosInt32(0x20, DosInt20h
);
2196 RegisterDosInt32(0x21, DosInt21h
);
2197 // RegisterDosInt32(0x22, DosInt22h ); // Termination
2198 RegisterDosInt32(0x23, DosBreakInterrupt
); // Ctrl-C / Ctrl-Break
2199 // RegisterDosInt32(0x24, DosInt24h ); // Critical Error
2200 RegisterDosInt32(0x25, DosAbsoluteRead
); // Absolute Disk Read
2201 RegisterDosInt32(0x26, DosAbsoluteWrite
); // Absolute Disk Write
2202 RegisterDosInt32(0x27, DosInt27h
); // Terminate and Stay Resident
2203 RegisterDosInt32(0x28, DosIdle
); // DOS Idle Interrupt
2204 RegisterDosInt32(0x29, DosFastConOut
); // DOS 2+ Fast Console Output
2205 RegisterDosInt32(0x2F, DosInt2Fh
); // Multiplex Interrupt
2207 /* Unimplemented DOS interrupts */
2208 RegisterDosInt32(0x2A, NULL
); // Network - Installation Check
2210 /* Initialize country data */
2211 DosCountryInitialize();
2213 /* Load the CON driver */
2216 /* Load the XMS driver (HIMEM) */
2219 /* Load the EMS driver */
2220 if (!EmsDrvInitialize(EMS_TOTAL_PAGES
))
2222 DPRINT1("Could not initialize EMS. EMS will not be available.\n"
2223 "Try reducing the number of EMS pages.\n");