mirror of
https://github.com/anrieff/libcpuid
synced 2024-12-16 16:35:45 +00:00
Related to issue #67: Information about the availability of SGX
Initial commit adding support for detection of SGX. Not tested yet. Increment version number due to binary incompatibility of the sizes of cpu_raw_data_t and cpu_id_t.
This commit is contained in:
parent
94843e8fd5
commit
4cf8cfa862
16 changed files with 340 additions and 20 deletions
|
@ -40,3 +40,9 @@ Version 0.3.0 (2016-07-09):
|
|||
of L4 cache.
|
||||
* MSR functions supported on FreeBSD.
|
||||
* INFO_VOLTAGE request supported by cpu_msrinfo().
|
||||
|
||||
Version 0.4.0 (2016-09-30):
|
||||
* A backwards-incompatible change, since the sizeof cpu_raw_data_t and
|
||||
cpu_id_t are now different.
|
||||
* Better detection of AMD clock multiplier with msrinfo.
|
||||
* Support for Intel SGX detection
|
||||
|
|
|
@ -1,4 +1,4 @@
|
|||
AC_INIT([libcpuid CPU Identification library], [0.3.0], [libcpuid-devel@lists.sourceforge.net], [libcpuid])
|
||||
AC_INIT([libcpuid CPU Identification library], [0.4.0], [libcpuid-devel@lists.sourceforge.net], [libcpuid])
|
||||
AC_CONFIG_SRCDIR([libcpuid/libcpuid.h])
|
||||
AC_CONFIG_HEADERS([config.h])
|
||||
AC_CONFIG_MACRO_DIR([m4])
|
||||
|
@ -21,7 +21,8 @@ dnl 12:1:0 Version 0.2.0: two more fields to cpu_id_t
|
|||
dnl 12:1:1 Version 0.2.1: more processors support
|
||||
dnl 12:1:2 Version 0.2.2: more processors support, *BSD/Solaris support, updates to MSR stuff
|
||||
dnl 13:0:0 Version 0.3.0: increment max Intel leaf 04 entries to 8
|
||||
LIBCPUID_CURRENT=13
|
||||
dnl 14:0:0 Version 0.4.0: add one more field per cpu_raw_data_t and cpu_id_t
|
||||
LIBCPUID_CURRENT=14
|
||||
LIBCPUID_AGE=0
|
||||
LIBCPUID_REVISION=0
|
||||
AC_SUBST([LIBCPUID_AGE])
|
||||
|
|
|
@ -90,6 +90,7 @@ typedef enum {
|
|||
NEED_CLOCK_IC,
|
||||
NEED_RDMSR,
|
||||
NEED_SSE_UNIT_SIZE,
|
||||
NEED_SGX,
|
||||
} output_data_switch;
|
||||
|
||||
int need_input = 0,
|
||||
|
@ -100,7 +101,8 @@ int need_input = 0,
|
|||
need_timed_clockreport = 0,
|
||||
verbose_level = 0,
|
||||
need_version = 0,
|
||||
need_cpulist = 0;
|
||||
need_cpulist = 0,
|
||||
need_sgx = 0;
|
||||
|
||||
#define MAX_REQUESTS 32
|
||||
int num_requests = 0;
|
||||
|
@ -145,6 +147,7 @@ matchtable[] = {
|
|||
{ NEED_CLOCK_IC , "--clock-ic" , 1},
|
||||
{ NEED_RDMSR , "--rdmsr" , 0},
|
||||
{ NEED_SSE_UNIT_SIZE, "--sse-size" , 1},
|
||||
{ NEED_SGX , "--sgx" , 1},
|
||||
};
|
||||
|
||||
const int sz_match = (sizeof(matchtable) / sizeof(matchtable[0]));
|
||||
|
@ -458,6 +461,25 @@ static void print_info(output_data_switch query, struct cpu_raw_data_t* raw,
|
|||
data->detection_hints[CPU_HINT_SSE_SIZE_AUTH] ? "authoritative" : "non-authoritative");
|
||||
break;
|
||||
}
|
||||
case NEED_SGX:
|
||||
{
|
||||
fprintf(fout, "SGX: %d (%s)\n", data->sgx.present, data->sgx.present ? "present" : "absent");
|
||||
if (data->sgx.present) {
|
||||
fprintf(fout, "SGX max enclave size (32-bit): 2^%d\n", data->sgx.max_enclave_32bit);
|
||||
fprintf(fout, "SGX max enclave size (64-bit): 2^%d\n", data->sgx.max_enclave_64bit);
|
||||
fprintf(fout, "SGX1 extensions : %d (%s)\n", data->sgx.flags[INTEL_SGX1], data->sgx.flags[INTEL_SGX1] ? "present" : "absent");
|
||||
fprintf(fout, "SGX2 extensions : %d (%s)\n", data->sgx.flags[INTEL_SGX2], data->sgx.flags[INTEL_SGX2] ? "present" : "absent");
|
||||
fprintf(fout, "SGX MISCSELECT : %08x\n", data->sgx.misc_select);
|
||||
fprintf(fout, "SGX SECS.ATTRIBUTES mask : %016llx\n", data->sgx.secs_attributes);
|
||||
fprintf(fout, "SGX SECS.XSAVE feature mask : %016llx\n", data->sgx.secs_xfrm);
|
||||
fprintf(fout, "SGX EPC sections count : %d\n", data->sgx.num_epc_sections);
|
||||
for (i = 0; i < data->sgx.num_epc_sections; i++) {
|
||||
struct cpu_epc_t epc = cpuid_get_epc(i, raw);
|
||||
fprintf(fout, "SGX EPC section #%-8d: start = %llx, size = %llu\n", epc.start_addr, epc.length);
|
||||
}
|
||||
}
|
||||
break;
|
||||
}
|
||||
default:
|
||||
fprintf(fout, "How did you get here?!?\n");
|
||||
break;
|
||||
|
|
9
debian/changelog
vendored
9
debian/changelog
vendored
|
@ -1,3 +1,12 @@
|
|||
libcpuid (0.4.0) unstable; urgency=log
|
||||
|
||||
* 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).
|
||||
|
||||
-- Georgiev, Veselin <anrieff@gmail.com> Thu, 30 Sep 2016 22:39:37 +0300
|
||||
|
||||
libcpuid (0.3.0) unstable; urgency=low
|
||||
|
||||
* A backwards-incompatible change, since the sizeof cpu_raw_data_t and
|
||||
|
|
|
@ -5,7 +5,7 @@ all: libcpuid.lib
|
|||
ASM = ml64 /nologo
|
||||
CC = cl.exe /nologo /TC
|
||||
OPTFLAGS = /MT
|
||||
DEFINES = /D "VERSION=\"0.3.0\""
|
||||
DEFINES = /D "VERSION=\"0.4.0\""
|
||||
OBJECTS = masm-x64.obj asm-bits.obj cpuid_main.obj libcpuid_util.obj recog_amd.obj recog_intel.obj rdtsc.obj
|
||||
|
||||
libcpuid.lib: $(OBJECTS)
|
||||
|
|
|
@ -12,7 +12,7 @@ all: libcpuid.lib
|
|||
|
||||
CC = cl.exe /nologo /TC
|
||||
OPTFLAGS = /MT
|
||||
DEFINES = /D "VERSION=\"0.3.0\""
|
||||
DEFINES = /D "VERSION=\"0.4.0\""
|
||||
OBJECTS = asm-bits.obj cpuid_main.obj libcpuid_util.obj recog_amd.obj recog_intel.obj rdtsc.obj
|
||||
|
||||
libcpuid.lib: $(OBJECTS)
|
||||
|
|
|
@ -6,6 +6,52 @@ if len(sys.argv) != 2:
|
|||
print "Usage: check-consistency <path>"
|
||||
sys.exit(0)
|
||||
|
||||
|
||||
def getEnumElements(enumName):
|
||||
f = open("%s/libcpuid.h" % sys.argv[1], "r")
|
||||
l = []
|
||||
on = False
|
||||
rexp = re.compile(r'^\s*([A-Z0-9_]+)(\s*=\s*[A-Z0-9_]+)?\s*,.*$')
|
||||
for line in f:
|
||||
line = line.strip()
|
||||
if line.startswith("typedef enum {"):
|
||||
l = []
|
||||
on = True
|
||||
if on and rexp.match(line):
|
||||
l.append(rexp.findall(line)[0][0])
|
||||
if on and line.startswith("} "):
|
||||
on = False
|
||||
if line.find(enumName) != -1:
|
||||
return l
|
||||
f.close()
|
||||
return []
|
||||
|
||||
def getConstant(constantName):
|
||||
f = open("%s/libcpuid_constants.h" % sys.argv[1], "r")
|
||||
value = 0
|
||||
for line in f:
|
||||
items = line.strip().split()
|
||||
if len(items) >= 3 and items[0] == "#define" and items[1] == constantName:
|
||||
value = int(items[2])
|
||||
f.close()
|
||||
return value
|
||||
|
||||
def checkEnumSize(enumName, constantName):
|
||||
print "Checking enum `%s':" % enumName,
|
||||
count = len(getEnumElements(enumName)) - 1
|
||||
themax = getConstant(constantName)
|
||||
print "%d elements; max size (%s=%d)..." % (count, constantName, themax),
|
||||
if count > themax:
|
||||
print "FAILED"
|
||||
global firstError
|
||||
firstError = False
|
||||
else:
|
||||
print "OK"
|
||||
|
||||
checkEnumSize("cpu_feature_t", "CPU_FLAGS_MAX")
|
||||
checkEnumSize("cpu_hint_t", "CPU_HINTS_MAX")
|
||||
checkEnumSize("cpu_sgx_feature_t", "SGX_FLAGS_MAX")
|
||||
|
||||
rexp = re.compile('.*{ CPU_FEATURE_([^,]+), "([^"]+)".*}.*')
|
||||
print "Finding features:"
|
||||
for fn in glob.glob("%s/*.c" % sys.argv[1]):
|
||||
|
|
|
@ -386,6 +386,18 @@ int cpuid_get_raw_data(struct cpu_raw_data_t* data)
|
|||
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);
|
||||
}
|
||||
|
||||
|
@ -417,6 +429,14 @@ int cpuid_serialize_raw_data(struct cpu_raw_data_t* data, const char* filename)
|
|||
fprintf(f, "intel_fn11[%d]=%08x %08x %08x %08x\n", i,
|
||||
data->intel_fn11[i][0], data->intel_fn11[i][1],
|
||||
data->intel_fn11[i][2], data->intel_fn11[i][3]);
|
||||
for (i = 0; i < MAX_INTELFN12H_LEVEL; i++)
|
||||
fprintf(f, "intel_fn12h[%d]=%08x %08x %08x %08x\n", i,
|
||||
data->intel_fn12h[i][0], data->intel_fn12h[i][1],
|
||||
data->intel_fn12h[i][2], data->intel_fn12h[i][3]);
|
||||
for (i = 0; i < MAX_INTELFN14H_LEVEL; i++)
|
||||
fprintf(f, "intel_fn14h[%d]=%08x %08x %08x %08x\n", i,
|
||||
data->intel_fn14h[i][0], data->intel_fn14h[i][1],
|
||||
data->intel_fn14h[i][2], data->intel_fn14h[i][3]);
|
||||
|
||||
if (strcmp(filename, ""))
|
||||
fclose(f);
|
||||
|
@ -462,9 +482,11 @@ int cpuid_deserialize_raw_data(struct cpu_raw_data_t* data, const char* filename
|
|||
}
|
||||
syntax = 1;
|
||||
syntax = syntax && parse_token("basic_cpuid", token, value, data->basic_cpuid, MAX_CPUID_LEVEL, &recognized);
|
||||
syntax = syntax && parse_token("ext_cpuid", token, value, data->ext_cpuid, MAX_EXT_CPUID_LEVEL, &recognized);
|
||||
syntax = syntax && parse_token("intel_fn4", token, value, data->intel_fn4, MAX_INTELFN4_LEVEL, &recognized);
|
||||
syntax = syntax && parse_token("intel_fn11", token, value, data->intel_fn11, MAX_INTELFN11_LEVEL, &recognized);
|
||||
syntax = syntax && parse_token("ext_cpuid", token, value, data->ext_cpuid, MAX_EXT_CPUID_LEVEL, &recognized);
|
||||
syntax = syntax && parse_token("intel_fn4", token, value, data->intel_fn4, MAX_INTELFN4_LEVEL, &recognized);
|
||||
syntax = syntax && parse_token("intel_fn11", token, value, data->intel_fn11, MAX_INTELFN11_LEVEL, &recognized);
|
||||
syntax = syntax && parse_token("intel_fn12h", token, value, data->intel_fn12h, MAX_INTELFN12H_LEVEL, &recognized);
|
||||
syntax = syntax && parse_token("intel_fn14h", token, value, data->intel_fn14h, MAX_INTELFN14H_LEVEL, &recognized);
|
||||
if (!syntax) {
|
||||
warnf("Error: %s:%d: Syntax error\n", filename, cur_line);
|
||||
fclose(f);
|
||||
|
@ -622,6 +644,7 @@ const char* cpu_feature_str(cpu_feature_t feature)
|
|||
{ CPU_FEATURE_SHA_NI, "sha_ni" },
|
||||
{ CPU_FEATURE_AVX512BW, "avx512bw" },
|
||||
{ CPU_FEATURE_AVX512VL, "avx512vl" },
|
||||
{ CPU_FEATURE_SGX, "sgx" },
|
||||
};
|
||||
unsigned i, n = COUNT_OF(matchtable);
|
||||
if (n != NUM_CPU_FEATURES) {
|
||||
|
|
|
@ -31,3 +31,4 @@ cpuid_get_total_cpus @27
|
|||
cpu_msr_driver_open_core @28
|
||||
cpuid_get_vendor @29
|
||||
cpu_rdmsr_range @30
|
||||
cpuid_get_epc @31
|
||||
|
|
|
@ -41,7 +41,7 @@ RSC=rc.exe
|
|||
# PROP Intermediate_Dir "Release"
|
||||
# PROP Target_Dir ""
|
||||
# ADD BASE CPP /nologo /W3 /GX /O2 /D "WIN32" /D "NDEBUG" /D "_MBCS" /D "_LIB" /YX /FD /c
|
||||
# ADD CPP /nologo /MD /W3 /GX /O2 /D "NDEBUG" /D "WIN32" /D "_MBCS" /D "_LIB" /D VERSION=\"0.3.0\" /YX /FD /c
|
||||
# ADD CPP /nologo /MD /W3 /GX /O2 /D "NDEBUG" /D "WIN32" /D "_MBCS" /D "_LIB" /D VERSION=\"0.4.0\" /YX /FD /c
|
||||
# ADD BASE RSC /l 0x409 /d "NDEBUG"
|
||||
# ADD RSC /l 0x409 /d "NDEBUG"
|
||||
BSC32=bscmake.exe
|
||||
|
@ -64,7 +64,7 @@ LIB32=link.exe -lib
|
|||
# PROP Intermediate_Dir "Debug"
|
||||
# PROP Target_Dir ""
|
||||
# ADD BASE CPP /nologo /W3 /Gm /GX /ZI /Od /D "WIN32" /D "_DEBUG" /D "_MBCS" /D "_LIB" /YX /FD /GZ /c
|
||||
# ADD CPP /nologo /MDd /W3 /Gm /GX /ZI /Od /D "_DEBUG" /D "WIN32" /D "_MBCS" /D "_LIB" /D VERSION=\"0.3.0\" /YX /FD /GZ /c
|
||||
# ADD CPP /nologo /MDd /W3 /Gm /GX /ZI /Od /D "_DEBUG" /D "WIN32" /D "_MBCS" /D "_LIB" /D VERSION=\"0.4.0\" /YX /FD /GZ /c
|
||||
# ADD BASE RSC /l 0x409 /d "_DEBUG"
|
||||
# ADD RSC /l 0x409 /d "_DEBUG"
|
||||
BSC32=bscmake.exe
|
||||
|
|
|
@ -29,7 +29,7 @@
|
|||
* \file libcpuid.h
|
||||
* \author Veselin Georgiev
|
||||
* \date Oct 2008
|
||||
* \version 0.3.0
|
||||
* \version 0.4.0
|
||||
*
|
||||
* Version history:
|
||||
*
|
||||
|
@ -53,6 +53,10 @@
|
|||
* 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
|
||||
|
@ -133,6 +137,81 @@ struct cpu_raw_data_t {
|
|||
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;
|
||||
};
|
||||
|
||||
/**
|
||||
|
@ -265,6 +344,9 @@ struct cpu_id_t {
|
|||
* @see Hints
|
||||
*/
|
||||
uint8_t detection_hints[CPU_HINTS_MAX];
|
||||
|
||||
/** contains information about SGX features if the processor, if present */
|
||||
struct cpu_sgx_t sgx;
|
||||
};
|
||||
|
||||
/**
|
||||
|
@ -395,6 +477,7 @@ typedef enum {
|
|||
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 */
|
||||
/* termination: */
|
||||
NUM_CPU_FEATURES,
|
||||
} cpu_feature_t;
|
||||
|
@ -410,6 +493,36 @@ typedef enum {
|
|||
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
|
||||
*/
|
||||
|
@ -756,6 +869,32 @@ int cpu_clock_by_ic(int millis, int runs);
|
|||
*/
|
||||
int cpu_clock(void);
|
||||
|
||||
|
||||
/**
|
||||
* @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
|
||||
*
|
||||
|
|
|
@ -28,3 +28,4 @@ cpuid_get_total_cpus
|
|||
cpu_msr_driver_open_core
|
||||
cpuid_get_vendor
|
||||
cpu_rdmsr_range
|
||||
cpuid_get_epc
|
||||
|
|
|
@ -39,6 +39,9 @@
|
|||
#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__ */
|
||||
|
|
|
@ -102,7 +102,7 @@
|
|||
<ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'">
|
||||
<ClCompile>
|
||||
<Optimization>Disabled</Optimization>
|
||||
<PreprocessorDefinitions>WIN32;_DEBUG;_LIB;VERSION="0.3.0";%(PreprocessorDefinitions)</PreprocessorDefinitions>
|
||||
<PreprocessorDefinitions>WIN32;_DEBUG;_LIB;VERSION="0.4.0";%(PreprocessorDefinitions)</PreprocessorDefinitions>
|
||||
<MinimalRebuild>true</MinimalRebuild>
|
||||
<BasicRuntimeChecks>EnableFastChecks</BasicRuntimeChecks>
|
||||
<RuntimeLibrary>MultiThreadedDebug</RuntimeLibrary>
|
||||
|
@ -117,7 +117,7 @@
|
|||
<ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Debug|x64'">
|
||||
<ClCompile>
|
||||
<Optimization>Disabled</Optimization>
|
||||
<PreprocessorDefinitions>WIN32;_DEBUG;_LIB;VERSION="0.3.0";%(PreprocessorDefinitions)</PreprocessorDefinitions>
|
||||
<PreprocessorDefinitions>WIN32;_DEBUG;_LIB;VERSION="0.4.0";%(PreprocessorDefinitions)</PreprocessorDefinitions>
|
||||
<BasicRuntimeChecks>EnableFastChecks</BasicRuntimeChecks>
|
||||
<RuntimeLibrary>MultiThreadedDebug</RuntimeLibrary>
|
||||
<PrecompiledHeader>
|
||||
|
@ -130,7 +130,7 @@
|
|||
</ItemDefinitionGroup>
|
||||
<ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Release|Win32'">
|
||||
<ClCompile>
|
||||
<PreprocessorDefinitions>WIN32;NDEBUG;_LIB;VERSION="0.3.0";%(PreprocessorDefinitions)</PreprocessorDefinitions>
|
||||
<PreprocessorDefinitions>WIN32;NDEBUG;_LIB;VERSION="0.4.0";%(PreprocessorDefinitions)</PreprocessorDefinitions>
|
||||
<RuntimeLibrary>MultiThreaded</RuntimeLibrary>
|
||||
<PrecompiledHeader>
|
||||
</PrecompiledHeader>
|
||||
|
@ -142,7 +142,7 @@
|
|||
</ItemDefinitionGroup>
|
||||
<ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='ReleaseDLL|Win32'">
|
||||
<ClCompile>
|
||||
<PreprocessorDefinitions>WIN32;NDEBUG;_LIB;VERSION="0.3.0";%(PreprocessorDefinitions)</PreprocessorDefinitions>
|
||||
<PreprocessorDefinitions>WIN32;NDEBUG;_LIB;VERSION="0.4.0";%(PreprocessorDefinitions)</PreprocessorDefinitions>
|
||||
<RuntimeLibrary>MultiThreaded</RuntimeLibrary>
|
||||
<PrecompiledHeader>
|
||||
</PrecompiledHeader>
|
||||
|
@ -157,7 +157,7 @@
|
|||
</ItemDefinitionGroup>
|
||||
<ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Release|x64'">
|
||||
<ClCompile>
|
||||
<PreprocessorDefinitions>WIN32;NDEBUG;_LIB;VERSION="0.3.0";%(PreprocessorDefinitions)</PreprocessorDefinitions>
|
||||
<PreprocessorDefinitions>WIN32;NDEBUG;_LIB;VERSION="0.4.0";%(PreprocessorDefinitions)</PreprocessorDefinitions>
|
||||
<RuntimeLibrary>MultiThreaded</RuntimeLibrary>
|
||||
<PrecompiledHeader>
|
||||
</PrecompiledHeader>
|
||||
|
@ -169,7 +169,7 @@
|
|||
</ItemDefinitionGroup>
|
||||
<ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='ReleaseDLL|x64'">
|
||||
<ClCompile>
|
||||
<PreprocessorDefinitions>WIN32;NDEBUG;_LIB;VERSION="0.3.0";%(PreprocessorDefinitions)</PreprocessorDefinitions>
|
||||
<PreprocessorDefinitions>WIN32;NDEBUG;_LIB;VERSION="0.4.0";%(PreprocessorDefinitions)</PreprocessorDefinitions>
|
||||
<RuntimeLibrary>MultiThreaded</RuntimeLibrary>
|
||||
<PrecompiledHeader>
|
||||
</PrecompiledHeader>
|
||||
|
|
|
@ -19,7 +19,7 @@
|
|||
<Tool
|
||||
Name="VCCLCompilerTool"
|
||||
Optimization="0"
|
||||
PreprocessorDefinitions="VERSION=\"0.3.0\""
|
||||
PreprocessorDefinitions="VERSION=\"0.4.0\""
|
||||
MinimalRebuild="TRUE"
|
||||
BasicRuntimeChecks="3"
|
||||
RuntimeLibrary="3"
|
||||
|
@ -60,7 +60,7 @@
|
|||
CharacterSet="2">
|
||||
<Tool
|
||||
Name="VCCLCompilerTool"
|
||||
PreprocessorDefinitions="VERSION=\"0.3.0\""
|
||||
PreprocessorDefinitions="VERSION=\"0.4.0\""
|
||||
RuntimeLibrary="2"
|
||||
UsePrecompiledHeader="0"
|
||||
WarningLevel="3"
|
||||
|
@ -99,7 +99,7 @@
|
|||
CharacterSet="2">
|
||||
<Tool
|
||||
Name="VCCLCompilerTool"
|
||||
PreprocessorDefinitions="VERSION=\"0.3.0\""
|
||||
PreprocessorDefinitions="VERSION=\"0.4.0\""
|
||||
RuntimeLibrary="2"
|
||||
UsePrecompiledHeader="0"
|
||||
WarningLevel="3"
|
||||
|
|
|
@ -349,6 +349,7 @@ static void load_intel_features(struct cpu_raw_data_t* raw, struct cpu_id_t* dat
|
|||
{ 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 },
|
||||
|
@ -783,6 +784,68 @@ static intel_model_t get_model_code(struct cpu_id_t* data)
|
|||
#undef HAVE
|
||||
}
|
||||
|
||||
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) {
|
||||
debugf(2, "SGX: epc section request for %d returned null, no more EPC sections.\n", i);
|
||||
data->sgx.num_epc_sections = i;
|
||||
break;
|
||||
}
|
||||
}
|
||||
if (data->sgx.num_epc_sections == -1) {
|
||||
debugf(1, "SGX: warning: seems to be infinitude of EPC sections.\n");
|
||||
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];
|
||||
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:
|
||||
struct cpu_epc_t retval = {0, 0};
|
||||
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_t brand_code;
|
||||
|
@ -814,6 +877,12 @@ int cpuid_identify_intel(struct cpu_raw_data_t* raw, struct cpu_id_t* data, stru
|
|||
debugf(2, "Detected Intel model code: %d\n", model_code);
|
||||
|
||||
internal->code.intel = brand_code;
|
||||
|
||||
if (data->flags[CPU_FEATURE_SGX]) {
|
||||
debugf(2, "SGX seems to be present, decoding...\n");
|
||||
// if SGX is indicated by the CPU, verify its presence:
|
||||
decode_intel_sgx_features(raw, data);
|
||||
}
|
||||
|
||||
internal->score = match_cpu_codename(cpudb_intel, COUNT_OF(cpudb_intel), data,
|
||||
brand_code, model_code);
|
||||
|
|
Loading…
Reference in a new issue