Fix the emulation of RDTSC instruction with ocall
This commit is contained in:
parent
e2edaa49c0
commit
f7ce60e764
@ -54,6 +54,7 @@ enclave {
|
|||||||
|
|
||||||
void occlum_ocall_gettimeofday([out] struct timeval* tv);
|
void occlum_ocall_gettimeofday([out] struct timeval* tv);
|
||||||
void occlum_ocall_clock_gettime(clockid_t clockid, [out] struct timespec* ts);
|
void occlum_ocall_clock_gettime(clockid_t clockid, [out] struct timespec* ts);
|
||||||
|
void occlum_ocall_rdtsc([out] uint32_t* low, [out] uint32_t* high);
|
||||||
|
|
||||||
void occlum_ocall_nanosleep([in] const struct timespec* req);
|
void occlum_ocall_nanosleep([in] const struct timespec* req);
|
||||||
|
|
||||||
|
@ -1,9 +1,15 @@
|
|||||||
use super::*;
|
use super::*;
|
||||||
|
use process::Task;
|
||||||
use sgx_types::*;
|
use sgx_types::*;
|
||||||
|
|
||||||
const RDTSC_OPCODE: u16 = 0x310F;
|
const RDTSC_OPCODE: u16 = 0x310F;
|
||||||
static mut FAKE_RDTSC_VALUE: u64 = 0;
|
|
||||||
static FAKE_RDTSC_INC_VALUE: u64 = 1000;
|
extern "C" {
|
||||||
|
fn occlum_ocall_rdtsc(low: *mut u32, high: *mut u32) -> sgx_status_t;
|
||||||
|
fn __get_current_task() -> *const Task;
|
||||||
|
fn switch_td_to_kernel(task: *const Task);
|
||||||
|
fn switch_td_to_user(task: *const Task);
|
||||||
|
}
|
||||||
|
|
||||||
#[no_mangle]
|
#[no_mangle]
|
||||||
pub extern "C" fn handle_rdtsc_exception(info: *mut sgx_exception_info_t) -> u32 {
|
pub extern "C" fn handle_rdtsc_exception(info: *mut sgx_exception_info_t) -> u32 {
|
||||||
@ -15,11 +21,19 @@ pub extern "C" fn handle_rdtsc_exception(info: *mut sgx_exception_info_t) -> u32
|
|||||||
{
|
{
|
||||||
return EXCEPTION_CONTINUE_SEARCH;
|
return EXCEPTION_CONTINUE_SEARCH;
|
||||||
}
|
}
|
||||||
// rdtsc support here is temporary, only for SKL, later CPU's will support this inside enclave
|
|
||||||
unsafe {
|
unsafe {
|
||||||
FAKE_RDTSC_VALUE += FAKE_RDTSC_INC_VALUE;
|
let task = __get_current_task();
|
||||||
info.cpu_context.rax = (FAKE_RDTSC_VALUE & 0xFFFFFFFF);
|
switch_td_to_kernel(task);
|
||||||
info.cpu_context.rdx = (FAKE_RDTSC_VALUE >> 32);
|
let (low, high) = {
|
||||||
|
let mut low = 0;
|
||||||
|
let mut high = 0;
|
||||||
|
let sgx_status = occlum_ocall_rdtsc(&mut low, &mut high);
|
||||||
|
assert!(sgx_status == sgx_status_t::SGX_SUCCESS);
|
||||||
|
(low, high)
|
||||||
|
};
|
||||||
|
info.cpu_context.rax = low as u64;
|
||||||
|
info.cpu_context.rdx = high as u64;
|
||||||
|
switch_td_to_user(task);
|
||||||
}
|
}
|
||||||
info.cpu_context.rip += 2;
|
info.cpu_context.rip += 2;
|
||||||
|
|
||||||
|
@ -7,7 +7,7 @@ pub use self::process::{Status, IDLE_PROCESS};
|
|||||||
pub use self::process_table::get;
|
pub use self::process_table::get;
|
||||||
pub use self::sched::{do_sched_getaffinity, do_sched_setaffinity, do_sched_yield, CpuSet};
|
pub use self::sched::{do_sched_getaffinity, do_sched_setaffinity, do_sched_yield, CpuSet};
|
||||||
pub use self::spawn::{do_spawn, do_spawn_without_exec, ElfFile, FileAction, ProgramHeaderExt};
|
pub use self::spawn::{do_spawn, do_spawn_without_exec, ElfFile, FileAction, ProgramHeaderExt};
|
||||||
pub use self::task::{current_pid, get_current, run_task};
|
pub use self::task::{current_pid, get_current, run_task, Task};
|
||||||
pub use self::thread::{do_clone, do_set_tid_address, CloneFlags, ThreadGroup};
|
pub use self::thread::{do_clone, do_set_tid_address, CloneFlags, ThreadGroup};
|
||||||
pub use self::wait::{WaitQueue, Waiter};
|
pub use self::wait::{WaitQueue, Waiter};
|
||||||
|
|
||||||
@ -82,7 +82,6 @@ mod task;
|
|||||||
mod thread;
|
mod thread;
|
||||||
mod wait;
|
mod wait;
|
||||||
|
|
||||||
use self::task::Task;
|
|
||||||
use super::*;
|
use super::*;
|
||||||
use fs::{File, FileRef, FileTable};
|
use fs::{File, FileRef, FileTable};
|
||||||
use misc::ResourceLimitsRef;
|
use misc::ResourceLimitsRef;
|
||||||
|
@ -37,6 +37,28 @@ static uint64_t get_syscall_stack(struct Task* this_task) {
|
|||||||
#define RESET_CURRENT_TASK() \
|
#define RESET_CURRENT_TASK() \
|
||||||
__set_stack_guard(stack_guard);
|
__set_stack_guard(stack_guard);
|
||||||
|
|
||||||
|
void switch_td_to_kernel(const struct Task* task) {
|
||||||
|
thread_data_t* td = get_thread_data();
|
||||||
|
|
||||||
|
// TODO: do do not support stack expansion, need a new design on SGX2 platform.
|
||||||
|
// Set the stack_commit_addr to 0, as the result no stack expansion happens at any situations
|
||||||
|
__atomic_store_n(&td->stack_commit_addr, 0, __ATOMIC_RELAXED);
|
||||||
|
td->stack_base_addr = task->kernel_stack_base;
|
||||||
|
td->stack_limit_addr = task->kernel_stack_limit;
|
||||||
|
td->stack_commit_addr = task->kernel_stack_limit;
|
||||||
|
}
|
||||||
|
|
||||||
|
void switch_td_to_user(const struct Task* task) {
|
||||||
|
thread_data_t* td = get_thread_data();
|
||||||
|
|
||||||
|
// TODO: do do not support stack expansion, need a new design on SGX2 platform.
|
||||||
|
// Set the stack_commit_addr to 0, as the result no stack expansion happens at any situations
|
||||||
|
__atomic_store_n(&td->stack_commit_addr, 0, __ATOMIC_RELAXED);
|
||||||
|
td->stack_base_addr = task->user_stack_base;
|
||||||
|
td->stack_limit_addr = task->user_stack_limit;
|
||||||
|
td->stack_commit_addr = task->user_stack_limit;
|
||||||
|
}
|
||||||
|
|
||||||
int do_run_task(struct Task* task) {
|
int do_run_task(struct Task* task) {
|
||||||
jmp_buf libos_state = {0};
|
jmp_buf libos_state = {0};
|
||||||
thread_data_t* td = get_thread_data();
|
thread_data_t* td = get_thread_data();
|
||||||
@ -45,12 +67,7 @@ int do_run_task(struct Task* task) {
|
|||||||
task->kernel_stack_base = td->stack_base_addr;
|
task->kernel_stack_base = td->stack_base_addr;
|
||||||
task->kernel_stack_limit = td->stack_limit_addr;
|
task->kernel_stack_limit = td->stack_limit_addr;
|
||||||
|
|
||||||
//Do do not support stack expansion, need a new design on SGX2 platform.
|
switch_td_to_user(task);
|
||||||
//Set the stack_commit_addr to 0, as the result no stack expansion happens at any situations
|
|
||||||
__atomic_store_n(&td->stack_commit_addr, 0, __ATOMIC_RELAXED);
|
|
||||||
td->stack_base_addr = task->user_stack_base;
|
|
||||||
td->stack_limit_addr = task->user_stack_limit;
|
|
||||||
td->stack_commit_addr = task->user_stack_limit;
|
|
||||||
|
|
||||||
SET_CURRENT_TASK(task);
|
SET_CURRENT_TASK(task);
|
||||||
|
|
||||||
@ -67,13 +84,7 @@ int do_run_task(struct Task* task) {
|
|||||||
void do_exit_task(void) {
|
void do_exit_task(void) {
|
||||||
struct Task* task = __get_current_task();
|
struct Task* task = __get_current_task();
|
||||||
jmp_buf* jb = task->saved_state;
|
jmp_buf* jb = task->saved_state;
|
||||||
thread_data_t* td = get_thread_data();
|
|
||||||
|
|
||||||
//Do do not support stack expansion, need a new design on SGX2 platform.
|
switch_td_to_kernel(task);
|
||||||
//Set the stack_commit_addr to 0, as the result no stack expansion happens at any situations
|
|
||||||
__atomic_store_n(&td->stack_commit_addr, 0, __ATOMIC_RELAXED);
|
|
||||||
td->stack_base_addr = task->kernel_stack_base;
|
|
||||||
td->stack_limit_addr = task->kernel_stack_limit;
|
|
||||||
td->stack_commit_addr = task->kernel_stack_limit;
|
|
||||||
longjmp(*jb, 1);
|
longjmp(*jb, 1);
|
||||||
}
|
}
|
||||||
|
@ -24,3 +24,10 @@ int occlum_ocall_thread_getcpuclock(struct timespec *tp) {
|
|||||||
|
|
||||||
return clock_gettime(thread_clock_id, tp);
|
return clock_gettime(thread_clock_id, tp);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void occlum_ocall_rdtsc(uint32_t* low, uint32_t* high) {
|
||||||
|
uint64_t rax, rdx;
|
||||||
|
asm volatile("rdtsc" : "=a"(rax), "=d"(rdx));
|
||||||
|
*low = (uint32_t)rax;
|
||||||
|
*high = (uint32_t)rdx;
|
||||||
|
}
|
||||||
|
@ -1,19 +1,41 @@
|
|||||||
#include <stdio.h>
|
#include <stdio.h>
|
||||||
#include <stdint.h>
|
#include <stdint.h>
|
||||||
|
#include "test.h"
|
||||||
|
|
||||||
|
// ============================================================================
|
||||||
|
// Helper functions for rdtsc
|
||||||
|
// ============================================================================
|
||||||
|
|
||||||
static inline uint64_t native_rdtsc() {
|
static inline uint64_t native_rdtsc() {
|
||||||
uint32_t hi, lo;
|
uint64_t low, high;
|
||||||
asm volatile("rdtsc" : "=a"(lo), "=d"(hi));
|
asm volatile("rdtsc" : "=a"(low), "=d"(high));
|
||||||
return (( (uint64_t)lo)|( ((uint64_t)hi)<<32 ));
|
return (high << 32) | low;
|
||||||
}
|
}
|
||||||
|
|
||||||
int main(int argc, char **argv)
|
// ============================================================================
|
||||||
{
|
// Test cases for rdtsc
|
||||||
/* Gets rdtsc information and tests the SGX support of the rdtsc */
|
// ============================================================================
|
||||||
uint64_t r;
|
|
||||||
|
|
||||||
r = native_rdtsc();
|
|
||||||
printf("rdtsc: %lu\n", r);
|
|
||||||
|
|
||||||
|
int test_rdtsc() {
|
||||||
|
uint64_t start_count = native_rdtsc();
|
||||||
|
if (start_count == 0) {
|
||||||
|
THROW_ERROR("call rdtsc failed");
|
||||||
|
}
|
||||||
|
uint64_t end_count = native_rdtsc();
|
||||||
|
if (end_count <= start_count) {
|
||||||
|
THROW_ERROR("check rdtsc return value failed");
|
||||||
|
}
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// ============================================================================
|
||||||
|
// Test suite main
|
||||||
|
// ============================================================================
|
||||||
|
|
||||||
|
static test_case_t test_cases[] = {
|
||||||
|
TEST_CASE(test_rdtsc),
|
||||||
|
};
|
||||||
|
|
||||||
|
int main() {
|
||||||
|
return test_suite_run(test_cases, ARRAY_SIZE(test_cases));
|
||||||
|
}
|
||||||
|
Loading…
Reference in New Issue
Block a user