home *** CD-ROM | disk | FTP | other *** search
/ Frostbyte's 1980s DOS Shareware Collection / floppyshareware.zip / floppyshareware / DOOG / INFOP131.ZIP / INFOPLUS.ASM next >
Assembly Source File  |  1990-09-04  |  24KB  |  794 lines

  1. ;--------------------------------------------------------------------
  2. ;
  3. ;       INFOPLUS.ASM
  4. ;
  5. ;       Version 1.30
  6. ;
  7. ;       Six subprograms used by INFOPLUS.PAS:
  8. ;
  9. ;               CPUID           - identifies host CPU and NDP (if
  10. ;                                       any)
  11. ;               DISKREAD        - reads absolute sectors from disk
  12. ;               LONGCALL        - calls a routine using a CALL FAR
  13. ;               ATIINFO         - for accessing ATI VGAWonder cards
  14. ;               ALTINTR         - calls interrupts with a true INT call
  15. ;               ALTMSDOS        - calls DOS with a true INT call
  16. ;
  17. ;       Originally by:
  18. ;       Steve Grant
  19. ;       Long Beach, CA
  20. ;       January 13, 1989
  21. ;
  22. ;       mods by Andrew Rossmann (9/4/90)
  23. ;--------------------------------------------------------------------
  24.  
  25. .286P
  26. .8087
  27.  
  28.         public  CPUID, DISKREAD, LONGCALL, ATIINFO, ALTINTR, ALTMSDOS
  29.  
  30. CODE    segment byte
  31.  
  32. ;       Conditional jumps are all coded with the SHORT qualifier in
  33. ;       order to minimize the size of the .OBJ file output of Turbo
  34. ;       Assembler.
  35.  
  36. ;--------------------------------------------------------------------
  37.  
  38. CPUID   proc    far
  39.  
  40. assume  cs:CODE, ds:DATA, es:nothing, ss:nothing
  41.  
  42. ;       On entry:
  43. ;
  44. ;               BP
  45. ;       SP =>   near return address
  46. ;               offset  of a cpu_info_t record
  47. ;               segment "  "     "        "
  48. ;       also, the test type byte should be a 'C' or 'N' to execute the
  49. ;       CPU or NDP tests.
  50. ;
  51. ;       On exit, the cpu_info_t record has been filled in as follows:
  52. ;
  53. ;               byte    = CPU type
  54. ;               word    = Machine Status Word
  55. ;               6 bytes = Global Descriptor Table
  56. ;               6 bytes = Interrupt Descriptor Table
  57. ;               boolean = segment register change/interrupt flag
  58. ;               byte    = NDP type
  59. ;               word    = NDP control word
  60. ;               byte    = Weitek presence
  61. ;               byte    = test type (C, N, or W)
  62.  
  63. cpu_info        equ     [bp + 6]
  64.  
  65. mCPU    equ     byte ptr [bx]
  66. mMSW    equ     word ptr [bx + 1]
  67. mGDT    equ     [bx + 3]
  68. mIDT    equ     [bx + 9]
  69. mchkint equ     byte ptr [bx + 15]
  70. mNDP    equ     byte ptr [bx + 16]
  71. mNDPCW  equ     word ptr [bx + 17]
  72. mWeitek equ     byte ptr [bx + 19]
  73. mtest   equ     byte ptr [bx + 20]
  74.  
  75. f8088   equ     0
  76. f8086   equ     1
  77. fV20    equ     2
  78. fV30    equ     3
  79. f80188  equ     4
  80. f80186  equ     5
  81. f80286  equ     6
  82. f80386  equ     7
  83. f80486  equ     8
  84. funk    =       0FFH
  85.  
  86. false   equ     0
  87. true    equ     1
  88.  
  89.         push    bp
  90.         mov     bp,sp
  91.         push    ds
  92.         lds     bx,cpu_info
  93.         cmp     mtest, 'C'
  94.         jnz     skipcpu
  95.         call    cpu
  96.         call    chkint
  97. skipcpu:
  98.         cmp     mtest, 'N'
  99.         jnz     skipndp
  100.         call    ndp
  101. skipndp:
  102.         cmp     mtest, 'W'
  103.         jnz     skipweitek
  104.         call    weitek
  105. skipweitek:
  106.         pop     ds
  107.         pop     bp
  108.         ret     4
  109. CPUID   endp
  110.  
  111. ;--------------------------------------------------------------------
  112.  
  113. cpu     proc    near
  114.  
  115. ; interrupt of multi-prefix string instruction
  116.  
  117.         mov     mCPU,funk               ;set CPU type to unknown
  118.         sti
  119.         mov     cx,0FFFFH
  120. rep     lods    byte ptr es:[si]
  121.         jcxz    short cpu_02
  122.         call    piq
  123.         cmp     dx,4
  124.         jg      short cpu_01
  125.         mov     mCPU,f8088
  126.         jmp     cpu_done
  127. cpu_01:
  128.         cmp     dx,6
  129.         jne     cpu_01a
  130.         mov     mCPU,f8086
  131. cpu_01a:
  132.         jmp     cpu_done
  133. cpu_02:
  134.  
  135. ; number of bits in displacement register used by shift
  136.  
  137.         mov     al,0FFH
  138.         mov     cl,20H
  139.         shl     al,cl
  140.         or      al,al
  141.         jnz     short cpu_04
  142.         call    piq
  143.         cmp     dx,4
  144.         jg      short cpu_03
  145.         mov     mCPU,fV20
  146.         jmp     cpu_done
  147. cpu_03:
  148.         cmp     dx,6
  149.         je      cpu_03a
  150.         jmp     cpu_done
  151. cpu_03a:
  152.         mov     mCPU,fV30
  153.         jmp     cpu_done
  154. cpu_04:
  155.  
  156. ; order of write/decrement by PUSH SP
  157.  
  158.         push    sp
  159.         pop     ax
  160.         cmp     ax,sp
  161.         je      short cpu_06
  162.         call    piq
  163.         cmp     dx,4
  164.         jg      short cpu_05
  165.         mov     mCPU,f80188
  166.         jmp     cpu_done
  167. cpu_05:
  168.         cmp     dx,6
  169.         jne     short cpu_done
  170.         mov     mCPU,f80186
  171.         jmp     cpu_done
  172.  
  173. ; We most likely have a 286, 386 or 486 CPU by now
  174. ;First, grab some tables
  175.  
  176. cpu_06:
  177.         smsw    mMSW
  178.         sgdt    mGDT
  179.         sidt    mIDT
  180.  
  181. ;!!!!!!!
  182. ;!!! Original 286/386 detection code (modified 8/10/90)
  183. ;!!! Modified by code supplied by John Levine, apparantly from an Intel
  184. ;!!! '486 manual.
  185. ;!!!!!!!
  186.  
  187.         pushf                           ;put flags into CX
  188.         pop     cx
  189.         and     cx,0fffh                ;mask off upper 4 bits
  190.         push    cx
  191.         popf
  192.         pushf
  193.         pop     ax
  194.         and     ax,0f000h               ;look only at upper 4 bits
  195.         cmp     ax,0f000h               ;88/86 etc.. turn them on
  196.         jz      badcpu                  ;not 286/386/486!!!
  197.         or      cx,0f000h               ;force upper 4 bits on
  198.         push    cx
  199.         popf
  200.         pushf
  201.         pop     ax
  202.         and     ax,0f000h
  203.         jz      found286                ;bits are zeroed in real mode 286
  204. ;
  205. ;since we probably have have a 386 or 486 by now, we need to do some 32-bit
  206. ;work. Detect the 486 by seeing if the Alignment Check flag is settable. This
  207. ;flag only exists on the '486.
  208. ;
  209. .386
  210.         and     esp,0FFFFh              ;use only 64K stack
  211.         mov     edx,esp                 ;save current stack position
  212.         and     esp,0FFFCh              ;dword align to avoid traps
  213.         pushfd                          ;push 32 bit flag
  214.         pop     eax
  215.         mov     ecx,eax                 ;save current flags
  216.         xor     eax,40000h              ;flip AC (alignment check) flag
  217.         push    eax
  218.         popfd
  219.         pushfd
  220.         pop     eax
  221.         xor     eax,ecx                 ;eliminate all but AC bit
  222.         push    ecx                     ;restore flags
  223.         popfd
  224.         mov     esp,edx                 ;restore stack position
  225.         test    eax,40000h              ;is bit set?
  226. .286
  227.         jz      found386                ;if not, is a 386
  228.         mov     mCPU,f80486             ;must be a 486!!
  229.         jmp     short cpu_done
  230. found286:
  231.         mov     mCPU,f80286
  232.         jmp     short cpu_done
  233. found386:
  234.         mov     mCPU,f80386
  235.         jmp     short cpu_done
  236. badcpu:
  237.         mov     mCPU,funk               ;how'd an 8088 get this far?????
  238. CPU_done:
  239.         ret
  240. cpu     endp
  241. ;--------------------------------------------------------------------
  242.  
  243. piq     proc    near
  244.  
  245. ;       On exit:
  246. ;
  247. ;               DX      = length of prefetch instruction queue
  248. ;
  249. ;       This subroutine uses self-modifying code, but can
  250. ;       nevertheless be run repeatedly in the course of the calling
  251. ;       program.
  252.  
  253. count   =       7
  254. opincdx equ     42H                     ; inc dx opcode
  255. opnop   equ     90H                     ; nop opcode
  256.  
  257.         mov     al,opincdx
  258.         mov     cx,count
  259.         push    cx
  260.         push    cs
  261.         pop     es
  262.         mov     di,offset piq_01 - 1
  263.         push    di
  264.         std
  265.         rep stosb
  266.         mov     al,opnop
  267.         pop     di
  268.         pop     cx
  269.         xor     dx,dx
  270.         cli
  271.         rep stosb
  272.         rept    count
  273.         inc     dx
  274.         endm
  275. piq_01:
  276.         sti
  277.         ret
  278. piq     endp
  279.  
  280. ;--------------------------------------------------------------------
  281.  
  282. chkint  proc    near
  283.  
  284. ; save old INT 01H vector
  285.  
  286.         push    bx
  287.         mov     ax,3501H
  288.         int     21H
  289.         mov     old_int01_ofs,bx
  290.         mov     old_int01_seg,es
  291.         pop     bx
  292.  
  293. ; redirect INT 01H vector
  294.  
  295.         push    ds
  296.         mov     ax,2501H
  297.         mov     dx,seg new_int01
  298.         mov     ds,dx
  299.         mov     dx,offset new_int01
  300.         int     21H
  301.         pop     ds
  302.  
  303. ; set TF and change SS -- did we trap on following instruction?
  304.  
  305.         pushf
  306.         pop     ax
  307.         or      ah,01H                  ; set TF
  308.         push    ax
  309.         popf
  310.         push    ss                      ; CPU may wait one
  311.                                         ; instruction before
  312.                                         ; recognizing single step
  313.                                         ; interrupt
  314.         pop     ss
  315. chkint_01:                              ; shouldn't ever trap here
  316.  
  317. ; restore old INT 01H vector
  318.  
  319.         push    ds
  320.         mov     ax,2501H
  321.         lds     dx,old_int01
  322.         int     21H
  323.         pop     ds
  324.         ret
  325. chkint  endp
  326. ;--------------------------------------------------------------------
  327.  
  328. new_int01       proc    near
  329.  
  330. ;       INT 01H handler (single step)
  331. ;
  332. ;       On entry:
  333. ;
  334. ;       SP =>   IP
  335. ;               CS
  336. ;               flags
  337.  
  338.         sti
  339.         pop     ax                      ; IP
  340.         cmp     ax,offset chkint_01
  341.         jb      short new_int01_03
  342.         je      short new_int01_01
  343.         mov     mchkint,false
  344.         jmp     short new_int01_02
  345. new_int01_01:
  346.         mov     mchkint,true
  347. new_int01_02:
  348.         pop     cx                      ; CS
  349.         pop     dx                      ; flags
  350.         and     dh,0FEH                 ; turn off TF
  351.         push    dx                      ; flags
  352.         push    cx                      ; CS
  353. new_int01_03:
  354.         push    ax                      ; IP
  355.         iret
  356. new_int01       endp
  357. ;--------------------------------------------------------------------
  358.  
  359. ndp     proc    near
  360.  
  361. fnone   equ     0
  362. f8087   equ     1
  363. f80287  equ     2
  364. f80387  equ     3
  365. funk    =       0FFH
  366.  
  367.  
  368. ; The next two 80x87 instructions cannot carry the WAIT prefix,
  369. ; because there may not be an 80x87 for which to wait.  The WAIT is
  370. ; therefore emulated with a MOV CX,<value>! LOOP $ combination.
  371.  
  372. .287
  373.         mov     word ptr ndp_cw,0000H
  374.         cli                     ;no interrupts during this test
  375.  
  376.         fninit                  ;initialize NDP
  377.         mov     cx,2
  378.         loop    $
  379.  
  380.         fnstcw  ndp_cw          ;store control word in ndp_cw
  381.         mov     cx,14h
  382.         loop    $
  383.  
  384.         sti
  385.         mov     ax,ndp_cw       ;check for valid status word
  386.         cmp     ah,3            ;is NDP present?
  387.         je      short ndp_01    ;if 3, must be there
  388.         mov     mNDP,fnone
  389.         jmp     short ndp_done
  390.  
  391. ndp_01:
  392.         cmp     ax,03FFH        ;check if 8087
  393.         jne     short ndp_02
  394.         mov     mNDP,f8087
  395.         jmp     short ndp_04
  396. ndp_02:
  397.  
  398. .287
  399.  
  400.         cmp     ax,037FH        ;check if 286/387/486
  401.         jne     short ndp_05    ;must be garbage
  402.  
  403. ;detect 287 or 387
  404.  
  405.         fld1                    ;Load +1.0 onto NDP stack
  406.         fldz                    ;Load +0.0 onto NDP stack
  407.         fdiv                    ;do +1/0
  408.         fld1                    ;Load +1.0 onto NDP stack
  409.         fchs                    ;Change to -1.0
  410.         fldz                    ;Load +0.0 onto NDP stack
  411.         fdiv                    ;do -1/0
  412.         fcom                    ;compare
  413.         fstsw   ndp_sw
  414.         mov     ax,ndp_sw
  415.         and     ah,41H          ; C3, C0
  416.         cmp     ah,40H          ; ST(0) = ST(1)
  417.         jne     short ndp_03
  418.         mov     mNDP,f80287
  419.         jmp     short ndp_04
  420. ndp_03:
  421.         cmp     ah,01H          ; ST(0) < ST(1)
  422.         jne     short ndp_05
  423.         mov     mNDP,f80387
  424. ndp_04:
  425.  
  426. .8087
  427.         fstcw   mNDPCW          ;save status for INFOPLUS
  428.         ret
  429. ndp_05:
  430.         mov     mNDP,funk
  431. ndp_done:
  432.         ret
  433. ndp     endp
  434.  
  435. ;------------------------------------------------------------------------------
  436. ; This checks to see if the BIOS reports a Weitek math coprocessor. This should
  437. ; only be called if a 386 or 486 is found.
  438. ; NOTE!! This may not work with all computers!!
  439.  
  440. fnoWeitek       equ     0
  441. fWeitek         equ     1
  442. fWeitek_real    equ     81h
  443.  
  444. weitek  proc    near
  445. .386
  446.         xor     eax,eax                 ;zero everything
  447.         int     11h                     ;do equipment check
  448.         test    eax,01000000h           ;check bit 24, set if Weitek present
  449.         je      no_weitek
  450.         mov     mWeitek,fWeitek
  451.         test    eax,0800000h            ;check bit 23, set if Weitek can be
  452.         je      weitek_done             ; addressed in real mode
  453.         mov     mWeitek,fWeitek_real
  454.         jmp     short weitek_done
  455. no_weitek:
  456.         mov     mWeitek,fnoWeitek
  457. weitek_done:
  458.         ret
  459. .286
  460. weitek  endp
  461.  
  462. ;--------------------------------------------------------------------
  463.  
  464. DISKREAD        proc    far
  465.  
  466. assume cs:CODE, ds:DATA, es:nothing
  467.  
  468. ;       On entry:
  469. ;
  470. ;               BP
  471. ;       SP =>   near return address
  472. ;               offset  of disk buffer
  473. ;               segment "   "     "
  474. ;               number of sectors to read
  475. ;               starting logical sector number
  476. ;               drive number (0=A, 1=B, etc.)
  477. ;
  478. ;       On exit:
  479. ;
  480. ;               AX      = function result
  481. ;                       00      - function successful
  482. ;                       01..FF  - DOS INT 25H error result
  483.  
  484.         drive                   equ     [bp + 14]
  485.         starting_sector         equ     [bp + 12]
  486.         number_of_sectors       equ     [bp + 10]
  487.         buffer                  equ     [bp + 6]
  488.  
  489.         push    bp
  490.         mov     bp,sp
  491.         mov     ax,3000h                ;get DOS version
  492.         int     21h
  493.         cmp     al,4                    ;DOS 4?
  494.         jb      read3                   ;Read assuming DOS 3.x
  495.         mov     al,drive
  496.         mov     bx,starting_sector      ;copy info into parameter block
  497.         mov     extd_starting_sector_lo,bx
  498.         mov     extd_starting_sector_hi,0       ;We're only using lower part
  499.         mov     bx,number_of_sectors
  500.         mov     extd_number_of_sectors,bx
  501.         les     bx,buffer               ;get seg:ofs of buffer in ES:BX
  502.         mov     extd_bufofs,bx          ;put into block
  503.         mov     extd_bufseg,es
  504.         mov     bx,offset dos4_block    ;DS:BX points to block
  505.         mov     cx,-1                   ;-1 means extended read
  506.         push    ds                      ;save DS (not really needed, but lets
  507.                                         ;me share code with DOS 3 read.)
  508.         jmp     short readit
  509.  
  510. read3:  mov     al,drive
  511.         mov     dx,starting_sector
  512.         mov     cx,number_of_sectors
  513.         push    ds
  514.         lds     bx,buffer               ;get seg:ofs of buffer in DS:BX
  515. readit: int     25H
  516.         inc     sp                      ; fix broken stack
  517.         inc     sp
  518.         pop     ds
  519.         jc      short diskread_01
  520.         xor     ax,ax
  521. diskread_01:
  522.  
  523.         pop     bp
  524.         ret     10
  525.  
  526. DISKREAD        endp
  527.  
  528. ;
  529. ;LONGCALL will call a routine using a CALL FAR.
  530. ;
  531. ;Pascal format: procedure longcall(addr: longint; var regs: registers); external;
  532. ;
  533.  
  534. longcall        proc    far
  535.         assume  cs:CODE, ds:DATA, es:nothing
  536.  
  537. regaddr equ     [bp + 6]
  538. addr    equ     [bp + 10]
  539.  
  540.         push    bp
  541.         mov     bp,sp
  542.         push    ds
  543.         mov     ax,addr                 ;copy calling address for later use
  544.         mov     word ptr cs:address,ax
  545.         mov     ax,addr+2
  546.         mov     word ptr cs:address+2,ax
  547.         lds     si,regaddr              ;get pointer to regs
  548.         mov     cs:ds_save,ds           ;save needed ones
  549.         mov     cs:si_save,si
  550.         cld                             ;go forward
  551.         lodsw                           ;load AX and hold it
  552.         push    ax
  553.         lodsw                           ;load BX
  554.         mov     bx,ax
  555.         lodsw                           ;load CX
  556.         mov     cx,ax
  557.         lodsw                           ;load DX
  558.         mov     dx,ax
  559.         lodsw                           ;load BP
  560.         mov     bp,ax
  561.         lodsw                           ;load SI and hold it
  562.         push    ax
  563.         lodsw                           ;load DI
  564.         mov     di,ax
  565.         lodsw                           ;load DS and hold it
  566.         push    ax
  567.         lodsw                           ;load ES
  568.         mov     es,ax
  569.         lodsw                           ;load Flags
  570.         push    ax
  571.         popf
  572.         pop     ds                      ;get rest of regs
  573.         pop     si
  574.         pop     ax
  575.         call    dword ptr cs:address    ;make far call
  576.         pushf                           ;save flags and modified regs
  577.         push    es
  578.         push    di
  579.         mov     es,cs:save_ds           ;get regs pointer into ES:DI
  580.         mov     di,cs:save_si
  581.         cld                             ;go forward
  582.         stosw                           ;save AX
  583.         mov     ax,bx
  584.         stosw                           ;save BX
  585.         mov     ax,cx
  586.         stosw                           ;save CX
  587.         mov     ax,dx
  588.         stosw                           ;save DX
  589.         mov     ax,bp
  590.         stosw                           ;save BP
  591.         mov     ax,si
  592.         stosw                           ;save SI
  593.         pop     ax
  594.         stosw                           ;save DI
  595.         mov     ax,ds
  596.         stosw                           ;save DS
  597.         pop     ax
  598.         stosw                           ;save ES
  599.         pop     ax
  600.         stosw                           ;save Flags
  601.         pop     ds                      ;restore regs
  602.         pop     bp
  603.         ret     8
  604.  
  605. address dd      ?
  606. ds_save dw      ?
  607. si_save dw      ?
  608.  
  609. longcall endp
  610.  
  611. ;
  612. ; ATIINFO is used in the Video identification routine to get special
  613. ; information from ATI VGA Wonder cards.
  614. ;
  615. ; Pascal format: function ATIinfo(data_in: byte; register: word): byte;
  616. ;
  617. ATIinfo         proc    far
  618.         assume  cs:CODE, ds:DATA, es:NOTHING
  619.  
  620. data_in         equ     [bp+8]
  621. register        equ     [bp+6]
  622.  
  623.         push    bp
  624.         mov     bp,sp
  625.         mov     dx,register             ;get register
  626.         mov     ax,data_in              ;get command word (actually byte)
  627.         cli                             ;no interrupts
  628.         out     dx,al
  629.         inc     dx                      ;next port
  630.         in      al,dx                   ;get result
  631.         sti                             ;restore interrupts
  632.         mov     sp,bp
  633.         pop     bp
  634.         ret     4
  635.  
  636. ATIinfo endp
  637.  
  638. ; AltIntr is an alternative to the Intr function. The standard Intr function
  639. ; does not do a true Interrupt!! Instead, it gets the address of the interrupt
  640. ; from the interrupt table, loads all the registers, and then does a RETF!!!
  641. ; The address of a return routine has been pushed on the stack so that it
  642. ; returns to TP and unloads the registers. This was probably done because
  643. ; Intel saw to it that all interrupt numbers must be immediate, and Borland
  644. ; didn't want to use self-modifying code.
  645. ;   NOTE: The MsDos routine is ALSO affected by this problem. It just stuffs
  646. ; a 21h into the stack, and calls Intr!!! So you can use ALTMSDOS instead!
  647. ;   Now, normally, the above procedure works perfectly fine, except under 1
  648. ; condition. When the CPU is under protected or Virtual 86 mode. When in those
  649. ; modes, a program with higher privileges can trap an interrupt and act on it.
  650. ; I found this out the hard way by going nuts wondering why I couldn't detect
  651. ; DPMI drivers or Windows!! My alternative Interrupt functions identically to
  652. ; Borlands, but uses self-modifying code to generate a true interrupt. To
  653. ; prevent possible problems with CPU pipelining, the entry point is near the
  654. ; end of the code, and then jumps back to continue.
  655. ;
  656. ; Pascal format: procedure AltIntr(intno: byte; regs: registers); external;
  657.  
  658. ALTINTRP        proc    far
  659.         assume  cs:CODE, ds:DATA, es:NOTHING
  660.  
  661. regaddr equ     [bp + 6]
  662. intno   equ     [bp + 10]
  663.  
  664.  
  665. altcont:
  666.         lds     si,regaddr              ;point DS:SI to regs
  667.         mov     cs:save_ds,ds           ;save pointer for return
  668.         mov     cs:save_si,si
  669.         cld                             ;go forward
  670.         lodsw                           ;load AX and hold it
  671.         push    ax
  672.         lodsw                           ;load BX
  673.         mov     bx,ax
  674.         lodsw                           ;load CX
  675.         mov     cx,ax
  676.         lodsw                           ;load DX
  677.         mov     dx,ax
  678.         lodsw                           ;load BP
  679.         mov     bp,ax
  680.         lodsw                           ;load SI and hold it
  681.         push    ax
  682.         lodsw                           ;load DI
  683.         mov     di,ax
  684.         lodsw                           ;load DS and hold it
  685.         push    ax
  686.         lodsw                           ;load ES
  687.         mov     es,ax
  688.         lodsw                           ;load Flags
  689.         push    ax
  690.         popf
  691.         pop     ds                      ;get rest of regs
  692.         pop     si
  693.         pop     ax
  694.         db      0cdh                    ;Int opcode
  695. intrpt  db      ?                       ;loaded with real interrupt
  696.         pushf                           ;save flags and modified regs
  697.         push    es
  698.         push    di
  699.         mov     es,cs:save_ds           ;get regs pointer into ES:DI
  700.         mov     di,cs:save_si
  701.         cld                             ;go forward
  702.         stosw                           ;save AX
  703.         mov     ax,bx
  704.         stosw                           ;save BX
  705.         mov     ax,cx
  706.         stosw                           ;save CX
  707.         mov     ax,dx
  708.         stosw                           ;save DX
  709.         mov     ax,bp
  710.         stosw                           ;save BP
  711.         mov     ax,si
  712.         stosw                           ;save SI
  713.         pop     ax
  714.         stosw                           ;save DI
  715.         mov     ax,ds
  716.         stosw                           ;save DS
  717.         pop     ax
  718.         stosw                           ;save ES
  719.         pop     ax
  720.         stosw                           ;save Flags
  721.         pop     ds                      ;restore regs
  722.         pop     bp
  723.         ret     6
  724.  
  725. altintr:
  726.         push    bp
  727.         mov     bp,sp
  728.         push    ds                      ;save DS, because we screw it up
  729.         mov     al,intno                ;get interrupt number to use
  730.         mov     cs:intrpt,al            ;and modify our code
  731.         jmp     altcont                 ;continue with rest of code
  732.  
  733. ;local storage
  734.  
  735. save_ds dw      ?
  736. save_si dw      ?
  737.  
  738. ALTINTRP        endp
  739. ;
  740. ; Pascal format: procedure AltMsDos(var regs: registers); external;
  741. ;
  742. ALTMSDOS        proc    far
  743.         assume  cs:CODE, ds:DATA, es:NOTHING
  744.  
  745.         pop     si              ;back track a bit so we can stuff
  746.         pop     dx              ;interrupt number in
  747.         pop     cx
  748.         pop     bx
  749.         mov     al,21h          ;push interrupt number
  750.         push    ax
  751.         push    bx
  752.         push    cx              ;restore other info
  753.         push    dx
  754.         push    si
  755.         jmp     ALTINTR         ;do interrupt call
  756.  
  757. ALTMSDOS        endp
  758.  
  759. code    ends
  760.  
  761. ;--------------------------------------------------------------------
  762.  
  763. DATA    segment byte
  764.  
  765. ; storage for CPUID
  766.  
  767. ; redirected INT 01H vector
  768.  
  769. old_int01       label   dword
  770. old_int01_ofs   dw      ?
  771. old_int01_seg   dw      ?
  772.  
  773. ; storage for NDPID
  774.  
  775. ; 80x87 control word after initialization, status word after divide by zero
  776.  
  777. ndp_cw          dw      ?
  778. ndp_sw          dw      ?
  779.  
  780. ; storage for DISKREAD
  781.  
  782. ; DOS 4.0 extended read parameter block
  783. dos4_block                      label   byte
  784. extd_starting_sector_lo         dw      ?
  785. extd_starting_sector_hi         dw      ?
  786. extd_number_of_sectors          dw      ?
  787. extd_bufofs                     dw      ?
  788. extd_bufseg                     dw      ?
  789.  
  790.  
  791. DATA    ends
  792.  
  793.         end
  794.