home *** CD-ROM | disk | FTP | other *** search
/ Programmer 7500 / MAX_PROGRAMMERS.iso / PROGRAMS / UTILS / HARDWARE / INFOP120.ZIP / INFOPLUS.ASM next >
Encoding:
Assembly Source File  |  1990-07-29  |  17.7 KB  |  620 lines

  1. page    75, 110
  2.  
  3. ;--------------------------------------------------------------------
  4. ;
  5. ;       INFOPLUS.ASM
  6. ;
  7. ;       Version 1.20
  8. ;
  9. ;       Three subprograms used by INFOPLUS.PAS:
  10. ;
  11. ;               CPUID           - identifies host CPU and NDP (if
  12. ;                                       any)
  13. ;               DISKREAD        - reads absolute sectors from disk
  14. ;               LONGCALL        - calls a routine using a CALL FAR
  15. ;
  16. ;       Originally by:
  17. ;       Steve Grant
  18. ;       Long Beach, CA
  19. ;       January 13, 1989
  20. ;
  21. ;       mods by Andrew Rossmann (7/29/90)
  22. ;       286/386/486 detection adapted from code by Robert Collins.
  23. ;!!!!!!!Due to problems, Robert Collins code is no longer used. It is
  24. ;       included but commented out. The original detection code is now being
  25. ;       used, at the expense of '486 detection.
  26. ;--------------------------------------------------------------------
  27.  
  28. .286P
  29. .8087
  30.  
  31.         public  CPUID, DISKREAD, LONGCALL
  32.  
  33. ;-----------------------------------------------------------------------------
  34. ;!!used by invalid opcode cpu detection method.
  35. ; 80486 instruction macro -- because MASM 5.1 doesn't support the 80486!
  36. ;-----------------------------------------------------------------------------
  37. ;uncomment next 3 lines if not using TASM 2.0
  38. ;XADD    macro
  39. ;        db      0fh,0C0h,0D2h           ; 80486 instruction macro
  40. ;ENDM
  41.  
  42. CODE    segment byte
  43.  
  44. ;       Conditional jumps are all coded with the SHORT qualifier in
  45. ;       order to minimize the size of the .OBJ file output of Turbo
  46. ;       Assembler.
  47.  
  48. ;--------------------------------------------------------------------
  49.  
  50. CPUID   proc    near
  51.  
  52. assume  cs:CODE, ds:DATA, es:nothing, ss:nothing
  53.  
  54. ;       On entry:
  55. ;
  56. ;               BP
  57. ;       SP =>   near return address
  58. ;               offset  of a cpu_info_t record
  59. ;               segment "  "     "        "
  60. ;
  61. ;       On exit, the cpu_info_t record has been filled in as follows:
  62. ;
  63. ;               byte    = CPU type
  64. ;               word    = Machine Status Word
  65. ;               6 bytes = Global Descriptor Table
  66. ;               6 bytes = Interrupt Descriptor Table
  67. ;               boolean = segment register change/interrupt flag
  68. ;               byte    = NDP type
  69. ;               word    = NDP control word
  70.  
  71. mCPU    equ     byte ptr [bx]
  72. mMSW    equ     word ptr [bx + 1]
  73. mGDT    equ     [bx + 3]
  74. mIDT    equ     [bx + 9]
  75. mchkint equ     byte ptr [bx + 15]
  76. mNDP    equ     byte ptr [bx + 16]
  77. mNDPCW  equ     word ptr [bx + 17]
  78.  
  79. f8088   equ     0
  80. f8086   equ     1
  81. fV20    equ     2
  82. fV30    equ     3
  83. f80188  equ     4
  84. f80186  equ     5
  85. f80286  equ     6
  86. f80386  equ     7
  87. f80486  equ     8
  88. funk    =       0FFH
  89.  
  90. false   equ     0
  91. true    equ     1
  92.  
  93.         push    bp
  94.         mov     bp,sp
  95.         push    ds
  96.         lds     bx,[bp + 4]
  97.         call    cpu
  98.         call    chkint
  99.         call    ndp
  100.         pop     ds
  101.         pop     bp
  102.         ret     4
  103.  
  104. ;--------------------------------------------------------------------
  105.  
  106. cpu:
  107.  
  108. ; interrupt of multi-prefix string instruction
  109.  
  110.         mov     mCPU,funk               ;set CPU type to unknown
  111.         sti
  112.         mov     cx,0FFFFH
  113. rep     lods    byte ptr es:[si]
  114.         jcxz    short cpu_02
  115.         call    piq
  116.         cmp     dx,4
  117.         jg      short cpu_01
  118.         mov     mCPU,f8088
  119.         ret
  120. cpu_01:
  121.         cmp     dx,6
  122.         jne     short cpu_01a
  123.         mov     mCPU,f8086
  124. cpu_01a:
  125.         ret
  126. cpu_02:
  127.  
  128. ; number of bits in displacement register used by shift
  129.  
  130.         mov     al,0FFH
  131.         mov     cl,20H
  132.         shl     al,cl
  133.         or      al,al
  134.         jnz     short cpu_04
  135.         call    piq
  136.         cmp     dx,4
  137.         jg      short cpu_03
  138.         mov     mCPU,fV20
  139.         ret
  140. cpu_03:
  141.         cmp     dx,6
  142.         je      cpu_03a
  143.         jmp     CPUID_done
  144. cpu_03a:
  145.         mov     mCPU,fV30
  146.         ret
  147. cpu_04:
  148.  
  149. ; order of write/decrement by PUSH SP
  150.  
  151.         push    sp
  152.         pop     ax
  153.         cmp     ax,sp
  154.         je      short cpu_06
  155.         call    piq
  156.         cmp     dx,4
  157.         jg      short cpu_05
  158.         mov     mCPU,f80188
  159.         ret
  160. cpu_05:
  161.         cmp     dx,6
  162.         jne     short CPUID_done
  163.         mov     mCPU,f80186
  164.         ret
  165. ;!!!!!
  166. ; Due to problems with computers locking up, I am restoring the original
  167. ; detection routines.  The code using invalid op-codes format is being
  168. ; commented out.
  169. ;!!!!!
  170.  
  171. ;First, though, grab some tables
  172.  
  173. cpu_06:
  174.         smsw    mMSW
  175.         sgdt    mGDT
  176.         sidt    mIDT
  177. ; The following code is adapted from a program by Robert Collins
  178. ;since we probably have a 286, 386 or 486, we'll trap the invalid opcode
  179. ;handler, and try to determine the cpu type by using various opcodes.
  180. ;-----------------------------------------------------------------------------
  181. ; Setup INT6 handler
  182. ;-----------------------------------------------------------------------------
  183. ;        push    bx                      ;save bx
  184. ;        mov     ax,3506h                ;get INT 6 pointer
  185. ;        int     21h
  186. ;        mov     old_int06_seg,es        ;save
  187. ;        mov     old_int06_ofs,bx
  188. ;        push    ds                      ;save DS
  189. ;        mov     dx,seg INT6_handler     ;point to new handler
  190. ;        mov     ds,dx
  191. ;        mov     dx,offset INT6_handler
  192. ;        mov     ax,2506h                ;put into effect
  193. ;        int     21h
  194. ;        pop     ds                      ;restore DS
  195. ;        pop     bx
  196. ;        mov     mCPU,f80486             ; initialize CPU flag
  197. ;        xor     cx,cx                   ; initialize semaphore
  198. ;
  199. ;-----------------------------------------------------------------------------
  200. ; Now, try and determine which CPU we are by executing invalid opcodes.
  201. ; The instructions I chose to invoke invalid opcodes, are themselves rather
  202. ; benign.  In each case, the chosen instruction modifies the DX register,
  203. ; and nothing else.  No system parameters are changed, e.g. protected mode,
  204. ; or other CPU dependant features.
  205. ;-----------------------------------------------------------------------------
  206. ; The 80486 instruction 'XADD' xchanges the registers, then adds them.
  207. ;-----------------------------------------------------------------------------
  208. ;if not using TASM 2.0, comment out next 2 lines, and uncoment 3rd.
  209. ;.486
  210. ;        XADD    DX,DX                   ; 80486
  211. ;       XADD    ;DX,DX
  212. ;.286
  213. ;        jcxz    CPU_exit
  214. ;        mov     mCPU,f80386             ; set 80386 semaphore
  215. ;        xor     cx,cx                   ; CX=0
  216. ;
  217. ;-----------------------------------------------------------------------------
  218. ; For a description on the effects of the following instructions, look in
  219. ; the Intel Programmers Reference Manual's for the 80186, 80286, or 80386.
  220. ;-----------------------------------------------------------------------------
  221. ;.386
  222. ;        mov     edx,edx                 ; 80386
  223. ;.286P
  224. ;        jcxz    CPU_exit
  225. ;        mov     mCPU,f80286             ; set 80286 semaphore
  226. ;        xor     cx,cx                   ; CX=0
  227. ;
  228. ;        smsw    dx                      ; 80286
  229. ;        jcxz    CPU_exit
  230. ;        mov     mCPU,funk               ; set unknown CPU
  231. ;
  232. ;CPU_exit:
  233. ;        push    ds                      ;save DS
  234. ;        lds     dx,old_int06            ;get old pointer
  235. ;        mov     ax,2506h                ;restore it
  236. ;        int     21h
  237. ;        pop     ds
  238.  
  239. ;!!!!!!!
  240. ;!!! Original 286/386 detection code.
  241. ;!!!!!!!
  242. ; try to alter flag register bits 15-12
  243.  
  244.         pushf
  245.         pop     ax
  246.         mov     cx,ax
  247.         xor     cx,0F000H
  248.         push    cx
  249.         popf
  250.         pushf
  251.         pop     cx
  252.         cmp     ax,cx
  253.         jne     short cpu_07
  254.         mov     mCPU,f80286
  255.         ret
  256. cpu_07:
  257.         mov     mCPU,f80386
  258.         ret
  259. cpu_08:
  260.         mov     mCPU,funk
  261. CPUID_done:
  262.         ret
  263.  
  264. ;--------------------------------------------------------------------
  265.  
  266. piq:
  267.  
  268. ;       On exit:
  269. ;
  270. ;               DX      = length of prefetch instruction queue
  271. ;
  272. ;       This subroutine uses self-modifying code, but can
  273. ;       nevertheless be run repeatedly in the course of the calling
  274. ;       program.
  275.  
  276. count   =       7
  277. opincdx equ     42H                     ; inc dx opcode
  278. opnop   equ     90H                     ; nop opcode
  279.  
  280.         mov     al,opincdx
  281.         mov     cx,count
  282.         push    cx
  283.         push    cs
  284.         pop     es
  285.         mov     di,offset piq_01 - 1
  286.         push    di
  287.         std
  288.         rep stosb
  289.         mov     al,opnop
  290.         pop     di
  291.         pop     cx
  292.         xor     dx,dx
  293.         cli
  294.         rep stosb
  295.         rept    count
  296.         inc     dx
  297.         endm
  298. piq_01:
  299.         sti
  300.         ret
  301.  
  302. ;--------------------------------------------------------------------
  303.  
  304. chkint:
  305.  
  306. ; save old INT 01H vector
  307.  
  308.         push    bx
  309.         mov     ax,3501H
  310.         int     21H
  311.         mov     old_int01_ofs,bx
  312.         mov     old_int01_seg,es
  313.         pop     bx
  314.  
  315. ; redirect INT 01H vector
  316.  
  317.         push    ds
  318.         mov     ax,2501H
  319.         mov     dx,seg new_int01
  320.         mov     ds,dx
  321.         mov     dx,offset new_int01
  322.         int     21H
  323.         pop     ds
  324.  
  325. ; set TF and change SS -- did we trap on following instruction?
  326.  
  327.         pushf
  328.         pop     ax
  329.         or      ah,01H                  ; set TF
  330.         push    ax
  331.         popf
  332.         push    ss                      ; CPU may wait one
  333.                                         ; instruction before
  334.                                         ; recognizing single step
  335.                                         ; interrupt
  336.         pop     ss
  337. chkint_01:                              ; shouldn't ever trap here
  338.  
  339. ; restore old INT 01H vector
  340.  
  341.         push    ds
  342.         mov     ax,2501H
  343.         lds     dx,old_int01
  344.         int     21H
  345.         pop     ds
  346.         ret
  347.  
  348. ;--------------------------------------------------------------------
  349.  
  350. new_int01:
  351.  
  352. ;       INT 01H handler (single step)
  353. ;
  354. ;       On entry:
  355. ;
  356. ;       SP =>   IP
  357. ;               CS
  358. ;               flags
  359.  
  360.         sti
  361.         pop     ax                      ; IP
  362.         cmp     ax,offset chkint_01
  363.         jb      short new_int01_03
  364.         je      short new_int01_01
  365.         mov     mchkint,false
  366.         jmp     short new_int01_02
  367. new_int01_01:
  368.         mov     mchkint,true
  369. new_int01_02:
  370.         pop     cx                      ; CS
  371.         pop     dx                      ; flags
  372.         and     dh,0FEH                 ; turn off TF
  373.         push    dx                      ; flags
  374.         push    cx                      ; CS
  375. new_int01_03:
  376.         push    ax                      ; IP
  377.         iret
  378. ;
  379. ;!!!handler used by invalid opcode method
  380. ;-----------------------------------------------------------------------------
  381. ; INT6 handler sets a semaphore (CX=FFFF) and adjusts the return address to
  382. ; point past the invalid opcode.
  383. ;-----------------------------------------------------------------------------
  384. ;INT6_handler:
  385. ;        enter   0,0                     ; create new stack frame
  386. ;        dec     cx                      ; make CX=FFFF
  387. ;        add     word ptr ss:[bp][2],3   ; point past invalid opcode
  388. ;        leave
  389. ;        iret
  390.  
  391. ;--------------------------------------------------------------------
  392.  
  393. ndp:
  394.  
  395. fnone   equ     0
  396. f8087   equ     1
  397. f80287  equ     2
  398. f80387  equ     3
  399. funk    =       0FFH
  400.  
  401.         mov     word ptr ndp_cw,0000H
  402.         cli
  403.  
  404. ; The next three 80x87 instructions cannot carry the WAIT prefix,
  405. ; because there may not be an 80x87 for which to wait.  The WAIT is
  406. ; therefore emulated with a MOV CX,<value>! LOOP $ combination.
  407.  
  408.                                         ;       CPU     NDP
  409.         fnsave  ndp_save                ;        14     221
  410.         mov     cx,(221-6-1)/17+1       ;         4
  411.         loop    $                       ;  17*CX-12
  412.                                         ;   17*CX+6
  413.  
  414.         fninit                          ;         8       8
  415.         mov     cx,(8-0-1)/17+1         ;         4
  416.         loop    $                       ;  17*CX-12
  417.                                         ;     17*CX
  418.  
  419.         fnstcw  ndp_cw                  ;        14      24
  420.         mov     cx,(24-2-1)/17+1        ;         4
  421.         loop    $                       ;  17*CX-12
  422.                                         ;   17*CX+2
  423.  
  424.         sti
  425.         mov     ax,ndp_cw
  426.         cmp     ax,0000H
  427.         jne     short ndp_01
  428.         mov     mNDP,fnone
  429.         ret
  430. ndp_01:
  431.         cmp     ax,03FFH
  432.         jne     short ndp_02
  433.         mov     mNDP,f8087
  434.         jmp     short ndp_04
  435. ndp_02:
  436.  
  437. .287
  438.  
  439.         cmp     ax,037FH
  440.         jne     short ndp_05
  441.         fld1
  442.         fldz
  443.         fdiv
  444.         fld1
  445.         fchs
  446.         fldz
  447.         fdiv
  448.         fcom
  449.         fstsw   ndp_sw
  450.         mov     ax,ndp_sw
  451.         and     ah,41H                  ; C3, C0
  452.         cmp     ah,40H                  ; ST(0) = ST(1)
  453.         jne     short ndp_03
  454.         mov     mNDP,f80287
  455.         jmp     short ndp_04
  456. ndp_03:
  457.         cmp     ah,01H                  ; ST(0) < ST(1)
  458.         jne     short ndp_05
  459.         mov     mNDP,f80387
  460. ndp_04:
  461.  
  462. .8087
  463.  
  464.         frstor  ndp_save
  465.         fstcw   mNDPCW
  466.         ret
  467. ndp_05:
  468.         mov     mNDP,funk
  469.         ret
  470.  
  471. CPUID   endp
  472.  
  473. ;--------------------------------------------------------------------
  474.  
  475. DISKREAD        proc    near
  476.  
  477. assume cs:CODE, ds:DATA, es:nothing
  478.  
  479. ;       On entry:
  480. ;
  481. ;               BP
  482. ;       SP =>   near return address
  483. ;               offset  of disk buffer
  484. ;               segment "   "     "
  485. ;               number of sectors to read
  486. ;               starting logical sector number
  487. ;               drive number (0=A, 1=B, etc.)
  488. ;
  489. ;       On exit:
  490. ;
  491. ;               AX      = function result
  492. ;                       00      - function successful
  493. ;                       01..FF  - DOS INT 25H error result
  494.  
  495.         drive                   equ     [bp + 12]
  496.         starting_sector         equ     [bp + 10]
  497.         number_of_sectors       equ     [bp + 8]
  498.         buffer                  equ     [bp + 4]
  499.  
  500.         push    bp
  501.         mov     bp,sp
  502.         mov     ax,3000h                ;get DOS version
  503.         int     21h
  504.         cmp     al,4                    ;DOS 4?
  505.         jb      read3                   ;Read assuming DOS 3.x
  506.         mov     al,drive
  507.         mov     bx,starting_sector      ;copy info into parameter block
  508.         mov     extd_starting_sector_lo,bx
  509.         mov     extd_starting_sector_hi,0       ;We're only using lower part
  510.         mov     bx,number_of_sectors
  511.         mov     extd_number_of_sectors,bx
  512.         les     bx,buffer               ;get seg:ofs of buffer in ES:BX
  513.         mov     extd_bufofs,bx          ;put into block
  514.         mov     extd_bufseg,es
  515.         mov     bx,offset dos4_block    ;DS:BX points to block
  516.         mov     cx,-1                   ;-1 means extended read
  517.         push    ds                      ;save DS (not really needed, but lets
  518.                                         ;me share code with DOS 3 read.)
  519.         jmp     short readit
  520.  
  521. read3:  mov     al,drive
  522.         mov     dx,starting_sector
  523.         mov     cx,number_of_sectors
  524.         push    ds
  525.         lds     bx,buffer               ;get seg:ofs of buffer in DS:BX
  526. readit: int     25H
  527.         inc     sp                      ; fix broken stack
  528.         inc     sp
  529.         pop     ds
  530.         jc      short diskread_01
  531.         xor     ax,ax
  532.  
  533. diskread_01:
  534.  
  535.         pop     bp
  536.         ret     10
  537.  
  538. DISKREAD        endp
  539.  
  540. ;
  541. ;LONGCALL will call a routine using a CALL FAR. This is used by XMS
  542. ;
  543. ;Pascal format: procedure longcall(AXi: word; var addr: longint;
  544. ;                                  var AXo, BXo, DXo: word); external;
  545. ;
  546.  
  547. longcall        proc    near
  548.         assume  cs:CODE, ds:DATA, es:nothing
  549.  
  550. AXi     equ     [bp+20]                 ;set up correct pointers
  551. addr    equ     [bp+16]
  552. AXo     equ     [bp+12]
  553. BXo     equ     [bp+8]
  554. DXo     equ     [bp+4]
  555.  
  556.         push    bp                      ;setup BP
  557.         mov     bp,sp
  558.         les     di,addr                 ;copy address to call into
  559.         mov     ax,es:[di]              ; local variable
  560.         mov     word ptr address,ax
  561.         mov     ax,es:[di+2]
  562.         mov     word ptr address+2,ax
  563.         mov     ax,AXi                  ;get function number
  564.         call    dword ptr address       ;do far call
  565.         les     di,DXo                  ;save DX, BX, and AX to correct
  566.         mov     [es:di],dx              ; Pascal variables.
  567.         les     di,BXo
  568.         mov     [es:di],bx
  569.         les     di,AXo
  570.         mov     [es:di],ax
  571.         pop     bp                      ;restore stack
  572.         ret     18
  573. longcall endp
  574.  
  575. code    ends
  576.  
  577. ;--------------------------------------------------------------------
  578.  
  579. DATA    segment byte
  580.  
  581. ; storage for CPUID
  582.  
  583. ; redirected INT 01H vector
  584.  
  585. old_int01       label   dword
  586. old_int01_ofs   dw      ?
  587. old_int01_seg   dw      ?
  588.  
  589. ;!!!Used by invalid opcode method
  590. ; redirected INT 6 vector
  591. ;old_int06       label   dword
  592. ;old_int06_ofs   dw      ?
  593. ;old_int06_seg   dw      ?
  594.  
  595. ; storage for NDPID
  596.  
  597. ; 80x87 control word after initialization, status word after divide by zero
  598.  
  599. ndp_cw          dw      ?
  600. ndp_save        db      94 dup (?)
  601. ndp_sw          dw      ?
  602.  
  603. ; storage for DISKREAD
  604.  
  605. ; DOS 4.0 extended read parameter block
  606. dos4_block                      label   byte
  607. extd_starting_sector_lo         dw      ?
  608. extd_starting_sector_hi         dw      ?
  609. extd_number_of_sectors          dw      ?
  610. extd_bufofs                     dw      ?
  611. extd_bufseg                     dw      ?
  612.  
  613. ; storage for LONGCALL
  614.  
  615. address dd      ?
  616.  
  617. DATA    ends
  618.  
  619.         end
  620.