514 lines
10 KiB
C
514 lines
10 KiB
C
/*++
|
||
|
||
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.
|
||
*/
|
||
}
|