Port WAMR to ESP-IDF (#892)
This PR introduces an implementation of the WAMR platform APIs for ESP-IDF and enables support for Espressif microcontrollers, and adds the documentation around how to build WAMR for ESP-IDF. This PR is related to the following issues at WAMR: closes #883, #628, #449 and #668 as well as [#4735](https://github.com/espressif/esp-idf/issues/4735) at the esp-idf repo. It implements most functions required by [platform_api_vmcore.h](https://github.com/bytecodealliance/wasm-micro-runtime/blob/main/core/shared/platform/include/platform_api_vmcore.h). The PR works in interpreter mode on Esp32c3 and Esp32. For the AOT mode, currently errors occur on both platforms with `Guru Meditation Error`. It seems that the AOT code isn't run with shared memory as os_mmap() allocates memory with malloc() API, it is to be fixed in the future.
This commit is contained in:
72
core/shared/platform/esp-idf/espidf_malloc.c
Normal file
72
core/shared/platform/esp-idf/espidf_malloc.c
Normal file
@ -0,0 +1,72 @@
|
||||
/*
|
||||
* Copyright (C) 2019 Intel Corporation. All rights reserved.
|
||||
* SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
|
||||
*/
|
||||
|
||||
#include "platform_api_vmcore.h"
|
||||
#include "platform_api_extension.h"
|
||||
|
||||
void *
|
||||
os_malloc(unsigned size)
|
||||
{
|
||||
void *buf_origin;
|
||||
void *buf_fixed;
|
||||
uintptr_t *addr_field;
|
||||
|
||||
buf_origin = malloc(size + 8 + sizeof(uintptr_t));
|
||||
buf_fixed = buf_origin + sizeof(void *);
|
||||
if ((uintptr_t)buf_fixed & (uintptr_t)0x7) {
|
||||
buf_fixed = (void *)((uintptr_t)(buf_fixed + 8) & (~(uintptr_t)7));
|
||||
}
|
||||
|
||||
addr_field = buf_fixed - sizeof(uintptr_t);
|
||||
*addr_field = (uintptr_t)buf_origin;
|
||||
|
||||
return buf_fixed;
|
||||
}
|
||||
|
||||
void *
|
||||
os_realloc(void *ptr, unsigned size)
|
||||
{
|
||||
void *mem_origin;
|
||||
void *mem_new;
|
||||
void *mem_new_fixed;
|
||||
uintptr_t *addr_field;
|
||||
|
||||
if (!ptr) {
|
||||
return NULL;
|
||||
}
|
||||
|
||||
addr_field = ptr - sizeof(uintptr_t);
|
||||
mem_origin = (void *)(*addr_field);
|
||||
mem_new = realloc(mem_origin, size + 8 + sizeof(uintptr_t));
|
||||
|
||||
if (mem_origin != mem_new) {
|
||||
mem_new_fixed = mem_new + sizeof(uintptr_t);
|
||||
if ((uint32)mem_new_fixed & 0x7) {
|
||||
mem_new_fixed =
|
||||
(void *)((uintptr_t)(mem_new + 8) & (~(uintptr_t)7));
|
||||
}
|
||||
|
||||
addr_field = mem_new_fixed - sizeof(uintptr_t);
|
||||
*addr_field = (uintptr_t)mem_new;
|
||||
|
||||
return mem_new_fixed;
|
||||
}
|
||||
|
||||
return ptr;
|
||||
}
|
||||
|
||||
void
|
||||
os_free(void *ptr)
|
||||
{
|
||||
void *mem_origin;
|
||||
uintptr *addr_field;
|
||||
|
||||
if (ptr) {
|
||||
addr_field = ptr - sizeof(uintptr_t);
|
||||
mem_origin = (void *)(*addr_field);
|
||||
|
||||
free(mem_origin);
|
||||
}
|
||||
}
|
||||
29
core/shared/platform/esp-idf/espidf_memmap.c
Normal file
29
core/shared/platform/esp-idf/espidf_memmap.c
Normal file
@ -0,0 +1,29 @@
|
||||
/*
|
||||
* Copyright (C) 2019 Intel Corporation. All rights reserved.
|
||||
* SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
|
||||
*/
|
||||
|
||||
#include "platform_api_vmcore.h"
|
||||
#include "platform_api_extension.h"
|
||||
|
||||
void *
|
||||
os_mmap(void *hint, size_t size, int prot, int flags)
|
||||
{
|
||||
return os_malloc((int)size);
|
||||
}
|
||||
|
||||
void
|
||||
os_munmap(void *addr, size_t size)
|
||||
{
|
||||
return os_free(addr);
|
||||
}
|
||||
|
||||
int
|
||||
os_mprotect(void *addr, size_t size, int prot)
|
||||
{
|
||||
return 0;
|
||||
}
|
||||
|
||||
void
|
||||
os_dcache_flush()
|
||||
{}
|
||||
@ -6,25 +6,15 @@
|
||||
#include "platform_api_vmcore.h"
|
||||
#include "platform_api_extension.h"
|
||||
|
||||
int errno = 0;
|
||||
|
||||
int
|
||||
os_thread_sys_init();
|
||||
|
||||
void
|
||||
os_thread_sys_destroy();
|
||||
|
||||
int
|
||||
bh_platform_init()
|
||||
{
|
||||
return os_thread_sys_init();
|
||||
return 0;
|
||||
}
|
||||
|
||||
void
|
||||
bh_platform_destroy()
|
||||
{
|
||||
os_thread_sys_destroy();
|
||||
}
|
||||
{}
|
||||
|
||||
int
|
||||
os_printf(const char *format, ...)
|
||||
@ -45,76 +35,20 @@ os_vprintf(const char *format, va_list ap)
|
||||
return vprintf(format, ap);
|
||||
}
|
||||
|
||||
void *
|
||||
os_mmap(void *hint, size_t size, int prot, int flags)
|
||||
uint64
|
||||
os_time_get_boot_microsecond(void)
|
||||
{
|
||||
|
||||
return BH_MALLOC(size);
|
||||
return (uint64)esp_timer_get_time();
|
||||
}
|
||||
|
||||
void
|
||||
os_munmap(void *addr, size_t size)
|
||||
uint8 *
|
||||
os_thread_get_stack_boundary(void)
|
||||
{
|
||||
BH_FREE(addr);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
int
|
||||
os_mprotect(void *addr, size_t size, int prot)
|
||||
os_usleep(uint32 usec)
|
||||
{
|
||||
return 0;
|
||||
}
|
||||
|
||||
void
|
||||
os_dcache_flush()
|
||||
{}
|
||||
|
||||
int
|
||||
atoi(const char *nptr)
|
||||
{
|
||||
bool is_negative = false;
|
||||
int total = 0;
|
||||
const char *p = nptr;
|
||||
char temp = '0';
|
||||
|
||||
if (NULL == p) {
|
||||
os_printf("invlaid atoi input\n");
|
||||
return 0;
|
||||
}
|
||||
|
||||
if (*p == '-') {
|
||||
is_negative = true;
|
||||
p++;
|
||||
}
|
||||
|
||||
while ((temp = *p++) != '\0') {
|
||||
if (temp > '9' || temp < '0') {
|
||||
continue;
|
||||
}
|
||||
|
||||
total = total * 10 + (int)(temp - '0');
|
||||
}
|
||||
|
||||
if (is_negative)
|
||||
total = 0 - total;
|
||||
|
||||
return total;
|
||||
}
|
||||
|
||||
void *
|
||||
memmove(void *dest, const void *src, size_t n)
|
||||
{
|
||||
char *d = dest;
|
||||
const char *s = src;
|
||||
|
||||
if (d < s) {
|
||||
while (n--)
|
||||
*d++ = *s++;
|
||||
}
|
||||
else {
|
||||
const char *lasts = s + (n - 1);
|
||||
char *lastd = d + (n - 1);
|
||||
while (n--)
|
||||
*lastd-- = *lasts--;
|
||||
}
|
||||
return dest;
|
||||
return usleep(usec);
|
||||
}
|
||||
|
||||
@ -3,12 +3,204 @@
|
||||
* SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
|
||||
*/
|
||||
|
||||
#ifndef _GNU_SOURCE
|
||||
#define _GNU_SOURCE
|
||||
#endif
|
||||
|
||||
#include "platform_api_vmcore.h"
|
||||
#include "platform_api_extension.h"
|
||||
|
||||
uint8 *
|
||||
os_thread_get_stack_boundary()
|
||||
typedef struct {
|
||||
thread_start_routine_t start;
|
||||
void *arg;
|
||||
} thread_wrapper_arg;
|
||||
|
||||
static void *
|
||||
os_thread_wrapper(void *arg)
|
||||
{
|
||||
/* TODO: implement os_thread_get_stack_boundary */
|
||||
thread_wrapper_arg *targ = arg;
|
||||
thread_start_routine_t start_func = targ->start;
|
||||
void *thread_arg = targ->arg;
|
||||
|
||||
os_printf("THREAD CREATED %jx\n", (uintmax_t)(uintptr_t)pthread_self());
|
||||
BH_FREE(targ);
|
||||
start_func(thread_arg);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
korp_tid
|
||||
os_self_thread(void)
|
||||
{
|
||||
/* only allowed if this is a thread, xTaskCreate is not enough look at
|
||||
* product_mini for how to use this*/
|
||||
return pthread_self();
|
||||
}
|
||||
|
||||
int
|
||||
os_mutex_init(korp_mutex *mutex)
|
||||
{
|
||||
return pthread_mutex_init(mutex, NULL);
|
||||
}
|
||||
|
||||
int
|
||||
os_mutex_destroy(korp_mutex *mutex)
|
||||
{
|
||||
return pthread_mutex_destroy(mutex);
|
||||
}
|
||||
|
||||
int
|
||||
os_mutex_lock(korp_mutex *mutex)
|
||||
{
|
||||
return pthread_mutex_lock(mutex);
|
||||
}
|
||||
|
||||
int
|
||||
os_mutex_unlock(korp_mutex *mutex)
|
||||
{
|
||||
return pthread_mutex_unlock(mutex);
|
||||
}
|
||||
|
||||
int
|
||||
os_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;
|
||||
|
||||
assert(stack_size > 0);
|
||||
assert(tid);
|
||||
assert(start);
|
||||
|
||||
pthread_attr_init(&tattr);
|
||||
pthread_attr_setdetachstate(&tattr, PTHREAD_CREATE_JOINABLE);
|
||||
if (pthread_attr_setstacksize(&tattr, stack_size) != 0) {
|
||||
os_printf("Invalid thread stack size %u. Min stack size = %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;
|
||||
|
||||
if (pthread_create(tid, &tattr, os_thread_wrapper, targ) != 0) {
|
||||
pthread_attr_destroy(&tattr);
|
||||
os_free(targ);
|
||||
return BHT_ERROR;
|
||||
}
|
||||
|
||||
pthread_attr_destroy(&tattr);
|
||||
return BHT_OK;
|
||||
}
|
||||
|
||||
int
|
||||
os_thread_create(korp_tid *tid, thread_start_routine_t start, void *arg,
|
||||
unsigned int stack_size)
|
||||
{
|
||||
return os_thread_create_with_prio(tid, start, arg, stack_size,
|
||||
BH_THREAD_DEFAULT_PRIORITY);
|
||||
}
|
||||
|
||||
int
|
||||
os_thread_join(korp_tid thread, void **retval)
|
||||
{
|
||||
return pthread_join(thread, retval);
|
||||
}
|
||||
|
||||
int
|
||||
os_thread_detach(korp_tid tid)
|
||||
{
|
||||
return pthread_detach(tid);
|
||||
}
|
||||
|
||||
void
|
||||
os_thread_exit(void *retval)
|
||||
{
|
||||
pthread_exit(retval);
|
||||
}
|
||||
|
||||
int
|
||||
os_cond_init(korp_cond *cond)
|
||||
{
|
||||
return pthread_cond_init(cond, NULL);
|
||||
}
|
||||
|
||||
int
|
||||
os_cond_destroy(korp_cond *cond)
|
||||
{
|
||||
return pthread_cond_destroy(cond);
|
||||
}
|
||||
|
||||
int
|
||||
os_cond_wait(korp_cond *cond, korp_mutex *mutex)
|
||||
{
|
||||
return pthread_cond_wait(cond, mutex);
|
||||
}
|
||||
|
||||
static void
|
||||
msec_nsec_to_abstime(struct timespec *ts, uint64 usec)
|
||||
{
|
||||
struct timeval tv;
|
||||
time_t tv_sec_new;
|
||||
long int tv_nsec_new;
|
||||
|
||||
gettimeofday(&tv, NULL);
|
||||
|
||||
tv_sec_new = (time_t)(tv.tv_sec + usec / 1000000);
|
||||
if (tv_sec_new >= tv.tv_sec) {
|
||||
ts->tv_sec = tv_sec_new;
|
||||
}
|
||||
else {
|
||||
/* integer overflow */
|
||||
ts->tv_sec = BH_TIME_T_MAX;
|
||||
os_printf("Warning: os_cond_reltimedwait exceeds limit, "
|
||||
"set to max timeout instead\n");
|
||||
}
|
||||
|
||||
tv_nsec_new = (long int)(tv.tv_usec * 1000 + (usec % 1000000) * 1000);
|
||||
if (tv.tv_usec * 1000 >= tv.tv_usec && tv_nsec_new >= tv.tv_usec * 1000) {
|
||||
ts->tv_nsec = tv_nsec_new;
|
||||
}
|
||||
else {
|
||||
/* integer overflow */
|
||||
ts->tv_nsec = LONG_MAX;
|
||||
os_printf("Warning: os_cond_reltimedwait exceeds limit, "
|
||||
"set to max timeout instead\n");
|
||||
}
|
||||
|
||||
if (ts->tv_nsec >= 1000000000L && ts->tv_sec < BH_TIME_T_MAX) {
|
||||
ts->tv_sec++;
|
||||
ts->tv_nsec -= 1000000000L;
|
||||
}
|
||||
}
|
||||
|
||||
int
|
||||
os_cond_reltimedwait(korp_cond *cond, korp_mutex *mutex, uint64 useconds)
|
||||
{
|
||||
int ret;
|
||||
struct timespec abstime;
|
||||
|
||||
if (useconds == BHT_WAIT_FOREVER)
|
||||
ret = pthread_cond_wait(cond, mutex);
|
||||
else {
|
||||
msec_nsec_to_abstime(&abstime, useconds);
|
||||
ret = pthread_cond_timedwait(cond, mutex, &abstime);
|
||||
}
|
||||
|
||||
if (ret != BHT_OK && ret != ETIMEDOUT)
|
||||
return BHT_ERROR;
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
int
|
||||
os_cond_signal(korp_cond *cond)
|
||||
{
|
||||
return pthread_cond_signal(cond);
|
||||
}
|
||||
|
||||
@ -14,88 +14,35 @@
|
||||
#include <stdlib.h>
|
||||
#include <ctype.h>
|
||||
#include <errno.h>
|
||||
#include <math.h>
|
||||
#include <unistd.h>
|
||||
#include <pthread.h>
|
||||
|
||||
#include <FreeRTOS.h>
|
||||
#include <semphr.h>
|
||||
#include <task.h>
|
||||
#include <os_api.h>
|
||||
#include "esp_pthread.h"
|
||||
#include "esp_timer.h"
|
||||
#include "freertos/FreeRTOS.h"
|
||||
#include "freertos/task.h"
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif
|
||||
|
||||
#ifndef BH_PLATFORM_ESP_IDF
|
||||
#define BH_PLATFORM_ESP_IDF
|
||||
#endif
|
||||
|
||||
typedef pthread_t korp_tid;
|
||||
typedef pthread_mutex_t korp_mutex;
|
||||
typedef pthread_cond_t korp_cond;
|
||||
typedef pthread_t korp_thread;
|
||||
|
||||
#define BH_APPLET_PRESERVED_STACK_SIZE (2 * BH_KB)
|
||||
|
||||
/* Default thread priority */
|
||||
#define BH_THREAD_DEFAULT_PRIORITY 5
|
||||
|
||||
extern int errno;
|
||||
|
||||
typedef TaskHandle_t korp_thread;
|
||||
typedef korp_thread korp_tid;
|
||||
typedef struct {
|
||||
bool is_recursive;
|
||||
SemaphoreHandle_t sem;
|
||||
} korp_mutex;
|
||||
|
||||
struct os_thread_wait_node;
|
||||
typedef struct os_thread_wait_node *os_thread_wait_list;
|
||||
typedef struct korp_cond {
|
||||
SemaphoreHandle_t wait_list_lock;
|
||||
os_thread_wait_list thread_wait_list;
|
||||
} korp_cond;
|
||||
|
||||
int
|
||||
os_printf(const char *format, ...);
|
||||
int
|
||||
os_vprintf(const char *format, va_list ap);
|
||||
|
||||
/* clang-format off */
|
||||
/* math functions which are not provided by os */
|
||||
double sqrt(double x);
|
||||
double floor(double x);
|
||||
double ceil(double x);
|
||||
double fmin(double x, double y);
|
||||
double fmax(double x, double y);
|
||||
double rint(double x);
|
||||
double fabs(double x);
|
||||
double trunc(double x);
|
||||
float floorf(float x);
|
||||
float ceilf(float x);
|
||||
float fminf(float x, float y);
|
||||
float fmaxf(float x, float y);
|
||||
float rintf(float x);
|
||||
float truncf(float x);
|
||||
int signbit(double x);
|
||||
int isnan(double x);
|
||||
|
||||
int atoi(const char *s);
|
||||
int strncasecmp(const char *s1, const char *s2, size_t n);
|
||||
long int strtol(const char *str, char **endptr, int base);
|
||||
unsigned long int strtoul(const char *str, char **endptr, int base);
|
||||
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);
|
||||
char *strstr(const char *haystack, const char *needle);
|
||||
size_t strspn(const char *s, const char *accept);
|
||||
size_t strcspn(const char *s, const char *reject);
|
||||
void *memchr(const void *s, int c, size_t n);
|
||||
int isalnum(int c);
|
||||
int isxdigit(int c);
|
||||
int isdigit(int c);
|
||||
int isprint(int c);
|
||||
int isgraph(int c);
|
||||
int isspace(int c);
|
||||
int isalpha(int c);
|
||||
int isupper(int c);
|
||||
int toupper(int c);
|
||||
int tolower(int c);
|
||||
void *memmove(void *dest, const void *src, size_t n);
|
||||
|
||||
uint32_t htonl(uint32_t hostlong);
|
||||
uint16_t htons(uint16_t hostshort);
|
||||
uint32_t ntohl(uint32_t netlong);
|
||||
uint16_t ntohs(uint16_t netshort);
|
||||
/* clang-format on */
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#endif
|
||||
|
||||
#endif
|
||||
|
||||
@ -8,12 +8,6 @@ add_definitions(-DBH_PLATFORM_ESP_IDF)
|
||||
include_directories(${PLATFORM_SHARED_DIR})
|
||||
include_directories(${PLATFORM_SHARED_DIR}/../include)
|
||||
|
||||
include (${CMAKE_CURRENT_LIST_DIR}/../common/freertos/platform_api_freertos.cmake)
|
||||
include (${CMAKE_CURRENT_LIST_DIR}/../common/math/platform_api_math.cmake)
|
||||
|
||||
file (GLOB_RECURSE source_all ${PLATFORM_SHARED_DIR}/*.c)
|
||||
|
||||
set (PLATFORM_SHARED_SOURCE ${source_all}
|
||||
${PLATFORM_COMMON_MATH_SOURCE}
|
||||
${PLATFORM_COMMON_FREERTOS_SOURCE})
|
||||
|
||||
set (PLATFORM_SHARED_SOURCE ${source_all} ${PLATFORM_COMMON_MATH_SOURCE})
|
||||
|
||||
@ -31,7 +31,7 @@ extern "C" {
|
||||
*/
|
||||
|
||||
/**
|
||||
* Ceates a thread
|
||||
* Creates a thread
|
||||
*
|
||||
* @param p_tid [OUTPUT] the pointer of tid
|
||||
* @param start main routine of the thread
|
||||
|
||||
Reference in New Issue
Block a user