diff --git a/subsystems/ntvdm/CMakeLists.txt b/subsystems/ntvdm/CMakeLists.txt index 278439733e9..4351ef56005 100644 --- a/subsystems/ntvdm/CMakeLists.txt +++ b/subsystems/ntvdm/CMakeLists.txt @@ -22,7 +22,7 @@ list(APPEND SOURCE bop.c clock.c emulator.c - int32.c + callback.c io.c registers.c vddsup.c diff --git a/subsystems/ntvdm/bios/bios32/bios32.c b/subsystems/ntvdm/bios/bios32/bios32.c index e37536742d6..6379c9b7369 100644 --- a/subsystems/ntvdm/bios/bios32/bios32.c +++ b/subsystems/ntvdm/bios/bios32/bios32.c @@ -11,6 +11,8 @@ #define NDEBUG #include "emulator.h" +#include "callback.h" + #include "bios32.h" #include "io.h" @@ -18,10 +20,9 @@ #include "hardware/pic.h" #include "hardware/timer.h" -#include "int32.h" - /* PRIVATE VARIABLES **********************************************************/ +CALLBACK16 BiosContext; PBIOS_DATA_AREA Bda; /* PRIVATE FUNCTIONS **********************************************************/ @@ -190,7 +191,7 @@ VOID EnableHwIRQ(UCHAR hwirq, EMULATOR_INT32_PROC func) else vector = BIOS_PIC_SLAVE_INT + hwirq - 8; - RegisterInt32(vector, func); + RegisterBiosInt32(vector, func); } @@ -250,7 +251,8 @@ static VOID WINAPI BiosTimerIrq(LPWORD Stack) * because some programs may hook only BIOS_SYS_TIMER_INTERRUPT * for their purpose... */ - EmulatorInterrupt(BIOS_SYS_TIMER_INTERRUPT); + /** EmulatorInterrupt(BIOS_SYS_TIMER_INTERRUPT); **/ + Int32Call(&BiosContext, BIOS_SYS_TIMER_INTERRUPT); PicIRQComplete(Stack); } @@ -303,6 +305,48 @@ static VOID BiosHwSetup(VOID) EnableHwIRQ(0, BiosTimerIrq); } +static VOID InitializeBiosInt32(VOID) +{ + USHORT i; + // USHORT Offset = 0; + + /* Initialize the callback context */ + InitializeContext(&BiosContext, BIOS_SEGMENT, 0x0000); + + /* Register the BIOS 32-bit Interrupts */ + for (i = 0x00; i <= 0xFF; i++) + { + // Offset += RegisterInt32(MAKELONG(Offset, BIOS_SEGMENT), i, NULL, NULL); + BiosContext.NextOffset += RegisterInt32(MAKELONG(BiosContext.NextOffset, + BiosContext.Segment), + i, NULL, NULL); + } + + /* Initialize the exception vector interrupts to a default Exception handler */ + for (i = 0; i < 8; i++) + RegisterBiosInt32(i, BiosException); + + /* Initialize HW vector interrupts to a default HW handler */ + for (i = BIOS_PIC_MASTER_INT; i < BIOS_PIC_MASTER_INT + 8; i++) + RegisterBiosInt32(i, BiosHandleMasterPicIRQ); + for (i = BIOS_PIC_SLAVE_INT ; i < BIOS_PIC_SLAVE_INT + 8; i++) + RegisterBiosInt32(i, BiosHandleSlavePicIRQ); + + /* Initialize software vector handlers */ + RegisterBiosInt32(BIOS_EQUIPMENT_INTERRUPT, BiosEquipmentService ); + RegisterBiosInt32(BIOS_MEMORY_SIZE , BiosGetMemorySize ); + RegisterBiosInt32(BIOS_MISC_INTERRUPT , BiosMiscService ); + RegisterBiosInt32(BIOS_TIME_INTERRUPT , BiosTimeService ); + RegisterBiosInt32(BIOS_SYS_TIMER_INTERRUPT, BiosSystemTimerInterrupt); + + /* Some interrupts are in fact addresses to tables */ + ((PULONG)BaseAddress)[0x1E] = (ULONG)NULL; + ((PULONG)BaseAddress)[0x41] = (ULONG)NULL; + ((PULONG)BaseAddress)[0x46] = (ULONG)NULL; + ((PULONG)BaseAddress)[0x48] = (ULONG)NULL; + ((PULONG)BaseAddress)[0x49] = (ULONG)NULL; +} + /* PUBLIC FUNCTIONS ***********************************************************/ /* @@ -312,7 +356,6 @@ BOOLEAN Bios32Initialize(IN HANDLE ConsoleInput, IN HANDLE ConsoleOutput) { UCHAR Low, High; - UCHAR i; /* Initialize the BDA */ Bda = (PBIOS_DATA_AREA)SEG_OFF_TO_PTR(BDA_SEGMENT, 0); @@ -328,34 +371,8 @@ BOOLEAN Bios32Initialize(IN HANDLE ConsoleInput, High = IOReadB(CMOS_DATA_PORT); Bda->MemorySize = MAKEWORD(Low, High); - /* Initialize the 32-bit Interrupt system */ - InitializeInt32(BIOS_SEGMENT); - /* Register the BIOS 32-bit Interrupts */ - - /* Initialize the exception vector interrupts to a default Exception handler */ - for (i = 0; i < 8; i++) - RegisterInt32(i, BiosException); - - /* Initialize HW vector interrupts to a default HW handler */ - for (i = BIOS_PIC_MASTER_INT; i < BIOS_PIC_MASTER_INT + 8; i++) - RegisterInt32(i, BiosHandleMasterPicIRQ); - for (i = BIOS_PIC_SLAVE_INT ; i < BIOS_PIC_SLAVE_INT + 8; i++) - RegisterInt32(i, BiosHandleSlavePicIRQ); - - /* Initialize software vector handlers */ - RegisterInt32(BIOS_EQUIPMENT_INTERRUPT, BiosEquipmentService ); - RegisterInt32(BIOS_MEMORY_SIZE , BiosGetMemorySize ); - RegisterInt32(BIOS_MISC_INTERRUPT , BiosMiscService ); - RegisterInt32(BIOS_TIME_INTERRUPT , BiosTimeService ); - RegisterInt32(BIOS_SYS_TIMER_INTERRUPT, BiosSystemTimerInterrupt); - - /* Some interrupts are in fact addresses to tables */ - ((PDWORD)BaseAddress)[0x1E] = (DWORD)NULL; - ((PDWORD)BaseAddress)[0x41] = (DWORD)NULL; - ((PDWORD)BaseAddress)[0x46] = (DWORD)NULL; - ((PDWORD)BaseAddress)[0x48] = (DWORD)NULL; - ((PDWORD)BaseAddress)[0x49] = (DWORD)NULL; + InitializeBiosInt32(); /* Initialize platform hardware (PIC/PIT chips, ...) */ BiosHwSetup(); diff --git a/subsystems/ntvdm/bios/bios32/bios32.h b/subsystems/ntvdm/bios/bios32/bios32.h index ba1f69bba12..8f153818203 100644 --- a/subsystems/ntvdm/bios/bios32/bios32.h +++ b/subsystems/ntvdm/bios/bios32/bios32.h @@ -15,6 +15,8 @@ #include "kbdbios32.h" #include "vidbios32.h" +/**/ #include "callback.h" /**/ + /* DEFINES ********************************************************************/ #define BIOS_PIC_MASTER_INT 0x08 @@ -115,6 +117,14 @@ C_ASSERT(sizeof(BIOS_DATA_AREA) == 0x133); /* FUNCTIONS ******************************************************************/ +extern CALLBACK16 BiosContext; +#define RegisterBiosInt32(IntNumber, IntHandler) \ +do { \ + BiosContext.NextOffset += RegisterInt32(MAKELONG(BiosContext.NextOffset, \ + BiosContext.Segment), \ + (IntNumber), (IntHandler), NULL); \ +} while(0); + extern PBIOS_DATA_AREA Bda; /**HACK!!**/typedef VOID (WINAPI *EMULATOR_INT32_PROC)(LPWORD Stack);/**HACK!!**/ diff --git a/subsystems/ntvdm/bios/bios32/kbdbios32.c b/subsystems/ntvdm/bios/bios32/kbdbios32.c index 6444004eaff..4f551618750 100644 --- a/subsystems/ntvdm/bios/bios32/kbdbios32.c +++ b/subsystems/ntvdm/bios/bios32/kbdbios32.c @@ -11,14 +11,14 @@ #define NDEBUG #include "emulator.h" +#include "callback.h" + // #include "kbdbios32.h" #include "bios32.h" #include "io.h" #include "hardware/ps2.h" -#include "int32.h" - /* PRIVATE VARIABLES **********************************************************/ static BYTE BiosKeyboardMap[256]; @@ -271,7 +271,7 @@ BOOLEAN KbdBios32Initialize(HANDLE ConsoleInput) /* Register the BIOS 32-bit Interrupts */ /* Initialize software vector handlers */ - RegisterInt32(BIOS_KBD_INTERRUPT, BiosKeyboardService); + RegisterBiosInt32(BIOS_KBD_INTERRUPT, BiosKeyboardService); /* Set up the HW vector interrupts */ EnableHwIRQ(1, BiosKeyboardIrq); diff --git a/subsystems/ntvdm/bios/bios32/vidbios32.c b/subsystems/ntvdm/bios/bios32/vidbios32.c index 4734f10497b..e84814507f1 100644 --- a/subsystems/ntvdm/bios/bios32/vidbios32.c +++ b/subsystems/ntvdm/bios/bios32/vidbios32.c @@ -11,14 +11,14 @@ #define NDEBUG #include "emulator.h" +#include "callback.h" + // #include "vidbios32.h" #include "bios32.h" #include "io.h" #include "hardware/vga.h" -#include "int32.h" - /* MACROS *********************************************************************/ // @@ -1536,11 +1536,11 @@ static VOID WINAPI VidBiosVideoService(LPWORD Stack) BOOLEAN VidBios32Initialize(HANDLE ConsoleOutput) { /* Some interrupts are in fact addresses to tables */ - ((PDWORD)BaseAddress)[0x1D] = (DWORD)NULL; - ((PDWORD)BaseAddress)[0x1F] = (DWORD)NULL; - // ((PDWORD)BaseAddress)[0x42] = (DWORD)NULL; - ((PDWORD)BaseAddress)[0x43] = (DWORD)NULL; - ((PDWORD)BaseAddress)[0x44] = (DWORD)NULL; + ((PULONG)BaseAddress)[0x1D] = (ULONG)NULL; + ((PULONG)BaseAddress)[0x1F] = (ULONG)NULL; + // ((PULONG)BaseAddress)[0x42] = (ULONG)NULL; + ((PULONG)BaseAddress)[0x43] = (ULONG)NULL; + ((PULONG)BaseAddress)[0x44] = (ULONG)NULL; /* Set the default video mode */ VidBiosSetVideoMode(BIOS_DEFAULT_VIDEO_MODE); @@ -1562,7 +1562,7 @@ BOOLEAN VidBios32Initialize(HANDLE ConsoleOutput) } /* Register the BIOS 32-bit Interrupts */ - RegisterInt32(BIOS_VIDEO_INTERRUPT, VidBiosVideoService); + RegisterBiosInt32(BIOS_VIDEO_INTERRUPT, VidBiosVideoService); return TRUE; } diff --git a/subsystems/ntvdm/dos/dem.c b/subsystems/ntvdm/dos/dem.c index 64ea8544ba4..b7f01790735 100644 --- a/subsystems/ntvdm/dos/dem.c +++ b/subsystems/ntvdm/dos/dem.c @@ -14,17 +14,130 @@ #define NDEBUG +#include "emulator.h" + #include "dem.h" +#include "bop.h" /* Extra PSDK/NDK Headers */ #include +/* 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); + + DPRINT1("Unknown DOS System BOP Function: 0x%02X\n", FuncNum); +} + +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) { + /* Register the DOS BOPs */ + RegisterBop(BOP_DOS, DosSystemBop ); + RegisterBop(BOP_CMD, DosCmdInterpreterBop); + if (DosKernelFileNames) { DisplayMessage(L"NTVDM: Loading DOS kernel from external files is currently unsupported"); @@ -35,7 +148,7 @@ BOOLEAN DosInitialize(IN LPCSTR DosKernelFileNames) BOOLEAN Result; Result = DosBIOSInitialize(); - Result &= DosKRNLInitialize(); + // Result &= DosKRNLInitialize(); return Result; } diff --git a/subsystems/ntvdm/dos/dos32krnl/bios.c b/subsystems/ntvdm/dos/dos32krnl/bios.c index e219e829a0b..d3cc39257e5 100644 --- a/subsystems/ntvdm/dos/dos32krnl/bios.c +++ b/subsystems/ntvdm/dos/dos32krnl/bios.c @@ -11,21 +11,17 @@ #define NDEBUG #include "emulator.h" +#include "callback.h" + #include "dos.h" #include "bios/bios.h" -#include "bop.h" -// #include "int32.h" /* PRIVATE VARIABLES **********************************************************/ // static BYTE CurrentDrive; // static CHAR CurrentDirectories[NUM_DRIVES][DOS_DIR_LENGTH]; -/* 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 **********************************************************/ #if 0 @@ -119,94 +115,6 @@ VOID DosPrintCharacter(CHAR Character) DosWriteFile(DOS_OUTPUT_HANDLE, &Character, sizeof(CHAR), &BytesWritten); } -VOID WINAPI DosSystemBop(LPWORD Stack) -{ - /* Get the Function Number and skip it */ - BYTE FuncNum = *(PBYTE)SEG_OFF_TO_PTR(getCS(), getIP()); - setIP(getIP() + 1); - - DPRINT1("Unknown DOS System BOP Function: 0x%02X\n", FuncNum); -} - -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()); - CHAR CommandLine[CMDLINE_LENGTH] = ""; - STARTUPINFOA StartupInfo; - PROCESS_INFORMATION ProcessInformation; - DPRINT1("CMD Run Command '%s'\n", Command); - - Command[strlen(Command)-1] = 0; - - 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"); - - /* 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; - } - } -} - BOOLEAN DosBIOSInitialize(VOID) { PDOS_MCB Mcb = SEGMENT_TO_MCB(FIRST_MCB_SEGMENT); @@ -345,16 +253,11 @@ BOOLEAN DosBIOSInitialize(VOID) #endif - /* Register the DOS BOPs */ - RegisterBop(BOP_DOS, DosSystemBop ); - RegisterBop(BOP_CMD, DosCmdInterpreterBop); - /* Register the DOS 32-bit Interrupts */ - // RegisterInt32(0x20, DosInt20h); + // RegisterDosInt32(0x20, DosInt20h); - /* TODO: Initialize the DOS kernel */ - - return TRUE; + /* Initialize the DOS kernel */ + return DosKRNLInitialize(); } /* EOF */ diff --git a/subsystems/ntvdm/dos/dos32krnl/dos.c b/subsystems/ntvdm/dos/dos32krnl/dos.c index 4789c41aa91..c86594db4e3 100644 --- a/subsystems/ntvdm/dos/dos32krnl/dos.c +++ b/subsystems/ntvdm/dos/dos32krnl/dos.c @@ -11,15 +11,18 @@ #define NDEBUG #include "emulator.h" +#include "callback.h" + #include "dos.h" #include "dos/dem.h" #include "bios/bios.h" -#include "int32.h" #include "registers.h" /* PRIVATE VARIABLES **********************************************************/ +CALLBACK16 DosContext; + static WORD CurrentPsp = SYSTEM_PSP; static WORD DosLastError = 0; static DWORD DiskTransferArea; @@ -1669,11 +1672,11 @@ VOID WINAPI DosInt21h(LPWORD Stack) /* Set Interrupt Vector */ case 0x25: { - DWORD FarPointer = MAKELONG(getDX(), getDS()); + ULONG FarPointer = MAKELONG(getDX(), getDS()); DPRINT1("Setting interrupt 0x%x ...\n", getAL()); /* Write the new far pointer to the IDT */ - ((PDWORD)BaseAddress)[getAL()] = FarPointer; + ((PULONG)BaseAddress)[getAL()] = FarPointer; break; } @@ -2480,6 +2483,7 @@ VOID WINAPI DosFastConOut(LPWORD Stack) * for more information. */ +#if 0 if (Stack[STACK_COUNTER] == 0) { Stack[STACK_COUNTER]++; @@ -2504,6 +2508,20 @@ VOID WINAPI DosFastConOut(LPWORD Stack) setAX(Stack[STACK_VAR_A]); setBX(Stack[STACK_VAR_B]); } +#else + /* Save AX and BX */ + USHORT AX = getAX(); + USHORT BX = getBX(); + + setBL(DOS_CHAR_ATTRIBUTE); + setBH(Bda->VideoPage); + setAH(0x0E); + Int32Call(&DosContext, 0x10); + + /* Restore AX and BX */ + setAX(AX); + setBX(BX); +#endif } VOID WINAPI DosInt2Fh(LPWORD Stack) @@ -2585,15 +2603,17 @@ BOOLEAN DosKRNLInitialize(VOID) #endif + /* Initialize the callback context */ + InitializeContext(&DosContext, 0x0070, 0x0000); /* Register the DOS 32-bit Interrupts */ - RegisterInt32(0x20, DosInt20h ); - RegisterInt32(0x21, DosInt21h ); -// RegisterInt32(0x22, DosInt22h ); // Termination - RegisterInt32(0x23, DosBreakInterrupt); // Ctrl-C / Ctrl-Break -// RegisterInt32(0x24, DosInt24h ); // Critical Error - RegisterInt32(0x29, DosFastConOut ); // DOS 2+ Fast Console Output - RegisterInt32(0x2F, DosInt2Fh ); + RegisterDosInt32(0x20, DosInt20h ); + RegisterDosInt32(0x21, DosInt21h ); +// RegisterDosInt32(0x22, DosInt22h ); // Termination + RegisterDosInt32(0x23, DosBreakInterrupt); // Ctrl-C / Ctrl-Break +// RegisterDosInt32(0x24, DosInt24h ); // Critical Error + RegisterDosInt32(0x29, DosFastConOut ); // DOS 2+ Fast Console Output + RegisterDosInt32(0x2F, DosInt2Fh ); return TRUE; } diff --git a/subsystems/ntvdm/dos/dos32krnl/dos.h b/subsystems/ntvdm/dos/dos32krnl/dos.h index d122d2dd3ec..d82bb1a74c6 100644 --- a/subsystems/ntvdm/dos/dos32krnl/dos.h +++ b/subsystems/ntvdm/dos/dos32krnl/dos.h @@ -13,6 +13,8 @@ #include "ntvdm.h" +/**/ #include "callback.h" /**/ + /* DEFINES ********************************************************************/ // @@ -138,6 +140,14 @@ typedef struct _DOS_FIND_FILE_BLOCK /* FUNCTIONS ******************************************************************/ +extern CALLBACK16 DosContext; +#define RegisterDosInt32(IntNumber, IntHandler) \ +do { \ + DosContext.NextOffset += RegisterInt32(MAKELONG(DosContext.NextOffset, \ + DosContext.Segment), \ + (IntNumber), (IntHandler), NULL); \ +} while(0); + /* * DOS BIOS Functions * See bios.c diff --git a/subsystems/ntvdm/emulator.c b/subsystems/ntvdm/emulator.c index 40f12ed810a..f29671939df 100644 --- a/subsystems/ntvdm/emulator.c +++ b/subsystems/ntvdm/emulator.c @@ -388,7 +388,8 @@ BOOLEAN EmulatorInitialize(HANDLE ConsoleInput, HANDLE ConsoleOutput) // if (!VgaInitialize(ConsoleOutput)) return FALSE; VgaInitialize(ConsoleOutput); - /* Register the emulator BOPs */ + /* Initialize the software callback system and register the emulator BOPs */ + InitializeCallbacks(); RegisterBop(BOP_DEBUGGER , EmulatorDebugBreakBop); RegisterBop(BOP_UNSIMULATE, EmulatorUnsimulateBop);