Author: aandrejevic
Date: Sat May  2 18:51:03 2015
New Revision: 67513
URL: 
http://svn.reactos.org/svn/reactos?rev=67513&view=rev
Log:
[NTVDM]
Save/restore the processor state when executing/terminating nested tasks.
Modified:
    trunk/reactos/subsystems/mvdm/ntvdm/dos/dos32krnl/process.c
    trunk/reactos/subsystems/mvdm/ntvdm/dos/dos32krnl/process.h
Modified: trunk/reactos/subsystems/mvdm/ntvdm/dos/dos32krnl/process.c
URL:
http://svn.reactos.org/svn/reactos/trunk/reactos/subsystems/mvdm/ntvdm/dos/…
==============================================================================
--- trunk/reactos/subsystems/mvdm/ntvdm/dos/dos32krnl/process.c [iso-8859-1] (original)
+++ trunk/reactos/subsystems/mvdm/ntvdm/dos/dos32krnl/process.c [iso-8859-1] Sat May  2
18:51:03 2015
@@ -44,6 +44,56 @@
     PspBlock->CommandLineSize = min(*(PBYTE)CommandLine, DOS_CMDLINE_LENGTH);
     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,
@@ -432,6 +482,9 @@
         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 @@
     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 @@
         {
             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);
-
-        /* 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);
-    }
+
+    /* Decrement the re-entry count */
+    CommandInfo.TaskId = SessionId;
+    CommandInfo.VDMState = VDM_DEC_REENTER_COUNT;
+    GetNextVDMCommand(&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);
+
 #endif
     /* Save the return code - Normal termination */
@@ -850,6 +902,9 @@
     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));
Modified: trunk/reactos/subsystems/mvdm/ntvdm/dos/dos32krnl/process.h
URL:
http://svn.reactos.org/svn/reactos/trunk/reactos/subsystems/mvdm/ntvdm/dos/…
==============================================================================
--- trunk/reactos/subsystems/mvdm/ntvdm/dos/dos32krnl/process.h [iso-8859-1] (original)
+++ trunk/reactos/subsystems/mvdm/ntvdm/dos/dos32krnl/process.h [iso-8859-1] Sat May  2
18:51:03 2015
@@ -72,6 +72,13 @@
     };
 } 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 ******************************************************************/