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.
4218 lines
125 KiB
4218 lines
125 KiB
PAGE ,132
|
|
TITLE Windows Protect Mode Routines
|
|
|
|
.xlist
|
|
include kernel.inc
|
|
|
|
.386p
|
|
|
|
include protect.inc
|
|
include pdb.inc
|
|
.list
|
|
|
|
ifdef WOW
|
|
|
|
;
|
|
; the dpmi func 04f1h is idential to function 00h, except that
|
|
; the descriptor base and limit are not initialized to zero.
|
|
;
|
|
|
|
;
|
|
; the dpmi func 04f2h is identical to 0ch except that it
|
|
; sets 'count' (in cx) LDTs at one time. The first selector is in
|
|
; register bx. The descriptor data is in gdtdsc[bx], gdtdsc[bx+8]
|
|
; etc. This data is shared between dpmi (dosx.exe) and us and thus
|
|
; need not be passed in es:di
|
|
|
|
WOW_DPMIFUNC_00 equ 04f1h
|
|
WOW_DPMIFUNC_0C equ 04f2h
|
|
|
|
|
|
endif
|
|
|
|
|
|
MovsDsc Macro ;Move (copy) a descriptor (4 words)
|
|
cld
|
|
movsd
|
|
movsd
|
|
endm
|
|
|
|
CheckDS Macro
|
|
local okds
|
|
if KDEBUG
|
|
push ax
|
|
mov ax, ds
|
|
SetKernelDS
|
|
cmp ax, ArenaSel
|
|
mov ds, ax
|
|
UnSetKernelDS
|
|
je short okds
|
|
int 3
|
|
int 3
|
|
okds:
|
|
pop ax
|
|
endif
|
|
endm
|
|
|
|
CheckLDT Macro selector
|
|
if KDEBUG
|
|
test selector,SEL_LDT
|
|
jnz short @F
|
|
int 3
|
|
@@:
|
|
endif
|
|
Endm
|
|
|
|
DPMICALL MACRO callno
|
|
mov ax, callno
|
|
call DPMIProc
|
|
ENDM
|
|
|
|
|
|
MY_SEL equ 0F00h ; Access word to indicate selector owned by kernel
|
|
|
|
externW pLocalHeap
|
|
|
|
DataBegin
|
|
|
|
ifdef WOW
|
|
externW SelectorFreeBlock
|
|
externW UserSelArray
|
|
externB fBooting
|
|
globalW high0c,0
|
|
globalD FlatAddressArray,0
|
|
endif
|
|
|
|
|
|
externW MyCSSeg
|
|
externW WinFlags
|
|
externW ArenaSel
|
|
externW pGlobalHeap
|
|
|
|
externW MyCSAlias
|
|
|
|
extrn kr1dsc:WORD
|
|
extrn kr2dsc:WORD
|
|
extrn blotdsc:WORD
|
|
extrn DemandLoadSel:WORD
|
|
extrn FreeArenaList:DWORD
|
|
extrn FreeArenaCount:DWORD
|
|
extrn HighestArena:DWORD
|
|
extrn temp_arena:DWORD
|
|
extrn SelTableLen:word
|
|
extrn SelTableStart:DWORD
|
|
extrn temp_sel:WORD
|
|
extrn FirstFreeSel:WORD
|
|
extrn CountFreeSel:WORD
|
|
|
|
DataEnd
|
|
|
|
DataBegin INIT
|
|
|
|
RModeCallStructure STRUC
|
|
RMCS_EDI dd 0
|
|
RMCS_ESI dd 0
|
|
RMCS_EBP dd 0
|
|
RMCS_Res dd 0
|
|
RMCS_EBX dd 0
|
|
RMCS_EDX dd 0
|
|
RMCS_ECX dd 0
|
|
RMCS_EAX dd 0
|
|
RMCS_Flags dw 0
|
|
RMCS_ES dw 0
|
|
RMCS_DS dw 0
|
|
RMCS_FS dw 0
|
|
RMCS_GS dw 0
|
|
RMCS_IP dw 0
|
|
RMCS_CS dw 0
|
|
RMCS_SP dw 0
|
|
RMCS_SS dw 0
|
|
RModeCallStructure ENDS
|
|
|
|
MyCallStruc RModeCallStructure <>
|
|
|
|
globalD lpProc,0
|
|
|
|
public MS_DOS_Name_String
|
|
MS_DOS_Name_String db "MS-DOS", 0
|
|
|
|
DataEnd INIT
|
|
|
|
externFP IGlobalFree
|
|
externFP IGlobalAlloc
|
|
ifdef WOW
|
|
externFP kSYSERRORBOX
|
|
externFP VirtualAlloc
|
|
endif
|
|
|
|
sBegin CODE
|
|
assumes cs,CODE
|
|
assumes ds,nothing
|
|
|
|
|
|
externNP genter
|
|
extrn GrowHeapDib: FAR
|
|
extrn LocalNotifyDib: FAR
|
|
extrn LocalNotifyDefault: FAR
|
|
extrn FreeHeapDib: FAR
|
|
externNP gleave
|
|
extrn IGlobalFix:FAR ;Far calls in this segment
|
|
extrn GlobalHandleNorip:FAR
|
|
extrn IGlobalFlags:FAR
|
|
extrn IGlobalHandle: FAR
|
|
extrn Free_Object2: FAR
|
|
|
|
extrn mycsds:WORD
|
|
|
|
extrn gdtdsc:WORD
|
|
|
|
ifdef WOW
|
|
externD prevInt31proc
|
|
endif
|
|
|
|
|
|
sEnd CODE
|
|
|
|
sBegin INITCODE
|
|
assumes cs,CODE
|
|
assumes ds,nothing
|
|
|
|
;=======================================================================;
|
|
; ;
|
|
; 386 PROTECTED MODE INITIALISATION ROUTINES ;
|
|
; ;
|
|
;=======================================================================;
|
|
|
|
; this function is not used in ROM since DOSX switches to Pmode before
|
|
; jumping to kernel. this means the enhanced mode loader will have
|
|
; to do something similar...
|
|
|
|
;-----------------------------------------------------------------------;
|
|
; SwitchToPMODE ;
|
|
; ;
|
|
; Entry: ;
|
|
; In Real or Virtual Mode ;
|
|
; ES -> PSP ;
|
|
; ;
|
|
; Returns: ;
|
|
; In Protect Mode ;
|
|
; BX -> LDT selector ;
|
|
; SI -> Segment of start of available memory ;
|
|
; ES -> PSP ;
|
|
; ;
|
|
; Error Returns: ;
|
|
; Exits via DOS call 4Ch ;
|
|
; ;
|
|
; Registers Preserved: ;
|
|
; ;
|
|
; ;
|
|
; Registers Destroyed: ;
|
|
; ;
|
|
; Calls: ;
|
|
; ;
|
|
; History: ;
|
|
; ;
|
|
;-----------------------------------------------------------------------;
|
|
|
|
assumes ds,DATA
|
|
assumes es,nothing
|
|
|
|
|
|
cProc SwitchToPMODE,<PUBLIC,NEAR>
|
|
cBegin nogen
|
|
|
|
push cx
|
|
push es ; Current PSP
|
|
|
|
mov ax, 1687h
|
|
int 2Fh ; Get PMODE switch entry
|
|
or ax, ax ; Can we do it?
|
|
jnz NoPMODE
|
|
|
|
xor bh, bh ; Set CPU type now
|
|
cmp cl, 3 ; At least a 386?
|
|
jb NoPMODE
|
|
|
|
mov bl,WF_CPU386
|
|
je short @F ; If 386
|
|
mov bl,WF_CPU486 ; No, assume 486 for now
|
|
@@:
|
|
mov WinFlags, bx ; Save away CPU type
|
|
mov word ptr [lpProc][0], di
|
|
mov word ptr [lpProc][2], es
|
|
pop ax ; PSP
|
|
add ax, 10h ; Skip the PSP
|
|
mov es, ax ; Give this to the DOS extender
|
|
add si, ax ; Start of memory available to us
|
|
|
|
; THIS IS IT FOLKS!
|
|
xor ax, ax ; 16-bit app
|
|
call [lpProc] ; Switch to PROTECTED mode
|
|
jc NoPMODE ; No, still Real/Virtual mode
|
|
|
|
mov ax, cs
|
|
and al, 7 ; LDT, Ring 3
|
|
cmp al, 7
|
|
jne short BadDPMI ; Insist on Ring 3!
|
|
|
|
mov bx, cs ; Allocate CS Alias
|
|
DPMICALL 000Ah
|
|
|
|
mov MyCSAlias, ax ; Save CS Alias in DS
|
|
|
|
mov bx, ds ; Use alias to update code seg var
|
|
mov ds, ax
|
|
assumes ds, CODE
|
|
|
|
mov MyCSDS, bx ; The DS selector
|
|
|
|
mov ds, bx
|
|
ReSetKernelDS
|
|
|
|
push es
|
|
push si
|
|
mov ax, 168Ah ; See if we have MS-DOS extensions
|
|
mov si, dataoffset MS_DOS_Name_String
|
|
int 2Fh ; DS:SI -> MS-DOS string
|
|
cmp al, 8Ah ; Have extensions?
|
|
je short BadDPMI ; no extensions, screwed
|
|
|
|
mov [lpProc][0], di ; Save CallBack address
|
|
mov [lpProc][2], es
|
|
|
|
mov ax, 0100h ; Get base of LDT
|
|
call [lpProc]
|
|
jc short NoLDTParty
|
|
verw ax ; Writeable?
|
|
jnz short NoLDTParty ; nope, don't bother with it yet
|
|
|
|
mov es, MyCSAlias
|
|
assumes es,CODE
|
|
mov gdtdsc, ax
|
|
assumes es,nothing
|
|
|
|
NoLDTParty:
|
|
pop si
|
|
pop es
|
|
|
|
push si ; Unlock all of our memory
|
|
ifndef WOW ; For WOW its all pageable
|
|
movzx ebx, si
|
|
shl ebx, 4 ; Linear address of start of our memory
|
|
movzx esi, es:[PDB_block_len] ; End of our memory
|
|
shl esi, 4
|
|
sub esi, ebx ; Size of our block
|
|
mov di, si
|
|
shr esi, 10h
|
|
mov cx, bx
|
|
shr ebx, 10h
|
|
mov ax, 0602h
|
|
int 31h ; Mark region as pageable.
|
|
endif
|
|
pop bx
|
|
mov ax, 2 ; Convert start of memory to selector
|
|
int 31h
|
|
mov si, ax
|
|
|
|
xor bx, bx
|
|
pop cx
|
|
ret
|
|
|
|
BadDPMI:
|
|
;
|
|
; Call real/virtual mode to whine
|
|
;
|
|
xor cx, cx ; Nothing on stack to copy
|
|
xor bh, bh ; Flags to DPMI
|
|
mov ax, MyCSSeg
|
|
mov MyCallStruc.RMCS_DS, ax ; Real mode DS will be parent PDB
|
|
mov MyCallStruc.RMCS_ES, cx ; Real mode ES will be 0
|
|
mov MyCallStruc.RMCS_CS, ax ; Real mode CS
|
|
mov MyCallStruc.RMCS_IP, codeoffset RModeCode ; Real mode IP
|
|
|
|
smov es, ds
|
|
mov di, dataOffset MyCallStruc ; ES:DI points to call structure
|
|
mov ax, 0301h ; Call Real Mode Procedure
|
|
int 31h
|
|
jmps GoodBye
|
|
|
|
RModeCode:
|
|
mov dx, codeoffset szInadequate
|
|
mov ah, 9
|
|
int 21h
|
|
retf
|
|
|
|
;Inadequate:
|
|
; DB 'KRNL386: Inadequate DPMI Server',13,10,'$'
|
|
externB <szNoPMode, szInadequate>
|
|
|
|
NoPMODE: ; NOTE: stack trashed...
|
|
ifdef WOW
|
|
;** Put Up a Dialog Box If we fail to Enter Protect Mode
|
|
;** Prepare the dialog box
|
|
push cs ;In our DS
|
|
push codeOFFSET szNoPMode ; -> unable to enter Prot Mode
|
|
|
|
push ds
|
|
externB <syserr>
|
|
push dataOffset syserr ;Caption
|
|
|
|
push 0 ;No left button
|
|
|
|
push SEB_CLOSE + SEB_DEFBUTTON ;Button 1 style
|
|
|
|
push 0 ;No right button
|
|
|
|
call kSYSERRORBOX ;Put up the system error message
|
|
externNP ExitKernel
|
|
jmp ExitKernel
|
|
|
|
else ; Not WOW
|
|
|
|
mov dx, codeoffset szNoPMode
|
|
; call complain
|
|
; DB 'KRNL386: Unable to enter Protected Mode',13,10,'$'
|
|
;complain:
|
|
; pop dx
|
|
push cs
|
|
pop ds ; DS:DX -> error message
|
|
mov ah,9 ; Print error message
|
|
int 21h
|
|
|
|
endif; WOW
|
|
|
|
GoodBye:
|
|
mov ax, 4CFFh
|
|
int 21h
|
|
cEnd nogen
|
|
|
|
;-----------------------------------------------------------------------;
|
|
; LDT_Init ;
|
|
; ;
|
|
; Entry: ;
|
|
; DS -> CS ;
|
|
; ;
|
|
; Returns: ;
|
|
; ;
|
|
; Error Returns: ;
|
|
; ;
|
|
; Registers Preserved: ;
|
|
; AX,BX,CX,DX,DI,SI,DS,ES ;
|
|
; ;
|
|
; Registers Destroyed: ;
|
|
; ;
|
|
; Calls: ;
|
|
; ;
|
|
; History: ;
|
|
; ;
|
|
;-----------------------------------------------------------------------;
|
|
|
|
|
|
cProc LDT_Init,<PUBLIC,NEAR>,<ax,bx,cx,di,es>
|
|
cBegin
|
|
ReSetKernelDS
|
|
|
|
cmp gdtdsc, 0
|
|
jz short SlowAllocation
|
|
;
|
|
; Scan LDT for free selectors and
|
|
; put on a linked list
|
|
;
|
|
mov es, gdtdsc
|
|
mov cx, 1
|
|
DPMICALL 0000h ; Get selector from win386
|
|
and al, NOT SEG_RING_MASK
|
|
mov FirstFreeSel, ax ; Set up header
|
|
mov si, ax
|
|
mov word ptr es:[si], -1
|
|
mov word ptr es:[si].dsc_access, MY_SEL ; MINE!
|
|
|
|
mov cx, es
|
|
lsl ecx, ecx ; limit of LDT
|
|
xor eax, eax
|
|
|
|
steal_sels:
|
|
mov di, si ; prev selector in list
|
|
not_this_one:
|
|
add si, DSC_LEN ; use add for flags
|
|
jz short end_ldt
|
|
cmp si, cx
|
|
ja short end_ldt
|
|
|
|
cmp dword ptr es:[si], eax
|
|
jne not_this_one
|
|
cmp dword ptr es:[si][4], eax
|
|
jne not_this_one
|
|
|
|
mov word ptr es:[di], si ; Link into list
|
|
mov word ptr es:[si].dsc_access, MY_SEL ; MINE!
|
|
inc CountFreeSel
|
|
jmps steal_sels
|
|
|
|
end_ldt:
|
|
mov word ptr es:[di], -1
|
|
SlowAllocation:
|
|
|
|
push es ; Get random selectors
|
|
smov es, ds
|
|
ReSetKernelDS es
|
|
UnSetKernelDS
|
|
; Could get 3 selectors at once here,
|
|
; but get_sel is more efficient for just 1
|
|
mov cx, 1 ; Argument to get_sel
|
|
call get_sel
|
|
or si, SEG_RING
|
|
mov kr1dsc, si
|
|
call get_sel
|
|
mov kr2dsc, si
|
|
call get_sel
|
|
mov blotdsc, si
|
|
call get_sel
|
|
or si, SEG_RING
|
|
mov DemandLoadSel, si ; for demand loading segments
|
|
smov ds, es
|
|
pop es
|
|
UnSetKernelDS es
|
|
cEnd
|
|
|
|
sEnd INITCODE
|
|
|
|
sBegin CODE
|
|
assumes cs,CODE
|
|
assumes ds,nothing
|
|
|
|
|
|
;=======================================================================;
|
|
; ;
|
|
; SELECTOR ALLOCATION/DEALLOCATION ROUTINES ;
|
|
; ;
|
|
;=======================================================================;
|
|
|
|
|
|
;-----------------------------------------------------------------------;
|
|
; AllocSelector
|
|
;
|
|
;
|
|
; Entry:
|
|
;
|
|
; Returns:
|
|
; AX = 0 if out of selectors
|
|
;
|
|
; Registers Destroyed:
|
|
;
|
|
; History:
|
|
; Thu 08-Dec-1988 14:17:38 -by- David N. Weise [davidw]
|
|
; Wrote it!
|
|
;-----------------------------------------------------------------------;
|
|
|
|
assumes ds,nothing
|
|
assumes es,nothing
|
|
|
|
ifdef WOW
|
|
labelFP <PUBLIC,AllocSelectorWOW>
|
|
mov ax, 1
|
|
jmps AllocSelectorWorker
|
|
|
|
labelFP <PUBLIC,AllocSelector>
|
|
xor ax, ax
|
|
; fall through
|
|
|
|
cProc AllocSelectorWorker,<PUBLIC,FAR>,<di,si,es>
|
|
parmW selector
|
|
localV OldDsc,DSC_LEN
|
|
localW fDontSetDescriptor
|
|
cBegin
|
|
mov fDontSetDescriptor, ax
|
|
else
|
|
cProc AllocSelector,<PUBLIC,FAR>,<di,si,es>
|
|
parmW selector
|
|
localV OldDsc,DSC_LEN
|
|
cBegin
|
|
|
|
endif
|
|
|
|
mov cx, 1
|
|
lsl ecx, dword ptr selector
|
|
jz short as_present
|
|
|
|
call get_sel ; He passed in some junk, give him
|
|
ifdef WOW ; just one selector...
|
|
; If we have a good selector, use DPMI to write it through to the
|
|
; system LDT before giving it to an application to use.
|
|
jz short as_exit1
|
|
mov ax, [bp+4] ; Get caller CS.
|
|
cmp ax, IGROUP ; Don't write thru if it's KRNL386 calling.
|
|
je short as_exit
|
|
cmp ax, _NRESTEXT
|
|
je short as_exit
|
|
cmp ax, _MISCTEXT
|
|
je short as_exit
|
|
|
|
;Set shadow LDT entry to known state.
|
|
push bx
|
|
push ds
|
|
mov ds, gdtdsc ; Get shadow LDT in DS
|
|
UnSetKernelDS
|
|
mov bx, si
|
|
|
|
mov [bx].dsc_limit, 00h ; Set entry to: BASE = 0, LIMIT = 0, BYTES,
|
|
mov [bx].dsc_lbase, 00h ; DPL = 3, PRESENT, DATA
|
|
mov [bx].dsc_mbase, 00h
|
|
mov [bx].dsc_hbase, 00h
|
|
mov ax, DSC_DATA+DSC_PRESENT
|
|
mov word ptr [bx].dsc_access, ax
|
|
pop ds
|
|
|
|
DPMICALL WOW_DPMIFUNC_0C ; Write shadow LDT entry thru to system LDT.
|
|
pop bx
|
|
jmps as_exit
|
|
else
|
|
jnz short as_exit ; just one selector...
|
|
jmps as_exit1
|
|
endif
|
|
|
|
as_present:
|
|
Limit_To_Selectors ecx
|
|
|
|
call get_sel
|
|
jz short as_exit1
|
|
ifdef WOW
|
|
test fDontSetDescriptor, 1
|
|
jnz as_exit
|
|
endif
|
|
smov es, ss
|
|
lea di, OldDsc ; ES:DI points to descriptor
|
|
mov bx, selector ; BX gets old selector
|
|
|
|
push ds
|
|
mov ds, gdtdsc
|
|
push si ; Get Descriptor
|
|
mov si, bx
|
|
and si, not 7
|
|
MovsDsc
|
|
lea di, [di-DSC_LEN] ; Restore DI
|
|
pop si
|
|
pop ds
|
|
mov bx, si ; BX gets new selector
|
|
or bl, SEG_RING
|
|
|
|
call fill_in_selector_array ; and set new array to match
|
|
|
|
as_exit:
|
|
or si, SEG_RING
|
|
as_exit1:
|
|
mov ax,si
|
|
cEnd
|
|
|
|
;-----------------------------------------------------------------------;
|
|
; AllocResSelArray - Allocate a resource Selector array (see resaux) ;
|
|
; Combination of AllocSelectorArray + SetResourceOwner;
|
|
; Entry: ;
|
|
; nSels = # selectors required ;
|
|
; parmW owner ;
|
|
; ;
|
|
; ;
|
|
; ;
|
|
; get_sel - get an array of selectors ;
|
|
; ;
|
|
; Entry: ;
|
|
; CX = # selectors required ;
|
|
; ;
|
|
; Returns: ;
|
|
; SI = First Selector ;
|
|
; DS = LDT ;
|
|
; ZF = 0 ;
|
|
; ;
|
|
; Error Returns: ;
|
|
; SI = 0 ;
|
|
; ZF = 1 ;
|
|
; ;
|
|
; Registers Preserved: ;
|
|
; DI,ES ;
|
|
; ;
|
|
; Registers Destroyed: ;
|
|
; ;
|
|
; Calls: ;
|
|
; ;
|
|
; History: ;
|
|
; mattfe March 30th 1993 - WOW Specific Routine, by combining the two ;
|
|
; routines I can reduce the number of DPMI calls by 40/1 for loading ;
|
|
; a typical app. ;
|
|
;-----------------------------------------------------------------------;
|
|
ifdef WOW
|
|
|
|
assumes ds, nothing
|
|
assumes es, nothing
|
|
|
|
cProc AllocResSelArray,<PUBLIC,NEAR>,<cx,si,di,es,ds>
|
|
parmW nSels
|
|
parmW owner
|
|
cBegin
|
|
mov cx, nSels
|
|
call get_sel
|
|
mov ax, si
|
|
jz short ARSA_fail
|
|
|
|
or si, SEG_RING
|
|
mov bx, si
|
|
|
|
mov dx, cx
|
|
|
|
push ds
|
|
mov ds, gdtdsc
|
|
push bx
|
|
and bl, not 7
|
|
|
|
;; For the first selector mark it with the resource owner
|
|
|
|
mov cx, owner
|
|
mov ds:[bx].dsc_owner, cx
|
|
mov word ptr ds:[bx].dsc_access, (DSC_DISCARDABLE SHL 8) + DSC_DATA
|
|
mov cx,nSels
|
|
mov ds:[bx].dsc_hbase, cl ; Save number of selectors here
|
|
|
|
mov cx, DSC_DATA+DSC_PRESENT
|
|
|
|
lea bx, [bx+DSC_LEN]
|
|
dec dx
|
|
jz ASRA_CallNT
|
|
|
|
ARSA_fill_in_access:
|
|
mov word ptr ds:[bx].dsc_access, cx
|
|
lea bx, [bx+DSC_LEN]
|
|
dec dx
|
|
jnz ARSA_fill_in_access
|
|
|
|
ASRA_CallNT:
|
|
mov bx,si ; First Selector
|
|
mov cx,nSels ; Count
|
|
DPMICALL WOW_DPMIFUNC_0C
|
|
|
|
SetKernelDS
|
|
mov ds, pGlobalHeap
|
|
UnSetKernelDS
|
|
cCall AssociateSelector32,<si,0,owner> ; And save in selector table
|
|
pop ax ; Return first sel
|
|
pop ds
|
|
|
|
ARSA_fail:
|
|
cEnd
|
|
endif ; WOW
|
|
|
|
|
|
;-----------------------------------------------------------------------;
|
|
; AllocSelectorArray - external entry for get_sel ;
|
|
; Entry: ;
|
|
; nSels = # selectors required ;
|
|
; ;
|
|
; get_sel - get an array of selectors ;
|
|
; ;
|
|
; Entry: ;
|
|
; CX = # selectors required ;
|
|
; ;
|
|
; Returns: ;
|
|
; SI = First Selector ;
|
|
; DS = LDT ;
|
|
; ZF = 0 ;
|
|
; ;
|
|
; Error Returns: ;
|
|
; SI = 0 ;
|
|
; ZF = 1 ;
|
|
; ;
|
|
; Registers Preserved: ;
|
|
; DI,ES ;
|
|
; ;
|
|
; Registers Destroyed: ;
|
|
; ;
|
|
; Calls: ;
|
|
; ;
|
|
; History: ;
|
|
; ;
|
|
;-----------------------------------------------------------------------;
|
|
|
|
assumes ds, nothing
|
|
assumes es, nothing
|
|
|
|
cProc AllocSelectorArray,<PUBLIC,FAR>,<si>
|
|
parmW nSels
|
|
cBegin
|
|
mov cx, nSels
|
|
call get_sel
|
|
mov ax, si
|
|
jz short asa_fail
|
|
|
|
or si, SEG_RING
|
|
mov bx, si
|
|
mov dx, cx
|
|
mov cx, DSC_DATA+DSC_PRESENT
|
|
ifdef WOW ; LATER should use single op to update
|
|
fill_in_access: ; complete LDT with one call.
|
|
DPMICALL 0009h
|
|
lea bx, [bx+DSC_LEN]
|
|
dec dx
|
|
jnz fill_in_access
|
|
else
|
|
push ds
|
|
mov ds, gdtdsc
|
|
push bx
|
|
and bl, not 7
|
|
fill_in_access:
|
|
mov word ptr ds:[bx].dsc_access, cx
|
|
lea bx, [bx+DSC_LEN]
|
|
dec dx
|
|
jnz fill_in_access
|
|
pop bx
|
|
pop ds
|
|
endif; WOW
|
|
mov ax, si
|
|
|
|
|
|
asa_fail:
|
|
cEnd
|
|
|
|
if KDEBUG
|
|
cProc check_free_sel_list,<PUBLIC,NEAR>
|
|
cBegin
|
|
pushf
|
|
pusha
|
|
push ds
|
|
|
|
call SetKernelDSProc ; Must call direct in this file
|
|
ReSetKernelDS
|
|
|
|
mov cx, CountFreeSel
|
|
cmp cx, 2 ; Only check list with more than 1 entry.
|
|
jb cfl_ok
|
|
inc cx ; Count dummy entry.
|
|
mov si, FirstFreeSel ; Pointer to head of list
|
|
mov ds, gdtdsc ; Get shadow LDT in DS
|
|
UnSetKernelDS
|
|
|
|
cfl_loop:
|
|
mov ax, word ptr [si] ; Get next.
|
|
cmp ax, 0FFFFH ; -1 is sentinal
|
|
je short cfl_trashed
|
|
mov di, si ; Save prev. for debugging.
|
|
mov si, ax
|
|
loop cfl_loop
|
|
mov ax, word ptr [si] ; Get sentinal.
|
|
|
|
cfl_done:
|
|
cmp ax, 0FFFFH ; -1 is sentinal
|
|
je short cfl_ok ; Must have sentinal and
|
|
cfl_trashed:
|
|
kerror 0, <Free sel list is trashed>
|
|
|
|
cfl_ok:
|
|
pop ds
|
|
popa
|
|
popf
|
|
cEnd
|
|
endif
|
|
|
|
cProc get_sel,<PUBLIC,NEAR>
|
|
localW MySel
|
|
cBegin
|
|
pusha
|
|
gs_retry_get_sel:
|
|
call SetKernelDSProc ; Must call direct in this file
|
|
ReSetKernelDS
|
|
|
|
mov si, FirstFreeSel ; Pointer to head of list
|
|
mov ds, gdtdsc
|
|
UnSetKernelDS
|
|
mov dx, cx ; Sels wanted
|
|
|
|
mov ax, word ptr [si]
|
|
inc ax ; -1 teminated
|
|
jz short gs_searchfailed
|
|
|
|
if KDEBUG
|
|
call check_free_sel_list
|
|
endif
|
|
|
|
cmp cx, 1 ; One selector only?
|
|
jne short gs_selblock
|
|
|
|
dec ax
|
|
mov di, ax
|
|
mov word ptr [di].dsc_access, DSC_USED ; Mark it used
|
|
mov di, word ptr [di] ; Unlink it
|
|
mov word ptr [si], di
|
|
mov si, ax
|
|
jmp got_my_sel
|
|
|
|
gs_selblock: ; Following stolen from DOSX
|
|
mov bx, si ; Start of list of free sels
|
|
lea si, [si+DSC_LEN] ; Start search here!
|
|
mov di, ds
|
|
lsl di, di ; limit of LDT
|
|
and di, NOT 7
|
|
gs_jail:
|
|
mov ax, si ; Starting selector
|
|
mov cx, dx ; number to check
|
|
gs_sb0:
|
|
cmp word ptr ds:[si].dsc_access, MY_SEL ; This one free?
|
|
jnz short gs_sb1 ; nope, keep looking
|
|
|
|
lea si, [si+DSC_LEN]
|
|
cmp si, di ; Falling off the end?
|
|
jae short gs_searchfailed
|
|
loop gs_sb0 ; All we wanted?
|
|
jmps gs_gotblock
|
|
|
|
gs_sb1:
|
|
lea si, [si+DSC_LEN] ; Restart scan after this selector
|
|
cmp si, di
|
|
jb short gs_jail
|
|
jmps gs_searchfailed
|
|
; Got our block, now blast them out
|
|
gs_gotblock: ; of the free list
|
|
mov cx, dx ; # selectors
|
|
push cx
|
|
shl dx, 3 ; Length of our array of selectors
|
|
add dx, ax ; First selector after our array
|
|
mov si, [bx] ; Next selector in free list
|
|
gs_blast:
|
|
inc si
|
|
jz short gs_blasted ; Gone thru whole list
|
|
dec si
|
|
cmp si, ax ; See if in range
|
|
jb short gs_noblast
|
|
cmp si, dx
|
|
jb short gs_unlink
|
|
gs_noblast:
|
|
mov bx, si
|
|
mov si, [si] ; Follow the link
|
|
jmps gs_blast
|
|
|
|
gs_unlink: ; This one is in range
|
|
mov si, [si] ; Unlink it
|
|
mov [bx], si
|
|
loop gs_blast ; Stop search when unlinked them all
|
|
|
|
gs_blasted:
|
|
pop cx
|
|
mov si, ax
|
|
lea si, [si].dsc_access ; Now mark them used
|
|
gs_markused:
|
|
mov byte ptr [si], DSC_USED
|
|
lea si, [si+DSC_LEN]
|
|
cmp si, dx
|
|
jb short gs_markused
|
|
|
|
mov si, ax
|
|
jmps got_my_sel
|
|
|
|
gs_searchfailed: ; Failed from our list, try WIN386
|
|
mov cx, dx
|
|
|
|
;;;%out Take me out later
|
|
;;; mov ds, gdtdsc
|
|
;;; UnSetKernelDS
|
|
|
|
gs_slow:
|
|
ifdef WOW
|
|
;; Calling DPMI to do anything is very slow, so lets grab at minimum 256
|
|
;; selectors at a time, that way we don't have to call again for a while
|
|
|
|
call SetKernelDSProc ; Must call direct in this file
|
|
ReSetKernelDS
|
|
|
|
push cx
|
|
test fbooting,1 ; Don't do optimization during boot
|
|
; since free_Sel will return them to
|
|
; DPMI.
|
|
jnz gs_0100
|
|
|
|
add cx,256 ; get more than we need
|
|
|
|
DPMICALL 0000h
|
|
jc gs_0100 ; Failed, then just grab the required
|
|
mov bx, ax ; number.
|
|
gs_free_loop:
|
|
cCall free_sel,<bx> ; Got the selectors, put them on
|
|
lea bx, [bx+DSC_LEN] ; our free list the easy way...
|
|
loop gs_free_loop
|
|
pop cx
|
|
jmp gs_retry_get_sel
|
|
|
|
gs_0100:
|
|
pop cx
|
|
endif; WOW
|
|
DPMICALL 0000h ; Call DPMI to get one
|
|
and al, NOT SEG_RING_MASK
|
|
mov si, ax
|
|
|
|
or si, si ; Did we get it?
|
|
jnz short got_dpmi_sel
|
|
if KDEBUG
|
|
push es
|
|
pusha
|
|
krDebugOut DEB_WARN, "Out of selectors"
|
|
popa
|
|
pop es
|
|
jmp gs_exit
|
|
else
|
|
jmps gs_exit
|
|
endif
|
|
|
|
; Try to avoid running out of selectors under Enhanced mode by keeping
|
|
; 256 selectors free. This will hopefully allow win386 to grow the
|
|
; LDT while there is still memory to do so.
|
|
|
|
got_my_sel:
|
|
SetKernelDS
|
|
sub CountFreeSel, cx
|
|
ifndef WOW
|
|
;; See above WOW code which grabs chunks of 256 selectors from DOSX
|
|
;; we don't need to do this.
|
|
test byte ptr WinFlags, WF_ENHANCED ; Standard mode can't grow the
|
|
jz got_either_sel ; LDT so don't bother
|
|
cmp CountFreeSel, 256
|
|
jae got_either_sel
|
|
lsl bx, gdtdsc ; LDT already full size?
|
|
cmp bx, 0F000h
|
|
ja got_either_sel
|
|
push ax
|
|
push cx
|
|
mov cx, 256
|
|
DPMICALL 0000h
|
|
jc gs_after_free
|
|
mov bx, ax
|
|
gs_free_it:
|
|
cCall free_sel,<bx> ; Got the selectors, put them on
|
|
lea bx, [bx+DSC_LEN] ; our free list the easy way...
|
|
loop gs_free_it
|
|
gs_after_free:
|
|
pop cx
|
|
pop ax
|
|
endif; NOT WOW
|
|
jmps got_either_sel
|
|
|
|
got_dpmi_sel:
|
|
SetKernelDS
|
|
|
|
got_either_sel:
|
|
cmp SelTableLen, 0
|
|
je short gs_exit ; Not set yet
|
|
push eax
|
|
.ERRNZ DSC_LEN-8
|
|
lea eax, [esi+ecx*DSC_LEN][-DSC_LEN] ; AX has last selector
|
|
shr ax, 1 ; ignore high word...
|
|
cmp ax, SelTableLen
|
|
pop eax
|
|
jb short gs_exit ; Can associate this selector
|
|
|
|
if KDEBUG
|
|
int 3
|
|
endif
|
|
mov bx, si
|
|
xor si, si
|
|
or bl, SEG_RING
|
|
as_free:
|
|
DPMICALL 0001h ; Free selector
|
|
; Give to WIN386 since we can't use it
|
|
lea bx, [bx+DSC_LEN]
|
|
loop as_free
|
|
|
|
gs_exit:
|
|
mov ds, gdtdsc
|
|
UnSetKernelDS
|
|
|
|
mov MySel, si
|
|
popa
|
|
mov si, MySel
|
|
or si, si ; Set ZF for caller
|
|
cEnd
|
|
|
|
|
|
;-----------------------------------------------------------------------;
|
|
; alloc_disc_data_sel
|
|
; alloc_data_sel
|
|
; alloc_data_sel32
|
|
; alloc_disc_CS_sel
|
|
; alloc_CS_sel
|
|
; alloc_NP_data_sel
|
|
; alloc_NP_CS_sel
|
|
;
|
|
; Set appropriate access rights flags then use
|
|
; alloc_sel to get a selector.
|
|
;
|
|
; Entry:
|
|
; Base address and Limit OR Owner
|
|
;
|
|
; Returns:
|
|
; Selector in AX
|
|
;
|
|
; Registers Destroyed:
|
|
; AX
|
|
;
|
|
; History:
|
|
; Fri 15-Jul-1988 21:05:19 -by- David N. Weise [davidw]
|
|
;
|
|
;-----------------------------------------------------------------------;
|
|
|
|
assumes ds,nothing
|
|
assumes es,nothing
|
|
|
|
public alloc_data_sel32
|
|
alloc_data_sel32 label near
|
|
cProc alloc_data_sel,<PUBLIC,NEAR>
|
|
; parmD Address
|
|
; parmD Limit
|
|
cBegin nogen
|
|
mov ax,DSC_PRESENT+DSC_DATA
|
|
jmps alloc_sel
|
|
cEnd nogen
|
|
|
|
|
|
;-----------------------------------------------------------------------;
|
|
; alloc_sel ;
|
|
; ;
|
|
; Entry: ;
|
|
; AL = flags ;
|
|
; Returns: ;
|
|
; ;
|
|
; Error Returns: ;
|
|
; ;
|
|
; Registers Preserved: ;
|
|
; BX,CX,DX,DI,SI,DS,ES ;
|
|
; ;
|
|
; Registers Destroyed: ;
|
|
; ;
|
|
; Calls: ;
|
|
; ;
|
|
; History: ;
|
|
; ;
|
|
; Thu 07-Apr-1988 21:33:27 -by- David N. Weise [davidw] ;
|
|
; Added the GlobalNotify check. ;
|
|
; ;
|
|
; Sun Feb 01, 1987 07:48:39p -by- David N. Weise [davidw] ;
|
|
; Added this nifty comment block. ;
|
|
;-----------------------------------------------------------------------;
|
|
|
|
cProc alloc_sel,<PUBLIC,NEAR>,<bx,dx,si,di,ds,es>
|
|
parmD Address
|
|
parmD Limit
|
|
localV DscBuf,DSC_LEN
|
|
cBegin
|
|
push ecx
|
|
mov cx, 1
|
|
test al, DSC_PRESENT
|
|
jz short as_oneonly
|
|
|
|
mov ecx, Limit ; Calculate how many selectors required
|
|
cmp ecx, 100000h ; More than 1Mb?
|
|
jb short as_byte
|
|
|
|
add ecx, 0FFFh ; Round to 4K pages
|
|
and cx, not 0FFFh
|
|
mov Limit, ecx
|
|
shr Limit, 12 ; # 4K pages
|
|
or ah, DSC_GRANULARITY ; 4K granularity!
|
|
as_byte:
|
|
dec Limit ; Came in as length, now limit
|
|
add ecx, 0FFFFh
|
|
shr ecx, 16 ; # selectors in array
|
|
|
|
as_oneonly:
|
|
call get_sel
|
|
jz short a_s_exit ; No selectors left
|
|
|
|
|
|
mov bx, si ; Selector in bx for DPMI
|
|
or bl, SEL_LDT
|
|
lea di, DscBuf
|
|
smov es, ss ; es:di points to descriptor buffer
|
|
test al, DSC_PRESENT
|
|
jnz short set_everything
|
|
|
|
push ax
|
|
|
|
mov ds, gdtdsc
|
|
and bl, not 7
|
|
pop word ptr [bx].dsc_access
|
|
mov ax, word ptr Limit
|
|
mov [bx].dsc_limit, ax
|
|
mov [bx].dsc_hbase, cl ; Number of selectors here
|
|
ifdef WOW
|
|
smov es, ds ; es:di -> descriptor
|
|
mov di, bx
|
|
or bl, SEG_RING ; bx selector #
|
|
DPMICALL 000Ch ; Set descriptor
|
|
endif; WOW
|
|
jmps as_done
|
|
|
|
set_everything:
|
|
and ah, not 0Fh ; Zero limit 19:16
|
|
or ah, byte ptr Limit+2 ; Fill in limit 19:16
|
|
mov word ptr DscBuf.dsc_access, ax
|
|
mov ax, Limit.lo
|
|
mov DscBuf.dsc_limit, ax
|
|
mov ax, Address.lo
|
|
mov DscBuf.dsc_lbase, ax
|
|
mov ax, Address.hi
|
|
mov DscBuf.dsc_mbase, al
|
|
mov DscBuf.dsc_hbase, ah
|
|
|
|
call fill_in_selector_array
|
|
|
|
as_done:
|
|
or si, SEG_RING
|
|
a_s_exit:
|
|
mov ax, si
|
|
pop ecx
|
|
cEnd
|
|
|
|
|
|
;-----------------------------------------------------------------------;
|
|
; free_sel ;
|
|
; FreeSelector ;
|
|
; ;
|
|
; Entry: ;
|
|
; ;
|
|
; Returns: ;
|
|
; ;
|
|
; Error Returns: ;
|
|
; ;
|
|
; Registers Preserved: ;
|
|
; AX,BX,CX,DX,DI,SI,DS,ES ;
|
|
; ;
|
|
; Registers Destroyed: ;
|
|
; ;
|
|
; Calls: ;
|
|
; ;
|
|
; History: ;
|
|
; ;
|
|
;-----------------------------------------------------------------------;
|
|
|
|
assumes ds,nothing
|
|
assumes es,nothing
|
|
|
|
cProc IFreeSelector,<FAR,PUBLIC>
|
|
parmW selector
|
|
cBegin
|
|
xor ax, ax
|
|
mov es, ax
|
|
cCall FreeSelArray,<selector>
|
|
cEnd
|
|
|
|
assumes ds, nothing
|
|
assumes es, nothing
|
|
|
|
ifdef WOW
|
|
; save cx too.
|
|
|
|
cProc free_sel,<PUBLIC,NEAR>,<ax,bx,si,ds,cx>
|
|
else
|
|
cProc free_sel,<PUBLIC,NEAR>,<ax,bx,si,ds>
|
|
endif
|
|
parmW selector
|
|
cBegin
|
|
pushf ; !!! for the nonce
|
|
mov bx,selector ; must be careful in gcompact
|
|
; to ignore error return
|
|
call SetKernelDSProc ; Must call direct in this file
|
|
ReSetKernelDS
|
|
|
|
cmp gdtdsc, 0
|
|
je short give_to_win386
|
|
|
|
sel_check bx
|
|
mov si, bx
|
|
shr si, 1
|
|
cmp si, SelTableLen
|
|
if 0
|
|
mov si, SelTableLen
|
|
shl si, 1
|
|
cmp bx, si
|
|
endif
|
|
jae short give_to_win386
|
|
|
|
mov si, FirstFreeSel
|
|
inc CountFreeSel
|
|
mov ds, gdtdsc
|
|
UnSetKernelDS
|
|
ifdef WOW
|
|
mov cx, word ptr [bx+4]
|
|
endif
|
|
|
|
; Link into list
|
|
mov ax, [si] ; ax := head.next
|
|
mov [si], bx ; head.next := new
|
|
mov [bx], ax ; new.next := ax
|
|
mov word ptr [bx][2], 0
|
|
mov dword ptr [bx][4], MY_SEL SHL 8 ; Make it free
|
|
|
|
ifdef WOW
|
|
cmp cx, MY_SEL
|
|
jz sel_freed
|
|
or bl, SEG_RING ; Ensure Table bit correct
|
|
mov cx, 1
|
|
DPMICALL WOW_DPMIFUNC_0C
|
|
endif
|
|
jmps sel_freed
|
|
|
|
|
|
give_to_win386:
|
|
or bl, SEG_RING ; Ensure Table bit correct
|
|
DPMICALL 0001H
|
|
sel_freed:
|
|
popf
|
|
cEnd
|
|
|
|
|
|
;-----------------------------------------------------------------------;
|
|
; FreeSelArray ;
|
|
; ;
|
|
; Entry: ;
|
|
; ;
|
|
; Returns: ;
|
|
; ;
|
|
; Error Returns: ;
|
|
; ;
|
|
; Registers Preserved: ;
|
|
; AX,BX,CX,DX,DI,SI,DS,ES ;
|
|
; ;
|
|
; Registers Destroyed: ;
|
|
; ;
|
|
; Calls: ;
|
|
; ;
|
|
; History: ;
|
|
; ;
|
|
;-----------------------------------------------------------------------;
|
|
|
|
assumes ds,nothing
|
|
assumes es,nothing
|
|
|
|
cProc FreeSelArray,<PUBLIC,NEAR>,<ax,bx>
|
|
|
|
parmW selector
|
|
cBegin
|
|
push ecx
|
|
|
|
mov cx, 1 ; In case lar, lsl fail, one sel to free
|
|
mov bx, selector
|
|
Handle_To_Sel bl
|
|
|
|
ifdef WOW
|
|
if KDEBUG
|
|
push ds
|
|
SetKernelDS
|
|
cmp DemandLoadSel, 0 ; Skip the test if we're freeing DemandLoadSel
|
|
UnSetKernelDS
|
|
pop ds
|
|
je short fsa_no_test
|
|
push bx
|
|
push ds
|
|
mov ds, gdtdsc
|
|
and bl, not 7
|
|
mov ch, [bx].dsc_access
|
|
pop ds
|
|
pop bx
|
|
|
|
lar ax, bx
|
|
and ah, 0feh ;ignore access bit
|
|
and ch, 0feh ;ignore access bit
|
|
cmp ah, ch
|
|
je short LDTs_match
|
|
|
|
kerror 0, <System LDT does not match Shadow LDT>
|
|
LDTs_match:
|
|
xor ch, ch
|
|
fsa_no_test:
|
|
endif
|
|
endif
|
|
|
|
lar ax, bx
|
|
jnz short just_free_it ; I'm completely confused...
|
|
|
|
test ah, DSC_CODEDATA ; Code or data?
|
|
jz short just_free_it ; No, assume only one selector
|
|
|
|
test ah, DSC_PRESENT ; Present?
|
|
jnz short use_limit ; yes, calculate # sels from limit
|
|
|
|
ifdef WOW
|
|
; MarkSelNotPresent Saves Number of selectors in the dsc_hbase entry to get
|
|
; it back directly from our copy of the LDT.
|
|
|
|
push bx
|
|
push ds
|
|
|
|
mov ds, gdtdsc
|
|
and bl, not 7
|
|
xor cx,cx
|
|
mov cl,[bx].dsc_hbase ; Get Saved # selectors
|
|
|
|
pop ds
|
|
pop bx
|
|
else
|
|
push dx ; DPMI call 6 returns CX:DX
|
|
DPMICALL 0006h ; Get physical address
|
|
shr cx, 8 ; number of selectors
|
|
pop dx
|
|
endif; WOW
|
|
jmps just_free_it
|
|
|
|
use_limit:
|
|
lsl ecx, ebx
|
|
jnz short just_free_it ; Not present
|
|
Limit_To_Selectors ecx
|
|
|
|
just_free_it:
|
|
if KDEBUG
|
|
cmp cl,ch
|
|
jnz short skip_zero_inc
|
|
kerror 0, <Looping on cx=0 in FreeSelArray>
|
|
inc cl
|
|
skip_zero_inc:
|
|
endif
|
|
just_free_it2:
|
|
cCall free_sel,<bx> ; (preserves cx)
|
|
lea bx, [bx+DSC_LEN]
|
|
loop just_free_it2 ; Any left to free
|
|
|
|
pop ecx
|
|
cEnd
|
|
|
|
|
|
;-----------------------------------------------------------------------;
|
|
; GrowSelArray ;
|
|
; ;
|
|
; Entry: ;
|
|
; ;
|
|
; Returns: ;
|
|
; ;
|
|
; Error Returns: ;
|
|
; AX = 0 ;
|
|
; ZF = 1 ;
|
|
; ;
|
|
; Registers Preserved: ;
|
|
; AX,BX,CX,DX,DI,SI,DS,ES ;
|
|
; ;
|
|
; Registers Destroyed: ;
|
|
; ;
|
|
; Calls: ;
|
|
; ;
|
|
; History: ;
|
|
; ;
|
|
;-----------------------------------------------------------------------;
|
|
|
|
assumes ds,nothing
|
|
assumes es,nothing
|
|
|
|
cProc GrowSelArray,<PUBLIC,NEAR>,<bx,di>
|
|
localV DscBuf,DSC_LEN
|
|
cBegin
|
|
push ecx
|
|
mov di, ds:[esi].pga_handle
|
|
mov bx, di
|
|
Handle_To_Sel di
|
|
lsl eax, edi
|
|
Limit_To_Selectors eax
|
|
if KDEBUG
|
|
cmp al, ds:[esi].pga_selcount
|
|
je short gsa_count_ok
|
|
int 3
|
|
int 3
|
|
gsa_count_ok:
|
|
endif
|
|
mov ecx, edx ; New size
|
|
add ecx, 0FFFFh
|
|
shr ecx, 16 ; new # selectors
|
|
cmp ax, cx ; Same # of selectors required?
|
|
je short gsa_done ; yes, just return!
|
|
|
|
push si
|
|
push es
|
|
push ds
|
|
push di ; Argument to FreeSelArray
|
|
|
|
cmp cx, 255 ; Max array is 255.
|
|
jae short gsa_nosels
|
|
|
|
call get_sel ; get a new selector array
|
|
jz short gsa_nosels
|
|
|
|
push bx
|
|
mov bx, di ; DI had original selector
|
|
|
|
push ds
|
|
mov ds,gdtdsc
|
|
mov es,gdtdsc
|
|
push si
|
|
mov di,si
|
|
and di, not 7
|
|
mov si,bx
|
|
and si, not 7
|
|
MovsDsc
|
|
pop si
|
|
pop ds
|
|
ifdef WOW
|
|
push cx
|
|
push bx
|
|
mov cx, 1
|
|
mov bx, si
|
|
or bx, SEG_RING_MASK
|
|
DPMICALL WOW_DPMIFUNC_0C
|
|
pop bx
|
|
pop cx
|
|
endif
|
|
|
|
mov di, si ; New selector in DI
|
|
pop bx
|
|
pop si
|
|
pop ds
|
|
cCall AssociateSelector32,<si,0,0>
|
|
pop es
|
|
pop si
|
|
mov ax, bx
|
|
and ax, SEG_RING_MASK ; Ring bits
|
|
or ax, di ; New handle
|
|
mov ds:[esi].pga_handle, ax
|
|
mov ds:[esi].pga_selcount, cl
|
|
cCall AssociateSelector32,<ax,esi>
|
|
jmps gsa_done
|
|
|
|
gsa_nosels:
|
|
pop di
|
|
pop ds
|
|
pop es
|
|
pop si
|
|
xor ax, ax ; Indicate failure
|
|
jmps gsa_ret
|
|
|
|
gsa_done:
|
|
mov ax, ds:[esi].pga_handle
|
|
or ax, ax ; Success
|
|
gsa_ret:
|
|
pop ecx
|
|
cEnd
|
|
|
|
|
|
;=======================================================================;
|
|
; ;
|
|
; SELECTOR ALIAS ROUTINES ;
|
|
; ;
|
|
;=======================================================================;
|
|
|
|
|
|
;-----------------------------------------------------------------------;
|
|
; PrestoChangoSel
|
|
;
|
|
;
|
|
; Entry:
|
|
;
|
|
; Returns:
|
|
;
|
|
; Registers Destroyed:
|
|
;
|
|
; History:
|
|
; Thu 08-Dec-1988 14:17:38 -by- David N. Weise [davidw]
|
|
; Wrote it!
|
|
;-----------------------------------------------------------------------;
|
|
|
|
assumes ds,nothing
|
|
assumes es,nothing
|
|
|
|
cProc IPrestoChangoSelector,<PUBLIC,FAR>,<di,si>
|
|
parmW sourcesel
|
|
parmW destsel
|
|
localV DscBuf,DSC_LEN
|
|
cBegin
|
|
ifdef WOW
|
|
smov es, ss
|
|
lea di, DscBuf
|
|
mov bx, sourcesel
|
|
DPMICALL 000Bh ; LATER change this to a single
|
|
xor DscBuf.dsc_access, DSC_CODE_BIT ; DPMI call, read from gdtdsc
|
|
mov bx, destsel
|
|
DPMICALL 000Ch
|
|
mov ax, bx
|
|
else
|
|
push bx
|
|
|
|
push ds
|
|
mov ds, gdtdsc
|
|
mov es, gdtdsc
|
|
mov si, sourcesel
|
|
and si, not 7
|
|
mov di, destsel
|
|
and di, not 7
|
|
MovsDsc
|
|
lea bx,[di-DSC_LEN]
|
|
xor ds:[bx].dsc_access,DSC_CODE_BIT ; Toggle CODE/DATA
|
|
pop ds
|
|
or bl, SEG_RING
|
|
mov ax, bx
|
|
pop bx
|
|
endif; WOW
|
|
smov es,0
|
|
cEnd
|
|
|
|
|
|
|
|
;-----------------------------------------------------------------------;
|
|
; AllocAlias ;
|
|
; AllocCStoDSAlias ;
|
|
; AllocDStoCSAlias ;
|
|
; All these routines return an alias selector for the ;
|
|
; given selector. ;
|
|
; ;
|
|
; Entry: ;
|
|
; ;
|
|
; Returns: ;
|
|
; AX is alias selector ;
|
|
; DX is original selector (compatibility thing) ;
|
|
; ;
|
|
; Error Returns: ;
|
|
; ;
|
|
; Registers Preserved: ;
|
|
; BX,CX,DI,SI,DS ;
|
|
; ;
|
|
; Registers Destroyed: ;
|
|
; ES destroyed ;
|
|
; ;
|
|
; Calls: ;
|
|
; ;
|
|
; History: ;
|
|
; ;
|
|
;-----------------------------------------------------------------------;
|
|
|
|
assumes ds,nothing
|
|
assumes es,nothing
|
|
|
|
labelFP <PUBLIC,IAllocDStoCSAlias>
|
|
;** AllocDStoCSAlias has an interesting hack. A fix was made to
|
|
;** not allow apps to GlobalAlloc fixed memory. This was done
|
|
;** for performance reasons. The only reason we can ascertain
|
|
;** for an app needing fixed GlobalAlloc'ed memory is in the case
|
|
;** of alias selectors. We assume that all apps needing alias
|
|
;** selectors will use this function to make the alias. So, if
|
|
;** we see a DStoCS alias being made, we make sure the DS is fixed.
|
|
push bp
|
|
mov bp, sp ;Create the stack frame
|
|
push WORD PTR [bp + 6] ;Get handle/selector
|
|
IF KDEBUG
|
|
call GlobalHandleNorip ;Make sure it's really a handle
|
|
ELSE
|
|
call IGlobalHandle ;Make sure it's really a handle
|
|
ENDIF
|
|
test ax, 1 ;Fixed blocks have low bit set
|
|
jnz SHORT ADCA_Already_Fixed ;It's already a fixed block!
|
|
|
|
;** If the block is not fixed, it may be locked so we must check this.
|
|
push ax ;Save returned selector
|
|
push ax ;Use as parameter
|
|
call IGlobalFlags ;Returns lock count if any
|
|
or al, al ;Non-zero lock count?
|
|
pop ax ;Get selector back
|
|
jnz SHORT ADCA_Already_Fixed ;Yes, don't mess with it
|
|
|
|
;** Fix the memory. Note that we're only doing this for the
|
|
;** apps that are calling this on non-fixed or -locked memory.
|
|
;** This will cause them to rip on the GlobalFree call to this
|
|
;** memory, but at least it won't move on them!
|
|
push ax ;Fix it
|
|
call IGlobalFix
|
|
ADCA_Already_Fixed:
|
|
pop bp ;Clear our stack frame
|
|
|
|
;** Flag which type of alias to make and jump to common routine
|
|
mov dl, 1
|
|
jmps aka
|
|
|
|
labelFP <PUBLIC,IAllocCStoDSAlias>
|
|
xor dl, dl
|
|
|
|
cProc aka,<FAR,PUBLIC>, <bx,cx,si,di,ds>
|
|
parmW sourceSel
|
|
localV DscBuf,DSC_LEN
|
|
localB flag ; 0 for data, !0 for code
|
|
cBegin
|
|
mov flag, dl
|
|
|
|
mov cx, 1
|
|
call get_sel
|
|
mov ax, si ; in case it failed
|
|
jz short aka_nope
|
|
or si, SEG_RING
|
|
|
|
ifdef WOW ; LATER Single DPMI call
|
|
push si ; save Target Selector
|
|
smov es,ss
|
|
lea di,DscBuf
|
|
mov bx,sourceSel
|
|
DPMICALL 000Bh ; Read the Selector into DscBuf
|
|
and es:[di].dsc_access,NOT DSC_CODE_BIT ; Toggle CODE/DATA
|
|
cmp flag, 0
|
|
jz @F
|
|
or es:[di].dsc_access,DSC_CODE_BIT
|
|
@@:
|
|
pop bx ; restore Target Selector
|
|
DPMICALL 0000Ch
|
|
else
|
|
mov ds, gdtdsc
|
|
mov es, gdtdsc
|
|
mov bx, si
|
|
mov di, si
|
|
and di, not 7
|
|
mov si, sourceSel
|
|
and si, not 7
|
|
MovsDsc
|
|
and es:[di][-DSC_LEN].dsc_access,NOT DSC_CODE_BIT ; Toggle CODE/DATA
|
|
cmp flag, 0
|
|
jz @F
|
|
or es:[di][-DSC_LEN].dsc_access,DSC_CODE_BIT
|
|
@@:
|
|
endif; WOW
|
|
mov ax, bx
|
|
smov es,0
|
|
aka_nope:
|
|
mov dx,sourceSel
|
|
cEnd
|
|
|
|
|
|
cProc AllocAlias,<FAR,PUBLIC>, <bx,cx,si,di,ds>
|
|
parmW selector
|
|
cBegin
|
|
ifdef WOW
|
|
push bx ; Whitewater tool ObjDraw needs this too
|
|
endif
|
|
mov cx, 1
|
|
call get_sel
|
|
jz short aca_nope
|
|
or si, SEG_RING
|
|
cCall IPrestoChangoSelector,<selector,si>
|
|
aca_nope:
|
|
; WhiteWater Resource Toolkit (shipped with Borland's Turbo
|
|
; Pascal) depends on dx being the data selector which was true
|
|
; in 3.0 but in 3.1 validation layer destroys it.
|
|
mov dx,selector
|
|
ifdef WOW
|
|
pop bx
|
|
endif
|
|
cEnd
|
|
|
|
;=======================================================================;
|
|
; ;
|
|
; SELECTOR MANPULATION ROUTINES ;
|
|
; ;
|
|
;=======================================================================;
|
|
|
|
|
|
;-----------------------------------------------------------------------;
|
|
; fill_in_selector_array ;
|
|
; ;
|
|
; Entry: ;
|
|
; AX = Limit for object ;
|
|
; DH = Discard bit for descriptors ;
|
|
; DL = Access bits ;
|
|
; BX:DI = 32 bit base address of object ;
|
|
; SI = index into LDT ;
|
|
; Returns: ;
|
|
; ;
|
|
; Error Returns: ;
|
|
; ;
|
|
; Registers Preserved: ;
|
|
; SI, DI, DS, ES ;
|
|
; ;
|
|
; Registers Destroyed: ;
|
|
; AX,BX,CX,DX ;
|
|
; ;
|
|
; Calls: ;
|
|
; ;
|
|
; History: ;
|
|
; ;
|
|
;-----------------------------------------------------------------------;
|
|
|
|
cProc fill_in_selector_array,<PUBLIC,NEAR>
|
|
cBegin nogen
|
|
|
|
push ds
|
|
mov ds, gdtdsc
|
|
push bx
|
|
push cx
|
|
|
|
mov dh, es:[di].dsc_hlimit ; For granularity
|
|
next_sel:
|
|
|
|
;; DPMICALL 000Ch ; Set this descriptor
|
|
|
|
push bx ; Set Descriptor
|
|
and bl, not 7
|
|
mov ax, es:[di] ; This looks slow but it isn't...
|
|
mov ds:[bx], ax
|
|
mov ax, es:[di][2]
|
|
mov ds:[bx][2], ax
|
|
mov ax, es:[di][4]
|
|
mov ds:[bx][4], ax
|
|
mov ax, es:[di][6]
|
|
mov ds:[bx][6], ax
|
|
pop bx
|
|
|
|
lea bx, [bx+DSC_LEN] ; On to next selector
|
|
add es:[di].dsc_mbase, 1 ; Add 64kb to address
|
|
adc es:[di].dsc_hbase, 0
|
|
|
|
test dh, DSC_GRANULARITY ; Page granular?
|
|
jz short byte_granular
|
|
|
|
sub es:[di].dsc_limit, 16 ; 64K is 16 4K pages
|
|
sbb es:[di].dsc_hlimit, 0 ; Carry into hlimit
|
|
loop next_sel
|
|
|
|
jmps fisa_ret
|
|
|
|
byte_granular:
|
|
dec es:[di].dsc_hlimit ; subtract 64kb from limit
|
|
loop next_sel
|
|
|
|
fisa_ret:
|
|
pop cx
|
|
pop bx
|
|
DPMICALL WOW_DPMIFUNC_0C
|
|
pop ds
|
|
|
|
ret
|
|
|
|
cEnd nogen
|
|
|
|
|
|
;-----------------------------------------------------------------------;
|
|
; GetSelectorBase
|
|
; get_physical_address
|
|
;
|
|
;
|
|
; Entry:
|
|
;
|
|
; Returns:
|
|
; DX:AX 32 bit physical address
|
|
; Registers Destroyed:
|
|
;
|
|
; History:
|
|
; Sat 09-Jul-1988 16:40:59 -by- David N. Weise [davidw]
|
|
;
|
|
;-----------------------------------------------------------------------;
|
|
|
|
assumes ds,nothing
|
|
assumes es,nothing
|
|
|
|
cProc GetSelectorBase,<PUBLIC,FAR>
|
|
parmW selector
|
|
cBegin
|
|
cCall get_physical_address, <selector>
|
|
cEnd
|
|
|
|
cProc get_physical_address,<PUBLIC,NEAR>
|
|
parmW selector
|
|
cBegin
|
|
push bx
|
|
push cx
|
|
mov bx, selector
|
|
|
|
push ds ; Get Segment Base Address
|
|
mov ds, gdtdsc
|
|
and bl, not 7
|
|
mov ax, ds:[bx].dsc_lbase
|
|
mov dl, ds:[bx].dsc_mbase
|
|
mov dh, ds:[bx].dsc_hbase
|
|
pop ds
|
|
pop cx
|
|
pop bx
|
|
cEnd
|
|
|
|
|
|
;-----------------------------------------------------------------------;
|
|
; get_selector_length16
|
|
;
|
|
;
|
|
; Entry:
|
|
;
|
|
; Returns:
|
|
; AX 16 bit segment length
|
|
; Registers Destroyed:
|
|
;
|
|
; History:
|
|
; Sat 09-Jul-1988 16:40:59 -by- David N. Weise [davidw]
|
|
;
|
|
;-----------------------------------------------------------------------;
|
|
|
|
assumes ds,nothing
|
|
assumes es,nothing
|
|
|
|
cProc get_selector_length16,<PUBLIC,NEAR>
|
|
parmW selector
|
|
cBegin
|
|
mov ax, -1
|
|
lsl ax, selector
|
|
inc ax ; length is one bigger!
|
|
cEnd
|
|
|
|
;-----------------------------------------------------------------------;
|
|
; set_physical_address
|
|
;
|
|
;
|
|
; Entry:
|
|
; DX:AX 32 bit physical address
|
|
; Returns:
|
|
;
|
|
; Registers Destroyed:
|
|
;
|
|
; History:
|
|
; Sat 09-Jul-1988 16:40:59 -by- David N. Weise [davidw]
|
|
;
|
|
;-----------------------------------------------------------------------;
|
|
|
|
assumes ds,nothing
|
|
assumes es,nothing
|
|
|
|
cProc far_set_physical_address,<PUBLIC,FAR>
|
|
parmW selector
|
|
cBegin
|
|
cCall set_physical_address,<selector>
|
|
cEnd
|
|
|
|
cProc set_physical_address,<PUBLIC,NEAR>,<bx,di>
|
|
parmW selector
|
|
cBegin
|
|
push ecx
|
|
mov bx, selector
|
|
CheckLDT bl
|
|
lsl ecx, ebx
|
|
if KDEBUG
|
|
jz short spa_ok
|
|
int 3
|
|
spa_ok:
|
|
endif
|
|
Limit_To_Selectors ecx
|
|
|
|
mov di, cx
|
|
mov cx, dx ; CX:DX has new address
|
|
mov dx, ax
|
|
|
|
push ds
|
|
push bx
|
|
ifdef WOW
|
|
set_bases:
|
|
DPMICALL 0007h ; Set selector base
|
|
else
|
|
mov ds, gdtdsc
|
|
set_bases:
|
|
and bl, not 7
|
|
mov ds:[bx].dsc_lbase, dx
|
|
mov ds:[bx].dsc_mbase, cl
|
|
mov ds:[bx].dsc_hbase, ch
|
|
endif; WOW
|
|
lea bx, [bx+DSC_LEN] ; On to next selector
|
|
inc cx ; Add 64k to base
|
|
dec di
|
|
jnz set_bases
|
|
|
|
pop bx
|
|
pop ds
|
|
mov ax, dx ; Restore AX and DX
|
|
mov dx, cx
|
|
pop ecx
|
|
cEnd
|
|
|
|
|
|
;-----------------------------------------------------------------------;
|
|
; set_selector_address32
|
|
;
|
|
;
|
|
; Entry:
|
|
;
|
|
; Returns:
|
|
;
|
|
; Registers Destroyed:
|
|
;
|
|
; History:
|
|
; Sat 09-Jul-1988 16:40:59 -by- David N. Weise [davidw]
|
|
;
|
|
;-----------------------------------------------------------------------;
|
|
|
|
assumes ds,nothing
|
|
assumes es,nothing
|
|
|
|
cProc set_selector_address32,<PUBLIC,NEAR>,<ax,dx>
|
|
parmW selector
|
|
parmD addr
|
|
cBegin
|
|
mov dx, addr.sel
|
|
mov ax, addr.off
|
|
cCall set_physical_address,<selector>
|
|
cEnd
|
|
|
|
|
|
;-----------------------------------------------------------------------;
|
|
; set_sel_limit
|
|
;
|
|
;
|
|
; Entry:
|
|
; CX:BX = length of segment
|
|
; Returns:
|
|
;
|
|
; Registers Destroyed:
|
|
; CX
|
|
;
|
|
; History:
|
|
; Fri 15-Jul-1988 19:41:44 -by- David N. Weise [davidw]
|
|
;
|
|
;-----------------------------------------------------------------------;
|
|
|
|
assumes ds,nothing
|
|
assumes es,nothing
|
|
|
|
cProc set_sel_limit,<PUBLIC,NEAR>,<ax,dx,si,di,es,ds>
|
|
parmW selector
|
|
localV DscBuf,DSC_LEN
|
|
cBegin
|
|
push ebx
|
|
push ecx
|
|
|
|
push bx ; Get existing descriptor
|
|
smov es, ss
|
|
lea di, DscBuf
|
|
mov bx, selector
|
|
|
|
push ds ; Get Descriptor
|
|
mov ds, gdtdsc
|
|
push si
|
|
mov si, bx
|
|
and si, not 7
|
|
MovsDsc
|
|
lea di, [di-DSC_LEN] ; Restore DI
|
|
pop si
|
|
pop ds
|
|
pop bx
|
|
mov dx, word ptr [DscBuf.dsc_access]
|
|
and dh, 0F0h ; Zap hlimit bits
|
|
test dl, DSC_PRESENT
|
|
jz short ssl_set_limit1 ; Not present, just one to set
|
|
|
|
and dh, NOT DSC_GRANULARITY ; Byte granularity
|
|
shl ecx, 16
|
|
mov cx, bx ; DWORD length
|
|
mov ebx, ecx
|
|
cmp ecx, 100000h ; More than 1Mb?
|
|
jb short ssl_byte
|
|
|
|
add ecx, 0FFFh ; Round to 4k pages
|
|
and cx, not 0FFFh
|
|
mov ebx, ecx
|
|
shr ebx, 12 ; # 4k pages
|
|
or dh, DSC_GRANULARITY ; Set 4k granularity
|
|
ssl_byte:
|
|
add ecx, 0FFFFh
|
|
shr ecx, 16 ; # selectors in array
|
|
cmp cx, 1
|
|
je short ssl_set_limit1
|
|
|
|
dec ebx ; length to limit
|
|
mov ax, bx ; low 16 bits of limit
|
|
shr ebx, 16
|
|
or dh, bl ; Bits 19:16 of limit
|
|
|
|
mov word ptr DscBuf.dsc_access, dx
|
|
mov DscBuf.dsc_limit, ax
|
|
mov bx, Selector
|
|
|
|
call fill_in_selector_array
|
|
jmps ssl_done
|
|
|
|
ssl_set_limit1: ; Fast out for one only
|
|
dec bx ; Came in as length
|
|
mov DscBuf.dsc_limit, bx ; and limit
|
|
mov word ptr DscBuf.dsc_access, dx ; Access, Discard and hlimit
|
|
mov bx, Selector
|
|
DPMICALL 000Ch
|
|
|
|
ssl_done:
|
|
smov ss,ss ; It may be SS we're changing
|
|
pop ecx
|
|
pop ebx
|
|
cEnd
|
|
|
|
|
|
;-----------------------------------------------------------------------;
|
|
; set_selector_limit32
|
|
;
|
|
;
|
|
; Entry:
|
|
;
|
|
; Returns:
|
|
;
|
|
; Registers Destroyed:
|
|
;
|
|
; History:
|
|
; Fri 15-Jul-1988 19:41:44 -by- David N. Weise [davidw]
|
|
;
|
|
;-----------------------------------------------------------------------;
|
|
|
|
assumes ds,nothing
|
|
assumes es,nothing
|
|
|
|
cProc set_selector_limit32,<PUBLIC,NEAR>,<cx,bx>
|
|
parmW selector
|
|
parmD sel_len
|
|
cBegin
|
|
mov cx, sel_len.hi
|
|
mov bx, sel_len.lo
|
|
cCall set_sel_limit,<selector>
|
|
cEnd
|
|
|
|
;-----------------------------------------------------------------------;
|
|
; mark_sel_NP
|
|
;
|
|
;
|
|
; Entry:
|
|
;
|
|
; Returns:
|
|
;
|
|
; Registers Destroyed:
|
|
; BX
|
|
;
|
|
; History:
|
|
; Fri 15-Jul-1988 21:37:22 -by- David N. Weise [davidw]
|
|
;
|
|
;-----------------------------------------------------------------------;
|
|
|
|
assumes ds,nothing
|
|
assumes es,nothing
|
|
|
|
cProc mark_sel_NP,<PUBLIC,NEAR>,<ds>
|
|
parmW selector
|
|
parmW owner
|
|
localV DscBuf,DSC_LEN
|
|
cBegin
|
|
push ecx
|
|
mov bx, selector
|
|
Handle_To_Sel bl
|
|
lsl ecx, ebx ; How many selectors do we have now?
|
|
Limit_To_Selectors ecx
|
|
|
|
push ax
|
|
push es
|
|
push di
|
|
|
|
push ds
|
|
mov ds, gdtdsc
|
|
push bx
|
|
and bl, not 7
|
|
mov [bx].dsc_hbase, cl ; Save # selectors
|
|
mov [bx].dsc_hlimit, DSC_DISCARDABLE
|
|
and [bx].dsc_access, NOT DSC_PRESENT
|
|
mov cx, owner
|
|
mov [bx].dsc_owner, cx ; Set owner in descriptor
|
|
|
|
ifdef WOW
|
|
;
|
|
; Now the copy of the LDT has the correct info set VIA DPMI the real NT
|
|
; LDT Entry
|
|
|
|
smov es,ds
|
|
mov di,bx ; es:di->selector
|
|
or bx, SEG_RING ; BX = selector
|
|
DPMICALL 000Ch
|
|
|
|
endif; WOW
|
|
pop bx
|
|
pop ds
|
|
|
|
SetKernelDS
|
|
mov ds, pGlobalHeap
|
|
UnSetKernelDS
|
|
cCall AssociateSelector32,<bx,0,cx> ; Save owner in selector table
|
|
pop di
|
|
pop es
|
|
pop ax
|
|
pop ecx
|
|
cEnd
|
|
|
|
|
|
;-----------------------------------------------------------------------;
|
|
; mark_sel_PRESENT
|
|
;
|
|
;
|
|
; Entry:
|
|
;
|
|
; Returns:
|
|
;
|
|
; Registers Destroyed:
|
|
;
|
|
; History:
|
|
; Fri 15-Jul-1988 21:37:22 -by- David N. Weise [davidw]
|
|
;
|
|
;-----------------------------------------------------------------------;
|
|
|
|
assumes ds,nothing
|
|
assumes es,nothing
|
|
|
|
cProc mark_sel_PRESENT,<PUBLIC,NEAR>,<dx,di,es>
|
|
parmD arena_ptr
|
|
parmW selector
|
|
localV DscBuf,DSC_LEN
|
|
cBegin
|
|
push eax
|
|
push ebx
|
|
push ecx
|
|
|
|
smov es, ss
|
|
lea di, DscBuf
|
|
mov bx, selector
|
|
DPMICALL 000Bh ; Get existing descriptor
|
|
mov ax, word ptr DscBuf.dsc_access ; Access and hlimit
|
|
or al, DSC_PRESENT ; Mark it present
|
|
and ah, NOT DSC_GRANULARITY ; Assume byte granular
|
|
|
|
mov esi, arena_ptr
|
|
CheckDS
|
|
mov ecx, ds:[esi].pga_size
|
|
mov ebx, ecx
|
|
cmp ecx, 100000h ; New size more than 1Mb?
|
|
jb short msp_byte
|
|
|
|
add ebx, 0FFFh ; Round to 4k pages
|
|
and bx, not 0FFFh
|
|
shr ebx, 12 ; # 4k pages
|
|
or ah, DSC_GRANULARITY ; Set 4k granularity
|
|
msp_byte:
|
|
dec ebx
|
|
mov DscBuf.dsc_limit, bx ; Fill in new limit fields
|
|
shr ebx, 16
|
|
and bl, 0Fh
|
|
and ah, NOT 0Fh
|
|
or ah, bl
|
|
mov word ptr DscBuf.dsc_access, ax ; Fill in new hlimit and access
|
|
|
|
dec ecx
|
|
Limit_To_Selectors ecx ; New number of selectors
|
|
mov ds:[esi].pga_selcount, cl
|
|
mov bl, DscBuf.dsc_hbase ; Old number of selectors
|
|
sub bl, cl
|
|
je short go_ahead ; Same number, just fill in array
|
|
jb short get_big
|
|
|
|
; here to get small
|
|
|
|
xor bh, bh
|
|
xchg bx, cx
|
|
shl bx, 3 ; Offset of first selector
|
|
.errnz DSC_LEN - 8
|
|
add bx, selector ; First selector to free
|
|
@@: cCall free_sel,<bx>
|
|
lea bx, [bx+DSC_LEN]
|
|
loop @B
|
|
jmps go_ahead ; And fill in remaining selectors
|
|
|
|
get_big:
|
|
mov ax, word ptr DscBuf.dsc_access ; Access bits in ax
|
|
mov ebx, ds:[esi].pga_address ; Get base address
|
|
mov ecx, ds:[esi].pga_size
|
|
cCall alloc_sel,<ebx,ecx> ; Access bits in ax
|
|
mov si, ax
|
|
or ax, ax ; did we get a set?
|
|
jz short return_new_handle
|
|
or si, SEG_RING ; Set ring bits like old selector
|
|
test selector, IS_SELECTOR
|
|
jnz short @F
|
|
StoH si
|
|
HtoS selector
|
|
@@:
|
|
cCall AssociateSelector32,<selector,0,0>
|
|
cCall FreeSelArray,<selector> ; Zap old handle
|
|
jmps return_new_handle
|
|
|
|
go_ahead:
|
|
mov ebx, ds:[esi].pga_address ; Fill in selector array with
|
|
mov DscBuf.dsc_lbase, bx ; new base and limit
|
|
shr ebx, 16
|
|
mov DscBuf.dsc_mbase, bl
|
|
mov DscBuf.dsc_hbase, bh
|
|
mov bx, selector
|
|
movzx cx, ds:[esi].pga_selcount
|
|
|
|
call fill_in_selector_array
|
|
mov si, selector ; return old selector in SI
|
|
return_new_handle:
|
|
|
|
pop ecx
|
|
pop ebx
|
|
pop eax
|
|
cEnd
|
|
|
|
;-----------------------------------------------------------------------;
|
|
; cmp_sel_address
|
|
;
|
|
; Compares the physical addresses corresponding to two selectors
|
|
;
|
|
; Entry:
|
|
;
|
|
; Returns:
|
|
;
|
|
; Registers Destroyed:
|
|
;
|
|
; History:
|
|
; Sat 09-Jul-1988 19:10:14 -by- David N. Weise [davidw]
|
|
;
|
|
;-----------------------------------------------------------------------;
|
|
|
|
assumes ds,nothing
|
|
assumes es,nothing
|
|
|
|
cProc cmp_sel_address,<PUBLIC,NEAR>
|
|
parmW sel1
|
|
parmW sel2
|
|
cBegin
|
|
push ax
|
|
push ebx
|
|
push edx
|
|
cCall get_physical_address,<sel1>
|
|
mov bx, dx
|
|
shl ebx, 16
|
|
mov bx, ax ; First address in EBX
|
|
cCall get_physical_address,<sel2>
|
|
shl edx, 16
|
|
mov dx, ax ; Second address in EDX
|
|
cmp ebx, edx
|
|
pop edx
|
|
pop ebx
|
|
pop ax
|
|
;;; mov ds,gdtdsc
|
|
;;; mov si,sel1
|
|
;;; mov di,sel2
|
|
;;; sel_check si
|
|
;;; sel_check di
|
|
;;; mov al,[si].dsc_hbase
|
|
;;; cmp al,[di].dsc_hbase
|
|
;;; jne short csa_done
|
|
;;; mov al,[si].dsc_mbase
|
|
;;; cmp al,[di].dsc_mbase
|
|
;;; jne short csa_done
|
|
;;; mov ax,[si].dsc_lbase
|
|
;;; cmp ax,[di].dsc_lbase
|
|
;;;csa_done:
|
|
cEnd
|
|
|
|
;-----------------------------------------------------------------------;
|
|
; pdref ;
|
|
; ;
|
|
; Dereferences the given global handle, i.e. gives back abs. address. ;
|
|
; ;
|
|
; Arguments: ;
|
|
; DX = selector ;
|
|
; DS:DI = BURGERMASTER ;
|
|
; ;
|
|
; Returns: ;
|
|
; ESI = address of arena header ;
|
|
; AX = address of client data ;
|
|
; CH = lock count or 0 for fixed objects ;
|
|
; CL = flags ;
|
|
; DX = handle, 0 for fixed objects ;
|
|
; ;
|
|
; Error Returns: ;
|
|
; ZF = 1 if invalid or discarded ;
|
|
; AX = 0 ;
|
|
; BX = owner of discarded object ;
|
|
; SI = handle of discarded object ;
|
|
; ;
|
|
; Registers Preserved: ;
|
|
; ;
|
|
; Registers Destroyed: ;
|
|
; ;
|
|
; Calls: ;
|
|
; ;
|
|
; History: ;
|
|
; ;
|
|
;-----------------------------------------------------------------------;
|
|
|
|
assumes ds,nothing
|
|
assumes es,nothing
|
|
|
|
cProc pdref,<PUBLIC,NEAR>
|
|
|
|
cBegin nogen
|
|
mov si, dx
|
|
sel_check si
|
|
or si, si ; Null handle?
|
|
mov ax, si
|
|
jz short pd_exit ; yes, return 0
|
|
|
|
lar eax, edx
|
|
jnz short pd_totally_bogus
|
|
shr eax, 8
|
|
|
|
; We should beef up the check for a valid discarded sel.
|
|
|
|
xor cx,cx
|
|
test ah, DSC_DISCARDABLE
|
|
jz short pd_not_discardable
|
|
or cl, GA_DISCARDABLE
|
|
; Discardable, is it code?
|
|
test al, DSC_CODE_BIT
|
|
jz short pd_not_code
|
|
or cl,GA_DISCCODE
|
|
pd_not_code:
|
|
|
|
pd_not_discardable:
|
|
test al, DSC_PRESENT
|
|
jnz short pd_not_discarded
|
|
|
|
; object discarded
|
|
|
|
or cl,HE_DISCARDED
|
|
ifdef WOW
|
|
; On WOW we don't copy the owner to the real LDT since it is slow to call
|
|
; the NT Kernel, so we read our copy of it directly.
|
|
; see set_discarded_sel_owner mattfe mar 23 93
|
|
|
|
move ax,es ; save es
|
|
mov bx,dx
|
|
mov es,cs:gdtdsc
|
|
and bl, not 7
|
|
mov bx,es:[bx].dsc_owner
|
|
mov es,ax ; restore
|
|
else
|
|
lsl bx, dx ; get the owner
|
|
endif
|
|
or si, SEG_RING-1 ; Handles are RING 2
|
|
xor ax,ax
|
|
jmps pd_exit
|
|
|
|
pd_not_discarded:
|
|
cCall get_arena_pointer32,<dx>
|
|
mov esi, eax
|
|
mov ax, dx
|
|
or esi, esi ; Unknown selector
|
|
jz short pd_maybe_alias
|
|
mov dx, ds:[esi].pga_handle
|
|
cmp dx, ax ; Quick check - handle in header
|
|
je short pd_match ; matches what we were given?
|
|
|
|
test al, IS_SELECTOR ; NOW, we MUST have been given
|
|
jz short pd_totally_bogus ; a selector address.
|
|
push ax
|
|
StoH al ; Turn into handle
|
|
cmp dx, ax
|
|
pop ax
|
|
jne short pd_nomatch
|
|
pd_match:
|
|
or cl, ds:[esi].pga_flags
|
|
and cl, NOT HE_DISCARDED ; same as GA_NOTIFY!!
|
|
mov ax, dx ; Get address in AX
|
|
test dl, GA_FIXED ; DX contains handle
|
|
jnz short pd_fixed ; Does handle need derefencing?
|
|
mov ch, ds:[esi].pga_count
|
|
HtoS al ; Dereference moveable handle
|
|
jmps pd_exit
|
|
pd_totally_bogus:
|
|
xor ax,ax
|
|
pd_maybe_alias:
|
|
if 0
|
|
if KDEBUG
|
|
or dx,dx
|
|
jnz short dref_invalid
|
|
endif
|
|
endif
|
|
pd_nomatch: ; Handle did not match...
|
|
xor dx, dx
|
|
;;; mov dx, ax ; Must be an alias...
|
|
pd_fixed:
|
|
;;; xor si, si
|
|
;;; xor dx, dx
|
|
pd_exit:
|
|
or ax,ax
|
|
ret
|
|
if 0
|
|
if KDEBUG
|
|
dref_invalid:
|
|
push ax
|
|
kerror ERR_GMEMHANDLE,<gdref: invalid handle>,0,dx
|
|
pop ax
|
|
jmps pd_nomatch
|
|
endif
|
|
endif
|
|
cEnd nogen
|
|
|
|
cProc Far_pdref,<PUBLIC,FAR>
|
|
cBegin nogen
|
|
call pdref
|
|
ret
|
|
cEnd nogen
|
|
|
|
|
|
;-----------------------------------------------------------------------;
|
|
; get_rover_2 ;
|
|
; ;
|
|
; Entry: ;
|
|
; ES Selector to get rover for ;
|
|
; Returns: ;
|
|
; ES (kr2dsc) is rover DATA and PRESENT ;
|
|
; Error Returns: ;
|
|
; ;
|
|
; Registers Preserved: ;
|
|
; AX,BX,CX,DX,DI,SI,DS ;
|
|
; ;
|
|
; Registers Destroyed: ;
|
|
; ;
|
|
; Calls: ;
|
|
; ;
|
|
; History: ;
|
|
; ;
|
|
;-----------------------------------------------------------------------;
|
|
|
|
assumes ds,nothing
|
|
assumes es,nothing
|
|
|
|
cProc get_rover_2,<PUBLIC,NEAR>,<di>
|
|
localV DscBuf,DSC_LEN
|
|
cBegin
|
|
push ax
|
|
push bx
|
|
mov bx, es ; Selector to get rover for
|
|
push ds
|
|
SetKernelDS ds
|
|
mov di, kr2dsc
|
|
mov es, gdtdsc
|
|
mov ds, gdtdsc
|
|
UnSetKernelDS ds
|
|
push si
|
|
mov si, bx
|
|
and si, not 7
|
|
and di, not 7
|
|
MovsDsc
|
|
lea bx, [di-DSC_LEN]
|
|
mov es:[bx].dsc_access, DSC_PRESENT+DSC_DATA
|
|
or bl, SEG_RING
|
|
pop si
|
|
ifdef WOW
|
|
push cx
|
|
mov cx, 1
|
|
DPMICALL WOW_DPMIFUNC_0C
|
|
pop cx
|
|
endif; WOW
|
|
pop ds
|
|
mov es, bx ; Return with ES containing rover
|
|
pop bx
|
|
pop ax
|
|
cEnd
|
|
|
|
|
|
;-----------------------------------------------------------------------;
|
|
; get_rover_232 ;
|
|
; ;
|
|
; Entry: ;
|
|
; ds:esi ;
|
|
; Returns: ;
|
|
; ES:0 ;
|
|
; Error Returns: ;
|
|
; ;
|
|
; Registers Preserved: ;
|
|
; AX,BX,CX,DX,DI,SI,DS ;
|
|
; ;
|
|
; Registers Destroyed: ;
|
|
; ;
|
|
; Calls: ;
|
|
; ;
|
|
; History: ;
|
|
; ;
|
|
;-----------------------------------------------------------------------;
|
|
ifndef WOW_x86
|
|
assumes ds,nothing
|
|
assumes es,nothing
|
|
cProc get_rover_232,<PUBLIC,NEAR>,<di>
|
|
localV DscBuf,DSC_LEN
|
|
cBegin
|
|
push eax
|
|
push bx
|
|
SetKernelDS es
|
|
mov bx, kr2dsc
|
|
or bl, SEG_RING
|
|
smov es, ss
|
|
UnSetKernelDS es
|
|
lea di, DscBuf ; ES:DI -> descriptor
|
|
mov eax, ds:[esi].pga_address
|
|
mov [DscBuf].dsc_lbase, ax ; Fill in base address
|
|
shr eax, 16
|
|
mov [DscBuf].dsc_mbase, al
|
|
mov [DscBuf].dsc_hbase, ah
|
|
mov [DscBuf].dsc_limit, 1000h ; Real big limit
|
|
mov [DscBuf].dsc_hlimit, DSC_GRANULARITY
|
|
mov [DscBuf].dsc_access,DSC_PRESENT+DSC_DATA
|
|
DPMICALL 000Ch ; Set descriptor
|
|
mov es, bx
|
|
pop bx
|
|
pop eax
|
|
cEnd
|
|
endif; WOW
|
|
|
|
cProc far_get_temp_sel,<FAR,PUBLIC>
|
|
cBegin
|
|
cCall get_temp_sel
|
|
cEnd
|
|
|
|
cProc get_temp_sel,<PUBLIC,NEAR>,<ax,cx,di,si>
|
|
localV DscBuf,DSC_LEN
|
|
cBegin
|
|
mov cx, 1
|
|
DPMICALL 0000h ; Get us a selector
|
|
push bx
|
|
mov si, ax ; New selector
|
|
mov bx, es ; Old selector
|
|
|
|
ifdef WOW ; LATER Make single dpmicall
|
|
smov es, ss
|
|
lea di, DscBuf
|
|
|
|
DPMICALL 000Bh ; Get existing descriptor
|
|
|
|
mov DscBuf.dsc_access,DSC_PRESENT+DSC_DATA
|
|
mov DscBuf.dsc_limit,0ffffh
|
|
or DscBuf.dsc_hlimit, 0Fh ; Max length
|
|
|
|
mov bx, si
|
|
or bl, SEG_RING
|
|
|
|
DPMICALL 000Ch ; Set new descriptor
|
|
else
|
|
push ds
|
|
mov ds, gdtdsc
|
|
mov es, gdtdsc
|
|
mov di, si
|
|
and di, not 7
|
|
mov si, bx
|
|
and si, not 7
|
|
MovsDsc
|
|
lea bx, [di-DSC_LEN]
|
|
mov [bx].dsc_access,DSC_PRESENT+DSC_DATA
|
|
mov [bx].dsc_limit,0ffffh
|
|
or [bx].dsc_hlimit, 0Fh ; Max length
|
|
or bl, SEG_RING
|
|
pop ds
|
|
endif; WOW
|
|
mov es, bx
|
|
pop bx
|
|
cEnd
|
|
|
|
cProc far_free_temp_sel,<PUBLIC,FAR>
|
|
parmW selector
|
|
cBegin
|
|
cCall free_sel,<selector>
|
|
cEnd
|
|
|
|
;-----------------------------------------------------------------------;
|
|
; get_blotto
|
|
;
|
|
;
|
|
; Entry:
|
|
; EAX = arena header
|
|
;
|
|
; Returns:
|
|
; BX = Selector points to pga_address (size pga_arena)
|
|
; Registers Destroyed:
|
|
;
|
|
; History:
|
|
; Sun 31-Jul-1988 16:20:53 -by- David N. Weise [davidw]
|
|
;
|
|
;-----------------------------------------------------------------------;
|
|
|
|
assumes ds,nothing
|
|
assumes es,nothing
|
|
|
|
ifndef WOW_x86
|
|
;; On WOW_x86 we try to avoid setting selectors since it is slow, we use selector
|
|
;; 23h to write to anywhere in VDM memory.
|
|
|
|
|
|
cProc get_blotto,<PUBLIC,NEAR>,<di>
|
|
localV DscBuf,DSC_LEN
|
|
cBegin
|
|
push es
|
|
push bx
|
|
lea di, DscBuf
|
|
SetKernelDS es
|
|
mov bx, blotdsc
|
|
smov es, ss
|
|
UnSetKernelDS es
|
|
or bl, SEG_RING
|
|
push eax
|
|
mov eax, ds:[eax].pga_address
|
|
mov [DscBuf].dsc_lbase,ax
|
|
shr eax, 16
|
|
mov [DscBuf].dsc_mbase,al
|
|
mov [DscBuf].dsc_hbase,ah
|
|
|
|
; Convert pga_size to limit in page granularity
|
|
|
|
pop eax
|
|
mov eax, ds:[eax].pga_size ; Get Size in Bytes
|
|
add eax, 4096-1 ; Round up to 4k multiple
|
|
shr eax, 3*4
|
|
mov [DscBuf].dsc_limit,ax
|
|
shr eax,16
|
|
or al, DSC_GRANULARITY
|
|
|
|
mov [DscBuf].dsc_hlimit, al
|
|
mov [DscBuf].dsc_access,DSC_PRESENT+DSC_DATA
|
|
DPMICALL 000Ch ; Set up the descriptor
|
|
mov ax, bx
|
|
pop bx
|
|
pop es
|
|
cEnd
|
|
endif;
|
|
|
|
|
|
;-----------------------------------------------------------------------;
|
|
; LongPtrAdd
|
|
;
|
|
; Performs segment arithmetic on a long pointer and a DWORD offset
|
|
; The resulting pointer is normalized to a paragraph boundary.
|
|
; The offset cannot be greater than 16 megabytes (current Enh Mode
|
|
; limit on size of an object).
|
|
;
|
|
; Entry:
|
|
;
|
|
; Returns:
|
|
; DX:AX new segment:offset
|
|
;
|
|
; Error returns:
|
|
; DX:AX = 0
|
|
;
|
|
; Registers Destroyed:
|
|
; BX,CX
|
|
;
|
|
; History:
|
|
; Mon 19-Dec-1988 18:37:23 -by- David N. Weise [davidw]
|
|
; Wrote it!
|
|
;-----------------------------------------------------------------------;
|
|
|
|
assumes ds,nothing
|
|
assumes es,nothing
|
|
|
|
ifdef WOW
|
|
|
|
LPTRADDWOW_SETBASE equ 01h
|
|
|
|
;cProc LongPtrAddWOW,<PUBLIC,FAR>,<si,di>
|
|
; parmD long_ptr
|
|
; parmD delta
|
|
; parmW RefSelector
|
|
; parmW flBaseSetting
|
|
;
|
|
; effectively pops RefSelector and flBaseSetting into dx and ax.
|
|
; and jumps to longptrAddWorker.
|
|
;
|
|
; RefSelector is used only if the descriptor needs to be set.
|
|
;
|
|
|
|
labelFP <PUBLIC,LongPtrAddWOW>
|
|
pop ax
|
|
pop dx ; far return address
|
|
mov bx,sp
|
|
xchg ax, ss:[bx] ; replace the 'dword' with the return address
|
|
xchg dx, ss:[bx+2]
|
|
jmps LongPtrAddWorker ; ax = flags; dx = reference selector
|
|
|
|
labelFP <PUBLIC,LongPtrAdd>
|
|
mov ax, LPTRADDWOW_SETBASE
|
|
xor dx, dx
|
|
; fall through
|
|
|
|
cProc LongPtrAddWorker,<PUBLIC,FAR>,<si,di>
|
|
parmD long_ptr
|
|
parmD delta
|
|
localV DscBuf,DSC_LEN
|
|
localW flBaseSetting
|
|
localW RefSelector
|
|
cBegin
|
|
mov flBaseSetting, ax ; save in localvariables
|
|
mov RefSelector, dx
|
|
or dx, dx ; if RefSelector is nonzero
|
|
jz @F ; use it for querying descriptor info.
|
|
xchg dx, word ptr long_ptr[2] ; and store the selector to be set in
|
|
mov RefSelector, dx ; the localvariable
|
|
@@:
|
|
else
|
|
|
|
cProc LongPtrAdd,<PUBLIC,FAR>,<si,di>
|
|
parmD long_ptr
|
|
parmD delta
|
|
localV DscBuf,DSC_LEN
|
|
cBegin
|
|
|
|
endif
|
|
mov bx,word ptr long_ptr[2]
|
|
lea di, DscBuf
|
|
smov es, ss
|
|
DPMICALL 000Bh ; Pick up old descriptor
|
|
mov ax,word ptr long_ptr[0] ; get the pointer into SI:AX
|
|
and ax,0FFF0h
|
|
|
|
mov si, DscBuf.dsc_lbase ; DX:SI gets old base
|
|
mov dl, DscBuf.dsc_mbase
|
|
mov dh, DscBuf.dsc_hbase
|
|
|
|
add si, ax ; Add in old pointer offset
|
|
adc dx, 0
|
|
|
|
mov cx, word ptr delta[2] ; add the segment and MSW
|
|
test cx, 0FF00h ; bigger than 16Meg?
|
|
ifdef WOW
|
|
jz @F
|
|
test flBaseSetting, LPTRADDWOW_SETBASE
|
|
jnz lptr_mustset
|
|
jmp short lpa_too_big
|
|
@@:
|
|
else
|
|
jnz short lpa_too_big
|
|
endif
|
|
|
|
add si, word ptr delta[0] ; add the offset and LSW
|
|
adc dx, cx
|
|
|
|
ifdef WOW
|
|
lptr_mustset:
|
|
endif
|
|
|
|
mov cx, 1 ; Calculate # selectors now in array
|
|
lsl ecx, dword ptr long_ptr[2]
|
|
jnz short trash
|
|
Limit_to_Selectors ecx
|
|
trash:
|
|
ifdef WOW
|
|
test flBaseSetting, LPTRADDWOW_SETBASE
|
|
jz lptr_dontset
|
|
cmp RefSelector, 0
|
|
jz @F
|
|
mov bx, RefSelector ; get the actual selector to be set
|
|
mov word ptr long_ptr[2], bx
|
|
@@:
|
|
endif
|
|
mov DscBuf.dsc_lbase, si ; Put new base back in descriptor
|
|
mov DscBuf.dsc_mbase, dl
|
|
mov DscBuf.dsc_hbase, dh
|
|
|
|
call fill_in_selector_array
|
|
ifdef WOW
|
|
lptr_dontset:
|
|
test word ptr delta[2], 0ff00h
|
|
jz @F
|
|
mov cx, word ptr delta[2]
|
|
jmps lpa_too_big
|
|
@@:
|
|
endif
|
|
mov dx,word ptr long_ptr[2]
|
|
mov ax,word ptr long_ptr[0]
|
|
and ax, 0Fh
|
|
jnc short lpa_exit
|
|
|
|
lpa_too_big:
|
|
xor ax,ax
|
|
xor dx,dx
|
|
lpa_exit:
|
|
smov es,0
|
|
cEnd
|
|
|
|
|
|
;-----------------------------------------------------------------------;
|
|
; SetSelectorBase
|
|
;
|
|
; Sets the base and limit of the given selector.
|
|
;
|
|
; Entry:
|
|
; parmW selector
|
|
; parmD selbase
|
|
;
|
|
; Returns:
|
|
; AX = selector
|
|
;
|
|
; Error Returns:
|
|
; AX = 0
|
|
;
|
|
; History:
|
|
; Tue 23-May-1989 21:10:29 -by- David N. Weise [davidw]
|
|
; Wrote it!
|
|
;-----------------------------------------------------------------------;
|
|
|
|
assumes ds,nothing
|
|
assumes es,nothing
|
|
|
|
cProc SetSelectorBase,<PUBLIC,FAR>
|
|
parmW selector
|
|
parmD selbase
|
|
cBegin
|
|
push bx
|
|
push cx
|
|
push dx
|
|
mov cx, selbase.hi
|
|
mov dx, selbase.lo
|
|
mov bx, selector
|
|
ifdef WOW
|
|
DPMICALL 0007h ; Set Segment Base Address
|
|
else
|
|
push ds
|
|
mov ds, gdtdsc
|
|
push bx
|
|
and bl, not 7
|
|
mov ds:[bx].dsc_lbase, dx
|
|
mov ds:[bx].dsc_mbase, cl
|
|
mov ds:[bx].dsc_hbase, ch
|
|
pop bx
|
|
pop ds
|
|
endif; WOW
|
|
pop dx
|
|
pop cx
|
|
pop bx
|
|
mov ax,selector
|
|
cEnd
|
|
|
|
;-----------------------------------------------------------------------;
|
|
; GetSelectorLimit
|
|
;
|
|
; Sets the limit of the given selector.
|
|
;
|
|
; Entry:
|
|
; parmW selector
|
|
;
|
|
; Returns:
|
|
; DX:AX = limit of selector
|
|
;
|
|
; Registers Destroyed:
|
|
;
|
|
; History:
|
|
; Tue 23-May-1989 21:10:29 -by- David N. Weise [davidw]
|
|
; Wrote it!
|
|
;-----------------------------------------------------------------------;
|
|
|
|
assumes ds,nothing
|
|
assumes es,nothing
|
|
|
|
cProc GetSelectorLimit,<PUBLIC,FAR>
|
|
parmW selector
|
|
cBegin
|
|
xor eax, eax ; In case lsl fails
|
|
lsl eax, dword ptr selector
|
|
mov edx, eax
|
|
shr edx, 16
|
|
cEnd
|
|
|
|
|
|
;-----------------------------------------------------------------------;
|
|
; SetSelectorLimit
|
|
;
|
|
; Sets the limit of the given selector.
|
|
;
|
|
; Entry:
|
|
; parmW selector
|
|
; parmD sellimit
|
|
;
|
|
; Returns:
|
|
; AX = 0 success
|
|
;
|
|
; Registers Destroyed:
|
|
;
|
|
; History:
|
|
; Tue 23-May-1989 21:10:29 -by- David N. Weise [davidw]
|
|
; Wrote it!
|
|
;-----------------------------------------------------------------------;
|
|
|
|
assumes ds,nothing
|
|
assumes es,nothing
|
|
|
|
cProc SetSelectorLimit,<PUBLIC,FAR>
|
|
parmW selector
|
|
parmD sellimit
|
|
localV DscBuf,DSC_LEN
|
|
cBegin
|
|
|
|
ifdef WOW
|
|
mov bx, selector
|
|
mov dx, word ptr sellimit[0]
|
|
mov cx, word ptr sellimit[2]
|
|
DPMICALL 0008h
|
|
else
|
|
push es
|
|
push di
|
|
mov bx,selector
|
|
|
|
push ds
|
|
mov ds, gdtdsc
|
|
and bl, not 7
|
|
mov ax,sellimit.lo
|
|
mov [bx].dsc_limit,ax
|
|
mov ax,sellimit.hi
|
|
and al,0Fh ; AND out flags
|
|
and [bx].dsc_hlimit,0F0h ; AND out hi limit
|
|
or [bx].dsc_hlimit,al
|
|
pop ds
|
|
pop di
|
|
pop es
|
|
endif; WOW
|
|
xor ax,ax ; for now always return success
|
|
cEnd
|
|
|
|
|
|
;-----------------------------------------------------------------------;
|
|
; SelectorAccessRights
|
|
;
|
|
; Sets the access and other bytes of the given selector.
|
|
;
|
|
; Entry:
|
|
; parmW selector
|
|
; parmW getsetflag
|
|
; parmD selrights
|
|
;
|
|
; Returns:
|
|
; AX = 0 success
|
|
;
|
|
; Registers Destroyed:
|
|
;
|
|
; History:
|
|
; Tue 23-May-1989 21:10:29 -by- David N. Weise [davidw]
|
|
; Wrote it!
|
|
;-----------------------------------------------------------------------;
|
|
|
|
assumes ds,nothing
|
|
assumes es,nothing
|
|
|
|
cProc SelectorAccessRights,<PUBLIC,FAR>
|
|
|
|
parmW selector
|
|
parmW getsetflag
|
|
parmW selrights
|
|
cBegin
|
|
|
|
mov bx, selector
|
|
lar eax, ebx ; Get current access rights
|
|
shr eax, 8 ; in AX
|
|
|
|
cmp getsetflag,0
|
|
jnz short sar_set
|
|
|
|
and ax, 0D01Eh ; Hide bits they can't play with
|
|
jmps sar_exit
|
|
|
|
sar_set:
|
|
mov cx, selrights
|
|
and cx, 0D01Eh ; Zap bits they can't set and
|
|
and ax, NOT 0D01Eh ; get them from existing access rights
|
|
or cx, ax
|
|
DPMICALL 0009h ; Set new access rights
|
|
xor ax,ax ; for now always return success
|
|
|
|
sar_exit:
|
|
|
|
cEnd
|
|
|
|
|
|
cProc SetKernelCSDwordProc,<PUBLIC,NEAR>,<ax,bx,ds>
|
|
parmw addr
|
|
parmw hiword
|
|
parmw loword
|
|
cBegin
|
|
SetKernelDS
|
|
mov ds, MyCSAlias
|
|
UnSetKernelDS
|
|
mov bx, addr
|
|
mov ax, loword
|
|
mov [bx], ax
|
|
mov ax, hiword
|
|
mov [bx+2], ax
|
|
cEnd
|
|
|
|
cProc GetKernelDataSeg,<PUBLIC,NEAR>
|
|
cBegin nogen
|
|
mov ax, cs:MyCSDS
|
|
ret
|
|
cEnd nogen
|
|
|
|
cProc SetKernelDSProc,<PUBLIC,NEAR>
|
|
cBegin nogen
|
|
mov ds, cs:MyCSDS
|
|
ret
|
|
cEnd nogen
|
|
|
|
cProc SetKernelESProc,<PUBLIC,NEAR>
|
|
cBegin nogen
|
|
mov es, cs:MyCSDS
|
|
ret
|
|
cEnd nogen
|
|
|
|
assumes ds, nothing
|
|
assumes es, nothing
|
|
|
|
cProc PreallocArena,<PUBLIC,NEAR>
|
|
cBegin nogen
|
|
push ds
|
|
push eax
|
|
cCall alloc_arena_header,<eax>
|
|
call SetKernelDSProc
|
|
ReSetKernelDS
|
|
mov temp_arena, eax
|
|
or eax, eax ; Set flags for caller
|
|
pop eax
|
|
pop ds
|
|
UnSetKernelDS
|
|
ret
|
|
cEnd nogen
|
|
|
|
assumes ds, nothing
|
|
assumes es, nothing
|
|
|
|
cProc alloc_arena_header,<PUBLIC,NEAR>,<es>
|
|
parmD Address
|
|
localV DscBuf,DSC_LEN
|
|
cBegin
|
|
SetKernelDS es
|
|
push ebx
|
|
|
|
xor eax, eax
|
|
cmp temp_arena, eax ; Have one waiting?
|
|
je short aah_look ; no, get one
|
|
xchg temp_arena, eax ; Use the waiting selector
|
|
jmp aah_found
|
|
|
|
aah_look:
|
|
cmp FreeArenaCount, 0
|
|
jnz aah_ok
|
|
; Out of arenas, try to get
|
|
push ecx
|
|
push si
|
|
push di
|
|
xor bx, bx
|
|
mov cx, ARENA_INCR_BYTES
|
|
DPMICALL 0501h
|
|
jc short aah_no_memory
|
|
|
|
if 0
|
|
push si
|
|
push di
|
|
mov ax, 0600h ; Page lock it
|
|
mov di, ARENA_INCR_BYTES
|
|
xor si, si
|
|
int 31h
|
|
pop di
|
|
pop si
|
|
jnc short aah_got_memory
|
|
|
|
give_it_back:
|
|
DPMICALL 0502h ; No good, give it back
|
|
else
|
|
jmp short aah_got_memory
|
|
endif
|
|
|
|
aah_no_memory:
|
|
pop di
|
|
pop si
|
|
pop ecx
|
|
xor eax, eax ; We are REALLY out of arenas!
|
|
jmp aah_exit
|
|
|
|
aah_got_memory:
|
|
shl ebx, 16
|
|
mov bx, cx ; Address of our new arenas
|
|
cCall get_arena_pointer32,<ds>; Arena of burgermaster
|
|
sub ebx, [eax].pga_address ; Above present arenas?
|
|
|
|
lea ecx, [ebx+ARENA_INCR_BYTES+0FFFh]
|
|
shr ecx, 12 ; #pages selector must cover
|
|
dec ecx ; limit with page granularity
|
|
cmp ecx, HighestArena
|
|
jbe short aah_limitOK
|
|
|
|
|
|
mov HighestArena, ecx
|
|
push es
|
|
push bx
|
|
mov bx, ds
|
|
lea di, DscBuf
|
|
smov es, ss
|
|
DPMICALL 000Bh ; Get DS descriptor
|
|
mov [DscBuf].dsc_limit, cx ; Set the new limit in the descriptor
|
|
shr ecx, 16
|
|
and cl, 0fh ; hlimit bits
|
|
and [DscBuf].dsc_hlimit, not 0fh; Zap old ones
|
|
or cl, DSC_GRANULARITY ; Granularity bit
|
|
or [DscBuf].dsc_hlimit, cl
|
|
DPMICALL 000Ch ; Set new limit
|
|
pop bx
|
|
pop es
|
|
|
|
aah_limitOK:
|
|
mov cx, ARENA_INCR_BYTES
|
|
shr cx, 5 ; # arenas to add
|
|
aah_loop:
|
|
cCall free_arena_header,<ebx> ; Free up all our new arenas
|
|
add ebx, size GlobalArena32
|
|
loop aah_loop
|
|
|
|
pop di
|
|
pop si
|
|
pop ecx
|
|
|
|
aah_ok:
|
|
mov eax, FreeArenaList
|
|
if KDEBUG
|
|
inc eax
|
|
jnz short aah_ook
|
|
int 3
|
|
int 3
|
|
aah_ook:
|
|
dec eax
|
|
endif
|
|
mov ebx, ds:[eax.pga_next]
|
|
mov FreeArenaList, ebx
|
|
dec FreeArenaCount
|
|
aah_found:
|
|
mov ebx, Address
|
|
mov ds:[eax.pga_address], ebx
|
|
mov dword ptr ds:[eax.pga_count], 0
|
|
aah_exit:
|
|
pop ebx
|
|
cEnd
|
|
|
|
assumes ds, nothing
|
|
assumes es, nothing
|
|
|
|
cProc free_arena_header,<PUBLIC,NEAR>,<es>
|
|
parmD arena
|
|
cBegin
|
|
push eax
|
|
push ebx
|
|
SetKernelDS es
|
|
CheckDS
|
|
|
|
mov ebx, arena
|
|
mov eax, FreeArenaList
|
|
mov ds:[ebx.pga_next], eax
|
|
mov FreeArenaList, ebx
|
|
inc FreeArenaCount
|
|
pop ebx
|
|
pop eax
|
|
cEnd
|
|
|
|
assumes ds, nothing
|
|
assumes es, nothing
|
|
|
|
cProc FarAssociateSelector32,<PUBLIC,FAR>
|
|
parmW Selector
|
|
parmD ArenaPtr
|
|
cBegin
|
|
cCall AssociateSelector32,<Selector,ArenaPtr>
|
|
cEnd
|
|
|
|
cProc AssociateSelector32,<PUBLIC,NEAR>,<ds,es>
|
|
parmW Selector
|
|
parmD ArenaPtr
|
|
cBegin
|
|
CheckDS
|
|
SetKernelDS es
|
|
push eax
|
|
push ebx
|
|
movzx ebx, Selector
|
|
and bl, NOT SEG_RING_MASK
|
|
shr bx, 1
|
|
if KDEBUG
|
|
cmp bx, SelTableLen
|
|
jb short as_ok
|
|
INT3_NEVER
|
|
INT3_NEVER
|
|
as_ok:
|
|
endif
|
|
add ebx, SelTableStart
|
|
mov eax, ArenaPtr
|
|
mov ds:[ebx], eax
|
|
pop ebx
|
|
pop eax
|
|
cEnd
|
|
|
|
assumes ds, nothing
|
|
assumes es, nothing
|
|
|
|
cProc far_get_arena_pointer32,<PUBLIC,FAR>
|
|
parmW Selector
|
|
cBegin
|
|
cCall get_arena_pointer32,<Selector>
|
|
cEnd
|
|
|
|
cProc get_arena_pointer32,<PUBLIC,NEAR>
|
|
parmW Selector
|
|
cBegin
|
|
CheckDS
|
|
push es
|
|
SetKernelDS es
|
|
push ebx
|
|
movzx ebx, Selector
|
|
and bl, not SEG_RING_MASK
|
|
shr bx, 1
|
|
cmp bx, SelTableLen
|
|
jb short gap_ok
|
|
xor eax, eax ; Bogus, return null
|
|
jmps gap_exit
|
|
gap_ok:
|
|
add ebx, SelTableStart
|
|
mov eax, ds:[ebx]
|
|
|
|
if KDEBUG
|
|
or eax, eax
|
|
jz short gap_exit ; Bogus, return null
|
|
push si
|
|
mov si, ds:[eax].pga_handle
|
|
sel_check si
|
|
or si, si
|
|
jz short gap32_match ; Boot time...
|
|
sub ebx, SelTableStart
|
|
shl bx, 1
|
|
cmp bx, si
|
|
je short gap32_match
|
|
xor eax, eax ; put back in 5 feb 90, alias avoided
|
|
;;; xor eax, eax ; Removed - may be an alias!
|
|
gap32_match:
|
|
pop si
|
|
endif
|
|
|
|
gap_exit:
|
|
pop ebx
|
|
pop es
|
|
cEnd
|
|
|
|
assumes ds, nothing
|
|
assumes es, nothing
|
|
|
|
cProc FarGetOwner,<PUBLIC,FAR>,<bx>
|
|
parmW Selector
|
|
cBegin
|
|
cCall GetOwner,<Selector>
|
|
cEnd
|
|
|
|
cProc GetOwner,<PUBLIC,NEAR>,<bx,es>
|
|
parmW Selector
|
|
cBegin
|
|
GENTER32
|
|
;;;push eax ;; why??? ax gets trashed anyway.
|
|
cCall get_arena_pointer32,<Selector>
|
|
or eax, eax
|
|
jz go_solong
|
|
mov bx, ds:[eax].pga_owner
|
|
;;;pop eax
|
|
mov ax, bx
|
|
go_solong:
|
|
GLEAVE32
|
|
cEnd
|
|
|
|
assumes ds, nothing
|
|
assumes es, nothing
|
|
|
|
cProc FarSetOwner,<PUBLIC,FAR>
|
|
parmW Selector
|
|
parmW owner
|
|
cBegin
|
|
cCall SetOwner,<Selector,owner>
|
|
cEnd
|
|
|
|
assumes ds, nothing
|
|
assumes es, nothing
|
|
|
|
cProc SetOwner,<PUBLIC,NEAR>,<ds,es>
|
|
parmW Selector
|
|
parmW owner
|
|
cBegin
|
|
GENTER32 ; Assume ds not set!
|
|
push eax
|
|
cCall get_arena_pointer32,<Selector>
|
|
push owner
|
|
pop ds:[eax].pga_owner
|
|
pop eax
|
|
GLEAVE32
|
|
cEnd
|
|
|
|
|
|
assumes ds, nothing
|
|
assumes es, nothing
|
|
|
|
cProc PageLockLinear,<PUBLIC,NEAR>,<ax,bx,cx,si,di>
|
|
parmD address
|
|
parmD len
|
|
cBegin
|
|
mov bx, word ptr address+2
|
|
mov cx, word ptr address
|
|
mov si, word ptr len+2
|
|
mov di, word ptr len
|
|
DPMICALL 0600h
|
|
; Let it return with carry flag from int 31h
|
|
cEnd
|
|
|
|
assumes ds, nothing
|
|
assumes es, nothing
|
|
|
|
cProc FarValidatePointer,<PUBLIC,FAR>
|
|
parmD lpointer
|
|
cBegin
|
|
cCall ValidatePointer,<lpointer>
|
|
cEnd
|
|
|
|
cProc ValidatePointer,<PUBLIC,NEAR>
|
|
parmD lpointer
|
|
cBegin
|
|
lar ax, lpointer.sel
|
|
jnz short bad_p ; Really bad selector
|
|
test ah, DSC_PRESENT ; Must be present
|
|
jz short bad_p
|
|
lsl eax, dword ptr lpointer.sel
|
|
movzx ecx, lpointer.off
|
|
cmp eax, ecx ; Is the offset valid?
|
|
jae short good_p
|
|
bad_p:
|
|
xor ax, ax
|
|
jmps vp_done
|
|
good_p:
|
|
mov ax, 1
|
|
vp_done:
|
|
cEnd
|
|
|
|
|
|
assumes ds, nothing
|
|
assumes es, nothing
|
|
|
|
OneParaBytes dw 10h
|
|
|
|
|
|
cProc SelToSeg,<PUBLIC,NEAR>,<dx>
|
|
parmW selector
|
|
cBegin
|
|
cCall get_physical_address,<selector>
|
|
div cs:OneParaBytes ; Smaller than rotates
|
|
cEnd
|
|
|
|
|
|
cProc SegToSelector,<PUBLIC,NEAR>,<bx,cx,di,ds>
|
|
parmW smegma
|
|
cBegin
|
|
mov bx, smegma
|
|
DPMICALL 0002h ; Make win386 do it
|
|
|
|
cEnd
|
|
|
|
|
|
;-----------------------------------------------------------------------;
|
|
; set_discarded_sel_owner
|
|
;
|
|
; Sets the owner of a selector that points to a discarded object,
|
|
; which lives in the limit field.
|
|
;
|
|
; Entry:
|
|
; BX = selector to mark
|
|
; ES = owner
|
|
;
|
|
; Returns:
|
|
; nothing
|
|
;
|
|
; Registers Destroyed:
|
|
; BX
|
|
;
|
|
; History:
|
|
; Sun 03-Dec-1989 21:02:24 -by- David N. Weise [davidw]
|
|
; Wrote it!
|
|
;-----------------------------------------------------------------------;
|
|
|
|
assumes ds,nothing
|
|
assumes es,nothing
|
|
|
|
cProc set_discarded_sel_owner,<PUBLIC,FAR>
|
|
localV DscBuf,DSC_LEN
|
|
cBegin
|
|
push cx
|
|
push di
|
|
mov cx, es
|
|
|
|
if KDEBUG
|
|
ifdef WOW
|
|
lea di, DscBuf
|
|
smov es, ss
|
|
DPMICALL 000Bh
|
|
push cx
|
|
xor cx,cx ; For debug build write 0 to LDT
|
|
mov DscBuf.dsc_owner, cx
|
|
DPMICALL 000Ch
|
|
pop cx
|
|
endif
|
|
endif
|
|
push ds
|
|
mov ds, gdtdsc
|
|
push bx
|
|
and bl, not 7
|
|
mov [bx].dsc_owner, cx
|
|
pop bx
|
|
pop ds
|
|
push ds
|
|
SetKernelDS
|
|
mov ds, pGlobalHeap
|
|
UnSetKernelDS
|
|
cCall AssociateSelector32,<bx,0,cx> ; And save in selector table
|
|
pop ds
|
|
mov es, cx
|
|
pop di
|
|
pop cx
|
|
cEnd
|
|
|
|
;-----------------------------------------------------------------------;
|
|
; SetResourceOwner
|
|
;
|
|
; Sets the owner of a selector that points to a not present resource
|
|
;
|
|
; Entry:
|
|
;
|
|
; Returns:
|
|
; nothing
|
|
;
|
|
; Registers Destroyed:
|
|
;
|
|
; History:
|
|
;-----------------------------------------------------------------------;
|
|
|
|
assumes ds,nothing
|
|
assumes es,nothing
|
|
|
|
cProc SetResourceOwner,<PUBLIC,NEAR>,<ax,bx,cx,di,ds,es>
|
|
parmW selector
|
|
parmW owner
|
|
parmW selCount
|
|
localV DscBuf,DSC_LEN
|
|
cBegin
|
|
mov bx, selector
|
|
mov cx, owner
|
|
ifdef WOW
|
|
smov es, ss
|
|
lea di, DscBuf
|
|
DPMICALL 000Bh ; Get current descriptor
|
|
mov DscBuf.dsc_owner, cx
|
|
mov word ptr DscBuf.dsc_access, (DSC_DISCARDABLE SHL 8) + DSC_DATA
|
|
mov cx,selCount
|
|
mov DscBuf.dsc_hbase, cl ; Save number of selectors here
|
|
DPMICALL 000Ch ; Set it with new owner
|
|
else
|
|
push ds
|
|
mov ds, gdtdsc
|
|
push bx
|
|
and bl, not 7
|
|
mov [bx].dsc_owner, cx
|
|
mov word ptr [bx].dsc_access, (DSC_DISCARDABLE SHL 8) + DSC_DATA
|
|
mov cx, selCount
|
|
mov [bx].dsc_hbase, cl ; Save number of selectors here
|
|
pop bx
|
|
pop ds
|
|
endif; WOW
|
|
SetKernelDS
|
|
mov ds, pGlobalHeap
|
|
UnSetKernelDS
|
|
cCall AssociateSelector32,<bx,0,owner> ; And save in selector table
|
|
cEnd
|
|
|
|
cProc GetAccessWord,<PUBLIC,NEAR>
|
|
parmW selector
|
|
cBegin
|
|
lar eax, dword ptr selector ; 386 or better, can use LAR
|
|
shr eax, 8
|
|
cEnd
|
|
|
|
|
|
;-----------------------------------------------------------------------;
|
|
; DPMIProc
|
|
;
|
|
; Called NEAR by the DPMICALL macro -
|
|
; this is better than intercepting int 31h
|
|
;
|
|
; By sheer fluke, all intercepts return with
|
|
; Carry clear ie no error.
|
|
;
|
|
;-----------------------------------------------------------------------;
|
|
cProc DPMIProc,<PUBLIC,NEAR>
|
|
cBegin nogen
|
|
if 0
|
|
cmp ax,WOW_DPMIFUNC_0C
|
|
jne @f
|
|
|
|
INT3_TEST
|
|
push ds
|
|
SetKernelDS ds
|
|
cmp high0c,cx
|
|
ja popit
|
|
|
|
mov high0c,cx
|
|
popit:
|
|
pop ds
|
|
@@:
|
|
endif
|
|
|
|
ifdef WOW
|
|
cmp ax,501h
|
|
jne normal
|
|
|
|
push eax
|
|
push edx
|
|
|
|
shl ebx,16 ; ebx = bx:cx
|
|
mov bx,cx
|
|
|
|
xor eax,eax
|
|
mov ecx,PAGE_READWRITE
|
|
mov edx,MEM_COMMIT_RESERVE
|
|
cCall VirtualAlloc,<eax,ebx,edx,ecx>
|
|
|
|
mov bx,dx ; DPMI returns BX:CX - linear Address
|
|
mov cx,ax
|
|
|
|
mov si,dx ; FAKE dpmi "handle" - linear Address
|
|
mov di,ax
|
|
|
|
or ax,dx ; NULL is Error
|
|
pop edx
|
|
pop eax
|
|
|
|
clc
|
|
jnz @f ; OK Jump
|
|
stc ; else set error
|
|
@@:
|
|
ret
|
|
|
|
normal:
|
|
endif ; WOW
|
|
|
|
or ah, ah
|
|
|
|
jz @F
|
|
ife KDEBUG
|
|
ifdef WOW_x86
|
|
|
|
;
|
|
; If it is the wow set selector call we will just set the selector
|
|
; directly using int 2a (only for the single selector case)
|
|
;
|
|
cmp ax,WOW_DPMIFUNC_0C
|
|
jne CallServer
|
|
|
|
cmp cx,1
|
|
jne CallServer
|
|
|
|
call WowSetSelector
|
|
jc CallServer
|
|
ret
|
|
endif
|
|
endif
|
|
CallServer:
|
|
ifndef WOW
|
|
int 31h ; Nope, call DPMI server
|
|
ret
|
|
else
|
|
test word ptr [prevInt31Proc + 2],0FFFFh
|
|
jz dp30
|
|
dp20:
|
|
pushf
|
|
call [prevInt31Proc]
|
|
ret
|
|
endif
|
|
@@:
|
|
ifdef WOW
|
|
cmp gdtdsc, 0 ; Can we party?
|
|
jz CallServer ; Nope
|
|
endif
|
|
push ds
|
|
mov ds, gdtdsc
|
|
ifdef WOW
|
|
|
|
or al, al
|
|
jnz @F
|
|
mov ax, WOW_DPMIFUNC_00
|
|
pop ds
|
|
jmp CallServer
|
|
@@:
|
|
endif
|
|
cmp al, 0Bh
|
|
jne short @F
|
|
|
|
push si ; Get Descriptor - used very often!
|
|
mov si, bx
|
|
and si, not 7
|
|
MovsDsc
|
|
lea di, [di-DSC_LEN] ; Restore DI
|
|
pop si
|
|
pop ds
|
|
ret
|
|
ifndef WOW
|
|
@@:
|
|
cmp al, 0Ch
|
|
jne @F
|
|
|
|
push bx ; Set Descriptor
|
|
and bl, not 7
|
|
mov ax, es:[di] ; This looks slow but it isn't...
|
|
mov ds:[bx], ax
|
|
mov ax, es:[di][2]
|
|
mov ds:[bx][2], ax
|
|
mov ax, es:[di][4]
|
|
mov ds:[bx][4], ax
|
|
mov ax, es:[di][6]
|
|
mov ds:[bx][6], ax
|
|
pop bx
|
|
pop ds
|
|
ret
|
|
|
|
@@:
|
|
cmp al, 07h ; Set Segment Base Address
|
|
jne @F
|
|
push bx
|
|
and bl, not 7
|
|
mov ds:[bx].dsc_lbase, dx
|
|
mov ds:[bx].dsc_mbase, cl
|
|
mov ds:[bx].dsc_hbase, ch
|
|
pop bx
|
|
pop ds
|
|
ret
|
|
endif
|
|
@@:
|
|
cmp al, 06h ; Get Segment Base Address
|
|
jne @F
|
|
push bx
|
|
and bl, not 7
|
|
mov dx, ds:[bx].dsc_lbase
|
|
mov cl, ds:[bx].dsc_mbase
|
|
mov ch, ds:[bx].dsc_hbase
|
|
pop bx
|
|
pop ds
|
|
ret
|
|
ifndef WOW
|
|
@@:
|
|
cmp al, 09h ; Set Descriptor Access Rights
|
|
jne @F
|
|
push bx
|
|
and bl, not 7
|
|
mov word ptr ds:[bx].dsc_access, cx
|
|
pop bx
|
|
pop ds
|
|
ret
|
|
endif
|
|
@@:
|
|
pop ds
|
|
jmp CallServer
|
|
|
|
ifdef WOW
|
|
dp30: int 31h
|
|
ret
|
|
endif
|
|
cEnd nogen
|
|
|
|
ife KDEBUG
|
|
ifdef WOW_x86
|
|
;-----------------------------------------------------------------------;
|
|
; WowSetSelector
|
|
;
|
|
; Entry
|
|
; BX contains selector #
|
|
;
|
|
; Exit
|
|
; CY clear for success
|
|
;
|
|
;
|
|
;-----------------------------------------------------------------------;
|
|
cProc WowSetSelector,<PUBLIC,NEAR>
|
|
cBegin nogen
|
|
|
|
push ds
|
|
push es
|
|
push eax
|
|
push ecx
|
|
push edx
|
|
push ebx
|
|
push ebp
|
|
|
|
SetKernelDS ds
|
|
;
|
|
; Check to see if we can do this
|
|
;
|
|
mov edx, FlatAddressArray
|
|
or edx, edx
|
|
stc
|
|
jz wss50
|
|
|
|
;
|
|
; put the base of the selector in the flat address array
|
|
;
|
|
mov es,gdtdsc
|
|
and bx, NOT SEG_RING
|
|
mov ax, FLAT_SEL
|
|
mov ds, ax
|
|
mov ah, es:[bx].dsc_hbase
|
|
mov al, es:[bx].dsc_mbase
|
|
shl eax,16
|
|
mov ax, es:[bx].dsc_lbase
|
|
movzx ecx,bx
|
|
shr ecx,1 ; dword index from selector index
|
|
add ecx, edx ; point to proper spot in array
|
|
mov [ecx], eax
|
|
|
|
;
|
|
; Form the limit of the selector
|
|
;
|
|
movzx dx, byte ptr es:[bx].dsc_hlimit
|
|
and dx,0fh ; remove gran etc.
|
|
shl edx, 16
|
|
mov dx, es:[bx].dsc_limit
|
|
|
|
;
|
|
; Adjust for granularity
|
|
;
|
|
test es:[bx].dsc_hlimit, DSC_GRANULARITY
|
|
jz wss10
|
|
|
|
shl edx,12
|
|
or edx,0fffh
|
|
|
|
;
|
|
; Verify that the base/limit combination is allowed
|
|
; duplicate of code in dpmi32/i386/dpmi386.c <DpmiSetDescriptorEntry>
|
|
;
|
|
wss10: cmp edx,07ffeffffh
|
|
ja wss30
|
|
|
|
mov ecx,eax
|
|
add ecx,edx
|
|
cmp ecx,07ffeffffh
|
|
jb wss40
|
|
|
|
;
|
|
; Limit is too high, so adjust it downward
|
|
;
|
|
wss30: mov edx,07ffeffffh
|
|
sub edx,eax
|
|
sub edx,0fffh
|
|
|
|
;
|
|
; fix for granularity
|
|
;
|
|
test es:[bx].dsc_hlimit, DSC_GRANULARITY
|
|
jz wss35
|
|
|
|
shr edx,12
|
|
|
|
;
|
|
; store the new limit in the descriptor table
|
|
;
|
|
wss35: mov es:[bx].dsc_limit,dx
|
|
shr edx,16
|
|
movzx ax,es:[bx].dsc_hlimit
|
|
and ax,0f0h ; mask for gran etc
|
|
and dx,00fh ; mask for limit bits
|
|
or dx,ax ; put back gran etc
|
|
mov es:[bx].dsc_hlimit,dl
|
|
|
|
;
|
|
; Call the system to set the selector
|
|
;
|
|
; int 2a special case for wow:
|
|
;
|
|
; eax = 0xf0f0f0f1
|
|
; ebp = 0xf0f0f0f1
|
|
; ebx = selector
|
|
; ecx = first dword of the descriptor (LODWORD)
|
|
; edx = second dword of the descriptor (HIDWORD)
|
|
|
|
wss40: mov eax, 0f0f0f0f1h
|
|
mov ebp, 0f0f0f0f1h
|
|
mov ecx, dword ptr es:[bx]
|
|
mov edx, dword ptr es:[bx+4]
|
|
movzx ebx,bx
|
|
or bl, 3
|
|
int 02ah
|
|
|
|
wss50:
|
|
pop ebp
|
|
pop ebx
|
|
pop edx
|
|
pop ecx
|
|
pop eax
|
|
pop es
|
|
pop ds
|
|
ret
|
|
cEnd nogen
|
|
endif ; WOW_x86
|
|
endif
|
|
|
|
ifdef WOW
|
|
|
|
;-----------------------------------------------------------------------------
|
|
; Grab the selector 0x47 so that we dont need to special case the biosdata
|
|
; selector (0x40) while converting seg:off address to flat 32bit address
|
|
;
|
|
; This, however should not be part of Krnl286 heap.
|
|
;
|
|
; - Nanduri Ramakrishna
|
|
;-----------------------------------------------------------------------------
|
|
cProc AllocSelector_0x47,<PUBLIC,FAR>, <ax, bx, cx, ds>
|
|
cBegin
|
|
|
|
; alloc the specific selector
|
|
|
|
mov bx, 047h
|
|
DPMICALL 0dh
|
|
jc as47_exit
|
|
|
|
; initialize the LDT
|
|
|
|
and bx, not SEG_RING
|
|
mov ds, gdtdsc
|
|
mov [bx].dsc_limit, 00h ; = 1 byte
|
|
mov [bx].dsc_lbase, 0400h
|
|
mov [bx].dsc_mbase, 00h
|
|
mov [bx].dsc_hbase, 00h
|
|
|
|
mov ax, DSC_DATA+DSC_PRESENT
|
|
and ah, not 0Fh ; Zero limit 19:16
|
|
mov word ptr [bx].dsc_access, ax
|
|
|
|
; set the LDT
|
|
|
|
mov cx,1
|
|
mov bx, 047h
|
|
DPMICALL WOW_DPMIFUNC_0C
|
|
|
|
as47_exit:
|
|
cEnd
|
|
|
|
endif
|
|
|
|
sEnd CODE
|
|
|
|
sBegin NRESCODE
|
|
|
|
assumes CS,NRESCODE
|
|
assumes DS,NOTHING
|
|
assumes ES,NOTHING
|
|
|
|
; All the code below is to support DIB.DRV and WING.
|
|
|
|
cProc get_sel_flags,<PUBLIC,FAR>
|
|
parmW selector
|
|
cBegin
|
|
SetKernelDSNRes
|
|
mov ds,pGlobalHeap
|
|
cCall far_get_arena_pointer32,<selector>
|
|
or eax,eax
|
|
jz gsf5
|
|
movzx ax, byte ptr ds:[eax].pga_flags
|
|
gsf5:
|
|
xor dx,dx
|
|
cEnd
|
|
|
|
cProc set_sel_for_dib,<PUBLIC,FAR>
|
|
parmW selector
|
|
parmW flags
|
|
parmW addressLo
|
|
parmW addressHi
|
|
parmW csel
|
|
cBegin
|
|
SetKernelDSNRes
|
|
push ecx
|
|
push ebx
|
|
push fs
|
|
push es
|
|
|
|
; if the selector has a value of -1, it means we either need to allocate
|
|
; or deallocate an array of selectors. If we are allocating, csel will have
|
|
; a count of 64k selectors. If csel is 0, we need to deallocate the selector
|
|
; array pointed to by address.
|
|
|
|
cmp selector,-1
|
|
jne ssfSetDIB
|
|
|
|
; see if we are actually deleting the selector array
|
|
|
|
cmp csel,0
|
|
jne ssfAllocSel
|
|
|
|
; free selector array at addressHi
|
|
|
|
cCall IFreeSelector,<addressHi>
|
|
|
|
mov ax,1
|
|
mov dx,0
|
|
jmp ssf5
|
|
|
|
ssfAllocSel:
|
|
; we need to have the selector array created
|
|
|
|
cCall AllocSelectorArray,<csel>
|
|
mov selector,ax
|
|
|
|
xor dx,dx
|
|
cmp ax,0
|
|
je ssf5
|
|
|
|
; we must set the limits in the selectors. Each selector
|
|
; must have a limit in bytes for the remainder of the buffer. If there are
|
|
; 3 selectors, the first will be 0x0002ffff, the second 0x0001ffff, the
|
|
; third 0x0000ffff.
|
|
|
|
mov cx,csel
|
|
mov bx,selector
|
|
|
|
ssfSetLimit:
|
|
sub cx,1 ; 1 less each time
|
|
cCall SetSelectorLimit,<bx,cx,-1>
|
|
add bx,DSC_LEN ; advance to the next selector
|
|
cmp cx,0 ; see if we have any more selector to set
|
|
jne ssfSetLimit
|
|
|
|
|
|
mov dx,addressHi
|
|
mov ax,addressLo
|
|
push selector
|
|
call far_set_physical_address
|
|
|
|
mov ax,0 ; return the first selector
|
|
mov dx,selector
|
|
jmp ssf5
|
|
|
|
ssfSetDIB:
|
|
push ds
|
|
mov ds,pGlobalHeap
|
|
cCall far_get_arena_pointer32,<selector>
|
|
or eax,eax
|
|
jz ssf5
|
|
pop fs
|
|
push eax ; save arena ptr
|
|
cCall GrowHeapDib,<eax,addressHi,addressLo>
|
|
or eax,eax
|
|
jnz ssf0
|
|
pop eax
|
|
xor eax,eax
|
|
jmp ssf5
|
|
ssf0:
|
|
pop esi ; ds:esi is arena ptr
|
|
push eax ; save the new arena
|
|
xor edi,edi ; ds:edi is global heap info
|
|
cCall Free_Object2
|
|
mov dx,addressHi
|
|
mov ax,addressLo
|
|
cCall far_set_physical_address,<selector>
|
|
pop eax
|
|
push eax
|
|
cCall FarAssociateSelector32, <selector, eax>
|
|
|
|
; now see that the GAH_PHANTOM flag is set in the arena
|
|
pop edx
|
|
or ds:[edx].pga_flags, GAH_PHANTOM
|
|
|
|
; Now check if we are operating on a local heap. If so we change the
|
|
; LocalNotifyDefault to LocalNotifyDib.
|
|
push es
|
|
push selector
|
|
pop es
|
|
xor edi,edi
|
|
mov di,word ptr es:[pLocalHeap]
|
|
or di,di
|
|
jz ssf4 ; Its not a local heap
|
|
cmp edi,ds:[edx].pga_size
|
|
jae ssf4 ; Its not a local heap
|
|
cmp word ptr es:[di].li_sig,LOCALHEAP_SIG ; es:li_sig == LH
|
|
jne ssf4
|
|
if KDEBUG
|
|
cmp word ptr es:[di].li_notify,codeOFFSET LocalNotifyDefault
|
|
jne ssf2
|
|
cmp word ptr es:[di].li_notify+2,codeBase
|
|
je ssf3
|
|
ssf2:
|
|
krDebugOut <DEB_TRACE OR DEB_KrMemMan>, "Set_Sel_For_Dib: App has hooked LocalNotifyDefault"
|
|
ssf3:
|
|
endif
|
|
mov word ptr es:[di].li_notify,codeOFFSET LocalNotifyDib
|
|
mov word ptr es:[di].li_notify+2,codeBase
|
|
ssf4:
|
|
pop es
|
|
mov eax,1
|
|
ssf5:
|
|
pop es
|
|
pop fs
|
|
pop ebx
|
|
pop ecx
|
|
cEnd
|
|
|
|
cProc RestoreDib,<PUBLIC,FAR>
|
|
parmW selector
|
|
parmW flags
|
|
parmD address
|
|
localw hNewDib
|
|
localw cSel
|
|
localD DibSize
|
|
localD NewArena
|
|
localD OldArena
|
|
cBegin
|
|
SetKernelDSNRes
|
|
push ecx
|
|
push ebx
|
|
push fs
|
|
push es
|
|
|
|
;; Allocate a new global block
|
|
xor eax, eax ; In case lsl fails
|
|
lsl eax, dword ptr selector
|
|
or eax,eax
|
|
jz rd_fail
|
|
|
|
inc eax
|
|
mov DibSize,eax
|
|
cCall IGlobalAlloc,<flags,eax>
|
|
or ax,ax
|
|
jz rd_fail
|
|
|
|
mov hNewDib,ax
|
|
|
|
push ds
|
|
pop fs
|
|
mov ds,pGlobalHeap
|
|
cCall far_get_arena_pointer32,<selector>
|
|
mov OldArena,eax
|
|
or eax,eax
|
|
jz rd2
|
|
movzx ax, word ptr [eax].pga_selcount
|
|
mov cSel,ax
|
|
cCall far_get_arena_pointer32,<hNewDib>
|
|
or eax,eax
|
|
jnz rd5
|
|
rd2:
|
|
cCall IGlobalFree,<hNewDib>
|
|
jmp rd_fail
|
|
rd5:
|
|
mov NewArena,eax
|
|
cld
|
|
|
|
push ds
|
|
mov ecx,DibSize
|
|
mov ax, hNewDib
|
|
or ax, 1
|
|
mov es, ax
|
|
mov ds, selector
|
|
xor esi, esi
|
|
xor edi, edi
|
|
mov eax,ecx
|
|
shr ecx,2 ; dwords
|
|
rep movs dword ptr es:[edi], dword ptr ds:[esi]
|
|
and eax,3
|
|
mov ecx,eax
|
|
rep movs byte ptr es:[edi], byte ptr ds:[esi]
|
|
|
|
pop ds
|
|
|
|
;; free the selector that came back with GlobalAlloc
|
|
xor eax,eax
|
|
cCall farAssociateSelector32, <hNewDib,eax>
|
|
cCall IFreeSelector, <hNewDib>
|
|
|
|
;; Map the original selector to this new block
|
|
mov eax,NewArena
|
|
mov edx,[eax].pga_address
|
|
mov ebx,[eax].pga_size
|
|
dec ebx
|
|
mov ax,dx
|
|
shr edx,16
|
|
cCall far_set_physical_address,<selector>
|
|
mov eax,NewArena
|
|
cCall farAssociateSelector32, <selector,eax>
|
|
mov cx,cSel
|
|
mov dx,selector
|
|
rd13:
|
|
dec cx
|
|
push bx
|
|
push cx
|
|
push dx
|
|
cCall SetSelectorLimit,<dx,cx,bx>
|
|
pop dx
|
|
pop cx
|
|
pop bx
|
|
add dx,DSC_LEN ; advance to the next selector
|
|
jcxz rd14
|
|
jmp short rd13
|
|
rd14:
|
|
|
|
;; Fix some values in the new arena from old arena
|
|
mov eax,NewArena
|
|
mov ebx,OldArena
|
|
|
|
mov ecx,dword ptr [ebx].pga_handle
|
|
mov dword ptr [eax].pga_handle,ecx
|
|
mov ecx,dword ptr [ebx].pga_count
|
|
dec ecx
|
|
mov dword ptr [eax].pga_count,ecx
|
|
|
|
and byte ptr [eax].pga_flags, NOT GAH_PHANTOM
|
|
|
|
;; Free the dib
|
|
cCall FreeHeapDib, <OldArena>
|
|
|
|
; Now check if we are operating on a local heap. If we so change the
|
|
; LocalNotifyDiB to LocalNotify.
|
|
|
|
mov edx, NewArena
|
|
push selector
|
|
pop es
|
|
xor edi,edi
|
|
mov di,word ptr es:[pLocalHeap]
|
|
or di,di
|
|
jz rd_15
|
|
cmp edi,ds:[edx].pga_size
|
|
jae rd_15 ; Its not a local heap
|
|
cmp word ptr es:[di].li_sig,LOCALHEAP_SIG ; es:li_sig == LH
|
|
jne rd_15
|
|
mov word ptr es:[di].li_notify,codeOFFSET LocalNotifyDefault
|
|
mov word ptr es:[di].li_notify+2,codeBase
|
|
|
|
rd_15:
|
|
mov eax,1
|
|
jmp short rd_exit
|
|
|
|
rd_fail:
|
|
xor eax,eax
|
|
|
|
rd_exit:
|
|
pop es
|
|
pop fs
|
|
pop ebx
|
|
pop ecx
|
|
cEnd
|
|
|
|
cProc DibRealloc,<PUBLIC,FAR>
|
|
parmW Selector
|
|
parmW NewSize
|
|
cBegin
|
|
SetKernelDSNRes
|
|
|
|
push ebx
|
|
mov ds,pGlobalHeap
|
|
cCall far_get_arena_pointer32,<Selector>
|
|
or eax,eax
|
|
jz dr20
|
|
|
|
movzx ebx,NewSize
|
|
mov ds:[eax].pga_size,bx
|
|
add ebx,ds:[eax].pga_address
|
|
mov eax,ds:[eax].pga_next
|
|
mov dword ptr ds:[eax].pga_address,ebx
|
|
mov bx,NewSize
|
|
dec bx
|
|
cCall SetSelectorLimit,<Selector,0,bx>
|
|
mov ax,Selector
|
|
jmp short drexit
|
|
dr20:
|
|
xor ax,ax
|
|
drexit:
|
|
pop ebx
|
|
cEnd
|
|
|
|
|
|
sEnd NRESCODE
|
|
|
|
|
|
end
|
|
|