#include #include #include #include #include #include "insignia.h" #include "host_def.h" #include #ifndef MONITOR #include #endif /* INSIGNIA MODULE SPECIFICATION ----------------------------- THIS PROGRAM SOURCE FILE IS SUPPLIED IN CONFIDENCE TO THE CUSTOMER, THE CONTENTS OR DETAILS OF ITS OPERATION MUST NOT BE DISCLOSED TO ANY OTHER PARTIES WITHOUT THE EXPRESS AUTHORISATION FROM THE DIRECTORS OF INSIGNIA SOLUTIONS LTD. DESIGNER : Jim Hatfield REVISION HISTORY : First version : 29th August 1988 Second version : 18th May 1991 MODULE NAME : nt_bop SOURCE FILE NAME : nt_bop.c PURPOSE : Supply the NT-specific BOP FF operations. ------------------------------------------------------------------------- [1.2 DATATYPES FOR [1.1] (if not basic C types)] STRUCTURES/TYPEDEFS/ENUMS: ------------------------------------------------------------------------- [1.3 INTERMODULE IMPORTS] PROCEDURES: None DATA: None ------------------------------------------------------------------------- [1.4 DESCRIPTION OF INTERMODULE INTERFACE] [1.4.1 IMPORTED OBJECTS] DATA OBJECTS : None /*======================================================================= [3.INTERMODULE INTERFACE DECLARATIONS] ========================================================================= [3.1 INTERMODULE IMPORTS] */ /* [3.1.1 #INCLUDES] */ #include "stdio.h" #include "xt.h" #include CpuH #include "sas.h" #include "error.h" #include "config.h" #include "cntlbop.h" #include "host_bop.h" #include "demexp.h" #include "xmsexp.h" #include "sim32.h" #include "idetect.h" #include "bios.h" #include "nt_reset.h" #include "nt_eoi.h" #include #include "yoda.h" /* [3.1.2 DECLARATIONS] */ /* [3.2 INTERMODULE EXPORTS] */ /* 5.MODULE INTERNALS : (not visible externally,global internally)] [5.1 LOCAL DECLARATIONS] */ /* [5.1.1 #DEFINES] */ /* [5.1.2 TYPEDEF, STRUCTURE, ENUM DECLARATIONS] */ // // MYFARPROC // typedef ULONG (*MYFARPROC)(); /* [5.1.3 PROCEDURE() DECLARATIONS] */ /* ----------------------------------------------------------------------- [5.2 LOCAL DEFINITIONS] [5.2.1 INTERNAL DATA DEFINITIONS */ /* [5.2.2 INTERNAL PROCEDURE DEFINITIONS] */ /* 7.INTERMODULE INTERFACE IMPLEMENTATION : */ VOID WaitIfIdle(VOID), WakeUpNow(VOID); VOID to_com_driver(VOID); VOID call_ica_hw_interrupt(int, half_word, int); VOID ica_enable_iret_hook(int, int, int); VOID ica_iret_hook_called(int); /* [7.1 INTERMODULE DATA DEFINITIONS] */ #define SEGOFF(seg,off) (((ULONG)(seg) << 16) + ((off))) /********************************************************/ /* GLOBALS */ void UMBNotify(unsigned char); VOID demDasdInit(VOID); control_bop_array host_bop_table[] = { 0, NULL }; /*:::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::*/ /*:::::::::::::::::::::::;:::::: MS BOP stubs :::::::::::::::::::::::::::::*/ /*:::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::*/ // DOS EMULATION BOP void MS_bop_0(void) { ULONG DemCmd; DemCmd = (ULONG)(*Sim32GetVDMPointer(SEGOFF(getCS(),getIP()), 1, FALSE )); DemDispatch( DemCmd ); setIP((USHORT)(getIP() + 1)); // we need to prevent the idle system from going off on intensive file // reads. However, we don't want to disable it for continuous 'Get Time' // calls (command 0x15). Nor for Get Date (0x15). if (DemCmd != 0x15 && DemCmd != 0x14) IDLE_disk(); } // WOW BOP HANDLE hWOWDll; MYFARPROC WOWDispatchEntry; MYFARPROC WOWInitEntry; VOID (*pW32HungAppNotifyThread)(UINT) = NULL; static BOOL WowModeInitialized = FALSE; void MS_bop_1(void) { if (!WowModeInitialized) { //Load the WOW DLL if ((hWOWDll = SafeLoadLibrary("WOW32")) == NULL) { #ifndef PROD HostDebugBreak(); #endif TerminateVDM(); return; } // Get the init entry point and dispatch entry point if ((WOWInitEntry = (MYFARPROC)GetProcAddress(hWOWDll, "W32Init")) == NULL) { #ifndef PROD HostDebugBreak(); #endif FreeLibrary(hWOWDll); TerminateVDM(); return; } if ((WOWDispatchEntry = GetProcAddress(hWOWDll, "W32Dispatch")) == NULL) { #ifndef PROD HostDebugBreak(); #endif FreeLibrary(hWOWDll); TerminateVDM(); return; } //Get Comms functions if ((GetCommHandle = (GCHfn) GetProcAddress(hWOWDll, "GetCommHandle")) == NULL) { #ifndef PROD HostDebugBreak(); #endif FreeLibrary(hWOWDll); TerminateVDM(); return; } if ((GetCommShadowMSR = (GCSfn) GetProcAddress(hWOWDll, "GetCommShadowMSR")) == NULL) { #ifndef PROD HostDebugBreak(); #endif FreeLibrary(hWOWDll); TerminateVDM(); return; } //Get hung app Notification routine pW32HungAppNotifyThread = (VOID(*)(UINT))GetProcAddress( hWOWDll, "W32HungAppNotifyThread"); if (!pW32HungAppNotifyThread) { #ifndef PROD HostDebugBreak(); #endif FreeLibrary(hWOWDll); TerminateVDM(); return; } // Call the init routine if ((*WOWInitEntry)() == FALSE) { #ifndef PROD HostDebugBreak(); #endif TerminateVDM(); return; } WowModeInitialized = TRUE; } #if !defined(CPU_40_STYLE) || defined(CCPU) (*WOWDispatchEntry)(); #else // Dispatch to WOW dispatcher { static BYTE **AddressOfLocal; BYTE *localSimulateContext = GLOBAL_SimulateContext; AddressOfLocal = &localSimulateContext; (*WOWDispatchEntry)(); SET_GLOBAL_SimulateContext(localSimulateContext); if(AddressOfLocal != &localSimulateContext) { //Thread switch detected via stack change, force CPU to //abort the current fragment, reseting GDP var's refering //to the host stack setEIP(getEIP()); } } #endif /* CPU_40_STYLE */ } // XMS BOP void MS_bop_2(void) { XMSDispatch((ULONG)(*Sim32GetVDMPointer(SEGOFF(getCS(),getIP()), 1, FALSE ))); setIP((USHORT)(getIP() + 1)); } // DEBUGGING BOP void MS_bop_int3(void) { #ifndef PROD force_yoda(); #endif } /*::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::*/ // MONITOR DPMI BOP void MS_bop_3(void) { IMPORT VOID DpmiDispatch(VOID); DpmiDispatch(); } // SCS BOP /* CMD dispatcher, this BOP will only work in real mode */ void MS_bop_4(void) { half_word Command; IMPORT BOOL CmdDispatch(ULONG); sas_load( ((ULONG)getCS()<<4) + getIP(), &Command); CmdDispatch((ULONG) Command); setIP((USHORT)(getIP() + 1)); } // // MsBop6 - used to dispatch to debugger support functions // void MS_bop_6() { IMPORT VOID DBGDispatch(VOID); /* ** All of the parameters for the debugger support ** should be on the VDMs stack. */ DBGDispatch(); } // // DefaultVrInitialized - calls to VrInitialized (through a pointer to a routine) // will return FALSE until the VDMREDIR DLL has been successfully loaded and // initialized // ULONG DefaultVrInitialized(VOID); ULONG DefaultVrInitialized() { return FALSE; } // // publicly accessible routine addresses. These are not expected to be called // until VrInitialized points at the real VrInitialized routine inside VdmRedir // #if DBG ULONG DefaultVrError(VOID); ULONG DefaultVrError() { printf("MS_bop_7: Error: function called without VDMREDIR loaded!\n"); HostDebugBreak(); return 0; } MYFARPROC VrDispatch = &DefaultVrError; MYFARPROC VrInitialized = &DefaultVrInitialized; MYFARPROC VrReadNamedPipe = &DefaultVrError; MYFARPROC VrWriteNamedPipe = &DefaultVrError; MYFARPROC VrIsNamedPipeName = &DefaultVrError; MYFARPROC VrIsNamedPipeHandle = &DefaultVrError; MYFARPROC VrAddOpenNamedPipeInfo = &DefaultVrError; MYFARPROC VrConvertLocalNtPipeName = &DefaultVrError; MYFARPROC VrRemoveOpenNamedPipeInfo = &DefaultVrError; #else MYFARPROC VrDispatch; MYFARPROC VrInitialized = DefaultVrInitialized; MYFARPROC VrReadNamedPipe; MYFARPROC VrWriteNamedPipe; MYFARPROC VrIsNamedPipeName; MYFARPROC VrIsNamedPipeHandle; MYFARPROC VrAddOpenNamedPipeInfo; MYFARPROC VrConvertLocalNtPipeName; MYFARPROC VrRemoveOpenNamedPipeInfo; #endif BOOL LoadVdmRedir(VOID); VOID MS_bop_7( VOID ) /*++ Routine Description: Calls Vdm Redir Dispatcher. If the VDMREDIR DLL is not loaded, tries to load it before calling Dispatcher. If the DLL could not be loaded (or couldn't be loaded in the past) return an ERROR_INVALID_FUNCTION Arguments: None. Return Value: None. --*/ { static int VdmRedirLoadState = 0; // tristate: // 0 = not loaded, first attempt // 1 = loaded // 2 = tried loading already, failed // // new: VdmRedir support is now a DLL. Try to load it. If it can't be loaded // for whatever reason, return an error to the DOS program. Since it is // trying to call a Redir function, we will return ERROR_INVALID_FUNCTION // switch (VdmRedirLoadState) { case 0: // // the DLL is not yet loaded. If we can't load it and get the entry // points for any reason, return ERROR_INVALID_FUNCTION. From now on, // net support (including DLC, NetBIOS, named pipes and mailslots) will // not be available to DOS programs in this session (running as part of // this NTVDM process), but the rest of DOS functionality will be OK // if (LoadVdmRedir()) { VdmRedirLoadState = 1; } else { VdmRedirLoadState = 2; goto returnError; } // // fall through to dispatcher in case 1 // case 1: // // VdmRedir is loaded: do it // VrDispatch((ULONG)(*Sim32GetVDMPointer(SEGOFF(getCS(),getIP()), 1, (UCHAR)(getMSW() & MSW_PE ? TRUE : FALSE) ))); break; case 2: // // we tried to load VdmRedir once, but the wheels fell off, so we don't // try it any more - just return an error, OK? // returnError: setCF(1); setAX(ERROR_INVALID_FUNCTION); break; #if DBG default: printf("MS_bop_7: BAD: VdmRedirLoadState=%d???\n", VdmRedirLoadState); #endif } // // irrespective of whether the DLL is/was loaded or not, we must bump the // VDM ip past the BOP // setIP((USHORT)(getIP() + 1)); } HANDLE hVdmRedir; BOOL VdmRedirLoaded = FALSE; BOOL IsVdmRedirLoaded() { return VdmRedirLoaded; } BOOL LoadVdmRedir() { #if DBG LPSTR funcName = ""; #endif if (VdmRedirLoaded) { return TRUE; } if (hVdmRedir = SafeLoadLibrary("VDMREDIR")) { // // get addresses of procedures called by functions in dos\dem\demfile.c // and dos\dem\demhndl.c // if ((VrDispatch = (MYFARPROC)GetProcAddress(hVdmRedir, "VrDispatch")) == NULL) { #if DBG funcName = "VrDispatch"; #endif goto closeAndReturnError; } if ((VrInitialized = (MYFARPROC)GetProcAddress(hVdmRedir, "VrInitialized")) == NULL) { #if DBG funcName = "VrInitialized"; #endif goto closeAndReturnError; } if ((VrReadNamedPipe = (MYFARPROC)GetProcAddress(hVdmRedir, "VrReadNamedPipe")) == NULL) { #if DBG funcName = "VrReadNamedPipe"; #endif goto closeAndReturnError; } if ((VrWriteNamedPipe = (MYFARPROC)GetProcAddress(hVdmRedir, "VrWriteNamedPipe")) == NULL) { #if DBG funcName = "VrWriteNamedPipe"; #endif goto closeAndReturnError; } if ((VrIsNamedPipeName = (MYFARPROC)GetProcAddress(hVdmRedir, "VrIsNamedPipeName")) == NULL) { #if DBG funcName = "VrIsNamedPipeName"; #endif goto closeAndReturnError; } if ((VrIsNamedPipeHandle = (MYFARPROC)GetProcAddress(hVdmRedir, "VrIsNamedPipeHandle")) == NULL) { #if DBG funcName = "VrIsNamedPipeHandle"; #endif goto closeAndReturnError; } if ((VrAddOpenNamedPipeInfo = (MYFARPROC)GetProcAddress(hVdmRedir, "VrAddOpenNamedPipeInfo")) == NULL) { #if DBG funcName = "VrAddOpenNamedPipeInfo"; #endif goto closeAndReturnError; } if ((VrConvertLocalNtPipeName = (MYFARPROC)GetProcAddress(hVdmRedir, "VrConvertLocalNtPipeName")) == NULL) { #if DBG funcName = "VrConvertLocalNtPipeName"; #endif goto closeAndReturnError; } if ((VrRemoveOpenNamedPipeInfo = (MYFARPROC)GetProcAddress(hVdmRedir, "VrRemoveOpenNamedPipeInfo")) == NULL) { #if DBG funcName = "VrRemoveOpenNamedPipeInfo"; #endif goto closeAndReturnError; } VdmRedirLoaded = TRUE; return TRUE; } closeAndReturnError: #if DBG printf("MS_bop_7: Error: cannot locate entry point %s in VDMREDIR.DLL\n", funcName); #endif CloseHandle(hVdmRedir); return FALSE; } /*::::::::::::::::::::::::::::::::::::::::::::::::::::::: More MS BOP stubs */ void MS_bop_5(void) { IMPORT VOID ms_bop(VOID); ms_bop(); } // // MS_BOP_8 : Third Party Bop // void ISV_RegisterModule (BOOL); void ISV_DeRegisterModule (void); void ISV_DispatchCall (void); void MS_bop_8 (void) { ULONG iFunc; UCHAR uchMode = getMSW() & MSW_PE ? TRUE : FALSE; // Get the Function Number iFunc = (ULONG)(*Sim32GetVDMPointer(SEGOFF(getCS(),getIP()), 1, uchMode )); switch (iFunc) { case 0: /* RegisterModule */ ISV_RegisterModule (uchMode); break; case 1: /* DeRegisterModule */ ISV_DeRegisterModule (); break; case 2: /* DispatchCall */ ISV_DispatchCall (); break; default: setCF(1); } setIP((USHORT)(getIP() + 1)); return; } // // MS_BOP_9 : Direct Access Error bop. An app has tried to do something // dubious. Tell the user about it. Picks up the type of the error from // AX. // void MS_bop_9(void) { host_direct_access_error((ULONG)getAX()); } // // MS_BOP_A : Idle control from VDD. // AX == 0: VDD wants VDM to idle. It will (briefly - 10ms) provided it // has not just seen some counter idle indication. // AX == 1: VDD wants VDM to wake up if still idling. // void MS_bop_A(void) { word control; control = getAX(); if (control == 0) WaitIfIdle(); else if (control == 1) WakeUpNow(); #ifndef PROD else printf("NTVDM:Idle control from VDD bop passed bad AX value (%d)\n", control); #endif } /* * DbgBreakPoint Jonle * A very simple way to break into the debugger from 16 bit * Apps registers are unmodified * Uses the safe DbgBreakPoint in ntvdm.c * On a free build when we are not being debugged, nothing will happen. * On a checked build when we are not being debugged, access violate * With debugger running breaks into 32 bit debugger */ void MS_bop_B(void) { OutputDebugString("NTVDM:BOP_DBGBREAKPOINT\n"); DbgBreakPoint(); } //timing bop void MS_bop_C(void) { illegal_bop(); } /*:::::::::::::::::::::::::::::::::: This bop is used to control iret hooks */ void MS_bop_D(void) { #ifdef MONITOR extern VOID MonitorEndIretHook(VOID); half_word iret_index; // get iret index iret_index = *Sim32GetVDMPointer(SEGOFF(getCS(),getIP()), 1, (UCHAR)(getPE() ? TRUE : FALSE) ); // Tell ica that an iret bop has been called ica_iret_hook_called((int) iret_index); // // Clean up stack, and resume normal code path // MonitorEndIretHook(); #else illegal_bop(); #endif } // Notification bop // currently defined notification code is // 00 -- config.sys processing completed. // extern LARGE_INTEGER CounterStart, FrequenceStart; void MS_bop_E(void) { unsigned char code; code = getAL(); if (code == 0) { UMBNotify(0); demDasdInit(); } else { #ifndef PROD printf("Invalid notification bop\n"); #endif } } void MS_bop_F(void) { extern void kb_setup_vectors(void); kb_setup_vectors(); #ifdef MONITOR AddrIretBopTable = ( ((ULONG)getDS() << 16) | (ULONG)getDI() ); #ifndef PROD if (getCX() != VDM_RM_IRETBOPSIZE) { OutputDebugString("NTVDM:spacing != VDM_RM_IRETBOPSIZE\n"); DebugBreak(); } #endif #endif /* * Now that spckbd is loaded, and the ivt rom vectors are hooked * we can allow hw interrupts. */ // nt_init_event_thread will resume the event thread after it // sync up BIOS led states with the system // ResumeThread(ThreadInfo.EventMgr.Handle); host_ica_lock(); DelayIrqLine = 0; if (!ica_restart_interrupts(ICA_SLAVE)) ica_restart_interrupts(ICA_MASTER); host_ica_unlock(); #ifdef MONITOR setCF(1); #else setCF(0); #endif } #define MAX_ISV_BOP 10 typedef struct _ISVBOP { FARPROC fpDispatch; HANDLE hDll; } ISVBOP; #define MAX_PROC_NAME 64 char procbuffer [MAX_PROC_NAME]; ISVBOP isvbop_table [MAX_ISV_BOP]; void ISV_RegisterModule (BOOL fMode) { char *pchDll,*pchInit,*pchDispatch; HANDLE hDll; FARPROC DispatchEntry; FARPROC InitEntry; ULONG i; UCHAR uchMode; // Check if we have free space in bop table. for (i=0; i= MAX_PROC_NAME) { FreeLibrary(hDll); setCF (1); setAX(4); return; } strcpy (procbuffer,pchInit); pchInit = procbuffer; } if ((InitEntry = (MYFARPROC)GetProcAddress(hDll, pchInit)) == NULL){ FreeLibrary(hDll); setCF(1); setAX(3); return; } } if ((ULONG)pchDispatch < 64*1024){ if (strlen (pchDispatch) >= MAX_PROC_NAME) { FreeLibrary(hDll); setCF (1); setAX(4); return; } strcpy (procbuffer,pchDispatch); pchDispatch = procbuffer; } if ((DispatchEntry = (MYFARPROC)GetProcAddress(hDll, pchDispatch)) == NULL){ FreeLibrary(hDll); setCF(1); setAX(2); return; } // Call the init routine if (pchInit) { (*InitEntry)(); } // Fill up the bop table isvbop_table[i].hDll = hDll; isvbop_table[i].fpDispatch = DispatchEntry; i++; setAX((USHORT)i); return; } void ISV_DeRegisterModule (void) { ULONG Handle; HANDLE hDll; Handle = (ULONG)getAX(); if (Handle == 0 || Handle > MAX_ISV_BOP){ #ifndef PROD printf("Invalid BOP Handle Passed to DeRegisterModule"); #endif TerminateVDM(); return; } Handle--; hDll = isvbop_table[Handle].hDll; FreeLibrary (hDll); isvbop_table[Handle].hDll = 0; isvbop_table[Handle].fpDispatch = NULL; return; } void ISV_DispatchCall (void) { ULONG Handle; FARPROC DispatchEntry; Handle = (ULONG)getAX(); if (Handle == 0 || Handle > MAX_ISV_BOP){ #ifndef PROD printf("Invalid BOP Handle Passed to DispatchCall"); #endif TerminateVDM(); return; } Handle--; DispatchEntry = isvbop_table[Handle].fpDispatch; (*DispatchEntry)(); return; } #ifdef i386 /* * "Safe" version of LoadLibrary which preserves floating-point state * across the load. This is critical on x86 because the FP state being * preserved is the 16-bit app's state. MSVCRT.DLL is one offender which * changes the Precision bits in its Dll init routine. * * On RISC, this is an alias for LoadLibrary * */ HINSTANCE SafeLoadLibrary(char *name) { HINSTANCE hInst; BYTE FpuState[108]; // Save the 487 state _asm { lea ecx, [FpuState] fsave [ecx] } hInst = LoadLibrary(name); // Restore the 487 state _asm { lea ecx, [FpuState] frstor [ecx] } return hInst; } #endif //i386