summaryrefslogtreecommitdiffstats
path: root/private/mvdm/softpc.new/host/src/nt_eoi.c
diff options
context:
space:
mode:
Diffstat (limited to 'private/mvdm/softpc.new/host/src/nt_eoi.c')
-rw-r--r--private/mvdm/softpc.new/host/src/nt_eoi.c545
1 files changed, 545 insertions, 0 deletions
diff --git a/private/mvdm/softpc.new/host/src/nt_eoi.c b/private/mvdm/softpc.new/host/src/nt_eoi.c
new file mode 100644
index 000000000..05653c2d5
--- /dev/null
+++ b/private/mvdm/softpc.new/host/src/nt_eoi.c
@@ -0,0 +1,545 @@
+/*
+ * SoftPC Revision 3.0
+ *
+ * Title : Host EOI hook controller
+ *
+ * Description : This module handles host specific ica code
+ * - EOI hook
+ * - ICA lock
+ *
+ * Author : D.A.Bartlett
+ *
+ * Notes : 30-Oct-1993 Jonle , Rewrote it
+ */
+
+
+/*:::::::::::::::::::::::::::::::::::::::::::::::::::::::::: Include files */
+
+
+#include <nt.h>
+#include <ntrtl.h>
+#include <nturtl.h>
+#include <ntexapi.h>
+#include <windows.h>
+#include <stdio.h>
+#include <vdm.h>
+#include "insignia.h"
+#include "host_def.h"
+#include "xt.h"
+#include CpuH
+#include "sas.h"
+#include "quick_ev.h"
+#include "ica.h"
+#include "host_rrr.h"
+#include "error.h"
+#include "nt_uis.h"
+#include "nt_reset.h"
+#include "nt_eoi.h"
+
+// from monitor.lib
+HANDLE ThreadLookUp(PVOID);
+extern PVOID CurrentMonitorTeb;
+
+// from nt_timer.c
+extern ULONG GetPerfCounter(VOID);
+
+
+RTL_CRITICAL_SECTION IcaLock; // ICA critical section lock
+ULONG UndelayIrqLine=0;
+ULONG DelayIrqLine=0xffffffff; // all ints are blocked until, spckbd loaded
+
+#ifdef MONITOR
+ULONG iretHookActive=0;
+ULONG iretHookMask =0;
+ULONG AddrIretBopTable=0; // seg:offset
+#endif
+
+HANDLE hWowIdleEvent = INVALID_HANDLE_VALUE;
+
+/*
+ * EOI defines, types, global data
+ *
+ */
+static EOIHOOKPROC EoiHooks[16]={NULL}; // must be init to NULL
+
+
+#ifndef MONITOR
+void DelayIrqQuickEvent(long param);
+q_ev_handle DelayHandle[16];
+#define pNtVDMState ((PULONG)(Start_of_M_area + FIXED_NTVDMSTATE_LINEAR))
+
+LARGE_INTEGER BlockTime = {0,0};
+extern LARGE_INTEGER CurrHeartBeat;
+void host_TimeStamp(PLARGE_INTEGER pliTime);
+#endif
+
+
+/*
+ * Called by wow32 to fetch the hWowIdleEvent, which wowexec waits on
+ * in the wow nonpreemptive scheduler.
+ */
+HANDLE RegisterWOWIdle(VOID)
+{
+ return hWowIdleEvent;
+}
+
+/*
+ * Called by WOW32 to inform the WOW idle code that the current WOW
+ * task may be scheduled\descheduled.
+ */
+
+void
+BlockWOWIdle(
+ BOOL Blocking
+ )
+{
+ host_ica_lock();
+
+ if (Blocking) {
+ *pNtVDMState |= VDM_WOWBLOCKED;
+
+#ifndef MONITOR
+ BlockTime = CurrHeartBeat;
+#endif
+
+ }
+ else {
+ *pNtVDMState &= ~VDM_WOWBLOCKED;
+
+
+
+#ifndef MONITOR
+ if (BlockTime.QuadPart &&
+ (CurrHeartBeat.QuadPart >= BlockTime.QuadPart + SYSTEM_TICK_INTV/2))
+ {
+ BlockTime.QuadPart = 0;
+ host_ica_unlock();
+
+ ActivityCheckAfterTimeSlice();
+ return;
+ }
+#endif
+ }
+
+ host_ica_unlock();
+}
+
+
+
+/*
+ * (WOWIdle)...check if an app requires hw interrupts servicing but all WOW
+ * threads are blocked. If so then the call will cause wowexec to awaken
+ * to handle them. Called from ica interrupt routines. NB. Default action
+ * of routine is to check state and return as fast as possible.
+ */
+void
+WOWIdle(
+ BOOL Force
+ )
+{
+ if (VDMForWOW && (Force || (*pNtVDMState & VDM_WOWBLOCKED))) {
+ SetEvent(hWowIdleEvent);
+ }
+
+}
+
+
+
+
+/* RegisterEoiHook
+ *
+ * Registers an call back function to be invoked upon eoi of
+ * a hardware interrupt.
+ *
+ * entry: IrqLine - IrqNumber to register
+ * EoiHookProc - function pointer to be called upon eoi
+ *
+ * returns FALSE if the the IrqLine already has an eoi hook registered
+ */
+BOOL RegisterEOIHook(int IrqLine, EOIHOOKPROC EoiHookProc)
+{
+
+ if (!EoiHooks[IrqLine]) {
+ EoiHooks[IrqLine] = EoiHookProc;
+ return(TRUE);
+ }
+
+ return(FALSE);
+}
+
+
+
+/* RemoveEOIHook
+ *
+ * entry: IrqLine - IrqNumber to remove
+ * EoiHookProc - function pointer previously registered
+ */
+BOOL RemoveEOIHook(int IrqLine, EOIHOOKPROC EoiHookProc)
+{
+ if (EoiHooks[IrqLine] == EoiHookProc) {
+ EoiHooks[IrqLine] = NULL;
+ return(TRUE);
+ }
+ return(FALSE);
+}
+
+
+
+/* host_EOI_hook
+ *
+ * base callback function to invoke device specific Eoi Hook routines
+ *
+ * Entry: IrqLine - Line number
+ * CallCount - The ica Call count for this Irq
+ * If the Call count is -1 then a pending
+ * interrupt is being canceled.
+ *
+ */
+VOID host_EOI_hook(int IrqLine, int CallCount)
+{
+ if ((ULONG)IrqLine >= sizeof(EoiHooks)/sizeof(EOIHOOKPROC)) {
+#if DBG
+ DbgPrint("ntvdm.Eoi_hook: Invalid IrqLine=%lx\n", (ULONG)IrqLine);
+#endif
+ return;
+ }
+
+ if (EoiHooks[IrqLine]) {
+ (*EoiHooks[IrqLine])(IrqLine, CallCount);
+ }
+}
+
+
+/* host_DelayHwInterrupt
+ *
+ * base callback function to queue a HW interrupt at a later time
+ *
+ * entry: IrqLineNum - Irq Line Number
+ * CallCount - Number of interrupts, May be Zero
+ * Delay - Delay time in usecs
+ * if Delay is 0xFFFFFFFF then per IrqLine data
+ * structures are freed, use for cleanup when
+ * the IrqLine is no longer needed for DelayedInterrupts
+ *
+ * Notes: The expected granularity is around 1 msec, but varies depending
+ * on the platform.
+ *
+ *
+ */
+BOOL host_DelayHwInterrupt(int IrqLineNum, int CallCount, ULONG Delay)
+{
+ int adapter;
+ ULONG IrqLine;
+
+#ifdef MONITOR
+ NTSTATUS status;
+ VDMDELAYINTSDATA DelayIntsData;
+#else
+ ULONG TicCount;
+#endif
+
+ host_ica_lock();
+
+ //
+ // Anything to do (only one delayed Irql at a time)
+ //
+
+ IrqLine = 1 << IrqLineNum;
+ if (!(DelayIrqLine & IrqLine) || Delay == 0xffffffff) {
+
+ //
+ // force a minimum delay of 1 ms
+ //
+ if (Delay < 1000) {
+ Delay = 1000;
+ }
+
+#ifdef MONITOR
+
+ //
+ // Set Kernel timer for this IrqLine
+ //
+ DelayIntsData.Delay = Delay;
+ DelayIntsData.DelayIrqLine = IrqLineNum;
+ DelayIntsData.hThread = ThreadLookUp(CurrentMonitorTeb);
+ if (DelayIntsData.hThread) {
+ status = NtVdmControl(VdmDelayInterrupt, &DelayIntsData);
+ if (!NT_SUCCESS(status)) {
+#if DBG
+ DbgPrint("NtVdmControl.VdmDelayInterrupt status=%lx\n",status);
+#endif
+ host_ica_unlock();
+ return FALSE;
+ }
+
+ }
+
+#else
+
+ //
+ // Cancel delay hw interrupt, delete quick event if any
+ //
+ if (Delay == 0xFFFFFFFF) {
+ if (DelayHandle[IrqLineNum]) {
+ delete_q_event(DelayHandle[IrqLineNum]);
+ DelayIrqLine &= ~IrqLine;
+ DelayHandle[IrqLineNum] = 0;
+ }
+ host_ica_unlock();
+ return TRUE;
+ }
+
+
+ //
+ // Mark The IrqLine as delayed until timer fires and queue a quick
+ // event, (a bit early for overhead in dispatching quick events).
+ //
+ DelayIrqLine |= IrqLine;
+ DelayHandle[IrqLineNum] = add_q_event_i(DelayIrqQuickEvent,
+ Delay - 200,
+ IrqLineNum
+ );
+
+ //
+ // Keep Wow Tasks active
+ //
+ WOWIdle(TRUE);
+
+
+
+#endif
+ }
+
+
+ //
+ // If we have more interrupts to generate, register them
+ //
+ if (CallCount) {
+ adapter = IrqLineNum >> 3;
+ ica_hw_interrupt(adapter,
+ (UCHAR)(IrqLineNum - (adapter << 3)),
+ CallCount
+ );
+ }
+
+
+ host_ica_unlock();
+ return TRUE;
+}
+
+
+
+#ifndef MONITOR
+/*
+ * QuickEvent call back function
+ *
+ */
+void DelayIrqQuickEvent(long param)
+{
+ ULONG IrqLineNum = param;
+
+ host_ica_lock();
+
+ DelayHandle[IrqLineNum] = 0;
+ ica_RestartInterrupts(1 << IrqLineNum);
+
+ host_ica_unlock();
+
+}
+#endif
+
+
+
+// ICA critical section locking code
+// This is needed to control access to the ICA from different threads.
+
+void host_ica_lock(void)
+{
+ RtlEnterCriticalSection(&IcaLock);
+}
+
+void host_ica_unlock(void)
+{
+ RtlLeaveCriticalSection(&IcaLock);
+}
+
+void InitializeIcaLock(void)
+{
+ RtlInitializeCriticalSection(&IcaLock);
+
+
+ if (VDMForWOW) {
+ if(!(hWowIdleEvent = CreateEvent(NULL, FALSE, FALSE, NULL))) {
+ DisplayErrorTerm(EHS_FUNC_FAILED,GetLastError(),__FILE__,__LINE__);
+ TerminateVDM();
+ }
+ }
+}
+
+
+
+#ifdef MONITOR
+//
+// Force creation of the LazyCreate LockSemaphore
+// for the ica lock.
+// It is assumed that:
+// the cpu thread Owns the critsect
+// the HeartBeat Thread will wait on the critsect creating contention
+//
+// This is done by polling for a lock count greater than zero
+// and verifying that the lock semaphore has been created.
+// If these conditions are not met we will end up polling infinitely.
+// Sounds dangerous but it is okay, since we will either get a
+// CreateSemaphore or a timeout(deadlock) error from the rtl critical
+// section code, which will result in an exception.
+//
+VOID WaitIcaLockFullyInitialized(VOID)
+{
+ DWORD Delay = 0;
+
+ do {
+ Sleep(Delay++);
+ } while (IcaLock.LockCount < 1 || !IcaLock.LockSemaphore);
+}
+#endif
+
+
+
+// The following routines are used to support IRET hooks. If an interrupt
+// uses an IRET hook then the ICA will not generate a interrupt of that
+// type until the IRET hook has been called.
+
+
+// Exported for vdmredir
+
+void SoftPcEoi(int Adapter, int* Line) {
+ ica_eoi(Adapter, Line, 0);
+}
+
+
+
+
+//
+// Restart delayed interrupts
+// IcaLock should be held upon entry
+//
+
+BOOL ica_restart_interrupts(int adapter)
+{
+ int i;
+
+ if((i = ica_scan_irr(adapter)) & 0x80) {
+ ica_interrupt_cpu(adapter, i &= 0x07);
+ return TRUE;
+ }
+
+ return FALSE;
+}
+//New ICA interrupt state reset function
+
+void ica_reset_interrupt_state(void)
+{
+ int line_no;
+
+ host_ica_lock();
+
+ for(line_no = 0; line_no < 8; line_no++) {
+ VirtualIca[ICA_MASTER].ica_count[line_no] =
+ VirtualIca[ICA_SLAVE].ica_count[line_no] = 0;
+ ica_clear_int(ICA_MASTER,line_no);
+ ica_clear_int(ICA_SLAVE,line_no);
+ }
+
+
+ //Clear interrupt counters
+ VirtualIca[ICA_MASTER].ica_cpu_int =
+ VirtualIca[ICA_SLAVE].ica_cpu_int = FALSE;
+
+#ifdef MONITOR
+ iretHookActive = 0;
+#endif
+ DelayIrqLine = 0;
+
+ //Tell CPU to remove any pending interrupts
+ host_clear_hw_int();
+
+ host_ica_unlock();
+}
+
+
+/*
+ * Handle callout from DPMI to say that an app has asked DPMI to switch it
+ * to protected mode. We use this as an indicator that a protected mode app
+ * will work with the Iret Hook system. If an app does it's own thing with
+ * selectors et al, the BOP table will be hidden, swallowed and generally
+ * lost. Attempts then to transfer control to it will fault.
+ * Known examples of such unfriendliness are the DOS Lotus 123 r3 series.
+ */
+VOID EnableEmulatorIretHooks(void)
+{
+ ; // obsolete
+}
+
+/*
+ * The app is closing - turn off the Iret Hooks in case the next app is
+ * iret hook unfriendly. If it's a friendly app, we'll be called again
+ * via the Enable... routine above.
+ */
+VOID DisableEmulatorIretHooks(void)
+{
+ ; // obsolete
+}
+
+//
+// Retry DelayInts (not iret hooks!)
+//
+// IrqLine - IrqLineBitMask, to be cleared
+//
+VOID ica_RestartInterrupts(ULONG IrqLine)
+{
+#ifdef MONITOR
+
+ //
+ // on x86 we may get multiple bits set
+ // so check both slave and master
+ //
+ UndelayIrqLine = 0;
+
+ if (!ica_restart_interrupts(ICA_SLAVE))
+ ica_restart_interrupts(ICA_MASTER);
+#else
+ host_ica_lock();
+
+ DelayIrqLine &= ~IrqLine;
+
+ ica_restart_interrupts(IrqLine >> 3 ? ICA_SLAVE : ICA_MASTER);
+
+ host_ica_unlock();
+#endif
+}
+
+#ifdef MONITOR
+extern IU16 getMSW(void);
+
+IU32 host_iret_bop_table_addr(IU32 line)
+{
+ ULONG AddrBopTable, IretBopSize;
+
+ ASSERT(line <= 15);
+
+ if (!(iretHookMask & (1 << line))) {
+ return 0;
+ }
+
+ if (getMSW() & 1) {
+ AddrBopTable = (VDM_PM_IRETBOPSEG << 16) | VDM_PM_IRETBOPOFF;
+ IretBopSize = VDM_PM_IRETBOPSIZE;
+ }
+ else {
+ AddrBopTable = AddrIretBopTable;
+ IretBopSize = VDM_RM_IRETBOPSIZE;
+ }
+ return AddrBopTable + IretBopSize * line;
+
+}
+#endif /* MONITOR */