X-Git-Url: http://git.ozlabs.org/?p=ccan;a=blobdiff_plain;f=ccan%2Fcpuid%2Fcpuid.c;h=d27441022d2bad386d4361a2ee5fbdff7113a402;hp=5c3aa34815b21a7c8140a52820d529f6bc99a5c6;hb=dbbefec6973725d9a16c82747e0c7ce8e5e6c4f2;hpb=d03f0db15bde9934e801ce9e935b2cfe82301ab3 diff --git a/ccan/cpuid/cpuid.c b/ccan/cpuid/cpuid.c index 5c3aa348..d2744102 100644 --- a/ccan/cpuid/cpuid.c +++ b/ccan/cpuid/cpuid.c @@ -29,10 +29,11 @@ #include "cpuid.h" #include +#include enum { - CPU_PROC_BRAND_STRING_INTERNAL0 = 0x80000003, - CPU_PROC_BRAND_STRING_INTERNAL1 = 0x80000004 + CPUID_PROC_BRAND_STRING_INTERNAL0 = 0x80000003, + CPUID_PROC_BRAND_STRING_INTERNAL1 = 0x80000004 }; #ifndef _MSC_VER @@ -61,37 +62,10 @@ static void ___cpuid(cpuid_t info, uint32_t *eax, uint32_t *ebx, uint32_t *ecx, } #endif -static struct { - uint32_t feature; - uint32_t mask; - bool use_edx; /* ecx will be used if false. */ -} features[] = { - { CF_MMX, 1 << 23, true }, - { CF_SSE, 1 << 25, true }, - { CF_SSE2, 1 << 26, true }, - { CF_SSE3, 1 << 9, false }, - { CF_FPU, 1 << 0, true }, - - { CF_TSC, 1 << 4, true }, - { CF_MSR, 1 << 5, true }, - - { CF_SSSE3, 1 << 9, false }, - { CF_AVX, 1 << 28, false }, - - /* Extended ones. */ - { CEF_x64, 1 << 30, true }, - { CEF_FPU, 1 << 0, true }, - { CEF_DE, 1 << 2, true }, - { CEF_SYSCALLRET, 1 << 11, true }, - { CEF_CMOV, 1 << 15, true }, - - { CEF_SSE4a, 1 << 6, false }, - { CEF_FMA4, 1 << 16, false }, - { CEF_XOP, 1 << 11, false } -}; - bool cpuid_is_supported(void) { + int ret = 0; +#if defined(__GNUC__) || defined(__clang__) /* The following assembly code uses EAX as the return value, * but we store the value of EAX into ret since GCC uses EAX * as the return register for every C function. That's a double @@ -124,7 +98,6 @@ bool cpuid_is_supported(void) #define ASM_PUSHECX "pushl %%ecx\n\t" #endif - int ret = 0; asm volatile( ASM_PUSHF ASM_POPEAX @@ -147,36 +120,79 @@ bool cpuid_is_supported(void) #undef ASM_PUSHEAX #undef ASM_POPEAX #undef ASM_PUSHECX - +#elif defined _MSC_VER + __asm { + pushfd + pop eax + mov ecx, eax + xor eax, 0x200000 + push eax + popfd + + pushfd + pop eax + xor eax, ecx + shr eax, 21 + and eax, 1 + push ecx + popfd + + mov eax, ret + }; +#endif return !!ret; } bool cpuid_test_feature(cpuid_t feature) { - if (feature > CPU_VIRT_PHYS_ADDR_SIZES || feature < CPU_EXTENDED_PROC_INFO_FEATURE_BITS) + if (feature > CPUID_VIRT_PHYS_ADDR_SIZES || feature < CPUID_EXTENDED_PROC_INFO_FEATURE_BITS) return false; return (feature <= cpuid_highest_ext_func_supported()); } -bool cpuid_has_feature(int feature, bool extended) +bool cpuid_has_ecxfeature(int feature) { - uint32_t eax, ebx, ecx, edx, i; + static uint32_t _ecx; + if (_ecx == 0) { +#if defined(__GNUC__) || defined(__clang__) + asm volatile( + "cpuid\n\t" + : "=c" (_ecx) + : "a" (CPUID_PROCINFO_AND_FEATUREBITS) + ); +#elif defined _MSC_VER + __asm { + mov eax, CPUID_PROCINFO_AND_FEATUREBITS + cpuid + mov _ecx, ecx + }; +#endif + } - if (!extended) - ___cpuid(CPU_PROCINFO_AND_FEATUREBITS, &eax, &ebx, &ecx, &edx); - else - ___cpuid(CPU_EXTENDED_PROC_INFO_FEATURE_BITS, &eax, &ebx, &ecx, &edx); - - for (i = 0; i < sizeof(features) / sizeof(features[0]); ++i) { - if (features[i].feature == feature) { - if (features[i].use_edx) - return (edx & features[i].mask); - else - return (ecx & features[i].mask); - } + return (_ecx & feature) == feature; +} + +bool cpuid_has_edxfeature(int feature) +{ + static uint32_t _edx; + if (_edx == 0) { +#if defined(__GNUC__) || defined(__clang__) + asm volatile( + "cpuid\n\t" + : "=d" (_edx) + : "a" (CPUID_PROCINFO_AND_FEATUREBITS) + ); +#elif defined _MSC_VER + __asm { + mov eax, CPUID_PROCINFO_AND_FEATUREBITS + cpuid + mov _edx, edx + }; +#endif } - return false; + + return (_edx & feature) == feature; } static const char *const cpuids[] = { @@ -208,7 +224,7 @@ cputype_t cpuid_get_cpu_type(void) } u; uint32_t i; - ___cpuid(CPU_VENDORID, &i, &u.bufu32[0], &u.bufu32[2], &u.bufu32[1]); + ___cpuid(CPUID_VENDORID, &i, &u.bufu32[0], &u.bufu32[2], &u.bufu32[1]); for (i = 0; i < sizeof(cpuids) / sizeof(cpuids[0]); ++i) { if (strncmp(cpuids[i], u.buf, 12) == 0) { cputype = (cputype_t)i; @@ -220,9 +236,14 @@ cputype_t cpuid_get_cpu_type(void) return cputype; } -const char *cpuid_get_cpu_type_string(const cputype_t cputype) +bool cpuid_sprintf_cputype(const cputype_t cputype, char *buf) { - return cpuids[(int)cputype]; + if (cputype == CT_NONE) + return false; + + memcpy(buf, cpuids[(int)cputype], 12); + buf[12] = '\0'; + return true; } uint32_t cpuid_highest_ext_func_supported(void) @@ -230,11 +251,19 @@ uint32_t cpuid_highest_ext_func_supported(void) static uint32_t highest; if (!highest) { +#if defined(__GNUC__) || defined(__clang__) asm volatile( "cpuid\n\t" : "=a" (highest) - : "a" (CPU_HIGHEST_EXTENDED_FUNCTION_SUPPORTED) + : "a" (CPUID_HIGHEST_EXTENDED_FUNCTION_SUPPORTED) ); +#elif defined _MSC_VER + __asm { + mov eax, CPUID_HIGHEST_EXTENDED_FUNCTION_SUPPORTED + cpuid + mov highest, eax + }; +#endif } return highest; @@ -245,23 +274,23 @@ void cpuid(cpuid_t info, uint32_t *buf) /* Sanity checks, make sure we're not trying to do something * invalid or we are trying to get information that isn't supported * by the CPU. */ - if (info > CPU_VIRT_PHYS_ADDR_SIZES || (info > CPU_HIGHEST_EXTENDED_FUNCTION_SUPPORTED + if (info > CPUID_VIRT_PHYS_ADDR_SIZES || (info > CPUID_HIGHEST_EXTENDED_FUNCTION_SUPPORTED && !cpuid_test_feature(info))) return; - if (info == CPU_PROC_BRAND_STRING) { + if (info == CPUID_PROC_BRAND_STRING) { static char cached[48] = { 0 }; if (cached[0] == '\0') { - ___cpuid(CPU_PROC_BRAND_STRING, &buf[0], &buf[1], &buf[2], &buf[3]); - ___cpuid(CPU_PROC_BRAND_STRING_INTERNAL0, &buf[4], &buf[5], &buf[6], &buf[7]); - ___cpuid(CPU_PROC_BRAND_STRING_INTERNAL1, &buf[8], &buf[9], &buf[10], &buf[11]); + ___cpuid(CPUID_PROC_BRAND_STRING, &buf[0], &buf[1], &buf[2], &buf[3] ); + ___cpuid(CPUID_PROC_BRAND_STRING_INTERNAL0, &buf[4], &buf[5], &buf[6], &buf[7] ); + ___cpuid(CPUID_PROC_BRAND_STRING_INTERNAL1, &buf[8], &buf[9], &buf[10], &buf[11]); memcpy(cached, buf, sizeof cached); } else buf = (uint32_t *)cached; return; - } else if (info == CPU_HIGHEST_EXTENDED_FUNCTION_SUPPORTED) { + } else if (info == CPUID_HIGHEST_EXTENDED_FUNCTION_SUPPORTED) { *buf = cpuid_highest_ext_func_supported(); return; } @@ -270,42 +299,64 @@ void cpuid(cpuid_t info, uint32_t *buf) ___cpuid(info, &eax, &ebx, &ecx, &edx); switch (info) { - case CPU_VENDORID: + case CPUID_VENDORID: buf[0] = ebx; buf[1] = edx; buf[2] = ecx; break; - case CPU_PROCINFO_AND_FEATUREBITS: - buf[0] = eax; /* The so called "signature" of the CPU. */ - buf[1] = edx; /* Feature flags #1. */ - buf[2] = ecx; /* Feature flags #2. */ - buf[3] = ebx; /* Additional feature information. */ + case CPUID_PROCINFO_AND_FEATUREBITS: + buf[0] = (eax & 0x0F); /* Stepping */ + buf[1] = (eax >> 4) & 0x0F; /* Model */ + buf[2] = (eax >> 8) & 0x0F; /* Family */ + buf[3] = (eax >> 16) & 0x0F; /* Extended Model. */ + buf[4] = (eax >> 24) & 0x0F; /* Extended Family. */ + + /* Additional Feature information. */ + buf[5] = ebx & 0xFF; + buf[6] = (ebx >> 8) & 0xFF; + buf[7] = (ebx >> 16) & 0xFF; + buf[8] = ebx >> 24; break; - case CPU_CACHE_AND_TLBD_INFO: + case CPUID_CACHE_AND_TLBD_INFO: buf[0] = eax; buf[1] = ebx; buf[2] = ecx; buf[3] = edx; break; - case CPU_EXTENDED_PROC_INFO_FEATURE_BITS: + case CPUID_EXTENDED_PROC_INFO_FEATURE_BITS: buf[0] = edx; buf[1] = ecx; break; - case CPU_L1_CACHE_AND_TLB_IDS: - buf[0] = eax; - buf[1] = ebx; - buf[2] = ecx; - buf[3] = edx; + case CPUID_L1_CACHE_AND_TLB_IDS: + buf[0] = eax & 0xFF; + buf[1] = (eax >> 8) & 0xFF; + buf[2] = (eax >> 16) & 0xFF; + buf[3] = eax >> 24; + + buf[4] = ebx & 0xFF; + buf[5] = (ebx >> 8) & 0xFF; + buf[6] = (ebx >> 16) & 0xFF; + buf[7] = ebx >> 24; + + buf[8] = ecx & 0xFF; + buf[9] = (ecx >> 8) & 0xFF; + buf[10] = (ecx >> 16) & 0xFF; + buf[11] = ecx >> 24; + + buf[12] = edx & 0xFF; + buf[13] = (edx >> 8) & 0xFF; + buf[14] = (edx >> 16) & 0xFF; + buf[15] = edx >> 24; break; - case CPU_EXTENDED_L2_CACHE_FEATURES: + case CPUID_EXTENDED_L2_CACHE_FEATURES: buf[0] = ecx & 0xFF; /* Line size. */ buf[1] = (ecx >> 12) & 0xFF; /* Associativity. */ buf[2] = ecx >> 16; /* Cache size. */ break; - case CPU_ADV_POWER_MGT_INFO: + case CPUID_ADV_POWER_MGT_INFO: *buf = edx; break; - case CPU_VIRT_PHYS_ADDR_SIZES: + case CPUID_VIRT_PHYS_ADDR_SIZES: buf[0] = eax & 0xFF; /* physical. */ buf[1] = (eax >> 8) & 0xFF; /* virtual. */ break; @@ -315,4 +366,315 @@ void cpuid(cpuid_t info, uint32_t *buf) } } +bool cpuid_write_info(uint32_t info, uint32_t featureset, const char *outfile) +{ + FILE *file; + char filename[256]; + char cpu_information[64]; + + if (!cpuid_sprintf_cputype(cpuid_get_cpu_type(), cpu_information)) + return false; + + char brand[48]; + cpuid(CPUID_PROC_BRAND_STRING, (uint32_t *)brand); + + cpu_information[12] = '_'; + memcpy(&cpu_information[13], brand, sizeof brand); + + if (!outfile) + strncpy(filename, cpu_information, sizeof cpu_information); + else + strncpy(filename, outfile, sizeof filename); + + file = fopen(filename, "w"); + if (!file) + return false; + + fprintf(file, "-- CPU Information for CPU: %s --\n\n", cpu_information); + + if (info & CPUID_HIGHEST_EXTENDED_FUNCTION_SUPPORTED) + fprintf(file, "Highest extended function supported: %#010x\n\n", cpuid_highest_ext_func_supported()); + + if (info & CPUID_EXTENDED_L2_CACHE_FEATURES) { + uint32_t l2c[3]; + cpuid(CPUID_EXTENDED_L2_CACHE_FEATURES, l2c); + + fprintf(file, "-- Extended L2 Cache features --\nL2 Line size: %u bytes\nAssociativity: %02xh\nCache Size: %u KB\n\n", + l2c[0], l2c[1], l2c[2]); + } + + if (info & CPUID_VIRT_PHYS_ADDR_SIZES) { + uint32_t phys_virt[2]; + cpuid(CPUID_VIRT_PHYS_ADDR_SIZES, phys_virt); + + fprintf(file, "-- Virtual and Physical address sizes --\n" + "Physical address size: %d\nVirtual address size: %d\n\n", phys_virt[0], phys_virt[1]); + } + + if (info & CPUID_PROCINFO_AND_FEATUREBITS) { + uint32_t procinfo[9]; + cpuid(CPUID_PROCINFO_AND_FEATUREBITS, procinfo); + + fputs("-- Processor information and feature bits --\n", file ); + fprintf(file, "Stepping: %d\nModel: 0x%X\nFamily: %d\nExtended model: %d\nExtended family: %d\n", + procinfo[0], procinfo[1], procinfo[2], procinfo[3], procinfo[4]); + fprintf(file, "\nBrand Index: %d\nCL Flush Line Size: %d\nLogical Processors: %d\nInitial APICID: %d\n\n", + procinfo[5], procinfo[6], procinfo[7], procinfo[8]); + } + + if (featureset != 0) + fputs("-- CPU FEATURES --\n\n", file); + + bool + sse3 = cpuid_has_ecxfeature(CPUID_FEAT_ECX_SSE3), + pclmul = cpuid_has_ecxfeature(CPUID_FEAT_ECX_PCLMUL), + dtes64 = cpuid_has_ecxfeature(CPUID_FEAT_ECX_DTES64), + monitor = cpuid_has_ecxfeature(CPUID_FEAT_ECX_MONITOR), + ds_cpl = cpuid_has_ecxfeature(CPUID_FEAT_ECX_DS_CPL), + vmx = cpuid_has_ecxfeature(CPUID_FEAT_ECX_VMX), + smx = cpuid_has_ecxfeature(CPUID_FEAT_ECX_SMX), + est = cpuid_has_ecxfeature(CPUID_FEAT_ECX_EST), + tm2 = cpuid_has_ecxfeature(CPUID_FEAT_ECX_TM2), + ssse3 = cpuid_has_ecxfeature(CPUID_FEAT_ECX_SSSE3), + cid = cpuid_has_ecxfeature(CPUID_FEAT_ECX_CID), + fma = cpuid_has_ecxfeature(CPUID_FEAT_ECX_FMA), + cx16 = cpuid_has_ecxfeature(CPUID_FEAT_ECX_CX16), + etprd = cpuid_has_ecxfeature(CPUID_FEAT_ECX_ETPRD), + pdcm = cpuid_has_ecxfeature(CPUID_FEAT_ECX_PDCM), + dca = cpuid_has_ecxfeature(CPUID_FEAT_ECX_DCA), + sse4_1 = cpuid_has_ecxfeature(CPUID_FEAT_ECX_SSE4_1), + sse4_2 = cpuid_has_ecxfeature(CPUID_FEAT_ECX_SSE4_2), + x2_apic = cpuid_has_ecxfeature(CPUID_FEAT_ECX_x2APIC), + movbe = cpuid_has_ecxfeature(CPUID_FEAT_ECX_MOVBE), + popcnt = cpuid_has_ecxfeature(CPUID_FEAT_ECX_POPCNT), + aes = cpuid_has_ecxfeature(CPUID_FEAT_ECX_AES), + xsave = cpuid_has_ecxfeature(CPUID_FEAT_ECX_XSAVE), + osxsave = cpuid_has_ecxfeature(CPUID_FEAT_ECX_OSXSAVE), + avx = cpuid_has_ecxfeature(CPUID_FEAT_ECX_AVX); + +#define YON(v) (v) ? "Yes" : "No" + if (featureset & CPUID_FEAT_ECX_ALL) { + fputs("-- ECX Features --\n", file); + fprintf(file, "SSE3: %s\n" + "PCMUL: %s\n" + "DTES64: %s\n" + "MONITOR: %s\n" + "DS_CPL: %s\n" + "VMX: %s\n" + "SMX: %s\n" + "EST: %s\n" + "TM2: %s\n" + "SSSE3: %s\n" + "CID: %s\n" + "FMA: %s\n" + "CX16: %s\n" + "ETPRD: %s\n" + "PDCM: %s\n" + "DCA: %s\n" + "SSE4_1: %s\n" + "SSE$_2: %s\n" + "X2_APIC: %s\n" + "MOVBE: %s\n" + "POPCNT: %s\n" + "AES: %s\n" + "XSAVE: %s\n" + "OSXSAVE: %s\n" + "AVS: %s\n\n", + YON(sse3), YON(pclmul), YON(dtes64), YON(monitor), YON(ds_cpl), + YON(vmx), YON(smx), YON(est), YON(tm2), YON(ssse3), YON(cid), + YON(fma), YON(cx16), YON(etprd), YON(pdcm), YON(dca), YON(sse4_1), + YON(sse4_2), YON(x2_apic), YON(movbe), YON(popcnt), YON(aes), + YON(xsave), YON(osxsave), YON(avx) + ); + } else { + if (featureset & CPUID_FEAT_ECX_SSE3) + fprintf(file, "SSE3: %s\n", YON(sse3)); + if (featureset & CPUID_FEAT_ECX_PCLMUL) + fprintf(file, "PCLMUL: %s\n", YON(pclmul)); + if (featureset & CPUID_FEAT_ECX_DTES64) + fprintf(file, "DTES64: %s\n", YON(dtes64)); + if (featureset & CPUID_FEAT_ECX_MONITOR) + fprintf(file, "Monitor: %s\n", YON(monitor)); + if (featureset & CPUID_FEAT_ECX_DS_CPL) + fprintf(file, "DS CPL: %s\n", YON(ds_cpl)); + if (featureset & CPUID_FEAT_ECX_VMX) + fprintf(file, "VMX: %s\n", YON(vmx)); + if (featureset & CPUID_FEAT_ECX_SMX) + fprintf(file, "SMX: %s\n", YON(smx)); + if (featureset & CPUID_FEAT_ECX_EST) + fprintf(file, "EST: %s\n", YON(est)); + if (featureset & CPUID_FEAT_ECX_TM2) + fprintf(file, "TM2: %s\n", YON(tm2)); + if (featureset & CPUID_FEAT_ECX_SSSE3) + fprintf(file, "SSSE3: %s\n", YON(ssse3)); + if (featureset & CPUID_FEAT_ECX_CID) + fprintf(file, "CID: %s\n", YON(cid)); + if (featureset & CPUID_FEAT_ECX_FMA) + fprintf(file, "FMA: %s\n", YON(fma)); + if (featureset & CPUID_FEAT_ECX_CX16) + fprintf(file, "CX16: %s\n", YON(cx16)); + if (featureset & CPUID_FEAT_ECX_ETPRD) + fprintf(file, "ETPRD: %s\n", YON(etprd)); + if (featureset & CPUID_FEAT_ECX_PDCM) + fprintf(file, "PDCM: %s\n", YON(pdcm)); + if (featureset & CPUID_FEAT_ECX_DCA) + fprintf(file, "DCA: %s\n", YON(dca)); + if (featureset & CPUID_FEAT_ECX_SSE4_1) + fprintf(file, "SSE4_1: %s\n", YON(sse4_1)); + if (featureset & CPUID_FEAT_ECX_SSE4_2) + fprintf(file, "SSE4_2: %s\n", YON(sse4_2)); + if (featureset & CPUID_FEAT_ECX_x2APIC) + fprintf(file, "x2APIC: %s\n", YON(x2_apic)); + if (featureset & CPUID_FEAT_ECX_MOVBE) + fprintf(file, "MOVBE: %s\n", YON(movbe)); + if (featureset & CPUID_FEAT_ECX_POPCNT) + fprintf(file, "POPCNT: %s\n", YON(popcnt)); + if (featureset & CPUID_FEAT_ECX_AES) + fprintf(file, "AES: %s\n", YON(aes)); + if (featureset & CPUID_FEAT_ECX_XSAVE) + fprintf(file, "XSAVE: %s\n", YON(xsave)); + if (featureset & CPUID_FEAT_ECX_OSXSAVE) + fprintf(file, "OSXSAVE: %s\n", YON(osxsave)); + if (featureset & CPUID_FEAT_ECX_AVX) + fprintf(file, "AVX: %s\n", YON(avx)); + } + + bool + fpu = cpuid_has_edxfeature(CPUID_FEAT_EDX_FPU), + vme = cpuid_has_edxfeature(CPUID_FEAT_EDX_VME), + de = cpuid_has_edxfeature(CPUID_FEAT_EDX_DE), + pse = cpuid_has_edxfeature(CPUID_FEAT_EDX_PSE), + tsc = cpuid_has_edxfeature(CPUID_FEAT_EDX_TSC), + msr = cpuid_has_edxfeature(CPUID_FEAT_EDX_MSR), + pae = cpuid_has_edxfeature(CPUID_FEAT_EDX_PAE), + mce = cpuid_has_edxfeature(CPUID_FEAT_EDX_MCE), + cx8 = cpuid_has_edxfeature(CPUID_FEAT_EDX_CX8), + apic = cpuid_has_edxfeature(CPUID_FEAT_EDX_APIC), + sep = cpuid_has_edxfeature(CPUID_FEAT_EDX_SEP), + mtrr = cpuid_has_edxfeature(CPUID_FEAT_EDX_MTRR), + pge = cpuid_has_edxfeature(CPUID_FEAT_EDX_PGE), + mca = cpuid_has_edxfeature(CPUID_FEAT_EDX_MCA), + cmov = cpuid_has_edxfeature(CPUID_FEAT_EDX_CMOV), + pat = cpuid_has_edxfeature(CPUID_FEAT_EDX_PAT), + pse36 = cpuid_has_edxfeature(CPUID_FEAT_EDX_PSE36), + psn = cpuid_has_edxfeature(CPUID_FEAT_EDX_PSN), + clf = cpuid_has_edxfeature(CPUID_FEAT_EDX_CLF), + dtes = cpuid_has_edxfeature(CPUID_FEAT_EDX_DTES), + acpi = cpuid_has_edxfeature(CPUID_FEAT_EDX_ACPI), + mmx = cpuid_has_edxfeature(CPUID_FEAT_EDX_MMX), + fxsr = cpuid_has_edxfeature(CPUID_FEAT_EDX_FXSR), + sse = cpuid_has_edxfeature(CPUID_FEAT_EDX_SSE), + sse2 = cpuid_has_edxfeature(CPUID_FEAT_EDX_SSE2), + ss = cpuid_has_edxfeature(CPUID_FEAT_EDX_SS), + htt = cpuid_has_edxfeature(CPUID_FEAT_EDX_HTT), + tm1 = cpuid_has_edxfeature(CPUID_FEAT_EDX_TM1), + ia64 = cpuid_has_edxfeature(CPUID_FEAT_EDX_IA64), + pbe = cpuid_has_edxfeature(CPUID_FEAT_EDX_PBE); + + if (featureset & CPUID_FEAT_EDX_ALL) { + fputs("-- EDX FEATURES --\n", file); + fprintf(file, "FPU: %s\n" + "VME: %s\n" + "DE: %s\n" + "PSE: %s\n" + "TSC: %s\n" + "MSR: %s\n" + "PAE: %s\n" + "MCE: %s\n" + "CX8: %s\n" + "APIC: %s\n" + "SEP: %s\n" + "MTRR: %s\n" + "PGE: %s\n" + "MCA: %s\n" + "CMOV: %s\n" + "PAT: %s\n" + "PSE36: %s\n" + "PSN: %s\n" + "CLF: %s\n" + "DTES: %s\n" + "ACPI: %s\n" + "MMX: %s\n" + "FXSR: %s\n" + "SSE: %s\n" + "SSE2: %s\n" + "SS: %s\n" + "HTT: %s\n" + "TM1: %s\n" + "IA64: %s\n" + "PBE: %s\n\n", + YON(fpu), YON(vme), YON(de), YON(pse), YON(tsc), YON(msr), + YON(pae), YON(mce), YON(cx8), YON(apic), YON(sep), YON(mtrr), + YON(pge), YON(mca), YON(cmov), YON(pat), YON(pse36), YON(psn), + YON(clf), YON(dtes), YON(acpi), YON(mmx), YON(fxsr), YON(sse), + YON(sse2), YON(ss), YON(htt), YON(tm1), YON(ia64), YON(pbe) + ); + } else { + if (featureset & CPUID_FEAT_EDX_FPU) + fprintf(file, "FPU: %s\n", YON(fpu)); + if (featureset & CPUID_FEAT_EDX_VME) + fprintf(file, "VME: %s\n", YON(vme)); + if (featureset & CPUID_FEAT_EDX_DE) + fprintf(file, "DE: %s\n", YON(de)); + if (featureset & CPUID_FEAT_EDX_PSE) + fprintf(file, "PSE: %s\n", YON(pse)); + if (featureset & CPUID_FEAT_EDX_TSC) + fprintf(file, "TSC: %s\n", YON(tsc)); + if (featureset & CPUID_FEAT_EDX_MSR) + fprintf(file, "MSR: %s\n", YON(msr)); + if (featureset & CPUID_FEAT_EDX_PAE) + fprintf(file, "PAE: %s\n", YON(pae)); + if (featureset & CPUID_FEAT_EDX_MCE) + fprintf(file, "MCE: %s\n", YON(mce)); + if (featureset & CPUID_FEAT_EDX_CX8) + fprintf(file, "CX8: %s\n", YON(cx8)); + if (featureset & CPUID_FEAT_EDX_APIC) + fprintf(file, "APIC: %s\n", YON(apic)); + if (featureset & CPUID_FEAT_EDX_SEP) + fprintf(file, "SEP: %s\n", YON(sep)); + if (featureset & CPUID_FEAT_EDX_MTRR) + fprintf(file, "MTRR: %s\n", YON(mtrr)); + if (featureset & CPUID_FEAT_EDX_PGE) + fprintf(file, "PGE: %s\n", YON(pge)); + if (featureset & CPUID_FEAT_EDX_MCA) + fprintf(file, "MCA: %s\n", YON(mca)); + if (featureset & CPUID_FEAT_EDX_CMOV) + fprintf(file, "CMOV: %s\n", YON(cmov)); + if (featureset & CPUID_FEAT_EDX_PAT) + fprintf(file, "PAT: %s\n", YON(pat)); + if (featureset & CPUID_FEAT_EDX_PSE36) + fprintf(file, "PSE36: %s\n", YON(pse36)); + if (featureset & CPUID_FEAT_EDX_PSN) + fprintf(file, "PSN: %s\n", YON(psn)); + if (featureset & CPUID_FEAT_EDX_CLF) + fprintf(file, "CLF: %s\n", YON(clf)); + if (featureset & CPUID_FEAT_EDX_DTES) + fprintf(file, "DTES:%s\n", YON(dtes)); + if (featureset & CPUID_FEAT_EDX_ACPI) + fprintf(file, "ACPI: %s\n", YON(acpi)); + if (featureset & CPUID_FEAT_EDX_MMX) + fprintf(file, "MMX: %s\n", YON(mmx)); + if (featureset & CPUID_FEAT_EDX_FXSR) + fprintf(file, "FXSR: %s\n", YON(fxsr)); + if (featureset & CPUID_FEAT_EDX_SSE) + fprintf(file, "SSE: %s\n", YON(sse)); + if (featureset & CPUID_FEAT_EDX_SSE2) + fprintf(file, "SSE2: %s\n", YON(sse2)); + if (featureset & CPUID_FEAT_EDX_SS) + fprintf(file, "SS: %s\n", YON(ss)); + if (featureset & CPUID_FEAT_EDX_HTT) + fprintf(file, "HTT: %s\n", YON(htt)); + if (featureset & CPUID_FEAT_EDX_TM1) + fprintf(file, "TM1: %s\n", YON(tm1)); + if (featureset & CPUID_FEAT_EDX_IA64) + fprintf(file, "IA64: %s\n", YON(ia64)); + if (featureset & CPUID_FEAT_EDX_PBE) + fprintf(file, "PBE: %s\n", YON(pbe)); + } +#undef YON + + fclose(file); + return true; +} + #endif