[NTVDM]
authorAleksandar Andrejevic <aandrejevic@reactos.org>
Tue, 2 Jul 2013 02:08:30 +0000 (02:08 +0000)
committerAleksandar Andrejevic <aandrejevic@reactos.org>
Tue, 2 Jul 2013 02:08:30 +0000 (02:08 +0000)
Fix several bugs:
The file was not entirely read due to an integer overflow.
The second WORD of the Program Segment Prefix (PSP) is not the number of allocated
paragraphs, but the segment of the last paragraph.
Fix the order of registers (SI and DI were mixed up with SP and BP).
Implement interrupt 0x11.
Implement redirection for reading/writing characters.

svn path=/branches/ntvdm/; revision=59409

subsystems/ntvdm/bios.c
subsystems/ntvdm/bios.h
subsystems/ntvdm/dos.c
subsystems/ntvdm/dos.h
subsystems/ntvdm/emulator.c
subsystems/ntvdm/emulator.h

index 9208495..5a796cf 100644 (file)
@@ -445,6 +445,12 @@ VOID BiosTimeService()
     }
 }
 
     }
 }
 
+VOID BiosEquipmentService()
+{
+    /* Return the equipment list */
+    EmulatorSetRegister(EMULATOR_REG_AX, BIOS_EQUIPMENT_LIST);
+}
+
 VOID BiosHandleIrq(BYTE IrqNumber)
 {
     switch (IrqNumber)
 VOID BiosHandleIrq(BYTE IrqNumber)
 {
     switch (IrqNumber)
index 548e40f..54fbdf6 100644 (file)
 #define BIOS_PIC_SLAVE_INT 0x70
 #define BIOS_SEGMENT 0xF000
 #define BIOS_VIDEO_INTERRUPT 0x10
 #define BIOS_PIC_SLAVE_INT 0x70
 #define BIOS_SEGMENT 0xF000
 #define BIOS_VIDEO_INTERRUPT 0x10
+#define BIOS_EQUIPMENT_INTERRUPT 0x11
 #define BIOS_KBD_INTERRUPT 0x16
 #define BIOS_TIME_INTERRUPT 0x1A
 #define CONSOLE_FONT_HEIGHT 8
 #define BIOS_KBD_BUFFER_SIZE 256
 #define BIOS_KBD_INTERRUPT 0x16
 #define BIOS_TIME_INTERRUPT 0x1A
 #define CONSOLE_FONT_HEIGHT 8
 #define BIOS_KBD_BUFFER_SIZE 256
+#define BIOS_EQUIPMENT_LIST 0x3C // HACK: Disable FPU for now
 
 /* FUNCTIONS ******************************************************************/
 
 
 /* FUNCTIONS ******************************************************************/
 
@@ -36,6 +38,7 @@ VOID BiosUpdateVideoMemory(ULONG StartAddress, ULONG EndAddress);
 WORD BiosPeekCharacter();
 WORD BiosGetCharacter();
 VOID BiosVideoService();
 WORD BiosPeekCharacter();
 WORD BiosGetCharacter();
 VOID BiosVideoService();
+VOID BiosEquipmentService();
 VOID BiosKeyboardService();
 VOID BiosTimeService();
 VOID BiosHandleIrq(BYTE IrqNumber);
 VOID BiosKeyboardService();
 VOID BiosTimeService();
 VOID BiosHandleIrq(BYTE IrqNumber);
index a17512a..71ec4d7 100644 (file)
@@ -79,7 +79,10 @@ static WORD DosCopyEnvironmentBlock(WORD SourceSegment)
 
         /* Advance to the next string */
         Ptr += strlen(Ptr) + 1;
 
         /* Advance to the next string */
         Ptr += strlen(Ptr) + 1;
-        DestBuffer += strlen(Ptr) + 1;
+        DestBuffer += strlen(Ptr);
+
+        /* Put a zero after the string */
+        *(DestBuffer++) = 0;
     }
 
     /* Set the final zero */
     }
 
     /* Set the final zero */
@@ -590,8 +593,8 @@ VOID DosInitializePsp(WORD PspSegment, LPCSTR CommandLine, WORD ProgramSize, WOR
     PspBlock->Exit[0] = 0xCD; // int 0x20
     PspBlock->Exit[1] = 0x20;
 
     PspBlock->Exit[0] = 0xCD; // int 0x20
     PspBlock->Exit[1] = 0x20;
 
-    /* Set the program size */
-    PspBlock->MemSize = ProgramSize;
+    /* Set the number of the last paragraph */
+    PspBlock->LastParagraph = PspSegment + ProgramSize - 1;
 
     /* Save the interrupt vectors */
     PspBlock->TerminateAddress = IntVecTable[0x22];
 
     /* Save the interrupt vectors */
     PspBlock->TerminateAddress = IntVecTable[0x22];
@@ -633,7 +636,8 @@ BOOLEAN DosCreateProcess(LPCSTR CommandLine, WORD EnvBlock)
     LPSTR ProgramFilePath, Parameters[128];
     CHAR CommandLineCopy[128];
     INT ParamCount = 0;
     LPSTR ProgramFilePath, Parameters[128];
     CHAR CommandLineCopy[128];
     INT ParamCount = 0;
-    WORD i, Segment = 0, FileSize, ExeSize;
+    DWORD Segment = 0;
+    DWORD i, FileSize, ExeSize;
     PIMAGE_DOS_HEADER Header;
     PDWORD RelocationTable;
     PWORD RelocWord;
     PIMAGE_DOS_HEADER Header;
     PDWORD RelocationTable;
     PWORD RelocWord;
@@ -700,13 +704,22 @@ BOOLEAN DosCreateProcess(LPCSTR CommandLine, WORD EnvBlock)
         // TODO: Verify checksum and executable!
 
         /* Get the base size of the file, in paragraphs (rounded up) */
         // TODO: Verify checksum and executable!
 
         /* Get the base size of the file, in paragraphs (rounded up) */
-        ExeSize = (((Header->e_cp - 1) << 8) + Header->e_cblp + 0x0F) >> 4;
+        ExeSize = (((Header->e_cp - 1) * 512) + Header->e_cblp + 0x0F) >> 4;
+
+        /* Add the PSP size, in paragraphs */
+        ExeSize += sizeof(DOS_PSP) >> 4;
+
+        /* Add the maximum size that should be allocated */
+        ExeSize += Header->e_maxalloc;
 
 
-        /* Loop from the maximum to the minimum number of extra paragraphs */
-        for (i = Header->e_maxalloc; i >= Header->e_minalloc; i--)
+        /* Make sure it does not pass 0xFFFF */
+        if (ExeSize > 0xFFFF) ExeSize = 0xFFFF;
+
+        /* Reduce the size one by one until the allocation is successful */
+        for (i = Header->e_maxalloc; i >= Header->e_minalloc; i--, ExeSize--)
         {
             /* Try to allocate that much memory */
         {
             /* Try to allocate that much memory */
-            Segment = DosAllocateMemory(ExeSize + (sizeof(DOS_PSP) >> 4) + i, NULL);
+            Segment = DosAllocateMemory(ExeSize, NULL);
             if (Segment != 0) break;
         }
 
             if (Segment != 0) break;
         }
 
@@ -715,7 +728,8 @@ BOOLEAN DosCreateProcess(LPCSTR CommandLine, WORD EnvBlock)
 
         /* Initialize the PSP */
         DosInitializePsp(Segment,
 
         /* Initialize the PSP */
         DosInitializePsp(Segment,
-                         CommandLine, ExeSize + (sizeof(DOS_PSP) >> 4) + i,
+                         CommandLine,
+                         ExeSize,
                          EnvBlock);
 
         /* The process owns its own memory */
                          EnvBlock);
 
         /* The process owns its own memory */
@@ -865,21 +879,21 @@ Done:
 
 CHAR DosReadCharacter()
 {
 
 CHAR DosReadCharacter()
 {
-    // TODO: STDIN can be redirected under DOS 2.0+
-    CHAR Character = 0;
+    CHAR Character = '\0';
+    WORD BytesRead;
 
 
-    /* A zero value for the character indicates a special key */
-    do Character = BiosGetCharacter();
-    while (!Character);
+    /* Use the file reading function */
+    DosReadFile(DOS_INPUT_HANDLE, &Character, sizeof(CHAR), &BytesRead);
 
     return Character;
 }
 
 VOID DosPrintCharacter(CHAR Character)
 {
 
     return Character;
 }
 
 VOID DosPrintCharacter(CHAR Character)
 {
-    // TODO: STDOUT can be redirected under DOS 2.0+
-    if (Character == '\r') Character = '\n';
-    putchar(Character);
+    WORD BytesWritten;
+
+    /* Use the file writing function */
+    DosWriteFile(DOS_OUTPUT_HANDLE, &Character, sizeof(CHAR), &BytesWritten);
 }
 
 VOID DosInt20h(WORD CodeSegment)
 }
 
 VOID DosInt20h(WORD CodeSegment)
@@ -1382,7 +1396,7 @@ BOOLEAN DosInitialize()
 
     /* Initialize the MCB */
     Mcb->BlockType = 'Z';
 
     /* Initialize the MCB */
     Mcb->BlockType = 'Z';
-    Mcb->Size = (WORD)USER_MEMORY_SIZE;
+    Mcb->Size = USER_MEMORY_SIZE;
     Mcb->OwnerPsp = 0;
 
     /* Get the environment strings */
     Mcb->OwnerPsp = 0;
 
     /* Get the environment strings */
@@ -1428,8 +1442,10 @@ BOOLEAN DosInitialize()
 
         /* Move to the next string */
         SourcePtr += wcslen(SourcePtr) + 1;
 
         /* Move to the next string */
         SourcePtr += wcslen(SourcePtr) + 1;
-        DestPtr += strlen(AsciiString) + 1;
+        DestPtr += strlen(AsciiString);
+        *(DestPtr++) = 0;
     }
     }
+    *DestPtr = 0;
 
     /* Free the memory allocated for environment strings */
     FreeEnvironmentStringsW(Environment);
 
     /* Free the memory allocated for environment strings */
     FreeEnvironmentStringsW(Environment);
index b832c95..0c5f1be 100644 (file)
 #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 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 0x8FFFF
+#define USER_MEMORY_SIZE 0x8FFF
 #define SYSTEM_PSP 0x08
 #define SYSTEM_ENV_BLOCK 0x800
 #define INVALID_DOS_HANDLE 0xFFFF
 #define SYSTEM_PSP 0x08
 #define SYSTEM_ENV_BLOCK 0x800
 #define INVALID_DOS_HANDLE 0xFFFF
+#define DOS_INPUT_HANDLE 0
+#define DOS_OUTPUT_HANDLE 1
+#define DOS_ERROR_HANDLE 2
 #define DOS_SFT_SIZE 255
 #define SEGMENT_TO_MCB(seg) ((PDOS_MCB)((ULONG_PTR)BaseAddress + TO_LINEAR((seg), 0)))
 #define SEGMENT_TO_PSP(seg) ((PDOS_PSP)((ULONG_PTR)BaseAddress + TO_LINEAR((seg), 0)))
 #define DOS_SFT_SIZE 255
 #define SEGMENT_TO_MCB(seg) ((PDOS_MCB)((ULONG_PTR)BaseAddress + TO_LINEAR((seg), 0)))
 #define SEGMENT_TO_PSP(seg) ((PDOS_PSP)((ULONG_PTR)BaseAddress + TO_LINEAR((seg), 0)))
@@ -56,7 +59,7 @@ typedef struct _DOS_FCB
 typedef struct _DOS_PSP
 {
     BYTE Exit[2];
 typedef struct _DOS_PSP
 {
     BYTE Exit[2];
-    WORD MemSize;
+    WORD LastParagraph;
     BYTE Reserved0[6];
     DWORD TerminateAddress;
     DWORD BreakAddress;
     BYTE Reserved0[6];
     DWORD TerminateAddress;
     DWORD BreakAddress;
index 3f23d52..a502dda 100644 (file)
@@ -216,6 +216,12 @@ static VOID EmulatorSoftwareInt(PVOID Context, BYTE Number)
                 BiosVideoService();
                 break;
             }
                 BiosVideoService();
                 break;
             }
+            case BIOS_EQUIPMENT_INTERRUPT:
+            {
+                /* This is the BIOS "get equipment" command, call the BIOS */
+                BiosEquipmentService();
+                break;
+            }
             case BIOS_KBD_INTERRUPT:
             {
                 /* This is the keyboard BIOS interrupt, call the BIOS */
             case BIOS_KBD_INTERRUPT:
             {
                 /* This is the keyboard BIOS interrupt, call the BIOS */
@@ -267,7 +273,7 @@ static VOID EmulatorHardwareIntAck(PVOID Context, BYTE Number)
 BOOLEAN EmulatorInitialize()
 {
     /* Allocate memory for the 16-bit address space */
 BOOLEAN EmulatorInitialize()
 {
     /* Allocate memory for the 16-bit address space */
-    BaseAddress = HeapAlloc(GetProcessHeap(), 0, MAX_ADDRESS);
+    BaseAddress = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, MAX_ADDRESS);
     if (BaseAddress == NULL) return FALSE;
 
     /* Initialize the softx86 CPU emulator */
     if (BaseAddress == NULL) return FALSE;
 
     /* Initialize the softx86 CPU emulator */
index fc94305..b8eb9c1 100644 (file)
@@ -53,10 +53,10 @@ typedef enum
     EMULATOR_REG_CX,
     EMULATOR_REG_DX,
     EMULATOR_REG_BX,
     EMULATOR_REG_CX,
     EMULATOR_REG_DX,
     EMULATOR_REG_BX,
-    EMULATOR_REG_SI,
-    EMULATOR_REG_DI,
     EMULATOR_REG_SP,
     EMULATOR_REG_BP,
     EMULATOR_REG_SP,
     EMULATOR_REG_BP,
+    EMULATOR_REG_SI,
+    EMULATOR_REG_DI,
     EMULATOR_REG_ES,
     EMULATOR_REG_CS,
     EMULATOR_REG_SS,
     EMULATOR_REG_ES,
     EMULATOR_REG_CS,
     EMULATOR_REG_SS,