Author: hbelusca
Date: Tue Oct 29 01:55:54 2013
New Revision: 60790
URL:
http://svn.reactos.org/svn/reactos?rev=60790&view=rev
Log:
[NTVDM]: DOS:
- The DosErrorLevel is stored as a WORD: its LOWORD is the return code and the HIWORD is
the termination code.
- When copying CurrentDirectories[...], be sure that we copy maximum DOS_DIR_LENGTH
chars.
- Implement (or stubplement) bunch of INT 21h functions: 0x03, 0x04, 0x05, 0x0C, 0x0D,
0x26, 0x37, 0x47, 0x4D and 0x50. Functions 0x18, 0x1D, 0x1E and 0x20 are NULL functions
present in DOS for CP/M compatibility only.
- Fix DOS version querying.
- Use set/getAX() instead of EmulatorSet/GetRegister, and use setCF instead of
EmulatorSetFlag.
Modified:
branches/ntvdm/subsystems/ntvdm/dos.c
branches/ntvdm/subsystems/ntvdm/dos.h
Modified: branches/ntvdm/subsystems/ntvdm/dos.c
URL:
http://svn.reactos.org/svn/reactos/branches/ntvdm/subsystems/ntvdm/dos.c?re…
==============================================================================
--- branches/ntvdm/subsystems/ntvdm/dos.c [iso-8859-1] (original)
+++ branches/ntvdm/subsystems/ntvdm/dos.c [iso-8859-1] Tue Oct 29 01:55:54 2013
@@ -28,7 +28,7 @@
static WORD DosSftRefCount[DOS_SFT_SIZE];
static BYTE DosAllocStrategy = DOS_ALLOC_BEST_FIT;
static BOOLEAN DosUmbLinked = FALSE;
-static BYTE DosErrorLevel = 0;
+static WORD DosErrorLevel = 0x0000;
/* PRIVATE FUNCTIONS **********************************************************/
@@ -790,6 +790,24 @@
return ERROR_SUCCESS;
}
+BOOLEAN DosFlushFileBuffers(WORD FileHandle)
+{
+ HANDLE Handle = DosGetRealHandle(FileHandle);
+
+ /* Make sure the handle is valid */
+ if (Handle == INVALID_HANDLE_VALUE) return FALSE;
+
+ /*
+ * No need to check whether the handle is a console handle since
+ * FlushFileBuffers() automatically does this check and calls
+ * FlushConsoleInputBuffer() for us.
+ */
+ // if (IsConsoleHandle(Handle))
+ // return (BOOLEAN)FlushConsoleInputBuffer(hFile);
+ // else
+ return (BOOLEAN)FlushFileBuffers(Handle);
+}
+
BOOLEAN DosDuplicateHandle(WORD OldHandle, WORD NewHandle)
{
BYTE SftIndex;
@@ -940,9 +958,15 @@
}
/* Set the directory for the drive */
- if (Path != NULL) strcpy(CurrentDirectories[DriveNumber], Path);
- else strcpy(CurrentDirectories[DriveNumber], "");
-
+ if (Path != NULL)
+ {
+ strncpy(CurrentDirectories[DriveNumber], Path, DOS_DIR_LENGTH);
+ }
+ else
+ {
+ CurrentDirectories[DriveNumber][0] = '\0';
+ }
+
/* Return success */
return TRUE;
}
@@ -963,8 +987,8 @@
/* Save the interrupt vectors */
PspBlock->TerminateAddress = IntVecTable[0x22];
- PspBlock->BreakAddress = IntVecTable[0x23];
- PspBlock->CriticalAddress = IntVecTable[0x24];
+ PspBlock->BreakAddress = IntVecTable[0x23];
+ PspBlock->CriticalAddress = IntVecTable[0x24];
/* Set the parent PSP */
PspBlock->ParentPsp = CurrentPsp;
@@ -1260,8 +1284,8 @@
if (CurrentPsp == SYSTEM_PSP) VdmRunning = FALSE;
}
- /* Save the return code */
- DosErrorLevel = ReturnCode;
+ /* Save the return code - Normal termination */
+ DosErrorLevel = MAKEWORD(ReturnCode, 0x00);
/* Return control to the parent process */
EmulatorExecute(HIWORD(PspBlock->TerminateAddress),
@@ -1371,7 +1395,7 @@
VOID DosInt21h(LPWORD Stack)
{
- CHAR Character;
+ BYTE Character;
SYSTEMTIME SystemTime;
PCHAR String;
PDOS_INPUT_BUFFER InputBuffer;
@@ -1386,38 +1410,68 @@
break;
}
- /* Read Character And Echo */
+ /* Read Character from STDIN with Echo */
case 0x01:
{
Character = DosReadCharacter();
DosPrintCharacter(Character);
/* Let the BOP repeat if needed */
- if (EmulatorGetFlag(EMULATOR_FLAG_CF)) break;
+ if (getCF()) break;
setAL(Character);
break;
}
- /* Print Character */
+ /* Write Character to STDOUT */
case 0x02:
{
- BYTE Character = getDL();
+ Character = getDL();
DosPrintCharacter(Character);
/*
- * We return the output character (DOS 2.1+), see:
- *
http://www.delorie.com/djgpp/doc/rbinter/id/65/25.html
+ * We return the output character (DOS 2.1+).
+ * Also, if we're going to output a TAB, then
+ * don't return a TAB but a SPACE instead.
+ * See Ralf Brown:
http://www.ctyme.com/intr/rb-2554.htm
* for more information.
*/
- setAL(Character);
+ setAL(Character == '\t' ? ' ' : Character);
+ break;
+ }
+
+ /* Read Character from STDAUX */
+ case 0x03:
+ {
+ // FIXME: Really read it from STDAUX!
+ DPRINT1("INT 16h, 03h: Read character from STDAUX is
HALFPLEMENTED\n");
+ setAL(DosReadCharacter());
+ break;
+ }
+
+ /* Write Character to STDAUX */
+ case 0x04:
+ {
+ // FIXME: Really write it to STDAUX!
+ DPRINT1("INT 16h, 04h: Write character to STDAUX is
HALFPLEMENTED\n");
+ DosPrintCharacter(getDL());
+ break;
+ }
+
+ /* Write Character to Printer */
+ case 0x05:
+ {
+ // FIXME: Really write it to printer!
+ DPRINT1("INT 16h, 05h: Write character to printer is HALFPLEMENTED
-\n\n");
+ DPRINT1("0x%p\n", getDL());
+ DPRINT1("\n\n-----------\n\n");
break;
}
/* Direct Console I/O */
case 0x06:
{
- BYTE Character = getDL();
+ Character = getDL();
if (Character != 0xFF)
{
@@ -1425,8 +1479,8 @@
DosPrintCharacter(Character);
/*
- * We return the output character (DOS 2.1+), see:
- *
http://www.delorie.com/djgpp/doc/rbinter/id/69/25.html
+ * We return the output character (DOS 2.1+).
+ * See Ralf Brown:
http://www.ctyme.com/intr/rb-2558.htm
* for more information.
*/
setAL(Character);
@@ -1443,27 +1497,27 @@
{
/* No character available */
Stack[STACK_FLAGS] |= EMULATOR_FLAG_ZF;
- setAL(0);
+ setAL(0x00);
}
}
break;
}
- /* Read Character Without Echo */
+ /* Character Input without Echo */
case 0x07:
case 0x08:
{
Character = DosReadCharacter();
/* Let the BOP repeat if needed */
- if (EmulatorGetFlag(EMULATOR_FLAG_CF)) break;
+ if (getCF()) break;
setAL(Character);
break;
}
- /* Print String */
+ /* Write string to STDOUT */
case 0x09:
{
String = (PCHAR)SEG_OFF_TO_PTR(getDS(), getDX());
@@ -1475,8 +1529,8 @@
}
/*
- * We return the output character (DOS 2.1+), see:
- *
http://www.delorie.com/djgpp/doc/rbinter/id/73/25.html
+ * We return the terminating character (DOS 2.1+).
+ * See Ralf Brown:
http://www.ctyme.com/intr/rb-2562.htm
* for more information.
*/
setAL('$');
@@ -1494,7 +1548,7 @@
Character = DosReadCharacter();
/* If it's not ready yet, let the BOP repeat */
- if (EmulatorGetFlag(EMULATOR_FLAG_CF)) break;
+ if (getCF()) break;
/* Echo the character and append it to the buffer */
DosPrintCharacter(Character);
@@ -1516,6 +1570,49 @@
break;
}
+ /* Flush Buffer and Read STDIN */
+ case 0x0C:
+ {
+ BYTE InputFunction = getAL();
+
+ /* Flush STDIN buffer */
+ DosFlushFileBuffers(DOS_INPUT_HANDLE); // Maybe just create a
DosFlushInputBuffer...
+
+ /*
+ * If the input function number contained in AL is valid, i.e.
+ * AL == 0x01 or 0x06 or 0x07 or 0x08 or 0x0A, call ourselves
+ * recursively with AL == AH.
+ */
+ if (InputFunction == 0x01 || InputFunction == 0x06 ||
+ InputFunction == 0x07 || InputFunction == 0x08 ||
+ InputFunction == 0x0A)
+ {
+ setAH(InputFunction);
+ /*
+ * Instead of calling ourselves really recursively as in:
+ * DosInt21h(Stack);
+ * prefer resetting the CF flag to let the BOP repeat.
+ */
+ setCF(1);
+ }
+ break;
+ }
+
+ /* Disk Reset */
+ case 0x0D:
+ {
+ PDOS_PSP PspBlock = SEGMENT_TO_PSP(CurrentPsp);
+
+ // TODO: Flush what's needed.
+ DPRINT1("INT 21h, 0Dh is UNIMPLEMENTED\n");
+
+ /* Clear CF in DOS 6 only */
+ if (PspBlock->DosVersion == 0x0006)
+ Stack[STACK_FLAGS] &= ~EMULATOR_FLAG_CF;
+
+ break;
+ }
+
/* Set Default Drive */
case 0x0E:
{
@@ -1524,6 +1621,22 @@
break;
}
+ /* NULL Function for CP/M Compatibility */
+ case 0x18:
+ {
+ /*
+ * This function corresponds to the CP/M BDOS function
+ * "get bit map of logged drives", which is meaningless
+ * under MS-DOS.
+ *
+ * For: PTS-DOS 6.51 & S/DOS 1.0 - EXTENDED RENAME FILE USING FCB
+ * See Ralf Brown:
http://www.ctyme.com/intr/rb-2584.htm
+ * for more information.
+ */
+ setAL(0x00);
+ break;
+ }
+
/* Get Default Drive */
case 0x19:
{
@@ -1538,6 +1651,42 @@
break;
}
+ /* NULL Function for CP/M Compatibility */
+ case 0x1D:
+ case 0x1E:
+ {
+ /*
+ * Function 0x1D corresponds to the CP/M BDOS function
+ * "get bit map of read-only drives", which is meaningless
+ * under MS-DOS.
+ * See Ralf Brown:
http://www.ctyme.com/intr/rb-2592.htm
+ * for more information.
+ *
+ * Function 0x1E corresponds to the CP/M BDOS function
+ * "set file attributes", which was meaningless under MS-DOS 1.x.
+ * See Ralf Brown:
http://www.ctyme.com/intr/rb-2593.htm
+ * for more information.
+ */
+ setAL(0x00);
+ break;
+ }
+
+ /* NULL Function for CP/M Compatibility */
+ case 0x20:
+ {
+ /*
+ * This function corresponds to the CP/M BDOS function
+ * "get/set default user (sublibrary) number", which is
meaningless
+ * under MS-DOS.
+ *
+ * For: S/DOS 1.0+ & PTS-DOS 6.51+ - GET OEM REVISION
+ * See Ralf Brown:
http://www.ctyme.com/intr/rb-2596.htm
+ * for more information.
+ */
+ setAL(0x00);
+ break;
+ }
+
/* Set Interrupt Vector */
case 0x25:
{
@@ -1545,11 +1694,17 @@
/* Write the new far pointer to the IDT */
((PDWORD)BaseAddress)[getAL()] = FarPointer;
-
- break;
- }
-
- /* Get system date */
+ break;
+ }
+
+ /* Create New PSP */
+ case 0x26:
+ {
+ DPRINT1("INT 21h, 26h - Create New PSP is UNIMPLEMENTED\n");
+ break;
+ }
+
+ /* Get System Date */
case 0x2A:
{
GetLocalTime(&SystemTime);
@@ -1559,7 +1714,7 @@
break;
}
- /* Set system date */
+ /* Set System Date */
case 0x2B:
{
GetLocalTime(&SystemTime);
@@ -1572,7 +1727,7 @@
break;
}
- /* Get system time */
+ /* Get System Time */
case 0x2C:
{
GetLocalTime(&SystemTime);
@@ -1581,7 +1736,7 @@
break;
}
- /* Set system time */
+ /* Set System Time */
case 0x2D:
{
GetLocalTime(&SystemTime);
@@ -1608,22 +1763,34 @@
{
PDOS_PSP PspBlock = SEGMENT_TO_PSP(CurrentPsp);
- if (LOBYTE(PspBlock->DosVersion) < 5 || getAL() == 0)
- {
- /* Return DOS 24-bit user serial number in BL:CX */
- setBL(0x00);
- setCX(0x0000);
- }
-
- if (LOBYTE(PspBlock->DosVersion) >= 5 && getAL() == 1)
+ /*
+ * See Ralf Brown:
http://www.ctyme.com/intr/rb-2711.htm
+ * for more information.
+ */
+
+ if (LOBYTE(PspBlock->DosVersion) < 5 || getAL() == 0x00)
{
/*
* Return DOS OEM number:
* 0x00 for IBM PC-DOS
- * 0xFF for MS-DOS
+ * 0x02 for packaged MS-DOS
*/
- setBH(0xFF);
- }
+ setBH(0x02);
+ }
+
+ if (LOBYTE(PspBlock->DosVersion) >= 5 && getAL() == 0x01)
+ {
+ /*
+ * Return version flag:
+ * 1 << 3 if DOS is in ROM,
+ * 0 (reserved) if not.
+ */
+ setBH(0x00);
+ }
+
+ /* Return DOS 24-bit user serial number in BL:CX */
+ setBL(0x00);
+ setCX(0x0000);
/* Return DOS version: Minor:Major in AH:AL */
setAX(PspBlock->DosVersion);
@@ -1640,6 +1807,60 @@
setES(HIWORD(FarPointer));
setBX(LOWORD(FarPointer));
break;
+ }
+
+ /* SWITCH character - AVAILDEV */
+ case 0x37:
+ {
+ if (getAL() == 0x00)
+ {
+ /*
+ * DOS 2+ - "SWITCHAR" - GET SWITCH CHARACTER
+ * This setting is ignored by MS-DOS 4.0+.
+ * MS-DOS 5+ always return AL=00h/DL=2Fh.
+ * See Ralf Brown:
http://www.ctyme.com/intr/rb-2752.htm
+ * for more information.
+ */
+ setDL('/');
+ setAL(0x00);
+ }
+ else if (getAL() == 0x01)
+ {
+ /*
+ * DOS 2+ - "SWITCHAR" - SET SWITCH CHARACTER
+ * This setting is ignored by MS-DOS 5+.
+ * See Ralf Brown:
http://www.ctyme.com/intr/rb-2753.htm
+ * for more information.
+ */
+ // getDL();
+ setAL(0xFF);
+ }
+ else if (getAL() == 0x02)
+ {
+ /*
+ * DOS 2.x and 3.3+ only - "AVAILDEV" - SPECIFY \DEV\ PREFIX
USE
+ * See Ralf Brown:
http://www.ctyme.com/intr/rb-2754.htm
+ * for more information.
+ */
+ // setDL();
+ setAL(0xFF);
+ }
+ else if (getAL() == 0x03)
+ {
+ /*
+ * DOS 2.x and 3.3+ only - "AVAILDEV" - SPECIFY \DEV\ PREFIX
USE
+ * See Ralf Brown:
http://www.ctyme.com/intr/rb-2754.htm
+ * for more information.
+ */
+ // getDL();
+ setAL(0xFF);
+ }
+ else
+ {
+ setAL(0xFF);
+ }
+
+ break;
}
/* Create Directory */
@@ -1756,7 +1977,7 @@
break;
}
- /* Read File */
+ /* Read from File or Device */
case 0x3F:
{
WORD Handle = getBX();
@@ -1770,17 +1991,20 @@
while (Stack[STACK_COUNTER] < Count)
{
/* Read a character from the BIOS */
- Buffer[Stack[STACK_COUNTER]] = LOBYTE(BiosGetCharacter()); // FIXME:
Security checks!
+ // FIXME: Security checks!
+ Buffer[Stack[STACK_COUNTER]] = LOBYTE(BiosGetCharacter());
/* Stop if the BOP needs to be repeated */
- if (EmulatorGetFlag(EMULATOR_FLAG_CF)) break;
+ if (getCF()) break;
/* Increment the counter */
Stack[STACK_COUNTER]++;
}
- if (Stack[STACK_COUNTER] < Count) ErrorCode = ERROR_NOT_READY;
- else BytesRead = Count;
+ if (Stack[STACK_COUNTER] < Count)
+ ErrorCode = ERROR_NOT_READY;
+ else
+ BytesRead = Count;
}
else
{
@@ -1788,7 +2012,7 @@
ErrorCode = DosReadFile(Handle, Buffer, Count, &BytesRead);
}
- if (ErrorCode == 0)
+ if (ErrorCode == ERROR_SUCCESS)
{
Stack[STACK_FLAGS] &= ~EMULATOR_FLAG_CF;
setAX(BytesRead);
@@ -1801,7 +2025,7 @@
break;
}
- /* Write File */
+ /* Write to File or Device */
case 0x40:
{
WORD BytesWritten = 0;
@@ -1810,7 +2034,7 @@
getCX(),
&BytesWritten);
- if (ErrorCode == 0)
+ if (ErrorCode == ERROR_SUCCESS)
{
Stack[STACK_FLAGS] &= ~EMULATOR_FLAG_CF;
setAX(BytesWritten);
@@ -1833,6 +2057,11 @@
if (DeleteFileA(FileName))
{
Stack[STACK_FLAGS] &= ~EMULATOR_FLAG_CF;
+ /*
+ * See Ralf Brown:
http://www.ctyme.com/intr/rb-2797.htm
+ * "AX destroyed (DOS 3.3) AL seems to be drive of deleted
file."
+ */
+ setAL(FileName[0] - 'A');
}
else
{
@@ -1852,7 +2081,7 @@
getAL(),
&NewLocation);
- if (ErrorCode == 0)
+ if (ErrorCode == ERROR_SUCCESS)
{
Stack[STACK_FLAGS] &= ~EMULATOR_FLAG_CF;
@@ -1885,12 +2114,13 @@
{
Stack[STACK_FLAGS] |= EMULATOR_FLAG_CF;
setAX(GetLastError());
- break;
}
-
- /* Return the attributes that DOS can understand */
- Stack[STACK_FLAGS] &= ~EMULATOR_FLAG_CF;
- setCL(LOBYTE(Attributes));
+ else
+ {
+ /* Return the attributes that DOS can understand */
+ Stack[STACK_FLAGS] &= ~EMULATOR_FLAG_CF;
+ setCX(Attributes & 0x00FF);
+ }
}
else if (getAL() == 0x01)
{
@@ -1977,6 +2207,42 @@
break;
}
+ /* Get Current Directory */
+ case 0x47:
+ {
+ BYTE DriveNumber = getDL();
+ String = (PCHAR)SEG_OFF_TO_PTR(getDS(), getSI());
+
+ /* Get the real drive number */
+ if (DriveNumber == 0)
+ {
+ DriveNumber = CurrentDrive;
+ }
+ else
+ {
+ /* Decrement DriveNumber since it was 1-based */
+ DriveNumber--;
+ }
+
+ if (DriveNumber <= LastDrive - 'A')
+ {
+ /*
+ * Copy the current directory into the target buffer.
+ * It doesn't contain the drive letter and the backslash.
+ */
+ strncpy(String, CurrentDirectories[DriveNumber], DOS_DIR_LENGTH);
+ Stack[STACK_FLAGS] &= ~EMULATOR_FLAG_CF;
+ setAX(0x0100); // Undocumented, see Ralf Brown:
http://www.ctyme.com/intr/rb-2933.htm
+ }
+ else
+ {
+ Stack[STACK_FLAGS] |= EMULATOR_FLAG_CF;
+ setAX(ERROR_INVALID_DRIVE);
+ }
+
+ break;
+ }
+
/* Allocate Memory */
case 0x48:
{
@@ -2040,7 +2306,28 @@
break;
}
- /* Get Current Process */
+ /* Get Return Code (ERRORLEVEL) */
+ case 0x4D:
+ {
+ /*
+ * According to Ralf Brown:
http://www.ctyme.com/intr/rb-2976.htm
+ * DosErrorLevel is cleared after being read by this function.
+ */
+ Stack[STACK_FLAGS] &= ~EMULATOR_FLAG_CF;
+ setAX(DosErrorLevel);
+ DosErrorLevel = 0x0000; // Clear it
+ break;
+ }
+
+ /* Internal - Set Current Process ID (Set PSP Address) */
+ case 0x50:
+ {
+ // FIXME: Is it really what it's done ??
+ CurrentPsp = getBX();
+ break;
+ }
+
+ /* Get Current Process ID (Get PSP Address) */
case 0x51:
{
setBX(CurrentPsp);
@@ -2221,7 +2508,7 @@
/* Set the drive */
CurrentDrive = DosDirectory[0] - 'A';
- /* Get the path */
+ /* Get the directory part of the path */
Path = strchr(DosDirectory, '\\');
if (Path != NULL)
{
@@ -2230,7 +2517,10 @@
}
/* Set the directory */
- if (Path != NULL) strcpy(CurrentDirectories[CurrentDrive], Path);
+ if (Path != NULL)
+ {
+ strncpy(CurrentDirectories[CurrentDrive], Path, DOS_DIR_LENGTH);
+ }
/* Read CONFIG.SYS */
Stream = _wfopen(DOS_CONFIG_PATH, L"r");
Modified: branches/ntvdm/subsystems/ntvdm/dos.h
URL:
http://svn.reactos.org/svn/reactos/branches/ntvdm/subsystems/ntvdm/dos.h?re…
==============================================================================
--- branches/ntvdm/subsystems/ntvdm/dos.h [iso-8859-1] (original)
+++ branches/ntvdm/subsystems/ntvdm/dos.h [iso-8859-1] Tue Oct 29 01:55:54 2013
@@ -102,7 +102,8 @@
typedef struct _DOS_INPUT_BUFFER
{
- BYTE MaxLength, Length;
+ BYTE MaxLength;
+ BYTE Length;
CHAR Buffer[ANYSIZE_ARRAY];
} DOS_INPUT_BUFFER, *PDOS_INPUT_BUFFER;