diff --git a/README.md b/README.md index 4f89bb767..6d89814d9 100644 --- a/README.md +++ b/README.md @@ -53,7 +53,7 @@ Execute following commands to build **wamrc** compiler: ```shell cd wamr-compiler -./build_llvm.sh +./build_llvm.sh (use build_llvm_xtensa.sh instead to support xtensa target) mkdir build && cd build cmake .. make diff --git a/core/iwasm/aot/aot_loader.c b/core/iwasm/aot/aot_loader.c index 50f1cdf39..006842211 100644 --- a/core/iwasm/aot/aot_loader.c +++ b/core/iwasm/aot/aot_loader.c @@ -985,14 +985,21 @@ load_text_section(const uint8 *buf, const uint8 *buf_end, return false; } - module->code = (void*)buf; - module->code_size = (uint32)(buf_end - buf); + read_uint32(buf, buf_end, module->literal_size); + + /* literal data is at begining of the text section */ + module->literal = (uint8*)buf; + module->code = (void*)(buf + module->literal_size); + module->code_size = (uint32)(buf_end - (uint8*)module->code); if (module->code_size > 0) { plt_base = (uint8*)buf_end - get_plt_table_size(); init_plt_table(plt_base); } return true; + +fail: + return false; } static bool @@ -1184,13 +1191,20 @@ resolve_target_sym(const char *symbol, int32 *p_index) return NULL; } +static bool +is_literal_relocation(const char *reloc_sec_name) +{ + return !strcmp(reloc_sec_name, ".rela.literal"); +} + static bool do_text_relocation(AOTModule *module, AOTRelocationGroup *group, char *error_buf, uint32 error_buf_size) { - uint8 *aot_text = module->code; - uint32 aot_text_size = module->code_size; + bool is_literal = is_literal_relocation(group->section_name); + uint8 *aot_text = is_literal ? module->literal : module->code; + uint32 aot_text_size = is_literal ? module->literal_size : module->code_size; uint32 i, func_index, symbol_len; char symbol_buf[128] = { 0 }, *symbol, *p; void *symbol_addr; @@ -1248,6 +1262,9 @@ do_text_relocation(AOTModule *module, goto check_symbol_fail; } } + else if (!strcmp(symbol, ".literal")) { + symbol_addr = module->literal; + } else if (!(symbol_addr = resolve_target_sym(symbol, &symbol_index))) { if (error_buf != NULL) snprintf(error_buf, error_buf_size, @@ -1495,7 +1512,8 @@ load_relocation_section(const uint8 *buf, const uint8 *buf_end, } if (!strcmp(group->section_name, ".rel.text") - || !strcmp(group->section_name, ".rela.text")) { + || !strcmp(group->section_name, ".rela.text") + || !strcmp(group->section_name, ".rela.literal")) { if (!do_text_relocation(module, group, error_buf, error_buf_size)) return false; } @@ -2079,8 +2097,11 @@ aot_unload(AOTModule *module) if (module->const_str_set) bh_hash_map_destroy(module->const_str_set); - if (module->code) - os_munmap(module->code, module->code_size); + if (module->code) { + uint8 *mmap_addr = module->literal - sizeof(module->literal_size); + uint32 total_size = sizeof(module->literal_size) + module->literal_size + module->code_size; + os_munmap(mmap_addr, total_size); + } if (module->data_sections) destroy_object_data_sections(module->data_sections, diff --git a/core/iwasm/aot/aot_runtime.h b/core/iwasm/aot/aot_runtime.h index 32d806025..35edd1686 100644 --- a/core/iwasm/aot/aot_runtime.h +++ b/core/iwasm/aot/aot_runtime.h @@ -125,6 +125,10 @@ typedef struct AOTModule { void *code; uint32 code_size; + /* literal for AOTed code, NULL for JIT mode */ + uint8 *literal; + uint32 literal_size; + /* data sections in AOT object file, including .data, .rodata * and .rodata.cstN. NULL for JIT mode. */ AOTObjectDataSection *data_sections; diff --git a/core/iwasm/aot/arch/aot_reloc_xtensa.c b/core/iwasm/aot/arch/aot_reloc_xtensa.c index 24c0db78e..ea04070f6 100644 --- a/core/iwasm/aot/arch/aot_reloc_xtensa.c +++ b/core/iwasm/aot/arch/aot_reloc_xtensa.c @@ -5,10 +5,50 @@ #include "aot_reloc.h" +#define R_XTENSA_32 1 /* Direct 32 bit */ +#define R_XTENSA_SLOT0_OP 20 /* PC relative */ + +/* for soft-float */ +void __floatsidf(); +void __divdf3(); +void __ltdf2(); + +/* for mul32 */ +void __mulsi3(); +void __muldi3(); + +void __modsi3(); + +void __divdi3(); + static SymbolMap target_sym_map[] = { - REG_COMMON_SYMBOLS + REG_COMMON_SYMBOLS, + + /* API's for soft-float */ + /* TODO: only register these symbols when Floating-Point Coprocessor + * Option is not enabled */ + REG_SYM(__floatsidf), + REG_SYM(__divdf3), + REG_SYM(__ltdf2), + + /* API's for 32-bit integer multiply */ + /* TODO: only register these symbols when 32-bit Integer Multiply Option + * is not enabled */ + REG_SYM(__mulsi3), + REG_SYM(__muldi3), + + REG_SYM(__modsi3), + + REG_SYM(__divdi3), }; +static void +set_error_buf(char *error_buf, uint32 error_buf_size, const char *string) +{ + if (error_buf != NULL) + snprintf(error_buf, error_buf_size, "%s", string); +} + SymbolMap * get_target_symbol_map(uint32 *sym_num) { @@ -40,6 +80,67 @@ get_plt_table_size() return get_plt_item_size() * (sizeof(target_sym_map) / sizeof(SymbolMap)); } +static bool +check_reloc_offset(uint32 target_section_size, + uint64 reloc_offset, uint32 reloc_data_size, + char *error_buf, uint32 error_buf_size) +{ + if (!(reloc_offset < (uint64)target_section_size + && reloc_offset + reloc_data_size <= (uint64)target_section_size)) { + set_error_buf(error_buf, error_buf_size, + "AOT module load failed: invalid relocation offset."); + return false; + } + return true; +} + +/* + * CPU like esp32 can read and write data through the instruction bus, but only + * in a word aligned manner; non-word-aligned access will cause a CPU exception. + * This function uses a world aligned manner to write 16bit value to instruction + * addreess. + */ +static void +put_imm16_to_addr(int16 imm16, int16 *addr) +{ + int8 bytes[8]; + int32 *addr_aligned1, *addr_aligned2; + + addr_aligned1 = (int32*)((intptr_t)addr & ~3); + + if ((intptr_t)addr % 4 != 3) { + *(int32*)bytes = *addr_aligned1; + *(int16*)(bytes + ((intptr_t)addr % 4)) = imm16; + memcpy(addr_aligned1, bytes, 4); + } + else { + addr_aligned2 = (int32*)(((intptr_t)addr + 3) & ~3); + *(int32*)bytes = *addr_aligned1; + *(int32*)(bytes + 4) = *addr_aligned2; + *(int16*)(bytes + 3) = imm16; + memcpy(addr_aligned1, bytes, 8); + } +} + +static union { + int a; + char b; +} __ue = { .a = 1 }; + +#define is_little_endian() (__ue.b == 1) + +typedef union { + struct l32r_le { + int8 other; + int16 imm16; + } __packed l; + + struct l32r_be { + int16 imm16; + int8 other; + } __packed b; +} l32r_insn_t; + bool apply_relocation(AOTModule *module, uint8 *target_section_addr, uint32 target_section_size, @@ -48,7 +149,73 @@ apply_relocation(AOTModule *module, char *error_buf, uint32 error_buf_size) { switch (reloc_type) { - /* TODO: implement relocation for xtensa */ + case R_XTENSA_32: + { + uint8 *insn_addr = target_section_addr + reloc_offset; + int32 initial_addend; + /* (S + A) */ + if ((intptr_t)insn_addr & 3) { + set_error_buf(error_buf, error_buf_size, + "AOT module load failed: " + "instruction address unaligned."); + return false; + } + CHECK_RELOC_OFFSET(4); + initial_addend = *(int32*)insn_addr; + *(uint8**)insn_addr + = (uint8*)symbol_addr + initial_addend + reloc_addend; + break; + } + + case R_XTENSA_SLOT0_OP: + { + uint8 *insn_addr = target_section_addr + reloc_offset; + /* Currently only l32r instruction generates R_XTENSA_SLOT0_OP relocation */ + l32r_insn_t *l32r_insn = (l32r_insn_t *)insn_addr; + uint8 *reloc_addr; + int32 relative_offset/*, initial_addend */; + int16 imm16; + + CHECK_RELOC_OFFSET(3); /* size of l32r instruction */ + + /* + imm16 = is_little_endian() ? + l32r_insn->l.imm16 : l32r_insn->b.imm16; + initial_addend = (int32)imm16 << 2; + */ + + reloc_addr = (uint8*)symbol_addr + reloc_addend; + + if ((intptr_t)reloc_addr & 3) { + set_error_buf(error_buf, error_buf_size, + "AOT module load failed: " + "relocation address unaligned."); + return false; + } + + relative_offset = (int32) + ((intptr_t)reloc_addr - + (((intptr_t)insn_addr + 3) & ~(intptr_t)3)); + /* relative_offset += initial_addend; */ + + /* check relative offset boundary */ + if (relative_offset < -256 * BH_KB || relative_offset > -4) { + set_error_buf(error_buf, error_buf_size, + "AOT module load failed: " + "target address out of range."); + return false; + } + + imm16 = (int16)(relative_offset >> 2); + + /* write back the imm16 to the l32r instruction */ + if (is_little_endian()) + put_imm16_to_addr(imm16, &l32r_insn->l.imm16); + else + put_imm16_to_addr(imm16, &l32r_insn->b.imm16); + + break; + } default: if (error_buf != NULL) diff --git a/core/iwasm/compilation/aot_emit_aot_file.c b/core/iwasm/compilation/aot_emit_aot_file.c index c2d2f6e3e..20675f224 100644 --- a/core/iwasm/compilation/aot_emit_aot_file.c +++ b/core/iwasm/compilation/aot_emit_aot_file.c @@ -49,6 +49,10 @@ typedef struct AOTObjectData { void *text; uint32 text_size; + /* literal data and size */ + void *literal; + uint32 literal_size; + AOTObjectDataSection *data_sections; uint32 data_sections_count; @@ -379,7 +383,7 @@ get_init_data_section_size(AOTCompData *comp_data, AOTObjectData *obj_data) static uint32 get_text_section_size(AOTObjectData *obj_data) { - return obj_data->text_size; + return (sizeof(uint32) + obj_data->literal_size + obj_data->text_size + 3) & ~3; } static uint32 @@ -1118,13 +1122,20 @@ aot_emit_text_section(uint8 *buf, uint8 *buf_end, uint32 *p_offset, { uint32 section_size = get_text_section_size(obj_data); uint32 offset = *p_offset; + uint8 placeholder = 0; *p_offset = offset = align_uint(offset, 4); EMIT_U32(AOT_SECTION_TYPE_TEXT); EMIT_U32(section_size); + EMIT_U32(obj_data->literal_size); + if (obj_data->literal_size > 0) + EMIT_BUF(obj_data->literal, obj_data->literal_size); EMIT_BUF(obj_data->text, obj_data->text_size); + while (offset & 3) + EMIT_BUF(&placeholder, 1); + if (offset - *p_offset != section_size + sizeof(uint32) * 2) { aot_set_last_error("emit text section failed."); return false; @@ -1449,6 +1460,29 @@ aot_resolve_text(AOTObjectData *obj_data) return true; } +static bool +aot_resolve_literal(AOTObjectData *obj_data) +{ + LLVMSectionIteratorRef sec_itr; + char *name; + + if (!(sec_itr = LLVMObjectFileCopySectionIterator(obj_data->binary))) { + aot_set_last_error("llvm get section iterator failed."); + return false; + } + while (!LLVMObjectFileIsSectionIteratorAtEnd(obj_data->binary, sec_itr)) { + if ((name = (char *)LLVMGetSectionName(sec_itr)) && !strcmp(name, ".literal")) { + obj_data->literal = (char *)LLVMGetSectionContents(sec_itr); + obj_data->literal_size = (uint32)LLVMGetSectionSize(sec_itr); + break; + } + LLVMMoveToNextSection(sec_itr); + } + LLVMDisposeSectionIterator(sec_itr); + + return true; +} + static bool is_data_section(char *section_name) { @@ -1701,6 +1735,7 @@ is_relocation_section(char *section_name) { return (!strcmp(section_name, ".rela.text") || !strcmp(section_name, ".rel.text") + || !strcmp(section_name, ".rela.literal") || !strcmp(section_name, ".rela.data") || !strcmp(section_name, ".rel.data") || !strcmp(section_name, ".rela.rodata") @@ -1873,6 +1908,7 @@ aot_obj_data_create(AOTCompContext *comp_ctx) /* resolve target info/text/relocations/functions */ if (!aot_resolve_target_info(comp_ctx, obj_data) || !aot_resolve_text(obj_data) + || !aot_resolve_literal(obj_data) || !aot_resolve_object_data_sections(obj_data) || !aot_resolve_object_relocation_groups(obj_data) || !aot_resolve_functions(comp_ctx, obj_data)) diff --git a/core/iwasm/compilation/aot_emit_numberic.c b/core/iwasm/compilation/aot_emit_numberic.c index 62ea6cc8c..de50db3d0 100644 --- a/core/iwasm/compilation/aot_emit_numberic.c +++ b/core/iwasm/compilation/aot_emit_numberic.c @@ -858,18 +858,63 @@ fail: } static bool -is_targeting_soft_float(LLVMTargetMachineRef target_machine) +is_target_arm(AOTCompContext *comp_ctx) +{ + return !strncmp(comp_ctx->target_arch, "arm", 3) || + !strncmp(comp_ctx->target_arch, "thumb", 5); +} + +static bool +is_target_x86(AOTCompContext *comp_ctx) +{ + return !strncmp(comp_ctx->target_arch, "x86_64", 6) || + !strncmp(comp_ctx->target_arch, "i386", 4); +} + +static bool +is_target_xtensa(AOTCompContext *comp_ctx) +{ + return !strncmp(comp_ctx->target_arch, "xtensa", 6); +} + +static bool +is_target_mips(AOTCompContext *comp_ctx) +{ + return !strncmp(comp_ctx->target_arch, "mips", 4); +} + +static bool +is_targeting_soft_float(AOTCompContext *comp_ctx, bool is_f32) { bool ret = false; char *feature_string; if (!(feature_string = - LLVMGetTargetMachineFeatureString(target_machine))) { + LLVMGetTargetMachineFeatureString(comp_ctx->target_machine))) { aot_set_last_error("llvm get target machine feature string fail."); return false; } - ret = strstr(feature_string, "+soft-float") ? true : false; + /* Note: + * LLVM CodeGen uses FPU Coprocessor registers by default, + * so user must specify '--cpu-features=+soft-float' to wamrc if the target + * doesn't have or enable FPU on arm, x86 or mips. */ + if (is_target_arm(comp_ctx) || + is_target_x86(comp_ctx) || + is_target_mips(comp_ctx)) + ret = strstr(feature_string, "+soft-float") ? true : false; + else if (is_target_xtensa(comp_ctx)) + /* Note: + * 1. The Floating-Point Coprocessor Option of xtensa only support + * single-precision floating-point operations, so must use soft-float + * for f64(i.e. double). + * 2. LLVM CodeGen uses Floating-Point Coprocessor registers by default, + * so user must specify '--cpu-features=-fp' to wamrc if the target + * doesn't have or enable Floating-Point Coprocessor Option on xtensa. */ + ret = (!is_f32 || strstr(feature_string, "-fp")) ? true : false; + else + ret = true; + LLVMDisposeMessage(feature_string); return ret; } @@ -880,7 +925,7 @@ compile_op_float_arithmetic(AOTCompContext *comp_ctx, AOTFuncContext *func_ctx, { switch (arith_op) { case FLOAT_ADD: - if (is_targeting_soft_float(comp_ctx->target_machine)) + if (is_targeting_soft_float(comp_ctx, is_f32)) DEF_FP_BINARY_OP(LLVMBuildFAdd(comp_ctx->builder, left, right, "fadd"), "llvm build fadd fail."); else @@ -897,7 +942,7 @@ compile_op_float_arithmetic(AOTCompContext *comp_ctx, AOTFuncContext *func_ctx, NULL); return true; case FLOAT_SUB: - if (is_targeting_soft_float(comp_ctx->target_machine)) + if (is_targeting_soft_float(comp_ctx, is_f32)) DEF_FP_BINARY_OP(LLVMBuildFSub(comp_ctx->builder, left, right, "fsub"), "llvm build fsub fail."); else @@ -914,7 +959,7 @@ compile_op_float_arithmetic(AOTCompContext *comp_ctx, AOTFuncContext *func_ctx, NULL); return true; case FLOAT_MUL: - if (is_targeting_soft_float(comp_ctx->target_machine)) + if (is_targeting_soft_float(comp_ctx, is_f32)) DEF_FP_BINARY_OP(LLVMBuildFMul(comp_ctx->builder, left, right, "fmul"), "llvm build fmul fail."); else @@ -931,7 +976,7 @@ compile_op_float_arithmetic(AOTCompContext *comp_ctx, AOTFuncContext *func_ctx, NULL); return true; case FLOAT_DIV: - if (is_targeting_soft_float(comp_ctx->target_machine)) + if (is_targeting_soft_float(comp_ctx, is_f32)) DEF_FP_BINARY_OP(LLVMBuildFDiv(comp_ctx->builder, left, right, "fdiv"), "llvm build fdiv fail."); else @@ -1050,7 +1095,7 @@ compile_op_float_math(AOTCompContext *comp_ctx, AOTFuncContext *func_ctx, NULL); return true; case FLOAT_SQRT: - if (is_targeting_soft_float(comp_ctx->target_machine)) + if (is_targeting_soft_float(comp_ctx, is_f32)) DEF_FP_UNARY_OP(call_llvm_float_math_intrinsic(comp_ctx, is_f32 ? "llvm.sqrt.f32" : "llvm.sqrt.f64", diff --git a/core/iwasm/compilation/aot_llvm.c b/core/iwasm/compilation/aot_llvm.c index c903a0c8e..37f8c20fd 100644 --- a/core/iwasm/compilation/aot_llvm.c +++ b/core/iwasm/compilation/aot_llvm.c @@ -740,6 +740,7 @@ typedef struct ArchItem { static ArchItem valid_archs[] = { { "x86_64", false }, { "i386", false }, + { "xtensa", false}, { "mips", true }, { "aarch64v8", false }, { "aarch64v8.1", false }, diff --git a/core/shared/platform/zephyr/platform_internal.h b/core/shared/platform/zephyr/platform_internal.h index 00a199fb2..c208bacd4 100644 --- a/core/shared/platform/zephyr/platform_internal.h +++ b/core/shared/platform/zephyr/platform_internal.h @@ -77,4 +77,24 @@ unsigned long long int strtoull(const char *nptr, char **endptr, int base); double strtod(const char *nptr, char **endptr); float strtof(const char *nptr, char **endptr); +/** + * @brief Allocate executable memroy + * + * @param size size of the memory to be allocated + * + * @return the address of the allocated memory if not NULL + */ +typedef void* (*exec_mem_alloc_func_t)(unsigned int size); + +/** + * @brief Release executable memroy + * + * @param the address of the executable memory to be released + */ +typedef void (*exec_mem_free_func_t)(void *addr); + +/* Below function are called by external project to set related function pointers that + * will be used to malloc/free executable memory. Otherwise default mechanise will be used. */ +void set_exec_mem_alloc_func(exec_mem_alloc_func_t alloc_func, exec_mem_free_func_t free_func); + #endif diff --git a/core/shared/platform/zephyr/zephyr_platform.c b/core/shared/platform/zephyr/zephyr_platform.c index fd7c48e04..0f52d1105 100644 --- a/core/shared/platform/zephyr/zephyr_platform.c +++ b/core/shared/platform/zephyr/zephyr_platform.c @@ -6,6 +6,10 @@ #include "platform_api_vmcore.h" #include "platform_api_extension.h" +/* function pointers for executable memory management */ +static exec_mem_alloc_func_t exec_mem_alloc_func = NULL; +static exec_mem_free_func_t exec_mem_free_func = NULL; + #if WASM_ENABLE_AOT != 0 #ifdef CONFIG_ARM_MPU /** @@ -108,13 +112,19 @@ os_vprintf(const char *fmt, va_list ap) void * os_mmap(void *hint, unsigned int size, int prot, int flags) { - return BH_MALLOC(size); + if (exec_mem_alloc_func) + return exec_mem_alloc_func(size); + else + return BH_MALLOC(size); } void os_munmap(void *addr, uint32 size) { - return BH_FREE(addr); + if (exec_mem_free_func) + exec_mem_free_func(addr); + else + BH_FREE(addr); } int @@ -133,3 +143,11 @@ os_dcache_flush() irq_unlock(key); #endif } + +void set_exec_mem_alloc_func(exec_mem_alloc_func_t alloc_func, + exec_mem_free_func_t free_func) +{ + exec_mem_alloc_func = alloc_func; + exec_mem_free_func = free_func; +} + diff --git a/doc/build_wamr.md b/doc/build_wamr.md index 602892a46..3bc01a485 100644 --- a/doc/build_wamr.md +++ b/doc/build_wamr.md @@ -277,14 +277,13 @@ AliOS-Things aos make ./out/helloworld@linuxhost/binary/helloworld@linuxhost.elf ``` -``` - + For developerkit: Modify file middleware/iwasm/aos.mk, patch as: ``` C -WAMR_BUILD_TARGET := THUMBV7M -``` + WAMR_BUILD_TARGET := THUMBV7M + ``` ``` Bash aos make helloworld@developerkit -c config diff --git a/doc/build_wasm_app.md b/doc/build_wasm_app.md index 2cf6239cc..39b6ed977 100644 --- a/doc/build_wasm_app.md +++ b/doc/build_wasm_app.md @@ -90,7 +90,7 @@ wamrc supports a number of compilation options through the command line argument wamrc --help Usage: wamrc [options] -o output_file wasm_file --target= Set the target arch, which has the general format: - = x86_64, i386, arm, thumb, mips. + = x86_64, i386, aarch64, arm, thumb, xtensa, mips. Default is host arch, e.g. x86_64 = for ex. on arm or thumb: v5, v6m, v7a, v7m, etc. Use --target=help to list supported targets diff --git a/product-mini/platforms/alios-things/aos.mk b/product-mini/platforms/alios-things/aos.mk index 246f8c920..4cdf95dda 100644 --- a/product-mini/platforms/alios-things/aos.mk +++ b/product-mini/platforms/alios-things/aos.mk @@ -92,6 +92,7 @@ $(NAME)_SOURCES := ${SHARED_ROOT}/platform/alios/alios_platform.c \ ${SHARED_ROOT}/utils/bh_log.c \ ${SHARED_ROOT}/utils/bh_queue.c \ ${SHARED_ROOT}/utils/bh_vector.c \ + ${SHARED_ROOT}/utils/runtime_timer.c \ ${IWASM_ROOT}/libraries/libc-builtin/libc_builtin_wrapper.c \ ${IWASM_ROOT}/common/wasm_runtime_common.c \ ${IWASM_ROOT}/common/wasm_native.c \ diff --git a/product-mini/platforms/zephyr/simple/CMakeLists.txt b/product-mini/platforms/zephyr/simple/CMakeLists.txt index 60aab2ba8..affa755ab 100644 --- a/product-mini/platforms/zephyr/simple/CMakeLists.txt +++ b/product-mini/platforms/zephyr/simple/CMakeLists.txt @@ -37,48 +37,10 @@ if (NOT DEFINED WAMR_BUILD_LIBC_WASI) endif () set (WAMR_ROOT_DIR ${CMAKE_CURRENT_SOURCE_DIR}/wamr) -set (SHARED_DIR ${WAMR_ROOT_DIR}/core/shared) -set (IWASM_DIR ${WAMR_ROOT_DIR}/core/iwasm) -set (APP_FRAMEWORK_DIR ${WAMR_ROOT_DIR}/core/app-framework) -# include the build config template makefile -include (${WAMR_ROOT_DIR}/build-scripts/config_common.cmake) - -include_directories (${SHARED_DIR}/include - ${IWASM_DIR}/include) - -include (${SHARED_DIR}/platform/${WAMR_BUILD_PLATFORM}/shared_platform.cmake) -include (${SHARED_DIR}/mem-alloc/mem_alloc.cmake) -include (${SHARED_DIR}/utils/shared_utils.cmake) -if (WAMR_BUILD_LIBC_BUILTIN EQUAL 1) - include (${IWASM_DIR}/libraries/libc-builtin/libc_builtin.cmake) -endif () -if (WAMR_BUILD_LIBC_WASI EQUAL 1) - include (${IWASM_DIR}/libraries/libc-wasi/libc_wasi.cmake) -endif () - -include (${IWASM_DIR}/common/iwasm_common.cmake) - -if (WAMR_BUILD_INTERP EQUAL 1 OR WAMR_BUILD_JIT EQUAL 1) - include (${IWASM_DIR}/interpreter/iwasm_interp.cmake) -endif() - -if (WAMR_BUILD_AOT EQUAL 1) - include (${IWASM_DIR}/aot/iwasm_aot.cmake) -endif () - -set (VM_LIB_SRCS - ${PLATFORM_SHARED_SOURCE} - ${MEM_ALLOC_SHARED_SOURCE} - ${UTILS_SHARED_SOURCE} - ${LIBC_BUILTIN_SOURCE} - ${LIBC_WASI_SOURCE} - ${IWASM_COMMON_SOURCE} - ${IWASM_INTERP_SOURCE} - ${IWASM_AOT_SOURCE} - ${IWASM_COMPL_SOURCE}) +include (${WAMR_ROOT_DIR}/build-scripts/runtime_lib.cmake) target_sources(app PRIVATE - ${VM_LIB_SRCS} + ${WAMR_RUNTIME_LIB_SOURCE} src/main.c) diff --git a/product-mini/platforms/zephyr/simple/build.sh b/product-mini/platforms/zephyr/simple/build.sh index 6656baf0e..245af8ac7 100755 --- a/product-mini/platforms/zephyr/simple/build.sh +++ b/product-mini/platforms/zephyr/simple/build.sh @@ -6,14 +6,18 @@ X86_TARGET="x86" STM32_TARGET="stm32" QEMU_CORTEX_A53="qemu_cortex_a53" +XTENSA_QEMU_TARGET="xtensa-qemu" +ESP32_TARGET="esp32" if [ $# != 1 ] ; then echo "USAGE:" - echo "$0 $X86_TARGET|$STM32_TARGET|$QEMU_CORTEX_A53" + echo "$0 $X86_TARGET|$STM32_TARGET|$QEMU_CORTEX_A53|$XTENSA_QEMU_TARGET|$ESP32_TARGET" echo "Example:" echo " $0 $X86_TARGET" echo " $0 $STM32_TARGET" echo " $0 $QEMU_CORTEX_A53" + echo " $0 $XTENSA_QEMU_TARGET" + echo " $0 $ESP32_TARGET" exit 1 fi @@ -31,6 +35,21 @@ elif [ "$TARGET" = "$STM32_TARGET" ] ; then cmake -GNinja -DBOARD=nucleo_f767zi -DWAMR_BUILD_TARGET=THUMBV7 .. ninja ninja flash +elif [ "$TARGET" = "$XTENSA_QEMU_TARGET" ] ; then + cp prj_qemu_xtensa.conf prj.conf + rm -fr build && mkdir build && cd build + cmake -GNinja -DBOARD=qemu_xtensa -DWAMR_BUILD_TARGET=XTENSA .. + ninja + ninja run +elif [ "$TARGET" = "$ESP32_TARGET" ] ; then + # suppose you have set environment variable ESP_IDF_PATH + west build -b esp32 . -p always -- \ + -DESP_IDF_PATH=$ESP_IDF_PATH \ + -DCONF_FILE=prj_esp32.conf \ + -DWAMR_BUILD_TARGET=XTENSA + # suppose the serial port is /dev/ttyUSB1 and you should change to + # the real name accordingly + west flash -d ./build --skip-rebuild --esp-device /dev/ttyUSB1 elif [ "$TARGET" = "$QEMU_CORTEX_A53" ] ; then cp prj_qemu_cortex_a53.conf prj.conf rm -fr build && mkdir build && cd build diff --git a/product-mini/platforms/zephyr/simple/esp32_custom_linker.ld b/product-mini/platforms/zephyr/simple/esp32_custom_linker.ld new file mode 100644 index 000000000..35932050f --- /dev/null +++ b/product-mini/platforms/zephyr/simple/esp32_custom_linker.ld @@ -0,0 +1,274 @@ +/* + * Copyright (c) 2016 Cadence Design Systems, Inc. + * Copyright (c) 2017 Intel Corporation + * SPDX-License-Identifier: Apache-2.0 + */ + +/** + * @file + * @brief Linker command/script file + * + * Linker script for the Xtensa platform. + */ + +#include +#include +#include +#include +#include + +#define RAMABLE_REGION dram0_0_seg :dram0_0_phdr +#define RAMABLE_REGION1 dram0_1_seg :dram0_0_phdr +#define ROMABLE_REGION iram0_0_seg :iram0_0_phdr + +PROVIDE ( __stack = 0x3ffe3f20 ); + +PROVIDE ( esp32_rom_uart_tx_one_char = 0x40009200 ); +PROVIDE ( esp32_rom_uart_rx_one_char = 0x400092d0 ); +PROVIDE ( esp32_rom_uart_attach = 0x40008fd0 ); +PROVIDE ( esp32_rom_intr_matrix_set = 0x4000681c ); +PROVIDE ( esp32_rom_gpio_matrix_in = 0x40009edc ); +PROVIDE ( esp32_rom_gpio_matrix_out = 0x40009f0c ); +PROVIDE ( esp32_rom_Cache_Flush = 0x40009a14 ); +PROVIDE ( esp32_rom_Cache_Read_Enable = 0x40009a84 ); +PROVIDE ( esp32_rom_ets_set_appcpu_boot_addr = 0x4000689c ); + +MEMORY +{ + iram0_0_seg(RX): org = 0x40080000, len = 0x20000 + iram0_2_seg(RX): org = 0x400D0018, len = 0x330000 + dram0_0_seg(RW): org = 0x3FFB0000, len = 0x30000 + dram0_1_seg(RWX):org = 0x400A0000, len = 0x20000 + drom0_0_seg(R): org = 0x3F400010, len = 0x800000 + rtc_iram_seg(RWX): org = 0x400C0000, len = 0x2000 + rtc_slow_seg(RW): org = 0x50000000, len = 0x1000 +#ifdef CONFIG_GEN_ISR_TABLES + IDT_LIST(RW): org = 0x3ebfe010, len = 0x2000 +#endif +} + +PHDRS +{ + iram0_0_phdr PT_LOAD; + dram0_0_phdr PT_LOAD; +} + +/* Default entry point: */ +PROVIDE ( _ResetVector = 0x40000400 ); +ENTRY(CONFIG_KERNEL_ENTRY) + +_rom_store_table = 0; + +PROVIDE(_memmap_vecbase_reset = 0x40000450); +PROVIDE(_memmap_reset_vector = 0x40000400); + +SECTIONS +{ + +#include + + /* RTC fast memory holds RTC wake stub code, + including from any source file named rtc_wake_stub*.c + */ + .rtc.text : + { + . = ALIGN(4); + *(.rtc.literal .rtc.text) + *rtc_wake_stub*.o(.literal .text .literal.* .text.*) + } >rtc_iram_seg + + /* RTC slow memory holds RTC wake stub + data/rodata, including from any source file + named rtc_wake_stub*.c + */ + .rtc.data : + { + _rtc_data_start = ABSOLUTE(.); + *(.rtc.data) + *(.rtc.rodata) + *rtc_wake_stub*.o(.data .rodata .data.* .rodata.* .bss .bss.*) + _rtc_data_end = ABSOLUTE(.); + } > rtc_slow_seg + + /* RTC bss, from any source file named rtc_wake_stub*.c */ + .rtc.bss (NOLOAD) : + { + _rtc_bss_start = ABSOLUTE(.); + *rtc_wake_stub*.o(.bss .bss.*) + *rtc_wake_stub*.o(COMMON) + _rtc_bss_end = ABSOLUTE(.); + } > rtc_slow_seg + + /* Send .iram0 code to iram */ + .iram0.vectors : ALIGN(4) + { + /* Vectors go to IRAM */ + _init_start = ABSOLUTE(.); + /* Vectors according to builds/RF-2015.2-win32/esp108_v1_2_s5_512int_2/config.html */ + . = 0x0; + KEEP(*(.WindowVectors.text)); + . = 0x180; + KEEP(*(.Level2InterruptVector.text)); + . = 0x1c0; + KEEP(*(.Level3InterruptVector.text)); + . = 0x200; + KEEP(*(.Level4InterruptVector.text)); + . = 0x240; + KEEP(*(.Level5InterruptVector.text)); + . = 0x280; + KEEP(*(.DebugExceptionVector.text)); + . = 0x2c0; + KEEP(*(.NMIExceptionVector.text)); + . = 0x300; + KEEP(*(.KernelExceptionVector.text)); + . = 0x340; + KEEP(*(.UserExceptionVector.text)); + . = 0x3C0; + KEEP(*(.DoubleExceptionVector.text)); + . = 0x400; + *(.*Vector.literal) + + *(.UserEnter.literal); + *(.UserEnter.text); + . = ALIGN (16); + *(.entry.text) + *(.init.literal) + *(.init) + _init_end = ABSOLUTE(.); + + /* This goes here, not at top of linker script, so addr2line finds it last, + and uses it in preference to the first symbol in IRAM */ + _iram_start = ABSOLUTE(0); + } GROUP_LINK_IN(ROMABLE_REGION) + +#include +#include + + SECTION_PROLOGUE(_TEXT_SECTION_NAME, , ALIGN(4)) + { + /* Code marked as running out of IRAM */ + _iram_text_start = ABSOLUTE(.); + *(.iram1 .iram1.*) + *(.iram0.literal .iram.literal .iram.text.literal .iram0.text .iram.text) + *(.literal .text .literal.* .text.*) + _iram_text_end = ABSOLUTE(.); + } GROUP_LINK_IN(ROMABLE_REGION) + + .dram0.text : + { + _data_start = ABSOLUTE(.); + *(.aot_code_buf) + _data_end = ABSOLUTE(.); + . = ALIGN(4); + } GROUP_LINK_IN(RAMABLE_REGION1) + + + .dram0.data : + { + _data_start = ABSOLUTE(.); + *(.data) + *(.data.*) + *(.gnu.linkonce.d.*) + *(.data1) + *(.sdata) + *(.sdata.*) + *(.gnu.linkonce.s.*) + *(.sdata2) + *(.sdata2.*) + *(.gnu.linkonce.s2.*) + KEEP(*(.jcr)) + *(.dram1 .dram1.*) + _data_end = ABSOLUTE(.); + . = ALIGN(4); + } GROUP_LINK_IN(RAMABLE_REGION) + + SECTION_PROLOGUE(_RODATA_SECTION_NAME,,ALIGN(4)) + { + _rodata_start = ABSOLUTE(.); + *(.rodata) + *(.rodata.*) + *(.gnu.linkonce.r.*) + *(.rodata1) + __XT_EXCEPTION_TABLE__ = ABSOLUTE(.); + KEEP (*(.xt_except_table)) + KEEP (*(.gcc_except_table .gcc_except_table.*)) + *(.gnu.linkonce.e.*) + *(.gnu.version_r) + KEEP (*(.eh_frame)) + /* C++ constructor and destructor tables, properly ordered: */ + KEEP (*crtbegin.o(.ctors)) + KEEP (*(EXCLUDE_FILE (*crtend.o) .ctors)) + KEEP (*(SORT(.ctors.*))) + KEEP (*(.ctors)) + KEEP (*crtbegin.o(.dtors)) + KEEP (*(EXCLUDE_FILE (*crtend.o) .dtors)) + KEEP (*(SORT(.dtors.*))) + KEEP (*(.dtors)) + /* C++ exception handlers table: */ + __XT_EXCEPTION_DESCS__ = ABSOLUTE(.); + *(.xt_except_desc) + *(.gnu.linkonce.h.*) + __XT_EXCEPTION_DESCS_END__ = ABSOLUTE(.); + *(.xt_except_desc_end) + *(.dynamic) + *(.gnu.version_d) + . = ALIGN(4); /* this table MUST be 4-byte aligned */ + _rodata_end = ABSOLUTE(.); + } GROUP_LINK_IN(RAMABLE_REGION) + + + /* Shared RAM */ + SECTION_DATA_PROLOGUE(_BSS_SECTION_NAME,(NOLOAD),) + { + . = ALIGN (8); + _bss_start = ABSOLUTE(.); + *(.dynsbss) + *(.sbss) + *(.sbss.*) + *(.gnu.linkonce.sb.*) + *(.scommon) + *(.sbss2) + *(.sbss2.*) + *(.gnu.linkonce.sb2.*) + *(.dynbss) + *(.bss) + *(.bss.*) + *(.share.mem) + *(.gnu.linkonce.b.*) + *(COMMON) + . = ALIGN (8); + _bss_end = ABSOLUTE(.); + } GROUP_LINK_IN(RAMABLE_REGION) + + + SECTION_DATA_PROLOGUE(_APP_NOINIT_SECTION_NAME, (NOLOAD),) + { + . = ALIGN (8); + *(.app_noinit) + *("app_noinit.*") + . = ALIGN (8); + _app_end = ABSOLUTE(.); + } GROUP_LINK_IN(RAMABLE_REGION) + + + SECTION_DATA_PROLOGUE(_NOINIT_SECTION_NAME, (NOLOAD),) + { + . = ALIGN (8); + *(.noinit) + *(".noinit.*") + . = ALIGN (8); + _heap_start = ABSOLUTE(.); + } GROUP_LINK_IN(RAMABLE_REGION) + +#ifdef CONFIG_GEN_ISR_TABLES +#include +#endif + +#include + + SECTION_PROLOGUE(.xtensa.info, 0,) + { + *(.xtensa.info) + } + +} diff --git a/product-mini/platforms/zephyr/simple/prj_esp32.conf b/product-mini/platforms/zephyr/simple/prj_esp32.conf new file mode 100644 index 000000000..5d6a67f9d --- /dev/null +++ b/product-mini/platforms/zephyr/simple/prj_esp32.conf @@ -0,0 +1,8 @@ +# Copyright (C) 2019 Intel Corporation. All rights reserved. +# SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception + +CONFIG_STACK_SENTINEL=y +CONFIG_PRINTK=y +CONFIG_LOG=y +CONFIG_HAVE_CUSTOM_LINKER_SCRIPT=y +CONFIG_CUSTOM_LINKER_SCRIPT="esp32_custom_linker.ld" diff --git a/product-mini/platforms/zephyr/simple/prj_qemu_xtensa.conf b/product-mini/platforms/zephyr/simple/prj_qemu_xtensa.conf new file mode 100644 index 000000000..7f4a32832 --- /dev/null +++ b/product-mini/platforms/zephyr/simple/prj_qemu_xtensa.conf @@ -0,0 +1,6 @@ +# Copyright (C) 2019 Intel Corporation. All rights reserved. +# SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception + +CONFIG_STACK_SENTINEL=y +CONFIG_PRINTK=y +CONFIG_LOG=y diff --git a/product-mini/platforms/zephyr/simple/src/main.c b/product-mini/platforms/zephyr/simple/src/main.c index eb03f2acb..5079888ef 100644 --- a/product-mini/platforms/zephyr/simple/src/main.c +++ b/product-mini/platforms/zephyr/simple/src/main.c @@ -54,6 +54,54 @@ app_instance_main(wasm_module_inst_t module_inst) static char global_heap_buf[CONFIG_GLOBAL_HEAP_BUF_SIZE] = { 0 }; +#ifdef CONFIG_BOARD_ESP32 +#include "mem_alloc.h" +/* +esp32_technical_reference_manual: +" +The capacity of Internal SRAM 1 is 128 KB. Either CPU can read and write this memory at addresses +0x3FFE_0000 ~ 0x3FFF_FFFF of the data bus, and also at addresses 0x400A_0000 ~ 0x400B_FFFF of the +instruction bus. +" + +The custom linker script defines dram0_1_seg and map it to 0x400A_0000 ~ 0x400B_FFFF for instruction bus access. +Here we define the buffer that will be placed to dram0_1_seg. +*/ +static char esp32_executable_memory_buf[100 * 1024] __attribute__((section (".aot_code_buf"))) = { 0 }; + +/* the poll allocator for executable memory */ +static mem_allocator_t esp32_exec_mem_pool_allocator; + +static int +esp32_exec_mem_init() +{ + if (!(esp32_exec_mem_pool_allocator = + mem_allocator_create(esp32_executable_memory_buf, + sizeof(esp32_executable_memory_buf)))) + return -1; + + return 0; +} + +static void +esp32_exec_mem_destroy() +{ + mem_allocator_destroy(esp32_exec_mem_pool_allocator); +} + +static void * +esp32_exec_mem_alloc(unsigned int size) +{ + return mem_allocator_malloc(esp32_exec_mem_pool_allocator, size); +} + +static void +esp32_exec_mem_free(void *addr) +{ + mem_allocator_free(esp32_exec_mem_pool_allocator, addr); +} +#endif /* end of #ifdef CONFIG_BOARD_ESP32 */ + void iwasm_main(void *arg1, void *arg2, void *arg3) { int start, end; @@ -72,6 +120,7 @@ void iwasm_main(void *arg1, void *arg2, void *arg3) (void) arg2; (void) arg3; + memset(&init_args, 0, sizeof(RuntimeInitArgs)); init_args.mem_alloc_type = Alloc_With_Pool; @@ -84,6 +133,16 @@ void iwasm_main(void *arg1, void *arg2, void *arg3) return; } +#ifdef CONFIG_BOARD_ESP32 + /* Initialize executable memory */ + if (esp32_exec_mem_init() != 0) { + printf("Init executable memory failed.\n"); + goto fail1; + } + /* Set hook functions for executable memory management */ + set_exec_mem_alloc_func(esp32_exec_mem_alloc, esp32_exec_mem_free); +#endif + #if WASM_ENABLE_LOG != 0 bh_log_set_verbose_level(log_verbose_level); #endif @@ -96,7 +155,11 @@ void iwasm_main(void *arg1, void *arg2, void *arg3) if (!(wasm_module = wasm_runtime_load(wasm_file_buf, wasm_file_size, error_buf, sizeof(error_buf)))) { printf("%s\n", error_buf); +#ifdef CONFIG_BOARD_ESP32 + goto fail1_1; +#else goto fail1; +#endif } /* instantiate the module */ @@ -119,6 +182,12 @@ fail2: /* unload the module */ wasm_runtime_unload(wasm_module); +#ifdef CONFIG_BOARD_ESP32 +fail1_1: + /* destroy executable memory */ + esp32_exec_mem_destroy(); +#endif + fail1: /* destroy runtime environment */ wasm_runtime_destroy(); diff --git a/wamr-compiler/build_llvm_xtensa.sh b/wamr-compiler/build_llvm_xtensa.sh new file mode 100755 index 000000000..d41089c68 --- /dev/null +++ b/wamr-compiler/build_llvm_xtensa.sh @@ -0,0 +1,44 @@ +#!/bin/sh + +# Copyright (C) 2019 Intel Corporation. All rights reserved. +# SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception + +DEPS_DIR=${PWD}/../core/deps + +cd ${DEPS_DIR} +if [ ! -d "llvm" ]; then + echo "Clone llvm Xtensa to core/deps/ .." + git clone https://github.com/espressif/llvm-project.git llvm +fi + +cd llvm +mkdir -p build +cd build + +if [ ! -f bin/llvm-lto ]; then + + CORE_NUM=$(nproc --all) + if [ -z "${CORE_NUM}" ]; then + CORE_NUM=1 + fi + + echo "Build llvm with" ${CORE_NUM} "cores" + + cmake ../llvm \ + -DCMAKE_EXPORT_COMPILE_COMMANDS=ON \ + -DCMAKE_BUILD_TYPE:STRING="Release" \ + -DLLVM_EXPERIMENTAL_TARGETS_TO_BUILD:STRING="Xtensa" \ + -DLLVM_BUILD_LLVM_DYLIB:BOOL=OFF \ + -DLLVM_OPTIMIZED_TABLEGEN:BOOL=ON \ + -DLLVM_INCLUDE_EXAMPLES:BOOL=OFF \ + -DLLVM_INCLUDE_TESTS:BOOL=OFF \ + -DLLVM_INCLUDE_BENCHMARKS:BOOL=OFF \ + -DLLVM_APPEND_VC_REV:BOOL=OFF + make -j ${CORE_NUM} + +else + echo "llvm has already been built" +fi + +cd ${PWD} + diff --git a/wamr-compiler/main.c b/wamr-compiler/main.c index 181e8cdcf..9a9d212fa 100644 --- a/wamr-compiler/main.c +++ b/wamr-compiler/main.c @@ -14,7 +14,7 @@ print_help() { printf("Usage: wamrc [options] -o output_file wasm_file\n"); printf(" --target= Set the target arch, which has the general format: \n"); - printf(" = x86_64, i386, aarch64, arm, thumb, mips.\n"); + printf(" = x86_64, i386, aarch64, arm, thumb, xtensa, mips.\n"); printf(" Default is host arch, e.g. x86_64\n"); printf(" = for ex. on arm or thumb: v5, v6m, v7a, v7m, etc.\n"); printf(" Use --target=help to list supported targets\n");