home *** CD-ROM | disk | FTP | other *** search
/ DP Tool Club 21 / CD_ASCQ_21_040595.iso / dos / prg / c / freedos3 / source / xms / xms.asm < prev    next >
Assembly Source File  |  1994-12-28  |  31KB  |  1,329 lines

  1. ;==============================================================================
  2. ;==
  3. ;==     Project                 : 286 XMS driver
  4. ;==     Module name             : HM286.ASM (HM286.SYS)
  5. ;==     Author(s)               : Mark E. Huss (meh@bis.adp.com)
  6. ;==     Purpose                 : Simplified HIMEM.SYS replacement
  7. ;==
  8. ;==     Created                 : 11/5/90
  9. ;==
  10. ;==                              Revision history
  11. ;==                              ================
  12. ;==
  13. ;==============================================================================
  14. ; Notes:
  15. ;
  16. ; * Some routines (e.g. xms_move_xmem) are NOT re-entrant.
  17. ;==============================================================================
  18.     page 65,132
  19.  
  20. .286
  21. include xms.inc
  22.  
  23. ;------------------------------------------------------------------------------
  24. ABS0    segment    at 0
  25.     org    4*15h
  26. int_15_vec    label    dword
  27. ABS0    ends
  28. ;------------------------------------------------------------------------------
  29.  
  30. CSEG    segment
  31.     assume cs:CSEG, ds:nothing, es:nothing
  32. segorg:
  33. ;
  34. ; stock device driver header
  35. ;
  36.     dd    -1        ; pointer to next device
  37.     dw    8000h        ; character device
  38.     dw    offset    strategy
  39.     dw    offset    interrupt
  40.     db    'XMSXXXX0'    ; 8 character name
  41. ;
  42. ; program data
  43. ;
  44.     even
  45. req_ptr        dd    ?
  46. old_int_15    dd    ?
  47. old_int_2f    dd    ?
  48. gate_a20    dw    AT_gate_a20        ; else ps2_gate_a20
  49. get_a20        dw    test_a20        ; else ps2_get_a20
  50.  
  51. ftable    label    word
  52.     dw    xms_get_version        ; 0 get XMS version
  53.     dw    xms_request_hma        ; 1 request high mem area
  54.     dw    xms_release_hma        ; 2 release high mem area
  55.     dw    xms_global_enable_A20    ; 3 global enable a20
  56.     dw    xms_global_disable_A20    ; 4 global disable a20
  57.     dw    xms_local_enable_A20    ; 5 local enable a20
  58.     dw    xms_local_disable_A20    ; 6 local disable a20
  59.     dw    xms_query_a20        ; 7 query a20
  60.     dw    xms_query_xmem        ; 8 query free extended mem
  61.     dw    xms_alloc_xmem        ; 9 alloc extended mem block (EMB)
  62.     dw    xms_free_xmem        ; A free EMB
  63.     dw    xms_move_xmem        ; B move EMB
  64.     dw    xms_lock_xmem        ; C lock EMB
  65.     dw    xms_unlock_xmem     ; D unlock EMB
  66.     dw    xms_handle_info        ; E get EMB handle info
  67. ;
  68. ; these are not yet supported
  69. ;
  70. ;    dw    xms_bad_fn    ; F realloc EMB
  71. ;    dw    xms_bad_fn    ; 10 request upper mem block (UMB)
  72. ;    dw    xms_bad_fn    ; 11 release UMB
  73. ;       dw      xms_bad_fn      ; 12 realloc UMB
  74. ftable_end    label    word
  75.  
  76. ; These fns won't go into the table (and are also not yet supported!)
  77. ; 88 Query any free extended memory
  78. ; 89 Allocate any Extended Memory Block
  79. ; 8E Get extended EMB handle
  80. ; 8F Reallocate any Extended Memory
  81.  
  82. ;
  83. ; global descriptor table for int 15h block moves
  84. ;
  85. gdt        desc    <0,0,0,0,0>
  86. base_desc    desc    <>
  87. src_desc    desc    <>
  88. dest_desc    desc    <>
  89. bios_cs        desc    <>
  90. bios_ss        desc    <>
  91.  
  92. maxaddr        dw    0,11h        ; starts at 110000
  93. _1024        dw    1024        ; for byte <-> kbyte conversions
  94. move_length    dw    0
  95.  
  96. hm_flags    db    0
  97. int_mask    db    0
  98.  
  99. .8086    ; could be anything here
  100. ;------------------------------------------------------------------------------
  101.  
  102. strategy    proc    far
  103.     mov    cs:req_ptr.lsw,bx
  104.     mov    cs:req_ptr.msw,es
  105.     ret
  106. strategy    endp
  107.  
  108. ;------------------------------------------------------------------------------
  109.  
  110. interrupt    proc    far
  111.     push    ax
  112.     push    cx
  113.     push    dx
  114.     push    bx
  115.     push    si
  116.     push    di
  117.     push    ds
  118.     push    es
  119.     mov    ax,DD_CMD_ERR    ; AX = error
  120.     sub    bx,bx        ; BX = 0 (assume the worst)
  121.     lds    si,req_ptr
  122.     cmp    [si].cmd,DD_INIT
  123.     jne    int_exit
  124.     test    hm_flags,INIT_DONE
  125.     jnz    int_exit
  126.     call    initialize    ; only call once!
  127.     lds    si,req_ptr
  128. int_exit:
  129.     mov    [si].stat,ax
  130.     mov    [si].endseg,cs    ; END offset = our CS:0000
  131.     mov    [si].endofs,bx    ; 0 or size to keep
  132.     pop    es
  133.     pop    ds
  134.     pop    di
  135.     pop    si
  136.     pop    bx
  137.     pop    dx
  138.     pop    cx
  139.     pop    ax
  140.     ret
  141. interrupt    endp
  142.  
  143. ;------------------------------------------------------------------------------
  144. .286    ; processor checked from here on
  145.  
  146. int_15    proc    far
  147.     cmp    ah,87h
  148.     je    int_15_move
  149.     cmp    ah,88h
  150.     je    int_15_size
  151.     jmp    old_int_15
  152. int_15_move:
  153.     mov    ah,3        ; 'gate a20 failed' error
  154.     push    bp
  155.     mov    bp,sp
  156.     or    byte ptr [bp+6],CARRY_FLAG
  157.     jmp    int_15_exit
  158. int_15_size:
  159.     sub    ax,ax        ; indicate 0K free
  160.     push    bp
  161.     mov    bp,sp
  162.     and    byte ptr [bp+6],not CARRY_FLAG
  163. int_15_exit:
  164.     pop    bp
  165.  
  166. popf_iret    proc    near        ; popf (for B-step 286 bug)
  167.     iret
  168. popf_iret    endp
  169.  
  170. int_15    endp
  171.  
  172. ;------------------------------------------------------------------------------
  173.  
  174. int_2f    proc    far
  175.     cmp    ah,43h
  176.     je    do_int2f
  177. do_old_2f:
  178.     jmp    old_int_2f
  179. do_int2f:
  180.     cmp    al,0
  181.     jne    try_2f_10
  182.     mov    al,80h
  183.     jmp    short int_2f_exit
  184. try_2f_10:
  185.     cmp    al,10h
  186.     jne    do_old_2f
  187.     push    cs
  188.     pop    es
  189.     mov    bx,offset hm_main
  190. int_2f_exit:
  191.     iret
  192. int_2f    endp
  193.  
  194. ;------------------------------------------------------------------------------
  195.     assume cs:CSEG, ds:CSEG, es:nothing
  196. ;------------------------------------------------------------------------------
  197. ; hook_int_15 -
  198. ;   hook int 15h and clear handle table on 1st non-version call
  199. ;
  200. ; input:
  201. ; output:
  202. ; modifies:
  203. ;    AX, CX, DI, ES
  204. ;
  205. ; Note: currently MUST preserve BX, DX & SI
  206. ;------------------------------------------------------------------------------
  207. hook_int_15    proc    near
  208.     pushf
  209.     cli                ; no ints now
  210.     sub    ax,ax
  211.     mov    es,ax
  212.     assume    es:ABS0
  213.     mov    ax,int_15_vec.lsw    ; get old vector
  214.     mov    old_int_15.lsw,ax
  215.     mov    ax,int_15_vec.msw
  216.     mov    old_int_15.msw,ax
  217.                     ; set our new int 15h vector
  218.     mov    int_15_vec.lsw,offset int_15
  219.     mov    int_15_vec.msw,cs
  220.     or    hm_flags,INT15_HOOKED
  221.     @popf                ; ints OK
  222.  
  223.     sub    ax,ax            ; init handle table to 00
  224.     push    cs
  225.     pop    es
  226. ;
  227. ; hose all but 1st handle to 0
  228. ;
  229.     mov    cx,((MAX_HANDLES-1) * type xms_handle) shr 1
  230.     mov    di,(offset handle_table - offset segorg) + type xms_handle
  231.     cld
  232.     rep    stosw
  233.     ret
  234. hook_int_15    endp
  235.  
  236. ;------------------------------------------------------------------------------
  237. ; test_a20 - see if A20 is enabled the hard way
  238. ;
  239. ; input:
  240. ;    nil
  241. ; output:
  242. ;    AX = 1 if A20 is enabled, ZF clear
  243. ;    AX = 0 if A20 is disabled, ZF set
  244. ; modifies:
  245. ;    AX
  246. ;------------------------------------------------------------------------------
  247. test_a20    proc    near
  248.         push    si
  249.         push    di
  250.     push    ds
  251.     push    es
  252.     mov     ax,0FFFFh
  253.     mov    es,ax        ; ES = FFFF
  254.     inc    ax
  255.     mov    ds,ax        ; DS = 0000
  256.     sub    si,si
  257.     mov    di,10h
  258.     mov    cx,100h        ; 0000:0000 vs. FFFF:0010
  259.     cld
  260.     rep    cmpsw
  261.         jz      ta_off         ; ZF set means a20 is off
  262.         inc     ax              ; this will keep the ZF cleared
  263. ta_off:
  264.     pop    es
  265.     pop    ds
  266.     pop    di
  267.     pop    si
  268.     ret
  269. test_a20    endp
  270.  
  271. ;------------------------------------------------------------------------------
  272. ; kbd_wait - wait for keyboard controller input ready
  273. ;
  274. ; input:
  275. ;    nil
  276. ; output:
  277. ;    nil
  278. ; modifies:
  279. ;    AL
  280. ;------------------------------------------------------------------------------
  281. kbd_wait    proc    near
  282.     push    cx
  283.     sub    cx,cx
  284. kw_loop:
  285.     in    al,KBD_STATUS
  286.     test    al,KS_INPORT_FULL
  287.     loopnz    kw_loop        ; wait 'til input bit is clear
  288.     pop    cx
  289.     ret
  290. kbd_wait    endp
  291.  
  292. ;------------------------------------------------------------------------------
  293. ; AT_gate_a20
  294. ;
  295. ; input:
  296. ;    AX = 0 --> disable
  297. ;    else   --> enable
  298. ; modifies:
  299. ;    AX
  300. ;------------------------------------------------------------------------------
  301. AT_gate_a20        proc    near
  302.     pushf
  303.     cli
  304.     test    ax,ax
  305. ;    in    al,KBD_DATA
  306.         mov     al,0DDh
  307.     jz    aga_disable
  308.     or    al,KC_A20_BIT
  309.     jmp    short aga_IO
  310. aga_disable:
  311.     and    al,not KC_A20_BIT
  312. aga_IO:
  313.     or    al,KC_RESET_BIT        ; don't reset the box!
  314.     mov    ah,al
  315.     call    kbd_wait
  316.     jnz    aga_err
  317.  
  318.     mov    al,KC_WR_OUTPORT
  319.     out    KBD_COMMAND,al
  320.     call    kbd_wait
  321.     jnz    aga_err
  322.  
  323.     mov    al,ah
  324.     out    KBD_DATA,al
  325.     call    kbd_wait
  326.  
  327. aga_err:
  328.     @popf
  329.     ret
  330. AT_gate_a20    endp
  331.  
  332. ;------------------------------------------------------------------------------
  333. ; ps2_gate_a20
  334. ;
  335. ; input:
  336. ;    AX = 0 --> disable
  337. ;    else   --> enable
  338. ;------------------------------------------------------------------------------
  339. ps2_gate_a20    proc    near
  340.     test    ax,ax
  341.     in    al,SYSTEM_CONTROL_PORT_A
  342.     jz    pga_disable    ; else fall thru to enable_a20
  343.     or    al,A20_ENABLE_BIT
  344.     jmp    short port_a_out
  345. pga_disable:
  346.     and    al,not A20_ENABLE_BIT
  347. port_a_out:
  348.     out    SYSTEM_CONTROL_PORT_A,al
  349.     ret
  350. ps2_gate_a20    endp
  351.  
  352. ;------------------------------------------------------------------------------
  353. ; enable_a20
  354. ; disable_a20
  355. ;
  356. ; input:
  357. ;    nil
  358. ; output:
  359. ;    nil
  360. ; modifies:
  361. ;    AX
  362. ;------------------------------------------------------------------------------
  363. enable_a20    proc    near
  364.     mov    al,1
  365.     jmp    gate_a20
  366. enable_a20    endp
  367.  
  368. disable_a20    proc    near
  369.     sub    ax,ax
  370.     jmp    gate_a20
  371. disable_a20    endp
  372.  
  373. ;------------------------------------------------------------------------------
  374. ; ps2_get_a20
  375. ;
  376. ; input:
  377. ;    nil
  378. ; output:
  379. ;    AX = 1 if A20 is enabled, ZF clear
  380. ;    AX = 0 if A20 is disabled, ZF set
  381. ; modifies:
  382. ;    AX
  383. ;------------------------------------------------------------------------------
  384. ps2_get_a20    proc    near
  385.     sub    ax,ax
  386.     in    al,SYSTEM_CONTROL_PORT_A
  387.     and    al,A20_ENABLE_BIT
  388.     shr    ax,1        ; move bit to LSB & set/clear ZF
  389.     ret
  390. ps2_get_a20    endp
  391.  
  392. ;------------------------------------------------------------------------------
  393. ; segoff_to_physical
  394. ;
  395. ; input:
  396. ;    DX:AX = seg:ofs
  397. ; output:
  398. ;    DX:AX = physical 24 bit address (DH = 00)
  399. ; modifies:
  400. ;    AX, CX, DX
  401. ;------------------------------------------------------------------------------
  402. segoff_to_physical    proc    near
  403.     mov    cx,dx
  404.     sub    dx,dx
  405.     mov    dl,ch
  406.     shr    dx,4        ; DX = seg MSD    000x
  407.     shl    cx,4        ; CX = seg 3 LSDs xxx0
  408.     add    ax,cx        ; AX = LSW 
  409.     adc    dx,0        ; DX = MSW
  410.     ret
  411. segoff_to_physical    endp
  412. ;------------------------------------------------------------------------------
  413. ; get_xmove_addr
  414. ;
  415. ; input:
  416. ;    ES:BX -> xmem_sub_move struc
  417. ; output:
  418. ;    CF = 0, DX:AX == physical addr
  419. ;    CF = 1, error 
  420. ; modifies:
  421. ;    AX, (BL), DX
  422. ;------------------------------------------------------------------------------
  423. get_xmove_addr    proc    near
  424.     mov    dx,es:[bx].xhandle
  425.     test    dx,dx
  426.     jnz    gxa_do_handle
  427.     mov    ax,es:[bx].xaddr_lo    ; handle 0 means seg:ofs ptr
  428.     mov    dx,es:[bx].xaddr_hi
  429.     call    segoff_to_physical
  430.     jmp    gxa_exit
  431.  
  432. gxa_do_handle:
  433.     call    check_handle
  434.     jc    gxa_exit
  435.     mov    ax,[di].xbase
  436.     mul    _1024            ; faster than 32 bit 10 place shift
  437.     add    ax,es:[bx].xaddr_lo
  438.     adc    dx,es:[bx].xaddr_hi
  439.  
  440. gxa_exit:
  441.     ret
  442. get_xmove_addr    endp
  443.  
  444. ;------------------------------------------------------------------------------
  445. ; check_addr
  446. ;
  447. ; input:
  448. ;    ES:SI -> xmem_move struc
  449. ;    DX:AX = physical 24 bit address (DH = 00)
  450. ;    if DEBUG
  451. ;       CF = 1 -> fail all HIMEM addresses
  452. ;       CF = 0 -> don't check for HIMEM
  453. ; output:
  454. ;    CF = 0, addr ok
  455. ;    CF = 1, bad addr
  456. ; modifies:
  457. ;    flags only
  458. ;------------------------------------------------------------------------------
  459. check_addr    proc    near
  460.     push    ax
  461.     push    dx
  462. if DEBUG
  463.     jnc    ca_ck_high_side
  464.     cmp    dx,11h        ; check for himem stomp
  465.     jae    ca_ck_high_side
  466.     cmp    dx,10h
  467.     jb    ca_addr_ok
  468.     jae    ca_addr_err
  469. ca_ck_high_side:
  470. endif
  471.     add    ax,es:[si].length_lo
  472.     adc    dx,es:[si].length_hi
  473.     cmp    dx,maxaddr[2]    ; check against maxaddr
  474.     jb    ca_addr_ok
  475.     ja    ca_addr_err
  476.     cmp    ax,maxaddr
  477.     jb    ca_addr_ok
  478. ca_addr_err:
  479.     stc
  480.     jc    ca_exit
  481. ca_addr_ok:
  482.     clc
  483. ca_exit:
  484.     pop    dx
  485.     pop    ax
  486.     ret
  487. check_addr    endp
  488.  
  489. ;------------------------------------------------------------------------------
  490. ; find_free_handle - find an unused handle in the handle_table
  491. ;
  492. ; input:
  493. ;    CF = 0 --> first time in
  494. ;    CF = 1 --> re-entering, adjust DI & CX first
  495. ;    CX = remaining handle count
  496. ;    DS:DI = handle to look at
  497. ; output:
  498. ;    CF = 0, DI = handle
  499. ;    CF = 1, DI = ???
  500. ; modifies:
  501. ;    CX, DI
  502. ;------------------------------------------------------------------------------
  503. find_free_handle    proc    near
  504.     jcxz    ffh_error_exit        ; for safety's sake
  505.     jc    ffh_keep_looking
  506. ffh_loop:
  507.     test    [di].xflags,XH_IN_USE    ; in use?
  508.     jnz    ffh_keep_looking
  509.     cmp    [di].xbase,0        ; totally free handle?
  510.     jz    ffh_exit        ; if true, CF = 0
  511. ffh_keep_looking:
  512.     add    di,type xms_handle
  513.     loop    ffh_loop
  514. ffh_error_exit:
  515.     stc
  516. ffh_exit:
  517.     ret
  518. find_free_handle    endp
  519.  
  520. ;------------------------------------------------------------------------------
  521. ; find_free_memory - find an unused memory block in the handle table
  522. ;
  523. ; input:
  524. ;    CF = 0 --> first time in
  525. ;    CF = 1 --> re-entering, adjust SI & CX first
  526. ;    DX = desired memory size
  527. ;    CX = remaining handle count
  528. ;    DS:SI = handle to look at
  529. ; output:
  530. ;    CF = 0, SI = handle
  531. ;    CF = 1, SI = ???
  532. ; modifies:
  533. ;    CX, SI
  534. ;------------------------------------------------------------------------------
  535. find_free_memory    proc    near
  536.     jcxz    ffm_error_exit        ; for safety's sake
  537.     jc    ffm_keep_looking
  538. ffm_loop:
  539.     test    [si].xflags,XH_IN_USE
  540.     jnz    ffm_keep_looking
  541.     cmp    [si].xsize,dx
  542.     jae    ffm_exit        ; CF = 0
  543. ffm_keep_looking:
  544.     add    si,type xms_handle
  545.     loop    ffm_loop
  546. ffm_error_exit:
  547.     stc
  548. ffm_exit:
  549.     ret
  550. find_free_memory    endp
  551.  
  552. ;------------------------------------------------------------------------------
  553. ; check_handle
  554. ;
  555. ; input:
  556. ;    DX = handle
  557. ; output:
  558. ;    CF = 0, DI = handle ptr
  559. ;    CF = 1, BL = error code
  560. ; modifies:
  561. ;    DX, DI        -- must preserve BX & SI --
  562. ;------------------------------------------------------------------------------
  563. check_handle    proc    near
  564.     mov    di,dx
  565.     sub    dx,offset handle_table
  566.     js    bad_handle
  567.     cmp    dx,(MAX_HANDLES-1) * type xms_handle
  568.     ja    bad_handle
  569.     cmp    [di].xbase,0
  570.     je    bad_handle
  571.     clc
  572.     ret
  573. bad_handle:
  574.     mov    bl,ERR_BAD_XHNDL
  575.     stc
  576.     ret
  577. check_handle    endp
  578.  
  579. ;------------------------------------------------------------------------------
  580. ; ----- XMS functions -----
  581. ;------------------------------------------------------------------------------
  582. ; On entry, SS:[BP] -> register stack frame
  583. ;
  584. ; All functions return:
  585. ;   CF=0 --> success, AX = returned AX, BL = returned BL (usually 00)
  586. ;   CF=1 --> error, AX = don't care, BL = returned error code
  587. ;------------------------------------------------------------------------------
  588. ; get XMS version number (function 00h)
  589. ;------------------------------------------------------------------------------
  590. xms_get_version    proc    near    
  591.     mov    [bp].r_dx,1        ; HMA exists
  592.     mov    bx,OUR_VERSION
  593.     mov    [bp].r_bx,bx        ; BL = returned BL
  594.     mov    ax,XMS_VERSION
  595.     clc
  596.     ret
  597. xms_get_version    endp
  598. ;------------------------------------------------------------------------------
  599. ; Request High Memory Area (function 01h)
  600. ; Release High Memory Area (function 02h)
  601. ;------------------------------------------------------------------------------
  602. xms_request_hma    proc    near
  603.     mov    bl,ERR_HMA_IN_USE
  604.     test    hm_flags,HMA_IN_USE
  605.     jnz    rhma_error_exit
  606.     or    hm_flags,HMA_IN_USE        ; & clc
  607.     jmp    short rhma_good_exit
  608. xms_request_hma    endp
  609. ;----------------------------------
  610. xms_release_hma    proc    near
  611.     mov    bl,ERR_HMA_NOT_ALLOCATED
  612.     test    hm_flags,HMA_IN_USE
  613.     jz    rhma_error_exit
  614.     and    hm_flags,not HMA_IN_USE        ; & clc
  615.  
  616. rhma_good_exit:
  617.     mov    ax,1
  618.     mov    bl,0
  619.     ret
  620.  
  621. rhma_error_exit:
  622.     stc
  623.     ret
  624. xms_release_hma    endp
  625. ;------------------------------------------------------------------------------
  626. ; Global/Local Enable A20 (function 03h/05h)
  627. ; Global/Local Disable A20 (function 04h/06h)
  628. ;------------------------------------------------------------------------------
  629. xms_global_enable_A20    proc    near
  630.     mov    bl,ERR_A20_GATE
  631.     test    hm_flags,HMA_IN_USE    ; 'global' checks for HMA user
  632.     jz    fa_error_exit
  633. xms_local_enable_A20:
  634.     call    enable_a20
  635.     jmp    short fa_good_exit
  636. xms_global_enable_A20    endp
  637. ;----------------------------------
  638. xms_global_disable_A20    proc    near
  639.     mov    bl,ERR_A20_STILL_ENABLED
  640.     test    hm_flags,HMA_IN_USE
  641.     jz    fa_error_exit
  642. xms_local_disable_A20:
  643.     call    disable_a20
  644.  
  645. fa_good_exit:
  646.     mov    ax,1
  647.     mov    bl,0
  648.     clc
  649.     ret
  650.  
  651. fa_error_exit:
  652.     stc
  653.     ret
  654. xms_global_disable_A20    endp
  655. ;------------------------------------------------------------------------------
  656. ; Query A20 (function 07h)
  657. ;------------------------------------------------------------------------------
  658. xms_query_a20    proc    near
  659.     call    get_a20
  660.     sub    bl,bl        ; & clc
  661.     ret
  662. xms_query_a20    endp
  663. ;------------------------------------------------------------------------------
  664. ; Query Free Extended Memory (function 08h)
  665. ;------------------------------------------------------------------------------
  666. xms_query_xmem    proc    near
  667.     sub    ax,ax            ; AX = largest found
  668.     sub    dx,dx            ; find even smallest free block
  669.     sub    di,di            ; DI = total ( & clc)
  670.      mov    cx,MAX_HANDLES
  671.     mov    si,offset handle_table
  672. qxm_loop:
  673.     call    find_free_memory    ; SI = memory handle
  674.     jc    qxm_done
  675.     add    di,[si].xsize        ; update total
  676.     cmp    ax,[si].xsize        ; update largest
  677.     ja    qxm_mine_is_bigger    ;  if necessary
  678.     mov    ax,[si].xsize
  679. qxm_mine_is_bigger:
  680.     stc
  681.     jmp    qxm_loop
  682.  
  683. qxm_done:
  684.     mov    [bp].r_dx,di        ; return DX = total
  685.     test    ax,ax            ; & clc
  686.     jz    qxm_empty
  687.     mov    bl,0            ;  AX = largest found
  688.     ret
  689. qxm_empty:
  690.     mov    bl,ERR_OUT_OF_XMEM
  691.     stc
  692.     ret
  693. xms_query_xmem    endp
  694. ;------------------------------------------------------------------------------
  695. ; Allocate Extended Memory Block (function 09h)
  696. ;    DX = block size
  697. ;------------------------------------------------------------------------------
  698. xms_alloc_xmem    proc    near
  699.      mov    cx,MAX_HANDLES
  700.     mov    si,offset handle_table
  701.     clc                ; CF = 0 --> first find_free
  702.     call    find_free_memory    ; SI = memory handle
  703.     jc    axm_error_exit        ; out of memory
  704.  
  705.     mov    cx,MAX_HANDLES
  706.     mov    di,offset handle_table    ; CF = 0 --> first find_free
  707. axm_find_handle:
  708.     call    find_free_handle    ; DI = blank handle
  709. ;
  710. ; if memory handle is last unused handle, give
  711. ; requestor all remaining memory
  712. ;
  713.     jc    axm_perfect_fit
  714. ;
  715. ; make sure we have two different handles!
  716. ;
  717.     cmp    si,di
  718.     stc                ; CF = 1 --> NOT first find_free
  719.     je    axm_find_handle
  720. ;
  721. ; found two handles, adjust memory size of memory handle and
  722. ;  use free handle for left over memory 
  723. ;
  724. axm_normal_alloc:
  725.     xchg    [si].xsize,dx        ; set size
  726.     sub    dx,[si].xsize        ; DX = left over size
  727.     jz    axm_perfect_fit
  728.  
  729.     mov    ax,[si].xbase        ; old xbase + xsize
  730.     add    ax,[si].xsize        ;  = new block xbase
  731.     mov    [di].xbase,ax
  732.     mov    [di].xsize,dx        ; new block size
  733.  
  734. axm_perfect_fit:
  735.     or    [si].xflags,XH_IN_USE
  736.     mov    [bp].r_dx,si        ; handle table offset is handle
  737.     mov    ax,1
  738.     sub    bl,bl            ; & clc
  739.     ret
  740.  
  741. axm_error_exit:
  742.     mov    bl,ERR_OUT_OF_XHNDL    ; this is what HIMEM returns
  743.     stc                ; (even if really 'out of memory')
  744.     ret
  745. xms_alloc_xmem    endp
  746. ;------------------------------------------------------------------------------
  747. ; Free Extended Memory Block (function 0Ah)
  748. ;------------------------------------------------------------------------------
  749. xms_free_xmem    proc    near
  750.     call    check_handle
  751.     jc    fxm_error_exit
  752.     cmp    [di].xlocks,0        ; make sure its unlocked
  753.     jne    fxm_locked
  754. ;
  755. ; check for 0 length handle
  756. ;
  757.     mov    ax,[di].xsize
  758.     test    ax,ax
  759.     jnz    fxm_len_ok
  760.     mov    [di].xbase,ax        ; 0 len, just clear & exit
  761.     jmp    fxm_done
  762. ;
  763. ; normal handle, check for and concatenate any contiguous free blocks
  764. ;
  765. fxm_len_ok:
  766.     add    ax,[di].xbase        ; AX = freeing handle xbase+size
  767.     sub    dx,dx            ; any len 0 & up OK (& CF = 0)
  768. ;
  769. ; check the high side first
  770. ;
  771.     mov    cx,MAX_HANDLES
  772.     mov    si,offset handle_table
  773. fxm_loop1:
  774.     call    find_free_memory    ; SI = memory handle
  775.     jc    fxm_hi_done        ; CF means no more memory handles
  776.     cmp    ax,[si].xbase        ; free mem right above us?
  777.     stc
  778.     jne    fxm_loop1
  779. ;
  780. ; found one high, concat
  781. ;
  782.     mov    bx,[si].xsize        ; add his size
  783.     add    [di].xsize,bx        ; to ours
  784.     mov    [si].xbase,dx        ; and hose his 
  785.     mov    [si].xsize,dx        ; fields to 0000
  786. ;
  787. ; check the low side next
  788. ;
  789. fxm_hi_done:
  790.     mov    cx,MAX_HANDLES
  791.     mov    si,offset handle_table
  792.     clc
  793. fxm_loop2:
  794.     call    find_free_memory    ; SI = memory handle
  795.     jc    fxm_done        ; CF means no more memory handles
  796.  
  797.     mov    bx,[si].xsize        
  798.     add    bx,[si].xbase
  799.     cmp    bx,[di].xbase        ; free mem right below us?    
  800.     stc
  801.     jne    fxm_loop2
  802. ;
  803. ; found one low, concat
  804. ;
  805.     mov    bx,[di].xsize        ; add our size
  806.     add    [si].xsize,bx        ; to his
  807.     mov    [di].xbase,dx        ; and hose our
  808.     mov    [di].xsize,dx        ; fields to 0000
  809.  
  810. fxm_done:
  811.     and    [di].xflags,not XH_IN_USE
  812.     mov    ax,1
  813.     sub    bl,bl            ; & clc
  814.     ret
  815.  
  816. fxm_locked:
  817.     mov    bl,ERR_BLOCK_LOCKED
  818. fxm_error_exit:
  819.     stc
  820.     ret
  821. xms_free_xmem    endp
  822. ;------------------------------------------------------------------------------
  823. ; Move Extended Memory Block (function 0Bh)
  824. ;------------------------------------------------------------------------------
  825. xms_move_xmem    proc    near
  826.     test    hm_flags,IN_MOVE    ; almost guarantee no re-entrancy
  827.     jnz    xms_move_xmem        ; (tiny window of 
  828.     or    hm_flags,IN_MOVE    ;   mis-opportunity here)
  829. ;
  830. ; check length info
  831. ;
  832.     mov    es,[bp].r_ds
  833.     mov    si,[bp].r_si        ; ES:SI -> xmove struc
  834.     mov    dx,es:[si].length_hi
  835.     mov    ax,es:[si].length_lo
  836.     shr    dx,1            ; convert byte to word count
  837.     jnz    mxm_len_err        ; must be <64K
  838.     rcr    ax,1
  839.     jc    mxm_len_err        ; len must be even
  840.     cmp    ax,8000h        ; word count in AX
  841.     jbe    mxm_ok            ; must be <= 64K bytes
  842. mxm_len_err:
  843.     mov    bl,ERR_BAD_LEN
  844.     jmp    mxm_error_exit
  845.  
  846. mxm_ok:
  847.     mov    move_length,ax
  848. ;
  849. ; process source info
  850. ;
  851.     lea    bx,[si].source_handle
  852.     call    get_xmove_addr
  853.     mov    bl,ERR_BAD_SRC_XHNDL
  854.     jc    mxm_error_exit
  855.  
  856.     call    check_addr
  857.     mov    bl,ERR_BAD_SRC_OFS
  858.     jc    mxm_error_exit
  859.  
  860.     mov    src_desc.basel,ax
  861.     mov    src_desc.baseh,dl
  862. ;
  863. ; process destination info
  864. ;
  865.     lea    bx,[si].dest_handle
  866.     call    get_xmove_addr
  867.     mov    bl,ERR_BAD_DEST_XHNDL
  868.     jc    mxm_error_exit
  869. if DEBUG
  870.     stc                ; check HIMEM area too
  871. endif
  872.     call    check_addr
  873.     mov    bl,ERR_BAD_DEST_OFS
  874.     jc    mxm_error_exit
  875.  
  876.     mov    dest_desc.basel,ax
  877.     mov    dest_desc.baseh,dl
  878. ;
  879. ; get machine critical
  880. ;    
  881.     pushf
  882.     cli                ; no ints here
  883.  
  884.     in    al,PIC_MASK        ; REALLY no ints here!
  885.     Rest
  886.     mov    int_mask,al        ; save current mask
  887.     mov    al,0FFh
  888.     out    PIC_MASK,al        ; mask ALL ints
  889. ;
  890. ; check A20 state, then do the move
  891. ;
  892.     call    get_a20
  893.     push    ax            ; save A20 state
  894.  
  895.     mov    cx,move_length        ; word count from above
  896.     push    cs
  897.     pop    es
  898.     mov    si,offset gdt        ; ES:SI --> GDT
  899.     mov    ah,87h            ; move block
  900.     pushf
  901.     call    old_int_15        ; this will disable a20
  902.     rcl    cl,1            ; save carry
  903.     pop    ax
  904.     call    gate_a20        ; restore a20
  905.  
  906.     cli
  907.     mov    al,int_mask
  908.     out    PIC_MASK,al        ; restore int mask
  909.     @popf                ; re-enable ints
  910.  
  911.     test    cl,1            ; check for int 15 CF
  912.     jnz    mxm_gate_exit
  913.     mov    ax,1
  914.     mov    bl,0
  915.     and    hm_flags,not IN_MOVE    ; & CLC
  916.     ret
  917.  
  918. mxm_gate_exit:
  919.     mov    bl,ERR_A20_GATE
  920. mxm_error_exit:
  921.     and    hm_flags,not IN_MOVE
  922.     stc
  923.     ret
  924. xms_move_xmem    endp
  925. ;------------------------------------------------------------------------------
  926. ; Lock Extended Memory Block (function 0Ch)
  927. ;------------------------------------------------------------------------------
  928. xms_lock_xmem    proc    near
  929.     call    check_handle
  930.     jc    lxm_error_exit
  931.     mov    bl,ERR_OUT_OF_LOCKS
  932.     inc    [di].xlocks
  933.     jz    lxm_lock_wrap
  934.     mov    ax,[di].xbase
  935.     mul    _1024
  936.     mov    [bp].r_bx,ax        ; return base address
  937.     mov    [bp].r_dx,dx        ;  in DX:BX
  938.     mov    bl,al            ; because BL gets returned
  939.     mov    ax,1            ;  in common exit routine
  940.     clc
  941.     ret
  942. lxm_lock_wrap:
  943.     dec    [di].xlocks
  944. lxm_error_exit:
  945.     stc
  946.     ret
  947. xms_lock_xmem    endp
  948. ;------------------------------------------------------------------------------
  949. ; Unlock Extended Memory Block (function 0Dh)
  950. ;------------------------------------------------------------------------------
  951. xms_unlock_xmem    proc    near
  952.     call    check_handle
  953.     jc    uxm_error_exit
  954.     mov    bl,ERR_BLOCK_NOT_LOCKED
  955.     cmp    [di].xlocks,0
  956.     je    uxm_error_exit
  957.     dec    [di].xlocks
  958.     mov    ax,1
  959.     sub    bl,bl            ; & clc
  960.     ret
  961. uxm_error_exit:
  962.     stc
  963.     ret
  964. xms_unlock_xmem    endp
  965. ;------------------------------------------------------------------------------
  966. ; Get EMB Handle Information (function 0Eh)
  967. ;------------------------------------------------------------------------------
  968. xms_handle_info    proc    near
  969.     call    check_handle
  970.     jc    hi_exit
  971.     mov    ax,[di].xsize
  972.     mov    [bp].r_dx,ax
  973.     mov    bh,[di].xlocks
  974.  
  975.     mov    cx,MAX_HANDLES
  976.     mov    di,offset handle_table
  977.     sub    bl,bl            ; CF = 0 --> first find_free
  978. hi_loop:
  979.     call    find_free_handle    ; DI = blank handle
  980.     jc    hi_done
  981.     inc    bl            ; bump free handle count
  982.     stc
  983.     jmp    hi_loop
  984. hi_done:                ; BL = # of free handles
  985.     mov    [bp].r_bx,bx        ; (BL = returned BL)
  986.     mov    ax,1
  987.     clc
  988. hi_exit:
  989.     ret
  990. xms_handle_info    endp
  991. ;------------------------------------------------------------------------------
  992. ; invalid/unsupported function handler
  993. ;------------------------------------------------------------------------------
  994. if 0
  995. xms_bad_fn    proc    near
  996.     mov    bl,ERR_BAD_FN
  997.     stc
  998.     ret
  999. xms_bad_fn    endp
  1000. endif
  1001. ;------------------------------------------------------------------------------
  1002. ; main procedure - call far
  1003. ;------------------------------------------------------------------------------
  1004.     assume    cs:CSEG, ds:nothing, es:nothing
  1005.  
  1006. hm_main        proc    far
  1007.     jmp    short silly
  1008.     nop
  1009.     nop
  1010.     nop
  1011. silly:            ; goofy recommended start for XMS drivers
  1012.     pusha
  1013.     push    ds
  1014.     push    es
  1015.     mov    bp,sp    ; [bp] -> regframe
  1016.     push    cs
  1017.     pop    ds
  1018.     assume    ds:CSEG
  1019.     sub    bx,bx
  1020.     mov    bl,ah
  1021.     shl    bx,1
  1022.  
  1023.     test    bx,bx
  1024.     jz    skip_int_15_hook    ; init function does not hook int 15
  1025.  
  1026.     cmp    bx,ftable_end - ftable
  1027.     jae    hm_bad_fn
  1028.  
  1029.     test    hm_flags,INT15_HOOKED    ; if not already hooked..
  1030.     jnz    skip_int_15_hook
  1031.     call    hook_int_15        ; ..hook int 15h
  1032. skip_int_15_hook:
  1033.  
  1034.     call    ftable[bx]        ; dispatch function
  1035.     jc    fn_error
  1036. hm_exit:
  1037.     mov    [bp].r_bx.lsb,bl    ; always return BL
  1038.     mov    [bp].r_ax,ax        ;  and AX
  1039.     pop    es
  1040.     pop    ds
  1041.     popa
  1042.     ret
  1043. ;
  1044. ; misc. exceptions/errors down here to keep 'normal' flow clean
  1045. ;
  1046. hm_bad_fn:
  1047.     mov    bl,ERR_BAD_FN
  1048. fn_error:
  1049.     sub    ax,ax            ; AX = 0000
  1050.     jmp    hm_exit
  1051. hm_main        endp
  1052.  
  1053.     even
  1054. handle_table    label    byte
  1055.  
  1056. ;==============================================================================
  1057. ; init code (this is discarded after initialization)
  1058. ;
  1059.     assume    ds:CSEG, es:nothing
  1060.  
  1061. hello    db    13,10,"XMS Driver v ",AVERSION
  1062. if DEBUG
  1063.     db    " (Debug) -- entry point $"
  1064. endif
  1065. crlf2    db    13,10,13,10,"$"
  1066.  
  1067. err_    db    "XMS Fatal Error: $"
  1068. err_re    db    "An XMS driver is already installed$"
  1069. err_pta    db    "Unable to gain control of A20 line$"
  1070. err_mem    db    "Insufficent extended memory available$"
  1071. err_vd    db    "A VDISK device was detected$"
  1072. err_cpu    db    " -- Processor is not an 80286 or better --"
  1073. crlf    db    13,10,"$"
  1074.  
  1075. vdisk_id    db    "VDISK"
  1076. VDISK_ID_LEN    equ    $ - vdisk_id
  1077.  
  1078. ;------------------------------------------------------------------------------
  1079. if DEBUG
  1080. htoa4    proc    near        ; print AX as ASCII hex
  1081.     push    ax
  1082.     xchg    al,ah
  1083.     call    htoa2
  1084.     pop    ax
  1085. htoa2:    push    ax
  1086.     REPT    4
  1087.     shr    al,1
  1088.     ENDM
  1089.     call    htoa1
  1090.     pop    ax
  1091. htoa1:    and    al,0Fh
  1092.     add    al,90h
  1093.     daa
  1094.     adc    al,40h
  1095.     daa
  1096.     mov    dl,al
  1097.     mov    ah,2
  1098.     int    21h
  1099.     ret
  1100. htoa4    endp
  1101. endif
  1102. ;------------------------------------------------------------------------------
  1103. determine_xmemsize    proc    near
  1104.     mov    ah,88h
  1105.     int    15h        ; use BIOS - why not
  1106.     jc    dx_exit
  1107.     cmp    ax,MIN_XMEM
  1108.     jb    dx_exit        ; CF = 1
  1109.     sub    ax,64        ; reserve HIMEM area
  1110. ;
  1111. ; initialize first handle
  1112. ;
  1113.     mov    handle_table.xsize,ax
  1114.     mov    handle_table.xbase,XMEM_BASE
  1115.     mov    handle_table.xlocks,0
  1116.     mov    handle_table.xflags,0
  1117. ;
  1118.     mul    _1024
  1119.     add    maxaddr,ax    ; max allowed ext addr
  1120.     adc    maxaddr[2],dx
  1121.     clc
  1122. dx_exit:
  1123.     ret
  1124. determine_xmemsize    endp
  1125. ;------------------------------------------------------------------------------
  1126. test_a20_port    proc    near
  1127.     pushf
  1128.     cli
  1129.     call    enable_a20
  1130.     call    test_a20            ; see if its ON
  1131.     jz    a20_port_failed
  1132.     call    disable_a20
  1133.     call    test_a20            ; see if its OFF
  1134.     jnz    a20_port_failed
  1135.     @popf
  1136.     clc
  1137.     ret
  1138.  
  1139. a20_port_failed:
  1140.     @popf
  1141.     stc
  1142.     ret
  1143. test_a20_port    endp
  1144. ;------------------------------------------------------------------------------
  1145. check_for_vdisk    proc    near
  1146.     mov    ax,3519h
  1147.     int    21h        ; get int 19h vector 
  1148.     mov    di,VDISK_OFS
  1149.     mov    si,offset vdisk_id
  1150.     mov    cx,VDISK_ID_LEN
  1151.     cld
  1152.     rep    cmpsb        ; ZF=1 if found
  1153.     jz    cfd_found
  1154.  
  1155.     mov    ax,0FFFFh    ; check FFFF:0013
  1156.     mov    es,ax
  1157.     mov    di,VDISK_OFS+1
  1158.     mov    si,offset vdisk_id
  1159.     mov    cx,VDISK_ID_LEN
  1160.     cld
  1161.     rep    cmpsb        ; ZF=1 if found
  1162. cfd_found:
  1163.     ret
  1164. check_for_vdisk    endp
  1165. ;------------------------------------------------------------------------------
  1166. if 0     ; future expansion
  1167.  
  1168. get_cmd_line_args    proc    near
  1169.     push    ds
  1170. ;
  1171. ; find cmd line params
  1172. ;
  1173.     
  1174.     lds    si,req_ptr
  1175.     les    di,dword ptr [si].bpbofs    ; cmd line ptr
  1176.     mov    bx,di
  1177.     mov    cx,80
  1178.     mov    al,13            ; EOL
  1179.     cld
  1180.     repne    scasb
  1181. ;    jne    error_exit
  1182.     not    cx
  1183.     add    cx,80            ; CX = count to EOL
  1184.     mov    di,bx
  1185.     mov    al,'/'
  1186.     repne    scasb            ; look for separator
  1187.     jne    no_params
  1188.     mov    al,es:[di]
  1189.     or    al,' '            ; tolower
  1190.     cmp    al,'x'            ; whatever
  1191.     jne    no_params
  1192.     ; ( act on params )
  1193. no_params:
  1194.     pop    ds
  1195.     ret
  1196. get_cmd_line_args    endp
  1197.  
  1198. endif
  1199.  
  1200. ;------------------------------------------------------------------------------
  1201. ;
  1202. ; Determine CPU type
  1203. ;
  1204. ; Returns:
  1205. ;    AX = 1 -> 8086    (flags MSD always F)
  1206. ;    AX = 2 -> 80286    (flags MSD always 0)
  1207. ;    AX = 3 -> 80386    (flags MSD changable)
  1208. ;
  1209. get_cpu    proc    near
  1210.     mov    bx,1        ; assume 8086
  1211.     pushf            ; save    original flags
  1212.  
  1213.     pop    ax
  1214.     push    ax        ; AX = original flags
  1215.     and    ax,0FFFh    ; clear bits 15..12
  1216.     push    ax
  1217.     @popf            ; put AX into flags reg
  1218.     pushf
  1219.     pop    ax        ; AX = modified flags
  1220.     and    ax,0F000h    ; clear 3 LSDs
  1221.     cmp    ax,0F000h    
  1222.     je    got_cpu_type
  1223.  
  1224.     inc    bx        ; = 2 (try 286)
  1225.     pop    ax
  1226.     push    ax        ; AX = original flags
  1227.     or    ax,0F000h    ; try to set bits 15..12
  1228.     push    ax
  1229.     @popf            ; put AX into flags reg
  1230.     pushf
  1231.     pop    ax        ; AX = modified flags
  1232.     and    ax,0F000h    ; are any MSD bits set?
  1233.     jz    got_cpu_type    ; if not, its a 286
  1234.  
  1235.     inc    bx        ; if so, we have a 386 ( = 3)
  1236. got_cpu_type:
  1237.     @popf            ; restore original flags
  1238.     mov    ax,bx
  1239.     ret
  1240. get_cpu    endp
  1241.  
  1242. ;------------------------------------------------------------------------------
  1243. initialize    proc    near
  1244.     push    cs
  1245.     pop    ds
  1246.     assume    ds:CSEG
  1247.     or    hm_flags,INIT_DONE    ; indicate init performed
  1248.     @Print    hello
  1249. if DEBUG
  1250.     mov    ax,cs
  1251.     call    htoa4
  1252.     mov    dl,':'
  1253.     mov    ah,2
  1254.     int    21h
  1255.     mov    ax,offset hm_main
  1256.     call    htoa4
  1257.     @Print    crlf2
  1258. endif    
  1259.     mov    ax,4300h
  1260.     int    2Fh            ; check for re-install
  1261.     cmp    al,80h
  1262.     jne    no_xms_yet
  1263.     mov    dx,offset err_re
  1264.     jmp    error_exit
  1265. no_xms_yet:
  1266.     call    check_for_vdisk        ; check for VDISK type allocations
  1267.     jnz    no_vdisks
  1268.     mov    dx,offset err_vd
  1269.     jmp    error_exit
  1270. no_vdisks:
  1271.     call    get_cpu            ; check for 80286
  1272.     cmp    ax,2
  1273.     jae    cpu_ok
  1274.     mov    dx,offset err_cpu
  1275.     jmp    warning_exit
  1276. cpu_ok:
  1277.     call    test_a20_port        ; make sure our A20 control works
  1278.     jnc    port_ok
  1279.                     ; AT failed, try ps2
  1280.     mov    gate_a20,offset ps2_gate_a20
  1281.     mov    get_a20,offset ps2_get_a20
  1282.     call    test_a20_port
  1283.     jnc    port_ok
  1284.                     ; both failed, give up
  1285.     mov    dx,offset err_pta
  1286.     jmp    error_exit
  1287. port_ok:
  1288.     call    determine_xmemsize    ; get available extended memory
  1289.     jnc    memsize_ok
  1290.     mov    dx,offset err_mem
  1291.     jmp    error_exit
  1292. memsize_ok:
  1293. ;    call    get_cmd_line_args
  1294.  
  1295.     mov    dx,cs
  1296.     mov    ax,offset gdt
  1297.     call    segoff_to_physical
  1298.     mov    base_desc.basel,ax    ; set up base_desc
  1299.     mov    base_desc.baseh,dl
  1300.  
  1301.     mov    ax,352Fh        ; get old int 2f
  1302.     int    21h
  1303.     mov    old_int_2f.lsw,bx
  1304.     mov    old_int_2f.msw,es
  1305.     mov    ax,252Fh        ; set new int 2f
  1306.     mov    dx,offset int_2f
  1307.     int    21h
  1308.  
  1309.     mov    bx,offset handle_table    ; calculate size to keep
  1310.     add    bx,(MAX_HANDLES * type xms_handle)
  1311.     mov    ax,DD_DONE        ; tell DOS we're OK
  1312.     ret
  1313.  
  1314. error_exit:
  1315.     push    dx
  1316.     @Print    err_            ; print error message
  1317.     pop    dx
  1318. warning_exit:
  1319.     @Print
  1320.     @Print    crlf
  1321.     sub    bx,bx            ; keep offset = 0000
  1322.     mov    ax,DD_ERROR + DD_DONE     ; return error
  1323.     ret
  1324. initialize    endp
  1325.  
  1326. ;------------------------------------------------------------------------------
  1327. CSEG    ends
  1328.     end
  1329.