www.pudn.com > fxvmm210.zip > _FXCPUID.ASM
;±°±°±°±°±°±°±°±°±°±°±°±°±°±°±°±°±°±°±°±°±°±°±°±°±°±°±°±°±°±°±°±°±°±°±°±°±°±°±°±°±°±°
;
; CPU & FPU Identification procedures
;
;
; Note: code originated from INTEL, and is not mine, just that you know ...
;
;
TITLE FXVMM_CPUID
DOSSEG
.model large
.186
;±°±°±°±°±°±°±°±°±°±°±°±°±°±°±°±°±°±°±°±°±°±°±°±°±°±°±°±°±°±°±°±°±°±°±°±°±°±°±°±°±°±°
include ..\source.asm\_fxvmm.inc
;±°±°±°±°±°±°±°±°±°±°±°±°±°±°±°±°±°±°±°±°±°±°±°±°±°±°±°±°±°±°±°±°±°±°±°±°±°±°±°±°±°±°
public __fxvmm_cpuid
;±°±°±°±°±°±°±°±°±°±°±°±°±°±°±°±°±°±°±°±°±°±°±°±°±°±°±°±°±°±°±°±°±°±°±°±°±°±°±°±°±°±°
public _id_flag
public _fp_status
public _fxvmm_cputype
public _zodel
public _stepping
public _fxvmm_fputype
public _intel_proc
public _feature_flags
;±°±°±°±°±°±°±°±°±°±°±°±°±°±°±°±°±°±°±°±°±°±°±°±°±°±°±°±°±°±°±°±°±°±°±°±°±°±°±°±°±°±°
OPND32 MACRO op_code, op_erand
db 66h ; Force 32-bit operand size
IFNB
db op_code
IFNB
dd op_erand; 32-bit immediate value
ENDIF
ENDIF
ENDM
;±°±°±°±°±°±°±°±°±°±°±°±°±°±°±°±°±°±°±°±°±°±°±°±°±°±°±°±°±°±°±°±°±°±°±°±°±°±°±°±°±°±°
FXVMM_CPUID MACRO
db 0fh ; Hardcoded opcode for FXVMM_CPUID instruction
db 0a2h
ENDM
TRUE equ 1
FAMILY_MASK equ 0f00h
FAMILY_SHIFT equ 8
MODEL_MASK equ 0f0h
MODEL_SHIFT equ 4
STEPPING_MASK equ 0fh
FPU_FLAG equ 1h
MCE_FLAG equ 80h
CMPXCHG8B_FLAG equ 100h
;±°±°±°±°±°±°±°±°±°±°±°±°±°±°±°±°±°±°±°±°±°±°±°±°±°±°±°±°±°±°±°±°±°±°±°±°±°±°±°±°±°±°
.data
_fp_status dw ?
_vendor_id db 12 dup (?)
_fxvmm_cputype db ?
_zodel db ?
_stepping db ?
_id_flag db 0
_fxvmm_fputype db 0
_intel_proc db 0
_feature_flags dw 2 dup (0)
_intel_id db "GenuineIntel"
;
; The purpose of this code is to identify the processor and
; coprocessor that is currently in the system. The program first
; determines the processor id. When that is accomplished,
; the program then determines whether a coprocessor
; exists in the system. If a coprocessor or integrated
; coprocessor exists, the program identifies
; the coprocessor id. The program then prints out
; the CPU and floating point presence and type.
;
;±°±°±°±°±°±°±°±°±°±°±°±°±°±°±°±°±°±°±°±°±°±°±°±°±°±°±°±°±°±°±°±°±°±°±°±°±°±°±°±°±°±°
.code
;±°±°±°±°±°±°±°±°±°±°±°±°±°±°±°±°±°±°±°±°±°±°±°±°±°±°±°±°±°±°±°±°±°±°±°±°±°±°±°±°±°±°
__fxvmm_cpuid: mov ax, _DATA ;@data
mov ds, ax ; set segment register
mov es, ax ; set segment register
pushf ; save for restoration at end
call get_cpuid
call get_fpuid
popf
retf
get_cpuid proc
;
; This procedure determines the type of CPU in a system
; and sets the _fxvmm_cputype variable with the appropriate
; value.
; All registers are used by this procedure, none are preserved.
; Intel 8086 CPU check
; Bits 12-15 of the FLAGS register are always set on the
; 8086 processor.
;
;±°±°±°±°±°±°±°±°±°±°±°±°±°±°±°±°±°±°±°±°±°±°±°±°±°±°±°±°±°±°±°±°±°±°±°±°±°±°±°±°±°±°
check_8086:
pushf ; push original FLAGS
pop ax ; get original FLAGS
mov cx, ax ; save original FLAGS
and ax, 0fffh ; clear bits 12-15 in FLAGS
push ax ; save new FLAGS value on stack
popf ; replace current FLAGS value
pushf ; get new FLAGS
pop ax ; store new FLAGS in AX
and ax, 0f000h ; if bits 12-15 are set, then CPU
cmp ax, 0f000h ; is an 8086/8088
mov _fxvmm_cputype, 0 ; turn on 8086/8088 flag
jne check_80286
jmp end_get_cpuid ; jump if CPU is 8086/8088
; Intel 286 CPU check
; Bits 12-15 of the FLAGS register are always clear on the
; Intel 286 processor in real-address mode.
;
;±°±°±°±°±°±°±°±°±°±°±°±°±°±°±°±°±°±°±°±°±°±°±°±°±°±°±°±°±°±°±°±°±°±°±°±°±°±°±°±°±°±°
check_80286:
or cx, 0f000h ; try to set bits 12-15
push cx ; save new FLAGS value on stack
popf ; replace current FLAGS value
pushf ; get new FLAGS
pop ax ; store new FLAGS in AX
and ax, 0f000h ; if bits 12-15 clear, CPU=80286
mov _fxvmm_cputype, 2 ; turn on 80286 flag
jnz check_80386
jmp end_get_cpuid ; if no bits set, CPU is 80286
; Intel386 CPU check
; The AC bit, bit #18, is a new bit introduced in the EFLAGS
; register on the Intel486 DX CPU to generate alignment faults.
; This bit cannot be set on the Intel386 CPU.
;
;±°±°±°±°±°±°±°±°±°±°±°±°±°±°±°±°±°±°±°±°±°±°±°±°±°±°±°±°±°±°±°±°±°±°±°±°±°±°±°±°±°±°
check_80386:
; It is now safe to use 32-bit opcode/operands
mov bx, sp ; save current stack pointer to align
and sp, not 3 ; align stack to avoid AC fault
OPND32
pushf ; push original EFLAGS
OPND32
pop ax ; get original EFLAGS
OPND32
mov cx, ax ; save original EFLAGS
OPND32 35h, 40000h ; flip AC bit in EFLAGS
OPND32
push ax ; save new EFLAGS value on stack
OPND32
popf ; replace current EFLAGS value
OPND32
pushf ; get new EFLAGS
OPND32
pop ax ; store new EFLAGS in EAX
OPND32
xor ax, cx ; can't toggle AC bit, CPU=80386
mov _fxvmm_cputype, 3 ; turn on 80386 CPU flag
mov sp, bx ; restore original stack pointer
jz end_get_cpuid ; jump if 80386 CPU
and sp, not 3 ; align stack to avoid AC fault
OPND32
push cx
OPND32
popf ; restore AC bit in EFLAGS first
mov sp, bx ; restore original stack pointer
; Intel486 DX CPU, Intel487 SX NDP, and Intel486 SX CPU check
; Checking for ability to set/clear ID flag (Bit 21) in EFLAGS
; which indicates the presence of a processor
; with the ability to use the FXVMM_CPUID instruction.
;
;±°±°±°±°±°±°±°±°±°±°±°±°±°±°±°±°±°±°±°±°±°±°±°±°±°±°±°±°±°±°±°±°±°±°±°±°±°±°±°±°±°±°
check_80486:
mov _fxvmm_cputype, 4 ; turn on 80486 CPU flag
OPND32
mov ax, cx ; get original EFLAGS
OPND32 35h, 200000h ; flip ID bit in EFLAGS
OPND32
push ax ; save new EFLAGS value on stack
OPND32
popf ; replace current EFLAGS value
OPND32
pushf ; get new EFLAGS
OPND32
pop ax ; store new EFLAGS in EAX
OPND32
xor ax, cx ; can't toggle ID bit,
je end_get_cpuid ; CPU=80486
; Execute FXVMM_CPUID instruction to determine vendor, family,
; model and _stepping.
;
;±°±°±°±°±°±°±°±°±°±°±°±°±°±°±°±°±°±°±°±°±°±°±°±°±°±°±°±°±°±°±°±°±°±°±°±°±°±°±°±°±°±°
check_vendor:
mov _id_flag, 1 ; set flag indicating use of FXVMM_CPUID inst.
OPND32
xor ax, ax ; set up input for FXVMM_CPUID instruction
FXVMM_CPUID ; macro for FXVMM_CPUID instruction
OPND32
mov word ptr _vendor_id, bx ; setup to test for vendor id
OPND32
mov word ptr _vendor_id[+4], dx
OPND32
mov word ptr _vendor_id[+8], cx
mov si, offset _vendor_id
mov di, offset _intel_id
mov cx, length _intel_id
;±°±°±°±°±°±°±°±°±°±°±°±°±°±°±°±°±°±°±°±°±°±°±°±°±°±°±°±°±°±°±°±°±°±°±°±°±°±°±°±°±°±°
compare:
repe cmpsb ; compare vendor id to "GenuineIntel"
or cx, cx
jnz end_get_cpuid ; if not zero, not an Intel CPU,
;±°±°±°±°±°±°±°±°±°±°±°±°±°±°±°±°±°±°±°±°±°±°±°±°±°±°±°±°±°±°±°±°±°±°±°±°±°±°±°±°±°±°
_intel_processor:
mov _intel_proc, 1
;±°±°±°±°±°±°±°±°±°±°±°±°±°±°±°±°±°±°±°±°±°±°±°±°±°±°±°±°±°±°±°±°±°±°±°±°±°±°±°±°±°±°
cpuid_data:
OPND32
cmp ax, 1 ; make sure 1 is a valid input
; value for FXVMM_CPUID
jl end_get_cpuid ; if not, jump to end
OPND32
xor ax, ax ; otherwise, use as input to FXVMM_CPUID
OPND32
inc ax ; and get _stepping, model and family
FXVMM_CPUID
mov _stepping, al
and _stepping, STEPPING_MASK ; isolate _stepping info
and al, MODEL_MASK ; isolate model info
shr al, MODEL_SHIFT
mov _zodel, al
and ax, FAMILY_MASK ; mask everything but family
shr ax, FAMILY_SHIFT
mov _fxvmm_cputype, al ; set _fxvmm_cputype with family
OPND32
mov _feature_flags, dx ; save feature flag data
end_get_cpuid:
ret
get_cpuid endp
;±°±°±°±°±°±°±°±°±°±°±°±°±°±°±°±°±°±°±°±°±°±°±°±°±°±°±°±°±°±°±°±°±°±°±°±°±°±°±°±°±°±°
get_fpuid proc
; This procedure determines the type of FPU in a system
; and sets the _fxvmm_fputype variable with the appropriate
; value.
; All registers are used by this procedure, none are preserved.
; Coprocessor check
; The algorithm is to determine whether the floating-point
; status and control words can be written to. If not, no
; coprocessor exists. If the status and control words can be
; written to, the correct coprocessor is then determined
; depending on the processor id. The Intel386 CPU can
; work with either an Intel287 NDP or an Intel387 NDP.
; The infinity of the coprocessor must be
; checked to determine the correct coprocessor id.
fninit ; reset FP status word
mov _fp_status, 5a5ah ; initialize temp word to
; non-zero value
fnstsw _fp_status ; save FP status word
mov ax, _fp_status ; check FP status word
cmp al, 0 ; see if correct status with
; written
mov _fxvmm_fputype, 0 ; no fpu present
jne end_get_fpuid
;±°±°±°±°±°±°±°±°±°±°±°±°±°±°±°±°±°±°±°±°±°±°±°±°±°±°±°±°±°±°±°±°±°±°±°±°±°±°±°±°±°±°
check_control_word:
fnstcw _fp_status ; save FP control word
mov ax, _fp_status ; check FP control word
and ax, 103fh ; see if selected parts
; looks OK
cmp ax, 3fh ; check that 1's & 0's
; correctly read
mov _fxvmm_fputype, 0
jne end_get_fpuid
mov _fxvmm_fputype, 1
;
; 80287/80387 check for the Intel386 CPU
;
;±°±°±°±°±°±°±°±°±°±°±°±°±°±°±°±°±°±°±°±°±°±°±°±°±°±°±°±°±°±°±°±°±°±°±°±°±°±°±°±°±°±°
check_infinity:
cmp _fxvmm_cputype, 3
jne end_get_fpuid
fld1 ; must use default control from FNINIT
fldz ; form infinity
fdiv ; 8087 and Intel287 NDP say +inf = -inf
fld st ; form negative infinity
fchs ; Intel387 NDP says +inf <> -inf
fcompp ; see if they are the same and remove them
fstsw _fp_status ; look at status from FCOMPP
mov ax, _fp_status
mov _fxvmm_fputype, 2 ; store Intel287 NDP for fpu type
sahf ; see if infinities matched
jz end_get_fpuid ; jump if 8087 or Intel287 is present
mov _fxvmm_fputype, 3 ; store Intel387 NDP for fpu type
end_get_fpuid:
ret
get_fpuid endp
end __fxvmm_cpuid
;±°±°±°±°±°±°±°±°±°±°±°±°±°±°±°±°±°±°±°±°±°±°±°±°±°±°±°±°±°±°±°±°±°±°±°±°±°±°±°±°±°±°