Implement libc-WASI for Linux SGX platform and update documents (#343)
This commit is contained in:
@ -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/0:build 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
|
||||
|
||||
@ -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
|
||||
|
||||

|
||||
|
||||
197
doc/linux_sgx.md
Normal file
197
doc/linux_sgx.md
Normal 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>
|
||||
```
|
||||
|
||||
Reference in New Issue
Block a user