|
|
/*++
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. */ }
|