PAGE 58,132
;******************************************************************************
TITLE LoadHi -- Support for Load Hi under Windows 3.0x
;******************************************************************************
;
;   (C) Copyright MICROSOFT Corp., 1990-1991
;
;   Title:      LoadHi -- Support for Load Hi under Windows 3.0x
;
;   Version:    1.00
;
;   Date:       20-Jul-1990
;
;   Author:     AC
;
;------------------------------------------------------------------------------
;
;   Change log:
;
;      DATE     REV                 DESCRIPTION
;   ----------- --- -----------------------------------------------------------
;    08-27-1990 AC  Hooked "Allocate_Global_V86_Data_Area" call to fix WIN3.0 bug
;    10-01-1990 ARR added some V86MMGR bug fix work around code.
;    10-03-1990 ARR Remove _Allocate_Global_V86_Data_Area work around (due to
;                     errata 10 handling). This work around is now sole job
;                     of LA20HMA device
;    02-20-1991 AC  Will not load if duplicate or not from INT 2F chain.
;
;==============================================================================
;
;   DESCRIPTION:
;
;******************************************************************************

        .386p


;******************************************************************************
;                             I N C L U D E S
;******************************************************************************



        .XLIST
        INCLUDE VMM.Inc
        INCLUDE DOSMGR.Inc
        INCLUDE Debug.Inc
        INCLUDE Instance.Inc
        INCLUDE v86mmgr.Inc
        .LIST

        Create_VDD2_Service_Table EQU TRUE
        INCLUDE .\VDD2.Inc
        LoadHi_Service_Table EQU VDD2_Service_Table
        Num_LoadHi_Services EQU Num_VDD2_Services

;******************************************************************************
;                V I R T U A L   D E V I C E   D E C L A R A T I O N
;******************************************************************************


Declare_Virtual_Device LoadHi, 1, 0, LoadHi_Control, VDD2_Device_ID, VMM_Init_Order

;******************************************************************************
;                                E Q U A T E S
;******************************************************************************

MONO_DISP_LO    equ     0B0H            ;start page in mono display area
MONO_DISP_HI    equ     0B7H            ;end page in mono display area

;******************************************************************************
;                            S T R U C T U R E S
;******************************************************************************

LimInstanceData STRUC
LimInstanceDataPtr      dd      ?       ;pointer to instance data start
LimInstanceDataSize     dw      ?       ;size in bytes
LimInstanceData ENDS

;******************************************************************************
;                          F L A G   E Q U A T E S
;******************************************************************************


;******************************************************************************
;                  I N I T I A L I Z A T I O N   D A T A
;******************************************************************************

VxD_IDATA_SEG

;;;;Real_AGVDA_Addr         dd      ?       ;original Allocate_Global_V86_Data_Area

; define a copyright string

MS_CopyRight            db      'Copyright (C) IBM Corp., 1993',0    ;*N001*
LoadHi_Device_Name      db      'LoadHi',0,0
CrashMsg                db      'LoadHi:Sys_Critical_Init Fails',0


; define strings for 'LOCAL=' and 'GLOBAL=' section names in [386Enhanced]
; section of SYSTEM.INI.

LH_DevNameBuf           db      8 dup (?);for storing device name
LH_Local_String         db      'LOCAL',0
LH_Global_String        db      'GLOBAL',0

Prev_GPS_Pointer        dd      ?       ; previous GetProfileString pointer

VxD_IDATA_ENDS


;******************************************************************************
;             R E A L   M O D E   I N I T I A L I Z A T I O N
;******************************************************************************

VxD_REAL_INIT_SEG

        Extrn   Real_Mode_Hook:near

;******************************************************************************
;
;   LoadHi_Real_Mode_Init
;
;   DESCRIPTION:
;
;       The VxD will not load if this is a duplicate load or if it is not
;       being loaded from the INT 2F chain.
;
;       This VxD should only be loaded for version 3.0 of Windows/386.
;       The real mode initialization portion of this device will abort its
;       load if the VMM version is less than version 3.10 (hex 30A)
;
;       If our test succeedes, we need to call a Limulator specific routine
;       to do test for them and this routine would setup registers such that
;       we could do a return to VMM directly. Look at the default code in
;       UMB.ASM
;
;   ENTRY:
;       CS, DS = Real mode segment
;       AX = VMM version (AH=Major, AL=Minor)
;       BX = Flags
;
;   EXIT:
;       BX = Null pointer (no pages to exclude)
;       SI = Null pointer (no instance data)
;       EDX = Reference data to pass to protected mode portion of VxD
;
;   USES:
;       AX, BX, DX, SI, Flags
;
;==============================================================================

BeginProc LoadHi_Real_Mode_Init

; check for duplicate device load.

        test    bx, Duplicate_From_INT2F OR Duplicate_Device_ID
        jnz     SHORT LH_RMI_Fail_Load

; this is not a duplicate load, but was the device loaded from INT 2F chain ?

        test    bx,Loading_From_INT2F
        jnz     SHORT LH_RMI_Loading_Ok         ;loading type is OK.

LH_RMI_Fail_Load:

; fail this device load without any error message.

        xor     bx,bx                           ;no pages to exclude
        xor     si,si                           ;no instance data
        mov     ax, Abort_Device_Load + No_Fail_Message
        jmp     SHORT LH_RMI_Exit

LH_RMI_Loading_Ok:

;
;   Make sure that we're running on Windows/386 version 3.10 or later.
;   If not, abort the load of this device with a warning message.
;

        cmp     ax, 30Ah                        ; Q: Is this version < 3.10?
        jae     SHORT LH_RMI_Abort_Load         ;    N: Don't load me
                                                ;    Y: Return success flags

; call Lim specific routines and return with whatever registers they setup

        call    Real_Mode_Hook                  ;Lim specific real mode hook

        ret

LH_RMI_Abort_Load:

        mov     ax, Abort_Device_Load

LH_RMI_Exit:

        ret

EndProc LoadHi_Real_Mode_Init
VxD_REAL_INIT_ENDS
;******************************************************************************
;                           L O C A L   D A T A
;******************************************************************************

VxD_DATA_SEG

                        public FirstUMBPage
                        public NumUMBPages
                        public CB_LoadHi_Inst_Hand
                        public CB_LoadHi_Inst_Buf_ptr
                        public GlobalDeviceList
                        public InstanceDataList

FirstUMBPage            dd      ?       ;first UMB page number
NumUMBPages             dd      ?       ;number of pages that we have to deal with
CB_LoadHi_Inst_Buf_ptr  dd      ?       ;Int buf ptr offset in CB
CB_LoadHi_Inst_Hand     dd      ?       ;Int buf handle offset in CB
DeviceHeaderStartPtr    dd      ?       ;start of device header chain
GlobalDeviceList        dd      ?       ;list handle for GLOBAL= List
InstanceDataList        dd      ?       ;list handle for inst data for devices
MonoDispAreaHasUMB      dd      0       ;UMB in mono display area or not.
LoadHiDeviceActive      dd      -1      ;we are active by default

        ;------------------------------------------------;
        ; save chain addresses for the hooked functions. ;
        ;------------------------------------------------;

                        public ActualAddInstanceItem
                        public ActualTGV86Mem
                        public ActualDOSMGRInstanceDev

ActualAddInstanceItem   dd      ?       ;original _AddInstanceItem service
ActualTGV86Mem          dd      ?       ;original _TestGlobalV86Mem
ActualDOSMGRInstanceDev dd      ?       ;original DOSMGR_InstanceDevice

LoadHi_OwnCall          dd      0       ;INT 21H hook flag
UMBLinkState            dd      ?       ;original state of UMB links

V86_CB_Offset_Addr      dd      0       ;Addr of Control block offset for V86MMGR
EMM_Patch_Ret_Addr      dd      0
EMM_Patch_NotPartial_Addr dd    0
V86_ImprtPtr_Addr       dd      0       ;Addr of variable for V86MMGR
EMM_Patch_Ret_Addr2     dd      0
EMM_Patch_Ret_Addr2a    dd      0

        ;------------------------------------------------;

VxD_DATA_ENDS



;******************************************************************************
;              D E V I C E   C O N T R O L   P R O C E D U R E
;******************************************************************************

VxD_CODE_SEG

        Extrn   LoadHi_Instance_Create_VM:near
        Extrn   LoadHi_Instance_Destroy_VM:near
        Extrn   LoadHi_Instance_Suspend_VM:near
        Extrn   LoadHi_Instance_Resume_VM:near
        Extrn   LoadHi_InstanceInitComplete:near
IFDEF   DEBUG
        Extrn   LoadHi_Debug_Query:near
ENDIF
        Extrn   LoadHi_Take_Instance_SnapShot:near
        Extrn   Swap_LoadHi_Instance_Page:near
        Extrn   Get_Mapped_Page_Num:near
        Extrn   Control_Call_Hook:near

;******************************************************************************
;
;   LoadHi_Control
;
;   DESCRIPTION:
;
;   ENTRY:
;       EAX = Control call ID
;
;   EXIT:
;       If carry clear then
;           Successful
;       else
;           Control call failed
;
;   USES:
;       EAX, EBX, ECX, EDX, ESI, EDI, Flags
;
;==============================================================================

BeginProc LoadHi_Control,PUBLIC

; call 'Control_Call_Hook' so that LIMulators can hook any of the control
; calls that they want to do additional processing on.

        pushad
        call    Control_Call_Hook
        popad
        jc      SHORT LoadHi_Control_Ret;LIMulator failed the call

; if our part of the device is turned off because we are running on a newer
; version of windows, we should not call our hooks.

        cmp     LoadHiDeviceActive,0    ;is it active ?
        jz      SHORT LoadHi_Control_Ret;no, carry is clear, return

; trap the control calls that we want to hook our selves.

        Control_Dispatch Sys_Critical_Init, LoadHi_Sys_Critical_Init
        Control_Dispatch Device_Init, LoadHi_Device_Init
        Control_Dispatch Create_VM, LoadHi_Instance_Create_VM
        Control_Dispatch Destroy_VM, LoadHi_Instance_Destroy_VM
        Control_Dispatch Init_Complete, LoadHi_InstanceInitComplete
        Control_Dispatch VM_Suspend, LoadHi_Instance_Suspend_VM
        Control_Dispatch VM_Resume, LoadHi_Instance_Resume_VM
        Control_Dispatch Sys_VM_Init, LoadHi_Sys_VM_Init
        Control_Dispatch System_Exit, <LoadHi_SystemExit>


IFDEF   DEBUG
        Control_Dispatch Debug_Query, LoadHi_Debug_Query
ENDIF   ;DEBUG

        clc                                     ; Ignore other control calls

LoadHi_Control_Ret:

        ret

EndProc LoadHi_Control

;----------------------------------------------------------------------------;
; LoadHi_Map_Pages:                                                          ;
;                                                                            ;
; This routine maps in the UMB pages into the VM's address space.            ;
;----------------------------------------------------------------------------;

BeginProc LoadHi_Map_Pages,PUBLIC

        mov     eax,[FirstUMBPage]      ;first page in the array
        mov     ecx,[NumUMBPages]       ;number of pages to map in.

MapPagesLoop:

        call    Get_Mapped_Page_Num     ;edx has the mapped page no.
        or      edx,edx                 ;is it an UMB ?
        jz      SHORT MapPagesCont      ;no.
        push    ecx
        push    eax
        VMMcall _PhysIntoV86, <edx,ebx,eax,1,0>
        pop     eax
        pop     ecx

IFDEF   DEBUG
        or      eax,eax                 ;was the mapping successful ?
        jnz     SHORT @f                ;yes.
        debug_out "LoadHi:PhysIntoV86 fails to map phys page number #EDX into page number #EAX"
@@:
ENDIF   ;DEBUG


MapPagesCont:

        inc     eax                     ;next V86 page
        loop    SHORT MapPagesLoop      ;continue

        ret

EndProc LoadHi_Map_Pages
;----------------------------------------------------------------------------;
VxD_CODE_ENDS


;******************************************************************************
;                   I N I T I A L I Z A T I O N   C O D E
;******************************************************************************

VxD_ICODE_SEG

        Extrn   LoadHi_Add_Instance_Item:near
        Extrn   Get_UMB_Info:near
        Extrn   Get_Device_Info:near
        Extrn   Get_Ptr_To_Instance_Data_List:near

;----------------------------------------------------------------------------;
; LoadHi_Sys_Critical_Init:                                                  ;
;                                                                            ;
; Entry:                                                                     ;
;        EDX  - 32 bit linear address of a table which has the UMB Page to   ;
;               physical page mapping information.                           ;
;                                                                            ;
;        EBX  - VM handle                                                    ;
;        EBP  - Client register frame for VM                                 ;
;                                                                            ;
; Action:                                                                    ;
;        . Saves the address of the mapping table for later use.             ;
;        . Allocate space in Control Block for a couble of DWORDS to keep    ;
;          track of each VM's instance data.                                 ;
;        . Hooks relevant VMM and DOSMGR services that this device must      ;
;          monitor.                                                          ;
;                                                                            ;
; Exit:                                                                      ;
;                                                                            ;
; Uses:                                                                      ;
;----------------------------------------------------------------------------;
BeginProc LoadHi_Sys_Critical_Init,PUBLIC

    ;
    ; Implement the work arounds for some bugs in the 3.00 V86MMGR device.
    ;
        pushad
        xor     eax,eax

        VxDCall V86MMGR_Get_Version

; if the version is above or equal 3.0A, the LoadHi device should be turned
; off.

        cmp     eax,030Ah                       ;Q: Is this version < 3.0A
        jb      SHORT LH_SCI_OK                 ;it is OK

; turn ourselves off.

        mov     LoadHiDeviceActive,0            ;inactive

LH_SCI_OK:

        cmp     eax,0300h
        jne     LH_NoFix

    ;
    ; This first fix fixes the problem with the marking of ROM pages in the
    ;   V86MMGR memory scan code
    ;
        mov     eax, V86MMGR_Set_Mapping_Info
        mov     esi, 0FFFFFFFFh

        VMMcall Hook_Device_Service

IFDEF DEBUG
        jnc     short LHD05
        debug_out "Couldn't patch V86MMGR 1"
LHD05:
ENDIF
        jc      LHSCI_Fail
        push    esi
        mov     eax, V86MMGR_Set_Mapping_Info

        VMMcall Hook_Device_Service

        pop     esi
IFDEF DEBUG
        jnc     short LHD05a
        debug_out "Couldn't patch V86MMGR 1a"
LHD05a:
ENDIF
        jc      LHSCI_Fail
        mov     eax,0EDFh
        cmp     dword ptr [esi.eax],0107C766h
        jne     short TryDebug
        cmp     byte ptr [esi.eax+4],04h
        je      short GotPatchLoc

TryDebug:
        mov     eax,14DCh
        cmp     dword ptr [esi.eax],0107C766h
IFDEF DEBUG
        je      short LHD10
        debug_out "Did not find patch instruction 1 LH_Sys_Critical_Init"
LHD10:
ENDIF
        jne     short LH_SecondFix
        cmp     byte ptr [esi.eax+4],04h
IFDEF DEBUG
        je      short LHD20
        debug_out "Did not find patch instruction 2 LH_Sys_Critical_Init"
LHD20:
ENDIF
        jne     short LH_SecondFix
GotPatchLoc:
        lea     edx,[esi.eax+5]                 ; EIP after patched instruction
        mov     ecx,offset32 LH_V86_Fix_Proc    ; Patch Target
        sub     ecx,edx
        mov     byte ptr [esi.eax],0E8h         ; Near call
        mov     dword ptr [esi.eax+1],ecx
    ;
    ; This fix is for some problems in the EMM code.
    ;
LH_SecondFix:
        mov     eax, V86MMGR_Get_EMS_XMS_Limits
        mov     esi, 0FFFFFFFFh

        VMMcall Hook_Device_Service

IFDEF DEBUG
        jnc     short LHD30
        debug_out "Couldn't patch V86MMGR 2"
LHD30:
ENDIF
        jc      LHSCI_Fail
        push    esi
        mov     eax, V86MMGR_Get_EMS_XMS_Limits

        VMMcall Hook_Device_Service

        pop     esi
IFDEF DEBUG
        jnc     short LHD30a
        debug_out "Couldn't patch V86MMGR 2a"
LHD30a:
ENDIF
        jc      LHSCI_Fail
        mov     eax,27E6h
        cmp     dword ptr [esi.eax],75014338h
        jne     short TryDebug2
        cmp     byte ptr [esi.eax+4],48h
        je      short GotPatchLoc2
TryDebug2:
        mov     eax,3F24h
        cmp     dword ptr [esi.eax],75014338h
IFDEF DEBUG
        je      short LHD40
        debug_out "Did not find patch instruction 3 LH_Sys_Critical_Init"
LHD40:
ENDIF
        jne     short LH_ThirdFix
        cmp     byte ptr [esi.eax+4],48h
IFDEF DEBUG
        je      short LHD50
        debug_out "Did not find patch instruction 4 LH_Sys_Critical_Init"
LHD50:
ENDIF
        jne     short LH_ThirdFix
GotPatchLoc2:
        mov     word ptr [esi.eax+3],9090h      ; NOP jne instruction
LH_ThirdFix:
    ;
    ; ESI still -> V86MMGR_Get_EMS_XMS_Limits address
    ;
        mov     eax,1B86h
        cmp     word ptr [esi.eax],358Bh
        jne     TryDebug3
        cmp     dword ptr [esi.eax+6],1D45B60Fh
        jne     TryDebug3
        mov     edx,dword ptr [esi.eax+2]
        mov     [V86_CB_Offset_Addr],edx
        mov     eax,26E9h
        cmp     dword ptr [esi.eax],7E800788h
IFDEF DEBUG
        je      short LHD55
        debug_out "Did not find patch instruction 5 LH_Sys_Critical_Init"
LHD55:
ENDIF
        jne     LH_NoFix
        cmp     word ptr [esi.eax+4],0401h
IFDEF DEBUG
        je      short LHD60
        debug_out "Did not find patch instruction 6 LH_Sys_Critical_Init"
LHD60:
ENDIF
        jne     LH_NoFix
        cmp     byte ptr [esi.eax+6],74h
IFDEF DEBUG
        je      short LHD70
        debug_out "Did not find patch instruction 7 LH_Sys_Critical_Init"
LHD70:
ENDIF
        jne     LH_NoFix
        jmp     GotPatchLoc3

TryDebug3:
        mov     eax,2974h
        cmp     word ptr [esi.eax],358Bh
IFDEF DEBUG
        je      short LHD90
        debug_out "Did not find patch instruction 8 LH_Sys_Critical_Init"
LHD90:
ENDIF
        jne     LH_FourthFix
        cmp     dword ptr [esi.eax+6],1D45B60Fh
IFDEF DEBUG
        je      short LHD100
        debug_out "Did not find patch instruction 9 LH_Sys_Critical_Init"
LHD100:
ENDIF
        jne     LH_FourthFix
        mov     edx,dword ptr [esi.eax+2]
        mov     [V86_CB_Offset_Addr],edx
        mov     eax,3DC0h
        cmp     dword ptr [esi.eax],7E800788h
IFDEF DEBUG
        je      short LHD110
        debug_out "Did not find patch instruction 10 LH_Sys_Critical_Init"
LHD110:
ENDIF
        jne     short LH_FourthFix
        cmp     word ptr [esi.eax+4],0401h
IFDEF DEBUG
        je      short LHD120
        debug_out "Did not find patch instruction 11 LH_Sys_Critical_Init"
LHD120:
ENDIF
        jne     short LH_FourthFix
        cmp     byte ptr [esi.eax+6],74h
IFDEF DEBUG
        je      short LHD130
        debug_out "Did not find patch instruction 12 LH_Sys_Critical_Init"
LHD130:
ENDIF
        jne     short LH_FourthFix
GotPatchLoc3:
        lea     edx,[esi.eax+8]                 ; EIP after modified instructions
        mov     [EMM_Patch_Ret_Addr],edx
        movzx   ecx,byte ptr [esi.eax+7]        ; Target of trailing JE
        add     ecx,edx
        mov     [EMM_Patch_NotPartial_Addr],ecx
        lea     edx,[esi.eax+2+5]               ; EIP after instruction we insert
        mov     ecx,offset32 LH_V86_EMM_Fix_Proc; Patch Target
        sub     ecx,edx
        mov     byte ptr [esi.eax+2],0E9h       ; Near unconditional jump
        mov     dword ptr [esi.eax+2+1],ecx
        mov     byte ptr [esi.eax+2+1+4],90h    ; NOP left over byte
LH_FourthFix:
    ;
    ; ESI still -> V86MMGR_Get_EMS_XMS_Limits address
    ;
        mov     eax,16BEh
        cmp     word ptr [esi.eax], 3D8Bh
        jne     TryDebug4
        cmp     dword ptr [esi.eax+6], 510A7F8Dh
        jne     TryDebug4
        mov     ecx,dword ptr [esi.eax+2]
        mov     [V86_ImprtPtr_Addr],ecx
        cmp     dword ptr [esi.eax+2Eh], 6602E8C1h
        jne     TryDebug4
        cmp     dword ptr [esi.eax+2Eh+4], 59024189h
        jne     short TryDebug4
DoP4Retail:
        lea     edx,[esi.eax+5]                 ; Jump back address
        mov     [EMM_Patch_Ret_Addr2],edx
        inc     [EMM_Patch_Ret_Addr2]           ; Skip trailing NOP
        mov     ecx,offset32 LH_V86_EMM_Fix_Proc2 ; Patch Target
        sub     ecx,edx
        mov     byte ptr [esi.eax],0E9h         ; Near unconditional jump
        mov     dword ptr [esi.eax+1],ecx
        mov     byte ptr [esi.eax+5],90h        ; NOP left over byte

        lea     edx,[esi.eax+2Eh+3+5]           ; Jump back address
        mov     [EMM_Patch_Ret_Addr2a],edx
        mov     ecx,offset32 LH_V86_EMM_Fix_Proc2a ; Patch Target
        sub     ecx,edx
        mov     byte ptr [esi.eax+2Eh+3],0E9h   ; Near unconditional jump
        mov     dword ptr [esi.eax+2Eh+3+1],ecx

        mov     eax,16E3h
        cmp     dword ptr [esi.eax], 4188028Ah
        jne     TryDebug4a
        cmp     byte ptr [esi.eax+4], 01h
        jne     TryDebug4a
        cmp     dword ptr [esi.eax+5], 0442B70Fh
        jne     TryDebug4a
DoP4aRetail:
        mov     byte ptr [esi.eax+1], 06h       ; change EDX to ESI
        mov     byte ptr [esi.eax+7], 46h       ; change EDX to ESI
        jmp     LH_NoFix

TryDebug4:
        mov     eax,23C9h
        cmp     word ptr [esi.eax], 3D8Bh
IFDEF DEBUG
        je      short LHD140
        debug_out "Did not find patch instruction 9 LH_Sys_Critical_Init"
LHD140:
ENDIF
        jne     TryDebug4a
        cmp     dword ptr [esi.eax+6], 510A7F8Dh
IFDEF DEBUG
        je      short LHD150
        debug_out "Did not find patch instruction 10 LH_Sys_Critical_Init"
LHD150:
ENDIF
        jne     TryDebug4a
        mov     ecx,dword ptr [esi.eax+2]
        mov     [V86_ImprtPtr_Addr],ecx
        cmp     dword ptr [esi.eax+95h], 6602E8C1h
IFDEF DEBUG
        je      short LHD160
        debug_out "Did not find patch instruction 11 LH_Sys_Critical_Init"
LHD160:
ENDIF
        jne     short TryDebug4a
        cmp     dword ptr [esi.eax+95h+4], 59024189h
IFDEF DEBUG
        je      short LHD170
        debug_out "Did not find patch instruction 12 LH_Sys_Critical_Init"
LHD170:
ENDIF
        jne     short TryDebug4a
DoP4Debug:
        lea     edx,[esi.eax+5]                 ; Jump back address
        mov     [EMM_Patch_Ret_Addr2],edx
        inc     [EMM_Patch_Ret_Addr2]           ; Skip trailing NOP
        mov     ecx,offset32 LH_V86_EMM_Fix_Proc2 ; Patch Target
        sub     ecx,edx
        mov     byte ptr [esi.eax],0E9h         ; Near unconditional jump
        mov     dword ptr [esi.eax+1],ecx
        mov     byte ptr [esi.eax+5],90h        ; NOP left over byte

        lea     edx,[esi.eax+95h+3+5]           ; Jump back address
        mov     [EMM_Patch_Ret_Addr2a],edx
        mov     ecx,offset32 LH_V86_EMM_Fix_Proc2a ; Patch Target
        sub     ecx,edx
        mov     byte ptr [esi.eax+95h+3],0E9h   ; Near unconditional jump
        mov     dword ptr [esi.eax+95h+3+1],ecx
TryDebug4a:
        mov     eax,2414h
        cmp     dword ptr [esi.eax], 4188028Ah
IFDEF DEBUG
        je      short LHD180
        debug_out "Did not find patch instruction 13 LH_Sys_Critical_Init"
LHD180:
ENDIF
        jne     short LH_NoFix
        cmp     dword ptr [esi.eax+4], 01428A01h
IFDEF DEBUG
        je      short LHD190
        debug_out "Did not find patch instruction 14 LH_Sys_Critical_Init"
LHD190:
ENDIF
        jne     short LH_NoFix
        cmp     dword ptr [esi.eax+27h], 0442B70Fh
IFDEF DEBUG
        je      short LHD200
        debug_out "Did not find patch instruction 15 LH_Sys_Critical_Init"
LHD200:
ENDIF
        jne     short LH_NoFix
DoP4aDebug:
        mov     byte ptr [esi.eax+1], 06h       ; change EDX to ESI
        mov     byte ptr [esi.eax+6], 46h       ; change EDX to ESI
        mov     byte ptr [esi.eax+27h+2], 46h   ; change EDX to ESI
LH_NoFix:
        popad

; if we are inactive (newer version of windows) we should proceed further
; with the call.

        cmp     LoadHiDeviceActive,0            ;are we active ?
        jz      LH_SCI_Ret                      ;no.

; get information about the first UMB page and the number of pages that we
; could expect UMBs to be in starting with the first page. EDX has a pointer
; to a structure that has this information and the following routine can
; interpret it.




; EDX was the linear address in EMM386's environment. We need to get the
; coressponding linear address in WIN386's space. We can't touch the block
; to figure out how big it is, for now we are going to go with the max size
; of the block, which is 4 + 4 + (100 - A0)* 4 = 392.



        VMMcall _MapPhysToLinear,<edx, 400, 0>
        mov     edx,eax                         ;get it back into edx.


        call    Get_UMB_Info
        mov     FirstUMBPage,eax        ;save the first UMB page number
        mov     NumUMBPages,edx         ;number of pages containing UMBs

; check to see whether the start page is above the minimum that we can work with.

        cmp     eax,MIN_LOADHI_INST_PAGE
        jae     SHORT @f                ;it is OK

IFDEF   DEBUG
        debug_out "LoadHi: First UMB page is #EAX, this is unacceptable"
ENDIF   ;DEBUG

        jmp     LHSCI_Fail              ;fail the call
@@:

; create LIST handles for the lists that we will need for handling memory
; needed for instancing devices and for maintaining the list of GLOBAL=
; devices.

        mov     eax,LF_Use_Heap
        mov     ecx,8                   ;for device names
        VMMcall List_Create
        mov     GlobalDeviceList,esi    ;for global= device list

        mov     eax,LF_Use_Heap
        mov     ecx,SIZE InstDataStruc  ;size of 'AddInstanceItem' datastruct
        VMMcall List_Create
        mov     InstanceDataList,esi    ;for instancing devices


; allocate space worth 2 DWORDs in the Control Block and save the two offsets

        VMMcall _Allocate_Device_CB_Area,<8,0>
        or      eax,eax                 ;did call fail ?

IFDEF   DEBUG
        jnz     SHORT @f                ;no.
        debug_out "LoadHi: Allocate_Device_CB_Area fails to allocate 8 bytes"
        jmp     LHSCI_Fail              ;fail the call
@@:
ELSE
        jz      LHSCI_Fail              ;yes, fail this call
ENDIF   ;DEBUG

        mov     CB_LoadHi_Inst_Buf_Ptr,eax
        add     eax,4                   ;next dword offset
        mov     CB_LoadHi_Inst_Hand,eax

; hook some of the services. Start with the _AddInstanceItem service.

        mov     eax,_AddInstanceItem
        mov     esi,OFFSET32 LoadHi_Add_Instance_Item
        VMMcall Hook_Device_Service

IFDEF   DEBUG
        jnc     SHORT @f                ;successful
        debug_out "LoadHi: Hook_Device_Service fails to hook AddInstanceItem"
        jmp     LHSCI_Fail              ;fail the call
@@:
ELSE
        jc      LHSCI_Fail              ;fail the call
ENDIF   ;DEBUG

        mov     [ActualAddInstanceItem],esi

; next hook the TestGlobalV86Mem service.

        mov     eax,_TestGlobalV86Mem
        mov     esi,OFFSET32 LoadHi_TestGlobalV86Mem
        VMMcall Hook_Device_Service

IFDEF   DEBUG
        jnc     SHORT @f                ;successful
        debug_out "LoadHi: Hook_Device_Service fails to hook TestGlobalV86Mem"
        jmp     LHSCI_Fail              ;fail the call
@@:
ELSE
        jc      LHSCI_Fail      ;fail the call
ENDIF   ;DEBUG

        mov     [ActualTGV86Mem],esi

; hook the DOSMGR_Instance_Device service

        mov     eax,DOSMGR_Instance_Device
        mov     esi,OFFSET32 LoadHi_Instance_Device
        VMMcall Hook_Device_Service

IFDEF   DEBUG
        jnc     SHORT @f                ;successful
        debug_out "LoadHi: Hook_Device_Service fails to hook DOSMGR_Instance_Device"
        jmp     LHSCI_Fail              ;fail the call
@@:
ELSE
        jc      DEBFAR LHSCI_Fail       ;fail the call
ENDIF   ;DEBUG

        mov     [ActualDOSMGRInstanceDev],esi

;;;;; hook the Allocate_Global_V86_Data_Area service
;;;;
;;;;        mov     eax,_Allocate_Global_V86_Data_Area
;;;;        mov     esi,OFFSET32 LoadHi_AGVDA_Hook
;;;;        VMMcall Hook_Device_Service
;;;;
;;;;IFDEF   DEBUG
;;;;        jnc     SHORT @f                ;successful
;;;;        debug_out "LoadHi: Hook_Device_Service fails to hook Allocate_Global_V86_Data_Area"
;;;;        jmp     LHSCI_Fail              ;fail the call
;;;;@@:
;;;;ELSE
;;;;        jc      DEBFAR LHSCI_Fail       ;fail the call
;;;;ENDIF   ;DEBUG
;;;;
;;;;        mov     [Real_AGVDA_Addr],esi

; assign the UMB pages & hook them.

        mov     eax,[FirstUMBPage]      ;start UMB page.
        mov     ecx,[NumUMBPages]       ;no of entries in the table

AssignPagesLoop:

; get the mapping page number.

        call    Get_Mapped_Page_Num     ;edx returns the mapped page number
        or      edx,edx                 ;is it a UMB page ?
        jz      SHORT AssignPagesCont   ;no.

; if the page is in the range for a monochrome adapter, set a flag.

        call    ProcessPageInMonoDispArea

        push    ecx                     ;save loop count
        push    eax                     ;save current page number
        VMMcall _Assign_Device_V86_Pages, <eax,1,0,0>
        or      eax,eax                 ;did the call fail ?
        pop     eax                     ;get back page number
        jnz     SHORT @f                ;successful
        pop     ecx                     ;balance the stack

IFDEF   DEBUG
        debug_out "LoadHi: Assign_Device_V86_Pages fails on page number #EAX"
ENDIF   ;DEBUG
        jmp     SHORT LHSCI_Fail        ;fail the call
@@:

; hook the page for monitoring page fault.

        push    eax                     ;save the current page number
        mov     esi,OFFSET32 Swap_LoadHi_Instance_Page
        VMMcall Hook_V86_Page
        pop     eax
        pop     ecx

IFDEF   DEBUG
        jnc     SHORT @f                ;call was successful
        debug_out "LoadHi: Hook_V86_Page fails on page number #EAX"
        jmp     SHORT LHSCI_Fail        ;fail the call
@@:
ELSE
        jc      DEBFAR LHSCI_Fail       ;fail the call
ENDIF   ;DEBUG

AssignPagesCont:

        inc     eax                     ;next V86 page number
        loop    AssignPagesLoop         ;go through the table.

AssignPagesDone:

; map the pages in for the SYSTEM VM

        VMMcall Get_Sys_VM_Handle       ;EBX = Sys_VM_Handle
        call    LoadHi_Map_Pages        ;map pages in for SYS_VM

; we are done.

LH_SCI_Ret:

        clc
        ret

LHSCI_Fail:

        Fatal_Error <OFFSET32 CrashMsg>

EndProc LoadHi_Sys_Critical_Init
;----------------------------------------------------------------------------;
; ProcessPageInMonoDispArea:                                                 ;
;                                                                            ;
; ENTRY:                                                                     ;
;       EAX  - V86 page number (0A0H - 10FH)                                 ;
;       EDX  - Mapped page (0 if EAX is not a UMB page)                      ;
;                                                                            ;
; ACTION:                                                                    ;
;       Sets MonoDispAreaHasUMB to -1 if EAX is within the mono display      ;
;       area page range and EDX is not 0.                                    ;
;                                                                            ;
; EXIT:                                                                      ;
;       None.                                                                ;
;                                                                            ;
; USES:                                                                      ;
;       Flags.                                                               ;
;----------------------------------------------------------------------------;
BeginProc ProcessPageInMonoDispArea,PUBLIC

        cmp     eax,MONO_DISP_LO        ;lower than mono display area ?
        jb      SHORT @f                ;yes
        cmp     eax,MONO_DISP_HI        ;higher than mono display area ?
        ja      SHORT @f                ;yes.
        cmp     edx,0                   ;is there an UMB in this page ?
        jz      SHORT @f                ;no.
        mov     MonoDispAreaHasUMB,-1   ;there is an UMB in the mono display area
@@:
        ret

EndProc ProcessPageInMonoDispArea
;----------------------------------------------------------------------------;
; LoadHi_Device_Init:                                                        ;
;                                                                            ;
;   DESCRIPTION:                                                             ;
;                                                                            ;
;       At first this routine get the current UMB state and saves it, it then;
;       unliks the UMB and sets its own INT 21 hook which will prevent the   ;
;       UMBs from being linked back in.                                      ;
;                                                                            ;
;       The routine then builds up a list of all 'GLOBAL=' devices that are  ;
;       specified in the [386Enhanced] section of system.ini.                ;
;                                                                            ;
;       It then scans [386Enhanced] section of SYSTEM.INI for 'LOCAL='       ;
;       devices and finds out whether they are LoadHi devices or not. If they;
;       are, then DOSMGR_Instance_Device is called. Ofcourse this call will  ;
;       be intercepted by the hook in this device and will not be chained on.;
;       This routine will do nothing for devices that are not loaded high.   ;
;                                                                            ;
;   ENTRY:                                                                   ;
;                                                                            ;
;   EXIT:                                                                    ;
;                                                                            ;
;   USES:                                                                    ;
;----------------------------------------------------------------------------;
BeginProc LoadHi_Device_Init,PUBLIC


; Get the UMB Link state, save it and turn the link state off.

        Push_Client_State
        VMMcall Begin_Nest_Exec         ;Get ready for software ints

; get the link state.

        mov     [ebp.Client_AX], 05802h ;get UMB link state
        mov     eax, 21h                ;INT 21H to be done
        VMMcall Exec_Int                ;do the INT
        movzx   eax,[ebp.Client_AX]     ;return is in AL
        mov     UMBLinkState,eax        ;save it

; reset the link state.

        mov     [ebp.Client_AX], 05803h ;set UMB link state
        mov     [ebp.Client_BX], 0      ;unlink them
        mov     eax, 21h                ;INT 21H to be done
        VMMcall Exec_Int                ;do the INT

; end the nested exec calls.

        VMMcall End_Nest_Exec
        Pop_Client_State

; now hook INT 21H in Ring0.

        mov     eax, 21h                ;want to hook INT 21H
        mov     esi, OFFSET32 Loadhi_Int21ISR
        VMMcall Hook_V86_Int_Chain      ;INT 21H hooked.

; Process the "GLOBAL=" SYSTEM.INI strings

        mov     edi,offset32 LH_Global_String
        xor     esi, esi                ;read [386ENH] section
        xor     edx,edx                 ;no default
        VMMCall Get_Profile_String      ;Get first occurance
        mov     Prev_GPS_Pointer,edx    ;save return value
        jc      short LHDI_GlobalDone   ;Not found
        jmp     short LHDI_DoGlobal

LHDI_NextGlobal:

; get the next occurrence of 'GLOBAL='

        xor     esi, esi                ;read [386ENH] section
        mov     edx,Prev_GPS_Pointer    ;get last pointer
        mov     edi,offset32 LH_Global_String
        VMMCall Get_Next_Profile_String ;Get next occurance
        mov     Prev_GPS_Pointer,edx    ;save return value
        jc      short LHDI_GlobalDone

LHDI_DoGlobal:

; allocate a new node for this.

        mov     esi,GlobalDeviceList    ;get the handle
        VMMcall List_Allocate           ;allocate a new node
        VMMcall List_Attach             ;attach node to the list
        mov     edi,eax                 ;get a pointer to the new node.

        mov     esi,edx                 ;get a pointer to the name
        mov     ecx,8                   ;Max length of device names
        cld

LHDI_CopyName:

; copy the device name over to the new node. Pad it with spaces if name is
; less than 8 characters.

        lodsb

LHDI_TestEnd:

        or      al,al
        jz      short LHDI_PadSpace
        stosb
        loop    SHORT LHDI_CopyName
        jmp     short LHDI_NextGlobal

LHDI_PadSpace:

        mov     al,20h                  ;space pad next of the name
        rep     stosb
        jmp     short LHDI_NextGlobal

LHDI_GlobalDone:

; Process the 'LOCAL=' devices. For each such device find out if the device
; is loaded high, if it is then instance it.


        mov     edi,offset32 LH_Local_String
        xor     esi, esi                ;search [386ENH] section
        xor     edx,edx                 ;no default
        VMMCall Get_Profile_String      ;Get first occurance
        mov     Prev_GPS_Pointer,edx    ;save return value
        jc      short LHDI_LocalDone    ;Not found
        jmp     short LHDI_DoLocal

LHDI_NextLocal:

        xor     esi, esi                ;read [386ENH] section
        mov     edx,Prev_GPS_Pointer    ;get last pointer
        mov     edi,offset32 LH_Local_String
        VMMCall Get_Next_Profile_String ; Get next occurance
        mov     Prev_GPS_Pointer,edx    ;save return value
        jc      short LHDI_LocalDone

LHDI_DoLocal:

; prepare a space padded copy of the name in a temporary buffer.

        mov     edi,offset32 LH_DevNameBuf
        mov     eax,20202020h
        mov     dword ptr [edi],eax
        mov     dword ptr [edi+4],eax
        mov     esi,edx
        mov     ecx,8                   ; Max length of device names

LHDI_CopyLocalName:

        cld
        lodsb
        or      al,al
        jz      short LHDI_TestDev
        stosb
        loop    LHDI_CopyLocalName

LHDI_TestDev:

        mov     esi,offset32 LH_DevNameBuf

; find out if this is in the Global Device List or not.

        call    LoadHi_IsDeviceGlobal
        jc      SHORT LHDI_NextLocal    ;yes, search for the next one.

; find out if the device is a LoadHi device.

        call    Get_Device_Info         ;is this a LoadHi device ?
        jc      SHORT LHDI_NextLocal    ;no, search for the next one.

; instance the device

        call    LoadHi_Instance_From_EDX_Size_EAX
        jmp     SHORT LHDI_NextLocal    ;carry on search

LHDI_LocalDone:

; obtain a pointer to the list of instance data that the LIMulator has obtained
; from WIN386.

        call    Get_Ptr_To_Instance_Data_List

; EDI has a pointer to an array of nodes. Each node in the array is of 6 bytes
; The first DWORD is a seg:off of data to instance (will be in UMB area) and
; the next WORD will be its size. The array is terminated by a DWORD of 0.
; Instance all of these areas.

LHDI_InatanceAdditionalLoop:

        cmp     [edi.LimInstanceDataPtr],0;end of array ?
        jz      SHORT LHDI_Ret          ;yes
        mov     edx,[edi.LimInstanceDataPtr]

; convert the DWORD from seg:off form to a linear address.

        mov     eax,edx                 ;save it
        and     edx,0ffff0000h          ;retain the segment
        shr     edx,12                  ;get it to start from bit 20.
        and     eax,0ffffh              ;just the offset
        add     edx,eax                 ;EDX - linear address
        movzx   eax,[edi.LimInstanceDataSize]

; Instance the area

        call    LoadHi_Instance_From_EDX_Size_EAX
        add     edi,SIZE LimInstanceData ;next node
        jmp     SHORT LHDI_InatanceAdditionalLoop

LHDI_Ret:

         clc
         ret

EndProc LoadHi_Device_Init
;----------------------------------------------------------------------------;
; LoadHi_Instance_Device:                                                    ;
;                                                                            ;
;   DESCRIPTION:                                                             ;
;       Instance the indicated INSTALLED DOS device driver only if it is     ;
;       loaded after higher than the start UMB page else pass it on to the   ;
;       original handler - DOSMGR_Instance_Device.                           ;
;       This service is only valid at Init_Complete device call time.        ;
;                                                                            ;
;   ENTRY:                                                                   ;
;       ESI -> 8 character device name string                                ;
;           THIS STRING MUST EXACTLY MATCH THE NAME AS IT WILL BE FOUND      ;
;           IN THE DEVICE HEADER IN LOW MEMORY!!!!!!!                        ;
;           No case conversion is performed (name in dev hdr is upper case)  ;
;           Length is 8 (name must be space padded as DOS device names are)  ;
;           NO ':'s!! There is no ':' in the name in the device header.      ;
;                                                                            ;
;   EXIT:                                                                    ;
;       Carry set if device could not be instanced                           ;
;           o No device with this name in device list                        ;
;           o User has overidden call with "GLOBAL=" in system.ini           ;
;           o The device does not have an arena associated with it.          ;
;       Carry clear                                                          ;
;           device instanced                                                 ;
;                                                                            ;
;   USES:                                                                    ;
;       FLAGS                                                                ;
;                                                                            ;
;   NOTES:                                                                   ;
;       This call applies only to INSTALLED character devices (device        ;
;           segment != 70h). It cannot instance devices that are in the DOS  ;
;           RAM BIOS because there is no way to deliniate their start and    ;
;           end addresses. It is the job of the DOS instancing to correctly  ;
;           instance things related to character devices in the DOS RAM BIOS.;
;                                                                            ;
;       This call instances the ENTIRE device. It cannot differentiate code  ;
;           and data.                                                        ;
;                                                                            ;
;       This service is available at Init_Complete time only.                ;
;           o Service cannot work until DOSMGR_Device_Init is complete.      ;
;           o Service is in ICODE segment so it becomes invalid after        ;
;               Init_Complete.                                               ;
;           o Calls to _AddInstanceItem are invalid after Init_Complete.     ;
;                                                                            ;
;       WARNING!! DO NOT USE THIS SERVICE TO INSTANCE DEVICES ADDED WITH THE ;
;           DOSMGR_Add_Device SERVICE!!!!! This will not work properly. If   ;
;           you need to instance one of these devices you must call          ;
;           _AddInstanceItem yourself on it, or use the GVDAInstance flag    ;
;           on your _Allocate_Global_V86_Data_Area call.                     ;
;                                                                            ;
;----------------------------------------------------------------------------;
BeginProc LoadHi_Instance_Device,PUBLIC


; find out if the device is in the global device list. If it is then we will
; not try to instance this device. We could actually end this call in this
; routine, but for the time being will chain it on to DOSMGR.

        call    LoadHi_IsDeviceGlobal   ;is it declared to be a global device?
        jc      SHORT LHID_Chain_On     ;yes, chain call on.

; find out if the device is loaded high and if so, get its address and length

        call    Get_Device_Info
        jc      SHORT LHID_Chain_On     ;don't know about this, chain call on.

; instance the device

        call    LoadHi_Instance_From_EDX_Size_EAX
        clc                             ;device has been instanced
        ret

LHID_Chain_On:

; chain this call to DOSMGR_Instance_Device and let it deal with it in what
; ever way it want's to.

        jmp     [ActualDOSMGRInstanceDev]

EndProc LoadHi_Instance_Device
;----------------------------------------------------------------------------;
; LoadHi_Instance_From_EDX_Size_EAX:                                         ;
;                                                                            ;
;   DESCRIPTION:                                                             ;
;       Instances a particular device whose starting address and location    ;
;       are passed in.                                                       ;
;                                                                            ;
;   ENTRY:                                                                   ;
;       EDX -  Start of the device.                                          ;
;       EAX -  Length of the device.                                         ;
;                                                                            ;
;   EXIT:                                                                    ;
;       NONE.                                                                ;
;                                                                            ;
;   USES:                                                                    ;
;       Flags.                                                               ;
;----------------------------------------------------------------------------;

BeginProc LoadHi_Instance_From_EDX_Size_EAX,PUBLIC

        pushad                          ;save all registers

; EDX has the start of the device and EAX has it's size.  Allocate an item for
; the add_instance_item call and fill in the information.

        mov     edi,eax                 ;size of device
        mov     esi,InstanceDataList    ;get the handle for the list
        VMMcall List_Allocate           ;get a new list
        VMMcall List_Attach             ;attach the list on

; fill in the information for this node

        mov     [eax.InstLinkF],0       ;initialize
        mov     [eax.InstLinkB],0       ;initialize
        mov     [eax.InstLinAddr],edx   ;save linear address of device
        mov     [eax.InstSize],edi      ;size in bytes of the device
        mov     [eax.InstType],ALWAYS_Field

; call service to instance the data.

        VMMcall _AddInstanceItem,<eax,0>
        popad                           ;restore all registers
        ret

EndProc LoadHi_Instance_From_EDX_Size_EAX
;----------------------------------------------------------------------------;
; LoadHi_IsDeviceGlobal:                                                     ;
;                                                                            ;
;   DESCRIPTION:                                                             ;
;       Finds out if a passed in device name is in the Global device list    ;
;       or not.                                                              ;
;                                                                            ;
;   ENTRY:                                                                   ;
;       ESI -  pointer to device name.                                       ;
;                                                                            ;
;   EXIT:                                                                    ;
;       CARRY SET: if match obtained in global list.                         ;
;       CARRY CLEAR: otherwise.                                              ;
;                                                                            ;
;   USES:                                                                    ;
;       EAX, Flags.                                                          ;
;----------------------------------------------------------------------------;
BeginProc LoadHi_IsDeviceGlobal,PUBLIC

        push    esi
        push    edi
        push    ecx
        mov     edi,esi                 ;get the name pointer

; get a pointer to the first node in the Global device list.

        mov     esi,GlobalDeviceList    ;get the list handle
        VMMcall List_Get_First          ;get a pointer to the first node.
        jz      SHORT LHIDG_No_Match    ;empty list, no match found

LHIDG_Match_Name:

        mov     esi,eax                 ;get a pointer to the node
        cld
        mov     ecx,8                   ;8 characters to match for
        repe    cmpsb                   ;do the names match ?
        jz      SHORT LHIDG_Match_Found ;match obtained

; get to the next node.

        mov     esi,GlobalDeviceList    ;get the list handle
        VMMcall List_Get_Next           ;get a pointer to the first node.
        jnz     SHORT LHIDG_Match_Name  ;continue to match

LHIDG_No_Match:

        clc                             ;not in global list
        jmp     SHORT LHIDG_Ret

LHIDG_Match_Found:

        stc                             ;device is in global list

LHIDG_Ret:

        pop     ecx
        pop     edi
        pop     esi                     ;restore thrashed registers
        ret

EndProc LoadHi_IsDeviceGlobal
;;;;;----------------------------------------------------------------------------;
;;;;;   LoadHi_AGVDA_Hook                                                        ;
;;;;;                                                                            ;
;;;;;   DESCRIPTION:                                                             ;
;;;;;       Hook to fix Allocate_Global_V86_Data_Area so that for page aligned   ;
;;;;;       reclaim allocations it will not return an address < 10000h.          ;
;;;;;                                                                            ;
;;;;;   ENTRY:                                                                   ;
;;;;;       As for Allocate_Global_V86_Data_Area                                 ;
;;;;;                                                                            ;
;;;;;   EXIT:                                                                    ;
;;;;;       As for Allocate_Global_V86_Data_Area                                 ;
;;;;;                                                                            ;
;;;;;   USES:                                                                    ;
;;;;;       'C' calling                                                          ;
;;;;;                                                                            ;
;;;;;----------------------------------------------------------------------------;
;;;;
;;;;BeginProc LoadHi_AGVDA_Hook
;;;;
;;;;        enter   0,0
;;;;
;;;;AGVDAnBytes   equ  dword ptr [ebp+8]            ; Number of bytes
;;;;AGVDAflags    equ  dword ptr [ebp+12]           ; Flags
;;;;
;;;;        push    esi
;;;;        push    edi
;;;;        push    ebx
;;;;
;;;;        VMMCall _GetFirstV86Page
;;;;
;;;;        cmp     eax,00000010h
;;;;        jae     short LoadHi_AGV_ChainThrough
;;;;        mov     esi,AGVDAflags
;;;;        test    esi,GVDAPageAlign
;;;;        jz      short LoadHi_AGV_ChainThrough
;;;;        test    esi,GVDAReclaim
;;;;        jz      short LoadHi_AGV_ChainThrough
;;;;        and     esi,NOT(GVDAReclaim)            ; Turn off reclaim
;;;;        mov     ecx,00000010h
;;;;        sub     ecx,eax                         ; Off by this many pages
;;;;        shl     ecx,12                          ; Pages to bytes
;;;;
;;;;        cCall   [Real_AGVDA_Addr],<ecx,esi>
;;;;
;;;;        jmp     short LoadHi_ChkRet
;;;;
;;;;LoadHi_AGV_Again:
;;;;
;;;;        cCall   [Real_AGVDA_Addr],<AGVDAnBytes,esi>
;;;;
;;;;LoadHi_ChkRet:
;;;;        or      eax,eax                         ; Error?
;;;;        jz      short LoadHi_AGV_Done           ; Yes, finished
;;;;        cmp     eax,00010000h
;;;;        jb      short LoadHi_AGV_Again
;;;;LoadHi_AGV_Done:
;;;;        pop     ebx
;;;;        pop     edi
;;;;        pop     esi
;;;;        leave
;;;;        ret
;;;;
;;;;LoadHi_AGV_ChainThrough:
;;;;        pop     ebx
;;;;        pop     edi
;;;;        pop     esi
;;;;        leave
;;;;        jmp     [Real_AGVDA_Addr]
;;;;
;;;;EndProc LoadHi_AGVDA_Hook

;******************************************************************************
;
;   LH_V86_Fix_Proc
;
;   DESCRIPTION:
;       Patch V86MMGR MEM_SCAN behavior
;
;   ENTRY:
;       None
;
;   EXIT:
;       None
;
;   USES:
;       None
;
;==============================================================================


BeginProc LH_V86_Fix_Proc

        test    word ptr [edi],0000001110100000b
        jnz     short SkipPg
        or      word ptr [edi],0000010000000001b
SkipPg:
        ret

EndProc LH_V86_Fix_Proc

;----------------------------------------------------------------------------;
VxD_ICODE_ENDS


VxD_CODE_SEG

;******************************************************************************
;
;   LH_V86_EMM_Fix_Proc
;
;   DESCRIPTION:
;       Hook to V86MMGR EMS driver.
;
;   ENTRY:
;       EBX is VM handle
;       THIS ROUTINE IS JUMPED TO NOT CALLED!!!!
;
;   EXIT:
;       None
;
;   USES:
;       None
;
;==============================================================================

BeginProc LH_V86_EMM_Fix_Proc

        push    ebx
        push    edi
        mov     edi,[V86_CB_Offset_Addr]
        add     ebx,dword ptr [edi]
        mov     ebx,dword ptr [ebx+50h]
        or      ebx,ebx
        jz      short NoBase
        test    byte ptr [ebx+691h],04h
NoBase:
        pop     edi
        pop     ebx
        jnz     short NormCode
        push    ebx
        mov     ebx,esi
        sub     ebx,dword ptr [esp+(1*4).Pushad_ESI]
;;;;        shr     ebx,3           ; index of entry
;;;;        shl     ebx,2           ; Times 4 4k pages per 16k page
;;;; Combine all of above yields
        shr     ebx,1
        cmp     ebx,0A0h
        pop     ebx
        jae     short NormCode
JNPart:
        jmp     [EMM_Patch_NotPartial_Addr]

NormCode:
        cmp     byte ptr [esi+01],4
        je      short JNPart
        jmp     [EMM_Patch_Ret_Addr]

EndProc LH_V86_EMM_Fix_Proc


;******************************************************************************
;
;   LH_V86_EMM_Fix_Proc2 and 2a
;
;   DESCRIPTION:
;       Hook to V86MMGR EMS driver.
;
;   ENTRY:
;       THIS ROUTINE IS JUMPED TO NOT CALLED!!!!
;
;   EXIT:
;       None
;
;   USES:
;       None
;
;==============================================================================

BeginProc LH_V86_EMM_Fix_Proc2

        push    edi
        mov     edi,[V86_ImprtPtr_Addr]
        mov     edi,dword ptr [edi]
        jmp     [EMM_Patch_Ret_Addr2]

EndProc LH_V86_EMM_Fix_Proc2

BeginProc LH_V86_EMM_Fix_Proc2a

        mov     word ptr [ecx+2],ax
        pop     ecx
        pop     edi
        jmp     [EMM_Patch_Ret_Addr2a]

EndProc LH_V86_EMM_Fix_Proc2a

;----------------------------------------------------------------------------;
; LoadHi_Sys_VM_Init:                                                        ;
;                                                                            ;
; Takes the instance snap shot and releases all the list memory that was used;
; in the initialization phase.                                               ;
;----------------------------------------------------------------------------;
BeginProc LoadHi_Sys_VM_Init,PUBLIC

; prepare the snap shot for the instance buffers

        call    LoadHi_Take_Instance_SnapShot

; release all initialization list memories.

        mov     esi,GlobalDeviceList    ;list used to store 'GLOBAL=' devices
        VMMcall List_Destroy
        mov     esi,InstanceDataList    ;list used to allocate instance data
        VMMcall List_Destroy

        clc                             ;call successful
        ret

EndProc LoadHi_Sys_VM_Init
;----------------------------------------------------------------------------;
; Loadhi_Int21ISR:                                                           ;
;                                                                            ;
; Traps the SetUMBLink INT 21H call and returns failure if the call tries to ;
; link the UMBs in.                                                          ;
;                                                                            ;
;   ENTRY:                                                                   ;
;       EAX = Interrupt # (21h)                                              ;
;       EBX = VM handle                                                      ;
;                                                                            ;
;   EXIT:                                                                    ;
;                                                                            ;
;   USES:                                                                    ;
;       All registers and flags                                              ;
;----------------------------------------------------------------------------;
BeginProc LoadHi_Int21ISR, High_Freq,PUBLIC

        cmp     [ebp.Client_AX],5803h   ;Set Link state call ?
        jnz     SHORT LoadHi_Int21Chain ;no.
        cmp     [ebp.Client_BX],1       ;Link UMB's in ?
        jnz     SHORT LoadHi_Int21Chain ;no.
        cmp     LoadHi_OwnCall,-1       ;from ourselves ?
        jz      SHORT LoadHi_Int21Chain ;yes.

; fail the set link call.

        or      [ebp.Client_Flags], CF_Mask
        mov     [ebp.Client_AX],1       ;invalid function (at this time)
        clc                             ;Don't reflect this int
        ret

LoadHi_Int21Chain:

        stc                             ;chain interrupt on
        ret

EndProc LoadHi_Int21ISR
;----------------------------------------------------------------------------;
; LoadHi_SystemExit:                                                         ;
;                                                                            ;
; This is called at system exit time and the UMB link information is reset.  ;
;----------------------------------------------------------------------------;
BeginProc LoadHi_SystemExit,PUBLIC

        Push_Client_State
        VMMcall Begin_Nest_Exec         ;Get ready for software ints

; reset the link state.

        mov     LoadHi_OwnCall,-1       ;we should nor trap it ourselves
        mov     [ebp.Client_AX], 05803h ;get UMB link state
        mov     ebx,UMBLinkState        ;get the saved state
        and     bx,0ffh                 ;only BL is significant
        mov     [ebp.Client_BX],bx      ;save the state to restore
        mov     eax, 21h                ;INT 21H to be done
        VMMcall Exec_Int                ;do the INT
        mov     LoadHi_OwnCall,0        ;just to make it clean.

; end the nested exec calls.

        VMMcall End_Nest_Exec
        Pop_Client_State

        clc                             ;call successful
        ret

EndProc LoadHi_SystemExit
;----------------------------------------------------------------------------;
;******************************************************************************
;                           S E R V I C E S
;******************************************************************************

BeginProc VDD2_Get_Version, Service

; if there is atleast one UMB in the mono display area then we will return
; success on this call.

        cmp     MonoDispAreaHasUMB,0    ;is there any UMB in MONO area ?
        jnz     SHORT @f                ;yes, return MONO disp VXD exits.
        xor     eax,eax
        xor     esi,esi
        stc                             ;no secondary display VXD
        ret
@@:
        mov     esi,OFFSET32 LoadHi_Device_Name
        mov     eax, 100h
        clc
        ret

EndProc VDD2_Get_Version

;******************************************************************************
;                    S E R V I C E   H O O K S
;******************************************************************************

;----------------------------------------------------------------------------;
; LoadHi_TeastGlobalV86Mem:                                                  ;
;                                                                            ;
; Entry:                                                                     ;
;       unsigned        LH_TGVLinAdd    (linear address)                     ;
;       unsigned        LH_TGVnBytes    (length of address in bytes)         ;
;       unsigned        LH_TGVflags                                          ;
;                                                                            ;
; Action:                                                                    ;
;       . If the Linear address is above 0A0000H, this routine returns a 1   ;
;         in EAX to imply that the address is global, else it will chain     ;
;         the call on to the original service handler.                       ;
;                                                                            ;
; Exit:                                                                      ;
;       . EAX = 1 if the linear address is above 0A0000H, else it chains the ;
;         call along.                                                        ;
;                                                                            ;
; Uses:                                                                      ;
;----------------------------------------------------------------------------;

BeginProc LoadHi_TestGlobalV86Mem,PUBLIC

        enter   0,0

        LH_TGVLinAdd equ        dword ptr [ebp+8]
        LH_TGVnBytes equ        dword ptr [ebp+12]
        LH_TGVflags  equ        dword ptr [ebp+16]

        mov     eax,FirstUMBPage        ;get the first UMB page
        shl     eax,12                  ;convert into a linear address
        cmp     LH_TGVLinAdd,eax        ;in UMB range ?
        jae     SHORT LH_TGVGlobalAdd   ;yes.
        leave
        jmp     [ActualTGV86Mem]        ;chain it on

LH_TGVGlobalAdd:

        mov     eax,1                   ;address is globa (in UMB range)
        leave
        ret

EndProc LoadHi_TestGlobalV86Mem
;******************************************************************************
;              D E V I C E   C O N T R O L   H A N D L E R S
;******************************************************************************


;******************************************************************************
;                       L O C A L   P R O C E D U R E S
;******************************************************************************


;******************************************************************************
;                      D E B U G G I N G   C O D E
;******************************************************************************


IFDEF DEBUG

ENDIF

VxD_CODE_ENDS


END LoadHi_Real_Mode_Init
