diff --git a/ChangeLog b/ChangeLog index f5d33b3..9919d37 100644 --- a/ChangeLog +++ b/ChangeLog @@ -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 diff --git a/configure.ac b/configure.ac index c6638ed..c28e957 100644 --- a/configure.ac +++ b/configure.ac @@ -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]) diff --git a/cpuid_tool/cpuid_tool.c b/cpuid_tool/cpuid_tool.c index c5ee6f6..f3f4037 100644 --- a/cpuid_tool/cpuid_tool.c +++ b/cpuid_tool/cpuid_tool.c @@ -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; diff --git a/debian/changelog b/debian/changelog index ab7a6f4..fbb159c 100644 --- a/debian/changelog +++ b/debian/changelog @@ -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 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 diff --git a/libcpuid/Makefile.x64 b/libcpuid/Makefile.x64 index 6ad46b8..9a9b0b0 100644 --- a/libcpuid/Makefile.x64 +++ b/libcpuid/Makefile.x64 @@ -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) diff --git a/libcpuid/Makefile.x86 b/libcpuid/Makefile.x86 index df37303..3d3df2d 100644 --- a/libcpuid/Makefile.x86 +++ b/libcpuid/Makefile.x86 @@ -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) diff --git a/libcpuid/check-consistency.py b/libcpuid/check-consistency.py index 077a848..11d05d0 100755 --- a/libcpuid/check-consistency.py +++ b/libcpuid/check-consistency.py @@ -6,6 +6,52 @@ if len(sys.argv) != 2: print "Usage: check-consistency " 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]): diff --git a/libcpuid/cpuid_main.c b/libcpuid/cpuid_main.c index 7c79fed..2235d99 100644 --- a/libcpuid/cpuid_main.c +++ b/libcpuid/cpuid_main.c @@ -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) { diff --git a/libcpuid/exports.def b/libcpuid/exports.def index 72b78e8..9bda55b 100644 --- a/libcpuid/exports.def +++ b/libcpuid/exports.def @@ -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 diff --git a/libcpuid/libcpuid.dsp b/libcpuid/libcpuid.dsp index 20a61e4..43c3a4b 100644 --- a/libcpuid/libcpuid.dsp +++ b/libcpuid/libcpuid.dsp @@ -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 diff --git a/libcpuid/libcpuid.h b/libcpuid/libcpuid.h index 33fc241..0db9bf2 100644 --- a/libcpuid/libcpuid.h +++ b/libcpuid/libcpuid.h @@ -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 * diff --git a/libcpuid/libcpuid.sym b/libcpuid/libcpuid.sym index d0c61e4..64869a0 100644 --- a/libcpuid/libcpuid.sym +++ b/libcpuid/libcpuid.sym @@ -28,3 +28,4 @@ cpuid_get_total_cpus cpu_msr_driver_open_core cpuid_get_vendor cpu_rdmsr_range +cpuid_get_epc diff --git a/libcpuid/libcpuid_constants.h b/libcpuid/libcpuid_constants.h index c5ebcb9..3ddb6d5 100644 --- a/libcpuid/libcpuid_constants.h +++ b/libcpuid/libcpuid_constants.h @@ -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__ */ diff --git a/libcpuid/libcpuid_vc10.vcxproj b/libcpuid/libcpuid_vc10.vcxproj index d6b3f25..b320dbe 100644 --- a/libcpuid/libcpuid_vc10.vcxproj +++ b/libcpuid/libcpuid_vc10.vcxproj @@ -102,7 +102,7 @@ Disabled - WIN32;_DEBUG;_LIB;VERSION="0.3.0";%(PreprocessorDefinitions) + WIN32;_DEBUG;_LIB;VERSION="0.4.0";%(PreprocessorDefinitions) true EnableFastChecks MultiThreadedDebug @@ -117,7 +117,7 @@ Disabled - WIN32;_DEBUG;_LIB;VERSION="0.3.0";%(PreprocessorDefinitions) + WIN32;_DEBUG;_LIB;VERSION="0.4.0";%(PreprocessorDefinitions) EnableFastChecks MultiThreadedDebug @@ -130,7 +130,7 @@ - WIN32;NDEBUG;_LIB;VERSION="0.3.0";%(PreprocessorDefinitions) + WIN32;NDEBUG;_LIB;VERSION="0.4.0";%(PreprocessorDefinitions) MultiThreaded @@ -142,7 +142,7 @@ - WIN32;NDEBUG;_LIB;VERSION="0.3.0";%(PreprocessorDefinitions) + WIN32;NDEBUG;_LIB;VERSION="0.4.0";%(PreprocessorDefinitions) MultiThreaded @@ -157,7 +157,7 @@ - WIN32;NDEBUG;_LIB;VERSION="0.3.0";%(PreprocessorDefinitions) + WIN32;NDEBUG;_LIB;VERSION="0.4.0";%(PreprocessorDefinitions) MultiThreaded @@ -169,7 +169,7 @@ - WIN32;NDEBUG;_LIB;VERSION="0.3.0";%(PreprocessorDefinitions) + WIN32;NDEBUG;_LIB;VERSION="0.4.0";%(PreprocessorDefinitions) MultiThreaded diff --git a/libcpuid/libcpuid_vc71.vcproj b/libcpuid/libcpuid_vc71.vcproj index 94e43c4..a7b6765 100644 --- a/libcpuid/libcpuid_vc71.vcproj +++ b/libcpuid/libcpuid_vc71.vcproj @@ -19,7 +19,7 @@ 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);