reactos/subsystems/mvdm/ntvdm/int32.c

201 lines
5.6 KiB
C
Raw Normal View History

/*
* COPYRIGHT: GPL - See COPYING in the top level directory
* PROJECT: ReactOS Virtual DOS Machine
* FILE: subsystems/mvdm/ntvdm/int32.c
* PURPOSE: 32-bit Interrupt Handlers
* PROGRAMMERS: Aleksandar Andrejevic <theflash AT sdf DOT lonestar DOT org>
* Hermes Belusca-Maito (hermes.belusca@sfr.fr)
*/
/* INCLUDES *******************************************************************/
#include "ntvdm.h"
#define NDEBUG
#include <debug.h>
#include "emulator.h"
#include "int32.h"
#include "cpu/bop.h"
#include <isvbop.h>
/* PRIVATE VARIABLES **********************************************************/
/*
* This is the list of registered 32-bit Interrupt handlers.
*/
static EMULATOR_INT32_PROC Int32Proc[EMULATOR_MAX_INT32_NUM] = { NULL };
/* BOP Identifiers */
#define BOP_CONTROL 0xFF // Control BOP Handler
#define BOP_CONTROL_DEFFUNC 0x00 // Default Control BOP Function
#define BOP_CONTROL_INT32 0xFF // 32-bit Interrupt dispatcher
#define INT16_TRAMPOLINE_SIZE sizeof(ULONGLONG) // == TRAMPOLINE_SIZE
/* 16-bit generic interrupt code for calling a 32-bit interrupt handler */
static BYTE Int16To32[] =
{
0xFA, // cli
/* Push the value of the interrupt to be called */
0x6A, 0xFF, // push i (patchable to 0x6A, 0xIntNum)
0xF8, // clc
/* The BOP Sequence */
// BOP_SEQ:
BOP(BOP_CONTROL), // Control BOP
BOP_CONTROL_INT32, // 32-bit Interrupt dispatcher
0x73, 0x04, // jnc EXIT (offset +4)
0xFB, // sti
0xF4, // hlt
0xEB, 0xF6, // jmp BOP_SEQ (offset -10)
// EXIT:
0x44, 0x44, // inc sp, inc sp
0xCF, // iret
};
C_ASSERT(sizeof(Int16To32) == Int16To32StubSize);
/* PUBLIC FUNCTIONS ***********************************************************/
static VOID WINAPI Int32Dispatch(LPWORD Stack)
{
/* Get the interrupt number */
[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
BYTE IntNum = LOBYTE(Stack[STACK_INT_NUM]);
/* Call the 32-bit Interrupt handler */
if (Int32Proc[IntNum] != NULL)
Int32Proc[IntNum](Stack);
else
DPRINT1("Unhandled 32-bit interrupt: 0x%02X, AX = 0x%04X\n", IntNum, getAX());
}
static VOID WINAPI ControlBop(LPWORD Stack)
{
/* Get the Function Number and skip it */
BYTE FuncNum = *(PBYTE)SEG_OFF_TO_PTR(getCS(), getIP());
setIP(getIP() + 1);
switch (FuncNum)
{
case BOP_CONTROL_INT32:
Int32Dispatch(Stack);
break;
default:
// DPRINT1("Unassigned Control BOP Function: 0x%02X\n", FuncNum);
DisplayMessage(L"Unassigned Control BOP Function: 0x%02X", FuncNum);
break;
}
}
ULONG
RegisterInt16(IN ULONG FarPtr,
IN BYTE IntNumber,
IN LPBYTE CallbackCode,
IN SIZE_T CallbackSize,
OUT PSIZE_T CodeSize OPTIONAL)
{
/* Get a pointer to the IVT and set the corresponding entry (far pointer) */
LPDWORD IntVecTable = (LPDWORD)SEG_OFF_TO_PTR(0x0000, 0x0000);
IntVecTable[IntNumber] = FarPtr;
/* Register the 16-bit callback */
return RegisterCallback16(FarPtr,
CallbackCode,
CallbackSize,
CodeSize);
}
ULONG
RegisterInt32(IN ULONG FarPtr,
IN BYTE IntNumber,
IN EMULATOR_INT32_PROC IntHandler,
OUT PSIZE_T CodeSize OPTIONAL)
{
/* Array for holding our copy of the 16-bit interrupt callback */
BYTE IntCallback[sizeof(Int16To32)/sizeof(BYTE)];
/* Check whether the 32-bit interrupt was already registered */
#if 0
if (Int32Proc[IntNumber] != NULL)
{
DPRINT1("RegisterInt32: Interrupt 0x%02X already registered!\n", IntNumber);
return 0;
}
#endif
/* Register the 32-bit interrupt handler */
Int32Proc[IntNumber] = IntHandler;
/* Copy the generic 16-bit interrupt callback and patch it */
RtlCopyMemory(IntCallback, Int16To32, sizeof(Int16To32));
IntCallback[2] = IntNumber;
/* Register the 16-bit interrupt callback */
return RegisterInt16(FarPtr,
IntNumber,
IntCallback,
sizeof(IntCallback),
CodeSize);
}
VOID
Int32Call(IN PCALLBACK16 Context,
IN BYTE IntNumber)
{
/*
* TODO: This function has almost the same code as RunCallback16.
* Something that may be nice is to have a common interface to
* build the trampoline...
*/
PUCHAR TrampolineBase = (PUCHAR)FAR_POINTER(Context->TrampolineFarPtr);
PUCHAR Trampoline = TrampolineBase;
UCHAR OldTrampoline[INT16_TRAMPOLINE_SIZE];
DPRINT("Int32Call(0x%02X)\n", IntNumber);
ASSERT(Context->TrampolineSize == INT16_TRAMPOLINE_SIZE);
/* Save the old trampoline */
((PULONGLONG)&OldTrampoline)[0] = ((PULONGLONG)TrampolineBase)[0];
/* Build the generic entry-point for 16-bit calls */
if (IntNumber == 0x03)
{
/* We are redefining for INT 03h */
*Trampoline++ = 0xCC; // Call INT 03h
/** *Trampoline++ = 0x90; // nop **/
}
else
{
/* Normal interrupt */
*Trampoline++ = 0xCD; // Call INT XXh
*Trampoline++ = IntNumber;
}
UnSimulate16(Trampoline);
/* Perform the call */
Call16(HIWORD(Context->TrampolineFarPtr),
LOWORD(Context->TrampolineFarPtr));
/* Restore the old trampoline */
((PULONGLONG)TrampolineBase)[0] = ((PULONGLONG)&OldTrampoline)[0];
}
VOID InitializeInt32(VOID)
{
/* Register the Control BOP */
RegisterBop(BOP_CONTROL, ControlBop);
}
/* EOF */