diff --git a/src/libos/src/entry.rs b/src/libos/src/entry.rs index 156f7907..ebde908a 100644 --- a/src/libos/src/entry.rs +++ b/src/libos/src/entry.rs @@ -1,4 +1,5 @@ use super::*; +use exception::*; use process::pid_t; use std::ffi::{CStr, CString, OsString}; use std::path::Path; @@ -14,13 +15,8 @@ pub extern "C" fn libos_boot(path_buf: *const c_char, argv: *const *const c_char } }; - // register exception handlers (support CPUID for now) - extern "C" { - fn register_exception_handlers() -> (); - } - unsafe { - register_exception_handlers(); - } + // register exception handlers (support cpuid & rdtsc for now) + register_exception_handlers(); let _ = backtrace::enable_backtrace("libocclum.signed.so", PrintFormat::Short); panic::catch_unwind(|| { diff --git a/src/libos/src/exception/cpuid.rs b/src/libos/src/exception/cpuid.rs new file mode 100644 index 00000000..dbaa9049 --- /dev/null +++ b/src/libos/src/exception/cpuid.rs @@ -0,0 +1,278 @@ +use super::*; +use sgx_types::*; +use std::collections::HashMap; +use std::rsgx_cpuidex; + +const CPUID_OPCODE: u16 = 0xA20F; +const CPUID_MIN_BASIC_LEAF: u32 = 0; +const CPUID_MAX_BASIC_LEAF: u32 = 0x17; +const CPUID_MIN_EXTEND_LEAF: u32 = 0x8000_0000; +const CPUID_MAX_EXTEND_LEAF: u32 = 0x8000_0008; +const CPUID_MAX_SUBLEAF: u32 = u32::max_value(); + +#[repr(C)] +#[derive(Eq, PartialEq, Hash, Clone, Copy)] +struct CpuIdInput { + leaf: u32, + subleaf: u32, +} + +#[repr(C)] +#[derive(Eq, PartialEq, Hash, Clone, Copy)] +struct CpuIdResult { + eax: u32, + ebx: u32, + ecx: u32, + edx: u32, +} + +struct CpuIdCache { + inner: HashMap, +} + +struct CpuId { + cache: CpuIdCache, + max_basic_leaf: u32, + max_extend_leaf: u32, +} + +impl CpuIdCache { + pub fn new(max_basic_leaf: u32, max_extend_leaf: u32) -> CpuIdCache { + let mut cache = CpuIdCache { + inner: HashMap::new(), + }; + cache.generate_cpuid_cache(max_basic_leaf, max_extend_leaf); + cache + } + + pub fn lookup(&self, key: &CpuIdInput) -> Option<&CpuIdResult> { + self.inner.get(key) + } + + fn insert(&mut self, key: CpuIdInput, value: CpuIdResult) { + // If EAX/EBX/ECX/EDX return 0, dismiss it + if (value.eax | value.ebx | value.ecx | value.edx) != 0 { + self.inner.insert(key, value); + } + } + + fn generate_cpuid_cache(&mut self, max_basic_leaf: u32, max_extend_leaf: u32) { + let mut sgx_support: bool = false; + // Generate basic leaf cpuid cache + for leaf in CPUID_MIN_BASIC_LEAF..=max_basic_leaf { + // Intel SGX Capability Enumeration Leaf, + // Leaf 12H sub-leaf 0 is supported if CPUID.(EAX=07H, ECX=0H):EBX[SGX] = 1. + if leaf == 0x12 && !sgx_support { + continue; + } + let mut max_subleaf = 0; + for subleaf in (0..) { + let cpuid_input = CpuIdInput { leaf, subleaf }; + let cpuid_result = get_cpuid_info_via_ocall(cpuid_input); + self.insert(cpuid_input, cpuid_result); + // Most leaf only supports (sub-leaf == 0), and many others can determine their + // maximum supported sub-leaf according to CPUID.(EAX=Leaf, ECX=0H). + if subleaf == 0 { + max_subleaf = match leaf { + // EAX Bits 31 - 00: Reports the maximum sub-leaf supported. + 0x7 | 0x14 | 0x17 => cpuid_result.eax, + // Reports valid resource type starting at bit position 1 of EDX. + // EDX Bit 00: Reserved. + // Bit 01: Supports L3 Cache Intel RDT Monitoring if 1. + // Bits 31 - 02: Reserved. + 0xF => cpuid_result.edx & 0x0000_0002 >> 1, + // Reports valid ResID starting at bit position 1 of EBX. + // EBX Bit 00: Reserved. + // Bit 01: Supports L3 Cache Allocation Technology if 1. + // Bit 02: Supports L2 Cache Allocation Technology if 1. + // Bits 31 - 03: Reserved. + 0x10 => match cpuid_result.ebx & 0x0000_0006 { + 0x0000_0006 => 2, + 0x0000_0002 => 1, + _ => 0, + }, + // Processor Extended State Enumeration, Sub-leaf n (0 ≤ n ≤ 63) + 0xD => 63, + // (Sub-leaf == 0) can not decide max_subleaf for these leaf, + // later match expression will decide the max_subleaf. + 0x4 | 0xB | 0x12 => CPUID_MAX_SUBLEAF, + // Default max_subleaf is 0. + _ => 0, + }; + if leaf == 0x7 { + // EBX Bit 02: Supports Intel® SGX Extensions if 1. + sgx_support = (cpuid_result.ebx & 0x0000_0004) != 0; + } + } + // These leafs determine the maximum supported sub-leaf according to + // the output of CPUID instruction at every iteration. + if max_subleaf == CPUID_MAX_SUBLEAF { + max_subleaf = match leaf { + // Deterministic Cache Parameters Leaf + // Sub-leaf index n+1 is invalid if subleaf n returns EAX[4:0] as 0. + 0x4 if (cpuid_result.eax & 0x1F) == 0 => subleaf, + // Extended Topology Enumeration Leaf + // If an input value n in ECX returns the invalid level-type of 0 in ECX[15:8], + // other input values with ECX > n also return 0 in ECX[15:8]. + 0xB if (cpuid_result.ecx & 0x0000_FF00) == 0 => subleaf, + // Intel SGX EPC Enumeration Leaf + // EAX Bit 03 - 00: Sub-leaf Type. + // 0000b: Indicates this sub-leaf is invalid. + 0x12 if subleaf >= 2 && (cpuid_result.eax & 0x0000000F) == 0 => subleaf, + // Condition not met. + _ => max_subleaf, + }; + } + if subleaf == max_subleaf { + break; + } + } + } + // Generate extend leaf cpuid cache + for leaf in CPUID_MIN_EXTEND_LEAF..=max_extend_leaf { + let cpuid_input = CpuIdInput { leaf, subleaf: 0 }; + let cpuid_result = get_cpuid_info_via_ocall(cpuid_input); + self.insert(cpuid_input, cpuid_result); + } + } +} + +impl CpuId { + pub fn new() -> CpuId { + let max_basic_leaf = match rsgx_cpuidex(CPUID_MIN_BASIC_LEAF as i32, 0) { + Ok(sgx_cpuinfo) => { + if is_valid_cpuid_basic_leaf(sgx_cpuinfo[0] as u32) { + sgx_cpuinfo[0] as u32 + } else { + panic!("invalid basic cpuid_level") + } + } + _ => panic!("failed to call sgx_cpuidex"), + }; + let max_extend_leaf = match rsgx_cpuidex(CPUID_MIN_EXTEND_LEAF as i32, 0) { + Ok(sgx_cpuinfo) => { + if is_valid_cpuid_extend_leaf(sgx_cpuinfo[0] as u32) { + sgx_cpuinfo[0] as u32 + } else { + panic!("invalid extend cpuid_xlevel") + } + } + _ => panic!("failed to call sgx_cpuidex"), + }; + let cpuid = CpuId { + cache: CpuIdCache::new(max_basic_leaf, max_extend_leaf), + max_basic_leaf, + max_extend_leaf, + }; + cpuid + } + + fn lookup_cpuid_from_cache(&self, cpuid_input: CpuIdInput) -> Result { + self.cache + .lookup(&cpuid_input) + .map(|result| result.clone()) + .ok_or_else(|| Error::new(Errno::ENOENT, "cpuid_result not found")) + } + + pub fn get_max_basic_leaf(&self) -> u32 { + self.max_basic_leaf + } + + pub fn get_max_extend_leaf(&self) -> u32 { + self.max_extend_leaf + } + + pub fn get_cpuid_info(&self, leaf: u32, subleaf: u32) -> CpuIdResult { + // If a value entered for CPUID.EAX is higher than the maximum input value + // for basic or extended function for that processor then the data for the + // highest basic information leaf is returned. + let fixed_leaf = if (CPUID_MIN_BASIC_LEAF..=self.max_basic_leaf).contains(&leaf) + || (CPUID_MIN_EXTEND_LEAF..=self.max_extend_leaf).contains(&leaf) + { + leaf + } else { + self.max_basic_leaf + }; + let fixed_subleaf = if is_cpuid_leaf_has_subleaves(fixed_leaf) { + subleaf + } else { + 0 + }; + let cpuid_input = CpuIdInput { + leaf: fixed_leaf, + subleaf: fixed_subleaf, + }; + let cpuid_result = match self.lookup_cpuid_from_cache(cpuid_input) { + Ok(cpuid_result) => cpuid_result, + // If a value entered for CPUID.EAX is less than or equal to the maximum input value + // and the leaf is not supported on that processor then 0 is returned in all the registers. + Err(error) => CpuIdResult { + eax: 0, + ebx: 0, + ecx: 0, + edx: 0, + }, + }; + cpuid_result + } +} + +lazy_static! { + static ref CPUID: CpuId = CpuId::new(); +} + +fn is_valid_cpuid_basic_leaf(leaf: u32) -> bool { + (CPUID_MIN_BASIC_LEAF..=CPUID_MAX_BASIC_LEAF).contains(&leaf) +} + +fn is_valid_cpuid_extend_leaf(leaf: u32) -> bool { + (CPUID_MIN_EXTEND_LEAF..=CPUID_MAX_EXTEND_LEAF).contains(&leaf) +} + +fn is_cpuid_leaf_has_subleaves(leaf: u32) -> bool { + const CPUID_LEAF_WITH_SUBLEAF: [u32; 9] = [0x4, 0x7, 0xB, 0xD, 0xF, 0x10, 0x12, 0x14, 0x17]; + CPUID_LEAF_WITH_SUBLEAF.contains(&leaf) +} + +// We cannot do OCalls when handling exceptions. So this function is only useful +// when we call setup_cpuid_info to initialize the CPUID singleton, +// which caches cpuid info for use when handling cpuid exception. +fn get_cpuid_info_via_ocall(cpuid_input: CpuIdInput) -> CpuIdResult { + let cpuid_result = match rsgx_cpuidex(cpuid_input.leaf as i32, cpuid_input.subleaf as i32) { + Ok(sgx_cpuinfo) => CpuIdResult { + eax: sgx_cpuinfo[0] as u32, + ebx: sgx_cpuinfo[1] as u32, + ecx: sgx_cpuinfo[2] as u32, + edx: sgx_cpuinfo[3] as u32, + }, + _ => panic!("failed to call sgx_cpuidex"), + }; + cpuid_result +} + +pub fn setup_cpuid_info() { + // Make lazy_static to be executed at runtime in order to be initialized + let max_basic_leaf = CPUID.get_max_basic_leaf(); +} + +#[no_mangle] +pub extern "C" fn handle_cpuid_exception(info: *mut sgx_exception_info_t) -> u32 { + let info = unsafe { &mut *info }; + let ip_opcode = unsafe { *(info.cpu_context.rip as *const u16) }; + if info.exception_vector != sgx_exception_vector_t::SGX_EXCEPTION_VECTOR_UD + || info.exception_type != sgx_exception_type_t::SGX_EXCEPTION_HARDWARE + || ip_opcode != CPUID_OPCODE + { + return EXCEPTION_CONTINUE_SEARCH; + } + let leaf = info.cpu_context.rax as u32; + let subleaf = info.cpu_context.rcx as u32; + let cpuid_result = CPUID.get_cpuid_info(leaf, subleaf); + info.cpu_context.rax = cpuid_result.eax as u64; + info.cpu_context.rbx = cpuid_result.ebx as u64; + info.cpu_context.rcx = cpuid_result.ecx as u64; + info.cpu_context.rdx = cpuid_result.edx as u64; + info.cpu_context.rip += 2; + + EXCEPTION_CONTINUE_EXECUTION +} diff --git a/src/libos/src/exception/mod.rs b/src/libos/src/exception/mod.rs new file mode 100644 index 00000000..f7664792 --- /dev/null +++ b/src/libos/src/exception/mod.rs @@ -0,0 +1,15 @@ +use self::cpuid::*; +use self::rdtsc::*; +use super::*; +use sgx_types::*; + +pub fn register_exception_handlers() { + setup_cpuid_info(); + unsafe { + sgx_register_exception_handler(1, handle_cpuid_exception); + sgx_register_exception_handler(1, handle_rdtsc_exception); + } +} + +mod cpuid; +mod rdtsc; diff --git a/src/libos/src/exception/rdtsc.rs b/src/libos/src/exception/rdtsc.rs new file mode 100644 index 00000000..b5f0f419 --- /dev/null +++ b/src/libos/src/exception/rdtsc.rs @@ -0,0 +1,27 @@ +use super::*; +use sgx_types::*; + +const RDTSC_OPCODE: u16 = 0x310F; +static mut FAKE_RDTSC_VALUE: u64 = 0; +static FAKE_RDTSC_INC_VALUE: u64 = 1000; + +#[no_mangle] +pub extern "C" fn handle_rdtsc_exception(info: *mut sgx_exception_info_t) -> u32 { + let info = unsafe { &mut *info }; + let ip_opcode = unsafe { *(info.cpu_context.rip as *const u16) }; + if info.exception_vector != sgx_exception_vector_t::SGX_EXCEPTION_VECTOR_UD + || info.exception_type != sgx_exception_type_t::SGX_EXCEPTION_HARDWARE + || ip_opcode != RDTSC_OPCODE + { + return EXCEPTION_CONTINUE_SEARCH; + } + // rdtsc support here is temporary, only for SKL, later CPU's will support this inside enclave + unsafe { + FAKE_RDTSC_VALUE += FAKE_RDTSC_INC_VALUE; + info.cpu_context.rax = (FAKE_RDTSC_VALUE & 0xFFFFFFFF); + info.cpu_context.rdx = (FAKE_RDTSC_VALUE >> 32); + } + info.cpu_context.rip += 2; + + EXCEPTION_CONTINUE_EXECUTION +} diff --git a/src/libos/src/exceptions.c b/src/libos/src/exceptions.c deleted file mode 100644 index 62df2e82..00000000 --- a/src/libos/src/exceptions.c +++ /dev/null @@ -1,101 +0,0 @@ -#include -#include - -#include "sgx_cpuid.h" -#include "sgx_trts_exception.h" - -#define CPUID_OPCODE 0xA20F -#define RDTSC_OPCODE 0x310F -#define SUPPORTED_CPUID_LEAF_NUM 30 -// the maximum supported sub-leaves may vary between different leaves and -// processors, fix it to a constant for now -#define SUPPORTED_CPUID_SUBLEAF_NUM 4 - -int supported_cpuid_leaves[] = { - // Basic CPUID Information - 0x00000000, 0x00000001, 0x00000002, 0x00000003, 0x00000004, 0x00000005, - 0x00000006, 0x00000007, 0x00000009, 0x0000000A, 0x0000000B, 0x0000000D, - 0x0000000F, 0x00000010, 0x00000012, 0x00000014, 0x00000015, 0x00000016, - 0x00000017, 0x00000018, 0x0000001F, - // Extended Function CPUID Information - 0x80000000, 0x80000001, 0x80000002, 0x80000003, 0x80000004, 0x80000005, - 0x80000006, 0x80000007, 0x80000008, -}; - -// holds cached CPUID information -typedef struct _CpuidInfo { - int leaf; - int subleaf; - int reg[4]; -} CpuidInfo; -CpuidInfo cpuid_info[SUPPORTED_CPUID_LEAF_NUM][SUPPORTED_CPUID_SUBLEAF_NUM]; - -// rdtsc support here is temporary, only for SKL, later CPU's will support this inside enclave -uint64_t fake_rdtsc_value = 0; -uint16_t fake_rdtsc_inc_value = 1000; - -void setup_cpuid_info() { - for (int i = 0; i < SUPPORTED_CPUID_LEAF_NUM; i++) { - for (int j = 0; j < SUPPORTED_CPUID_SUBLEAF_NUM; j++) { - int index = supported_cpuid_leaves[i]; - cpuid_info[i][j].leaf = index; - cpuid_info[i][j].subleaf = j; - if (sgx_cpuidex(cpuid_info[i][j].reg, index, j) != SGX_SUCCESS) - abort(); - } - } -} - -int handle_cpuid_exception(sgx_exception_info_t *info) { - uint16_t ip_opcode = *(uint16_t *)(info->cpu_context.rip); - uint32_t leaf; - uint32_t subleaf; - - if (info->exception_vector != SGX_EXCEPTION_VECTOR_UD || - info->exception_type != SGX_EXCEPTION_HARDWARE || - ip_opcode != CPUID_OPCODE) { - return EXCEPTION_CONTINUE_SEARCH; - } - - leaf = (uint32_t)info->cpu_context.rax; - subleaf = (uint32_t)info->cpu_context.rcx; - - for (int i = 0; i < SUPPORTED_CPUID_LEAF_NUM; i++) { - for (int j = 0; j < SUPPORTED_CPUID_SUBLEAF_NUM; j++) { - if (cpuid_info[i][j].leaf == leaf && - cpuid_info[i][j].subleaf == subleaf) { - info->cpu_context.rax = cpuid_info[i][j].reg[0]; - info->cpu_context.rbx = cpuid_info[i][j].reg[1]; - info->cpu_context.rcx = cpuid_info[i][j].reg[2]; - info->cpu_context.rdx = cpuid_info[i][j].reg[3]; - - info->cpu_context.rip += 2; - return EXCEPTION_CONTINUE_EXECUTION; - } - } - } - return EXCEPTION_CONTINUE_SEARCH; -} - -int handle_rdtsc_exception(sgx_exception_info_t *info) { - uint16_t ip_opcode = *(uint16_t *)(info->cpu_context.rip); - - if (info->exception_vector != SGX_EXCEPTION_VECTOR_UD || - info->exception_type != SGX_EXCEPTION_HARDWARE || - ip_opcode != RDTSC_OPCODE) { - return EXCEPTION_CONTINUE_SEARCH; - } - - fake_rdtsc_value += fake_rdtsc_inc_value; - info->cpu_context.rax = (uint32_t)(fake_rdtsc_value & 0xFFFFFFFF); - info->cpu_context.rdx = (uint32_t)(fake_rdtsc_value >> 32); - info->cpu_context.rip += 2; - - return EXCEPTION_CONTINUE_EXECUTION; -} - -void register_exception_handlers() { - setup_cpuid_info(); - sgx_register_exception_handler(true, handle_cpuid_exception); - sgx_register_exception_handler(true, handle_rdtsc_exception); -} diff --git a/src/libos/src/lib.rs b/src/libos/src/lib.rs index 0cfdef86..89342d92 100644 --- a/src/libos/src/lib.rs +++ b/src/libos/src/lib.rs @@ -42,6 +42,7 @@ mod prelude; mod config; mod entry; mod errno; +mod exception; mod fs; mod misc; mod process; diff --git a/test/cpuid/Makefile b/test/cpuid/Makefile index 9e1b6dec..3a0100d2 100644 --- a/test/cpuid/Makefile +++ b/test/cpuid/Makefile @@ -1,5 +1,10 @@ +DEPS_FILE := test_cpuid.txt include ../test_common.mk EXTRA_C_FLAGS := EXTRA_LINK_FLAGS := BIN_ARGS := + +test_cpuid.txt: + @/usr/bin/cpuid -r > $@ + @mv $@ $(IMAGE_DIR)/$@ diff --git a/test/cpuid/main.c b/test/cpuid/main.c index c773167d..2e5ed4be 100644 --- a/test/cpuid/main.c +++ b/test/cpuid/main.c @@ -1,6 +1,14 @@ -#include +#include #include +#include +#include #include +#include +#include "test.h" + +// ============================================================================ +// Helper struct & functions for cpuid +// ============================================================================ typedef struct t_cpuid { unsigned int eax; @@ -21,71 +29,254 @@ static inline void native_cpuid(int leaf, int subleaf, t_cpuid_t *p) : "a" (leaf), "c" (subleaf)); } -int main(int argc, char **argv) -{ - /* Gets CPUID information and tests the SGX support of the CPU */ +static bool is_cpuidinfo_equal(int leaf, t_cpuid_t *cpu, t_cpuid_t *cpu_sgx) { + /* Leaf 01H CPUID.EBX is related with logical processor. */ + if (leaf == 1) { + return ((cpu->eax == cpu_sgx->eax) && + (cpu->ecx == cpu_sgx->ecx) && + (cpu->edx == cpu_sgx->edx)); + } + /* Leaf 0BH CPUID.EDX is related with logical processor. */ + if (leaf == 0xB) { + return ((cpu->eax == cpu_sgx->eax) && + (cpu->ebx == cpu_sgx->ebx) && + (cpu->ecx == cpu_sgx->ecx)); + } + return ((cpu->eax == cpu_sgx->eax) && + (cpu->ebx == cpu_sgx->ebx) && + (cpu->ecx == cpu_sgx->ecx) && + (cpu->edx == cpu_sgx->edx)); +} + +static int g_max_basic_leaf = 0; +static int g_max_extend_leaf = 0; + +// ============================================================================ +// Test cases for cpuid +// ============================================================================ + +static int test_cpuid_with_basic_leaf_zero() { t_cpuid_t cpu; - int leaf = 1; + int leaf = 0; + int subleaf = 0; + + native_cpuid(leaf, subleaf, &cpu); + // cpu should support sgx + if (cpu.eax < 0x12) { + throw_error("failed to call cpuid with eax=0"); + } + g_max_basic_leaf = cpu.eax; + return 0; +} + +static int test_cpuid_with_basic_leaf_zero_with_subleaf() { + t_cpuid_t cpu; + int leaf = 0; + int subleaf = 256; + + native_cpuid(leaf, subleaf, &cpu); + if (cpu.eax != g_max_basic_leaf) { + throw_error("failed to call cpuid with eax=0 and subleaf"); + } + return 0; +} + +static int test_cpuid_with_extend_leaf_zero() { + t_cpuid_t cpu; + int leaf = 0x80000000; + int subleaf = 0; + + native_cpuid(leaf, subleaf, &cpu); + if (cpu.eax < 0x80000000) { + throw_error("failed to call cpuid with eax=0x80000000"); + } + g_max_extend_leaf = cpu.eax; + return 0; +} + +static int test_cpuid_with_extend_leaf_zero_with_subleaf() { + t_cpuid_t cpu; + int leaf = 0x80000000; + int subleaf = 256; + + native_cpuid(leaf, subleaf, &cpu); + if (cpu.eax != g_max_extend_leaf) { + throw_error("failed to call cpuid with eax=0x80000000"); + } + return 0; +} + +static int test_cpuid_with_basic_leaf_one() { + t_cpuid_t cpu; + int leaf = 0x1; int subleaf = 0; native_cpuid(leaf, subleaf, &cpu); - printf("eax: %x ebx: %x ecx: %x edx: %x\n", cpu.eax, cpu.ebx, cpu.ecx, cpu.edx); printf("Stepping %d\n", cpu.eax & 0xF); // Bit 3-0 printf("Model %d\n", (cpu.eax >> 4) & 0xF); // Bit 7-4 printf("Family %d\n", (cpu.eax >> 8) & 0xF); // Bit 11-8 printf("Processor Type %d\n", (cpu.eax >> 12) & 0x3); // Bit 13-12 printf("Extended Model %d\n", (cpu.eax >> 16) & 0xF); // Bit 19-16 printf("Extended Family %d\n", (cpu.eax >> 20) & 0xFF); // Bit 27-20 + if (cpu.eax == 0) { + throw_error("faild to call cpuid with eax=1"); + } + if (!((cpu.ecx >> 6) & 1)) { + throw_error("smx is not enabled"); + } + return 0; +} - // if smx (Safer Mode Extensions) set - SGX global enable is supported - printf("smx: %d\n", (cpu.ecx >> 6) & 1); // CPUID.1:ECX.[bit6] +static int test_cpuid_with_sgx_verify() { + t_cpuid_t cpu; + int leaf = 0x7; + int subleaf = 0; - /* Extended feature bits (EAX=07H, ECX=0H)*/ - printf("\nExtended feature bits (EAX=07H, ECX=0H)\n"); - leaf = 7; - subleaf = 0; native_cpuid(leaf, subleaf, &cpu); - printf("eax: %x ebx: %x ecx: %x edx: %x\n", cpu.eax, cpu.ebx, cpu.ecx, cpu.edx); - //CPUID.(EAX=07H, ECX=0H):EBX.SGX = 1, // Bit 02: SGX. Supports Intel® Software Guard Extensions (Intel® SGX Extensions) if 1. - printf("SGX is available: %d\n", (cpu.ebx >> 2) & 0x1); + if (((cpu.ebx >> 2) & 0x1) != 1) { + throw_error("failed to call cpuid to verify sgx"); + } + return 0; +} - /* SGX has to be enabled in MSR.IA32_Feature_Control.SGX_Enable - check with msr-tools: rdmsr -ax 0x3a - SGX_Enable is Bit 18 - if SGX_Enable = 0 no leaf information will appear. - for more information check Intel Docs Architectures-software-developer-system-programming-manual - 35.1 Architectural MSRS - */ +static int test_cpuid_with_sgx_enumeration() { + t_cpuid_t cpu; + int leaf = 0x12; + int subleaf = 0; - /* CPUID Leaf 12H, Sub-Leaf 0 Enumeration of Intel SGX Capabilities (EAX=12H,ECX=0) */ - printf("\nCPUID Leaf 12H, Sub-Leaf 0 of Intel SGX Capabilities (EAX=12H,ECX=0)\n"); - leaf = 0x12; - subleaf = 0; native_cpuid(leaf, subleaf, &cpu); - printf("eax: %x ebx: %x ecx: %x edx: %x\n", cpu.eax, cpu.ebx, cpu.ecx, cpu.edx); - printf("Sgx 1 supported: %d\n", cpu.eax & 0x1); printf("Sgx 2 supported: %d\n", (cpu.eax >> 1) & 0x1); - printf("MaxEnclaveSize_Not64: %x\n", cpu.edx & 0xFF); - printf("MaxEnclaveSize_64: %x\n", (cpu.edx >> 8) & 0xFF); - - /* CPUID Leaf 12H, Sub-Leaf 1 Enumeration of Intel SGX Capabilities (EAX=12H,ECX=1) */ - printf("\nCPUID Leaf 12H, Sub-Leaf 1 of Intel SGX Capabilities (EAX=12H,ECX=1)\n"); + if (((cpu.eax & 0x1) | ((cpu.eax >> 1) & 0x1)) == 0) { + throw_error("failed to call cpuid to get SGX Capbilities"); + } + if (((cpu.edx & 0xFF) | ((cpu.edx >> 8) & 0xFF)) == 0) { + throw_error("get MaxEnclaveSize failed"); + } leaf = 0x12; subleaf = 1; native_cpuid(leaf, subleaf, &cpu); - printf("eax: %x ebx: %x ecx: %x edx: %x\n", cpu.eax, cpu.ebx, cpu.ecx, cpu.edx); - - int i; - for (i=2; i<4; i++) { - /* CPUID Leaf 12H, Sub-Leaf i Enumeration of Intel SGX Capabilities (EAX=12H,ECX=i) */ - printf("\nCPUID Leaf 12H, Sub-Leaf %d of Intel SGX Capabilities (EAX=12H,ECX=%d)\n", i, i); - leaf = 0x12; - subleaf = i; - native_cpuid(leaf, subleaf, &cpu); - printf("eax: %x ebx: %x ecx: %x edx: %x\n", cpu.eax, cpu.ebx, cpu.ecx, cpu.edx); + if ((cpu.eax | cpu.ebx | cpu.ecx | cpu.edx) == 0) { + throw_error("failed to call cpuid to get SGX Attributes"); } - return 0; } + +static int test_cpuid_with_invalid_leaf() { + t_cpuid_t cpu; + int leaf = 0x8; + int subleaf = 0; + + native_cpuid(leaf, subleaf, &cpu); + if (cpu.eax | cpu.ebx | cpu.ecx | cpu.edx) { + throw_error("faild to call cpuid with invalid leaf 0x8"); + } + + leaf = 0xC; + native_cpuid(leaf, subleaf, &cpu); + if (cpu.eax | cpu.ebx | cpu.ecx | cpu.edx) { + throw_error("faild to call cpuid with invalid leaf 0xC"); + } + + leaf = 0xE; + native_cpuid(leaf, subleaf, &cpu); + if (cpu.eax | cpu.ebx | cpu.ecx | cpu.edx) { + throw_error("faild to call cpuid with invalid leaf 0xE"); + } + + leaf = 0x11; + native_cpuid(leaf, subleaf, &cpu); + if (cpu.eax | cpu.ebx | cpu.ecx | cpu.edx) { + throw_error("faild to call cpuid with invalid leaf 0x11"); + } + return 0; +} + +static int test_cpuid_with_oversized_leaf() { + t_cpuid_t cpu; + int leaf = g_max_extend_leaf + 1; + int subleaf = 1; + native_cpuid(leaf, subleaf, &cpu); + + t_cpuid_t cpu_max; + leaf = g_max_basic_leaf; + subleaf = 1; + native_cpuid(leaf, subleaf, &cpu_max); + + if ((cpu.eax != cpu_max.eax) || (cpu.ebx != cpu_max.ebx) || + (cpu.ecx != cpu_max.ecx) || (cpu.edx != cpu_max.edx)) { + throw_error("failed to call cpuid with oversize leaf"); + } + return 0; +} + +static int test_cpuid_with_random_leaf() { + t_cpuid_t cpu; + srand((int)time(NULL)); + int leaf = 0; + int subleaf = 0; + + for (int i = 0; i < 5; i++) { + leaf = rand(); + subleaf = rand(); + native_cpuid(leaf, subleaf, &cpu); + printf("random leaf:%x, subleaf:%x \n", leaf, subleaf); + printf("eax: %x ebx: %x ecx: %x edx: %x\n", cpu.eax, cpu.ebx, cpu.ecx, cpu.edx); + } + return 0; +} + +#define BUFF_SIZE (1024) +static int test_cpuid_with_host_cpuidinfo() { + char buff[BUFF_SIZE] = {0}; + FILE * fp = fopen("./test_cpuid.txt","r"); + if (fp == NULL) { + throw_error("failed to open host cpuid.txt"); + } + while (fgets(buff, BUFF_SIZE, fp)) { + uint32_t leaf = 0; + uint32_t subleaf = 0; + t_cpuid_t cpu = {0}; + int num = sscanf(buff, " %x %x: eax=%x ebx=%x ecx=%x edx=%x", &leaf, &subleaf, + &cpu.eax, &cpu.ebx, &cpu.ecx, &cpu.edx); + if (num != 6) { + continue; + } + t_cpuid_t cpu_sgx = {0}; + native_cpuid(leaf, subleaf, &cpu_sgx); + if (!is_cpuidinfo_equal(leaf, &cpu, &cpu_sgx)) { + printf("leaf:0x%x subleaf:0x%x\n", leaf, subleaf); + printf("ori_eax:0x%x ori_ebx:0x%x ori_ecx:0x%x ori_edx:0x%x\n", + cpu.eax, cpu.ebx, cpu.ecx, cpu.edx); + printf("sgx_eax:0x%x sgx_ebx:0x%x sgx_ecx:0x%x sgx_edx:0x%x\n", + cpu_sgx.eax, cpu_sgx.ebx, cpu_sgx.ecx, cpu_sgx.edx); + throw_error("failed to check cpuid info"); + } + } + fclose(fp); + return 0; +} + +// ============================================================================ +// Test suite main +// ============================================================================ + +static test_case_t test_cases[] = { + TEST_CASE(test_cpuid_with_basic_leaf_zero), + TEST_CASE(test_cpuid_with_basic_leaf_zero_with_subleaf), + TEST_CASE(test_cpuid_with_extend_leaf_zero), + TEST_CASE(test_cpuid_with_extend_leaf_zero_with_subleaf), + TEST_CASE(test_cpuid_with_basic_leaf_one), + TEST_CASE(test_cpuid_with_sgx_verify), + TEST_CASE(test_cpuid_with_sgx_enumeration), + TEST_CASE(test_cpuid_with_invalid_leaf), + TEST_CASE(test_cpuid_with_oversized_leaf), + TEST_CASE(test_cpuid_with_random_leaf), + TEST_CASE(test_cpuid_with_host_cpuidinfo), +}; + +int main() { + return test_suite_run(test_cases, ARRAY_SIZE(test_cases)); +} diff --git a/test/test_common.mk b/test/test_common.mk index 72ea2540..cf924395 100644 --- a/test/test_common.mk +++ b/test/test_common.mk @@ -27,7 +27,7 @@ LINK_FLAGS = $(C_FLAGS) -pie $(EXTRA_LINK_FLAGS) # Build ############################################################################# -all: $(ALL_BUILD_SUBDIRS) $(BIN) +all: $(ALL_BUILD_SUBDIRS) $(BIN) $(DEPS_FILE) $(ALL_BUILD_SUBDIRS): @mkdir -p $@ @@ -52,7 +52,6 @@ $(BUILD_DIR)/test/obj/$(TEST_NAME)/%.o: %.c $(BUILD_DIR)/test/obj/$(TEST_NAME)/%.o: %.cc @$(CXX) $(C_FLAGS) -c $< -o $@ @echo "CXX <= $@" - ############################################################################# # Test ############################################################################# @@ -69,4 +68,4 @@ test-native: ############################################################################# clean: - @-$(RM) -f $(BIN) $(C_OBJS) $(CXX_OBJS) + @-$(RM) -f $(BIN) $(DEPS_FILE) $(C_OBJS) $(CXX_OBJS) diff --git a/tools/docker/Dockerfile b/tools/docker/Dockerfile index 8ac3e790..63b4ae81 100644 --- a/tools/docker/Dockerfile +++ b/tools/docker/Dockerfile @@ -38,6 +38,13 @@ RUN apt-get update && apt-get install -y --no-install-recommends \ apt-get clean && \ rm -rf /var/lib/apt/lists/* +# Install depend cpuid test tool +WORKDIR /tmp +RUN wget http://www.etallen.com/cpuid/cpuid-20180519.x86_64.tar.gz && \ + tar -xf ./cpuid-20180519.x86_64.tar.gz && \ + cp ./cpuid-20180519/cpuid /usr/bin/ && \ + rm -rf /tmp/cpuid-20180519* + # Install SGX SDK WORKDIR /tmp RUN git clone https://github.com/occlum/linux-sgx . && \