Compare commits
10 Commits
ded96d761d
...
ffe6a750b0
Author | SHA1 | Date | |
---|---|---|---|
|
ffe6a750b0 | ||
|
f8e8d400d3 | ||
|
060d2ec1b3 | ||
|
3b90df67dc | ||
|
d3e84d2269 | ||
|
501abda5ca | ||
|
5b704984e3 | ||
|
4027258ec5 | ||
|
0c1c0621e6 | ||
|
f58652da96 |
@ -12,12 +12,6 @@ on:
|
|||||||
description: 'Whether it is a release image or test image (must choose from <Y/N/T>)'
|
description: 'Whether it is a release image or test image (must choose from <Y/N/T>)'
|
||||||
required: true
|
required: true
|
||||||
default: 'N'
|
default: 'N'
|
||||||
# If rc image works well, directly tag with the release version
|
|
||||||
# source image: "reuse_image" specified here
|
|
||||||
# target iamge: Get from the current source code
|
|
||||||
reuse_image:
|
|
||||||
description: 'Set reuse image name, e.g.: 0.30.0-rc (When release is set to <Y>, admin can choose to reuse an old rc image as the new release image)'
|
|
||||||
required: false
|
|
||||||
|
|
||||||
jobs:
|
jobs:
|
||||||
generate-anolis-image:
|
generate-anolis-image:
|
||||||
@ -44,6 +38,16 @@ jobs:
|
|||||||
# ${GITHUB_REF##*/} == branch-name
|
# ${GITHUB_REF##*/} == branch-name
|
||||||
run: echo "OCCLUM_BRANCH=$(echo ${GITHUB_REF##*/})" >> $GITHUB_ENV;
|
run: echo "OCCLUM_BRANCH=$(echo ${GITHUB_REF##*/})" >> $GITHUB_ENV;
|
||||||
|
|
||||||
|
- name: Get image tag name for release image
|
||||||
|
if: github.event.inputs.release == 'Y'
|
||||||
|
run: echo "IMAGE_TAG=${{ env.RELEASE_VERSION }}" >> $GITHUB_ENV
|
||||||
|
- name: Get image tage name for dev image
|
||||||
|
if: github.event.inputs.release == 'N'
|
||||||
|
run: echo "IMAGE_TAG=latest-dev-${GITHUB_SHA:0:7}" >> $GITHUB_ENV
|
||||||
|
- name: Get image tage name for test image
|
||||||
|
if: github.event.inputs.release == 'T'
|
||||||
|
run: echo "IMAGE_TAG=${{ env.RELEASE_VERSION }}-test" >> $GITHUB_ENV
|
||||||
|
|
||||||
- name: Set up QEMU
|
- name: Set up QEMU
|
||||||
uses: docker/setup-qemu-action@v1
|
uses: docker/setup-qemu-action@v1
|
||||||
|
|
||||||
@ -58,19 +62,7 @@ jobs:
|
|||||||
username: ${{ secrets.DOCKER_USERNAME }}
|
username: ${{ secrets.DOCKER_USERNAME }}
|
||||||
password: ${{ secrets.DOCKER_PASSWORD }}
|
password: ${{ secrets.DOCKER_PASSWORD }}
|
||||||
|
|
||||||
- name: Get image tag name for release image
|
|
||||||
if: github.event.inputs.release == 'Y'
|
|
||||||
run: echo "IMAGE_TAG=${{ env.RELEASE_VERSION }}" >> $GITHUB_ENV
|
|
||||||
- name: Get image tage name for dev image
|
|
||||||
if: github.event.inputs.release == 'N'
|
|
||||||
run: echo "IMAGE_TAG=latest-dev-${GITHUB_SHA:0:7}" >> $GITHUB_ENV
|
|
||||||
- name: Get image tage name for test image
|
|
||||||
if: github.event.inputs.release == 'T'
|
|
||||||
run: echo "IMAGE_TAG=${{ env.RELEASE_VERSION }}-test" >> $GITHUB_ENV
|
|
||||||
|
|
||||||
# Rebuild new image
|
|
||||||
- name: Build and push
|
- name: Build and push
|
||||||
if: "${{ github.event.inputs.reuse_image == '' }}"
|
|
||||||
uses: docker/build-push-action@v2
|
uses: docker/build-push-action@v2
|
||||||
with:
|
with:
|
||||||
context: .
|
context: .
|
||||||
@ -80,15 +72,6 @@ jobs:
|
|||||||
push: true
|
push: true
|
||||||
tags: occlum/occlum:${{ env.IMAGE_TAG }}-anolis8.8
|
tags: occlum/occlum:${{ env.IMAGE_TAG }}-anolis8.8
|
||||||
|
|
||||||
# Reuse old image
|
|
||||||
- name: Reuse old image
|
|
||||||
if: "${{ github.event.inputs.reuse_image != '' }}"
|
|
||||||
run: |
|
|
||||||
echo "REUSE_VERSION=${{ github.event.inputs.reuse_image }}" >> $GITHUB_ENV;
|
|
||||||
docker pull occlum/occlum:${{ env.REUSE_VERSION }}-anolis8.8
|
|
||||||
docker tag occlum/occlum:${{ env.REUSE_VERSION }}-anolis8.8 occlum/occlum:${{ env.IMAGE_TAG }}-anolis8.8
|
|
||||||
docker push occlum/occlum:${{ env.IMAGE_TAG }}-anolis8.8
|
|
||||||
|
|
||||||
|
|
||||||
generate-ubuntu20-image:
|
generate-ubuntu20-image:
|
||||||
runs-on: ubuntu-20.04
|
runs-on: ubuntu-20.04
|
||||||
@ -113,6 +96,16 @@ jobs:
|
|||||||
# ${GITHUB_REF##*/} == branch-name
|
# ${GITHUB_REF##*/} == branch-name
|
||||||
run: echo "OCCLUM_BRANCH=$(echo ${GITHUB_REF##*/})" >> $GITHUB_ENV;
|
run: echo "OCCLUM_BRANCH=$(echo ${GITHUB_REF##*/})" >> $GITHUB_ENV;
|
||||||
|
|
||||||
|
- name: Get image tag name for release image
|
||||||
|
if: github.event.inputs.release == 'Y'
|
||||||
|
run: echo "IMAGE_TAG=${{ env.RELEASE_VERSION }}" >> $GITHUB_ENV
|
||||||
|
- name: Get image tage name for dev image
|
||||||
|
if: github.event.inputs.release == 'N'
|
||||||
|
run: echo "IMAGE_TAG=latest-dev-${GITHUB_SHA:0:7}" >> $GITHUB_ENV
|
||||||
|
- name: Get image tage name for test image
|
||||||
|
if: github.event.inputs.release == 'T'
|
||||||
|
run: echo "IMAGE_TAG=${{ env.RELEASE_VERSION }}-test" >> $GITHUB_ENV
|
||||||
|
|
||||||
- name: Set up QEMU
|
- name: Set up QEMU
|
||||||
uses: docker/setup-qemu-action@v1
|
uses: docker/setup-qemu-action@v1
|
||||||
|
|
||||||
@ -127,19 +120,7 @@ jobs:
|
|||||||
username: ${{ secrets.DOCKER_USERNAME }}
|
username: ${{ secrets.DOCKER_USERNAME }}
|
||||||
password: ${{ secrets.DOCKER_PASSWORD }}
|
password: ${{ secrets.DOCKER_PASSWORD }}
|
||||||
|
|
||||||
- name: Get image tag name for release image
|
|
||||||
if: github.event.inputs.release == 'Y'
|
|
||||||
run: echo "IMAGE_TAG=${{ env.RELEASE_VERSION }}" >> $GITHUB_ENV
|
|
||||||
- name: Get image tage name for dev image
|
|
||||||
if: github.event.inputs.release == 'N'
|
|
||||||
run: echo "IMAGE_TAG=latest-dev-${GITHUB_SHA:0:7}" >> $GITHUB_ENV
|
|
||||||
- name: Get image tage name for test image
|
|
||||||
if: github.event.inputs.release == 'T'
|
|
||||||
run: echo "IMAGE_TAG=${{ env.RELEASE_VERSION }}-test" >> $GITHUB_ENV
|
|
||||||
|
|
||||||
# Rebuild new image
|
|
||||||
- name: Build and push
|
- name: Build and push
|
||||||
if: "${{ github.event.inputs.reuse_image == '' }}"
|
|
||||||
uses: docker/build-push-action@v2
|
uses: docker/build-push-action@v2
|
||||||
with:
|
with:
|
||||||
context: .
|
context: .
|
||||||
@ -148,12 +129,3 @@ jobs:
|
|||||||
build-args: OCCLUM_BRANCH=${{ env.OCCLUM_BRANCH }}
|
build-args: OCCLUM_BRANCH=${{ env.OCCLUM_BRANCH }}
|
||||||
push: true
|
push: true
|
||||||
tags: occlum/occlum:${{ env.IMAGE_TAG }}-ubuntu20.04
|
tags: occlum/occlum:${{ env.IMAGE_TAG }}-ubuntu20.04
|
||||||
|
|
||||||
# Reuse old image
|
|
||||||
- name: Reuse old image
|
|
||||||
if: "${{ github.event.inputs.reuse_image != '' }}"
|
|
||||||
run: |
|
|
||||||
echo "REUSE_VERSION=${{ github.event.inputs.reuse_image }}" >> $GITHUB_ENV;
|
|
||||||
docker pull occlum/occlum:${{ env.REUSE_VERSION }}-ubuntu20.04
|
|
||||||
docker tag occlum/occlum:${{ env.REUSE_VERSION }}-ubuntu20.04 occlum/occlum:${{ env.IMAGE_TAG }}-ubuntu20.04
|
|
||||||
docker push occlum/occlum:${{ env.IMAGE_TAG }}-ubuntu20.04
|
|
||||||
|
9
.github/workflows/hw_mode_test.yml
vendored
9
.github/workflows/hw_mode_test.yml
vendored
@ -54,6 +54,15 @@ jobs:
|
|||||||
container-name: ${{ github.job }}
|
container-name: ${{ github.job }}
|
||||||
build-envs: 'OCCLUM_RELEASE_BUILD=1'
|
build-envs: 'OCCLUM_RELEASE_BUILD=1'
|
||||||
|
|
||||||
|
# Udpate the test json file
|
||||||
|
# When there comes new features, the configuration should be enabled accordingly
|
||||||
|
- name: Configure Occlum features
|
||||||
|
run: |
|
||||||
|
if [[ "${{ matrix.self_runner[2] }}" == "EDMM" ]]; then
|
||||||
|
docker exec ${{ env.CONTAINER_NAME }} bash -c "jq '.feature.enable_posix_shm = true | .feature.enable_edmm = true' /root/occlum/test/Occlum.json > /tmp.json && mv /tmp.json /root/occlum/test/Occlum.json"
|
||||||
|
fi;
|
||||||
|
shell: bash
|
||||||
|
|
||||||
- name: Integration test
|
- name: Integration test
|
||||||
run: docker exec ${{ env.CONTAINER_NAME }} bash -c "cd /root/occlum; OCCLUM_LOG_LEVEL=trace make test"
|
run: docker exec ${{ env.CONTAINER_NAME }} bash -c "cd /root/occlum; OCCLUM_LOG_LEVEL=trace make test"
|
||||||
|
|
||||||
|
6
.github/workflows/main.yml
vendored
6
.github/workflows/main.yml
vendored
@ -68,6 +68,12 @@ jobs:
|
|||||||
if: ${{ failure() }}
|
if: ${{ failure() }}
|
||||||
run: docker exec ${{ github.job }} bash -c "cat /root/occlum/build/test/.fail"
|
run: docker exec ${{ github.job }} bash -c "cat /root/occlum/build/test/.fail"
|
||||||
|
|
||||||
|
- name: Integration test with optional Occlum features
|
||||||
|
run: |
|
||||||
|
docker exec ${{ github.job }} bash -c 'source /opt/intel/sgxsdk/environment; cd /root/occlum; make clean && LIBOS_FEATURES="kernel_heap_monitor" make install'
|
||||||
|
docker exec ${{ github.job }} bash -c "cd /root/occlum; SGX_MODE=SIM make test-glibc"
|
||||||
|
shell: bash
|
||||||
|
|
||||||
# Make_test_on_centos:
|
# Make_test_on_centos:
|
||||||
# runs-on: ubuntu-18.04
|
# runs-on: ubuntu-18.04
|
||||||
|
|
||||||
|
2
deps/rust-sgx-sdk
vendored
2
deps/rust-sgx-sdk
vendored
@ -1 +1 @@
|
|||||||
Subproject commit e28e25ce718cc21b232a1bf37bb6446535d7ea00
|
Subproject commit 81384ce4d10c67eea5e1ba4ea332087940c1836b
|
@ -6,6 +6,7 @@ enclave {
|
|||||||
from "sgx_tprotected_fs.edl" import *;
|
from "sgx_tprotected_fs.edl" import *;
|
||||||
from "sgx_net.edl" import *;
|
from "sgx_net.edl" import *;
|
||||||
from "sgx_occlum_utils.edl" import *;
|
from "sgx_occlum_utils.edl" import *;
|
||||||
|
from "sgx_vdso_time_ocalls.edl" import *;
|
||||||
|
|
||||||
include "sgx_quote.h"
|
include "sgx_quote.h"
|
||||||
include "occlum_edl_types.h"
|
include "occlum_edl_types.h"
|
||||||
@ -148,9 +149,6 @@ enclave {
|
|||||||
|
|
||||||
int occlum_ocall_thread_getcpuclock([out] struct timespec* ts) propagate_errno;
|
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_rdtsc([out] uint32_t* low, [out] uint32_t* high);
|
||||||
void occlum_ocall_get_timerslack([out] int *timer_slack);
|
void occlum_ocall_get_timerslack([out] int *timer_slack);
|
||||||
|
|
||||||
|
2
src/exec/Cargo.lock
generated
2
src/exec/Cargo.lock
generated
@ -542,7 +542,7 @@ dependencies = [
|
|||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "occlum_exec"
|
name = "occlum_exec"
|
||||||
version = "0.30.0"
|
version = "0.30.1"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"chrono",
|
"chrono",
|
||||||
"clap",
|
"clap",
|
||||||
|
@ -1,6 +1,6 @@
|
|||||||
[package]
|
[package]
|
||||||
name = "occlum_exec"
|
name = "occlum_exec"
|
||||||
version = "0.30.0"
|
version = "0.30.1"
|
||||||
edition = "2021"
|
edition = "2021"
|
||||||
|
|
||||||
[lib]
|
[lib]
|
||||||
|
2
src/libos/Cargo.lock
generated
2
src/libos/Cargo.lock
generated
@ -4,7 +4,7 @@ version = 3
|
|||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "Occlum"
|
name = "Occlum"
|
||||||
version = "0.30.0"
|
version = "0.30.1"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"aligned",
|
"aligned",
|
||||||
"atomic",
|
"atomic",
|
||||||
|
@ -1,6 +1,6 @@
|
|||||||
[package]
|
[package]
|
||||||
name = "Occlum"
|
name = "Occlum"
|
||||||
version = "0.30.0"
|
version = "0.30.1"
|
||||||
edition = "2021"
|
edition = "2021"
|
||||||
|
|
||||||
[lib]
|
[lib]
|
||||||
@ -25,6 +25,8 @@ rcore-fs-devfs = { path = "../../deps/sefs/rcore-fs-devfs" }
|
|||||||
resolv-conf = { path = "../../deps/resolv-conf" }
|
resolv-conf = { path = "../../deps/resolv-conf" }
|
||||||
serde = { path = "../../deps/serde-sgx/serde", features = ["derive"] }
|
serde = { path = "../../deps/serde-sgx/serde", features = ["derive"] }
|
||||||
serde_json = { path = "../../deps/serde-json-sgx" }
|
serde_json = { path = "../../deps/serde-json-sgx" }
|
||||||
|
errno = { path = "crates/errno", features = ["occlum"] }
|
||||||
|
vdso-time = { path = "crates/vdso-time", default-features = false, features = ["sgx"] }
|
||||||
memoffset = "0.6.1"
|
memoffset = "0.6.1"
|
||||||
scroll = { version = "0.11.0", default-features = false }
|
scroll = { version = "0.11.0", default-features = false }
|
||||||
itertools = { version = "0.10.0", default-features = false, features = ["use_alloc"] }
|
itertools = { version = "0.10.0", default-features = false, features = ["use_alloc"] }
|
||||||
@ -48,6 +50,7 @@ dcap = [] # DCAP support. The compilation relies on DCAP package.
|
|||||||
cov = ["sgx_cov"] # Enable coverage colletcion.
|
cov = ["sgx_cov"] # Enable coverage colletcion.
|
||||||
hyper_mode = [] # For running in hyper mode.
|
hyper_mode = [] # For running in hyper mode.
|
||||||
pku = [] # PKU Support
|
pku = [] # PKU Support
|
||||||
|
kernel_heap_monitor = []# Kernel heap usage tracking. With overhead.
|
||||||
|
|
||||||
[target.'cfg(not(target_env = "sgx"))'.dependencies]
|
[target.'cfg(not(target_env = "sgx"))'.dependencies]
|
||||||
sgx_types = { path = "../../deps/rust-sgx-sdk/sgx_types" }
|
sgx_types = { path = "../../deps/rust-sgx-sdk/sgx_types" }
|
||||||
|
@ -45,7 +45,7 @@ LIBOS_LOG ?= error
|
|||||||
|
|
||||||
LIBOS_SONAME := libocclum-libos.so.$(MAJOR_VER_NUM)
|
LIBOS_SONAME := libocclum-libos.so.$(MAJOR_VER_NUM)
|
||||||
|
|
||||||
LIBOS_FEATURES :=
|
LIBOS_FEATURES := $(LIBOS_FEATURES)
|
||||||
|
|
||||||
ifeq ($(SGX_MODE), HW)
|
ifeq ($(SGX_MODE), HW)
|
||||||
LIBOS_CORE_LIB_NAME := occlum-libos-core
|
LIBOS_CORE_LIB_NAME := occlum-libos-core
|
||||||
@ -162,7 +162,11 @@ $(OBJ_DIR)/libos/$(SRC_OBJ)/Enclave_t.o: $(OBJ_DIR)/libos/$(SRC_OBJ)/Enclave_t.c
|
|||||||
@echo "CC <= $@"
|
@echo "CC <= $@"
|
||||||
|
|
||||||
$(OBJ_DIR)/libos/$(SRC_OBJ)/Enclave_t.c: $(SGX_EDGER8R) ../Enclave.edl
|
$(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 <= $@"
|
@echo "GEN <= $@"
|
||||||
|
|
||||||
$(C_OBJS):$(OBJ_DIR)/libos/$(SRC_OBJ)/%.o: src/%.c
|
$(C_OBJS):$(OBJ_DIR)/libos/$(SRC_OBJ)/%.o: src/%.c
|
||||||
|
265
src/libos/crates/errno/Cargo.lock
generated
Normal file
265
src/libos/crates/errno/Cargo.lock
generated
Normal file
@ -0,0 +1,265 @@
|
|||||||
|
# This file is automatically @generated by Cargo.
|
||||||
|
# It is not intended for manual editing.
|
||||||
|
version = 3
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "bitflags"
|
||||||
|
version = "1.3.2"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "bef38d45163c2f1dde094a7dfd33ccf595c92905c8f8f4fdc18d06fb1037718a"
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "cc"
|
||||||
|
version = "1.0.83"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "f1174fb0b6ec23863f8b971027804a42614e347eafb0a95bf0b12cdae21fc4d0"
|
||||||
|
dependencies = [
|
||||||
|
"libc",
|
||||||
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "errno"
|
||||||
|
version = "0.1.0"
|
||||||
|
dependencies = [
|
||||||
|
"log",
|
||||||
|
"rcore-fs",
|
||||||
|
"serde_json",
|
||||||
|
"sgx_tstd 1.1.6",
|
||||||
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "hashbrown_tstd"
|
||||||
|
version = "0.12.0"
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "itoa"
|
||||||
|
version = "0.4.5"
|
||||||
|
dependencies = [
|
||||||
|
"sgx_tstd 1.1.0",
|
||||||
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "libc"
|
||||||
|
version = "0.2.149"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "a08173bc88b7955d1b3145aa561539096c421ac8debde8cbc3612ec635fee29b"
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "log"
|
||||||
|
version = "0.4.20"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "b5e6163cb8c49088c2c36f57875e58ccd8c87c7427f7fbd50ea6710b2f3f2e8f"
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "rcore-fs"
|
||||||
|
version = "0.1.0"
|
||||||
|
dependencies = [
|
||||||
|
"bitflags",
|
||||||
|
"spin",
|
||||||
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "ryu"
|
||||||
|
version = "1.0.15"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "1ad4cc8da4ef723ed60bced201181d83791ad433213d8c24efffda1eec85d741"
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "serde"
|
||||||
|
version = "1.0.104"
|
||||||
|
dependencies = [
|
||||||
|
"sgx_tstd 1.1.0",
|
||||||
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "serde_json"
|
||||||
|
version = "1.0.40"
|
||||||
|
dependencies = [
|
||||||
|
"itoa",
|
||||||
|
"ryu",
|
||||||
|
"serde",
|
||||||
|
"sgx_tstd 1.1.0",
|
||||||
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "sgx_alloc"
|
||||||
|
version = "1.1.0"
|
||||||
|
source = "git+https://github.com/apache/teaclave-sgx-sdk.git?rev=v1.1.0#71a88b647bb76a16cbc5c3e29403e2afb67f82fd"
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "sgx_alloc"
|
||||||
|
version = "1.1.6"
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "sgx_backtrace_sys"
|
||||||
|
version = "1.1.0"
|
||||||
|
source = "git+https://github.com/apache/teaclave-sgx-sdk.git?rev=v1.1.0#71a88b647bb76a16cbc5c3e29403e2afb67f82fd"
|
||||||
|
dependencies = [
|
||||||
|
"cc",
|
||||||
|
"sgx_build_helper 0.1.0",
|
||||||
|
"sgx_libc 1.1.0",
|
||||||
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "sgx_backtrace_sys"
|
||||||
|
version = "1.1.6"
|
||||||
|
dependencies = [
|
||||||
|
"cc",
|
||||||
|
"sgx_build_helper 1.1.6",
|
||||||
|
"sgx_libc 1.1.6",
|
||||||
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "sgx_build_helper"
|
||||||
|
version = "0.1.0"
|
||||||
|
source = "git+https://github.com/apache/teaclave-sgx-sdk.git?rev=v1.1.0#71a88b647bb76a16cbc5c3e29403e2afb67f82fd"
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "sgx_build_helper"
|
||||||
|
version = "1.1.6"
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "sgx_demangle"
|
||||||
|
version = "1.1.0"
|
||||||
|
source = "git+https://github.com/apache/teaclave-sgx-sdk.git?rev=v1.1.0#71a88b647bb76a16cbc5c3e29403e2afb67f82fd"
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "sgx_demangle"
|
||||||
|
version = "1.1.6"
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "sgx_libc"
|
||||||
|
version = "1.1.0"
|
||||||
|
source = "git+https://github.com/apache/teaclave-sgx-sdk.git?rev=v1.1.0#71a88b647bb76a16cbc5c3e29403e2afb67f82fd"
|
||||||
|
dependencies = [
|
||||||
|
"sgx_types 1.1.0",
|
||||||
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "sgx_libc"
|
||||||
|
version = "1.1.6"
|
||||||
|
dependencies = [
|
||||||
|
"sgx_types 1.1.6",
|
||||||
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "sgx_tcrypto"
|
||||||
|
version = "1.1.0"
|
||||||
|
source = "git+https://github.com/apache/teaclave-sgx-sdk.git?rev=v1.1.0#71a88b647bb76a16cbc5c3e29403e2afb67f82fd"
|
||||||
|
dependencies = [
|
||||||
|
"sgx_types 1.1.0",
|
||||||
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "sgx_tprotected_fs"
|
||||||
|
version = "1.1.0"
|
||||||
|
source = "git+https://github.com/apache/teaclave-sgx-sdk.git?rev=v1.1.0#71a88b647bb76a16cbc5c3e29403e2afb67f82fd"
|
||||||
|
dependencies = [
|
||||||
|
"sgx_trts 1.1.0",
|
||||||
|
"sgx_types 1.1.0",
|
||||||
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "sgx_tprotected_fs"
|
||||||
|
version = "1.1.6"
|
||||||
|
dependencies = [
|
||||||
|
"sgx_trts 1.1.6",
|
||||||
|
"sgx_types 1.1.6",
|
||||||
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "sgx_trts"
|
||||||
|
version = "1.1.0"
|
||||||
|
source = "git+https://github.com/apache/teaclave-sgx-sdk.git?rev=v1.1.0#71a88b647bb76a16cbc5c3e29403e2afb67f82fd"
|
||||||
|
dependencies = [
|
||||||
|
"sgx_libc 1.1.0",
|
||||||
|
"sgx_types 1.1.0",
|
||||||
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "sgx_trts"
|
||||||
|
version = "1.1.6"
|
||||||
|
dependencies = [
|
||||||
|
"sgx_libc 1.1.6",
|
||||||
|
"sgx_types 1.1.6",
|
||||||
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "sgx_tse"
|
||||||
|
version = "1.1.0"
|
||||||
|
source = "git+https://github.com/apache/teaclave-sgx-sdk.git?rev=v1.1.0#71a88b647bb76a16cbc5c3e29403e2afb67f82fd"
|
||||||
|
dependencies = [
|
||||||
|
"sgx_types 1.1.0",
|
||||||
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "sgx_tseal"
|
||||||
|
version = "1.1.0"
|
||||||
|
source = "git+https://github.com/apache/teaclave-sgx-sdk.git?rev=v1.1.0#71a88b647bb76a16cbc5c3e29403e2afb67f82fd"
|
||||||
|
dependencies = [
|
||||||
|
"sgx_tcrypto",
|
||||||
|
"sgx_trts 1.1.0",
|
||||||
|
"sgx_tse",
|
||||||
|
"sgx_types 1.1.0",
|
||||||
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "sgx_tstd"
|
||||||
|
version = "1.1.0"
|
||||||
|
source = "git+https://github.com/apache/teaclave-sgx-sdk.git?rev=v1.1.0#71a88b647bb76a16cbc5c3e29403e2afb67f82fd"
|
||||||
|
dependencies = [
|
||||||
|
"sgx_alloc 1.1.0",
|
||||||
|
"sgx_backtrace_sys 1.1.0",
|
||||||
|
"sgx_demangle 1.1.0",
|
||||||
|
"sgx_libc 1.1.0",
|
||||||
|
"sgx_tprotected_fs 1.1.0",
|
||||||
|
"sgx_trts 1.1.0",
|
||||||
|
"sgx_tseal",
|
||||||
|
"sgx_types 1.1.0",
|
||||||
|
"sgx_unwind 0.1.0",
|
||||||
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "sgx_tstd"
|
||||||
|
version = "1.1.6"
|
||||||
|
dependencies = [
|
||||||
|
"hashbrown_tstd",
|
||||||
|
"sgx_alloc 1.1.6",
|
||||||
|
"sgx_backtrace_sys 1.1.6",
|
||||||
|
"sgx_demangle 1.1.6",
|
||||||
|
"sgx_libc 1.1.6",
|
||||||
|
"sgx_tprotected_fs 1.1.6",
|
||||||
|
"sgx_trts 1.1.6",
|
||||||
|
"sgx_types 1.1.6",
|
||||||
|
"sgx_unwind 1.1.6",
|
||||||
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "sgx_types"
|
||||||
|
version = "1.1.0"
|
||||||
|
source = "git+https://github.com/apache/teaclave-sgx-sdk.git?rev=v1.1.0#71a88b647bb76a16cbc5c3e29403e2afb67f82fd"
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "sgx_types"
|
||||||
|
version = "1.1.6"
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "sgx_unwind"
|
||||||
|
version = "0.1.0"
|
||||||
|
source = "git+https://github.com/apache/teaclave-sgx-sdk.git?rev=v1.1.0#71a88b647bb76a16cbc5c3e29403e2afb67f82fd"
|
||||||
|
dependencies = [
|
||||||
|
"sgx_build_helper 0.1.0",
|
||||||
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "sgx_unwind"
|
||||||
|
version = "1.1.6"
|
||||||
|
dependencies = [
|
||||||
|
"sgx_build_helper 1.1.6",
|
||||||
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "spin"
|
||||||
|
version = "0.5.2"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "6e63cff320ae2c57904679ba7cb63280a3dc4613885beafb148ee7bf9aa9042d"
|
19
src/libos/crates/errno/Cargo.toml
Normal file
19
src/libos/crates/errno/Cargo.toml
Normal file
@ -0,0 +1,19 @@
|
|||||||
|
[package]
|
||||||
|
name = "errno"
|
||||||
|
version = "0.1.0"
|
||||||
|
authors = ["Tate, Hongliang Tian <tate.thl@antgroup.com>"]
|
||||||
|
edition = "2021"
|
||||||
|
|
||||||
|
# See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html
|
||||||
|
|
||||||
|
[features]
|
||||||
|
default = []
|
||||||
|
std = []
|
||||||
|
occlum = ["sgx", "serde_json", "rcore-fs"]
|
||||||
|
sgx = ["sgx_tstd"]
|
||||||
|
|
||||||
|
[dependencies]
|
||||||
|
log = "0.4"
|
||||||
|
serde_json = { path = "../../../../deps/serde-json-sgx", optional = true }
|
||||||
|
sgx_tstd = { path = "../../../../deps/rust-sgx-sdk/sgx_tstd", optional = true }
|
||||||
|
rcore-fs = { path = "../../../../deps/sefs/rcore-fs", optional = true }
|
@ -1,4 +1,9 @@
|
|||||||
use super::*;
|
use alloc::boxed::Box;
|
||||||
|
use alloc::string::String;
|
||||||
|
use alloc::vec::Vec;
|
||||||
|
use core::fmt;
|
||||||
|
|
||||||
|
use super::Error;
|
||||||
|
|
||||||
#[derive(Debug, Clone)]
|
#[derive(Debug, Clone)]
|
||||||
pub struct ErrorBacktrace<'a> {
|
pub struct ErrorBacktrace<'a> {
|
||||||
@ -15,7 +20,7 @@ impl<'a> ErrorBacktrace<'a> {
|
|||||||
|
|
||||||
impl<'a> fmt::Display for ErrorBacktrace<'a> {
|
impl<'a> fmt::Display for ErrorBacktrace<'a> {
|
||||||
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
|
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
|
||||||
let error_strings: Vec<String> = self.clone().map(|e| e.to_string()).collect();
|
let error_strings: Vec<String> = self.clone().map(|e| alloc::format!("{}", e)).collect();
|
||||||
let error_backtrace = error_strings.join("\n Caused by ");
|
let error_backtrace = error_strings.join("\n Caused by ");
|
||||||
write!(f, "{}", error_backtrace)
|
write!(f, "{}", error_backtrace)
|
||||||
}
|
}
|
||||||
@ -48,18 +53,3 @@ impl Error {
|
|||||||
ErrorBacktrace::new(self)
|
ErrorBacktrace::new(self)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
pub trait ResultExt<T> {
|
|
||||||
fn cause_err<F>(self, f: F) -> Result<T>
|
|
||||||
where
|
|
||||||
F: FnOnce(&Error) -> Error;
|
|
||||||
}
|
|
||||||
|
|
||||||
impl<T> ResultExt<T> for Result<T> {
|
|
||||||
fn cause_err<F>(self, f: F) -> Result<T>
|
|
||||||
where
|
|
||||||
F: FnOnce(&Error) -> Error,
|
|
||||||
{
|
|
||||||
self.map_err(|old_e| old_e.cause_err(f))
|
|
||||||
}
|
|
||||||
}
|
|
@ -1,4 +1,4 @@
|
|||||||
use super::*;
|
use core::fmt;
|
||||||
|
|
||||||
/// POSIX errno
|
/// POSIX errno
|
||||||
#[derive(Clone, Copy, Debug, PartialEq)]
|
#[derive(Clone, Copy, Debug, PartialEq)]
|
||||||
@ -46,7 +46,6 @@ pub enum Errno {
|
|||||||
ENOSYS = 38,
|
ENOSYS = 38,
|
||||||
ENOTEMPTY = 39,
|
ENOTEMPTY = 39,
|
||||||
ELOOP = 40,
|
ELOOP = 40,
|
||||||
EWOULDBLOCK = 41,
|
|
||||||
ENOMSG = 42,
|
ENOMSG = 42,
|
||||||
EIDRM = 43,
|
EIDRM = 43,
|
||||||
ECHRNG = 44,
|
ECHRNG = 44,
|
||||||
@ -145,6 +144,9 @@ const ERRNO_MIN: u32 = Errno::EPERM as u32;
|
|||||||
const ERRNO_MAX: u32 = Errno::EHWPOISON as u32;
|
const ERRNO_MAX: u32 = Errno::EHWPOISON as u32;
|
||||||
|
|
||||||
impl Errno {
|
impl Errno {
|
||||||
|
// EWOULDBLOCK was used on BSD/Sun variants of Unix, and EAGAIN was the AT&T System V error code.
|
||||||
|
// Here we keep same with linux, define EWOULDBLOCK with EAGAIN.
|
||||||
|
pub const EWOULDBLOCK: Errno = Errno::EAGAIN;
|
||||||
pub(crate) fn as_str(&self) -> &'static str {
|
pub(crate) fn as_str(&self) -> &'static str {
|
||||||
use self::Errno::*;
|
use self::Errno::*;
|
||||||
match *self {
|
match *self {
|
@ -1,4 +1,7 @@
|
|||||||
use super::*;
|
use alloc::boxed::Box;
|
||||||
|
use core::fmt;
|
||||||
|
|
||||||
|
use super::{Errno, ToErrno};
|
||||||
|
|
||||||
#[derive(Debug)]
|
#[derive(Debug)]
|
||||||
pub struct Error {
|
pub struct Error {
|
||||||
@ -10,7 +13,7 @@ pub struct Error {
|
|||||||
#[derive(Debug)]
|
#[derive(Debug)]
|
||||||
enum Error__ {
|
enum Error__ {
|
||||||
Embedded((Errno, &'static str)),
|
Embedded((Errno, &'static str)),
|
||||||
Boxed(Box<dyn ToErrno + 'static>),
|
Boxed(Box<dyn ToErrno + Send + 'static>),
|
||||||
}
|
}
|
||||||
|
|
||||||
#[derive(Debug, Clone, Copy)]
|
#[derive(Debug, Clone, Copy)]
|
||||||
@ -30,7 +33,7 @@ impl Error {
|
|||||||
|
|
||||||
pub fn boxed<T>(inner: T, location: Option<ErrorLocation>) -> Error
|
pub fn boxed<T>(inner: T, location: Option<ErrorLocation>) -> Error
|
||||||
where
|
where
|
||||||
T: ToErrno + 'static,
|
T: ToErrno + Send + 'static,
|
||||||
{
|
{
|
||||||
Error {
|
Error {
|
||||||
inner: Error__::Boxed(Box::new(inner)),
|
inner: Error__::Boxed(Box::new(inner)),
|
||||||
@ -64,23 +67,6 @@ impl ErrorLocation {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl std::error::Error for Error {
|
|
||||||
fn description(&self) -> &str {
|
|
||||||
self.errno().as_str()
|
|
||||||
}
|
|
||||||
|
|
||||||
fn cause(&self) -> Option<&dyn std::error::Error> {
|
|
||||||
self.cause.as_ref().map(|e| e as &dyn std::error::Error)
|
|
||||||
}
|
|
||||||
/*
|
|
||||||
fn source(&self) -> Option<&(dyn std::error::Error + 'static)> {
|
|
||||||
self.cause
|
|
||||||
.as_ref()
|
|
||||||
.map(|e| e as &(dyn std::error::Error + 'static))
|
|
||||||
}
|
|
||||||
*/
|
|
||||||
}
|
|
||||||
|
|
||||||
impl fmt::Display for Error {
|
impl fmt::Display for Error {
|
||||||
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
|
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
|
||||||
write!(f, "{}", self.inner)?;
|
write!(f, "{}", self.inner)?;
|
||||||
@ -105,3 +91,25 @@ impl fmt::Display for ErrorLocation {
|
|||||||
write!(f, "[line = {}, file = {}]", self.line, self.file)
|
write!(f, "[line = {}, file = {}]", self.line, self.file)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[cfg(any(feature = "std", feature = "sgx", test, doctest))]
|
||||||
|
mod if_std {
|
||||||
|
use super::*;
|
||||||
|
|
||||||
|
impl std::error::Error for Error {
|
||||||
|
fn description(&self) -> &str {
|
||||||
|
self.errno().as_str()
|
||||||
|
}
|
||||||
|
|
||||||
|
fn cause(&self) -> Option<&dyn std::error::Error> {
|
||||||
|
self.cause.as_ref().map(|e| e as &dyn std::error::Error)
|
||||||
|
}
|
||||||
|
/*
|
||||||
|
fn source(&self) -> Option<&(dyn std::error::Error + 'static)> {
|
||||||
|
self.cause
|
||||||
|
.as_ref()
|
||||||
|
.map(|e| e as &(dyn std::error::Error + 'static))
|
||||||
|
}
|
||||||
|
*/
|
||||||
|
}
|
||||||
|
}
|
204
src/libos/crates/errno/src/lib.rs
Normal file
204
src/libos/crates/errno/src/lib.rs
Normal file
@ -0,0 +1,204 @@
|
|||||||
|
//! User-friendly error handling with build-in support for POSIX errno.
|
||||||
|
//!
|
||||||
|
//! This crate extends Rust's standard error handling with the abilities of
|
||||||
|
//! reporting error locations, providing backtrace information, and unifying
|
||||||
|
//! all types of errors with POSIX errno.
|
||||||
|
//!
|
||||||
|
//! # Motivation
|
||||||
|
//!
|
||||||
|
//! While the built-in error handling mechanism of Rust is undoubtedly superior
|
||||||
|
//! than that of a traditional system programming language (e.g., C/C++), it
|
||||||
|
//! is _not perfect_.
|
||||||
|
//!
|
||||||
|
//! First, trait `std::error::Error` does not provide any means to
|
||||||
|
//! record the location of the source code that triggers an error, leading to
|
||||||
|
//! a slow process of diagnosing errors or bugs.
|
||||||
|
//!
|
||||||
|
//! Second, while the `Error` trait (which has a `cause` method)
|
||||||
|
//! supports backtrace in theory, it is inconvenient---in practice---to implement
|
||||||
|
//! backtrace. This is because the users still need to manually write the concrete
|
||||||
|
//! implementation that stores the cause for every error struct.
|
||||||
|
//!
|
||||||
|
//! Third, one challenging aspect of error handling in Rust is
|
||||||
|
//! dealing with the various types of errors. The standard library
|
||||||
|
//! defines errors like `std::io::Error`, `std::fmt::Error`, `std::str::Utf8Error`, etc.
|
||||||
|
//! Not to mention the error types defined by third-party libraries.
|
||||||
|
//! To make it even worse, we, as OS writers, have to convert all these errors
|
||||||
|
//! into POSIX errno eventually.
|
||||||
|
//!
|
||||||
|
//! To cope with the issues above, this crate extends Rust's standard error
|
||||||
|
//! handling mechanism. Specifically, it aims at the following design goals:
|
||||||
|
//!
|
||||||
|
//! * **Fast diagnose** (e.g., reporting the backtrace and the code location of an error).
|
||||||
|
//! * **First-class POSIX errno** (e.g., every error has an errno).
|
||||||
|
//! * **Zero-overhead abstraction** (e.g., no heap allocation unless absolutely necesary).
|
||||||
|
//! * **Ergonomic grammar** (e.g., use macros to avoid writing code manually).
|
||||||
|
//! * **Compatibility with `no_std`**.
|
||||||
|
//!
|
||||||
|
//! # How to Use
|
||||||
|
//!
|
||||||
|
//! ## Basic Usage
|
||||||
|
//!
|
||||||
|
//! The simplest usage involves just one macro---`errno!`.
|
||||||
|
//! See the sample code below:
|
||||||
|
//! ```rust
|
||||||
|
//! use errno::prelude::*;
|
||||||
|
//!
|
||||||
|
//! fn return_err() -> Result<()> {
|
||||||
|
//! Err(errno!(EINVAL, "the root error"))
|
||||||
|
//! }
|
||||||
|
//!
|
||||||
|
//! # fn main() {
|
||||||
|
//! if let Err(e) = return_err() {
|
||||||
|
//! println!("{}", e);
|
||||||
|
//! }
|
||||||
|
//! # }
|
||||||
|
//! ```
|
||||||
|
//! which prints something like
|
||||||
|
//! ```text
|
||||||
|
//! EINVAL (#22, Invalid argument): the root error [line = 45, file = src/lib.rs]
|
||||||
|
//! ```
|
||||||
|
//! Note that the specific line and file of source code that generates the error
|
||||||
|
//! is printed. This facilitates diagnosing errors.
|
||||||
|
//!
|
||||||
|
//! ## Backtrace
|
||||||
|
//!
|
||||||
|
//! A more interesting usage is to print the backtrace of an error. To create
|
||||||
|
//! the chains of errors, `std::result::Result` is extended with a new method
|
||||||
|
//! named `cause_err`. If the result is `Ok`, the method does nothing; otherwise,
|
||||||
|
//! this method executes a user-given closure to output a new error whose cause
|
||||||
|
//! is the error contained in the result. The method consumes the current result
|
||||||
|
//! and generates a new result that contains the new error. The two errors are
|
||||||
|
//! chained. More calls to `cause_err` form deeper backtraces.
|
||||||
|
//!
|
||||||
|
//! See the sample code below:
|
||||||
|
//! ```rust
|
||||||
|
//! use errno::prelude::*;
|
||||||
|
//!
|
||||||
|
//! fn return_err() -> Result<()> {
|
||||||
|
//! Err(errno!(EINVAL, "the root error"))
|
||||||
|
//! }
|
||||||
|
//!
|
||||||
|
//! fn cause_err() -> Result<()> {
|
||||||
|
//! return_err()
|
||||||
|
//! .cause_err(|_e| errno!(EIO, "another error"))
|
||||||
|
//! }
|
||||||
|
//!
|
||||||
|
//! # fn main() {
|
||||||
|
//! if let Err(e) = cause_err() {
|
||||||
|
//! println!("{}", e.backtrace());
|
||||||
|
//! }
|
||||||
|
//! # }
|
||||||
|
//! ```
|
||||||
|
//! which prints something like
|
||||||
|
//! ```text
|
||||||
|
//! EIO (#5, I/O error): another error [line = 71, file = src/lib.rs]
|
||||||
|
//! Caused by EINVAL (#22, Invalid argument): the root error [line = 68, file = src/lib.rs]
|
||||||
|
//! ```
|
||||||
|
//!
|
||||||
|
|
||||||
|
#![feature(allocator_api)]
|
||||||
|
// Use no_std and alloc crate except when given std feature or during test.
|
||||||
|
#![cfg_attr(not(any(feature = "std", test, doctest)), no_std)]
|
||||||
|
extern crate alloc;
|
||||||
|
// Use Rust SGX SDK's std when given SGX feature.
|
||||||
|
#[cfg(feature = "sgx")]
|
||||||
|
extern crate sgx_tstd as std;
|
||||||
|
|
||||||
|
#[macro_use]
|
||||||
|
extern crate log;
|
||||||
|
|
||||||
|
mod backtrace;
|
||||||
|
mod errno;
|
||||||
|
mod error;
|
||||||
|
pub mod prelude;
|
||||||
|
mod result;
|
||||||
|
mod to_errno;
|
||||||
|
|
||||||
|
pub use self::backtrace::ErrorBacktrace;
|
||||||
|
pub use self::errno::*;
|
||||||
|
pub use self::errno::Errno::*;
|
||||||
|
pub use self::error::{Error, ErrorLocation};
|
||||||
|
pub use self::result::{Result, ResultExt};
|
||||||
|
pub use self::to_errno::ToErrno;
|
||||||
|
|
||||||
|
#[macro_export]
|
||||||
|
macro_rules! errno {
|
||||||
|
($errno_expr: expr, $error_msg: expr) => {{
|
||||||
|
let inner_error = {
|
||||||
|
let errno: Errno = $errno_expr;
|
||||||
|
let msg: &'static str = $error_msg;
|
||||||
|
(errno, msg)
|
||||||
|
};
|
||||||
|
let error =
|
||||||
|
$crate::Error::embedded(inner_error, Some($crate::ErrorLocation::new(file!(), line!())));
|
||||||
|
error
|
||||||
|
}};
|
||||||
|
($error_expr: expr) => {{
|
||||||
|
let inner_error = $error_expr;
|
||||||
|
let error = $crate::Error::boxed(inner_error, Some($crate::ErrorLocation::new(file!(), line!())));
|
||||||
|
error
|
||||||
|
}};
|
||||||
|
}
|
||||||
|
|
||||||
|
#[macro_export]
|
||||||
|
macro_rules! return_errno {
|
||||||
|
($errno_expr: expr, $error_msg: expr) => {{
|
||||||
|
return Err(errno!($errno_expr, $error_msg));
|
||||||
|
}};
|
||||||
|
($error_expr: expr) => {{
|
||||||
|
return Err(errno!($error_expr));
|
||||||
|
}};
|
||||||
|
}
|
||||||
|
|
||||||
|
// return Err(errno) if libc return -1
|
||||||
|
#[macro_export]
|
||||||
|
macro_rules! try_libc {
|
||||||
|
($ret: expr) => {{
|
||||||
|
let ret = unsafe { $ret };
|
||||||
|
if ret < 0 {
|
||||||
|
let errno = unsafe { libc::errno() };
|
||||||
|
return_errno!(Errno::from(errno as u32), "libc error");
|
||||||
|
}
|
||||||
|
ret
|
||||||
|
}};
|
||||||
|
}
|
||||||
|
|
||||||
|
// return Err(errno) if libc return -1
|
||||||
|
// raise SIGPIPE if errno == EPIPE
|
||||||
|
#[macro_export]
|
||||||
|
macro_rules! try_libc_may_epipe {
|
||||||
|
($ret: expr) => {{
|
||||||
|
let ret = unsafe { $ret };
|
||||||
|
if ret < 0 {
|
||||||
|
let errno = unsafe { libc::errno() };
|
||||||
|
if errno == Errno::EPIPE as i32 {
|
||||||
|
crate::signal::do_tkill(current!().tid(), crate::signal::SIGPIPE.as_u8() as i32);
|
||||||
|
}
|
||||||
|
return_errno!(Errno::from(errno as u32), "libc error");
|
||||||
|
}
|
||||||
|
ret
|
||||||
|
}};
|
||||||
|
}
|
||||||
|
|
||||||
|
#[cfg(test)]
|
||||||
|
mod tests {
|
||||||
|
use crate::prelude::*;
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn convert_std_io_error() -> Result<()> {
|
||||||
|
use std::io::{BufWriter, Write};
|
||||||
|
let mut buf_writer = BufWriter::new(Vec::<u8>::new());
|
||||||
|
// std::io::Error can be converted crate::Error implicitly
|
||||||
|
buf_writer.write("foo".as_bytes())?;
|
||||||
|
Ok(())
|
||||||
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn convert_std_ffi_nul_error() -> Result<()> {
|
||||||
|
use std::ffi::CString;
|
||||||
|
// std::ffi::NulError can be converted crate::Error implicitly
|
||||||
|
let _ = CString::new(b"foo".to_vec())?;
|
||||||
|
Ok(())
|
||||||
|
}
|
||||||
|
}
|
3
src/libos/crates/errno/src/prelude.rs
Normal file
3
src/libos/crates/errno/src/prelude.rs
Normal file
@ -0,0 +1,3 @@
|
|||||||
|
pub use crate::{
|
||||||
|
errno, return_errno, Errno, Errno::*, Error, ErrorLocation, Result, ResultExt, ToErrno,
|
||||||
|
};
|
34
src/libos/crates/errno/src/result.rs
Normal file
34
src/libos/crates/errno/src/result.rs
Normal file
@ -0,0 +1,34 @@
|
|||||||
|
use super::{Errno, Error};
|
||||||
|
|
||||||
|
pub type Result<T> = core::result::Result<T, Error>;
|
||||||
|
|
||||||
|
/// Extending `Result` with extra functionalities.
|
||||||
|
pub trait ResultExt<T> {
|
||||||
|
fn cause_err<F>(self, f: F) -> Result<T>
|
||||||
|
where
|
||||||
|
F: FnOnce(&Error) -> Error;
|
||||||
|
|
||||||
|
fn errno(&self) -> Option<Errno>;
|
||||||
|
|
||||||
|
fn has_errno(&self, errno: Errno) -> bool;
|
||||||
|
}
|
||||||
|
|
||||||
|
impl<T> ResultExt<T> for Result<T> {
|
||||||
|
fn cause_err<F>(self, f: F) -> Result<T>
|
||||||
|
where
|
||||||
|
F: FnOnce(&Error) -> Error,
|
||||||
|
{
|
||||||
|
self.map_err(|old_e| old_e.cause_err(f))
|
||||||
|
}
|
||||||
|
|
||||||
|
fn errno(&self) -> Option<Errno> {
|
||||||
|
match self {
|
||||||
|
Ok(_) => None,
|
||||||
|
Err(e) => Some(e.errno()),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
fn has_errno(&self, errno: Errno) -> bool {
|
||||||
|
self.errno() == Some(errno)
|
||||||
|
}
|
||||||
|
}
|
138
src/libos/crates/errno/src/to_errno.rs
Normal file
138
src/libos/crates/errno/src/to_errno.rs
Normal file
@ -0,0 +1,138 @@
|
|||||||
|
use core::fmt;
|
||||||
|
|
||||||
|
use super::{Errno, Error};
|
||||||
|
|
||||||
|
pub trait ToErrno: fmt::Display + fmt::Debug {
|
||||||
|
fn errno(&self) -> Errno;
|
||||||
|
}
|
||||||
|
|
||||||
|
impl<T> From<T> for Error
|
||||||
|
where
|
||||||
|
T: ToErrno + Send + 'static,
|
||||||
|
{
|
||||||
|
fn from(t: T) -> Error {
|
||||||
|
Error::boxed(t, None)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl ToErrno for Errno {
|
||||||
|
fn errno(&self) -> Errno {
|
||||||
|
*self
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl ToErrno for core::alloc::AllocError {
|
||||||
|
fn errno(&self) -> Errno {
|
||||||
|
Errno::ENOMEM
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl ToErrno for core::alloc::LayoutError {
|
||||||
|
fn errno(&self) -> Errno {
|
||||||
|
Errno::EINVAL
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl ToErrno for core::num::ParseIntError {
|
||||||
|
fn errno(&self) -> Errno {
|
||||||
|
Errno::EINVAL
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
#[cfg(any(feature = "std", feature = "sgx", test, doctest))]
|
||||||
|
mod if_std {
|
||||||
|
use super::*;
|
||||||
|
|
||||||
|
impl From<std::io::ErrorKind> for Errno {
|
||||||
|
fn from(kind: std::io::ErrorKind) -> Errno {
|
||||||
|
use std::io::ErrorKind::*;
|
||||||
|
use Errno::*;
|
||||||
|
match kind {
|
||||||
|
NotFound => ENOENT,
|
||||||
|
PermissionDenied => EPERM,
|
||||||
|
ConnectionRefused => ECONNREFUSED,
|
||||||
|
ConnectionReset => ECONNRESET,
|
||||||
|
ConnectionAborted => ECONNABORTED,
|
||||||
|
NotConnected => ENOTCONN,
|
||||||
|
AddrInUse => EADDRINUSE,
|
||||||
|
AddrNotAvailable => EADDRNOTAVAIL,
|
||||||
|
BrokenPipe => EPIPE,
|
||||||
|
AlreadyExists => EEXIST,
|
||||||
|
WouldBlock => Errno::EWOULDBLOCK,
|
||||||
|
InvalidInput => EINVAL,
|
||||||
|
InvalidData => EBADMSG, /* TODO: correct? */
|
||||||
|
TimedOut => ETIMEDOUT,
|
||||||
|
Interrupted => EINTR,
|
||||||
|
WriteZero => EINVAL,
|
||||||
|
UnexpectedEof => EIO,
|
||||||
|
Other => EIO,
|
||||||
|
_ => EIO,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl ToErrno for std::io::Error {
|
||||||
|
fn errno(&self) -> Errno {
|
||||||
|
Errno::from(self.kind())
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl ToErrno for std::ffi::NulError {
|
||||||
|
fn errno(&self) -> Errno {
|
||||||
|
Errno::EINVAL
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
#[cfg(feature = "occlum")]
|
||||||
|
mod if_occlum {
|
||||||
|
use rcore_fs::dev::DevError;
|
||||||
|
use rcore_fs::vfs::FsError;
|
||||||
|
|
||||||
|
use super::*;
|
||||||
|
|
||||||
|
impl ToErrno for serde_json::Error {
|
||||||
|
fn errno(&self) -> Errno {
|
||||||
|
Errno::EINVAL
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl ToErrno for FsError {
|
||||||
|
fn errno(&self) -> Errno {
|
||||||
|
use Errno::*;
|
||||||
|
match *self {
|
||||||
|
FsError::NotSupported => ENOSYS,
|
||||||
|
FsError::NotFile => EISDIR,
|
||||||
|
FsError::IsDir => EISDIR,
|
||||||
|
FsError::NotDir => ENOTDIR,
|
||||||
|
FsError::EntryNotFound => ENOENT,
|
||||||
|
FsError::EntryExist => EEXIST,
|
||||||
|
FsError::NotSameFs => EXDEV,
|
||||||
|
FsError::InvalidParam => EINVAL,
|
||||||
|
FsError::NoDeviceSpace => ENOMEM,
|
||||||
|
FsError::DirRemoved => ENOENT,
|
||||||
|
FsError::DirNotEmpty => ENOTEMPTY,
|
||||||
|
FsError::WrongFs => EINVAL,
|
||||||
|
FsError::DeviceError(_err) => EIO,
|
||||||
|
FsError::SymLoop => ELOOP,
|
||||||
|
FsError::NoDevice => ENXIO,
|
||||||
|
FsError::IOCTLError => EINVAL,
|
||||||
|
FsError::Again => EAGAIN,
|
||||||
|
FsError::Busy => EBUSY,
|
||||||
|
FsError::WrProtected => EROFS,
|
||||||
|
FsError::NoIntegrity => EIO,
|
||||||
|
FsError::PermError => EPERM,
|
||||||
|
FsError::NameTooLong => ENAMETOOLONG,
|
||||||
|
FsError::FileTooBig => EFBIG,
|
||||||
|
FsError::OpNotSupported => EOPNOTSUPP,
|
||||||
|
FsError::NotMountPoint => EINVAL,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl From<Error> for DevError {
|
||||||
|
fn from(e: Error) -> Self {
|
||||||
|
DevError(e.errno() as i32)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
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);
|
||||||
|
}
|
616
src/libos/crates/vdso-time/src/lib.rs
Normal file
616
src/libos/crates/vdso-time/src/lib.rs
Normal file
@ -0,0 +1,616 @@
|
|||||||
|
#![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().ok();
|
||||||
|
}
|
||||||
|
|
||||||
|
/// 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)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
pub 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")
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
pub 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
|
||||||
|
}
|
||||||
|
}
|
@ -10,7 +10,7 @@ use crate::interrupt;
|
|||||||
use crate::process::idle_reap_zombie_children;
|
use crate::process::idle_reap_zombie_children;
|
||||||
use crate::process::{ProcessFilter, SpawnAttr};
|
use crate::process::{ProcessFilter, SpawnAttr};
|
||||||
use crate::signal::SigNum;
|
use crate::signal::SigNum;
|
||||||
use crate::time::up_time::init;
|
use crate::time::init;
|
||||||
use crate::util::host_file_util::{host_file_buffer, parse_host_file, write_host_file, HostFile};
|
use crate::util::host_file_util::{host_file_buffer, parse_host_file, write_host_file, HostFile};
|
||||||
use crate::util::log::LevelFilter;
|
use crate::util::log::LevelFilter;
|
||||||
use crate::util::mem_util::from_untrusted::*;
|
use crate::util::mem_util::from_untrusted::*;
|
||||||
@ -96,8 +96,8 @@ pub extern "C" fn occlum_ecall_init(
|
|||||||
|
|
||||||
interrupt::init();
|
interrupt::init();
|
||||||
|
|
||||||
// Init boot up time stamp here.
|
// Init vdso and boot up time stamp here.
|
||||||
time::up_time::init();
|
time::init();
|
||||||
|
|
||||||
vm::init_user_space();
|
vm::init_user_space();
|
||||||
|
|
||||||
|
@ -1,69 +1 @@
|
|||||||
use super::*;
|
pub use errno::{Errno::*, *};
|
||||||
use std::fmt;
|
|
||||||
|
|
||||||
mod backtrace;
|
|
||||||
mod errno;
|
|
||||||
mod error;
|
|
||||||
mod to_errno;
|
|
||||||
|
|
||||||
pub use self::backtrace::{ErrorBacktrace, ResultExt};
|
|
||||||
pub use self::errno::Errno;
|
|
||||||
pub use self::errno::Errno::*;
|
|
||||||
pub use self::error::{Error, ErrorLocation};
|
|
||||||
pub use self::to_errno::ToErrno;
|
|
||||||
|
|
||||||
pub type Result<T> = std::result::Result<T, Error>;
|
|
||||||
|
|
||||||
macro_rules! errno {
|
|
||||||
($errno_expr: expr, $error_msg: expr) => {{
|
|
||||||
let inner_error = {
|
|
||||||
let errno: Errno = $errno_expr;
|
|
||||||
let msg: &'static str = $error_msg;
|
|
||||||
(errno, msg)
|
|
||||||
};
|
|
||||||
let error = Error::embedded(inner_error, Some(ErrorLocation::new(file!(), line!())));
|
|
||||||
error
|
|
||||||
}};
|
|
||||||
($error_expr: expr) => {{
|
|
||||||
let inner_error = $error_expr;
|
|
||||||
let error = Error::boxed(inner_error, Some(ErrorLocation::new(file!(), line!())));
|
|
||||||
error
|
|
||||||
}};
|
|
||||||
}
|
|
||||||
|
|
||||||
macro_rules! return_errno {
|
|
||||||
($errno_expr: expr, $error_msg: expr) => {{
|
|
||||||
return Err(errno!($errno_expr, $error_msg));
|
|
||||||
}};
|
|
||||||
($error_expr: expr) => {{
|
|
||||||
return Err(errno!($error_expr));
|
|
||||||
}};
|
|
||||||
}
|
|
||||||
|
|
||||||
// return Err(errno) if libc return -1
|
|
||||||
macro_rules! try_libc {
|
|
||||||
($ret: expr) => {{
|
|
||||||
let ret = unsafe { $ret };
|
|
||||||
if ret < 0 {
|
|
||||||
let errno = unsafe { libc::errno() };
|
|
||||||
return_errno!(Errno::from(errno as u32), "libc error");
|
|
||||||
}
|
|
||||||
ret
|
|
||||||
}};
|
|
||||||
}
|
|
||||||
|
|
||||||
// return Err(errno) if libc return -1
|
|
||||||
// raise SIGPIPE if errno == EPIPE
|
|
||||||
macro_rules! try_libc_may_epipe {
|
|
||||||
($ret: expr) => {{
|
|
||||||
let ret = unsafe { $ret };
|
|
||||||
if ret < 0 {
|
|
||||||
let errno = unsafe { libc::errno() };
|
|
||||||
if errno == Errno::EPIPE as i32 {
|
|
||||||
crate::signal::do_tkill(current!().tid(), crate::signal::SIGPIPE.as_u8() as i32);
|
|
||||||
}
|
|
||||||
return_errno!(Errno::from(errno as u32), "libc error");
|
|
||||||
}
|
|
||||||
ret
|
|
||||||
}};
|
|
||||||
}
|
|
||||||
|
@ -1,116 +0,0 @@
|
|||||||
use super::*;
|
|
||||||
|
|
||||||
pub trait ToErrno: fmt::Display + fmt::Debug {
|
|
||||||
fn errno(&self) -> Errno;
|
|
||||||
}
|
|
||||||
|
|
||||||
impl ToErrno for Errno {
|
|
||||||
fn errno(&self) -> Errno {
|
|
||||||
*self
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
impl<T> From<T> for Error
|
|
||||||
where
|
|
||||||
T: ToErrno + 'static,
|
|
||||||
{
|
|
||||||
fn from(t: T) -> Error {
|
|
||||||
Error::boxed(t, None)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
impl From<std::io::ErrorKind> for Errno {
|
|
||||||
fn from(kind: std::io::ErrorKind) -> Errno {
|
|
||||||
use std::io::ErrorKind::*;
|
|
||||||
match kind {
|
|
||||||
NotFound => ENOENT,
|
|
||||||
PermissionDenied => EPERM,
|
|
||||||
ConnectionRefused => ECONNREFUSED,
|
|
||||||
ConnectionReset => ECONNRESET,
|
|
||||||
ConnectionAborted => ECONNABORTED,
|
|
||||||
NotConnected => ENOTCONN,
|
|
||||||
AddrInUse => EADDRINUSE,
|
|
||||||
AddrNotAvailable => EADDRNOTAVAIL,
|
|
||||||
BrokenPipe => EPIPE,
|
|
||||||
AlreadyExists => EEXIST,
|
|
||||||
WouldBlock => EWOULDBLOCK,
|
|
||||||
InvalidInput => EINVAL,
|
|
||||||
InvalidData => EBADMSG, /* TODO: correct? */
|
|
||||||
TimedOut => ETIMEDOUT,
|
|
||||||
Interrupted => EINTR,
|
|
||||||
WriteZero => EINVAL,
|
|
||||||
UnexpectedEof => EIO,
|
|
||||||
Other => EIO,
|
|
||||||
_ => EIO,
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
impl ToErrno for std::io::Error {
|
|
||||||
fn errno(&self) -> Errno {
|
|
||||||
Errno::from(self.kind())
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
impl ToErrno for std::ffi::NulError {
|
|
||||||
fn errno(&self) -> Errno {
|
|
||||||
EINVAL
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
impl ToErrno for std::num::ParseIntError {
|
|
||||||
fn errno(&self) -> Errno {
|
|
||||||
EINVAL
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
impl ToErrno for serde_json::Error {
|
|
||||||
fn errno(&self) -> Errno {
|
|
||||||
EINVAL
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
impl ToErrno for rcore_fs::vfs::FsError {
|
|
||||||
fn errno(&self) -> Errno {
|
|
||||||
use rcore_fs::vfs::FsError;
|
|
||||||
match *self {
|
|
||||||
FsError::NotSupported => ENOSYS,
|
|
||||||
FsError::NotFile => EISDIR,
|
|
||||||
FsError::IsDir => EISDIR,
|
|
||||||
FsError::NotDir => ENOTDIR,
|
|
||||||
FsError::EntryNotFound => ENOENT,
|
|
||||||
FsError::EntryExist => EEXIST,
|
|
||||||
FsError::NotSameFs => EXDEV,
|
|
||||||
FsError::InvalidParam => EINVAL,
|
|
||||||
FsError::NoDeviceSpace => ENOMEM,
|
|
||||||
FsError::DirRemoved => ENOENT,
|
|
||||||
FsError::DirNotEmpty => ENOTEMPTY,
|
|
||||||
FsError::WrongFs => EINVAL,
|
|
||||||
FsError::DeviceError(err) => EIO,
|
|
||||||
FsError::SymLoop => ELOOP,
|
|
||||||
FsError::NoDevice => ENXIO,
|
|
||||||
FsError::IOCTLError => EINVAL,
|
|
||||||
FsError::Again => EAGAIN,
|
|
||||||
FsError::Busy => EBUSY,
|
|
||||||
FsError::WrProtected => EROFS,
|
|
||||||
FsError::NoIntegrity => EIO,
|
|
||||||
FsError::PermError => EPERM,
|
|
||||||
FsError::NameTooLong => ENAMETOOLONG,
|
|
||||||
FsError::FileTooBig => EFBIG,
|
|
||||||
FsError::OpNotSupported => EOPNOTSUPP,
|
|
||||||
FsError::NotMountPoint => EINVAL,
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
impl ToErrno for std::alloc::AllocError {
|
|
||||||
fn errno(&self) -> Errno {
|
|
||||||
ENOMEM
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
impl ToErrno for std::alloc::LayoutError {
|
|
||||||
fn errno(&self) -> Errno {
|
|
||||||
EINVAL
|
|
||||||
}
|
|
||||||
}
|
|
@ -18,7 +18,7 @@ struct CpuIdInput {
|
|||||||
|
|
||||||
#[repr(C)]
|
#[repr(C)]
|
||||||
#[derive(Eq, PartialEq, Hash, Clone, Copy, Debug)]
|
#[derive(Eq, PartialEq, Hash, Clone, Copy, Debug)]
|
||||||
struct CpuIdResult {
|
pub struct CpuIdResult {
|
||||||
eax: u32,
|
eax: u32,
|
||||||
ebx: u32,
|
ebx: u32,
|
||||||
ecx: u32,
|
ecx: u32,
|
||||||
@ -218,6 +218,15 @@ impl CpuId {
|
|||||||
};
|
};
|
||||||
cpuid_result
|
cpuid_result
|
||||||
}
|
}
|
||||||
|
|
||||||
|
pub fn support_sgx2(&self) -> bool {
|
||||||
|
const SGX_CPUID: u32 = 0x12;
|
||||||
|
let cpuid = self.get_cpuid_info(SGX_CPUID, 0);
|
||||||
|
|
||||||
|
// The 0th bit set to 1 in `cpuid.eax` indicates that the SGX feature is enabled.
|
||||||
|
// The 1st bit set to 1 in `cpuid.eax` indicates that the SGX2 feature is enabled.
|
||||||
|
(cpuid.eax & 0b11) == 0b11
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
lazy_static! {
|
lazy_static! {
|
||||||
@ -247,6 +256,14 @@ fn get_cpuid_info_via_ocall(cpuid_input: CpuIdInput) -> CpuIdResult {
|
|||||||
cpuid_result
|
cpuid_result
|
||||||
}
|
}
|
||||||
|
|
||||||
|
pub fn is_cpu_support_sgx2() -> bool {
|
||||||
|
CPUID.support_sgx2()
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn get_cpuid_info(leaf: u32, subleaf: u32) -> CpuIdResult {
|
||||||
|
CPUID.get_cpuid_info(leaf, subleaf)
|
||||||
|
}
|
||||||
|
|
||||||
pub fn setup_cpuid_info() {
|
pub fn setup_cpuid_info() {
|
||||||
// Make lazy_static to be executed at runtime in order to be initialized
|
// Make lazy_static to be executed at runtime in order to be initialized
|
||||||
let max_basic_leaf = CPUID.get_max_basic_leaf();
|
let max_basic_leaf = CPUID.get_max_basic_leaf();
|
||||||
|
@ -11,6 +11,8 @@ use crate::vm::{enclave_page_fault_handler, is_page_committed, VMRange, USER_SPA
|
|||||||
use sgx_types::*;
|
use sgx_types::*;
|
||||||
use sgx_types::{sgx_exception_type_t, sgx_exception_vector_t};
|
use sgx_types::{sgx_exception_type_t, sgx_exception_vector_t};
|
||||||
|
|
||||||
|
pub use self::cpuid::{get_cpuid_info, is_cpu_support_sgx2};
|
||||||
|
|
||||||
const ENCLU: u32 = 0xd7010f;
|
const ENCLU: u32 = 0xd7010f;
|
||||||
const EACCEPT: u32 = 0x5;
|
const EACCEPT: u32 = 0x5;
|
||||||
const EACCEPTCOPY: u32 = 0x7;
|
const EACCEPTCOPY: u32 = 0x7;
|
||||||
|
@ -1,4 +1,5 @@
|
|||||||
use super::*;
|
use super::*;
|
||||||
|
use crate::util::kernel_alloc::KernelAlloc;
|
||||||
use crate::vm::USER_SPACE_VM_MANAGER;
|
use crate::vm::USER_SPACE_VM_MANAGER;
|
||||||
|
|
||||||
pub struct MemInfoINode;
|
pub struct MemInfoINode;
|
||||||
@ -15,13 +16,26 @@ impl ProcINode for MemInfoINode {
|
|||||||
fn generate_data_in_bytes(&self) -> vfs::Result<Vec<u8>> {
|
fn generate_data_in_bytes(&self) -> vfs::Result<Vec<u8>> {
|
||||||
let total_ram = USER_SPACE_VM_MANAGER.get_total_size();
|
let total_ram = USER_SPACE_VM_MANAGER.get_total_size();
|
||||||
let free_ram = USER_SPACE_VM_MANAGER.get_precise_free_size();
|
let free_ram = USER_SPACE_VM_MANAGER.get_precise_free_size();
|
||||||
|
let kernel_heap_total = KernelAlloc::get_kernel_heap_config();
|
||||||
|
let kernel_heap_peak_used = KernelAlloc::get_kernel_heap_peak_used();
|
||||||
|
let kernel_heap_in_use = if let Some(bytes) = KernelAlloc::get_kernel_mem_size() {
|
||||||
|
format!("{} kB", bytes / KB)
|
||||||
|
} else {
|
||||||
|
"Feature not enabled".to_string()
|
||||||
|
};
|
||||||
Ok(format!(
|
Ok(format!(
|
||||||
"MemTotal: {} kB\n\
|
"MemTotal: {} kB\n\
|
||||||
MemFree: {} kB\n\
|
MemFree: {} kB\n\
|
||||||
MemAvailable: {} kB\n",
|
MemAvailable: {} kB\n\
|
||||||
|
KernelHeapTotal: {} kB\n\
|
||||||
|
KernelHeapPeakUsed: {} kB\n\
|
||||||
|
KernelHeapInUse: {}\n",
|
||||||
total_ram / KB,
|
total_ram / KB,
|
||||||
free_ram / KB,
|
free_ram / KB,
|
||||||
free_ram / KB,
|
free_ram / KB,
|
||||||
|
kernel_heap_total / KB,
|
||||||
|
kernel_heap_peak_used / KB,
|
||||||
|
kernel_heap_in_use,
|
||||||
)
|
)
|
||||||
.into_bytes())
|
.into_bytes())
|
||||||
}
|
}
|
||||||
|
@ -321,10 +321,3 @@ impl File for LockedFile {
|
|||||||
Ok(SefsMac(file.get_mac().unwrap()))
|
Ok(SefsMac(file.get_mac().unwrap()))
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl From<Error> for DevError {
|
|
||||||
fn from(e: Error) -> Self {
|
|
||||||
error!("SGX protected file I/O error: {}", e.backtrace());
|
|
||||||
DevError(e.errno() as i32)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
@ -6,7 +6,7 @@ use super::file_ops::{
|
|||||||
};
|
};
|
||||||
use super::fs_ops;
|
use super::fs_ops;
|
||||||
use super::fs_ops::{MountFlags, MountOptions, UmountFlags};
|
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::timer_file::{TimerCreationFlags, TimerSetFlags};
|
||||||
use super::*;
|
use super::*;
|
||||||
use crate::config::{user_rootfs_config, ConfigApp, ConfigMountFsType};
|
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> {
|
pub fn do_timerfd_create(clockid: clockid_t, flags: i32) -> Result<isize> {
|
||||||
debug!("timerfd: clockid {}, flags {} ", clockid, flags);
|
debug!("timerfd: clockid {}, flags {} ", clockid, flags);
|
||||||
|
|
||||||
let clockid = ClockID::from_raw(clockid)?;
|
let clockid = ClockId::try_from(clockid)?;
|
||||||
match clockid {
|
match clockid {
|
||||||
ClockID::CLOCK_REALTIME | ClockID::CLOCK_MONOTONIC => {}
|
ClockId::CLOCK_REALTIME | ClockId::CLOCK_MONOTONIC => {}
|
||||||
_ => {
|
_ => {
|
||||||
return_errno!(EINVAL, "invalid clockid");
|
return_errno!(EINVAL, "invalid clockid");
|
||||||
}
|
}
|
||||||
|
@ -1,6 +1,6 @@
|
|||||||
use super::*;
|
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 atomic::{Atomic, Ordering};
|
||||||
use std::time::Duration;
|
use std::time::Duration;
|
||||||
|
|
||||||
@ -13,7 +13,7 @@ pub struct TimerFile {
|
|||||||
}
|
}
|
||||||
|
|
||||||
impl 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 raw_host_fd = try_libc!({
|
||||||
let mut ret: i32 = 0;
|
let mut ret: i32 = 0;
|
||||||
let status = occlum_ocall_timerfd_create(&mut ret, clockid as clockid_t, flags.bits());
|
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 itertools;
|
||||||
extern crate modular_bitfield;
|
extern crate modular_bitfield;
|
||||||
extern crate resolv_conf;
|
extern crate resolv_conf;
|
||||||
|
extern crate vdso_time;
|
||||||
|
|
||||||
use sgx_trts::libc;
|
use sgx_trts::libc;
|
||||||
use sgx_types::*;
|
use sgx_types::*;
|
||||||
|
@ -102,12 +102,12 @@ pub fn do_exec(
|
|||||||
// Blocking wait until there is only one thread in the calling process
|
// Blocking wait until there is only one thread in the calling process
|
||||||
fn wait_for_other_threads_to_exit(current_ref: &ThreadRef) {
|
fn wait_for_other_threads_to_exit(current_ref: &ThreadRef) {
|
||||||
use super::do_futex::{self, FutexTimeout};
|
use super::do_futex::{self, FutexTimeout};
|
||||||
use crate::time::{timespec_t, ClockID};
|
use crate::time::{timespec_t, ClockId};
|
||||||
use core::time::Duration;
|
use core::time::Duration;
|
||||||
|
|
||||||
// Set timeout to 50ms
|
// Set timeout to 50ms
|
||||||
let timeout = FutexTimeout::new(
|
let timeout = FutexTimeout::new(
|
||||||
ClockID::CLOCK_MONOTONIC,
|
ClockId::CLOCK_MONOTONIC,
|
||||||
timespec_t::from(Duration::from_millis(50)),
|
timespec_t::from(Duration::from_millis(50)),
|
||||||
false,
|
false,
|
||||||
);
|
);
|
||||||
|
@ -4,7 +4,7 @@ use std::intrinsics::atomic_load_seqcst;
|
|||||||
use std::sync::atomic::{AtomicBool, Ordering};
|
use std::sync::atomic::{AtomicBool, Ordering};
|
||||||
|
|
||||||
use crate::prelude::*;
|
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
|
/// `FutexOp`, `FutexFlags`, and `futex_op_and_flags_from_u32` are helper types and
|
||||||
/// functions for handling the versatile commands and arguments of futex system
|
/// 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)]
|
#[derive(Debug, Copy, Clone)]
|
||||||
pub struct FutexTimeout {
|
pub struct FutexTimeout {
|
||||||
clock_id: ClockID,
|
clock_id: ClockId,
|
||||||
ts: timespec_t,
|
ts: timespec_t,
|
||||||
absolute_time: bool,
|
absolute_time: bool,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl FutexTimeout {
|
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 {
|
Self {
|
||||||
clock_id,
|
clock_id,
|
||||||
ts,
|
ts,
|
||||||
@ -89,7 +89,7 @@ impl FutexTimeout {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn clock_id(&self) -> &ClockID {
|
pub fn clock_id(&self) -> &ClockId {
|
||||||
&self.clock_id
|
&self.clock_id
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -502,7 +502,7 @@ fn wait_event_timeout(thread: *const c_void, timeout: &Option<FutexTimeout>) ->
|
|||||||
.as_ref()
|
.as_ref()
|
||||||
.map(|timeout| {
|
.map(|timeout| {
|
||||||
let clockbit = match timeout.clock_id() {
|
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,
|
_ => 0,
|
||||||
};
|
};
|
||||||
(
|
(
|
||||||
|
@ -11,7 +11,7 @@ use super::process::ProcessFilter;
|
|||||||
use super::spawn_attribute::{clone_spawn_atrributes_safely, posix_spawnattr_t, SpawnAttr};
|
use super::spawn_attribute::{clone_spawn_atrributes_safely, posix_spawnattr_t, SpawnAttr};
|
||||||
use crate::prelude::*;
|
use crate::prelude::*;
|
||||||
use crate::syscall::CpuContext;
|
use crate::syscall::CpuContext;
|
||||||
use crate::time::{timespec_t, ClockID};
|
use crate::time::{timespec_t, ClockId};
|
||||||
use crate::util::mem_util::from_user::*;
|
use crate::util::mem_util::from_user::*;
|
||||||
use std::ptr::NonNull;
|
use std::ptr::NonNull;
|
||||||
|
|
||||||
@ -290,9 +290,9 @@ pub fn do_futex(
|
|||||||
"FUTEX_CLOCK_REALTIME with this futex operation is not supported"
|
"FUTEX_CLOCK_REALTIME with this futex operation is not supported"
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
ClockID::CLOCK_REALTIME
|
ClockId::CLOCK_REALTIME
|
||||||
} else {
|
} else {
|
||||||
ClockID::CLOCK_MONOTONIC
|
ClockId::CLOCK_MONOTONIC
|
||||||
};
|
};
|
||||||
|
|
||||||
// From futex man page:
|
// 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> {
|
fn do_clock_gettime(clockid: clockid_t, ts_u: *mut timespec_t) -> Result<isize> {
|
||||||
check_mut_ptr(ts_u)?;
|
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)?;
|
let ts = time::do_clock_gettime(clockid)?;
|
||||||
unsafe {
|
unsafe {
|
||||||
*ts_u = ts;
|
*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> {
|
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() {
|
if !tloc_u.is_null() {
|
||||||
check_mut_ptr(tloc_u)?;
|
check_mut_ptr(tloc_u)?;
|
||||||
unsafe {
|
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> {
|
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() {
|
if res_u.is_null() {
|
||||||
return Ok(0);
|
return Ok(0);
|
||||||
}
|
}
|
||||||
@ -981,7 +981,7 @@ fn do_clock_nanosleep(
|
|||||||
} else {
|
} else {
|
||||||
None
|
None
|
||||||
};
|
};
|
||||||
let clockid = time::ClockID::from_raw(clockid)?;
|
let clockid = time::ClockId::try_from(clockid)?;
|
||||||
time::do_clock_nanosleep(clockid, flags, &req, rem)?;
|
time::do_clock_nanosleep(clockid, flags, &req, rem)?;
|
||||||
Ok(0)
|
Ok(0)
|
||||||
}
|
}
|
||||||
|
@ -1,9 +1,12 @@
|
|||||||
use self::timer_slack::*;
|
use self::timer_slack::*;
|
||||||
use super::*;
|
use super::*;
|
||||||
|
use crate::exception::is_cpu_support_sgx2;
|
||||||
use core::convert::TryFrom;
|
use core::convert::TryFrom;
|
||||||
use process::pid_t;
|
use process::pid_t;
|
||||||
use rcore_fs::dev::TimeProvider;
|
use rcore_fs::dev::TimeProvider;
|
||||||
use rcore_fs::vfs::Timespec;
|
use rcore_fs::vfs::Timespec;
|
||||||
|
use sgx_trts::enclave::{rsgx_get_enclave_mode, EnclaveMode};
|
||||||
|
use spin::Once;
|
||||||
use std::time::Duration;
|
use std::time::Duration;
|
||||||
use std::{fmt, u64};
|
use std::{fmt, u64};
|
||||||
use syscall::SyscallNum;
|
use syscall::SyscallNum;
|
||||||
@ -14,6 +17,7 @@ pub mod up_time;
|
|||||||
|
|
||||||
pub use profiler::ThreadProfiler;
|
pub use profiler::ThreadProfiler;
|
||||||
pub use timer_slack::TIMERSLACK;
|
pub use timer_slack::TIMERSLACK;
|
||||||
|
pub use vdso_time::ClockId;
|
||||||
|
|
||||||
#[allow(non_camel_case_types)]
|
#[allow(non_camel_case_types)]
|
||||||
pub type time_t = i64;
|
pub type time_t = i64;
|
||||||
@ -27,6 +31,26 @@ pub type clock_t = i64;
|
|||||||
/// Clock ticks per second
|
/// Clock ticks per second
|
||||||
pub const SC_CLK_TCK: u64 = 100;
|
pub const SC_CLK_TCK: u64 = 100;
|
||||||
|
|
||||||
|
static IS_ENABLE_VDSO: Once<bool> = Once::new();
|
||||||
|
|
||||||
|
pub fn init() {
|
||||||
|
init_vdso();
|
||||||
|
up_time::init();
|
||||||
|
}
|
||||||
|
|
||||||
|
fn init_vdso() {
|
||||||
|
IS_ENABLE_VDSO.call_once(|| match rsgx_get_enclave_mode() {
|
||||||
|
EnclaveMode::Hw if is_cpu_support_sgx2() => true,
|
||||||
|
EnclaveMode::Sim => true,
|
||||||
|
_ => false,
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
#[inline(always)]
|
||||||
|
fn is_enable_vdso() -> bool {
|
||||||
|
IS_ENABLE_VDSO.get().map_or(false, |is_enable| *is_enable)
|
||||||
|
}
|
||||||
|
|
||||||
#[repr(C)]
|
#[repr(C)]
|
||||||
#[derive(Debug, Default, Copy, Clone)]
|
#[derive(Debug, Default, Copy, Clone)]
|
||||||
#[allow(non_camel_case_types)]
|
#[allow(non_camel_case_types)]
|
||||||
@ -74,15 +98,16 @@ impl From<Duration> for timeval_t {
|
|||||||
}
|
}
|
||||||
|
|
||||||
pub fn do_gettimeofday() -> timeval_t {
|
pub fn do_gettimeofday() -> timeval_t {
|
||||||
extern "C" {
|
let duration = if is_enable_vdso() {
|
||||||
fn occlum_ocall_gettimeofday(tv: *mut timeval_t) -> sgx_status_t;
|
vdso_time::clock_gettime(ClockId::CLOCK_REALTIME).unwrap()
|
||||||
}
|
} else {
|
||||||
|
// SGX1 Hardware doesn't support rdtsc instruction
|
||||||
|
vdso_time::clock_gettime_slow(ClockId::CLOCK_REALTIME).unwrap()
|
||||||
|
};
|
||||||
|
|
||||||
let mut tv: timeval_t = Default::default();
|
let tv = timeval_t::from(duration);
|
||||||
unsafe {
|
tv.validate()
|
||||||
occlum_ocall_gettimeofday(&mut tv as *mut timeval_t);
|
.expect("gettimeofday returned invalid timeval_t");
|
||||||
}
|
|
||||||
tv.validate().expect("ocall returned invalid timeval_t");
|
|
||||||
tv
|
tv
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -149,58 +174,29 @@ impl timespec_t {
|
|||||||
#[allow(non_camel_case_types)]
|
#[allow(non_camel_case_types)]
|
||||||
pub type clockid_t = i32;
|
pub type clockid_t = i32;
|
||||||
|
|
||||||
#[derive(Debug, Copy, Clone)]
|
pub fn do_clock_gettime(clockid: ClockId) -> Result<timespec_t> {
|
||||||
#[allow(non_camel_case_types)]
|
let duration = if is_enable_vdso() {
|
||||||
pub enum ClockID {
|
vdso_time::clock_gettime(clockid).unwrap()
|
||||||
CLOCK_REALTIME = 0,
|
} else {
|
||||||
CLOCK_MONOTONIC = 1,
|
// SGX1 Hardware doesn't support rdtsc instruction
|
||||||
CLOCK_PROCESS_CPUTIME_ID = 2,
|
vdso_time::clock_gettime_slow(clockid).unwrap()
|
||||||
CLOCK_THREAD_CPUTIME_ID = 3,
|
};
|
||||||
CLOCK_MONOTONIC_RAW = 4,
|
|
||||||
CLOCK_REALTIME_COARSE = 5,
|
|
||||||
CLOCK_MONOTONIC_COARSE = 6,
|
|
||||||
CLOCK_BOOTTIME = 7,
|
|
||||||
}
|
|
||||||
|
|
||||||
impl ClockID {
|
let tv = timespec_t::from(duration);
|
||||||
#[deny(unreachable_patterns)]
|
tv.validate()
|
||||||
pub fn from_raw(clockid: clockid_t) -> Result<ClockID> {
|
.expect("clock_gettime returned invalid timespec");
|
||||||
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");
|
|
||||||
Ok(tv)
|
Ok(tv)
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn do_clock_getres(clockid: ClockID) -> Result<timespec_t> {
|
pub fn do_clock_getres(clockid: ClockId) -> Result<timespec_t> {
|
||||||
extern "C" {
|
let duration = if is_enable_vdso() {
|
||||||
fn occlum_ocall_clock_getres(clockid: clockid_t, res: *mut timespec_t) -> sgx_status_t;
|
vdso_time::clock_getres(clockid).unwrap()
|
||||||
}
|
} else {
|
||||||
|
// SGX1 Hardware doesn't support rdtsc instruction
|
||||||
|
vdso_time::clock_getres_slow(clockid).unwrap()
|
||||||
|
};
|
||||||
|
|
||||||
let mut res: timespec_t = Default::default();
|
let res = timespec_t::from(duration);
|
||||||
unsafe {
|
|
||||||
occlum_ocall_clock_getres(clockid as clockid_t, &mut res as *mut timespec_t);
|
|
||||||
}
|
|
||||||
let validate_resolution = |res: ×pec_t| -> Result<()> {
|
let validate_resolution = |res: ×pec_t| -> Result<()> {
|
||||||
// The resolution can be ranged from 1 nanosecond to a few milliseconds
|
// 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 {
|
if res.sec == 0 && res.nsec > 0 && res.nsec < 1_000_000_000 {
|
||||||
@ -210,14 +206,14 @@ pub fn do_clock_getres(clockid: ClockID) -> Result<timespec_t> {
|
|||||||
}
|
}
|
||||||
};
|
};
|
||||||
// do sanity check
|
// do sanity check
|
||||||
validate_resolution(&res).expect("ocall returned invalid resolution");
|
validate_resolution(&res).expect("clock_getres returned invalid resolution");
|
||||||
Ok(res)
|
Ok(res)
|
||||||
}
|
}
|
||||||
|
|
||||||
const TIMER_ABSTIME: i32 = 0x01;
|
const TIMER_ABSTIME: i32 = 0x01;
|
||||||
|
|
||||||
pub fn do_clock_nanosleep(
|
pub fn do_clock_nanosleep(
|
||||||
clockid: ClockID,
|
clockid: ClockId,
|
||||||
flags: i32,
|
flags: i32,
|
||||||
req: ×pec_t,
|
req: ×pec_t,
|
||||||
rem: Option<&mut timespec_t>,
|
rem: Option<&mut timespec_t>,
|
||||||
@ -235,11 +231,11 @@ pub fn do_clock_nanosleep(
|
|||||||
let mut ret = 0;
|
let mut ret = 0;
|
||||||
let mut u_rem: timespec_t = timespec_t { sec: 0, nsec: 0 };
|
let mut u_rem: timespec_t = timespec_t { sec: 0, nsec: 0 };
|
||||||
match clockid {
|
match clockid {
|
||||||
ClockID::CLOCK_REALTIME
|
ClockId::CLOCK_REALTIME
|
||||||
| ClockID::CLOCK_MONOTONIC
|
| ClockId::CLOCK_MONOTONIC
|
||||||
| ClockID::CLOCK_BOOTTIME
|
| ClockId::CLOCK_BOOTTIME
|
||||||
| ClockID::CLOCK_PROCESS_CPUTIME_ID => {}
|
| ClockId::CLOCK_PROCESS_CPUTIME_ID => {}
|
||||||
ClockID::CLOCK_THREAD_CPUTIME_ID => {
|
ClockId::CLOCK_THREAD_CPUTIME_ID => {
|
||||||
return_errno!(EINVAL, "CLOCK_THREAD_CPUTIME_ID is not a permitted value");
|
return_errno!(EINVAL, "CLOCK_THREAD_CPUTIME_ID is not a permitted value");
|
||||||
}
|
}
|
||||||
_ => {
|
_ => {
|
||||||
@ -269,7 +265,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_REALTIME clock. However, Linux measures the time using
|
||||||
// the CLOCK_MONOTONIC clock.
|
// the CLOCK_MONOTONIC clock.
|
||||||
// Here we follow the POSIX.1
|
// 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);
|
return do_clock_nanosleep(clock_id, 0, req, rem);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -1,16 +1,16 @@
|
|||||||
use super::{do_clock_gettime, ClockID};
|
use super::{do_clock_gettime, ClockId};
|
||||||
use std::time::Duration;
|
use std::time::Duration;
|
||||||
|
|
||||||
lazy_static! {
|
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()
|
.unwrap()
|
||||||
.as_duration();
|
.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()
|
.unwrap()
|
||||||
.as_duration();
|
.as_duration();
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn init() {
|
pub(super) fn init() {
|
||||||
*BOOT_TIME_STAMP;
|
*BOOT_TIME_STAMP;
|
||||||
*BOOT_TIME_STAMP_SINCE_EPOCH;
|
*BOOT_TIME_STAMP_SINCE_EPOCH;
|
||||||
}
|
}
|
||||||
@ -20,7 +20,7 @@ pub fn boot_time_since_epoch() -> Duration {
|
|||||||
}
|
}
|
||||||
|
|
||||||
pub fn get() -> Option<Duration> {
|
pub fn get() -> Option<Duration> {
|
||||||
do_clock_gettime(ClockID::CLOCK_MONOTONIC_RAW)
|
do_clock_gettime(ClockId::CLOCK_MONOTONIC_RAW)
|
||||||
.unwrap()
|
.unwrap()
|
||||||
.as_duration()
|
.as_duration()
|
||||||
.checked_sub(*BOOT_TIME_STAMP)
|
.checked_sub(*BOOT_TIME_STAMP)
|
||||||
|
81
src/libos/src/util/kernel_alloc.rs
Normal file
81
src/libos/src/util/kernel_alloc.rs
Normal file
@ -0,0 +1,81 @@
|
|||||||
|
use std::alloc::{GlobalAlloc, Layout, System};
|
||||||
|
use std::sync::atomic::{AtomicUsize, Ordering};
|
||||||
|
|
||||||
|
// This file provides "KernelAlloc", a wrapper for sgx_std "System" allocator, is used as
|
||||||
|
// the global allocator for Occlum kernel. Currently, this can provides the ability to
|
||||||
|
// monitor the kernel heap usage.
|
||||||
|
|
||||||
|
pub struct KernelAlloc {
|
||||||
|
size: AtomicUsize,
|
||||||
|
}
|
||||||
|
|
||||||
|
impl KernelAlloc {
|
||||||
|
pub fn get_kernel_mem_size() -> Option<usize> {
|
||||||
|
cfg_if! {
|
||||||
|
if #[cfg(feature = "kernel_heap_monitor")] {
|
||||||
|
Some(ALLOC.size.load(Ordering::Relaxed))
|
||||||
|
} else {
|
||||||
|
None
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn get_kernel_heap_config() -> usize {
|
||||||
|
std::enclave::get_heap_size()
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn get_kernel_heap_peak_used() -> usize {
|
||||||
|
sgx_trts::enclave::rsgx_get_peak_heap_used()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
unsafe impl GlobalAlloc for KernelAlloc {
|
||||||
|
#[inline]
|
||||||
|
unsafe fn alloc(&self, layout: Layout) -> *mut u8 {
|
||||||
|
let ptr = System.alloc(layout);
|
||||||
|
if !ptr.is_null() {
|
||||||
|
self.size.fetch_add(layout.size(), Ordering::Relaxed);
|
||||||
|
}
|
||||||
|
|
||||||
|
ptr
|
||||||
|
}
|
||||||
|
|
||||||
|
#[inline]
|
||||||
|
unsafe fn alloc_zeroed(&self, layout: Layout) -> *mut u8 {
|
||||||
|
let ptr = System.alloc_zeroed(layout);
|
||||||
|
if !ptr.is_null() {
|
||||||
|
self.size.fetch_add(layout.size(), Ordering::Relaxed);
|
||||||
|
}
|
||||||
|
|
||||||
|
ptr
|
||||||
|
}
|
||||||
|
|
||||||
|
#[inline]
|
||||||
|
unsafe fn dealloc(&self, ptr: *mut u8, layout: Layout) {
|
||||||
|
System.dealloc(ptr, layout);
|
||||||
|
self.size.fetch_sub(layout.size(), Ordering::Relaxed);
|
||||||
|
}
|
||||||
|
|
||||||
|
#[inline]
|
||||||
|
unsafe fn realloc(&self, ptr: *mut u8, layout: Layout, new_size: usize) -> *mut u8 {
|
||||||
|
let ptr = System.realloc(ptr, layout, new_size);
|
||||||
|
if !ptr.is_null() {
|
||||||
|
let old_size = layout.size();
|
||||||
|
if new_size > old_size {
|
||||||
|
// grow
|
||||||
|
self.size.fetch_add(new_size - old_size, Ordering::Relaxed);
|
||||||
|
} else if new_size < old_size {
|
||||||
|
// shrink
|
||||||
|
self.size.fetch_sub(old_size - new_size, Ordering::Relaxed);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
ptr
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
#[cfg(feature = "kernel_heap_monitor")]
|
||||||
|
#[global_allocator]
|
||||||
|
static ALLOC: KernelAlloc = KernelAlloc {
|
||||||
|
size: AtomicUsize::new(0),
|
||||||
|
};
|
@ -3,6 +3,7 @@ use super::*;
|
|||||||
pub mod dirty;
|
pub mod dirty;
|
||||||
pub mod host_file_util;
|
pub mod host_file_util;
|
||||||
pub mod hosts_parser_util;
|
pub mod hosts_parser_util;
|
||||||
|
pub mod kernel_alloc;
|
||||||
pub mod log;
|
pub mod log;
|
||||||
pub mod mem_util;
|
pub mod mem_util;
|
||||||
pub mod mpx_util;
|
pub mod mpx_util;
|
||||||
|
@ -21,6 +21,8 @@ C_SRCS := $(sort $(wildcard src/*.c src/*/*.c))
|
|||||||
CXX_SRCS := $(sort $(wildcard src/*.cpp src/*/*.cpp))
|
CXX_SRCS := $(sort $(wildcard src/*.cpp src/*/*.cpp))
|
||||||
C_OBJS := $(addprefix $(OBJ_DIR)/pal/,$(C_SRCS:.c=.o))
|
C_OBJS := $(addprefix $(OBJ_DIR)/pal/,$(C_SRCS:.c=.o))
|
||||||
CXX_OBJS := $(addprefix $(OBJ_DIR)/pal/,$(CXX_SRCS:.cpp=.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
|
# Object files for simulation mode are stored in pal/src_sim
|
||||||
ifeq ($(SGX_MODE), SIM)
|
ifeq ($(SGX_MODE), SIM)
|
||||||
@ -52,7 +54,7 @@ LINK_FLAGS += -lsgx_quote_ex_sim
|
|||||||
endif
|
endif
|
||||||
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
|
.PHONY: all format format-check clean
|
||||||
|
|
||||||
@ -61,7 +63,7 @@ all: $(ALL_BUILD_SUBDIRS) $(LIBOCCLUM_PAL_SO_REAL)
|
|||||||
$(ALL_BUILD_SUBDIRS):
|
$(ALL_BUILD_SUBDIRS):
|
||||||
@mkdir -p $@
|
@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)
|
@$(CXX) $^ -o $@ $(LINK_FLAGS) -Wl,-soname=$(LIBOCCLUM_PAL_SONAME)
|
||||||
@# Create symbolic files because occlum run and exec will need it when linking.
|
@# 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)) && \
|
@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) && \
|
@cd $(OBJ_DIR)/pal/$(SRC_OBJ) && \
|
||||||
$(SGX_EDGER8R) $(SGX_EDGER8R_MODE) --untrusted $(CUR_DIR)/../Enclave.edl \
|
$(SGX_EDGER8R) $(SGX_EDGER8R_MODE) --untrusted $(CUR_DIR)/../Enclave.edl \
|
||||||
--search-path $(SGX_SDK)/include \
|
--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 <= $@"
|
@echo "GEN <= $@"
|
||||||
|
|
||||||
$(OBJ_DIR)/pal/$(SRC_OBJ)/%.o: src/%.c
|
$(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 $@
|
@$(CXX) $(CXX_FLAGS) -c $< -o $@
|
||||||
@echo "CXX <= $@"
|
@echo "CXX <= $@"
|
||||||
|
|
||||||
|
$(VDSO_OBJS): $(VDSO_SRCS)
|
||||||
|
@$(CC) $(C_FLAGS) -c $< -o $@
|
||||||
|
@echo "CC <= $@"
|
||||||
|
|
||||||
$(LIBSGX_USTDC_A):
|
$(LIBSGX_USTDC_A):
|
||||||
@$(MAKE) --no-print-directory -C $(RUST_SGX_SDK_DIR)/sgx_ustdc/ > /dev/null
|
@$(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)
|
@cp $(RUST_SGX_SDK_DIR)/sgx_ustdc/libsgx_ustdc.a $(LIBSGX_USTDC_A)
|
||||||
|
@ -3,10 +3,10 @@
|
|||||||
#ifndef _OCCLUM_VERSION_H_
|
#ifndef _OCCLUM_VERSION_H_
|
||||||
#define _OCCLUM_VERSION_H_
|
#define _OCCLUM_VERSION_H_
|
||||||
|
|
||||||
// Version = 0.30.0
|
// Version = 0.30.1
|
||||||
#define OCCLUM_MAJOR_VERSION 0
|
#define OCCLUM_MAJOR_VERSION 0
|
||||||
#define OCCLUM_MINOR_VERSION 30
|
#define OCCLUM_MINOR_VERSION 30
|
||||||
#define OCCLUM_PATCH_VERSION 0
|
#define OCCLUM_PATCH_VERSION 1
|
||||||
|
|
||||||
#define STRINGIZE_PRE(X) #X
|
#define STRINGIZE_PRE(X) #X
|
||||||
#define STRINGIZE(X) STRINGIZE_PRE(X)
|
#define STRINGIZE(X) STRINGIZE_PRE(X)
|
||||||
|
@ -4,18 +4,6 @@
|
|||||||
#include <sys/prctl.h>
|
#include <sys/prctl.h>
|
||||||
#include "ocalls.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,
|
int occlum_ocall_clock_nanosleep(clockid_t clockid, int flags, const struct timespec *req,
|
||||||
struct timespec *rem) {
|
struct timespec *rem) {
|
||||||
return clock_nanosleep(clockid, flags, req, rem);
|
return clock_nanosleep(clockid, flags, req, rem);
|
||||||
|
@ -2,6 +2,7 @@ MAIN_MAKEFILE := $(firstword $(MAKEFILE_LIST))
|
|||||||
INCLUDE_MAKEFILE := $(lastword $(MAKEFILE_LIST))
|
INCLUDE_MAKEFILE := $(lastword $(MAKEFILE_LIST))
|
||||||
CUR_DIR := $(shell dirname $(realpath $(MAIN_MAKEFILE)))
|
CUR_DIR := $(shell dirname $(realpath $(MAIN_MAKEFILE)))
|
||||||
PROJECT_DIR := $(realpath $(CUR_DIR)/../../)
|
PROJECT_DIR := $(realpath $(CUR_DIR)/../../)
|
||||||
|
CRATES_DIR := $(realpath $(CUR_DIR)/../libos/crates)
|
||||||
|
|
||||||
SHELL := /bin/bash
|
SHELL := /bin/bash
|
||||||
|
|
||||||
|
@ -2,9 +2,12 @@
|
|||||||
SRC_DIR=/tmp/glibc/glibc
|
SRC_DIR=/tmp/glibc/glibc
|
||||||
BUILD_DIR=/tmp/glibc/glibc_build
|
BUILD_DIR=/tmp/glibc/glibc_build
|
||||||
INSTALL_DIR=/opt/occlum/glibc
|
INSTALL_DIR=/opt/occlum/glibc
|
||||||
|
GLIBC_BRANCH=${1:-"occlum-glibc-2.31"}
|
||||||
|
|
||||||
# GCC 9/10 introduces many new checkings and will cause the build to fail.
|
# GCC 9/10 introduces many new checkings and will cause the build to fail.
|
||||||
if [ "$(gcc -dumpversion)" = "9" -o "$(gcc -dumpversion)" = "10" ]; then
|
if [ "$(gcc -dumpversion)" = "9" ] || \
|
||||||
|
[ "$(gcc -dumpversion)" = "10" ] || \
|
||||||
|
[ "$(gcc -dumpversion)" = "11" ]; then
|
||||||
EXTRA_CFLAGS=-fcommon
|
EXTRA_CFLAGS=-fcommon
|
||||||
EXTRA_CONFIG_OPTION="--disable-werror"
|
EXTRA_CONFIG_OPTION="--disable-werror"
|
||||||
fi
|
fi
|
||||||
@ -20,7 +23,7 @@ rm -rf ${INSTALL_DIR}
|
|||||||
mkdir -p ${SRC_DIR}
|
mkdir -p ${SRC_DIR}
|
||||||
cd ${SRC_DIR}
|
cd ${SRC_DIR}
|
||||||
# Download glibc
|
# Download glibc
|
||||||
git clone -b occlum-glibc-2.31 https://github.com/occlum/glibc .
|
git clone -b ${GLIBC_BRANCH} https://github.com/occlum/glibc .
|
||||||
|
|
||||||
mkdir -p ${BUILD_DIR}
|
mkdir -p ${BUILD_DIR}
|
||||||
cd ${BUILD_DIR}
|
cd ${BUILD_DIR}
|
||||||
|
Loading…
Reference in New Issue
Block a user