mirror of https://github.com/tongzx/nt5src
You can not select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
2635 lines
78 KiB
2635 lines
78 KiB
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
|
|
|
|
include intmac.inc
|
|
include stackchk.inc
|
|
.list
|
|
|
|
; -------------------------------------------------------
|
|
; GENERAL SYMBOL DEFINITIONS
|
|
; -------------------------------------------------------
|
|
|
|
RealMode_SaveBP equ word ptr RealMode_EBP+4
|
|
RealMode_SaveSP equ word ptr RealMode_EBP+6
|
|
|
|
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)
|
|
I31FLAGS equ 000Dh ; 386 extender, pMode NetBIOS
|
|
I31MasterPIC equ 08h ;Master PIC Interrupts start at 08h
|
|
ifdef NEC_98
|
|
I31SlavePIC equ 10h
|
|
else ;NEC_98
|
|
I31SlavePIC equ 70h ;Slave PIC Interrupts start at 70h
|
|
endif ;NEC_98
|
|
|
|
; -------------------------------------------------------
|
|
; 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
|
|
extrn NSetSegmentLimit:near
|
|
extrn NMoveDescriptor:near
|
|
extrn NWOWSetDescriptor: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 lpfnXMSFunc:DWORD
|
|
extrn A20EnableCount:WORD
|
|
extrn regUserAX:WORD, regUserFL:WORD, regUserSS:WORD
|
|
extrn regUserSP:WORD, regUserDS:WORD, regUserES:WORD
|
|
extrn PMInt24Handler:DWORD
|
|
extrn DpmiFlags:WORD
|
|
IFDEF WOW_x86
|
|
extrn FastBop:fword
|
|
ENDIF
|
|
|
|
extrn selPspChild:WORD
|
|
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
|
|
ifdef JAPAN
|
|
justw_flag dw 0 ; for Just Window
|
|
endif ; JAPAN
|
|
DXDATA ends
|
|
|
|
; -------------------------------------------------------
|
|
; CODE SEGMENT VARIABLES
|
|
; -------------------------------------------------------
|
|
|
|
DXCODE segment
|
|
assume cs:DXCODE
|
|
|
|
extrn segDXData:WORD
|
|
extrn selDgroup:WORD
|
|
extrn segDXCode:word
|
|
|
|
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_x86
|
|
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
|
|
|
|
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
|
|
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
|
|
push cx ; save # of selector to be allocated
|
|
xor cx,cx ; allocate from lower range
|
|
call AllocateSelectorBlock ;allocate a block of selectors
|
|
pop cx
|
|
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
|
|
cCall NSetSegmentLimit,<bx>
|
|
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
|
|
ifdef JAPAN
|
|
justw_check:
|
|
endif ; JAPAN
|
|
call AllocateSelector
|
|
jc cda_failed
|
|
|
|
ifdef JAPAN
|
|
cmp [justw_flag],0
|
|
jne not_justw
|
|
mov [justw_flag],1
|
|
jmp justw_check
|
|
not_justw:
|
|
endif ; JAPAN
|
|
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
|
|
mov ah, es:[bx].cbLimitHi386
|
|
cCall NSetSegmentAccess,<bx,ax>
|
|
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
|
|
|
|
.386p
|
|
push esi
|
|
push edi
|
|
.286p
|
|
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
|
|
|
|
.386p
|
|
pop edi
|
|
pop esi
|
|
.286p
|
|
jmp i31_fail_CY ;fail if invalid selector specified
|
|
@@:
|
|
call IsSelectorFree
|
|
jc @f
|
|
|
|
.386p
|
|
pop edi
|
|
pop esi
|
|
.286p
|
|
jmp i31_fail_CY
|
|
@@:
|
|
|
|
cmp byte ptr [bp].intUserAX,SelMgt_Get_Desc ;Get or Set?
|
|
jz i31_GetDscr
|
|
|
|
;
|
|
; Set Descriptor
|
|
;
|
|
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:
|
|
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
|
|
|
|
.386p
|
|
mov cl,ds:[esi].arbSegAccess386
|
|
.286p
|
|
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
|
|
.386p
|
|
pop edi
|
|
pop esi
|
|
.286p
|
|
jmp i31_fail_CY
|
|
|
|
i31_GetDscr:
|
|
assume ds:DGROUP
|
|
;
|
|
; Get Descriptor
|
|
;
|
|
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
|
|
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:
|
|
.386p
|
|
cCall NMoveDescriptor,<ds,esi,es,edi>
|
|
.286p
|
|
i31_gs25:
|
|
pop ds
|
|
assume ds:DGROUP
|
|
|
|
.386p
|
|
pop edi
|
|
pop esi
|
|
.286p
|
|
jmp i31_done
|
|
|
|
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
|
|
ifdef JAPAN
|
|
or cx,cx
|
|
jz notdec
|
|
dec cx
|
|
notdec:
|
|
endif ; JAPAN
|
|
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
|
|
|
|
push bx
|
|
mov bx, ax ; selector
|
|
and bx,SELECTOR_INDEX ; make it index into ldt
|
|
|
|
call IsSelectorFree
|
|
pop bx
|
|
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
|
|
|
|
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]
|
|
|
|
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:
|
|
.386p
|
|
test DpmiFlags,DPMI_32BIT
|
|
jnz sfv10
|
|
|
|
movzx edx,dx ; zero high half
|
|
.286p
|
|
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
|
|
sub di,32 ; pushad
|
|
push di ; plus copy of di.
|
|
.386p
|
|
pushad ; have to save high 16 bits
|
|
.286p
|
|
|
|
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_x86
|
|
; | | |
|
|
; | 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
|
|
.386p
|
|
xor ecx,ecx
|
|
.286p
|
|
mov cx,(size Real_Mode_Call_Struc) / 2
|
|
|
|
mov bx,di ;bx used to reference client regs below
|
|
.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
|
|
mov si,[bp].pmUserDI
|
|
mov ds,[bp].pmUserES
|
|
assume ds:NOTHING
|
|
.386p
|
|
rep movs word ptr [esi],word ptr [edi]
|
|
.286p
|
|
|
|
|
|
; 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...
|
|
|
|
.386p
|
|
xor ecx,ecx
|
|
.286p
|
|
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"
|
|
|
|
.386p
|
|
xor esi,esi
|
|
.286p
|
|
mov ds,[bp].pmUserSS
|
|
mov si,[bp].pmUserSP
|
|
.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
|
|
;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?
|
|
|
|
mov ax, [bx].RealMode_Flags ;real mode routine thinks these were
|
|
and ax, NOT 100h ;remove TF
|
|
push ax
|
|
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
|
|
|
|
mov ax, [bx].RealMode_Flags ;real mode rtn entered with these flags
|
|
and ax, NOT 100h ;remove TF
|
|
push ax
|
|
@@:
|
|
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
|
|
.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
|
|
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
|
|
.386p
|
|
push ebx
|
|
.286p
|
|
|
|
mov ds,segDXData ;address our DGROUP
|
|
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
|
|
|
|
.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
|
|
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.
|
|
|
|
mov ss,segDXData ;address our DGROUP
|
|
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
|
|
.386p
|
|
xor ecx,ecx
|
|
.286p
|
|
mov cx,(size Real_Mode_Call_Struc) / 2
|
|
.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
|
|
mov si,bx
|
|
mov di,[bp].pmUserDI
|
|
mov es,[bp].pmUserES
|
|
assume es:NOTHING
|
|
.386p
|
|
rep movs word ptr [esi],word ptr [edi]
|
|
|
|
pop sp ; value calculated above
|
|
popad
|
|
mov sp,bp
|
|
.286p
|
|
|
|
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
|
|
|
|
push ax
|
|
|
|
call AllocateLDTSelector
|
|
jc acb_nosel
|
|
push [bp].pmUserDS ;pass in user's ds on stack
|
|
push [bp].pmUserES ;pass in user's es on stack
|
|
DPMIBOP AllocateRMCallBack
|
|
add sp, 4
|
|
jc acb_nocb
|
|
|
|
mov [bp].intUserCX,cx ;callback segment
|
|
mov [bp].intUserDX,dx ;callback offset
|
|
mov cx,-1
|
|
cCall NSetSegmentDscr,<ax,0,0,0,cx,STD_DATA>
|
|
pop ax
|
|
jmp i31_done
|
|
|
|
acb_nocb:
|
|
call FreeSelector
|
|
acb_nosel:
|
|
pop ax
|
|
jmp i31_fail_CY ;no call-backs available, fail
|
|
|
|
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
|
|
|
|
push ax
|
|
DPMIBOP FreeRMCallBack
|
|
jc @f
|
|
call FreeSelector
|
|
pop ax
|
|
jmp i31_done
|
|
@@:
|
|
pop ax
|
|
jmp i31_fail_CY ;no call-backs available, fail
|
|
|
|
i31_FreeCallBack endp
|
|
|
|
|
|
; -------------------------------------------------------
|
|
|
|
DXPMCODE ends
|
|
|
|
; -------------------------------------------------------
|
|
|
|
DXCODE segment
|
|
assume cs:DXCODE
|
|
|
|
;
|
|
; RMCallBackBop
|
|
;
|
|
; Originally, the real mode call back hook was implemented here in
|
|
; the 16-bit client dosx. What it did was allocate a stacklet on
|
|
; its own stack and run the PM code on that stack. So the basic
|
|
; stack layout was that the RM stack pointer was followed by approx.
|
|
; 100 bytes or so of space, and then you started on the PM stack
|
|
; (corresponding to the start of the next stacklet).
|
|
;
|
|
; This whole approach was basically broken, since apps don't expect
|
|
; this. For example, the DOS4GW dos extender, which is used by a
|
|
; lot of games, switches stacks immediately in the PM callback proc
|
|
; from the protect mode stack to the real mode stack. That is, they
|
|
; use the same contiguous stack for both real mode and protect mode.
|
|
; What happens then with the original design is that the protect mode
|
|
; code, depending on how deep it goes on the stack, ends up overwriting
|
|
; the new stacklet further down, so we lose the return information
|
|
; needed to get back from the PM callback proc.
|
|
;
|
|
; The new design is just to do it in the unobtrusive dpmi32 host,
|
|
; including switching to a real PM stack. So here we just bop out
|
|
; to perform the switch and PM call.
|
|
;
|
|
|
|
public RMCallBackBop
|
|
RMCallBackBop proc far
|
|
DPMIBOP RMCallBackCall
|
|
ret ;finished!
|
|
RMCallBackBop 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_x86
|
|
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_x86
|
|
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_x86
|
|
;******************************************************************************
|
|
;
|
|
; 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_x86
|
|
|
|
; -------------------------------------------------------
|
|
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
|
|
test DpmiFlags,DPMI_32BIT
|
|
jz gssr10
|
|
|
|
mov edi,dword ptr (offset DXPMCODE:PmSaveRestoreState)
|
|
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
|
|
test DpmiFlags,DPMI_32BIT
|
|
jz grms10
|
|
|
|
mov edi,dword ptr (offset DXPMCODE:PmRawModeSwitch)
|
|
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 ;WOW, cx != 0, allocate from higher range
|
|
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
|
|
|
|
@@:
|
|
cCall NWOWSetDescriptor,<cx,es,bx>
|
|
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
|