diff --git a/contrib/libcpuid/include/libcpuid/amd_code_t.h b/contrib/libcpuid/include/libcpuid/amd_code_t.h new file mode 100644 index 00000000000..2472a3d61d5 --- /dev/null +++ b/contrib/libcpuid/include/libcpuid/amd_code_t.h @@ -0,0 +1,65 @@ +/* + * Copyright 2016 Veselin Georgiev, + * anrieffNOSPAM @ mgail_DOT.com (convert to gmail) + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR + * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES + * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. + * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, + * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT + * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, + * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY + * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF + * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +/* + * This file contains a list of internal codes we use in detection. It is + * of no external use and isn't a complete list of AMD products. + */ + CODE2(OPTERON_GENERIC, 1000), + CODE(OPTERON_800), + CODE(ATHLON_XP), + CODE(ATHLON_XP_M), + CODE(ATHLON_XP_M_LV), + CODE(ATHLON), + CODE(ATHLON_MP), + CODE(MOBILE_ATHLON64), + CODE(ATHLON_FX), + CODE(DURON), + CODE(DURON_MP), + CODE(MOBILE_DURON), + CODE(MOBILE_SEMPRON), + CODE(OPTERON_SINGLE), + CODE(OPTERON_DUALCORE), + CODE(OPTERON_800_DUALCORE), + CODE(MOBILE_TURION), + CODE(ATHLON_64), + CODE(ATHLON_64_FX), + CODE(TURION_64), + CODE(TURION_X2), + CODE(SEMPRON), + CODE(M_SEMPRON), + CODE(SEMPRON_DUALCORE), + CODE(PHENOM), + CODE(PHENOM2), + CODE(ATHLON_64_X2), + CODE(ATHLON_64_X3), + CODE(ATHLON_64_X4), + CODE(FUSION_C), + CODE(FUSION_E), + CODE(FUSION_EA), + CODE(FUSION_Z), + CODE(FUSION_A), + diff --git a/contrib/libcpuid/include/libcpuid/asm-bits.c b/contrib/libcpuid/include/libcpuid/asm-bits.c index ca936f2abf5..b8e32284f57 100644 --- a/contrib/libcpuid/include/libcpuid/asm-bits.c +++ b/contrib/libcpuid/include/libcpuid/asm-bits.c @@ -75,13 +75,13 @@ int cpuid_exists_by_eflags(void) #endif /* PLATFORM_X86 */ } +#ifdef INLINE_ASM_SUPPORTED /* * with MSVC/AMD64, the exec_cpuid() and cpu_rdtsc() functions * are implemented in separate .asm files. Otherwise, use inline assembly */ void exec_cpuid(uint32_t *regs) { -#ifdef INLINE_ASM_SUPPORTED #ifdef COMPILER_GCC # ifdef PLATFORM_X64 __asm __volatile( @@ -166,8 +166,8 @@ void exec_cpuid(uint32_t *regs) # error "Unsupported compiler" # endif /* COMPILER_MICROSOFT */ #endif -#endif /* INLINE_ASSEMBLY_SUPPORTED */ } +#endif /* INLINE_ASSEMBLY_SUPPORTED */ #ifdef INLINE_ASM_SUPPORTED void cpu_rdtsc(uint64_t* result) @@ -214,7 +214,8 @@ void busy_sse_loop(int cycles) " xorps %%xmm6, %%xmm6\n" " xorps %%xmm7, %%xmm7\n" XALIGN - ".bsLoop:\n" + /* ".bsLoop:\n" */ + "1:\n" // 0: " addps %%xmm1, %%xmm0\n" " addps %%xmm2, %%xmm1\n" @@ -505,7 +506,8 @@ void busy_sse_loop(int cycles) " addps %%xmm0, %%xmm7\n" " dec %%eax\n" - " jnz .bsLoop\n" + /* "jnz .bsLoop\n" */ + " jnz 1b\n" ::"a"(cycles) ); #else diff --git a/contrib/libcpuid/include/libcpuid/config.h b/contrib/libcpuid/include/libcpuid/config.h index 29b513c4ac1..2326cfeede5 100644 --- a/contrib/libcpuid/include/libcpuid/config.h +++ b/contrib/libcpuid/include/libcpuid/config.h @@ -1,2 +1,2 @@ /* Version number of package */ -#define VERSION "0.2.1" +#define VERSION "0.4.0" diff --git a/contrib/libcpuid/include/libcpuid/cpuid_main.c b/contrib/libcpuid/include/libcpuid/cpuid_main.c index 737aa706a37..02a7cb7ad50 100644 --- a/contrib/libcpuid/include/libcpuid/cpuid_main.c +++ b/contrib/libcpuid/include/libcpuid/cpuid_main.c @@ -24,11 +24,14 @@ * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. */ #include "libcpuid.h" +#include "libcpuid_internal.h" #include "recog_intel.h" #include "recog_amd.h" #include "asm-bits.h" #include "libcpuid_util.h" +//#ifdef HAVE_CONFIG_H // CLICKHOUSE PATCH #include "config.h" +//#endif // CLICKHOUSE PATCH #include #include #include @@ -51,9 +54,9 @@ static void raw_data_t_constructor(struct cpu_raw_data_t* raw) static void cpu_id_t_constructor(struct cpu_id_t* id) { memset(id, 0, sizeof(struct cpu_id_t)); - id->l1_data_cache = id->l1_instruction_cache = id->l2_cache = id->l3_cache = -1; - id->l1_assoc = id->l2_assoc = id->l3_assoc = -1; - id->l1_cacheline = id->l2_cacheline = id->l3_cacheline = -1; + id->l1_data_cache = id->l1_instruction_cache = id->l2_cache = id->l3_cache = id->l4_cache = -1; + id->l1_assoc = id->l2_assoc = id->l3_assoc = id->l4_assoc = -1; + id->l1_cacheline = id->l2_cacheline = id->l3_cacheline = id->l4_cacheline = -1; id->sse_size = -1; } @@ -181,14 +184,26 @@ static void load_features_common(struct cpu_raw_data_t* raw, struct cpu_id_t* da }; const struct feature_map_t matchtable_ecx1[] = { { 0, CPU_FEATURE_PNI }, + { 1, CPU_FEATURE_PCLMUL }, { 3, CPU_FEATURE_MONITOR }, { 9, CPU_FEATURE_SSSE3 }, { 12, CPU_FEATURE_FMA3 }, { 13, CPU_FEATURE_CX16 }, { 19, CPU_FEATURE_SSE4_1 }, - { 21, CPU_FEATURE_X2APIC }, + { 20, CPU_FEATURE_SSE4_2 }, + { 22, CPU_FEATURE_MOVBE }, { 23, CPU_FEATURE_POPCNT }, + { 25, CPU_FEATURE_AES }, + { 26, CPU_FEATURE_XSAVE }, + { 27, CPU_FEATURE_OSXSAVE }, + { 28, CPU_FEATURE_AVX }, { 29, CPU_FEATURE_F16C }, + { 30, CPU_FEATURE_RDRAND }, + }; + const struct feature_map_t matchtable_ebx7[] = { + { 3, CPU_FEATURE_BMI1 }, + { 5, CPU_FEATURE_AVX2 }, + { 8, CPU_FEATURE_BMI2 }, }; const struct feature_map_t matchtable_edx81[] = { { 11, CPU_FEATURE_SYSCALL }, @@ -205,6 +220,9 @@ static void load_features_common(struct cpu_raw_data_t* raw, struct cpu_id_t* da match_features(matchtable_edx1, COUNT_OF(matchtable_edx1), raw->basic_cpuid[1][3], data); match_features(matchtable_ecx1, COUNT_OF(matchtable_ecx1), raw->basic_cpuid[1][2], data); } + if (raw->basic_cpuid[0][0] >= 7) { + match_features(matchtable_ebx7, COUNT_OF(matchtable_ebx7), raw->basic_cpuid[7][1], data); + } if (raw->ext_cpuid[0][0] >= 0x80000001) { match_features(matchtable_edx81, COUNT_OF(matchtable_edx81), raw->ext_cpuid[1][3], data); match_features(matchtable_ecx81, COUNT_OF(matchtable_ecx81), raw->ext_cpuid[1][2], data); @@ -229,10 +247,10 @@ static void load_features_common(struct cpu_raw_data_t* raw, struct cpu_id_t* da } } -static int cpuid_basic_identify(struct cpu_raw_data_t* raw, struct cpu_id_t* data) +static cpu_vendor_t cpuid_vendor_identify(const uint32_t *raw_vendor, char *vendor_str) { - int i, j, basic, xmodel, xfamily, ext; - char brandstr[64] = {0}; + int i; + cpu_vendor_t vendor = VENDOR_UNKNOWN; const struct { cpu_vendor_t vendor; char match[16]; } matchtable[NUM_CPU_VENDORS] = { /* source: http://www.sandpile.org/ia32/cpuid.htm */ @@ -247,18 +265,27 @@ static int cpuid_basic_identify(struct cpu_raw_data_t* raw, struct cpu_id_t* dat { VENDOR_SIS , "SiS SiS SiS " }, { VENDOR_NSC , "Geode by NSC" }, }; - - memcpy(data->vendor_str + 0, &raw->basic_cpuid[0][1], 4); - memcpy(data->vendor_str + 4, &raw->basic_cpuid[0][3], 4); - memcpy(data->vendor_str + 8, &raw->basic_cpuid[0][2], 4); - data->vendor_str[12] = 0; + + memcpy(vendor_str + 0, &raw_vendor[1], 4); + memcpy(vendor_str + 4, &raw_vendor[3], 4); + memcpy(vendor_str + 8, &raw_vendor[2], 4); + vendor_str[12] = 0; + /* Determine vendor: */ - data->vendor = VENDOR_UNKNOWN; for (i = 0; i < NUM_CPU_VENDORS; i++) - if (!strcmp(data->vendor_str, matchtable[i].match)) { - data->vendor = matchtable[i].vendor; + if (!strcmp(vendor_str, matchtable[i].match)) { + vendor = matchtable[i].vendor; break; } + return vendor; +} + +static int cpuid_basic_identify(struct cpu_raw_data_t* raw, struct cpu_id_t* data) +{ + int i, j, basic, xmodel, xfamily, ext; + char brandstr[64] = {0}; + data->vendor = cpuid_vendor_identify(raw->basic_cpuid[0], data->vendor_str); + if (data->vendor == VENDOR_UNKNOWN) return set_error(ERR_CPU_UNKN); basic = raw->basic_cpuid[0][0]; @@ -347,7 +374,7 @@ int cpuid_get_raw_data(struct cpu_raw_data_t* data) cpu_exec_cpuid(i, data->basic_cpuid[i]); for (i = 0; i < 32; i++) cpu_exec_cpuid(0x80000000 + i, data->ext_cpuid[i]); - for (i = 0; i < 4; i++) { + for (i = 0; i < MAX_INTELFN4_LEVEL; i++) { memset(data->intel_fn4[i], 0, sizeof(data->intel_fn4[i])); data->intel_fn4[i][0] = 4; data->intel_fn4[i][2] = i; @@ -359,6 +386,18 @@ int cpuid_get_raw_data(struct cpu_raw_data_t* data) data->intel_fn11[i][2] = i; cpu_exec_cpuid_ext(data->intel_fn11[i]); } + for (i = 0; i < MAX_INTELFN12H_LEVEL; i++) { + memset(data->intel_fn12h[i], 0, sizeof(data->intel_fn12h[i])); + data->intel_fn12h[i][0] = 0x12; + data->intel_fn12h[i][2] = i; + cpu_exec_cpuid_ext(data->intel_fn12h[i]); + } + for (i = 0; i < MAX_INTELFN14H_LEVEL; i++) { + memset(data->intel_fn14h[i], 0, sizeof(data->intel_fn14h[i])); + data->intel_fn14h[i][0] = 0x14; + data->intel_fn14h[i][2] = i; + cpu_exec_cpuid_ext(data->intel_fn14h[i]); + } return set_error(ERR_OK); } @@ -390,6 +429,14 @@ int cpuid_serialize_raw_data(struct cpu_raw_data_t* data, const char* filename) fprintf(f, "intel_fn11[%d]=%08x %08x %08x %08x\n", i, data->intel_fn11[i][0], data->intel_fn11[i][1], data->intel_fn11[i][2], data->intel_fn11[i][3]); + for (i = 0; i < MAX_INTELFN12H_LEVEL; i++) + fprintf(f, "intel_fn12h[%d]=%08x %08x %08x %08x\n", i, + data->intel_fn12h[i][0], data->intel_fn12h[i][1], + data->intel_fn12h[i][2], data->intel_fn12h[i][3]); + for (i = 0; i < MAX_INTELFN14H_LEVEL; i++) + fprintf(f, "intel_fn14h[%d]=%08x %08x %08x %08x\n", i, + data->intel_fn14h[i][0], data->intel_fn14h[i][1], + data->intel_fn14h[i][2], data->intel_fn14h[i][3]); if (strcmp(filename, "")) fclose(f); @@ -434,10 +481,12 @@ int cpuid_deserialize_raw_data(struct cpu_raw_data_t* data, const char* filename recognized = 1; } syntax = 1; - syntax = syntax && parse_token("basic_cpuid", token, value, data->basic_cpuid, 32, &recognized); - syntax = syntax && parse_token("ext_cpuid", token, value, data->ext_cpuid, 32, &recognized); - syntax = syntax && parse_token("intel_fn4", token, value, data->intel_fn4, 4, &recognized); - syntax = syntax && parse_token("intel_fn11", token, value, data->intel_fn11, 4, &recognized); + syntax = syntax && parse_token("basic_cpuid", token, value, data->basic_cpuid, MAX_CPUID_LEVEL, &recognized); + syntax = syntax && parse_token("ext_cpuid", token, value, data->ext_cpuid, MAX_EXT_CPUID_LEVEL, &recognized); + syntax = syntax && parse_token("intel_fn4", token, value, data->intel_fn4, MAX_INTELFN4_LEVEL, &recognized); + syntax = syntax && parse_token("intel_fn11", token, value, data->intel_fn11, MAX_INTELFN11_LEVEL, &recognized); + syntax = syntax && parse_token("intel_fn12h", token, value, data->intel_fn12h, MAX_INTELFN12H_LEVEL, &recognized); + syntax = syntax && parse_token("intel_fn14h", token, value, data->intel_fn14h, MAX_INTELFN14H_LEVEL, &recognized); if (!syntax) { warnf("Error: %s:%d: Syntax error\n", filename, cur_line); fclose(f); @@ -453,7 +502,7 @@ int cpuid_deserialize_raw_data(struct cpu_raw_data_t* data, const char* filename return set_error(ERR_OK); } -int cpu_identify(struct cpu_raw_data_t* raw, struct cpu_id_t* data) +int cpu_ident_internal(struct cpu_raw_data_t* raw, struct cpu_id_t* data, struct internal_id_info_t* internal) { int r; struct cpu_raw_data_t myraw; @@ -467,10 +516,10 @@ int cpu_identify(struct cpu_raw_data_t* raw, struct cpu_id_t* data) return set_error(r); switch (data->vendor) { case VENDOR_INTEL: - r = cpuid_identify_intel(raw, data); + r = cpuid_identify_intel(raw, data, internal); break; case VENDOR_AMD: - r = cpuid_identify_amd(raw, data); + r = cpuid_identify_amd(raw, data, internal); break; default: break; @@ -478,6 +527,12 @@ int cpu_identify(struct cpu_raw_data_t* raw, struct cpu_id_t* data) return set_error(r); } +int cpu_identify(struct cpu_raw_data_t* raw, struct cpu_id_t* data) +{ + struct internal_id_info_t throwaway; + return cpu_ident_internal(raw, data, &throwaway); +} + const char* cpu_feature_str(cpu_feature_t feature) { const struct { cpu_feature_t feature; const char* name; } @@ -577,6 +632,21 @@ const char* cpu_feature_str(cpu_feature_t feature) { CPU_FEATURE_PFI, "pfi" }, { CPU_FEATURE_PA, "pa" }, { CPU_FEATURE_AVX2, "avx2" }, + { CPU_FEATURE_BMI1, "bmi1" }, + { CPU_FEATURE_BMI2, "bmi2" }, + { CPU_FEATURE_HLE, "hle" }, + { CPU_FEATURE_RTM, "rtm" }, + { CPU_FEATURE_AVX512F, "avx512f" }, + { CPU_FEATURE_AVX512DQ, "avx512dq" }, + { CPU_FEATURE_AVX512PF, "avx512pf" }, + { CPU_FEATURE_AVX512ER, "avx512er" }, + { CPU_FEATURE_AVX512CD, "avx512cd" }, + { CPU_FEATURE_SHA_NI, "sha_ni" }, + { CPU_FEATURE_AVX512BW, "avx512bw" }, + { CPU_FEATURE_AVX512VL, "avx512vl" }, + { CPU_FEATURE_SGX, "sgx" }, + { CPU_FEATURE_RDSEED, "rdseed" }, + { CPU_FEATURE_ADX, "adx" }, }; unsigned i, n = COUNT_OF(matchtable); if (n != NUM_CPU_FEATURES) { @@ -600,6 +670,15 @@ const char* cpuid_error(void) { ERR_BADFMT , "Bad file format"}, { ERR_NOT_IMP , "Not implemented"}, { ERR_CPU_UNKN , "Unsupported processor"}, + { ERR_NO_RDMSR , "RDMSR instruction is not supported"}, + { ERR_NO_DRIVER, "RDMSR driver error (generic)"}, + { ERR_NO_PERMS , "No permissions to install RDMSR driver"}, + { ERR_EXTRACT , "Cannot extract RDMSR driver (read only media?)"}, + { ERR_HANDLE , "Bad handle"}, + { ERR_INVMSR , "Invalid MSR"}, + { ERR_INVCNB , "Invalid core number"}, + { ERR_HANDLE_R , "Error on handle read"}, + { ERR_INVRANGE , "Invalid given range"}, }; unsigned i; for (i = 0; i < COUNT_OF(matchtable); i++) @@ -626,6 +705,23 @@ void cpuid_set_verbosiness_level(int level) _current_verboselevel = level; } +cpu_vendor_t cpuid_get_vendor(void) +{ + static cpu_vendor_t vendor = VENDOR_UNKNOWN; + uint32_t raw_vendor[4]; + char vendor_str[VENDOR_STR_MAX]; + + if(vendor == VENDOR_UNKNOWN) { + if (!cpuid_present()) + set_error(ERR_NO_CPUID); + else { + cpu_exec_cpuid(0, raw_vendor); + vendor = cpuid_vendor_identify(raw_vendor, vendor_str); + } + } + return vendor; +} + void cpuid_get_cpu_list(cpu_vendor_t vendor, struct cpu_list_t* list) { switch (vendor) { diff --git a/contrib/libcpuid/include/libcpuid/intel_code_t.h b/contrib/libcpuid/include/libcpuid/intel_code_t.h new file mode 100644 index 00000000000..c50ec9c5a83 --- /dev/null +++ b/contrib/libcpuid/include/libcpuid/intel_code_t.h @@ -0,0 +1,83 @@ +/* + * Copyright 2016 Veselin Georgiev, + * anrieffNOSPAM @ mgail_DOT.com (convert to gmail) + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR + * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES + * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. + * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, + * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT + * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, + * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY + * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF + * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +/* + * This file contains a list of internal codes we use in detection. It is + * of no external use and isn't a complete list of intel products. + */ + CODE2(PENTIUM, 2000), + CODE(MOBILE_PENTIUM), + + CODE(XEON), + CODE(XEON_IRWIN), + CODE(XEONMP), + CODE(XEON_POTOMAC), + CODE(XEON_I7), + CODE(XEON_GAINESTOWN), + CODE(XEON_WESTMERE), + + CODE(MOBILE_PENTIUM_M), + CODE(CELERON), + CODE(MOBILE_CELERON), + CODE(NOT_CELERON), + + + CODE(CORE_SOLO), + CODE(MOBILE_CORE_SOLO), + CODE(CORE_DUO), + CODE(MOBILE_CORE_DUO), + + CODE(WOLFDALE), + CODE(MEROM), + CODE(PENRYN), + CODE(QUAD_CORE), + CODE(DUAL_CORE_HT), + CODE(QUAD_CORE_HT), + CODE(MORE_THAN_QUADCORE), + CODE(PENTIUM_D), + + CODE(ATOM_UNKNOWN), + CODE(ATOM_SILVERTHORNE), + CODE(ATOM_DIAMONDVILLE), + CODE(ATOM_PINEVIEW), + CODE(ATOM_CEDARVIEW), + + CODE(CORE_I3), + CODE(CORE_I5), + CODE(CORE_I7), + CODE(CORE_IVY3), /* 22nm Core-iX */ + CODE(CORE_IVY5), + CODE(CORE_IVY7), + CODE(CORE_HASWELL3), /* 22nm Core-iX, Haswell */ + CODE(CORE_HASWELL5), + CODE(CORE_HASWELL7), + CODE(CORE_BROADWELL3), /* 14nm Core-iX, Broadwell */ + CODE(CORE_BROADWELL5), + CODE(CORE_BROADWELL7), + CODE(CORE_SKYLAKE3), /* 14nm Core-iX, Skylake */ + CODE(CORE_SKYLAKE5), + CODE(CORE_SKYLAKE7), + diff --git a/contrib/libcpuid/include/libcpuid/libcpuid.h b/contrib/libcpuid/include/libcpuid/libcpuid.h index b78b0d6f514..866c0e8441d 100644 --- a/contrib/libcpuid/include/libcpuid/libcpuid.h +++ b/contrib/libcpuid/include/libcpuid/libcpuid.h @@ -26,25 +26,37 @@ #ifndef __LIBCPUID_H__ #define __LIBCPUID_H__ /** - * @File libcpuid.h - * @Author Veselin Georgiev - * @Date Oct 2008 - * @Version 0.2.1 + * \file libcpuid.h + * \author Veselin Georgiev + * \date Oct 2008 + * \version 0.4.0 * * Version history: * - * 0.1.0 (2008-10-15): initial adaptation from wxfractgui sources - * 0.1.1 (2009-07-06): Added intel_fn11 fields to cpu_raw_data_t to handle - * new processor topology enumeration required on Core i7 - * 0.1.2 (2009-09-26): Added support for MSR reading through self-extracting - * kernel driver on Win32. - * 0.1.3 (2010-04-20): Added support for greater more accurate CPU clock - * measurements with cpu_clock_by_ic() - * 0.2.0 (2011-10-11): Support for AMD Bulldozer CPUs, 128-bit SSE unit size - * checking. A backwards-incompatible change, since the - * sizeof cpu_id_t is now different. - * 0.2.1 (2012-05-26): Support for Ivy Bridge, and detecting the presence of - * the RdRand instruction. + * * 0.1.0 (2008-10-15): initial adaptation from wxfractgui sources + * * 0.1.1 (2009-07-06): Added intel_fn11 fields to cpu_raw_data_t to handle + * new processor topology enumeration required on Core i7 + * * 0.1.2 (2009-09-26): Added support for MSR reading through self-extracting + * kernel driver on Win32. + * * 0.1.3 (2010-04-20): Added support for greater more accurate CPU clock + * measurements with cpu_clock_by_ic() + * * 0.2.0 (2011-10-11): Support for AMD Bulldozer CPUs, 128-bit SSE unit size + * checking. A backwards-incompatible change, since the + * sizeof cpu_id_t is now different. + * * 0.2.1 (2012-05-26): Support for Ivy Bridge, and detecting the presence of + * the RdRand instruction. + * * 0.2.2 (2015-11-04): Support for newer processors up to Haswell and Vishera. + * Fix clock detection in cpu_clock_by_ic() for Bulldozer. + * More entries supported in cpu_msrinfo(). + * *BSD and Solaris support (unofficial). + * * 0.3.0 (2016-07-09): Support for Skylake; MSR ops in FreeBSD; INFO_VOLTAGE + * for AMD CPUs. Level 4 cache support for Crystalwell + * (a backwards-incompatible change since the sizeof + * cpu_raw_data_t is now different). + * * 0.4.0 (2016-09-30): Better detection of AMD clock multiplier with msrinfo. + * Support for Intel SGX detection + * (a backwards-incompatible change since the sizeof + * cpu_raw_data_t and cpu_id_t is now different). */ /** @mainpage A simple libcpuid introduction @@ -57,6 +69,15 @@ * To fetch the CPUID info needed for CPU identification, use * \ref cpuid_get_raw_data
* To make sense of that data (decode, extract features), use \ref cpu_identify
+ * To detect the CPU speed, use either \ref cpu_clock, \ref cpu_clock_by_os, + * \ref cpu_tsc_mark + \ref cpu_tsc_unmark + \ref cpu_clock_by_mark, + * \ref cpu_clock_measure or \ref cpu_clock_by_ic. + * Read carefully for pros/cons of each method.
+ * + * To read MSRs, use \ref cpu_msr_driver_open to get a handle, and then + * \ref cpu_rdmsr for querying abilities. Some MSR decoding is available on recent + * CPUs, and can be queried through \ref cpu_msrinfo; the various types of queries + * are described in \ref cpu_msrinfo_request_t. *

*/ @@ -116,6 +137,81 @@ struct cpu_raw_data_t { enumeration leaf), this stores the result of CPUID with eax = 11 and ecx = 0, 1, 2... */ uint32_t intel_fn11[MAX_INTELFN11_LEVEL][4]; + + /** when the CPU is intel and supports leaf 12h (SGX enumeration leaf), + * this stores the result of CPUID with eax = 0x12 and + * ecx = 0, 1, 2... */ + uint32_t intel_fn12h[MAX_INTELFN12H_LEVEL][4]; + + /** when the CPU is intel and supports leaf 14h (Intel Processor Trace + * capabilities leaf). + * this stores the result of CPUID with eax = 0x12 and + * ecx = 0, 1, 2... */ + uint32_t intel_fn14h[MAX_INTELFN14H_LEVEL][4]; +}; + +/** + * @brief This contains information about SGX features of the processor + * Example usage: + * @code + * ... + * struct cpu_raw_data_t raw; + * struct cpu_id_t id; + * + * if (cpuid_get_raw_data(&raw) == 0 && cpu_identify(&raw, &id) == 0 && id.sgx.present) { + * printf("SGX is present.\n"); + * printf("SGX1 instructions: %s.\n", id.sgx.flags[INTEL_SGX1] ? "present" : "absent"); + * printf("SGX2 instructions: %s.\n", id.sgx.flags[INTEL_SGX2] ? "present" : "absent"); + * printf("Max 32-bit enclave size: 2^%d bytes.\n", id.sgx.max_enclave_32bit); + * printf("Max 64-bit enclave size: 2^%d bytes.\n", id.sgx.max_enclave_64bit); + * for (int i = 0; i < id.sgx.num_epc_sections; i++) { + * struct cpu_epc_t epc = cpuid_get_epc(i, NULL); + * printf("EPC section #%d: address = %x, size = %d bytes.\n", epc.address, epc.size); + * } + * } else { + * printf("SGX is not present.\n"); + * } + * @endcode + */ +struct cpu_sgx_t { + /** Whether SGX is present (boolean) */ + uint32_t present; + + /** Max enclave size in 32-bit mode. This is a power-of-two value: + * if it is "31", then the max enclave size is 2^31 bytes (2 GiB). + */ + uint8_t max_enclave_32bit; + + /** Max enclave size in 64-bit mode. This is a power-of-two value: + * if it is "36", then the max enclave size is 2^36 bytes (64 GiB). + */ + uint8_t max_enclave_64bit; + + /** + * contains SGX feature flags. See the \ref cpu_sgx_feature_t + * "INTEL_SGX*" macros below. + */ + uint8_t flags[SGX_FLAGS_MAX]; + + /** number of Enclave Page Cache (EPC) sections. Info for each + * section is available through the \ref cpuid_get_epc() function + */ + int num_epc_sections; + + /** bit vector of the supported extended features that can be written + * to the MISC region of the SSA (Save State Area) + */ + uint32_t misc_select; + + /** a bit vector of the attributes that can be set to SECS.ATTRIBUTES + * via ECREATE. Corresponds to bits 0-63 (incl.) of SECS.ATTRIBUTES. + */ + uint64_t secs_attributes; + + /** a bit vector of the bits that can be set in the XSAVE feature + * request mask; Corresponds to bits 64-127 of SECS.ATTRIBUTES. + */ + uint64_t secs_xfrm; }; /** @@ -133,7 +229,8 @@ struct cpu_id_t { /** * contain CPU flags. Used to test for features. See - * the CPU_FEATURE_* macros below. @see Features + * the \ref cpu_feature_t "CPU_FEATURE_*" macros below. + * @see Features */ uint8_t flags[CPU_FLAGS_MAX]; @@ -164,11 +261,17 @@ struct cpu_id_t { /** * The total number of logical processors. + * The same value is availabe through \ref cpuid_get_total_cpus. * * This is num_logical_cpus * {total physical processors in the system} + * (but only on a real system, under a VM this number may be lower). * * If you're writing a multithreaded program and you want to run it on * all CPUs, this is the number of threads you need. + * + * @note in a VM, this will exactly match the number of CPUs set in + * the VM's configuration. + * */ int32_t total_logical_cpus; @@ -194,6 +297,9 @@ struct cpu_id_t { /** L3 cache size in KB. Zero on most systems */ int32_t l3_cache; + + /** L4 cache size in KB. Zero on most systems */ + int32_t l4_cache; /** Cache associativity for the L1 data cache. -1 if undetermined */ int32_t l1_assoc; @@ -203,6 +309,9 @@ struct cpu_id_t { /** Cache associativity for the L3 cache. -1 if undetermined */ int32_t l3_assoc; + + /** Cache associativity for the L4 cache. -1 if undetermined */ + int32_t l4_assoc; /** Cache-line size for L1 data cache. -1 if undetermined */ int32_t l1_cacheline; @@ -213,6 +322,9 @@ struct cpu_id_t { /** Cache-line size for L3 cache. -1 if undetermined */ int32_t l3_cacheline; + /** Cache-line size for L4 cache. -1 if undetermined */ + int32_t l4_cacheline; + /** * The brief and human-friendly CPU codename, which was recognized.
* Examples: @@ -234,9 +346,13 @@ struct cpu_id_t { /** * contain miscellaneous detection information. Used to test about specifics of - * certain detected features. See CPU_HINT_* macros below. @see Hints + * certain detected features. See \ref cpu_hint_t "CPU_HINT_*" macros below. + * @see Hints */ uint8_t detection_hints[CPU_HINTS_MAX]; + + /** contains information about SGX features if the processor, if present */ + struct cpu_sgx_t sgx; }; /** @@ -355,6 +471,21 @@ typedef enum { CPU_FEATURE_PFI, /*!< Processor Feedback Interface support */ CPU_FEATURE_PA, /*!< Processor accumulator */ CPU_FEATURE_AVX2, /*!< AVX2 instructions */ + CPU_FEATURE_BMI1, /*!< BMI1 instructions */ + CPU_FEATURE_BMI2, /*!< BMI2 instructions */ + CPU_FEATURE_HLE, /*!< Hardware Lock Elision prefixes */ + CPU_FEATURE_RTM, /*!< Restricted Transactional Memory instructions */ + CPU_FEATURE_AVX512F, /*!< AVX-512 Foundation */ + CPU_FEATURE_AVX512DQ, /*!< AVX-512 Double/Quad granular insns */ + CPU_FEATURE_AVX512PF, /*!< AVX-512 Prefetch */ + CPU_FEATURE_AVX512ER, /*!< AVX-512 Exponential/Reciprocal */ + CPU_FEATURE_AVX512CD, /*!< AVX-512 Conflict detection */ + CPU_FEATURE_SHA_NI, /*!< SHA-1/SHA-256 instructions */ + CPU_FEATURE_AVX512BW, /*!< AVX-512 Byte/Word granular insns */ + CPU_FEATURE_AVX512VL, /*!< AVX-512 128/256 vector length extensions */ + CPU_FEATURE_SGX, /*!< SGX extensions. Non-autoritative, check cpu_id_t::sgx::present to verify presence */ + CPU_FEATURE_RDSEED, /*!< RDSEED instruction */ + CPU_FEATURE_ADX, /*!< ADX extensions (arbitrary precision) */ /* termination: */ NUM_CPU_FEATURES, } cpu_feature_t; @@ -370,6 +501,36 @@ typedef enum { NUM_CPU_HINTS, } cpu_hint_t; +/** + * @brief SGX features flags + * \see cpu_sgx_t + * + * Usage: + * @code + * ... + * struct cpu_raw_data_t raw; + * struct cpu_id_t id; + * if (cpuid_get_raw_data(&raw) == 0 && cpu_identify(&raw, &id) == 0 && id.sgx.present) { + * if (id.sgx.flags[INTEL_SGX1]) + * // The CPU has SGX1 instructions support... + * ... + * } else { + * // no SGX + * } + * } else { + * // processor cannot be determined. + * } + * @endcode + */ + +typedef enum { + INTEL_SGX1, /*!< SGX1 instructions support */ + INTEL_SGX2, /*!< SGX2 instructions support */ + + /* termination: */ + NUM_SGX_FEATURES, +} cpu_sgx_feature_t; + /** * @brief Describes common library error codes */ @@ -387,7 +548,10 @@ typedef enum { ERR_NO_PERMS = -10, /*!< "No permissions to install RDMSR driver" */ ERR_EXTRACT = -11, /*!< "Cannot extract RDMSR driver (read only media?)" */ ERR_HANDLE = -12, /*!< "Bad handle" */ - ERR_INVMSR = -13, /*!< "Invalid MSR" */ + ERR_INVMSR = -13, /*!< "Invalid MSR" */ + ERR_INVCNB = -14, /*!< "Invalid core number" */ + ERR_HANDLE_R = -15, /*!< "Error on handle read" */ + ERR_INVRANGE = -16, /*!< "Invalid given range" */ } cpu_error_t; /** @@ -400,8 +564,14 @@ struct cpu_mark_t { }; /** - * @brief Returns the total number of CPUs even if CPUID is not present - * @retval Number of CPUs available + * @brief Returns the total number of logical CPU threads (even if CPUID is not present). + * + * Under VM, this number (and total_logical_cpus, since they are fetched with the same code) + * may be nonsensical, i.e. might not equal NumPhysicalCPUs*NumCoresPerCPU*HyperThreading. + * This is because no matter how many logical threads the host machine has, you may limit them + * in the VM to any number you like. **This** is the number returned by cpuid_get_total_cpus(). + * + * @returns Number of logical CPU threads available. Equals the \ref cpu_id_t::total_logical_cpus. */ int cpuid_get_total_cpus(void); @@ -713,6 +883,32 @@ int cpu_clock_by_ic(int millis, int runs); */ int cpu_clock(void); + +/** + * @brief The return value of cpuid_get_epc(). + * @details + * Describes an EPC (Enclave Page Cache) layout (physical address and size). + * A CPU may have one or more EPC areas, and information about each is + * fetched via \ref cpuid_get_epc. + */ +struct cpu_epc_t { + uint64_t start_addr; + uint64_t length; +}; + +/** + * @brief Fetches information about an EPC (Enclave Page Cache) area. + * @param index - zero-based index, valid range [0..cpu_id_t.egx.num_epc_sections) + * @param raw - a pointer to fetched raw CPUID data. Needed only for testing, + * you can safely pass NULL here (if you pass a real structure, + * it will be used for fetching the leaf 12h data if index < 2; + * otherwise the real CPUID instruction will be used). + * @returns the requested data. If the CPU doesn't support SGX, or if + * index >= cpu_id_t.egx.num_epc_sections, both fields of the returned + * structure will be zeros. + */ +struct cpu_epc_t cpuid_get_epc(int index, const struct cpu_raw_data_t* raw); + /** * @brief Returns the libcpuid version * @@ -750,6 +946,14 @@ libcpuid_warn_fn_t cpuid_set_warn_function(libcpuid_warn_fn_t warn_fun); void cpuid_set_verbosiness_level(int level); +/** + * @brief Obtains the CPU vendor from CPUID from the current CPU + * @note The result is cached. + * @returns VENDOR_UNKNOWN if failed, otherwise the CPU vendor type. + * @see cpu_vendor_t + */ +cpu_vendor_t cpuid_get_vendor(void); + /** * @brief a structure that holds a list of processor names */ @@ -788,6 +992,7 @@ void cpuid_get_cpu_list(cpu_vendor_t vendor, struct cpu_list_t* list); */ void cpuid_free_cpu_list(struct cpu_list_t* list); +struct msr_driver_t; /** * @brief Starts/opens a driver, needed to read MSRs (Model Specific Registers) * @@ -799,9 +1004,23 @@ void cpuid_free_cpu_list(struct cpu_list_t* list); * The error message can be obtained by calling \ref cpuid_error. * @see cpu_error_t */ -struct msr_driver_t; struct msr_driver_t* cpu_msr_driver_open(void); +/** + * @brief Similar to \ref cpu_msr_driver_open, but accept one parameter + * + * This function works on certain operating systems (GNU/Linux, FreeBSD) + * + * @param core_num specify the core number for MSR. + * The first core number is 0. + * The last core number is \ref cpuid_get_total_cpus - 1. + * + * @returns a handle to the driver on success, and NULL on error. + * The error message can be obtained by calling \ref cpuid_error. + * @see cpu_error_t + */ +struct msr_driver_t* cpu_msr_driver_open_core(unsigned core_num); + /** * @brief Reads a Model-Specific Register (MSR) * @@ -826,26 +1045,51 @@ struct msr_driver_t* cpu_msr_driver_open(void); * The error message can be obtained by calling \ref cpuid_error. * @see cpu_error_t */ -int cpu_rdmsr(struct msr_driver_t* handle, int msr_index, uint64_t* result); +int cpu_rdmsr(struct msr_driver_t* handle, uint32_t msr_index, uint64_t* result); typedef enum { INFO_MPERF, /*!< Maximum performance frequency clock. This is a counter, which increments as a - proportion of the actual processor speed */ + proportion of the actual processor speed. */ INFO_APERF, /*!< Actual performance frequency clock. This accumulates the core clock counts when the core is active. */ + INFO_MIN_MULTIPLIER, /*!< Minimum CPU:FSB ratio for this CPU, + multiplied by 100. */ INFO_CUR_MULTIPLIER, /*!< Current CPU:FSB ratio, multiplied by 100. e.g., a CPU:FSB value of 18.5 reads as - 1850. */ - INFO_MAX_MULTIPLIER, /*!< Maxumum CPU:FSB ratio for this CPU, - multiplied by 100 */ - INFO_TEMPERATURE, /*!< The current core temperature in Celsius */ + "1850". */ + INFO_MAX_MULTIPLIER, /*!< Maximum CPU:FSB ratio for this CPU, + multiplied by 100. */ + INFO_TEMPERATURE, /*!< The current core temperature in Celsius. */ INFO_THROTTLING, /*!< 1 if the current logical processor is throttling. 0 if it is running normally. */ + INFO_VOLTAGE, /*!< The current core voltage in Volt, + multiplied by 100. */ + INFO_BCLK, /*!< See \ref INFO_BUS_CLOCK. */ + INFO_BUS_CLOCK, /*!< The main bus clock in MHz, + e.g., FSB/QPI/DMI/HT base clock, + multiplied by 100. */ } cpu_msrinfo_request_t; +/** + * @brief Similar to \ref cpu_rdmsr, but extract a range of bits + * + * @param handle - a handle to the MSR reader driver, as created by + * cpu_msr_driver_open + * @param msr_index - the numeric ID of the MSR you want to read + * @param highbit - the high bit in range, must be inferior to 64 + * @param lowbit - the low bit in range, must be equal or superior to 0 + * @param result - a pointer to a 64-bit integer, where the MSR value is stored + * + * @returns zero if successful, and some negative number on error. + * The error message can be obtained by calling \ref cpuid_error. + * @see cpu_error_t + */ +int cpu_rdmsr_range(struct msr_driver_t* handle, uint32_t msr_index, uint8_t highbit, + uint8_t lowbit, uint64_t* result); + /** * @brief Reads extended CPU information from Model-Specific Registers. * @param handle - a handle to an open MSR driver, @see cpu_msr_driver_open diff --git a/contrib/libcpuid/include/libcpuid/libcpuid_constants.h b/contrib/libcpuid/include/libcpuid/libcpuid_constants.h index 8af4718c906..3ddb6d5e14e 100644 --- a/contrib/libcpuid/include/libcpuid/libcpuid_constants.h +++ b/contrib/libcpuid/include/libcpuid/libcpuid_constants.h @@ -37,8 +37,11 @@ #define CPU_FLAGS_MAX 128 #define MAX_CPUID_LEVEL 32 #define MAX_EXT_CPUID_LEVEL 32 -#define MAX_INTELFN4_LEVEL 4 +#define MAX_INTELFN4_LEVEL 8 #define MAX_INTELFN11_LEVEL 4 +#define MAX_INTELFN12H_LEVEL 4 +#define MAX_INTELFN14H_LEVEL 4 #define CPU_HINTS_MAX 16 +#define SGX_FLAGS_MAX 14 #endif /* __LIBCPUID_CONSTANTS_H__ */ diff --git a/contrib/libcpuid/include/libcpuid/libcpuid_internal.h b/contrib/libcpuid/include/libcpuid/libcpuid_internal.h new file mode 100644 index 00000000000..95528896219 --- /dev/null +++ b/contrib/libcpuid/include/libcpuid/libcpuid_internal.h @@ -0,0 +1,63 @@ +/* + * Copyright 2016 Veselin Georgiev, + * anrieffNOSPAM @ mgail_DOT.com (convert to gmail) + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR + * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES + * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. + * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, + * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT + * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, + * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY + * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF + * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ +#ifndef __LIBCPUID_INTERNAL_H__ +#define __LIBCPUID_INTERNAL_H__ +/* + * This file contains internal undocumented declarations and function prototypes + * for the workings of the internal library infrastructure. + */ + +enum _common_codes_t { + NA = 0, + NO_CODE, +}; + +#define CODE(x) x +#define CODE2(x, y) x = y +enum _amd_code_t { + #include "amd_code_t.h" +}; +typedef enum _amd_code_t amd_code_t; + +enum _intel_code_t { + #include "intel_code_t.h" +}; +typedef enum _intel_code_t intel_code_t; +#undef CODE +#undef CODE2 + +struct internal_id_info_t { + union { + amd_code_t amd; + intel_code_t intel; + } code; + int score; // detection (matchtable) score +}; + +int cpu_ident_internal(struct cpu_raw_data_t* raw, struct cpu_id_t* data, + struct internal_id_info_t* internal); + +#endif /* __LIBCPUID_INTERNAL_H__ */ diff --git a/contrib/libcpuid/include/libcpuid/libcpuid_types.h b/contrib/libcpuid/include/libcpuid/libcpuid_types.h index 6dd18a97724..f1181edf2ee 100644 --- a/contrib/libcpuid/include/libcpuid/libcpuid_types.h +++ b/contrib/libcpuid/include/libcpuid/libcpuid_types.h @@ -32,6 +32,37 @@ #ifndef __LIBCPUID_TYPES_H__ #define __LIBCPUID_TYPES_H__ +//#ifdef HAVE_CONFIG_H // CLICKHOUSE PATCH +# include "config.h" +//#endif // CLICKHOUSE PATCH + +#if 1 // CLICKHOUSE PATCH +//#if defined(HAVE_STDINT_H) // CLICKHOUSE PATCH # include +#else +/* we have to provide our own: */ +# if !defined(HAVE_INT32_T) && !defined(__int32_t_defined) +typedef int int32_t; +# endif + +# if !defined(HAVE_UINT32_T) && !defined(__uint32_t_defined) +typedef unsigned uint32_t; +# endif + +typedef signed char int8_t; +typedef unsigned char uint8_t; +typedef signed short int16_t; +typedef unsigned short uint16_t; +#if (defined _MSC_VER) && (_MSC_VER <= 1300) + /* MSVC 6.0: no long longs ... */ + typedef signed __int64 int64_t; + typedef unsigned __int64 uint64_t; +#else + /* all other sane compilers: */ + typedef signed long long int64_t; + typedef unsigned long long uint64_t; +#endif + +#endif #endif /* __LIBCPUID_TYPES_H__ */ diff --git a/contrib/libcpuid/include/libcpuid/libcpuid_util.c b/contrib/libcpuid/include/libcpuid/libcpuid_util.c index 36e83c84b4a..ea6b1b8dfb4 100644 --- a/contrib/libcpuid/include/libcpuid/libcpuid_util.c +++ b/contrib/libcpuid/include/libcpuid/libcpuid_util.c @@ -38,7 +38,7 @@ void match_features(const struct feature_map_t* matchtable, int count, uint32_t { int i; for (i = 0; i < count; i++) - if (reg & (1U << matchtable[i].bit)) + if (reg & (1u << matchtable[i].bit)) data->flags[matchtable[i].feature] = 1; } @@ -78,20 +78,20 @@ static int score(const struct match_entry_t* entry, const struct cpu_id_t* data, int brand_code, int model_code) { int res = 0; - if (entry->family == data->family ) res++; - if (entry->model == data->model ) res++; - if (entry->stepping == data->stepping ) res++; - if (entry->ext_family == data->ext_family) res++; - if (entry->ext_model == data->ext_model ) res++; - if (entry->ncores == data->num_cores ) res++; - if (entry->l2cache == data->l2_cache ) res++; - if (entry->l3cache == data->l3_cache ) res++; - if (entry->brand_code == brand_code ) res++; - if (entry->model_code == model_code ) res++; + if (entry->family == data->family ) res += 2; + if (entry->model == data->model ) res += 2; + if (entry->stepping == data->stepping ) res += 2; + if (entry->ext_family == data->ext_family) res += 2; + if (entry->ext_model == data->ext_model ) res += 2; + if (entry->ncores == data->num_cores ) res += 2; + if (entry->l2cache == data->l2_cache ) res += 1; + if (entry->l3cache == data->l3_cache ) res += 1; + if (entry->brand_code == brand_code ) res += 2; + if (entry->model_code == model_code ) res += 2; return res; } -void match_cpu_codename(const struct match_entry_t* matchtable, int count, +int match_cpu_codename(const struct match_entry_t* matchtable, int count, struct cpu_id_t* data, int brand_code, int model_code) { int bestscore = -1; @@ -112,6 +112,7 @@ void match_cpu_codename(const struct match_entry_t* matchtable, int count, } } strcpy(data->cpu_codename, matchtable[bestindex].name); + return bestscore; } void generic_get_cpu_list(const struct match_entry_t* matchtable, int count, @@ -129,7 +130,11 @@ void generic_get_cpu_list(const struct match_entry_t* matchtable, int count, break; } if (!good) continue; +#if defined(_MSC_VER) + list->names[n++] = _strdup(matchtable[i].name); +#else list->names[n++] = strdup(matchtable[i].name); +#endif } list->num_entries = n; } diff --git a/contrib/libcpuid/include/libcpuid/libcpuid_util.h b/contrib/libcpuid/include/libcpuid/libcpuid_util.h index 34e1efe960a..22becea26f6 100644 --- a/contrib/libcpuid/include/libcpuid/libcpuid_util.h +++ b/contrib/libcpuid/include/libcpuid/libcpuid_util.h @@ -42,7 +42,8 @@ struct match_entry_t { char name[32]; }; -void match_cpu_codename(const struct match_entry_t* matchtable, int count, +// returns the match score: +int match_cpu_codename(const struct match_entry_t* matchtable, int count, struct cpu_id_t* data, int brand_code, int model_code); void warnf(const char* format, ...) diff --git a/contrib/libcpuid/include/libcpuid/msrdriver.c b/contrib/libcpuid/include/libcpuid/msrdriver.c new file mode 100644 index 00000000000..8f9d7ed0ca8 --- /dev/null +++ b/contrib/libcpuid/include/libcpuid/msrdriver.c @@ -0,0 +1,593 @@ +/* + * Copyright 2009 Veselin Georgiev, + * anrieffNOSPAM @ mgail_DOT.com (convert to gmail) + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR + * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES + * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. + * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, + * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT + * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, + * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY + * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF + * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +/** + * @File msrdriver.c + * @Brief Contains the binary images of the x86 and x64 MSR drivers for Windows + * @Date 2009-09-29 + * + * The driver is courtesy of Nick 'Bombera' Gabareff, and its source is actually + * available, see the contrib/ dir. + * + * However, for simplicity, here we just include the images of the compiled .SYS + * files. + * They are extracted to the filesystem on demand and loaded in the kernel + * by the cpu_msr_driver_open() function + */ +#ifdef _WIN32 +#include "asm-bits.h" +//begin { +int cc_x86driver_code_size = 4608; +uint8_t cc_x86driver_code[4608] = { + 0x4d,0x5a,0x90,0x00,0x03,0x00,0x00,0x00,0x04,0x00,0x00,0x00,0xff,0xff,0x00,0x00,0xb8,0x00, + 0x00,0x00,0x00,0x00,0x00,0x00,0x40,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, + 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, + 0x00,0x00,0x00,0x00,0x00,0x00,0xc8,0x00,0x00,0x00,0x0e,0x1f,0xba,0x0e,0x00,0xb4,0x09,0xcd, + 0x21,0xb8,0x01,0x4c,0xcd,0x21,0x54,0x68,0x69,0x73,0x20,0x70,0x72,0x6f,0x67,0x72,0x61,0x6d, + 0x20,0x63,0x61,0x6e,0x6e,0x6f,0x74,0x20,0x62,0x65,0x20,0x72,0x75,0x6e,0x20,0x69,0x6e,0x20, + 0x44,0x4f,0x53,0x20,0x6d,0x6f,0x64,0x65,0x2e,0x0d,0x0d,0x0a,0x24,0x00,0x00,0x00,0x00,0x00, + 0x00,0x00,0x9f,0x99,0x48,0xdf,0xdb,0xf8,0x26,0x8c,0xdb,0xf8,0x26,0x8c,0xdb,0xf8,0x26,0x8c, + 0xdb,0xf8,0x27,0x8c,0xdd,0xf8,0x26,0x8c,0x21,0xdb,0x3f,0x8c,0xd8,0xf8,0x26,0x8c,0xfc,0x3e, + 0x57,0x8c,0xda,0xf8,0x26,0x8c,0xfc,0x3e,0x5a,0x8c,0xda,0xf8,0x26,0x8c,0xfc,0x3e,0x5e,0x8c, + 0xda,0xf8,0x26,0x8c,0x52,0x69,0x63,0x68,0xdb,0xf8,0x26,0x8c,0x00,0x00,0x00,0x00,0x00,0x00, + 0x00,0x00,0x50,0x45,0x00,0x00,0x4c,0x01,0x07,0x00,0x12,0x9b,0x9b,0x4a,0x00,0x00,0x00,0x00, + 0x00,0x00,0x00,0x00,0xe0,0x00,0x02,0x21,0x0b,0x01,0x08,0x00,0x00,0x06,0x00,0x00,0x00,0x0a, + 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x40,0x00,0x00,0x00,0x10,0x00,0x00,0x00,0x20,0x00,0x00, + 0x00,0x00,0x01,0x00,0x00,0x10,0x00,0x00,0x00,0x02,0x00,0x00,0x04,0x00,0x00,0x00,0x00,0x00, + 0x00,0x00,0x04,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x80,0x00,0x00,0x00,0x04,0x00,0x00, + 0xa9,0xd1,0x00,0x00,0x01,0x00,0x00,0x04,0x00,0x00,0x10,0x00,0x00,0x10,0x00,0x00,0x00,0x00, + 0x10,0x00,0x00,0x10,0x00,0x00,0x00,0x00,0x00,0x00,0x10,0x00,0x00,0x00,0x00,0x00,0x00,0x00, + 0x00,0x00,0x00,0x00,0x00,0x50,0x00,0x00,0x28,0x00,0x00,0x00,0x00,0x60,0x00,0x00,0xc0,0x03, + 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, + 0x00,0x70,0x00,0x00,0x30,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, + 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, + 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, + 0x00,0x00,0x00,0x20,0x00,0x00,0x1c,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, + 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x2e,0x74, + 0x65,0x78,0x74,0x00,0x00,0x00,0xa3,0x00,0x00,0x00,0x00,0x10,0x00,0x00,0x00,0x02,0x00,0x00, + 0x00,0x04,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x20,0x00, + 0x00,0x68,0x2e,0x72,0x64,0x61,0x74,0x61,0x00,0x00,0x62,0x00,0x00,0x00,0x00,0x20,0x00,0x00, + 0x00,0x02,0x00,0x00,0x00,0x06,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, + 0x00,0x00,0x40,0x00,0x00,0x48,0x2e,0x64,0x61,0x74,0x61,0x00,0x00,0x00,0x04,0x00,0x00,0x00, + 0x00,0x30,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, + 0x00,0x00,0x00,0x00,0x00,0x00,0x40,0x00,0x00,0xc8,0x50,0x41,0x47,0x45,0x30,0x44,0x45,0x46, + 0x8c,0x00,0x00,0x00,0x00,0x40,0x00,0x00,0x00,0x02,0x00,0x00,0x00,0x08,0x00,0x00,0x00,0x00, + 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x20,0x00,0x00,0x60,0x49,0x4e,0x49,0x54, + 0x00,0x00,0x00,0x00,0xd4,0x00,0x00,0x00,0x00,0x50,0x00,0x00,0x00,0x02,0x00,0x00,0x00,0x0a, + 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x20,0x00,0x00,0xe2, + 0x2e,0x72,0x73,0x72,0x63,0x00,0x00,0x00,0xc0,0x03,0x00,0x00,0x00,0x60,0x00,0x00,0x00,0x04, + 0x00,0x00,0x00,0x0c,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, + 0x40,0x00,0x00,0x42,0x2e,0x72,0x65,0x6c,0x6f,0x63,0x00,0x00,0x68,0x00,0x00,0x00,0x00,0x70, + 0x00,0x00,0x00,0x02,0x00,0x00,0x00,0x10,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, + 0x00,0x00,0x00,0x00,0x40,0x00,0x00,0x42,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, + 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, + 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, + 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, + 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, + 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, + 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, + 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, + 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, + 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, + 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, + 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, + 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, + 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, + 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, + 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, + 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x8b,0x4c, + 0x24,0x08,0x83,0x61,0x18,0x00,0x83,0x61,0x1c,0x00,0x32,0xd2,0xff,0x15,0x08,0x20,0x01,0x00, + 0x33,0xc0,0xc2,0x08,0x00,0x56,0x8b,0x74,0x24,0x0c,0x8b,0x46,0x60,0x81,0x78,0x0c,0x0c,0xe0, + 0x22,0x00,0x57,0x75,0x3c,0x83,0x78,0x04,0x08,0x72,0x36,0x83,0x78,0x08,0x04,0x75,0x07,0x8b, + 0x46,0x0c,0x8b,0x08,0xeb,0x05,0xb9,0x9c,0x01,0x00,0x00,0x8b,0x7e,0x0c,0x0f,0x32,0x89,0x07, + 0x89,0x57,0x04,0xc7,0x46,0x1c,0x08,0x00,0x00,0x00,0x33,0xff,0x32,0xd2,0x8b,0xce,0xff,0x15, + 0x08,0x20,0x01,0x00,0x8b,0xc7,0x5f,0x5e,0xc2,0x08,0x00,0x83,0x66,0x1c,0x00,0xbf,0x01,0x00, + 0x00,0xc0,0x89,0x7e,0x18,0xeb,0xe1,0x55,0x8b,0xec,0x51,0x51,0x8b,0x45,0x08,0xff,0x70,0x04, + 0xff,0x15,0x04,0x20,0x01,0x00,0x68,0x3c,0x20,0x01,0x00,0x8d,0x45,0xf8,0x50,0xff,0x15,0x00, + 0x20,0x01,0x00,0x8d,0x45,0xf8,0x50,0xff,0x15,0x14,0x20,0x01,0x00,0xc9,0xc2,0x04,0x00,0x00, + 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, + 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, + 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, + 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, + 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, + 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, + 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, + 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, + 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, + 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, + 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, + 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, + 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, + 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, + 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, + 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, + 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, + 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, + 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, + 0x00,0x00,0x00,0x00,0x00,0x00,0x5c,0x50,0x00,0x00,0x74,0x50,0x00,0x00,0x86,0x50,0x00,0x00, + 0x9c,0x50,0x00,0x00,0xb4,0x50,0x00,0x00,0x44,0x50,0x00,0x00,0x00,0x00,0x00,0x00,0x5c,0x00, + 0x44,0x00,0x65,0x00,0x76,0x00,0x69,0x00,0x63,0x00,0x65,0x00,0x5c,0x00,0x54,0x00,0x6d,0x00, + 0x70,0x00,0x52,0x00,0x64,0x00,0x72,0x00,0x00,0x00,0x00,0x00,0x5c,0x00,0x44,0x00,0x6f,0x00, + 0x73,0x00,0x44,0x00,0x65,0x00,0x76,0x00,0x69,0x00,0x63,0x00,0x65,0x00,0x73,0x00,0x5c,0x00, + 0x54,0x00,0x6d,0x00,0x70,0x00,0x52,0x00,0x64,0x00,0x72,0x00,0x00,0x00,0x00,0x00,0x00,0x00, + 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, + 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, + 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, + 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, + 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, + 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, + 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, + 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, + 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, + 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, + 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, + 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, + 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, + 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, + 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, + 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, + 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, + 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, + 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, + 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, + 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, + 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, + 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x55,0x8b,0xec,0x83, + 0xec,0x14,0x56,0x8b,0x35,0x00,0x20,0x01,0x00,0x57,0x68,0x1c,0x20,0x01,0x00,0x8d,0x45,0xf4, + 0x50,0xff,0xd6,0x8b,0x7d,0x08,0x8d,0x45,0xfc,0x50,0x6a,0x00,0x6a,0x00,0x6a,0x22,0x8d,0x45, + 0xf4,0x50,0x6a,0x04,0x57,0xff,0x15,0x10,0x20,0x01,0x00,0x85,0xc0,0x75,0x4f,0x68,0x3c,0x20, + 0x01,0x00,0x8d,0x45,0xec,0x50,0xff,0xd6,0x8d,0x45,0xf4,0x50,0x8d,0x45,0xec,0x50,0xff,0x15, + 0x0c,0x20,0x01,0x00,0x8b,0xf0,0x85,0xf6,0x74,0x0d,0xff,0x75,0xfc,0xff,0x15,0x04,0x20,0x01, + 0x00,0x8b,0xc6,0xeb,0x23,0x8b,0x45,0xfc,0xa3,0x00,0x30,0x01,0x00,0xb8,0x00,0x10,0x01,0x00, + 0x89,0x47,0x38,0x89,0x47,0x40,0xc7,0x47,0x34,0x75,0x10,0x01,0x00,0xc7,0x47,0x70,0x19,0x10, + 0x01,0x00,0x33,0xc0,0x5f,0x5e,0xc9,0xc2,0x08,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, + 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, + 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, + 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, + 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, + 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, + 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, + 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, + 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, + 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, + 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, + 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, + 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, + 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, + 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, + 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, + 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, + 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, + 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, + 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, + 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, + 0x00,0x00,0x00,0x00,0x28,0x50,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xc6,0x50, + 0x00,0x00,0x00,0x20,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, + 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x5c,0x50,0x00,0x00,0x74,0x50,0x00,0x00,0x86,0x50, + 0x00,0x00,0x9c,0x50,0x00,0x00,0xb4,0x50,0x00,0x00,0x44,0x50,0x00,0x00,0x00,0x00,0x00,0x00, + 0x4b,0x01,0x49,0x6f,0x44,0x65,0x6c,0x65,0x74,0x65,0x53,0x79,0x6d,0x62,0x6f,0x6c,0x69,0x63, + 0x4c,0x69,0x6e,0x6b,0x00,0x00,0x0b,0x04,0x52,0x74,0x6c,0x49,0x6e,0x69,0x74,0x55,0x6e,0x69, + 0x63,0x6f,0x64,0x65,0x53,0x74,0x72,0x69,0x6e,0x67,0x00,0x00,0x49,0x01,0x49,0x6f,0x44,0x65, + 0x6c,0x65,0x74,0x65,0x44,0x65,0x76,0x69,0x63,0x65,0x00,0x00,0xda,0x01,0x49,0x6f,0x66,0x43, + 0x6f,0x6d,0x70,0x6c,0x65,0x74,0x65,0x52,0x65,0x71,0x75,0x65,0x73,0x74,0x00,0x00,0x41,0x01, + 0x49,0x6f,0x43,0x72,0x65,0x61,0x74,0x65,0x53,0x79,0x6d,0x62,0x6f,0x6c,0x69,0x63,0x4c,0x69, + 0x6e,0x6b,0x00,0x00,0x38,0x01,0x49,0x6f,0x43,0x72,0x65,0x61,0x74,0x65,0x44,0x65,0x76,0x69, + 0x63,0x65,0x00,0x00,0x6e,0x74,0x6f,0x73,0x6b,0x72,0x6e,0x6c,0x2e,0x65,0x78,0x65,0x00,0x00, + 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, + 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, + 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, + 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, + 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, + 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, + 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, + 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, + 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, + 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, + 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, + 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, + 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, + 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, + 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, + 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, + 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, + 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x01,0x00,0x10,0x00,0x00,0x00,0x18,0x00,0x00,0x80, + 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x01,0x00,0x01,0x00, + 0x00,0x00,0x30,0x00,0x00,0x80,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, + 0x00,0x00,0x01,0x00,0x09,0x04,0x00,0x00,0x48,0x00,0x00,0x00,0x60,0x60,0x00,0x00,0x5c,0x03, + 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, + 0x5c,0x03,0x34,0x00,0x00,0x00,0x56,0x00,0x53,0x00,0x5f,0x00,0x56,0x00,0x45,0x00,0x52,0x00, + 0x53,0x00,0x49,0x00,0x4f,0x00,0x4e,0x00,0x5f,0x00,0x49,0x00,0x4e,0x00,0x46,0x00,0x4f,0x00, + 0x00,0x00,0x00,0x00,0xbd,0x04,0xef,0xfe,0x00,0x00,0x01,0x00,0x00,0x00,0x01,0x00,0x01,0x00, + 0x00,0x00,0x00,0x00,0x01,0x00,0x01,0x00,0x00,0x00,0x17,0x00,0x00,0x00,0x00,0x00,0x00,0x00, + 0x04,0x00,0x04,0x00,0x03,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, + 0x00,0x00,0xba,0x02,0x00,0x00,0x01,0x00,0x53,0x00,0x74,0x00,0x72,0x00,0x69,0x00,0x6e,0x00, + 0x67,0x00,0x46,0x00,0x69,0x00,0x6c,0x00,0x65,0x00,0x49,0x00,0x6e,0x00,0x66,0x00,0x6f,0x00, + 0x00,0x00,0x96,0x02,0x00,0x00,0x01,0x00,0x30,0x00,0x34,0x00,0x30,0x00,0x39,0x00,0x30,0x00, + 0x34,0x00,0x62,0x00,0x30,0x00,0x00,0x00,0x58,0x00,0x20,0x00,0x01,0x00,0x43,0x00,0x6f,0x00, + 0x6d,0x00,0x6d,0x00,0x65,0x00,0x6e,0x00,0x74,0x00,0x73,0x00,0x00,0x00,0x4d,0x00,0x53,0x00, + 0x52,0x00,0x20,0x00,0x72,0x00,0x65,0x00,0x61,0x00,0x64,0x00,0x65,0x00,0x72,0x00,0x20,0x00, + 0x33,0x00,0x32,0x00,0x2d,0x00,0x62,0x00,0x69,0x00,0x74,0x00,0x20,0x00,0x6b,0x00,0x65,0x00, + 0x72,0x00,0x6e,0x00,0x65,0x00,0x6c,0x00,0x20,0x00,0x64,0x00,0x72,0x00,0x69,0x00,0x76,0x00, + 0x65,0x00,0x72,0x00,0x00,0x00,0x42,0x00,0x11,0x00,0x01,0x00,0x43,0x00,0x6f,0x00,0x6d,0x00, + 0x70,0x00,0x61,0x00,0x6e,0x00,0x79,0x00,0x4e,0x00,0x61,0x00,0x6d,0x00,0x65,0x00,0x00,0x00, + 0x00,0x00,0x49,0x00,0x72,0x00,0x6f,0x00,0x6e,0x00,0x20,0x00,0x53,0x00,0x74,0x00,0x65,0x00, + 0x65,0x00,0x64,0x00,0x73,0x00,0x20,0x00,0x49,0x00,0x6e,0x00,0x63,0x00,0x2e,0x00,0x00,0x00, + 0x00,0x00,0x60,0x00,0x1c,0x00,0x01,0x00,0x46,0x00,0x69,0x00,0x6c,0x00,0x65,0x00,0x44,0x00, + 0x65,0x00,0x73,0x00,0x63,0x00,0x72,0x00,0x69,0x00,0x70,0x00,0x74,0x00,0x69,0x00,0x6f,0x00, + 0x6e,0x00,0x00,0x00,0x00,0x00,0x54,0x00,0x6d,0x00,0x70,0x00,0x52,0x00,0x64,0x00,0x72,0x00, + 0x20,0x00,0x33,0x00,0x32,0x00,0x2d,0x00,0x62,0x00,0x69,0x00,0x74,0x00,0x20,0x00,0x4b,0x00, + 0x65,0x00,0x72,0x00,0x6e,0x00,0x65,0x00,0x6c,0x00,0x20,0x00,0x4d,0x00,0x6f,0x00,0x64,0x00, + 0x75,0x00,0x6c,0x00,0x65,0x00,0x00,0x00,0x36,0x00,0x0b,0x00,0x01,0x00,0x46,0x00,0x69,0x00, + 0x6c,0x00,0x65,0x00,0x56,0x00,0x65,0x00,0x72,0x00,0x73,0x00,0x69,0x00,0x6f,0x00,0x6e,0x00, + 0x00,0x00,0x00,0x00,0x31,0x00,0x2c,0x00,0x20,0x00,0x30,0x00,0x2c,0x00,0x20,0x00,0x30,0x00, + 0x2c,0x00,0x20,0x00,0x31,0x00,0x00,0x00,0x00,0x00,0x2e,0x00,0x07,0x00,0x01,0x00,0x49,0x00, + 0x6e,0x00,0x74,0x00,0x65,0x00,0x72,0x00,0x6e,0x00,0x61,0x00,0x6c,0x00,0x4e,0x00,0x61,0x00, + 0x6d,0x00,0x65,0x00,0x00,0x00,0x54,0x00,0x6d,0x00,0x70,0x00,0x52,0x00,0x64,0x00,0x72,0x00, + 0x00,0x00,0x00,0x00,0x4a,0x00,0x13,0x00,0x01,0x00,0x4c,0x00,0x65,0x00,0x67,0x00,0x61,0x00, + 0x6c,0x00,0x43,0x00,0x6f,0x00,0x70,0x00,0x79,0x00,0x72,0x00,0x69,0x00,0x67,0x00,0x68,0x00, + 0x74,0x00,0x00,0x00,0x4e,0x00,0x69,0x00,0x63,0x00,0x6b,0x00,0x20,0x00,0x47,0x00,0x61,0x00, + 0x62,0x00,0x61,0x00,0x72,0x00,0x65,0x00,0x76,0x00,0x20,0x00,0x27,0x00,0x32,0x00,0x30,0x00, + 0x30,0x00,0x39,0x00,0x00,0x00,0x00,0x00,0x3e,0x00,0x0b,0x00,0x01,0x00,0x4f,0x00,0x72,0x00, + 0x69,0x00,0x67,0x00,0x69,0x00,0x6e,0x00,0x61,0x00,0x6c,0x00,0x46,0x00,0x69,0x00,0x6c,0x00, + 0x65,0x00,0x6e,0x00,0x61,0x00,0x6d,0x00,0x65,0x00,0x00,0x00,0x54,0x00,0x6d,0x00,0x70,0x00, + 0x52,0x00,0x64,0x00,0x72,0x00,0x2e,0x00,0x73,0x00,0x79,0x00,0x73,0x00,0x00,0x00,0x00,0x00, + 0x54,0x00,0x1a,0x00,0x01,0x00,0x50,0x00,0x72,0x00,0x6f,0x00,0x64,0x00,0x75,0x00,0x63,0x00, + 0x74,0x00,0x4e,0x00,0x61,0x00,0x6d,0x00,0x65,0x00,0x00,0x00,0x00,0x00,0x43,0x00,0x6f,0x00, + 0x72,0x00,0x65,0x00,0x20,0x00,0x32,0x00,0x20,0x00,0x54,0x00,0x65,0x00,0x6d,0x00,0x70,0x00, + 0x65,0x00,0x72,0x00,0x61,0x00,0x74,0x00,0x75,0x00,0x72,0x00,0x65,0x00,0x20,0x00,0x52,0x00, + 0x65,0x00,0x61,0x00,0x64,0x00,0x65,0x00,0x72,0x00,0x00,0x00,0x3a,0x00,0x0b,0x00,0x01,0x00, + 0x50,0x00,0x72,0x00,0x6f,0x00,0x64,0x00,0x75,0x00,0x63,0x00,0x74,0x00,0x56,0x00,0x65,0x00, + 0x72,0x00,0x73,0x00,0x69,0x00,0x6f,0x00,0x6e,0x00,0x00,0x00,0x31,0x00,0x2c,0x00,0x20,0x00, + 0x30,0x00,0x2c,0x00,0x20,0x00,0x30,0x00,0x2c,0x00,0x20,0x00,0x31,0x00,0x00,0x00,0x00,0x00, + 0x44,0x00,0x00,0x00,0x01,0x00,0x56,0x00,0x61,0x00,0x72,0x00,0x46,0x00,0x69,0x00,0x6c,0x00, + 0x65,0x00,0x49,0x00,0x6e,0x00,0x66,0x00,0x6f,0x00,0x00,0x00,0x00,0x00,0x24,0x00,0x04,0x00, + 0x00,0x00,0x54,0x00,0x72,0x00,0x61,0x00,0x6e,0x00,0x73,0x00,0x6c,0x00,0x61,0x00,0x74,0x00, + 0x69,0x00,0x6f,0x00,0x6e,0x00,0x00,0x00,0x00,0x00,0x09,0x04,0xb0,0x04,0x00,0x00,0x00,0x00, + 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, + 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, + 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, + 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x10,0x00,0x00,0x14,0x00,0x00,0x00, + 0x10,0x30,0x5c,0x30,0x82,0x30,0x87,0x30,0x91,0x30,0x9b,0x30,0x00,0x40,0x00,0x00,0x1c,0x00, + 0x00,0x00,0x09,0x30,0x0f,0x30,0x2f,0x30,0x38,0x30,0x4c,0x30,0x5b,0x30,0x67,0x30,0x6c,0x30, + 0x79,0x30,0x80,0x30,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, + 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, + 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, + 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, + 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, + 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, + 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, + 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, + 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, + 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, + 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, + 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, + 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, + 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, + 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, + 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, + 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, + 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, + 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, + 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, + 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, + 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, + 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, + 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, + 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, + 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +}; +int cc_x64driver_code_size = 5120; +uint8_t cc_x64driver_code[5120] = { + 0x4d,0x5a,0x90,0x00,0x03,0x00,0x00,0x00,0x04,0x00,0x00,0x00,0xff,0xff,0x00,0x00,0xb8,0x00, + 0x00,0x00,0x00,0x00,0x00,0x00,0x40,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, + 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, + 0x00,0x00,0x00,0x00,0x00,0x00,0xd0,0x00,0x00,0x00,0x0e,0x1f,0xba,0x0e,0x00,0xb4,0x09,0xcd, + 0x21,0xb8,0x01,0x4c,0xcd,0x21,0x54,0x68,0x69,0x73,0x20,0x70,0x72,0x6f,0x67,0x72,0x61,0x6d, + 0x20,0x63,0x61,0x6e,0x6e,0x6f,0x74,0x20,0x62,0x65,0x20,0x72,0x75,0x6e,0x20,0x69,0x6e,0x20, + 0x44,0x4f,0x53,0x20,0x6d,0x6f,0x64,0x65,0x2e,0x0d,0x0d,0x0a,0x24,0x00,0x00,0x00,0x00,0x00, + 0x00,0x00,0xb7,0x04,0xa8,0xc2,0xf3,0x65,0xc6,0x91,0xf3,0x65,0xc6,0x91,0xf3,0x65,0xc6,0x91, + 0xf3,0x65,0xc7,0x91,0xf4,0x65,0xc6,0x91,0x85,0xf8,0xbd,0x91,0xf0,0x65,0xc6,0x91,0x85,0xf8, + 0xab,0x91,0xf0,0x65,0xc6,0x91,0x30,0x6a,0x98,0x91,0xf2,0x65,0xc6,0x91,0x85,0xf8,0xbe,0x91, + 0xf2,0x65,0xc6,0x91,0x52,0x69,0x63,0x68,0xf3,0x65,0xc6,0x91,0x00,0x00,0x00,0x00,0x00,0x00, + 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x50,0x45,0x00,0x00,0x64,0x86,0x07,0x00, + 0x41,0xc8,0x6d,0x49,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xf0,0x00,0x22,0x00,0x0b,0x02, + 0x08,0x00,0x00,0x06,0x00,0x00,0x00,0x0a,0x00,0x00,0x00,0x00,0x00,0x00,0x10,0x60,0x00,0x00, + 0x00,0x10,0x00,0x00,0x00,0x00,0x01,0x00,0x00,0x00,0x00,0x00,0x00,0x10,0x00,0x00,0x00,0x02, + 0x00,0x00,0x05,0x00,0x02,0x00,0x05,0x00,0x02,0x00,0x05,0x00,0x02,0x00,0x00,0x00,0x00,0x00, + 0x00,0x80,0x00,0x00,0x00,0x04,0x00,0x00,0x79,0x44,0x00,0x00,0x01,0x00,0x00,0x00,0x00,0x00, + 0x04,0x00,0x00,0x00,0x00,0x00,0x00,0x10,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x10,0x00, + 0x00,0x00,0x00,0x00,0x00,0x10,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x10,0x00, + 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x6c,0x60,0x00,0x00,0x28,0x00,0x00,0x00, + 0x00,0x70,0x00,0x00,0xc0,0x03,0x00,0x00,0x00,0x40,0x00,0x00,0x48,0x00,0x00,0x00,0x00,0x00, + 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x40,0x20,0x00,0x00, + 0x1c,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, + 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, + 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x20,0x00,0x00,0x38,0x00,0x00,0x00,0x00,0x00, + 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, + 0x00,0x00,0x00,0x00,0x2e,0x74,0x65,0x78,0x74,0x00,0x00,0x00,0x26,0x01,0x00,0x00,0x00,0x10, + 0x00,0x00,0x00,0x02,0x00,0x00,0x00,0x04,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, + 0x00,0x00,0x00,0x00,0x20,0x00,0x00,0x68,0x2e,0x72,0x64,0x61,0x74,0x61,0x00,0x00,0xf0,0x00, + 0x00,0x00,0x00,0x20,0x00,0x00,0x00,0x02,0x00,0x00,0x00,0x06,0x00,0x00,0x00,0x00,0x00,0x00, + 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x40,0x00,0x00,0x48,0x2e,0x64,0x61,0x74,0x61,0x00, + 0x00,0x00,0x18,0x01,0x00,0x00,0x00,0x30,0x00,0x00,0x00,0x02,0x00,0x00,0x00,0x08,0x00,0x00, + 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x40,0x00,0x00,0xc8,0x2e,0x70, + 0x64,0x61,0x74,0x61,0x00,0x00,0x48,0x00,0x00,0x00,0x00,0x40,0x00,0x00,0x00,0x02,0x00,0x00, + 0x00,0x0a,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x40,0x00, + 0x00,0x48,0x50,0x41,0x47,0x45,0x30,0x44,0x45,0x46,0x4e,0x01,0x00,0x00,0x00,0x50,0x00,0x00, + 0x00,0x02,0x00,0x00,0x00,0x0c,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, + 0x00,0x00,0x20,0x00,0x00,0x60,0x49,0x4e,0x49,0x54,0x00,0x00,0x00,0x00,0x60,0x01,0x00,0x00, + 0x00,0x60,0x00,0x00,0x00,0x02,0x00,0x00,0x00,0x0e,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, + 0x00,0x00,0x00,0x00,0x00,0x00,0x20,0x00,0x00,0xe2,0x2e,0x72,0x73,0x72,0x63,0x00,0x00,0x00, + 0xc0,0x03,0x00,0x00,0x00,0x70,0x00,0x00,0x00,0x04,0x00,0x00,0x00,0x10,0x00,0x00,0x00,0x00, + 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x40,0x00,0x00,0x42,0x00,0x00,0x00,0x00, + 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, + 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, + 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, + 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, + 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, + 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, + 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, + 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, + 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, + 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, + 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, + 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, + 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, + 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, + 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, + 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x48,0x83,0xec,0x28, + 0x33,0xc9,0x48,0x8b,0xc2,0x89,0x4a,0x30,0x48,0x89,0x4a,0x38,0x33,0xd2,0x48,0x8b,0xc8,0xff, + 0x15,0xfd,0x0f,0x00,0x00,0x33,0xc0,0x48,0x83,0xc4,0x28,0xc3,0xcc,0xcc,0xcc,0xcc,0xcc,0xcc, + 0xcc,0xcc,0xcc,0xcc,0xcc,0xcc,0xcc,0xcc,0x48,0x83,0xec,0x28,0x48,0x8b,0x82,0xb8,0x00,0x00, + 0x00,0x4c,0x8b,0xca,0x81,0x78,0x18,0x0c,0xe0,0x22,0x00,0x75,0x43,0x83,0x78,0x08,0x08,0x72, + 0x3d,0x83,0x78,0x10,0x04,0x75,0x08,0x48,0x8b,0x42,0x18,0x8b,0x08,0xeb,0x05,0xb9,0x9c,0x01, + 0x00,0x00,0x4c,0x8b,0x42,0x18,0x0f,0x32,0x48,0xc1,0xe2,0x20,0x49,0x8b,0xc9,0x48,0x0b,0xc2, + 0x33,0xd2,0x49,0x89,0x00,0x49,0xc7,0x41,0x38,0x08,0x00,0x00,0x00,0xff,0x15,0x95,0x0f,0x00, + 0x00,0x33,0xc0,0x48,0x83,0xc4,0x28,0xc3,0xc7,0x42,0x30,0x01,0x00,0x00,0xc0,0x48,0xc7,0x42, + 0x38,0x00,0x00,0x00,0x00,0x49,0x8b,0xc9,0x33,0xd2,0xff,0x15,0x74,0x0f,0x00,0x00,0xb8,0x01, + 0x00,0x00,0xc0,0x48,0x83,0xc4,0x28,0xc3,0xcc,0xcc,0xcc,0xcc,0xcc,0xcc,0xcc,0xcc,0xcc,0xcc, + 0xcc,0xcc,0xcc,0xcc,0xcc,0xcc,0xcc,0xcc,0x48,0x83,0xec,0x38,0x48,0x8b,0x49,0x08,0xff,0x15, + 0x32,0x0f,0x00,0x00,0x48,0x8d,0x15,0x1b,0x00,0x00,0x00,0x48,0x8d,0x4c,0x24,0x20,0xff,0x15, + 0x18,0x0f,0x00,0x00,0x48,0x8d,0x4c,0x24,0x20,0xff,0x15,0x05,0x0f,0x00,0x00,0x48,0x83,0xc4, + 0x38,0xc3,0x5c,0x00,0x44,0x00,0x6f,0x00,0x73,0x00,0x44,0x00,0x65,0x00,0x76,0x00,0x69,0x00, + 0x63,0x00,0x65,0x00,0x73,0x00,0x5c,0x00,0x54,0x00,0x6d,0x00,0x70,0x00,0x52,0x00,0x64,0x00, + 0x72,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, + 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, + 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, + 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, + 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, + 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, + 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, + 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, + 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, + 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, + 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, + 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, + 0x00,0x00,0x00,0x00,0x00,0x00,0xe6,0x60,0x00,0x00,0x00,0x00,0x00,0x00,0xfe,0x60,0x00,0x00, + 0x00,0x00,0x00,0x00,0x16,0x61,0x00,0x00,0x00,0x00,0x00,0x00,0x28,0x61,0x00,0x00,0x00,0x00, + 0x00,0x00,0x40,0x61,0x00,0x00,0x00,0x00,0x00,0x00,0xd0,0x60,0x00,0x00,0x00,0x00,0x00,0x00, + 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, + 0x00,0x00,0x41,0xc8,0x6d,0x49,0x00,0x00,0x00,0x00,0x02,0x00,0x00,0x00,0x49,0x00,0x00,0x00, + 0x5c,0x20,0x00,0x00,0x5c,0x06,0x00,0x00,0x52,0x53,0x44,0x53,0xd9,0x5e,0xab,0x47,0xc4,0xf2, + 0x4f,0x40,0xaa,0xe9,0x90,0x47,0x67,0x30,0xa5,0xfa,0x03,0x00,0x00,0x00,0x44,0x3a,0x5c,0x74, + 0x6d,0x70,0x5c,0x4b,0x65,0x72,0x6e,0x65,0x6c,0x5c,0x6f,0x62,0x6a,0x66,0x72,0x65,0x5f,0x77, + 0x6e,0x65,0x74,0x5f,0x41,0x4d,0x44,0x36,0x34,0x5c,0x61,0x6d,0x64,0x36,0x34,0x5c,0x54,0x6d, + 0x70,0x52,0x64,0x72,0x2e,0x70,0x64,0x62,0x00,0x00,0x00,0x00,0x01,0x04,0x01,0x00,0x04,0x42, + 0x00,0x00,0x01,0x04,0x01,0x00,0x04,0x42,0x00,0x00,0x01,0x04,0x01,0x00,0x04,0x62,0x00,0x00, + 0x21,0x00,0x00,0x00,0x10,0x50,0x00,0x00,0x74,0x50,0x00,0x00,0xe4,0x20,0x00,0x00,0x21,0x08, + 0x02,0x00,0x08,0x74,0x13,0x00,0x10,0x50,0x00,0x00,0x74,0x50,0x00,0x00,0xe4,0x20,0x00,0x00, + 0x01,0x0c,0x03,0x00,0x0c,0x34,0x12,0x00,0x04,0xe2,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, + 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, + 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, + 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, + 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, + 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, + 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, + 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, + 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, + 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, + 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, + 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, + 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, + 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, + 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, + 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, + 0x00,0x01,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, + 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, + 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, + 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, + 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, + 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, + 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, + 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, + 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, + 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, + 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, + 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, + 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, + 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, + 0xcd,0x5d,0x20,0xd2,0x66,0xd4,0xff,0xff,0x32,0xa2,0xdf,0x2d,0x99,0x2b,0x00,0x00,0x00,0x00, + 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, + 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, + 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, + 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, + 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, + 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, + 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, + 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, + 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, + 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, + 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, + 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, + 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, + 0x00,0x00,0x00,0x00,0x10,0x10,0x00,0x00,0x32,0x10,0x00,0x00,0xa8,0x20,0x00,0x00,0x40,0x10, + 0x00,0x00,0xbe,0x10,0x00,0x00,0xb0,0x20,0x00,0x00,0xd0,0x10,0x00,0x00,0x00,0x11,0x00,0x00, + 0xb8,0x20,0x00,0x00,0x10,0x50,0x00,0x00,0x74,0x50,0x00,0x00,0xe4,0x20,0x00,0x00,0x74,0x50, + 0x00,0x00,0xe8,0x50,0x00,0x00,0xd0,0x20,0x00,0x00,0xe8,0x50,0x00,0x00,0xf5,0x50,0x00,0x00, + 0xc0,0x20,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, + 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, + 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, + 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, + 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, + 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, + 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, + 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, + 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, + 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, + 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, + 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, + 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, + 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, + 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, + 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, + 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, + 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, + 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, + 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, + 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, + 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, + 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, + 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, + 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, + 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x48,0x83,0xec,0x78,0x48,0x89,0x9c,0x24, + 0x90,0x00,0x00,0x00,0x48,0x8b,0xd9,0x48,0x8d,0x15,0x0a,0x01,0x00,0x00,0x48,0x8d,0x4c,0x24, + 0x48,0xff,0x15,0xd7,0xcf,0xff,0xff,0x41,0xb9,0x22,0x00,0x00,0x00,0x4c,0x8d,0x5c,0x24,0x40, + 0x4c,0x89,0x5c,0x24,0x30,0x4c,0x8d,0x44,0x24,0x48,0x41,0x8d,0x51,0xe6,0x48,0x8b,0xcb,0xc6, + 0x44,0x24,0x28,0x00,0xc7,0x44,0x24,0x20,0x00,0x00,0x00,0x00,0xff,0x15,0xc0,0xcf,0xff,0xff, + 0x85,0xc0,0x0f,0x85,0x80,0x00,0x00,0x00,0x48,0x8d,0x15,0x91,0x00,0x00,0x00,0x48,0x8d,0x4c, + 0x24,0x58,0x48,0x89,0xbc,0x24,0x98,0x00,0x00,0x00,0xff,0x15,0x86,0xcf,0xff,0xff,0x48,0x8d, + 0x54,0x24,0x48,0x48,0x8d,0x4c,0x24,0x58,0xff,0x15,0x86,0xcf,0xff,0xff,0x85,0xc0,0x8b,0xf8, + 0x74,0x0f,0x48,0x8b,0x4c,0x24,0x40,0xff,0x15,0x6d,0xcf,0xff,0xff,0x8b,0xc7,0xeb,0x39,0x48, + 0x8b,0x44,0x24,0x40,0x48,0x89,0x05,0x5d,0xe0,0xff,0xff,0x48,0x8d,0x05,0x16,0xc0,0xff,0xff, + 0x48,0x89,0x43,0x68,0x48,0x8d,0x05,0x4b,0xbf,0xff,0xff,0x48,0x89,0x43,0x70,0x48,0x89,0x83, + 0x80,0x00,0x00,0x00,0x48,0x8d,0x05,0x69,0xbf,0xff,0xff,0x48,0x89,0x83,0xe0,0x00,0x00,0x00, + 0x33,0xc0,0x48,0x8b,0xbc,0x24,0x98,0x00,0x00,0x00,0x48,0x8b,0x9c,0x24,0x90,0x00,0x00,0x00, + 0x48,0x83,0xc4,0x78,0xc3,0xcc,0xcc,0xcc,0xcc,0xcc,0xcc,0xcc,0xcc,0xcc,0xcc,0xcc,0x5c,0x00, + 0x44,0x00,0x6f,0x00,0x73,0x00,0x44,0x00,0x65,0x00,0x76,0x00,0x69,0x00,0x63,0x00,0x65,0x00, + 0x73,0x00,0x5c,0x00,0x54,0x00,0x6d,0x00,0x70,0x00,0x52,0x00,0x64,0x00,0x72,0x00,0x00,0x00, + 0xcc,0xcc,0xcc,0xcc,0xcc,0xcc,0xcc,0xcc,0xcc,0xcc,0x5c,0x00,0x44,0x00,0x65,0x00,0x76,0x00, + 0x69,0x00,0x63,0x00,0x65,0x00,0x5c,0x00,0x54,0x00,0x6d,0x00,0x70,0x00,0x52,0x00,0x64,0x00, + 0x72,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, + 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, + 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, + 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, + 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, + 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, + 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, + 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, + 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, + 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, + 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, + 0x48,0x8b,0x05,0xf1,0xd0,0xff,0xff,0x49,0xb9,0x32,0xa2,0xdf,0x2d,0x99,0x2b,0x00,0x00,0x48, + 0x85,0xc0,0x74,0x05,0x49,0x3b,0xc1,0x75,0x2f,0x4c,0x8d,0x05,0xd6,0xd0,0xff,0xff,0x48,0xb8, + 0x20,0x03,0x00,0x00,0x80,0xf7,0xff,0xff,0x48,0x8b,0x00,0x49,0x33,0xc0,0x49,0xb8,0xff,0xff, + 0xff,0xff,0xff,0xff,0x00,0x00,0x49,0x23,0xc0,0x49,0x0f,0x44,0xc1,0x48,0x89,0x05,0xae,0xd0, + 0xff,0xff,0x48,0xf7,0xd0,0x48,0x89,0x05,0x9c,0xd0,0xff,0xff,0xe9,0xa7,0xef,0xff,0xff,0xcc, + 0xcc,0xcc,0x98,0x60,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x52,0x61,0x00,0x00, + 0x00,0x20,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, + 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xe6,0x60,0x00,0x00,0x00,0x00,0x00,0x00, + 0xfe,0x60,0x00,0x00,0x00,0x00,0x00,0x00,0x16,0x61,0x00,0x00,0x00,0x00,0x00,0x00,0x28,0x61, + 0x00,0x00,0x00,0x00,0x00,0x00,0x40,0x61,0x00,0x00,0x00,0x00,0x00,0x00,0xd0,0x60,0x00,0x00, + 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xf6,0x01,0x49,0x6f,0x66,0x43, + 0x6f,0x6d,0x70,0x6c,0x65,0x74,0x65,0x52,0x65,0x71,0x75,0x65,0x73,0x74,0x00,0x00,0x61,0x01, + 0x49,0x6f,0x44,0x65,0x6c,0x65,0x74,0x65,0x53,0x79,0x6d,0x62,0x6f,0x6c,0x69,0x63,0x4c,0x69, + 0x6e,0x6b,0x00,0x00,0x3e,0x04,0x52,0x74,0x6c,0x49,0x6e,0x69,0x74,0x55,0x6e,0x69,0x63,0x6f, + 0x64,0x65,0x53,0x74,0x72,0x69,0x6e,0x67,0x00,0x00,0x5f,0x01,0x49,0x6f,0x44,0x65,0x6c,0x65, + 0x74,0x65,0x44,0x65,0x76,0x69,0x63,0x65,0x00,0x00,0x55,0x01,0x49,0x6f,0x43,0x72,0x65,0x61, + 0x74,0x65,0x53,0x79,0x6d,0x62,0x6f,0x6c,0x69,0x63,0x4c,0x69,0x6e,0x6b,0x00,0x00,0x4c,0x01, + 0x49,0x6f,0x43,0x72,0x65,0x61,0x74,0x65,0x44,0x65,0x76,0x69,0x63,0x65,0x00,0x00,0x6e,0x74, + 0x6f,0x73,0x6b,0x72,0x6e,0x6c,0x2e,0x65,0x78,0x65,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, + 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, + 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, + 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, + 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, + 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, + 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, + 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, + 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, + 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, + 0x00,0x00,0x00,0x00,0x00,0x00,0x01,0x00,0x10,0x00,0x00,0x00,0x18,0x00,0x00,0x80,0x00,0x00, + 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x01,0x00,0x01,0x00,0x00,0x00, + 0x30,0x00,0x00,0x80,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, + 0x01,0x00,0x09,0x04,0x00,0x00,0x48,0x00,0x00,0x00,0x60,0x70,0x00,0x00,0x60,0x03,0x00,0x00, + 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x60,0x03, + 0x34,0x00,0x00,0x00,0x56,0x00,0x53,0x00,0x5f,0x00,0x56,0x00,0x45,0x00,0x52,0x00,0x53,0x00, + 0x49,0x00,0x4f,0x00,0x4e,0x00,0x5f,0x00,0x49,0x00,0x4e,0x00,0x46,0x00,0x4f,0x00,0x00,0x00, + 0x00,0x00,0xbd,0x04,0xef,0xfe,0x00,0x00,0x01,0x00,0x00,0x00,0x01,0x00,0x01,0x00,0x00,0x00, + 0x00,0x00,0x01,0x00,0x01,0x00,0x00,0x00,0x17,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x04,0x00, + 0x04,0x00,0x03,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, + 0xbe,0x02,0x00,0x00,0x01,0x00,0x53,0x00,0x74,0x00,0x72,0x00,0x69,0x00,0x6e,0x00,0x67,0x00, + 0x46,0x00,0x69,0x00,0x6c,0x00,0x65,0x00,0x49,0x00,0x6e,0x00,0x66,0x00,0x6f,0x00,0x00,0x00, + 0x9a,0x02,0x00,0x00,0x01,0x00,0x30,0x00,0x34,0x00,0x30,0x00,0x39,0x00,0x30,0x00,0x34,0x00, + 0x62,0x00,0x30,0x00,0x00,0x00,0x58,0x00,0x20,0x00,0x01,0x00,0x43,0x00,0x6f,0x00,0x6d,0x00, + 0x6d,0x00,0x65,0x00,0x6e,0x00,0x74,0x00,0x73,0x00,0x00,0x00,0x4d,0x00,0x53,0x00,0x52,0x00, + 0x20,0x00,0x72,0x00,0x65,0x00,0x61,0x00,0x64,0x00,0x65,0x00,0x72,0x00,0x20,0x00,0x36,0x00, + 0x34,0x00,0x2d,0x00,0x62,0x00,0x69,0x00,0x74,0x00,0x20,0x00,0x6b,0x00,0x65,0x00,0x72,0x00, + 0x6e,0x00,0x65,0x00,0x6c,0x00,0x20,0x00,0x64,0x00,0x72,0x00,0x69,0x00,0x76,0x00,0x65,0x00, + 0x72,0x00,0x00,0x00,0x42,0x00,0x11,0x00,0x01,0x00,0x43,0x00,0x6f,0x00,0x6d,0x00,0x70,0x00, + 0x61,0x00,0x6e,0x00,0x79,0x00,0x4e,0x00,0x61,0x00,0x6d,0x00,0x65,0x00,0x00,0x00,0x00,0x00, + 0x49,0x00,0x72,0x00,0x6f,0x00,0x6e,0x00,0x20,0x00,0x53,0x00,0x74,0x00,0x65,0x00,0x65,0x00, + 0x64,0x00,0x73,0x00,0x20,0x00,0x49,0x00,0x6e,0x00,0x63,0x00,0x2e,0x00,0x00,0x00,0x00,0x00, + 0x60,0x00,0x1c,0x00,0x01,0x00,0x46,0x00,0x69,0x00,0x6c,0x00,0x65,0x00,0x44,0x00,0x65,0x00, + 0x73,0x00,0x63,0x00,0x72,0x00,0x69,0x00,0x70,0x00,0x74,0x00,0x69,0x00,0x6f,0x00,0x6e,0x00, + 0x00,0x00,0x00,0x00,0x54,0x00,0x6d,0x00,0x70,0x00,0x52,0x00,0x64,0x00,0x72,0x00,0x20,0x00, + 0x36,0x00,0x34,0x00,0x2d,0x00,0x62,0x00,0x69,0x00,0x74,0x00,0x20,0x00,0x4b,0x00,0x65,0x00, + 0x72,0x00,0x6e,0x00,0x65,0x00,0x6c,0x00,0x20,0x00,0x4d,0x00,0x6f,0x00,0x64,0x00,0x75,0x00, + 0x6c,0x00,0x65,0x00,0x00,0x00,0x36,0x00,0x0b,0x00,0x01,0x00,0x46,0x00,0x69,0x00,0x6c,0x00, + 0x65,0x00,0x56,0x00,0x65,0x00,0x72,0x00,0x73,0x00,0x69,0x00,0x6f,0x00,0x6e,0x00,0x00,0x00, + 0x00,0x00,0x31,0x00,0x2c,0x00,0x20,0x00,0x30,0x00,0x2c,0x00,0x20,0x00,0x30,0x00,0x2c,0x00, + 0x20,0x00,0x31,0x00,0x00,0x00,0x00,0x00,0x2e,0x00,0x07,0x00,0x01,0x00,0x49,0x00,0x6e,0x00, + 0x74,0x00,0x65,0x00,0x72,0x00,0x6e,0x00,0x61,0x00,0x6c,0x00,0x4e,0x00,0x61,0x00,0x6d,0x00, + 0x65,0x00,0x00,0x00,0x54,0x00,0x6d,0x00,0x70,0x00,0x52,0x00,0x64,0x00,0x72,0x00,0x00,0x00, + 0x00,0x00,0x4a,0x00,0x13,0x00,0x01,0x00,0x4c,0x00,0x65,0x00,0x67,0x00,0x61,0x00,0x6c,0x00, + 0x43,0x00,0x6f,0x00,0x70,0x00,0x79,0x00,0x72,0x00,0x69,0x00,0x67,0x00,0x68,0x00,0x74,0x00, + 0x00,0x00,0x4e,0x00,0x69,0x00,0x63,0x00,0x6b,0x00,0x20,0x00,0x47,0x00,0x61,0x00,0x62,0x00, + 0x61,0x00,0x72,0x00,0x65,0x00,0x76,0x00,0x20,0x00,0x27,0x00,0x32,0x00,0x30,0x00,0x30,0x00, + 0x39,0x00,0x00,0x00,0x00,0x00,0x42,0x00,0x0d,0x00,0x01,0x00,0x4f,0x00,0x72,0x00,0x69,0x00, + 0x67,0x00,0x69,0x00,0x6e,0x00,0x61,0x00,0x6c,0x00,0x46,0x00,0x69,0x00,0x6c,0x00,0x65,0x00, + 0x6e,0x00,0x61,0x00,0x6d,0x00,0x65,0x00,0x00,0x00,0x54,0x00,0x6d,0x00,0x70,0x00,0x52,0x00, + 0x64,0x00,0x72,0x00,0x36,0x00,0x34,0x00,0x2e,0x00,0x73,0x00,0x79,0x00,0x73,0x00,0x00,0x00, + 0x00,0x00,0x54,0x00,0x1a,0x00,0x01,0x00,0x50,0x00,0x72,0x00,0x6f,0x00,0x64,0x00,0x75,0x00, + 0x63,0x00,0x74,0x00,0x4e,0x00,0x61,0x00,0x6d,0x00,0x65,0x00,0x00,0x00,0x00,0x00,0x43,0x00, + 0x6f,0x00,0x72,0x00,0x65,0x00,0x20,0x00,0x32,0x00,0x20,0x00,0x54,0x00,0x65,0x00,0x6d,0x00, + 0x70,0x00,0x65,0x00,0x72,0x00,0x61,0x00,0x74,0x00,0x75,0x00,0x72,0x00,0x65,0x00,0x20,0x00, + 0x52,0x00,0x65,0x00,0x61,0x00,0x64,0x00,0x65,0x00,0x72,0x00,0x00,0x00,0x3a,0x00,0x0b,0x00, + 0x01,0x00,0x50,0x00,0x72,0x00,0x6f,0x00,0x64,0x00,0x75,0x00,0x63,0x00,0x74,0x00,0x56,0x00, + 0x65,0x00,0x72,0x00,0x73,0x00,0x69,0x00,0x6f,0x00,0x6e,0x00,0x00,0x00,0x31,0x00,0x2c,0x00, + 0x20,0x00,0x30,0x00,0x2c,0x00,0x20,0x00,0x30,0x00,0x2c,0x00,0x20,0x00,0x31,0x00,0x00,0x00, + 0x00,0x00,0x44,0x00,0x00,0x00,0x01,0x00,0x56,0x00,0x61,0x00,0x72,0x00,0x46,0x00,0x69,0x00, + 0x6c,0x00,0x65,0x00,0x49,0x00,0x6e,0x00,0x66,0x00,0x6f,0x00,0x00,0x00,0x00,0x00,0x24,0x00, + 0x04,0x00,0x00,0x00,0x54,0x00,0x72,0x00,0x61,0x00,0x6e,0x00,0x73,0x00,0x6c,0x00,0x61,0x00, + 0x74,0x00,0x69,0x00,0x6f,0x00,0x6e,0x00,0x00,0x00,0x00,0x00,0x09,0x04,0xb0,0x04,0x00,0x00, + 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, + 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, + 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, + 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +}; +//} end +#endif // _WIN32 + +int msrdriver_dummy; // a dummy to avoid a linker warning on OS X. diff --git a/contrib/libcpuid/include/libcpuid/rdmsr.c b/contrib/libcpuid/include/libcpuid/rdmsr.c new file mode 100644 index 00000000000..a27e939bba0 --- /dev/null +++ b/contrib/libcpuid/include/libcpuid/rdmsr.c @@ -0,0 +1,922 @@ +/* + * Copyright 2009 Veselin Georgiev, + * anrieffNOSPAM @ mgail_DOT.com (convert to gmail) + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR + * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES + * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. + * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, + * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT + * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, + * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY + * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF + * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ +#define _XOPEN_SOURCE 500 +#include +#include +#include "libcpuid.h" +#include "asm-bits.h" +#include "libcpuid_util.h" +#include "libcpuid_internal.h" +#include "rdtsc.h" + +#if defined (__linux__) || defined (__gnu_linux__) +/* Assuming linux with /dev/cpu/x/msr: */ +#include +#include +#include +#include +#include +#include +struct msr_driver_t { int fd; }; +static int rdmsr_supported(void); +static int load_driver(char *msr_path) +{ + const int file_exists = !access(msr_path, F_OK); + const int file_readable = !access(msr_path, R_OK); + + if (file_exists && file_readable) + return 1; + else if (file_exists && !file_readable) + return 0; + else if (getuid() != 0) + return 0; + else + return !system("modprobe msr 2> /dev/null"); +} + +struct msr_driver_t* cpu_msr_driver_open(void) +{ + return cpu_msr_driver_open_core(0); +} + +struct msr_driver_t* cpu_msr_driver_open_core(unsigned core_num) +{ + char msr[32]; + struct msr_driver_t* handle; + if (core_num >= cpuid_get_total_cpus()) { + set_error(ERR_INVCNB); + return NULL; + } + if (!rdmsr_supported()) { + set_error(ERR_NO_RDMSR); + return NULL; + } + sprintf(msr, "/dev/cpu/%u/msr", core_num); + if(!load_driver(msr)) { + set_error(ERR_NO_DRIVER); + return NULL; + } + int fd = open(msr, O_RDONLY); + if (fd < 0) { + if (errno == EIO) { + set_error(ERR_NO_RDMSR); + return NULL; + } + set_error(ERR_NO_DRIVER); + return NULL; + } + handle = (struct msr_driver_t*) malloc(sizeof(struct msr_driver_t)); + handle->fd = fd; + return handle; +} + +int cpu_rdmsr(struct msr_driver_t* driver, uint32_t msr_index, uint64_t* result) +{ + ssize_t ret; + + if (!driver || driver->fd < 0) + return set_error(ERR_HANDLE); + ret = pread(driver->fd, result, 8, msr_index); + if (ret != 8) + return set_error(ERR_INVMSR); + return 0; +} + +int cpu_msr_driver_close(struct msr_driver_t* drv) +{ + if (drv && drv->fd >= 0) { + close(drv->fd); + free(drv); + } + return 0; +} + +/* #endif defined (__linux__) || defined (__gnu_linux__) */ + +#elif defined (__FreeBSD__) || defined (__DragonFly__) +/* Assuming FreeBSD with /dev/cpuctlX */ +#include +#include +#include +#include +#include + +struct msr_driver_t { int fd; }; +static int rdmsr_supported(void); +static int load_driver(char *msr_path) +{ + const int file_exists = !access(msr_path, F_OK); + const int file_readable = !access(msr_path, R_OK); + + if (file_exists && file_readable) + return 1; + else if (file_exists && !file_readable) + return 0; + else if (getuid() != 0) + return 0; + else + return !system("kldload -n cpuctl 2> /dev/null"); +} + +struct msr_driver_t* cpu_msr_driver_open(void) +{ + return cpu_msr_driver_open_core(0); +} + +struct msr_driver_t* cpu_msr_driver_open_core(unsigned core_num) +{ + char msr[32]; + struct msr_driver_t* handle; + if (core_num >= cpuid_get_total_cpus()) { + set_error(ERR_INVCNB); + return NULL; + } + if (!rdmsr_supported()) { + set_error(ERR_NO_RDMSR); + return NULL; + } + sprintf(msr, "/dev/cpuctl%u", core_num); + if(!load_driver(msr)) { + set_error(ERR_NO_DRIVER); + return NULL; + } + int fd = open(msr, O_RDONLY); + if (fd < 0) { + if (errno == EIO) { + set_error(ERR_NO_RDMSR); + return NULL; + } + set_error(ERR_NO_DRIVER); + return NULL; + } + handle = (struct msr_driver_t*) malloc(sizeof(struct msr_driver_t)); + handle->fd = fd; + return handle; +} + +int cpu_rdmsr(struct msr_driver_t* driver, uint32_t msr_index, uint64_t* result) +{ + cpuctl_msr_args_t args; + args.msr = msr_index; + + if (!driver || driver->fd < 0) + return set_error(ERR_HANDLE); + + if(ioctl(driver->fd, CPUCTL_RDMSR, &args)) + return set_error(ERR_INVMSR); + + *result = args.data; + return 0; +} + +int cpu_msr_driver_close(struct msr_driver_t* drv) +{ + if (drv && drv->fd >= 0) { + close(drv->fd); + free(drv); + } + return 0; +} + +/* #endif defined (__FreeBSD__) || defined (__DragonFly__) */ + +#elif defined (_WIN32) +#include +#include +#include + +extern uint8_t cc_x86driver_code[]; +extern int cc_x86driver_code_size; +extern uint8_t cc_x64driver_code[]; +extern int cc_x64driver_code_size; + +struct msr_driver_t { + char driver_path[MAX_PATH + 1]; + SC_HANDLE scManager; + volatile SC_HANDLE scDriver; + HANDLE hhDriver; + OVERLAPPED ovl; + int errorcode; +}; + +static int rdmsr_supported(void); +static int extract_driver(struct msr_driver_t* driver); +static int load_driver(struct msr_driver_t* driver); + +struct msr_driver_t* cpu_msr_driver_open(void) +{ + struct msr_driver_t* drv; + int status; + if (!rdmsr_supported()) { + set_error(ERR_NO_RDMSR); + return NULL; + } + + drv = (struct msr_driver_t*) malloc(sizeof(struct msr_driver_t)); + if (!drv) { + set_error(ERR_NO_MEM); + return NULL; + } + memset(drv, 0, sizeof(struct msr_driver_t)); + + if (!extract_driver(drv)) { + free(drv); + set_error(ERR_EXTRACT); + return NULL; + } + + status = load_driver(drv); + if (!DeleteFile(drv->driver_path)) + debugf(1, "Deleting temporary driver file failed.\n"); + if (!status) { + set_error(drv->errorcode ? drv->errorcode : ERR_NO_DRIVER); + free(drv); + return NULL; + } + return drv; +} + +struct msr_driver_t* cpu_msr_driver_open_core(unsigned core_num) +{ + warnf("cpu_msr_driver_open_core(): parameter ignored (function is the same as cpu_msr_driver_open)\n"); + return cpu_msr_driver_open(); +} + +typedef BOOL (WINAPI *LPFN_ISWOW64PROCESS) (HANDLE, PBOOL); +static BOOL is_running_x64(void) +{ + BOOL bIsWow64 = FALSE; + + LPFN_ISWOW64PROCESS fnIsWow64Process = (LPFN_ISWOW64PROCESS)GetProcAddress(GetModuleHandle(__TEXT("kernel32")), "IsWow64Process"); + if(NULL != fnIsWow64Process) + fnIsWow64Process(GetCurrentProcess(), &bIsWow64); + return bIsWow64; +} + + +static int extract_driver(struct msr_driver_t* driver) +{ + FILE *f; + if (!GetTempPath(sizeof(driver->driver_path), driver->driver_path)) return 0; + strcat(driver->driver_path, "TmpRdr.sys"); + + f = fopen(driver->driver_path, "wb"); + if (!f) return 0; + if (is_running_x64()) + fwrite(cc_x64driver_code, 1, cc_x64driver_code_size, f); + else + fwrite(cc_x86driver_code, 1, cc_x86driver_code_size, f); + fclose(f); + return 1; +} + +static BOOL wait_for_service_state(SC_HANDLE hService, DWORD dwDesiredState, SERVICE_STATUS *lpsrvStatus){ + BOOL fOK = FALSE; + DWORD dwWaitHint; + + if(hService != NULL){ + while(TRUE){ + fOK = QueryServiceStatus(hService, lpsrvStatus); + if(!fOK) + break; + if(lpsrvStatus->dwCurrentState == dwDesiredState) + break; + + dwWaitHint = lpsrvStatus->dwWaitHint / 10; // Poll 1/10 of the wait hint + if (dwWaitHint < 1000) + dwWaitHint = 1000; // At most once per second + if (dwWaitHint > 10000) + dwWaitHint = 10000; // At least every 10 seconds + Sleep(dwWaitHint); + } + } + + return fOK; +} + +static int load_driver(struct msr_driver_t* drv) +{ + LPTSTR lpszInfo = __TEXT("RDMSR Executor Driver"); + USHORT uLen = 0; + SERVICE_STATUS srvStatus = {0}; + BOOL fRunning = FALSE; + DWORD dwLastError; + LPTSTR lpszDriverServiceName = __TEXT("TmpRdr"); + TCHAR lpszDriverName[] = __TEXT("\\\\.\\Global\\TmpRdr"); + + if((LPVOID)(drv->scManager = OpenSCManager(NULL, NULL, SC_MANAGER_ALL_ACCESS)) != NULL) { + drv->scDriver = CreateService(drv->scManager, lpszDriverServiceName, lpszInfo, SERVICE_ALL_ACCESS, + SERVICE_KERNEL_DRIVER, SERVICE_DEMAND_START, SERVICE_ERROR_NORMAL, + drv->driver_path, NULL, NULL, NULL, NULL, NULL); + if(drv->scDriver == NULL){ + switch(dwLastError = GetLastError()){ + case ERROR_SERVICE_EXISTS: + case ERROR_SERVICE_MARKED_FOR_DELETE:{ + LPQUERY_SERVICE_CONFIG lpqsc; + DWORD dwBytesNeeded; + + drv->scDriver = OpenService(drv->scManager, lpszDriverServiceName, SERVICE_ALL_ACCESS); + if(drv->scDriver == NULL){ + debugf(1, "Error opening service: %d\n", GetLastError()); + break; + } + + QueryServiceConfig(drv->scDriver, NULL, 0, &dwBytesNeeded); + if((dwLastError = GetLastError()) == ERROR_INSUFFICIENT_BUFFER){ + lpqsc = calloc(1, dwBytesNeeded); + if(!QueryServiceConfig(drv->scDriver, lpqsc, dwBytesNeeded, &dwBytesNeeded)){ + free(lpqsc); + debugf(1, "Error query service config(adjusted buffer): %d\n", GetLastError()); + goto clean_up; + } + else{ + free(lpqsc); + } + } + else{ + debugf(1, "Error query service config: %d\n", dwLastError); + goto clean_up; + } + + break; + } + case ERROR_ACCESS_DENIED: + drv->errorcode = ERR_NO_PERMS; + break; + default: + debugf(1, "Create driver service failed: %d\n", dwLastError); + break; + } + } + if(drv->scDriver != NULL){ + if(StartService(drv->scDriver, 0, NULL)){ + if(!wait_for_service_state(drv->scDriver, SERVICE_RUNNING, &srvStatus)){ + debugf(1, "Driver load failed.\n"); + DeleteService(drv->scDriver); + CloseServiceHandle(drv->scManager); + drv->scDriver = NULL; + goto clean_up; + } else { + fRunning = TRUE; + } + } else{ + if((dwLastError = GetLastError()) == ERROR_SERVICE_ALREADY_RUNNING) + fRunning = TRUE; + else{ + debugf(1, "Driver start failed.\n"); + DeleteService(drv->scDriver); + CloseServiceHandle(drv->scManager); + drv->scDriver = NULL; + goto clean_up; + } + + } + if(fRunning) + debugf(1, "Driver already running.\n"); + else + debugf(1, "Driver loaded.\n"); + CloseServiceHandle(drv->scManager); + drv->hhDriver = CreateFile(lpszDriverName, GENERIC_READ | GENERIC_WRITE, FILE_SHARE_READ | FILE_SHARE_WRITE, 0, OPEN_EXISTING, FILE_FLAG_OVERLAPPED, 0); + drv->ovl.hEvent = CreateEvent(NULL, TRUE, FALSE, NULL); + return 1; + } + } else { + debugf(1, "Open SCM failed: %d\n", GetLastError()); + } + +clean_up: + if(drv->scManager != NULL){ + CloseServiceHandle(drv->scManager); + drv->scManager = 0; // pointless + } + if(drv->scDriver != NULL){ + if(!DeleteService(drv->scDriver)) + debugf(1, "Delete driver service failed: %d\n", GetLastError()); + CloseServiceHandle(drv->scDriver); + drv->scDriver = 0; + } + + return 0; +} + +#define FILE_DEVICE_UNKNOWN 0x00000022 +#define IOCTL_UNKNOWN_BASE FILE_DEVICE_UNKNOWN +#define IOCTL_PROCVIEW_RDMSR CTL_CODE(IOCTL_UNKNOWN_BASE, 0x0803, METHOD_BUFFERED, FILE_READ_ACCESS | FILE_WRITE_ACCESS) + +int cpu_rdmsr(struct msr_driver_t* driver, uint32_t msr_index, uint64_t* result) +{ + DWORD dwBytesReturned; + __int64 msrdata; + SERVICE_STATUS srvStatus = {0}; + + if (!driver) + return set_error(ERR_HANDLE); + DeviceIoControl(driver->hhDriver, IOCTL_PROCVIEW_RDMSR, &msr_index, sizeof(int), &msrdata, sizeof(__int64), &dwBytesReturned, &driver->ovl); + GetOverlappedResult(driver->hhDriver, &driver->ovl, &dwBytesReturned, TRUE); + *result = msrdata; + return 0; +} + +int cpu_msr_driver_close(struct msr_driver_t* drv) +{ + SERVICE_STATUS srvStatus = {0}; + if (drv == NULL) return 0; + if(drv->scDriver != NULL){ + if (drv->hhDriver) CancelIo(drv->hhDriver); + if(drv->ovl.hEvent != NULL) + CloseHandle(drv->ovl.hEvent); + if (drv->hhDriver) CloseHandle(drv->hhDriver); + drv->hhDriver = NULL; + drv->ovl.hEvent = NULL; + if (ControlService(drv->scDriver, SERVICE_CONTROL_STOP, &srvStatus)){ + if (wait_for_service_state(drv->scDriver, SERVICE_STOPPED, &srvStatus)){ + DeleteService(drv->scDriver); + } + } + } + return 0; +} + +/* endif defined (_WIN32) */ + +#else /* Unsupported OS */ +/* On others OS (i.e., Darwin), we still do not support RDMSR, so supply dummy struct + and functions */ + +#define RDMSR_UNSUPPORTED_OS + +struct msr_driver_t { int dummy; }; +struct msr_driver_t* cpu_msr_driver_open(void) +{ + set_error(ERR_NOT_IMP); + return NULL; +} + +struct msr_driver_t* cpu_msr_driver_open_core(unsigned core_num) +{ + set_error(ERR_NOT_IMP); + return NULL; +} + +int cpu_rdmsr(struct msr_driver_t* driver, uint32_t msr_index, uint64_t* result) +{ + return set_error(ERR_NOT_IMP); +} + +int cpu_msr_driver_close(struct msr_driver_t* driver) +{ + return set_error(ERR_NOT_IMP); +} + +int cpu_rdmsr_range(struct msr_driver_t* handle, uint32_t msr_index, uint8_t highbit, + uint8_t lowbit, uint64_t* result) +{ + return set_error(ERR_NOT_IMP); +} + +int cpu_msrinfo(struct msr_driver_t* driver, cpu_msrinfo_request_t which) +{ + return set_error(ERR_NOT_IMP); +} + +#endif /* Unsupported OS */ + +#ifndef RDMSR_UNSUPPORTED_OS + +/* Useful links for hackers: +- AMD MSRs: + AMD BIOS and Kernel Developer’s Guide (BKDG) + * AMD Family 10h Processors + http://support.amd.com/TechDocs/31116.pdf + * AMD Family 11h Processors + http://support.amd.com/TechDocs/41256.pdf + * AMD Family 12h Processors + http://support.amd.com/TechDocs/41131.pdf + * AMD Family 14h Processors + http://support.amd.com/TechDocs/43170_14h_Mod_00h-0Fh_BKDG.pdf + * AMD Family 15h Processors + http://support.amd.com/TechDocs/42301_15h_Mod_00h-0Fh_BKDG.pdf + http://support.amd.com/TechDocs/42300_15h_Mod_10h-1Fh_BKDG.pdf + http://support.amd.com/TechDocs/49125_15h_Models_30h-3Fh_BKDG.pdf + http://support.amd.com/TechDocs/50742_15h_Models_60h-6Fh_BKDG.pdf + http://support.amd.com/TechDocs/49125_15h_Models_30h-3Fh_BKDG.pdf + * AMD Family 16h Processors + http://support.amd.com/TechDocs/48751_16h_bkdg.pdf + http://support.amd.com/TechDocs/52740_16h_Models_30h-3Fh_BKDG.pdf + +- Intel MSRs: + Intel® 64 and IA-32 Architectures Software Developer’s Manual + * Volume 3 (3A, 3B, 3C & 3D): System Programming Guide + http://www.intel.com/content/dam/www/public/us/en/documents/manuals/64-ia-32-architectures-software-developer-system-programming-manual-325384.pdf +*/ + +/* AMD MSRs addresses */ +#define MSR_PSTATE_L 0xC0010061 +#define MSR_PSTATE_S 0xC0010063 +#define MSR_PSTATE_0 0xC0010064 +#define MSR_PSTATE_7 0xC001006B + +/* Intel MSRs addresses */ +#define IA32_MPERF 0xE7 +#define IA32_APERF 0xE8 +#define IA32_PERF_STATUS 0x198 +#define IA32_THERM_STATUS 0x19C +#define MSR_EBL_CR_POWERON 0x2A +#define MSR_TURBO_RATIO_LIMIT 0x1AD +#define MSR_TEMPERATURE_TARGET 0x1A2 +#define MSR_PERF_STATUS 0x198 +#define MSR_PLATFORM_INFO 0xCE + + +static int rdmsr_supported(void) +{ + struct cpu_id_t* id = get_cached_cpuid(); + return id->flags[CPU_FEATURE_MSR]; +} + +static int perfmsr_measure(struct msr_driver_t* handle, int msr) +{ + int err; + uint64_t a, b; + uint64_t x, y; + err = cpu_rdmsr(handle, msr, &x); + if (err) return CPU_INVALID_VALUE; + sys_precise_clock(&a); + busy_loop_delay(10); + cpu_rdmsr(handle, msr, &y); + sys_precise_clock(&b); + if (a >= b || x > y) return CPU_INVALID_VALUE; + return (int) ((y - x) / (b - a)); +} + +static int get_amd_multipliers(struct msr_driver_t* handle, struct cpu_id_t *id, + struct internal_id_info_t *internal, + uint32_t pstate, uint64_t *multiplier) +{ + int err; + static int clock = 0; + uint64_t CpuFid, CpuDid, CpuDidLSD; + double divisor; + + if (pstate < MSR_PSTATE_0 || MSR_PSTATE_7 < pstate) + return 1; + + switch (id->ext_family) { + case 0x11: + /* BKDG 11h, page 236 + MSRC001_00[6B:64][8:6] is CpuDid + MSRC001_00[6B:64][5:0] is CpuFid + CPU COF is ((100 MHz * (CpuFid + 08h)) / (2^CpuDid)) */ + err = cpu_rdmsr_range(handle, pstate, 8, 6, &CpuDid); + err += cpu_rdmsr_range(handle, pstate, 5, 0, &CpuFid); + *multiplier = (uint64_t) ((CpuFid + 0x8) / (1ull << CpuDid)); + break; + case 0x12: + /* BKDG 12h, page 469 + MSRC001_00[6B:64][8:4] is CpuFid + MSRC001_00[6B:64][3:0] is CpuDid + CPU COF is (100MHz * (CpuFid + 10h) / (divisor specified by CpuDid)) */ + err = cpu_rdmsr_range(handle, pstate, 8, 4, &CpuFid); + err += cpu_rdmsr_range(handle, pstate, 3, 0, &CpuDid); + if (CpuDid == 0x0) + divisor = 1; + else if (CpuDid == 0x1) + divisor = 1.5; + else if (CpuDid == 0x2) + divisor = 2; + else if (CpuDid == 0x3) + divisor = 3; + else if (CpuDid == 0x4) + divisor = 4; + else if (CpuDid == 0x5) + divisor = 6; + else if (CpuDid == 0x6) + divisor = 8; + else if (CpuDid == 0x7) + divisor = 12; + else if (CpuDid == 0x8) + divisor = 16; + else + divisor = 0; + + if (divisor > 0) + *multiplier = (uint64_t) ((CpuFid + 0x10) / divisor); + else + err++; + break; + case 0x14: + /* BKDG 14h, page 430 + MSRC001_00[6B:64][8:4] is CpuDidMSD + MSRC001_00[6B:64][3:0] is CpuDidLSD + PLL COF is (100 MHz * (D18F3xD4[MainPllOpFreqId] + 10h)) + Divisor is (CpuDidMSD + (CpuDidLSD * 0.25) + 1) + CPU COF is (main PLL frequency specified by D18F3xD4[MainPllOpFreqId]) / (core clock divisor specified by CpuDidMSD and CpuDidLSD) */ + err = cpu_rdmsr_range(handle, pstate, 8, 4, &CpuDid); + err += cpu_rdmsr_range(handle, pstate, 3, 0, &CpuDidLSD); + if (clock == 0) + clock = cpu_clock_measure(100, 1) + 5; // Fake round + *multiplier = (uint64_t) ((clock / 100 + 0x10) / (CpuDid + CpuDidLSD * 0.25 + 1)); + break; + case 0x10: + /* BKDG 10h, page 429 + MSRC001_00[6B:64][8:6] is CpuDid + MSRC001_00[6B:64][5:0] is CpuFid + CPU COF is (100 MHz * (CpuFid + 10h) / (2^CpuDid)) */ + case 0x15: + /* BKDG 15h, page 570/580/635/692 (00h-0Fh/10h-1Fh/30h-3Fh/60h-6Fh) + MSRC001_00[6B:64][8:6] is CpuDid + MSRC001_00[6B:64][5:0] is CpuFid + CoreCOF is (100 * (MSRC001_00[6B:64][CpuFid] + 10h) / (2^MSRC001_00[6B:64][CpuDid])) */ + case 0x16: + /* BKDG 16h, page 549/611 (00h-0Fh/30h-3Fh) + MSRC001_00[6B:64][8:6] is CpuDid + MSRC001_00[6B:64][5:0] is CpuFid + CoreCOF is (100 * (MSRC001_00[6B:64][CpuFid] + 10h) / (2^MSRC001_00[6B:64][CpuDid])) */ + err = cpu_rdmsr_range(handle, pstate, 8, 6, &CpuDid); + err += cpu_rdmsr_range(handle, pstate, 5, 0, &CpuFid); + *multiplier = (uint64_t) ((CpuFid + 0x10) / (1ull << CpuDid)); + break; + default: + err = 1; + break; + } + + return err; +} + +static double get_info_min_multiplier(struct msr_driver_t* handle, struct cpu_id_t *id, + struct internal_id_info_t *internal) +{ + int err; + uint64_t reg; + + if(id->vendor == VENDOR_INTEL) { + /* Refer links above + Table 35-12. MSRs in Next Generation Intel Atom Processors Based on the Goldmont Microarchitecture + Table 35-13. MSRs in Processors Based on Intel® Microarchitecture Code Name Nehalem + Table 35-18. MSRs Supported by Intel® Processors based on Intel® microarchitecture code name Sandy Bridge (Contd.) + Table 35-23. Additional MSRs Supported by 3rd Generation Intel® Core™ Processors (based on Intel® microarchitecture code name Ivy Bridge) + Table 35-24. MSRs Supported by Intel® Xeon® Processors E5 v2 Product Family (based on Ivy Bridge-E microarchitecture) + Table 35-27. Additional MSRs Supported by Processors based on the Haswell or Haswell-E microarchitectures + Table 35-34. Additional MSRs Common to Intel® Xeon® Processor D and Intel Xeon Processors E5 v4 Family Based on the Broadwell Microarchitecture + Table 35-40. Selected MSRs Supported by Next Generation Intel® Xeon Phi™ Processors with DisplayFamily_DisplayModel Signature 06_57H + MSR_PLATFORM_INFO[47:40] is Maximum Efficiency Ratio + Maximum Efficiency Ratio is the minimum ratio that the processor can operates */ + err = cpu_rdmsr_range(handle, MSR_PLATFORM_INFO, 47, 40, ®); + if (!err) return (double) reg; + } + else if(id->vendor == VENDOR_AMD) { + /* Refer links above + MSRC001_0061[6:4] is PstateMaxVal + PstateMaxVal is the lowest-performance non-boosted P-state */ + err = cpu_rdmsr_range(handle, MSR_PSTATE_L, 6, 4, ®); + err += get_amd_multipliers(handle, id, internal, MSR_PSTATE_0 + (uint32_t) reg, ®); + if (!err) return (double) reg; + } + + return (double) CPU_INVALID_VALUE / 100; +} + +static double get_info_cur_multiplier(struct msr_driver_t* handle, struct cpu_id_t *id, + struct internal_id_info_t *internal) +{ + int err; + uint64_t reg; + + if(id->vendor == VENDOR_INTEL && internal->code.intel == PENTIUM) { + err = cpu_rdmsr(handle, MSR_EBL_CR_POWERON, ®); + if (!err) return (double) ((reg>>22) & 0x1f); + } + else if(id->vendor == VENDOR_INTEL && internal->code.intel != PENTIUM) { + /* Refer links above + Table 35-2. IA-32 Architectural MSRs (Contd.) + IA32_PERF_STATUS[15:0] is Current performance State Value + [7:0] is 0x0, [15:8] looks like current ratio */ + err = cpu_rdmsr_range(handle, IA32_PERF_STATUS, 15, 8, ®); + if (!err) return (double) reg; + } + else if(id->vendor == VENDOR_AMD) { + /* Refer links above + MSRC001_0063[2:0] is CurPstate */ + err = cpu_rdmsr_range(handle, MSR_PSTATE_S, 2, 0, ®); + err += get_amd_multipliers(handle, id, internal, MSR_PSTATE_0 + (uint32_t) reg, ®); + if (!err) return (double) reg; + } + + return (double) CPU_INVALID_VALUE / 100; +} + +static double get_info_max_multiplier(struct msr_driver_t* handle, struct cpu_id_t *id, + struct internal_id_info_t *internal) +{ + int err; + uint64_t reg; + + if(id->vendor == VENDOR_INTEL && internal->code.intel == PENTIUM) { + err = cpu_rdmsr(handle, IA32_PERF_STATUS, ®); + if (!err) return (double) ((reg >> 40) & 0x1f); + } + else if(id->vendor == VENDOR_INTEL && internal->code.intel != PENTIUM) { + /* Refer links above + Table 35-10. Specific MSRs Supported by Intel® Atom™ Processor C2000 Series with CPUID Signature 06_4DH + Table 35-12. MSRs in Next Generation Intel Atom Processors Based on the Goldmont Microarchitecture (Contd.) + Table 35-13. MSRs in Processors Based on Intel® Microarchitecture Code Name Nehalem (Contd.) + Table 35-14. Additional MSRs in Intel® Xeon® Processor 5500 and 3400 Series + Table 35-16. Additional MSRs Supported by Intel Processors (Based on Intel® Microarchitecture Code Name Westmere) + Table 35-19. MSRs Supported by 2nd Generation Intel® Core™ Processors (Intel® microarchitecture code name Sandy Bridge) + Table 35-21. Selected MSRs Supported by Intel® Xeon® Processors E5 Family (based on Sandy Bridge microarchitecture) + Table 35-28. MSRs Supported by 4th Generation Intel® Core™ Processors (Haswell microarchitecture) (Contd.) + Table 35-30. Additional MSRs Supported by Intel® Xeon® Processor E5 v3 Family + Table 35-33. Additional MSRs Supported by Intel® Core™ M Processors and 5th Generation Intel® Core™ Processors + Table 35-34. Additional MSRs Common to Intel® Xeon® Processor D and Intel Xeon Processors E5 v4 Family Based on the Broadwell Microarchitecture + Table 35-37. Additional MSRs Supported by 6th Generation Intel® Core™ Processors Based on Skylake Microarchitecture + Table 35-40. Selected MSRs Supported by Next Generation Intel® Xeon Phi™ Processors with DisplayFamily_DisplayModel Signature 06_57H + MSR_TURBO_RATIO_LIMIT[7:0] is Maximum Ratio Limit for 1C */ + err = cpu_rdmsr_range(handle, MSR_TURBO_RATIO_LIMIT, 7, 0, ®); + if (!err) return (double) reg; + } + else if(id->vendor == VENDOR_AMD) { + /* Refer links above + MSRC001_0064 is Pb0 + Pb0 is the highest-performance boosted P-state */ + err = get_amd_multipliers(handle, id, internal, MSR_PSTATE_0, ®); + if (!err) return (double) reg; + } + + return (double) CPU_INVALID_VALUE / 100; +} + +static int get_info_temperature(struct msr_driver_t* handle, struct cpu_id_t *id, + struct internal_id_info_t *internal) +{ + int err; + uint64_t DigitalReadout, ReadingValid, TemperatureTarget; + + if(id->vendor == VENDOR_INTEL) { + /* Refer links above + Table 35-2. IA-32 Architectural MSRs + IA32_THERM_STATUS[22:16] is Digital Readout + IA32_THERM_STATUS[31] is Reading Valid + + Table 35-6. MSRs Common to the Silvermont Microarchitecture and Newer Microarchitectures for Intel® Atom + Table 35-13. MSRs in Processors Based on Intel® Microarchitecture Code Name Nehalem (Contd.) + Table 35-18. MSRs Supported by Intel® Processors based on Intel® microarchitecture code name Sandy Bridge (Contd.) + Table 35-24. MSRs Supported by Intel® Xeon® Processors E5 v2 Product Family (based on Ivy Bridge-E microarchitecture) (Contd.) + Table 35-34. Additional MSRs Common to Intel® Xeon® Processor D and Intel Xeon Processors E5 v4 Family Based on the Broadwell Microarchitecture + Table 35-40. Selected MSRs Supported by Next Generation Intel® Xeon Phi™ Processors with DisplayFamily_DisplayModel Signature 06_57H + MSR_TEMPERATURE_TARGET[23:16] is Temperature Target */ + err = cpu_rdmsr_range(handle, IA32_THERM_STATUS, 22, 16, &DigitalReadout); + err += cpu_rdmsr_range(handle, IA32_THERM_STATUS, 31, 31, &ReadingValid); + err += cpu_rdmsr_range(handle, MSR_TEMPERATURE_TARGET, 23, 16, &TemperatureTarget); + if(!err && ReadingValid) return (int) (TemperatureTarget - DigitalReadout); + } + + return CPU_INVALID_VALUE; +} + +static double get_info_voltage(struct msr_driver_t* handle, struct cpu_id_t *id, + struct internal_id_info_t *internal) +{ + int err; + uint64_t reg, CpuVid; + + if(id->vendor == VENDOR_INTEL) { + /* Refer links above + Table 35-18. MSRs Supported by Intel® Processors based on Intel® microarchitecture code name Sandy Bridge (Contd.) + MSR_PERF_STATUS[47:32] is Core Voltage + P-state core voltage can be computed by MSR_PERF_STATUS[37:32] * (float) 1/(2^13). */ + err = cpu_rdmsr_range(handle, MSR_PERF_STATUS, 47, 32, ®); + if (!err) return (double) reg / (1 << 13); + } + else if(id->vendor == VENDOR_AMD) { + /* Refer links above + MSRC001_00[6B:64][15:9] is CpuVid + MSRC001_0063[2:0] is P-state Status + 2.4.1.6.3 Serial VID (SVI) Encodings: voltage = 1.550V - 0.0125V * SviVid[6:0] */ + err = cpu_rdmsr_range(handle, MSR_PSTATE_S, 2, 0, ®); + err += cpu_rdmsr_range(handle, MSR_PSTATE_0 + (uint32_t) reg, 15, 9, &CpuVid); + if (!err && MSR_PSTATE_0 + (uint32_t) reg <= MSR_PSTATE_7) return 1.550 - 0.0125 * CpuVid; + } + + return (double) CPU_INVALID_VALUE / 100; +} + +static double get_info_bus_clock(struct msr_driver_t* handle, struct cpu_id_t *id, + struct internal_id_info_t *internal) +{ + int err; + static int clock = 0; + uint64_t reg; + + if(clock == 0) + clock = cpu_clock_measure(100, 1); + + if(id->vendor == VENDOR_INTEL) { + /* Refer links above + Table 35-12. MSRs in Next Generation Intel Atom Processors Based on the Goldmont Microarchitecture + Table 35-13. MSRs in Processors Based on Intel® Microarchitecture Code Name Nehalem + Table 35-18. MSRs Supported by Intel® Processors based on Intel® microarchitecture code name Sandy Bridge (Contd.) + Table 35-23. Additional MSRs Supported by 3rd Generation Intel® Core™ Processors (based on Intel® microarchitecture code name Ivy Bridge) + Table 35-24. MSRs Supported by Intel® Xeon® Processors E5 v2 Product Family (based on Ivy Bridge-E microarchitecture) + Table 35-27. Additional MSRs Supported by Processors based on the Haswell or Haswell-E microarchitectures + Table 35-40. Selected MSRs Supported by Next Generation Intel® Xeon Phi™ Processors with DisplayFamily_DisplayModel Signature 06_57H + MSR_PLATFORM_INFO[15:8] is Maximum Non-Turbo Ratio */ + err = cpu_rdmsr_range(handle, MSR_PLATFORM_INFO, 15, 8, ®); + if (!err) return (double) clock / reg; + } + else if(id->vendor == VENDOR_AMD) { + /* Refer links above + MSRC001_0061[2:0] is CurPstateLimit + CurPstateLimit is the highest-performance non-boosted P-state */ + err = cpu_rdmsr_range(handle, MSR_PSTATE_L, 2, 0, ®); + err += get_amd_multipliers(handle, id, internal, MSR_PSTATE_0 + (uint32_t) reg, ®); + if (!err) return (double) clock / reg; + } + + return (double) CPU_INVALID_VALUE / 100; +} + +int cpu_rdmsr_range(struct msr_driver_t* handle, uint32_t msr_index, uint8_t highbit, + uint8_t lowbit, uint64_t* result) +{ + int err; + const uint8_t bits = highbit - lowbit + 1; + + if(highbit > 63 || lowbit > highbit) + return set_error(ERR_INVRANGE); + + err = cpu_rdmsr(handle, msr_index, result); + + if(!err && bits < 64) { + /* Show only part of register */ + *result >>= lowbit; + *result &= (1ULL << bits) - 1; + } + + return err; +} + +int cpu_msrinfo(struct msr_driver_t* handle, cpu_msrinfo_request_t which) +{ + struct cpu_raw_data_t raw; + static struct cpu_id_t id; + static struct internal_id_info_t internal; + internal.score = -1; + + if (handle == NULL) + return set_error(ERR_HANDLE); + + if (internal.score == -1) { + cpuid_get_raw_data(&raw); + cpu_ident_internal(&raw, &id, &internal); + } + + switch (which) { + case INFO_MPERF: + return perfmsr_measure(handle, IA32_MPERF); + case INFO_APERF: + return perfmsr_measure(handle, IA32_APERF); + case INFO_MIN_MULTIPLIER: + return (int) (get_info_min_multiplier(handle, &id, &internal) * 100); + case INFO_CUR_MULTIPLIER: + return (int) (get_info_cur_multiplier(handle, &id, &internal) * 100); + case INFO_MAX_MULTIPLIER: + return (int) (get_info_max_multiplier(handle, &id, &internal) * 100); + case INFO_TEMPERATURE: + return get_info_temperature(handle, &id, &internal); + case INFO_THROTTLING: + return CPU_INVALID_VALUE; + case INFO_VOLTAGE: + return (int) (get_info_voltage(handle, &id, &internal) * 100); + case INFO_BCLK: + case INFO_BUS_CLOCK: + return (int) (get_info_bus_clock(handle, &id, &internal) * 100); + default: + return CPU_INVALID_VALUE; + } +} + +#endif // RDMSR_UNSUPPORTED_OS diff --git a/contrib/libcpuid/include/libcpuid/rdtsc.c b/contrib/libcpuid/include/libcpuid/rdtsc.c index 5930681561a..df4543946f5 100644 --- a/contrib/libcpuid/include/libcpuid/rdtsc.c +++ b/contrib/libcpuid/include/libcpuid/rdtsc.c @@ -226,6 +226,45 @@ int cpu_clock_measure(int millis, int quad_check) return (results[bi] + results[bj] + _zero) / 2; } + +static void adjust_march_ic_multiplier(const struct cpu_id_t* id, int* numerator, int* denom) +{ + /* + * for cpu_clock_by_ic: we need to know how many clocks does a typical ADDPS instruction + * take, when issued in rapid succesion without dependencies. The whole idea of + * cpu_clock_by_ic was that this is easy to determine, at least it was back in 2010. Now + * it's getting progressively more hairy, but here are the current measurements: + * + * 1. For CPUs with 64-bit SSE units, ADDPS issue rate is 0.5 IPC (one insn in 2 clocks) + * 2. For CPUs with 128-bit SSE units, issue rate is exactly 1.0 IPC + * 3. For Bulldozer and later, it is 1.4 IPC (we multiply by 5/7) + * 4. For Skylake and later, it is 1.6 IPC (we multiply by 5/8) + */ + // + if (id->sse_size < 128) { + debugf(1, "SSE execution path is 64-bit\n"); + // on a CPU with half SSE unit length, SSE instructions execute at 0.5 IPC; + // the resulting value must be multiplied by 2: + *numerator = 2; + } else { + debugf(1, "SSE execution path is 128-bit\n"); + } + // + // Bulldozer or later: assume 1.4 IPC + if (id->vendor == VENDOR_AMD && id->ext_family >= 21) { + debugf(1, "cpu_clock_by_ic: Bulldozer (or later) detected, dividing result by 1.4\n"); + *numerator = 5; + *denom = 7; // multiply by 5/7, to divide by 1.4 + } + // + // Skylake or later: assume 1.6 IPC + if (id->vendor == VENDOR_INTEL && id->ext_model >= 94) { + debugf(1, "cpu_clock_by_ic: Skylake (or later) detected, dividing result by 1.6\n"); + *numerator = 5; + *denom = 8; // to divide by 1.6, multiply by 5/8 + } +} + int cpu_clock_by_ic(int millis, int runs) { int max_value = 0, cur_value, i, ri, cycles_inner, cycles_outer, c; @@ -237,21 +276,7 @@ int cpu_clock_by_ic(int millis, int runs) // if there aren't SSE instructions - we can't run the test at all if (!id || !id->flags[CPU_FEATURE_SSE]) return -1; // - if (id->sse_size < 128) { - debugf(1, "SSE execution path is 64-bit\n"); - // on a CPU with half SSE unit length, SSE instructions execute at 0.5 IPC; - // the resulting value must be multiplied by 2: - multiplier_numerator = 2; - } else { - debugf(1, "SSE execution path is 128-bit\n"); - } - // - // on a Bulldozer or later CPU, SSE instructions execute at 1.4 IPC, handle that as well: - if (id->vendor == VENDOR_AMD && id->ext_family >= 21) { - debugf(1, "cpu_clock_by_ic: Bulldozer (or later) detected, dividing result by 1.4\n"); - multiplier_numerator = 5; - multiplier_denom = 7; // multiply by 5/7, to divide by 1.4 - } + adjust_march_ic_multiplier(id, &multiplier_numerator, &multiplier_denom); // tl = millis * 125; // (*1000 / 8) cycles_inner = 128; diff --git a/contrib/libcpuid/include/libcpuid/recog_amd.c b/contrib/libcpuid/include/libcpuid/recog_amd.c index c5390b9fd24..2e6c8a9ead8 100644 --- a/contrib/libcpuid/include/libcpuid/recog_amd.c +++ b/contrib/libcpuid/include/libcpuid/recog_amd.c @@ -28,47 +28,16 @@ #include #include #include "libcpuid.h" -#include "recog_amd.h" #include "libcpuid_util.h" +#include "libcpuid_internal.h" +#include "recog_amd.h" -enum _amd_code_t { - NA, - NO_CODE, - OPTERON_GENERIC, - OPTERON_800, - ATHLON_XP, - ATHLON_XP_M, - ATHLON_XP_M_LV, - ATHLON, - ATHLON_MP, - MOBILE_ATHLON64, - ATHLON_FX, - DURON, - DURON_MP, - MOBILE_DURON, - MOBILE_SEMPRON, - OPTERON_SINGLE, - OPTERON_DUALCORE, - OPTERON_800_DUALCORE, - MOBILE_TURION, - ATHLON_64, - ATHLON_64_FX, - TURION_64, - TURION_X2, - SEMPRON, - M_SEMPRON, - SEMPRON_DUALCORE, - PHENOM, - PHENOM2, - ATHLON_64_X2, - ATHLON_64_X3, - ATHLON_64_X4, - FUSION_C, - FUSION_E, - FUSION_EA, - FUSION_Z, +const struct amd_code_str { amd_code_t code; char *str; } amd_code_str[] = { + #define CODE(x) { x, #x } + #define CODE2(x, y) CODE(x) + #include "amd_code_t.h" + #undef CODE }; -typedef enum _amd_code_t amd_code_t; const struct match_entry_t cpudb_amd[] = { { -1, -1, -1, -1, -1, 1, -1, -1, NO_CODE , 0, "Unknown AMD CPU" }, @@ -146,6 +115,7 @@ const struct match_entry_t cpudb_amd[] = { { 15, -1, -1, 15, -1, 1, 1024, -1, ATHLON_64 , 0, "Athlon 64 (1024K)" }, { 15, -1, -1, 15, -1, 1, -1, -1, ATHLON_FX , 0, "Athlon FX" }, { 15, -1, -1, 15, -1, 1, -1, -1, ATHLON_64_FX , 0, "Athlon 64 FX" }, + { 15, 3, -1, 15, 35, 2, -1, -1, ATHLON_64_FX , 0, "Athlon 64 FX X2 (Toledo)" }, { 15, -1, -1, 15, -1, 2, 512, -1, ATHLON_64_X2 , 0, "Athlon 64 X2 (512K)" }, { 15, -1, -1, 15, -1, 2, 1024, -1, ATHLON_64_X2 , 0, "Athlon 64 X2 (1024K)" }, { 15, -1, -1, 15, -1, 1, 512, -1, TURION_64 , 0, "Turion 64 (512K)" }, @@ -237,31 +207,65 @@ const struct match_entry_t cpudb_amd[] = { { 15, 4, -1, 16, 10, 4, 512, -1, PHENOM2 , 0, "Phenom II X4 (Zosma)" }, { 15, 4, -1, 16, 10, 6, 512, -1, PHENOM2 , 0, "Phenom II X6 (Thuban)" }, - { 15, 4, -1, 16, -1, 2, 1024, -1, ATHLON_64_X2 , 0, "Athlon II X2 (Regor)" }, - { 15, 4, -1, 16, -1, 2, 512, -1, ATHLON_64_X2 , 0, "Athlon II X2 (Regor)" }, + { 15, 6, -1, 16, 6, 2, 512, -1, ATHLON , 0, "Athlon II (Champlain)" }, + { 15, 6, -1, 16, 6, 2, 512, -1, ATHLON_64_X2 , 0, "Athlon II X2 (Regor)" }, + { 15, 6, -1, 16, 6, 2, 1024, -1, ATHLON_64_X2 , 0, "Athlon II X2 (Regor)" }, { 15, 5, -1, 16, 5, 3, 512, -1, ATHLON_64_X3 , 0, "Athlon II X3 (Rana)" }, { 15, 5, -1, 16, 5, 4, 512, -1, ATHLON_64_X4 , 0, "Athlon II X4 (Propus)" }, - /* 2011 CPUs with AMD fusion: */ - { 15, -1, -1, 20, 1, 1, 512, -1, FUSION_C , 0, "Brazos Ontario" }, - { 15, -1, -1, 20, 1, 2, 512, -1, FUSION_C , 0, "Brazos Ontario (Dual-core)" }, - { 15, -1, -1, 20, 1, 1, 512, -1, FUSION_E , 0, "Brazos Zacate" }, - { 15, -1, -1, 20, 1, 2, 512, -1, FUSION_E , 0, "Brazos Zacate (Dual-core)" }, - { 15, -1, -1, 20, 1, 1, 512, -1, FUSION_Z , 0, "Brazos Desna" }, - { 15, -1, -1, 18, 1, 2, 512, -1, FUSION_EA , 0, "Llano X2" }, - { 15, -1, -1, 18, 1, 2, 1024, -1, FUSION_EA , 0, "Llano X2" }, - { 15, -1, -1, 18, 1, 3, 1024, -1, FUSION_EA , 0, "Llano X3" }, - { 15, -1, -1, 18, 1, 4, 1024, -1, FUSION_EA , 0, "Llano X4" }, + + /* 2011 CPUs: K10 architecture: Llano */ + { 15, 1, -1, 18, 1, 2, 512, -1, FUSION_EA , 0, "Llano X2" }, + { 15, 1, -1, 18, 1, 2, 1024, -1, FUSION_EA , 0, "Llano X2" }, + { 15, 1, -1, 18, 1, 3, 1024, -1, FUSION_EA , 0, "Llano X3" }, + { 15, 1, -1, 18, 1, 4, 1024, -1, FUSION_EA , 0, "Llano X4" }, + /* 2011 CPUs: Bobcat architecture: Ontario, Zacate, Desna, Hondo */ + { 15, 2, -1, 20, -1, 1, 512, -1, FUSION_C , 0, "Brazos Ontario" }, + { 15, 2, -1, 20, -1, 2, 512, -1, FUSION_C , 0, "Brazos Ontario (Dual-core)" }, + { 15, 1, -1, 20, -1, 1, 512, -1, FUSION_E , 0, "Brazos Zacate" }, + { 15, 1, -1, 20, -1, 2, 512, -1, FUSION_E , 0, "Brazos Zacate (Dual-core)" }, + { 15, 2, -1, 20, -1, 2, 512, -1, FUSION_Z , 0, "Brazos Desna (Dual-core)" }, + /* 2012 CPUs: Piledriver architecture: Trinity and Richland */ + { 15, 0, -1, 21, 10, 2, 1024, -1, FUSION_A , 0, "Trinity X2" }, + { 15, 0, -1, 21, 16, 2, 1024, -1, FUSION_A , 0, "Trinity X2" }, + { 15, 0, -1, 21, 10, 4, 1024, -1, FUSION_A , 0, "Trinity X4" }, + { 15, 0, -1, 21, 16, 4, 1024, -1, FUSION_A , 0, "Trinity X4" }, + { 15, 3, -1, 21, 13, 2, 1024, -1, FUSION_A , 0, "Richland X2" }, + { 15, 3, -1, 21, 13, 4, 1024, -1, FUSION_A , 0, "Richland X4" }, + /* 2013 CPUs: Jaguar architecture: Kabini and Temash */ + { 15, 0, -1, 22, 0, 2, 1024, -1, FUSION_A , 0, "Kabini X2" }, + { 15, 0, -1, 22, 0, 4, 1024, -1, FUSION_A , 0, "Kabini X4" }, + /* 2014 CPUs: Steamroller architecture: Kaveri */ + { 15, 0, -1, 21, 30, 2, 1024, -1, FUSION_A , 0, "Kaveri X2" }, + { 15, 0, -1, 21, 30, 4, 1024, -1, FUSION_A , 0, "Kaveri X4" }, + /* 2014 CPUs: Puma architecture: Beema and Mullins */ + { 15, 0, -1, 22, 30, 2, 1024, -1, FUSION_E , 0, "Mullins X2" }, + { 15, 0, -1, 22, 30, 4, 1024, -1, FUSION_A , 0, "Mullins X4" }, + /* 2015 CPUs: Excavator architecture: Carrizo */ + { 15, 1, -1, 21, 60, 2, 1024, -1, FUSION_A , 0, "Carrizo X2" }, + { 15, 1, -1, 21, 60, 4, 1024, -1, FUSION_A , 0, "Carrizo X4" }, + /* 2015 CPUs: Steamroller architecture: Godavari */ + //TODO + /* 2016 CPUs: Excavator architecture: Bristol Ridge */ + //TODO /* Newer Opterons: */ - { 15, 9, -1, 16, 9, 8, -1, -1, OPTERON_GENERIC , 0, "Magny-Cours Opteron" }, + { 15, 9, -1, 22, 9, 8, -1, -1, OPTERON_GENERIC , 0, "Magny-Cours Opteron" }, /* Bulldozer CPUs: */ + { 15, -1, -1, 21, 0, 4, 2048, -1, NO_CODE , 0, "Bulldozer X2" }, { 15, -1, -1, 21, 1, 4, 2048, -1, NO_CODE , 0, "Bulldozer X2" }, { 15, -1, -1, 21, 1, 6, 2048, -1, NO_CODE , 0, "Bulldozer X3" }, { 15, -1, -1, 21, 1, 8, 2048, -1, NO_CODE , 0, "Bulldozer X4" }, + /* Piledriver CPUs: */ { 15, -1, -1, 21, 2, 4, 2048, -1, NO_CODE , 0, "Vishera X2" }, { 15, -1, -1, 21, 2, 6, 2048, -1, NO_CODE , 0, "Vishera X3" }, { 15, -1, -1, 21, 2, 8, 2048, -1, NO_CODE , 0, "Vishera X4" }, + /* Steamroller CPUs: */ + //TODO + /* Excavator CPUs: */ + //TODO + /* Zen CPUs: */ + //TODO }; @@ -287,6 +291,7 @@ static void load_amd_features(struct cpu_raw_data_t* raw, struct cpu_id_t* data) { 12, CPU_FEATURE_SKINIT }, { 13, CPU_FEATURE_WDT }, { 16, CPU_FEATURE_FMA4 }, + { 21, CPU_FEATURE_TBM }, }; const struct feature_map_t matchtable_edx87[] = { { 0, CPU_FEATURE_TS }, @@ -307,7 +312,7 @@ static void load_amd_features(struct cpu_raw_data_t* raw, struct cpu_id_t* data) match_features(matchtable_edx81, COUNT_OF(matchtable_edx81), raw->ext_cpuid[1][3], data); match_features(matchtable_ecx81, COUNT_OF(matchtable_ecx81), raw->ext_cpuid[1][2], data); } - if (raw->ext_cpuid[0][0] >= 0x80000001) + if (raw->ext_cpuid[0][0] >= 0x80000007) match_features(matchtable_edx87, COUNT_OF(matchtable_edx87), raw->ext_cpuid[7][3], data); if (raw->ext_cpuid[0][0] >= 0x8000001a) { /* We have the extended info about SSE unit size */ @@ -320,7 +325,7 @@ static void decode_amd_cache_info(struct cpu_raw_data_t* raw, struct cpu_id_t* d { int l3_result; const int assoc_table[16] = { - 0, 1, 2, 0, 4, 0, 8, 0, 16, 0, 32, 48, 64, 92, 128, 255 + 0, 1, 2, 0, 4, 0, 8, 0, 16, 0, 32, 48, 64, 96, 128, 255 }; unsigned n = raw->ext_cpuid[0][0]; @@ -442,24 +447,36 @@ static amd_code_t decode_amd_codename_part1(const char *bs) if (match_pattern(bs, "Z-##")) return FUSION_Z; if (match_pattern(bs, "E#-####") || match_pattern(bs, "A#-####")) return FUSION_EA; - return NO_CODE; + return (amd_code_t) NO_CODE; } -static void decode_amd_codename(struct cpu_raw_data_t* raw, struct cpu_id_t* data) +static void decode_amd_codename(struct cpu_raw_data_t* raw, struct cpu_id_t* data, struct internal_id_info_t* internal) { amd_code_t code = decode_amd_codename_part1(data->brand_str); - + int i = 0; + char* code_str = NULL; + for (i = 0; i < COUNT_OF(amd_code_str); i++) { + if (code == amd_code_str[i].code) { + code_str = amd_code_str[i].str; + break; + } + } if (code == ATHLON_64_X2 && data->l2_cache < 512) code = SEMPRON_DUALCORE; - match_cpu_codename(cpudb_amd, COUNT_OF(cpudb_amd), data, code, 0); + if (code_str) + debugf(2, "Detected AMD brand code: %d (%s)\n", code, code_str); + else + debugf(2, "Detected AMD brand code: %d\n", code); + internal->code.amd = code; + internal->score = match_cpu_codename(cpudb_amd, COUNT_OF(cpudb_amd), data, code, 0); } -int cpuid_identify_amd(struct cpu_raw_data_t* raw, struct cpu_id_t* data) +int cpuid_identify_amd(struct cpu_raw_data_t* raw, struct cpu_id_t* data, struct internal_id_info_t* internal) { load_amd_features(raw, data); decode_amd_cache_info(raw, data); decode_amd_number_of_cores(raw, data); - decode_amd_codename(raw, data); + decode_amd_codename(raw, data, internal); return 0; } diff --git a/contrib/libcpuid/include/libcpuid/recog_amd.h b/contrib/libcpuid/include/libcpuid/recog_amd.h index e0f3b61f727..34e89598397 100644 --- a/contrib/libcpuid/include/libcpuid/recog_amd.h +++ b/contrib/libcpuid/include/libcpuid/recog_amd.h @@ -26,7 +26,7 @@ #ifndef __RECOG_AMD_H__ #define __RECOG_AMD_H__ -int cpuid_identify_amd(struct cpu_raw_data_t* raw, struct cpu_id_t* data); +int cpuid_identify_amd(struct cpu_raw_data_t* raw, struct cpu_id_t* data, struct internal_id_info_t* internal); void cpuid_get_list_amd(struct cpu_list_t* list); #endif /* __RECOG_AMD_H__ */ diff --git a/contrib/libcpuid/include/libcpuid/recog_intel.c b/contrib/libcpuid/include/libcpuid/recog_intel.c index 625b2777f51..2ffc41c8a15 100644 --- a/contrib/libcpuid/include/libcpuid/recog_intel.c +++ b/contrib/libcpuid/include/libcpuid/recog_intel.c @@ -26,61 +26,16 @@ #include #include #include "libcpuid.h" -#include "recog_intel.h" #include "libcpuid_util.h" +#include "libcpuid_internal.h" +#include "recog_intel.h" - -enum _intel_code_t { - NA, - NO_CODE, - PENTIUM = 10, - MOBILE_PENTIUM, - - XEON = 20, - XEON_IRWIN, - XEONMP, - XEON_POTOMAC, - XEON_I7, - XEON_GAINESTOWN, - XEON_WESTMERE, - - MOBILE_PENTIUM_M = 30, - CELERON, - MOBILE_CELERON, - NOT_CELERON, - - - CORE_SOLO = 40, - MOBILE_CORE_SOLO, - CORE_DUO, - MOBILE_CORE_DUO, - - WOLFDALE = 50, - MEROM, - PENRYN, - QUAD_CORE, - DUAL_CORE_HT, - QUAD_CORE_HT, - MORE_THAN_QUADCORE, - PENTIUM_D, - - ATOM = 60, - ATOM_SILVERTHORNE, - ATOM_DIAMONDVILLE, - ATOM_PINEVIEW, - ATOM_CEDARVIEW, - - CORE_I3 = 70, - CORE_I5, - CORE_I7, - CORE_IVY3, /* 22nm Core-iX */ - CORE_IVY5, - CORE_IVY7, - CORE_HASWELL3, /* 22nm Core-iX, Haswell */ - CORE_HASWELL5, - CORE_HASWELL7, +const struct intel_bcode_str { intel_code_t code; char *str; } intel_bcode_str[] = { + #define CODE(x) { x, #x } + #define CODE2(x, y) CODE(x) + #include "intel_code_t.h" + #undef CODE }; -typedef enum _intel_code_t intel_code_t; enum _intel_model_t { UNKNOWN = -1, @@ -134,12 +89,12 @@ const struct match_entry_t cpudb_intel[] = { { 6, 5, -1, -1, -1, 1, -1, -1, MOBILE_PENTIUM , 0, "Mobile Pentium II (Tonga)"}, { 6, 6, -1, -1, -1, 1, -1, -1, NO_CODE , 0, "Pentium II (Dixon)" }, - { 6, 3, -1, -1, -1, 1, -1, -1, XEON , 0, "P-II Xeon" }, - { 6, 5, -1, -1, -1, 1, -1, -1, XEON , 0, "P-II Xeon" }, - { 6, 6, -1, -1, -1, 1, -1, -1, XEON , 0, "P-II Xeon" }, + { 6, 3, -1, -1, -1, 1, -1, -1, XEON , 0, "P-II Xeon (Klamath)" }, + { 6, 5, -1, -1, -1, 1, -1, -1, XEON , 0, "P-II Xeon (Drake)" }, + { 6, 6, -1, -1, -1, 1, -1, -1, XEON , 0, "P-II Xeon (Dixon)" }, - { 6, 5, -1, -1, -1, 1, -1, -1, CELERON , 0, "P-II Celeron (no L2)" }, - { 6, 6, -1, -1, -1, 1, -1, -1, CELERON , 0, "P-II Celeron (128K)" }, + { 6, 5, -1, -1, -1, 1, -1, -1, CELERON , 0, "P-II Celeron (Covingtons" }, + { 6, 6, -1, -1, -1, 1, -1, -1, CELERON , 0, "P-II Celeron (Mendocino)" }, /* -------------------------------------------------- */ @@ -148,15 +103,15 @@ const struct match_entry_t cpudb_intel[] = { { 6, 10, -1, -1, -1, 1, -1, -1, NO_CODE , 0, "Pentium III (Coppermine)"}, { 6, 11, -1, -1, -1, 1, -1, -1, NO_CODE , 0, "Pentium III (Tualatin)" }, - { 6, 7, -1, -1, -1, 1, -1, -1, XEON , 0, "P-III Xeon" }, - { 6, 8, -1, -1, -1, 1, -1, -1, XEON , 0, "P-III Xeon" }, - { 6, 10, -1, -1, -1, 1, -1, -1, XEON , 0, "P-III Xeon" }, - { 6, 11, -1, -1, -1, 1, -1, -1, XEON , 0, "P-III Xeon" }, + { 6, 7, -1, -1, -1, 1, -1, -1, XEON , 0, "P-III Xeon (Tanner)" }, + { 6, 8, -1, -1, -1, 1, -1, -1, XEON , 0, "P-III Xeon (Cascades)" }, + { 6, 10, -1, -1, -1, 1, -1, -1, XEON , 0, "P-III Xeon (Cascades)" }, + { 6, 11, -1, -1, -1, 1, -1, -1, XEON , 0, "P-III Xeon (Tualatin)" }, - { 6, 7, -1, -1, -1, 1, -1, -1, CELERON , 0, "P-III Celeron" }, - { 6, 8, -1, -1, -1, 1, -1, -1, CELERON , 0, "P-III Celeron" }, - { 6, 10, -1, -1, -1, 1, -1, -1, CELERON , 0, "P-III Celeron" }, - { 6, 11, -1, -1, -1, 1, -1, -1, CELERON , 0, "P-III Celeron" }, + { 6, 7, -1, -1, -1, 1, -1, -1, CELERON , 0, "P-III Celeron (Katmai)" }, + { 6, 8, -1, -1, -1, 1, -1, -1, CELERON , 0, "P-III Celeron (Coppermine)" }, + { 6, 10, -1, -1, -1, 1, -1, -1, CELERON , 0, "P-III Celeron (Coppermine)" }, + { 6, 11, -1, -1, -1, 1, -1, -1, CELERON , 0, "P-III Celeron (Tualatin)" }, /* Netburst based (Pentium 4 and later) classic P4s */ @@ -190,17 +145,17 @@ const struct match_entry_t cpudb_intel[] = { { 15, 6, -1, 15, -1, 1, -1, -1, XEON , 0, "Xeon (Dempsey)" }, /* Pentium Ds */ - { 15, 4, 4, 15, -1, 1, -1, -1, NO_CODE , 0, "Pentium D" }, - { 15, 4, -1, 15, -1, 1, -1, -1, PENTIUM_D , 0, "Pentium D" }, - { 15, 4, 7, 15, -1, 1, -1, -1, NO_CODE , 0, "Pentium D" }, - { 15, 6, -1, 15, -1, 1, -1, -1, PENTIUM_D , 0, "Pentium D" }, + { 15, 4, 4, 15, -1, 1, -1, -1, NO_CODE , 0, "Pentium D (SmithField)" }, + { 15, 4, -1, 15, -1, 1, -1, -1, PENTIUM_D , 0, "Pentium D (SmithField)" }, + { 15, 4, 7, 15, -1, 1, -1, -1, NO_CODE , 0, "Pentium D (SmithField)" }, + { 15, 6, -1, 15, -1, 1, -1, -1, PENTIUM_D , 0, "Pentium D (Presler)" }, /* Celeron and Celeron Ds */ - { 15, 1, -1, 15, -1, 1, -1, -1, CELERON , 0, "P-4 Celeron (128K)" }, - { 15, 2, -1, 15, -1, 1, -1, -1, CELERON , 0, "P-4 Celeron (128K)" }, - { 15, 3, -1, 15, -1, 1, -1, -1, CELERON , 0, "Celeron D" }, - { 15, 4, -1, 15, -1, 1, -1, -1, CELERON , 0, "Celeron D" }, - { 15, 6, -1, 15, -1, 1, -1, -1, CELERON , 0, "Celeron D" }, + { 15, 1, -1, 15, -1, 1, -1, -1, CELERON , 0, "P-4 Celeron (Willamette)" }, + { 15, 2, -1, 15, -1, 1, -1, -1, CELERON , 0, "P-4 Celeron (Northwood)" }, + { 15, 3, -1, 15, -1, 1, -1, -1, CELERON , 0, "P-4 Celeron D (Prescott)" }, + { 15, 4, -1, 15, -1, 1, -1, -1, CELERON , 0, "P-4 Celeron D (Prescott)" }, + { 15, 6, -1, 15, -1, 1, -1, -1, CELERON , 0, "P-4 Celeron D (Cedar Mill)" }, /* -------------------------------------------------- */ /* Intel Core microarchitecture - P6-based */ @@ -214,7 +169,7 @@ const struct match_entry_t cpudb_intel[] = { { 6, 13, -1, -1, -1, 1, -1, -1, MOBILE_PENTIUM_M , 0, "Pentium M (Dothan)" }, { 6, 13, -1, -1, -1, 1, -1, -1, CELERON , 0, "Celeron M" }, - { 6, 12, -1, -1, -1, -1, -1, -1, ATOM , 0, "Unknown Atom" }, + { 6, 12, -1, -1, -1, -1, -1, -1, ATOM_UNKNOWN , 0, "Unknown Atom" }, { 6, 12, -1, -1, -1, -1, -1, -1, ATOM_DIAMONDVILLE , 0, "Atom (Diamondville)" }, { 6, 12, -1, -1, -1, -1, -1, -1, ATOM_SILVERTHORNE , 0, "Atom (Silverthorne)" }, { 6, 12, -1, -1, -1, -1, -1, -1, ATOM_CEDARVIEW , 0, "Atom (Cedarview)" }, @@ -260,57 +215,13 @@ const struct match_entry_t cpudb_intel[] = { { 6, 7, -1, -1, 23, 2, 3072, -1, WOLFDALE , 0, "Wolfdale (Core 2 Duo) 3M" }, { 6, 7, -1, -1, 23, 2, 6144, -1, WOLFDALE , 0, "Wolfdale (Core 2 Duo) 6M" }, { 6, 7, -1, -1, 23, 1, -1, -1, MOBILE_CORE_DUO , 0, "Penryn (Core 2 Duo)" }, + { 6, 7, -1, -1, 23, 2, 1024, -1, PENRYN , 0, "Penryn (Core 2 Duo)" }, { 6, 7, -1, -1, 23, 2, 3072, -1, PENRYN , 0, "Penryn (Core 2 Duo) 3M" }, { 6, 7, -1, -1, 23, 2, 6144, -1, PENRYN , 0, "Penryn (Core 2 Duo) 6M" }, { 6, 7, -1, -1, 23, 4, 2048, -1, QUAD_CORE , 0, "Yorkfield (Core 2 Quad) 2M"}, { 6, 7, -1, -1, 23, 4, 3072, -1, QUAD_CORE , 0, "Yorkfield (Core 2 Quad) 3M"}, { 6, 7, -1, -1, 23, 4, 6144, -1, QUAD_CORE , 0, "Yorkfield (Core 2 Quad) 6M"}, - { 6, 5, -1, -1, 37, 2, -1, -1, NO_CODE , 0, "Unknown Core i3/i5 CPU" }, - { 6, 5, -1, -1, 37, 2, -1, 4096, CORE_I7 , 0, "Arrandale (Core i7)" }, - { 6, 5, -1, -1, 37, 2, -1, 3072, CORE_I5 , 0, "Arrandale (Core i5)" }, - { 6, 5, -1, -1, 37, 2, -1, 4096, CORE_I5 , 0, "Clarkdale (Core i5)" }, - { 6, 5, -1, -1, 37, 4, -1, 8192, CORE_I5 , 0, "Lynnfield (Core i5)" }, - { 6, 5, -1, -1, 37, 2, -1, 3072, CORE_I3 , 0, "Arrandale (Core i3)" }, - { 6, 5, -1, -1, 37, 2, -1, 4096, CORE_I3 , 0, "Clarkdale (Core i3)" }, - - { 6, 10, -1, -1, 42, -1, -1, -1, NO_CODE , 0, "Unknown Sandy Bridge" }, - { 6, 10, -1, -1, 42, -1, -1, -1, CORE_I7 , 0, "Sandy Bridge i7" }, - { 6, 10, -1, -1, 42, 4, -1, -1, CORE_I7 , 0, "Sandy Bridge (Core i7)" }, - { 6, 10, -1, -1, 42, 4, -1, -1, CORE_I5 , 0, "Sandy Bridge (Core i5)" }, - { 6, 10, -1, -1, 42, 2, -1, -1, CORE_I3 , 0, "Sandy Bridge (Core i3)" }, - { 6, 10, -1, -1, 42, 1, -1, -1, CELERON , 0, "Celeron (Sandy Bridge)" }, - { 6, 10, -1, -1, 42, 2, -1, -1, CELERON , 0, "Celeron (Sandy Bridge)" }, - { 6, 10, -1, -1, 42, 2, -1, -1, PENTIUM , 0, "Pentium (Sandy Bridge)" }, - - { 6, 10, -1, -1, 26, 1, -1, -1, CORE_I7 , 0, "Intel Core i7" }, - { 6, 10, -1, -1, 26, 4, -1, -1, CORE_I7 , 0, "Bloomfield (Core i7)" }, - { 6, 10, -1, -1, 30, 4, -1, -1, CORE_I7 , 0, "Lynnfield (Core i7)" }, - { 6, 10, -1, -1, 26, 4, -1, -1, XEON_I7 , 0, "Xeon (Bloomfield)" }, - - { 6, 10, -1, -1, 26, 4, -1, -1, XEON_GAINESTOWN , 0, "Xeon (Gainestown)" }, - { 6, 10, -1, -1, 26, 4, -1, 4096, XEON_GAINESTOWN , 0, "Xeon (Gainestown) 4M" }, - { 6, 10, -1, -1, 26, 4, -1, 8192, XEON_GAINESTOWN , 0, "Xeon (Gainestown) 8M" }, - - { 6, 12, -1, -1, 44, -1, -1, -1, XEON_WESTMERE , 0, "Xeon (Westmere-based)" }, - { 6, 12, -1, -1, 44, 4, -1, 12288, CORE_I7 , 0, "Gulftown (Core i7)" }, - { 6, 12, -1, -1, 44, -1, -1, 12288, XEON_WESTMERE , 0, "Xeon (Gulftown)" }, - - { 6, 13, -1, -1, 45, -1, -1, -1, XEON , 0, "Xeon (Sandy Bridge)" }, - - { 6, 13, -1, -1, 45, -1, -1, -1, CORE_I7 , 0, "Sandy Bridge-E (Core i7)" }, - { 6, 13, -1, -1, 45, -1, -1, -1, CORE_I5 , 0, "Sandy Bridge-E (Core i5)" }, - { 6, 13, -1, -1, 45, -1, -1, -1, CORE_I3 , 0, "Sandy Bridge-E (Core i3)" }, - - { 6, 10, -1, -1, 58, 4, -1, -1, CORE_IVY7 , 0, "Ivy Bridge (Core i7)" }, - { 6, 10, -1, -1, 58, 4, -1, -1, CORE_IVY5 , 0, "Ivy Bridge (Core i5)" }, - { 6, 10, -1, -1, 58, 2, -1, -1, CORE_IVY3 , 0, "Ivy Bridge (Core i3)" }, - - { 6, 12, -1, -1, 60, 4, -1, -1, CORE_HASWELL7 , 0, "Haswell (Core i7)" }, - { 6, 12, -1, -1, 60, 4, -1, -1, CORE_HASWELL5 , 0, "Haswell (Core i5)" }, - { 6, 12, -1, -1, 60, 2, -1, -1, CORE_HASWELL3 , 0, "Haswell (Core i3)" }, - - /* Core microarchitecture-based Xeons: */ { 6, 14, -1, -1, 14, 1, -1, -1, XEON , 0, "Xeon LV" }, { 6, 15, -1, -1, 15, 2, 4096, -1, XEON , _5100, "Xeon (Woodcrest)" }, @@ -324,6 +235,85 @@ const struct match_entry_t cpudb_intel[] = { { 6, 7, -1, -1, 23, 4, 3072, -1, XEON , X3300, "Xeon (Yorkfield/3M)" }, { 6, 7, -1, -1, 23, 4, 6144, -1, XEON , X3300, "Xeon (Yorkfield/6M)" }, + /* Nehalem CPUs (45nm): */ + { 6, 10, -1, -1, 26, 4, -1, -1, XEON_GAINESTOWN , 0, "Gainestown (Xeon)" }, + { 6, 10, -1, -1, 26, 4, -1, 4096, XEON_GAINESTOWN , 0, "Gainestown 4M (Xeon)" }, + { 6, 10, -1, -1, 26, 4, -1, 8192, XEON_GAINESTOWN , 0, "Gainestown 8M (Xeon)" }, + { 6, 10, -1, -1, 26, 4, -1, -1, XEON_I7 , 0, "Bloomfield (Xeon)" }, + { 6, 10, -1, -1, 26, 4, -1, -1, CORE_I7 , 0, "Bloomfield (Core i7)" }, + { 6, 10, -1, -1, 30, 4, -1, -1, CORE_I7 , 0, "Lynnfield (Core i7)" }, + { 6, 5, -1, -1, 37, 4, -1, 8192, CORE_I5 , 0, "Lynnfield (Core i5)" }, + + /* Westmere CPUs (32nm): */ + { 6, 5, -1, -1, 37, 2, -1, -1, NO_CODE , 0, "Unknown Core i3/i5" }, + { 6, 12, -1, -1, 44, -1, -1, -1, XEON_WESTMERE , 0, "Westmere (Xeon)" }, + { 6, 12, -1, -1, 44, -1, -1, 12288, XEON_WESTMERE , 0, "Gulftown (Xeon)" }, + { 6, 12, -1, -1, 44, 4, -1, 12288, CORE_I7 , 0, "Gulftown (Core i7)" }, + { 6, 5, -1, -1, 37, 2, -1, 4096, CORE_I5 , 0, "Clarkdale (Core i5)" }, + { 6, 5, -1, -1, 37, 2, -1, 4096, CORE_I3 , 0, "Clarkdale (Core i3)" }, + { 6, 5, -1, -1, 37, 2, -1, -1, PENTIUM , 0, "Arrandale" }, + { 6, 5, -1, -1, 37, 2, -1, 4096, CORE_I7 , 0, "Arrandale (Core i7)" }, + { 6, 5, -1, -1, 37, 2, -1, 3072, CORE_I5 , 0, "Arrandale (Core i5)" }, + { 6, 5, -1, -1, 37, 2, -1, 3072, CORE_I3 , 0, "Arrandale (Core i3)" }, + + /* Sandy Bridge CPUs (32nm): */ + { 6, 10, -1, -1, 42, -1, -1, -1, NO_CODE , 0, "Unknown Sandy Bridge" }, + { 6, 10, -1, -1, 42, -1, -1, -1, XEON , 0, "Sandy Bridge (Xeon)" }, + { 6, 10, -1, -1, 42, -1, -1, -1, CORE_I7 , 0, "Sandy Bridge (Core i7)" }, + { 6, 10, -1, -1, 42, 4, -1, -1, CORE_I7 , 0, "Sandy Bridge (Core i7)" }, + { 6, 10, -1, -1, 42, 4, -1, -1, CORE_I5 , 0, "Sandy Bridge (Core i5)" }, + { 6, 10, -1, -1, 42, 2, -1, -1, CORE_I3 , 0, "Sandy Bridge (Core i3)" }, + { 6, 10, -1, -1, 42, 2, -1, -1, PENTIUM , 0, "Sandy Bridge (Pentium)" }, + { 6, 10, -1, -1, 42, 1, -1, -1, CELERON , 0, "Sandy Bridge (Celeron)" }, + { 6, 10, -1, -1, 42, 2, -1, -1, CELERON , 0, "Sandy Bridge (Celeron)" }, + { 6, 13, -1, -1, 45, -1, -1, -1, NO_CODE , 0, "Sandy Bridge-E" }, + { 6, 13, -1, -1, 45, -1, -1, -1, XEON , 0, "Sandy Bridge-E (Xeon)" }, + + /* Ivy Bridge CPUs (22nm): */ + { 6, 10, -1, -1, 58, -1, -1, -1, XEON , 0, "Ivy Bridge (Xeon)" }, + { 6, 10, -1, -1, 58, 4, -1, -1, CORE_IVY7 , 0, "Ivy Bridge (Core i7)" }, + { 6, 10, -1, -1, 58, 4, -1, -1, CORE_IVY5 , 0, "Ivy Bridge (Core i5)" }, + { 6, 10, -1, -1, 58, 2, -1, -1, CORE_IVY3 , 0, "Ivy Bridge (Core i3)" }, + { 6, 10, -1, -1, 58, 2, -1, -1, PENTIUM , 0, "Ivy Bridge (Pentium)" }, + { 6, 10, -1, -1, 58, 1, -1, -1, CELERON , 0, "Ivy Bridge (Celeron)" }, + { 6, 10, -1, -1, 58, 2, -1, -1, CELERON , 0, "Ivy Bridge (Celeron)" }, + { 6, 14, -1, -1, 62, -1, -1, -1, NO_CODE , 0, "Ivy Bridge-E" }, + + /* Haswell CPUs (22nm): */ + { 6, 12, -1, -1, 60, -1, -1, -1, XEON , 0, "Haswell (Xeon)" }, + { 6, 12, -1, -1, 60, 4, -1, -1, CORE_HASWELL7 , 0, "Haswell (Core i7)" }, + { 6, 5, -1, -1, 69, 4, -1, -1, CORE_HASWELL7 , 0, "Haswell (Core i7)" }, + { 6, 12, -1, -1, 60, 4, -1, -1, CORE_HASWELL5 , 0, "Haswell (Core i5)" }, + { 6, 5, -1, -1, 69, 4, -1, -1, CORE_HASWELL5 , 0, "Haswell (Core i5)" }, + { 6, 12, -1, -1, 60, 2, -1, -1, CORE_HASWELL3 , 0, "Haswell (Core i3)" }, + { 6, 5, -1, -1, 69, 2, -1, -1, CORE_HASWELL3 , 0, "Haswell (Core i3)" }, + { 6, 12, -1, -1, 60, 2, -1, -1, PENTIUM , 0, "Haswell (Pentium)" }, + { 6, 12, -1, -1, 60, 2, -1, -1, CELERON , 0, "Haswell (Celeron)" }, + { 6, 12, -1, -1, 60, 1, -1, -1, CELERON , 0, "Haswell (Celeron)" }, + { 6, 15, -1, -1, 63, -1, -1, -1, NO_CODE , 0, "Haswell-E" }, + + /* Broadwell CPUs (14nm): */ + { 6, 7, -1, -1, 71, 4, -1, -1, CORE_BROADWELL7 , 0, "Broadwell (Core i7)" }, + { 6, 7, -1, -1, 71, 4, -1, -1, CORE_BROADWELL5 , 0, "Broadwell (Core i5)" }, + { 6, 13, -1, -1, 61, 4, -1, -1, CORE_BROADWELL7 , 0, "Broadwell-U (Core i7)" }, + { 6, 13, -1, -1, 61, 2, -1, -1, CORE_BROADWELL7 , 0, "Broadwell-U (Core i7)" }, + { 6, 13, -1, -1, 61, 2, -1, -1, CORE_BROADWELL5 , 0, "Broadwell-U (Core i5)" }, + { 6, 13, -1, -1, 61, 2, -1, -1, CORE_BROADWELL3 , 0, "Broadwell-U (Core i3)" }, + { 6, 13, -1, -1, 61, 2, -1, -1, PENTIUM , 0, "Broadwell-U (Pentium)" }, + { 6, 13, -1, -1, 61, 2, -1, -1, CELERON , 0, "Broadwell-U (Celeron)" }, + { 6, 13, -1, -1, 61, 2, -1, -1, NA , 0, "Broadwell-U (Core M)" }, + { 6, 15, -1, -1, 79, 2, -1, -1, CORE_BROADWELL3 , 0, "Broadwell-E (Core i3)" }, + { 6, 15, -1, -1, 79, 2, -1, -1, CORE_BROADWELL5 , 0, "Broadwell-E (Core i5)" }, + { 6, 15, -1, -1, 79, 4, -1, -1, CORE_BROADWELL5 , 0, "Broadwell-E (Core i5)" }, + { 6, 15, -1, -1, 79, 2, -1, -1, CORE_BROADWELL7 , 0, "Broadwell-E (Core i7)" }, + { 6, 15, -1, -1, 79, 4, -1, -1, CORE_BROADWELL7 , 0, "Broadwell-E (Core i7)" }, + + /* Skylake CPUs (14nm): */ + { 6, 14, -1, -1, 94, 4, -1, -1, CORE_BROADWELL7 , 0, "Skylake (Core i7)" }, + { 6, 14, -1, -1, 94, 4, -1, -1, CORE_BROADWELL5 , 0, "Skylake (Core i5)" }, + { 6, 14, -1, -1, 94, 4, -1, -1, CORE_BROADWELL3 , 0, "Skylake (Core i3)" }, + { 6, 14, -1, -1, 94, 4, -1, -1, PENTIUM , 0, "Skylake (Pentium)" }, + /* Itaniums */ { 7, -1, -1, -1, -1, 1, -1, -1, NO_CODE , 0, "Itanium" }, { 15, -1, -1, 16, -1, 1, -1, -1, NO_CODE , 0, "Itanium 2" }, @@ -343,7 +333,6 @@ static void load_intel_features(struct cpu_raw_data_t* raw, struct cpu_id_t* dat { 31, CPU_FEATURE_PBE }, }; const struct feature_map_t matchtable_ecx1[] = { - { 1, CPU_FEATURE_PCLMUL }, { 2, CPU_FEATURE_DTS64 }, { 4, CPU_FEATURE_DS_CPL }, { 5, CPU_FEATURE_VMX }, @@ -354,37 +343,45 @@ static void load_intel_features(struct cpu_raw_data_t* raw, struct cpu_id_t* dat { 14, CPU_FEATURE_XTPR }, { 15, CPU_FEATURE_PDCM }, { 18, CPU_FEATURE_DCA }, - { 20, CPU_FEATURE_SSE4_2 }, - { 22, CPU_FEATURE_MOVBE }, - { 25, CPU_FEATURE_AES }, - { 26, CPU_FEATURE_XSAVE }, - { 27, CPU_FEATURE_OSXSAVE }, - { 28, CPU_FEATURE_AVX }, - { 30, CPU_FEATURE_RDRAND }, - }; - const struct feature_map_t matchtable_ebx7[] = { - { 5, CPU_FEATURE_AVX2 }, + { 21, CPU_FEATURE_X2APIC }, }; const struct feature_map_t matchtable_edx81[] = { { 20, CPU_FEATURE_XD }, }; + const struct feature_map_t matchtable_ebx7[] = { + { 2, CPU_FEATURE_SGX }, + { 4, CPU_FEATURE_HLE }, + { 11, CPU_FEATURE_RTM }, + { 16, CPU_FEATURE_AVX512F }, + { 17, CPU_FEATURE_AVX512DQ }, + { 18, CPU_FEATURE_RDSEED }, + { 19, CPU_FEATURE_ADX }, + { 26, CPU_FEATURE_AVX512PF }, + { 27, CPU_FEATURE_AVX512ER }, + { 28, CPU_FEATURE_AVX512CD }, + { 29, CPU_FEATURE_SHA_NI }, + { 30, CPU_FEATURE_AVX512BW }, + { 31, CPU_FEATURE_AVX512VL }, + }; if (raw->basic_cpuid[0][0] >= 1) { match_features(matchtable_edx1, COUNT_OF(matchtable_edx1), raw->basic_cpuid[1][3], data); match_features(matchtable_ecx1, COUNT_OF(matchtable_ecx1), raw->basic_cpuid[1][2], data); } - if (raw->basic_cpuid[0][0] >= 7) { - match_features(matchtable_ebx7, COUNT_OF(matchtable_ebx7), raw->basic_cpuid[7][1], data); - } if (raw->ext_cpuid[0][0] >= 1) { match_features(matchtable_edx81, COUNT_OF(matchtable_edx81), raw->ext_cpuid[1][3], data); } + // detect TSX/AVX512: + if (raw->basic_cpuid[0][0] >= 7) { + match_features(matchtable_ebx7, COUNT_OF(matchtable_ebx7), raw->basic_cpuid[7][1], data); + } } enum _cache_type_t { L1I, L1D, L2, - L3 + L3, + L4 }; typedef enum _cache_type_t cache_type_t; @@ -409,6 +406,12 @@ static void check_case(uint8_t on, cache_type_t cache, int size, int assoc, int data->l3_cache = size; data->l3_assoc = assoc; data->l3_cacheline = linesize; + break; + case L4: + data->l4_cache = size; + data->l4_assoc = assoc; + data->l4_cacheline = linesize; + break; default: break; } @@ -529,6 +532,8 @@ static void decode_intel_deterministic_cache_info(struct cpu_raw_data_t* raw, type = L2; else if (level == 3 && typenumber == 3) type = L3; + else if (level == 4 && typenumber == 3) + type = L4; else { warnf("deterministic_cache: unknown level/typenumber combo (%d/%d), cannot\n", level, typenumber); warnf("deterministic_cache: recognize cache type\n"); @@ -561,8 +566,12 @@ static int decode_intel_extended_topology(struct cpu_raw_data_t* raw, } } if (num_smt == -1 || num_core == -1) return 0; - data->num_cores = num_core / num_smt; data->num_logical_cpus = num_core; + data->num_cores = num_core / num_smt; + // make sure num_cores is at least 1. In VMs, the CPUID instruction + // is rigged and may give nonsensical results, but we should at least + // avoid outputs like data->num_cores == 0. + if (data->num_cores <= 0) data->num_cores = 1; return 1; } @@ -587,7 +596,9 @@ static void decode_intel_number_of_cores(struct cpu_raw_data_t* raw, data->num_logical_cpus = logical_cpus; } else { data->num_cores = 1; - data->num_logical_cpus = (logical_cpus >= 2 ? logical_cpus : 2); + data->num_logical_cpus = (logical_cpus >= 1 ? logical_cpus : 1); + if (data->num_logical_cpus == 1) + data->flags[CPU_FEATURE_HT] = 0; } } else { data->num_cores = data->num_logical_cpus = 1; @@ -596,7 +607,7 @@ static void decode_intel_number_of_cores(struct cpu_raw_data_t* raw, static intel_code_t get_brand_code(struct cpu_id_t* data) { - intel_code_t code = NO_CODE; + intel_code_t code = (intel_code_t) NO_CODE; int i, need_matchtable = 1, core_ix_base = 0; const char* bs = data->brand_str; const char* s; @@ -607,15 +618,16 @@ static intel_code_t get_brand_code(struct cpu_id_t* data) { CELERON, "Celeron" }, { MOBILE_PENTIUM_M, "Pentium(R) M" }, { CORE_SOLO, "Pentium(R) Dual CPU" }, + { CORE_SOLO, "Pentium(R) Dual-Core" }, { PENTIUM_D, "Pentium(R) D" }, { PENTIUM, "Pentium" }, { CORE_SOLO, "Genuine Intel(R) CPU" }, { CORE_SOLO, "Intel(R) Core(TM)" }, { ATOM_DIAMONDVILLE, "Atom(TM) CPU [N ][23]## " }, { ATOM_SILVERTHORNE, "Atom(TM) CPU Z" }, - { ATOM_PINEVIEW, "Atom(TM) CPU D" }, - { ATOM_CEDARVIEW, "Atom(TM) CPU N####" }, - { ATOM, "Atom(TM) CPU" }, + { ATOM_PINEVIEW, "Atom(TM) CPU [ND][45]## " }, + { ATOM_CEDARVIEW, "Atom(TM) CPU [ND]#### " }, + { ATOM_UNKNOWN, "Atom(TM) CPU" }, }; if (strstr(bs, "Mobile")) { @@ -637,6 +649,9 @@ static intel_code_t get_brand_code(struct cpu_id_t* data) /* if it has FMA, then it is at least Haswell */ if (data->flags[CPU_FEATURE_FMA3]) core_ix_base = CORE_HASWELL3; + /* if it has RTM, then it is at least a Broadwell-E or Skylake */ + if (data->flags[CPU_FEATURE_RDSEED]) + core_ix_base = CORE_BROADWELL3; switch (bs[i + 9]) { case '3': code = core_ix_base + 0; break; @@ -659,7 +674,8 @@ static intel_code_t get_brand_code(struct cpu_id_t* data) code = XEON_GAINESTOWN; else if (match_pattern(bs, "[ELXW]56##")) code = XEON_WESTMERE; - else if (data->l3_cache > 0) + else if (data->l3_cache > 0 && data->family == 16) + /* restrict by family, since later Xeons also have L3 ... */ code = XEON_IRWIN; } if (code == XEONMP && data->l3_cache > 0) @@ -770,8 +786,75 @@ static intel_model_t get_model_code(struct cpu_id_t* data) #undef HAVE } -int cpuid_identify_intel(struct cpu_raw_data_t* raw, struct cpu_id_t* data) +static void decode_intel_sgx_features(const struct cpu_raw_data_t* raw, struct cpu_id_t* data) { + struct cpu_epc_t epc; + int i; + + if (raw->basic_cpuid[0][0] < 0x12) return; // no 12h leaf + if (raw->basic_cpuid[0x12][0] == 0) return; // no sub-leafs available, probably it's disabled by BIOS + + // decode sub-leaf 0: + if (raw->basic_cpuid[0x12][0] & 1) data->sgx.flags[INTEL_SGX1] = 1; + if (raw->basic_cpuid[0x12][0] & 2) data->sgx.flags[INTEL_SGX2] = 1; + if (data->sgx.flags[INTEL_SGX1] || data->sgx.flags[INTEL_SGX2]) + data->sgx.present = 1; + data->sgx.misc_select = raw->basic_cpuid[0x12][1]; + data->sgx.max_enclave_32bit = (raw->basic_cpuid[0x12][3] ) & 0xff; + data->sgx.max_enclave_64bit = (raw->basic_cpuid[0x12][3] >> 8) & 0xff; + + // decode sub-leaf 1: + data->sgx.secs_attributes = raw->intel_fn12h[1][0] | (((uint64_t) raw->intel_fn12h[1][1]) << 32); + data->sgx.secs_xfrm = raw->intel_fn12h[1][2] | (((uint64_t) raw->intel_fn12h[1][3]) << 32); + + // decode higher-order subleafs, whenever present: + data->sgx.num_epc_sections = -1; + for (i = 0; i < 1000000; i++) { + epc = cpuid_get_epc(i, raw); + if (epc.length == 0) { + debugf(2, "SGX: epc section request for %d returned null, no more EPC sections.\n", i); + data->sgx.num_epc_sections = i; + break; + } + } + if (data->sgx.num_epc_sections == -1) { + debugf(1, "SGX: warning: seems to be infinitude of EPC sections.\n"); + data->sgx.num_epc_sections = 1000000; + } +} + +struct cpu_epc_t cpuid_get_epc(int index, const struct cpu_raw_data_t* raw) +{ + uint32_t regs[4]; + struct cpu_epc_t retval = {0, 0}; + if (raw && index < MAX_INTELFN12H_LEVEL - 2) { + // this was queried already, use the data: + memcpy(regs, raw->intel_fn12h[2 + index], sizeof(regs)); + } else { + // query this ourselves: + regs[0] = 0x12; + regs[2] = 2 + index; + regs[1] = regs[3] = 0; + cpu_exec_cpuid_ext(regs); + } + + // decode values: + if ((regs[0] & 0xf) == 0x1) { + retval.start_addr |= (regs[0] & 0xfffff000); // bits [12, 32) -> bits [12, 32) + retval.start_addr |= ((uint64_t) (regs[1] & 0x000fffff)) << 32; // bits [0, 20) -> bits [32, 52) + retval.length |= (regs[2] & 0xfffff000); // bits [12, 32) -> bits [12, 32) + retval.length |= ((uint64_t) (regs[3] & 0x000fffff)) << 32; // bits [0, 20) -> bits [32, 52) + } + return retval; +} + +int cpuid_identify_intel(struct cpu_raw_data_t* raw, struct cpu_id_t* data, struct internal_id_info_t* internal) +{ + intel_code_t brand_code; + intel_model_t model_code; + int i; + char* brand_code_str = NULL; + load_intel_features(raw, data); if (raw->basic_cpuid[0][0] >= 4) { /* Deterministic way is preferred, being more generic */ @@ -780,8 +863,31 @@ int cpuid_identify_intel(struct cpu_raw_data_t* raw, struct cpu_id_t* data) decode_intel_oldstyle_cache_info(raw, data); } decode_intel_number_of_cores(raw, data); - match_cpu_codename(cpudb_intel, COUNT_OF(cpudb_intel), data, - get_brand_code(data), get_model_code(data)); + + brand_code = get_brand_code(data); + model_code = get_model_code(data); + for (i = 0; i < COUNT_OF(intel_bcode_str); i++) { + if (brand_code == intel_bcode_str[i].code) { + brand_code_str = intel_bcode_str[i].str; + break; + } + } + if (brand_code_str) + debugf(2, "Detected Intel brand code: %d (%s)\n", brand_code, brand_code_str); + else + debugf(2, "Detected Intel brand code: %d\n", brand_code); + debugf(2, "Detected Intel model code: %d\n", model_code); + + internal->code.intel = brand_code; + + if (data->flags[CPU_FEATURE_SGX]) { + debugf(2, "SGX seems to be present, decoding...\n"); + // if SGX is indicated by the CPU, verify its presence: + decode_intel_sgx_features(raw, data); + } + + internal->score = match_cpu_codename(cpudb_intel, COUNT_OF(cpudb_intel), data, + brand_code, model_code); return 0; } diff --git a/contrib/libcpuid/include/libcpuid/recog_intel.h b/contrib/libcpuid/include/libcpuid/recog_intel.h index 67279373271..b99c783bf43 100644 --- a/contrib/libcpuid/include/libcpuid/recog_intel.h +++ b/contrib/libcpuid/include/libcpuid/recog_intel.h @@ -26,7 +26,7 @@ #ifndef __RECOG_INTEL_H__ #define __RECOG_INTEL_H__ -int cpuid_identify_intel(struct cpu_raw_data_t* raw, struct cpu_id_t* data); +int cpuid_identify_intel(struct cpu_raw_data_t* raw, struct cpu_id_t* data, struct internal_id_info_t* internal); void cpuid_get_list_intel(struct cpu_list_t* list); #endif /*__RECOG_INTEL_H__*/