|
|
PAGE ,132 TITLE DXFUNC.ASM -- Dos Extender Function Handlers
; Copyright (c) Microsoft Corporation 1988-1991. All Rights Reserved.
;**************************************************************** ;* * ;* DXFUNC.ASM - Dos Extender Function Handlers * ;* * ;**************************************************************** ;* * ;* Module Description: * ;* * ;* This module contains the functions for handling the Dos * ;* Extender user functions. These are functions called by * ;* the client application to request special Dos Extender * ;* services. * ;* * ;* Any INT 2Fh requests that aren't Dos Extender functions * ;* are handled by switching to real mode and passing control * ;* on to the previous owner of the real mode INT 2Fh vector. * ;* This is accomplished by jumping into the interrupt * ;* reflector entry vector at the location for int 2fh. * ;* * ;**************************************************************** ;* Revision History: * ;* * ;* 01/09/91 amitc At switch out time Co-Processor being reset* ;* 11/29/90 amitc Replaced FnSuspend/FnResume by FnObsolete * ;* These are not needed anymore for 3.1 * ;* 11/29/90 amitc Modified RMInt2FHandler to respond to the * ;* BuildChain SWAPI call. * ;* 11/29/90 amitc Added a SWAPI CallIn function to be called * ;* by the task switcher. * ;* 11/16/90 jimmat Added DPMI MS-DOS Extension support * ;* 08/08/90 earleh Started changes to make DOSX a DPMI server * ;* 8/29/89 jimmat Added real mode Int 2Fh hook * ;* 6/23/89 jimmat Added DOSX Info Int 2Fh * ;* 6/16/89 jimmat Ifdef'd out most DOSX Int 2Fh services * ;* 6/15/89 jimmat Added suspend/resume Int 2Fh hooks, and * ;* Win/386 compatible Int 31h check * ;* 6/14/89 jimmat Removed PTRACE hooks & unused DynaLink code * ;* 5/19/89 jimmat Reduce # mode switches by ignoring Win/386 * ;* Int 2Fh/1680h idle calls * ;* 5/07/89 jimmat Added Int 2Fh protected mode hook to XMS * ;* driver * ;* 3/21/89 jimmat Corrected problem with jmping to wrong int * ;* 2Fh handler if not for the DOS extender * ;* 3/09/89 jimmat Added FNDynaLink function * ;* 02/10/89 (GeneA): change Dos Extender from small model to * ;* medium model * ;* 01/24/89 (GeneA): removed all real mode dos extender * ;* function handlers. * ;* 09/29/88 (GeneA): created * ; 18-Dec-1992 sudeepb Changed cli/sti to faster FCLI/FSTI ;* * ;****************************************************************
.286p .287
; ------------------------------------------------------- ; INCLUDE FILE DEFINITIONS ; -------------------------------------------------------
include segdefs.inc include gendefs.inc include pmdefs.inc include dosx.inc include hostdata.inc include intmac.inc include dpmi.inc include stackchk.inc include bop.inc
; ------------------------------------------------------- ; GENERAL SYMBOL DEFINITIONS ; -------------------------------------------------------
XMS_INS_CHK equ 00h ;Installition check function
WIN386_FUNC equ 16h ;Windows Enhanced mode Int 2Fh ID
WIN386_VER equ 00h ;Windows 386 version
WIN386_INIT equ 05h ;Windows/386 & DOSX startup call
W386_Get_Device_API equ 84h ;es:di -> device API
DPMI_DETECT equ 87h ;WIN386/DPMI detection call
DPMI_VER equ 005ah ;version 0.90 served here DPMI_SUCCESS equ 0000h ;zero to indicate success DPMI_FLAGS equ 0001h ;32 bit support ;DPMI client requesting 32-bit support
DPMI_MSDOS_VER equ 0100h ;WIN386/DPMI MS-DOS Extensions version 01.00
DPMI_MSDOS_API_GET_VER equ 0000h ;Get MS-DOS Extension version call DPMI_MSDOS_API_GET_LDT equ 0100h ;Get LDT Base selector call
; ------------------------------------------------------- ; EXTERNAL SYMBOL DEFINITIONS ; -------------------------------------------------------
extrn AllocateSelector:NEAR extrn FreeSelector:NEAR extrn ParaToLinear:NEAR externFP NSetSegmentDscr externNP NSetSegmentAccess extrn DupSegmentDscr:NEAR extrn XMScontrol:NEAR IFDEF WOW extrn Wow32IntrRefl:near ENDIF extrn HookNetBiosHwInt:NEAR
extrn AllocateExceptionStack:NEAR
DXSTACK segment
extrn rgw2FStack:WORD
DXSTACK ends
; ------------------------------------------------------- ; DATA SEGMENT DEFINITIONS ; -------------------------------------------------------
DXDATA segment
extrn selPSPChild:WORD extrn segPSPChild:WORD extrn idCpuType:WORD
extrn DtaSegment:WORD extrn DtaSelector:WORD extrn DtaOffset:WORD
IFDEF WOW extrn Wow16BitHandlers:WORD extrn selEHStack:WORD ENDIF IFDEF WOW_x86 extrn FastBop:FWORD ENDIF
; ; Count of DPMI clients active (that have entered protected mode). ;
public cDPMIClients cDPMIClients dw 0
public selCurrentHostData, segCurrentHostData, DpmiFlags, DpmiSegAttr selCurrentHostData dw 0 segCurrentHostData dw 0 DpmiSegAttr dw 0 DpmiFlags dw 0
DXDATA ends
; ------------------------------------------------------- ; CODE SEGMENT VARIABLES ; -------------------------------------------------------
DXCODE segment
extrn segDXData:WORD extrn PrevInt2FHandler:DWORD
DXCODE ends
DXPMCODE segment
extrn selDgroupPM:WORD
EXTRN MakeLowSegment:PROC
DXPMCODE ends
; -------------------------------------------------------
DXPMCODE segment assume cs:DXPMCODE
; WOW ; ------------------------------------------------------- ; ; Simulate VCD API's. DX contains function number. ; assume ds:NOTHING,es:NOTHING,ss:NOTHING public VCD_PM_Svc_Call
VCD_PM_Svc_Call: DPMIBOP VcdPmSvcCall32 retf
; ------------------------------------------------------- ; XMSfunc - The following routine provides a protected mode ; service for XMS Int 2Fh services. Two services are ; implemented: XMS driver installation check, and obtain ; XMS driver control function address. ; ; Input: UserAL - function request ; Output: UserAL - XMS driver installed flag, or ; UserES:BX - XMS driver control function address ; Errors: none ; Uses: all registers may be used
assume ds:DGROUP,es:NOTHING,ss:NOTHING public XMSfunc
XMSfunc proc near
cmp al,XMS_INS_CHK ;XMS driver installation check? jnz @f
mov byte ptr [bp].fnsUserAX,80h ;indicate driver is installed ret
@@:
; It must be an obtain XMS driver control function address request
mov [bp].fnsUserBX,offset DXPMCODE:XMScontrol mov [bp].fnsUserES,cs
ret
XMSfunc endp
; ------------------------------------------------------- subttl DPMI MS-DOS Extension API page ; ------------------------------------------------------- ; DPMI MS-DOS EXTENSION API ; ------------------------------------------------------- ; ; The following routine implements the DPMI MS-DOS Extensions ; API. This API must be 'detected' by the use of the ; DMPI_MSDOS_EXT Int 2F function (above).
public DPMI_MsDos_API DPMI_MsDos_API proc far
cmp ax, DPMI_MSDOS_API_GET_VER ;Get version call? jne DPMI_MsDos_API_Not_Ver
mov ax,DPMI_MSDOS_VER jmp short DPMI_MsDos_API_Exit
DPMI_MsDos_API_Not_Ver:
cmp ax, DPMI_MSDOS_API_GET_LDT ;Get LDT Base call? jne DPMI_MsDos_Api_Failed ifdef WOW_x86 mov ax,SEL_WOW_LDT or STD_RING ; yup, give it to 'em else mov ax,SEL_LDT_ALIAS or STD_RING ; yup, give it to 'em endif
DPMI_MsDos_API_Exit:
clc ;Succss ret
DPMI_MsDos_API_Failed:
stc ;Unsupported function ret
DPMI_MsDos_API endp
DXPMCODE ends
; -------------------------------------------------------
DXCODE segment assume cs:DXCODE ; ------------------------------------------------------- ; ; ------------------------------------------------------- ; ; DPMI_Client_Pmode_Entry -- This routine is the entry ; point for a DPMI client to switch to protected mode. ; Reference: DOS Protected Mode Interface Specification 0.9 ; Section 5.2: Calling the Real to Protected ; Mode Switch Entry Point ; ; Entry: AX = Flags ; Bit 0 = 1 if program is a 32-bit application ; ES = Real mode segment of DPMI host data area. This is the ; size of the data area we specified in RMInt2FHandler, ; below. ; ; Returns: ; Success: Carry clear. ; Program is in protected mode. ; CS = 16-bit selector with base of real mode ; CS and a 64k limit. ; SS = 16-bit selector with base of real mode ; SS and a 64k limit. ; DS = 16-bit selector with base of real mode ; DS and a 64k limit. ; ES = Selector to program's PSP with a 100h ; byte limit. ; 80386, 80486: ; FS, GS = 0 ; All other registers preserved. ; ; Failure: Carry flag set. ; Program is in real mode. ; ; Exceptions: ; 32-bit programs not (yet) supported. Any attempt to load ; a 32-bit program by this mechanism returns failure. ; ; The only error that can occur here is a failure to allocate ; sufficient selectors. ;
; ; Structure of the stack frame used to store the client's registers ; while implementing the DPMI protected mode entry. ;
DPMI_Client_Frame STRUC Client_ES dw ? ; Client's ES Client_DS dw ? ; Client's DS Client_DI dw ? ; Client's DI Client_SI dw ? ; Client's SI Client_Pusha_BP dw ? ; BP at pusha Client_Pusha_SP dw ? ; SP at pusha Client_BX dw ? ; Client's BX Client_DX dw ? ; Client's DX Client_CX dw ? ; Client's CX Client_AX dw ? ; Client's AX Client_Flags dw ? ; Client's flags Client_IP dw ? ; Client's IP, lsw of return Client_CS dw ? ; Client's CS, msw of return DPMI_Client_Frame ENDS
public DPMI_Client_Pmode_Entry DPMI_Client_Pmode_Entry proc far ; ; Reject any 32-bit program requests. ;
IFNDEF WOW test ax, DPMI_32BIT ; 32-bit application? stc ; yep, refuse to do it jz dcpe_flags_ok ; no, try to get into Pmode jmp dcpe_x dcpe_flags_ok: ENDIF
IFDEF WOW stc ENDIF pushf ;save client's flags (with carry set) pusha ;save caller's general registers push ds ;save caller's DS push es ;save caller's ES mov bp, sp ;create the stack frame dossvc 62h ;now get caller's PSP address mov di, bx ;and store it here for a while push es dossvc 2fh ;get caller's dta address
mov ax, segDXData ;get our DGROUP mov ds, ax ;point to it
mov DtaSegment,es mov DtaOffset,bx pop es
; ; For now, we only support one DPMI client application at a time. ; ;; cmp cDPMIClients,0 ;Any active? ;; je @F ;; jmp dcpe_return
@@: mov ax,[segCurrentHostData] mov es:[HdSegParent],ax ; save rm link mov ax,es mov [segCurrentHostData],ax mov ax,[bp].Client_AX ; get dpmi flags mov es:[HdFlags],ax ; save for future reference mov DpmiFlags,ax test ax,DPMI_32BIT jne cpe10
mov DpmiSegAttr,0 jmp cpe20
cpe10: mov DpmiSegAttr,AB_BIG
cpe20: mov si, ss ;SI = caller SS
mov ax, ds ;use a DOSX stack during the mode ;switch FCLI mov ss, ax mov sp, offset DGROUP:rgw2FStack
SwitchToProtectedMode
mov ax, si ;make a selector for client's stack mov bx, STD_DATA or bx, DpmiSegAttr call MakeLowSegment jnc got_client_stack_selector jmp dcpe_error_exit ;back out if error got_client_stack_selector:
or al,STD_TBL_RING
mov ss, ax ;back to client's stack .386p movzx esp,bp .286p
; push [bp.Client_Flags] ;enable interupts if client had ; npopf ;them enabled
; ; After DOSX enters protected mode, convert the caller's segment registers ; to PMODE selectors, replacing the values in the client's register image ; on the stack. First, allocate the three or four selectors we will need. ; xor ax,ax ;an invalid selector push ax ;marker
mov cx,4 ;CS, PSP, Environ, Host data cmp si,[bp.Client_DS] ;Client SS == Client DS ? je dcpe_allocate_loop inc cx dcpe_allocate_loop: call AllocateSelector jnc @F jmp dcpe_pfail @@: or al,STD_TBL_RING push ax loop dcpe_allocate_loop
mov dx,[bp.Client_CS] ;get client CS paragraph call ParaToLinear ;convert to linear address in BX:DX mov cx,0ffffh ;limit = 64k pop ax ;get one of the selectors allocated mov [bp.Client_CS],ax ;save value for client cCall NSetSegmentDscr,<ax,bx,dx,0,cx,STD_CODE>
mov dx, [bp.Client_DS] mov [bp.Client_DS],ss ;DS = SS for now cmp dx, si ;need separate DS selector? je dcpe_do_child_PSP
call ParaToLinear ;convert to linear address in BL:DX mov cx,0ffffh ;limit = 64k pop ax ;get another selector mov [bp.Client_DS],ax ;save value for client push di mov di,STD_DATA or di,DpmiSegAttr cCall NSetSegmentDscr,<ax,bx,dx,0,cx,di> pop di
dcpe_do_child_PSP: mov dx,[bp.Client_ES] ; get HostData selector call ParaToLinear mov cx,HOST_DATA_SIZE ; limit = size of HostData pop ax ; get another selector push [selCurrentHostData] mov [selCurrentHostData],ax ; save for us cCall NSetSegmentDscr,<ax,bx,dx,0,cx,STD_DATA> mov es,ax pop ax mov es:[HdSelParent],ax mov ax,SelPSPChild mov es:[HdPSPParent],ax
mov dx, di ;get client PSP paragraph mov segPSPChild, di call ParaToLinear ;convert to linear address in BL:DX mov cx,100h ;limit = 100h pop ax ;get another selector mov [bp.Client_ES],ax ;save value for client mov selPSPChild, ax ;save a copy for DOSX cCall NSetSegmentDscr,<ax,bx,dx,0,cx,STD_DATA>
mov es:[HdSelPSP],ax mov es,ax ;point to client's PSP mov dx,es:segEnviron ;fetch client's environment pointer call ParaToLinear ;convert to linear address in BL:DX mov cx,0ffffh ;limit = 32k pop ax ;get another selector mov es:segEnviron,ax ;save client's environment selector cCall NSetSegmentDscr,<ax,bx,dx,0,cx,STD_DATA>
; We need to set up the DTA selector mov dx,DtaSegment cmp dx,segPSPChild jne dcpe_50
mov dx,selPSPChild mov DtaSelector,dx jmp dcpe_60
dcpe_50: mov cx,1 call AllocateSelector jnc @f
jmp dcpe_free_client_stack
@@: or al,STD_TBL_RING mov DtaSelector,ax call ParaToLinear cCall NSetSegmentDscr,<ax,bx,dx,0,0ffffh,STD_DATA>
dcpe_60:
inc cDPMIClients ;increment count of Pmode clients cmp cDPMIClients, 1 ; first client? jne @f ; already taken care of
call AllocateExceptionStack
call DpmiStackSizeInit call DpmiSizeInit FBOP BOP_DPMI,DpmiInUse,FastBop ; @@: ; ; Everything OK. Clear error flag, and return to caller. ; not byte ptr [bp.Client_Flags] ;reverse status flags, clearing carry
; Let 32 bit code know if this is a 32 or 16 bit application mov ax,DpmiFlags push selPSPChild push DtaSelector push DtaOffset FBOP BOP_DPMI,InitApp,FastBop add sp,4
cmp cDPMIClients, 1 ; first client? jne @f ; already taken care of ; Note: We have to do InitApp before we try to hook the netbios ; interrupt. If we don't, we will fault in the dos extender. ; (HookNetBiosHwInt calls int 21, enabling interrupts) call HookNetBiosHwInt @@:
; jmp far ptr dcpe_return ;avoid need for fix ups db 0EAh dw offset DXCODE:dcpe_return dw SEL_DXCODE OR STD_RING ; ; If we get here, it means DOSX failed to allocate enough selectors for the ; client. Deallocate those which have been allocated, switch back to ; real mode, and return an error to the caller. Selectors to deallocate ; are on the stack, pushed after a zero word. Then switch to a DOSX stack, ; deallocate the client stack selector, and switch to real mode. ; dcpe_pfail: pop ax ;any selectors allocated? or ax,ax ; (we pushed a zero before allocating) jz dcpe_free_client_stack ;done call FreeSelector ;free the selector jnc dcpe_pfail ;free any more dcpe_free_client_stack: mov di, ss ;make copy of client stack selector mov ax, ds ;have to be on a DOSX stack to do this FCLI mov ss, ax mov sp, offset DGROUP:rgw2FStack mov ax, di ;free client stack selector call FreeSelector dcpe_error_exit: ; ; Error exit from protected mode. Any allocated selectors have already ; been freed. Switch to real mode, restore client stack, pop off client's ; registers, return with the carry flag set. ; SwitchToRealMode mov ss, si ;restore client stack
errnz <dcpe_return-$>
dcpe_return: ; The next line must restore the stack.
mov sp, bp
jc dcpe_return_1 ; error return ; ; Pop the client's registers off the stack frame, switch back to the ; client's stack, and return. ; dcpe_return_1: pop es ;pop copy of PSP selector/segment pop ds ;pop client DS selector/segment popa ;pop client's general registers npopf ;restore interrupt flag, return status dcpe_x: retf ;and out of here DPMI_Client_Pmode_Entry endp
; ------------------------------------------------------- ; REAL MODE FUNCTION HANDLER ; ------------------------------------------------------- ; ; RMInt2FHandler -- This routine hooks the real mode Int 2Fh chain ; and watches for 'interesting' Int 2Fh calls. ; ; WIN386/DOSX startup broadcast ; DPMI server detection ; Switcher API functions ; assume ds:NOTHING,es:NOTHING,ss:NOTHING public RMInt2FHandler
RMInt2FHandler proc near
cmp ah,WIN386_FUNC ;WIN386/DOSX/DPMI call? jz rm2f_0
rm2f_chain: jmp [PrevInt2FHandler] ;no, just chain it on...
rm2f_0:
if 0 ; don't claim to be win 3.1 in enhanced mode cmp al,WIN386_INIT ;WIN386/DOSX startup attempt? jnz rm2f_1 ;no mov cx,-1 ;yes, don't let'm load jmp rm2f_x endif cmp al,W386_Get_Device_API ;not supported jne rm2f_1
xor di,di mov es,di jmp rm2f_x
rm2f_1: cmp al,DPMI_DETECT ;DPMI detection? jnz rm2f_2 ;no
mov ax,DPMI_SUCCESS ;yes, return Pmode switch entry mov bx,DPMI_FLAGS ;flags
push segDXData pop es assume es:DXDATA mov cl,byte ptr es:[idCpuType] ;CPU type assume es:nothing
mov dx,DPMI_VER ;DPMI server version mov si,(HOST_DATA_SIZE + 15) / 16 push cs ;entry point is in this segment pop es ;prospective client wants lea di,DPMI_Client_Pmode_Entry ;switch entry point in ES:DI jmp rm2f_x ;done rm2f_2: if 0 ; don't claim to be windows cmp al,WIN386_VER ;Windows 386 version check? jnz rm2f_chain ;no, chain the interrupt
mov ax, 0a03h else jmp rm2f_chain endif rm2f_x: iret
RMInt2FHandler endp
;--------------------------------------------------------------------------------
DXCODE ends
IFDEF WOW DXPMCODE segment assume cs:DXPMCODE
;---------------------------------------------------------------------- ; ; DpmiSizeInit -- This routine insures that the appropriately sized ; interrupt handlers will be called ; ; Inputs: None ; Outputs: None ; public DpmiSizeInit assume ds:dgroup,es:nothing,ss:nothing DpmiSizeInit proc
push ax push bx push cx push si push di push es rpushf FCLI test DpmiFlags,DPMI_32BIT jnz dsi20
cCall NSetSegmentAccess,<selDgroupPM,STD_DATA> cCall NSetSegmentAccess,<selEHStack,STD_DATA>
jmp dsi90 dsi20: ; ; Copy 16 bit handler addresses ; .386p lea di,Wow16BitHandlers
mov ax,ds mov es,ax assume es:DGROUP
push ds mov ax,SEL_IDT OR STD_RING mov ds,ax assume ds:nothing
mov si,0 mov cx,256 dsi40: movsd add si,4 loop dsi40 pop ds ; ; Put 32 bit handlers into IDT ;
mov ax,SEL_IDT OR STD_RING mov es,ax
mov es:[1h*8].offDest,offset DXPMCODE:Wow32IntrRefl+1h*6 mov es:[3h*8].offDest,offset DXPMCODE:Wow32IntrRefl+3h*6 mov es:[10h*8].offDest,offset DXPMCODE:Wow32IntrRefl+10h*6 mov es:[13h*8].offDest,offset DXPMCODE:Wow32IntrRefl+13h*6 mov es:[15h*8].offDest,offset DXPMCODE:Wow32IntrRefl+15h*6 mov es:[19h*8].offDest,offset DXPMCODE:Wow32IntrRefl+19h*6
mov es:[21h*8].offDest,offset DXPMCODE:Wow32IntrRefl+21h*6 mov es:[25h*8].offDest,offset DXPMCODE:Wow32IntrRefl+25h*6 mov es:[26h*8].offDest,offset DXPMCODE:Wow32IntrRefl+26h*6 mov es:[28h*8].offDest,offset DXPMCODE:Wow32IntrRefl+28h*6 mov es:[30h*8].offDest,offset DXPMCODE:Wow32IntrRefl+30h*6 mov es:[33h*8].offDest,offset DXPMCODE:Wow32IntrRefl+33h*6 mov es:[41h*8].offDest,offset DXPMCODE:Wow32IntrRefl+41h*6
; ; Set up the IDT, and dpmi32 state ; mov ax,es ; Idt selector mov bx,VDM_INT_32 DPMIBOP InitIDT
assume ds:DGROUP
dsi90: rpopf pop es pop di pop si pop cx pop bx pop ax ret DpmiSizeInit endp
assume ds:DGROUP, es:NOTHING, ss:NOTHING DpmiStackSizeInit proc
push ax test DpmiFlags,DPMI_32BIT jz @f ; ; Make the dgroup selector 32 bit ; ; NOTE: The following equ is only necessary to get the cmacro package ; to pass the correct value to NSetSegmentAccess
NEW_DX_DATA equ STD_DATA OR AB_BIG cCall NSetSegmentAccess,<selDgroupPM,NEW_DX_DATA> cCall NSetSegmentAccess,<selEHStack,NEW_DX_DATA> .286p
@@: pop ax ret
DpmiStackSizeInit endp
DXPMCODE ends ENDIF ; ;****************************************************************
end
|