json_out: make json_out_finished finish buffer.
[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[0]); ++i) {
241                         if (strncmp(c_cpunames[i], u.buf, 12) == 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, FILE *file)
372 {
373         char brand[48];
374         cpuid(CPUID_PROC_BRAND_STRING, (uint32_t *)brand);
375
376         fprintf(file, "-- CPU Information for: %s_%s --\n\n", cpuid_get_name(), brand);
377         if (info & CPUID_HIGHEST_EXTENDED_FUNCTION_SUPPORTED)
378                 fprintf(file, "Highest extended function supported: %#010x\n\n", cpuid_highest_ext_func_supported());
379
380         if (info & CPUID_EXTENDED_L2_CACHE_FEATURES) {
381                 uint32_t l2c[3];
382                 cpuid(CPUID_EXTENDED_L2_CACHE_FEATURES, l2c);
383
384                 fprintf(file, "-- Extended L2 Cache features --\nL2 Line size: %u bytes\nAssociativity: %02xh\nCache Size: %u KB\n\n",
385                         l2c[0], l2c[1], l2c[2]);
386         }
387
388         if (info & CPUID_VIRT_PHYS_ADDR_SIZES) {
389                 uint32_t phys_virt[2];
390                 cpuid(CPUID_VIRT_PHYS_ADDR_SIZES, phys_virt);
391
392                 fprintf(file, "-- Virtual and Physical address sizes --\n"
393                                 "Physical address size: %d\nVirtual address size: %d\n\n", phys_virt[0], phys_virt[1]);
394         }
395
396         if (info & CPUID_PROCINFO_AND_FEATUREBITS) {
397                 uint32_t procinfo[9];
398                 cpuid(CPUID_PROCINFO_AND_FEATUREBITS, procinfo);
399
400                 fputs("-- Processor information and feature bits --\n", file    );
401                 fprintf(file, "Stepping: %d\nModel: 0x%X\nFamily: %d\nExtended model: %d\nExtended family: %d\n",
402                         procinfo[0], procinfo[1], procinfo[2], procinfo[3], procinfo[4]);
403                 fprintf(file, "\nBrand Index: %d\nCL Flush Line Size: %d\nLogical Processors: %d\nInitial APICID: %d\n\n",
404                         procinfo[5], procinfo[6], procinfo[7], procinfo[8]);
405         }
406
407         if (featureset != 0)
408                 fputs("-- CPU FEATURES --\n\n", file);
409
410         bool
411                 sse3    = cpuid_has_ecxfeature(CPUID_FEAT_ECX_SSE3),
412                 pclmul  = cpuid_has_ecxfeature(CPUID_FEAT_ECX_PCLMUL),
413                 dtes64  = cpuid_has_ecxfeature(CPUID_FEAT_ECX_DTES64),
414                 monitor = cpuid_has_ecxfeature(CPUID_FEAT_ECX_MONITOR),
415                 ds_cpl  = cpuid_has_ecxfeature(CPUID_FEAT_ECX_DS_CPL),
416                 vmx     = cpuid_has_ecxfeature(CPUID_FEAT_ECX_VMX),
417                 smx     = cpuid_has_ecxfeature(CPUID_FEAT_ECX_SMX),
418                 est     = cpuid_has_ecxfeature(CPUID_FEAT_ECX_EST),
419                 tm2     = cpuid_has_ecxfeature(CPUID_FEAT_ECX_TM2),
420                 ssse3   = cpuid_has_ecxfeature(CPUID_FEAT_ECX_SSSE3),
421                 cid     = cpuid_has_ecxfeature(CPUID_FEAT_ECX_CID),
422                 fma     = cpuid_has_ecxfeature(CPUID_FEAT_ECX_FMA),
423                 cx16    = cpuid_has_ecxfeature(CPUID_FEAT_ECX_CX16),
424                 etprd   = cpuid_has_ecxfeature(CPUID_FEAT_ECX_ETPRD),
425                 pdcm    = cpuid_has_ecxfeature(CPUID_FEAT_ECX_PDCM),
426                 dca     = cpuid_has_ecxfeature(CPUID_FEAT_ECX_DCA),
427                 sse4_1  = cpuid_has_ecxfeature(CPUID_FEAT_ECX_SSE4_1),
428                 sse4_2  = cpuid_has_ecxfeature(CPUID_FEAT_ECX_SSE4_2),
429                 x2_apic = cpuid_has_ecxfeature(CPUID_FEAT_ECX_x2APIC),
430                 movbe   = cpuid_has_ecxfeature(CPUID_FEAT_ECX_MOVBE),
431                 popcnt  = cpuid_has_ecxfeature(CPUID_FEAT_ECX_POPCNT),
432                 aes     = cpuid_has_ecxfeature(CPUID_FEAT_ECX_AES),
433                 xsave   = cpuid_has_ecxfeature(CPUID_FEAT_ECX_XSAVE),
434                 osxsave = cpuid_has_ecxfeature(CPUID_FEAT_ECX_OSXSAVE),
435                 avx     = cpuid_has_ecxfeature(CPUID_FEAT_ECX_AVX);
436
437 #define YON(v)  (v) ? "Yes" : "No"
438         if (featureset & CPUID_FEAT_ECX_ALL) {
439                 fputs("-- ECX Features --\n", file);
440                 fprintf(file, "SSE3:    %s\n"
441                               "PCMUL:   %s\n"
442                               "DTES64:  %s\n"
443                               "MONITOR: %s\n"
444                               "DS_CPL:  %s\n"
445                               "VMX:     %s\n"
446                               "SMX:     %s\n"
447                               "EST:     %s\n"
448                               "TM2:     %s\n"
449                               "SSSE3:   %s\n"
450                               "CID:     %s\n"
451                               "FMA:     %s\n"
452                               "CX16:    %s\n"
453                               "ETPRD:   %s\n"
454                               "PDCM:    %s\n"
455                               "DCA:     %s\n"
456                               "SSE4_1:  %s\n"
457                               "SSE$_2:  %s\n"
458                               "X2_APIC: %s\n"
459                               "MOVBE:   %s\n"
460                               "POPCNT:  %s\n"
461                               "AES:     %s\n"
462                               "XSAVE:   %s\n"
463                               "OSXSAVE: %s\n"
464                               "AVS:     %s\n\n",
465                         YON(sse3), YON(pclmul), YON(dtes64), YON(monitor), YON(ds_cpl),
466                         YON(vmx), YON(smx), YON(est), YON(tm2), YON(ssse3), YON(cid),
467                         YON(fma), YON(cx16), YON(etprd), YON(pdcm), YON(dca), YON(sse4_1),
468                         YON(sse4_2), YON(x2_apic), YON(movbe), YON(popcnt), YON(aes),
469                         YON(xsave), YON(osxsave), YON(avx)
470                 );
471         } else {
472                 if (featureset & CPUID_FEAT_ECX_SSE3)
473                         fprintf(file, "SSE3:    %s\n", YON(sse3));
474                 if (featureset & CPUID_FEAT_ECX_PCLMUL)
475                         fprintf(file, "PCLMUL:    %s\n", YON(pclmul));
476                 if (featureset & CPUID_FEAT_ECX_DTES64)
477                         fprintf(file, "DTES64:    %s\n", YON(dtes64));
478                 if (featureset & CPUID_FEAT_ECX_MONITOR)
479                         fprintf(file, "Monitor:    %s\n", YON(monitor));
480                 if (featureset & CPUID_FEAT_ECX_DS_CPL)
481                         fprintf(file, "DS CPL:    %s\n", YON(ds_cpl));
482                 if (featureset & CPUID_FEAT_ECX_VMX)
483                         fprintf(file, "VMX:    %s\n", YON(vmx));
484                 if (featureset & CPUID_FEAT_ECX_SMX)
485                         fprintf(file, "SMX:    %s\n", YON(smx));
486                 if (featureset & CPUID_FEAT_ECX_EST)
487                         fprintf(file, "EST:    %s\n", YON(est));
488                 if (featureset & CPUID_FEAT_ECX_TM2)
489                         fprintf(file, "TM2:    %s\n", YON(tm2));
490                 if (featureset & CPUID_FEAT_ECX_SSSE3)
491                         fprintf(file, "SSSE3:    %s\n", YON(ssse3));
492                 if (featureset & CPUID_FEAT_ECX_CID)
493                         fprintf(file, "CID:    %s\n", YON(cid));
494                 if (featureset & CPUID_FEAT_ECX_FMA)
495                         fprintf(file, "FMA:    %s\n", YON(fma));
496                 if (featureset & CPUID_FEAT_ECX_CX16)
497                         fprintf(file, "CX16:    %s\n", YON(cx16));
498                 if (featureset & CPUID_FEAT_ECX_ETPRD)
499                         fprintf(file, "ETPRD:    %s\n", YON(etprd));
500                 if (featureset & CPUID_FEAT_ECX_PDCM)
501                         fprintf(file, "PDCM:    %s\n", YON(pdcm));
502                 if (featureset & CPUID_FEAT_ECX_DCA)
503                         fprintf(file, "DCA:    %s\n", YON(dca));
504                 if (featureset & CPUID_FEAT_ECX_SSE4_1)
505                         fprintf(file, "SSE4_1:    %s\n", YON(sse4_1));
506                 if (featureset & CPUID_FEAT_ECX_SSE4_2)
507                         fprintf(file, "SSE4_2:    %s\n", YON(sse4_2));
508                 if (featureset & CPUID_FEAT_ECX_x2APIC)
509                         fprintf(file, "x2APIC:    %s\n", YON(x2_apic));
510                 if (featureset & CPUID_FEAT_ECX_MOVBE)
511                         fprintf(file, "MOVBE:    %s\n", YON(movbe));
512                 if (featureset & CPUID_FEAT_ECX_POPCNT)
513                         fprintf(file, "POPCNT:    %s\n", YON(popcnt));
514                 if (featureset & CPUID_FEAT_ECX_AES)
515                         fprintf(file, "AES:    %s\n", YON(aes));
516                 if (featureset & CPUID_FEAT_ECX_XSAVE)
517                         fprintf(file, "XSAVE:    %s\n", YON(xsave));
518                 if (featureset & CPUID_FEAT_ECX_OSXSAVE)
519                         fprintf(file, "OSXSAVE:    %s\n", YON(osxsave));
520                 if (featureset & CPUID_FEAT_ECX_AVX)
521                         fprintf(file, "AVX:    %s\n", YON(avx));
522         }
523
524         bool
525                 fpu = cpuid_has_edxfeature(CPUID_FEAT_EDX_FPU),
526                 vme   = cpuid_has_edxfeature(CPUID_FEAT_EDX_VME),
527                 de    = cpuid_has_edxfeature(CPUID_FEAT_EDX_DE),
528                 pse   = cpuid_has_edxfeature(CPUID_FEAT_EDX_PSE),
529                 tsc   = cpuid_has_edxfeature(CPUID_FEAT_EDX_TSC),
530                 msr   = cpuid_has_edxfeature(CPUID_FEAT_EDX_MSR),
531                 pae   = cpuid_has_edxfeature(CPUID_FEAT_EDX_PAE),
532                 mce   = cpuid_has_edxfeature(CPUID_FEAT_EDX_MCE),
533                 cx8   = cpuid_has_edxfeature(CPUID_FEAT_EDX_CX8),
534                 apic  = cpuid_has_edxfeature(CPUID_FEAT_EDX_APIC),
535                 sep   = cpuid_has_edxfeature(CPUID_FEAT_EDX_SEP),
536                 mtrr  = cpuid_has_edxfeature(CPUID_FEAT_EDX_MTRR),
537                 pge   = cpuid_has_edxfeature(CPUID_FEAT_EDX_PGE),
538                 mca   = cpuid_has_edxfeature(CPUID_FEAT_EDX_MCA),
539                 cmov  = cpuid_has_edxfeature(CPUID_FEAT_EDX_CMOV),
540                 pat   = cpuid_has_edxfeature(CPUID_FEAT_EDX_PAT),
541                 pse36 = cpuid_has_edxfeature(CPUID_FEAT_EDX_PSE36),
542                 psn   = cpuid_has_edxfeature(CPUID_FEAT_EDX_PSN),
543                 clf   = cpuid_has_edxfeature(CPUID_FEAT_EDX_CLF),
544                 dtes  = cpuid_has_edxfeature(CPUID_FEAT_EDX_DTES),
545                 acpi  = cpuid_has_edxfeature(CPUID_FEAT_EDX_ACPI),
546                 mmx   = cpuid_has_edxfeature(CPUID_FEAT_EDX_MMX),
547                 fxsr  = cpuid_has_edxfeature(CPUID_FEAT_EDX_FXSR),
548                 sse   = cpuid_has_edxfeature(CPUID_FEAT_EDX_SSE),
549                 sse2  = cpuid_has_edxfeature(CPUID_FEAT_EDX_SSE2),
550                 ss    = cpuid_has_edxfeature(CPUID_FEAT_EDX_SS),
551                 htt   = cpuid_has_edxfeature(CPUID_FEAT_EDX_HTT),
552                 tm1   = cpuid_has_edxfeature(CPUID_FEAT_EDX_TM1),
553                 ia64  = cpuid_has_edxfeature(CPUID_FEAT_EDX_IA64),
554                 pbe   = cpuid_has_edxfeature(CPUID_FEAT_EDX_PBE);
555
556         if (featureset & CPUID_FEAT_EDX_ALL) {
557                 fputs("-- EDX FEATURES --\n", file);
558                 fprintf(file, "FPU:   %s\n"
559                               "VME:   %s\n"
560                               "DE:    %s\n"
561                               "PSE:   %s\n"
562                               "TSC:   %s\n"
563                               "MSR:   %s\n"
564                               "PAE:   %s\n"
565                               "MCE:   %s\n"
566                               "CX8:   %s\n"
567                               "APIC:  %s\n"
568                               "SEP:   %s\n"
569                               "MTRR:  %s\n"
570                               "PGE:   %s\n"
571                               "MCA:   %s\n"
572                               "CMOV:  %s\n"
573                               "PAT:   %s\n"
574                               "PSE36: %s\n"
575                               "PSN:   %s\n"
576                               "CLF:   %s\n"
577                               "DTES:  %s\n"
578                               "ACPI:  %s\n"
579                               "MMX:   %s\n"
580                               "FXSR:  %s\n"
581                               "SSE:   %s\n"
582                               "SSE2:  %s\n"
583                               "SS:    %s\n"
584                               "HTT:   %s\n"
585                               "TM1:   %s\n"
586                               "IA64:  %s\n"
587                               "PBE:   %s\n\n",
588                         YON(fpu), YON(vme), YON(de), YON(pse), YON(tsc), YON(msr),
589                         YON(pae), YON(mce), YON(cx8), YON(apic), YON(sep), YON(mtrr),
590                         YON(pge), YON(mca), YON(cmov), YON(pat), YON(pse36), YON(psn),
591                         YON(clf), YON(dtes), YON(acpi), YON(mmx), YON(fxsr), YON(sse),
592                         YON(sse2), YON(ss), YON(htt), YON(tm1), YON(ia64), YON(pbe)
593                 );
594         } else {
595                 if (featureset & CPUID_FEAT_EDX_FPU)
596                         fprintf(file, "FPU:   %s\n", YON(fpu));
597                 if (featureset & CPUID_FEAT_EDX_VME)
598                         fprintf(file, "VME:   %s\n", YON(vme));
599                 if (featureset & CPUID_FEAT_EDX_DE)
600                         fprintf(file, "DE: %s\n", YON(de));
601                 if (featureset & CPUID_FEAT_EDX_PSE)
602                         fprintf(file, "PSE:   %s\n", YON(pse));
603                 if (featureset & CPUID_FEAT_EDX_TSC)
604                         fprintf(file, "TSC:   %s\n", YON(tsc));
605                 if (featureset & CPUID_FEAT_EDX_MSR)
606                         fprintf(file, "MSR:   %s\n", YON(msr));
607                 if (featureset & CPUID_FEAT_EDX_PAE)
608                         fprintf(file, "PAE:   %s\n", YON(pae));
609                 if (featureset & CPUID_FEAT_EDX_MCE)
610                         fprintf(file, "MCE:   %s\n", YON(mce));
611                 if (featureset & CPUID_FEAT_EDX_CX8)
612                         fprintf(file, "CX8:   %s\n", YON(cx8));
613                 if (featureset & CPUID_FEAT_EDX_APIC)
614                         fprintf(file, "APIC: %s\n", YON(apic));
615                 if (featureset & CPUID_FEAT_EDX_SEP)
616                         fprintf(file, "SEP:   %s\n", YON(sep));
617                 if (featureset & CPUID_FEAT_EDX_MTRR)
618                         fprintf(file, "MTRR: %s\n", YON(mtrr));
619                 if (featureset & CPUID_FEAT_EDX_PGE)
620                         fprintf(file, "PGE:   %s\n", YON(pge));
621                 if (featureset & CPUID_FEAT_EDX_MCA)
622                         fprintf(file, "MCA:   %s\n", YON(mca));
623                 if (featureset & CPUID_FEAT_EDX_CMOV)
624                         fprintf(file, "CMOV: %s\n", YON(cmov));
625                 if (featureset & CPUID_FEAT_EDX_PAT)
626                         fprintf(file, "PAT:   %s\n", YON(pat));
627                 if (featureset & CPUID_FEAT_EDX_PSE36)
628                         fprintf(file, "PSE36: %s\n", YON(pse36));
629                 if (featureset & CPUID_FEAT_EDX_PSN)
630                         fprintf(file, "PSN:   %s\n", YON(psn));
631                 if (featureset & CPUID_FEAT_EDX_CLF)
632                         fprintf(file, "CLF:   %s\n", YON(clf));
633                 if (featureset & CPUID_FEAT_EDX_DTES)
634                         fprintf(file, "DTES:%s\n", YON(dtes));
635                 if (featureset & CPUID_FEAT_EDX_ACPI)
636                         fprintf(file, "ACPI: %s\n", YON(acpi));
637                 if (featureset & CPUID_FEAT_EDX_MMX)
638                         fprintf(file, "MMX:   %s\n", YON(mmx));
639                 if (featureset & CPUID_FEAT_EDX_FXSR)
640                         fprintf(file, "FXSR: %s\n", YON(fxsr));
641                 if (featureset & CPUID_FEAT_EDX_SSE)
642                         fprintf(file, "SSE:   %s\n", YON(sse));
643                 if (featureset & CPUID_FEAT_EDX_SSE2)
644                         fprintf(file, "SSE2: %s\n", YON(sse2));
645                 if (featureset & CPUID_FEAT_EDX_SS)
646                         fprintf(file, "SS: %s\n", YON(ss));
647                 if (featureset & CPUID_FEAT_EDX_HTT)
648                         fprintf(file, "HTT:   %s\n", YON(htt));
649                 if (featureset & CPUID_FEAT_EDX_TM1)
650                         fprintf(file, "TM1:   %s\n", YON(tm1));
651                 if (featureset & CPUID_FEAT_EDX_IA64)
652                         fprintf(file, "IA64: %s\n", YON(ia64));
653                 if (featureset & CPUID_FEAT_EDX_PBE)
654                         fprintf(file, "PBE:   %s\n", YON(pbe));
655         }
656 #undef YON
657
658         return true;
659 }
660
661 #endif