1
0
mirror of https://github.com/gnss-sdr/gnss-sdr synced 2024-12-13 19:50:34 +00:00

Merge branch 'update-cpufeatures' into next

This commit is contained in:
Carles Fernandez 2021-10-25 17:45:38 +02:00
commit 8849f78eb0
No known key found for this signature in database
GPG Key ID: 4C583C52B0C3877D
12 changed files with 373 additions and 198 deletions

View File

@ -270,10 +270,6 @@ elseif(CMAKE_SYSTEM_PROCESSOR MATCHES "^(powerpc|ppc)")
endif() endif()
if(CMAKE_VERSION VERSION_GREATER 3.0 AND SUPPORTED_CPU_FEATURES_ARCH) if(CMAKE_VERSION VERSION_GREATER 3.0 AND SUPPORTED_CPU_FEATURES_ARCH)
set(BUILD_PIC ON CACHE BOOL
"Build cpu_features with Position Independent Code (PIC)."
FORCE
)
set(USE_CPU_FEATURES ON) set(USE_CPU_FEATURES ON)
set(BUILD_SHARED_LIBS_SAVED "${BUILD_SHARED_LIBS}") set(BUILD_SHARED_LIBS_SAVED "${BUILD_SHARED_LIBS}")
set(BUILD_SHARED_LIBS OFF) set(BUILD_SHARED_LIBS OFF)

View File

@ -32,13 +32,11 @@ option(BUILD_TESTING "Enable test (depends on googletest)." OFF)
# As a consequence it is discouraged to use cpu_features as a shared library because different compilers may interpret the code in different ways. # As a consequence it is discouraged to use cpu_features as a shared library because different compilers may interpret the code in different ways.
# Prefer static linking from source whenever possible. # Prefer static linking from source whenever possible.
option(BUILD_SHARED_LIBS "Build library as shared." OFF) option(BUILD_SHARED_LIBS "Build library as shared." OFF)
# PIC
option(BUILD_PIC "Build with Position Independant Code." OFF) # Default is off at least for GCC
# Force PIC on unix when building shared libs # Force PIC on unix when building shared libs
# see: https://en.wikipedia.org/wiki/Position-independent_code # see: https://en.wikipedia.org/wiki/Position-independent_code
if(BUILD_SHARED_LIBS AND UNIX) if(BUILD_SHARED_LIBS AND UNIX)
set(BUILD_PIC ON) option(CMAKE_POSITION_INDEPENDENT_CODE "Build with Position Independant Code." ON)
endif() endif()
include(CheckIncludeFile) include(CheckIncludeFile)
@ -110,7 +108,6 @@ add_library(utils OBJECT
${PROJECT_SOURCE_DIR}/src/stack_line_reader.c ${PROJECT_SOURCE_DIR}/src/stack_line_reader.c
${PROJECT_SOURCE_DIR}/src/string_view.c ${PROJECT_SOURCE_DIR}/src/string_view.c
) )
set_property(TARGET utils PROPERTY POSITION_INDEPENDENT_CODE ${BUILD_PIC})
setup_include_and_definitions(utils) setup_include_and_definitions(utils)
# #
@ -131,7 +128,6 @@ if(UNIX)
if(HAVE_STRONG_GETAUXVAL) if(HAVE_STRONG_GETAUXVAL)
target_compile_definitions(unix_based_hardware_detection PRIVATE HAVE_STRONG_GETAUXVAL) target_compile_definitions(unix_based_hardware_detection PRIVATE HAVE_STRONG_GETAUXVAL)
endif() endif()
set_property(TARGET unix_based_hardware_detection PROPERTY POSITION_INDEPENDENT_CODE ${BUILD_PIC})
endif() endif()
# #
@ -148,7 +144,6 @@ add_library(cpu_features ${CPU_FEATURES_HDRS} ${CPU_FEATURES_SRCS})
set_target_properties(cpu_features PROPERTIES PUBLIC_HEADER "${CPU_FEATURES_HDRS}") set_target_properties(cpu_features PROPERTIES PUBLIC_HEADER "${CPU_FEATURES_HDRS}")
setup_include_and_definitions(cpu_features) setup_include_and_definitions(cpu_features)
target_link_libraries(cpu_features PUBLIC ${CMAKE_DL_LIBS}) target_link_libraries(cpu_features PUBLIC ${CMAKE_DL_LIBS})
set_property(TARGET cpu_features PROPERTY POSITION_INDEPENDENT_CODE ${BUILD_PIC})
target_include_directories(cpu_features target_include_directories(cpu_features
PUBLIC $<INSTALL_INTERFACE:${CMAKE_INSTALL_INCLUDEDIR}/cpu_features> PUBLIC $<INSTALL_INTERFACE:${CMAKE_INSTALL_INCLUDEDIR}/cpu_features>
) )
@ -237,6 +232,7 @@ install(TARGETS cpu_features list_cpu_features
ARCHIVE DESTINATION ${CMAKE_INSTALL_LIBDIR} ARCHIVE DESTINATION ${CMAKE_INSTALL_LIBDIR}
LIBRARY DESTINATION ${CMAKE_INSTALL_LIBDIR} LIBRARY DESTINATION ${CMAKE_INSTALL_LIBDIR}
RUNTIME DESTINATION ${CMAKE_INSTALL_BINDIR} RUNTIME DESTINATION ${CMAKE_INSTALL_BINDIR}
BUNDLE DESTINATION ${CMAKE_INSTALL_BINDIR}
) )
install(EXPORT CpuFeaturesTargets install(EXPORT CpuFeaturesTargets
NAMESPACE CpuFeatures:: NAMESPACE CpuFeatures::

View File

@ -10,6 +10,11 @@
CPU_FEATURES_START_CPP_NAMESPACE CPU_FEATURES_START_CPP_NAMESPACE
// CPUID Vendors
#define CPU_FEATURES_VENDOR_GENUINE_INTEL "GenuineIntel"
#define CPU_FEATURES_VENDOR_AUTHENTIC_AMD "AuthenticAMD"
#define CPU_FEATURES_VENDOR_HYGON_GENUINE "HygonGenuine"
// See https://en.wikipedia.org/wiki/CPUID for a list of x86 cpu features. // See https://en.wikipedia.org/wiki/CPUID for a list of x86 cpu features.
// The field names are based on the short name provided in the wikipedia tables. // The field names are based on the short name provided in the wikipedia tables.
typedef struct typedef struct

View File

@ -87,7 +87,8 @@ void CpuFeatures_StringView_CopyString(const StringView src, char* dst,
// Checks if line contains the specified whitespace separated word. // Checks if line contains the specified whitespace separated word.
bool CpuFeatures_StringView_HasWord(const StringView line, bool CpuFeatures_StringView_HasWord(const StringView line,
const char* const word); const char* const word,
const char separator);
// Get key/value from line. key and value are separated by ": ". // Get key/value from line. key and value are separated by ": ".
// key and value are cleaned up from leading and trailing whitespaces. // key and value are cleaned up from leading and trailing whitespaces.

View File

@ -107,8 +107,8 @@ static bool HandleAarch64Line(const LineResult result,
{ {
for (size_t i = 0; i < AARCH64_LAST_; ++i) for (size_t i = 0; i < AARCH64_LAST_; ++i)
{ {
kSetters[i](&info->features, kSetters[i](&info->features, CpuFeatures_StringView_HasWord(
CpuFeatures_StringView_HasWord(value, kCpuInfoFlags[i])); value, kCpuInfoFlags[i], ' '));
} }
} }
else if (CpuFeatures_StringView_IsEquals(key, str("CPU implementer"))) else if (CpuFeatures_StringView_IsEquals(key, str("CPU implementer")))

View File

@ -71,8 +71,8 @@ static bool HandleArmLine(const LineResult result, ArmInfo* const info,
{ {
for (size_t i = 0; i < ARM_LAST_; ++i) for (size_t i = 0; i < ARM_LAST_; ++i)
{ {
kSetters[i](&info->features, kSetters[i](&info->features, CpuFeatures_StringView_HasWord(
CpuFeatures_StringView_HasWord(value, kCpuInfoFlags[i])); value, kCpuInfoFlags[i], ' '));
} }
} }
else if (CpuFeatures_StringView_IsEquals(key, str("CPU implementer"))) else if (CpuFeatures_StringView_IsEquals(key, str("CPU implementer")))

View File

@ -28,8 +28,8 @@ static bool HandleMipsLine(const LineResult result,
{ {
for (size_t i = 0; i < MIPS_LAST_; ++i) for (size_t i = 0; i < MIPS_LAST_; ++i)
{ {
kSetters[i](features, kSetters[i](features, CpuFeatures_StringView_HasWord(
CpuFeatures_StringView_HasWord(value, kCpuInfoFlags[i])); value, kCpuInfoFlags[i], ' '));
} }
} }
} }

View File

@ -71,7 +71,7 @@ static bool HandlePPCLine(const LineResult result,
StringView key, value; StringView key, value;
if (CpuFeatures_StringView_GetAttributeKeyValue(line, &key, &value)) if (CpuFeatures_StringView_GetAttributeKeyValue(line, &key, &value))
{ {
if (CpuFeatures_StringView_HasWord(key, "platform")) if (CpuFeatures_StringView_HasWord(key, "platform", ' '))
{ {
CpuFeatures_StringView_CopyString(value, strings->platform, CpuFeatures_StringView_CopyString(value, strings->platform,
sizeof(strings->platform)); sizeof(strings->platform));

View File

@ -88,7 +88,6 @@
defined(CPU_FEATURES_OS_FREEBSD) defined(CPU_FEATURES_OS_FREEBSD)
#include "internal/filesystem.h" // Needed to parse /proc/cpuinfo #include "internal/filesystem.h" // Needed to parse /proc/cpuinfo
#include "internal/stack_line_reader.h" // Needed to parse /proc/cpuinfo #include "internal/stack_line_reader.h" // Needed to parse /proc/cpuinfo
#include "internal/string_view.h" // Needed to parse /proc/cpuinfo
#elif defined(CPU_FEATURES_OS_DARWIN) #elif defined(CPU_FEATURES_OS_DARWIN)
#if !defined(HAVE_SYSCTLBYNAME) #if !defined(HAVE_SYSCTLBYNAME)
#error "Darwin needs support for sysctlbyname" #error "Darwin needs support for sysctlbyname"
@ -98,6 +97,8 @@
#error "Unsupported OS" #error "Unsupported OS"
#endif // CPU_FEATURES_OS #endif // CPU_FEATURES_OS
#include "internal/string_view.h"
//////////////////////////////////////////////////////////////////////////////// ////////////////////////////////////////////////////////////////////////////////
// Definitions for CpuId and GetXCR0Eax. // Definitions for CpuId and GetXCR0Eax.
//////////////////////////////////////////////////////////////////////////////// ////////////////////////////////////////////////////////////////////////////////
@ -267,6 +268,11 @@ static int IsVendor(const Leaf leaf, const char* const name)
return leaf.ebx == ebx && leaf.ecx == ecx && leaf.edx == edx; return leaf.ebx == ebx && leaf.ecx == ecx && leaf.edx == edx;
} }
static int IsVendorByX86Info(const X86Info* info, const char* const name)
{
return memcmp(info->vendor, name, sizeof(info->vendor)) == 0;
}
static const CacheLevelInfo kEmptyCacheLevelInfo; static const CacheLevelInfo kEmptyCacheLevelInfo;
static CacheLevelInfo GetCacheLevelInfo(const uint32_t reg) static CacheLevelInfo GetCacheLevelInfo(const uint32_t reg)
@ -1129,55 +1135,52 @@ static CacheLevelInfo GetCacheLevelInfo(const uint32_t reg)
} }
} }
static void GetByteArrayFromRegister(uint32_t result[4], const uint32_t reg) // From https://www.felixcloutier.com/x86/cpuid#tbl-3-12
{
for (int i = 0; i < 4; ++i)
{
result[i] = ExtractBitRange(reg, (i + 1) * 8, i * 8);
}
}
static void ParseLeaf2(const int max_cpuid_leaf, CacheInfo* info) static void ParseLeaf2(const int max_cpuid_leaf, CacheInfo* info)
{ {
Leaf leaf = SafeCpuId(max_cpuid_leaf, 2); Leaf leaf = SafeCpuId(max_cpuid_leaf, 2);
uint32_t registers[] = {leaf.eax, leaf.ebx, leaf.ecx, leaf.edx}; // The least-significant byte in register EAX (register AL) will always return
for (int i = 0; i < 4; ++i) // 01H. Software should ignore this value and not interpret it as an
// informational descriptor.
leaf.eax &= 0xFFFFFF00; // Zeroing out AL. 0 is the empty descriptor.
// The most significant bit (bit 31) of each register indicates whether the
// register contains valid information (set to 0) or is reserved (set to 1).
if (IsBitSet(leaf.eax, 31)) leaf.eax = 0;
if (IsBitSet(leaf.ebx, 31)) leaf.ebx = 0;
if (IsBitSet(leaf.ecx, 31)) leaf.ecx = 0;
if (IsBitSet(leaf.edx, 31)) leaf.edx = 0;
uint8_t data[16];
#if __STDC_VERSION__ >= 201112L
_Static_assert(sizeof(Leaf) == sizeof(data), "Leaf must be 16 bytes");
#endif
memcpy(&data, &leaf, sizeof(data));
for (size_t i = 0; i < sizeof(data); ++i)
{ {
if (registers[i] & (1U << 31)) const uint8_t descriptor = data[i];
{ if (descriptor == 0) continue;
continue; // register does not contains valid information info->levels[info->size] = GetCacheLevelInfo(descriptor);
}
uint32_t bytes[4];
GetByteArrayFromRegister(bytes, registers[i]);
for (int j = 0; j < 4; ++j)
{
if (bytes[j] == 0xFF)
break; // leaf 4 should be used to fetch cache information
info->levels[info->size] = GetCacheLevelInfo(bytes[j]);
}
info->size++; info->size++;
} }
} }
static void ParseLeaf4(const int max_cpuid_leaf, CacheInfo* info) // For newer Intel CPUs uses "CPUID, eax=0x00000004".
// For newer AMD CPUs uses "CPUID, eax=0x8000001D"
static void ParseCacheInfo(const int max_cpuid_leaf, uint32_t leaf_id,
CacheInfo* info)
{ {
info->size = 0;
for (int cache_id = 0; cache_id < CPU_FEATURES_MAX_CACHE_LEVEL; cache_id++) for (int cache_id = 0; cache_id < CPU_FEATURES_MAX_CACHE_LEVEL; cache_id++)
{ {
const Leaf leaf = SafeCpuIdEx(max_cpuid_leaf, 4, cache_id); const Leaf leaf = SafeCpuIdEx(max_cpuid_leaf, leaf_id, cache_id);
CacheType cache_type = ExtractBitRange(leaf.eax, 4, 0); CacheType cache_type = ExtractBitRange(leaf.eax, 4, 0);
if (cache_type == CPU_FEATURE_CACHE_NULL) if (cache_type == CPU_FEATURE_CACHE_NULL) continue;
{
info->levels[cache_id] = kEmptyCacheLevelInfo;
continue;
}
int level = ExtractBitRange(leaf.eax, 7, 5); int level = ExtractBitRange(leaf.eax, 7, 5);
int line_size = ExtractBitRange(leaf.ebx, 11, 0) + 1; int line_size = ExtractBitRange(leaf.ebx, 11, 0) + 1;
int partitioning = ExtractBitRange(leaf.ebx, 21, 12) + 1; int partitioning = ExtractBitRange(leaf.ebx, 21, 12) + 1;
int ways = ExtractBitRange(leaf.ebx, 31, 22) + 1; int ways = ExtractBitRange(leaf.ebx, 31, 22) + 1;
int tlb_entries = leaf.ecx + 1; int tlb_entries = leaf.ecx + 1;
int cache_size = (ways * partitioning * line_size * (tlb_entries)); int cache_size = (ways * partitioning * line_size * (tlb_entries));
info->levels[cache_id] = (CacheLevelInfo){.level = level, info->levels[info->size] = (CacheLevelInfo){.level = level,
.cache_type = cache_type, .cache_type = cache_type,
.cache_size = cache_size, .cache_size = cache_size,
.ways = ways, .ways = ways,
@ -1371,41 +1374,33 @@ static void ParseCpuId(const uint32_t max_cpuid_leaf, X86Info* info,
{ {
StackLineReader reader; StackLineReader reader;
StackLineReader_Initialize(&reader, fd); StackLineReader_Initialize(&reader, fd);
for (;;) for (bool stop = false; !stop;)
{ {
const LineResult result = StackLineReader_NextLine(&reader); const LineResult result = StackLineReader_NextLine(&reader);
if (result.eof) stop = true;
const StringView line = result.line; const StringView line = result.line;
const bool is_feature = if (!CpuFeatures_StringView_StartsWith(line, str(" Features")))
CpuFeatures_StringView_StartsWith(line, str(" Features=")); continue;
const bool is_feature2 = // Lines of interests are of the following form:
CpuFeatures_StringView_StartsWith(line, str(" Features2=")); // " Features=0x1783fbff<PSE36,MMX,FXSR,SSE,SSE2,HTT>"
if (is_feature || is_feature2) // We first extract the comma separated values between angle brackets.
{ StringView csv = result.line;
// Lines of interests are of the following form: int index = CpuFeatures_StringView_IndexOfChar(csv, '<');
// " Features=0x1783fbff<PSE36,MMX,FXSR,SSE,SSE2,HTT>" if (index >= 0) csv = CpuFeatures_StringView_PopFront(csv, index + 1);
// We replace '<', '>' and ',' with space so we can search by if (csv.size > 0 && CpuFeatures_StringView_Back(csv) == '>')
// whitespace separated word. csv = CpuFeatures_StringView_PopBack(csv, 1);
// TODO: Fix CpuFeatures_StringView_HasWord to allow for different if (CpuFeatures_StringView_HasWord(csv, "SSE", ','))
// separators. features->sse = true;
for (size_t i = 0; i < line.size; ++i) if (CpuFeatures_StringView_HasWord(csv, "SSE2", ','))
{ features->sse2 = true;
char* c = (char*)(&(line.ptr[i])); if (CpuFeatures_StringView_HasWord(csv, "SSE3", ','))
if (*c == '<' || *c == '>' || *c == ',') *c = ' '; features->sse3 = true;
} if (CpuFeatures_StringView_HasWord(csv, "SSSE3", ','))
if (is_feature) features->ssse3 = true;
{ if (CpuFeatures_StringView_HasWord(csv, "SSE4.1", ','))
features->sse = CpuFeatures_StringView_HasWord(line, "SSE"); features->sse4_1 = true;
features->sse2 = CpuFeatures_StringView_HasWord(line, "SSE2"); if (CpuFeatures_StringView_HasWord(csv, "SSE4.2", ','))
} features->sse4_2 = true;
if (is_feature2)
{
features->sse3 = CpuFeatures_StringView_HasWord(line, "SSE3");
features->ssse3 = CpuFeatures_StringView_HasWord(line, "SSSE3");
features->sse4_1 = CpuFeatures_StringView_HasWord(line, "SSE4.1");
features->sse4_2 = CpuFeatures_StringView_HasWord(line, "SSE4.2");
}
}
if (result.eof) break;
} }
CpuFeatures_CloseFile(fd); CpuFeatures_CloseFile(fd);
} }
@ -1416,25 +1411,22 @@ static void ParseCpuId(const uint32_t max_cpuid_leaf, X86Info* info,
{ {
StackLineReader reader; StackLineReader reader;
StackLineReader_Initialize(&reader, fd); StackLineReader_Initialize(&reader, fd);
for (;;) for (bool stop = false; !stop;)
{ {
const LineResult result = StackLineReader_NextLine(&reader); const LineResult result = StackLineReader_NextLine(&reader);
if (result.eof) stop = true;
const StringView line = result.line; const StringView line = result.line;
StringView key, value; StringView key, value;
if (CpuFeatures_StringView_GetAttributeKeyValue(line, &key, &value)) if (!CpuFeatures_StringView_GetAttributeKeyValue(line, &key, &value))
{ continue;
if (CpuFeatures_StringView_IsEquals(key, str("flags"))) if (!CpuFeatures_StringView_IsEquals(key, str("flags"))) continue;
{ features->sse = CpuFeatures_StringView_HasWord(value, "sse", ' ');
features->sse = CpuFeatures_StringView_HasWord(value, "sse"); features->sse2 = CpuFeatures_StringView_HasWord(value, "sse2", ' ');
features->sse2 = CpuFeatures_StringView_HasWord(value, "sse2"); features->sse3 = CpuFeatures_StringView_HasWord(value, "sse3", ' ');
features->sse3 = CpuFeatures_StringView_HasWord(value, "sse3"); features->ssse3 = CpuFeatures_StringView_HasWord(value, "ssse3", ' ');
features->ssse3 = CpuFeatures_StringView_HasWord(value, "ssse3"); features->sse4_1 = CpuFeatures_StringView_HasWord(value, "sse4_1", ' ');
features->sse4_1 = CpuFeatures_StringView_HasWord(value, "sse4_1"); features->sse4_2 = CpuFeatures_StringView_HasWord(value, "sse4_2", ' ');
features->sse4_2 = CpuFeatures_StringView_HasWord(value, "sse4_2"); break;
break;
}
}
if (result.eof) break;
} }
CpuFeatures_CloseFile(fd); CpuFeatures_CloseFile(fd);
} }
@ -1450,11 +1442,15 @@ static void ParseCpuId(const uint32_t max_cpuid_leaf, X86Info* info,
// Reference // Reference
// https://en.wikipedia.org/wiki/CPUID#EAX=80000000h:_Get_Highest_Extended_Function_Implemented. // https://en.wikipedia.org/wiki/CPUID#EAX=80000000h:_Get_Highest_Extended_Function_Implemented.
static Leaf GetLeafByIdAMD(uint32_t leaf_id)
{
uint32_t max_extended = CpuId(0x80000000).eax;
return SafeCpuId(max_extended, leaf_id);
}
static void ParseExtraAMDCpuId(X86Info* info, OsPreserves os_preserves) static void ParseExtraAMDCpuId(X86Info* info, OsPreserves os_preserves)
{ {
const Leaf leaf_80000000 = CpuId(0x80000000); const Leaf leaf_80000001 = GetLeafByIdAMD(0x80000001);
const uint32_t max_extended_cpuid_leaf = leaf_80000000.eax;
const Leaf leaf_80000001 = SafeCpuId(max_extended_cpuid_leaf, 0x80000001);
X86Features* const features = &info->features; X86Features* const features = &info->features;
@ -1477,9 +1473,9 @@ X86Info GetX86Info(void)
{ {
X86Info info = kEmptyX86Info; X86Info info = kEmptyX86Info;
const Leaf leaf_0 = CpuId(0); const Leaf leaf_0 = CpuId(0);
const bool is_intel = IsVendor(leaf_0, "GenuineIntel"); const bool is_intel = IsVendor(leaf_0, CPU_FEATURES_VENDOR_GENUINE_INTEL);
const bool is_amd = IsVendor(leaf_0, "AuthenticAMD"); const bool is_amd = IsVendor(leaf_0, CPU_FEATURES_VENDOR_AUTHENTIC_AMD);
const bool is_hygon = IsVendor(leaf_0, "HygonGenuine"); const bool is_hygon = IsVendor(leaf_0, CPU_FEATURES_VENDOR_HYGON_GENUINE);
SetVendor(leaf_0, info.vendor); SetVendor(leaf_0, info.vendor);
if (is_intel || is_amd || is_hygon) if (is_intel || is_amd || is_hygon)
{ {
@ -1498,11 +1494,25 @@ CacheInfo GetX86CacheInfo(void)
{ {
CacheInfo info = kEmptyCacheInfo; CacheInfo info = kEmptyCacheInfo;
const Leaf leaf_0 = CpuId(0); const Leaf leaf_0 = CpuId(0);
const uint32_t max_cpuid_leaf = leaf_0.eax; if (IsVendor(leaf_0, CPU_FEATURES_VENDOR_GENUINE_INTEL))
if (IsVendor(leaf_0, "GenuineIntel"))
{ {
ParseLeaf2(max_cpuid_leaf, &info); info.size = 0;
ParseLeaf4(max_cpuid_leaf, &info); ParseLeaf2(leaf_0.eax, &info);
ParseCacheInfo(leaf_0.eax, 4, &info);
}
else if (IsVendor(leaf_0, CPU_FEATURES_VENDOR_AUTHENTIC_AMD) ||
IsVendor(leaf_0, CPU_FEATURES_VENDOR_HYGON_GENUINE))
{
const uint32_t max_ext = CpuId(0x80000000).eax;
const uint32_t cpuid_ext = SafeCpuId(max_ext, 0x80000001).ecx;
// If CPUID Fn8000_0001_ECX[TopologyExtensions]==0
// then CPUID Fn8000_0001_E[D,C,B,A]X is reserved.
// https://www.amd.com/system/files/TechDocs/25481.pdf
if (IsBitSet(cpuid_ext, 22))
{
ParseCacheInfo(max_ext, 0x8000001D, &info);
}
} }
return info; return info;
} }
@ -1511,7 +1521,7 @@ CacheInfo GetX86CacheInfo(void)
X86Microarchitecture GetX86Microarchitecture(const X86Info* info) X86Microarchitecture GetX86Microarchitecture(const X86Info* info)
{ {
if (memcmp(info->vendor, "GenuineIntel", sizeof(info->vendor)) == 0) if (IsVendorByX86Info(info, CPU_FEATURES_VENDOR_GENUINE_INTEL))
{ {
switch (CPUID(info->family, info->model)) switch (CPUID(info->family, info->model))
{ {
@ -1616,7 +1626,7 @@ X86Microarchitecture GetX86Microarchitecture(const X86Info* info)
return X86_UNKNOWN; return X86_UNKNOWN;
} }
} }
if (memcmp(info->vendor, "AuthenticAMD", sizeof(info->vendor)) == 0) if (IsVendorByX86Info(info, CPU_FEATURES_VENDOR_AUTHENTIC_AMD))
{ {
switch (CPUID(info->family, info->model)) switch (CPUID(info->family, info->model))
{ {
@ -1726,7 +1736,7 @@ X86Microarchitecture GetX86Microarchitecture(const X86Info* info)
return X86_UNKNOWN; return X86_UNKNOWN;
} }
} }
if (memcmp(info->vendor, "HygonGenuine", sizeof(info->vendor)) == 0) if (IsVendorByX86Info(info, CPU_FEATURES_VENDOR_HYGON_GENUINE))
{ {
switch (CPUID(info->family, info->model)) switch (CPUID(info->family, info->model))
{ {
@ -1737,23 +1747,20 @@ X86Microarchitecture GetX86Microarchitecture(const X86Info* info)
return X86_UNKNOWN; return X86_UNKNOWN;
} }
static void SetString(const uint32_t max_cpuid_ext_leaf, const uint32_t leaf_id,
char* buffer)
{
const Leaf leaf = SafeCpuId(max_cpuid_ext_leaf, leaf_id);
// We allow calling memcpy from SetString which is only called when requesting
// X86BrandString.
memcpy(buffer, &leaf, sizeof(Leaf));
}
void FillX86BrandString(char brand_string[49]) void FillX86BrandString(char brand_string[49])
{ {
const Leaf leaf_ext_0 = CpuId(0x80000000); const Leaf leaf_ext_0 = CpuId(0x80000000);
const uint32_t max_cpuid_leaf_ext = leaf_ext_0.eax; const uint32_t max_cpuid_leaf_ext = leaf_ext_0.eax;
SetString(max_cpuid_leaf_ext, 0x80000002, brand_string); const Leaf leaves[3] = {
SetString(max_cpuid_leaf_ext, 0x80000003, brand_string + 16); SafeCpuId(max_cpuid_leaf_ext, 0x80000002),
SetString(max_cpuid_leaf_ext, 0x80000004, brand_string + 32); SafeCpuId(max_cpuid_leaf_ext, 0x80000003),
brand_string[48] = '\0'; SafeCpuId(max_cpuid_leaf_ext, 0x80000004),
};
#if __STDC_VERSION__ >= 201112L
_Static_assert(sizeof(leaves) == 48, "Leaves must be packed");
#endif
CpuFeatures_StringView_CopyString(view((const char*)leaves, sizeof(leaves)),
brand_string, 49);
} }
//////////////////////////////////////////////////////////////////////////////// ////////////////////////////////////////////////////////////////////////////////

View File

@ -158,7 +158,8 @@ void CpuFeatures_StringView_CopyString(const StringView src, char* dst,
} }
bool CpuFeatures_StringView_HasWord(const StringView line, bool CpuFeatures_StringView_HasWord(const StringView line,
const char* const word_str) const char* const word_str,
const char separator)
{ {
const StringView word = str(word_str); const StringView word = str(word_str);
StringView remainder = line; StringView remainder = line;
@ -176,9 +177,9 @@ bool CpuFeatures_StringView_HasWord(const StringView line,
const StringView after = const StringView after =
CpuFeatures_StringView_PopFront(line, index_of_word + word.size); CpuFeatures_StringView_PopFront(line, index_of_word + word.size);
const bool valid_before = const bool valid_before =
before.size == 0 || CpuFeatures_StringView_Back(before) == ' '; before.size == 0 || CpuFeatures_StringView_Back(before) == separator;
const bool valid_after = const bool valid_after =
after.size == 0 || CpuFeatures_StringView_Front(after) == ' '; after.size == 0 || CpuFeatures_StringView_Front(after) == separator;
if (valid_before && valid_after) return true; if (valid_before && valid_after) return true;
remainder = remainder =
CpuFeatures_StringView_PopFront(remainder, index_of_word + word.size); CpuFeatures_StringView_PopFront(remainder, index_of_word + word.size);

View File

@ -76,26 +76,32 @@ private:
uint32_t xcr0_eax_; uint32_t xcr0_eax_;
}; };
FakeCpu* g_fake_cpu = nullptr; static FakeCpu* g_fake_cpu_instance = nullptr;
static FakeCpu& cpu()
{
assert(g_fake_cpu_instance != nullptr);
return *g_fake_cpu_instance;
}
extern "C" Leaf GetCpuidLeaf(uint32_t leaf_id, int ecx) extern "C" Leaf GetCpuidLeaf(uint32_t leaf_id, int ecx)
{ {
return g_fake_cpu->GetCpuidLeaf(leaf_id, ecx); return cpu().GetCpuidLeaf(leaf_id, ecx);
} }
extern "C" uint32_t GetXCR0Eax(void) { return g_fake_cpu->GetXCR0Eax(); } extern "C" uint32_t GetXCR0Eax(void) { return cpu().GetXCR0Eax(); }
#if defined(CPU_FEATURES_OS_DARWIN) #if defined(CPU_FEATURES_OS_DARWIN)
extern "C" bool GetDarwinSysCtlByName(const char* name) extern "C" bool GetDarwinSysCtlByName(const char* name)
{ {
return g_fake_cpu->GetDarwinSysCtlByName(name); return cpu().GetDarwinSysCtlByName(name);
} }
#endif // CPU_FEATURES_OS_DARWIN #endif // CPU_FEATURES_OS_DARWIN
#if defined(CPU_FEATURES_OS_WINDOWS) #if defined(CPU_FEATURES_OS_WINDOWS)
extern "C" bool GetWindowsIsProcessorFeaturePresent(DWORD ProcessorFeature) extern "C" bool GetWindowsIsProcessorFeaturePresent(DWORD ProcessorFeature)
{ {
return g_fake_cpu->GetWindowsIsProcessorFeaturePresent(ProcessorFeature); return cpu().GetWindowsIsProcessorFeaturePresent(ProcessorFeature);
} }
#endif // CPU_FEATURES_OS_WINDOWS #endif // CPU_FEATURES_OS_WINDOWS
@ -104,14 +110,22 @@ namespace
class CpuidX86Test : public ::testing::Test class CpuidX86Test : public ::testing::Test
{ {
protected: protected:
void SetUp() override { g_fake_cpu = new FakeCpu(); } void SetUp() override
void TearDown() override { delete g_fake_cpu; } {
assert(g_fake_cpu_instance == nullptr);
g_fake_cpu_instance = new FakeCpu();
}
void TearDown() override
{
delete g_fake_cpu_instance;
g_fake_cpu_instance = nullptr;
}
}; };
TEST_F(CpuidX86Test, SandyBridge) TEST_F(CpuidX86Test, SandyBridge)
{ {
g_fake_cpu->SetOsBackupsExtendedRegisters(true); cpu().SetOsBackupsExtendedRegisters(true);
g_fake_cpu->SetLeaves({ cpu().SetLeaves({
{{0x00000000, 0}, Leaf{0x0000000D, 0x756E6547, 0x6C65746E, 0x49656E69}}, {{0x00000000, 0}, Leaf{0x0000000D, 0x756E6547, 0x6C65746E, 0x49656E69}},
{{0x00000001, 0}, Leaf{0x000206A6, 0x00100800, 0x1F9AE3BF, 0xBFEBFBFF}}, {{0x00000001, 0}, Leaf{0x000206A6, 0x00100800, 0x1F9AE3BF, 0xBFEBFBFF}},
{{0x00000007, 0}, Leaf{0x00000000, 0x00000000, 0x00000000, 0x00000000}}, {{0x00000007, 0}, Leaf{0x00000000, 0x00000000, 0x00000000, 0x00000000}},
@ -153,28 +167,29 @@ TEST_F(CpuidX86Test, SandyBridge)
EXPECT_FALSE(features.adx); EXPECT_FALSE(features.adx);
} }
const int UNDEF = -1;
const int KiB = 1024; const int KiB = 1024;
const int MiB = 1024 * KiB; const int MiB = 1024 * KiB;
TEST_F(CpuidX86Test, SandyBridgeTestOsSupport) TEST_F(CpuidX86Test, SandyBridgeTestOsSupport)
{ {
g_fake_cpu->SetLeaves({ cpu().SetLeaves({
{{0x00000000, 0}, Leaf{0x0000000D, 0x756E6547, 0x6C65746E, 0x49656E69}}, {{0x00000000, 0}, Leaf{0x0000000D, 0x756E6547, 0x6C65746E, 0x49656E69}},
{{0x00000001, 0}, Leaf{0x000206A6, 0x00100800, 0x1F9AE3BF, 0xBFEBFBFF}}, {{0x00000001, 0}, Leaf{0x000206A6, 0x00100800, 0x1F9AE3BF, 0xBFEBFBFF}},
{{0x00000007, 0}, Leaf{0x00000000, 0x00000000, 0x00000000, 0x00000000}}, {{0x00000007, 0}, Leaf{0x00000000, 0x00000000, 0x00000000, 0x00000000}},
}); });
// avx is disabled if os does not support backing up ymm registers. // avx is disabled if os does not support backing up ymm registers.
g_fake_cpu->SetOsBackupsExtendedRegisters(false); cpu().SetOsBackupsExtendedRegisters(false);
EXPECT_FALSE(GetX86Info().features.avx); EXPECT_FALSE(GetX86Info().features.avx);
// avx is disabled if os does not support backing up ymm registers. // avx is disabled if os does not support backing up ymm registers.
g_fake_cpu->SetOsBackupsExtendedRegisters(true); cpu().SetOsBackupsExtendedRegisters(true);
EXPECT_TRUE(GetX86Info().features.avx); EXPECT_TRUE(GetX86Info().features.avx);
} }
TEST_F(CpuidX86Test, SkyLake) TEST_F(CpuidX86Test, SkyLake)
{ {
g_fake_cpu->SetOsBackupsExtendedRegisters(true); cpu().SetOsBackupsExtendedRegisters(true);
g_fake_cpu->SetLeaves({ cpu().SetLeaves({
{{0x00000000, 0}, Leaf{0x00000016, 0x756E6547, 0x6C65746E, 0x49656E69}}, {{0x00000000, 0}, Leaf{0x00000016, 0x756E6547, 0x6C65746E, 0x49656E69}},
{{0x00000001, 0}, Leaf{0x000406E3, 0x00100800, 0x7FFAFBBF, 0xBFEBFBFF}}, {{0x00000001, 0}, Leaf{0x000406E3, 0x00100800, 0x7FFAFBBF, 0xBFEBFBFF}},
{{0x00000007, 0}, Leaf{0x00000000, 0x029C67AF, 0x00000000, 0x00000000}}, {{0x00000007, 0}, Leaf{0x00000000, 0x029C67AF, 0x00000000, 0x00000000}},
@ -189,7 +204,7 @@ TEST_F(CpuidX86Test, SkyLake)
TEST_F(CpuidX86Test, Branding) TEST_F(CpuidX86Test, Branding)
{ {
g_fake_cpu->SetLeaves({ cpu().SetLeaves({
{{0x00000000, 0}, Leaf{0x00000016, 0x756E6547, 0x6C65746E, 0x49656E69}}, {{0x00000000, 0}, Leaf{0x00000016, 0x756E6547, 0x6C65746E, 0x49656E69}},
{{0x00000001, 0}, Leaf{0x000406E3, 0x00100800, 0x7FFAFBBF, 0xBFEBFBFF}}, {{0x00000001, 0}, Leaf{0x000406E3, 0x00100800, 0x7FFAFBBF, 0xBFEBFBFF}},
{{0x00000007, 0}, Leaf{0x00000000, 0x029C67AF, 0x00000000, 0x00000000}}, {{0x00000007, 0}, Leaf{0x00000000, 0x029C67AF, 0x00000000, 0x00000000}},
@ -206,7 +221,7 @@ TEST_F(CpuidX86Test, Branding)
TEST_F(CpuidX86Test, KabyLakeCache) TEST_F(CpuidX86Test, KabyLakeCache)
{ {
g_fake_cpu->SetLeaves({ cpu().SetLeaves({
{{0x00000000, 0}, Leaf{0x00000016, 0x756E6547, 0x6C65746E, 0x49656E69}}, {{0x00000000, 0}, Leaf{0x00000016, 0x756E6547, 0x6C65746E, 0x49656E69}},
{{0x00000001, 0}, Leaf{0x000406E3, 0x00100800, 0x7FFAFBBF, 0xBFEBFBFF}}, {{0x00000001, 0}, Leaf{0x000406E3, 0x00100800, 0x7FFAFBBF, 0xBFEBFBFF}},
{{0x00000004, 0}, Leaf{0x1C004121, 0x01C0003F, 0x0000003F, 0x00000000}}, {{0x00000004, 0}, Leaf{0x1C004121, 0x01C0003F, 0x0000003F, 0x00000000}},
@ -256,7 +271,7 @@ TEST_F(CpuidX86Test, KabyLakeCache)
TEST_F(CpuidX86Test, HSWCache) TEST_F(CpuidX86Test, HSWCache)
{ {
g_fake_cpu->SetLeaves({ cpu().SetLeaves({
{{0x00000000, 0}, Leaf{0x00000016, 0x756E6547, 0x6C65746E, 0x49656E69}}, {{0x00000000, 0}, Leaf{0x00000016, 0x756E6547, 0x6C65746E, 0x49656E69}},
{{0x00000001, 0}, Leaf{0x000406E3, 0x00100800, 0x7FFAFBBF, 0xBFEBFBFF}}, {{0x00000001, 0}, Leaf{0x000406E3, 0x00100800, 0x7FFAFBBF, 0xBFEBFBFF}},
{{0x00000004, 0}, Leaf{0x1C004121, 0x01C0003F, 0x0000003F, 0x00000000}}, {{0x00000004, 0}, Leaf{0x1C004121, 0x01C0003F, 0x0000003F, 0x00000000}},
@ -307,7 +322,7 @@ TEST_F(CpuidX86Test, HSWCache)
// http://users.atw.hu/instlatx64/AuthenticAMD/AuthenticAMD0200F30_K11_Griffin_CPUID.txt // http://users.atw.hu/instlatx64/AuthenticAMD/AuthenticAMD0200F30_K11_Griffin_CPUID.txt
TEST_F(CpuidX86Test, AMD_K11_GRIFFIN) TEST_F(CpuidX86Test, AMD_K11_GRIFFIN)
{ {
g_fake_cpu->SetLeaves({ cpu().SetLeaves({
{{0x00000000, 0}, Leaf{0x00000001, 0x68747541, 0x444D4163, 0x69746E65}}, {{0x00000000, 0}, Leaf{0x00000001, 0x68747541, 0x444D4163, 0x69746E65}},
{{0x00000001, 0}, Leaf{0x00200F30, 0x00020800, 0x00002001, 0x178BFBFF}}, {{0x00000001, 0}, Leaf{0x00200F30, 0x00020800, 0x00002001, 0x178BFBFF}},
{{0x80000000, 0}, Leaf{0x8000001A, 0x68747541, 0x444D4163, 0x69746E65}}, {{0x80000000, 0}, Leaf{0x8000001A, 0x68747541, 0x444D4163, 0x69746E65}},
@ -324,7 +339,7 @@ TEST_F(CpuidX86Test, AMD_K11_GRIFFIN)
// http://users.atw.hu/instlatx64/AuthenticAMD/AuthenticAMD0300F10_K12_Llano_CPUID.txt // http://users.atw.hu/instlatx64/AuthenticAMD/AuthenticAMD0300F10_K12_Llano_CPUID.txt
TEST_F(CpuidX86Test, AMD_K12_LLANO) TEST_F(CpuidX86Test, AMD_K12_LLANO)
{ {
g_fake_cpu->SetLeaves({ cpu().SetLeaves({
{{0x00000000, 0}, Leaf{0x00000006, 0x68747541, 0x444D4163, 0x69746E65}}, {{0x00000000, 0}, Leaf{0x00000006, 0x68747541, 0x444D4163, 0x69746E65}},
{{0x00000001, 0}, Leaf{0x00300F10, 0x00040800, 0x00802009, 0x178BFBFF}}, {{0x00000001, 0}, Leaf{0x00300F10, 0x00040800, 0x00802009, 0x178BFBFF}},
{{0x80000000, 0}, Leaf{0x8000001B, 0x68747541, 0x444D4163, 0x69746E65}}, {{0x80000000, 0}, Leaf{0x8000001B, 0x68747541, 0x444D4163, 0x69746E65}},
@ -341,7 +356,7 @@ TEST_F(CpuidX86Test, AMD_K12_LLANO)
// http://users.atw.hu/instlatx64/AuthenticAMD/AuthenticAMD0500F01_K14_Bobcat_CPUID.txt // http://users.atw.hu/instlatx64/AuthenticAMD/AuthenticAMD0500F01_K14_Bobcat_CPUID.txt
TEST_F(CpuidX86Test, AMD_K14_BOBCAT_AMD0500F01) TEST_F(CpuidX86Test, AMD_K14_BOBCAT_AMD0500F01)
{ {
g_fake_cpu->SetLeaves({ cpu().SetLeaves({
{{0x00000000, 0}, Leaf{0x00000006, 0x68747541, 0x444D4163, 0x69746E65}}, {{0x00000000, 0}, Leaf{0x00000006, 0x68747541, 0x444D4163, 0x69746E65}},
{{0x00000001, 0}, Leaf{0x00500F01, 0x00020800, 0x00802209, 0x178BFBFF}}, {{0x00000001, 0}, Leaf{0x00500F01, 0x00020800, 0x00802209, 0x178BFBFF}},
{{0x80000000, 0}, Leaf{0x8000001B, 0x68747541, 0x444D4163, 0x69746E65}}, {{0x80000000, 0}, Leaf{0x8000001B, 0x68747541, 0x444D4163, 0x69746E65}},
@ -358,7 +373,7 @@ TEST_F(CpuidX86Test, AMD_K14_BOBCAT_AMD0500F01)
// http://users.atw.hu/instlatx64/AuthenticAMD/AuthenticAMD0500F10_K14_Bobcat_CPUID.txt // http://users.atw.hu/instlatx64/AuthenticAMD/AuthenticAMD0500F10_K14_Bobcat_CPUID.txt
TEST_F(CpuidX86Test, AMD_K14_BOBCAT_AMD0500F10) TEST_F(CpuidX86Test, AMD_K14_BOBCAT_AMD0500F10)
{ {
g_fake_cpu->SetLeaves({ cpu().SetLeaves({
{{0x00000000, 0}, Leaf{0x00000006, 0x68747541, 0x444D4163, 0x69746E65}}, {{0x00000000, 0}, Leaf{0x00000006, 0x68747541, 0x444D4163, 0x69746E65}},
{{0x00000001, 0}, Leaf{0x00500F10, 0x00020800, 0x00802209, 0x178BFBFF}}, {{0x00000001, 0}, Leaf{0x00500F10, 0x00020800, 0x00802209, 0x178BFBFF}},
{{0x00000002, 0}, Leaf{0x00000000, 0x00000000, 0x00000000, 0x00000000}}, {{0x00000002, 0}, Leaf{0x00000000, 0x00000000, 0x00000000, 0x00000000}},
@ -383,7 +398,7 @@ TEST_F(CpuidX86Test, AMD_K14_BOBCAT_AMD0500F10)
// http://users.atw.hu/instlatx64/AuthenticAMD/AuthenticAMD0500F20_K14_Bobcat_CPUID.txt // http://users.atw.hu/instlatx64/AuthenticAMD/AuthenticAMD0500F20_K14_Bobcat_CPUID.txt
TEST_F(CpuidX86Test, AMD_K14_BOBCAT_AMD0500F20) TEST_F(CpuidX86Test, AMD_K14_BOBCAT_AMD0500F20)
{ {
g_fake_cpu->SetLeaves({ cpu().SetLeaves({
{{0x00000000, 0}, Leaf{0x00000006, 0x68747541, 0x444D4163, 0x69746E65}}, {{0x00000000, 0}, Leaf{0x00000006, 0x68747541, 0x444D4163, 0x69746E65}},
{{0x00000001, 0}, Leaf{0x00500F20, 0x00020800, 0x00802209, 0x178BFBFF}}, {{0x00000001, 0}, Leaf{0x00500F20, 0x00020800, 0x00802209, 0x178BFBFF}},
{{0x80000000, 0}, Leaf{0x8000001B, 0x68747541, 0x444D4163, 0x69746E65}}, {{0x80000000, 0}, Leaf{0x8000001B, 0x68747541, 0x444D4163, 0x69746E65}},
@ -400,7 +415,7 @@ TEST_F(CpuidX86Test, AMD_K14_BOBCAT_AMD0500F20)
// http://users.atw.hu/instlatx64/AuthenticAMD/AuthenticAMD0670F00_K15_StoneyRidge_CPUID.txt // http://users.atw.hu/instlatx64/AuthenticAMD/AuthenticAMD0670F00_K15_StoneyRidge_CPUID.txt
TEST_F(CpuidX86Test, AMD_K15_EXCAVATOR_STONEY_RIDGE) TEST_F(CpuidX86Test, AMD_K15_EXCAVATOR_STONEY_RIDGE)
{ {
g_fake_cpu->SetLeaves({ cpu().SetLeaves({
{{0x00000000, 0}, Leaf{0x0000000D, 0x68747541, 0x444D4163, 0x69746E65}}, {{0x00000000, 0}, Leaf{0x0000000D, 0x68747541, 0x444D4163, 0x69746E65}},
{{0x00000001, 0}, Leaf{0x00670F00, 0x00020800, 0x7ED8320B, 0x178BFBFF}}, {{0x00000001, 0}, Leaf{0x00670F00, 0x00020800, 0x7ED8320B, 0x178BFBFF}},
{{0x00000007, 0}, Leaf{0x00000000, 0x000001A9, 0x00000000, 0x00000000}}, {{0x00000007, 0}, Leaf{0x00000000, 0x000001A9, 0x00000000, 0x00000000}},
@ -426,7 +441,7 @@ TEST_F(CpuidX86Test, AMD_K15_EXCAVATOR_STONEY_RIDGE)
// http://users.atw.hu/instlatx64/AuthenticAMD/AuthenticAMD0600F20_K15_AbuDhabi_CPUID0.txt // http://users.atw.hu/instlatx64/AuthenticAMD/AuthenticAMD0600F20_K15_AbuDhabi_CPUID0.txt
TEST_F(CpuidX86Test, AMD_K15_PILEDRIVER_ABU_DHABI) TEST_F(CpuidX86Test, AMD_K15_PILEDRIVER_ABU_DHABI)
{ {
g_fake_cpu->SetLeaves({ cpu().SetLeaves({
{{0x00000000, 0}, Leaf{0x0000000D, 0x68747541, 0x444D4163, 0x69746E65}}, {{0x00000000, 0}, Leaf{0x0000000D, 0x68747541, 0x444D4163, 0x69746E65}},
{{0x00000001, 0}, Leaf{0x00600F20, 0x00100800, 0x3E98320B, 0x178BFBFF}}, {{0x00000001, 0}, Leaf{0x00600F20, 0x00100800, 0x3E98320B, 0x178BFBFF}},
{{0x00000007, 0}, Leaf{0x00000000, 0x00000008, 0x00000000, 0x00000000}}, {{0x00000007, 0}, Leaf{0x00000000, 0x00000008, 0x00000000, 0x00000000}},
@ -449,10 +464,59 @@ TEST_F(CpuidX86Test, AMD_K15_PILEDRIVER_ABU_DHABI)
EXPECT_STREQ(brand_string, "AMD Opteron(tm) Processor 6376 "); EXPECT_STREQ(brand_string, "AMD Opteron(tm) Processor 6376 ");
} }
// http://users.atw.hu/instlatx64/AuthenticAMD/AuthenticAMD0600F20_K15_AbuDhabi_CPUID0.txt
TEST_F(CpuidX86Test, AMD_K15_PILEDRIVER_ABU_DHABI_CACHE_INFO)
{
cpu().SetLeaves({
{{0x00000000, 0}, Leaf{0x0000000D, 0x68747541, 0x444D4163, 0x69746E65}},
{{0x00000001, 0}, Leaf{0x00600F20, 0x00100800, 0x3E98320B, 0x178BFBFF}},
{{0x80000000, 0}, Leaf{0x8000001E, 0x68747541, 0x444D4163, 0x69746E65}},
{{0x80000001, 0}, Leaf{0x00600F20, 0x30000000, 0x01EBBFFF, 0x2FD3FBFF}},
{{0x8000001D, 0}, Leaf{0x00000121, 0x00C0003F, 0x0000003F, 0x00000000}},
{{0x8000001D, 1}, Leaf{0x00004122, 0x0040003F, 0x000001FF, 0x00000000}},
{{0x8000001D, 2}, Leaf{0x00004143, 0x03C0003F, 0x000007FF, 0x00000001}},
{{0x8000001D, 3}, Leaf{0x0001C163, 0x0BC0003F, 0x000007FF, 0x00000001}},
});
const auto info = GetX86CacheInfo();
EXPECT_EQ(info.size, 4);
EXPECT_EQ(info.levels[0].level, 1);
EXPECT_EQ(info.levels[0].cache_type, 1);
EXPECT_EQ(info.levels[0].cache_size, 16 * KiB);
EXPECT_EQ(info.levels[0].ways, 4);
EXPECT_EQ(info.levels[0].line_size, 64);
EXPECT_EQ(info.levels[0].tlb_entries, 64);
EXPECT_EQ(info.levels[0].partitioning, 1);
EXPECT_EQ(info.levels[1].level, 1);
EXPECT_EQ(info.levels[1].cache_type, 2);
EXPECT_EQ(info.levels[1].cache_size, 64 * KiB);
EXPECT_EQ(info.levels[1].ways, 2);
EXPECT_EQ(info.levels[1].line_size, 64);
EXPECT_EQ(info.levels[1].tlb_entries, 512);
EXPECT_EQ(info.levels[1].partitioning, 1);
EXPECT_EQ(info.levels[2].level, 2);
EXPECT_EQ(info.levels[2].cache_type, 3);
EXPECT_EQ(info.levels[2].cache_size, 2 * MiB);
EXPECT_EQ(info.levels[2].ways, 16);
EXPECT_EQ(info.levels[2].line_size, 64);
EXPECT_EQ(info.levels[2].tlb_entries, 2048);
EXPECT_EQ(info.levels[2].partitioning, 1);
EXPECT_EQ(info.levels[3].level, 3);
EXPECT_EQ(info.levels[3].cache_type, 3);
EXPECT_EQ(info.levels[3].cache_size, 6 * MiB);
EXPECT_EQ(info.levels[3].ways, 48);
EXPECT_EQ(info.levels[3].line_size, 64);
EXPECT_EQ(info.levels[3].tlb_entries, 2048);
EXPECT_EQ(info.levels[3].partitioning, 1);
}
// http://users.atw.hu/instlatx64/AuthenticAMD/AuthenticAMD0600F12_K15_Interlagos_CPUID3.txt // http://users.atw.hu/instlatx64/AuthenticAMD/AuthenticAMD0600F12_K15_Interlagos_CPUID3.txt
TEST_F(CpuidX86Test, AMD_K15_BULLDOZER_INTERLAGOS) TEST_F(CpuidX86Test, AMD_K15_BULLDOZER_INTERLAGOS)
{ {
g_fake_cpu->SetLeaves({ cpu().SetLeaves({
{{0x00000000, 0}, Leaf{0x0000000D, 0x68747541, 0x444D4163, 0x69746E65}}, {{0x00000000, 0}, Leaf{0x0000000D, 0x68747541, 0x444D4163, 0x69746E65}},
{{0x00000001, 0}, Leaf{0x00600F12, 0x000C0800, 0x1E98220B, 0x178BFBFF}}, {{0x00000001, 0}, Leaf{0x00600F12, 0x000C0800, 0x1E98220B, 0x178BFBFF}},
{{0x00000007, 0}, Leaf{0x00000000, 0x00000000, 0x00000000, 0x00000000}}, {{0x00000007, 0}, Leaf{0x00000000, 0x00000000, 0x00000000, 0x00000000}},
@ -478,7 +542,7 @@ TEST_F(CpuidX86Test, AMD_K15_BULLDOZER_INTERLAGOS)
// http://users.atw.hu/instlatx64/AuthenticAMD0630F81_K15_Godavari_CPUID.txt // http://users.atw.hu/instlatx64/AuthenticAMD0630F81_K15_Godavari_CPUID.txt
TEST_F(CpuidX86Test, AMD_K15_STREAMROLLER_GODAVARI) TEST_F(CpuidX86Test, AMD_K15_STREAMROLLER_GODAVARI)
{ {
g_fake_cpu->SetLeaves({ cpu().SetLeaves({
{{0x00000000, 0}, Leaf{0x0000000D, 0x68747541, 0x444D4163, 0x69746E65}}, {{0x00000000, 0}, Leaf{0x0000000D, 0x68747541, 0x444D4163, 0x69746E65}},
{{0x00000001, 0}, Leaf{0x00630F81, 0x00040800, 0x3E98320B, 0x178BFBFF}}, {{0x00000001, 0}, Leaf{0x00630F81, 0x00040800, 0x3E98320B, 0x178BFBFF}},
{{0x00000007, 0}, Leaf{0x00000000, 0x00000000, 0x00000000, 0x00000000}}, {{0x00000007, 0}, Leaf{0x00000000, 0x00000000, 0x00000000, 0x00000000}},
@ -506,7 +570,7 @@ TEST_F(CpuidX86Test, AMD_K15_STREAMROLLER_GODAVARI)
// http://users.atw.hu/instlatx64/AuthenticAMD/AuthenticAMD0700F01_K16_Kabini_CPUID.txt // http://users.atw.hu/instlatx64/AuthenticAMD/AuthenticAMD0700F01_K16_Kabini_CPUID.txt
TEST_F(CpuidX86Test, AMD_K16_JAGUAR_KABINI) TEST_F(CpuidX86Test, AMD_K16_JAGUAR_KABINI)
{ {
g_fake_cpu->SetLeaves({ cpu().SetLeaves({
{{0x00000000, 0}, Leaf{0x0000000D, 0x68747541, 0x444D4163, 0x69746E65}}, {{0x00000000, 0}, Leaf{0x0000000D, 0x68747541, 0x444D4163, 0x69746E65}},
{{0x00000001, 0}, Leaf{0x00700F01, 0x00040800, 0x3ED8220B, 0x178BFBFF}}, {{0x00000001, 0}, Leaf{0x00700F01, 0x00040800, 0x3ED8220B, 0x178BFBFF}},
{{0x00000007, 0}, Leaf{0x00000000, 0x00000008, 0x00000000, 0x00000000}}, {{0x00000007, 0}, Leaf{0x00000000, 0x00000008, 0x00000000, 0x00000000}},
@ -531,7 +595,7 @@ TEST_F(CpuidX86Test, AMD_K16_JAGUAR_KABINI)
// http://users.atw.hu/instlatx64/AuthenticAMD/AuthenticAMD0730F01_K16_Beema_CPUID2.txt // http://users.atw.hu/instlatx64/AuthenticAMD/AuthenticAMD0730F01_K16_Beema_CPUID2.txt
TEST_F(CpuidX86Test, AMD_K16_PUMA_BEEMA) TEST_F(CpuidX86Test, AMD_K16_PUMA_BEEMA)
{ {
g_fake_cpu->SetLeaves({ cpu().SetLeaves({
{{0x00000000, 0}, Leaf{0x0000000D, 0x68747541, 0x444D4163, 0x69746E65}}, {{0x00000000, 0}, Leaf{0x0000000D, 0x68747541, 0x444D4163, 0x69746E65}},
{{0x00000001, 0}, Leaf{0x00730F01, 0x00040800, 0x7ED8220B, 0x178BFBFF}}, {{0x00000001, 0}, Leaf{0x00730F01, 0x00040800, 0x7ED8220B, 0x178BFBFF}},
{{0x00000007, 0}, Leaf{0x00000000, 0x00000008, 0x00000000, 0x00000000}}, {{0x00000007, 0}, Leaf{0x00000000, 0x00000008, 0x00000000, 0x00000000}},
@ -556,7 +620,7 @@ TEST_F(CpuidX86Test, AMD_K16_PUMA_BEEMA)
// http://users.atw.hu/instlatx64/AuthenticAMD/AuthenticAMD0820F01_K17_Dali_CPUID.txt // http://users.atw.hu/instlatx64/AuthenticAMD/AuthenticAMD0820F01_K17_Dali_CPUID.txt
TEST_F(CpuidX86Test, AMD_K17_ZEN_DALI) TEST_F(CpuidX86Test, AMD_K17_ZEN_DALI)
{ {
g_fake_cpu->SetLeaves({ cpu().SetLeaves({
{{0x00000000, 0}, Leaf{0x0000000D, 0x68747541, 0x444D4163, 0x69746E65}}, {{0x00000000, 0}, Leaf{0x0000000D, 0x68747541, 0x444D4163, 0x69746E65}},
{{0x00000001, 0}, Leaf{0x00820F01, 0x00020800, 0x7ED8320B, 0x178BFBFF}}, {{0x00000001, 0}, Leaf{0x00820F01, 0x00020800, 0x7ED8320B, 0x178BFBFF}},
{{0x00000007, 0}, Leaf{0x00000000, 0x209C01A9, 0x00000000, 0x00000000}}, {{0x00000007, 0}, Leaf{0x00000000, 0x209C01A9, 0x00000000, 0x00000000}},
@ -581,7 +645,7 @@ TEST_F(CpuidX86Test, AMD_K17_ZEN_DALI)
// http://users.atw.hu/instlatx64/AuthenticAMD/AuthenticAMD0800F82_K17_ZenP_CPUID.txt // http://users.atw.hu/instlatx64/AuthenticAMD/AuthenticAMD0800F82_K17_ZenP_CPUID.txt
TEST_F(CpuidX86Test, AMD_K17_ZEN_PLUS_PINNACLE_RIDGE) TEST_F(CpuidX86Test, AMD_K17_ZEN_PLUS_PINNACLE_RIDGE)
{ {
g_fake_cpu->SetLeaves({ cpu().SetLeaves({
{{0x00000000, 0}, Leaf{0x0000000D, 0x68747541, 0x444D4163, 0x69746E65}}, {{0x00000000, 0}, Leaf{0x0000000D, 0x68747541, 0x444D4163, 0x69746E65}},
{{0x00000001, 0}, Leaf{0x00800F82, 0x00100800, 0x7ED8320B, 0x178BFBFF}}, {{0x00000001, 0}, Leaf{0x00800F82, 0x00100800, 0x7ED8320B, 0x178BFBFF}},
{{0x00000007, 0}, Leaf{0x00000000, 0x209C01A9, 0x00000000, 0x00000000}}, {{0x00000007, 0}, Leaf{0x00000000, 0x209C01A9, 0x00000000, 0x00000000}},
@ -606,7 +670,7 @@ TEST_F(CpuidX86Test, AMD_K17_ZEN_PLUS_PINNACLE_RIDGE)
// http://users.atw.hu/instlatx64/AuthenticAMD/AuthenticAMD0840F70_K17_CPUID.txt // http://users.atw.hu/instlatx64/AuthenticAMD/AuthenticAMD0840F70_K17_CPUID.txt
TEST_F(CpuidX86Test, AMD_K17_ZEN2_XBOX_SERIES_X) TEST_F(CpuidX86Test, AMD_K17_ZEN2_XBOX_SERIES_X)
{ {
g_fake_cpu->SetLeaves({ cpu().SetLeaves({
{{0x00000000, 0}, Leaf{0x00000010, 0x68747541, 0x444D4163, 0x69746E65}}, {{0x00000000, 0}, Leaf{0x00000010, 0x68747541, 0x444D4163, 0x69746E65}},
{{0x00000001, 0}, Leaf{0x00840F70, 0x00100800, 0x7ED8320B, 0x178BFBFF}}, {{0x00000001, 0}, Leaf{0x00840F70, 0x00100800, 0x7ED8320B, 0x178BFBFF}},
{{0x00000007, 0}, Leaf{0x00000000, 0x219C91A9, 0x00400004, 0x00000000}}, {{0x00000007, 0}, Leaf{0x00000000, 0x219C91A9, 0x00400004, 0x00000000}},
@ -631,7 +695,7 @@ TEST_F(CpuidX86Test, AMD_K17_ZEN2_XBOX_SERIES_X)
// http://users.atw.hu/instlatx64/HygonGenuine/HygonGenuine0900F02_Hygon_CPUID3.txt // http://users.atw.hu/instlatx64/HygonGenuine/HygonGenuine0900F02_Hygon_CPUID3.txt
TEST_F(CpuidX86Test, AMD_K18_ZEN_DHYANA) TEST_F(CpuidX86Test, AMD_K18_ZEN_DHYANA)
{ {
g_fake_cpu->SetLeaves({ cpu().SetLeaves({
{{0x00000000, 0}, Leaf{0x0000000D, 0x6F677948, 0x656E6975, 0x6E65476E}}, {{0x00000000, 0}, Leaf{0x0000000D, 0x6F677948, 0x656E6975, 0x6E65476E}},
{{0x00000001, 0}, Leaf{0x00900F02, 0x00100800, 0x74D83209, 0x178BFBFF}}, {{0x00000001, 0}, Leaf{0x00900F02, 0x00100800, 0x74D83209, 0x178BFBFF}},
{{0x00000007, 0}, Leaf{0x00000000, 0x009C01A9, 0x0040068C, 0x00000000}}, {{0x00000007, 0}, Leaf{0x00000000, 0x009C01A9, 0x0040068C, 0x00000000}},
@ -653,10 +717,59 @@ TEST_F(CpuidX86Test, AMD_K18_ZEN_DHYANA)
EXPECT_STREQ(brand_string, "Hygon C86 3185 8-core Processor "); EXPECT_STREQ(brand_string, "Hygon C86 3185 8-core Processor ");
} }
// http://users.atw.hu/instlatx64/HygonGenuine/HygonGenuine0900F02_Hygon_CPUID.txt
TEST_F(CpuidX86Test, AMD_K18_ZEN_DHYANA_CACHE_INFO)
{
cpu().SetLeaves({
{{0x00000000, 0}, Leaf{0x0000000D, 0x6F677948, 0x656E6975, 0x6E65476E}},
{{0x00000001, 0}, Leaf{0x00900F02, 0x00100800, 0x74D83209, 0x178BFBFF}},
{{0x80000000, 0}, Leaf{0x8000001F, 0x6F677948, 0x656E6975, 0x6E65476E}},
{{0x80000001, 0}, Leaf{0x00900F02, 0x60000000, 0x35C233FF, 0x2FD3FBFF}},
{{0x8000001D, 0}, Leaf{0x00004121, 0x01C0003F, 0x0000003F, 0x00000000}},
{{0x8000001D, 1}, Leaf{0x00004122, 0x00C0003F, 0x000000FF, 0x00000000}},
{{0x8000001D, 2}, Leaf{0x00004143, 0x01C0003F, 0x000003FF, 0x00000002}},
{{0x8000001D, 3}, Leaf{0x0001C163, 0x03C0003F, 0x00001FFF, 0x00000001}},
});
const auto info = GetX86CacheInfo();
EXPECT_EQ(info.size, 4);
EXPECT_EQ(info.levels[0].level, 1);
EXPECT_EQ(info.levels[0].cache_type, 1);
EXPECT_EQ(info.levels[0].cache_size, 32 * KiB);
EXPECT_EQ(info.levels[0].ways, 8);
EXPECT_EQ(info.levels[0].line_size, 64);
EXPECT_EQ(info.levels[0].tlb_entries, 64);
EXPECT_EQ(info.levels[0].partitioning, 1);
EXPECT_EQ(info.levels[1].level, 1);
EXPECT_EQ(info.levels[1].cache_type, 2);
EXPECT_EQ(info.levels[1].cache_size, 64 * KiB);
EXPECT_EQ(info.levels[1].ways, 4);
EXPECT_EQ(info.levels[1].line_size, 64);
EXPECT_EQ(info.levels[1].tlb_entries, 256);
EXPECT_EQ(info.levels[1].partitioning, 1);
EXPECT_EQ(info.levels[2].level, 2);
EXPECT_EQ(info.levels[2].cache_type, 3);
EXPECT_EQ(info.levels[2].cache_size, 512 * KiB);
EXPECT_EQ(info.levels[2].ways, 8);
EXPECT_EQ(info.levels[2].line_size, 64);
EXPECT_EQ(info.levels[2].tlb_entries, 1024);
EXPECT_EQ(info.levels[2].partitioning, 1);
EXPECT_EQ(info.levels[3].level, 3);
EXPECT_EQ(info.levels[3].cache_type, 3);
EXPECT_EQ(info.levels[3].cache_size, 8 * MiB);
EXPECT_EQ(info.levels[3].ways, 16);
EXPECT_EQ(info.levels[3].line_size, 64);
EXPECT_EQ(info.levels[3].tlb_entries, 8192);
EXPECT_EQ(info.levels[3].partitioning, 1);
}
// http://users.atw.hu/instlatx64/AuthenticAMD/AuthenticAMD0A20F10_K19_Vermeer2_CPUID.txt // http://users.atw.hu/instlatx64/AuthenticAMD/AuthenticAMD0A20F10_K19_Vermeer2_CPUID.txt
TEST_F(CpuidX86Test, AMD_K19_ZEN3_VERMEER) TEST_F(CpuidX86Test, AMD_K19_ZEN3_VERMEER)
{ {
g_fake_cpu->SetLeaves({ cpu().SetLeaves({
{{0x00000000, 0}, Leaf{0x00000010, 0x68747541, 0x444D4163, 0x69746E65}}, {{0x00000000, 0}, Leaf{0x00000010, 0x68747541, 0x444D4163, 0x69746E65}},
{{0x00000001, 0}, Leaf{0x00A20F10, 0x01180800, 0x7ED8320B, 0x178BFBFF}}, {{0x00000001, 0}, Leaf{0x00A20F10, 0x01180800, 0x7ED8320B, 0x178BFBFF}},
{{0x00000007, 0}, Leaf{0x00000000, 0x219C97A9, 0x0040068C, 0x00000000}}, {{0x00000007, 0}, Leaf{0x00000000, 0x219C97A9, 0x0040068C, 0x00000000}},
@ -682,21 +795,18 @@ TEST_F(CpuidX86Test, AMD_K19_ZEN3_VERMEER)
TEST_F(CpuidX86Test, Nehalem) TEST_F(CpuidX86Test, Nehalem)
{ {
// Pre AVX cpus don't have xsave // Pre AVX cpus don't have xsave
g_fake_cpu->SetOsBackupsExtendedRegisters(false); cpu().SetOsBackupsExtendedRegisters(false);
#if defined(CPU_FEATURES_OS_WINDOWS) #if defined(CPU_FEATURES_OS_WINDOWS)
g_fake_cpu->SetWindowsIsProcessorFeaturePresent( cpu().SetWindowsIsProcessorFeaturePresent(PF_XMMI_INSTRUCTIONS_AVAILABLE);
PF_XMMI_INSTRUCTIONS_AVAILABLE); cpu().SetWindowsIsProcessorFeaturePresent(PF_XMMI64_INSTRUCTIONS_AVAILABLE);
g_fake_cpu->SetWindowsIsProcessorFeaturePresent( cpu().SetWindowsIsProcessorFeaturePresent(PF_SSE3_INSTRUCTIONS_AVAILABLE);
PF_XMMI64_INSTRUCTIONS_AVAILABLE);
g_fake_cpu->SetWindowsIsProcessorFeaturePresent(
PF_SSE3_INSTRUCTIONS_AVAILABLE);
#elif defined(CPU_FEATURES_OS_DARWIN) #elif defined(CPU_FEATURES_OS_DARWIN)
g_fake_cpu->SetDarwinSysCtlByName("hw.optional.sse"); cpu().SetDarwinSysCtlByName("hw.optional.sse");
g_fake_cpu->SetDarwinSysCtlByName("hw.optional.sse2"); cpu().SetDarwinSysCtlByName("hw.optional.sse2");
g_fake_cpu->SetDarwinSysCtlByName("hw.optional.sse3"); cpu().SetDarwinSysCtlByName("hw.optional.sse3");
g_fake_cpu->SetDarwinSysCtlByName("hw.optional.supplementalsse3"); cpu().SetDarwinSysCtlByName("hw.optional.supplementalsse3");
g_fake_cpu->SetDarwinSysCtlByName("hw.optional.sse4_1"); cpu().SetDarwinSysCtlByName("hw.optional.sse4_1");
g_fake_cpu->SetDarwinSysCtlByName("hw.optional.sse4_2"); cpu().SetDarwinSysCtlByName("hw.optional.sse4_2");
#elif defined(CPU_FEATURES_OS_FREEBSD) #elif defined(CPU_FEATURES_OS_FREEBSD)
auto& fs = GetEmptyFilesystem(); auto& fs = GetEmptyFilesystem();
fs.CreateFile("/var/run/dmesg.boot", R"( fs.CreateFile("/var/run/dmesg.boot", R"(
@ -713,7 +823,7 @@ real memory = 2147418112 (2047 MB)
flags : fpu mmx sse sse2 sse3 ssse3 sse4_1 sse4_2 flags : fpu mmx sse sse2 sse3 ssse3 sse4_1 sse4_2
)"); )");
#endif #endif
g_fake_cpu->SetLeaves({ cpu().SetLeaves({
{{0x00000000, 0}, Leaf{0x0000000B, 0x756E6547, 0x6C65746E, 0x49656E69}}, {{0x00000000, 0}, Leaf{0x0000000B, 0x756E6547, 0x6C65746E, 0x49656E69}},
{{0x00000001, 0}, Leaf{0x000106A2, 0x00100800, 0x00BCE3BD, 0xBFEBFBFF}}, {{0x00000001, 0}, Leaf{0x000106A2, 0x00100800, 0x00BCE3BD, 0xBFEBFBFF}},
{{0x00000002, 0}, Leaf{0x55035A01, 0x00F0B0E3, 0x00000000, 0x09CA212C}}, {{0x00000002, 0}, Leaf{0x55035A01, 0x00F0B0E3, 0x00000000, 0x09CA212C}},
@ -768,21 +878,18 @@ flags : fpu mmx sse sse2 sse3 ssse3 sse4_1 sse4_2
TEST_F(CpuidX86Test, Atom) TEST_F(CpuidX86Test, Atom)
{ {
// Pre AVX cpus don't have xsave // Pre AVX cpus don't have xsave
g_fake_cpu->SetOsBackupsExtendedRegisters(false); cpu().SetOsBackupsExtendedRegisters(false);
#if defined(CPU_FEATURES_OS_WINDOWS) #if defined(CPU_FEATURES_OS_WINDOWS)
g_fake_cpu->SetWindowsIsProcessorFeaturePresent( cpu().SetWindowsIsProcessorFeaturePresent(PF_XMMI_INSTRUCTIONS_AVAILABLE);
PF_XMMI_INSTRUCTIONS_AVAILABLE); cpu().SetWindowsIsProcessorFeaturePresent(PF_XMMI64_INSTRUCTIONS_AVAILABLE);
g_fake_cpu->SetWindowsIsProcessorFeaturePresent( cpu().SetWindowsIsProcessorFeaturePresent(PF_SSE3_INSTRUCTIONS_AVAILABLE);
PF_XMMI64_INSTRUCTIONS_AVAILABLE);
g_fake_cpu->SetWindowsIsProcessorFeaturePresent(
PF_SSE3_INSTRUCTIONS_AVAILABLE);
#elif defined(CPU_FEATURES_OS_DARWIN) #elif defined(CPU_FEATURES_OS_DARWIN)
g_fake_cpu->SetDarwinSysCtlByName("hw.optional.sse"); cpu().SetDarwinSysCtlByName("hw.optional.sse");
g_fake_cpu->SetDarwinSysCtlByName("hw.optional.sse2"); cpu().SetDarwinSysCtlByName("hw.optional.sse2");
g_fake_cpu->SetDarwinSysCtlByName("hw.optional.sse3"); cpu().SetDarwinSysCtlByName("hw.optional.sse3");
g_fake_cpu->SetDarwinSysCtlByName("hw.optional.supplementalsse3"); cpu().SetDarwinSysCtlByName("hw.optional.supplementalsse3");
g_fake_cpu->SetDarwinSysCtlByName("hw.optional.sse4_1"); cpu().SetDarwinSysCtlByName("hw.optional.sse4_1");
g_fake_cpu->SetDarwinSysCtlByName("hw.optional.sse4_2"); cpu().SetDarwinSysCtlByName("hw.optional.sse4_2");
#elif defined(CPU_FEATURES_OS_FREEBSD) #elif defined(CPU_FEATURES_OS_FREEBSD)
auto& fs = GetEmptyFilesystem(); auto& fs = GetEmptyFilesystem();
fs.CreateFile("/var/run/dmesg.boot", R"( fs.CreateFile("/var/run/dmesg.boot", R"(
@ -799,7 +906,7 @@ real memory = 2147418112 (2047 MB)
flags : fpu mmx sse sse2 sse3 ssse3 sse4_1 sse4_2 flags : fpu mmx sse sse2 sse3 ssse3 sse4_1 sse4_2
)"); )");
#endif #endif
g_fake_cpu->SetLeaves({ cpu().SetLeaves({
{{0x00000000, 0}, Leaf{0x0000000B, 0x756E6547, 0x6C65746E, 0x49656E69}}, {{0x00000000, 0}, Leaf{0x0000000B, 0x756E6547, 0x6C65746E, 0x49656E69}},
{{0x00000001, 0}, Leaf{0x00030673, 0x00100800, 0x41D8E3BF, 0xBFEBFBFF}}, {{0x00000001, 0}, Leaf{0x00030673, 0x00100800, 0x41D8E3BF, 0xBFEBFBFF}},
{{0x00000002, 0}, Leaf{0x61B3A001, 0x0000FFC2, 0x00000000, 0x00000000}}, {{0x00000002, 0}, Leaf{0x61B3A001, 0x0000FFC2, 0x00000000, 0x00000000}},
@ -850,16 +957,68 @@ flags : fpu mmx sse sse2 sse3 ssse3 sse4_1 sse4_2
#endif // !defined(CPU_FEATURES_OS_WINDOWS) #endif // !defined(CPU_FEATURES_OS_WINDOWS)
} }
// https://www.felixcloutier.com/x86/cpuid#example-3-1--example-of-cache-and-tlb-interpretation
TEST_F(CpuidX86Test, P4_CacheInfo)
{
cpu().SetLeaves({
{{0x00000000, 0}, Leaf{0x00000002, 0x756E6547, 0x6C65746E, 0x49656E69}},
{{0x00000001, 0}, Leaf{0x00000F0A, 0x00010808, 0x00000000, 0x3FEBFBFF}},
{{0x00000002, 0}, Leaf{0x665B5001, 0x00000000, 0x00000000, 0x007A7000}},
});
const auto info = GetX86CacheInfo();
EXPECT_EQ(info.size, 5);
EXPECT_EQ(info.levels[0].level, UNDEF);
EXPECT_EQ(info.levels[0].cache_type, CPU_FEATURE_CACHE_TLB);
EXPECT_EQ(info.levels[0].cache_size, 4 * KiB);
EXPECT_EQ(info.levels[0].ways, UNDEF);
EXPECT_EQ(info.levels[0].line_size, UNDEF);
EXPECT_EQ(info.levels[0].tlb_entries, 64);
EXPECT_EQ(info.levels[0].partitioning, 0);
EXPECT_EQ(info.levels[1].level, UNDEF);
EXPECT_EQ(info.levels[1].cache_type, CPU_FEATURE_CACHE_TLB);
EXPECT_EQ(info.levels[1].cache_size, 4 * KiB);
EXPECT_EQ(info.levels[1].ways, UNDEF);
EXPECT_EQ(info.levels[1].line_size, UNDEF);
EXPECT_EQ(info.levels[1].tlb_entries, 64);
EXPECT_EQ(info.levels[1].partitioning, 0);
EXPECT_EQ(info.levels[2].level, 1);
EXPECT_EQ(info.levels[2].cache_type, CPU_FEATURE_CACHE_DATA);
EXPECT_EQ(info.levels[2].cache_size, 8 * KiB);
EXPECT_EQ(info.levels[2].ways, 4);
EXPECT_EQ(info.levels[2].line_size, 64);
EXPECT_EQ(info.levels[2].tlb_entries, UNDEF);
EXPECT_EQ(info.levels[2].partitioning, 0);
EXPECT_EQ(info.levels[3].level, 1);
EXPECT_EQ(info.levels[3].cache_type, CPU_FEATURE_CACHE_INSTRUCTION);
EXPECT_EQ(info.levels[3].cache_size, 12 * KiB);
EXPECT_EQ(info.levels[3].ways, 8);
EXPECT_EQ(info.levels[3].line_size, UNDEF);
EXPECT_EQ(info.levels[3].tlb_entries, UNDEF);
EXPECT_EQ(info.levels[3].partitioning, 0);
EXPECT_EQ(info.levels[4].level, 2);
EXPECT_EQ(info.levels[4].cache_type, CPU_FEATURE_CACHE_DATA);
EXPECT_EQ(info.levels[4].cache_size, 256 * KiB);
EXPECT_EQ(info.levels[4].ways, 8);
EXPECT_EQ(info.levels[4].line_size, 64);
EXPECT_EQ(info.levels[4].tlb_entries, UNDEF);
EXPECT_EQ(info.levels[4].partitioning, 2);
}
// https://github.com/InstLatx64/InstLatx64/blob/master/GenuineIntel/GenuineIntel0000673_P3_KatmaiDP_CPUID.txt // https://github.com/InstLatx64/InstLatx64/blob/master/GenuineIntel/GenuineIntel0000673_P3_KatmaiDP_CPUID.txt
TEST_F(CpuidX86Test, P3) TEST_F(CpuidX86Test, P3)
{ {
// Pre AVX cpus don't have xsave // Pre AVX cpus don't have xsave
g_fake_cpu->SetOsBackupsExtendedRegisters(false); cpu().SetOsBackupsExtendedRegisters(false);
#if defined(CPU_FEATURES_OS_WINDOWS) #if defined(CPU_FEATURES_OS_WINDOWS)
g_fake_cpu->SetWindowsIsProcessorFeaturePresent( cpu().SetWindowsIsProcessorFeaturePresent(PF_XMMI_INSTRUCTIONS_AVAILABLE);
PF_XMMI_INSTRUCTIONS_AVAILABLE);
#elif defined(CPU_FEATURES_OS_DARWIN) #elif defined(CPU_FEATURES_OS_DARWIN)
g_fake_cpu->SetDarwinSysCtlByName("hw.optional.sse"); cpu().SetDarwinSysCtlByName("hw.optional.sse");
#elif defined(CPU_FEATURES_OS_FREEBSD) #elif defined(CPU_FEATURES_OS_FREEBSD)
auto& fs = GetEmptyFilesystem(); auto& fs = GetEmptyFilesystem();
fs.CreateFile("/var/run/dmesg.boot", R"( fs.CreateFile("/var/run/dmesg.boot", R"(
@ -875,7 +1034,7 @@ real memory = 2147418112 (2047 MB)
flags : fpu mmx sse flags : fpu mmx sse
)"); )");
#endif #endif
g_fake_cpu->SetLeaves({ cpu().SetLeaves({
{{0x00000000, 0}, Leaf{0x00000003, 0x756E6547, 0x6C65746E, 0x49656E69}}, {{0x00000000, 0}, Leaf{0x00000003, 0x756E6547, 0x6C65746E, 0x49656E69}},
{{0x00000001, 0}, Leaf{0x00000673, 0x00000000, 0x00000000, 0x0387FBFF}}, {{0x00000001, 0}, Leaf{0x00000673, 0x00000000, 0x00000000, 0x0387FBFF}},
{{0x00000002, 0}, Leaf{0x03020101, 0x00000000, 0x00000000, 0x0C040843}}, {{0x00000002, 0}, Leaf{0x03020101, 0x00000000, 0x00000000, 0x0C040843}},

View File

@ -167,15 +167,25 @@ TEST(StringViewTest, CpuFeatures_StringView_HasWord)
{ {
// Find flags at beginning, middle and end. // Find flags at beginning, middle and end.
EXPECT_TRUE( EXPECT_TRUE(
CpuFeatures_StringView_HasWord(str("first middle last"), "first")); CpuFeatures_StringView_HasWord(str("first middle last"), "first", ' '));
EXPECT_TRUE( EXPECT_TRUE(
CpuFeatures_StringView_HasWord(str("first middle last"), "middle")); CpuFeatures_StringView_HasWord(str("first middle last"), "middle", ' '));
EXPECT_TRUE(CpuFeatures_StringView_HasWord(str("first middle last"), "last")); EXPECT_TRUE(
CpuFeatures_StringView_HasWord(str("first middle last"), "last", ' '));
// Find flags at beginning, middle and end with a different separator
EXPECT_TRUE(
CpuFeatures_StringView_HasWord(str("first-middle-last"), "first", '-'));
EXPECT_TRUE(
CpuFeatures_StringView_HasWord(str("first-middle-last"), "middle", '-'));
EXPECT_TRUE(
CpuFeatures_StringView_HasWord(str("first-middle-last"), "last", '-'));
// Do not match partial flags // Do not match partial flags
EXPECT_FALSE( EXPECT_FALSE(
CpuFeatures_StringView_HasWord(str("first middle last"), "irst")); CpuFeatures_StringView_HasWord(str("first middle last"), "irst", ' '));
EXPECT_FALSE(CpuFeatures_StringView_HasWord(str("first middle last"), "mid")); EXPECT_FALSE(
EXPECT_FALSE(CpuFeatures_StringView_HasWord(str("first middle last"), "las")); CpuFeatures_StringView_HasWord(str("first middle last"), "mid", ' '));
EXPECT_FALSE(
CpuFeatures_StringView_HasWord(str("first middle last"), "las", ' '));
} }
TEST(StringViewTest, CpuFeatures_StringView_GetAttributeKeyValue) TEST(StringViewTest, CpuFeatures_StringView_GetAttributeKeyValue)