home *** CD-ROM | disk | FTP | other *** search
- page 75, 110
-
- ;--------------------------------------------------------------------
- ;
- ; INFOPLUS.ASM
- ;
- ; Version 1.20
- ;
- ; Three subprograms used by INFOPLUS.PAS:
- ;
- ; CPUID - identifies host CPU and NDP (if
- ; any)
- ; DISKREAD - reads absolute sectors from disk
- ; LONGCALL - calls a routine using a CALL FAR
- ;
- ; Originally by:
- ; Steve Grant
- ; Long Beach, CA
- ; January 13, 1989
- ;
- ; mods by Andrew Rossmann (7/29/90)
- ; 286/386/486 detection adapted from code by Robert Collins.
- ;!!!!!!!Due to problems, Robert Collins code is no longer used. It is
- ; included but commented out. The original detection code is now being
- ; used, at the expense of '486 detection.
- ;--------------------------------------------------------------------
-
- .286P
- .8087
-
- public CPUID, DISKREAD, LONGCALL
-
- ;-----------------------------------------------------------------------------
- ;!!used by invalid opcode cpu detection method.
- ; 80486 instruction macro -- because MASM 5.1 doesn't support the 80486!
- ;-----------------------------------------------------------------------------
- ;uncomment next 3 lines if not using TASM 2.0
- ;XADD macro
- ; db 0fh,0C0h,0D2h ; 80486 instruction macro
- ;ENDM
-
- CODE segment byte
-
- ; Conditional jumps are all coded with the SHORT qualifier in
- ; order to minimize the size of the .OBJ file output of Turbo
- ; Assembler.
-
- ;--------------------------------------------------------------------
-
- CPUID proc near
-
- assume cs:CODE, ds:DATA, es:nothing, ss:nothing
-
- ; On entry:
- ;
- ; BP
- ; SP => near return address
- ; offset of a cpu_info_t record
- ; segment " " " "
- ;
- ; On exit, the cpu_info_t record has been filled in as follows:
- ;
- ; byte = CPU type
- ; word = Machine Status Word
- ; 6 bytes = Global Descriptor Table
- ; 6 bytes = Interrupt Descriptor Table
- ; boolean = segment register change/interrupt flag
- ; byte = NDP type
- ; word = NDP control word
-
- mCPU equ byte ptr [bx]
- mMSW equ word ptr [bx + 1]
- mGDT equ [bx + 3]
- mIDT equ [bx + 9]
- mchkint equ byte ptr [bx + 15]
- mNDP equ byte ptr [bx + 16]
- mNDPCW equ word ptr [bx + 17]
-
- f8088 equ 0
- f8086 equ 1
- fV20 equ 2
- fV30 equ 3
- f80188 equ 4
- f80186 equ 5
- f80286 equ 6
- f80386 equ 7
- f80486 equ 8
- funk = 0FFH
-
- false equ 0
- true equ 1
-
- push bp
- mov bp,sp
- push ds
- lds bx,[bp + 4]
- call cpu
- call chkint
- call ndp
- pop ds
- pop bp
- ret 4
-
- ;--------------------------------------------------------------------
-
- cpu:
-
- ; interrupt of multi-prefix string instruction
-
- mov mCPU,funk ;set CPU type to unknown
- sti
- mov cx,0FFFFH
- rep lods byte ptr es:[si]
- jcxz short cpu_02
- call piq
- cmp dx,4
- jg short cpu_01
- mov mCPU,f8088
- ret
- cpu_01:
- cmp dx,6
- jne short cpu_01a
- mov mCPU,f8086
- cpu_01a:
- ret
- cpu_02:
-
- ; number of bits in displacement register used by shift
-
- mov al,0FFH
- mov cl,20H
- shl al,cl
- or al,al
- jnz short cpu_04
- call piq
- cmp dx,4
- jg short cpu_03
- mov mCPU,fV20
- ret
- cpu_03:
- cmp dx,6
- je cpu_03a
- jmp CPUID_done
- cpu_03a:
- mov mCPU,fV30
- ret
- cpu_04:
-
- ; order of write/decrement by PUSH SP
-
- push sp
- pop ax
- cmp ax,sp
- je short cpu_06
- call piq
- cmp dx,4
- jg short cpu_05
- mov mCPU,f80188
- ret
- cpu_05:
- cmp dx,6
- jne short CPUID_done
- mov mCPU,f80186
- ret
- ;!!!!!
- ; Due to problems with computers locking up, I am restoring the original
- ; detection routines. The code using invalid op-codes format is being
- ; commented out.
- ;!!!!!
-
- ;First, though, grab some tables
-
- cpu_06:
- smsw mMSW
- sgdt mGDT
- sidt mIDT
- ; The following code is adapted from a program by Robert Collins
- ;since we probably have a 286, 386 or 486, we'll trap the invalid opcode
- ;handler, and try to determine the cpu type by using various opcodes.
- ;-----------------------------------------------------------------------------
- ; Setup INT6 handler
- ;-----------------------------------------------------------------------------
- ; push bx ;save bx
- ; mov ax,3506h ;get INT 6 pointer
- ; int 21h
- ; mov old_int06_seg,es ;save
- ; mov old_int06_ofs,bx
- ; push ds ;save DS
- ; mov dx,seg INT6_handler ;point to new handler
- ; mov ds,dx
- ; mov dx,offset INT6_handler
- ; mov ax,2506h ;put into effect
- ; int 21h
- ; pop ds ;restore DS
- ; pop bx
- ; mov mCPU,f80486 ; initialize CPU flag
- ; xor cx,cx ; initialize semaphore
- ;
- ;-----------------------------------------------------------------------------
- ; Now, try and determine which CPU we are by executing invalid opcodes.
- ; The instructions I chose to invoke invalid opcodes, are themselves rather
- ; benign. In each case, the chosen instruction modifies the DX register,
- ; and nothing else. No system parameters are changed, e.g. protected mode,
- ; or other CPU dependant features.
- ;-----------------------------------------------------------------------------
- ; The 80486 instruction 'XADD' xchanges the registers, then adds them.
- ;-----------------------------------------------------------------------------
- ;if not using TASM 2.0, comment out next 2 lines, and uncoment 3rd.
- ;.486
- ; XADD DX,DX ; 80486
- ; XADD ;DX,DX
- ;.286
- ; jcxz CPU_exit
- ; mov mCPU,f80386 ; set 80386 semaphore
- ; xor cx,cx ; CX=0
- ;
- ;-----------------------------------------------------------------------------
- ; For a description on the effects of the following instructions, look in
- ; the Intel Programmers Reference Manual's for the 80186, 80286, or 80386.
- ;-----------------------------------------------------------------------------
- ;.386
- ; mov edx,edx ; 80386
- ;.286P
- ; jcxz CPU_exit
- ; mov mCPU,f80286 ; set 80286 semaphore
- ; xor cx,cx ; CX=0
- ;
- ; smsw dx ; 80286
- ; jcxz CPU_exit
- ; mov mCPU,funk ; set unknown CPU
- ;
- ;CPU_exit:
- ; push ds ;save DS
- ; lds dx,old_int06 ;get old pointer
- ; mov ax,2506h ;restore it
- ; int 21h
- ; pop ds
-
- ;!!!!!!!
- ;!!! Original 286/386 detection code.
- ;!!!!!!!
- ; try to alter flag register bits 15-12
-
- pushf
- pop ax
- mov cx,ax
- xor cx,0F000H
- push cx
- popf
- pushf
- pop cx
- cmp ax,cx
- jne short cpu_07
- mov mCPU,f80286
- ret
- cpu_07:
- mov mCPU,f80386
- ret
- cpu_08:
- mov mCPU,funk
- CPUID_done:
- ret
-
- ;--------------------------------------------------------------------
-
- piq:
-
- ; On exit:
- ;
- ; DX = length of prefetch instruction queue
- ;
- ; This subroutine uses self-modifying code, but can
- ; nevertheless be run repeatedly in the course of the calling
- ; program.
-
- count = 7
- opincdx equ 42H ; inc dx opcode
- opnop equ 90H ; nop opcode
-
- mov al,opincdx
- mov cx,count
- push cx
- push cs
- pop es
- mov di,offset piq_01 - 1
- push di
- std
- rep stosb
- mov al,opnop
- pop di
- pop cx
- xor dx,dx
- cli
- rep stosb
- rept count
- inc dx
- endm
- piq_01:
- sti
- ret
-
- ;--------------------------------------------------------------------
-
- chkint:
-
- ; save old INT 01H vector
-
- push bx
- mov ax,3501H
- int 21H
- mov old_int01_ofs,bx
- mov old_int01_seg,es
- pop bx
-
- ; redirect INT 01H vector
-
- push ds
- mov ax,2501H
- mov dx,seg new_int01
- mov ds,dx
- mov dx,offset new_int01
- int 21H
- pop ds
-
- ; set TF and change SS -- did we trap on following instruction?
-
- pushf
- pop ax
- or ah,01H ; set TF
- push ax
- popf
- push ss ; CPU may wait one
- ; instruction before
- ; recognizing single step
- ; interrupt
- pop ss
- chkint_01: ; shouldn't ever trap here
-
- ; restore old INT 01H vector
-
- push ds
- mov ax,2501H
- lds dx,old_int01
- int 21H
- pop ds
- ret
-
- ;--------------------------------------------------------------------
-
- new_int01:
-
- ; INT 01H handler (single step)
- ;
- ; On entry:
- ;
- ; SP => IP
- ; CS
- ; flags
-
- sti
- pop ax ; IP
- cmp ax,offset chkint_01
- jb short new_int01_03
- je short new_int01_01
- mov mchkint,false
- jmp short new_int01_02
- new_int01_01:
- mov mchkint,true
- new_int01_02:
- pop cx ; CS
- pop dx ; flags
- and dh,0FEH ; turn off TF
- push dx ; flags
- push cx ; CS
- new_int01_03:
- push ax ; IP
- iret
- ;
- ;!!!handler used by invalid opcode method
- ;-----------------------------------------------------------------------------
- ; INT6 handler sets a semaphore (CX=FFFF) and adjusts the return address to
- ; point past the invalid opcode.
- ;-----------------------------------------------------------------------------
- ;INT6_handler:
- ; enter 0,0 ; create new stack frame
- ; dec cx ; make CX=FFFF
- ; add word ptr ss:[bp][2],3 ; point past invalid opcode
- ; leave
- ; iret
-
- ;--------------------------------------------------------------------
-
- ndp:
-
- fnone equ 0
- f8087 equ 1
- f80287 equ 2
- f80387 equ 3
- funk = 0FFH
-
- mov word ptr ndp_cw,0000H
- cli
-
- ; The next three 80x87 instructions cannot carry the WAIT prefix,
- ; because there may not be an 80x87 for which to wait. The WAIT is
- ; therefore emulated with a MOV CX,<value>! LOOP $ combination.
-
- ; CPU NDP
- fnsave ndp_save ; 14 221
- mov cx,(221-6-1)/17+1 ; 4
- loop $ ; 17*CX-12
- ; 17*CX+6
-
- fninit ; 8 8
- mov cx,(8-0-1)/17+1 ; 4
- loop $ ; 17*CX-12
- ; 17*CX
-
- fnstcw ndp_cw ; 14 24
- mov cx,(24-2-1)/17+1 ; 4
- loop $ ; 17*CX-12
- ; 17*CX+2
-
- sti
- mov ax,ndp_cw
- cmp ax,0000H
- jne short ndp_01
- mov mNDP,fnone
- ret
- ndp_01:
- cmp ax,03FFH
- jne short ndp_02
- mov mNDP,f8087
- jmp short ndp_04
- ndp_02:
-
- .287
-
- cmp ax,037FH
- jne short ndp_05
- fld1
- fldz
- fdiv
- fld1
- fchs
- fldz
- fdiv
- fcom
- fstsw ndp_sw
- mov ax,ndp_sw
- and ah,41H ; C3, C0
- cmp ah,40H ; ST(0) = ST(1)
- jne short ndp_03
- mov mNDP,f80287
- jmp short ndp_04
- ndp_03:
- cmp ah,01H ; ST(0) < ST(1)
- jne short ndp_05
- mov mNDP,f80387
- ndp_04:
-
- .8087
-
- frstor ndp_save
- fstcw mNDPCW
- ret
- ndp_05:
- mov mNDP,funk
- ret
-
- CPUID endp
-
- ;--------------------------------------------------------------------
-
- DISKREAD proc near
-
- assume cs:CODE, ds:DATA, es:nothing
-
- ; On entry:
- ;
- ; BP
- ; SP => near return address
- ; offset of disk buffer
- ; segment " " "
- ; number of sectors to read
- ; starting logical sector number
- ; drive number (0=A, 1=B, etc.)
- ;
- ; On exit:
- ;
- ; AX = function result
- ; 00 - function successful
- ; 01..FF - DOS INT 25H error result
-
- drive equ [bp + 12]
- starting_sector equ [bp + 10]
- number_of_sectors equ [bp + 8]
- buffer equ [bp + 4]
-
- push bp
- mov bp,sp
- mov ax,3000h ;get DOS version
- int 21h
- cmp al,4 ;DOS 4?
- jb read3 ;Read assuming DOS 3.x
- mov al,drive
- mov bx,starting_sector ;copy info into parameter block
- mov extd_starting_sector_lo,bx
- mov extd_starting_sector_hi,0 ;We're only using lower part
- mov bx,number_of_sectors
- mov extd_number_of_sectors,bx
- les bx,buffer ;get seg:ofs of buffer in ES:BX
- mov extd_bufofs,bx ;put into block
- mov extd_bufseg,es
- mov bx,offset dos4_block ;DS:BX points to block
- mov cx,-1 ;-1 means extended read
- push ds ;save DS (not really needed, but lets
- ;me share code with DOS 3 read.)
- jmp short readit
-
- read3: mov al,drive
- mov dx,starting_sector
- mov cx,number_of_sectors
- push ds
- lds bx,buffer ;get seg:ofs of buffer in DS:BX
- readit: int 25H
- inc sp ; fix broken stack
- inc sp
- pop ds
- jc short diskread_01
- xor ax,ax
-
- diskread_01:
-
- pop bp
- ret 10
-
- DISKREAD endp
-
- ;
- ;LONGCALL will call a routine using a CALL FAR. This is used by XMS
- ;
- ;Pascal format: procedure longcall(AXi: word; var addr: longint;
- ; var AXo, BXo, DXo: word); external;
- ;
-
- longcall proc near
- assume cs:CODE, ds:DATA, es:nothing
-
- AXi equ [bp+20] ;set up correct pointers
- addr equ [bp+16]
- AXo equ [bp+12]
- BXo equ [bp+8]
- DXo equ [bp+4]
-
- push bp ;setup BP
- mov bp,sp
- les di,addr ;copy address to call into
- mov ax,es:[di] ; local variable
- mov word ptr address,ax
- mov ax,es:[di+2]
- mov word ptr address+2,ax
- mov ax,AXi ;get function number
- call dword ptr address ;do far call
- les di,DXo ;save DX, BX, and AX to correct
- mov [es:di],dx ; Pascal variables.
- les di,BXo
- mov [es:di],bx
- les di,AXo
- mov [es:di],ax
- pop bp ;restore stack
- ret 18
- longcall endp
-
- code ends
-
- ;--------------------------------------------------------------------
-
- DATA segment byte
-
- ; storage for CPUID
-
- ; redirected INT 01H vector
-
- old_int01 label dword
- old_int01_ofs dw ?
- old_int01_seg dw ?
-
- ;!!!Used by invalid opcode method
- ; redirected INT 6 vector
- ;old_int06 label dword
- ;old_int06_ofs dw ?
- ;old_int06_seg dw ?
-
- ; storage for NDPID
-
- ; 80x87 control word after initialization, status word after divide by zero
-
- ndp_cw dw ?
- ndp_save db 94 dup (?)
- ndp_sw dw ?
-
- ; storage for DISKREAD
-
- ; DOS 4.0 extended read parameter block
- dos4_block label byte
- extd_starting_sector_lo dw ?
- extd_starting_sector_hi dw ?
- extd_number_of_sectors dw ?
- extd_bufofs dw ?
- extd_bufseg dw ?
-
- ; storage for LONGCALL
-
- address dd ?
-
- DATA ends
-
- end