]> git.ozlabs.org Git - ccan/blob - ccan/cpuid/cpuid.c
d27441022d2bad386d4361a2ee5fbdff7113a402
[ccan] / ccan / cpuid / cpuid.c
1 /*
2  * Copyright (c) 2013 Ahmed Samy  <f.fallen45@gmail.com>
3  *
4  * Permission is hereby granted, free of charge, to any person obtaining a copy
5  * of this software and associated documentation files (the "Software"), to deal
6  * in the Software without restriction, including without limitation the rights
7  * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
8  * copies of the Software, and to permit persons to whom the Software is
9  * furnished to do so, subject to the following conditions:
10  *
11  * The above copyright notice and this permission notice shall be included in
12  * all copies or substantial portions of the Software.
13  *
14  * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
15  * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
16  * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
17  * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
18  * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
19  * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
20  * THE SOFTWARE.
21  *
22  * This file has been written with some help from wikipedia:
23  *      http://en.wikipedia.org/wiki/CPUID
24  */
25
26 /* Only compile this file if we're on a x86 machine.  */
27 #if defined(__i386__) || defined(__i386) || defined(__x86_64) \
28         || defined(_M_AMD64) || defined(__M_X64)
29 #include "cpuid.h"
30
31 #include <string.h>
32 #include <stdio.h>
33
34 enum {
35         CPUID_PROC_BRAND_STRING_INTERNAL0               = 0x80000003,
36         CPUID_PROC_BRAND_STRING_INTERNAL1               = 0x80000004
37 };
38
39 #ifndef _MSC_VER
40 static void ___cpuid(cpuid_t info, uint32_t *eax, uint32_t *ebx, uint32_t *ecx, uint32_t *edx)
41 {
42         __asm__(
43                 "xchg %%ebx, %%edi\n\t"         /* 32bit PIC: Don't clobber ebx.  */
44                 "cpuid\n\t"
45                 "xchg %%ebx, %%edi\n\t"
46                 : "=a"(*eax), "=D"(*ebx), "=c"(*ecx), "=d"(*edx)
47                 : "0" (info)
48         );
49 }
50 #else
51 #include <intrin.h>
52
53 static void ___cpuid(cpuid_t info, uint32_t *eax, uint32_t *ebx, uint32_t *ecx, uint32_t *edx)
54 {
55         uint32_t registers[4];
56         __cpuid(registers, info);
57
58         *eax = registers[0];
59         *ebx = registers[1];
60         *ecx = registers[2];
61         *edx = registers[3];
62 }
63 #endif
64
65 bool cpuid_is_supported(void)
66 {
67         int ret = 0;
68 #if defined(__GNUC__) || defined(__clang__)
69         /* The following assembly code uses EAX as the return value,
70          * but we store the value of EAX into ret since GCC uses EAX
71          * as the return register for every C function.  That's a double
72          * operation, but there's no other way to do this unless doing this
73          * function entirely in assembly.
74          *
75          * The following assembly code has been shamelessly stolen from:
76          *      http://wiki.osdev.org/CPUID
77          * and converted to work with AT&T syntax.
78          *
79          * This check is to make sure that the compiler is actually compiling
80          * for 64-bit.
81          *
82          * The compiler can be 32-bit and the system 64-bit so the 
83          * following would be true:
84          *      #if defined(__x86_64) ...
85          */
86
87 #if UINTPTR_MAX == 0xffffffffffffffff
88 #define ASM_PUSHF       "pushfq\n\t"
89 #define ASM_POPF        "popfq\n\t"
90 #define ASM_PUSHEAX     "pushq %%rax\n\t"
91 #define ASM_POPEAX      "popq %%rax\n\t"
92 #define ASM_PUSHECX     "pushq %%rcx\n\t"
93 #elif UINTPTR_MAX == 0xffffffff
94 #define ASM_PUSHF       "pushfl\n\t"
95 #define ASM_POPF        "popfl\n\t"
96 #define ASM_PUSHEAX     "pushl %%eax\n\t"
97 #define ASM_POPEAX      "popl %%eax\n\t"
98 #define ASM_PUSHECX     "pushl %%ecx\n\t"
99 #endif
100
101         asm volatile(
102                 ASM_PUSHF
103                 ASM_POPEAX
104                 "movl %%eax, %%ecx\n\t"
105                 "xorl $0x200000, %%eax\n\t"
106                 ASM_PUSHEAX
107                 ASM_POPF
108                 ASM_PUSHF
109                 ASM_POPEAX
110                 "xorl %%ecx, %%eax\n\t"
111                 "shrl $21, %%eax\n\t"
112                 "andl $1, %%eax\n\t"
113                 ASM_PUSHECX
114                 ASM_POPF
115                 : "=a" (ret)
116         );
117
118 #undef ASM_PUSHF
119 #undef ASM_POPF
120 #undef ASM_PUSHEAX
121 #undef ASM_POPEAX
122 #undef ASM_PUSHECX
123 #elif defined _MSC_VER
124         __asm {
125                 pushfd
126                 pop eax
127                 mov ecx, eax
128                 xor eax, 0x200000
129                 push eax
130                 popfd
131
132                 pushfd
133                 pop eax
134                 xor eax, ecx
135                 shr eax, 21
136                 and eax, 1
137                 push ecx
138                 popfd
139
140                 mov eax, ret
141         };
142 #endif
143         return !!ret;
144 }
145
146 bool cpuid_test_feature(cpuid_t feature)
147 {
148         if (feature > CPUID_VIRT_PHYS_ADDR_SIZES || feature < CPUID_EXTENDED_PROC_INFO_FEATURE_BITS)
149                 return false;
150
151         return (feature <= cpuid_highest_ext_func_supported());
152 }
153
154 bool cpuid_has_ecxfeature(int feature)
155 {
156         static uint32_t _ecx;
157         if (_ecx == 0) {
158 #if defined(__GNUC__) || defined(__clang__)
159                 asm volatile(
160                         "cpuid\n\t"
161                         : "=c" (_ecx)
162                         : "a" (CPUID_PROCINFO_AND_FEATUREBITS)
163                 );
164 #elif defined _MSC_VER
165                 __asm {
166                         mov eax, CPUID_PROCINFO_AND_FEATUREBITS
167                         cpuid
168                         mov _ecx, ecx
169                 };
170 #endif
171         }
172
173         return (_ecx & feature) == feature;
174 }
175
176 bool cpuid_has_edxfeature(int feature)
177 {
178         static uint32_t _edx;
179         if (_edx == 0) {
180 #if defined(__GNUC__) || defined(__clang__)
181                 asm volatile(
182                         "cpuid\n\t"
183                         : "=d" (_edx)
184                         : "a" (CPUID_PROCINFO_AND_FEATUREBITS)
185                 );
186 #elif defined _MSC_VER
187                 __asm {
188                         mov eax, CPUID_PROCINFO_AND_FEATUREBITS
189                         cpuid
190                         mov _edx, edx
191                 };
192 #endif
193         }
194
195         return (_edx & feature) == feature;
196 }
197
198 static const char *const cpuids[] = {
199         "Nooooooooone",
200         "AMDisbetter!",
201         "AuthenticAMD",
202         "CentaurHauls",
203         "CyrixInstead",
204         "GenuineIntel",
205         "TransmetaCPU",
206         "GeniuneTMx86",
207         "Geode by NSC",
208         "NexGenDriven",
209         "RiseRiseRise",
210         "SiS SiS SiS ",
211         "UMC UMC UMC ",
212         "VIA VIA VIA ",
213         "Vortex86 SoC",
214         "KVMKVMKVMKVM"
215 };
216
217 cputype_t cpuid_get_cpu_type(void)
218 {
219         static cputype_t cputype;
220         if (cputype == CT_NONE) {
221                 union {
222                         char buf[12];
223                         uint32_t bufu32[3];
224                 } u;
225                 uint32_t i;
226
227                 ___cpuid(CPUID_VENDORID, &i, &u.bufu32[0], &u.bufu32[2], &u.bufu32[1]);
228                 for (i = 0; i < sizeof(cpuids) / sizeof(cpuids[0]); ++i) {
229                         if (strncmp(cpuids[i], u.buf, 12) == 0) {
230                                 cputype = (cputype_t)i;
231                                 break;
232                         }
233                 }
234         }
235
236         return cputype;
237 }
238
239 bool cpuid_sprintf_cputype(const cputype_t cputype, char *buf)
240 {
241         if (cputype == CT_NONE)
242                 return false;
243
244         memcpy(buf, cpuids[(int)cputype], 12);
245         buf[12] = '\0';
246         return true;
247 }
248
249 uint32_t cpuid_highest_ext_func_supported(void)
250 {
251         static uint32_t highest;
252
253         if (!highest) {
254 #if defined(__GNUC__) || defined(__clang__)
255                 asm volatile(
256                         "cpuid\n\t"
257                         : "=a" (highest)
258                         : "a" (CPUID_HIGHEST_EXTENDED_FUNCTION_SUPPORTED)
259                 );
260 #elif defined _MSC_VER
261                 __asm {
262                         mov eax, CPUID_HIGHEST_EXTENDED_FUNCTION_SUPPORTED
263                         cpuid
264                         mov highest, eax
265                 };
266 #endif
267         }
268
269         return highest;
270 }
271
272 void cpuid(cpuid_t info, uint32_t *buf)
273 {
274         /* Sanity checks, make sure we're not trying to do something
275          * invalid or we are trying to get information that isn't supported
276          * by the CPU.  */
277         if (info > CPUID_VIRT_PHYS_ADDR_SIZES || (info > CPUID_HIGHEST_EXTENDED_FUNCTION_SUPPORTED
278                 && !cpuid_test_feature(info)))
279                 return;
280
281         if (info == CPUID_PROC_BRAND_STRING) {
282                 static char cached[48] = { 0 };
283                 if (cached[0] == '\0') {
284                         ___cpuid(CPUID_PROC_BRAND_STRING,           &buf[0], &buf[1], &buf[2],  &buf[3] );
285                         ___cpuid(CPUID_PROC_BRAND_STRING_INTERNAL0, &buf[4], &buf[5], &buf[6],  &buf[7] );
286                         ___cpuid(CPUID_PROC_BRAND_STRING_INTERNAL1, &buf[8], &buf[9], &buf[10], &buf[11]);
287
288                         memcpy(cached, buf, sizeof cached);
289                 } else
290                         buf = (uint32_t *)cached;
291
292                 return;
293         } else if (info == CPUID_HIGHEST_EXTENDED_FUNCTION_SUPPORTED) {
294                 *buf = cpuid_highest_ext_func_supported();
295                 return;
296         }
297
298         uint32_t eax, ebx, ecx, edx;
299         ___cpuid(info, &eax, &ebx, &ecx, &edx);
300
301         switch (info) {
302                 case CPUID_VENDORID:
303                         buf[0] = ebx;
304                         buf[1] = edx;
305                         buf[2] = ecx;
306                         break;
307                 case CPUID_PROCINFO_AND_FEATUREBITS:
308                         buf[0] = (eax & 0x0F);          /* Stepping  */
309                         buf[1] = (eax >> 4)  & 0x0F;    /* Model  */
310                         buf[2] = (eax >> 8)  & 0x0F;    /* Family  */
311                         buf[3] = (eax >> 16) & 0x0F;    /* Extended Model.  */
312                         buf[4] = (eax >> 24) & 0x0F;    /* Extended Family.  */
313
314                         /* Additional Feature information.  */
315                         buf[5] = ebx & 0xFF;
316                         buf[6] = (ebx >> 8) & 0xFF;
317                         buf[7] = (ebx >> 16) & 0xFF;
318                         buf[8] = ebx >> 24;
319                         break;
320                 case CPUID_CACHE_AND_TLBD_INFO:
321                         buf[0] = eax;
322                         buf[1] = ebx;
323                         buf[2] = ecx;
324                         buf[3] = edx;
325                         break;
326                 case CPUID_EXTENDED_PROC_INFO_FEATURE_BITS:
327                         buf[0] = edx;
328                         buf[1] = ecx;
329                         break;
330                 case CPUID_L1_CACHE_AND_TLB_IDS:
331                         buf[0] = eax & 0xFF;
332                         buf[1] = (eax >> 8) & 0xFF;
333                         buf[2] = (eax >> 16) & 0xFF;
334                         buf[3] = eax >> 24;
335
336                         buf[4] = ebx & 0xFF;
337                         buf[5] = (ebx >> 8) & 0xFF;
338                         buf[6] = (ebx >> 16) & 0xFF;
339                         buf[7] = ebx >> 24;
340
341                         buf[8] = ecx & 0xFF;
342                         buf[9] = (ecx >> 8) & 0xFF;
343                         buf[10] = (ecx >> 16) & 0xFF;
344                         buf[11] = ecx >> 24;
345
346                         buf[12] = edx & 0xFF;
347                         buf[13] = (edx >> 8) & 0xFF;
348                         buf[14] = (edx >> 16) & 0xFF;
349                         buf[15] = edx >> 24;
350                         break;
351                 case CPUID_EXTENDED_L2_CACHE_FEATURES:
352                         buf[0] = ecx & 0xFF;            /* Line size.  */
353                         buf[1] = (ecx >> 12) & 0xFF;    /* Associativity.  */
354                         buf[2] = ecx >> 16;             /* Cache size.  */
355                         break;
356                 case CPUID_ADV_POWER_MGT_INFO:
357                         *buf = edx;
358                         break;
359                 case CPUID_VIRT_PHYS_ADDR_SIZES:
360                         buf[0] = eax & 0xFF;            /* physical.  */
361                         buf[1] = (eax >> 8) & 0xFF;     /* virtual.  */
362                         break;
363                 default:
364                         *buf = 0xbaadf00d;
365                         break;
366         }
367 }
368
369 bool cpuid_write_info(uint32_t info, uint32_t featureset, const char *outfile)
370 {
371         FILE *file;
372         char filename[256];
373         char cpu_information[64];
374
375         if (!cpuid_sprintf_cputype(cpuid_get_cpu_type(), cpu_information))
376                 return false;
377
378         char brand[48];
379         cpuid(CPUID_PROC_BRAND_STRING, (uint32_t *)brand);
380
381         cpu_information[12] = '_';
382         memcpy(&cpu_information[13], brand, sizeof brand);
383
384         if (!outfile)
385                 strncpy(filename, cpu_information, sizeof cpu_information);
386         else
387                 strncpy(filename, outfile, sizeof filename);
388
389         file = fopen(filename, "w");
390         if (!file)
391                 return false;
392
393         fprintf(file, "-- CPU Information for CPU: %s --\n\n", cpu_information);
394
395         if (info & CPUID_HIGHEST_EXTENDED_FUNCTION_SUPPORTED)
396                 fprintf(file, "Highest extended function supported: %#010x\n\n", cpuid_highest_ext_func_supported());
397
398         if (info & CPUID_EXTENDED_L2_CACHE_FEATURES) {
399                 uint32_t l2c[3];
400                 cpuid(CPUID_EXTENDED_L2_CACHE_FEATURES, l2c);
401
402                 fprintf(file, "-- Extended L2 Cache features --\nL2 Line size: %u bytes\nAssociativity: %02xh\nCache Size: %u KB\n\n",
403                         l2c[0], l2c[1], l2c[2]);
404         }
405
406         if (info & CPUID_VIRT_PHYS_ADDR_SIZES) {
407                 uint32_t phys_virt[2];
408                 cpuid(CPUID_VIRT_PHYS_ADDR_SIZES, phys_virt);
409
410                 fprintf(file, "-- Virtual and Physical address sizes --\n"
411                                 "Physical address size: %d\nVirtual address size: %d\n\n", phys_virt[0], phys_virt[1]);
412         }
413
414         if (info & CPUID_PROCINFO_AND_FEATUREBITS) {
415                 uint32_t procinfo[9];
416                 cpuid(CPUID_PROCINFO_AND_FEATUREBITS, procinfo);
417
418                 fputs("-- Processor information and feature bits --\n", file    );
419                 fprintf(file, "Stepping: %d\nModel: 0x%X\nFamily: %d\nExtended model: %d\nExtended family: %d\n",
420                         procinfo[0], procinfo[1], procinfo[2], procinfo[3], procinfo[4]);
421                 fprintf(file, "\nBrand Index: %d\nCL Flush Line Size: %d\nLogical Processors: %d\nInitial APICID: %d\n\n",
422                         procinfo[5], procinfo[6], procinfo[7], procinfo[8]);
423         }
424
425         if (featureset != 0)
426                 fputs("-- CPU FEATURES --\n\n", file);
427
428         bool
429                 sse3    = cpuid_has_ecxfeature(CPUID_FEAT_ECX_SSE3),
430                 pclmul  = cpuid_has_ecxfeature(CPUID_FEAT_ECX_PCLMUL),
431                 dtes64  = cpuid_has_ecxfeature(CPUID_FEAT_ECX_DTES64),
432                 monitor = cpuid_has_ecxfeature(CPUID_FEAT_ECX_MONITOR),
433                 ds_cpl  = cpuid_has_ecxfeature(CPUID_FEAT_ECX_DS_CPL),
434                 vmx     = cpuid_has_ecxfeature(CPUID_FEAT_ECX_VMX),
435                 smx     = cpuid_has_ecxfeature(CPUID_FEAT_ECX_SMX),
436                 est     = cpuid_has_ecxfeature(CPUID_FEAT_ECX_EST),
437                 tm2     = cpuid_has_ecxfeature(CPUID_FEAT_ECX_TM2),
438                 ssse3   = cpuid_has_ecxfeature(CPUID_FEAT_ECX_SSSE3),
439                 cid     = cpuid_has_ecxfeature(CPUID_FEAT_ECX_CID),
440                 fma     = cpuid_has_ecxfeature(CPUID_FEAT_ECX_FMA),
441                 cx16    = cpuid_has_ecxfeature(CPUID_FEAT_ECX_CX16),
442                 etprd   = cpuid_has_ecxfeature(CPUID_FEAT_ECX_ETPRD),
443                 pdcm    = cpuid_has_ecxfeature(CPUID_FEAT_ECX_PDCM),
444                 dca     = cpuid_has_ecxfeature(CPUID_FEAT_ECX_DCA),
445                 sse4_1  = cpuid_has_ecxfeature(CPUID_FEAT_ECX_SSE4_1),
446                 sse4_2  = cpuid_has_ecxfeature(CPUID_FEAT_ECX_SSE4_2),
447                 x2_apic = cpuid_has_ecxfeature(CPUID_FEAT_ECX_x2APIC),
448                 movbe   = cpuid_has_ecxfeature(CPUID_FEAT_ECX_MOVBE),
449                 popcnt  = cpuid_has_ecxfeature(CPUID_FEAT_ECX_POPCNT),
450                 aes     = cpuid_has_ecxfeature(CPUID_FEAT_ECX_AES),
451                 xsave   = cpuid_has_ecxfeature(CPUID_FEAT_ECX_XSAVE),
452                 osxsave = cpuid_has_ecxfeature(CPUID_FEAT_ECX_OSXSAVE),
453                 avx     = cpuid_has_ecxfeature(CPUID_FEAT_ECX_AVX);
454
455 #define YON(v)  (v) ? "Yes" : "No"
456         if (featureset & CPUID_FEAT_ECX_ALL) {
457                 fputs("-- ECX Features --\n", file);
458                 fprintf(file, "SSE3:    %s\n"
459                               "PCMUL:   %s\n"
460                               "DTES64:  %s\n"
461                               "MONITOR: %s\n"
462                               "DS_CPL:  %s\n"
463                               "VMX:     %s\n"
464                               "SMX:     %s\n"
465                               "EST:     %s\n"
466                               "TM2:     %s\n"
467                               "SSSE3:   %s\n"
468                               "CID:     %s\n"
469                               "FMA:     %s\n"
470                               "CX16:    %s\n"
471                               "ETPRD:   %s\n"
472                               "PDCM:    %s\n"
473                               "DCA:     %s\n"
474                               "SSE4_1:  %s\n"
475                               "SSE$_2:  %s\n"
476                               "X2_APIC: %s\n"
477                               "MOVBE:   %s\n"
478                               "POPCNT:  %s\n"
479                               "AES:     %s\n"
480                               "XSAVE:   %s\n"
481                               "OSXSAVE: %s\n"
482                               "AVS:     %s\n\n",
483                         YON(sse3), YON(pclmul), YON(dtes64), YON(monitor), YON(ds_cpl),
484                         YON(vmx), YON(smx), YON(est), YON(tm2), YON(ssse3), YON(cid),
485                         YON(fma), YON(cx16), YON(etprd), YON(pdcm), YON(dca), YON(sse4_1),
486                         YON(sse4_2), YON(x2_apic), YON(movbe), YON(popcnt), YON(aes),
487                         YON(xsave), YON(osxsave), YON(avx)
488                 );
489         } else {
490                 if (featureset & CPUID_FEAT_ECX_SSE3)
491                         fprintf(file, "SSE3:    %s\n", YON(sse3));
492                 if (featureset & CPUID_FEAT_ECX_PCLMUL)
493                         fprintf(file, "PCLMUL:    %s\n", YON(pclmul));
494                 if (featureset & CPUID_FEAT_ECX_DTES64)
495                         fprintf(file, "DTES64:    %s\n", YON(dtes64));
496                 if (featureset & CPUID_FEAT_ECX_MONITOR)
497                         fprintf(file, "Monitor:    %s\n", YON(monitor));
498                 if (featureset & CPUID_FEAT_ECX_DS_CPL)
499                         fprintf(file, "DS CPL:    %s\n", YON(ds_cpl));
500                 if (featureset & CPUID_FEAT_ECX_VMX)
501                         fprintf(file, "VMX:    %s\n", YON(vmx));
502                 if (featureset & CPUID_FEAT_ECX_SMX)
503                         fprintf(file, "SMX:    %s\n", YON(smx));
504                 if (featureset & CPUID_FEAT_ECX_EST)
505                         fprintf(file, "EST:    %s\n", YON(est));
506                 if (featureset & CPUID_FEAT_ECX_TM2)
507                         fprintf(file, "TM2:    %s\n", YON(tm2));
508                 if (featureset & CPUID_FEAT_ECX_SSSE3)
509                         fprintf(file, "SSSE3:    %s\n", YON(ssse3));
510                 if (featureset & CPUID_FEAT_ECX_CID)
511                         fprintf(file, "CID:    %s\n", YON(cid));
512                 if (featureset & CPUID_FEAT_ECX_FMA)
513                         fprintf(file, "FMA:    %s\n", YON(fma));
514                 if (featureset & CPUID_FEAT_ECX_CX16)
515                         fprintf(file, "CX16:    %s\n", YON(cx16));
516                 if (featureset & CPUID_FEAT_ECX_ETPRD)
517                         fprintf(file, "ETPRD:    %s\n", YON(etprd));
518                 if (featureset & CPUID_FEAT_ECX_PDCM)
519                         fprintf(file, "PDCM:    %s\n", YON(pdcm));
520                 if (featureset & CPUID_FEAT_ECX_DCA)
521                         fprintf(file, "DCA:    %s\n", YON(dca));
522                 if (featureset & CPUID_FEAT_ECX_SSE4_1)
523                         fprintf(file, "SSE4_1:    %s\n", YON(sse4_1));
524                 if (featureset & CPUID_FEAT_ECX_SSE4_2)
525                         fprintf(file, "SSE4_2:    %s\n", YON(sse4_2));
526                 if (featureset & CPUID_FEAT_ECX_x2APIC)
527                         fprintf(file, "x2APIC:    %s\n", YON(x2_apic));
528                 if (featureset & CPUID_FEAT_ECX_MOVBE)
529                         fprintf(file, "MOVBE:    %s\n", YON(movbe));
530                 if (featureset & CPUID_FEAT_ECX_POPCNT)
531                         fprintf(file, "POPCNT:    %s\n", YON(popcnt));
532                 if (featureset & CPUID_FEAT_ECX_AES)
533                         fprintf(file, "AES:    %s\n", YON(aes));
534                 if (featureset & CPUID_FEAT_ECX_XSAVE)
535                         fprintf(file, "XSAVE:    %s\n", YON(xsave));
536                 if (featureset & CPUID_FEAT_ECX_OSXSAVE)
537                         fprintf(file, "OSXSAVE:    %s\n", YON(osxsave));
538                 if (featureset & CPUID_FEAT_ECX_AVX)
539                         fprintf(file, "AVX:    %s\n", YON(avx));
540         }
541
542         bool
543                 fpu = cpuid_has_edxfeature(CPUID_FEAT_EDX_FPU),
544                 vme   = cpuid_has_edxfeature(CPUID_FEAT_EDX_VME),
545                 de    = cpuid_has_edxfeature(CPUID_FEAT_EDX_DE),
546                 pse   = cpuid_has_edxfeature(CPUID_FEAT_EDX_PSE),
547                 tsc   = cpuid_has_edxfeature(CPUID_FEAT_EDX_TSC),
548                 msr   = cpuid_has_edxfeature(CPUID_FEAT_EDX_MSR),
549                 pae   = cpuid_has_edxfeature(CPUID_FEAT_EDX_PAE),
550                 mce   = cpuid_has_edxfeature(CPUID_FEAT_EDX_MCE),
551                 cx8   = cpuid_has_edxfeature(CPUID_FEAT_EDX_CX8),
552                 apic  = cpuid_has_edxfeature(CPUID_FEAT_EDX_APIC),
553                 sep   = cpuid_has_edxfeature(CPUID_FEAT_EDX_SEP),
554                 mtrr  = cpuid_has_edxfeature(CPUID_FEAT_EDX_MTRR),
555                 pge   = cpuid_has_edxfeature(CPUID_FEAT_EDX_PGE),
556                 mca   = cpuid_has_edxfeature(CPUID_FEAT_EDX_MCA),
557                 cmov  = cpuid_has_edxfeature(CPUID_FEAT_EDX_CMOV),
558                 pat   = cpuid_has_edxfeature(CPUID_FEAT_EDX_PAT),
559                 pse36 = cpuid_has_edxfeature(CPUID_FEAT_EDX_PSE36),
560                 psn   = cpuid_has_edxfeature(CPUID_FEAT_EDX_PSN),
561                 clf   = cpuid_has_edxfeature(CPUID_FEAT_EDX_CLF),
562                 dtes  = cpuid_has_edxfeature(CPUID_FEAT_EDX_DTES),
563                 acpi  = cpuid_has_edxfeature(CPUID_FEAT_EDX_ACPI),
564                 mmx   = cpuid_has_edxfeature(CPUID_FEAT_EDX_MMX),
565                 fxsr  = cpuid_has_edxfeature(CPUID_FEAT_EDX_FXSR),
566                 sse   = cpuid_has_edxfeature(CPUID_FEAT_EDX_SSE),
567                 sse2  = cpuid_has_edxfeature(CPUID_FEAT_EDX_SSE2),
568                 ss    = cpuid_has_edxfeature(CPUID_FEAT_EDX_SS),
569                 htt   = cpuid_has_edxfeature(CPUID_FEAT_EDX_HTT),
570                 tm1   = cpuid_has_edxfeature(CPUID_FEAT_EDX_TM1),
571                 ia64  = cpuid_has_edxfeature(CPUID_FEAT_EDX_IA64),
572                 pbe   = cpuid_has_edxfeature(CPUID_FEAT_EDX_PBE);
573
574         if (featureset & CPUID_FEAT_EDX_ALL) {
575                 fputs("-- EDX FEATURES --\n", file);
576                 fprintf(file, "FPU:   %s\n"
577                               "VME:   %s\n"
578                               "DE:    %s\n"
579                               "PSE:   %s\n"
580                               "TSC:   %s\n"
581                               "MSR:   %s\n"
582                               "PAE:   %s\n"
583                               "MCE:   %s\n"
584                               "CX8:   %s\n"
585                               "APIC:  %s\n"
586                               "SEP:   %s\n"
587                               "MTRR:  %s\n"
588                               "PGE:   %s\n"
589                               "MCA:   %s\n"
590                               "CMOV:  %s\n"
591                               "PAT:   %s\n"
592                               "PSE36: %s\n"
593                               "PSN:   %s\n"
594                               "CLF:   %s\n"
595                               "DTES:  %s\n"
596                               "ACPI:  %s\n"
597                               "MMX:   %s\n"
598                               "FXSR:  %s\n"
599                               "SSE:   %s\n"
600                               "SSE2:  %s\n"
601                               "SS:    %s\n"
602                               "HTT:   %s\n"
603                               "TM1:   %s\n"
604                               "IA64:  %s\n"
605                               "PBE:   %s\n\n",
606                         YON(fpu), YON(vme), YON(de), YON(pse), YON(tsc), YON(msr),
607                         YON(pae), YON(mce), YON(cx8), YON(apic), YON(sep), YON(mtrr),
608                         YON(pge), YON(mca), YON(cmov), YON(pat), YON(pse36), YON(psn),
609                         YON(clf), YON(dtes), YON(acpi), YON(mmx), YON(fxsr), YON(sse),
610                         YON(sse2), YON(ss), YON(htt), YON(tm1), YON(ia64), YON(pbe)
611                 );
612         } else {
613                 if (featureset & CPUID_FEAT_EDX_FPU)
614                         fprintf(file, "FPU:   %s\n", YON(fpu));
615                 if (featureset & CPUID_FEAT_EDX_VME)
616                         fprintf(file, "VME:   %s\n", YON(vme));
617                 if (featureset & CPUID_FEAT_EDX_DE)
618                         fprintf(file, "DE: %s\n", YON(de));
619                 if (featureset & CPUID_FEAT_EDX_PSE)
620                         fprintf(file, "PSE:   %s\n", YON(pse));
621                 if (featureset & CPUID_FEAT_EDX_TSC)
622                         fprintf(file, "TSC:   %s\n", YON(tsc));
623                 if (featureset & CPUID_FEAT_EDX_MSR)
624                         fprintf(file, "MSR:   %s\n", YON(msr));
625                 if (featureset & CPUID_FEAT_EDX_PAE)
626                         fprintf(file, "PAE:   %s\n", YON(pae));
627                 if (featureset & CPUID_FEAT_EDX_MCE)
628                         fprintf(file, "MCE:   %s\n", YON(mce));
629                 if (featureset & CPUID_FEAT_EDX_CX8)
630                         fprintf(file, "CX8:   %s\n", YON(cx8));
631                 if (featureset & CPUID_FEAT_EDX_APIC)
632                         fprintf(file, "APIC: %s\n", YON(apic));
633                 if (featureset & CPUID_FEAT_EDX_SEP)
634                         fprintf(file, "SEP:   %s\n", YON(sep));
635                 if (featureset & CPUID_FEAT_EDX_MTRR)
636                         fprintf(file, "MTRR: %s\n", YON(mtrr));
637                 if (featureset & CPUID_FEAT_EDX_PGE)
638                         fprintf(file, "PGE:   %s\n", YON(pge));
639                 if (featureset & CPUID_FEAT_EDX_MCA)
640                         fprintf(file, "MCA:   %s\n", YON(mca));
641                 if (featureset & CPUID_FEAT_EDX_CMOV)
642                         fprintf(file, "CMOV: %s\n", YON(cmov));
643                 if (featureset & CPUID_FEAT_EDX_PAT)
644                         fprintf(file, "PAT:   %s\n", YON(pat));
645                 if (featureset & CPUID_FEAT_EDX_PSE36)
646                         fprintf(file, "PSE36: %s\n", YON(pse36));
647                 if (featureset & CPUID_FEAT_EDX_PSN)
648                         fprintf(file, "PSN:   %s\n", YON(psn));
649                 if (featureset & CPUID_FEAT_EDX_CLF)
650                         fprintf(file, "CLF:   %s\n", YON(clf));
651                 if (featureset & CPUID_FEAT_EDX_DTES)
652                         fprintf(file, "DTES:%s\n", YON(dtes));
653                 if (featureset & CPUID_FEAT_EDX_ACPI)
654                         fprintf(file, "ACPI: %s\n", YON(acpi));
655                 if (featureset & CPUID_FEAT_EDX_MMX)
656                         fprintf(file, "MMX:   %s\n", YON(mmx));
657                 if (featureset & CPUID_FEAT_EDX_FXSR)
658                         fprintf(file, "FXSR: %s\n", YON(fxsr));
659                 if (featureset & CPUID_FEAT_EDX_SSE)
660                         fprintf(file, "SSE:   %s\n", YON(sse));
661                 if (featureset & CPUID_FEAT_EDX_SSE2)
662                         fprintf(file, "SSE2: %s\n", YON(sse2));
663                 if (featureset & CPUID_FEAT_EDX_SS)
664                         fprintf(file, "SS: %s\n", YON(ss));
665                 if (featureset & CPUID_FEAT_EDX_HTT)
666                         fprintf(file, "HTT:   %s\n", YON(htt));
667                 if (featureset & CPUID_FEAT_EDX_TM1)
668                         fprintf(file, "TM1:   %s\n", YON(tm1));
669                 if (featureset & CPUID_FEAT_EDX_IA64)
670                         fprintf(file, "IA64: %s\n", YON(ia64));
671                 if (featureset & CPUID_FEAT_EDX_PBE)
672                         fprintf(file, "PBE:   %s\n", YON(pbe));
673         }
674 #undef YON
675
676         fclose(file);
677         return true;
678 }
679
680 #endif