reactos/subsystems/mvdm/ntvdm/emulator.c

684 lines
17 KiB
C
Raw Permalink Normal View History

/*
* COPYRIGHT: GPL - See COPYING in the top level directory
* PROJECT: ReactOS Virtual DOS Machine
* FILE: subsystems/mvdm/ntvdm/emulator.c
* PURPOSE: Minimal x86 machine emulator for the VDM
* PROGRAMMERS: Aleksandar Andrejevic <theflash AT sdf DOT lonestar DOT org>
*/
/* INCLUDES *******************************************************************/
#include "ntvdm.h"
#define NDEBUG
#include <debug.h>
#include "emulator.h"
#include "memory.h"
#include "cpu/callback.h"
#include "cpu/cpu.h"
#include "cpu/bop.h"
#include <isvbop.h>
#include "int32.h"
#include "clock.h"
#include "bios/rom.h"
#include "hardware/cmos.h"
#include "hardware/disk.h"
#include "hardware/dma.h"
#include "hardware/keyboard.h"
#include "hardware/mouse.h"
#include "hardware/pic.h"
#include "hardware/pit.h"
#include "hardware/ppi.h"
#include "hardware/ps2.h"
#include "hardware/sound/speaker.h"
#include "hardware/video/svga.h"
/**/
#include "./console/video.h"
/**/
#include "vddsup.h"
#include "io.h"
/* PRIVATE VARIABLES **********************************************************/
LPVOID BaseAddress = NULL;
BOOLEAN VdmRunning = TRUE;
HANDLE VdmTaskEvent = NULL;
static HANDLE InputThread = NULL;
[NTVDM] - Move all the hardware initialization to EmulatorInitialize (since emulator.c can be viewed as support functions for emulating a PC motherboard) --> PS2 and VGA go there. - Break bios.c into bios.c and kbdbios.c (the keyboard bios module) (according to the IBM documentation as well as other emulator sources or SeaBIOS or...). - Move Exception handling from int32.c to emulator.c, because it's something tight to the emulator, not to the interrupt system by itself (yet it happens that INT 00h to 07h are commonly set to some exception handlers). In the bios.c, initialize those vectors with the default exception handler. - Handling IRQs is done fully in bios.c now: introduce PicSetIRQMask and EnableHwIRQ helper functions (adapted from their equivalents from SeaBIOS) that allows the bios to set (and activate in the PIC) a given IRQ with its corresponding handler. Also introduce PicIRQComplete that serves as a PIC IRQ completer (i.e. sends the EOI to the right PIC(s)). - Continuing on that, at the moment I set dumb default PIC IRQ handlers for IRQ 08h - 0Fh and IRQ 70h - 77h). - By default I disable all the IRQs; there are then set on-demand with EnableHwIRQ. - Rework the POST (aka. BiosInitialize function): * the memory size is now get from the CMOS (as well as the extended memory size via INT 12h, AH=88h), * then we initialize the interrupts, * then platform hardware (ie. the chips) are initialized, * and finally the keyboard and video bioses. - As said before, move memory sizes into the CMOS. - Simplify video bios initialization. svn path=/branches/ntvdm/; revision=61796
2014-01-25 00:21:51 +00:00
LPCWSTR ExceptionName[] =
{
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"
};
/* BOP Identifiers */
#define BOP_DEBUGGER 0x56 // Break into the debugger from a 16-bit app
/* PRIVATE FUNCTIONS **********************************************************/
UCHAR FASTCALL EmulatorIntAcknowledge(PFAST486_STATE State)
{
UNREFERENCED_PARAMETER(State);
/* Get the interrupt number from the PIC */
return PicGetInterrupt();
}
VOID FASTCALL EmulatorFpu(PFAST486_STATE State)
{
/* The FPU is wired to IRQ 13 */
PicInterruptRequest(13);
}
VOID EmulatorException(BYTE ExceptionNumber, LPWORD Stack)
{
WORD CodeSegment, InstructionPointer;
PBYTE Opcode;
ASSERT(ExceptionNumber < 8);
/* Get the CS:IP */
InstructionPointer = Stack[STACK_IP];
CodeSegment = Stack[STACK_CS];
Opcode = (PBYTE)SEG_OFF_TO_PTR(CodeSegment, InstructionPointer);
/* Display a message to the user */
DisplayMessage(L"Exception: %s occurred at %04X:%04X\n"
L"Opcode: %02X %02X %02X %02X %02X %02X %02X %02X %02X %02X",
ExceptionName[ExceptionNumber],
CodeSegment,
InstructionPointer,
Opcode[0],
Opcode[1],
Opcode[2],
Opcode[3],
Opcode[4],
Opcode[5],
Opcode[6],
Opcode[7],
Opcode[8],
Opcode[9]);
Fast486DumpState(&EmulatorContext);
/* Stop the VDM */
EmulatorTerminate();
}
VOID EmulatorInterruptSignal(VOID)
{
/* Call the Fast486 API */
Fast486InterruptSignal(&EmulatorContext);
}
static VOID WINAPI EmulatorDebugBreakBop(LPWORD Stack)
{
DPRINT1("NTVDM: BOP_DEBUGGER\n");
DebugBreak();
}
static VOID WINAPI PitChan0Out(LPVOID Param, BOOLEAN State)
{
if (State)
{
DPRINT("PicInterruptRequest\n");
PicInterruptRequest(0); // Raise IRQ 0
}
// else < Lower IRQ 0 >
}
static VOID WINAPI PitChan1Out(LPVOID Param, BOOLEAN State)
{
#if 0
if (State)
{
/* Set bit 4 of Port 61h */
Port61hState |= 1 << 4;
}
else
{
/* Clear bit 4 of Port 61h */
Port61hState &= ~(1 << 4);
}
#else
Port61hState = (Port61hState & 0xEF) | (State << 4);
#endif
}
static VOID WINAPI PitChan2Out(LPVOID Param, BOOLEAN State)
{
BYTE OldPort61hState = Port61hState;
#if 0
if (State)
{
/* Set bit 5 of Port 61h */
Port61hState |= 1 << 5;
}
else
{
/* Clear bit 5 of Port 61h */
Port61hState &= ~(1 << 5);
}
#else
Port61hState = (Port61hState & 0xDF) | (State << 5);
#endif
if ((OldPort61hState ^ Port61hState) & 0x20)
{
DPRINT("PitChan2Out -- Port61hState changed\n");
SpeakerChange(Port61hState);
}
}
static DWORD
WINAPI
ConsoleEventThread(LPVOID Parameter)
{
HANDLE ConsoleInput = (HANDLE)Parameter;
HANDLE WaitHandles[2];
DWORD WaitResult;
/*
* For optimization purposes, Windows (and hence ReactOS, too, for
* compatibility reasons) uses a static buffer if no more than five
* input records are read. Otherwise a new buffer is used.
* The client-side expects that we know this behaviour.
* See consrv/coninput.c
*
* We exploit here this optimization by also using a buffer of 5 records.
*/
INPUT_RECORD InputRecords[5];
ULONG NumRecords, i;
WaitHandles[0] = VdmTaskEvent;
WaitHandles[1] = GetConsoleInputWaitHandle();
while (VdmRunning)
{
/* Make sure the task event is signaled */
WaitResult = WaitForMultipleObjects(ARRAYSIZE(WaitHandles),
WaitHandles,
TRUE,
INFINITE);
switch (WaitResult)
{
case WAIT_OBJECT_0 + 0:
case WAIT_OBJECT_0 + 1:
break;
default:
return GetLastError();
}
/* Wait for an input record */
if (!ReadConsoleInputExW(ConsoleInput,
InputRecords,
ARRAYSIZE(InputRecords),
&NumRecords,
CONSOLE_READ_NOWAIT))
{
DWORD LastError = GetLastError();
DPRINT1("Error reading console input (0x%p, %lu) - Error %lu\n", ConsoleInput, NumRecords, LastError);
return LastError;
}
// ASSERT(NumRecords != 0);
if (NumRecords == 0)
{
DPRINT1("Got NumRecords == 0!\n");
continue;
}
/* Dispatch the events */
for (i = 0; i < NumRecords; i++)
{
/* Check the event type */
switch (InputRecords[i].EventType)
{
/*
* Hardware events
*/
case KEY_EVENT:
KeyboardEventHandler(&InputRecords[i].Event.KeyEvent);
break;
case MOUSE_EVENT:
MouseEventHandler(&InputRecords[i].Event.MouseEvent);
break;
case WINDOW_BUFFER_SIZE_EVENT:
ScreenEventHandler(&InputRecords[i].Event.WindowBufferSizeEvent);
break;
/*
* Interface events
*/
case MENU_EVENT:
MenuEventHandler(&InputRecords[i].Event.MenuEvent);
break;
case FOCUS_EVENT:
FocusEventHandler(&InputRecords[i].Event.FocusEvent);
break;
default:
DPRINT1("Unknown input event type 0x%04x\n", InputRecords[i].EventType);
break;
}
}
/* Let the console subsystem queue some new events */
Sleep(10);
}
return 0;
}
static VOID PauseEventThread(VOID)
{
ResetEvent(VdmTaskEvent);
}
static VOID ResumeEventThread(VOID)
{
SetEvent(VdmTaskEvent);
}
/* PUBLIC FUNCTIONS ***********************************************************/
static VOID
DumpMemoryRaw(HANDLE hFile)
{
PVOID Buffer;
2018-02-11 23:38:10 +00:00
DWORD Size;
/* Dump the VM memory */
SetFilePointer(hFile, 0, NULL, FILE_BEGIN);
Buffer = REAL_TO_PHYS(NULL);
Size = MAX_ADDRESS - (ULONG_PTR)(NULL);
WriteFile(hFile, Buffer, Size, &Size, NULL);
}
static VOID
DumpMemoryTxt(HANDLE hFile)
{
#define LINE_SIZE 75 + 2
ULONG i;
PBYTE Ptr1, Ptr2;
CHAR LineBuffer[LINE_SIZE];
PCHAR Line;
2018-02-11 23:38:10 +00:00
DWORD LineSize;
/* Dump the VM memory */
SetFilePointer(hFile, 0, NULL, FILE_BEGIN);
Ptr1 = Ptr2 = REAL_TO_PHYS(NULL);
while (MAX_ADDRESS - (ULONG_PTR)PHYS_TO_REAL(Ptr1) > 0)
{
Ptr1 = Ptr2;
Line = LineBuffer;
/* Print the address */
2018-02-11 23:38:10 +00:00
Line += snprintf(Line, LINE_SIZE + LineBuffer - Line, "%08Ix ", (ULONG_PTR)PHYS_TO_REAL(Ptr1));
/* Print up to 16 bytes... */
/* ... in hexadecimal form first... */
i = 0;
while (i++ <= 0x0F && (MAX_ADDRESS - (ULONG_PTR)PHYS_TO_REAL(Ptr1) > 0))
{
Line += snprintf(Line, LINE_SIZE + LineBuffer - Line, " %02x", *Ptr1);
++Ptr1;
}
/* ... align with spaces if needed... */
RtlFillMemory(Line, (0x0F + 2 - i) * 3 + 2, ' ');
Line += (0x0F + 2 - i) * 3 + 2;
/* ... then in character form. */
i = 0;
while (i++ <= 0x0F && (MAX_ADDRESS - (ULONG_PTR)PHYS_TO_REAL(Ptr2) > 0))
{
*Line++ = ((*Ptr2 >= 0x20 && *Ptr2 <= 0x7E) || (*Ptr2 >= 0x80 && *Ptr2 < 0xFF) ? *Ptr2 : '.');
++Ptr2;
}
/* Newline */
*Line++ = '\r';
*Line++ = '\n';
/* Finally write the line to the file */
LineSize = Line - LineBuffer;
WriteFile(hFile, LineBuffer, LineSize, &LineSize, NULL);
}
}
VOID DumpMemory(BOOLEAN TextFormat)
{
static ULONG DumpNumber = 0;
HANDLE hFile;
WCHAR FileName[MAX_PATH];
/* Build a suitable file name */
_snwprintf(FileName, MAX_PATH,
L"memdump%lu.%s",
DumpNumber,
TextFormat ? L"txt" : L"dat");
++DumpNumber;
DPRINT1("Creating memory dump file '%S'...\n", FileName);
/* Always create the dump file */
hFile = CreateFileW(FileName,
GENERIC_WRITE,
0,
NULL,
CREATE_ALWAYS,
FILE_ATTRIBUTE_NORMAL,
NULL);
if (hFile == INVALID_HANDLE_VALUE)
{
DPRINT1("Error when creating '%S' for memory dumping, GetLastError() = %u\n",
FileName, GetLastError());
return;
}
/* Dump the VM memory in the chosen format */
if (TextFormat)
DumpMemoryTxt(hFile);
else
DumpMemoryRaw(hFile);
/* Close the file */
CloseHandle(hFile);
DPRINT1("Memory dump done\n");
}
VOID MountFloppy(IN ULONG DiskNumber)
{
// FIXME: This should be present in PSDK commdlg.h
//
// FlagsEx Values
#if (_WIN32_WINNT >= 0x0500)
#define OFN_EX_NOPLACESBAR 0x00000001
#endif // (_WIN32_WINNT >= 0x0500)
BOOLEAN Success;
OPENFILENAMEW ofn;
WCHAR szFile[MAX_PATH] = L"";
ASSERT(DiskNumber < ARRAYSIZE(GlobalSettings.FloppyDisks));
RtlZeroMemory(&ofn, sizeof(ofn));
ofn.lStructSize = sizeof(ofn);
ofn.hwndOwner = hConsoleWnd;
ofn.lpstrTitle = L"Select a virtual floppy image";
ofn.Flags = OFN_EXPLORER | OFN_ENABLESIZING | OFN_LONGNAMES | OFN_PATHMUSTEXIST | OFN_FILEMUSTEXIST;
// ofn.FlagsEx = OFN_EX_NOPLACESBAR;
ofn.lpstrFilter = L"Virtual floppy images (*.vfd;*.img;*.ima;*.dsk)\0*.vfd;*.img;*.ima;*.dsk\0All files (*.*)\0*.*\0\0";
ofn.lpstrDefExt = L"vfd";
ofn.nFilterIndex = 0;
ofn.lpstrFile = szFile;
ofn.nMaxFile = ARRAYSIZE(szFile);
if (!GetOpenFileNameW(&ofn))
{
DPRINT1("CommDlgExtendedError = %d\n", CommDlgExtendedError());
return;
}
/* Free the old string */
if (GlobalSettings.FloppyDisks[DiskNumber].Buffer)
RtlFreeUnicodeString(&GlobalSettings.FloppyDisks[DiskNumber]);
/* Reinitialize the string */
Success = RtlCreateUnicodeString(&GlobalSettings.FloppyDisks[DiskNumber], szFile);
ASSERT(Success);
/* Mount the disk */
if (!MountDisk(FLOPPY_DISK, DiskNumber, GlobalSettings.FloppyDisks[DiskNumber].Buffer, !!(ofn.Flags & OFN_READONLY)))
{
DisplayMessage(L"An error happened when mounting disk %d", DiskNumber);
RtlFreeUnicodeString(&GlobalSettings.FloppyDisks[DiskNumber]);
RtlInitEmptyUnicodeString(&GlobalSettings.FloppyDisks[DiskNumber], NULL, 0);
return;
}
/* Refresh the menu state */
UpdateVdmMenuDisks();
}
VOID EjectFloppy(IN ULONG DiskNumber)
{
ASSERT(DiskNumber < ARRAYSIZE(GlobalSettings.FloppyDisks));
/* Unmount the disk */
if (!UnmountDisk(FLOPPY_DISK, DiskNumber))
DisplayMessage(L"An error happened when ejecting disk %d", DiskNumber);
/* Free the old string */
if (GlobalSettings.FloppyDisks[DiskNumber].Buffer)
{
RtlFreeUnicodeString(&GlobalSettings.FloppyDisks[DiskNumber]);
RtlInitEmptyUnicodeString(&GlobalSettings.FloppyDisks[DiskNumber], NULL, 0);
}
/* Refresh the menu state */
UpdateVdmMenuDisks();
}
VOID EmulatorPause(VOID)
{
/* Pause the VDM */
VDDBlockUserHook();
VgaRefreshDisplay();
PauseEventThread();
}
VOID EmulatorResume(VOID)
{
/* Resume the VDM */
ResumeEventThread();
VgaRefreshDisplay();
VDDResumeUserHook();
}
VOID EmulatorTerminate(VOID)
{
/* Stop the VDM */
CpuUnsimulate(); // Halt the CPU
VdmRunning = FALSE;
}
[NTVDM] - Move all the hardware initialization to EmulatorInitialize (since emulator.c can be viewed as support functions for emulating a PC motherboard) --> PS2 and VGA go there. - Break bios.c into bios.c and kbdbios.c (the keyboard bios module) (according to the IBM documentation as well as other emulator sources or SeaBIOS or...). - Move Exception handling from int32.c to emulator.c, because it's something tight to the emulator, not to the interrupt system by itself (yet it happens that INT 00h to 07h are commonly set to some exception handlers). In the bios.c, initialize those vectors with the default exception handler. - Handling IRQs is done fully in bios.c now: introduce PicSetIRQMask and EnableHwIRQ helper functions (adapted from their equivalents from SeaBIOS) that allows the bios to set (and activate in the PIC) a given IRQ with its corresponding handler. Also introduce PicIRQComplete that serves as a PIC IRQ completer (i.e. sends the EOI to the right PIC(s)). - Continuing on that, at the moment I set dumb default PIC IRQ handlers for IRQ 08h - 0Fh and IRQ 70h - 77h). - By default I disable all the IRQs; there are then set on-demand with EnableHwIRQ. - Rework the POST (aka. BiosInitialize function): * the memory size is now get from the CMOS (as well as the extended memory size via INT 12h, AH=88h), * then we initialize the interrupts, * then platform hardware (ie. the chips) are initialized, * and finally the keyboard and video bioses. - As said before, move memory sizes into the CMOS. - Simplify video bios initialization. svn path=/branches/ntvdm/; revision=61796
2014-01-25 00:21:51 +00:00
BOOLEAN EmulatorInitialize(HANDLE ConsoleInput, HANDLE ConsoleOutput)
{
USHORT i;
/* Initialize memory */
if (!MemInitialize())
{
wprintf(L"Memory initialization failed.\n");
return FALSE;
}
/* Initialize I/O ports */
/* Initialize RAM */
/* Initialize the CPU */
/* Initialize the internal clock */
if (!ClockInitialize())
{
wprintf(L"FATAL: Failed to initialize the clock\n");
EmulatorCleanup();
return FALSE;
}
/* Initialize the CPU */
CpuInitialize();
/* Initialize DMA */
DmaInitialize();
/* Initialize PIC, PIT, CMOS, PC Speaker and PS/2 */
PicInitialize();
PitInitialize();
PitSetOutFunction(0, NULL, PitChan0Out);
PitSetOutFunction(1, NULL, PitChan1Out);
PitSetOutFunction(2, NULL, PitChan2Out);
CmosInitialize();
SpeakerInitialize();
PpiInitialize();
PS2Initialize();
/* Initialize the keyboard and mouse and connect them to their PS/2 ports */
KeyboardInit(0);
MouseInit(1);
[NTVDM] - Move all the hardware initialization to EmulatorInitialize (since emulator.c can be viewed as support functions for emulating a PC motherboard) --> PS2 and VGA go there. - Break bios.c into bios.c and kbdbios.c (the keyboard bios module) (according to the IBM documentation as well as other emulator sources or SeaBIOS or...). - Move Exception handling from int32.c to emulator.c, because it's something tight to the emulator, not to the interrupt system by itself (yet it happens that INT 00h to 07h are commonly set to some exception handlers). In the bios.c, initialize those vectors with the default exception handler. - Handling IRQs is done fully in bios.c now: introduce PicSetIRQMask and EnableHwIRQ helper functions (adapted from their equivalents from SeaBIOS) that allows the bios to set (and activate in the PIC) a given IRQ with its corresponding handler. Also introduce PicIRQComplete that serves as a PIC IRQ completer (i.e. sends the EOI to the right PIC(s)). - Continuing on that, at the moment I set dumb default PIC IRQ handlers for IRQ 08h - 0Fh and IRQ 70h - 77h). - By default I disable all the IRQs; there are then set on-demand with EnableHwIRQ. - Rework the POST (aka. BiosInitialize function): * the memory size is now get from the CMOS (as well as the extended memory size via INT 12h, AH=88h), * then we initialize the interrupts, * then platform hardware (ie. the chips) are initialized, * and finally the keyboard and video bioses. - As said before, move memory sizes into the CMOS. - Simplify video bios initialization. svn path=/branches/ntvdm/; revision=61796
2014-01-25 00:21:51 +00:00
/**************** ATTACH INPUT WITH CONSOLE *****************/
/* Create the task event */
VdmTaskEvent = CreateEventW(NULL, TRUE, FALSE, NULL);
ASSERT(VdmTaskEvent != NULL);
/* Start the input thread */
InputThread = CreateThread(NULL, 0, &ConsoleEventThread, ConsoleInput, 0, NULL);
if (InputThread == NULL)
{
wprintf(L"FATAL: Failed to create the console input thread.\n");
EmulatorCleanup();
return FALSE;
}
ResumeEventThread();
/************************************************************/
[NTVDM] - Move all the hardware initialization to EmulatorInitialize (since emulator.c can be viewed as support functions for emulating a PC motherboard) --> PS2 and VGA go there. - Break bios.c into bios.c and kbdbios.c (the keyboard bios module) (according to the IBM documentation as well as other emulator sources or SeaBIOS or...). - Move Exception handling from int32.c to emulator.c, because it's something tight to the emulator, not to the interrupt system by itself (yet it happens that INT 00h to 07h are commonly set to some exception handlers). In the bios.c, initialize those vectors with the default exception handler. - Handling IRQs is done fully in bios.c now: introduce PicSetIRQMask and EnableHwIRQ helper functions (adapted from their equivalents from SeaBIOS) that allows the bios to set (and activate in the PIC) a given IRQ with its corresponding handler. Also introduce PicIRQComplete that serves as a PIC IRQ completer (i.e. sends the EOI to the right PIC(s)). - Continuing on that, at the moment I set dumb default PIC IRQ handlers for IRQ 08h - 0Fh and IRQ 70h - 77h). - By default I disable all the IRQs; there are then set on-demand with EnableHwIRQ. - Rework the POST (aka. BiosInitialize function): * the memory size is now get from the CMOS (as well as the extended memory size via INT 12h, AH=88h), * then we initialize the interrupts, * then platform hardware (ie. the chips) are initialized, * and finally the keyboard and video bioses. - As said before, move memory sizes into the CMOS. - Simplify video bios initialization. svn path=/branches/ntvdm/; revision=61796
2014-01-25 00:21:51 +00:00
/* Initialize the VGA */
if (!VgaInitialize(ConsoleOutput))
{
wprintf(L"FATAL: Failed to initialize VGA support.\n");
EmulatorCleanup();
return FALSE;
}
[NTVDM] - Move all the hardware initialization to EmulatorInitialize (since emulator.c can be viewed as support functions for emulating a PC motherboard) --> PS2 and VGA go there. - Break bios.c into bios.c and kbdbios.c (the keyboard bios module) (according to the IBM documentation as well as other emulator sources or SeaBIOS or...). - Move Exception handling from int32.c to emulator.c, because it's something tight to the emulator, not to the interrupt system by itself (yet it happens that INT 00h to 07h are commonly set to some exception handlers). In the bios.c, initialize those vectors with the default exception handler. - Handling IRQs is done fully in bios.c now: introduce PicSetIRQMask and EnableHwIRQ helper functions (adapted from their equivalents from SeaBIOS) that allows the bios to set (and activate in the PIC) a given IRQ with its corresponding handler. Also introduce PicIRQComplete that serves as a PIC IRQ completer (i.e. sends the EOI to the right PIC(s)). - Continuing on that, at the moment I set dumb default PIC IRQ handlers for IRQ 08h - 0Fh and IRQ 70h - 77h). - By default I disable all the IRQs; there are then set on-demand with EnableHwIRQ. - Rework the POST (aka. BiosInitialize function): * the memory size is now get from the CMOS (as well as the extended memory size via INT 12h, AH=88h), * then we initialize the interrupts, * then platform hardware (ie. the chips) are initialized, * and finally the keyboard and video bioses. - As said before, move memory sizes into the CMOS. - Simplify video bios initialization. svn path=/branches/ntvdm/; revision=61796
2014-01-25 00:21:51 +00:00
/* Initialize the disk controller */
if (!DiskCtrlInitialize())
{
wprintf(L"FATAL: Failed to completely initialize the disk controller.\n");
EmulatorCleanup();
return FALSE;
}
/* Mount the available floppy disks */
for (i = 0; i < ARRAYSIZE(GlobalSettings.FloppyDisks); ++i)
{
if (GlobalSettings.FloppyDisks[i].Length != 0 &&
GlobalSettings.FloppyDisks[i].Buffer &&
*GlobalSettings.FloppyDisks[i].Buffer != L'\0')
{
if (!MountDisk(FLOPPY_DISK, i, GlobalSettings.FloppyDisks[i].Buffer, FALSE))
{
DPRINT1("Failed to mount floppy disk file '%wZ'.\n", &GlobalSettings.FloppyDisks[i]);
RtlFreeUnicodeString(&GlobalSettings.FloppyDisks[i]);
RtlInitEmptyUnicodeString(&GlobalSettings.FloppyDisks[i], NULL, 0);
}
}
}
/*
* Mount the available hard disks. Contrary to floppies, failing
* mounting a hard disk is considered as an unrecoverable error.
*/
for (i = 0; i < ARRAYSIZE(GlobalSettings.HardDisks); ++i)
{
if (GlobalSettings.HardDisks[i].Length != 0 &&
GlobalSettings.HardDisks[i].Buffer &&
*GlobalSettings.HardDisks[i].Buffer != L'\0')
{
if (!MountDisk(HARD_DISK, i, GlobalSettings.HardDisks[i].Buffer, FALSE))
{
wprintf(L"FATAL: Failed to mount hard disk file '%wZ'.\n", &GlobalSettings.HardDisks[i]);
EmulatorCleanup();
return FALSE;
}
}
}
/* Refresh the menu state */
UpdateVdmMenuDisks();
/* Initialize the software callback system and register the emulator BOPs */
InitializeInt32();
RegisterBop(BOP_DEBUGGER , EmulatorDebugBreakBop);
// RegisterBop(BOP_UNSIMULATE, CpuUnsimulateBop);
/* Initialize VDD support */
VDDSupInitialize();
return TRUE;
}
VOID EmulatorCleanup(VOID)
{
DiskCtrlCleanup();
VgaCleanup();
/* Close the input thread handle */
if (InputThread != NULL) CloseHandle(InputThread);
InputThread = NULL;
/* Close the task event */
if (VdmTaskEvent != NULL) CloseHandle(VdmTaskEvent);
VdmTaskEvent = NULL;
[NTVDM] - Move all the hardware initialization to EmulatorInitialize (since emulator.c can be viewed as support functions for emulating a PC motherboard) --> PS2 and VGA go there. - Break bios.c into bios.c and kbdbios.c (the keyboard bios module) (according to the IBM documentation as well as other emulator sources or SeaBIOS or...). - Move Exception handling from int32.c to emulator.c, because it's something tight to the emulator, not to the interrupt system by itself (yet it happens that INT 00h to 07h are commonly set to some exception handlers). In the bios.c, initialize those vectors with the default exception handler. - Handling IRQs is done fully in bios.c now: introduce PicSetIRQMask and EnableHwIRQ helper functions (adapted from their equivalents from SeaBIOS) that allows the bios to set (and activate in the PIC) a given IRQ with its corresponding handler. Also introduce PicIRQComplete that serves as a PIC IRQ completer (i.e. sends the EOI to the right PIC(s)). - Continuing on that, at the moment I set dumb default PIC IRQ handlers for IRQ 08h - 0Fh and IRQ 70h - 77h). - By default I disable all the IRQs; there are then set on-demand with EnableHwIRQ. - Rework the POST (aka. BiosInitialize function): * the memory size is now get from the CMOS (as well as the extended memory size via INT 12h, AH=88h), * then we initialize the interrupts, * then platform hardware (ie. the chips) are initialized, * and finally the keyboard and video bioses. - As said before, move memory sizes into the CMOS. - Simplify video bios initialization. svn path=/branches/ntvdm/; revision=61796
2014-01-25 00:21:51 +00:00
PS2Cleanup();
SpeakerCleanup();
CmosCleanup();
// PitCleanup();
// PicCleanup();
// DmaCleanup();
CpuCleanup();
MemCleanup();
}
VOID
WINAPI
VDDSimulate16(VOID)
{
CpuSimulate();
}
VOID
WINAPI
VDDTerminateVDM(VOID)
{
/* Stop the VDM */
EmulatorTerminate();
}
/* EOF */