Author: hbelusca
Date: Mon Aug 17 20:11:51 2015
New Revision: 68746
URL:
http://svn.reactos.org/svn/reactos?rev=68746&view=rev
Log:
[NTVDM]
Changes in preparation for CORE-9773
- Split DosLoadExecutable into DosLoadExecutable & DosLoadExecutableInternal, the
latter one can be used for small programs embedded in ntvdm.exe (will be used for
integrated
command.com).
- Factorize common loading code in DosLoadExecutable(Internal); just before starting a
program, set the CPU registers to the default values DOS use; see comments in the code for
more details (some programs expect those values).
- Set a correct termination type (hiword in the returned ErrorLevel) when terminating
programs (the value is different for TSRs and for regular programs).
CORE-9773 CORE-9729 CORE-9711 CORE-8247
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] Mon Aug 17
20:11:51 2015
@@ -73,7 +73,10 @@
{
PDOS_REGISTER_STATE State;
- /* Pop the state structure from the stack */
+ /*
+ * Pop the state structure from the stack. Note that we
+ * already have one word allocated (the interrupt number).
+ */
State = SEG_OFF_TO_PTR(getSS(), getSP());
setSP(getSP() + sizeof(DOS_REGISTER_STATE) - sizeof(WORD));
@@ -89,8 +92,8 @@
setDI(State->DI);
}
-static WORD DosCopyEnvironmentBlock(LPCSTR Environment OPTIONAL,
- LPCSTR ProgramName)
+static WORD DosCopyEnvironmentBlock(IN LPCSTR Environment OPTIONAL,
+ IN LPCSTR ProgramName)
{
PCHAR Ptr, DestBuffer = NULL;
ULONG TotalSize = 0;
@@ -237,82 +240,29 @@
Sda->DiskTransferArea = MAKELONG(0x80, Segment);
}
-DWORD DosLoadExecutable(IN DOS_EXEC_TYPE LoadType,
- IN LPCSTR ExecutablePath,
- IN PDOS_EXEC_PARAM_BLOCK Parameters,
- IN LPCSTR CommandLine OPTIONAL,
- IN LPCSTR Environment OPTIONAL,
- IN DWORD ReturnAddress OPTIONAL)
+DWORD DosLoadExecutableInternal(IN DOS_EXEC_TYPE LoadType,
+ IN LPBYTE ExeBuffer,
+ IN DWORD ExeBufferSize,
+ IN LPCSTR ExePath,
+ IN PDOS_EXEC_PARAM_BLOCK Parameters,
+ IN LPCSTR CommandLine OPTIONAL,
+ IN LPCSTR Environment OPTIONAL,
+ IN DWORD ReturnAddress OPTIONAL)
{
DWORD Result = ERROR_SUCCESS;
- HANDLE FileHandle = INVALID_HANDLE_VALUE, FileMapping = NULL;
- LPBYTE Address = NULL;
WORD Segment = 0;
WORD EnvBlock = 0;
WORD LoadSegment;
WORD MaxAllocSize;
- DWORD i, FileSize;
- CHAR FullPath[MAX_PATH];
- CHAR ShortFullPath[MAX_PATH];
+
+ WORD FinalSS, FinalSP;
+ WORD FinalCS, FinalIP;
/* Buffer for command line conversion: 1 byte for size; 127 bytes for contents */
CHAR CmdLineBuffer[1 + DOS_CMDLINE_LENGTH];
- DPRINT1("DosLoadExecutable(%d, '%s', 0x%08X, 0x%08X, 0x%08X)\n",
- LoadType,
- ExecutablePath,
- Parameters,
- CommandLine,
- Environment);
-
- /* Try to get the full path to the executable */
- if (GetFullPathNameA(ExecutablePath, sizeof(FullPath), FullPath, NULL))
- {
- /* Try to shorten the full path */
- if (GetShortPathNameA(FullPath, ShortFullPath, sizeof(ShortFullPath)))
- {
- /* Use the shortened full path from now on */
- ExecutablePath = ShortFullPath;
- }
- }
-
- /* Open a handle to the executable */
- FileHandle = CreateFileA(ExecutablePath,
- GENERIC_READ,
- FILE_SHARE_READ,
- NULL,
- OPEN_EXISTING,
- FILE_ATTRIBUTE_NORMAL,
- NULL);
- if (FileHandle == INVALID_HANDLE_VALUE)
- {
- Result = GetLastError();
- goto Cleanup;
- }
-
- /* Get the file size */
- FileSize = GetFileSize(FileHandle, NULL);
-
- /* Create a mapping object for the file */
- FileMapping = CreateFileMapping(FileHandle,
- NULL,
- PAGE_READONLY,
- 0,
- 0,
- NULL);
- if (FileMapping == NULL)
- {
- Result = GetLastError();
- goto Cleanup;
- }
-
- /* Map the file into memory */
- Address = (LPBYTE)MapViewOfFile(FileMapping, FILE_MAP_READ, 0, 0, 0);
- if (Address == NULL)
- {
- Result = GetLastError();
- goto Cleanup;
- }
+ DPRINT1("DosLoadExecutableInternal(%d, 0x%p, '%s', 0x%p, 0x%p,
0x%p)\n",
+ LoadType, ExeBuffer, ExePath, Parameters, CommandLine, Environment);
if (LoadType != DOS_LOAD_OVERLAY)
{
@@ -388,7 +338,7 @@
}
/* Copy the environment block to DOS memory */
- EnvBlock = DosCopyEnvironmentBlock(Environment, ExecutablePath);
+ EnvBlock = DosCopyEnvironmentBlock(Environment, ExePath);
if (EnvBlock == 0)
{
Result = Sda->LastErrorCode;
@@ -397,18 +347,18 @@
}
/* Check if this is an EXE file or a COM file */
- if (Address[0] == 'M' && Address[1] == 'Z')
+ if (ExeBuffer[0] == 'M' && ExeBuffer[1] == 'Z')
{
/* EXE file */
PIMAGE_DOS_HEADER Header;
- DWORD BaseSize;
+ DWORD BaseSize, i;
PDWORD RelocationTable;
PWORD RelocWord;
WORD RelocFactor;
BOOLEAN LoadHigh = FALSE;
/* Get the MZ header */
- Header = (PIMAGE_DOS_HEADER)Address;
+ Header = (PIMAGE_DOS_HEADER)ExeBuffer;
/* Get the base size of the file, in paragraphs (rounded up) */
BaseSize = ((((Header->e_cp - (Header->e_cblp != 0)) * 512)
@@ -452,7 +402,7 @@
}
/* The process owns its own memory */
- DosChangeMemoryOwner(Segment, Segment);
+ DosChangeMemoryOwner(Segment , Segment);
DosChangeMemoryOwner(EnvBlock, Segment);
/* Set INT 22h to the return address */
@@ -480,11 +430,11 @@
/* Copy the program to the code segment */
RtlCopyMemory(SEG_OFF_TO_PTR(LoadSegment, 0),
- Address + (Header->e_cparhdr << 4),
- min(FileSize - (Header->e_cparhdr << 4), BaseSize <<
4));
+ ExeBuffer + (Header->e_cparhdr << 4),
+ min(ExeBufferSize - (Header->e_cparhdr << 4), BaseSize
<< 4));
/* Get the relocation table */
- RelocationTable = (PDWORD)(Address + Header->e_lfarlc);
+ RelocationTable = (PDWORD)(ExeBuffer + Header->e_lfarlc);
/* Perform relocations */
for (i = 0; i < Header->e_crlc; i++)
@@ -497,39 +447,13 @@
*RelocWord += RelocFactor;
}
- if (LoadType == DOS_LOAD_AND_EXECUTE)
- {
- /* Save the program state */
- if (Sda->CurrentPsp != SYSTEM_PSP)
- {
- /* Push the task state */
- DosSaveState();
-
- /* Update the last stack in the PSP */
- SEGMENT_TO_PSP(Sda->CurrentPsp)->LastStack = MAKELONG(getSP(),
getSS());
- }
-
- /* Set the initial segment registers */
- setDS(Segment);
- setES(Segment);
-
- /* Set the stack to the location from the header */
- setSS(LoadSegment + Header->e_ss);
- setSP(Header->e_sp);
-
- /* Notify VDDs of process execution */
- VDDCreateUserHook(Segment);
-
- /* Execute */
- DosSetProcessContext(Segment);
- CpuExecute(LoadSegment + Header->e_cs, Header->e_ip);
- }
- else if (LoadType == DOS_LOAD_ONLY)
- {
- ASSERT(Parameters);
- Parameters->StackLocation = MAKELONG(Header->e_sp, LoadSegment +
Header->e_ss);
- Parameters->EntryPoint = MAKELONG(Header->e_ip, LoadSegment +
Header->e_cs);
- }
+ /* Set the stack to the location from the header */
+ FinalSS = LoadSegment + Header->e_ss;
+ FinalSP = Header->e_sp;
+
+ /* Set the code segment/pointer */
+ FinalCS = LoadSegment + Header->e_cs;
+ FinalIP = Header->e_ip;
}
else
{
@@ -541,7 +465,7 @@
DosAllocateMemory(0xFFFF, &MaxAllocSize);
/* Make sure it's enough for the whole program and the PSP */
- if (((DWORD)MaxAllocSize << 4) < (FileSize + sizeof(DOS_PSP)))
+ if (((DWORD)MaxAllocSize << 4) < (ExeBufferSize + sizeof(DOS_PSP)))
{
Result = ERROR_NOT_ENOUGH_MEMORY;
goto Cleanup;
@@ -556,7 +480,7 @@
}
/* The process owns its own memory */
- DosChangeMemoryOwner(Segment, Segment);
+ DosChangeMemoryOwner(Segment , Segment);
DosChangeMemoryOwner(EnvBlock, Segment);
/* Set INT 22h to the return address */
@@ -578,48 +502,75 @@
/* Copy the program to the code segment */
RtlCopyMemory(SEG_OFF_TO_PTR(LoadSegment, 0),
- Address,
- FileSize);
-
- if (LoadType == DOS_LOAD_AND_EXECUTE)
- {
- /* Save the program state */
- if (Sda->CurrentPsp != SYSTEM_PSP)
- {
- /* Push the task state */
- DosSaveState();
-
- /* Update the last stack in the PSP */
- SEGMENT_TO_PSP(Sda->CurrentPsp)->LastStack = MAKELONG(getSP(),
getSS());
- }
-
- /* Set the initial segment registers */
- setDS(Segment);
- setES(Segment);
-
- /* Set the stack to the last word of the segment */
- setSS(Segment);
- setSP(0xFFFE);
-
- /*
- * Set the value on the stack to 0, so that a near return
- * jumps to PSP:0000 which has the exit code.
- */
- *((LPWORD)SEG_OFF_TO_PTR(Segment, 0xFFFE)) = 0;
-
- /* Notify VDDs of process execution */
- VDDCreateUserHook(Segment);
-
- /* Execute */
- DosSetProcessContext(Segment);
- CpuExecute(Segment, 0x100);
- }
- else if (LoadType == DOS_LOAD_ONLY)
- {
- ASSERT(Parameters);
- Parameters->StackLocation = MAKELONG(0xFFFE, Segment);
- Parameters->EntryPoint = MAKELONG(0x0100, Segment);
- }
+ ExeBuffer, ExeBufferSize);
+
+ /* Set the stack to the last word of the segment */
+ FinalSS = Segment;
+ FinalSP = 0xFFFE;
+
+ /*
+ * Set the value on the stack to 0x0000, so that a near return
+ * jumps to PSP:0000 which has the exit code.
+ */
+ *((LPWORD)SEG_OFF_TO_PTR(Segment, 0xFFFE)) = 0x0000;
+
+ /* Set the code segment/pointer */
+ FinalCS = Segment;
+ FinalIP = 0x0100;
+ }
+
+ if (LoadType == DOS_LOAD_AND_EXECUTE)
+ {
+ /* Save the program state */
+ if (Sda->CurrentPsp != SYSTEM_PSP)
+ {
+ /* Push the task state */
+ DosSaveState();
+
+ /* Update the last stack in the PSP */
+ SEGMENT_TO_PSP(Sda->CurrentPsp)->LastStack = MAKELONG(getSP(),
getSS());
+ }
+
+ /* Set the initial segment registers */
+ setDS(Segment);
+ setES(Segment);
+
+ /* Set the stack */
+ setSS(FinalSS);
+ setSP(FinalSP);
+
+ /*
+ * Set the other registers as in real DOS: some demos expect them so!
+ * See
http://www.fysnet.net/yourhelp.htm
+ * and
http://www.beroset.com/asm/showregs.asm
+ */
+ setDX(Segment);
+ setDI(FinalSP);
+ setBP(0x091E); // DOS base stack pointer relic value
+ setSI(FinalIP);
+
+ setAX(0/*0xFFFF*/); // FIXME: fcbcode
+ setBX(0/*0xFFFF*/); // FIXME: fcbcode
+ setCX(0x00FF);
+
+ /*
+ * Keep critical flags, clear test flags (OF, SF, ZF, AF, PF, CF)
+ * and explicitely set the interrupt flag.
+ */
+ setEFLAGS((getEFLAGS() & ~0x08D5) | 0x0200);
+
+ /* Notify VDDs of process execution */
+ VDDCreateUserHook(Segment);
+
+ /* Execute */
+ DosSetProcessContext(Segment);
+ CpuExecute(FinalCS, FinalIP);
+ }
+ else if (LoadType == DOS_LOAD_ONLY)
+ {
+ ASSERT(Parameters);
+ Parameters->StackLocation = MAKELONG(FinalSP, FinalSS);
+ Parameters->EntryPoint = MAKELONG(FinalIP, FinalCS);
}
Cleanup:
@@ -630,6 +581,85 @@
if (Segment) DosFreeMemory(Segment);
}
+ return Result;
+}
+
+DWORD DosLoadExecutable(IN DOS_EXEC_TYPE LoadType,
+ IN LPCSTR ExecutablePath,
+ IN PDOS_EXEC_PARAM_BLOCK Parameters,
+ IN LPCSTR CommandLine OPTIONAL,
+ IN LPCSTR Environment OPTIONAL,
+ IN DWORD ReturnAddress OPTIONAL)
+{
+ DWORD Result = ERROR_SUCCESS;
+ HANDLE FileHandle = INVALID_HANDLE_VALUE, FileMapping = NULL;
+ DWORD FileSize;
+ LPBYTE Address = NULL;
+ CHAR FullPath[MAX_PATH];
+ CHAR ShortFullPath[MAX_PATH];
+
+ DPRINT1("DosLoadExecutable(%d, '%s', 0x%p, 0x%p, 0x%p)\n",
+ LoadType, ExecutablePath, Parameters, CommandLine, Environment);
+
+ /* Try to get the full path to the executable */
+ if (GetFullPathNameA(ExecutablePath, sizeof(FullPath), FullPath, NULL))
+ {
+ /* Get the corresponding short path */
+ if (GetShortPathNameA(FullPath, ShortFullPath, sizeof(ShortFullPath)))
+ {
+ /* Use the shortened full path from now on */
+ ExecutablePath = ShortFullPath;
+ }
+ }
+
+ /* Open a handle to the executable */
+ FileHandle = CreateFileA(ExecutablePath,
+ GENERIC_READ,
+ FILE_SHARE_READ,
+ NULL,
+ OPEN_EXISTING,
+ FILE_ATTRIBUTE_NORMAL,
+ NULL);
+ if (FileHandle == INVALID_HANDLE_VALUE)
+ {
+ Result = GetLastError();
+ goto Cleanup;
+ }
+
+ /* Get the file size */
+ FileSize = GetFileSize(FileHandle, NULL);
+
+ /* Create a mapping object for the file */
+ FileMapping = CreateFileMapping(FileHandle,
+ NULL,
+ PAGE_READONLY,
+ 0,
+ 0,
+ NULL);
+ if (FileMapping == NULL)
+ {
+ Result = GetLastError();
+ goto Cleanup;
+ }
+
+ /* Map the file into memory */
+ Address = (LPBYTE)MapViewOfFile(FileMapping, FILE_MAP_READ, 0, 0, 0);
+ if (Address == NULL)
+ {
+ Result = GetLastError();
+ goto Cleanup;
+ }
+
+ Result = DosLoadExecutableInternal(LoadType,
+ Address,
+ FileSize,
+ ExecutablePath,
+ Parameters,
+ CommandLine,
+ Environment,
+ ReturnAddress);
+
+Cleanup:
/* Unmap the file*/
if (Address != NULL) UnmapViewOfFile(Address);
@@ -690,9 +720,9 @@
}
#ifndef STANDALONE
-WORD DosCreateProcess(LPCSTR ProgramName,
- PDOS_EXEC_PARAM_BLOCK Parameters,
- DWORD ReturnAddress OPTIONAL)
+WORD DosCreateProcess(IN LPCSTR ProgramName,
+ IN PDOS_EXEC_PARAM_BLOCK Parameters,
+ IN DWORD ReturnAddress OPTIONAL)
{
DWORD Result;
DWORD BinaryType;
@@ -851,29 +881,28 @@
VOID DosTerminateProcess(WORD Psp, BYTE ReturnCode, WORD KeepResident)
{
- WORD i;
WORD McbSegment = SysVars->FirstMcb;
PDOS_MCB CurrentMcb;
LPDWORD IntVecTable = (LPDWORD)((ULONG_PTR)BaseAddress);
PDOS_PSP PspBlock = SEGMENT_TO_PSP(Psp);
LPWORD Stack;
+ BYTE TerminationType;
#ifndef STANDALONE
VDM_COMMAND_INFO CommandInfo;
#endif
DPRINT("DosTerminateProcess: Psp 0x%04X, ReturnCode 0x%02X, KeepResident
0x%04X\n",
- Psp,
- ReturnCode,
- KeepResident);
+ Psp, ReturnCode, KeepResident);
+
+ /* Notify VDDs of process termination */
+ VDDTerminateUserHook(Psp);
/* Check if this PSP is it's own parent */
if (PspBlock->ParentPsp == Psp) goto Done;
- /* Notify VDDs of process termination */
- VDDTerminateUserHook(Psp);
-
if (KeepResident == 0)
{
+ WORD i;
for (i = 0; i < PspBlock->HandleTableSize; i++)
{
/* Close the handle */
@@ -923,10 +952,10 @@
IntVecTable[0x23] = PspBlock->BreakAddress;
IntVecTable[0x24] = PspBlock->CriticalAddress;
- /* Update the current PSP */
+ /* Update the current PSP with the parent's one */
if (Psp == Sda->CurrentPsp)
{
- Sda->CurrentPsp = PspBlock->ParentPsp;
+ DosSetProcessContext(PspBlock->ParentPsp);
if (Sda->CurrentPsp == SYSTEM_PSP)
{
ResetEvent(VdmTaskEvent);
@@ -952,15 +981,19 @@
#endif
- /* Save the return code - Normal termination */
- Sda->ErrorLevel = MAKEWORD(ReturnCode, 0x00);
-
- /* Restore the old stack */
- setSS(HIWORD(SEGMENT_TO_PSP(Sda->CurrentPsp)->LastStack));
- setSP(LOWORD(SEGMENT_TO_PSP(Sda->CurrentPsp)->LastStack));
-
- /* Pop the task state */
- DosRestoreState();
+ /* Save the return code - Normal termination or TSR */
+ TerminationType = (KeepResident != 0 ? 0x03 : 0x00);
+ Sda->ErrorLevel = MAKEWORD(ReturnCode, TerminationType);
+
+ if (Sda->CurrentPsp != SYSTEM_PSP)
+ {
+ /* Restore the parent's stack */
+ setSS(HIWORD(SEGMENT_TO_PSP(Sda->CurrentPsp)->LastStack));
+ setSP(LOWORD(SEGMENT_TO_PSP(Sda->CurrentPsp)->LastStack));
+
+ /* Pop the task state */
+ DosRestoreState();
+ }
/* Return control to the parent process */
Stack = (LPWORD)SEG_OFF_TO_PTR(getSS(), getSP());
@@ -968,3 +1001,4 @@
Stack[STACK_IP] = LOWORD(PspBlock->TerminateAddress);
}
+/* EOF */
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] Mon Aug 17
20:11:51 2015
@@ -87,6 +87,18 @@
VOID DosCreatePsp(WORD Segment, WORD ProgramSize);
VOID DosSetProcessContext(WORD Segment);
+DWORD DosLoadExecutableInternal
+(
+ IN DOS_EXEC_TYPE LoadType,
+ IN LPBYTE ExeBuffer,
+ IN DWORD ExeBufferSize,
+ IN LPCSTR ExePath,
+ IN PDOS_EXEC_PARAM_BLOCK Parameters,
+ IN LPCSTR CommandLine OPTIONAL,
+ IN LPCSTR Environment OPTIONAL,
+ IN DWORD ReturnAddress OPTIONAL
+);
+
DWORD DosLoadExecutable
(
IN DOS_EXEC_TYPE LoadType,