查看“CPUID”的源代码
←
CPUID
跳到导航
跳到搜索
因为以下原因,您没有权限编辑本页:
您请求的操作仅限属于该用户组的用户执行:
用户
您可以查看和复制此页面的源代码。
CPUID指令可用于检索有关cpu的各种信息,如供应商字符串和型号、内部缓存的大小以及(更有趣的是)支持的cpu功能列表。 ==如何使用CPUID== === 检查CPUID可用性 === 在使用CPUID指令之前,还应该通过测试eflags中的“ID”位(0x200000)来确保处理器支持该指令。 此位仅在支持CPUID指令时才可修改。 对于不支持CPUID的系统,更改 'ID' 位不会有任何影响。 '''注意:'''在示例C中实现此例程可能会导致问题,因为编译器可能随时更改EFLAG。 此汇编例程检查是否支持CPUID: <source lang="asm"> pushfd ;保存EFLAGS pushfd ;存储EFLAGS xor dword [esp],0x00200000 ;反转存储的EFLAGS中的ID位 popfd ;加载存储的电子标志 (ID位反转) pushfd ;再次存储EFLAGS(ID位可能反转,也可能不反转) pop eax ;eax=修改后的EFLAGS(ID位可能反转,也可能不反转) xor eax,[esp] ;eax = 更改了哪些位 popfd ;恢复原始EFLAG and eax,0x00200000 ;如果ID位不能更改,则eax=0,否则为非零值 ret </source> 注1: 有一些旧的cpu支持CPUID但eblags中的ID位不支持 (NexGen)。 当且仅当必须首先启用CPUID(Cyrix M1)时,这些CPU也支持CPUID。 注2:您可以简单地尝试执行CPUID指令,并查看是否得到无效操作码异常。 这避免了支持CPUID但不支持EBLAGS中的ID位的cpu的问题; 对于支持CPUID的CPU,速度可能会更快(对于不支持CPUID的CPU,速度可能会更慢)。 ===基本用法=== CPUID指令的想法是,您可以在EAX中使用不同的值调用它,它将返回有关处理器的不同信息。 例如,如果我们想要供应商ID字符串(见下文),我们应该这样编码: <source lang="asm"> mov eax, 0x0 cpuid </source> AMD和英特尔之间存在差异。 根据Intel CPUID应用说明,在取出信息 (例如处理器签名,处理器功能标志等) 之前,我们应该首先检查供应商ID字符串中的 “GenuineIntel”。 ===CPU供应商ID字符串=== 在EAX=0的情况下调用时,CPUID返回EBX、EDX和ECX格式的供应商ID字符串。 按此顺序将它们写入内存会产生12个字符的字符串。 这些可以根据已知的供应商ID字符串进行测试: <source lang="c"> /* Vendor strings from CPUs. */ #define CPUID_VENDOR_OLDAMD "AMDisbetter!" // Early engineering samples of AMD K5 processor #define CPUID_VENDOR_AMD "AuthenticAMD" #define CPUID_VENDOR_INTEL "GenuineIntel" #define CPUID_VENDOR_VIA "VIA VIA VIA " #define CPUID_VENDOR_OLDTRANSMETA "TransmetaCPU" #define CPUID_VENDOR_TRANSMETA "GenuineTMx86" #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_OLDAO486 "GenuineAO486" #define CPUID_VENDOR_AO486 "MiSTer AO486" #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 " //有时Parallels会因为字节顺序不匹配而将“PRL HyperV”错误地编码为“lrpepyh VR”。 #define CPUID_VENDOR_BHYVE "bhyve bhyve " #define CPUID_VENDOR_QNX " QNXQVMBSQG " </source> 您已经知道供应商ID字符串在EBX,ECX,EDX中返回。 让我们以英特尔处理器为例。 它应该返回“GenuineIntel”。 查看以下文本,以了解如何将字符串放置在寄存器中: <pre> MSB LSB EBX = 'u' 'n' 'e' 'G' EDX = 'I' 'e' 'n' 'i' ECX = 'l' 'e' 't' 'n' 其中,MSB代表“最高有效字节”,LSB代表“最低有效字节”。 </pre> 此外,EAX设置为CPUID调用支持的最大EAX值,因为并非所有处理器都支持所有查询。 === 中央处理器功能 === 当使用EAX=1(CPUID_GETFEATURES)调用CPUID时,CPUID会在EDX中返回一个包含以下值的位字段。 请注意,不同品牌的CPU可能会赋予这些处理器不同的含义。 最近的一些处理器还将ECX用于功能 (形成不同的集合),由于某些旧cpu在此寄存器中返回虚假信息,因此您应该非常小心。 <source lang="c"> 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 }; </source> ==在GCC中使用CPUID== 或者,可以使用GCC附带的__get_cpuid函数。 要使用此函数,请包含 <cpuid.h>。 <source lang="c"> #include <cpuid.h> /*示例:获取CPU的型号*/ static int get_model(void) { int ebx, unused; __cpuid(0, unused, ebx, unused, unused); return ebx; } /*示例:检查内置本地APIC。*/ static int check_apic(void) { unsigned int eax, unused, edx; __get_cpuid(1, &eax, &unused, &unused, %edx); return edx & CPUID_FEAT_EDX_APIC; } </source> {{Disputed}} CPUID可以用各种请求代码 (在eax中) 调用,并且将在一般寄存器中返回值 (很大程度上是内置的服务中断)。 以下代码由Clicker的x86/cpu.h公开。H <source lang="c"> /*已弃用:应该使用GCC附带的<cpuid.h>头。*/ enum cpuid_requests { CPUID_GETVENDORSTRING, CPUID_GETFEATURES, CPUID_GETTLB, CPUID_GETSERIAL, CPUID_INTELEXTENDED=0x80000000, CPUID_INTELFEATURES, CPUID_INTELBRANDSTRING, CPUID_INTELBRANDSTRINGMORE, CPUID_INTELBRANDSTRINGEND, }; /** 向CPUID发出单个请求。例如,适配 “intel功能特性” * 请注意,即使只关注“eax”和“edx”,其他寄存器 * 将被操作修改,因此我们需要将其告知编译器。 */ static inline void cpuid(int code, uint32_t *a, uint32_t *d) { asm volatile("cpuid":"=a"(*a),"=d"(*d):"a"(code):"ecx","ebx"); } /** 发出完整请求,将通用寄存器输出存储为字符串 */ 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]; } </source> ==另见== ===文章=== * [[VMX]] 英特尔的虚拟机扩展(Virtual-Machine Extensions) * [[Detecting CPU Topology (80x86)]]检测80x86上的CPU拓扑 === 论坛文章 === * [[Topic:11998|CPUID For OS Developers]], an implementation written by Brynet-Inc. * [[Topic:12146|Forum topic about issues with CPUID]] === 外部链接 === * 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] * AMD's [http://support.amd.com/TechDocs/25481.pdf CPUID Specification] [[Category:X86 CPU]] [[de:CPUID]]
本页使用的模板:
模板:DiscussThis
(
查看源代码
)
模板:Disputed
(
查看源代码
)
返回至“
CPUID
”。
导航菜单
个人工具
登录
命名空间
页面
讨论
变体
已展开
已折叠
查看
阅读
查看源代码
查看历史
更多
已展开
已折叠
搜索
导航
首页
最近更改
随机页面
MediaWiki帮助
工具
链入页面
相关更改
特殊页面
页面信息