2
0
Эх сурвалжийг харах

Update LibCpuId to 0.4.0. Closes #1819.

Lasse Öörni 8 жил өмнө
parent
commit
6a490f05f2

+ 1 - 1
Docs/Urho3D.dox

@@ -197,7 +197,7 @@ Urho3D uses the following third-party libraries:
 - GLEW 1.13.0 (http://glew.sourceforge.net)
 - GLEW 1.13.0 (http://glew.sourceforge.net)
 - jo_jpeg 1.52 (http://www.jonolick.com/uploads/7/9/2/1/7921194/jo_jpeg.cpp)
 - jo_jpeg 1.52 (http://www.jonolick.com/uploads/7/9/2/1/7921194/jo_jpeg.cpp)
 - kNet (https://github.com/juj/kNet)
 - kNet (https://github.com/juj/kNet)
-- libcpuid 0.2.2 (https://github.com/anrieff/libcpuid)
+- libcpuid 0.4.0 (https://github.com/anrieff/libcpuid)
 - Lua 5.1 (https://www.lua.org)
 - Lua 5.1 (https://www.lua.org)
 - LuaJIT 2.1.0+ (http://www.luajit.org)
 - LuaJIT 2.1.0+ (http://www.luajit.org)
 - LZ4 r131 (https://github.com/Cyan4973/lz4)
 - LZ4 r131 (https://github.com/Cyan4973/lz4)

+ 1 - 1
README.md

@@ -160,7 +160,7 @@ Urho3D uses the following third-party libraries:
 - GLEW 1.13.0 (http://glew.sourceforge.net)
 - GLEW 1.13.0 (http://glew.sourceforge.net)
 - jo_jpeg 1.52 (http://www.jonolick.com/uploads/7/9/2/1/7921194/jo_jpeg.cpp)
 - jo_jpeg 1.52 (http://www.jonolick.com/uploads/7/9/2/1/7921194/jo_jpeg.cpp)
 - kNet (https://github.com/juj/kNet)
 - kNet (https://github.com/juj/kNet)
-- libcpuid 0.2.2 (https://github.com/anrieff/libcpuid)
+- libcpuid 0.4.0 (https://github.com/anrieff/libcpuid)
 - Lua 5.1 (https://www.lua.org)
 - Lua 5.1 (https://www.lua.org)
 - LuaJIT 2.1.0+ (http://www.luajit.org)
 - LuaJIT 2.1.0+ (http://www.luajit.org)
 - LZ4 r131 (https://github.com/Cyan4973/lz4)
 - LZ4 r131 (https://github.com/Cyan4973/lz4)

+ 2 - 0
Source/ThirdParty/LibCpuId/CMakeLists.txt

@@ -23,6 +23,8 @@
 # Define target name
 # Define target name
 set (TARGET_NAME LibCpuId)
 set (TARGET_NAME LibCpuId)
 
 
+add_definitions (-DVERSION="0.4.0")
+
 # Define generated source files
 # Define generated source files
 if (MSVC AND URHO3D_64BIT)
 if (MSVC AND URHO3D_64BIT)
     enable_language (ASM_MASM)
     enable_language (ASM_MASM)

+ 28 - 2
Source/ThirdParty/LibCpuId/Readme.md

@@ -2,8 +2,11 @@ libcpuid
 ========
 ========
 
 
 libcpuid provides CPU identification for the x86 (and x86_64).
 libcpuid provides CPU identification for the x86 (and x86_64).
-For details about the programming API, please see the docs
-on the project's site (http://libcpuid.sourceforge.net/)
+For details about the programming API, you might want to 
+take a look at the project's website on sourceforge
+(http://libcpuid.sourceforge.net/). There you'd find a short
+[tutorial](http://libcpuid.sf.net/documentation.html), as well
+as the full [API reference](http://libcpuid.sf.net/doxy).
 
 
 Configuring after checkout
 Configuring after checkout
 --------------------------
 --------------------------
@@ -25,6 +28,29 @@ the library.
 `make dist` will create a tarball (with "configure" inside) with the
 `make dist` will create a tarball (with "configure" inside) with the
 sources.
 sources.
 
 
+Testing
+-------
+
+After any change to the detection routines or match tables, it's always
+a good idea to run `make test`. If some test fails, and you're confident
+that the test is wrong and needs fixing, run `make fix-tests`.
+
+You can also add a new test (which is basically a file containing
+the raw CPUID data and the expected decoded items) by using 
+`tests/create_test.py`. The workflow there is as follows:
+
+1. Run "cpuid_tool" with no arguments. It will tell you that it
+   has written a pair of files, raw.txt and report.txt. Ensure
+   that report.txt contains meaningful data.
+2. Run "tests/create_test.py raw.txt report.txt > «my-cpu».test"
+3. Use a proper descriptive name for the test (look into tests/amd
+   and tests/intel to get an idea) and copy your test file to an
+   appropriate place within the tests directory hierarchy.
+
+For non-developers, who still want to contribute tests for the project,
+use [this page](http://libcpuid.sourceforge.net/bugreport.php) to report
+misdetections or new CPUs that libcpuid doesn't handle well yet.
+
 Users
 Users
 -----
 -----
 
 

+ 65 - 0
Source/ThirdParty/LibCpuId/src/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),
+	

+ 4 - 2
Source/ThirdParty/LibCpuId/src/asm-bits.c

@@ -214,7 +214,8 @@ void busy_sse_loop(int cycles)
 		"	xorps	%%xmm6,	%%xmm6\n"
 		"	xorps	%%xmm6,	%%xmm6\n"
 		"	xorps	%%xmm7,	%%xmm7\n"
 		"	xorps	%%xmm7,	%%xmm7\n"
 		XALIGN
 		XALIGN
-		".bsLoop:\n"
+		/* ".bsLoop:\n" */
+		"1:\n"
 		// 0:
 		// 0:
 		"	addps	%%xmm1, %%xmm0\n"
 		"	addps	%%xmm1, %%xmm0\n"
 		"	addps	%%xmm2, %%xmm1\n"
 		"	addps	%%xmm2, %%xmm1\n"
@@ -505,7 +506,8 @@ void busy_sse_loop(int cycles)
 		"	addps	%%xmm0, %%xmm7\n"
 		"	addps	%%xmm0, %%xmm7\n"
 		
 		
 		"	dec	%%eax\n"
 		"	dec	%%eax\n"
-		"	jnz	.bsLoop\n"
+		/* "jnz	.bsLoop\n" */
+		"	jnz	1b\n"
 		::"a"(cycles)
 		::"a"(cycles)
 	);
 	);
 #else
 #else

+ 62 - 12
Source/ThirdParty/LibCpuId/src/cpuid_main.c

@@ -24,6 +24,7 @@
  * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
  * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
  */
  */
 #include "libcpuid.h"
 #include "libcpuid.h"
+#include "libcpuid_internal.h"
 #include "recog_intel.h"
 #include "recog_intel.h"
 #include "recog_amd.h"
 #include "recog_amd.h"
 #include "asm-bits.h"
 #include "asm-bits.h"
@@ -53,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)
 static void cpu_id_t_constructor(struct cpu_id_t* id)
 {
 {
 	memset(id, 0, sizeof(struct cpu_id_t));
 	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;
 	id->sse_size = -1;
 }
 }
 
 
@@ -125,6 +126,7 @@ static int get_total_cpus(void)
 #endif
 #endif
 
 
 #if defined __FreeBSD__ || defined __OpenBSD__ || defined __NetBSD__ || defined __bsdi__ || defined __QNX__
 #if defined __FreeBSD__ || defined __OpenBSD__ || defined __NetBSD__ || defined __bsdi__ || defined __QNX__
+#include <sys/types.h>
 #include <sys/sysctl.h>
 #include <sys/sysctl.h>
 
 
 static int get_total_cpus(void)
 static int get_total_cpus(void)
@@ -182,15 +184,21 @@ static void load_features_common(struct cpu_raw_data_t* raw, struct cpu_id_t* da
 	};
 	};
 	const struct feature_map_t matchtable_ecx1[] = {
 	const struct feature_map_t matchtable_ecx1[] = {
 		{  0, CPU_FEATURE_PNI },
 		{  0, CPU_FEATURE_PNI },
+		{  1, CPU_FEATURE_PCLMUL },
 		{  3, CPU_FEATURE_MONITOR },
 		{  3, CPU_FEATURE_MONITOR },
 		{  9, CPU_FEATURE_SSSE3 },
 		{  9, CPU_FEATURE_SSSE3 },
 		{ 12, CPU_FEATURE_FMA3 },
 		{ 12, CPU_FEATURE_FMA3 },
 		{ 13, CPU_FEATURE_CX16 },
 		{ 13, CPU_FEATURE_CX16 },
 		{ 19, CPU_FEATURE_SSE4_1 },
 		{ 19, CPU_FEATURE_SSE4_1 },
-		{ 21, CPU_FEATURE_X2APIC },
+		{ 20, CPU_FEATURE_SSE4_2 },
+		{ 22, CPU_FEATURE_MOVBE },
 		{ 23, CPU_FEATURE_POPCNT },
 		{ 23, CPU_FEATURE_POPCNT },
+		{ 25, CPU_FEATURE_AES },
+		{ 26, CPU_FEATURE_XSAVE },
+		{ 27, CPU_FEATURE_OSXSAVE },
 		{ 28, CPU_FEATURE_AVX },
 		{ 28, CPU_FEATURE_AVX },
 		{ 29, CPU_FEATURE_F16C },
 		{ 29, CPU_FEATURE_F16C },
+		{ 30, CPU_FEATURE_RDRAND },
 	};
 	};
 	const struct feature_map_t matchtable_ebx7[] = {
 	const struct feature_map_t matchtable_ebx7[] = {
 		{  3, CPU_FEATURE_BMI1 },
 		{  3, CPU_FEATURE_BMI1 },
@@ -366,7 +374,7 @@ int cpuid_get_raw_data(struct cpu_raw_data_t* data)
 		cpu_exec_cpuid(i, data->basic_cpuid[i]);
 		cpu_exec_cpuid(i, data->basic_cpuid[i]);
 	for (i = 0; i < 32; i++)
 	for (i = 0; i < 32; i++)
 		cpu_exec_cpuid(0x80000000 + i, data->ext_cpuid[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]));
 		memset(data->intel_fn4[i], 0, sizeof(data->intel_fn4[i]));
 		data->intel_fn4[i][0] = 4;
 		data->intel_fn4[i][0] = 4;
 		data->intel_fn4[i][2] = i;
 		data->intel_fn4[i][2] = i;
@@ -378,6 +386,18 @@ int cpuid_get_raw_data(struct cpu_raw_data_t* data)
 		data->intel_fn11[i][2] = i;
 		data->intel_fn11[i][2] = i;
 		cpu_exec_cpuid_ext(data->intel_fn11[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);
 	return set_error(ERR_OK);
 }
 }
 
 
@@ -409,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,
 		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][0], data->intel_fn11[i][1],
 			data->intel_fn11[i][2], data->intel_fn11[i][3]);
 			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, ""))
 	if (strcmp(filename, ""))
 		fclose(f);
 		fclose(f);
@@ -453,10 +481,12 @@ int cpuid_deserialize_raw_data(struct cpu_raw_data_t* data, const char* filename
 			recognized = 1;
 			recognized = 1;
 		}
 		}
 		syntax = 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) {
 		if (!syntax) {
 			warnf("Error: %s:%d: Syntax error\n", filename, cur_line);
 			warnf("Error: %s:%d: Syntax error\n", filename, cur_line);
 			fclose(f);
 			fclose(f);
@@ -472,7 +502,7 @@ int cpuid_deserialize_raw_data(struct cpu_raw_data_t* data, const char* filename
 	return set_error(ERR_OK);
 	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;
 	int r;
 	struct cpu_raw_data_t myraw;
 	struct cpu_raw_data_t myraw;
@@ -486,10 +516,10 @@ int cpu_identify(struct cpu_raw_data_t* raw, struct cpu_id_t* data)
 		return set_error(r);
 		return set_error(r);
 	switch (data->vendor) {
 	switch (data->vendor) {
 		case VENDOR_INTEL:
 		case VENDOR_INTEL:
-			r = cpuid_identify_intel(raw, data);
+			r = cpuid_identify_intel(raw, data, internal);
 			break;
 			break;
 		case VENDOR_AMD:
 		case VENDOR_AMD:
-			r = cpuid_identify_amd(raw, data);
+			r = cpuid_identify_amd(raw, data, internal);
 			break;
 			break;
 		default:
 		default:
 			break;
 			break;
@@ -497,6 +527,12 @@ int cpu_identify(struct cpu_raw_data_t* raw, struct cpu_id_t* data)
 	return set_error(r);
 	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 char* cpu_feature_str(cpu_feature_t feature)
 {
 {
 	const struct { cpu_feature_t feature; const char* name; }
 	const struct { cpu_feature_t feature; const char* name; }
@@ -598,6 +634,19 @@ const char* cpu_feature_str(cpu_feature_t feature)
 		{ CPU_FEATURE_AVX2, "avx2" },
 		{ CPU_FEATURE_AVX2, "avx2" },
 		{ CPU_FEATURE_BMI1, "bmi1" },
 		{ CPU_FEATURE_BMI1, "bmi1" },
 		{ CPU_FEATURE_BMI2, "bmi2" },
 		{ 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);
 	unsigned i, n = COUNT_OF(matchtable);
 	if (n != NUM_CPU_FEATURES) {
 	if (n != NUM_CPU_FEATURES) {
@@ -629,6 +678,7 @@ const char* cpuid_error(void)
 		{ ERR_INVMSR   , "Invalid MSR"},
 		{ ERR_INVMSR   , "Invalid MSR"},
 		{ ERR_INVCNB   , "Invalid core number"},
 		{ ERR_INVCNB   , "Invalid core number"},
 		{ ERR_HANDLE_R , "Error on handle read"},
 		{ ERR_HANDLE_R , "Error on handle read"},
+		{ ERR_INVRANGE , "Invalid given range"},
 	};
 	};
 	unsigned i;
 	unsigned i;
 	for (i = 0; i < COUNT_OF(matchtable); i++)
 	for (i = 0; i < COUNT_OF(matchtable); i++)

+ 83 - 0
Source/ThirdParty/LibCpuId/src/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),
+	

+ 342 - 31
Source/ThirdParty/LibCpuId/src/libcpuid.h

@@ -23,35 +23,40 @@
  * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
  * (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 SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
  */
  */
-
-// Modified by Lasse Oorni for Urho3D: removed the MSR specific code
-
 #ifndef __LIBCPUID_H__
 #ifndef __LIBCPUID_H__
 #define __LIBCPUID_H__
 #define __LIBCPUID_H__
 /**
 /**
- * @File     libcpuid.h
- * @Author   Veselin Georgiev
- * @Date     Oct 2008
- * @Version  0.2.2
+ * \file     libcpuid.h
+ * \author   Veselin Georgiev
+ * \date     Oct 2008
+ * \version  0.4.0
  *
  *
  * Version history:
  * 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.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.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
 /** @mainpage A simple libcpuid introduction
@@ -64,6 +69,15 @@
  * To fetch the CPUID info needed for CPU identification, use
  * To fetch the CPUID info needed for CPU identification, use
  *   \ref cpuid_get_raw_data <br>
  *   \ref cpuid_get_raw_data <br>
  * To make sense of that data (decode, extract features), use \ref cpu_identify <br>
  * To make sense of that data (decode, extract features), use \ref cpu_identify <br>
+ * 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. <br>
+ * 
+ * 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.
  * </p>
  * </p>
  */
  */
 
 
@@ -80,7 +94,6 @@
 extern "C" {
 extern "C" {
 #endif
 #endif
 
 
-#define VERSION "0.2.2"
 /**
 /**
  * @brief CPU vendor, as guessed from the Vendor String.
  * @brief CPU vendor, as guessed from the Vendor String.
  */
  */
@@ -124,6 +137,81 @@ struct cpu_raw_data_t {
 	    enumeration leaf), this stores the result of CPUID with 
 	    enumeration leaf), this stores the result of CPUID with 
 	    eax = 11 and ecx = 0, 1, 2... */
 	    eax = 11 and ecx = 0, 1, 2... */
 	uint32_t intel_fn11[MAX_INTELFN11_LEVEL][4];
 	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;
 };
 };
 
 
 /**
 /**
@@ -141,7 +229,8 @@ struct cpu_id_t {
 	
 	
 	/**
 	/**
 	 * contain CPU flags. Used to test for features. See
 	 * 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];
 	uint8_t flags[CPU_FLAGS_MAX];
 	
 	
@@ -172,11 +261,17 @@ struct cpu_id_t {
 	
 	
 	/**
 	/**
 	 * The total number of logical processors.
 	 * 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}
 	 * 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
 	 * If you're writing a multithreaded program and you want to run it on
 	 * all CPUs, this is the number of threads you need.
 	 * 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;
 	int32_t total_logical_cpus;
 	
 	
@@ -202,6 +297,9 @@ struct cpu_id_t {
 	
 	
 	/** L3 cache size in KB. Zero on most systems */
 	/** L3 cache size in KB. Zero on most systems */
 	int32_t l3_cache;
 	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 */
 	/** Cache associativity for the L1 data cache. -1 if undetermined */
 	int32_t l1_assoc;
 	int32_t l1_assoc;
@@ -211,6 +309,9 @@ struct cpu_id_t {
 	
 	
 	/** Cache associativity for the L3 cache. -1 if undetermined */
 	/** Cache associativity for the L3 cache. -1 if undetermined */
 	int32_t l3_assoc;
 	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 */
 	/** Cache-line size for L1 data cache. -1 if undetermined */
 	int32_t l1_cacheline;
 	int32_t l1_cacheline;
@@ -221,6 +322,9 @@ struct cpu_id_t {
 	/** Cache-line size for L3 cache. -1 if undetermined */
 	/** Cache-line size for L3 cache. -1 if undetermined */
 	int32_t l3_cacheline;
 	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.<br>
 	 * The brief and human-friendly CPU codename, which was recognized.<br>
 	 * Examples:
 	 * Examples:
@@ -242,9 +346,13 @@ struct cpu_id_t {
 	
 	
 	/**
 	/**
 	 * contain miscellaneous detection information. Used to test about specifics of
 	 * 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];
 	uint8_t detection_hints[CPU_HINTS_MAX];
+	
+	/** contains information about SGX features if the processor, if present */
+	struct cpu_sgx_t sgx;
 };
 };
 
 
 /**
 /**
@@ -365,6 +473,19 @@ typedef enum {
 	CPU_FEATURE_AVX2,	/*!< AVX2 instructions */
 	CPU_FEATURE_AVX2,	/*!< AVX2 instructions */
 	CPU_FEATURE_BMI1,	/*!< BMI1 instructions */
 	CPU_FEATURE_BMI1,	/*!< BMI1 instructions */
 	CPU_FEATURE_BMI2,	/*!< BMI2 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: */
 	/* termination: */
 	NUM_CPU_FEATURES,
 	NUM_CPU_FEATURES,
 } cpu_feature_t;
 } cpu_feature_t;
@@ -380,6 +501,36 @@ typedef enum {
 	NUM_CPU_HINTS,
 	NUM_CPU_HINTS,
 } cpu_hint_t;
 } 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
  * @brief Describes common library error codes
  */
  */
@@ -397,9 +548,10 @@ typedef enum {
 	ERR_NO_PERMS = -10,	/*!< "No permissions to install RDMSR driver" */
 	ERR_NO_PERMS = -10,	/*!< "No permissions to install RDMSR driver" */
 	ERR_EXTRACT  = -11,	/*!< "Cannot extract RDMSR driver (read only media?)" */
 	ERR_EXTRACT  = -11,	/*!< "Cannot extract RDMSR driver (read only media?)" */
 	ERR_HANDLE   = -12,	/*!< "Bad handle" */
 	ERR_HANDLE   = -12,	/*!< "Bad handle" */
-	ERR_INVMSR   = -13,     /*!< "Invalid MSR" */
-	ERR_INVCNB   = -14,     /*!< "Invalid core number" */
-	ERR_HANDLE_R = -15,     /*!< "Error on handle read" */
+	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;
 } cpu_error_t;
 
 
 /**
 /**
@@ -412,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);
 int cpuid_get_total_cpus(void);
 
 
@@ -725,6 +883,32 @@ int cpu_clock_by_ic(int millis, int runs);
  */
  */
 int cpu_clock(void);
 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
  * @brief Returns the libcpuid version
  *
  *
@@ -808,6 +992,133 @@ void cpuid_get_cpu_list(cpu_vendor_t vendor, struct cpu_list_t* list);
  */
  */
 void cpuid_free_cpu_list(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)
+ *
+ * On systems that support it, this function will create a temporary
+ * system driver, that has privileges to execute the RDMSR instruction.
+ * After the driver is created, you can read MSRs by calling \ref cpu_rdmsr
+ *
+ * @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(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)
+ *
+ * If the CPU has MSRs (as indicated by the CPU_FEATURE_MSR flag), you can
+ * read a MSR with the given index by calling this function.
+ *
+ * There are several prerequisites you must do before reading MSRs:
+ * 1) You must ensure the CPU has RDMSR. Check the CPU_FEATURE_MSR flag
+ *    in cpu_id_t::flags
+ * 2) You must ensure that the CPU implements the specific MSR you intend to
+ *    read.
+ * 3) You must open a MSR-reader driver. RDMSR is a privileged instruction and
+ *    needs ring-0 access in order to work. This temporary driver is created
+ *    by calling \ref cpu_msr_driver_open
+ *
+ * @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 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(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. */
+	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,       /*!< 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
+ * @param which - which info field should be returned. A list of
+ *                available information entities is listed in the
+ *                cpu_msrinfo_request_t enum.
+ * @retval - if the requested information is available for the current
+ *           processor model, the respective value is returned.
+ *           if no information is available, or the CPU doesn't support
+ *           the query, the special value CPU_INVALID_VALUE is returned
+ */
+int cpu_msrinfo(struct msr_driver_t* handle, cpu_msrinfo_request_t which);
+#define CPU_INVALID_VALUE 0x3fffffff
+
+/**
+ * @brief Closes an open MSR driver
+ *
+ * This function unloads the MSR driver opened by cpu_msr_driver_open and
+ * frees any resources associated with it.
+ *
+ * @param handle - a handle to the MSR reader driver, as created by
+ *                 cpu_msr_driver_open
+ *
+ * @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_msr_driver_close(struct msr_driver_t* handle);
+
 #ifdef __cplusplus
 #ifdef __cplusplus
 }; /* extern "C" */
 }; /* extern "C" */
 #endif
 #endif

+ 4 - 1
Source/ThirdParty/LibCpuId/src/libcpuid_constants.h

@@ -37,8 +37,11 @@
 #define CPU_FLAGS_MAX		128
 #define CPU_FLAGS_MAX		128
 #define MAX_CPUID_LEVEL		32
 #define MAX_CPUID_LEVEL		32
 #define MAX_EXT_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_INTELFN11_LEVEL	4
+#define MAX_INTELFN12H_LEVEL	4
+#define MAX_INTELFN14H_LEVEL	4
 #define CPU_HINTS_MAX		16
 #define CPU_HINTS_MAX		16
+#define SGX_FLAGS_MAX		14
 
 
 #endif /* __LIBCPUID_CONSTANTS_H__ */
 #endif /* __LIBCPUID_CONSTANTS_H__ */

+ 63 - 0
Source/ThirdParty/LibCpuId/src/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__ */

+ 3 - 2
Source/ThirdParty/LibCpuId/src/libcpuid_util.c

@@ -38,7 +38,7 @@ void match_features(const struct feature_map_t* matchtable, int count, uint32_t
 {
 {
 	int i;
 	int i;
 	for (i = 0; i < count; i++)
 	for (i = 0; i < count; i++)
-		if (reg & (1 << matchtable[i].bit))
+		if (reg & (1u << matchtable[i].bit))
 			data->flags[matchtable[i].feature] = 1;
 			data->flags[matchtable[i].feature] = 1;
 }
 }
 
 
@@ -91,7 +91,7 @@ static int score(const struct match_entry_t* entry, const struct cpu_id_t* data,
 	return res;
 	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)
                         struct cpu_id_t* data, int brand_code, int model_code)
 {
 {
 	int bestscore = -1;
 	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);
 	strcpy(data->cpu_codename, matchtable[bestindex].name);
+	return bestscore;
 }
 }
 
 
 void generic_get_cpu_list(const struct match_entry_t* matchtable, int count,
 void generic_get_cpu_list(const struct match_entry_t* matchtable, int count,

+ 2 - 1
Source/ThirdParty/LibCpuId/src/libcpuid_util.h

@@ -42,7 +42,8 @@ struct match_entry_t {
 	char name[32];
 	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);
                         struct cpu_id_t* data, int brand_code, int model_code);
 
 
 void warnf(const char* format, ...)
 void warnf(const char* format, ...)

+ 38 - 13
Source/ThirdParty/LibCpuId/src/rdtsc.c

@@ -226,33 +226,58 @@ int cpu_clock_measure(int millis, int quad_check)
 	return (results[bi] + results[bj] + _zero) / 2;
 	return (results[bi] + results[bj] + _zero) / 2;
 }
 }
 
 
-int cpu_clock_by_ic(int millis, int runs)
+
+static void adjust_march_ic_multiplier(const struct cpu_id_t* id, int* numerator, int* denom)
 {
 {
-	int max_value = 0, cur_value, i, ri, cycles_inner, cycles_outer, c;
-	struct cpu_id_t* id;
-	uint64_t t0, t1, tl, hz;
-	int multiplier_numerator = 1, multiplier_denom = 1;
-	if (millis <= 0 || runs <= 0) return -2;
-	id = get_cached_cpuid();
-	// if there aren't SSE instructions - we can't run the test at all
-	if (!id || !id->flags[CPU_FEATURE_SSE]) return -1;
+	/*
+	 * 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) {
 	if (id->sse_size < 128) {
 		debugf(1, "SSE execution path is 64-bit\n");
 		debugf(1, "SSE execution path is 64-bit\n");
 		// on a CPU with half SSE unit length, SSE instructions execute at 0.5 IPC;
 		// on a CPU with half SSE unit length, SSE instructions execute at 0.5 IPC;
 		// the resulting value must be multiplied by 2:
 		// the resulting value must be multiplied by 2:
-		multiplier_numerator = 2;
+		*numerator = 2;
 	} else {
 	} else {
 		debugf(1, "SSE execution path is 128-bit\n");
 		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:
+	// Bulldozer or later: assume 1.4 IPC
 	if (id->vendor == VENDOR_AMD && id->ext_family >= 21) {
 	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");
 		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
+		*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;
+	struct cpu_id_t* id;
+	uint64_t t0, t1, tl, hz;
+	int multiplier_numerator = 1, multiplier_denom = 1;
+	if (millis <= 0 || runs <= 0) return -2;
+	id = get_cached_cpuid();
+	// if there aren't SSE instructions - we can't run the test at all
+	if (!id || !id->flags[CPU_FEATURE_SSE]) return -1;
+	//
+	adjust_march_ic_multiplier(id, &multiplier_numerator, &multiplier_denom);
+	//
 	tl = millis * 125; // (*1000 / 8)
 	tl = millis * 125; // (*1000 / 8)
 	cycles_inner = 128;
 	cycles_inner = 128;
 	cycles_outer = 1;
 	cycles_outer = 1;

+ 34 - 48
Source/ThirdParty/LibCpuId/src/recog_amd.c

@@ -28,48 +28,16 @@
 #include <string.h>
 #include <string.h>
 #include <ctype.h>
 #include <ctype.h>
 #include "libcpuid.h"
 #include "libcpuid.h"
-#include "recog_amd.h"
 #include "libcpuid_util.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,
-	FUSION_A,
+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[] = {
 const struct match_entry_t cpudb_amd[] = {
 	{ -1, -1, -1, -1,   -1,   1,    -1,    -1, NO_CODE                 ,     0, "Unknown AMD CPU"               },
 	{ -1, -1, -1, -1,   -1,   1,    -1,    -1, NO_CODE                 ,     0, "Unknown AMD CPU"               },
@@ -147,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,  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_FX               ,     0, "Athlon FX"                     },
 	{ 15, -1, -1, 15,   -1,   1,    -1,    -1, ATHLON_64_FX            ,     0, "Athlon 64 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,   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,   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)"              },
 	{ 15, -1, -1, 15,   -1,   1,   512,    -1, TURION_64               ,     0, "Turion 64 (512K)"              },
@@ -238,10 +207,12 @@ 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,   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,   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,   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)"         },
 	{ 15,  5, -1, 16,    5,   4,   512,    -1, ATHLON_64_X4            ,     0, "Athlon II X4 (Propus)"         },
+
 	/* 2011 CPUs: K10 architecture: Llano */
 	/* 2011 CPUs: K10 architecture: Llano */
 	{ 15,  1, -1, 18,    1,   2,   512,    -1, FUSION_EA               ,     0, "Llano X2"                      },
 	{ 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,   2,  1024,    -1, FUSION_EA               ,     0, "Llano X2"                      },
@@ -255,7 +226,9 @@ const struct match_entry_t cpudb_amd[] = {
 	{ 15,  2, -1, 20,   -1,   2,   512,    -1, FUSION_Z                ,     0, "Brazos Desna (Dual-core)"      },
 	{ 15,  2, -1, 20,   -1,   2,   512,    -1, FUSION_Z                ,     0, "Brazos Desna (Dual-core)"      },
 	/* 2012 CPUs: Piledriver architecture: Trinity and Richland */
 	/* 2012 CPUs: Piledriver architecture: Trinity and Richland */
 	{ 15,  0, -1, 21,   10,   2,  1024,    -1, FUSION_A                ,     0, "Trinity X2"                    },
 	{ 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,   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,   2,  1024,    -1, FUSION_A                ,     0, "Richland X2"                   },
 	{ 15,  3, -1, 21,   13,   4,  1024,    -1, FUSION_A                ,     0, "Richland X4"                   },
 	{ 15,  3, -1, 21,   13,   4,  1024,    -1, FUSION_A                ,     0, "Richland X4"                   },
 	/* 2013 CPUs: Jaguar architecture: Kabini and Temash */
 	/* 2013 CPUs: Jaguar architecture: Kabini and Temash */
@@ -318,6 +291,7 @@ static void load_amd_features(struct cpu_raw_data_t* raw, struct cpu_id_t* data)
 		{ 12, CPU_FEATURE_SKINIT },
 		{ 12, CPU_FEATURE_SKINIT },
 		{ 13, CPU_FEATURE_WDT },
 		{ 13, CPU_FEATURE_WDT },
 		{ 16, CPU_FEATURE_FMA4 },
 		{ 16, CPU_FEATURE_FMA4 },
+		{ 21, CPU_FEATURE_TBM },
 	};
 	};
 	const struct feature_map_t matchtable_edx87[] = {
 	const struct feature_map_t matchtable_edx87[] = {
 		{  0, CPU_FEATURE_TS },
 		{  0, CPU_FEATURE_TS },
@@ -351,7 +325,7 @@ static void decode_amd_cache_info(struct cpu_raw_data_t* raw, struct cpu_id_t* d
 {
 {
 	int l3_result;
 	int l3_result;
 	const int assoc_table[16] = {
 	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];
 	unsigned n = raw->ext_cpuid[0][0];
 	
 	
@@ -473,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, "Z-##")) return FUSION_Z;
 	if (match_pattern(bs, "E#-####") || match_pattern(bs, "A#-####")) return FUSION_EA;
 	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);
 	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)
 	if (code == ATHLON_64_X2 && data->l2_cache < 512)
 		code = SEMPRON_DUALCORE;
 		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);
 	load_amd_features(raw, data);
 	decode_amd_cache_info(raw, data);
 	decode_amd_cache_info(raw, data);
 	decode_amd_number_of_cores(raw, data);
 	decode_amd_number_of_cores(raw, data);
-	decode_amd_codename(raw, data);
+	decode_amd_codename(raw, data, internal);
 	return 0;
 	return 0;
 }
 }
 
 

+ 1 - 1
Source/ThirdParty/LibCpuId/src/recog_amd.h

@@ -26,7 +26,7 @@
 #ifndef __RECOG_AMD_H__
 #ifndef __RECOG_AMD_H__
 #define __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);
 void cpuid_get_list_amd(struct cpu_list_t* list);
 
 
 #endif /* __RECOG_AMD_H__ */
 #endif /* __RECOG_AMD_H__ */

+ 179 - 101
Source/ThirdParty/LibCpuId/src/recog_intel.c

@@ -26,67 +26,16 @@
 #include <string.h>
 #include <string.h>
 #include <ctype.h>
 #include <ctype.h>
 #include "libcpuid.h"
 #include "libcpuid.h"
-#include "recog_intel.h"
 #include "libcpuid_util.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,
-	CORE_BROADWELL3, /* 14nm Core-iX, Broadwell */
-	CORE_BROADWELL5,
-	CORE_BROADWELL7,
-	CORE_SKYLAKE3, /* 14nm Core-iX, Skylake */
-	CORE_SKYLAKE5,
-	CORE_SKYLAKE7,
+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 {
 enum _intel_model_t {
 	UNKNOWN = -1,
 	UNKNOWN = -1,
@@ -140,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,  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,  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)" },
 	
 	
 	/* -------------------------------------------------- */
 	/* -------------------------------------------------- */
 	
 	
@@ -154,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, 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, 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)
 	/* Netburst based (Pentium 4 and later)
 	   classic P4s */
 	   classic P4s */
@@ -196,17 +145,17 @@ const struct match_entry_t cpudb_intel[] = {
 	{ 15,  6, -1, 15, -1,   1,    -1,    -1, XEON              ,     0, "Xeon (Dempsey)"          },
 	{ 15,  6, -1, 15, -1,   1,    -1,    -1, XEON              ,     0, "Xeon (Dempsey)"          },
 	
 	
 	/* Pentium Ds */
 	/* 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 */
 	/* 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 */
 	/* Intel Core microarchitecture - P6-based */
@@ -220,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, MOBILE_PENTIUM_M  ,     0, "Pentium M (Dothan)"         },
 	{  6, 13, -1, -1, -1,   1,    -1,    -1, CELERON           ,     0, "Celeron M"                  },
 	{  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_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_SILVERTHORNE ,     0, "Atom (Silverthorne)"        },
 	{  6, 12, -1, -1, -1,  -1,    -1,    -1, ATOM_CEDARVIEW    ,     0, "Atom (Cedarview)"           },
 	{  6, 12, -1, -1, -1,  -1,    -1,    -1, ATOM_CEDARVIEW    ,     0, "Atom (Cedarview)"           },
@@ -266,6 +215,7 @@ 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,  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,   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,   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,  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,   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,  2048,    -1, QUAD_CORE         ,     0, "Yorkfield (Core 2 Quad) 2M"},
@@ -301,6 +251,7 @@ const struct match_entry_t cpudb_intel[] = {
 	{  6, 12, -1, -1, 44,   4,    -1, 12288, CORE_I7           ,     0, "Gulftown (Core i7)"       },
 	{  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_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,  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,  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_I5           ,     0, "Arrandale (Core i5)"      },
 	{  6,  5, -1, -1, 37,   2,    -1,  3072, CORE_I3           ,     0, "Arrandale (Core i3)"      },
 	{  6,  5, -1, -1, 37,   2,    -1,  3072, CORE_I3           ,     0, "Arrandale (Core i3)"      },
@@ -351,11 +302,16 @@ const struct match_entry_t cpudb_intel[] = {
 	{  6, 13, -1, -1, 61,   2,    -1,    -1, PENTIUM           ,     0, "Broadwell-U (Pentium)"    },
 	{  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, CELERON           ,     0, "Broadwell-U (Celeron)"    },
 	{  6, 13, -1, -1, 61,   2,    -1,    -1, NA                ,     0, "Broadwell-U (Core M)"     },
 	{  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): */
 	/* Skylake CPUs (14nm): */
-	{  6, 14, -1, -1, 94,   4,    -1,    -1, CORE_SKYLAKE7     ,     0, "Skylake (Core i7)"        },
-	{  6, 14, -1, -1, 94,   4,    -1,    -1, CORE_SKYLAKE5     ,     0, "Skylake (Core i5)"        },
-	{  6, 14, -1, -1, 94,   4,    -1,    -1, CORE_SKYLAKE3     ,     0, "Skylake (Core i3)"        },
+	{  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)"        },
 	{  6, 14, -1, -1, 94,   4,    -1,    -1, PENTIUM           ,     0, "Skylake (Pentium)"        },
 
 
 	/* Itaniums */
 	/* Itaniums */
@@ -377,7 +333,6 @@ static void load_intel_features(struct cpu_raw_data_t* raw, struct cpu_id_t* dat
 		{ 31, CPU_FEATURE_PBE },
 		{ 31, CPU_FEATURE_PBE },
 	};
 	};
 	const struct feature_map_t matchtable_ecx1[] = {
 	const struct feature_map_t matchtable_ecx1[] = {
-		{  1, CPU_FEATURE_PCLMUL },
 		{  2, CPU_FEATURE_DTS64 },
 		{  2, CPU_FEATURE_DTS64 },
 		{  4, CPU_FEATURE_DS_CPL },
 		{  4, CPU_FEATURE_DS_CPL },
 		{  5, CPU_FEATURE_VMX },
 		{  5, CPU_FEATURE_VMX },
@@ -388,16 +343,26 @@ static void load_intel_features(struct cpu_raw_data_t* raw, struct cpu_id_t* dat
 		{ 14, CPU_FEATURE_XTPR },
 		{ 14, CPU_FEATURE_XTPR },
 		{ 15, CPU_FEATURE_PDCM },
 		{ 15, CPU_FEATURE_PDCM },
 		{ 18, CPU_FEATURE_DCA },
 		{ 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 },
-		{ 30, CPU_FEATURE_RDRAND },
+		{ 21, CPU_FEATURE_X2APIC },
 	};
 	};
 	const struct feature_map_t matchtable_edx81[] = {
 	const struct feature_map_t matchtable_edx81[] = {
 		{ 20, CPU_FEATURE_XD },
 		{ 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) {
 	if (raw->basic_cpuid[0][0] >= 1) {
 		match_features(matchtable_edx1, COUNT_OF(matchtable_edx1), raw->basic_cpuid[1][3], data);
 		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);
 		match_features(matchtable_ecx1, COUNT_OF(matchtable_ecx1), raw->basic_cpuid[1][2], data);
@@ -405,13 +370,18 @@ static void load_intel_features(struct cpu_raw_data_t* raw, struct cpu_id_t* dat
 	if (raw->ext_cpuid[0][0] >= 1) {
 	if (raw->ext_cpuid[0][0] >= 1) {
 		match_features(matchtable_edx81, COUNT_OF(matchtable_edx81), raw->ext_cpuid[1][3], data);
 		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 {
 enum _cache_type_t {
 	L1I,
 	L1I,
 	L1D,
 	L1D,
 	L2,
 	L2,
-	L3
+	L3,
+	L4
 };
 };
 typedef enum _cache_type_t cache_type_t;
 typedef enum _cache_type_t cache_type_t;
 
 
@@ -436,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_cache = size;
 			data->l3_assoc = assoc;
 			data->l3_assoc = assoc;
 			data->l3_cacheline = linesize;
 			data->l3_cacheline = linesize;
+			break;
+		case L4:
+			data->l4_cache = size;
+			data->l4_assoc = assoc;
+			data->l4_cacheline = linesize;
+			break;
 		default:
 		default:
 			break;
 			break;
 	}
 	}
@@ -556,6 +532,8 @@ static void decode_intel_deterministic_cache_info(struct cpu_raw_data_t* raw,
 			type = L2;
 			type = L2;
 		else if (level == 3 && typenumber == 3)
 		else if (level == 3 && typenumber == 3)
 			type = L3;
 			type = L3;
+		else if (level == 4 && typenumber == 3)
+			type = L4;
 		else {
 		else {
 			warnf("deterministic_cache: unknown level/typenumber combo (%d/%d), cannot\n", level, typenumber);
 			warnf("deterministic_cache: unknown level/typenumber combo (%d/%d), cannot\n", level, typenumber);
 			warnf("deterministic_cache: recognize cache type\n");
 			warnf("deterministic_cache: recognize cache type\n");
@@ -588,8 +566,12 @@ static int decode_intel_extended_topology(struct cpu_raw_data_t* raw,
 		}
 		}
 	}
 	}
 	if (num_smt == -1 || num_core == -1) return 0;
 	if (num_smt == -1 || num_core == -1) return 0;
-	data->num_cores = num_core / num_smt;
 	data->num_logical_cpus = num_core;
 	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;
 	return 1;
 }
 }
 
 
@@ -614,7 +596,9 @@ static void decode_intel_number_of_cores(struct cpu_raw_data_t* raw,
 			data->num_logical_cpus = logical_cpus;
 			data->num_logical_cpus = logical_cpus;
 		} else {
 		} else {
 			data->num_cores = 1;
 			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 {
 	} else {
 		data->num_cores = data->num_logical_cpus = 1;
 		data->num_cores = data->num_logical_cpus = 1;
@@ -623,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)
 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;
 	int i, need_matchtable = 1, core_ix_base = 0;
 	const char* bs = data->brand_str;
 	const char* bs = data->brand_str;
 	const char* s;
 	const char* s;
@@ -634,15 +618,16 @@ static intel_code_t get_brand_code(struct cpu_id_t* data)
 		{ CELERON, "Celeron" },
 		{ CELERON, "Celeron" },
 		{ MOBILE_PENTIUM_M, "Pentium(R) M" },
 		{ MOBILE_PENTIUM_M, "Pentium(R) M" },
 		{ CORE_SOLO, "Pentium(R) Dual  CPU" },
 		{ CORE_SOLO, "Pentium(R) Dual  CPU" },
+		{ CORE_SOLO, "Pentium(R) Dual-Core" },
 		{ PENTIUM_D, "Pentium(R) D" },
 		{ PENTIUM_D, "Pentium(R) D" },
 		{ PENTIUM, "Pentium" },
 		{ PENTIUM, "Pentium" },
 		{ CORE_SOLO, "Genuine Intel(R) CPU" },
 		{ CORE_SOLO, "Genuine Intel(R) CPU" },
 		{ CORE_SOLO, "Intel(R) Core(TM)" },
 		{ CORE_SOLO, "Intel(R) Core(TM)" },
 		{ ATOM_DIAMONDVILLE, "Atom(TM) CPU [N ][23]## " },
 		{ ATOM_DIAMONDVILLE, "Atom(TM) CPU [N ][23]## " },
 		{ ATOM_SILVERTHORNE, "Atom(TM) CPU Z" },
 		{ 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")) {
 	if (strstr(bs, "Mobile")) {
@@ -664,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 it has FMA, then it is at least Haswell */
 		if (data->flags[CPU_FEATURE_FMA3])
 		if (data->flags[CPU_FEATURE_FMA3])
 			core_ix_base = CORE_HASWELL3;
 			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]) {
 		switch (bs[i + 9]) {
 			case '3': code = core_ix_base + 0; break;
 			case '3': code = core_ix_base + 0; break;
@@ -798,8 +786,75 @@ static intel_model_t get_model_code(struct cpu_id_t* data)
 #undef HAVE
 #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);
 	load_intel_features(raw, data);
 	if (raw->basic_cpuid[0][0] >= 4) {
 	if (raw->basic_cpuid[0][0] >= 4) {
 		/* Deterministic way is preferred, being more generic */
 		/* Deterministic way is preferred, being more generic */
@@ -808,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_oldstyle_cache_info(raw, data);
 	}
 	}
 	decode_intel_number_of_cores(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;
 	return 0;
 }
 }
 
 

+ 1 - 1
Source/ThirdParty/LibCpuId/src/recog_intel.h

@@ -26,7 +26,7 @@
 #ifndef __RECOG_INTEL_H__
 #ifndef __RECOG_INTEL_H__
 #define __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);
 void cpuid_get_list_intel(struct cpu_list_t* list);
 
 
 #endif /*__RECOG_INTEL_H__*/
 #endif /*__RECOG_INTEL_H__*/