    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

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

if ROM
externW selROMTOC
externW selROMLDT
externW sel1stAvail
endif

if ROM
externD lmaHiROM
externD cbHiROM
externD linHiROM
endif

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

if ROM
externW gdtdsc
endif

public MS_DOS_Name_String
MS_DOS_Name_String	db	"MS-DOS", 0

DataEnd INIT


sBegin	CODE
assumes cs,CODE
assumes ds,nothing


externNP genter
externNP gleave
extrn IGlobalFix:FAR                    ;Far calls in this segment
extrn GlobalHandleNorip:FAR
extrn IGlobalFlags:FAR
extrn IGlobalHandle: FAR

extrn	mycsds:WORD

ife ROM
extrn	gdtdsc:WORD
endif

ifdef WOW
externD prevInt31proc
externFP VirtualAlloc
endif


sEnd	CODE

sBegin	INITCODE
assumes cs,CODE
assumes ds,nothing

;=======================================================================;
;									;
; 386 PROTECTED MODE INITIALISATION ROUTINES				;
;									;
;=======================================================================;

ife ROM

;   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
	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
ifndef WOW  ; For WOW its all pageable
	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
externFP kSYSERRORBOX
	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

endif

;-----------------------------------------------------------------------;
; 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
if ROM
	SetKernelDS
endif
	mov	ds, gdtdsc
if ROM
	assumes ds,nothing
endif
	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	ax,fs
        and     ax, not 7           ; remove ring bits
        push    bx
        and     bx, not 7           ; remove ring bits
        cmp     ax,bx
        pop     bx
	jnz	ARSA_dont_do_it1

        xor     ax,ax               ; QuatroPro passes around FS which is
        mov     fs,ax               ; about to be made not present.  Since we
                                    ; can't live with not present selectors
                                    ; in segment registers, we just blow it
				    ; away
ARSA_dont_do_it1:
	mov	ax,gs
        and     ax, not 7           ; remove ring bits
        push    bx
        and     bx, not 7           ; remove ring bits
        cmp     ax,bx
        pop     bx
	jnz	ARSA_dont_do_it

	xor	ax,ax
	mov	gs,ax

ARSA_dont_do_it:
	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
if 0 ;;ROM and KDEBUG
	call	CheckROMSelector
endif
	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
	cmp	fbooting,1		; Don't do optimization during boot
					; since free_Sel will return them to
					; DPMI.
	jz	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
	kerror	0,<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

if ROM
;
;   there is a bunch of selector allocating in the ROM initialization
;   so have a couple functions for 16 bit limits...
;

cProc	far_alloc_data_sel16, <PUBLIC,FAR>

    parmD   base
    parmW   limit

cBegin

    movzx   eax, limit
    shl     eax, 4
    mov     edx, base
    cCall   alloc_data_sel, <edx, eax>

cEnd

cProc	alloc_data_sel16, <PUBLIC, NEAR>

    parmD   base
    parmW   limit

cBegin
    movzx   eax, limit
    shl     eax, 4		    ;; this is is paragraphs...
    mov     edx, base
    cCall   alloc_data_sel, <edx, eax>
cEnd

endif


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

if ROM
	SetKernelDS
	mov	ds, gdtdsc
	assumes ds,nothing
else
	mov	ds, gdtdsc
endif
	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

if ROM
	; don't free ROM selectors...
	cmp	bx, sel1stAvail
	jb	sel_freed
endif

	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
    cmp  ah, ch
    je   short LDTs_match

    kerror  0, <System LDT doesn't 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
if ROM
	SetKernelDS
	mov	es,gdtdsc
	mov	ds,gdtdsc
	assumes ds,nothing
else
	mov	ds,gdtdsc
	mov	es,gdtdsc
endif
	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
if ROM
	SetKernelDS
	mov	es, gdtdsc
	mov	ds, gdtdsc
	assumes ds, nothing
else
	mov	ds, gdtdsc
	mov	es, gdtdsc
endif
	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 bonehead
        ;**     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
if ROM
	SetKernelDS
	mov	es, gdtdsc
	mov	ds, gdtdsc
	assumes ds, nothing
else
	mov	ds, gdtdsc
	mov	es, gdtdsc
endif
	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
if ROM
	SetKernelDS
	mov	ds, gdtdsc
	assumes ds, nothing
else
	mov	ds, gdtdsc
endif
	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
if ROM
	SetKernelDS
	mov	ds, gdtdsc
	assumes ds, nothing
else
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
endif; ROM
	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
if ROM
	SetKernelDS
	mov	ds, gdtdsc
	assumes ds,nothing
else
	mov	ds, gdtdsc
endif
	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
if ROM
	SetKernelDS
	mov	ds, gdtdsc
	assumes ds, nothing
else
	mov	ds, gdtdsc
endif
	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:
ife ROM
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 KDEBUG
dref_invalid:
	push	ax
	kerror	ERR_GMEMHANDLE,<gdref: invalid handle>,0,dx
	pop	ax
	jmps	pd_nomatch
endif
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
ifdef WOW
	lea	di, DscBuf
        smov    es, ss
	DPMICALL 000Bh			; Get source descriptor
	mov	word ptr DscBuf.dsc_access, DSC_PRESENT+DSC_DATA
	mov	bx, kr2dsc		; kr2dsc is target
	or	bl, SEG_RING
        DPMICALL 000Ch
else
	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
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
	assumes	ds,nothing
	assumes	es,nothing
cProc	get_rover_232,<PUBLIC,NEAR>,<di>
	localV	DscBuf,DSC_LEN
cBegin
	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
if ROM
	SetKernelDS
	mov	es, gdtdsc
	mov	ds, gdtdsc
	UnsetKernelDS
else
	mov	ds, gdtdsc
	mov	es, gdtdsc
endif
	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
;; On WOW 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
if ROM
	SetKernelDS
	mov	ds, gdtdsc
	UnsetKernelDS
else
	mov	ds, gdtdsc
endif
	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
if ROM
	SetKernelDS
	mov	ds, gdtdsc
	UnsetKernelDS
else
	mov	ds, gdtdsc
endif
	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 ROM
	; hack for ROM-owned selectors.  these do not have arenas
	; but the owner is stored in the low word.  ack ack ack!!
	;
	cmp	eax, 0FFFF0000h
	jb	short @F
	xor	eax, eax
@@:
endif

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>
if ROM
	or	eax, eax
	jnz	short @F
	cCall	GetROMOwner,<selector>
	jmp	short go_solong
@@:
endif
	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
if ROM
	SetKernelDS
	mov	ds, gdtdsc
	UnsetKernelDS
else
	mov	ds, gdtdsc
endif
	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
        mov     ax,fs
        and     ax, not 7           ; remove ring bits
        push    bx
        and     bx, not 7           ; remove ring bits
        cmp     ax,bx
        pop     bx
        jnz     dont_do_it

        xor     ax,ax               ; QuatroPro passes around FS which is
        mov     fs,ax               ; about to be made not present.  Since we
                                    ; can't live with not present selectors
                                    ; in segment registers, we just blow it
                                    ; away

; BUGBUG should do the same for GS

dont_do_it:
	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
if ROM
	SetKernelDS
	mov	ds, gdtdsc
	UnsetKernelDS
else
	mov	ds, gdtdsc
endif
	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
	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:
        or      ah, ah

        jz      @F
ife KDEBUG
ifdef WOW        

        ;
        ; 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
if 0 ;;ROM and KDEBUG
        call    CheckROMSelector
endif
        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
if 0 ;;ROM and KDEBUG
        call    CheckROMSelector
endif
        pop     bx
        pop     ds
        ret
endif
@@:
        pop     ds
        jmp     CallServer

ifdef WOW
dp30:   int     31h
        ret
endif
cEnd nogen

ife KDEBUG
ifdef WOW
;-----------------------------------------------------------------------;
; 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
endif
if ROM

;-----------------------------------------------------------------------------
;
;   Functions for ROM Windows
;
;

;-----------------------------------------------------------------------------
;
;   HocusROMBase
;
;-----------------------------------------------------------------------------

assumes ds,nothing
assumes es,nothing
assumes fs,nothing
assumes gs,nothing

cProc	HocusROMBase, <PUBLIC, FAR>

    parmW   selector

cBegin
    push    bx
    push    cx
    push    dx
    push    ds
    SetKernelDS
    mov     bx, selector
    DPMICALL 0006h
    mov     ax, cx
    shl     eax, 16
    mov     ax, dx
    sub     eax, lmaHiROM
    jb	    not_in_hi_rom
    cmp     eax, cbHiROM
    jae     not_in_hi_rom
    add     eax, linHiROM
    mov     dx, ax
    shr     eax, 16
    mov     cx, ax
    DPMICALL 0007h
not_in_hi_rom:
    mov     ax, bx
    pop     ds
    UnsetKernelDS
    pop     dx
    pop     cx
    pop     bx
cEnd


;-----------------------------------------------------------------------------
;
;   ChangeROMHandle
;
;-----------------------------------------------------------------------------

assumes ds,nothing
assumes es,nothing
assumes fs,nothing
assumes gs,nothing

cProc	ChangeROMHandle, <FAR, PUBLIC>, <si, bx, es, di, ds>

    parmW   hold
    parmW   hnew

    localV  dscbuf, DSC_LEN

cBegin

    SetKernelDS
    mov     ds, ArenaSel
    UnsetKernelDS

    mov     bx, hold
    cCall   get_arena_pointer32, <bx>
    or	    eax, eax
    jz	    short crh_bummer_dude

    push    eax

    mov     si, bx
    and     si, SEG_RING_MASK
    or	    si, hnew
    smov    es, ss
    lea     di, dscbuf
    DPMICALL	000Bh
    xchg    bx, si
    DPMICALL	000Ch

    cCall   AssociateSelector32, <si, 0, 0>

    pop     eax

    test    dscbuf.dsc_access, DSC_PRESENT
    jz	    short @F
    mov     ds:[eax].pga_handle, bx
@@:
    cCall   AssociateSelector32, <bx, eax>
    cCall   FreeSelArray, <hold>

    mov     ax, bx

crh_bummer_dude:

cEnd


;-----------------------------------------------------------------------------
;
;   CloneROMSelector
;
;-----------------------------------------------------------------------------

assumes ds,nothing
assumes es,nothing
assumes fs,nothing
assumes gs,nothing

cProc	CloneROMSelector, <NEAR, PUBLIC>, <es, di, bx, ds>

    parmW   selROM
    parmW   selClone

cBegin

    SetKernelDS
    mov     di, selROM
    mov     es, selROMTOC
    assumes es, nothing
    and     di, NOT SEG_RING_MASK
    sub     di, es:[FirstROMSel]
    mov     es, selROMLDT
    mov     bx, selClone
    DPMICALL	000Ch

    cCall   HocusROMBase, <bx>

    mov     ds, ArenaSel
    cCall   AssociateSelector32, <bx, 0, 0>

    mov     ax, bx

cEnd

;-----------------------------------------------------------------------------
;
;   Get/SetROMOwner
;
;-----------------------------------------------------------------------------

assumes ds,nothing
assumes es,nothing
assumes fs,nothing
assumes gs,nothing

cProc	SetROMOwner, <NEAR, PUBLIC>, <ds, ebx, es>

	parmW	selector
	parmW	owner

cBegin
	GENTER32
	cCall	AssociateSelector32, <selector, 0FFFFh, owner>
	GLEAVE32
cEnd

cProc	FarSetROMOwner, <FAR, PUBLIC>

	parmW	selector
	parmW	owner

cBegin
	cCall	SetROMOwner, <selector, owner>
cEnd

cProc	GetROMOwner, <NEAR, PUBLIC>, <ds, es, ebx>

	parmW	selector

cBegin
	UnsetKernelDS
	SetKernelDS es
	mov	ds, ArenaSel
	movzx	ebx, selector
	and	bl, not SEG_RING_MASK
	shr	bx, 1
	cmp	bx, SelTableLen
	jae	short gro_nope
	add	ebx, SelTableStart
	mov	eax, ds:[ebx]
	cmp	eax, 0FFFF0000h
	jae	short gro_ok
gro_nope:
	xor	eax, eax
gro_ok:
cEnd

;-----------------------------------------------------------------------------
;
;   IsROMObject
;
;-----------------------------------------------------------------------------

assumes ds,nothing
assumes es,nothing
assumes fs,nothing
assumes gs,nothing

cProc	IsROMObject, <NEAR, PUBLIC>, <bx, di, es>

	parmW	selector
	localV	DscBuf, DSC_LEN

cBegin

if KDEBUG
	mov	ax, selector
	sel_check   ax
endif

	mov	bx, selector
	smov	es, ss
	lea	di, DscBuf
	DPMICALL    000Bh

	SetKernelDS ES

	mov	ah, DscBuf.dsc_hbase
	mov	al, DscBuf.dsc_mbase
	shl	eax, 16
	mov	ax, DscBuf.dsc_lbase
	sub	eax, linHiROM
	jc	short iro_not_rom
	sub	eax, cbHiROM
	jnc	short iro_not_rom
	mov	al, 1
	jmps	iro_exit

iro_not_rom:
	xor	eax, eax

iro_exit:
cEnd

cProc	FarIsROMObject, <FAR, PUBLIC>

	parmW	selector

cBegin
	cCall	IsROMObject, <selector>
cEnd

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

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

    ; 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

    mov     dx,addressHi
    mov     ax,addressLo
    push    selector
    call    far_set_physical_address

    ; 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     ax,0        ; return the first selector
    mov     dx,selector
    jmp     ssf5

ssfSetDIB:
    mov     ds,pGlobalHeap
    cCall   far_get_arena_pointer32,<selector>
    mov     edx,eax
    or      eax,eax
    jz      ssf5
    push    word ptr ds:[eax].pga_address       ; push base address
    push    word ptr ds:[eax].pga_address+2
    movzx   bx,flags
    mov     dx,addressLo
    mov     byte ptr ds:[eax].pga_flags,bl
    mov     word ptr ds:[eax].pga_address, dx
    mov     dx,addressHi
    mov     word ptr ds:[eax].pga_address+2, dx
    mov     ax,addressLo
    cCall   far_set_physical_address,<selector>
    pop     dx                                  ; pop base address
    pop     ax
ssf5:
    pop     ebx
    pop     ecx
cEnd

sEnd	NRESCODE


end

