Implement libc-WASI for Linux SGX platform and update documents (#343)

This commit is contained in:
Wenyong Huang 2020-08-10 15:12:26 +08:00 committed by GitHub
parent 8edf1e152f
commit 1b6ddb37d0
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
55 changed files with 3692 additions and 516 deletions

View File

@ -13,8 +13,6 @@ WebAssembly Micro Runtime (WAMR) is a standalone WebAssembly (WASM) runtime with
- The **dynamic management** of the WASM applications
iwasm VM core
=========================
@ -53,7 +51,8 @@ The iwasm supports the following architectures:
Following platforms are supported. Refer to [WAMR porting guide](./doc/port_wamr.md) for how to port WAMR to a new platform.
- [Linux](./doc/build_wamr.md#linux), [Zephyr](./doc/build_wamr.md#zephyr), [MacOS](./doc/build_wamr.md#macos), [VxWorks](./doc/build_wamr.md#vxworks), [AliOS-Things](./doc/build_wamr.md#alios-things), [Intel Software Guard Extention (Linux)](./doc/build_wamr.md#linux-sgx-intel-software-guard-extention), [Android](./doc/build_wamr.md#android)
- [Linux](./doc/build_wamr.md#linux), [Linux SGX (Intel Software Guard Extension)](./doc/linux_sgx.md), [MacOS](./doc/build_wamr.md#macos), [Android](./doc/build_wamr.md#android)
- [Zephyr](./doc/build_wamr.md#zephyr), [AliOS-Things](./doc/build_wamr.md#alios-things), [VxWorks](./doc/build_wamr.md#vxworks)
### Build iwasm VM core (mini product)
@ -84,8 +83,6 @@ The WAMR has offered a comprehensive framework for programming WASM applications
Browse the folder [core/app-framework](./core/app-framework) for how to extend the application framework.
# Remote application management
The WAMR application manager supports [remote application management](./core/app-mgr) from the host environment or the cloud through any physical communications such as TCP, UPD, UART, BLE, etc. Its modular design makes it able to support application management for different managed runtimes.
@ -109,11 +106,14 @@ Samples
The WAMR [samples](./samples) integrate the iwasm VM core, application manager and selected application framework components.
- [**Basic**](./samples/basic): Demonstrating how host runtime calls WASM function as well as WASM function calls native function.
- **[Simple](./samples/simple/README.md)**: The runtime is integrated with most of the WAMR APP libraries, and a few WASM applications are provided for testing the WAMR APP API set. It uses **built-in libc** and executes apps in **interpreter** mode by default.
- **[littlevgl](./samples/littlevgl/README.md)**: Demonstrating the graphic user interface application usage on WAMR. The whole [LittlevGL](https://github.com/lvgl/) 2D user graphic library and the UI application is built into WASM application. It uses **WASI libc** and executes apps in **AoT mode** by default.
- **[gui](./samples/gui/README.md)**: Moved the [LittlevGL](https://github.com/lvgl/) library into the runtime and defined a WASM application interface by wrapping the littlevgl API. It uses **WASI libc** and executes apps in **interpreter** mode by default.
- **[wasm-c-api](./samples/wasm-c-api/README.md)**: they are samples from [wasm-c-api proposal](https://github.com/WebAssembly/wasm-c-api) and show supported APIs.
- [**basic**](./samples/basic): Demonstrating how to use runtime exposed API's to call WASM functions, how to register native functions and call them, and how to call WASM function from native function.
- **[simple](./samples/simple/README.md)**: The runtime is integrated with most of the WAMR APP libraries, and a few WASM applications are provided for testing the WAMR APP API set. It uses **built-in libc** and executes apps in **interpreter** mode by default.
- **[littlevgl](./samples/littlevgl/README.md)**: Demonstrating the graphic user interface application usage on WAMR. The whole [LittleVGL](https://github.com/lvgl/) 2D user graphic library and the UI application are built into WASM application. It uses **WASI libc** and executes apps in **AoT mode** by default.
- **[gui](./samples/gui/README.md)**: Move the [LittleVGL](https://github.com/lvgl/) library into the runtime and define a WASM application interface by wrapping the littlevgl API. It uses **WASI libc** and executes apps in **interpreter** mode by default.
- **[multi-thread](./samples/multi-thread/)**: Demonstrating how to run wasm application which creates multiple threads to execute wasm functions concurrently, and uses mutex/cond by calling pthread related API's.
- **[spawn-thread](./samples/spawn-thread)**: Demonstrating how to execute wasm functions of the same wasm application concurrently, in threads created by host embedder or runtime, but not the wasm application itself.
- **[multi-module](./samples/multi-module)**: Demonstrating the [multiple modules as dependencies](./doc/multi_module.md) feature which implements the [load-time dynamic linking](https://webassembly.org/docs/dynamic-linking/).
- **[wasm-c-api](./samples/wasm-c-api/README.md)**: Demonstrating how to run some samples from [wasm-c-api proposal](https://github.com/WebAssembly/wasm-c-api) and showing the supported API's.
Releases and acknowledgments

View File

@ -972,9 +972,11 @@ load_object_data_sections(const uint8 **p_buf, const uint8 *buf_end,
return false;
}
#if defined(BUILD_TARGET_X86_64) || defined(BUILD_TARGET_AMD_64)
#ifndef BH_PLATFORM_LINUX_SGX
/* address must be in the first 2 Gigabytes of
the process address space */
bh_assert((uintptr_t)data_sections[i].data < INT32_MAX);
#endif
#endif
read_byte_array(buf, buf_end,
@ -1799,9 +1801,11 @@ create_sections(const uint8 *buf, uint32 size,
goto fail;
}
#if defined(BUILD_TARGET_X86_64) || defined(BUILD_TARGET_AMD_64)
#ifndef BH_PLATFORM_LINUX_SGX
/* address must be in the first 2 Gigabytes of
the process address space */
bh_assert((uintptr_t)aot_text < INT32_MAX);
#endif
#endif
bh_memcpy_s(aot_text, (uint32)total_size,
section->section_body, (uint32)section_size);

View File

@ -76,7 +76,9 @@ static inline void
generic_vec_init_data(Vector *out, size_t num_of_elems, size_t size_of_elem)
{
if (!bh_vector_init(out, num_of_elems, size_of_elem)) {
memset(out, 0, sizeof(Vector));
out->data = NULL;
out->max_elems = 0;
out->num_elems = 0;
}
else {
memset(out->data, 0, num_of_elems * size_of_elem);

View File

@ -1279,6 +1279,8 @@ wasm_runtime_init_wasi(WASMModuleInstanceCommon *module_inst,
struct fd_table *curfds;
struct fd_prestats *prestats;
struct argv_environ_values *argv_environ;
bool fd_table_inited = false, fd_prestats_inited = false;
bool argv_environ_inited = false;
int32 offset_argv_offsets = 0, offset_env_offsets = 0;
int32 offset_argv_buf = 0, offset_env_buf = 0;
int32 offset_curfds = 0;
@ -1373,9 +1375,26 @@ wasm_runtime_init_wasi(WASMModuleInstanceCommon *module_inst,
wasi_ctx->curfds_offset = offset_curfds;
wasi_ctx->prestats_offset = offset_prestats;
wasi_ctx->argv_environ_offset = offset_argv_environ;
wasi_ctx->argv_buf_offset = offset_argv_buf;
wasi_ctx->argv_offsets_offset = offset_argv_offsets;
wasi_ctx->env_buf_offset = offset_env_buf;
wasi_ctx->env_offsets_offset = offset_env_offsets;
fd_table_init(curfds);
fd_prestats_init(prestats);
if (!fd_table_init(curfds)) {
set_error_buf(error_buf, error_buf_size,
"Init wasi environment failed: "
"init fd table failed.");
goto fail;
}
fd_table_inited = true;
if (!fd_prestats_init(prestats)) {
set_error_buf(error_buf, error_buf_size,
"Init wasi environment failed: "
"init fd prestats failed.");
goto fail;
}
fd_prestats_inited = true;
if (!argv_environ_init(argv_environ,
argv_offsets, argc,
@ -1387,6 +1406,7 @@ wasm_runtime_init_wasi(WASMModuleInstanceCommon *module_inst,
"init argument environment failed.");
goto fail;
}
argv_environ_inited = true;
/* Prepopulate curfds with stdin, stdout, and stderr file descriptors. */
if (!fd_table_insert_existing(curfds, 0, 0)
@ -1424,6 +1444,12 @@ wasm_runtime_init_wasi(WASMModuleInstanceCommon *module_inst,
return true;
fail:
if (argv_environ_inited)
argv_environ_destroy(argv_environ);
if (fd_prestats_inited)
fd_prestats_destroy(prestats);
if (fd_table_inited)
fd_table_destroy(curfds);
if (offset_curfds != 0)
wasm_runtime_module_free(module_inst, offset_curfds);
if (offset_prestats != 0)
@ -1537,6 +1563,14 @@ wasm_runtime_destroy_wasi(WASMModuleInstanceCommon *module_inst)
fd_prestats_destroy(prestats);
wasm_runtime_module_free(module_inst, wasi_ctx->prestats_offset);
}
if (wasi_ctx->argv_buf_offset)
wasm_runtime_module_free(module_inst, wasi_ctx->argv_buf_offset);
if (wasi_ctx->argv_offsets_offset)
wasm_runtime_module_free(module_inst, wasi_ctx->argv_offsets_offset);
if (wasi_ctx->env_buf_offset)
wasm_runtime_module_free(module_inst, wasi_ctx->env_buf_offset);
if (wasi_ctx->env_offsets_offset)
wasm_runtime_module_free(module_inst, wasi_ctx->env_offsets_offset);
wasm_runtime_free(wasi_ctx);
}
}

View File

@ -52,6 +52,10 @@ typedef struct WASIContext {
int32 curfds_offset;
int32 prestats_offset;
int32 argv_environ_offset;
int32 argv_buf_offset;
int32 argv_offsets_offset;
int32 env_buf_offset;
int32 env_offsets_offset;
} WASIContext;
#endif

View File

@ -4,8 +4,7 @@
*/
#include "libc_wasi_wrapper.h"
#include "bh_common.h"
#include "bh_log.h"
#include "bh_platform.h"
#include "wasm_export.h"
void

View File

@ -832,9 +832,15 @@ __wasi_errno_t wasmtime_ssp_poll_oneoff(
size_t *nevents
) WASMTIME_SSP_SYSCALL_NAME(poll_oneoff) __attribute__((__warn_unused_result__));
#if 0
/**
* We throw exception in libc-wasi wrapper function wasi_proc_exit()
* but not call this function.
*/
_Noreturn void wasmtime_ssp_proc_exit(
__wasi_exitcode_t rval
) WASMTIME_SSP_SYSCALL_NAME(proc_exit);
#endif
__wasi_errno_t wasmtime_ssp_proc_raise(
__wasi_signal_t sig

View File

@ -14,12 +14,6 @@
#include "ssp_config.h"
#include <assert.h>
#include <errno.h>
#include <pthread.h>
#include <stdint.h>
#include <time.h>
#ifndef __has_extension
#define __has_extension(x) 0
#endif
@ -30,7 +24,7 @@
#define LOCK_ANNOTATE(x)
#endif
// Lock annotation macros.
/* Lock annotation macros. */
#define LOCKABLE LOCK_ANNOTATE(lockable)
@ -50,166 +44,216 @@
#define NO_LOCK_ANALYSIS LOCK_ANNOTATE(no_thread_safety_analysis)
// Mutex that uses the lock annotations.
/* Mutex that uses the lock annotations. */
struct LOCKABLE mutex {
pthread_mutex_t object;
pthread_mutex_t object;
};
#define MUTEX_INITIALIZER \
{ PTHREAD_MUTEX_INITIALIZER }
static inline void mutex_init(struct mutex *lock) REQUIRES_UNLOCKED(*lock) {
pthread_mutex_init(&lock->object, NULL);
static inline bool
mutex_init(struct mutex *lock) REQUIRES_UNLOCKED(*lock)
{
return pthread_mutex_init(&lock->object, NULL) == 0 ? true : false;
}
static inline void mutex_destroy(struct mutex *lock) REQUIRES_UNLOCKED(*lock) {
pthread_mutex_destroy(&lock->object);
static inline void
mutex_destroy(struct mutex *lock) REQUIRES_UNLOCKED(*lock)
{
pthread_mutex_destroy(&lock->object);
}
static inline void mutex_lock(struct mutex *lock)
LOCKS_EXCLUSIVE(*lock) NO_LOCK_ANALYSIS {
pthread_mutex_lock(&lock->object);
static inline void
mutex_lock(struct mutex *lock) LOCKS_EXCLUSIVE(*lock) NO_LOCK_ANALYSIS
{
pthread_mutex_lock(&lock->object);
}
static inline void mutex_unlock(struct mutex *lock)
UNLOCKS(*lock) NO_LOCK_ANALYSIS {
pthread_mutex_unlock(&lock->object);
static inline void
mutex_unlock(struct mutex *lock) UNLOCKS(*lock) NO_LOCK_ANALYSIS
{
pthread_mutex_unlock(&lock->object);
}
// Read-write lock that uses the lock annotations.
/* Read-write lock that uses the lock annotations. */
struct LOCKABLE rwlock {
pthread_rwlock_t object;
pthread_rwlock_t object;
};
static inline void rwlock_init(struct rwlock *lock) REQUIRES_UNLOCKED(*lock) {
pthread_rwlock_init(&lock->object, NULL);
static inline bool
rwlock_init(struct rwlock *lock) REQUIRES_UNLOCKED(*lock)
{
return pthread_rwlock_init(&lock->object, NULL) == 0 ? true : false;
}
static inline void rwlock_rdlock(struct rwlock *lock)
LOCKS_SHARED(*lock) NO_LOCK_ANALYSIS {
pthread_rwlock_rdlock(&lock->object);
static inline void
rwlock_rdlock(struct rwlock *lock) LOCKS_SHARED(*lock) NO_LOCK_ANALYSIS
{
pthread_rwlock_rdlock(&lock->object);
}
static inline void rwlock_wrlock(struct rwlock *lock)
LOCKS_EXCLUSIVE(*lock) NO_LOCK_ANALYSIS {
pthread_rwlock_wrlock(&lock->object);
static inline void
rwlock_wrlock(struct rwlock *lock) LOCKS_EXCLUSIVE(*lock) NO_LOCK_ANALYSIS
{
pthread_rwlock_wrlock(&lock->object);
}
static inline void rwlock_unlock(struct rwlock *lock)
UNLOCKS(*lock) NO_LOCK_ANALYSIS {
pthread_rwlock_unlock(&lock->object);
static inline void
rwlock_unlock(struct rwlock *lock) UNLOCKS(*lock) NO_LOCK_ANALYSIS
{
pthread_rwlock_unlock(&lock->object);
}
// Condition variable that uses the lock annotations.
static inline void
rwlock_destroy(struct rwlock *lock) UNLOCKS(*lock) NO_LOCK_ANALYSIS
{
pthread_rwlock_destroy(&lock->object);
}
/* Condition variable that uses the lock annotations. */
struct LOCKABLE cond {
pthread_cond_t object;
pthread_cond_t object;
#if !CONFIG_HAS_PTHREAD_CONDATTR_SETCLOCK || \
!CONFIG_HAS_PTHREAD_COND_TIMEDWAIT_RELATIVE_NP
clockid_t clock;
clockid_t clock;
#endif
};
static inline void cond_init_monotonic(struct cond *cond) {
static inline bool
cond_init_monotonic(struct cond *cond) {
bool ret = false;
#if CONFIG_HAS_PTHREAD_CONDATTR_SETCLOCK
pthread_condattr_t attr;
pthread_condattr_init(&attr);
pthread_condattr_setclock(&attr, CLOCK_MONOTONIC);
pthread_cond_init(&cond->object, &attr);
pthread_condattr_destroy(&attr);
pthread_condattr_t attr;
if (pthread_condattr_init(&attr) != 0)
return false;
if (pthread_condattr_setclock(&attr, CLOCK_MONOTONIC) != 0)
goto fail;
if (pthread_cond_init(&cond->object, &attr) != 0)
goto fail;
ret = true;
fail:
pthread_condattr_destroy(&attr);
#else
pthread_cond_init(&cond->object, NULL);
if (pthread_cond_init(&cond->object, NULL) != 0)
return false;
ret = true;
#endif
#if !CONFIG_HAS_PTHREAD_CONDATTR_SETCLOCK || \
!CONFIG_HAS_PTHREAD_COND_TIMEDWAIT_RELATIVE_NP
cond->clock = CLOCK_MONOTONIC;
cond->clock = CLOCK_MONOTONIC;
#endif
return ret;
}
static inline void cond_init_realtime(struct cond *cond) {
pthread_cond_init(&cond->object, NULL);
static inline bool
cond_init_realtime(struct cond *cond)
{
if (pthread_cond_init(&cond->object, NULL) != 0)
return false;
#if !CONFIG_HAS_PTHREAD_CONDATTR_SETCLOCK || \
!CONFIG_HAS_PTHREAD_COND_TIMEDWAIT_RELATIVE_NP
cond->clock = CLOCK_REALTIME;
cond->clock = CLOCK_REALTIME;
#endif
return true;
}
static inline void cond_destroy(struct cond *cond) {
pthread_cond_destroy(&cond->object);
static inline void
cond_destroy(struct cond *cond) {
pthread_cond_destroy(&cond->object);
}
static inline void cond_signal(struct cond *cond) {
pthread_cond_signal(&cond->object);
static inline void
cond_signal(struct cond *cond) {
pthread_cond_signal(&cond->object);
}
static inline bool cond_timedwait(struct cond *cond, struct mutex *lock,
uint64_t timeout, bool abstime)
REQUIRES_EXCLUSIVE(*lock) NO_LOCK_ANALYSIS {
struct timespec ts = {
.tv_sec = (time_t)(timeout / 1000000000),
.tv_nsec = (long)(timeout % 1000000000),
};
#if !CONFIG_HAS_CLOCK_NANOSLEEP
static inline bool
cond_timedwait(struct cond *cond, struct mutex *lock,
uint64_t timeout, bool abstime)
REQUIRES_EXCLUSIVE(*lock) NO_LOCK_ANALYSIS
{
int ret;
struct timespec ts = {
.tv_sec = (time_t)(timeout / 1000000000),
.tv_nsec = (long)(timeout % 1000000000),
};
if (abstime) {
if (abstime) {
#if !CONFIG_HAS_PTHREAD_CONDATTR_SETCLOCK
// No native support for sleeping on monotonic clocks. Convert the
// timeout to a relative value and then to an absolute value for the
// realtime clock.
if (cond->clock != CLOCK_REALTIME) {
struct timespec ts_monotonic;
clock_gettime(cond->clock, &ts_monotonic);
ts.tv_sec -= ts_monotonic.tv_sec;
ts.tv_nsec -= ts_monotonic.tv_nsec;
if (ts.tv_nsec < 0) {
ts.tv_nsec += 1000000000;
--ts.tv_sec;
}
/**
* No native support for sleeping on monotonic clocks. Convert the
* timeout to a relative value and then to an absolute value for the
* realtime clock.
*/
if (cond->clock != CLOCK_REALTIME) {
struct timespec ts_monotonic;
struct timespec ts_realtime;
struct timespec ts_realtime;
clock_gettime(CLOCK_REALTIME, &ts_realtime);
ts.tv_sec += ts_realtime.tv_sec;
ts.tv_nsec += ts_realtime.tv_nsec;
if (ts.tv_nsec >= 1000000000) {
ts.tv_nsec -= 1000000000;
++ts.tv_sec;
}
}
clock_gettime(cond->clock, &ts_monotonic);
ts.tv_sec -= ts_monotonic.tv_sec;
ts.tv_nsec -= ts_monotonic.tv_nsec;
if (ts.tv_nsec < 0) {
ts.tv_nsec += 1000000000;
--ts.tv_sec;
}
clock_gettime(CLOCK_REALTIME, &ts_realtime);
ts.tv_sec += ts_realtime.tv_sec;
ts.tv_nsec += ts_realtime.tv_nsec;
if (ts.tv_nsec >= 1000000000) {
ts.tv_nsec -= 1000000000;
++ts.tv_sec;
}
}
#endif
} else {
}
else {
#if CONFIG_HAS_PTHREAD_COND_TIMEDWAIT_RELATIVE_NP
// Implementation supports relative timeouts.
int ret =
pthread_cond_timedwait_relative_np(&cond->object, &lock->object, &ts);
assert((ret == 0 || ret == ETIMEDOUT) &&
"pthread_cond_timedwait_relative_np() failed");
return ret == ETIMEDOUT;
/* Implementation supports relative timeouts. */
ret = pthread_cond_timedwait_relative_np(&cond->object,
&lock->object, &ts);
bh_assert((ret == 0 || ret == ETIMEDOUT)
&& "pthread_cond_timedwait_relative_np() failed");
return ret == ETIMEDOUT;
#else
// Convert to absolute timeout.
struct timespec ts_now;
/* Convert to absolute timeout. */
struct timespec ts_now;
#if CONFIG_HAS_PTHREAD_CONDATTR_SETCLOCK
clock_gettime(cond->clock, &ts_now);
clock_gettime(cond->clock, &ts_now);
#else
clock_gettime(CLOCK_REALTIME, &ts_now);
clock_gettime(CLOCK_REALTIME, &ts_now);
#endif
ts.tv_sec += ts_now.tv_sec;
ts.tv_nsec += ts_now.tv_nsec;
if (ts.tv_nsec >= 1000000000) {
ts.tv_nsec -= 1000000000;
++ts.tv_sec;
}
#endif
ts.tv_sec += ts_now.tv_sec;
ts.tv_nsec += ts_now.tv_nsec;
if (ts.tv_nsec >= 1000000000) {
ts.tv_nsec -= 1000000000;
++ts.tv_sec;
}
#endif
}
int ret = pthread_cond_timedwait(&cond->object, &lock->object, &ts);
assert((ret == 0 || ret == ETIMEDOUT) && "pthread_cond_timedwait() failed");
return ret == ETIMEDOUT;
ret = pthread_cond_timedwait(&cond->object, &lock->object, &ts);
bh_assert((ret == 0 || ret == ETIMEDOUT)
&& "pthread_cond_timedwait() failed");
return ret == ETIMEDOUT;
}
#endif
static inline void cond_wait(struct cond *cond, struct mutex *lock)
REQUIRES_EXCLUSIVE(*lock) NO_LOCK_ANALYSIS {
pthread_cond_wait(&cond->object, &lock->object);
static inline void
cond_wait(struct cond *cond, struct mutex *lock)
REQUIRES_EXCLUSIVE(*lock) NO_LOCK_ANALYSIS
{
pthread_cond_wait(&cond->object, &lock->object);
}
#endif

View File

@ -12,8 +12,6 @@
#ifndef COMMON_LIMITS_H
#define COMMON_LIMITS_H
#include <limits.h>
#define NUMERIC_MIN(t) \
_Generic((t)0, char \
: CHAR_MIN, signed char \

View File

@ -10,34 +10,8 @@
// Copyright (c) 2016-2018 Nuxi, https://nuxi.nl/
#include "ssp_config.h"
#include <sys/types.h>
#include <sys/ioctl.h>
#include <sys/mman.h>
#include <sys/resource.h>
#include <sys/socket.h>
#include <sys/stat.h>
#include <sys/time.h>
#include <sys/uio.h>
#include <assert.h>
#include <dirent.h>
#include <errno.h>
#include <fcntl.h>
#include <poll.h>
#include <sched.h>
#include <signal.h>
#include <stdbool.h>
#include <stddef.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <time.h>
#include <unistd.h>
#include <wasmtime_ssp.h>
#include "bh_platform.h"
#include "wasmtime_ssp.h"
#include "locking.h"
#include "numeric_limits.h"
#include "posix.h"
@ -46,9 +20,6 @@
#include "rights.h"
#include "str.h"
#include "bh_common.h"
#include "bh_assert.h"
#if 0 /* TODO: -std=gnu99 causes compile error, comment them first */
// struct iovec must have the same layout as __wasi_iovec_t.
static_assert(offsetof(struct iovec, iov_base) ==
@ -252,16 +223,18 @@ struct fd_prestat {
const char *dir;
};
void fd_prestats_init(
bool fd_prestats_init(
struct fd_prestats *pt
) {
rwlock_init(&pt->lock);
if (!rwlock_init(&pt->lock))
return false;
pt->prestats = NULL;
pt->size = 0;
pt->used = 0;
#if defined(WASMTIME_SSP_STATIC_CURFDS)
prestats = pt;
#endif
return true;
}
// Grows the preopened resource table to a required lower bound and a
@ -359,16 +332,18 @@ struct fd_entry {
__wasi_rights_t rights_inheriting;
};
void fd_table_init(
bool fd_table_init(
struct fd_table *ft
) {
rwlock_init(&ft->lock);
if (!rwlock_init(&ft->lock))
return false;
ft->entries = NULL;
ft->size = 0;
ft->used = 0;
#if defined(WASMTIME_SSP_STATIC_CURFDS)
curfds = ft;
#endif
return true;
}
// Looks up a file descriptor table entry by number and required rights.
@ -598,17 +573,22 @@ bool fd_table_insert_existing(
) {
__wasi_filetype_t type;
__wasi_rights_t rights_base, rights_inheriting;
if (fd_determine_type_rights(out, &type, &rights_base, &rights_inheriting) !=
0)
struct fd_object *fo;
__wasi_errno_t error;
if (fd_determine_type_rights(out, &type, &rights_base,
&rights_inheriting) != 0)
return false;
struct fd_object *fo;
__wasi_errno_t error = fd_object_new(type, &fo);
error = fd_object_new(type, &fo);
if (error != 0)
return false;
fo->number = out;
if (type == __WASI_FILETYPE_DIRECTORY) {
mutex_init(&fo->directory.lock);
if (!mutex_init(&fo->directory.lock)) {
fd_object_release(fo);
return false;
}
fo->directory.handle = NULL;
}
@ -671,13 +651,17 @@ static __wasi_errno_t fd_table_insert_fd(
) REQUIRES_UNLOCKED(ft->lock) {
struct fd_object *fo;
__wasi_errno_t error = fd_object_new(type, &fo);
if (error != 0) {
close(in);
return error;
}
fo->number = in;
if (type == __WASI_FILETYPE_DIRECTORY) {
mutex_init(&fo->directory.lock);
if (!mutex_init(&fo->directory.lock)) {
fd_object_release(fo);
return -1;
}
fo->directory.handle = NULL;
}
return fd_table_insert(ft, fo, rights_base, rights_inheriting, out);
@ -2471,9 +2455,14 @@ __wasi_errno_t wasmtime_ssp_poll_oneoff(
// Sleeping to an absolute point in time can only be done
// by waiting on a condition variable.
struct mutex mutex;
mutex_init(&mutex);
struct cond cond;
cond_init_realtime(&cond);
if (!mutex_init(&mutex))
return -1;
if (!cond_init_realtime(&cond)) {
mutex_destroy(&mutex);
return -1;
}
mutex_lock(&mutex);
cond_timedwait(&cond, &mutex, in[0].u.clock.timeout, true);
mutex_unlock(&mutex);
@ -2649,11 +2638,17 @@ __wasi_errno_t wasmtime_ssp_poll_oneoff(
return error;
}
#if 0
/**
* We throw exception in libc-wasi wrapper function wasi_proc_exit()
* but not call this function.
*/
void wasmtime_ssp_proc_exit(
__wasi_exitcode_t rval
) {
_Exit((int32)rval);
}
#endif
__wasi_errno_t wasmtime_ssp_proc_raise(
__wasi_signal_t sig
@ -2952,6 +2947,7 @@ void fd_table_destroy(struct fd_table *ft)
fd_object_release(ft->entries[i].object);
}
}
rwlock_destroy(&ft->lock);
wasm_runtime_free(ft->entries);
}
}
@ -2964,6 +2960,7 @@ void fd_prestats_destroy(struct fd_prestats *pt)
wasm_runtime_free((void*)pt->prestats[i].dir);
}
}
rwlock_destroy(&pt->lock);
wasm_runtime_free(pt->prestats);
}
}

View File

@ -12,9 +12,7 @@
#ifndef POSIX_H
#define POSIX_H
#include <stdbool.h>
#include <stddef.h>
#include "bh_platform.h"
#include "locking.h"
struct fd_entry;
@ -46,9 +44,9 @@ struct argv_environ_values {
char *environ_buf;
};
void fd_table_init(struct fd_table *);
bool fd_table_init(struct fd_table *);
bool fd_table_insert_existing(struct fd_table *, __wasi_fd_t, int);
void fd_prestats_init(struct fd_prestats *);
bool fd_prestats_init(struct fd_prestats *);
bool fd_prestats_insert(struct fd_prestats *, const char *, __wasi_fd_t);
bool argv_environ_init(struct argv_environ_values *,
const size_t *argv_offsets, size_t argv_offsets_len,

View File

@ -12,8 +12,6 @@
#ifndef QUEUE_H
#define QUEUE_H
#include <stddef.h>
// LIST: Double-linked list.
#define LIST_HEAD(name, type) \

View File

@ -10,15 +10,7 @@
// Copyright (c) 2016 Nuxi, https://nuxi.nl/
#include "ssp_config.h"
#include <fcntl.h>
#include <pthread.h>
#include <stdio.h>
#include <stdlib.h>
#include <errno.h>
#include <string.h>
#include <unistd.h>
#include "bh_platform.h"
#include "random.h"
#if CONFIG_HAS_ARC4RANDOM_BUF
@ -29,7 +21,9 @@ void random_buf(void *buf, size_t len) {
#elif CONFIG_HAS_GETRANDOM
#ifndef BH_PLATFORM_LINUX_SGX
#include <sys/random.h>
#endif
void random_buf(void *buf, size_t len) {
for (;;) {
@ -37,7 +31,7 @@ void random_buf(void *buf, size_t len) {
if (x < 0) {
if (errno == EINTR)
continue;
fprintf(stderr, "getrandom failed: %s", strerror(errno));
os_printf("getrandom failed: %s", strerror(errno));
abort();
}
if ((size_t)x == len)
@ -54,7 +48,7 @@ static int urandom;
static void open_urandom(void) {
urandom = open("/dev/urandom", O_RDONLY);
if (urandom < 0) {
fputs("Failed to open /dev/urandom\n", stderr);
os_printf("Failed to open /dev/urandom\n");
abort();
}
}
@ -64,7 +58,7 @@ void random_buf(void *buf, size_t len) {
pthread_once(&open_once, open_urandom);
if ((size_t)read(urandom, buf, len) != len) {
fputs("Short read on /dev/urandom\n", stderr);
os_printf("Short read on /dev/urandom\n");
abort();
}
}

View File

@ -12,8 +12,6 @@
#ifndef RANDOM_H
#define RANDOM_H
#include <stdint.h>
void random_buf(void *, size_t);
uintmax_t random_uniform(uintmax_t);

View File

@ -12,36 +12,89 @@
#ifndef REFCOUNT_H
#define REFCOUNT_H
#include <assert.h>
#include <stdatomic.h>
#include <stdbool.h>
#include "bh_platform.h"
#include "locking.h"
// Simple reference counter.
struct LOCKABLE refcount {
atomic_uint count;
};
#define PRODUCES(...) LOCKS_SHARED(__VA_ARGS__) NO_LOCK_ANALYSIS
#define CONSUMES(...) UNLOCKS(__VA_ARGS__) NO_LOCK_ANALYSIS
// Initialize the reference counter.
static void refcount_init(struct refcount *r, unsigned int count) PRODUCES(*r) {
atomic_init(&r->count, count);
#if CONFIG_HAS_STD_ATOMIC != 0
#include <stdatomic.h>
/* Simple reference counter. */
struct LOCKABLE refcount {
atomic_uint count;
};
/* Initialize the reference counter. */
static inline void
refcount_init(struct refcount *r, unsigned int count) PRODUCES(*r)
{
atomic_init(&r->count, count);
}
// Increment the reference counter.
static inline void refcount_acquire(struct refcount *r) PRODUCES(*r) {
atomic_fetch_add_explicit(&r->count, 1, memory_order_acquire);
/* Increment the reference counter. */
static inline void
refcount_acquire(struct refcount *r) PRODUCES(*r)
{
atomic_fetch_add_explicit(&r->count, 1, memory_order_acquire);
}
// Decrement the reference counter, returning whether the reference
// dropped to zero.
static inline bool refcount_release(struct refcount *r) CONSUMES(*r) {
int old = (int)atomic_fetch_sub_explicit(&r->count, 1, memory_order_release);
assert(old != 0 && "Reference count becoming negative");
return old == 1;
/* Decrement the reference counter, returning whether the reference
dropped to zero. */
static inline bool
refcount_release(struct refcount *r) CONSUMES(*r)
{
int old = (int)atomic_fetch_sub_explicit(&r->count, 1,
memory_order_release);
bh_assert(old != 0 && "Reference count becoming negative");
return old == 1;
}
#endif
#elif defined(BH_PLATFORM_LINUX_SGX)
#include <sgx_spinlock.h>
/* Simple reference counter. */
struct refcount {
sgx_spinlock_t lock;
unsigned int count;
};
/* Initialize the reference counter. */
static inline void
refcount_init(struct refcount *r, unsigned int count)
{
r->lock = SGX_SPINLOCK_INITIALIZER;
r->count = count;
}
/* Increment the reference counter. */
static inline void
refcount_acquire(struct refcount *r)
{
sgx_spin_lock(&r->lock);
r->count++;
sgx_spin_unlock(&r->lock);
}
/* Decrement the reference counter, returning whether the reference
dropped to zero. */
static inline bool
refcount_release(struct refcount *r)
{
int old;
sgx_spin_lock(&r->lock);
old = (int)r->count;
r->count--;
sgx_spin_unlock(&r->lock);
bh_assert(old != 0 && "Reference count becoming negative");
return old == 1;
}
#else /* else of CONFIG_HAS_STD_ATOMIC */
#error "Reference counter isn't implemented"
#endif /* end of CONFIG_HAS_STD_ATOMIC */
#endif /* end of REFCOUNT_H */

View File

@ -73,7 +73,7 @@
#define CONFIG_HAS_PTHREAD_COND_TIMEDWAIT_RELATIVE_NP 0
#endif
#ifndef __APPLE__
#if !defined(__APPLE__) && !defined(BH_PLATFORM_LINUX_SGX)
#define CONFIG_HAS_PTHREAD_CONDATTR_SETCLOCK 1
#else
#define CONFIG_HAS_PTHREAD_CONDATTR_SETCLOCK 0
@ -97,4 +97,10 @@
#define CONFIG_TLS_USE_GSBASE 0
#endif
#if !defined(BH_PLATFORM_LINUX_SGX)
#define CONFIG_HAS_STD_ATOMIC 1
#else
#define CONFIG_HAS_STD_ATOMIC 0
#endif
#endif

View File

@ -10,24 +10,35 @@
// Copyright (c) 2016 Nuxi, https://nuxi.nl/
#include "ssp_config.h"
#include <errno.h>
#include <stdlib.h>
#include <string.h>
#include "bh_platform.h"
#include "str.h"
char *str_nullterminate(const char *s, size_t len) {
// Copy string.
char *ret = strndup(s, len);
if (ret == NULL)
return NULL;
static char *
bh_strndup(const char *s, size_t n)
{
size_t l = strnlen(s, n);
char *s1 = wasm_runtime_malloc((uint32)(l + 1));
// Ensure that it contains no null bytes within.
if (strlen(ret) != len) {
free(ret);
errno = EILSEQ;
return NULL;
}
if (!s1)
return NULL;
bh_memcpy_s(s1, (uint32)(l + 1), s, (uint32)l);
s1[l] = 0;
return s1;
}
char *
str_nullterminate(const char *s, size_t len) {
/* Copy string */
char *ret = bh_strndup(s, len);
if (ret == NULL)
return NULL;
/* Ensure that it contains no null bytes within */
if (strlen(ret) != len) {
wasm_runtime_free(ret);
errno = EILSEQ;
return NULL;
}
return ret;
}

View File

@ -630,6 +630,12 @@ gci_dump(gc_heap_t *heap)
os_printf("#%d %08x %x %x %d %c %d\n",
i, (int32)((char*) cur - (char*) heap->base_addr),
ut, p, mark, inuse, (int32)hmu_obj_size(size));
#if BH_ENABLE_GC_VERIFY != 0
if (inuse == 'V') {
gc_object_prefix_t *prefix = (gc_object_prefix_t *)(cur + 1);
os_printf("#%s:%d\n", prefix->file_name, prefix->line_no);
}
#endif
cur = (hmu_t*)((char *)cur + size);
i++;

View File

@ -84,8 +84,8 @@ hmu_verify(hmu_t *hmu)
if(!is_padding_ok)
{
printf("Invalid padding for object created at %s:%d",
(prefix->file_name ? prefix->file_name : ""), prefix->line_no);
os_printf("Invalid padding for object created at %s:%d",
(prefix->file_name ? prefix->file_name : ""), prefix->line_no);
}
bh_assert(is_padding_ok);
}

View File

@ -80,6 +80,17 @@ int
gc_destroy_with_pool(gc_handle_t handle)
{
gc_heap_t *heap = (gc_heap_t *) handle;
#if BH_ENABLE_GC_VERIFY != 0
hmu_t *cur = (hmu_t*)heap->base_addr;
hmu_t *end = (hmu_t*)((char*)heap->base_addr + heap->current_size);
if ((hmu_t*)((char *)cur + hmu_get_size(cur)) != end) {
os_printf("Memory leak detected:\n");
gci_dump(heap);
#if WASM_ENABLE_SPEC_TEST != 0
while (1);
#endif
}
#endif
os_mutex_destroy(&heap->lock);
memset(heap->base_addr, 0, heap->current_size);
memset(heap, 0, sizeof(gc_heap_t));

View File

@ -10,7 +10,6 @@
#include <stdbool.h>
#include <assert.h>
#include <time.h>
#include <sys/time.h>
#include <string.h>
#include <stdio.h>
#include <stdlib.h>
@ -18,15 +17,24 @@
#include <stdarg.h>
#include <ctype.h>
#include <pthread.h>
#include <signal.h>
#include <semaphore.h>
#include <limits.h>
#include <dirent.h>
#include <fcntl.h>
#include <unistd.h>
#include <poll.h>
#include <sched.h>
#include <errno.h>
#include <sys/socket.h>
#include <netinet/in.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <sys/mman.h>
#include <netinet/in.h>
#include <sys/time.h>
#include <sys/uio.h>
#include <sys/ioctl.h>
#include <sys/socket.h>
#include <sys/resource.h>
#include <android/log.h>
#ifdef __cplusplus
@ -53,7 +61,6 @@ typedef pthread_t korp_thread;
|| defined(BUILD_TARGET_AMD_64) \
|| defined(BUILD_TARGET_AARCH64)
#include <signal.h>
#include <setjmp.h>
#define OS_ENABLE_HW_BOUND_CHECK

View File

@ -10,8 +10,6 @@
#include <stdbool.h>
#include <assert.h>
#include <time.h>
#include <sys/time.h>
#include <sys/timeb.h>
#include <string.h>
#include <stdio.h>
#include <stdlib.h>
@ -19,15 +17,26 @@
#include <stdarg.h>
#include <ctype.h>
#include <pthread.h>
#include <signal.h>
#include <semaphore.h>
#include <limits.h>
#include <dirent.h>
#include <fcntl.h>
#include <unistd.h>
#include <poll.h>
#include <sched.h>
#include <errno.h>
#include <netinet/in.h>
#include <sys/types.h>
#include <sys/socket.h>
#include <sys/stat.h>
#include <sys/mman.h>
#include <netinet/in.h>
#include <sys/time.h>
#include <sys/timeb.h>
#include <sys/uio.h>
#include <sys/ioctl.h>
#include <sys/socket.h>
#include <sys/resource.h>
#ifdef __cplusplus
extern "C" {
@ -56,7 +65,6 @@ typedef pthread_t korp_thread;
|| defined(BUILD_TARGET_AMD_64) \
|| defined(BUILD_TARGET_AARCH64)
#include <signal.h>
#include <setjmp.h>
#define OS_ENABLE_HW_BOUND_CHECK

View File

@ -20,6 +20,14 @@
#include <limits.h>
#include <errno.h>
#include <sgx_thread.h>
#include <pthread.h>
#include "sgx_error.h"
#include "sgx_file.h"
#include "sgx_pthread.h"
#include "sgx_time.h"
#include "sgx_socket.h"
#include "sgx_signal.h"
#ifdef __cplusplus
extern "C" {
@ -37,14 +45,16 @@ extern "C" {
/* Default thread priority */
#define BH_THREAD_DEFAULT_PRIORITY 0
typedef sgx_thread_t korp_thread;
typedef sgx_thread_t korp_tid;
typedef sgx_thread_mutex_t korp_mutex;
typedef sgx_thread_cond_t korp_cond;
typedef pthread_t korp_thread;
typedef pthread_t korp_tid;
typedef pthread_mutex_t korp_mutex;
typedef pthread_cond_t korp_cond;
typedef void (*os_print_function_t)(const char* message);
void os_set_print_function(os_print_function_t pf);
char *strcpy(char *dest, const char *src);
#ifdef __cplusplus
}
#endif

View File

@ -0,0 +1,832 @@
/*
* Copyright (C) 2019 Intel Corporation. All rights reserved.
* SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
*/
#include "platform_api_vmcore.h"
#include "sgx_error.h"
#include "sgx_file.h"
#define TRACE_FUNC() os_printf("undefined %s\n", __FUNCTION__)
#define TRACE_OCALL_FAIL() os_printf("ocall %s failed!\n", __FUNCTION__)
/** fd **/
int ocall_open(int *p_fd, const char *pathname, int flags,
bool has_mode, unsigned mode);
int ocall_openat(int *p_fd, int dirfd, const char *pathname, int flags,
bool has_mode, unsigned mode);
int ocall_read(ssize_t *p_ret, int fd, void *buf, size_t read_size);
int ocall_close(int *p_ret, int fd);
int ocall_lseek(off_t *p_ret, int fd, off_t offset, int whence);
int ocall_ftruncate(int *p_ret, int fd, off_t length);
int ocall_fsync(int *p_ret, int fd);
int ocall_fdatasync(int *p_ret, int fd);
int ocall_isatty(int *p_ret, int fd);
/** fd end **/
/** DIR **/
int ocall_fdopendir(int fd, void **p_dirp);
int ocall_readdir(void **p_dirent, void *dirp);
int ocall_rewinddir(void *dirp);
int ocall_seekdir(void *dirp, long loc);
int ocall_telldir(long *p_dir, void *dirp);
int ocall_closedir(int *p_ret, void *dirp);
/** DIR end **/
/** stat **/
int ocall_fstat(int *p_ret, int fd, void *buf, unsigned int buf_len);
int ocall_fstatat(int *p_ret, int dirfd, const char *pathname, void *buf,
unsigned int buf_len, int flags);
/** stat end **/
/** link **/
int ocall_mkdirat(int *p_ret, int dirfd, const char * pathname,
unsigned mode);
int ocall_link(int *p_ret, const char *oldpath, const char *newpath);
int ocall_linkat(int *p_ret, int olddirfd, const char *oldpath,
int newdirfd, const char *newpath, int flags);
int ocall_unlinkat(int *p_ret, int dirfd, const char *pathname,
int flags);
int ocall_readlinkat(ssize_t *p_ret, int dirfd, const char *pathname,
char *buf, size_t bufsiz);
int ocall_renameat(int *p_ret, int olddirfd,const char *oldpath,
int newdirfd,const char *newpath);
int ocall_symlinkat(int *p_ret, const char *target, int newdirfd,
const char *linkpath);
/** link end **/
/** control **/
int ocall_ioctl(int *p_ret, int fd, unsigned long request, void *arg,
unsigned int arg_len);
int ocall_fcntl(int *p_ret, int fd, int cmd);
int ocall_fcntl_long(int *p_ret, int fd, int cmd, long arg);
/** control end **/
/** **/
int ocall_realpath(int *p_ret, const char *path, char *buf,
unsigned int buf_len);
int ocall_posix_fallocate(int *p_ret, int fd, off_t offset, off_t len);
int ocall_poll(int *p_ret, void *fds, unsigned nfds, int timeout,
unsigned int fds_len);
int ocall_getopt(int *p_ret, int argc, char *argv_buf,
unsigned int argv_buf_len, const char *optstring);
int ocall_getrandom(ssize_t *p_ret, void *buf, size_t buflen,
unsigned int flags);
int ocall_sched_yield(int *p_ret);
/** struct iovec **/
ssize_t ocall_readv(ssize_t *p_ret, int fd, char *iov_buf,
unsigned int buf_size, int iovcnt,
bool has_offset, off_t offset);
ssize_t ocall_writev(ssize_t *p_ret, int fd, char *iov_buf,
unsigned int buf_size, int iovcnt,
bool has_offset, off_t offset);
/** iovec end **/
int ocall_get_errno(int *p_ret);
int open(const char *pathname, int flags, ...)
{
int fd;
bool has_mode = false;
mode_t mode = 0;
if ((flags & O_CREAT) || (flags & O_TMPFILE) == O_TMPFILE) {
va_list ap;
va_start(ap, flags);
mode = va_arg(ap, mode_t);
va_end(ap);
has_mode = true;
}
if (SGX_SUCCESS != ocall_open(&fd, pathname, flags, has_mode, mode)) {
TRACE_OCALL_FAIL();
return -1;
}
if (fd >= 0 && (flags & O_CLOEXEC))
fcntl(fd, F_SETFD, FD_CLOEXEC);
if (fd == -1)
errno = get_errno();
return fd;
}
int openat(int dirfd, const char *pathname, int flags, ...)
{
int fd;
bool has_mode = false;
mode_t mode = 0;
if ((flags & O_CREAT) || (flags & O_TMPFILE) == O_TMPFILE) {
va_list ap;
va_start(ap, flags);
mode = va_arg(ap, mode_t);
va_end(ap);
has_mode = true;
}
if (SGX_SUCCESS != ocall_openat(&fd, dirfd, pathname, flags,
has_mode, mode)) {
TRACE_OCALL_FAIL();
return -1;
}
if (fd >= 0 && (flags & O_CLOEXEC))
fcntl(fd, F_SETFD, FD_CLOEXEC);
if (fd == -1)
errno = get_errno();
return fd;
}
int close(int fd)
{
int ret;
if (ocall_close(&ret, fd) != SGX_SUCCESS) {
TRACE_OCALL_FAIL();
return -1;
}
if (ret == -1)
errno = get_errno();
return ret;
}
ssize_t read(int fd, void *buf, size_t size)
{
ssize_t ret;
int size_read_max = 2048, size_read, total_size_read = 0, count, i;
char *p = buf;
if (buf == NULL) {
TRACE_FUNC();
return -1;
}
count = (size + size_read_max - 1) / size_read_max;
for (i = 0; i < count; i++) {
size_read = (i < count - 1)
? size_read_max
: size - size_read_max * i;
if (ocall_read(&ret, fd, p, size_read) != SGX_SUCCESS) {
TRACE_OCALL_FAIL();
return -1;
}
if (ret == -1) {
/* read failed */
errno = get_errno();
return -1;
}
p += ret;
total_size_read += ret;
if (ret < size_read)
/* end of file */
break;
}
return total_size_read;
}
DIR *fdopendir(int fd)
{
DIR *result = NULL;
result = (DIR *)BH_MALLOC(sizeof(DIR));
if (!result)
return NULL;
if (ocall_fdopendir(fd, (void **)result) != SGX_SUCCESS) {
TRACE_OCALL_FAIL();
BH_FREE(result);
return NULL;
}
if ((void *)*result == NULL) { /* opendir failed */
TRACE_FUNC();
BH_FREE(result);
errno = get_errno();
return NULL;
}
return result;
}
struct dirent *readdir(DIR *dirp)
{
struct dirent *result;
if (dirp == NULL)
return NULL;
if (ocall_readdir((void **)&result, (void *)*dirp) != SGX_SUCCESS) {
TRACE_OCALL_FAIL();
return NULL;
}
if (!result)
errno = get_errno();
return result;
}
void rewinddir(DIR *dirp)
{
if (ocall_rewinddir((void *)*dirp) != SGX_SUCCESS) {
TRACE_OCALL_FAIL();
}
}
void seekdir(DIR *dirp, long loc)
{
if (ocall_seekdir((void *)*dirp, loc) != SGX_SUCCESS) {
TRACE_OCALL_FAIL();
}
}
long telldir(DIR *dirp)
{
long ret;
if (ocall_telldir(&ret, (void *)*dirp) != SGX_SUCCESS) {
TRACE_OCALL_FAIL();
return -1;
}
if (ret == -1)
errno = get_errno();
return ret;
}
int closedir(DIR *dirp)
{
int ret;
if (ocall_closedir(&ret, (void *)*dirp) != SGX_SUCCESS) {
TRACE_OCALL_FAIL();
return -1;
}
BH_FREE(dirp);
if (ret == -1)
errno = get_errno();
return ret;
}
static ssize_t
readv_internal(int fd, const struct iovec *iov, int iovcnt,
bool has_offset, off_t offset)
{
ssize_t ret, size_left;
struct iovec *iov1;
int i;
char *p;
uint64 total_size = sizeof(struct iovec) * (uint64)iovcnt;
if (iov == NULL || iovcnt < 1)
return -1;
for (i = 0; i < iovcnt; i++) {
total_size += iov[i].iov_len;
}
if (total_size >= UINT32_MAX)
return -1;
iov1 = BH_MALLOC((uint32)total_size);
if (iov1 == NULL)
return -1;
memset(iov1, 0, (uint32)total_size);
p = (char*)(uintptr_t)(sizeof(struct iovec) * iovcnt);
for (i = 0; i < iovcnt; i++) {
iov1[i].iov_len = iov[i].iov_len;
iov1[i].iov_base = p;
p += iov[i].iov_len;
}
if (ocall_readv(&ret, fd, (char *)iov1, (uint32)total_size,
iovcnt, has_offset, offset) != SGX_SUCCESS) {
TRACE_OCALL_FAIL();
BH_FREE(iov1);
return -1;
}
p = (char *)(uintptr_t)(sizeof(struct iovec) * iovcnt);
size_left = ret;
for (i = 0; i < iovcnt; i++) {
if (size_left > iov[i].iov_len) {
memcpy(iov[i].iov_base, (uintptr_t)p + (char *)iov1,
iov[i].iov_len);
p += iov[i].iov_len;
size_left -= iov[i].iov_len;
}
else {
memcpy(iov[i].iov_base, (uintptr_t)p + (char *)iov1,
size_left);
break;
}
}
BH_FREE(iov1);
if (ret == -1)
errno = get_errno();
return ret;
}
static ssize_t
writev_internal(int fd, const struct iovec *iov, int iovcnt,
bool has_offset, off_t offset)
{
ssize_t ret;
struct iovec *iov1;
int i;
char *p;
uint64 total_size = sizeof(struct iovec) * (uint64)iovcnt;
if (iov == NULL || iovcnt < 1)
return -1;
for (i = 0; i < iovcnt; i++) {
total_size += iov[i].iov_len;
}
if (total_size >= UINT32_MAX)
return -1;
iov1 = BH_MALLOC((uint32)total_size);
if (iov1 == NULL)
return -1;
memset(iov1, 0, (uint32)total_size);
p = (char *)(uintptr_t)(sizeof(struct iovec) * iovcnt);
for (i = 0; i < iovcnt; i++) {
iov1[i].iov_len = iov[i].iov_len;
iov1[i].iov_base = p;
memcpy((uintptr_t)p + (char *)iov1, iov[i].iov_base,
iov[i].iov_len);
p += iov[i].iov_len;
}
if (ocall_writev(&ret, fd, (char *)iov1, (uint32)total_size,
iovcnt, has_offset, offset) != SGX_SUCCESS) {
TRACE_OCALL_FAIL();
BH_FREE(iov1);
return -1;
}
BH_FREE(iov1);
if (ret == -1)
errno = get_errno();
return ret;
}
ssize_t readv(int fd, const struct iovec *iov, int iovcnt)
{
return readv_internal(fd, iov, iovcnt, false, 0);
}
ssize_t writev(int fd, const struct iovec *iov, int iovcnt)
{
return writev_internal(fd, iov, iovcnt, false, 0);
}
ssize_t preadv(int fd, const struct iovec *iov, int iovcnt,
off_t offset)
{
return readv_internal(fd, iov, iovcnt, true, offset);
}
ssize_t pwritev(int fd, const struct iovec *iov, int iovcnt,
off_t offset)
{
return writev_internal(fd, iov, iovcnt, true, offset);
}
off_t lseek(int fd, off_t offset, int whence)
{
off_t ret;
if (ocall_lseek(&ret, fd, (long)offset, whence) != SGX_SUCCESS) {
TRACE_OCALL_FAIL();
return -1;
}
if (ret == -1)
errno = get_errno();
return ret;
}
int ftruncate(int fd, off_t length)
{
int ret;
if (ocall_ftruncate(&ret, fd, length) != SGX_SUCCESS) {
TRACE_OCALL_FAIL();
return -1;
}
if (ret == -1)
errno = get_errno();
return ret;
}
int fstat(int fd, struct stat *statbuf)
{
int ret;
if (statbuf == NULL)
return -1;
if (ocall_fstat(&ret, fd, (void *)statbuf,
sizeof(struct stat)) != SGX_SUCCESS) {
TRACE_OCALL_FAIL();
return -1;
}
if (ret == -1)
errno = get_errno();
return ret;
}
int fstatat(int dirfd, const char *pathname, struct stat *statbuf,
int flags)
{
int ret;
if (statbuf == NULL)
return -1;
if (ocall_fstatat(&ret, dirfd, pathname, (void *)statbuf,
sizeof(struct stat), flags) != SGX_SUCCESS) {
TRACE_OCALL_FAIL();
return -1;
}
if (ret == -1)
errno = get_errno();
return ret;
}
int fsync(int fd)
{
int ret;
if (ocall_fsync(&ret, fd) != SGX_SUCCESS) {
TRACE_OCALL_FAIL();
return -1;
}
if (ret == -1)
errno = get_errno();
return ret;
}
int fdatasync(int fd)
{
int ret;
if (ocall_fdatasync(&ret, fd) != SGX_SUCCESS) {
TRACE_OCALL_FAIL();
return -1;
}
if (ret == -1)
errno = get_errno();
return ret;
}
int mkdirat(int dirfd, const char *pathname, mode_t mode)
{
int ret;
if (ocall_mkdirat(&ret, dirfd, pathname, mode) != SGX_SUCCESS) {
TRACE_OCALL_FAIL();
return -1;
}
if (ret == -1)
errno = get_errno();
return ret;
}
int link(const char *oldpath, const char *newpath)
{
int ret;
if (ocall_link(&ret, oldpath, newpath) != SGX_SUCCESS) {
TRACE_OCALL_FAIL();
return -1;
}
if (ret == -1)
errno = get_errno();
return ret;
}
int linkat(int olddirfd, const char *oldpath,
int newdirfd, const char *newpath, int flags)
{
int ret;
if (ocall_linkat(&ret, olddirfd, oldpath, newdirfd, newpath,
flags) != SGX_SUCCESS) {
TRACE_OCALL_FAIL();
return -1;
}
if (ret == -1)
errno = get_errno();
return ret;
}
int unlinkat(int dirfd, const char *pathname, int flags)
{
int ret;
if (ocall_unlinkat(&ret, dirfd, pathname, flags) != SGX_SUCCESS) {
TRACE_OCALL_FAIL();
return -1;
}
if (ret == -1)
errno = get_errno();
return ret;
}
ssize_t readlinkat(int dirfd, const char *pathname,
char *buf, size_t bufsiz)
{
ssize_t ret;
if (buf == NULL)
return -1;
if (ocall_readlinkat(&ret, dirfd, pathname, buf,
bufsiz) != SGX_SUCCESS) {
TRACE_OCALL_FAIL();
return -1;
}
if (ret == -1)
errno = get_errno();
return ret;
}
int symlinkat(const char *target, int newdirfd, const char *linkpath)
{
int ret;
if (ocall_symlinkat(&ret, target,
newdirfd, linkpath) != SGX_SUCCESS) {
TRACE_OCALL_FAIL();
return -1;
}
if (ret == -1)
errno = get_errno();
return ret;
}
int renameat(int olddirfd, const char *oldpath,
int newdirfd, const char *newpath)
{
int ret;
if (ocall_renameat(&ret, olddirfd, oldpath,
newdirfd, newpath) != SGX_SUCCESS) {
TRACE_OCALL_FAIL();
return -1;
}
if (ret == -1)
errno = get_errno();
return ret;
}
int ioctl(int fd, unsigned long request, ...)
{
int ret;
va_list args;
switch (request) {
case FIONREAD:
va_start(args, request);
int *arg = (int *)va_arg(args, int *);
if (ocall_ioctl(&ret, fd, request, arg,
sizeof(*arg)) != SGX_SUCCESS) {
TRACE_OCALL_FAIL();
va_end(args);
return -1;
}
va_end(args);
break;
default:
os_printf("ioctl failed: unknown request", request);
return -1;
}
if (ret == -1)
errno = get_errno();
return ret;
}
int fcntl(int fd, int cmd, ... /* arg */ )
{
int ret;
va_list args;
switch (cmd) {
case F_GETFD:
case F_GETFL:
if (ocall_fcntl(&ret, fd, cmd) != SGX_SUCCESS) {
TRACE_OCALL_FAIL();
return -1;
}
break;
case F_DUPFD:
case F_SETFD:
case F_SETFL:
va_start(args, cmd);
long arg_1 = (long)va_arg(args, long);
if (ocall_fcntl_long(&ret, fd, cmd, arg_1) != SGX_SUCCESS) {
TRACE_OCALL_FAIL();
va_end(args);
return -1;
}
va_end(args);
break;
default:
os_printf("fcntl failed: unknown cmd %d.\n", cmd);
return -1;
}
if (ret == -1)
errno = get_errno();
return ret;
}
int isatty(int fd)
{
int ret;
if (ocall_isatty(&ret, fd) != SGX_SUCCESS) {
TRACE_OCALL_FAIL();
return -1;
}
if (ret == 0)
errno = get_errno();
return ret;
}
char *realpath(const char *path, char *resolved_path)
{
int ret;
char buf[PATH_MAX] = { 0 };
if (ocall_realpath(&ret, path, buf, PATH_MAX) != SGX_SUCCESS) {
TRACE_OCALL_FAIL();
return (char *)NULL;
}
if (ret != 0)
return (char *)NULL;
if (resolved_path) {
strcpy(resolved_path, buf);
}
else {
resolved_path = BH_MALLOC(strlen(buf) + 1);
if (resolved_path == NULL)
return NULL;
strcpy(resolved_path, buf);
}
return resolved_path;
}
int posix_fallocate(int fd, off_t offset, off_t len)
{
int ret;
if (ocall_posix_fallocate(&ret, fd, offset, len) != SGX_SUCCESS) {
TRACE_OCALL_FAIL();
return -1;
}
return ret;
}
int poll(struct pollfd *fds, nfds_t nfds, int timeout)
{
int ret;
if (fds == NULL)
return -1;
if (ocall_poll(&ret, fds, nfds, timeout,
sizeof(*fds) * nfds) != SGX_SUCCESS) {
TRACE_OCALL_FAIL();
return -1;
}
if (ret == -1)
errno = get_errno();
return ret;
}
int getopt(int argc, char * const argv[],
const char *optstring)
{
int ret;
char **argv1;
char *p;
int i;
uint64 total_size = sizeof(char *) * (uint64)argc;
for (i = 0; i < argc; i++) {
total_size += strlen(argv[i]) + 1;
}
if (total_size >= UINT32_MAX)
return -1;
argv1 = BH_MALLOC((uint32)total_size);
if (argv1 == NULL)
return -1;
p = (char *)(uintptr_t)(sizeof(char *) * argc);
for (i = 0; i < argc; i++) {
argv1[i] = p;
strcpy((char *)argv1 + (uintptr_t)p, argv[i]);
p += ((uintptr_t)strlen(argv[i]) + 1);
}
if (ocall_getopt(&ret, argc, (char *)argv1, total_size,
optstring) != SGX_SUCCESS) {
TRACE_OCALL_FAIL();
BH_FREE(argv1);
return -1;
}
BH_FREE(argv1);
if (ret == -1)
errno = get_errno();
return ret;
}
int sched_yield(void)
{
int ret;
if (ocall_sched_yield(&ret) != SGX_SUCCESS) {
TRACE_OCALL_FAIL();
return -1;
}
if (ret == -1)
errno = get_errno();
return ret;
}
ssize_t getrandom(void *buf, size_t buflen, unsigned int flags)
{
ssize_t ret;
if (ocall_getrandom(&ret, buf, buflen, flags) != SGX_SUCCESS) {
TRACE_OCALL_FAIL();
return -1;
}
if (ret == -1)
errno = get_errno();
return ret;
}
int get_errno(void)
{
int ret;
if (ocall_get_errno(&ret) != SGX_SUCCESS) {
TRACE_OCALL_FAIL();
return -1;
}
return ret;
}

View File

@ -0,0 +1,229 @@
/*
* Copyright (C) 2019 Intel Corporation. All rights reserved.
* SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
*/
#ifndef _SGX_FILE_H
#define _SGX_FILE_H
#include "sgx_time.h"
#ifdef __cplusplus
extern "C" {
#endif
#define F_DUPFD 0
#define F_GETFD 1
#define F_SETFD 2
#define F_GETFL 3
#define F_SETFL 4
#define FD_CLOEXEC 1
#define O_PATH 010000000
#define O_SEARCH O_PATH
#define O_EXEC O_PATH
#define O_ACCMODE (03|O_SEARCH)
#define O_RDONLY 00
#define O_WRONLY 01
#define O_RDWR 02
#define O_CREAT 0100
#define O_EXCL 0200
#define O_NOCTTY 0400
#define O_TRUNC 01000
#define O_APPEND 02000
#define O_NONBLOCK 04000
#define O_DSYNC 010000
#define O_SYNC 04010000
#define O_RSYNC 04010000
#define O_DIRECTORY 0200000
#define O_NOFOLLOW 0400000
#define O_CLOEXEC 02000000
#define O_ASYNC 020000
#define O_DIRECT 040000
#define O_LARGEFILE 0
#define O_NOATIME 01000000
#define O_PATH 010000000
#define O_TMPFILE 020200000
#define O_NDELAY O_NONBLOCK
#define S_IFMT 0170000
#define S_IFDIR 0040000
#define S_IFCHR 0020000
#define S_IFBLK 0060000
#define S_IFREG 0100000
#define S_IFIFO 0010000
#define S_IFLNK 0120000
#define S_IFSOCK 0140000
#define SEEK_SET 0
#define SEEK_CUR 1
#define SEEK_END 2
#define S_ISDIR(mode) (((mode) & S_IFMT) == S_IFDIR)
#define S_ISCHR(mode) (((mode) & S_IFMT) == S_IFCHR)
#define S_ISBLK(mode) (((mode) & S_IFMT) == S_IFBLK)
#define S_ISREG(mode) (((mode) & S_IFMT) == S_IFREG)
#define S_ISFIFO(mode) (((mode) & S_IFMT) == S_IFIFO)
#define S_ISLNK(mode) (((mode) & S_IFMT) == S_IFLNK)
#define S_ISSOCK(mode) (((mode) & S_IFMT) == S_IFSOCK)
#define DT_UNKNOWN 0
#define DT_FIFO 1
#define DT_CHR 2
#define DT_DIR 4
#define DT_BLK 6
#define DT_REG 8
#define DT_LNK 10
#define DT_SOCK 12
#define DT_WHT 14
#define AT_SYMLINK_NOFOLLOW 0x100
#define AT_REMOVEDIR 0x200
#define AT_SYMLINK_FOLLOW 0x400
#define POLLIN 0x001
#define POLLPRI 0x002
#define POLLOUT 0x004
#define POLLERR 0x008
#define POLLHUP 0x010
#define POLLNVAL 0x020
#define POLLRDNORM 0x040
#define POLLRDBAND 0x080
#define POLLWRNORM 0x100
#define POLLWRBAND 0x200
#define FIONREAD 0x541B
#define PATH_MAX 4096
/* Special value used to indicate openat should use the current
working directory. */
#define AT_FDCWD -100
typedef long __syscall_slong_t;
typedef unsigned long dev_t;
typedef unsigned long ino_t;
typedef unsigned mode_t;
typedef unsigned long nlink_t;
typedef unsigned socklen_t;
typedef long blksize_t;
typedef long blkcnt_t;
typedef int pid_t;
typedef unsigned gid_t;
typedef unsigned uid_t;
typedef unsigned long nfds_t;
typedef uintptr_t DIR;
struct dirent {
ino_t d_ino;
off_t d_off;
unsigned short d_reclen;
unsigned char d_type;
char d_name[256];
};
struct stat {
dev_t st_dev;
ino_t st_ino;
nlink_t st_nlink;
mode_t st_mode;
uid_t st_uid;
gid_t st_gid;
unsigned int __pad0;
dev_t st_rdev;
off_t st_size;
blksize_t st_blksize;
blkcnt_t st_blocks;
struct timespec st_atim;
struct timespec st_mtim;
struct timespec st_ctim;
long __unused[3];
};
struct iovec {
void *iov_base;
size_t iov_len;
};
struct pollfd {
int fd;
short events;
short revents;
};
int open(const char *pathname, int flags, ...);
int openat(int dirfd, const char *pathname, int flags, ...);
int close(int fd);
DIR *fdopendir(int fd);
int closedir(DIR *dirp);
void rewinddir(DIR *dirp);
void seekdir(DIR *dirp, long loc);
struct dirent *readdir(DIR *dirp);
long telldir(DIR *dirp);
ssize_t read(int fd, void *buf, size_t count);
ssize_t readv(int fd, const struct iovec *iov, int iovcnt);
ssize_t writev(int fd, const struct iovec *iov, int iovcnt);
ssize_t preadv(int fd, const struct iovec *iov, int iovcnt,
off_t offset);
ssize_t pwritev(int fd, const struct iovec *iov, int iovcnt,
off_t offset);
off_t lseek(int fd, off_t offset, int whence);
int ftruncate(int fd, off_t length);
int fstat(int fd, struct stat *statbuf);
int fstatat(int dirfd, const char *pathname, struct stat *statbuf,
int flags);
int fsync(int fd);
int fdatasync(int fd);
int mkdirat(int dirfd, const char *pathname, mode_t mode);
int link(const char *oldpath, const char *newpath);
int linkat(int olddirfd, const char *oldpath,
int newdirfd, const char *newpath, int flags);
int unlinkat(int dirfd, const char *pathname, int flags);
ssize_t readlinkat(int dirfd, const char *pathname,
char *buf, size_t bufsiz);
int symlinkat(const char *target, int newdirfd, const char *linkpath);
int renameat(int olddirfd, const char *oldpath,
int newdirfd, const char *newpath);
int ioctl(int fd, unsigned long request, ...);
int fcntl(int fd, int cmd, ... /* arg */ );
int isatty(int fd);
char *realpath(const char *path, char *resolved_path);
int posix_fallocate(int fd, off_t offset, off_t len);
int poll(struct pollfd *fds, nfds_t nfds, int timeout);
int getopt(int argc, char * const argv[],
const char *optstring);
int sched_yield(void);
ssize_t getrandom(void *buf, size_t buflen, unsigned int flags);
int get_errno(void);
#ifdef __cplusplus
}
#endif
#endif /* end of _SGX_FILE_H */

View File

@ -5,10 +5,7 @@
#include "platform_api_vmcore.h"
#include "platform_api_extension.h"
#if WASM_ENABLE_AOT != 0
#include "sgx_rsrv_mem_mngr.h"
#endif
#define FIXED_BUFFER_SIZE (1<<9)
@ -82,9 +79,17 @@ int os_vprintf(const char * format, va_list arg)
return 0;
}
char *strcpy(char *dest, const char *src)
{
const unsigned char *s = src;
unsigned char *d = dest;
while ((*d++ = *s++));
return dest;
}
void* os_mmap(void *hint, size_t size, int prot, int flags)
{
#if WASM_ENABLE_AOT != 0
int mprot = 0;
uint64 aligned_size, page_size;
void* ret = NULL;
@ -119,25 +124,19 @@ void* os_mmap(void *hint, size_t size, int prot, int flags)
}
return ret;
#else
return NULL;
#endif
}
void os_munmap(void *addr, size_t size)
{
#if WASM_ENABLE_AOT != 0
uint64 aligned_size, page_size;
page_size = getpagesize();
aligned_size = (size + page_size - 1) & ~(page_size - 1);
sgx_free_rsrv_mem(addr, aligned_size);
#endif
}
int os_mprotect(void *addr, size_t size, int prot)
{
#if WASM_ENABLE_AOT != 0
int mprot = 0;
sgx_status_t st = 0;
uint64 aligned_size, page_size;
@ -157,9 +156,6 @@ int os_mprotect(void *addr, size_t size, int prot)
addr, size, prot);
return (st == SGX_SUCCESS? 0:-1);
#else
return -1;
#endif
}
void

View File

@ -0,0 +1,75 @@
/*
* Copyright (C) 2019 Intel Corporation. All rights reserved.
* SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
*/
#include "platform_api_vmcore.h"
#include "sgx_pthread.h"
#include "sgx_error.h"
#define TRACE_FUNC() os_printf("undefined %s\n", __FUNCTION__)
#define TRACE_OCALL_FAIL() os_printf("ocall %s failed!\n", __FUNCTION__)
int ocall_pthread_rwlock_init(int *p_ret, void **rwlock, void *attr);
int ocall_pthread_rwlock_destroy(int *p_ret, void **rwlock);
int ocall_pthread_rwlock_rdlock(int *p_ret, void **rwlock);
int ocall_pthread_rwlock_wrlock(int *p_ret, void **rwlock);
int ocall_pthread_rwlock_unlock(int *p_ret, void **rwlock);
int pthread_rwlock_init(pthread_rwlock_t *rwlock, void *attr)
{
int ret = -1;
if (ocall_pthread_rwlock_init(&ret, (void **)rwlock, NULL)
!= SGX_SUCCESS) {
TRACE_OCALL_FAIL();
return -1;
}
(void)attr;
return ret;
}
int pthread_rwlock_destroy(pthread_rwlock_t *rwlock)
{
int ret = -1;
if (ocall_pthread_rwlock_destroy(&ret, (void *)*rwlock) != SGX_SUCCESS) {
TRACE_OCALL_FAIL();
}
return ret;
}
int pthread_rwlock_rdlock(pthread_rwlock_t *rwlock)
{
int ret = -1;
if (ocall_pthread_rwlock_rdlock(&ret, (void*)*rwlock) != SGX_SUCCESS) {
TRACE_OCALL_FAIL();
}
return ret;
}
int pthread_rwlock_wrlock(pthread_rwlock_t *rwlock)
{
int ret = -1;
if (ocall_pthread_rwlock_wrlock(&ret, (void*)*rwlock) != SGX_SUCCESS) {
TRACE_OCALL_FAIL();
}
return ret;
}
int pthread_rwlock_unlock(pthread_rwlock_t *rwlock)
{
int ret = -1;
if (ocall_pthread_rwlock_unlock(&ret, (void*)*rwlock) != SGX_SUCCESS) {
TRACE_OCALL_FAIL();
}
return ret;
}

View File

@ -0,0 +1,27 @@
/*
* Copyright (C) 2019 Intel Corporation. All rights reserved.
* SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
*/
#ifndef _SGX_PTHREAD_H
#define _SGX_PTHREAD_H
#ifdef __cplusplus
extern "C" {
#endif
typedef uintptr_t pthread_rwlock_t;
int pthread_rwlock_init(pthread_rwlock_t *rwlock, void *attr);
int pthread_rwlock_destroy(pthread_rwlock_t *rwlock);
int pthread_rwlock_wrlock(pthread_rwlock_t *rwlock);
int pthread_rwlock_rdlock(pthread_rwlock_t *rwlock);
int pthread_rwlock_unlock(pthread_rwlock_t *rwlock);
#ifdef __cplusplus
}
#endif
#endif /* end of _SGX_PTHREAD_H */

View File

@ -0,0 +1,26 @@
/*
* Copyright (C) 2019 Intel Corporation. All rights reserved.
* SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
*/
#include "platform_api_vmcore.h"
#define TRACE_OCALL_FAIL() os_printf("ocall %s failed!\n", __FUNCTION__)
int ocall_raise(int *p_ret, int sig);
int raise(int sig)
{
int ret;
if (ocall_raise(&ret, sig) != SGX_SUCCESS) {
TRACE_OCALL_FAIL();
return -1;
}
if (ret == -1)
errno = get_errno();
return ret;
}

View File

@ -0,0 +1,57 @@
/*
* Copyright (C) 2019 Intel Corporation. All rights reserved.
* SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
*/
#ifndef _SGX_SIGNAL_H
#define _SGX_SIGNAL_H
#ifdef __cplusplus
extern "C" {
#endif
/* Signals. */
#define SIGHUP 1 /* Hangup (POSIX). */
#define SIGINT 2 /* Interrupt (ANSI). */
#define SIGQUIT 3 /* Quit (POSIX). */
#define SIGILL 4 /* Illegal instruction (ANSI). */
#define SIGTRAP 5 /* Trace trap (POSIX). */
#define SIGABRT 6 /* Abort (ANSI). */
#define SIGIOT 6 /* IOT trap (4.2 BSD). */
#define SIGBUS 7 /* BUS error (4.2 BSD). */
#define SIGFPE 8 /* Floating-point exception (ANSI). */
#define SIGKILL 9 /* Kill, unblockable (POSIX). */
#define SIGUSR1 10 /* User-defined signal 1 (POSIX). */
#define SIGSEGV 11 /* Segmentation violation (ANSI). */
#define SIGUSR2 12 /* User-defined signal 2 (POSIX). */
#define SIGPIPE 13 /* Broken pipe (POSIX). */
#define SIGALRM 14 /* Alarm clock (POSIX). */
#define SIGTERM 15 /* Termination (ANSI). */
#define SIGSTKFLT 16 /* Stack fault. */
#define SIGCLD SIGCHLD /* Same as SIGCHLD (System V). */
#define SIGCHLD 17 /* Child status has changed (POSIX). */
#define SIGCONT 18 /* Continue (POSIX). */
#define SIGSTOP 19 /* Stop, unblockable (POSIX). */
#define SIGTSTP 20 /* Keyboard stop (POSIX). */
#define SIGTTIN 21 /* Background read from tty (POSIX). */
#define SIGTTOU 22 /* Background write to tty (POSIX). */
#define SIGURG 23 /* Urgent condition on socket (4.2 BSD). */
#define SIGXCPU 24 /* CPU limit exceeded (4.2 BSD). */
#define SIGXFSZ 25 /* File size limit exceeded (4.2 BSD). */
#define SIGVTALRM 26 /* Virtual alarm clock (4.2 BSD). */
#define SIGPROF 27 /* Profiling alarm clock (4.2 BSD). */
#define SIGWINCH 28 /* Window size change (4.3 BSD, Sun). */
#define SIGPOLL SIGIO /* Pollable event occurred (System V). */
#define SIGIO 29 /* I/O now possible (4.2 BSD). */
#define SIGPWR 30 /* Power failure restart (System V). */
#define SIGSYS 31 /* Bad system call. */
#define SIGUNUSED 31
int raise(int sig);
#ifdef __cplusplus
}
#endif
#endif /* end of _SGX_SIGNAL_H */

View File

@ -0,0 +1,218 @@
/*
* Copyright (C) 2019 Intel Corporation. All rights reserved.
* SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
*/
#include "platform_api_vmcore.h"
#define TRACE_OCALL_FAIL() os_printf("ocall %s failed!\n", __FUNCTION__)
int ocall_socket(int *p_ret, int domain, int type, int protocol);
int ocall_getsockopt(int *p_ret, int sockfd, int level, int optname,
void *val_buf, unsigned int val_buf_size,
void *len_buf);
int ocall_sendmsg(ssize_t *p_ret, int sockfd, void *msg_buf,
unsigned int msg_buf_size, int flags);
int ocall_recvmsg(ssize_t *p_ret, int sockfd, void *msg_buf,
unsigned int msg_buf_size, int flags);
int ocall_shutdown(int *p_ret, int sockfd, int how);
int socket(int domain, int type, int protocol)
{
int ret;
if (ocall_socket(&ret, domain, type, protocol) != SGX_SUCCESS) {
TRACE_OCALL_FAIL();
return -1;
}
if (ret == -1)
errno = get_errno();
return ret;
}
int getsockopt(int sockfd, int level, int optname,
void *optval, socklen_t *optlen)
{
int ret;
unsigned int val_buf_size = *optlen;
if (ocall_getsockopt(&ret, sockfd, level, optname, optval,
val_buf_size, (void *)optlen) != SGX_SUCCESS) {
TRACE_OCALL_FAIL();
return -1;
}
if (ret == -1)
errno = get_errno();
return ret;
}
ssize_t sendmsg(int sockfd, const struct msghdr *msg, int flags)
{
ssize_t ret;
int i;
char *p;
struct msghdr *msg1;
uint64 total_size = sizeof(struct msghdr) + (uint64)msg->msg_namelen
+ (uint64)msg->msg_controllen;
total_size += sizeof(struct iovec) * (msg->msg_iovlen);
for (i = 0; i < msg->msg_iovlen; i++) {
total_size += msg->msg_iov[i].iov_len;
}
if (total_size >= UINT32_MAX)
return -1;
msg1 = BH_MALLOC((uint32)total_size);
if (msg1 == NULL)
return -1;
p = (char*)(uintptr_t)sizeof(struct msghdr);
if (msg->msg_name != NULL) {
msg1->msg_name = p;
memcpy((uintptr_t)p + (char *)msg1, msg->msg_name,
(size_t)msg->msg_namelen);
p += msg->msg_namelen;
}
if (msg->msg_control != NULL) {
msg1->msg_control = p;
memcpy((uintptr_t)p + (char *)msg1, msg->msg_control,
(size_t)msg->msg_control);
p += msg->msg_controllen;
}
if (msg->msg_iov != NULL) {
msg1->msg_iov = (struct iovec *)p;
p += (uintptr_t)(sizeof(struct iovec) * (msg->msg_iovlen));
for (i = 0; i < msg->msg_iovlen; i++) {
msg1->msg_iov[i].iov_base = p;
msg1->msg_iov[i].iov_len = msg->msg_iov[i].iov_len;
memcpy((uintptr_t)p + (char *)msg1, msg->msg_iov[i].iov_base,
(size_t)(msg->msg_iov[i].iov_len));
p += msg->msg_iov[i].iov_len;
}
}
if (ocall_sendmsg(&ret, sockfd, (void *)msg1, (uint32)total_size,
flags) != SGX_SUCCESS) {
TRACE_OCALL_FAIL();
return -1;
}
if (ret == -1)
errno = get_errno();
return ret;
}
ssize_t recvmsg(int sockfd, struct msghdr *msg, int flags)
{
ssize_t ret;
int i;
char *p;
struct msghdr *msg1;
uint64 total_size = sizeof(struct msghdr) + (uint64)msg->msg_namelen
+ (uint64)msg->msg_controllen;
total_size += sizeof(struct iovec) * (msg->msg_iovlen);
for (i = 0; i < msg->msg_iovlen; i++) {
total_size += msg->msg_iov[i].iov_len;
}
if (total_size >= UINT32_MAX)
return -1;
msg1 = BH_MALLOC((uint32)total_size);
if (msg1 == NULL)
return -1;
memset(msg1, 0, total_size);
p = (char*)(uintptr_t)sizeof(struct msghdr);
if (msg->msg_name != NULL) {
msg1->msg_name = p;
p += msg->msg_namelen;
}
if (msg->msg_control != NULL) {
msg1->msg_control = p;
p += msg->msg_controllen;
}
if (msg->msg_iov != NULL) {
msg1->msg_iov = (struct iovec *)p;
p += (uintptr_t)(sizeof(struct iovec) * (msg->msg_iovlen));
for (i = 0; i < msg->msg_iovlen; i++) {
msg1->msg_iov[i].iov_base = p;
msg1->msg_iov[i].iov_len = msg->msg_iov[i].iov_len;
p += msg->msg_iov[i].iov_len;
}
}
if (ocall_recvmsg(&ret, sockfd, (void *)msg1, (uint32)total_size,
flags) != SGX_SUCCESS) {
TRACE_OCALL_FAIL();
return -1;
}
p = (char *)(uintptr_t)(sizeof(struct msghdr));
if (msg1->msg_name != NULL) {
memcpy(msg->msg_name, (uintptr_t)p + (char *)msg1,
(size_t)msg1->msg_namelen);
p += msg1->msg_namelen;
}
if (msg1->msg_control != NULL) {
memcpy(msg->msg_control, (uintptr_t)p + (char *)msg1,
(size_t)msg1->msg_control);
p += msg->msg_controllen;
}
if (msg1->msg_iov != NULL) {
p += (uintptr_t)(sizeof(struct iovec) * (msg1->msg_iovlen));
for (i = 0; i < msg1->msg_iovlen; i++) {
memcpy(msg->msg_iov[i].iov_base, (uintptr_t)p + (char *)msg1,
(size_t)(msg1->msg_iov[i].iov_len));
p += msg1->msg_iov[i].iov_len;
}
}
if (ret == -1)
errno = get_errno();
return ret;
}
int shutdown(int sockfd, int how)
{
int ret;
if (ocall_shutdown(&ret, sockfd, how) != SGX_SUCCESS) {
TRACE_OCALL_FAIL();
return -1;
}
if (ret == -1)
errno = get_errno();
return ret;
}

View File

@ -0,0 +1,74 @@
/*
* Copyright (C) 2019 Intel Corporation. All rights reserved.
* SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
*/
#ifndef _SGX_SOCKET_H
#define _SGX_SOCKET_H
#include "sgx_file.h"
#ifdef __cplusplus
extern "C" {
#endif
#define SOL_SOCKET 1
#define SOCK_STREAM 1
#define SOCK_DGRAM 2
#define SO_TYPE 3
#define MSG_OOB 0x0001
#define MSG_PEEK 0x0002
#define MSG_DONTROUTE 0x0004
#define MSG_CTRUNC 0x0008
#define MSG_PROXY 0x0010
#define MSG_TRUNC 0x0020
#define MSG_DONTWAIT 0x0040
#define MSG_EOR 0x0080
#define MSG_WAITALL 0x0100
#define MSG_FIN 0x0200
#define MSG_SYN 0x0400
#define MSG_CONFIRM 0x0800
#define MSG_RST 0x1000
#define MSG_ERRQUEUE 0x2000
#define MSG_NOSIGNAL 0x4000
#define MSG_MORE 0x8000
#define MSG_WAITFORONE 0x10000
#define MSG_BATCH 0x40000
#define MSG_FASTOPEN 0x20000000
#define MSG_CMSG_CLOEXEC 0x40000000
#define SHUT_RD 0
#define SHUT_WR 1
#define SHUT_RDWR 2
struct msghdr {
void *msg_name;
socklen_t msg_namelen;
struct iovec *msg_iov;
int msg_iovlen;
void *msg_control;
socklen_t msg_controllen;
int msg_flags;
};
int socket(int domain, int type, int protocol);
int getsockopt(int sockfd, int level, int optname,
void *optval, socklen_t *optlen);
ssize_t sendmsg(int sockfd, const struct msghdr *msg, int flags);
ssize_t recvmsg(int sockfd, struct msghdr *msg, int flags);
int shutdown(int sockfd, int how);
#ifdef __cplusplus
}
#endif
#endif /* end of _SGX_SOCKET_H */

View File

@ -6,47 +6,138 @@
#include "platform_api_vmcore.h"
#include "platform_api_extension.h"
typedef struct {
thread_start_routine_t start;
void *arg;
} thread_wrapper_arg;
static void *os_thread_wrapper(void *arg)
{
thread_wrapper_arg * targ = arg;
thread_start_routine_t start_func = targ->start;
void *thread_arg = targ->arg;
os_printf("THREAD CREATED %p\n", &targ);
BH_FREE(targ);
start_func(thread_arg);
return NULL;
}
int os_thread_create_with_prio(korp_tid *tid, thread_start_routine_t start,
void *arg, unsigned int stack_size, int prio)
{
thread_wrapper_arg *targ;
assert(tid);
assert(start);
targ = (thread_wrapper_arg *) BH_MALLOC(sizeof(*targ));
if (!targ) {
return BHT_ERROR;
}
targ->start = start;
targ->arg = arg;
if (pthread_create(tid, NULL, os_thread_wrapper, targ) != 0) {
BH_FREE(targ);
return BHT_ERROR;
}
return BHT_OK;
}
int os_thread_create(korp_tid *tid, thread_start_routine_t start, void *arg,
unsigned int stack_size)
{
return os_thread_create_with_prio(tid, start, arg, stack_size,
BH_THREAD_DEFAULT_PRIORITY);
}
korp_tid os_self_thread()
{
return sgx_thread_self();
return pthread_self();
}
int os_mutex_init(korp_mutex *mutex)
{
sgx_thread_mutex_t m = SGX_THREAD_MUTEX_INITIALIZER;
pthread_mutex_t m = PTHREAD_MUTEX_INITIALIZER;
*mutex = m;
return BHT_OK;
}
int os_mutex_destroy(korp_mutex *mutex)
{
sgx_thread_mutex_destroy(mutex);
pthread_mutex_destroy(mutex);
return BHT_OK;
}
int os_mutex_lock(korp_mutex *mutex)
{
return sgx_thread_mutex_lock(mutex);
return pthread_mutex_lock(mutex);
}
int os_mutex_unlock(korp_mutex *mutex)
{
return sgx_thread_mutex_unlock(mutex);
return pthread_mutex_unlock(mutex);
}
int os_cond_init(korp_cond *cond)
{
sgx_thread_cond_t c = SGX_THREAD_COND_INITIALIZER;
pthread_cond_t c = PTHREAD_COND_INITIALIZER;
*cond = c;
return BHT_OK;
}
int os_cond_destroy(korp_cond *cond)
{
sgx_thread_cond_destroy(cond);
pthread_cond_destroy(cond);
return BHT_OK;
}
int os_cond_wait(korp_cond *cond, korp_mutex *mutex)
{
assert(cond);
assert(mutex);
if (pthread_cond_wait(cond, mutex) != BHT_OK)
return BHT_ERROR;
return BHT_OK;
}
int os_cond_reltimedwait(korp_cond *cond, korp_mutex *mutex, int useconds)
{
os_printf("warning: SGX pthread_cond_timedwait isn't supported, "
"calling pthread_cond_wait instead!\n");
return BHT_ERROR;
}
int os_cond_signal(korp_cond *cond)
{
assert(cond);
if (pthread_cond_signal(cond) != BHT_OK)
return BHT_ERROR;
return BHT_OK;
}
int os_thread_join(korp_tid thread, void **value_ptr)
{
return pthread_join(thread, value_ptr);
}
int os_thread_detach(korp_tid thread)
{
/* SGX pthread_detach isn't provided, return directly. */
return 0;
}
void os_thread_exit(void *retval)
{
return pthread_exit(retval);
}
uint8 *os_thread_get_stack_boundary()
{
/* TODO: get sgx stack boundary */

View File

@ -5,6 +5,22 @@
#include "platform_api_vmcore.h"
#define TRACE_FUNC() os_printf("undefined %s\n", __FUNCTION__)
#define TRACE_OCALL_FAIL() os_printf("ocall %s failed!\n", __FUNCTION__)
int ocall_clock_gettime(int *p_ret, unsigned clock_id,
void *tp_buf, unsigned int tp_buf_size);
int ocall_clock_getres(int *p_ret, int clock_id,
void *res_buf, unsigned int res_buf_size);
int ocall_utimensat(int *p_ret, int dirfd, const char *pathname,
const void *times_buf, unsigned int times_buf_size,
int flags);
int ocall_futimens(int *p_ret, int fd,
const void *times_buf, unsigned int times_buf_size);
int ocall_clock_nanosleep(int *p_ret, unsigned clock_id, int flags,
const void *req_buf, unsigned int req_buf_size,
const void *rem_buf, unsigned int rem_buf_size);
uint64
os_time_get_boot_microsecond()
{
@ -12,3 +28,88 @@ os_time_get_boot_microsecond()
return 0;
}
int clock_getres(int clock_id, struct timespec *res)
{
int ret;
if (ocall_clock_getres(&ret, clock_id, (void *)res,
sizeof(struct timespec)) != SGX_SUCCESS) {
TRACE_OCALL_FAIL();
return -1;
}
if (ret == -1)
errno = get_errno();
return ret;
}
int clock_gettime(clockid_t clock_id, struct timespec *tp)
{
int ret;
if(ocall_clock_gettime(&ret, clock_id, (void *)tp,
sizeof(struct timespec)) != SGX_SUCCESS) {
TRACE_OCALL_FAIL();
return -1;
}
if (ret == -1)
errno = get_errno();
return ret;
}
int utimensat(int dirfd, const char *pathname,
const struct timespec times[2], int flags)
{
int ret;
if (ocall_utimensat(&ret, dirfd, pathname, (void *)times,
sizeof(struct timespec) * 2,
flags) != SGX_SUCCESS) {
TRACE_OCALL_FAIL();
return -1;
}
if (ret == -1)
errno = get_errno();
return ret;
}
int futimens(int fd, const struct timespec times[2])
{
int ret;
if (ocall_futimens(&ret, fd, (void *)times,
sizeof(struct timespec) * 2) != SGX_SUCCESS) {
TRACE_OCALL_FAIL();
return -1;
}
if (ret == -1)
errno = get_errno();
return ret;
}
int clock_nanosleep(clockid_t clock_id, int flags,
const struct timespec *request,
struct timespec *remain)
{
int ret;
if (ocall_clock_nanosleep(&ret, clock_id, flags, (void *)request,
sizeof(struct timespec),
(void *)remain,
sizeof(struct timespec)) != SGX_SUCCESS) {
TRACE_OCALL_FAIL();
return -1;
}
if (ret == -1)
errno = get_errno();
return ret;
}

View File

@ -0,0 +1,47 @@
/*
* Copyright (C) 2019 Intel Corporation. All rights reserved.
* SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
*/
#ifndef _SGX_TIME_H
#define _SGX_TIME_H
#ifdef __cplusplus
extern "C" {
#endif
#define CLOCK_REALTIME 0
#define CLOCK_MONOTONIC 1
#define CLOCK_PROCESS_CPUTIME_ID 2
#define CLOCK_THREAD_CPUTIME_ID 3
#define UTIME_NOW 0x3fffffff
#define UTIME_OMIT 0x3ffffffe
#define TIMER_ABSTIME 1
typedef long int time_t;
typedef int clockid_t;
struct timespec {
time_t tv_sec;
long tv_nsec;
};
int clock_getres(int clock_id, struct timespec *res);
int clock_gettime(clockid_t clock_id, struct timespec *tp);
int utimensat(int dirfd, const char *pathname,
const struct timespec times[2], int flags);
int futimens(int fd, const struct timespec times[2]);
int clock_nanosleep(clockid_t clock_id, int flags,
const struct timespec *request,
struct timespec *remain);
#ifdef __cplusplus
}
#endif
#endif /* end of _SGX_TIME_H */

View File

@ -0,0 +1,132 @@
/*
* Copyright (C) 2019 Intel Corporation. All rights reserved.
* SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
*/
enclave {
include "stdint.h"
include "stdbool.h"
include "unistd.h"
untrusted {
int ocall_open([in, string]const char *pathname, int flags,
bool has_mode, unsigned mode);
int ocall_openat(int dirfd,
[in, string]const char *pathname, int flags,
bool has_mode, unsigned mode);
int ocall_close(int fd);
ssize_t ocall_read(int fd, [out, size=read_size]void *buf,
size_t read_size);
off_t ocall_lseek(int fd, off_t offset, int whence);
int ocall_ftruncate(int fd, off_t length);
int ocall_fsync(int fd);
int ocall_fdatasync(int fd);
int ocall_isatty(int fd);
void ocall_fdopendir(int fd, [out]void **p_dirp);
/* implementation related to multiple thread */
void *ocall_readdir([user_check]void *dirp);
void ocall_rewinddir([user_check]void *dirp);
void ocall_seekdir([user_check]void *dirp, long loc);
long ocall_telldir([user_check]void *dirp);
int ocall_closedir([user_check]void *dirp);
int ocall_fstat(int fd, [out, size=buf_len]void *buf,
unsigned int buf_len);
int ocall_fstatat(int dirfd, [in, string]const char *pathname,
[out, size=buf_len]void *buf,
unsigned int buf_len, int flags);
int ocall_mkdirat(int dirfd, [in, string]const char *pathname,
unsigned mode);
int ocall_link([in, string] const char *oldpath,
[in, string] const char *newpath);
int ocall_linkat(int olddirfd, [in, string]const char *oldpath,
int newdirfd, [in, string]const char *newpath,
int flags);
int ocall_unlinkat(int dirfd, [in, string]const char *pathname,
int flags);
ssize_t ocall_readlinkat(int dirfd,
[in, string]const char *pathname,
[out, size=bufsiz]char *buf,
size_t bufsiz);
int ocall_renameat(int olddirfd,
[in, string]const char *oldpath,
int newdirfd,
[in, string]const char *newpath);
int ocall_symlinkat([in ,string]const char *target,
int newdirfd,
[in, string]const char *linkpath);
int ocall_ioctl(int fd, unsigned long request,
[out, size=arg_len]void *arg,
unsigned int arg_len);
int ocall_fcntl(int fd, int cmd);
int ocall_fcntl_long(int fd, int cmd, long arg);
int ocall_realpath([in, string]const char *path,
[out, size=buf_len]char *buf,
unsigned int buf_len);
int ocall_posix_fallocate(int fd, off_t offset, off_t len);
int ocall_poll([out, size=fds_len]void *fds, unsigned nfds,
int timeout, unsigned int fds_len);
int ocall_getopt(int argc,
[in, size=argv_buf_len]char *argv_buf,
unsigned int argv_buf_len,
[in, string]const char *optstring);
ssize_t ocall_getrandom([out, size=buflen]void *buf, size_t buflen,
unsigned int flags);
ssize_t ocall_readv(int fd,
[in, out, size=buf_size]char *iov_buf,
unsigned int buf_size, int iovcnt,
bool has_offset, off_t offset);
ssize_t ocall_writev(int fd,
[in, size=buf_size]char *iov_buf,
unsigned int buf_size, int iovcnt,
bool has_offset, off_t offset);
/* time clock */
int ocall_clock_gettime(unsigned clock_id,
[out, size=tp_buf_size]void *tp_buf,
unsigned int tp_buf_size);
int ocall_clock_getres(int clock_id,
[out, size=res_buf_size]void *res_buf,
unsigned int res_buf_size);
int ocall_utimensat(int dirfd, [in, string]const char *pathname,
[in, size=times_buf_size]const void *times_buf,
unsigned int times_buf_size, int flags);
int ocall_futimens(int fd, [in, size=times_buf_size]const void *times_buf,
unsigned int times_buf_size);
int ocall_clock_nanosleep(unsigned clock_id, int flags,
[in, size=req_buf_size]const void *req_buf,
unsigned int req_buf_size,
[out, size=rem_buf_size]void *rem_buf,
unsigned int rem_buf_size);
int ocall_raise(int sig);
int ocall_sched_yield();
int ocall_pthread_rwlock_init([out]void **rwlock, [user_check]void *attr);
int ocall_pthread_rwlock_destroy([user_check]void *rwlock);
int ocall_pthread_rwlock_rdlock([user_check]void *rwlock);
int ocall_pthread_rwlock_wrlock([user_check]void *rwlock);
int ocall_pthread_rwlock_unlock([user_check]void *rwlock);
int ocall_get_errno();
int ocall_socket(int domain, int type, int protocol);
int ocall_getsockopt(int sockfd, int level, int optname,
[out, size=val_buf_size]void *val_buf,
unsigned int val_buf_size,
[in, out, size=4]void *len_buf);
ssize_t ocall_sendmsg(int sockfd,
[in, size=msg_buf_size]void *msg_buf,
unsigned int msg_buf_size,
int flags);
ssize_t ocall_recvmsg(int sockfd,
[in, out, size=msg_buf_size]void *msg_buf,
unsigned int msg_buf_size,
int flags);
int ocall_shutdown(int sockfd, int how);
};
};

View File

@ -20,7 +20,11 @@ if (NOT BUILD_UNTRUST_PART EQUAL 1)
${SGX_SDK_DIR}/include/libcxx)
endif ()
file (GLOB_RECURSE source_all ${PLATFORM_SHARED_DIR}/*.c)
file (GLOB source_all ${PLATFORM_SHARED_DIR}/*.c)
file (GLOB source_all_untrusted ${PLATFORM_SHARED_DIR}/untrusted/*.c)
set (PLATFORM_SHARED_SOURCE ${source_all})
set (PLATFORM_SHARED_SOURCE_UNTRUSTED ${source_all_untrusted})

View File

@ -0,0 +1,288 @@
/*
* Copyright (C) 2019 Intel Corporation. All rights reserved.
* SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
*/
#include <stdbool.h>
#include <stdint.h>
#include <stdio.h>
#include <stdlib.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <sys/ioctl.h>
#include <sys/random.h>
#include <sys/uio.h>
#include <fcntl.h>
#include <unistd.h>
#include <dirent.h>
#include <sched.h>
#include <poll.h>
#include <errno.h>
int ocall_open(const char *pathname, int flags,
bool has_mode, unsigned mode)
{
if (has_mode) {
return open(pathname, flags, (mode_t)mode);
}
else {
return open(pathname, flags);
}
}
int ocall_openat(int dirfd,
const char *pathname, int flags,
bool has_mode, unsigned mode)
{
if (has_mode) {
return openat(dirfd, pathname, flags, (mode_t)mode);
}
else {
return openat(dirfd, pathname, flags);
}
}
int ocall_close(int fd)
{
return close(fd);
}
ssize_t ocall_read(int fd, void *buf, size_t read_size)
{
if (buf != NULL) {
return read(fd, buf, read_size);
}
else {
return -1;
}
}
off_t ocall_lseek(int fd, off_t offset, int whence)
{
return lseek(fd, offset, whence);
}
int ocall_ftruncate(int fd, off_t length)
{
return ftruncate(fd, length);
}
int ocall_fsync(int fd)
{
return fsync(fd);
}
int ocall_fdatasync(int fd)
{
return fdatasync(fd);
}
int ocall_isatty(int fd)
{
return isatty(fd);
}
void ocall_fdopendir(int fd, void **dirp)
{
if (dirp) {
*(DIR **)dirp = fdopendir(fd);
}
}
void *ocall_readdir(void *dirp)
{
DIR *p_dirp = (DIR *)dirp;
return readdir(p_dirp);
}
void ocall_rewinddir(void *dirp)
{
DIR *p_dirp = (DIR *)dirp;
if (p_dirp) {
rewinddir(p_dirp);
}
}
void ocall_seekdir(void *dirp, long loc)
{
DIR *p_dirp = (DIR *)dirp;
if (p_dirp) {
seekdir(p_dirp, loc);
}
}
long ocall_telldir(void *dirp)
{
DIR *p_dirp = (DIR *)dirp;
if (p_dirp) {
return telldir(p_dirp);
}
return -1;
}
int ocall_closedir(void* dirp)
{
DIR *p_dirp = (DIR *)dirp;
if (p_dirp) {
return closedir(p_dirp);
}
return -1;
}
int ocall_fstat(int fd, void *buf, unsigned int buf_len)
{
return fstat(fd, (struct stat *)buf);
}
int ocall_fstatat(int dirfd, const char *pathname, void *buf,
unsigned int buf_len, int flags)
{
return fstatat(dirfd, pathname, (struct stat *)buf, flags);
}
int ocall_mkdirat(int dirfd, const char *pathname, unsigned mode)
{
return mkdirat(dirfd, pathname, (mode_t)mode);
}
int ocall_link(const char *oldpath, const char *newpath)
{
return link(oldpath, newpath);
}
int ocall_linkat(int olddirfd, const char *oldpath,
int newdirfd, const char *newpath, int flags)
{
return linkat(olddirfd, oldpath, newdirfd, newpath, flags);
}
int ocall_unlinkat(int dirfd, const char *pathname, int flags)
{
return unlinkat(dirfd, pathname, flags);
}
ssize_t ocall_readlinkat(int dirfd, const char *pathname,
char *buf, size_t bufsiz)
{
return readlinkat(dirfd, pathname, buf, bufsiz);
}
int ocall_renameat(int olddirfd, const char *oldpath,
int newdirfd, const char *newpath)
{
return renameat(olddirfd, oldpath, newdirfd, newpath);
}
int ocall_symlinkat(const char *target, int newdirfd,
const char *linkpath)
{
return symlinkat(target, newdirfd, linkpath);
}
int ocall_ioctl(int fd, unsigned long request,
void *arg, unsigned int arg_len)
{
/* support just int *arg temporally */
return ioctl(fd, request, (int *)arg);
}
int ocall_fcntl(int fd, int cmd)
{
return fcntl(fd, cmd);
}
int ocall_fcntl_long(int fd, int cmd, long arg)
{
return fcntl(fd, cmd, arg);
}
ssize_t ocall_readv(int fd, char *iov_buf,
unsigned int buf_size, int iovcnt,
bool has_offset, off_t offset)
{
struct iovec *iov = (struct iovec *)iov_buf;
ssize_t ret;
int i;
for (i = 0; i < iovcnt; i++) {
iov[i].iov_base = iov_buf + (unsigned)(uintptr_t)iov[i].iov_base;
}
if (has_offset)
ret = preadv(fd, iov, iovcnt, offset);
else
ret = readv(fd, iov, iovcnt);
return ret;
}
ssize_t ocall_writev(int fd, char *iov_buf,
unsigned int buf_size, int iovcnt,
bool has_offset, off_t offset)
{
struct iovec *iov = (struct iovec *)iov_buf;
int i;
ssize_t ret;
for (i = 0; i < iovcnt; i++) {
iov[i].iov_base = iov_buf + (unsigned)(uintptr_t)iov[i].iov_base;
}
if (has_offset)
ret = pwritev(fd, iov, iovcnt, offset);
else
ret = writev(fd, iov, iovcnt);
return ret;
}
int ocall_realpath(const char *path, char *buf, unsigned int buf_len)
{
char* val = NULL;
val = realpath(path, buf);
if (val != NULL) {
return 0;
}
return -1;
}
int ocall_posix_fallocate(int fd, off_t offset, off_t len)
{
return posix_fallocate(fd, offset, len);
}
int ocall_poll(void *fds, unsigned nfds, int timeout,
unsigned int fds_len)
{
return poll((struct pollfd *)fds, (nfds_t)nfds, timeout);
}
int ocall_getopt(int argc, char *argv_buf, unsigned int argv_buf_len,
const char *optstring)
{
int ret;
int i;
char **argv = (char **)argv_buf;
for (i=0; i < argc; i++) {
argv[i] = argv_buf + (uintptr_t)argv[i];
}
return getopt(argc, argv, optstring);
}
ssize_t ocall_getrandom(void *buf, size_t buflen, unsigned int flags)
{
return getrandom(buf, buflen, flags);
}
int ocall_sched_yield()
{
return sched_yield();
}
int ocall_get_errno()
{
return errno;
}

View File

@ -0,0 +1,50 @@
/*
* Copyright (C) 2019 Intel Corporation. All rights reserved.
* SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
*/
#include <stdlib.h>
#include <pthread.h>
int ocall_pthread_rwlock_init(void **rwlock, void *attr)
{
int ret = 0;
*rwlock = malloc(sizeof(pthread_rwlock_t));
if (*rwlock == NULL)
return -1;
ret = pthread_rwlock_init((pthread_rwlock_t *)*rwlock, NULL);
if (ret != 0) {
free(*rwlock);
*rwlock = NULL;
}
(void)attr;
return ret;
}
int ocall_pthread_rwlock_destroy(void *rwlock)
{
pthread_rwlock_t *lock = (pthread_rwlock_t *)rwlock;
int ret;
ret = pthread_rwlock_destroy(lock);
free(lock);
return ret;
}
int ocall_pthread_rwlock_rdlock(void *rwlock)
{
return pthread_rwlock_rdlock((pthread_rwlock_t *)rwlock);
}
int ocall_pthread_rwlock_wrlock(void *rwlock)
{
return pthread_rwlock_wrlock((pthread_rwlock_t *)rwlock);
}
int ocall_pthread_rwlock_unlock(void *rwlock)
{
return pthread_rwlock_unlock((pthread_rwlock_t *)rwlock);
}

View File

@ -0,0 +1,10 @@
/*
* Copyright (C) 2019 Intel Corporation. All rights reserved.
* SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
*/
#include <signal.h>
int ocall_raise(int sig)
{
return raise(sig);
}

View File

@ -0,0 +1,73 @@
/*
* Copyright (C) 2019 Intel Corporation. All rights reserved.
* SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
*/
#include <sys/types.h>
#include <sys/socket.h>
#include <stdint.h>
#include <stddef.h>
int ocall_socket(int domain, int type, int protocol)
{
return socket(domain, type, protocol);
}
int ocall_getsockopt(int sockfd, int level, int optname, void *val_buf,
unsigned int val_buf_size, void *len_buf)
{
return getsockopt(sockfd, level, optname, val_buf,
(socklen_t *)len_buf);
}
ssize_t ocall_sendmsg(int sockfd, void *msg_buf,
unsigned int msg_buf_size, int flags)
{
struct msghdr *msg = (struct msghdr *)msg_buf;
int i;
ssize_t ret;
if (msg->msg_name != NULL)
msg->msg_name = msg_buf + (unsigned)(uintptr_t)msg->msg_name;
if (msg->msg_control != NULL)
msg->msg_control = msg_buf + (unsigned)(uintptr_t)msg->msg_control;
if (msg->msg_iov != NULL) {
msg->msg_iov = msg_buf + (unsigned)(uintptr_t)msg->msg_iov;
for (i = 0; i < msg->msg_iovlen; i++) {
msg->msg_iov[i].iov_base = msg_buf + (unsigned)(uintptr_t)
msg->msg_iov[i].iov_base;
}
}
return sendmsg(sockfd, msg, flags);
}
ssize_t ocall_recvmsg(int sockfd, void *msg_buf, unsigned int msg_buf_size,
int flags)
{
struct msghdr *msg = (struct msghdr *)msg_buf;
int i;
ssize_t ret;
if (msg->msg_name != NULL)
msg->msg_name = msg_buf + (unsigned)(uintptr_t)msg->msg_name;
if (msg->msg_control != NULL)
msg->msg_control = msg_buf + (unsigned)(uintptr_t)msg->msg_control;
if (msg->msg_iov != NULL) {
msg->msg_iov = msg_buf + (unsigned)(uintptr_t)msg->msg_iov;
for (i = 0; i <msg->msg_iovlen; i++) {
msg->msg_iov[i].iov_base = msg_buf + (unsigned)(uintptr_t)
msg->msg_iov[i].iov_base;
}
}
return recvmsg(sockfd, msg, flags);
}
int ocall_shutdown(int sockfd, int how)
{
return shutdown(sockfd, how);
}

View File

@ -0,0 +1,47 @@
/*
* Copyright (C) 2019 Intel Corporation. All rights reserved.
* SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
*/
#include <stdbool.h>
#include <sys/stat.h>
#include <time.h>
#include <fcntl.h>
/** time clock **/
int ocall_clock_gettime(unsigned clock_id, void *tp_buf,
unsigned int tp_buf_size)
{
return clock_gettime((clockid_t)clock_id,
(struct timespec *)tp_buf);
}
int ocall_clock_getres(int clock_id, void *res_buf,
unsigned int res_buf_size)
{
return clock_getres(clock_id, (struct timespec *)res_buf);
}
int ocall_utimensat(int dirfd, const char *pathname,
const void *times_buf,
unsigned int times_buf_size, int flags)
{
return utimensat(dirfd, pathname, (struct timespec *)times_buf, flags);
}
int ocall_futimens(int fd, const void *times_buf,
unsigned int times_buf_size)
{
return futimens(fd, (struct timespec *)times_buf);
}
int ocall_clock_nanosleep(unsigned clock_id, int flags,
const void *req_buf, unsigned int req_buf_size,
const void *rem_buf, unsigned int rem_buf_size)
{
return clock_nanosleep((clockid_t)clock_id, flags,
(struct timespec *)req_buf,
(struct timespec *)rem_buf);
}

View File

@ -10,8 +10,6 @@
#include <stdbool.h>
#include <assert.h>
#include <time.h>
#include <sys/time.h>
#include <sys/timeb.h>
#include <string.h>
#include <stdio.h>
#include <stdlib.h>
@ -19,15 +17,25 @@
#include <stdarg.h>
#include <ctype.h>
#include <pthread.h>
#include <signal.h>
#include <semaphore.h>
#include <limits.h>
#include <dirent.h>
#include <fcntl.h>
#include <unistd.h>
#include <poll.h>
#include <sched.h>
#include <errno.h>
#include <sys/socket.h>
#include <netinet/in.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <sys/mman.h>
#include <netinet/in.h>
#include <sys/time.h>
#include <sys/timeb.h>
#include <sys/uio.h>
#include <sys/ioctl.h>
#include <sys/socket.h>
#include <sys/resource.h>
#ifdef __cplusplus
extern "C" {
@ -56,7 +64,6 @@ typedef pthread_t korp_thread;
|| defined(BUILD_TARGET_AMD_64) \
|| defined(BUILD_TARGET_AARCH64)
#include <signal.h>
#include <setjmp.h>
#define OS_ENABLE_HW_BOUND_CHECK

View File

@ -10,8 +10,6 @@
#include <stdbool.h>
#include <assert.h>
#include <time.h>
#include <sys/time.h>
#include <sys/timeb.h>
#include <string.h>
#include <stdio.h>
#include <stdlib.h>
@ -19,14 +17,24 @@
#include <stdarg.h>
#include <ctype.h>
#include <pthread.h>
#include <signal.h>
#include <semaphore.h>
#include <limits.h>
#include <dirent.h>
#include <fcntl.h>
#include <unistd.h>
#include <poll.h>
#include <sched.h>
#include <errno.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <sys/mman.h>
#include <sys/time.h>
#include <sys/timeb.h>
#include <sys/uio.h>
#include <sys/ioctl.h>
#include <sys/socket.h>
#include <sys/resource.h>
#ifdef __cplusplus
extern "C" {
@ -55,7 +63,6 @@ typedef pthread_t korp_thread;
|| defined(BUILD_TARGET_AMD_64) \
|| defined(BUILD_TARGET_AARCH64)
#include <signal.h>
#include <setjmp.h>
#define OS_ENABLE_HW_BOUND_CHECK

View File

@ -41,7 +41,7 @@ bh_log(LogLevel log_level, const char *file, int line, const char *fmt, ...)
snprintf(buf, sizeof(buf), "%02u:%02u:%02u:%03u", h, m, s, mills);
os_printf("[%s - %X]: ", buf, (uint32)self);
os_printf("[%s - %X]: ", buf, (uint32)(uintptr_t)self);
if (file)
os_printf("%s, line %d, ", file, line);

View File

@ -1,33 +1,29 @@
Build WAMR core (iwasm)
Build WAMR vmcore (iwasm)
=========================
It is recommended to use the [WAMR SDK](../wamr-sdk) tools to build a project that integrates the WAMR. This document introduces how to build the WAMR minimal product which is vmcore only (no app-framework and app-mgr) for multiple platforms.
## WAMR vmcore cmake building configurations
## iwasm VM core CMake building configurations
By including the script `runtime_lib.cmake` under folder [build-scripts](../build-scripts) in CMakeList.txt, it is easy to build minimal product with CMake.
By including the script `runtime_lib.cmake` under folder [build-scripts](../build-scripts) in CMakeList.txt, it is easy to build minimal product with cmake.
```cmake
# add this in your CMakeList.text
# add this into your CMakeList.txt
include (${WAMR_ROOT_DIR}/build-scripts/runtime_lib.cmake)
add_library(vmlib ${WAMR_RUNTIME_LIB_SOURCE})
```
The script `runtime_lib.cmake` defined a number of variables for configuring the WAMR runtime features. You can set these variables in your CMakeList.txt or pass the configurations from cmake command line.
The script `runtime_lib.cmake` defines a number of variables for configuring the WAMR runtime features. You can set these variables in your CMakeList.txt or pass the configurations from cmake command line.
#### **Configure platform and architecture**
- **WAMR_BUILD_PLATFORM**: set the target platform. It can be set to any platform name (folder name) under folder [core/shared/platform](../core/shared/platform).
- **WAMR_BUILD_TARGET**: set the target CPU architecture. Current supported targets: X86_64, X86_32, AArch64, ARM, THUMB, XTENSA and MIPS. For AArch64, ARM and THUMB, the format is <arch>[<sub-arch>][_VFP] where <sub-arch> is the ARM sub-architecture and the "_VFP" suffix means VFP coprocessor registers s0-s15 (d0-d7) are used for passing arguments or returning results in standard procedure-call. Both <sub-arch> and "_VFP" are optional. e.g. AARCH64, AARCH64V8, AARCHV8.1, ARMV7, ARMV7_VFP, THUMBV7, THUMBV7_VFP and so on.
- **WAMR_BUILD_TARGET**: set the target CPU architecture. Current supported targets are: X86_64, X86_32, AArch64, ARM, THUMB, XTENSA and MIPS. For AArch64, ARM and THUMB, the format is \<arch>\[\<sub-arch>]\[_VFP] where \<sub-arch> is the ARM sub-architecture and the "_VFP" suffix means VFP coprocessor registers s0-s15 (d0-d7) are used for passing arguments or returning results in standard procedure-call. Both \<sub-arch> and "_VFP" are optional, e.g. AARCH64, AARCH64V8, AARCHV8.1, ARMV7, ARMV7_VFP, THUMBV7, THUMBV7_VFP and so on.
```bash
cmake -DWAMR_BUILD_PLATFORM=linux -DWAMR_BUILD_TARGET=ARM
```
```bash
cmake -DWAMR_BUILD_PLATFORM=linux -DWAMR_BUILD_TARGET=ARM
```
#### **Configure interpreter**
@ -35,18 +31,18 @@ The script `runtime_lib.cmake` defined a number of variables for configuring the
- **WAMR_BUILD_FAST_INTERP**=1/0build fast (default) or classic WASM interpreter.
NOTE: the fast interpreter will run ~2X faster than classic interpreter, but it consumes about 2X memory to hold the WASM bytecode code.
NOTE: the fast interpreter runs ~2X faster than classic interpreter, but consumes about 2X memory to hold the WASM bytecode code.
#### **Configure AoT and JIT**
- **WAMR_BUILD_AOT**=1/0
- **WAMR_BUILD_JIT**=1/0 , (Disabled if no set)
- **WAMR_BUILD_AOT**=1/0, default to enable if not set
- **WAMR_BUILD_JIT**=1/0 , default to disable if not set
#### **Configure LIBC**
- **WAMR_BUILD_LIBC_BUILTIN**=1/0, default to enable if no set
- **WAMR_BUILD_LIBC_BUILTIN**=1/0, default to enable if not set
- **WAMR_BUILD_LIBC_WASI**=1/0, default to enable if no set
- **WAMR_BUILD_LIBC_WASI**=1/0, default to enable if not set
#### **Enable Multi-Module feature**
@ -55,7 +51,8 @@ The script `runtime_lib.cmake` defined a number of variables for configuring the
#### **Enable WASM mini loader**
- **WAMR_BUILD_MINI_LOADER**=1/0, default to disable if not set
Note: the mini loader doesn't check the integrity of the WASM binary file, developer must ensure that the WASM file is not mal-formed.
> Note: the mini loader doesn't check the integrity of the WASM binary file, developer must ensure that the WASM file is well-formed.
#### **Enable shared memory feature**
- **WAMR_BUILD_SHARED_MEMORY**=1/0, default to disable if not set
@ -68,7 +65,7 @@ Note: the mini loader doesn't check the integrity of the WASM binary file, devel
> Note: The dependent feature of lib pthread such as the `shared memory` and `thread manager` will be enabled automatically.
#### **Disable boundary check with hardware trap in AOT or JIT mode**
- **WAMR_DISABLE_HW_BOUND_CHECK=1, default to enable if not set and supported by platform
- **WAMR_DISABLE_HW_BOUND_CHECK**=1/0, default to enable if not set and supported by platform
> Note: by default only platform linux/darwin/android/vxworks 64-bit will enable boundary check with hardware trap in AOT or JIT mode, and the wamrc tool will generate AOT code without boundary check instructions in all 64-bit targets except SGX to improve performance.
**Combination of configurations:**
@ -85,8 +82,6 @@ Or if we want to enable interpreter, disable AOT and WASI, and build as X86_32,
cmake .. -DWAMR_BUILD_INTERP=1 -DWAMR_BUILD_AOT=0 -DWAMR_BUILD_LIBC_WASI=0 -DWAMR_BUILD_TARGET=X86_32
```
## Cross compilation
If you are building for ARM architecture on a X86 development machine, you can use the `CMAKE_TOOLCHAIN_FILE` to set the toolchain file for cross compling.
@ -97,9 +92,7 @@ cmake .. -DCMAKE_TOOLCHAIN_FILE=$TOOL_CHAIN_FILE \
-DWAMR_BUILD_TARGET=ARM
```
Refer to toochain sample file [`samples/simple/profiles/arm-interp/toolchain.cmake`](../samples/simple/profiles/arm-interp/toolchain.cmake) for how to build mini product for ARM target architecture.
Refer to toolchain sample file [`samples/simple/profiles/arm-interp/toolchain.cmake`](../samples/simple/profiles/arm-interp/toolchain.cmake) for how to build mini product for ARM target architecture.
Linux
-------------------------
@ -147,40 +140,14 @@ cmake .. -DWAMR_BUILD_JIT=1
make
```
Linux SGX (Intel Software Guard Extention)
Linux SGX (Intel Software Guard Extension)
-------------------------
First of all please install the [Intel SGX SDK](https://software.intel.com/en-us/sgx/sdk).
After installing dependencies, build the source code:
``` Bash
source <SGX_SDK dir>/environment
cd product-mini/platforms/linux-sgx/
mkdir build
cd build
cmake ..
make
```
This builds the libraries used by SGX enclave sample, the generated file libvmlib.a and libextlib.a will be copied to enclave-sample folder.
Then build the enclave sample:
``` Bash
source <SGX_SDK dir>/environment
cd enclave-sample
make
```
The binary file app will be generated.
To run the sample:
``` Bash
source <SGX_SDK dir>/environment
./app
```
Please see [Build and Port WAMR vmcore for Linux SGX](./linux_sgx.md) for the details.
MacOS
-------------------------
Make sure to install Xcode from App Store firstly, and install cmake.
If you use Homebrew, install cmake from the command line:
@ -197,7 +164,7 @@ cmake ..
make
```
Note:
WAMR provides some features which can be easily configured by passing options to cmake, please see [Linux platform](./build_wamr.md#linux) for details. Currently in MacOS, interpreter, AoT, and builtin libc are enabled by default.
WAMR provides some features which can be easily configured by passing options to cmake, please see [WAMR vmcore cmake building configurations](./build_wamr.md#wamr-vmcore-cmake-building-configurations) for details. Currently in MacOS, interpreter, AoT, and builtin libc are enabled by default.
VxWorks
-------------------------
@ -227,7 +194,7 @@ shared libraries (libc.so.1, libllvm.so.1 or libgnu.so.1 depending on the VSB,
libunix.so.1) to a supported file system (eg: romfs).
Note:
WAMR provides some features which can be easily configured by passing options to cmake, please see [Linux platform](./build_wamr.md#linux) for details. Currently in VxWorks, interpreter and builtin libc are enabled by default.
WAMR provides some features which can be easily configured by passing options to cmake, please see [WAMR vmcore cmake building configurations](./build_wamr.md#wamr-vmcore-cmake-building-configurations) for details. Currently in VxWorks, interpreter and builtin libc are enabled by default.
Zephyr
-------------------------
@ -245,7 +212,7 @@ source ../../zephyr-env.sh
```
Note:
WAMR provides some features which can be easily configured by passing options to cmake, please see [Linux platform](./build_wamr.md#linux) for details. Currently in Zephyr, interpreter, AoT and builtin libc are enabled by default.
WAMR provides some features which can be easily configured by passing options to cmake, please see [WAMR vmcore cmake building configurations](./build_wamr.md#wamr-vmcore-cmake-building-configurations) for details. Currently in Zephyr, interpreter, AoT and builtin libc are enabled by default.
AliOS-Things

View File

@ -6,8 +6,6 @@ Embedding WAMR guideline
## The runtime initialization
``` C
char *buffer, error_buf[128];
wasm_module_t module;
@ -16,64 +14,61 @@ Embedding WAMR guideline
wasm_exec_env_t exec_env;
uint32 size, stack_size = 8092, heap_size = 8092;
// initialize the wasm runtime by default configurations
/* initialize the wasm runtime by default configurations */
wasm_runtime_init();
// read WASM file into a memory buffer
/* read WASM file into a memory buffer */
buffer = read_wasm_binary_to_buffer(…, &size);
// Add it below if runtime needs to export native functions to WASM APP
// wasm_runtime_register_natives(...)
/* add line below if we want to export native functions to WASM app */
wasm_runtime_register_natives(...);
// parse the WASM file from buffer and create a WASM module
/* parse the WASM file from buffer and create a WASM module */
module = wasm_runtime_load(buffer, size, error_buf, sizeof(error_buf));
// create an instance of the WASM module (WASM linear memory is ready)
module_inst = wasm_runtime_instantiate(module,
stack_size,
heap_size,
error_buf,
sizeof(error_buf));
/* create an instance of the WASM module (WASM linear memory is ready) */
module_inst = wasm_runtime_instantiate(module, stack_size, heap_size,
error_buf, sizeof(error_buf));
```
The `wasm_runtime_init()` will use the default memory allocator from the [`core/shared/platform`](../core/shared/platform) for the runtime memory management.
The `wasm_runtime_init()` uses the default memory allocator os_malloc/os_free function from the [`core/shared/platform`](../core/shared/platform) for the runtime memory management.
The WAMR supports to restrict its all memory allocations in a raw buffer. It ensures the dynamics by the WASM applications won't harm the system availability, which is extremely important for embedded systems. This can be done by using `wasm_runtime_full_init()`. This function also allows you to configure the native APIs for exporting to WASM app.
WAMR supports to restrict its all memory allocations in a raw buffer. It ensures the dynamic memories used by the WASM applications won't harm the system availability, which is extremely important for embedded systems. This can be done by using `wasm_runtime_full_init()`. This function also allows you to configure the native API's for exporting to WASM app, and set the maximum thread number when multi-thread feature is enabled.
Refer to the following sample:
```c
// the native functions that will be exported to WASM app
/* the native functions that will be exported to WASM app */
static NativeSymbol native_symbols[] = {
EXPORT_WASM_API_WITH_SIG(display_input_read, "(*)i"),
EXPORT_WASM_API_WITH_SIG(display_flush, "(iiii*)")
};
// all the runtime memory allocations are retricted in the global_heap_buf array
/* all the runtime memory allocations are retricted in the global_heap_buf array */
static char global_heap_buf[512 * 1024];
RuntimeInitArgs init_args;
memset(&init_args, 0, sizeof(RuntimeInitArgs));
// configure the memory allocator for the runtime
/* configure the memory allocator for the runtime */
init_args.mem_alloc_type = Alloc_With_Pool;
init_args.mem_alloc_option.pool.heap_buf = global_heap_buf;
init_args.mem_alloc_option.pool.heap_size = sizeof(global_heap_buf);
// configure the native functions being exported to WASM app
/* configure the native functions being exported to WASM app */
init_args.native_module_name = "env";
init_args.n_native_symbols = sizeof(native_symbols) / sizeof(NativeSymbol);
init_args.native_symbols = native_symbols;
/* set maximum thread number if needed when multi-thread is enabled,
the default value is 4 */
init_args.max_thread_num = max_thread_num;
/* initialize runtime environment with user configurations*/
if (!wasm_runtime_full_init(&init_args)) {
return -1;
return -1;
}
```
## Native calls WASM functions and passes parameters
After a module is instantiated, the runtime native can lookup WASM functions by the names and call them.
@ -81,28 +76,27 @@ After a module is instantiated, the runtime native can lookup WASM functions by
```c
unit32 argv[2];
// lookup a WASM function by its name.
// The function signature can NULL here
/* lookup a WASM function by its name
The function signature can NULL here */
func = wasm_runtime_lookup_function(module_inst, "fib", NULL);
// creat a excution environment which can be used by executing WASM functions
/* creat an execution environment to execute the WASM functions */
exec_env = wasm_runtime_create_exec_env(module_inst, stack_size);
// arguments are always transferred in 32 bits element
/* arguments are always transferred in 32-bit element */
argv[0] = 8;
// call the WASM function
/* call the WASM function */
if (wasm_runtime_call_wasm(exec_env, func, 1, argv) ) {
/* the return value is stored in argv[0] */
printf("fib function return: %d\n", argv[0]);
/* the return value is stored in argv[0] */
printf("fib function return: %d\n", argv[0]);
}
else {
printf("%s\n", wasm_runtime_get_exception(module_inst));
/* exception is thrown if call fails */
printf("%s\n", wasm_runtime_get_exception(module_inst));
}
```
The parameters are transferred in an array of 32 bits elements. For parameters that occupy 4 or fewer bytes, each parameter can be a single array element. For parameters in types like double or int64, each parameter will take two array elements. The function return value will be sent back in the first one or two elements of the array according to the value type. See the sample code below:
```c
@ -116,69 +110,60 @@ The parameters are transferred in an array of 32 bits elements. For parameters t
argv[0] = arg1;
argv[1] = arg2;
// use memory copy for 8 bytes parameters rather than
// *(double*)(&argv[2]) = arg3 here because some archs
// like ARM, MIPS requires address is 8 aligned.
// Or use the aligned malloc or compiler align attribute
// to ensure the array address is 8 bytes aligned
/**
* use memory copy for 8-byte parameters rather than
* *(double*)(&argv[2]) = arg3 here because some archs
* like ARM, MIPS require the address must be 8-byte aligned.
* Or use the aligned malloc or compiler align attribute
* to ensure the array address is 8-byte aligned
*/
memcpy(&argv[2], &arg3, sizeof(arg3));
memcpy(&argv[4], &arg4, sizeof(arg4));
//
// attention: the arg number is 6 here since both
// arg3 and arg4 each takes 2 elements
//
/* attention: the arg number is 6 here since both
arg3 and arg4 each takes 2 elements */
wasm_runtime_call_wasm(exec_env, func, 6, argv);
// if the return value is type of 8 bytes, it takes
// the first two array elements
/* if the return value is type of 8 bytes, it takes
the first two array elements */
memcpy(&ret, &argv[0], sizeof(ret));
```
## Pass buffer to WASM function
If we need to transfer a buffer to WASM function, we can pass the buffer address through a parameter. **Attention**: The sandbox will forbid the WASM code to access outside memory, we must **allocate the buffer from WASM instance's own memory space and pass the buffer address in instance's space (not the runtime native address)**.
There are two runtime APIs available for this purpose.
```c
/*
* description: malloc a buffer from instance's private memory space.
*
* return: the buffer address in instance's memory space (pass to the WASM funciton)
* p_native_addr: return the native address of allocated memory
* size: the buffer size to allocate
*/
/**
* malloc a buffer from instance's private memory space.
*
* return: the buffer address in instance's memory space (pass to the WASM funciton)
* p_native_addr: return the native address of allocated memory
* size: the buffer size to allocate
*/
int32_t
wasm_runtime_module_malloc(wasm_module_inst_t module_inst,
uint32_t size,
void **p_native_addr);
uint32_t size, void **p_native_addr);
/*
* description: malloc a buffer from instance's private memory space,
* and copy the data from another native buffer to it.
* return: the buffer address in instance's memory space (pass to the WASM funciton)
* src: the native buffer address
* size: the size of buffer to be allocated and copy data
*/
/**
* malloc a buffer from instance's private memory space,
* and copy the data from another native buffer to it.
*
* return: the buffer address in instance's memory space (pass to the WASM funciton)
* src: the native buffer address
* size: the size of buffer to be allocated and copy data
*/
int32
wasm_runtime_module_dup_data(WASMModuleInstanceCommon *module_inst,
const char *src,
uint32 size);
const char *src, uint32 size);
// free the memory allocated from module memory space
/* free the memory allocated from module memory space */
void
wasm_runtime_module_free(wasm_module_inst_t module_inst, int32_t ptr);
```
Usage sample:
```c
@ -186,29 +171,23 @@ char * buffer = NULL;
int32_t buffer_for_wasm;
buffer_for_wasm = wasm_runtime_module_malloc(module_inst, 100, &buffer);
if(buffer_for_wasm != 0)
{
if (buffer_for_wasm != 0) {
unit32 argv[2];
strncpy(buffer, "hello", 100); // use native address for accessing in runtime
argv[0] = buffer_for_wasm; // pass the buffer address for WASM space.
argv[1] = 100; // the size of buffer
strncpy(buffer, "hello", 100); /* use native address for accessing in runtime */
argv[0] = buffer_for_wasm; /* pass the buffer address for WASM space */
argv[1] = 100; /* the size of buffer */
wasm_runtime_call_wasm(exec_env, func, 2, argv);
// it is runtime responsibility to release the memory,
// unless the WASM app will free the passed pointer in its code
/* it is runtime embedder's responsibility to release the memory,
unless the WASM app will free the passed pointer in its code */
wasm_runtime_module_free(module_inst, buffer_for_wasm);
}
```
## Pass structured data to WASM function
We can't pass structure data or class objects through the pointer since the memory layout can different in two worlds. The way to do it is serialization. Refer to [export_native_api.md](./export_native_api.md) for the details.
## Execute wasm functions in multiple threads
The `exec_env` is not thread safety, it will cause unexpected behavior if the same `exec_env` is used in multiple threads. However, we've provided two ways to execute wasm functions concurrently:
@ -219,7 +198,7 @@ The `exec_env` is not thread safety, it will cause unexpected behavior if the sa
*spawn exec_env:*
`spawn exec_env` API spawn a `new_exec_env` base on the original `exec_env`, use can use it in other threads:
`spawn exec_env` API spawns a `new_exec_env` base on the original `exec_env`, use can use it in other threads:
```C
new_exec_env = wasm_runtime_spawn_exec_env(exec_env);
@ -257,7 +236,7 @@ init_args.max_thread_num = THREAD_NUM;
/* If this init argument is not set, the default maximum thread number is 4 */
```
**Note2: The wasm application should be built with `--shared-memory` and `-pthread` enabled:**
**Note2: The wasm application should be built with `--shared-memory` and `-pthread` enabled:**
```bash
/opt/wasi-sdk/bin/clang -o test.wasm test.c -nostdlib -pthread \
@ -274,8 +253,6 @@ init_args.max_thread_num = THREAD_NUM;
[Here](../samples/spawn-thread) is a sample to show how to use these APIs.
## The deinitialization procedure
```
@ -286,8 +263,6 @@ init_args.max_thread_num = THREAD_NUM;
```
## Native calling WASM function working flow
![WAMR embed diagram](./pics/embed.PNG "WAMR embed architecture diagram")

197
doc/linux_sgx.md Normal file
View File

@ -0,0 +1,197 @@
Build and Port WAMR vmcore (iwasm) for Linux SGX
================================================
Build WAMR vmcore (iwasm) for Linux SGX
---------------------------------------
First of all please install the [Intel SGX SDK](https://software.intel.com/en-us/sgx/sdk), v2.8 or later is required, and it is recommended to install the SDK to /opt/intel/sgxsdk.
After installing the dependencies, build the source code:
``` Bash
source <SGX_SDK dir>/environment
cd product-mini/platforms/linux-sgx/
mkdir build
cd build
cmake ..
make
```
This builds two libraries required by SGX application:
- libvmlib.a for Enclave part
- libvmlib_untrusted.a for App part
**Note:** WAMR provides some features which can be easily configured by passing options to cmake, please see [WAMR vmcore cmake building configurations](./build_wamr.md#wamr-vmcore-cmake-building-configurations) for the details. Currently in Linux SGX, fast interpreter, AOT, libc-builtin, libc-WASI and lib-pthread are enabled by default.
Then build the enclave sample:
``` Bash
source <SGX_SDK dir>/environment
cd enclave-sample
make
```
The binary file iwasm will be generated. To run the sample:
``` Bash
source <SGX_SDK dir>/environment
iwasm [-options] wasm_file [args...]
or:
iwasm [-options] aot_file [args...]
```
Port WAMR vmcore for Linux SGX
------------------------------
The enclave-sample creates a sample to embed wamr vmlib of Enclave part and App part to an SGX application. To port WAMR vmcore lib to SGX application, there are some steps to do:
**Step 1: Add "sgx_wamr.edl" and "sgx_pthread.edl" into EDL file, e.g. Enclave.edl:**
```bash
from "sgx_pthread.edl" import *;
from "sgx_wamr.edl" import *;
```
The sgx_wamr.edl is under ${WAMR_ROOT}/core/shared/platform/linux-sgx, so please **add it to the search path list** when generating Enclave_u.c and Enclave_t.c from Enclave.edl:
```bash
@cd App && $(SGX_EDGER8R) --untrusted ../Enclave/Enclave.edl \
--search-path ../Enclave \
--search-path $(SGX_SDK)/include \
--search-path $(WAMR_ROOT)/core/shared/platform/linux-sgx
```
```bash
@cd Enclave && $(SGX_EDGER8R) --trusted ../Enclave/Enclave.edl \
--search-path ../Enclave \
--search-path $(SGX_SDK)/include \
--search-path $(WAMR_ROOT)/core/shared/platform/linux-sgx
```
**Step 2: Link libvmlib.a to Enclave part and link libvmlib_untrusted.a to App part:**
```makefile
Enclave_Link_Flags := ... libvmlib.a ...
```
```makefile
App_Link_Flags := ... libvmlib_untrusted.a ...
```
**And link SGX pthread lib to Enclave part:**
```makefile
Enclave_Link_Flags := ... -lsgx_pthread ...
```
**Step 3: Add WAMR folders and SGX SDK folders to Enclave include path:**
```makefile
Enclave_Include_Paths := ... -I$(WAMR_ROOT)/core/iwasm/include \
-I$(WAMR_ROOT)/core/shared/utils \
-I$(WAMR_ROOT)/core/shared/platform/linux-sgx \
-I$(SGX_SDK)/include \
-I$(SGX_SDK)/include/tlibc \
-I$(SGX_SDK)/include/stlport
```
**Step 4: Configure reserved memory and thread info in file Enclave config file (e.g. Enclave.config.xml) to support WAMR AOT and multi-thread, e.g:**
```xml
<ReservedMemMaxSize>0x400000</ReservedMemMaxSize>
<ReservedMemExecutable>1</ReservedMemExecutable>
<TCSNum>10</TCSNum>
```
**Step 5: To support log output and os_printf() function in Enclave, please implement an ocall_print function, e.g. in Enclave.edl, add:**
```cpp
untrusted {
void ocall_print([in, string]const char* str);
};
```
In App part, add:
```cpp
void
ocall_print(const char* str)
{
printf("%s", str);
}
```
And in Enclave part, set the print function:
```cpp
#include "wasm_export.h"
#include "bh_platform.h"
extern "C" {
typedef void (*os_print_function_t)(const char* message);
extern void os_set_print_function(os_print_function_t pf);
void
enclave_print(const char *message)
{
ocall_print(message);
}
}
// In the beginning of Enclave initialization, add:
os_set_print_function(enclave_print);
```
Embed WAMR vmcore in Linux SGX
------------------------------
Normally we can embed WAMR vmcore in Linux SGX by calling the vmcore exported API's, see [Embed WAMR guide](./embed_wamr.md) for the details. And the the ecall_iwasm_main() function in file Enclave.cpp of enclave-sample also provides sample to invoke wasm app main function with wasm file buffer:
```cpp
void
ecall_iwasm_main(uint8_t *wasm_file_buf, uint32_t wasm_file_size);
```
The enclave-sample also wraps an ecall function to receive commands from App to Enclave, and handle the commands in Enclave by calling the related WAMR vmcore API. The commands and related API's are:
```cpp
typedef enum EcallCmd {
CMD_INIT_RUNTIME = 0, /* wasm_runtime_init/full_init() */
CMD_LOAD_MODULE, /* wasm_runtime_load() */
CMD_INSTANTIATE_MODULE, /* wasm_runtime_instantiate() */
CMD_LOOKUP_FUNCTION, /* wasm_runtime_lookup_function() */
CMD_CREATE_EXEC_ENV, /* wasm_runtime_create_exec_env() */
CMD_CALL_WASM, /* wasm_runtime_call_wasm */
CMD_EXEC_APP_FUNC, /* wasm_application_execute_func() */
CMD_EXEC_APP_MAIN, /* wasm_application_execute_main() */
CMD_GET_EXCEPTION, /* wasm_runtime_get_exception() */
CMD_DEINSTANTIATE_MODULE, /* wasm_runtime_deinstantiate() */
CMD_UNLOAD_MODULE, /* wasm_runtime_unload() */
CMD_DESTROY_RUNTIME, /* wasm_runtime_destroy() */
CMD_SET_WASI_ARGS, /* wasm_runtime_set_wasi_args() */
CMD_SET_LOG_LEVEL, /* bh_log_set_verbose_level() */
};
```
Others
------
- Please add "-sgx" option when generating AoT file for SGX platform, e.g.:
```bash
wamrc -sgx -o test.aot test.wasm
```
- The default max heap size of Enclave is 16 MB, it might be not enough when executing some workloads, please modify it in Enclave/Enclave.config.xml with a larger size when exception was thrown:
```bash
Exception: fail to enlarge memory.
or
Exception: allocate memory failed.
```
Enclave/Enclave.config.xml, default max heap size is 16 MB:
```xml
<HeapMaxSize>0x1000000</HeapMaxSize>
```

View File

@ -48,8 +48,23 @@ if (NOT DEFINED WAMR_BUILD_LIBC_BUILTIN)
endif ()
if (NOT DEFINED WAMR_BUILD_LIBC_WASI)
# Disable libc wasi support by default
set (WAMR_BUILD_LIBC_WASI 0)
# Enable libc wasi support by default
set (WAMR_BUILD_LIBC_WASI 1)
endif ()
if (NOT DEFINED WAMR_BUILD_FAST_INTERP)
# Enable fast interpreter
set (WAMR_BUILD_FAST_INTERP 1)
endif ()
if (NOT DEFINED WAMR_BUILD_MULTI_MODULE)
# Enable multiple modules
set (WAMR_BUILD_MULTI_MODULE 0)
endif ()
if (NOT DEFINED WAMR_BUILD_LIB_PTHREAD)
# Enable pthread library by default
set (WAMR_BUILD_LIB_PTHREAD 1)
endif ()
if (COLLECT_CODE_COVERAGE EQUAL 1)
@ -62,49 +77,14 @@ set (CMAKE_C_FLAGS "${CMAKE_C_FLAGS} -std=gnu99 -ffunction-sections -fdata-secti
-nostdinc -fvisibility=hidden -fpie" )
set (WAMR_ROOT_DIR ${CMAKE_CURRENT_SOURCE_DIR}/../../..)
set (SHARED_DIR ${WAMR_ROOT_DIR}/core/shared)
set (IWASM_DIR ${WAMR_ROOT_DIR}/core/iwasm)
set (APP_FRAMEWORK_DIR ${WAMR_ROOT_DIR}/core/app-framework)
# include the build config template file
include (${WAMR_ROOT_DIR}/build-scripts/config_common.cmake)
include (${WAMR_ROOT_DIR}/build-scripts/runtime_lib.cmake)
add_library(vmlib ${WAMR_RUNTIME_LIB_SOURCE})
include_directories (${SHARED_DIR}/include
${IWASM_DIR}/include)
enable_language (ASM)
include (${SHARED_DIR}/platform/${WAMR_BUILD_PLATFORM}/shared_platform.cmake)
include (${SHARED_DIR}/mem-alloc/mem_alloc.cmake)
include (${SHARED_DIR}/utils/shared_utils.cmake)
if (WAMR_BUILD_LIBC_BUILTIN EQUAL 1)
include (${IWASM_DIR}/libraries/libc-builtin/libc_builtin.cmake)
endif ()
if (WAMR_BUILD_LIBC_WASI EQUAL 1)
include (${IWASM_DIR}/libraries/libc-wasi/libc_wasi.cmake)
endif ()
include (${IWASM_DIR}/common/iwasm_common.cmake)
if (WAMR_BUILD_INTERP EQUAL 1 OR WAMR_BUILD_JIT EQUAL 1)
include (${IWASM_DIR}/interpreter/iwasm_interp.cmake)
endif ()
if (WAMR_BUILD_AOT EQUAL 1)
include (${IWASM_DIR}/aot/iwasm_aot.cmake)
if (WAMR_BUILD_JIT EQUAL 1)
include (${IWASM_DIR}/compilation/iwasm_compl.cmake)
endif ()
endif ()
add_library (vmlib
${PLATFORM_SHARED_SOURCE}
${MEM_ALLOC_SHARED_SOURCE}
${UTILS_SHARED_SOURCE}
${LIBC_BUILTIN_SOURCE}
${LIBC_WASI_SOURCE}
${IWASM_COMMON_SOURCE}
${IWASM_INTERP_SOURCE}
${IWASM_AOT_SOURCE}
${IWASM_COMPL_SOURCE})
add_custom_command (
OUTPUT libvmlib_untrusted.a
COMMAND mkdir -p untrusted && cd untrusted &&
${CMAKE_C_COMPILER} -c ${PLATFORM_SHARED_SOURCE_UNTRUSTED}
COMMAND ${CMAKE_AR} rc libvmlib_untrusted.a untrusted/*.o)
add_custom_target (vmlib_untrusted ALL DEPENDS libvmlib_untrusted.a)

View File

@ -27,7 +27,7 @@
#define TOKEN_FILENAME "enclave.token"
#define ENCLAVE_FILENAME "enclave.signed.so"
#define MAX_PATH FILENAME_MAX
#define MAX_PATH 1024
#define TEST_OCALL_API 0
@ -39,10 +39,25 @@ ocall_print(const char* str)
printf("%s", str);
}
static void
print_error_message(sgx_status_t ret)
static char *
get_exe_path(char *path_buf, unsigned path_buf_size)
{
printf("SGX error code: %d\n", ret);
ssize_t i;
ssize_t size = readlink("/proc/self/exe",
path_buf, path_buf_size - 1);
if (size < 0 || (size >= path_buf_size - 1)) {
return NULL;
}
path_buf[size] = '\0';
for (i = size - 1; i >= 0; i--) {
if (path_buf[i] == '/') {
path_buf[i + 1] = '\0';
break;
}
}
return path_buf;
}
/* Initialize the enclave:
@ -54,16 +69,27 @@ static int
enclave_init(sgx_enclave_id_t *p_eid)
{
char token_path[MAX_PATH] = {'\0'};
sgx_launch_token_t token = {0};
char token_path[MAX_PATH] = { '\0' };
char enclave_path[MAX_PATH] = { '\0' };
const char *home_dir;
sgx_launch_token_t token = { 0 };
sgx_status_t ret = SGX_ERROR_UNEXPECTED;
int updated = 0;
size_t write_num, enc_file_len;
FILE *fp;
enc_file_len = strlen(ENCLAVE_FILENAME);
if (!get_exe_path(enclave_path, sizeof(enclave_path) - enc_file_len)) {
printf("Failed to get exec path\n");
return -1;
}
memcpy(enclave_path + strlen(enclave_path), ENCLAVE_FILENAME, enc_file_len);
/* Step 1: try to retrieve the launch token saved by last transaction
* if there is no token, then create a new one.
*/
/* try to get the token saved in $HOME */
const char *home_dir = getpwuid(getuid())->pw_dir;
home_dir = getpwuid(getuid())->pw_dir;
if (home_dir != NULL &&
(strlen(home_dir) + strlen("/") + sizeof(TOKEN_FILENAME) + 1) <= MAX_PATH) {
@ -77,9 +103,10 @@ enclave_init(sgx_enclave_id_t *p_eid)
strncpy(token_path, TOKEN_FILENAME, sizeof(TOKEN_FILENAME));
}
FILE *fp = fopen(token_path, "rb");
fp = fopen(token_path, "rb");
if (fp == NULL && (fp = fopen(token_path, "wb")) == NULL) {
printf("Warning: Failed to create/open the launch token file \"%s\".\n", token_path);
printf("Warning: Failed to create/open the launch token file \"%s\".\n",
token_path);
}
if (fp != NULL) {
@ -94,9 +121,15 @@ enclave_init(sgx_enclave_id_t *p_eid)
/* Step 2: call sgx_create_enclave to initialize an enclave instance */
/* Debug Support: set 2nd parameter to 1 */
ret = sgx_create_enclave(ENCLAVE_FILENAME, SGX_DEBUG_FLAG, &token, &updated, p_eid, NULL);
ret = sgx_create_enclave(ENCLAVE_FILENAME, SGX_DEBUG_FLAG,
&token, &updated, p_eid, NULL);
if (ret != SGX_SUCCESS)
/* Try to load enclave.sign.so from the path of exe file */
ret = sgx_create_enclave(enclave_path, SGX_DEBUG_FLAG,
&token, &updated, p_eid, NULL);
if (ret != SGX_SUCCESS) {
print_error_message(ret);
printf("Failed to create enclave from %s, error code: %d\n",
ENCLAVE_FILENAME, ret);
if (fp != NULL)
fclose(fp);
return -1;
@ -114,7 +147,7 @@ enclave_init(sgx_enclave_id_t *p_eid)
if (fp == NULL)
return 0;
size_t write_num = fwrite(token, 1, sizeof(sgx_launch_token_t), fp);
write_num = fwrite(token, 1, sizeof(sgx_launch_token_t), fp);
if (write_num != sizeof(sgx_launch_token_t))
printf("Warning: Failed to save launch token to \"%s\".\n", token_path);
@ -129,14 +162,23 @@ read_file_to_buffer(const char *filename, uint32_t *ret_size)
FILE *file;
int file_size, read_size;
if (!(file = fopen(filename, "r")))
if (!filename || !ret_size) {
printf("Read file to buffer failed: invalid filename or ret size.\n");
return NULL;
}
if (!(file = fopen(filename, "r"))) {
printf("Read file to buffer failed: open file %s failed.\n",
filename);
return NULL;
}
fseek(file, 0, SEEK_END);
file_size = ftell(file);
fseek(file, 0, SEEK_SET);
if (!(buffer = (unsigned char*)malloc(file_size))) {
printf("Read file to buffer failed: alloc memory failed.\n");
fclose(file);
return NULL;
}
@ -145,6 +187,7 @@ read_file_to_buffer(const char *filename, uint32_t *ret_size)
fclose(file);
if (read_size < file_size) {
printf("Read file to buffer failed: read file content failed.\n");
free(buffer);
return NULL;
}
@ -233,7 +276,6 @@ typedef enum EcallCmd {
CMD_DESTROY_RUNTIME, /* wasm_runtime_destroy() */
CMD_SET_WASI_ARGS, /* wasm_runtime_set_wasi_args() */
CMD_SET_LOG_LEVEL, /* bh_log_set_verbose_level() */
CMD_SET_MAX_THREAD_NUM, /* wasm_runtime_set_max_thread_num() */
} EcallCmd;
static void
@ -310,14 +352,15 @@ set_log_verbose_level(int log_verbose_level)
}
static bool
init_runtime(bool alloc_with_pool)
init_runtime(bool alloc_with_pool, uint32_t max_thread_num)
{
uint64_t ecall_args[1];
uint64_t ecall_args[2];
ecall_args[0] = alloc_with_pool;
ecall_args[1] = max_thread_num;
if (SGX_SUCCESS != ecall_handle_command(g_eid, CMD_INIT_RUNTIME,
(uint8_t *)ecall_args,
sizeof(uint64_t))) {
sizeof(uint64_t) * 2)) {
printf("Call ecall_handle_command() failed.\n");
return false;
}
@ -536,6 +579,7 @@ main(int argc, char *argv[])
uint32_t dir_list_size = 0;
const char *env_list[8] = { NULL };
uint32_t env_list_size = 0;
uint32_t max_thread_num = 4;
if (enclave_init(&g_eid) < 0) {
std::cout << "Fail to initialize enclave." << std::endl;
@ -544,7 +588,11 @@ main(int argc, char *argv[])
#if TEST_OCALL_API != 0
{
if (!init_runtime(alloc_with_pool, max_thread_num)) {
return -1;
}
ecall_iwasm_test(g_eid);
destroy_runtime();
return 0;
}
#endif
@ -610,8 +658,7 @@ main(int argc, char *argv[])
else if (!strncmp(argv[0], "--max-threads=", 14)) {
if (argv[0][14] == '\0')
return print_help();
/*wasm_runtime_set_max_thread_num(atoi(argv[0] + 14));*/
/* TODO */
max_thread_num = atoi(argv[0] + 14);
}
else
return print_help();
@ -623,7 +670,7 @@ main(int argc, char *argv[])
wasm_file = argv[0];
/* Init runtime */
if (!init_runtime(alloc_with_pool)) {
if (!init_runtime(alloc_with_pool, max_thread_num)) {
return -1;
}

View File

@ -2,9 +2,9 @@
<EnclaveConfiguration>
<ProdID>0</ProdID>
<ISVSVN>0</ISVSVN>
<StackMaxSize>0x40000</StackMaxSize>
<HeapMaxSize>0x400000</HeapMaxSize>
<ReservedMemMaxSize>0x100000</ReservedMemMaxSize>
<StackMaxSize>0x100000</StackMaxSize>
<HeapMaxSize>0x1000000</HeapMaxSize>
<ReservedMemMaxSize>0x400000</ReservedMemMaxSize>
<ReservedMemExecutable>1</ReservedMemExecutable>
<TCSNum>10</TCSNum>
<TCSPolicy>1</TCSPolicy>

View File

@ -38,7 +38,6 @@ typedef enum EcallCmd {
CMD_DESTROY_RUNTIME, /* wasm_runtime_destroy() */
CMD_SET_WASI_ARGS, /* wasm_runtime_set_wasi_args() */
CMD_SET_LOG_LEVEL, /* bh_log_set_verbose_level() */
CMD_SET_MAX_THREAD_NUM, /* wasm_runtime_set_max_thread_num() */
} EcallCmd;
typedef struct EnclaveModule {
@ -54,7 +53,11 @@ typedef struct EnclaveModule {
uint32 wasi_argc;
} EnclaveModule;
static char global_heap_buf[2 * 1024 * 1024] = { 0 };
#if WASM_ENABLE_SPEC_TEST == 0
static char global_heap_buf[10 * 1024 * 1024] = { 0 };
#else
static char global_heap_buf[100 * 1024 * 1024] = { 0 };
#endif
static void
set_error_buf(char *error_buf, uint32 error_buf_size, const char *string)
@ -66,16 +69,23 @@ set_error_buf(char *error_buf, uint32 error_buf_size, const char *string)
static void
handle_cmd_init_runtime(uint64 *args, uint32 argc)
{
bool alloc_with_pool = true;
bool alloc_with_pool;
uint32 max_thread_num;
RuntimeInitArgs init_args;
bh_assert(argc == 2);
os_set_print_function(enclave_print);
if (argc > 0) {
alloc_with_pool = (bool)args[0];
}
#if WASM_ENABLE_SPEC_TEST == 0
alloc_with_pool = (bool)args[0];
#else
alloc_with_pool = true;
#endif
max_thread_num = (uint32)args[1];
memset(&init_args, 0, sizeof(RuntimeInitArgs));
init_args.max_thread_num = max_thread_num;
if (alloc_with_pool) {
init_args.mem_alloc_type = Alloc_With_Pool;
@ -290,15 +300,6 @@ handle_cmd_set_log_level(uint64 *args, uint32 argc)
#endif
}
static void
handle_cmd_set_max_thread_num(uint64 *args, uint32 argc)
{
#if WASM_ENABLE_LIB_PTHREAD != 0
LOG_VERBOSE("Set max thread num to %d.\n", (uint32)args[0]);
wasm_runtime_set_max_thread_num((uint32)args[0]);
#endif
}
static void
handle_cmd_set_wasi_args(uint64 *args, int32 argc)
{
@ -379,16 +380,14 @@ handle_cmd_set_wasi_args(uint64 *args, int32 argc)
p += sizeof(char *) * wasi_argc;
}
#if WASM_ENABLE_LIBC_WASI != 0
wasm_runtime_set_wasi_args(enclave_module->module,
(const char **)enclave_module->wasi_dir_list,
dir_list_size,
NULL, 0,
(const char **)enclave_module->wasi_env_list,
env_list_size,
envclave_module->wasi_argv,
envclave_module->wasi_argc);
#endif
enclave_module->wasi_argv,
enclave_module->wasi_argc);
*args_org = true;
}
@ -441,9 +440,6 @@ ecall_handle_command(unsigned cmd,
case CMD_SET_LOG_LEVEL:
handle_cmd_set_log_level(args, argc);
break;
case CMD_SET_MAX_THREAD_NUM:
handle_cmd_set_max_thread_num(args, argc);
break;
default:
LOG_ERROR("Unknown command %d\n", cmd);
break;

View File

@ -5,6 +5,8 @@
enclave {
from "sgx_tstdc.edl" import *;
from "sgx_pthread.edl" import *;
from "sgx_wamr.edl" import *;
trusted {
/* define ECALLs here. */
@ -13,6 +15,7 @@ enclave {
unsigned cmd_buf_size);
public void ecall_iwasm_main([user_check]uint8_t *wasm_file_buf,
uint32_t wasm_file_size);
public void ecall_iwasm_test();
};
untrusted {

View File

@ -0,0 +1,416 @@
/*
* Copyright (C) 2019 Intel Corporation. All rights reserved.
* SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
*/
#include <stdio.h>
#include <string.h>
#include "Enclave_t.h"
#include "wasm_export.h"
#include "bh_platform.h"
void ecall_iwasm_test()
{
ocall_print(" Prepare to invoke sgx_open ... ==>\n\n");
/* creat test.txt firstly */
char file[] = "test.txt";
char file_hd_ln[] = "test_hd_ln.txt";
char file_sf_ln[] = "test_sf_ln.txt";
char rlt_dir_path[] = "./tmp";
char rlt_dir_path_new[] = "./tmp_new";
char *str0 = (char *)"good luck, ";
char *str1 = (char *)"have fun!";
char buf0[4], buf1[4];
struct iovec iov_w[2];
struct iovec iov_r[2];
char buf[2048];
ssize_t total_size;
ssize_t s_ret;
int fd;
int dird;
int file_buf;
int ret;
long ret_l;
DIR *dirp;
struct dirent *p_dirent;
struct stat *statbuf;
struct pollfd fds[1];
char *res;
/** getopt value **/
int argc = 3;
char n_1[] = "./main";
char n_2[] = "-a";
char n_3[] = "test.txt";
char *argv[3];
argv[0] = n_1;
argv[1] = n_2;
argv[2] = n_3;
/* time clock */
struct timespec ts;
struct timespec t_res;
struct timespec times[2];
struct stat statbuf_2;
times[0] = statbuf_2.st_atim;
times[1] = statbuf_2.st_mtim;
struct timespec rqtp;
struct timespec rmtp;
rqtp.tv_sec = 0;
rqtp.tv_nsec = 0;
/** mkdirat **/
/* mkdir tmp in current directory for test
* if the ./tmp directory has exits, mkdirat will fail
*/
ret = mkdirat(AT_FDCWD, rlt_dir_path, 0755);
if (ret == 0) {
ocall_print("\tOperation mkdirat success.\n");
}
/* flags:
0100: - O_CREAT
02 : - O_RDWR */
/** 1. open **/
fd = open(file, O_RDWR);
if (fd !=-1) {
ocall_print("\tOperation open test_open.txt success.\n");
}
/** read **/
total_size = read(fd, buf, 2048);
if (total_size != -1) {
ocall_print("\tOperation read test_open.txt success.\n");
ocall_print("\t\tthe details of the file: ");
ocall_print(buf);
ocall_print("\n");
}
/** lseek **/
ret = lseek(fd, 1, SEEK_CUR);
if (ret != -1) {
ocall_print("\tOperation lseek success.\n");
}
/** ftruncate **/
ret = ftruncate(fd, 0);
if (ret == 0) {
ocall_print("\tOperation ftruncate success.\n");
}
/** fdatasync **/
ret = fdatasync(fd);
if (ret == 0) {
ocall_print("\tOperation fdatasync success.\n");
}
/** isatty **/
ret = isatty(fd);
if (ret == 0) {
ocall_print("\tOperation fisatty success.\n");
}
/** fsync **/
ret = fsync(fd);
if (ret == 0) {
ocall_print("\tOperation fsync success.\n");
}
/** 1. close **/
ret = close(fd);
if (ret != -1) {
ocall_print("\tOperation close success.\n");
}
/*----------------------------------------------------------------*/
/**-- DIR --**/
/** fdopendir **/
/* 2. open */
dird = open(rlt_dir_path, O_RDONLY);
dirp = fdopendir(dird);
if (dirp != NULL) {
ocall_print("\tOperation fdopendir success.\n");
}
/** readdir **/
p_dirent = readdir(dirp);
if (p_dirent != NULL) {
ocall_print("\tOperation readdir success.\t");
ocall_print(p_dirent -> d_name);
ocall_print("\n");
}
/** rewinddir **/
rewinddir(dirp);
/** seekdir **/
seekdir(dirp, 1);
/** telldir **/
ret_l = telldir(dirp);
if (ret_l != -1) {
ocall_print("\tOperation telldir success. \n");
}
/** closedir **/
ret = closedir(dirp);
if (ret == 0 ) {
ocall_print("\tOperation closedir success. \n");
}
/* 2. close */
close(dird);
/*----------------------------------------------------------------*/
/** fstat **/
/** 3. open file firstly **/
fd = open(file, O_RDWR);
statbuf = (stat *)malloc(sizeof(stat));
ret = fstat(fd, statbuf);
if (ret == 0) {
ocall_print("\tOperation fstat success. \n");
}
free(statbuf);
/* 3. close */
close(fd);
/*----------------------------------------------------------------*/
/** fstatat **/
/* 4. open */
dird = open(rlt_dir_path, O_RDONLY);
ret = fstatat(AT_FDCWD, rlt_dir_path, statbuf, 0);
if (ret == 0) {
ocall_print("\tOperation fstatat success. \n");
}
/** renameat **/
ret = renameat(AT_FDCWD, rlt_dir_path, AT_FDCWD, rlt_dir_path_new);
if (ret == 0) {
ocall_print("\tOperation renameat ./tmp to "
"./tmp_new success. \n");
}
renameat(AT_FDCWD, rlt_dir_path_new, AT_FDCWD, rlt_dir_path);
/** link **/
ret = link(file, file_hd_ln);
if (ret == 0) {
ocall_print("\tOperation link success. \n");
}
/** unlinkat **/
ret = unlinkat(AT_FDCWD, file_hd_ln, 0);
if (ret == 0) {
ocall_print("\tOperation unlinkat success. \n");
}
/** linkat **/
ret = linkat(AT_FDCWD, file, AT_FDCWD, file_hd_ln, 0);
if (ret == 0) {
ocall_print("\tOperation linkat success. \n");
}
/* delete hard link file */
unlinkat(AT_FDCWD, file_hd_ln, 0);
/** symlinkat **/
ret = symlinkat(file, AT_FDCWD, file_sf_ln);
if (ret == 0) {
ocall_print("\tOperation symlinkat from test.txt "
"to text_sf_ln.txt success. \n");
}
/** readlinkat **/
total_size = readlinkat(AT_FDCWD, file_sf_ln, buf, sizeof(buf));
if (total_size != -1) {
ocall_print("\tOperation readlinkat success. \n");
ocall_print("\t\t the link details of the file is: ");
ocall_print(buf);
ocall_print("\n");
}
/* delete soft link file */
unlinkat(AT_FDCWD, file_sf_ln, 0);
/* 4. close */
close(dird);
/*----------------------------------------------------------------*/
/* 5. open */
fd = open(file, O_RDWR);
/** ioctl **/
ret = ioctl(fd, FIONREAD, &file_buf);
if (ret == 0) {
ocall_print("\tOperation ioctl success. \n");
}
/** fcntl(fd, cmd) **/
ret = fcntl(fd, F_GETFD);
if (ret != 0 || ret != -1) {
ocall_print("\tOperation fcntl_1 success. \n");
}
/** fcntl(fd, cmd, long) **/
ret = fcntl(fd, F_SETFD, ret);
if (ret != 0 || ret != -1) {
ocall_print("\tOperation fcntl_2 success. \n");
}
/* 5. close */
close(fd);
/*----------------------------------------------------------------*/
/** posix_fallocate **/
/* 6. open */
fd = open(file, O_RDWR);
ret = posix_fallocate(fd, 1, 1);
if (ret != 0 || ret != -1) {
ocall_print("\tOperation posix_fallocate success. \n");
}
/* 6. close */
close(fd);
/** poll **/
ret = poll(fds, 1, 10);
if (ret != 0 || ret != -1) {
ocall_print("\tOperation poll success. \n");
}
/** realpath **/
res = realpath(file, res);
if (res) {
ocall_print("\tOperation realpath success. \n");
ocall_print("\t\t the absolute path of the file is: ");
ocall_print(res);
ocall_print("\n");
}
/** getrandom **/
total_size = getrandom(buf, 1024, 0);
if (ret != -1) {
ocall_print("\tOperation getrandom success. \n");
}
/** writev **/
/* 7. open */
fd = open(file, O_RDWR);
iov_w[0].iov_base = str0;
iov_w[0].iov_len = strlen(str0);
iov_w[1].iov_base = str1;
iov_w[1].iov_len = strlen(str1);
s_ret = writev(fd, iov_w, 2);
if (s_ret != -1) {
ocall_print("\tOperation writev success. \n");
}
/** readv **/
iov_r[0].iov_base = buf0;
iov_r[0].iov_len = sizeof(buf0) - 1;
iov_r[1].iov_base = buf1;
iov_r[1].iov_len = sizeof(buf1) - 1;
s_ret = readv(fd, iov_r, 2);
if (s_ret != -1) {
ocall_print("\tOperation readv success. \n");
ocall_print("\t\t");
ocall_print(buf0);
ocall_print(buf1);
ocall_print("\n");
}
iov_r[0].iov_base = buf0;
iov_r[0].iov_len = sizeof(buf0) - 1;
iov_r[1].iov_base = buf1;
iov_r[1].iov_len = sizeof(buf1) - 1;
s_ret = preadv(fd, iov_r, 2, 2);
if (s_ret != -1) {
ocall_print("\tOperation readv success. \n");
ocall_print("\t\t");
ocall_print(buf0);
ocall_print(buf1);
ocall_print("\n");
}
/* 7. close */
close(fd);
/** getopt **/
while((ret = getopt(argc, argv, "f:abc")) != -1){ //get option from the getopt() method
switch(ret){
//For option i, r, l, print that these are options
case 'a':
case 'b':
case 'c':
ocall_print("\tGiven Option operation success. \n");
break;
case 'f': //here f is used for some file name
ocall_print("\tGiven File operation success.\n");
break;
case '?': //used for some unknown options
ocall_print("\tunknown option trigger success.\n");
break;
}
}
/** sched_yield **/
ret = sched_yield();
if (ret == 0) {
ocall_print("\tOperation sched_yield success. \n");
}
/** clock_gettime **/
ret = clock_gettime(CLOCK_REALTIME, &ts);
if (ret == 0) {
ocall_print("\tOperation clock_gettime success. \n");
}
/** clock_getres **/
ret = clock_getres(CLOCK_REALTIME, &t_res);
if (ret == 0) {
ocall_print("\tOperation clock_getres success. \n");
}
/** futimens **/
/* 8. open */
fd = open(file, O_RDWR);
ret = futimens(fd, NULL);
if (ret == 0) {
ocall_print("\tOperation futimens NULL success. \n");
}
ret = futimens(fd, times);
if (ret == 0) {
ocall_print("\tOperation futimens times[2] success. \n");
}
/* 8. close */
close(fd);
/** utimensat **/
/* 9. open */
dird = open(rlt_dir_path, O_RDONLY);
ret = utimensat(AT_FDCWD, file, NULL, AT_SYMLINK_NOFOLLOW);
if (ret == 0) {
ocall_print("\tOperation utimensat NULL success. \n");
}
ret = utimensat(AT_FDCWD, file, times, AT_SYMLINK_NOFOLLOW);
if (ret == 0) {
ocall_print("\tOperation utimensat times[2] success. \n");
}
/* 9. close */
close(fd);
/** clock_nanosleep **/
ret = clock_nanosleep(CLOCK_REALTIME, 0, &rqtp, NULL);
if (ret == 0) {
ocall_print("\tOperation clock_nanosleep NULL success. \n");
}
ret = clock_nanosleep(CLOCK_REALTIME, 0, &rqtp, &rmtp);
if (ret == 0) {
ocall_print("\tOperation clock_nanosleep 2 success. \n");
}
ocall_print("\n<== ... End test\n");
}

View File

@ -7,6 +7,7 @@ SGX_SDK ?= /opt/intel/sgxsdk
SGX_MODE ?= SIM
SGX_ARCH ?= x64
SGX_DEBUG ?= 0
SPEC_TEST ?= 0
ifeq ($(shell getconf LONG_BIT), 32)
SGX_ARCH := x86
@ -33,9 +34,9 @@ endif
endif
ifeq ($(SGX_DEBUG), 1)
SGX_COMMON_CFLAGS += -O0 -g
SGX_COMMON_CFLAGS += -O0 -g
else
SGX_COMMON_CFLAGS += -O2
SGX_COMMON_CFLAGS += -O2
endif
######## App Settings ########
@ -56,15 +57,15 @@ App_C_Flags := $(SGX_COMMON_CFLAGS) -fPIC -Wno-attributes $(App_Include_Paths)
# Prerelease - Macro NDEBUG and EDEBUG enabled.
# Release - Macro NDEBUG enabled.
ifeq ($(SGX_DEBUG), 1)
App_C_Flags += -DDEBUG -UNDEBUG -UEDEBUG
App_C_Flags += -DDEBUG -UNDEBUG -UEDEBUG
else ifeq ($(SGX_PRERELEASE), 1)
App_C_Flags += -DNDEBUG -DEDEBUG -UDEBUG
App_C_Flags += -DNDEBUG -DEDEBUG -UDEBUG
else
App_C_Flags += -DNDEBUG -UEDEBUG -UDEBUG
App_C_Flags += -DNDEBUG -UEDEBUG -UDEBUG
endif
App_Cpp_Flags := $(App_C_Flags) -std=c++11
App_Link_Flags := $(SGX_COMMON_CFLAGS) -L$(SGX_LIBRARY_PATH) -l$(Urts_Library_Name) -lpthread
App_Link_Flags := $(SGX_COMMON_CFLAGS) libvmlib_untrusted.a -L$(SGX_LIBRARY_PATH) -l$(Urts_Library_Name) -lpthread
ifneq ($(SGX_MODE), HW)
App_Link_Flags += -lsgx_uae_service_sim
@ -89,7 +90,7 @@ Crypto_Library_Name := sgx_tcrypto
WAMR_ROOT := $(CURDIR)/../../../../
Enclave_Cpp_Files := Enclave/Enclave.cpp
Enclave_Cpp_Files := Enclave/Enclave.cpp Enclave/Enclave_test.cpp
Enclave_Include_Paths := -IEnclave -I$(WAMR_ROOT)/core/iwasm/include \
-I$(WAMR_ROOT)/core/shared/utils \
@ -99,6 +100,11 @@ Enclave_Include_Paths := -IEnclave -I$(WAMR_ROOT)/core/iwasm/include \
-I$(SGX_SDK)/include/stlport
Enclave_C_Flags := $(SGX_COMMON_CFLAGS) -nostdinc -fvisibility=hidden -fpie -fstack-protector $(Enclave_Include_Paths)
ifeq ($(SPEC_TEST), 1)
Enclave_C_Flags += -DWASM_ENABLE_SPEC_TEST=1
else
Enclave_C_Flags += -DWASM_ENABLE_SPEC_TEST=0
endif
Enclave_Cpp_Flags := $(Enclave_C_Flags) -std=c++03 -nostdinc++
Enclave_Link_Flags := $(SGX_COMMON_CFLAGS) -Wl,--no-undefined -nostdlib -nodefaultlibs -nostartfiles -L$(SGX_LIBRARY_PATH) \
-Wl,--whole-archive -l$(Trts_Library_Name) -Wl,--no-whole-archive \
@ -146,7 +152,10 @@ endif
######## App Objects ########
App/Enclave_u.c: $(SGX_EDGER8R) Enclave/Enclave.edl
@cd App && $(SGX_EDGER8R) --untrusted ../Enclave/Enclave.edl --search-path ../Enclave --search-path $(SGX_SDK)/include --search-path $(WAMR_ROOT)/core/shared/platform/linux-sgx
@cd App && $(SGX_EDGER8R) --untrusted ../Enclave/Enclave.edl \
--search-path ../Enclave \
--search-path $(SGX_SDK)/include \
--search-path $(WAMR_ROOT)/core/shared/platform/linux-sgx
@echo "GEN => $@"
App/Enclave_u.o: App/Enclave_u.c
@ -157,7 +166,11 @@ App/%.o: App/%.cpp
@$(CXX) $(App_Cpp_Flags) -c $< -o $@
@echo "CXX <= $<"
$(App_Name): App/Enclave_u.o $(App_Cpp_Objects)
libvmlib_untrusted.a: ../build/libvmlib_untrusted.a
@cp $< $@
@echo "CP $@ <= $<"
$(App_Name): App/Enclave_u.o $(App_Cpp_Objects) libvmlib_untrusted.a
@$(CXX) $^ -o $@ $(App_Link_Flags)
@echo "LINK => $@"
@ -165,7 +178,10 @@ $(App_Name): App/Enclave_u.o $(App_Cpp_Objects)
######## Enclave Objects ########
Enclave/Enclave_t.c: $(SGX_EDGER8R) Enclave/Enclave.edl
@cd Enclave && $(SGX_EDGER8R) --trusted ../Enclave/Enclave.edl --search-path ../Enclave --search-path $(SGX_SDK)/include --search-path $(WAMR_ROOT)/core/shared/platform/linux-sgx
@cd Enclave && $(SGX_EDGER8R) --trusted ../Enclave/Enclave.edl \
--search-path ../Enclave \
--search-path $(SGX_SDK)/include \
--search-path $(WAMR_ROOT)/core/shared/platform/linux-sgx
@echo "GEN => $@"
Enclave/Enclave_t.o: Enclave/Enclave_t.c
@ -191,4 +207,4 @@ $(Signed_Enclave_Name): $(Enclave_Name)
.PHONY: clean
clean:
@rm -f $(App_Name) $(Enclave_Name) $(Signed_Enclave_Name) $(App_Cpp_Objects) App/Enclave_u.* $(Enclave_Cpp_Objects) Enclave/Enclave_t.* libvmlib.a
@rm -f $(App_Name) $(Enclave_Name) $(Signed_Enclave_Name) $(App_Cpp_Objects) App/Enclave_u.* $(Enclave_Cpp_Objects) Enclave/Enclave_t.* libvmlib.a libvmlib_untrusted.a