- Move almost all the DOS command launch thread into dem.c,
- Rework the code so that now, when we want to either load our BIOS32 or a custom one, we start their execution at F000:FFF0 as it should be,
- For modularity purposes (ie. to be able one day to load real OSes in our ntvdm), implement INT 19h (bootstrap loader) so that it calls a (temporary) dos bootsector loader that writes some bootstrap code at 0000:7c00, then the INT 19h runs this code, that has as an effect to load our DOS32 (for a real OS, the MBR code goes to 0000:7c00 and is then run).

svn path=/trunk/; revision=64521
This commit is contained in:
Hermès Bélusca-Maïto 2014-10-04 13:36:17 +00:00
parent 38258d656e
commit 8d73d7c58a
7 changed files with 407 additions and 267 deletions

View file

@ -25,7 +25,7 @@
/* DEFINES ********************************************************************/ /* DEFINES ********************************************************************/
/* BOP Identifiers */ /* BOP Identifiers */
#define BOP_BIOSINIT 0x00 // Windows NTVDM (SoftPC) BIOS calls BOP 0x00 #define BOP_RESET 0x00 // Windows NTVDM (SoftPC) BIOS calls BOP 0x00
// to let the virtual machine initialize itself // to let the virtual machine initialize itself
// the IVT and its hardware. // the IVT and its hardware.
#define BOP_EQUIPLIST 0x11 #define BOP_EQUIPLIST 0x11
@ -35,84 +35,11 @@
static BOOLEAN Bios32Loaded = FALSE; static BOOLEAN Bios32Loaded = FALSE;
static CALLBACK16 __BiosContext;
PBIOS_DATA_AREA Bda; PBIOS_DATA_AREA Bda;
PBIOS_CONFIG_TABLE Bct; PBIOS_CONFIG_TABLE Bct;
/* PRIVATE FUNCTIONS **********************************************************/ /* PRIVATE FUNCTIONS **********************************************************/
static VOID WINAPI BiosInitBop(LPWORD Stack)
{
BOOLEAN Success;
/* Load the second part of the Windows NTVDM BIOS image */
LPCSTR BiosFileName = "bios1.rom";
PVOID BiosLocation = (PVOID)TO_LINEAR(BIOS_SEGMENT, 0x0000);
DWORD BiosSize = 0;
/* Disable interrupts */
setIF(0);
DisplayMessage(L"You are loading Windows NTVDM BIOS!\n");
/* Initialize a private callback context */
InitializeContext(&__BiosContext, BIOS_SEGMENT, 0x0000);
Success = LoadRom(BiosFileName, BiosLocation, &BiosSize);
DPRINT1("BIOS loading %s ; GetLastError() = %u\n", Success ? "succeeded" : "failed", GetLastError());
if (Success == FALSE)
{
/* Stop the VDM */
EmulatorTerminate();
return;
}
// DisplayMessage(L"First bytes at 0x%p: 0x%02x 0x%02x 0x%02x 0x%02x 0x%02x 0x%02x 0x%02x 0x%02x 0x%02x 0x%02x\n"
// L"3 last bytes at 0x%p: 0x%02x 0x%02x 0x%02x",
// BiosLocation,
// *(PCHAR)((ULONG_PTR)REAL_TO_PHYS(BiosLocation) + 0),
// *(PCHAR)((ULONG_PTR)REAL_TO_PHYS(BiosLocation) + 1),
// *(PCHAR)((ULONG_PTR)REAL_TO_PHYS(BiosLocation) + 2),
// *(PCHAR)((ULONG_PTR)REAL_TO_PHYS(BiosLocation) + 3),
// *(PCHAR)((ULONG_PTR)REAL_TO_PHYS(BiosLocation) + 4),
// *(PCHAR)((ULONG_PTR)REAL_TO_PHYS(BiosLocation) + 5),
// *(PCHAR)((ULONG_PTR)REAL_TO_PHYS(BiosLocation) + 6),
// *(PCHAR)((ULONG_PTR)REAL_TO_PHYS(BiosLocation) + 7),
// *(PCHAR)((ULONG_PTR)REAL_TO_PHYS(BiosLocation) + 8),
// *(PCHAR)((ULONG_PTR)REAL_TO_PHYS(BiosLocation) + 9),
// (PVOID)((ULONG_PTR)BiosLocation + BiosSize - 2),
// *(PCHAR)((ULONG_PTR)REAL_TO_PHYS(BiosLocation) + BiosSize - 2),
// *(PCHAR)((ULONG_PTR)REAL_TO_PHYS(BiosLocation) + BiosSize - 1),
// *(PCHAR)((ULONG_PTR)REAL_TO_PHYS(BiosLocation) + BiosSize - 0));
/* Initialize IVT and hardware */
/* Initialize the Keyboard and Video BIOS */
if (!KbdBiosInitialize() || !VidBiosInitialize())
{
/* Stop the VDM */
EmulatorTerminate();
return;
}
/* Load VGA BIOS */
// Success = LoadRom("v7vga.rom", (PVOID)0xC0000, &BiosSize);
// DPRINT1("VGA BIOS loading %s ; GetLastError() = %u\n", Success ? "succeeded" : "failed", GetLastError());
/* Enable interrupts */
setIF(1);
///////////// MUST BE DONE AFTER IVT INITIALIZATION !! /////////////////////
/* Load some ROMs */
// Success = LoadRom("boot.bin", (PVOID)0xE0000, &BiosSize);
// DPRINT1("Test ROM loading %s ; GetLastError() = %u\n", Success ? "succeeded" : "failed", GetLastError());
SearchAndInitRoms(&__BiosContext);
}
/* PUBLIC FUNCTIONS ***********************************************************/ /* PUBLIC FUNCTIONS ***********************************************************/
VOID WINAPI BiosEquipmentService(LPWORD Stack) VOID WINAPI BiosEquipmentService(LPWORD Stack)
@ -140,12 +67,14 @@ BiosInitialize(IN LPCSTR BiosFileName)
// The BCT is found at F000:E6F5 for 100% compatible BIOSes. // The BCT is found at F000:E6F5 for 100% compatible BIOSes.
Bct = (PBIOS_CONFIG_TABLE)SEG_OFF_TO_PTR(BIOS_SEGMENT, 0xE6F5); Bct = (PBIOS_CONFIG_TABLE)SEG_OFF_TO_PTR(BIOS_SEGMENT, 0xE6F5);
/* Register the BIOS support BOPs */ /**** HACK! HACK! for Windows NTVDM BIOS ****/
RegisterBop(BOP_BIOSINIT , BiosInitBop); // WinNtVdmBiosSupportInitialize();
RegisterBop(BOP_EQUIPLIST , BiosEquipmentService);
RegisterBop(BOP_GETMEMSIZE, BiosGetMemorySize);
if (BiosFileName) // /* Register the BIOS support BOPs */
// RegisterBop(BOP_EQUIPLIST , BiosEquipmentService);
// RegisterBop(BOP_GETMEMSIZE, BiosGetMemorySize);
if (BiosFileName && BiosFileName[0] != '\0')
{ {
PVOID BiosLocation = NULL; PVOID BiosLocation = NULL;
DWORD BiosSize = 0; DWORD BiosSize = 0;
@ -199,8 +128,8 @@ BiosInitialize(IN LPCSTR BiosFileName)
Success = Bios32Loaded = Bios32Initialize(); Success = Bios32Loaded = Bios32Initialize();
} }
/* Enable interrupts */ // /* Enable interrupts */
setIF(1); // setIF(1);
return Success; return Success;
} }

View file

@ -17,6 +17,16 @@
/* DEFINES ********************************************************************/ /* DEFINES ********************************************************************/
/* BOP Identifiers */
#define BOP_RESET 0x00 // Windows NTVDM (SoftPC) BIOS calls BOP 0x00
// to let the virtual machine initialize itself
// the IVT and its hardware.
#define BOP_EQUIPLIST 0x11
#define BOP_GETMEMSIZE 0x12
#define BDA_SEGMENT 0x40 #define BDA_SEGMENT 0x40
#define BIOS_SEGMENT 0xF000 #define BIOS_SEGMENT 0xF000

View file

@ -15,8 +15,8 @@
#include "emulator.h" #include "emulator.h"
#include "cpu/cpu.h" // for EMULATOR_FLAG_CF #include "cpu/cpu.h" // for EMULATOR_FLAG_CF
#include "cpu/bop.h"
#include "int32.h" #include "int32.h"
// #include "bop.h"
#include "../bios.h" #include "../bios.h"
#include "../rom.h" #include "../rom.h"
@ -129,7 +129,8 @@ static BYTE Bootstrap[] =
*/ */
static BYTE PostCode[] = static BYTE PostCode[] =
{ {
0xCD, 0x19, // int 0x19, the bootstrap loader interrupt LOBYTE(EMULATOR_BOP), HIBYTE(EMULATOR_BOP), BOP_RESET, // Call BIOS POST
0xCD, 0x19, // INT 0x19, the bootstrap loader interrupt
// LOBYTE(EMULATOR_BOP), HIBYTE(EMULATOR_BOP), BOP_UNSIMULATE // LOBYTE(EMULATOR_BOP), HIBYTE(EMULATOR_BOP), BOP_UNSIMULATE
}; };
@ -278,17 +279,26 @@ static VOID WINAPI BiosRomBasic(LPWORD Stack)
return; return;
} }
VOID DosBootsectorInitialize(VOID);
static VOID WINAPI BiosBootstrapLoader(LPWORD Stack) static VOID WINAPI BiosBootstrapLoader(LPWORD Stack)
{ {
/* /*
* In real bioses one loads the bootsector read from a diskette * In real BIOSes one loads the bootsector read from a diskette
* or from a disk, to 0000:7C00 and then one runs it. * or from a disk, copy it to 0000:7C00 and then boot it.
* Since we are 32-bit VM and we hardcode our DOS at the moment, * Since we are 32-bit VM and we hardcode our DOS at the moment,
* just call the DOS 32-bit initialization code. * just call the DOS 32-bit initialization code.
*/ */
DPRINT1("BiosBootstrapLoader -->\n"); DPRINT1("BiosBootstrapLoader -->\n");
/* Load DOS */
DosBootsectorInitialize();
/* Position CPU to 0000:7C00 to boot the OS */
setCS(0x0000);
setIP(0x7C00);
DPRINT1("<-- BiosBootstrapLoader\n"); DPRINT1("<-- BiosBootstrapLoader\n");
} }
@ -510,37 +520,10 @@ static VOID InitializeBiosInt32(VOID)
((PULONG)BaseAddress)[0x49] = (ULONG)NULL; ((PULONG)BaseAddress)[0x49] = (ULONG)NULL;
} }
static VOID InitializeBiosInfo(VOID)
{
RtlZeroMemory(Bct, sizeof(*Bct));
Bct->Length = sizeof(*Bct);
Bct->Model = BIOS_MODEL;
Bct->SubModel = BIOS_SUBMODEL;
Bct->Revision = BIOS_REVISION;
Bct->Feature[0] = 0x70; // At the moment we don't support "wait for external event (INT 15/AH=41h)", we also don't have any "extended BIOS area allocated (usually at top of RAM)"; see http://www.ctyme.com/intr/rb-1594.htm#Table510
Bct->Feature[1] = 0x00; // We don't support anything from here; see http://www.ctyme.com/intr/rb-1594.htm#Table511
Bct->Feature[2] = 0x00;
Bct->Feature[3] = 0x00;
Bct->Feature[4] = 0x00;
}
static VOID InitializeBiosData(VOID) static VOID InitializeBiosData(VOID)
{ {
UCHAR Low, High; UCHAR Low, High;
/* System BIOS Copyright */
RtlCopyMemory(SEG_OFF_TO_PTR(0xF000, 0xE000), BiosCopyright, sizeof(BiosCopyright)-1);
/* System BIOS Version */
RtlCopyMemory(SEG_OFF_TO_PTR(0xF000, 0xE080), BiosVersion, sizeof(BiosVersion)-1); // FIXME: or E061, or E100 ??
/* System BIOS Date */
RtlCopyMemory(SEG_OFF_TO_PTR(0xF000, 0xFFF5), BiosDate, sizeof(BiosDate)-1);
/* System BIOS Model (same as Bct->Model) */
*(PBYTE)(SEG_OFF_TO_PTR(0xF000, 0xFFFE)) = BIOS_MODEL;
/* Initialize the BDA contents */ /* Initialize the BDA contents */
RtlZeroMemory(Bda, sizeof(*Bda)); RtlZeroMemory(Bda, sizeof(*Bda));
Bda->EquipmentList = BIOS_EQUIPMENT_LIST; Bda->EquipmentList = BIOS_EQUIPMENT_LIST;
@ -556,15 +539,33 @@ static VOID InitializeBiosData(VOID)
Bda->MemorySize = MAKEWORD(Low, High); Bda->MemorySize = MAKEWORD(Low, High);
} }
/* PUBLIC FUNCTIONS ***********************************************************/ static VOID InitializeBiosInfo(VOID)
{
RtlZeroMemory(Bct, sizeof(*Bct));
Bct->Length = sizeof(*Bct);
Bct->Model = BIOS_MODEL;
Bct->SubModel = BIOS_SUBMODEL;
Bct->Revision = BIOS_REVISION;
Bct->Feature[0] = 0x70; // At the moment we don't support "wait for external event (INT 15/AH=41h)", we also don't have any "extended BIOS area allocated (usually at top of RAM)"; see http://www.ctyme.com/intr/rb-1594.htm#Table510
Bct->Feature[1] = 0x00; // We don't support anything from here; see http://www.ctyme.com/intr/rb-1594.htm#Table511
Bct->Feature[2] = 0x00;
Bct->Feature[3] = 0x00;
Bct->Feature[4] = 0x00;
}
/* /*
* The BIOS POST (Power On-Self Test) * The BIOS POST (Power On-Self Test)
*/ */
BOOLEAN Bios32Initialize(VOID) VOID
Bios32Post(VOID)
{ {
BOOLEAN Success; BOOLEAN Success;
DPRINT1("Bios32Post\n");
/* Initialize the stack */ /* Initialize the stack */
// That's what says IBM... (stack at 30:00FF going downwards) // That's what says IBM... (stack at 30:00FF going downwards)
// setSS(0x0000); // setSS(0x0000);
@ -587,7 +588,13 @@ BOOLEAN Bios32Initialize(VOID)
/* Initialize the Keyboard, Video and Mouse BIOS */ /* Initialize the Keyboard, Video and Mouse BIOS */
if (!KbdBios32Initialize() || !VidBios32Initialize() || !MouseBios32Initialize()) if (!KbdBios32Initialize() || !VidBios32Initialize() || !MouseBios32Initialize())
return FALSE; {
// return FALSE;
/* Stop the VDM */
EmulatorTerminate();
return;
}
///////////// MUST BE DONE AFTER IVT INITIALIZATION !! ///////////////////// ///////////// MUST BE DONE AFTER IVT INITIALIZATION !! /////////////////////
@ -597,10 +604,70 @@ BOOLEAN Bios32Initialize(VOID)
SearchAndInitRoms(&BiosContext); SearchAndInitRoms(&BiosContext);
/*
* End of the 32-bit POST portion. We then fall back into 16-bit where
* the rest of the POST code is executed, typically calling INT 19h
* to boot up the OS.
*/
}
static VOID WINAPI Bios32ResetBop(LPWORD Stack)
{
DPRINT1("Bios32ResetBop\n");
/* Disable interrupts */
setIF(0);
// FIXME: Check the word at 0040h:0072h and do one of the following actions:
// - if the word is 1234h, perform a warm reboot (aka. Ctrl-Alt-Del);
// - if the word is 0000h, perform a cold reboot (aka. Reset).
/* Initialize IVT and hardware */
/* Initialize the Keyboard and Video BIOS */
if (!KbdBiosInitialize() || !VidBiosInitialize())
{
/* Stop the VDM */
EmulatorTerminate();
return;
}
/* Do the POST */
Bios32Post();
/* Enable interrupts */
setIF(1);
}
/* PUBLIC FUNCTIONS ***********************************************************/
BOOLEAN Bios32Initialize(VOID)
{
/*
* Initialize BIOS32 static data
*/
/* Bootstrap code */ /* Bootstrap code */
RtlCopyMemory(SEG_OFF_TO_PTR(0xF000, 0xE05B), PostCode , sizeof(PostCode )); RtlCopyMemory(SEG_OFF_TO_PTR(0xF000, 0xE05B), PostCode , sizeof(PostCode ));
RtlCopyMemory(SEG_OFF_TO_PTR(0xF000, 0xFFF0), Bootstrap, sizeof(Bootstrap)); RtlCopyMemory(SEG_OFF_TO_PTR(0xF000, 0xFFF0), Bootstrap, sizeof(Bootstrap));
/* System BIOS Copyright */
RtlCopyMemory(SEG_OFF_TO_PTR(0xF000, 0xE000), BiosCopyright, sizeof(BiosCopyright)-1);
/* System BIOS Version */
RtlCopyMemory(SEG_OFF_TO_PTR(0xF000, 0xE080), BiosVersion, sizeof(BiosVersion)-1);
// FIXME: or E061, or E100 ??
/* System BIOS Date */
RtlCopyMemory(SEG_OFF_TO_PTR(0xF000, 0xFFF5), BiosDate, sizeof(BiosDate)-1);
/* System BIOS Model (same as Bct->Model) */
*(PBYTE)(SEG_OFF_TO_PTR(0xF000, 0xFFFE)) = BIOS_MODEL;
/* Redefine our POST function */
RegisterBop(BOP_RESET, Bios32ResetBop);
/* We are done */ /* We are done */
return TRUE; return TRUE;
} }

View file

@ -33,8 +33,10 @@
/* DEFINES ********************************************************************/ /* DEFINES ********************************************************************/
/* BOP Identifiers */ /* BOP Identifiers */
#define BOP_DOS 0x50 // DOS System BOP (for NTIO.SYS and NTDOS.SYS) #define BOP_LOAD_DOS 0x2B // DOS Loading and Initializing BOP. In parameter (following bytes) we take a NULL-terminated string indicating the name of the DOS kernel file.
#define BOP_CMD 0x54 // DOS Command Interpreter BOP (for COMMAND.COM) #define BOP_START_DOS 0x2C // DOS Starting BOP. In parameter (following bytes) we take a NULL-terminated string indicating the name of the DOS kernel file.
#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 **********************************************************/ /* PRIVATE FUNCTIONS **********************************************************/
@ -185,17 +187,157 @@ static VOID WINAPI DosCmdInterpreterBop(LPWORD Stack)
} }
} }
#ifndef STANDALONE
static DWORD
WINAPI
CommandThreadProc(LPVOID Parameter)
{
BOOLEAN First = TRUE;
DWORD Result;
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 = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, EnvSize);
UNREFERENCED_PARAMETER(Parameter);
ASSERT(Env != NULL);
do
{
/* Clear the structure */
ZeroMemory(&CommandInfo, sizeof(CommandInfo));
/* Initialize the structure members */
CommandInfo.TaskId = SessionId;
CommandInfo.VDMState = VDM_FLAG_DOS;
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;
if (First) CommandInfo.VDMState |= VDM_FLAG_FIRST_TASK;
Command:
if (!GetNextVDMCommand(&CommandInfo))
{
if (CommandInfo.EnvLen > EnvSize)
{
/* Expand the environment size */
EnvSize = CommandInfo.EnvLen;
Env = HeapReAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, Env, EnvSize);
/* Repeat the request */
goto Command;
}
break;
}
/* Start the process from the command line */
DPRINT1("Starting '%s' ('%s')...\n", AppName, CmdLine);
Result = DosStartProcess(AppName, CmdLine, Env);
if (Result != ERROR_SUCCESS)
{
DisplayMessage(L"Could not start '%S'. Error: %u", AppName, Result);
// break;
continue;
}
First = FALSE;
}
while (AcceptCommands);
HeapFree(GetProcessHeap(), 0, Env);
return 0;
}
#endif
/* PUBLIC FUNCTIONS ***********************************************************/ /* PUBLIC FUNCTIONS ***********************************************************/
BOOLEAN DosInitialize(IN LPCSTR DosKernelFileName) //
// This function (equivalent of the DOS bootsector) is called by the bootstrap
// loader *BEFORE* jumping at 0000:7C00. What we should do is to write at 0000:7C00
// a BOP call that calls DosInitialize back. Then the bootstrap loader jumps at
// 0000:7C00, our BOP gets called and then we can initialize the 32-bit part of the DOS.
//
/* 16-bit bootstrap code at 0000:7C00 */
/* Of course, this is not in real bootsector format, because we don't care */
static BYTE Bootsector1[] =
{ {
LOBYTE(EMULATOR_BOP), HIBYTE(EMULATOR_BOP), BOP_LOAD_DOS, // Call DOS Loading
};
/* This portion of code is run if we failed to load the DOS */
static BYTE Bootsector2[] =
{
0xEA, // jmp far ptr
0x5B, 0xE0, 0x00, 0xF0, // F000:E05B /** HACK! What to do instead?? **/
};
static VOID WINAPI DosInitialize(LPWORD Stack);
VOID DosBootsectorInitialize(VOID)
{
/* We write the bootsector at 0000:7C00 */
ULONG_PTR Address = (ULONG_PTR)SEG_OFF_TO_PTR(0x0000, 0x7C00);
CHAR DosKernelFileName[] = ""; // No DOS file name, therefore we'll load DOS32
DPRINT1("DosBootsectorInitialize\n");
/* Write the "bootsector" */
RtlCopyMemory((PVOID)Address, Bootsector1, sizeof(Bootsector1));
Address += sizeof(Bootsector1);
RtlCopyMemory((PVOID)Address, DosKernelFileName, sizeof(DosKernelFileName));
Address += sizeof(DosKernelFileName);
RtlCopyMemory((PVOID)Address, Bootsector2, sizeof(Bootsector2));
/* Register the DOS Loading BOP */
RegisterBop(BOP_LOAD_DOS, DosInitialize);
}
//
// This function is called by the DOS bootsector. We finish to load
// the DOS, then we jump to 0070:0000.
//
/* 16-bit startup code at 0070:0000 */
static BYTE Startup[] =
{
LOBYTE(EMULATOR_BOP), HIBYTE(EMULATOR_BOP), BOP_START_DOS, // Call DOS Start
};
static VOID WINAPI DosStart(LPWORD Stack);
static VOID WINAPI DosInitialize(LPWORD Stack)
{
BOOLEAN Success = FALSE;
/* Get the DOS kernel file name (NULL-terminated) */
// FIXME: Isn't it possible to use some DS:SI instead??
LPCSTR DosKernelFileName = (LPCSTR)SEG_OFF_TO_PTR(getCS(), getIP());
setIP(getIP() + strlen(DosKernelFileName) + 1); // Skip it
DPRINT1("DosInitialize('%s')\n", DosKernelFileName);
/* Register the DOS BOPs */ /* Register the DOS BOPs */
RegisterBop(BOP_DOS, DosSystemBop ); RegisterBop(BOP_DOS, DosSystemBop );
RegisterBop(BOP_CMD, DosCmdInterpreterBop); RegisterBop(BOP_CMD, DosCmdInterpreterBop);
if (DosKernelFileName) if (DosKernelFileName && DosKernelFileName[0] != '\0')
{ {
BOOLEAN Success;
HANDLE hDosBios; HANDLE hDosBios;
ULONG ulDosBiosSize = 0; ULONG ulDosBiosSize = 0;
@ -203,7 +345,7 @@ BOOLEAN DosInitialize(IN LPCSTR DosKernelFileName)
hDosBios = FileOpen(DosKernelFileName, &ulDosBiosSize); hDosBios = FileOpen(DosKernelFileName, &ulDosBiosSize);
/* If we failed, bail out */ /* If we failed, bail out */
if (hDosBios == NULL) return FALSE; if (hDosBios == NULL) goto QuitCustom;
/* Attempt to load the DOS BIOS into memory */ /* Attempt to load the DOS BIOS into memory */
Success = FileLoadByHandle(hDosBios, Success = FileLoadByHandle(hDosBios,
@ -220,27 +362,122 @@ BOOLEAN DosInitialize(IN LPCSTR DosKernelFileName)
/* Close the DOS BIOS file */ /* Close the DOS BIOS file */
FileClose(hDosBios); FileClose(hDosBios);
if (Success) if (!Success) goto QuitCustom;
{
/* Position execution pointers and return */
setCS(0x0070);
setIP(0x0000);
}
return Success; /* Position execution pointers and return */
setCS(0x0070);
setIP(0x0000);
/* Return control */
QuitCustom:
if (!Success)
DisplayMessage(L"Custom DOS '%S' loading failed, what to do??", DosKernelFileName);
} }
else else
{ {
BOOLEAN Result; Success = DosBIOSInitialize();
// Success &= DosKRNLInitialize();
Result = DosBIOSInitialize(); if (!Success) goto Quit32;
DosMouseInitialize(); // FIXME: Should be done by the DOS BIOS
// Result &= DosKRNLInitialize();
return Result; /* Write the "bootsector" */
RtlCopyMemory(SEG_OFF_TO_PTR(0x0070, 0x0000), Startup, sizeof(Startup));
/* Register the DOS Starting BOP */
RegisterBop(BOP_START_DOS, DosStart);
/* Position execution pointers and return */
setCS(0x0070);
setIP(0x0000);
/* Return control */
Quit32:
if (!Success)
DisplayMessage(L"DOS32 loading failed, what to do??");
}
if (Success)
{
/*
* We succeeded, deregister the DOS Loading BOP
* so that no app will be able to call us back.
*/
RegisterBop(BOP_LOAD_DOS, NULL);
} }
} }
static VOID WINAPI DosStart(LPWORD Stack)
{
#ifdef STANDALONE
DWORD Result;
CHAR ApplicationName[MAX_PATH];
CHAR CommandLine[DOS_CMDLINE_LENGTH];
#endif
DPRINT1("DosStart\n");
/*
* We succeeded, deregister the DOS Starting BOP
* so that no app will be able to call us back.
*/
RegisterBop(BOP_START_DOS, NULL);
/* Load the mouse driver */
DosMouseInitialize();
#ifndef STANDALONE
/* Create the GetNextVDMCommand thread */
CommandThread = CreateThread(NULL, 0, &CommandThreadProc, NULL, 0, NULL);
if (CommandThread == NULL)
{
wprintf(L"FATAL: Failed to create the command processing thread: %d\n", GetLastError());
goto Quit;
}
/* Wait for the command thread to exit */
WaitForSingleObject(CommandThread, INFINITE);
/* Close the thread handle */
CloseHandle(CommandThread);
#else
if (NtVdmArgc >= 2)
{
WideCharToMultiByte(CP_ACP, 0, NtVdmArgv[1], -1, ApplicationName, sizeof(ApplicationName), NULL, NULL);
if (NtVdmArgc >= 3)
WideCharToMultiByte(CP_ACP, 0, NtVdmArgv[2], -1, CommandLine, sizeof(CommandLine), NULL, NULL);
else
strcpy(CommandLine, "");
}
else
{
DisplayMessage(L"Invalid DOS command line\n");
goto Quit;
}
/* Start the process from the command line */
DPRINT1("Starting '%s' ('%s')...\n", ApplicationName, CommandLine);
Result = DosStartProcess(ApplicationName,
CommandLine,
GetEnvironmentStrings());
if (Result != ERROR_SUCCESS)
{
DisplayMessage(L"Could not start '%S'. Error: %u", ApplicationName, Result);
goto Quit;
}
#endif
Quit:
/* Stop the VDM */
EmulatorTerminate();
}
/* PUBLIC EXPORTED APIS *******************************************************/ /* PUBLIC EXPORTED APIS *******************************************************/
// demLFNCleanup // demLFNCleanup

View file

@ -20,8 +20,6 @@
/* FUNCTIONS ******************************************************************/ /* FUNCTIONS ******************************************************************/
BOOLEAN DosInitialize(IN LPCSTR DosKernelFileNames);
DWORD DWORD
WINAPI WINAPI
demClientErrorEx demClientErrorEx

View file

@ -12,6 +12,7 @@
#include "ntvdm.h" #include "ntvdm.h"
#include "emulator.h" #include "emulator.h"
#include "cpu/cpu.h"
#include "clock.h" #include "clock.h"
#include "hardware/ps2.h" #include "hardware/ps2.h"
@ -26,19 +27,25 @@
static HANDLE ConsoleInput = INVALID_HANDLE_VALUE; static HANDLE ConsoleInput = INVALID_HANDLE_VALUE;
static HANDLE ConsoleOutput = INVALID_HANDLE_VALUE; static HANDLE ConsoleOutput = INVALID_HANDLE_VALUE;
static DWORD OrgConsoleInputMode, OrgConsoleOutputMode; static DWORD OrgConsoleInputMode, OrgConsoleOutputMode;
static BOOLEAN AcceptCommands = TRUE;
static HANDLE CommandThread = NULL;
static HMENU hConsoleMenu = NULL;
static INT VdmMenuPos = -1;
static BOOLEAN ShowPointer = FALSE;
// For DOS
#ifndef STANDALONE #ifndef STANDALONE
BOOLEAN AcceptCommands = TRUE;
HANDLE CommandThread = NULL;
ULONG SessionId = 0; ULONG SessionId = 0;
#endif #endif
HANDLE VdmTaskEvent = NULL; HANDLE VdmTaskEvent = NULL;
// Command line of NTVDM
INT NtVdmArgc;
WCHAR** NtVdmArgv;
static HMENU hConsoleMenu = NULL;
static INT VdmMenuPos = -1;
static BOOLEAN ShowPointer = FALSE;
/* /*
* Those menu helpers were taken from the GUI frontend in winsrv.dll * Those menu helpers were taken from the GUI frontend in winsrv.dll
*/ */
@ -198,6 +205,7 @@ ConsoleCtrlHandler(DWORD ControlType)
case CTRL_BREAK_EVENT: case CTRL_BREAK_EVENT:
{ {
/* Call INT 23h */ /* Call INT 23h */
DPRINT1("Ctrl-C/Break: Call INT 23h\n");
EmulatorInterrupt(0x23); EmulatorInterrupt(0x23);
break; break;
} }
@ -206,14 +214,18 @@ ConsoleCtrlHandler(DWORD ControlType)
if (WaitForSingleObject(VdmTaskEvent, 0) == WAIT_TIMEOUT) if (WaitForSingleObject(VdmTaskEvent, 0) == WAIT_TIMEOUT)
{ {
/* Exit immediately */ /* Exit immediately */
#ifndef STANDALONE
if (CommandThread) TerminateThread(CommandThread, 0); if (CommandThread) TerminateThread(CommandThread, 0);
#endif
EmulatorTerminate(); EmulatorTerminate();
} }
#ifndef STANDALONE
else else
{ {
/* Stop accepting new commands */ /* Stop accepting new commands */
AcceptCommands = FALSE; AcceptCommands = FALSE;
} }
#endif
break; break;
} }
@ -361,100 +373,12 @@ VOID FocusEventHandler(PFOCUS_EVENT_RECORD FocusEvent)
DPRINT1("Focus events not handled\n"); DPRINT1("Focus events not handled\n");
} }
#ifndef STANDALONE
static DWORD
WINAPI
CommandThreadProc(LPVOID Parameter)
{
BOOLEAN First = TRUE;
DWORD Result;
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 = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, EnvSize);
UNREFERENCED_PARAMETER(Parameter);
ASSERT(Env != NULL);
do
{
/* Clear the structure */
ZeroMemory(&CommandInfo, sizeof(CommandInfo));
/* Initialize the structure members */
CommandInfo.TaskId = SessionId;
CommandInfo.VDMState = VDM_FLAG_DOS;
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;
if (First) CommandInfo.VDMState |= VDM_FLAG_FIRST_TASK;
Command:
if (!GetNextVDMCommand(&CommandInfo))
{
if (CommandInfo.EnvLen > EnvSize)
{
/* Expand the environment size */
EnvSize = CommandInfo.EnvLen;
Env = HeapReAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, Env, EnvSize);
/* Repeat the request */
goto Command;
}
break;
}
/* Start the process from the command line */
DPRINT1("Starting '%s' ('%s')...\n", AppName, CmdLine);
Result = DosStartProcess(AppName, CmdLine, Env);
if (Result != ERROR_SUCCESS)
{
DisplayMessage(L"Could not start '%S'. Error: %u", AppName, Result);
// break;
continue;
}
First = FALSE;
}
while (AcceptCommands);
HeapFree(GetProcessHeap(), 0, Env);
return 0;
}
#endif
INT INT
wmain(INT argc, WCHAR *argv[]) wmain(INT argc, WCHAR *argv[])
{ {
#ifdef STANDALONE #ifdef STANDALONE
DWORD Result; if (argc < 2)
CHAR ApplicationName[MAX_PATH];
CHAR CommandLine[DOS_CMDLINE_LENGTH];
if (argc >= 2)
{
WideCharToMultiByte(CP_ACP, 0, argv[1], -1, ApplicationName, sizeof(ApplicationName), NULL, NULL);
if (argc >= 3) WideCharToMultiByte(CP_ACP, 0, argv[2], -1, CommandLine, sizeof(CommandLine), NULL, NULL);
else strcpy(CommandLine, "");
}
else
{ {
wprintf(L"\nReactOS Virtual DOS Machine\n\n" wprintf(L"\nReactOS Virtual DOS Machine\n\n"
L"Usage: NTVDM <executable> [<parameters>]\n"); L"Usage: NTVDM <executable> [<parameters>]\n");
@ -481,6 +405,9 @@ wmain(INT argc, WCHAR *argv[])
#endif #endif
NtVdmArgc = argc;
NtVdmArgv = argv;
DPRINT1("\n\n\nNTVDM - Starting...\n\n\n"); DPRINT1("\n\n\nNTVDM - Starting...\n\n\n");
/* Create the task event */ /* Create the task event */
@ -508,43 +435,8 @@ wmain(INT argc, WCHAR *argv[])
goto Cleanup; goto Cleanup;
} }
/* Initialize the VDM DOS kernel */ /* Let's go! Start simulation */
if (!DosInitialize(NULL)) CpuSimulate();
{
wprintf(L"FATAL: Failed to initialize the VDM DOS kernel.\n");
goto Cleanup;
}
#ifndef STANDALONE
/* Create the GetNextVDMCommand thread */
CommandThread = CreateThread(NULL, 0, &CommandThreadProc, NULL, 0, NULL);
if (CommandThread == NULL)
{
wprintf(L"FATAL: Failed to create the command processing thread: %d\n", GetLastError());
goto Cleanup;
}
/* Wait for the command thread to exit */
WaitForSingleObject(CommandThread, INFINITE);
/* Close the thread handle */
CloseHandle(CommandThread);
#else
/* Start the process from the command line */
DPRINT1("Starting '%s' ('%s')...\n", ApplicationName, CommandLine);
Result = DosStartProcess(ApplicationName,
CommandLine,
GetEnvironmentStrings());
if (Result != ERROR_SUCCESS)
{
DisplayMessage(L"Could not start '%S'. Error: %u", ApplicationName, Result);
goto Cleanup;
}
#endif
Cleanup: Cleanup:
BiosCleanup(); BiosCleanup();

View file

@ -41,11 +41,18 @@ DWORD WINAPI SetLastConsoleEventActive(VOID);
/* FUNCTIONS ******************************************************************/ /* FUNCTIONS ******************************************************************/
#ifndef STANDALONE #ifndef STANDALONE
extern BOOLEAN AcceptCommands;
extern HANDLE CommandThread;
extern ULONG SessionId; extern ULONG SessionId;
#endif #endif
extern HANDLE VdmTaskEvent; extern HANDLE VdmTaskEvent;
// Command line of NTVDM
extern INT NtVdmArgc;
extern WCHAR** NtVdmArgv;
/* /*
* Interface functions * Interface functions
*/ */