    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

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

externFP IGlobalFree
externFP IGlobalAlloc

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

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
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
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     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
    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
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

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
ifdef WOW
        lea     di, DscBuf
        smov    es, ss
        DPMICALL 000Bh                  ; Get source descriptor
        mov     byte 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_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
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_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
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
        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

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
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_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
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

; 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

