[crates] Implement vdso for time precision
This commit is contained in:
parent
9404da7cf8
commit
b2f721d1bb
@ -6,6 +6,7 @@ enclave {
|
||||
from "sgx_tprotected_fs.edl" import *;
|
||||
from "sgx_net.edl" import *;
|
||||
from "sgx_occlum_utils.edl" import *;
|
||||
from "sgx_vdso_time_ocalls.edl" import *;
|
||||
|
||||
include "sgx_quote.h"
|
||||
include "occlum_edl_types.h"
|
||||
@ -148,9 +149,6 @@ enclave {
|
||||
|
||||
int occlum_ocall_thread_getcpuclock([out] struct timespec* ts) propagate_errno;
|
||||
|
||||
void occlum_ocall_gettimeofday([out] struct timeval* tv);
|
||||
void occlum_ocall_clock_gettime(clockid_t clockid, [out] struct timespec* ts);
|
||||
void occlum_ocall_clock_getres(clockid_t clockid, [out] struct timespec* res);
|
||||
void occlum_ocall_rdtsc([out] uint32_t* low, [out] uint32_t* high);
|
||||
void occlum_ocall_get_timerslack([out] int *timer_slack);
|
||||
|
||||
|
@ -25,7 +25,8 @@ rcore-fs-devfs = { path = "../../deps/sefs/rcore-fs-devfs" }
|
||||
resolv-conf = { path = "../../deps/resolv-conf" }
|
||||
serde = { path = "../../deps/serde-sgx/serde", features = ["derive"] }
|
||||
serde_json = { path = "../../deps/serde-json-sgx" }
|
||||
errno = { path = "./crates/errno", features = ["occlum"] }
|
||||
errno = { path = "crates/errno", features = ["occlum"] }
|
||||
vdso-time = { path = "crates/vdso-time", default-features = false, features = ["sgx"] }
|
||||
memoffset = "0.6.1"
|
||||
scroll = { version = "0.11.0", default-features = false }
|
||||
itertools = { version = "0.10.0", default-features = false, features = ["use_alloc"] }
|
||||
|
@ -162,7 +162,11 @@ $(OBJ_DIR)/libos/$(SRC_OBJ)/Enclave_t.o: $(OBJ_DIR)/libos/$(SRC_OBJ)/Enclave_t.c
|
||||
@echo "CC <= $@"
|
||||
|
||||
$(OBJ_DIR)/libos/$(SRC_OBJ)/Enclave_t.c: $(SGX_EDGER8R) ../Enclave.edl
|
||||
@cd $(OBJ_DIR)/libos/$(SRC_OBJ) && $(SGX_EDGER8R) $(SGX_EDGER8R_MODE) --trusted $(CUR_DIR)/../Enclave.edl --search-path $(SGX_SDK)/include --search-path $(RUST_SGX_SDK_DIR)/edl
|
||||
@cd $(OBJ_DIR)/libos/$(SRC_OBJ) && \
|
||||
$(SGX_EDGER8R) $(SGX_EDGER8R_MODE) --trusted $(CUR_DIR)/../Enclave.edl \
|
||||
--search-path $(SGX_SDK)/include \
|
||||
--search-path $(RUST_SGX_SDK_DIR)/edl \
|
||||
--search-path $(CRATES_DIR)/vdso-time/ocalls
|
||||
@echo "GEN <= $@"
|
||||
|
||||
$(C_OBJS):$(OBJ_DIR)/libos/$(SRC_OBJ)/%.o: src/%.c
|
||||
|
10
src/libos/crates/vdso-time/.gitignore
vendored
Normal file
10
src/libos/crates/vdso-time/.gitignore
vendored
Normal file
@ -0,0 +1,10 @@
|
||||
# Generated by Cargo
|
||||
# will have compiled files and executables
|
||||
/target/
|
||||
|
||||
# Remove Cargo.lock from gitignore if creating an executable, leave it for libraries
|
||||
# More information here https://doc.rust-lang.org/cargo/guide/cargo-toml-vs-cargo-lock.html
|
||||
Cargo.lock
|
||||
|
||||
# These are backup files generated by rustfmt
|
||||
**/*.rs.bk
|
32
src/libos/crates/vdso-time/Cargo.toml
Normal file
32
src/libos/crates/vdso-time/Cargo.toml
Normal file
@ -0,0 +1,32 @@
|
||||
[package]
|
||||
name = "vdso-time"
|
||||
version = "0.1.0"
|
||||
authors = ["Shuocheng Wang <shuocheng.wsc@antgroup.com>"]
|
||||
edition = "2021"
|
||||
|
||||
# See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html
|
||||
|
||||
[features]
|
||||
default = ["std"]
|
||||
std = ["libc"]
|
||||
sgx = ["sgx_types", "sgx_tstd", "sgx_libc", "sgx_trts"]
|
||||
|
||||
[dependencies]
|
||||
cfg-if = "1.0"
|
||||
errno = { path = "../errno" }
|
||||
lazy_static = { version = "1.4.0", features = ["spin_no_std"] }
|
||||
libc = { version = "0.2", optional = true }
|
||||
log = "0.4"
|
||||
sgx_types = { path = "../../../../deps/rust-sgx-sdk/sgx_types", optional = true }
|
||||
sgx_tstd = { path = "../../../../deps/rust-sgx-sdk/sgx_tstd", optional = true, features = ["backtrace"] }
|
||||
sgx_libc = { path = "../../../../deps/rust-sgx-sdk/sgx_libc", optional = true }
|
||||
sgx_trts = { path = "../../../../deps/rust-sgx-sdk/sgx_trts", optional = true }
|
||||
|
||||
[dev-dependencies]
|
||||
criterion = "0.3"
|
||||
lazy_static = { version = "1.4.0", features = ["spin_no_std"] }
|
||||
ctor = "0.1"
|
||||
|
||||
[[bench]]
|
||||
name = "bench"
|
||||
harness = false
|
40
src/libos/crates/vdso-time/README.md
Normal file
40
src/libos/crates/vdso-time/README.md
Normal file
@ -0,0 +1,40 @@
|
||||
# vdso-time
|
||||
A rust crate for getting time using vDSO. This crate can support host and SGX (based on Rust-SGX-SDK).
|
||||
|
||||
## Getting Started
|
||||
Add the following dependency to your Cargo manifest:
|
||||
|
||||
```
|
||||
vdso-time = { path = "yourpath/vdso-time" }
|
||||
```
|
||||
|
||||
If you want to use in SGX environment, add the following dependency to your Cargo manifest:
|
||||
|
||||
```
|
||||
vdso-time = { path = "yourpath/vdso-time", default-features = false, features = ["sgx"] }
|
||||
```
|
||||
|
||||
## API examples
|
||||
|
||||
```
|
||||
use vdso_time::ClockId;
|
||||
|
||||
let time = vdso_time::clock_gettime(ClockId::CLOCK_MONOTONIC).unwrap();
|
||||
println!("vdso_time::clock_gettime: {:?}", time);
|
||||
|
||||
let res = vdso_time::clock_getres(ClockId::CLOCK_MONOTONIC).unwrap();
|
||||
println!("vdso_time::clock_getres: {:?}", res);
|
||||
```
|
||||
|
||||
```
|
||||
use vdso_time::{Vdso, ClockId};
|
||||
|
||||
let vdso = Vdso::new().unwrap();
|
||||
|
||||
let time = vdso.clock_gettime(ClockId::CLOCK_MONOTONIC).unwrap();
|
||||
println!("vdso.clock_gettime: {:?}", time);
|
||||
|
||||
let res = vdso.clock_getres(ClockId::CLOCK_MONOTONIC).unwrap();
|
||||
println!("vdso.clock_getres: {:?}", res);
|
||||
}
|
||||
```
|
42
src/libos/crates/vdso-time/benches/bench.rs
Normal file
42
src/libos/crates/vdso-time/benches/bench.rs
Normal file
@ -0,0 +1,42 @@
|
||||
use criterion::{black_box, criterion_group, criterion_main, Criterion};
|
||||
use vdso_time::ClockId;
|
||||
|
||||
fn libc_clock_gettime() -> libc::timespec {
|
||||
let mut tp = libc::timespec {
|
||||
tv_sec: 0,
|
||||
tv_nsec: 0,
|
||||
};
|
||||
unsafe {
|
||||
libc::clock_gettime(ClockId::CLOCK_MONOTONIC as _, &mut tp as *mut _);
|
||||
}
|
||||
tp
|
||||
}
|
||||
|
||||
fn libc_clock_getres() -> libc::timespec {
|
||||
let mut tp = libc::timespec {
|
||||
tv_sec: 0,
|
||||
tv_nsec: 0,
|
||||
};
|
||||
unsafe {
|
||||
libc::clock_getres(ClockId::CLOCK_MONOTONIC as _, &mut tp as *mut _);
|
||||
}
|
||||
tp
|
||||
}
|
||||
|
||||
fn criterion_benchmark(c: &mut Criterion) {
|
||||
c.bench_function("libc clock_gettime", |b| {
|
||||
b.iter(|| black_box(libc_clock_gettime()))
|
||||
});
|
||||
c.bench_function("vdso clock_gettime", |b| {
|
||||
b.iter(|| black_box(vdso_time::clock_gettime(ClockId::CLOCK_MONOTONIC).unwrap()))
|
||||
});
|
||||
c.bench_function("libc clock_getres", |b| {
|
||||
b.iter(|| black_box(libc_clock_getres()))
|
||||
});
|
||||
c.bench_function("vdso clock_getres", |b| {
|
||||
b.iter(|| black_box(vdso_time::clock_getres(ClockId::CLOCK_MONOTONIC).unwrap()))
|
||||
});
|
||||
}
|
||||
|
||||
criterion_group!(benches, criterion_benchmark);
|
||||
criterion_main!(benches);
|
33
src/libos/crates/vdso-time/examples/bench.rs
Normal file
33
src/libos/crates/vdso-time/examples/bench.rs
Normal file
@ -0,0 +1,33 @@
|
||||
include!("common/bench.rs");
|
||||
|
||||
fn libc_clock_gettime() -> Duration {
|
||||
let mut tp = libc::timespec {
|
||||
tv_sec: 0,
|
||||
tv_nsec: 0,
|
||||
};
|
||||
unsafe {
|
||||
libc::clock_gettime(ClockId::CLOCK_MONOTONIC as _, &mut tp as *mut _);
|
||||
}
|
||||
Duration::new(tp.tv_sec as u64, tp.tv_nsec as u32)
|
||||
}
|
||||
|
||||
fn libc_clock_getres() -> Duration {
|
||||
let mut tp = libc::timespec {
|
||||
tv_sec: 0,
|
||||
tv_nsec: 0,
|
||||
};
|
||||
unsafe {
|
||||
libc::clock_getres(ClockId::CLOCK_MONOTONIC as _, &mut tp as *mut _);
|
||||
}
|
||||
Duration::new(tp.tv_sec as u64, tp.tv_nsec as u32)
|
||||
}
|
||||
|
||||
fn libc_benchmarks() {
|
||||
benchmark("Libc clock_gettime()", libc_clock_gettime);
|
||||
benchmark("Libc clock_getres()", libc_clock_getres);
|
||||
}
|
||||
|
||||
fn main() {
|
||||
libc_benchmarks();
|
||||
vdso_benchmarks();
|
||||
}
|
31
src/libos/crates/vdso-time/examples/common/bench.rs
Normal file
31
src/libos/crates/vdso-time/examples/common/bench.rs
Normal file
@ -0,0 +1,31 @@
|
||||
use std::time::Duration;
|
||||
use vdso_time::{ClockId, clock_getres, clock_gettime};
|
||||
|
||||
/// from criterion crate:
|
||||
/// A function that is opaque to the optimizer, used to prevent the compiler from
|
||||
/// optimizing away computations in a benchmark.
|
||||
///
|
||||
/// This variant is stable-compatible, but it may cause some performance overhead
|
||||
/// or fail to prevent code from being eliminated.
|
||||
fn black_box<T>(dummy: T) -> T {
|
||||
unsafe {
|
||||
let ret = std::ptr::read_volatile(&dummy);
|
||||
std::mem::forget(dummy);
|
||||
ret
|
||||
}
|
||||
}
|
||||
|
||||
fn benchmark(name: &str, func: impl Fn() -> Duration) {
|
||||
let start = clock_gettime(ClockId::CLOCK_MONOTONIC).unwrap();
|
||||
let loops = 1000000;
|
||||
for _ in 0..loops {
|
||||
black_box(func());
|
||||
}
|
||||
let end = clock_gettime(ClockId::CLOCK_MONOTONIC).unwrap();
|
||||
println!("[{}] avg_time: {:?} ns", name, (end - start).as_nanos() / loops);
|
||||
}
|
||||
|
||||
fn vdso_benchmarks() {
|
||||
benchmark("vdso clock_gettime()", || clock_gettime(ClockId::CLOCK_MONOTONIC).unwrap());
|
||||
benchmark("vdso clock_getres()", || clock_getres(ClockId::CLOCK_MONOTONIC).unwrap());
|
||||
}
|
26
src/libos/crates/vdso-time/examples/common/example.rs
Normal file
26
src/libos/crates/vdso-time/examples/common/example.rs
Normal file
@ -0,0 +1,26 @@
|
||||
fn first_example() {
|
||||
use vdso_time::ClockId;
|
||||
|
||||
let time = vdso_time::clock_gettime(ClockId::CLOCK_MONOTONIC).unwrap();
|
||||
println!("vdso_time::clock_gettime: {:?}", time);
|
||||
|
||||
let res = vdso_time::clock_getres(ClockId::CLOCK_MONOTONIC).unwrap();
|
||||
println!("vdso_time::clock_getres: {:?}", res);
|
||||
}
|
||||
|
||||
fn second_example() {
|
||||
use vdso_time::{Vdso, ClockId};
|
||||
|
||||
let vdso = Vdso::new().unwrap();
|
||||
|
||||
let time = vdso.clock_gettime(ClockId::CLOCK_MONOTONIC).unwrap();
|
||||
println!("vdso.clock_gettime: {:?}", time);
|
||||
|
||||
let res = vdso.clock_getres(ClockId::CLOCK_MONOTONIC).unwrap();
|
||||
println!("vdso.clock_getres: {:?}", res);
|
||||
}
|
||||
|
||||
fn example() {
|
||||
first_example();
|
||||
second_example();
|
||||
}
|
5
src/libos/crates/vdso-time/examples/example.rs
Normal file
5
src/libos/crates/vdso-time/examples/example.rs
Normal file
@ -0,0 +1,5 @@
|
||||
include!("common/example.rs");
|
||||
|
||||
fn main() {
|
||||
example();
|
||||
}
|
11
src/libos/crates/vdso-time/examples/sgx/.gitignore
vendored
Normal file
11
src/libos/crates/vdso-time/examples/sgx/.gitignore
vendored
Normal file
@ -0,0 +1,11 @@
|
||||
Cargo.lock
|
||||
Enclave_u.c
|
||||
Enclave_u.h
|
||||
Enclave_t.c
|
||||
Enclave_t.h
|
||||
app/target
|
||||
enclave/target
|
||||
bin/app
|
||||
*.o
|
||||
*.a
|
||||
*.so
|
167
src/libos/crates/vdso-time/examples/sgx/Makefile
Normal file
167
src/libos/crates/vdso-time/examples/sgx/Makefile
Normal file
@ -0,0 +1,167 @@
|
||||
# Licensed to the Apache Software Foundation (ASF) under one
|
||||
# or more contributor license agreements. See the NOTICE file
|
||||
# distributed with this work for additional information
|
||||
# regarding copyright ownership. The ASF licenses this file
|
||||
# to you under the Apache License, Version 2.0 (the
|
||||
# "License"); you may not use this file except in compliance
|
||||
# with the License. You may obtain a copy of the License at
|
||||
#
|
||||
# http://www.apache.org/licenses/LICENSE-2.0
|
||||
#
|
||||
# Unless required by applicable law or agreed to in writing,
|
||||
# software distributed under the License is distributed on an
|
||||
# "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
|
||||
# KIND, either express or implied. See the License for the
|
||||
# specific language governing permissions and limitations
|
||||
# under the License.
|
||||
|
||||
######## SGX SDK Settings ########
|
||||
|
||||
SGX_SDK ?= /opt/sgxsdk
|
||||
SGX_MODE ?= HW
|
||||
SGX_ARCH ?= x64
|
||||
|
||||
include ../../../common.mk
|
||||
|
||||
include $(RUST_SGX_SDK_DIR)/buildenv.mk
|
||||
|
||||
OCALLS_DIR := ../../ocalls
|
||||
|
||||
ifeq ($(shell getconf LONG_BIT), 32)
|
||||
SGX_ARCH := x86
|
||||
else ifeq ($(findstring -m32, $(CXXFLAGS)), -m32)
|
||||
SGX_ARCH := x86
|
||||
endif
|
||||
|
||||
ifeq ($(SGX_ARCH), x86)
|
||||
SGX_COMMON_CFLAGS := -m32
|
||||
SGX_LIBRARY_PATH := $(SGX_SDK)/lib
|
||||
SGX_ENCLAVE_SIGNER := $(SGX_SDK)/bin/x86/sgx_sign
|
||||
SGX_EDGER8R := $(SGX_SDK)/bin/x86/sgx_edger8r
|
||||
else
|
||||
SGX_COMMON_CFLAGS := -m64
|
||||
SGX_LIBRARY_PATH := $(SGX_SDK)/lib64
|
||||
SGX_ENCLAVE_SIGNER := $(SGX_SDK)/bin/x64/sgx_sign
|
||||
SGX_EDGER8R := $(SGX_SDK)/bin/x64/sgx_edger8r
|
||||
endif
|
||||
|
||||
ifeq ($(SGX_DEBUG), 1)
|
||||
ifeq ($(SGX_PRERELEASE), 1)
|
||||
$(error Cannot set SGX_DEBUG and SGX_PRERELEASE at the same time!!)
|
||||
endif
|
||||
endif
|
||||
|
||||
ifeq ($(SGX_DEBUG), 1)
|
||||
SGX_COMMON_CFLAGS += -O0 -g
|
||||
else
|
||||
SGX_COMMON_CFLAGS += -O2
|
||||
endif
|
||||
|
||||
SGX_COMMON_CFLAGS += -fstack-protector
|
||||
|
||||
######## CUSTOM Settings ########
|
||||
|
||||
CUSTOM_LIBRARY_PATH := ./lib
|
||||
CUSTOM_BIN_PATH := ./bin
|
||||
CUSTOM_EDL_PATH := $(RUST_SGX_SDK_DIR)/edl
|
||||
CUSTOM_COMMON_PATH := $(RUST_SGX_SDK_DIR)/common
|
||||
|
||||
######## EDL Settings ########
|
||||
|
||||
Enclave_EDL_Files := enclave/Enclave_t.c enclave/Enclave_t.h app/Enclave_u.c app/Enclave_u.h
|
||||
|
||||
######## APP Settings ########
|
||||
|
||||
App_Rust_Flags := --release
|
||||
App_SRC_Files := $(shell find app/ -type f -name '*.rs') $(shell find app/ -type f -name 'Cargo.toml')
|
||||
App_Include_Paths := -I ./app -I./include -I$(SGX_SDK)/include -I$(CUSTOM_EDL_PATH)
|
||||
App_C_Flags := $(SGX_COMMON_CFLAGS) -fPIC -Wno-attributes $(App_Include_Paths)
|
||||
|
||||
App_Rust_Path := ./app/target/release
|
||||
App_Enclave_u_Object := lib/libEnclave_u.a
|
||||
App_Ocall_Object_Name := libvdso_time_ocalls.a
|
||||
App_Ocall_Object := lib/$(App_Ocall_Object_Name)
|
||||
App_Name := bin/app
|
||||
|
||||
######## Enclave Settings ########
|
||||
|
||||
ifneq ($(SGX_MODE), HW)
|
||||
Trts_Library_Name := sgx_trts_sim
|
||||
Service_Library_Name := sgx_tservice_sim
|
||||
else
|
||||
Trts_Library_Name := sgx_trts
|
||||
Service_Library_Name := sgx_tservice
|
||||
endif
|
||||
Crypto_Library_Name := sgx_tcrypto
|
||||
KeyExchange_Library_Name := sgx_tkey_exchange
|
||||
ProtectedFs_Library_Name := sgx_tprotected_fs
|
||||
|
||||
RustEnclave_C_Files := $(wildcard ./enclave/*.c)
|
||||
RustEnclave_C_Objects := $(RustEnclave_C_Files:.c=.o)
|
||||
RustEnclave_Include_Paths := -I$(CUSTOM_COMMON_PATH)/inc -I$(CUSTOM_EDL_PATH) -I$(SGX_SDK)/include -I$(SGX_SDK)/include/tlibc -I$(SGX_SDK)/include/stlport -I$(SGX_SDK)/include/epid -I ./enclave -I./include
|
||||
|
||||
RustEnclave_Link_Libs := -L$(CUSTOM_LIBRARY_PATH) -lenclave
|
||||
RustEnclave_Compile_Flags := $(SGX_COMMON_CFLAGS) $(ENCLAVE_CFLAGS) $(RustEnclave_Include_Paths)
|
||||
RustEnclave_Link_Flags := -Wl,--no-undefined -nostdlib -nodefaultlibs -nostartfiles -L$(SGX_LIBRARY_PATH) \
|
||||
-Wl,--whole-archive -l$(Trts_Library_Name) -Wl,--no-whole-archive \
|
||||
-Wl,--start-group -lsgx_tstdc -l$(Service_Library_Name) -l$(Crypto_Library_Name) $(RustEnclave_Link_Libs) -Wl,--end-group \
|
||||
-Wl,--version-script=enclave/Enclave.lds \
|
||||
$(ENCLAVE_LDFLAGS)
|
||||
|
||||
RustEnclave_Name := enclave/enclave.so
|
||||
Signed_RustEnclave_Name := bin/enclave.signed.so
|
||||
|
||||
.PHONY: all
|
||||
all: $(App_Name) $(Signed_RustEnclave_Name)
|
||||
|
||||
######## EDL Objects ########
|
||||
|
||||
$(Enclave_EDL_Files): $(SGX_EDGER8R) enclave/Enclave.edl
|
||||
$(SGX_EDGER8R) --trusted enclave/Enclave.edl --search-path $(OCALLS_DIR) --search-path $(SGX_SDK)/include --search-path $(CUSTOM_EDL_PATH) --trusted-dir enclave
|
||||
$(SGX_EDGER8R) --untrusted enclave/Enclave.edl --search-path $(OCALLS_DIR) --search-path $(SGX_SDK)/include --search-path $(CUSTOM_EDL_PATH) --untrusted-dir app
|
||||
@echo "GEN => $(Enclave_EDL_Files)"
|
||||
|
||||
######## App Objects ########
|
||||
|
||||
app/Enclave_u.o: $(Enclave_EDL_Files)
|
||||
@$(CC) $(App_C_Flags) -c app/Enclave_u.c -o $@
|
||||
@echo "CC <= $<"
|
||||
|
||||
$(App_Enclave_u_Object): app/Enclave_u.o
|
||||
$(AR) rcsD $@ $^
|
||||
|
||||
$(App_Ocall_Object):
|
||||
@$(MAKE) -C $(OCALLS_DIR)
|
||||
@cp $(OCALLS_DIR)/$(App_Ocall_Object_Name) $@
|
||||
|
||||
$(App_Name): $(App_Ocall_Object) $(App_Enclave_u_Object) $(App_SRC_Files)
|
||||
@cd app && SGX_SDK=$(SGX_SDK) cargo build $(App_Rust_Flags)
|
||||
@echo "Cargo => $@"
|
||||
mkdir -p bin
|
||||
cp $(App_Rust_Path)/app ./bin
|
||||
|
||||
######## Enclave Objects ########
|
||||
|
||||
enclave/Enclave_t.o: $(Enclave_EDL_Files)
|
||||
@$(CC) $(RustEnclave_Compile_Flags) -c enclave/Enclave_t.c -o $@
|
||||
@echo "CC <= $<"
|
||||
|
||||
$(RustEnclave_Name): enclave enclave/Enclave_t.o
|
||||
@$(CXX) enclave/Enclave_t.o -o $@ $(RustEnclave_Link_Flags)
|
||||
@echo "LINK => $@"
|
||||
|
||||
$(Signed_RustEnclave_Name): $(RustEnclave_Name)
|
||||
mkdir -p bin
|
||||
@$(SGX_ENCLAVE_SIGNER) sign -key enclave/Enclave_private.pem -enclave $(RustEnclave_Name) -out $@ -config enclave/Enclave.config.xml
|
||||
@echo "SIGN => $@"
|
||||
|
||||
.PHONY: enclave
|
||||
enclave:
|
||||
$(MAKE) -C ./enclave/
|
||||
|
||||
|
||||
.PHONY: clean
|
||||
clean:
|
||||
@rm -f $(App_Name) $(RustEnclave_Name) $(Signed_RustEnclave_Name) enclave/*_t.* app/*_u.* lib/*.a
|
||||
@cd enclave && cargo clean && rm -f Cargo.lock
|
||||
@cd app && cargo clean && rm -f Cargo.lock
|
11
src/libos/crates/vdso-time/examples/sgx/README.md
Normal file
11
src/libos/crates/vdso-time/examples/sgx/README.md
Normal file
@ -0,0 +1,11 @@
|
||||
## example for SGX
|
||||
This is an example of using vdso-time in SGX.
|
||||
This example combines vdso-time example of io_uring and hello-rust example of incubator-teaclave-sgx-sdk.
|
||||
- ./app : untrusted code
|
||||
- ./bin : executable program
|
||||
- ./enclave : trusted code
|
||||
- ./lib : library
|
||||
|
||||
### run example in SGX
|
||||
1. ```make```
|
||||
2. ```cd bin && ./app```
|
10
src/libos/crates/vdso-time/examples/sgx/app/Cargo.toml
Normal file
10
src/libos/crates/vdso-time/examples/sgx/app/Cargo.toml
Normal file
@ -0,0 +1,10 @@
|
||||
[package]
|
||||
name = "app"
|
||||
version = "1.0.0"
|
||||
build = "build.rs"
|
||||
|
||||
[dependencies]
|
||||
sgx_types = { path = "../../../../../../../deps/rust-sgx-sdk/sgx_types" }
|
||||
sgx_urts = { path = "../../../../../../../deps/rust-sgx-sdk/sgx_urts" }
|
||||
|
||||
[workspace]
|
34
src/libos/crates/vdso-time/examples/sgx/app/build.rs
Normal file
34
src/libos/crates/vdso-time/examples/sgx/app/build.rs
Normal file
@ -0,0 +1,34 @@
|
||||
// Licensed to the Apache Software Foundation (ASF) under one
|
||||
// or more contributor license agreements. See the NOTICE file
|
||||
// distributed with this work for additional information
|
||||
// regarding copyright ownership. The ASF licenses this file
|
||||
// to you under the Apache License, Version 2.0 (the
|
||||
// "License"); you may not use this file except in compliance
|
||||
// with the License. You may obtain a copy of the License at
|
||||
//
|
||||
// http://www.apache.org/licenses/LICENSE-2.0
|
||||
//
|
||||
// Unless required by applicable law or agreed to in writing,
|
||||
// software distributed under the License is distributed on an
|
||||
// "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
|
||||
// KIND, either express or implied. See the License for the
|
||||
// specific language governing permissions and limitations
|
||||
// under the License..
|
||||
|
||||
use std::env;
|
||||
|
||||
fn main() {
|
||||
let sdk_dir = env::var("SGX_SDK").unwrap_or_else(|_| "/opt/sgxsdk".to_string());
|
||||
let is_sim = env::var("SGX_MODE").unwrap_or_else(|_| "HW".to_string());
|
||||
|
||||
println!("cargo:rustc-link-search=native=../lib");
|
||||
println!("cargo:rustc-link-lib=static=Enclave_u");
|
||||
println!("cargo:rustc-link-lib=static=vdso_time_ocalls");
|
||||
|
||||
println!("cargo:rustc-link-search=native={}/lib64", sdk_dir);
|
||||
match is_sim.as_ref() {
|
||||
"SW" => println!("cargo:rustc-link-lib=dylib=sgx_urts_sim"),
|
||||
"HW" => println!("cargo:rustc-link-lib=dylib=sgx_urts"),
|
||||
_ => println!("cargo:rustc-link-lib=dylib=sgx_urts"), // Treat undefined as HW
|
||||
}
|
||||
}
|
@ -0,0 +1 @@
|
||||
nightly-2020-10-25
|
78
src/libos/crates/vdso-time/examples/sgx/app/src/main.rs
Normal file
78
src/libos/crates/vdso-time/examples/sgx/app/src/main.rs
Normal file
@ -0,0 +1,78 @@
|
||||
// Licensed to the Apache Software Foundation (ASF) under one
|
||||
// or more contributor license agreements. See the NOTICE file
|
||||
// distributed with this work for additional information
|
||||
// regarding copyright ownership. The ASF licenses this file
|
||||
// to you under the Apache License, Version 2.0 (the
|
||||
// "License"); you may not use this file except in compliance
|
||||
// with the License. You may obtain a copy of the License at
|
||||
//
|
||||
// http://www.apache.org/licenses/LICENSE-2.0
|
||||
//
|
||||
// Unless required by applicable law or agreed to in writing,
|
||||
// software distributed under the License is distributed on an
|
||||
// "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
|
||||
// KIND, either express or implied. See the License for the
|
||||
// specific language governing permissions and limitations
|
||||
// under the License..
|
||||
|
||||
extern crate sgx_types;
|
||||
extern crate sgx_urts;
|
||||
use sgx_types::*;
|
||||
use sgx_urts::SgxEnclave;
|
||||
|
||||
static ENCLAVE_FILE: &'static str = "enclave.signed.so";
|
||||
|
||||
extern "C" {
|
||||
fn run_sgx_example(eid: sgx_enclave_id_t, retval: *mut sgx_status_t) -> sgx_status_t;
|
||||
}
|
||||
|
||||
fn init_enclave() -> SgxResult<SgxEnclave> {
|
||||
let mut launch_token: sgx_launch_token_t = [0; 1024];
|
||||
let mut launch_token_updated: i32 = 0;
|
||||
// call sgx_create_enclave to initialize an enclave instance
|
||||
// Debug Support: set 2nd parameter to 1
|
||||
let debug = 1;
|
||||
let mut misc_attr = sgx_misc_attribute_t {
|
||||
secs_attr: sgx_attributes_t { flags: 0, xfrm: 0 },
|
||||
misc_select: 0,
|
||||
};
|
||||
SgxEnclave::create(
|
||||
ENCLAVE_FILE,
|
||||
debug,
|
||||
&mut launch_token,
|
||||
&mut launch_token_updated,
|
||||
&mut misc_attr,
|
||||
)
|
||||
}
|
||||
|
||||
fn main() {
|
||||
let enclave = match init_enclave() {
|
||||
Ok(r) => {
|
||||
println!("[+] Init Enclave Successful {}!", r.geteid());
|
||||
r
|
||||
}
|
||||
Err(x) => {
|
||||
println!("[-] Init Enclave Failed {}!", x.as_str());
|
||||
return;
|
||||
}
|
||||
};
|
||||
|
||||
let mut retval = sgx_status_t::SGX_SUCCESS;
|
||||
let result = unsafe { run_sgx_example(enclave.geteid(), &mut retval) };
|
||||
match result {
|
||||
sgx_status_t::SGX_SUCCESS => {}
|
||||
_ => {
|
||||
println!("[-] ECALL Enclave Failed {}!", result.as_str());
|
||||
return;
|
||||
}
|
||||
}
|
||||
match retval {
|
||||
sgx_status_t::SGX_SUCCESS => {}
|
||||
_ => {
|
||||
println!("[-] ECALL Returned Error {}!", retval.as_str());
|
||||
return;
|
||||
}
|
||||
}
|
||||
println!("[+] run_sgx_example success...");
|
||||
enclave.destroy();
|
||||
}
|
1
src/libos/crates/vdso-time/examples/sgx/bin/readme.txt
Normal file
1
src/libos/crates/vdso-time/examples/sgx/bin/readme.txt
Normal file
@ -0,0 +1 @@
|
||||
bin
|
22
src/libos/crates/vdso-time/examples/sgx/enclave/Cargo.toml
Normal file
22
src/libos/crates/vdso-time/examples/sgx/enclave/Cargo.toml
Normal file
@ -0,0 +1,22 @@
|
||||
[package]
|
||||
name = "Helloworldsampleenclave"
|
||||
version = "1.0.0"
|
||||
|
||||
[lib]
|
||||
name = "helloworldsampleenclave"
|
||||
crate-type = ["staticlib"]
|
||||
|
||||
[features]
|
||||
default = []
|
||||
|
||||
[dependencies]
|
||||
vdso-time = { path = "../../../../vdso-time", default-features = false, features = ["sgx"] }
|
||||
lazy_static = { version = "1.4.0", features = ["spin_no_std"] }
|
||||
|
||||
[target.'cfg(not(target_env = "sgx"))'.dependencies]
|
||||
sgx_types = { path = "../../../../../../../deps/rust-sgx-sdk/sgx_types" }
|
||||
sgx_tstd = { path = "../../../../../../../deps/rust-sgx-sdk/sgx_tstd", features = ["backtrace", "thread"] }
|
||||
sgx_trts = { path = "../../../../../../../deps/rust-sgx-sdk/sgx_trts" }
|
||||
sgx_libc = { path = "../../../../../../../deps/rust-sgx-sdk/sgx_libc" }
|
||||
|
||||
[workspace]
|
@ -0,0 +1,13 @@
|
||||
<!-- Please refer to User's Guide for the explanation of each field -->
|
||||
<EnclaveConfiguration>
|
||||
<ProdID>0</ProdID>
|
||||
<ISVSVN>0</ISVSVN>
|
||||
<StackMaxSize>0x40000</StackMaxSize>
|
||||
<HeapMaxSize>0x400000</HeapMaxSize>
|
||||
<TCSNum>1</TCSNum>
|
||||
<TCSMaxNum>1</TCSMaxNum>
|
||||
<TCSPolicy>0</TCSPolicy>
|
||||
<DisableDebug>0</DisableDebug>
|
||||
<MiscSelect>0</MiscSelect>
|
||||
<MiscMask>0xFFFFFFFF</MiscMask>
|
||||
</EnclaveConfiguration>
|
36
src/libos/crates/vdso-time/examples/sgx/enclave/Enclave.edl
Normal file
36
src/libos/crates/vdso-time/examples/sgx/enclave/Enclave.edl
Normal file
@ -0,0 +1,36 @@
|
||||
// Licensed to the Apache Software Foundation (ASF) under one
|
||||
// or more contributor license agreements. See the NOTICE file
|
||||
// distributed with this work for additional information
|
||||
// regarding copyright ownership. The ASF licenses this file
|
||||
// to you under the Apache License, Version 2.0 (the
|
||||
// "License"); you may not use this file except in compliance
|
||||
// with the License. You may obtain a copy of the License at
|
||||
//
|
||||
// http://www.apache.org/licenses/LICENSE-2.0
|
||||
//
|
||||
// Unless required by applicable law or agreed to in writing,
|
||||
// software distributed under the License is distributed on an
|
||||
// "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
|
||||
// KIND, either express or implied. See the License for the
|
||||
// specific language governing permissions and limitations
|
||||
// under the License.
|
||||
|
||||
enclave {
|
||||
from "sgx_tstd.edl" import *;
|
||||
from "sgx_stdio.edl" import *;
|
||||
from "sgx_backtrace.edl" import *;
|
||||
from "sgx_tstdc.edl" import *;
|
||||
from "sgx_net.edl" import *;
|
||||
from "sgx_thread.edl" import *;
|
||||
|
||||
from "sgx_vdso_time_ocalls.edl" import *;
|
||||
|
||||
trusted {
|
||||
/* define ECALLs here. */
|
||||
public sgx_status_t run_sgx_example();
|
||||
};
|
||||
|
||||
untrusted {
|
||||
/* define OCALLs here. */
|
||||
};
|
||||
};
|
@ -0,0 +1,9 @@
|
||||
enclave.so
|
||||
{
|
||||
global:
|
||||
g_global_data_sim;
|
||||
g_global_data;
|
||||
enclave_entry;
|
||||
local:
|
||||
*;
|
||||
};
|
@ -0,0 +1,39 @@
|
||||
-----BEGIN RSA PRIVATE KEY-----
|
||||
MIIG4gIBAAKCAYEAroOogvsj/fZDZY8XFdkl6dJmky0lRvnWMmpeH41Bla6U1qLZ
|
||||
AmZuyIF+mQC/cgojIsrBMzBxb1kKqzATF4+XwPwgKz7fmiddmHyYz2WDJfAjIveJ
|
||||
ZjdMjM4+EytGlkkJ52T8V8ds0/L2qKexJ+NBLxkeQLfV8n1mIk7zX7jguwbCG1Pr
|
||||
nEMdJ3Sew20vnje+RsngAzdPChoJpVsWi/K7cettX/tbnre1DL02GXc5qJoQYk7b
|
||||
3zkmhz31TgFrd9VVtmUGyFXAysuSAb3EN+5VnHGr0xKkeg8utErea2FNtNIgua8H
|
||||
ONfm9Eiyaav1SVKzPHlyqLtcdxH3I8Wg7yqMsaprZ1n5A1v/levxnL8+It02KseD
|
||||
5HqV4rf/cImSlCt3lpRg8U5E1pyFQ2IVEC/XTDMiI3c+AR+w2jSRB3Bwn9zJtFlW
|
||||
KHG3m1xGI4ck+Lci1JvWWLXQagQSPtZTsubxTQNx1gsgZhgv1JHVZMdbVlAbbRMC
|
||||
1nSuJNl7KPAS/VfzAgEDAoIBgHRXxaynbVP5gkO0ug6Qw/E27wzIw4SmjsxG6Wpe
|
||||
K7kfDeRskKxESdsA/xCrKkwGwhcx1iIgS5+Qscd1Yg+1D9X9asd/P7waPmWoZd+Z
|
||||
AhlKwhdPsO7PiF3e1AzHhGQwsUTt/Y/aSI1MpHBvy2/s1h9mFCslOUxTmWw0oj/Q
|
||||
ldIEgWeNR72CE2+jFIJIyml6ftnb6qzPiga8Bm48ubKh0kvySOqnkmnPzgh+JBD6
|
||||
JnBmtZbfPT97bwTT+N6rnPqOOApvfHPf15kWI8yDbprG1l4OCUaIUH1AszxLd826
|
||||
5IPM+8gINLRDP1MA6azECPjTyHXhtnSIBZCyWSVkc05vYmNXYUNiXWMajcxW9M02
|
||||
wKzFELO8NCEAkaTPxwo4SCyIjUxiK1LbQ9h8PSy4c1+gGP4LAMR8xqP4QKg6zdu9
|
||||
osUGG/xRe/uufgTBFkcjqBHtK5L5VI0jeNIUAgW/6iNbYXjBMJ0GfauLs+g1VsOm
|
||||
WfdgXzsb9DYdMa0OXXHypmV4GwKBwQDUwQj8RKJ6c8cT4vcWCoJvJF00+RFL+P3i
|
||||
Gx2DLERxRrDa8AVGfqaCjsR+3vLgG8V/py+z+dxZYSqeB80Qeo6PDITcRKoeAYh9
|
||||
xlT3LJOS+k1cJcEmlbbO2IjLkTmzSwa80fWexKu8/Xv6vv15gpqYl1ngYoqJM3pd
|
||||
vzmTIOi7MKSZ0WmEQavrZj8zK4endE3v0eAEeQ55j1GImbypSf7Idh7wOXtjZ7WD
|
||||
Dg6yWDrri+AP/L3gClMj8wsAxMV4ZR8CgcEA0fzDHkFa6raVOxWnObmRoDhAtE0a
|
||||
cjUj976NM5yyfdf2MrKy4/RhdTiPZ6b08/lBC/+xRfV3xKVGzacm6QjqjZrUpgHC
|
||||
0LKiZaMtccCJjLtPwQd0jGQEnKfMFaPsnhOc5y8qVkCzVOSthY5qhz0XNotHHFmJ
|
||||
gffVgB0iqrMTvSL7IA2yqqpOqNRlhaYhNl8TiFP3gIeMtVa9rZy31JPgT2uJ+kfo
|
||||
gV7sdTPEjPWZd7OshGxWpT6QfVDj/T9T7L6tAoHBAI3WBf2DFvxNL2KXT2QHAZ9t
|
||||
k3imC4f7U+wSE6zILaDZyzygA4RUbwG0gv8/TJVn2P/Eynf76DuWHGlaiLWnCbSz
|
||||
Az2DHBQBBaku409zDQym3j1ugMRjzzSQWzJg0SIyBH3hTmnYcn3+Uqcp/lEBvGW6
|
||||
O+rsXFt3pukqJmIV8HzLGGaLm62BHUeZf3dyWm+i3p/hQAL7Xvu04QW70xuGqdr5
|
||||
afV7p5eaeQIJXyGQJ0eylV/90+qxjMKiB1XYg6WYvwKBwQCL/ddpgOdHJGN8uRom
|
||||
e7Zq0Csi3hGheMKlKbN3vcxT5U7MdyHtTZZOJbTvxKNNUNYH/8uD+PqDGNneb29G
|
||||
BfGzvI3EASyLIcGZF3OhKwZd0jUrWk2y7Vhob91jwp2+t73vdMbkKyI4mHOuXvGv
|
||||
fg95si9oO7EBT+Oqvhccd2J+F1IVXncccYnF4u5ZGWt5lLewN/pVr7MjjykeaHqN
|
||||
t+rfnQam2psA6fL4zS2zTmZPzR2tnY8Y1GBTi0Ko1OKd1HMCgcAb5cB/7/AQlhP9
|
||||
yQa04PLH9ygQkKKptZp7dy5WcWRx0K/hAHRoi2aw1wZqfm7VBNu2SLcs90kCCCxp
|
||||
6C5sfJi6b8NpNbIPC+sc9wsFr7pGo9SFzQ78UlcWYK2Gu2FxlMjonhka5hvo4zvg
|
||||
WxlpXKEkaFt3gLd92m/dMqBrHfafH7VwOJY2zT3WIpjwuk0ZzmRg5p0pG/svVQEH
|
||||
NZmwRwlopysbR69B/n1nefJ84UO50fLh5s5Zr3gBRwbWNZyzhXk=
|
||||
-----END RSA PRIVATE KEY-----
|
38
src/libos/crates/vdso-time/examples/sgx/enclave/Makefile
Normal file
38
src/libos/crates/vdso-time/examples/sgx/enclave/Makefile
Normal file
@ -0,0 +1,38 @@
|
||||
# Licensed to the Apache Software Foundation (ASF) under one
|
||||
# or more contributor license agreements. See the NOTICE file
|
||||
# distributed with this work for additional information
|
||||
# regarding copyright ownership. The ASF licenses this file
|
||||
# to you under the Apache License, Version 2.0 (the
|
||||
# "License"); you may not use this file except in compliance
|
||||
# with the License. You may obtain a copy of the License at
|
||||
#
|
||||
# http://www.apache.org/licenses/LICENSE-2.0
|
||||
#
|
||||
# Unless required by applicable law or agreed to in writing,
|
||||
# software distributed under the License is distributed on an
|
||||
# "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
|
||||
# KIND, either express or implied. See the License for the
|
||||
# specific language governing permissions and limitations
|
||||
# under the License.
|
||||
Rust_Enclave_Name := libenclave.a
|
||||
Rust_Enclave_Files := $(wildcard src/*.rs)
|
||||
Rust_Target_Path := $(CURDIR)/../../../../../../deps/rust-sgx-sdk/xargo
|
||||
|
||||
ifeq ($(MITIGATION-CVE-2020-0551), LOAD)
|
||||
export MITIGATION_CVE_2020_0551=LOAD
|
||||
else ifeq ($(MITIGATION-CVE-2020-0551), CF)
|
||||
export MITIGATION_CVE_2020_0551=CF
|
||||
endif
|
||||
|
||||
.PHONY: all
|
||||
|
||||
all: $(Rust_Enclave_Name)
|
||||
|
||||
$(Rust_Enclave_Name): $(Rust_Enclave_Files)
|
||||
ifeq ($(XARGO_SGX), 1)
|
||||
RUST_TARGET_PATH=$(Rust_Target_Path) xargo build --target x86_64-unknown-linux-sgx --release
|
||||
cp ./target/x86_64-unknown-linux-sgx/release/libhelloworldsampleenclave.a ../lib/libenclave.a
|
||||
else
|
||||
cargo build --release
|
||||
cp ./target/release/libhelloworldsampleenclave.a ../lib/libenclave.a
|
||||
endif
|
@ -0,0 +1 @@
|
||||
nightly-2020-10-25
|
49
src/libos/crates/vdso-time/examples/sgx/enclave/src/lib.rs
Normal file
49
src/libos/crates/vdso-time/examples/sgx/enclave/src/lib.rs
Normal file
@ -0,0 +1,49 @@
|
||||
// Licensed to the Apache Software Foundation (ASF) under one
|
||||
// or more contributor license agreements. See the NOTICE file
|
||||
// distributed with this work for additional information
|
||||
// regarding copyright ownership. The ASF licenses this file
|
||||
// to you under the Apache License, Version 2.0 (the
|
||||
// "License"); you may not use this file except in compliance
|
||||
// with the License. You may obtain a copy of the License at
|
||||
//
|
||||
// http://www.apache.org/licenses/LICENSE-2.0
|
||||
//
|
||||
// Unless required by applicable law or agreed to in writing,
|
||||
// software distributed under the License is distributed on an
|
||||
// "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
|
||||
// KIND, either express or implied. See the License for the
|
||||
// specific language governing permissions and limitations
|
||||
// under the License..
|
||||
|
||||
#![crate_name = "helloworldsampleenclave"]
|
||||
#![crate_type = "staticlib"]
|
||||
#![cfg_attr(not(target_env = "sgx"), no_std)]
|
||||
#![cfg_attr(target_env = "sgx", feature(rustc_private))]
|
||||
|
||||
extern crate sgx_trts;
|
||||
extern crate sgx_types;
|
||||
#[cfg(not(target_env = "sgx"))]
|
||||
#[macro_use]
|
||||
extern crate sgx_tstd as std;
|
||||
extern crate sgx_libc as libc;
|
||||
|
||||
extern crate vdso_time;
|
||||
extern crate lazy_static;
|
||||
|
||||
use sgx_types::*;
|
||||
use std::prelude::v1::*;
|
||||
|
||||
include!("../../../common/example.rs");
|
||||
include!("../../../common/bench.rs");
|
||||
|
||||
#[no_mangle]
|
||||
pub extern "C" fn run_sgx_example() -> sgx_status_t {
|
||||
// std::backtrace::enable_backtrace("enclave.signed.so", std::backtrace::PrintFormat::Full);
|
||||
println!("[ECALL] run_sgx_example");
|
||||
|
||||
example();
|
||||
|
||||
vdso_benchmarks();
|
||||
|
||||
sgx_status_t::SGX_SUCCESS
|
||||
}
|
@ -0,0 +1,31 @@
|
||||
{
|
||||
"arch": "x86_64",
|
||||
"cpu": "x86-64",
|
||||
"data-layout": "e-m:e-i64:64-f80:128-n8:16:32:64-S128",
|
||||
"dynamic-linking": true,
|
||||
"env": "sgx",
|
||||
"exe-allocation-crate": "alloc_system",
|
||||
"executables": true,
|
||||
"has-elf-tls": true,
|
||||
"has-rpath": true,
|
||||
"linker-flavor": "gcc",
|
||||
"linker-is-gnu": true,
|
||||
"llvm-target": "x86_64-unknown-linux-gnu",
|
||||
"max-atomic-width": 64,
|
||||
"os": "linux",
|
||||
"position-independent-executables": true,
|
||||
"pre-link-args": {
|
||||
"gcc": [
|
||||
"-Wl,--as-needed",
|
||||
"-Wl,-z,noexecstack",
|
||||
"-m64"
|
||||
]
|
||||
},
|
||||
"relro-level": "full",
|
||||
"stack-probes": true,
|
||||
"target-c-int-width": "32",
|
||||
"target-endian": "little",
|
||||
"target-family": "unix",
|
||||
"target-pointer-width": "64",
|
||||
"vendor": "mesalock"
|
||||
}
|
1
src/libos/crates/vdso-time/examples/sgx/lib/readme.txt
Normal file
1
src/libos/crates/vdso-time/examples/sgx/lib/readme.txt
Normal file
@ -0,0 +1 @@
|
||||
lib
|
3
src/libos/crates/vdso-time/ocalls/.gitignore
vendored
Normal file
3
src/libos/crates/vdso-time/ocalls/.gitignore
vendored
Normal file
@ -0,0 +1,3 @@
|
||||
*.o
|
||||
*.a
|
||||
*.so
|
12
src/libos/crates/vdso-time/ocalls/Makefile
Normal file
12
src/libos/crates/vdso-time/ocalls/Makefile
Normal file
@ -0,0 +1,12 @@
|
||||
all: libs
|
||||
|
||||
libs: libvdso_time_ocalls.a
|
||||
|
||||
libvdso_time_ocalls.a: vdso_time_ocalls.o
|
||||
ar rcs $@ $^
|
||||
|
||||
vdso_time_ocalls.o: vdso-time-ocalls.c
|
||||
gcc -O3 -c -o $@ $<
|
||||
|
||||
clean:
|
||||
rm -f *.o *.a
|
14
src/libos/crates/vdso-time/ocalls/sgx_vdso_time_ocalls.edl
Normal file
14
src/libos/crates/vdso-time/ocalls/sgx_vdso_time_ocalls.edl
Normal file
@ -0,0 +1,14 @@
|
||||
enclave {
|
||||
include "time.h"
|
||||
|
||||
untrusted {
|
||||
int vdso_ocall_get_vdso_info(
|
||||
[out] unsigned long* vdso_addr,
|
||||
[out, size = release_len] char* release,
|
||||
int release_len
|
||||
);
|
||||
|
||||
int vdso_ocall_clock_gettime(int clockid, [out] struct timespec* ts);
|
||||
int vdso_ocall_clock_getres(int clockid, [out] struct timespec* res);
|
||||
};
|
||||
};
|
30
src/libos/crates/vdso-time/ocalls/vdso-time-ocalls.c
Normal file
30
src/libos/crates/vdso-time/ocalls/vdso-time-ocalls.c
Normal file
@ -0,0 +1,30 @@
|
||||
#include <sys/auxv.h>
|
||||
#include <sys/utsname.h>
|
||||
#include <time.h>
|
||||
#include <string.h>
|
||||
|
||||
int vdso_ocall_get_vdso_info(
|
||||
unsigned long *vdso_addr,
|
||||
char *release,
|
||||
int release_len) {
|
||||
// If AT_SYSINFO_EHDR isn't found, getauxval will return 0.
|
||||
*vdso_addr = getauxval(AT_SYSINFO_EHDR);
|
||||
|
||||
struct utsname buf;
|
||||
int ret = uname(&buf);
|
||||
// uname should always succeed here, since uname only fails when buf is not invalid.
|
||||
if (ret != 0) { return -1; }
|
||||
|
||||
strncpy(release, buf.release, release_len);
|
||||
release[release_len - 1] = '\0';
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
int vdso_ocall_clock_gettime(int clockid, struct timespec *tp) {
|
||||
return clock_gettime(clockid, tp);
|
||||
}
|
||||
|
||||
int vdso_ocall_clock_getres(int clockid, struct timespec *res) {
|
||||
return clock_getres(clockid, res);
|
||||
}
|
622
src/libos/crates/vdso-time/src/lib.rs
Normal file
622
src/libos/crates/vdso-time/src/lib.rs
Normal file
@ -0,0 +1,622 @@
|
||||
#![cfg_attr(feature = "sgx", no_std)]
|
||||
|
||||
#[cfg(feature = "sgx")]
|
||||
extern crate sgx_types;
|
||||
#[cfg(feature = "sgx")]
|
||||
#[macro_use]
|
||||
extern crate sgx_tstd as std;
|
||||
#[cfg(feature = "sgx")]
|
||||
extern crate sgx_libc as libc;
|
||||
#[cfg(feature = "sgx")]
|
||||
extern crate sgx_trts;
|
||||
|
||||
mod sys;
|
||||
|
||||
use errno::prelude::*;
|
||||
use lazy_static::lazy_static;
|
||||
use log::trace;
|
||||
use std::convert::TryFrom;
|
||||
use std::time::Duration;
|
||||
use std::{hint, str};
|
||||
use sys::*;
|
||||
|
||||
pub const NANOS_PER_SEC: u32 = 1_000_000_000;
|
||||
pub const NANOS_PER_MILLI: u32 = 1_000_000;
|
||||
pub const NANOS_PER_MICRO: u32 = 1_000;
|
||||
pub const MILLIS_PER_SEC: u64 = 1_000;
|
||||
pub const MICROS_PER_SEC: u64 = 1_000_000;
|
||||
|
||||
/// Clocks supported by the linux kernel, corresponding to clockid_t in Linux.
|
||||
#[derive(Debug, Eq, PartialEq, Copy, Clone)]
|
||||
#[allow(non_camel_case_types)]
|
||||
pub enum ClockId {
|
||||
CLOCK_REALTIME = 0,
|
||||
CLOCK_MONOTONIC = 1,
|
||||
// vDSO doesn't support CLOCK_PROCESS_CPUTIME_ID.
|
||||
CLOCK_PROCESS_CPUTIME_ID = 2,
|
||||
// vDSO doesn't support CLOCK_THREAD_CPUTIME_ID.
|
||||
CLOCK_THREAD_CPUTIME_ID = 3,
|
||||
CLOCK_MONOTONIC_RAW = 4,
|
||||
CLOCK_REALTIME_COARSE = 5,
|
||||
CLOCK_MONOTONIC_COARSE = 6,
|
||||
CLOCK_BOOTTIME = 7,
|
||||
}
|
||||
|
||||
impl TryFrom<i32> for ClockId {
|
||||
type Error = Error;
|
||||
|
||||
fn try_from(clockid: i32) -> Result<Self> {
|
||||
Ok(match clockid {
|
||||
0 => ClockId::CLOCK_REALTIME,
|
||||
1 => ClockId::CLOCK_MONOTONIC,
|
||||
2 => ClockId::CLOCK_PROCESS_CPUTIME_ID,
|
||||
3 => ClockId::CLOCK_THREAD_CPUTIME_ID,
|
||||
4 => ClockId::CLOCK_MONOTONIC_RAW,
|
||||
5 => ClockId::CLOCK_REALTIME_COARSE,
|
||||
6 => ClockId::CLOCK_MONOTONIC_COARSE,
|
||||
7 => ClockId::CLOCK_BOOTTIME,
|
||||
_ => return_errno!(EINVAL, "Unsupported clockid"),
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
/// An abstraction of Linux vDSO provides the clock and time interface through Linux vDSO.
|
||||
pub struct Vdso {
|
||||
vdso_data_ptr: VdsoDataPtr,
|
||||
// hres resolution for clock_getres
|
||||
hres_resolution: Option<Duration>,
|
||||
// coarse resolution for clock_getres
|
||||
coarse_resolution: Option<Duration>,
|
||||
}
|
||||
|
||||
impl Vdso {
|
||||
/// Try to create a new Vdso by libc or SGX OCALL.
|
||||
///
|
||||
/// # Examples
|
||||
///
|
||||
/// ```
|
||||
/// use vdso_time::Vdso;
|
||||
/// let vdso = Vdso::new().unwrap();
|
||||
/// ```
|
||||
pub fn new() -> Result<Self> {
|
||||
let vdso_data_ptr = Self::get_vdso_data_ptr_from_host()?;
|
||||
let hres_resolution = clock_getres_slow(ClockId::CLOCK_MONOTONIC).ok();
|
||||
let coarse_resolution = clock_getres_slow(ClockId::CLOCK_MONOTONIC_COARSE).ok();
|
||||
let vdso = Self {
|
||||
vdso_data_ptr,
|
||||
hres_resolution,
|
||||
coarse_resolution,
|
||||
};
|
||||
vdso.check_accuracy()?;
|
||||
Ok(vdso)
|
||||
}
|
||||
|
||||
#[cfg(feature = "sgx")]
|
||||
fn get_vdso_data_ptr_from_host() -> Result<VdsoDataPtr> {
|
||||
extern "C" {
|
||||
fn vdso_ocall_get_vdso_info(
|
||||
ret: *mut libc::c_int,
|
||||
vdso_addr: *mut libc::c_ulong,
|
||||
release: *mut libc::c_char,
|
||||
release_len: libc::c_int,
|
||||
) -> sgx_types::sgx_status_t;
|
||||
}
|
||||
|
||||
let mut vdso_addr: libc::c_ulong = 0;
|
||||
let mut release = [0 as libc::c_char; 65];
|
||||
let mut ret: libc::c_int = 0;
|
||||
unsafe {
|
||||
vdso_ocall_get_vdso_info(
|
||||
&mut ret as *mut _,
|
||||
&mut vdso_addr as *mut _,
|
||||
release.as_mut_ptr(),
|
||||
release.len() as _,
|
||||
);
|
||||
}
|
||||
if ret != 0 {
|
||||
return_errno!(EINVAL, "Vdso vdso_ocall_get_vdso_info() failed")
|
||||
}
|
||||
|
||||
Self::match_kernel_version(vdso_addr, &release)
|
||||
}
|
||||
|
||||
#[cfg(not(feature = "sgx"))]
|
||||
fn get_vdso_data_ptr_from_host() -> Result<VdsoDataPtr> {
|
||||
const AT_SYSINFO_EHDR: u64 = 33;
|
||||
let vdso_addr = unsafe { libc::getauxval(AT_SYSINFO_EHDR) };
|
||||
|
||||
let mut utsname: libc::utsname = unsafe { std::mem::zeroed() };
|
||||
let ret = unsafe { libc::uname(&mut utsname as *mut _) };
|
||||
if ret != 0 {
|
||||
return_errno!(EINVAL, "Vdso get utsname failed");
|
||||
}
|
||||
let release = utsname.release;
|
||||
|
||||
Self::match_kernel_version(vdso_addr, &release)
|
||||
}
|
||||
|
||||
fn check_vdso_addr(vdso_addr: &u64) -> Result<()> {
|
||||
let vdso_addr = *vdso_addr;
|
||||
if vdso_addr == 0 {
|
||||
return_errno!(EFAULT, "Vdso vdso_addr is 0")
|
||||
}
|
||||
const VDSO_DATA_MAX_SIZE: u64 = 4 * PAGE_SIZE;
|
||||
if vdso_addr < VDSO_DATA_MAX_SIZE {
|
||||
return_errno!(EFAULT, "Vdso vdso_addr is less than vdso data size");
|
||||
}
|
||||
|
||||
#[cfg(feature = "sgx")]
|
||||
if !sgx_trts::trts::rsgx_raw_is_outside_enclave(
|
||||
(vdso_addr - VDSO_DATA_MAX_SIZE) as *const u8,
|
||||
VDSO_DATA_MAX_SIZE as _,
|
||||
) {
|
||||
return_errno!(EFAULT, "Vdso vdso_addr we got is not outside enclave")
|
||||
}
|
||||
|
||||
Ok(())
|
||||
}
|
||||
|
||||
fn match_kernel_version(vdso_addr: u64, release: &[libc::c_char]) -> Result<VdsoDataPtr> {
|
||||
Self::check_vdso_addr(&vdso_addr)?;
|
||||
|
||||
// release, e.g., "5.9.6-050906-generic"
|
||||
let release = unsafe { &*(release as *const [i8] as *const [u8]) };
|
||||
let release = str::from_utf8(release);
|
||||
if release.is_err() {
|
||||
return_errno!(EINVAL, "Vdso get kernel release failed")
|
||||
}
|
||||
let mut release = release.unwrap().split(&['-', '.', ' '][..]);
|
||||
let version_big: u8 = release
|
||||
.next()
|
||||
.ok_or(errno!(EINVAL, "Vdso get kernel big version failed"))?
|
||||
.parse()?;
|
||||
let version_little: u8 = release
|
||||
.next()
|
||||
.ok_or(errno!(EINVAL, "Vdso get kernel little version failed"))?
|
||||
.parse()?;
|
||||
|
||||
Ok(match (version_big, version_little) {
|
||||
(4, 0..=4) | (4, 7..=11) => VdsoDataPtr::V4_0(vdso_data_v4_0::vdsodata_ptr(vdso_addr)),
|
||||
(4, 5..=6) | (4, 12..=19) => VdsoDataPtr::V4_5(vdso_data_v4_5::vdsodata_ptr(vdso_addr)),
|
||||
(5, 0..=2) => VdsoDataPtr::V5_0(vdso_data_v5_0::vdsodata_ptr(vdso_addr)),
|
||||
(5, 3..=5) => VdsoDataPtr::V5_3(vdso_data_v5_3::vdsodata_ptr(vdso_addr)),
|
||||
(5, 6..=8) => VdsoDataPtr::V5_6(vdso_data_v5_6::vdsodata_ptr(vdso_addr)),
|
||||
(5, 9..=19) | (6, 0..=2) => VdsoDataPtr::V5_9(vdso_data_v5_9::vdsodata_ptr(vdso_addr)),
|
||||
(_, _) => return_errno!(EINVAL, "Vdso match kernel release failed"),
|
||||
})
|
||||
}
|
||||
|
||||
/// Compare the results of Linux syscall and vdso to check whether vdso can support the clockid correctly.
|
||||
fn check_accuracy(&self) -> Result<()> {
|
||||
let vdso_supported_clockids = [
|
||||
ClockId::CLOCK_REALTIME,
|
||||
ClockId::CLOCK_MONOTONIC,
|
||||
ClockId::CLOCK_MONOTONIC_RAW,
|
||||
ClockId::CLOCK_REALTIME_COARSE,
|
||||
ClockId::CLOCK_MONOTONIC_COARSE,
|
||||
ClockId::CLOCK_BOOTTIME,
|
||||
];
|
||||
const MAX_INACCURACY: Duration = Duration::from_millis(1);
|
||||
const MAX_RETRY_NUM: u32 = 3;
|
||||
for &clockid in vdso_supported_clockids.iter() {
|
||||
for retry_num in 0..MAX_RETRY_NUM {
|
||||
let time = match self.do_clock_gettime(clockid) {
|
||||
Ok(time) => time,
|
||||
Err(_) => break,
|
||||
};
|
||||
|
||||
let host_time = match clock_gettime_slow(clockid) {
|
||||
Ok(host_time) => host_time,
|
||||
Err(_) => break,
|
||||
};
|
||||
|
||||
let estimated_inaccuracy = match host_time.checked_sub(time) {
|
||||
Some(diff) => diff,
|
||||
None => return_errno!(EOPNOTSUPP, "Vdso can not provide valid time"),
|
||||
};
|
||||
if estimated_inaccuracy > MAX_INACCURACY {
|
||||
if retry_num == MAX_RETRY_NUM - 1 {
|
||||
return_errno!(EOPNOTSUPP, "Vdso reached max retry number");
|
||||
}
|
||||
continue;
|
||||
}
|
||||
break;
|
||||
}
|
||||
}
|
||||
Ok(())
|
||||
}
|
||||
|
||||
/// Try to get time according to ClockId.
|
||||
/// Firstly try to get time through vDSO, if failed, then try fallback.
|
||||
///
|
||||
/// # Examples
|
||||
///
|
||||
/// ```
|
||||
/// use vdso_time::{Vdso, ClockId};
|
||||
/// let vdso = Vdso::new().unwrap();
|
||||
/// let time = vdso.clock_gettime(ClockId::CLOCK_MONOTONIC).unwrap();
|
||||
/// println!("{:?}", time);
|
||||
/// ```
|
||||
pub fn clock_gettime(&self, clockid: ClockId) -> Result<Duration> {
|
||||
self.do_clock_gettime(clockid)
|
||||
.or_else(|_| clock_gettime_slow(clockid))
|
||||
}
|
||||
|
||||
/// Try to get time resolution according to ClockId.
|
||||
/// Firstly try to return resolution inside self, if failed, then try fallback.
|
||||
///
|
||||
/// # Examples
|
||||
///
|
||||
/// ```
|
||||
/// use vdso_time::{Vdso, ClockId};
|
||||
/// let vdso = Vdso::new().unwrap();
|
||||
/// let res = vdso.clock_getres(ClockId::CLOCK_MONOTONIC).unwrap();
|
||||
/// println!("{:?}", res);
|
||||
/// ```
|
||||
pub fn clock_getres(&self, clockid: ClockId) -> Result<Duration> {
|
||||
self.do_clock_getres(clockid)
|
||||
.or_else(|_| clock_getres_slow(clockid))
|
||||
}
|
||||
|
||||
fn do_clock_gettime(&self, clockid: ClockId) -> Result<Duration> {
|
||||
match clockid {
|
||||
ClockId::CLOCK_REALTIME | ClockId::CLOCK_MONOTONIC | ClockId::CLOCK_BOOTTIME => {
|
||||
self.do_hres(ClockSource::CS_HRES_COARSE, clockid)
|
||||
}
|
||||
ClockId::CLOCK_MONOTONIC_RAW => self.do_hres(ClockSource::CS_RAW, clockid),
|
||||
ClockId::CLOCK_REALTIME_COARSE | ClockId::CLOCK_MONOTONIC_COARSE => {
|
||||
self.do_coarse(ClockSource::CS_HRES_COARSE, clockid)
|
||||
}
|
||||
// TODO: support CLOCK_PROCESS_CPUTIME_ID and CLOCK_THREAD_CPUTIME_ID.
|
||||
_ => return_errno!(EINVAL, "Unsupported clockid in do_clock_gettime()"),
|
||||
}
|
||||
}
|
||||
|
||||
fn do_clock_getres(&self, clockid: ClockId) -> Result<Duration> {
|
||||
match clockid {
|
||||
ClockId::CLOCK_REALTIME
|
||||
| ClockId::CLOCK_MONOTONIC
|
||||
| ClockId::CLOCK_BOOTTIME
|
||||
| ClockId::CLOCK_MONOTONIC_RAW => self
|
||||
.hres_resolution
|
||||
.ok_or(errno!(EOPNOTSUPP, "hres_resolution is none")),
|
||||
ClockId::CLOCK_REALTIME_COARSE | ClockId::CLOCK_MONOTONIC_COARSE => self
|
||||
.coarse_resolution
|
||||
.ok_or(errno!(EOPNOTSUPP, "coarse_resolution is none")),
|
||||
// TODO: support CLOCK_PROCESS_CPUTIME_ID and CLOCK_THREAD_CPUTIME_ID.
|
||||
_ => return_errno!(EINVAL, "Unsupported clockid in do_clock_getres()"),
|
||||
}
|
||||
}
|
||||
|
||||
fn vdso_data(&self, cs: ClockSource) -> &'static dyn VdsoData {
|
||||
match self.vdso_data_ptr {
|
||||
VdsoDataPtr::V4_0(ptr) => unsafe { &*(ptr) },
|
||||
VdsoDataPtr::V4_5(ptr) => unsafe { &*(ptr) },
|
||||
VdsoDataPtr::V5_0(ptr) => unsafe { &*(ptr) },
|
||||
VdsoDataPtr::V5_3(ptr) => unsafe { &*(ptr.add(cs as _)) },
|
||||
VdsoDataPtr::V5_6(ptr) => unsafe { &*(ptr.add(cs as _)) },
|
||||
VdsoDataPtr::V5_9(ptr) => unsafe { &*(ptr.add(cs as _)) },
|
||||
}
|
||||
}
|
||||
|
||||
fn do_hres(&self, cs: ClockSource, clockid: ClockId) -> Result<Duration> {
|
||||
let vdso_data = self.vdso_data(cs);
|
||||
loop {
|
||||
let seq = vdso_data.seq();
|
||||
// if seq is odd, it might means that a concurrent update is in progress.
|
||||
// Hence, we do some instructions to spin waiting for seq to become even again.
|
||||
if seq & 1 != 0 {
|
||||
hint::spin_loop();
|
||||
continue;
|
||||
}
|
||||
|
||||
// Make sure that all prior load-from-memory instructions have completed locally,
|
||||
// and no later instruction begins execution until LFENCE completes.
|
||||
// We want to make sure the execution order as followning:
|
||||
// seq -> [cycles, cycle_last, mult, shift, sec, secs] -> seq
|
||||
// This LFENCE can ensure that the first seq is before [cycles, cycle_last, mult, shift, sec, secs]
|
||||
lfence();
|
||||
|
||||
// Get hardware counter according to vdso_data's clock_mode.
|
||||
let cycles = Self::get_hw_counter(vdso_data)?;
|
||||
|
||||
let cycle_last = vdso_data.cycle_last();
|
||||
let mult = vdso_data.mult();
|
||||
let shift = vdso_data.shift();
|
||||
let secs = vdso_data.sec(clockid as _)?;
|
||||
let mut nanos = vdso_data.nsec(clockid as _)?;
|
||||
|
||||
if !Self::vdso_read_retry(vdso_data, seq) {
|
||||
// On x86 arch, the TSC can be slightly off across sockets,
|
||||
// which might cause cycles < cycle_last. Since they are u64 type,
|
||||
// cycles - cycle_last will panic in this case.
|
||||
// Hence we need to verify that cycles is greater than cycle_last.
|
||||
// If not then just use cycle_last, which is the base time of the
|
||||
// current conversion period.
|
||||
// And the vdso mask is always u64_MAX on x86, we don't need use mask.
|
||||
if cycles > cycle_last {
|
||||
nanos += (cycles - cycle_last) * mult as u64
|
||||
}
|
||||
nanos = nanos >> shift;
|
||||
|
||||
return Ok(Duration::new(secs, nanos as u32));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
fn do_coarse(&self, cs: ClockSource, clockid: ClockId) -> Result<Duration> {
|
||||
let vdso_data = self.vdso_data(cs);
|
||||
loop {
|
||||
let seq = vdso_data.seq();
|
||||
// see comments in do_hres
|
||||
if seq & 1 != 0 {
|
||||
hint::spin_loop();
|
||||
continue;
|
||||
}
|
||||
|
||||
// see comments in do_hres
|
||||
lfence();
|
||||
|
||||
let secs = vdso_data.sec(clockid as _)?;
|
||||
let nanos = vdso_data.nsec(clockid as _)?;
|
||||
|
||||
if !Self::vdso_read_retry(vdso_data, seq) {
|
||||
return Ok(Duration::new(secs, nanos as u32));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
fn vdso_read_retry(vdso_data: &dyn VdsoData, old_seq: u32) -> bool {
|
||||
// Make sure that all prior load-from-memory instructions have completed locally,
|
||||
// and no later instruction begins execution until LFENCE completes
|
||||
lfence();
|
||||
|
||||
old_seq != vdso_data.seq()
|
||||
}
|
||||
|
||||
fn get_hw_counter(vdso_data: &dyn VdsoData) -> Result<u64> {
|
||||
let clock_mode = vdso_data.clock_mode();
|
||||
if clock_mode == VdsoClockMode::VDSO_CLOCKMODE_TSC as i32 {
|
||||
return Ok(rdtsc_ordered());
|
||||
} else if clock_mode == VdsoClockMode::VDSO_CLOCKMODE_PVCLOCK as i32 {
|
||||
// TODO: support pvclock
|
||||
return_errno!(
|
||||
EOPNOTSUPP,
|
||||
"VDSO_CLOCKMODE_PVCLOCK support is not implemented"
|
||||
);
|
||||
} else if clock_mode == VdsoClockMode::VDSO_CLOCKMODE_HVCLOCK as i32 {
|
||||
// TODO: support hvclock
|
||||
return_errno!(
|
||||
EOPNOTSUPP,
|
||||
"VDSO_CLOCKMODE_HVCLOCK support is not implemented"
|
||||
);
|
||||
} else if clock_mode == VdsoClockMode::VDSO_CLOCKMODE_TIMENS as i32 {
|
||||
// TODO: support timens
|
||||
return_errno!(
|
||||
EOPNOTSUPP,
|
||||
"VDSO_CLOCKMODE_TIMENS support is not implemented"
|
||||
);
|
||||
} else if clock_mode == VdsoClockMode::VDSO_CLOCKMODE_NONE as i32 {
|
||||
// In x86 Linux, the clock_mode will never be VDSO_CLOCKMODE_NONE.
|
||||
return_errno!(EINVAL, "The clock_mode must not be VDSO_CLOCKMODE_NONE");
|
||||
}
|
||||
return_errno!(EINVAL, "Unsupported clock_mode");
|
||||
}
|
||||
}
|
||||
|
||||
unsafe impl Sync for Vdso {}
|
||||
unsafe impl Send for Vdso {}
|
||||
|
||||
lazy_static! {
|
||||
static ref VDSO: Option<Vdso> = Vdso::new().map_or_else(
|
||||
|e| {
|
||||
trace!("{}", e);
|
||||
None
|
||||
},
|
||||
|v| Some(v)
|
||||
);
|
||||
}
|
||||
|
||||
/// Try to get time according to ClockId.
|
||||
/// Firstly try to get time through vDSO, if failed, then try fallback.
|
||||
///
|
||||
/// # Examples
|
||||
///
|
||||
/// ```
|
||||
/// use vdso_time::ClockId;
|
||||
///
|
||||
/// let time = vdso_time::clock_gettime(ClockId::CLOCK_MONOTONIC).unwrap();
|
||||
/// println!("{:?}", time);
|
||||
/// ```
|
||||
pub fn clock_gettime(clockid: ClockId) -> Result<Duration> {
|
||||
if VDSO.is_none() {
|
||||
clock_gettime_slow(clockid)
|
||||
} else {
|
||||
VDSO.as_ref().unwrap().clock_gettime(clockid)
|
||||
}
|
||||
}
|
||||
|
||||
/// Try to get time resolution according to ClockId.
|
||||
/// Firstly try to get time through vDSO, if failed, then try fallback.
|
||||
///
|
||||
/// # Examples
|
||||
///
|
||||
/// ```
|
||||
/// use vdso_time::ClockId;
|
||||
///
|
||||
/// let time = vdso_time::clock_getres(ClockId::CLOCK_MONOTONIC).unwrap();
|
||||
/// println!("{:?}", time);
|
||||
/// ```
|
||||
pub fn clock_getres(clockid: ClockId) -> Result<Duration> {
|
||||
if VDSO.is_none() {
|
||||
clock_getres_slow(clockid)
|
||||
} else {
|
||||
VDSO.as_ref().unwrap().clock_getres(clockid)
|
||||
}
|
||||
}
|
||||
|
||||
fn clock_gettime_slow(clockid: ClockId) -> Result<Duration> {
|
||||
let mut ts = libc::timespec {
|
||||
tv_sec: 0,
|
||||
tv_nsec: 0,
|
||||
};
|
||||
|
||||
cfg_if::cfg_if! {
|
||||
if #[cfg(feature = "sgx")] {
|
||||
extern "C" {
|
||||
fn vdso_ocall_clock_gettime(
|
||||
ret: *mut libc::c_int,
|
||||
clockid: libc::c_int,
|
||||
ts: *mut libc::timespec,
|
||||
) -> sgx_types::sgx_status_t;
|
||||
}
|
||||
let mut ret: libc::c_int = 0;
|
||||
unsafe {
|
||||
vdso_ocall_clock_gettime(&mut ret as *mut _, clockid as _, &mut ts as *mut _);
|
||||
}
|
||||
} else {
|
||||
let ret = unsafe { libc::clock_gettime(clockid as _, &mut ts as *mut _) };
|
||||
}
|
||||
}
|
||||
|
||||
if ret == 0 {
|
||||
Ok(Duration::new(ts.tv_sec as u64, ts.tv_nsec as u32))
|
||||
} else {
|
||||
return_errno!(EINVAL, "clock_gettime_slow failed")
|
||||
}
|
||||
}
|
||||
|
||||
fn clock_getres_slow(clockid: ClockId) -> Result<Duration> {
|
||||
let mut res = libc::timespec {
|
||||
tv_sec: 0,
|
||||
tv_nsec: 0,
|
||||
};
|
||||
|
||||
cfg_if::cfg_if! {
|
||||
if #[cfg(feature = "sgx")] {
|
||||
extern "C" {
|
||||
fn vdso_ocall_clock_getres(
|
||||
ret: *mut libc::c_int,
|
||||
clockid: libc::c_int,
|
||||
res: *mut libc::timespec,
|
||||
) -> sgx_types::sgx_status_t;
|
||||
}
|
||||
let mut ret: libc::c_int = 0;
|
||||
unsafe {
|
||||
vdso_ocall_clock_getres(&mut ret as *mut _, clockid as _, &mut res as *mut _);
|
||||
}
|
||||
} else {
|
||||
let ret = unsafe { libc::clock_getres(clockid as _, &mut res as *mut _) };
|
||||
}
|
||||
}
|
||||
|
||||
if ret == 0 {
|
||||
Ok(Duration::new(res.tv_sec as u64, res.tv_nsec as u32))
|
||||
} else {
|
||||
return_errno!(EINVAL, "clock_getres_slow failed")
|
||||
}
|
||||
}
|
||||
|
||||
// All unit tests
|
||||
#[cfg(test)]
|
||||
#[allow(deprecated)]
|
||||
mod tests {
|
||||
use super::*;
|
||||
use std::thread;
|
||||
|
||||
const LOOPS: usize = 3;
|
||||
const SLEEP_DURATION: u64 = 10;
|
||||
const HRES_MAX_DIFF_NANOS: u64 = 50_000;
|
||||
const COARSE_MAX_DIFF_NANOS: u64 = 4_000_000;
|
||||
|
||||
#[test]
|
||||
fn test_clock_gettime() {
|
||||
test_single_clock_gettime(ClockId::CLOCK_REALTIME_COARSE, COARSE_MAX_DIFF_NANOS);
|
||||
test_single_clock_gettime(ClockId::CLOCK_MONOTONIC_COARSE, COARSE_MAX_DIFF_NANOS);
|
||||
test_single_clock_gettime(ClockId::CLOCK_REALTIME, HRES_MAX_DIFF_NANOS);
|
||||
test_single_clock_gettime(ClockId::CLOCK_MONOTONIC, HRES_MAX_DIFF_NANOS);
|
||||
test_single_clock_gettime(ClockId::CLOCK_BOOTTIME, HRES_MAX_DIFF_NANOS);
|
||||
test_single_clock_gettime(ClockId::CLOCK_MONOTONIC_RAW, HRES_MAX_DIFF_NANOS);
|
||||
}
|
||||
|
||||
fn test_single_clock_gettime(clockid: ClockId, max_diff_nanos: u64) {
|
||||
for _ in 0..LOOPS {
|
||||
let mut libc_tp = libc::timespec {
|
||||
tv_sec: 0,
|
||||
tv_nsec: 0,
|
||||
};
|
||||
unsafe { libc::clock_gettime(clockid as _, &mut libc_tp as *mut _) };
|
||||
let libc_time = Duration::new(libc_tp.tv_sec as u64, libc_tp.tv_nsec as u32);
|
||||
|
||||
let vdso_time = clock_gettime(clockid).unwrap();
|
||||
|
||||
assert!(vdso_time - libc_time <= Duration::from_nanos(max_diff_nanos));
|
||||
|
||||
thread::sleep(Duration::from_millis(SLEEP_DURATION));
|
||||
}
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_clock_getres() {
|
||||
test_single_clock_getres(ClockId::CLOCK_REALTIME_COARSE);
|
||||
test_single_clock_getres(ClockId::CLOCK_MONOTONIC_COARSE);
|
||||
test_single_clock_getres(ClockId::CLOCK_REALTIME);
|
||||
test_single_clock_getres(ClockId::CLOCK_MONOTONIC);
|
||||
test_single_clock_getres(ClockId::CLOCK_BOOTTIME);
|
||||
test_single_clock_getres(ClockId::CLOCK_MONOTONIC_RAW);
|
||||
}
|
||||
|
||||
fn test_single_clock_getres(clockid: ClockId) {
|
||||
for _ in 0..LOOPS {
|
||||
let mut libc_tp = libc::timespec {
|
||||
tv_sec: 0,
|
||||
tv_nsec: 0,
|
||||
};
|
||||
unsafe { libc::clock_getres(clockid as _, &mut libc_tp as *mut _) };
|
||||
|
||||
let res = clock_getres(clockid).unwrap();
|
||||
|
||||
assert_eq!(res.as_secs(), libc_tp.tv_sec as u64);
|
||||
assert_eq!(res.subsec_nanos(), libc_tp.tv_nsec as u32);
|
||||
}
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_monotonic() {
|
||||
let mut last_now = Duration::new(0, 0);
|
||||
for _ in 0..1_000_000 {
|
||||
let now = clock_gettime(ClockId::CLOCK_MONOTONIC).unwrap();
|
||||
assert!(now >= last_now);
|
||||
last_now = now;
|
||||
}
|
||||
}
|
||||
|
||||
mod logger {
|
||||
use log::{Level, LevelFilter, Metadata, Record};
|
||||
|
||||
#[ctor::ctor]
|
||||
fn auto_init() {
|
||||
log::set_logger(&LOGGER)
|
||||
.map(|()| log::set_max_level(LevelFilter::Trace))
|
||||
.expect("failed to init the logger");
|
||||
}
|
||||
|
||||
static LOGGER: SimpleLogger = SimpleLogger;
|
||||
|
||||
struct SimpleLogger;
|
||||
|
||||
impl log::Log for SimpleLogger {
|
||||
fn enabled(&self, metadata: &Metadata) -> bool {
|
||||
metadata.level() <= Level::Trace
|
||||
}
|
||||
|
||||
fn log(&self, record: &Record) {
|
||||
if self.enabled(record.metadata()) {
|
||||
println!("[{}] {}", record.level(), record.args());
|
||||
}
|
||||
}
|
||||
|
||||
fn flush(&self) {}
|
||||
}
|
||||
}
|
||||
}
|
595
src/libos/crates/vdso-time/src/sys.rs
Normal file
595
src/libos/crates/vdso-time/src/sys.rs
Normal file
@ -0,0 +1,595 @@
|
||||
use super::*;
|
||||
use std::sync::atomic::{AtomicU32, Ordering};
|
||||
|
||||
pub const PAGE_SIZE: u64 = 4096;
|
||||
|
||||
pub const CLOCK_TAI: usize = 11;
|
||||
pub const VDSO_BASES: usize = CLOCK_TAI + 1;
|
||||
|
||||
#[cfg(not(any(arget_arch = "x86", target_arch = "x86_64")))]
|
||||
compile_error!("Only support x86 or x86_64 architecture now.");
|
||||
|
||||
/// Reads the current value of the processor’s time-stamp counter.
|
||||
///
|
||||
/// The processor monotonically increments the time-stamp counter MSR every clock cycle
|
||||
/// and resets it to 0 whenever the processor is reset.
|
||||
///
|
||||
/// The RDTSC instruction is not a serializing instruction. It does not necessarily
|
||||
/// wait until all previous instructions have been executed before reading the counter.
|
||||
/// Similarly, subsequent instructions may begin execution before the read operation is performed.
|
||||
pub fn rdtsc() -> u64 {
|
||||
cfg_if::cfg_if! {
|
||||
if #[cfg(target_arch = "x86_64")] {
|
||||
unsafe { core::arch::x86_64::_rdtsc() as u64 }
|
||||
} else if #[cfg(target_arch = "x86")] {
|
||||
unsafe { core::arch::x86::_rdtsc() as u64 }
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/// Reads the current value of the processor’s time-stamp counter.
|
||||
///
|
||||
/// The processor monotonically increments the time-stamp counter MSR every clock cycle
|
||||
/// and resets it to 0 whenever the processor is reset.
|
||||
/// The RDTSCP instruction waits until all previous instructions have been executed before
|
||||
/// reading the counter. However, subsequent instructions may begin execution before
|
||||
/// the read operation is performed.
|
||||
#[allow(dead_code)]
|
||||
pub fn rdtscp() -> u64 {
|
||||
cfg_if::cfg_if! {
|
||||
if #[cfg(target_arch = "x86_64")] {
|
||||
let mut aux: u32 = 0;
|
||||
unsafe { core::arch::x86_64::__rdtscp(&mut aux) as u64 }
|
||||
} else if #[cfg(target_arch = "x86")] {
|
||||
let mut aux: u32 = 0;
|
||||
unsafe { core::arch::x86::__rdtscp(&mut aux) as u64 }
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/// Performs a serializing operation on all load-from-memory instructions
|
||||
/// that were issued prior to this instruction.
|
||||
///
|
||||
/// Guarantees that every load instruction that precedes, in program order,
|
||||
/// is globally visible before any load instruction which follows the fence in program order.
|
||||
pub fn lfence() {
|
||||
cfg_if::cfg_if! {
|
||||
if #[cfg(target_arch = "x86_64")] {
|
||||
unsafe { core::arch::x86_64::_mm_lfence() }
|
||||
} else if #[cfg(target_arch = "x86")] {
|
||||
unsafe { core::arch::x86::_mm_lfence() }
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/// Read the current TSC in program order.
|
||||
///
|
||||
/// The RDTSC instruction might not be ordered relative to memory access.
|
||||
/// But an RDTSC immediately after an appropriate barrier appears to be ordered as a normal load.
|
||||
/// Hence, we could use a barrier before RDTSC to get ordered TSC.
|
||||
///
|
||||
/// We also can just use RDTSCP, which is also ordered.
|
||||
pub fn rdtsc_ordered() -> u64 {
|
||||
lfence();
|
||||
rdtsc()
|
||||
}
|
||||
|
||||
/// The timers is divided in 3 sets (HRES, COARSE, RAW) since Linux v5.3.
|
||||
/// CS_HRES_COARSE refers to the first two and CS_RAW to the third.
|
||||
#[derive(Debug, Copy, Clone)]
|
||||
#[allow(non_camel_case_types)]
|
||||
pub enum ClockSource {
|
||||
CS_HRES_COARSE = 0,
|
||||
CS_RAW = 1,
|
||||
}
|
||||
|
||||
#[derive(Debug, Copy, Clone)]
|
||||
#[allow(non_camel_case_types)]
|
||||
pub enum VdsoClockMode {
|
||||
VDSO_CLOCKMODE_NONE = 0,
|
||||
VDSO_CLOCKMODE_TSC = 1,
|
||||
VDSO_CLOCKMODE_PVCLOCK = 2,
|
||||
VDSO_CLOCKMODE_HVCLOCK = 3,
|
||||
VDSO_CLOCKMODE_TIMENS = i32::MAX as isize,
|
||||
}
|
||||
|
||||
// Struct VdsoDataPtr must impl this trait to unify vdso_data interface of different linux verisons.
|
||||
pub trait VdsoData {
|
||||
fn sec(&self, clockid: ClockId) -> Result<u64>;
|
||||
fn nsec(&self, clockid: ClockId) -> Result<u64>;
|
||||
fn seq(&self) -> u32;
|
||||
fn clock_mode(&self) -> i32;
|
||||
fn cycle_last(&self) -> u64;
|
||||
fn mask(&self) -> u64;
|
||||
fn mult(&self) -> u32;
|
||||
fn shift(&self) -> u32;
|
||||
fn tz_minuteswest(&self) -> i32;
|
||||
fn tz_dsttime(&self) -> i32;
|
||||
|
||||
fn vdsodata_ptr(vdso_addr: u64) -> *const Self
|
||||
where
|
||||
Self: Sized;
|
||||
}
|
||||
|
||||
pub enum VdsoDataPtr {
|
||||
// === Linux 4.0 - 4.4, 4.7 - 4.11 ===
|
||||
V4_0(*const vdso_data_v4_0),
|
||||
// === Linux 4.5 - 4.6, 4.12 - 4.19 ===
|
||||
V4_5(*const vdso_data_v4_5),
|
||||
// === Linux 5.0 - 5.2 ===
|
||||
V5_0(*const vdso_data_v5_0),
|
||||
// === Linux 5.3 - 5.5 ===
|
||||
V5_3(*const vdso_data_v5_3),
|
||||
// === Linux 5.6 - 5.8 ===
|
||||
V5_6(*const vdso_data_v5_6),
|
||||
// === Linux 5.9 - 6.2 ===
|
||||
V5_9(*const vdso_data_v5_9),
|
||||
}
|
||||
|
||||
// === Linux 4.0 - 4.4, 4.7 - 4.11 ===
|
||||
// struct vsyscall_gtod_data
|
||||
|
||||
#[repr(C)]
|
||||
pub struct vdso_data_v4_0 {
|
||||
pub seq: AtomicU32,
|
||||
|
||||
pub vclock_mode: i32,
|
||||
pub cycle_last: u64,
|
||||
pub mask: u64,
|
||||
pub mult: u32,
|
||||
pub shift: u32,
|
||||
|
||||
pub wall_time_snsec: u64,
|
||||
pub wall_time_sec: u64,
|
||||
pub monotonic_time_sec: u64,
|
||||
pub monotonic_time_snsec: u64,
|
||||
pub wall_time_coarse_sec: u64,
|
||||
pub wall_time_coarse_nsec: u64,
|
||||
pub monotonic_time_coarse_sec: u64,
|
||||
pub monotonic_time_coarse_nsec: u64,
|
||||
|
||||
pub tz_minuteswest: i32,
|
||||
pub tz_dsttime: i32,
|
||||
}
|
||||
|
||||
impl VdsoData for vdso_data_v4_0 {
|
||||
fn vdsodata_ptr(vdso_addr: u64) -> *const Self {
|
||||
(vdso_addr - 2 * PAGE_SIZE + 128) as *const Self
|
||||
}
|
||||
|
||||
fn sec(&self, clockid: ClockId) -> Result<u64> {
|
||||
match clockid {
|
||||
ClockId::CLOCK_REALTIME => Ok(self.wall_time_sec),
|
||||
ClockId::CLOCK_MONOTONIC => Ok(self.monotonic_time_sec),
|
||||
ClockId::CLOCK_REALTIME_COARSE => Ok(self.wall_time_coarse_sec),
|
||||
ClockId::CLOCK_MONOTONIC_COARSE => Ok(self.monotonic_time_coarse_sec),
|
||||
_ => return_errno!(EINVAL, "Unsupported clockid in sec()"),
|
||||
}
|
||||
}
|
||||
|
||||
fn nsec(&self, clockid: ClockId) -> Result<u64> {
|
||||
match clockid {
|
||||
ClockId::CLOCK_REALTIME => Ok(self.wall_time_snsec),
|
||||
ClockId::CLOCK_MONOTONIC => Ok(self.monotonic_time_snsec),
|
||||
ClockId::CLOCK_REALTIME_COARSE => Ok(self.wall_time_coarse_nsec),
|
||||
ClockId::CLOCK_MONOTONIC_COARSE => Ok(self.monotonic_time_coarse_nsec),
|
||||
_ => return_errno!(EINVAL, "Unsupported clockid in nsec()"),
|
||||
}
|
||||
}
|
||||
|
||||
fn seq(&self) -> u32 {
|
||||
self.seq.load(Ordering::Relaxed)
|
||||
}
|
||||
|
||||
fn clock_mode(&self) -> i32 {
|
||||
self.vclock_mode
|
||||
}
|
||||
|
||||
fn cycle_last(&self) -> u64 {
|
||||
self.cycle_last
|
||||
}
|
||||
|
||||
fn mask(&self) -> u64 {
|
||||
self.mask
|
||||
}
|
||||
|
||||
fn mult(&self) -> u32 {
|
||||
self.mult
|
||||
}
|
||||
|
||||
fn shift(&self) -> u32 {
|
||||
self.shift
|
||||
}
|
||||
|
||||
fn tz_minuteswest(&self) -> i32 {
|
||||
self.tz_minuteswest
|
||||
}
|
||||
|
||||
fn tz_dsttime(&self) -> i32 {
|
||||
self.tz_dsttime
|
||||
}
|
||||
}
|
||||
|
||||
// === Linux 4.5 - 4.6, 4.12 - 4.19 ===
|
||||
// struct vsyscall_gtod_data
|
||||
|
||||
#[repr(C)]
|
||||
pub struct vdso_data_v4_5 {
|
||||
pub seq: AtomicU32,
|
||||
|
||||
pub vclock_mode: i32,
|
||||
pub cycle_last: u64,
|
||||
pub mask: u64,
|
||||
pub mult: u32,
|
||||
pub shift: u32,
|
||||
|
||||
pub wall_time_snsec: u64,
|
||||
pub wall_time_sec: u64,
|
||||
pub monotonic_time_sec: u64,
|
||||
pub monotonic_time_snsec: u64,
|
||||
pub wall_time_coarse_sec: u64,
|
||||
pub wall_time_coarse_nsec: u64,
|
||||
pub monotonic_time_coarse_sec: u64,
|
||||
pub monotonic_time_coarse_nsec: u64,
|
||||
|
||||
pub tz_minuteswest: i32,
|
||||
pub tz_dsttime: i32,
|
||||
}
|
||||
|
||||
impl VdsoData for vdso_data_v4_5 {
|
||||
fn vdsodata_ptr(vdso_addr: u64) -> *const Self {
|
||||
(vdso_addr - 3 * PAGE_SIZE + 128) as *const Self
|
||||
}
|
||||
|
||||
fn sec(&self, clockid: ClockId) -> Result<u64> {
|
||||
match clockid {
|
||||
ClockId::CLOCK_REALTIME => Ok(self.wall_time_sec),
|
||||
ClockId::CLOCK_MONOTONIC => Ok(self.monotonic_time_sec),
|
||||
ClockId::CLOCK_REALTIME_COARSE => Ok(self.wall_time_coarse_sec),
|
||||
ClockId::CLOCK_MONOTONIC_COARSE => Ok(self.monotonic_time_coarse_sec),
|
||||
_ => return_errno!(EINVAL, "Unsupported clockid in sec()"),
|
||||
}
|
||||
}
|
||||
|
||||
fn nsec(&self, clockid: ClockId) -> Result<u64> {
|
||||
match clockid {
|
||||
ClockId::CLOCK_REALTIME => Ok(self.wall_time_snsec),
|
||||
ClockId::CLOCK_MONOTONIC => Ok(self.monotonic_time_snsec),
|
||||
ClockId::CLOCK_REALTIME_COARSE => Ok(self.wall_time_coarse_nsec),
|
||||
ClockId::CLOCK_MONOTONIC_COARSE => Ok(self.monotonic_time_coarse_nsec),
|
||||
_ => return_errno!(EINVAL, "Unsupported clockid in nsec()"),
|
||||
}
|
||||
}
|
||||
|
||||
fn seq(&self) -> u32 {
|
||||
self.seq.load(Ordering::Relaxed)
|
||||
}
|
||||
|
||||
fn clock_mode(&self) -> i32 {
|
||||
self.vclock_mode
|
||||
}
|
||||
|
||||
fn cycle_last(&self) -> u64 {
|
||||
self.cycle_last
|
||||
}
|
||||
|
||||
fn mask(&self) -> u64 {
|
||||
self.mask
|
||||
}
|
||||
|
||||
fn mult(&self) -> u32 {
|
||||
self.mult
|
||||
}
|
||||
|
||||
fn shift(&self) -> u32 {
|
||||
self.shift
|
||||
}
|
||||
|
||||
fn tz_minuteswest(&self) -> i32 {
|
||||
self.tz_minuteswest
|
||||
}
|
||||
|
||||
fn tz_dsttime(&self) -> i32 {
|
||||
self.tz_dsttime
|
||||
}
|
||||
}
|
||||
|
||||
// === Linux 5.0 - 5.2 ===
|
||||
// struct vsyscall_gtod_data
|
||||
|
||||
#[repr(C)]
|
||||
pub struct vdso_data_v5_0 {
|
||||
pub seq: AtomicU32,
|
||||
|
||||
pub vclock_mode: i32,
|
||||
pub cycle_last: u64,
|
||||
pub mask: u64,
|
||||
pub mult: u32,
|
||||
pub shift: u32,
|
||||
|
||||
pub basetime: [vgtod_ts; VDSO_BASES],
|
||||
|
||||
pub tz_minuteswest: i32,
|
||||
pub tz_dsttime: i32,
|
||||
}
|
||||
|
||||
#[repr(C)]
|
||||
#[derive(Debug, Default, Copy, Clone)]
|
||||
pub struct vgtod_ts {
|
||||
pub sec: u64,
|
||||
pub nsec: u64,
|
||||
}
|
||||
|
||||
impl VdsoData for vdso_data_v5_0 {
|
||||
fn vdsodata_ptr(vdso_addr: u64) -> *const Self {
|
||||
(vdso_addr - 3 * PAGE_SIZE + 128) as *const Self
|
||||
}
|
||||
|
||||
fn sec(&self, clockid: ClockId) -> Result<u64> {
|
||||
Ok(self.basetime[clockid as usize].sec)
|
||||
}
|
||||
|
||||
fn nsec(&self, clockid: ClockId) -> Result<u64> {
|
||||
Ok(self.basetime[clockid as usize].nsec)
|
||||
}
|
||||
|
||||
fn seq(&self) -> u32 {
|
||||
self.seq.load(Ordering::Relaxed)
|
||||
}
|
||||
|
||||
fn clock_mode(&self) -> i32 {
|
||||
self.vclock_mode
|
||||
}
|
||||
|
||||
fn cycle_last(&self) -> u64 {
|
||||
self.cycle_last
|
||||
}
|
||||
|
||||
fn mask(&self) -> u64 {
|
||||
self.mask
|
||||
}
|
||||
|
||||
fn mult(&self) -> u32 {
|
||||
self.mult
|
||||
}
|
||||
|
||||
fn shift(&self) -> u32 {
|
||||
self.shift
|
||||
}
|
||||
|
||||
fn tz_minuteswest(&self) -> i32 {
|
||||
self.tz_minuteswest
|
||||
}
|
||||
|
||||
fn tz_dsttime(&self) -> i32 {
|
||||
self.tz_dsttime
|
||||
}
|
||||
}
|
||||
|
||||
// === Linux 5.3 - 5.5 ===
|
||||
// struct vdso_data
|
||||
|
||||
#[repr(C)]
|
||||
pub struct vdso_data_v5_3 {
|
||||
pub seq: AtomicU32,
|
||||
|
||||
pub clock_mode: i32,
|
||||
pub cycle_last: u64,
|
||||
pub mask: u64,
|
||||
pub mult: u32,
|
||||
pub shift: u32,
|
||||
|
||||
pub basetime: [vdso_timestamp; VDSO_BASES],
|
||||
|
||||
pub tz_minuteswest: i32,
|
||||
pub tz_dsttime: i32,
|
||||
pub hrtimer_res: u32,
|
||||
pub __unused: u32,
|
||||
}
|
||||
|
||||
#[repr(C)]
|
||||
#[derive(Debug, Default, Copy, Clone)]
|
||||
pub struct vdso_timestamp {
|
||||
pub sec: u64,
|
||||
pub nsec: u64,
|
||||
}
|
||||
|
||||
impl VdsoData for vdso_data_v5_3 {
|
||||
fn vdsodata_ptr(vdso_addr: u64) -> *const Self {
|
||||
(vdso_addr - 3 * PAGE_SIZE + 128) as *const Self
|
||||
}
|
||||
|
||||
fn sec(&self, clockid: ClockId) -> Result<u64> {
|
||||
Ok(self.basetime[clockid as usize].sec)
|
||||
}
|
||||
|
||||
fn nsec(&self, clockid: ClockId) -> Result<u64> {
|
||||
Ok(self.basetime[clockid as usize].nsec)
|
||||
}
|
||||
|
||||
fn seq(&self) -> u32 {
|
||||
self.seq.load(Ordering::Relaxed)
|
||||
}
|
||||
|
||||
fn clock_mode(&self) -> i32 {
|
||||
self.clock_mode
|
||||
}
|
||||
|
||||
fn cycle_last(&self) -> u64 {
|
||||
self.cycle_last
|
||||
}
|
||||
|
||||
fn mask(&self) -> u64 {
|
||||
self.mask
|
||||
}
|
||||
|
||||
fn mult(&self) -> u32 {
|
||||
self.mult
|
||||
}
|
||||
|
||||
fn shift(&self) -> u32 {
|
||||
self.shift
|
||||
}
|
||||
|
||||
fn tz_minuteswest(&self) -> i32 {
|
||||
self.tz_minuteswest
|
||||
}
|
||||
|
||||
fn tz_dsttime(&self) -> i32 {
|
||||
self.tz_dsttime
|
||||
}
|
||||
}
|
||||
|
||||
// === Linux 5.6 - 5.8 ===
|
||||
// struct vdso_data
|
||||
|
||||
#[repr(C)]
|
||||
pub struct vdso_data_v5_6 {
|
||||
pub seq: AtomicU32,
|
||||
|
||||
pub clock_mode: i32,
|
||||
pub cycle_last: u64,
|
||||
pub mask: u64,
|
||||
pub mult: u32,
|
||||
pub shift: u32,
|
||||
|
||||
pub union_1: vdso_data_v5_6_union_1,
|
||||
|
||||
pub tz_minuteswest: i32,
|
||||
pub tz_dsttime: i32,
|
||||
pub hrtimer_res: u32,
|
||||
pub __unused: u32,
|
||||
}
|
||||
|
||||
#[repr(C)]
|
||||
#[derive(Debug, Default, Copy, Clone)]
|
||||
pub struct timens_offset {
|
||||
pub sec: i64,
|
||||
pub nsec: u64,
|
||||
}
|
||||
|
||||
#[repr(C)]
|
||||
#[derive(Copy, Clone)]
|
||||
pub union vdso_data_v5_6_union_1 {
|
||||
pub basetime: [vdso_timestamp; VDSO_BASES],
|
||||
pub offset: [timens_offset; VDSO_BASES],
|
||||
}
|
||||
|
||||
impl VdsoData for vdso_data_v5_6 {
|
||||
fn vdsodata_ptr(vdso_addr: u64) -> *const Self {
|
||||
(vdso_addr - 4 * PAGE_SIZE + 128) as *const Self
|
||||
}
|
||||
|
||||
fn sec(&self, clockid: ClockId) -> Result<u64> {
|
||||
unsafe { Ok(self.union_1.basetime[clockid as usize].sec) }
|
||||
}
|
||||
|
||||
fn nsec(&self, clockid: ClockId) -> Result<u64> {
|
||||
unsafe { Ok(self.union_1.basetime[clockid as usize].nsec) }
|
||||
}
|
||||
|
||||
fn seq(&self) -> u32 {
|
||||
self.seq.load(Ordering::Relaxed)
|
||||
}
|
||||
|
||||
fn clock_mode(&self) -> i32 {
|
||||
self.clock_mode
|
||||
}
|
||||
|
||||
fn cycle_last(&self) -> u64 {
|
||||
self.cycle_last
|
||||
}
|
||||
|
||||
fn mask(&self) -> u64 {
|
||||
self.mask
|
||||
}
|
||||
|
||||
fn mult(&self) -> u32 {
|
||||
self.mult
|
||||
}
|
||||
|
||||
fn shift(&self) -> u32 {
|
||||
self.shift
|
||||
}
|
||||
|
||||
fn tz_minuteswest(&self) -> i32 {
|
||||
self.tz_minuteswest
|
||||
}
|
||||
|
||||
fn tz_dsttime(&self) -> i32 {
|
||||
self.tz_dsttime
|
||||
}
|
||||
}
|
||||
|
||||
// === Linux 5.9 - 5.19, 6.0 - 6.2 ===
|
||||
// struct vdso_data
|
||||
|
||||
#[repr(C)]
|
||||
pub struct vdso_data_v5_9 {
|
||||
pub seq: AtomicU32,
|
||||
|
||||
pub clock_mode: i32,
|
||||
pub cycle_last: u64,
|
||||
pub mask: u64,
|
||||
pub mult: u32,
|
||||
pub shift: u32,
|
||||
|
||||
pub union_1: vdso_data_v5_6_union_1,
|
||||
|
||||
pub tz_minuteswest: i32,
|
||||
pub tz_dsttime: i32,
|
||||
pub hrtimer_res: u32,
|
||||
pub __unused: u32,
|
||||
|
||||
pub arch_data: arch_vdso_data,
|
||||
}
|
||||
|
||||
#[repr(C)]
|
||||
#[derive(Debug, Default, Copy, Clone)]
|
||||
pub struct arch_vdso_data {}
|
||||
|
||||
impl VdsoData for vdso_data_v5_9 {
|
||||
fn vdsodata_ptr(vdso_addr: u64) -> *const Self {
|
||||
(vdso_addr - 4 * PAGE_SIZE + 128) as *const Self
|
||||
}
|
||||
|
||||
fn sec(&self, clockid: ClockId) -> Result<u64> {
|
||||
unsafe { Ok(self.union_1.basetime[clockid as usize].sec) }
|
||||
}
|
||||
|
||||
fn nsec(&self, clockid: ClockId) -> Result<u64> {
|
||||
unsafe { Ok(self.union_1.basetime[clockid as usize].nsec) }
|
||||
}
|
||||
|
||||
fn seq(&self) -> u32 {
|
||||
self.seq.load(Ordering::Relaxed)
|
||||
}
|
||||
|
||||
fn clock_mode(&self) -> i32 {
|
||||
self.clock_mode
|
||||
}
|
||||
|
||||
fn cycle_last(&self) -> u64 {
|
||||
self.cycle_last
|
||||
}
|
||||
|
||||
fn mask(&self) -> u64 {
|
||||
self.mask
|
||||
}
|
||||
|
||||
fn mult(&self) -> u32 {
|
||||
self.mult
|
||||
}
|
||||
|
||||
fn shift(&self) -> u32 {
|
||||
self.shift
|
||||
}
|
||||
|
||||
fn tz_minuteswest(&self) -> i32 {
|
||||
self.tz_minuteswest
|
||||
}
|
||||
|
||||
fn tz_dsttime(&self) -> i32 {
|
||||
self.tz_dsttime
|
||||
}
|
||||
}
|
@ -1,3 +1 @@
|
||||
use super::*;
|
||||
|
||||
pub use errno::{Errno::*, *};
|
||||
|
@ -6,7 +6,7 @@ use super::file_ops::{
|
||||
};
|
||||
use super::fs_ops;
|
||||
use super::fs_ops::{MountFlags, MountOptions, UmountFlags};
|
||||
use super::time::{clockid_t, itimerspec_t, timespec_t, timeval_t, ClockID};
|
||||
use super::time::{clockid_t, itimerspec_t, timespec_t, timeval_t, ClockId};
|
||||
use super::timer_file::{TimerCreationFlags, TimerSetFlags};
|
||||
use super::*;
|
||||
use crate::config::{user_rootfs_config, ConfigApp, ConfigMountFsType};
|
||||
@ -42,9 +42,9 @@ pub fn do_eventfd2(init_val: u32, flags: i32) -> Result<isize> {
|
||||
pub fn do_timerfd_create(clockid: clockid_t, flags: i32) -> Result<isize> {
|
||||
debug!("timerfd: clockid {}, flags {} ", clockid, flags);
|
||||
|
||||
let clockid = ClockID::from_raw(clockid)?;
|
||||
let clockid = ClockId::try_from(clockid)?;
|
||||
match clockid {
|
||||
ClockID::CLOCK_REALTIME | ClockID::CLOCK_MONOTONIC => {}
|
||||
ClockId::CLOCK_REALTIME | ClockId::CLOCK_MONOTONIC => {}
|
||||
_ => {
|
||||
return_errno!(EINVAL, "invalid clockid");
|
||||
}
|
||||
|
@ -1,6 +1,6 @@
|
||||
use super::*;
|
||||
|
||||
use crate::time::{clockid_t, itimerspec_t, timespec_t, ClockID};
|
||||
use crate::time::{clockid_t, itimerspec_t, timespec_t, ClockId};
|
||||
use atomic::{Atomic, Ordering};
|
||||
use std::time::Duration;
|
||||
|
||||
@ -13,7 +13,7 @@ pub struct TimerFile {
|
||||
}
|
||||
|
||||
impl TimerFile {
|
||||
pub fn new(clockid: ClockID, flags: TimerCreationFlags) -> Result<Self> {
|
||||
pub fn new(clockid: ClockId, flags: TimerCreationFlags) -> Result<Self> {
|
||||
let raw_host_fd = try_libc!({
|
||||
let mut ret: i32 = 0;
|
||||
let status = occlum_ocall_timerfd_create(&mut ret, clockid as clockid_t, flags.bits());
|
||||
|
@ -66,6 +66,7 @@ extern crate intrusive_collections;
|
||||
extern crate itertools;
|
||||
extern crate modular_bitfield;
|
||||
extern crate resolv_conf;
|
||||
extern crate vdso_time;
|
||||
|
||||
use sgx_trts::libc;
|
||||
use sgx_types::*;
|
||||
|
@ -102,12 +102,12 @@ pub fn do_exec(
|
||||
// Blocking wait until there is only one thread in the calling process
|
||||
fn wait_for_other_threads_to_exit(current_ref: &ThreadRef) {
|
||||
use super::do_futex::{self, FutexTimeout};
|
||||
use crate::time::{timespec_t, ClockID};
|
||||
use crate::time::{timespec_t, ClockId};
|
||||
use core::time::Duration;
|
||||
|
||||
// Set timeout to 50ms
|
||||
let timeout = FutexTimeout::new(
|
||||
ClockID::CLOCK_MONOTONIC,
|
||||
ClockId::CLOCK_MONOTONIC,
|
||||
timespec_t::from(Duration::from_millis(50)),
|
||||
false,
|
||||
);
|
||||
|
@ -4,7 +4,7 @@ use std::intrinsics::atomic_load_seqcst;
|
||||
use std::sync::atomic::{AtomicBool, Ordering};
|
||||
|
||||
use crate::prelude::*;
|
||||
use crate::time::{timespec_t, ClockID};
|
||||
use crate::time::{timespec_t, ClockId};
|
||||
|
||||
/// `FutexOp`, `FutexFlags`, and `futex_op_and_flags_from_u32` are helper types and
|
||||
/// functions for handling the versatile commands and arguments of futex system
|
||||
@ -75,13 +75,13 @@ const FUTEX_BITSET_MATCH_ANY: u32 = 0xFFFF_FFFF;
|
||||
|
||||
#[derive(Debug, Copy, Clone)]
|
||||
pub struct FutexTimeout {
|
||||
clock_id: ClockID,
|
||||
clock_id: ClockId,
|
||||
ts: timespec_t,
|
||||
absolute_time: bool,
|
||||
}
|
||||
|
||||
impl FutexTimeout {
|
||||
pub fn new(clock_id: ClockID, ts: timespec_t, absolute_time: bool) -> Self {
|
||||
pub fn new(clock_id: ClockId, ts: timespec_t, absolute_time: bool) -> Self {
|
||||
Self {
|
||||
clock_id,
|
||||
ts,
|
||||
@ -89,7 +89,7 @@ impl FutexTimeout {
|
||||
}
|
||||
}
|
||||
|
||||
pub fn clock_id(&self) -> &ClockID {
|
||||
pub fn clock_id(&self) -> &ClockId {
|
||||
&self.clock_id
|
||||
}
|
||||
|
||||
@ -502,7 +502,7 @@ fn wait_event_timeout(thread: *const c_void, timeout: &Option<FutexTimeout>) ->
|
||||
.as_ref()
|
||||
.map(|timeout| {
|
||||
let clockbit = match timeout.clock_id() {
|
||||
ClockID::CLOCK_REALTIME => FutexFlags::FUTEX_CLOCK_REALTIME.bits() as i32,
|
||||
ClockId::CLOCK_REALTIME => FutexFlags::FUTEX_CLOCK_REALTIME.bits() as i32,
|
||||
_ => 0,
|
||||
};
|
||||
(
|
||||
|
@ -11,7 +11,7 @@ use super::process::ProcessFilter;
|
||||
use super::spawn_attribute::{clone_spawn_atrributes_safely, posix_spawnattr_t, SpawnAttr};
|
||||
use crate::prelude::*;
|
||||
use crate::syscall::CpuContext;
|
||||
use crate::time::{timespec_t, ClockID};
|
||||
use crate::time::{timespec_t, ClockId};
|
||||
use crate::util::mem_util::from_user::*;
|
||||
use std::ptr::NonNull;
|
||||
|
||||
@ -290,9 +290,9 @@ pub fn do_futex(
|
||||
"FUTEX_CLOCK_REALTIME with this futex operation is not supported"
|
||||
);
|
||||
}
|
||||
ClockID::CLOCK_REALTIME
|
||||
ClockId::CLOCK_REALTIME
|
||||
} else {
|
||||
ClockID::CLOCK_MONOTONIC
|
||||
ClockId::CLOCK_MONOTONIC
|
||||
};
|
||||
|
||||
// From futex man page:
|
||||
|
@ -932,7 +932,7 @@ fn do_gettimeofday(tv_u: *mut timeval_t) -> Result<isize> {
|
||||
|
||||
fn do_clock_gettime(clockid: clockid_t, ts_u: *mut timespec_t) -> Result<isize> {
|
||||
check_mut_ptr(ts_u)?;
|
||||
let clockid = time::ClockID::from_raw(clockid)?;
|
||||
let clockid = time::ClockId::try_from(clockid)?;
|
||||
let ts = time::do_clock_gettime(clockid)?;
|
||||
unsafe {
|
||||
*ts_u = ts;
|
||||
@ -941,7 +941,7 @@ fn do_clock_gettime(clockid: clockid_t, ts_u: *mut timespec_t) -> Result<isize>
|
||||
}
|
||||
|
||||
fn do_time(tloc_u: *mut time_t) -> Result<isize> {
|
||||
let ts = time::do_clock_gettime(time::ClockID::CLOCK_REALTIME)?;
|
||||
let ts = time::do_clock_gettime(time::ClockId::CLOCK_REALTIME)?;
|
||||
if !tloc_u.is_null() {
|
||||
check_mut_ptr(tloc_u)?;
|
||||
unsafe {
|
||||
@ -952,7 +952,7 @@ fn do_time(tloc_u: *mut time_t) -> Result<isize> {
|
||||
}
|
||||
|
||||
fn do_clock_getres(clockid: clockid_t, res_u: *mut timespec_t) -> Result<isize> {
|
||||
let clockid = time::ClockID::from_raw(clockid)?;
|
||||
let clockid = time::ClockId::try_from(clockid)?;
|
||||
if res_u.is_null() {
|
||||
return Ok(0);
|
||||
}
|
||||
@ -981,7 +981,7 @@ fn do_clock_nanosleep(
|
||||
} else {
|
||||
None
|
||||
};
|
||||
let clockid = time::ClockID::from_raw(clockid)?;
|
||||
let clockid = time::ClockId::try_from(clockid)?;
|
||||
time::do_clock_nanosleep(clockid, flags, &req, rem)?;
|
||||
Ok(0)
|
||||
}
|
||||
|
@ -14,6 +14,7 @@ pub mod up_time;
|
||||
|
||||
pub use profiler::ThreadProfiler;
|
||||
pub use timer_slack::TIMERSLACK;
|
||||
pub use vdso_time::ClockId;
|
||||
|
||||
#[allow(non_camel_case_types)]
|
||||
pub type time_t = i64;
|
||||
@ -74,15 +75,9 @@ impl From<Duration> for timeval_t {
|
||||
}
|
||||
|
||||
pub fn do_gettimeofday() -> timeval_t {
|
||||
extern "C" {
|
||||
fn occlum_ocall_gettimeofday(tv: *mut timeval_t) -> sgx_status_t;
|
||||
}
|
||||
|
||||
let mut tv: timeval_t = Default::default();
|
||||
unsafe {
|
||||
occlum_ocall_gettimeofday(&mut tv as *mut timeval_t);
|
||||
}
|
||||
tv.validate().expect("ocall returned invalid timeval_t");
|
||||
let tv = timeval_t::from(vdso_time::clock_gettime(ClockId::CLOCK_REALTIME).unwrap());
|
||||
tv.validate()
|
||||
.expect("gettimeofday returned invalid timeval_t");
|
||||
tv
|
||||
}
|
||||
|
||||
@ -149,58 +144,15 @@ impl timespec_t {
|
||||
#[allow(non_camel_case_types)]
|
||||
pub type clockid_t = i32;
|
||||
|
||||
#[derive(Debug, Copy, Clone)]
|
||||
#[allow(non_camel_case_types)]
|
||||
pub enum ClockID {
|
||||
CLOCK_REALTIME = 0,
|
||||
CLOCK_MONOTONIC = 1,
|
||||
CLOCK_PROCESS_CPUTIME_ID = 2,
|
||||
CLOCK_THREAD_CPUTIME_ID = 3,
|
||||
CLOCK_MONOTONIC_RAW = 4,
|
||||
CLOCK_REALTIME_COARSE = 5,
|
||||
CLOCK_MONOTONIC_COARSE = 6,
|
||||
CLOCK_BOOTTIME = 7,
|
||||
}
|
||||
|
||||
impl ClockID {
|
||||
#[deny(unreachable_patterns)]
|
||||
pub fn from_raw(clockid: clockid_t) -> Result<ClockID> {
|
||||
Ok(match clockid as i32 {
|
||||
0 => ClockID::CLOCK_REALTIME,
|
||||
1 => ClockID::CLOCK_MONOTONIC,
|
||||
2 => ClockID::CLOCK_PROCESS_CPUTIME_ID,
|
||||
3 => ClockID::CLOCK_THREAD_CPUTIME_ID,
|
||||
4 => ClockID::CLOCK_MONOTONIC_RAW,
|
||||
5 => ClockID::CLOCK_REALTIME_COARSE,
|
||||
6 => ClockID::CLOCK_MONOTONIC_COARSE,
|
||||
7 => ClockID::CLOCK_BOOTTIME,
|
||||
_ => return_errno!(EINVAL, "invalid command"),
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
pub fn do_clock_gettime(clockid: ClockID) -> Result<timespec_t> {
|
||||
extern "C" {
|
||||
fn occlum_ocall_clock_gettime(clockid: clockid_t, tp: *mut timespec_t) -> sgx_status_t;
|
||||
}
|
||||
|
||||
let mut tv: timespec_t = Default::default();
|
||||
unsafe {
|
||||
occlum_ocall_clock_gettime(clockid as clockid_t, &mut tv as *mut timespec_t);
|
||||
}
|
||||
tv.validate().expect("ocall returned invalid timespec");
|
||||
pub fn do_clock_gettime(clockid: ClockId) -> Result<timespec_t> {
|
||||
let tv = timespec_t::from(vdso_time::clock_gettime(clockid).unwrap());
|
||||
tv.validate()
|
||||
.expect("clock_gettime returned invalid timespec");
|
||||
Ok(tv)
|
||||
}
|
||||
|
||||
pub fn do_clock_getres(clockid: ClockID) -> Result<timespec_t> {
|
||||
extern "C" {
|
||||
fn occlum_ocall_clock_getres(clockid: clockid_t, res: *mut timespec_t) -> sgx_status_t;
|
||||
}
|
||||
|
||||
let mut res: timespec_t = Default::default();
|
||||
unsafe {
|
||||
occlum_ocall_clock_getres(clockid as clockid_t, &mut res as *mut timespec_t);
|
||||
}
|
||||
pub fn do_clock_getres(clockid: ClockId) -> Result<timespec_t> {
|
||||
let res = timespec_t::from(vdso_time::clock_getres(clockid).unwrap());
|
||||
let validate_resolution = |res: ×pec_t| -> Result<()> {
|
||||
// The resolution can be ranged from 1 nanosecond to a few milliseconds
|
||||
if res.sec == 0 && res.nsec > 0 && res.nsec < 1_000_000_000 {
|
||||
@ -210,14 +162,14 @@ pub fn do_clock_getres(clockid: ClockID) -> Result<timespec_t> {
|
||||
}
|
||||
};
|
||||
// do sanity check
|
||||
validate_resolution(&res).expect("ocall returned invalid resolution");
|
||||
validate_resolution(&res).expect("clock_getres returned invalid resolution");
|
||||
Ok(res)
|
||||
}
|
||||
|
||||
const TIMER_ABSTIME: i32 = 0x01;
|
||||
|
||||
pub fn do_clock_nanosleep(
|
||||
clockid: ClockID,
|
||||
clockid: ClockId,
|
||||
flags: i32,
|
||||
req: ×pec_t,
|
||||
rem: Option<&mut timespec_t>,
|
||||
@ -235,11 +187,11 @@ pub fn do_clock_nanosleep(
|
||||
let mut ret = 0;
|
||||
let mut u_rem: timespec_t = timespec_t { sec: 0, nsec: 0 };
|
||||
match clockid {
|
||||
ClockID::CLOCK_REALTIME
|
||||
| ClockID::CLOCK_MONOTONIC
|
||||
| ClockID::CLOCK_BOOTTIME
|
||||
| ClockID::CLOCK_PROCESS_CPUTIME_ID => {}
|
||||
ClockID::CLOCK_THREAD_CPUTIME_ID => {
|
||||
ClockId::CLOCK_REALTIME
|
||||
| ClockId::CLOCK_MONOTONIC
|
||||
| ClockId::CLOCK_BOOTTIME
|
||||
| ClockId::CLOCK_PROCESS_CPUTIME_ID => {}
|
||||
ClockId::CLOCK_THREAD_CPUTIME_ID => {
|
||||
return_errno!(EINVAL, "CLOCK_THREAD_CPUTIME_ID is not a permitted value");
|
||||
}
|
||||
_ => {
|
||||
@ -269,7 +221,7 @@ pub fn do_nanosleep(req: ×pec_t, rem: Option<&mut timespec_t>) -> Result<()
|
||||
// the CLOCK_REALTIME clock. However, Linux measures the time using
|
||||
// the CLOCK_MONOTONIC clock.
|
||||
// Here we follow the POSIX.1
|
||||
let clock_id = ClockID::CLOCK_REALTIME;
|
||||
let clock_id = ClockId::CLOCK_REALTIME;
|
||||
return do_clock_nanosleep(clock_id, 0, req, rem);
|
||||
}
|
||||
|
||||
|
@ -1,11 +1,11 @@
|
||||
use super::{do_clock_gettime, ClockID};
|
||||
use super::{do_clock_gettime, ClockId};
|
||||
use std::time::Duration;
|
||||
|
||||
lazy_static! {
|
||||
static ref BOOT_TIME_STAMP: Duration = do_clock_gettime(ClockID::CLOCK_MONOTONIC_RAW)
|
||||
static ref BOOT_TIME_STAMP: Duration = do_clock_gettime(ClockId::CLOCK_MONOTONIC_RAW)
|
||||
.unwrap()
|
||||
.as_duration();
|
||||
static ref BOOT_TIME_STAMP_SINCE_EPOCH: Duration = do_clock_gettime(ClockID::CLOCK_REALTIME)
|
||||
static ref BOOT_TIME_STAMP_SINCE_EPOCH: Duration = do_clock_gettime(ClockId::CLOCK_REALTIME)
|
||||
.unwrap()
|
||||
.as_duration();
|
||||
}
|
||||
@ -20,7 +20,7 @@ pub fn boot_time_since_epoch() -> Duration {
|
||||
}
|
||||
|
||||
pub fn get() -> Option<Duration> {
|
||||
do_clock_gettime(ClockID::CLOCK_MONOTONIC_RAW)
|
||||
do_clock_gettime(ClockId::CLOCK_MONOTONIC_RAW)
|
||||
.unwrap()
|
||||
.as_duration()
|
||||
.checked_sub(*BOOT_TIME_STAMP)
|
||||
|
@ -21,6 +21,8 @@ C_SRCS := $(sort $(wildcard src/*.c src/*/*.c))
|
||||
CXX_SRCS := $(sort $(wildcard src/*.cpp src/*/*.cpp))
|
||||
C_OBJS := $(addprefix $(OBJ_DIR)/pal/,$(C_SRCS:.c=.o))
|
||||
CXX_OBJS := $(addprefix $(OBJ_DIR)/pal/,$(CXX_SRCS:.cpp=.o))
|
||||
VDSO_SRCS := $(CRATES_DIR)/vdso-time/ocalls/vdso-time-ocalls.c
|
||||
VDSO_OBJS := $(addprefix $(OBJ_DIR)/pal/external_ocalls,$(VDSO_SRCS:.c=.o))
|
||||
|
||||
# Object files for simulation mode are stored in pal/src_sim
|
||||
ifeq ($(SGX_MODE), SIM)
|
||||
@ -52,7 +54,7 @@ LINK_FLAGS += -lsgx_quote_ex_sim
|
||||
endif
|
||||
endif
|
||||
|
||||
ALL_BUILD_SUBDIRS := $(sort $(patsubst %/,%,$(dir $(LIBOCCLUM_PAL_SO_REAL) $(EDL_C_OBJS) $(C_OBJS) $(CXX_OBJS))))
|
||||
ALL_BUILD_SUBDIRS := $(sort $(patsubst %/,%,$(dir $(LIBOCCLUM_PAL_SO_REAL) $(EDL_C_OBJS) $(C_OBJS) $(CXX_OBJS) $(VDSO_OBJS))))
|
||||
|
||||
.PHONY: all format format-check clean
|
||||
|
||||
@ -61,7 +63,7 @@ all: $(ALL_BUILD_SUBDIRS) $(LIBOCCLUM_PAL_SO_REAL)
|
||||
$(ALL_BUILD_SUBDIRS):
|
||||
@mkdir -p $@
|
||||
|
||||
$(LIBOCCLUM_PAL_SO_REAL): $(LIBSGX_USTDC_A) $(EDL_C_OBJS) $(C_OBJS) $(CXX_OBJS)
|
||||
$(LIBOCCLUM_PAL_SO_REAL): $(LIBSGX_USTDC_A) $(EDL_C_OBJS) $(C_OBJS) $(CXX_OBJS) $(VDSO_OBJS)
|
||||
@$(CXX) $^ -o $@ $(LINK_FLAGS) -Wl,-soname=$(LIBOCCLUM_PAL_SONAME)
|
||||
@# Create symbolic files because occlum run and exec will need it when linking.
|
||||
@cd $(BUILD_DIR)/lib && ln -sf $(notdir $(LIBOCCLUM_PAL_SO_REAL)) $(notdir $(LIBOCCLUM_PAL_SONAME)) && \
|
||||
@ -76,7 +78,8 @@ $(OBJ_DIR)/pal/$(SRC_OBJ)/Enclave_u.c: $(SGX_EDGER8R) ../Enclave.edl
|
||||
@cd $(OBJ_DIR)/pal/$(SRC_OBJ) && \
|
||||
$(SGX_EDGER8R) $(SGX_EDGER8R_MODE) --untrusted $(CUR_DIR)/../Enclave.edl \
|
||||
--search-path $(SGX_SDK)/include \
|
||||
--search-path $(RUST_SGX_SDK_DIR)/edl/
|
||||
--search-path $(RUST_SGX_SDK_DIR)/edl/ \
|
||||
--search-path $(CRATES_DIR)/vdso-time/ocalls
|
||||
@echo "GEN <= $@"
|
||||
|
||||
$(OBJ_DIR)/pal/$(SRC_OBJ)/%.o: src/%.c
|
||||
@ -87,6 +90,10 @@ $(OBJ_DIR)/pal/$(SRC_OBJ)/%.o: src/%.cpp
|
||||
@$(CXX) $(CXX_FLAGS) -c $< -o $@
|
||||
@echo "CXX <= $@"
|
||||
|
||||
$(VDSO_OBJS): $(VDSO_SRCS)
|
||||
@$(CC) $(C_FLAGS) -c $< -o $@
|
||||
@echo "CC <= $@"
|
||||
|
||||
$(LIBSGX_USTDC_A):
|
||||
@$(MAKE) --no-print-directory -C $(RUST_SGX_SDK_DIR)/sgx_ustdc/ > /dev/null
|
||||
@cp $(RUST_SGX_SDK_DIR)/sgx_ustdc/libsgx_ustdc.a $(LIBSGX_USTDC_A)
|
||||
|
@ -4,18 +4,6 @@
|
||||
#include <sys/prctl.h>
|
||||
#include "ocalls.h"
|
||||
|
||||
void occlum_ocall_gettimeofday(struct timeval *tv) {
|
||||
gettimeofday(tv, NULL);
|
||||
}
|
||||
|
||||
void occlum_ocall_clock_gettime(int clockid, struct timespec *tp) {
|
||||
clock_gettime(clockid, tp);
|
||||
}
|
||||
|
||||
void occlum_ocall_clock_getres(int clockid, struct timespec *res) {
|
||||
clock_getres(clockid, res);
|
||||
}
|
||||
|
||||
int occlum_ocall_clock_nanosleep(clockid_t clockid, int flags, const struct timespec *req,
|
||||
struct timespec *rem) {
|
||||
return clock_nanosleep(clockid, flags, req, rem);
|
||||
|
@ -2,6 +2,7 @@ MAIN_MAKEFILE := $(firstword $(MAKEFILE_LIST))
|
||||
INCLUDE_MAKEFILE := $(lastword $(MAKEFILE_LIST))
|
||||
CUR_DIR := $(shell dirname $(realpath $(MAIN_MAKEFILE)))
|
||||
PROJECT_DIR := $(realpath $(CUR_DIR)/../../)
|
||||
CRATES_DIR := $(realpath $(CUR_DIR)/../libos/crates)
|
||||
|
||||
SHELL := /bin/bash
|
||||
|
||||
|
Loading…
Reference in New Issue
Block a user