[NTVDM]
[reactos.git] / subsystems / ntvdm / dos / dem.c
index 64ea854..df57840 100644 (file)
 
 #define NDEBUG
 
+#include "emulator.h"
+#include "utils.h"
+
 #include "dem.h"
+#include "bop.h"
 
 /* Extra PSDK/NDK Headers */
 #include <ndk/obtypes.h>
 
+/* PRIVATE VARIABLES **********************************************************/
+
 /**/extern BYTE CurrentDrive;/**/
 
+/* DEFINES ********************************************************************/
+
+/* BOP Identifiers */
+#define BOP_DOS 0x50    // DOS System BOP (for NTIO.SYS and NTDOS.SYS)
+#define BOP_CMD 0x54    // DOS Command Interpreter BOP (for COMMAND.COM)
+
+/* PRIVATE FUNCTIONS **********************************************************/
+
+static VOID WINAPI DosSystemBop(LPWORD Stack)
+{
+    /* Get the Function Number and skip it */
+    BYTE FuncNum = *(PBYTE)SEG_OFF_TO_PTR(getCS(), getIP());
+    setIP(getIP() + 1);
+
+    switch (FuncNum)
+    {
+        case 0x11:  // Load the DOS kernel
+        {
+            BOOLEAN Success;
+            HANDLE  hDosKernel;
+            ULONG   ulDosKernelSize = 0;
+
+            DPRINT1("You are loading Windows NT DOS!\n");
+
+            /* Open the DOS kernel file */
+            hDosKernel = FileOpen("ntdos.sys", &ulDosKernelSize);
+
+            /* If we failed, bail out */
+            if (hDosKernel == NULL) goto Quit;
+
+            /*
+             * Attempt to load the DOS kernel into memory.
+             * The segment where to load the DOS kernel is defined
+             * by the DOS BIOS and is found in DI:0000 .
+             */
+            Success = FileLoadByHandle(hDosKernel,
+                                       REAL_TO_PHYS(TO_LINEAR(getDI(), 0x0000)),
+                                       ulDosKernelSize,
+                                       &ulDosKernelSize);
+            DPRINT1("DOS loading %s ; GetLastError() = %u\n", Success ? "succeeded" : "failed", GetLastError());
+
+            /* Close the DOS kernel file */
+            FileClose(hDosKernel);
+
+Quit:
+            if (!Success)
+            {
+                /* We failed everything, stop the VDM */
+                VdmRunning = FALSE;
+            }
+
+            break;
+        }
+
+        default:
+        {
+
+            DPRINT1("Unknown DOS System BOP Function: 0x%02X\n", FuncNum);
+            // setCF(1); // Disable, otherwise we enter an infinite loop
+            break;
+        }
+    }
+}
+
+static VOID WINAPI DosCmdInterpreterBop(LPWORD Stack)
+{
+    /* Get the Function Number and skip it */
+    BYTE FuncNum = *(PBYTE)SEG_OFF_TO_PTR(getCS(), getIP());
+    setIP(getIP() + 1);
+
+    switch (FuncNum)
+    {
+        case 0x08:  // Launch external command
+        {
+#define CMDLINE_LENGTH  1024
+
+            BOOL Result;
+            DWORD dwExitCode;
+
+            LPSTR Command = (LPSTR)SEG_OFF_TO_PTR(getDS(), getSI());
+            LPSTR CmdPtr  = Command;
+            CHAR CommandLine[CMDLINE_LENGTH] = "";
+            STARTUPINFOA StartupInfo;
+            PROCESS_INFORMATION ProcessInformation;
+
+            /* Remove return carriage character */
+            while (*CmdPtr != '\r') CmdPtr++;
+            *CmdPtr = '\0';
+
+            DPRINT1("CMD Run Command '%s'\n", Command);
+
+            /* Spawn a user-defined 32-bit command preprocessor */
+
+            /* Build the command line */
+            // FIXME: Use COMSPEC env var!!
+            strcpy(CommandLine, "cmd.exe /c ");
+            strcat(CommandLine, Command);
+
+            ZeroMemory(&StartupInfo, sizeof(StartupInfo));
+            ZeroMemory(&ProcessInformation, sizeof(ProcessInformation));
+
+            StartupInfo.cb = sizeof(StartupInfo);
+
+            DosPrintCharacter('\n');
+
+            Result = CreateProcessA(NULL,
+                                    CommandLine,
+                                    NULL,
+                                    NULL,
+                                    TRUE,
+                                    0,
+                                    NULL,
+                                    NULL,
+                                    &StartupInfo,
+                                    &ProcessInformation);
+            if (Result)
+            {
+                DPRINT1("Command '%s' launched successfully\n", Command);
+
+                /* Wait for process termination */
+                WaitForSingleObject(ProcessInformation.hProcess, INFINITE);
+
+                /* Get the exit code */
+                GetExitCodeProcess(ProcessInformation.hProcess, &dwExitCode);
+
+                /* Close handles */
+                CloseHandle(ProcessInformation.hThread);
+                CloseHandle(ProcessInformation.hProcess);
+            }
+            else
+            {
+                DPRINT1("Failed when launched command '%s'\n");
+                dwExitCode = GetLastError();
+            }
+            
+            DosPrintCharacter('\n');
+
+            setAL((UCHAR)dwExitCode);
+
+            break;
+        }
+
+        default:
+        {
+            DPRINT1("Unknown DOS CMD Interpreter BOP Function: 0x%02X\n", FuncNum);
+            // setCF(1); // Disable, otherwise we enter an infinite loop
+            break;
+        }
+    }
+}
+
 /* PUBLIC FUNCTIONS ***********************************************************/
 
-BOOLEAN DosInitialize(IN LPCSTR DosKernelFileNames)
+BOOLEAN DosInitialize(IN LPCSTR DosKernelFileName)
 {
-    if (DosKernelFileNames)
+    /* Register the DOS BOPs */
+    RegisterBop(BOP_DOS, DosSystemBop        );
+    RegisterBop(BOP_CMD, DosCmdInterpreterBop);
+
+    if (DosKernelFileName)
     {
-        DisplayMessage(L"NTVDM: Loading DOS kernel from external files is currently unsupported");
-        return FALSE;
+        BOOLEAN Success;
+        HANDLE  hDosBios;
+        ULONG   ulDosBiosSize = 0;
+
+        /* Open the DOS BIOS file */
+        hDosBios = FileOpen(DosKernelFileName, &ulDosBiosSize);
+
+        /* If we failed, bail out */
+        if (hDosBios == NULL) return FALSE;
+
+        /* Attempt to load the DOS BIOS into memory */
+        Success = FileLoadByHandle(hDosBios,
+                                   REAL_TO_PHYS(TO_LINEAR(0x0070, 0x0000)),
+                                   ulDosBiosSize,
+                                   &ulDosBiosSize);
+        DPRINT1("DOS BIOS loading %s ; GetLastError() = %u\n", Success ? "succeeded" : "failed", GetLastError());
+
+        /* Close the DOS BIOS file */
+        FileClose(hDosBios);
+
+        if (Success)
+        {
+            /* Position execution pointers and return */
+            setCS(0x0070);
+            setIP(0x0000);
+        }
+
+        return Success;
     }
     else
     {
         BOOLEAN Result;
 
         Result  = DosBIOSInitialize();
-        Result &= DosKRNLInitialize();
+        // Result &= DosKRNLInitialize();
 
         return Result;
     }