Browse Source

Merge commit '987280793337c6caedaa65233b0611999614ab3c' as 'Source/ThirdParty/LibCpuId'

Yao Wei Tjong 姚伟忠 7 years ago
parent
commit
da01a0d5b1
28 changed files with 7618 additions and 0 deletions
  1. 41 0
      Source/ThirdParty/LibCpuId/.gitignore
  2. 1 0
      Source/ThirdParty/LibCpuId/AUTHORS
  3. 53 0
      Source/ThirdParty/LibCpuId/CMakeLists.txt
  4. 23 0
      Source/ThirdParty/LibCpuId/COPYING
  5. 48 0
      Source/ThirdParty/LibCpuId/ChangeLog
  6. 0 0
      Source/ThirdParty/LibCpuId/NEWS
  7. 64 0
      Source/ThirdParty/LibCpuId/Readme.md
  8. 39 0
      Source/ThirdParty/LibCpuId/src/amd_code_t.h
  9. 825 0
      Source/ThirdParty/LibCpuId/src/asm-bits.c
  10. 53 0
      Source/ThirdParty/LibCpuId/src/asm-bits.h
  11. 771 0
      Source/ThirdParty/LibCpuId/src/cpuid_main.c
  12. 84 0
      Source/ThirdParty/LibCpuId/src/embed_drivers.cpp
  13. 58 0
      Source/ThirdParty/LibCpuId/src/intel_code_t.h
  14. 1150 0
      Source/ThirdParty/LibCpuId/src/libcpuid.h
  15. 47 0
      Source/ThirdParty/LibCpuId/src/libcpuid_constants.h
  16. 106 0
      Source/ThirdParty/LibCpuId/src/libcpuid_internal.h
  17. 67 0
      Source/ThirdParty/LibCpuId/src/libcpuid_types.h
  18. 218 0
      Source/ThirdParty/LibCpuId/src/libcpuid_util.c
  19. 98 0
      Source/ThirdParty/LibCpuId/src/libcpuid_util.h
  20. 359 0
      Source/ThirdParty/LibCpuId/src/masm-x64.asm
  21. 593 0
      Source/ThirdParty/LibCpuId/src/msrdriver.c
  22. 1054 0
      Source/ThirdParty/LibCpuId/src/rdmsr.c
  23. 320 0
      Source/ThirdParty/LibCpuId/src/rdtsc.c
  24. 33 0
      Source/ThirdParty/LibCpuId/src/rdtsc.h
  25. 530 0
      Source/ThirdParty/LibCpuId/src/recog_amd.c
  26. 32 0
      Source/ThirdParty/LibCpuId/src/recog_amd.h
  27. 919 0
      Source/ThirdParty/LibCpuId/src/recog_intel.c
  28. 32 0
      Source/ThirdParty/LibCpuId/src/recog_intel.h

+ 41 - 0
Source/ThirdParty/LibCpuId/.gitignore

@@ -0,0 +1,41 @@
+*~
+*.lo
+*.la
+*.o
+*.obj
+libtool
+ltmain.sh
+configure
+missing
+stamp-h1
+Makefile
+Makefile.in
+aclocal.m4
+m4
+autom4te.cache
+config.guess
+config.h.in
+config.h
+config.log
+config.status
+config.sub
+*/.deps
+*/.libs
+cpuid_tool/cpuid_tool
+depcomp
+install-sh
+libcpuid.pc
+libcpuid/docs
+libcpuid/Doxyfile
+libcpuid/doxyfile.stamp
+ar-lib
+compile
+ipch
+*.opensdf
+*.sdf
+*.suo
+libcpuid/x32
+libcpuid/x64
+cpuid_tool/x32
+cpuid_tool/x64
+*.vcxproj.user

+ 1 - 0
Source/ThirdParty/LibCpuId/AUTHORS

@@ -0,0 +1 @@
+Veselin Georgiev <[email protected]> (convert to gmail)

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

@@ -0,0 +1,53 @@
+#
+# Copyright (c) 2008-2018 the Urho3D project.
+#
+# Permission is hereby granted, free of charge, to any person obtaining a copy
+# of this software and associated documentation files (the "Software"), to deal
+# in the Software without restriction, including without limitation the rights
+# to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+# copies of the Software, and to permit persons to whom the Software is
+# furnished to do so, subject to the following conditions:
+#
+# The above copyright notice and this permission notice shall be included in
+# all copies or substantial portions of the Software.
+#
+# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+# IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+# FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+# AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+# LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+# OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
+# THE SOFTWARE.
+#
+
+# Define target name
+set (TARGET_NAME LibCpuId)
+
+# Define preprocessor macros
+add_definitions (-DVERSION="0.4.0+ (2f4c21e)")
+if (HAVE_STDINT_H)
+    add_definitions (-DHAVE_STDINT_H)
+endif ()
+
+# Define generated source files
+if (MSVC AND URHO3D_64BIT)
+    enable_language (ASM_MASM)
+    # Commented out due to cmake bug
+    #set (ASM_FILES src/masm-x64.asm)
+    # As a temporary workaround
+    add_custom_command (OUTPUT masm-x64.obj COMMAND ${CMAKE_ASM_MASM_COMPILER} -Fo ${CMAKE_CURRENT_BINARY_DIR}/masm-x64.obj -c ${CMAKE_CURRENT_SOURCE_DIR}/src/masm-x64.asm DEPENDS ${CMAKE_CURRENT_SOURCE_DIR}/src/masm-x64.asm COMMENT "Temporary workaround for MASM")
+    set (ASM_FILES ${CMAKE_CURRENT_BINARY_DIR}/masm-x64.obj ${CMAKE_CURRENT_SOURCE_DIR}/src/masm-x64.asm)
+endif ()
+
+# Define source files
+define_source_files (GLOB_CPP_PATTERNS src/*.c GLOB_H_PATTERNS src/*.h)
+list (APPEND SOURCE_FILES ${ASM_FILES})
+
+# Define dependency libs
+set (INCLUDE_DIRS src)
+
+# Setup target
+setup_library ()
+
+# Install headers for building the Urho3D library
+install_header_files (DIRECTORY src/ DESTINATION ${DEST_INCLUDE_DIR}/ThirdParty/LibCpuId FILES_MATCHING PATTERN *.h BUILD_TREE_ONLY)  # Note: the trailing slash is significant

+ 23 - 0
Source/ThirdParty/LibCpuId/COPYING

@@ -0,0 +1,23 @@
+Copyright 2008  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.

+ 48 - 0
Source/ThirdParty/LibCpuId/ChangeLog

@@ -0,0 +1,48 @@
+Version 0.1.0 (2008-10-15):
+	* Initial public release
+
+Version 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
+	* Support for Intel Nehalem architecture CPUs (Core i7, Xeon i7)
+
+Version 0.1.2 (2009-09-26):
+	* Added support for MSR reading through self-extracting kernel driver
+	  on Win32.
+
+Version 0.1.3 (2010-04-20):
+	* Added support for greater more accurate CPU clock measurements with
+	  cpu_clock_by_ic()
+
+Version 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.
+
+Version 0.2.1 (2012-05-26):
+	* Support for Ivy Bridge, and detecting the presence of the RdRand
+	  instruction.
+
+Version 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
+	* Support for detection of AVX/AVX2/BMI1/BMI2
+	* More entries supported in cpu_msrinfo()
+	* Rename of some CPU codenames, made more consistent
+	* *BSD and Solaris support (unofficial)
+
+Version 0.3.0 (2016-07-09):
+	* A backwards-incompatible change, since the sizeof cpu_raw_data_t and
+	  cpu_id_t are now different.
+	* Support for processors up to Skylake.
+	* Fix clock detection in cpu_clock_by_ic() for Skylake.
+	* Support up to 8 subleaf entries for CPUID leaf 04 and detection
+	  of L4 cache.
+	* MSR functions supported on FreeBSD.
+	* INFO_VOLTAGE request supported by cpu_msrinfo().
+
+Version 0.4.0 (2016-09-30):
+	* A backwards-incompatible change, since the sizeof cpu_raw_data_t and
+	  cpu_id_t are now different.
+	* Better detection of AMD clock multiplier with msrinfo.
+	* Support for Intel SGX detection

+ 0 - 0
Source/ThirdParty/LibCpuId/NEWS


+ 64 - 0
Source/ThirdParty/LibCpuId/Readme.md

@@ -0,0 +1,64 @@
+libcpuid
+========
+
+libcpuid provides CPU identification for the x86 (and x86_64).
+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
+--------------------------
+
+Under linux, where you download the sources, there's no
+configure script to run. This is because it isn't a good practice to keep
+such scripts in a source control system. To create it, you need to run the
+following commands once, after you checkout the libcpuid sources
+from github:
+
+        1. run "libtoolize"
+        2. run "autoreconf --install"
+
+You need to have `autoconf`, `automake` and `libtool` installed.
+
+After that you can run `./configure` and `make` - this will build
+the library.
+
+`make dist` will create a tarball (with "configure" inside) with the
+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
+-----
+
+So far, I'm aware of the following projects which utilize libcpuid:
+
+* CPU-X (https://github.com/X0rg/CPU-X)
+* fre:ac (https://www.freac.org/)
+* ucbench (http://anrieff.net/ucbench)
+* Multiprecision Computing Toolbox for MATLAB (https://www.advanpix.com/)
+
+We'd love to hear from you if you are also using libcpuid and want your project listed above.

+ 39 - 0
Source/ThirdParty/LibCpuId/src/amd_code_t.h

@@ -0,0 +1,39 @@
+/*
+ * 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_800, 1000),
+	CODE(PHENOM),
+	CODE(PHENOM2),
+	CODE(FUSION_C),
+	CODE(FUSION_E),
+	CODE(FUSION_EA),
+	CODE(FUSION_Z),
+	CODE(FUSION_A),
+	

+ 825 - 0
Source/ThirdParty/LibCpuId/src/asm-bits.c

@@ -0,0 +1,825 @@
+/*
+ * Copyright 2008  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.
+ */
+
+#include "libcpuid.h"
+#include "asm-bits.h"
+
+int cpuid_exists_by_eflags(void)
+{
+#if defined(PLATFORM_X64)
+	return 1; /* CPUID is always present on the x86_64 */
+#elif defined(PLATFORM_X86)
+#  if defined(COMPILER_GCC)
+	int result;
+	__asm __volatile(
+		"	pushfl\n"
+		"	pop	%%eax\n"
+		"	mov	%%eax,	%%ecx\n"
+		"	xor	$0x200000,	%%eax\n"
+		"	push	%%eax\n"
+		"	popfl\n"
+		"	pushfl\n"
+		"	pop	%%eax\n"
+		"	xor	%%ecx,	%%eax\n"
+		"	mov	%%eax,	%0\n"
+		"	push	%%ecx\n"
+		"	popfl\n"
+		: "=m"(result)
+		: :"eax", "ecx", "memory");
+	return (result != 0);
+#  elif defined(COMPILER_MICROSOFT)
+	int result;
+	__asm {
+		pushfd
+		pop	eax
+		mov	ecx,	eax
+		xor	eax,	0x200000
+		push	eax
+		popfd
+		pushfd
+		pop	eax
+		xor	eax,	ecx
+		mov	result,	eax
+		push	ecx
+		popfd
+	};
+	return (result != 0);
+#  else
+	return 0;
+#  endif /* COMPILER_MICROSOFT */
+#else
+	return 0;
+#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 COMPILER_GCC
+#	ifdef PLATFORM_X64
+	__asm __volatile(
+		"	mov	%0,	%%rdi\n"
+
+		"	push	%%rbx\n"
+		"	push	%%rcx\n"
+		"	push	%%rdx\n"
+		
+		"	mov	(%%rdi),	%%eax\n"
+		"	mov	4(%%rdi),	%%ebx\n"
+		"	mov	8(%%rdi),	%%ecx\n"
+		"	mov	12(%%rdi),	%%edx\n"
+		
+		"	cpuid\n"
+		
+		"	movl	%%eax,	(%%rdi)\n"
+		"	movl	%%ebx,	4(%%rdi)\n"
+		"	movl	%%ecx,	8(%%rdi)\n"
+		"	movl	%%edx,	12(%%rdi)\n"
+		"	pop	%%rdx\n"
+		"	pop	%%rcx\n"
+		"	pop	%%rbx\n"
+		:
+		:"m"(regs)
+		:"memory", "eax", "rdi"
+	);
+#	else
+	__asm __volatile(
+		"	mov	%0,	%%edi\n"
+
+		"	push	%%ebx\n"
+		"	push	%%ecx\n"
+		"	push	%%edx\n"
+		
+		"	mov	(%%edi),	%%eax\n"
+		"	mov	4(%%edi),	%%ebx\n"
+		"	mov	8(%%edi),	%%ecx\n"
+		"	mov	12(%%edi),	%%edx\n"
+		
+		"	cpuid\n"
+		
+		"	mov	%%eax,	(%%edi)\n"
+		"	mov	%%ebx,	4(%%edi)\n"
+		"	mov	%%ecx,	8(%%edi)\n"
+		"	mov	%%edx,	12(%%edi)\n"
+		"	pop	%%edx\n"
+		"	pop	%%ecx\n"
+		"	pop	%%ebx\n"
+		:
+		:"m"(regs)
+		:"memory", "eax", "edi"
+	);
+#	endif /* COMPILER_GCC */
+#else
+#  ifdef COMPILER_MICROSOFT
+	__asm {
+		push	ebx
+		push	ecx
+		push	edx
+		push	edi
+		mov	edi,	regs
+		
+		mov	eax,	[edi]
+		mov	ebx,	[edi+4]
+		mov	ecx,	[edi+8]
+		mov	edx,	[edi+12]
+		
+		cpuid
+		
+		mov	[edi],		eax
+		mov	[edi+4],	ebx
+		mov	[edi+8],	ecx
+		mov	[edi+12],	edx
+		
+		pop	edi
+		pop	edx
+		pop	ecx
+		pop	ebx
+	}
+#  else
+#    error "Unsupported compiler"
+#  endif /* COMPILER_MICROSOFT */
+#endif
+}
+#endif /* INLINE_ASSEMBLY_SUPPORTED */
+
+#ifdef INLINE_ASM_SUPPORTED
+void cpu_rdtsc(uint64_t* result)
+{
+	uint32_t low_part, hi_part;
+#ifdef COMPILER_GCC
+	__asm __volatile (
+		"	rdtsc\n"
+		"	mov	%%eax,	%0\n"
+		"	mov	%%edx,	%1\n"
+		:"=m"(low_part), "=m"(hi_part)::"memory", "eax", "edx"
+	);
+#else
+#  ifdef COMPILER_MICROSOFT
+	__asm {
+		rdtsc
+		mov	low_part,	eax
+		mov	hi_part,	edx
+	};
+#  else
+#    error "Unsupported compiler"
+#  endif /* COMPILER_MICROSOFT */
+#endif /* COMPILER_GCC */
+	*result = (uint64_t)low_part + (((uint64_t) hi_part) << 32);
+}
+#endif /* INLINE_ASM_SUPPORTED */
+
+#ifdef INLINE_ASM_SUPPORTED
+void busy_sse_loop(int cycles)
+{
+#ifdef COMPILER_GCC
+#ifndef __APPLE__
+#	define XALIGN ".balign 16\n"
+#else
+#	define XALIGN ".align 4\n"
+#endif
+	__asm __volatile (
+		"	xorps	%%xmm0,	%%xmm0\n"
+		"	xorps	%%xmm1,	%%xmm1\n"
+		"	xorps	%%xmm2,	%%xmm2\n"
+		"	xorps	%%xmm3,	%%xmm3\n"
+		"	xorps	%%xmm4,	%%xmm4\n"
+		"	xorps	%%xmm5,	%%xmm5\n"
+		"	xorps	%%xmm6,	%%xmm6\n"
+		"	xorps	%%xmm7,	%%xmm7\n"
+		XALIGN
+		/* ".bsLoop:\n" */
+		"1:\n"
+		// 0:
+		"	addps	%%xmm1, %%xmm0\n"
+		"	addps	%%xmm2, %%xmm1\n"
+		"	addps	%%xmm3, %%xmm2\n"
+		"	addps	%%xmm4, %%xmm3\n"
+		"	addps	%%xmm5, %%xmm4\n"
+		"	addps	%%xmm6, %%xmm5\n"
+		"	addps	%%xmm7, %%xmm6\n"
+		"	addps	%%xmm0, %%xmm7\n"
+		// 1:
+		"	addps	%%xmm1, %%xmm0\n"
+		"	addps	%%xmm2, %%xmm1\n"
+		"	addps	%%xmm3, %%xmm2\n"
+		"	addps	%%xmm4, %%xmm3\n"
+		"	addps	%%xmm5, %%xmm4\n"
+		"	addps	%%xmm6, %%xmm5\n"
+		"	addps	%%xmm7, %%xmm6\n"
+		"	addps	%%xmm0, %%xmm7\n"
+		// 2:
+		"	addps	%%xmm1, %%xmm0\n"
+		"	addps	%%xmm2, %%xmm1\n"
+		"	addps	%%xmm3, %%xmm2\n"
+		"	addps	%%xmm4, %%xmm3\n"
+		"	addps	%%xmm5, %%xmm4\n"
+		"	addps	%%xmm6, %%xmm5\n"
+		"	addps	%%xmm7, %%xmm6\n"
+		"	addps	%%xmm0, %%xmm7\n"
+		// 3:
+		"	addps	%%xmm1, %%xmm0\n"
+		"	addps	%%xmm2, %%xmm1\n"
+		"	addps	%%xmm3, %%xmm2\n"
+		"	addps	%%xmm4, %%xmm3\n"
+		"	addps	%%xmm5, %%xmm4\n"
+		"	addps	%%xmm6, %%xmm5\n"
+		"	addps	%%xmm7, %%xmm6\n"
+		"	addps	%%xmm0, %%xmm7\n"
+		// 4:
+		"	addps	%%xmm1, %%xmm0\n"
+		"	addps	%%xmm2, %%xmm1\n"
+		"	addps	%%xmm3, %%xmm2\n"
+		"	addps	%%xmm4, %%xmm3\n"
+		"	addps	%%xmm5, %%xmm4\n"
+		"	addps	%%xmm6, %%xmm5\n"
+		"	addps	%%xmm7, %%xmm6\n"
+		"	addps	%%xmm0, %%xmm7\n"
+		// 5:
+		"	addps	%%xmm1, %%xmm0\n"
+		"	addps	%%xmm2, %%xmm1\n"
+		"	addps	%%xmm3, %%xmm2\n"
+		"	addps	%%xmm4, %%xmm3\n"
+		"	addps	%%xmm5, %%xmm4\n"
+		"	addps	%%xmm6, %%xmm5\n"
+		"	addps	%%xmm7, %%xmm6\n"
+		"	addps	%%xmm0, %%xmm7\n"
+		// 6:
+		"	addps	%%xmm1, %%xmm0\n"
+		"	addps	%%xmm2, %%xmm1\n"
+		"	addps	%%xmm3, %%xmm2\n"
+		"	addps	%%xmm4, %%xmm3\n"
+		"	addps	%%xmm5, %%xmm4\n"
+		"	addps	%%xmm6, %%xmm5\n"
+		"	addps	%%xmm7, %%xmm6\n"
+		"	addps	%%xmm0, %%xmm7\n"
+		// 7:
+		"	addps	%%xmm1, %%xmm0\n"
+		"	addps	%%xmm2, %%xmm1\n"
+		"	addps	%%xmm3, %%xmm2\n"
+		"	addps	%%xmm4, %%xmm3\n"
+		"	addps	%%xmm5, %%xmm4\n"
+		"	addps	%%xmm6, %%xmm5\n"
+		"	addps	%%xmm7, %%xmm6\n"
+		"	addps	%%xmm0, %%xmm7\n"
+		// 8:
+		"	addps	%%xmm1, %%xmm0\n"
+		"	addps	%%xmm2, %%xmm1\n"
+		"	addps	%%xmm3, %%xmm2\n"
+		"	addps	%%xmm4, %%xmm3\n"
+		"	addps	%%xmm5, %%xmm4\n"
+		"	addps	%%xmm6, %%xmm5\n"
+		"	addps	%%xmm7, %%xmm6\n"
+		"	addps	%%xmm0, %%xmm7\n"
+		// 9:
+		"	addps	%%xmm1, %%xmm0\n"
+		"	addps	%%xmm2, %%xmm1\n"
+		"	addps	%%xmm3, %%xmm2\n"
+		"	addps	%%xmm4, %%xmm3\n"
+		"	addps	%%xmm5, %%xmm4\n"
+		"	addps	%%xmm6, %%xmm5\n"
+		"	addps	%%xmm7, %%xmm6\n"
+		"	addps	%%xmm0, %%xmm7\n"
+		//10:
+		"	addps	%%xmm1, %%xmm0\n"
+		"	addps	%%xmm2, %%xmm1\n"
+		"	addps	%%xmm3, %%xmm2\n"
+		"	addps	%%xmm4, %%xmm3\n"
+		"	addps	%%xmm5, %%xmm4\n"
+		"	addps	%%xmm6, %%xmm5\n"
+		"	addps	%%xmm7, %%xmm6\n"
+		"	addps	%%xmm0, %%xmm7\n"
+		//11:
+		"	addps	%%xmm1, %%xmm0\n"
+		"	addps	%%xmm2, %%xmm1\n"
+		"	addps	%%xmm3, %%xmm2\n"
+		"	addps	%%xmm4, %%xmm3\n"
+		"	addps	%%xmm5, %%xmm4\n"
+		"	addps	%%xmm6, %%xmm5\n"
+		"	addps	%%xmm7, %%xmm6\n"
+		"	addps	%%xmm0, %%xmm7\n"
+		//12:
+		"	addps	%%xmm1, %%xmm0\n"
+		"	addps	%%xmm2, %%xmm1\n"
+		"	addps	%%xmm3, %%xmm2\n"
+		"	addps	%%xmm4, %%xmm3\n"
+		"	addps	%%xmm5, %%xmm4\n"
+		"	addps	%%xmm6, %%xmm5\n"
+		"	addps	%%xmm7, %%xmm6\n"
+		"	addps	%%xmm0, %%xmm7\n"
+		//13:
+		"	addps	%%xmm1, %%xmm0\n"
+		"	addps	%%xmm2, %%xmm1\n"
+		"	addps	%%xmm3, %%xmm2\n"
+		"	addps	%%xmm4, %%xmm3\n"
+		"	addps	%%xmm5, %%xmm4\n"
+		"	addps	%%xmm6, %%xmm5\n"
+		"	addps	%%xmm7, %%xmm6\n"
+		"	addps	%%xmm0, %%xmm7\n"
+		//14:
+		"	addps	%%xmm1, %%xmm0\n"
+		"	addps	%%xmm2, %%xmm1\n"
+		"	addps	%%xmm3, %%xmm2\n"
+		"	addps	%%xmm4, %%xmm3\n"
+		"	addps	%%xmm5, %%xmm4\n"
+		"	addps	%%xmm6, %%xmm5\n"
+		"	addps	%%xmm7, %%xmm6\n"
+		"	addps	%%xmm0, %%xmm7\n"
+		//15:
+		"	addps	%%xmm1, %%xmm0\n"
+		"	addps	%%xmm2, %%xmm1\n"
+		"	addps	%%xmm3, %%xmm2\n"
+		"	addps	%%xmm4, %%xmm3\n"
+		"	addps	%%xmm5, %%xmm4\n"
+		"	addps	%%xmm6, %%xmm5\n"
+		"	addps	%%xmm7, %%xmm6\n"
+		"	addps	%%xmm0, %%xmm7\n"
+		//16:
+		"	addps	%%xmm1, %%xmm0\n"
+		"	addps	%%xmm2, %%xmm1\n"
+		"	addps	%%xmm3, %%xmm2\n"
+		"	addps	%%xmm4, %%xmm3\n"
+		"	addps	%%xmm5, %%xmm4\n"
+		"	addps	%%xmm6, %%xmm5\n"
+		"	addps	%%xmm7, %%xmm6\n"
+		"	addps	%%xmm0, %%xmm7\n"
+		//17:
+		"	addps	%%xmm1, %%xmm0\n"
+		"	addps	%%xmm2, %%xmm1\n"
+		"	addps	%%xmm3, %%xmm2\n"
+		"	addps	%%xmm4, %%xmm3\n"
+		"	addps	%%xmm5, %%xmm4\n"
+		"	addps	%%xmm6, %%xmm5\n"
+		"	addps	%%xmm7, %%xmm6\n"
+		"	addps	%%xmm0, %%xmm7\n"
+		//18:
+		"	addps	%%xmm1, %%xmm0\n"
+		"	addps	%%xmm2, %%xmm1\n"
+		"	addps	%%xmm3, %%xmm2\n"
+		"	addps	%%xmm4, %%xmm3\n"
+		"	addps	%%xmm5, %%xmm4\n"
+		"	addps	%%xmm6, %%xmm5\n"
+		"	addps	%%xmm7, %%xmm6\n"
+		"	addps	%%xmm0, %%xmm7\n"
+		//19:
+		"	addps	%%xmm1, %%xmm0\n"
+		"	addps	%%xmm2, %%xmm1\n"
+		"	addps	%%xmm3, %%xmm2\n"
+		"	addps	%%xmm4, %%xmm3\n"
+		"	addps	%%xmm5, %%xmm4\n"
+		"	addps	%%xmm6, %%xmm5\n"
+		"	addps	%%xmm7, %%xmm6\n"
+		"	addps	%%xmm0, %%xmm7\n"
+		//20:
+		"	addps	%%xmm1, %%xmm0\n"
+		"	addps	%%xmm2, %%xmm1\n"
+		"	addps	%%xmm3, %%xmm2\n"
+		"	addps	%%xmm4, %%xmm3\n"
+		"	addps	%%xmm5, %%xmm4\n"
+		"	addps	%%xmm6, %%xmm5\n"
+		"	addps	%%xmm7, %%xmm6\n"
+		"	addps	%%xmm0, %%xmm7\n"
+		//21:
+		"	addps	%%xmm1, %%xmm0\n"
+		"	addps	%%xmm2, %%xmm1\n"
+		"	addps	%%xmm3, %%xmm2\n"
+		"	addps	%%xmm4, %%xmm3\n"
+		"	addps	%%xmm5, %%xmm4\n"
+		"	addps	%%xmm6, %%xmm5\n"
+		"	addps	%%xmm7, %%xmm6\n"
+		"	addps	%%xmm0, %%xmm7\n"
+		//22:
+		"	addps	%%xmm1, %%xmm0\n"
+		"	addps	%%xmm2, %%xmm1\n"
+		"	addps	%%xmm3, %%xmm2\n"
+		"	addps	%%xmm4, %%xmm3\n"
+		"	addps	%%xmm5, %%xmm4\n"
+		"	addps	%%xmm6, %%xmm5\n"
+		"	addps	%%xmm7, %%xmm6\n"
+		"	addps	%%xmm0, %%xmm7\n"
+		//23:
+		"	addps	%%xmm1, %%xmm0\n"
+		"	addps	%%xmm2, %%xmm1\n"
+		"	addps	%%xmm3, %%xmm2\n"
+		"	addps	%%xmm4, %%xmm3\n"
+		"	addps	%%xmm5, %%xmm4\n"
+		"	addps	%%xmm6, %%xmm5\n"
+		"	addps	%%xmm7, %%xmm6\n"
+		"	addps	%%xmm0, %%xmm7\n"
+		//24:
+		"	addps	%%xmm1, %%xmm0\n"
+		"	addps	%%xmm2, %%xmm1\n"
+		"	addps	%%xmm3, %%xmm2\n"
+		"	addps	%%xmm4, %%xmm3\n"
+		"	addps	%%xmm5, %%xmm4\n"
+		"	addps	%%xmm6, %%xmm5\n"
+		"	addps	%%xmm7, %%xmm6\n"
+		"	addps	%%xmm0, %%xmm7\n"
+		//25:
+		"	addps	%%xmm1, %%xmm0\n"
+		"	addps	%%xmm2, %%xmm1\n"
+		"	addps	%%xmm3, %%xmm2\n"
+		"	addps	%%xmm4, %%xmm3\n"
+		"	addps	%%xmm5, %%xmm4\n"
+		"	addps	%%xmm6, %%xmm5\n"
+		"	addps	%%xmm7, %%xmm6\n"
+		"	addps	%%xmm0, %%xmm7\n"
+		//26:
+		"	addps	%%xmm1, %%xmm0\n"
+		"	addps	%%xmm2, %%xmm1\n"
+		"	addps	%%xmm3, %%xmm2\n"
+		"	addps	%%xmm4, %%xmm3\n"
+		"	addps	%%xmm5, %%xmm4\n"
+		"	addps	%%xmm6, %%xmm5\n"
+		"	addps	%%xmm7, %%xmm6\n"
+		"	addps	%%xmm0, %%xmm7\n"
+		//27:
+		"	addps	%%xmm1, %%xmm0\n"
+		"	addps	%%xmm2, %%xmm1\n"
+		"	addps	%%xmm3, %%xmm2\n"
+		"	addps	%%xmm4, %%xmm3\n"
+		"	addps	%%xmm5, %%xmm4\n"
+		"	addps	%%xmm6, %%xmm5\n"
+		"	addps	%%xmm7, %%xmm6\n"
+		"	addps	%%xmm0, %%xmm7\n"
+		//28:
+		"	addps	%%xmm1, %%xmm0\n"
+		"	addps	%%xmm2, %%xmm1\n"
+		"	addps	%%xmm3, %%xmm2\n"
+		"	addps	%%xmm4, %%xmm3\n"
+		"	addps	%%xmm5, %%xmm4\n"
+		"	addps	%%xmm6, %%xmm5\n"
+		"	addps	%%xmm7, %%xmm6\n"
+		"	addps	%%xmm0, %%xmm7\n"
+		//29:
+		"	addps	%%xmm1, %%xmm0\n"
+		"	addps	%%xmm2, %%xmm1\n"
+		"	addps	%%xmm3, %%xmm2\n"
+		"	addps	%%xmm4, %%xmm3\n"
+		"	addps	%%xmm5, %%xmm4\n"
+		"	addps	%%xmm6, %%xmm5\n"
+		"	addps	%%xmm7, %%xmm6\n"
+		"	addps	%%xmm0, %%xmm7\n"
+		//30:
+		"	addps	%%xmm1, %%xmm0\n"
+		"	addps	%%xmm2, %%xmm1\n"
+		"	addps	%%xmm3, %%xmm2\n"
+		"	addps	%%xmm4, %%xmm3\n"
+		"	addps	%%xmm5, %%xmm4\n"
+		"	addps	%%xmm6, %%xmm5\n"
+		"	addps	%%xmm7, %%xmm6\n"
+		"	addps	%%xmm0, %%xmm7\n"
+		//31:
+		"	addps	%%xmm1, %%xmm0\n"
+		"	addps	%%xmm2, %%xmm1\n"
+		"	addps	%%xmm3, %%xmm2\n"
+		"	addps	%%xmm4, %%xmm3\n"
+		"	addps	%%xmm5, %%xmm4\n"
+		"	addps	%%xmm6, %%xmm5\n"
+		"	addps	%%xmm7, %%xmm6\n"
+		"	addps	%%xmm0, %%xmm7\n"
+		
+		"	dec	%%eax\n"
+		/* "jnz	.bsLoop\n" */
+		"	jnz	1b\n"
+		::"a"(cycles)
+	);
+#else
+#  ifdef COMPILER_MICROSOFT
+	__asm {
+		mov	eax,	cycles
+		xorps	xmm0,	xmm0
+		xorps	xmm1,	xmm1
+		xorps	xmm2,	xmm2
+		xorps	xmm3,	xmm3
+		xorps	xmm4,	xmm4
+		xorps	xmm5,	xmm5
+		xorps	xmm6,	xmm6
+		xorps	xmm7,	xmm7
+		//--
+		align 16
+bsLoop:
+		// 0:
+		addps	xmm0,	xmm1
+		addps	xmm1,	xmm2
+		addps	xmm2,	xmm3
+		addps	xmm3,	xmm4
+		addps	xmm4,	xmm5
+		addps	xmm5,	xmm6
+		addps	xmm6,	xmm7
+		addps	xmm7,	xmm0
+		// 1:
+		addps	xmm0,	xmm1
+		addps	xmm1,	xmm2
+		addps	xmm2,	xmm3
+		addps	xmm3,	xmm4
+		addps	xmm4,	xmm5
+		addps	xmm5,	xmm6
+		addps	xmm6,	xmm7
+		addps	xmm7,	xmm0
+		// 2:
+		addps	xmm0,	xmm1
+		addps	xmm1,	xmm2
+		addps	xmm2,	xmm3
+		addps	xmm3,	xmm4
+		addps	xmm4,	xmm5
+		addps	xmm5,	xmm6
+		addps	xmm6,	xmm7
+		addps	xmm7,	xmm0
+		// 3:
+		addps	xmm0,	xmm1
+		addps	xmm1,	xmm2
+		addps	xmm2,	xmm3
+		addps	xmm3,	xmm4
+		addps	xmm4,	xmm5
+		addps	xmm5,	xmm6
+		addps	xmm6,	xmm7
+		addps	xmm7,	xmm0
+		// 4:
+		addps	xmm0,	xmm1
+		addps	xmm1,	xmm2
+		addps	xmm2,	xmm3
+		addps	xmm3,	xmm4
+		addps	xmm4,	xmm5
+		addps	xmm5,	xmm6
+		addps	xmm6,	xmm7
+		addps	xmm7,	xmm0
+		// 5:
+		addps	xmm0,	xmm1
+		addps	xmm1,	xmm2
+		addps	xmm2,	xmm3
+		addps	xmm3,	xmm4
+		addps	xmm4,	xmm5
+		addps	xmm5,	xmm6
+		addps	xmm6,	xmm7
+		addps	xmm7,	xmm0
+		// 6:
+		addps	xmm0,	xmm1
+		addps	xmm1,	xmm2
+		addps	xmm2,	xmm3
+		addps	xmm3,	xmm4
+		addps	xmm4,	xmm5
+		addps	xmm5,	xmm6
+		addps	xmm6,	xmm7
+		addps	xmm7,	xmm0
+		// 7:
+		addps	xmm0,	xmm1
+		addps	xmm1,	xmm2
+		addps	xmm2,	xmm3
+		addps	xmm3,	xmm4
+		addps	xmm4,	xmm5
+		addps	xmm5,	xmm6
+		addps	xmm6,	xmm7
+		addps	xmm7,	xmm0
+		// 8:
+		addps	xmm0,	xmm1
+		addps	xmm1,	xmm2
+		addps	xmm2,	xmm3
+		addps	xmm3,	xmm4
+		addps	xmm4,	xmm5
+		addps	xmm5,	xmm6
+		addps	xmm6,	xmm7
+		addps	xmm7,	xmm0
+		// 9:
+		addps	xmm0,	xmm1
+		addps	xmm1,	xmm2
+		addps	xmm2,	xmm3
+		addps	xmm3,	xmm4
+		addps	xmm4,	xmm5
+		addps	xmm5,	xmm6
+		addps	xmm6,	xmm7
+		addps	xmm7,	xmm0
+		// 10:
+		addps	xmm0,	xmm1
+		addps	xmm1,	xmm2
+		addps	xmm2,	xmm3
+		addps	xmm3,	xmm4
+		addps	xmm4,	xmm5
+		addps	xmm5,	xmm6
+		addps	xmm6,	xmm7
+		addps	xmm7,	xmm0
+		// 11:
+		addps	xmm0,	xmm1
+		addps	xmm1,	xmm2
+		addps	xmm2,	xmm3
+		addps	xmm3,	xmm4
+		addps	xmm4,	xmm5
+		addps	xmm5,	xmm6
+		addps	xmm6,	xmm7
+		addps	xmm7,	xmm0
+		// 12:
+		addps	xmm0,	xmm1
+		addps	xmm1,	xmm2
+		addps	xmm2,	xmm3
+		addps	xmm3,	xmm4
+		addps	xmm4,	xmm5
+		addps	xmm5,	xmm6
+		addps	xmm6,	xmm7
+		addps	xmm7,	xmm0
+		// 13:
+		addps	xmm0,	xmm1
+		addps	xmm1,	xmm2
+		addps	xmm2,	xmm3
+		addps	xmm3,	xmm4
+		addps	xmm4,	xmm5
+		addps	xmm5,	xmm6
+		addps	xmm6,	xmm7
+		addps	xmm7,	xmm0
+		// 14:
+		addps	xmm0,	xmm1
+		addps	xmm1,	xmm2
+		addps	xmm2,	xmm3
+		addps	xmm3,	xmm4
+		addps	xmm4,	xmm5
+		addps	xmm5,	xmm6
+		addps	xmm6,	xmm7
+		addps	xmm7,	xmm0
+		// 15:
+		addps	xmm0,	xmm1
+		addps	xmm1,	xmm2
+		addps	xmm2,	xmm3
+		addps	xmm3,	xmm4
+		addps	xmm4,	xmm5
+		addps	xmm5,	xmm6
+		addps	xmm6,	xmm7
+		addps	xmm7,	xmm0
+		// 16:
+		addps	xmm0,	xmm1
+		addps	xmm1,	xmm2
+		addps	xmm2,	xmm3
+		addps	xmm3,	xmm4
+		addps	xmm4,	xmm5
+		addps	xmm5,	xmm6
+		addps	xmm6,	xmm7
+		addps	xmm7,	xmm0
+		// 17:
+		addps	xmm0,	xmm1
+		addps	xmm1,	xmm2
+		addps	xmm2,	xmm3
+		addps	xmm3,	xmm4
+		addps	xmm4,	xmm5
+		addps	xmm5,	xmm6
+		addps	xmm6,	xmm7
+		addps	xmm7,	xmm0
+		// 18:
+		addps	xmm0,	xmm1
+		addps	xmm1,	xmm2
+		addps	xmm2,	xmm3
+		addps	xmm3,	xmm4
+		addps	xmm4,	xmm5
+		addps	xmm5,	xmm6
+		addps	xmm6,	xmm7
+		addps	xmm7,	xmm0
+		// 19:
+		addps	xmm0,	xmm1
+		addps	xmm1,	xmm2
+		addps	xmm2,	xmm3
+		addps	xmm3,	xmm4
+		addps	xmm4,	xmm5
+		addps	xmm5,	xmm6
+		addps	xmm6,	xmm7
+		addps	xmm7,	xmm0
+		// 20:
+		addps	xmm0,	xmm1
+		addps	xmm1,	xmm2
+		addps	xmm2,	xmm3
+		addps	xmm3,	xmm4
+		addps	xmm4,	xmm5
+		addps	xmm5,	xmm6
+		addps	xmm6,	xmm7
+		addps	xmm7,	xmm0
+		// 21:
+		addps	xmm0,	xmm1
+		addps	xmm1,	xmm2
+		addps	xmm2,	xmm3
+		addps	xmm3,	xmm4
+		addps	xmm4,	xmm5
+		addps	xmm5,	xmm6
+		addps	xmm6,	xmm7
+		addps	xmm7,	xmm0
+		// 22:
+		addps	xmm0,	xmm1
+		addps	xmm1,	xmm2
+		addps	xmm2,	xmm3
+		addps	xmm3,	xmm4
+		addps	xmm4,	xmm5
+		addps	xmm5,	xmm6
+		addps	xmm6,	xmm7
+		addps	xmm7,	xmm0
+		// 23:
+		addps	xmm0,	xmm1
+		addps	xmm1,	xmm2
+		addps	xmm2,	xmm3
+		addps	xmm3,	xmm4
+		addps	xmm4,	xmm5
+		addps	xmm5,	xmm6
+		addps	xmm6,	xmm7
+		addps	xmm7,	xmm0
+		// 24:
+		addps	xmm0,	xmm1
+		addps	xmm1,	xmm2
+		addps	xmm2,	xmm3
+		addps	xmm3,	xmm4
+		addps	xmm4,	xmm5
+		addps	xmm5,	xmm6
+		addps	xmm6,	xmm7
+		addps	xmm7,	xmm0
+		// 25:
+		addps	xmm0,	xmm1
+		addps	xmm1,	xmm2
+		addps	xmm2,	xmm3
+		addps	xmm3,	xmm4
+		addps	xmm4,	xmm5
+		addps	xmm5,	xmm6
+		addps	xmm6,	xmm7
+		addps	xmm7,	xmm0
+		// 26:
+		addps	xmm0,	xmm1
+		addps	xmm1,	xmm2
+		addps	xmm2,	xmm3
+		addps	xmm3,	xmm4
+		addps	xmm4,	xmm5
+		addps	xmm5,	xmm6
+		addps	xmm6,	xmm7
+		addps	xmm7,	xmm0
+		// 27:
+		addps	xmm0,	xmm1
+		addps	xmm1,	xmm2
+		addps	xmm2,	xmm3
+		addps	xmm3,	xmm4
+		addps	xmm4,	xmm5
+		addps	xmm5,	xmm6
+		addps	xmm6,	xmm7
+		addps	xmm7,	xmm0
+		// 28:
+		addps	xmm0,	xmm1
+		addps	xmm1,	xmm2
+		addps	xmm2,	xmm3
+		addps	xmm3,	xmm4
+		addps	xmm4,	xmm5
+		addps	xmm5,	xmm6
+		addps	xmm6,	xmm7
+		addps	xmm7,	xmm0
+		// 29:
+		addps	xmm0,	xmm1
+		addps	xmm1,	xmm2
+		addps	xmm2,	xmm3
+		addps	xmm3,	xmm4
+		addps	xmm4,	xmm5
+		addps	xmm5,	xmm6
+		addps	xmm6,	xmm7
+		addps	xmm7,	xmm0
+		// 30:
+		addps	xmm0,	xmm1
+		addps	xmm1,	xmm2
+		addps	xmm2,	xmm3
+		addps	xmm3,	xmm4
+		addps	xmm4,	xmm5
+		addps	xmm5,	xmm6
+		addps	xmm6,	xmm7
+		addps	xmm7,	xmm0
+		// 31:
+		addps	xmm0,	xmm1
+		addps	xmm1,	xmm2
+		addps	xmm2,	xmm3
+		addps	xmm3,	xmm4
+		addps	xmm4,	xmm5
+		addps	xmm5,	xmm6
+		addps	xmm6,	xmm7
+		addps	xmm7,	xmm0
+		//----------------------
+		dec		eax
+		jnz		bsLoop
+	}
+#  else
+#    error "Unsupported compiler"
+#  endif /* COMPILER_MICROSOFT */
+#endif /* COMPILER_GCC */
+}
+#endif /* INLINE_ASSEMBLY_SUPPORTED */

+ 53 - 0
Source/ThirdParty/LibCpuId/src/asm-bits.h

@@ -0,0 +1,53 @@
+/*
+ * Copyright 2008  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 __ASM_BITS_H__
+#define __ASM_BITS_H__
+#include "libcpuid.h"
+
+/* Determine Compiler: */
+#if defined(_MSC_VER)
+#	define COMPILER_MICROSOFT
+#elif defined(__GNUC__)
+#	define COMPILER_GCC
+#endif
+
+/* Determine Platform */
+#if defined(__x86_64__) || defined(_M_AMD64)
+#	define PLATFORM_X64
+#elif defined(__i386__) || defined(_M_IX86)
+#	define PLATFORM_X86
+#endif
+
+/* Under Windows/AMD64 with MSVC, inline assembly isn't supported */
+#if (defined(COMPILER_GCC) && defined(PLATFORM_X64)) || defined(PLATFORM_X86)
+#	define INLINE_ASM_SUPPORTED
+#endif
+
+int cpuid_exists_by_eflags(void);
+void exec_cpuid(uint32_t *regs);
+void busy_sse_loop(int cycles);
+
+#endif /* __ASM_BITS_H__ */

+ 771 - 0
Source/ThirdParty/LibCpuId/src/cpuid_main.c

@@ -0,0 +1,771 @@
+/*
+ * Copyright 2008  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.
+ */
+#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
+#include "config.h"
+#endif
+#include <stdio.h>
+#include <string.h>
+#include <stdlib.h>
+
+/* Implementation: */
+
+static int _libcpiud_errno = ERR_OK;
+
+int set_error(cpu_error_t err)
+{
+	_libcpiud_errno = (int) err;
+	return (int) err;
+}
+
+static void raw_data_t_constructor(struct cpu_raw_data_t* raw)
+{
+	memset(raw, 0, sizeof(struct cpu_raw_data_t));
+}
+
+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 = 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;
+}
+
+static int parse_token(const char* expected_token, const char *token,
+                        const char *value, uint32_t array[][4], int limit, int *recognized)
+{
+	char format[32];
+	int veax, vebx, vecx, vedx;
+	int index;
+
+	if (*recognized) return 1; /* already recognized */
+	if (strncmp(token, expected_token, strlen(expected_token))) return 1; /* not what we search for */
+	sprintf(format, "%s[%%d]", expected_token);
+	*recognized = 1;
+	if (1 == sscanf(token, format, &index) && index >=0 && index < limit) {
+		if (4 == sscanf(value, "%x%x%x%x", &veax, &vebx, &vecx, &vedx)) {
+			array[index][0] = veax;
+			array[index][1] = vebx;
+			array[index][2] = vecx;
+			array[index][3] = vedx;
+			return 1;
+		}
+	}
+	return 0;
+}
+
+/* get_total_cpus() system specific code: uses OS routines to determine total number of CPUs */
+#ifdef __APPLE__
+#include <unistd.h>
+#include <mach/clock_types.h>
+#include <mach/clock.h>
+#include <mach/mach.h>
+static int get_total_cpus(void)
+{
+	kern_return_t kr;
+	host_basic_info_data_t basic_info;
+	host_info_t info = (host_info_t)&basic_info;
+	host_flavor_t flavor = HOST_BASIC_INFO;
+	mach_msg_type_number_t count = HOST_BASIC_INFO_COUNT;
+	kr = host_info(mach_host_self(), flavor, info, &count);
+	if (kr != KERN_SUCCESS) return 1;
+	return basic_info.avail_cpus;
+}
+#define GET_TOTAL_CPUS_DEFINED
+#endif
+
+#ifdef _WIN32
+#include <windows.h>
+static int get_total_cpus(void)
+{
+	SYSTEM_INFO system_info;
+	GetSystemInfo(&system_info);
+	return system_info.dwNumberOfProcessors;
+}
+#define GET_TOTAL_CPUS_DEFINED
+#endif
+
+#if defined linux || defined __linux__ || defined __sun
+#include <sys/sysinfo.h>
+#include <unistd.h>
+ 
+static int get_total_cpus(void)
+{
+	return sysconf(_SC_NPROCESSORS_ONLN);
+}
+#define GET_TOTAL_CPUS_DEFINED
+#endif
+
+#if defined __FreeBSD__ || defined __OpenBSD__ || defined __NetBSD__ || defined __bsdi__ || defined __QNX__
+#include <sys/types.h>
+#include <sys/sysctl.h>
+
+static int get_total_cpus(void)
+{
+	int mib[2] = { CTL_HW, HW_NCPU };
+	int ncpus;
+	size_t len = sizeof(ncpus);
+	if (sysctl(mib, 2, &ncpus, &len, (void *) 0, 0) != 0) return 1;
+	return ncpus;
+}
+#define GET_TOTAL_CPUS_DEFINED
+#endif
+
+#ifndef GET_TOTAL_CPUS_DEFINED
+static int get_total_cpus(void)
+{
+	static int warning_printed = 0;
+	if (!warning_printed) {
+		warning_printed = 1;
+		warnf("Your system is not supported by libcpuid -- don't know how to detect the\n");
+		warnf("total number of CPUs on your system. It will be reported as 1.\n");
+		printf("Please use cpu_id_t.logical_cpus field instead.\n");
+	}
+	return 1;
+}
+#endif /* GET_TOTAL_CPUS_DEFINED */
+
+
+static void load_features_common(struct cpu_raw_data_t* raw, struct cpu_id_t* data)
+{
+	const struct feature_map_t matchtable_edx1[] = {
+		{  0, CPU_FEATURE_FPU },
+		{  1, CPU_FEATURE_VME },
+		{  2, CPU_FEATURE_DE },
+		{  3, CPU_FEATURE_PSE },
+		{  4, CPU_FEATURE_TSC },
+		{  5, CPU_FEATURE_MSR },
+		{  6, CPU_FEATURE_PAE },
+		{  7, CPU_FEATURE_MCE },
+		{  8, CPU_FEATURE_CX8 },
+		{  9, CPU_FEATURE_APIC },
+		{ 11, CPU_FEATURE_SEP },
+		{ 12, CPU_FEATURE_MTRR },
+		{ 13, CPU_FEATURE_PGE },
+		{ 14, CPU_FEATURE_MCA },
+		{ 15, CPU_FEATURE_CMOV },
+		{ 16, CPU_FEATURE_PAT },
+		{ 17, CPU_FEATURE_PSE36 },
+		{ 19, CPU_FEATURE_CLFLUSH },
+		{ 23, CPU_FEATURE_MMX },
+		{ 24, CPU_FEATURE_FXSR },
+		{ 25, CPU_FEATURE_SSE },
+		{ 26, CPU_FEATURE_SSE2 },
+		{ 28, CPU_FEATURE_HT },
+	};
+	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 },
+		{ 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 },
+		{ 27, CPU_FEATURE_RDTSCP },
+		{ 29, CPU_FEATURE_LM },
+	};
+	const struct feature_map_t matchtable_ecx81[] = {
+		{  0, CPU_FEATURE_LAHF_LM },
+	};
+	const struct feature_map_t matchtable_edx87[] = {
+		{  8, CPU_FEATURE_CONSTANT_TSC },
+	};
+	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] >= 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);
+	}
+	if (raw->ext_cpuid[0][0] >= 0x80000007) {
+		match_features(matchtable_edx87, COUNT_OF(matchtable_edx87), raw->ext_cpuid[7][3], data);
+	}
+	if (data->flags[CPU_FEATURE_SSE]) {
+		/* apply guesswork to check if the SSE unit width is 128 bit */
+		switch (data->vendor) {
+			case VENDOR_AMD:
+				data->sse_size = (data->ext_family >= 16 && data->ext_family != 17) ? 128 : 64;
+				break;
+			case VENDOR_INTEL:
+				data->sse_size = (data->family == 6 && data->ext_model >= 15) ? 128 : 64;
+				break;
+			default:
+				break;
+		}
+		/* leave the CPU_FEATURE_128BIT_SSE_AUTH 0; the advanced per-vendor detection routines
+		 * will set it accordingly if they detect the needed bit */
+	}
+}
+
+static cpu_vendor_t cpuid_vendor_identify(const uint32_t *raw_vendor, char *vendor_str)
+{
+	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 */
+		{ VENDOR_INTEL		, "GenuineIntel" },
+		{ VENDOR_AMD		, "AuthenticAMD" },
+		{ VENDOR_CYRIX		, "CyrixInstead" },
+		{ VENDOR_NEXGEN		, "NexGenDriven" },
+		{ VENDOR_TRANSMETA	, "GenuineTMx86" },
+		{ VENDOR_UMC		, "UMC UMC UMC " },
+		{ VENDOR_CENTAUR	, "CentaurHauls" },
+		{ VENDOR_RISE		, "RiseRiseRise" },
+		{ VENDOR_SIS		, "SiS SiS SiS " },
+		{ VENDOR_NSC		, "Geode by NSC" },
+	};
+
+	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: */
+	for (i = 0; i < NUM_CPU_VENDORS; i++)
+		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];
+	if (basic >= 1) {
+		data->family = (raw->basic_cpuid[1][0] >> 8) & 0xf;
+		data->model = (raw->basic_cpuid[1][0] >> 4) & 0xf;
+		data->stepping = raw->basic_cpuid[1][0] & 0xf;
+		xmodel = (raw->basic_cpuid[1][0] >> 16) & 0xf;
+		xfamily = (raw->basic_cpuid[1][0] >> 20) & 0xff;
+		if (data->vendor == VENDOR_AMD && data->family < 0xf)
+			data->ext_family = data->family;
+		else
+			data->ext_family = data->family + xfamily;
+		data->ext_model = data->model + (xmodel << 4);
+	}
+	ext = raw->ext_cpuid[0][0] - 0x8000000;
+	
+	/* obtain the brand string, if present: */
+	if (ext >= 4) {
+		for (i = 0; i < 3; i++)
+			for (j = 0; j < 4; j++)
+				memcpy(brandstr + i * 16 + j * 4,
+				       &raw->ext_cpuid[2 + i][j], 4);
+		brandstr[48] = 0;
+		i = 0;
+		while (brandstr[i] == ' ') i++;
+		strncpy(data->brand_str, brandstr + i, sizeof(data->brand_str));
+		data->brand_str[48] = 0;
+	}
+	load_features_common(raw, data);
+	data->total_logical_cpus = get_total_cpus();
+	return set_error(ERR_OK);
+}
+
+static void make_list_from_string(const char* csv, struct cpu_list_t* list)
+{
+	int i, n, l, last;
+	l = (int) strlen(csv);
+	n = 0;
+	for (i = 0; i < l; i++) if (csv[i] == ',') n++;
+	n++;
+	list->num_entries = n;
+	list->names = (char**) malloc(sizeof(char*) * n);
+	last = -1;
+	n = 0;
+	for (i = 0; i <= l; i++) if (i == l || csv[i] == ',') {
+		list->names[n] = (char*) malloc(i - last);
+		memcpy(list->names[n], &csv[last + 1], i - last - 1);
+		list->names[n][i - last - 1] = '\0';
+		n++;
+		last = i;
+	}
+}
+
+
+/* Interface: */
+
+int cpuid_get_total_cpus(void)
+{
+	return get_total_cpus();
+}
+
+int cpuid_present(void)
+{
+	return cpuid_exists_by_eflags();
+}
+
+void cpu_exec_cpuid(uint32_t eax, uint32_t* regs)
+{
+	regs[0] = eax;
+	regs[1] = regs[2] = regs[3] = 0;
+	exec_cpuid(regs);
+}
+
+void cpu_exec_cpuid_ext(uint32_t* regs)
+{
+	exec_cpuid(regs);
+}
+
+int cpuid_get_raw_data(struct cpu_raw_data_t* data)
+{
+	unsigned i;
+	if (!cpuid_present())
+		return set_error(ERR_NO_CPUID);
+	for (i = 0; i < 32; i++)
+		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 < 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;
+		cpu_exec_cpuid_ext(data->intel_fn4[i]);
+	}
+	for (i = 0; i < MAX_INTELFN11_LEVEL; i++) {
+		memset(data->intel_fn11[i], 0, sizeof(data->intel_fn11[i]));
+		data->intel_fn11[i][0] = 11;
+		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);
+}
+
+int cpuid_serialize_raw_data(struct cpu_raw_data_t* data, const char* filename)
+{
+	int i;
+	FILE *f;
+	
+	if (!strcmp(filename, ""))
+		f = stdout;
+	else
+		f = fopen(filename, "wt");
+	if (!f) return set_error(ERR_OPEN);
+	
+	fprintf(f, "version=%s\n", VERSION);
+	for (i = 0; i < MAX_CPUID_LEVEL; i++)
+		fprintf(f, "basic_cpuid[%d]=%08x %08x %08x %08x\n", i,
+			data->basic_cpuid[i][0], data->basic_cpuid[i][1],
+			data->basic_cpuid[i][2], data->basic_cpuid[i][3]);
+	for (i = 0; i < MAX_EXT_CPUID_LEVEL; i++)
+		fprintf(f, "ext_cpuid[%d]=%08x %08x %08x %08x\n", i,
+			data->ext_cpuid[i][0], data->ext_cpuid[i][1],
+			data->ext_cpuid[i][2], data->ext_cpuid[i][3]);
+	for (i = 0; i < MAX_INTELFN4_LEVEL; i++)
+		fprintf(f, "intel_fn4[%d]=%08x %08x %08x %08x\n", i,
+			data->intel_fn4[i][0], data->intel_fn4[i][1],
+			data->intel_fn4[i][2], data->intel_fn4[i][3]);
+	for (i = 0; i < MAX_INTELFN11_LEVEL; 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][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);
+	return set_error(ERR_OK);
+}
+
+int cpuid_deserialize_raw_data(struct cpu_raw_data_t* data, const char* filename)
+{
+	int i, len;
+	char line[100];
+	char token[100];
+	char *value;
+	int syntax;
+	int cur_line = 0;
+	int recognized;
+	FILE *f;
+	
+	raw_data_t_constructor(data);
+	
+	if (!strcmp(filename, ""))
+		f = stdin;
+	else
+		f = fopen(filename, "rt");
+	if (!f) return set_error(ERR_OPEN);
+	while (fgets(line, sizeof(line), f)) {
+		++cur_line;
+		len = (int) strlen(line);
+		if (len < 2) continue;
+		if (line[len - 1] == '\n')
+			line[--len] = '\0';
+		for (i = 0; i < len && line[i] != '='; i++)
+		if (i >= len && i < 1 && len - i - 1 <= 0) {
+			fclose(f);
+			return set_error(ERR_BADFMT);
+		}
+		strncpy(token, line, i);
+		token[i] = '\0';
+		value = &line[i + 1];
+		/* try to recognize the line */
+		recognized = 0;
+		if (!strcmp(token, "version") || !strcmp(token, "build_date")) {
+			recognized = 1;
+		}
+		syntax = 1;
+		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);
+			return set_error(ERR_BADFMT);
+		}
+		if (!recognized) {
+			warnf("Warning: %s:%d not understood!\n", filename, cur_line);
+		}
+	}
+	
+	if (strcmp(filename, ""))
+		fclose(f);
+	return set_error(ERR_OK);
+}
+
+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;
+	if (!raw) {
+		if ((r = cpuid_get_raw_data(&myraw)) < 0)
+			return set_error(r);
+		raw = &myraw;
+	}
+	cpu_id_t_constructor(data);
+	if ((r = cpuid_basic_identify(raw, data)) < 0)
+		return set_error(r);
+	switch (data->vendor) {
+		case VENDOR_INTEL:
+			r = cpuid_identify_intel(raw, data, internal);
+			break;
+		case VENDOR_AMD:
+			r = cpuid_identify_amd(raw, data, internal);
+			break;
+		default:
+			break;
+	}
+	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; }
+	matchtable[] = {
+		{ CPU_FEATURE_FPU, "fpu" },
+		{ CPU_FEATURE_VME, "vme" },
+		{ CPU_FEATURE_DE, "de" },
+		{ CPU_FEATURE_PSE, "pse" },
+		{ CPU_FEATURE_TSC, "tsc" },
+		{ CPU_FEATURE_MSR, "msr" },
+		{ CPU_FEATURE_PAE, "pae" },
+		{ CPU_FEATURE_MCE, "mce" },
+		{ CPU_FEATURE_CX8, "cx8" },
+		{ CPU_FEATURE_APIC, "apic" },
+		{ CPU_FEATURE_MTRR, "mtrr" },
+		{ CPU_FEATURE_SEP, "sep" },
+		{ CPU_FEATURE_PGE, "pge" },
+		{ CPU_FEATURE_MCA, "mca" },
+		{ CPU_FEATURE_CMOV, "cmov" },
+		{ CPU_FEATURE_PAT, "pat" },
+		{ CPU_FEATURE_PSE36, "pse36" },
+		{ CPU_FEATURE_PN, "pn" },
+		{ CPU_FEATURE_CLFLUSH, "clflush" },
+		{ CPU_FEATURE_DTS, "dts" },
+		{ CPU_FEATURE_ACPI, "acpi" },
+		{ CPU_FEATURE_MMX, "mmx" },
+		{ CPU_FEATURE_FXSR, "fxsr" },
+		{ CPU_FEATURE_SSE, "sse" },
+		{ CPU_FEATURE_SSE2, "sse2" },
+		{ CPU_FEATURE_SS, "ss" },
+		{ CPU_FEATURE_HT, "ht" },
+		{ CPU_FEATURE_TM, "tm" },
+		{ CPU_FEATURE_IA64, "ia64" },
+		{ CPU_FEATURE_PBE, "pbe" },
+		{ CPU_FEATURE_PNI, "pni" },
+		{ CPU_FEATURE_PCLMUL, "pclmul" },
+		{ CPU_FEATURE_DTS64, "dts64" },
+		{ CPU_FEATURE_MONITOR, "monitor" },
+		{ CPU_FEATURE_DS_CPL, "ds_cpl" },
+		{ CPU_FEATURE_VMX, "vmx" },
+		{ CPU_FEATURE_SMX, "smx" },
+		{ CPU_FEATURE_EST, "est" },
+		{ CPU_FEATURE_TM2, "tm2" },
+		{ CPU_FEATURE_SSSE3, "ssse3" },
+		{ CPU_FEATURE_CID, "cid" },
+		{ CPU_FEATURE_CX16, "cx16" },
+		{ CPU_FEATURE_XTPR, "xtpr" },
+		{ CPU_FEATURE_PDCM, "pdcm" },
+		{ CPU_FEATURE_DCA, "dca" },
+		{ CPU_FEATURE_SSE4_1, "sse4_1" },
+		{ CPU_FEATURE_SSE4_2, "sse4_2" },
+		{ CPU_FEATURE_SYSCALL, "syscall" },
+		{ CPU_FEATURE_XD, "xd" },
+		{ CPU_FEATURE_X2APIC, "x2apic"},
+		{ CPU_FEATURE_MOVBE, "movbe" },
+		{ CPU_FEATURE_POPCNT, "popcnt" },
+		{ CPU_FEATURE_AES, "aes" },
+		{ CPU_FEATURE_XSAVE, "xsave" },
+		{ CPU_FEATURE_OSXSAVE, "osxsave" },
+		{ CPU_FEATURE_AVX, "avx" },
+		{ CPU_FEATURE_MMXEXT, "mmxext" },
+		{ CPU_FEATURE_3DNOW, "3dnow" },
+		{ CPU_FEATURE_3DNOWEXT, "3dnowext" },
+		{ CPU_FEATURE_NX, "nx" },
+		{ CPU_FEATURE_FXSR_OPT, "fxsr_opt" },
+		{ CPU_FEATURE_RDTSCP, "rdtscp" },
+		{ CPU_FEATURE_LM, "lm" },
+		{ CPU_FEATURE_LAHF_LM, "lahf_lm" },
+		{ CPU_FEATURE_CMP_LEGACY, "cmp_legacy" },
+		{ CPU_FEATURE_SVM, "svm" },
+		{ CPU_FEATURE_SSE4A, "sse4a" },
+		{ CPU_FEATURE_MISALIGNSSE, "misalignsse" },
+		{ CPU_FEATURE_ABM, "abm" },
+		{ CPU_FEATURE_3DNOWPREFETCH, "3dnowprefetch" },
+		{ CPU_FEATURE_OSVW, "osvw" },
+		{ CPU_FEATURE_IBS, "ibs" },
+		{ CPU_FEATURE_SSE5, "sse5" },
+		{ CPU_FEATURE_SKINIT, "skinit" },
+		{ CPU_FEATURE_WDT, "wdt" },
+		{ CPU_FEATURE_TS, "ts" },
+		{ CPU_FEATURE_FID, "fid" },
+		{ CPU_FEATURE_VID, "vid" },
+		{ CPU_FEATURE_TTP, "ttp" },
+		{ CPU_FEATURE_TM_AMD, "tm_amd" },
+		{ CPU_FEATURE_STC, "stc" },
+		{ CPU_FEATURE_100MHZSTEPS, "100mhzsteps" },
+		{ CPU_FEATURE_HWPSTATE, "hwpstate" },
+		{ CPU_FEATURE_CONSTANT_TSC, "constant_tsc" },
+		{ CPU_FEATURE_XOP, "xop" },
+		{ CPU_FEATURE_FMA3, "fma3" },
+		{ CPU_FEATURE_FMA4, "fma4" },
+		{ CPU_FEATURE_TBM, "tbm" },
+		{ CPU_FEATURE_F16C, "f16c" },
+		{ CPU_FEATURE_RDRAND, "rdrand" },
+		{ CPU_FEATURE_CPB, "cpb" },
+		{ CPU_FEATURE_APERFMPERF, "aperfmperf" },
+		{ 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) {
+		warnf("Warning: incomplete library, feature matchtable size differs from the actual number of features.\n");
+	}
+	for (i = 0; i < n; i++)
+		if (matchtable[i].feature == feature)
+			return matchtable[i].name;
+	return "";
+}
+
+const char* cpuid_error(void)
+{
+	const struct { cpu_error_t error; const char *description; }
+	matchtable[] = {
+		{ ERR_OK       , "No error"},
+		{ ERR_NO_CPUID , "CPUID instruction is not supported"},
+		{ ERR_NO_RDTSC , "RDTSC instruction is not supported"},
+		{ ERR_NO_MEM   , "Memory allocation failed"},
+		{ ERR_OPEN     , "File open operation failed"},
+		{ 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++)
+		if (_libcpiud_errno == matchtable[i].error)
+			return matchtable[i].description;
+	return "Unknown error";
+}
+
+
+const char* cpuid_lib_version(void)
+{
+	return VERSION;
+}
+
+libcpuid_warn_fn_t cpuid_set_warn_function(libcpuid_warn_fn_t new_fn)
+{
+	libcpuid_warn_fn_t ret = _warn_fun;
+	_warn_fun = new_fn;
+	return ret;
+}
+
+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) {
+		case VENDOR_INTEL:
+			cpuid_get_list_intel(list);
+			break;
+		case VENDOR_AMD:
+			cpuid_get_list_amd(list);
+			break;
+		case VENDOR_CYRIX:
+			make_list_from_string("Cx486,Cx5x86,6x86,6x86MX,M II,MediaGX,MediaGXi,MediaGXm", list);
+			break;
+		case VENDOR_NEXGEN:
+			make_list_from_string("Nx586", list);
+			break;
+		case VENDOR_TRANSMETA:
+			make_list_from_string("Crusoe,Efficeon", list);
+			break;
+		case VENDOR_UMC:
+			make_list_from_string("UMC x86 CPU", list);
+			break;
+		case VENDOR_CENTAUR:
+			make_list_from_string("VIA C3,VIA C7,VIA Nano", list);
+			break;
+		case VENDOR_RISE:
+			make_list_from_string("Rise mP6", list);
+			break;
+		case VENDOR_SIS:
+			make_list_from_string("SiS mP6", list);
+			break;
+		case VENDOR_NSC:
+			make_list_from_string("Geode GXm,Geode GXLV,Geode GX1,Geode GX2", list);
+			break;
+		default:
+			warnf("Unknown vendor passed to cpuid_get_cpu_list()\n");
+			break;
+ 	}
+}
+
+void cpuid_free_cpu_list(struct cpu_list_t* list)
+{
+	int i;
+	if (list->num_entries <= 0) return;
+	for (i = 0; i < list->num_entries; i++)
+		free(list->names[i]);
+	free(list->names);
+}

+ 84 - 0
Source/ThirdParty/LibCpuId/src/embed_drivers.cpp

@@ -0,0 +1,84 @@
+// A simple utility to read and embed the MSR drivers for X86
+
+#include <stdio.h>
+#include <string.h>
+#include <stdlib.h>
+#include <vector>
+#include <string>
+using namespace std;
+
+const char* drivers_root = "..\\contrib\\MSR Driver\\";
+const char* sourcefile = "msrdriver.c";
+
+char* images[2];
+int sizes[2];
+const char* filenames[] = { "TmpRdr.sys", "TmpRdr64.sys" };
+vector<string> source;
+
+bool read_image(const char* filename, char*& image, int& isize)
+{
+	char fn[512];
+	sprintf(fn, "%s%s", drivers_root, filename);
+	FILE* f = fopen(fn, "rb");
+	if (!f) return false;
+	fseek(f, 0, SEEK_END);
+	long size = ftell(f);
+	isize = (int) size;
+	rewind(f);
+	image = new char[size];
+	fread(image, 1, size, f);
+	fclose(f);
+	return true;
+}
+
+bool read_source(const char* filename)
+{
+	source.clear();
+	FILE* f = fopen(filename, "rt");
+	if (!f) return false;
+	char line[200];
+	while (fgets(line, sizeof(line), f)) {
+		int i = (int) strlen(line);
+		if (i && line[i - 1] == '\n') line[--i] = 0;
+		source.push_back(string(line));
+	}
+	fclose(f);
+	return true;
+}
+
+void print_image(FILE* f, const char* arch, const char* image, int size)
+{
+	fprintf(f, "int cc_%sdriver_code_size = %d;\n", arch, size);
+	fprintf(f, "uint8_t cc_%sdriver_code[%d] = {", arch, size);
+	for (int i = 0; i < size; i++) {
+		if (i % 18 == 0) fprintf(f, "\n\t");
+		fprintf(f, "0x%02x,", (unsigned) (unsigned char) image[i]);
+	}
+	fprintf(f, "\n};\n");
+}
+
+int main(void)
+{
+	for (int i = 0; i < 2; i++)
+		if (!read_image(filenames[i], images[i], sizes[i])) {
+			printf("Cannot read image `%s' from `%s'!\n", filenames[i], drivers_root);
+			return -1;
+		}
+	if (!read_source(sourcefile)) {
+		printf("Cannot read source `%s'\n", sourcefile);
+		return -2;
+	}
+	FILE* f = fopen(sourcefile, "wt");
+	bool on = true;
+	for (unsigned i = 0; i < source.size(); i++) {
+		if (source[i] == "//} end")
+			on = true;
+		if (on) fprintf(f, "%s\n", source[i].c_str());
+		if (source[i] == "//begin {") {
+			on = false;
+			print_image(f, "x86", images[0], sizes[0]);
+			print_image(f, "x64", images[1], sizes[1]);
+		}
+	}
+	return 0;
+}

+ 58 - 0
Source/ThirdParty/LibCpuId/src/intel_code_t.h

@@ -0,0 +1,58 @@
+/*
+ * 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(IRWIN),
+	CODE(POTOMAC),
+	CODE(GAINESTOWN),
+	CODE(WESTMERE),
+	
+	CODE(PENTIUM_M),
+	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(SILVERTHORNE),
+	CODE(DIAMONDVILLE),
+	CODE(PINEVIEW),
+	CODE(CEDARVIEW),

+ 1150 - 0
Source/ThirdParty/LibCpuId/src/libcpuid.h

@@ -0,0 +1,1150 @@
+/*
+ * Copyright 2008  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_H__
+#define __LIBCPUID_H__
+/**
+ * \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.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
+ *
+ * LibCPUID provides CPU identification and access to the CPUID and RDTSC
+ * instructions on the x86.
+ * <p>
+ * To execute CPUID, use \ref cpu_exec_cpuid <br>
+ * To execute RDTSC, use \ref cpu_rdtsc <br>
+ * To fetch the CPUID info needed for CPU identification, use
+ *   \ref cpuid_get_raw_data <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>
+ */
+
+/** @defgroup libcpuid LibCPUID
+ @{ */
+
+/* Include some integer type specifications: */
+#include "libcpuid_types.h"
+
+/* Some limits and other constants */
+#include "libcpuid_constants.h"
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+/**
+ * @brief CPU vendor, as guessed from the Vendor String.
+ */
+typedef enum {
+	VENDOR_INTEL = 0,  /*!< Intel CPU */
+	VENDOR_AMD,        /*!< AMD CPU */
+	VENDOR_CYRIX,      /*!< Cyrix CPU */
+	VENDOR_NEXGEN,     /*!< NexGen CPU */
+	VENDOR_TRANSMETA,  /*!< Transmeta CPU */
+	VENDOR_UMC,        /*!< x86 CPU by UMC */
+	VENDOR_CENTAUR,    /*!< x86 CPU by IDT */
+	VENDOR_RISE,       /*!< x86 CPU by Rise Technology */
+	VENDOR_SIS,        /*!< x86 CPU by SiS */
+	VENDOR_NSC,        /*!< x86 CPU by National Semiconductor */
+	
+	NUM_CPU_VENDORS,   /*!< Valid CPU vendor ids: 0..NUM_CPU_VENDORS - 1 */
+	VENDOR_UNKNOWN = -1,
+} cpu_vendor_t;
+#define NUM_CPU_VENDORS NUM_CPU_VENDORS
+
+/**
+ * @brief Contains just the raw CPUID data.
+ *
+ * This contains only the most basic CPU data, required to do identification
+ * and feature recognition. Every processor should be identifiable using this
+ * data only.
+ */
+struct cpu_raw_data_t {
+	/** contains results of CPUID for eax = 0, 1, ...*/
+	uint32_t basic_cpuid[MAX_CPUID_LEVEL][4];
+
+	/** contains results of CPUID for eax = 0x80000000, 0x80000001, ...*/
+	uint32_t ext_cpuid[MAX_EXT_CPUID_LEVEL][4];
+	
+	/** when the CPU is intel and it supports deterministic cache
+	    information: this contains the results of CPUID for eax = 4
+	    and ecx = 0, 1, ... */
+	uint32_t intel_fn4[MAX_INTELFN4_LEVEL][4];
+	
+	/** when the CPU is intel and it supports leaf 0Bh (Extended Topology
+	    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;
+};
+
+/**
+ * @brief This contains the recognized CPU features/info
+ */
+struct cpu_id_t {
+	/** contains the CPU vendor string, e.g. "GenuineIntel" */
+	char vendor_str[VENDOR_STR_MAX];
+	
+	/** contains the brand string, e.g. "Intel(R) Xeon(TM) CPU 2.40GHz" */
+	char brand_str[BRAND_STR_MAX];
+	
+	/** contains the recognized CPU vendor */
+	cpu_vendor_t vendor;
+	
+	/**
+	 * contain CPU flags. Used to test for features. See
+	 * the \ref cpu_feature_t "CPU_FEATURE_*" macros below.
+	 * @see Features
+	 */
+	uint8_t flags[CPU_FLAGS_MAX];
+	
+	/** CPU family */
+	int32_t family;
+	
+	/** CPU model */
+	int32_t model;
+	
+	/** CPU stepping */
+	int32_t stepping;
+	
+	/** CPU extended family */
+	int32_t ext_family;
+	
+	/** CPU extended model */
+	int32_t ext_model;
+	
+	/** Number of CPU cores on the current processor */
+	int32_t num_cores;
+	
+	/**
+	 * Number of logical processors on the current processor.
+	 * Could be more than the number of physical cores,
+	 * e.g. when the processor has HyperThreading.
+	 */
+	int32_t num_logical_cpus;
+	
+	/**
+	 * 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;
+	
+	/**
+	 * L1 data cache size in KB. Could be zero, if the CPU lacks cache.
+	 * If the size cannot be determined, it will be -1.
+	 */
+	int32_t l1_data_cache;
+	
+	/**
+	 * L1 instruction cache size in KB. Could be zero, if the CPU lacks
+	 * cache. If the size cannot be determined, it will be -1.
+	 * @note On some Intel CPUs, whose instruction cache is in fact
+	 * a trace cache, the size will be expressed in K uOps.
+	 */
+	int32_t l1_instruction_cache;
+	
+	/**
+	 * L2 cache size in KB. Could be zero, if the CPU lacks L2 cache.
+	 * If the size of the cache could not be determined, it will be -1
+	 */
+	int32_t l2_cache;
+	
+	/** 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;
+	
+	/** Cache associativity for the L2 cache. -1 if undetermined */
+	int32_t l2_assoc;
+	
+	/** 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;
+	
+	/** Cache-line size for L2 cache. -1 if undetermined */
+	int32_t l2_cacheline;
+	
+	/** 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.<br>
+	 * Examples:
+	 * @code
+	 * +--------+--------+-------+-------+-------+---------------------------------------+-----------------------+
+	 * | Vendor | Family | Model | Step. | Cache |       Brand String                    | cpu_id_t.cpu_codename |
+	 * +--------+--------+-------+-------+-------+---------------------------------------+-----------------------+
+	 * | AMD    |      6 |     8 |     0 |   256 | (not available - will be ignored)     | "K6-2"                |
+	 * | Intel  |     15 |     2 |     5 |   512 | "Intel(R) Xeon(TM) CPU 2.40GHz"       | "Xeon (Prestonia)"    |
+	 * | Intel  |      6 |    15 |    11 |  4096 | "Intel(R) Core(TM)2 Duo CPU E6550..." | "Conroe (Core 2 Duo)" |
+	 * | AMD    |     15 |    35 |     2 |  1024 | "Dual Core AMD Opteron(tm) Proces..." | "Opteron (Dual Core)" |
+	 * +--------+--------+-------+-------+-------+---------------------------------------+-----------------------+
+	 * @endcode
+	 */
+	char cpu_codename[64];
+	
+	/** SSE execution unit size (64 or 128; -1 if N/A) */
+	int32_t sse_size;
+	
+	/**
+	 * contain miscellaneous detection information. Used to test about specifics of
+	 * 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;
+};
+
+/**
+ * @brief CPU feature identifiers
+ *
+ * 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) {
+ *     if (id.flags[CPU_FEATURE_SSE2]) {
+ *         // The CPU has SSE2...
+ *         ...
+ *     } else {
+ *         // no SSE2
+ *     }
+ * } else {
+ *   // processor cannot be determined.
+ * }
+ * @endcode
+ */
+typedef enum {
+	CPU_FEATURE_FPU = 0,	/*!< Floating point unit */
+	CPU_FEATURE_VME,	/*!< Virtual mode extension */
+	CPU_FEATURE_DE,		/*!< Debugging extension */
+	CPU_FEATURE_PSE,	/*!< Page size extension */
+	CPU_FEATURE_TSC,	/*!< Time-stamp counter */
+	CPU_FEATURE_MSR,	/*!< Model-specific regsisters, RDMSR/WRMSR supported */
+	CPU_FEATURE_PAE,	/*!< Physical address extension */
+	CPU_FEATURE_MCE,	/*!< Machine check exception */
+	CPU_FEATURE_CX8,	/*!< CMPXCHG8B instruction supported */
+	CPU_FEATURE_APIC,	/*!< APIC support */
+	CPU_FEATURE_MTRR,	/*!< Memory type range registers */
+	CPU_FEATURE_SEP,	/*!< SYSENTER / SYSEXIT instructions supported */
+	CPU_FEATURE_PGE,	/*!< Page global enable */
+	CPU_FEATURE_MCA,	/*!< Machine check architecture */
+	CPU_FEATURE_CMOV,	/*!< CMOVxx instructions supported */
+	CPU_FEATURE_PAT,	/*!< Page attribute table */
+	CPU_FEATURE_PSE36,	/*!< 36-bit page address extension */
+	CPU_FEATURE_PN,		/*!< Processor serial # implemented (Intel P3 only) */
+	CPU_FEATURE_CLFLUSH,	/*!< CLFLUSH instruction supported */
+	CPU_FEATURE_DTS,	/*!< Debug store supported */
+	CPU_FEATURE_ACPI,	/*!< ACPI support (power states) */
+	CPU_FEATURE_MMX,	/*!< MMX instruction set supported */
+	CPU_FEATURE_FXSR,	/*!< FXSAVE / FXRSTOR supported */
+	CPU_FEATURE_SSE,	/*!< Streaming-SIMD Extensions (SSE) supported */
+	CPU_FEATURE_SSE2,	/*!< SSE2 instructions supported */
+	CPU_FEATURE_SS,		/*!< Self-snoop */
+	CPU_FEATURE_HT,		/*!< Hyper-threading supported (but might be disabled) */
+	CPU_FEATURE_TM,		/*!< Thermal monitor */
+	CPU_FEATURE_IA64,	/*!< IA64 supported (Itanium only) */
+	CPU_FEATURE_PBE,	/*!< Pending-break enable */
+	CPU_FEATURE_PNI,	/*!< PNI (SSE3) instructions supported */
+	CPU_FEATURE_PCLMUL,	/*!< PCLMULQDQ instruction supported */
+	CPU_FEATURE_DTS64,	/*!< 64-bit Debug store supported */
+	CPU_FEATURE_MONITOR,	/*!< MONITOR / MWAIT supported */
+	CPU_FEATURE_DS_CPL,	/*!< CPL Qualified Debug Store */
+	CPU_FEATURE_VMX,	/*!< Virtualization technology supported */
+	CPU_FEATURE_SMX,	/*!< Safer mode exceptions */
+	CPU_FEATURE_EST,	/*!< Enhanced SpeedStep */
+	CPU_FEATURE_TM2,	/*!< Thermal monitor 2 */
+	CPU_FEATURE_SSSE3,	/*!< SSSE3 instructionss supported (this is different from SSE3!) */
+	CPU_FEATURE_CID,	/*!< Context ID supported */
+	CPU_FEATURE_CX16,	/*!< CMPXCHG16B instruction supported */
+	CPU_FEATURE_XTPR,	/*!< Send Task Priority Messages disable */
+	CPU_FEATURE_PDCM,	/*!< Performance capabilities MSR supported */
+	CPU_FEATURE_DCA,	/*!< Direct cache access supported */
+	CPU_FEATURE_SSE4_1,	/*!< SSE 4.1 instructions supported */
+	CPU_FEATURE_SSE4_2,	/*!< SSE 4.2 instructions supported */
+	CPU_FEATURE_SYSCALL,	/*!< SYSCALL / SYSRET instructions supported */
+	CPU_FEATURE_XD,		/*!< Execute disable bit supported */
+	CPU_FEATURE_MOVBE,	/*!< MOVBE instruction supported */
+	CPU_FEATURE_POPCNT,	/*!< POPCNT instruction supported */
+	CPU_FEATURE_AES,	/*!< AES* instructions supported */
+	CPU_FEATURE_XSAVE,	/*!< XSAVE/XRSTOR/etc instructions supported */
+	CPU_FEATURE_OSXSAVE,	/*!< non-privileged copy of OSXSAVE supported */
+	CPU_FEATURE_AVX,	/*!< Advanced vector extensions supported */
+	CPU_FEATURE_MMXEXT,	/*!< AMD MMX-extended instructions supported */
+	CPU_FEATURE_3DNOW,	/*!< AMD 3DNow! instructions supported */
+	CPU_FEATURE_3DNOWEXT,	/*!< AMD 3DNow! extended instructions supported */
+	CPU_FEATURE_NX,		/*!< No-execute bit supported */
+	CPU_FEATURE_FXSR_OPT,	/*!< FFXSR: FXSAVE and FXRSTOR optimizations */
+	CPU_FEATURE_RDTSCP,	/*!< RDTSCP instruction supported (AMD-only) */
+	CPU_FEATURE_LM,		/*!< Long mode (x86_64/EM64T) supported */
+	CPU_FEATURE_LAHF_LM,	/*!< LAHF/SAHF supported in 64-bit mode */
+	CPU_FEATURE_CMP_LEGACY,	/*!< core multi-processing legacy mode */
+	CPU_FEATURE_SVM,	/*!< AMD Secure virtual machine */
+	CPU_FEATURE_ABM,	/*!< LZCNT instruction support */
+	CPU_FEATURE_MISALIGNSSE,/*!< Misaligned SSE supported */
+	CPU_FEATURE_SSE4A,	/*!< SSE 4a from AMD */
+	CPU_FEATURE_3DNOWPREFETCH,	/*!< PREFETCH/PREFETCHW support */
+	CPU_FEATURE_OSVW,	/*!< OS Visible Workaround (AMD) */
+	CPU_FEATURE_IBS,	/*!< Instruction-based sampling */
+	CPU_FEATURE_SSE5,	/*!< SSE 5 instructions supported (deprecated, will never be 1) */
+	CPU_FEATURE_SKINIT,	/*!< SKINIT / STGI supported */
+	CPU_FEATURE_WDT,	/*!< Watchdog timer support */
+	CPU_FEATURE_TS,		/*!< Temperature sensor */
+	CPU_FEATURE_FID,	/*!< Frequency ID control */
+	CPU_FEATURE_VID,	/*!< Voltage ID control */
+	CPU_FEATURE_TTP,	/*!< THERMTRIP */
+	CPU_FEATURE_TM_AMD,	/*!< AMD-specified hardware thermal control */
+	CPU_FEATURE_STC,	/*!< Software thermal control */
+	CPU_FEATURE_100MHZSTEPS,/*!< 100 MHz multiplier control */
+	CPU_FEATURE_HWPSTATE,	/*!< Hardware P-state control */
+	CPU_FEATURE_CONSTANT_TSC,	/*!< TSC ticks at constant rate */
+	CPU_FEATURE_XOP,	/*!< The XOP instruction set (same as the old CPU_FEATURE_SSE5) */
+	CPU_FEATURE_FMA3,	/*!< The FMA3 instruction set */
+	CPU_FEATURE_FMA4,	/*!< The FMA4 instruction set */
+	CPU_FEATURE_TBM,	/*!< Trailing bit manipulation instruction support */
+	CPU_FEATURE_F16C,	/*!< 16-bit FP convert instruction support */
+	CPU_FEATURE_RDRAND,     /*!< RdRand instruction */
+	CPU_FEATURE_X2APIC,     /*!< x2APIC, APIC_BASE.EXTD, MSRs 0000_0800h...0000_0BFFh 64-bit ICR (+030h but not +031h), no DFR (+00Eh), SELF_IPI (+040h) also see standard level 0000_000Bh */
+	CPU_FEATURE_CPB,	/*!< Core performance boost */
+	CPU_FEATURE_APERFMPERF,	/*!< MPERF/APERF MSRs support */
+	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;
+
+/**
+ * @brief CPU detection hints identifiers
+ *
+ * Usage: similar to the flags usage
+ */
+typedef enum {
+	CPU_HINT_SSE_SIZE_AUTH = 0,	/*!< SSE unit size is authoritative (not only a Family/Model guesswork, but based on an actual CPUID bit) */
+	/* termination */
+	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
+ */
+typedef enum {
+	ERR_OK       =  0,	/*!< "No error" */
+	ERR_NO_CPUID = -1,	/*!< "CPUID instruction is not supported" */
+	ERR_NO_RDTSC = -2,	/*!< "RDTSC instruction is not supported" */
+	ERR_NO_MEM   = -3,	/*!< "Memory allocation failed" */
+	ERR_OPEN     = -4,	/*!< "File open operation failed" */
+	ERR_BADFMT   = -5,	/*!< "Bad file format" */
+	ERR_NOT_IMP  = -6,	/*!< "Not implemented" */
+	ERR_CPU_UNKN = -7,	/*!< "Unsupported processor" */
+	ERR_NO_RDMSR = -8,	/*!< "RDMSR instruction is not supported" */
+	ERR_NO_DRIVER= -9,	/*!< "RDMSR driver error (generic)" */
+	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_INVCNB   = -14,	/*!< "Invalid core number" */
+	ERR_HANDLE_R = -15,	/*!< "Error on handle read" */
+	ERR_INVRANGE = -16,	/*!< "Invalid given range" */
+} cpu_error_t;
+
+/**
+ * @brief Internal structure, used in cpu_tsc_mark, cpu_tsc_unmark and
+ *        cpu_clock_by_mark
+ */
+struct cpu_mark_t {
+	uint64_t tsc;		/*!< Time-stamp from RDTSC */
+	uint64_t sys_clock;	/*!< In microsecond resolution */
+};
+
+/**
+ * @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);
+
+/**
+ * @brief Checks if the CPUID instruction is supported
+ * @retval 1 if CPUID is present
+ * @retval 0 the CPU doesn't have CPUID.
+ */
+int cpuid_present(void);
+
+/**
+ * @brief Executes the CPUID instruction
+ * @param eax - the value of the EAX register when executing CPUID
+ * @param regs - the results will be stored here. regs[0] = EAX, regs[1] = EBX, ...
+ * @note CPUID will be executed with EAX set to the given value and EBX, ECX,
+ *       EDX set to zero.
+ */
+void cpu_exec_cpuid(uint32_t eax, uint32_t* regs);
+
+/**
+ * @brief Executes the CPUID instruction with the given input registers
+ * @note This is just a bit more generic version of cpu_exec_cpuid - it allows
+ *       you to control all the registers.
+ * @param regs - Input/output. Prior to executing CPUID, EAX, EBX, ECX and
+ *               EDX will be set to regs[0], regs[1], regs[2] and regs[3].
+ *               After CPUID, this array will contain the results.
+ */
+void cpu_exec_cpuid_ext(uint32_t* regs);
+
+/**
+ * @brief Obtains the raw CPUID data from the current CPU
+ * @param data - a pointer to cpu_raw_data_t structure
+ * @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 cpuid_get_raw_data(struct cpu_raw_data_t* data);
+
+/**
+ * @brief Writes the raw CPUID data to a text file
+ * @param data - a pointer to cpu_raw_data_t structure
+ * @param filename - the path of the file, where the serialized data should be
+ *                   written. If empty, stdout will be used.
+ * @note This is intended primarily for debugging. On some processor, which is
+ *       not currently supported or not completely recognized by cpu_identify,
+ *       one can still successfully get the raw data and write it to a file.
+ *       libcpuid developers can later import this file and debug the detection
+ *       code as if running on the actual hardware.
+ *       The file is simple text format of "something=value" pairs. Version info
+ *       is also written, but the format is not intended to be neither backward-
+ *       nor forward compatible.
+ * @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 cpuid_serialize_raw_data(struct cpu_raw_data_t* data, const char* filename);
+
+/**
+ * @brief Reads raw CPUID data from file
+ * @param data - a pointer to cpu_raw_data_t structure. The deserialized data will
+ *               be written here.
+ * @param filename - the path of the file, containing the serialized raw data.
+ *                   If empty, stdin will be used.
+ * @note This function may fail, if the file is created by different version of
+ *       the library. Also, see the notes on cpuid_serialize_raw_data.
+ * @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 cpuid_deserialize_raw_data(struct cpu_raw_data_t* data, const char* filename);
+
+/**
+ * @brief Identifies the CPU
+ * @param raw - Input - a pointer to the raw CPUID data, which is obtained
+ *              either by cpuid_get_raw_data or cpuid_deserialize_raw_data.
+ *              Can also be NULL, in which case the functions calls
+ *              cpuid_get_raw_data itself.
+ * @param data - Output - the decoded CPU features/info is written here.
+ * @note The function will not fail, even if some of the information
+ *       cannot be obtained. Even when the CPU is new and thus unknown to
+ *       libcpuid, some generic info, such as "AMD K9 family CPU" will be
+ *       written to data.cpu_codename, and most other things, such as the
+ *       CPU flags, cache sizes, etc. should be detected correctly anyway.
+ *       However, the function CAN fail, if the CPU is completely alien to
+ *       libcpuid.
+ * @note While cpu_identify() and cpuid_get_raw_data() are fast for most
+ *       purposes, running them several thousand times per second can hamper
+ *       performance significantly. Specifically, avoid writing "cpu feature
+ *       checker" wrapping function, which calls cpu_identify and returns the
+ *       value of some flag, if that function is going to be called frequently.
+ * @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_identify(struct cpu_raw_data_t* raw, struct cpu_id_t* data);
+
+/**
+ * @brief Returns the short textual representation of a CPU flag
+ * @param feature - the feature, whose textual representation is wanted.
+ * @returns a constant string like "fpu", "tsc", "sse2", etc.
+ * @note the names of the returned flags are compatible with those from
+ *       /proc/cpuinfo in Linux, with the exception of `tm_amd'
+ */
+const char* cpu_feature_str(cpu_feature_t feature);
+
+/**
+ * @brief Returns textual description of the last error
+ *
+ * libcpuid stores an `errno'-style error status, whose description
+ * can be obtained with this function.
+ * @note This function is not thread-safe
+ * @see cpu_error_t
+ */
+const char* cpuid_error(void);
+
+/**
+ * @brief Executes RDTSC
+ *
+ * The RDTSC (ReaD Time Stamp Counter) instruction gives access to an
+ * internal 64-bit counter, which usually increments at each clock cycle.
+ * This can be used for various timing routines, and as a very precise
+ * clock source. It is set to zero on system startup. Beware that may not
+ * increment at the same frequency as the CPU. Consecutive calls of RDTSC
+ * are, however, guaranteed to return monotonically-increasing values.
+ *
+ * @param result - a pointer to a 64-bit unsigned integer, where the TSC value
+ *                 will be stored
+ *
+ * @note  If 100% compatibility is a concern, you must first check if the
+ * RDTSC instruction is present (if it is not, your program will crash
+ * with "invalid opcode" exception). Only some very old processors (i486,
+ * early AMD K5 and some Cyrix CPUs) lack that instruction - they should
+ * have become exceedingly rare these days. To verify RDTSC presence,
+ * run cpu_identify() and check flags[CPU_FEATURE_TSC].
+ *
+ * @note The monotonically increasing nature of the TSC may be violated
+ * on SMP systems, if their TSC clocks run at different rate. If the OS
+ * doesn't account for that, the TSC drift may become arbitrary large.
+ */
+void cpu_rdtsc(uint64_t* result);
+
+/**
+ * @brief Store TSC and timing info
+ *
+ * This function stores the current TSC value and current
+ * time info from a precise OS-specific clock source in the cpu_mark_t
+ * structure. The sys_clock field contains time with microsecond resolution.
+ * The values can later be used to measure time intervals, number of clocks,
+ * FPU frequency, etc.
+ * @see cpu_rdtsc
+ *
+ * @param mark [out] - a pointer to a cpu_mark_t structure
+ */
+void cpu_tsc_mark(struct cpu_mark_t* mark);
+
+/**
+ * @brief Calculate TSC and timing difference
+ *
+ * @param mark - input/output: a pointer to a cpu_mark_t sturcture, which has
+ *               already been initialized by cpu_tsc_mark. The difference in
+ *               TSC and time will be written here.
+ *
+ * This function calculates the TSC and time difference, by obtaining the
+ * current TSC and timing values and subtracting the contents of the `mark'
+ * structure from them. Results are written in the same structure.
+ *
+ * Example:
+ * @code
+ * ...
+ * struct cpu_mark_t mark;
+ * cpu_tsc_mark(&mark);
+ * foo();
+ * cpu_tsc_unmark(&mark);
+ * printf("Foo finished. Executed in %llu cycles and %llu usecs\n",
+ *        mark.tsc, mark.sys_clock);
+ * ...
+ * @endcode
+ */
+void cpu_tsc_unmark(struct cpu_mark_t* mark);
+
+/**
+ * @brief Calculates the CPU clock
+ *
+ * @param mark - pointer to a cpu_mark_t structure, which has been initialized
+ *   with cpu_tsc_mark and later `stopped' with cpu_tsc_unmark.
+ *
+ * @note For reliable results, the marked time interval should be at least about
+ * 10 ms.
+ *
+ * @returns the CPU clock frequency, in MHz. Due to measurement error, it will
+ * differ from the true value in a few least-significant bits. Accuracy depends
+ * on the timing interval - the more, the better. If the timing interval is
+ * insufficient, the result is -1. Also, see the comment on cpu_clock_measure
+ * for additional issues and pitfalls in using RDTSC for CPU frequency
+ * measurements.
+ */
+int cpu_clock_by_mark(struct cpu_mark_t* mark);
+
+/**
+ * @brief Returns the CPU clock, as reported by the OS
+ *
+ * This function uses OS-specific functions to obtain the CPU clock. It may
+ * differ from the true clock for several reasons:<br><br>
+ *
+ * i) The CPU might be in some power saving state, while the OS reports its
+ *    full-power frequency, or vice-versa.<br>
+ * ii) In some cases you can raise or lower the CPU frequency with overclocking
+ *     utilities and the OS will not notice.
+ *
+ * @returns the CPU clock frequency in MHz. If the OS is not (yet) supported
+ * or lacks the necessary reporting machinery, the return value is -1
+ */
+int cpu_clock_by_os(void);
+
+/**
+ * @brief Measure the CPU clock frequency
+ *
+ * @param millis - How much time to waste in the busy-wait cycle. In millisecs.
+ *                 Useful values 10 - 1000
+ * @param quad_check - Do a more thorough measurement if nonzero
+ *                     (see the explanation).
+ *
+ * The function performs a busy-wait cycle for the given time and calculates
+ * the CPU frequency by the difference of the TSC values. The accuracy of the
+ * calculation depends on the length of the busy-wait cycle: more is better,
+ * but 100ms should be enough for most purposes.
+ *
+ * While this will calculate the CPU frequency correctly in most cases, there are
+ * several reasons why it might be incorrect:<br>
+ *
+ * i) RDTSC doesn't guarantee it will run at the same clock as the CPU.
+ *    Apparently there aren't CPUs at the moment, but still, there's no
+ *    guarantee.<br>
+ * ii) The CPU might be in a low-frequency power saving mode, and the CPU
+ *     might be switched to higher frequency at any time. If this happens
+ *     during the measurement, the result can be anywhere between the
+ *     low and high frequencies. Also, if you're interested in the
+ *     high frequency value only, this function might return the low one
+ *     instead.<br>
+ * iii) On SMP systems exhibiting TSC drift (see \ref cpu_rdtsc)
+ *
+ * the quad_check option will run four consecutive measurements and
+ * then return the average of the two most-consistent results. The total
+ * runtime of the function will still be `millis' - consider using
+ * a bit more time for the timing interval.
+ *
+ * Finally, for benchmarking / CPU intensive applications, the best strategy is
+ * to use the cpu_tsc_mark() / cpu_tsc_unmark() / cpu_clock_by_mark() method.
+ * Begin by mark()-ing about one second after application startup (allowing the
+ * power-saving manager to kick in and rise the frequency during that time),
+ * then unmark() just before application finishing. The result will most
+ * acurately represent at what frequency your app was running.
+ *
+ * @returns the CPU clock frequency in MHz (within some measurement error
+ * margin). If RDTSC is not supported, the result is -1.
+ */
+int cpu_clock_measure(int millis, int quad_check);
+
+/**
+ * @brief Measure the CPU clock frequency using instruction-counting
+ *
+ * @param millis - how much time to allocate for each run, in milliseconds
+ * @param runs - how many runs to perform
+ *
+ * The function performs a busy-wait cycle using a known number of "heavy" (SSE)
+ * instructions. These instructions run at (more or less guaranteed) 1 IPC rate,
+ * so by running a busy loop for a fixed amount of time, and measuring the
+ * amount of instructions done, the CPU clock is accurately measured.
+ *
+ * Of course, this function is still affected by the power-saving schemes, so
+ * the warnings as of cpu_clock_measure() still apply. However, this function is
+ * immune to problems with detection, related to the Intel Nehalem's "Turbo"
+ * mode, where the internal clock is raised, but the RDTSC rate is unaffected.
+ *
+ * The function will run for about (millis * runs) milliseconds.
+ * You can make only a single busy-wait run (runs == 1); however, this can
+ * be affected by task scheduling (which will break the counting), so allowing
+ * more than one run is recommended. As run length is not imperative for
+ * accurate readings (e.g., 50ms is sufficient), you can afford a lot of short
+ * runs, e.g. 10 runs of 50ms or 20 runs of 25ms.
+ *
+ * Recommended values - millis = 50, runs = 4. For more robustness,
+ * increase the number of runs.
+ * 
+ * NOTE: on Bulldozer and later CPUs, the busy-wait cycle runs at 1.4 IPC, thus
+ * the results are skewed. This is corrected internally by dividing the resulting
+ * value by 1.4.
+ * However, this only occurs if the thread is executed on a single CMT
+ * module - if there are other threads competing for resources, the results are
+ * unpredictable. Make sure you run cpu_clock_by_ic() on a CPU that is free from
+ * competing threads, or if there are such threads, they shouldn't exceed the
+ * number of modules. On a Bulldozer X8, that means 4 threads.
+ *
+ * @returns the CPU clock frequency in MHz (within some measurement error
+ * margin). If SSE is not supported, the result is -1. If the input parameters
+ * are incorrect, or some other internal fault is detected, the result is -2.
+ */
+int cpu_clock_by_ic(int millis, int runs);
+
+/**
+ * @brief Get the CPU clock frequency (all-in-one method)
+ *
+ * This is an all-in-one method for getting the CPU clock frequency.
+ * It tries to use the OS for that. If the OS doesn't have this info, it
+ * uses cpu_clock_measure with 200ms time interval and quadruple checking.
+ *
+ * @returns the CPU clock frequency in MHz. If every possible method fails,
+ * the result is -1.
+ */
+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
+ *
+ * @returns the string representation of the libcpuid version, like "0.1.1"
+ */
+const char* cpuid_lib_version(void);
+
+typedef void (*libcpuid_warn_fn_t) (const char *msg);
+/**
+ * @brief Sets the warning print function
+ *
+ * In some cases, the internal libcpuid machinery would like to emit useful
+ * debug warnings. By default, these warnings are written to stderr. However,
+ * you can set a custom function that will receive those warnings.
+ *
+ * @param warn_fun - the warning function you want to set. If NULL, warnings
+ *                   are disabled. The function takes const char* argument.
+ *
+ * @returns the current warning function. You can use the return value to
+ * keep the previous warning function and restore it at your discretion.
+ */
+libcpuid_warn_fn_t cpuid_set_warn_function(libcpuid_warn_fn_t warn_fun);
+
+/**
+ * @brief Sets the verbosiness level
+ *
+ * When the verbosiness level is above zero, some functions might print
+ * diagnostic information about what are they doing. The higher the level is,
+ * the more detail is printed. Level zero is guaranteed to omit all such
+ * output. The output is written using the same machinery as the warnings,
+ * @see cpuid_set_warn_function()
+ *
+ * @param level the desired verbosiness level. Useful values 0..2 inclusive
+ */
+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
+ */
+struct cpu_list_t {
+	/** Number of entries in the list */
+	int num_entries;
+	/** Pointers to names. There will be num_entries of them */
+	char **names;
+};
+
+/**
+ * @brief Gets a list of all known CPU names from a specific vendor.
+ *
+ * This function compiles a list of all known CPU (code)names
+ * (i.e. the possible values of cpu_id_t::cpu_codename) for the given vendor.
+ *
+ * There are about 100 entries for Intel and AMD, and a few for the other
+ * vendors. The list is written out in approximate chronological introduction
+ * order of the parts.
+ *
+ * @param vendor the vendor to be queried
+ * @param list [out] the resulting list will be written here.
+ * NOTE: As the memory is dynamically allocated, be sure to call
+ *       cpuid_free_cpu_list() after you're done with the data
+ * @see cpu_list_t
+ */
+void cpuid_get_cpu_list(cpu_vendor_t vendor, struct cpu_list_t* list);
+
+/**
+ * @brief Frees a CPU list
+ *
+ * This function deletes all the memory associated with a CPU list, as obtained
+ * by cpuid_get_cpu_list()
+ *
+ * @param list - the list to be free()'d.
+ */
+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
+ * @note This function is not MT-safe. If you intend to call it from multiple
+ *       threads, guard it through a mutex or a similar primitive.
+ */
+int cpu_msrinfo(struct msr_driver_t* handle, cpu_msrinfo_request_t which);
+#define CPU_INVALID_VALUE 0x3fffffff
+
+/**
+ * @brief Writes the raw MSR data to a text file
+ * @param data - a pointer to msr_driver_t structure
+ * @param filename - the path of the file, where the serialized data should be
+ *                   written. If empty, stdout will be used.
+ * @note This is intended primarily for debugging. On some processor, which is
+ *       not currently supported or not completely recognized by cpu_identify,
+ *       one can still successfully get the raw data and write it to a file.
+ *       libcpuid developers can later import this file and debug the detection
+ *       code as if running on the actual hardware.
+ *       The file is simple text format of "something=value" pairs. Version info
+ *       is also written, but the format is not intended to be neither backward-
+ *       nor forward compatible.
+ * @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 msr_serialize_raw_data(struct msr_driver_t* handle, const char* filename);
+
+/**
+ * @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
+}; /* extern "C" */
+#endif
+
+
+/** @} */
+
+#endif /* __LIBCPUID_H__ */

+ 47 - 0
Source/ThirdParty/LibCpuId/src/libcpuid_constants.h

@@ -0,0 +1,47 @@
+/*
+ * Copyright 2008  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     libcpuid_constants.h
+ * @Author   Veselin Georgiev
+ * @Brief    Some limits and constants for libcpuid
+ */
+
+#ifndef __LIBCPUID_CONSTANTS_H__
+#define __LIBCPUID_CONSTANTS_H__
+
+#define VENDOR_STR_MAX		16
+#define BRAND_STR_MAX		64
+#define CPU_FLAGS_MAX		128
+#define MAX_CPUID_LEVEL		32
+#define MAX_EXT_CPUID_LEVEL	32
+#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__ */

+ 106 - 0
Source/ThirdParty/LibCpuId/src/libcpuid_internal.h

@@ -0,0 +1,106 @@
+/*
+ * 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,
+	NC, /* 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;
+	uint64_t bits;
+	int score; // detection (matchtable) score
+};
+
+#define LBIT(x) (((long long) 1) << x)
+
+enum _common_bits_t {
+	_M_                     = LBIT(  0 ),
+	MOBILE_                 = LBIT(  1 ),
+	_MP_                    = LBIT(  2 ),
+};
+
+// additional detection bits for Intel CPUs:
+enum _intel_bits_t {
+	PENTIUM_                = LBIT( 10 ),
+	CELERON_                = LBIT( 11 ),
+	CORE_                   = LBIT( 12 ),
+	_I_                     = LBIT( 13 ),
+	_3                      = LBIT( 14 ),
+	_5                      = LBIT( 15 ),
+	_7                      = LBIT( 16 ),
+	XEON_                   = LBIT( 17 ),
+	ATOM_                   = LBIT( 18 ),
+};
+typedef enum _intel_bits_t intel_bits_t;
+
+enum _amd_bits_t {
+	ATHLON_      = LBIT( 10 ),
+	_XP_         = LBIT( 11 ),
+	DURON_       = LBIT( 12 ),
+	SEMPRON_     = LBIT( 13 ),
+	OPTERON_     = LBIT( 14 ),
+	TURION_      = LBIT( 15 ),
+	_LV_         = LBIT( 16 ),
+	_64_         = LBIT( 17 ),
+	_X2          = LBIT( 18 ),
+	_X3          = LBIT( 19 ),
+	_X4          = LBIT( 20 ),
+	_X6          = LBIT( 21 ),
+	_FX          = LBIT( 22 ),
+	_APU_        = LBIT( 23 ),
+};
+typedef enum _amd_bits_t amd_bits_t;
+
+
+
+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__ */

+ 67 - 0
Source/ThirdParty/LibCpuId/src/libcpuid_types.h

@@ -0,0 +1,67 @@
+/*
+ * Copyright 2008  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     libcpuid_types.h
+ * @Author   Veselin Georgiev
+ * @Brief    Type specifications for libcpuid.
+ */
+
+#ifndef __LIBCPUID_TYPES_H__
+#define __LIBCPUID_TYPES_H__
+
+#ifdef HAVE_CONFIG_H
+#  include "config.h"
+#endif
+
+#if defined(HAVE_STDINT_H)
+#  include <stdint.h>
+#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__ */

+ 218 - 0
Source/ThirdParty/LibCpuId/src/libcpuid_util.c

@@ -0,0 +1,218 @@
+/*
+ * Copyright 2008  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.
+ */
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <stdarg.h>
+#include <string.h>
+#include <ctype.h>
+#include "libcpuid.h"
+#include "libcpuid_util.h"
+
+int _current_verboselevel;
+
+void match_features(const struct feature_map_t* matchtable, int count, uint32_t reg, struct cpu_id_t* data)
+{
+	int i;
+	for (i = 0; i < count; i++)
+		if (reg & (1u << matchtable[i].bit))
+			data->flags[matchtable[i].feature] = 1;
+}
+
+static void default_warn(const char *msg)
+{
+	fprintf(stderr, "%s", msg);
+}
+
+libcpuid_warn_fn_t _warn_fun = default_warn;
+
+#if defined(_MSC_VER)
+#	define vsnprintf _vsnprintf
+#endif
+void warnf(const char* format, ...)
+{
+	char buff[1024];
+	va_list va;
+	if (!_warn_fun) return;
+	va_start(va, format);
+	vsnprintf(buff, sizeof(buff), format, va);
+	va_end(va);
+	_warn_fun(buff);
+}
+
+void debugf(int verboselevel, const char* format, ...)
+{
+	char buff[1024];
+	va_list va;
+	if (verboselevel > _current_verboselevel) return;
+	va_start(va, format);
+	vsnprintf(buff, sizeof(buff), format, va);
+	va_end(va);
+	_warn_fun(buff);
+}
+
+static int popcount64(uint64_t mask)
+{
+	int num_set_bits = 0;
+	
+	while (mask) {
+		mask &= mask - 1;
+		num_set_bits++;
+	}
+	
+	return num_set_bits;
+}
+
+static int score(const struct match_entry_t* entry, const struct cpu_id_t* data,
+                 int brand_code, uint64_t bits, int model_code)
+{
+	int res = 0;
+	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;
+	
+	res += popcount64(entry->model_bits & bits) * 2;
+	return res;
+}
+
+int match_cpu_codename(const struct match_entry_t* matchtable, int count,
+                       struct cpu_id_t* data, int brand_code, uint64_t bits,
+                       int model_code)
+{
+	int bestscore = -1;
+	int bestindex = 0;
+	int i, t;
+	
+	debugf(3, "Matching cpu f:%d, m:%d, s:%d, xf:%d, xm:%d, ncore:%d, l2:%d, bcode:%d, bits:%llu, code:%d\n",
+		data->family, data->model, data->stepping, data->ext_family,
+		data->ext_model, data->num_cores, data->l2_cache, brand_code, (unsigned long long) bits, model_code);
+	
+	for (i = 0; i < count; i++) {
+		t = score(&matchtable[i], data, brand_code, bits, model_code);
+		debugf(3, "Entry %d, `%s', score %d\n", i, matchtable[i].name, t);
+		if (t > bestscore) {
+			debugf(2, "Entry `%s' selected - best score so far (%d)\n", matchtable[i].name, t);
+			bestscore = t;
+			bestindex = i;
+		}
+	}
+	strcpy(data->cpu_codename, matchtable[bestindex].name);
+	return bestscore;
+}
+
+void generic_get_cpu_list(const struct match_entry_t* matchtable, int count,
+                          struct cpu_list_t* list)
+{
+	int i, j, n, good;
+	n = 0;
+	list->names = (char**) malloc(sizeof(char*) * count);
+	for (i = 0; i < count; i++) {
+		if (strstr(matchtable[i].name, "Unknown")) continue;
+		good = 1;
+		for (j = n - 1; j >= 0; j--)
+			if (!strcmp(list->names[j], matchtable[i].name)) {
+				good = 0;
+				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;
+}
+
+static int xmatch_entry(char c, const char* p)
+{
+	int i, j;
+	if (c == 0) return -1;
+	if (c == p[0]) return 1;
+	if (p[0] == '.') return 1;
+	if (p[0] == '#' && isdigit(c)) return 1;
+	if (p[0] == '[') {
+		j = 1;
+		while (p[j] && p[j] != ']') j++;
+		if (!p[j]) return -1;
+		for (i = 1; i < j; i++)
+			if (p[i] == c) return j + 1;
+	}
+	return -1;
+}
+
+int match_pattern(const char* s, const char* p)
+{
+	int i, j, dj, k, n, m;
+	n = (int) strlen(s);
+	m = (int) strlen(p);
+	for (i = 0; i < n; i++) {
+		if (xmatch_entry(s[i], p) != -1) {
+			j = 0;
+			k = 0;
+			while (j < m && ((dj = xmatch_entry(s[i + k], p + j)) != -1)) {
+				k++;
+				j += dj;
+			}
+			if (j == m) return i + 1;
+		}
+	}
+	return 0;
+}
+
+struct cpu_id_t* get_cached_cpuid(void)
+{
+	static int initialized = 0;
+	static struct cpu_id_t id;
+	if (initialized) return &id;
+	if (cpu_identify(NULL, &id))
+		memset(&id, 0, sizeof(id));
+	initialized = 1;
+	return &id;
+}
+
+int match_all(uint64_t bits, uint64_t mask)
+{
+	return (bits & mask) == mask;
+}
+
+void debug_print_lbits(int debuglevel, uint64_t mask)
+{
+	int i, first = 0;
+	for (i = 0; i < 64; i++) if (mask & (((uint64_t) 1) << i)) {
+		if (first) first = 0;
+		else debugf(2, " + ");
+		debugf(2, "LBIT(%d)", i);
+	}
+	debugf(2, "\n");
+}

+ 98 - 0
Source/ThirdParty/LibCpuId/src/libcpuid_util.h

@@ -0,0 +1,98 @@
+/*
+ * Copyright 2008  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_UTIL_H__
+#define __LIBCPUID_UTIL_H__
+
+#define COUNT_OF(array) (sizeof(array) / sizeof(array[0]))
+
+struct feature_map_t {
+	unsigned bit;
+	cpu_feature_t feature;
+};
+ 
+void match_features(const struct feature_map_t* matchtable, int count,
+                    uint32_t reg, struct cpu_id_t* data);
+
+struct match_entry_t {
+	int family, model, stepping, ext_family, ext_model;
+	int ncores, l2cache, l3cache, brand_code;
+	uint64_t model_bits;
+	int model_code;
+	char name[32];
+};
+
+// returns the match score:
+int match_cpu_codename(const struct match_entry_t* matchtable, int count,
+                       struct cpu_id_t* data, int brand_code, uint64_t bits,
+                       int model_code);
+
+void warnf(const char* format, ...)
+#ifdef __GNUC__
+__attribute__((format(printf, 1, 2)))
+#endif
+;
+void debugf(int verboselevel, const char* format, ...)
+#ifdef __GNUC__
+__attribute__((format(printf, 2, 3)))
+#endif
+;
+void generic_get_cpu_list(const struct match_entry_t* matchtable, int count,
+                          struct cpu_list_t* list);
+
+/*
+ * Seek for a pattern in `haystack'.
+ * Pattern may be an fixed string, or contain the special metacharacters
+ * '.' - match any single character
+ * '#' - match any digit
+ * '[<chars>] - match any of the given chars (regex-like ranges are not
+ *              supported)
+ * Return val: 0 if the pattern is not found. Nonzero if it is found (actually,
+ *             x + 1 where x is the index where the match is found).
+ */
+int match_pattern(const char* haystack, const char* pattern);
+
+/*
+ * Gets an initialized cpu_id_t. It is cached, so that internal libcpuid
+ * machinery doesn't need to issue cpu_identify more than once.
+ */
+struct cpu_id_t* get_cached_cpuid(void);
+
+
+/* returns true if all bits of mask are present in `bits'. */
+int match_all(uint64_t bits, uint64_t mask);
+
+/* print what bits a mask consists of */
+void debug_print_lbits(int debuglevel, uint64_t mask);
+
+/*
+ * Sets the current errno
+ */
+int set_error(cpu_error_t err);
+
+extern libcpuid_warn_fn_t _warn_fun;
+extern int _current_verboselevel;
+
+#endif /* __LIBCPUID_UTIL_H__ */

+ 359 - 0
Source/ThirdParty/LibCpuId/src/masm-x64.asm

@@ -0,0 +1,359 @@
+
+.code
+; procedure exec_cpuid
+; Signature: void exec_cpiud(uint32_t *regs)
+exec_cpuid Proc
+	push	rbx
+	push	rcx
+	push	rdx
+	push	rdi
+	
+	mov	rdi,	rcx
+	
+	mov	eax,	[rdi]
+	mov	ebx,	[rdi+4]
+	mov	ecx,	[rdi+8]
+	mov	edx,	[rdi+12]
+	
+	cpuid
+	
+	mov	[rdi],	eax
+	mov	[rdi+4],	ebx
+	mov	[rdi+8],	ecx
+	mov	[rdi+12],	edx
+	pop	rdi
+	pop	rdx
+	pop	rcx
+	pop	rbx
+	ret
+exec_cpuid endp
+
+; procedure cpu_rdtsc
+; Signature: void cpu_rdtsc(uint64_t *result)
+cpu_rdtsc Proc
+	push	rdx
+	rdtsc
+	mov	[rcx],	eax
+	mov	[rcx+4],	edx
+	pop	rdx
+	ret
+cpu_rdtsc endp
+
+; procedure busy_sse_loop
+; Signature: void busy_sse_loop(int cycles)
+busy_sse_loop Proc
+	; save xmm6 & xmm7 into the shadow area, as Visual C++ 2008
+	; expects that we don't touch them:
+	movups	[rsp + 8],	xmm6
+	movups	[rsp + 24],	xmm7
+
+	xorps	xmm0,	xmm0
+	xorps	xmm1,	xmm1
+	xorps	xmm2,	xmm2
+	xorps	xmm3,	xmm3
+	xorps	xmm4,	xmm4
+	xorps	xmm5,	xmm5
+	xorps	xmm6,	xmm6
+	xorps	xmm7,	xmm7
+	; --
+	align 16
+bsLoop:
+	; 0:
+	addps	xmm0,	xmm1
+	addps	xmm1,	xmm2
+	addps	xmm2,	xmm3
+	addps	xmm3,	xmm4
+	addps	xmm4,	xmm5
+	addps	xmm5,	xmm6
+	addps	xmm6,	xmm7
+	addps	xmm7,	xmm0
+	; 1:
+	addps	xmm0,	xmm1
+	addps	xmm1,	xmm2
+	addps	xmm2,	xmm3
+	addps	xmm3,	xmm4
+	addps	xmm4,	xmm5
+	addps	xmm5,	xmm6
+	addps	xmm6,	xmm7
+	addps	xmm7,	xmm0
+	; 2:
+	addps	xmm0,	xmm1
+	addps	xmm1,	xmm2
+	addps	xmm2,	xmm3
+	addps	xmm3,	xmm4
+	addps	xmm4,	xmm5
+	addps	xmm5,	xmm6
+	addps	xmm6,	xmm7
+	addps	xmm7,	xmm0
+	; 3:
+	addps	xmm0,	xmm1
+	addps	xmm1,	xmm2
+	addps	xmm2,	xmm3
+	addps	xmm3,	xmm4
+	addps	xmm4,	xmm5
+	addps	xmm5,	xmm6
+	addps	xmm6,	xmm7
+	addps	xmm7,	xmm0
+	; 4:
+	addps	xmm0,	xmm1
+	addps	xmm1,	xmm2
+	addps	xmm2,	xmm3
+	addps	xmm3,	xmm4
+	addps	xmm4,	xmm5
+	addps	xmm5,	xmm6
+	addps	xmm6,	xmm7
+	addps	xmm7,	xmm0
+	; 5:
+	addps	xmm0,	xmm1
+	addps	xmm1,	xmm2
+	addps	xmm2,	xmm3
+	addps	xmm3,	xmm4
+	addps	xmm4,	xmm5
+	addps	xmm5,	xmm6
+	addps	xmm6,	xmm7
+	addps	xmm7,	xmm0
+	; 6:
+	addps	xmm0,	xmm1
+	addps	xmm1,	xmm2
+	addps	xmm2,	xmm3
+	addps	xmm3,	xmm4
+	addps	xmm4,	xmm5
+	addps	xmm5,	xmm6
+	addps	xmm6,	xmm7
+	addps	xmm7,	xmm0
+	; 7:
+	addps	xmm0,	xmm1
+	addps	xmm1,	xmm2
+	addps	xmm2,	xmm3
+	addps	xmm3,	xmm4
+	addps	xmm4,	xmm5
+	addps	xmm5,	xmm6
+	addps	xmm6,	xmm7
+	addps	xmm7,	xmm0
+	; 8:
+	addps	xmm0,	xmm1
+	addps	xmm1,	xmm2
+	addps	xmm2,	xmm3
+	addps	xmm3,	xmm4
+	addps	xmm4,	xmm5
+	addps	xmm5,	xmm6
+	addps	xmm6,	xmm7
+	addps	xmm7,	xmm0
+	; 9:
+	addps	xmm0,	xmm1
+	addps	xmm1,	xmm2
+	addps	xmm2,	xmm3
+	addps	xmm3,	xmm4
+	addps	xmm4,	xmm5
+	addps	xmm5,	xmm6
+	addps	xmm6,	xmm7
+	addps	xmm7,	xmm0
+	; 10:
+	addps	xmm0,	xmm1
+	addps	xmm1,	xmm2
+	addps	xmm2,	xmm3
+	addps	xmm3,	xmm4
+	addps	xmm4,	xmm5
+	addps	xmm5,	xmm6
+	addps	xmm6,	xmm7
+	addps	xmm7,	xmm0
+	; 11:
+	addps	xmm0,	xmm1
+	addps	xmm1,	xmm2
+	addps	xmm2,	xmm3
+	addps	xmm3,	xmm4
+	addps	xmm4,	xmm5
+	addps	xmm5,	xmm6
+	addps	xmm6,	xmm7
+	addps	xmm7,	xmm0
+	; 12:
+	addps	xmm0,	xmm1
+	addps	xmm1,	xmm2
+	addps	xmm2,	xmm3
+	addps	xmm3,	xmm4
+	addps	xmm4,	xmm5
+	addps	xmm5,	xmm6
+	addps	xmm6,	xmm7
+	addps	xmm7,	xmm0
+	; 13:
+	addps	xmm0,	xmm1
+	addps	xmm1,	xmm2
+	addps	xmm2,	xmm3
+	addps	xmm3,	xmm4
+	addps	xmm4,	xmm5
+	addps	xmm5,	xmm6
+	addps	xmm6,	xmm7
+	addps	xmm7,	xmm0
+	; 14:
+	addps	xmm0,	xmm1
+	addps	xmm1,	xmm2
+	addps	xmm2,	xmm3
+	addps	xmm3,	xmm4
+	addps	xmm4,	xmm5
+	addps	xmm5,	xmm6
+	addps	xmm6,	xmm7
+	addps	xmm7,	xmm0
+	; 15:
+	addps	xmm0,	xmm1
+	addps	xmm1,	xmm2
+	addps	xmm2,	xmm3
+	addps	xmm3,	xmm4
+	addps	xmm4,	xmm5
+	addps	xmm5,	xmm6
+	addps	xmm6,	xmm7
+	addps	xmm7,	xmm0
+	; 16:
+	addps	xmm0,	xmm1
+	addps	xmm1,	xmm2
+	addps	xmm2,	xmm3
+	addps	xmm3,	xmm4
+	addps	xmm4,	xmm5
+	addps	xmm5,	xmm6
+	addps	xmm6,	xmm7
+	addps	xmm7,	xmm0
+	; 17:
+	addps	xmm0,	xmm1
+	addps	xmm1,	xmm2
+	addps	xmm2,	xmm3
+	addps	xmm3,	xmm4
+	addps	xmm4,	xmm5
+	addps	xmm5,	xmm6
+	addps	xmm6,	xmm7
+	addps	xmm7,	xmm0
+	; 18:
+	addps	xmm0,	xmm1
+	addps	xmm1,	xmm2
+	addps	xmm2,	xmm3
+	addps	xmm3,	xmm4
+	addps	xmm4,	xmm5
+	addps	xmm5,	xmm6
+	addps	xmm6,	xmm7
+	addps	xmm7,	xmm0
+	; 19:
+	addps	xmm0,	xmm1
+	addps	xmm1,	xmm2
+	addps	xmm2,	xmm3
+	addps	xmm3,	xmm4
+	addps	xmm4,	xmm5
+	addps	xmm5,	xmm6
+	addps	xmm6,	xmm7
+	addps	xmm7,	xmm0
+	; 20:
+	addps	xmm0,	xmm1
+	addps	xmm1,	xmm2
+	addps	xmm2,	xmm3
+	addps	xmm3,	xmm4
+	addps	xmm4,	xmm5
+	addps	xmm5,	xmm6
+	addps	xmm6,	xmm7
+	addps	xmm7,	xmm0
+	; 21:
+	addps	xmm0,	xmm1
+	addps	xmm1,	xmm2
+	addps	xmm2,	xmm3
+	addps	xmm3,	xmm4
+	addps	xmm4,	xmm5
+	addps	xmm5,	xmm6
+	addps	xmm6,	xmm7
+	addps	xmm7,	xmm0
+	; 22:
+	addps	xmm0,	xmm1
+	addps	xmm1,	xmm2
+	addps	xmm2,	xmm3
+	addps	xmm3,	xmm4
+	addps	xmm4,	xmm5
+	addps	xmm5,	xmm6
+	addps	xmm6,	xmm7
+	addps	xmm7,	xmm0
+	; 23:
+	addps	xmm0,	xmm1
+	addps	xmm1,	xmm2
+	addps	xmm2,	xmm3
+	addps	xmm3,	xmm4
+	addps	xmm4,	xmm5
+	addps	xmm5,	xmm6
+	addps	xmm6,	xmm7
+	addps	xmm7,	xmm0
+	; 24:
+	addps	xmm0,	xmm1
+	addps	xmm1,	xmm2
+	addps	xmm2,	xmm3
+	addps	xmm3,	xmm4
+	addps	xmm4,	xmm5
+	addps	xmm5,	xmm6
+	addps	xmm6,	xmm7
+	addps	xmm7,	xmm0
+	; 25:
+	addps	xmm0,	xmm1
+	addps	xmm1,	xmm2
+	addps	xmm2,	xmm3
+	addps	xmm3,	xmm4
+	addps	xmm4,	xmm5
+	addps	xmm5,	xmm6
+	addps	xmm6,	xmm7
+	addps	xmm7,	xmm0
+	; 26:
+	addps	xmm0,	xmm1
+	addps	xmm1,	xmm2
+	addps	xmm2,	xmm3
+	addps	xmm3,	xmm4
+	addps	xmm4,	xmm5
+	addps	xmm5,	xmm6
+	addps	xmm6,	xmm7
+	addps	xmm7,	xmm0
+	; 27:
+	addps	xmm0,	xmm1
+	addps	xmm1,	xmm2
+	addps	xmm2,	xmm3
+	addps	xmm3,	xmm4
+	addps	xmm4,	xmm5
+	addps	xmm5,	xmm6
+	addps	xmm6,	xmm7
+	addps	xmm7,	xmm0
+	; 28:
+	addps	xmm0,	xmm1
+	addps	xmm1,	xmm2
+	addps	xmm2,	xmm3
+	addps	xmm3,	xmm4
+	addps	xmm4,	xmm5
+	addps	xmm5,	xmm6
+	addps	xmm6,	xmm7
+	addps	xmm7,	xmm0
+	; 29:
+	addps	xmm0,	xmm1
+	addps	xmm1,	xmm2
+	addps	xmm2,	xmm3
+	addps	xmm3,	xmm4
+	addps	xmm4,	xmm5
+	addps	xmm5,	xmm6
+	addps	xmm6,	xmm7
+	addps	xmm7,	xmm0
+	; 30:
+	addps	xmm0,	xmm1
+	addps	xmm1,	xmm2
+	addps	xmm2,	xmm3
+	addps	xmm3,	xmm4
+	addps	xmm4,	xmm5
+	addps	xmm5,	xmm6
+	addps	xmm6,	xmm7
+	addps	xmm7,	xmm0
+	; 31:
+	addps	xmm0,	xmm1
+	addps	xmm1,	xmm2
+	addps	xmm2,	xmm3
+	addps	xmm3,	xmm4
+	addps	xmm4,	xmm5
+	addps	xmm5,	xmm6
+	addps	xmm6,	xmm7
+	addps	xmm7,	xmm0
+	; ----------------------
+	dec		ecx
+	jnz		bsLoop
+
+	; restore xmm6 & xmm7:
+	movups	xmm6,	[rsp + 8]
+	movups	xmm7,	[rsp + 24]
+	ret
+busy_sse_loop endp
+
+END

+ 593 - 0
Source/ThirdParty/LibCpuId/src/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.

+ 1054 - 0
Source/ThirdParty/LibCpuId/src/rdmsr.c

@@ -0,0 +1,1054 @@
+/*
+ * 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 <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#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 <unistd.h>
+#include <stdio.h>
+#include <sys/types.h>
+#include <sys/stat.h>
+#include <fcntl.h>
+#include <errno.h>
+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 <fcntl.h>
+#include <unistd.h>
+#include <errno.h>
+#include <sys/ioctl.h>
+#include <sys/cpuctl.h>
+
+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 <windows.h>
+#include <winioctl.h>
+#include <winerror.h>
+
+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);
+}
+
+int msr_serialize_raw_data(struct msr_driver_t* handle, const char* filename)
+{
+	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/55072_AMD_Family_15h_Models_70h-7Fh_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
+
+  AMD Processor Programming Reference (PPR)
+  * AMD Family 17h Processors
+  https://support.amd.com/TechDocs/54945_PPR_Family_17h_Models_00h-0Fh.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_1           0xC0010065
+#define MSR_PSTATE_2           0xC0010066
+#define MSR_PSTATE_3           0xC0010067
+#define MSR_PSTATE_4           0xC0010068
+#define MSR_PSTATE_5           0xC0010069
+#define MSR_PSTATE_6           0xC001006A
+#define MSR_PSTATE_7           0xC001006B
+static const uint32_t amd_msr[] = {
+	MSR_PSTATE_L,
+	MSR_PSTATE_S,
+	MSR_PSTATE_0,
+	MSR_PSTATE_1,
+	MSR_PSTATE_2,
+	MSR_PSTATE_3,
+	MSR_PSTATE_4,
+	MSR_PSTATE_5,
+	MSR_PSTATE_6,
+	MSR_PSTATE_7,
+	CPU_INVALID_VALUE
+};
+
+/* 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 const uint32_t intel_msr[] = {
+	IA32_MPERF,
+	IA32_APERF,
+	IA32_PERF_STATUS,
+	IA32_THERM_STATUS,
+	MSR_EBL_CR_POWERON,
+	MSR_TURBO_RATIO_LIMIT,
+	MSR_TEMPERATURE_TARGET,
+	MSR_PERF_STATUS,
+	MSR_PLATFORM_INFO,
+	CPU_INVALID_VALUE
+};
+
+struct msr_info_t {
+	int cpu_clock;
+	struct msr_driver_t *handle;
+	struct cpu_id_t *id;
+	struct internal_id_info_t *internal;
+};
+
+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_info_t *info, uint32_t pstate, double *multiplier)
+{
+	int i, err;
+	uint64_t CpuFid, CpuDid, CpuDidLSD;
+
+	/* Constant values needed for 12h family */
+	const struct { uint64_t did; double divisor; } divisor_t[] = {
+		{ 0x0,    1   },
+		{ 0x1,    1.5 },
+		{ 0x2,    2   },
+		{ 0x3,    3   },
+		{ 0x4,    4   },
+		{ 0x5,    6   },
+		{ 0x6,    8   },
+		{ 0x7,    12  },
+		{ 0x8,    16  },
+	};
+	const int num_dids = (int) COUNT_OF(divisor_t);
+
+	/* Constant values for common families */
+	const int magic_constant = (info->id->ext_family == 0x11) ? 0x8 : 0x10;
+	const int is_apu = ((FUSION_C <= info->internal->code.amd) && (info->internal->code.amd <= FUSION_A)) || (info->internal->bits & _APU_);
+	const double divisor = is_apu ? 1.0 : 2.0;
+
+	/* Check if P-state is valid */
+	if (pstate < MSR_PSTATE_0 || MSR_PSTATE_7 < pstate)
+		return 1;
+
+	switch (info->id->ext_family) {
+		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))
+			Note: This family contains only APUs */
+			err  = cpu_rdmsr_range(info->handle, pstate, 8, 4, &CpuFid);
+			err += cpu_rdmsr_range(info->handle, pstate, 3, 0, &CpuDid);
+			i = 0;
+			while (i < num_dids && divisor_t[i].did != CpuDid)
+				i++;
+			if (i < num_dids)
+				*multiplier = (double) ((CpuFid + magic_constant) / divisor_t[i].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)
+			Note: This family contains only APUs */
+			err  = cpu_rdmsr_range(info->handle, pstate, 8, 4, &CpuDid);
+			err += cpu_rdmsr_range(info->handle, pstate, 3, 0, &CpuDidLSD);
+			*multiplier = (double) (((info->cpu_clock + 5) / 100 + magic_constant) / (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))
+			Note: This family contains only CPUs */
+		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))
+			Note: This family contains only CPUs */
+		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]))
+			Note: This family contains BOTH CPUs and APUs */
+		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]))
+			Note: This family contains only APUs */
+			err  = cpu_rdmsr_range(info->handle, pstate, 8, 6, &CpuDid);
+			err += cpu_rdmsr_range(info->handle, pstate, 5, 0, &CpuFid);
+			*multiplier = (double) ((CpuFid + magic_constant) / (1ull << CpuDid)) / divisor;
+			break;
+		case 0x17:
+			/* PPR 17h, pages 30 and 138-139
+			MSRC001_00[6B:64][13:8] is CpuDfsId
+			MSRC001_00[6B:64][7:0]  is CpuFid
+			CoreCOF is (Core::X86::Msr::PStateDef[CpuFid[7:0]] / Core::X86::Msr::PStateDef[CpuDfsId]) * 200 */
+			err  = cpu_rdmsr_range(info->handle, pstate, 13, 8, &CpuDid);
+			err += cpu_rdmsr_range(info->handle, pstate,  7, 0, &CpuFid);
+			*multiplier = (double) (CpuFid / CpuDid) * 2;
+			break;
+		default:
+			err = 1;
+			break;
+	}
+
+	return err;
+}
+
+static uint32_t get_amd_last_pstate_addr(struct msr_info_t *info)
+{
+	static uint32_t last_addr = 0x0;
+	uint64_t reg = 0x0;
+
+	/* The result is cached, need to be computed once */
+	if(last_addr != 0x0)
+		return last_addr;
+
+	/* Refer links above
+	MSRC001_00[6B:64][63] is PstateEn
+	PstateEn indicates if the rest of the P-state information in the register is valid after a reset */
+	last_addr = MSR_PSTATE_7 + 1;
+	while((reg == 0x0) && (last_addr > MSR_PSTATE_0)) {
+		last_addr--;
+		cpu_rdmsr_range(info->handle, last_addr, 63, 63, &reg);
+	}
+	return last_addr;
+}
+
+static double get_info_min_multiplier(struct msr_info_t *info)
+{
+	int err;
+	double mult;
+	uint32_t addr;
+	uint64_t reg;
+
+	if(info->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(info->handle, MSR_PLATFORM_INFO, 47, 40, &reg);
+		if (!err) return (double) reg;
+	}
+	else if(info->id->vendor == VENDOR_AMD) {
+		/* N.B.: Find the last P-state
+		get_amd_last_pstate_addr() returns the last P-state, MSR_PSTATE_0 <= addr <= MSR_PSTATE_7 */
+		addr = get_amd_last_pstate_addr(info);
+		err  = get_amd_multipliers(info, addr, &mult);
+		if (!err) return mult;
+	}
+
+	return (double) CPU_INVALID_VALUE / 100;
+}
+
+static double get_info_cur_multiplier(struct msr_info_t *info)
+{
+	int err;
+	double mult;
+	uint64_t reg;
+
+	if(info->id->vendor == VENDOR_INTEL && info->internal->code.intel == PENTIUM) {
+		err = cpu_rdmsr(info->handle, MSR_EBL_CR_POWERON, &reg);
+		if (!err) return (double) ((reg>>22) & 0x1f);
+	}
+	else if(info->id->vendor == VENDOR_INTEL && info->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(info->handle, IA32_PERF_STATUS, 15, 8, &reg);
+		if (!err) return (double) reg;
+	}
+	else if(info->id->vendor == VENDOR_AMD) {
+		/* Refer links above
+		MSRC001_0063[2:0] is CurPstate */
+		err  = cpu_rdmsr_range(info->handle, MSR_PSTATE_S, 2, 0, &reg);
+		err += get_amd_multipliers(info, MSR_PSTATE_0 + (uint32_t) reg, &mult);
+		if (!err) return mult;
+	}
+
+	return (double) CPU_INVALID_VALUE / 100;
+}
+
+static double get_info_max_multiplier(struct msr_info_t *info)
+{
+	int err;
+	double mult;
+	uint64_t reg;
+
+	if(info->id->vendor == VENDOR_INTEL && info->internal->code.intel == PENTIUM) {
+		err = cpu_rdmsr(info->handle, IA32_PERF_STATUS, &reg);
+		if (!err) return (double) ((reg >> 40) & 0x1f);
+	}
+	else if(info->id->vendor == VENDOR_INTEL && info->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(info->handle, MSR_TURBO_RATIO_LIMIT, 7, 0, &reg);
+		if (!err) return (double) reg;
+	}
+	else if(info->id->vendor == VENDOR_AMD) {
+		/* Refer links above
+		MSRC001_0064 is Pb0
+		Pb0 is the highest-performance boosted P-state */
+		err = get_amd_multipliers(info, MSR_PSTATE_0, &mult);
+		if (!err) return mult;
+	}
+
+	return (double) CPU_INVALID_VALUE / 100;
+}
+
+static int get_info_temperature(struct msr_info_t *info)
+{
+	int err;
+	uint64_t DigitalReadout, ReadingValid, TemperatureTarget;
+
+	if(info->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(info->handle, IA32_THERM_STATUS,      22, 16, &DigitalReadout);
+		err += cpu_rdmsr_range(info->handle, IA32_THERM_STATUS,      31, 31, &ReadingValid);
+		err += cpu_rdmsr_range(info->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_info_t *info)
+{
+	int err;
+	double VIDStep;
+	uint64_t reg, CpuVid;
+
+	if(info->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(info->handle, MSR_PERF_STATUS, 47, 32, &reg);
+		if (!err) return (double) reg / (1 << 13);
+	}
+	else if(info->id->vendor == VENDOR_AMD) {
+		/* Refer links above
+		MSRC001_00[6B:64][15:9]  is CpuVid (Jaguar and before)
+		MSRC001_00[6B:64][21:14] is CpuVid (Zen)
+		MSRC001_0063[2:0] is P-state Status
+		BKDG 10h, page 49: voltage = 1.550V - 0.0125V * SviVid (SVI1)
+		BKDG 15h, page 50: Voltage = 1.5500 - 0.00625 * Vid[7:0] (SVI2)
+		SVI2 since Piledriver (Family 15h, 2nd-gen): Models 10h-1Fh Processors */
+		VIDStep = ((info->id->ext_family < 0x15) || ((info->id->ext_family == 0x15) && (info->id->ext_model < 0x10))) ? 0.0125 : 0.00625;
+		err = cpu_rdmsr_range(info->handle, MSR_PSTATE_S, 2, 0, &reg);
+		if(info->id->ext_family < 0x17)
+			err += cpu_rdmsr_range(info->handle, MSR_PSTATE_0 + (uint32_t) reg, 15, 9, &CpuVid);
+		else
+			err += cpu_rdmsr_range(info->handle, MSR_PSTATE_0 + (uint32_t) reg, 21, 14, &CpuVid);
+		if (!err && MSR_PSTATE_0 + (uint32_t) reg <= MSR_PSTATE_7) return 1.550 - VIDStep * CpuVid;
+	}
+
+	return (double) CPU_INVALID_VALUE / 100;
+}
+
+static double get_info_bus_clock(struct msr_info_t *info)
+{
+	int err;
+	double mult;
+	uint32_t addr;
+	uint64_t reg;
+
+	if(info->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(info->handle, MSR_PLATFORM_INFO, 15, 8, &reg);
+		if (!err) return (double) info->cpu_clock / reg;
+	}
+	else if(info->id->vendor == VENDOR_AMD) {
+		/* Refer links above
+		MSRC001_0061[6:4] is PstateMaxVal
+		PstateMaxVal is the the lowest-performance non-boosted P-state */
+		addr = get_amd_last_pstate_addr(info);
+		err  = cpu_rdmsr_range(info->handle, MSR_PSTATE_L, 6, 4, &reg);
+		err += get_amd_multipliers(info, addr - reg, &mult);
+		if (!err) return (double) info->cpu_clock / mult;
+	}
+
+	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)
+{
+	static int err = 0, init = 0;
+	struct cpu_raw_data_t raw;
+	static struct cpu_id_t id;
+	static struct internal_id_info_t internal;
+	static struct msr_info_t info;
+
+	if (handle == NULL) {
+		set_error(ERR_HANDLE);
+		return CPU_INVALID_VALUE;
+	}
+
+	info.handle = handle;
+	if (!init) {
+		err  = cpuid_get_raw_data(&raw);
+		err += cpu_ident_internal(&raw, &id, &internal);
+		info.cpu_clock = cpu_clock_measure(250, 1);
+		info.id = &id;
+		info.internal = &internal;
+		init = 1;
+	}
+
+	if (err)
+		return CPU_INVALID_VALUE;
+
+	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(&info) * 100);
+		case INFO_CUR_MULTIPLIER:
+			return (int) (get_info_cur_multiplier(&info) * 100);
+		case INFO_MAX_MULTIPLIER:
+			return (int) (get_info_max_multiplier(&info) * 100);
+		case INFO_TEMPERATURE:
+			return get_info_temperature(&info);
+		case INFO_THROTTLING:
+			return CPU_INVALID_VALUE;
+		case INFO_VOLTAGE:
+			return (int) (get_info_voltage(&info) * 100);
+		case INFO_BCLK:
+		case INFO_BUS_CLOCK:
+			return (int) (get_info_bus_clock(&info) * 100);
+		default:
+			return CPU_INVALID_VALUE;
+	}
+}
+
+int msr_serialize_raw_data(struct msr_driver_t* handle, const char* filename)
+{
+	int i, j;
+	FILE *f;
+	uint64_t reg;
+	const uint32_t *msr;
+	struct cpu_raw_data_t raw;
+	struct cpu_id_t id;
+	struct internal_id_info_t internal;
+
+	if (handle == NULL)
+		return set_error(ERR_HANDLE);
+
+	if (!strcmp(filename, ""))
+		f = stdout;
+	else
+		f = fopen(filename, "wt");
+	if (!f) return set_error(ERR_OPEN);
+
+	if (cpuid_get_raw_data(&raw) || cpu_ident_internal(&raw, &id, &internal))
+		return -1;
+
+	fprintf(f, "CPU is %s %s, stock clock is %dMHz.\n", id.vendor_str, id.brand_str, cpu_clock_measure(250, 1));
+	if (id.vendor == VENDOR_INTEL)
+		msr = intel_msr;
+	else if (id.vendor == VENDOR_AMD)
+		msr = amd_msr;
+	else
+		return set_error(ERR_CPU_UNKN);
+
+	for (i = 0; msr[i] != CPU_INVALID_VALUE; i++) {
+		cpu_rdmsr(handle, msr[i], &reg);
+		fprintf(f, "msr[%#08x]=", msr[i]);
+		for (j = 56; j >= 0; j -= 8)
+			fprintf(f, "%02x ", (int) (reg >> j) & 0xff);
+		printf("\n");
+	}
+
+	if (strcmp(filename, ""))
+		fclose(f);
+	return set_error(ERR_OK);
+}
+
+#endif // RDMSR_UNSUPPORTED_OS

+ 320 - 0
Source/ThirdParty/LibCpuId/src/rdtsc.c

@@ -0,0 +1,320 @@
+/*
+ * Copyright 2008  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.
+ */
+#include <stdio.h>
+#include <string.h>
+#include "libcpuid.h"
+#include "libcpuid_util.h"
+#include "asm-bits.h"
+#include "rdtsc.h"
+
+#ifdef _WIN32
+#include <windows.h>
+void sys_precise_clock(uint64_t *result)
+{
+	double c, f;
+	LARGE_INTEGER freq, counter;
+	QueryPerformanceCounter(&counter);
+	QueryPerformanceFrequency(&freq);
+	c = (double) counter.QuadPart;
+	f = (double) freq.QuadPart;
+	*result = (uint64_t) ( c * 1000000.0 / f );
+}
+#else
+/* assuming Linux, Mac OS or other POSIX */
+#include <sys/time.h>
+void sys_precise_clock(uint64_t *result)
+{
+	struct timeval tv;
+	gettimeofday(&tv, NULL);
+	*result = (uint64_t) tv.tv_sec * (uint64_t) 1000000 +
+	          (uint64_t) tv.tv_usec;
+}
+#endif /* _WIN32 */
+
+/* out = a - b */
+static void mark_t_subtract(struct cpu_mark_t* a, struct cpu_mark_t* b, struct cpu_mark_t *out)
+{
+	out->tsc = a->tsc - b->tsc;
+	out->sys_clock = a->sys_clock - b->sys_clock;
+}
+
+void cpu_tsc_mark(struct cpu_mark_t* mark)
+{
+	cpu_rdtsc(&mark->tsc);
+	sys_precise_clock(&mark->sys_clock);
+}
+
+void cpu_tsc_unmark(struct cpu_mark_t* mark)
+{
+	struct cpu_mark_t temp;
+	cpu_tsc_mark(&temp);
+	mark_t_subtract(&temp, mark, mark);
+}
+
+
+int cpu_clock_by_mark(struct cpu_mark_t* mark)
+{
+	uint64_t result;
+	
+	/* Check if some subtraction resulted in a negative number: */
+	if ((mark->tsc >> 63) != 0 || (mark->sys_clock >> 63) != 0) return -1;
+	
+	/* Divide-by-zero check: */
+	if (mark->sys_clock == 0) return -1;
+	
+	/* Check if the result fits in 32bits */
+	result = mark->tsc / mark->sys_clock;
+	if (result > (uint64_t) 0x7fffffff) return -1;
+	return (int) result;
+}
+
+#ifdef _WIN32
+int cpu_clock_by_os(void)
+{
+	HKEY key;
+	DWORD result;
+	DWORD size = 4;
+	
+	if (RegOpenKeyEx(HKEY_LOCAL_MACHINE, TEXT("HARDWARE\\DESCRIPTION\\System\\CentralProcessor\\0"), 0, KEY_READ, &key) != ERROR_SUCCESS)
+		return -1;
+	
+	if (RegQueryValueEx(key, TEXT("~MHz"), NULL, NULL, (LPBYTE) &result, (LPDWORD) &size) != ERROR_SUCCESS) {
+		RegCloseKey(key);
+		return -1;
+	}
+	RegCloseKey(key);
+	
+	return (int)result;
+}
+#else
+#ifdef __APPLE__
+#include <sys/types.h>
+#include <sys/sysctl.h>
+/* Assuming Mac OS X with hw.cpufrequency sysctl */
+int cpu_clock_by_os(void)
+{
+	long long result = -1;
+	size_t size = sizeof(result);
+	if (sysctlbyname("hw.cpufrequency", &result, &size, NULL, 0))
+		return -1;
+	return (int) (result / (long long) 1000000);
+}
+#else
+/* Assuming Linux with /proc/cpuinfo */
+int cpu_clock_by_os(void)
+{
+	FILE *f;
+	char line[1024], *s;
+	int result;
+	
+	f = fopen("/proc/cpuinfo", "rt");
+	if (!f) return -1;
+	
+	while (fgets(line, sizeof(line), f)) {
+		if (!strncmp(line, "cpu MHz", 7)) {
+			s = strchr(line, ':');
+			if (s && 1 == sscanf(s, ":%d.", &result)) {
+				fclose(f);
+				return result;
+			}
+		}
+	}
+	fclose(f);
+	return -1;
+}
+#endif /* __APPLE__ */
+#endif /* _WIN32 */
+
+/* Emulate doing useful CPU intensive work */
+static int busy_loop(int amount)
+{
+	int i, j, k, s = 0;
+	static volatile int data[42] = {32, 12, -1, 5, 23, 0 };
+	for (i = 0; i < amount; i++)
+		for (j = 0; j < 65536; j++)
+			for (k = 0; k < 42; k++)
+				s += data[k];
+	return s;
+}
+
+int busy_loop_delay(int milliseconds)
+{
+	int cycles = 0, r = 0, first = 1;
+	uint64_t a, b, c;
+	sys_precise_clock(&a);
+	while (1) {
+		sys_precise_clock(&c);
+		if ((c - a) / 1000 > milliseconds) return r;
+		r += busy_loop(cycles);
+		if (first) {
+			first = 0;
+		} else {
+			if (c - b < 1000) cycles *= 2;
+			if (c - b > 10000) cycles /= 2;
+		}
+		b = c;
+	}
+}
+
+int cpu_clock_measure(int millis, int quad_check)
+{
+	struct cpu_mark_t begin[4], end[4], temp, temp2;
+	int results[4], cycles, n, k, i, j, bi, bj, mdiff, diff, _zero = 0;
+	uint64_t tl;
+	
+	if (millis < 1) return -1;
+	tl = millis * (uint64_t) 1000;
+	if (quad_check)
+		tl /= 4;
+	n = quad_check ? 4 : 1;
+	cycles = 1;
+	for (k = 0; k < n; k++) {
+		cpu_tsc_mark(&begin[k]);
+		end[k] = begin[k];
+		do {
+			/* Run busy loop, and fool the compiler that we USE the garbishy
+			   value it calculates */
+			_zero |= (1 & busy_loop(cycles));
+			cpu_tsc_mark(&temp);
+			mark_t_subtract(&temp, &end[k], &temp2);
+			/* If busy loop is too short, increase it */
+			if (temp2.sys_clock < tl / 8)
+				cycles *= 2;
+			end[k] = temp;
+		} while (end[k].sys_clock - begin[k].sys_clock < tl);
+		mark_t_subtract(&end[k], &begin[k], &temp);
+		results[k] = cpu_clock_by_mark(&temp);
+	}
+	if (n == 1) return results[0];
+	mdiff = 0x7fffffff;
+	bi = bj = -1;
+	for (i = 0; i < 4; i++) {
+		for (j = i + 1; j < 4; j++) {
+			diff = results[i] - results[j];
+			if (diff < 0) diff = -diff;
+			if (diff < mdiff) {
+				mdiff = diff;
+				bi = i;
+				bj = j;
+			}
+		}
+	}
+	if (results[bi] == -1) return -1;
+	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;
+	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)
+	cycles_inner = 128;
+	cycles_outer = 1;
+	do {
+		if (cycles_inner < 1000000000) cycles_inner *= 2;
+		else cycles_outer *= 2;
+		sys_precise_clock(&t0);
+		for (i = 0; i < cycles_outer; i++)
+			busy_sse_loop(cycles_inner);
+		sys_precise_clock(&t1);
+	} while (t1 - t0 < tl);
+	debugf(2, "inner: %d, outer: %d\n", cycles_inner, cycles_outer);
+	for (ri = 0; ri < runs; ri++) {
+		sys_precise_clock(&t0);
+		c = 0;
+		do {
+			c++;
+			for (i = 0; i < cycles_outer; i++)
+				busy_sse_loop(cycles_inner);
+			sys_precise_clock(&t1);
+		} while (t1 - t0 < tl * (uint64_t) 8);
+		// cpu_Hz = cycles_inner * cycles_outer * 256 / (t1 - t0) * 1000000
+		debugf(2, "c = %d, td = %d\n", c, (int) (t1 - t0));
+		hz = ((uint64_t) cycles_inner * (uint64_t) 256 + 12) * 
+		     (uint64_t) cycles_outer * (uint64_t) multiplier_numerator * (uint64_t) c * (uint64_t) 1000000
+		     / ((t1 - t0) * (uint64_t) multiplier_denom);
+		cur_value = (int) (hz / 1000000);
+		if (cur_value > max_value) max_value = cur_value;
+	}
+	return max_value;
+}
+
+int cpu_clock(void)
+{
+	int result;
+	result = cpu_clock_by_os();
+	if (result <= 0)
+		result = cpu_clock_measure(200, 1);
+	return result;
+}

+ 33 - 0
Source/ThirdParty/LibCpuId/src/rdtsc.h

@@ -0,0 +1,33 @@
+/*
+ * Copyright 2010  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 __RDTSC_H__
+#define __RDTSC_H__
+
+void sys_precise_clock(uint64_t *result);
+int busy_loop_delay(int milliseconds);
+
+
+#endif /* __RDTSC_H__ */

+ 530 - 0
Source/ThirdParty/LibCpuId/src/recog_amd.c

@@ -0,0 +1,530 @@
+/*
+ * Copyright 2008  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.
+ */
+
+#include <stdio.h>
+#include <string.h>
+#include <ctype.h>
+#include "libcpuid.h"
+#include "libcpuid_util.h"
+#include "libcpuid_internal.h"
+#include "recog_amd.h"
+
+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
+};
+
+struct amd_code_and_bits_t {
+	int code;
+	uint64_t bits;
+};
+
+enum _amd_model_codes_t {
+	// Only for Ryzen CPUs:
+	_1400,
+	_1500,
+	_1600,
+};
+
+
+const struct match_entry_t cpudb_amd[] = {
+	{ -1, -1, -1, -1,   -1,   1,    -1,    -1, NC, 0                   ,     0, "Unknown AMD CPU"               },
+	
+	/* 486 and the likes */
+	{  4, -1, -1, -1,   -1,   1,    -1,    -1, NC, 0                   ,     0, "Unknown AMD 486"               },
+	{  4,  3, -1, -1,   -1,   1,    -1,    -1, NC, 0                   ,     0, "AMD 486DX2"                    },
+	{  4,  7, -1, -1,   -1,   1,    -1,    -1, NC, 0                   ,     0, "AMD 486DX2WB"                  },
+	{  4,  8, -1, -1,   -1,   1,    -1,    -1, NC, 0                   ,     0, "AMD 486DX4"                    },
+	{  4,  9, -1, -1,   -1,   1,    -1,    -1, NC, 0                   ,     0, "AMD 486DX4WB"                  },
+	
+	/* Pentia clones */
+	{  5, -1, -1, -1,   -1,   1,    -1,    -1, NC, 0                   ,     0, "Unknown AMD 586"               },
+	{  5,  0, -1, -1,   -1,   1,    -1,    -1, NC, 0                   ,     0, "K5"                            },
+	{  5,  1, -1, -1,   -1,   1,    -1,    -1, NC, 0                   ,     0, "K5"                            },
+	{  5,  2, -1, -1,   -1,   1,    -1,    -1, NC, 0                   ,     0, "K5"                            },
+	{  5,  3, -1, -1,   -1,   1,    -1,    -1, NC, 0                   ,     0, "K5"                            },
+	
+	/* The K6 */
+	{  5,  6, -1, -1,   -1,   1,    -1,    -1, NC, 0                   ,     0, "K6"                            },
+	{  5,  7, -1, -1,   -1,   1,    -1,    -1, NC, 0                   ,     0, "K6"                            },
+	
+	{  5,  8, -1, -1,   -1,   1,    -1,    -1, NC, 0                   ,     0, "K6-2"                          },
+	{  5,  9, -1, -1,   -1,   1,    -1,    -1, NC, 0                   ,     0, "K6-III"                        },
+	{  5, 10, -1, -1,   -1,   1,    -1,    -1, NC, 0                   ,     0, "Unknown K6"                    },
+	{  5, 11, -1, -1,   -1,   1,    -1,    -1, NC, 0                   ,     0, "Unknown K6"                    },
+	{  5, 12, -1, -1,   -1,   1,    -1,    -1, NC, 0                   ,     0, "Unknown K6"                    },
+	{  5, 13, -1, -1,   -1,   1,    -1,    -1, NC, 0                   ,     0, "K6-2+"                         },
+	
+	/* Athlon et al. */
+	{  6,  1, -1, -1,   -1,   1,    -1,    -1, NC, 0                   ,     0, "Athlon (Slot-A)"               },
+	{  6,  2, -1, -1,   -1,   1,    -1,    -1, NC, 0                   ,     0, "Athlon (Slot-A)"               },
+	{  6,  3, -1, -1,   -1,   1,    -1,    -1, NC, 0                   ,     0, "Duron (Spitfire)"              },
+	{  6,  4, -1, -1,   -1,   1,    -1,    -1, NC, 0                   ,     0, "Athlon (ThunderBird)"          },
+	
+	{  6,  6, -1, -1,   -1,   1,    -1,    -1, NC, 0                   ,     0, "Unknown Athlon"                },
+	{  6,  6, -1, -1,   -1,   1,    -1,    -1, NC, ATHLON_             ,     0, "Athlon (Palomino)"             },
+	{  6,  6, -1, -1,   -1,   1,    -1,    -1, NC, ATHLON_|_MP_        ,     0, "Athlon MP (Palomino)"          },
+	{  6,  6, -1, -1,   -1,   1,    -1,    -1, NC, DURON_              ,     0, "Duron (Palomino)"              },
+	{  6,  6, -1, -1,   -1,   1,    -1,    -1, NC, ATHLON_|_XP_        ,     0, "Athlon XP"                     },
+	
+	{  6,  7, -1, -1,   -1,   1,    -1,    -1, NC, 0                   ,     0, "Unknown Athlon XP"             },
+	{  6,  7, -1, -1,   -1,   1,    -1,    -1, NC, DURON_              ,     0, "Duron (Morgan)"                },
+	
+	{  6,  8, -1, -1,   -1,   1,    -1,    -1, NC, 0                   ,     0, "Athlon XP"                     },
+	{  6,  8, -1, -1,   -1,   1,    -1,    -1, NC, ATHLON_             ,     0, "Athlon XP (Thoroughbred)"      },
+	{  6,  8, -1, -1,   -1,   1,    -1,    -1, NC, ATHLON_|_XP_        ,     0, "Athlon XP (Thoroughbred)"      },
+	{  6,  8, -1, -1,   -1,   1,    -1,    -1, NC, DURON_              ,     0, "Duron (Applebred)"             },
+	{  6,  8, -1, -1,   -1,   1,    -1,    -1, NC, SEMPRON_            ,     0, "Sempron (Thoroughbred)"        },
+	{  6,  8, -1, -1,   -1,   1,   128,    -1, NC, SEMPRON_            ,     0, "Sempron (Thoroughbred)"        },
+	{  6,  8, -1, -1,   -1,   1,   256,    -1, NC, SEMPRON_            ,     0, "Sempron (Thoroughbred)"        },
+	{  6,  8, -1, -1,   -1,   1,    -1,    -1, NC, ATHLON_|_MP_        ,     0, "Athlon MP (Thoroughbred)"      },
+	{  6,  8, -1, -1,   -1,   1,    -1,    -1, NC, ATHLON_|_XP_|_M_    ,     0, "Mobile Athlon (T-Bred)"        },
+	{  6,  8, -1, -1,   -1,   1,    -1,    -1, NC, ATHLON_|_XP_|_M_|_LV_,    0, "Mobile Athlon (T-Bred)"        },
+	
+	{  6, 10, -1, -1,   -1,   1,    -1,    -1, NC, 0                   ,     0, "Athlon XP (Barton)"            },
+	{  6, 10, -1, -1,   -1,   1,   512,    -1, NC, ATHLON_|_XP_        ,     0, "Athlon XP (Barton)"            },
+	{  6, 10, -1, -1,   -1,   1,   512,    -1, NC, SEMPRON_            ,     0, "Sempron (Barton)"              },
+	{  6, 10, -1, -1,   -1,   1,   256,    -1, NC, SEMPRON_            ,     0, "Sempron (Thorton)"             },
+	{  6, 10, -1, -1,   -1,   1,   256,    -1, NC, ATHLON_|_XP_        ,     0, "Athlon XP (Thorton)"           },
+	{  6, 10, -1, -1,   -1,   1,    -1,    -1, NC, ATHLON_|_MP_        ,     0, "Athlon MP (Barton)"            },
+	{  6, 10, -1, -1,   -1,   1,    -1,    -1, NC, ATHLON_|_XP_|_M_    ,     0, "Mobile Athlon (Barton)"        },
+	{  6, 10, -1, -1,   -1,   1,    -1,    -1, NC, ATHLON_|_XP_|_M_|_LV_,    0, "Mobile Athlon (Barton)"        },
+	
+	/* K8 Architecture */
+	{ 15, -1, -1, 15,   -1,   1,    -1,    -1, NC, 0                   ,     0, "Unknown K8"                    },
+	{ 15, -1, -1, 16,   -1,   1,    -1,    -1, NC, 0                   ,     0, "Unknown K9"                    },
+	
+	{ 15, -1, -1, 15,   -1,   1,    -1,    -1, NC, 0                   ,     0, "Unknown A64"                   },
+	{ 15, -1, -1, 15,   -1,   1,    -1,    -1, NC, OPTERON_            ,     0, "Opteron"                       },
+	{ 15, -1, -1, 15,   -1,   2,    -1,    -1, NC, OPTERON_|_X2        ,     0, "Opteron (Dual Core)"           },
+	{ 15,  3, -1, 15,   -1,   1,    -1,    -1, NC, OPTERON_            ,     0, "Opteron"                       },
+	{ 15,  3, -1, 15,   -1,   2,    -1,    -1, NC, OPTERON_|_X2        ,     0, "Opteron (Dual Core)"           },
+	{ 15, -1, -1, 15,   -1,   1,   512,    -1, NC, ATHLON_|_64_        ,     0, "Athlon 64 (512K)"              },
+	{ 15, -1, -1, 15,   -1,   1,  1024,    -1, NC, ATHLON_|_64_        ,     0, "Athlon 64 (1024K)"             },
+	{ 15, -1, -1, 15,   -1,   1,    -1,    -1, NC, ATHLON_|_FX         ,     0, "Athlon FX"                     },
+	{ 15, -1, -1, 15,   -1,   1,    -1,    -1, NC, ATHLON_|_64_|_FX    ,     0, "Athlon 64 FX"                  },
+	{ 15,  3, -1, 15,   35,   2,    -1,    -1, NC, ATHLON_|_64_|_FX    ,     0, "Athlon 64 FX X2 (Toledo)"      },
+	{ 15, -1, -1, 15,   -1,   2,   512,    -1, NC, ATHLON_|_64_|_X2    ,     0, "Athlon 64 X2 (512K)"           },
+	{ 15, -1, -1, 15,   -1,   2,  1024,    -1, NC, ATHLON_|_64_|_X2    ,     0, "Athlon 64 X2 (1024K)"          },
+	{ 15, -1, -1, 15,   -1,   1,   512,    -1, NC, TURION_|_64_        ,     0, "Turion 64 (512K)"              },
+	{ 15, -1, -1, 15,   -1,   1,  1024,    -1, NC, TURION_|_64_        ,     0, "Turion 64 (1024K)"             },
+	{ 15, -1, -1, 15,   -1,   2,   512,    -1, NC, TURION_|_X2         ,     0, "Turion 64 X2 (512K)"           },
+	{ 15, -1, -1, 15,   -1,   2,  1024,    -1, NC, TURION_|_X2         ,     0, "Turion 64 X2 (1024K)"          },
+	{ 15, -1, -1, 15,   -1,   1,   128,    -1, NC, SEMPRON_            ,     0, "A64 Sempron (128K)"            },
+	{ 15, -1, -1, 15,   -1,   1,   256,    -1, NC, SEMPRON_            ,     0, "A64 Sempron (256K)"            },
+	{ 15, -1, -1, 15,   -1,   1,   512,    -1, NC, SEMPRON_            ,     0, "A64 Sempron (512K)"            },
+	{ 15, -1, -1, 15, 0x4f,   1,   512,    -1, NC, ATHLON_|_64_        ,     0, "Athlon 64 (Orleans/512K)"      },
+	{ 15, -1, -1, 15, 0x5f,   1,   512,    -1, NC, ATHLON_|_64_        ,     0, "Athlon 64 (Orleans/512K)"      },
+	{ 15, -1, -1, 15, 0x2f,   1,   512,    -1, NC, ATHLON_|_64_        ,     0, "Athlon 64 (Venice/512K)"       },
+	{ 15, -1, -1, 15, 0x2c,   1,   512,    -1, NC, ATHLON_|_64_        ,     0, "Athlon 64 (Venice/512K)"       },
+	{ 15, -1, -1, 15, 0x1f,   1,   512,    -1, NC, ATHLON_|_64_        ,     0, "Athlon 64 (Winchester/512K)"   },
+	{ 15, -1, -1, 15, 0x0c,   1,   512,    -1, NC, ATHLON_|_64_        ,     0, "Athlon 64 (Newcastle/512K)"    },
+	{ 15, -1, -1, 15, 0x27,   1,   512,    -1, NC, ATHLON_|_64_        ,     0, "Athlon 64 (San Diego/512K)"    },
+	{ 15, -1, -1, 15, 0x37,   1,   512,    -1, NC, ATHLON_|_64_        ,     0, "Athlon 64 (San Diego/512K)"    },
+	{ 15, -1, -1, 15, 0x04,   1,   512,    -1, NC, ATHLON_|_64_        ,     0, "Athlon 64 (ClawHammer/512K)"   },
+	
+	{ 15, -1, -1, 15, 0x5f,   1,  1024,    -1, NC, ATHLON_|_64_        ,     0, "Athlon 64 (Orleans/1024K)"     },
+	{ 15, -1, -1, 15, 0x27,   1,  1024,    -1, NC, ATHLON_|_64_        ,     0, "Athlon 64 (San Diego/1024K)"   },
+	{ 15, -1, -1, 15, 0x04,   1,  1024,    -1, NC, ATHLON_|_64_        ,     0, "Athlon 64 (ClawHammer/1024K)"  },
+	
+	{ 15, -1, -1, 15, 0x4b,   2,   256,    -1, NC, SEMPRON_            ,     0, "Athlon 64 X2 (Windsor/256K)"   },
+	
+	{ 15, -1, -1, 15, 0x23,   2,   512,    -1, NC, ATHLON_|_64_|_X2    ,     0, "Athlon 64 X2 (Toledo/512K)"    },
+	{ 15, -1, -1, 15, 0x4b,   2,   512,    -1, NC, ATHLON_|_64_|_X2    ,     0, "Athlon 64 X2 (Windsor/512K)"   },
+	{ 15, -1, -1, 15, 0x43,   2,   512,    -1, NC, ATHLON_|_64_|_X2    ,     0, "Athlon 64 X2 (Windsor/512K)"   },
+	{ 15, -1, -1, 15, 0x6b,   2,   512,    -1, NC, ATHLON_|_64_|_X2    ,     0, "Athlon 64 X2 (Brisbane/512K)"  },
+	{ 15, -1, -1, 15, 0x2b,   2,   512,    -1, NC, ATHLON_|_64_|_X2    ,     0, "Athlon 64 X2 (Manchester/512K)"},
+	
+	{ 15, -1, -1, 15, 0x23,   2,  1024,    -1, NC, ATHLON_|_64_|_X2    ,     0, "Athlon 64 X2 (Toledo/1024K)"   },
+	{ 15, -1, -1, 15, 0x43,   2,  1024,    -1, NC, ATHLON_|_64_|_X2    ,     0, "Athlon 64 X2 (Windsor/1024K)"  },
+	
+	{ 15, -1, -1, 15, 0x08,   1,   128,    -1, NC, MOBILE_|SEMPRON_    ,     0, "Mobile Sempron 64 (Dublin/128K)"},
+	{ 15, -1, -1, 15, 0x08,   1,   256,    -1, NC, MOBILE_|SEMPRON_    ,     0, "Mobile Sempron 64 (Dublin/256K)"},
+	{ 15, -1, -1, 15, 0x0c,   1,   256,    -1, NC, SEMPRON_            ,     0, "Sempron 64 (Paris)"            },
+	{ 15, -1, -1, 15, 0x1c,   1,   128,    -1, NC, SEMPRON_            ,     0, "Sempron 64 (Palermo/128K)"     },
+	{ 15, -1, -1, 15, 0x1c,   1,   256,    -1, NC, SEMPRON_            ,     0, "Sempron 64 (Palermo/256K)"     },
+	{ 15, -1, -1, 15, 0x1c,   1,   128,    -1, NC, MOBILE_| SEMPRON_   ,     0, "Mobile Sempron 64 (Sonora/128K)"},
+	{ 15, -1, -1, 15, 0x1c,   1,   256,    -1, NC, MOBILE_| SEMPRON_   ,     0, "Mobile Sempron 64 (Sonora/256K)"},
+	{ 15, -1, -1, 15, 0x2c,   1,   128,    -1, NC, SEMPRON_            ,     0, "Sempron 64 (Palermo/128K)"     },
+	{ 15, -1, -1, 15, 0x2c,   1,   256,    -1, NC, SEMPRON_            ,     0, "Sempron 64 (Palermo/256K)"     },
+	{ 15, -1, -1, 15, 0x2c,   1,   128,    -1, NC, MOBILE_| SEMPRON_   ,     0, "Mobile Sempron 64 (Albany/128K)"},
+	{ 15, -1, -1, 15, 0x2c,   1,   256,    -1, NC, MOBILE_| SEMPRON_   ,     0, "Mobile Sempron 64 (Albany/256K)"},
+	{ 15, -1, -1, 15, 0x2f,   1,   128,    -1, NC, SEMPRON_            ,     0, "Sempron 64 (Palermo/128K)"     },
+	{ 15, -1, -1, 15, 0x2f,   1,   256,    -1, NC, SEMPRON_            ,     0, "Sempron 64 (Palermo/256K)"     },
+	{ 15, -1, -1, 15, 0x4f,   1,   128,    -1, NC, SEMPRON_            ,     0, "Sempron 64 (Manila/128K)"      },
+	{ 15, -1, -1, 15, 0x4f,   1,   256,    -1, NC, SEMPRON_            ,     0, "Sempron 64 (Manila/256K)"      },
+	{ 15, -1, -1, 15, 0x5f,   1,   128,    -1, NC, SEMPRON_            ,     0, "Sempron 64 (Manila/128K)"      },
+	{ 15, -1, -1, 15, 0x5f,   1,   256,    -1, NC, SEMPRON_            ,     0, "Sempron 64 (Manila/256K)"      },
+	{ 15, -1, -1, 15, 0x6b,   2,   256,    -1, NC, SEMPRON_            ,     0, "Sempron 64 Dual (Sherman/256K)"},
+	{ 15, -1, -1, 15, 0x6b,   2,   512,    -1, NC, SEMPRON_            ,     0, "Sempron 64 Dual (Sherman/512K)"},
+	{ 15, -1, -1, 15, 0x7f,   1,   256,    -1, NC, SEMPRON_            ,     0, "Sempron 64 (Sparta/256K)"      },
+	{ 15, -1, -1, 15, 0x7f,   1,   512,    -1, NC, SEMPRON_            ,     0, "Sempron 64 (Sparta/512K)"      },
+	{ 15, -1, -1, 15, 0x4c,   1,   256,    -1, NC, MOBILE_| SEMPRON_   ,     0, "Mobile Sempron 64 (Keene/256K)"},
+	{ 15, -1, -1, 15, 0x4c,   1,   512,    -1, NC, MOBILE_| SEMPRON_   ,     0, "Mobile Sempron 64 (Keene/512K)"},
+	{ 15, -1, -1, 15,   -1,   2,    -1,    -1, NC, SEMPRON_            ,     0, "Sempron Dual Core"             },
+	
+	{ 15, -1, -1, 15, 0x24,   1,   512,    -1, NC, TURION_|_64_        ,     0, "Turion 64 (Lancaster/512K)"    },
+	{ 15, -1, -1, 15, 0x24,   1,  1024,    -1, NC, TURION_|_64_        ,     0, "Turion 64 (Lancaster/1024K)"   },
+	{ 15, -1, -1, 15, 0x48,   2,   256,    -1, NC, TURION_|_X2         ,     0, "Turion X2 (Taylor)"            },
+	{ 15, -1, -1, 15, 0x48,   2,   512,    -1, NC, TURION_|_X2         ,     0, "Turion X2 (Trinidad)"          },
+	{ 15, -1, -1, 15, 0x4c,   1,   512,    -1, NC, TURION_|_64_        ,     0, "Turion 64 (Richmond)"          },
+	{ 15, -1, -1, 15, 0x68,   2,   256,    -1, NC, TURION_|_X2         ,     0, "Turion X2 (Tyler/256K)"        },
+	{ 15, -1, -1, 15, 0x68,   2,   512,    -1, NC, TURION_|_X2         ,     0, "Turion X2 (Tyler/512K)"        },
+	{ 15, -1, -1, 17,    3,   2,   512,    -1, NC, TURION_|_X2         ,     0, "Turion X2 (Griffin/512K)"      },
+	{ 15, -1, -1, 17,    3,   2,  1024,    -1, NC, TURION_|_X2         ,     0, "Turion X2 (Griffin/1024K)"     },
+
+	/* K10 Architecture (2007) */
+	{ 15, -1, -1, 16,   -1,   1,    -1,    -1, PHENOM, 0               ,     0, "Unknown AMD Phenom"            },
+	{ 15,  2, -1, 16,   -1,   1,    -1,    -1, PHENOM, 0               ,     0, "Phenom"                        },
+	{ 15,  2, -1, 16,   -1,   3,    -1,    -1, PHENOM, 0               ,     0, "Phenom X3 (Toliman)"           },
+	{ 15,  2, -1, 16,   -1,   4,    -1,    -1, PHENOM, 0               ,     0, "Phenom X4 (Agena)"             },
+	{ 15,  2, -1, 16,   -1,   3,   512,    -1, PHENOM, 0               ,     0, "Phenom X3 (Toliman/256K)"      },
+	{ 15,  2, -1, 16,   -1,   3,   512,    -1, PHENOM, 0               ,     0, "Phenom X3 (Toliman/512K)"      },
+	{ 15,  2, -1, 16,   -1,   4,   128,    -1, PHENOM, 0               ,     0, "Phenom X4 (Agena/128K)"        },
+	{ 15,  2, -1, 16,   -1,   4,   256,    -1, PHENOM, 0               ,     0, "Phenom X4 (Agena/256K)"        },
+	{ 15,  2, -1, 16,   -1,   4,   512,    -1, PHENOM,  0              ,     0, "Phenom X4 (Agena/512K)"        },
+	{ 15,  2, -1, 16,   -1,   2,   512,    -1, NC, ATHLON_|_64_|_X2    ,     0, "Athlon X2 (Kuma)"              },
+	/* Phenom II derivates: */
+	{ 15,  4, -1, 16,   -1,   4,    -1,    -1, NC, 0                   ,     0, "Phenom (Deneb-based)"          },
+	{ 15,  4, -1, 16,   -1,   1,  1024,    -1, NC, SEMPRON_            ,     0, "Sempron (Sargas)"              },
+	{ 15,  4, -1, 16,   -1,   2,   512,    -1, PHENOM2, 0              ,     0, "Phenom II X2 (Callisto)"       },
+	{ 15,  4, -1, 16,   -1,   3,   512,    -1, PHENOM2, 0              ,     0, "Phenom II X3 (Heka)"           },
+	{ 15,  4, -1, 16,   -1,   4,   512,    -1, PHENOM2, 0              ,     0, "Phenom II X4"                  },
+	{ 15,  4, -1, 16,    4,   4,   512,    -1, PHENOM2, 0              ,     0, "Phenom II X4 (Deneb)"          },
+	{ 15,  5, -1, 16,    5,   4,   512,    -1, PHENOM2, 0              ,     0, "Phenom II X4 (Deneb)"          },
+	{ 15,  4, -1, 16,   10,   4,   512,    -1, PHENOM2, 0              ,     0, "Phenom II X4 (Zosma)"          },
+	{ 15,  4, -1, 16,   10,   6,   512,    -1, PHENOM2, 0              ,     0, "Phenom II X6 (Thuban)"         },
+	/* Athlon II derivates: */
+	{ 15,  6, -1, 16,    6,   2,   512,    -1, NC, ATHLON_|_X2         ,     0, "Athlon II (Champlain)"         },
+	{ 15,  6, -1, 16,    6,   2,   512,    -1, NC, ATHLON_|_64_|_X2    ,     0, "Athlon II X2 (Regor)"          },
+	{ 15,  6, -1, 16,    6,   2,  1024,    -1, NC, ATHLON_|_64_|_X2    ,     0, "Athlon II X2 (Regor)"          },
+	{ 15,  5, -1, 16,    5,   3,   512,    -1, NC, ATHLON_|_64_|_X3    ,     0, "Athlon II X3 (Rana)"           },
+	{ 15,  5, -1, 16,    5,   4,   512,    -1, NC, ATHLON_|_64_|_X4    ,     0, "Athlon II X4 (Propus)"         },
+	/* Llano APUs (2011): */
+	{ 15,  1, -1, 18,    1,   2,    -1,    -1, FUSION_EA, 0            ,     0, "Llano X2"                      },
+	{ 15,  1, -1, 18,    1,   3,    -1,    -1, FUSION_EA, 0            ,     0, "Llano X3"                      },
+	{ 15,  1, -1, 18,    1,   4,    -1,    -1, FUSION_EA, 0            ,     0, "Llano X4"                      },
+
+	/* Family 14h: Bobcat Architecture (2011) */
+	{ 15,  2, -1, 20,   -1,   1,    -1,    -1, FUSION_C, 0             ,     0, "Brazos Ontario"                },
+	{ 15,  2, -1, 20,   -1,   2,    -1,    -1, FUSION_C, 0             ,     0, "Brazos Ontario (Dual-core)"    },
+	{ 15,  1, -1, 20,   -1,   1,    -1,    -1, FUSION_E, 0             ,     0, "Brazos Zacate"                 },
+	{ 15,  1, -1, 20,   -1,   2,    -1,    -1, FUSION_E, 0             ,     0, "Brazos Zacate (Dual-core)"     },
+	{ 15,  2, -1, 20,   -1,   2,    -1,    -1, FUSION_Z, 0             ,     0, "Brazos Desna (Dual-core)"      },
+
+	/* Family 15h: Bulldozer Architecture (2011) */
+	{ 15, -1, -1, 21,    0,   4,    -1,    -1, NC, 0                   ,     0, "Bulldozer X2"                  },
+	{ 15, -1, -1, 21,    1,   4,    -1,    -1, NC, 0                   ,     0, "Bulldozer X2"                  },
+	{ 15, -1, -1, 21,    1,   6,    -1,    -1, NC, 0                   ,     0, "Bulldozer X3"                  },
+	{ 15, -1, -1, 21,    1,   8,    -1,    -1, NC, 0                   ,     0, "Bulldozer X4"                  },
+	/* 2nd-gen, Piledriver core (2012): */
+	{ 15, -1, -1, 21,    2,   4,    -1,    -1, NC, 0                   ,     0, "Vishera X2"                    },
+	{ 15, -1, -1, 21,    2,   6,    -1,    -1, NC, 0                   ,     0, "Vishera X3"                    },
+	{ 15, -1, -1, 21,    2,   8,    -1,    -1, NC, 0                   ,     0, "Vishera X4"                    },
+	{ 15,  0, -1, 21,   16,   2,    -1,    -1, FUSION_A, 0             ,     0, "Trinity X2"                    },
+	{ 15,  0, -1, 21,   16,   4,    -1,    -1, FUSION_A, 0             ,     0, "Trinity X4"                    },
+	{ 15,  3, -1, 21,   19,   2,    -1,    -1, FUSION_A, 0             ,     0, "Richland X2"                   },
+	{ 15,  3, -1, 21,   19,   4,    -1,    -1, FUSION_A, 0             ,     0, "Richland X4"                   },
+	/* 3rd-gen, Steamroller core (2014): */
+	{ 15,  0, -1, 21,   48,   2,    -1,    -1, FUSION_A, 0             ,     0, "Kaveri X2"                     },
+	{ 15,  0, -1, 21,   48,   4,    -1,    -1, FUSION_A, 0             ,     0, "Kaveri X4"                     },
+	{ 15,  8, -1, 21,   56,   4,    -1,    -1, FUSION_A, 0             ,     0, "Godavari X4"                   },
+	/* 4th-gen, Excavator core (2015): */
+	{ 15,  1, -1, 21,   96,   2,    -1,    -1, FUSION_A, 0             ,     0, "Carrizo X2"                    },
+	{ 15,  1, -1, 21,   96,   4,    -1,    -1, FUSION_A, 0             ,     0, "Carrizo X4"                    },
+	{ 15,  5, -1, 21,  101,   2,    -1,    -1, FUSION_A, 0             ,     0, "Bristol Ridge X2"              },
+	{ 15,  5, -1, 21,  101,   4,    -1,    -1, FUSION_A, 0             ,     0, "Bristol Ridge X4"              },
+	{ 15,  0, -1, 21,  112,   2,    -1,    -1, FUSION_A, 0             ,     0, "Stoney Ridge X2"               },
+	{ 15,  0, -1, 21,  112,   2,    -1,    -1, FUSION_E, 0             ,     0, "Stoney Ridge X2"               },
+
+	/* Family 16h: Jaguar Architecture (2013) */
+	{ 15,  0, -1, 22,    0,   2,    -1,    -1, FUSION_A, 0             ,     0, "Kabini X2"                     },
+	{ 15,  0, -1, 22,    0,   4,    -1,    -1, FUSION_A, 0             ,     0, "Kabini X4"                     },
+	/* 2nd-gen, Puma core (2013): */
+	{ 15,  0, -1, 22,   48,   2,    -1,    -1, FUSION_E, 0             ,     0, "Mullins X2"                    },
+	{ 15,  0, -1, 22,   48,   4,    -1,    -1, FUSION_A, 0             ,     0, "Mullins X4"                    },
+
+	/* Family 17h: Zen Architecture (2017) */
+	{ 15, -1, -1, 23,    1,   8,    -1,    -1, NC, 0                   ,     0, "Ryzen 7"                       },
+	{ 15, -1, -1, 23,    1,   6,    -1,    -1, NC, 0                   , _1600, "Ryzen 5"                       },
+	{ 15, -1, -1, 23,    1,   4,    -1,    -1, NC, 0                   , _1500, "Ryzen 5"                       },
+	{ 15, -1, -1, 23,    1,   4,    -1,    -1, NC, 0                   , _1400, "Ryzen 5"                       },
+	{ 15, -1, -1, 23,    1,   4,    -1,    -1, NC, 0                   ,     0, "Ryzen 3"                       },
+	//{ 15, -1, -1, 23,    1,   4,    -1,    -1, NC, 0                   ,     0, "Raven Ridge"                   }, //TBA
+
+	/* Newer Opterons: */
+	{ 15,  9, -1, 22,    9,   8,    -1,    -1, NC, OPTERON_            ,     0, "Magny-Cours Opteron"           },
+};
+
+
+static void load_amd_features(struct cpu_raw_data_t* raw, struct cpu_id_t* data)
+{
+	const struct feature_map_t matchtable_edx81[] = {
+		{ 20, CPU_FEATURE_NX },
+		{ 22, CPU_FEATURE_MMXEXT },
+		{ 25, CPU_FEATURE_FXSR_OPT },
+		{ 30, CPU_FEATURE_3DNOWEXT },
+		{ 31, CPU_FEATURE_3DNOW },
+	};
+	const struct feature_map_t matchtable_ecx81[] = {
+		{  1, CPU_FEATURE_CMP_LEGACY },
+		{  2, CPU_FEATURE_SVM },
+		{  5, CPU_FEATURE_ABM },
+		{  6, CPU_FEATURE_SSE4A },
+		{  7, CPU_FEATURE_MISALIGNSSE },
+		{  8, CPU_FEATURE_3DNOWPREFETCH },
+		{  9, CPU_FEATURE_OSVW },
+		{ 10, CPU_FEATURE_IBS },
+		{ 11, CPU_FEATURE_XOP },
+		{ 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 },
+		{  1, CPU_FEATURE_FID },
+		{  2, CPU_FEATURE_VID },
+		{  3, CPU_FEATURE_TTP },
+		{  4, CPU_FEATURE_TM_AMD },
+		{  5, CPU_FEATURE_STC },
+		{  6, CPU_FEATURE_100MHZSTEPS },
+		{  7, CPU_FEATURE_HWPSTATE },
+		/* id 8 is handled in common */
+		{  9, CPU_FEATURE_CPB },
+		{ 10, CPU_FEATURE_APERFMPERF },
+		{ 11, CPU_FEATURE_PFI },
+		{ 12, CPU_FEATURE_PA },
+	};
+	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);
+	}
+	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 */
+		data->detection_hints[CPU_HINT_SSE_SIZE_AUTH] = 1;
+		data->sse_size = (raw->ext_cpuid[0x1a][0] & 1) ? 128 : 64;
+	}
+}
+
+static void decode_amd_cache_info(struct cpu_raw_data_t* raw, struct cpu_id_t* data)
+{
+	int l3_result;
+	const int assoc_table[16] = {
+		0, 1, 2, 0, 4, 0, 8, 0, 16, 0, 32, 48, 64, 96, 128, 255
+	};
+	unsigned n = raw->ext_cpuid[0][0];
+	
+	if (n >= 0x80000005) {
+		data->l1_data_cache = (raw->ext_cpuid[5][2] >> 24) & 0xff;
+		data->l1_assoc = (raw->ext_cpuid[5][2] >> 16) & 0xff;
+		data->l1_cacheline = (raw->ext_cpuid[5][2]) & 0xff;
+		data->l1_instruction_cache = (raw->ext_cpuid[5][3] >> 24) & 0xff;
+	}
+	if (n >= 0x80000006) {
+		data->l2_cache = (raw->ext_cpuid[6][2] >> 16) & 0xffff;
+		data->l2_assoc = assoc_table[(raw->ext_cpuid[6][2] >> 12) & 0xf];
+		data->l2_cacheline = (raw->ext_cpuid[6][2]) & 0xff;
+		
+		l3_result = (raw->ext_cpuid[6][3] >> 18);
+		if (l3_result > 0) {
+			l3_result = 512 * l3_result; /* AMD spec says it's a range,
+			                                but we take the lower bound */
+			data->l3_cache = l3_result;
+			data->l3_assoc = assoc_table[(raw->ext_cpuid[6][3] >> 12) & 0xf];
+			data->l3_cacheline = (raw->ext_cpuid[6][3]) & 0xff;
+		} else {
+			data->l3_cache = 0;
+		}
+	}
+}
+
+static void decode_amd_number_of_cores(struct cpu_raw_data_t* raw, struct cpu_id_t* data)
+{
+	int logical_cpus = -1, num_cores = -1;
+	
+	if (raw->basic_cpuid[0][0] >= 1) {
+		logical_cpus = (raw->basic_cpuid[1][1] >> 16) & 0xff;
+		if (raw->ext_cpuid[0][0] >= 8) {
+			num_cores = 1 + (raw->ext_cpuid[8][2] & 0xff);
+		}
+	}
+	if (data->flags[CPU_FEATURE_HT]) {
+		if (num_cores > 1) {
+			if (data->ext_family >= 23)
+				num_cores /= 2; // e.g., Ryzen 7 reports 16 "real" cores, but they are really just 8.
+			data->num_cores = num_cores;
+			data->num_logical_cpus = logical_cpus;
+		} else {
+			data->num_cores = 1;
+			data->num_logical_cpus = (logical_cpus >= 2 ? logical_cpus : 2);
+		}
+	} else {
+		data->num_cores = data->num_logical_cpus = 1;
+	}
+}
+
+static int amd_has_turion_modelname(const char *bs)
+{
+	/* We search for something like TL-60. Ahh, I miss regexes...*/
+	int i, l, k;
+	char code[3] = {0};
+	const char* codes[] = { "ML", "MT", "MK", "TK", "TL", "RM", "ZM", "" };
+	l = (int) strlen(bs);
+	for (i = 3; i < l - 2; i++) {
+		if (bs[i] == '-' &&
+		    isupper(bs[i-1]) && isupper(bs[i-2]) && !isupper(bs[i-3]) &&
+		    isdigit(bs[i+1]) && isdigit(bs[i+2]) && !isdigit(bs[i+3]))
+		{
+			code[0] = bs[i-2];
+			code[1] = bs[i-1];
+			for (k = 0; codes[k][0]; k++)
+				if (!strcmp(codes[k], code)) return 1;
+		}
+	}
+	return 0;
+}
+
+static struct amd_code_and_bits_t decode_amd_codename_part1(const char *bs)
+{
+	amd_code_t code = NC;
+	uint64_t bits = 0;
+	struct amd_code_and_bits_t result;
+
+	if (strstr(bs, "Dual Core") ||
+	    strstr(bs, "Dual-Core") ||
+	    strstr(bs, " X2 "))
+		bits |= _X2;
+	if (strstr(bs, " X4 ")) bits |= _X4;
+	if (strstr(bs, " X3 ")) bits |= _X3;
+	if (strstr(bs, "Opteron")) bits |= OPTERON_;
+	if (strstr(bs, "Phenom")) {
+		code = (strstr(bs, "II")) ? PHENOM2 : PHENOM;
+	}
+	if (amd_has_turion_modelname(bs)) {
+		bits |= TURION_;
+	}
+	if (strstr(bs, "Athlon(tm)")) bits |= ATHLON_;
+	if (strstr(bs, "Sempron(tm)")) bits |= SEMPRON_;
+	if (strstr(bs, "Duron")) bits |= DURON_;
+	if (strstr(bs, " 64 ")) bits |= _64_;
+	if (strstr(bs, " FX")) bits |= _FX;
+	if (strstr(bs, " MP")) bits |= _MP_;
+	if (strstr(bs, "Athlon(tm) 64") || strstr(bs, "Athlon(tm) II X") || match_pattern(bs, "Athlon(tm) X#")) {
+		bits |= ATHLON_ | _64_;
+	}
+	if (strstr(bs, "Turion")) bits |= TURION_;
+	
+	if (strstr(bs, "mobile") || strstr(bs, "Mobile")) {
+		bits |= MOBILE_;
+	}
+	
+	if (strstr(bs, "XP")) bits |= _XP_;
+	if (strstr(bs, "XP-M")) bits |= _M_;
+	if (strstr(bs, "(LV)")) bits |= _LV_;
+	if (strstr(bs, " APU ")) bits |= _APU_;
+
+	if (match_pattern(bs, "C-##")) code = FUSION_C;
+	if (match_pattern(bs, "E-###")) code = FUSION_E;
+	if (match_pattern(bs, "Z-##")) code = FUSION_Z;
+	if (match_pattern(bs, "[EA]#-####")) code = FUSION_EA;
+
+	result.code = code;
+	result.bits = bits;
+	return result;
+}
+
+static int decode_amd_ryzen_model_code(const char* bs)
+{
+	const struct {
+		int model_code;
+		const char* match_str;
+	} patterns[] = {
+		{ _1600, "1600" },
+		{ _1500, "1500" },
+		{ _1400, "1400" },
+	};
+	int i;
+
+	for (i = 0; i < COUNT_OF(patterns); i++)
+		if (strstr(bs, patterns[i].match_str))
+			return patterns[i].model_code;
+	//
+	return 0;
+}
+
+static void decode_amd_codename(struct cpu_raw_data_t* raw, struct cpu_id_t* data, struct internal_id_info_t* internal)
+{
+	struct amd_code_and_bits_t code_and_bits = decode_amd_codename_part1(data->brand_str);
+	int i = 0;
+	char* code_str = NULL;
+	int model_code;
+
+	for (i = 0; i < COUNT_OF(amd_code_str); i++) {
+		if (code_and_bits.code == amd_code_str[i].code) {
+			code_str = amd_code_str[i].str;
+			break;
+		}
+	}
+	if (/*code == ATHLON_64_X2*/ match_all(code_and_bits.bits, ATHLON_|_64_|_X2) && data->l2_cache < 512) {
+		code_and_bits.bits &= ~(ATHLON_ | _64_);
+		code_and_bits.bits |= SEMPRON_;
+	}
+	if (code_str)
+		debugf(2, "Detected AMD brand code: %d (%s)\n", code_and_bits.code, code_str);
+	else
+		debugf(2, "Detected AMD brand code: %d\n", code_and_bits.code);
+
+	if (code_and_bits.bits) {
+		debugf(2, "Detected AMD bits: ");
+		debug_print_lbits(2, code_and_bits.bits);
+	}
+	// is it Ryzen? if so, we need to detect discern between the four-core 1400/1500 (Ryzen 5) and the four-core Ryzen 3:
+	model_code = (data->ext_family == 23) ? decode_amd_ryzen_model_code(data->brand_str) : 0;
+
+	internal->code.amd = code_and_bits.code;
+	internal->bits = code_and_bits.bits;
+	internal->score = match_cpu_codename(cpudb_amd, COUNT_OF(cpudb_amd), data, code_and_bits.code,
+	                                     code_and_bits.bits, model_code);
+}
+
+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, internal);
+	return 0;
+}
+
+void cpuid_get_list_amd(struct cpu_list_t* list)
+{
+	generic_get_cpu_list(cpudb_amd, COUNT_OF(cpudb_amd), list);
+}

+ 32 - 0
Source/ThirdParty/LibCpuId/src/recog_amd.h

@@ -0,0 +1,32 @@
+/*
+ * Copyright 2008  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 __RECOG_AMD_H__
+#define __RECOG_AMD_H__
+
+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__ */

+ 919 - 0
Source/ThirdParty/LibCpuId/src/recog_intel.c

@@ -0,0 +1,919 @@
+/*
+ * Copyright 2008  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.
+ */
+#include <string.h>
+#include <ctype.h>
+#include "libcpuid.h"
+#include "libcpuid_util.h"
+#include "libcpuid_internal.h"
+#include "recog_intel.h"
+
+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 struct {
+	int code;
+	uint64_t bits;
+} intel_code_and_bits_t;
+
+enum _intel_model_t {
+	UNKNOWN = -1,
+	_3000 = 100,
+	_3100,
+	_3200,
+	X3200,
+	_3300,
+	X3300,
+	_5100,
+	_5200,
+	_5300,
+	_5400,
+	_2xxx, /* Core i[357] 2xxx */
+	_3xxx, /* Core i[357] 3xxx */
+};
+typedef enum _intel_model_t intel_model_t;
+
+const struct match_entry_t cpudb_intel[] = {
+	{ -1, -1, -1, -1, -1,   1,    -1,    -1, NC, 0             ,     0, "Unknown Intel CPU"       },
+	
+	/* i486 */
+	{  4, -1, -1, -1, -1,   1,    -1,    -1, NC, 0             ,     0, "Unknown i486"            },
+	{  4,  0, -1, -1, -1,   1,    -1,    -1, NC, 0             ,     0, "i486 DX-25/33"           },
+	{  4,  1, -1, -1, -1,   1,    -1,    -1, NC, 0             ,     0, "i486 DX-50"              },
+	{  4,  2, -1, -1, -1,   1,    -1,    -1, NC, 0             ,     0, "i486 SX"                 },
+	{  4,  3, -1, -1, -1,   1,    -1,    -1, NC, 0             ,     0, "i486 DX2"                },
+	{  4,  4, -1, -1, -1,   1,    -1,    -1, NC, 0             ,     0, "i486 SL"                 },
+	{  4,  5, -1, -1, -1,   1,    -1,    -1, NC, 0             ,     0, "i486 SX2"                },
+	{  4,  7, -1, -1, -1,   1,    -1,    -1, NC, 0             ,     0, "i486 DX2 WriteBack"      },
+	{  4,  8, -1, -1, -1,   1,    -1,    -1, NC, 0             ,     0, "i486 DX4"                },
+	{  4,  9, -1, -1, -1,   1,    -1,    -1, NC, 0             ,     0, "i486 DX4 WriteBack"      },
+	
+	/* All Pentia:
+	   Pentium 1 */
+	{  5, -1, -1, -1, -1,   1,    -1,    -1, NC, 0             ,     0, "Unknown Pentium"         },
+	{  5,  0, -1, -1, -1,   1,    -1,    -1, NC, 0             ,     0, "Pentium A-Step"          },
+	{  5,  1, -1, -1, -1,   1,    -1,    -1, NC, 0             ,     0, "Pentium 1 (0.8u)"        },
+	{  5,  2, -1, -1, -1,   1,    -1,    -1, NC, 0             ,     0, "Pentium 1 (0.35u)"       },
+	{  5,  3, -1, -1, -1,   1,    -1,    -1, NC, 0             ,     0, "Pentium OverDrive"       },
+	{  5,  4, -1, -1, -1,   1,    -1,    -1, NC, 0             ,     0, "Pentium 1 (0.35u)"       },
+	{  5,  7, -1, -1, -1,   1,    -1,    -1, NC, 0             ,     0, "Pentium 1 (0.35u)"       },
+	{  5,  8, -1, -1, -1,   1,    -1,    -1, NC, 0             ,     0, "Pentium MMX (0.25u)"     },
+	
+	/* Pentium 2 / 3 / M / Conroe / whatsnext - all P6 based. */
+	{  6, -1, -1, -1, -1,   1,    -1,    -1, NC, 0             ,     0, "Unknown P6"              },
+	{  6,  0, -1, -1, -1,   1,    -1,    -1, NC, 0             ,     0, "Pentium Pro"             },
+	{  6,  1, -1, -1, -1,   1,    -1,    -1, NC, 0             ,     0, "Pentium Pro"             },
+	{  6,  3, -1, -1, -1,   1,    -1,    -1, NC, 0             ,     0, "Pentium II (Klamath)"    },
+	{  6,  5, -1, -1, -1,   1,    -1,    -1, NC, 0             ,     0, "Pentium II (Deschutes)"  },
+	{  6,  5, -1, -1, -1,   1,    -1,    -1, NC, MOBILE_|PENTIUM_,   0, "Mobile Pentium II (Tonga)"},
+	{  6,  6, -1, -1, -1,   1,    -1,    -1, NC,0              ,     0, "Pentium II (Dixon)"      },
+	
+	{  6,  3, -1, -1, -1,   1,    -1,    -1, NC, XEON_         ,     0, "P-II Xeon (Klamath)"     },
+	{  6,  5, -1, -1, -1,   1,    -1,    -1, NC, XEON_         ,     0, "P-II Xeon (Drake)"       },
+	{  6,  6, -1, -1, -1,   1,    -1,    -1, NC, XEON_         ,     0, "P-II Xeon (Dixon)"       },
+		
+	{  6,  5, -1, -1, -1,   1,    -1,    -1, NC, CELERON_      ,     0, "P-II Celeron (Covington)" },
+	{  6,  6, -1, -1, -1,   1,    -1,    -1, NC, CELERON_      ,     0, "P-II Celeron (Mendocino)" },
+	
+	/* -------------------------------------------------- */
+	
+	{  6,  7, -1, -1, -1,   1,    -1,    -1, NC, 0             ,     0, "Pentium III (Katmai)"    },
+	{  6,  8, -1, -1, -1,   1,    -1,    -1, NC, 0             ,     0, "Pentium III (Coppermine)"},
+	{  6, 10, -1, -1, -1,   1,    -1,    -1, NC, 0             ,     0, "Pentium III (Coppermine)"},
+	{  6, 11, -1, -1, -1,   1,    -1,    -1, NC, 0             ,     0, "Pentium III (Tualatin)"  },
+	
+	{  6,  7, -1, -1, -1,   1,    -1,    -1, NC, XEON_         ,     0, "P-III Xeon (Tanner)"     },
+	{  6,  8, -1, -1, -1,   1,    -1,    -1, NC, XEON_         ,     0, "P-III Xeon (Cascades)"   },
+	{  6, 10, -1, -1, -1,   1,    -1,    -1, NC, XEON_         ,     0, "P-III Xeon (Cascades)"   },
+	{  6, 11, -1, -1, -1,   1,    -1,    -1, NC, XEON_         ,     0, "P-III Xeon (Tualatin)"   },
+	
+	{  6,  7, -1, -1, -1,   1,    -1,    -1, NC, CELERON_      ,     0, "P-III Celeron (Katmai)"     },
+	{  6,  8, -1, -1, -1,   1,    -1,    -1, NC, CELERON_      ,     0, "P-III Celeron (Coppermine)" },
+	{  6, 10, -1, -1, -1,   1,    -1,    -1, NC, CELERON_      ,     0, "P-III Celeron (Coppermine)" },
+	{  6, 11, -1, -1, -1,   1,    -1,    -1, NC, CELERON_      ,     0, "P-III Celeron (Tualatin)"   },
+	
+	/* Netburst based (Pentium 4 and later)
+	   classic P4s */
+	{ 15, -1, -1, -1, -1,   1,    -1,    -1, NC, 0             ,     0, "Unknown Pentium 4"       },
+	{ 15, -1, -1, 15, -1,   1,    -1,    -1, NC, CELERON_      ,     0, "Unknown P-4 Celeron"     },
+	{ 15, -1, -1, 15, -1,   1,    -1,    -1, NC, XEON_         ,     0, "Unknown Xeon"            },
+	
+	{ 15,  0, -1, 15, -1,   1,    -1,    -1, NC, PENTIUM_      ,     0, "Pentium 4 (Willamette)"  },
+	{ 15,  1, -1, 15, -1,   1,    -1,    -1, NC, PENTIUM_      ,     0, "Pentium 4 (Willamette)"  },
+	{ 15,  2, -1, 15, -1,   1,    -1,    -1, NC, PENTIUM_      ,     0, "Pentium 4 (Northwood)"   },
+	{ 15,  3, -1, 15, -1,   1,    -1,    -1, NC, PENTIUM_      ,     0, "Pentium 4 (Prescott)"    },
+	{ 15,  4, -1, 15, -1,   1,    -1,    -1, NC, PENTIUM_      ,     0, "Pentium 4 (Prescott)"    },
+	{ 15,  6, -1, 15, -1,   1,    -1,    -1, NC, PENTIUM_      ,     0, "Pentium 4 (Cedar Mill)"  },
+	{ 15,  0, -1, 15, -1,   1,    -1,    -1, NC, MOBILE_|PENTIUM_,   0, "Mobile P-4 (Willamette)" },
+	{ 15,  1, -1, 15, -1,   1,    -1,    -1, NC, MOBILE_|PENTIUM_,   0, "Mobile P-4 (Willamette)" },
+	{ 15,  2, -1, 15, -1,   1,    -1,    -1, NC, MOBILE_|PENTIUM_,   0, "Mobile P-4 (Northwood)"  },
+	{ 15,  3, -1, 15, -1,   1,    -1,    -1, NC, MOBILE_|PENTIUM_,   0, "Mobile P-4 (Prescott)"   },
+	{ 15,  4, -1, 15, -1,   1,    -1,    -1, NC, MOBILE_|PENTIUM_,   0, "Mobile P-4 (Prescott)"   },
+	{ 15,  6, -1, 15, -1,   1,    -1,    -1, NC, MOBILE_|PENTIUM_,   0, "Mobile P-4 (Cedar Mill)" },
+	
+	/* server CPUs */
+	{ 15,  0, -1, 15, -1,   1,    -1,    -1, NC, XEON_         ,     0, "Xeon (Foster)"           },
+	{ 15,  1, -1, 15, -1,   1,    -1,    -1, NC, XEON_         ,     0, "Xeon (Foster)"           },
+	{ 15,  2, -1, 15, -1,   1,    -1,    -1, NC, XEON_         ,     0, "Xeon (Prestonia)"        },
+	{ 15,  2, -1, 15, -1,   1,    -1,    -1, NC, XEON_|_MP_    ,     0, "Xeon (Gallatin)"         },
+	{ 15,  3, -1, 15, -1,   1,    -1,    -1, NC, XEON_         ,     0, "Xeon (Nocona)"           },
+	{ 15,  4, -1, 15, -1,   1,    -1,    -1, NC, XEON_         ,     0, "Xeon (Nocona)"           },
+	{ 15,  4, -1, 15, -1,   1,    -1,    -1, IRWIN, XEON_      ,     0, "Xeon (Irwindale)"        },
+	{ 15,  4, -1, 15, -1,   1,    -1,    -1, NC, XEON_|_MP_    ,     0, "Xeon (Cranford)"         },
+	{ 15,  4, -1, 15, -1,   1,    -1,    -1, POTOMAC, XEON_    ,     0, "Xeon (Potomac)"          },
+	{ 15,  6, -1, 15, -1,   1,    -1,    -1, NC, XEON_         ,     0, "Xeon (Dempsey)"          },
+	
+	/* Pentium Ds */
+	{ 15,  4,  4, 15, -1,   1,    -1,    -1, NC, 0             ,     0, "Pentium D (SmithField)"  },
+	{ 15,  4, -1, 15, -1,   1,    -1,    -1, PENTIUM_D, 0      ,     0, "Pentium D (SmithField)"  },
+	{ 15,  4,  7, 15, -1,   1,    -1,    -1, NC, 0             ,     0, "Pentium D (SmithField)"  },
+	{ 15,  6, -1, 15, -1,   1,    -1,    -1, PENTIUM_D, 0      ,     0, "Pentium D (Presler)"     },
+
+	/* Celeron and Celeron Ds */
+	{ 15,  1, -1, 15, -1,   1,    -1,    -1, NC, CELERON_      ,     0, "P-4 Celeron (Willamette)"   },
+	{ 15,  2, -1, 15, -1,   1,    -1,    -1, NC, CELERON_      ,     0, "P-4 Celeron (Northwood)"    },
+	{ 15,  3, -1, 15, -1,   1,    -1,    -1, NC, CELERON_      ,     0, "P-4 Celeron D (Prescott)"   },
+	{ 15,  4, -1, 15, -1,   1,    -1,    -1, NC, CELERON_      ,     0, "P-4 Celeron D (Prescott)"   },
+	{ 15,  6, -1, 15, -1,   1,    -1,    -1, NC, CELERON_      ,     0, "P-4 Celeron D (Cedar Mill)" },
+	
+	/* -------------------------------------------------- */
+	/* Intel Core microarchitecture - P6-based */
+	
+	{  6,  9, -1, -1, -1,   1,    -1,    -1, NC, 0             ,     0, "Unknown Pentium M"          },
+	{  6,  9, -1, -1, -1,   1,    -1,    -1, PENTIUM_M, 0      ,     0, "Unknown Pentium M"          },
+	{  6,  9, -1, -1, -1,   1,    -1,    -1, NC, PENTIUM_      ,     0, "Pentium M (Banias)"         },
+	{  6,  9, -1, -1, -1,   1,    -1,    -1, PENTIUM_M, 0      ,     0, "Pentium M (Banias)"         },
+	{  6,  9, -1, -1, -1,   1,    -1,    -1, NC, CELERON_      ,     0, "Celeron M"                  },
+	{  6, 13, -1, -1, -1,   1,    -1,    -1, NC, PENTIUM_      ,     0, "Pentium M (Dothan)"         },
+	{  6, 13, -1, -1, -1,   1,    -1,    -1, PENTIUM_M, 0      ,     0, "Pentium M (Dothan)"         },
+	{  6, 13, -1, -1, -1,   1,    -1,    -1, NC, CELERON_      ,     0, "Celeron M"                  },
+	
+	{  6, 12, -1, -1, -1,  -1,    -1,    -1, NC, ATOM_         ,     0, "Unknown Atom"               },
+	{  6, 12, -1, -1, -1,  -1,    -1,    -1, DIAMONDVILLE,ATOM_,     0, "Atom (Diamondville)"        },
+	{  6, 12, -1, -1, -1,  -1,    -1,    -1, SILVERTHORNE,ATOM_,     0, "Atom (Silverthorne)"        },
+	{  6, 12, -1, -1, -1,  -1,    -1,    -1, CEDARVIEW, ATOM_  ,     0, "Atom (Cedarview)"           },
+	{  6,  6, -1, -1, -1,  -1,    -1,    -1, CEDARVIEW, ATOM_  ,     0, "Atom (Cedarview)"           },
+	{  6, 12, -1, -1, -1,  -1,    -1,    -1, PINEVIEW, ATOM_   ,     0, "Atom (Pineview)"            },
+	
+	/* -------------------------------------------------- */
+	
+	{  6, 14, -1, -1, -1,   1,    -1,    -1, NC, 0             ,     0, "Unknown Yonah"             },
+	{  6, 14, -1, -1, -1,   1,    -1,    -1, CORE_SOLO, 0      ,     0, "Yonah (Core Solo)"         },
+	{  6, 14, -1, -1, -1,   2,    -1,    -1, CORE_DUO, 0       ,     0, "Yonah (Core Duo)"          },
+	{  6, 14, -1, -1, -1,   1,    -1,    -1, CORE_SOLO, MOBILE_,     0, "Yonah (Core Solo)"         },
+	{  6, 14, -1, -1, -1,   2,    -1,    -1, CORE_DUO , MOBILE_,     0, "Yonah (Core Duo)"          },
+	{  6, 14, -1, -1, -1,   1,    -1,    -1, CORE_SOLO, 0      ,     0, "Yonah (Core Solo)"         },
+	
+	{  6, 15, -1, -1, -1,   1,    -1,    -1, NC, 0             ,     0, "Unknown Core 2"            },
+	{  6, 15, -1, -1, -1,   2,  4096,    -1, CORE_DUO, 0       ,     0, "Conroe (Core 2 Duo)"       },
+	{  6, 15, -1, -1, -1,   2,  1024,    -1, CORE_DUO, 0       ,     0, "Conroe (Core 2 Duo) 1024K" },
+	{  6, 15, -1, -1, -1,   2,   512,    -1, CORE_DUO, 0       ,     0, "Conroe (Core 2 Duo) 512K"  },
+	{  6, 15, -1, -1, -1,   4,    -1,    -1, QUAD_CORE, 0      ,     0, "Kentsfield (Core 2 Quad)"  },
+	{  6, 15, -1, -1, -1,   4,  4096,    -1, QUAD_CORE, 0      ,     0, "Kentsfield (Core 2 Quad)"  },
+	{  6, 15, -1, -1, -1, 400,    -1,    -1, MORE_THAN_QUADCORE, 0,  0, "More than quad-core"       },
+	{  6, 15, -1, -1, -1,   2,  2048,    -1, CORE_DUO, 0       ,     0, "Allendale (Core 2 Duo)"    },
+	{  6, 15, -1, -1, -1,   2,    -1,    -1, MOBILE_CORE_DUO, 0,     0, "Merom (Core 2 Duo)"        },
+	{  6, 15, -1, -1, -1,   2,  2048,    -1, MEROM, 0          ,     0, "Merom (Core 2 Duo) 2048K"  },
+	{  6, 15, -1, -1, -1,   2,  4096,    -1, MEROM, 0          ,     0, "Merom (Core 2 Duo) 4096K"  },
+	
+	{  6, 15, -1, -1, 15,   1,    -1,    -1, NC, CELERON_      ,     0, "Conroe-L (Celeron)"        },
+	{  6,  6, -1, -1, 22,   1,    -1,    -1, NC, CELERON_      ,     0, "Conroe-L (Celeron)"        },
+	{  6, 15, -1, -1, 15,   2,    -1,    -1, NC, CELERON_      ,     0, "Conroe-L (Allendale)"      },
+	{  6,  6, -1, -1, 22,   2,    -1,    -1, NC, CELERON_      ,     0, "Conroe-L (Allendale)"      },
+	
+	
+	{  6,  6, -1, -1, 22,   1,    -1,    -1, NC, 0             ,     0, "Unknown Core ?"           },
+	{  6,  7, -1, -1, 23,   1,    -1,    -1, NC, 0             ,     0, "Unknown Core ?"           },
+	{  6,  6, -1, -1, 22, 400,    -1,    -1, MORE_THAN_QUADCORE, 0,  0, "More than quad-core"      },
+	{  6,  7, -1, -1, 23, 400,    -1,    -1, MORE_THAN_QUADCORE, 0,  0, "More than quad-core"      },
+	
+	{  6,  7, -1, -1, 23,   1,    -1,    -1, CORE_SOLO         , 0,  0, "Unknown Core 45nm"        },
+	{  6,  7, -1, -1, 23,   1,    -1,    -1, CORE_DUO          , 0,  0, "Unknown Core 45nm"        },
+	{  6,  7, -1, -1, 23,   2,  1024,    -1, WOLFDALE          , 0,  0, "Celeron Wolfdale 1M"      },
+	{  6,  7, -1, -1, 23,   2,  2048,    -1, WOLFDALE          , 0,  0, "Wolfdale (Core 2 Duo) 2M" },
+	{  6,  7, -1, -1, 23,   2,  3072,    -1, WOLFDALE          , 0,  0, "Wolfdale (Core 2 Duo) 3M" },
+	{  6,  7, -1, -1, 23,   2,  6144,    -1, WOLFDALE          , 0,  0, "Wolfdale (Core 2 Duo) 6M" },
+	{  6,  7, -1, -1, 23,   1,    -1,    -1, MOBILE_CORE_DUO   , 0,  0, "Penryn (Core 2 Duo)"      },
+	{  6,  7, -1, -1, 23,   2,  1024,    -1, PENRYN            , 0,  0, "Penryn (Core 2 Duo)"      },
+	{  6,  7, -1, -1, 23,   2,  3072,    -1, PENRYN            , 0,  0, "Penryn (Core 2 Duo) 3M"   },
+	{  6,  7, -1, -1, 23,   2,  6144,    -1, PENRYN            , 0,  0, "Penryn (Core 2 Duo) 6M"   },
+	{  6,  7, -1, -1, 23,   4,  2048,    -1, NC                , 0,  0, "Yorkfield (Core 2 Quad) 2M"},
+	{  6,  7, -1, -1, 23,   4,  3072,    -1, NC                , 0,  0, "Yorkfield (Core 2 Quad) 3M"},
+	{  6,  7, -1, -1, 23,   4,  6144,    -1, NC                , 0,  0, "Yorkfield (Core 2 Quad) 6M"},
+	
+	/* Core microarchitecture-based Xeons: */
+	{  6, 14, -1, -1, 14,   1,    -1,    -1, NC, XEON_         ,     0, "Xeon LV"                  },
+	{  6, 15, -1, -1, 15,   2,  4096,    -1, NC, XEON_         , _5100, "Xeon (Woodcrest)"         },
+	{  6, 15, -1, -1, 15,   2,  2048,    -1, NC, XEON_         , _3000, "Xeon (Conroe/2M)"         },
+	{  6, 15, -1, -1, 15,   2,  4096,    -1, NC, XEON_         , _3000, "Xeon (Conroe/4M)"         },
+	{  6, 15, -1, -1, 15,   4,  4096,    -1, NC, XEON_         , X3200, "Xeon (Kentsfield)"        },
+	{  6, 15, -1, -1, 15,   4,  4096,    -1, NC, XEON_         , _5300, "Xeon (Clovertown)"        },
+	{  6,  7, -1, -1, 23,   2,  6144,    -1, NC, XEON_         , _3100, "Xeon (Wolfdale)"          },
+	{  6,  7, -1, -1, 23,   2,  6144,    -1, NC, XEON_         , _5200, "Xeon (Wolfdale DP)"       },
+	{  6,  7, -1, -1, 23,   4,  6144,    -1, NC, XEON_         , _5400, "Xeon (Harpertown)"        },
+	{  6,  7, -1, -1, 23,   4,  3072,    -1, NC, XEON_         , X3300, "Xeon (Yorkfield/3M)"      },
+	{  6,  7, -1, -1, 23,   4,  6144,    -1, NC, XEON_         , X3300, "Xeon (Yorkfield/6M)"      },
+
+	/* Nehalem CPUs (45nm): */
+	{  6, 10, -1, -1, 26,   4,    -1,    -1, GAINESTOWN, XEON_ ,     0, "Gainestown (Xeon)"        },
+	{  6, 10, -1, -1, 26,   4,    -1,  4096, GAINESTOWN, XEON_ ,     0, "Gainestown 4M (Xeon)"     },
+	{  6, 10, -1, -1, 26,   4,    -1,  8192, GAINESTOWN, XEON_ ,     0, "Gainestown 8M (Xeon)"     },
+	{  6, 10, -1, -1, 26,   4,    -1,    -1, NC, XEON_|_7      ,     0, "Bloomfield (Xeon)"        },
+	{  6, 10, -1, -1, 26,   4,    -1,    -1, NC, CORE_|_I_|_7  ,     0, "Bloomfield (Core i7)"     },
+	{  6, 10, -1, -1, 30,   4,    -1,    -1, NC, CORE_|_I_|_7  ,     0, "Lynnfield (Core i7)"      },
+	{  6,  5, -1, -1, 37,   4,    -1,  8192, NC, CORE_|_I_|_5  ,     0, "Lynnfield (Core i5)"      },
+
+	/* Westmere CPUs (32nm): */
+	{  6,  5, -1, -1, 37,   2,    -1,    -1, NC, 0             ,     0, "Unknown Core i3/i5"       },
+	{  6, 12, -1, -1, 44,  -1,    -1,    -1, WESTMERE, XEON_   ,     0, "Westmere (Xeon)"          },
+	{  6, 12, -1, -1, 44,  -1,    -1, 12288, WESTMERE, XEON_   ,     0, "Gulftown (Xeon)"          },
+	{  6, 12, -1, -1, 44,   4,    -1, 12288, NC, CORE_|_I_|_7  ,     0, "Gulftown (Core i7)"       },
+	{  6,  5, -1, -1, 37,   2,    -1,  4096, NC, CORE_|_I_|_5  ,     0, "Clarkdale (Core i5)"      },
+	{  6,  5, -1, -1, 37,   2,    -1,  4096, NC, CORE_|_I_|_3  ,     0, "Clarkdale (Core i3)"      },
+	{  6,  5, -1, -1, 37,   2,    -1,    -1, NC, PENTIUM_      ,     0, "Arrandale"                },
+	{  6,  5, -1, -1, 37,   2,    -1,  4096, NC, CORE_|_I_|_7  ,     0, "Arrandale (Core i7)"      },
+	{  6,  5, -1, -1, 37,   2,    -1,  3072, NC, CORE_|_I_|_5  ,     0, "Arrandale (Core i5)"      },
+	{  6,  5, -1, -1, 37,   2,    -1,  3072, NC, CORE_|_I_|_3  ,     0, "Arrandale (Core i3)"      },
+
+	/* Sandy Bridge CPUs (32nm): */
+	{  6, 10, -1, -1, 42,  -1,    -1,    -1, NC, 0             ,     0, "Unknown Sandy Bridge"     },
+	{  6, 10, -1, -1, 42,  -1,    -1,    -1, NC, XEON_         ,     0, "Sandy Bridge (Xeon)"      },
+	{  6, 10, -1, -1, 42,  -1,    -1,    -1, NC, CORE_|_I_|_7  ,     0, "Sandy Bridge (Core i7)"   },
+	{  6, 10, -1, -1, 42,   4,    -1,    -1, NC, CORE_|_I_|_7  ,     0, "Sandy Bridge (Core i7)"   },
+	{  6, 10, -1, -1, 42,   4,    -1,    -1, NC, CORE_|_I_|_5  ,     0, "Sandy Bridge (Core i5)"   },
+	{  6, 10, -1, -1, 42,   2,    -1,    -1, NC, CORE_|_I_|_3  ,     0, "Sandy Bridge (Core i3)"   },
+	{  6, 10, -1, -1, 42,   2,    -1,    -1, NC, PENTIUM_      ,     0, "Sandy Bridge (Pentium)"   },
+	{  6, 10, -1, -1, 42,   1,    -1,    -1, NC, CELERON_      ,     0, "Sandy Bridge (Celeron)"   },
+	{  6, 10, -1, -1, 42,   2,    -1,    -1, NC, CELERON_      ,     0, "Sandy Bridge (Celeron)"   },
+	{  6, 13, -1, -1, 45,  -1,    -1,    -1, NC, CORE_|_I_|_3  ,     0, "Sandy Bridge-E"           },
+	{  6, 13, -1, -1, 45,  -1,    -1,    -1, NC, XEON_         ,     0, "Sandy Bridge-E (Xeon)"    },
+
+	/* Ivy Bridge CPUs (22nm): */
+	{  6, 10, -1, -1, 58,  -1,    -1,    -1, NC, XEON_         ,     0, "Ivy Bridge (Xeon)"        },
+	{  6, 10, -1, -1, 58,   4,    -1,    -1, NC, CORE_|_I_|_7  ,     0, "Ivy Bridge (Core i7)"     },
+	{  6, 10, -1, -1, 58,   4,    -1,    -1, NC, CORE_|_I_|_5  ,     0, "Ivy Bridge (Core i5)"     },
+	{  6, 10, -1, -1, 58,   2,    -1,    -1, NC, CORE_|_I_|_3  ,     0, "Ivy Bridge (Core i3)"     },
+	{  6, 10, -1, -1, 58,   2,    -1,    -1, NC, PENTIUM_      ,     0, "Ivy Bridge (Pentium)"     },
+	{  6, 10, -1, -1, 58,   1,    -1,    -1, NC, CELERON_      ,     0, "Ivy Bridge (Celeron)"     },
+	{  6, 10, -1, -1, 58,   2,    -1,    -1, NC, CELERON_      ,     0, "Ivy Bridge (Celeron)"     },
+	{  6, 14, -1, -1, 62,  -1,    -1,    -1, NC, 0             ,     0, "Ivy Bridge-E"             },
+	
+	/* Haswell CPUs (22nm): */
+	{  6, 12, -1, -1, 60,  -1,    -1,    -1, NC, XEON_         ,     0, "Haswell (Xeon)"           },
+	{  6, 12, -1, -1, 60,   4,    -1,    -1, NC, CORE_|_I_|_7  ,     0, "Haswell (Core i7)"        },
+	{  6,  5, -1, -1, 69,   4,    -1,    -1, NC, CORE_|_I_|_7  ,     0, "Haswell (Core i7)"        },
+	{  6,  6, -1, -1, 70,   4,    -1,    -1, NC, CORE_|_I_|_7  ,     0, "Haswell (Core i7)"        },
+	{  6, 12, -1, -1, 60,   4,    -1,    -1, NC, CORE_|_I_|_5  ,     0, "Haswell (Core i5)"        },
+	{  6,  5, -1, -1, 69,   4,    -1,    -1, NC, CORE_|_I_|_5  ,     0, "Haswell (Core i5)"        },
+	{  6, 12, -1, -1, 60,   2,    -1,    -1, NC, CORE_|_I_|_5  ,     0, "Haswell (Core i5)"        },
+	{  6,  5, -1, -1, 69,   2,    -1,    -1, NC, CORE_|_I_|_5  ,     0, "Haswell (Core i5)"        },
+	{  6, 12, -1, -1, 60,   2,    -1,    -1, NC, CORE_|_I_|_3  ,     0, "Haswell (Core i3)"        },
+	{  6,  5, -1, -1, 69,   2,    -1,    -1, NC, CORE_|_I_|_3  ,     0, "Haswell (Core i3)"        },
+	{  6, 12, -1, -1, 60,   2,    -1,    -1, NC, PENTIUM_      ,     0, "Haswell (Pentium)"        },
+	{  6, 12, -1, -1, 60,   2,    -1,    -1, NC, CELERON_      ,     0, "Haswell (Celeron)"        },
+	{  6, 12, -1, -1, 60,   1,    -1,    -1, NC, CELERON_      ,     0, "Haswell (Celeron)"        },
+	{  6, 15, -1, -1, 63,  -1,    -1,    -1, NC, 0             ,     0, "Haswell-E"                },
+
+	/* Broadwell CPUs (14nm): */
+	{  6,  7, -1, -1, 71,   4,    -1,    -1, NC, CORE_|_I_|_7  ,     0, "Broadwell (Core i7)"      },
+	{  6,  7, -1, -1, 71,   4,    -1,    -1, NC, CORE_|_I_|_5  ,     0, "Broadwell (Core i5)"      },
+	{  6, 13, -1, -1, 61,   4,    -1,    -1, NC, CORE_|_I_|_7  ,     0, "Broadwell-U (Core i7)"    },
+	{  6, 13, -1, -1, 61,   2,    -1,    -1, NC, CORE_|_I_|_7  ,     0, "Broadwell-U (Core i7)"    },
+	{  6, 13, -1, -1, 61,   2,    -1,    -1, NC, CORE_|_I_|_5  ,     0, "Broadwell-U (Core i5)"    },
+	{  6, 13, -1, -1, 61,   2,    -1,    -1, NC, CORE_|_I_|_3  ,     0, "Broadwell-U (Core i3)"    },
+	{  6, 13, -1, -1, 61,   2,    -1,    -1, NC, PENTIUM_      ,     0, "Broadwell-U (Pentium)"    },
+	{  6, 13, -1, -1, 61,   2,    -1,    -1, NC, CELERON_      ,     0, "Broadwell-U (Celeron)"    },
+	{  6, 13, -1, -1, 61,   2,    -1,    -1, NA, 0             ,     0, "Broadwell-U (Core M)"     },
+	{  6, 15, -1, -1, 79,  -1,    -1,    -1, NC, XEON_         ,     0, "Broadwell-E (Xeon)"       },
+	{  6, 15, -1, -1, 79,   2,    -1,    -1, NC, CORE_|_I_|_3  ,     0, "Broadwell-E (Core i3)"    },
+	{  6, 15, -1, -1, 79,   2,    -1,    -1, NC, CORE_|_I_|_5  ,     0, "Broadwell-E (Core i5)"    },
+	{  6, 15, -1, -1, 79,   4,    -1,    -1, NC, CORE_|_I_|_5  ,     0, "Broadwell-E (Core i5)"    },
+	{  6, 15, -1, -1, 79,   2,    -1,    -1, NC, CORE_|_I_|_7  ,     0, "Broadwell-E (Core i7)"    },
+	{  6, 15, -1, -1, 79,   4,    -1,    -1, NC, CORE_|_I_|_7  ,     0, "Broadwell-E (Core i7)"    },
+
+	/* Skylake CPUs (14nm): */
+	{  6, 14, -1, -1, 94,  -1,    -1,    -1, NC, XEON_         ,     0, "Skylake (Xeon)"           },
+	{  6, 14, -1, -1, 94,   4,    -1,    -1, NC, CORE_|_I_|_7  ,     0, "Skylake (Core i7)"        },
+	{  6, 14, -1, -1, 94,   4,    -1,    -1, NC, CORE_|_I_|_5  ,     0, "Skylake (Core i5)"        },
+	{  6, 14, -1, -1, 94,   2,    -1,    -1, NC, CORE_|_I_|_3  ,     0, "Skylake (Core i3)"        },
+	{  6, 14, -1, -1, 94,   2,    -1,    -1, NC, PENTIUM_      ,     0, "Skylake (Pentium)"        },
+	{  6, 14, -1, -1, 78,   2,    -1,    -1, NC, PENTIUM_      ,     0, "Skylake (Pentium)"        },
+	{  6, 14, -1, -1, 94,   2,    -1,    -1, NC, CELERON_      ,     0, "Skylake (Celeron)"        },
+	{  6, 14, -1, -1, 78,   2,    -1,    -1, NC, CELERON_      ,     0, "Skylake (Celeron)"        },
+	{  6, 14, -1, -1, 78,   2,    -1,    -1, NC, CORE_|_M_|_7  ,     0, "Skylake (Core m7)"        },
+	{  6, 14, -1, -1, 78,   2,    -1,    -1, NC, CORE_|_M_|_5  ,     0, "Skylake (Core m5)"        },
+	{  6, 14, -1, -1, 78,   2,    -1,    -1, NC, CORE_|_M_|_3  ,     0, "Skylake (Core m3)"        },
+	{  6,  5, -1, -1, 85,   8,    -1,    -1, NC, XEON_,              0, "Skylake (Xeon Scalable)"  },
+
+	/* Kaby Lake CPUs (14nm): */
+	{  6, 14, -1, -1, 158,  4,    -1,    -1, NC, CORE_|_I_|_7  ,     0, "Kaby Lake (Core i7)"      },
+	{  6, 14, -1, -1, 158,  4,    -1,    -1, NC, CORE_|_I_|_5  ,     0, "Kaby Lake (Core i5)"      },
+	{  6, 14, -1, -1, 158,  2,    -1,    -1, NC, CORE_|_I_|_3  ,     0, "Kaby Lake (Core i3)"      },
+	{  6, 14, -1, -1, 158,  2,    -1,    -1, NC, PENTIUM_      ,     0, "Kaby Lake (Pentium)"      },
+	{  6, 14, -1, -1, 158,  2,    -1,    -1, NC, CELERON_      ,     0, "Kaby Lake (Celeron)"      },
+	{  6, 14, -1, -1, 158,  2,    -1,    -1, NC, CORE_|_M_|_3  ,     0, "Kaby Lake (Core m3)"      },
+
+	/* Itaniums */
+	{  7, -1, -1, -1, -1,   1,    -1,    -1, NC, 0             ,     0, "Itanium"                  },
+	{ 15, -1, -1, 16, -1,   1,    -1,    -1, NC, 0             ,     0, "Itanium 2"                },
+};
+
+
+static void load_intel_features(struct cpu_raw_data_t* raw, struct cpu_id_t* data)
+{
+	const struct feature_map_t matchtable_edx1[] = {
+		{ 18, CPU_FEATURE_PN },
+		{ 21, CPU_FEATURE_DTS },
+		{ 22, CPU_FEATURE_ACPI },
+		{ 27, CPU_FEATURE_SS },
+		{ 29, CPU_FEATURE_TM },
+		{ 30, CPU_FEATURE_IA64 },
+		{ 31, CPU_FEATURE_PBE },
+	};
+	const struct feature_map_t matchtable_ecx1[] = {
+		{  2, CPU_FEATURE_DTS64 },
+		{  4, CPU_FEATURE_DS_CPL },
+		{  5, CPU_FEATURE_VMX },
+		{  6, CPU_FEATURE_SMX },
+		{  7, CPU_FEATURE_EST },
+		{  8, CPU_FEATURE_TM2 },
+		{ 10, CPU_FEATURE_CID },
+		{ 14, CPU_FEATURE_XTPR },
+		{ 15, CPU_FEATURE_PDCM },
+		{ 18, CPU_FEATURE_DCA },
+		{ 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->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,
+	L4
+};
+typedef enum _cache_type_t cache_type_t;
+
+static void check_case(uint8_t on, cache_type_t cache, int size, int assoc, int linesize, struct cpu_id_t* data)
+{
+	if (!on) return;
+	switch (cache) {
+		case L1I:
+			data->l1_instruction_cache = size;
+			break;
+		case L1D:
+			data->l1_data_cache = size;
+			data->l1_assoc = assoc;
+			data->l1_cacheline = linesize;
+			break;
+		case L2:
+			data->l2_cache = size;
+			data->l2_assoc = assoc;
+			data->l2_cacheline = linesize;
+			break;
+		case L3:
+			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;
+	}
+}
+
+static void decode_intel_oldstyle_cache_info(struct cpu_raw_data_t* raw, struct cpu_id_t* data)
+{
+	uint8_t f[256] = {0};
+	int reg, off;
+	uint32_t x;
+	for (reg = 0; reg < 4; reg++) {
+		x = raw->basic_cpuid[2][reg];
+		if (x & 0x80000000) continue;
+		for (off = 0; off < 4; off++) {
+			f[x & 0xff] = 1;
+			x >>= 8;
+		}
+	}
+	
+	check_case(f[0x06], L1I,      8,  4,  32, data);
+	check_case(f[0x08], L1I,     16,  4,  32, data);
+	check_case(f[0x0A], L1D,      8,  2,  32, data);
+	check_case(f[0x0C], L1D,     16,  4,  32, data);
+	check_case(f[0x22],  L3,    512,  4,  64, data);
+	check_case(f[0x23],  L3,   1024,  8,  64, data);
+	check_case(f[0x25],  L3,   2048,  8,  64, data);
+	check_case(f[0x29],  L3,   4096,  8,  64, data);
+	check_case(f[0x2C], L1D,     32,  8,  64, data);
+	check_case(f[0x30], L1I,     32,  8,  64, data);
+	check_case(f[0x39],  L2,    128,  4,  64, data);
+	check_case(f[0x3A],  L2,    192,  6,  64, data);
+	check_case(f[0x3B],  L2,    128,  2,  64, data);
+	check_case(f[0x3C],  L2,    256,  4,  64, data);
+	check_case(f[0x3D],  L2,    384,  6,  64, data);
+	check_case(f[0x3E],  L2,    512,  4,  64, data);
+	check_case(f[0x41],  L2,    128,  4,  32, data);
+	check_case(f[0x42],  L2,    256,  4,  32, data);
+	check_case(f[0x43],  L2,    512,  4,  32, data);
+	check_case(f[0x44],  L2,   1024,  4,  32, data);
+	check_case(f[0x45],  L2,   2048,  4,  32, data);
+	check_case(f[0x46],  L3,   4096,  4,  64, data);
+	check_case(f[0x47],  L3,   8192,  8,  64, data);
+	check_case(f[0x4A],  L3,   6144, 12,  64, data);
+	check_case(f[0x4B],  L3,   8192, 16,  64, data);
+	check_case(f[0x4C],  L3,  12288, 12,  64, data);
+	check_case(f[0x4D],  L3,  16384, 16,  64, data);
+	check_case(f[0x4E],  L2,   6144, 24,  64, data);
+	check_case(f[0x60], L1D,     16,  8,  64, data);
+	check_case(f[0x66], L1D,      8,  4,  64, data);
+	check_case(f[0x67], L1D,     16,  4,  64, data);
+	check_case(f[0x68], L1D,     32,  4,  64, data);
+	/* The following four entries are trace cache. Intel does not
+	 * specify a cache-line size, so we use -1 instead
+	 */
+	check_case(f[0x70], L1I,     12,  8,  -1, data);
+	check_case(f[0x71], L1I,     16,  8,  -1, data);
+	check_case(f[0x72], L1I,     32,  8,  -1, data);
+	check_case(f[0x73], L1I,     64,  8,  -1, data);
+	
+	check_case(f[0x78],  L2,   1024,  4,  64, data);
+	check_case(f[0x79],  L2,    128,  8,  64, data);
+	check_case(f[0x7A],  L2,    256,  8,  64, data);
+	check_case(f[0x7B],  L2,    512,  8,  64, data);
+	check_case(f[0x7C],  L2,   1024,  8,  64, data);
+	check_case(f[0x7D],  L2,   2048,  8,  64, data);
+	check_case(f[0x7F],  L2,    512,  2,  64, data);
+	check_case(f[0x82],  L2,    256,  8,  32, data);
+	check_case(f[0x83],  L2,    512,  8,  32, data);
+	check_case(f[0x84],  L2,   1024,  8,  32, data);
+	check_case(f[0x85],  L2,   2048,  8,  32, data);
+	check_case(f[0x86],  L2,    512,  4,  64, data);
+	check_case(f[0x87],  L2,   1024,  8,  64, data);
+	
+	if (f[0x49]) {
+		/* This flag is overloaded with two meanings. On Xeon MP
+		 * (family 0xf, model 0x6) this means L3 cache. On all other
+		 * CPUs (notably Conroe et al), this is L2 cache. In both cases
+		 * it means 4MB, 16-way associative, 64-byte line size.
+		 */
+		if (data->family == 0xf && data->model == 0x6) {
+			data->l3_cache = 4096;
+			data->l3_assoc = 16;
+			data->l3_cacheline = 64;
+		} else {
+			data->l2_cache = 4096;
+			data->l2_assoc = 16;
+			data->l2_cacheline = 64;
+		}
+	}
+	if (f[0x40]) {
+		/* Again, a special flag. It means:
+		 * 1) If no L2 is specified, then CPU is w/o L2 (0 KB)
+		 * 2) If L2 is specified by other flags, then, CPU is w/o L3.
+		 */
+		if (data->l2_cache == -1) {
+			data->l2_cache = 0;
+		} else {
+			data->l3_cache = 0;
+		}
+	}
+}
+
+static void decode_intel_deterministic_cache_info(struct cpu_raw_data_t* raw,
+                                                  struct cpu_id_t* data)
+{
+	int ecx;
+	int ways, partitions, linesize, sets, size, level, typenumber;
+	cache_type_t type;
+	for (ecx = 0; ecx < MAX_INTELFN4_LEVEL; ecx++) {
+		typenumber = raw->intel_fn4[ecx][0] & 0x1f;
+		if (typenumber == 0) break;
+		level = (raw->intel_fn4[ecx][0] >> 5) & 0x7;
+		if (level == 1 && typenumber == 1)
+			type = L1D;
+		else if (level == 1 && typenumber == 2)
+			type = L1I;
+		else if (level == 2 && typenumber == 3)
+			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");
+			continue;
+		}
+		ways = ((raw->intel_fn4[ecx][1] >> 22) & 0x3ff) + 1;
+		partitions = ((raw->intel_fn4[ecx][1] >> 12) & 0x3ff) + 1;
+		linesize = (raw->intel_fn4[ecx][1] & 0xfff) + 1;
+		sets = raw->intel_fn4[ecx][2] + 1;
+		size = ways * partitions * linesize * sets / 1024;
+		check_case(1, type, size, ways, linesize, data);
+	}
+}
+
+static int decode_intel_extended_topology(struct cpu_raw_data_t* raw,
+                                           struct cpu_id_t* data)
+{
+	int i, level_type, num_smt = -1, num_core = -1;
+	for (i = 0; i < MAX_INTELFN11_LEVEL; i++) {
+		level_type = (raw->intel_fn11[i][2] & 0xff00) >> 8;
+		switch (level_type) {
+			case 0x01:
+				num_smt = raw->intel_fn11[i][1] & 0xffff;
+				break;
+			case 0x02:
+				num_core = raw->intel_fn11[i][1] & 0xffff;
+				break;
+			default:
+				break;
+		}
+	}
+	if (num_smt == -1 || num_core == -1) return 0;
+	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;
+}
+
+static void decode_intel_number_of_cores(struct cpu_raw_data_t* raw,
+                                         struct cpu_id_t* data)
+{
+	int logical_cpus = -1, num_cores = -1;
+	
+	if (raw->basic_cpuid[0][0] >= 11) {
+		if (decode_intel_extended_topology(raw, data)) return;
+	}
+	
+	if (raw->basic_cpuid[0][0] >= 1) {
+		logical_cpus = (raw->basic_cpuid[1][1] >> 16) & 0xff;
+		if (raw->basic_cpuid[0][0] >= 4) {
+			num_cores = 1 + ((raw->basic_cpuid[4][0] >> 26) & 0x3f);
+		}
+	}
+	if (data->flags[CPU_FEATURE_HT]) {
+		if (num_cores > 1) {
+			data->num_cores = num_cores;
+			data->num_logical_cpus = logical_cpus;
+		} else {
+			data->num_cores = 1;
+			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;
+	}
+}
+
+static intel_code_and_bits_t get_brand_code_and_bits(struct cpu_id_t* data)
+{
+	intel_code_t code = (intel_code_t) NC;
+	intel_code_and_bits_t result;
+	uint64_t bits = 0;
+	int i = 0;
+	const char* bs = data->brand_str;
+	const char* s;
+	const struct { intel_code_t c; const char *search; } matchtable[] = {
+		{ PENTIUM_M, "Pentium(R) M" },
+		{ CORE_SOLO, "Pentium(R) Dual  CPU" },
+		{ CORE_SOLO, "Pentium(R) Dual-Core" },
+		{ PENTIUM_D, "Pentium(R) D" },
+		{ CORE_SOLO, "Genuine Intel(R) CPU" },
+		{ CORE_SOLO, "Intel(R) Core(TM)" },
+		{ DIAMONDVILLE, "CPU [N ][23]## " },
+		{ SILVERTHORNE, "CPU Z" },
+		{ PINEVIEW, "CPU [ND][45]## " },
+		{ CEDARVIEW, "CPU [ND]#### " },
+	};
+	
+	const struct { uint64_t bit; const char* search; } bit_matchtable[] = {
+		{ XEON_, "Xeon" },
+		{ _MP_, " MP" },
+		{ ATOM_, "Atom(TM) CPU" },
+		{ MOBILE_, "Mobile" },
+		{ CELERON_, "Celeron" },
+		{ PENTIUM_, "Pentium" },
+	};
+	
+	for (i = 0; i < COUNT_OF(bit_matchtable); i++) {
+		if (match_pattern(bs, bit_matchtable[i].search))
+			bits |= bit_matchtable[i].bit;
+	}
+	
+	if ((i = match_pattern(bs, "Core(TM) [im][357]")) != 0) {
+		bits |= CORE_;
+		i--;
+		switch (bs[i + 9]) {
+			case 'i': bits |= _I_; break;
+			case 'm': bits |= _M_; break;
+		}
+		switch (bs[i + 10]) {
+			case '3': bits |= _3; break;
+			case '5': bits |= _5; break;
+			case '7': bits |= _7; break;
+		}
+	}
+	for (i = 0; i < COUNT_OF(matchtable); i++)
+		if (match_pattern(bs, matchtable[i].search)) {
+			code = matchtable[i].c;
+			break;
+		}
+	debugf(2, "intel matchtable result is %d\n", code);
+	if (bits & XEON_) {
+		if (match_pattern(bs, "W35##") || match_pattern(bs, "[ELXW]75##"))
+			bits |= _7;
+		else if (match_pattern(bs, "[ELXW]55##"))
+			code = GAINESTOWN;
+		else if (match_pattern(bs, "[ELXW]56##"))
+			code = WESTMERE;
+		else if (data->l3_cache > 0 && data->family == 16)
+			/* restrict by family, since later Xeons also have L3 ... */
+			code = IRWIN;
+	}
+	if (match_all(bits, XEON_ + _MP_) && data->l3_cache > 0)
+		code = POTOMAC;
+	if (code == CORE_SOLO) {
+		s = strstr(bs, "CPU");
+		if (s) {
+			s += 3;
+			while (*s == ' ') s++;
+			if (*s == 'T')
+				bits |= MOBILE_;
+		}
+	}
+	if (code == CORE_SOLO) {
+		switch (data->num_cores) {
+			case 1: break;
+			case 2:
+			{
+				code = CORE_DUO;
+				if (data->num_logical_cpus > 2)
+					code = DUAL_CORE_HT;
+				break;
+			}
+			case 4:
+			{
+				code = QUAD_CORE;
+				if (data->num_logical_cpus > 4)
+					code = QUAD_CORE_HT;
+				break;
+			}
+			default:
+				code = MORE_THAN_QUADCORE; break;
+		}
+	}
+	
+	if (code == CORE_DUO && (bits & MOBILE_) && data->model != 14) {
+		if (data->ext_model < 23) {
+			code = MEROM;
+		} else {
+			code = PENRYN;
+		}
+	}
+	if (data->ext_model == 23 &&
+		(code == CORE_DUO || code == PENTIUM_D || (bits & CELERON_))) {
+		code = WOLFDALE;
+	}
+
+	result.code = code;
+	result.bits = bits;
+	return result;
+}
+
+static intel_model_t get_model_code(struct cpu_id_t* data)
+{
+	int i = 0;
+	int l = (int) strlen(data->brand_str);
+	const char *bs = data->brand_str;
+	int mod_flags = 0, model_no = 0, ndigs = 0;
+	/* If the CPU is a Core ix, then just return the model number generation: */
+	if ((i = match_pattern(bs, "Core(TM) i[357]")) != 0) {
+		i += 11;
+		if (i + 4 >= l) return UNKNOWN;
+		if (bs[i] == '2') return _2xxx;
+		if (bs[i] == '3') return _3xxx;
+		return UNKNOWN;
+	}
+	
+	/* For Core2-based Xeons: */
+	while (i < l - 3) {
+		if (bs[i] == 'C' && bs[i+1] == 'P' && bs[i+2] == 'U')
+			break;
+		i++;
+	}
+	if (i >= l - 3) return UNKNOWN;
+	i += 3;
+	while (i < l - 4 && bs[i] == ' ') i++;
+	if (i >= l - 4) return UNKNOWN;
+	while (i < l - 4 && !isdigit(bs[i])) {
+		if (bs[i] >= 'A' && bs[i] <= 'Z')
+			mod_flags |= (1 << (bs[i] - 'A'));
+		i++;
+	}
+	if (i >= l - 4) return UNKNOWN;
+	while (isdigit(bs[i])) {
+		ndigs++;
+		model_no = model_no * 10 + (int) (bs[i] - '0');
+		i++;
+	}
+	if (ndigs != 4) return UNKNOWN;
+#define HAVE(ch, flags) ((flags & (1 << ((int)(ch-'A')))) != 0)
+	switch (model_no / 100) {
+		case 30: return _3000;
+		case 31: return _3100;
+		case 32:
+		{
+			return (HAVE('X', mod_flags)) ? X3200 : _3200;
+		}
+		case 33:
+		{
+			return (HAVE('X', mod_flags)) ? X3300 : _3300;
+		}
+		case 51: return _5100;
+		case 52: return _5200;
+		case 53: return _5300;
+		case 54: return _5400;
+		default:
+			return UNKNOWN;
+	}
+#undef HAVE
+}
+
+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_and_bits_t brand;
+	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 */
+		decode_intel_deterministic_cache_info(raw, data);
+	} else if (raw->basic_cpuid[0][0] >= 2) {
+		decode_intel_oldstyle_cache_info(raw, data);
+	}
+	decode_intel_number_of_cores(raw, data);
+
+	brand = get_brand_code_and_bits(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);
+	if (brand.bits) {
+		debugf(2, "Detected Intel bits: ");
+		debug_print_lbits(2, brand.bits);
+	}
+	debugf(2, "Detected Intel model code: %d\n", model_code);
+	
+	internal->code.intel = brand.code;
+	internal->bits = brand.bits;
+	
+	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, brand.bits, model_code);
+	return 0;
+}
+
+void cpuid_get_list_intel(struct cpu_list_t* list)
+{
+	generic_get_cpu_list(cpudb_intel, COUNT_OF(cpudb_intel), list);
+}

+ 32 - 0
Source/ThirdParty/LibCpuId/src/recog_intel.h

@@ -0,0 +1,32 @@
+/*
+ * Copyright 2008  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 __RECOG_INTEL_H__
+#define __RECOG_INTEL_H__
+
+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__*/