/*++ Copyright (c) 1992 Microsoft Corporation Module Name: dpmi32.h Abstract: This is the private include file for the 32 bit dpmi and protected mode support Author: Dave Hastings (daveh) 24-Nov-1992 Revision History: Neil Sandlin (neilsa) 31-Jul-1995 - Updates for the 486 emulator Neil Sandlin (neilsa) 15-Sep-1996 - Merged dpmi32p.h, dpmidata.h --*/ #define FAST_VDM_REGISTERS // // DPMI structures and definitions // #define I31VERSION 90 // Int 31 services major/minor version #'s #define I31FLAGS 0x000D // 386 extender, pMode NetBIOS #define idCpuType 3 // LATER: conceivably, we could return the real proc type #define I31MasterPIC 0x08 // Master PIC Interrupts start at 08h #define I31SlavePIC 0x70 // Slave PIC Interrupts start at 70h #define MAX_APP_XMEM 0x2000000 // 32 MB = max DPMI mem + max XMS from pif #pragma pack(1) typedef struct _DPMIMEMINFO { DWORD LargestFree; DWORD MaxUnlocked; DWORD MaxLocked; DWORD AddressSpaceSize; DWORD UnlockedPages; DWORD FreePages; DWORD PhysicalPages; DWORD FreeAddressSpace; DWORD PageFileSize; } DPMIMEMINFO, *PDPMIMEMINFO; #pragma pack() #pragma pack(1) typedef struct _DPMI_RMCALLSTRUCT { DWORD Edi; DWORD Esi; DWORD Ebp; DWORD Reserved; DWORD Ebx; DWORD Edx; DWORD Ecx; DWORD Eax; WORD Flags; WORD Es; WORD Ds; WORD Fs; WORD Gs; WORD Ip; WORD Cs; WORD Sp; WORD Ss; } DPMI_RMCALLSTRUCT, *PDPMI_RMCALLSTRUCT; #pragma pack() // // dpmi32 init structure // #pragma pack(1) typedef struct _DOSX_RM_INIT_INFO { USHORT StackSegment; USHORT StackFrameSize; ULONG RmBopFe; ULONG PmBopFe; USHORT RmCodeSegment; USHORT RmCodeSelector; ULONG pFaultHandlerIret; ULONG pFaultHandlerIretd; ULONG pIntHandlerIret; ULONG pIntHandlerIretd; ULONG pIret; ULONG pIretd; USHORT RMCallBackBopOffset; USHORT RMCallBackBopSeg; ULONG RMReflector; USHORT PMReflectorSeg; USHORT InitialLDTSeg; USHORT InitialLDTSize; ULONG RmSaveRestoreState; ULONG PmSaveRestoreState; ULONG RmRawModeSwitch; ULONG PmRawModeSwitch; ULONG VcdPmSvcCall; ULONG MsDosApi; ULONG XmsControl; ULONG HungAppExit; } DOSX_RM_INIT_INFO; typedef DOSX_RM_INIT_INFO UNALIGNED* PDOSX_RM_INIT_INFO; typedef struct _DOSX_INIT_INFO { ULONG pSmallXlatBuffer; ULONG pLargeXlatBuffer; ULONG pStackFramePointer; ULONG pDtaBuffer; } DOSX_INIT_INFO; typedef DOSX_INIT_INFO UNALIGNED* PDOSX_INIT_INFO; #pragma pack() #define SWITCH_TO_DOSX_RMSTACK() { \ setSS(DosxStackSegment); \ setSP(*DosxStackFramePointer); \ *DosxStackFramePointer -= DosxStackFrameSize; \ } #define SWITCH_FROM_DOSX_RMSTACK() { \ *DosxStackFramePointer += DosxStackFrameSize; \ } // // Defines to allow us to use a common dispatch table without having // to add a bunch of stub functions // extern VDM_INTERRUPTHANDLER DpmiInterruptHandlers[256]; extern VDM_FAULTHANDLER DpmiFaultHandlers[32]; #ifdef _X86_ #ifdef FAST_VDM_REGISTERS #define LockedPMStackSel (_LocalVdmTib->DpmiInfo.SsSelector) #define LockedPMStackCount (_LocalVdmTib->DpmiInfo.LockCount) #define PMLockOrigEIP (_LocalVdmTib->DpmiInfo.SaveEip) #define PMLockOrigESP (_LocalVdmTib->DpmiInfo.SaveEsp) #define PMLockOrigSS (_LocalVdmTib->DpmiInfo.SaveSsSelector) #define DosxFaultHandlerIret (_LocalVdmTib->DpmiInfo.DosxFaultIret) #define DosxFaultHandlerIretd (_LocalVdmTib->DpmiInfo.DosxFaultIretD) #define DosxIntHandlerIret (_LocalVdmTib->DpmiInfo.DosxIntIret) #define DosxIntHandlerIretd (_LocalVdmTib->DpmiInfo.DosxIntIretD) #define DosxRMReflector (_LocalVdmTib->DpmiInfo.DosxRmReflector) #else //FAST_VDM_REGISTERS // Temporary only. Doing this so I can switch back to the old way in case ... #define LockedPMStackSel ((PVDM_TIB)NtCurrentTeb()->Vdm)->DpmiInfo.SsSelector #define LockedPMStackCount ((PVDM_TIB)NtCurrentTeb()->Vdm)->DpmiInfo.LockCount #define PMLockOrigEIP ((PVDM_TIB)NtCurrentTeb()->Vdm)->DpmiInfo.SaveEip #define PMLockOrigESP ((PVDM_TIB)NtCurrentTeb()->Vdm)->DpmiInfo.SaveEsp #define PMLockOrigSS ((PVDM_TIB)NtCurrentTeb()->Vdm)->DpmiInfo.SaveSsSelector #define DosxFaultHandlerIret ((PVDM_TIB)NtCurrentTeb()->Vdm)->DpmiInfo.DosxFaultIret #define DosxFaultHandlerIretd ((PVDM_TIB)NtCurrentTeb()->Vdm)->DpmiInfo.DosxFaultIretD #define DosxIntHandlerIret ((PVDM_TIB)NtCurrentTeb()->Vdm)->DpmiInfo.DosxIntIret #define DosxIntHandlerIretd ((PVDM_TIB)NtCurrentTeb()->Vdm)->DpmiInfo.DosxIntIretD #define DosxRMReflector ((PVDM_TIB)NtCurrentTeb()->Vdm)->DpmiInfo.DosxRmReflector #endif //FAST_VDM_REGISTERS #else // _X86_ extern USHORT LockedPMStackSel; extern ULONG LockedPMStackCount; extern ULONG PMLockOrigEIP; extern ULONG PMLockOrigSS; extern ULONG PMLockOrigESP; extern ULONG DosxFaultHandlerIret; extern ULONG DosxFaultHandlerIretd; extern ULONG DosxIntHandlerIret; extern ULONG DosxIntHandlerIretd; extern ULONG DosxRMReflector; // // Ldt entry definition // // This appears in nti386.h, and winnt.h. The definitions in // winnt.h are not included if the nt include files are included. // The simple solution, since this structure will never change // is to put the definition here. // typedef struct _LDT_ENTRY { WORD LimitLow; WORD BaseLow; union { struct { BYTE BaseMid; BYTE Flags1; // Declare as bytes to avoid alignment BYTE Flags2; // Problems. BYTE BaseHi; } Bytes; struct { DWORD BaseMid : 8; DWORD Type : 5; DWORD Dpl : 2; DWORD Pres : 1; DWORD LimitHi : 4; DWORD Sys : 1; DWORD Reserved_0 : 1; DWORD Default_Big : 1; DWORD Granularity : 1; DWORD BaseHi : 8; } Bits; } HighWord; } LDT_ENTRY, *PLDT_ENTRY; // // Data items // extern VOID force_yoda(VOID); extern VOID DisableEmulatorIretHooks(VOID); extern VOID EnableEmulatorIretHooks(VOID); #endif typedef struct _IDT_ENTRY { WORD OffsetLow; WORD Selector; BYTE Reserved; union { struct { BYTE Flags; } Bytes; struct { BYTE Type : 5; BYTE Dpl : 2; BYTE Pres : 1; } Bits; } u; WORD OffsetHi; } IDT_ENTRY, *PIDT_ENTRY; #define GET_SELECTOR_BASE(Sel) ( (ULONG) ( \ Ldt[Sel>>3].BaseLow | \ Ldt[Sel>>3].HighWord.Bytes.BaseMid << 16 | \ Ldt[Sel>>3].HighWord.Bytes.BaseHi << 24 \ )) #define GET_SELECTOR_LIMIT(Sel) ( (ULONG) ( \ ((Ldt[Sel>>3].HighWord.Bits.LimitHi << 16 | Ldt[Sel>>3].LimitLow) \ << (12 * Ldt[Sel>>3].HighWord.Bits.Granularity)) + \ Ldt[Sel>>3].HighWord.Bits.Granularity * 0xFFF \ )) #if DBG #define GET_SHADOW_SELECTOR_LIMIT(Selector, Limit) \ Limit = SelectorLimit[Selector>>3] #else #ifdef _X86_ #define GET_SHADOW_SELECTOR_LIMIT(Selector, Limit) _asm \ { \ _asm xor eax, eax \ _asm xor ecx, ecx \ _asm mov ax, Selector \ _asm or eax, 7 \ _asm lsl ecx, eax \ _asm mov [Limit], ecx \ } #else #define GET_SHADOW_SELECTOR_LIMIT(Selector, Limit) \ Limit = GET_SELECTOR_LIMIT(Selector) #endif #endif #define SET_SELECTOR_LIMIT(Sel, Limit) { \ USHORT i = Sel>>3; \ if (!Ldt[i].HighWord.Bits.Granularity) { \ Ldt[i].LimitLow = (USHORT)(Limit & 0x0000FFFF); \ Ldt[i].HighWord.Bits.LimitHi = \ (Limit & 0x000f0000) >> 16; \ } else { \ Ldt[i].LimitLow = (USHORT)((Limit >> 12) & 0xFFFF); \ Ldt[i].HighWord.Bits.LimitHi = \ ((Limit >> 12) & 0x000f0000) >> 16; \ } \ } #define SET_SELECTOR_ACCESS(Sel, Access) { \ Ldt[Sel>>3].HighWord.Bytes.Flags1 = LOBYTE(Access); \ Ldt[Sel>>3].HighWord.Bytes.Flags2 = (HIBYTE(Access) & 0xd0) + \ (Ldt[Sel>>3].HighWord.Bytes.Flags2 & 0x0f); \ } #define IS_SELECTOR_FREE(Sel) ((Ldt[Sel>>3].HighWord.Bytes.Flags1 == 0) && \ (Ldt[Sel>>3].HighWord.Bytes.BaseHi == 0x80)) #define IS_SELECTOR_READABLE(Sel) ( \ ((Ldt[Sel>>3].HighWord.Bytes.Flags1 & \ (AB_DPL3|AB_PRESENT|AB_DATA)) == \ (AB_DPL3|AB_PRESENT|AB_DATA)) \ ) #ifdef _X86_ #define FLUSH_SELECTOR_CACHE(SelStart, SelCount) TRUE #else #define FLUSH_SELECTOR_CACHE(SelStart, SelCount) FlushSelectorCache(SelStart, SelCount) #endif // // These values define the range of the reserved DPMI selectors, given // out by Int31, func 000d. // #define SEL_DPMI_FIRST 0 #define SEL_DPMI_LAST 0x78 // Whenever we allocate a descriptor, the access rights byte is set // to 0Fh. This marks it as a '386 task gate, which is not legal to // have in the GDT. We need to stick something in this byte, because // having the access rights byte be 0 means that it is free, which is // no longer the case. #define MARK_SELECTOR_ALLOCATED(Sel) { \ Ldt[Sel>>3].HighWord.Bytes.Flags1 = 0xf; \ Ldt[Sel>>3].HighWord.Bytes.BaseHi = 0; \ } #define MARK_SELECTOR_FREE(Sel) { \ Ldt[Sel>>3].HighWord.Bytes.Flags1 = 0; \ Ldt[Sel>>3].HighWord.Bytes.BaseHi = 0x80; \ } #define NEXT_FREE_SEL(Sel) (Ldt[Sel>>3].LimitLow) #define ALLOCATE_SELECTOR() AllocateSelectors(1, FALSE) #define ALLOCATE_SELECTORS(Count) AllocateSelectors(Count, FALSE) #define ALLOCATE_WOW_SELECTORS(Count) AllocateSelectors(Count, TRUE) #define SEGMENT_IS_BIG(sel) ((selPrev)->Next = BLK->Next;\ (BLK->Next)->Prev = BLK->Prev;\ if (CurrentPSPSelector != 0 && BLK->Owner != 0) CurrentPSPXmem -= BLK->Length #define INSERT_BLOCK(BLK, HEAD) \ BLK->Next = HEAD.Next; \ BLK->Prev= HEAD.Next->Prev;\ (HEAD.Next)->Prev = BLK; \ HEAD.Next = BLK; \ if (CurrentPSPSelector != 0 && BLK->Owner != 0) CurrentPSPXmem += BLK->Length #define RESIZE_BLOCK(BLK, ADDR, SIZE) \ if (CurrentPSPSelector != 0 && BLK->Owner != 0) { \ CurrentPSPXmem -= BLK->Length; \ CurrentPSPXmem += SIZE; \ } \ BLK->Address = (PVOID)ADDR; \ BLK->Length = SIZE // // Visible structure for save state stuff // typedef struct _VSavedState { UCHAR Misc[28]; } VSAVEDSTATE, PVSAVEDSTATE; // // Descriptor mapping (for dib.drv) // #ifndef _X86_ ULONG GetDescriptorMapping( USHORT Sel, ULONG LdtBase ); typedef struct _DESC_MAPPING { USHORT Sel; USHORT SelCount; ULONG LdtBase; ULONG FlatBase; struct _DESC_MAPPING* pNext; } DESC_MAPPING, *PDESC_MAPPING; #endif // // Dpmi32 data // //SLT: these two should be per-thread extern ULONG LastLockedPMStackSS; extern ULONG LastLockedPMStackESP; extern PUCHAR SmallXlatBuffer; extern PUCHAR LargeXlatBuffer; extern BOOL SmallBufferInUse; extern USHORT LargeBufferInUseCount; extern USHORT DosxStackSegment; extern USHORT DosxRmCodeSegment; extern USHORT DosxRmCodeSelector; extern PWORD16 DosxStackFramePointer; extern USHORT DosxStackFrameSize; extern USHORT CurrentAppFlags; extern ULONG RmBopFe; extern ULONG PmBopFe; extern USHORT RMCallBackBopSeg; extern USHORT RMCallBackBopOffset; extern USHORT PMReflectorSeg; extern PUCHAR DosxDtaBuffer; extern ULONG IntelBase; extern PLDT_ENTRY Ldt; extern USHORT LdtSel; extern USHORT LdtMaxSel; extern USHORT LdtUserSel; extern PIDT_ENTRY Idt; extern USHORT WOWAllocSeg; extern USHORT WOWAllocFunc; extern USHORT WOWFreeSeg; extern USHORT WOWFreeFunc; // // Information about the current DTA // // N.B. The selector:offset, and flat pointer following MAY point to // different linear addresses. This will be the case if the // dta selector is in high memory extern PUCHAR CurrentDta; extern PUCHAR CurrentPmDtaAddress; extern PUCHAR CurrentDosDta; extern USHORT CurrentDtaSelector; extern USHORT CurrentDtaOffset; #if DBG extern ULONG SelectorLimit[LDT_SIZE]; #endif // // Register manipulation functions (for register that might be 16 or 32 bits) // extern GETREGISTERFUNCTION GetCXRegister; extern GETREGISTERFUNCTION GetDXRegister; extern GETREGISTERFUNCTION GetDIRegister; extern GETREGISTERFUNCTION GetSIRegister; extern GETREGISTERFUNCTION GetBXRegister; extern GETREGISTERFUNCTION GetAXRegister; extern GETREGISTERFUNCTION GetSPRegister; extern SETREGISTERFUNCTION SetCXRegister; extern SETREGISTERFUNCTION SetDXRegister; extern SETREGISTERFUNCTION SetDIRegister; extern SETREGISTERFUNCTION SetSIRegister; extern SETREGISTERFUNCTION SetBXRegister; extern SETREGISTERFUNCTION SetAXRegister; extern SETREGISTERFUNCTION SetSPRegister; extern USHORT CurrentPSPSelector; extern ULONG CurrentPSPXmem; extern ULONG FlatAddress[LDT_SIZE]; extern ULONG DosxIret; extern ULONG DosxIretd; extern ULONG DosxRmSaveRestoreState; extern ULONG DosxPmSaveRestoreState; extern ULONG DosxRmRawModeSwitch; extern ULONG DosxPmRawModeSwitch; extern ULONG DosxVcdPmSvcCall; extern ULONG DosxMsDosApi; extern ULONG DosxXmsControl; extern ULONG DosxHungAppExit; // // Monitor functions // VOID GetFastBopEntryAddress( PCONTEXT VdmContext ); // // Dispatched functions (via bop) // VOID DpmiInitDosxRM(VOID); VOID DpmiInitDosx(VOID); VOID DpmiInitLDT(VOID); VOID DpmiGetFastBopEntry(VOID); VOID DpmiInitIDT(VOID); VOID DpmiInitExceptionHandlers(VOID); VOID DpmiInitPmStackInfo(VOID); VOID DpmiInitApp(VOID); VOID DpmiTerminateApp(VOID); VOID DpmiDpmiInUse(VOID); VOID DpmiDpmiNoLongerInUse(VOID); VOID switch_to_protected_mode(VOID); VOID switch_to_real_mode(VOID); VOID DpmiSetAltRegs(VOID); VOID DpmiVcdPmSvcCall32(VOID); VOID DpmiFreeAppXmem(USHORT); VOID DpmiFreeAllXmem(VOID); VOID DpmiIntHandlerIret16(VOID); VOID DpmiIntHandlerIret32(VOID); VOID DpmiFaultHandlerIret16(VOID); VOID DpmiFaultHandlerIret32(VOID); VOID DpmiUnhandledExceptionHandler(VOID); VOID DpmiRMCallBackCall(VOID); VOID DpmiReflectIntrToPM(VOID); VOID DpmiReflectIntrToV86(VOID); VOID DpmiSetDescriptorEntry(VOID); VOID DpmiAllocateSelectors(VOID); VOID DpmiFreeSelector(VOID); VOID DpmiResetLDTUserBase(VOID); VOID DpmiXlatInt21Call(VOID); VOID DpmiInt31Entry(VOID); VOID DpmiInt31Call(VOID); VOID DpmiHungAppIretAndExit(VOID); // // Internal functions // VOID BeginUseLockedPMStack( VOID ); BOOL EndUseLockedPMStack( VOID ); BOOL BuildStackFrame( ULONG StackUnits, PUCHAR *pVdmStackPointer, ULONG *pNewSP ); VOID EmulateV86Int( UCHAR InterruptNumber ); typedef enum { RESTORE_FLAGS, PASS_FLAGS, PASS_CARRY_FLAG, PASS_CARRY_FLAG_16 } IRET_BEHAVIOR; VOID SimulateIret( IRET_BEHAVIOR fdsp ); VOID SimulateFarCall( USHORT Seg, ULONG Offset ); VOID SimulateCallWithIretFrame( USHORT Seg, ULONG Offset ); BOOL DpmiSwIntHandler( ULONG IntNumber ); BOOL DpmiHwIntHandler( ULONG IntNumber ); BOOL DpmiFaultHandler( ULONG IntNumber, ULONG ErrorCode ); BOOL SetProtectedModeInterrupt( USHORT IntNumber, USHORT Sel, ULONG Offset, USHORT Flags ); BOOL SetFaultHandler( USHORT IntNumber, USHORT Sel, ULONG Offset ); BOOL DispatchPMInt( UCHAR InterruptNumber ); VOID DpmiRMCall( UCHAR mode ); VOID DpmiAllocateRMCallBack( VOID ); VOID DpmiFreeRMCallBack( VOID ); BOOL PMInt2fHandler( VOID ); VOID GetVxDApiHandler( USHORT VxdId ); BOOL DpmiSetDebugRegisters( PULONG RegisterPointer ); BOOL DpmiGetDebugRegisters( PULONG RegisterPointer ); // // Descriptor managagment // #ifdef _X86_ BOOL DpmiSetX86Descriptor( USHORT SelStart, USHORT SelCount ); #else VOID FlushSelectorCache( USHORT SelStart, USHORT SelCount ); #endif VOID SetShadowDescriptorEntries( USHORT SelStart, USHORT SelCount ); VOID SetDescriptorBase( USHORT Sel, ULONG Base ); VOID SetDescriptor( USHORT Sel, ULONG Base, ULONG Limit, USHORT Access ); USHORT AllocateSelectors( USHORT Count, BOOL bWow ); BOOL FreeSelector( USHORT Sel ); USHORT FindSelector( ULONG Base, UCHAR Access ); BOOL RemoveFreeSelector( USHORT Sel ); USHORT SegmentToSelector( USHORT Segment, USHORT Access ); VOID SetDescriptorArray( USHORT Sel, ULONG Base, ULONG MemSize ); // // Memory management // NTSTATUS DpmiAllocateVirtualMemory( PVOID *Address, PULONG Size ); NTSTATUS DpmiFreeVirtualMemory( PVOID *Address, PULONG Size ); NTSTATUS DpmiReallocateVirtualMemory( PVOID OldAddress, ULONG OldSize, PVOID *NewAddress, PULONG NewSize ); VOID DpmiGetMemoryInfo( VOID ); PMEM_DPMI DpmiAllocateXmem( ULONG Size ); BOOL DpmiFreeXmem( PMEM_DPMI XmemBlock ); BOOL DpmiIsXmemHandle( PMEM_DPMI XmemBlock ); BOOL DpmiReallocateXmem( PMEM_DPMI XmemBlock, ULONG Size ); PMEM_DPMI DpmiFindXmem( USHORT Sel ); ULONG DpmiCalculateAppXmem( VOID ); VOID DpmiAllocateDosMem( VOID ); VOID DpmiFreeDosMem( VOID ); VOID DpmiSizeDosMem( VOID ); // // Utility functions // VOID DpmiInitRegisterSize( VOID ); VOID DpmiSwitchToProtectedMode( VOID ); VOID DpmiSwitchToRealMode( VOID ); VOID DpmiPushRmInt( USHORT InterruptNumber ); VOID DpmiSaveSegmentsAndStack( PVOID ContextPointer ); PVOID DpmiRestoreSegmentsAndStack( VOID ); // // Int21 translation // VOID SetVector( VOID ); VOID GetVector( VOID ); PUCHAR DpmiMapAndCopyBuffer( PUCHAR Buffer, USHORT BufferLength ); VOID DpmiUnmapAndCopyBuffer( PUCHAR Destination, PUCHAR Source, USHORT BufferLength ); USHORT DpmiCalcFcbLength( PUCHAR FcbPointer ); PUCHAR DpmiMapString( USHORT StringSeg, ULONG StringOff, PWORD16 Length ); PUCHAR DpmiAllocateBuffer( USHORT Length ); #define DpmiUnmapString DpmiFreeBuffer #define DpmiUnmapBuffer DpmiFreeBuffer VOID DpmiFreeBuffer( PUCHAR Buffer, USHORT Length ); VOID DpmiFreeAllBuffers( VOID ); #ifdef DBCS VOID DpmiSwitchToDosxStack( VOID ); VOID DpmiSwitchFromDosxStack( VOID ); #endif //DBCS