You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@teaclave.apache.org by ms...@apache.org on 2021/06/15 22:46:04 UTC

[incubator-teaclave] branch master updated: Add WebAssembly Executor (#504)

This is an automated email from the ASF dual-hosted git repository.

mssun pushed a commit to branch master
in repository https://gitbox.apache.org/repos/asf/incubator-teaclave.git


The following commit(s) were added to refs/heads/master by this push:
     new 90e7231  Add WebAssembly Executor (#504)
90e7231 is described below

commit 90e7231d8eed601b84d91633c58f9b2452157c95
Author: Hongbo <12...@users.noreply.github.com>
AuthorDate: Tue Jun 15 18:45:56 2021 -0400

    Add WebAssembly Executor (#504)
    
    - MVP implementation
    - Simple add exmaple
---
 .github/workflows/ci.yml                           |   8 +-
 .gitmodules                                        |   3 +
 CMakeLists.txt                                     |  28 +
 LICENSE                                            |   1 +
 cmake/TeaclaveGenVars.cmake                        |   3 +
 cmake/TeaclaveUtils.cmake                          |  12 +-
 cmake/scripts/sgx_link_sign.sh                     |   2 +-
 cmake/scripts/test.sh                              |   1 +
 docs/adding-custom-executor.md                     |  46 ++
 examples/python/wasm_simple_add.py                 | 100 ++++
 .../python/wasm_simple_add_payload/simple_add.c    |  65 ++
 .../python/wasm_simple_add_payload/simple_add.wasm | Bin 0 -> 1594 bytes
 executor/src/lib.rs                                |   3 +
 executor/src/wamr.rs                               | 202 +++++++
 LICENSE => licenses/LICENSE-wasm-micro-runtime.txt |  35 +-
 rpc/src/protocol.rs                                |   2 +-
 sdk/rust/src/bindings.rs                           | 156 +++--
 sdk/rust/src/lib.rs                                |   1 +
 services/proto/proto_gen/main.rs                   |   2 -
 third_party/wamr.patch                             | 651 +++++++++++++++++++++
 third_party/wasm-micro-runtime                     |   1 +
 types/src/worker.rs                                |   6 +
 worker/src/worker.rs                               |   6 +-
 23 files changed, 1236 insertions(+), 98 deletions(-)

diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml
index 6be2c85..ef1363f 100644
--- a/.github/workflows/ci.yml
+++ b/.github/workflows/ci.yml
@@ -29,8 +29,6 @@ jobs:
     container: teaclave/teaclave-build-ubuntu-1804-sgx-2.9.1:0.1.2
     steps:
       - uses: actions/checkout@v2
-        with:
-          submodules: 'true'
       - name: Setting up $HOME
         run: |
           cp /root/.bashrc $HOME/.bashrc &&
@@ -45,6 +43,7 @@ jobs:
           cmake -DCMAKE_BUILD_TYPE=Debug -DSGX_SIM_MODE=ON -DTEST_MODE=ON ..
       - name: Building
         run: |
+          . /opt/sgxsdk/environment &&
           . ~/.cargo/env &&
           cd build &&
           make VERBOSE=1
@@ -63,8 +62,6 @@ jobs:
     container: teaclave/teaclave-build-ubuntu-1804-sgx-2.9.1:0.1.2
     steps:
       - uses: actions/checkout@v2
-        with:
-          submodules: 'true'
       - name: Setting up $HOME
         run: |
           cp /root/.bashrc $HOME/.bashrc &&
@@ -86,8 +83,6 @@ jobs:
     container: teaclave/teaclave-build-ubuntu-1804-sgx-2.9.1:0.1.2
     steps:
       - uses: actions/checkout@v2
-        with:
-          submodules: 'true'
       - name: Setting up $HOME
         run: |
           cp /root/.bashrc $HOME/.bashrc &&
@@ -102,5 +97,6 @@ jobs:
           cmake -DRUSTFLAGS="-D warnings" -DTEST_MODE=ON ..
       - name: Code linting with Clippy
         run: |
+          . /opt/sgxsdk/environment &&
           . /root/.cargo/env &&
           cd build && make CLP=1
diff --git a/.gitmodules b/.gitmodules
index d913305..489b426 100644
--- a/.gitmodules
+++ b/.gitmodules
@@ -13,3 +13,6 @@
 	path = third_party/crates-io
 	url = https://github.com/mesalock-linux/crates-io.git
 	ignore = dirty
+[submodule "third_party/wasm-micro-runtime"]
+	path = third_party/wasm-micro-runtime
+	url = https://github.com/bytecodealliance/wasm-micro-runtime
diff --git a/CMakeLists.txt b/CMakeLists.txt
index 8b8ec62..b3ddba1 100644
--- a/CMakeLists.txt
+++ b/CMakeLists.txt
@@ -151,6 +151,13 @@ set(MESAPY_OUTPUTS
   ${TEACLAVE_OUT_DIR}/libsgx_ulibc.a
   ${TEACLAVE_OUT_DIR}/ffi.o
 )
+
+# WAMR library
+
+set(WAMR_OUTPUTS
+  ${TEACLAVE_OUT_DIR}/libvmlib.a
+)
+
 if(USE_PREBUILT_MESAPY)
 add_custom_command(
   OUTPUT ${MESAPY_OUTPUTS}
@@ -172,10 +179,30 @@ else()
         ${TEACLAVE_OUT_DIR}
     WORKING_DIRECTORY ${PROJECT_SOURCE_DIR}/third_party/mesapy)
 endif()
+
+ExternalProject_Add(wamr_teaclave
+  SOURCE_DIR ${WAMR_TEACLAVE_ROOT_DIR}
+  BINARY_DIR ${WAMR_TEACLAVE_ROOT_DIR}/build
+  INSTALL_COMMAND ""
+  LOG_BUILD 1
+)
+
+add_custom_command(
+  OUTPUT ${WAMR_OUTPUTS}
+  DEPENDS wamr_teaclave
+  COMMAND
+    cp ${WAMR_TEACLAVE_ROOT_DIR}/build/libvmlib.a ${TEACLAVE_OUT_DIR}
+  WORKING_DIRECTORY ${WAMR_TEACLAVE_ROOT_DIR}/build
+  )
+
 add_custom_target(mesapy
   DEPENDS ${MESAPY_OUTPUTS}
   )
 
+add_custom_target(wamr
+  DEPENDS $(WAMR_TEACLAVE_ROOT_DIR)/CMakeLists.txt ${WAMR_OUTPUTS}
+  )
+
 # mesapy components
 add_custom_command(
   OUTPUT ${TEACLAVE_OUT_DIR}/acs_py_enclave.c
@@ -213,6 +240,7 @@ foreach(_i RANGE ${SGX_LIB_LAST_INDEX})
     DEPENDS
     prep
     mesapy
+    wamr
     pycomponent
     INSTALL_DIR
     ${TEACLAVE_INSTALL_DIR}/${_category}
diff --git a/LICENSE b/LICENSE
index 310ee62..74412ab 100644
--- a/LICENSE
+++ b/LICENSE
@@ -213,6 +213,7 @@ Apache License, Version 2.0
 
 third-party/crates-io
 third-party/crates-sgx
+third_party/wasm-micro-runtime
 
 
 BSD 3-Clause License
diff --git a/cmake/TeaclaveGenVars.cmake b/cmake/TeaclaveGenVars.cmake
index 8a00491..107e61e 100644
--- a/cmake/TeaclaveGenVars.cmake
+++ b/cmake/TeaclaveGenVars.cmake
@@ -42,6 +42,9 @@ set(THIRD_PARTY_DIR ${PROJECT_SOURCE_DIR}/third_party)
 set(UNTRUSTED_TARGET_DIR ${TEACLAVE_TARGET_DIR}/untrusted)
 set(UNIX_TARGET_DIR ${TEACLAVE_TARGET_DIR}/unix)
 set(TRUSTED_TARGET_DIR ${TEACLAVE_TARGET_DIR}/trusted)
+set(WAMR_TEACLAVE_ROOT_DIR
+  ${PROJECT_SOURCE_DIR}/third_party/wasm-micro-runtime/product-mini/platforms/teaclave-sgx
+)
 # build.rs will read ENV{ENCLAVE_OUT_DIR} for linking
 set(ENCLAVE_OUT_DIR ${TEACLAVE_OUT_DIR})
 set(RUST_SGX_SDK ${PROJECT_SOURCE_DIR}/third_party/rust-sgx-sdk)
diff --git a/cmake/TeaclaveUtils.cmake b/cmake/TeaclaveUtils.cmake
index 8271dd8..83cee77 100644
--- a/cmake/TeaclaveUtils.cmake
+++ b/cmake/TeaclaveUtils.cmake
@@ -57,13 +57,23 @@ function(init_submodules)
             "git submodule update --init failed with ${GIT_SUBMOD_RESULT}, please checkout submodules"
         )
       endif()
+      # Patch WAMR after pulling
+      if(NOT EXISTS "${PROJECT_SOURCE_DIR}/third_party/wasm-micro-runtime/product-mini/platforms/teaclave/CMakeLists.txt")
+        execute_process(
+          COMMAND 
+            patch -N -p1
+          INPUT_FILE "../wamr.patch"
+          WORKING_DIRECTORY ${PROJECT_SOURCE_DIR}/third_party/wasm-micro-runtime
+          )
+      endif()
     endif()
   endif()
 
   if(NOT EXISTS "${PROJECT_SOURCE_DIR}/third_party/crates-io"
      OR NOT EXISTS "${PROJECT_SOURCE_DIR}/third_party/crates-sgx"
      OR NOT EXISTS "${PROJECT_SOURCE_DIR}/third_party/mesapy"
-     OR NOT EXISTS "${PROJECT_SOURCE_DIR}/third_party/rust-sgx-sdk")
+     OR NOT EXISTS "${PROJECT_SOURCE_DIR}/third_party/rust-sgx-sdk"
+     OR NOT EXISTS "${PROJECT_SOURCE_DIR}/third_party/wasm-micro-runtime")
     message(
       FATAL_ERROR
         "The submodules were not downloaded! GIT_SUBMODULE was turned off or failed. Please update submodules and try again."
diff --git a/cmake/scripts/sgx_link_sign.sh b/cmake/scripts/sgx_link_sign.sh
index ca82c9e..670e7b6 100755
--- a/cmake/scripts/sgx_link_sign.sh
+++ b/cmake/scripts/sgx_link_sign.sh
@@ -52,7 +52,7 @@ ${CMAKE_C_COMPILER} "lib${edl_lib_name}.o" -o \
     -Wl,--no-whole-archive -Wl,--start-group \
     -l${Service_Library_Name} -lsgx_tprotected_fs -lsgx_tkey_exchange \
     -lsgx_tstdc -lsgx_tcxx -lsgx_tservice -lsgx_tcrypto \
-    -L${TEACLAVE_OUT_DIR} -lpycomponent ffi.o -lpypy-c -lsgx_tlibc_ext -lffi \
+    -L${TEACLAVE_OUT_DIR} -lpycomponent ffi.o -lpypy-c -lsgx_tlibc_ext -lffi -lvmlib\
     -L${TRUSTED_TARGET_DIR}/${TARGET} -l${CUR_PKG_NAME} -Wl,--end-group \
     -Wl,-Bstatic -Wl,-Bsymbolic -Wl,--no-undefined \
     -Wl,-pie,-eenclave_entry -Wl,--export-dynamic  \
diff --git a/cmake/scripts/test.sh b/cmake/scripts/test.sh
index feb93b7..1fe6282 100755
--- a/cmake/scripts/test.sh
+++ b/cmake/scripts/test.sh
@@ -230,6 +230,7 @@ run_examples() {
   python3 builtin_rsa_sign.py
   python3 builtin_face_detection.py
   python3 builtin_password_check.py
+  python3 wasm_simple_add.py
   popd
 
   pushd ${TEACLAVE_PROJECT_ROOT}/examples/c
diff --git a/docs/adding-custom-executor.md b/docs/adding-custom-executor.md
new file mode 100644
index 0000000..da53abc
--- /dev/null
+++ b/docs/adding-custom-executor.md
@@ -0,0 +1,46 @@
+---
+permalink: /docs/adding-custom-executor
+---
+
+# Source Code of the Executor
+
+The source code of the new executor should be at `executor/src/`.
+
+1. Create a public executor unit struct.
+2. Implement `TeaclaveExecutor` trait and `execute` function for the new struct.
+3. Re-export your new executor in `executor/src/lib.rs` to make it callable.
+4. Optionally, add unit test code to test your executor, and add a line calling your test in `executor/src/lib.rs`.
+
+## Extern Function
+
+Usually the new executor for other language or bytecode cannot be supported by this single rust source file,
+and the embedded execution environment is ported from another project, which can be written in another
+language. Therefore some extern functions should be imported to the rust source code and a **static** library
+is needed in linking.
+
+You may add this library in the linking command located at `cmake/scripts/sgx_link_sign.sh`, and such library
+should be in `${TEACLAVE_OUT_DIR}`, which will be parsed to `build/intermediate` in build phase.
+
+# Add the Interface
+
+You also need to add some auxillary code for teaclave and tell it when and how to invoked the new executor.
+
+## `types/src/worker.rs`
+
+1. Add a new enum value in `ExecutorType`;
+2. Add a match case in `ExecutorType::try_from` to get the `ExecutorType` from a string;
+3. Add a match case in `ExecutorType::fmt` for printing;
+4. Besides, add a enum in `Executor`;
+5. Add match cases in `Executor::try_from` and `Executor::fmt` just like what you've done in step 3 and 4.
+
+## `worker/src/worker.rs`
+
+1. Import the executor in `use teaclave_executor::{...}`
+2. Register the new executor in `Worker::Default`
+
+# Invoke the New Executor
+
+Just call the API and remember to set `executor_type` to your new executor type's name (the string used in
+`ExecutorType::try_from` match case) when calling `register_function`, and set the `executor` to the executor's
+name correspondingly.
+
diff --git a/examples/python/wasm_simple_add.py b/examples/python/wasm_simple_add.py
new file mode 100644
index 0000000..7663616
--- /dev/null
+++ b/examples/python/wasm_simple_add.py
@@ -0,0 +1,100 @@
+#!/usr/bin/env python3
+
+# Licensed to the Apache Software Foundation (ASF) under one
+# or more contributor license agreements.  See the NOTICE file
+# distributed with this work for additional information
+# regarding copyright ownership.  The ASF licenses this file
+# to you under the Apache License, Version 2.0 (the
+# "License"); you may not use this file except in compliance
+# with the License.  You may obtain a copy of the License at
+#
+#   http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing,
+# software distributed under the License is distributed on an
+# "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+# KIND, either express or implied.  See the License for the
+# specific language governing permissions and limitations
+# under the License.
+
+import sys
+
+from teaclave import (AuthenticationService, FrontendService,
+                      AuthenticationClient, FrontendClient)
+from utils import (AUTHENTICATION_SERVICE_ADDRESS, FRONTEND_SERVICE_ADDRESS,
+                   AS_ROOT_CA_CERT_PATH, ENCLAVE_INFO_PATH, USER_ID,
+                   USER_PASSWORD)
+
+
+class WASMAddExample:
+    def __init__(self, user_id, user_password):
+        self.user_id = user_id
+        self.user_password = user_password
+
+    def add(self,
+            payload_file="wasm_simple_add_payload/simple_add.wasm",
+            adder1="3",
+            adder2="4"):
+        client = AuthenticationService(
+            AUTHENTICATION_SERVICE_ADDRESS, AS_ROOT_CA_CERT_PATH,
+            ENCLAVE_INFO_PATH).connect().get_client()
+
+        print("[+] registering user")
+        client.user_register(self.user_id, self.user_password)
+
+        print("[+] login")
+        token = client.user_login(self.user_id, self.user_password)
+
+        client = FrontendService(FRONTEND_SERVICE_ADDRESS,
+                                 AS_ROOT_CA_CERT_PATH,
+                                 ENCLAVE_INFO_PATH).connect().get_client()
+        metadata = {"id": self.user_id, "token": token}
+        client.metadata = metadata
+
+        print("[+] registering function")
+
+        with open(payload_file, "rb") as f:
+            payload = f.read()
+
+        function_id = client.register_function(name="entrypoint",
+                                               description="test of wasm",
+                                               executor_type="wamr",
+                                               payload=list(payload),
+                                               arguments=["adder1", "adder2"])
+
+        print("[+] creating task")
+        task_id = client.create_task(function_id=function_id,
+                                     function_arguments={
+                                         "adder1": adder1,
+                                         "adder2": adder2
+                                     },
+                                     executor="wamr")
+
+        print("[+] invoking task")
+        client.invoke_task(task_id)
+
+        print("[+] getting result")
+        result = client.get_task_result(task_id)
+        print("[+] done")
+
+        return bytes(result)
+
+
+def main():
+    example = WASMAddExample(USER_ID, USER_PASSWORD)
+    if len(sys.argv) == 2:
+        adder1 = sys.argv[1]
+        rt = example.add(adder1=adder1)
+    elif len(sys.argv) == 3:
+        adder1 = sys.argv[1]
+        adder2 = sys.argv[2]
+
+        rt = example.add(adder1=adder1, adder2=adder2)
+    else:
+        rt = example.add()
+
+    print("[+] function return: ", rt)
+
+
+if __name__ == '__main__':
+    main()
diff --git a/examples/python/wasm_simple_add_payload/simple_add.c b/examples/python/wasm_simple_add_payload/simple_add.c
new file mode 100644
index 0000000..ddb39dc
--- /dev/null
+++ b/examples/python/wasm_simple_add_payload/simple_add.c
@@ -0,0 +1,65 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements.  See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership.  The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License.  You may obtain a copy of the License at
+ *
+ *   http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied.  See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ *
+ */
+
+
+int
+atoi(const char *str)
+{
+    int result = 0;
+    int sign = 0;
+    // proc whitespace characters
+    while (*str == ' ' || *str == '\t' || *str == '\n')
+        ++str;
+
+    // proc sign character
+    if (*str == '-') {
+        sign = 1;
+        ++str;
+    }
+    else if (*str == '+') {
+        ++str;
+    }
+
+    // proc numbers
+    while (*str >= '0' && *str <= '9') {
+        result = result * 10 + *str - '0';
+        ++str;
+    }
+
+    // return result
+    if (sign == 1)
+        return -result;
+    else
+        return result;
+}
+
+int
+entrypoint(int argc, char *argv[])
+{
+    if (argc < 4) {
+        return -1;
+    }
+    
+    if ((argv[0] == 0) || argv[2] == 0) {
+        return -1;
+    }
+
+    return atoi(argv[1]) + atoi(argv[3]);
+}
diff --git a/examples/python/wasm_simple_add_payload/simple_add.wasm b/examples/python/wasm_simple_add_payload/simple_add.wasm
new file mode 100755
index 0000000..dacab0b
Binary files /dev/null and b/examples/python/wasm_simple_add_payload/simple_add.wasm differ
diff --git a/executor/src/lib.rs b/executor/src/lib.rs
index e9e6cb0..31e566e 100644
--- a/executor/src/lib.rs
+++ b/executor/src/lib.rs
@@ -28,9 +28,11 @@ extern crate log;
 mod builtin;
 mod context;
 mod mesapy;
+mod wamr;
 
 pub use builtin::BuiltinFunctionExecutor;
 pub use mesapy::MesaPy;
+pub use wamr::WAMicroRuntime;
 
 #[cfg(feature = "enclave_unit_test")]
 pub mod tests {
@@ -42,6 +44,7 @@ pub mod tests {
             context::tests::run_tests(),
             mesapy::tests::run_tests(),
             builtin::tests::run_tests(),
+            wamr::tests::run_tests(),
         )
     }
 }
diff --git a/executor/src/wamr.rs b/executor/src/wamr.rs
new file mode 100644
index 0000000..b37bb3f
--- /dev/null
+++ b/executor/src/wamr.rs
@@ -0,0 +1,202 @@
+// Licensed to the Apache Software Foundation (ASF) under one
+// or more contributor license agreements.  See the NOTICE file
+// distributed with this work for additional information
+// regarding copyright ownership.  The ASF licenses this file
+// to you under the Apache License, Version 2.0 (the
+// "License"); you may not use this file except in compliance
+// with the License.  You may obtain a copy of the License at
+//
+//   http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing,
+// software distributed under the License is distributed on an
+// "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+// KIND, either express or implied.  See the License for the
+// specific language governing permissions and limitations
+// under the License.
+
+use std::prelude::v1::*;
+
+use crate::context::reset_thread_context;
+use crate::context::set_thread_context;
+use crate::context::Context;
+
+use std::ffi::{c_void, CString};
+
+use teaclave_types::{FunctionArguments, FunctionRuntime, TeaclaveExecutor};
+
+const DEFAULT_HEAP_SIZE: u32 = 8092;
+const DEFAULT_STACK_SIZE: u32 = 8092;
+const DEFAULT_ERROR_BUF_SIZE: usize = 128;
+
+extern "C" {
+
+    fn wasm_runtime_init() -> bool;
+
+    fn wasm_runtime_load(
+        buf: *const u8,
+        size: u32,
+        error_buf: *mut u8,
+        error_buf_size: u32,
+    ) -> *const c_void;
+
+    fn wasm_runtime_instantiate(
+        module: *const c_void,
+        stack_size: u32,
+        heap_size: u32,
+        error_buf: *mut u8,
+        error_buf_size: u32,
+    ) -> *const c_void;
+
+    fn wasm_runtime_lookup_function(
+        module_inst: *const c_void,
+        name: *const i8,
+        signature: *const u8,
+    ) -> *const c_void;
+
+    fn wasm_runtime_create_exec_env(module_inst: *const c_void, stack_size: u32) -> *const c_void;
+
+    fn wasm_runtime_call_wasm(
+        exec_env: *const c_void,
+        function: *const c_void,
+        argc: u32,
+        argv: *const u32,
+    ) -> bool;
+
+    fn wasm_runtime_module_dup_data(module_inst: *const c_void, src: *const u8, size: u32) -> u32;
+
+    fn wasm_runtime_module_free(module_inst: *const c_void, ptr: u32);
+}
+
+#[derive(Default)]
+pub struct WAMicroRuntime;
+
+impl TeaclaveExecutor for WAMicroRuntime {
+    fn execute(
+        &self,
+        _name: String,
+        arguments: FunctionArguments,
+        payload: Vec<u8>,
+        runtime: FunctionRuntime,
+    ) -> anyhow::Result<String> {
+        let wa_argv: Vec<_> = arguments.into_vec();
+
+        let mut error_buf = [0u8; DEFAULT_ERROR_BUF_SIZE];
+        let entry_name = CString::new("entrypoint").expect("CString::new failed");
+
+        set_thread_context(Context::new(runtime))?;
+
+        unsafe { wasm_runtime_init() };
+        let module = unsafe {
+            wasm_runtime_load(
+                payload.as_ptr(),
+                payload.len() as u32,
+                error_buf.as_mut_ptr(),
+                error_buf.len() as u32,
+            )
+        };
+
+        assert!((module as usize) != 0);
+
+        error_buf = [0u8; DEFAULT_ERROR_BUF_SIZE];
+        let module_instance = unsafe {
+            wasm_runtime_instantiate(
+                module,
+                DEFAULT_STACK_SIZE,
+                DEFAULT_HEAP_SIZE,
+                error_buf.as_mut_ptr(),
+                error_buf.len() as u32,
+            )
+        };
+        assert!((module_instance as usize) != 0);
+
+        let entry_func = unsafe {
+            wasm_runtime_lookup_function(module_instance, entry_name.as_ptr(), std::ptr::null())
+        };
+        assert!((entry_func as usize) != 0);
+
+        let exec_env = unsafe { wasm_runtime_create_exec_env(module_instance, DEFAULT_STACK_SIZE) };
+        assert!((exec_env as usize) != 0);
+
+        // prepare the arguments
+        // for best compatibility with Teaclave, the function signature is `int entrypoint(int argc, char* argv[])`
+        let cstr_argv: Vec<_> = wa_argv
+            .iter()
+            .map(|arg| CString::new(arg.as_str()).unwrap())
+            .collect();
+        let wasm_argc = 2;
+        let p_argv: Vec<u32> = cstr_argv
+            .iter() // do NOT into_iter()
+            .map(|arg| unsafe {
+                wasm_runtime_module_dup_data(
+                    module_instance,
+                    arg.as_ptr() as *const u8,
+                    arg.to_bytes_with_nul().len() as u32,
+                )
+            })
+            .collect();
+        let func_argv = unsafe {
+            wasm_runtime_module_dup_data(
+                module_instance,
+                p_argv.as_ptr() as *const u8,
+                (p_argv.len() * 4) as u32,
+            )
+        };
+        let wasm_argv: [u32; 2] = [p_argv.len() as u32, func_argv];
+
+        if unsafe { wasm_runtime_call_wasm(exec_env, entry_func, wasm_argc, wasm_argv.as_ptr()) } {
+            reset_thread_context()?;
+            log::debug!(
+                "IN WAMicroRuntime::execute after `wasm_runtime_call_wasm`, {:?}",
+                wasm_argv[0]
+            );
+            // clean WAMR allocated memory
+            let _ = p_argv
+                .iter()
+                .map(|addr| unsafe { wasm_runtime_module_free(module_instance, *addr) });
+            unsafe { wasm_runtime_module_free(module_instance, func_argv) };
+            Ok(wasm_argv[0].to_string())
+        } else {
+            Ok("WAMR Error".to_string())
+        }
+    }
+}
+
+#[cfg(feature = "enclave_unit_test")]
+pub mod tests {
+    use super::*;
+    use std::collections::HashMap;
+    use teaclave_runtime::*;
+    use teaclave_test_utils::*;
+    use teaclave_types::*;
+
+    pub fn run_tests() -> bool {
+        run_tests!(test_wamr,)
+    }
+
+    fn test_wamr() {
+        let mut args = HashMap::new();
+
+        args.insert("adder 1".to_string(), "3".to_string());
+        args.insert("adder 2".to_string(), "4".to_string());
+        let args = FunctionArguments::from(args);
+
+        let wa_payload =
+            include_bytes!("../../examples/python/wasm_simple_add_payload/simple_add.wasm");
+
+        let wa_payload = wa_payload.to_vec();
+
+        let input_files = StagedFiles::default();
+        let output_files = StagedFiles::default();
+
+        let runtime = Box::new(RawIoRuntime::new(input_files, output_files));
+
+        let function = WAMicroRuntime::default();
+        let summary = function
+            .execute("".to_string(), args, wa_payload, runtime)
+            .unwrap();
+        log::debug!("IN TEST test_wamr: AFTER execution, summary: {:?}", summary);
+
+        assert_eq!(summary, "7");
+    }
+}
diff --git a/LICENSE b/licenses/LICENSE-wasm-micro-runtime.txt
similarity index 92%
copy from LICENSE
copy to licenses/LICENSE-wasm-micro-runtime.txt
index 310ee62..c6bd7e0 100644
--- a/LICENSE
+++ b/licenses/LICENSE-wasm-micro-runtime.txt
@@ -1,4 +1,3 @@
-
                                  Apache License
                            Version 2.0, January 2004
                         http://www.apache.org/licenses/
@@ -202,27 +201,19 @@
    limitations under the License.
 
 
--------------------------------------------------------------------------------
-This product bundles various third-party components under other open source
-licenses. This section summarizes those components and their licenses. See
-licenses/ for text of these licenses.
-
-
-Apache License, Version 2.0
----------------------------
-
-third-party/crates-io
-third-party/crates-sgx
-
-
-BSD 3-Clause License
---------------------
-
-common/protected_fs_rs/protected_fs_c
+--- LLVM Exceptions to the Apache 2.0 License ----
 
+As an exception, if, as a result of your compiling your source code, portions
+of this Software are embedded into an Object form of such source code, you
+may redistribute such embedded portions in such Object form without complying
+with the conditions of Sections 4(a), 4(b) and 4(d) of the License.
 
-MIT License
------------
+In addition, if you combine or link compiled forms of this Software with
+software that is licensed under the GPLv2 ("Combined Software") and if a
+court of competent jurisdiction determines that the patent provision (Section
+3), the indemnity provision (Section 9) or other Section of the License
+conflicts with the conditions of the GPLv2, you may retroactively and
+prospectively choose to deem waived or otherwise exclude such Section(s) of
+the License, but only in their entirety and only with respect to the Combined
+Software.
 
-third_party/mesapy
-common/rusty_leveldb_sgx
diff --git a/rpc/src/protocol.rs b/rpc/src/protocol.rs
index aa73b4e..c8496af 100644
--- a/rpc/src/protocol.rs
+++ b/rpc/src/protocol.rs
@@ -103,7 +103,7 @@ where
         let buf_len = send_buf.len() as u64;
         let header = buf_len.to_be_bytes();
 
-        self.transport.write(&header)?;
+        self.transport.write_all(&header)?;
         self.transport.write_all(&send_buf)?;
         self.transport.flush()?;
 
diff --git a/sdk/rust/src/bindings.rs b/sdk/rust/src/bindings.rs
index be7b072..bdb0d5b 100644
--- a/sdk/rust/src/bindings.rs
+++ b/sdk/rust/src/bindings.rs
@@ -62,8 +62,12 @@ macro_rules! unwrap_or_return_one {
 ///
 /// * The function returns an opaque pointer (handle) of the service. On error,
 /// the function returns NULL.
+///
+/// # Safety
+///
+/// `address`, `enclave_info_path`, `as_root_ca_cert_path` should be C string (null terminated).
 #[no_mangle]
-pub extern "C" fn teaclave_connect_authentication_service(
+pub unsafe extern "C" fn teaclave_connect_authentication_service(
     address: *const c_char,
     enclave_info_path: *const c_char,
     as_root_ca_cert_path: *const c_char,
@@ -72,17 +76,13 @@ pub extern "C" fn teaclave_connect_authentication_service(
         return ptr::null_mut();
     }
 
-    let address = unsafe { CStr::from_ptr(address).to_string_lossy().into_owned() };
-    let enclave_info_path = unsafe {
-        CStr::from_ptr(enclave_info_path)
-            .to_string_lossy()
-            .into_owned()
-    };
-    let as_root_ca_cert_path = unsafe {
-        CStr::from_ptr(as_root_ca_cert_path)
-            .to_string_lossy()
-            .into_owned()
-    };
+    let address = CStr::from_ptr(address).to_string_lossy().into_owned();
+    let enclave_info_path = CStr::from_ptr(enclave_info_path)
+        .to_string_lossy()
+        .into_owned();
+    let as_root_ca_cert_path = CStr::from_ptr(as_root_ca_cert_path)
+        .to_string_lossy()
+        .into_owned();
     let enclave_info = unwrap_or_return_null!(EnclaveInfo::from_file(enclave_info_path));
     let bytes = unwrap_or_return_null!(fs::read(as_root_ca_cert_path));
     let as_root_ca_cert = unwrap_or_return_null!(pem::parse(bytes)).contents;
@@ -98,6 +98,12 @@ pub extern "C" fn teaclave_connect_authentication_service(
 /// Close and free the authentication service handle, i.e., the
 /// `AuthenticaionClient` type opaque pointer. The function returns 0 for
 /// success. On error, the function returns 1.
+///
+/// # Safety
+///
+/// This function is unsafe because improper use may lead to
+/// memory problems. For example, a double-free may occur if the
+/// function is called twice on the same raw pointer.
 #[no_mangle]
 pub unsafe extern "C" fn teaclave_close_authentication_service(
     client: *mut AuthenticationClient,
@@ -113,8 +119,12 @@ pub unsafe extern "C" fn teaclave_close_authentication_service(
 
 /// Register a new user with `user_id` and `user_password`. The function returns
 /// 0 for success. On error, the function returns 1.
+///
+/// # Safety
+///
+/// `user_id`, `user_password` should be C string (null terminated).
 #[no_mangle]
-pub extern "C" fn teaclave_user_register(
+pub unsafe extern "C" fn teaclave_user_register(
     client: &mut AuthenticationClient,
     user_id: *const c_char,
     user_password: *const c_char,
@@ -126,8 +136,8 @@ pub extern "C" fn teaclave_user_register(
         return 1;
     }
 
-    let user_id = unsafe { CStr::from_ptr(user_id).to_string_lossy().into_owned() };
-    let user_password = unsafe { CStr::from_ptr(user_password).to_string_lossy().into_owned() };
+    let user_id = CStr::from_ptr(user_id).to_string_lossy().into_owned();
+    let user_password = CStr::from_ptr(user_password).to_string_lossy().into_owned();
     unwrap_or_return_one!(client.user_register(&user_id, &user_password));
 
     0
@@ -137,8 +147,12 @@ pub extern "C" fn teaclave_user_register(
 /// will be save in the `token` buffer, and length will be set in the
 /// `token_len` argument. The function returns 0 for success. On error, the
 /// function returns 1.
+///
+/// # Safety
+///
+/// `user_id`, `user_password` should be C string (null terminated), token and token_len should be consistent.
 #[no_mangle]
-pub extern "C" fn teaclave_user_login(
+pub unsafe extern "C" fn teaclave_user_login(
     client: &mut AuthenticationClient,
     user_id: *const c_char,
     user_password: *const c_char,
@@ -154,20 +168,18 @@ pub extern "C" fn teaclave_user_login(
         return 1;
     }
 
-    let user_id = unsafe { CStr::from_ptr(user_id).to_string_lossy().into_owned() };
-    let user_password = unsafe { CStr::from_ptr(user_password).to_string_lossy().into_owned() };
+    let user_id = CStr::from_ptr(user_id).to_string_lossy().into_owned();
+    let user_password = CStr::from_ptr(user_password).to_string_lossy().into_owned();
 
     let token_string = unwrap_or_return_one!(client.user_login(&user_id, &user_password));
     let token_c_string = unwrap_or_return_one!(CString::new(token_string));
     let bytes = token_c_string.as_bytes_with_nul();
 
-    unsafe {
-        if *token_len < bytes.len() {
-            return 1;
-        } else {
-            ptr::copy_nonoverlapping(bytes.as_ptr(), token as _, bytes.len());
-            *token_len = bytes.len();
-        }
+    if *token_len < bytes.len() {
+        return 1;
+    } else {
+        ptr::copy_nonoverlapping(bytes.as_ptr(), token as _, bytes.len());
+        *token_len = bytes.len();
     }
 
     0
@@ -190,8 +202,12 @@ pub extern "C" fn teaclave_user_login(
 ///
 /// * The function returns an opaque pointer (handle) of the service. On error,
 /// the function returns NULL.
+///
+/// # Safety
+///
+/// All arguments should be C string (null terminated).
 #[no_mangle]
-pub extern "C" fn teaclave_connect_frontend_service(
+pub unsafe extern "C" fn teaclave_connect_frontend_service(
     address: *const c_char,
     enclave_info_path: *const c_char,
     as_root_ca_cert_path: *const c_char,
@@ -200,17 +216,13 @@ pub extern "C" fn teaclave_connect_frontend_service(
         return ptr::null_mut();
     }
 
-    let address = unsafe { CStr::from_ptr(address).to_string_lossy().into_owned() };
-    let enclave_info_path = unsafe {
-        CStr::from_ptr(enclave_info_path)
-            .to_string_lossy()
-            .into_owned()
-    };
-    let as_root_ca_cert_path = unsafe {
-        CStr::from_ptr(as_root_ca_cert_path)
-            .to_string_lossy()
-            .into_owned()
-    };
+    let address = CStr::from_ptr(address).to_string_lossy().into_owned();
+    let enclave_info_path = CStr::from_ptr(enclave_info_path)
+        .to_string_lossy()
+        .into_owned();
+    let as_root_ca_cert_path = CStr::from_ptr(as_root_ca_cert_path)
+        .to_string_lossy()
+        .into_owned();
     let enclave_info = unwrap_or_return_null!(EnclaveInfo::from_file(enclave_info_path));
     let bytes = unwrap_or_return_null!(fs::read(as_root_ca_cert_path));
     let as_root_ca_cert = unwrap_or_return_null!(pem::parse(bytes)).contents;
@@ -226,6 +238,12 @@ pub extern "C" fn teaclave_connect_frontend_service(
 /// Close and free the frontend service handle, i.e., the `FrontendClient` type
 /// opaque pointer. The function returns 0 for success. On error, the function
 /// returns 1.
+///
+/// # Safety
+///
+/// This function is unsafe because improper use may lead to
+/// memory problems. For example, a double-free may occur if the
+/// function is called twice on the same raw pointer.
 #[no_mangle]
 pub unsafe extern "C" fn teaclave_close_frontend_service(client: *mut FrontendClient) -> c_int {
     if client.is_null() {
@@ -239,8 +257,12 @@ pub unsafe extern "C" fn teaclave_close_frontend_service(client: *mut FrontendCl
 
 /// Set user's credential with `user_id` and `user_token`. The function returns
 /// 0 for success. On error, the function returns 1.
+///
+/// # Safety
+///
+/// `user_id` and `user_token` should be C string (null terminated).
 #[no_mangle]
-pub extern "C" fn teaclave_set_credential(
+pub unsafe extern "C" fn teaclave_set_credential(
     client: &mut FrontendClient,
     user_id: *const c_char,
     user_token: *const c_char,
@@ -249,8 +271,8 @@ pub extern "C" fn teaclave_set_credential(
         return 1;
     }
 
-    let user_id = unsafe { CStr::from_ptr(user_id).to_string_lossy().into_owned() };
-    let user_token = unsafe { CStr::from_ptr(user_token).to_string_lossy().into_owned() };
+    let user_id = CStr::from_ptr(user_id).to_string_lossy().into_owned();
+    let user_token = CStr::from_ptr(user_token).to_string_lossy().into_owned();
     client.set_credential(&user_id, &user_token);
 
     0
@@ -258,8 +280,12 @@ pub extern "C" fn teaclave_set_credential(
 
 /// Invoke task with `task_id`. The function returns 0 for success. On error,
 /// the function returns 1.
+///
+/// # Safety
+///
+/// `task_id` should be C string (null terminated).
 #[no_mangle]
-pub extern "C" fn teaclave_invoke_task(
+pub unsafe extern "C" fn teaclave_invoke_task(
     client: &mut FrontendClient,
     task_id: *const c_char,
 ) -> c_int {
@@ -267,7 +293,7 @@ pub extern "C" fn teaclave_invoke_task(
         return 1;
     }
 
-    let task_id = unsafe { CStr::from_ptr(task_id).to_string_lossy().into_owned() };
+    let task_id = CStr::from_ptr(task_id).to_string_lossy().into_owned();
     match client.invoke_task(&task_id) {
         Ok(_) => 0,
         Err(_) => 1,
@@ -278,8 +304,12 @@ pub extern "C" fn teaclave_invoke_task(
 /// buffer, and set corresponding `task_result_len` argument. Note that this is
 /// a blocking function and wait for the return of the task. The function
 /// returns 0 for success. On error, the function returns 1.
+///
+/// # Safety
+///
+/// Inconsistent length of allocated buffer may caused overflow.
 #[no_mangle]
-pub extern "C" fn teaclave_get_task_result(
+pub unsafe extern "C" fn teaclave_get_task_result(
     client: &mut FrontendClient,
     task_id: *const c_char,
     task_result: *mut c_char,
@@ -289,16 +319,14 @@ pub extern "C" fn teaclave_get_task_result(
         return 1;
     }
 
-    let task_id = unsafe { CStr::from_ptr(task_id).to_string_lossy().into_owned() };
+    let task_id = CStr::from_ptr(task_id).to_string_lossy().into_owned();
     match client.get_task_result(&task_id) {
         Ok(result) => {
-            unsafe {
-                if *task_result_len < result.len() {
-                    return 1;
-                } else {
-                    ptr::copy_nonoverlapping(result.as_ptr(), task_result as _, result.len());
-                    *task_result_len = result.len();
-                }
+            if *task_result_len < result.len() {
+                return 1;
+            } else {
+                ptr::copy_nonoverlapping(result.as_ptr(), task_result as _, result.len());
+                *task_result_len = result.len();
             }
             0
         }
@@ -323,8 +351,12 @@ macro_rules! generate_function_serialized {
         /// # Return
         ///
         /// The function returns 0 for success. On error, the function returns 1.
+        ///
+        /// # Safety
+        ///
+        /// Inconsistent length of allocated buffer may caused overflow.
         #[no_mangle]
-        pub extern "C" fn $c_function_name(
+        pub unsafe extern "C" fn $c_function_name(
             client: &mut $client_type,
             serialized_request: *const c_char,
             serialized_response: *mut c_char,
@@ -338,23 +370,19 @@ macro_rules! generate_function_serialized {
                 return 1;
             }
 
-            let serialized_request = unsafe {
-                CStr::from_ptr(serialized_request)
-                    .to_string_lossy()
-                    .into_owned()
-            };
+            let serialized_request = CStr::from_ptr(serialized_request)
+                .to_string_lossy()
+                .into_owned();
             let function_id_string =
                 unwrap_or_return_one!(client.$rust_function_name(&serialized_request));
             let function_id_c_string = unwrap_or_return_one!(CString::new(function_id_string));
             let bytes = function_id_c_string.as_bytes_with_nul();
 
-            unsafe {
-                if *serialized_response_len < bytes.len() {
-                    return 1;
-                } else {
-                    ptr::copy_nonoverlapping(bytes.as_ptr(), serialized_response as _, bytes.len());
-                    *serialized_response_len = bytes.len();
-                }
+            if *serialized_response_len < bytes.len() {
+                return 1;
+            } else {
+                ptr::copy_nonoverlapping(bytes.as_ptr(), serialized_response as _, bytes.len());
+                *serialized_response_len = bytes.len();
             }
 
             0
diff --git a/sdk/rust/src/lib.rs b/sdk/rust/src/lib.rs
index 633b9ce..95c768c 100644
--- a/sdk/rust/src/lib.rs
+++ b/sdk/rust/src/lib.rs
@@ -190,6 +190,7 @@ impl FrontendClient {
         Ok(response)
     }
 
+    #[allow(clippy::too_many_arguments)]
     pub fn register_function(
         &mut self,
         name: &str,
diff --git a/services/proto/proto_gen/main.rs b/services/proto/proto_gen/main.rs
index d686980..00eddf6 100644
--- a/services/proto/proto_gen/main.rs
+++ b/services/proto/proto_gen/main.rs
@@ -15,9 +15,7 @@
 // specific language governing permissions and limitations
 // under the License.
 
-use askama;
 use askama::Template;
-use prost_build;
 use std::path;
 use structopt::StructOpt;
 
diff --git a/third_party/wamr.patch b/third_party/wamr.patch
new file mode 100644
index 0000000..793b07d
--- /dev/null
+++ b/third_party/wamr.patch
@@ -0,0 +1,651 @@
+diff --git a/core/shared/platform/teaclave-sgx/platform_internal.h b/core/shared/platform/teaclave-sgx/platform_internal.h
+new file mode 100644
+index 0000000..93417b4
+--- /dev/null
++++ b/core/shared/platform/teaclave-sgx/platform_internal.h
+@@ -0,0 +1,58 @@
++/*
++ * Copyright (C) 2019 Intel Corporation.  All rights reserved.
++ * SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
++ */
++
++#ifndef _PLATFORM_INTERNAL_H
++#define _PLATFORM_INTERNAL_H
++
++#include <inttypes.h>
++#include <stdbool.h>
++#include <assert.h>
++#include <time.h>
++#include <string.h>
++#include <stdio.h>
++#include <stdlib.h>
++#include <math.h>
++#include <unistd.h>
++#include <stdarg.h>
++#include <ctype.h>
++#include <limits.h>
++#include <errno.h>
++#include <sgx_thread.h>
++#include <pthread.h>
++
++#include "sgx_error.h"
++
++#ifdef __cplusplus
++extern "C" {
++#endif
++
++#ifndef BH_PLATFORM_LINUX_SGX
++#define BH_PLATFORM_LINUX_SGX
++#endif
++
++#define _STACK_SIZE_ADJUSTMENT (32 * 1024)
++
++/* Stack size of applet threads's native part.  */
++#define BH_APPLET_PRESERVED_STACK_SIZE      (8 * 1024 + _STACK_SIZE_ADJUSTMENT)
++
++/* Default thread priority */
++#define BH_THREAD_DEFAULT_PRIORITY 0
++
++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
++
++#endif /* end of _PLATFORM_INTERNAL_H */
++
+diff --git a/core/shared/platform/teaclave-sgx/sgx_platform.c b/core/shared/platform/teaclave-sgx/sgx_platform.c
+new file mode 100644
+index 0000000..e819f26
+--- /dev/null
++++ b/core/shared/platform/teaclave-sgx/sgx_platform.c
+@@ -0,0 +1,172 @@
++/*
++ * Copyright (C) 2019 Intel Corporation.  All rights reserved.
++ * SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
++ */
++
++#include "platform_api_vmcore.h"
++#include "platform_api_extension.h"
++#include "sgx_rsrv_mem_mngr.h"
++
++#define FIXED_BUFFER_SIZE (1<<9)
++
++static os_print_function_t print_function = NULL;
++
++int bh_platform_init()
++{
++    return 0;
++}
++
++void
++bh_platform_destroy()
++{
++}
++
++void *
++os_malloc(unsigned size)
++{
++    return malloc(size);
++}
++
++void *
++os_realloc(void *ptr, unsigned size)
++{
++    return realloc(ptr, size);
++}
++
++void
++os_free(void *ptr)
++{
++    free(ptr);
++}
++
++int putchar(int c)
++{
++    return 0;
++}
++
++int puts(const char *s)
++{
++    return 0;
++}
++
++void os_set_print_function(os_print_function_t pf)
++{
++    print_function = pf;
++}
++
++int os_printf(const char *message, ...)
++{
++    if (print_function != NULL) {
++        char msg[FIXED_BUFFER_SIZE] = { '\0' };
++        va_list ap;
++        va_start(ap, message);
++        vsnprintf(msg, FIXED_BUFFER_SIZE, message, ap);
++        va_end(ap);
++        print_function(msg);
++    }
++
++    return 0;
++}
++
++int os_vprintf(const char * format, va_list arg)
++{
++    if (print_function != NULL) {
++        char msg[FIXED_BUFFER_SIZE] = { '\0' };
++        vsnprintf(msg, FIXED_BUFFER_SIZE, format, arg);
++        print_function(msg);
++    }
++
++    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)
++{
++    int mprot = 0;
++    uint64 aligned_size, page_size;
++    void* ret = NULL;
++    sgx_status_t st = 0;
++
++    page_size = getpagesize();
++    aligned_size = (size + page_size - 1) & ~(page_size - 1);
++
++    if (aligned_size >= UINT32_MAX)
++        return NULL;
++
++    ret = sgx_alloc_rsrv_mem(aligned_size);
++    if (ret == NULL) {
++        os_printf("os_mmap(size=%u, aligned size=%lu, prot=0x%x) failed.",
++                  size, aligned_size, prot);
++        return NULL;
++    }
++
++    if (prot & MMAP_PROT_READ)
++        mprot |= SGX_PROT_READ;
++    if (prot & MMAP_PROT_WRITE)
++        mprot |= SGX_PROT_WRITE;
++    if (prot & MMAP_PROT_EXEC)
++        mprot |= SGX_PROT_EXEC;
++
++    st = sgx_tprotect_rsrv_mem(ret, aligned_size, mprot);
++    if (st != SGX_SUCCESS) {
++        os_printf("os_mmap(size=%u, prot=0x%x) failed to set protect.",
++                  size, prot);
++        sgx_free_rsrv_mem(ret, aligned_size);
++        return NULL;
++    }
++
++    return ret;
++}
++
++void os_munmap(void *addr, size_t size)
++{
++    uint64 aligned_size, page_size;
++
++    page_size = getpagesize();
++    aligned_size = (size + page_size - 1) & ~(page_size - 1);
++    sgx_free_rsrv_mem(addr, aligned_size);
++}
++
++int os_mprotect(void *addr, size_t size, int prot)
++{
++    int mprot = 0;
++    sgx_status_t st = 0;
++    uint64 aligned_size, page_size;
++
++    page_size = getpagesize();
++    aligned_size = (size + page_size - 1) & ~(page_size - 1);
++
++    if (prot & MMAP_PROT_READ)
++        mprot |= SGX_PROT_READ;
++    if (prot & MMAP_PROT_WRITE)
++        mprot |= SGX_PROT_WRITE;
++    if (prot & MMAP_PROT_EXEC)
++        mprot |= SGX_PROT_EXEC;
++    st = sgx_tprotect_rsrv_mem(addr, aligned_size, mprot);
++    if (st != SGX_SUCCESS)
++        os_printf("os_mprotect(addr=0x%"PRIx64", size=%u, prot=0x%x) failed.",
++                  (uintptr_t)addr, size, prot);
++
++    return (st == SGX_SUCCESS? 0:-1);
++}
++
++uint64
++os_time_get_boot_microsecond()
++{
++    /* TODO */
++    return 0;
++}
++
++void
++os_dcache_flush(void)
++{
++}
++
+diff --git a/core/shared/platform/teaclave-sgx/sgx_rsrv_mem_mngr.h b/core/shared/platform/teaclave-sgx/sgx_rsrv_mem_mngr.h
+new file mode 100644
+index 0000000..b32a68b
+--- /dev/null
++++ b/core/shared/platform/teaclave-sgx/sgx_rsrv_mem_mngr.h
+@@ -0,0 +1,90 @@
++/*
++ * Copyright (C) 2011-2019 Intel Corporation. All rights reserved.
++ *
++ * Redistribution and use in source and binary forms, with or without
++ * modification, are permitted provided that the following conditions
++ * are met:
++ *
++ *   * Redistributions of source code must retain the above copyright
++ *     notice, this list of conditions and the following disclaimer.
++ *   * Redistributions in binary form must reproduce the above copyright
++ *     notice, this list of conditions and the following disclaimer in
++ *     the documentation and/or other materials provided with the
++ *     distribution.
++ *   * Neither the name of Intel Corporation nor the names of its
++ *     contributors may be used to endorse or promote products derived
++ *     from this software without specific prior written permission.
++ *
++ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
++ * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
++ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
++ * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
++ * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
++ * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
++ * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
++ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
++ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
++ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
++ * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
++ *
++ */
++
++/*
++ * This file is copied from https://github.com/intel/linux-sgx/blob/4589daddd58bec7367a6a9de3fe301e6de17671a/common/inc/internal/sgx_rsrv_mem_mngr.h
++ * The reason we copied here is that the official SGX SDK release has
++ * not included this header file yet.
++ */
++
++#pragma once
++
++#ifndef _SGX_RSRV_MEM_MNGR_H_
++#define _SGX_RSRV_MEM_MNGR_H_
++
++#include "stdint.h"
++#include "sgx_error.h"
++
++#define SGX_PROT_READ	0x1		/* page can be read */
++#define SGX_PROT_WRITE	0x2		/* page can be written */
++#define SGX_PROT_EXEC	0x4		/* page can be executed */
++#define SGX_PROT_NONE	0x0		/* page can not be accessed */
++
++#ifdef __cplusplus
++extern "C" {
++#endif
++
++    /* Allocate a range of EPC memory from the reserved memory area with RW permission
++     *
++     * Parameters:
++     * Inputs: length [in]: Size of region to be allocated in bytes. Page aligned
++     * Return: Starting address of the new allocated memory area on success; otherwise NULL
++     */
++    void * sgx_alloc_rsrv_mem(size_t length);
++
++
++    /* Free a range of EPC memory from the reserved memory area
++     *
++     * Parameters:
++     * Inputs: addr[in]: Starting address of region to be freed. Page aligned.
++     *         length[in]: The length of the memory to be freed in bytes.  Page aligned
++     * Return: 0 on success; otherwise -1
++     */
++    int sgx_free_rsrv_mem(void * addr, size_t length);
++
++
++    /* Modify the access permissions of the pages in the reserved memory area.
++     *
++     * Parameters: 
++     * Inputs: addr[in]: Starting address of region which needs to change access permission. Page aligned.
++     *         length[in]: The length of the memory to be manipulated in bytes. Page aligned.
++     *         prot[in]: The target memory protection.
++     * Return: sgx_status_t - SGX_SUCCESS or failure as defined in sgx_error.h
++     */
++    sgx_status_t sgx_tprotect_rsrv_mem(void *addr, size_t len, int prot);
++
++
++#ifdef __cplusplus
++}
++#endif
++
++#endif
++
+diff --git a/core/shared/platform/teaclave-sgx/sgx_thread.c b/core/shared/platform/teaclave-sgx/sgx_thread.c
+new file mode 100644
+index 0000000..d1503b4
+--- /dev/null
++++ b/core/shared/platform/teaclave-sgx/sgx_thread.c
+@@ -0,0 +1,180 @@
++/*
++ * Copyright (C) 2019 Intel Corporation.  All rights reserved.
++ * SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
++ */
++
++#include "platform_api_vmcore.h"
++#include "platform_api_extension.h"
++
++#ifndef SGX_DISABLE_PTHREAD
++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);
++}
++#endif
++
++korp_tid os_self_thread()
++{
++#ifndef SGX_DISABLE_PTHREAD
++    return pthread_self();
++#else
++    return 0;
++#endif
++}
++
++int os_mutex_init(korp_mutex *mutex)
++{
++#ifndef SGX_DISABLE_PTHREAD
++    pthread_mutex_t m = PTHREAD_MUTEX_INITIALIZER;
++    *mutex = m;
++#endif
++    return BHT_OK;
++}
++
++int os_mutex_destroy(korp_mutex *mutex)
++{
++#ifndef SGX_DISABLE_PTHREAD
++    pthread_mutex_destroy(mutex);
++#endif
++    return BHT_OK;
++}
++
++int os_mutex_lock(korp_mutex *mutex)
++{
++#ifndef SGX_DISABLE_PTHREAD
++    return pthread_mutex_lock(mutex);
++#else
++    return 0;
++#endif
++}
++
++int os_mutex_unlock(korp_mutex *mutex)
++{
++#ifndef SGX_DISABLE_PTHREAD
++    return pthread_mutex_unlock(mutex);
++#else
++    return 0;
++#endif
++}
++
++int os_cond_init(korp_cond *cond)
++{
++#ifndef SGX_DISABLE_PTHREAD
++    pthread_cond_t c = PTHREAD_COND_INITIALIZER;
++    *cond = c;
++#endif
++    return BHT_OK;
++}
++
++int os_cond_destroy(korp_cond *cond)
++{
++#ifndef SGX_DISABLE_PTHREAD
++    pthread_cond_destroy(cond);
++#endif
++    return BHT_OK;
++}
++
++int os_cond_wait(korp_cond *cond, korp_mutex *mutex)
++{
++#ifndef SGX_DISABLE_PTHREAD
++    assert(cond);
++    assert(mutex);
++
++    if (pthread_cond_wait(cond, mutex) != BHT_OK)
++        return BHT_ERROR;
++
++#endif
++    return BHT_OK;
++}
++
++int os_cond_reltimedwait(korp_cond *cond, korp_mutex *mutex, uint64 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)
++{
++#ifndef SGX_DISABLE_PTHREAD
++    assert(cond);
++
++    if (pthread_cond_signal(cond) != BHT_OK)
++        return BHT_ERROR;
++
++#endif
++    return BHT_OK;
++}
++
++int os_thread_join(korp_tid thread, void **value_ptr)
++{
++#ifndef SGX_DISABLE_PTHREAD
++    return pthread_join(thread, value_ptr);
++#else
++    return 0;
++#endif
++}
++
++int os_thread_detach(korp_tid thread)
++{
++    /* SGX pthread_detach isn't provided, return directly. */
++    return 0;
++}
++
++void os_thread_exit(void *retval)
++{
++#ifndef SGX_DISABLE_PTHREAD
++    pthread_exit(retval);
++#else
++    return;
++#endif
++}
++
++uint8 *os_thread_get_stack_boundary()
++{
++    /* TODO: get sgx stack boundary */
++    return NULL;
++}
++
+diff --git a/core/shared/platform/teaclave-sgx/shared_platform.cmake b/core/shared/platform/teaclave-sgx/shared_platform.cmake
+new file mode 100644
+index 0000000..fa3a7aa
+--- /dev/null
++++ b/core/shared/platform/teaclave-sgx/shared_platform.cmake
+@@ -0,0 +1,33 @@
++# Copyright (C) 2019 Intel Corporation.  All rights reserved.
++# SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
++
++set (PLATFORM_SHARED_DIR ${CMAKE_CURRENT_LIST_DIR})
++
++add_definitions(-DBH_PLATFORM_LINUX_SGX)
++
++include_directories(${PLATFORM_SHARED_DIR})
++include_directories(${PLATFORM_SHARED_DIR}/../include)
++
++if ("$ENV{SGX_SDK}" STREQUAL "")
++  set (SGX_SDK_DIR "/opt/intel/sgxsdk")
++else()
++  set (SGX_SDK_DIR $ENV{SGX_SDK})
++endif()
++
++include_directories (${SGX_SDK_DIR}/include)
++if (NOT BUILD_UNTRUST_PART EQUAL 1)
++  include_directories (${SGX_SDK_DIR}/include/tlibc
++                       ${SGX_SDK_DIR}/include/libcxx)
++endif ()
++
++if (NOT WAMR_BUILD_LIBC_WASI EQUAL 1)
++  add_definitions(-DSGX_DISABLE_WASI)
++endif ()
++
++if (NOT WAMR_BUILD_THREAD_MGR EQUAL 1)
++  add_definitions(-DSGX_DISABLE_PTHREAD)
++endif ()
++
++file (GLOB source_all ${PLATFORM_SHARED_DIR}/*.c)
++
++set (PLATFORM_SHARED_SOURCE ${source_all})
+diff --git a/product-mini/platforms/teaclave-sgx/CMakeLists.txt b/product-mini/platforms/teaclave-sgx/CMakeLists.txt
+new file mode 100644
+index 0000000..d4c71d8
+--- /dev/null
++++ b/product-mini/platforms/teaclave-sgx/CMakeLists.txt
+@@ -0,0 +1,82 @@
++# Copyright (C) 2019 Intel Corporation.  All rights reserved.
++# SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
++
++cmake_minimum_required (VERSION 2.8)
++
++project (iwasm)
++
++set (WAMR_BUILD_PLATFORM "teaclave-sgx")
++
++# Reset default linker flags
++set (CMAKE_SHARED_LIBRARY_LINK_C_FLAGS "")
++set (CMAKE_SHARED_LIBRARY_LINK_CXX_FLAGS "")
++
++# Set WAMR_BUILD_TARGET
++if (NOT DEFINED WAMR_BUILD_TARGET)
++  if (CMAKE_SIZEOF_VOID_P EQUAL 8)
++    # Build as X86_64 by default in 64-bit platform
++    set (WAMR_BUILD_TARGET "X86_64")
++  else ()
++    # Build as X86_32 by default in 32-bit platform
++    set (WAMR_BUILD_TARGET "X86_32")
++  endif ()
++endif ()
++
++if (NOT CMAKE_BUILD_TYPE)
++  set(CMAKE_BUILD_TYPE Release)
++endif ()
++
++if (NOT DEFINED WAMR_BUILD_INTERP)
++  # Enable Interpreter by default
++  set (WAMR_BUILD_INTERP 1)
++endif ()
++
++if (NOT DEFINED WAMR_BUILD_AOT)
++  # Enable AOT by default
++  # Please install Intel SGX SDKv2.8 or later.
++  set (WAMR_BUILD_AOT 0)
++endif ()
++
++if (NOT DEFINED WAMR_BUILD_JIT)
++  # Disable JIT by default.
++  set (WAMR_BUILD_JIT 0)
++endif ()
++
++if (NOT DEFINED WAMR_BUILD_LIBC_BUILTIN)
++  # Enable libc builtin support by default
++  set (WAMR_BUILD_LIBC_BUILTIN 0)
++endif ()
++
++if (NOT DEFINED WAMR_BUILD_LIBC_WASI)
++  # Enable libc wasi support by default
++  set (WAMR_BUILD_LIBC_WASI 0)
++endif ()
++
++if (NOT DEFINED WAMR_BUILD_FAST_INTERP)
++  # Enable fast interpreter
++  set (WAMR_BUILD_FAST_INTERP 0)
++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 0)
++endif ()
++
++if (COLLECT_CODE_COVERAGE EQUAL 1)
++  set (CMAKE_C_FLAGS "${CMAKE_C_FLAGS} -fprofile-arcs -ftest-coverage")
++endif ()
++
++set (CMAKE_EXE_LINKER_FLAGS "${CMAKE_EXE_LINKER_FLAGS} -Wl,--gc-sections")
++set (CMAKE_C_FLAGS "${CMAKE_C_FLAGS} -std=gnu99 -ffunction-sections -fdata-sections \
++                                     -Wall -Wno-unused-parameter -Wno-pedantic \
++                                     -nostdinc -fvisibility=hidden -fpie" )
++
++set (WAMR_ROOT_DIR ${CMAKE_CURRENT_SOURCE_DIR}/../../..)
++
++include (${WAMR_ROOT_DIR}/build-scripts/runtime_lib.cmake)
++add_library(vmlib ${WAMR_RUNTIME_LIB_SOURCE})
diff --git a/third_party/wasm-micro-runtime b/third_party/wasm-micro-runtime
new file mode 160000
index 0000000..7706e4b
--- /dev/null
+++ b/third_party/wasm-micro-runtime
@@ -0,0 +1 @@
+Subproject commit 7706e4b1514e5fd95a1c5efe258ecd08467d030a
diff --git a/types/src/worker.rs b/types/src/worker.rs
index 37c5991..a3cc5be 100644
--- a/types/src/worker.rs
+++ b/types/src/worker.rs
@@ -41,6 +41,7 @@ pub trait TeaclaveExecutor {
 pub enum ExecutorType {
     Builtin,
     Python,
+    WAMicroRuntime,
 }
 
 impl std::default::Default for ExecutorType {
@@ -56,6 +57,7 @@ impl std::convert::TryFrom<&str> for ExecutorType {
         let executor_type = match selector {
             "python" => ExecutorType::Python,
             "builtin" => ExecutorType::Builtin,
+            "wamr" => ExecutorType::WAMicroRuntime,
             _ => anyhow::bail!("Invalid executor type: {}", selector),
         };
         Ok(executor_type)
@@ -81,6 +83,7 @@ impl std::fmt::Display for ExecutorType {
         match self {
             ExecutorType::Builtin => write!(f, "builtin"),
             ExecutorType::Python => write!(f, "python"),
+            ExecutorType::WAMicroRuntime => write!(f, "wamr"),
         }
     }
 }
@@ -89,6 +92,7 @@ impl std::fmt::Display for ExecutorType {
 pub enum Executor {
     MesaPy,
     Builtin,
+    WAMicroRuntime,
 }
 
 impl std::default::Default for Executor {
@@ -104,6 +108,7 @@ impl std::convert::TryFrom<&str> for Executor {
         let executor = match selector {
             "mesapy" => Executor::MesaPy,
             "builtin" => Executor::Builtin,
+            "wamr" => Executor::WAMicroRuntime,
             _ => anyhow::bail!("Unsupported executor: {}", selector),
         };
         Ok(executor)
@@ -123,6 +128,7 @@ impl std::fmt::Display for Executor {
         match self {
             Executor::MesaPy => write!(f, "mesapy"),
             Executor::Builtin => write!(f, "builtin"),
+            Executor::WAMicroRuntime => write!(f, "wamr"),
         }
     }
 }
diff --git a/worker/src/worker.rs b/worker/src/worker.rs
index 2109451..1f1ed1e 100644
--- a/worker/src/worker.rs
+++ b/worker/src/worker.rs
@@ -23,7 +23,7 @@ use std::format;
 
 use teaclave_types::{Executor, ExecutorType, StagedFiles, StagedFunction};
 
-use teaclave_executor::{BuiltinFunctionExecutor, MesaPy};
+use teaclave_executor::{BuiltinFunctionExecutor, MesaPy, WAMicroRuntime};
 use teaclave_runtime::DefaultRuntime;
 use teaclave_types::{TeaclaveExecutor, TeaclaveRuntime};
 
@@ -58,6 +58,10 @@ impl Default for Worker {
         worker.register_executor((ExecutorType::Builtin, Executor::Builtin), || {
             Box::new(BuiltinFunctionExecutor::default())
         });
+        worker.register_executor(
+            (ExecutorType::WAMicroRuntime, Executor::WAMicroRuntime),
+            || Box::new(WAMicroRuntime::default()),
+        );
 
         worker
     }

---------------------------------------------------------------------
To unsubscribe, e-mail: commits-unsubscribe@teaclave.apache.org
For additional commands, e-mail: commits-help@teaclave.apache.org