summaryrefslogtreecommitdiffstats
path: root/private/mvdm/dpmi/dxint31.asm
diff options
context:
space:
mode:
Diffstat (limited to 'private/mvdm/dpmi/dxint31.asm')
-rw-r--r--private/mvdm/dpmi/dxint31.asm3183
1 files changed, 3183 insertions, 0 deletions
diff --git a/private/mvdm/dpmi/dxint31.asm b/private/mvdm/dpmi/dxint31.asm
new file mode 100644
index 000000000..3b3c43276
--- /dev/null
+++ b/private/mvdm/dpmi/dxint31.asm
@@ -0,0 +1,3183 @@
+ PAGE ,132
+ TITLE DXINT31.ASM -- Dos Extender Int 31h Handler
+
+; Copyright (c) Microsoft Corporation 1989-1991. All Rights Reserved.
+
+;***********************************************************************
+;
+; DXINT31.ASM -- DOS Extender Int 31h Handler
+;
+;-----------------------------------------------------------------------
+;
+; This module provides the Int 31h services to the protected mode
+; application running under the DOS Extender.
+;
+;-----------------------------------------------------------------------
+;
+; 12/03/90 amitc 'i31_GetSetRMInt' will map vectors in the range 50-57h
+; to the range 8-fh if 'Win30CommDriver' switch is set in
+; system.ini
+; 12/18/89 jimmat Service 0003 changed from Get LDT Base to Get Sel Incr,
+; and added Virtual Interrupt State services.
+; 09/18/89 jimmat Added Allocate/Free Real Mode Call-Back services
+; 08/20/89 jimmat Changed A20 diddling to use XMS local enable/disable
+; 06/14/89 jimmat Added a few missing and new services.
+; 05/17/89 jimmat Added protected to real mode call/int services.
+; 05/12/89 jimmat Original version (split out from DXINTR.ASM)
+; 18-Dec-1992 sudeepb Changed cli/sti to faster FCLI/FSTI
+;
+;***********************************************************************
+
+ .286p
+
+; -------------------------------------------------------
+; INCLUDE FILE DEFINITIONS
+; -------------------------------------------------------
+
+ .xlist
+ .sall
+include segdefs.inc
+include gendefs.inc
+include pmdefs.inc
+include interupt.inc
+include int31.inc
+include dpmi.inc
+
+ Int_Get_PMode_Vec EQU 04h
+ Int_Set_PMode_Vec EQU 05h
+
+IFDEF ROM
+include dxrom.inc
+ENDIF
+include intmac.inc
+IFDEF XMEMNT
+include dpmi.inc
+ENDIF
+include stackchk.inc
+ .list
+
+; -------------------------------------------------------
+; GENERAL SYMBOL DEFINITIONS
+; -------------------------------------------------------
+
+RealMode_SaveBP equ word ptr RealMode_EBP+4
+RealMode_SaveSP equ word ptr RealMode_EBP+6
+
+cRM_CALL_BACK equ 16 ;Count of Real Mode Call-Backs supported
+ ;DPMI 0.90 spec says 16 required.
+IFNDEF WOW
+CallBackTableStruc struc ;Structure of Real Mode Call-Back Table
+fInUse db 0 ;use/free flag
+PM_CS_IP dd ? ;pMode CS:IP to call
+PM_Client_Frame dd ? ;Client Register Frame
+CallBackTableStruc ends
+ELSE
+CallBackTableStruc struc ;Structure of Real Mode Call-Back Table
+fInUse db 0 ;use/free flag
+PM_CS_IP dd ? ;pMode EIP to call
+ dw ? ;pMode CS to call
+PM_Client_Frame dd ? ;Client Register Frame
+ dw ? ; segment of above
+CallBackTableStruc ends
+ENDIF
+
+SelectorIncrement equ 8 ;DOSX increments consecutive selectors by 8
+
+Trans_Reset_HW equ 01h ;Reset PIC/A20 line on PM->Call services
+
+I31VERSION equ 0090d ;Int 31 services major/minor version #'s
+ ; version 00.90 (not quite ready for DPMI)
+IFNDEF WOW
+I31FLAGS equ 000Ah ;Running under 286 Extender & pMode NetBIOS
+ELSE
+I31FLAGS equ 000Dh ; 386 extender, pMode NetBIOS
+ENDIF
+I31MasterPIC equ 08h ;Master PIC Interrupts start at 08h
+I31SlavePIC equ 70h ;Slave PIC Interrupts start at 70h
+
+; -------------------------------------------------------
+; EXTERNAL SYMBOL DEFINITIONS
+; -------------------------------------------------------
+
+ extrn EnterIntHandler:NEAR
+ extrn LeaveIntHandler:NEAR
+ extrn EnterRealMode:NEAR
+ extrn EnterProtectedMode:NEAR
+ extrn GetSegmentAddress:NEAR
+ extrn SetSegmentAddress:NEAR
+ extrn FreeSelector:NEAR
+ extrn FreeSelectorBlock:NEAR
+ extrn AllocateSelector:NEAR
+ extrn AllocateSelectorBlock:NEAR
+ extrn ParaToLDTSelector:NEAR
+ extrn DupSegmentDscr:NEAR
+ extrn GetFaultVector:NEAR
+ extrn PutFaultVector:NEAR
+ extrn AllocateXmemBlock:NEAR
+ extrn FreeXmemBlock:NEAR
+ extrn ModifyXmemBlock:NEAR
+ extrn FreeLowBlock:NEAR
+ extrn AllocateLowBlock:NEAR
+ extrn AllocateLDTSelector:NEAR
+ extrn ParaToLinear:NEAR
+ extrn GetIntrVector:NEAR, PutIntrVector:NEAR
+ifdef WOW
+ extrn NSetSegmentLimit:near
+ extrn NMoveDescriptor:near
+ extrn NWOWSetDescriptor:near
+endif
+ extrn RMIntrEntryVector:near
+ extrn EndRMIntrEntry:near
+ extrn DFSetIntrVector:near
+ extrn RmSaveRestoreState:far
+ extrn PmSaveRestoreState:far
+ extrn RmRawModeSwitch:far
+ extrn PmRawModeSwitch:far
+ extrn IsSelectorFree:near
+ extrn gtpara:near
+
+externNP NSetSegmentAccess
+externFP NSetSegmentDscr
+externNP FreeSpace
+
+; -------------------------------------------------------
+; DATA SEGMENT DEFINITIONS
+; -------------------------------------------------------
+
+DXDATA segment
+
+ extrn selGDT:WORD
+ extrn segPSP:WORD
+ extrn idCpuType:WORD
+ extrn npXfrBuf1:WORD
+ extrn rgbXfrBuf1:BYTE
+ extrn pbReflStack:WORD
+ extrn bReflStack:WORD
+ extrn rglpfnRmISR:DWORD
+ extrn lpfnXMSFunc:DWORD
+ extrn A20EnableCount:WORD
+ extrn regUserAX:WORD, regUserFL:WORD, regUserSS:WORD
+ extrn regUserSP:WORD, regUserDS:WORD, regUserES:WORD
+ extrn fWin30CommDrv:WORD
+ extrn PMInt24Handler:DWORD
+IFDEF WOW
+ extrn DpmiFlags:WORD
+ extrn FastBop:fword
+ENDIF
+
+ extrn selPspChild:WORD
+ extrn RmHwIsr:DWORD
+ extrn LowMemAllocFn:DWORD
+ extrn LowMemFreeFn:DWORD
+
+ public i31HWReset
+
+i31HWReset db 0 ;NZ if in 'standard' real mode state
+
+i31_dsp_rtn dw 0 ;Int 31h service routine to dispatch
+
+ifdef DEBUG
+debugsavess dw 0 ; Usefull when debugging WOW KERNEL
+debugsavesp dw 0 ;
+debugsavebp dw 0 ;
+debugsavecx dw 0 ;
+endif
+
+ public i31_selectorbitmap
+i31_selectorbitmap dw 0000000000000000b
+ ;Reserved LDT Selectors
+
+CallBackTable label byte ;Real Mode Call-Back Table
+ rept cRM_CALL_BACK
+ CallBackTableStruc <>
+ endm
+
+DXDATA ends
+
+; -------------------------------------------------------
+; CODE SEGMENT VARIABLES
+; -------------------------------------------------------
+
+DXCODE segment
+ assume cs:DXCODE
+
+IFNDEF ROM
+ extrn segDXData:WORD
+ extrn selDgroup:WORD
+ENDIF
+
+ extrn segDXCode:word
+
+RMCallBackEntryVector label near ;Real Mode Call-Back Entry Points
+ rept cRM_CALL_BACK
+ call RMCallBackHook
+ endm
+
+ assume cs:NOTHING
+
+DXCODE ends
+
+DXPMCODE segment
+
+ extrn selDgroupPM:WORD
+ extrn segDXCodePM:WORD
+
+i31_dispatch label word
+
+ dw 0000h, offset i31_AllocSel
+ dw 0001h, offset i31_FreeSel
+ dw 0002h, offset i31_MapSeg2Sel
+ dw 0003h, offset i31_GetSelIncr
+ dw 0004h, offset i31_Success ;lock selector memory
+ dw 0005h, offset i31_Success ;unlock selector mem
+ dw 0006h, offset i31_GetSegAddr
+ dw 0007h, offset i31_SetSegAddr
+ dw 0008h, offset i31_SetLimit
+ dw 0009h, offset i31_SetAccess
+ dw 000Ah, offset i31_CreateDataAlias
+ dw 000Bh, offset i31_GetSetDescriptor
+ dw 000Ch, offset i31_GetSetDescriptor
+ dw 000Dh, offset i31_SpecificSel ; Allocate specific descriptor
+ dw 0100h, offset i31_AllocDOSMem
+ dw 0101h, offset i31_FreeDOSMem
+ dw 0102h, offset i31_SizeDOSMem
+
+ dw 0200h, offset i31_GetSetRMInt
+ dw 0201h, offset i31_GetSetRMInt
+ dw 0202h, offset i31_GetSetFaultVector
+ dw 0203h, offset i31_GetSetFaultVector
+ dw 0204h, offset i31_GetSetPMInt
+ dw 0205h, offset i31_GetSetPMInt
+ dw 0300h, offset i31_RMCall
+ dw 0301h, offset i31_RMCall
+ dw 0302h, offset i31_RMCall
+ dw 0303h, offset i31_AllocCallBack
+ dw 0304h, offset i31_FreeCallBack
+ dw 0305h, offset i31_GetStateSaveRestore
+ dw 0306h, offset i31_GetRawModeSwitch
+ dw 0400h, offset i31_Version
+
+ dw 04f1h, offset i31_WOW_AllocSel
+ dw 04f2h, offset i31_WOW_SetDescriptor
+ dw 04f3h, offset i31_WOW_SetAllocFunctions
+
+;
+; INCOMPLETE !!!!!!!!!!!
+; Needed by kernel.
+;
+ dw 0500h, offset i31_GetFreeMem
+ dw 0501h, offset i31_AllocMem
+ dw 0502h, offset i31_FreeMem
+;
+; Fails by design if block is to be extended and this cannot be done
+; in place.
+;
+ dw 0503h, offset i31_SizeMem
+
+ dw 0600h, offset i31_Success ;lock linear region
+ dw 0601h, offset i31_Success ;unlock linear region
+ dw 0602h, offset i31_Success ;mark real mode rgn pageable
+ dw 0603h, offset i31_Success ;relock real mode region
+ dw 0604h, offset i31_PageSize ;get page size
+
+ dw 0700h, offset i31_fail ;reserved
+ dw 0701h, offset i31_fail ;reserved
+ dw 0702h, offset i31_Success ;demand page candidate
+ dw 0703h, offset i31_Success ;discard page contents
+
+ dw 0800h, offset i31_fail ;physical addr mapping
+
+ dw 0900h, offset i31_VirtualInt ;get & disable Int state
+ dw 0901h, offset i31_VirtualInt ;get & enable Int state
+ dw 0902h, offset i31_VirtualInt ;get Int state
+;
+; UNIMPLEMENTED !!!!!!!!!!!
+; To be used for MSDOS protected mode API?
+;
+ dw 0A00h, offset i31_unimplemented ;get vendor specific API
+
+IFDEF WOW
+ NO386 = 0
+else
+ NO386 = 1
+ENDIF
+ife NO386
+;
+; 386 Debug Register access routines.
+;
+ dw 0B00h, offset i31_Debug_Register_Access
+ ;set debug watchpoint
+ dw 0B01h, offset i31_Debug_Register_Access
+ ;clear debug watchpoint
+ dw 0B02h, offset i31_Debug_Register_Access
+ ;get debug watchpoint state
+ dw 0B03h, offset i31_Debug_Register_Access
+ ;reset debug watchpoint
+endif ; NO386
+
+ dw -1, offset i31_unimplemented
+
+
+DXPMCODE ends
+
+; -------------------------------------------------------
+ subttl INT 31h Entry Point
+ page
+; -------------------------------------------------------
+; INT 31h SERVICE ENTRY POINT
+; -------------------------------------------------------
+
+DXPMCODE segment
+ assume cs:DXPMCODE
+
+; -------------------------------------------------------
+; PMIntr31 -- Service routine for the Protect Mode INT 31h
+; services. These functions duplicate the
+; Windows/386 VMM INT 31h services for protected
+; mode applications. They were implemented to
+; support a protect mode version of Windows/286.
+;
+; Input: Various registers
+; Output: Various registers
+; Errors:
+; Uses: All registers preserved, other than return values
+
+ assume ds:NOTHING,es:NOTHING,ss:NOTHING
+ public PMIntr31
+
+PMIntr31 proc near
+
+ cld ;practice 'safe programming'
+
+; Determine if this one of the services we support.
+
+ push bx
+ mov bx,offset i31_dispatch ;cs:bx -> dispatch table
+
+@@:
+ cmp ax,cs:[bx] ;scan dispatch table for
+ jz i31_do_it ; service code in AH/AL
+
+ cmp word ptr cs:[bx],-1 ;end of table is -1
+ jz i31_do_it
+
+ add bx,4
+ jmp short @b
+
+; BX contains the offset of the routine to service this request!
+
+i31_do_it:
+ push ds ;save the service routine address
+ mov ds,selDgroupPM ; in our DGROUP for now
+ assume ds:DGROUP
+
+ mov bx,cs:[bx+2]
+ FCLI ;needed for [i31_dsp_rtn]
+ mov i31_dsp_rtn,bx
+
+ifdef DEBUG
+ mov debugsavess,ss ; usefule when debugging WOW kernel
+ mov debugsavesp,sp
+ mov debugsavebp,bp
+ mov debugsavecx,cx
+endif
+
+ pop ds
+ pop bx
+
+i31_doit:
+ call EnterIntHandler ;build an interrupt stack frame
+ assume ds:DGROUP,es:DGROUP ; also sets up addressability
+
+ push i31_dsp_rtn ;routine address on stack
+
+ DEBUG_TRACE DBGTR_ENTRY, 31h, ax, 0
+
+ FSTI ;no need to keep interrupts disabled
+
+ retn ;go perform the service
+
+i31_unimplemented: ;not implemented or undefined
+
+ Debug_Out "Unsupported Int 31h requested (AX = #AX)"
+
+; Int 31h service routines return (jmp) here to indicate failure. The
+; standard failure return sets the carry flag, and sets ax = 0.
+
+i31_fail:
+
+ mov [bp].intUserAX,0
+
+i31_fail_CY:
+
+ or byte ptr [bp].intUserFL,1
+ jmp short i31_exit
+
+; Int 31h service routines return (jmp) here -- they jump back instead
+; of returning because they expect the stack to be setup by EnterIntHandler,
+; no extra items should be pushed.
+
+i31_done:
+
+ and byte ptr [bp].intUserFL,not 1 ;clear carry flag
+
+i31_exit:
+ assume ds:NOTHING,es:NOTHING
+
+ FCLI ;LeaveIntHandler needs them off
+ call LeaveIntHandler ;restore caller's registers, and
+ DEBUG_TRACE DBGTR_EXIT, 31h, 0, 0
+ riret ; get on down the road
+
+PMIntr31 endp
+
+
+; -------------------------------------------------------
+; This routine is for Int 31h services that the 286 DOS extender
+; allows, but doesn't actually perform any work. Most of these
+; services are related to demand paging under Windows/386.
+
+ assume ds:DGROUP,es:DGROUP
+ public i31_Success
+
+i31_Success proc near
+
+ jmp i31_done ;nothing to do currently
+
+i31_Success endp
+
+; -------------------------------------------------------
+; Page Size. Gotta be 1000h, even if we don't do anything
+; with it.
+;
+
+ assume ds:DGROUP,es:DGROUP
+ public i31_PageSize
+
+i31_PageSize proc near
+
+ mov [bp].intUserBX,0
+ mov [bp].intUserCX,1000h
+ jmp i31_done ;nothing to do currently
+
+i31_pageSize endp
+
+; -------------------------------------------------------
+ subttl INT 31h LDT/Heap Services
+ page
+; -------------------------------------------------------
+; LDT/HEAP INTERRUPT (INT 31h) SERVICE ROUTINES
+; -------------------------------------------------------
+
+; -------------------------------------------------------
+; Service 00/00 - Allocate Space in LDT for Selector
+; in: cx - # selectors required
+; out: ax - *index* of first selector
+
+ assume ds:DGROUP,es:DGROUP
+ public i31_AllocSel
+
+i31_AllocSel proc near
+
+ jcxz short i31_15
+ cmp cx,1 ;1 selector or more?
+ ja @f
+
+ call AllocateSelector ;allocate 1 selector
+ jc i31_15
+ jmp short i31_10
+
+@@: mov ax,cx
+ call AllocateSelectorBlock ;allocate a block of selectors
+ jc i31_15
+
+i31_10:
+ or al,STD_TBL_RING ;add standard table/ring bits
+ mov [bp].intUserAX,ax ;return 1st/only selector in AX
+
+setsel: mov bx,STD_DATA ;all the selectors we allocate
+; xor bl,bl ; get initialized to data/ring ?
+ xor dx,dx ; 0 base, 0 limit
+@@:
+ cCall NSetSegmentDscr,<ax,dx,dx,dx,dx,bx>
+ add ax,SelectorIncrement
+ loop @b
+
+ jmp i31_done
+
+i31_15:
+ jmp i31_fail ;fail the request
+
+i31_AllocSel endp
+
+
+; -------------------------------------------------------
+; Service 00/01 - Free LDT Selector
+; in: bx - selector to free
+; out: none
+
+ assume ds:DGROUP,es:DGROUP
+ public i31_FreeSel
+
+i31_FreeSel proc near
+
+ mov ax,bx ;release the selector
+ cmp ax,SEL_DPMI_LAST ; reserved selector?
+ ja i31_Free_Regular_LDT_Selector ; No.
+ mov cx,ax
+ shr cl,3 ; Selector to selector index in LDT
+ mov ax,1
+ shl ax,cl ; AX = bit in i31_selectorbitmap
+ test i31_selectorbitmap,ax ; test for already allocated
+ jz i31_FreeSel_Fail ; already free!
+ not ax
+ and i31_selectorbitmap,ax ; mark as free
+ jmp i31_done
+
+i31_Free_Regular_LDT_Selector:
+
+ and ax,SELECTOR_INDEX ; only pass it the index
+ or ax,SELECTOR_TI ;only allow LDT selectors
+ jz i31_Check_DS_ES
+ call FreeSelector
+ jnc i31_Check_DS_ES
+i31_FreeSel_Fail:
+ jmp i31_fail_CY
+
+i31_Check_DS_ES:
+
+ ; check in case user frees the selector in DS or ES - we
+ ; don't want to fault when popping his regs
+
+ and bl,NOT SELECTOR_RPL ;compare without ring bits
+
+ mov ax,[bp].pmUserDS
+ and al,NOT SELECTOR_RPL
+ cmp ax,bx
+ jnz @f
+
+ mov [bp].pmUserDS,0
+
+@@: mov ax,[bp].pmUserES
+ and al,NOT SELECTOR_RPL
+ cmp ax,bx
+ jnz @f
+
+ mov [bp].pmUserES,0
+@@:
+ jmp i31_done
+
+i31_FreeSel endp
+
+
+; -------------------------------------------------------
+; Service 00/02 - Map Segment to Selector
+; in: bx - real mode segment value
+; out: ax - selector which maps area
+
+ assume ds:DGROUP,es:DGROUP
+ public i31_MapSeg2Sel
+
+i31_MapSeg2Sel proc near
+
+ mov ax,bx ;find/make selector for real memory
+ mov bx,STD_DATA ;assume it's a data selector
+ call ParaToLDTSelector
+ jnc @f
+
+ jmp i31_fail_CY ;Falied!?
+@@:
+ mov [bp].intUserAX,ax
+ jmp i31_done
+
+i31_MapSeg2Sel endp
+
+
+; -------------------------------------------------------
+; Service 00/03 - Get Next Selector Increment Value
+; in: none
+; out: ax - Next Selector Increment Value
+
+ assume ds:DGROUP,es:DGROUP
+ public i31_GetSelIncr
+
+i31_GetSelIncr proc near
+
+ mov [bp].intUserAX,SelectorIncrement ;DOSX incr value
+ jmp i31_done
+
+i31_GetSelIncr endp
+
+
+; -------------------------------------------------------
+; Service 00/06 - Get Segment Base address.
+; in: bx - selector
+; out: cx:dx - 32 bit lma of segment
+
+ assume ds:DGROUP,es:DGROUP
+ public i31_GetSegAddr
+
+i31_GetSegAddr proc near
+
+ mov ax,selGDT
+ assume es:nothing
+ lsl ax,ax
+
+ push bx
+ and bx,SELECTOR_INDEX
+
+ cmp bx,ax
+ jnc gsa10 ; not in ldt
+
+ call IsSelectorFree
+ jc gsa20
+
+gsa10: pop bx
+ jmp i31_fail_CY
+
+gsa20: pop bx
+
+ mov ax,bx
+ call GetSegmentAddress
+
+ mov [bp].intUserCX,bx
+ mov [bp].intUserDX,dx
+
+ jmp i31_done
+
+i31_GetSegAddr endp
+
+
+; -------------------------------------------------------
+; Service 00/07 - Set Segment Base address.
+; in: bx - selector
+; cx:dx - 32 bit lma of segment
+; out: none
+
+ assume ds:DGROUP,es:DGROUP
+ public i31_SetSegAddr
+
+i31_SetSegAddr proc near
+
+ mov ax,selGDT
+ assume es:nothing
+ lsl ax,ax
+
+ push bx
+ and bx,SELECTOR_INDEX
+
+ cmp bx,ax
+ jnc ssa10 ; not in ldt
+
+ call IsSelectorFree
+ jc ssa20
+
+ssa10: pop bx
+ jmp i31_fail_CY
+
+ssa20: pop bx
+ mov ax,bx
+ mov bx,cx
+ call SetSegmentAddress
+
+ jmp i31_done
+
+i31_SetSegAddr endp
+
+
+; -------------------------------------------------------
+; Service 00/08 - Set Segment Limit.
+; in: bx - selector
+; cx:dx - 32 bit limit of segment
+; out: none
+
+ assume ds:DGROUP,es:DGROUP
+ public i31_SetLimit
+
+i31_SetLimit proc near
+
+ mov ax,selGDT
+ assume es:nothing
+ lsl ax,ax
+
+ push bx
+ and bx,SELECTOR_INDEX
+
+ cmp bx,ax
+ jnc sl10 ; not in ldt
+
+ call IsSelectorFree
+ jc sl20
+
+sl10: pop bx
+ jmp i31_fail_CY
+
+sl20: pop bx
+ mov es,selGDT
+ and bx,SELECTOR_INDEX
+ and es:[bx].cbLimitHi386,070h ; clear 'G' bit and old
+ ; extended limit bits
+ test cx,0fff0h ; bits 20-31 set?
+ jz i31_SetLimit_0 ; No
+ shr dx,12d ; Yes
+ mov ax,cx
+ shl ax,4d
+ or dx,ax
+ shr cx,12d
+ or es:[bx].cbLimitHi386,080h ; set 'G' bit
+i31_SetLimit_0:
+ mov es:[bx].cbLimit,dx
+ or es:[bx].cbLimitHi386,cl
+ifdef WOW
+ cCall NSetSegmentLimit,<bx>
+endif ; WOW
+ jmp i31_done
+
+i31_SetLimit endp
+
+
+; -------------------------------------------------------
+; Service 00/09 - Set Segment Access Rights
+; in: bx - selector
+; cl - segment access rights byte
+
+ assume ds:DGROUP,es:DGROUP
+ public i31_SetAccess
+
+i31_SetAccess proc near
+
+ mov ax,selGDT
+ assume es:nothing
+ lsl ax,ax
+
+ push bx
+ and bx,SELECTOR_INDEX
+
+ cmp bx,ax
+ jnc sa10 ; not in ldt
+
+ call IsSelectorFree
+ jc sa20
+
+sa10: pop bx
+sa11:
+ jmp i31_fail_CY
+
+sa20: pop bx
+
+ test cl,010000b ; system segment?
+ jz sa11 ; y: error
+ push cx
+ and cl,AB_DPL ; mask off all but DPL bits
+ cmp cl,STD_DPL ; is this the correct DPL?
+ pop cx
+ jnz sa11 ; n: error
+
+ cCall NSetSegmentAccess,<bx,cx>
+ jmp i31_done
+
+i31_SetAccess endp
+
+
+; -------------------------------------------------------
+; Service 00/0A - Create Data Segment Alias (for a code seg)
+; in: bx - selector
+; out: ax - new data selector
+
+ assume ds:DGROUP,es:DGROUP
+ public i31_CreateDataAlias
+
+i31_CreateDataAlias proc near
+
+ mov ax,bx ;make sure it's a vaild selector
+ verr ax
+ jnz cda_failed
+
+ mov bx,ax ;get a new selector for the alias
+ call AllocateSelector
+ jc cda_failed
+
+ xchg ax,bx ;copy old to new
+ call DupSegmentDscr
+
+ mov es,selGDT
+ and bx,SELECTOR_INDEX
+ mov al,es:[bx].arbSegAccess
+ and al,11100000b ;mask off all but present and DPL bits
+ or al,AB_DATA or AB_WRITE
+ifndef WOW
+ mov es:[bx].arbSegAccess,al
+else
+ mov ah, es:[bx].cbLimitHi386
+ cCall NSetSegmentAccess,<bx,ax>
+endif ; WOW
+ or bl,STD_TBL_RING ;set standard table/ring bits
+ mov [bp].intUserAX,bx
+
+ jmp i31_done
+
+cda_failed:
+ jmp i31_fail_CY
+
+i31_CreateDataAlias endp
+
+
+; -------------------------------------------------------
+; Service 00/0B - Get Descriptor
+; Service 00/0C - Set Descriptor
+; in: bx - selector
+; es:di -> buffer to hold copy of descriptor
+
+ assume ds:DGROUP,es:DGROUP
+ public i31_GetSetDescriptor
+
+i31_GetSetDescriptor proc near
+IFNDEF WOW
+ test bx,4
+ jz getgdtdsc
+ENDIF
+
+IFDEF WOW
+ .386p
+ push esi
+ push edi
+ .286p
+ENDIF
+ mov ax,selGDT
+ mov es,ax
+ assume es:NOTHING
+ lsl ax,ax
+
+ and bx,SELECTOR_INDEX
+
+ cmp bx,ax ; range-test selector against
+ jc @f ; the limit of the GDT/LDT
+
+IFDEF WOW
+.386p
+ pop edi
+ pop esi
+.286p
+ENDIF
+ jmp i31_fail_CY ;fail if invalid selector specified
+@@:
+ call IsSelectorFree
+ jc @f
+
+IFDEF WOW
+.386p
+ pop edi
+ pop esi
+.286p
+ENDIF
+ jmp i31_fail_CY
+@@:
+
+ cmp byte ptr [bp].intUserAX,SelMgt_Get_Desc ;Get or Set?
+ jz i31_GetDscr
+
+;
+; Set Descriptor
+;
+IFDEF WOW
+ test DpmiFlags,DPMI_32BIT
+ jnz gsd10
+.386p
+ mov esi,0 ; zero high half
+ mov edi,0
+ jmp gsd20
+
+gsd10: mov esi,edi ; get high half of edi
+ mov edi,0 ; zero high half
+.286p
+gsd20:
+ENDIF
+ push ds ;Set -
+ mov ds,[bp].pmUserES
+ assume ds:nothing
+
+ mov si,[bp].pmUserDI ; ds:si -> caller's buffer
+ mov di,bx ; es:di -> dscr slot in GDT/LDT
+
+IFDEF WOW
+ .386p
+ mov cl,ds:[esi].arbSegAccess386
+ .286p
+ELSE
+ mov cl,ds:[si].arbSegAccess386
+ENDIF
+ test cl,010000b ; system segment?
+ jz gsd25 ; y: error
+ and cl,AB_DPL ; mask off all but DPL bits
+ cmp cl,STD_DPL ; is this the correct DPL?
+ jnz gsd25 ; n: error
+ jmp short i31_MovDscr
+
+gsd25: ; set ldt format error
+ pop ds
+IFDEF WOW
+.386p
+ pop edi
+ pop esi
+.286p
+ENDIF
+ jmp i31_fail_CY
+
+i31_GetDscr:
+ assume ds:DGROUP
+;
+; Get Descriptor
+;
+IFDEF WOW
+ test DpmiFlags,DPMI_32BIT
+ jnz gsd30
+.386p
+ mov edi,0 ; zero high half of edi
+gsd30: mov esi,0 ; zero high half of esi
+
+.286p
+ENDIF
+ push ds ;Get -
+ push es
+ pop ds
+ assume ds:nothing
+ mov si,bx ; ds:si -> dscr slot in GDT/LDT
+ mov es,[bp].pmUserES
+ mov di,[bp].pmUserDI ; es:di -> caller's buffer
+
+i31_MovDscr:
+ifndef WOW
+ cld
+ mov cx,4 ;copy the descriptor
+ rep movsw
+
+ cmp byte ptr [bp].intUserAX,SelMgt_Get_Desc ; Get or Set?
+ jz i31_gs25 ; Done if get.
+
+ push ax ; notify dpmi32 of segment base change
+ mov ax,bx ; ax -> selector
+ mov cx,1 ; cx -> selector count
+ DPMIBOP SetDescriptorTableEntries
+ pop ax
+else
+ .386p
+ cCall NMoveDescriptor,<ds,esi,es,edi>
+ .286p
+endif ; WOW
+i31_gs25:
+ pop ds
+ assume ds:DGROUP
+
+IFDEF WOW
+.386p
+ pop edi
+ pop esi
+.286p
+ENDIF
+ jmp i31_done
+
+IFNDEF WOW
+getgdtdsc:
+ cmp byte ptr [bp].intUserAX,SelMgt_Get_Desc
+ je @f
+ jmp i31_Fail_CY
+
+@@: and bx, NOT 3
+ push ds
+ mov ax,SEL_GDT or STD_RING
+ mov ds,ax
+ assume ds:nothing
+ lsl ax,ax
+ sub ax,8
+ cmp ax,bx
+ ja @f
+ pop ds
+ jmp i31_Fail_CY
+
+@@: mov ax,[bp].pmUserES
+ mov es,ax
+ mov di,[bp].pmUserDI
+ mov si,bx
+ mov cx,4
+ rep movsw
+ pop ds
+ jmp i31_done
+endif
+i31_GetSetDescriptor endp
+
+; -------------------------------------------------------
+; Service 00/0D - Allocate Specific LDT Selector
+; in: bx - selector
+; out: carry clear if selector was allocated
+; carry set if selector was not allocated
+ assume ds:DGROUP,es:DGROUP
+ public i31_SpecificSel
+
+i31_SpecificSel proc near
+
+ and bx,SELECTOR_INDEX
+ cmp bx,SEL_DPMI_LAST
+ ja i31_SpecificSel_Fail
+ mov cx,bx
+ shr cl,3 ; Selector to selector index in LDT
+ mov ax,1
+ shl ax,cl ; AX = bit in i31_selectorbitmap
+ test i31_selectorbitmap,ax ; test for already allocated
+ jnz i31_SpecificSel_Fail ; allocated, fail
+ or i31_selectorbitmap,ax ; mark as allocated
+
+ ;
+ ; Set up the DPL and size
+ ;
+ mov ax,bx
+ mov cx,1
+
+ jmp setsel
+
+i31_SpecificSel_Fail: ; couldn't get that one
+ jmp i31_fail_CY
+
+i31_SpecificSel endp
+
+; -------------------------------------------------------
+ subttl INT 31h DOS Memory Services
+ page
+; -------------------------------------------------------
+; INT 31h DOS MEMORY SERVICE ROUTINES
+; -------------------------------------------------------
+
+; -------------------------------------------------------
+; Service 01/00 - Allocate DOS Memory Block
+;
+; In: BX - # paragraphs to allocate
+; Out: If successful: Carry Clear
+; AX - segment address of block
+; DX - selector to access block
+;
+; If unsuccessful: Carry Set
+; AX - DOS error code
+; BX - size of largest available block in paragraphs
+;
+; 13-Feb-1991 -- ERH This call is not supported under Windows 3.1,
+; but try to find a block in our net heap to
+; satisfy the request, anyway.
+;
+
+
+ assume ds:DGROUP,es:DGROUP
+ public i31_AllocDOSMem
+
+i31_AllocDOSMem proc near
+ and [bp].intUserFL,NOT 1 ; clear carry in status
+ mov cx,[bp].intUserBX
+ mov dx,[bp].intUserBX
+ shr dx,12 ; high half of byte count
+ shl cx,4 ; low half of byte count
+
+ call AllocateLowBlock
+
+ jc adm30
+
+ mov [bp].intUserDX,ax
+ mov si,ax
+
+ call GTPARA ; get paragraph address
+
+ mov [bp].intUserAX,ax
+ jmp i31_done
+
+adm30: shr cx,4
+ shl dx,12
+ or cx,dx ; paragraph size of largest
+ mov [bp].intUserBX,cx
+ mov [bp].intUserAX,ax ; error code
+ jmp i31_fail_CY
+
+i31_AllocDOSMem endp
+
+
+; -------------------------------------------------------
+; Service 01/01 - Release DOS Memory Block
+;
+; In: DX - SELECTOR of block to release
+; Out: If successful: Carry Clear
+;
+; If unsuccessful: Carry Set
+; AX - DOS error code
+
+ assume ds:DGROUP,es:DGROUP
+ public i31_FreeDOSMem
+
+i31_FreeDOSMem proc near
+
+ mov ax,[bp].intUserDX
+ verw ax
+ jnz fdm60
+
+ call IsSelectorFree
+ jnc fdm60
+
+ mov ax,[bp].intUserDX
+ call FreeLowBlock
+
+ jc fdm60
+ jmp i31_Success
+
+fdm60: mov [bp].intUserAX,ax
+ jmp i31_fail_CY
+
+i31_FreeDOSMem endp
+
+
+; -------------------------------------------------------
+; Service 01/02 - Resize DOS Memory Block
+;
+; In: BX - new block size in paragraphs
+; DX - SELECTOR of block to release
+; Out: If successful: Carry Clear
+;
+; If unsuccessful: Carry Set
+; AX - DOS error code
+
+ assume ds:DGROUP,es:DGROUP
+ public i31_SizeDOSMem
+
+i31_SizeDOSMem proc near
+
+ mov [bp].intUserBX,0
+ mov [bp].intUserAX,08h ; insufficient mem. available
+ jmp i31_fail_CY
+
+i31_SizeDOSMem endp
+
+
+; -------------------------------------------------------
+ subttl INT 31h Real Mode Int Vector Routines
+ page
+; -------------------------------------------------------
+; INT 31h INTERRUPT SERVICES
+; -------------------------------------------------------
+
+; -------------------------------------------------------
+; i31_GetSetRMInt -- Get/Set Real Mode Interrupt Vector
+;
+; In: bl - Interrupt #
+; cx:dx - SEG:Offset of real mode int vector (if set)
+; Out: cx:dx - SEG:Offset of real mode int vector (if get)
+
+ assume ds:DGROUP,es:DGROUP
+ public i31_GetSetRMInt
+
+i31_GetSetRMInt proc near
+
+ push SEL_RMIVT or STD_RING ;address the real mode IVT
+ pop es
+ assume es:NOTHING
+
+; HACK. Starting with Windows 3.1, we do not remap the PIC anymore. However,
+; Windows 3.0 Comm Drivers, thinking that the PIC will always be remapped,
+; deal with interrupts in the range 50h to 57h. There is now a SYSTEM.INI
+; switch to tell us that a Windows 3.0 Comm Driver is being used. If this
+; switch is set, we will map 50-57h to 8-0fh in this call.
+
+ cmp fWin30CommDrv,0 ;are we using a Windows 3.0 Comm Drv ?
+ je i31_GSRMInt_not_50to57h ;no.
+ cmp bl,50h ;is it in the range 50 to 57h ?
+ jb i31_GSRMInt_not_50to57h ;no.
+ cmp bl,57h ;is it above 57h
+ ja i31_GSRMInt_not_50to57h ;yes, no hack needed.
+
+; map from the range 50-57h to 08-0fh.
+
+ sub bl,50h-8h
+
+i31_GSRMInt_not_50to57h:
+
+ xor bh,bh ;convert int # to offset
+ shl bx,2
+
+ FCLI ;play it safe
+
+ cmp al,Int_Get_Real_Vec ;Get or Set?
+ jnz i31_gs_set
+
+ mov cx,word ptr es:[bx+2] ;get segment:offset
+ mov dx,word ptr es:[bx]
+
+ ;
+ ; If we have installed a reflector, return the original handler
+ ;
+ cmp cx,segDXCodePM
+ jne gsr20
+
+ cmp dx,offset RMIntrEntryVector
+ jb gsr20
+
+ cmp dx,offset EndRMIntrEntry
+ jae gsr20
+
+ mov cx,word ptr RmHwIsr[bx + 2]
+ mov dx,word ptr RmHwIsr[bx]
+
+gsr20: mov [bp].intUserCX,cx ;return them to caller
+ mov [bp].intUserDX,dx
+
+ jmp short i31_gs_ret
+
+i31_gs_set: ;setting the vector...
+
+ mov es:[bx],dx ;set the real mode IDT vector
+ mov es:[bx+2],cx
+
+i31_gs_ret:
+
+ FSTI
+ jmp i31_done
+
+i31_GetSetRMInt endp
+
+
+; -------------------------------------------------------
+; i31_GetSetFaultVector -- Get/Set Protected Mode Fault Vector (0h-1Fh)
+;
+; In: bl - Interrupt #
+; cx:dx - Sel:Offset of pMode int vector (if set)
+; Out: cx:dx - Sel:Offset of pMode int vector (if get)
+
+ assume ds:DGROUP,es:DGROUP
+ public i31_GetSetFaultVector
+
+i31_GetSetFaultVector proc near
+
+ cmp bl,10h ; zero to 10h are defined for 80386
+ jbe @f
+ jmp i31_fail_CY ;must be <= 10h or fail it
+@@:
+ xor bh,bh
+ mov ax,bx ;interrupt # to AX
+
+ cmp byte ptr [bp].intUserAX,Int_Get_Excep_Vec ;Get or Set?
+ jne i31_gfv_set
+
+ call GetFaultVector ;wants to get the vector
+ mov [bp].intUserCX,cx
+ mov [bp].intUserDX,dx
+
+ jmp short i31_gfv_ret
+
+i31_gfv_set:
+IFDEF WOW
+.386p
+ test DpmiFlags,DPMI_32BIT
+ jnz sfv10
+
+ movzx edx,dx ; zero high half
+.286p
+ENDIF
+sfv10: call PutFaultVector ;doing a set (args already set)
+
+i31_gfv_ret:
+ jmp i31_done
+
+i31_GetSetFaultVector endp
+
+; -------------------------------------------------------
+; i31_GetSetPMInt -- Get/Set Protected Mode Interrupt Vector
+;
+; In: bl - Interrupt #
+; cx:dx - SEL:Offset of protected mode int vector (if set)
+; Out: cx:dx - SEL:Offset of protected mode int vector (if get)
+
+ assume ds:DGROUP,es:DGROUP
+ public i31_GetSetPMInt
+
+i31_GetSetPMInt proc near
+
+ xchg al,bl
+ xor ah,ah
+
+ cmp bl,Int_Get_PMode_Vec ;Get or Set?
+ jnz i31_gsp_set
+
+; NOTE: we don't call DFGetIntrVector here, because all it does is a call to
+; the following routine
+
+ call GetIntrVector
+ mov [bp].intUserCX,cx
+ mov [bp].intUserDX,dx
+
+ jmp i31_gsp_done
+
+i31_gsp_set:
+
+ ; set up the appropriate real mode reflector, and hook the int.
+ call DFSetIntrVector
+
+i31_gsp_done:
+ FSTI
+ jmp i31_done
+
+i31_GetSetPMInt endp
+
+; -------------------------------------------------------
+ subttl INT 31h Protected-to-Real Mode Call/Int
+ page
+; -------------------------------------------------------
+; INT 31h PROTECTED-TO-REAL MODE CALL/INT SERVICES
+; -------------------------------------------------------
+
+; -------------------------------------------------------
+; Service 03/00 -- Simulate real mode interrupt
+; Service 03/01 -- Call real mode procedure with far return frame
+; Service 03/02 -- Call real mode procedure with iret return frame
+;
+; In: es:di -> client register structure for real mode
+; bl = interrupt number (03/00 only)
+; cx = # words to copy from protected mode stack
+; Out: es:di -> updated client register structure
+
+ assume ds:DGROUP,es:DGROUP
+ public i31_RMCall
+
+i31_RMCall proc near
+
+; First off, we need to copy the client register structure down to
+; real mode addressable memory... Lets use rgbXfrBuf1 for now...
+; Changed to use the interrupt reflector stack because these routines
+; need to be reentrant. This also lets us leave interrupts enabled
+; longer.
+; Earleh - 27-Jun-1990.
+
+ mov di,sp ; DI = SP = client regs. buffer
+
+ sub di,size Real_Mode_Call_Struc+2 ; Make room for client
+ sub di,[bp].intUserCX ; call structure plus
+ sub di,[bp].intUserCX ; any optional stack params
+IFDEF WOW
+ sub di,32 ; pushad
+ENDIF
+ push di ; plus copy of di.
+IFDEF WOW
+.386p
+ pushad ; have to save high 16 bits
+.286p
+ENDIF
+
+ mov sp,di
+
+; --------------------------------------------------------------
+;
+; The interrupt reflector stack frame now looks like this...
+;
+; pbReflStack + CB_STKFRAME-> ---------------------------
+; (old pbReflStack) | |
+; | INTRSTACK Struc |
+; | from EnterIntHandler |
+; | |
+; ---------------------------
+; pbReflStack + CB_STKFRAME | word pointer |>>--\
+; - (SIZE INTRSTACK) - 2 -> --------------------------- |
+IFDEF WOW
+; | | |
+; | Pushad frame | |
+; | | |
+; --------------------------- |
+ENDIF
+; | | |
+; | optional stack params | |
+; | | |
+; --------------------------- |
+; | | |
+; | | |
+; | Real_Mode_Call_Struc | |
+; | | |
+; | | |
+; ---------------------------<<--/
+; | |
+; | Available stack space |
+; | |
+; pbReflStack---------->---------------------------
+;
+; After returning from the real mode procedure, we will need
+; to fetch the word pointer stored just below the EnterIntHandler
+; frame, and use it to access our temporary Real_Mode_Call_Struc.
+; In addition to holding the client register values, this also
+; holds the SP and BP values we will need to switch back to our
+; stack when we return from the real mode procedure.
+;
+; !!! -- Storing the optional stack parameters on top of our
+; Real_Mode_Call_Struc has several problems. It eats up stack
+; space if we call the real mode procedure on our stack, because
+; we then have to make another copy of these. It also means we have to
+; carry around a pointer to where the Real_Mode_Call_Struc lives.
+; If we didn't have the stack parameters on top of the Real_Mode_Call_Struc,
+; then we could find things strictly by offset from the value in
+; pbReflStack. The picture above should be rearranged to make optimal
+; use of space. I basically did it this way so I could have a minimum-
+; change fix for a bug in Windows 3.0.
+; !!!
+; --------------------------------------------------------------
+;
+;
+
+ cld
+IFDEF WOW
+ .386p
+ xor ecx,ecx
+ .286p
+ENDIF
+ mov cx,(size Real_Mode_Call_Struc) / 2
+
+ mov bx,di ;bx used to reference client regs below
+IFDEF WOW
+.386p
+ test DpmiFlags,DPMI_32BIT
+ jz rmc10
+
+ mov esi,edi ; copy over high 16 bits
+ jmp rmc20
+
+rmc10: xor esi,esi ; clear high 16 bits esi
+rmc20: xor edi,edi ; clear high 16 bits edi
+ mov di,bx
+.286p
+ENDIF
+ mov si,[bp].pmUserDI
+ mov ds,[bp].pmUserES
+ assume ds:NOTHING
+IFNDEF WOW
+ rep movsw
+ELSE
+.386p
+ rep movs word ptr [esi],word ptr [edi]
+.286p
+ENDIF
+
+
+; Copy stack parameters from PM to RM stack if requested by caller. To
+; avoid excessive selector munging, we do this in two steps (under the
+; assumption the # words to copy will be small). First the PM stack args
+; are copied to a buffer in DXDATA, then after switching to real mode,
+; to the real mode stack. If the caller has more stack words than will
+; fit in our buffer, or the real mode stack, bad things will happen...
+
+IFDEF WOW
+ .386p
+ xor ecx,ecx
+ .286p
+ENDIF
+ mov cx,[bp].intUserCX ;caller's CX has # stack words to copy
+ jcxz @f
+
+ Trace_Out "Int 31h PM-to-RM int/call copying #CX stack words"
+
+IFDEF WOW
+.386p
+ xor esi,esi
+.286p
+ENDIF
+ mov ds,[bp].pmUserSS
+ mov si,[bp].pmUserSP
+IFDEF WOW
+.386p
+ test DpmiFlags,DPMI_32BIT
+ jz rmc30
+;
+; Have to go groping for user stack, since we switched stacks to get
+; here.
+;
+; | |
+; +----------------+
+; | |
+; +---- SS -----+
+; | |
+; +----------------+
+; | |
+; +---- ESP -----+
+; | |
+; +----------------+
+; | Flags |
+; +----------------+
+; | CS |
+; +----------------+
+; | IP |
+; ds:si -> +----------------+
+
+ push dword ptr ds:[si + 6]
+ push word ptr ds:[si + 10]
+ pop ds
+ pop esi
+ add esi,6 ; other half of 32 bit stack frame
+
+rmc30: add esi,6 ;ds:si -> PM stack args
+ rep movs word ptr [esi],word ptr [edi]
+.286p
+ELSE
+ add si,6
+ rep movsw
+ENDIF
+ ;es:di already points to buffer
+@@:
+ push es ;restore ds -> DGROUP
+ pop ds
+ assume ds:DGROUP
+
+; Switch to real mode, set up the real mode stack
+
+ SwitchToRealMode
+ assume ds:DGROUP,es:DGROUP
+
+i31_rmcall_hw_ok:
+ FSTI ;RestoreHardwareIntr disables ints
+ ;don't need them disabled now
+
+ mov [bx].RealMode_SaveBP,bp ;save our stack in reserved area of
+ mov [bx].RealMode_SaveSP,sp ; real mode register frame
+
+ mov cx,[bp].pmUserCX ;cx = caller's CX (# stk words)
+ mov dh,byte ptr [bp].pmUserAX ;dh = caller's AL (subfunction)
+ mov dl,byte ptr [bp].pmUserBX ;dl = caller's BL (RM int #)
+
+ mov ax,[bx].RealMode_SS ;did caller specify his own stack?
+ or ax,[bx].RealMode_SP
+
+ jz @f
+
+ ; NOTE: can't reference [bp].xxUserXX varaibles after switching stacks
+
+ mov ss,[bx].RealMode_SS ;switch to caller's real mode stack
+ mov sp,[bx].RealMode_SP
+
+ assume ss:NOTHING
+@@:
+
+; Copy stack args to real mode stack if there are any
+
+ jcxz @f
+
+ sub sp,cx
+ sub sp,cx ;make space on stack for args
+
+ mov di,sp
+ mov ax,ss
+ mov es,ax ;es:di -> real mode stack
+ assume es:NOTHING
+
+ lea si,[bx + size Real_Mode_Call_Struc]
+
+ cld
+ rep movsw
+
+ push ds
+ pop es
+ assume es:DGROUP
+@@:
+
+; Put a far ret or iret frame on stack to return to us
+
+ cmp dh,Trans_Far_Call ;Does this service use a far ret or
+ jz i31_rmcall_retf ; an iret frame?
+
+ push [bx].RealMode_Flags ;real mode routine thinks these were
+ push cs ; the prior flags and CS:IP
+ push offset i31_rmcall_ret
+
+ FCLI ;flags with interrupts disabled -- real
+ pushf ; mode rtn entered with these flags
+ FSTI
+ jmp short @f
+
+i31_rmcall_retf:
+
+ push cs ;push a far ret frame so the
+ push offset i31_rmcall_ret ; real mode routine returns to us
+
+ push [bx].RealMode_Flags ;real mode rtn entered with these flags
+@@:
+ cmp dh,Trans_Sim_Int ;use an int vector, or caller's spec'd
+ jnz i31_rmcall_csip ; cs:ip?
+
+ mov al,dl ;push CS:IP for interrupt
+ xor ah,ah ; number in caller's BL
+ mov si,ax
+ shl si,2
+
+ xor ax,ax ;address real mode IDT
+ mov es,ax
+ assume es:NOTHING
+
+ push word ptr es:[si+2]
+ push word ptr es:[si]
+
+ jmp short @f
+
+i31_rmcall_csip:
+
+ push [bx].RealMode_CS ;execute the real mode routine at
+ push [bx].RealMode_IP ; specified CS:IP
+@@:
+
+; Load the clients registers, and pass control to the real mode routine
+IFNDEF WOW
+ mov di,[bx].RealMode_DI
+ mov si,[bx].RealMode_SI
+ mov bp,[bx].RealMode_BP
+ mov dx,[bx].RealMode_DX
+ mov cx,[bx].RealMode_CX
+ mov ax,[bx].RealMode_AX
+ mov es,[bx].RealMode_ES
+ assume es:NOTHING
+
+ push [bx].RealMode_DS
+ push [bx].RealMode_BX
+
+ pop bx
+ pop ds
+ assume ds:NOTHING
+ELSE
+.386p
+ mov edi,dword ptr [bx].RealMode_DI
+ mov esi,dword ptr [bx].RealMode_SI
+ mov ebp,dword ptr [bx].RealMode_BP
+ mov edx,dword ptr [bx].RealMode_DX
+ mov ecx,dword ptr [bx].RealMode_CX
+ mov eax,dword ptr [bx].RealMode_AX
+ mov es,[bx].RealMode_ES
+ assume es:NOTHING
+
+ push [bx].RealMode_DS
+ push dword ptr [bx].RealMode_BX
+
+ pop ebx
+ pop ds
+ assume ds:NOTHING
+.286p
+ENDIF
+ iret
+
+
+; The real mode routine returns here when finished
+
+i31_rmcall_ret:
+
+ pushf ;save returned flags, ds, bx on stack
+ FSTI ;don't need ints disabled
+ push ds
+IFNDEF WOW
+ push bx
+ELSE
+.386p
+ push ebx
+.286p
+ENDIF
+
+IFDEF ROM
+ SetRMDataSeg
+ELSE
+ mov ds,segDXData ;address our DGROUP
+ENDIF
+ assume ds:DGROUP
+;
+; Fetch word pointer to temporary client register save area, that we
+; saved before switching stacks.
+;
+ mov bx,[pbReflStack]
+ mov bx,[bx + CB_STKFRAME - (SIZE INTRSTACK) - 2]
+
+; Save the real mode registers in client frame
+
+IFNDEF WOW
+ mov [bx].RealMode_DI,di
+ mov [bx].RealMode_SI,si
+ mov [bx].RealMode_BP,bp
+ mov [bx].RealMode_DX,dx
+ mov [bx].RealMode_CX,cx
+ mov [bx].RealMode_AX,ax
+ mov [bx].RealMode_ES,es
+
+ pop [bx].RealMode_BX
+ELSE
+.386p
+ mov dword ptr [bx].RealMode_DI,edi
+ mov dword ptr [bx].RealMode_SI,esi
+ mov dword ptr [bx].RealMode_BP,ebp
+ mov dword ptr [bx].RealMode_DX,edx
+ mov dword ptr [bx].RealMode_CX,ecx
+ mov dword ptr [bx].RealMode_AX,eax
+ mov [bx].RealMode_ES,es
+
+ pop dword ptr [bx].RealMode_BX
+.286p
+ENDIF
+ pop [bx].RealMode_DS
+ pop [bx].RealMode_Flags
+ or [bx].RealMode_Flags,03000h ; IOPL always has to be 3
+
+
+; Restore our stack and return to protected mode
+; SP will now point to base of temporary client register save area
+; on our stack. BP points to stack frame set up for us by EnterIntHandler.
+; SP must be restored to value in BP before calling LeaveIntHandler.
+
+IFDEF ROM
+ push ds
+ pop ss
+ELSE
+ mov ss,segDXData ;address our DGROUP
+ENDIF
+ mov sp,[bx].RealMode_SaveSP
+ mov bp,[bx].RealMode_SaveBP
+
+ SwitchToProtectedMode
+ assume ds:DGROUP,es:DGROUP
+
+ FSTI ;still don't need ints disabled
+
+; Apparently in win31 standard mode, the pm caller's flags are set to the
+; value of the rm flags at the handler's iret. On win31 enhanced mode, this
+; was *not* done, and the pm flags are, except for carry, basically
+; preserved. Since setting the flags kills some apps (winfax deltest),
+; we should adhere to the enhanced mode convention. Thus, the following
+; code is if'd out.
+if 0
+ mov ax,[bx].RealMode_Flags
+ mov [bp].intUserFL,ax
+endif
+
+; Copy the updated client register frame to the caller, and we're finished
+
+ cld
+IFDEF WOW
+ .386p
+ xor ecx,ecx
+ .286p
+ENDIF
+ mov cx,(size Real_Mode_Call_Struc) / 2
+IFDEF WOW
+.386p
+ xor esi,esi
+ xor edi,edi
+
+ mov si,bx
+ add si,[bp].pmUserCX
+ add si,[bp].pmUserCX
+ add si,size Real_Mode_Call_Struc
+;
+; Si now points at pushad frame
+;
+ push si
+
+ test DpmiFlags,DPMI_32BIT
+ jz rmc80
+ mov edi,[si]
+rmc80:
+.286p
+ENDIF
+ mov si,bx
+ mov di,[bp].pmUserDI
+ mov es,[bp].pmUserES
+ assume es:NOTHING
+IFNDEF WOW
+ rep movsw
+
+ mov sp,bp ;Restore sp for LeaveIntHandler
+ELSE
+.386p
+ rep movs word ptr [esi],word ptr [edi]
+
+ pop sp ; value calculated above
+ popad
+ mov sp,bp
+.286p
+ENDIF
+
+ jmp i31_done ;finished!
+
+i31_RMCall endp
+
+
+; -------------------------------------------------------
+; Service 03/03 -- Allocate Real Mode Call-Back Address
+;
+; In: ds:si -> pMode CS:IP to be called when rMode
+; call-back address executed
+; es:di -> client register structure to be updated
+; when call-back address executed
+; Out: cx:dx -> SEGMENT:offset of real mode call-back hook
+; CY clear if successful, CY set if can't allocate
+; call back
+
+ assume ds:DGROUP,es:DGROUP
+ public i31_AllocCallBack
+
+i31_AllocCallBack proc near
+
+; Search call-back table for a free entry
+
+ mov bx,offset DGROUP:CallBackTable
+ mov cx,cRM_CALL_BACK
+@@:
+ test [bx].fInUse,0FFh ;in use?
+ jz i31_avail_callback
+ add bx,size CallBackTableStruc
+ loop @b
+
+ jmp i31_fail_CY ;no call-backs available, fail
+
+; Fill in the call back table entry with caller's info
+
+i31_avail_callback:
+
+ mov [bx].fInUse,0FFh ;mark as in use
+
+ mov ax,[bp].pmUserDS
+IFNDEF WOW
+ mov word ptr [bx].PM_CS_IP,si ;store pMode call-back CS:IP
+ mov word ptr [bx].PM_CS_IP+2,ax
+ELSE
+.386p
+ test DpmiFlags,DPMI_32BIT
+ jz acb20
+ mov [bx].PM_CS_IP,esi
+ mov [bx].PM_Client_Frame,edi
+ mov word ptr [bx].PM_CS_IP + 4,ax
+ jmp acb30
+
+acb20: mov word ptr [bx].PM_CS_IP,si
+ mov word ptr [bx].PM_Client_Frame,di
+ mov word ptr [bx].PM_CS_IP + 4,ax
+ mov ax,0
+ mov word ptr [bx].PM_CS_IP + 2,ax
+ mov word ptr [bx].PM_Client_Frame + 2,ax
+acb30:
+.286p
+ENDIF
+
+ mov ax,[bp].pmUserES
+IFNDEF WOW
+ mov word ptr [bx].PM_Client_Frame,di
+ mov word ptr [bx].PM_Client_Frame+2,ax
+ELSE
+.386p
+ mov word ptr [bx].PM_Client_Frame + 4,ax
+.286p
+ENDIF
+
+; Return Seg:Off of Real Mode call-back to caller in CX:DX
+
+ mov ax,segDXCodePM ;segment
+ mov [bp].intUserCX,ax
+
+ sub cx,cRM_CALL_BACK
+ neg cx ;cx = allocated entry # (0..n)
+
+ errnz <cRM_CALL_BACK gt 255> ;code assumes cx <= 255
+
+ mov al,3 ;convert entry # to IP
+ mul cl ;3 bytes per entry
+ add ax,offset DXCODE:RMCallBackEntryVector
+ mov [bp].intUserDX,ax
+
+ jmp i31_done
+
+i31_AllocCallBack endp
+
+
+; -------------------------------------------------------
+; Service 03/04 -- Free Real Mode Call-Back Address
+;
+; In: cx:dx -> SEGMENT:offset of rMode call-back to free
+; Out: CY clear if successful, CY set if failure
+
+ assume ds:DGROUP,es:DGROUP
+ public i31_FreeCallBack
+
+i31_FreeCallBack proc near
+
+; Determine which Real Mode Call-Back is being freed
+
+ cmp cx,segDXCodePM ;sanity check the incoming CS:IP
+ jne i31_FreeCBFail
+
+ cmp dx,offset DXCODE:RMCallBackEntryVector
+ jb i31_FreeCBFail
+
+ mov ax,dx
+ sub ax,offset DXCODE:RMCallBackEntryVector
+ mov bl,3
+ div bl ;al = entry # (0..n)
+
+ cmp al,cRM_CALL_BACK ;past end of table?
+ jae i31_FreeCBFail
+
+ errnz <size CallBackTableStruc gt 255>
+
+ mov bl,size CallBackTableStruc
+ mul bl
+ mov bx,ax
+ add bx,offset DGROUP:CallBackTable ;bx -> CallBackTable entry
+
+ mov [bx].fInUse,0 ;mark it free
+
+ jmp i31_done ;finished!
+
+i31_FreeCBFail:
+
+ jmp i31_fail_CY
+
+i31_FreeCallBack endp
+
+
+; -------------------------------------------------------
+
+DXPMCODE ends
+
+; -------------------------------------------------------
+
+DXCODE segment
+ assume cs:DXCODE
+
+; -------------------------------------------------------
+; RMCallBackHook -- Real Mode to Protected Mode Call-Back Hook
+;
+; This routine gets control whenever a user's real mode call-back
+; hook is executed. This routine saves the current registers in
+; the specified client register frame, switches to protected mode,
+; and invokes the specified pMode CS:IP. Upon return from the
+; pMode call-back, the registers are restored from a client frame
+; and control is passed to the CS:IP specified in the frame.
+;
+
+ public RMCallBackHook
+ assume ds:NOTHING,es:NOTHING,ss:NOTHING
+
+RMCallBackHook proc
+
+ pushf ;save current flags
+
+ FCLI ;protect global variables
+ cld ;and we expect direction to be 'normal'
+
+ push ds ;address our DGROUP
+IFDEF ROM
+ SetRMDataSeg
+ELSE
+ mov ds,selDgroup
+ENDIF
+ assume ds:DGROUP
+
+ pop regUserDS ;save regs in global vars -- keep ints off!
+ pop regUserFL
+ mov regUserAX,ax
+ mov regUserES,es
+
+ pop ax ;ax = entry vector return address
+
+; Convert the entry vector return address into a call-back table pointer
+
+ push bx
+
+ sub ax,offset RMCallBackEntryVector+3
+ mov bl,3
+ div bl
+ mov bl,size CallBackTableStruc
+ mul bl
+ add ax,offset DGROUP:CallBackTable
+
+ pop bx
+
+; Allocate a new stack frame, and then switch to the reflector stack
+; frame, and switch to pMode.
+
+ mov regUserSS,ss ;save current user stack
+ mov regUserSP,sp
+IFDEF ROM
+ push ds
+ pop ss
+ELSE
+ mov ss,selDgroup ;switch to the reflector stack frame
+ENDIF
+ mov sp,pbReflStack
+ sub pbReflStack,2 * CB_STKFRAME ;adjust pointer to next stack frame
+
+ FIX_STACK
+ DEBUG_TRACE_RM DBGTR_STACKPTR, pbReflStack, 0, 0
+ push ax ;save CallBackTable pointer
+
+ SwitchToProtectedMode
+ assume ds:DGROUP,es:DGROUP
+
+ mov ax,bx ;save bx in ax
+ pop bx ;CallBackTable pointer to bx
+
+; Store current registers into Client register frame
+
+IFNDEF WOW
+ push di
+
+ les di,[bx].PM_Client_Frame
+ assume es:NOTHING
+
+ pop es:[di].RealMode_DI
+ mov es:[di].RealMode_BX,ax
+ mov es:[di].RealMode_CX,cx
+ mov es:[di].RealMode_DX,dx
+ mov es:[di].RealMode_SI,si
+ mov es:[di].RealMode_BP,bp
+ mov ax,regUserAX
+ mov es:[di].RealMode_AX,ax
+ELSE
+.386p
+ push edi
+
+ les edi,fword ptr [bx].PM_Client_Frame
+ assume es:NOTHING
+
+ pop dword ptr es:[di].RealMode_DI
+ push bx
+ mov bx,ax
+ mov dword ptr es:[di].RealMode_BX,ebx
+ pop bx
+ mov dword ptr es:[di].RealMode_CX,ecx
+ mov dword ptr es:[di].RealMode_DX,edx
+ mov dword ptr es:[di].RealMode_SI,esi
+ mov dword ptr es:[di].RealMode_BP,ebp
+ mov ax,regUserAX
+ mov dword ptr es:[di].RealMode_AX,eax
+.286p
+ENDIF
+ mov ax,regUserDS
+ mov es:[di].REalMode_DS,ax
+ mov ax,regUserES
+ mov es:[di].RealMode_ES,ax
+ mov dx,regUserSS ;keep real mode SS in DX
+ mov es:[di].RealMode_SS,dx
+ mov si,regUserSP ; and rMode SP in SI
+ mov es:[di].RealMode_SP,si
+ mov ax,regUserFL
+ mov es:[di].RealMode_Flags,ax
+
+
+; Map a selector to the real mode stack segment
+
+ call AllocateLDTSelector
+ jnc @f
+ mov ax,SEL_USERSCR or STD_TBL_RING ;use a scratch if can't alloc
+@@:
+ push ax ;save selector on our stack
+
+ push bx ;save CallBackTable entry pointer
+
+ call ParaToLinear ;convert SS in DX to BX:DX lma
+ mov cx,-1
+ cCall NSetSegmentDscr,<ax,bx,dx,0,cx,STD_DATA>
+
+ pop bx
+
+; Build an IRET frame on the stack for the pMode routine to return to us
+IFDEF WOW
+.386p
+ test DpmiFlags,DPMI_32BIT
+ jz rmcbh10
+
+ pushfd
+ sub sp,2
+ push cs
+ push dword ptr (offset i31_CBret)
+ jmp rmcbh20
+.286p
+ENDIF
+
+rmcbh10:
+ pushf
+ push cs
+ push offset i31_CBret
+
+rmcbh20:
+; Build a far ret frame to give control to user's Call-Back routine
+
+IFNDEF WOW
+ push word ptr [bx].PM_CS_IP+2
+ push word ptr [bx].PM_CS_IP
+
+; Do final register setups, and give control to pMode call-back routine
+
+ mov ds,ax ;DS:SI -> real mode stack
+ assume ds:NOTHING
+
+ public PMCallBack
+PMCallBack:
+ retf ;and away we go...
+ELSE
+.386p
+ push dword ptr [bx].PM_CS_IP+4
+ push dword ptr [bx].PM_CS_IP
+
+; Do final register setups, and give control to pMode call-back routine
+
+ mov ds,ax ;DS:SI -> real mode stack
+ assume ds:NOTHING
+
+ public PMCallBack
+PMCallBack:
+ db 066h
+ retf ;and away we go...
+.286p
+ENDIF
+; The pMode call-back routine returns here when finished
+
+i31_CBret:
+ cld ;take no chances
+
+ mov ds,selDgroupPM ;restore DGROUP addressability
+ assume ds:DGROUP
+
+ pop ax ;recover selector for RM stack seg
+ and al,SELECTOR_INDEX ;clear ring/table bits
+
+ cmp ax,SEL_USERSCR ;free the selector, unless it was
+ jz @f ; a scratch selector
+ call FreeSelector
+@@:
+
+; Copy the returned register Client frame to our stack so we can access
+; it from real mode
+
+ sub sp,size Real_Mode_Call_Struc+2
+ mov si,sp
+
+ push es ;ES:DI, DS:SI need to be reversed
+ mov es,selDgroupPM ; for rep movs
+ assume es:DGROUP
+ pop ds
+ assume ds:NOTHING
+
+IFDEF WOW
+ .386p
+ push ecx
+ xor ecx,ecx
+ .286p
+ENDIF
+ mov cx,(size Real_Mode_Call_Struc) / 2
+IFDEF WOW
+.386p
+ test DpmiFlags,DPMI_32BIT
+ jz rmcbh80
+
+ push si
+ xor esi,esi
+ pop si
+ xchg esi,edi
+ rep movs word ptr [esi], word ptr [edi]
+ jmp rmcbh90
+.386p
+ENDIF
+rmcbh80:
+ xchg si, di
+ rep movsw
+
+rmcbh90:
+IFDEF WOW
+ .386p
+ pop ecx
+ .286p
+ENDIF
+ push es ;everybody assumes ds=dgroup
+ pop ds
+ assume ds:DGROUP
+
+; Switch to real mode, and switch to user specified stack
+
+ SwitchToRealMode ;leaves ints disabled
+ assume ds:DGROUP,es:DGROUP
+
+ mov bx,sp ;use bx as ptr to client reg frame
+
+ CHECK_STACK
+ mov ss,[bx].RealMode_SS
+ mov sp,[bx].RealMode_SP
+
+; Restore real mode registers as specified in client frame (all but DS & BX)
+
+IFNDEF WOW
+ mov ax,[bx].RealMode_AX
+ mov cx,[bx].RealMode_CX
+ mov dx,[bx].RealMode_DX
+ mov si,[bx].RealMode_SI
+ mov di,[bx].RealMode_DI
+ mov bp,[bx].RealMode_BP
+ELSE
+.386p
+ mov eax,dword ptr [bx].RealMode_AX
+ mov ecx,dword ptr [bx].RealMode_CX
+ mov edx,dword ptr [bx].RealMode_DX
+ mov esi,dword ptr [bx].RealMode_SI
+ mov edi,dword ptr [bx].RealMode_DI
+ mov ebp,dword ptr [bx].RealMode_BP
+.286p
+ENDIF
+ mov es,[bx].RealMode_ES
+ assume es:NOTHING
+
+; Build an IRET frame to return to specified CS:IP, and do it
+
+ push [bx].RealMode_Flags
+ push [bx].RealMode_CS
+ push [bx].RealMode_IP
+
+ push [bx].RealMode_DS ;last 2 regs to restore
+IFNDEF WOW
+ push [bx].RealMode_BX
+ pop bx
+ELSE
+.386p
+ push dword ptr [bx].RealMode_BX
+ pop ebx
+.286p
+ENDIF
+ add pbReflStack,2 * CB_STKFRAME ;deallocate our stack frame
+
+ pop ds
+
+ iret ;finished!
+
+RMCallBackHook endp
+
+; -------------------------------------------------------
+
+DXCODE ends
+
+; -------------------------------------------------------
+
+DXPMCODE segment
+ assume cs:DXPMCODE
+
+; -------------------------------------------------------
+ subttl INT 31h Memory Management Services
+ page
+; -------------------------------------------------------
+; INT 31h MEMORY MANAGEMENT SERVICES
+; -------------------------------------------------------
+
+; -------------------------------------------------------
+; Service 05/00 -- Get Free Memory Information
+;
+; In: es:di -> 30h byte buffer
+; Out: es:di -> Largest free block (in bytes) placed at
+; start of caller's buffer
+; Rest of buffer filled in with -1.
+
+ assume ds:DGROUP,es:DGROUP
+ public i31_GetFreeMem
+
+i31_GetFreeMem proc near
+ mov es,[bp].pmUserES ; Point to user buffer
+ mov di,[bp].pmUserDI
+ assume es:NOTHING
+
+
+ FBOP BOP_DPMI, GetMemoryInformation, FastBop
+ jmp i31_done
+
+i31_GetFreeMem endp
+
+
+
+; -------------------------------------------------------
+; Service 05/01 -- Allocate Memory Block
+;
+; In: bx:cx - size of block to allocate in bytes
+; Out: successful, carry clear &
+; bx:cx = linear memory address of block
+; si:di = handle to block
+; failed, carry set
+
+ assume ds:DGROUP,es:DGROUP
+ public i31_AllocMem
+
+i31_AllocMem proc near
+
+ mov bx,[bp].pmUserBX
+ mov cx,[bp].pmUserCX
+ mov dx, selPSPChild
+
+ FBOP BOP_DPMI, AllocXmem, FastBop
+
+ jnc @f
+
+ jmp i31_fail_CY
+
+@@: mov [bp].intUserBX,bx
+ mov [bp].intUserCX,cx
+ mov [bp].intUserSI,si
+ mov [bp].intUserDI,di
+ jmp i31_Done
+
+i31_AllocMem endp
+
+
+; -------------------------------------------------------
+; Service 05/02 -- Free Memory Block
+;
+; In: si:di - 'handle' of block to free
+; Out: successful, carry clear
+; failed, carry set
+
+ assume ds:DGROUP,es:DGROUP
+ public i31_FreeMem
+
+i31_FreeMem proc near
+
+ mov si,[bp].pmUserSI
+ mov di,[bp].pmUserDI
+
+ FBOP BOP_DPMI, FreeXmem, FastBop
+
+ jnc @f
+
+ jmp i31_fail_CY
+
+@@: jmp i31_Done
+
+i31_FreeMem endp
+
+
+; -------------------------------------------------------
+; Service 05/03 -- Resize Memory Block
+;
+; In: bx:cx - new size of block to allocate in bytes
+; si:di - 'handle' of block to free
+; Out: successful, carry clear &
+; bx:cx = linear memory address of block
+; si:di = handle to block
+; failed, carry set
+
+ assume ds:DGROUP,es:DGROUP
+ public i31_SizeMem
+
+i31_SizeMem proc near
+
+ mov bx,[bp].pmUserBX
+ mov cx,[bp].pmUserCX
+ mov si,[bp].pmUserSI
+ mov di,[bp].pmUserDI
+
+ FBOP BOP_DPMI, ReallocXmem, FastBop
+
+ jnc @f
+
+ jmp i31_fail_CY
+
+@@: mov [bp].intUserBX,bx
+ mov [bp].intUserCX,cx
+ mov [bp].intUserSI,si
+ mov [bp].intUserDI,di
+ jmp i31_Done
+
+i31_SizeMem endp
+
+
+; -------------------------------------------------------
+; Service 09/00 -- Get and Disable Virtual Interrupt State
+; 09/01 -- Get and Enable Virtual Interrupt State
+; 09/02 -- Get Virtual Interrupt State
+;
+; In: none
+; Out: AL = previous interrupt state
+
+ assume ds:DGROUP,es:DGROUP
+ public i31_VirtualInt
+
+i31_VirtualInt proc near
+
+ mov ah,byte ptr [bp].intUserFL+1 ;get/isolate user's IF in AH
+ shr ah,1
+ and ah,1
+
+ cmp byte ptr [bp].intUserAX,Get_Int_State ;only getting state?
+ jz @f ; yes, skip set
+
+ mov al,byte ptr [bp].intUserAX ;get desired state
+ shl al,1 ; move into IF position
+
+ and byte ptr [bp].intUserFL+1,not 02h ;clr old IF bit
+ or byte ptr [bp].intUserFL+1,al ; set desired
+@@:
+ mov byte ptr [bp].intUserAX,ah ;return old state in user's AL
+
+ jmp i31_done
+
+i31_VirtualInt endp
+
+; -------------------------------------------------------
+ subttl INT 31h Utility Routines
+ page
+; -------------------------------------------------------
+; INT 31h UTILITY ROUTINES
+; -------------------------------------------------------
+
+; -------------------------------------------------------
+; i31_Version -- Return Int 31h version information.
+;
+; In: none
+; Out: ah - major version
+; al - minor version
+; bx - flags
+; cl - processor type
+; dh - master PIC base interrupt
+; dl - slave PIC bas interrupt
+;
+
+ public i31_Version
+ assume ds:DGROUP,es:DGROUP
+
+i31_Version proc near
+
+ mov [bp].intUserAX,I31VERSION
+ mov [bp].intUserBX,I31FLAGS
+ mov al,byte ptr idCpuType
+ mov byte ptr [bp].intUserCX,al
+ mov [bp].intUserDX,(I31MasterPIC SHL 8) OR I31SlavePIC
+
+ jmp i31_done
+
+i31_Version endp
+
+; -------------------------------------------------------
+; i31_MemGetHeader -- Get selector to our header on a Int 31h allocated
+; DOS memory block.
+;
+; In: DX - SELECTOR of block to get header of
+; Out: ES - selector pointing to our header for block
+; Uses: none
+
+ public i31_MemGetHeader
+ assume ds:DGROUP,es:NOTHING,ss:NOTHING
+
+i31_MemGetHeader proc near
+
+; User wants to release block pointed to by selector in DX. Use a scratch
+; selector to point 1 paragraph before that to make sure this is a block
+; we allocated, and get some misc info
+
+ push ax
+ push bx
+ push cx
+ push dx
+
+ mov ax,dx
+ call GetSegmentAddress ;BX:DX -> user's data area
+
+ sub dx,10h ;backup one paragraph
+ sbb bx,0
+
+ mov cx,0fh
+ mov ax,SEL_SCR0 or STD_TBL_RING
+ cCall NSetSegmentDscr,<ax,bx,dx,0,cx,STD_DATA>
+
+ mov es,ax
+
+ pop dx
+ pop cx
+ pop bx
+ pop ax
+ ret
+
+i31_MemGetHeader endp
+
+; -------------------------------------------------------
+; RZCall -- Utility routine to call a Ring
+; Zero procedure. Stack parameter is the NEAR
+; address of the routine in the DXPMCODE segment to
+; call. The called routine must be declared FAR
+; and take no stack parameters.
+;
+; USES: Whatever Ring 0 routine uses
+; +Flags
+; RETURNS: Whatever Ring 0 routine returns
+;
+; NOTE: Assumes that interrupts must be disabled
+; for the Ring 0 routine.
+;
+; History:
+; 12-Feb-1991 -- ERH wrote it!!!
+; -------------------------------------------------------
+
+My_Call_Gate dd (SEL_SCR0 or STD_TBL_RING) shl 10h
+
+ public RZCall
+RZCall proc near
+
+ pushf
+ FCLI
+ push bp
+ mov bp,sp
+ cCall NSetSegmentDscr,<SEL_SCR0,0,SEL_EH,0,[bp+6],STD_CALL>
+ pop bp
+
+ call dword ptr My_Call_Gate
+
+ cCall NSetSegmentDscr,<SEL_SCR0,0,0,0,-1,STD_DATA>
+
+ npopf
+
+ retn 2
+
+RZCall endp
+
+ife NO386
+
+i31_Debug_Register_Access proc near
+
+ or byte ptr [bp].intUserFL,1 ;set carry flag
+ cmp idCpuType,3 ;at least 386?
+ jb i31_Debug_Register_Access_Done ;No.
+
+IFNDEF WOW
+ push offset DXPMCODE:I31_Win386_Call
+ call RZCall
+ELSE
+ call far ptr I31_Win386_Call
+ENDIF
+i31_Debug_Register_Access_Done:
+ jmp i31_exit
+
+i31_Debug_Register_Access endp
+
+ .386
+
+;******************************************************************************
+;
+; I31_Win386_Call
+;
+; The routine to implement the INT 31h debug register functions is copied
+; directly from the WIN386 routine in vmm/int31.asm. This routine sets
+; up the 386 registers so that the actual API is callable from the 16-bit
+; DOS Extender.
+;
+;******************************************************************************
+I31_Win386_Call proc far ; Called via ring-transition call gate
+;
+; Save 386 extended registers that are used by the WIN386 code.
+;
+ pushad
+;
+; Call the actual routine
+;
+ movzx ebp,bp
+
+ call I31_Debug_Register_Support
+;
+; Restore 386 extended registers that are used by the WIN386 code.
+;
+ popad
+ ret
+
+I31_Win386_Call endp
+
+DXPMCODE ends
+
+;******************************************************************************
+; R E C O R D S
+;******************************************************************************
+
+;
+; The following record defines the debug status register.
+;
+DBG6 RECORD d6_r1:16,d6_bt:1,d6_bs:1,d6_bd:1,d6_r2:9,d6_b3:1,d6_b2:1,d6_b1:1,d6_b0:1
+DBG6_RESERVED EQU (MASK d6_r1) OR (MASK D6_r2)
+
+;
+; The following record defines the debug control register.
+;
+DBG7 RECORD d7_ln3:2,d7_rw3:2,d7_ln2:2,d7_rw2:2,d7_ln1:2,d7_rw1:2,d7_ln0:2,d7_rw0:2,d7_rs:6,d7_ge:1,d7_le:1,d7_g3:1,d7_l3:1,d7_g2:1,d7_l2:1,d7_g1:1,d7_l1:1,d7_g0:1,d7_l0:1
+DBG7_RESERVED EQU (MASK d7_rs)
+
+Num_Watchpoints EQU 4 ; Only 4 live watchpoints in 386, 486.
+
+;******************************************************************************
+; m a c r o s
+;******************************************************************************
+
+;******************************************************************************
+;
+; The following set of macros allows us to copy WIN386 code directly
+;
+;******************************************************************************
+
+BeginProc macro fname
+ fname proc near
+endm
+
+EndProc macro fname
+ fname endp
+endm
+
+Assert_Client_Ptr macro dummy
+endm
+
+Client_Flags equ intUserFL
+Client_EAX equ intUserAX
+Client_AX equ intUserAX
+Client_BX equ intUserBX
+Client_CX equ intUserCX
+Client_DX equ intUserDX
+
+CF_MASK equ 1
+
+OFFSET32 equ <OFFSET>
+
+
+
+;******************************************************************************
+; d a t a
+;******************************************************************************
+
+DXDATA segment
+
+PUBLIC Debug_Regs
+;
+; A memory image of the debug registers. The first version assumes
+; that we have complete control over the debug registers, so only
+; one copy is needed.
+;
+ ALIGN DWORD
+Debug_Regs LABEL DWORD
+DD_DR0 dd 0
+DD_DR1 dd 0
+DD_DR2 dd 0
+DD_DR3 dd 0
+
+DD_DR6 dd 0
+DD_DR7 dd 0
+
+DXDATA ends
+
+ .386p
+
+DXPMCODE segment
+
+;******************************************************************************
+;
+; I31_Debug_Register_Support
+;
+; ENTRY: AL = Function code
+; 01 -- Set debug watchpoint
+; BX:CX = linear address of watchpoint
+; DL = size of watchpoint (1, 2, or 4)
+; DH = type of watchpoint
+; 0 = Execute
+; 1 = Write
+; 2 = Read/Write
+;
+; Returns
+; BX = debug watchpoint handle
+;
+; 02 -- Clear debug watchpoint
+;
+; 03 -- Get state of debug watchpoint
+; Returns
+; AX = bit 0 set if watch point has been executed
+;
+; 04 -- Reset debug watchpoint
+;
+; EXIT: Carry clear in client flags if successful
+; Carry set in client flags if not
+;
+; USES: EDI, EAX, ECX, EDX, ESI
+;
+; History:
+; 08-Feb-1991 -- ERH wrote it.
+;
+;******************************************************************************
+BeginProc I31_Debug_Register_Support
+
+IFNDEF WOW
+ call Store_DBG_Regs ; make copy of debug regs.
+ENDIF
+
+ test [DD_DR6],MASK d6_bd
+ jnz DD_I31_Error ; ICE-386 is active!
+ and [ebp.Client_Flags],NOT CF_MASK
+
+ mov eax, dword ptr [ebp.Client_EAX]
+ cmp al, 03h
+ ja DD_I31_Error
+ je DD_I31_Reset_Watchpoint
+ cmp al, 01h
+ ja DD_I31_Get_Status
+ je DD_I31_Clear_Watchpoint
+
+;
+; Function AX = 0A00h -- Set Debug Watchpoint
+;
+PUBLIC DD_I31_Set_Watchpoint
+DD_I31_Set_Watchpoint:
+ xor ecx, ecx
+ mov edx,(MASK d7_l0) OR (MASK d7_g0); EDX = DR0 enable bits
+DD_I31_Search_Loop:
+;
+; Look for an unused breakpoint. In order for a breakpoint to be
+; unused, the corresponding global and local enable bits must be clear.
+;
+ test [DD_DR7],edx
+ jz SHORT DD_I31_SW_Found_One
+DD_I31_SkipIt:
+ shl edx,2 ; EDX = next BP's enable bits
+ inc ecx
+ cmp ecx, Num_Watchpoints
+ jb DD_I31_Search_Loop
+ jmp DD_I31_Error
+
+DD_I31_SW_Found_One:
+ mov esi, OFFSET32 Debug_Regs
+ mov eax,ecx
+ shl eax,2
+ add esi,eax ; ESI -> BP address buffer
+ mov ax, [ebp.Client_BX]
+ shl eax, 16
+ mov ax, [ebp.Client_CX] ; EAX = linear address
+ mov dword ptr [esi],eax ; record address
+ or [DD_DR7],edx ; enable the break point
+
+ mov edx,NOT((MASK d7_ln0) OR (MASK d7_rw0))
+ shl cl,2
+ rol edx,cl
+ shr cl,2
+ and [DD_DR7],edx ; clear type and size bits
+;
+; Client_DX =
+; DH = 0 : execute
+; DH = 1 : write
+; DH = 2 : read/write
+;
+; DL = 1 : byte
+; DL = 2 : word
+; DL = 4 : dword
+;
+ movzx edx,[ebp.Client_DX] ; load BP size and type
+ cmp dh,0 ; execute?
+ jne SHORT @F ; no
+ mov dl,1 ; yes, force size zero
+@@:
+
+ cmp dl,4 ; check for valid values
+ ja DD_I31_Error ; size in dl is 1, 2, or 4
+ cmp dl,3
+ je DD_I31_Error
+ dec dl ; DL = 0, 1, or 3 for DR7
+ js DD_I31_Error ; len field
+
+ cmp dh,2 ; type in dh is 0, 1, or 2
+ ja DD_I31_Error
+
+ jne SHORT @F
+ inc dh ; 386 wants 3, not 2
+@@: ; DH = RWn field
+ shl dl,2
+ or dl,dh
+ xor dh,dh
+ shl edx,d7_rw0
+ shl cl,2
+ shl edx,cl
+ or [DD_DR7],edx ; set size, type
+ shr cl,2
+
+ mov edx,NOT (MASK d6_b0) ; clear triggered bit
+ rol edx,cl ; EDX = mask to clear hit
+ and [DD_DR6],edx ; clear triggered bit
+ mov [ebp.Client_BX],cx ; return address register
+ ; number as BP handle
+ or [DD_DR7],(MASK d7_ge) OR (MASK d7_le)
+ ; enable debugging
+ call Load_DBG_Regs ; load changes into debug registers
+ ret
+;
+; Function AX = 0A01h -- Clear Debug Watchpoint
+;
+; Error if Watchpoint not previously set. In that case, do nothing.
+; If Watchpoint was set, then clear enable bits, triggered bit, and
+; breakpoint address.
+;
+PUBLIC DD_I31_Clear_Watchpoint
+DD_I31_Clear_Watchpoint:
+ movzx ecx,[ebp.Client_BX]
+ cmp ecx, Num_Watchpoints
+ jnb DD_I31_Error
+
+ mov edx,(MASK d7_l0) OR (MASK d7_g0); EDX = enable DR0 mask
+ shl edx,cl
+ shl edx,cl ; EDX = enable DRn mask
+ test [DD_DR7],edx ; BP set?
+ jz DD_I31_Error ; No, error.
+ not edx
+ and [DD_DR7],edx ; disable the BP
+ mov edx,NOT (MASK d6_b0) ; EDX = DR0 not hit
+ rol edx,cl ; EDX = DRn not hit
+ and [DD_DR6],edx ; clear triggered bit
+ mov esi, OFFSET32 Debug_Regs ; ESI -> DRn table
+ shl ecx,2 ; ECX = DWORD offset
+ add esi,ecx ; ESI -> DRn
+ mov dword ptr [esi],0 ; clear address
+ mov edx,NOT((MASK d7_ln0) OR (MASK d7_rw0))
+ rol edx,cl
+ and [DD_DR7],edx
+;
+; Test whether this leaves any breakpoints active. If not, disable
+; the exact match condition. Note: the following is a long line.
+;
+ test [DD_DR7],(MASK d7_g3) OR (MASK d7_l3) OR (MASK d7_g2) OR (MASK d7_l2) OR (MASK d7_g1) OR (MASK d7_l1) OR (MASK d7_g0) OR (MASK d7_l0)
+ jne SHORT @F
+ and [DD_DR7],NOT ((MASK d7_ge) OR (MASK d7_le))
+@@:
+ call Load_DBG_Regs ; load changes into debug registers
+ ret
+;
+; Function AX = 0A02h -- Get Status of Debug Watchpoint
+;
+PUBLIC DD_I31_Get_Status
+DD_I31_Get_Status:
+ movzx ecx,[ebp.Client_BX]
+ cmp ecx, Num_Watchpoints
+ jnb SHORT DD_I31_Error
+
+ mov edx,(MASK d7_g0) OR (MASK d7_l0); EDX = DR0 enable bits
+ shl edx,cl
+ shl edx,cl ; EDX = DRn enable bits
+ test [DD_DR7],edx ; DRn enabled?
+ jz SHORT DD_I31_Error ; No, error.
+ mov edx,MASK d6_b0 ; EDX = DR0 hit mask
+ shl edx,cl ; EDX = DRn hit mask
+ xor eax,eax
+ test [DD_DR6],edx ; DRn hit?
+ jne SHORT @F ; no
+ inc al ; yes, store result
+@@:
+ mov [ebp.Client_AX],ax
+ ret
+;
+; Function AX = 0A03h -- Reset Debug Watchpoint
+;
+PUBLIC DD_I31_Reset_Watchpoint
+DD_I31_Reset_Watchpoint:
+ movzx ecx,[ebp.Client_BX]
+ cmp ecx, Num_Watchpoints
+ jnb SHORT DD_I31_Error
+
+ mov edx,(MASK d7_g0) OR (MASK d7_l0); EDX = DR0 enable bits
+ shl edx,cl
+ shl edx,cl ; EDX = DRn enable bits
+ test [DD_DR7],edx ; DRn enabled?
+ jz SHORT DD_I31_Error ; No, error.
+ mov edx,NOT (MASK d6_b0) ; EDX = DR0 hit mask
+ rol edx,cl ; EDX = DRn hit mask
+ and [DD_DR6],edx ; clear triggered bit
+ call Load_DBG_Regs ; load changes into debug registers
+ ret
+
+DD_I31_Error:
+ Assert_Client_Ptr ebp
+ or [ebp.Client_Flags], CF_Mask
+ ret
+
+EndProc I31_Debug_Register_Support
+
+
+;******************************************************************************
+;
+; Load_DBG_Regs - Load debug registers from memory.
+; Do not change undefined bits.
+;
+; ENTRY: NONE
+; EXIT: Memory image copied to debug registers, undefined bits unchanged.
+; USES: eax, ecx, edi, esi
+;
+;******************************************************************************
+
+BeginProc Load_DBG_Regs
+
+ mov esi,OFFSET32 Debug_Regs
+ DPMIBOP SetDebugRegisters
+ jnc short ldr_exit
+
+ cld
+ xor eax, eax
+ mov ecx, 6
+ mov edi, OFFSET32 Debug_Regs
+ rep stosd ;clear local copy
+ldr_exit:
+ ret
+
+EndProc Load_DBG_Regs
+
+; -------------------------------------------------------
+
+IFNDEF WOW
+;******************************************************************************
+;
+; Load_DBG_Regs - Load debug registers from memory.
+; Do not change undefined bits.
+;
+; ENTRY: NONE
+; EXIT: Memory image copied to debug registers, undefined bits unchanged.
+; USES: NONE
+;
+;******************************************************************************
+
+BeginProc Load_DBG_Regs
+
+ push esi
+ push edx
+ push eax
+
+ cld
+
+ mov esi,OFFSET32 Debug_Regs
+ lods dword ptr ds:[esi]
+ mov dr0, eax
+ lods dword ptr ds:[esi]
+ mov dr1, eax
+ lods dword ptr ds:[esi]
+ mov dr2, eax
+ lods dword ptr ds:[esi]
+ mov dr3, eax
+ lods dword ptr ds:[esi]
+ and eax,NOT DBG6_RESERVED
+ mov edx,dr6
+ and edx,DBG6_RESERVED
+ or eax,edx
+ mov dr6, eax
+.ERRNZ dd_dr6 - dd_dr3 - 4
+ lods dword ptr ds:[esi]
+ and eax,NOT DBG7_RESERVED
+ mov edx,dr7
+ and edx,DBG7_RESERVED
+ or eax,edx
+ mov dr7, eax
+
+ pop eax
+ pop edx
+ pop esi
+
+ ret
+
+EndProc Load_DBG_Regs
+
+;******************************************************************************
+;
+; Store_DBG_Regs - Copy debug registers to memory.
+;
+; ENTRY: NONE
+; EXIT: Debug registers copied to memory image.
+; Undefined bits = don't care.
+; USES: NONE
+;
+;******************************************************************************
+
+BeginProc Store_DBG_Regs
+
+ push eax
+ push edi
+
+ cld
+
+ mov edi,OFFSET32 Debug_Regs
+ mov eax, dr0
+ stos dword ptr es:[edi]
+ mov eax, dr1
+ stos dword ptr es:[edi]
+ mov eax, dr2
+ stos dword ptr es:[edi]
+ mov eax, dr3
+ stos dword ptr es:[edi]
+ mov eax, dr6
+.ERRNZ dd_dr6 - dd_dr3 - 4
+ stos dword ptr es:[edi]
+ mov eax, dr7
+ stos dword ptr es:[edi]
+
+ pop edi
+ pop eax
+
+ ret
+
+EndProc Store_DBG_Regs
+ENDIF ; WOW
+
+; -------------------------------------------------------
+endif ; NO386
+
+
+; -------------------------------------------------------
+ subttl INT 31h Raw Modeswitch Routines
+ page
+; -------------------------------------------------------
+; INT 31h Raw Modeswitch Routines
+; -------------------------------------------------------
+
+; -------------------------------------------------------
+; i31_GetSaveRestoreState -- Return Int 31h Save/Restore State addresses.
+;
+; In: none
+; Out: ax - size of buffer required to save state
+; bx:cx - real mode address used to save/restore state
+; si:di - protected mode address used to save/restore state
+;
+
+ public i31_GetStateSaveRestore
+ assume ds:DGROUP,es:DGROUP
+
+i31_GetStateSaveRestore proc near
+
+ mov [bp].intUserAX,0
+ push es
+ push SEL_DXCODE OR STD_RING
+ pop es
+ assume es:DXCODE
+ mov ax,segDXCode
+ pop es
+ assume es:DGROUP
+ mov [bp].intUserBX,ax
+ mov [bp].intUserCX,offset DXCODE:RmSaveRestoreState
+ mov [bp].intUserSI,SEL_DXPMCODE OR STD_RING
+IFDEF WOW
+ test DpmiFlags,DPMI_32BIT
+ jz gssr10
+
+ mov edi,dword ptr (offset DXPMCODE:PmSaveRestoreState)
+ENDIF
+gssr10: mov [bp].intUserDI,offset DXPMCODE:PmSaveRestoreState
+
+ jmp i31_done
+
+i31_GetStateSaveRestore endp
+
+; -------------------------------------------------------
+; i31_GetRawModeSwitch -- Return Int 31h Save/Restore State addresses.
+;
+; In: none
+; Out: bx:cx - real -> protected mode switch address
+; si:di - protected -> real mode switch address
+;
+
+ public i31_GetRawModeSwitch
+ assume ds:DGROUP,es:DGROUP
+
+i31_GetRawModeSwitch proc near
+
+ push es
+ push SEL_DXCODE OR STD_RING
+ pop es
+ assume es:DXCODE
+ mov ax,segDXCode
+ pop es
+ assume es:DGROUP
+ mov [bp].intUserBX,ax
+ mov [bp].intUserCX,offset DXCODE:RmRawModeSwitch
+ mov [bp].intUserSI,SEL_DXPMCODE OR STD_RING
+IFDEF WOW
+ test DpmiFlags,DPMI_32BIT
+ jz grms10
+
+ mov edi,dword ptr (offset DXPMCODE:PmRawModeSwitch)
+ENDIF
+grms10: mov [bp].intUserDI,offset DXPMCODE:PmRawModeSwitch
+
+ jmp i31_done
+
+i31_GetRawModeSwitch endp
+
+
+;
+; make sure 286 protect mode else code generated for mips will be wrong.
+;
+ .286p
+
+; -------------------------------------------------------
+; Service 04/f1 - Allocate Space in LDT for Selector (WOW only)
+; Don't initialize the descriptor to Zero.
+; in: cx - # selectors required
+; out: ax - *index* of first selector
+
+ assume ds:DGROUP,es:DGROUP
+ public i31_WOW_AllocSel
+
+i31_WOW_AllocSel proc near
+
+ cmp cx,1 ;1 selector or more?
+ ja @f
+
+ call AllocateSelector ;allocate 1 selector
+ jc i31_WOW_15
+ jmp short i31_WOW_10
+
+@@: mov ax,cx
+ call AllocateSelectorBlock ;allocate a block of selectors
+ jc i31_WOW_15
+
+i31_WOW_10:
+ or al,STD_TBL_RING ;add standard table/ring bits
+ mov [bp].intUserAX,ax ;return 1st/only selector in AX
+
+ jmp i31_done
+
+i31_WOW_15:
+ jmp i31_fail ;fail the request
+
+i31_WOW_AllocSel endp
+
+
+; -------------------------------------------------------
+; Service 04/f2 - Set Descriptor (WOW only)
+; in: bx - selector
+; cx - number of contiguous selectors
+
+ assume ds:DGROUP,es:DGROUP
+ public i31_WOW_SetDescriptor
+
+i31_WOW_SetDescriptor proc near
+
+ mov ax,selGDT
+ mov es,ax
+ assume es:NOTHING
+ lsl ax,ax
+
+ and bx,SELECTOR_INDEX ; input selector
+ cmp bx,ax ; range-test selector against
+ jc @F ; the limit of the GDT/LDT
+ jmp i31_fail_CY
+
+@@:
+ifndef WOW
+ ; notify dpmi32 so it can maintain FlatAddress array (MIPS case)
+ mov ax,bx
+ DPMIBOP SetDescriptorTableEntries
+else
+ cCall NWOWSetDescriptor,<cx,es,bx>
+endif ; WOW
+ jmp i31_done
+
+i31_WOW_SetDescriptor endp
+
+; -------------------------------------------------------
+; Service 04/f3 - Set Descriptor (WOW only)
+; in: bx:dx -- pointer to low memory allocation routine
+; si:di -- pointer to low memory free routine
+
+ assume ds:DGROUP,es:DGROUP
+ public i31_WOW_SetAllocFunctions
+
+i31_WOW_SetAllocFunctions proc near
+
+ mov word ptr [LowMemAllocFn],dx
+ mov word ptr [LowMemAllocFn + 2],bx
+ mov word ptr [LowMemFreeFn],di
+ mov word ptr [LowMemFreeFn + 2], si
+ jmp i31_done
+
+i31_WOW_SetAllocFunctions endp
+
+DXPMCODE ends
+
+;****************************************************************
+ end