Git conversion: Make reactos the root directory, move rosapps, rostests, wallpapers...
[reactos.git] / reactos / subsystems / mvdm / ntvdm / dos / dos32krnl / process.c
diff --git a/reactos/subsystems/mvdm/ntvdm/dos/dos32krnl/process.c b/reactos/subsystems/mvdm/ntvdm/dos/dos32krnl/process.c
deleted file mode 100644 (file)
index 01291b4..0000000
+++ /dev/null
@@ -1,981 +0,0 @@
-/*
- * COPYRIGHT:       GPL - See COPYING in the top level directory
- * PROJECT:         ReactOS Virtual DOS Machine
- * FILE:            subsystems/mvdm/ntvdm/dos/dos32krnl/process.c
- * PURPOSE:         DOS32 Processes
- * PROGRAMMERS:     Aleksandar Andrejevic <theflash AT sdf DOT lonestar DOT org>
- *                  Hermes Belusca-Maito (hermes.belusca@sfr.fr)
- */
-
-/* INCLUDES *******************************************************************/
-
-#include "ntvdm.h"
-
-#define NDEBUG
-#include <debug.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"
-
-#include "vddsup.h"
-
-/* PRIVATE FUNCTIONS **********************************************************/
-
-static VOID DosInitPsp(IN WORD Segment,
-                       IN WORD EnvBlock,
-                       IN LPCSTR CommandLine,
-                       IN LPCSTR ProgramName)
-{
-    PDOS_PSP PspBlock = SEGMENT_TO_PSP(Segment);
-    PDOS_MCB Mcb = SEGMENT_TO_MCB(Segment - 1);
-    LPCSTR PspName;
-    USHORT i;
-
-    /* Link the environment block */
-    PspBlock->EnvBlock = EnvBlock;
-
-    /*
-     * Copy the command line.
-     * Format of the CommandLine parameter: 1 byte for size; 127 bytes for contents.
-     */
-    PspBlock->CommandLineSize = min(*(PBYTE)CommandLine, DOS_CMDLINE_LENGTH);
-    CommandLine++;
-    RtlCopyMemory(PspBlock->CommandLine, CommandLine, DOS_CMDLINE_LENGTH);
-
-    /*
-     * Initialize the owner name of the MCB of the PSP.
-     */
-
-    /* Find the start of the file name, skipping all the path elements */
-    PspName = ProgramName;
-    while (*ProgramName)
-    {
-        switch (*ProgramName++)
-        {
-            /* Path delimiter, skip it */
-            case ':': case '\\': case '/':
-                PspName = ProgramName;
-                break;
-        }
-    }
-    /* Copy the file name up to the extension... */
-    for (i = 0; i < sizeof(Mcb->Name) && PspName[i] != '.' && PspName[i] != '\0'; ++i)
-    {
-        Mcb->Name[i] = RtlUpperChar(PspName[i]);
-    }
-    /* ... and NULL-terminate if needed */
-    if (i < sizeof(Mcb->Name)) Mcb->Name[i] = '\0';
-
-    // FIXME: Initialize the FCBs
-}
-
-static inline VOID DosSaveState(VOID)
-{
-    PDOS_REGISTER_STATE State;
-    WORD StackPointer = getSP();
-
-    DPRINT1("\n"
-            "DosSaveState(before) -- SS:SP == %04X:%04X\n"
-            "Original CPU State =\n"
-            "DS = %04X; ES = %04X; AX = %04X; CX = %04X\n"
-            "DX = %04X; BX = %04X; BP = %04X; SI = %04X; DI = %04X"
-            "\n",
-            getSS(), getSP(),
-            getDS(), getES(), getAX(), getCX(),
-            getDX(), getBX(), getBP(), getSI(), getDI());
-
-    /*
-     * Allocate stack space for the registers. Note that we
-     * already have one word allocated (the interrupt number).
-     */
-    StackPointer -= sizeof(DOS_REGISTER_STATE) - sizeof(WORD);
-    State = SEG_OFF_TO_PTR(getSS(), StackPointer);
-    setSP(StackPointer);
-
-    /* Save */
-    State->DS = getDS();
-    State->ES = getES();
-    State->AX = getAX();
-    State->CX = getCX();
-    State->DX = getDX();
-    State->BX = getBX();
-    State->BP = getBP();
-    State->SI = getSI();
-    State->DI = getDI();
-
-    DPRINT1("\n"
-            "DosSaveState(after) -- SS:SP == %04X:%04X\n"
-            "Saved State =\n"
-            "DS = %04X; ES = %04X; AX = %04X; CX = %04X\n"
-            "DX = %04X; BX = %04X; BP = %04X; SI = %04X; DI = %04X"
-            "\n",
-            getSS(), getSP(),
-            State->DS, State->ES, State->AX, State->CX,
-            State->DX, State->BX, State->BP, State->SI, State->DI);
-}
-
-static inline VOID DosRestoreState(VOID)
-{
-    PDOS_REGISTER_STATE State;
-
-    /*
-     * 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());
-
-    DPRINT1("\n"
-            "DosRestoreState(before) -- SS:SP == %04X:%04X\n"
-            "Saved State =\n"
-            "DS = %04X; ES = %04X; AX = %04X; CX = %04X\n"
-            "DX = %04X; BX = %04X; BP = %04X; SI = %04X; DI = %04X"
-            "\n",
-            getSS(), getSP(),
-            State->DS, State->ES, State->AX, State->CX,
-            State->DX, State->BX, State->BP, State->SI, State->DI);
-
-    setSP(getSP() + sizeof(DOS_REGISTER_STATE) - sizeof(WORD));
-
-    /* Restore */
-    setDS(State->DS);
-    setES(State->ES);
-    setAX(State->AX);
-    setCX(State->CX);
-    setDX(State->DX);
-    setBX(State->BX);
-    setBP(State->BP);
-    setSI(State->SI);
-    setDI(State->DI);
-
-    DPRINT1("\n"
-            "DosRestoreState(after) -- SS:SP == %04X:%04X\n"
-            "Restored CPU State =\n"
-            "DS = %04X; ES = %04X; AX = %04X; CX = %04X\n"
-            "DX = %04X; BX = %04X; BP = %04X; SI = %04X; DI = %04X"
-            "\n",
-            getSS(), getSP(),
-            getDS(), getES(), getAX(), getCX(),
-            getDX(), getBX(), getBP(), getSI(), getDI());
-}
-
-static WORD DosCopyEnvironmentBlock(IN LPCSTR Environment OPTIONAL,
-                                    IN 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(*DestPsp));
-
-    /* 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;
-
-    /* Save the interrupt vectors */
-    PspBlock->TerminateAddress = IntVecTable[0x22];
-    PspBlock->BreakAddress     = IntVecTable[0x23];
-    PspBlock->CriticalAddress  = IntVecTable[0x24];
-
-    /* Set the parent PSP */
-    PspBlock->ParentPsp = Sda->CurrentPsp;
-
-    if (Sda->CurrentPsp != SYSTEM_PSP)
-    {
-        /* Link to the parent's environment block */
-        PspBlock->EnvBlock = SEGMENT_TO_PSP(Sda->CurrentPsp)->EnvBlock;
-    }
-/*
-    else
-    {
-        PspBlock->EnvBlock = SEG_OFF_TO_PTR(SYSTEM_ENV_BLOCK, 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 */
-    // FIXME: This is here that SETVER stuff enters into action!
-    PspBlock->DosVersion = DosData->DosVersion;
-
-    /* Set the far call opcodes */
-    PspBlock->FarCall[0] = 0xCD; // int 0x21
-    PspBlock->FarCall[1] = 0x21;
-    PspBlock->FarCall[2] = 0xCB; // retf
-}
-
-VOID DosSetProcessContext(WORD Segment)
-{
-    Sda->CurrentPsp = Segment;
-    Sda->DiskTransferArea = MAKELONG(0x80, 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 Result = ERROR_SUCCESS;
-    WORD Segment = 0;
-    WORD EnvBlock = 0;
-    WORD ExeSignature;
-    WORD LoadSegment;
-    WORD MaxAllocSize;
-
-    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("DosLoadExecutableInternal(%d, 0x%p, '%s', 0x%p, 0x%p, 0x%p)\n",
-            LoadType, ExeBuffer, ExePath, Parameters, CommandLine, Environment);
-
-    if (LoadType != DOS_LOAD_OVERLAY)
-    {
-        /* If an optional Win32 command line is given... */
-        if (CommandLine)
-        {
-            /* ... convert it into DOS format */
-            BYTE CmdLineLen;
-
-            PBYTE CmdLineSize  = (PBYTE)CmdLineBuffer;
-            LPSTR CmdLineStart = CmdLineBuffer + 1;
-            LPSTR CmdLinePtr   = CmdLineStart;
-
-            // For debugging purposes
-            RtlFillMemory(CmdLineBuffer, sizeof(CmdLineBuffer), 0xFF);
-
-            /*
-             * Set the command line: it is either an empty command line or has
-             * the format: " foo bar ..." (with at least one leading whitespace),
-             * and is then always followed by '\r' (and optionally by '\n').
-             */
-            CmdLineLen = (BYTE)strlen(CommandLine);
-            *CmdLineSize = 0;
-
-            /*
-             * Add the leading space if the command line is not empty
-             * and doesn't already start with some whitespace...
-             */
-            if (*CommandLine && *CommandLine != '\r' && *CommandLine != '\n' &&
-                *CommandLine != ' ' && *CommandLine != '\t')
-            {
-                (*CmdLineSize)++;
-                *CmdLinePtr++ = ' ';
-            }
-
-            /* Compute the number of characters we need to copy from the original command line */
-            CmdLineLen = min(CmdLineLen, DOS_CMDLINE_LENGTH - *CmdLineSize);
-
-            /* The trailing '\r' or '\n' do not count in the PSP command line size parameter */
-            while (CmdLineLen && (CommandLine[CmdLineLen - 1] == '\r' || CommandLine[CmdLineLen - 1] == '\n'))
-            {
-                CmdLineLen--;
-            }
-
-            /* Finally, set everything up */
-            *CmdLineSize += CmdLineLen;
-            RtlCopyMemory(CmdLinePtr, CommandLine, CmdLineLen);
-            CmdLineStart[*CmdLineSize] = '\r';
-
-            /* Finally make the pointer point to the static buffer */
-            CommandLine = CmdLineBuffer;
-        }
-        else
-        {
-            /*
-             * ... otherwise, get the one from the parameter block.
-             * Format of the command line: 1 byte for size; 127 bytes for contents.
-             */
-            ASSERT(Parameters);
-            CommandLine = (LPCSTR)FAR_POINTER(Parameters->CommandLine);
-        }
-
-        /* If no optional environment is given... */
-        if (Environment == NULL)
-        {
-            ASSERT(Parameters);
-            /* ... get the one from the parameter block (if not NULL)... */
-            if (Parameters->Environment)
-                Environment = (LPCSTR)SEG_OFF_TO_PTR(Parameters->Environment, 0);
-            /* ... or the one from the parent (otherwise) */
-            else
-                Environment = (LPCSTR)SEG_OFF_TO_PTR(SEGMENT_TO_PSP(Sda->CurrentPsp)->EnvBlock, 0);
-        }
-
-        /* Copy the environment block to DOS memory */
-        EnvBlock = DosCopyEnvironmentBlock(Environment, ExePath);
-        if (EnvBlock == 0)
-        {
-            Result = Sda->LastErrorCode;
-            goto Cleanup;
-        }
-    }
-
-    /*
-     * Check if this is an EXE file or a COM file by looking
-     * at the MZ signature:
-     * 0x4D5A 'MZ': old signature (stored as 0x5A, 0x4D)
-     * 0x5A4D 'ZM': new signature (stored as 0x4D, 0x5A)
-     */
-    ExeSignature = *(PWORD)ExeBuffer;
-    if (ExeSignature == 'MZ' || ExeSignature == 'ZM')
-    {
-        /* EXE file */
-        PIMAGE_DOS_HEADER Header;
-        DWORD BaseSize;
-        PDWORD RelocationTable;
-        PWORD RelocWord;
-        WORD RelocFactor;
-        WORD i;
-
-        /* Get the MZ header */
-        Header = (PIMAGE_DOS_HEADER)ExeBuffer;
-
-        /* Get the base size of the file, in paragraphs (rounded up) */
-#if 0   // Normally this is not needed to check for the number of bytes in the last pages.
-        BaseSize = ((((Header->e_cp - (Header->e_cblp != 0)) * 512) + Header->e_cblp) >> 4)
-                    - Header->e_cparhdr;
-#else
-        // e_cp is the number of 512-byte blocks. 512 == (1 << 9)
-        // so this corresponds to (1 << 5) number of paragraphs.
-        //
-        // For DOS compatibility we need to truncate BaseSize to a WORD value.
-        // This fact is exploited by some EXEs which are bigger than 1 Mb while
-        // being able to load on DOS, the main EXE code loads the remaining data.
-
-        BaseSize = ((Header->e_cp << 5) - Header->e_cparhdr) & 0xFFFF;
-#endif
-
-        if (LoadType != DOS_LOAD_OVERLAY)
-        {
-            BOOLEAN LoadHigh = FALSE;
-            DWORD TotalSize;
-
-            /* Find the maximum amount of memory that can be allocated */
-            DosAllocateMemory(0xFFFF, &MaxAllocSize);
-
-            /* Compute the total needed size, in paragraphs */
-            TotalSize = BaseSize + (sizeof(DOS_PSP) >> 4);
-
-            /* We must have the required minimum amount of memory. If not, bail out. */
-            if (MaxAllocSize < TotalSize + Header->e_minalloc)
-            {
-                Result = ERROR_NOT_ENOUGH_MEMORY;
-                goto Cleanup;
-            }
-
-            /* Check if the program should be loaded high */
-            if (Header->e_minalloc == 0 && Header->e_maxalloc == 0)
-            {
-                /* Yes it should. Use all the available memory. */
-                LoadHigh  = TRUE;
-                TotalSize = MaxAllocSize;
-            }
-            else
-            {
-                /* Compute the maximum memory size that can be allocated */
-                if (Header->e_maxalloc != 0)
-                    TotalSize = min(TotalSize + Header->e_maxalloc, MaxAllocSize);
-                else
-                    TotalSize = MaxAllocSize; // Use all the available memory
-            }
-
-            /* Try to allocate that much memory */
-            Segment = DosAllocateMemory((WORD)TotalSize, NULL);
-            if (Segment == 0)
-            {
-                Result = Sda->LastErrorCode;
-                goto Cleanup;
-            }
-
-            /* The process owns its memory */
-            DosChangeMemoryOwner(Segment , Segment);
-            DosChangeMemoryOwner(EnvBlock, Segment);
-
-            /* Set INT 22h to the return address */
-            ((PULONG)BaseAddress)[0x22] = ReturnAddress;
-
-            /* Create the PSP and initialize it */
-            DosCreatePsp(Segment, (WORD)TotalSize);
-            DosInitPsp(Segment, EnvBlock, CommandLine, ExePath);
-
-            /* 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
-        {
-            ASSERT(Parameters);
-            LoadSegment = Parameters->Overlay.Segment;
-            RelocFactor = Parameters->Overlay.RelocationFactor;
-        }
-
-        /* Copy the program to the code segment */
-        RtlCopyMemory(SEG_OFF_TO_PTR(LoadSegment, 0),
-                      ExeBuffer + (Header->e_cparhdr << 4),
-                      min(ExeBufferSize - (Header->e_cparhdr << 4), BaseSize << 4));
-
-        /* Get the relocation table */
-        RelocationTable = (PDWORD)(ExeBuffer + 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;
-        }
-
-        /* 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
-    {
-        /* 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) < (ExeBufferSize + sizeof(DOS_PSP)))
-            {
-                Result = ERROR_NOT_ENOUGH_MEMORY;
-                goto Cleanup;
-            }
-
-            /* Allocate all of it */
-            Segment = DosAllocateMemory(MaxAllocSize, NULL);
-            if (Segment == 0)
-            {
-                Result = Sda->LastErrorCode;
-                goto Cleanup;
-            }
-
-            /* The process owns its memory */
-            DosChangeMemoryOwner(Segment , Segment);
-            DosChangeMemoryOwner(EnvBlock, Segment);
-
-            /* Set INT 22h to the return address */
-            ((PULONG)BaseAddress)[0x22] = ReturnAddress;
-
-            /* Create the PSP and initialize it */
-            DosCreatePsp(Segment, MaxAllocSize);
-            DosInitPsp(Segment, EnvBlock, CommandLine, ExePath);
-
-            /* Calculate the segment where the program should be loaded */
-            LoadSegment = Segment + (sizeof(DOS_PSP) >> 4);
-        }
-        else
-        {
-            ASSERT(Parameters);
-            LoadSegment = Parameters->Overlay.Segment;
-        }
-
-        /* Copy the program to the code segment */
-        RtlCopyMemory(SEG_OFF_TO_PTR(LoadSegment, 0),
-                      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();
-
-            DPRINT1("Sda->CurrentPsp = 0x%04x; Old LastStack = 0x%08x, New LastStack = 0x%08x\n",
-                   Sda->CurrentPsp, SEGMENT_TO_PSP(Sda->CurrentPsp)->LastStack, MAKELONG(getSP(), getSS()));
-
-            /* 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. In MS-DOS 5.0 and Windows' NTVDM it's 0x091C. This is in fact the old SP value inside DosData disk stack.
-        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:
-    if (Result != ERROR_SUCCESS)
-    {
-        /* It was not successful, cleanup the DOS memory */
-        if (EnvBlock) DosFreeMemory(EnvBlock);
-        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);
-
-    /* Close the file mapping object */
-    if (FileMapping != NULL) CloseHandle(FileMapping);
-
-    /* Close the file handle */
-    if (FileHandle != INVALID_HANDLE_VALUE) CloseHandle(FileHandle);
-
-    return Result;
-}
-
-WORD DosCreateProcess(IN LPCSTR ProgramName,
-                      IN PDOS_EXEC_PARAM_BLOCK Parameters,
-                      IN DWORD ReturnAddress OPTIONAL)
-{
-    DWORD Result = ERROR_SUCCESS;
-    DWORD BinaryType;
-
-    /* Get the binary type */
-    if (!GetBinaryTypeA(ProgramName, &BinaryType)) return GetLastError();
-
-    /* Check the type of the program */
-    switch (BinaryType)
-    {
-        /* Those are handled by NTVDM */
-        case SCS_WOW_BINARY:
-        {
-            DisplayMessage(L"Trying to load '%S'.\n"
-                           L"WOW16 applications are not supported internally by NTVDM at the moment.\n"
-                           L"Press 'OK' to continue.",
-                           ProgramName);
-            // Fall through
-        }
-        case SCS_DOS_BINARY:
-        {
-            /* Load the executable */
-            Result = DosLoadExecutable(DOS_LOAD_AND_EXECUTE,
-                                       ProgramName,
-                                       Parameters,
-                                       NULL,
-                                       NULL,
-                                       ReturnAddress);
-            if (Result != ERROR_SUCCESS)
-            {
-                DisplayMessage(L"Could not load '%S'. Error: %u", ProgramName, Result);
-            }
-
-            break;
-        }
-
-        /* Not handled by NTVDM */
-        default:
-        {
-            LPSTR Environment = NULL;
-            CHAR CmdLine[MAX_PATH + DOS_CMDLINE_LENGTH + 1];
-            LPSTR CmdLinePtr;
-            ULONG CmdLineSize;
-
-            /* Did the caller specify an environment segment? */
-            if (Parameters->Environment)
-            {
-                /* Yes, use it instead of the parent one */
-                Environment = (LPSTR)SEG_OFF_TO_PTR(Parameters->Environment, 0);
-            }
-
-            /*
-             * Convert the DOS command line to Win32-compatible format, by concatenating
-             * the program name with the converted command line.
-             * Format of the DOS command line: 1 byte for size; 127 bytes for contents.
-             */
-            CmdLinePtr = CmdLine;
-            strncpy(CmdLinePtr, ProgramName, MAX_PATH); // Concatenate the program name
-            CmdLinePtr += strlen(CmdLinePtr);
-            *CmdLinePtr++ = ' ';                        // Add separating space
-
-            CmdLineSize = min(*(PBYTE)FAR_POINTER(Parameters->CommandLine), DOS_CMDLINE_LENGTH);
-            RtlCopyMemory(CmdLinePtr,
-                          (LPSTR)FAR_POINTER(Parameters->CommandLine) + 1,
-                          CmdLineSize);
-            /* NULL-terminate it */
-            CmdLinePtr[CmdLineSize] = '\0';
-
-            /* Remove any trailing return carriage character and NULL-terminate the command line */
-            while (*CmdLinePtr && *CmdLinePtr != '\r' && *CmdLinePtr != '\n') CmdLinePtr++;
-            *CmdLinePtr = '\0';
-
-            Result = DosStartProcess32(ProgramName, CmdLine,
-                                       Environment, ReturnAddress,
-                                       TRUE);
-            if (Result != ERROR_SUCCESS)
-            {
-                DisplayMessage(L"Could not load 32-bit '%S'. Error: %u", ProgramName, Result);
-            }
-
-            break;
-        }
-    }
-
-    return Result;
-}
-
-VOID DosTerminateProcess(WORD Psp, BYTE ReturnCode, WORD KeepResident)
-{
-    WORD McbSegment = SysVars->FirstMcb;
-    PDOS_MCB CurrentMcb;
-    LPDWORD IntVecTable = (LPDWORD)((ULONG_PTR)BaseAddress);
-    PDOS_PSP PspBlock = SEGMENT_TO_PSP(Psp);
-    LPWORD Stack;
-    BYTE TerminationType;
-
-    DPRINT("DosTerminateProcess: Psp 0x%04X, ReturnCode 0x%02X, KeepResident 0x%04X\n",
-           Psp, ReturnCode, KeepResident);
-
-    /* Notify VDDs of process termination */
-    VDDTerminateUserHook(Psp);
-
-    /* Check if this PSP is its own parent */
-    if (PspBlock->ParentPsp == Psp) goto Done;
-
-    if (KeepResident == 0)
-    {
-        WORD i;
-        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)
-            {
-                /* Check if this is the PSP block and we should reduce its size */
-                if ((McbSegment + 1) == Psp && KeepResident < CurrentMcb->Size)
-                {
-                    /* Reduce the size of the block */
-                    DosResizeMemory(McbSegment + 1, KeepResident, NULL);
-                    break;
-                }
-            }
-            else
-            {
-                /* Free this entire block */
-                DosFreeMemory(McbSegment + 1);
-            }
-        }
-
-        /* 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 with the parent's one */
-    if (Psp == Sda->CurrentPsp)
-    {
-        DosSetProcessContext(PspBlock->ParentPsp);
-        if (Sda->CurrentPsp == SYSTEM_PSP)
-        {
-            // NOTE: we can also use the DOS BIOS exit code.
-            CpuUnsimulate();
-            return;
-        }
-    }
-
-    /* Save the return code - Normal termination or TSR */
-    TerminationType = (KeepResident != 0 ? 0x03 : 0x00);
-    Sda->ErrorLevel = MAKEWORD(ReturnCode, TerminationType);
-
-    DPRINT1("PspBlock->ParentPsp = 0x%04x; Sda->CurrentPsp = 0x%04x\n",
-           PspBlock->ParentPsp, Sda->CurrentPsp);
-
-    if (Sda->CurrentPsp != SYSTEM_PSP)
-    {
-        DPRINT1("Sda->CurrentPsp = 0x%04x; Old SS:SP = %04X:%04X going to be LastStack = 0x%08x\n",
-               Sda->CurrentPsp, getSS(), getSP(), SEGMENT_TO_PSP(Sda->CurrentPsp)->LastStack);
-
-        /* 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());
-    Stack[STACK_CS] = HIWORD(PspBlock->TerminateAddress);
-    Stack[STACK_IP] = LOWORD(PspBlock->TerminateAddress);
-}
-
-/* EOF */