253 lines
6.2 KiB
NASM
253 lines
6.2 KiB
NASM
title "Processor type and stepping detection"
|
|
;++
|
|
;
|
|
; Copyright (c) 1989 Microsoft Corporation
|
|
;
|
|
; Module Name:
|
|
;
|
|
; cpu.asm
|
|
;
|
|
; Abstract:
|
|
;
|
|
; This module implements the assembley code necessary to determine
|
|
; cpu type and stepping information.
|
|
;
|
|
; Author:
|
|
;
|
|
; Shie-Lin Tzong (shielint) 28-Oct-1991.
|
|
;
|
|
; Environment:
|
|
;
|
|
; 80x86
|
|
;
|
|
; Revision History:
|
|
;
|
|
;--
|
|
|
|
.586p
|
|
.xlist
|
|
include mac386.inc
|
|
include callconv.inc
|
|
.list
|
|
|
|
_TEXT SEGMENT DWORD PUBLIC 'CODE'
|
|
ASSUME DS:FLAT, ES:FLAT, SS:NOTHING, FS:NOTHING, GS:NOTHING
|
|
|
|
CR0_AM equ 40000h
|
|
EFLAGS_AC equ 40000h
|
|
|
|
subttl "Is386"
|
|
;++
|
|
;
|
|
; BOOLEAN
|
|
; BlIs386(
|
|
; VOID
|
|
; )
|
|
;
|
|
; Routine Description:
|
|
;
|
|
; This function determines whether the processor we're running on
|
|
; is a 386. If not a 386, it is assumed that the processor is
|
|
; a 486 or greater.
|
|
;
|
|
; Arguments:
|
|
;
|
|
; None.
|
|
;
|
|
; Return Value:
|
|
;
|
|
; (al) = 1 - processor is a 386
|
|
; (al) = 0 - processor is a 486 or greater.
|
|
;
|
|
;--
|
|
public _BlIs386@0
|
|
_BlIs386@0 proc
|
|
|
|
mov eax,cr0
|
|
push eax ; save current cr0
|
|
and eax,not CR0_AM ; mask out alignment check bit
|
|
mov cr0,eax ; disable alignment check
|
|
pushfd ; save flags
|
|
pushfd ; turn on alignment check bit in
|
|
or dword ptr [esp],EFLAGS_AC ; a copy of the flags register
|
|
popfd ; and try to load flags
|
|
pushfd
|
|
pop ecx ; get new flags into ecx
|
|
popfd ; restore original flags
|
|
pop eax ; restore original cr0
|
|
mov cr0,eax
|
|
xor al,al ; prepare for return, assume not 386
|
|
and ecx,EFLAGS_AC ; did AC bit get set?
|
|
jnz short @f ; yes, we don't have a 386
|
|
inc al ; we have a 386
|
|
@@: ret
|
|
|
|
_BlIs386@0 endp
|
|
|
|
subttl "IsCpuidPresent"
|
|
;++
|
|
;
|
|
; BOOLEAN
|
|
; BlIsCpuidPresent(
|
|
; VOID
|
|
; )
|
|
;
|
|
; Routine Description:
|
|
;
|
|
; If bit 21 of the EFLAGS register is writable, CPUID is supported on
|
|
; this processor. If not writable, CPUID is not supported.
|
|
;
|
|
; Note: It is expected that this routine is "locked" onto a single
|
|
; processor when run.
|
|
;
|
|
; Arguments:
|
|
;
|
|
; None.
|
|
;
|
|
; Return Value:
|
|
;
|
|
; TRUE if CPUID is supported,
|
|
; FALSE otherwise.
|
|
;
|
|
;--
|
|
|
|
EFLAGS_ID equ 200000h ; bit 21
|
|
|
|
|
|
cPublicProc _BlIsCpuidPresent ,0
|
|
pushfd ; save EFLAGS
|
|
pop ecx ; get current value
|
|
xor ecx, EFLAGS_ID ; flip bit 21
|
|
push ecx ; set flipped value in EFLAGS
|
|
popfd
|
|
pushfd ; read it back again
|
|
pop eax
|
|
xor eax, ecx ; if new value is what we set
|
|
shr eax, 21 ; then these two are the same
|
|
and eax, 1 ; isolate bit 21 (in bit 0)
|
|
xor eax, 1 ; and flip it
|
|
|
|
stdRET _BlIsCpuidPresent
|
|
|
|
stdENDP _BlIsCpuidPresent
|
|
|
|
|
|
page
|
|
subttl "GetFeatureBits"
|
|
;++
|
|
;
|
|
; VOID
|
|
; BlGetFeatureBits(
|
|
; VOID
|
|
; )
|
|
;
|
|
; Routine Description:
|
|
;
|
|
; Execute the CPUID instruction to get the feature bits supported
|
|
; by this processor.
|
|
;
|
|
; Arguments:
|
|
;
|
|
; None.
|
|
;
|
|
; Return Value:
|
|
;
|
|
; Returns the set of feature bits supported by this processor or
|
|
; 0 if this processor does not support the CPUID instruction.
|
|
;
|
|
;--
|
|
|
|
|
|
cPublicProc _BlGetFeatureBits ,0
|
|
stdCall _BlIsCpuidPresent ; Does this processor do CPUID?
|
|
test eax, 1
|
|
jnz short @f ; Jif yes.
|
|
xor eax, eax ; No, return 0.
|
|
stdRet _BlGetFeatureBits
|
|
|
|
@@: mov eax, 1 ; CPUID function 1 gets feature bits.
|
|
push ebx ; save ebx
|
|
cpuid ; execute
|
|
|
|
;
|
|
; Due to a bug in NT 4, some processors report that they do
|
|
; not support cmpxchg8b even though they do. Win2K doesn't
|
|
; care but cmpxchg8b is a requirement for Whistler.
|
|
;
|
|
; Check to see if this is one of those processors and if we
|
|
; have been told by the processor manufacturer how to reenable
|
|
; cmpxchg8b, do so.
|
|
;
|
|
|
|
test edx, 0100h ; is cmpxchg8b present?
|
|
jnz short gfb90 ; yes, skip
|
|
|
|
;
|
|
; cmpxchg8b not present, check for recognized processor
|
|
;
|
|
|
|
push eax ; save Family, Model, Stepping
|
|
mov eax, 0
|
|
cpuid
|
|
pop eax
|
|
|
|
cmp ebx, 0746e6543h ; Cyrix III = 'CentaurHauls'
|
|
jnz short gfb30
|
|
cmp edx, 048727561h
|
|
jnz short gfb80
|
|
cmp ecx, 0736c7561h
|
|
jnz short gfb80
|
|
cmp eax, 0600h ; consider Cyrix III F/M/S 600 and above
|
|
|
|
;
|
|
; Cyrix (Centaur) Set MSR 1107h bit 1 to 1.
|
|
;
|
|
|
|
mov ecx, 01107h
|
|
jae gfb20
|
|
cmp eax, 0500h ; consider IDT/Centaur F/M/S 500 and above
|
|
jb short gfb80
|
|
|
|
;
|
|
; Centaur family 5, set MSR 107h bit 1 to 1.
|
|
;
|
|
|
|
mov ecx, 0107h
|
|
|
|
gfb20: rdmsr
|
|
or eax, 2
|
|
wrmsr
|
|
jmp short gfb80
|
|
|
|
|
|
gfb30: cmp ebx, 0756e6547h ; Transmeta = 'GenuineTMx86'
|
|
jnz short gfb80
|
|
cmp edx, 054656e69h
|
|
jnz short gfb80
|
|
cmp ecx, 03638784dh
|
|
jnz short gfb80
|
|
cmp eax, 0542h ; consider Transmeta F/M/S 542 and above
|
|
jb short gfb80
|
|
|
|
;
|
|
; Transmeta MSR 80860004h is a mask applied to the feature bits.
|
|
;
|
|
|
|
mov ecx, 080860004h
|
|
rdmsr
|
|
or eax, 0100h
|
|
wrmsr
|
|
|
|
|
|
gfb80: mov eax, 1 ; reexecute CPUID function 1
|
|
cpuid
|
|
gfb90: mov eax, edx ; return feature bits
|
|
pop ebx ; restore ebx, esi
|
|
|
|
stdRET _BlGetFeatureBits
|
|
|
|
stdENDP _BlGetFeatureBits
|
|
|
|
_TEXT ends
|
|
end
|