[NTOSKRNL]
authorAleksandar Andrejevic <aandrejevic@reactos.org>
Mon, 24 Jun 2013 01:59:09 +0000 (01:59 +0000)
committerAleksandar Andrejevic <aandrejevic@reactos.org>
Mon, 24 Jun 2013 01:59:09 +0000 (01:59 +0000)
Check for old-style MZ executable in PeFmtCreateSection.
[NTVDM]
Fix bugs.
Implement MZ executable loading.

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

ntoskrnl/mm/section.c
subsystems/ntvdm/dos.c
subsystems/ntvdm/emulator.c
subsystems/ntvdm/ntvdm.c
subsystems/ntvdm/ntvdm.h

index 42ccf97..ee925a1 100644 (file)
@@ -237,6 +237,10 @@ NTSTATUS NTAPI PeFmtCreateSection(IN CONST VOID * FileHeader,
     if(pidhDosHeader->e_magic != IMAGE_DOS_SIGNATURE)
         DIE(("No MZ signature found, e_magic is %hX\n", pidhDosHeader->e_magic));
 
+    /* check if this is an old MZ executable */
+    if(pidhDosHeader->e_lfarlc < 0x40)
+        DIE(("Old-style MZ executable found, e_lfarlc is %d\n", pidhDosHeader->e_lfarlc));
+
     /* not a Windows executable */
     if(pidhDosHeader->e_lfanew <= 0)
         DIE(("Not a Windows executable, e_lfanew is %d\n", pidhDosHeader->e_lfanew));
index 29b89ff..8e9290b 100644 (file)
@@ -320,7 +320,10 @@ BOOLEAN DosCreateProcess(LPCSTR CommandLine, WORD EnvBlock)
     LPSTR ProgramFilePath, Parameters[128];
     CHAR CommandLineCopy[128];
     INT ParamCount = 0;
-    WORD Segment, FileSize;
+    WORD i, Segment, FileSize, ExeSize;
+    PIMAGE_DOS_HEADER Header;
+    PDWORD RelocationTable;
+    PWORD RelocWord;
 
     /* Save a copy of the command line */
     strcpy(CommandLineCopy, CommandLine);
@@ -366,8 +369,64 @@ BOOLEAN DosCreateProcess(LPCSTR CommandLine, WORD EnvBlock)
     {
         /* EXE file */
 
-        // TODO: NOT IMPLEMENTED
-        DisplayMessage(L"EXE files are not yet supported!");
+        /* Get the MZ header */
+        Header = (PIMAGE_DOS_HEADER)Address;
+
+        // 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;
+
+        /* Loop from the maximum to the minimum number of extra paragraphs */
+        for (i = Header->e_maxalloc; i >= Header->e_minalloc; i--)
+        {
+            /* Try to allocate that much memory */
+            Segment = DosAllocateMemory(ExeSize + (sizeof(DOS_PSP) >> 4) + i);
+            if (Segment != 0) break;
+        }
+
+        /* Check if at least the lowest allocation was successful */
+        if (Segment == 0) goto Cleanup;
+
+        /* Initialize the PSP */
+        DosInitializePsp(Segment,
+                         CommandLine, ExeSize + (sizeof(DOS_PSP) >> 4) + i,
+                         EnvBlock);
+
+        /* Copy the program to Segment:0100 */
+        RtlCopyMemory((PVOID)((ULONG_PTR)BaseAddress
+                      + TO_LINEAR(Segment, 0x100)),
+                      Address + (Header->e_cparhdr << 4),
+                      FileSize - (Header->e_cparhdr << 4));
+
+        /* Get the relocation table */
+        RelocationTable = (PDWORD)(Address + Header->e_lfarlc);
+
+        /* Perform relocations */
+        for (i = 0; i < Header->e_crlc; i++)
+        {
+            /* Get a pointer to the word that needs to be patched */
+            RelocWord = (PWORD)((ULONG_PTR)BaseAddress
+                                + TO_LINEAR(Segment + HIWORD(RelocationTable[i]),
+                                            0x100 + LOWORD(RelocationTable[i])));
+
+            /* Add the number of the EXE segment to it */
+            *RelocWord += Segment + (sizeof(DOS_PSP) >> 4);
+        }
+
+        /* Set the initial segment registers */
+        EmulatorSetRegister(EMULATOR_REG_DS, Segment);
+        EmulatorSetRegister(EMULATOR_REG_ES, Segment);
+
+        /* Set the stack to the location from the header */
+        EmulatorSetStack(Segment + (sizeof(DOS_PSP) >> 4) + Header->e_ss,
+                         Header->e_sp);
+
+        /* Execute */
+        CurrentPsp = Segment;
+        EmulatorExecute(Segment + Header->e_cs, sizeof(DOS_PSP) + Header->e_ip);
+
+        Success = TRUE;
     }
     else
     {
index 2d09c58..265acd9 100644 (file)
@@ -254,13 +254,13 @@ VOID EmulatorInterrupt(BYTE Number)
 
 ULONG EmulatorGetRegister(ULONG Register)
 {
-    if (Register < EMULATOR_REG_CS)
+    if (Register < EMULATOR_REG_ES)
     {
         return EmulatorContext.state->general_reg[Register].val;
     }
     else
     {
-        return EmulatorContext.state->segment_reg[(Register >> 3) - 1].val;
+        return EmulatorContext.state->segment_reg[Register - EMULATOR_REG_ES].val;
     }
 }
 
@@ -272,7 +272,7 @@ VOID EmulatorSetRegister(ULONG Register, ULONG Value)
     }
     else
     {
-        EmulatorContext.state->segment_reg[(Register >> 3) - 1].val = Value;
+        EmulatorContext.state->segment_reg[Register - EMULATOR_REG_ES].val = Value;
     }
 }
 
index 429b5a1..f20457c 100644 (file)
@@ -42,6 +42,7 @@ BOOL WINAPI ConsoleCtrlHandler(DWORD ControlType)
         {
             /* Perform interrupt 0x23 */
             EmulatorInterrupt(0x23);
+            break;
         }
         default:
         {
@@ -124,9 +125,12 @@ INT wmain(INT argc, WCHAR *argv[])
         }
         
         /* Continue CPU emulation */
-        for (i = 0; i < STEPS_PER_CYCLE; i++) EmulatorStep();
+        for (i = 0; (i < STEPS_PER_CYCLE) && VdmRunning; i++)
+        {
+            EmulatorStep();
+            Cycles++;
+        }
         
-        Cycles += STEPS_PER_CYCLE;
         if ((CurrentTickCount - LastCyclePrintout) >= 1000)
         {
             DPRINT1("NTVDM: %d Instructions Per Second\n", Cycles);
index 896ce7a..28ea8b8 100644 (file)
@@ -102,12 +102,10 @@ typedef enum
     EMULATOR_REG_DI,
     EMULATOR_REG_SP,
     EMULATOR_REG_BP,
+    EMULATOR_REG_ES,
     EMULATOR_REG_CS,
     EMULATOR_REG_SS,
     EMULATOR_REG_DS,
-    EMULATOR_REG_ES,
-    EMULATOR_REG_FS,
-    EMULATOR_REG_GS
 } EMULATOR_REGISTER;
 
 #pragma pack(push, 1)