Handle cpuid and rdtsc instruction

Init support for cpuid and rdtsc instruction handling in occlum.

This patch includes:
1. cpuid exception handler for all information leaves;
2. rdtsc exception handler;
3. handler registration;
4. cpuid test;
5. rdtsc test.

Signed-off-by: 散樗 <kailun.qkl@antfin.com>
This commit is contained in:
散樗 2019-07-18 13:51:50 +08:00
parent 56c69b5f3c
commit 2553298b1d
7 changed files with 232 additions and 1 deletions

@ -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) {

101
src/libos/src/exceptions.c Normal file

@ -0,0 +1,101 @@
#include <stdlib.h>
#include <stdbool.h>
#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);
}

@ -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

5
test/cpuid/Makefile Normal file

@ -0,0 +1,5 @@
include ../test_common.mk
EXTRA_C_FLAGS :=
EXTRA_LINK_FLAGS :=
BIN_ARGS :=

93
test/cpuid/main.c Normal file

@ -0,0 +1,93 @@
#include <stdio.h>
#include <stdint.h>
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;
}

5
test/rdtsc/Makefile Normal file

@ -0,0 +1,5 @@
include ../test_common.mk
EXTRA_C_FLAGS :=
EXTRA_LINK_FLAGS :=
BIN_ARGS :=

19
test/rdtsc/main.c Normal file

@ -0,0 +1,19 @@
#include <stdio.h>
#include <stdint.h>
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;
}