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 
 
;±°±°±°±°±°±°±°±°±°±°±°±°±°±°±°±°±°±°±°±°±°±°±°±°±°±°±°±°±°±°±°±°±°±°±°±°±°±°±°±°±°±°