diff --git a/src/libos/src/entry.rs b/src/libos/src/entry.rs index 66e34afb..6d1a1e60 100644 --- a/src/libos/src/entry.rs +++ b/src/libos/src/entry.rs @@ -13,6 +13,14 @@ 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(); + } + let _ = backtrace::enable_backtrace("libocclum.signed.so", PrintFormat::Short); panic::catch_unwind(|| { backtrace::__rust_begin_short_backtrace(|| match do_boot(&path, &args) { diff --git a/src/libos/src/exceptions.c b/src/libos/src/exceptions.c new file mode 100644 index 00000000..3efc8564 --- /dev/null +++ b/src/libos/src/exceptions.c @@ -0,0 +1,101 @@ +#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); + uint64_t leaf; + uint64_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 = info->cpu_context.rax; + subleaf = 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/test/Makefile b/test/Makefile index e616d906..7023b082 100644 --- a/test/Makefile +++ b/test/Makefile @@ -4,7 +4,7 @@ PROJECT_DIR := $(realpath $(CUR_DIR)/../) # Dependencies: need to be compiled but not to run by any Makefile target TEST_DEPS := dev_null # Tests: need to be compiled and run by test-% target -TESTS := empty argv hello_world malloc mmap file getpid spawn pipe time truncate readdir mkdir link tls pthread uname rlimit client server server_epoll unix_socket cout +TESTS := empty argv hello_world malloc mmap file getpid spawn pipe time truncate readdir mkdir link tls pthread uname rlimit client server server_epoll unix_socket cout cpuid rdtsc # Benchmarks: need to be compiled and run by bench-% target BENCHES := spawn_and_exit_latency pipe_throughput unix_socket_throughput diff --git a/test/cpuid/Makefile b/test/cpuid/Makefile new file mode 100644 index 00000000..9e1b6dec --- /dev/null +++ b/test/cpuid/Makefile @@ -0,0 +1,5 @@ +include ../test_common.mk + +EXTRA_C_FLAGS := +EXTRA_LINK_FLAGS := +BIN_ARGS := diff --git a/test/cpuid/main.c b/test/cpuid/main.c new file mode 100644 index 00000000..83d51439 --- /dev/null +++ b/test/cpuid/main.c @@ -0,0 +1,93 @@ +#include +#include + +typedef struct t_cpuid { + unsigned int eax; + unsigned int ebx; + unsigned int ecx; + unsigned int edx; +} t_cpuid_t; + +static inline void native_cpuid(int leaf, int subleaf, t_cpuid_t *p) +{ + /* ecx is often an input as well as an output. */ + asm volatile("cpuid" + : "=a" (p->eax), + "=b" (p->ebx), + "=c" (p->ecx), + "=d" (p->edx) + : "a" (leaf), "c" (subleaf)); +} + +int main(int argc, char **argv) +{ + /* Gets CPUID information and tests the SGX support of the CPU */ + t_cpuid_t cpu = {0}; + int leaf = 1; + 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 smx (Safer Mode Extensions) set - SGX global enable is supported + printf("smx: %d\n", (cpu.ecx >> 6) & 1); // CPUID.1:ECX.[bit6] + + /* Extended feature bits (EAX=07H, ECX=0H)*/ + printf("\nExtended feature bits (EAX=07H, ECX=0H)\n"); + leaf = 7; + subleaf = 0; + cpu = {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); + + /* 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 + */ + + /* 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; + cpu = {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"); + leaf = 0x12; + subleaf = 1; + cpu = {0}; + 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; + cpu = {0}; + native_cpuid(leaf, subleaf, &cpu); + printf("eax: %x ebx: %x ecx: %x edx: %x\n", cpu.eax, cpu.ebx, cpu.ecx, cpu.edx); + } + + return 0; +} diff --git a/test/rdtsc/Makefile b/test/rdtsc/Makefile new file mode 100644 index 00000000..9e1b6dec --- /dev/null +++ b/test/rdtsc/Makefile @@ -0,0 +1,5 @@ +include ../test_common.mk + +EXTRA_C_FLAGS := +EXTRA_LINK_FLAGS := +BIN_ARGS := diff --git a/test/rdtsc/main.c b/test/rdtsc/main.c new file mode 100644 index 00000000..59f985ef --- /dev/null +++ b/test/rdtsc/main.c @@ -0,0 +1,19 @@ +#include +#include + +static inline uint64_t native_rdtsc() { + uint32_t hi, lo; + asm volatile("rdtsc" : "=a"(lo), "=d"(hi)); + return (( (uint64_t)lo)|( ((uint64_t)hi)<<32 )); +} + +int main(int argc, char **argv) +{ + /* Gets rdtsc information and tests the SGX support of the rdtsc */ + uint64_t r; + + r = native_rdtsc(); + printf("rdtsc: %lu\n", r); + + return 0; +}