CPUID: Difference between revisions

From OSDev.wiki
Jump to navigation Jump to search
[unchecked revision][unchecked revision]
Content added Content deleted
(added a routine for checking CPUID support)
m (Bot: Replace deprecated source tag with syntaxhighlight)
 
(48 intermediate revisions by 33 users not shown)
Line 1: Line 1:
The CPUID instruction can be used to retrieve various information about your CPU, such as its vendor string and model number, the size of internal caches and (more interesting), the list of CPU features supported.
{{Infobox Instruction
|Instruction=CPUID
|Definition=CPU Identification
|Usage=CPUID
|Availability=Pentium
}}

The CPUID instruction can be used to retrieve various amount of information about your cpu, like its vendor string and model number, the size of internal caches and (more interesting), the list of CPU features supported.


== How to use CPUID ==
== How to use CPUID ==
=== Checking CPUID availability ===
Prior to using the CPUID instruction, you should also make sure the processor supports it by testing the 'ID' bit (0x200000) in eflags. This bit is modifiable only when the CPUID instruction is supported. For systems that don't support CPUID, changing the 'ID' bit will have no effect.


'''Note:''' Implementing this routine in for example C can lead to issues, because the compiler may change EFLAGS at any time.
Note that prior to use the CPUID instruction, you should also make sure the processor support it by testing the 'ID' bit in eflags (this is 0x200000 and is modifiable only when CPUID instruction is supported. For systems that doesn't support CPUID, writing a '1' at that place will have no effect).
A routine in assembly for checking support of CPUID may look something like this:


This assembly routine checks if CPUID is supported:
<pre>
; returns zero if CPUID is not supported. returns at least 1 otherwise.
pushfd
pop eax
mov ebx, eax
xor eax, 0x200000
and ebx, 0x200000
push eax
popfd
pushfd
pop eax
and eax, 0x200000
xor eax, ebx
shr eax, 21
ret
</pre>


<syntaxhighlight lang="asm">
pushfd ;Save EFLAGS
pushfd ;Store EFLAGS
xor dword [esp],0x00200000 ;Invert the ID bit in stored EFLAGS
popfd ;Load stored EFLAGS (with ID bit inverted)
pushfd ;Store EFLAGS again (ID bit may or may not be inverted)
pop eax ;eax = modified EFLAGS (ID bit may or may not be inverted)
xor eax,[esp] ;eax = whichever bits were changed
popfd ;Restore original EFLAGS
and eax,0x00200000 ;eax = zero if ID bit can't be changed, else non-zero
ret
</syntaxhighlight>

Note 1: There are some old CPUs where CPUID is supported but the ID bit in EFLAGS is not (NexGen). There are also CPUs that support CPUID if and only if it has to be enabled first (Cyrix M1).

Note 2: You can simply attempt to execute the CPUID instruction and see if you get an invalid opcode exception. This avoids problems with CPUs that do support CPUID but don't support the ID bit in EFLAGS; and is likely to be faster for CPUs that do support CPUID (and slower for CPUs that don't).

=== Basic usage ===
The idea of the CPUID instruction is that you can call it with different values in EAX, and it will return different information about the processor. For example, if we want the Vendor ID String (see below), we should code something like that:
The idea of the CPUID instruction is that you can call it with different values in EAX, and it will return different information about the processor. For example, if we want the Vendor ID String (see below), we should code something like that:


<syntaxhighlight lang="asm">
<pre>
mov eax, 0x0
mov eax, 0x0
cpuid
cpuid
</syntaxhighlight>
</pre>


There are differences between AMD and Intel. According to the Intel CPUID application note, we should first check the Vendor ID String for "GenuineIntel" before taking out information, such as the Processor Signature, Processor Feature Flags, etc.
There are differences between AMD and Intel. According to the Intel CPUID application note, we should first check the Vendor ID String for "GenuineIntel" before taking out information, such as the Processor Signature, Processor Feature Flags, etc.
Line 43: Line 40:
When called with EAX = 0, CPUID returns the vendor ID string in EBX, EDX and ECX. Writing these to memory in this order results in a 12-character string. These can be tested against known Vendor ID strings:
When called with EAX = 0, CPUID returns the vendor ID string in EBX, EDX and ECX. Writing these to memory in this order results in a 12-character string. These can be tested against known Vendor ID strings:


<syntaxhighlight lang="c">
<pre>
/* Vendor-strings. */
// Vendor strings from CPUs.
#define CPUID_VENDOR_AMD "AuthenticAMD"
#define CPUID_VENDOR_AMD "AuthenticAMD"
#define CPUID_VENDOR_AMD_OLD "AMDisbetter!" // Early engineering samples of AMD K5 processor
#define CPUID_VENDOR_INTEL "GenuineIntel"
#define CPUID_VENDOR_VIA "CentaurHauls"
#define CPUID_VENDOR_INTEL "GenuineIntel"
#define CPUID_VENDOR_TRANSMETA "GenuineTMx86"
#define CPUID_VENDOR_VIA "VIA VIA VIA "
#define CPUID_VENDOR_CYRIX "CyrixInstead"
#define CPUID_VENDOR_TRANSMETA "GenuineTMx86"
#define CPUID_VENDOR_CENTAUR "CentaurHauls"
#define CPUID_VENDOR_TRANSMETA_OLD "TransmetaCPU"
#define CPUID_VENDOR_NEXGEN "NexGenDriven"
#define CPUID_VENDOR_CYRIX "CyrixInstead"
#define CPUID_VENDOR_UMC "UMC UMC UMC "
#define CPUID_VENDOR_CENTAUR "CentaurHauls"
#define CPUID_VENDOR_SIS "SiS SiS SiS "
#define CPUID_VENDOR_NEXGEN "NexGenDriven"
#define CPUID_VENDOR_NSC "Geode by NSC"
#define CPUID_VENDOR_UMC "UMC UMC UMC "
#define CPUID_VENDOR_RISE "RiseRiseRise"
#define CPUID_VENDOR_SIS "SiS SiS SiS "
#define CPUID_VENDOR_NSC "Geode by NSC"
</pre>
#define CPUID_VENDOR_RISE "RiseRiseRise"
#define CPUID_VENDOR_VORTEX "Vortex86 SoC"
#define CPUID_VENDOR_AO486 "MiSTer AO486"
#define CPUID_VENDOR_AO486_OLD "GenuineAO486"
#define CPUID_VENDOR_ZHAOXIN " Shanghai "
#define CPUID_VENDOR_HYGON "HygonGenuine"
#define CPUID_VENDOR_ELBRUS "E2K MACHINE "
// Vendor strings from hypervisors.
#define CPUID_VENDOR_QEMU "TCGTCGTCGTCG"
#define CPUID_VENDOR_KVM " KVMKVMKVM "
#define CPUID_VENDOR_VMWARE "VMwareVMware"
#define CPUID_VENDOR_VIRTUALBOX "VBoxVBoxVBox"
#define CPUID_VENDOR_XEN "XenVMMXenVMM"
#define CPUID_VENDOR_HYPERV "Microsoft Hv"
#define CPUID_VENDOR_PARALLELS " prl hyperv "
#define CPUID_VENDOR_PARALLELS_ALT " lrpepyh vr " // Sometimes Parallels incorrectly encodes "prl hyperv" as "lrpepyh vr" due to an endianness mismatch.
#define CPUID_VENDOR_BHYVE "bhyve bhyve "
#define CPUID_VENDOR_QNX " QNXQVMBSQG "
</syntaxhighlight>
You already know that the Vendor ID String is returned in EBX, ECX, EDX. Let us take an Intel processor. It should return "GenuineIntel". Look at the following text to see how the string is placed in the registers:
You already know that the Vendor ID String is returned in EBX, ECX, EDX. Let us take an Intel processor. It should return "GenuineIntel". Look at the following text to see how the string is placed in the registers:
Line 77: Line 94:
Recent processors also use ECX for features (which form a different set), with which you should be very careful as some old CPUs return bogus information in this register.
Recent processors also use ECX for features (which form a different set), with which you should be very careful as some old CPUs return bogus information in this register.


<syntaxhighlight lang="c">
<pre>
enum {
/* Flags. */
CPUID_FEAT_ECX_SSE3 = 1 << 0,
#define CPUID_FLAG_FPU 0x1 /* Floating Point Unit. */
CPUID_FEAT_ECX_PCLMUL = 1 << 1,
#define CPUID_FLAG_VME 0x2 /* Virtual Mode Extensions. */
CPUID_FEAT_ECX_DTES64 = 1 << 2,
#define CPUID_FLAG_DE 0x4 /* Debugging Extensions. */
CPUID_FEAT_ECX_MONITOR = 1 << 3,
#define CPUID_FLAG_PSE 0x8 /* Page Size Extensions. */
CPUID_FEAT_ECX_DS_CPL = 1 << 4,
#define CPUID_FLAG_TSC 0x10 /* Time Stamp Counter. */
CPUID_FEAT_ECX_VMX = 1 << 5,
#define CPUID_FLAG_MSR 0x20 /* Model-specific registers. */
CPUID_FEAT_ECX_SMX = 1 << 6,
#define CPUID_FLAG_PAE 0x40 /* Physical Address Extensions. */
CPUID_FEAT_ECX_EST = 1 << 7,
#define CPUID_FLAG_MCE 0x80 /* Machine Check Exceptions. */
CPUID_FEAT_ECX_TM2 = 1 << 8,
#define CPUID_FLAG_CXCHG8 0x100 /* Compare and exchange 8-byte. */
CPUID_FEAT_ECX_SSSE3 = 1 << 9,
#define CPUID_FLAG_APIC 0x200 /* On-chip APIC. */
CPUID_FEAT_ECX_CID = 1 << 10,
#define CPUID_FLAG_SEP 0x800 /* Fast System Calls. */
CPUID_FEAT_ECX_SDBG = 1 << 11,
#define CPUID_FLAG_MTRR 0x1000 /* Memory Type Range Registers.*/
CPUID_FEAT_ECX_FMA = 1 << 12,
#define CPUID_FLAG_PGE 0x2000 /* Page Global Enable.*/
CPUID_FEAT_ECX_CX16 = 1 << 13,
#define CPUID_FLAG_MCA 0x4000 /* Machine Check Architecture. */
CPUID_FEAT_ECX_XTPR = 1 << 14,
#define CPUID_FLAG_CMOV 0x8000 /* Conditional move-instruction. */
CPUID_FEAT_ECX_PDCM = 1 << 15,
#define CPUID_FLAG_PAT 0x10000 /* Page Attribute Table. */
CPUID_FEAT_ECX_PCID = 1 << 17,
#define CPUID_FLAG_PSE36 0x20000 /* 36-bit Page Size Extensions. */
CPUID_FEAT_ECX_DCA = 1 << 18,
#define CPUID_FLAG_PSN 0x40000 /* Processor Serial Number. */
CPUID_FEAT_ECX_SSE4_1 = 1 << 19,
#define CPUID_FLAG_CLFL 0x80000 /* CLFLUSH - fixme? */
CPUID_FEAT_ECX_SSE4_2 = 1 << 20,
#define CPUID_FLAG_DTES 0x200000 /* Debug Trace and EMON Store MSRs. */
CPUID_FEAT_ECX_X2APIC = 1 << 21,
#define CPUID_FLAG_ACPI 0x400000 /* Thermal Cotrol MSR. */
CPUID_FEAT_ECX_MOVBE = 1 << 22,
#define CPUID_FLAG_MMX 0x800000 /* MMX instruction set. */
CPUID_FEAT_ECX_POPCNT = 1 << 23,
#define CPUID_FLAG_FXSR 0x1000000 /* Fast floating point save/restore. */
CPUID_FEAT_ECX_TSC = 1 << 24,
#define CPUID_FLAG_SSE 0x2000000 /* SSE (Streaming SIMD Extensions) */
CPUID_FEAT_ECX_AES = 1 << 25,
#define CPUID_FLAG_SSE2 0x4000000 /* SSE2 (Streaming SIMD Extensions - #2) */
CPUID_FEAT_ECX_XSAVE = 1 << 26,
#define CPUID_FLAG_SS 0x8000000 /* Selfsnoop. */
CPUID_FEAT_ECX_OSXSAVE = 1 << 27,
#define CPUID_FLAG_HTT 0x10000000 /* Hyper-Threading Technology. */
CPUID_FEAT_ECX_AVX = 1 << 28,
#define CPUID_FLAG_TM1 0x20000000 /* Thermal Interrupts, Status MSRs. */
CPUID_FEAT_ECX_F16C = 1 << 29,
#define CPUID_FLAG_IA64 0x40000000 /* IA-64 (64-bit Intel CPU) */
CPUID_FEAT_ECX_RDRAND = 1 << 30,
#define CPUID_FLAG_PBE 0x80000000 /* Pending Break Event. */
CPUID_FEAT_ECX_HYPERVISOR = 1 << 31,
</pre>

CPUID_FEAT_EDX_FPU = 1 << 0,
CPUID_FEAT_EDX_VME = 1 << 1,
CPUID_FEAT_EDX_DE = 1 << 2,
CPUID_FEAT_EDX_PSE = 1 << 3,
CPUID_FEAT_EDX_TSC = 1 << 4,
CPUID_FEAT_EDX_MSR = 1 << 5,
CPUID_FEAT_EDX_PAE = 1 << 6,
CPUID_FEAT_EDX_MCE = 1 << 7,
CPUID_FEAT_EDX_CX8 = 1 << 8,
CPUID_FEAT_EDX_APIC = 1 << 9,
CPUID_FEAT_EDX_SEP = 1 << 11,
CPUID_FEAT_EDX_MTRR = 1 << 12,
CPUID_FEAT_EDX_PGE = 1 << 13,
CPUID_FEAT_EDX_MCA = 1 << 14,
CPUID_FEAT_EDX_CMOV = 1 << 15,
CPUID_FEAT_EDX_PAT = 1 << 16,
CPUID_FEAT_EDX_PSE36 = 1 << 17,
CPUID_FEAT_EDX_PSN = 1 << 18,
CPUID_FEAT_EDX_CLFLUSH = 1 << 19,
CPUID_FEAT_EDX_DS = 1 << 21,
CPUID_FEAT_EDX_ACPI = 1 << 22,
CPUID_FEAT_EDX_MMX = 1 << 23,
CPUID_FEAT_EDX_FXSR = 1 << 24,
CPUID_FEAT_EDX_SSE = 1 << 25,
CPUID_FEAT_EDX_SSE2 = 1 << 26,
CPUID_FEAT_EDX_SS = 1 << 27,
CPUID_FEAT_EDX_HTT = 1 << 28,
CPUID_FEAT_EDX_TM = 1 << 29,
CPUID_FEAT_EDX_IA64 = 1 << 30,
CPUID_FEAT_EDX_PBE = 1 << 31
};
</syntaxhighlight>


== Using CPUID from GCC ==
== Using CPUID from GCC ==

Alternatively, one can use the __get_cpuid function that comes with GCC. To use this function, include <cpuid.h>.

<syntaxhighlight lang="c">
#include <cpuid.h>

/* Example: Get CPU's model number */
static int get_model(void)
{
int ebx, unused;
__cpuid(0, unused, ebx, unused, unused);
return ebx;
}

/* Example: Check for builtin local APIC. */
static int check_apic(void)
{
unsigned int eax, unused, edx;
__get_cpuid(1, &eax, &unused, &unused, &edx);
return edx & CPUID_FEAT_EDX_APIC;
}

</syntaxhighlight>

{{Disputed}}


CPUID can be invoked with various request codes (in eax) and will return values in general registers (much as a built-in service interrupt). The following code is made Public Domain out of Clicker's x86/cpu.h
CPUID can be invoked with various request codes (in eax) and will return values in general registers (much as a built-in service interrupt). The following code is made Public Domain out of Clicker's x86/cpu.h


<syntaxhighlight lang="c">
<pre>
/* DEPRECATED: You should use the <cpuid.h> header that comes with GCC instead. */

enum cpuid_requests {
enum cpuid_requests {
CPUID_GETVENDORSTRING,
CPUID_GETVENDORSTRING,
Line 130: Line 207:
/** issue a single request to CPUID. Fits 'intel features', for instance
/** issue a single request to CPUID. Fits 'intel features', for instance
* note that even if only "eax" and "edx" are of interrest, other registers
* note that even if only "eax" and "edx" are of interest, other registers
* will be modified by the operation, so we need to tell the compiler about it.
* will be modified by the operation, so we need to tell the compiler about it.
*/
*/
static inline void cpuid(int code, dword *a, dword *d) {
static inline void cpuid(int code, uint32_t *a, uint32_t *d) {
asm volatile("cpuid":"=a"(*a),"=d"(*d):"0"(code):"ecx","ebx");
asm volatile("cpuid":"=a"(*a),"=d"(*d):"a"(code):"ecx","ebx");
}
}
/** issue a complete request, storing general registers output as a string
/** issue a complete request, storing general registers output as a string
*/
*/
static inline int cpuid_string(int code, dword where[4]) {
static inline int cpuid_string(int code, uint32_t where[4]) {
int highest;
asm volatile("cpuid":"=a"(*where),"=b"(*(where+1)),
asm volatile("cpuid":"=a"(*where),"=b"(*(where+1)),
"=c"(*(where+2)),"=d"(*(where+3)):"0"(code));
"=c"(*(where+2)),"=d"(*(where+3)):"a"(code));
return highest;
return (int)where[0];
}
}
</syntaxhighlight>
</pre>


== See Also ==
== See Also ==

===Forum Topics===
=== Articles ===
* [[VMX]] Intel's Virtual-Machine Extensions
* [[Detecting CPU Topology (80x86)]] Detecting CPU Topology on 80x86

=== Threads ===
* [[Topic:11998|CPUID For OS Developers]], an implementation written by Brynet-Inc.
* [[Topic:11998|CPUID For OS Developers]], an implementation written by Brynet-Inc.
* [[Topic:12146|Forum topic about issues with CPUID]]
* [[Topic:12146|Forum topic about issues with CPUID]]

===External Links===
===External Links===
* You can check out [http://sandpile.org/ia32/cpuid.htm SandPile.org] for an exhaustive list of functions available through CPUID instruction.
* You can check out [http://sandpile.org/x86/cpuid.htm SandPile.org] for an exhaustive list of functions available through CPUID instruction.
* Intel's [http://bochs.sourceforge.net/techspec/24161821.pdf CPUID Specification]
* Intel's [http://bochs.sourceforge.net/techspec/24161821.pdf CPUID Specification]
* AMD's [http://www.amd.com/us-en/assets/content_type/white_papers_and_tech_docs/25481.pdf CPUID Specification]
* AMD's [http://support.amd.com/TechDocs/25481.pdf CPUID Specification]


[[Category:X86_Instructions]]
[[Category:X86 CPU]]
[[Category:Hardware Detection]]
[[de:CPUID]]

Latest revision as of 05:16, 9 June 2024

The CPUID instruction can be used to retrieve various information about your CPU, such as its vendor string and model number, the size of internal caches and (more interesting), the list of CPU features supported.

How to use CPUID

Checking CPUID availability

Prior to using the CPUID instruction, you should also make sure the processor supports it by testing the 'ID' bit (0x200000) in eflags. This bit is modifiable only when the CPUID instruction is supported. For systems that don't support CPUID, changing the 'ID' bit will have no effect.

Note: Implementing this routine in for example C can lead to issues, because the compiler may change EFLAGS at any time.

This assembly routine checks if CPUID is supported:

    pushfd                               ;Save EFLAGS
    pushfd                               ;Store EFLAGS
    xor dword [esp],0x00200000           ;Invert the ID bit in stored EFLAGS
    popfd                                ;Load stored EFLAGS (with ID bit inverted)
    pushfd                               ;Store EFLAGS again (ID bit may or may not be inverted)
    pop eax                              ;eax = modified EFLAGS (ID bit may or may not be inverted)
    xor eax,[esp]                        ;eax = whichever bits were changed
    popfd                                ;Restore original EFLAGS
    and eax,0x00200000                   ;eax = zero if ID bit can't be changed, else non-zero
    ret

Note 1: There are some old CPUs where CPUID is supported but the ID bit in EFLAGS is not (NexGen). There are also CPUs that support CPUID if and only if it has to be enabled first (Cyrix M1).

Note 2: You can simply attempt to execute the CPUID instruction and see if you get an invalid opcode exception. This avoids problems with CPUs that do support CPUID but don't support the ID bit in EFLAGS; and is likely to be faster for CPUs that do support CPUID (and slower for CPUs that don't).

Basic usage

The idea of the CPUID instruction is that you can call it with different values in EAX, and it will return different information about the processor. For example, if we want the Vendor ID String (see below), we should code something like that:

mov eax, 0x0
cpuid

There are differences between AMD and Intel. According to the Intel CPUID application note, we should first check the Vendor ID String for "GenuineIntel" before taking out information, such as the Processor Signature, Processor Feature Flags, etc.

CPU Vendor ID String

When called with EAX = 0, CPUID returns the vendor ID string in EBX, EDX and ECX. Writing these to memory in this order results in a 12-character string. These can be tested against known Vendor ID strings:

// Vendor strings from CPUs.
#define CPUID_VENDOR_AMD           "AuthenticAMD"
#define CPUID_VENDOR_AMD_OLD       "AMDisbetter!" // Early engineering samples of AMD K5 processor
#define CPUID_VENDOR_INTEL         "GenuineIntel"
#define CPUID_VENDOR_VIA           "VIA VIA VIA "
#define CPUID_VENDOR_TRANSMETA     "GenuineTMx86"
#define CPUID_VENDOR_TRANSMETA_OLD "TransmetaCPU"
#define CPUID_VENDOR_CYRIX         "CyrixInstead"
#define CPUID_VENDOR_CENTAUR       "CentaurHauls"
#define CPUID_VENDOR_NEXGEN        "NexGenDriven"
#define CPUID_VENDOR_UMC           "UMC UMC UMC "
#define CPUID_VENDOR_SIS           "SiS SiS SiS "
#define CPUID_VENDOR_NSC           "Geode by NSC"
#define CPUID_VENDOR_RISE          "RiseRiseRise"
#define CPUID_VENDOR_VORTEX        "Vortex86 SoC"
#define CPUID_VENDOR_AO486         "MiSTer AO486"
#define CPUID_VENDOR_AO486_OLD     "GenuineAO486"
#define CPUID_VENDOR_ZHAOXIN       "  Shanghai  "
#define CPUID_VENDOR_HYGON         "HygonGenuine"
#define CPUID_VENDOR_ELBRUS        "E2K MACHINE "
 
// Vendor strings from hypervisors.
#define CPUID_VENDOR_QEMU          "TCGTCGTCGTCG"
#define CPUID_VENDOR_KVM           " KVMKVMKVM  "
#define CPUID_VENDOR_VMWARE        "VMwareVMware"
#define CPUID_VENDOR_VIRTUALBOX    "VBoxVBoxVBox"
#define CPUID_VENDOR_XEN           "XenVMMXenVMM"
#define CPUID_VENDOR_HYPERV        "Microsoft Hv"
#define CPUID_VENDOR_PARALLELS     " prl hyperv "
#define CPUID_VENDOR_PARALLELS_ALT " lrpepyh vr " // Sometimes Parallels incorrectly encodes "prl hyperv" as "lrpepyh vr" due to an endianness mismatch.
#define CPUID_VENDOR_BHYVE         "bhyve bhyve "
#define CPUID_VENDOR_QNX           " QNXQVMBSQG "

You already know that the Vendor ID String is returned in EBX, ECX, EDX. Let us take an Intel processor. It should return "GenuineIntel". Look at the following text to see how the string is placed in the registers:

      MSB         LSB
EBX = 'u' 'n' 'e' 'G'
EDX = 'I' 'e' 'n' 'i'
ECX = 'l' 'e' 't' 'n' 
 
 Where, MSB stands for "Most Significant Byte" and LSB is the "Least Significant Byte".

Also, EAX is set to the maximum EAX value supported for CPUID calls, as not all queries are supported on all processors.

CPU Features

When called with EAX = 1 (CPUID_GETFEATURES), CPUID returns a bit field in EDX containing the following values. Note that different brands of CPUs may have given different meanings to these. Recent processors also use ECX for features (which form a different set), with which you should be very careful as some old CPUs return bogus information in this register.

enum {
    CPUID_FEAT_ECX_SSE3         = 1 << 0, 
    CPUID_FEAT_ECX_PCLMUL       = 1 << 1,
    CPUID_FEAT_ECX_DTES64       = 1 << 2,
    CPUID_FEAT_ECX_MONITOR      = 1 << 3,  
    CPUID_FEAT_ECX_DS_CPL       = 1 << 4,  
    CPUID_FEAT_ECX_VMX          = 1 << 5,  
    CPUID_FEAT_ECX_SMX          = 1 << 6,  
    CPUID_FEAT_ECX_EST          = 1 << 7,  
    CPUID_FEAT_ECX_TM2          = 1 << 8,  
    CPUID_FEAT_ECX_SSSE3        = 1 << 9,  
    CPUID_FEAT_ECX_CID          = 1 << 10,
    CPUID_FEAT_ECX_SDBG         = 1 << 11,
    CPUID_FEAT_ECX_FMA          = 1 << 12,
    CPUID_FEAT_ECX_CX16         = 1 << 13, 
    CPUID_FEAT_ECX_XTPR         = 1 << 14, 
    CPUID_FEAT_ECX_PDCM         = 1 << 15, 
    CPUID_FEAT_ECX_PCID         = 1 << 17, 
    CPUID_FEAT_ECX_DCA          = 1 << 18, 
    CPUID_FEAT_ECX_SSE4_1       = 1 << 19, 
    CPUID_FEAT_ECX_SSE4_2       = 1 << 20, 
    CPUID_FEAT_ECX_X2APIC       = 1 << 21, 
    CPUID_FEAT_ECX_MOVBE        = 1 << 22, 
    CPUID_FEAT_ECX_POPCNT       = 1 << 23, 
    CPUID_FEAT_ECX_TSC          = 1 << 24, 
    CPUID_FEAT_ECX_AES          = 1 << 25, 
    CPUID_FEAT_ECX_XSAVE        = 1 << 26, 
    CPUID_FEAT_ECX_OSXSAVE      = 1 << 27, 
    CPUID_FEAT_ECX_AVX          = 1 << 28,
    CPUID_FEAT_ECX_F16C         = 1 << 29,
    CPUID_FEAT_ECX_RDRAND       = 1 << 30,
    CPUID_FEAT_ECX_HYPERVISOR   = 1 << 31,

    CPUID_FEAT_EDX_FPU          = 1 << 0,  
    CPUID_FEAT_EDX_VME          = 1 << 1,  
    CPUID_FEAT_EDX_DE           = 1 << 2,  
    CPUID_FEAT_EDX_PSE          = 1 << 3,  
    CPUID_FEAT_EDX_TSC          = 1 << 4,  
    CPUID_FEAT_EDX_MSR          = 1 << 5,  
    CPUID_FEAT_EDX_PAE          = 1 << 6,  
    CPUID_FEAT_EDX_MCE          = 1 << 7,  
    CPUID_FEAT_EDX_CX8          = 1 << 8,  
    CPUID_FEAT_EDX_APIC         = 1 << 9,  
    CPUID_FEAT_EDX_SEP          = 1 << 11, 
    CPUID_FEAT_EDX_MTRR         = 1 << 12, 
    CPUID_FEAT_EDX_PGE          = 1 << 13, 
    CPUID_FEAT_EDX_MCA          = 1 << 14, 
    CPUID_FEAT_EDX_CMOV         = 1 << 15, 
    CPUID_FEAT_EDX_PAT          = 1 << 16, 
    CPUID_FEAT_EDX_PSE36        = 1 << 17, 
    CPUID_FEAT_EDX_PSN          = 1 << 18, 
    CPUID_FEAT_EDX_CLFLUSH      = 1 << 19, 
    CPUID_FEAT_EDX_DS           = 1 << 21, 
    CPUID_FEAT_EDX_ACPI         = 1 << 22, 
    CPUID_FEAT_EDX_MMX          = 1 << 23, 
    CPUID_FEAT_EDX_FXSR         = 1 << 24, 
    CPUID_FEAT_EDX_SSE          = 1 << 25, 
    CPUID_FEAT_EDX_SSE2         = 1 << 26, 
    CPUID_FEAT_EDX_SS           = 1 << 27, 
    CPUID_FEAT_EDX_HTT          = 1 << 28, 
    CPUID_FEAT_EDX_TM           = 1 << 29, 
    CPUID_FEAT_EDX_IA64         = 1 << 30,
    CPUID_FEAT_EDX_PBE          = 1 << 31
};

Using CPUID from GCC

Alternatively, one can use the __get_cpuid function that comes with GCC. To use this function, include <cpuid.h>.

#include <cpuid.h>

/* Example: Get CPU's model number */
static int get_model(void)
{
    int ebx, unused;
    __cpuid(0, unused, ebx, unused, unused);
    return ebx;
}

/* Example: Check for builtin local APIC. */
static int check_apic(void)
{
    unsigned int eax, unused, edx;
    __get_cpuid(1, &eax, &unused, &unused, &edx);
    return edx & CPUID_FEAT_EDX_APIC;
}
The factual accuracy of this article is disputed.
Please see the relevant discussion on the talk page.

CPUID can be invoked with various request codes (in eax) and will return values in general registers (much as a built-in service interrupt). The following code is made Public Domain out of Clicker's x86/cpu.h

/* DEPRECATED: You should use the <cpuid.h> header that comes with GCC instead. */

enum cpuid_requests {
  CPUID_GETVENDORSTRING,
  CPUID_GETFEATURES,
  CPUID_GETTLB,
  CPUID_GETSERIAL,
  
  CPUID_INTELEXTENDED=0x80000000,
  CPUID_INTELFEATURES,
  CPUID_INTELBRANDSTRING,
  CPUID_INTELBRANDSTRINGMORE,
  CPUID_INTELBRANDSTRINGEND,
};
    
/** issue a single request to CPUID. Fits 'intel features', for instance
 *  note that even if only "eax" and "edx" are of interest, other registers
 *  will be modified by the operation, so we need to tell the compiler about it.
 */
static inline void cpuid(int code, uint32_t *a, uint32_t *d) {
  asm volatile("cpuid":"=a"(*a),"=d"(*d):"a"(code):"ecx","ebx");
}
    
/** issue a complete request, storing general registers output as a string
 */
static inline int cpuid_string(int code, uint32_t where[4]) {
  asm volatile("cpuid":"=a"(*where),"=b"(*(where+1)),
               "=c"(*(where+2)),"=d"(*(where+3)):"a"(code));
  return (int)where[0];
}

See Also

Articles

Threads

External Links