[crates] Implement vdso for time precision
This commit is contained in:
		
							parent
							
								
									5b704984e3
								
							
						
					
					
						commit
						501abda5ca
					
				| @ -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