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, 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, 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, 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, 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, ; 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, 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: ; 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, cCall NSetSegmentAccess, 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, cCall NSetSegmentAccess, .286p @@: pop ax ret DpmiStackSizeInit endp DXPMCODE ends ENDIF ; ;**************************************************************** end