#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
#define cpuid(func, subfunc, cpuinfo)\
do { (void)(func); (void)(subfunc); (void)(cpuinfo); } while (0)
#endif
#ifndef bit_SSE2
#define bit_SSE2 (1 << 26)
#endif
#ifndef bit_CLFLUSH
#define bit_CLFLUSH (1 << 23)
#endif
#ifndef bit_CLFLUSHOPT
#define bit_CLFLUSHOPT (1 << 23)
#endif
#ifndef bit_CLWB
#define bit_CLWB (1 << 24)
#endif
static int
is_cpu_feature_present(unsigned func, unsigned reg, unsigned bit)
{
unsigned cpuinfo[4] = { 0 };
cpuid(0x0, 0x0, cpuinfo);
if (cpuinfo[EAX_IDX] < func)
return 0;
cpuid(func, 0x0, cpuinfo);
return (cpuinfo[reg] & bit) != 0;
}
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;
}
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;
}
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;
}
int
is_cpu_clwb_present(void)
{
if (!is_cpu_genuine_intel())
return 0;
int ret = is_cpu_feature_present(0x7, EBX_IDX, bit_CLWB);
LOG(4, "CLWB %ssupported", ret == 0 ? "not " : "");
return ret;
}