windows-nt/Source/XPSP1/NT/base/mvdm/dpmi/dxfunc.asm

822 lines
26 KiB
NASM
Raw Permalink Normal View History

2020-09-26 03:20:57 -05:00
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