Hi, this is the 1st commit, does it work?
[vmware.git] / cpuid.c
blob920e9a26f0abde569e72191b6c699a1d5fd64d3c
1 /**
2 * file : cpuid.c
3 * author : albcamus <albcamus@gmail.com>
4 * usage : gcc -m32 cpuid.c -o cpuid
5 * ./cpuid
6 * description : a silly program to get the information of your x86 CPU.
7 * This program is licensed under GPLv2. No warrant.
8 * revision : 0.1.1 - Fix bugs about changing eflags
9 * 0.1 - First release
10 * TODO : supporting for AMD/VIA-Cyrix/Transmeta CPUs
13 #include <stdio.h>
14 #include <string.h>
15 #include <stdlib.h>
17 enum x86_cpus {
18 X86_VENDOR_INTEL,
19 X86_VENDOR_AMD,
20 X86_VENDOR_CYRIX,
21 X86_VENDOR_TRANSMETA,
22 X86_VENDOR_UNKNOWN
23 } x86_vendor;
26 void print_cache_descriptor(unsigned char);
28 int main(void)
30 unsigned int eflags1, eflags2 = 0;
31 unsigned int eax, ebx, ecx, edx;
32 unsigned int serial_num = 0;
34 eax = ebx = ecx = edx = 0;
36 /**
37 * 测试CPU是否支持CPUID指令。
38 * eflags寄存器的第21位,如果程序可以清除/设置它,则说明CPU支持CPUID指令。否则不支持
41 /* 先取eflags */
42 asm volatile ("pushf\n\t"
43 "popl %%eax"
44 : "=a"(eflags1)
46 : "memory"
48 printf("original eflags is\t\t: 0x%08x\n", eflags1);
53 /* 把eflags的第21位取反,写回寄存器中 */
54 asm volatile ("pushl %0\n\t"
55 "popf"
57 : "g"(eflags1 ^ 0x00200000)
60 /* 检查一下现在的eflags,确认第21位和最初的值相反 */
61 asm volatile ("pushf\n\t"
62 "popl %%eax"
63 : "=a"(eflags2)
65 : "memory"
67 printf("modified eflags is\t\t: 0x%08x\n", eflags2);
69 /* 如果eflags的值没有发生改变,则说明CPU不支持cpuid指令,程序退出 */
70 if (eflags1 == eflags2) {
71 printf("Sorry, Your CPU dosen't support CPUID instruction.\n");
72 exit(1);
75 /* 把原来的eflags值设置回去 */
76 asm volatile ("pushl %0\n\t"
77 "popf"
79 : "g"(eflags1)
81 /**
82 * FIXME: Intel文档并没有说,如果不支持CPUID的话,clear/set eflags的第21位会有什么错误。
83 * 它只说,在不支持CPUID指令的CPU上,如80386,执行CPUID会产生invalid opcode错误
85 * ──我猜测,如果CPUID不被支持,只是程序无法clear/set EFLAGS[21]而已.
86 * 所以,在这里我们不处理 读/写 eflags 第21比特失败的情形
90 /**
91 * eax == 0
92 * eax : cpuid指令允许的最大eax输入值
93 * ebx : "Genu"
94 * ecx : "ntel"
95 * edx : "ineI"
97 asm volatile ("cpuid"
98 : "=a"(eax), "=b"(ebx), "=c"(ecx), "=d"(edx)
99 : "0"(0)
101 printf("Maximum CPUID Input EAX\t\t: 0x%08x\n", eax);
103 char string[128];
104 snprintf(string, 5, "%s", (char *)&ebx);
105 snprintf(string + 4, 5, "%s", (char *)&edx);
106 snprintf(string + 8, 5, "%s", (char *)&ecx);
107 printf("Vendor\t\t\t\t: %s\n", string);
109 if (strcmp(string, "GenuineIntel") == 0)
110 x86_vendor = X86_VENDOR_INTEL;
111 else if (strstr(string, "AuthenticAMD") == 0 )
112 x86_vendor = X86_VENDOR_AMD;
113 else if (strstr(string, "CyrixInstead") == 0 )
114 x86_vendor = X86_VENDOR_CYRIX;
115 else if ( (strcmp(string, "GenuineTMx86") == 0) || (strcmp(string, "TransmetaCPU") == 0) )
116 x86_vendor = X86_VENDOR_TRANSMETA;
117 else
118 x86_vendor = X86_VENDOR_UNKNOWN;
121 printf("\n");
128 * eax == 1,则在eax中返回Family/Model/Stepping等信息
129 * 在EBX返回另一些信息
130 * ECX和EDX返回一些features信息
132 * EAX[0:3] stepping
133 * EAX[4:7] model
134 * EAX[8:11] family
135 * EAX[12:13] processor type
136 * EAX[16:19] extended model ID
137 * EAX[20:27] extended family ID
139 * EBX[0:7] Brand index
140 * EBX[8:15] CLFLUSH. 执行clflush时作用的I-Cache line size,Pentium4引入
141 * EBX[24:31] Local APIC ID,也是Pentium4引入
142 * //FIXME: Core2的x2APIC的APIC ID已经扩展到32bit,怎么处理?
143 * //FIX: 回答:见下面ECX[21]bit的描述
145 * ECX[0] SSE3
146 * ECX[3] MONITOR/MWAIT
147 * ECX[4] CPL Qualified Debug Store
148 * ECX[5] VMX
149 * ECX[7] EST, Enhanced SpeedStep Technology
150 * ECX[8] TM2, Thermal Monitor2
151 * ECX[9] SSSE3, Supplemental SSE3
152 * ECX[10] CNXT-ID, L1 Context ID. 如果为1,则说明L1 D-Cache可以设置为 自适应(adaptive)模式
153 * 或shared模式. 为0则说明不支持。
154 * ECX[13] CMPXCHG16B. 如果为1则说明支持该指令。
155 * ECX[14] xTPR Update Control. 为1则说明支持改变MSR寄存器IA32_MISC_ENABLES[23]的值
156 * ECX[16] PDCM, Perfmon and Debug Capability,1说明支持MSR寄存器IA32_PERF_CAPABILITIES
157 * ECX[21] x2APIC. 并且,如果该bit为1,则需要使eax==0xb && ecx==0,执行cpuid,如果ebx!=0,则CPU
158 * 支持extended topology enumeration leaf
160 * EDX[0] FPU
161 * EDX[1] VME, 用CR4的VME控制
162 * EDX[2] DE, Debugging Extensions, 用CR4的DE控制
163 * EDX[3] PSE, Page Size Extensions, 用CR4的PSE控制
164 * EDX[4] TSC, 是否支持rdtsc和wrtsc指令。用CR4.TSD控制RING3是否可以访问TSC
165 * EDX[5] MSR,是否支持rdmsr和wrmsrl指令
166 * EDX[6] PAE, Physical Address Extionsion.
167 * EDX[7] MCE, Machine Check Exception. 由CR4.MCE控制MCE特性
168 * EDX[8] CX8, CMPXCHG8B指令
169 * EDX[9] APIC On-Chip. CPU是否有APIC,内存映射默认在物理地址范围0xfffe0000~0xfffe0fff,
170 * 有些CPU允许APIC被relocate
171 * EDX[11] SEP. sysenter和sysexit指令,以及相关的MSR寄存器是否可用
172 * EDX[12] MTRR. MTRRcap MSR寄存器包含一些bits,描述了支持的variable和fixed MTRR
173 * EDX[13] PGE. PTE Global Bit. PDEs(page directory entries)和PTEs中的global bit是否支持.
174 * 如果为1,则那些对不同进程都一样的TLB entries在进程切换时不用冲刷。
175 * 用CR4.PGE来控制该特性。
176 * EDX[14] MCA, Machine Check Architecture. P6开始支持,MSR寄存器MCG_CAP包含其他多少个
177 * 相关的MSR寄存器被支持
178 * EDX[15] CMOV, Conditional Move Instructions. 看CMOV指令是否支持。 另外,如果CPUID.FPU
179 * 支持,则FCOMI和FCOMV指令支持。
180 * EDX[16] PAT. Page Attribute Table. 类似于MTRR,但PAT指定的是线性地址范围
181 * EDX[17] PSE-36, 36位的Page Size Extension. 物理地址36bit,其中高4bit用来指定一个4M页
182 * 的PDE的13~16位。
183 * EDX[18] PSN. Serial Number是否支持。
184 * EDX[19] CLFLUSH指令是否支持
185 * EDX[21] DS, Debug Store. 如果支持DS,就是CPU把调试信息写到一块驻留内存的buffer(
186 * memory-resident buffer). 该特性可以被BTS(Branch Trace Store)和PEBS(Precis
187 * event-based sampling)使用。见手册'Debugging and Performance Monitoring'部分
188 * EDX[22] ACPI, Thermal Monitor and Software Controlled Clock Facilities. 如果为真,则
189 * CPU支持热量控制和由软件控制CPU主频等ACPI特性。
190 * EDX[23] MMX
191 * EDX[24] FXSR, FXSAVE和FXRSTOR指令。 用来快速的保存/恢复 浮点上下文。 注意:即使该指令
192 * 可用,也要看CR4.OSFXSR的设置,根据后者的不同设置,FXSAVE/FXRSTOR所作用的寄存器
193 * 不同。
194 * EDX[25] SSE
195 * EDX[26] SSE2
196 * EDX[27] SS, Self Snoop. CPU支持对cache snooping进行管理。
197 * EDX[28] HTT, Muti-Threading
198 * EDX[29] TM, Thermal Monitor. CPU实现了热量监控电路(TCC: thermal control circuitry)
199 * EDX[31] PBE, Pending Break Enable. 如果支持,那么CPU处于Stop状态时(STPCLK# is asserted),
200 * 可以通过FERR#/PBE#针脚告诉CPU有中断正pending,唤醒它到正常状态去处理中断 * * *
202 asm volatile ("cpuid"
203 : "=a"(eax), "=b"(ebx), "=c"(ecx), "=d"(edx)
204 : "0"(1)
206 printf("\n");
209 /* 处理eax */
210 printf("Extended Family\t\t\t: %d\n", (0xff00000 & eax) >> 20);
211 printf("Extended Model\t\t\t: %d\n", (0xf0000 & eax) >> 16);
212 printf("Processor type\t\t\t: ");
213 switch( (0x3000 & eax) >> 12 )
215 case 0:
216 printf("Original OEM Processor\n");
217 break;
218 case 1:
219 printf("Intel OverDrive Processor\n");
220 break;
221 case 2:
222 printf("Dual Processor\n");
223 break;
224 case 3:
225 printf("Intel Reserved\n");
226 break;
227 default:
228 printf("UNKNOWN\n");
230 printf("Family\t\t\t\t: %d\n", (0xf00 & eax) >> 8);
231 printf("Model\t\t\t\t: %d\n", (0xf0 & eax) >> 4);
232 printf("Stepping:\t\t\t: %d\n", (0xf & eax));
234 printf("\n");
236 /* 处理ebx */
237 printf("Brand Index\t\t\t: %d\n", (0xff & ebx));
238 printf("I-Cache line size with CLFLUSH\t: %d\n", (0xff00 & ebx) >> 8 );
240 /* 我在Core 2 Duo上执行,输出有时是0,有时是1, 说明前后被调度到了不同的core上 */
241 printf("Local APIC ID\t\t\t: %d\n", (0xff000000 & ebx) >> 24 );
243 printf("\n");
246 /* 处理ecx */
247 printf("Features: ");
248 if ( ecx & 1 )
249 printf("\t\t\tSSE2\n");
250 if ( ecx & (1 << 3) )
251 printf("\t\t\t\tMONITOR/MWAIT\n");
252 if ( ecx & (1 << 4) )
253 printf("\t\t\t\tCPL\n");
254 if ( ecx & (1 << 5) )
255 printf("\t\t\t\tVMX\n");
256 if ( ecx & (1 << 7) )
257 printf("\t\t\t\tEST\n");
258 if ( ecx & (1 << 8) )
259 printf("\t\t\t\tTM2\n");
260 if ( ecx & (1 << 9) )
261 printf("\t\t\t\tSSSE3\n");
262 if ( ecx & (1 << 10) )
263 printf("\t\t\t\tCNXT\n");
264 if ( ecx & (1 << 13) )
265 printf("\t\t\t\tCMPXCHG16B\n");
266 if ( ecx & (1 << 14) )
267 printf("\t\t\t\txPTR\n");
268 if ( ecx & (1 << 16) )
269 printf("\t\t\t\tPDCM\t");
272 /* 处理edx */
273 if ( edx & 1 )
274 printf("\t\t\t\tFPU\n");
275 if ( edx & (1 << 1) )
276 printf("\t\t\t\tVME\n");
277 if ( edx & (1 << 2) )
278 printf("\t\t\t\tDE\n");
279 if ( edx & (1 << 3) )
280 printf("\t\t\t\tPSE\n");
281 if ( edx & (1 << 4) )
282 printf("\t\t\t\tTSC\n");
283 if ( edx & (1 << 5) )
284 printf("\t\t\t\tMSR\n");
285 if ( edx & (1 << 6) )
286 printf("\t\t\t\tPAE\n");
287 if ( edx & (1 << 7) )
288 printf("\t\t\t\tMCE\n");
289 if ( edx & (1 << 8) )
290 printf("\t\t\t\tCMPXCHG8B\n");
291 if ( edx & (1 << 9) )
292 printf("\t\t\t\tAPIC\n");
293 if ( edx & (1 << 11) )
294 printf("\t\t\t\tSEP: sysenter/sysexit\n");
295 if ( edx & (1 << 12) )
296 printf("\t\t\t\tMTRR\n");
297 if ( edx & (1 << 13) )
298 printf("\t\t\t\tPGE: PTE Global Bit\n");
299 if ( edx & (1 << 14) )
300 printf("\t\t\t\tMCA: Machine Check Architecture\n");
301 if ( edx & (1 << 15) )
302 printf("\t\t\t\tCMOV: Conditional Move Instruction\n");
303 if ( edx & (1 << 16) )
304 printf("\t\t\t\tPAT: Page Attribute Table\n");
305 if ( edx & (1 << 17) )
306 printf("\t\t\t\tPSE-36\n");
307 if ( edx & (1 << 18) ) {
308 printf("\t\t\tPSN: Processor Serial Number\n");
309 serial_num = 1;
311 if ( edx & (1 << 19) )
312 printf("\t\t\t\tCLFLUSH\n");
313 if ( edx & (1 << 21) )
314 printf("\t\t\t\tDS: Debug Store\n");
315 if ( edx & (1 << 22) )
316 printf("\t\t\t\tACPI\n");
317 if ( edx & (1 << 23) )
318 printf("\t\t\t\tMMX\n");
319 if ( edx & (1 << 24) )
320 printf("\t\t\t\tFXSR: FXSAVE and FXRSTOR\n");
321 if ( edx & (1 << 25) )
322 printf("\t\t\t\tSSE\n");
323 if ( edx & (1 << 26) )
324 printf("\t\t\t\tSSE2\n");
325 if ( edx & (1 << 27) )
326 printf("\t\t\t\tSS: Self Snoop\n");
327 if ( edx & (1 << 28) )
328 printf("\t\t\t\tHTT: Multi-Threading\n");
329 if ( edx & (1 << 29) )
330 printf("\t\t\t\tTM: Thermal Monitor\n");
331 if ( edx & (1 << 31) )
332 printf("\t\t\t\tPBE: Pending Break Enable\n");
335 printf("\n");
339 * edx的第18比特为1,则CPU支持serial number
340 * 为0,则不支持,或者被disabled
341 * 序列号有96位,其中最高32位即是eax的输出值。应当把它保存下来,然后
342 * 再设置eax==3, 取剩下的64位
344 if ( serial_num ) {
345 /* serial number supported */
346 /* edx输出中间32位的序列号,ecx输出最低32位的序列号 */
347 asm volatile ("cpuid"
348 : "=c"(ecx), "=d"(edx)
349 : "a"(3)
351 printf("Serial Number\t : %x-%x-%x-%x-%x-%x\n", eax >> 16, (eax << 16) >> 16,
352 edx >> 16, (edx << 16) >> 16, ecx >> 16, (ecx << 16) >> 16);
353 } else
354 printf("Serial Number not supported.\n");
357 printf("\n");
363 * eax == 2, Cache/TLB相关信息在EAX/EBX/ECX/EDX中返回。
365 * eax[0:7] : 一个数值,表示eax==2的CPUID指令需要执行几次才能完整获取Cache/TLB的信息
366 * : 例如如果al是2,则你还要执行一次CPUID指令(with eax==2)
368 * [eax|ebx|ecx|edx][31] : 每个寄存器的第31bit,代表了该寄存器是否包含合法的信息
369 * : 如果为0则合法,1非法
371 * 如果某寄存器第31bit为0,则每个字节(对EAX来说,第一次执行eax==2的cpuid指令时,[0:7]这个
372 * 字节不算)都包含一个值,根据这个值到表(Intel Manuals, Volume 2A, Table 3-17)中查找它代表
373 * 的意义。
375 * 该表内容见Intel手册2A,表3-17. 也可以在print_cache_descriptor()函数中找到。
378 unsigned int count = 0;
379 static unsigned char desc[4][4];
380 int i, j;
382 /** AMD的CPUID指令,其eax输入值0x0000 000[4:2] 为保留 */
383 if( x86_vendor != X86_VENDOR_AMD ) {/*{{{*/
384 do {
385 asm volatile ("cpuid"
386 : "=a"(eax), "=b"(ebx), "=c"(ecx), "=d"(edx)
387 : "0"(2)
390 if (count == 0 ) /* the first pass */
391 count = (unsigned int)(eax & 0xff);
393 if ( !(eax >> 31) ) {
394 if ( count == (unsigned int)(eax & 0xff) )
395 desc[0][0] = 0;
396 else
397 desc[0][0] = (unsigned char)eax & 0xff;
398 desc[0][1] = (eax & 0xff00) >> 8;
399 desc[0][2] = (eax & 0xff0000) >> 16;
400 desc[0][3] = (eax & 0xff000000) >> 24;
403 if ( !(ebx >> 31) ) {
404 desc[1][0] = (ebx & 0xff);
405 desc[1][1] = (ebx & 0xff00) >> 8;
406 desc[1][2] = (ebx & 0xff0000) >> 16;
407 desc[1][3] = (ebx & 0xff000000) >> 24;
410 if ( !(ecx >> 31) ) {
411 desc[2][0] = (ecx & 0xff);
412 desc[2][1] = (ecx & 0xff00) >> 8;
413 desc[2][2] = (ecx & 0xff0000) >> 16;
414 desc[2][3] = (ecx & 0xff000000) >> 24;
417 if ( !(edx >> 31) ) {
418 desc[3][0] = (edx & 0xff);
419 desc[3][1] = (edx & 0xff00) >> 8;
420 desc[3][2] = (edx & 0xff0000) >> 16;
421 desc[3][3] = (edx & 0xff000000) >> 24;
424 printf("Cache and TLB information:\n");
426 for (i = 0; i < 4; i++)
427 for(j = 0; j < 4; j++) {
428 print_cache_descriptor( (unsigned char)desc[i][j] );
431 } while (--count);
432 }/*}}}*/
435 printf("\n");
441 * Input : eax == 4 && ecx == <index>
442 * eax ==4时的cpuid指令输出取决于ecx的输入值。
443 * 返回:Deterministic Cache Parameters Leaf
445 * ecx中的值是index,可以从0开始,一直到cpuid返回的eax[0:4]值为0.
447 * EAX[0:4] : Cache Type,Type: 0 -- 没有更多level的Cache了
448 * 1 -- 数据Cache
449 * 2 -- 指令Cache
450 * 3 -- 统一Cache(不分指令/数据)
451 * EAX[5:7] : Cache Level
452 * EAX[8] : Self Initializing cache level(不需要软件初试化)
453 * EAX[9] : Fully Associative cache
454 * EAX[10] : Write-Back Invalidate和Invalidate的方式
455 * 0 : 多个线程共享Cache时,当其中一个执行WBINVD/INVD指令,
456 * CPU能保证作用到lower Level的Caches
457 * 1 : 共享Cache的多个线程,若一个线程不是WBINVD/INVD指令
458 * 的发起者,CPU不保证指令能作用到lower Level的Caches
459 * EAX[11] : Cache Inclusiveness
460 * 0 : Cache is not inclusive of lower cache levels
461 * 1 : Cache is inclusive of lower cache levels
462 * EAX[14:25] : 一个物理CPU package中,多少线程共享该Cache(需加1)
463 * EAX[26:31] : 一个物理CPU package中,共有多少Cores. (需加1)
465 * EBX[00:11] : L = System Coherency Line Size(需加1)
466 * EBX[12:21] : P = physical Line Partitions(需加1)
467 * EBX[22:31] : W = ways of associativity(需加1)
469 * ECX[00:31] : Number of Set,有多少组。(需加1)
472 * (eax[31:26] + 1) 是该物理处理器package上实现的core CPUs数目
476 /* AMD CPU的[2:4]输入值是保留了的 */
477 if ( x86_vendor != X86_VENDOR_AMD ) {/*{{{*/
479 printf("Deterministic Cache Parameters Leaf:\n");
480 int index = 0;
481 while(1)
483 asm volatile ("cpuid"
484 : "=a"(eax), "=b"(ebx), "=c"(ecx)
485 : "0"(4), "2"(index)
488 // no more caches
490 if ( !(eax & 0x1f) )
491 break;
493 printf("Index %d :\n", index);
494 printf("\tCache Type: ");
495 switch( (eax & 0x1f) ) {
496 case 0:
497 printf("Null-No more Caches\n");
498 break;
499 case 1:
500 printf("Data Cache\n");
501 break;
502 case 2:
503 printf("Instruction Cache\n");
504 break;
505 case 3:
506 printf("Unified Cache\n");
507 break;
508 default:
509 ;/* wrong value. we'll keep silent with this */
512 printf("\tCache Level\t: %d\n", (eax & 0xe0) >> 5);
513 printf("\tSelf Initializing cache level: %d\n", (eax & 0x100) >> 8);
514 printf("\tFully Associative cache: %d\n", (eax & 0x200) >> 9);
515 printf("\tWBINVD/INVD act upon lower shared cache? %s\n", (eax & (1<<10))?"No":"Yes" );
516 printf("\tCache Inclusiveness: %s\n", (eax & (1<<11))?"inclusive of lower cache levels":
517 "not inclusive of lower cache levels" );
518 printf("\tMaximum number of threads sharing this cache in a physical package: %d\n",
519 ((eax&0x3ffc000) >> 14) + 1 );
520 printf("\tMaximum number of cores in the physical package: %d\n",
521 (eax >> 26) + 1 );
523 //处理ebx
525 printf("\tSystem Coherency Line Size: %d\n", (ebx & 0xfff) + 1 );
526 printf("\tPhysical Line partitions: %d\n", ((ebx & 0x3ff000) >> 12) +1 );
527 printf("\t%d-Ways of associativity\n", (ebx >> 22) + 1 );
529 //处理ecx
531 printf("\tNumber of Sets: %d\n", ecx + 1);
536 printf("\n");
537 index++;
541 }/*}}}*/
546 * 探测x2APIC分2步:
547 * step 1: eax == 1
548 * ECX[21] x2APIC.
549 * step 2: eax == 0xb && ecx == 0
550 * ebx != 0 如果ebx!=0,则CPU支持extended topology emumeration leaf。否则不支持
552 * 注意step1执行之后发现ecx[21]==1才进行step2。
554 unsigned int has_x2apic = 0;
555 asm volatile ("cpuid"
556 : "=c" (ecx)
557 : "a"(0)
559 if (ecx & 0x00200000) {
560 printf("\t\t\t x2APIC\n");
561 has_x2apic = 1;
564 if (has_x2apic) {
565 asm volatile("cpuid"
566 : "=b" (ebx)
567 : "a"(0xb), "c"(0)
570 if (ebx != 0)
571 printf("\t\t\t Extended topology enumeration leaf\n");
584 /* XXX: eax >= 0x80000000 的输入值,是CPUID指令的扩展功能. 下面的代码是这部分功能的探测 */
593 * eax == 0x800000000
594 * 如果CPU支持Brand String,则在EAX中返 >= 0x80000004的值。
596 asm volatile ("cpuid"
597 : "=a"(eax)
598 : "0"(0x80000000)
600 printf("CPU support Brand String?\t: %s\n", eax >= 0x80000004? "yes":"no");
604 * 如果支持Brand String,则EAX从0x80000002到0x80000004,每次增1,CPUID指令返回:
605 * EAX : Processor Brand String
606 * EBX : Processor Brand String Continued
607 * ECX : Processor Brand String Continued
608 * EDX : Processor Brand String Continued
611 if(eax >= 0x80000004) {
612 printf("Brand String\t\t\t: ");
615 unsigned int brands[4]; //每次的eax、ebx、ecx、edx
616 unsigned int i;
618 for (i = 0x80000002; i <= 0x80000004; i++) {
619 asm volatile ("cpuid"
620 : "=a"(brands[0]), "=b"(brands[1]), "=c"(brands[2]), "=d"(brands[3])
621 : "0" (i)
623 printf("%s", (char *)brands);
624 } */
627 unsigned int bs[] = { [0 ... 12] = 0 };
628 asm volatile("cpuid"
629 : "=a"(bs[0]), "=b"(bs[1]), "=c"(bs[2]), "=d"(bs[3])
630 : "0"(0x80000002)
632 asm volatile("cpuid"
633 : "=a"(bs[4]), "=b"(bs[5]), "=c"(bs[6]), "=d"(bs[7])
634 : "0"(0x80000003)
636 asm volatile("cpuid"
637 : "=a"(bs[8]), "=b"(bs[9]), "=c"(bs[10]), "=d"(bs[11])
638 : "0"(0x80000004)
641 printf("%s\n", (char *)bs);
647 printf("\n");
651 * eax == 0x80000001
652 * 如果CPU支持NX,如果edx的第20比特为1,则说明支持NX(Non-eXecute);否则不支持。
654 * eax : extended processor signature and extended feature bits
655 * ecx[0] : LAHF/SAHF 在64位模式下有效
656 * edx[11] : SYSCALL/SYSRET在64-bit下有效
657 * edx[20] : NX
658 * edx[29] : Intel 64技术(AKA EM64T)
660 asm volatile ("cpuid"
661 : "=d"(edx)
662 : "a"(0x80000001)
665 if ( ecx & 0x1 )
666 printf("\t\t\t\tLAHF/SAHF available when in 64-bit mode.\n");
668 if ( edx & 0x800 )
669 printf("\t\t\t\tSYSCALL/SYSRET available when in 64-bit mode.\n");
670 if ( edx & 0x100000 )
671 printf("\t\t\t\tNX: Execute Disable\n");
672 if ( edx & 0x20000000 )
673 printf("\t\t\t\tIntel 64(AKA EM64T)\n");
676 printf("\n");
680 printf("\n");
684 * eax == 80000006h,返回L2 Cache的信息
686 * ecx[31:16] : L2 Cache size, in Kbytes
687 * ecx[15:12] : L2 Cache Associativity
688 * 00h disabled
689 * 01h direct mapped
690 * 02h 2-Way
691 * 04h 4-Way
692 * 06h 8-Way
693 * 08h 16-Way
694 * 0Fh Fully associative
695 * ecx[7:0] : L2 Cache Line size in bytes
697 asm volatile ("cpuid"
698 : "=c"(ecx)
699 : "a"(0x80000006)
701 printf("L2 Cache Size\t\t\t: %d Kbytes\n", ( ecx >> 16 ) );
702 printf("L2 Cache Line Size\t\t: %d bytes\n", (ecx & 0xff));
704 printf("L2 Cache Associativity\t\t: ");
705 switch ( (ecx & 0xf000) >> 12 )
707 case 0x00:
708 printf("%s\n", "disabled");
709 break;
710 case 0x01:
711 printf("%s\n", "direct mapped");
712 break;
713 case 0x02:
714 printf("%s\n", "2-Way");
715 break;
716 case 0x04:
717 printf("%s\n", "4-Way");
718 break;
719 case 0x06:
720 printf("%s\n", "8-Way");
721 break;
722 case 0x08:
723 printf("%s\n", "16-Way");
724 break;
725 case 0x0f:
726 printf("Fully associative");
727 break;
728 default:
729 printf("No such entry...\n");
732 printf("\n");
738 * eax == 0x80000008
740 * EAX[0:7] : 物理地址bits
741 * EAX[8:15] : 虚拟地址bits
743 asm volatile ("cpuid"
744 : "=a"(eax)
745 : "0"(0x80000008)
747 printf("Physical Address Bits\t\t: %d\n", (0xff & eax));
748 printf("Virtual Address Bits\t\t: %d\n", (0xff00 & eax) >> 8);
750 printf("\n");
755 printf("\n");
757 return 0;
760 void print_cache_descriptor(unsigned char desc)
761 {/*{{{*/
762 switch (desc)
764 case 0x00:
765 break;
766 case 0x01:
767 printf("\t\t\t\t: Instruction TLB: 4 KByte pages, 4-way set associative, 32 entries\n");
768 break;
769 case 0x02:
770 printf("\t\t\t\t: Instruction TLB: 4 MByte pages, 4-way set associative, 2 entries\n");
771 break;
772 case 0x03:
773 printf("\t\t\t\t: Data TLB: 4 KByte pages, 4-way set associative, 64 entries\n");
774 break;
775 case 0x04:
776 printf("\t\t\t\t: Data TLB: 4 MByte pages, 4-way set associative, 8 entries\n");
777 break;
778 case 0x05:
779 printf("\t\t\t\t: Data TLB1: 4 MByte pages, 4-way set associative, 32 entries\n");
780 break;
781 case 0x06:
782 printf("\t\t\t\t: 1st-level instruction cache: 8 KBytes, 4-way set associative, 32 byte line size\n");
783 break;
784 case 0x08:
785 printf("\t\t\t\t: 1st-level instruction cache: 16 KBytes, 4-way set associative, 32 byte line size\n");
786 break;
787 case 0x0a:
788 printf("\t\t\t\t: 1st-level data cache: 8 KBytes, 2-way set associative, 32 byte line size\n");
789 break;
790 case 0x0b:
791 printf("\t\t\t\t: Instruction TLB: 4 MByte pages, 4-way set associative, 4 entries\n");
792 break;
793 case 0x0c:
794 printf("\t\t\t\t: 1st-level data cache: 16 KBytes, 4-way set associative, 32 byte line size\n");
795 break;
796 case 0x22:
797 printf("\t\t\t\t: 3rd-level cache: 512 KBytes, 4-way set associative, 64 byte line size, 2 lines per sector\n");
798 break;
799 case 0x23:
800 printf("\t\t\t\t: 3rd-level cache: 1 MBytes, 8-way set associative, 64 byte line size, 2 lines per sector\n");
801 break;
802 case 0x25:
803 printf("\t\t\t\t: 3rd-level cache: 2 MBytes, 8-way set associative, 64 byte line size, 2 lines per sector\n");
804 break;
805 case 0x29:
806 printf("\t\t\t\t: 3rd-level cache: 4 MBytes, 8-way set associative, 64 byte line size, 2 lines per sector\n");
807 break;
808 case 0x2c:
809 printf("\t\t\t\t: 1st-level data cache: 32 KBytes, 8-way set associative, 64 byte line size\n");
810 break;
811 case 0x30:
812 printf("\t\t\t\t: 1st-level instruction cache: 32 KBytes, 8-way set associative, 64 byte line size\n");
813 break;
814 case 0x40:
815 printf("\t\t\t\t: No 2nd-level cache or, if processor contains a valid 2nd-level cache, no 3rd-level cache\n");
816 break;
817 case 0x41:
818 printf("\t\t\t\t: 2nd-level cache: 128 KBytes, 4-way set associative, 32 byte line size\n");
819 break;
820 case 0x42:
821 printf("\t\t\t\t: 2nd-level cache: 256 KBytes, 4-way set associative, 32 byte line size\n");
822 break;
823 case 0x43:
824 printf("\t\t\t\t: 2nd-level cache: 512 KBytes, 4-way set associative, 32 byte line size\n");
825 break;
826 case 0x44:
827 printf("\t\t\t\t: 2nd-level cache: 1 MByte, 4-way set associative, 32 byte line size\n");
828 break;
829 case 0x45:
830 printf("\t\t\t\t: 2nd-level cache: 2 MByte, 4-way set associative, 32 byte line size\n");
831 break;
832 case 0x46:
833 printf("\t\t\t\t: 3rd-level cache: 4 MByte, 4-way set associative, 64 byte line size\n");
834 break;
835 case 0x47:
836 printf("\t\t\t\t: 3rd-level cache: 8 MByte, 8-way set associative, 64 byte line size\n");
837 break;
838 case 0x49:
839 printf("\t\t\t\t: 2nd-level cache: 4 MByte, 16-way set associative, 64 byte line size\n");
840 break;
841 case 0x50:
842 printf("\t\t\t\t: Instruction TLB: 4 KByte and 2-MByte or 4-MByte pages, 64 entries\n");
843 break;
844 case 0x51:
845 printf("\t\t\t\t: Instruction TLB: 4 KByte and 2-MByte or 4-MByte pages, 128 entries\n");
846 break;
847 case 0x52:
848 printf("\t\t\t\t: Instruction TLB: 4 KByte and 2-MByte or 4-MByte pages, 256 entries\n");
849 break;
850 case 0x56:
851 printf("\t\t\t\t: Data TLB0: 4 MByte pages, 4-way set associative, 16 entries\n");
852 break;
853 case 0x57:
854 printf("\t\t\t\t: Data TLB0: 4 KByte pages, 4-way associative, 16 entries\n");
855 break;
856 case 0x5B:
857 printf("\t\t\t\t: Data TLB: 4 KByte and 4 MByte pages, 64 entries\n");
858 break;
859 case 0x5c:
860 printf("\t\t\t\t: Data TLB: 4 KByte and 4 MByte pages,128 entries\n");
861 break;
862 case 0x5d:
863 printf("\t\t\t\t: Data TLB: 4 KByte and 4 MByte pages,256 entries\n");
864 break;
865 case 0x60:
866 printf("\t\t\t\t: 1st-level data cache: 16 KByte, 8-way set associative, 64 byte line size\n");
867 break;
868 case 0x66:
869 printf("\t\t\t\t: 1st-level data cache: 8 KByte, 4-way set associative, 64 byte line size\n");
870 break;
871 case 0x67:
872 printf("\t\t\t\t: 1st-level data cache: 16 KByte, 4-way set associative, 64 byte line size\n");
873 break;
874 case 0x68:
875 printf("\t\t\t\t: 1st-level data cache: 32 KByte, 4-way set associative, 64 byte line size\n");
876 break;
877 case 0x70:
878 printf("\t\t\t\t: Trace cache: 12 K-μop, 8-way set associative\n");
879 break;
880 case 0x71:
881 printf("\t\t\t\t: Trace cache: 16 K-μop, 8-way set associative\n");
882 break;
883 case 0x72:
884 printf("\t\t\t\t: Trace cache: 32 K-μop, 8-way set associative\n");
885 break;
886 case 0x78:
887 printf("\t\t\t\t: 2nd-level cache: 1 MByte, 4-way set associative, 64byte line size\n");
888 break;
889 case 0x79:
890 printf("\t\t\t\t: 2nd-level cache: 128 KByte, 8-way set associative, 64 byte line size, 2 lines per sector\n");
891 break;
892 case 0x7a:
893 printf("\t\t\t\t: 2nd-level cache: 256 KByte, 8-way set associative, 64 byte line size, 2 lines per sector\n");
894 break;
895 case 0x7b:
896 printf("\t\t\t\t: 2nd-level cache: 512 KByte, 8-way set associative, 64 byte line size, 2 lines per sector\n");
897 break;
898 case 0x7c:
899 printf("\t\t\t\t: 2nd-level cache: 1 MByte, 8-way set associative, 64 byte line size, 2 lines per sector\n");
900 break;
901 case 0x7d:
902 printf("\t\t\t\t: 2nd-level cache: 2 MByte, 8-way set associative, 64byte line size\n");
903 break;
904 case 0x7f:
905 printf("\t\t\t\t: 2nd-level cache: 512 KByte, 2-way set associative, 64-byte line size\n");
906 break;
907 case 0x82:
908 printf("\t\t\t\t: 2nd-level cache: 256 KByte, 8-way set associative, 32 byte line size\n");
909 break;
910 case 0x83:
911 printf("\t\t\t\t: 2nd-level cache: 512 KByte, 8-way set associative, 32 byte line size\n");
912 break;
913 case 0x84:
914 printf("\t\t\t\t: 2nd-level cache: 1 MByte, 8-way set associative, 32 byte line size\n");
915 break;
916 case 0x85:
917 printf("\t\t\t\t: 2nd-level cache: 2 MByte, 8-way set associative, 32 byte line size\n");
918 break;
919 case 0x86:
920 printf("\t\t\t\t: 2nd-level cache: 512 KByte, 4-way set associative, 64 byte line size\n");
921 break;
922 case 0x87:
923 printf("\t\t\t\t: 2nd-level cache: 1 MByte, 8-way set associative, 64 byte line size\n");
924 break;
925 case 0xb0:
926 printf("\t\t\t\t: Instruction TLB: 4 KByte pages, 4-way set associative, 128 entries\n");
927 break;
928 case 0xb3:
929 printf("\t\t\t\t: Data TLB: 4 KByte pages, 4-way set associative, 128 entries\n");
930 break;
931 case 0xb4:
932 printf("\t\t\t\t: Data TLB1: 4 KByte pages, 4-way associative, 256 entries\n");
933 break;
934 case 0xf0:
935 printf("\t\t\t\t: 64-Byte prefetching\n");
936 break;
937 case 0xf1:
938 printf("\t\t\t\t: 128-Byte prefetching\n");
939 break;
941 default:
942 ;/* invalid descriptor. We'll print nothing */
945 }/*}}}*/