Author: aandrejevic
Date: Sat Apr 26 08:57:17 2014
New Revision: 62972
URL:
http://svn.reactos.org/svn/reactos?rev=62972&view=rev
Log:
[NTVDM]
Rewrite DosCreateProcess, separating the loading code into DosLoadExecutable.
Implement INT 21h function AH = 0x4B (Create Process).
Modified:
branches/ntvdm/subsystems/ntvdm/dos/dos32krnl/dos.c
branches/ntvdm/subsystems/ntvdm/dos/dos32krnl/dos.h
branches/ntvdm/subsystems/ntvdm/ntvdm.c
Modified: branches/ntvdm/subsystems/ntvdm/dos/dos32krnl/dos.c
URL:
http://svn.reactos.org/svn/reactos/branches/ntvdm/subsystems/ntvdm/dos/dos3…
==============================================================================
--- branches/ntvdm/subsystems/ntvdm/dos/dos32krnl/dos.c [iso-8859-1] (original)
+++ branches/ntvdm/subsystems/ntvdm/dos/dos32krnl/dos.c [iso-8859-1] Sat Apr 26 08:57:17
2014
@@ -383,15 +383,13 @@
Mcb->OwnerPsp = NewOwner;
}
-
-
-static WORD DosCopyEnvironmentBlock(WORD SourceSegment, LPCSTR ProgramName)
-{
- PCHAR Ptr, SourceBuffer, DestBuffer = NULL;
+static WORD DosCopyEnvironmentBlock(LPCVOID Environment, LPCSTR ProgramName)
+{
+ PCHAR Ptr, DestBuffer = NULL;
ULONG TotalSize = 0;
WORD DestSegment;
- Ptr = SourceBuffer = (PCHAR)SEG_OFF_TO_PTR(SourceSegment, 0);
+ Ptr = (PCHAR)Environment;
/* Calculate the size of the environment block */
while (*Ptr)
@@ -408,7 +406,7 @@
DestSegment = DosAllocateMemory((WORD)((TotalSize + 0x0F) >> 4), NULL);
if (!DestSegment) return 0;
- Ptr = SourceBuffer;
+ Ptr = (PCHAR)Environment;
DestBuffer = (PCHAR)SEG_OFF_TO_PTR(DestSegment, 0);
while (*Ptr)
@@ -1042,57 +1040,51 @@
PspBlock->CommandLine[PspBlock->CommandLineSize] = '\r';
}
-BOOLEAN DosCreateProcess(LPCSTR CommandLine, WORD EnvBlock)
-{
- BOOLEAN Success = FALSE, AllocatedEnvBlock = FALSE;
+DWORD DosLoadExecutable(IN DOS_EXEC_TYPE LoadType,
+ IN LPCSTR ExecutablePath,
+ IN LPCSTR CommandLine,
+ IN PVOID Environment,
+ OUT PDWORD StackLocation OPTIONAL,
+ OUT PDWORD EntryPoint OPTIONAL)
+{
+ DWORD Result = ERROR_SUCCESS;
HANDLE FileHandle = INVALID_HANDLE_VALUE, FileMapping = NULL;
LPBYTE Address = NULL;
- LPSTR ProgramFilePath, Parameters[256];
- CHAR CommandLineCopy[DOS_CMDLINE_LENGTH];
- CHAR ParamString[DOS_CMDLINE_LENGTH];
- DWORD ParamCount = 0;
WORD Segment = 0;
+ WORD EnvBlock = 0;
WORD MaxAllocSize;
DWORD i, FileSize, ExeSize;
PIMAGE_DOS_HEADER Header;
PDWORD RelocationTable;
PWORD RelocWord;
- DPRINT("DosCreateProcess: CommandLine \"%s\", EnvBlock
0x%04X\n",
- CommandLine,
- EnvBlock);
-
- /* Save a copy of the command line */
- strcpy(CommandLineCopy, CommandLine);
-
- /* Get the file name of the executable */
- ProgramFilePath = strtok(CommandLineCopy, " \t");
-
- /* Load the parameters in the local array */
- while ((ParamCount < sizeof(Parameters)/sizeof(Parameters[0]))
- && ((Parameters[ParamCount] = strtok(NULL, " \t")) !=
NULL))
- {
- ParamCount++;
- }
-
- ZeroMemory(ParamString, sizeof(ParamString));
-
- /* Store the parameters in a string */
- for (i = 0; i < ParamCount; i++)
- {
- strncat(ParamString, Parameters[i], DOS_CMDLINE_LENGTH - strlen(ParamString) -
1);
- strncat(ParamString, " ", DOS_CMDLINE_LENGTH - strlen(ParamString) -
1);
+ DPRINT1("DosLoadExecutable(%d, %s, %s, %s, 0x%08X, 0x%08X)\n",
+ LoadType,
+ ExecutablePath,
+ CommandLine,
+ Environment,
+ StackLocation,
+ EntryPoint);
+
+ if (LoadType == DOS_LOAD_OVERLAY)
+ {
+ DPRINT1("Overlay loading is not supported yet.\n");
+ return ERROR_NOT_SUPPORTED;
}
/* Open a handle to the executable */
- FileHandle = CreateFileA(ProgramFilePath,
+ FileHandle = CreateFileA(ExecutablePath,
GENERIC_READ,
0,
NULL,
OPEN_EXISTING,
FILE_ATTRIBUTE_NORMAL,
NULL);
- if (FileHandle == INVALID_HANDLE_VALUE) goto Cleanup;
+ if (FileHandle == INVALID_HANDLE_VALUE)
+ {
+ Result = GetLastError();
+ goto Cleanup;
+ }
/* Get the file size */
FileSize = GetFileSize(FileHandle, NULL);
@@ -1104,23 +1096,26 @@
0,
0,
NULL);
- if (FileMapping == NULL) goto Cleanup;
+ 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) goto Cleanup;
-
- /* Did we get an environment segment? */
- if (!EnvBlock)
- {
- /* Set a flag to know if the environment block was allocated here */
- AllocatedEnvBlock = TRUE;
-
- /* No, copy the one from the parent */
- EnvBlock = DosCopyEnvironmentBlock((CurrentPsp != SYSTEM_PSP)
- ? SEGMENT_TO_PSP(CurrentPsp)->EnvBlock
- : SYSTEM_ENV_BLOCK,
- ProgramFilePath);
+ if (Address == NULL)
+ {
+ Result = GetLastError();
+ goto Cleanup;
+ }
+
+ /* Copy the environment block to DOS memory */
+ EnvBlock = DosCopyEnvironmentBlock(Environment, ExecutablePath);
+ if (EnvBlock == 0)
+ {
+ Result = ERROR_NOT_ENOUGH_MEMORY;
+ goto Cleanup;
}
/* Check if this is an EXE file or a COM file */
@@ -1152,11 +1147,15 @@
}
/* Check if at least the lowest allocation was successful */
- if (Segment == 0) goto Cleanup;
+ if (Segment == 0)
+ {
+ Result = ERROR_NOT_ENOUGH_MEMORY;
+ goto Cleanup;
+ }
/* Initialize the PSP */
DosInitializePsp(Segment,
- ParamString,
+ CommandLine,
(WORD)ExeSize,
EnvBlock);
@@ -1184,21 +1183,22 @@
*RelocWord += Segment + (sizeof(DOS_PSP) >> 4);
}
- /* Set the initial segment registers */
- setDS(Segment);
- setES(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;
- DiskTransferArea = MAKELONG(0x80, Segment);
- EmulatorExecute(Segment + Header->e_cs + (sizeof(DOS_PSP) >> 4),
- Header->e_ip);
-
- Success = TRUE;
+ if (LoadType == DOS_LOAD_AND_EXECUTE)
+ {
+ /* Set the initial segment registers */
+ setDS(Segment);
+ setES(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;
+ DiskTransferArea = MAKELONG(0x80, Segment);
+ EmulatorExecute(Segment + Header->e_cs + (sizeof(DOS_PSP) >> 4),
+ Header->e_ip);
+ }
}
else
{
@@ -1208,11 +1208,19 @@
DosAllocateMemory(0xFFFF, &MaxAllocSize);
/* Make sure it's enough for the whole program and the PSP */
- if (((DWORD)MaxAllocSize << 4) < (FileSize + sizeof(DOS_PSP))) goto
Cleanup;
+ if (((DWORD)MaxAllocSize << 4) < (FileSize + sizeof(DOS_PSP)))
+ {
+ Result = ERROR_NOT_ENOUGH_MEMORY;
+ goto Cleanup;
+ }
/* Allocate all of it */
Segment = DosAllocateMemory(MaxAllocSize, NULL);
- if (Segment == 0) goto Cleanup;
+ if (Segment == 0)
+ {
+ Result = ERROR_ARENA_TRASHED;
+ goto Cleanup;
+ }
/* The process owns its own memory */
DosChangeMemoryOwner(Segment, Segment);
@@ -1225,36 +1233,37 @@
/* Initialize the PSP */
DosInitializePsp(Segment,
- ParamString,
+ CommandLine,
MaxAllocSize,
EnvBlock);
- /* Set the initial segment registers */
- setDS(Segment);
- setES(Segment);
-
- /* Set the stack to the last word of the segment */
- EmulatorSetStack(Segment, 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;
-
- /* Execute */
- CurrentPsp = Segment;
- DiskTransferArea = MAKELONG(0x80, Segment);
- EmulatorExecute(Segment, 0x100);
-
- Success = TRUE;
+ if (LoadType == DOS_LOAD_AND_EXECUTE)
+ {
+ /* Set the initial segment registers */
+ setDS(Segment);
+ setES(Segment);
+
+ /* Set the stack to the last word of the segment */
+ EmulatorSetStack(Segment, 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;
+
+ /* Execute */
+ CurrentPsp = Segment;
+ DiskTransferArea = MAKELONG(0x80, Segment);
+ EmulatorExecute(Segment, 0x100);
+ }
}
Cleanup:
- if (!Success)
+ if (Result != ERROR_SUCCESS)
{
/* It was not successful, cleanup the DOS memory */
- if (AllocatedEnvBlock) DosFreeMemory(EnvBlock);
+ if (EnvBlock) DosFreeMemory(EnvBlock);
if (Segment) DosFreeMemory(Segment);
}
@@ -1267,7 +1276,118 @@
/* Close the file handle */
if (FileHandle != INVALID_HANDLE_VALUE) CloseHandle(FileHandle);
- return Success;
+ return Result;
+}
+
+WORD DosCreateProcess(DOS_EXEC_TYPE LoadType,
+ LPCSTR ProgramName,
+ PDOS_EXEC_PARAM_BLOCK Parameters)
+{
+ DWORD BinaryType;
+ LPVOID Environment = NULL;
+ VDM_COMMAND_INFO CommandInfo;
+ CHAR CmdLine[MAX_PATH];
+ CHAR AppName[MAX_PATH];
+ CHAR PifFile[MAX_PATH];
+ CHAR Desktop[MAX_PATH];
+ CHAR Title[MAX_PATH];
+ CHAR Env[MAX_PATH];
+ STARTUPINFOA StartupInfo;
+ PROCESS_INFORMATION ProcessInfo;
+
+ /* Get the binary type */
+ if (!GetBinaryTypeA(ProgramName, &BinaryType)) return GetLastError();
+
+ /* Did the caller specify an environment segment? */
+ if (Parameters->Environment)
+ {
+ /* Yes, use it instead of the parent one */
+ Environment = SEG_OFF_TO_PTR(Parameters->Environment, 0);
+ }
+
+ /* Set up the startup info structure */
+ ZeroMemory(&StartupInfo, sizeof(STARTUPINFOA));
+ StartupInfo.cb = sizeof(STARTUPINFOA);
+
+ /* Create the process */
+ if (!CreateProcessA(ProgramName,
+ FAR_POINTER(Parameters->CommandLine),
+ NULL,
+ NULL,
+ FALSE,
+ 0,
+ Environment,
+ NULL,
+ &StartupInfo,
+ &ProcessInfo))
+ {
+ return GetLastError();
+ }
+
+ /* Check the type of the program */
+ switch (BinaryType)
+ {
+ /* These are handled by NTVDM */
+ case SCS_DOS_BINARY:
+ case SCS_WOW_BINARY:
+ {
+ /* Clear the structure */
+ ZeroMemory(&CommandInfo, sizeof(CommandInfo));
+
+ /* Initialize the structure members */
+ CommandInfo.VDMState = VDM_NOT_READY;
+ CommandInfo.CmdLine = CmdLine;
+ CommandInfo.CmdLen = sizeof(CmdLine);
+ CommandInfo.AppName = AppName;
+ CommandInfo.AppLen = sizeof(AppName);
+ CommandInfo.PifFile = PifFile;
+ CommandInfo.PifLen = sizeof(PifFile);
+ CommandInfo.Desktop = Desktop;
+ CommandInfo.DesktopLen = sizeof(Desktop);
+ CommandInfo.Title = Title;
+ CommandInfo.TitleLen = sizeof(Title);
+ CommandInfo.Env = Env;
+ CommandInfo.EnvLen = sizeof(Env);
+
+ /* Get the VDM command information */
+ if (!GetNextVDMCommand(&CommandInfo))
+ {
+ /* Shouldn't happen */
+ ASSERT(FALSE);
+ }
+
+ /* Increment the re-entry count */
+ CommandInfo.VDMState = VDM_INC_REENTER_COUNT;
+ GetNextVDMCommand(&CommandInfo);
+
+ /* Load the executable */
+ if (DosLoadExecutable(LoadType,
+ AppName,
+ CmdLine,
+ Env,
+ &Parameters->StackLocation,
+ &Parameters->EntryPoint) != ERROR_SUCCESS)
+ {
+ DisplayMessage(L"Could not load '%S'", AppName);
+ break;
+ }
+
+ break;
+ }
+
+ /* Not handled by NTVDM */
+ default:
+ {
+ /* Wait for the process to finish executing */
+ WaitForSingleObject(ProcessInfo.hProcess, INFINITE);
+ }
+ }
+
+ /* Close the handles */
+ CloseHandle(ProcessInfo.hProcess);
+ CloseHandle(ProcessInfo.hThread);
+
+ return ERROR_SUCCESS;
}
VOID DosTerminateProcess(WORD Psp, BYTE ReturnCode)
@@ -2345,6 +2465,27 @@
break;
}
+ /* Execute */
+ case 0x4B:
+ {
+ DOS_EXEC_TYPE LoadType = (DOS_EXEC_TYPE)getAL();
+ LPSTR ProgramName = SEG_OFF_TO_PTR(getDS(), getDX());
+ PDOS_EXEC_PARAM_BLOCK ParamBlock = SEG_OFF_TO_PTR(getES(), getBX());
+ WORD ErrorCode = DosCreateProcess(LoadType, ProgramName, ParamBlock);
+
+ if (ErrorCode == ERROR_SUCCESS)
+ {
+ Stack[STACK_FLAGS] &= ~EMULATOR_FLAG_CF;
+ }
+ else
+ {
+ Stack[STACK_FLAGS] |= EMULATOR_FLAG_CF;
+ setAX(ErrorCode);
+ }
+
+ break;
+ }
+
/* Terminate With Return Code */
case 0x4C:
{
Modified: branches/ntvdm/subsystems/ntvdm/dos/dos32krnl/dos.h
URL:
http://svn.reactos.org/svn/reactos/branches/ntvdm/subsystems/ntvdm/dos/dos3…
==============================================================================
--- branches/ntvdm/subsystems/ntvdm/dos/dos32krnl/dos.h [iso-8859-1] (original)
+++ branches/ntvdm/subsystems/ntvdm/dos/dos32krnl/dos.h [iso-8859-1] Sat Apr 26 08:57:17
2014
@@ -52,6 +52,13 @@
DOS_ALLOC_BEST_FIT,
DOS_ALLOC_LAST_FIT
};
+
+typedef enum
+{
+ DOS_LOAD_AND_EXECUTE = 0x00,
+ DOS_LOAD_ONLY = 0x01,
+ DOS_LOAD_OVERLAY = 0x03
+} DOS_EXEC_TYPE;
#pragma pack(push, 1)
@@ -136,6 +143,19 @@
CHAR FileName[13];
} DOS_FIND_FILE_BLOCK, *PDOS_FIND_FILE_BLOCK;
+typedef struct _DOS_EXEC_PARAM_BLOCK
+{
+ /* Input variables */
+ WORD Environment;
+ DWORD CommandLine;
+ DWORD FirstFcb;
+ DWORD SecondFcb;
+
+ /* Output variables */
+ DWORD StackLocation;
+ DWORD EntryPoint;
+} DOS_EXEC_PARAM_BLOCK, *PDOS_EXEC_PARAM_BLOCK;
+
#pragma pack(pop)
/* FUNCTIONS ******************************************************************/
@@ -169,7 +189,19 @@
WORD DosWriteFile(WORD FileHandle, LPVOID Buffer, WORD Count, LPWORD BytesWritten);
VOID DosInitializePsp(WORD PspSegment, LPCSTR CommandLine, WORD ProgramSize, WORD
Environment);
-BOOLEAN DosCreateProcess(LPCSTR CommandLine, WORD EnvBlock);
+DWORD DosLoadExecutable(
+ IN DOS_EXEC_TYPE LoadType,
+ IN LPCSTR ExecutablePath,
+ IN LPCSTR CommandLine,
+ IN PVOID Environment,
+ OUT PDWORD StackLocation OPTIONAL,
+ OUT PDWORD EntryPoint OPTIONAL
+);
+WORD DosCreateProcess(
+ DOS_EXEC_TYPE LoadType,
+ LPCSTR ProgramName,
+ PDOS_EXEC_PARAM_BLOCK Parameters
+);
VOID DosTerminateProcess(WORD Psp, BYTE ReturnCode);
BOOLEAN DosHandleIoctl(BYTE ControlCode, WORD FileHandle);
Modified: branches/ntvdm/subsystems/ntvdm/ntvdm.c
URL:
http://svn.reactos.org/svn/reactos/branches/ntvdm/subsystems/ntvdm/ntvdm.c?…
==============================================================================
--- branches/ntvdm/subsystems/ntvdm/ntvdm.c [iso-8859-1] (original)
+++ branches/ntvdm/subsystems/ntvdm/ntvdm.c [iso-8859-1] Sat Apr 26 08:57:17 2014
@@ -385,6 +385,7 @@
CHAR PifFile[MAX_PATH];
CHAR Desktop[MAX_PATH];
CHAR Title[MAX_PATH];
+ CHAR Env[MAX_PATH];
UNREFERENCED_PARAMETER(Parameter);
@@ -405,13 +406,20 @@
CommandInfo.DesktopLen = sizeof(Desktop);
CommandInfo.Title = Title;
CommandInfo.TitleLen = sizeof(Title);
+ CommandInfo.Env = Env;
+ CommandInfo.EnvLen = sizeof(Env);
/* Wait for the next available VDM */
if (!GetNextVDMCommand(&CommandInfo)) break;
/* Start the process from the command line */
DPRINT1("Starting '%s'...\n", AppName);
- if (!DosCreateProcess(AppName, 0))
+ if (DosLoadExecutable(DOS_LOAD_AND_EXECUTE,
+ AppName,
+ CmdLine,
+ Env,
+ NULL,
+ NULL) != ERROR_SUCCESS)
{
DisplayMessage(L"Could not start '%S'", AppName);
break;
@@ -430,17 +438,20 @@
INT wmain(INT argc, WCHAR *argv[])
{
#ifdef STANDALONE
-
+ CHAR ApplicationName[MAX_PATH];
CHAR CommandLine[DOS_CMDLINE_LENGTH];
- if (argc == 2 && argv[1] != NULL)
- {
- WideCharToMultiByte(CP_ACP, 0, argv[1], -1, CommandLine, sizeof(CommandLine),
NULL, NULL);
+ if (argc >= 2)
+ {
+ WideCharToMultiByte(CP_ACP, 0, argv[1], -1, ApplicationName,
sizeof(ApplicationName), NULL, NULL);
+
+ if (argc >= 3) WideCharToMultiByte(CP_ACP, 0, argv[2], -1, CommandLine,
sizeof(CommandLine), NULL, NULL);
+ else strcpy(CommandLine, "");
}
else
{
wprintf(L"\nReactOS Virtual DOS Machine\n\n"
- L"Usage: NTVDM <executable>\n");
+ L"Usage: NTVDM <executable> [<parameters>]\n");
return 0;
}
@@ -496,9 +507,14 @@
/* Start the process from the command line */
DPRINT1("Starting '%s'...\n", CommandLine);
- if (!DosCreateProcess(CommandLine, 0))
- {
- DisplayMessage(L"Could not start '%S'", CommandLine);
+ if (DosLoadExecutable(DOS_LOAD_AND_EXECUTE,
+ ApplicationName,
+ CommandLine,
+ GetEnvironmentStrings(),
+ NULL,
+ NULL) != ERROR_SUCCESS)
+ {
+ DisplayMessage(L"Could not start '%S'", ApplicationName);
goto Cleanup;
}