;******************************************************************************
;
;   (C) Copyright IBM Corp. 1989-1993
;
;   Module:   HIGHEXIT.INC - Code executed after LoadHigh or DeviceHigh
;
;   Date:     May 14, 1992
;
;******************************************************************************
;
;   Modification log:
;
;     DATE    WHO      DESCRIPTION
;   --------  -------  --------------------------------------------------------
;   05/14/92  t-richj  Original
;   06/21/92  t-richj  Final revisions before check-in
;
;******************************************************************************
;
;
; Public:
;
;       PROCEDURES
;               FreeUMBs
;               HeadUMB
;               UnHideUMBs
;
; Internal:
;
;       PROCEDURES
;               freeMCB
;               he_unlink
;               isHideMCB
;               linkumb
;
; Definitions:
;
;       DOS_STRATEGY_SET -      AX value when calling int 21h, to set the DOS
;                               memory-allocation strategy.
;       DOS_UMBLINK_SET -       AX value when calling int 21h, to set the UMB
;                               link-state.
;       DOS_GET_LISTS -         AH value when calling int 21h, to get the DOS
;                               "list of lists".
;       UMB_HeadIdx -           After returning from int 21h, func 52h...
;                               ES:[Umb_HeadIdx] will contain the address of
;                               the first UMB delimiter, usually 0x9FFF... if
;                               it's 0xFFFF, then it hasn't been set yet.
;
; *****************************************************************************

DOS_STRATEGY_GET  equ   5800h   ; Int 21h, Func 58h, Svc 0 = get alloc strategy
DOS_STRATEGY_SET  equ   5801h   ; Int 21h, Func 58h, Svc 1 = set alloc strategy
DOS_UMBLINK_GET   equ   5802h   ; Int 21h, Func 58h, Svc 2 = get link state
DOS_UMBLINK_SET   equ   5803h   ; Int 21h, Func 58h, Svc 3 = set link state
DOS_GET_LISTS     equ     52h   ; Int 21h, Func 52h = get list of lists

UMB_HeadIdx       equ     8Ch   ; Offset from ES (after func52h) to get UMBHead

;
; If HV_LoadHigh has been defined, this is going into stub.asm under
; cmd\command... and stub doesn't include dosmac.inc.  So, rather than
; include dosmac to get BREAK, its definition is just copied here.
;

ifdef HV_LoadHigh

BREAK   MACRO   subtitle        ; Arena.inc, below, needs this macro... but
        SUBTTL  subtitle        ; if we include dosmac to get it, we've gotta
        PAGE                    ; include more crap, and so on, and so on, and
ENDM                            ; so on, and so on, and so on, and so on...

include arena.inc       ; For DeviceHigh, highload and highexit are in the
                        ; same module, so they both have arena.inc; in LoadHigh
endif                   ; they don't.

; -----------------------------------------------------------------------------
;*** UnHideUMBs - Marks HIDDEN elements as FREE
; -----------------------------------------------------------------------------
; ENTRY:  None; perhaps, earlier, HideUMBs was called... if not, we have
;               very little to do, as no elelments will be marked as HIDDEN.
; EXIT:   Sets InHigh to zero; carry clear if HideUMBs was called earlier.
; ERROR:  None
; USES:   fInHigh (from highvar.inc), carry flag
; -----------------------------------------------------------------------------

        public  UnHideUMBs

UnHideUMBs      proc    near
        push    ax              ; Save ax for what we're about to do

; -----------------------------------------------------------------------------
; BUGBUG t-richj 11-8-92: The following six lines were commented out for a good
;    length of time.  Those six constitute a check of whether or not we should
;    indeed clean up the upper-memory chain; without such a check, COMMAND.COM
;    will destroy the current link-state and memory-allocation strategy after
;    every command execution.
; -----------------------------------------------------------------------------

        getdata al, fInHigh     ; Get InHigh from data segment
        or      al, al
        jnz     uhu10           ; If didn't call loadhigh/devicehigh earlier,

        pop     ax              ; then there's nothing to do here... so
        stc                     ; restore everything and return.  Just like
        ret                     ; that.


uhu10:  call    linkumb         ; Make sure UMBs are linked in.
        call    FreeUMBs

        putdata fInHigh, 0      ; We're leaving, so update fInHigh.

        call    he_unlink       ; Unlink UMBs

        pop     ax
        clc
        ret
UnHideUMBs      endp

; -----------------------------------------------------------------------------
;*** he_unlink - unlinks UMBs if fm_umb is set to 0
; -----------------------------------------------------------------------------
; ENTRY:    fm_umb == 1 : leave linked, else unlink
; EXIT:     None
; ERROR:    None
; USES:     AX, BX
; -----------------------------------------------------------------------------

he_unlink       proc    near
        xor     bh, bh
        getdata bl, fm_umb              ; Restore original link-state
        mov     ax, DOS_UMBLINK_SET
        int     21h

ifdef HV_LoadHigh
        xor     bh, bh
        getdata bl, fm_strat            ; Restore original mem-alloc strategy

        mov     ax, DOS_STRATEGY_SET
        int     21h
endif
        ret
he_unlink       endp

; -----------------------------------------------------------------------------
;*** freeUMBs - frees all HIDDEN memory elements in upper-memory.
; -----------------------------------------------------------------------------
; ENTRY:    None
; EXIT:     None; HIDDEN memory elements returned to FREE
; ERROR:    None (ignore CF)
; USES:     Flags
; -----------------------------------------------------------------------------

        public  FreeUMBs

FreeUMBs        proc    near
        pushreg <ax, es>

        call    HeadUmb         ; Returns with carry if err, else ES == MCB
        jc      fusX

fus10:  mov     es, ax          ; Prepare for the loop; ES = current MCB addr.

        call    isHideMCB       ; Returns with ZF set if owner is 0
        jnz     fus20
        call    freeMCB

fus20:  mov     al, es:[arena_signature]
        cmp     al, arena_signature_end
        jz      fusX            ; That means this was the last MCB--that's it.

        mov     ax, es
        add     ax, es:[arena_size]
        inc     ax
        jmp short fus10

fusX:   popreg  <es, ax>
        ret
FreeUMBs        endp

; -----------------------------------------------------------------------------
;*** isHideMCB - returns with ZF set if current MCB (ES:0) is HIDDEN
; -----------------------------------------------------------------------------
; ENTRY:    ES:0 should point to an MCB
; EXIT:     ZF set if MCB is hidden, else !ZF
; ERROR:    None
; USES:     Flags
; -----------------------------------------------------------------------------

isHideMCB       proc    near
        push    ax

        cmp     es:[arena_owner], SystemPSPOwner        ; If the owner's SYSTEM
        jnz     ihm_x                                   ; then check for HIDDEN

        mov     ax, word ptr es:[arena_name]
        cmp     ax, 'IH'
        jnz     ihm_x
        mov     ax, word ptr es:[arena_name+2]
        cmp     ax, 'DD'
        jnz     ihm_x
        mov     ax, word ptr es:[arena_name+4]
        cmp     ax, 'NE'
        jnz     ihm_x
        mov     ax, word ptr es:[arena_name+6]
        cmp     ax, '  '

ihm_x:  pop     ax
        ret
isHideMCB       endp

; -----------------------------------------------------------------------------
;*** freeMCB - marks as free the MCB at ES:0
; -----------------------------------------------------------------------------
; ENTRY:    ES:0 should point to an MCB
; EXIT:     None; MCB free'd
; ERROR:    None
; USES:     AX
; -----------------------------------------------------------------------------

freeMCB proc    near
        mov     es:[arena_owner], 0
        mov     ax, '  '
        mov     word ptr es:[arena_name+0], ax
        mov     word ptr es:[arena_name+2], ax
        mov     word ptr es:[arena_name+4], ax
        mov     word ptr es:[arena_name+6], ax
        ret
freeMCB endp

; -----------------------------------------------------------------------------
;*** HeadUmb - returns in AX the address of the first UMB block (0x9FFF)
; -----------------------------------------------------------------------------
; ENTRY:  Nothing
; EXIT:   AX contains 0x9FFF for most systems
; ERROR:  Carry set if pointer is 0xFFFF (if not set up yet--DH runs into this)
; USES:   Flags, AX
; -----------------------------------------------------------------------------

        public  HeadUmb

HeadUmb proc    near
; VCB - DS and SI aren't changed so don't save and restore them
;       pushreg <si, ds, es>

        pushreg <es>

        mov     ah, DOS_GET_LISTS       ; Call int 21h, function 52h...
        int     21h

        mov     ax, es:[UMB_HeadIdx]    ; And read what's in ES:008C
        cmp     ax, 0FFFFh
        jz      xhu_e                   ; If it's 0xFFFF, it's an error...

        clc                             ; Else, it isn't.
        jmp short xhu_x

xhu_e:  stc

; VCB - DS and SI aren't changed so don't save and restore them
;hu_x:  popreg  <es, ds, si>

xhu_x:  popreg  <es>
        ret
HeadUmb endp

; -----------------------------------------------------------------------------
;*** linkumb - links UMBs not already linked in; updates fm_umb as needed
; -----------------------------------------------------------------------------
; ENTRY:    None
; EXIT:     fm_umb == 0 if not linked in previously, 1 if already linked in
; ERROR:    None
; USES:     AX, BX, fm_umb
; -----------------------------------------------------------------------------

linkumb proc    near
        mov     ax, DOS_UMBLINK_GET
        int     21h                     ; Current link-state is now in al

        or      al, al                  ; BUGBUG: proper check?
        jnz     lumbX                   ; Jumps if UMBs already linked in

        mov     ax, DOS_UMBLINK_SET
        mov     bx, 1
        int     21h

lumbX:
        ret
linkumb endp

