Path: 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> < <3839@altos86.Altos.COM> Reply-To: andyross@ddsw1.MCS.COM (Andrew Rossmann) Organization: ddsw1.MCS.COM Contributor, Wheeling, IL Lines: 507 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,! 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