[NTVDM]
authorAleksandar Andrejevic <aandrejevic@reactos.org>
Sat, 2 May 2015 18:51:03 +0000 (18:51 +0000)
committerAleksandar Andrejevic <aandrejevic@reactos.org>
Sat, 2 May 2015 18:51:03 +0000 (18:51 +0000)
Save/restore the processor state when executing/terminating nested tasks.

svn path=/trunk/; revision=67513

reactos/subsystems/mvdm/ntvdm/dos/dos32krnl/process.c
reactos/subsystems/mvdm/ntvdm/dos/dos32krnl/process.h

index 75b975a..76f0f6d 100644 (file)
@@ -46,6 +46,56 @@ static inline VOID DosSetPspCommandLine(WORD Segment, LPCSTR CommandLine)
     RtlCopyMemory(PspBlock->CommandLine, CommandLine, DOS_CMDLINE_LENGTH);
 }
 
+static inline VOID DosSaveState(VOID)
+{
+    PDOS_REGISTER_STATE State;
+    WORD StackPointer = getSP();
+
+    /* Allocate stack space for the registers */
+    StackPointer -= sizeof(DOS_REGISTER_STATE);
+    State = SEG_OFF_TO_PTR(getSS(), StackPointer);
+
+    /* Save */
+    State->EAX = getEAX();
+    State->ECX = getECX();
+    State->EDX = getEDX();
+    State->EBX = getEBX();
+    State->ESP = getESP();
+    State->EBP = getEBP();
+    State->ESI = getESI();
+    State->EDI = getEDI();
+    State->DS = getDS();
+    State->ES = getES();
+    State->FS = getFS();
+    State->GS = getGS();
+    State->Flags = getEFLAGS();
+}
+
+static inline VOID DosRestoreState(VOID)
+{
+    PDOS_REGISTER_STATE State;
+    WORD StackPointer = getSP();
+
+    /* SS:SP points to the stack on the last entry to INT 21h */
+    StackPointer -= (STACK_FLAGS + 1) * 2;      /* Interrupt parameters */
+    StackPointer -= sizeof(DOS_REGISTER_STATE); /* Pushed state structure */
+    State = SEG_OFF_TO_PTR(getSS(), StackPointer);
+
+    /* Restore */
+    setEAX(State->EAX);
+    setECX(State->ECX);
+    setEDX(State->EDX);
+    setEBX(State->EBX);
+    setEBP(State->EBP);
+    setESI(State->ESI);
+    setEDI(State->EDI);
+    setDS(State->DS);
+    setES(State->ES);
+    setFS(State->FS);
+    setGS(State->GS);
+    setEFLAGS(State->Flags);
+}
+
 static WORD DosCopyEnvironmentBlock(LPCSTR Environment OPTIONAL,
                                     LPCSTR ProgramName)
 {
@@ -432,6 +482,9 @@ DWORD DosLoadExecutable(IN DOS_EXEC_TYPE LoadType,
 
         if (LoadType == DOS_LOAD_AND_EXECUTE)
         {
+            /* Save the program state */
+            if (CurrentPsp != SYSTEM_PSP) DosSaveState();
+
             /* Set the initial segment registers */
             setDS(Segment);
             setES(Segment);
@@ -750,6 +803,9 @@ VOID DosTerminateProcess(WORD Psp, BYTE ReturnCode, WORD KeepResident)
     PDOS_MCB CurrentMcb;
     LPDWORD IntVecTable = (LPDWORD)((ULONG_PTR)BaseAddress);
     PDOS_PSP PspBlock = SEGMENT_TO_PSP(Psp);
+#ifndef STANDALONE
+    VDM_COMMAND_INFO CommandInfo;
+#endif
 
     DPRINT("DosTerminateProcess: Psp 0x%04X, ReturnCode 0x%02X, KeepResident 0x%04X\n",
            Psp,
@@ -818,29 +874,25 @@ Done:
         {
             ResetEvent(VdmTaskEvent);
             CpuUnsimulate();
+            return;
         }
     }
 
 #ifndef STANDALONE
-    // FIXME: This is probably not the best way to do it
-    /* Check if this was a nested DOS task */
-    if (CurrentPsp != SYSTEM_PSP)
-    {
-        VDM_COMMAND_INFO CommandInfo;
 
-        /* Decrement the re-entry count */
-        CommandInfo.TaskId = SessionId;
-        CommandInfo.VDMState = VDM_DEC_REENTER_COUNT;
-        GetNextVDMCommand(&CommandInfo);
+    /* Decrement the re-entry count */
+    CommandInfo.TaskId = SessionId;
+    CommandInfo.VDMState = VDM_DEC_REENTER_COUNT;
+    GetNextVDMCommand(&CommandInfo);
 
-        /* Clear the structure */
-        RtlZeroMemory(&CommandInfo, sizeof(CommandInfo));
+    /* Clear the structure */
+    RtlZeroMemory(&CommandInfo, sizeof(CommandInfo));
+
+    /* Update the VDM state of the task */
+    CommandInfo.TaskId = SessionId;
+    CommandInfo.VDMState = VDM_FLAG_DONT_WAIT;
+    GetNextVDMCommand(&CommandInfo);
 
-        /* Update the VDM state of the task */
-        CommandInfo.TaskId = SessionId;
-        CommandInfo.VDMState = VDM_FLAG_DONT_WAIT;
-        GetNextVDMCommand(&CommandInfo);
-    }
 #endif
 
     /* Save the return code - Normal termination */
@@ -850,6 +902,9 @@ Done:
     setSS(HIWORD(SEGMENT_TO_PSP(CurrentPsp)->LastStack));
     setSP(LOWORD(SEGMENT_TO_PSP(CurrentPsp)->LastStack));
 
+    /* Restore the program state */
+    DosRestoreState();
+
     /* Return control to the parent process */
     CpuExecute(HIWORD(PspBlock->TerminateAddress),
                LOWORD(PspBlock->TerminateAddress));
index a9f5e7d..42744dc 100644 (file)
@@ -72,6 +72,13 @@ typedef struct _DOS_EXEC_PARAM_BLOCK
     };
 } DOS_EXEC_PARAM_BLOCK, *PDOS_EXEC_PARAM_BLOCK;
 
+typedef struct _DOS_REGISTER_STATE
+{
+    DWORD Flags;
+    WORD GS, FS, ES, DS;
+    DWORD EDI, ESI, EBP, ESP, EBX, EDX, ECX, EAX;
+} DOS_REGISTER_STATE, *PDOS_REGISTER_STATE;
+
 #pragma pack(pop)
 
 /* VARIABLES ******************************************************************/