![support@xmrig.com](/assets/img/avatar_default.png)
26 changed files with 13 additions and 3886 deletions
@ -1,38 +0,0 @@ |
|||
cmake_minimum_required (VERSION 2.8) |
|||
project (cpuid C) |
|||
|
|||
add_definitions(/DVERSION="0.4.0") |
|||
|
|||
set(CMAKE_C_FLAGS_RELEASE "${CMAKE_C_FLAGS_RELEASE} -Os") |
|||
|
|||
set(HEADERS |
|||
libcpuid.h |
|||
libcpuid_types.h |
|||
libcpuid_constants.h |
|||
libcpuid_internal.h |
|||
amd_code_t.h |
|||
intel_code_t.h |
|||
recog_amd.h |
|||
recog_intel.h |
|||
asm-bits.h |
|||
libcpuid_util.h |
|||
) |
|||
|
|||
set(SOURCES |
|||
cpuid_main.c |
|||
asm-bits.c |
|||
recog_amd.c |
|||
recog_intel.c |
|||
libcpuid_util.c |
|||
) |
|||
|
|||
if (CMAKE_CL_64) |
|||
enable_language(ASM_MASM) |
|||
set(SOURCES_ASM masm-x64.asm) |
|||
endif() |
|||
|
|||
add_library(cpuid STATIC |
|||
${HEADERS} |
|||
${SOURCES} |
|||
${SOURCES_ASM} |
|||
) |
@ -1,39 +0,0 @@ |
|||
/*
|
|||
* 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), |
|||
|
@ -1,836 +0,0 @@ |
|||
/*
|
|||
* 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) || defined(COMPILER_CLANG) |
|||
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 */ |
|||
#elif defined(PLATFORM_ARM) |
|||
return 0; |
|||
#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) |
|||
{ |
|||
# if defined(COMPILER_GCC) || defined(COMPILER_CLANG) |
|||
# 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" |
|||
); |
|||
# elif defined(PLATFORM_X86) |
|||
__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" |
|||
); |
|||
# elif defined(PLATFORM_ARM) |
|||
# 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; |
|||
#if defined(COMPILER_GCC) || defined(COMPILER_CLANG) |
|||
#ifdef PLATFORM_ARM |
|||
low_part = 0; |
|||
hi_part = 0; |
|||
#else |
|||
__asm __volatile ( |
|||
" rdtsc\n" |
|||
" mov %%eax, %0\n" |
|||
" mov %%edx, %1\n" |
|||
:"=m"(low_part), "=m"(hi_part)::"memory", "eax", "edx" |
|||
); |
|||
#endif |
|||
#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) |
|||
{ |
|||
# if defined(COMPILER_GCC) || defined(COMPILER_CLANG) |
|||
#ifndef __APPLE__ |
|||
# define XALIGN ".balign 16\n" |
|||
#else |
|||
# define XALIGN ".align 4\n" |
|||
#endif |
|||
#ifdef PLATFORM_ARM |
|||
#else |
|||
__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) |
|||
); |
|||
#endif |
|||
#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 */ |
@ -1,71 +0,0 @@ |
|||
/*
|
|||
* 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) |
|||
#if !defined(COMPILER_MICROSOFT) |
|||
# define COMPILER_MICROSOFT |
|||
#endif |
|||
#elif defined(__GNUC__) |
|||
#if !defined(COMPILER_GCC) |
|||
# define COMPILER_GCC |
|||
#endif |
|||
#elif defined(__clang__) |
|||
#if !defined(COMPILER_CLANG) |
|||
# define COMPILER_CLANG |
|||
#endif |
|||
#endif |
|||
|
|||
/* Determine Platform */ |
|||
#if defined(__x86_64__) || defined(_M_AMD64) |
|||
#if !defined(PLATFORM_X64) |
|||
# define PLATFORM_X64 |
|||
#endif |
|||
#elif defined(__i386__) || defined(_M_IX86) |
|||
#if !defined(PLATFORM_X86) |
|||
# define PLATFORM_X86 |
|||
#endif |
|||
#elif defined(__ARMEL__) |
|||
#if !defined(PLATFORM_ARM) |
|||
# define PLATFORM_ARM |
|||
#endif |
|||
#endif |
|||
|
|||
/* Under Windows/AMD64 with MSVC, inline assembly isn't supported */ |
|||
#if (((defined(COMPILER_GCC) || defined(COMPILER_CLANG))) && \ |
|||
(defined(PLATFORM_X64) || defined(PLATFORM_X86) || defined(PLATFORM_ARM))) || \ |
|||
(defined(COMPILER_MICROSOFT) && 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__ */ |
@ -1,389 +0,0 @@ |
|||
/*
|
|||
* 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 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; |
|||
} |
|||
|
|||
/* 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); |
|||
} |
|||
|
|||
/* 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 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* cpuid_lib_version(void) |
|||
{ |
|||
return VERSION; |
|||
} |
@ -1,58 +0,0 @@ |
|||
/*
|
|||
* 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), |
@ -1,678 +0,0 @@ |
|||
/*
|
|||
* 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
|
|||
* @brief LibCPUID provides CPU identification |
|||
@{ */ |
|||
|
|||
/* 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 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 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); |
|||
|
|||
#ifdef __cplusplus |
|||
} /* extern "C" */ |
|||
#endif |
|||
|
|||
|
|||
/** @} */ |
|||
|
|||
#endif /* __LIBCPUID_H__ */ |
@ -1,47 +0,0 @@ |
|||
/*
|
|||
* 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__ */ |
@ -1,107 +0,0 @@ |
|||
/*
|
|||
* 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 ), |
|||
_9 = LBIT( 17 ), |
|||
XEON_ = LBIT( 18 ), |
|||
ATOM_ = LBIT( 19 ), |
|||
}; |
|||
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__ */ |
@ -1,63 +0,0 @@ |
|||
/*
|
|||
* 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__ |
|||
|
|||
#if !defined(_MSC_VER) || _MSC_VER >= 1600 |
|||
# include <stdint.h> |
|||
#else |
|||
/* we have to provide our own: */ |
|||
# if !defined(__int32_t_defined) |
|||
typedef int int32_t; |
|||
# endif |
|||
|
|||
# if !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__ */ |
@ -1,93 +0,0 @@ |
|||
/*
|
|||
* 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" |
|||
|
|||
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 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; |
|||
} |
@ -1,78 +0,0 @@ |
|||
/*
|
|||
* 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); |
|||
/*
|
|||
* 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); |
|||
|
|||
/*
|
|||
* Sets the current errno |
|||
*/ |
|||
int set_error(cpu_error_t err); |
|||
|
|||
#endif /* __LIBCPUID_UTIL_H__ */ |
@ -1,359 +0,0 @@ |
|||
|
|||
.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 |
@ -1,173 +0,0 @@ |
|||
/*
|
|||
* 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, |
|||
_1900, |
|||
_2400, |
|||
_2500, |
|||
_2700, |
|||
}; |
|||
|
|||
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; |
|||
} |
|||
} |
|||
|
|||
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); |
|||
return 0; |
|||
} |
@ -1,31 +0,0 @@ |
|||
/*
|
|||
* 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); |
|||
|
|||
#endif /* __RECOG_AMD_H__ */ |
@ -1,543 +0,0 @@ |
|||
/*
|
|||
* 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; |
|||
|
|||
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 { |
|||
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][3579]")) != 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; |
|||
case '9': bits |= _9; break; |
|||
} |
|||
} |
|||
for (i = 0; i < COUNT_OF(matchtable); i++) |
|||
if (match_pattern(bs, matchtable[i].search)) { |
|||
code = matchtable[i].c; |
|||
break; |
|||
} |
|||
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 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) { |
|||
data->sgx.num_epc_sections = i; |
|||
break; |
|||
} |
|||
} |
|||
if (data->sgx.num_epc_sections == -1) { |
|||
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; |
|||
|
|||
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); |
|||
|
|||
internal->code.intel = brand.code; |
|||
internal->bits = brand.bits; |
|||
|
|||
if (data->flags[CPU_FEATURE_SGX]) { |
|||
// if SGX is indicated by the CPU, verify its presence:
|
|||
decode_intel_sgx_features(raw, data); |
|||
} |
|||
|
|||
return 0; |
|||
} |
@ -1,31 +0,0 @@ |
|||
/*
|
|||
* 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); |
|||
|
|||
#endif /*__RECOG_INTEL_H__*/ |
@ -1,130 +0,0 @@ |
|||
/* XMRig
|
|||
* Copyright 2010 Jeff Garzik <jgarzik@pobox.com> |
|||
* Copyright 2012-2014 pooler <pooler@litecoinpool.org> |
|||
* Copyright 2014 Lucas Jones <https://github.com/lucasjones>
|
|||
* Copyright 2014-2016 Wolf9466 <https://github.com/OhGodAPet>
|
|||
* Copyright 2016 Jay D Dee <jayddee246@gmail.com> |
|||
* Copyright 2017-2019 XMR-Stak <https://github.com/fireice-uk>, <https://github.com/psychocrypt>
|
|||
* Copyright 2018-2020 SChernykh <https://github.com/SChernykh>
|
|||
* Copyright 2016-2020 XMRig <support@xmrig.com> |
|||
* |
|||
* This program is free software: you can redistribute it and/or modify |
|||
* it under the terms of the GNU General Public License as published by |
|||
* the Free Software Foundation, either version 3 of the License, or |
|||
* (at your option) any later version. |
|||
* |
|||
* This program is distributed in the hope that it will be useful, |
|||
* but WITHOUT ANY WARRANTY; without even the implied warranty of |
|||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the |
|||
* GNU General Public License for more details. |
|||
* |
|||
* You should have received a copy of the GNU General Public License |
|||
* along with this program. If not, see <http://www.gnu.org/licenses/>.
|
|||
*/ |
|||
|
|||
#include "backend/cpu/platform/AdvancedCpuInfo.h" |
|||
#include "3rdparty/libcpuid/libcpuid.h" |
|||
|
|||
|
|||
#include <algorithm> |
|||
#include <cassert> |
|||
#include <cmath> |
|||
#include <cstdio> |
|||
#include <cstring> |
|||
|
|||
|
|||
xmrig::AdvancedCpuInfo::AdvancedCpuInfo() |
|||
{ |
|||
struct cpu_raw_data_t raw = {}; |
|||
struct cpu_id_t data = {}; |
|||
|
|||
cpuid_get_raw_data(&raw); |
|||
cpu_identify(&raw, &data); |
|||
|
|||
snprintf(m_backend, sizeof m_backend, "libcpuid/%s", cpuid_lib_version()); |
|||
|
|||
m_threads = static_cast<size_t>(data.total_logical_cpus); |
|||
m_packages = std::max<size_t>(m_threads / static_cast<size_t>(data.num_logical_cpus), 1); |
|||
m_cores = static_cast<size_t>(data.num_cores) * m_packages; |
|||
m_L3 = data.l3_cache > 0 ? static_cast<size_t>(data.l3_cache) * m_packages : 0; |
|||
|
|||
const auto l2 = static_cast<size_t>(data.l2_cache); |
|||
|
|||
// Workaround for AMD CPUs https://github.com/anrieff/libcpuid/issues/97
|
|||
if (m_vendor == VENDOR_AMD && data.ext_family >= 0x15 && data.ext_family < 0x17) { |
|||
m_L2 = l2 * (cores() / 2) * m_packages; |
|||
m_L2_exclusive = true; |
|||
} |
|||
// Workaround for Intel Pentium Dual-Core, Core Duo, Core 2 Duo, Core 2 Quad and their Xeon homologue
|
|||
// These processors have L2 cache shared by 2 cores.
|
|||
else if (m_vendor == VENDOR_INTEL && data.ext_family == 0x06 && (data.ext_model == 0x0E || data.ext_model == 0x0F || data.ext_model == 0x17)) { |
|||
size_t l2_count_per_socket = cores() > 1 ? cores() / 2 : 1; |
|||
m_L2 = data.l2_cache > 0 ? l2 * l2_count_per_socket * m_packages : 0; |
|||
} |
|||
else{ |
|||
m_L2 = data.l2_cache > 0 ? l2 * cores() * m_packages : 0; |
|||
} |
|||
|
|||
m_L2 *= 1024; |
|||
m_L3 *= 1024; |
|||
} |
|||
|
|||
|
|||
xmrig::CpuThreads xmrig::AdvancedCpuInfo::threads(const Algorithm &algorithm, uint32_t limit) const |
|||
{ |
|||
if (threads() == 1) { |
|||
return 1; |
|||
} |
|||
|
|||
size_t cache = 0; |
|||
size_t count = 0; |
|||
|
|||
# ifdef XMRIG_ALGO_ASTROBWT |
|||
if (algorithm == Algorithm::ASTROBWT_DERO) { |
|||
CpuThreads t; |
|||
count = threads(); |
|||
for (size_t i = 0; i < count; ++i) { |
|||
t.add(i, 0); |
|||
} |
|||
return t; |
|||
} |
|||
# endif |
|||
|
|||
if (m_L3) { |
|||
cache = m_L2_exclusive ? (m_L2 + m_L3) : m_L3; |
|||
} |
|||
else { |
|||
cache = m_L2; |
|||
} |
|||
|
|||
if (cache) { |
|||
const size_t memory = algorithm.l3(); |
|||
assert(memory > 0); |
|||
|
|||
count = cache / memory; |
|||
|
|||
if (cache % memory >= memory / 2) { |
|||
count++; |
|||
} |
|||
} |
|||
else { |
|||
count = threads() / 2; |
|||
} |
|||
|
|||
uint32_t intensity = algorithm.maxIntensity() == 1 ? 0 : 1; |
|||
|
|||
# ifdef XMRIG_ALGO_CN_PICO |
|||
if (algorithm == Algorithm::CN_PICO_0 && (count / cores()) >= 2) { |
|||
intensity = 2; |
|||
} |
|||
# endif |
|||
|
|||
if (limit > 0 && limit < 100) { |
|||
count = std::min(count, static_cast<size_t>(round(threads() * (limit / 100.0)))); |
|||
} |
|||
else { |
|||
count = std::min(count, threads()); |
|||
} |
|||
|
|||
return CpuThreads(std::max<size_t>(count, 1), intensity); |
|||
} |
@ -1,63 +0,0 @@ |
|||
/* XMRig
|
|||
* Copyright 2010 Jeff Garzik <jgarzik@pobox.com> |
|||
* Copyright 2012-2014 pooler <pooler@litecoinpool.org> |
|||
* Copyright 2014 Lucas Jones <https://github.com/lucasjones>
|
|||
* Copyright 2014-2016 Wolf9466 <https://github.com/OhGodAPet>
|
|||
* Copyright 2016 Jay D Dee <jayddee246@gmail.com> |
|||
* Copyright 2017-2019 XMR-Stak <https://github.com/fireice-uk>, <https://github.com/psychocrypt>
|
|||
* Copyright 2018-2020 SChernykh <https://github.com/SChernykh>
|
|||
* Copyright 2016-2020 XMRig <support@xmrig.com> |
|||
* |
|||
* This program is free software: you can redistribute it and/or modify |
|||
* it under the terms of the GNU General Public License as published by |
|||
* the Free Software Foundation, either version 3 of the License, or |
|||
* (at your option) any later version. |
|||
* |
|||
* This program is distributed in the hope that it will be useful, |
|||
* but WITHOUT ANY WARRANTY; without even the implied warranty of |
|||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the |
|||
* GNU General Public License for more details. |
|||
* |
|||
* You should have received a copy of the GNU General Public License |
|||
* along with this program. If not, see <http://www.gnu.org/licenses/>.
|
|||
*/ |
|||
|
|||
#ifndef XMRIG_ADVANCEDCPUINFO_H |
|||
#define XMRIG_ADVANCEDCPUINFO_H |
|||
|
|||
|
|||
#include "backend/cpu/platform/BasicCpuInfo.h" |
|||
|
|||
|
|||
namespace xmrig { |
|||
|
|||
|
|||
class AdvancedCpuInfo : public BasicCpuInfo |
|||
{ |
|||
public: |
|||
AdvancedCpuInfo(); |
|||
|
|||
protected: |
|||
CpuThreads threads(const Algorithm &algorithm, uint32_t limit) const override; |
|||
|
|||
inline const char *backend() const override { return m_backend; } |
|||
inline size_t cores() const override { return m_cores; } |
|||
inline size_t L2() const override { return m_L2; } |
|||
inline size_t L3() const override { return m_L3; } |
|||
inline size_t packages() const override { return m_packages; } |
|||
inline size_t threads() const override { return m_threads; } |
|||
|
|||
private: |
|||
bool m_L2_exclusive = false; |
|||
char m_backend[32]{}; |
|||
size_t m_cores = 0; |
|||
size_t m_L2 = 0; |
|||
size_t m_L3 = 0; |
|||
size_t m_packages = 1; |
|||
}; |
|||
|
|||
|
|||
} /* namespace xmrig */ |
|||
|
|||
|
|||
#endif /* XMRIG_ADVANCEDCPUINFO_H */ |
Loading…
Reference in new issue