You can not select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
513 lines
10 KiB
513 lines
10 KiB
/*++
|
|
|
|
Copyright (c) 1992 Microsoft Corporation
|
|
|
|
Module Name:
|
|
|
|
int.c
|
|
|
|
Abstract:
|
|
|
|
This file contains interrupt support routines for the monitor
|
|
|
|
Author:
|
|
|
|
Dave Hastings (daveh) 18-Apr-1992
|
|
|
|
Notes:
|
|
|
|
The code in this file split out from monitor.c (18-Apr-1992)
|
|
|
|
Revision History:
|
|
|
|
--*/
|
|
|
|
#include <monitorp.h>
|
|
|
|
#if defined(NEC_98)
|
|
VOID WaitVsync();
|
|
#endif // NEC_98
|
|
|
|
BOOL
|
|
DpmiHwIntHandler(
|
|
ULONG IntNumber
|
|
);
|
|
|
|
VOID
|
|
IRQ13_Eoi(
|
|
int IrqLine,
|
|
int CallCount
|
|
);
|
|
|
|
#if defined(NEC_98)
|
|
VOID
|
|
IRQ13_Eoi_real(
|
|
int IrqLine,
|
|
int CallCount
|
|
);
|
|
#endif // NEC_98
|
|
|
|
BOOLEAN IRQ13BeingHandled; // true until IRQ13 eoi'ed
|
|
|
|
|
|
VOID
|
|
InterruptInit(
|
|
VOID
|
|
)
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
This routine initializes the interrupt code for the monitor.
|
|
|
|
Arguments:
|
|
|
|
|
|
Return Value:
|
|
|
|
None.
|
|
|
|
--*/
|
|
{
|
|
BOOL Bool;
|
|
|
|
|
|
|
|
#if defined(NEC_98)
|
|
Bool = RegisterEOIHook( 8, IRQ13_Eoi);
|
|
Bool = RegisterEOIHook( 14, IRQ13_Eoi_real);
|
|
#else // !NEC_98
|
|
Bool = RegisterEOIHook( 13, IRQ13_Eoi);
|
|
#endif // !NEC_98
|
|
if (!Bool) {
|
|
#if DBG
|
|
DbgPrint("NtVdm : Could not register IRQ 13 Eoi handler\n");
|
|
DbgBreakPoint();
|
|
#endif
|
|
TerminateVDM();
|
|
}
|
|
}
|
|
|
|
VOID
|
|
InterruptTerminate(
|
|
VOID
|
|
)
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
This routine frees the resoures allocated by InterruptInit
|
|
|
|
Arguments:
|
|
|
|
|
|
Return Value:
|
|
|
|
None.
|
|
|
|
--*/
|
|
{
|
|
}
|
|
|
|
|
|
VOID
|
|
cpu_interrupt(
|
|
IN int Type,
|
|
IN int Number
|
|
)
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
This routine causes an interrupt of the specified type to be raised
|
|
at the appropriate time.
|
|
|
|
Arguments:
|
|
|
|
Type -- indicates the type of the interrupt. One of HARDWARE, TIMER, YODA,
|
|
or RESET
|
|
|
|
YODA and RESET are ignored
|
|
|
|
Return Value:
|
|
|
|
None.
|
|
|
|
Notes:
|
|
|
|
--*/
|
|
{
|
|
NTSTATUS Status;
|
|
HANDLE MonitorThread;
|
|
|
|
host_ica_lock();
|
|
|
|
if (CurrentMonitorTeb == NtCurrentTeb() && !getIF() && (getMSW() & MSW_PE)) {
|
|
VDM_PM_CLI_DATA cliData;
|
|
|
|
cliData.Control = PM_CLI_CONTROL_CHECK;
|
|
NtVdmControl(VdmPMCliControl, &cliData);
|
|
}
|
|
|
|
if (Type == CPU_TIMER_TICK) {
|
|
|
|
//
|
|
// Set the VDM State for timer tick int pending
|
|
//
|
|
_asm {
|
|
mov eax, FIXED_NTVDMSTATE_LINEAR
|
|
lock or dword ptr [eax], VDM_INT_TIMER
|
|
}
|
|
} else if (Type == CPU_HW_INT) {
|
|
|
|
|
|
if (*pNtVDMState & VDM_INT_HARDWARE) {
|
|
goto EarlyExit;
|
|
}
|
|
|
|
//
|
|
// Set the VDM State for Hardware Int pending
|
|
//
|
|
_asm {
|
|
mov eax, FIXED_NTVDMSTATE_LINEAR
|
|
lock or dword ptr [eax], VDM_INT_HARDWARE
|
|
}
|
|
} else {
|
|
#if DBG
|
|
DbgPrint("Monitor: Invalid Interrupt Type=%ld\n",Type);
|
|
#endif
|
|
goto EarlyExit;
|
|
}
|
|
|
|
if (CurrentMonitorTeb != NtCurrentTeb()) {
|
|
|
|
/*
|
|
* Look up the ThreadHandle and Queue and InterruptApc
|
|
* If no ThreadHandle found do nothing
|
|
*
|
|
* The CurrentMonitorTeb may not be in the ThreadHandle\Teb list
|
|
* because upon task termination the the CurrentMonitorTeb variable
|
|
* cannot be updated until a new task is activated by the
|
|
* non-preemptive scheduler.
|
|
*/
|
|
MonitorThread = ThreadLookUp(CurrentMonitorTeb);
|
|
if (MonitorThread) {
|
|
Status = NtVdmControl(VdmQueueInterrupt, (PVOID)MonitorThread);
|
|
// nothing much we can do if this fails
|
|
#if DBG
|
|
if (!NT_SUCCESS(Status) && Status != STATUS_UNSUCCESSFUL) {
|
|
DbgPrint("NtVdmControl.VdmQueueInterrupt Status=%lx\n",Status);
|
|
}
|
|
#endif
|
|
}
|
|
|
|
}
|
|
|
|
EarlyExit:
|
|
|
|
host_ica_unlock();
|
|
}
|
|
|
|
|
|
|
|
|
|
VOID
|
|
DispatchInterrupts(
|
|
)
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
This routine dispatches interrupts to their appropriate handler routine
|
|
in priority order. The order is YODA, RESET, TIMER, HARDWARE. however
|
|
the YODA and RESET interrupts do nothing. Hardware interrupts are not
|
|
simulated unless the virtual interrupt enable flag is set. Flags
|
|
indicating which interrupts are pending appear in the pNtVDMState.
|
|
|
|
|
|
Arguments:
|
|
|
|
None.
|
|
|
|
Return Value:
|
|
|
|
None.
|
|
|
|
Notes:
|
|
|
|
--*/
|
|
{
|
|
|
|
host_ica_lock();
|
|
|
|
// If any delayed interrupts have expired
|
|
// call the ica to restart interrupts
|
|
if (UndelayIrqLine) {
|
|
ica_RestartInterrupts(UndelayIrqLine);
|
|
}
|
|
|
|
|
|
if (*pNtVDMState & VDM_INT_TIMER) {
|
|
*pNtVDMState &= ~VDM_INT_TIMER;
|
|
host_ica_unlock(); // maybe don't need to unlock ? Jonle
|
|
host_timer_event();
|
|
host_ica_lock();
|
|
}
|
|
|
|
if ( getIF() && getMSW() & MSW_PE && *pNtVDMState & VDM_INT_HARDWARE) {
|
|
//
|
|
// Mark the vdm state as hw int dispatched. Must use the lock as
|
|
// kernel mode DelayedIntApcRoutine changes the bit as well
|
|
//
|
|
_asm {
|
|
mov eax,FIXED_NTVDMSTATE_LINEAR
|
|
lock and dword ptr [eax], NOT VDM_INT_HARDWARE
|
|
}
|
|
DispatchHwInterrupt();
|
|
}
|
|
|
|
host_ica_unlock();
|
|
}
|
|
|
|
|
|
|
|
|
|
VOID
|
|
DispatchHwInterrupt(
|
|
)
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
This routine dispatches hardware interrupts to the vdm in Protect Mode.
|
|
It calls the ICA to get the vector number and sets up the VDM stack
|
|
appropriately. Real Mode interrupt dispatching has been moved to the
|
|
kernel.
|
|
|
|
Arguments:
|
|
|
|
None.
|
|
|
|
Return Value:
|
|
|
|
None.
|
|
|
|
--*/
|
|
{
|
|
int InterruptNumber;
|
|
ULONG IretHookAddress = 0L;
|
|
PVDM_TIB VdmTib;
|
|
|
|
InterruptNumber = ica_intack(&IretHookAddress);
|
|
if (InterruptNumber == -1) { // skip spurious ints
|
|
return;
|
|
}
|
|
|
|
DpmiHwIntHandler(InterruptNumber);
|
|
|
|
VdmTib = (PVDM_TIB)(NtCurrentTeb()->Vdm);
|
|
if (IretHookAddress) {
|
|
BOOL Frame32 = (BOOL) VdmTib->DpmiInfo.Flags;
|
|
BOOL Stack32;
|
|
USHORT SegSs, VdmCs;
|
|
ULONG VdmSp, VdmEip;
|
|
PUCHAR VdmStackPointer;
|
|
ULONG StackOffset;
|
|
|
|
SegSs = getSS();
|
|
VdmStackPointer = Sim32GetVDMPointer(((ULONG)SegSs) << 16, 1, TRUE);
|
|
|
|
//
|
|
// Figure out how many bits of sp to use
|
|
//
|
|
|
|
if (Ldt[(SegSs & ~0x7)/sizeof(LDT_ENTRY)].HighWord.Bits.Default_Big) {
|
|
VdmSp = getESP();
|
|
StackOffset = 12;
|
|
} else {
|
|
VdmSp = getSP();
|
|
StackOffset = 6;
|
|
}
|
|
|
|
(PCHAR)VdmStackPointer += VdmSp;
|
|
|
|
//
|
|
// BUGBUG need to add stack limit checking 15-Nov-1993 Jonle
|
|
//
|
|
setESP(VdmSp - StackOffset);
|
|
|
|
//
|
|
// Push info for Iret hook handler
|
|
//
|
|
VdmCs = (USHORT) ((IretHookAddress & 0xFFFF0000) >> 16);
|
|
VdmEip = (IretHookAddress & 0xFFFF);
|
|
|
|
if (Frame32) {
|
|
*(PULONG)(VdmStackPointer - 4) = VdmTib->VdmContext.EFlags;
|
|
*(PULONG)(VdmStackPointer - 8) = (ULONG) VdmCs;
|
|
*(PULONG)(VdmStackPointer - 12) = VdmEip;
|
|
} else {
|
|
*(PUSHORT)(VdmStackPointer - 2) = (USHORT) VdmTib->VdmContext.EFlags;
|
|
*(PUSHORT)(VdmStackPointer - 4) = VdmCs;
|
|
*(PUSHORT)(VdmStackPointer - 6) = (USHORT) VdmEip;
|
|
}
|
|
}
|
|
|
|
#if defined(NEC_98)
|
|
if(InterruptNumber == 0xA) {
|
|
WaitVsync();
|
|
}
|
|
#endif // NEC_98
|
|
}
|
|
|
|
|
|
VOID
|
|
IRQ13_Eoi(
|
|
int IrqLine,
|
|
int CallCount
|
|
)
|
|
{
|
|
UNREFERENCED_PARAMETER(IrqLine);
|
|
UNREFERENCED_PARAMETER(CallCount);
|
|
|
|
//
|
|
// if CallCount is less than Zero, then the interrupt request
|
|
// is being canceled.
|
|
//
|
|
#if defined(NEC_98)
|
|
if( getMSW() & MSW_PE ){
|
|
#endif // NEC_98
|
|
if (CallCount < 0) {
|
|
return;
|
|
}
|
|
|
|
IRQ13BeingHandled = FALSE;
|
|
|
|
#if defined(NEC_98)
|
|
}
|
|
#endif // NEC_98
|
|
}
|
|
|
|
#if defined(NEC_98)
|
|
VOID
|
|
IRQ13_Eoi_real(
|
|
int IrqLine,
|
|
int CallCount
|
|
)
|
|
{
|
|
UNREFERENCED_PARAMETER(IrqLine);
|
|
UNREFERENCED_PARAMETER(CallCount);
|
|
|
|
if( !(getMSW() & MSW_PE) ){
|
|
if (CallCount < 0) {
|
|
return;
|
|
}
|
|
IRQ13BeingHandled = FALSE;
|
|
}
|
|
}
|
|
#endif // NEC_98
|
|
|
|
|
|
|
|
|
|
|
|
VOID
|
|
MonitorEndIretHook(
|
|
VOID
|
|
)
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
|
|
Arguments:
|
|
|
|
None.
|
|
|
|
Return Value:
|
|
|
|
None.
|
|
|
|
--*/
|
|
{
|
|
|
|
PVOID VdmStackPointer;
|
|
PVDM_TIB VdmTib;
|
|
|
|
VdmTib = (PVDM_TIB)(NtCurrentTeb()->Vdm);
|
|
if (VdmTib->IntelMSW & MSW_PE) {
|
|
BOOL Frame32 = (BOOL) VdmTib->DpmiInfo.Flags;
|
|
ULONG FrameSize;
|
|
|
|
if (Frame32) {
|
|
FrameSize = 12;
|
|
} else {
|
|
FrameSize = 6;
|
|
}
|
|
|
|
VdmStackPointer = Sim32GetVDMPointer(((ULONG)getSS() << 16),2,TRUE);
|
|
|
|
if (Ldt[(getSS() & ~0x7)/sizeof(LDT_ENTRY)].HighWord.Bits.Default_Big) {
|
|
(PCHAR)VdmStackPointer += getESP();
|
|
setESP(getESP() + FrameSize);
|
|
} else {
|
|
(PCHAR)VdmStackPointer += getSP();
|
|
setSP((USHORT) (getSP() + FrameSize));
|
|
}
|
|
|
|
if (Frame32) {
|
|
|
|
VdmTib->VdmContext.EFlags = *(PULONG)((PCHAR)VdmStackPointer + 8);
|
|
setCS(*(PUSHORT)((PCHAR)VdmStackPointer + 4));
|
|
VdmTib->VdmContext.Eip = *((PULONG)VdmStackPointer);
|
|
|
|
} else {
|
|
|
|
VdmTib->VdmContext.EFlags = (VdmTib->VdmContext.EFlags & 0xFFFF0000) |
|
|
((ULONG) *(PUSHORT)((PCHAR)VdmStackPointer + 4));
|
|
setCS(*(PUSHORT)((PCHAR)VdmStackPointer + 2));
|
|
VdmTib->VdmContext.Eip = (VdmTib->VdmContext.Eip & 0xFFFF0000) |
|
|
((ULONG) *(PUSHORT)((PCHAR)VdmStackPointer));
|
|
|
|
}
|
|
|
|
} else {
|
|
|
|
VdmStackPointer = Sim32GetVDMPointer(((ULONG)getSS() << 16) | getSP(),2,FALSE);
|
|
|
|
setSP((USHORT) (getSP() + 6));
|
|
|
|
(USHORT)(VdmTib->VdmContext.EFlags) = *((PUSHORT)((PCHAR)VdmStackPointer + 4));
|
|
setCS(*((PUSHORT)((PCHAR)VdmStackPointer + 2)));
|
|
setIP(*((PUSHORT)VdmStackPointer));
|
|
|
|
}
|
|
|
|
|
|
}
|
|
|
|
VOID
|
|
host_clear_hw_int()
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
This routine "forgets" a previously requested hardware interrupt.
|
|
|
|
Arguments:
|
|
|
|
None.
|
|
|
|
Return Value:
|
|
|
|
None.
|
|
|
|
--*/
|
|
{
|
|
/*
|
|
* We do nothing here to save a kernel call, because the
|
|
* interrupt if it hasn't been intacked yet or dispatched,
|
|
* will produce a harmless spurious int, which is dropped
|
|
* in the i386 interrupt dispatching code anyhow.
|
|
*/
|
|
}
|