home *** CD-ROM | disk | FTP | other *** search
/ Power-Programmierung / CD1.mdf / assemblr / library / memory / himem / src / himem.asm < prev    next >
Assembly Source File  |  1988-08-11  |  83KB  |  2,803 lines

  1. ;*****************************************************************************
  2. ;*                                         *
  3. ;*  HIMEM.ASM -                            Chip Anderson    *
  4. ;*                                         *
  5. ;*    Extended Memory Specification Driver -                     *
  6. ;*        Copyright 1988, Microsoft Corporation                 *
  7. ;*                                         *
  8. ;*    The HMA was originally envisioned by Ralph Lipe.             *
  9. ;*    Original XMS spec designed by Aaron Reynolds, Chip Anderson, and     *
  10. ;*    Tony Gosling.  Additional spec suggestions by Phil Barrett and David *
  11. ;*    Weise of Microsoft, Ed McNierney of Lotus and Bob Smith of Qualitas. *
  12. ;*                                         *
  13. ;*    MoveExtMemory function written by Tony Gosling.                 *
  14. ;*                                         *
  15. ;*    AT&T 6300 support added by Bill Hall, Olivetti ATC, Cupertino, CA    *
  16. ;*    HP Vectra support added by Ralph Peterson, Hewlett Packard Corp.     *
  17. ;*                                         *
  18. ;*****************************************************************************
  19.  
  20. XMSVersion    equ    0200h
  21. HimemVersion    equ    0203h
  22.  
  23. ; Version -
  24. ;
  25. ;   1.00    - Written                    4/17/88
  26. ;   1.01    - Added Global/Temporary Enable of A20        4/18/88
  27. ;   1.02    - Don't use DOS to change interrupts        4/19/88
  28. ;        - Return 1 for success in Disable cases        4/19/88
  29. ;        - Prevent disables if A20 enabled at start    4/19/88
  30. ;        - Added INT 2F handler check            4/19/88
  31. ;        - Used smarter hooking routine            4/19/88
  32. ;   1.03    - Optimized some code                4/20/88
  33. ;        - Temporarily Disable properly            4/20/88
  34. ;        - Disable INT's while changing vars        4/20/88
  35. ;   1.04    - Check to see if A20 works during init        4/23/88
  36. ;        - Fixed PS/2 support                4/23/88
  37. ;   1.05    - Added QueryExtMemory and AllocExtMemory    4/25/88
  38. ;   1.06    - Never remove the INT 15h hook once it is in    4/27/88
  39. ;        - Changed ExtMemory calls to provide "full" MM    4/27/88
  40. ;        - Force A20 line off on PS2's at init time    4/27/88
  41. ;   1.07    - Added Multiple A20 Handler support        5/01/88
  42. ;        - Added popff macro                5/01/88
  43. ;        - REP MOVSW words not bytes            5/04/88
  44. ;   1.08    - Made popff relocateable            5/04/88
  45. ;        - Added support for the AT&T 6300 Plus        5/05/88
  46. ;        - Added support for the HP Vectra        5/06/88
  47. ;   1.09    - Added CEMM recognition code            5/16/88
  48. ;        - Don't automatically trash BX in HMMControl    5/17/88
  49. ;   1.10    - Change PS/2 ID routine to use Watchdog timer    6/02/88
  50. ;        - Changed CEMM recognition string to just VDISK 6/07/88
  51. ;        - Fixed 2 instance bug                6/14/88
  52. ;   1.11    - Changed INT 2F multiplex number to 43h    6/23/88
  53. ;        - Fixed HP Vectra support for older Vectras    6/23/88
  54. ;        - Fixed Block Move register trashing bug    6/25/88
  55. ;   2.00    - Updated to XMS v2.00                7/10/88
  56. ;        - Reworked initialization code            7/12/88
  57. ;        - Reworked reentrancy issues            7/13/88
  58. ;        - Finialized A20 handling            7/14/88
  59. ;        - Added parameter support            7/14/88
  60. ;   2.01    - Official version with Vecta and 6300 support    7/15/88
  61. ;   2.02    - Removed INT 1 from MoveExtMemory        7/19/88
  62. ;        - Fixed minor problems in QueryExtMemory    7/19/88
  63. ;   2.03    - Added 386 Big Mode MoveBlock            8/04/88
  64. ;        - Added Compaq "Built-In" Memory support    8/05/88
  65. ;        - Fixed 64K-free Installation bug        8/05/88
  66. ;        - Change PS/2 detection code yet again        8/08/88
  67. ;        - Fixed "A20 On" Message bug (ugh)        8/09/88
  68. ;        - Fixed A20 Init testing code            8/09/88
  69. ;        - Cleaned up for publication            8/09/88
  70.  
  71.         name    Himem
  72.         title   'HIMEM.SYS - Microsoft XMS Device Driver'
  73.  
  74. ;*--------------------------------------------------------------------------*
  75. ;*    EQUATES                                    *
  76. ;*--------------------------------------------------------------------------*
  77.  
  78. DEFHANDLES        equ    32        ; Default # of EMB handles
  79. MAXHANDLES        equ    128        ; Max # of EMB handles
  80.  
  81. cXMSFunctions        equ    12h        ; = # of last function+1!
  82.  
  83. FREEFLAG        equ    00000001b    ; EMB Flags
  84. USEDFLAG        equ    00000010b
  85. UNUSEDFLAG        equ    00000100b
  86.  
  87. ; XMS Error Codes.
  88. ERR_NOTIMPLEMENTED    equ    080h
  89. ERR_VDISKFOUND        equ    081h
  90. ERR_A20            equ    082h
  91. ERR_GENERAL        equ    08Eh
  92. ERR_UNRECOVERABLE    equ    08Fh
  93.  
  94. ERR_HMANOTEXIST        equ    090h
  95. ERR_HMAINUSE        equ    091h
  96. ERR_HMAMINSIZE        equ    092h
  97. ERR_HMANOTALLOCED    equ    093h
  98.  
  99. ERR_OUTOMEMORY        equ    0A0h
  100. ERR_OUTOHANDLES        equ    0A1h
  101. ERR_INVALIDHANDLE    equ    0A2h
  102. ERR_SHINVALID        equ    0A3h
  103. ERR_SOINVALID        equ    0A4h
  104. ERR_DHINVALID        equ    0A5h
  105. ERR_DOINVALID        equ    0A6h
  106. ERR_LENINVALID        equ    0A7h
  107. ERR_OVERLAP        equ    0A8h
  108. ERR_PARITY        equ    0A9h
  109. ERR_EMBUNLOCKED        equ    0AAh
  110. ERR_EMBLOCKED        equ    0ABh
  111. ERR_LOCKOVERFLOW    equ    0ACh
  112. ERR_LOCKFAIL        equ    0ADh
  113.  
  114. ERR_UMBSIZETOOBIG    equ    0B0h
  115. ERR_NOUMBS        equ    0B1h
  116. ERR_INVALIDUMB        equ    0B2h
  117.  
  118. .386p
  119.  
  120. ; In order to address memory above 1 MB on the AT&T 6300 PLUS, it is
  121. ; necessary to use the special OS-MERGE hardware to activate lines
  122. ; A20 to A23.  However, these lines can be disabled only by resetting
  123. ; the processor.  The address to which to return after reset are placed
  124. ; at 40:A2, noted here as RealLoc1.
  125.  
  126. BiosSeg SEGMENT USE16 AT 40h          ; Used to locate 6300 PLUS reset address
  127.  
  128.         org    00A2h
  129. RealLoc1    dd    0
  130.  
  131. BiosSeg ends
  132.  
  133.  
  134. ; Macro to avoid the 286 POPF bug.  Performs a harmless IRET to simulate a
  135. ;   popf.  Some 286s allow interrupts to sneak in during a real popf.
  136.  
  137. popff        macro
  138.         push    cs
  139.         call    pPPFIRet    ; Defined as the offset of any IRET
  140.         endm
  141.  
  142. ;*--------------------------------------------------------------------------*
  143. ;*        SEGMENT DEFINITION                            *
  144. ;*--------------------------------------------------------------------------*
  145.  
  146. CODE        SEGMENT PARA PUBLIC USE16 'CODE'
  147.  
  148.         assume  cs:code,ds:code,es:code
  149.  
  150.         org        0
  151.  
  152. ; The Driver Header definition.
  153. Header        dd    -1        ; Link to next driver, -1 = end of list
  154.         dw    1010000000000000b
  155.                     ; Device attributes, Non-IBM bit set
  156.         dw    Strategy    ; "Stategy" entry point
  157.         dw    Interrupt   ; "Interrupt" entry point
  158.         db    'XMSXXXX0'  ; Device name
  159.  
  160.  
  161. ;****************************************************************************
  162. ;*                                        *
  163. ;*  Data Structures and Global Variables -                    *
  164. ;*                                        *
  165. ;****************************************************************************
  166.  
  167. ; The driver Request Header structure definition.
  168. ReqHdr struc
  169.     ReqLen    db    ?
  170.     Unit    db    ?
  171.     Command    db    ?
  172.     Status    dw    ?
  173.     Reserved    db    8 dup (?)
  174.     Units    db    ?
  175.     Address    dd    ?
  176.     pCmdLine    dd    ?
  177. ReqHdr ends
  178.  
  179. ; An EMB Handle structure definition.
  180. Handle struc            ; Handle Table Entry
  181.     Flags    db    ?    ; Unused/InUse/Free
  182.     cLock    db    ?    ; Lock count
  183.     Base    dw    ?    ; 32-bit base address in K
  184.     Len        dw    ?    ; 32-bit length in K
  185. Handle ends
  186.  
  187. ; Extended Memory Move Block structure definition.
  188. MoveExtendedStruc struc
  189.     bCount        dd    ?    ; Length of block to move
  190.     SourceHandle    dw    ?    ; Handle for souce
  191.     SourceOffset    dd    ?    ; Offset into source
  192.     DestHandle        dw    ?    ; Handle for destination
  193.     DestOffset        dd    ?    ; Offset into destination
  194. MoveExtendedStruc ends
  195.  
  196. ; The Global variables.
  197. pPPFIRet    dw    PPFIRet ; The offset of an IRET for the POPFF macro
  198. pReqHdr        dd    ?    ; Pointer to MSDOS Request Header structure
  199. pInt15Vector    dw    15h*4,0 ; Pointer to the INT 15 Vector
  200. PrevInt15    dd    0    ; Original INT 15 Vector
  201. PrevInt2F    dd    0    ; Original INT 2F Vector
  202. fHMAInUse    db    0    ; High Memory Control Flag, != 0 -> In Use
  203. fCanChangeA20    db    0    ; A20 Enabled at start?
  204. fHMAMayExist    db    0    ; True if the HMA could exist at init time
  205. fHMAExists    db    0    ; True if the HMA exists
  206. fVDISK        db    0    ; True if a VDISK device was found
  207. EnableCount    dw    0    ; A20 Enable/Disable counter
  208. fGlobalEnable    dw    0    ; Global A20 Enable/Disable flag
  209. KiddValley    dw    0    ; The address of the handle table 
  210. KiddValleyTop    dw    0    ; Points to the end of the handle table
  211. MinHMASize    dw    0        ; /HMAMIN= parameter value
  212. cHandles    dw    DEFHANDLES  ; # of handles to allocate
  213.  
  214. cImplementedFuncs db    cXMSFunctions-3        ; Omit the UMB functions
  215.                         ; and ReallocEMB
  216.  
  217. A20Handler    dw    0    ; Offset of the A20 Handler
  218.  
  219. BIMBase     dw    0    ; Base address and Lenght of remaining Compaq
  220. BIMLength    dw    0    ;   Built-In Memory (set at Init time)
  221.  
  222. MemCorr        dw    0    ; KB of memory at FA0000 on AT&T 6300 Plus.
  223.                 ;      This is used to correct INT 15h,
  224.                 ;      Function 88h return value.
  225. OldStackSeg    dw    0    ; Stack segment save area for 6300 Plus.
  226.                 ;      Needed during processor reset.
  227.  
  228. ;*--------------------------------------------------------------------------*
  229. ;*                                        *
  230. ;*  Strategy -                                    *
  231. ;*                                        *
  232. ;*    Called by MS-DOS when ever the driver is accessed.            *
  233. ;*                                        *
  234. ;*  ARGS:   ES:BX = Address of Request Header                    *
  235. ;*  RETS:   Nothing                                *
  236. ;*  REGS:   Preserved                                *
  237. ;*                                        *
  238. ;*--------------------------------------------------------------------------*
  239.  
  240. Strategy    proc    far
  241.  
  242.         ; Save the address of the request header.
  243.         mov        word ptr cs:[pReqHdr],bx
  244.         mov        word ptr cs:[pReqHdr][2],es
  245.         ret
  246.  
  247. Strategy    endp
  248.  
  249.  
  250. ;*--------------------------------------------------------------------------*
  251. ;*                                        *
  252. ;*  Interrupt -                                    *
  253. ;*                                        *
  254. ;*    Called by MS-DOS immediately after Strategy routine            *
  255. ;*                                        *
  256. ;*  ARGS:   None                                *
  257. ;*  RETS:   Return code in Request Header's Status field            *
  258. ;*  REGS:   Preserved                                *
  259. ;*                                        *
  260. ;*--------------------------------------------------------------------------*
  261.  
  262. Interrupt   proc    far
  263.  
  264.         ; Save the registers including flags.
  265.         push    ax            ; We cannot use pusha\popa because
  266.         push    bx            ;    we could be on an 8086 at this point
  267.         push    cx
  268.         push    dx
  269.         push    ds
  270.         push    es
  271.         push    di
  272.         push    si
  273.         push    bp
  274.         pushf
  275.  
  276.         ; Set DS=CS for access to global variables.
  277.         push    cs
  278.         pop        ds
  279.  
  280.         les        di,[pReqHdr]    ; ES:DI = Request Header
  281.  
  282.         mov     bl,es:[di.Command]    ; Get Function code in BL
  283.  
  284.         or        bl,bl        ; Only Function 00h (Init) is legal
  285.         jz        short IInit
  286.  
  287.         cmp     bl,16        ; Test for "legal" DOS functions
  288.         jle     short IOtherFunc
  289.  
  290. IBogusFunc: mov     ax,8003h        ; Return "Unknown Command"
  291.         jmp     short IExit
  292.  
  293. IOtherFunc: xor     ax,ax        ; Return zero for unsupported functions
  294.         jmp     short IExit
  295.  
  296.         ; Initialize the driver.
  297. IInit:        call    InitDriver
  298.  
  299.         les        di,[pReqHdr]    ; Restore ES:DI = Request Header
  300.  
  301. IExit:        or        ax,0100h        ; Turn on the "Done" bit
  302.         mov        es:[di.Status],ax    ; Store return code
  303.  
  304.         ; Restore the registers.
  305.         popff
  306.         pop        bp
  307.         pop        si
  308.         pop        di
  309.         pop        es
  310.         pop        ds
  311.         pop        dx
  312.         pop        cx
  313.         pop        bx
  314.         pop        ax
  315.         ret
  316.  
  317. Interrupt   endp
  318.  
  319.  
  320. ;*--------------------------------------------------------------------------*
  321. ;*                                        *
  322. ;*  Int2FHandler -                                *
  323. ;*                                        *
  324. ;*    Hooks Function 43h, Subfunction 10h to return the            *
  325. ;*    address of the High Memory Manager Control function.            *
  326. ;*    Also returns 80h if Function 43h, Subfunction 0h is requested.        *
  327. ;*                                        *
  328. ;*  ARGS:   AH = Function, AL = Subfunction                    *
  329. ;*  RETS:   ES:BX = Address of XMMControl function (if AX=4310h)        *
  330. ;*        AL = 80h (if AX=4300)                        *
  331. ;*  REGS:   Preserved except for ES:BX (if AX=4310h)                *
  332. ;*        Preserved except for AL    (if AX=4300h)                *
  333. ;*                                        *
  334. ;*--------------------------------------------------------------------------*
  335.  
  336. Int2FHandler proc   far
  337.  
  338.         sti                    ; Flush any queued interrupts
  339.  
  340.         cmp        ah,43h            ; Function 43h?
  341.         jne     short I2FNextInt
  342.         or        al,al            ; Subfunction 0?
  343.         jne     short I2FNextSub        ; No, continue
  344.  
  345.         ; Indicate that an XMS driver is installed.
  346.         mov        al,80h            ; Return 80h in AL
  347. PPFIRet:    iret                ; Label sets up the POPFF macro
  348.  
  349. I2FNextSub: cmp        al,10h            ; Subfunction 10?
  350.         jne     short I2FNextInt        ; No, goto next handler
  351.  
  352.         ; Return the address of the XMS Control function in ES:BX.
  353.         push    cs
  354.         pop        es
  355.         mov        bx,offset XMMControl
  356.         iret
  357.  
  358.         ; Continue down the Int 2F chain.
  359. I2FNextInt: cli                    ; Disable interrupts again
  360.         jmp        cs:[PrevInt2F]
  361.  
  362. Int2FHandler endp
  363.  
  364.  
  365. ;*--------------------------------------------------------------------------*
  366. ;*                                        *
  367. ;*  ControlJumpTable -                                *
  368. ;*                                        *
  369. ;*    Contains the address for each of the XMS Functions.            *
  370. ;*                                        *
  371. ;*--------------------------------------------------------------------------*
  372.  
  373. ControlJumpTable label word
  374.         dw    Version            ; Function 00h
  375.         dw    RequestHMA        ; Function 01h
  376.         dw    ReleaseHMA        ; Function 02h
  377.         dw    GlobalEnableA20        ; Function 03h
  378.         dw    GlobalDisableA20    ; Function 04h
  379.         dw    LocalEnableA20        ; Function 05h
  380.         dw    LocalDisableA20        ; Function 06h
  381.         dw    IsA20On            ; Function 07h
  382.         dw    QueryExtMemory        ; Function 08h
  383.         dw    AllocExtMemory        ; Function 09h
  384.         dw    FreeExtMemory        ; Function 0Ah
  385.         dw    MoveBlock        ; Function 0Bh
  386.         dw    LockExtMemory        ; Function 0Ch
  387.         dw    UnlockExtMemory        ; Function 0Dh
  388.         dw    GetExtMemoryInfo    ; Function 0Eh
  389.  
  390.         ; We don't implement Realloc in this version.
  391. ;        dw    ReallocExtMemory    ; Function 0Fh
  392.      
  393.         ; We don't implement the UMB functions.
  394. ;        dw    RequestUMB        ; Function 14
  395. ;        dw    ReleaseUMB        ; Function 15
  396.  
  397.  
  398. ;*--------------------------------------------------------------------------*
  399. ;*                                        *
  400. ;*  XMMControl -                                *
  401. ;*                                        *
  402. ;*    Main Entry point for the Extended Memory Manager            *
  403. ;*                                        *
  404. ;*  ARGS:   AH = Function, AL = Optional parm                    *
  405. ;*  RETS:   AX = Function Success Code, BL = Optional Error Code        *
  406. ;*  REGS:   AX, BX, DX and ES may not be preserved depending on function    *
  407. ;*                                        *
  408. ;*  INTERNALLY REENTRANT                            *
  409. ;*                                        *
  410. ;*--------------------------------------------------------------------------*
  411.  
  412. XMMControl  proc   far
  413.  
  414.         jmp        short XCControlEntry    ; For "hookability"
  415.         nop                    ; NOTE: The jump must be a 
  416.         nop                    ;  short jump to indicate
  417.         nop                    ;  the end of any hook chain.
  418.                         ;  The nop's allow a far jump
  419.                         ;  to be patched in.
  420. XCControlEntry:
  421.         ; Preserve the following registers.
  422.         push    cx
  423.         push    si
  424.         push    di
  425.         push    ds
  426.         push    es
  427.         pushf
  428.  
  429.         ; Save DS in ES.
  430.         push    ds
  431.         pop        es            ; NOTE: ES cannot be used for parms!
  432.         
  433.         ; Set DS equal to CS.
  434.         push    cs
  435.         pop        ds
  436.         
  437.         ; Preserve the current function number.
  438.         push    ax
  439.  
  440.         ; Is this a call to "Get XMS Version"?
  441.         or        ah,ah
  442.         jz        short XCCallFunc      ; Yes, don't hook INT 15h yet
  443.         
  444.         ; Is this a valid function number?
  445.         cmp        ah,[cImplementedFuncs]
  446.         jb        short XCCheckHook
  447.         pop        ax            ; No, Un-preserve AX and return an error
  448.         xor        ax,ax
  449.         mov        bl,ERR_NOTIMPLEMENTED
  450.         jmp        short XCExit
  451.  
  452.         ; Is INT 15h already hooked?
  453. XCCheckHook:pushf
  454.         cli                ; This is a critical section
  455.         
  456.         cmp        word ptr [PrevInt15][2],0    ; Is the segment non-zero?
  457.         jne     short XCCheckVD
  458.  
  459.         ; Try to claim all remaining extended memory.
  460.         call    HookInt15
  461.  
  462.         ; Was a VDISK device found?
  463. XCCheckVD:  popff            ; End of critical section
  464.         cmp        [fVDISK],0
  465.         je        short XCCallFunc
  466.         pop        ax            ; Yes, Un-preserve AX and return an error
  467.         xor        ax,ax
  468.         mov        bl,ERR_VDISKFOUND
  469.         xor        dx,dx
  470.         jmp        short XCExit
  471.  
  472.         ; Call the appropriate API function.        
  473. XCCallFunc: pop        ax            ; Restore AX
  474.         mov        al,ah
  475.         xor        ah,ah
  476.         shl        ax,1
  477.         mov        di,ax        ; NOTE: DI cannot be used for parms!
  478.         
  479.         call    word ptr [ControlJumpTable+di]
  480.  
  481.         ; Restore the preserved registers.
  482. XCExit:        popff            ; NOTE: Flags must be restored immediately
  483.         pop        es            ;    after the call to the API functions.
  484.         pop        ds
  485.         pop        di
  486.         pop        si
  487.         pop        cx
  488.         ret
  489.  
  490. XMMControl  endp
  491.  
  492.  
  493. ;*--------------------------------------------------------------------------*
  494. ;*                                        *
  495. ;*  Get XMS Version Number -                    FUNCTION 00h    *
  496. ;*                                        *
  497. ;*    Returns the XMS version number                        *
  498. ;*                                        *
  499. ;*  ARGS:   None                                *
  500. ;*  RETS:   AX = XMS Version Number                        *
  501. ;*        BX = Internal Driver Version Number                    *
  502. ;*        DX = 1 if HMA exists, 0 if it doesn't                *
  503. ;*  REGS:   AX, BX and DX are clobbered                        *
  504. ;*                                        *
  505. ;*  INTERNALLY REENTRANT                            *
  506. ;*                                        *
  507. ;*--------------------------------------------------------------------------*
  508.  
  509. Version        proc    near
  510.  
  511.         mov        ax,XMSVersion
  512.         mov        bx,HimemVersion
  513.         xor        dh,dh
  514.  
  515.         ; Is Int 15h hooked?
  516.         cmp        word ptr [PrevInt15][2],0    ; Is the segment non-zero?
  517.         jne     short VHooked
  518.         mov        dl,[fHMAMayExist]        ; No, return the status at
  519.         ret                    ;  init time.
  520.  
  521. VHooked:    mov        dl,[fHMAExists]        ; Yes, return the real status
  522.         ret
  523.  
  524. Version        endp
  525.  
  526.  
  527. ;*--------------------------------------------------------------------------*
  528. ;*                                        *
  529. ;*  HookInt15 -                                    *
  530. ;*                                        *
  531. ;*    Insert the INT 15 hook                            *
  532. ;*                                        *
  533. ;*  ARGS:   None                                *
  534. ;*  RETS:   None                                *
  535. ;*  REGS:   AX, BX, CS, DI, SI, and Flags are clobbered                *
  536. ;*                                        *
  537. ;*  EXTERNALLY NON-REENTRANT                            *
  538. ;*    Interrupts must be disabled before calling this function.        *
  539. ;*                                        *
  540. ;*--------------------------------------------------------------------------*
  541.  
  542. HookInt15   proc    near
  543.  
  544.         push    es
  545.     
  546.         ; Has a VDISK device been installed?        
  547.         call    IsVDISKIn
  548.         cmp        [fVDISK],0
  549.         je        short HINoVD    ; No, continue
  550.         pop        es            ; Yes, return without hooking
  551.         ret
  552.         
  553. HINoVD:        mov        ah,88h        ; Is 64K of Extended memory around?
  554.         int        15h
  555.         sub        ax,[MemCorr]    ; 6300 Plus may have memory at FA0000h
  556.         cmp        ax,64
  557.         jb        short HIInitMemory    ; Less than 64K free?  Then no HMA.
  558.         mov        [fHMAExists],1
  559.  
  560. HIInitMemory:
  561.         ; Init the first handle to be one huge free block.
  562.         mov        bx,[KiddValley]
  563.         mov        [bx.Flags],FREEFLAG
  564.         mov        [bx.Len],ax
  565.         mov        [bx.Base],1024
  566.         cmp        [fHMAExists],0
  567.         je        short HICont
  568.         add     [bx.Base],64
  569.  
  570.         ; See if any Compaq "Built In Memory" exists.
  571. HICont:     mov     ax,[BIMBase]
  572.         or        ax,ax
  573.         jz        short HIHookEmHorns
  574.  
  575.         mov     cx,[BIMLength]
  576.  
  577.         ; Fill out the next handle entry.
  578.         add     bx,size Handle
  579.         mov        [bx.Flags],FREEFLAG
  580.         mov     [bx.Len],cx
  581.         mov     [bx.Base],ax
  582.  
  583.         ; Save the current INT 15 vector.
  584. HIHookEmHorns:
  585.         les     si,dword ptr pInt15Vector
  586.  
  587.         ; Exchange the old vector with the new one.
  588.         mov        ax,offset Int15Handler
  589.         xchg    ax,es:[si][0]
  590.         mov        word ptr [PrevInt15][0],ax
  591.         mov        ax,cs
  592.         xchg    ax,es:[si][2]
  593.         mov        word ptr [PrevInt15][2],ax
  594.         
  595.         pop        es
  596.         ret
  597.  
  598. HookInt15   endp
  599.  
  600.  
  601. ;*--------------------------------------------------------------------------*
  602. ;*                                        *
  603. ;*  IsVDISKIn -                                    *
  604. ;*                                        *
  605. ;*    Looks for drivers which use the IBM VDISK method of allocating        *
  606. ;*  Extended Memory.  XMS is incompatible with the VDISK method.        *
  607. ;*                                        *
  608. ;*  ARGS:   None                                *
  609. ;*  RETS:   None.  Sets "fVDISK" accordingly                    *
  610. ;*  REGS:   AX, CX, SI, DI and Flags are clobbered                *
  611. ;*                                        *
  612. ;*  INTERNALLY REENTRANT                            *
  613. ;*                                        *
  614. ;*--------------------------------------------------------------------------*
  615.  
  616. pVDISK        label   dword
  617.         dw        00013h
  618.         dw        0FFFFh
  619.         
  620. szVDISK        db        'VDISK'           
  621.  
  622. IsVDISKIn   proc    near
  623.  
  624.         ; Look for "VDISK" starting at the 4th byte of extended memory.
  625.         call    LocalEnableA20        ; Turn on A20
  626.  
  627.         push    ds
  628.         push    es
  629.  
  630.         ; Set up the comparison.
  631.         lds        si,cs:pVDISK
  632.         push    cs
  633.         pop        es
  634.         mov        di,offset szVDISK
  635.         mov        cx,5
  636.         cld
  637.         rep     cmpsb            ; Do the comparison
  638.  
  639.         pop     es                ; Restore ES and DS
  640.         pop     ds
  641.  
  642.         jz        short IVIFoundIt
  643.         mov     [fVDISK],0            ; No VDISK device found
  644.         jmp        short IVIExit
  645.         
  646.         ; "VDISK" was found.
  647. IVIFoundIt: mov        [fVDISK],1
  648.  
  649. IVIExit:    call    LocalDisableA20
  650.         ret                 ; Turn off A20
  651.  
  652. IsVDISKIn   endp
  653.  
  654.  
  655. ;*--------------------------------------------------------------------------*
  656. ;*                                        *
  657. ;*  Int15Handler -                                *
  658. ;*                                        *
  659. ;*    Hooks Function 88h to return zero as the amount of extended        *
  660. ;*    memory available in the system.                        *
  661. ;*                                        *
  662. ;*    Hooks Function 87h and preserves the state of A20 across the        *
  663. ;*    block move.                                *
  664. ;*                                        *
  665. ;*  ARGS:   AH = Function, AL = Subfunction                    *
  666. ;*  RETS:   AX = 0 (if AH == 88h)                        *
  667. ;*  REGS:   AX is clobbered                            *
  668. ;*                                        *
  669. ;*--------------------------------------------------------------------------*
  670.  
  671. I15RegSave  dw        ?
  672.  
  673. Int15Handler proc   far
  674.  
  675.         ; Is this a request for the amount of free extended memory?
  676.         cmp        ah,88h
  677.         jne     short I15HCont    ; No, continue
  678.  
  679.         xor     ax,ax        ; Yes, return zero
  680.         iret
  681.  
  682.         ; Is it a Block Move?
  683. I15HCont:   cmp        ah,87h
  684.         jne     short I15HNext    ; No, continue
  685.  
  686.         ; Int 15h Block Move:
  687.         cli             ; Make sure interrupts are off
  688.  
  689.         ; Store the A20 line's state.
  690.         pusha            ; Preserve the registers
  691.         call    IsA20On
  692.         mov        cs:[I15RegSave],ax
  693.         popa            ; Restore the registers
  694.  
  695.         ; Call the previous Int 15h handler.
  696.         pushf            ; Simualate an interrupt
  697.         call    cs:[PrevInt15]
  698.         pusha            ; Preserve previous handler's return
  699.  
  700.         ; Was A20 on before?
  701.         cmp        cs:[I15RegSave],0
  702.         je        short I15HExit    ; No, continue
  703.         mov     ax,1
  704.         call    cs:[A20Handler]    ; Yes, turn A20 back on
  705.  
  706. I15HExit:   popa            ; Restore the previous handler's return
  707.         iret
  708.  
  709.         ; Continue down the Int 15h chain.
  710. I15HNext:   jmp     cs:[PrevInt15]
  711.  
  712. Int15Handler endp
  713.  
  714.  
  715. ;*--------------------------------------------------------------------------*
  716. ;*                                        *
  717. ;*  RequestHMA -                        FUNCTION 01h    *
  718. ;*                                        *
  719. ;*    Give caller control of the High Memory Area if it is available.        *
  720. ;*                                        *
  721. ;*  ARGS:   DX = HMA space requested in bytes                    *
  722. ;*  RETS:   AX = 1 if the HMA was reserved, 0 otherwise.  BL = Error Code   *
  723. ;*  REGS:   AX, BX and Flags clobbered                        *
  724. ;*                                        *
  725. ;*  INTERNALLY NON-REENTRANT                            *
  726. ;*                                        *
  727. ;*--------------------------------------------------------------------------*
  728.  
  729. RequestHMA  proc   near
  730.  
  731.         cli                ; This is a non-reentrant function.
  732.                     ;    Flags are restored after the return.        
  733.         mov        bl,ERR_HMAINUSE
  734.         cmp        [fHMAInUse],1   ; Is the HMA already allocated?
  735.         je        short RHRetErr
  736.  
  737.         mov        bl,ERR_HMANOTEXIST
  738.         cmp        [fHMAExists],0  ; Is the HMA available?
  739.         je        short RHRetErr
  740.  
  741.         mov        bl,ERR_HMAMINSIZE
  742.         cmp        dx,[MinHMASize] ; Is this guy allowed in?
  743.         jb        short RHRetErr
  744.  
  745.         mov        ax,1
  746.         mov        [fHMAInUse],al  ; Reserve the High Memory Area
  747.         xor     bl,bl        ; Clear the error code
  748.         ret
  749.  
  750. RHRetErr:   xor     ax,ax        ; Return failure with error code in BL
  751.         ret
  752.  
  753. RequestHMA  endp
  754.  
  755.  
  756. ;*--------------------------------------------------------------------------*
  757. ;*                                        *
  758. ;*  ReleaseHMA -                        FUNCTION 02h    *
  759. ;*                                        *
  760. ;*    Caller is releasing control of the High Memory area            *
  761. ;*                                        *
  762. ;*  ARGS:   None                                *
  763. ;*  RETS:   AX = 1 if control is released, 0 otherwise.     BL = Error Code    *
  764. ;*  REGS:   AX, BX and Flags clobbered                        *
  765. ;*                                        *
  766. ;*  INTERNALLY NON-REENTRANT                            *
  767. ;*                                        *
  768. ;*--------------------------------------------------------------------------*
  769.  
  770. ReleaseHMA  proc   near
  771.  
  772.         cli                ; This is a non-reentrant function
  773.         
  774.         ; Is the HMA currently in use?
  775.         mov        al,[fHMAInUse]
  776.         or        al,al
  777.         jz        short RLHRetErr ; No, return error
  778.         
  779.         ; Release the HMA and return success.
  780.         mov        [fHMAInUse],0
  781.         mov        ax,1
  782.         xor        bl,bl
  783.         ret
  784.         
  785. RLHRetErr:  xor        ax,ax
  786.         mov        bl,ERR_HMANOTALLOCED
  787.         ret           
  788.  
  789. ReleaseHMA  endp
  790.  
  791.  
  792. ;*--------------------------------------------------------------------------*
  793. ;*                                        *
  794. ;*  GlobalEnableA20 -                        FUNCTION 03h    *
  795. ;*                                        *
  796. ;*    Globally enable the A20 line                        *
  797. ;*                                        *
  798. ;*  ARGS:   None                                *
  799. ;*  RETS:   AX = 1 if the A20 line is enabled, 0 otherwise.  BL = Error        *
  800. ;*  REGS:   AX, BX and Flags clobbered                        *
  801. ;*                                        *
  802. ;*  INTERNALLY NON-REENTRANT                            *
  803. ;*                                        *
  804. ;*--------------------------------------------------------------------------*
  805.  
  806. GlobalEnableA20 proc near
  807.  
  808.         cli                ; This is a non-reentrant function
  809.  
  810.         ; Is A20 already globally enabled?
  811.         cmp        [fGlobalEnable],1
  812.         je        short GEARet
  813.  
  814.         ; Attempt to enable the A20 line.
  815.         call    LocalEnableA20
  816.         or        ax,ax
  817.         jz        short GEAA20Err
  818.  
  819.         ; Mark A20 as globally enabled.
  820.         mov        [fGlobalEnable],1
  821.  
  822.         ; Return success.
  823. GEARet:        mov        ax,1
  824.         xor        bl,bl
  825.         ret
  826.  
  827.         ; Some A20 error occured.
  828. GEAA20Err:  mov        bl,ERR_A20
  829.         xor        ax,ax
  830.         ret
  831.  
  832. GlobalEnableA20 endp
  833.  
  834.  
  835. ;*--------------------------------------------------------------------------*
  836. ;*                                        *
  837. ;*  GlobalDisableA20 -                        FUNCTION 04h    *
  838. ;*                                        *
  839. ;*    Globally disable the A20 line                        *
  840. ;*                                        *
  841. ;*  ARGS:   None                                *
  842. ;*  RETS:   AX = 1 if the A20 line is disabled, 0 otherwise.  BL = Error    *
  843. ;*  REGS:   AX, BX and Flags are clobbered                    *
  844. ;*                                        *
  845. ;*  INTERNALLY NON-REENTRANT                            *
  846. ;*                                        *
  847. ;*--------------------------------------------------------------------------*
  848.  
  849. GlobalDisableA20 proc near
  850.  
  851.         cli                ; This is a non-reentrant function
  852.  
  853.         ; Is A20 already globally disabled?
  854.         cmp        [fGlobalEnable],0
  855.         je        short GDARet
  856.  
  857.         ; Attempt to disable the A20 line.
  858.         call    LocalDisableA20
  859.         or        ax,ax
  860.         jz        short GDAA20Err
  861.  
  862.         ; Mark A20 as globally disabled.
  863.         mov        [fGlobalEnable],0
  864.  
  865.         ; Return success.
  866. GDARet:        mov        ax,1
  867.         xor        bl,bl
  868.         ret
  869.  
  870.         ; Some A20 error occured.
  871. GDAA20Err:  mov        bl,ERR_A20
  872.         xor        ax,ax
  873.         ret
  874.  
  875. GlobalDisableA20 endp
  876.  
  877.  
  878. ;*--------------------------------------------------------------------------*
  879. ;*                                        *
  880. ;*  LocalEnableA20 -                        FUNCTION 05h    *
  881. ;*                                        *
  882. ;*    Locally enable the A20 line                        *
  883. ;*                                        *
  884. ;*  ARGS:   None                                *
  885. ;*  RETS:   AX = 1 if the A20 line is enabled, 0 otherwise.  BL = Error        *
  886. ;*  REGS:   AX, BX and Flags clobbered                        *
  887. ;*                                        *
  888. ;*  INTERNALLY NON-REENTRANT                            *
  889. ;*                                        *
  890. ;*--------------------------------------------------------------------------*
  891.  
  892. LocalEnableA20 proc near
  893.  
  894.         cli                ; This is a non-reentrant function
  895.         
  896.         cmp        [fCanChangeA20],1    ; Can we change A20?
  897.         jne     short LEARet    ; No, don't touch A20
  898.  
  899.         ; Only actually enable A20 if the count is zero.
  900.         cmp        [EnableCount],0
  901.         jne     short LEAIncIt
  902.  
  903.         ; Attempt to enable the A20 line.
  904.         mov        ax,1
  905.         call    [A20Handler]    ; Call machine-specific A20 handler
  906.         or        ax,ax
  907.         jz        short LEAA20Err
  908.  
  909. LEAIncIt:   inc        [EnableCount]
  910.  
  911.         ; Return success.
  912. LEARet:        mov        ax,1
  913.         xor        bl,bl
  914.         ret
  915.  
  916.         ; Some A20 error occurred.
  917. LEAA20Err:  mov        bl,ERR_A20
  918.         xor        ax,ax
  919.         ret
  920.         
  921. LocalEnableA20 endp
  922.  
  923.  
  924. ;*--------------------------------------------------------------------------*
  925. ;*                                        *
  926. ;*  LocalDisableA20 -                        FUNCTION 06h    *
  927. ;*                                        *
  928. ;*    Locally disable the A20 line                        *
  929. ;*                                        *
  930. ;*  ARGS:   None                                *
  931. ;*  RETS:   AX = 1 if the A20 line is disabled, 0 otherwise.  BL = Error    *
  932. ;*  REGS:   AX, BX and Flags are clobbered                    *
  933. ;*                                        *
  934. ;*  INTERNALLY NON-REENTRANT                            *
  935. ;*                                        *
  936. ;*--------------------------------------------------------------------------*
  937.  
  938. LocalDisableA20 proc near
  939.  
  940.         cli                ; This is a non-reentrant function
  941.         
  942.         cmp        [fCanChangeA20],0    ; Can we change A20?
  943.         je        short LDARet    ; No, don't touch A20
  944.  
  945.         ; Make sure the count's not zero.
  946.         cmp        [EnableCount],0
  947.         je        short LDAA20Err
  948.  
  949.         ; Only actually disable if the count is one.
  950.         cmp        [EnableCount],1
  951.         jne     short LDADecIt
  952.  
  953.         xor        ax,ax
  954.         call    [A20Handler]    ; Call machine-specific A20 handler
  955.         or        ax,ax
  956.         jz        short LDAA20Err
  957.  
  958. LDADecIt:   dec        [EnableCount]
  959.  
  960.         ; Return success.
  961. LDARet:        mov        ax,1
  962.         xor        bl,bl
  963.         ret
  964.  
  965.         ; Some A20 error occurred.
  966. LDAA20Err:  mov     bl,ERR_A20
  967.         xor     ax,ax
  968.         ret
  969.             
  970. LocalDisableA20 endp
  971.  
  972.  
  973. ;*--------------------------------------------------------------------------*
  974. ;*                                        *
  975. ;*  IsA20On -                            FUNCTION 07h    *
  976. ;*                                        *
  977. ;*    Returns the state of the A20 line                    *
  978. ;*                                        *
  979. ;*  ARGS:   None                                *
  980. ;*  RETS:   AX = 1 if the A20 line is enabled, 0 otherwise            *
  981. ;*  REGS:   AX, CX, DI, SI and Flags clobbered                    *
  982. ;*                                        *
  983. ;*  INTERNALLY REENTRANT                            *
  984. ;*                                        *
  985. ;*--------------------------------------------------------------------------*
  986.  
  987. LowMemory   label   dword        ; Set equal to 0000:0080
  988.         dw        00080h
  989.         dw        00000h
  990.  
  991. HighMemory  label   dword
  992.         dw        00090h        ; Set equal to FFFF:0090
  993.         dw        0FFFFh
  994.  
  995. IsA20On        proc    near
  996.  
  997.         push    ds
  998.         push    es
  999.  
  1000.         lds        si,cs:LowMemory    ; Compare the four words at 0000:0080
  1001.         les        di,cs:HighMemory    ;   with the four at FFFF:0090
  1002.         mov        cx,4
  1003.         cld
  1004.         repe    cmpsw
  1005.  
  1006.         pop        es
  1007.         pop        ds
  1008.         xor        ax,ax
  1009.  
  1010.         jcxz    short IAONoWrap ; Are the two areas the same?
  1011.         inc        ax            ; No, return A20 Enabled
  1012.  
  1013. IAONoWrap:  xor     bl,bl
  1014.         ret                ; Yes, return A20 Disabled
  1015.  
  1016. IsA20On        endp
  1017.  
  1018.  
  1019. ;*--------------------------------------------------------------------------*
  1020. ;*                                        *
  1021. ;*  QueryExtMemory -                        FUNCTION 08h    *
  1022. ;*                                        *
  1023. ;*    Returns the size of the largest free extended memory block in K        *
  1024. ;*                                        *
  1025. ;*  ARGS:   None                                *
  1026. ;*  RETS:   AX = Size of largest free block in K.  BL = Error code        *
  1027. ;*        DX = Total amount of free extended memory in K            *
  1028. ;*  REGS:   AX, BX, DX, DI, SI and Flags clobbered                *
  1029. ;*                                        *
  1030. ;*  INTERNALLY REENTRANT                            *
  1031. ;*                                        *
  1032. ;*--------------------------------------------------------------------------*
  1033.  
  1034. QueryExtMemory proc near
  1035.  
  1036.         ; Init the error code in DL.
  1037.         mov        dl,ERR_OUTOMEMORY
  1038.     
  1039.         ; Scan for the largest block marked FREE.
  1040.         xor        di,di            ; DI = Max. size found so far
  1041.         xor        si,si            ; SI = Total amount of free memory
  1042.         mov        bx,KiddValley
  1043.         mov     cx,[cHandles]        ; Loop through the handle table
  1044. QEMLoop:    cmp        [bx.Flags],FREEFLAG
  1045.         jne     short QEMBottom
  1046.  
  1047.         ; Add this free block to the total.
  1048.         add     si,[bx.Len]         ; CHANGED 7/19/88
  1049.  
  1050.         ; Is this block larger?
  1051.         mov        ax,[bx.Len]
  1052.         cmp        di,ax
  1053.         jae     short QEMBottom        ; CHANGED 7/19/88
  1054.         
  1055.         ; Yes, save it away.
  1056.         mov        di,ax
  1057.         xor     dl,dl            ; We ain't Out o' Memory
  1058.         
  1059. QEMBottom:  add        bx,SIZE Handle
  1060.         loop    QEMLoop
  1061.  
  1062.         ; Setup the return.
  1063.         mov        ax,di
  1064.         mov        bl,dl            ; Retrieve the error code
  1065.         mov     dx,si            ; CHANGED 7/19/88
  1066.         ret
  1067.  
  1068. QueryExtMemory endp
  1069.  
  1070.  
  1071. ;*--------------------------------------------------------------------------*
  1072. ;*                                        *
  1073. ;*  AllocExtMemory -                        FUNCTION 09h    *
  1074. ;*                                        *
  1075. ;*    Reserve a block of extended memory                    *
  1076. ;*                                        *
  1077. ;*  ARGS:   DX = Amount of K being requested                    *
  1078. ;*  RETS:   AX = 1 of successful, 0 otherwise.    BL = Error Code            *
  1079. ;*        DX = 16-bit handle to the allocated block                *
  1080. ;*  REGS:   AX, BX, DX and Flags clobbered                    *
  1081. ;*                                        *
  1082. ;*  INTERNALLY NON-REENTRANT                            *
  1083. ;*                                        *
  1084. ;*--------------------------------------------------------------------------*
  1085.  
  1086. ; Algorithm -
  1087. ;
  1088. ;   Scan the Handle Table looking for BOTH an unused handle and
  1089. ;    a free block which is large enough:
  1090. ;
  1091. ;   1.    If both are found -
  1092. ;        Mark the free block as used and adjust its size.
  1093. ;        Make the unused handle a free block containing the remaining
  1094. ;        unallocated portion of the original free block.
  1095. ;
  1096. ;   2.    If only an unused handle is found -
  1097. ;        We're out of memory.
  1098. ;
  1099. ;   3.    If only a properly sized free block is found -
  1100. ;        We only have one handle left.
  1101. ;        Mark the free block as used.  The requester gets all of the
  1102. ;        block's memory.
  1103. ;
  1104. ;   4.    If neither are found -
  1105. ;        We're out of memory.
  1106.  
  1107. hFreeBlock    dw  ?
  1108. hUnusedBlock    dw  ?
  1109.  
  1110. AllocExtMemory proc near
  1111.  
  1112.         cli             ; This is a non-reentrant function
  1113.         
  1114.         ; Scan the handle table looking for BOTH an unused handle and 
  1115.         ;    a free block which is large enough.
  1116.         xor        ax,ax
  1117.         mov        [hFreeBlock],ax
  1118.         mov        [hUnusedBlock],ax
  1119.         mov        bx,KiddValley
  1120.         mov     cx,[cHandles]    ; Loop through the handle table
  1121.  
  1122.         ; Have we already found a free block which is large enough?
  1123. AEMhLoop:   cmp     [hFreeBlock],0
  1124.         jne     short AEMUnused    ; Yes, see if this one is unused
  1125.         
  1126.         ; Is this block free?
  1127.         cmp     [bx.Flags],FREEFLAG
  1128.         jne     short AEMUnused    ; No, see if it is unused
  1129.         
  1130.         ; Is it large enough?
  1131.         cmp        dx,[bx.Len]
  1132.         ja        short AEMNexth    ; No, get the next handle
  1133.  
  1134.         ; Save this guy away.
  1135.         mov        [hFreeBlock],bx
  1136.         jmp        short AEMBottom
  1137.         
  1138. AEMUnused:  ; Have we already found an unused handle?
  1139.         cmp     [hUnusedBlock],0
  1140.         jne     short AEMNexth    ; Yes, get the next handle
  1141.  
  1142.         ; Is this block unused?
  1143.         cmp     [bx.Flags],UNUSEDFLAG
  1144.         jne     short AEMNexth    ; No, get the next handle
  1145.         
  1146.         ; Save this guy away.
  1147.         mov        [hUnusedBlock],bx
  1148.             
  1149.         ; Have we found what we are looking for?
  1150.         cmp        [hFreeBlock],0
  1151.         je        short AEMNexth
  1152. AEMBottom:  cmp        [hUnusedBlock],0
  1153.         jne     short AEMGotBoth    ; Yes, continue
  1154.         
  1155. AEMNexth:   ; Get the next handle
  1156.         add        bx,SIZE Handle
  1157.         loop    AEMhLoop
  1158.         
  1159.         ; We are at the end of the handle table and we didn't find both
  1160.         ; things we were looking for.  Did we find a free block?
  1161.         mov     si,[hFreeBlock]
  1162.         or        si,si
  1163.         jnz     short AEMRetSuc    ; Yes, Case 3 - Alloc the entire block
  1164.         
  1165.         ; Did we find an unused handle?
  1166.         cmp        [hUnusedBlock],0
  1167.         je        short AEMOOHandles    ; No, Case 4 - We're out of handles
  1168.         
  1169.         ; Case 2 - Is this a request for a zero-length handle?
  1170.         or        dx,dx
  1171.         jnz     short AEMOOMemory    ; No, we're out of memory
  1172.         
  1173.         ; Reserve the zero-length handle.
  1174.         mov        si,[hUnusedBlock]
  1175.         mov        [hFreeBlock],si
  1176.         jmp        short AEMRetSuc
  1177.         
  1178. AEMGotBoth: ; We're at Case 1 above.
  1179.         ;    Mark the free block as used (done below) and adjust its size.
  1180.         ;    Make the unused handle a free block containing the remaining
  1181.         ;       unallocated portion of the original free block.
  1182.         mov        si,[hFreeBlock]
  1183.         mov        di,[hUnusedBlock]
  1184.         
  1185.         ; Unused.Base = Old.Base + request
  1186.         mov        ax,[si].Base
  1187.         add        ax,dx
  1188.         mov        [di].Base,ax
  1189.         
  1190.         ; New.Len = request
  1191.         mov        ax,dx
  1192.         xchg    [si].Len,ax
  1193.         
  1194.         ; Unused.Len = Old.Len - request
  1195.         sub        ax,dx
  1196.         mov        [di].Len,ax
  1197.         mov        [di].Flags,FREEFLAG        ; Unused.Flags = FREE
  1198.         
  1199. AEMRetSuc:  ; Complete the allocation.
  1200.         mov        [si].Flags,USEDFLAG        ; New.Flags = USED
  1201.         mov        dx,[hFreeBlock]
  1202.         mov        ax,1
  1203.         xor        bl,bl
  1204.         ret
  1205.  
  1206. AEMOOMemory:mov        bl,ERR_OUTOMEMORY
  1207.         jmp        short AEMErrRet
  1208.         
  1209. AEMOOHandles:
  1210.         mov        bl,ERR_OUTOHANDLES
  1211. AEMErrRet:  xor        ax,ax            ; Return failure
  1212.         mov        dx,ax
  1213.         ret               
  1214.         
  1215. AllocExtMemory endp
  1216.  
  1217.  
  1218. ;*--------------------------------------------------------------------------*
  1219. ;*                                        *
  1220. ;*  ValidateHandle -                                *
  1221. ;*                                        *
  1222. ;*    Validates an extended memory block handle                *
  1223. ;*                                        *
  1224. ;*  ARGS:   DX = 16-bit handle to the extended memory block            *
  1225. ;*  RETS:   Carry is set if the handle is valid                    *
  1226. ;*  REGS:   Preserved except the carry flag                    *
  1227. ;*                                        *
  1228. ;*--------------------------------------------------------------------------*
  1229.  
  1230. ValidateHandle proc near
  1231.  
  1232.         pusha                ; Save everything
  1233.         mov        bx,dx            ; Move the handle into BX
  1234.  
  1235.         ; The handle must be equal to or above "KiddValley".
  1236.         cmp        bx,[KiddValley]
  1237.         jb        short VHOne
  1238.         
  1239.         ; The handle must not be above "KiddValleyTop".
  1240.         cmp        bx,[KiddValleyTop]
  1241.         ja        short VHOne
  1242.         
  1243.         ; (The handle-"KiddValley") must be a multiple of a handle's size.
  1244.         sub        dx,[KiddValley]
  1245.         mov        ax,dx
  1246.         xor        dx,dx
  1247.         mov        cx,SIZE Handle
  1248.         div        cx                
  1249.         or        dx,dx            ; Any remainder?        
  1250.         jnz     short VHOne         ; Yup, it's bad
  1251.  
  1252.         ; Does the handle point to a currently USED block?
  1253.         cmp        [bx.Flags],USEDFLAG
  1254.         jne     short VHOne         ; This handle is not being used.
  1255.         
  1256.         ; The handle looks good to me...
  1257.         popa                ; Restore everything
  1258.         stc                 ; Return success
  1259.         ret
  1260.  
  1261. VHOne:        ; It's really bad.
  1262.         popa                ; Restore everything
  1263.         clc                 ; Return failure
  1264.         ret
  1265.         
  1266. ValidateHandle endp
  1267.  
  1268.  
  1269. ;*--------------------------------------------------------------------------*
  1270. ;*                                        *
  1271. ;*  FreeExtMemory -                        FUNCTION 0Ah    *
  1272. ;*                                        *
  1273. ;*    Frees a block of extended memory which was allocated via AllocExt   *
  1274. ;*                                        *
  1275. ;*  ARGS:   DX = 16-bit handle to the extended memory block            *
  1276. ;*  RETS:   AX = 1 if successful, 0 otherwise.    BL = Error code            *
  1277. ;*  REGS:   AX, BX, CX, DX, SI, DI and Flags clobbered                *
  1278. ;*                                        *
  1279. ;*  INTERNALLY NON-REENTRANT                            *
  1280. ;*                                        *
  1281. ;*--------------------------------------------------------------------------*
  1282.  
  1283. FreeExtMemory proc near
  1284.  
  1285.         cli                 ; This is a non-reentrant function
  1286.         
  1287.         ; Make sure that the handle is valid.
  1288.         call    ValidateHandle
  1289.         jnc     short FEMBadh
  1290.         mov        si,dx            ; Move the handle into SI
  1291.         
  1292.         ; Make sure that the handle points to a FREE block.
  1293.         cmp        [si].cLock,0
  1294.         jne     short FEMLockedh
  1295.         
  1296.         ; Mark the block as FREE and cancel any locks.
  1297.         mov        [si].Flags,FREEFLAG
  1298.         mov        [si].cLock,0
  1299.         
  1300.         ; Is an adjacent block also free?
  1301. FEMScanIt:  mov        bx,[si].Base        ; BX = Bottom of block
  1302.         mov        ax,bx
  1303.         add        ax,[si].Len            ; AX = Top of block
  1304.         
  1305.         ; Search for an adjacent FREE block.
  1306.         mov        di,[KiddValley]        ; DI = Handle being scanned
  1307.         
  1308.         mov     cx,cHandles         ; Loop through the handle table
  1309. FEMLoopTop: cmp        [di].Flags,FREEFLAG        ; Is this block free?
  1310.         jne     short FEMNexth        ; No, continue
  1311.  
  1312.         ; Is this block just above the one we are freeing?
  1313.         mov        dx,[di].Base
  1314.         cmp     dx,ax
  1315.         je        short FEMBlockAbove     ; Yes, coaless upwards
  1316.  
  1317.         ; Is it just below?
  1318.         add        dx,[di].Len
  1319.         cmp     dx,bx
  1320.         je        short FEMBlockBelow     ; Yes, coaless downwards
  1321.         
  1322. FEMNexth:   add        di,SIZE Handle
  1323.         loop    FEMLoopTop
  1324.  
  1325.         ; No adjacent blocks to coaless.
  1326.         mov     ax,1            ; Return success
  1327.         xor        bl,bl
  1328.         ret
  1329.  
  1330.         ; Exchange the pointer to the "upper" and "lower" blocks.
  1331. FEMBlockBelow:
  1332.         xchg    si,di
  1333.  
  1334.         ; Move the free block above into the current handle.
  1335. FEMBlockAbove:
  1336.         mov        dx,[si].Len
  1337.         add     dx,[di].Len         ; Combine the lengths
  1338.         mov        [si].Len,dx
  1339.         mov     [di].Flags,UNUSEDFLAG   ; Mark old block's handle as UNUSED
  1340.         jmp        short FEMScanIt        ; Rescan the list
  1341.  
  1342. FEMBadh:    mov        bl,ERR_INVALIDHANDLE
  1343.         jmp        short FEMErrExit
  1344.         
  1345. FEMLockedh: mov        bl,ERR_EMBLOCKED
  1346. FEMErrExit: xor     ax,ax            ; Return failure
  1347.         ret
  1348.         
  1349. FreeExtMemory endp          
  1350.  
  1351.  
  1352. ;*--------------------------------------------------------------------------*
  1353. ;*                                        *
  1354. ;*  LockExtMemory -                        FUNCTION 0Ch    *
  1355. ;*                                        *
  1356. ;*    Locks a block of extended memory                    *
  1357. ;*                                        *
  1358. ;*  ARGS:   DX = 16-bit handle to the extended memory block            *
  1359. ;*  RETS:   AX = 1 of successful, 0 otherwise.    BL = Error code            *
  1360. ;*        DX:BX = 32-bit linear address of the base of the memory block   *
  1361. ;*  REGS:   AX, BX, DX and Flags clobbered                    *
  1362. ;*                                        *
  1363. ;*  INTERNALLY NON-REENTRANT                            *
  1364. ;*                                        *
  1365. ;*--------------------------------------------------------------------------*
  1366.  
  1367. LockExtMemory proc near
  1368.  
  1369.         cli                 ; This is a non-reentrant function
  1370.         
  1371.         ; Is the handle valid?
  1372.         call    ValidateHandle
  1373.         jnc     short LEMBadh
  1374.         mov     bx,dx            ; Move the handle into BX
  1375.  
  1376.         ; Are we at some preposterously large limit?
  1377.         cmp        [bx.cLock],0FFh
  1378.         je        short LEMOverflow
  1379.  
  1380.         ; Lock the block.
  1381.         inc        [bx.cLock]
  1382.         
  1383.         ; Return the 32-bit address of its base.
  1384.         mov        dx,[bx.Base]
  1385.         mov        bx,dx
  1386.         shr        dx,6
  1387.         shl        bx,10
  1388.  
  1389.         ; Return success.
  1390.         mov        ax,1
  1391.         ret
  1392.         
  1393. LEMBadh:    mov        bl,ERR_INVALIDHANDLE
  1394.         jmp        short LEMErrExit
  1395.  
  1396. LEMOverflow:mov        bl,ERR_LOCKOVERFLOW
  1397. LEMErrExit: xor     ax,ax            ; Return failure
  1398.         mov        dx,ax
  1399.         ret 
  1400.         
  1401. LockExtMemory endp
  1402.  
  1403.  
  1404. ;*--------------------------------------------------------------------------*
  1405. ;*                                        *
  1406. ;*  UnlockExtMemory -                        FUNCTION 0Dh    *
  1407. ;*                                        *
  1408. ;*    Unlocks a block of extended memory                    *
  1409. ;*                                        *
  1410. ;*  ARGS:   DX = 16-bit handle to the extended memory block            *
  1411. ;*  RETS:   AX = 1 if successful, 0 otherwise.    BL = Error code            *
  1412. ;*  REGS:   AX, BX and Flags clobbered                        *
  1413. ;*                                        *
  1414. ;*  INTERNALLY NON-REENTRANT                            *
  1415. ;*                                        *
  1416. ;*--------------------------------------------------------------------------*
  1417.  
  1418. UnlockExtMemory proc near
  1419.  
  1420.         cli                ; This is a non-reentrant function
  1421.     
  1422.         ; Is the handle valid?
  1423.         call    ValidateHandle
  1424.         jnc     short UEMBadh
  1425.         mov        bx,dx        ; Move the handle into BX
  1426.  
  1427.         ; Does the handle point to a locked block?
  1428.         cmp        [bx.cLock],0
  1429.         je        short UEMUnlocked    ; No, return error
  1430.  
  1431.         ; Unlock the block.
  1432.         dec        [bx.cLock]
  1433.  
  1434.         mov     ax,1        ; Return success
  1435.         xor     bl,bl
  1436.         ret
  1437.         
  1438. UEMUnlocked:mov        bl,ERR_EMBUNLOCKED
  1439.         jmp        short UEMErrExit
  1440.  
  1441. UEMBadh:    mov        bl,ERR_INVALIDHANDLE
  1442. UEMErrExit: xor        ax,ax
  1443.         ret           
  1444.  
  1445. UnlockExtMemory endp
  1446.  
  1447.  
  1448. ;*--------------------------------------------------------------------------*
  1449. ;*                                        *
  1450. ;*  GetExtMemoryInfo -                        FUNCTION 0Eh    *
  1451. ;*                                        *
  1452. ;*    Gets other information about an extended memory block            *
  1453. ;*                                        *
  1454. ;*  ARGS:   DX = 16-bit handle to the extended memory block            *
  1455. ;*  RETS:   AX = 1 if successful, 0 otherwise.    BL = Error code            *
  1456. ;*        BH = EMB's lock count                        *
  1457. ;*        BL = Total number of unused handles in the system            *
  1458. ;*        DX = EMB's length                            *
  1459. ;*  REGS:   AX, BX, CX, DX and Flags clobbered                    *
  1460. ;*                                        *
  1461. ;*  INTERNALLY NON-REENTRANT                            *
  1462. ;*                                        *
  1463. ;*--------------------------------------------------------------------------*
  1464.  
  1465. GetExtMemoryInfo proc    near
  1466.  
  1467.         cli                 ; This is a non-reentrant function
  1468.         
  1469.         ; Is the handle valid?
  1470.         call    ValidateHandle
  1471.         jnc     short GEMBadh
  1472.         mov     si,dx            ; Move the handle into SI
  1473.  
  1474.         ; Count the number of handles which are not currently being used.
  1475.         xor     al,al
  1476.         mov     bx,[KiddValley]
  1477.         mov     cx,[cHandles]        ; Loop through the handle table
  1478. GEMLoop:    cmp     [bx.Flags],USEDFLAG     ; Is this handle in use?
  1479.         je        short GEMNexth          ; Yes, continue
  1480.         inc     al                ; No, increment the count
  1481. GEMNexth:   add     bx,SIZE Handle
  1482.         loop    GEMLoop
  1483.  
  1484.         ; Setup the return.
  1485.         mov     dx,[si.Len]         ; Length in DX
  1486.         mov     bh,[si.cLock]        ; Lock count in BH
  1487.         mov     bl,al
  1488.         mov        ax,1
  1489.         ret
  1490.         
  1491. GEMBadh:    mov        bl,ERR_INVALIDHANDLE
  1492.         xor        ax,ax
  1493.         ret
  1494.  
  1495. GetExtMemoryInfo endp
  1496.         
  1497.  
  1498. ;*--------------------------------------------------------------------------*
  1499. ;*                                        *
  1500. ;*  ReallocExtMemory -                        FUNCTION 0Fh    *
  1501. ;*                                        *
  1502. ;*    Reallocates a block of extended memory                    *
  1503. ;*                                        *
  1504. ;*  ARGS:   DX = 16-bit handle to the extended memory block            *
  1505. ;*  RETS:   AX = 1 if successful, 0 otherwise.    BL = Error code            *
  1506. ;*  REGS:                                    *
  1507. ;*                                        *
  1508. ;*  INTERNALLY NON-REENTRANT                            *
  1509. ;*                                        *
  1510. ;*--------------------------------------------------------------------------*
  1511.  
  1512. ; FUNCTION NOT YET IMPLEMENTED
  1513.  
  1514.  
  1515. ;*--------------------------------------------------------------------------*
  1516. ;*                                        *
  1517. ;*  NOTE: RequestUMB and ReleaseUMB will not be implemented by HIMEM.        *
  1518. ;*                                        *
  1519. ;*--------------------------------------------------------------------------*
  1520.  
  1521.  
  1522. ;*--------------------------------------------------------------------------*
  1523. ;*                                        *
  1524. ;*  MoveExtMemory -                        FUNCTION 0Bh    *
  1525. ;*                                        *
  1526. ;*    Copys a block of memory from anywhere to anywhere            *
  1527. ;*                                        *
  1528. ;*  ARGS:   ES:SI = Pointer to an Extended Memory Block Move Structure        *
  1529. ;*        (NOTE: Originally passed in as DS:SI)                *
  1530. ;*  RETS:   AX = 1 of successful, 0 otherwise.    BL = Error code.        *
  1531. ;*  REGS:   Everybody clobbered                            *
  1532. ;*                                        *
  1533. ;*  INTERNALLY REENTRANT (believe it or not)                    *
  1534. ;*                                        *
  1535. ;*--------------------------------------------------------------------------*
  1536.  
  1537. EVEN                ; Must be word aligned.
  1538.  
  1539. MoveBlock:
  1540.  
  1541. MEM3_Data    label    byte    ; Start of MoveBlock data
  1542. MoveBlock286:
  1543.  
  1544. include xm286.asm
  1545.  
  1546. EndMoveBlock286:
  1547.  
  1548. ;*--------------------------------------------------------------------------*
  1549.  
  1550. MoveBlock386:
  1551.  
  1552. include xm386.asm
  1553.  
  1554. EndMoveBlock386:
  1555.  
  1556.  
  1557. ;****************************************************************************
  1558. ;*                                        *
  1559. ;* A20 Handler Section:                             *
  1560. ;*                                        *
  1561. ;* The Init code copies the proper A20 Handler in place just below the        *
  1562. ;*   proper MoveBlock routine.                            *
  1563. ;*                                        *
  1564. ;* NOTE: A20 HANDLERS MUST ONLY HAVE RELATIVE JUMPS!  HOWEVER ANY CALLS TO  *
  1565. ;*     FUNCTIONS OUTSIDE OF THE HANDLER MUST BE NON-RELATIVE!     The best   *
  1566. ;*     method is to call thru a variable such as ControlJumpTable[n].        *
  1567. ;*                                        *
  1568. ;****************************************************************************
  1569.  
  1570. ;*--------------------------------------------------------------------------*
  1571. ;*                                        *
  1572. ;*  AT_A20Handler -                        HARDWARE DEP.   *
  1573. ;*                                        *
  1574. ;*    Enable/Disable the A20 line on non-PS/2 machines            *
  1575. ;*                                        *
  1576. ;*  ARGS:   AX = 0 for Disable, 1 for Enable                    *
  1577. ;*  RETS:   AX = 1 for success, 0 otherwise                    *
  1578. ;*  REGS:   AX, CX and Flags clobbered                        *
  1579. ;*                                        *
  1580. ;*--------------------------------------------------------------------------*
  1581.  
  1582. AT_A20Handler proc   near
  1583.  
  1584.         or        ax,ax
  1585.         jz        short AAHDisable
  1586.  
  1587. AAHEnable:  call    Sync8042    ; Make sure the Keyboard Controller is Ready
  1588.         jnz     short AAHErr
  1589.  
  1590.         mov        al,0D1h    ; Send D1h
  1591.         out        64h,al
  1592.         call    Sync8042
  1593.         jnz     short AAHErr
  1594.  
  1595.         mov        al,0DFh    ; Send DFh
  1596.         out        60h,al
  1597.         call    Sync8042
  1598.         jnz     short AAHErr
  1599.  
  1600.         ; Wait for the A20 line to settle down (up to 20usecs)
  1601.         mov        al,0FFh    ; Send FFh (Pulse Output Port NULL)
  1602.         out        64h,al
  1603.         call    Sync8042
  1604.         jnz     short AAHErr
  1605.         jmp        short AAHExit
  1606.  
  1607. AAHDisable: call    Sync8042    ; Make sure the Keyboard Controller is Ready
  1608.         jnz     short AAHErr
  1609.  
  1610.         mov        al,0D1h    ; Send D1h
  1611.         out        64h,al
  1612.         call    Sync8042
  1613.         jnz     short AAHErr
  1614.  
  1615.         mov        al,0DDh    ; Send DDh
  1616.         out        60h,al
  1617.         call    Sync8042
  1618.         jnz     short AAHErr
  1619.  
  1620.         ; Wait for the A20 line to settle down (up to 20usecs)
  1621.         mov        al,0FFh    ; Send FFh (Pulse Output Port NULL)
  1622.         out        64h,al
  1623.         call    Sync8042
  1624.         
  1625. AAHExit:    mov        ax,1
  1626.         ret
  1627.         
  1628. AAHErr:        xor        ax,ax
  1629.         ret
  1630.         
  1631. AT_A20Handler endp
  1632.  
  1633.  
  1634. ;*--------------------------------------------------------------------------*
  1635.  
  1636. Sync8042    proc    near
  1637.  
  1638.         xor        cx,cx
  1639. S8InSync:   in        al,64h
  1640.         and        al,2
  1641.         loopnz  S8InSync
  1642.         ret
  1643.  
  1644. Sync8042    endp
  1645.  
  1646. EndAT_A20Handler:
  1647.  
  1648.  
  1649. ;*--------------------------------------------------------------------------*
  1650. ;*                                        *
  1651. ;*  PS2_A20Handler -                        HARDWARE DEP.   *
  1652. ;*                                        *
  1653. ;*    Enable/Disable the A20 line on PS/2 machines                *
  1654. ;*                                        *
  1655. ;*  ARGS:   AX = 0 for Disable, 1 for Enable                    *
  1656. ;*  RETS:   AX = 1 for success, 0 otherwise                    *
  1657. ;*  REGS:   AX, CX and Flags clobbered                        *
  1658. ;*                                        *
  1659. ;*--------------------------------------------------------------------------*
  1660.  
  1661. PS2_PORTA   equ        0092h
  1662. PS2_A20BIT  equ        00000010b
  1663.  
  1664. PS2_A20Handler proc   near
  1665.  
  1666.         or        ax,ax
  1667.         jz        short PAHDisable
  1668.  
  1669. PAHEnable:  in        al,PS2_PORTA    ; Get the current A20 state
  1670.         test    al,PS2_A20BIT   ; Is A20 already on?
  1671.         jnz     short PAHErr
  1672.  
  1673.         or        al,PS2_A20BIT   ; Turn on the A20 line
  1674.         out        PS2_PORTA,al
  1675.  
  1676.         xor        cx,cx        ; Make sure we loop for awhile
  1677. PAHIsItOn:  in        al,PS2_PORTA    ; Loop until the A20 line comes on
  1678.         test    al,PS2_A20BIT
  1679.         loopz   PAHIsItOn
  1680.         jz        short PAHErr    ; Unable to turn on the A20 line
  1681.         jmp        short PAHExit
  1682.  
  1683. PAHDisable: in        al,PS2_PORTA    ; Get the current A20 state
  1684.         and        al,NOT PS2_A20BIT    ; Turn off the A20 line
  1685.         out        PS2_PORTA,al
  1686.  
  1687.         xor        cx,cx        ; Make sure we loop for awhile
  1688. PAHIsItOff: in        al,PS2_PORTA    ; Loop until the A20 line goes off
  1689.         test    al,PS2_A20BIT
  1690.         loopnz  PAHIsItOff
  1691.         jnz     short PAHErr    ; Unable to turn off the A20 line
  1692.  
  1693. PAHExit:    mov        ax,1
  1694.         ret
  1695.         
  1696. PAHErr:        xor        ax,ax
  1697.         ret           
  1698.  
  1699. PS2_A20Handler endp
  1700.  
  1701. EndPS2_A20Handler:
  1702.  
  1703.  
  1704. ;*--------------------------------------------------------------------------*
  1705. ;*                                        *
  1706. ;*  $6300Plus_A20Handler -                    HARDWARE DEP.   *
  1707. ;*                                        *
  1708. ;*     Enable/Disable address lines A20-A23 on AT&T 6300 Plus            *
  1709. ;*                                        *
  1710. ;*  ARGS:   AX = 0 for Disable, 1 for Enable                    *
  1711. ;*  RETS:   AX = 1 for success, 0 otherwise                    *
  1712. ;*  REGS:   AX, BX, and Flags clobbered                        *
  1713. ;*                                        *
  1714. ;*  Note:   Don't want to do two back to back disables on PLUS,            *
  1715. ;*        so we call IsA20On to see if it is necessary.            *
  1716. ;*  Warning:  The calcuation of the ReturnBack label depends on the        *
  1717. ;*          expectation that this routine is being moved at init time.    *
  1718. ;*                                        *
  1719. ;*--------------------------------------------------------------------------*
  1720.  
  1721. PLUS_PORT   equ        03F20h
  1722. PLUS_SET    equ        90h
  1723. PLUS_RESET  equ        0
  1724.  
  1725. $6300PLUS_A20Handler proc   near
  1726.  
  1727.         push    ax                ; Save entry
  1728.         call    word ptr ControlJumpTable[7*2] ; Call IsA20On()
  1729.         pop        bx
  1730.         cmp        ax,bx
  1731.         jne     short $6AHEnable
  1732.         mov        ax,1
  1733.         ret                    ; No, just return
  1734.  
  1735. $6AHEnable: mov        al,PLUS_SET
  1736.         or        bx,bx            ; Zero if disable
  1737.         jnz     short $6AHNext
  1738.         mov        al,PLUS_RESET
  1739.         call    $6300Reset            ; Reset the processor
  1740.  
  1741. $6AHNext:   mov        dx,PLUS_PORT        ; Set/reset the port
  1742.         out        dx,al
  1743.         mov        ax,1            ; Return success
  1744.         ret
  1745.  
  1746. $6300Plus_A20Handler endp
  1747.  
  1748.  
  1749. ;*--------------------------------------------------------------------------*
  1750. ;*                                        *
  1751. ;* $6300Reset -                           HARDWARE DEP.    *
  1752. ;*                                        *
  1753. ;* Reset the 80286 in order to turn off the address lines on the 6300 PLUS. *
  1754. ;* This is the only way to do this on the current hardware.            *
  1755. ;* The processor itself is reset by reading or writing port 03F00h.        *
  1756. ;*                                        *
  1757. ;*  Uses flags.                                    *
  1758. ;*                                        *
  1759. ;*--------------------------------------------------------------------------*
  1760.  
  1761. $6300Reset  proc    near
  1762.  
  1763.         pusha                ; Save world
  1764.         push    ds                ; Save segments
  1765.         push    es
  1766.         mov        ax,BiosSeg            ; Point to the BIOS segment
  1767.         mov        ds,ax            ; ds -> 40h
  1768.  
  1769.         ; Setup the reset return address.
  1770. assume ds:nothing
  1771.         push    word ptr ds:[RealLoc1]  ; Save what might have been here
  1772.         push    word ptr ds:[RealLoc1+2]
  1773.  
  1774.         ; Load our return address, remembering that we will be relocated
  1775.         ;    at init time.
  1776.         mov        word ptr ds:[RealLoc1+2],cs
  1777.         mov        word ptr ds:[RealLoc1],offset ReturnBack-offset $6300Plus_A20Handler+offset A20Handler
  1778.  
  1779.         mov        cs:[OldStackSeg],ss        ; Save the stack segment, too
  1780.  
  1781.         ; Reset the processor - turning off A20 in the process.
  1782.         mov        dx,03F00h
  1783.         in        ax,dx
  1784.  
  1785.         ; We shouldn't get here.  Halt the machine if we do.
  1786.         nop
  1787.         nop
  1788.         nop
  1789.         nop
  1790.         cli
  1791.         hlt
  1792.  
  1793. ReturnBack: mov        ss,cs:[OldStackSeg]        ; Start the recovery
  1794.         pop        word ptr ds:[RealLoc1+2]    ; ROM code has set ds->40h
  1795.         pop        word ptr ds:[RealLoc1]
  1796.         pop        es
  1797.         pop        ds
  1798.  
  1799. assume ds:code
  1800.         popa
  1801.         ret
  1802.  
  1803. $6300Reset endp
  1804.  
  1805. End6300Plus_Handler:
  1806.  
  1807.  
  1808. ;*--------------------------------------------------------------------------*
  1809. ;*                                        *
  1810. ;*  HP_A20Handler -                        HARDWARE DEP.   *
  1811. ;*                                        *
  1812. ;*    Enable/Disable the A20 line on HP Vectra machines            *
  1813. ;*                                        *
  1814. ;*  ARGS:   AX = 0 for Disable, 1 for Enable                    *
  1815. ;*  RETS:   AX = 1 for success, 0 otherwise                    *
  1816. ;*  REGS:   AX, CX and Flags clobbered                        *
  1817. ;*                                        *
  1818. ;*--------------------------------------------------------------------------*
  1819.  
  1820. HP_A20Handler proc   near
  1821.  
  1822.         or        ax,ax
  1823.         jz        short HAHDisable
  1824.  
  1825. HAHEnable:  call    HPSync8042    ; Make sure the Keyboard Controller is ready
  1826.         jnz     short HAHErr
  1827.  
  1828.         mov        al,0DFh    ; Send DFh
  1829.         out        64h,al
  1830.         call    HPSync8042
  1831.         jnz     short HAHErr
  1832.  
  1833.         mov        al,0DFh    ; Send second DFh
  1834.         out        64h,al
  1835.         call    HPSync8042
  1836.         jnz     short HAHErr
  1837.         jmp        short HAHExit
  1838.  
  1839. HAHDisable: call    HPSync8042      ; Make sure the Keyboard Controller is Ready
  1840.         jnz     short HAHErr
  1841.  
  1842.         mov        al,0DDh    ; Send DDh
  1843.         out        64h,al
  1844.         call    HPSync8042
  1845.         jnz     short HAHErr
  1846.  
  1847.         mov        al,0DDh    ; Send second DDh
  1848.         out        64h,al
  1849.         call    HPSync8042
  1850.         jnz     short HAHErr
  1851.  
  1852. HAHExit:    mov        ax,1
  1853.         ret
  1854.  
  1855. HAHErr:        xor        ax,ax
  1856.         ret
  1857.         
  1858. HP_A20Handler endp
  1859.  
  1860.  
  1861. ;*--------------------------------------------------------------------------*
  1862.  
  1863. HPSync8042  proc    near
  1864.  
  1865.         xor        cx,cx
  1866. H8InSync:   in        al,64h
  1867.         and        al,2
  1868.         loopnz  H8InSync
  1869.         ret
  1870.  
  1871. HPSync8042  endp
  1872.  
  1873. EndHP_A20Handler:
  1874.  
  1875.  
  1876. ;*--------------------------------------------------------------------------*
  1877. ;*                                        *
  1878. ;*  Extended Memory Handle Table -                        *
  1879. ;*                                        *
  1880. ;*--------------------------------------------------------------------------*
  1881.  
  1882. ; Actually, the handle table will be located just after the end of whichever
  1883. ; A20 Handler is installed and will overwrite the others.  In large cases
  1884. ; however, it could extend beyond all of these guys and crunch the Init code.
  1885. ; Hence this buffer.  If the driver ever gets over 64K (heaven forbid) this
  1886. ; scheme should be reworked.
  1887.  
  1888. ; Guarantee space for all handles.  Kinda overkill but any extra will be 
  1889. ; discarded with the Init code.
  1890.  
  1891. HandleFiller        dw        MAXHANDLES * SIZE Handle DUP(?)
  1892.  
  1893.  
  1894. ;****************************************************************************
  1895. ;*                                        *
  1896. ;*  NOTE: Code below here will be discarded after driver initialization.    *
  1897. ;*                                        *
  1898. ;****************************************************************************
  1899.  
  1900. ;*--------------------------------------------------------------------------*
  1901. ;*                                        *
  1902. ;*  InitDriver -                                *
  1903. ;*                                        *
  1904. ;*    Called when driver is Initialized.                    *
  1905. ;*                                        *
  1906. ;*  ARGS:   ES:DI = Address of the Request Header                *
  1907. ;*  RETS:   AX = 0, pHdr.Address = Bottom of resident driver code        *
  1908. ;*  REGS:   AX, CX and Flags are clobbered                    *
  1909. ;*                                        *
  1910. ;*--------------------------------------------------------------------------*
  1911.  
  1912. InitLine    dw        MoveBlock        ; The line which defines what will be dis-
  1913.                     ;    carded after the driver is initialized
  1914. InitDriver  proc    near
  1915.  
  1916.         ; Display the sign on message.
  1917.         mov        ah,9h
  1918.         mov        dx,offset SignOnMsg
  1919.         int        21h
  1920.  
  1921.         ; Is this DOS 3.00 or higher?
  1922.         mov        ah,30h
  1923.         int        21h            ; Get DOS versions number
  1924.         cmp        al,3
  1925.         jae     short IDCheckXMS
  1926.         
  1927.         mov        dx,offset BadDOSMsg
  1928.         jmp     short IDFlushMe2
  1929.             
  1930.         ; Is another XMS driver already installed?
  1931. IDCheckXMS: mov     ax,4300h
  1932.         int        2Fh
  1933.         cmp        al,80h        ; Is INT 2F hooked?
  1934.         jne     short IDNotInYet
  1935.         mov        dx,offset NowInMsg
  1936.         jmp     short IDFlushMe2
  1937.  
  1938.         ; What kind of processor are we on?
  1939. IDNotInYet: call    MachineCheck
  1940.         cmp        ax,1        ; Is it an 8086/8088?
  1941.         jne     short IDProcOK
  1942.         mov        dx,offset On8086Msg
  1943.         jmp     short IDFlushMe
  1944.  
  1945.         ; Is there any Compaq BIM?
  1946. IDProcOK:
  1947.         call    GetBIMMemory
  1948.         or        ax,ax
  1949.         jz        short IDNoBIM
  1950.  
  1951.         ; How much extended memory is installed?
  1952.         call    GetInt15Memory
  1953.         cmp     ax,64        ; Is there >= 64K of extended?
  1954.         jb        short IDNoHMA    ; Nope - No HMA
  1955.         jmp     short IDHMAOK    ; Yup - continue
  1956.  
  1957.         ; How much extended memory is installed?
  1958. IDNoBIM:    call    GetInt15Memory
  1959.         cmp     ax,64        ; Is there >= 64K of extended?
  1960.         jae     short IDHMAOK    ; Yup - continue
  1961.  
  1962.         or        ax,ax        ; Is there any extended?
  1963.         jnz     short IDNoHMA    ; Yup - No HMA
  1964.  
  1965.         ; We can't find any memory to manage.
  1966.         mov        dx,offset NoExtMemMsg
  1967. IDFlushMe2: jmp     short IDFlushMe
  1968.         
  1969.         ; There isn't enough for the HMA, but there is some extended
  1970.         ; memory which we can manage.
  1971. IDNoHMA:    mov     dx,offset NoHMAMsg
  1972.         mov        ah,9h
  1973.         int        21h
  1974.         jmp     short IDFinalInit
  1975.  
  1976. IDHMAOK:    mov     [fHMAMayExist],1
  1977.  
  1978.         ; Install the proper MoveBlock function.
  1979. IDFinalInit:call    InstallMoveBlock
  1980.  
  1981.         ; Install the proper A20 handler.
  1982.         call    InstallA20
  1983.         
  1984.         ; Was A20 on already?
  1985.         call    IsA20On
  1986.         xor        ax,1
  1987.         mov        [fCanChangeA20],al    ; Yes, don't ever disable it
  1988.         cmp     al,0
  1989.         jne     short IDDiddler
  1990.         
  1991.         ; Display the "A20 Already On" message.
  1992.         mov        dx,offset A20OnMsg
  1993.         mov     ah,9h        ; CHANGED - 8/9/88
  1994.         int        21h
  1995.         
  1996.         ; Can we successfully diddle A20?    CHANGED - 8/9/88
  1997. IDDiddler:  call    LocalEnableA20    ; Try to enable A20
  1998.         or        ax,ax        ; Did we do it?
  1999.         jz        short IDBadA20    ; Nope - phoosh ourselves
  2000.  
  2001.         call    IsA20On        ; Is A20 on?
  2002.         or        ax,ax
  2003.         jz        short IDBadA20    ; Nope - phoosh ourselves
  2004.  
  2005.         call    LocalDisableA20    ; Try to disable A20
  2006.         or        ax,ax        ; Did we do it?
  2007.         jnz     short IDA20Cont    ; Yup - continue
  2008.  
  2009.         cmp     [fCanChangeA20],1    ; Has A20 been permenantly enabled?
  2010.         je        short IDGetParms    ; Yup - continue
  2011.         jmp     short IDBadA20    ; Nope - phoosh ourselves
  2012.         
  2013. IDA20Cont:  call    IsA20On        ; Is A20 off?
  2014.         or        ax,ax
  2015.         jz        short IDGetParms    ; Yup - continue
  2016.  
  2017.         ; A20 ain't doing it.
  2018. IDBadA20:   mov        dx,offset BadA20Msg
  2019.  
  2020.         ; Display the message in DX followed by the "Flush" message.
  2021. IDFlushMe:  mov        ah,9h
  2022.         int        21h
  2023.         mov        dx,offset FlushMsg
  2024.         mov        ah,9h
  2025.         int        21h
  2026.         
  2027.         ; Discard the entire driver.
  2028.         xor        ax,ax
  2029.         mov        [InitLine],ax
  2030.         les        di,[pReqHdr]
  2031.         mov        es:[di.Units],al
  2032.         jmp        short IDReturn
  2033.         
  2034.         ; Process the command line parameters.
  2035. IDGetParms: call    GetParms
  2036.         
  2037.         ; Initialize the Handle Table.
  2038.         call    InitHandles
  2039.  
  2040.         ; Display the success messages.
  2041.         cmp        [fHMAMayExist],0
  2042.         je        short IDIgnition
  2043.         mov        dx,offset HMAOKMsg
  2044.         mov        ah,9h
  2045.         int        21h
  2046.  
  2047.         ; "Turn On" the driver.
  2048. IDIgnition: call    HookInt2F
  2049.  
  2050.         ; Discard the initialization code.
  2051. IDReturn:   les        di,[pReqHdr]
  2052.         mov        ax,[InitLine]
  2053.         mov        word ptr es:[di.Address][0],ax
  2054.         mov        word ptr es:[di.Address][2],cs
  2055.  
  2056.         ; Return success.
  2057.         xor        ax,ax
  2058.         ret
  2059.  
  2060. InitDriver  endp
  2061.  
  2062.         
  2063. ;*--------------------------------------------------------------------------*
  2064. ;*                                        *
  2065. ;*  HookInt2F -                                    *
  2066. ;*                                        *
  2067. ;*    Insert the INT 2F hook                            *
  2068. ;*                                        *
  2069. ;*  ARGS:   None                                *
  2070. ;*  RETS:   None                                *
  2071. ;*  REGS:   AX, SI, ES and Flags are clobbered                    *
  2072. ;*                                        *
  2073. ;*  EXTERNALLY NON-REENTRANT                            *
  2074. ;*    Interrupts must be disabled before calling this function.        *
  2075. ;*                                        *
  2076. ;*--------------------------------------------------------------------------*
  2077.  
  2078. HookInt2F   proc    near
  2079.  
  2080.         ; Save the current INT 2F vector
  2081.         cli
  2082.         xor        ax,ax
  2083.         mov        es,ax
  2084.         mov        si,2Fh * 4            ; ES:SI = Address of 2F vector
  2085.  
  2086.         ; Exchange the old vector with the new one
  2087.         mov        ax,offset Int2FHandler
  2088.         xchg    ax,es:[si][0]
  2089.         mov        word ptr [PrevInt2F][0],ax
  2090.         mov        ax,cs
  2091.         xchg    ax,es:[si][2]
  2092.         mov        word ptr [PrevInt2F][2],ax
  2093.         sti
  2094.         ret
  2095.  
  2096. HookInt2F   endp
  2097.  
  2098.  
  2099. ;*--------------------------------------------------------------------------*
  2100. ;*                                        *
  2101. ;*  MachineCheck -                                *
  2102. ;*                                        *
  2103. ;*    Determines the CPU type.                        *
  2104. ;*                                        *
  2105. ;*  ARGS:   None                                *
  2106. ;*  RETS:   AX = 1 if we're on an 8086/8088 or an 80186, 0 otherwise        *
  2107. ;*  REGS:   AX and Flags are clobbered                        *
  2108. ;*                                        *
  2109. ;*--------------------------------------------------------------------------*
  2110.  
  2111. ; NOTE: This is the "official" Intel method for determining CPU type.
  2112.  
  2113. MachineCheck proc   near
  2114.  
  2115.         xor     ax,ax        ; Move 0 into the Flags register
  2116.         push    ax
  2117.         popf
  2118.         pushf            ; Try and get it back out
  2119.         pop     ax
  2120.         and     ax,0F000h        ; If the top four bits are set...
  2121.         cmp     ax,0F000h
  2122.         je        short MC_8086    ; ...it's an 8086 machine
  2123.  
  2124.         mov     ax,0F000h        ; Move F000h into the Flags register
  2125.         push    ax
  2126.         popf
  2127.         pushf            ; Try and get it back out
  2128.         pop     ax
  2129.         and     ax,0F000h        ; If the top four bits aren't set...
  2130.         jz        short MC_80286    ; ...it's an 80286 machine
  2131.  
  2132.         ; We're on an 80386 machine
  2133.         mov     ax,3
  2134.         ret
  2135.  
  2136. MC_80286:   ; We're on an 80286 machine
  2137.         mov     ax,2
  2138.         ret
  2139.  
  2140. MC_8086:    ; We're on an 8086 machine
  2141.         mov     ax,1
  2142.         ret
  2143.         
  2144. MachineCheck endp
  2145.  
  2146.         
  2147. ;*--------------------------------------------------------------------------*
  2148. ;*                                        *
  2149. ;*  GetBIMMemory -                                *
  2150. ;*                                        *
  2151. ;*    Look for Compaq 'Built In Memory' and add it to the pool of        *
  2152. ;*  available memory                                *
  2153. ;*                                        *
  2154. ;*  ARGS:   None                                *
  2155. ;*  RETS:   AX = Amount of BIM memory found                    *
  2156. ;*  REGS:   AX, BX, CX, and Flags are clobbered                    *
  2157. ;*                                        *
  2158. ;*--------------------------------------------------------------------------*
  2159.  
  2160. ; "Built In Memory" (BIM) starts at FE00:0000h and grows downward.  It is
  2161. ; controlled by a data structure at F000:FFE0h.  Changing the data structure
  2162. ; involves un-write-protecting the ROMs (!) by flipping bit 1 of 80C00000.
  2163.  
  2164. pBIMSTRUCT  equ     0FFE0h
  2165. AVAILABLE   equ     0        ; Set to -1 if BIM isn't around
  2166. TOTALBIM    equ     2        ; Total amount of BIM in the system
  2167. AVAILBIM    equ     4        ; Amount of BIM available in paragraphs
  2168. LASTUSED    equ     6        ; Paragraph address of last (lowest) used
  2169.                 ;  paragraph of BIM
  2170.  
  2171. pCOMPAQ     label   dword
  2172.         dw        0FFE8h
  2173.         dw        0F000h
  2174.         
  2175. szCOMPAQ    db        '03COMPAQ'
  2176.  
  2177. pRAMRELOC   label   dword
  2178.         dw        00000h
  2179.         dw        080C0h
  2180.  
  2181. GDT_TYPE    struc
  2182.         dw        0,0,0,0
  2183.         dw        0,0,0,0
  2184.  
  2185. S_LIMIT     dw        1
  2186. S_BASE_LOW  dw        0
  2187. S_BASE_HI   db        0
  2188. S_RIGHTS    db        93h
  2189. S_RESERVED  dw        0
  2190.  
  2191. D_LIMIT     dw        1
  2192. D_BASE_LOW  dw        0000h
  2193. D_BASE_HI   db        0C0h
  2194. D_RIGHTS    db        93h
  2195. D_RES386    db        0
  2196. D_BASE_XHI  db        080h
  2197.  
  2198.         dw        0,0,0,0
  2199.         dw        0,0,0,0
  2200. GDT_TYPE    ends
  2201.  
  2202. BIMGDT        GDT_TYPE <>
  2203.  
  2204. BIMBuffer   dw        ?
  2205.  
  2206.  
  2207. GetBIMMemory proc near
  2208.  
  2209.         xor     ax,ax
  2210.  
  2211.         ; Are we on a Compaq 386 machine?
  2212.         push    es
  2213.  
  2214.         ; Set up the comparison.
  2215.         les     di,cs:pCOMPAQ
  2216.         mov     si,offset szCOMPAQ
  2217.         mov     cx,8
  2218.         cld
  2219.         rep     cmpsb            ; Do the comparison
  2220.  
  2221.         jne     short FCMNoMem2        ; Nope, return
  2222.  
  2223.         ; Is there a 32-bit memory board installed?
  2224.         mov     bx,pBIMSTRUCT
  2225.         mov     bx,es:[bx]            ; De-reference the pointer
  2226.         mov     dx,es:[bx+AVAILABLE]    ; -1 means no board is installed
  2227.         inc     dx
  2228.         jz        short FCMNoMem2        ; Nope, return
  2229.  
  2230.         ; How much memory is available and where does it start?
  2231.         mov     dx,es:[bx+AVAILBIM]     ; Size in paragraphs
  2232.         or        dx,dx            ; Any left?
  2233.         jz        short FCMNoMem
  2234.         mov     cx,dx            ; CX = Size in paragraphs
  2235.         mov     ax,es:[bx+LASTUSED]
  2236.         sub     ax,cx            ; AX = Starting location - F0000h
  2237.                         ;         in paragraphs
  2238.         push    es                ; Save for a rainy day...
  2239.         push    bx
  2240.         push    ax
  2241.  
  2242.         ; Change AX to the starting location in K.
  2243.         shr     ax,4
  2244.         add     ax,0F000h
  2245.         shr     ax,2
  2246.  
  2247.         ; Change CX to the size in K.
  2248.         shr     cx,6
  2249.  
  2250.         ; Store away for use by HookInt15().
  2251.         mov     [BIMBase],ax
  2252.         mov     [BIMLength],cx
  2253.  
  2254.         ; Un-WriteProtect the ROMs.
  2255.         mov     si,offset BIMGDT            ; Set up the BlockMove GDT
  2256.         mov     ax,cs
  2257.         mov     es,ax
  2258.         mov     cx,16
  2259.         mul     cx
  2260.         add     ax,offset BIMBuffer
  2261.         adc     dl,0
  2262.         mov     [si.S_BASE_LOW],ax
  2263.         mov     [si.S_BASE_HI],dl
  2264.         mov     cx,1
  2265.  
  2266.         mov     word ptr [BIMBuffer],0FEFEh     ; FEh unlocks the ROMs
  2267.  
  2268.         mov     ah,87h                ; Do the BlockMove
  2269.         int     15h
  2270.         or        ah,ah                ; Was there an error?
  2271.         jz        short FCMReserve            ; Nope - continue
  2272.  
  2273.         ; Return error.
  2274.         pop     ax                    ; Clean up
  2275.         pop     bx
  2276.         pop     es
  2277.         xor     ax,ax
  2278.         mov     [BIMBase],ax
  2279.         mov     [BIMLength],ax
  2280. FCMNoMem2:  jmp     short FCMNoMem
  2281.  
  2282.         ; Change the ROM values to reserve the BIM stuff.
  2283. FCMReserve: pop     ax
  2284.         pop     bx
  2285.         pop     es
  2286.         mov     word ptr es:[bx+AVAILBIM],0      ; Reserve all remaining BIM
  2287.         mov     word ptr es:[bx+LASTUSED],ax
  2288.  
  2289.         ; Re-WriteProtect the ROMs.
  2290.         push    cs
  2291.         pop     es
  2292.         mov     si,offset BIMGDT            ; Set up the BlockMove GDT
  2293.  
  2294.         mov     word ptr [BIMBuffer],0FCFCh     ; FCh unlocks the ROMs
  2295.  
  2296.         mov     ah,87h                ; Do the BlockMove
  2297.         int     15h
  2298.  
  2299.         mov     ax,1                ; Return success
  2300.  
  2301. FCMNoMem:   pop     es
  2302.         ret
  2303.  
  2304. GetBIMMemory endp
  2305.  
  2306.  
  2307. ;*--------------------------------------------------------------------------*
  2308. ;*                                        *
  2309. ;*  GetInt15Memory -                                *
  2310. ;*                                        *
  2311. ;*    Returns the amount of memory INT 15h, Function 88h says is free        *
  2312. ;*                                        *
  2313. ;*  ARGS:   None                                *
  2314. ;*  RETS:   AX = Amount of free extended memory in K-bytes            *
  2315. ;*  REGS:   AX and Flags are clobbered                        *
  2316. ;*                                        *
  2317. ;*--------------------------------------------------------------------------*
  2318.         
  2319. GetInt15Memory proc near
  2320.  
  2321.         ; Check for 6300 Plus (to set "MemCorr").
  2322.         call    Is6300Plus
  2323.  
  2324.         ; Get the amount of extended memory Int 15h says is around.
  2325.         mov        ah,88h
  2326.         clc
  2327.         int        15h            ; Is Function 88h around?
  2328.         jnc     short GIM100
  2329.         xor        ax,ax        ; No, return 0
  2330.         ret
  2331.         
  2332. GIM100:        sub        ax,[MemCorr]    ; Compensate for 6300 Plus machines
  2333.         ret
  2334.  
  2335. GetInt15Memory endp               
  2336.         
  2337.         
  2338. ;*--------------------------------------------------------------------------*
  2339. ;*                                        *
  2340. ;*  InstallMoveBlock -                        HARDWARE DEP.   *
  2341. ;*                                        *
  2342. ;*    Attempt to install the proper MoveBlock function.            *
  2343. ;*                                        *
  2344. ;*  ARGS:   None                                *
  2345. ;*  RETS:   None                                *
  2346. ;*  REGS:   AX, CX, DI, SI, ES and Flags are clobbered                *
  2347. ;*                                        *
  2348. ;*--------------------------------------------------------------------------*
  2349.  
  2350. InstallMoveBlock proc near
  2351.  
  2352.         ; Are we on a 386 machine?
  2353.         call    MachineCheck
  2354.         cmp     ax,3
  2355.         je        short IMBOn386        ; Yes, install the 386 routine
  2356.  
  2357.         ; Install the 286 MoveBlock routine.
  2358.         mov     [InitLine],offset EndMoveBlock286
  2359.         ret
  2360.  
  2361.         ; Install the 386 MoveBlock routine.
  2362. IMBOn386:   mov     si,offset MoveBlock386
  2363.         mov     cx,(offset EndMoveBlock386 - offset MoveBlock386)
  2364.  
  2365.         ; REP MOV the routine into position.
  2366.         cld
  2367.         push    cs
  2368.         pop        es
  2369.         mov     di,offset MoveBlock
  2370.         add     [InitLine],cx
  2371.         rep movsb
  2372.         call    InitMoveBlock386
  2373.         ret
  2374.  
  2375. InstallMoveBlock endp
  2376.  
  2377.  
  2378. ;*--------------------------------------------------------------------------*
  2379. ;*                                        *
  2380. ;*  InitMoveBlock386 -                        HARDWARE DEP.   *
  2381. ;*                                        *
  2382. ;*    Initializes the 386 MoveBlock routine                    *
  2383. ;*                                        *
  2384. ;*  ARGS:   None                                *
  2385. ;*  RETS:   None                                *
  2386. ;*  REGS:   AX, CX, DX and Flags are clobbered                    *
  2387. ;*                                        *
  2388. ;*--------------------------------------------------------------------------*
  2389.  
  2390. InitMoveBlock386 proc near
  2391.  
  2392.         mov     ax,cs            ; dx has CS of codeg
  2393.         mov     [patch3],ax         ; Patch code
  2394.         mov     cx,16
  2395.         mul     cx
  2396.         mov     [descCS].LO_apDesc386,ax    ; Set up selector for our CS
  2397.         mov     [descCS].MID_apDesc386,dl
  2398.         add     ax,offset code:OurGDT    ; Calculate Base of GDT
  2399.         adc     dx,0
  2400.         mov     [GDTPtr.LO_apBaseGdt],ax
  2401.         mov     [GDTPtr.HI_apBaseGdt],dx
  2402.         mov     ax,offset code:MoveExtended386+MEM3_Offset
  2403.         mov     ControlJumpTable[0Bh*2],ax
  2404.         ret
  2405.  
  2406. InitMoveBlock386 endp
  2407.  
  2408.  
  2409. ;*--------------------------------------------------------------------------*
  2410. ;*                                        *
  2411. ;*  InstallA20 -                        HARDWARE DEP.   *
  2412. ;*                                        *
  2413. ;*    Attempt to install the proper A20 Handler                *
  2414. ;*                                        *
  2415. ;*  ARGS:   None                                *
  2416. ;*  RETS:   None                                *
  2417. ;*  REGS:   AX, CX, DI, SI, ES and Flags are clobbered                *
  2418. ;*                                        *
  2419. ;*--------------------------------------------------------------------------*
  2420.  
  2421. InstallA20  proc near
  2422.         
  2423.         ; Are we on a 6300 Plus?
  2424.         call    Is6300Plus
  2425.         or        ax,ax
  2426.         jz        short IAChkPS2
  2427.  
  2428.         ; Yes, relocate 6300 Plus A20 handler.
  2429.         mov        si,offset $6300PLUS_A20Handler
  2430.         mov        cx,(offset End6300PLUS_Handler - offset $6300PLUS_A20Handler)
  2431.         jmp        short IAMoveIt
  2432.  
  2433.         ; Are we on a PS/2?
  2434. IAChkPS2:   call    IsPS2Machine
  2435.         cmp        ax,1
  2436.         jne     short IACheckHP
  2437.  
  2438.         ; Yes, relocate the PS/2 A20 handler.
  2439.         mov        si,offset PS2_A20Handler
  2440.         mov        cx,(offset EndPS2_A20Handler - offset PS2_A20Handler)
  2441.         jmp        short IAMoveIt
  2442.  
  2443.         ; Are we on a HP Vectra?
  2444. IACheckHP:  call    IsHPMachine
  2445.         cmp        ax,1
  2446.         jne     short IAOnAT
  2447.  
  2448.         ; Yes, relocate the HP A20 handler.
  2449.         mov        si,offset HP_A20Handler
  2450.         mov     cx,(offset EndHP_A20Handler - offset HP_A20Handler)
  2451.         jmp     short IAMoveIt
  2452.  
  2453. IAOnAT:     mov     si,offset AT_A20Handler
  2454.         mov     cx,(offset EndAT_A20Handler - offset AT_A20Handler)
  2455.  
  2456.         ; REP MOV the proper handler into position.
  2457. IAMoveIt:   cld
  2458.         push    cs
  2459.         pop        es
  2460.         mov     di,[InitLine]
  2461.         mov     [A20Handler],di
  2462.         add        [InitLine],cx
  2463.         rep movsb
  2464.         ret
  2465.  
  2466. InstallA20  endp
  2467.  
  2468.  
  2469. ;*--------------------------------------------------------------------------*
  2470. ;*                                        *
  2471. ;*  GetParms -                                    *
  2472. ;*                                        *
  2473. ;*    Get any parameters off of the HIMEM command line            *
  2474. ;*                                        *
  2475. ;*  ARGS:   None                                *
  2476. ;*  RETS:   None                                *
  2477. ;*  REGS:   AX, BX, CX, DX, DI, SI, ES and Flags clobbered            *
  2478. ;*                                        *
  2479. ;*  Side Effects:   cHandles and MinHMASize may be changed            *
  2480. ;*                                        *
  2481. ;*--------------------------------------------------------------------------*
  2482.  
  2483. GPRegSave   dw        ?
  2484.  
  2485. GetParms    proc    near
  2486.  
  2487.         push    ds
  2488.  
  2489.         cld
  2490.         les        di,[pReqHdr]
  2491.         lds        si,es:[di.pCmdLine]        ; DS:SI points to first char
  2492.                         ; after "DEVICE="
  2493.         ; Scan until we see a frontslash or the end of line.
  2494. GPBadParm:          
  2495. GPNextChar: lodsb
  2496.         cmp        al,'/'
  2497.         je        short GPGotOne
  2498.         cmp        al,13
  2499.         jne     short GPNextChar
  2500. GPDatsAll:  pop        ds
  2501.         ret
  2502.  
  2503.         ; Save what we found and get the number after it.
  2504. GPGotOne:   lodsb
  2505.         mov        cs:[GPRegSave],ax
  2506.         
  2507.         ; Scan past the rest of the parm for a number, EOL, or a space.
  2508. GPNeedNum:  lodsb
  2509.         cmp        al,' '
  2510.         je        short GPBadParm
  2511.         cmp        al,13
  2512.         je        short GPBadParm
  2513.         cmp        al,'0'
  2514.         jb        short GPNeedNum
  2515.         cmp        al,'9'
  2516.         ja        short GPNeedNum
  2517.         
  2518.         ; Read the number at DS:SI into DX.
  2519.         xor        dx,dx
  2520. GPNumLoop:  sub        al,'0'
  2521.         cbw
  2522.         add        dx,ax
  2523.         lodsb
  2524.         cmp        al,' '
  2525.         je        short GPNumDone
  2526.         cmp        al,13
  2527.         je        short GPNumDone
  2528.         cmp        al,'0'
  2529.         jb        short GPBadParm
  2530.         cmp        al,'9'
  2531.         ja        short GPBadParm
  2532.         shl        dx,1            ; Stupid multiply DX by 10
  2533.         mov        bx,dx
  2534.         shl        dx,1
  2535.         shl        dx,1
  2536.         add        dx,bx
  2537.         jmp        short GPNumLoop
  2538.         
  2539.         ; Which parameter are we dealing with here?
  2540. GPNumDone:  xchg    ax,cs:[GPRegSave]
  2541.         cmp        al,'H'            ; HMAMIN= parameter?
  2542.         je        short GPGotMin
  2543.         cmp        al,'N'            ; NUMHANDLES= parameter?
  2544.         jne     short GPBadParm
  2545.  
  2546.         ; Process /NUMHANDLES= parameter.
  2547. GPGotHands: cmp        dx,MAXHANDLES
  2548.         ja        short GPBadParm
  2549.  
  2550.         mov        cs:[cHandles],dx
  2551.  
  2552.         ; Print descriptive message.
  2553.         mov        dx,offset StartMsg
  2554.         call    GPPrintIt
  2555.         mov        ax,cs:[cHandles]
  2556.         call    GPPrintAX
  2557.         mov        dx,offset HandlesMsg
  2558.         call    GPPrintIt
  2559.         jmp        short GPNextParm
  2560.  
  2561.         ; Process /HMAMIN= parameter.
  2562. GPGotMin:   cmp        dx,64
  2563.         ja        short GPBadParm
  2564.  
  2565.         push    dx
  2566.         mov        cs:[MinHMASize],dx
  2567.  
  2568.         ; Print a descriptive message.
  2569.         mov        dx,offset HMAMINMsg
  2570.         call    GPPrintIt
  2571.         mov        ax,cs:[MinHMASize]
  2572.         call    GPPrintAX
  2573.         mov        dx,offset KMsg
  2574.         call    GPPrintIt
  2575.  
  2576.         pop        dx
  2577.         mov        cl,10            ; Convert from K to bytes
  2578.         shl        dx,cl
  2579.         mov        cs:[MinHMASize],dx
  2580.  
  2581.         ; Were we at the end of the line?
  2582. GPNextParm: mov        ax,cs:[GPRegSave]
  2583.         cmp        al,13
  2584.         je        short GPExit
  2585.         jmp     GPNextChar
  2586.  
  2587. GPExit:        pop        ds
  2588.         ret
  2589.         
  2590. GetParms    endp
  2591.  
  2592. ;*--------------------------------------------------------------------------*
  2593.  
  2594. GPPrintIt   proc    near
  2595.  
  2596.         push    ds                ; Save current DS
  2597.         push    cs                ; Set DS=CS
  2598.         pop        ds
  2599.         mov        ah,9h
  2600.         int        21h
  2601.         pop        ds                ; Restore DS
  2602.         ret
  2603.  
  2604. GPPrintIt   endp
  2605.  
  2606. ;*--------------------------------------------------------------------------*
  2607.  
  2608. GPPrintAX   proc    near
  2609.  
  2610.         mov        cx,10
  2611.         xor        dx,dx
  2612.         div        cx
  2613.         or        ax,ax
  2614.         jz        short GPAPrint
  2615.         push    dx
  2616.         call    GPPrintAX
  2617.         pop        dx
  2618. GPAPrint:   add        dl,'0'
  2619.         mov        ah,2h
  2620.         int        21h
  2621.         ret
  2622.  
  2623. GPPrintAX   endp
  2624.  
  2625.  
  2626. ;*--------------------------------------------------------------------------*
  2627. ;*                                        *
  2628. ;*  InitHandles -                                *
  2629. ;*                                        *
  2630. ;*    Initialize the Extended Memory Handle Table                *
  2631. ;*                                        *
  2632. ;*  ARGS:   None                                *
  2633. ;*  RETS:   None                                *
  2634. ;*  REGS:   AX, BX, CX, and Flags are clobbered                    *
  2635. ;*                                        *
  2636. ;*--------------------------------------------------------------------------*
  2637.  
  2638. InitHandles proc    near
  2639.  
  2640.         ; Allocate room for the Handle table at the end.
  2641.         mov        ax,[InitLine]
  2642.         mov        [KiddValley],ax
  2643.         mov        ax,SIZE Handle
  2644.         mov        cx,[cHandles]
  2645.         mul        cx
  2646.         add        [InitLine],ax
  2647.         
  2648.         ; Init the Handle table.
  2649.         mov        bx,KiddValley
  2650.         xor        ax,ax
  2651.         mov        cx,[cHandles]
  2652. IHTabLoop:  mov        [bx.Flags],UNUSEDFLAG
  2653.         mov        [bx.cLock],al
  2654.         mov        [bx.Base],ax
  2655.         mov        [bx.Len],ax
  2656.         add        bx,SIZE Handle
  2657.         loop    IHTabLoop
  2658.  
  2659.         ; Store away the top of the table for handle validation.
  2660.         mov        [KiddValleyTop],bx
  2661.         ret
  2662.         
  2663. InitHandles endp
  2664.  
  2665.  
  2666. ;*--------------------------------------------------------------------------*
  2667. ;*                                        *
  2668. ;*  Is6300Plus                           HARDWARE DEP.    *
  2669. ;*                                        *
  2670. ;*    Check for AT&T 6300 Plus                        *
  2671. ;*                                        *
  2672. ;*  ARGS:   None                                *
  2673. ;*  RETS:   AX = 1 if we're on an AT&T 6300 Plus, 0 otherwise            *
  2674. ;*  REGS:   AX, flags used.                            *
  2675. ;*                                        *
  2676. ;*  Side Effects:   MemCorr value updated to 384 if necessary.            *
  2677. ;*                                        *
  2678. ;*--------------------------------------------------------------------------*
  2679.  
  2680. Is6300Plus  proc near
  2681.  
  2682.         xor        ax,ax
  2683.         push    bx
  2684.         mov        bx,0FC00h            ; Look for 'OL' at FC00:50
  2685.         mov        es,bx
  2686.         cmp        es:[0050h],'LO'
  2687.         jne     short I6PNotPlus        ; Not found
  2688.         mov        bx,0F000h
  2689.         mov        es,bx
  2690.         cmp        word ptr es:[0FFFDh],0FC00h        ; Look for 6300 PLUS
  2691.         jne     short I6PNotPlus
  2692.  
  2693.         in        al,66h            ; Look for upper extended memory
  2694.         and        al,00001111b
  2695.         cmp        al,00001011b
  2696.         jne     short I6PNoMem
  2697.         mov        [MemCorr],384        ; Save value
  2698.  
  2699. I6PNoMem:   mov        ax,1            ; We found a PLUS
  2700. I6PNotPlus: pop        bx
  2701.         ret
  2702.  
  2703. Is6300Plus  endp
  2704.  
  2705.  
  2706. ;*--------------------------------------------------------------------------*
  2707. ;*                                        *
  2708. ;*  IsPS2Machine                        HARDWARE DEP.   *
  2709. ;*                                        *
  2710. ;*    Check for PS/2 machine                            *
  2711. ;*                                        *
  2712. ;*  ARGS:   None                                *
  2713. ;*  RETS:   AX = 1 if we're on a valid PS/2 machine, 0 otherwise        *
  2714. ;*  REGS:   AX    and Flags clobbered                        *
  2715. ;*                                        *
  2716. ;*--------------------------------------------------------------------------*
  2717.  
  2718. IsPS2Machine proc   near
  2719.  
  2720.         mov     ah,0C0h        ; Get System Description Vector
  2721.         stc
  2722.         int        15h
  2723.         jc        short IPMNoPS2  ; Error?  Not a PS/2.
  2724.  
  2725.         ; Do we have a "Micro Channel" computer?
  2726.         mov     al,byte ptr es:[bx+5]   ; Get "Feature Information Byte 1"
  2727.         test    al,00000010b    ; Test the "Micro Channel Implemented" bit
  2728.         jz        short IPMNoPS2
  2729.  
  2730. IPMFoundIt: xor        ax,ax        ; Disable A20. Fixes PS2 Ctl-Alt-Del bug
  2731.         call    PS2_A20Handler
  2732.         mov        ax,1
  2733.         ret
  2734.  
  2735. IPMNoPS2:   xor        ax,ax
  2736.         ret
  2737.  
  2738. IsPS2Machine endp
  2739.  
  2740.  
  2741. ;*--------------------------------------------------------------------------*
  2742. ;*                                        *
  2743. ;*  IsHPMachine                            HARDWARE DEP.   *
  2744. ;*                                        *
  2745. ;*    Check for HP Vectra Machine                        *
  2746. ;*                                        *
  2747. ;*  ARGS:   None                                *
  2748. ;*  RETS:   AX = 1 if we're on a HP Vectra machine, 0 otherwise            *
  2749. ;*  REGS:   AX, ES and Flags clobbered                        *
  2750. ;*                                        *
  2751. ;*--------------------------------------------------------------------------*
  2752.  
  2753. IsHPMachine proc   near
  2754.  
  2755.         mov        ax,0F000h
  2756.         mov        es,ax
  2757.         mov        ax,word ptr es:[0F8h]
  2758.         cmp        ax,'PH'
  2759.         je        short IHMFoundIt
  2760.         xor        ax,ax
  2761.         ret
  2762.  
  2763. IHMFoundIt: mov        ax,1
  2764.         ret
  2765.  
  2766. IsHPMachine endp
  2767.  
  2768.  
  2769. ;*--------------------------------------------------------------------------*
  2770. ;*    DRIVER MESSAGES                                *
  2771. ;*--------------------------------------------------------------------------*         
  2772.  
  2773. SignOnMsg   db    13,10,'HIMEM: DOS XMS Driver, Version 2.03 - 8/09/88'
  2774.         db    13,10,'Copyright 1988, Microsoft Corp.'
  2775.         db    13,10,'$'
  2776.  
  2777. BadDOSMsg   db    13,10,'ERROR: HIMEM.SYS requires DOS 3.00 or higher.$'
  2778. NowInMsg    db    13,10,'ERROR: An Extended Memory Manager is already installed.$'
  2779. On8086Msg   db    13,10,'ERROR: HIMEM.SYS requires an 80x86-based machine.$'
  2780. NoExtMemMsg db    13,10,'ERROR: No available extended memory was found.$'
  2781. BadA20Msg   db    13,10,'ERROR: Unrecognized A20 hardware.$'
  2782. FlushMsg    db    13,10,'          XMS Driver not installed.',13,10,13,10,'$'
  2783.  
  2784. StartMsg    db    13,10,'$'
  2785. HandlesMsg  db    ' extended memory handles available.$'
  2786. HMAMINMsg   db    13,10,'Minimum HMA size set to $'
  2787. KMsg        db    'K.$'
  2788.  
  2789. NoHMAMsg    db    13,10,'WARNING: The High Memory Area is unavailable.',13,10,'$'
  2790. A20OnMsg    db    13,10,'WARNING: The A20 Line was already enabled.',13,10,'$'
  2791.  
  2792. HMAOKMsg    db    13,10,'64K High Memory Area is available.',13,10,13,10,'$'
  2793.  
  2794.         db    'This program is the property of Microsoft Corporation.'
  2795.         
  2796.         db    64 dup(0)            ; For internationalization
  2797.  
  2798. ;*==========================================================================*
  2799.  
  2800. code        ends
  2801.  
  2802.         end
  2803.