diff options
Diffstat (limited to 'src/pmdk/src/libpmem2/x86_64/cpu.c')
-rw-r--r-- | src/pmdk/src/libpmem2/x86_64/cpu.c | 174 |
1 files changed, 174 insertions, 0 deletions
diff --git a/src/pmdk/src/libpmem2/x86_64/cpu.c b/src/pmdk/src/libpmem2/x86_64/cpu.c new file mode 100644 index 000000000..7c368c5d3 --- /dev/null +++ b/src/pmdk/src/libpmem2/x86_64/cpu.c @@ -0,0 +1,174 @@ +// SPDX-License-Identifier: BSD-3-Clause +/* Copyright 2015-2020, Intel Corporation */ + +/* + * cpu.c -- CPU features detection + */ + +/* + * Reference: + * http://www.intel.com/content/www/us/en/processors/ + * architectures-software-developer-manuals.html + * + * https://support.amd.com/TechDocs/24594.pdf + */ + +#include <string.h> + +#include "out.h" +#include "cpu.h" + +#define EAX_IDX 0 +#define EBX_IDX 1 +#define ECX_IDX 2 +#define EDX_IDX 3 + +#if defined(__x86_64__) || defined(__amd64__) + +#include <cpuid.h> + +static inline void +cpuid(unsigned func, unsigned subfunc, unsigned cpuinfo[4]) +{ + __cpuid_count(func, subfunc, cpuinfo[EAX_IDX], cpuinfo[EBX_IDX], + cpuinfo[ECX_IDX], cpuinfo[EDX_IDX]); +} + +#elif defined(_M_X64) || defined(_M_AMD64) + +#include <intrin.h> + +static inline void +cpuid(unsigned func, unsigned subfunc, unsigned cpuinfo[4]) +{ + __cpuidex(cpuinfo, func, subfunc); +} + +#else + +#error unsupported compiler + +#endif + +#ifndef bit_CLFLUSH +#define bit_CLFLUSH (1 << 19) +#endif + +#ifndef bit_CLFLUSHOPT +#define bit_CLFLUSHOPT (1 << 23) +#endif + +#ifndef bit_CLWB +#define bit_CLWB (1 << 24) +#endif + +#ifndef bit_AVX +#define bit_AVX (1 << 28) +#endif + +#ifndef bit_AVX512F +#define bit_AVX512F (1 << 16) +#endif + +/* + * is_cpu_feature_present -- (internal) checks if CPU feature is supported + */ +static int +is_cpu_feature_present(unsigned func, unsigned reg, unsigned bit) +{ + unsigned cpuinfo[4] = { 0 }; + + /* check CPUID level first */ + cpuid(0x0, 0x0, cpuinfo); + if (cpuinfo[EAX_IDX] < func) + return 0; + + cpuid(func, 0x0, cpuinfo); + return (cpuinfo[reg] & bit) != 0; +} + +/* + * is_cpu_genuine_intel -- checks for genuine Intel CPU + */ +int +is_cpu_genuine_intel(void) +{ + unsigned cpuinfo[4] = { 0 }; + + union { + char name[0x20]; + unsigned cpuinfo[3]; + } vendor; + + memset(&vendor, 0, sizeof(vendor)); + + cpuid(0x0, 0x0, cpuinfo); + + vendor.cpuinfo[0] = cpuinfo[EBX_IDX]; + vendor.cpuinfo[1] = cpuinfo[EDX_IDX]; + vendor.cpuinfo[2] = cpuinfo[ECX_IDX]; + + LOG(4, "CPU vendor: %s", vendor.name); + return (strncmp(vendor.name, "GenuineIntel", + sizeof(vendor.name))) == 0; +} + +/* + * is_cpu_clflush_present -- checks if CLFLUSH instruction is supported + */ +int +is_cpu_clflush_present(void) +{ + int ret = is_cpu_feature_present(0x1, EDX_IDX, bit_CLFLUSH); + LOG(4, "CLFLUSH %ssupported", ret == 0 ? "not " : ""); + + return ret; +} + +/* + * is_cpu_clflushopt_present -- checks if CLFLUSHOPT instruction is supported + */ +int +is_cpu_clflushopt_present(void) +{ + int ret = is_cpu_feature_present(0x7, EBX_IDX, bit_CLFLUSHOPT); + LOG(4, "CLFLUSHOPT %ssupported", ret == 0 ? "not " : ""); + + return ret; +} + +/* + * is_cpu_clwb_present -- checks if CLWB instruction is supported + */ +int +is_cpu_clwb_present(void) +{ + int ret = is_cpu_feature_present(0x7, EBX_IDX, bit_CLWB); + LOG(4, "CLWB %ssupported", ret == 0 ? "not " : ""); + + return ret; +} + +/* + * is_cpu_avx_present -- checks if AVX instructions are supported + */ +int +is_cpu_avx_present(void) +{ + int ret = is_cpu_feature_present(0x1, ECX_IDX, bit_AVX); + LOG(4, "AVX %ssupported", ret == 0 ? "not " : ""); + + return ret; +} + +/* + * is_cpu_avx512f_present -- checks if AVX-512f instructions are supported + */ +int +is_cpu_avx512f_present(void) +{ + int ret = is_cpu_feature_present(0x7, EBX_IDX, bit_AVX512F); + LOG(4, "AVX512f %ssupported", ret == 0 ? "not " : ""); + + return ret; +} |