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