]> git.ozlabs.org Git - ccan/blob - ccan/cpuid/cpuid.c
cpuid: Now we support extended feature testing.
[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 #if defined(__GNUC__) || defined(__clang__)
155 static uint32_t fetch_ecx(uint32_t what)
156 {
157         static uint32_t ecx;
158         if (ecx == 0) {
159                 asm volatile(
160                         "cpuid\n\t"
161                         : "=c" (ecx)
162                         : "a" (what)
163                 );
164         }
165
166         return ecx;
167 }
168
169 static uint32_t fetch_edx(uint32_t what)
170 {
171         static uint32_t edx;
172         if (edx == 0) {
173                 asm volatile(
174                         "cpuid\n\t"
175                         : "=d" (edx)
176                         : "a" (what)
177                 );
178         }
179
180         return edx;
181 }
182 #elif defined(_MSC_VER)
183 static uint32_t fetch_ecx(uint32_t what)
184 {
185         static uint32_t _ecx;
186         if (_ecx == 0) {
187                 __asm {
188                         mov eax, what
189                         cpuid
190                         mov _ecx, ecx
191                 };
192         }
193
194         return _ecx;
195 }
196
197 static uint32_t fetch_edx(uint32_t what)
198 {
199         static uint32_t _edx;
200         if (_edx == 0) {
201                 __asm {
202                         mov eax, what
203                         cpuid
204                         mov _edx, edx
205                 };
206         }
207
208         return _edx;
209 }
210 #endif
211
212 #define DEFINE_FEATURE_FUNC(NAME, REGISTER, TYPE) \
213         bool cpuid_has_##NAME(int feature) \
214         { \
215                 static uint32_t REGISTER; \
216                 if (REGISTER == 0) \
217                         REGISTER = fetch_##REGISTER(TYPE); \
218                 return (REGISTER & feature) == feature; \
219         }
220
221 DEFINE_FEATURE_FUNC(ecxfeature, ecx, CPUID_PROCINFO_AND_FEATUREBITS)
222 DEFINE_FEATURE_FUNC(edxfeature, edx, CPUID_PROCINFO_AND_FEATUREBITS)
223
224 DEFINE_FEATURE_FUNC(ecxfeature_ext, ecx, CPUID_EXTENDED_PROC_INFO_FEATURE_BITS)
225 DEFINE_FEATURE_FUNC(edxfeature_ext, edx, CPUID_EXTENDED_PROC_INFO_FEATURE_BITS)
226
227 #undef DEFINE_FEATURE_FUNC
228
229 static const char *const cpuids[] = {
230         "Nooooooooone",
231         "AMDisbetter!",
232         "AuthenticAMD",
233         "CentaurHauls",
234         "CyrixInstead",
235         "GenuineIntel",
236         "TransmetaCPU",
237         "GeniuneTMx86",
238         "Geode by NSC",
239         "NexGenDriven",
240         "RiseRiseRise",
241         "SiS SiS SiS ",
242         "UMC UMC UMC ",
243         "VIA VIA VIA ",
244         "Vortex86 SoC",
245         "KVMKVMKVMKVM"
246 };
247
248 cputype_t cpuid_get_cpu_type(void)
249 {
250         static cputype_t cputype;
251         if (cputype == CT_NONE) {
252                 union {
253                         char buf[12];
254                         uint32_t bufu32[3];
255                 } u;
256                 uint32_t i;
257
258                 ___cpuid(CPUID_VENDORID, &i, &u.bufu32[0], &u.bufu32[2], &u.bufu32[1]);
259                 for (i = 0; i < sizeof(cpuids) / sizeof(cpuids[0]); ++i) {
260                         if (strncmp(cpuids[i], u.buf, 12) == 0) {
261                                 cputype = (cputype_t)i;
262                                 break;
263                         }
264                 }
265         }
266
267         return cputype;
268 }
269
270 bool cpuid_sprintf_cputype(const cputype_t cputype, char *buf)
271 {
272         if (cputype == CT_NONE)
273                 return false;
274
275         memcpy(buf, cpuids[(int)cputype], 12);
276         buf[12] = '\0';
277         return true;
278 }
279
280 uint32_t cpuid_highest_ext_func_supported(void)
281 {
282         static uint32_t highest;
283
284         if (!highest) {
285 #if defined(__GNUC__) || defined(__clang__)
286                 asm volatile(
287                         "cpuid\n\t"
288                         : "=a" (highest)
289                         : "a" (CPUID_HIGHEST_EXTENDED_FUNCTION_SUPPORTED)
290                 );
291 #elif defined _MSC_VER
292                 __asm {
293                         mov eax, CPUID_HIGHEST_EXTENDED_FUNCTION_SUPPORTED
294                         cpuid
295                         mov highest, eax
296                 };
297 #endif
298         }
299
300         return highest;
301 }
302
303 void cpuid(cpuid_t info, uint32_t *buf)
304 {
305         /* Sanity checks, make sure we're not trying to do something
306          * invalid or we are trying to get information that isn't supported
307          * by the CPU.  */
308         if (info > CPUID_VIRT_PHYS_ADDR_SIZES || (info > CPUID_HIGHEST_EXTENDED_FUNCTION_SUPPORTED
309                 && !cpuid_test_feature(info)))
310                 return;
311
312         if (info == CPUID_PROC_BRAND_STRING) {
313                 static char cached[48] = { 0 };
314                 if (cached[0] == '\0') {
315                         ___cpuid(CPUID_PROC_BRAND_STRING,           &buf[0], &buf[1], &buf[2],  &buf[3] );
316                         ___cpuid(CPUID_PROC_BRAND_STRING_INTERNAL0, &buf[4], &buf[5], &buf[6],  &buf[7] );
317                         ___cpuid(CPUID_PROC_BRAND_STRING_INTERNAL1, &buf[8], &buf[9], &buf[10], &buf[11]);
318
319                         memcpy(cached, buf, sizeof cached);
320                 } else
321                         buf = (uint32_t *)cached;
322
323                 return;
324         } else if (info == CPUID_HIGHEST_EXTENDED_FUNCTION_SUPPORTED) {
325                 *buf = cpuid_highest_ext_func_supported();
326                 return;
327         }
328
329         uint32_t eax, ebx, ecx, edx;
330         ___cpuid(info, &eax, &ebx, &ecx, &edx);
331
332         switch (info) {
333                 case CPUID_VENDORID:
334                         buf[0] = ebx;
335                         buf[1] = edx;
336                         buf[2] = ecx;
337                         break;
338                 case CPUID_PROCINFO_AND_FEATUREBITS:
339                         buf[0] = (eax & 0x0F);          /* Stepping  */
340                         buf[1] = (eax >> 4)  & 0x0F;    /* Model  */
341                         buf[2] = (eax >> 8)  & 0x0F;    /* Family  */
342                         buf[3] = (eax >> 16) & 0x0F;    /* Extended Model.  */
343                         buf[4] = (eax >> 24) & 0x0F;    /* Extended Family.  */
344
345                         /* Additional Feature information.  */
346                         buf[5] = ebx & 0xFF;
347                         buf[6] = (ebx >> 8) & 0xFF;
348                         buf[7] = (ebx >> 16) & 0xFF;
349                         buf[8] = ebx >> 24;
350                         break;
351                 case CPUID_CACHE_AND_TLBD_INFO:
352                         buf[0] = eax;
353                         buf[1] = ebx;
354                         buf[2] = ecx;
355                         buf[3] = edx;
356                         break;
357                 case CPUID_EXTENDED_PROC_INFO_FEATURE_BITS:
358                         buf[0] = edx;
359                         buf[1] = ecx;
360                         break;
361                 case CPUID_L1_CACHE_AND_TLB_IDS:
362                         buf[0] = eax & 0xFF;
363                         buf[1] = (eax >> 8) & 0xFF;
364                         buf[2] = (eax >> 16) & 0xFF;
365                         buf[3] = eax >> 24;
366
367                         buf[4] = ebx & 0xFF;
368                         buf[5] = (ebx >> 8) & 0xFF;
369                         buf[6] = (ebx >> 16) & 0xFF;
370                         buf[7] = ebx >> 24;
371
372                         buf[8] = ecx & 0xFF;
373                         buf[9] = (ecx >> 8) & 0xFF;
374                         buf[10] = (ecx >> 16) & 0xFF;
375                         buf[11] = ecx >> 24;
376
377                         buf[12] = edx & 0xFF;
378                         buf[13] = (edx >> 8) & 0xFF;
379                         buf[14] = (edx >> 16) & 0xFF;
380                         buf[15] = edx >> 24;
381                         break;
382                 case CPUID_EXTENDED_L2_CACHE_FEATURES:
383                         buf[0] = ecx & 0xFF;            /* Line size.  */
384                         buf[1] = (ecx >> 12) & 0xFF;    /* Associativity.  */
385                         buf[2] = ecx >> 16;             /* Cache size.  */
386                         break;
387                 case CPUID_ADV_POWER_MGT_INFO:
388                         *buf = edx;
389                         break;
390                 case CPUID_VIRT_PHYS_ADDR_SIZES:
391                         buf[0] = eax & 0xFF;            /* physical.  */
392                         buf[1] = (eax >> 8) & 0xFF;     /* virtual.  */
393                         break;
394                 default:
395                         *buf = 0xbaadf00d;
396                         break;
397         }
398 }
399
400 bool cpuid_write_info(uint32_t info, uint32_t featureset, const char *outfile)
401 {
402         FILE *file;
403         char filename[256];
404         char cpu_information[64];
405
406         if (!cpuid_sprintf_cputype(cpuid_get_cpu_type(), cpu_information))
407                 return false;
408
409         char brand[48];
410         cpuid(CPUID_PROC_BRAND_STRING, (uint32_t *)brand);
411
412         cpu_information[12] = '_';
413         memcpy(&cpu_information[13], brand, sizeof brand);
414
415         if (!outfile)
416                 strncpy(filename, cpu_information, sizeof cpu_information);
417         else
418                 strncpy(filename, outfile, sizeof filename);
419
420         file = fopen(filename, "w");
421         if (!file)
422                 return false;
423
424         fprintf(file, "-- CPU Information for CPU: %s --\n\n", cpu_information);
425
426         if (info & CPUID_HIGHEST_EXTENDED_FUNCTION_SUPPORTED)
427                 fprintf(file, "Highest extended function supported: %#010x\n\n", cpuid_highest_ext_func_supported());
428
429         if (info & CPUID_EXTENDED_L2_CACHE_FEATURES) {
430                 uint32_t l2c[3];
431                 cpuid(CPUID_EXTENDED_L2_CACHE_FEATURES, l2c);
432
433                 fprintf(file, "-- Extended L2 Cache features --\nL2 Line size: %u bytes\nAssociativity: %02xh\nCache Size: %u KB\n\n",
434                         l2c[0], l2c[1], l2c[2]);
435         }
436
437         if (info & CPUID_VIRT_PHYS_ADDR_SIZES) {
438                 uint32_t phys_virt[2];
439                 cpuid(CPUID_VIRT_PHYS_ADDR_SIZES, phys_virt);
440
441                 fprintf(file, "-- Virtual and Physical address sizes --\n"
442                                 "Physical address size: %d\nVirtual address size: %d\n\n", phys_virt[0], phys_virt[1]);
443         }
444
445         if (info & CPUID_PROCINFO_AND_FEATUREBITS) {
446                 uint32_t procinfo[9];
447                 cpuid(CPUID_PROCINFO_AND_FEATUREBITS, procinfo);
448
449                 fputs("-- Processor information and feature bits --\n", file    );
450                 fprintf(file, "Stepping: %d\nModel: 0x%X\nFamily: %d\nExtended model: %d\nExtended family: %d\n",
451                         procinfo[0], procinfo[1], procinfo[2], procinfo[3], procinfo[4]);
452                 fprintf(file, "\nBrand Index: %d\nCL Flush Line Size: %d\nLogical Processors: %d\nInitial APICID: %d\n\n",
453                         procinfo[5], procinfo[6], procinfo[7], procinfo[8]);
454         }
455
456         if (featureset != 0)
457                 fputs("-- CPU FEATURES --\n\n", file);
458
459         bool
460                 sse3    = cpuid_has_ecxfeature(CPUID_FEAT_ECX_SSE3),
461                 pclmul  = cpuid_has_ecxfeature(CPUID_FEAT_ECX_PCLMUL),
462                 dtes64  = cpuid_has_ecxfeature(CPUID_FEAT_ECX_DTES64),
463                 monitor = cpuid_has_ecxfeature(CPUID_FEAT_ECX_MONITOR),
464                 ds_cpl  = cpuid_has_ecxfeature(CPUID_FEAT_ECX_DS_CPL),
465                 vmx     = cpuid_has_ecxfeature(CPUID_FEAT_ECX_VMX),
466                 smx     = cpuid_has_ecxfeature(CPUID_FEAT_ECX_SMX),
467                 est     = cpuid_has_ecxfeature(CPUID_FEAT_ECX_EST),
468                 tm2     = cpuid_has_ecxfeature(CPUID_FEAT_ECX_TM2),
469                 ssse3   = cpuid_has_ecxfeature(CPUID_FEAT_ECX_SSSE3),
470                 cid     = cpuid_has_ecxfeature(CPUID_FEAT_ECX_CID),
471                 fma     = cpuid_has_ecxfeature(CPUID_FEAT_ECX_FMA),
472                 cx16    = cpuid_has_ecxfeature(CPUID_FEAT_ECX_CX16),
473                 etprd   = cpuid_has_ecxfeature(CPUID_FEAT_ECX_ETPRD),
474                 pdcm    = cpuid_has_ecxfeature(CPUID_FEAT_ECX_PDCM),
475                 dca     = cpuid_has_ecxfeature(CPUID_FEAT_ECX_DCA),
476                 sse4_1  = cpuid_has_ecxfeature(CPUID_FEAT_ECX_SSE4_1),
477                 sse4_2  = cpuid_has_ecxfeature(CPUID_FEAT_ECX_SSE4_2),
478                 x2_apic = cpuid_has_ecxfeature(CPUID_FEAT_ECX_x2APIC),
479                 movbe   = cpuid_has_ecxfeature(CPUID_FEAT_ECX_MOVBE),
480                 popcnt  = cpuid_has_ecxfeature(CPUID_FEAT_ECX_POPCNT),
481                 aes     = cpuid_has_ecxfeature(CPUID_FEAT_ECX_AES),
482                 xsave   = cpuid_has_ecxfeature(CPUID_FEAT_ECX_XSAVE),
483                 osxsave = cpuid_has_ecxfeature(CPUID_FEAT_ECX_OSXSAVE),
484                 avx     = cpuid_has_ecxfeature(CPUID_FEAT_ECX_AVX);
485
486 #define YON(v)  (v) ? "Yes" : "No"
487         if (featureset & CPUID_FEAT_ECX_ALL) {
488                 fputs("-- ECX Features --\n", file);
489                 fprintf(file, "SSE3:    %s\n"
490                               "PCMUL:   %s\n"
491                               "DTES64:  %s\n"
492                               "MONITOR: %s\n"
493                               "DS_CPL:  %s\n"
494                               "VMX:     %s\n"
495                               "SMX:     %s\n"
496                               "EST:     %s\n"
497                               "TM2:     %s\n"
498                               "SSSE3:   %s\n"
499                               "CID:     %s\n"
500                               "FMA:     %s\n"
501                               "CX16:    %s\n"
502                               "ETPRD:   %s\n"
503                               "PDCM:    %s\n"
504                               "DCA:     %s\n"
505                               "SSE4_1:  %s\n"
506                               "SSE$_2:  %s\n"
507                               "X2_APIC: %s\n"
508                               "MOVBE:   %s\n"
509                               "POPCNT:  %s\n"
510                               "AES:     %s\n"
511                               "XSAVE:   %s\n"
512                               "OSXSAVE: %s\n"
513                               "AVS:     %s\n\n",
514                         YON(sse3), YON(pclmul), YON(dtes64), YON(monitor), YON(ds_cpl),
515                         YON(vmx), YON(smx), YON(est), YON(tm2), YON(ssse3), YON(cid),
516                         YON(fma), YON(cx16), YON(etprd), YON(pdcm), YON(dca), YON(sse4_1),
517                         YON(sse4_2), YON(x2_apic), YON(movbe), YON(popcnt), YON(aes),
518                         YON(xsave), YON(osxsave), YON(avx)
519                 );
520         } else {
521                 if (featureset & CPUID_FEAT_ECX_SSE3)
522                         fprintf(file, "SSE3:    %s\n", YON(sse3));
523                 if (featureset & CPUID_FEAT_ECX_PCLMUL)
524                         fprintf(file, "PCLMUL:    %s\n", YON(pclmul));
525                 if (featureset & CPUID_FEAT_ECX_DTES64)
526                         fprintf(file, "DTES64:    %s\n", YON(dtes64));
527                 if (featureset & CPUID_FEAT_ECX_MONITOR)
528                         fprintf(file, "Monitor:    %s\n", YON(monitor));
529                 if (featureset & CPUID_FEAT_ECX_DS_CPL)
530                         fprintf(file, "DS CPL:    %s\n", YON(ds_cpl));
531                 if (featureset & CPUID_FEAT_ECX_VMX)
532                         fprintf(file, "VMX:    %s\n", YON(vmx));
533                 if (featureset & CPUID_FEAT_ECX_SMX)
534                         fprintf(file, "SMX:    %s\n", YON(smx));
535                 if (featureset & CPUID_FEAT_ECX_EST)
536                         fprintf(file, "EST:    %s\n", YON(est));
537                 if (featureset & CPUID_FEAT_ECX_TM2)
538                         fprintf(file, "TM2:    %s\n", YON(tm2));
539                 if (featureset & CPUID_FEAT_ECX_SSSE3)
540                         fprintf(file, "SSSE3:    %s\n", YON(ssse3));
541                 if (featureset & CPUID_FEAT_ECX_CID)
542                         fprintf(file, "CID:    %s\n", YON(cid));
543                 if (featureset & CPUID_FEAT_ECX_FMA)
544                         fprintf(file, "FMA:    %s\n", YON(fma));
545                 if (featureset & CPUID_FEAT_ECX_CX16)
546                         fprintf(file, "CX16:    %s\n", YON(cx16));
547                 if (featureset & CPUID_FEAT_ECX_ETPRD)
548                         fprintf(file, "ETPRD:    %s\n", YON(etprd));
549                 if (featureset & CPUID_FEAT_ECX_PDCM)
550                         fprintf(file, "PDCM:    %s\n", YON(pdcm));
551                 if (featureset & CPUID_FEAT_ECX_DCA)
552                         fprintf(file, "DCA:    %s\n", YON(dca));
553                 if (featureset & CPUID_FEAT_ECX_SSE4_1)
554                         fprintf(file, "SSE4_1:    %s\n", YON(sse4_1));
555                 if (featureset & CPUID_FEAT_ECX_SSE4_2)
556                         fprintf(file, "SSE4_2:    %s\n", YON(sse4_2));
557                 if (featureset & CPUID_FEAT_ECX_x2APIC)
558                         fprintf(file, "x2APIC:    %s\n", YON(x2_apic));
559                 if (featureset & CPUID_FEAT_ECX_MOVBE)
560                         fprintf(file, "MOVBE:    %s\n", YON(movbe));
561                 if (featureset & CPUID_FEAT_ECX_POPCNT)
562                         fprintf(file, "POPCNT:    %s\n", YON(popcnt));
563                 if (featureset & CPUID_FEAT_ECX_AES)
564                         fprintf(file, "AES:    %s\n", YON(aes));
565                 if (featureset & CPUID_FEAT_ECX_XSAVE)
566                         fprintf(file, "XSAVE:    %s\n", YON(xsave));
567                 if (featureset & CPUID_FEAT_ECX_OSXSAVE)
568                         fprintf(file, "OSXSAVE:    %s\n", YON(osxsave));
569                 if (featureset & CPUID_FEAT_ECX_AVX)
570                         fprintf(file, "AVX:    %s\n", YON(avx));
571         }
572
573         bool
574                 fpu = cpuid_has_edxfeature(CPUID_FEAT_EDX_FPU),
575                 vme   = cpuid_has_edxfeature(CPUID_FEAT_EDX_VME),
576                 de    = cpuid_has_edxfeature(CPUID_FEAT_EDX_DE),
577                 pse   = cpuid_has_edxfeature(CPUID_FEAT_EDX_PSE),
578                 tsc   = cpuid_has_edxfeature(CPUID_FEAT_EDX_TSC),
579                 msr   = cpuid_has_edxfeature(CPUID_FEAT_EDX_MSR),
580                 pae   = cpuid_has_edxfeature(CPUID_FEAT_EDX_PAE),
581                 mce   = cpuid_has_edxfeature(CPUID_FEAT_EDX_MCE),
582                 cx8   = cpuid_has_edxfeature(CPUID_FEAT_EDX_CX8),
583                 apic  = cpuid_has_edxfeature(CPUID_FEAT_EDX_APIC),
584                 sep   = cpuid_has_edxfeature(CPUID_FEAT_EDX_SEP),
585                 mtrr  = cpuid_has_edxfeature(CPUID_FEAT_EDX_MTRR),
586                 pge   = cpuid_has_edxfeature(CPUID_FEAT_EDX_PGE),
587                 mca   = cpuid_has_edxfeature(CPUID_FEAT_EDX_MCA),
588                 cmov  = cpuid_has_edxfeature(CPUID_FEAT_EDX_CMOV),
589                 pat   = cpuid_has_edxfeature(CPUID_FEAT_EDX_PAT),
590                 pse36 = cpuid_has_edxfeature(CPUID_FEAT_EDX_PSE36),
591                 psn   = cpuid_has_edxfeature(CPUID_FEAT_EDX_PSN),
592                 clf   = cpuid_has_edxfeature(CPUID_FEAT_EDX_CLF),
593                 dtes  = cpuid_has_edxfeature(CPUID_FEAT_EDX_DTES),
594                 acpi  = cpuid_has_edxfeature(CPUID_FEAT_EDX_ACPI),
595                 mmx   = cpuid_has_edxfeature(CPUID_FEAT_EDX_MMX),
596                 fxsr  = cpuid_has_edxfeature(CPUID_FEAT_EDX_FXSR),
597                 sse   = cpuid_has_edxfeature(CPUID_FEAT_EDX_SSE),
598                 sse2  = cpuid_has_edxfeature(CPUID_FEAT_EDX_SSE2),
599                 ss    = cpuid_has_edxfeature(CPUID_FEAT_EDX_SS),
600                 htt   = cpuid_has_edxfeature(CPUID_FEAT_EDX_HTT),
601                 tm1   = cpuid_has_edxfeature(CPUID_FEAT_EDX_TM1),
602                 ia64  = cpuid_has_edxfeature(CPUID_FEAT_EDX_IA64),
603                 pbe   = cpuid_has_edxfeature(CPUID_FEAT_EDX_PBE);
604
605         if (featureset & CPUID_FEAT_EDX_ALL) {
606                 fputs("-- EDX FEATURES --\n", file);
607                 fprintf(file, "FPU:   %s\n"
608                               "VME:   %s\n"
609                               "DE:    %s\n"
610                               "PSE:   %s\n"
611                               "TSC:   %s\n"
612                               "MSR:   %s\n"
613                               "PAE:   %s\n"
614                               "MCE:   %s\n"
615                               "CX8:   %s\n"
616                               "APIC:  %s\n"
617                               "SEP:   %s\n"
618                               "MTRR:  %s\n"
619                               "PGE:   %s\n"
620                               "MCA:   %s\n"
621                               "CMOV:  %s\n"
622                               "PAT:   %s\n"
623                               "PSE36: %s\n"
624                               "PSN:   %s\n"
625                               "CLF:   %s\n"
626                               "DTES:  %s\n"
627                               "ACPI:  %s\n"
628                               "MMX:   %s\n"
629                               "FXSR:  %s\n"
630                               "SSE:   %s\n"
631                               "SSE2:  %s\n"
632                               "SS:    %s\n"
633                               "HTT:   %s\n"
634                               "TM1:   %s\n"
635                               "IA64:  %s\n"
636                               "PBE:   %s\n\n",
637                         YON(fpu), YON(vme), YON(de), YON(pse), YON(tsc), YON(msr),
638                         YON(pae), YON(mce), YON(cx8), YON(apic), YON(sep), YON(mtrr),
639                         YON(pge), YON(mca), YON(cmov), YON(pat), YON(pse36), YON(psn),
640                         YON(clf), YON(dtes), YON(acpi), YON(mmx), YON(fxsr), YON(sse),
641                         YON(sse2), YON(ss), YON(htt), YON(tm1), YON(ia64), YON(pbe)
642                 );
643         } else {
644                 if (featureset & CPUID_FEAT_EDX_FPU)
645                         fprintf(file, "FPU:   %s\n", YON(fpu));
646                 if (featureset & CPUID_FEAT_EDX_VME)
647                         fprintf(file, "VME:   %s\n", YON(vme));
648                 if (featureset & CPUID_FEAT_EDX_DE)
649                         fprintf(file, "DE: %s\n", YON(de));
650                 if (featureset & CPUID_FEAT_EDX_PSE)
651                         fprintf(file, "PSE:   %s\n", YON(pse));
652                 if (featureset & CPUID_FEAT_EDX_TSC)
653                         fprintf(file, "TSC:   %s\n", YON(tsc));
654                 if (featureset & CPUID_FEAT_EDX_MSR)
655                         fprintf(file, "MSR:   %s\n", YON(msr));
656                 if (featureset & CPUID_FEAT_EDX_PAE)
657                         fprintf(file, "PAE:   %s\n", YON(pae));
658                 if (featureset & CPUID_FEAT_EDX_MCE)
659                         fprintf(file, "MCE:   %s\n", YON(mce));
660                 if (featureset & CPUID_FEAT_EDX_CX8)
661                         fprintf(file, "CX8:   %s\n", YON(cx8));
662                 if (featureset & CPUID_FEAT_EDX_APIC)
663                         fprintf(file, "APIC: %s\n", YON(apic));
664                 if (featureset & CPUID_FEAT_EDX_SEP)
665                         fprintf(file, "SEP:   %s\n", YON(sep));
666                 if (featureset & CPUID_FEAT_EDX_MTRR)
667                         fprintf(file, "MTRR: %s\n", YON(mtrr));
668                 if (featureset & CPUID_FEAT_EDX_PGE)
669                         fprintf(file, "PGE:   %s\n", YON(pge));
670                 if (featureset & CPUID_FEAT_EDX_MCA)
671                         fprintf(file, "MCA:   %s\n", YON(mca));
672                 if (featureset & CPUID_FEAT_EDX_CMOV)
673                         fprintf(file, "CMOV: %s\n", YON(cmov));
674                 if (featureset & CPUID_FEAT_EDX_PAT)
675                         fprintf(file, "PAT:   %s\n", YON(pat));
676                 if (featureset & CPUID_FEAT_EDX_PSE36)
677                         fprintf(file, "PSE36: %s\n", YON(pse36));
678                 if (featureset & CPUID_FEAT_EDX_PSN)
679                         fprintf(file, "PSN:   %s\n", YON(psn));
680                 if (featureset & CPUID_FEAT_EDX_CLF)
681                         fprintf(file, "CLF:   %s\n", YON(clf));
682                 if (featureset & CPUID_FEAT_EDX_DTES)
683                         fprintf(file, "DTES:%s\n", YON(dtes));
684                 if (featureset & CPUID_FEAT_EDX_ACPI)
685                         fprintf(file, "ACPI: %s\n", YON(acpi));
686                 if (featureset & CPUID_FEAT_EDX_MMX)
687                         fprintf(file, "MMX:   %s\n", YON(mmx));
688                 if (featureset & CPUID_FEAT_EDX_FXSR)
689                         fprintf(file, "FXSR: %s\n", YON(fxsr));
690                 if (featureset & CPUID_FEAT_EDX_SSE)
691                         fprintf(file, "SSE:   %s\n", YON(sse));
692                 if (featureset & CPUID_FEAT_EDX_SSE2)
693                         fprintf(file, "SSE2: %s\n", YON(sse2));
694                 if (featureset & CPUID_FEAT_EDX_SS)
695                         fprintf(file, "SS: %s\n", YON(ss));
696                 if (featureset & CPUID_FEAT_EDX_HTT)
697                         fprintf(file, "HTT:   %s\n", YON(htt));
698                 if (featureset & CPUID_FEAT_EDX_TM1)
699                         fprintf(file, "TM1:   %s\n", YON(tm1));
700                 if (featureset & CPUID_FEAT_EDX_IA64)
701                         fprintf(file, "IA64: %s\n", YON(ia64));
702                 if (featureset & CPUID_FEAT_EDX_PBE)
703                         fprintf(file, "PBE:   %s\n", YON(pbe));
704         }
705 #undef YON
706
707         fclose(file);
708         return true;
709 }
710
711 #endif