620 lines
14 KiB
C
620 lines
14 KiB
C
/***************************************************************
|
|
* C file: cpuid.c... for cpuinf32 DLL
|
|
*
|
|
* This program has been developed by Intel Corporation.
|
|
* You have Intel's permission to incorporate this code
|
|
* into your product, royalty free. Intel has various
|
|
* intellectual property rights which it may assert under
|
|
* certain circumstances, such as if another manufacturer's
|
|
* processor mis-identifies itself as being "GenuineIntel"
|
|
* when the CPUID instruction is executed.
|
|
*
|
|
* Intel specifically disclaims all warranties, express or
|
|
* implied, and all liability, including consequential and
|
|
* other indirect damages, for the use of this code,
|
|
* including liability for infringement of any proprietary
|
|
* rights, and including the warranties of merchantability
|
|
* and fitness for a particular purpose. Intel does not
|
|
* assume any responsibility for any errors which may
|
|
* appear in this code nor any responsibility to update it.
|
|
*
|
|
* * Other brands and names are the property of their respective
|
|
* owners.
|
|
*
|
|
* Copyright (c) 1995, Intel Corporation. All rights reserved.
|
|
***************************************************************/
|
|
|
|
|
|
|
|
/***************************************************************
|
|
* This is a 32-bit MS-Windows* DLL. It uses the standard Intel
|
|
* 32-bit cpuid assembly code to determine what type of processor
|
|
* is in the computer.
|
|
*
|
|
* Warning: avoid making frequent calls to wincpuid() or using
|
|
* the CPUID instruction frequently. This instruction & function
|
|
* require several clocks to execute, and they cause
|
|
* serialization of the instruction stream.
|
|
***************************************************************/
|
|
|
|
#include <windows.h>
|
|
#include "cpuid.h"
|
|
#include "speed.h"
|
|
|
|
|
|
// Global Variable /////////////////////////////////////////////
|
|
int clone_flag; // Flag to show whether processor
|
|
// is an Intel clone
|
|
|
|
|
|
|
|
// Public DLL Functions ////////////////////////////////////////
|
|
|
|
/***************************************************************
|
|
* wincpuidsupport()
|
|
*
|
|
* Inputs: none
|
|
*
|
|
* Returns:
|
|
* 1 = CPUID opcode is supported
|
|
* 0 = CPUID opcode is not supported
|
|
***************************************************************/
|
|
|
|
WORD wincpuidsupport() {
|
|
int cpuid_support = 1;
|
|
|
|
_asm {
|
|
pushfd // Get original EFLAGS
|
|
pop eax
|
|
mov ecx, eax
|
|
xor eax, 200000h // Flip ID bit in EFLAGS
|
|
push eax // Save new EFLAGS value on
|
|
// stack
|
|
popfd // Replace current EFLAGS value
|
|
pushfd // Get new EFLAGS
|
|
pop eax // Store new EFLAGS in EAX
|
|
xor eax, ecx // Can not toggle ID bit,
|
|
jnz support // Processor=80486
|
|
|
|
mov cpuid_support,0 // Clear support flag
|
|
support:
|
|
}
|
|
|
|
return cpuid_support;
|
|
|
|
} // wincpuidsupport()
|
|
|
|
|
|
|
|
/***************************************************************
|
|
* wincpuid()
|
|
*
|
|
* Inputs: none
|
|
*
|
|
* Returns:
|
|
* 0 = 8086/88
|
|
* 2 = 80286
|
|
* 3 = 80386
|
|
* 4 = 80486
|
|
* 5 = Pentium(R) Processor
|
|
* 6 = PentiumPro(R) Processor
|
|
* 7 or higher = Processor beyond the PentiumPro6(R) Processor
|
|
*
|
|
* Note: This function also sets the global variable clone_flag
|
|
***************************************************************/
|
|
|
|
WORD wincpuid() {
|
|
|
|
WORD cpuid;
|
|
|
|
if ( wincpuidsupport() ) // Determine whether CPUID
|
|
// opcode is supported
|
|
cpuid=check_IDProc();
|
|
|
|
else {
|
|
|
|
clone_flag=check_clone();
|
|
|
|
cpuid=check_8086(); // Will return FFFFh or 0
|
|
if (cpuid == 0) goto end;
|
|
|
|
cpuid=check_80286(); // Will return FFFFh or 2
|
|
if (cpuid == 2) goto end;
|
|
|
|
cpuid=check_80386(); // Will return FFFFh or 3
|
|
if (cpuid == 3) goto end; // temporarily commented out.
|
|
|
|
cpuid=4; // If the processor does not support CPUID,
|
|
// is not an 8086, 80286, or 80386, assign
|
|
// processor to be an 80486
|
|
}
|
|
|
|
end:
|
|
if (clone_flag)
|
|
cpuid = cpuid | CLONE_MASK; // Signify that a clone has been
|
|
// detected by setting MSB high
|
|
|
|
return cpuid;
|
|
|
|
} // wincpuid ()
|
|
|
|
|
|
|
|
/***************************************************************
|
|
* wincpuidext()
|
|
*
|
|
* Inputs: none
|
|
*
|
|
* Returns:
|
|
* AX(15:14) = Reserved (mask these off in the calling code
|
|
* before using)
|
|
* AX(13:12) = Processor type (00=Standard OEM CPU, 01=OverDrive,
|
|
* 10=Dual CPU, 11=Reserved)
|
|
* AX(11:8) = CPU Family (the same 4-bit quantity as wincpuid())
|
|
* AX(7:4) = CPU Model, if the processor supports the CPUID
|
|
* opcode; zero otherwise
|
|
* AX(3:0) = Stepping #, if the processor supports the CPUID
|
|
* opcode; zero otherwise
|
|
*
|
|
* Note: This function also sets the global variable clone_flag
|
|
***************************************************************/
|
|
|
|
WORD wincpuidext() {
|
|
|
|
int i=0;
|
|
WORD cpu_type=0x0000;
|
|
WORD cpuidext=0x0000;
|
|
BYTE vendor_id[12]="------------";
|
|
BYTE intel_id[12]="GenuineIntel";
|
|
|
|
if ( wincpuidsupport() ) {
|
|
|
|
_asm {
|
|
|
|
xor eax, eax // Set up for CPUID instruction
|
|
|
|
CPU_ID // Get and save vendor ID
|
|
|
|
mov dword ptr vendor_id, ebx
|
|
mov dword ptr vendor_id[+4], edx
|
|
mov dword ptr vendor_id[+8], ecx
|
|
}
|
|
|
|
for (i=0;i<12;i++)
|
|
{
|
|
if (!(vendor_id[i]==intel_id[i]))
|
|
clone_flag = 1;
|
|
}
|
|
|
|
_asm {
|
|
|
|
cmp eax, 1 // Make sure 1 is valid input
|
|
// for CPUID
|
|
|
|
jl end_cpuidext // If not, jump to end
|
|
xor eax, eax
|
|
inc eax
|
|
CPU_ID // Get family/model/stepping/
|
|
// features
|
|
|
|
mov cpuidext, ax
|
|
|
|
end_cpuidext:
|
|
mov ax, cpuidext
|
|
}
|
|
}
|
|
else {
|
|
|
|
cpu_type = wincpuid(); // If CPUID opcode is not
|
|
cpuidext = cpu_type << 8; // supported, put family
|
|
// value in extensions and
|
|
} // return
|
|
|
|
return cpuidext;
|
|
|
|
} // wincpuidext()
|
|
|
|
|
|
|
|
/***************************************************************
|
|
* wincpufeatures()
|
|
*
|
|
* Inputs: none
|
|
*
|
|
* Returns:
|
|
* 0 = Processor which does not execute the CPUID instruction.
|
|
* This includes 8086, 8088, 80286, 80386, and some
|
|
* older 80486 processors.
|
|
*
|
|
* Else
|
|
* Feature Flags (refer to App Note AP-485 for description).
|
|
* This DWORD was put into EDX by the CPUID instruction.
|
|
*
|
|
* Current flag assignment is as follows:
|
|
*
|
|
* bit31..10 reserved (=0)
|
|
* bit9=1 CPU contains a local APIC (iPentium-3V)
|
|
* bit8=1 CMPXCHG8B instruction supported
|
|
* bit7=1 machine check exception supported
|
|
* bit6=0 reserved (36bit-addressing & 2MB-paging)
|
|
* bit5=1 iPentium-style MSRs supported
|
|
* bit4=1 time stamp counter TSC supported
|
|
* bit3=1 page size extensions supported
|
|
* bit2=1 I/O breakpoints supported
|
|
* bit1=1 enhanced virtual 8086 mode supported
|
|
* bit0=1 CPU contains a floating-point unit (FPU)
|
|
*
|
|
* Note: New bits will be assigned on future processors... see
|
|
* processor data books for updated information
|
|
*
|
|
* Note: This function also sets the global variable clone_flag
|
|
***************************************************************/
|
|
|
|
DWORD wincpufeatures() {
|
|
|
|
int i=0;
|
|
DWORD cpuff=0x00000000;
|
|
BYTE vendor_id[12]="------------";
|
|
BYTE intel_id[12]="GenuineIntel";
|
|
|
|
if ( wincpuidsupport() ) {
|
|
|
|
_asm {
|
|
|
|
xor eax, eax // Set up for CPUID instruction
|
|
|
|
CPU_ID // Get and save vendor ID
|
|
|
|
mov dword ptr vendor_id, ebx
|
|
mov dword ptr vendor_id[+4], edx
|
|
mov dword ptr vendor_id[+8], ecx
|
|
}
|
|
|
|
for (i=0;i<12;i++)
|
|
{
|
|
if (!(vendor_id[i]==intel_id[i]))
|
|
clone_flag = 1;
|
|
}
|
|
|
|
_asm {
|
|
|
|
cmp eax, 1 // Make sure 1 is valid input
|
|
// for CPUID
|
|
|
|
jl end_cpuff // If not, jump to end
|
|
xor eax, eax
|
|
inc eax
|
|
CPU_ID // Get family/model/stepping/
|
|
// features
|
|
|
|
mov cpuff, edx
|
|
|
|
end_cpuff:
|
|
mov eax, cpuff
|
|
}
|
|
}
|
|
|
|
return cpuff;
|
|
|
|
} // wincpufeatures()
|
|
|
|
|
|
|
|
/***************************************************************
|
|
* winrdtsc()
|
|
*
|
|
* Inputs: none
|
|
*
|
|
* Returns:
|
|
* 0 = CPU does not support the time stamp register
|
|
*
|
|
* Else
|
|
* Returns a variable of type TIME_STAMP which is composed of
|
|
* two DWORD variables. The 'High' DWORD contains the upper
|
|
* 32-bits of the Time Stamp Register. The 'Low' DWORD
|
|
* contains the lower 32-bits of the Time Stamp Register.
|
|
*
|
|
* Note: This function also sets the global variable clone_flag
|
|
***************************************************************/
|
|
|
|
struct TIME_STAMP winrdtsc() {
|
|
|
|
struct TIME_STAMP timestamp; // Return variable for time
|
|
// stamp read
|
|
DWORD features = wincpufeatures(); // Processor Features
|
|
|
|
timestamp.Low = 0;
|
|
timestamp.High = 0;
|
|
|
|
if ( features & 0x00000010 ) {
|
|
|
|
RDTSC // Read Time Stamp
|
|
|
|
_asm
|
|
{
|
|
MOV timestamp.Low, EAX
|
|
MOV timestamp.High, EDX
|
|
|
|
}
|
|
}
|
|
|
|
return timestamp;
|
|
|
|
} // winrdtsc
|
|
|
|
|
|
|
|
/***************************************************************
|
|
* getdllversion()
|
|
*
|
|
* Inputs: none
|
|
*
|
|
* Returns: Major and Minor version of this DLL.
|
|
*
|
|
* i.e. getdllversion() = 0x01 00
|
|
* Major Version<--|-->Minor Version
|
|
*
|
|
***************************************************************/
|
|
|
|
unsigned short getdllversion(void) {
|
|
unsigned short Version = VERSION;
|
|
|
|
return Version;
|
|
|
|
} // getdllversion()
|
|
|
|
|
|
|
|
// Internal Private Functions //////////////////////////////////
|
|
|
|
/***************************************************************
|
|
* check_clone()
|
|
*
|
|
* Inputs: none
|
|
*
|
|
* Returns:
|
|
* 1 if processor is clone (limited detection ability)
|
|
* 0 otherwise
|
|
***************************************************************/
|
|
|
|
static WORD check_clone()
|
|
{
|
|
short cpu_type=0;
|
|
|
|
_asm
|
|
{
|
|
MOV AX,5555h // Check to make sure this
|
|
XOR DX,DX // is a 32-bit processor
|
|
MOV CX,2h
|
|
DIV CX // Perform Division
|
|
CLC
|
|
JNZ no_clone
|
|
JMP clone
|
|
no_clone: STC
|
|
clone: PUSHF
|
|
POP AX // Get the flags
|
|
AND AL,1
|
|
XOR AL,1 // AL=0 is probably Intel,
|
|
// AL=1 is a Clone
|
|
|
|
MOV cpu_type, ax
|
|
}
|
|
|
|
cpu_type = cpu_type & 0x0001;
|
|
|
|
return cpu_type;
|
|
|
|
} // check_clone()
|
|
|
|
|
|
|
|
/***************************************************************
|
|
* check_8086()
|
|
*
|
|
* Inputs: none
|
|
*
|
|
* Returns:
|
|
* 0 if processor 8086
|
|
* 0xffff otherwise
|
|
***************************************************************/
|
|
|
|
static WORD check_8086()
|
|
{
|
|
|
|
WORD cpu_type=0xffff;
|
|
|
|
_asm {
|
|
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
|
|
cmp ax, 0f000h // processor is an 8086/8088
|
|
mov cpu_type, 0 // Turn on 8086/8088 flag
|
|
je end_8086 // Jump if processor is 8086/
|
|
// 8088
|
|
mov cpu_type, 0ffffh
|
|
end_8086:
|
|
push cx
|
|
popf
|
|
mov ax, cpu_type
|
|
|
|
}
|
|
|
|
return cpu_type;
|
|
|
|
} // check_8086()
|
|
|
|
|
|
|
|
/***************************************************************
|
|
* check_80286()
|
|
*
|
|
* Inputs: none
|
|
*
|
|
* Returns:
|
|
* 2 if processor 80286
|
|
* 0xffff otherwise
|
|
***************************************************************/
|
|
|
|
static WORD check_80286()
|
|
{
|
|
|
|
WORD cpu_type=0xffff;
|
|
|
|
_asm {
|
|
pushf
|
|
pop cx
|
|
mov bx, cx
|
|
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 are clear
|
|
|
|
mov cpu_type, 2 // Processor=80286, turn on
|
|
// 80286 flag
|
|
|
|
jz end_80286 // If no bits set, processor is
|
|
// 80286
|
|
|
|
mov cpu_type, 0ffffh
|
|
end_80286:
|
|
push bx
|
|
popf
|
|
mov ax, cpu_type
|
|
|
|
}
|
|
|
|
return cpu_type;
|
|
|
|
} // check_80286()
|
|
|
|
|
|
|
|
/***************************************************************
|
|
* check_80386()
|
|
*
|
|
* Inputs: none
|
|
*
|
|
* Returns:
|
|
* 3 if processor 80386
|
|
* 0xffff otherwise
|
|
***************************************************************/
|
|
|
|
static WORD check_80386()
|
|
{
|
|
|
|
WORD cpu_type=0xffff;
|
|
|
|
_asm {
|
|
mov bx, sp
|
|
and sp, not 3
|
|
pushfd // Push original EFLAGS
|
|
pop eax // Get original EFLAGS
|
|
mov ecx, eax // Save original EFLAGS
|
|
xor eax, 40000h // Flip AC bit in EFLAGS
|
|
|
|
push eax // Save new EFLAGS value on
|
|
// stack
|
|
|
|
popfd // Replace current EFLAGS value
|
|
pushfd // Get new EFLAGS
|
|
pop eax // Store new EFLAGS in EAX
|
|
|
|
xor eax, ecx // Can't toggle AC bit,
|
|
// processor=80386
|
|
|
|
mov cpu_type, 3 // Turn on 80386 processor flag
|
|
jz end_80386 // Jump if 80386 processor
|
|
mov cpu_type, 0ffffh
|
|
end_80386:
|
|
push ecx
|
|
popfd
|
|
mov sp, bx
|
|
mov ax, cpu_type
|
|
and eax, 0000ffffh
|
|
}
|
|
|
|
return cpu_type;
|
|
|
|
} // check_80386()
|
|
|
|
|
|
|
|
/***************************************************************
|
|
* check_IDProc()
|
|
*
|
|
* Inputs: none
|
|
*
|
|
* Returns:
|
|
* CPU Family (i.e. 4 if Intel 486, 5 if Pentium(R) Processor)
|
|
*
|
|
* Note: This function also sets the global variable clone_flag
|
|
***************************************************************/
|
|
|
|
static WORD check_IDProc() {
|
|
|
|
int i=0;
|
|
WORD cpu_type=0xffff;
|
|
BYTE stepping=0;
|
|
BYTE model=0;
|
|
BYTE vendor_id[12]="------------";
|
|
BYTE intel_id[12]="GenuineIntel";
|
|
|
|
_asm {
|
|
|
|
xor eax, eax // Set up for CPUID instruction
|
|
|
|
CPU_ID // Get and save vendor ID
|
|
|
|
mov dword ptr vendor_id, ebx
|
|
mov dword ptr vendor_id[+4], edx
|
|
mov dword ptr vendor_id[+8], ecx
|
|
}
|
|
|
|
for (i=0;i<12;i++)
|
|
{
|
|
if (!(vendor_id[i]==intel_id[i]))
|
|
clone_flag = 1;
|
|
}
|
|
|
|
_asm {
|
|
|
|
cmp eax, 1 // Make sure 1 is valid input
|
|
// for CPUID
|
|
|
|
jl end_IDProc // If not, jump to end
|
|
xor eax, eax
|
|
inc eax
|
|
CPU_ID // Get family/model/stepping/
|
|
// features
|
|
|
|
mov stepping, al
|
|
and stepping, 0x0f //0fh
|
|
|
|
and al, 0f0h
|
|
shr al, 4
|
|
mov model, al
|
|
|
|
and eax, 0f00h
|
|
shr eax, 8 // Isolate family
|
|
and eax, 0fh
|
|
mov cpu_type, ax // Set _cpu_type with family
|
|
|
|
end_IDProc:
|
|
mov ax, cpu_type
|
|
}
|
|
|
|
return cpu_type;
|
|
|
|
} // Check_IDProc()
|
|
|
|
|
|
|