;****************************************************************************
;*
;* The Universal VESA VBE
;*
;* Copyright (C) 1996 SciTech Software
;* All rights reserved.
;*
;* Filename: $Workfile: cpu.asm $
;* Version: $Revision: 1.2 $
;*
;* Language: 8086 Assembler
;* Environment: IBM PC Real Mode and 16/32 bit Protected Mode.
;*
;* Description: Autodetection routine to determine the type of CPU installed
;* in the system.
;*
;* $Date: 20 Jun 1996 13:32:38 $ $Author: KendallB $
;*
;****************************************************************************
IDEAL
INCLUDE "model.mac" ; Memory model macros
header cpu ; Set up memory model
;****************************************************************************
;
; Equates used by queryCPU routine.
;
;****************************************************************************
; Central Processing Unit type codes
CPU86 = 0 ; 8086/88 type processor
CPU186 = 1 ; 80186 type processor
CPU286 = 2 ; 80286 type processor
CPU286p = 3 ; 80286 type processor in protected mode
CPU386 = 4 ; 80386 type processor
CPU386p = 5 ; 80386 type processor in protected mode
CPU486 = 6 ; 80486 type processor
CPU486p = 7 ; 80486 type processor in protected mode
CPU586 = 8 ; Pentium type processor
CPU586p = 9 ; Pentium type processor in protected mode
begcodeseg cpu ; Start of code segment
P386 ; Turn on 386 instructions
;----------------------------------------------------------------------------
; cpu_type SV_queryCpu(void)
;----------------------------------------------------------------------------
; Determine type of processor present.
;----------------------------------------------------------------------------
procstartdll16 _SV_queryCpu
push _bx
push _bp ; We MUST save bp for initialization code...
ife flatmodel
mov _ax,CPU86 ; Default to 8086/8088 processor
push sp
pop bx ; BX holds the value of SP or SP-2
cmp bx,sp ; 88/86/186 pushes the value of SP-2
je @@Check286 ; Must be a 286/386/486 type processor
mov cl,32 ; 186 uses count mod 32 = 0
shl bx,cl ; 86 shifts 32 bits left so ax = 0
jz @@Done ; zero: shifted out all bits so 86/88
mov _ax,CPU186 ; nonzero: no shift, so 186
jz @@Done
@@Check286: ; First check for 386/486 in 32 bit mode
pushf ; Test for 16 or 32 operand size:
mov bx,sp ; pushed 2 or 4 bytes of flags
popf
inc bx
inc bx
cmp bx,sp ; did pushf change sp by 2?
jnz @@Check386 ; 32 bit push, so it is a 386/486
sub sp,6 ; Is it a 286/386/486 in 16 bit mode?
mov bp,sp
sgdt [QWORD ptr bp] ; 80286/386/486 specific instrucion
add sp,4 ; Get global descriptor table
pop bx
inc bh ; Third word of GDT = -1 for 286
jnz @@Check486 ; We have a 386/486
mov _ax,CPU286 ; We have a 286
jmp @@TestPROT
@@Check386:
endif
; Distinguish an 80386 from an 80486. Bit 18 (40000H) of EFLAGS register
; is used only in the 486. This code flips it and tests if anything happened.
mov edx,esp ; Save stack pointer
and esp,not 3 ; Align stack pointer to prevent a fault
; when we set the AC flag on a 486
pushfd ; Copy the EFLAGS register
pop eax ; into register eax
mov ecx,eax ; Save the original EFLAGS value
xor eax,40000H ; Flip the AC flag bit
push eax ; Try to put the modified value back
popfd ; into the EFLAGS register
pushfd ; Copy the EFLAGS register again
pop eax ; into eax
xor eax,ecx ; Compare the old and new AC bits
shr eax,18 ; Shift and mask to get the AC comparison bit
and eax,1 ; in the low order position of eax
push ecx
popfd ; Restore EFLAGS that were saved on entry
mov esp,edx ; And restore stack pointer to saved value
mov bx,ax ; and move into bx
; At this point bx = 0 for a 386, or bx = 1 for a 486
test bx,bx
jnz @@Check486 ; Check for the presence of a 486/P5
mov _ax,CPU386
jnz @@TestPROT ; We have a 386
@@Check486:
; Distinguish between the i486 and Pentium by the ability to set the ID flag
; in the EFLAGS register. If the ID flag is set, then we can use the CPUID
; instruction to determine the final version of the chip. Otherwise we
; simply have an 80486.
pushfd ; push original EFLAGS
pop eax ; get original EFLAGS in eax
mov ecx,eax ; save original EFLAGS in ecx
or eax,200000h ; flip ID bit in EFLAGS
push eax ; save for EFLAGS
popfd ; copy to EFLAGS
pushfd ; push EFLAGS
pop eax ; get new EFLAGS value
xor eax,ecx
mov _ax,CPU486
jz @@TestProt ; We have an old i486 (flag would not set)
; Now execute the CPUID instruction to determine the vendor, family, model
; and stepping (some new 486's answer to the CPUID test also).
mov eax,1 ; set up for CPUID instruction
; cpuid
db 0Fh, 0A2h ; Opcodes for CPUID instruction
and eax,0F00H ; mask everything but family
shr eax,8
cmp al,5
mov _ax,CPU486
jl @@TestProt ; We have an i486
mov _ax,CPU586 ; We have a Pentium(tm)
@@TestPROT:
smsw cx ; protected? machine status -> cx
ror cx,1 ; protection bit -> carry flag
jnc @@Done ; Real mode if no carry
inc _ax ; Protected: return value + 1
@@Done:
pop _bp ; Restore bp
pop _bx
ret ; We are done
procenddll16 _SV_queryCpu
endcodeseg cpu
END ; End of module