-/* $Id$
- *
- * COPYRIGHT: See COPYING in the top level directory
- * PROJECT: ReactOS kernel
- * FILE: subsys/ntvdm/ntvdm->c
- * PURPOSE: Virtual DOS Machine
- * PROGRAMMER: Robert Dickenson (robd@mok.lvcm.com)
- * UPDATE HISTORY:
- * Created 23/10/2002
- */
-
-/* INCLUDES *****************************************************************/
-#define WIN32_NO_STATUS
-#include <windows.h>
-#include <stdio.h>
-#include <wchar.h>
-#include "resource.h"
-
-#define NTOS_MODE_USER
-#include <ndk/ntndk.h>
-
-#define NDEBUG
-#include <debug.h>
-
-/* GLOBALS ******************************************************************/
-
-
-/* FUNCTIONS *****************************************************************/
-
-void PrintString(char* fmt,...)
-{
- char buffer[512];
- va_list ap;
-
- va_start(ap, fmt);
- vsprintf(buffer, fmt, ap);
- va_end(ap);
-
- OutputDebugStringA(buffer);
-}
-
/*
-GetVersion
-GetVolumeInformationW
-GetWindowsDirectoryA
-GlobalMemoryStatus
-HeapAlloc
-HeapCreate
-HeapDestroy
-HeapFree
-HeapReAlloc
-
-GetNextVDMCommand
-ExitVDM
-RegisterConsoleVDM
-SetVDMCurrentDirectories
-VDMConsoleOperation
-WriteConsoleInputVDMW
-
-NtSetLdtEntries
-NtTerminateProcess
-
-NtMapViewOfSection
-NtUnmapViewOfSection
-
-NtVdmControl
+ * COPYRIGHT: GPL - See COPYING in the top level directory
+ * PROJECT: ReactOS Virtual DOS Machine
+ * FILE: ntvdm.c
+ * PURPOSE: Virtual DOS Machine
+ * PROGRAMMERS: Aleksandar Andrejevic <theflash AT sdf DOT lonestar DOT org>
*/
-typedef struct tag_VDM_CONFIG {
- int dos_options;
- int files;
- int buffers;
- WCHAR** device_list;
-//dos=high, umb
-//device=%SystemRoot%\system32\himem.sys
-//files=40
-} VDM_CONFIG, *PVDM_CONFIG;
-typedef struct tag_VDM_AUTOEXEC {
- WCHAR** load_list;
-//lh %SystemRoot%\system32\mscdexnt.exe
-//lh %SystemRoot%\system32\redir
-//lh %SystemRoot%\system32\dosx
-} VDM_AUTOEXEC, *PVDM_AUTOEXEC;
+/* INCLUDES *******************************************************************/
-typedef struct tag_VDM_CONTROL_BLOCK {
- HANDLE hHeap;
- PVOID ImageMem;
- VDM_CONFIG vdmConfig;
- VDM_AUTOEXEC vdmAutoexec;
- PROCESS_INFORMATION ProcessInformation;
- CHAR CommandLine[MAX_PATH];
- CHAR CurrentDirectory[MAX_PATH];
+#include "ntvdm.h"
+#include "emulator.h"
+#include "bios.h"
+#include "dos.h"
+#include "timer.h"
+#include "pic.h"
+#include "ps2.h"
-} VDM_CONTROL_BLOCK, *PVDM_CONTROL_BLOCK;
+/* PUBLIC VARIABLES ***********************************************************/
-
-BOOL
-StartVDM(PVDM_CONTROL_BLOCK vdm)
+BOOLEAN VdmRunning = TRUE;
+LPVOID BaseAddress = NULL;
+LPCWSTR ExceptionName[] =
{
- BOOL Result;
- STARTUPINFOA StartupInfo;
-
- StartupInfo.cb = sizeof(StartupInfo);
- StartupInfo.lpReserved = NULL;
- StartupInfo.lpDesktop = NULL;
- StartupInfo.lpTitle = NULL;
- StartupInfo.dwFlags = 0;
- StartupInfo.cbReserved2 = 0;
- StartupInfo.lpReserved2 = 0;
-
- Result = CreateProcessA(vdm->CommandLine,
- NULL,
- NULL,
- NULL,
- FALSE,
- DETACHED_PROCESS,
- NULL,
- NULL,
- &StartupInfo,
- &vdm->ProcessInformation);
- if (!Result) {
- PrintString("VDM: Failed to execute target process\n");
- return FALSE;
- }
- WaitForSingleObject(vdm->ProcessInformation.hProcess, INFINITE);
- CloseHandle(vdm->ProcessInformation.hProcess);
- CloseHandle(vdm->ProcessInformation.hThread);
- return TRUE;
-}
-
-BOOL
-ShutdownVDM(PVDM_CONTROL_BLOCK vdm)
+ L"Division By Zero",
+ L"Debug",
+ L"Unexpected Error",
+ L"Breakpoint",
+ L"Integer Overflow",
+ L"Bound Range Exceeded",
+ L"Invalid Opcode",
+ L"FPU Not Available"
+};
+
+/* PUBLIC FUNCTIONS ***********************************************************/
+
+VOID DisplayMessage(LPCWSTR Format, ...)
{
- BOOL result = TRUE;
+ WCHAR Buffer[256];
+ va_list Parameters;
- return result;
+ va_start(Parameters, Format);
+ _vsnwprintf(Buffer, 256, Format, Parameters);
+ MessageBox(NULL, Buffer, L"NTVDM Subsystem", MB_OK);
+ va_end(Parameters);
}
-BOOL ReadConfigForVDM(PVDM_CONTROL_BLOCK vdm)
+BOOL WINAPI ConsoleCtrlHandler(DWORD ControlType)
{
- BOOL result = TRUE;
- DWORD dwError;
- HANDLE hFile;
-
- hFile = CreateFileW(L"\\system32\\config.nt",
- GENERIC_READ,
- FILE_SHARE_READ,
- NULL,
- OPEN_ALWAYS /*OPEN_EXISTING*/,
- FILE_ATTRIBUTE_NORMAL,
- 0);
- dwError = GetLastError();
- if (hFile == INVALID_HANDLE_VALUE) {
- // error with file path or system problem?
- } else {
- if (dwError == 0L) {
- // we just created a new file, perhaps we should set/write some defaults?
- }
- if (dwError == ERROR_ALREADY_EXISTS) {
- // read the line entries and cache in some struct...
- }
- CloseHandle(hFile);
- }
-
- hFile = CreateFileW(L"\\system32\\autoexec.nt",
- GENERIC_READ,
- FILE_SHARE_READ,
- NULL,
- OPEN_ALWAYS,
- FILE_ATTRIBUTE_NORMAL,
- 0);
- dwError = GetLastError();
- if (hFile == INVALID_HANDLE_VALUE) {
- // error with file path or system problem?
- } else {
- if (dwError == 0L) {
- // we just created a new file, perhaps we should set/write some defaults?
+ switch (ControlType)
+ {
+ case CTRL_C_EVENT:
+ case CTRL_BREAK_EVENT:
+ {
+ /* Perform interrupt 0x23 */
+ EmulatorInterrupt(0x23);
+ break;
}
- if (dwError == ERROR_ALREADY_EXISTS) {
- // read the line entries and cache in some struct...
+ default:
+ {
+ /* Stop the VDM if the user logs out or closes the console */
+ VdmRunning = FALSE;
}
- CloseHandle(hFile);
- }
-
- return result;
-}
-
-BOOL
-LoadConfigDriversForVDM(PVDM_CONFIG vdmConfig)
-{
- BOOL result = TRUE;
-
- return result;
-}
-
-BOOL
-SetConfigOptionsForVDM(PVDM_AUTOEXEC vdmAutoexec)
-{
- BOOL result = TRUE;
-
- return result;
-}
-
-BOOL
-CreateVDM(PVDM_CONTROL_BLOCK vdm)
-{
-// BOOL result = TRUE;
- SYSTEM_INFO inf;
- MEMORYSTATUS stat;
-
-
- GlobalMemoryStatus(&stat);
- if (stat.dwLength != sizeof(MEMORYSTATUS)) {
- printf("WARNING: GlobalMemoryStatus() returned unknown structure version, size %ld, expected %d.\n", stat.dwLength, sizeof(stat));
- } else {
- printf("Memory Load: %ld percent in use.\n", stat.dwMemoryLoad);
- printf("\t%ld total bytes physical memory.\n", stat.dwTotalPhys);
- printf("\t%ld available physical memory.\n", stat.dwAvailPhys);
- printf("\t%ld total bytes paging file.\n", stat.dwTotalPageFile);
- printf("\t%ld available paging file.\n", stat.dwAvailPageFile);
- printf("\t%lx total bytes virtual memory.\n", stat.dwTotalVirtual);
- printf("\t%lx available bytes virtual memory.\n", stat.dwAvailVirtual);
-
-#define OUT_OF_HEADROOM 90
- if (stat.dwMemoryLoad > OUT_OF_HEADROOM) {
- DPRINT("VDM: system resources deemed to low to start VDM.\n");
- //SetLastError();
- return FALSE;
- }
-
- }
-
- GetSystemInfo(&inf);
- vdm->hHeap = HeapCreate(0, inf.dwAllocationGranularity, 0);
- if (vdm->hHeap == NULL) {
- DPRINT("VDM: failed to create heap.\n");
- return FALSE;
- }
-
-#define DEFAULT_VDM_IMAGE_SIZE 2000000
- vdm->ImageMem = HeapAlloc(vdm->hHeap, 0, DEFAULT_VDM_IMAGE_SIZE);
- if (vdm->ImageMem == NULL) {
- DPRINT("VDM: failed to allocate image memory from heap %x.\n", vdm->hHeap);
- HeapDestroy(vdm->hHeap);
- vdm->hHeap = NULL;
- return FALSE;
}
return TRUE;
}
-BOOL
-DestroyVDM(PVDM_CONTROL_BLOCK vdm)
+INT wmain(INT argc, WCHAR *argv[])
{
- BOOL result = TRUE;
-
- if (vdm->ImageMem != NULL) {
- if (HeapFree(vdm->hHeap, 0, vdm->ImageMem) != FALSE) {
- DPRINT("VDM: failed to free memory from heap %x.\n", vdm->hHeap);
- result = FALSE;
- }
- vdm->ImageMem = NULL;
+ INT i;
+ CHAR CommandLine[128];
+ DWORD CurrentTickCount, LastTickCount = 0, Cycles = 0, LastCyclePrintout = 0;
+ LARGE_INTEGER Frequency, LastTimerTick, Counter;
+ LONGLONG TimerTicks;
+
+ /* Set the handler routine */
+ SetConsoleCtrlHandler(ConsoleCtrlHandler, TRUE);
+
+ /* The DOS command line must be ASCII */
+ WideCharToMultiByte(CP_ACP, 0, GetCommandLine(), -1, CommandLine, 128, NULL, NULL);
+
+ if (!EmulatorInitialize()) return 1;
+
+ /* Initialize the performance counter (needed for hardware timers) */
+ if (!QueryPerformanceFrequency(&Frequency))
+ {
+ wprintf(L"FATAL: Performance counter not available\n");
+ goto Cleanup;
}
- if (vdm->hHeap != NULL) {
- if (!HeapDestroy(vdm->hHeap)) {
- DPRINT("VDM: failed to destroy heap %x.\n", vdm->hHeap);
- result = FALSE;
- }
- vdm->hHeap = NULL;
- }
- return result;
-}
-
-int WINAPI
-WinMain(HINSTANCE hInstance, HINSTANCE hPrevInstance, LPSTR lpCmdLine, int nShowCmd)
-{
- VDM_CONTROL_BLOCK VdmCB;
- DWORD Result;
- ULONG i;
- BOOL vdmStarted = FALSE;
-
- WCHAR WelcomeMsg[RC_STRING_MAX_SIZE];
- WCHAR PromptMsg[RC_STRING_MAX_SIZE];
- CHAR InputBuffer[255];
- LoadStringW( GetModuleHandle(NULL), STRING_WelcomeMsg, WelcomeMsg,sizeof(WelcomeMsg) / sizeof(WelcomeMsg[0]));
- LoadStringW( GetModuleHandle(NULL), STRING_PromptMsg, PromptMsg ,sizeof(PromptMsg) / sizeof(PromptMsg[0]));
-
- AllocConsole();
- SetConsoleTitleW(L"ntvdm");
-
- WriteConsoleW(GetStdHandle(STD_OUTPUT_HANDLE),
- WelcomeMsg, lstrlenW(WelcomeMsg), // wcslen(WelcomeMsg),
- &Result, NULL);
-
- if (!CreateVDM(&VdmCB)) {
- DPRINT("VDM: failed to create VDM.\n");
- //SetLastError();
- return 2;
+ /* Initialize the system BIOS */
+ if (!BiosInitialize())
+ {
+ wprintf(L"FATAL: Failed to initialize the VDM BIOS.\n");
+ goto Cleanup;
}
- ReadConfigForVDM(&VdmCB);
-
- if (!LoadConfigDriversForVDM(&(VdmCB.vdmConfig))) {
- DPRINT("VDM: failed to load configuration drivers.\n");
- //SetLastError();
- return 2;
+ /* Initialize the VDM DOS kernel */
+ if (!DosInitialize())
+ {
+ wprintf(L"FATAL: Failed to initialize the VDM DOS kernel.\n");
+ goto Cleanup;
}
- if (!SetConfigOptionsForVDM(&(VdmCB.vdmAutoexec))) {
- DPRINT("VDM: failed to set configuration options.\n");
- //SetLastError();
- return 3;
- }
-
- GetSystemDirectoryA(VdmCB.CommandLine, MAX_PATH);
- strcat(VdmCB.CommandLine, "\\hello.exe");
- GetWindowsDirectoryA(VdmCB.CurrentDirectory, MAX_PATH);
-
- for (;;) {
- WriteConsoleW(GetStdHandle(STD_OUTPUT_HANDLE),
- PromptMsg, lstrlenW(PromptMsg), // wcslen(PromptMsg),
- &Result, NULL);
- i = 0;
- do {
- ReadConsoleA(GetStdHandle(STD_INPUT_HANDLE),
- &InputBuffer[i], 1,
- &Result, NULL);
- if (++i >= (sizeof(InputBuffer) - 1)) {
- break;
- }
- } while (InputBuffer[i - 1] != '\n');
- InputBuffer[i - 1] = '\0';
- if (InputBuffer[0] == 'r' || InputBuffer[0] == 'R') {
- if (!vdmStarted) {
- if (StartVDM(&VdmCB)) {
- vdmStarted = TRUE;
- } else {
- DPRINT("VDM: failed to start.\n");
- }
- } else {
- DPRINT("VDM: already started.\n");
- }
+ /* Start the process from the command line */
+ if (!DosCreateProcess(CommandLine, 0))
+ {
+ DisplayMessage(L"Could not start program: %S", CommandLine);
+ return -1;
+ }
+
+ /* Set the last timer tick to the current time */
+ QueryPerformanceCounter(&LastTimerTick);
+
+ /* Main loop */
+ while (VdmRunning)
+ {
+ /* Get the current number of ticks */
+ CurrentTickCount = GetTickCount();
+
+ /* Get the current performance counter value */
+ QueryPerformanceCounter(&Counter);
+
+ /* Get the number of PIT ticks that have passed */
+ TimerTicks = ((Counter.QuadPart - LastTimerTick.QuadPart)
+ * PIT_BASE_FREQUENCY) / Frequency.QuadPart;
+
+ /* Update the PIT */
+ for (i = 0; i < TimerTicks; i++) PitDecrementCount();
+ LastTimerTick = Counter;
+
+ /* Check for console input events every millisecond */
+ if (CurrentTickCount != LastTickCount)
+ {
+ CheckForInputEvents();
+ LastTickCount = CurrentTickCount;
}
- if (InputBuffer[0] == 's' || InputBuffer[0] == 'S') {
- if (vdmStarted) {
- if (ShutdownVDM(&VdmCB)) {
- vdmStarted = FALSE;
- } else {
- DPRINT("VDM: failed to shutdown.\n");
- }
- } else {
- DPRINT("VDM: not started.\n");
- }
+
+ /* Continue CPU emulation */
+ for (i = 0; (i < STEPS_PER_CYCLE) && VdmRunning; i++)
+ {
+ EmulatorStep();
+ Cycles++;
}
- if (InputBuffer[0] == 'q' || InputBuffer[0] == 'Q') {
- break;
+
+ if ((CurrentTickCount - LastCyclePrintout) >= 1000)
+ {
+ DPRINT1("NTVDM: %d Instructions Per Second\n", Cycles);
+ LastCyclePrintout = CurrentTickCount;
+ Cycles = 0;
}
}
- if (!ShutdownVDM(&VdmCB)) {
- DPRINT("VDM: failed to cleanly shutdown VDM.\n");
- //SetLastError();
- return 5;
- }
-
- if (!DestroyVDM(&VdmCB)) {
- DPRINT("VDM: failed to cleanly destroy VDM.\n");
- //SetLastError();
- return 6;
- }
+Cleanup:
+ EmulatorCleanup();
- ExitProcess(0);
return 0;
}
+
+/* EOF */