Author: aandrejevic
Date: Fri May 1 15:42:54 2015
New Revision: 67498
URL:
http://svn.reactos.org/svn/reactos?rev=67498&view=rev
Log:
[NTVDM]
Separate the process-related code from the DOS kernel.
Enable starting processes from other processes in STANDALONE mode.
Implement INT 21h, AH = 55h and INT 21h, AH = 26h (Create/Clone PSP).
Implement overlay loading.
Added:
trunk/reactos/subsystems/mvdm/ntvdm/dos/dos32krnl/process.c (with props)
trunk/reactos/subsystems/mvdm/ntvdm/dos/dos32krnl/process.h (with props)
Modified:
trunk/reactos/subsystems/mvdm/ntvdm/CMakeLists.txt
trunk/reactos/subsystems/mvdm/ntvdm/dos/dem.c
trunk/reactos/subsystems/mvdm/ntvdm/dos/dos32krnl/dos.c
trunk/reactos/subsystems/mvdm/ntvdm/dos/dos32krnl/dos.h
trunk/reactos/subsystems/mvdm/ntvdm/dos/dos32krnl/dosfiles.c
trunk/reactos/subsystems/mvdm/ntvdm/dos/dos32krnl/handle.c
trunk/reactos/subsystems/mvdm/ntvdm/dos/dos32krnl/memory.c
trunk/reactos/subsystems/mvdm/ntvdm/dos/dos32krnl/memory.h
Modified: trunk/reactos/subsystems/mvdm/ntvdm/CMakeLists.txt
URL:
http://svn.reactos.org/svn/reactos/trunk/reactos/subsystems/mvdm/ntvdm/CMak…
==============================================================================
--- trunk/reactos/subsystems/mvdm/ntvdm/CMakeLists.txt [iso-8859-1] (original)
+++ trunk/reactos/subsystems/mvdm/ntvdm/CMakeLists.txt [iso-8859-1] Fri May 1 15:42:54
2015
@@ -36,6 +36,7 @@
dos/dos32krnl/handle.c
dos/dos32krnl/himem.c
dos/dos32krnl/memory.c
+ dos/dos32krnl/process.c
dos/mouse32.c
dos/dem.c
clock.c
Modified: trunk/reactos/subsystems/mvdm/ntvdm/dos/dem.c
URL:
http://svn.reactos.org/svn/reactos/trunk/reactos/subsystems/mvdm/ntvdm/dos/…
==============================================================================
--- trunk/reactos/subsystems/mvdm/ntvdm/dos/dem.c [iso-8859-1] (original)
+++ trunk/reactos/subsystems/mvdm/ntvdm/dos/dem.c [iso-8859-1] Fri May 1 15:42:54 2015
@@ -20,6 +20,7 @@
#include "dem.h"
#include "dos/dos32krnl/device.h"
+#include "dos/dos32krnl/process.h"
#include "cpu/bop.h"
#include "bios/bios.h"
Modified: trunk/reactos/subsystems/mvdm/ntvdm/dos/dos32krnl/dos.c
URL:
http://svn.reactos.org/svn/reactos/trunk/reactos/subsystems/mvdm/ntvdm/dos/…
==============================================================================
--- trunk/reactos/subsystems/mvdm/ntvdm/dos/dos32krnl/dos.c [iso-8859-1] (original)
+++ trunk/reactos/subsystems/mvdm/ntvdm/dos/dos32krnl/dos.c [iso-8859-1] Fri May 1
15:42:54 2015
@@ -22,6 +22,7 @@
#include "handle.h"
#include "dosfiles.h"
#include "memory.h"
+#include "process.h"
#include "himem.h"
#include "bios/bios.h"
@@ -37,11 +38,9 @@
CALLBACK16 DosContext;
-static DWORD DiskTransferArea;
/*static*/ BYTE CurrentDrive;
static CHAR LastDrive = 'E';
static CHAR CurrentDirectories[NUM_DRIVES][DOS_DIR_LENGTH];
-static WORD DosErrorLevel = 0x0000;
static PBYTE InDos;
/* PUBLIC VARIABLES ***********************************************************/
@@ -50,78 +49,12 @@
/* Echo state for INT 21h, AH = 01h and AH = 3Fh */
BOOLEAN DoEcho = FALSE;
-WORD CurrentPsp = SYSTEM_PSP;
+
+DWORD DiskTransferArea;
+WORD DosErrorLevel = 0x0000;
WORD DosLastError = 0;
/* PRIVATE FUNCTIONS **********************************************************/
-
-static WORD DosCopyEnvironmentBlock(LPCSTR Environment OPTIONAL,
- LPCSTR ProgramName)
-{
- PCHAR Ptr, DestBuffer = NULL;
- ULONG TotalSize = 0;
- WORD DestSegment;
-
- /* If we have an environment strings list, compute its size */
- if (Environment)
- {
- /* Calculate the size of the environment block */
- Ptr = (PCHAR)Environment;
- while (*Ptr) Ptr += strlen(Ptr) + 1;
- TotalSize = (ULONG_PTR)Ptr - (ULONG_PTR)Environment;
- }
- else
- {
- /* Empty environment string */
- TotalSize = 1;
- }
- /* Add the final environment block NULL-terminator */
- TotalSize++;
-
- /* Add the two bytes for the program name tag */
- TotalSize += 2;
-
- /* Add the string buffer size */
- TotalSize += strlen(ProgramName) + 1;
-
- /* Allocate the memory for the environment block */
- DestSegment = DosAllocateMemory((WORD)((TotalSize + 0x0F) >> 4), NULL);
- if (!DestSegment) return 0;
-
- DestBuffer = (PCHAR)SEG_OFF_TO_PTR(DestSegment, 0);
-
- /* If we have an environment strings list, copy it */
- if (Environment)
- {
- Ptr = (PCHAR)Environment;
- while (*Ptr)
- {
- /* Copy the string and NULL-terminate it */
- strcpy(DestBuffer, Ptr);
- DestBuffer += strlen(Ptr);
- *(DestBuffer++) = '\0';
-
- /* Move to the next string */
- Ptr += strlen(Ptr) + 1;
- }
- }
- else
- {
- /* Empty environment string */
- *(DestBuffer++) = '\0';
- }
- /* NULL-terminate the environment block */
- *(DestBuffer++) = '\0';
-
- /* Store the special program name tag */
- *(DestBuffer++) = LOBYTE(DOS_PROGRAM_NAME_TAG);
- *(DestBuffer++) = HIBYTE(DOS_PROGRAM_NAME_TAG);
-
- /* Copy the program name after the environment block */
- strcpy(DestBuffer, ProgramName);
-
- return DestSegment;
-}
static BOOLEAN DosChangeDrive(BYTE Drive)
{
@@ -272,556 +205,13 @@
PspBlock->FarCall[1] = 0x21;
PspBlock->FarCall[2] = 0xCB; // retf
- /* Set the command line */
- PspBlock->CommandLineSize = (BYTE)min(strlen(CommandLine), DOS_CMDLINE_LENGTH -
1);
- RtlCopyMemory(PspBlock->CommandLine, CommandLine, PspBlock->CommandLineSize);
- PspBlock->CommandLine[PspBlock->CommandLineSize] = '\r';
-}
-
-DWORD DosLoadExecutable(IN DOS_EXEC_TYPE LoadType,
- IN LPCSTR ExecutablePath,
- IN LPCSTR CommandLine,
- IN LPCSTR Environment OPTIONAL,
- IN DWORD ReturnAddress OPTIONAL,
- OUT PDWORD StackLocation OPTIONAL,
- OUT PDWORD EntryPoint OPTIONAL)
-{
- DWORD Result = ERROR_SUCCESS;
- HANDLE FileHandle = INVALID_HANDLE_VALUE, FileMapping = NULL;
- LPBYTE Address = NULL;
- WORD Segment = 0;
- WORD EnvBlock = 0;
- WORD MaxAllocSize;
- WORD ExeSegment;
- DWORD i, FileSize, BaseSize, TotalSize;
- PIMAGE_DOS_HEADER Header;
- PDWORD RelocationTable;
- PWORD RelocWord;
- LPSTR CmdLinePtr = (LPSTR)CommandLine;
- BOOLEAN LoadHigh = FALSE;
-
- DPRINT1("DosLoadExecutable(%d, %s, %s, %s, 0x%08X, 0x%08X)\n",
- LoadType,
- ExecutablePath,
- CommandLine,
- Environment ? Environment : "n/a",
- StackLocation,
- EntryPoint);
-
- if (LoadType == DOS_LOAD_OVERLAY)
+ if (CommandLine)
{
- DPRINT1("Overlay loading is not supported yet.\n");
- return ERROR_NOT_SUPPORTED;
+ /* Set the command line */
+ PspBlock->CommandLineSize = (BYTE)min(strlen(CommandLine), DOS_CMDLINE_LENGTH
- 1);
+ RtlCopyMemory(PspBlock->CommandLine, CommandLine,
PspBlock->CommandLineSize);
+ PspBlock->CommandLine[PspBlock->CommandLineSize] = '\r';
}
-
- /* NULL-terminate the command line by removing the return carriage character */
- while (*CmdLinePtr && *CmdLinePtr != '\r') CmdLinePtr++;
- *CmdLinePtr = '\0';
-
- /* 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;
- }
-
- /* 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 */
- if (Address[0] == 'M' && Address[1] == 'Z')
- {
- /* EXE file */
-
- /* Get the MZ header */
- Header = (PIMAGE_DOS_HEADER)Address;
-
- /* Get the base size of the file, in paragraphs (rounded up) */
- BaseSize = TotalSize = (((Header->e_cp - 1) * 512) + Header->e_cblp + 0x0F)
>> 4;
-
- /* Add the PSP size, in paragraphs */
- TotalSize += sizeof(DOS_PSP) >> 4;
-
- /* Add the maximum size that should be allocated */
- TotalSize += Header->e_maxalloc;
-
- if (Header->e_minalloc == 0 && Header->e_maxalloc == 0)
- {
- /* This program should be loaded high */
- LoadHigh = TRUE;
- TotalSize = 0xFFFF;
- }
-
- /* Make sure it does not pass 0xFFFF */
- if (TotalSize > 0xFFFF) TotalSize = 0xFFFF;
-
- /* Try to allocate that much memory */
- Segment = DosAllocateMemory((WORD)TotalSize, &MaxAllocSize);
-
- if (Segment == 0)
- {
- /* Check if there's at least enough memory for the minimum size */
- if (MaxAllocSize < (BaseSize + (sizeof(DOS_PSP) >> 4) +
Header->e_minalloc))
- {
- Result = DosLastError;
- goto Cleanup;
- }
-
- /* Allocate that minimum amount */
- TotalSize = MaxAllocSize;
- Segment = DosAllocateMemory((WORD)TotalSize, NULL);
- ASSERT(Segment != 0);
- }
-
- /* Initialize the PSP */
- DosInitializePsp(Segment,
- CommandLine,
- (WORD)TotalSize,
- EnvBlock,
- ReturnAddress);
-
- /* The process owns its own memory */
- DosChangeMemoryOwner(Segment, Segment);
- DosChangeMemoryOwner(EnvBlock, Segment);
-
- /* Find the EXE segment */
- if (!LoadHigh) ExeSegment = Segment + (sizeof(DOS_PSP) >> 4);
- else ExeSegment = Segment + TotalSize - BaseSize;
-
- /* Copy the program to the code segment */
- RtlCopyMemory(SEG_OFF_TO_PTR(ExeSegment, 0),
- Address + (Header->e_cparhdr << 4),
- min(FileSize - (Header->e_cparhdr << 4), BaseSize <<
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)SEG_OFF_TO_PTR(ExeSegment + HIWORD(RelocationTable[i]),
- LOWORD(RelocationTable[i]));
-
- /* Add the number of the EXE segment to it */
- *RelocWord += ExeSegment;
- }
-
- if (LoadType == DOS_LOAD_AND_EXECUTE)
- {
- /* Set the initial segment registers */
- setDS(Segment);
- setES(Segment);
-
- /* Set the stack to the location from the header */
- setSS(ExeSegment + Header->e_ss);
- setSP(Header->e_sp);
-
- /* Execute */
- CurrentPsp = Segment;
- DiskTransferArea = MAKELONG(0x80, Segment);
- CpuExecute(ExeSegment + Header->e_cs, Header->e_ip);
- }
- }
- else
- {
- /* COM file */
-
- /* Find the maximum amount of memory that can be allocated */
- DosAllocateMemory(0xFFFF, &MaxAllocSize);
-
- /* Make sure it's enough for the whole program and the PSP */
- 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)
- {
- Result = DosLastError;
- goto Cleanup;
- }
-
- /* The process owns its own memory */
- DosChangeMemoryOwner(Segment, Segment);
- DosChangeMemoryOwner(EnvBlock, Segment);
-
- /* Copy the program to Segment:0100 */
- RtlCopyMemory(SEG_OFF_TO_PTR(Segment, 0x100),
- Address,
- FileSize);
-
- /* Initialize the PSP */
- DosInitializePsp(Segment,
- CommandLine,
- MaxAllocSize,
- EnvBlock,
- ReturnAddress);
-
- 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 */
- 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;
-
- /* Execute */
- CurrentPsp = Segment;
- DiskTransferArea = MAKELONG(0x80, Segment);
- CpuExecute(Segment, 0x100);
- }
- }
-
-Cleanup:
- if (Result != ERROR_SUCCESS)
- {
- /* It was not successful, cleanup the DOS memory */
- if (EnvBlock) DosFreeMemory(EnvBlock);
- if (Segment) DosFreeMemory(Segment);
- }
-
- /* Unmap the file*/
- if (Address != NULL) UnmapViewOfFile(Address);
-
- /* Close the file mapping object */
- if (FileMapping != NULL) CloseHandle(FileMapping);
-
- /* Close the file handle */
- if (FileHandle != INVALID_HANDLE_VALUE) CloseHandle(FileHandle);
-
- return Result;
-}
-
-DWORD DosStartProcess(IN LPCSTR ExecutablePath,
- IN LPCSTR CommandLine,
- IN LPCSTR Environment OPTIONAL)
-{
- DWORD Result;
- LPDWORD IntVecTable = (LPDWORD)((ULONG_PTR)BaseAddress);
-
- Result = DosLoadExecutable(DOS_LOAD_AND_EXECUTE,
- ExecutablePath,
- CommandLine,
- Environment,
- IntVecTable[0x20], // Use INT 20h
- NULL,
- NULL);
-
- if (Result != ERROR_SUCCESS) goto Quit;
-
- /* Attach to the console */
- ConsoleAttach();
- VidBiosAttachToConsole();
-
- // HACK: Simulate a ENTER key release scancode on the PS/2 port because
- // some apps expect to read a key release scancode (> 0x80) when they
- // are started.
- IOWriteB(PS2_CONTROL_PORT, 0xD2); // Next write is for the first PS/2 port
- IOWriteB(PS2_DATA_PORT, 0x80 | 0x1C); // ENTER key release
-
- /* Start simulation */
- SetEvent(VdmTaskEvent);
- CpuSimulate();
-
- /* Detach from the console */
- VidBiosDetachFromConsole();
- ConsoleDetach();
-
-Quit:
- return Result;
-}
-
-#ifndef STANDALONE
-WORD DosCreateProcess(DOS_EXEC_TYPE LoadType,
- LPCSTR ProgramName,
- PDOS_EXEC_PARAM_BLOCK Parameters,
- DWORD ReturnAddress)
-{
- DWORD Result;
- 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];
- ULONG EnvSize = 256;
- PVOID Env = RtlAllocateHeap(RtlGetProcessHeap(), HEAP_ZERO_MEMORY, EnvSize);
- 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 */
- RtlZeroMemory(&StartupInfo, sizeof(StartupInfo));
- StartupInfo.cb = sizeof(StartupInfo);
-
- /* 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 */
- RtlZeroMemory(&CommandInfo, sizeof(CommandInfo));
-
- /* Initialize the structure members */
- CommandInfo.TaskId = SessionId;
- CommandInfo.VDMState = VDM_FLAG_NESTED_TASK | VDM_FLAG_DONT_WAIT;
- 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 = EnvSize;
-
-Command:
- /* Get the VDM command information */
- if (!GetNextVDMCommand(&CommandInfo))
- {
- if (CommandInfo.EnvLen > EnvSize)
- {
- /* Expand the environment size */
- EnvSize = CommandInfo.EnvLen;
- CommandInfo.Env = Env = RtlReAllocateHeap(RtlGetProcessHeap(),
HEAP_ZERO_MEMORY, Env, EnvSize);
-
- /* Repeat the request */
- CommandInfo.VDMState |= VDM_FLAG_RETRY;
- goto Command;
- }
-
- /* Shouldn't happen */
- ASSERT(FALSE);
- }
-
- /* Load the executable */
- Result = DosLoadExecutable(LoadType,
- AppName,
- CmdLine,
- Env,
- ReturnAddress,
- &Parameters->StackLocation,
- &Parameters->EntryPoint);
- if (Result == ERROR_SUCCESS)
- {
- /* Increment the re-entry count */
- CommandInfo.VDMState = VDM_INC_REENTER_COUNT;
- GetNextVDMCommand(&CommandInfo);
- }
- else
- {
- DisplayMessage(L"Could not load '%S'. Error: %u",
AppName, Result);
- }
-
- break;
- }
-
- /* Not handled by NTVDM */
- default:
- {
- /* Wait for the process to finish executing */
- WaitForSingleObject(ProcessInfo.hProcess, INFINITE);
- }
- }
-
- RtlFreeHeap(RtlGetProcessHeap(), 0, Env);
-
- /* Close the handles */
- CloseHandle(ProcessInfo.hProcess);
- CloseHandle(ProcessInfo.hThread);
-
- return ERROR_SUCCESS;
-}
-#endif
-
-VOID DosTerminateProcess(WORD Psp, BYTE ReturnCode, WORD KeepResident)
-{
- WORD i;
- WORD McbSegment = FIRST_MCB_SEGMENT;
- PDOS_MCB CurrentMcb;
- LPDWORD IntVecTable = (LPDWORD)((ULONG_PTR)BaseAddress);
- PDOS_PSP PspBlock = SEGMENT_TO_PSP(Psp);
-
- DPRINT("DosTerminateProcess: Psp 0x%04X, ReturnCode 0x%02X, KeepResident
0x%04X\n",
- Psp,
- ReturnCode,
- KeepResident);
-
- /* Check if this PSP is it's own parent */
- if (PspBlock->ParentPsp == Psp) goto Done;
-
- if (KeepResident == 0)
- {
- for (i = 0; i < PspBlock->HandleTableSize; i++)
- {
- /* Close the handle */
- DosCloseHandle(i);
- }
- }
-
- /* Free the memory used by the process */
- while (TRUE)
- {
- /* Get a pointer to the MCB */
- CurrentMcb = SEGMENT_TO_MCB(McbSegment);
-
- /* Make sure the MCB is valid */
- if (CurrentMcb->BlockType != 'M' && CurrentMcb->BlockType
!= 'Z') break;
-
- /* Check if this block was allocated by the process */
- if (CurrentMcb->OwnerPsp == Psp)
- {
- if (KeepResident == 0)
- {
- /* Free this entire block */
- DosFreeMemory(McbSegment + 1);
- }
- else if (KeepResident < CurrentMcb->Size)
- {
- /* Reduce the size of the block */
- DosResizeMemory(McbSegment + 1, KeepResident, NULL);
-
- /* No further paragraphs need to stay resident */
- KeepResident = 0;
- }
- else
- {
- /* Just reduce the amount of paragraphs we need to keep resident */
- KeepResident -= CurrentMcb->Size;
- }
- }
-
- /* If this was the last block, quit */
- if (CurrentMcb->BlockType == 'Z') break;
-
- /* Update the segment and continue */
- McbSegment += CurrentMcb->Size + 1;
- }
-
-Done:
- /* Restore the interrupt vectors */
- IntVecTable[0x22] = PspBlock->TerminateAddress;
- IntVecTable[0x23] = PspBlock->BreakAddress;
- IntVecTable[0x24] = PspBlock->CriticalAddress;
-
- /* Update the current PSP */
- if (Psp == CurrentPsp)
- {
- CurrentPsp = PspBlock->ParentPsp;
- if (CurrentPsp == SYSTEM_PSP)
- {
- ResetEvent(VdmTaskEvent);
- CpuUnsimulate();
- }
- }
-
-#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);
- }
-#endif
-
- /* Save the return code - Normal termination */
- DosErrorLevel = MAKEWORD(ReturnCode, 0x00);
-
- /* Return control to the parent process */
- CpuExecute(HIWORD(PspBlock->TerminateAddress),
- LOWORD(PspBlock->TerminateAddress));
}
VOID WINAPI DosInt20h(LPWORD Stack)
@@ -1205,7 +595,7 @@
/* Create New PSP */
case 0x26:
{
- DPRINT1("INT 21h, AH = 26h - Create New PSP is UNIMPLEMENTED\n");
+ DosClonePsp(getDX(), getCS());
break;
}
@@ -1963,7 +1353,6 @@
break;
}
-#ifndef STANDALONE
/* Execute */
case 0x4B:
{
@@ -1973,19 +1362,24 @@
DWORD ReturnAddress = MAKELONG(Stack[STACK_IP], Stack[STACK_CS]);
WORD ErrorCode;
- if (LoadType != DOS_LOAD_OVERLAY)
- {
- ErrorCode = DosCreateProcess(LoadType, ProgramName, ParamBlock,
ReturnAddress);
- }
- else
- {
- ErrorCode = DosLoadExecutable(DOS_LOAD_OVERLAY,
+#ifndef STANDALONE
+ if (LoadType == DOS_LOAD_AND_EXECUTE)
+ {
+ /* Create a new process */
+ ErrorCode = DosCreateProcess(ProgramName, ParamBlock, ReturnAddress);
+ }
+ else
+ {
+#else
+ {
+#endif
+ /* Just load an executable */
+ ErrorCode = DosLoadExecutable(LoadType,
ProgramName,
- FAR_POINTER(ParamBlock->CommandLine),
- SEG_OFF_TO_PTR(ParamBlock->Environment,
0),
- ReturnAddress,
+ ParamBlock,
NULL,
- NULL);
+ NULL,
+ ReturnAddress);
}
if (ErrorCode == ERROR_SUCCESS)
@@ -2000,7 +1394,6 @@
break;
}
-#endif
/* Terminate With Return Code */
case 0x4C:
@@ -2057,8 +1450,7 @@
/* Internal - Set Current Process ID (Set PSP Address) */
case 0x50:
{
- // FIXME: Is it really what it's done ??
- CurrentPsp = getBX();
+ DosSetProcessContext(getBX());
break;
}
@@ -2090,6 +1482,13 @@
setES(DOS_DATA_SEGMENT);
setBX(FIELD_OFFSET(DOS_SYSVARS, FirstDpb));
+ break;
+ }
+
+ /* Create Child PSP */
+ case 0x55:
+ {
+ DosCreatePsp(getDX(), getSI());
break;
}
Modified: trunk/reactos/subsystems/mvdm/ntvdm/dos/dos32krnl/dos.h
URL:
http://svn.reactos.org/svn/reactos/trunk/reactos/subsystems/mvdm/ntvdm/dos/…
==============================================================================
--- trunk/reactos/subsystems/mvdm/ntvdm/dos/dos32krnl/dos.h [iso-8859-1] (original)
+++ trunk/reactos/subsystems/mvdm/ntvdm/dos/dos32krnl/dos.h [iso-8859-1] Fri May 1
15:42:54 2015
@@ -39,27 +39,16 @@
#define DOS_ERROR_HANDLE 2
#define DOS_SFT_SIZE 255
-#define SEGMENT_TO_MCB(seg) ((PDOS_MCB)((ULONG_PTR)BaseAddress + TO_LINEAR((seg), 0)))
-#define SEGMENT_TO_PSP(seg) ((PDOS_PSP)((ULONG_PTR)BaseAddress + TO_LINEAR((seg), 0)))
#define UMB_START_SEGMENT 0xC000
#define UMB_END_SEGMENT 0xDFFF
#define DOS_ALLOC_HIGH 0x40
#define DOS_ALLOC_HIGH_LOW 0x80
-#define DOS_CMDLINE_LENGTH 127
#define DOS_DIR_LENGTH 64
#define NUM_DRIVES ('Z' - 'A' + 1)
#define DOS_CHAR_ATTRIBUTE 0x07
-#define DOS_PROGRAM_NAME_TAG 0x0001
/* 16 MB of EMS memory */
#define EMS_TOTAL_PAGES 1024
-
-typedef enum
-{
- DOS_LOAD_AND_EXECUTE = 0x00,
- DOS_LOAD_ONLY = 0x01,
- DOS_LOAD_OVERLAY = 0x03
-} DOS_EXEC_TYPE;
#pragma pack(push, 1)
@@ -102,31 +91,6 @@
BYTE NullDriverRoutine[7];
} DOS_SYSVARS, *PDOS_SYSVARS;
-typedef struct _DOS_PSP
-{
- BYTE Exit[2];
- WORD LastParagraph;
- BYTE Reserved0[6];
- DWORD TerminateAddress;
- DWORD BreakAddress;
- DWORD CriticalAddress;
- WORD ParentPsp;
- BYTE HandleTable[20];
- WORD EnvBlock;
- DWORD LastStack;
- WORD HandleTableSize;
- DWORD HandleTablePtr;
- DWORD PreviousPsp;
- DWORD Reserved1;
- WORD DosVersion;
- BYTE Reserved2[14];
- BYTE FarCall[3];
- BYTE Reserved3[9];
- DOS_FCB Fcb;
- BYTE CommandLineSize;
- CHAR CommandLine[DOS_CMDLINE_LENGTH];
-} DOS_PSP, *PDOS_PSP;
-
typedef struct _DOS_INPUT_BUFFER
{
BYTE MaxLength;
@@ -150,19 +114,6 @@
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;
-
typedef struct _DOS_COUNTRY_CODE_BUFFER
{
WORD TimeFormat;
@@ -176,7 +127,8 @@
/* VARIABLES ******************************************************************/
extern BOOLEAN DoEcho;
-extern WORD CurrentPsp;
+extern DWORD DiskTransferArea;
+extern WORD DosErrorLevel;
extern WORD DosLastError;
extern PDOS_SYSVARS SysVars;
@@ -207,36 +159,6 @@
* See dos.c
*/
-VOID DosInitializePsp(
- WORD PspSegment,
- LPCSTR CommandLine,
- WORD ProgramSize,
- WORD Environment,
- DWORD ReturnAddress
-);
-DWORD DosLoadExecutable(
- IN DOS_EXEC_TYPE LoadType,
- IN LPCSTR ExecutablePath,
- IN LPCSTR CommandLine,
- IN LPCSTR Environment OPTIONAL,
- IN DWORD ReturnAddress OPTIONAL,
- OUT PDWORD StackLocation OPTIONAL,
- OUT PDWORD EntryPoint OPTIONAL
-);
-WORD DosCreateProcess(
- DOS_EXEC_TYPE LoadType,
- LPCSTR ProgramName,
- PDOS_EXEC_PARAM_BLOCK Parameters,
- DWORD ReturnAddress
-);
-DWORD DosStartProcess(
- IN LPCSTR ExecutablePath,
- IN LPCSTR CommandLine,
- IN LPCSTR Environment OPTIONAL
-);
-VOID DosTerminateProcess(WORD Psp, BYTE ReturnCode, WORD KeepResident);
-BOOLEAN DosHandleIoctl(BYTE ControlCode, WORD FileHandle);
-
BOOLEAN DosKRNLInitialize(VOID);
#endif // _DOS_H_
Modified: trunk/reactos/subsystems/mvdm/ntvdm/dos/dos32krnl/dosfiles.c
URL:
http://svn.reactos.org/svn/reactos/trunk/reactos/subsystems/mvdm/ntvdm/dos/…
==============================================================================
--- trunk/reactos/subsystems/mvdm/ntvdm/dos/dos32krnl/dosfiles.c [iso-8859-1] (original)
+++ trunk/reactos/subsystems/mvdm/ntvdm/dos/dos32krnl/dosfiles.c [iso-8859-1] Fri May 1
15:42:54 2015
@@ -19,6 +19,7 @@
#include "dos/dem.h"
#include "dosfiles.h"
#include "handle.h"
+#include "process.h"
#include "bios/bios.h"
Modified: trunk/reactos/subsystems/mvdm/ntvdm/dos/dos32krnl/handle.c
URL:
http://svn.reactos.org/svn/reactos/trunk/reactos/subsystems/mvdm/ntvdm/dos/…
==============================================================================
--- trunk/reactos/subsystems/mvdm/ntvdm/dos/dos32krnl/handle.c [iso-8859-1] (original)
+++ trunk/reactos/subsystems/mvdm/ntvdm/dos/dos32krnl/handle.c [iso-8859-1] Fri May 1
15:42:54 2015
@@ -18,6 +18,7 @@
#include "dosfiles.h"
#include "handle.h"
#include "memory.h"
+#include "process.h"
/* PRIVATE FUNCTIONS **********************************************************/
Modified: trunk/reactos/subsystems/mvdm/ntvdm/dos/dos32krnl/memory.c
URL:
http://svn.reactos.org/svn/reactos/trunk/reactos/subsystems/mvdm/ntvdm/dos/…
==============================================================================
--- trunk/reactos/subsystems/mvdm/ntvdm/dos/dos32krnl/memory.c [iso-8859-1] (original)
+++ trunk/reactos/subsystems/mvdm/ntvdm/dos/dos32krnl/memory.c [iso-8859-1] Fri May 1
15:42:54 2015
@@ -12,10 +12,11 @@
#include "ntvdm.h"
#include "emulator.h"
-#include "memory.h"
#include "dos.h"
#include "dos/dem.h"
+#include "memory.h"
+#include "process.h"
/* PUBLIC VARIABLES ***********************************************************/
Modified: trunk/reactos/subsystems/mvdm/ntvdm/dos/dos32krnl/memory.h
URL:
http://svn.reactos.org/svn/reactos/trunk/reactos/subsystems/mvdm/ntvdm/dos/…
==============================================================================
--- trunk/reactos/subsystems/mvdm/ntvdm/dos/dos32krnl/memory.h [iso-8859-1] (original)
+++ trunk/reactos/subsystems/mvdm/ntvdm/dos/dos32krnl/memory.h [iso-8859-1] Fri May 1
15:42:54 2015
@@ -10,6 +10,8 @@
#define _MEMORY_H_
/* TYPEDEFS *******************************************************************/
+
+#define SEGMENT_TO_MCB(seg) ((PDOS_MCB)((ULONG_PTR)BaseAddress + TO_LINEAR((seg), 0)))
enum DOS_ALLOC_STRATEGY
{
Added: 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 (added)
+++ trunk/reactos/subsystems/mvdm/ntvdm/dos/dos32krnl/process.c [iso-8859-1] Fri May 1
15:42:54 2015
@@ -0,0 +1,773 @@
+/*
+ * COPYRIGHT: GPL - See COPYING in the top level directory
+ * PROJECT: ReactOS Virtual DOS Machine
+ * FILE: dos/dos32krnl/process.c
+ * PURPOSE: DOS32 Processes
+ * PROGRAMMERS: Aleksandar Andrejevic <theflash AT sdf DOT lonestar DOT org>
+ * Hermes Belusca-Maito (hermes.belusca(a)sfr.fr)
+ */
+
+/* INCLUDES *******************************************************************/
+
+#define NDEBUG
+
+#include "ntvdm.h"
+#include "emulator.h"
+#include "cpu/cpu.h"
+
+#include "dos.h"
+#include "dos/dem.h"
+#include "dosfiles.h"
+#include "handle.h"
+#include "process.h"
+#include "memory.h"
+
+#include "bios/bios.h"
+
+#include "io.h"
+#include "hardware/ps2.h"
+
+/* PUBLIC VARIABLES ***********************************************************/
+
+WORD CurrentPsp = SYSTEM_PSP;
+
+/* PRIVATE FUNCTIONS **********************************************************/
+
+static inline VOID DosSetPspCommandLine(WORD Segment, LPCSTR CommandLine)
+{
+ PDOS_PSP PspBlock = SEGMENT_TO_PSP(Segment);
+
+ /* Set the command line */
+ PspBlock->CommandLineSize = (BYTE)min(strlen(CommandLine), DOS_CMDLINE_LENGTH -
1);
+ RtlCopyMemory(PspBlock->CommandLine, CommandLine, PspBlock->CommandLineSize);
+ PspBlock->CommandLine[PspBlock->CommandLineSize] = '\r';
+}
+
+static WORD DosCopyEnvironmentBlock(LPCSTR Environment OPTIONAL,
+ LPCSTR ProgramName)
+{
+ PCHAR Ptr, DestBuffer = NULL;
+ ULONG TotalSize = 0;
+ WORD DestSegment;
+
+ /* If we have an environment strings list, compute its size */
+ if (Environment)
+ {
+ /* Calculate the size of the environment block */
+ Ptr = (PCHAR)Environment;
+ while (*Ptr) Ptr += strlen(Ptr) + 1;
+ TotalSize = (ULONG_PTR)Ptr - (ULONG_PTR)Environment;
+ }
+ else
+ {
+ /* Empty environment string */
+ TotalSize = 1;
+ }
+ /* Add the final environment block NULL-terminator */
+ TotalSize++;
+
+ /* Add the two bytes for the program name tag */
+ TotalSize += 2;
+
+ /* Add the string buffer size */
+ TotalSize += strlen(ProgramName) + 1;
+
+ /* Allocate the memory for the environment block */
+ DestSegment = DosAllocateMemory((WORD)((TotalSize + 0x0F) >> 4), NULL);
+ if (!DestSegment) return 0;
+
+ DestBuffer = (PCHAR)SEG_OFF_TO_PTR(DestSegment, 0);
+
+ /* If we have an environment strings list, copy it */
+ if (Environment)
+ {
+ Ptr = (PCHAR)Environment;
+ while (*Ptr)
+ {
+ /* Copy the string and NULL-terminate it */
+ strcpy(DestBuffer, Ptr);
+ DestBuffer += strlen(Ptr);
+ *(DestBuffer++) = '\0';
+
+ /* Move to the next string */
+ Ptr += strlen(Ptr) + 1;
+ }
+ }
+ else
+ {
+ /* Empty environment string */
+ *(DestBuffer++) = '\0';
+ }
+ /* NULL-terminate the environment block */
+ *(DestBuffer++) = '\0';
+
+ /* Store the special program name tag */
+ *(DestBuffer++) = LOBYTE(DOS_PROGRAM_NAME_TAG);
+ *(DestBuffer++) = HIBYTE(DOS_PROGRAM_NAME_TAG);
+
+ /* Copy the program name after the environment block */
+ strcpy(DestBuffer, ProgramName);
+
+ return DestSegment;
+}
+
+/* PUBLIC FUNCTIONS ***********************************************************/
+
+VOID DosClonePsp(WORD DestSegment, WORD SourceSegment)
+{
+ PDOS_PSP DestPsp = SEGMENT_TO_PSP(DestSegment);
+ PDOS_PSP SourcePsp = SEGMENT_TO_PSP(SourceSegment);
+ LPDWORD IntVecTable = (LPDWORD)((ULONG_PTR)BaseAddress);
+
+ /* Literally copy the PSP first */
+ RtlCopyMemory(DestPsp, SourcePsp, sizeof(DOS_PSP));
+
+ /* Save the interrupt vectors */
+ DestPsp->TerminateAddress = IntVecTable[0x22];
+ DestPsp->BreakAddress = IntVecTable[0x23];
+ DestPsp->CriticalAddress = IntVecTable[0x24];
+
+ /* No parent PSP */
+ DestPsp->ParentPsp = 0;
+
+ /* Set the handle table pointers to the internal handle table */
+ DestPsp->HandleTableSize = DEFAULT_JFT_SIZE;
+ DestPsp->HandleTablePtr = MAKELONG(0x18, DestSegment);
+
+ /* Copy the parent handle table without referencing the SFT */
+ RtlCopyMemory(FAR_POINTER(DestPsp->HandleTablePtr),
+ FAR_POINTER(SourcePsp->HandleTablePtr),
+ DEFAULT_JFT_SIZE);
+}
+
+VOID DosCreatePsp(WORD Segment, WORD ProgramSize)
+{
+ PDOS_PSP PspBlock = SEGMENT_TO_PSP(Segment);
+ LPDWORD IntVecTable = (LPDWORD)((ULONG_PTR)BaseAddress);
+
+ RtlZeroMemory(PspBlock, sizeof(*PspBlock));
+
+ /* Set the exit interrupt */
+ PspBlock->Exit[0] = 0xCD; // int 0x20
+ PspBlock->Exit[1] = 0x20;
+
+ /* Set the number of the last paragraph */
+ PspBlock->LastParagraph = Segment + ProgramSize - 1;
+
+ /* Save the interrupt vectors */
+ PspBlock->TerminateAddress = IntVecTable[0x22];
+ PspBlock->BreakAddress = IntVecTable[0x23];
+ PspBlock->CriticalAddress = IntVecTable[0x24];
+
+ /* Set the parent PSP */
+ PspBlock->ParentPsp = CurrentPsp;
+
+ /* No environment block yet */
+ PspBlock->EnvBlock = 0;
+
+ /* Copy the parent handle table */
+ DosCopyHandleTable(PspBlock->HandleTable);
+
+ /* Set the handle table pointers to the internal handle table */
+ PspBlock->HandleTableSize = DEFAULT_JFT_SIZE;
+ PspBlock->HandleTablePtr = MAKELONG(0x18, Segment);
+
+ /* Set the DOS version */
+ PspBlock->DosVersion = DOS_VERSION;
+
+ /* Set the far call opcodes */
+ PspBlock->FarCall[0] = 0xCD; // int 0x21
+ PspBlock->FarCall[1] = 0x21;
+ PspBlock->FarCall[2] = 0xCB; // retf
+}
+
+VOID DosSetProcessContext(WORD Segment)
+{
+ CurrentPsp = Segment;
+ 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 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;
+
+ DPRINT1("DosLoadExecutable(%d, %s, 0x%08X, 0x%08X)\n",
+ LoadType,
+ ExecutablePath,
+ Parameters,
+ ReturnAddress);
+
+ /* 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;
+ }
+
+ if (LoadType != DOS_LOAD_OVERLAY)
+ {
+ LPSTR CmdLinePtr;
+
+ if (CommandLine == NULL)
+ {
+ /* Get the command line from the parameter block */
+ CommandLine = (LPCSTR)FAR_POINTER(Parameters->CommandLine);
+ }
+
+ if (Environment == NULL)
+ {
+ /* Get the environment from the parameter block */
+ Environment = (LPCSTR)SEG_OFF_TO_PTR(Parameters->Environment, 0);
+ }
+
+ /* NULL-terminate the command line by removing the return carriage character */
+ CmdLinePtr = (LPSTR)CommandLine;
+ while (*CmdLinePtr && *CmdLinePtr != '\r') CmdLinePtr++;
+ *CmdLinePtr = '\0';
+
+ /* 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 */
+ if (Address[0] == 'M' && Address[1] == 'Z')
+ {
+ /* EXE file */
+ PIMAGE_DOS_HEADER Header;
+ DWORD BaseSize;
+ PDWORD RelocationTable;
+ PWORD RelocWord;
+ WORD RelocFactor;
+ BOOLEAN LoadHigh = FALSE;
+
+ /* Get the MZ header */
+ Header = (PIMAGE_DOS_HEADER)Address;
+
+ /* Get the base size of the file, in paragraphs (rounded up) */
+ BaseSize = (((Header->e_cp - 1) * 512) + Header->e_cblp + 0x0F) >>
4;
+
+ if (LoadType != DOS_LOAD_OVERLAY)
+ {
+ DWORD TotalSize = BaseSize;
+
+ /* Add the PSP size, in paragraphs */
+ TotalSize += sizeof(DOS_PSP) >> 4;
+
+ /* Add the maximum size that should be allocated */
+ TotalSize += Header->e_maxalloc;
+
+ if (Header->e_minalloc == 0 && Header->e_maxalloc == 0)
+ {
+ /* This program should be loaded high */
+ LoadHigh = TRUE;
+ TotalSize = 0xFFFF;
+ }
+
+ /* Make sure it does not pass 0xFFFF */
+ if (TotalSize > 0xFFFF) TotalSize = 0xFFFF;
+
+ /* Try to allocate that much memory */
+ Segment = DosAllocateMemory((WORD)TotalSize, &MaxAllocSize);
+
+ if (Segment == 0)
+ {
+ /* Check if there's at least enough memory for the minimum size */
+ if (MaxAllocSize < (BaseSize + (sizeof(DOS_PSP) >> 4) +
Header->e_minalloc))
+ {
+ Result = DosLastError;
+ goto Cleanup;
+ }
+
+ /* Allocate that minimum amount */
+ TotalSize = MaxAllocSize;
+ Segment = DosAllocateMemory((WORD)TotalSize, NULL);
+ ASSERT(Segment != 0);
+ }
+
+ /* The process owns its own memory */
+ DosChangeMemoryOwner(Segment, Segment);
+ DosChangeMemoryOwner(EnvBlock, Segment);
+
+ /* Set INT 22h to the return address */
+ ((PULONG)BaseAddress)[0x22] = ReturnAddress;
+
+ /* Create the PSP */
+ DosCreatePsp(Segment, (WORD)TotalSize);
+ DosSetPspCommandLine(Segment, CommandLine);
+ SEGMENT_TO_PSP(Segment)->EnvBlock = EnvBlock;
+
+ /* Calculate the segment where the program should be loaded */
+ if (!LoadHigh) LoadSegment = Segment + (sizeof(DOS_PSP) >> 4);
+ else LoadSegment = Segment + TotalSize - BaseSize;
+
+ RelocFactor = LoadSegment;
+ }
+ else
+ {
+ LoadSegment = Parameters->Overlay.Segment;
+ RelocFactor = Parameters->Overlay.RelocationFactor;
+ }
+
+ /* 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));
+
+ /* 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)SEG_OFF_TO_PTR(LoadSegment + HIWORD(RelocationTable[i]),
+ LOWORD(RelocationTable[i]));
+
+ /* Add the relocation factor to it */
+ *RelocWord += RelocFactor;
+ }
+
+ if (LoadType == DOS_LOAD_AND_EXECUTE)
+ {
+ /* 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);
+
+ /* Execute */
+ DosSetProcessContext(Segment);
+ CpuExecute(LoadSegment + Header->e_cs, Header->e_ip);
+ }
+ else if (LoadType == DOS_LOAD_ONLY)
+ {
+ Parameters->StackLocation = MAKELONG(Header->e_sp, LoadSegment +
Header->e_ss);
+ Parameters->EntryPoint = MAKELONG(Header->e_ip, LoadSegment +
Header->e_cs);
+ }
+ }
+ else
+ {
+ /* COM file */
+
+ if (LoadType != DOS_LOAD_OVERLAY)
+ {
+ /* Find the maximum amount of memory that can be allocated */
+ DosAllocateMemory(0xFFFF, &MaxAllocSize);
+
+ /* Make sure it's enough for the whole program and the PSP */
+ 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)
+ {
+ Result = DosLastError;
+ goto Cleanup;
+ }
+
+ /* The process owns its own memory */
+ DosChangeMemoryOwner(Segment, Segment);
+ DosChangeMemoryOwner(EnvBlock, Segment);
+
+ /* Set INT 22h to the return address */
+ ((PULONG)BaseAddress)[0x22] = ReturnAddress;
+
+ /* Create the PSP */
+ DosCreatePsp(Segment, MaxAllocSize);
+ DosSetPspCommandLine(Segment, CommandLine);
+ SEGMENT_TO_PSP(Segment)->EnvBlock = EnvBlock;
+
+ /* Calculate the segment where the program should be loaded */
+ LoadSegment = Segment + (sizeof(DOS_PSP) >> 4);
+ }
+ else
+ {
+ LoadSegment = Parameters->Overlay.Segment;
+ }
+
+ RtlCopyMemory(SEG_OFF_TO_PTR(LoadSegment, 0),
+ Address,
+ FileSize);
+
+ 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 */
+ 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;
+
+ /* Execute */
+ DosSetProcessContext(Segment);
+ CpuExecute(Segment, 0x100);
+ }
+ else if (LoadType == DOS_LOAD_ONLY)
+ {
+ Parameters->StackLocation = MAKELONG(0xFFFE, Segment);
+ Parameters->EntryPoint = MAKELONG(0x0100, Segment);
+ }
+ }
+
+Cleanup:
+ if (Result != ERROR_SUCCESS)
+ {
+ /* It was not successful, cleanup the DOS memory */
+ if (EnvBlock) DosFreeMemory(EnvBlock);
+ if (Segment) DosFreeMemory(Segment);
+ }
+
+ /* Unmap the file*/
+ if (Address != NULL) UnmapViewOfFile(Address);
+
+ /* Close the file mapping object */
+ if (FileMapping != NULL) CloseHandle(FileMapping);
+
+ /* Close the file handle */
+ if (FileHandle != INVALID_HANDLE_VALUE) CloseHandle(FileHandle);
+
+ return Result;
+}
+
+DWORD DosStartProcess(IN LPCSTR ExecutablePath,
+ IN LPCSTR CommandLine,
+ IN LPCSTR Environment OPTIONAL)
+{
+ DWORD Result;
+ LPDWORD IntVecTable = (LPDWORD)((ULONG_PTR)BaseAddress);
+
+ Result = DosLoadExecutable(DOS_LOAD_AND_EXECUTE,
+ ExecutablePath,
+ NULL,
+ CommandLine,
+ Environment,
+ IntVecTable[0x20]);
+
+ if (Result != ERROR_SUCCESS) goto Quit;
+
+ /* Attach to the console */
+ ConsoleAttach();
+ VidBiosAttachToConsole();
+
+ // HACK: Simulate a ENTER key release scancode on the PS/2 port because
+ // some apps expect to read a key release scancode (> 0x80) when they
+ // are started.
+ IOWriteB(PS2_CONTROL_PORT, 0xD2); // Next write is for the first PS/2 port
+ IOWriteB(PS2_DATA_PORT, 0x80 | 0x1C); // ENTER key release
+
+ /* Start simulation */
+ SetEvent(VdmTaskEvent);
+ CpuSimulate();
+
+ /* Detach from the console */
+ VidBiosDetachFromConsole();
+ ConsoleDetach();
+
+Quit:
+ return Result;
+}
+
+#ifndef STANDALONE
+WORD DosCreateProcess(LPCSTR ProgramName,
+ PDOS_EXEC_PARAM_BLOCK Parameters,
+ DWORD ReturnAddress)
+{
+ DWORD Result;
+ 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];
+ ULONG EnvSize = 256;
+ PVOID Env = RtlAllocateHeap(RtlGetProcessHeap(), HEAP_ZERO_MEMORY, EnvSize);
+ 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 */
+ RtlZeroMemory(&StartupInfo, sizeof(StartupInfo));
+ StartupInfo.cb = sizeof(StartupInfo);
+
+ /* 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 */
+ RtlZeroMemory(&CommandInfo, sizeof(CommandInfo));
+
+ /* Initialize the structure members */
+ CommandInfo.TaskId = SessionId;
+ CommandInfo.VDMState = VDM_FLAG_NESTED_TASK | VDM_FLAG_DONT_WAIT;
+ 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 = EnvSize;
+
+Command:
+ /* Get the VDM command information */
+ if (!GetNextVDMCommand(&CommandInfo))
+ {
+ if (CommandInfo.EnvLen > EnvSize)
+ {
+ /* Expand the environment size */
+ EnvSize = CommandInfo.EnvLen;
+ CommandInfo.Env = Env = RtlReAllocateHeap(RtlGetProcessHeap(),
HEAP_ZERO_MEMORY, Env, EnvSize);
+
+ /* Repeat the request */
+ CommandInfo.VDMState |= VDM_FLAG_RETRY;
+ goto Command;
+ }
+
+ /* Shouldn't happen */
+ ASSERT(FALSE);
+ }
+
+ /* Load the executable */
+ Result = DosLoadExecutable(DOS_LOAD_AND_EXECUTE,
+ AppName,
+ Parameters,
+ CmdLine,
+ Env,
+ ReturnAddress);
+ if (Result == ERROR_SUCCESS)
+ {
+ /* Increment the re-entry count */
+ CommandInfo.VDMState = VDM_INC_REENTER_COUNT;
+ GetNextVDMCommand(&CommandInfo);
+ }
+ else
+ {
+ DisplayMessage(L"Could not load '%S'. Error: %u",
AppName, Result);
+ }
+
+ break;
+ }
+
+ /* Not handled by NTVDM */
+ default:
+ {
+ /* Wait for the process to finish executing */
+ WaitForSingleObject(ProcessInfo.hProcess, INFINITE);
+ }
+ }
+
+ RtlFreeHeap(RtlGetProcessHeap(), 0, Env);
+
+ /* Close the handles */
+ CloseHandle(ProcessInfo.hProcess);
+ CloseHandle(ProcessInfo.hThread);
+
+ return ERROR_SUCCESS;
+}
+#endif
+
+VOID DosTerminateProcess(WORD Psp, BYTE ReturnCode, WORD KeepResident)
+{
+ WORD i;
+ WORD McbSegment = FIRST_MCB_SEGMENT;
+ PDOS_MCB CurrentMcb;
+ LPDWORD IntVecTable = (LPDWORD)((ULONG_PTR)BaseAddress);
+ PDOS_PSP PspBlock = SEGMENT_TO_PSP(Psp);
+
+ DPRINT("DosTerminateProcess: Psp 0x%04X, ReturnCode 0x%02X, KeepResident
0x%04X\n",
+ Psp,
+ ReturnCode,
+ KeepResident);
+
+ /* Check if this PSP is it's own parent */
+ if (PspBlock->ParentPsp == Psp) goto Done;
+
+ if (KeepResident == 0)
+ {
+ for (i = 0; i < PspBlock->HandleTableSize; i++)
+ {
+ /* Close the handle */
+ DosCloseHandle(i);
+ }
+ }
+
+ /* Free the memory used by the process */
+ while (TRUE)
+ {
+ /* Get a pointer to the MCB */
+ CurrentMcb = SEGMENT_TO_MCB(McbSegment);
+
+ /* Make sure the MCB is valid */
+ if (CurrentMcb->BlockType != 'M' && CurrentMcb->BlockType
!= 'Z') break;
+
+ /* Check if this block was allocated by the process */
+ if (CurrentMcb->OwnerPsp == Psp)
+ {
+ if (KeepResident == 0)
+ {
+ /* Free this entire block */
+ DosFreeMemory(McbSegment + 1);
+ }
+ else if (KeepResident < CurrentMcb->Size)
+ {
+ /* Reduce the size of the block */
+ DosResizeMemory(McbSegment + 1, KeepResident, NULL);
+
+ /* No further paragraphs need to stay resident */
+ KeepResident = 0;
+ }
+ else
+ {
+ /* Just reduce the amount of paragraphs we need to keep resident */
+ KeepResident -= CurrentMcb->Size;
+ }
+ }
+
+ /* If this was the last block, quit */
+ if (CurrentMcb->BlockType == 'Z') break;
+
+ /* Update the segment and continue */
+ McbSegment += CurrentMcb->Size + 1;
+ }
+
+Done:
+ /* Restore the interrupt vectors */
+ IntVecTable[0x22] = PspBlock->TerminateAddress;
+ IntVecTable[0x23] = PspBlock->BreakAddress;
+ IntVecTable[0x24] = PspBlock->CriticalAddress;
+
+ /* Update the current PSP */
+ if (Psp == CurrentPsp)
+ {
+ CurrentPsp = PspBlock->ParentPsp;
+ if (CurrentPsp == SYSTEM_PSP)
+ {
+ ResetEvent(VdmTaskEvent);
+ CpuUnsimulate();
+ }
+ }
+
+#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);
+ }
+#endif
+
+ /* Save the return code - Normal termination */
+ DosErrorLevel = MAKEWORD(ReturnCode, 0x00);
+
+ /* Return control to the parent process */
+ CpuExecute(HIWORD(PspBlock->TerminateAddress),
+ LOWORD(PspBlock->TerminateAddress));
+}
+
Propchange: trunk/reactos/subsystems/mvdm/ntvdm/dos/dos32krnl/process.c
------------------------------------------------------------------------------
svn:eol-style = native
Added: 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 (added)
+++ trunk/reactos/subsystems/mvdm/ntvdm/dos/dos32krnl/process.h [iso-8859-1] Fri May 1
15:42:54 2015
@@ -0,0 +1,110 @@
+/*
+ * COPYRIGHT: GPLv2 - See COPYING in the top level directory
+ * PROJECT: ReactOS Virtual DOS Machine
+ * FILE: dos/dos32krnl/process.h
+ * PURPOSE: DOS32 Processes
+ * PROGRAMMERS: Aleksandar Andrejevic <theflash AT sdf DOT lonestar DOT org>
+ */
+
+/* DEFINITIONS ****************************************************************/
+
+#define DOS_CMDLINE_LENGTH 127
+#define DOS_PROGRAM_NAME_TAG 0x0001
+
+#define SEGMENT_TO_PSP(seg) ((PDOS_PSP)((ULONG_PTR)BaseAddress + TO_LINEAR((seg), 0)))
+
+typedef enum
+{
+ DOS_LOAD_AND_EXECUTE = 0x00,
+ DOS_LOAD_ONLY = 0x01,
+ DOS_LOAD_OVERLAY = 0x03
+} DOS_EXEC_TYPE;
+
+#pragma pack(push, 1)
+
+typedef struct _DOS_PSP
+{
+ BYTE Exit[2];
+ WORD LastParagraph;
+ BYTE Reserved0[6];
+ DWORD TerminateAddress;
+ DWORD BreakAddress;
+ DWORD CriticalAddress;
+ WORD ParentPsp;
+ BYTE HandleTable[20];
+ WORD EnvBlock;
+ DWORD LastStack;
+ WORD HandleTableSize;
+ DWORD HandleTablePtr;
+ DWORD PreviousPsp;
+ DWORD Reserved1;
+ WORD DosVersion;
+ BYTE Reserved2[14];
+ BYTE FarCall[3];
+ BYTE Reserved3[9];
+ DOS_FCB Fcb;
+ BYTE CommandLineSize;
+ CHAR CommandLine[DOS_CMDLINE_LENGTH];
+} DOS_PSP, *PDOS_PSP;
+
+typedef struct _DOS_EXEC_PARAM_BLOCK
+{
+ union
+ {
+ struct
+ {
+ /* Input variables */
+ WORD Environment;
+ DWORD CommandLine;
+ DWORD FirstFcb;
+ DWORD SecondFcb;
+
+ /* Output variables */
+ DWORD StackLocation;
+ DWORD EntryPoint;
+ };
+
+ struct
+ {
+ WORD Segment;
+ WORD RelocationFactor;
+ } Overlay;
+ };
+} DOS_EXEC_PARAM_BLOCK, *PDOS_EXEC_PARAM_BLOCK;
+
+#pragma pack(pop)
+
+/* VARIABLES ******************************************************************/
+
+extern WORD CurrentPsp;
+
+/* FUNCTIONS ******************************************************************/
+
+VOID DosClonePsp(WORD DestSegment, WORD SourceSegment);
+VOID DosCreatePsp(WORD Segment, WORD ProgramSize);
+VOID DosSetProcessContext(WORD 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 DosStartProcess(
+ IN LPCSTR ExecutablePath,
+ IN LPCSTR CommandLine,
+ IN LPCSTR Environment OPTIONAL
+);
+
+WORD DosCreateProcess
+(
+ LPCSTR ProgramName,
+ PDOS_EXEC_PARAM_BLOCK Parameters,
+ DWORD ReturnAddress
+);
+
+VOID DosTerminateProcess(WORD Psp, BYTE ReturnCode, WORD KeepResident);
Propchange: trunk/reactos/subsystems/mvdm/ntvdm/dos/dos32krnl/process.h
------------------------------------------------------------------------------
svn:eol-style = native