[NTVDM]
authorHermès Bélusca-Maïto <hermes.belusca-maito@reactos.org>
Sat, 18 Jul 2015 19:45:37 +0000 (19:45 +0000)
committerHermès Bélusca-Maïto <hermes.belusca-maito@reactos.org>
Sat, 18 Jul 2015 19:45:37 +0000 (19:45 +0000)
- Move some #defines into their correct headers.
- Fix some DPRINTs.
- Add missing DOS SYSVars values (memory-related), confirmed by DOS undocumented & FreeDOS.
- Implement INT 21h, AX=5700h and 5701h "Get/Set File last-written date & time".
- Implement INT 2Fh, AH=13h "Set Disk Interrupt Handler" chain support, which is an obscure functionality (to make story short: allows inserting disk filter drivers): see the comments inside the code (dos.c/dos.h) for more information.

svn path=/trunk/; revision=68418

reactos/subsystems/mvdm/ntvdm/dos/dos32krnl/dos.c
reactos/subsystems/mvdm/ntvdm/dos/dos32krnl/dos.h
reactos/subsystems/mvdm/ntvdm/dos/dos32krnl/emsdrv.h
reactos/subsystems/mvdm/ntvdm/dos/dos32krnl/memory.h

index efa1ea6..26d3c5b 100644 (file)
@@ -785,10 +785,10 @@ VOID WINAPI DosInt21h(LPWORD Stack)
                     break;
                 }
 
-                default:
+                default: // goto Default;
                 {
-                    DPRINT1("INT 21h, AH = 33h, subfunction AL = %Xh NOT IMPLEMENTED\n",
-                            getAL());
+                    DPRINT1("INT 21h, AH = %02Xh, subfunction AL = %02Xh NOT IMPLEMENTED\n",
+                            getAH(), getAL());
                 }
             }
 
@@ -1512,6 +1512,110 @@ VOID WINAPI DosInt21h(LPWORD Stack)
             break;
         }
 
+        /* File Attributes */
+        case 0x57:
+        {
+            switch (getAL())
+            {
+                /* Get File's last-written Date and Time */
+                case 0x00:
+                {
+                    PDOS_FILE_DESCRIPTOR Descriptor = DosGetHandleFileDescriptor(getBX());
+                    FILETIME LastWriteTime;
+                    WORD FileDate, FileTime;
+
+                    if (Descriptor == NULL)
+                    {
+                        /* Invalid handle */
+                        Stack[STACK_FLAGS] |= EMULATOR_FLAG_CF;
+                        // Sda->LastErrorCode = ERROR_INVALID_HANDLE;
+                        setAX(ERROR_INVALID_HANDLE);
+                        break;
+                    }
+
+                    if (Descriptor->DeviceInfo & FILE_INFO_DEVICE)
+                    {
+                        /* Invalid for devices */
+                        Stack[STACK_FLAGS] |= EMULATOR_FLAG_CF;
+                        // setAX(ERROR_INVALID_FUNCTION);
+                        setAX(ERROR_INVALID_HANDLE);
+                        break;
+                    }
+
+                    /*
+                     * Retrieve the last-written Win32 date and time,
+                     * and convert it to DOS format.
+                     */
+                    if (!GetFileTime(Descriptor->Win32Handle,
+                                     NULL, NULL, &LastWriteTime) ||
+                        !FileTimeToDosDateTime(&LastWriteTime,
+                                               &FileDate, &FileTime))
+                    {
+                        Stack[STACK_FLAGS] |= EMULATOR_FLAG_CF;
+                        setAX(GetLastError());
+                        break;
+                    }
+
+                    Stack[STACK_FLAGS] &= ~EMULATOR_FLAG_CF;
+                    setCX(FileTime);
+                    setDX(FileDate);
+                    break;
+                }
+
+                /* Set File's last-written Date and Time */
+                case 0x01:
+                {
+                    PDOS_FILE_DESCRIPTOR Descriptor = DosGetHandleFileDescriptor(getBX());
+                    FILETIME LastWriteTime;
+                    WORD FileDate = getDX();
+                    WORD FileTime = getCX();
+
+                    if (Descriptor == NULL)
+                    {
+                        /* Invalid handle */
+                        Stack[STACK_FLAGS] |= EMULATOR_FLAG_CF;
+                        // Sda->LastErrorCode = ERROR_INVALID_HANDLE;
+                        setAX(ERROR_INVALID_HANDLE);
+                        break;
+                    }
+
+                    if (Descriptor->DeviceInfo & FILE_INFO_DEVICE)
+                    {
+                        /* Invalid for devices */
+                        Stack[STACK_FLAGS] |= EMULATOR_FLAG_CF;
+                        // setAX(ERROR_INVALID_FUNCTION);
+                        setAX(ERROR_INVALID_HANDLE);
+                        break;
+                    }
+
+                    /*
+                     * Convert the new last-written DOS date and time
+                     * to Win32 format and set it.
+                     */
+                    if (!DosDateTimeToFileTime(FileDate, FileTime,
+                                               &LastWriteTime) ||
+                        !SetFileTime(Descriptor->Win32Handle,
+                                     NULL, NULL, &LastWriteTime))
+                    {
+                        Stack[STACK_FLAGS] |= EMULATOR_FLAG_CF;
+                        setAX(GetLastError());
+                        break;
+                    }
+
+                    Stack[STACK_FLAGS] &= ~EMULATOR_FLAG_CF;
+                    break;
+                }
+
+                default: // goto Default;
+                {
+                    DPRINT1("INT 21h, AH = %02Xh, subfunction AL = %02Xh NOT IMPLEMENTED\n",
+                            getAH(), getAL());
+                }
+            }
+
+            break;
+        }
+
         /* Get/Set Memory Management Options */
         case 0x58:
         {
@@ -1748,10 +1852,10 @@ VOID WINAPI DosInt21h(LPWORD Stack)
                     break;
                 }
 
-                default:
+                default: // goto Default;
                 {
-                    DPRINT1("INT 21h, AH = 5Dh, subfunction AL = %Xh NOT IMPLEMENTED\n",
-                            getAL());
+                    DPRINT1("INT 21h, AH = %02Xh, subfunction AL = %02Xh NOT IMPLEMENTED\n",
+                            getAH(), getAL());
                 }
             }
 
@@ -1833,10 +1937,10 @@ VOID WINAPI DosInt21h(LPWORD Stack)
                     break;
                 }
 
-                default:
+                default: // goto Default;
                 {
-                    DPRINT1("INT 21h, AH = 65h, subfunction AL = %Xh NOT IMPLEMENTED\n",
-                            getAL());
+                    DPRINT1("INT 21h, AH = %02Xh, subfunction AL = %02Xh NOT IMPLEMENTED\n",
+                            getAH(), getAL());
                 }
             }
 
@@ -1926,9 +2030,9 @@ VOID WINAPI DosInt21h(LPWORD Stack)
         }
 
         /* Unsupported */
-        default:
+        default: // Default:
         {
-            DPRINT1("DOS Function INT 0x21, AH = %xh, AL = %xh NOT IMPLEMENTED!\n",
+            DPRINT1("DOS Function INT 21h, AH = %02Xh, AL = %02Xh NOT IMPLEMENTED!\n",
                     getAH(), getAL());
 
             setAL(0); // Some functions expect AL to be 0 when it's not supported.
@@ -2091,6 +2195,28 @@ VOID WINAPI DosInt2Fh(LPWORD Stack)
             break;
         }
 
+        /* Set Disk Interrupt Handler */
+        case 0x13:
+        {
+            /* Save the old values of PrevInt13 and RomBiosInt13 */
+            ULONG OldInt13     = DosData->PrevInt13;
+            ULONG OldBiosInt13 = DosData->RomBiosInt13;
+
+            /* Set PrevInt13 and RomBiosInt13 to their new values */
+            DosData->PrevInt13    = MAKELONG(getDX(), getDS());
+            DosData->RomBiosInt13 = MAKELONG(getBX(), getES());
+
+            /* Return in DS:DX the old value of PrevInt13 */
+            setDS(HIWORD(OldInt13));
+            setDX(LOWORD(OldInt13));
+
+            /* Return in DS:DX the old value of RomBiosInt13 */
+            setES(HIWORD(OldBiosInt13));
+            setBX(LOWORD(OldBiosInt13));
+
+            break;
+        }
+
         /* Mostly Windows 2.x/3.x/9x support */
         case 0x16:
         {
@@ -2127,7 +2253,7 @@ VOID WINAPI DosInt2Fh(LPWORD Stack)
                 }
 
                 default:
-                    DPRINT1("Unknown DOS XMS Function: INT 0x2F, AH = 43h, AL = %xh\n", getAL());
+                    DPRINT1("Unknown DOS XMS Function: INT 2Fh, AH = 43h, AL = %02Xh\n", getAL());
                     break;
             }
 
@@ -2136,7 +2262,7 @@ VOID WINAPI DosInt2Fh(LPWORD Stack)
 
         default: Default:
         {
-            DPRINT1("DOS Internal System Function INT 0x2F, AH = %xh, AL = %xh NOT IMPLEMENTED!\n",
+            DPRINT1("DOS Internal System Function INT 2Fh, AH = %02Xh, AL = %02Xh NOT IMPLEMENTED!\n",
                     getAH(), getAL());
             Stack[STACK_FLAGS] |= EMULATOR_FLAG_CF;
         }
@@ -2315,12 +2441,37 @@ BOOLEAN DosKRNLInitialize(VOID)
     /* Unimplemented DOS interrupts */
     RegisterDosInt32(0x2A, DosInt2Ah); // DOS Critical Sections / Network
 //  RegisterDosInt32(0x2E, NULL); // COMMAND.COM "Reload Transient"
+//  COMMAND.COM adds support for INT 2Fh, AX=AE00h and AE01h "Installable Command - Installation Check & Execute"
+//  COMMAND.COM adds support for INT 2Fh, AX=5500h "COMMAND.COM Interface"
 
     /* Reserved DOS interrupts */
     RegisterDosInt32(0x2B, NULL);
     RegisterDosInt32(0x2C, NULL);
     RegisterDosInt32(0x2D, NULL);
 
+    /*
+     * Initialize the INT 13h (BIOS Disk Services) handler chain support.
+     *
+     * The INT 13h handler chain is some functionality that allows DOS
+     * to insert disk filter drivers in between the (hooked) INT 13h handler
+     * and its original handler.
+     * Typically, those are:
+     * - filter for detecting disk changes (for floppy disks),
+     * - filter for tracking formatting calls and correcting DMA boundary errors,
+     * - a possible filter to work around a bug in a particular version of PC-AT's
+     *   IBM's ROM BIOS (on systems with model byte FCh and BIOS date "01/10/84" only)
+     * (see http://www.ctyme.com/intr/rb-4453.htm for more details).
+     *
+     * This functionality is known to be used by some legitimate programs,
+     * by Windows 3.x, as well as some illegitimate ones (aka. virii).
+     *
+     * See extra information about this support in dos.h
+     */
+    // FIXME: Should be done by the DOS BIOS
+    DosData->RomBiosInt13 = ((PULONG)BaseAddress)[0x13];
+    DosData->PrevInt13    = DosData->RomBiosInt13;
+//  RegisterDosInt32(0x13, DosInt13h); // Unused at the moment!
+
     /* Initialize country data */
     DosCountryInitialize();
 
index 964b6b6..b6ce853 100644 (file)
@@ -26,8 +26,7 @@
 
 #define DOS_CONFIG_PATH L"%SystemRoot%\\system32\\CONFIG.NT"
 #define DOS_COMMAND_INTERPRETER L"%SystemRoot%\\system32\\COMMAND.COM /k %SystemRoot%\\system32\\AUTOEXEC.NT"
-#define FIRST_MCB_SEGMENT 0x1000
-#define USER_MEMORY_SIZE (0x9FFE - FIRST_MCB_SEGMENT)
+
 #define SYSTEM_PSP 0x08
 #define SYSTEM_ENV_BLOCK 0x800
 #define DOS_CODE_SEGMENT 0x70
 #define DOS_ERROR_HANDLE    2
 
 #define DOS_SFT_SIZE 255
-#define UMB_START_SEGMENT 0xC000
-#define UMB_END_SEGMENT 0xDFFF
-#define DOS_ALLOC_HIGH 0x40
-#define DOS_ALLOC_HIGH_LOW 0x80
 #define DOS_DIR_LENGTH 64
 #define NUM_DRIVES ('Z' - 'A' + 1)
 #define DOS_CHAR_ATTRIBUTE 0x07
 
-/* 16 MB of EMS memory */
-#define EMS_TOTAL_PAGES 1024
-
 #pragma pack(push, 1)
 
 typedef struct _DOS_FCB
@@ -99,6 +91,11 @@ typedef struct _DOS_SYSVARS
     BYTE BootDrive;                             // 0x43
     BYTE UseDwordMoves;                         // 0x44
     WORD ExtMemSize;                            // 0x45
+    BYTE Reserved4[0x1C];                       // 0x47
+    BYTE ChainUMB;                              // 0x63 - 0/1: UMB chain (un)linked to MCB chain
+    WORD Reserved5;                             // 0x64
+    WORD UMBChainStart;                         // 0x66 - Segment of the first UMB MCB
+    WORD MemAllocScanStart;                     // 0x68 - Segment where allocation scan starts
 } DOS_SYSVARS, *PDOS_SYSVARS;
 
 typedef struct _DOS_CLOCK_TRANSFER_RECORD
@@ -235,6 +232,33 @@ typedef struct _DOS_SDA
 
 typedef struct _DOS_DATA
 {
+/*
+ * INT 13h (BIOS Disk Services) handler chain support.
+ *
+ * RomBiosInt13: The original INT 13h vector (normally from ROM BIOS).
+ * PrevInt13   : The previous INT 13h vector in the handler chain (initially
+ *               initialized with the RomBiosInt13 value; each time some
+ *               program calls INT 2Fh, AH=13h, PrevInt13 is updated).
+ *
+ * DOS hooks INT 13h with its own code, then (in normal circumstances) calls
+ * PrevInt13, so that when a program calls INT 13h, the DOS hook is first called,
+ * followed by the previous INT 13h (be it the original or some other hooked one).
+ * DOS may call PrevInt13 directly in some internal operations too.
+ * RomBiosInt13 is intended to be the original INT 13h vector that existed
+ * before DOS was loaded. A particular version of PC-AT's IBM's ROM BIOS
+ * (on systems with model byte FCh and BIOS date "01/10/84" only, see
+ * http://www.ctyme.com/intr/rb-4453.htm for more details) had a bug on disk
+ * reads so that it was patched by DOS, and therefore PrevInt13 was the fixed
+ * INT 13 interrupt (for the other cases, a direct call to RomBiosInt13 is done).
+ *
+ * NOTE: For compatibility with some programs (including virii), PrevInt13 should
+ * be at 0070:00B4, see for more details:
+ * http://repo.hackerzvoice.net/depot_madchat/vxdevl/vdat/tuvd0001.htm
+ * http://vxheaven.org/lib/vsm01.html
+ */
+    DWORD RomBiosInt13;
+    DWORD PrevInt13; // FIXME: Put it at 0070:00B4
+
     DOS_SYSVARS SysVars;
     BYTE NullDriverRoutine[7];
     WORD DosVersion; // DOS version to report to programs (can be different from the true one)
index 0bfd521..b02b994 100644 (file)
@@ -19,6 +19,9 @@
 #define EMS_PAGE_SIZE       (1 << EMS_PAGE_BITS)
 #define EMS_PHYSICAL_PAGES  4
 
+/* 16 MB of EMS memory */
+#define EMS_TOTAL_PAGES     1024
+
 #define EMS_STATUS_OK                   0x00
 #define EMS_STATUS_INTERNAL_ERROR       0x80
 #define EMS_STATUS_INVALID_HANDLE       0x83
index 76ac6e2..401cafe 100644 (file)
 
 #define SEGMENT_TO_MCB(seg) ((PDOS_MCB)SEG_OFF_TO_PTR((seg), 0))
 
+#define FIRST_MCB_SEGMENT   0x1000
+#define USER_MEMORY_SIZE   (0x9FFE - FIRST_MCB_SEGMENT)
+
+#define UMB_START_SEGMENT   0xC000
+#define UMB_END_SEGMENT     0xDFFF
+
+#define DOS_ALLOC_HIGH      0x40
+#define DOS_ALLOC_HIGH_LOW  0x80
+
 enum DOS_ALLOC_STRATEGY
 {
     DOS_ALLOC_FIRST_FIT,