2013-03-14 21:04:13 +00:00
|
|
|
/*
|
2013-06-17 00:00:36 +00:00
|
|
|
* COPYRIGHT: GPL - See COPYING in the top level directory
|
|
|
|
* PROJECT: ReactOS Virtual DOS Machine
|
|
|
|
* FILE: ntvdm.c
|
2002-10-28 13:59:59 +00:00
|
|
|
* PURPOSE: Virtual DOS Machine
|
2013-06-17 00:00:36 +00:00
|
|
|
* PROGRAMMERS: Aleksandar Andrejevic <theflash AT sdf DOT lonestar DOT org>
|
2002-10-28 13:59:59 +00:00
|
|
|
*/
|
|
|
|
|
2013-06-26 22:58:41 +00:00
|
|
|
/* INCLUDES *******************************************************************/
|
|
|
|
|
2013-07-22 13:51:26 +00:00
|
|
|
#define NDEBUG
|
|
|
|
|
2013-06-17 00:00:36 +00:00
|
|
|
#include "ntvdm.h"
|
2013-06-26 22:58:41 +00:00
|
|
|
#include "emulator.h"
|
|
|
|
#include "bios.h"
|
2013-08-05 23:20:25 +00:00
|
|
|
#include "vga.h"
|
2013-06-26 22:58:41 +00:00
|
|
|
#include "dos.h"
|
|
|
|
#include "timer.h"
|
|
|
|
#include "pic.h"
|
|
|
|
#include "ps2.h"
|
|
|
|
|
2013-07-18 00:17:04 +00:00
|
|
|
/*
|
|
|
|
* Activate this line if you want to be able to test NTVDM with:
|
|
|
|
* ntvdm.exe <program>
|
|
|
|
*/
|
2013-08-09 13:14:56 +00:00
|
|
|
#define TESTING
|
2013-07-18 00:17:04 +00:00
|
|
|
|
2013-06-26 22:58:41 +00:00
|
|
|
/* PUBLIC VARIABLES ***********************************************************/
|
2013-01-24 23:00:42 +00:00
|
|
|
|
2013-06-17 00:00:36 +00:00
|
|
|
BOOLEAN VdmRunning = TRUE;
|
|
|
|
LPVOID BaseAddress = NULL;
|
|
|
|
|
2013-06-26 22:58:41 +00:00
|
|
|
/* PUBLIC FUNCTIONS ***********************************************************/
|
|
|
|
|
2013-06-17 00:00:36 +00:00
|
|
|
VOID DisplayMessage(LPCWSTR Format, ...)
|
2003-01-12 01:54:40 +00:00
|
|
|
{
|
2013-06-17 00:00:36 +00:00
|
|
|
WCHAR Buffer[256];
|
|
|
|
va_list Parameters;
|
2003-01-12 01:54:40 +00:00
|
|
|
|
2013-06-17 00:00:36 +00:00
|
|
|
va_start(Parameters, Format);
|
|
|
|
_vsnwprintf(Buffer, 256, Format, Parameters);
|
2013-08-06 20:01:05 +00:00
|
|
|
MessageBoxW(NULL, Buffer, L"NTVDM Subsystem", MB_OK);
|
2013-06-17 00:00:36 +00:00
|
|
|
va_end(Parameters);
|
2003-01-12 01:54:40 +00:00
|
|
|
}
|
|
|
|
|
2013-06-17 00:00:36 +00:00
|
|
|
BOOL WINAPI ConsoleCtrlHandler(DWORD ControlType)
|
2003-01-12 01:54:40 +00:00
|
|
|
{
|
2013-06-17 00:00:36 +00:00
|
|
|
switch (ControlType)
|
|
|
|
{
|
|
|
|
case CTRL_C_EVENT:
|
|
|
|
case CTRL_BREAK_EVENT:
|
|
|
|
{
|
|
|
|
/* Perform interrupt 0x23 */
|
|
|
|
EmulatorInterrupt(0x23);
|
2013-06-24 01:59:09 +00:00
|
|
|
break;
|
2003-01-12 01:54:40 +00:00
|
|
|
}
|
2013-06-17 00:00:36 +00:00
|
|
|
default:
|
|
|
|
{
|
|
|
|
/* Stop the VDM if the user logs out or closes the console */
|
|
|
|
VdmRunning = FALSE;
|
2003-01-12 01:54:40 +00:00
|
|
|
}
|
2002-10-28 13:59:59 +00:00
|
|
|
}
|
|
|
|
return TRUE;
|
|
|
|
}
|
|
|
|
|
2013-06-17 00:00:36 +00:00
|
|
|
INT wmain(INT argc, WCHAR *argv[])
|
2003-01-12 01:54:40 +00:00
|
|
|
{
|
2013-06-17 00:00:36 +00:00
|
|
|
INT i;
|
2013-08-10 21:41:20 +00:00
|
|
|
CHAR CommandLine[DOS_CMDLINE_LENGTH];
|
2013-07-02 21:40:11 +00:00
|
|
|
DWORD CurrentTickCount;
|
|
|
|
DWORD Cycles = 0;
|
|
|
|
DWORD LastCyclePrintout = GetTickCount();
|
2013-07-05 00:08:18 +00:00
|
|
|
DWORD LastVerticalRefresh = GetTickCount();
|
2013-06-21 13:55:31 +00:00
|
|
|
LARGE_INTEGER Frequency, LastTimerTick, Counter;
|
|
|
|
LONGLONG TimerTicks;
|
2013-10-27 00:37:01 +00:00
|
|
|
HANDLE InputThread = NULL;
|
2013-06-17 00:00:36 +00:00
|
|
|
|
|
|
|
/* Set the handler routine */
|
|
|
|
SetConsoleCtrlHandler(ConsoleCtrlHandler, TRUE);
|
|
|
|
|
2013-07-18 00:01:18 +00:00
|
|
|
#ifndef TESTING
|
2013-08-07 19:56:28 +00:00
|
|
|
UNREFERENCED_PARAMETER(argc);
|
|
|
|
UNREFERENCED_PARAMETER(argv);
|
|
|
|
|
2013-06-23 12:33:13 +00:00
|
|
|
/* The DOS command line must be ASCII */
|
2013-08-10 20:50:37 +00:00
|
|
|
WideCharToMultiByte(CP_ACP, 0, GetCommandLine(), -1, CommandLine, sizeof(CommandLine), NULL, NULL);
|
2013-07-18 00:01:18 +00:00
|
|
|
#else
|
2013-07-18 00:17:04 +00:00
|
|
|
if (argc == 2 && argv[1] != NULL)
|
|
|
|
{
|
2013-08-10 20:50:37 +00:00
|
|
|
WideCharToMultiByte(CP_ACP, 0, argv[1], -1, CommandLine, sizeof(CommandLine), NULL, NULL);
|
2013-07-18 00:17:04 +00:00
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
|
|
|
wprintf(L"\nReactOS Virtual DOS Machine\n\n"
|
|
|
|
L"Usage: NTVDM <executable>\n");
|
|
|
|
return 0;
|
|
|
|
}
|
2013-07-18 00:01:18 +00:00
|
|
|
#endif
|
2005-05-08 04:07:56 +00:00
|
|
|
|
2013-07-02 21:40:11 +00:00
|
|
|
if (!EmulatorInitialize())
|
|
|
|
{
|
|
|
|
wprintf(L"FATAL: Failed to initialize the CPU emulator\n");
|
2013-07-05 00:08:18 +00:00
|
|
|
goto Cleanup;
|
2013-07-02 21:40:11 +00:00
|
|
|
}
|
2013-06-21 13:55:31 +00:00
|
|
|
|
|
|
|
/* Initialize the performance counter (needed for hardware timers) */
|
|
|
|
if (!QueryPerformanceFrequency(&Frequency))
|
|
|
|
{
|
|
|
|
wprintf(L"FATAL: Performance counter not available\n");
|
|
|
|
goto Cleanup;
|
|
|
|
}
|
2003-01-12 01:54:40 +00:00
|
|
|
|
2013-06-17 00:00:36 +00:00
|
|
|
/* Initialize the system BIOS */
|
2013-07-05 01:31:50 +00:00
|
|
|
if (!BiosInitialize())
|
2013-06-17 00:00:36 +00:00
|
|
|
{
|
|
|
|
wprintf(L"FATAL: Failed to initialize the VDM BIOS.\n");
|
|
|
|
goto Cleanup;
|
2003-01-12 01:54:40 +00:00
|
|
|
}
|
2002-10-28 13:59:59 +00:00
|
|
|
|
2013-06-17 00:00:36 +00:00
|
|
|
/* Initialize the VDM DOS kernel */
|
|
|
|
if (!DosInitialize())
|
|
|
|
{
|
|
|
|
wprintf(L"FATAL: Failed to initialize the VDM DOS kernel.\n");
|
|
|
|
goto Cleanup;
|
2002-10-28 13:59:59 +00:00
|
|
|
}
|
|
|
|
|
2013-06-17 00:00:36 +00:00
|
|
|
/* Start the process from the command line */
|
|
|
|
if (!DosCreateProcess(CommandLine, 0))
|
|
|
|
{
|
|
|
|
DisplayMessage(L"Could not start program: %S", CommandLine);
|
|
|
|
return -1;
|
2003-01-12 01:54:40 +00:00
|
|
|
}
|
2013-10-27 00:37:01 +00:00
|
|
|
|
|
|
|
/* Start the input thread */
|
|
|
|
InputThread = CreateThread(NULL, 0, &InputThreadProc, NULL, 0, NULL);
|
2013-08-05 23:20:25 +00:00
|
|
|
|
2013-06-21 13:55:31 +00:00
|
|
|
/* Set the last timer tick to the current time */
|
|
|
|
QueryPerformanceCounter(&LastTimerTick);
|
2003-01-12 01:54:40 +00:00
|
|
|
|
2013-06-17 00:00:36 +00:00
|
|
|
/* Main loop */
|
2013-06-21 13:55:31 +00:00
|
|
|
while (VdmRunning)
|
|
|
|
{
|
2013-06-22 01:41:51 +00:00
|
|
|
/* Get the current number of ticks */
|
|
|
|
CurrentTickCount = GetTickCount();
|
2013-08-05 23:20:25 +00:00
|
|
|
|
2013-11-01 01:57:40 +00:00
|
|
|
/* Get the current performance counter value */
|
|
|
|
QueryPerformanceCounter(&Counter);
|
2013-08-05 23:20:25 +00:00
|
|
|
|
2013-11-01 01:57:40 +00:00
|
|
|
/* Get the number of PIT ticks that have passed */
|
|
|
|
TimerTicks = ((Counter.QuadPart - LastTimerTick.QuadPart)
|
|
|
|
* PIT_BASE_FREQUENCY) / Frequency.QuadPart;
|
2013-10-28 02:25:54 +00:00
|
|
|
|
2013-06-21 13:55:31 +00:00
|
|
|
/* Update the PIT */
|
2013-10-28 02:25:54 +00:00
|
|
|
if (TimerTicks > 0)
|
|
|
|
{
|
2013-11-01 01:57:40 +00:00
|
|
|
PitDecrementCount(TimerTicks);
|
2013-10-28 02:25:54 +00:00
|
|
|
LastTimerTick = Counter;
|
|
|
|
}
|
2013-08-05 23:20:25 +00:00
|
|
|
|
|
|
|
/* Check for vertical retrace */
|
2013-07-05 00:08:18 +00:00
|
|
|
if ((CurrentTickCount - LastVerticalRefresh) >= 16)
|
|
|
|
{
|
2013-08-05 23:20:25 +00:00
|
|
|
VgaRefreshDisplay();
|
2013-07-05 00:08:18 +00:00
|
|
|
LastVerticalRefresh = CurrentTickCount;
|
|
|
|
}
|
2013-08-05 23:20:25 +00:00
|
|
|
|
|
|
|
/* Horizontal retrace occurs as fast as possible */
|
|
|
|
VgaHorizontalRetrace();
|
|
|
|
|
2013-06-21 13:55:31 +00:00
|
|
|
/* Continue CPU emulation */
|
2013-06-24 01:59:09 +00:00
|
|
|
for (i = 0; (i < STEPS_PER_CYCLE) && VdmRunning; i++)
|
|
|
|
{
|
|
|
|
EmulatorStep();
|
|
|
|
Cycles++;
|
|
|
|
}
|
2013-08-05 23:20:25 +00:00
|
|
|
|
2013-06-22 01:41:51 +00:00
|
|
|
if ((CurrentTickCount - LastCyclePrintout) >= 1000)
|
|
|
|
{
|
2013-08-07 19:56:28 +00:00
|
|
|
DPRINT1("NTVDM: %lu Instructions Per Second\n", Cycles);
|
2013-06-22 01:41:51 +00:00
|
|
|
LastCyclePrintout = CurrentTickCount;
|
|
|
|
Cycles = 0;
|
|
|
|
}
|
2013-06-21 13:55:31 +00:00
|
|
|
}
|
2013-06-17 00:00:36 +00:00
|
|
|
|
2013-08-05 23:20:25 +00:00
|
|
|
/* Perform another screen refresh */
|
|
|
|
VgaRefreshDisplay();
|
|
|
|
|
2013-06-17 00:00:36 +00:00
|
|
|
Cleanup:
|
2013-10-27 00:37:01 +00:00
|
|
|
if (InputThread != NULL) CloseHandle(InputThread);
|
2013-07-05 01:31:50 +00:00
|
|
|
BiosCleanup();
|
2013-06-17 00:00:36 +00:00
|
|
|
EmulatorCleanup();
|
2003-01-12 01:54:40 +00:00
|
|
|
|
2002-10-28 13:59:59 +00:00
|
|
|
return 0;
|
|
|
|
}
|
2013-06-17 00:00:36 +00:00
|
|
|
|
|
|
|
/* EOF */
|