summaryrefslogtreecommitdiffstats
path: root/src/pmdk/src/libpmem2/x86_64/cpu.c
diff options
context:
space:
mode:
Diffstat (limited to 'src/pmdk/src/libpmem2/x86_64/cpu.c')
-rw-r--r--src/pmdk/src/libpmem2/x86_64/cpu.c174
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;
+}