🚀 go-pugleaf

RetroBBS NetNews Server

Inspired by RockSolid Light RIP Retro Guy

Article View: comp.os.msdos.programmer
Article #1962

Re: Re: Detecting an 80486

#1962
From: Andrew Rossmann
Date: Tue, 21 Aug 1990 22:34
507 lines
13566 bytes
In article <3839@altos86.Altos.COM> rcollins@altos86.UUCP (Robert Collins) writes:
>In article <9008161307.AA11621@esegue.segue.boston.ma.us> johnl@esegue.segue.boston.ma.us (John R. Levine) writes:
>>
>>can't try it myself.)  If flag bit 18 really doesn't work, it might work to
>>try wiggling bit 18 in CR0 which is unimplemented on the 386.
>>
>
>You can't access CR0 in CPL3.  So setting any bit in CR0 in V86 mode will
>be trapped.  I have tried setting bit18 in EFLAGS, and found it not to
>be latched in real mode.  I found this astonishing, and therefore posted
>my results.  Since that posting I did further testing, and found my first
>conclusion to be wrong.

  I just took a 'peek' at Nortons SI, version 5 (the new one). It detects
the '486 by fiddling with bit 18! So, apparantly, they must think it's OK,
although I should think they have probably tested it, too.

  What follows is the latest version of the CPU/NDP code from INFOPLUS.
I've slightly tweaked the '486 detection, and further changed the NDP
detection. I hope to get that problem fixed soon, if this doesn't do it.
Some people have said that the 386 w/ AMI BIOS and no 387 is giving the
most problems.

  Andrew Rossmann
  andyross@ddsw1.MCS.COM

P.S.> Version 1.3 of INFOPLUS is still under development.


;--------------------------------------------------------------------
;
;       INFOPLUS.ASM
;
;       Version 1.30
;
;       Four 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
;		ATIINFO		- for accessing ATI VGAWonder cards
;
;       Originally by:
;       Steve Grant
;       Long Beach, CA
;       January 13, 1989
;
;       mods by Andrew Rossmann (8/19/90)
;--------------------------------------------------------------------

.286P
.8087

        public  CPUID, DISKREAD, LONGCALL, ATIINFO, AltIntr

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 "  "     "        "
;	also, the test type byte should be 'C', 'N' or 'W' to execute the
;	CPU or NDP or Weitek tests.
;
;       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
;		byte	= Weitek presence
;		byte	= test type (C, N, or W)

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]
mWeitek	equ	byte ptr [bx + 19]
mtest	equ	byte ptr [bx + 20]

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]
	cmp	mtest, 'C'
	jnz	skipcpu
        call    cpu
        call    chkint
skipcpu:
	cmp	mtest, 'N'
	jnz	skipndp
        call    ndp
skipndp:
	cmp	mtest, 'W'
	jnz	skipweitek
	call	weitek
skipweitek:
        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

;First, grab some tables

cpu_06:
        smsw    mMSW
        sgdt    mGDT
        sidt    mIDT

;!!!!!!!
;!!! Original 286/386 detection code (modified 8/10/90)
;!!! Modified by code supplied by John Levine, apparantly from an Intel
;!!! '486 manual.
;!!!!!!!

        pushf				;put flags into CX
	pop	cx
	and	cx,0fffh		;mask off upper 4 bits
	push	cx
	popf
	pushf
	pop	ax
	and	ax,0f000h		;look only at upper 4 bits
	cmp	ax,0f000h		;88/86 etc.. turn them on
	jz	badcpu			;not 286/386/486!!!
	or	cx,0f000h		;force upper 4 bits on
	push	cx
	popf
	pushf
	pop	ax
	and	ax,0f000h
	jz	found286		;bits are zeroed in real mode 286
;
;since we probably have have a 386 or 486 by now, we need to do some 32-bit
;work. Detect the 486 by seeing if the Alignment Check flag is settable. This
;flag only exists on the '486.
;
.386
	and	esp,0FFFFh		;use only 64K stack
	mov	edx,esp			;save current stack position
	and	esp,0FFFCh		;dword align to avoid traps
	pushfd				;push 32 bit flag
	pop	eax
	mov	ecx,eax			;save current flags
	xor	eax,40000h		;flip AC (alignment check) flag
	push	eax
	popfd
	pushfd
	pop	eax
	xor	eax,ecx			;eliminate all but AC bit
	push	ecx			;restore flags
	popfd
	mov	esp,edx			;restore stack position
	test	eax,40000h		;is bit set?
.286
	jz	found386		;if not, is a 386
	mov	mCPU,f80486		;must be a 486!!
	jmp	short CPUID_done
found286:
        mov     mCPU,f80286
	jmp	short CPUID_done
found386:
        mov     mCPU,f80386
        jmp	short CPUID_done
badcpu:
	mov	mCPU,funk		;how'd an 8088 get this far?????
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
;--------------------------------------------------------------------

ndp:

fnone   equ     0
f8087   equ     1
f80287  equ     2
f80387  equ     3
funk    =       0FFH

        mov     word ptr ndp_cw,0000H
        cli

; The next two 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.

.287
	cli			;no interrupts during this test
;
; if there are problems, try uncommenting the following lines
;	xor	ax,ax
;	out	0f0h,al

        finit			;initialize NDP
        mov     cx,2
        loop    $

        fstcw  ndp_cw		;store status word in ndp_cw
        mov     cx,14h
        loop    $

        sti
        mov     ax,ndp_cw		;check for valid status word
        cmp     ah,3			;is NDP present?
        je      short ndp_01		;if 3, must be there
        mov     mNDP,fnone
        jmp	short ndp_done

ndp_01:
        cmp     ax,03FFH		;check if 8087
        jne     short ndp_02
        mov     mNDP,f8087
        jmp     short ndp_04
ndp_02:

.287

        cmp     ax,037FH		;check if 286/387/486
        jne     short ndp_05		;must be garbage

;detect 287 or 387

        fld1				;Load +1.0 onto NDP stack
        fldz				;Load +0.0 onto NDP stack
        fdiv				;do +1/0
        fld1				;Load +1.0 onto NDP stack
        fchs				;Change to -1.0
        fldz				;Load +0.0 onto NDP stack
        fdiv				;do -1/0
        fcom				;compare 
        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
        fstcw   mNDPCW			;save status for INFOPLUS
        ret
ndp_05:
        mov     mNDP,funk
ndp_done:
        ret

; This checks to see if the BIOS reports a Weitek math coprocessor. This should
; only be called if a 386 or 486 is found.
; NOTE!! This may not work with all computers!!

fnoWeitek	equ	0
fWeitek		equ	1
fWeitek_real	equ	81h

weitek:
.386
	xor	eax,eax			;zero everything
	int	11h			;do equipment check
	test	eax,01000000h		;check bit 24, set if Weitek present
	je	no_weitek
	mov	mWeitek,fWeitek
	test	eax,0800000h		;check bit 23, set if Weitek can be
	je	weitek_done		; addressed in real mode
	mov	mWeitek,fWeitek_real
	jmp	short weitek_done
no_weitek:
	mov	mWeitek,fnoWeitek
weitek_done:
	ret
.286
CPUID   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      ?

; storage for NDPID

; 80x87 control word after initialization, status word after divide by zero

ndp_cw          dw      ?
ndp_sw          dw      ?

DATA    ends

        end
Technical Details
Message-ID: <1990Aug21.223404.19523@ddsw1.MCS.COM>
Path: arc1-ca.pugleaf.net!utzoo!utgpu!news-server.csri.toronto.edu!rutgers!mcdchg!ddsw1!andyross
References: <26a858b9@ralf> <3817@altos86.Altos.COM> <1990Aug14.025550.17669@esegue.segue.boston.ma.us> <OTTO.90Aug15022916@tukki.jyu.fi> < <3839@altos86.Altos.COM>

Show Full Headers
Complete Article Headers
Path: arc1-ca.pugleaf.net!utzoo!utgpu!news-server.csri.toronto.edu!rutgers!mcdchg!ddsw1!andyross
From: andyross@ddsw1.MCS.COM (Andrew Rossmann)
Newsgroups: comp.os.msdos.programmer
Subject: Re: Re: Detecting an 80486
Message-ID: <1990Aug21.223404.19523@ddsw1.MCS.COM>
Date: 21 Aug 90 22:34:04 GMT
References: <26a858b9@ralf> <3817@altos86.Altos.COM> <1990Aug14.025550.17669@esegue.segue.boston.ma.us> <OTTO.90Aug15022916@tukki.jyu.fi> < <3839@altos86.Altos.COM>
Reply-To: andyross@ddsw1.MCS.COM (Andrew Rossmann)
Organization: ddsw1.MCS.COM Contributor, Wheeling, IL
Lines: 507