diff --git a/.gitignore b/.gitignore new file mode 100644 index 000000000..0e82e0b5b --- /dev/null +++ b/.gitignore @@ -0,0 +1,2 @@ +.vscode +**/*build/ diff --git a/Dockerfile b/Dockerfile new file mode 100644 index 000000000..565b740e6 --- /dev/null +++ b/Dockerfile @@ -0,0 +1,21 @@ +# Currently supports clang-8 compiler +# Using the "test.c" app from the README.md: +# clang-8 --target=wasm32 -O3 -Wl,--initial-memory=131072,--allow-undefined,--export=main,--no-threads,--strip-all,--no-entry -nostdlib -o test.wasm test.c +# Pay attention to spacing above! ^ +# iwasm test.wasm + +FROM ubuntu:latest + +RUN apt-get update && \ + apt-get -y upgrade && \ + apt-get install -y build-essential clang-8 cmake g++-multilib git lib32gcc-5-dev llvm-8 lld-8 nano + +WORKDIR /root + +RUN git clone https://github.com/intel/wasm-micro-runtime + +RUN cd wasm-micro-runtime/core/iwasm/products/linux/ && mkdir build && \ + cd build && cmake .. && make + +RUN cd /usr/bin && ln -s wasm-ld-8 wasm-ld +RUN cd /usr/bin && ln -s ~/wasm-micro-runtime/core/iwasm/products/linux/build/iwasm iwasm diff --git a/README.md b/README.md index 8a17d7d29..a7383eb65 100644 --- a/README.md +++ b/README.md @@ -1,26 +1,17 @@ WebAssembly Micro Runtime ========================= -WebAssembly Micro Runtime (WAMR) is a standalone WebAssembly (WASM) runtime designed for a small footprint. It includes: -- A WebAssembly (WASM) VM core +WebAssembly Micro Runtime (WAMR) is a standalone WebAssembly (WASM) runtime with small footprint. It includes a few parts as below: +- A WebAssembly VM core (namely iwasm) - The supporting API's for the WASM applications - A mechanism for dynamic management of the WASM application -Why should you use a WASM runtime out of your browser? There are a few points where this might be meaningful: -1. WASM is already an LLVM official backend target. That means WASM can run any programming languages which can be compiled to LLVM IR. It is a huge advantage compared to language bound runtimes like JS or Lua. -2. WASM is an open standard and it is fast becoming supported by the whole web ecosystem. -3. WASM is designed to be very friendly for compiling to native binaries and gaining the native speed. -4. It can potentially change the development practices. Imagine we can do both the WASM application development and validation in a browser, then just download the WASM binary code onto the target device. -5. WASM can work without garbage collection. It is designed to support execution determinics for the time sensitive requirement. -6. Maintain the safety goals WASM has of providing a sandboxed execution environment for untrusted code. In addition, because WASM is a compilation target, this implies the benefit of being able to target both an execution and security profile that is consistent across popular high-level programming languages. - - Current Features of WAMR ========================= - WASM interpreter (AOT is planned) -- Provides support for a subset of Libc. +- Supports for a subset of Libc. - Supports "SIDE_MODULE=1" EMCC compilation option -- Provides API's for embedding runtime into production software +- Provides embedding C API - Provides a mechanism for exporting native API's to WASM applications - Supports the programming of firmware apps in a large range of languages (C/C++/Java/Rust/Go/TypeScript etc.) - App sandbox execution environment on embedded OS @@ -29,631 +20,104 @@ Current Features of WAMR - Supports micro-service and pub-sub event inter-app communication models - Easy to extend to support remote FW application management from host or cloud -Architecture -========================= -The application manager component handles the packets that the platform receives from external sources through any communication buses such as a socket, serial port or SPI. A packet type can be either a request, a response or an event. The application manager will serve the requests with URI "/applet" and call the runtime glue layer interfaces for installing/uninstalling the application. For other URI's, it will filter the resource registration table and route the request to the internal queue of the responsible application. +Application framework architecture +=================================== -- The WebAssembly runtime provides the execution environment for WASM applications. +By using the iwasm VM core, we are flexible to build different application frameworks for the specific domains. -- The messaging layer can support the API for WASM applications to communicate with each other and also the host environment. +The WAMR has offered a comprehensive application framework for device and IoT usages. The framework solves many common requirements for building a real project: +- Modular design for more language runtimes support +- Inter application communication +- Remote application management +- WASM APP programming model and API extension mechanism -- When ahead of time (AOT) compilation is enabled (TODO), the WASM application could be either WASM or a compiled native binary. + - +Build WAMR Core and run WASM applications +================================================ -Build WAMR Core -========================= -Please follow the instructions below to build the WAMR core on different platforms. +WAMR VM core (iwasm) can support building on different platforms: +- Linux +- Zephyr +- Mac +- VxWorks +- AliOS-Things +- Docker +- Intel Software Guard Extention (SGX) -Linux -------------------------- -First of all please install library dependencies of lib gcc. -Use installation commands below for Ubuntu Linux: -``` Bash -sudo apt install lib32gcc-5-dev g++-multilib -``` -Or in Fedora: -``` Bash -sudo dnf install glibc-devel.i686 -``` +After building the iwasm, we can compile some basic WASM applications and run it from the WAMR core. As the WAMR core doesn't include the extended application library, your WASM applications can only use the [WAMR built-in APIs](./doc/wamr_api.md). -After installing dependencies, build the source code: -``` Bash -cd core/iwasm/products/linux/ -mkdir build -cd build -cmake .. -make -``` -VxWorks -------------------------- -VxWorks 7 SR0620 release is validated. +See the [doc/building.md](./doc/building.md) for the detailed instructions. -First you need to build a VSB. Make sure *UTILS_UNIX* layer is added in the VSB. -After the VSB is built, export the VxWorks toolchain path by: -``` -export /host/vx-compiler/bin:$PATH -``` -Now switch to iwasm source tree to build the source code: -``` -cd core/iwasm/products/vxworks/ -mkdir build -cd build -cmake .. -make -``` -Create a VIP based on the VSB. Make sure the following components are added: -* INCLUDE_POSIX_PTHREADS -* INCLUDE_POSIX_PTHREAD_SCHEDULER -* INCLUDE_SHARED_DATA -* INCLUDE_SHL -Copy the generated iwasm executable, the test WASM binary as well as the needed -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). +Embed WAMR +=========== -Zephyr -------------------------- -You need to download the Zephyr source code first and embed WAMR into it. -``` Bash -git clone https://github.com/zephyrproject-rtos/zephyr.git -cd zephyr/samples/ -cp -a /products/zephyr/simple . -cd simple -ln -s iwasm -ln -s shared-lib -mkdir build && cd build -source ../../../zephyr-env.sh -cmake -GNinja -DBOARD=qemu_x86 .. -ninja -``` -AliOS-Things -------------------------- -1. a developerkit board id needed for testing -2. download the AliOS-Things code - ``` Bash - git clone https://github.com/alibaba/AliOS-Things.git - ``` -3. copy /products/alios-things directory to AliOS-Things/middleware, and rename it as iwasm - ``` Bash - cp -a /products/alios-things middleware/iwasm - ``` -4. create a link to in middleware/iwasm/ and rename it to iwasm - ``` Bash - ln -s middleware/iwasm/iwasm - ``` -5. create a link to in middleware/iwasm/ and rename it to shared-lib - ``` Bash - ln -s middle/iwasm/shared-lib - ``` -6. modify file app/example/helloworld/helloworld.c, patch as: - ``` C - #include - #include - extern bool iwasm_init(); - int application_start(int argc, char *argv[]) - { - int count = 0; - iwasm_init(); - ... - } - ``` -7. modify file app/example/helloworld/aos.mk - ``` C - $(NAME)_COMPONENTS := osal_aos iwasm - ``` -8. build source code - ``` Bash - aos make helloworld@developerkit -c config - aos make - ``` -9. download the binary to developerkit board, check the output from serial port +WAMR can be built into a standalone executable which takes the WASM application file name as input, and then executes it. In some other situations, the WAMR source code is embedded the product code and built into the final product. -Build WASM app -========================= -You can write a simple ```test.c``` as the first sample. +WAMR provides a set of C API for loading the WASM module, instantiating the module and invoking a WASM function from a native call. -```C -#include -#include +See the [doc/embed_wamr.md](./doc/embed_wamr.md) for the details. -int main(int argc, char **argv) -{ - char *buf; +WAMR application programming library +=================================== - printf("Hello world!\n"); +WAMR defined event driven programming model: +- Single thread per WASM app instance +- App must implement system callbacks: on_init, on_destrory - buf = malloc(1024); - if (!buf) { - printf("malloc buf failed\n"); - return -1; - } - printf("buf ptr: %p\n", buf); +In general there are a few API classes for the WASM application programming: +- WAMR Built-in API: WAMR core provides a minimal libc API set for WASM APP +- WAMR application libraries: + - Timer + - Micro service (Request/Response) + - Pub/Sub + - Sensor + - Connection and data transmission + - 2D graphic UI (based on littlevgl) +- User extended native API: extend the native API to the WASM applications +- 3rd party libraries: Programmers can download any 3rd party C/C++ source code and build it together with the WASM APP code - sprintf(buf, "%s", "1234\n"); - printf("buf: %s", buf); +See the [doc/wamr_api.md](./doc/wamr_api.md) for the details. - free(buf); - return 0; -} -``` - -There are two methods to build a WASM binary. One is using Emscripten tool, another is using clang compiler. - -## Use Emscripten tool - -A method to build a WASM binary is to use Emscripten tool ```emcc```. -Assuming you are using Linux, you may install emcc from Emscripten EMSDK following the steps below: - -``` -git clone https://github.com/emscripten-core/emsdk.git -emsdk install latest -emsdk activate latest -``` -source ```./emsdk_env.sh```. -The Emscripten website provides other installation methods beyond Linux. - -Use the emcc command below to build the WASM C source code into the WASM binary. -``` Bash -emcc -g -O3 *.c -s WASM=1 -s SIDE_MODULE=1 -s ASSERTIONS=1 -s STACK_OVERFLOW_CHECK=2 \ - -s TOTAL_MEMORY=65536 -s TOTAL_STACK=4096 -o test.wasm -``` -You will get ```test.wasm``` which is the WASM app binary. - -## Use clang compiler - -Another method to build a WASM binary is to use clang compiler```clang-8```. - -Add source to your system source list from llvm website, for ubuntu16.04, add following lines to /etc/apt/sources.list: - -```Bash -deb http://apt.llvm.org/xenial/ llvm-toolchain-xenial main -deb-src http://apt.llvm.org/xenial/ llvm-toolchain-xenial main # 7 -deb http://apt.llvm.org/xenial/ llvm-toolchain-xenial-7 main -deb-src http://apt.llvm.org/xenial/ llvm-toolchain-xenial-7 main # 8 -deb http://apt.llvm.org/xenial/ llvm-toolchain-xenial-8 main -deb-src http://apt.llvm.org/xenial/ llvm-toolchain-xenial-8 main -``` - -Download and install clang-8 tool-chain using following commands: - -```Bash -wget -O - https://apt.llvm.org/llvm-snapshot.gpg.key | sudo apt-key add - -sudo apt-get update -sudo apt-get install llvm-8 lld-8 clang-8 -``` - -Create a soft link under /usr/bin: - -```Bash -cd /usr/bin -sudo ln -s wasm-ld-8 wasm-ld -``` - -Use the clang-8 command below to build the WASM C source code into the WASM binary. - -```Bash -clang-8 --target=wasm32 -O3 -Wl,--initial-memory=131072,--allow-undefined,--export=main, ---no-threads,--strip-all,--no-entry -nostdlib -o test.wasm test.c -``` - -You will get ```test.wasm``` which is the WASM app binary. - -Run WASM app -======================== - -Assume you are using Linux, the command to run the test.wasm is: -``` Bash -cd iwasm/products/linux/build -./iwasm test.wasm -``` -You will get the following output: -``` -Hello world! -buf ptr: 0x400002b0 -buf: 1234 -``` -If you would like to run the test app on Zephyr, we have embedded a test sample into its OS image. You will need to execute: -``` -ninja run -``` - -Embed WAMR into software production -===================================== -WAMR can be built into a standalone executable which takes the WASM application file name as input, and then executes it. To use it in the embedded environment you should embed WAMR into your own software product. WASM provides a set of API's for embedded code to load the WASM module, instantiate the module and invoke a WASM function from a native call. - - - - -A typical WAMR API usage is shown below (some return value checks are ignored): -``` C - static char global_heap_buf[512 * 1024]; - - char *buffer; - wasm_module_t module; - wasm_module_inst_t inst; - wasm_function_inst_t func; - wasm_exec_env_t env; - uint32 argv[2]; - - bh_memory_init_with_pool(global_heap_buf, sizeof(global_heap_buf)); - wasm_runtime_init(); - - buffer = read_wasm_binary_to_buffer(…); - module = wasm_runtime_load(buffer, size, err, err_size); - inst = wasm_runtime_instantiate(module, 0, 0, err, err_size); - func = wasm_runtime_lookup_function(inst, "fib", "(i32)i32"); - env = wasm_runtime_create_exec_env(stack_size); - - argv[0] = 8; - if (!wasm_runtime_call_wasm(inst, env, func, 1, argv_buf) ) { - wasm_runtime_clear_exception(inst); - } - /* the return value is stored in argv[0] */ - printf("fib function return: %d\n", argv[0]); - - wasm_runtime_destory_exec_env(env); - wasm_runtime_deinstantiate(inst); - wasm_runtime_unload(module); - wasm_runtime_destroy(); - bh_memory_destroy(); -``` - - -WASM application library -======================== -In general, there are 3 classes of API's important for the WASM application: -- Built-in API's: WAMR provides a minimal API set for developers. -- 3rd party API's: Programmer can download and include any 3rd party C source code and add it into their own WASM app source tree. -- Platform native API's: WAMR provides a mechanism to export a native API to the WASM application. - - -Built-in application library ---------------- -Built-in API's include Libc API's, Base library and Extension library reference. - -**Libc API's**
-This is a minimal set of Libc API's for memory allocation, string manipulation and printing. The header file is located at ```lib/app-libs/libc/lib_base.h```. The current supported API set is listed here: -``` C -void *malloc(size_t size); -void *calloc(size_t n, size_t size); -void free(void *ptr); -int memcmp(const void *s1, const void *s2, size_t n); -void *memcpy(void *dest, const void *src, size_t n); -void *memmove(void *dest, const void *src, size_t n); -void *memset(void *s, int c, size_t n); -int putchar(int c); -int snprintf(char *str, size_t size, const char *format, ...); -int sprintf(char *str, const char *format, ...); -char *strchr(const char *s, int c); -int strcmp(const char *s1, const char *s2); -char *strcpy(char *dest, const char *src); -size_t strlen(const char *s); -int strncmp(const char * str1, const char * str2, size_t n); -char *strncpy(char *dest, const char *src, unsigned long n); -``` - -**Base library**
-Basic support for communication, timers, etc is available. You can refer to the header file ```lib/app-libs/base/wasm_app.h``` which contains the definitions for request and response API's, event pub/sub API's and timer API's. Please note that these API's require the native implementations. -The API set is listed below: -``` C -typedef void(*request_handler_f)(request_t *) ; -typedef void(*response_handler_f)(response_t *, void *) ; - -// Request API's -bool api_register_resource_handler(const char *url, request_handler_f); -void api_send_request(request_t * request, response_handler_f response_handler, void * user_data); -void api_response_send(response_t *response); - -// Event API's -bool api_publish_event(const char *url, int fmt, void *payload, int payload_len); -bool api_subscribe_event(const char * url, request_handler_f handler); - -struct user_timer; -typedef struct user_timer * user_timer_t; - -// Timer API's -user_timer_t api_timer_create(int interval, bool is_period, bool auto_start, void(*on_user_timer_update)(user_timer_t -)); -void api_timer_cancel(user_timer_t timer); -void api_timer_restart(user_timer_t timer, int interval); -``` - -**Library extension reference**
-Currently we provide several kinds of extension library for reference including sensor, connection and GUI. - -Sensor API: In the header file ```lib/app-libs/extension/sensor/sensor.h```, the API set is defined as below: -``` C -sensor_t sensor_open(const char* name, int index, - void(*on_sensor_event)(sensor_t, attr_container_t *, void *), - void *user_data); -bool sensor_config(sensor_t sensor, int interval, int bit_cfg, int delay); -bool sensor_config_with_attr_container(sensor_t sensor, attr_container_t *cfg); -bool sensor_close(sensor_t sensor); -``` -Connection API: In the header file `lib/app-libs/extension/connection/connection.h.`, the API set is defined as below: -``` C -/* Connection event type */ -typedef enum { - /* Data is received */ - CONN_EVENT_TYPE_DATA = 1, - /* Connection is disconnected */ - CONN_EVENT_TYPE_DISCONNECT -} conn_event_type_t; - -typedef void (*on_connection_event_f)(connection_t *conn, - conn_event_type_t type, - const char *data, - uint32 len, - void *user_data); -connection_t *api_open_connection(const char *name, - attr_container_t *args, - on_connection_event_f on_event, - void *user_data); -void api_close_connection(connection_t *conn); -int api_send_on_connection(connection_t *conn, const char *data, uint32 len); -bool api_config_connection(connection_t *conn, attr_container_t *cfg); -``` -GUI API: The API's is list in header file ```lib/app-libs/extension/gui/wgl.h``` which is implemented based open soure 2D graphic library [LittlevGL](https://docs.littlevgl.com/en/html/index.html). Currently supported widgets include button, label, list and check box and more wigdet would be provided in future. - - -The mechanism of exporting native API to WASM application -======================================================= - -The basic working flow for WASM application calling into the native API is shown in the following diagram: - - - - -WAMR provides the macro `EXPORT_WASM_API` to enable users to export a native API to a WASM application. WAMR has implemented a base API for the timer and messaging by using `EXPORT_WASM_API`. This can be a point of reference for extending your own library. -``` C -static NativeSymbol extended_native_symbol_defs[] = { - EXPORT_WASM_API(wasm_register_resource), - EXPORT_WASM_API(wasm_response_send), - EXPORT_WASM_API(wasm_post_request), - EXPORT_WASM_API(wasm_sub_event), - EXPORT_WASM_API(wasm_create_timer), - EXPORT_WASM_API(wasm_timer_set_interval), - EXPORT_WASM_API(wasm_timer_cancel), - EXPORT_WASM_API(wasm_timer_restart) -}; -``` - -![#f03c15](https://placehold.it/15/f03c15/000000?text=+) **Security attention:** A WebAssembly application should only have access to its own memory space. As a result, the integrator should carefully design the native function to ensure that the memory accesses are safe. The native API to be exported to the WASM application must: -- Only use 32 bits number for parameters -- Should not pass data to the structure pointer (do data serialization instead) -- Should do the pointer address conversion in the native API -- Should not pass function pointer as callback - -Below is a sample of a library extension. All code invoked across WASM and native world must be serialized and de-serialized, and the native world must do a boundary check for every incoming address from the WASM world. - - - -Steps for exporting native API -========================== - -WAMR implemented a framework for developers to export API's. Below is the procedure to expose the platform API's in three steps: - -**Step 1. Create a header file**
-Declare the API's for your WASM application source project to include. - -**Step 2. Create a source file**
-Export the platform API's, for example in ``` products/linux/ext_lib_export.c ``` -``` C -#include "lib_export.h" - -static NativeSymbol extended_native_symbol_defs[] = -{ -}; - -#include "ext_lib_export.h" -``` - -**Step 3. Register new API's**
-Use the macro `EXPORT_WASM_API` and `EXPORT_WASM_API2` to add exported API's into the array of ```extended_native_symbol_defs```. -The pre-defined MACRO `EXPORT_WASM_API` should be used to declare a function export: -``` c -#define EXPORT_WASM_API(symbol) {#symbol, symbol} -``` - -Below code example shows how to extend the library to support `customized()`: - -``` -//lib_export_impl.c -void customized() -{ - // your code -} - - -// lib_export_dec.h -#ifndef _LIB_EXPORT_DEC_H_ -#define _LIB_EXPORT_DEC_H_ -#ifdef __cplusplus -extern "C" { -#endif - -void customized(); - -#ifdef __cplusplus -} -#endif -#endif - - -// ext_lib_export.c -#include "lib_export.h" -#include "lib_export_dec.h" - -static NativeSymbol extended_native_symbol_defs[] = -{ - EXPORT_WASM_API(customized) -}; - -#include "ext_lib_export.h" -``` - -Use extended library ------------------------- -In the application source project, it will include the WAMR built-in API's header file and platform extension header files. Assuming the board vendor extends the library which added an API called customized(), the WASM application would be like this: -``` C -#include -#include "lib_export_dec.h" // provided by the platform vendor - -int main(int argc, char **argv) -{ - int I; - char *buf = “abcd”; - customized(); // customized API provided by the platform vendor - return i; -} -``` - - -Communication programming models -========================= -WAMR supports two typical communication programming models, the microservice model and the pub/sub model. - - -Microservice model -------------------------- -The microservice model is also known as request and response model. One WASM application acts as the server which provides a specific service. Other WASM applications or host/cloud applications request that service and get the response. - - -Below is the reference implementation of the server application. It provides room temperature measurement service. - -``` C -void on_init() -{ - api_register_resource_handler("/room_temp", room_temp_handler); -} - -void on_destroy() -{ -} - -void room_temp_handler(request_t *request) -{ - response_t response[1]; - attr_container_t *payload; - payload = attr_container_create("room_temp payload"); - if (payload == NULL) - return; - - attr_container_set_string(&payload, "temp unit", "centigrade"); - attr_container_set_int(&payload, "value", 26); - - make_response_for_request(request, response); - set_response(response, - CONTENT_2_05, - FMT_ATTR_CONTAINER, - payload, - attr_container_get_serialize_length(payload)); - - api_response_send(response); - attr_container_destroy(payload); -} -``` - - -Pub/sub model -------------------------- -One WASM application acts as the event publisher. It publishes events to notify WASM applications or host/cloud applications which subscribe to the events. - - - -Below is the reference implementation of the pub application. It utilizes a timer to repeatedly publish an overheat alert event to the subscriber applications. Then the subscriber applications receive the events immediately. - -``` C -/* Timer callback */ -void timer_update(user_timer_t timer -{ - attr_container_t *event; - - event = attr_container_create("event"); - attr_container_set_string(&event, - "warning", - "temperature is over high"); - - api_publish_event("alert/overheat", - FMT_ATTR_CONTAINER, - event, - attr_container_get_serialize_length(event)); - - attr_container_destroy(event); -} - -void on_init() -{ - user_timer_t timer; - timer = api_timer_create(1000, true, true, timer_update); -} - -void on_destroy() -{ -} -``` - -Below is the reference implementation of the sub application. -``` C -void overheat_handler(request_t *event) -{ - printf("Event: %s\n", event->url); - - if (event->payload != NULL && event->fmt == FMT_ATTR_CONTAINER) - attr_container_dump((attr_container_t *) event->payload); -} - -void on_init( -{ - api_subscribe_event ("alert/overheat", overheat_handler); -} - -void on_destroy() -{ -} -``` -**Note:** You can also subscribe this event from host side by using host tool. Please refer `samples/simple` project for deail usage. Samples and demos -========================= -The simple sample --------- -Please refer to the ```samples/simple``` folder for samples of WASM application life cyle management and programming models. +================= -2D graphic user interface with LittlevGL ------------------------------------------------- -We have 2 samples for 2D graphic user interface. - -One of them demonstrates that a graphic user interface application in WebAssembly integrates the LittlevGL, an open-source embedded 2d graphic library. The sample source code is under ```samples/littlevgl``` - -In this sample, the LittlevGL source code is built into the WebAssembly code with the user application source files. The platform interfaces defined by LittlevGL is implemented in the runtime and exported to the application through the declarations from source "ext_lib_export.c" as below: - - EXPORT_WASM_API(display_init), - EXPORT_WASM_API(display_input_read), - EXPORT_WASM_API(display_flush), - EXPORT_WASM_API(display_fill), - EXPORT_WASM_API(display_vdb_write), - EXPORT_WASM_API(display_map), - EXPORT_WASM_API(time_get_ms), }; - -The runtime component supports building target for Linux and AliOS-Things, Zephyr/STM Nucleo board respectively. The beauty of this sample is the WebAssembly application can have identical display and behavior when running from both runtime environments. That implies we can do the majority of application validation from the desktop environment then load it to the target device as long as two runtime distributions support the same set of the application interface. +The WAMR samples are located in folder [./samples](./samples). A sample usually contains the WAMR runtime build, WASM applications and test tools. The WARM provides following samples: +- [Simple](./samples/simple/README.md): The runtime is integrated with most of the WAMR APP libaries and multiple WASM applications are provided for using different WASM API set. +- [littlevgl](./samples/littlevgl/README.md): Demostrating the graphic user interface application usage on WAMR. The whole [LittlevGL](https://github.com/littlevgl/) 2D user graphic library and the UI application is built into WASM application. +- [gui](./samples/gui/README.md): Moved the [LittlevGL](https://github.com/littlevgl/) library into the runtime and defined a WASM application interface by wrapping the littlevgl API. +- [IoT-APP-Store-Demo](./test-tools/IoT-APP-Store-Demo/README.md): A web site for demostrating a WASM APP store usage where we can remotely install and uninstall WASM application on remote devices. -Below pictures show the WASM application is running on an STM board with an LCD touch panel. When users click the blue button, the WASM application increases the counter, and the latest counter value is displayed on the top banner of the touch panel. +The graphic user interface demo photo: - - +![WAMR samples diagram](./doc/pics/vgl_demo.png "WAMR samples diagram") + + + + +Releases and acknowledgments +============================ + +WAMR is a community efforts. Since Intel Corp contributed the first release of this open source project, this project has received many good contributions from the community. + +See the [major features releasing history and contributor names](./doc/release_ack.md) + + +Roadmap +======= + +See the [roadmap](./doc/roadmap.md) to understand what major features are planed or under development. + +Please submit issues for any new feature request, or your plan for contributing new features. -The sample also provides the native Linux version of application without the runtime under folder "vgl-native-ui-app". It can help to check differences between the implementations in native and WebAssembly. - -The other sample demonstrates that a graphic user interface application in WebAssembly programming with WAMR graphic library(WGL), which is implemented based on LittlevGL, an open-source embedded 2d graphic library. The sample source code is under ```samples/gui``` -Unlike `sample/littlevgl/val-wasm-runtime`, in this sample, the LittlevGL source code is built into the WAMR runtime and exported to Webassembly applicaton but not directly built into Webassembly application. And WGL provides a group of WebAssembly wrapper API's for user to write graphic application. These API's are listed in: `/core/iwasm/lib/app-libs/extension/gui/wgl.h`. Currently only a few API's are provided and there will be more. Submit issues and contact the maintainers diff --git a/core/app-mgr/app-manager/event.c b/core/app-mgr/app-manager/event.c index 2f78a406c..2295f20fe 100644 --- a/core/app-mgr/app-manager/event.c +++ b/core/app-mgr/app-manager/event.c @@ -176,7 +176,8 @@ void am_publish_event(request_t * event) if (c->subscriber_id == ID_HOST) { send_request_to_host(event); } else { - module_request_handler(event, (void *)c->subscriber_id); + module_request_handler + (event, (void *)(uintptr_t)c->subscriber_id); } c = c->next; } diff --git a/core/app-mgr/app-manager/module_wasm_app.c b/core/app-mgr/app-manager/module_wasm_app.c index 3958520a7..4154b33e3 100644 --- a/core/app-mgr/app-manager/module_wasm_app.c +++ b/core/app-mgr/app-manager/module_wasm_app.c @@ -224,8 +224,8 @@ static void app_instance_queue_callback(void *queue_msg) app_manager_printf("Cannot find function _on_timer_callback\n"); break; } - unsigned int timer_id = (unsigned int) bh_message_payload( - queue_msg); + unsigned int timer_id = (unsigned int)(uintptr_t) + bh_message_payload(queue_msg); argv[0] = timer_id; if (!wasm_runtime_call_wasm(inst, NULL, func_onTimer, 1, argv)) { app_manager_printf("Got exception running wasm code: %s\n", @@ -642,7 +642,8 @@ static bool wasm_app_module_uninstall(request_t *msg) static bool wasm_app_module_handle_host_url(void *queue_msg) { //todo: implement in future - app_manager_printf("App handles host url address %d\n", (int) queue_msg); + app_manager_printf("App handles host url address %d\n", + (int)(uintptr_t)queue_msg); return false; } diff --git a/core/app-mgr/app-manager/resource_reg.c b/core/app-mgr/app-manager/resource_reg.c index bbadcd03f..4fe477e3d 100644 --- a/core/app-mgr/app-manager/resource_reg.c +++ b/core/app-mgr/app-manager/resource_reg.c @@ -33,7 +33,7 @@ static app_res_register_t * g_resources = NULL; void module_request_handler(request_t *request, void *user_data) { - unsigned int mod_id = (unsigned int) user_data; + unsigned int mod_id = (unsigned int)(uintptr_t)user_data; bh_message_t msg; module_data *m_data; request_t *req; @@ -99,7 +99,7 @@ void targeted_app_request_handler(request_t *request, void *unused) goto end; } - module_request_handler(request, (void *)m_data->id); + module_request_handler(request, (void *)(uintptr_t)m_data->id); end: request->url = url; } @@ -138,7 +138,7 @@ void * am_dispatch_request(request_t *request) while (r) { if (check_url_start(request->url, strlen(request->url), r->url) > 0) { - r->request_handler(request, (void *)r->register_id); + r->request_handler(request, (void *)(uintptr_t)r->register_id); return r; } r = r->next; diff --git a/core/iwasm/lib/app-libs/base/request.c b/core/iwasm/lib/app-libs/base/request.c index 4251e2bfe..ade6ce4e2 100644 --- a/core/iwasm/lib/app-libs/base/request.c +++ b/core/iwasm/lib/app-libs/base/request.c @@ -18,6 +18,8 @@ #include "request.h" #include "shared_utils.h" #include "wasm_app.h" +#include "req_resp_api.h" +#include "timer_api.h" #define TRANSACTION_TIMEOUT_MS 5000 @@ -138,15 +140,15 @@ static bool register_url_handler(const char *url, // tell app mgr to route this url to me if (reg_type == Reg_Request) - wasm_register_resource((int32)url); + wasm_register_resource(url); else - wasm_sub_event((int32)url); + wasm_sub_event(url); return true; } bool api_register_resource_handler(const char *url, - request_handler_f request_handler) + request_handler_f request_handler) { return register_url_handler(url, request_handler, Reg_Request); } @@ -242,7 +244,7 @@ void api_send_request(request_t * request, response_handler_f response_handler, } } - wasm_post_request((int32)buffer, size); + wasm_post_request(buffer, size); free_req_resp_packet(buffer); } @@ -329,7 +331,7 @@ void api_response_send(response_t *response) if (buffer == NULL) return; - wasm_response_send((int32)buffer, size); + wasm_response_send(buffer, size); free_req_resp_packet(buffer); } @@ -343,7 +345,7 @@ bool api_publish_event(const char *url, int fmt, void *payload, int payload_len) char * buffer = pack_request(request, &size); if (buffer == NULL) return false; - wasm_post_request((int32)buffer, size); + wasm_post_request(buffer, size); free_req_resp_packet(buffer); diff --git a/core/iwasm/lib/app-libs/base/request.h b/core/iwasm/lib/app-libs/base/request.h index e7766dac0..f60b9f698 100644 --- a/core/iwasm/lib/app-libs/base/request.h +++ b/core/iwasm/lib/app-libs/base/request.h @@ -17,7 +17,6 @@ #ifndef _AEE_REQUEST_H_ #define _AEE_REQUEST_H_ -#include "native_interface.h" #include "shared_utils.h" #ifdef __cplusplus diff --git a/core/iwasm/lib/app-libs/base/timer.c b/core/iwasm/lib/app-libs/base/timer.c index cb042670e..0b3cd9f01 100644 --- a/core/iwasm/lib/app-libs/base/timer.c +++ b/core/iwasm/lib/app-libs/base/timer.c @@ -14,12 +14,12 @@ * limitations under the License. */ -#include "timer_wasm_app.h" -#include "native_interface.h" - #include #include +#include "timer_wasm_app.h" +#include "timer_api.h" + #if 1 #include #else diff --git a/core/iwasm/lib/app-libs/base/wasm_app.h b/core/iwasm/lib/app-libs/base/wasm_app.h index 081b2bfe2..3513001e4 100644 --- a/core/iwasm/lib/app-libs/base/wasm_app.h +++ b/core/iwasm/lib/app-libs/base/wasm_app.h @@ -32,7 +32,6 @@ #ifndef _LIB_AEE_H_ #define _LIB_AEE_H_ -#include "native_interface.h" #include "shared_utils.h" #include "attr_container.h" #include "request.h" diff --git a/core/iwasm/lib/app-libs/extension/connection/connection.c b/core/iwasm/lib/app-libs/extension/connection/connection.c index 1c7845d4b..e60504c24 100644 --- a/core/iwasm/lib/app-libs/extension/connection/connection.c +++ b/core/iwasm/lib/app-libs/extension/connection/connection.c @@ -15,7 +15,7 @@ */ #include "connection.h" -#include "native_interface.h" +#include "connection_api.h" /* Raw connection structure */ typedef struct _connection { @@ -44,7 +44,7 @@ connection_t *api_open_connection(const char *name, char *args_buffer = (char *)args; uint32 handle, args_len = attr_container_get_serialize_length(args); - handle = wasm_open_connection((int32)name, (int32)args_buffer, args_len); + handle = wasm_open_connection(name, args_buffer, args_len); if (handle == -1) return NULL; @@ -91,7 +91,7 @@ void api_close_connection(connection_t *c) int api_send_on_connection(connection_t *conn, const char *data, uint32 len) { - return wasm_send_on_connection(conn->handle, (int32)data, len); + return wasm_send_on_connection(conn->handle, data, len); } bool api_config_connection(connection_t *conn, attr_container_t *cfg) @@ -99,7 +99,7 @@ bool api_config_connection(connection_t *conn, attr_container_t *cfg) char *cfg_buffer = (char *)cfg; uint32 cfg_len = attr_container_get_serialize_length(cfg); - return wasm_config_connection(conn->handle, (int32)cfg_buffer, cfg_len); + return wasm_config_connection(conn->handle, cfg_buffer, cfg_len); } void on_connection_data(uint32 handle, char *buffer, uint32 len) diff --git a/core/iwasm/lib/app-libs/extension/gui/src/wgl_btn.c b/core/iwasm/lib/app-libs/extension/gui/src/wgl_btn.c index 5cf8c1c29..5623abe6c 100644 --- a/core/iwasm/lib/app-libs/extension/gui/src/wgl_btn.c +++ b/core/iwasm/lib/app-libs/extension/gui/src/wgl_btn.c @@ -15,11 +15,11 @@ */ #include "wgl.h" -#include "native_interface.h" - +#include "bh_platform.h" +#include "gui_api.h" #define ARGC sizeof(argv)/sizeof(uint32) -#define CALL_BTN_NATIVE_FUNC(id) wasm_btn_native_call(id, (int32)argv, ARGC) +#define CALL_BTN_NATIVE_FUNC(id) wasm_btn_native_call(id, argv, ARGC) wgl_obj_t wgl_btn_create(wgl_obj_t par, wgl_obj_t copy) { diff --git a/core/iwasm/lib/app-libs/extension/gui/src/wgl_cb.c b/core/iwasm/lib/app-libs/extension/gui/src/wgl_cb.c index df646fbc8..cbfa11ebd 100644 --- a/core/iwasm/lib/app-libs/extension/gui/src/wgl_cb.c +++ b/core/iwasm/lib/app-libs/extension/gui/src/wgl_cb.c @@ -15,12 +15,12 @@ */ #include "wgl.h" -#include "native_interface.h" +#include "gui_api.h" #include #define ARGC sizeof(argv)/sizeof(uint32) -#define CALL_CB_NATIVE_FUNC(id) wasm_cb_native_call(id, (uint32)argv, ARGC) +#define CALL_CB_NATIVE_FUNC(id) wasm_cb_native_call(id, argv, ARGC) wgl_obj_t wgl_cb_create(wgl_obj_t par, const wgl_obj_t copy) { diff --git a/core/iwasm/lib/app-libs/extension/gui/src/wgl_label.c b/core/iwasm/lib/app-libs/extension/gui/src/wgl_label.c index 3a14cdb47..a602e2aee 100644 --- a/core/iwasm/lib/app-libs/extension/gui/src/wgl_label.c +++ b/core/iwasm/lib/app-libs/extension/gui/src/wgl_label.c @@ -16,12 +16,12 @@ #include "wgl.h" -#include "native_interface.h" +#include "gui_api.h" #include #define ARGC sizeof(argv)/sizeof(uint32) -#define CALL_LABEL_NATIVE_FUNC(id) wasm_label_native_call(id, (uint32)argv, ARGC) +#define CALL_LABEL_NATIVE_FUNC(id) wasm_label_native_call(id, argv, ARGC) wgl_obj_t wgl_label_create(wgl_obj_t par, wgl_obj_t copy) { diff --git a/core/iwasm/lib/app-libs/extension/gui/src/wgl_list.c b/core/iwasm/lib/app-libs/extension/gui/src/wgl_list.c index ad580b7fa..c815964db 100644 --- a/core/iwasm/lib/app-libs/extension/gui/src/wgl_list.c +++ b/core/iwasm/lib/app-libs/extension/gui/src/wgl_list.c @@ -15,12 +15,12 @@ */ #include "wgl.h" -#include "native_interface.h" +#include "gui_api.h" #include #define ARGC sizeof(argv)/sizeof(uint32) -#define CALL_LIST_NATIVE_FUNC(id) wasm_list_native_call(id, (int32)argv, ARGC) +#define CALL_LIST_NATIVE_FUNC(id) wasm_list_native_call(id, argv, ARGC) wgl_obj_t wgl_list_create(wgl_obj_t par, const wgl_obj_t copy) diff --git a/core/iwasm/lib/app-libs/extension/gui/src/wgl_obj.c b/core/iwasm/lib/app-libs/extension/gui/src/wgl_obj.c index d53f8b29f..5798ca3dd 100644 --- a/core/iwasm/lib/app-libs/extension/gui/src/wgl_obj.c +++ b/core/iwasm/lib/app-libs/extension/gui/src/wgl_obj.c @@ -15,12 +15,12 @@ */ #include "wgl.h" -#include "native_interface.h" +#include "gui_api.h" #include #include #define ARGC sizeof(argv)/sizeof(uint32) -#define CALL_OBJ_NATIVE_FUNC(id) wasm_obj_native_call(id, (int32)argv, ARGC) +#define CALL_OBJ_NATIVE_FUNC(id) wasm_obj_native_call(id, argv, ARGC) typedef struct _obj_evt_cb { struct _obj_evt_cb *next; diff --git a/core/iwasm/lib/app-libs/extension/sensor/sensor.c b/core/iwasm/lib/app-libs/extension/sensor/sensor.c index 53f413bf7..212b2e166 100644 --- a/core/iwasm/lib/app-libs/extension/sensor/sensor.c +++ b/core/iwasm/lib/app-libs/extension/sensor/sensor.c @@ -15,7 +15,7 @@ */ #include "sensor.h" -#include "native_interface.h" +#include "sensor_api.h" typedef struct _sensor { struct _sensor * next; @@ -31,7 +31,7 @@ sensor_t sensor_open(const char* name, int index, sensor_event_handler_f sensor_event_handler, void *user_data) { - uint32 id = wasm_sensor_open((int32)name, index); + uint32 id = wasm_sensor_open(name, index); if (id == -1) return NULL; @@ -66,7 +66,7 @@ bool sensor_config_with_attr_container(sensor_t sensor, attr_container_t *cfg) char *buffer = (char *)cfg; int len = attr_container_get_serialize_length(cfg); - return wasm_sensor_config_with_attr_container(sensor->handle, (int32)buffer, len); + return wasm_sensor_config_with_attr_container(sensor->handle, buffer, len); } bool sensor_config(sensor_t sensor, int interval, int bit_cfg, int delay) diff --git a/core/iwasm/lib/native-interface/connection_api.h b/core/iwasm/lib/native-interface/connection_api.h index f55583bd9..21142b70a 100644 --- a/core/iwasm/lib/native-interface/connection_api.h +++ b/core/iwasm/lib/native-interface/connection_api.h @@ -16,23 +16,28 @@ #ifndef CONNECTION_API_H_ #define CONNECTION_API_H_ + #include "bh_platform.h" #ifdef __cplusplus extern "C" { #endif -uint32 wasm_open_connection(int32 name_offset, int32 args_offset, uint32 len); +uint32 +wasm_open_connection(const char *name, char *args_buf, uint32 args_buf_len); -void wasm_close_connection(uint32 handle); +void +wasm_close_connection(uint32 handle); -int wasm_send_on_connection(uint32 handle, int32 data_offset, uint32 len); +int +wasm_send_on_connection(uint32 handle, const char *data, uint32 data_len); -bool wasm_config_connection(uint32 handle, int32 cfg_offset, uint32 len); +bool +wasm_config_connection(uint32 handle, const char *cfg_buf, uint32 cfg_buf_len); #ifdef __cplusplus } #endif -#endif /* CONNECTION_API_H_ */ +#endif /* end of CONNECTION_API_H_ */ diff --git a/core/iwasm/lib/native-interface/gui_api.h b/core/iwasm/lib/native-interface/gui_api.h index 0b1dbb005..04031c1fa 100644 --- a/core/iwasm/lib/native-interface/gui_api.h +++ b/core/iwasm/lib/native-interface/gui_api.h @@ -14,19 +14,29 @@ * limitations under the License. */ -#ifndef GUI_API_H_ -#define GUI_API_H_ +#ifndef _GUI_API_H_ +#define _GUI_API_H_ + #include "bh_platform.h" #ifdef __cplusplus extern "C" { #endif -void wasm_obj_native_call(int32 func_id, uint32 argv_offset, uint32 argc); -void wasm_btn_native_call(int32 func_id, uint32 argv_offset, uint32 argc); -void wasm_label_native_call(int32 func_id, uint32 argv_offset, uint32 argc); -void wasm_cb_native_call(int32 func_id, uint32 argv_offset, uint32 argc); -void wasm_list_native_call(int32 func_id, uint32 argv_offset, uint32 argc); +void +wasm_obj_native_call(int32 func_id, uint32 *argv, uint32 argc); + +void +wasm_btn_native_call(int32 func_id, uint32 *argv, uint32 argc); + +void +wasm_label_native_call(int32 func_id, uint32 *argv, uint32 argc); + +void +wasm_cb_native_call(int32 func_id, uint32 *argv, uint32 argc); + +void +wasm_list_native_call(int32 func_id, uint32 *argv, uint32 argc); #ifdef __cplusplus @@ -34,4 +44,4 @@ void wasm_list_native_call(int32 func_id, uint32 argv_offset, uint32 argc); #endif -#endif /* GUI_API_H_ */ +#endif /* end of _GUI_API_H_ */ diff --git a/core/iwasm/lib/native-interface/native_interface.h b/core/iwasm/lib/native-interface/native_interface.h index 0312b1f63..49c7c1e66 100644 --- a/core/iwasm/lib/native-interface/native_interface.h +++ b/core/iwasm/lib/native-interface/native_interface.h @@ -14,12 +14,13 @@ * limitations under the License. */ -#ifndef DEPS_SSG_MICRO_RUNTIME_WASM_POC_APP_LIBS_NATIVE_INTERFACE_NATIVE_INTERFACE_H_ -#define DEPS_SSG_MICRO_RUNTIME_WASM_POC_APP_LIBS_NATIVE_INTERFACE_NATIVE_INTERFACE_H_ +#ifndef _NATIVE_INTERFACE_H_ +#define _NATIVE_INTERFACE_H_ -// note: the bh_plaform.h is the only head file separately -// implemented by both [app] and [native] worlds +/* Note: the bh_plaform.h is the only head file separately + implemented by both [app] and [native] worlds */ #include "bh_platform.h" +#include "wasm_export.h" #define get_module_inst() \ wasm_runtime_get_current_module_inst() @@ -39,52 +40,102 @@ #define module_free(offset) \ wasm_runtime_module_free(module_inst, offset) -char *wa_strdup(const char *); - -bool -wasm_response_send(int32 buffer_offset, int size); - -void wasm_register_resource(int32 url_offset); - -void wasm_post_request(int32 buffer_offset, int size); - -void wasm_sub_event(int32 url_offset); +/*char *wa_strdup(const char *);*/ /* - * ************* sensor interfaces ************* + * request/response interfaces */ bool -wasm_sensor_config(uint32 sensor, int interval, int bit_cfg, int delay); -uint32 -wasm_sensor_open(int32 name_offset, int instance); -bool -wasm_sensor_config_with_attr_container(uint32 sensor, int32 buffer_offset, - int len); - -bool -wasm_sensor_close(uint32 sensor); +wasm_response_send(wasm_module_inst_t module_inst, + int32 buffer_offset, int size); +void +wasm_register_resource(wasm_module_inst_t module_inst, + int32 url_offset); +void +wasm_post_request(wasm_module_inst_t module_inst, + int32 buffer_offset, int size); +void +wasm_sub_event(wasm_module_inst_t module_inst, + int32 url_offset); /* - * *** timer interface *** + * sensor interfaces + */ + +bool +wasm_sensor_config(wasm_module_inst_t module_inst, + uint32 sensor, int interval, int bit_cfg, int delay); +uint32 +wasm_sensor_open(wasm_module_inst_t module_inst, + int32 name_offset, int instance); +bool +wasm_sensor_config_with_attr_container(wasm_module_inst_t module_inst, + uint32 sensor, + int32 buffer_offset, int len); +bool +wasm_sensor_close(wasm_module_inst_t module_inst, + uint32 sensor); + +/* + * timer interfaces */ typedef unsigned int timer_id_t; -timer_id_t wasm_create_timer(int interval, bool is_period, bool auto_start); -void wasm_timer_destory(timer_id_t timer_id); -void wasm_timer_cancel(timer_id_t timer_id); -void wasm_timer_restart(timer_id_t timer_id, int interval); -uint32 wasm_get_sys_tick_ms(void); + +timer_id_t +wasm_create_timer(wasm_module_inst_t module_inst, + int interval, bool is_period, bool auto_start); +void +wasm_timer_destory(wasm_module_inst_t module_inst, timer_id_t timer_id); +void +wasm_timer_cancel(wasm_module_inst_t module_inst, timer_id_t timer_id); +void +wasm_timer_restart(wasm_module_inst_t module_inst, + timer_id_t timer_id, int interval); +uint32 +wasm_get_sys_tick_ms(wasm_module_inst_t module_inst); /* - * *** connection interface *** + * connection interfaces */ -uint32 wasm_open_connection(int32 name_offset, int32 args_offset, uint32 len); -void wasm_close_connection(uint32 handle); -int wasm_send_on_connection(uint32 handle, int32 data_offset, uint32 len); -bool wasm_config_connection(uint32 handle, int32 cfg_offset, uint32 len); -#include "gui_api.h" +uint32 +wasm_open_connection(wasm_module_inst_t module_inst, + int32 name_offset, int32 args_offset, uint32 len); +void +wasm_close_connection(wasm_module_inst_t module_inst, + uint32 handle); +int +wasm_send_on_connection(wasm_module_inst_t module_inst, + uint32 handle, int32 data_offset, uint32 len); +bool +wasm_config_connection(wasm_module_inst_t module_inst, + uint32 handle, int32 cfg_offset, uint32 len); + +/** + * gui interfaces + */ + +void +wasm_obj_native_call(wasm_module_inst_t module_inst, + int32 func_id, uint32 argv_offset, uint32 argc); + +void +wasm_btn_native_call(wasm_module_inst_t module_inst, + int32 func_id, uint32 argv_offset, uint32 argc); + +void +wasm_label_native_call(wasm_module_inst_t module_inst, + int32 func_id, uint32 argv_offset, uint32 argc); + +void +wasm_cb_native_call(wasm_module_inst_t module_inst, + int32 func_id, uint32 argv_offset, uint32 argc); + +void +wasm_list_native_call(wasm_module_inst_t module_inst, + int32 func_id, uint32 argv_offset, uint32 argc); + +#endif /* end of _NATIVE_INTERFACE_H */ -#endif /* DEPS_SSG_MICRO_RUNTIME_WASM_PO -C_APP_LIBS_NATIVE_INTERFACE_NATIVE_INTERFACE_H_ */ diff --git a/core/iwasm/lib/native-interface/readme.txt b/core/iwasm/lib/native-interface/readme.txt index e3b59042b..7197d5844 100644 --- a/core/iwasm/lib/native-interface/readme.txt +++ b/core/iwasm/lib/native-interface/readme.txt @@ -1,6 +1,6 @@ Attention: ======= -Only add files are shared by both wasm application and native runtime into this directory! +Only add files which are shared by both wasm application and native runtime into this directory! The c files are both compiled into the the WASM APP and native runtime. diff --git a/core/iwasm/lib/native-interface/req_resp_api.h b/core/iwasm/lib/native-interface/req_resp_api.h new file mode 100644 index 000000000..8b2235712 --- /dev/null +++ b/core/iwasm/lib/native-interface/req_resp_api.h @@ -0,0 +1,43 @@ +/* + * Copyright (C) 2019 Intel Corporation. All rights reserved. + * + * Licensed 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. + */ + +#ifndef _REQ_RESP_API_H_ +#define _REQ_RESP_API_H_ + +#include "bh_platform.h" + +#ifdef __cplusplus +extern "C" { +#endif + +bool +wasm_response_send(const char *buf, int size); + +void +wasm_register_resource(const char *url); + +void +wasm_post_request(const char *buf, int size); + +void +wasm_sub_event(const char *url); + +#ifdef __cplusplus +} +#endif + +#endif /* end of _REQ_RESP_API_H_ */ + diff --git a/core/iwasm/lib/native-interface/restful_utils.c b/core/iwasm/lib/native-interface/restful_utils.c index 71b5d782e..e7afad469 100644 --- a/core/iwasm/lib/native-interface/restful_utils.c +++ b/core/iwasm/lib/native-interface/restful_utils.c @@ -19,7 +19,6 @@ #include #include -#include "native_interface.h" #include "shared_utils.h" /* Serialization of request and response message diff --git a/core/iwasm/lib/native-interface/sensor_api.h b/core/iwasm/lib/native-interface/sensor_api.h index 0f8a8583b..1adf93b1e 100644 --- a/core/iwasm/lib/native-interface/sensor_api.h +++ b/core/iwasm/lib/native-interface/sensor_api.h @@ -14,8 +14,9 @@ * limitations under the License. */ -#ifndef DEPS_IWASM_APP_LIBS_NATIVE_INTERFACE_SENSOR_API_H_ -#define DEPS_IWASM_APP_LIBS_NATIVE_INTERFACE_SENSOR_API_H_ +#ifndef _SENSOR_API_H_ +#define _SENSOR_API_H_ + #include "bh_platform.h" #ifdef __cplusplus @@ -29,7 +30,7 @@ bool wasm_sensor_config(uint32 sensor, int interval, int bit_cfg, int delay); bool -wasm_sensor_config_with_attr_container(uint32 sensor, char * buffer, int len); +wasm_sensor_config_with_attr_container(uint32 sensor, char *buffer, int len); bool wasm_sensor_close(uint32 sensor); @@ -38,4 +39,5 @@ wasm_sensor_close(uint32 sensor); } #endif -#endif /* DEPS_IWASM_APP_LIBS_NATIVE_INTERFACE_SENSOR_API_H_ */ +#endif /* end of _SENSOR_API_H_ */ + diff --git a/core/iwasm/lib/native-interface/shared_utils.h b/core/iwasm/lib/native-interface/shared_utils.h index 693dcf957..70f561b43 100644 --- a/core/iwasm/lib/native-interface/shared_utils.h +++ b/core/iwasm/lib/native-interface/shared_utils.h @@ -14,10 +14,10 @@ * limitations under the License. */ -#ifndef DEPS_SSG_MICRO_RUNTIME_WASM_POC_APP_LIBS_NATIVE_INTERFACE_SHARED_UTILS_H_ -#define DEPS_SSG_MICRO_RUNTIME_WASM_POC_APP_LIBS_NATIVE_INTERFACE_SHARED_UTILS_H_ +#ifndef _SHARED_UTILS_H_ +#define _SHARED_UTILS_H_ -#include "native_interface.h" +#include "bh_platform.h" #ifdef __cplusplus extern "C" { @@ -71,16 +71,27 @@ typedef struct response { unsigned long reciever; } response_t; -int check_url_start(const char* url, int url_len, const char * leading_str); -bool match_url(char * pattern, char * matched); -char * find_key_value(char * buffer, int buffer_len, char * key, char * value, - int value_len, char delimiter); +int +check_url_start(const char* url, int url_len, const char * leading_str); -request_t *clone_request(request_t *request); -void request_cleaner(request_t *request); +bool +match_url(char * pattern, char * matched); -response_t * clone_response(response_t * response); -void response_cleaner(response_t * response); +char * +find_key_value(char * buffer, int buffer_len, char * key, char * value, + int value_len, char delimiter); + +request_t * +clone_request(request_t *request); + +void +request_cleaner(request_t *request); + +response_t * +clone_response(response_t * response); + +void +response_cleaner(response_t * response); /** * @brief Set fields of response. @@ -95,8 +106,9 @@ void response_cleaner(response_t * response); * * @warning the response pointer MUST NOT be NULL */ -response_t * set_response(response_t * response, int status, int fmt, - const char *payload, int payload_len); +response_t * +set_response(response_t * response, int status, int fmt, + const char *payload, int payload_len); /** * @brief Make a response for a request. @@ -108,8 +120,8 @@ response_t * set_response(response_t * response, int status, int fmt, * * @warning the request and response pointers MUST NOT be NULL */ -response_t * make_response_for_request(request_t * request, - response_t * response); +response_t * +make_response_for_request(request_t * request, response_t * response); /** * @brief Initialize a request. @@ -125,14 +137,24 @@ response_t * make_response_for_request(request_t * request, * * @warning the request pointer MUST NOT be NULL */ -request_t * init_request(request_t * request, char *url, int action, int fmt, - void *payload, int payload_len); +request_t * +init_request(request_t * request, char *url, int action, int fmt, + void *payload, int payload_len); -char * pack_request(request_t *request, int * size); -request_t * unpack_request(char * packet, int size, request_t * request); -char * pack_response(response_t *response, int * size); -response_t * unpack_response(char * packet, int size, response_t * response); -void free_req_resp_packet(char * packet); +char * +pack_request(request_t *request, int * size); + +request_t * +unpack_request(char * packet, int size, request_t * request); + +char * +pack_response(response_t *response, int * size); + +response_t * +unpack_response(char * packet, int size, response_t * response); + +void +free_req_resp_packet(char * packet); #include "wgl_shared_utils.h" @@ -140,4 +162,4 @@ void free_req_resp_packet(char * packet); } #endif -#endif /* DEPS_SSG_MICRO_RUNTIME_WASM_POC_APP_LIBS_NATIVE_INTERFACE_SHARED_UTILS_H_ */ +#endif /* end of _SHARED_UTILS_H_ */ diff --git a/core/iwasm/lib/native-interface/timer_api.h b/core/iwasm/lib/native-interface/timer_api.h new file mode 100644 index 000000000..81ea839ab --- /dev/null +++ b/core/iwasm/lib/native-interface/timer_api.h @@ -0,0 +1,48 @@ +/* + * Copyright (C) 2019 Intel Corporation. All rights reserved. + * + * Licensed 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. + */ + +#ifndef _TIMER_API_H_ +#define _TIMER_API_H_ + +#include "bh_platform.h" + +#ifdef __cplusplus +extern "C" { +#endif + +typedef unsigned int timer_id_t; + +timer_id_t +wasm_create_timer(int interval, bool is_period, bool auto_start); + +void +wasm_timer_destory(timer_id_t timer_id); + +void +wasm_timer_cancel(timer_id_t timer_id); + +void +wasm_timer_restart(timer_id_t timer_id, int interval); + +uint32 +wasm_get_sys_tick_ms(void); + +#ifdef __cplusplus +} +#endif + +#endif /* end of _TIMER_API_H_ */ + diff --git a/core/iwasm/lib/native-interface/wasm_export.h b/core/iwasm/lib/native-interface/wasm_export.h new file mode 100644 index 000000000..ed9d570f8 --- /dev/null +++ b/core/iwasm/lib/native-interface/wasm_export.h @@ -0,0 +1,102 @@ +/* + * Copyright (C) 2019 Intel Corporation. All rights reserved. + * + * Licensed 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. + */ + +#ifndef _WASM_EXPORT_H +#define _WASM_EXPORT_H + +#include +#include + +/** + * API exported to WASM application + */ + +#ifdef __cplusplus +extern "C" { +#endif + +/** + * Get current WASM module instance of the current native thread + * + * @return current WASM module instance of the current native thread, 0 + * if not found + * Note: the return type is uint64_t but not pointer type, because that + * the we only supports WASM-32, in which the pointer type is + * compiled to WASM i32 type, but the pointer type in native can be + * 32-bit and 64-bit. And if the native pointer is 64-bit, data loss + * occurs after converting it to WASM i32 type. + */ +uint64_t +wasm_runtime_get_current_module_inst(); + +/** + * Validate the app address, check whether it belongs to WASM module + * instance's address space, or in its heap space or memory space. + * + * @param module_inst the WASM module instance + * @param app_offset the app address to validate, which is a relative address + * @param size the size bytes of the app address + * + * @return true if success, false otherwise. + */ +bool +wasm_runtime_validate_app_addr(uint64_t module_inst, + int32_t app_offset, uint32_t size); + +/** + * Validate the native address, check whether it belongs to WASM module + * instance's address space, or in its heap space or memory space. + * + * @param module_inst the WASM module instance + * @param native_ptr the native address to validate, which is an absolute + * address + * @param size the size bytes of the app address + * + * @return true if success, false otherwise. + */ +bool +wasm_runtime_validate_native_addr(uint64_t module_inst, + uint64_t native_ptr, uint32_t size); + +/** + * Convert app address(relative address) to native address(absolute address) + * + * @param module_inst the WASM module instance + * @param app_offset the app adress + * + * @return the native address converted + */ +uint64_t +wasm_runtime_addr_app_to_native(uint64_t module_inst, + int32_t app_offset); + +/** + * Convert native address(absolute address) to app address(relative address) + * + * @param module_inst the WASM module instance + * @param native_ptr the native address + * + * @return the app address converted + */ +int32_t +wasm_runtime_addr_native_to_app(uint64_t module_inst, + uint64_t native_ptr); + +#ifdef __cplusplus +} +#endif + +#endif /* end of _WASM_EXPORT_H */ diff --git a/core/iwasm/lib/native-interface/wasm_export_api.h b/core/iwasm/lib/native-interface/wasm_export_api.h new file mode 100644 index 000000000..ed9d570f8 --- /dev/null +++ b/core/iwasm/lib/native-interface/wasm_export_api.h @@ -0,0 +1,102 @@ +/* + * Copyright (C) 2019 Intel Corporation. All rights reserved. + * + * Licensed 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. + */ + +#ifndef _WASM_EXPORT_H +#define _WASM_EXPORT_H + +#include +#include + +/** + * API exported to WASM application + */ + +#ifdef __cplusplus +extern "C" { +#endif + +/** + * Get current WASM module instance of the current native thread + * + * @return current WASM module instance of the current native thread, 0 + * if not found + * Note: the return type is uint64_t but not pointer type, because that + * the we only supports WASM-32, in which the pointer type is + * compiled to WASM i32 type, but the pointer type in native can be + * 32-bit and 64-bit. And if the native pointer is 64-bit, data loss + * occurs after converting it to WASM i32 type. + */ +uint64_t +wasm_runtime_get_current_module_inst(); + +/** + * Validate the app address, check whether it belongs to WASM module + * instance's address space, or in its heap space or memory space. + * + * @param module_inst the WASM module instance + * @param app_offset the app address to validate, which is a relative address + * @param size the size bytes of the app address + * + * @return true if success, false otherwise. + */ +bool +wasm_runtime_validate_app_addr(uint64_t module_inst, + int32_t app_offset, uint32_t size); + +/** + * Validate the native address, check whether it belongs to WASM module + * instance's address space, or in its heap space or memory space. + * + * @param module_inst the WASM module instance + * @param native_ptr the native address to validate, which is an absolute + * address + * @param size the size bytes of the app address + * + * @return true if success, false otherwise. + */ +bool +wasm_runtime_validate_native_addr(uint64_t module_inst, + uint64_t native_ptr, uint32_t size); + +/** + * Convert app address(relative address) to native address(absolute address) + * + * @param module_inst the WASM module instance + * @param app_offset the app adress + * + * @return the native address converted + */ +uint64_t +wasm_runtime_addr_app_to_native(uint64_t module_inst, + int32_t app_offset); + +/** + * Convert native address(absolute address) to app address(relative address) + * + * @param module_inst the WASM module instance + * @param native_ptr the native address + * + * @return the app address converted + */ +int32_t +wasm_runtime_addr_native_to_app(uint64_t module_inst, + uint64_t native_ptr); + +#ifdef __cplusplus +} +#endif + +#endif /* end of _WASM_EXPORT_H */ diff --git a/core/iwasm/lib/native/base/base_lib_export.c b/core/iwasm/lib/native/base/base_lib_export.c index 4392a7ba4..4d259a392 100644 --- a/core/iwasm/lib/native/base/base_lib_export.c +++ b/core/iwasm/lib/native/base/base_lib_export.c @@ -18,11 +18,111 @@ #include #include #include "lib_export.h" +#include "bh_platform.h" +#include "wasm_export.h" #ifdef WASM_ENABLE_BASE_LIB #include "base_lib_export.h" #endif +static uint64 +wasm_runtime_get_current_module_inst_wrapper(wasm_module_inst_t module_inst) +{ + return (uint64)(uintptr_t)module_inst; +} + +static bool +wasm_runtime_validate_app_addr_wrapper(wasm_module_inst_t module_inst, + uint32 inst_part0, uint32 inst_part1, + int32 app_offset, uint32 size) +{ + bool ret; + union { uint64 u64; uint32 parts[2]; } inst; + + inst.parts[0] = inst_part0; + inst.parts[1] = inst_part1; + + if (inst.u64 != (uint64)(uintptr_t)module_inst) { + printf("Invalid module instance\n"); + return false; + } + + ret = wasm_runtime_validate_app_addr(module_inst, app_offset, size); + if (!ret) + wasm_runtime_clear_exception(module_inst); + return ret; +} + +static bool +wasm_runtime_validate_native_addr_wrapper(wasm_module_inst_t module_inst, + uint32 inst_part0, uint32 inst_part1, + uint32 native_ptr_part0, + uint32 native_ptr_part1, + uint32 size) +{ + bool ret; + union { uint64 u64; uint32 parts[2]; } inst; + union { uint64 u64; uint32 parts[2]; } native_ptr; + + inst.parts[0] = inst_part0; + inst.parts[1] = inst_part1; + + if (inst.u64 != (uint64)(uintptr_t)module_inst) { + printf("Invalid module instance\n"); + return false; + } + + native_ptr.parts[0] = native_ptr_part0; + native_ptr.parts[1] = native_ptr_part1; + ret = wasm_runtime_validate_native_addr(module_inst, + (void*)(uintptr_t)native_ptr.u64, + size); + if (!ret) + wasm_runtime_clear_exception(module_inst); + return ret; +} + +static uint64 +wasm_runtime_addr_app_to_native_wrapper(wasm_module_inst_t module_inst, + uint32 inst_part0, uint32 inst_part1, + int32 app_offset) +{ + union { uint64 u64; uint32 parts[2]; } inst; + + inst.parts[0] = inst_part0; + inst.parts[1] = inst_part1; + + if (inst.u64 != (uint64)(uintptr_t)module_inst) { + printf("Invalid module instance\n"); + return 0; + } + return (uint64)(uintptr_t) + wasm_runtime_addr_app_to_native(module_inst, app_offset); +} + +static int32 +wasm_runtime_addr_native_to_app_wrapper(wasm_module_inst_t module_inst, + uint32 inst_part0, uint32 inst_part1, + uint32 native_ptr_part0, + uint32 native_ptr_part1) +{ + union { uint64 u64; uint32 parts[2]; } inst; + union { uint64 u64; uint32 parts[2]; } native_ptr; + + inst.parts[0] = inst_part0; + inst.parts[1] = inst_part1; + + if (inst.u64 != (uint64)(uintptr_t)module_inst) { + printf("Invalid module instance\n"); + return 0; + } + + native_ptr.parts[0] = native_ptr_part0; + native_ptr.parts[1] = native_ptr_part1; + return wasm_runtime_addr_native_to_app(module_inst, + (void*)(uintptr_t)native_ptr.u64); +} + static NativeSymbol extended_native_symbol_defs[] = { /* TODO: use macro EXPORT_WASM_API() or EXPORT_WASM_API2() to add functions to register. */ @@ -38,6 +138,11 @@ static NativeSymbol extended_native_symbol_defs[] = { EXPORT_WASM_API(wasm_timer_restart), EXPORT_WASM_API(wasm_get_sys_tick_ms), #endif + EXPORT_WASM_API2(wasm_runtime_get_current_module_inst), + EXPORT_WASM_API2(wasm_runtime_validate_app_addr), + EXPORT_WASM_API2(wasm_runtime_validate_native_addr), + EXPORT_WASM_API2(wasm_runtime_addr_app_to_native), + EXPORT_WASM_API2(wasm_runtime_addr_native_to_app), }; int get_base_lib_export_apis(NativeSymbol **p_base_lib_apis) diff --git a/core/iwasm/lib/native/base/request_response.c b/core/iwasm/lib/native/base/request_response.c index 641dc549c..6e6ab5992 100644 --- a/core/iwasm/lib/native/base/request_response.c +++ b/core/iwasm/lib/native/base/request_response.c @@ -14,16 +14,16 @@ * limitations under the License. */ -#include "native_interface.h" #include "app_manager_export.h" #include "coap_ext.h" #include "wasm_export.h" extern void module_request_handler(request_t *request, void *user_data); -bool wasm_response_send(int32 buffer_offset, int size) +bool +wasm_response_send(wasm_module_inst_t module_inst, + int32 buffer_offset, int size) { - wasm_module_inst_t module_inst = get_module_inst(); char *buffer = NULL; if (!validate_app_addr(buffer_offset, size)) @@ -45,9 +45,9 @@ bool wasm_response_send(int32 buffer_offset, int size) return false; } -void wasm_register_resource(int32 url_offset) +void +wasm_register_resource(wasm_module_inst_t module_inst, int32 url_offset) { - wasm_module_inst_t module_inst = get_module_inst(); char *url = NULL; if (!validate_app_addr(url_offset, 1)) @@ -61,9 +61,10 @@ void wasm_register_resource(int32 url_offset) } } -void wasm_post_request(int32 buffer_offset, int size) +void +wasm_post_request(wasm_module_inst_t module_inst, + int32 buffer_offset, int size) { - wasm_module_inst_t module_inst = get_module_inst(); char *buffer = NULL; if (!validate_app_addr(buffer_offset, size)) @@ -92,9 +93,9 @@ void wasm_post_request(int32 buffer_offset, int size) } } -void wasm_sub_event(int32 url_offset) +void +wasm_sub_event(wasm_module_inst_t module_inst, int32 url_offset) { - wasm_module_inst_t module_inst = get_module_inst(); char *url = NULL; if (!validate_app_addr(url_offset, 1)) diff --git a/core/iwasm/lib/native/base/runtime_lib.h b/core/iwasm/lib/native/base/runtime_lib.h index bf4dccfe3..d264eb84e 100644 --- a/core/iwasm/lib/native/base/runtime_lib.h +++ b/core/iwasm/lib/native/base/runtime_lib.h @@ -17,7 +17,6 @@ #ifndef LIB_BASE_RUNTIME_LIB_H_ #define LIB_BASE_RUNTIME_LIB_H_ -#include "native_interface.h" #include "runtime_timer.h" diff --git a/core/iwasm/lib/native/base/timer_wrapper.c b/core/iwasm/lib/native/base/timer_wrapper.c index da5c8943f..c655ed040 100644 --- a/core/iwasm/lib/native/base/timer_wrapper.c +++ b/core/iwasm/lib/native/base/timer_wrapper.c @@ -37,7 +37,7 @@ void wasm_timer_callback(timer_id_t id, unsigned int mod_id) // !!! the length parameter must be 0, so the receiver will // not free the payload pointer. - bh_post_msg(module->queue, TIMER_EVENT_WASM, (char *) id, 0); + bh_post_msg(module->queue, TIMER_EVENT_WASM, (char *)(uintptr_t)id, 0); } /// @@ -149,30 +149,37 @@ timer_ctx_t get_wasm_timer_ctx() return m->timer_ctx; } -timer_id_t wasm_create_timer(int interval, bool is_period, bool auto_start) +timer_id_t +wasm_create_timer(wasm_module_inst_t module_inst, + int interval, bool is_period, bool auto_start) { return sys_create_timer(get_wasm_timer_ctx(), interval, is_period, auto_start); } -void wasm_timer_destory(timer_id_t timer_id) +void +wasm_timer_destory(wasm_module_inst_t module_inst, timer_id_t timer_id) { sys_timer_destory(get_wasm_timer_ctx(), timer_id); } -void wasm_timer_cancel(timer_id_t timer_id) +void +wasm_timer_cancel(wasm_module_inst_t module_inst, timer_id_t timer_id) { sys_timer_cancel(get_wasm_timer_ctx(), timer_id); } -void wasm_timer_restart(timer_id_t timer_id, int interval) +void +wasm_timer_restart(wasm_module_inst_t module_inst, + timer_id_t timer_id, int interval) { sys_timer_restart(get_wasm_timer_ctx(), timer_id, interval); } extern uint32 get_sys_tick_ms(); -uint32 wasm_get_sys_tick_ms(void) +uint32 +wasm_get_sys_tick_ms(wasm_module_inst_t module_inst) { return (uint32) bh_get_tick_ms(); } diff --git a/core/iwasm/lib/native/extension/connection/connection_wrapper.c b/core/iwasm/lib/native/extension/connection/connection_wrapper.c index 7bcf5860d..1a163e429 100644 --- a/core/iwasm/lib/native/extension/connection/connection_wrapper.c +++ b/core/iwasm/lib/native/extension/connection/connection_wrapper.c @@ -23,10 +23,10 @@ * This file is the consumer of connection lib which is implemented by different platforms */ - -uint32 wasm_open_connection(int32 name_offset, int32 args_offset, uint32 len) +uint32 +wasm_open_connection(wasm_module_inst_t module_inst, + int32 name_offset, int32 args_offset, uint32 len) { - wasm_module_inst_t module_inst = get_module_inst(); attr_container_t *args; char *name, *args_buf; @@ -44,15 +44,17 @@ uint32 wasm_open_connection(int32 name_offset, int32 args_offset, uint32 len) return -1; } -void wasm_close_connection(uint32 handle) +void +wasm_close_connection(wasm_module_inst_t module_inst, uint32 handle) { if (connection_impl._close != NULL) connection_impl._close(handle); } -int wasm_send_on_connection(uint32 handle, int32 data_offset, uint32 len) +int +wasm_send_on_connection(wasm_module_inst_t module_inst, + uint32 handle, int32 data_offset, uint32 len) { - wasm_module_inst_t module_inst = get_module_inst(); char *data; if (!validate_app_addr(data_offset, len) || @@ -65,9 +67,10 @@ int wasm_send_on_connection(uint32 handle, int32 data_offset, uint32 len) return -1; } -bool wasm_config_connection(uint32 handle, int32 cfg_offset, uint32 len) +bool +wasm_config_connection(wasm_module_inst_t module_inst, + uint32 handle, int32 cfg_offset, uint32 len) { - wasm_module_inst_t module_inst = get_module_inst(); char *cfg_buf; attr_container_t *cfg; diff --git a/core/iwasm/lib/native/extension/gui/wgl_btn_wrapper.c b/core/iwasm/lib/native/extension/gui/wgl_btn_wrapper.c index 7b41826d1..fa46cb66a 100644 --- a/core/iwasm/lib/native/extension/gui/wgl_btn_wrapper.c +++ b/core/iwasm/lib/native/extension/gui/wgl_btn_wrapper.c @@ -45,7 +45,9 @@ static WGLNativeFuncDef btn_native_func_defs[] = { }; /*************** Native Interface to Wasm App ***********/ -void wasm_btn_native_call(int32 func_id, uint32 argv_offset, uint32 argc) +void +wasm_btn_native_call(wasm_module_inst_t module_inst, + int32 func_id, uint32 argv_offset, uint32 argc) { uint32 size = sizeof(btn_native_func_defs) / sizeof(WGLNativeFuncDef); diff --git a/core/iwasm/lib/native/extension/gui/wgl_cb_wrapper.c b/core/iwasm/lib/native/extension/gui/wgl_cb_wrapper.c index 435643310..d0ed63e07 100644 --- a/core/iwasm/lib/native/extension/gui/wgl_cb_wrapper.c +++ b/core/iwasm/lib/native/extension/gui/wgl_cb_wrapper.c @@ -61,7 +61,9 @@ static WGLNativeFuncDef cb_native_func_defs[] = { }; /*************** Native Interface to Wasm App ***********/ -void wasm_cb_native_call(int32 func_id, uint32 argv_offset, uint32 argc) +void +wasm_cb_native_call(wasm_module_inst_t module_inst, + int32 func_id, uint32 argv_offset, uint32 argc) { uint32 size = sizeof(cb_native_func_defs) / sizeof(WGLNativeFuncDef); diff --git a/core/iwasm/lib/native/extension/gui/wgl_label_wrapper.c b/core/iwasm/lib/native/extension/gui/wgl_label_wrapper.c index edf5ba49e..a99b591b3 100644 --- a/core/iwasm/lib/native/extension/gui/wgl_label_wrapper.c +++ b/core/iwasm/lib/native/extension/gui/wgl_label_wrapper.c @@ -60,7 +60,9 @@ static WGLNativeFuncDef label_native_func_defs[] = { }; /*************** Native Interface to Wasm App ***********/ -void wasm_label_native_call(int32 func_id, uint32 argv_offset, uint32 argc) +void +wasm_label_native_call(wasm_module_inst_t module_inst, + int32 func_id, uint32 argv_offset, uint32 argc) { uint32 size = sizeof(label_native_func_defs) / sizeof(WGLNativeFuncDef); diff --git a/core/iwasm/lib/native/extension/gui/wgl_list_wrapper.c b/core/iwasm/lib/native/extension/gui/wgl_list_wrapper.c index 882230777..59040fc05 100644 --- a/core/iwasm/lib/native/extension/gui/wgl_list_wrapper.c +++ b/core/iwasm/lib/native/extension/gui/wgl_list_wrapper.c @@ -51,7 +51,9 @@ static WGLNativeFuncDef list_native_func_defs[] = { }; /*************** Native Interface to Wasm App ***********/ -void wasm_list_native_call(int32 func_id, uint32 argv_offset, uint32 argc) +void +wasm_list_native_call(wasm_module_inst_t module_inst, + int32 func_id, uint32 argv_offset, uint32 argc) { uint32 size = sizeof(list_native_func_defs) / sizeof(WGLNativeFuncDef); diff --git a/core/iwasm/lib/native/extension/gui/wgl_obj_wrapper.c b/core/iwasm/lib/native/extension/gui/wgl_obj_wrapper.c index cd9c724b8..625077626 100644 --- a/core/iwasm/lib/native/extension/gui/wgl_obj_wrapper.c +++ b/core/iwasm/lib/native/extension/gui/wgl_obj_wrapper.c @@ -341,7 +341,9 @@ static WGLNativeFuncDef obj_native_func_defs[] = { }; /*************** Native Interface to Wasm App ***********/ -void wasm_obj_native_call(int32 func_id, uint32 argv_offset, uint32 argc) +void +wasm_obj_native_call(wasm_module_inst_t module_inst, + int32 func_id, uint32 argv_offset, uint32 argc) { uint32 size = sizeof(obj_native_func_defs) / sizeof(WGLNativeFuncDef); diff --git a/core/iwasm/lib/native/extension/sensor/runtime_sensor.c b/core/iwasm/lib/native/extension/sensor/runtime_sensor.c index ffaf4826d..54e1e799e 100644 --- a/core/iwasm/lib/native/extension/sensor/runtime_sensor.c +++ b/core/iwasm/lib/native/extension/sensor/runtime_sensor.c @@ -22,8 +22,10 @@ static sys_sensor_t * g_sys_sensors = NULL; static int g_sensor_id_max = 0; -static sensor_client_t *find_sensor_client(sys_sensor_t * sensor, - unsigned int client_id, bool remove_if_found); + +static sensor_client_t * +find_sensor_client(sys_sensor_t * sensor, + unsigned int client_id, bool remove_if_found); void (*rechedule_sensor_callback)() = NULL; @@ -32,7 +34,8 @@ void (*rechedule_sensor_callback)() = NULL; * */ -static void sensor_event_cleaner(sensor_event_data_t *sensor_event) +static void +sensor_event_cleaner(sensor_event_data_t *sensor_event) { if (sensor_event->data != NULL) { if (sensor_event->data_fmt == FMT_ATTR_CONTAINER) @@ -44,8 +47,8 @@ static void sensor_event_cleaner(sensor_event_data_t *sensor_event) bh_free(sensor_event); } -static void wasm_sensor_callback(void *client, uint32 sensor_id, - void *user_data) +static void +wasm_sensor_callback(void *client, uint32 sensor_id, void *user_data) { attr_container_t *sensor_data = (attr_container_t *) user_data; attr_container_t *sensor_data_clone; @@ -92,7 +95,10 @@ static void wasm_sensor_callback(void *client, uint32 sensor_id, bh_post_msg2(module->queue, msg); } -bool wasm_sensor_config(uint32 sensor, int interval, int bit_cfg, int delay) +bool +wasm_sensor_config(wasm_module_inst_t module_inst, + uint32 sensor, int interval, + int bit_cfg, int delay) { attr_container_t * attr_cont; sensor_client_t * c; @@ -132,9 +138,10 @@ bool wasm_sensor_config(uint32 sensor, int interval, int bit_cfg, int delay) return true; } -uint32 wasm_sensor_open(int32 name_offset, int instance) +uint32 +wasm_sensor_open(wasm_module_inst_t module_inst, + int32 name_offset, int instance) { - wasm_module_inst_t module_inst = get_module_inst(); char *name = NULL; if (!validate_app_addr(name_offset, 1)) @@ -185,10 +192,11 @@ uint32 wasm_sensor_open(int32 name_offset, int instance) return -1; } -bool wasm_sensor_config_with_attr_container(uint32 sensor, int32 buffer_offset, - int len) +bool +wasm_sensor_config_with_attr_container(wasm_module_inst_t module_inst, + uint32 sensor, int32 buffer_offset, + int len) { - wasm_module_inst_t module_inst = get_module_inst(); char *buffer = NULL; if (!validate_app_addr(buffer_offset, len)) @@ -211,7 +219,8 @@ bool wasm_sensor_config_with_attr_container(uint32 sensor, int32 buffer_offset, return false; } -bool wasm_sensor_close(uint32 sensor) +bool +wasm_sensor_close(wasm_module_inst_t module_inst, uint32 sensor) { unsigned int mod_id = app_manager_get_module_id(Module_WASM_App); unsigned int client_id = mod_id; @@ -271,8 +280,9 @@ void refresh_read_interval(sensor_obj_t sensor) sensor->read_interval = interval; } -sensor_obj_t add_sys_sensor(char * name, char * description, int instance, - uint32 default_interval, void * read_func, void * config_func) +sensor_obj_t +add_sys_sensor(char * name, char * description, int instance, + uint32 default_interval, void * read_func, void * config_func) { sys_sensor_t * s = (sys_sensor_t *) bh_malloc(sizeof(sys_sensor_t)); if (s == NULL) diff --git a/core/iwasm/lib/native/extension/sensor/runtime_sensor.h b/core/iwasm/lib/native/extension/sensor/runtime_sensor.h index ce53392fa..f19b4f09d 100644 --- a/core/iwasm/lib/native/extension/sensor/runtime_sensor.h +++ b/core/iwasm/lib/native/extension/sensor/runtime_sensor.h @@ -19,6 +19,8 @@ #include "bh_platform.h" #include "attr_container.h" +#include "wasm_export.h" + struct _sys_sensor; typedef struct _sys_sensor* sensor_obj_t; @@ -60,16 +62,19 @@ int check_sensor_timers(); void reschedule_sensor_read(); uint32 -wasm_sensor_open(int32 name_offset, int instance); +wasm_sensor_open(wasm_module_inst_t module_inst, + int32 name_offset, int instance); bool -wasm_sensor_config(uint32 sensor, int interval, int bit_cfg, int delay); +wasm_sensor_config(wasm_module_inst_t module_inst, + uint32 sensor, int interval, int bit_cfg, int delay); bool -wasm_sensor_config_with_attr_container(uint32 sensor, int32 buffer_offset, - int len); +wasm_sensor_config_with_attr_container(wasm_module_inst_t module_inst, + uint32 sensor, int32 buffer_offset, + int len); bool -wasm_sensor_close(uint32 sensor); +wasm_sensor_close(wasm_module_inst_t module_inst, uint32 sensor); #endif /* LIB_EXTENSION_RUNTIME_SENSOR_H_ */ diff --git a/core/iwasm/lib/native/libc/libc_wrapper.c b/core/iwasm/lib/native/libc/libc_wrapper.c index fabc8b892..bfd2c53df 100644 --- a/core/iwasm/lib/native/libc/libc_wrapper.c +++ b/core/iwasm/lib/native/libc/libc_wrapper.c @@ -34,9 +34,6 @@ wasm_runtime_get_llvm_stack(wasm_module_inst_t module); void wasm_runtime_set_llvm_stack(wasm_module_inst_t module, uint32 llvm_stack); -#define get_module_inst() \ - wasm_runtime_get_current_module_inst() - #define validate_app_addr(offset, size) \ wasm_runtime_validate_app_addr(module_inst, offset, size) @@ -52,6 +49,29 @@ wasm_runtime_set_llvm_stack(wasm_module_inst_t module, uint32 llvm_stack); #define module_free(offset) \ wasm_runtime_module_free(module_inst, offset) +static bool +validate_str_addr(wasm_module_inst_t module_inst, int32 str_offset) +{ + int32 app_end_offset; + char *str, *str_end; + + if (!wasm_runtime_get_app_addr_range(module_inst, str_offset, + NULL, &app_end_offset)) + goto fail; + + str = addr_app_to_native(str_offset); + str_end = str + (app_end_offset - str_offset); + while (str < str_end && *str != '\0') + str++; + if (str == str_end) + goto fail; + return true; + +fail: + wasm_runtime_set_exception(module_inst, "out of bounds memory access"); + return false; +} + typedef int (*out_func_t)(int c, void *ctx); enum pad_type { @@ -64,9 +84,14 @@ enum pad_type { typedef char *_va_list; #define _INTSIZEOF(n) \ ((sizeof(n) + 3) & ~3) -#define _va_arg(ap,t) \ +#define _va_arg(ap, t) \ (*(t*)((ap += _INTSIZEOF(t)) - _INTSIZEOF(t))) +#define CHECK_VA_ARG(ap, t) do { \ + if ((uint8*)ap + _INTSIZEOF(t) > native_end_addr) \ + goto fail; \ +} while (0) + /** * @brief Output an unsigned int in hex format * @@ -172,14 +197,19 @@ print_err(out_func_t out, void *ctx) out('R', ctx); } -static void -_vprintf(out_func_t out, void *ctx, const char *fmt, _va_list ap, - wasm_module_inst_t module_inst) +static bool +_vprintf_wa(out_func_t out, void *ctx, const char *fmt, _va_list ap, + wasm_module_inst_t module_inst) { int might_format = 0; /* 1 if encountered a '%' */ enum pad_type padding = PAD_NONE; int min_width = -1; int long_ctr = 0; + uint8 *native_end_addr; + + if (!wasm_runtime_get_native_addr_range(module_inst, (uint8*)ap, + NULL, &native_end_addr)) + goto fail; /* fmt has already been adjusted if needed */ @@ -232,10 +262,13 @@ _vprintf(out_func_t out, void *ctx, const char *fmt, _va_list ap, int32 d; if (long_ctr < 2) { + CHECK_VA_ARG(ap, int32); d = _va_arg(ap, int32); } else { - int64 lld = _va_arg(ap, int64); + int64 lld; + CHECK_VA_ARG(ap, int64); + lld = _va_arg(ap, int64); if (lld > INT32_MAX || lld < INT32_MIN) { print_err(out, ctx); break; @@ -255,10 +288,13 @@ _vprintf(out_func_t out, void *ctx, const char *fmt, _va_list ap, uint32 u; if (long_ctr < 2) { + CHECK_VA_ARG(ap, uint32); u = _va_arg(ap, uint32); } else { - uint64 llu = _va_arg(ap, uint64); + uint64 llu; + CHECK_VA_ARG(ap, uint64); + llu = _va_arg(ap, uint64); if (llu > INT32_MAX) { print_err(out, ctx); break; @@ -281,8 +317,10 @@ _vprintf(out_func_t out, void *ctx, const char *fmt, _va_list ap, bool is_ptr = (*fmt == 'p') ? true : false; if (long_ctr < 2) { + CHECK_VA_ARG(ap, uint32); x = _va_arg(ap, uint32); } else { + CHECK_VA_ARG(ap, uint64); x = _va_arg(ap, uint64); } _printf_hex_uint(out, ctx, x, !is_ptr, padding, min_width); @@ -292,11 +330,13 @@ _vprintf(out_func_t out, void *ctx, const char *fmt, _va_list ap, case 's': { char *s; char *start; - int32 s_offset = _va_arg(ap, uint32); + int32 s_offset; - if (!validate_app_addr(s_offset, 1)) { - wasm_runtime_set_exception(module_inst, "out of bounds memory access"); - return; + CHECK_VA_ARG(ap, uint32); + s_offset = _va_arg(ap, uint32); + + if (!validate_str_addr(module_inst, s_offset)) { + return false; } s = start = addr_app_to_native(s_offset); @@ -314,7 +354,9 @@ _vprintf(out_func_t out, void *ctx, const char *fmt, _va_list ap, } case 'c': { - int c = _va_arg(ap, int); + int c; + CHECK_VA_ARG(ap, int); + c = _va_arg(ap, int); out(c, ctx); break; } @@ -336,6 +378,11 @@ _vprintf(out_func_t out, void *ctx, const char *fmt, _va_list ap, still_might_format: ++fmt; } + return true; + +fail: + wasm_runtime_set_exception(module_inst, "out of bounds memory access"); + return false; } struct str_context { @@ -364,7 +411,7 @@ sprintf_out(int c, struct str_context *ctx) static int printf_out(int c, struct str_context *ctx) { - printf("%c", c); + bh_printf("%c", c); ctx->count++; return c; } @@ -391,7 +438,7 @@ parse_printf_args(wasm_module_inst_t module_inst, int32 fmt_offset, _va_list v; } u; - if (!validate_app_addr(fmt_offset, 1) + if (!validate_str_addr(module_inst, fmt_offset) || !validate_app_addr(va_list_offset, sizeof(int32))) return false; @@ -404,9 +451,9 @@ parse_printf_args(wasm_module_inst_t module_inst, int32 fmt_offset, } static int -_printf_wrapper(int32 fmt_offset, int32 va_list_offset) +_printf_wrapper(wasm_module_inst_t module_inst, + int32 fmt_offset, int32 va_list_offset) { - wasm_module_inst_t module_inst = get_module_inst(); struct str_context ctx = { NULL, 0, 0 }; const char *fmt; _va_list va_args; @@ -414,21 +461,26 @@ _printf_wrapper(int32 fmt_offset, int32 va_list_offset) if (!parse_printf_args(module_inst, fmt_offset, va_list_offset, &fmt, &va_args)) return 0; - _vprintf((out_func_t) printf_out, &ctx, fmt, va_args, module_inst); + if (!_vprintf_wa((out_func_t)printf_out, &ctx, fmt, va_args, module_inst)) + return 0; return ctx.count; } static int -_sprintf_wrapper(int32 str_offset, int32 fmt_offset, int32 va_list_offset) +_sprintf_wrapper(wasm_module_inst_t module_inst, + int32 str_offset, int32 fmt_offset, int32 va_list_offset) { - wasm_module_inst_t module_inst = get_module_inst(); + int32 app_end_offset; struct str_context ctx; char *str; const char *fmt; _va_list va_args; - if (!validate_app_addr(str_offset, 1)) - return 0; + if (!wasm_runtime_get_app_addr_range(module_inst, str_offset, + NULL, &app_end_offset)) { + wasm_runtime_set_exception(module_inst, "out of bounds memory access"); + return false; + } str = addr_app_to_native(str_offset); @@ -436,10 +488,11 @@ _sprintf_wrapper(int32 str_offset, int32 fmt_offset, int32 va_list_offset) return 0; ctx.str = str; - ctx.max = INT_MAX; + ctx.max = app_end_offset - str_offset; ctx.count = 0; - _vprintf((out_func_t) sprintf_out, &ctx, fmt, va_args, module_inst); + if (!_vprintf_wa((out_func_t)sprintf_out, &ctx, fmt, va_args, module_inst)) + return 0; if (ctx.count < ctx.max) { str[ctx.count] = '\0'; @@ -449,10 +502,10 @@ _sprintf_wrapper(int32 str_offset, int32 fmt_offset, int32 va_list_offset) } static int -_snprintf_wrapper(int32 str_offset, int32 size, int32 fmt_offset, +_snprintf_wrapper(wasm_module_inst_t module_inst, + int32 str_offset, int32 size, int32 fmt_offset, int32 va_list_offset) { - wasm_module_inst_t module_inst = get_module_inst(); struct str_context ctx; char *str; const char *fmt; @@ -470,7 +523,8 @@ _snprintf_wrapper(int32 str_offset, int32 size, int32 fmt_offset, ctx.max = size; ctx.count = 0; - _vprintf((out_func_t) sprintf_out, &ctx, fmt, va_args, module_inst); + if (!_vprintf_wa((out_func_t)sprintf_out, &ctx, fmt, va_args, module_inst)) + return 0; if (ctx.count < ctx.max) { str[ctx.count] = '\0'; @@ -480,34 +534,34 @@ _snprintf_wrapper(int32 str_offset, int32 size, int32 fmt_offset, } static int -_puts_wrapper(int32 str_offset) +_puts_wrapper(wasm_module_inst_t module_inst, + int32 str_offset) { - wasm_module_inst_t module_inst = get_module_inst(); const char *str; - if (!validate_app_addr(str_offset, 1)) + if (!validate_str_addr(module_inst, str_offset)) return 0; str = addr_app_to_native(str_offset); - return printf("%s\n", str); + return bh_printf("%s\n", str); } static int -_putchar_wrapper(int c) +_putchar_wrapper(wasm_module_inst_t module_inst, int c) { - printf("%c", c); + bh_printf("%c", c); return 1; } static int32 -_strdup_wrapper(int32 str_offset) +_strdup_wrapper(wasm_module_inst_t module_inst, + int32 str_offset) { - wasm_module_inst_t module_inst = get_module_inst(); char *str, *str_ret; uint32 len; int32 str_ret_offset = 0; - if (!validate_app_addr(str_offset, 1)) + if (!validate_str_addr(module_inst, str_offset)) return 0; str = addr_app_to_native(str_offset); @@ -526,9 +580,9 @@ _strdup_wrapper(int32 str_offset) } static int32 -_memcmp_wrapper(int32 s1_offset, int32 s2_offset, int32 size) +_memcmp_wrapper(wasm_module_inst_t module_inst, + int32 s1_offset, int32 s2_offset, int32 size) { - wasm_module_inst_t module_inst = get_module_inst(); void *s1, *s2; if (!validate_app_addr(s1_offset, size) @@ -541,9 +595,9 @@ _memcmp_wrapper(int32 s1_offset, int32 s2_offset, int32 size) } static int32 -_memcpy_wrapper(int32 dst_offset, int32 src_offset, int32 size) +_memcpy_wrapper(wasm_module_inst_t module_inst, + int32 dst_offset, int32 src_offset, int32 size) { - wasm_module_inst_t module_inst = get_module_inst(); void *dst, *src; if (size == 0) @@ -560,9 +614,9 @@ _memcpy_wrapper(int32 dst_offset, int32 src_offset, int32 size) } static int32 -_memmove_wrapper(int32 dst_offset, int32 src_offset, int32 size) +_memmove_wrapper(wasm_module_inst_t module_inst, + int32 dst_offset, int32 src_offset, int32 size) { - wasm_module_inst_t module_inst = get_module_inst(); void *dst, *src; if (!validate_app_addr(dst_offset, size) @@ -576,9 +630,9 @@ _memmove_wrapper(int32 dst_offset, int32 src_offset, int32 size) } static int32 -_memset_wrapper(int32 s_offset, int32 c, int32 size) +_memset_wrapper(wasm_module_inst_t module_inst, + int32 s_offset, int32 c, int32 size) { - wasm_module_inst_t module_inst = get_module_inst(); void *s; if (!validate_app_addr(s_offset, size)) @@ -590,13 +644,13 @@ _memset_wrapper(int32 s_offset, int32 c, int32 size) } static int32 -_strchr_wrapper(int32 s_offset, int32 c) +_strchr_wrapper(wasm_module_inst_t module_inst, + int32 s_offset, int32 c) { - wasm_module_inst_t module_inst = get_module_inst(); const char *s; char *ret; - if (!validate_app_addr(s_offset, 1)) + if (!validate_str_addr(module_inst, s_offset)) return s_offset; s = addr_app_to_native(s_offset); @@ -605,13 +659,13 @@ _strchr_wrapper(int32 s_offset, int32 c) } static int32 -_strcmp_wrapper(int32 s1_offset, int32 s2_offset) +_strcmp_wrapper(wasm_module_inst_t module_inst, + int32 s1_offset, int32 s2_offset) { - wasm_module_inst_t module_inst = get_module_inst(); void *s1, *s2; - if (!validate_app_addr(s1_offset, 1) - || !validate_app_addr(s2_offset, 1)) + if (!validate_str_addr(module_inst, s1_offset) + || !validate_str_addr(module_inst, s2_offset)) return 0; s1 = addr_app_to_native(s1_offset); @@ -620,9 +674,9 @@ _strcmp_wrapper(int32 s1_offset, int32 s2_offset) } static int32 -_strncmp_wrapper(int32 s1_offset, int32 s2_offset, uint32 size) +_strncmp_wrapper(wasm_module_inst_t module_inst, + int32 s1_offset, int32 s2_offset, uint32 size) { - wasm_module_inst_t module_inst = get_module_inst(); void *s1, *s2; if (!validate_app_addr(s1_offset, size) @@ -635,25 +689,30 @@ _strncmp_wrapper(int32 s1_offset, int32 s2_offset, uint32 size) } static int32 -_strcpy_wrapper(int32 dst_offset, int32 src_offset) +_strcpy_wrapper(wasm_module_inst_t module_inst, + int32 dst_offset, int32 src_offset) { - wasm_module_inst_t module_inst = get_module_inst(); char *dst, *src; + uint32 len; - if (!validate_app_addr(dst_offset, 1) - || !validate_app_addr(src_offset, 1)) + if (!validate_str_addr(module_inst, src_offset)) + return 0; + + src = addr_app_to_native(src_offset); + len = strlen(src); + + if (!validate_app_addr(dst_offset, len + 1)) return 0; dst = addr_app_to_native(dst_offset); - src = addr_app_to_native(src_offset); - strcpy(dst, src); + strncpy(dst, src, len + 1); return dst_offset; } static int32 -_strncpy_wrapper(int32 dst_offset, int32 src_offset, uint32 size) +_strncpy_wrapper(wasm_module_inst_t module_inst, + int32 dst_offset, int32 src_offset, uint32 size) { - wasm_module_inst_t module_inst = get_module_inst(); char *dst, *src; if (!validate_app_addr(dst_offset, size) @@ -667,12 +726,12 @@ _strncpy_wrapper(int32 dst_offset, int32 src_offset, uint32 size) } static uint32 -_strlen_wrapper(int32 s_offset) +_strlen_wrapper(wasm_module_inst_t module_inst, + int32 s_offset) { - wasm_module_inst_t module_inst = get_module_inst(); char *s; - if (!validate_app_addr(s_offset, 1)) + if (!validate_str_addr(module_inst, s_offset)) return 0; s = addr_app_to_native(s_offset); @@ -680,17 +739,17 @@ _strlen_wrapper(int32 s_offset) } static int32 -_malloc_wrapper(uint32 size) +_malloc_wrapper(wasm_module_inst_t module_inst, + uint32 size) { - wasm_module_inst_t module_inst = get_module_inst(); return module_malloc(size); } static int32 -_calloc_wrapper(uint32 nmemb, uint32 size) +_calloc_wrapper(wasm_module_inst_t module_inst, + uint32 nmemb, uint32 size) { uint64 total_size = (uint64) nmemb * (uint64) size; - wasm_module_inst_t module_inst = get_module_inst(); uint32 ret_offset = 0; uint8 *ret_ptr; @@ -707,31 +766,30 @@ _calloc_wrapper(uint32 nmemb, uint32 size) } static void -_free_wrapper(int32 ptr_offset) +_free_wrapper(wasm_module_inst_t module_inst, + int32 ptr_offset) { - wasm_module_inst_t module_inst = get_module_inst(); - if (!validate_app_addr(ptr_offset, 4)) return; return module_free(ptr_offset); } static void -setTempRet0_wrapper(uint32 temp_ret) +setTempRet0_wrapper(wasm_module_inst_t module_inst, + uint32 temp_ret) { - wasm_module_inst_t module_inst = get_module_inst(); wasm_runtime_set_temp_ret(module_inst, temp_ret); } static uint32 -getTempRet0_wrapper() +getTempRet0_wrapper(wasm_module_inst_t module_inst) { - wasm_module_inst_t module_inst = get_module_inst(); return wasm_runtime_get_temp_ret(module_inst); } static uint32 -_llvm_bswap_i16_wrapper(uint32 data) +_llvm_bswap_i16_wrapper(wasm_module_inst_t module_inst, + uint32 data) { return (data & 0xFFFF0000) | ((data & 0xFF) << 8) @@ -739,7 +797,8 @@ _llvm_bswap_i16_wrapper(uint32 data) } static uint32 -_llvm_bswap_i32_wrapper(uint32 data) +_llvm_bswap_i32_wrapper(wasm_module_inst_t module_inst, + uint32 data) { return ((data & 0xFF) << 24) | ((data & 0xFF00) << 8) @@ -748,10 +807,10 @@ _llvm_bswap_i32_wrapper(uint32 data) } static uint32 -_bitshift64Lshr_wrapper(uint32 uint64_part0, uint32 uint64_part1, +_bitshift64Lshr_wrapper(wasm_module_inst_t module_inst, + uint32 uint64_part0, uint32 uint64_part1, uint32 bits) { - wasm_module_inst_t module_inst = get_module_inst(); union { uint64 value; uint32 parts[2]; @@ -767,10 +826,10 @@ _bitshift64Lshr_wrapper(uint32 uint64_part0, uint32 uint64_part1, } static uint32 -_bitshift64Shl_wrapper(uint32 int64_part0, uint32 int64_part1, +_bitshift64Shl_wrapper(wasm_module_inst_t module_inst, + uint32 int64_part0, uint32 int64_part1, uint32 bits) { - wasm_module_inst_t module_inst = get_module_inst(); union { int64 value; uint32 parts[2]; @@ -786,26 +845,25 @@ _bitshift64Shl_wrapper(uint32 int64_part0, uint32 int64_part1, } static void -_llvm_stackrestore_wrapper(uint32 llvm_stack) +_llvm_stackrestore_wrapper(wasm_module_inst_t module_inst, + uint32 llvm_stack) { - wasm_module_inst_t module_inst = get_module_inst(); - printf("_llvm_stackrestore called!\n"); + bh_printf("_llvm_stackrestore called!\n"); wasm_runtime_set_llvm_stack(module_inst, llvm_stack); } static uint32 -_llvm_stacksave_wrapper() +_llvm_stacksave_wrapper(wasm_module_inst_t module_inst) { - wasm_module_inst_t module_inst = get_module_inst(); - printf("_llvm_stacksave called!\n"); + bh_printf("_llvm_stacksave called!\n"); return wasm_runtime_get_llvm_stack(module_inst); } static int32 -_emscripten_memcpy_big_wrapper(int32 dst_offset, int32 src_offset, +_emscripten_memcpy_big_wrapper(wasm_module_inst_t module_inst, + int32 dst_offset, int32 src_offset, uint32 size) { - wasm_module_inst_t module_inst = get_module_inst(); void *dst, *src; if (!validate_app_addr(dst_offset, size) @@ -820,32 +878,48 @@ _emscripten_memcpy_big_wrapper(int32 dst_offset, int32 src_offset, } static void -abort_wrapper(int32 code) +abort_wrapper(wasm_module_inst_t module_inst, + int32 code) { - wasm_module_inst_t module_inst = get_module_inst(); char buf[32]; snprintf(buf, sizeof(buf), "env.abort(%i)", code); wasm_runtime_set_exception(module_inst, buf); } static void -abortStackOverflow_wrapper(int32 code) +abortStackOverflow_wrapper(wasm_module_inst_t module_inst, + int32 code) { - wasm_module_inst_t module_inst = get_module_inst(); char buf[32]; snprintf(buf, sizeof(buf), "env.abortStackOverflow(%i)", code); wasm_runtime_set_exception(module_inst, buf); } static void -nullFunc_X_wrapper(int32 code) +nullFunc_X_wrapper(wasm_module_inst_t module_inst, + int32 code) { - wasm_module_inst_t module_inst = get_module_inst(); char buf[32]; snprintf(buf, sizeof(buf), "env.nullFunc_X(%i)", code); wasm_runtime_set_exception(module_inst, buf); } +/*#define ENABLE_SPEC_TEST 1*/ + +#ifdef ENABLE_SPEC_TEST +static void +print_i32_wrapper(wasm_module_inst_t module_inst, int i32) +{ + bh_printf("%d\n", i32); +} + +static void +print_wrapper(wasm_module_inst_t module_inst, int i32) +{ + bh_printf("%d\n", i32); +} +#endif + /* TODO: add function parameter/result types check */ #define REG_NATIVE_FUNC(module_name, func_name) \ { #module_name, #func_name, func_name##_wrapper } @@ -857,6 +931,10 @@ typedef struct WASMNativeFuncDef { } WASMNativeFuncDef; static WASMNativeFuncDef native_func_defs[] = { +#ifdef ENABLE_SPEC_TEST + REG_NATIVE_FUNC(spectest, print_i32), + REG_NATIVE_FUNC(spectest, print), +#endif REG_NATIVE_FUNC(env, _printf), REG_NATIVE_FUNC(env, _sprintf), REG_NATIVE_FUNC(env, _snprintf), @@ -927,6 +1005,9 @@ typedef struct WASMNativeGlobalDef { } WASMNativeGlobalDef; static WASMNativeGlobalDef native_global_defs[] = { +#ifdef ENABLE_SPEC_TEST + { "spectest", "global_i32", .global_data.u32 = 0 }, +#endif { "env", "STACKTOP", .global_data.u32 = 0 }, { "env", "STACK_MAX", .global_data.u32 = 0 }, { "env", "ABORT", .global_data.u32 = 0 }, @@ -961,23 +1042,6 @@ wasm_native_global_lookup(const char *module_name, const char *global_name, global_def++; } - /* Lookup non-constant globals which cannot be defined by table */ - if (!strcmp(module_name, "env")) { - if (!strcmp(global_name, "_stdin")) { - global->global_data_linked.addr = (uintptr_t)stdin; - global->is_addr = true; - return true; - } else if (!strcmp(global_name, "_stdout")) { - global->global_data_linked.addr = (uintptr_t)stdout; - global->is_addr = true; - return true; - } else if (!strcmp(global_name, "_stderr")) { - global->global_data_linked.addr = (uintptr_t)stderr; - global->is_addr = true; - return true; - } - } - return false; } diff --git a/core/iwasm/products/alios-things/src/main.c b/core/iwasm/products/alios-things/src/main.c index 395c9b852..336247856 100644 --- a/core/iwasm/products/alios-things/src/main.c +++ b/core/iwasm/products/alios-things/src/main.c @@ -29,6 +29,20 @@ static int app_argc; static char **app_argv; +/** + * Find the unique main function from a WASM module instance + * and execute that function. + * + * @param module_inst the WASM module instance + * @param argc the number of arguments + * @param argv the arguments array + * + * @return true if the main function is called, false otherwise. + */ +bool +wasm_application_execute_main(wasm_module_inst_t module_inst, + int argc, char *argv[]); + static void* app_instance_main(wasm_module_inst_t module_inst) { diff --git a/core/iwasm/products/darwin/CMakeLists.txt b/core/iwasm/products/darwin/CMakeLists.txt new file mode 100644 index 000000000..a88b155ac --- /dev/null +++ b/core/iwasm/products/darwin/CMakeLists.txt @@ -0,0 +1,107 @@ +# Copyright (C) 2019 Intel Corporation. All rights reserved. +# +# Licensed 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. + +cmake_minimum_required (VERSION 2.8) + +project (iwasm) + +set (PLATFORM "darwin") + +# Reset default linker flags +set (CMAKE_SHARED_LIBRARY_LINK_C_FLAGS "") +set (CMAKE_SHARED_LIBRARY_LINK_CXX_FLAGS "") + +# Enable repl mode if want to test spec cases +# add_definitions(-DWASM_ENABLE_REPL) + +if (NOT ("$ENV{VALGRIND}" STREQUAL "YES")) + add_definitions(-DNVALGRIND) +endif () + +# Currently build as 64-bit by default. +set (BUILD_AS_64BIT_SUPPORT "YES") + +if (CMAKE_SIZEOF_VOID_P EQUAL 8) +if (${BUILD_AS_64BIT_SUPPORT} STREQUAL "YES") + # Add -fPIC flag if build as 64-bit + set (CMAKE_C_FLAGS "${CMAKE_C_FLAGS} -fPIC") + set (CMAKE_SHARED_LIBRARY_LINK_C_FLAGS "${CMAKE_SHARED_LIBRARY_LINK_C_FLAGS} -fPIC") +else () + add_definitions (-m32) + set (CMAKE_EXE_LINKER_FLAGS "${CMAKE_EXE_LINKER_FLAGS} -m32") + set (CMAKE_SHARED_LINKER_FLAGS "${CMAKE_SHARED_LINKER_FLAGS} -m32") +endif () +endif () + +if (NOT CMAKE_BUILD_TYPE) + set(CMAKE_BUILD_TYPE Release) +endif (NOT CMAKE_BUILD_TYPE) +message ("CMAKE_BUILD_TYPE = " ${CMAKE_BUILD_TYPE}) + +set (CMAKE_EXE_LINKER_FLAGS "${CMAKE_EXE_LINKER_FLAGS} -Wl") +set (CMAKE_C_FLAGS "${CMAKE_C_FLAGS} -ffunction-sections -fdata-sections -Wall -Wno-unused-parameter -Wno-pedantic") + +set (CMAKE_MACOSX_RPATH True) + +set (SHARED_LIB_DIR ../../../shared-lib) + +include_directories (. + ../../runtime/include + ../../runtime/platform/include + ${SHARED_LIB_DIR}/include) + +enable_language (ASM) + +include (../../runtime/platform/${PLATFORM}/platform.cmake) +include (../../runtime/utils/utils.cmake) +include (../../runtime/vmcore-wasm/vmcore.cmake) +include (../../lib/native/base/wasm_lib_base.cmake) +include (../../lib/native/libc/wasm_libc.cmake) +include (${SHARED_LIB_DIR}/platform/${PLATFORM}/shared_platform.cmake) +include (${SHARED_LIB_DIR}/mem-alloc/mem_alloc.cmake) +include (${SHARED_LIB_DIR}/utils/shared_utils.cmake) + +add_library (vmlib + ${WASM_PLATFORM_LIB_SOURCE} + ${WASM_UTILS_LIB_SOURCE} + ${VMCORE_LIB_SOURCE} + ${WASM_LIB_BASE_DIR}/base_lib_export.c + ${WASM_LIBC_SOURCE} + ${PLATFORM_SHARED_SOURCE} + ${MEM_ALLOC_SHARED_SOURCE} + ${UTILS_SHARED_SOURCE}) + +add_executable (iwasm main.c ext_lib_export.c) + +install (TARGETS iwasm DESTINATION bin) + +target_link_libraries (iwasm vmlib -lm -ldl -lpthread) + +add_library (libiwasm SHARED + ${WASM_PLATFORM_LIB_SOURCE} + ${WASM_UTILS_LIB_SOURCE} + ${VMCORE_LIB_SOURCE} + ${WASM_LIB_BASE_DIR}/base_lib_export.c + ${WASM_LIBC_SOURCE} + ${PLATFORM_SHARED_SOURCE} + ${MEM_ALLOC_SHARED_SOURCE} + ${UTILS_SHARED_SOURCE} + ext_lib_export.c) + +install (TARGETS libiwasm DESTINATION lib) + +set_target_properties (libiwasm PROPERTIES OUTPUT_NAME iwasm) + +target_link_libraries (libiwasm -lm -ldl -lpthread) + diff --git a/core/iwasm/products/darwin/ext_lib_export.c b/core/iwasm/products/darwin/ext_lib_export.c new file mode 100644 index 000000000..8d78f3ae1 --- /dev/null +++ b/core/iwasm/products/darwin/ext_lib_export.c @@ -0,0 +1,21 @@ +/* + * Copyright (C) 2019 Intel Corporation. All rights reserved. + * + * Licensed 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. + */ + +#include "lib_export.h" + +static NativeSymbol extended_native_symbol_defs[] = { }; + +#include "ext_lib_export.h" diff --git a/core/iwasm/products/darwin/main.c b/core/iwasm/products/darwin/main.c new file mode 100644 index 000000000..65f464c0b --- /dev/null +++ b/core/iwasm/products/darwin/main.c @@ -0,0 +1,251 @@ +/* + * Copyright (C) 2019 Intel Corporation. All rights reserved. + * + * Licensed 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. + */ + +#ifndef _GNU_SOURCE +#define _GNU_SOURCE +#endif +#include +#include +#include +#include "bh_platform.h" +#include "wasm_application.h" +#include "wasm_assert.h" +#include "wasm_log.h" +#include "wasm_platform_log.h" +#include "wasm_thread.h" +#include "wasm_export.h" +#include "wasm_memory.h" +#include "bh_memory.h" + +static int app_argc; +static char **app_argv; + +static int print_help() +{ + wasm_printf("Usage: iwasm [-options] wasm_file [args...]\n"); + wasm_printf("options:\n"); + wasm_printf(" -f|--function name Specify function name to run in module\n" + " rather than main\n"); +#if WASM_ENABLE_LOG != 0 + wasm_printf(" -v=X Set log verbose level (0 to 2, default is 1),\n" + " larger level with more log\n"); +#endif + wasm_printf(" --repl Start a very simple REPL (read-eval-print-loop) mode\n" + " that runs commands in the form of `FUNC ARG...`\n"); + return 1; +} + +static void* +app_instance_main(wasm_module_inst_t module_inst) +{ + const char *exception; + + wasm_application_execute_main(module_inst, app_argc, app_argv); + if ((exception = wasm_runtime_get_exception(module_inst))) + wasm_printf("%s\n", exception); + return NULL; +} + +static void* +app_instance_func(wasm_module_inst_t module_inst, const char *func_name) +{ + const char *exception; + + wasm_application_execute_func(module_inst, func_name, app_argc - 1, + app_argv + 1); + if ((exception = wasm_runtime_get_exception(module_inst))) + wasm_printf("%s\n", exception); + return NULL; +} + +/** + * Split a space separated strings into an array of strings + * Returns NULL on failure + * Memory must be freed by caller + * Based on: http://stackoverflow.com/a/11198630/471795 + */ +static char ** +split_string(char *str, int *count) +{ + char **res = NULL; + char *p; + int idx = 0; + + /* split string and append tokens to 'res' */ + do { + p = strtok(str, " "); + str = NULL; + res = (char**) realloc(res, sizeof(char*) * (idx + 1)); + if (res == NULL) { + return NULL; + } + res[idx++] = p; + } while (p); + + if (count) { + *count = idx - 1; + } + return res; +} + +static void* +app_instance_repl(wasm_module_inst_t module_inst) +{ + char *cmd = NULL; + size_t len = 0; + ssize_t n; + + while ((wasm_printf("webassembly> "), n = getline(&cmd, &len, stdin)) != -1) { + wasm_assert(n > 0); + if (cmd[n - 1] == '\n') { + if (n == 1) + continue; + else + cmd[n - 1] = '\0'; + } + app_argv = split_string(cmd, &app_argc); + if (app_argv == NULL) { + LOG_ERROR("Wasm prepare param failed: split string failed.\n"); + break; + } + if (app_argc != 0) { + wasm_application_execute_func(module_inst, app_argv[0], + app_argc - 1, app_argv + 1); + } + free(app_argv); + } + free(cmd); + return NULL; +} + +#define USE_GLOBAL_HEAP_BUF 0 + +#if USE_GLOBAL_HEAP_BUF != 0 +static char global_heap_buf[10 * 1024 * 1024] = { 0 }; +#endif + +int main(int argc, char *argv[]) +{ + char *wasm_file = NULL; + const char *func_name = NULL; + uint8 *wasm_file_buf = NULL; + int wasm_file_size; + wasm_module_t wasm_module = NULL; + wasm_module_inst_t wasm_module_inst = NULL; + char error_buf[128]; +#if WASM_ENABLE_LOG != 0 + int log_verbose_level = 1; +#endif + bool is_repl_mode = false; + + /* Process options. */ + for (argc--, argv++; argc > 0 && argv[0][0] == '-'; argc--, argv++) { + if (!strcmp(argv[0], "-f") || !strcmp(argv[0], "--function")) { + argc--, argv++; + if (argc < 2) { + print_help(); + return 0; + } + func_name = argv[0]; + } +#if WASM_ENABLE_LOG != 0 + else if (!strncmp(argv[0], "-v=", 3)) { + log_verbose_level = atoi(argv[0] + 3); + if (log_verbose_level < 0 || log_verbose_level > 2) + return print_help(); + } +#endif + else if (!strcmp(argv[0], "--repl")) + is_repl_mode = true; + else + return print_help(); + } + + if (argc == 0) + return print_help(); + + wasm_file = argv[0]; + app_argc = argc; + app_argv = argv; + +#if USE_GLOBAL_HEAP_BUF != 0 + if (bh_memory_init_with_pool(global_heap_buf, sizeof(global_heap_buf)) + != 0) { + wasm_printf("Init memory with global heap buffer failed.\n"); + return -1; + } +#else + if (bh_memory_init_with_allocator(malloc, free)) { + wasm_printf("Init memory with memory allocator failed.\n"); + return -1; + } +#endif + + /* initialize runtime environment */ + if (!wasm_runtime_init()) + goto fail1; + + wasm_log_set_verbose_level(log_verbose_level); + + /* load WASM byte buffer from WASM bin file */ + if (!(wasm_file_buf = (uint8*) bh_read_file_to_buffer(wasm_file, + &wasm_file_size))) + goto fail2; + + /* load WASM module */ + if (!(wasm_module = wasm_runtime_load(wasm_file_buf, wasm_file_size, + error_buf, sizeof(error_buf)))) { + wasm_printf("%s\n", error_buf); + goto fail3; + } + + /* instantiate the module */ + if (!(wasm_module_inst = wasm_runtime_instantiate(wasm_module, + 64 * 1024, /* stack size */ + 64 * 1024, /* heap size */ + error_buf, + sizeof(error_buf)))) { + wasm_printf("%s\n", error_buf); + goto fail4; + } + + if (is_repl_mode) + app_instance_repl(wasm_module_inst); + else if (func_name) + app_instance_func(wasm_module_inst, func_name); + else + app_instance_main(wasm_module_inst); + + /* destroy the module instance */ + wasm_runtime_deinstantiate(wasm_module_inst); + +fail4: + /* unload the module */ + wasm_runtime_unload(wasm_module); + +fail3: + /* free the file buffer */ + wasm_free(wasm_file_buf); + +fail2: + /* destroy runtime environment */ + wasm_runtime_destroy(); + +fail1: + bh_memory_destroy(); + return 0; +} + diff --git a/core/iwasm/products/linux-sgx/CMakeLists.txt b/core/iwasm/products/linux-sgx/CMakeLists.txt new file mode 100644 index 000000000..4d590a8ef --- /dev/null +++ b/core/iwasm/products/linux-sgx/CMakeLists.txt @@ -0,0 +1,90 @@ +# Copyright (C) 2019 Intel Corporation. All rights reserved. +# +# Licensed 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. + +cmake_minimum_required (VERSION 2.8) + +project (iwasm) + +set (PLATFORM "linux-sgx") + +# Reset default linker flags +set (CMAKE_SHARED_LIBRARY_LINK_C_FLAGS "") +set (CMAKE_SHARED_LIBRARY_LINK_CXX_FLAGS "") + +add_definitions(-DUSE_SGX=1) +add_definitions(-DOPS_INPUT_OUTPUT=1) +add_definitions(-DOPS_UNSAFE_BUFFERS=0) +add_definitions(-DWASM_ENABLE_LOG=0) +add_definitions(-Dbh_printf=bh_printf_sgx) + +# Enable repl mode if want to test spec cases +# add_definitions(-DWASM_ENABLE_REPL) + +if (NOT ("$ENV{VALGRIND}" STREQUAL "YES")) + add_definitions(-DNVALGRIND) +endif () + +# Currently build as 64-bit by default. +set (BUILD_AS_64BIT_SUPPORT "YES") + +if (CMAKE_SIZEOF_VOID_P EQUAL 8) +if (${BUILD_AS_64BIT_SUPPORT} STREQUAL "YES") + # Add -fPIC flag if build as 64-bit + set (CMAKE_C_FLAGS "${CMAKE_C_FLAGS} -fPIC") + set (CMAKE_SHARED_LIBRARY_LINK_C_FLAGS "${CMAKE_SHARED_LIBRARY_LINK_C_FLAGS} -fPIC") +else () + add_definitions (-m32) + set (CMAKE_EXE_LINKER_FLAGS "${CMAKE_EXE_LINKER_FLAGS} -m32") + set (CMAKE_SHARED_LINKER_FLAGS "${CMAKE_SHARED_LINKER_FLAGS} -m32") +endif () +endif () + +if (NOT CMAKE_BUILD_TYPE) + set(CMAKE_BUILD_TYPE Release) +endif (NOT CMAKE_BUILD_TYPE) +message ("CMAKE_BUILD_TYPE = " ${CMAKE_BUILD_TYPE}) + +set (CMAKE_EXE_LINKER_FLAGS "${CMAKE_EXE_LINKER_FLAGS} -Wl,--gc-sections") +set (CMAKE_C_FLAGS "${CMAKE_C_FLAGS} -ffunction-sections -fdata-sections -Wall -Wno-unused-parameter -Wno-pedantic") + +set (SHARED_LIB_DIR ../../../shared-lib) + +include_directories (. + ../../runtime/include + ../../runtime/platform/include + ${SHARED_LIB_DIR}/include + $ENV{SGX_SDK}/include) + +enable_language (ASM) + +include (../../runtime/platform/${PLATFORM}/platform.cmake) +include (../../runtime/utils/utils.cmake) +include (../../runtime/vmcore-wasm/vmcore.cmake) +include (../../lib/native/base/wasm_lib_base.cmake) +include (../../lib/native/libc/wasm_libc.cmake) +include (${SHARED_LIB_DIR}/platform/${PLATFORM}/shared_platform.cmake) +include (${SHARED_LIB_DIR}/mem-alloc/mem_alloc.cmake) +include (${SHARED_LIB_DIR}/utils/shared_utils.cmake) + +add_library (vmlib + ${WASM_PLATFORM_LIB_SOURCE} + ${WASM_UTILS_LIB_SOURCE} + ${VMCORE_LIB_SOURCE} + ${WASM_LIB_BASE_DIR}/base_lib_export.c + ${WASM_LIBC_SOURCE} + ${PLATFORM_SHARED_SOURCE} + ${MEM_ALLOC_SHARED_SOURCE} + ${UTILS_SHARED_SOURCE}) + +add_library (extlib ext_lib_export.c) diff --git a/core/iwasm/products/linux-sgx/ext_lib_export.c b/core/iwasm/products/linux-sgx/ext_lib_export.c new file mode 100644 index 000000000..8d78f3ae1 --- /dev/null +++ b/core/iwasm/products/linux-sgx/ext_lib_export.c @@ -0,0 +1,21 @@ +/* + * Copyright (C) 2019 Intel Corporation. All rights reserved. + * + * Licensed 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. + */ + +#include "lib_export.h" + +static NativeSymbol extended_native_symbol_defs[] = { }; + +#include "ext_lib_export.h" diff --git a/core/iwasm/products/linux/CMakeLists.txt b/core/iwasm/products/linux/CMakeLists.txt index a2510790e..6e8936707 100644 --- a/core/iwasm/products/linux/CMakeLists.txt +++ b/core/iwasm/products/linux/CMakeLists.txt @@ -68,6 +68,7 @@ include (../../lib/native/base/wasm_lib_base.cmake) include (../../lib/native/libc/wasm_libc.cmake) include (${SHARED_LIB_DIR}/platform/${PLATFORM}/shared_platform.cmake) include (${SHARED_LIB_DIR}/mem-alloc/mem_alloc.cmake) +include (${SHARED_LIB_DIR}/utils/shared_utils.cmake) add_library (vmlib ${WASM_PLATFORM_LIB_SOURCE} @@ -76,7 +77,8 @@ add_library (vmlib ${WASM_LIB_BASE_DIR}/base_lib_export.c ${WASM_LIBC_SOURCE} ${PLATFORM_SHARED_SOURCE} - ${MEM_ALLOC_SHARED_SOURCE}) + ${MEM_ALLOC_SHARED_SOURCE} + ${UTILS_SHARED_SOURCE}) add_executable (iwasm main.c ext_lib_export.c) @@ -91,7 +93,8 @@ add_library (libiwasm SHARED ${WASM_LIB_BASE_DIR}/base_lib_export.c ${WASM_LIBC_SOURCE} ${PLATFORM_SHARED_SOURCE} - ${MEM_ALLOC_SHARED_SOURCE}) + ${MEM_ALLOC_SHARED_SOURCE} + ${UTILS_SHARED_SOURCE}) install (TARGETS libiwasm DESTINATION lib) diff --git a/core/iwasm/products/linux/main.c b/core/iwasm/products/linux/main.c index 9b0dc08cc..86c6e5e75 100644 --- a/core/iwasm/products/linux/main.c +++ b/core/iwasm/products/linux/main.c @@ -46,6 +46,35 @@ static int print_help() return 1; } +/** + * Find the unique main function from a WASM module instance + * and execute that function. + * + * @param module_inst the WASM module instance + * @param argc the number of arguments + * @param argv the arguments array + * + * @return true if the main function is called, false otherwise. + */ +bool +wasm_application_execute_main(wasm_module_inst_t module_inst, + int argc, char *argv[]); + +/** + * Find the specified function in argv[0] from WASM module of current instance + * and execute that function. + * + * @param module_inst the WASM module instance + * @param name the name of the function to execute + * @param argc the number of arguments + * @param argv the arguments array + * + * @return true if the specified function is called, false otherwise. + */ +bool +wasm_application_execute_func(wasm_module_inst_t module_inst, + const char *name, int argc, char *argv[]); + static void* app_instance_main(wasm_module_inst_t module_inst) { @@ -129,7 +158,11 @@ app_instance_repl(wasm_module_inst_t module_inst) return NULL; } -static char global_heap_buf[512 * 1024] = { 0 }; +#define USE_GLOBAL_HEAP_BUF 0 + +#if USE_GLOBAL_HEAP_BUF != 0 +static char global_heap_buf[10 * 1024 * 1024] = { 0 }; +#endif int main(int argc, char *argv[]) { @@ -175,11 +208,18 @@ int main(int argc, char *argv[]) app_argc = argc; app_argv = argv; +#if USE_GLOBAL_HEAP_BUF != 0 if (bh_memory_init_with_pool(global_heap_buf, sizeof(global_heap_buf)) != 0) { - wasm_printf("Init global heap failed.\n"); + wasm_printf("Init memory with global heap buffer failed.\n"); return -1; } +#else + if (bh_memory_init_with_allocator(malloc, free)) { + wasm_printf("Init memory with memory allocator failed.\n"); + return -1; + } +#endif /* initialize runtime environment */ if (!wasm_runtime_init()) @@ -201,8 +241,8 @@ int main(int argc, char *argv[]) /* instantiate the module */ if (!(wasm_module_inst = wasm_runtime_instantiate(wasm_module, - 16 * 1024, /* stack size */ - 8 * 1024, /* heap size */ + 64 * 1024, /* stack size */ + 64 * 1024, /* heap size */ error_buf, sizeof(error_buf)))) { wasm_printf("%s\n", error_buf); diff --git a/core/iwasm/products/vxworks/main.c b/core/iwasm/products/vxworks/main.c index dc2630428..a1a503f31 100644 --- a/core/iwasm/products/vxworks/main.c +++ b/core/iwasm/products/vxworks/main.c @@ -46,6 +46,35 @@ static int print_help() return 1; } +/** + * Find the unique main function from a WASM module instance + * and execute that function. + * + * @param module_inst the WASM module instance + * @param argc the number of arguments + * @param argv the arguments array + * + * @return true if the main function is called, false otherwise. + */ +bool +wasm_application_execute_main(wasm_module_inst_t module_inst, + int argc, char *argv[]); + +/** + * Find the specified function in argv[0] from WASM module of current instance + * and execute that function. + * + * @param module_inst the WASM module instance + * @param name the name of the function to execute + * @param argc the number of arguments + * @param argv the arguments array + * + * @return true if the specified function is called, false otherwise. + */ +bool +wasm_application_execute_func(wasm_module_inst_t module_inst, + const char *name, int argc, char *argv[]); + static void* app_instance_main(wasm_module_inst_t module_inst) { diff --git a/core/iwasm/products/zephyr/simple/src/main.c b/core/iwasm/products/zephyr/simple/src/main.c index a6a9260a7..da85a3bba 100644 --- a/core/iwasm/products/zephyr/simple/src/main.c +++ b/core/iwasm/products/zephyr/simple/src/main.c @@ -26,9 +26,28 @@ #include "bh_memory.h" #include "test_wasm.h" +#define CONFIG_GLOBAL_HEAP_BUF_SIZE 131072 +#define CONFIG_APP_STACK_SIZE 8192 +#define CONFIG_APP_HEAP_SIZE 8192 +#define CONFIG_MAIN_THREAD_STACK_SIZE 4096 + static int app_argc; static char **app_argv; +/** + * Find the unique main function from a WASM module instance + * and execute that function. + * + * @param module_inst the WASM module instance + * @param argc the number of arguments + * @param argv the arguments array + * + * @return true if the main function is called, false otherwise. + */ +bool +wasm_application_execute_main(wasm_module_inst_t module_inst, + int argc, char *argv[]); + static void* app_instance_main(wasm_module_inst_t module_inst) { @@ -40,7 +59,7 @@ app_instance_main(wasm_module_inst_t module_inst) return NULL; } -static char global_heap_buf[512 * 1024] = { 0 }; +static char global_heap_buf[CONFIG_GLOBAL_HEAP_BUF_SIZE] = { 0 }; void iwasm_main(void *arg1, void *arg2, void *arg3) { @@ -58,7 +77,7 @@ void iwasm_main(void *arg1, void *arg2, void *arg3) (void) arg3; if (bh_memory_init_with_pool(global_heap_buf, sizeof(global_heap_buf)) - != 0) { + != 0) { wasm_printf("Init global heap failed.\n"); return; } @@ -77,14 +96,17 @@ void iwasm_main(void *arg1, void *arg2, void *arg3) /* load WASM module */ if (!(wasm_module = wasm_runtime_load(wasm_file_buf, wasm_file_size, - error_buf, sizeof(error_buf)))) { + error_buf, sizeof(error_buf)))) { wasm_printf("%s\n", error_buf); goto fail2; } /* instantiate the module */ - if (!(wasm_module_inst = wasm_runtime_instantiate(wasm_module, 8 * 1024, - 8 * 1024, error_buf, sizeof(error_buf)))) { + if (!(wasm_module_inst = wasm_runtime_instantiate(wasm_module, + CONFIG_APP_STACK_SIZE, + CONFIG_APP_HEAP_SIZE, + error_buf, + sizeof(error_buf)))) { wasm_printf("%s\n", error_buf); goto fail3; } @@ -105,24 +127,23 @@ void iwasm_main(void *arg1, void *arg2, void *arg3) fail1: bh_memory_destroy(); } -#define DEFAULT_THREAD_STACKSIZE (6 * 1024) -#define DEFAULT_THREAD_PRIORITY 5 +#define MAIN_THREAD_STACK_SIZE (CONFIG_MAIN_THREAD_STACK_SIZE) +#define MAIN_THREAD_PRIORITY 5 -K_THREAD_STACK_DEFINE(iwasm_main_thread_stack, DEFAULT_THREAD_STACKSIZE); +K_THREAD_STACK_DEFINE(iwasm_main_thread_stack, MAIN_THREAD_STACK_SIZE); static struct k_thread iwasm_main_thread; bool iwasm_init(void) { k_tid_t tid = k_thread_create(&iwasm_main_thread, iwasm_main_thread_stack, - DEFAULT_THREAD_STACKSIZE, iwasm_main, NULL, NULL, NULL, - DEFAULT_THREAD_PRIORITY, 0, K_NO_WAIT); + MAIN_THREAD_STACK_SIZE, + iwasm_main, NULL, NULL, NULL, + MAIN_THREAD_PRIORITY, 0, K_NO_WAIT); return tid ? true : false; } -#ifndef CONFIG_AEE_ENABLE void main(void) { iwasm_init(); } -#endif diff --git a/core/iwasm/runtime/include/bh_memory.h b/core/iwasm/runtime/include/bh_memory.h new file mode 100644 index 000000000..352137a34 --- /dev/null +++ b/core/iwasm/runtime/include/bh_memory.h @@ -0,0 +1,110 @@ +/* + * Copyright (C) 2019 Intel Corporation. All rights reserved. + * + * Licensed 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. + */ + +#ifndef _BH_MEMORY_H +#define _BH_MEMORY_H + +#ifdef __cplusplus +extern "C" { +#endif + +#define BH_KB (1024) +#define BH_MB ((BH_KB)*1024) +#define BH_GB ((BH_MB)*1024) + +/** + * Initialize memory allocator with a pool, the bh_malloc/bh_free function + * will malloc/free memory from the pool + * + * @param mem the pool buffer + * @param bytes the size bytes of the buffer + * + * @return 0 if success, -1 otherwise + */ +int bh_memory_init_with_pool(void *mem, unsigned int bytes); + +/** + * Initialize memory allocator with memory allocator, the bh_malloc/bh_free + * function will malloc/free memory with the allocator passed + * + * @param malloc_func the malloc function + * @param free_func the free function + * + * @return 0 if success, -1 otherwise + */ +int bh_memory_init_with_allocator(void *malloc_func, void *free_func); + +/** + * Destroy memory + */ +void bh_memory_destroy(); + +/** + * Get the pool size of memory, if memory is initialized with allocator, + * return 1GB by default. + */ +int bh_memory_pool_size(); + +#if BEIHAI_ENABLE_MEMORY_PROFILING == 0 + +/** + * This function allocates a memory chunk from system + * + * @param size bytes need allocate + * + * @return the pointer to memory allocated + */ +void* bh_malloc(unsigned int size); + +/** + * This function frees memory chunk + * + * @param ptr the pointer to memory need free + */ +void bh_free(void *ptr); + +#else + +void* bh_malloc_profile(const char *file, int line, const char *func, unsigned int size); +void bh_free_profile(const char *file, int line, const char *func, void *ptr); + +#define bh_malloc(size) bh_malloc_profile(__FILE__, __LINE__, __func__, size) +#define bh_free(ptr) bh_free_profile(__FILE__, __LINE__, __func__, ptr) + +/** + * Print current memory profiling data + * + * @param file file name of the caller + * @param line line of the file of the caller + * @param func function name of the caller + */ +void memory_profile_print(const char *file, int line, const char *func, int alloc); + +/** + * Summarize memory usage and print it out + * Can use awk to analyze the output like below: + * awk -F: '{print $2,$4,$6,$8,$9}' OFS="\t" ./out.txt | sort -n -r -k 1 + */ +void memory_usage_summarize(); + +#endif + +#ifdef __cplusplus +} +#endif + +#endif /* #ifndef _BH_MEMORY_H */ + diff --git a/core/iwasm/runtime/include/lib_export.h b/core/iwasm/runtime/include/lib_export.h index d6b335f2e..e5eb6b7ee 100644 --- a/core/iwasm/runtime/include/lib_export.h +++ b/core/iwasm/runtime/include/lib_export.h @@ -40,7 +40,13 @@ int get_base_lib_export_apis(NativeSymbol **p_base_lib_apis); /** - * Get the exported APIs of extend lib + * Get the exported APIs of extended lib, this API isn't provided by WASM VM, + * it must be provided by developer to register the extended native APIs, + * for example, developer can register his native APIs to extended_native_symbol_defs, + * array, and include file ext_lib_export.h which implements this API. + * And if developer hasn't any native API to register, he can define an empty + * extended_native_symbol_defs array, and then include file ext_lib_export.h to + * implements this API. * * @param p_base_lib_apis return the exported API array of extend lib * diff --git a/core/iwasm/runtime/include/wasm_application.h b/core/iwasm/runtime/include/wasm_application.h new file mode 100644 index 000000000..31813b2ee --- /dev/null +++ b/core/iwasm/runtime/include/wasm_application.h @@ -0,0 +1,65 @@ +/* + * Copyright (C) 2019 Taobao (China) Inc. All rights reserved. + * + * Licensed 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. + */ + +#ifndef _WASM_APPLICATION_H +#define _WASM_APPLICATION_H + +//#include "wasm_runtime.h" + + +#ifdef __cplusplus +extern "C" { +#endif + +struct WASMModuleInstance; + +/** + * Find the unique main function from a WASM module instance + * and execute that function. + * + * @param module_inst the WASM module instance + * @param argc the number of arguments + * @param argv the arguments array + * + * @return true if the main function is called, false otherwise and exception will be thrown, + * the caller can call wasm_runtime_get_exception to get exception info. + */ +bool +wasm_application_execute_main(struct WASMModuleInstance *module_inst, + int argc, char *argv[]); + +/** + * Find the specified function in argv[0] from a WASM module instance + * and execute that function. + * + * @param module_inst the WASM module instance + * @param name the name of the function to execute + * @param argc the number of arguments + * @param argv the arguments array + * + * @return true if the specified function is called, false otherwise and exception will be thrown, + * the caller can call wasm_runtime_get_exception to get exception info. + */ +bool +wasm_application_execute_func(struct WASMModuleInstance *module_inst, + char *name, int argc, char *argv[]); + +#ifdef __cplusplus +} +#endif + +#endif /* end of _WASM_APPLICATION_H */ + diff --git a/core/iwasm/runtime/include/wasm_export.h b/core/iwasm/runtime/include/wasm_export.h index 0492fcb44..e6c9df5d7 100644 --- a/core/iwasm/runtime/include/wasm_export.h +++ b/core/iwasm/runtime/include/wasm_export.h @@ -152,6 +152,13 @@ wasm_runtime_instantiate(const wasm_module_t module, void wasm_runtime_deinstantiate(wasm_module_inst_t module_inst); +#if WASM_ENABLE_EXT_MEMORY_SPACE != 0 +bool +wasm_runtime_set_ext_memory(wasm_module_inst_t module_inst, + uint8_t *ext_mem_data, uint32_t ext_mem_size, + char *error_buf, uint32_t error_buf_size); +#endif + /** * Load WASM module instance from AOT file. * @@ -385,34 +392,36 @@ wasm_runtime_addr_native_to_app(wasm_module_inst_t module_inst, void *native_ptr); /** - * Find the unique main function from a WASM module instance - * and execute that function. + * Get the app address range (relative address) that a app address belongs to * * @param module_inst the WASM module instance - * @param argc the number of arguments - * @param argv the arguments array + * @param app_offset the app address to retrieve + * @param p_app_start_offset buffer to output the app start offset if not NULL + * @param p_app_end_offset buffer to output the app end offset if not NULL * - * @return true if the main function is called, false otherwise. + * @return true if success, false otherwise. */ bool -wasm_application_execute_main(wasm_module_inst_t module_inst, - int argc, char *argv[]); +wasm_runtime_get_app_addr_range(wasm_module_inst_t module_inst, + int32_t app_offset, + int32_t *p_app_start_offset, + int32_t *p_app_end_offset); /** - * Find the specified function in argv[0] from WASM module of current instance - * and execute that function. + * Get the native address range (absolute address) that a native address belongs to * * @param module_inst the WASM module instance - * @param name the name of the function to execute - * @param argc the number of arguments - * @param argv the arguments array + * @param native_ptr the native address to retrieve + * @param p_native_start_addr buffer to output the native start address if not NULL + * @param p_native_end_addr buffer to output the native end address if not NULL * - * @return true if the specified function is called, false otherwise. + * @return true if success, false otherwise. */ bool -wasm_application_execute_func(wasm_module_inst_t module_inst, - const char *name, int argc, char *argv[]); - +wasm_runtime_get_native_addr_range(wasm_module_inst_t module_inst, + uint8_t *native_ptr, + uint8_t **p_native_start_addr, + uint8_t **p_native_end_addr); #ifdef __cplusplus } diff --git a/core/iwasm/runtime/platform/darwin/platform.cmake b/core/iwasm/runtime/platform/darwin/platform.cmake new file mode 100644 index 000000000..ea7f7497e --- /dev/null +++ b/core/iwasm/runtime/platform/darwin/platform.cmake @@ -0,0 +1,25 @@ +# Copyright (C) 2019 Intel Corporation. All rights reserved. +# +# Licensed 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. + +add_definitions (-D__POSIX__ -D_XOPEN_SOURCE=600 -D_POSIX_C_SOURCE=200809L) + +set (PLATFORM_LIB_DIR ${CMAKE_CURRENT_LIST_DIR}) + +include_directories(${PLATFORM_LIB_DIR}) +include_directories(${PLATFORM_LIB_DIR}/../include) + +file (GLOB_RECURSE source_all ${PLATFORM_LIB_DIR}/*.c) + +set (WASM_PLATFORM_LIB_SOURCE ${source_all}) + diff --git a/core/iwasm/runtime/platform/darwin/wasm_native.c b/core/iwasm/runtime/platform/darwin/wasm_native.c new file mode 100644 index 000000000..8feb8412b --- /dev/null +++ b/core/iwasm/runtime/platform/darwin/wasm_native.c @@ -0,0 +1,25 @@ +/* + * Copyright (C) 2019 Intel Corporation. All rights reserved. + * + * Licensed 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. + */ + +#include "wasm_native.h" + +void* +wasm_platform_native_func_lookup(const char *module_name, + const char *func_name) +{ + return NULL; +} + diff --git a/core/iwasm/runtime/platform/include/wasm_platform_log.h b/core/iwasm/runtime/platform/include/wasm_platform_log.h index 3fe55bf59..e74de3ff2 100644 --- a/core/iwasm/runtime/platform/include/wasm_platform_log.h +++ b/core/iwasm/runtime/platform/include/wasm_platform_log.h @@ -17,7 +17,9 @@ #ifndef _WASM_PLATFORM_LOG #define _WASM_PLATFORM_LOG -#define wasm_printf printf +#include "bh_platform.h" + +#define wasm_printf bh_printf #define wasm_vprintf vprintf diff --git a/core/iwasm/runtime/platform/linux-sgx/platform.cmake b/core/iwasm/runtime/platform/linux-sgx/platform.cmake new file mode 100644 index 000000000..c01fd0e57 --- /dev/null +++ b/core/iwasm/runtime/platform/linux-sgx/platform.cmake @@ -0,0 +1,25 @@ +# Copyright (C) 2019 Intel Corporation. All rights reserved. +# +# Licensed 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. + +add_definitions (-D__POSIX__ -D_XOPEN_SOURCE=600 -D_POSIX_C_SOURCE=199309L) + +set (PLATFORM_LIB_DIR ${CMAKE_CURRENT_LIST_DIR}) + +include_directories(${PLATFORM_LIB_DIR}) +include_directories(${PLATFORM_LIB_DIR}/../include) + +file (GLOB_RECURSE source_all ${PLATFORM_LIB_DIR}/*.c) + +set (WASM_PLATFORM_LIB_SOURCE ${source_all}) + diff --git a/core/iwasm/runtime/platform/linux-sgx/wasm_native.c b/core/iwasm/runtime/platform/linux-sgx/wasm_native.c new file mode 100644 index 000000000..b8d64b08c --- /dev/null +++ b/core/iwasm/runtime/platform/linux-sgx/wasm_native.c @@ -0,0 +1,336 @@ +/* + * Copyright (C) 2019 Intel Corporation. All rights reserved. + * + * Licensed 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. + */ + +#ifndef _GNU_SOURCE +#define _GNU_SOURCE /* for O_DIRECT */ +#endif + +#include "wasm_native.h" +#include "wasm_runtime.h" +#include "wasm_log.h" +#include "wasm_memory.h" +#include "wasm_platform_log.h" + +#include +#include +#include +#include +#include +#include +#include +#include +#include + + +#define validate_app_addr(offset, size) \ + wasm_runtime_validate_app_addr(module_inst, offset, size) + +#define addr_app_to_native(offset) \ + wasm_runtime_addr_app_to_native(module_inst, offset) + +#define addr_native_to_app(ptr) \ + wasm_runtime_addr_native_to_app(module_inst, ptr) + +#define module_malloc(size) \ + wasm_runtime_module_malloc(module_inst, size) + +#define module_free(offset) \ + wasm_runtime_module_free(module_inst, offset) + + +static int32 +__syscall0_wrapper(WASMModuleInstance *module_inst, int32 arg0) +{ + switch (arg0) { + case 199: /* getuid */ + /* TODO */ + default: + bh_printf("##_syscall0 called, syscall id: %d\n", arg0); + } + return 0; +} + +static int32 +__syscall1_wrapper(WASMModuleInstance *module_inst, int32 arg0, int32 arg1) +{ + switch (arg0) { + case 6: /* close */ + /* TODO */ + default: + bh_printf("##_syscall1 called, syscall id: %d\n", arg0); + } + return 0; +} + +static int32 +__syscall2_wrapper(WASMModuleInstance *module_inst, + int32 arg0, int32 arg1, int32 arg2) +{ + switch (arg0) { + case 183: /* getcwd */ + /* TODO */ + default: + bh_printf("##_syscall2 called, syscall id: %d\n", arg0); + } + return 0; +} + +static int32 +__syscall3_wrapper(WASMModuleInstance *module_inst, + int32 arg0, int32 arg1, int32 arg2, int32 arg3) +{ + switch (arg0) { + case 146: /* writev */ + { + /* Implement syscall 54 and syscall 146 to support printf() + for non SIDE_MODULE=1 mode */ + struct iovec_app { + int32 iov_base_offset; + uint32 iov_len; + } *vec; + int32 vec_offset = arg2, str_offset; + uint32 iov_count = arg3, i; + int32 count = 0; + char *iov_base, *str; + + if (!validate_app_addr(vec_offset, sizeof(struct iovec_app))) + return 0; + + vec = (struct iovec_app *)addr_app_to_native(vec_offset); + for (i = 0; i < iov_count; i++, vec++) { + if (vec->iov_len > 0) { + if (!validate_app_addr(vec->iov_base_offset, 1)) + return 0; + iov_base = (char*)addr_app_to_native(vec->iov_base_offset); + + if (!(str_offset = module_malloc(vec->iov_len + 1))) + return 0; + + str = addr_app_to_native(str_offset); + + memcpy(str, iov_base, vec->iov_len); + str[vec->iov_len] = '\0'; + count += wasm_printf("%s", str); + + module_free(str_offset); + } + } + return count; + } + case 145: /* readv */ + case 3: /* read*/ + case 5: /* open */ + case 221: /* fcntl */ + /* TODO */ + default: + bh_printf("##_syscall3 called, syscall id: %d\n", arg0); + } + return 0; +} + +static int32 +__syscall4_wrapper(WASMModuleInstance *module_inst, + int32 arg0, int32 arg1, int32 arg2, + int32 arg3, int32 arg4) +{ + bh_printf("##_syscall4 called, syscall id: %d\n", arg0); + return 0; +} + +static int32 +__syscall5_wrapper(WASMModuleInstance *module_inst, + int32 arg0, int32 arg1, int32 arg2, + int32 arg3, int32 arg4, int32 arg5) +{ + switch (arg0) { + case 140: /* llseek */ + /* TODO */ + default: + bh_printf("##_syscall5 called, args[0]: %d\n", arg0); + } + return 0; +} + +#define GET_EMCC_SYSCALL_ARGS() \ + int32 *args; \ + if (!validate_app_addr(args_off, 1)) \ + return 0; \ + args = addr_app_to_native(args_off) \ + +#define EMCC_SYSCALL_WRAPPER0(id) \ + static int32 ___syscall##id##_wrapper(WASMModuleInstance *module_inst,\ + int32 _id) { \ + return __syscall0_wrapper(module_inst, id); \ + } + +#define EMCC_SYSCALL_WRAPPER1(id) \ + static int32 ___syscall##id##_wrapper(WASMModuleInstance *module_inst,\ + int32 _id, int32 args_off) { \ + GET_EMCC_SYSCALL_ARGS(); \ + return __syscall1_wrapper(module_inst, id, args[0]); \ + } + +#define EMCC_SYSCALL_WRAPPER2(id) \ + static int32 ___syscall##id##_wrapper(WASMModuleInstance *module_inst,\ + int32 _id, int32 args_off){ \ + GET_EMCC_SYSCALL_ARGS(); \ + return __syscall2_wrapper(module_inst, id, args[0], args[1]); \ + } + +#define EMCC_SYSCALL_WRAPPER3(id) \ + static int32 ___syscall##id##_wrapper(WASMModuleInstance *module_inst,\ + int32 _id, int32 args_off) { \ + GET_EMCC_SYSCALL_ARGS(); \ + return __syscall3_wrapper(module_inst, id, \ + args[0], args[1], args[2]); \ + } + +#define EMCC_SYSCALL_WRAPPER4(id) \ + static int32 ___syscall##id##_wrapper(WASMModuleInstance *module_inst,\ + int32 _id, int32 args_off) { \ + GET_EMCC_SYSCALL_ARGS(); \ + return __syscall4_wrapper(module_inst, id, \ + args[0], args[1], args[2], args[3]); \ + } + +#define EMCC_SYSCALL_WRAPPER5(id) \ + static int32 ___syscall##id##_wrapper(WASMModuleInstance *module_inst,\ + int32 _id, int32 args_off) { \ + GET_EMCC_SYSCALL_ARGS(); \ + return __syscall5_wrapper(module_inst, id, \ + args[0], args[1], args[2], \ + args[3], args[4]); \ + } + +EMCC_SYSCALL_WRAPPER0(199) + +EMCC_SYSCALL_WRAPPER1(6) + +EMCC_SYSCALL_WRAPPER2(183) + +EMCC_SYSCALL_WRAPPER3(3) +EMCC_SYSCALL_WRAPPER3(5) +EMCC_SYSCALL_WRAPPER3(54) +EMCC_SYSCALL_WRAPPER3(145) +EMCC_SYSCALL_WRAPPER3(146) +EMCC_SYSCALL_WRAPPER3(221) + +EMCC_SYSCALL_WRAPPER5(140) + +static int32 +getTotalMemory_wrapper(WASMModuleInstance *module_inst) +{ + WASMMemoryInstance *memory = module_inst->default_memory; + return NumBytesPerPage * memory->cur_page_count; +} + +static int32 +enlargeMemory_wrapper(WASMModuleInstance *module_inst) +{ + bool ret; + WASMMemoryInstance *memory = module_inst->default_memory; + uint32 DYNAMICTOP_PTR_offset = module_inst->DYNAMICTOP_PTR_offset; + uint32 addr_data_offset = *(uint32*)(memory->global_data + DYNAMICTOP_PTR_offset); + uint32 *DYNAMICTOP_PTR = (uint32*)(memory->memory_data + addr_data_offset); + uint32 memory_size_expected = *DYNAMICTOP_PTR; + uint32 total_page_count = (memory_size_expected + NumBytesPerPage - 1) / NumBytesPerPage; + + if (total_page_count < memory->cur_page_count) { + return 1; + } + else { + ret = wasm_runtime_enlarge_memory(module_inst, total_page_count - + memory->cur_page_count); + return ret ? 1 : 0; + } +} + +static void +_abort_wrapper(WASMModuleInstance *module_inst, int32 code) +{ + char buf[32]; + + snprintf(buf, sizeof(buf), "env.abort(%i)", code); + wasm_runtime_set_exception(module_inst, buf); +} + +static void +abortOnCannotGrowMemory_wrapper(WASMModuleInstance *module_inst) +{ + wasm_runtime_set_exception(module_inst, "abort on cannot grow memory"); +} + +static void +___setErrNo_wrapper(WASMModuleInstance *module_inst, int32 error_no) +{ + errno = error_no; +} + +/* TODO: add function parameter/result types check */ +#define REG_NATIVE_FUNC(module_name, func_name) \ + {#module_name, #func_name, func_name##_wrapper} + +typedef struct WASMNativeFuncDef { + const char *module_name; + const char *func_name; + void *func_ptr; +} WASMNativeFuncDef; + +static WASMNativeFuncDef native_func_defs[] = { + REG_NATIVE_FUNC(env, __syscall0), + REG_NATIVE_FUNC(env, __syscall1), + REG_NATIVE_FUNC(env, __syscall2), + REG_NATIVE_FUNC(env, __syscall3), + REG_NATIVE_FUNC(env, __syscall4), + REG_NATIVE_FUNC(env, __syscall5), + REG_NATIVE_FUNC(env, ___syscall3), + REG_NATIVE_FUNC(env, ___syscall5), + REG_NATIVE_FUNC(env, ___syscall6), + REG_NATIVE_FUNC(env, ___syscall54), + REG_NATIVE_FUNC(env, ___syscall140), + REG_NATIVE_FUNC(env, ___syscall145), + REG_NATIVE_FUNC(env, ___syscall146), + REG_NATIVE_FUNC(env, ___syscall183), + REG_NATIVE_FUNC(env, ___syscall199), + REG_NATIVE_FUNC(env, ___syscall221), + REG_NATIVE_FUNC(env, _abort), + REG_NATIVE_FUNC(env, abortOnCannotGrowMemory), + REG_NATIVE_FUNC(env, enlargeMemory), + REG_NATIVE_FUNC(env, getTotalMemory), + REG_NATIVE_FUNC(env, ___setErrNo), +}; + +void* +wasm_platform_native_func_lookup(const char *module_name, + const char *func_name) +{ + uint32 size = sizeof(native_func_defs) / sizeof(WASMNativeFuncDef); + WASMNativeFuncDef *func_def = native_func_defs; + WASMNativeFuncDef *func_def_end = func_def + size; + + if (!module_name || !func_name) + return NULL; + + while (func_def < func_def_end) { + if (!strcmp(func_def->module_name, module_name) + && !strcmp(func_def->func_name, func_name)) + return (void*)(uintptr_t)func_def->func_ptr; + func_def++; + } + + return NULL; +} + diff --git a/core/iwasm/runtime/platform/linux/wasm_native.c b/core/iwasm/runtime/platform/linux/wasm_native.c index c12e85c75..638f57344 100644 --- a/core/iwasm/runtime/platform/linux/wasm_native.c +++ b/core/iwasm/runtime/platform/linux/wasm_native.c @@ -35,9 +35,6 @@ #include -#define get_module_inst() \ - wasm_runtime_get_current_module_inst() - #define validate_app_addr(offset, size) \ wasm_runtime_validate_app_addr(module_inst, offset, size) @@ -55,46 +52,46 @@ static int32 -__syscall0_wrapper(int32 arg0) +__syscall0_wrapper(WASMModuleInstance *module_inst, int32 arg0) { switch (arg0) { case 199: /* getuid */ /* TODO */ default: - printf("##_syscall0 called, syscall id: %d\n", arg0); + bh_printf("##_syscall0 called, syscall id: %d\n", arg0); } return 0; } static int32 -__syscall1_wrapper(int32 arg0, int32 arg1) +__syscall1_wrapper(WASMModuleInstance *module_inst, int32 arg0, int32 arg1) { switch (arg0) { case 6: /* close */ /* TODO */ default: - printf("##_syscall1 called, syscall id: %d\n", arg0); + bh_printf("##_syscall1 called, syscall id: %d\n", arg0); } return 0; } static int32 -__syscall2_wrapper(int32 arg0, int32 arg1, int32 arg2) +__syscall2_wrapper(WASMModuleInstance *module_inst, + int32 arg0, int32 arg1, int32 arg2) { switch (arg0) { case 183: /* getcwd */ /* TODO */ default: - printf("##_syscall2 called, syscall id: %d\n", arg0); + bh_printf("##_syscall2 called, syscall id: %d\n", arg0); } return 0; } static int32 -__syscall3_wrapper(int32 arg0, int32 arg1, int32 arg2, int32 arg3) +__syscall3_wrapper(WASMModuleInstance *module_inst, + int32 arg0, int32 arg1, int32 arg2, int32 arg3) { - WASMModuleInstance *module_inst = get_module_inst(); - switch (arg0) { case 54: /* ioctl */ { @@ -152,73 +149,83 @@ __syscall3_wrapper(int32 arg0, int32 arg1, int32 arg2, int32 arg3) case 221: /* fcntl */ /* TODO */ default: - printf("##_syscall3 called, syscall id: %d\n", arg0); + bh_printf("##_syscall3 called, syscall id: %d\n", arg0); } return 0; } static int32 -__syscall4_wrapper(int32 arg0, int32 arg1, int32 arg2, +__syscall4_wrapper(WASMModuleInstance *module_inst, + int32 arg0, int32 arg1, int32 arg2, int32 arg3, int32 arg4) { - printf("##_syscall4 called, syscall id: %d\n", arg0); + bh_printf("##_syscall4 called, syscall id: %d\n", arg0); return 0; } static int32 -__syscall5_wrapper(int32 arg0, int32 arg1, int32 arg2, +__syscall5_wrapper(WASMModuleInstance *module_inst, + int32 arg0, int32 arg1, int32 arg2, int32 arg3, int32 arg4, int32 arg5) { switch (arg0) { case 140: /* llseek */ /* TODO */ default: - printf("##_syscall5 called, args[0]: %d\n", arg0); + bh_printf("##_syscall5 called, args[0]: %d\n", arg0); } return 0; } #define GET_EMCC_SYSCALL_ARGS() \ - WASMModuleInstance *module_inst = get_module_inst(); \ int32 *args; \ if (!validate_app_addr(args_off, 1)) \ return 0; \ args = addr_app_to_native(args_off) \ -#define EMCC_SYSCALL_WRAPPER0(id) \ - static int32 ___syscall##id##_wrapper(int32 _id) { \ - return __syscall0_wrapper(id); \ +#define EMCC_SYSCALL_WRAPPER0(id) \ + static int32 ___syscall##id##_wrapper(WASMModuleInstance *module_inst,\ + int32 _id) { \ + return __syscall0_wrapper(module_inst, id); \ } -#define EMCC_SYSCALL_WRAPPER1(id) \ - static int32 ___syscall##id##_wrapper(int32 _id, int32 args_off) {\ - GET_EMCC_SYSCALL_ARGS(); \ - return __syscall1_wrapper(id, args[0]); \ +#define EMCC_SYSCALL_WRAPPER1(id) \ + static int32 ___syscall##id##_wrapper(WASMModuleInstance *module_inst,\ + int32 _id, int32 args_off) { \ + GET_EMCC_SYSCALL_ARGS(); \ + return __syscall1_wrapper(module_inst, id, args[0]); \ } -#define EMCC_SYSCALL_WRAPPER2(id) \ - static int32 ___syscall##id##_wrapper(int32 _id, int32 args_off) {\ - GET_EMCC_SYSCALL_ARGS(); \ - return __syscall2_wrapper(id, args[0], args[1]); \ +#define EMCC_SYSCALL_WRAPPER2(id) \ + static int32 ___syscall##id##_wrapper(WASMModuleInstance *module_inst,\ + int32 _id, int32 args_off){ \ + GET_EMCC_SYSCALL_ARGS(); \ + return __syscall2_wrapper(module_inst, id, args[0], args[1]); \ } -#define EMCC_SYSCALL_WRAPPER3(id) \ - static int32 ___syscall##id##_wrapper(int32 _id, int32 args_off) {\ - GET_EMCC_SYSCALL_ARGS(); \ - return __syscall3_wrapper(id, args[0], args[1], args[2]); \ +#define EMCC_SYSCALL_WRAPPER3(id) \ + static int32 ___syscall##id##_wrapper(WASMModuleInstance *module_inst,\ + int32 _id, int32 args_off) { \ + GET_EMCC_SYSCALL_ARGS(); \ + return __syscall3_wrapper(module_inst, id, \ + args[0], args[1], args[2]); \ } -#define EMCC_SYSCALL_WRAPPER4(id) \ - static int32 ___syscall##id##_wrapper(int32 _id, int32 args_off) {\ - GET_EMCC_SYSCALL_ARGS(); \ - return __syscall4_wrapper(id, args[0], args[1], args[2], args[3]);\ +#define EMCC_SYSCALL_WRAPPER4(id) \ + static int32 ___syscall##id##_wrapper(WASMModuleInstance *module_inst,\ + int32 _id, int32 args_off) { \ + GET_EMCC_SYSCALL_ARGS(); \ + return __syscall4_wrapper(module_inst, id, \ + args[0], args[1], args[2], args[3]); \ } -#define EMCC_SYSCALL_WRAPPER5(id) \ - static int32 ___syscall##id##_wrapper(int32 _id, int32 args_off) {\ - GET_EMCC_SYSCALL_ARGS(); \ - return __syscall5_wrapper(id, args[0], args[1], args[2], \ - args[3], args[4]); \ +#define EMCC_SYSCALL_WRAPPER5(id) \ + static int32 ___syscall##id##_wrapper(WASMModuleInstance *module_inst,\ + int32 _id, int32 args_off) { \ + GET_EMCC_SYSCALL_ARGS(); \ + return __syscall5_wrapper(module_inst, id, \ + args[0], args[1], args[2], \ + args[3], args[4]); \ } EMCC_SYSCALL_WRAPPER0(199) @@ -237,18 +244,16 @@ EMCC_SYSCALL_WRAPPER3(221) EMCC_SYSCALL_WRAPPER5(140) static int32 -getTotalMemory_wrapper() +getTotalMemory_wrapper(WASMModuleInstance *module_inst) { - WASMModuleInstance *module_inst = wasm_runtime_get_current_module_inst(); WASMMemoryInstance *memory = module_inst->default_memory; return NumBytesPerPage * memory->cur_page_count; } static int32 -enlargeMemory_wrapper() +enlargeMemory_wrapper(WASMModuleInstance *module_inst) { bool ret; - WASMModuleInstance *module_inst = wasm_runtime_get_current_module_inst(); WASMMemoryInstance *memory = module_inst->default_memory; uint32 DYNAMICTOP_PTR_offset = module_inst->DYNAMICTOP_PTR_offset; uint32 addr_data_offset = *(uint32*)(memory->global_data + DYNAMICTOP_PTR_offset); @@ -267,9 +272,8 @@ enlargeMemory_wrapper() } static void -_abort_wrapper(int32 code) +_abort_wrapper(WASMModuleInstance *module_inst, int32 code) { - WASMModuleInstance *module_inst = wasm_runtime_get_current_module_inst(); char buf[32]; snprintf(buf, sizeof(buf), "env.abort(%i)", code); @@ -277,14 +281,13 @@ _abort_wrapper(int32 code) } static void -abortOnCannotGrowMemory_wrapper() +abortOnCannotGrowMemory_wrapper(WASMModuleInstance *module_inst) { - WASMModuleInstance *module_inst = wasm_runtime_get_current_module_inst(); wasm_runtime_set_exception(module_inst, "abort on cannot grow memory"); } static void -___setErrNo_wrapper(int32 error_no) +___setErrNo_wrapper(WASMModuleInstance *module_inst, int32 error_no) { errno = error_no; } diff --git a/core/iwasm/runtime/vmcore-wasm/invokeNative_arm.s b/core/iwasm/runtime/vmcore-wasm/invokeNative_arm.s new file mode 100644 index 000000000..10f6b591d --- /dev/null +++ b/core/iwasm/runtime/vmcore-wasm/invokeNative_arm.s @@ -0,0 +1,75 @@ +/* + * Copyright (C) 2019 Intel Corporation. All rights reserved. + * + * Licensed 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. + */ + .text + .align 2 + .global invokeNative + .type invokeNative,function + +/* + * Arguments passed in: + * + * r0 argv + * r1 argc + * r2 function pntr + */ + +invokeNative: + stmfd sp!, {r4, r5, r6, r7, lr} + mov r4, r0 /* get argv */ + mov r5, r1 /* get argc */ + mov ip, r2 /* get function ptr */ + + cmp r5, #2 /* is argc < 2 ? */ + blt return + + ldr r0, [r4], #4 /* argv[0] */ + ldr r1, [r4], #4 /* argv[1] */ + + mov r6, #0 + + cmp r5, #2 + beq call_func + ldr r2, [r4], #4 + cmp r5, #3 + beq call_func + ldr r3, [r4], #4 + + subs r5, r5, #4 /* now we have r0 ~ r3 */ + + /* Ensure address is 8 byte aligned */ + mov r6, r5, lsl#2 + add r6, r6, #7 + bic r6, r6, #7 + add r6, r6, #4 /* +4 because only odd(5) registers are in stack */ + subs sp, sp, r6 /* for stacked args */ + mov r7, sp + +loop_args: + cmp r5, #0 + beq call_func + ldr lr, [r4], #4 + str lr, [r7], #4 + subs r5, r5, #1 + b loop_args + +call_func: + blx ip + + add sp, sp, r6 /* recover sp */ + +return: + ldmfd sp!, {r4, r5, r6, r7, lr} + bx lr diff --git a/core/iwasm/runtime/vmcore-wasm/invokeNative_em64.s b/core/iwasm/runtime/vmcore-wasm/invokeNative_em64.s new file mode 100644 index 000000000..d4c922f65 --- /dev/null +++ b/core/iwasm/runtime/vmcore-wasm/invokeNative_em64.s @@ -0,0 +1,72 @@ +// 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. +// +// Author: Ivan Volosyuk +// + .text + .align 2 +.globl invokeNative + .type invokeNative, @function +invokeNative: + /* rdi - memory */ + /* rsi - n fp args */ + /* rdx - n mem args */ + /* rcx - function ptr */ + + push %rbp + mov %rsp, %rbp + + /* cycle to fill all fp args */ + movq 8(%rdi), %xmm0 + movq 16(%rdi), %xmm1 + movq 24(%rdi), %xmm2 + movq 32(%rdi), %xmm3 + movq 40(%rdi), %xmm4 + movq 48(%rdi), %xmm5 + movq 56(%rdi), %xmm6 + movq 64(%rdi), %xmm7 + + mov %rsp, %r10 /* Check that stack is aligned on */ + and $8, %r10 /* 16 bytes. This code may be removed */ + jz no_abort /* when we are sure that compiler always */ + int3 /* calls us with aligned stack */ +no_abort: + mov %rdx, %r10 /* Align stack on 16 bytes before pushing */ + and $1, %r10 /* stack arguments in case we have an odd */ + shl $3, %r10 /* number of stack arguments */ + sub %r10, %rsp + /* store memory args */ + movq %rcx, %r10 /* func ptr */ + movq %rdx, %rcx /* counter */ + lea 8+64+48-8(%rdi,%rcx,8), %rdx + sub %rsp, %rdx + cmpq $0, %rcx + jz cycle_end +cycle: + push 0(%rsp,%rdx) + loop cycle +cycle_end: + movq 80(%rdi), %rsi + movq 88(%rdi), %rdx + movq 96(%rdi), %rcx + movq 104(%rdi), %r8 + movq 112(%rdi), %r9 + + movq 72(%rdi), %rdi + + call *%r10 + leave + ret + diff --git a/core/iwasm/runtime/vmcore-wasm/invokeNative_mips.s b/core/iwasm/runtime/vmcore-wasm/invokeNative_mips.s new file mode 100644 index 000000000..bf1ad5965 --- /dev/null +++ b/core/iwasm/runtime/vmcore-wasm/invokeNative_mips.s @@ -0,0 +1,85 @@ +/* + * Copyright (C) 2019 Intel Corporation. All rights reserved. + * + * Licensed 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. + */ + + .text + .align 2 + .globl invokeNative + .ent invokeNative + .type invokeNative, @function + +/** + * On function entry parameters: + * $4 = args + * $5 = arg_num + * $6 = func_ptr + */ + +invokeNative: + .frame $fp, 8, $0 + .mask 0x00000000, 0 + .fmask 0x00000000, 0 + + /* Fixed part of frame */ + subu $sp, 8 + + /* save registers */ + sw $31, 4($sp) + sw $fp, 0($sp) + + /* set frame pointer to bottom of fixed frame */ + move $fp, $sp + + /* allocate enough stack space */ + sll $11, $5, 2 + subu $sp, $11 + + /* make 8-byte aligned */ + and $sp, ~7 + + move $9, $sp + move $25, $6 /* $25 = func_ptr */ + +push_args: + beq $5, 0, done /* arg_num == 0 ? */ + lw $8, 0($4) + sw $8, 0($9) + addu $4, 4 + addu $9, 4 + subu $5, 1 /* arg_index-- */ + j push_args + +done: + lw $4, 0($sp) /* Load $4..$7 from stack */ + lw $5, 4($sp) + lw $6, 8($sp) + lw $7, 12($sp) + ldc1 $f12, 0($sp) /* Load $f12, $f13, $f14, $f15 */ + ldc1 $f14, 8($sp) + + jalr $25 /* call function */ + + nop + + /* restore saved registers */ + move $sp, $fp + lw $31, 4($sp) + lw $fp, 0($sp) + + /* pop frame */ + addu $sp, $sp, 8 + + j $31 + .end invokeNative diff --git a/core/iwasm/runtime/vmcore-wasm/vmcore.cmake b/core/iwasm/runtime/vmcore-wasm/vmcore.cmake index 8e3d94ca9..7af218ee6 100644 --- a/core/iwasm/runtime/vmcore-wasm/vmcore.cmake +++ b/core/iwasm/runtime/vmcore-wasm/vmcore.cmake @@ -17,11 +17,13 @@ set (VMCORE_LIB_DIR ${CMAKE_CURRENT_LIST_DIR}) include_directories(${VMCORE_LIB_DIR}) include_directories(${VMCORE_LIB_DIR}/../include) +file (GLOB_RECURSE c_source_all ${VMCORE_LIB_DIR}/*.c) +list (REMOVE_ITEM c_source_all ${VMCORE_LIB_DIR}/invokeNative_general.c) + if (${BUILD_AS_64BIT_SUPPORT} STREQUAL "YES") -file (GLOB_RECURSE source_all ${VMCORE_LIB_DIR}/*.c) +set (source_all ${c_source_all} ${VMCORE_LIB_DIR}/invokeNative_em64.s) else () -file (GLOB_RECURSE source_all ${VMCORE_LIB_DIR}/*.c ${VMCORE_LIB_DIR}/*.s) -list (REMOVE_ITEM source_all ${VMCORE_LIB_DIR}/invokeNative_general.c) +set (source_all ${c_source_all} ${VMCORE_LIB_DIR}/invokeNative_ia32.s) endif () set (VMCORE_LIB_SOURCE ${source_all}) diff --git a/core/iwasm/runtime/vmcore-wasm/wasm_application.c b/core/iwasm/runtime/vmcore-wasm/wasm_application.c index 5073ef2e3..d3aef0c6d 100644 --- a/core/iwasm/runtime/vmcore-wasm/wasm_application.c +++ b/core/iwasm/runtime/vmcore-wasm/wasm_application.c @@ -18,6 +18,7 @@ #include #include #include "wasm.h" +#include "wasm_application.h" #include "wasm_interp.h" #include "wasm_runtime.h" #include "wasm_thread.h" @@ -293,10 +294,15 @@ wasm_application_execute_func(WASMModuleInstance *module_inst, break; case VALUE_TYPE_I64: { + char buf[16]; union { uint64 val; uint32 parts[2]; } u; u.parts[0] = argv1[0]; u.parts[1] = argv1[1]; - wasm_printf("0x%llx:i64", u.val); + if (sizeof(long) == 4) + snprintf(buf, sizeof(buf), "%s", "0x%llx:i64"); + else + snprintf(buf, sizeof(buf), "%s", "0x%lx:i64"); + wasm_printf(buf, u.val); break; } case VALUE_TYPE_F32: diff --git a/core/iwasm/runtime/vmcore-wasm/wasm_interp.c b/core/iwasm/runtime/vmcore-wasm/wasm_interp.c index 73163f32c..d4afabe5e 100644 --- a/core/iwasm/runtime/vmcore-wasm/wasm_interp.c +++ b/core/iwasm/runtime/vmcore-wasm/wasm_interp.c @@ -74,6 +74,24 @@ GET_F64_FROM_ADDR (uint32 *addr) } #endif /* WASM_CPU_SUPPORTS_UNALIGNED_64BIT_ACCESS != 0 */ +#if WASM_ENABLE_EXT_MEMORY_SPACE != 0 +#define CHECK_EXT_MEMORY_SPACE() \ + else if (module->ext_mem_data \ + && module->ext_mem_base_offset <= offset1 \ + && offset1 < module->ext_mem_base_offset \ + + module->ext_mem_size) { \ + maddr = module->ext_mem_data \ + + (offset1 - module->ext_mem_base_offset); \ + if (maddr < module->ext_mem_data) \ + goto out_of_bounds; \ + maddr1 = maddr + LOAD_SIZE[opcode - WASM_OP_I32_LOAD]; \ + if (maddr1 > module->ext_mem_data_end) \ + goto out_of_bounds; \ + } +#else +#define CHECK_EXT_MEMORY_SPACE() +#endif + #define CHECK_MEMORY_OVERFLOW() do { \ uint32 offset1 = offset + addr; \ uint8 *maddr1; \ @@ -89,7 +107,8 @@ GET_F64_FROM_ADDR (uint32 *addr) if (maddr1 > memory->end_addr) \ goto out_of_bounds; \ } \ - else { \ + else if (offset1 < memory->heap_base_offset \ + + (memory->heap_data_end - memory->heap_data)) { \ maddr = memory->heap_data + offset1 - memory->heap_base_offset; \ if (maddr < memory->heap_data) \ goto out_of_bounds; \ @@ -97,6 +116,9 @@ GET_F64_FROM_ADDR (uint32 *addr) if (maddr1 > memory->heap_data_end) \ goto out_of_bounds; \ } \ + CHECK_EXT_MEMORY_SPACE() \ + else \ + goto out_of_bounds; \ } while (0) static inline uint32 @@ -262,7 +284,7 @@ read_leb(const uint8 *buf, uint32 *p_offset, uint32 maxbits, bool sign) } if (sign && (shift < maxbits) && (byte & 0x40)) { /* Sign extend */ - result |= - (1 << shift); + result |= - ((uint64)1 << shift); } return result; } @@ -588,7 +610,7 @@ ALLOC_FRAME(WASMThread *self, uint32 size, WASMInterpFrame *prev_frame) frame->prev_frame = prev_frame; else { wasm_runtime_set_exception(self->module_inst, - "WASM interp failed, alloc frame failed."); + "WASM interp failed: stack overflow."); } return frame; @@ -600,21 +622,6 @@ FREE_FRAME(WASMThread *self, WASMInterpFrame *frame) wasm_thread_free_wasm_frame(self, frame); } -typedef void (*GenericFunctionPointer)(); -int64 invokeNative(uint32 *args, uint32 sz, GenericFunctionPointer f); - -typedef float64 (*Float64FuncPtr)(uint32*, uint32, GenericFunctionPointer); -typedef float32 (*Float32FuncPtr)(uint32*, uint32, GenericFunctionPointer); -typedef int64 (*Int64FuncPtr)(uint32*, uint32, GenericFunctionPointer); -typedef int32 (*Int32FuncPtr)(uint32*, uint32, GenericFunctionPointer); -typedef void (*VoidFuncPtr)(uint32*, uint32, GenericFunctionPointer); - -static Int64FuncPtr invokeNative_Int64 = (Int64FuncPtr)invokeNative; -static Int32FuncPtr invokeNative_Int32 = (Int32FuncPtr)invokeNative; -static Float64FuncPtr invokeNative_Float64 = (Float64FuncPtr)invokeNative; -static Float32FuncPtr invokeNative_Float32 = (Float32FuncPtr)invokeNative; -static VoidFuncPtr invokeNative_Void = (VoidFuncPtr)invokeNative; - static void wasm_interp_call_func_native(WASMThread *self, WASMFunctionInstance *cur_func, @@ -622,9 +629,8 @@ wasm_interp_call_func_native(WASMThread *self, { unsigned local_cell_num = 2; WASMInterpFrame *frame; - typedef void (*F)(WASMThread*, uint32 *argv); - union { F f; void *v; } u; - uint32 argv_buf[32], *argv, argc = cur_func->param_cell_num; + uint32 argv_ret[2]; + bool ret; if (!(frame = ALLOC_FRAME (self, wasm_interp_interp_frame_size(local_cell_num), prev_frame))) @@ -636,60 +642,24 @@ wasm_interp_call_func_native(WASMThread *self, wasm_thread_set_cur_frame (self, frame); - if (argc <= 32) - argv = argv_buf; - else { - if (!(argv = wasm_malloc(sizeof(uint32) * argc))) { - wasm_runtime_set_exception(self->module_inst, - "WASM call native failed: alloc memory for argv failed."); - return; - } - } + ret = wasm_runtime_invoke_native(cur_func->u.func_import->func_ptr_linked, + cur_func->u.func_import->func_type, + self->module_inst, + frame->lp, cur_func->param_cell_num, argv_ret); - word_copy(argv, frame->lp, argc); - - u.v = cur_func->u.func_import->func_ptr_linked; - { - WASMType *func_type = cur_func->u.func_import->func_type; - uint8 ret_type = func_type->result_count - ? func_type->types[func_type->param_count] - : VALUE_TYPE_VOID; - GenericFunctionPointer f = (GenericFunctionPointer)(uintptr_t)u.v; - - if (func_type->result_count == 0) { - invokeNative_Void(argv, argc, f); - } - else { - switch (ret_type) { - case VALUE_TYPE_I32: - argv[0] = invokeNative_Int32(argv, argc, f); - break; - case VALUE_TYPE_I64: - PUT_I64_TO_ADDR(argv, invokeNative_Int64(argv, argc, f)); - break; - case VALUE_TYPE_F32: - *(float32*)argv = invokeNative_Float32(argv, argc, f); - break; - case VALUE_TYPE_F64: - PUT_F64_TO_ADDR(argv, invokeNative_Float64(argv, argc, f)); - break; - } - } - } + if (!ret) + return; if (cur_func->ret_cell_num == 1) { - prev_frame->sp[0] = argv[0]; + prev_frame->sp[0] = argv_ret[0]; prev_frame->sp++; } else if (cur_func->ret_cell_num == 2) { - prev_frame->sp[0] = argv[0]; - prev_frame->sp[1] = argv[1]; + prev_frame->sp[0] = argv_ret[0]; + prev_frame->sp[1] = argv_ret[1]; prev_frame->sp += 2; } - if (argc > 32) - wasm_free(argv); - FREE_FRAME(self, frame); wasm_thread_set_cur_frame(self, prev_frame); } @@ -731,7 +701,7 @@ wasm_interp_call_func_bytecode(WASMThread *self, uint32 i, depth, cond, count, fidx, tidx, frame_size = 0, all_cell_num = 0; int32 didx, val; uint8 *else_addr, *end_addr; - uint8 *maddr; + uint8 *maddr = NULL; #if WASM_ENABLE_LABELS_AS_VALUES != 0 #define HANDLE_OPCODE(op) &&HANDLE_##op @@ -768,7 +738,7 @@ wasm_interp_call_func_bytecode(WASMThread *self, BLOCK_TYPE_BLOCK, &else_addr, &end_addr, NULL, 0)) { - wasm_runtime_set_exception(module, "find block addr failed"); + wasm_runtime_set_exception(module, "find block address failed"); goto got_exception; } @@ -783,7 +753,7 @@ wasm_interp_call_func_bytecode(WASMThread *self, BLOCK_TYPE_LOOP, &else_addr, &end_addr, NULL, 0)) { - wasm_runtime_set_exception(module, "find block addr failed"); + wasm_runtime_set_exception(module, "find block address failed"); goto got_exception; } @@ -798,7 +768,7 @@ wasm_interp_call_func_bytecode(WASMThread *self, BLOCK_TYPE_IF, &else_addr, &end_addr, NULL, 0)) { - wasm_runtime_set_exception(module, "find block addr failed"); + wasm_runtime_set_exception(module, "find block address failed"); goto got_exception; } @@ -855,8 +825,9 @@ wasm_interp_call_func_bytecode(WASMThread *self, depths = depth_buf; else { if (!(depths = wasm_malloc(sizeof(uint32) * count))) { - wasm_runtime_set_exception(module, "WASM interp failed, " - "alloc block memory for br_table failed."); + wasm_runtime_set_exception(module, + "WASM interp failed: " + "allocate memory failed."); goto got_exception; } } @@ -931,7 +902,7 @@ wasm_interp_call_func_bytecode(WASMThread *self, HANDLE_OP (WASM_OP_DROP): { wasm_runtime_set_exception(module, - "wasm interp failed: unsupported opcode"); + "WASM interp failed: unsupported opcode."); goto got_exception; } @@ -950,7 +921,7 @@ wasm_interp_call_func_bytecode(WASMThread *self, HANDLE_OP (WASM_OP_SELECT): { wasm_runtime_set_exception(module, - "wasm interp failed: unsupported opcode"); + "WASM interp failed: unsupported opcode."); goto got_exception; } @@ -997,7 +968,7 @@ wasm_interp_call_func_bytecode(WASMThread *self, break; default: wasm_runtime_set_exception(module, - "get local type is invalid"); + "invalid local type"); goto got_exception; } (void)local_count; @@ -1026,7 +997,7 @@ wasm_interp_call_func_bytecode(WASMThread *self, break; default: wasm_runtime_set_exception(module, - "set local type is invalid"); + "invalid local type"); goto got_exception; } (void)local_count; @@ -1054,7 +1025,7 @@ wasm_interp_call_func_bytecode(WASMThread *self, SET_LOCAL_F64(local_idx, GET_F64_FROM_ADDR(frame_sp - 2)); break; default: - wasm_runtime_set_exception(module, "tee local type is invalid"); + wasm_runtime_set_exception(module, "invalid local type"); goto got_exception; } (void)local_count; @@ -1085,7 +1056,7 @@ wasm_interp_call_func_bytecode(WASMThread *self, PUSH_F64(*(float64*)get_global_addr(memory, global)); break; default: - wasm_runtime_set_exception(module, "get global type is invalid"); + wasm_runtime_set_exception(module, "invalid global type"); goto got_exception; } HANDLE_OP_END (); @@ -1117,7 +1088,7 @@ wasm_interp_call_func_bytecode(WASMThread *self, PUT_F64_TO_ADDR((uint32*)global_addr, POP_F64()); break; default: - wasm_runtime_set_exception(module, "set global index is overflow"); + wasm_runtime_set_exception(module, "invalid global type"); goto got_exception; } HANDLE_OP_END (); @@ -1125,70 +1096,98 @@ wasm_interp_call_func_bytecode(WASMThread *self, /* memory load instructions */ HANDLE_OP (WASM_OP_I32_LOAD): - DEF_OP_LOAD(PUSH_I32(*(int32*)maddr)); - HANDLE_OP_END (); - HANDLE_OP (WASM_OP_I64_LOAD): - DEF_OP_LOAD(PUSH_I64(GET_I64_FROM_ADDR((uint32*)maddr))); - HANDLE_OP_END (); - HANDLE_OP (WASM_OP_F32_LOAD): - DEF_OP_LOAD(PUSH_F32(*(float32*)maddr)); - HANDLE_OP_END (); - HANDLE_OP (WASM_OP_F64_LOAD): - DEF_OP_LOAD(PUSH_F64(GET_F64_FROM_ADDR((uint32*)maddr))); - HANDLE_OP_END (); - HANDLE_OP (WASM_OP_I32_LOAD8_S): - DEF_OP_LOAD(PUSH_I32(sign_ext_8_32(*(int8*)maddr))); - HANDLE_OP_END (); - HANDLE_OP (WASM_OP_I32_LOAD8_U): - DEF_OP_LOAD(PUSH_I32((uint32)(*(uint8*)maddr))); - HANDLE_OP_END (); - HANDLE_OP (WASM_OP_I32_LOAD16_S): - DEF_OP_LOAD(PUSH_I32(sign_ext_16_32(*(int16*)maddr))); - HANDLE_OP_END (); - HANDLE_OP (WASM_OP_I32_LOAD16_U): - DEF_OP_LOAD(PUSH_I32((uint32)(*(uint16*)maddr))); - HANDLE_OP_END (); - HANDLE_OP (WASM_OP_I64_LOAD8_S): - DEF_OP_LOAD(PUSH_I64(sign_ext_8_64(*(int8*)maddr))); - HANDLE_OP_END (); - HANDLE_OP (WASM_OP_I64_LOAD8_U): - DEF_OP_LOAD(PUSH_I64((uint64)(*(uint8*)maddr))); - HANDLE_OP_END (); - HANDLE_OP (WASM_OP_I64_LOAD16_S): - DEF_OP_LOAD(PUSH_I64(sign_ext_16_64(*(int16*)maddr))); - HANDLE_OP_END (); - HANDLE_OP (WASM_OP_I64_LOAD16_U): - DEF_OP_LOAD(PUSH_I64((uint64)(*(uint16*)maddr))); - HANDLE_OP_END (); - HANDLE_OP (WASM_OP_I64_LOAD32_S): - DEF_OP_LOAD(PUSH_I64(sign_ext_32_64(*(int32*)maddr))); - HANDLE_OP_END (); - HANDLE_OP (WASM_OP_I64_LOAD32_U): - DEF_OP_LOAD(PUSH_I64((uint64)(*(uint32*)maddr))); - HANDLE_OP_END (); + { + uint32 offset, flags, addr; + GET_OPCODE(); + read_leb_uint32(frame_ip, frame_ip_end, flags); + read_leb_uint32(frame_ip, frame_ip_end, offset); + addr = POP_I32(); + CHECK_MEMORY_OVERFLOW(); +#if WASM_ENABLE_LABELS_AS_VALUES != 0 + static const void *handle_load_table[] = { + &&HANDLE_LOAD_WASM_OP_I32_LOAD, + &&HANDLE_LOAD_WASM_OP_I64_LOAD, + &&HANDLE_LOAD_WASM_OP_F32_LOAD, + &&HANDLE_LOAD_WASM_OP_F64_LOAD, + &&HANDLE_LOAD_WASM_OP_I32_LOAD8_S, + &&HANDLE_LOAD_WASM_OP_I32_LOAD8_U, + &&HANDLE_LOAD_WASM_OP_I32_LOAD16_S, + &&HANDLE_LOAD_WASM_OP_I32_LOAD16_U, + &&HANDLE_LOAD_WASM_OP_I64_LOAD8_S, + &&HANDLE_LOAD_WASM_OP_I64_LOAD8_U, + &&HANDLE_LOAD_WASM_OP_I64_LOAD16_S, + &&HANDLE_LOAD_WASM_OP_I64_LOAD16_U, + &&HANDLE_LOAD_WASM_OP_I64_LOAD32_S, + &&HANDLE_LOAD_WASM_OP_I64_LOAD32_U + }; + #define HANDLE_OP_LOAD(opcode) HANDLE_LOAD_##opcode + goto *handle_load_table[opcode - WASM_OP_I32_LOAD]; +#else + #define HANDLE_OP_LOAD(opcode) case opcode + switch (opcode) +#endif + { + HANDLE_OP_LOAD(WASM_OP_I32_LOAD): + PUSH_I32(*(int32*)maddr); + HANDLE_OP_END(); + HANDLE_OP_LOAD(WASM_OP_I64_LOAD): + PUSH_I64(GET_I64_FROM_ADDR((uint32*)maddr)); + HANDLE_OP_END(); + HANDLE_OP_LOAD(WASM_OP_F32_LOAD): + PUSH_F32(*(float32*)maddr); + HANDLE_OP_END(); + HANDLE_OP_LOAD(WASM_OP_F64_LOAD): + PUSH_F64(GET_F64_FROM_ADDR((uint32*)maddr)); + HANDLE_OP_END(); + HANDLE_OP_LOAD(WASM_OP_I32_LOAD8_S): + PUSH_I32(sign_ext_8_32(*(int8*)maddr)); + HANDLE_OP_END(); + HANDLE_OP_LOAD(WASM_OP_I32_LOAD8_U): + PUSH_I32((uint32)(*(uint8*)maddr)); + HANDLE_OP_END(); + HANDLE_OP_LOAD(WASM_OP_I32_LOAD16_S): + PUSH_I32(sign_ext_16_32(*(int16*)maddr)); + HANDLE_OP_END(); + HANDLE_OP_LOAD(WASM_OP_I32_LOAD16_U): + PUSH_I32((uint32)(*(uint16*)maddr)); + HANDLE_OP_END(); + HANDLE_OP_LOAD(WASM_OP_I64_LOAD8_S): + PUSH_I64(sign_ext_8_64(*(int8*)maddr)); + HANDLE_OP_END(); + HANDLE_OP_LOAD(WASM_OP_I64_LOAD8_U): + PUSH_I64((uint64)(*(uint8*)maddr)); + HANDLE_OP_END(); + HANDLE_OP_LOAD(WASM_OP_I64_LOAD16_S): + PUSH_I64(sign_ext_16_64(*(int16*)maddr)); + HANDLE_OP_END(); + HANDLE_OP_LOAD(WASM_OP_I64_LOAD16_U): + PUSH_I64((uint64)(*(uint16*)maddr)); + HANDLE_OP_END(); + HANDLE_OP_LOAD(WASM_OP_I64_LOAD32_S): + PUSH_I64(sign_ext_32_64(*(int32*)maddr)); + HANDLE_OP_END(); + HANDLE_OP_LOAD(WASM_OP_I64_LOAD32_U): + PUSH_I64((uint64)(*(uint32*)maddr)); + HANDLE_OP_END(); + } + (void)flags; + HANDLE_OP_END (); + } /* memory store instructions */ - HANDLE_OP (WASM_OP_I32_STORE): - DEF_OP_STORE(uint32, I32, *(int32*)maddr = sval); - HANDLE_OP_END (); - - HANDLE_OP (WASM_OP_I64_STORE): - DEF_OP_STORE(uint64, I64, PUT_I64_TO_ADDR((uint32*)maddr, sval)); - HANDLE_OP_END (); - HANDLE_OP (WASM_OP_F32_STORE): { uint32 offset, flags, addr; @@ -1218,25 +1217,63 @@ wasm_interp_call_func_bytecode(WASMThread *self, HANDLE_OP_END (); } + HANDLE_OP (WASM_OP_I32_STORE): HANDLE_OP (WASM_OP_I32_STORE8): - DEF_OP_STORE(uint32, I32, *(uint8*)maddr = (uint8)sval); - HANDLE_OP_END (); - HANDLE_OP (WASM_OP_I32_STORE16): - DEF_OP_STORE(uint32, I32, *(uint16*)maddr = (uint16)sval); - HANDLE_OP_END (); + { + uint32 offset, flags, addr; + uint32 sval; + GET_OPCODE(); + read_leb_uint32(frame_ip, frame_ip_end, flags); + read_leb_uint32(frame_ip, frame_ip_end, offset); + sval = POP_I32(); + addr = POP_I32(); + CHECK_MEMORY_OVERFLOW(); + switch (opcode) { + case WASM_OP_I32_STORE: + *(int32*)maddr = sval; + break; + case WASM_OP_I32_STORE8: + *(uint8*)maddr = (uint8)sval; + break; + case WASM_OP_I32_STORE16: + *(uint16*)maddr = (uint16)sval; + break; + } + (void)flags; + HANDLE_OP_END (); + } + HANDLE_OP (WASM_OP_I64_STORE): HANDLE_OP (WASM_OP_I64_STORE8): - DEF_OP_STORE(uint64, I64, *(uint8*)maddr = (uint8)sval); - HANDLE_OP_END (); - HANDLE_OP (WASM_OP_I64_STORE16): - DEF_OP_STORE(uint64, I64, *(uint16*)maddr = (uint16)sval); - HANDLE_OP_END (); - HANDLE_OP (WASM_OP_I64_STORE32): - DEF_OP_STORE(uint64, I64, *(uint32*)maddr = (uint32)sval); - HANDLE_OP_END (); + { + uint32 offset, flags, addr; + uint64 sval; + GET_OPCODE(); + read_leb_uint32(frame_ip, frame_ip_end, flags); + read_leb_uint32(frame_ip, frame_ip_end, offset); + sval = POP_I64(); + addr = POP_I32(); + CHECK_MEMORY_OVERFLOW(); + switch (opcode) { + case WASM_OP_I64_STORE: + PUT_I64_TO_ADDR((uint32*)maddr, sval); + break; + case WASM_OP_I64_STORE8: + *(uint8*)maddr = (uint8)sval; + break; + case WASM_OP_I64_STORE16: + *(uint16*)maddr = (uint16)sval; + break; + case WASM_OP_I64_STORE32: + *(uint32*)maddr = (uint32)sval; + break; + } + (void)flags; + HANDLE_OP_END (); + } /* memory size and memory grow instructions */ HANDLE_OP (WASM_OP_MEMORY_SIZE): @@ -1977,7 +2014,8 @@ wasm_interp_call_func_bytecode(WASMThread *self, #if WASM_ENABLE_LABELS_AS_VALUES == 0 default: - wasm_runtime_set_exception(module, "wasm interp failed: unsupported opcode"); + wasm_runtime_set_exception(module, + "WASM interp failed: unsupported opcode."); goto got_exception; } #endif @@ -2005,7 +2043,8 @@ wasm_interp_call_func_bytecode(WASMThread *self, HANDLE_OP (WASM_OP_UNUSED_0x26): HANDLE_OP (WASM_OP_UNUSED_0x27): { - wasm_runtime_set_exception(module, "wasm interp failed: unsupported opcode"); + wasm_runtime_set_exception(module, + "WASM interp failed: unsupported opcode."); goto got_exception; } #endif diff --git a/core/iwasm/runtime/vmcore-wasm/wasm_loader.c b/core/iwasm/runtime/vmcore-wasm/wasm_loader.c index 7b4733eff..8057f3805 100644 --- a/core/iwasm/runtime/vmcore-wasm/wasm_loader.c +++ b/core/iwasm/runtime/vmcore-wasm/wasm_loader.c @@ -72,7 +72,7 @@ read_leb(const uint8 *buf, const uint8 *buf_end, } if (sign && (shift < maxbits) && (byte & 0x40)) { /* Sign extend */ - result |= - (1 << shift); + result |= - ((uint64)1 << shift); } *p_result = result; return true; @@ -141,7 +141,8 @@ const_str_set_insert(const uint8 *str, int32 len, WASMModule *module, if (!c_str) { set_error_buf(error_buf, error_buf_size, - "WASM module load failed: alloc memory failed."); + "WASM module load failed: " + "allocate memory failed."); return NULL; } @@ -234,7 +235,7 @@ load_type_section(const uint8 *buf, const uint8 *buf_end, WASMModule *module, module->type_count = type_count; if (!(module->types = wasm_malloc(sizeof(WASMType*) * type_count))) { set_error_buf(error_buf, error_buf_size, - "Load type section failed: alloc memory failed."); + "Load type section failed: allocate memory failed."); return false; } @@ -256,13 +257,20 @@ load_type_section(const uint8 *buf, const uint8 *buf_end, WASMModule *module, CHECK_BUF(p, p_end, param_count); p += param_count; read_leb_uint32(p, p_end, result_count); - wasm_assert(result_count <= 1); + if (result_count > 1) { + set_error_buf(error_buf, error_buf_size, + "Load type section failed: invalid result count."); + return false; + } CHECK_BUF(p, p_end, result_count); p = p_org; if (!(type = module->types[i] = wasm_malloc(offsetof(WASMType, types) + - sizeof(uint8) * (param_count + result_count)))) + sizeof(uint8) * (param_count + result_count)))) { + set_error_buf(error_buf, error_buf_size, + "Load type section failed: allocate memory failed."); return false; + } /* Resolve param types and result types */ type->param_count = param_count; @@ -413,7 +421,7 @@ load_import_section(const uint8 *buf, const uint8 *buf_end, WASMModule *module, module->import_count = import_count; if (!(module->imports = wasm_malloc(sizeof(WASMImport) * import_count))) { set_error_buf(error_buf, error_buf_size, - "Load import section failed: alloc memory failed."); + "Load import section failed: allocate memory failed."); return false; } @@ -635,7 +643,7 @@ load_function_section(const uint8 *buf, const uint8 *buf_end, module->function_count = func_count; if (!(module->functions = wasm_malloc(sizeof(WASMFunction*) * func_count))) { set_error_buf(error_buf, error_buf_size, - "Load function section failed: alloc memory failed."); + "Load function section failed: allocate memory failed."); return false; } @@ -652,7 +660,8 @@ load_function_section(const uint8 *buf, const uint8 *buf_end, } read_leb_uint32(p_code, buf_code_end, code_size); - if (code_size == 0) { + if (code_size == 0 + || p_code + code_size > buf_code_end) { set_error_buf(error_buf, error_buf_size, "Load function section failed: " "invalid function code size."); @@ -678,7 +687,8 @@ load_function_section(const uint8 *buf, const uint8 *buf_end, if (!(func = module->functions[i] = wasm_malloc(total_size))) { set_error_buf(error_buf, error_buf_size, - "Load function section failed: alloc memory failed."); + "Load function section failed: " + "allocate memory failed."); return false; } @@ -696,7 +706,20 @@ load_function_section(const uint8 *buf, const uint8 *buf_end, local_type_index = 0; for (j = 0; j < local_set_count; j++) { read_leb_uint32(p_code, buf_code_end, sub_local_count); + if (local_type_index + sub_local_count <= local_type_index + || local_type_index + sub_local_count > local_count) { + set_error_buf(error_buf, error_buf_size, + "Load function section failed: " + "invalid local count."); + return false; + } read_leb_uint8(p_code, buf_code_end, type); + if (type < VALUE_TYPE_F64 || type > VALUE_TYPE_I32) { + set_error_buf(error_buf, error_buf_size, + "Load function section failed: " + "invalid local type."); + return false; + } for (k = 0; k < sub_local_count; k++) { func->local_types[local_type_index++] = type; } @@ -707,8 +730,8 @@ load_function_section(const uint8 *buf, const uint8 *buf_end, if (p != p_end) { set_error_buf(error_buf, error_buf_size, - "Load function section failed: " - "invalid section size."); + "Load function section failed: " + "invalid section size."); return false; } @@ -735,7 +758,8 @@ load_table_section(const uint8 *buf, const uint8 *buf_end, WASMModule *module, module->table_count = table_count; if (!(module->tables = wasm_malloc(sizeof(WASMTable) * table_count))) { set_error_buf(error_buf, error_buf_size, - "Load table section failed: alloc memory failed."); + "Load table section failed: " + "allocate memory failed."); return false; } @@ -777,7 +801,8 @@ load_memory_section(const uint8 *buf, const uint8 *buf_end, WASMModule *module, module->memory_count = memory_count; if (!(module->memories = wasm_malloc(sizeof(WASMMemory) * memory_count))) { set_error_buf(error_buf, error_buf_size, - "Load memory section failed: alloc memory failed."); + "Load memory section failed: " + "allocate memory failed."); return false; } @@ -814,7 +839,8 @@ load_global_section(const uint8 *buf, const uint8 *buf_end, WASMModule *module, module->global_count = global_count; if (!(module->globals = wasm_malloc(sizeof(WASMGlobal) * global_count))) { set_error_buf(error_buf, error_buf_size, - "Load global section failed: alloc memory failed."); + "Load global section failed: " + "allocate memory failed."); return false; } @@ -859,7 +885,8 @@ load_export_section(const uint8 *buf, const uint8 *buf_end, WASMModule *module, module->export_count = export_count; if (!(module->exports = wasm_malloc(sizeof(WASMExport) * export_count))) { set_error_buf(error_buf, error_buf_size, - "Load export section failed: alloc memory failed."); + "Load export section failed: " + "allocate memory failed."); return false; } @@ -952,7 +979,7 @@ load_table_segment_section(const uint8 *buf, const uint8 *buf_end, WASMModule *m (sizeof(WASMTableSeg) * table_segment_count))) { set_error_buf(error_buf, error_buf_size, "Load table segment section failed: " - "alloc memory failed."); + "allocate memory failed."); return false; } @@ -974,7 +1001,7 @@ load_table_segment_section(const uint8 *buf, const uint8 *buf_end, WASMModule *m wasm_malloc(sizeof(uint32) * function_count))) { set_error_buf(error_buf, error_buf_size, "Load table segment section failed: " - "alloc memory failed."); + "allocate memory failed."); return false; } for (j = 0; j < function_count; j++) { @@ -1012,8 +1039,8 @@ load_data_segment_section(const uint8 *buf, const uint8 *buf_end, if (!(module->data_segments = wasm_malloc(sizeof(WASMDataSeg*) * data_seg_count))) { set_error_buf(error_buf, error_buf_size, - "Load data segment section failed, " - "alloc memory failed."); + "Load data segment section failed: " + "allocate memory failed."); return false; } @@ -1031,7 +1058,7 @@ load_data_segment_section(const uint8 *buf, const uint8 *buf_end, wasm_malloc(sizeof(WASMDataSeg)))) { set_error_buf(error_buf, error_buf_size, "Load data segment section failed: " - "alloc memory failed."); + "allocate memory failed."); return false; } @@ -1117,12 +1144,6 @@ load_from_sections(WASMModule *module, WASMSection *sections, section = section->next; } - if (!buf_code) { - set_error_buf(error_buf, error_buf_size, - "WASM module load failed: find code section failed."); - return false; - } - section = sections; while (section) { buf = section->section_body; @@ -1140,8 +1161,13 @@ load_from_sections(WASMModule *module, WASMSection *sections, return false; break; case SECTION_TYPE_FUNC: + if (!buf_code) { + set_error_buf(error_buf, error_buf_size, + "WASM module load failed: find code section failed."); + return false; + } if (!load_function_section(buf, buf_end, buf_code, buf_code_end, - module, error_buf, error_buf_size)) + module, error_buf, error_buf_size)) return false; break; case SECTION_TYPE_TABLE: @@ -1229,7 +1255,8 @@ create_module(char *error_buf, uint32 error_buf_size) if (!module) { set_error_buf(error_buf, error_buf_size, - "WASM module load failed: alloc memory failed."); + "WASM module load failed: " + "allocate memory failed."); return NULL; } @@ -1309,7 +1336,8 @@ create_sections(const uint8 *buf, uint32 size, if (!(section = wasm_malloc(sizeof(WASMSection)))) { set_error_buf(error_buf, error_buf_size, - "WASM module load failed: alloc memory failed."); + "WASM module load failed: " + "allocate memory failed."); return false; } @@ -1401,7 +1429,7 @@ wasm_loader_load(const uint8 *buf, uint32 size, char *error_buf, uint32 error_bu if (!module) { set_error_buf(error_buf, error_buf_size, - "WASM module load failed: alloc memory failed."); + "WASM module load failed: allocate memory failed."); return NULL; } @@ -1855,9 +1883,11 @@ wasm_loader_find_block_addr(WASMModule *module, break; default: - LOG_ERROR("WASM loader find block addr failed: invalid opcode %02x.\n", - opcode); - break; + if (error_buf) + snprintf(error_buf, error_buf_size, + "WASM loader find block addr failed: " + "invalid opcode %02x.", opcode); + return false; } } @@ -1902,7 +1932,7 @@ memory_realloc(void *mem_old, uint32 size_old, uint32 size_new) if (!mem_new) { \ set_error_buf(error_buf, error_buf_size, \ "WASM loader prepare bytecode failed: " \ - "alloc memory failed"); \ + "allocate memory failed."); \ goto fail; \ } \ mem = mem_new; \ @@ -2201,6 +2231,24 @@ pop_type(uint8 type, uint8 **p_frame_ref, uint32 *p_stack_cell_num, } \ } while (0) +static bool +check_memory(WASMModule *module, + char *error_buf, uint32 error_buf_size) +{ + if (module->memory_count == 0 + && module->import_memory_count == 0) { + set_error_buf(error_buf, error_buf_size, + "load or store in module without default memory"); + return false; + } + return true; +} + +#define CHECK_MEMORY() do { \ + if (!check_memory(module, error_buf, error_buf_size)) \ + goto fail; \ + } while (0) + static bool wasm_loader_prepare_bytecode(WASMModule *module, WASMFunction *func, char *error_buf, uint32 error_buf_size) @@ -2235,7 +2283,8 @@ wasm_loader_prepare_bytecode(WASMModule *module, WASMFunction *func, frame_ref_size = 32; if (!(frame_ref_bottom = frame_ref = wasm_malloc(frame_ref_size))) { set_error_buf(error_buf, error_buf_size, - "WASM loader prepare bytecode failed: alloc memory failed"); + "WASM loader prepare bytecode failed: " + "allocate memory failed"); goto fail; } memset(frame_ref_bottom, 0, frame_ref_size); @@ -2244,7 +2293,8 @@ wasm_loader_prepare_bytecode(WASMModule *module, WASMFunction *func, frame_csp_size = sizeof(BranchBlock) * 8; if (!(frame_csp_bottom = frame_csp = wasm_malloc(frame_csp_size))) { set_error_buf(error_buf, error_buf_size, - "WASM loader prepare bytecode failed: alloc memory failed"); + "WASM loader prepare bytecode failed: " + "allocate memory failed"); goto fail; } @@ -2337,7 +2387,7 @@ wasm_loader_prepare_bytecode(WASMModule *module, WASMFunction *func, if (!block) { set_error_buf(error_buf, error_buf_size, "WASM loader prepare bytecode failed: " - "alloc memory failed"); + "allocate memory failed."); goto fail; } @@ -2350,7 +2400,7 @@ wasm_loader_prepare_bytecode(WASMModule *module, WASMFunction *func, block)) { set_error_buf(error_buf, error_buf_size, "WASM loader prepare bytecode failed: " - "alloc memory failed"); + "allocate memory failed."); wasm_free(block); goto fail; } @@ -2482,12 +2532,20 @@ handle_op_br: WASMType *func_type; uint32 type_idx; + if (module->table_count == 0 + && module->import_table_count == 0) { + set_error_buf(error_buf, error_buf_size, + "call indirect without default table"); + goto fail; + } + read_leb_uint32(p, p_end, type_idx); read_leb_uint8(p, p_end, u8); /* 0x00 */ POP_I32(); if (type_idx >= module->type_count) { - set_error_buf(error_buf, error_buf_size, "function index is overflow"); + set_error_buf(error_buf, error_buf_size, + "function index is overflow"); goto fail; } @@ -2618,6 +2676,7 @@ handle_op_br: case WASM_OP_I32_LOAD8_U: case WASM_OP_I32_LOAD16_S: case WASM_OP_I32_LOAD16_U: + CHECK_MEMORY(); read_leb_uint32(p, p_end, u32); /* align */ read_leb_uint32(p, p_end, u32); /* offset */ POP_I32(); @@ -2631,6 +2690,7 @@ handle_op_br: case WASM_OP_I64_LOAD16_U: case WASM_OP_I64_LOAD32_S: case WASM_OP_I64_LOAD32_U: + CHECK_MEMORY(); read_leb_uint32(p, p_end, u32); /* align */ read_leb_uint32(p, p_end, u32); /* offset */ POP_I32(); @@ -2638,6 +2698,7 @@ handle_op_br: break; case WASM_OP_F32_LOAD: + CHECK_MEMORY(); read_leb_uint32(p, p_end, u32); /* align */ read_leb_uint32(p, p_end, u32); /* offset */ POP_I32(); @@ -2645,6 +2706,7 @@ handle_op_br: break; case WASM_OP_F64_LOAD: + CHECK_MEMORY(); read_leb_uint32(p, p_end, u32); /* align */ read_leb_uint32(p, p_end, u32); /* offset */ POP_I32(); @@ -2654,6 +2716,7 @@ handle_op_br: case WASM_OP_I32_STORE: case WASM_OP_I32_STORE8: case WASM_OP_I32_STORE16: + CHECK_MEMORY(); read_leb_uint32(p, p_end, u32); /* align */ read_leb_uint32(p, p_end, u32); /* offset */ POP_I32(); @@ -2664,6 +2727,7 @@ handle_op_br: case WASM_OP_I64_STORE8: case WASM_OP_I64_STORE16: case WASM_OP_I64_STORE32: + CHECK_MEMORY(); read_leb_uint32(p, p_end, u32); /* align */ read_leb_uint32(p, p_end, u32); /* offset */ POP_I64(); @@ -2671,6 +2735,7 @@ handle_op_br: break; case WASM_OP_F32_STORE: + CHECK_MEMORY(); read_leb_uint32(p, p_end, u32); /* align */ read_leb_uint32(p, p_end, u32); /* offset */ POP_F32(); @@ -2678,6 +2743,7 @@ handle_op_br: break; case WASM_OP_F64_STORE: + CHECK_MEMORY(); read_leb_uint32(p, p_end, u32); /* align */ read_leb_uint32(p, p_end, u32); /* offset */ POP_F64(); @@ -2685,11 +2751,13 @@ handle_op_br: break; case WASM_OP_MEMORY_SIZE: + CHECK_MEMORY(); read_leb_uint32(p, p_end, u32); /* 0x00 */ PUSH_I32(); break; case WASM_OP_MEMORY_GROW: + CHECK_MEMORY(); read_leb_uint32(p, p_end, u32); /* 0x00 */ POP_I32(); PUSH_I32(); @@ -2971,15 +3039,24 @@ handle_op_br: break; default: - LOG_ERROR("WASM loader find block addr failed: invalid opcode %02x.\n", - opcode); - break; + if (error_buf != NULL) + snprintf(error_buf, error_buf_size, + "WASM module load failed: " + "invalid opcode %02x.", opcode); + goto fail; } if (opcode != WASM_OP_I32_CONST) is_i32_const = false; } + if (csp_num > 0) { + set_error_buf(error_buf, error_buf_size, + "WASM module load failed: " + "function body must end with END opcode."); + goto fail; + } + func->max_stack_cell_num = max_stack_cell_num; func->max_block_num = max_csp_num; return_value = true; diff --git a/core/iwasm/runtime/vmcore-wasm/wasm_runtime.c b/core/iwasm/runtime/vmcore-wasm/wasm_runtime.c index 7b1c65617..fc46f97d5 100644 --- a/core/iwasm/runtime/vmcore-wasm/wasm_runtime.c +++ b/core/iwasm/runtime/vmcore-wasm/wasm_runtime.c @@ -70,33 +70,41 @@ wasm_runtime_call_wasm(WASMModuleInstance *module_inst, WASMFunctionInstance *function, unsigned argc, uint32 argv[]) { - if (!exec_env) { - if (!module_inst->wasm_stack) { - if (!(module_inst->wasm_stack = - wasm_malloc(module_inst->wasm_stack_size))) { - wasm_runtime_set_exception(module_inst, "allocate memory failed."); - return false; + /* Only init stack when no application is running. */ + if (!wasm_runtime_get_self()->cur_frame) { + if (!exec_env) { + if (!module_inst->wasm_stack) { + if (!(module_inst->wasm_stack = + wasm_malloc(module_inst->wasm_stack_size))) { + wasm_runtime_set_exception(module_inst, + "allocate memory failed."); + return false; + } + + init_wasm_stack(&module_inst->main_tlr.wasm_stack, + module_inst->wasm_stack, + module_inst->wasm_stack_size); } - } + } + else { + uintptr_t stack = (uintptr_t)exec_env->stack; + uint32 stack_size; - init_wasm_stack(&module_inst->main_tlr.wasm_stack, - module_inst->wasm_stack, module_inst->wasm_stack_size); - } - else { - uintptr_t stack = (uintptr_t)exec_env->stack; - uint32 stack_size; + /* Set to 8 bytes align */ + stack = (stack + 7) & ~7; + stack_size = exec_env->stack_size + - (stack - (uintptr_t)exec_env->stack); - /* Set to 8 bytes align */ - stack = (stack + 7) & ~7; - stack_size = exec_env->stack_size - (stack - (uintptr_t)exec_env->stack); + if (!exec_env->stack || exec_env->stack_size <= 0 + || exec_env->stack_size < stack - (uintptr_t)exec_env->stack) { + wasm_runtime_set_exception(module_inst, + "Invalid execution stack info."); + return false; + } - if (!exec_env->stack || exec_env->stack_size <= 0 - || exec_env->stack_size < stack - (uintptr_t)exec_env->stack) { - wasm_runtime_set_exception(module_inst, "Invalid execution stack info."); - return false; - } - - init_wasm_stack(&module_inst->main_tlr.wasm_stack, (uint8*)stack, stack_size); + init_wasm_stack(&module_inst->main_tlr.wasm_stack, + (uint8*)stack, stack_size); + } } wasm_interp_call_wasm(function, argc, argv); @@ -877,8 +885,9 @@ wasm_runtime_instantiate(WASMModule *module, length = data_seg->data_length; memory_size = NumBytesPerPage * module_inst->default_memory->cur_page_count; - if (base_offset >= memory_size - || base_offset + length > memory_size) { + if (length > 0 + && (base_offset >= memory_size + || base_offset + length > memory_size)) { set_error_buf(error_buf, error_buf_size, "Instantiate module failed: data segment out of range."); wasm_runtime_deinstantiate(module_inst); @@ -946,18 +955,11 @@ wasm_runtime_instantiate(WASMModule *module, wasm_runtime_set_tlr(&module_inst->main_tlr); module_inst->main_tlr.handle = ws_self_thread(); - /* Execute __post_instantiate function */ - if (!execute_post_inst_function(module_inst)) { - const char *exception = wasm_runtime_get_exception(module_inst); - wasm_printf("%s\n", exception); - wasm_runtime_deinstantiate(module_inst); - return NULL; - } - - /* Execute start function */ - if (!execute_start_function(module_inst)) { - const char *exception = wasm_runtime_get_exception(module_inst); - wasm_printf("%s\n", exception); + /* Execute __post_instantiate and start function */ + if (!execute_post_inst_function(module_inst) + || !execute_start_function(module_inst)) { + set_error_buf(error_buf, error_buf_size, + module_inst->cur_exception); wasm_runtime_deinstantiate(module_inst); return NULL; } @@ -991,6 +993,37 @@ wasm_runtime_deinstantiate(WASMModuleInstance *module_inst) wasm_free(module_inst); } +#if WASM_ENABLE_EXT_MEMORY_SPACE != 0 +bool +wasm_runtime_set_ext_memory(WASMModuleInstance *module_inst, + uint8 *ext_mem_data, uint32 ext_mem_size, + char *error_buf, uint32 error_buf_size) +{ + if (module_inst->ext_mem_data) { + set_error_buf(error_buf, error_buf_size, + "Set external memory failed: " + "an external memory has been set."); + return false; + } + + if (!ext_mem_data + || ext_mem_size > 1 * BH_GB + || ext_mem_data + ext_mem_size < ext_mem_data) { + set_error_buf(error_buf, error_buf_size, + "Set external memory failed: " + "invalid input."); + return false; + } + + module_inst->ext_mem_data = ext_mem_data; + module_inst->ext_mem_data_end = ext_mem_data + ext_mem_size; + module_inst->ext_mem_size = ext_mem_size; + module_inst->ext_mem_base_offset = DEFAULT_EXT_MEM_BASE_OFFSET; + + return true; +} +#endif + bool wasm_runtime_enlarge_memory(WASMModuleInstance *module, int inc_page_count) { @@ -1165,24 +1198,40 @@ wasm_runtime_validate_app_addr(WASMModuleInstance *module_inst, uint8 *addr; /* integer overflow check */ - if(app_offset < 0 || - app_offset + size < app_offset) { + if(app_offset + size < app_offset) { goto fail; } memory = module_inst->default_memory; - if (app_offset < memory->heap_base_offset) { + if (0 <= app_offset + && app_offset < memory->heap_base_offset) { addr = memory->memory_data + app_offset; if (!(memory->base_addr <= addr && addr + size <= memory->end_addr)) goto fail; return true; } - else { + else if (memory->heap_base_offset < app_offset + && app_offset < memory->heap_base_offset + + (memory->heap_data_end - memory->heap_data)) { addr = memory->heap_data + (app_offset - memory->heap_base_offset); if (!(memory->heap_data <= addr && addr + size <= memory->heap_data_end)) goto fail; return true; } +#if WASM_ENABLE_EXT_MEMORY_SPACE != 0 + else if (module_inst->ext_mem_data + && module_inst->ext_mem_base_offset <= app_offset + && app_offset < module_inst->ext_mem_base_offset + + module_inst->ext_mem_size) { + addr = module_inst->ext_mem_data + + (app_offset - module_inst->ext_mem_base_offset); + if (!(module_inst->ext_mem_data <= addr + && addr + size <= module_inst->ext_mem_data_end)) + goto fail; + + return true; + } +#endif fail: wasm_runtime_set_exception(module_inst, "out of bounds memory access"); @@ -1201,7 +1250,13 @@ wasm_runtime_validate_native_addr(WASMModuleInstance *module_inst, } if ((memory->base_addr <= addr && addr + size <= memory->end_addr) - || (memory->heap_data <= addr && addr + size <= memory->heap_data_end)) + || (memory->heap_data <= addr && addr + size <= memory->heap_data_end) +#if WASM_ENABLE_EXT_MEMORY_SPACE != 0 + || (module_inst->ext_mem_data + && module_inst->ext_mem_data <= addr + && addr + size <= module_inst->ext_mem_data_end) +#endif + ) return true; fail: @@ -1214,10 +1269,22 @@ wasm_runtime_addr_app_to_native(WASMModuleInstance *module_inst, int32 app_offset) { WASMMemoryInstance *memory = module_inst->default_memory; - if (app_offset < memory->heap_base_offset) + if (0 <= app_offset && app_offset < memory->heap_base_offset) return memory->memory_data + app_offset; - else + else if (memory->heap_base_offset < app_offset + && app_offset < memory->heap_base_offset + + (memory->heap_data_end - memory->heap_data)) return memory->heap_data + (app_offset - memory->heap_base_offset); +#if WASM_ENABLE_EXT_MEMORY_SPACE != 0 + else if (module_inst->ext_mem_data + && module_inst->ext_mem_base_offset <= app_offset + && app_offset < module_inst->ext_mem_base_offset + + module_inst->ext_mem_size) + return module_inst->ext_mem_data + + (app_offset - module_inst->ext_mem_base_offset); +#endif + else + return NULL; } int32 @@ -1228,11 +1295,99 @@ wasm_runtime_addr_native_to_app(WASMModuleInstance *module_inst, if (memory->base_addr <= (uint8*)native_ptr && (uint8*)native_ptr < memory->end_addr) return (uint8*)native_ptr - memory->memory_data; - else + else if (memory->heap_data <= (uint8*)native_ptr + && (uint8*)native_ptr < memory->heap_data_end) return memory->heap_base_offset + ((uint8*)native_ptr - memory->heap_data); +#if WASM_ENABLE_EXT_MEMORY_SPACE != 0 + else if (module_inst->ext_mem_data + && module_inst->ext_mem_data <= (uint8*)native_ptr + && (uint8*)native_ptr < module_inst->ext_mem_data_end) + return module_inst->ext_mem_base_offset + + ((uint8*)native_ptr - module_inst->ext_mem_data); +#endif + else + return 0; } +bool +wasm_runtime_get_app_addr_range(WASMModuleInstance *module_inst, + int32 app_offset, + int32 *p_app_start_offset, + int32 *p_app_end_offset) +{ + int32 app_start_offset, app_end_offset; + WASMMemoryInstance *memory = module_inst->default_memory; + + if (0 <= app_offset && app_offset < memory->heap_base_offset) { + app_start_offset = 0; + app_end_offset = NumBytesPerPage * memory->cur_page_count; + } + else if (memory->heap_base_offset < app_offset + && app_offset < memory->heap_base_offset + + (memory->heap_data_end - memory->heap_data)) { + app_start_offset = memory->heap_base_offset; + app_end_offset = memory->heap_base_offset + + (memory->heap_data_end - memory->heap_data); + } +#if WASM_ENABLE_EXT_MEMORY_SPACE != 0 + else if (module_inst->ext_mem_data + && module_inst->ext_mem_base_offset <= app_offset + && app_offset < module_inst->ext_mem_base_offset + + module_inst->ext_mem_size) { + app_start_offset = module_inst->ext_mem_base_offset; + app_end_offset = app_start_offset + module_inst->ext_mem_size; + } +#endif + else + return false; + + if (p_app_start_offset) + *p_app_start_offset = app_start_offset; + if (p_app_end_offset) + *p_app_end_offset = app_end_offset; + return true; +} + +bool +wasm_runtime_get_native_addr_range(WASMModuleInstance *module_inst, + uint8 *native_ptr, + uint8 **p_native_start_addr, + uint8 **p_native_end_addr) +{ + uint8 *native_start_addr, *native_end_addr; + WASMMemoryInstance *memory = module_inst->default_memory; + + if (memory->base_addr <= (uint8*)native_ptr + && (uint8*)native_ptr < memory->end_addr) { + native_start_addr = memory->memory_data; + native_end_addr = memory->memory_data + + NumBytesPerPage * memory->cur_page_count; + } + else if (memory->heap_data <= (uint8*)native_ptr + && (uint8*)native_ptr < memory->heap_data_end) { + native_start_addr = memory->heap_data; + native_end_addr = memory->heap_data_end; + } +#if WASM_ENABLE_EXT_MEMORY_SPACE != 0 + else if (module_inst->ext_mem_data + && module_inst->ext_mem_data <= (uint8*)native_ptr + && (uint8*)native_ptr < module_inst->ext_mem_data_end) { + native_start_addr = module_inst->ext_mem_data; + native_end_addr = module_inst->ext_mem_data_end; + } +#endif + else + return false; + + if (p_native_start_addr) + *p_native_start_addr = native_start_addr; + if (p_native_end_addr) + *p_native_end_addr = native_end_addr; + return true; +} + + uint32 wasm_runtime_get_temp_ret(WASMModuleInstance *module_inst) { @@ -1272,3 +1427,248 @@ wasm_runtime_load_aot(uint8 *aot_file, uint32 aot_file_size, return NULL; } +static inline void +word_copy(uint32 *dest, uint32 *src, unsigned num) +{ + for (; num > 0; num--) + *dest++ = *src++; +} + +#define PUT_I64_TO_ADDR(addr, value) do { \ + union { int64 val; uint32 parts[2]; } u; \ + u.val = (value); \ + (addr)[0] = u.parts[0]; \ + (addr)[1] = u.parts[1]; \ + } while (0) + +#define PUT_F64_TO_ADDR(addr, value) do { \ + union { float64 val; uint32 parts[2]; } u; \ + u.val = (value); \ + (addr)[0] = u.parts[0]; \ + (addr)[1] = u.parts[1]; \ + } while (0) + +#if !defined(__x86_64__) && !defined(__amd_64__) + +typedef void (*GenericFunctionPointer)(); +int64 invokeNative(uint32 *args, uint32 sz, GenericFunctionPointer f); + +typedef float64 (*Float64FuncPtr)(uint32*, uint32, GenericFunctionPointer); +typedef float32 (*Float32FuncPtr)(uint32*, uint32, GenericFunctionPointer); +typedef int64 (*Int64FuncPtr)(uint32*, uint32, GenericFunctionPointer); +typedef int32 (*Int32FuncPtr)(uint32*, uint32, GenericFunctionPointer); +typedef void (*VoidFuncPtr)(uint32*, uint32, GenericFunctionPointer); + +static Int64FuncPtr invokeNative_Int64 = (Int64FuncPtr)invokeNative; +static Int32FuncPtr invokeNative_Int32 = (Int32FuncPtr)invokeNative; +static Float64FuncPtr invokeNative_Float64 = (Float64FuncPtr)invokeNative; +static Float32FuncPtr invokeNative_Float32 = (Float32FuncPtr)invokeNative; +static VoidFuncPtr invokeNative_Void = (VoidFuncPtr)invokeNative; + +/* As JavaScript can't represent int64s, emcc compiles C int64 argument + into two WASM i32 arguments, see: + https://github.com/emscripten-core/emscripten/issues/7199 + And also JavaScript float point is always 64-bit, emcc compiles + float32 argument into WASM f64 argument. + But clang compiles C int64 argument into WASM i64 argument, and + compiles C float32 argument into WASM f32 argument. + So for the compatability of emcc and clang, we treat i64 as two i32s, + treat f32 as f64 while passing arguments to the native function, and + require the native function uses two i32 arguments instead one i64 + argument, and uses double argument instead of float argment. */ + +bool +wasm_runtime_invoke_native(void *func_ptr, WASMType *func_type, + WASMModuleInstance *module_inst, + uint32 *argv, uint32 argc, uint32 *ret) +{ + union { float64 val; int32 parts[2]; } u; + uint32 argv_buf[32], *argv1 = argv_buf, argc1, i, j = 0; + uint64 size; + + argc1 = func_type->param_count * 2 + 2; + + if (argc1 > sizeof(argv_buf) / sizeof(uint32)) { + size = ((uint64)sizeof(uint32)) * argc1; + if (size >= UINT_MAX + || !(argv1 = wasm_malloc((uint32)size))) { + wasm_runtime_set_exception(module_inst, "allocate memory failed."); + return false; + } + } + + for (i = 0; i < sizeof(WASMModuleInstance*) / sizeof(uint32); i++) + argv1[j++] = ((uint32*)&module_inst)[i]; + + for (i = 0; i < func_type->param_count; i++) { + switch (func_type->types[i]) { + case VALUE_TYPE_I32: + argv1[j++] = *argv++; + break; + case VALUE_TYPE_I64: + case VALUE_TYPE_F64: + argv1[j++] = *argv++; + argv1[j++] = *argv++; + break; + case VALUE_TYPE_F32: + u.val = *(float32*)argv++; +#if defined(__arm__) || defined(__mips__) + /* 64-bit data must be 8 bytes alined in arm and mips */ + if (j & 1) + j++; +#endif + argv1[j++] = u.parts[0]; + argv1[j++] = u.parts[1]; + break; + default: + wasm_assert(0); + break; + } + } + + if (func_type->result_count == 0) { + invokeNative_Void(argv1, argc1, func_ptr); + } + else { + switch (func_type->types[func_type->param_count]) { + case VALUE_TYPE_I32: + ret[0] = invokeNative_Int32(argv1, argc1, func_ptr); + break; + case VALUE_TYPE_I64: + PUT_I64_TO_ADDR(ret, invokeNative_Int64(argv1, argc1, func_ptr)); + break; + case VALUE_TYPE_F32: + *(float32*)ret = invokeNative_Float32(argv1, argc1, func_ptr); + break; + case VALUE_TYPE_F64: + PUT_F64_TO_ADDR(ret, invokeNative_Float64(argv1, argc1, func_ptr)); + break; + } + } + + if (argv1 != argv_buf) + wasm_free(argv1); + return true; +} + +#else /* else of !defined(__x86_64__) && !defined(__amd_64__) */ + +typedef void (*GenericFunctionPointer)(); +int64 invokeNative(uint64 *args, uint64 n_fps, uint64 n_stacks, GenericFunctionPointer f); + +typedef float64 (*Float64FuncPtr)(uint64*, uint64, uint64, GenericFunctionPointer); +typedef float32 (*Float32FuncPtr)(uint64*, uint64, uint64, GenericFunctionPointer); +typedef int64 (*Int64FuncPtr)(uint64*,uint64, uint64, GenericFunctionPointer); +typedef int32 (*Int32FuncPtr)(uint64*, uint64, uint64, GenericFunctionPointer); +typedef void (*VoidFuncPtr)(uint64*, uint64, uint64, GenericFunctionPointer); + +static Float64FuncPtr invokeNative_Float64 = (Float64FuncPtr)invokeNative; +static Float32FuncPtr invokeNative_Float32 = (Float32FuncPtr)invokeNative; +static Int64FuncPtr invokeNative_Int64 = (Int64FuncPtr)invokeNative; +static Int32FuncPtr invokeNative_Int32 = (Int32FuncPtr)invokeNative; +static VoidFuncPtr invokeNative_Void = (VoidFuncPtr)invokeNative; + +#if defined(_WIN32) || defined(_WIN32_) +#define MAX_REG_FLOATS 4 +#define MAX_REG_INTS 4 +#else +#define MAX_REG_FLOATS 8 +#define MAX_REG_INTS 6 +#endif + +bool +wasm_runtime_invoke_native(void *func_ptr, WASMType *func_type, + WASMModuleInstance *module_inst, + uint32 *argv, uint32 argc, uint32 *ret) +{ + uint64 argv_buf[32], *argv1 = argv_buf, *fps, *ints, *stacks, size; + uint32 *argv_src = argv, i, j, argc1, n_ints = 0, n_stacks = 0; +#if defined(_WIN32) || defined(_WIN32_) + /* important difference in calling conventions */ +#define n_fps n_ints +#else + int n_fps = 0; +#endif + + argc1 = 1 + MAX_REG_FLOATS + func_type->param_count + 2; + if (argc1 > sizeof(argv_buf) / sizeof(uint64)) { + size = sizeof(uint64) * argc1; + if (size >= UINT32_MAX + || !(argv1 = wasm_malloc(size))) { + wasm_runtime_set_exception(module_inst, "allocate memory failed."); + return false; + } + } + + fps = argv1 + 1; + ints = fps + MAX_REG_FLOATS; + stacks = ints + MAX_REG_INTS; + + ints[n_ints++] = (uint64)(uintptr_t)module_inst; + + for (i = 0; i < func_type->param_count; i++) { + switch (func_type->types[i]) { + case VALUE_TYPE_I32: + if (n_ints < MAX_REG_INTS) + ints[n_ints++] = *argv_src++; + else + stacks[n_stacks++] = *argv_src++; + break; + case VALUE_TYPE_I64: + for (j = 0; j < 2; j++) { + if (n_ints < MAX_REG_INTS) + ints[n_ints++] = *argv_src++; + else + stacks[n_stacks++] = *argv_src++; + } + break; + case VALUE_TYPE_F32: + if (n_fps < MAX_REG_FLOATS) + *(float64*)&fps[n_fps++] = *(float32*)argv_src++; + else + *(float64*)&stacks[n_stacks++] = *(float32*)argv_src++; + break; + case VALUE_TYPE_F64: + if (n_fps < MAX_REG_FLOATS) + *(float64*)&fps[n_fps++] = *(float64*)argv_src; + else + *(float64*)&stacks[n_stacks++] = *(float64*)argv_src; + argv_src += 2; + break; + default: + wasm_assert(0); + break; + } + } + + if (func_type->result_count == 0) { + invokeNative_Void(argv1, n_fps, n_stacks, func_ptr); + } + else { + switch (func_type->types[func_type->param_count]) { + case VALUE_TYPE_I32: + ret[0] = invokeNative_Int32(argv1, n_fps, n_stacks, func_ptr); + break; + case VALUE_TYPE_I64: + PUT_I64_TO_ADDR(ret, invokeNative_Int64(argv1, n_fps, n_stacks, func_ptr)); + break; + case VALUE_TYPE_F32: + *(float32*)ret = invokeNative_Float32(argv1, n_fps, n_stacks, func_ptr); + break; + case VALUE_TYPE_F64: + PUT_F64_TO_ADDR(ret, invokeNative_Float64(argv1, n_fps, n_stacks, func_ptr)); + break; + default: + wasm_assert(0); + break; + } + } + + if (argv1 != argv_buf) + wasm_free(argv1); + + return true; +} + +#endif /* end of !defined(__x86_64__) && !defined(__amd_64__) */ + diff --git a/core/iwasm/runtime/vmcore-wasm/wasm_runtime.h b/core/iwasm/runtime/vmcore-wasm/wasm_runtime.h index 56e806b94..85c0bcf37 100644 --- a/core/iwasm/runtime/vmcore-wasm/wasm_runtime.h +++ b/core/iwasm/runtime/vmcore-wasm/wasm_runtime.h @@ -148,6 +148,13 @@ typedef struct WASMModuleInstance { uint32 temp_ret; uint32 llvm_stack; +#if WASM_ENABLE_EXT_MEMORY_SPACE != 0 + int32 ext_mem_base_offset; + uint8 *ext_mem_data; + uint8 *ext_mem_data_end; + uint32 ext_mem_size; +#endif + /* Default WASM stack size of threads of this Module instance. */ uint32 wasm_stack_size; @@ -308,6 +315,11 @@ int32 wasm_runtime_addr_native_to_app(WASMModuleInstance *module_inst, void *native_ptr); +bool +wasm_runtime_invoke_native(void *func_ptr, WASMType *func_type, + WASMModuleInstance *module_inst, + uint32 *argv, uint32 argc, uint32 *ret); + #ifdef __cplusplus } #endif diff --git a/core/shared-lib/include/bh_common.h b/core/shared-lib/include/bh_common.h index 9a3366ce1..a8176dc7f 100755 --- a/core/shared-lib/include/bh_common.h +++ b/core/shared-lib/include/bh_common.h @@ -23,6 +23,9 @@ #include "bh_log.h" #include "bh_list.h" +typedef void (*bh_print_function_t)(const char* message); +void bh_set_print_function(bh_print_function_t pf); + #define bh_memcpy_s(dest, dlen, src, slen) do { \ int _ret = slen == 0 ? 0 : b_memcpy_s (dest, dlen, src, slen); \ (void)_ret; \ diff --git a/core/shared-lib/include/config.h b/core/shared-lib/include/config.h index 0cf7bd4fb..a7c2a8b2d 100644 --- a/core/shared-lib/include/config.h +++ b/core/shared-lib/include/config.h @@ -43,7 +43,9 @@ #endif /* WASM VM log system */ +#ifndef WASM_ENABLE_LOG #define WASM_ENABLE_LOG 1 +#endif /* WASM Interpreter labels-as-values feature */ #define WASM_ENABLE_LABELS_AS_VALUES 1 @@ -115,3 +117,17 @@ #define APP_THREAD_STACK_SIZE_MAX (256 * 1024) #endif #endif + +/* External memory space provided by user, + but not wasm memory space and app heap space */ +#ifndef WASM_ENABLE_EXT_MEMORY_SPACE +#define WASM_ENABLE_EXT_MEMORY_SPACE 0 +#endif + +/* Default base offset of external memory space */ +#define DEFAULT_EXT_MEM_BASE_OFFSET (-2 * BH_GB) + +#ifndef bh_printf +#define bh_printf printf +#endif + diff --git a/core/shared-lib/mem-alloc/bh_memory.c b/core/shared-lib/mem-alloc/bh_memory.c index bca697051..f0a6641e5 100644 --- a/core/shared-lib/mem-alloc/bh_memory.c +++ b/core/shared-lib/mem-alloc/bh_memory.c @@ -15,9 +15,9 @@ */ #include "bh_config.h" +#include "bh_platform.h" #include "bh_memory.h" #include "mem_alloc.h" -#include #include #if BEIHAI_ENABLE_MEMORY_PROFILING != 0 @@ -76,7 +76,7 @@ int bh_memory_init_with_pool(void *mem, unsigned int bytes) global_pool_size = bytes; return 0; } - printf("Init memory with pool (%p, %u) failed.\n", mem, bytes); + bh_printf("Init memory with pool (%p, %u) failed.\n", mem, bytes); return -1; } @@ -91,7 +91,7 @@ int bh_memory_init_with_allocator(void *_malloc_func, void *_free_func) #endif return 0; } - printf("Init memory with allocator (%p, %p) failed.\n", _malloc_func, + bh_printf("Init memory with allocator (%p, %p) failed.\n", _malloc_func, _free_func); return -1; } @@ -117,7 +117,7 @@ int bh_memory_pool_size() void* bh_malloc_internal(unsigned int size) { if (memory_mode == MEMORY_MODE_UNKNOWN) { - printf("bh_malloc failed: memory hasn't been initialize.\n"); + bh_printf("bh_malloc failed: memory hasn't been initialize.\n"); return NULL; } else if (memory_mode == MEMORY_MODE_POOL) { return mem_allocator_malloc(pool_allocator, size); @@ -129,7 +129,7 @@ void* bh_malloc_internal(unsigned int size) void bh_free_internal(void *ptr) { if (memory_mode == MEMORY_MODE_UNKNOWN) { - printf("bh_free failed: memory hasn't been initialize.\n"); + bh_printf("bh_free failed: memory hasn't been initialize.\n"); } else if (memory_mode == MEMORY_MODE_POOL) { mem_allocator_free(pool_allocator, ptr); } else { @@ -250,7 +250,7 @@ void memory_usage_summarize() profile = memory_profiles_list; while (profile) { - printf("malloc:%d:malloc_num:%d:free:%d:free_num:%d:%s\n", + bh_printf("malloc:%d:malloc_num:%d:free:%d:free_num:%d:%s\n", profile->total_malloc, profile->malloc_num, profile->total_free, @@ -267,7 +267,7 @@ void memory_profile_print(const char *file, const char *func, int alloc) { - printf("location:%s@%d:used:%d:contribution:%d\n", + bh_printf("location:%s@%d:used:%d:contribution:%d\n", func, line, memory_in_use, alloc); } @@ -328,4 +328,3 @@ void bh_free_profile(const char *file, int line, const char *func, void *ptr) } #endif /* end of BEIHAI_ENABLE_MEMORY_PROFILING */ #endif /* end of MALLOC_MEMORY_FROM_SYSTEM*/ - diff --git a/core/shared-lib/mem-alloc/ems/ems_alloc.c b/core/shared-lib/mem-alloc/ems/ems_alloc.c index d8682b6c7..ca575f35b 100644 --- a/core/shared-lib/mem-alloc/ems/ems_alloc.c +++ b/core/shared-lib/mem-alloc/ems/ems_alloc.c @@ -118,7 +118,7 @@ static void unlink_hmu(gc_heap_t *heap, hmu_t *hmu) } if (!node) { - printf("[GC_ERROR]couldn't find the node in the normal list"); + bh_printf("[GC_ERROR]couldn't find the node in the normal list"); } } else { remove_tree_node((hmu_tree_node_t *) hmu); @@ -152,7 +152,7 @@ void gci_add_fc(gc_heap_t *heap, hmu_t *hmu, gc_size_t size) bh_assert( hmu && (gc_uint8*) hmu >= heap->base_addr && (gc_uint8*) hmu < heap->base_addr + heap->current_size); - bh_assert(((gc_uint32) hmu_to_obj(hmu) & 7) == 0); + bh_assert(((gc_uint32)(uintptr_t)hmu_to_obj(hmu) & 7) == 0); bh_assert( size > 0 && ((gc_uint8*) hmu) + size @@ -242,7 +242,7 @@ BH_STATIC hmu_t *alloc_hmu(gc_heap_t *heap, gc_size_t size) p = node->next; node->next = p->next; - bh_assert(((gc_int32) hmu_to_obj(p) & 7) == 0); + bh_assert(((gc_int32)(uintptr_t)hmu_to_obj(p) & 7) == 0); if ((gc_size_t) node_idx != init_node_idx&& ((gc_size_t)node_idx << 3) >= size + GC_SMALLEST_SIZE) { /* with bigger size*/ @@ -392,7 +392,7 @@ gc_object_t _gc_alloc_vo_i_heap(void *vheap, ret = hmu_to_obj(hmu); #if BH_ENABLE_MEMORY_PROFILING != 0 - printf("HEAP.ALLOC: heap: %p, size: %u", heap, size); + bh_printf("HEAP.ALLOC: heap: %p, size: %u", heap, size); #endif FINISH: @@ -434,7 +434,7 @@ gc_object_t _gc_alloc_jo_i_heap(void *vheap, ret = hmu_to_obj(hmu); #if BH_ENABLE_MEMORY_PROFILING != 0 - printf("HEAP.ALLOC: heap: %p, size: %u", heap, size); + bh_printf("HEAP.ALLOC: heap: %p, size: %u", heap, size); #endif FINISH: @@ -495,7 +495,7 @@ int gc_free_i_heap(void *vheap, gc_object_t obj ALLOC_EXTRA_PARAMETERS) heap->total_free_size += size; #endif #if BH_ENABLE_MEMORY_PROFILING != 0 - printf("HEAP.FREE, heap: %p, size: %u\n",heap, size); + bh_printf("HEAP.FREE, heap: %p, size: %u\n",heap, size); #endif if (!hmu_get_pinuse(hmu)) { @@ -538,12 +538,12 @@ int gc_free_i_heap(void *vheap, gc_object_t obj ALLOC_EXTRA_PARAMETERS) void gc_dump_heap_stats(gc_heap_t *heap) { - printf("heap: %p, heap start: %p\n", heap, heap->base_addr); - printf( + bh_printf("heap: %p, heap start: %p\n", heap, heap->base_addr); + bh_printf( "total malloc: totalfree: %u, current: %u, highmark: %u, gc cnt: %u\n", heap->total_free_size, heap->current_size, heap->highmark_size, heap->total_gc_count); - printf("g_total_malloc=%lu, g_total_free=%lu, occupied=%lu\n", + bh_printf("g_total_malloc=%lu, g_total_free=%lu, occupied=%lu\n", g_total_malloc, g_total_free, g_total_malloc - g_total_free); } diff --git a/core/shared-lib/mem-alloc/ems/ems_gc_internal.h b/core/shared-lib/mem-alloc/ems/ems_gc_internal.h index b717971ae..51308d2a9 100644 --- a/core/shared-lib/mem-alloc/ems/ems_gc_internal.h +++ b/core/shared-lib/mem-alloc/ems/ems_gc_internal.h @@ -21,6 +21,7 @@ extern "C" { #endif +#include "bh_platform.h" #include "bh_thread.h" #include "bh_memory.h" #include "bh_assert.h" @@ -279,4 +280,3 @@ extern int (*gct_vm_gc_finished)(void); #endif #endif - diff --git a/core/shared-lib/mem-alloc/ems/ems_kfc.c b/core/shared-lib/mem-alloc/ems/ems_kfc.c index 791a298a5..4409d65db 100644 --- a/core/shared-lib/mem-alloc/ems/ems_kfc.c +++ b/core/shared-lib/mem-alloc/ems/ems_kfc.c @@ -30,7 +30,7 @@ int gci_check_platform() { #define CHECK(x, y) do { \ if((x) != (y)) { \ - printf("Platform checking failed on LINE %d at FILE %s.", \ + bh_printf("Platform checking failed on LINE %d at FILE %s.",\ __LINE__, __FILE__); \ return GC_ERROR; \ } \ @@ -62,12 +62,12 @@ gc_handle_t gc_init_with_pool(char *buf, gc_size_t buf_size) /* check system compatibility*/ if (gci_check_platform() == GC_ERROR) { - printf("Check platform compatibility failed"); + bh_printf("Check platform compatibility failed"); return NULL; } if (buf_size < 1024) { - printf("[GC_ERROR]heap_init_size(%d) < 1024", buf_size); + bh_printf("[GC_ERROR]heap_init_size(%d) < 1024", buf_size); return NULL; } @@ -79,12 +79,12 @@ gc_handle_t gc_init_with_pool(char *buf, gc_size_t buf_size) ret = gct_vm_mutex_init(&heap->lock); if (ret != BHT_OK) { - printf("[GC_ERROR]failed to init lock "); + bh_printf("[GC_ERROR]failed to init lock "); return NULL; } #ifdef BH_FOOTPRINT - printf("\nINIT HEAP 0x%08x %d\n", base_addr, heap_max_size); + bh_printf("\nINIT HEAP 0x%08x %d\n", base_addr, heap_max_size); #endif /* init all data structures*/ @@ -131,7 +131,7 @@ gc_handle_t gc_init_with_pool(char *buf, gc_size_t buf_size) && HMU_FC_NORMAL_MAX_SIZE < q->size); /*@NOTIFY*/ #if BH_ENABLE_MEMORY_PROFILING != 0 - printf("heap is successfully initialized with max_size=%u.", + bh_printf("heap is successfully initialized with max_size=%u.", heap_max_size); #endif return heap; diff --git a/core/shared-lib/platform/darwin/bh_assert.c b/core/shared-lib/platform/darwin/bh_assert.c new file mode 100644 index 000000000..b52a9aa5b --- /dev/null +++ b/core/shared-lib/platform/darwin/bh_assert.c @@ -0,0 +1,69 @@ +/* + * Copyright (C) 2019 Intel Corporation. All rights reserved. + * + * Licensed 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. + */ + +#include "bh_platform.h" +#include "bh_assert.h" +#include +#include +#include + +#ifdef BH_TEST +#include +#endif + +#ifdef BH_TEST +/* for exception throwing */ +jmp_buf bh_test_jb; +#endif + +void bh_assert_internal(int v, const char *file_name, int line_number, + const char *expr_string) +{ + if (v) + return; + + if (!file_name) + file_name = "NULL FILENAME"; + if (!expr_string) + expr_string = "NULL EXPR_STRING"; + + printf("\nASSERTION FAILED: %s, at FILE=%s, LINE=%d\n", expr_string, + file_name, line_number); + +#ifdef BH_TEST + longjmp(bh_test_jb, 1); +#endif + + abort(); +} + +void bh_debug_internal(const char *file_name, int line_number, const char *fmt, + ...) +{ +#ifndef JEFF_TEST_VERIFIER + va_list args; + + va_start(args, fmt); + bh_assert(file_name); + + printf("\nDebug info FILE=%s, LINE=%d: ", file_name, line_number); + vprintf(fmt, args); + + va_end(args); + printf("\n"); +#endif +} + diff --git a/core/shared-lib/platform/darwin/bh_definition.c b/core/shared-lib/platform/darwin/bh_definition.c new file mode 100644 index 000000000..47ee11ed2 --- /dev/null +++ b/core/shared-lib/platform/darwin/bh_definition.c @@ -0,0 +1,81 @@ +/* + * Copyright (C) 2019 Intel Corporation. All rights reserved. + * + * Licensed 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. + */ + +#include "bh_definition.h" +#include "bh_platform.h" + +int bh_return(int ret) +{ + return ret; +} + +#define RSIZE_MAX 0x7FFFFFFF +int b_memcpy_s(void * s1, unsigned int s1max, const void * s2, unsigned int n) +{ + char *dest = (char*) s1; + char *src = (char*) s2; + if (n == 0) { + return 0; + } + + if (s1 == NULL || s1max > RSIZE_MAX) { + return -1; + } + if (s2 == NULL || n > s1max) { + memset(dest, 0, s1max); + return -1; + } + memcpy(dest, src, n); + return 0; +} + +int b_strcat_s(char * s1, size_t s1max, const char * s2) +{ + if (NULL + == s1|| NULL == s2 || s1max < (strlen(s1) + strlen(s2) + 1) || s1max > RSIZE_MAX) { + return -1; + } + + strcat(s1, s2); + + return 0; +} + +int b_strcpy_s(char * s1, size_t s1max, const char * s2) +{ + if (NULL + == s1|| NULL == s2 || s1max < (strlen(s2) + 1) || s1max > RSIZE_MAX) { + return -1; + } + + strcpy(s1, s2); + + return 0; +} + +int fopen_s(FILE ** pFile, const char *filename, const char *mode) +{ + if (NULL == pFile || NULL == filename || NULL == mode) { + return -1; + } + + *pFile = fopen(filename, mode); + + if (NULL == *pFile) + return -1; + + return 0; +} diff --git a/core/shared-lib/platform/darwin/bh_platform.c b/core/shared-lib/platform/darwin/bh_platform.c new file mode 100644 index 000000000..3ff600cfc --- /dev/null +++ b/core/shared-lib/platform/darwin/bh_platform.c @@ -0,0 +1,82 @@ +/* + * Copyright (C) 2019 Intel Corporation. All rights reserved. + * + * Licensed 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. + */ + +#include "bh_platform.h" + +#include +#include +#include + +char *bh_strdup(const char *s) +{ + char *s1 = NULL; + if (s && (s1 = bh_malloc(strlen(s) + 1))) + memcpy(s1, s, strlen(s) + 1); + return s1; +} + +int bh_platform_init() +{ + return 0; +} + +char* +bh_read_file_to_buffer(const char *filename, int *ret_size) +{ + char *buffer; + int file; + int file_size, read_size; + struct stat stat_buf; + + if (!filename || !ret_size) { + printf("Read file to buffer failed: invalid filename or ret size.\n"); + return NULL; + } + + if ((file = open(filename, O_RDONLY, 0)) == -1) { + printf("Read file to buffer failed: open file %s failed.\n", + filename); + return NULL; + } + + if (fstat(file, &stat_buf) != 0) { + printf("Read file to buffer failed: fstat file %s failed.\n", + filename); + close(file); + return NULL; + } + + file_size = stat_buf.st_size; + + if (!(buffer = bh_malloc(file_size))) { + printf("Read file to buffer failed: alloc memory failed.\n"); + close(file); + return NULL; + } + + read_size = read(file, buffer, file_size); + close(file); + + if (read_size < file_size) { + printf("Read file to buffer failed: read file content failed.\n"); + bh_free(buffer); + return NULL; + } + + *ret_size = file_size; + return buffer; +} + diff --git a/core/shared-lib/platform/darwin/bh_platform.h b/core/shared-lib/platform/darwin/bh_platform.h new file mode 100644 index 000000000..2715670b6 --- /dev/null +++ b/core/shared-lib/platform/darwin/bh_platform.h @@ -0,0 +1,122 @@ +/* + * Copyright (C) 2019 Intel Corporation. All rights reserved. + * + * Licensed 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. + */ + +#ifndef _BH_PLATFORM_H +#define _BH_PLATFORM_H + +#include "bh_config.h" +#include "bh_types.h" +#include "bh_memory.h" +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#ifdef __cplusplus +extern "C" { +#endif + +typedef uint64_t uint64; +typedef int64_t int64; + +extern void DEBUGME(void); + +#define DIE do{bh_debug("Die here\n\n\n\n\n\n\n\n\n\n\n\n\n\n"); DEBUGME(void); while(1);}while(0) + +#define BH_PLATFORM "Darwin" + +/* NEED qsort */ + +#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 + +#define BH_ROUTINE_MODIFIER + +#define BHT_TIMEDOUT ETIMEDOUT + +#define INVALID_THREAD_ID 0xFFffFFff + +typedef pthread_t korp_tid; +typedef pthread_mutex_t korp_mutex; +typedef sem_t korp_sem; +typedef pthread_cond_t korp_cond; +typedef pthread_t korp_thread; +typedef void* (*thread_start_routine_t)(void*); + +#define wa_malloc bh_malloc +#define wa_free bh_free +#define wa_strdup bh_strdup + +//int snprintf(char *buffer, size_t count, const char *format, ...); +double fmod(double x, double y); +float fmodf(float x, float y); +double sqrt(double x); + +#define BH_WAIT_FOREVER 0xFFFFFFFF + +#ifndef NULL +# define NULL ((void*) 0) +#endif + +/** + * Return the offset of the given field in the given type. + * + * @param Type the type containing the filed + * @param field the field in the type + * + * @return the offset of field in Type + */ +#ifndef offsetof +#define offsetof(Type, field) ((size_t)(&((Type *)0)->field)) +#endif + +#define bh_assert assert + +int b_memcpy_s(void * s1, unsigned int s1max, const void * s2, + unsigned int n); +int b_strcat_s(char * s1, size_t s1max, const char * s2); +int b_strcpy_s(char * s1, size_t s1max, const char * s2); + +int fopen_s(FILE ** pFile, const char *filename, const char *mode); + +char *bh_read_file_to_buffer(const char *filename, int *ret_size); + +char *bh_strdup(const char *s); + +int bh_platform_init(); + +#ifdef __cplusplus +} +#endif + +#endif diff --git a/core/shared-lib/platform/darwin/bh_platform_log.c b/core/shared-lib/platform/darwin/bh_platform_log.c new file mode 100644 index 000000000..4ff03192a --- /dev/null +++ b/core/shared-lib/platform/darwin/bh_platform_log.c @@ -0,0 +1,41 @@ +/* + * Copyright (C) 2019 Intel Corporation. All rights reserved. + * + * Licensed 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. + */ + +#include "bh_platform.h" +#include + +void bh_log_emit(const char *fmt, va_list ap) +{ + vprintf(fmt, ap); + fflush(stdout); +} + +int bh_fprintf(FILE *stream, const char *fmt, ...) +{ + va_list ap; + int ret; + + va_start(ap, fmt); + ret = vfprintf(stream ? stream : stdout, fmt, ap); + va_end(ap); + + return ret; +} + +int bh_fflush(void *stream) +{ + return fflush(stream ? stream : stdout); +} diff --git a/core/shared-lib/platform/darwin/bh_thread.c b/core/shared-lib/platform/darwin/bh_thread.c new file mode 100644 index 000000000..97879aa77 --- /dev/null +++ b/core/shared-lib/platform/darwin/bh_thread.c @@ -0,0 +1,405 @@ +/* + * Copyright (C) 2019 Intel Corporation. All rights reserved. + * + * Licensed 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. + */ + +#include "bh_thread.h" +#include "bh_assert.h" +#include "bh_log.h" +#include "bh_memory.h" +#include +#include +#include + +static bool is_thread_sys_inited = false; + +static korp_mutex thread_list_lock; +static pthread_key_t thread_local_storage_key[BH_MAX_TLS_NUM]; + +int _vm_thread_sys_init() +{ + unsigned i, j; + int ret; + + if (is_thread_sys_inited) + return 0; + + for (i = 0; i < BH_MAX_TLS_NUM; i++) { + ret = pthread_key_create(&thread_local_storage_key[i], NULL); + if (ret) + goto fail; + } + + ret = vm_mutex_init(&thread_list_lock); + if (ret) + goto fail; + + is_thread_sys_inited = true; + return 0; + + fail: for (j = 0; j < i; j++) + pthread_key_delete(thread_local_storage_key[j]); + return -1; +} + +void vm_thread_sys_destroy(void) +{ + if (is_thread_sys_inited) { + unsigned i; + for (i = 0; i < BH_MAX_TLS_NUM; i++) + pthread_key_delete(thread_local_storage_key[i]); + vm_mutex_destroy(&thread_list_lock); + is_thread_sys_inited = false; + } +} + +typedef struct { + thread_start_routine_t start; + void* stack; + int stack_size; + void* arg; +} thread_wrapper_arg; + +static void *vm_thread_wrapper(void *arg) +{ + thread_wrapper_arg * targ = arg; + LOG_VERBOSE("THREAD CREATE 0x%08x\n", &targ); + targ->stack = (void *)((uintptr_t)(&arg) & ~0xfff); + _vm_tls_put(1, targ); + targ->start(targ->arg); + bh_free(targ); + _vm_tls_put(1, NULL); + return NULL; +} + +int _vm_thread_create_with_prio(korp_tid *tid, thread_start_routine_t start, + void *arg, unsigned int stack_size, int prio) +{ + pthread_attr_t tattr; + thread_wrapper_arg *targ; + + bh_assert(stack_size > 0); + bh_assert(tid); + bh_assert(start); + + *tid = INVALID_THREAD_ID; + + pthread_attr_init(&tattr); + pthread_attr_setdetachstate(&tattr, PTHREAD_CREATE_JOINABLE); + if (pthread_attr_setstacksize(&tattr, stack_size) != 0) { + bh_debug("Invalid thread stack size %u. Min stack size on Linux = %u", + stack_size, PTHREAD_STACK_MIN); + pthread_attr_destroy(&tattr); + return BHT_ERROR; + } + + targ = (thread_wrapper_arg*) bh_malloc(sizeof(*targ)); + if (!targ) { + pthread_attr_destroy(&tattr); + return BHT_ERROR; + } + + targ->start = start; + targ->arg = arg; + targ->stack_size = stack_size; + + if (pthread_create(tid, &tattr, vm_thread_wrapper, targ) != 0) { + pthread_attr_destroy(&tattr); + bh_free(targ); + return BHT_ERROR; + } + + pthread_attr_destroy(&tattr); + return BHT_OK; +} + +int _vm_thread_create(korp_tid *tid, thread_start_routine_t start, void *arg, + unsigned int stack_size) +{ + return _vm_thread_create_with_prio(tid, start, arg, stack_size, + BH_THREAD_DEFAULT_PRIORITY); +} + +korp_tid _vm_self_thread() +{ + return (korp_tid) pthread_self(); +} + +void vm_thread_exit(void * code) +{ + bh_free(_vm_tls_get(1)); + _vm_tls_put(1, NULL); + pthread_exit(code); +} + +void *_vm_tls_get(unsigned idx) +{ + bh_assert(idx < BH_MAX_TLS_NUM); + return pthread_getspecific(thread_local_storage_key[idx]); +} + +int _vm_tls_put(unsigned idx, void * tls) +{ + bh_assert(idx < BH_MAX_TLS_NUM); + pthread_setspecific(thread_local_storage_key[idx], tls); + return BHT_OK; +} + +int _vm_mutex_init(korp_mutex *mutex) +{ + return pthread_mutex_init(mutex, NULL) == 0 ? BHT_OK : BHT_ERROR; +} + +int _vm_recursive_mutex_init(korp_mutex *mutex) +{ + int ret; + + pthread_mutexattr_t mattr; + + bh_assert(mutex); + ret = pthread_mutexattr_init(&mattr); + if (ret) + return BHT_ERROR; + + pthread_mutexattr_settype(&mattr, PTHREAD_MUTEX_RECURSIVE); + ret = pthread_mutex_init(mutex, &mattr); + pthread_mutexattr_destroy(&mattr); + + return ret == 0 ? BHT_OK : BHT_ERROR; +} + +int _vm_mutex_destroy(korp_mutex *mutex) +{ + int ret; + + bh_assert(mutex); + ret = pthread_mutex_destroy(mutex); + + return ret == 0 ? BHT_OK : BHT_ERROR; +} + +/* Returned error (EINVAL, EAGAIN and EDEADLK) from + locking the mutex indicates some logic error present in + the program somewhere. + Don't try to recover error for an existing unknown error.*/ +void vm_mutex_lock(korp_mutex *mutex) +{ + int ret; + + bh_assert(mutex); + ret = pthread_mutex_lock(mutex); + if (0 != ret) { + printf("vm mutex lock failed (ret=%d)!\n", ret); + exit(-1); + } +} + +int vm_mutex_trylock(korp_mutex *mutex) +{ + int ret; + + bh_assert(mutex); + ret = pthread_mutex_trylock(mutex); + + return ret == 0 ? BHT_OK : BHT_ERROR; +} + +/* Returned error (EINVAL, EAGAIN and EPERM) from + unlocking the mutex indicates some logic error present + in the program somewhere. + Don't try to recover error for an existing unknown error.*/ +void vm_mutex_unlock(korp_mutex *mutex) +{ + int ret; + + bh_assert(mutex); + ret = pthread_mutex_unlock(mutex); + if (0 != ret) { + printf("vm mutex unlock failed (ret=%d)!\n", ret); + exit(-1); + } +} + +int _vm_sem_init(korp_sem* sem, unsigned int c) +{ + int ret; + + bh_assert(sem); + ret = sem_init(sem, 0, c); + + return ret == 0 ? BHT_OK : BHT_ERROR; +} + +int _vm_sem_destroy(korp_sem *sem) +{ + int ret; + + bh_assert(sem); + ret = sem_destroy(sem); + + return ret == 0 ? BHT_OK : BHT_ERROR; +} + +int _vm_sem_wait(korp_sem *sem) +{ + int ret; + + bh_assert(sem); + + ret = sem_wait(sem); + + return ret == 0 ? BHT_OK : BHT_ERROR; +} + +/*int _vm_sem_reltimedwait(korp_sem *sem, int mills) +{ + int ret = BHT_OK; + + struct timespec timeout; + const int mills_per_sec = 1000; + const int mills_to_nsec = 1E6; + + bh_assert(sem); + + if (mills == BHT_WAIT_FOREVER) { + ret = sem_wait(sem); + } else { + + timeout.tv_sec = mills / mills_per_sec; + timeout.tv_nsec = (mills % mills_per_sec) * mills_to_nsec; + timeout.tv_sec += time(NULL); + + ret = sem_timedwait(sem, &timeout); + } + + if (ret != BHT_OK) { + if (errno == BHT_TIMEDOUT) { + ret = BHT_TIMEDOUT; + errno = 0; + } else { + bh_debug("Faliure happens when timed wait is called"); + bh_assert(0); + } + } + + return ret; +} +*/ + +int _vm_sem_post(korp_sem *sem) +{ + bh_assert(sem); + + return sem_post(sem) == 0 ? BHT_OK : BHT_ERROR; +} + +int _vm_cond_init(korp_cond *cond) +{ + bh_assert(cond); + + if (pthread_cond_init(cond, NULL) != BHT_OK) + return BHT_ERROR; + + return BHT_OK; +} + +int _vm_cond_destroy(korp_cond *cond) +{ + bh_assert(cond); + + if (pthread_cond_destroy(cond) != BHT_OK) + return BHT_ERROR; + + return BHT_OK; +} + +int _vm_cond_wait(korp_cond *cond, korp_mutex *mutex) +{ + bh_assert(cond); + bh_assert(mutex); + + if (pthread_cond_wait(cond, mutex) != BHT_OK) + return BHT_ERROR; + + return BHT_OK; +} + +static void msec_nsec_to_abstime(struct timespec *ts, int64 msec, int32 nsec) +{ + struct timeval tv; + + gettimeofday(&tv, NULL); + + ts->tv_sec = tv.tv_sec + msec / 1000; + ts->tv_nsec = tv.tv_usec * 1000 + (msec % 1000) * 1000000 + nsec; + + if (ts->tv_nsec >= 1000000000L) { + ts->tv_sec++; + ts->tv_nsec -= 1000000000L; + } +} + +int _vm_cond_reltimedwait(korp_cond *cond, korp_mutex *mutex, int mills) +{ + int ret; + struct timespec abstime; + + if (mills == BHT_WAIT_FOREVER) + ret = pthread_cond_wait(cond, mutex); + else { + msec_nsec_to_abstime(&abstime, mills, 0); + ret = pthread_cond_timedwait(cond, mutex, &abstime); + } + + if (ret != BHT_OK && ret != BHT_TIMEDOUT) + return BHT_ERROR; + + return BHT_OK; +} + +int _vm_cond_signal(korp_cond *cond) +{ + bh_assert(cond); + + if (pthread_cond_signal(cond) != BHT_OK) + return BHT_ERROR; + + return BHT_OK; +} + +int _vm_cond_broadcast(korp_cond *cond) +{ + bh_assert(cond); + + if (pthread_cond_broadcast(cond) != BHT_OK) + return BHT_ERROR; + + return BHT_OK; +} + +int _vm_thread_cancel(korp_tid thread) +{ + return pthread_cancel(thread); +} + +int _vm_thread_join(korp_tid thread, void **value_ptr, int mills) +{ + return pthread_join(thread, value_ptr); +} + +int _vm_thread_detach(korp_tid thread) +{ + return pthread_detach(thread); +} + diff --git a/core/shared-lib/platform/darwin/bh_time.c b/core/shared-lib/platform/darwin/bh_time.c new file mode 100644 index 000000000..0627b08d0 --- /dev/null +++ b/core/shared-lib/platform/darwin/bh_time.c @@ -0,0 +1,80 @@ +/* + * Copyright (C) 2019 Intel Corporation. All rights reserved. + * + * Licensed 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. + */ + +#include "bh_time.h" + +#include +#include +#include +#include + +/* + * This function returns milliseconds per tick. + * @return milliseconds per tick. + */ +uint64 _bh_time_get_tick_millisecond() +{ + return sysconf(_SC_CLK_TCK); +} + +/* + * This function returns milliseconds after boot. + * @return milliseconds after boot. + */ +uint64 _bh_time_get_boot_millisecond() +{ + struct timespec ts; + if (clock_gettime(CLOCK_MONOTONIC, &ts) != 0) { + return 0; + } + + return ((uint64) ts.tv_sec) * 1000 + ts.tv_nsec / (1000 * 1000); +} + +uint32 bh_get_tick_sec() +{ + return _bh_time_get_boot_millisecond() / 1000; +} + +/* + * This function returns GMT time milliseconds since from 1970.1.1, AKA UNIX time. + * @return milliseconds since from 1970.1.1. + */ +uint64 _bh_time_get_millisecond_from_1970() +{ + struct timeb tp; + ftime(&tp); + + return ((uint64) tp.time) * 1000 + tp.millitm + - (tp.dstflag == 0 ? 0 : 60 * 60 * 1000) + tp.timezone * 60 * 1000; +} + +size_t _bh_time_strftime(char *s, size_t max, const char *format, int64 time) +{ + time_t time_sec = time / 1000; + struct timeb tp; + struct tm *ltp; + + ftime(&tp); + time_sec -= tp.timezone * 60; + + ltp = localtime(&time_sec); + if (ltp == NULL) { + return 0; + } + return strftime(s, max, format, ltp); +} + diff --git a/core/shared-lib/platform/darwin/shared_platform.cmake b/core/shared-lib/platform/darwin/shared_platform.cmake new file mode 100644 index 000000000..5b403a09c --- /dev/null +++ b/core/shared-lib/platform/darwin/shared_platform.cmake @@ -0,0 +1,24 @@ +# Copyright (C) 2019 Intel Corporation. All rights reserved. +# +# Licensed 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. + +set (PLATFORM_SHARED_DIR ${CMAKE_CURRENT_LIST_DIR}) + +include_directories(${PLATFORM_SHARED_DIR}) +include_directories(${PLATFORM_SHARED_DIR}/../include) + + +file (GLOB_RECURSE source_all ${PLATFORM_SHARED_DIR}/*.c) + +set (PLATFORM_SHARED_SOURCE ${source_all}) + diff --git a/core/shared-lib/platform/linux-sgx/bh_assert.c b/core/shared-lib/platform/linux-sgx/bh_assert.c new file mode 100644 index 000000000..b52a9aa5b --- /dev/null +++ b/core/shared-lib/platform/linux-sgx/bh_assert.c @@ -0,0 +1,69 @@ +/* + * Copyright (C) 2019 Intel Corporation. All rights reserved. + * + * Licensed 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. + */ + +#include "bh_platform.h" +#include "bh_assert.h" +#include +#include +#include + +#ifdef BH_TEST +#include +#endif + +#ifdef BH_TEST +/* for exception throwing */ +jmp_buf bh_test_jb; +#endif + +void bh_assert_internal(int v, const char *file_name, int line_number, + const char *expr_string) +{ + if (v) + return; + + if (!file_name) + file_name = "NULL FILENAME"; + if (!expr_string) + expr_string = "NULL EXPR_STRING"; + + printf("\nASSERTION FAILED: %s, at FILE=%s, LINE=%d\n", expr_string, + file_name, line_number); + +#ifdef BH_TEST + longjmp(bh_test_jb, 1); +#endif + + abort(); +} + +void bh_debug_internal(const char *file_name, int line_number, const char *fmt, + ...) +{ +#ifndef JEFF_TEST_VERIFIER + va_list args; + + va_start(args, fmt); + bh_assert(file_name); + + printf("\nDebug info FILE=%s, LINE=%d: ", file_name, line_number); + vprintf(fmt, args); + + va_end(args); + printf("\n"); +#endif +} + diff --git a/core/shared-lib/platform/linux-sgx/bh_definition.c b/core/shared-lib/platform/linux-sgx/bh_definition.c new file mode 100644 index 000000000..5105d0ff8 --- /dev/null +++ b/core/shared-lib/platform/linux-sgx/bh_definition.c @@ -0,0 +1,81 @@ +/* + * Copyright (C) 2019 Intel Corporation. All rights reserved. + * + * Licensed 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. + */ + +#include "bh_definition.h" +#include "bh_platform.h" + +int bh_return(int ret) +{ + return ret; +} + +#define RSIZE_MAX 0x7FFFFFFF +int b_memcpy_s(void * s1, unsigned int s1max, const void * s2, unsigned int n) +{ + char *dest = (char*) s1; + char *src = (char*) s2; + if (n == 0) { + return 0; + } + + if (s1 == NULL || s1max > RSIZE_MAX) { + return -1; + } + if (s2 == NULL || n > s1max) { + memset(dest, 0, s1max); + return -1; + } + memcpy(dest, src, n); + return 0; +} + +int b_strcat_s(char * s1, size_t s1max, const char * s2) +{ + if (NULL + == s1|| NULL == s2 || s1max < (strlen(s1) + strlen(s2) + 1) || s1max > RSIZE_MAX) { + return -1; + } + + strcat(s1, s2); + + return 0; +} + +int b_strcpy_s(char * s1, size_t s1max, const char * s2) +{ + if (NULL + == s1|| NULL == s2 || s1max < (strlen(s2) + 1) || s1max > RSIZE_MAX) { + return -1; + } + + strncpy(s1, s2, s1max); + + return 0; +} + +int fopen_s(FILE ** pFile, const char *filename, const char *mode) +{ + if (NULL == pFile || NULL == filename || NULL == mode) { + return -1; + } + + *pFile = fopen(filename, mode); + + if (NULL == *pFile) + return -1; + + return 0; +} diff --git a/core/shared-lib/platform/linux-sgx/bh_platform.c b/core/shared-lib/platform/linux-sgx/bh_platform.c new file mode 100644 index 000000000..d6f4c29ce --- /dev/null +++ b/core/shared-lib/platform/linux-sgx/bh_platform.c @@ -0,0 +1,67 @@ +/* + * Copyright (C) 2019 Intel Corporation. All rights reserved. + * + * Licensed 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. + */ + +#include "bh_common.h" +#include "bh_platform.h" + +#include +#include +#include + +#define FIXED_BUFFER_SIZE (1<<14) +static bh_print_function_t print_function = NULL; + +char *bh_strdup(const char *s) +{ + char *s1 = NULL; + if (s && (s1 = bh_malloc(strlen(s) + 1))) + memcpy(s1, s, strlen(s) + 1); + return s1; +} + +int bh_platform_init() +{ + return 0; +} + +int putchar(int c) +{ + return 0; +} + +int puts(const char *s) +{ + return 0; +} + +void bh_set_print_function(bh_print_function_t pf) +{ + print_function = pf; +} + +int bh_printf_sgx(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; +} diff --git a/core/shared-lib/platform/linux-sgx/bh_platform.h b/core/shared-lib/platform/linux-sgx/bh_platform.h new file mode 100644 index 000000000..7a835ef84 --- /dev/null +++ b/core/shared-lib/platform/linux-sgx/bh_platform.h @@ -0,0 +1,115 @@ +/* + * Copyright (C) 2019 Intel Corporation. All rights reserved. + * + * Licensed 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. + */ + +#ifndef _BH_PLATFORM_H +#define _BH_PLATFORM_H + +#include "bh_config.h" +#include "bh_types.h" +#include "bh_memory.h" +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#ifdef __cplusplus +extern "C" { +#endif + +extern int bh_printf_sgx(const char *message, ...); + +typedef uint64_t uint64; +typedef int64_t int64; + +#define DIE do{bh_debug("Die here\n\n\n\n\n\n\n\n\n\n\n\n\n\n"); DEBUGME(void); while(1);}while(0) + +#define BH_PLATFORM "Linux-SGX" + +/* NEED qsort */ + +#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 + +#define BH_ROUTINE_MODIFIER + +#define BHT_TIMEDOUT ETIMEDOUT + +#define INVALID_THREAD_ID 0xFFffFFff + +typedef int korp_tid; +typedef int korp_mutex; +typedef int korp_sem; +typedef int korp_cond; +typedef int korp_thread; +typedef void* (*thread_start_routine_t)(void*); + +#define wa_malloc bh_malloc +#define wa_free bh_free +#define wa_strdup bh_strdup + +int snprintf(char *buffer, size_t count, const char *format, ...); +double fmod(double x, double y); +float fmodf(float x, float y); +double sqrt(double x); + +#define BH_WAIT_FOREVER 0xFFFFFFFF + +#ifndef NULL +# define NULL ((void*) 0) +#endif + +/** + * Return the offset of the given field in the given type. + * + * @param Type the type containing the filed + * @param field the field in the type + * + * @return the offset of field in Type + */ +#ifndef offsetof +#define offsetof(Type, field) ((size_t)(&((Type *)0)->field)) +#endif + +#define bh_assert assert + +int b_memcpy_s(void * s1, unsigned int s1max, const void * s2, + unsigned int n); +int b_strcat_s(char * s1, size_t s1max, const char * s2); +int b_strcpy_s(char * s1, size_t s1max, const char * s2); + +char *bh_strdup(const char *s); + +int bh_platform_init(); + +#ifdef __cplusplus +} +#endif + +#endif diff --git a/core/shared-lib/platform/linux-sgx/bh_platform_log.c b/core/shared-lib/platform/linux-sgx/bh_platform_log.c new file mode 100644 index 000000000..4ff03192a --- /dev/null +++ b/core/shared-lib/platform/linux-sgx/bh_platform_log.c @@ -0,0 +1,41 @@ +/* + * Copyright (C) 2019 Intel Corporation. All rights reserved. + * + * Licensed 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. + */ + +#include "bh_platform.h" +#include + +void bh_log_emit(const char *fmt, va_list ap) +{ + vprintf(fmt, ap); + fflush(stdout); +} + +int bh_fprintf(FILE *stream, const char *fmt, ...) +{ + va_list ap; + int ret; + + va_start(ap, fmt); + ret = vfprintf(stream ? stream : stdout, fmt, ap); + va_end(ap); + + return ret; +} + +int bh_fflush(void *stream) +{ + return fflush(stream ? stream : stdout); +} diff --git a/core/shared-lib/platform/linux-sgx/bh_thread.c b/core/shared-lib/platform/linux-sgx/bh_thread.c new file mode 100644 index 000000000..8730e13cd --- /dev/null +++ b/core/shared-lib/platform/linux-sgx/bh_thread.c @@ -0,0 +1,190 @@ +/* + * Copyright (C) 2019 Intel Corporation. All rights reserved. + * + * Licensed 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. + */ + +#include "bh_thread.h" +#include "bh_assert.h" +#include "bh_memory.h" +#include +#include +#include + +int _vm_thread_sys_init() +{ + return 0; +} + +void vm_thread_sys_destroy(void) +{ +} + +int _vm_thread_create_with_prio(korp_tid *tid, thread_start_routine_t start, + void *arg, unsigned int stack_size, int prio) +{ + return BHT_ERROR; + // return BHT_OK; +} + +int _vm_thread_create(korp_tid *tid, thread_start_routine_t start, void *arg, + unsigned int stack_size) +{ + return _vm_thread_create_with_prio(tid, start, arg, stack_size, + BH_THREAD_DEFAULT_PRIORITY); +} + +korp_tid _vm_self_thread() +{ + return 0; +} + +void vm_thread_exit(void * code) +{ +} + +// storage for one thread +static void *_tls_store = NULL; + +void *_vm_tls_get(unsigned idx) +{ + return _tls_store; +} + +int _vm_tls_put(unsigned idx, void * tls) +{ + _tls_store = tls; + return BHT_OK; + //return BHT_ERROR; +} + +int _vm_mutex_init(korp_mutex *mutex) +{ + return BHT_OK; + //return BHT_ERROR; +} + +int _vm_recursive_mutex_init(korp_mutex *mutex) +{ + return BHT_OK; + //return BHT_ERROR; +} + +int _vm_mutex_destroy(korp_mutex *mutex) +{ + return BHT_OK; + //return BHT_ERROR; +} + +/* Returned error (EINVAL, EAGAIN and EDEADLK) from + locking the mutex indicates some logic error present in + the program somewhere. + Don't try to recover error for an existing unknown error.*/ +void vm_mutex_lock(korp_mutex *mutex) +{ +} + +int vm_mutex_trylock(korp_mutex *mutex) +{ + return BHT_OK; + //return BHT_ERROR; +} + +/* Returned error (EINVAL, EAGAIN and EPERM) from + unlocking the mutex indicates some logic error present + in the program somewhere. + Don't try to recover error for an existing unknown error.*/ +void vm_mutex_unlock(korp_mutex *mutex) +{ +} + +int _vm_sem_init(korp_sem* sem, unsigned int c) +{ + return BHT_OK; + //return BHT_ERROR; +} + +int _vm_sem_destroy(korp_sem *sem) +{ + return BHT_OK; + //return BHT_ERROR; +} + +int _vm_sem_wait(korp_sem *sem) +{ + return BHT_OK; + //return BHT_ERROR; +} + +int _vm_sem_reltimedwait(korp_sem *sem, int mills) +{ + return BHT_OK; + //return BHT_ERROR; +} + +int _vm_sem_post(korp_sem *sem) +{ + return BHT_OK; + //return BHT_ERROR; +} + +int _vm_cond_init(korp_cond *cond) +{ + return BHT_OK; + //return BHT_ERROR; +} + +int _vm_cond_destroy(korp_cond *cond) +{ + return BHT_OK; + //return BHT_ERROR; +} + +int _vm_cond_wait(korp_cond *cond, korp_mutex *mutex) +{ + return BHT_OK; + //return BHT_ERROR; +} + +int _vm_cond_reltimedwait(korp_cond *cond, korp_mutex *mutex, int mills) +{ + return BHT_OK; + //return BHT_ERROR; +} + +int _vm_cond_signal(korp_cond *cond) +{ + return BHT_OK; + //return BHT_ERROR; +} + +int _vm_cond_broadcast(korp_cond *cond) +{ + return BHT_OK; + //return BHT_ERROR; +} + +int _vm_thread_cancel(korp_tid thread) +{ + return 0; +} + +int _vm_thread_join(korp_tid thread, void **value_ptr, int mills) +{ + return 0; +} + +int _vm_thread_detach(korp_tid thread) +{ + return 0; +} diff --git a/core/shared-lib/platform/linux-sgx/bh_time.c b/core/shared-lib/platform/linux-sgx/bh_time.c new file mode 100644 index 000000000..0627b08d0 --- /dev/null +++ b/core/shared-lib/platform/linux-sgx/bh_time.c @@ -0,0 +1,80 @@ +/* + * Copyright (C) 2019 Intel Corporation. All rights reserved. + * + * Licensed 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. + */ + +#include "bh_time.h" + +#include +#include +#include +#include + +/* + * This function returns milliseconds per tick. + * @return milliseconds per tick. + */ +uint64 _bh_time_get_tick_millisecond() +{ + return sysconf(_SC_CLK_TCK); +} + +/* + * This function returns milliseconds after boot. + * @return milliseconds after boot. + */ +uint64 _bh_time_get_boot_millisecond() +{ + struct timespec ts; + if (clock_gettime(CLOCK_MONOTONIC, &ts) != 0) { + return 0; + } + + return ((uint64) ts.tv_sec) * 1000 + ts.tv_nsec / (1000 * 1000); +} + +uint32 bh_get_tick_sec() +{ + return _bh_time_get_boot_millisecond() / 1000; +} + +/* + * This function returns GMT time milliseconds since from 1970.1.1, AKA UNIX time. + * @return milliseconds since from 1970.1.1. + */ +uint64 _bh_time_get_millisecond_from_1970() +{ + struct timeb tp; + ftime(&tp); + + return ((uint64) tp.time) * 1000 + tp.millitm + - (tp.dstflag == 0 ? 0 : 60 * 60 * 1000) + tp.timezone * 60 * 1000; +} + +size_t _bh_time_strftime(char *s, size_t max, const char *format, int64 time) +{ + time_t time_sec = time / 1000; + struct timeb tp; + struct tm *ltp; + + ftime(&tp); + time_sec -= tp.timezone * 60; + + ltp = localtime(&time_sec); + if (ltp == NULL) { + return 0; + } + return strftime(s, max, format, ltp); +} + diff --git a/core/shared-lib/platform/linux-sgx/shared_platform.cmake b/core/shared-lib/platform/linux-sgx/shared_platform.cmake new file mode 100644 index 000000000..5b403a09c --- /dev/null +++ b/core/shared-lib/platform/linux-sgx/shared_platform.cmake @@ -0,0 +1,24 @@ +# Copyright (C) 2019 Intel Corporation. All rights reserved. +# +# Licensed 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. + +set (PLATFORM_SHARED_DIR ${CMAKE_CURRENT_LIST_DIR}) + +include_directories(${PLATFORM_SHARED_DIR}) +include_directories(${PLATFORM_SHARED_DIR}/../include) + + +file (GLOB_RECURSE source_all ${PLATFORM_SHARED_DIR}/*.c) + +set (PLATFORM_SHARED_SOURCE ${source_all}) + diff --git a/doc/building.md b/doc/building.md new file mode 100644 index 000000000..13c5bdc14 --- /dev/null +++ b/doc/building.md @@ -0,0 +1,268 @@ + +Build WAMR Core +========================= +Please follow the instructions below to build the WAMR core on different platforms. + +Linux +------------------------- +First of all please install library dependencies of lib gcc. +Use installation commands below for Ubuntu Linux: +``` Bash +sudo apt install lib32gcc-5-dev g++-multilib +``` +Or in Fedora: +``` Bash +sudo dnf install glibc-devel.i686 +``` + +After installing dependencies, build the source code: +``` Bash +cd core/iwasm/products/linux/ +mkdir build +cd build +cmake .. +make +``` + +Mac +------------------------- +Make sure to install Xcode from App Store firstly, and install cmake. + +If you use Homebrew, install cmake from the command line: +``` Bash +brew install cmake +``` + +Then build the source codes: +``` +cd core/iwasm/products/darwin/ +mkdir build +cd build +cmake .. +make +``` + +VxWorks +------------------------- +VxWorks 7 SR0620 release is validated. + +First you need to build a VSB. Make sure *UTILS_UNIX* layer is added in the VSB. +After the VSB is built, export the VxWorks toolchain path by: +``` +export /host/vx-compiler/bin:$PATH +``` +Now switch to iwasm source tree to build the source code: +``` +cd core/iwasm/products/vxworks/ +mkdir build +cd build +cmake .. +make +``` +Create a VIP based on the VSB. Make sure the following components are added: +* INCLUDE_POSIX_PTHREADS +* INCLUDE_POSIX_PTHREAD_SCHEDULER +* INCLUDE_SHARED_DATA +* INCLUDE_SHL + +Copy the generated iwasm executable, the test WASM binary as well as the needed +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). + +Zephyr +------------------------- +You need to download the Zephyr source code first and embed WAMR into it. +``` Bash +git clone https://github.com/zephyrproject-rtos/zephyr.git +cd zephyr/samples/ +cp -a /products/zephyr/simple . +cd simple +ln -s iwasm +ln -s shared-lib +mkdir build && cd build +source ../../../zephyr-env.sh +cmake -GNinja -DBOARD=qemu_x86 .. +ninja +``` +AliOS-Things +------------------------- +1. a developerkit board id needed for testing +2. download the AliOS-Things code + ``` Bash + git clone https://github.com/alibaba/AliOS-Things.git + ``` +3. copy /products/alios-things directory to AliOS-Things/middleware, and rename it as iwasm + ``` Bash + cp -a /products/alios-things middleware/iwasm + ``` +4. create a link to in middleware/iwasm/ and rename it to iwasm + ``` Bash + ln -s middleware/iwasm/iwasm + ``` +5. create a link to in middleware/iwasm/ and rename it to shared-lib + ``` Bash + ln -s middle/iwasm/shared-lib + ``` +6. modify file app/example/helloworld/helloworld.c, patch as: + ``` C + #include + #include + extern bool iwasm_init(); + int application_start(int argc, char *argv[]) + { + int count = 0; + iwasm_init(); + ... + } + ``` +7. modify file app/example/helloworld/aos.mk + ``` C + $(NAME)_COMPONENTS := osal_aos iwasm + ``` +8. build source code + ``` Bash + aos make helloworld@developerkit -c config + aos make + ``` +9. download the binary to developerkit board, check the output from serial port + +Docker +------------------------- +[Docker](https://www.docker.com/) will download all the dependencies and build WAMR Core on your behalf. + +Make sure you have Docker installed on your machine: [macOS](https://docs.docker.com/docker-for-mac/install/), [Windows](https://docs.docker.com/docker-for-windows/install/) or [Linux](https://docs.docker.com/install/linux/docker-ce/ubuntu/). + +Build the Docker image: + +``` Bash +docker build --rm -f "Dockerfile" -t wamr:latest . +``` +Run the image in interactive mode: +``` Bash +docker run --rm -it wamr:latest +``` +You'll now enter the container at `/root`. + + +Build WASM app +========================= +You can write a simple ```test.c``` as the first sample. + +```C +#include +#include + +int main(int argc, char **argv) +{ + char *buf; + + printf("Hello world!\n"); + + buf = malloc(1024); + if (!buf) { + printf("malloc buf failed\n"); + return -1; + } + + printf("buf ptr: %p\n", buf); + + sprintf(buf, "%s", "1234\n"); + printf("buf: %s", buf); + + free(buf); + return 0; +} +``` + +There are three methods to build a WASM binary. They are Emscripten, the clang compiler and Docker. + +## Use Emscripten tool + +A method to build a WASM binary is to use Emscripten tool ```emcc```. +Assuming you are using Linux, you may install emcc from Emscripten EMSDK following the steps below: + +``` +git clone https://github.com/emscripten-core/emsdk.git +emsdk install latest +emsdk activate latest +``` +source ```./emsdk_env.sh```. +The Emscripten website provides other installation methods beyond Linux. + +Use the emcc command below to build the WASM C source code into the WASM binary. +``` Bash +emcc -g -O3 *.c -s WASM=1 -s SIDE_MODULE=1 -s ASSERTIONS=1 -s STACK_OVERFLOW_CHECK=2 \ + -s TOTAL_MEMORY=65536 -s TOTAL_STACK=4096 -o test.wasm +``` +You will get ```test.wasm``` which is the WASM app binary. + +## Use clang compiler + +Another method to build a WASM binary is to use clang compiler```clang-8```. + +Add source to your system source list from llvm website, for ubuntu16.04, add following lines to /etc/apt/sources.list: + +```Bash +deb http://apt.llvm.org/xenial/ llvm-toolchain-xenial main +deb-src http://apt.llvm.org/xenial/ llvm-toolchain-xenial main # 7 +deb http://apt.llvm.org/xenial/ llvm-toolchain-xenial-7 main +deb-src http://apt.llvm.org/xenial/ llvm-toolchain-xenial-7 main # 8 +deb http://apt.llvm.org/xenial/ llvm-toolchain-xenial-8 main +deb-src http://apt.llvm.org/xenial/ llvm-toolchain-xenial-8 main +``` + +Download and install clang-8 tool-chain using following commands: + +```Bash +wget -O - https://apt.llvm.org/llvm-snapshot.gpg.key | sudo apt-key add - +sudo apt-get update +sudo apt-get install llvm-8 lld-8 clang-8 +``` + +Create a soft link under /usr/bin: + +```Bash +cd /usr/bin +sudo ln -s wasm-ld-8 wasm-ld +``` + +Use the clang-8 command below to build the WASM C source code into the WASM binary. + +```Bash +clang-8 --target=wasm32 -O3 -Wl,--initial-memory=131072,--allow-undefined,--export=main, +--no-threads,--strip-all,--no-entry -nostdlib -o test.wasm test.c +``` + +You will get ```test.wasm``` which is the WASM app binary. + +## Using Docker + +The last method availble is using [Docker](https://www.docker.com/). We assume you've already configured Docker (see Platform section above) and have a running interactive shell. Currently the Dockerfile only supports compiling apps with clang, with Emscripten planned for the future. + +Use the clang-8 command below to build the WASM C source code into the WASM binary. + +```Bash +clang-8 --target=wasm32 -O3 -Wl,--initial-memory=131072,--allow-undefined,--export=main, +--no-threads,--strip-all,--no-entry -nostdlib -o test.wasm test.c +``` + +You will get ```test.wasm``` which is the WASM app binary. + +Run WASM app +======================== + +Assume you are using Linux, the command to run the test.wasm is: +``` Bash +cd iwasm/products/linux/build +./iwasm test.wasm +``` +You will get the following output: +``` +Hello world! +buf ptr: 0x400002b0 +buf: 1234 +``` +If you would like to run the test app on Zephyr, we have embedded a test sample into its OS image. You will need to execute: +``` +ninja run +``` diff --git a/doc/embed_wamr.md b/doc/embed_wamr.md new file mode 100644 index 000000000..4c1588f8f --- /dev/null +++ b/doc/embed_wamr.md @@ -0,0 +1,40 @@ +Embed WAMR into software production +===================================== + +![WAMR embed diagram](./pics/embed.PNG "WAMR embed architecture diagram") + + +A typical WAMR API usage is shown below (some return value checks are ignored): +``` C + static char global_heap_buf[512 * 1024]; + + char *buffer; + wasm_module_t module; + wasm_module_inst_t inst; + wasm_function_inst_t func; + wasm_exec_env_t env; + uint32 argv[2]; + + bh_memory_init_with_pool(global_heap_buf, sizeof(global_heap_buf)); + wasm_runtime_init(); + + buffer = read_wasm_binary_to_buffer(…); + module = wasm_runtime_load(buffer, size, err, err_size); + inst = wasm_runtime_instantiate(module, 0, 0, err, err_size); + func = wasm_runtime_lookup_function(inst, "fib", "(i32)i32"); + env = wasm_runtime_create_exec_env(stack_size); + + argv[0] = 8; + if (!wasm_runtime_call_wasm(inst, env, func, 1, argv_buf) ) { + wasm_runtime_clear_exception(inst); + } + /* the return value is stored in argv[0] */ + printf("fib function return: %d\n", argv[0]); + + wasm_runtime_destory_exec_env(env); + wasm_runtime_deinstantiate(inst); + wasm_runtime_unload(module); + wasm_runtime_destroy(); + bh_memory_destroy(); +``` + diff --git a/doc/pics/architecture.PNG b/doc/pics/architecture.PNG deleted file mode 100644 index 00dba560a..000000000 Binary files a/doc/pics/architecture.PNG and /dev/null differ diff --git a/doc/pics/architecture_extend.PNG b/doc/pics/architecture_extend.PNG deleted file mode 100644 index 31905df5a..000000000 Binary files a/doc/pics/architecture_extend.PNG and /dev/null differ diff --git a/doc/pics/vgl.PNG b/doc/pics/vgl.PNG deleted file mode 100644 index d7a06d956..000000000 Binary files a/doc/pics/vgl.PNG and /dev/null differ diff --git a/doc/pics/vgl2.PNG b/doc/pics/vgl2.PNG deleted file mode 100644 index 1387d6f10..000000000 Binary files a/doc/pics/vgl2.PNG and /dev/null differ diff --git a/doc/pics/vgl_demo.png b/doc/pics/vgl_demo.png new file mode 100644 index 000000000..3cb7eb464 Binary files /dev/null and b/doc/pics/vgl_demo.png differ diff --git a/doc/pics/vgl_demo2.png b/doc/pics/vgl_demo2.png new file mode 100644 index 000000000..8b07e6275 Binary files /dev/null and b/doc/pics/vgl_demo2.png differ diff --git a/doc/pics/vgl_demo_linux.png b/doc/pics/vgl_demo_linux.png new file mode 100644 index 000000000..848537382 Binary files /dev/null and b/doc/pics/vgl_demo_linux.png differ diff --git a/doc/pics/wamr-arch.JPG b/doc/pics/wamr-arch.JPG new file mode 100644 index 000000000..759ed3888 Binary files /dev/null and b/doc/pics/wamr-arch.JPG differ diff --git a/doc/release_ack.md b/doc/release_ack.md new file mode 100644 index 000000000..e72466441 --- /dev/null +++ b/doc/release_ack.md @@ -0,0 +1,60 @@ +Major feature releases and contributors +========================================= + + +**May 07, 2019: WAMR first GitHub release** + +- Contributors: Wenyong Huang, Weining Lu, Lei Shi, Li Tian, Jizhao Zhang, Yi Zhang, Daoming Qiu, Xin Wang (Intel) + +**May 17, 2019: Application manager, WASM APP API, samples and test tools** + +- Contributors: Wenyong Huang, Weining Lu, Lei Shi, Li Tian, Jizhao Zhang, Yi Zhang, Daoming Qiu, Xin Wang (Intel) + + +**May 23, 2019: Support AliOS Things** + +- Contributor: JinZhou Zhu (Alibaba) + + + +**May 24, 2019: Support memory usage profiler** + +- Contributors Wenyong Huang (Intel) + +**Jun 11, 2019: Add WASM APP API connection** + + +- Contributor: Weining Lu (Intel) + +**Jun 10, 2019: Support VxWorks** + +- Contributor: Yiting Wang (WindRiver) + +**Aug 1, 2019: Add WGL graphic user interface API** + +- Contributor: Weining Lu + +**Aug 14, 2019: Add Docker support** + + +- Contributor: beriberikix + + +**Aug 14, 2019: WASM IoT app store demo** + + +- Contributor: Luhanzhi Li, Jun Xu (Intel) + + +**Aug 28, 2019: SGX support** + + +- Contributor: Mic Bowman (Intel) + + +**Sep 6, 2019: Mac platform support** + + +- Contributor: Jonathan Dong (Alibaba) + + diff --git a/doc/roadmap.md b/doc/roadmap.md new file mode 100644 index 000000000..4cff8ac60 --- /dev/null +++ b/doc/roadmap.md @@ -0,0 +1,16 @@ + +# WebAssembly Micro Runtime Roadmap + + +## Ahead of time compilation +Status: under development. The first release is targetted to the end of 2019. + +## WASI support +Evaluated solution. + +## Data serialization +Evauating using cbor as the default data serialization + +## Threading +Not started yet + diff --git a/doc/wamr_api.md b/doc/wamr_api.md new file mode 100644 index 000000000..7b46e2220 --- /dev/null +++ b/doc/wamr_api.md @@ -0,0 +1,310 @@ + +WASM application library +======================== + +WAMR APP API includes built-in Libc API's, Base library and Extension library reference. + + +**Libc API's**
+This is a minimal set of Libc API's for memory allocation, string manipulation and printing. The header file is located at ```lib/app-libs/libc/lib_base.h```. The current supported API set is listed here: +``` C +void *malloc(size_t size); +void *calloc(size_t n, size_t size); +void free(void *ptr); +int memcmp(const void *s1, const void *s2, size_t n); +void *memcpy(void *dest, const void *src, size_t n); +void *memmove(void *dest, const void *src, size_t n); +void *memset(void *s, int c, size_t n); +int putchar(int c); +int snprintf(char *str, size_t size, const char *format, ...); +int sprintf(char *str, const char *format, ...); +char *strchr(const char *s, int c); +int strcmp(const char *s1, const char *s2); +char *strcpy(char *dest, const char *src); +size_t strlen(const char *s); +int strncmp(const char * str1, const char * str2, size_t n); +char *strncpy(char *dest, const char *src, unsigned long n); +``` + +**Base library**
+Basic support for communication, timers, etc is available. You can refer to the header file ```lib/app-libs/base/wasm_app.h``` which contains the definitions for request and response API's, event pub/sub API's and timer API's. Please note that these API's require the native implementations. +The API set is listed below: +``` C +typedef void(*request_handler_f)(request_t *) ; +typedef void(*response_handler_f)(response_t *, void *) ; + +// Request API's +bool api_register_resource_handler(const char *url, request_handler_f); +void api_send_request(request_t * request, response_handler_f response_handler, void * user_data); +void api_response_send(response_t *response); + +// Event API's +bool api_publish_event(const char *url, int fmt, void *payload, int payload_len); +bool api_subscribe_event(const char * url, request_handler_f handler); + +struct user_timer; +typedef struct user_timer * user_timer_t; + +// Timer API's +user_timer_t api_timer_create(int interval, bool is_period, bool auto_start, void(*on_user_timer_update)(user_timer_t +)); +void api_timer_cancel(user_timer_t timer); +void api_timer_restart(user_timer_t timer, int interval); +``` + +**Library extension reference**
+Currently we provide several kinds of extension library for reference including sensor, connection and GUI. + +Sensor API: In the header file ```lib/app-libs/extension/sensor/sensor.h```, the API set is defined as below: +``` C +sensor_t sensor_open(const char* name, int index, + void(*on_sensor_event)(sensor_t, attr_container_t *, void *), + void *user_data); +bool sensor_config(sensor_t sensor, int interval, int bit_cfg, int delay); +bool sensor_config_with_attr_container(sensor_t sensor, attr_container_t *cfg); +bool sensor_close(sensor_t sensor); +``` +Connection API: In the header file `lib/app-libs/extension/connection/connection.h.`, the API set is defined as below: +``` C +/* Connection event type */ +typedef enum { + /* Data is received */ + CONN_EVENT_TYPE_DATA = 1, + /* Connection is disconnected */ + CONN_EVENT_TYPE_DISCONNECT +} conn_event_type_t; + +typedef void (*on_connection_event_f)(connection_t *conn, + conn_event_type_t type, + const char *data, + uint32 len, + void *user_data); +connection_t *api_open_connection(const char *name, + attr_container_t *args, + on_connection_event_f on_event, + void *user_data); +void api_close_connection(connection_t *conn); +int api_send_on_connection(connection_t *conn, const char *data, uint32 len); +bool api_config_connection(connection_t *conn, attr_container_t *cfg); +``` +GUI API: The API's is list in header file ```lib/app-libs/extension/gui/wgl.h``` which is implemented based open soure 2D graphic library [LittlevGL](https://docs.littlevgl.com/en/html/index.html). Currently supported widgets include button, label, list and check box and more wigdet would be provided in future. + +The mechanism of exporting native API to WASM application +======================================================= + +The basic working flow for WASM application calling into the native API is shown in the following diagram: + +![WAMR WASM API ext diagram](./pics/extend_library.PNG "WAMR WASM API ext architecture diagram") + + +WAMR provides the macro `EXPORT_WASM_API` to enable users to export a native API to a WASM application. WAMR has implemented a base API for the timer and messaging by using `EXPORT_WASM_API`. This can be a point of reference for extending your own library. +``` C +static NativeSymbol extended_native_symbol_defs[] = { + EXPORT_WASM_API(wasm_register_resource), + EXPORT_WASM_API(wasm_response_send), + EXPORT_WASM_API(wasm_post_request), + EXPORT_WASM_API(wasm_sub_event), + EXPORT_WASM_API(wasm_create_timer), + EXPORT_WASM_API(wasm_timer_set_interval), + EXPORT_WASM_API(wasm_timer_cancel), + EXPORT_WASM_API(wasm_timer_restart) +}; +``` + +![#f03c15](https://placehold.it/15/f03c15/000000?text=+) **Security attention:** A WebAssembly application should only have access to its own memory space. As a result, the integrator should carefully design the native function to ensure that the memory accesses are safe. The native API to be exported to the WASM application must: +- Only use 32 bits number for parameters +- Should not pass data to the structure pointer (do data serialization instead) +- Should do the pointer address conversion in the native API +- Should not pass function pointer as callback + +Below is a sample of a library extension. All code invoked across WASM and native world must be serialized and de-serialized, and the native world must do a boundary check for every incoming address from the WASM world. + + + + + +Steps for exporting native API +========================== + +WAMR implemented a framework for developers to export API's. Below is the procedure to expose the platform API's in three steps: + +**Step 1. Create a header file**
+Declare the API's for your WASM application source project to include. + +**Step 2. Create a source file**
+Export the platform API's, for example in ``` products/linux/ext_lib_export.c ``` +``` C +#include "lib_export.h" + +static NativeSymbol extended_native_symbol_defs[] = +{ +}; + +#include "ext_lib_export.h" +``` + +**Step 3. Register new API's**
+Use the macro `EXPORT_WASM_API` and `EXPORT_WASM_API2` to add exported API's into the array of ```extended_native_symbol_defs```. +The pre-defined MACRO `EXPORT_WASM_API` should be used to declare a function export: +``` c +#define EXPORT_WASM_API(symbol) {#symbol, symbol} +``` + +Below code example shows how to extend the library to support `customized()`: + +``` +//lib_export_impl.c +void customized() +{ + // your code +} + + +// lib_export_dec.h +#ifndef _LIB_EXPORT_DEC_H_ +#define _LIB_EXPORT_DEC_H_ +#ifdef __cplusplus +extern "C" { +#endif + +void customized(); + +#ifdef __cplusplus +} +#endif +#endif + + +// ext_lib_export.c +#include "lib_export.h" +#include "lib_export_dec.h" + +static NativeSymbol extended_native_symbol_defs[] = +{ + EXPORT_WASM_API(customized) +}; + +#include "ext_lib_export.h" +``` + +Use extended library +------------------------ +In the application source project, it will include the WAMR built-in API's header file and platform extension header files. Assuming the board vendor extends the library which added an API called customized(), the WASM application would be like this: +``` C +#include +#include "lib_export_dec.h" // provided by the platform vendor + +int main(int argc, char **argv) +{ + int I; + char *buf = “abcd”; + customized(); // customized API provided by the platform vendor + return i; +} +``` + + +Communication programming models +========================= +WAMR supports two typical communication programming models, the microservice model and the pub/sub model. + + +Microservice model +------------------------- +The microservice model is also known as request and response model. One WASM application acts as the server which provides a specific service. Other WASM applications or host/cloud applications request that service and get the response. + + +Below is the reference implementation of the server application. It provides room temperature measurement service. + +``` C +void on_init() +{ + api_register_resource_handler("/room_temp", room_temp_handler); +} + +void on_destroy() +{ +} + +void room_temp_handler(request_t *request) +{ + response_t response[1]; + attr_container_t *payload; + payload = attr_container_create("room_temp payload"); + if (payload == NULL) + return; + + attr_container_set_string(&payload, "temp unit", "centigrade"); + attr_container_set_int(&payload, "value", 26); + + make_response_for_request(request, response); + set_response(response, + CONTENT_2_05, + FMT_ATTR_CONTAINER, + payload, + attr_container_get_serialize_length(payload)); + + api_response_send(response); + attr_container_destroy(payload); +} +``` + + +Pub/sub model +------------------------- +One WASM application acts as the event publisher. It publishes events to notify WASM applications or host/cloud applications which subscribe to the events. + + + +Below is the reference implementation of the pub application. It utilizes a timer to repeatedly publish an overheat alert event to the subscriber applications. Then the subscriber applications receive the events immediately. + +``` C +/* Timer callback */ +void timer_update(user_timer_t timer +{ + attr_container_t *event; + + event = attr_container_create("event"); + attr_container_set_string(&event, + "warning", + "temperature is over high"); + + api_publish_event("alert/overheat", + FMT_ATTR_CONTAINER, + event, + attr_container_get_serialize_length(event)); + + attr_container_destroy(event); +} + +void on_init() +{ + user_timer_t timer; + timer = api_timer_create(1000, true, true, timer_update); +} + +void on_destroy() +{ +} +``` + +Below is the reference implementation of the sub application. +``` C +void overheat_handler(request_t *event) +{ + printf("Event: %s\n", event->url); + + if (event->payload != NULL && event->fmt == FMT_ATTR_CONTAINER) + attr_container_dump((attr_container_t *) event->payload); +} + +void on_init( +{ + api_subscribe_event ("alert/overheat", overheat_handler); +} + +void on_destroy() +{ +} +``` +**Note:** You can also subscribe this event from host side by using host tool. Please refer `samples/simple` project for deail usage. \ No newline at end of file diff --git a/samples/gui/README.md b/samples/gui/README.md index 3bfd18dd6..e04e33dc7 100644 --- a/samples/gui/README.md +++ b/samples/gui/README.md @@ -1,15 +1,17 @@ Introduction ============== -This sample demonstrates that a graphic user interface application in WebAssembly programming with WAMR graphic library(WGL) extension. WGL is implemented based on LittlevGL, an open-source embedded 2d graphic library. LittlevGL source code is built into the WAMR runtime and exported to Webassembly application with WGL extension. These extension API's are listed in: `/core/iwasm/lib/app-libs/extension/gui/wgl.h`. Currently only a small set of API's are provided and that would be extended in future. +This sample demonstrates that a graphic user interface application in WebAssembly programming with WAMR graphic library(WGL) extension. WGL defined a WASM application API set for programming the UI applications. + +WGL implemention is based on [LittlevGL](https://github.com/littlevgl/), an open-source embedded 2d graphic library. Comparing the building the LittlevGL into WASM bytecode in the [littlevgl](../littlevgl) sample, WGL compiled LittlevGL source code into the WAMR runtime and defined a wrapper API for exporting to Webassembly application. These extension API's are listed in: `/core/iwasm/lib/app-libs/extension/gui/wgl.h`. Currently only a small set of API's are provided and that would be extended in future. + The runtime component supports building target for Linux and Zephyr/STM Nucleo board. The beauty of this sample is the WebAssembly application can have identical display and behavior when running from both runtime environments. That implies we can do majority of application validation from desktop environment as long as two runtime distributions support the same set of application interface. -The sample also provides the native Linux version of application without the runtime under folder "lvgl-native-ui-app". It can help to check differences between the implementations in native and WebAssembly. - - +Below pictures show the WASM application is running on an STM board with an LCD touch panel. When users click the blue button, the WASM application increases the counter, and the latest counter value is displayed on the top banner of the touch panel. The number on top will plus one each second, and the number on the bottom will plus one when clicked. -The number on top will plus one each second, and the number on the bottom will plus one when clicked. + +![WAMR UI SAMPLE](../../doc/pics/vgl_demo2.png "WAMR UI DEMO") Configure 32 bit or 64 bit build ============== diff --git a/samples/gui/wasm-runtime-wgl/src/ext_lib_export.c b/samples/gui/wasm-runtime-wgl/src/ext_lib_export.c index e478b7e45..4f696f0ad 100644 --- a/samples/gui/wasm-runtime-wgl/src/ext_lib_export.c +++ b/samples/gui/wasm-runtime-wgl/src/ext_lib_export.c @@ -1,5 +1,5 @@ #include "lib_export.h" -#include "native_interface.h" +#include "sensor_api.h" #include "connection_api.h" #include "gui_api.h" diff --git a/samples/gui/wasm-runtime-wgl/src/platform/zephyr/iwasm_main.c b/samples/gui/wasm-runtime-wgl/src/platform/zephyr/iwasm_main.c index 6c42acc8e..486815504 100644 --- a/samples/gui/wasm-runtime-wgl/src/platform/zephyr/iwasm_main.c +++ b/samples/gui/wasm-runtime-wgl/src/platform/zephyr/iwasm_main.c @@ -69,6 +69,9 @@ static bool host_init() int host_send(void * ctx, const char *buf, int size) { + if (!uart_dev) + return 0; + for (int i = 0; i < size; i++) uart_poll_out(uart_dev, buf[i]); diff --git a/samples/gui/wasm-runtime-wgl/zephyr-build/prj.conf b/samples/gui/wasm-runtime-wgl/zephyr-build/prj.conf index 2375969e1..79d892054 100644 --- a/samples/gui/wasm-runtime-wgl/zephyr-build/prj.conf +++ b/samples/gui/wasm-runtime-wgl/zephyr-build/prj.conf @@ -5,3 +5,5 @@ CONFIG_PRINTK=y CONFIG_LOG=y #CONFIG_UART_2=y CONFIG_UART_INTERRUPT_DRIVEN=y +CONFIG_STACK_SENTINEL=y +CONFIG_MAIN_STACK_SIZE=2048 diff --git a/samples/littlevgl/README.md b/samples/littlevgl/README.md index 18e2527fc..4f37d84fc 100644 --- a/samples/littlevgl/README.md +++ b/samples/littlevgl/README.md @@ -1,6 +1,6 @@ Introduction ============== -This sample demonstrates that a graphic user interface application in WebAssembly integrates the LittlevGL, an open-source embedded 2d graphic library. +This sample demonstrates that a graphic user interface application in WebAssembly by compiling the LittlevGL, an open-source embedded 2d graphic library into the WASM bytecode. In this sample, the whole LittlevGL source code is built into the WebAssembly code with the user application. The platform interfaces defined by LittlevGL is implemented in the runtime and exported to the application through the declarations from source "ext_lib_export.c" as below: @@ -14,12 +14,20 @@ In this sample, the whole LittlevGL source code is built into the WebAssembly co The runtime component supports building target for Linux and Zephyr/STM Nucleo board. The beauty of this sample is the WebAssembly application can have identical display and behavior when running from both runtime environments. That implies we can do majority of application validation from desktop environment as long as two runtime distributions support the same set of application interface. + +Below pictures show the WASM application is running on an STM board with an LCD touch panel. + +![WAMR UI SAMPLE](../../doc/pics/vgl_demo2.png "WAMR UI DEMO STM32") + +![WAMR UI SAMPLE](../../doc/pics/vgl_demo_linux.png "WAMR UI DEMO LINUX") + + +The number on top will plus one each second, and the number on the bottom will plus one when clicked. When users click the blue button, the WASM application increases the counter, and the latest counter value is displayed on the top banner of the touch panel. + The sample also provides the native Linux version of application without the runtime under folder "vgl-native-ui-app". It can help to check differences between the implementations in native and WebAssembly. - - -The number on top will plus one each second, and the number on the bottom will plus one when clicked. + Configure 32 bit or 64 bit build ============== diff --git a/samples/littlevgl/vgl-wasm-runtime/src/display_indev.h b/samples/littlevgl/vgl-wasm-runtime/src/display_indev.h index 154071e36..cb8d76e0e 100644 --- a/samples/littlevgl/vgl-wasm-runtime/src/display_indev.h +++ b/samples/littlevgl/vgl-wasm-runtime/src/display_indev.h @@ -1,9 +1,10 @@ #ifndef DISPLAY_INDEV_H_ #define DISPLAY_INDEV_H_ #include -#include "bh_platform.h" #include #include +#include "bh_platform.h" +#include "wasm_export.h" #define USE_MOUSE 1 typedef union { @@ -54,21 +55,37 @@ enum { LV_OPA_100 = 255, LV_OPA_COVER = 255, }; -extern void display_init(void); -extern void display_deinit(void); -extern int time_get_ms(); -extern bool touchscreen_read(lv_indev_data_t * data); extern void xpt2046_init(void); -extern void display_flush(int32_t x1, int32_t y1, int32_t x2, int32_t y2, - int32 color_p_offset); -extern void display_fill(int32_t x1, int32_t y1, int32_t x2, int32_t y2, - lv_color_t color_p); -extern void display_map(int32_t x1, int32_t y1, int32_t x2, int32_t y2, - const lv_color_t * color_p); -extern bool display_input_read(int32 data_offset); -void display_vdb_write(int32 buf_offset, lv_coord_t buf_w, lv_coord_t x, - lv_coord_t y, int32 color_p_offset, lv_opa_t opa); + +extern bool touchscreen_read(lv_indev_data_t * data); + extern bool mouse_read(lv_indev_data_t * data); + +extern void display_init(wasm_module_inst_t module_inst); + +extern void display_deinit(wasm_module_inst_t module_inst); + +extern int time_get_ms(wasm_module_inst_t module_inst); + +extern void display_flush(wasm_module_inst_t module_inst, + int32_t x1, int32_t y1, int32_t x2, int32_t y2, + int32 color_p_offset); + +extern void display_fill(wasm_module_inst_t module_inst, + int32_t x1, int32_t y1, int32_t x2, int32_t y2, + lv_color_t color_p); + +extern void display_map(wasm_module_inst_t module_inst, + int32_t x1, int32_t y1, int32_t x2, int32_t y2, + const lv_color_t * color_p); + +extern bool display_input_read(wasm_module_inst_t module_inst, + int32 data_offset); + +void display_vdb_write(wasm_module_inst_t module_inst, + int32 buf_offset, lv_coord_t buf_w, lv_coord_t x, + lv_coord_t y, int32 color_p_offset, lv_opa_t opa); + #endif diff --git a/samples/littlevgl/vgl-wasm-runtime/src/ext_lib_export.c b/samples/littlevgl/vgl-wasm-runtime/src/ext_lib_export.c index 3897b3b0b..0f68dd860 100644 --- a/samples/littlevgl/vgl-wasm-runtime/src/ext_lib_export.c +++ b/samples/littlevgl/vgl-wasm-runtime/src/ext_lib_export.c @@ -1,5 +1,5 @@ #include "lib_export.h" -#include "native_interface.h" +#include "sensor_api.h" #include "connection_api.h" #include "display_indev.h" @@ -12,6 +12,7 @@ static NativeSymbol extended_native_symbol_defs[] = { EXPORT_WASM_API(display_fill), EXPORT_WASM_API(display_vdb_write), EXPORT_WASM_API(display_map), - EXPORT_WASM_API(time_get_ms), }; + EXPORT_WASM_API(time_get_ms) +}; #include "ext_lib_export.h" diff --git a/samples/littlevgl/vgl-wasm-runtime/src/platform/linux/display_indev.c b/samples/littlevgl/vgl-wasm-runtime/src/platform/linux/display_indev.c index f7d8b5cce..5fe98d429 100644 --- a/samples/littlevgl/vgl-wasm-runtime/src/platform/linux/display_indev.c +++ b/samples/littlevgl/vgl-wasm-runtime/src/platform/linux/display_indev.c @@ -35,7 +35,8 @@ static uint32_t tft_fb[MONITOR_HOR_RES * MONITOR_VER_RES]; -int time_get_ms() +int +time_get_ms(wasm_module_inst_t module_inst) { static struct timeval tv; gettimeofday(&tv, NULL); @@ -157,15 +158,16 @@ void monitor_map(int32_t x1, int32_t y1, int32_t x2, int32_t y2, } -void display_init(void) +void +display_init(wasm_module_inst_t module_inst) { } -void display_flush(int32_t x1, int32_t y1, int32_t x2, int32_t y2, - int32 color_p_offset) +void +display_flush(wasm_module_inst_t module_inst, + int32_t x1, int32_t y1, int32_t x2, int32_t y2, + int32 color_p_offset) { - - wasm_module_inst_t module_inst = wasm_runtime_get_current_module_inst(); if (!wasm_runtime_validate_app_addr(module_inst, color_p_offset, 1)) return; lv_color_t * color_p = wasm_runtime_addr_app_to_native(module_inst, @@ -173,21 +175,28 @@ void display_flush(int32_t x1, int32_t y1, int32_t x2, int32_t y2, monitor_flush(x1, y1, x2, y2, color_p); } -void display_fill(int32_t x1, int32_t y1, int32_t x2, int32_t y2, - lv_color_t color_p) + +void +display_fill(wasm_module_inst_t module_inst, + int32_t x1, int32_t y1, int32_t x2, int32_t y2, + lv_color_t color_p) { monitor_fill(x1, y1, x2, y2, color_p); } -void display_map(int32_t x1, int32_t y1, int32_t x2, int32_t y2, - const lv_color_t * color_p) + +void +display_map(wasm_module_inst_t module_inst, + int32_t x1, int32_t y1, int32_t x2, int32_t y2, + const lv_color_t * color_p) { monitor_map(x1, y1, x2, y2, color_p); } -bool display_input_read(int32 data_p_offset) +bool +display_input_read(wasm_module_inst_t module_inst, + int32 data_p_offset) { bool ret; - wasm_module_inst_t module_inst = wasm_runtime_get_current_module_inst(); if (!wasm_runtime_validate_app_addr(module_inst, data_p_offset, 1)) return false; @@ -205,21 +214,23 @@ bool display_input_read(int32 data_p_offset) data_p_offset); data_app->point = data.point; - data_app->user_data_offset = (int32_t)data.user_data; + data_app->user_data_offset = + wasm_runtime_addr_native_to_app(module_inst, data.user_data); data_app->state = data.state; return ret; } -void display_deinit(void) +void +display_deinit(wasm_module_inst_t module_inst) { - } -void display_vdb_write(int32 buf_offset, lv_coord_t buf_w, lv_coord_t x, - lv_coord_t y, int32 color_p_offset, lv_opa_t opa) +void +display_vdb_write(wasm_module_inst_t module_inst, + int32 buf_offset, lv_coord_t buf_w, lv_coord_t x, + lv_coord_t y, int32 color_p_offset, lv_opa_t opa) { - wasm_module_inst_t module_inst = wasm_runtime_get_current_module_inst(); if (!wasm_runtime_validate_app_addr(module_inst, color_p_offset, 1)) return; lv_color_t *color = wasm_runtime_addr_app_to_native(module_inst, diff --git a/samples/littlevgl/vgl-wasm-runtime/src/platform/zephyr/display_indev.c b/samples/littlevgl/vgl-wasm-runtime/src/platform/zephyr/display_indev.c index 1ed562c02..58ac43f72 100644 --- a/samples/littlevgl/vgl-wasm-runtime/src/platform/zephyr/display_indev.c +++ b/samples/littlevgl/vgl-wasm-runtime/src/platform/zephyr/display_indev.c @@ -24,8 +24,11 @@ #ifndef MONITOR_ZOOM #define MONITOR_ZOOM 1 #endif -int lcd_initialized = 0; -void display_init(void) + +static int lcd_initialized = 0; + +void +display_init(wasm_module_inst_t module_inst) { if (lcd_initialized != 0) { return; @@ -36,10 +39,11 @@ void display_init(void) display_blanking_off(NULL); } -void display_flush(int32_t x1, int32_t y1, int32_t x2, int32_t y2, - int32 color_p_offset) +void +display_flush(wasm_module_inst_t module_inst, + int32_t x1, int32_t y1, int32_t x2, int32_t y2, + int32 color_p_offset) { - wasm_module_inst_t module_inst = wasm_runtime_get_current_module_inst(); if (!wasm_runtime_validate_app_addr(module_inst, color_p_offset, 1)) return; lv_color_t * color_p = wasm_runtime_addr_app_to_native(module_inst, @@ -57,20 +61,24 @@ void display_flush(int32_t x1, int32_t y1, int32_t x2, int32_t y2, /*lv_flush_ready();*/ } -void display_fill(int32_t x1, int32_t y1, int32_t x2, int32_t y2, - lv_color_t color_p) -{ -} -void display_map(int32_t x1, int32_t y1, int32_t x2, int32_t y2, - const lv_color_t * color_p) +void +display_fill(wasm_module_inst_t module_inst, + int32_t x1, int32_t y1, int32_t x2, int32_t y2, + lv_color_t color_p) { - } -bool display_input_read(int32 data_p_offset) +void +display_map(wasm_module_inst_t module_inst, + int32_t x1, int32_t y1, int32_t x2, int32_t y2, + const lv_color_t * color_p) +{ +} + +bool +display_input_read(wasm_module_inst_t module_inst, int32 data_p_offset) { - wasm_module_inst_t module_inst = wasm_runtime_get_current_module_inst(); if (!wasm_runtime_validate_app_addr(module_inst, data_p_offset, 1)) return false; lv_indev_data_t * data = wasm_runtime_addr_app_to_native(module_inst, @@ -80,15 +88,17 @@ bool display_input_read(int32 data_p_offset) } -void display_deinit(void) +void +display_deinit(wasm_module_inst_t module_inst) { } -void display_vdb_write(int32 buf_offset, lv_coord_t buf_w, lv_coord_t x, - lv_coord_t y, int32 color_p_offset, lv_opa_t opa) +void +display_vdb_write(wasm_module_inst_t module_inst, + int32 buf_offset, lv_coord_t buf_w, lv_coord_t x, + lv_coord_t y, int32 color_p_offset, lv_opa_t opa) { - wasm_module_inst_t module_inst = wasm_runtime_get_current_module_inst(); if (!wasm_runtime_validate_app_addr(module_inst, color_p_offset, 1)) return; lv_color_t *color = wasm_runtime_addr_app_to_native(module_inst, @@ -112,7 +122,8 @@ void display_vdb_write(int32 buf_offset, lv_coord_t buf_w, lv_coord_t x, *(buf_xy + 2) = color->blue; } -int time_get_ms() +int +time_get_ms(wasm_module_inst_t module_inst) { return k_uptime_get_32(); } diff --git a/samples/littlevgl/vgl-wasm-runtime/src/platform/zephyr/iwasm_main.c b/samples/littlevgl/vgl-wasm-runtime/src/platform/zephyr/iwasm_main.c index 1fc3eb941..64e27d715 100644 --- a/samples/littlevgl/vgl-wasm-runtime/src/platform/zephyr/iwasm_main.c +++ b/samples/littlevgl/vgl-wasm-runtime/src/platform/zephyr/iwasm_main.c @@ -55,7 +55,7 @@ static bool host_init() uart_dev = device_get_binding(HOST_DEVICE_COMM_UART_NAME); if (!uart_dev) { printf("UART: Device driver not found.\n"); - return; + return false; } uart_irq_rx_enable(uart_dev); uart_irq_callback_set(uart_dev, uart_irq_callback); @@ -64,6 +64,9 @@ static bool host_init() int host_send(void * ctx, const char *buf, int size) { + if (!uart_dev) + return 0; + for (int i = 0; i < size; i++) uart_poll_out(uart_dev, buf[i]); diff --git a/samples/littlevgl/vgl-wasm-runtime/zephyr-build/prj.conf b/samples/littlevgl/vgl-wasm-runtime/zephyr-build/prj.conf index 2375969e1..79d892054 100644 --- a/samples/littlevgl/vgl-wasm-runtime/zephyr-build/prj.conf +++ b/samples/littlevgl/vgl-wasm-runtime/zephyr-build/prj.conf @@ -5,3 +5,5 @@ CONFIG_PRINTK=y CONFIG_LOG=y #CONFIG_UART_2=y CONFIG_UART_INTERRUPT_DRIVEN=y +CONFIG_STACK_SENTINEL=y +CONFIG_MAIN_STACK_SIZE=2048 diff --git a/test-tools/IoT-APP-Store-Demo/README.md b/test-tools/IoT-APP-Store-Demo/README.md new file mode 100644 index 000000000..06d17a659 --- /dev/null +++ b/test-tools/IoT-APP-Store-Demo/README.md @@ -0,0 +1,36 @@ +# IoT Application Store +Wasm application management portal for WAMR + +# Requirement +Install django with pip3 +``` +pip3 install django +``` + +# Run +1. Start wasm server + ``` + cd wasm_django/server + python3 wasm_server.py + ``` + +2. Start IoT application management web portal + ``` + cd wasm_django + python3 manage.py runserver 0.0.0.0:80 + ``` + +3. Download WAMR runtime from [help](http://localhost/help/) page + > NOTE: You need to start web server according to *step 2* before accessing this link! + +4. Start a WAMR runtime from localhost + ``` + ./simple + ``` + or from other computers + ``` + ./simple -a [your.server.ip.address] + ``` + +# Online demo + http://39.106.110.7/ diff --git a/test-tools/IoT-APP-Store-Demo/wasm_django/db.sqlite3 b/test-tools/IoT-APP-Store-Demo/wasm_django/db.sqlite3 new file mode 100755 index 000000000..211576ca3 Binary files /dev/null and b/test-tools/IoT-APP-Store-Demo/wasm_django/db.sqlite3 differ diff --git a/test-tools/IoT-APP-Store-Demo/wasm_django/devices/__init__.py b/test-tools/IoT-APP-Store-Demo/wasm_django/devices/__init__.py new file mode 100755 index 000000000..e69de29bb diff --git a/test-tools/IoT-APP-Store-Demo/wasm_django/devices/admin.py b/test-tools/IoT-APP-Store-Demo/wasm_django/devices/admin.py new file mode 100755 index 000000000..8c38f3f3d --- /dev/null +++ b/test-tools/IoT-APP-Store-Demo/wasm_django/devices/admin.py @@ -0,0 +1,3 @@ +from django.contrib import admin + +# Register your models here. diff --git a/test-tools/IoT-APP-Store-Demo/wasm_django/devices/apps.py b/test-tools/IoT-APP-Store-Demo/wasm_django/devices/apps.py new file mode 100755 index 000000000..d43cc4b66 --- /dev/null +++ b/test-tools/IoT-APP-Store-Demo/wasm_django/devices/apps.py @@ -0,0 +1,5 @@ +from django.apps import AppConfig + + +class DevicesConfig(AppConfig): + name = 'devices' diff --git a/test-tools/IoT-APP-Store-Demo/wasm_django/devices/migrations/__init__.py b/test-tools/IoT-APP-Store-Demo/wasm_django/devices/migrations/__init__.py new file mode 100755 index 000000000..e69de29bb diff --git a/test-tools/IoT-APP-Store-Demo/wasm_django/devices/models.py b/test-tools/IoT-APP-Store-Demo/wasm_django/devices/models.py new file mode 100755 index 000000000..71a836239 --- /dev/null +++ b/test-tools/IoT-APP-Store-Demo/wasm_django/devices/models.py @@ -0,0 +1,3 @@ +from django.db import models + +# Create your models here. diff --git a/test-tools/IoT-APP-Store-Demo/wasm_django/devices/templates/application.html b/test-tools/IoT-APP-Store-Demo/wasm_django/devices/templates/application.html new file mode 100644 index 000000000..55852977c --- /dev/null +++ b/test-tools/IoT-APP-Store-Demo/wasm_django/devices/templates/application.html @@ -0,0 +1,152 @@ + +{% load static %} + + + + + + + Wasm-Micro-Runtime + + + + + + + + + + +
+
+ +
+
+

WebAssembly Micro Runtime - APP Store Demo

+
+
+ + + +
+
+
+
+

+ +

+
+
IP :
+
Port :
+
Installed apps :
+
+
+
+ + + + + +
+

app is downloading now

+
+
+
+
+ + +
+
+
×
+
HOT Applications
+ +
+
+ +

Product Name:

+

Current Version:

+ +
+
+
+
+ + +
+

List of Installed Apps:

+ +
+ + +
+
+ +
Product Name:
+
Staus:
+
Current Version:
+
+
+
+ +
Copyright© intel.com
+ + + + + + + + + + + + + + \ No newline at end of file diff --git a/test-tools/IoT-APP-Store-Demo/wasm_django/devices/templates/appstore.html b/test-tools/IoT-APP-Store-Demo/wasm_django/devices/templates/appstore.html new file mode 100644 index 000000000..36f1fb8da --- /dev/null +++ b/test-tools/IoT-APP-Store-Demo/wasm_django/devices/templates/appstore.html @@ -0,0 +1,106 @@ + +{% load static %} + + + + + + + + Wasm-Micro-Runtime + + + + + + + + + + +
+
+ +
+
+

WebAssembly Micro Runtime - APP Store Demo

+
+
+ + + + + +
+
+
+
The products
+
Application List
+
+
+ {%csrf_token%} +
+ + Choose File +
+
+ +
+
+
+
+
+
+
+

Product Name:

+

Product Version:

+

Preloaded Apps

+ +
+
+
+
+
+ + +
+ Copyright© intel.com +
+ + + + + + + + + diff --git a/test-tools/IoT-APP-Store-Demo/wasm_django/devices/templates/empty.html b/test-tools/IoT-APP-Store-Demo/wasm_django/devices/templates/empty.html new file mode 100644 index 000000000..6aef0f2a7 --- /dev/null +++ b/test-tools/IoT-APP-Store-Demo/wasm_django/devices/templates/empty.html @@ -0,0 +1,119 @@ + + + +wasm-micro-runtime + + + + + + + + + + +
+

404

+

Server Not Found

+

Github

+
+ + + + + + + + + + diff --git a/test-tools/IoT-APP-Store-Demo/wasm_django/devices/templates/help.html b/test-tools/IoT-APP-Store-Demo/wasm_django/devices/templates/help.html new file mode 100755 index 000000000..2e77cfadb --- /dev/null +++ b/test-tools/IoT-APP-Store-Demo/wasm_django/devices/templates/help.html @@ -0,0 +1,110 @@ + +{% load static %} + + + + + + + Wasm-Micro-Runtime + + + + + + + + + + + + +
+
+
+
+

+ How to use? +

+

+ 1. Download a simple runtime (build for ubuntu 16.04 64 bits, other platforms please build + from the source code) +

+

+ 2. In the terminal: cd ~/Download && ./simple -a 39.106.110.7 +

+
+
+ +
+ Notes: +
We also have a UI-enabled runtime, please download here and enjoy. It may require + a few more setups. +

Before running the UI-enabled runtime, please install some required softwares:

+

sudo apt-get install libsdl2-2.0-0:i386

+

For more details please refer to this guide +

+

cd ~/Download && ./wasm_runtime_wgl -a 39.106.110.7

+
+
+

+ 3. Return to device page, find your device according to the IP address and click it, you + will enter application installation page +

+

+ 4. In the application installation page, click the Install Application button, and chose an + app to install. (The "ui_app" is only for UI_enabled_runtimes, simple runtime can't install + this app) +

+

+ 5. If you want to upload a new application, go to App Store page, choose a file and click + upload +

+

+ Go Back + Download + simple_runtime + Download + UI_enabled_runtime +

+
+
+
+
+

Like this project?

+

Join us and build a powerful and interesting world for embedded + devices!

+ + +

+ View + on GitHub +

+
+
+
+
+
+
+ + + \ No newline at end of file diff --git a/test-tools/IoT-APP-Store-Demo/wasm_django/devices/templates/mysite.html b/test-tools/IoT-APP-Store-Demo/wasm_django/devices/templates/mysite.html new file mode 100644 index 000000000..88f0e9234 --- /dev/null +++ b/test-tools/IoT-APP-Store-Demo/wasm_django/devices/templates/mysite.html @@ -0,0 +1,99 @@ + +{% load static %} + + + + + + + Wasm-Micro-Runtime + + + + + + + + + + +
+
+ +
+
+

WebAssembly Micro Runtime - APP Store Demo

+
+
+ +
+
+
+
+

+ +

+
+

The devices

+
+
+ +
+ + +
+
+
+
+

+ +

+
+
IP :
+
Port :
+
Installed apps :
+
+
+

+ +

+
+
+
+ + + + +
+ Copyright© intel.com +
+ + + + + + + + \ No newline at end of file diff --git a/test-tools/IoT-APP-Store-Demo/wasm_django/devices/tests.py b/test-tools/IoT-APP-Store-Demo/wasm_django/devices/tests.py new file mode 100755 index 000000000..7ce503c2d --- /dev/null +++ b/test-tools/IoT-APP-Store-Demo/wasm_django/devices/tests.py @@ -0,0 +1,3 @@ +from django.test import TestCase + +# Create your tests here. diff --git a/test-tools/IoT-APP-Store-Demo/wasm_django/devices/views.py b/test-tools/IoT-APP-Store-Demo/wasm_django/devices/views.py new file mode 100755 index 000000000..4fd4c09c2 --- /dev/null +++ b/test-tools/IoT-APP-Store-Demo/wasm_django/devices/views.py @@ -0,0 +1,284 @@ +''' + /* Copyright (C) 2019 Intel Corporation. All rights reserved. + * + * Licensed 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. + */ +''' + +# _*_ +from django.shortcuts import render, render_to_response +from django.http import HttpResponse, HttpResponseRedirect, HttpResponseNotFound +import json +import socket +import os + +# Create your views here. + + +avaliable_list = [ + {'ID': 'timer', 'Version': '1.0'}, + {'ID': 'connection', 'Version': '1.0'}, + {'ID': 'event_publisher', 'Version': '3.0'}, + {'ID': 'event_subscriber', 'Version': '1.0'}, + {'ID': 'request_handler', 'Version': '1.0'}, + {'ID': 'sensor', 'Version': '1.0'}, + {'ID': 'ui_app', 'Version': '1.0'} +] + +# Help +def help(req): +# return "Help" page + return render(req, "help.html") + +# View +def index(req): + s = socket.socket(socket.AF_INET, socket.SOCK_STREAM) + + host = '127.0.0.1' + port = 8889 + msg = "" + err = "" + + try: + s.connect((host, port)) + s.send(bytes("query:all", encoding='utf8')) + s.settimeout(10) + msg = s.recv(1024) + except socket.timeout as e: + err = "empty" + print("no client connected") + except socket.error as e: + err = "refused" + print("server not started") + + s.close() + + device_list = [] + if msg != "": + devices = msg.decode('utf-8').split("*") + for dev in devices: + dev_info = eval(dev) + addr = dev_info['addr'] + port = dev_info['port'] + apps = dev_info['num'] + device_list.append({'IP': addr, 'Port': port, 'apps': apps}) + else: + if err == "refused": + return render(req, "empty.html") + + dlist = device_list + + return render(req, 'mysite.html', {'dlist': json.dumps(dlist)}) + + +def apps(req): + open_status = '' + search_node = [] + if req.method == "POST": + dev_search = req.POST['mykey'] + dev_addr = req.POST['voip'] + dev_port = req.POST['voport'] + open_status = 'open' + for i in avaliable_list: + if i['ID'] == dev_search: + search_node = [{'ID':dev_search, 'Version': '1.0'}] + print("search_node:",search_node) + break + else: + search_node = ["Nothing find"] + print( "final:",search_node) + else: + dev_addr = req.GET['ip'] + dev_port = req.GET['port'] + open_status = 'close' + + s = socket.socket(socket.AF_INET, socket.SOCK_STREAM) + host = '127.0.0.1' + port = 8889 + msg = "" + err = "" + + try: + s.connect((host, port)) + s.send(bytes("query:"+dev_addr+":"+str(dev_port), encoding='utf8')) + msg = s.recv(1024) + except socket.error as e: + print("unable to connect to server") + msg = b"fail" + s.close() + + app_list = [] + + if msg != "": + if msg.decode() == "fail": + return render(req, "empty.html") + else: + dic = eval(msg.decode(encoding='utf8')) + app_num = dic["num"] + for i in range(app_num): + app_list.append( + {'pname': dic["applet"+str(i+1)], 'status': 'Installed', 'current_version': '1.0'}) + + alist = app_list + device_info = [] + device_info.append( + {'IP': dev_addr, 'Port': str(dev_port), 'apps': app_num}) + + print(device_info) + return render(req, 'application.html', {'alist': json.dumps(alist), 'dlist': json.dumps(device_info), 'llist': json.dumps(avaliable_list), + "open_status":json.dumps(open_status),"search_node": json.dumps(search_node),}) + + +def appDownload(req): + dev_addr = req.GET['ip'] + dev_port = req.GET['port'] + app_name = req.GET['name'] + + s = socket.socket(socket.AF_INET, socket.SOCK_STREAM) + + host = '127.0.0.1' + port = 8889 + msg = "" + + app_path = os.path.abspath(os.path.join(os.getcwd(), "static", "upload")) + if app_path[-1] != '/': + app_path += '/' + + try: + s.connect((host, port)) + s.send(bytes("install:"+dev_addr+":"+str(dev_port)+":"+app_name + + ":"+app_path + app_name + ".wasm", encoding='utf8')) + msg = s.recv(1024) + except socket.error as e: + print("unable to connect to server") + s.close() + + success = "ok" + fail = "Fail!" + status = [success, fail] + print(msg) + if msg == b"fail": + return HttpResponse(json.dumps({ + "status": fail + })) + elif msg == b"success": + return HttpResponse(json.dumps({ + "status": success + })) + else: + return HttpResponse(json.dumps({ + "status": eval(msg.decode())["error message"].split(':')[1] + })) + + +def appDelete(req): + dev_addr = req.GET['ip'] + dev_port = req.GET['port'] + app_name = req.GET['name'] + + s = socket.socket(socket.AF_INET, socket.SOCK_STREAM) + + host = '127.0.0.1' + port = 8889 + s.connect((host, port)) + s.send(bytes("uninstall:"+dev_addr+":" + + str(dev_port)+":"+app_name, encoding='utf8')) + msg = s.recv(1024) + s.close() + r = HttpResponse("ok") + return r + +static_list = [{'ID': 'timer', 'Version': '1.0'}, {'ID': 'connection', 'Version': '1.0'}, {'ID': 'event_publisher', 'Version': '3.0'}, { + 'ID': 'event_subscriber', 'Version': '1.0'}, {'ID': 'reuqest_handler', 'Version': '1.0'}, {'ID': 'sensor', 'Version': '1.0'}, {'ID': 'ui_app', 'Version': '1.0'}] + +def store(req): + + store_path = os.path.join('static', 'upload') + status = [] + + print(user_file_list) + return render(req, 'appstore.html', {'staticlist': json.dumps(static_list), 'flist': json.dumps(user_file_list),'ulist':json.dumps(status)}) + +user_file_list = [] +files_list = [] +def uploadapps(req): + status = [] + local_list = ['timer','connection','event_publisher','event_subscriber','reuqest_handler','sensor'] + req.encoding = 'utf-8' + if req.method == 'POST': + myfile = req.FILES.get("myfile", None) + obj = req.FILES.get('myfile') + store_path = os.path.join('static', 'upload') + file_path = os.path.join('static', 'upload', obj.name) + + if not os.path.exists(store_path): + os.makedirs(store_path) + + file_name = obj.name.split(".")[0] + file_prefix = obj.name.split(".")[-1] + + + if file_prefix != "wasm": + status = ["Not a wasm file"] + elif file_name in local_list: + status = ["This App is preloaded"] + elif file_name in files_list: + status = ["This App is already uploaded"] + else: + status = [] + avaliable_list.append({'ID': file_name, 'Version': '1.0'}) + user_file_list.append({'ID': file_name, 'Version': '1.0'}) + files_list.append(file_name) + + print(user_file_list) + f = open(file_path, 'wb') + for chunk in obj.chunks(): + f.write(chunk) + f.close() + return render(req, 'appstore.html', {'staticlist': json.dumps(static_list), 'flist': json.dumps(user_file_list),'ulist':json.dumps(status)}) + +appname_list = [] + +def addapps(request): + types = '' + print("enter addapps") + request.encoding = 'utf-8' + app_dic = {'ID': '', 'Version': ''} + + # if request.method == 'get': + if "NAME" in request.GET: + a_name = request.GET['NAME'] + if a_name != "" and a_name not in appname_list: + appname_list.append(a_name) + message = request.GET['NAME'] + request.GET['Version'] + app_dic['ID'] = request.GET['NAME'] + app_dic['Version'] = request.GET['Version'] + avaliable_list.append(app_dic) + else: + types = "Exist" + print(avaliable_list) + return render(request, 'appstore.html', {'alist': json.dumps(avaliable_list)}) + +def removeapps(req): + app_name = req.GET['name'] + app_version = req.GET['version'] + remove_app = {'ID': app_name, 'Version': app_version} + avaliable_list.remove(remove_app) + user_file_list.remove(remove_app) + files_list.remove(app_name) + return render(req, 'appstore.html', {'alist': json.dumps(avaliable_list),'flist': json.dumps(user_file_list)}) + +# Test +if __name__ == "__main__": + print(device_list[0]['IP']) + print(device['IP']) diff --git a/test-tools/IoT-APP-Store-Demo/wasm_django/manage.py b/test-tools/IoT-APP-Store-Demo/wasm_django/manage.py new file mode 100755 index 000000000..341863cf6 --- /dev/null +++ b/test-tools/IoT-APP-Store-Demo/wasm_django/manage.py @@ -0,0 +1,21 @@ +#!/usr/bin/env python +"""Django's command-line utility for administrative tasks.""" +import os +import sys + + +def main(): + os.environ.setdefault('DJANGO_SETTINGS_MODULE', 'mysite.settings') + try: + from django.core.management import execute_from_command_line + except ImportError as exc: + raise ImportError( + "Couldn't import Django. Are you sure it's installed and " + "available on your PYTHONPATH environment variable? Did you " + "forget to activate a virtual environment?" + ) from exc + execute_from_command_line(sys.argv) + + +if __name__ == '__main__': + main() diff --git a/test-tools/IoT-APP-Store-Demo/wasm_django/mysite/__init__.py b/test-tools/IoT-APP-Store-Demo/wasm_django/mysite/__init__.py new file mode 100755 index 000000000..e69de29bb diff --git a/test-tools/IoT-APP-Store-Demo/wasm_django/mysite/settings.py b/test-tools/IoT-APP-Store-Demo/wasm_django/mysite/settings.py new file mode 100755 index 000000000..7eb3685c4 --- /dev/null +++ b/test-tools/IoT-APP-Store-Demo/wasm_django/mysite/settings.py @@ -0,0 +1,136 @@ +""" +Django settings for mysite project. + +Generated by 'django-admin startproject' using Django 2.2.2. + +For more information on this file, see +https://docs.djangoproject.com/en/2.2/topics/settings/ + +For the full list of settings and their values, see +https://docs.djangoproject.com/en/2.2/ref/settings/ +""" + +import os +from django.conf.global_settings import STATIC_ROOT + +# Build paths inside the project like this: os.path.join(BASE_DIR, ...) +BASE_DIR = os.path.dirname(os.path.dirname(os.path.abspath(__file__))) + + +# Quick-start development settings - unsuitable for production +# See https://docs.djangoproject.com/en/2.2/howto/deployment/checklist/ + +# SECURITY WARNING: keep the secret key used in production secret! +SECRET_KEY = '8m05#6yx5wcygj*a+v6+=-y(#o+(z58-3!epq$u@5)64!mmu8q' + +# SECURITY WARNING: don't run with debug turned on in production! +DEBUG = True + +ALLOWED_HOSTS = ['*'] + + +# Application definition + +INSTALLED_APPS = [ + 'django.contrib.admin', + 'django.contrib.auth', + 'django.contrib.contenttypes', + 'django.contrib.sessions', + 'django.contrib.messages', + 'django.contrib.staticfiles', + + + 'devices', +] + +MIDDLEWARE = [ + 'django.middleware.security.SecurityMiddleware', + 'django.contrib.sessions.middleware.SessionMiddleware', + 'django.middleware.common.CommonMiddleware', + 'django.middleware.csrf.CsrfViewMiddleware', + 'django.contrib.auth.middleware.AuthenticationMiddleware', + 'django.contrib.messages.middleware.MessageMiddleware', + 'django.middleware.clickjacking.XFrameOptionsMiddleware', +] + +ROOT_URLCONF = 'mysite.urls' + +TEMPLATES = [ + { + 'BACKEND': 'django.template.backends.django.DjangoTemplates', + 'DIRS': [], + 'APP_DIRS': True, + 'OPTIONS': { + 'context_processors': [ + 'django.template.context_processors.debug', + 'django.template.context_processors.request', + 'django.contrib.auth.context_processors.auth', + 'django.contrib.messages.context_processors.messages', + ], + }, + }, +] + +WSGI_APPLICATION = 'mysite.wsgi.application' + + +# Database +# https://docs.djangoproject.com/en/2.2/ref/settings/#databases + +DATABASES = { + 'default': { + 'ENGINE': 'django.db.backends.sqlite3', + 'NAME': os.path.join(BASE_DIR, 'db.sqlite3'), + } +} + + +# Password validation +# https://docs.djangoproject.com/en/2.2/ref/settings/#auth-password-validators + +AUTH_PASSWORD_VALIDATORS = [ + { + 'NAME': 'django.contrib.auth.password_validation.UserAttributeSimilarityValidator', + }, + { + 'NAME': 'django.contrib.auth.password_validation.MinimumLengthValidator', + }, + { + 'NAME': 'django.contrib.auth.password_validation.CommonPasswordValidator', + }, + { + 'NAME': 'django.contrib.auth.password_validation.NumericPasswordValidator', + }, +] + + +# Internationalization +# https://docs.djangoproject.com/en/2.2/topics/i18n/ + +LANGUAGE_CODE = 'en-us' + +TIME_ZONE = 'UTC' + +USE_I18N = True + +USE_L10N = True + +USE_TZ = True + +APPEND_SLASH = False + + +# Static files (CSS, JavaScript, Images) +# https://docs.djangoproject.com/en/2.2/howto/static-files/ + +STATIC_URL = '/static/' +HERE = os.path.dirname(os.path.abspath(__file__)) +HERE = os.path.join(HERE,'../') +STATICFILES_DIRS = (os.path.join(HERE,'static/'),) +#STATICFILES_DIRS = (os.path.join(BASE_DIR,'static'),) +#STATIC_ROOT = (os.path.join(os.path.dirname(_file_),'static') +#templates +TEMPLATE_DIRS=[ + '/home/xujun/mysite/templates', +] + diff --git a/test-tools/IoT-APP-Store-Demo/wasm_django/mysite/urls.py b/test-tools/IoT-APP-Store-Demo/wasm_django/mysite/urls.py new file mode 100755 index 000000000..8a74b5509 --- /dev/null +++ b/test-tools/IoT-APP-Store-Demo/wasm_django/mysite/urls.py @@ -0,0 +1,41 @@ +#config:utf-8 + +"""mysite URL Configuration + +The `urlpatterns` list routes URLs to views. For more information please see: + https://docs.djangoproject.com/en/2.2/topics/http/urls/ +Examples: +Function views + 1. Add an import: from my_app import views + 2. Add a URL to urlpatterns: path('', views.home, name='home') +Class-based views + 1. Add an import: from other_app.views import Home + 2. Add a URL to urlpatterns: path('', Home.as_view(), name='home') +Including another URLconf + 1. Import the include() function: from django.urls import include, path + 2. Add a URL to urlpatterns: path('blog/', include('blog.urls')) +""" +from django.contrib import admin +#from django.conf.urls import include,url +from django.urls import path,include +from devices import views as devices_views +#from login import views as login_views + + +urlpatterns = [ + + path('admin/', admin.site.urls), + path('',devices_views.index), + path('apps/',devices_views.apps), + path('appDownload/', devices_views.appDownload), + path('appDelete/', devices_views.appDelete), + path('appstore/',devices_views.store), +## path('apps/appstore/',devices_views.storeofdevic), +## path('search/',devices_views.search), + path('upload',devices_views.uploadapps), + path('removeapps/',devices_views.removeapps), + path('help/',devices_views.help), + +] + + diff --git a/test-tools/IoT-APP-Store-Demo/wasm_django/mysite/wsgi.py b/test-tools/IoT-APP-Store-Demo/wasm_django/mysite/wsgi.py new file mode 100755 index 000000000..45e28c9a1 --- /dev/null +++ b/test-tools/IoT-APP-Store-Demo/wasm_django/mysite/wsgi.py @@ -0,0 +1,16 @@ +""" +WSGI config for mysite project. + +It exposes the WSGI callable as a module-level variable named ``application``. + +For more information on this file, see +https://docs.djangoproject.com/en/2.2/howto/deployment/wsgi/ +""" + +import os + +from django.core.wsgi import get_wsgi_application + +os.environ.setdefault('DJANGO_SETTINGS_MODULE', 'mysite.settings') + +application = get_wsgi_application() diff --git a/test-tools/IoT-APP-Store-Demo/wasm_django/server/wasm_server.py b/test-tools/IoT-APP-Store-Demo/wasm_django/server/wasm_server.py new file mode 100755 index 000000000..1754b368e --- /dev/null +++ b/test-tools/IoT-APP-Store-Demo/wasm_django/server/wasm_server.py @@ -0,0 +1,616 @@ +''' + /* Copyright (C) 2019 Intel Corporation. All rights reserved. + * + * Licensed 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 select +import socket +import queue +from time import sleep +import struct +import threading +import time +from ctypes import * +import json +import logging +import os + +attr_type_list = [ + "ATTR_NONE", + "ATTR_TYPE_SHORT", + "ATTR_TYPE_INT", + "ATTR_TYPE_INT64", + "ATTR_TYPE_BYTE", + "ATTR_TYPE_UINT16", + "ATTR_TYPE_FLOAT", + "ATTR_TYPE_DOUBLE", + "ATTR_TYPE_BOOLEAN", + "ATTR_TYPE_STRING", + "ATTR_TYPE_BYTEARRAY" +] + + +Phase_Non_Start = 0 +Phase_Leading = 1 +Phase_Type = 2 +Phase_Size = 3 +Phase_Payload = 4 + + + +class imrt_link_message(object): + def __init__(self): + self.leading = bytes([0x12, 0x34]) + self.phase = Phase_Non_Start + self.size_in_phase = 0 + self.message_type = bytes() + self.message_size = bytes() + self.payload = bytes() + self.msg = bytes() + + def set_recv_phase(self, phase): + self.phase = phase + + def on_imrt_link_byte_arrive(self, ch): + self.msg += ch + if self.phase == Phase_Non_Start: + if ch == b'\x12': + self.set_recv_phase(Phase_Leading) + else: + return -1 + elif self.phase == Phase_Leading: + if ch == b'\x34': + self.set_recv_phase(Phase_Type) + else: + self.set_recv_phase(Phase_Non_Start) + return -1 + elif self.phase == Phase_Type: + self.message_type += ch + self.size_in_phase += 1 + + if self.size_in_phase == 2: + (self.message_type, ) = struct.unpack('!H', self.message_type) + self.size_in_phase = 0 + self.set_recv_phase(Phase_Size) + elif self.phase == Phase_Size: + self.message_size += ch + self.size_in_phase += 1 + + if self.size_in_phase == 4: + (self.message_size, ) = struct.unpack('!I', self.message_size) + self.size_in_phase = 0 + self.set_recv_phase(Phase_Payload) + + if self.message_size == b'\x00': + self.set_recv_phase(Phase_Non_Start) + return 0 + + self.set_recv_phase(Phase_Payload) + + elif self.phase == Phase_Payload: + self.payload += ch + self.size_in_phase += 1 + + if self.size_in_phase == self.message_size: + self.set_recv_phase(Phase_Non_Start) + return 0 + + return 2 + + return 1 + + + +def read_file_to_buffer(file_name): + file_object = open(file_name, 'rb') + buffer = None + + if not os.path.exists(file_name): + logging.error("file {} not found.".format(file_name)) + return "file not found" + + try: + buffer = file_object.read() + finally: + file_object.close() + + return buffer + +def decode_attr_container(msg): + + attr_dict = {} + + buf = msg[26 : ] + (total_len, tag_len) = struct.unpack('@IH', buf[0 : 6]) + tag_name = buf[6 : 6 + tag_len].decode() + buf = buf[6 + tag_len : ] + (attr_num, ) = struct.unpack('@H', buf[0 : 2]) + buf = buf[2 : ] + + logging.info("parsed attr:") + logging.info("total_len:{}, tag_len:{}, tag_name:{}, attr_num:{}" + .format(str(total_len), str(tag_len), str(tag_name), str(attr_num))) + + for i in range(attr_num): + (key_len, ) = struct.unpack('@H', buf[0 : 2]) + key_name = buf[2 : 2 + key_len - 1].decode() + buf = buf[2 + key_len : ] + (type_index, ) = struct.unpack('@c', buf[0 : 1]) + + attr_type = attr_type_list[int(type_index[0])] + buf = buf[1 : ] + + if attr_type == "ATTR_TYPE_SHORT": + (attr_value, ) = struct.unpack('@h', buf[0 : 2]) + buf = buf[2 : ] + # continue + elif attr_type == "ATTR_TYPE_INT": + (attr_value, ) = struct.unpack('@I', buf[0 : 4]) + buf = buf[4 : ] + # continue + elif attr_type == "ATTR_TYPE_INT64": + (attr_value, ) = struct.unpack('@q', buf[0 : 8]) + buf = buf[8 : ] + # continue + elif attr_type == "ATTR_TYPE_BYTE": + (attr_value, ) = struct.unpack('@c', buf[0 : 1]) + buf = buf[1 : ] + # continue + elif attr_type == "ATTR_TYPE_UINT16": + (attr_value, ) = struct.unpack('@H', buf[0 : 2]) + buf = buf[2 : ] + # continue + elif attr_type == "ATTR_TYPE_FLOAT": + (attr_value, ) = struct.unpack('@f', buf[0 : 4]) + buf = buf[4 : ] + # continue + elif attr_type == "ATTR_TYPE_DOUBLE": + (attr_value, ) = struct.unpack('@d', buf[0 : 8]) + buf = buf[8 : ] + # continue + elif attr_type == "ATTR_TYPE_BOOLEAN": + (attr_value, ) = struct.unpack('@?', buf[0 : 1]) + buf = buf[1 : ] + # continue + elif attr_type == "ATTR_TYPE_STRING": + (str_len, ) = struct.unpack('@H', buf[0 : 2]) + attr_value = buf[2 : 2 + str_len - 1].decode() + buf = buf[2 + str_len : ] + # continue + elif attr_type == "ATTR_TYPE_BYTEARRAY": + (byte_len, ) = struct.unpack('@I', buf[0 : 4]) + attr_value = buf[4 : 4 + byte_len] + buf = buf[4 + byte_len : ] + # continue + + attr_dict[key_name] = attr_value + + logging.info(str(attr_dict)) + return attr_dict + +class Request(): + mid = 0 + url = "" + action = 0 + fmt = 0 + payload = "" + payload_len = 0 + sender = 0 + + def __init__(self, url, action, fmt, payload, payload_len): + self.url = url + self.action = action + self.fmt = fmt + # if type(payload) == bytes: + # self.payload = bytes(payload, encoding = "utf8") + # else: + self.payload_len = payload_len + if self.payload_len > 0: + self.payload = payload + + + def pack_request(self): + url_len = len(self.url) + 1 + buffer_len = url_len + self.payload_len + + req_buffer = struct.pack('!2BH2IHI',1, self.action, self.fmt, self.mid, self.sender, url_len, self.payload_len) + for i in range(url_len - 1): + req_buffer += struct.pack('!c', bytes(self.url[i], encoding = "utf8")) + req_buffer += bytes([0]) + for i in range(self.payload_len): + req_buffer += struct.pack('!B', self.payload[i]) + + return req_buffer, len(req_buffer) + + + def send(self, conn, is_install): + leading = struct.pack('!2B', 0x12, 0x34) + + if not is_install: + msg_type = struct.pack('!H', 0x0002) + else: + msg_type = struct.pack('!H', 0x0004) + buff, buff_len = self.pack_request() + lenth = struct.pack('!I', buff_len) + + try: + conn.send(leading) + conn.send(msg_type) + conn.send(lenth) + conn.send(buff) + except socket.error as e: + logging.error("device closed") + for dev in tcpserver.devices: + if dev.conn == conn: + tcpserver.devices.remove(dev) + return -1 + + +def query(conn): + req = Request("/applet", 1, 0, "", 0) + if req.send(conn, False) == -1: + return "fail" + time.sleep(0.05) + try: + receive_context = imrt_link_message() + start = time.time() + while True: + if receive_context.on_imrt_link_byte_arrive(conn.recv(1)) == 0: + break + elif time.time() - start >= 5.0: + return "fail" + query_resp = receive_context.msg + print(query_resp) + except OSError as e: + logging.error("OSError exception occur") + return "fail" + + res = decode_attr_container(query_resp) + + logging.info('Query device infomation success') + return res + +def install(conn, app_name, wasm_file): + wasm = read_file_to_buffer(wasm_file) + if wasm == "file not found": + return "failed to install: file not found" + + print("wasm file len:") + print(len(wasm)) + req = Request("/applet?name=" + app_name, 3, 98, wasm, len(wasm)) + if req.send(conn, True) == -1: + return "fail" + time.sleep(0.05) + try: + receive_context = imrt_link_message() + start = time.time() + while True: + if receive_context.on_imrt_link_byte_arrive(conn.recv(1)) == 0: + break + elif time.time() - start >= 5.0: + return "fail" + msg = receive_context.msg + except OSError as e: + logging.error("OSError exception occur") + # TODO: check return message + + if len(msg) == 24 and msg[8 + 1] == 65: + logging.info('Install application success') + return "success" + else: + res = decode_attr_container(msg) + logging.warning('Install application failed: %s' % (str(res))) + print(str(res)) + + return str(res) + + +def uninstall(conn, app_name): + req = Request("/applet?name=" + app_name, 4, 99, "", 0) + if req.send(conn, False) == -1: + return "fail" + time.sleep(0.05) + try: + receive_context = imrt_link_message() + start = time.time() + while True: + if receive_context.on_imrt_link_byte_arrive(conn.recv(1)) == 0: + break + elif time.time() - start >= 5.0: + return "fail" + msg = receive_context.msg + except OSError as e: + logging.error("OSError exception occur") + # TODO: check return message + + if len(msg) == 24 and msg[8 + 1] == 66: + logging.info('Uninstall application success') + return "success" + else: + res = decode_attr_container(msg) + logging.warning('Uninstall application failed: %s' % (str(res))) + print(str(res)) + + return str(res) + +class Device: + def __init__(self, conn, addr, port): + self.conn = conn + self.addr = addr + self.port = port + self.app_num = 0 + self.apps = [] + +cmd = [] + +class TCPServer: + def __init__(self, server, server_address, inputs, outputs, message_queues): + # Create a TCP/IP + self.server = server + self.server.setblocking(False) + + # Bind the socket to the port + self.server_address = server_address + print('starting up on %s port %s' % self.server_address) + self.server.bind(self.server_address) + + # Listen for incoming connections + self.server.listen(10) + + self.cmd_sock = socket.socket(socket.AF_INET, socket.SOCK_STREAM) + self.cmd_sock.setsockopt(socket.SOL_SOCKET,socket.SO_REUSEADDR,1) + + self.cmd_sock.bind(('127.0.0.1', 8889)) + self.cmd_sock.listen(5) + + + # Sockets from which we expect to read + self.inputs = inputs + self.inputs.append(self.cmd_sock) + + # Sockets to which we expect to write + # 处理要发送的消息 + self.outputs = outputs + # Outgoing message queues (socket: Queue) + self.message_queues = message_queues + + self.devices = [] + self.conn_dict = {} + + def handler_recever(self, readable): + # Handle inputs + for s in readable: + if s is self.server: + # A "readable" socket is ready to accept a connection + connection, client_address = s.accept() + self.client_address = client_address + print('connection from', client_address) + # this is connection not server + # connection.setblocking(0) + self.inputs.append(connection) + + # Give the connection a queue for data we want to send + # self.message_queues[connection] = queue.Queue() + + res = query(connection) + + if res != "fail": + dev = Device(connection, client_address[0], client_address[1]) + self.devices.append(dev) + self.conn_dict[client_address] = connection + + dev_info = {} + dev_info['addr'] = dev.addr + dev_info['port'] = dev.port + dev_info['apps'] = 0 + + logging.info('A new client connected from ("%s":"%s")' % (dev.conn, dev.port)) + + elif s is self.cmd_sock: + connection, client_address = s.accept() + print("web server socket connected") + logging.info("Django server connected") + self.inputs.append(connection) + self.message_queues[connection] = queue.Queue() + + else: + data = s.recv(1024) + if data != b'': + # A readable client socket has data + logging.info('received "%s" from %s' % (data, s.getpeername())) + + # self.message_queues[s].put(data) + # # Add output channel for response + + # if s not in self.outputs: + # self.outputs.append(s) + + if(data.decode().split(':')[0] == "query"): + if data.decode().split(':')[1] == "all": + resp = [] + print('start query all devices') + for dev in self.devices: + dev_info = query(dev.conn) + if dev_info == "fail": + continue + dev_info["addr"] = dev.addr + dev_info["port"] = dev.port + resp.append(str(dev_info)) + + print(resp) + + if self.message_queues[s] is not None: + # '*' is used in web server to sperate the string + self.message_queues[s].put(bytes("*".join(resp), encoding = 'utf8')) + if s not in self.outputs: + self.outputs.append(s) + else: + client_addr = (data.decode().split(':')[1],int(data.decode().split(':')[2])) + + if client_addr in self.conn_dict.keys(): + print('start query device from (%s:%s)' % (client_addr[0], client_addr[1])) + resp = query(self.conn_dict[client_addr]) + print(resp) + + if self.message_queues[s] is not None: + self.message_queues[s].put(bytes(str(resp), encoding = 'utf8')) + if s not in self.outputs: + self.outputs.append(s) + else: # no connection + if self.message_queues[s] is not None: + self.message_queues[s].put(bytes(str("fail"), encoding = 'utf8')) + if s not in self.outputs: + self.outputs.append(s) + elif(data.decode().split(':')[0] == "install"): + client_addr = (data.decode().split(':')[1],int(data.decode().split(':')[2])) + app_name = data.decode().split(':')[3] + app_file = data.decode().split(':')[4] + + if client_addr in self.conn_dict.keys(): + print('start install application %s to ("%s":"%s")' % (app_name, client_addr[0], client_addr[1])) + res = install(self.conn_dict[client_addr], app_name, app_file) + if self.message_queues[s] is not None: + logging.info("response {} to cmd server".format(res)) + self.message_queues[s].put(bytes(res, encoding = 'utf8')) + if s not in self.outputs: + self.outputs.append(s) + elif(data.decode().split(':')[0] == "uninstall"): + client_addr = (data.decode().split(':')[1],int(data.decode().split(':')[2])) + app_name = data.decode().split(':')[3] + + if client_addr in self.conn_dict.keys(): + print("start uninstall") + res = uninstall(self.conn_dict[client_addr], app_name) + if self.message_queues[s] is not None: + logging.info("response {} to cmd server".format(res)) + self.message_queues[s].put(bytes(res, encoding = 'utf8')) + if s not in self.outputs: + self.outputs.append(s) + + + # if self.message_queues[s] is not None: + # self.message_queues[s].put(data) + # if s not in self.outputs: + # self.outputs.append(s) + else: + logging.warning(data) + + # Interpret empty result as closed connection + try: + for dev in self.devices: + if s == dev.conn: + self.devices.remove(dev) + # Stop listening for input on the connection + if s in self.outputs: + self.outputs.remove(s) + self.inputs.remove(s) + + # Remove message queue + if s in self.message_queues.keys(): + del self.message_queues[s] + s.close() + except OSError as e: + logging.error("OSError raised, unknown connection") + return "got it" + + def handler_send(self, writable): + # Handle outputs + for s in writable: + try: + message_queue = self.message_queues.get(s) + send_data = '' + if message_queue is not None: + send_data = message_queue.get_nowait() + except queue.Empty: + self.outputs.remove(s) + else: + # print "sending %s to %s " % (send_data, s.getpeername) + # print "send something" + if message_queue is not None: + s.send(send_data) + else: + print("client has closed") + # del message_queues[s] + # writable.remove(s) + # print "Client %s disconnected" % (client_address) + return "got it" + + def handler_exception(self, exceptional): + # # Handle "exceptional conditions" + for s in exceptional: + print('exception condition on', s.getpeername()) + # Stop listening for input on the connection + self.inputs.remove(s) + if s in self.outputs: + self.outputs.remove(s) + s.close() + + # Remove message queue + del self.message_queues[s] + return "got it" + + +def event_loop(tcpserver, inputs, outputs): + while inputs: + # Wait for at least one of the sockets to be ready for processing + print('waiting for the next event') + readable, writable, exceptional = select.select(inputs, outputs, inputs) + if readable is not None: + tcp_recever = tcpserver.handler_recever(readable) + if tcp_recever == 'got it': + print("server have received") + if writable is not None: + tcp_send = tcpserver.handler_send(writable) + if tcp_send == 'got it': + print("server have send") + if exceptional is not None: + tcp_exception = tcpserver.handler_exception(exceptional) + if tcp_exception == 'got it': + print("server have exception") + + + sleep(0.1) + +def run_wasm_server(): + server_address = ('localhost', 8888) + server = socket.socket(socket.AF_INET, socket.SOCK_STREAM) + server.setsockopt(socket.SOL_SOCKET,socket.SO_REUSEADDR,1) + inputs = [server] + outputs = [] + message_queues = {} + tcpserver = TCPServer(server, server_address, inputs, outputs, message_queues) + + task = threading.Thread(target=event_loop,args=(tcpserver,inputs,outputs)) + task.start() + +if __name__ == '__main__': + logging.basicConfig(level=logging.DEBUG, + filename='wasm_server.log', + filemode='a', + format= + '%(asctime)s - %(pathname)s[line:%(lineno)d] - %(levelname)s: %(message)s' + ) + server_address = ('0.0.0.0', 8888) + server = socket.socket(socket.AF_INET, socket.SOCK_STREAM) + server.setsockopt(socket.SOL_SOCKET,socket.SO_REUSEADDR,1) + inputs = [server] + outputs = [] + message_queues = {} + tcpserver = TCPServer(server, server_address, inputs, outputs, message_queues) + logging.info("TCP Server start at {}:{}".format(server_address[0], "8888")) + + task = threading.Thread(target=event_loop,args=(tcpserver,inputs,outputs)) + task.start() + + # event_loop(tcpserver, inputs, outputs) \ No newline at end of file diff --git a/test-tools/IoT-APP-Store-Demo/wasm_django/static/css/application.css b/test-tools/IoT-APP-Store-Demo/wasm_django/static/css/application.css new file mode 100644 index 000000000..5876b9426 --- /dev/null +++ b/test-tools/IoT-APP-Store-Demo/wasm_django/static/css/application.css @@ -0,0 +1,411 @@ +/* Copyright (C) 2019 Intel Corporation. All rights reserved. +* +* Licensed 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. +*/ + +{% load static %} + diff --git a/test-tools/IoT-APP-Store-Demo/wasm_django/static/js/application.js b/test-tools/IoT-APP-Store-Demo/wasm_django/static/js/application.js new file mode 100644 index 000000000..d359962e3 --- /dev/null +++ b/test-tools/IoT-APP-Store-Demo/wasm_django/static/js/application.js @@ -0,0 +1,228 @@ +/* Copyright (C) 2019 Intel Corporation. All rights reserved. +* +* Licensed 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. +*/ + +/* + * Dom Location + * + */ + + function setDivCenter(divname) +// make qn element center aligned + { + var Top =($(window).height()-$(divname).height())/2; + var Left = ($(window).width()-$(divname).width())/2; + var scrollTop = $(document).scrollTop(); + var scrollLeft = $(document).scrollLeft(); + $(divname).css({posisiton:'absolute','top':Top+scrollTop,'left':Left+scrollLeft}); + +}; + +setDivCenter(".middlebox"); +setDivCenter(".deletebox"); + +function setmain(divname){ +// Set the pop-up window of apps for download at the right place + var x = $('#btn').offset().top; + var Top = x + $('#btn').height()+15; + var y = $('#btn').offset().left; + var Left = y + ($('#btn').width()/2)-($(divname).width()/2); + console.log(Top,Left) + $(divname).css({'top':Top,'left':Left}); +} +setmain(".main") + +/* + * download apps + * + */ + +function getthis(val) +//Telling background which app to be loaded from appstore_list and to be installed in the current device. +{ + + /* Get the ip adress and the port of a device, as well as the application ID to be downloaded on this device*/ + var ip,port,name,version; + var ipArr=$("#IPs").text().split(":"); + ip=ipArr[1]; + var portArr=$("#ports").text().split(":"); + port=portArr[1]; + name = $(val).parent().find("#appsinfo1").text().split(":")[1]; + version = $(val).parent().find("#appsinfo2").text().split(":")[1]; + $(".main").fadeOut(); + + for (num in alist){ + if (alist[num]['pname'].trim() == name.trim()) + {alert("This app has been downloaded."); + return;}}; + $("#loading").fadeIn(); + var sNode = document.getElementById("APPS"); + var tempNode= sNode.cloneNode(true); + sNode.parentNode.appendChild(tempNode); + $("#appinfo1").html("Product Name : "+ name); + $("#appinfo2").html("Status : "+"Installing"); + $("#appinfo3").html("Current_Version : "+ version); + + $.get("/appDownload/",{'ip':ip.trim(),'port':port.trim(),'name':name.trim(),},function (ret) { + var status = $.trim(ret.split(":")[1].split("}")[0]); + $(".loadapp").html(name+" is downloading now"); + var msg = JSON.parse(status) + console.log(msg) + if (JSON.parse(status)=="ok"){ + $(".middlebox").fadeIn(); + $(".sourceapp").fadeOut(); + $("#loading").fadeOut(); + $(".findapp").html("Download "+name +" successfully"); + $(".surebtn").click(function (){ + $(".middlebox").fadeOut(); + window.location.reload(); + })} + else if (JSON.parse(status)=="Fail!"){ + alert("Download failed!"); + $("#loading").fadeOut(); + sNode.remove(); + } + else { + alert("Install app failed:" + msg) + $("#loading").fadeOut(); + sNode.remove(); + } + }) +}; + +window.onload = function clone() +//Add & Delete apps to the device. +{ + /*Install Apps*/ + var sourceNode = document.getElementById("APPS"); + if (alist.length != 0) + { + $("#appinfo1").html("Product Name : "+ alist[0]['pname']); + $("#appinfo2").html("Status : "+ alist[0]['status']); + $("#appinfo3").html("Current_Version : "+ alist[0]['current_version']); + $("#delete").attr('class','delet0'); + $("#APPS").attr('class','app0'); + + for (var i=1; i=3){ + alert("Install app failed: exceed max app installations.") + } + $(".main").fadeOut(); + getthis(".mybtn2"); + var newurl = "?"+"ip="+ip+"&port="+port; + window.location.href= newurl; + }); + + } +} +givevalue(); + +function popbox(){ +/*Open and close the "install apps" window*/ + $(".btn").click(function(){ + $(".main").fadeIn(); + }); + $(".close").click(function(){ + $(".main").fadeOut(); + }); +}; +popbox(); diff --git a/test-tools/IoT-APP-Store-Demo/wasm_django/static/js/appstore.js b/test-tools/IoT-APP-Store-Demo/wasm_django/static/js/appstore.js new file mode 100644 index 000000000..911de1f08 --- /dev/null +++ b/test-tools/IoT-APP-Store-Demo/wasm_django/static/js/appstore.js @@ -0,0 +1,136 @@ +/* Copyright (C) 2019 Intel Corporation. All rights reserved. +* +* Licensed 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. +*/ + +function setDivCenter(divname) +//Center a dom +{ + var Top =($(window).height()-$(divname).height())/2; + var Left = ($(window).width()-$(divname).width())/2; + var scrollTop = $(document).scrollTop(); + var scrollLeft = $(document).scrollLeft(); + $(divname).css({posisiton:'absolute','top':Top+scrollTop,'left':Left+scrollLeft}); + +}; +setDivCenter(".deletebox"); + +function setDivheight(divname) +//set the height of "appbook" to contain all its child elements. +{ + var leng = elist.length + flist.length; + var heig = 51 * leng; + $(divname).css({height:'heig'}); +}; +setDivheight(".appbook"); + +function setfooterposition(divname) +//Locate footer on the right place +{ + var Top = flist.length* $("#devices").height()+300; + var scrollTop = $(document).scrollTop(); + if (flist.length >=4){ + $(divname).css({posisiton:'absolute','top':Top+scrollTop}); + } +} +setfooterposition(".footer"); + +function deleteClick (obj) +//Remove an app from apppstore if clicks the "OK" button +{ + var indexapp = $(obj).attr('class').match(/\d+\b/); + var removeitem = $(".applic"+indexapp); + var name=removeitem.find('#appinfo1').text().split(":")[1].trim(); + var version=removeitem.find('#appinfo2').text().split(":")[1].trim(); + + if (flist.length >= 1){ + $(".deletebox").fadeIn(); + $(".findapp").html("Are you sure to delete "+name); + $(".suresbtn").click(function (){ + removeitem.remove(); + $.get("/removeapps/",{'name':name,'version':version},function (ret) { + console.log(ret);}); + $(".deletebox").fadeOut(); + window.location.href="/appstore/"; + }) + $(".delsbtn").click(function (){ + $(".deletebox").fadeOut(); })} +}; + +function upload_file() +//Make sure the uploading file is eligible +{ + var type = ulist[0]; + console.log(type); + if (type == "Not a wasm file"){ + alert(type); + window.location.href="/appstore/"; + } + if (type == "This App is preloaded"){ + alert(type); + window.location.href="/appstore/"; + } + if (type == "This App is already uploaded"){ + alert(type); + window.location.href="/appstore/"; + } +}; +upload_file(); + + +function clone() +//Render a interface that shows all the apps for installing in appstore, +//including preloaded ones and locally uploaded ones. +{ + + var sourceNode = document.getElementById("applications"); + $("#appinfo1").html("product name : "+ elist[0]['ID']); + $("#appinfo2").html("product Version : "+ elist[0]['Version']); + $("#delbutton").attr('class','del0'); + $("#applications").attr('class','applic0'); + + + for (var i=1; i=4){ + $(divname).css({posisiton:'absolute','top':Top+scrollTop}); + } +} +setfooterposition(".footer"); + +window.onload = function clone() +//Show the list of connected devices +{ + var sourceNode = document.getElementById("devices"); + $("#IPs").html("IP : "+ dlist[0]['IP']); + $("#ports").html("Port : "+ dlist[0]['Port']); + $("#installs").html("Installed Apps : "+ dlist[0]['apps']); + $("#devices").attr('class','devic0'); + $("#dbutton").attr('class','bt0'); + $("#choose").attr('class','chos0'); + + for (var i=1; i