mirror of
https://github.com/bytecodealliance/wasm-micro-runtime.git
synced 2024-11-26 15:32:05 +00:00
zephyr: Enable WASI support for file system and sockets on zephyr (#3633)
To address #3311. This work also implements the WASI support on Zephyr. Note that some comments haven't been addressed and will be fixed in the further patches.
This commit is contained in:
parent
e352f0ab10
commit
04642622d4
|
@ -175,14 +175,14 @@ blocking_op_openat(wasm_exec_env_t exec_env, os_file_handle handle,
|
|||
#ifndef BH_PLATFORM_WINDOWS
|
||||
/* REVISIT: apply the os_file_handle style abstraction for pollfd? */
|
||||
__wasi_errno_t
|
||||
blocking_op_poll(wasm_exec_env_t exec_env, struct pollfd *pfds, nfds_t nfds,
|
||||
int timeout_ms, int *retp)
|
||||
blocking_op_poll(wasm_exec_env_t exec_env, os_poll_file_handle *pfds,
|
||||
os_nfds_t nfds, int timeout_ms, int *retp)
|
||||
{
|
||||
int ret;
|
||||
if (!wasm_runtime_begin_blocking_op(exec_env)) {
|
||||
return __WASI_EINTR;
|
||||
}
|
||||
ret = poll(pfds, nfds, timeout_ms);
|
||||
ret = os_poll(pfds, nfds, timeout_ms);
|
||||
wasm_runtime_end_blocking_op(exec_env);
|
||||
if (ret == -1) {
|
||||
return convert_errno(errno);
|
||||
|
|
|
@ -57,8 +57,8 @@ blocking_op_openat(wasm_exec_env_t exec_env, os_file_handle handle,
|
|||
|
||||
#ifndef BH_PLATFORM_WINDOWS
|
||||
__wasi_errno_t
|
||||
blocking_op_poll(wasm_exec_env_t exec_env, struct pollfd *pfds, nfds_t nfds,
|
||||
int timeout, int *retp);
|
||||
blocking_op_poll(wasm_exec_env_t exec_env, os_poll_file_handle *pfds,
|
||||
os_nfds_t nfds, int timeout, int *retp);
|
||||
#endif
|
||||
|
||||
#endif /* end of _BLOCKING_OP_H_ */
|
||||
|
|
|
@ -196,8 +196,12 @@ static inline bool
|
|||
cond_timedwait(struct cond *cond, struct mutex *lock, uint64_t timeout,
|
||||
bool abstime) REQUIRES_EXCLUSIVE(*lock) NO_LOCK_ANALYSIS
|
||||
{
|
||||
#if defined(BH_PLATFORM_ZEPHYR)
|
||||
// TODO: Implement this for Zephyr
|
||||
return false;
|
||||
#else
|
||||
int ret;
|
||||
struct timespec ts = {
|
||||
os_timespec ts = {
|
||||
.tv_sec = (time_t)(timeout / 1000000000),
|
||||
.tv_nsec = (long)(timeout % 1000000000),
|
||||
};
|
||||
|
@ -210,8 +214,8 @@ cond_timedwait(struct cond *cond, struct mutex *lock, uint64_t timeout,
|
|||
* realtime clock.
|
||||
*/
|
||||
if (cond->clock != CLOCK_REALTIME) {
|
||||
struct timespec ts_monotonic;
|
||||
struct timespec ts_realtime;
|
||||
os_timespec ts_monotonic;
|
||||
os_timespec ts_realtime;
|
||||
|
||||
clock_gettime(cond->clock, &ts_monotonic);
|
||||
ts.tv_sec -= ts_monotonic.tv_sec;
|
||||
|
@ -229,7 +233,7 @@ cond_timedwait(struct cond *cond, struct mutex *lock, uint64_t timeout,
|
|||
++ts.tv_sec;
|
||||
}
|
||||
}
|
||||
#endif
|
||||
#endif /* !CONFIG_HAS_PTHREAD_CONDATTR_SETCLOCK */
|
||||
}
|
||||
else {
|
||||
#if CONFIG_HAS_PTHREAD_COND_TIMEDWAIT_RELATIVE_NP
|
||||
|
@ -241,7 +245,7 @@ cond_timedwait(struct cond *cond, struct mutex *lock, uint64_t timeout,
|
|||
return ret == ETIMEDOUT;
|
||||
#else
|
||||
/* Convert to absolute timeout. */
|
||||
struct timespec ts_now;
|
||||
os_timespec ts_now;
|
||||
#if CONFIG_HAS_PTHREAD_CONDATTR_SETCLOCK
|
||||
clock_gettime(cond->clock, &ts_now);
|
||||
#else
|
||||
|
@ -253,13 +257,14 @@ cond_timedwait(struct cond *cond, struct mutex *lock, uint64_t timeout,
|
|||
ts.tv_nsec -= 1000000000;
|
||||
++ts.tv_sec;
|
||||
}
|
||||
#endif
|
||||
#endif /* CONFIG_HAS_PTHREAD_COND_TIMEDWAIT_RELATIVE_NP */
|
||||
}
|
||||
|
||||
ret = pthread_cond_timedwait(&cond->object, &lock->object, &ts);
|
||||
bh_assert((ret == 0 || ret == ETIMEDOUT)
|
||||
&& "pthread_cond_timedwait() failed");
|
||||
return ret == ETIMEDOUT;
|
||||
#endif /* BH_PLATFORM_ZEPHYR */
|
||||
}
|
||||
#endif
|
||||
|
||||
|
|
|
@ -356,16 +356,20 @@ fd_table_get_entry(struct fd_table *ft, __wasi_fd_t fd,
|
|||
REQUIRES_SHARED(ft->lock)
|
||||
{
|
||||
// Test for file descriptor existence.
|
||||
if (fd >= ft->size)
|
||||
if (fd >= ft->size) {
|
||||
return __WASI_EBADF;
|
||||
}
|
||||
|
||||
struct fd_entry *fe = &ft->entries[fd];
|
||||
if (fe->object == NULL)
|
||||
if (fe->object == NULL) {
|
||||
return __WASI_EBADF;
|
||||
}
|
||||
|
||||
// Validate rights.
|
||||
if ((~fe->rights_base & rights_base) != 0
|
||||
|| (~fe->rights_inheriting & rights_inheriting) != 0)
|
||||
|| (~fe->rights_inheriting & rights_inheriting) != 0) {
|
||||
return __WASI_ENOTCAPABLE;
|
||||
}
|
||||
*ret = fe;
|
||||
return 0;
|
||||
}
|
||||
|
@ -426,15 +430,15 @@ fd_table_attach(struct fd_table *ft, __wasi_fd_t fd, struct fd_object *fo,
|
|||
__wasi_rights_t rights_base, __wasi_rights_t rights_inheriting)
|
||||
REQUIRES_EXCLUSIVE(ft->lock) CONSUMES(fo->refcount)
|
||||
{
|
||||
assert(ft->size > fd && "File descriptor table too small");
|
||||
bh_assert(ft->size > fd && "File descriptor table too small");
|
||||
struct fd_entry *fe = &ft->entries[fd];
|
||||
assert(fe->object == NULL
|
||||
&& "Attempted to overwrite an existing descriptor");
|
||||
bh_assert(fe->object == NULL
|
||||
&& "Attempted to overwrite an existing descriptor");
|
||||
fe->object = fo;
|
||||
fe->rights_base = rights_base;
|
||||
fe->rights_inheriting = rights_inheriting;
|
||||
++ft->used;
|
||||
assert(ft->size >= ft->used * 2 && "File descriptor too full");
|
||||
bh_assert(ft->size >= ft->used * 2 && "File descriptor too full");
|
||||
}
|
||||
|
||||
// Detaches a file descriptor from the file descriptor table.
|
||||
|
@ -442,12 +446,12 @@ static void
|
|||
fd_table_detach(struct fd_table *ft, __wasi_fd_t fd, struct fd_object **fo)
|
||||
REQUIRES_EXCLUSIVE(ft->lock) PRODUCES((*fo)->refcount)
|
||||
{
|
||||
assert(ft->size > fd && "File descriptor table too small");
|
||||
bh_assert(ft->size > fd && "File descriptor table too small");
|
||||
struct fd_entry *fe = &ft->entries[fd];
|
||||
*fo = fe->object;
|
||||
assert(*fo != NULL && "Attempted to detach nonexistent descriptor");
|
||||
bh_assert(*fo != NULL && "Attempted to detach nonexistent descriptor");
|
||||
fe->object = NULL;
|
||||
assert(ft->used > 0 && "Reference count mismatch");
|
||||
bh_assert(ft->used > 0 && "Reference count mismatch");
|
||||
--ft->used;
|
||||
}
|
||||
|
||||
|
@ -636,7 +640,7 @@ fd_table_insert_existing(struct fd_table *ft, __wasi_fd_t in,
|
|||
static __wasi_errno_t
|
||||
fd_table_unused(struct fd_table *ft, __wasi_fd_t *out) REQUIRES_SHARED(ft->lock)
|
||||
{
|
||||
assert(ft->size > ft->used && "File descriptor table has no free slots");
|
||||
bh_assert(ft->size > ft->used && "File descriptor table has no free slots");
|
||||
for (;;) {
|
||||
uintmax_t random_fd = 0;
|
||||
__wasi_errno_t error = random_uniform(ft->size, &random_fd);
|
||||
|
@ -1537,7 +1541,8 @@ path_put(struct path_access *pa) UNLOCKS(pa->fd_object->refcount)
|
|||
{
|
||||
if (pa->path_start)
|
||||
wasm_runtime_free(pa->path_start);
|
||||
if (pa->fd_object->file_handle != pa->fd)
|
||||
/* Can't use `!=` operator when `os_file_handle` is a struct */
|
||||
if (!os_compare_file_handle(pa->fd_object->file_handle, pa->fd))
|
||||
os_close(pa->fd, false);
|
||||
fd_object_release(NULL, pa->fd_object);
|
||||
}
|
||||
|
@ -1878,7 +1883,7 @@ wasmtime_ssp_fd_filestat_get(wasm_exec_env_t exec_env, struct fd_table *curfds,
|
|||
}
|
||||
|
||||
static void
|
||||
convert_timestamp(__wasi_timestamp_t in, struct timespec *out)
|
||||
convert_timestamp(__wasi_timestamp_t in, os_timespec *out)
|
||||
{
|
||||
// Store sub-second remainder.
|
||||
#if defined(__SYSCALL_SLONG_TYPE)
|
||||
|
@ -2076,7 +2081,7 @@ wasmtime_ssp_poll_oneoff(wasm_exec_env_t exec_env, struct fd_table *curfds,
|
|||
size_t nsubscriptions,
|
||||
size_t *nevents) NO_LOCK_ANALYSIS
|
||||
{
|
||||
#ifdef BH_PLATFORM_WINDOWS
|
||||
#if defined(BH_PLATFORM_WINDOWS) || defined(BH_PLATFORM_ZEPHYR)
|
||||
return __WASI_ENOSYS;
|
||||
#else
|
||||
// Sleeping.
|
||||
|
@ -2088,7 +2093,7 @@ wasmtime_ssp_poll_oneoff(wasm_exec_env_t exec_env, struct fd_table *curfds,
|
|||
#if CONFIG_HAS_CLOCK_NANOSLEEP
|
||||
clockid_t clock_id;
|
||||
if (wasi_clockid_to_clockid(in[0].u.u.clock.clock_id, &clock_id)) {
|
||||
struct timespec ts;
|
||||
os_timespec ts;
|
||||
convert_timestamp(in[0].u.u.clock.timeout, &ts);
|
||||
int ret = clock_nanosleep(
|
||||
clock_id,
|
||||
|
@ -2115,7 +2120,7 @@ wasmtime_ssp_poll_oneoff(wasm_exec_env_t exec_env, struct fd_table *curfds,
|
|||
else {
|
||||
// Perform relative sleeps on the monotonic clock also using
|
||||
// nanosleep(). This is incorrect, but good enough for now.
|
||||
struct timespec ts;
|
||||
os_timespec ts;
|
||||
convert_timestamp(in[0].u.u.clock.timeout, &ts);
|
||||
nanosleep(&ts, NULL);
|
||||
}
|
||||
|
@ -2143,7 +2148,7 @@ wasmtime_ssp_poll_oneoff(wasm_exec_env_t exec_env, struct fd_table *curfds,
|
|||
}
|
||||
else {
|
||||
// Relative sleeps can be done using nanosleep().
|
||||
struct timespec ts;
|
||||
os_timespec ts;
|
||||
convert_timestamp(in[0].u.u.clock.timeout, &ts);
|
||||
nanosleep(&ts, NULL);
|
||||
}
|
||||
|
@ -2168,7 +2173,7 @@ wasmtime_ssp_poll_oneoff(wasm_exec_env_t exec_env, struct fd_table *curfds,
|
|||
wasm_runtime_malloc((uint32)(nsubscriptions * sizeof(*fos)));
|
||||
if (fos == NULL)
|
||||
return __WASI_ENOMEM;
|
||||
struct pollfd *pfds =
|
||||
os_poll_file_handle *pfds =
|
||||
wasm_runtime_malloc((uint32)(nsubscriptions * sizeof(*pfds)));
|
||||
if (pfds == NULL) {
|
||||
wasm_runtime_free(fos);
|
||||
|
@ -2193,7 +2198,7 @@ wasmtime_ssp_poll_oneoff(wasm_exec_env_t exec_env, struct fd_table *curfds,
|
|||
__WASI_RIGHT_POLL_FD_READWRITE, 0);
|
||||
if (error == 0) {
|
||||
// Proper file descriptor on which we can poll().
|
||||
pfds[i] = (struct pollfd){
|
||||
pfds[i] = (os_poll_file_handle){
|
||||
.fd = fos[i]->file_handle,
|
||||
.events = s->u.type == __WASI_EVENTTYPE_FD_READ
|
||||
? POLLIN
|
||||
|
@ -2203,7 +2208,7 @@ wasmtime_ssp_poll_oneoff(wasm_exec_env_t exec_env, struct fd_table *curfds,
|
|||
else {
|
||||
// Invalid file descriptor or rights missing.
|
||||
fos[i] = NULL;
|
||||
pfds[i] = (struct pollfd){ .fd = -1 };
|
||||
pfds[i] = (os_poll_file_handle){ .fd = -1 };
|
||||
out[(*nevents)++] = (__wasi_event_t){
|
||||
.userdata = s->userdata,
|
||||
.error = error,
|
||||
|
@ -2218,7 +2223,7 @@ wasmtime_ssp_poll_oneoff(wasm_exec_env_t exec_env, struct fd_table *curfds,
|
|||
== 0) {
|
||||
// Relative timeout.
|
||||
fos[i] = NULL;
|
||||
pfds[i] = (struct pollfd){ .fd = -1 };
|
||||
pfds[i] = (os_poll_file_handle){ .fd = -1 };
|
||||
clock_subscription = s;
|
||||
break;
|
||||
}
|
||||
|
@ -2226,7 +2231,7 @@ wasmtime_ssp_poll_oneoff(wasm_exec_env_t exec_env, struct fd_table *curfds,
|
|||
default:
|
||||
// Unsupported event.
|
||||
fos[i] = NULL;
|
||||
pfds[i] = (struct pollfd){ .fd = -1 };
|
||||
pfds[i] = (os_poll_file_handle){ .fd = -1 };
|
||||
out[(*nevents)++] = (__wasi_event_t){
|
||||
.userdata = s->userdata,
|
||||
.error = __WASI_ENOSYS,
|
||||
|
@ -2270,7 +2275,7 @@ wasmtime_ssp_poll_oneoff(wasm_exec_env_t exec_env, struct fd_table *curfds,
|
|||
__wasi_filesize_t nbytes = 0;
|
||||
if (in[i].u.type == __WASI_EVENTTYPE_FD_READ) {
|
||||
int l;
|
||||
if (ioctl(fos[i]->file_handle, FIONREAD, &l) == 0)
|
||||
if (os_ioctl(fos[i]->file_handle, FIONREAD, &l) == 0)
|
||||
nbytes = (__wasi_filesize_t)l;
|
||||
}
|
||||
if ((pfds[i].revents & POLLNVAL) != 0) {
|
||||
|
@ -2436,7 +2441,7 @@ wasi_addr_to_string(const __wasi_addr_t *addr, char *buf, size_t buflen)
|
|||
if (addr->kind == IPv4) {
|
||||
const char *format = "%u.%u.%u.%u";
|
||||
|
||||
assert(buflen >= 16);
|
||||
bh_assert(buflen >= 16);
|
||||
|
||||
snprintf(buf, buflen, format, addr->addr.ip4.addr.n0,
|
||||
addr->addr.ip4.addr.n1, addr->addr.ip4.addr.n2,
|
||||
|
@ -2448,14 +2453,13 @@ wasi_addr_to_string(const __wasi_addr_t *addr, char *buf, size_t buflen)
|
|||
const char *format = "%04x:%04x:%04x:%04x:%04x:%04x:%04x:%04x";
|
||||
__wasi_addr_ip6_t ipv6 = addr->addr.ip6.addr;
|
||||
|
||||
assert(buflen >= 40);
|
||||
bh_assert(buflen >= 40);
|
||||
|
||||
snprintf(buf, buflen, format, ipv6.n0, ipv6.n1, ipv6.n2, ipv6.n3,
|
||||
ipv6.h0, ipv6.h1, ipv6.h2, ipv6.h3);
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
|
@ -2562,9 +2566,11 @@ wasi_ssp_sock_connect(wasm_exec_env_t exec_env, struct fd_table *curfds,
|
|||
}
|
||||
|
||||
error = fd_object_get(curfds, &fo, fd, __WASI_RIGHT_SOCK_BIND, 0);
|
||||
if (error != __WASI_ESUCCESS)
|
||||
if (error != __WASI_ESUCCESS) {
|
||||
return error;
|
||||
}
|
||||
|
||||
/* Consume __wasi_addr_t */
|
||||
ret = blocking_op_socket_connect(exec_env, fo->file_handle, buf,
|
||||
addr->kind == IPv4 ? addr->addr.ip4.port
|
||||
: addr->addr.ip6.port);
|
||||
|
@ -2713,10 +2719,10 @@ wasi_ssp_sock_open(wasm_exec_env_t exec_env, struct fd_table *curfds,
|
|||
}
|
||||
|
||||
if (SOCKET_DGRAM == socktype) {
|
||||
assert(wasi_type == __WASI_FILETYPE_SOCKET_DGRAM);
|
||||
bh_assert(wasi_type == __WASI_FILETYPE_SOCKET_DGRAM);
|
||||
}
|
||||
else {
|
||||
assert(wasi_type == __WASI_FILETYPE_SOCKET_STREAM);
|
||||
bh_assert(wasi_type == __WASI_FILETYPE_SOCKET_STREAM);
|
||||
}
|
||||
|
||||
// TODO: base rights and inheriting rights ?
|
||||
|
@ -2834,6 +2840,9 @@ wasmtime_ssp_sock_recv_from(wasm_exec_env_t exec_env, struct fd_table *curfds,
|
|||
return error;
|
||||
}
|
||||
|
||||
wasi_addr_to_bh_sockaddr(src_addr, &sockaddr);
|
||||
|
||||
/* Consume bh_sockaddr_t instead of __wasi_addr_t */
|
||||
ret = blocking_op_socket_recv_from(exec_env, fo->file_handle, buf, buf_len,
|
||||
0, &sockaddr);
|
||||
fd_object_release(exec_env, fo);
|
||||
|
@ -2899,6 +2908,7 @@ wasmtime_ssp_sock_send_to(wasm_exec_env_t exec_env, struct fd_table *curfds,
|
|||
|
||||
wasi_addr_to_bh_sockaddr(dest_addr, &sockaddr);
|
||||
|
||||
/* Consume bh_sockaddr instead of __wasi_addr_t */
|
||||
ret = blocking_op_socket_send_to(exec_env, fo->file_handle, buf, buf_len, 0,
|
||||
&sockaddr);
|
||||
fd_object_release(exec_env, fo);
|
||||
|
@ -2930,8 +2940,10 @@ wasmtime_ssp_sock_shutdown(wasm_exec_env_t exec_env, struct fd_table *curfds,
|
|||
__wasi_errno_t
|
||||
wasmtime_ssp_sched_yield(void)
|
||||
{
|
||||
#ifdef BH_PLATFORM_WINDOWS
|
||||
#if defined(BH_PLATFORM_WINDOWS)
|
||||
SwitchToThread();
|
||||
#elif defined(BH_PLATFORM_ZEPHYR)
|
||||
k_yield();
|
||||
#else
|
||||
if (sched_yield() < 0)
|
||||
return convert_errno(errno);
|
||||
|
|
|
@ -66,6 +66,20 @@ random_buf(void *buf, size_t len)
|
|||
return ret ? __WASI_EINVAL : __WASI_ESUCCESS;
|
||||
}
|
||||
|
||||
#elif defined(BH_PLATFORM_ZEPHYR)
|
||||
#include <zephyr/random/random.h>
|
||||
// Maybe having an OS abstraction api would be a good idea
|
||||
// because every platform is implementing this function.
|
||||
// we could have a function like `os_random_buf`
|
||||
// and call `os_random_buf.` in the SSP wrapper `random_buf`.
|
||||
|
||||
__wasi_errno_t
|
||||
random_buf(void *buf, size_t len)
|
||||
{
|
||||
sys_rand_get(buf, len);
|
||||
return __WASI_ESUCCESS;
|
||||
}
|
||||
|
||||
#else
|
||||
|
||||
static int urandom = -1;
|
||||
|
|
|
@ -42,7 +42,8 @@
|
|||
#define CONFIG_HAS_GETRANDOM 0
|
||||
#endif
|
||||
|
||||
#if defined(__CloudABI__) || defined(BH_PLATFORM_FREERTOS)
|
||||
#if defined(__CloudABI__) || defined(BH_PLATFORM_FREERTOS) \
|
||||
|| defined(BH_PLATFORM_ZEPHYR)
|
||||
#define CONFIG_HAS_CAP_ENTER 1
|
||||
#else
|
||||
#define CONFIG_HAS_CAP_ENTER 0
|
||||
|
@ -50,7 +51,7 @@
|
|||
|
||||
#if !defined(__APPLE__) && !defined(__FreeBSD__) && !defined(__EMSCRIPTEN__) \
|
||||
&& !defined(ESP_PLATFORM) && !defined(DISABLE_CLOCK_NANOSLEEP) \
|
||||
&& !defined(BH_PLATFORM_FREERTOS)
|
||||
&& !defined(BH_PLATFORM_FREERTOS) && !defined(BH_PLATFORM_ZEPHYR)
|
||||
#define CONFIG_HAS_CLOCK_NANOSLEEP 1
|
||||
#else
|
||||
#define CONFIG_HAS_CLOCK_NANOSLEEP 0
|
||||
|
@ -63,7 +64,8 @@
|
|||
#endif
|
||||
|
||||
#if !defined(__APPLE__) && !defined(BH_PLATFORM_LINUX_SGX) && !defined(_WIN32) \
|
||||
&& !defined(__COSMOPOLITAN__) && !defined(BH_PLATFORM_FREERTOS)
|
||||
&& !defined(__COSMOPOLITAN__) && !defined(BH_PLATFORM_FREERTOS) \
|
||||
&& !defined(BH_PLATFORM_ZEPHYR)
|
||||
#define CONFIG_HAS_PTHREAD_CONDATTR_SETCLOCK 1
|
||||
#else
|
||||
#define CONFIG_HAS_PTHREAD_CONDATTR_SETCLOCK 0
|
||||
|
|
|
@ -75,6 +75,9 @@ int isnan(double x);
|
|||
typedef int os_file_handle;
|
||||
typedef void *os_dir_stream;
|
||||
typedef int os_raw_file_handle;
|
||||
typedef int os_poll_file_handle;
|
||||
typedef unsigned int os_nfds_t;
|
||||
typedef int os_timespec;
|
||||
|
||||
static inline os_file_handle
|
||||
os_get_invalid_handle(void)
|
||||
|
|
|
@ -150,6 +150,12 @@ typedef int os_file_handle;
|
|||
typedef DIR *os_dir_stream;
|
||||
typedef int os_raw_file_handle;
|
||||
|
||||
/* The below types are used in platform_api_extension.h,
|
||||
we just define them to make the compiler happy */
|
||||
typedef struct pollfd os_poll_file_handle;
|
||||
typedef nfds_t os_nfds_t;
|
||||
typedef struct timespec os_timespec;
|
||||
|
||||
static inline os_file_handle
|
||||
os_get_invalid_handle(void)
|
||||
{
|
||||
|
|
|
@ -1032,4 +1032,32 @@ char *
|
|||
os_realpath(const char *path, char *resolved_path)
|
||||
{
|
||||
return realpath(path, resolved_path);
|
||||
}
|
||||
|
||||
// Better to define the function here, as Linux-SGX will
|
||||
// use this file to implement the `_os` functions.
|
||||
// So we don't need to define them in the Linux-SGX platform.
|
||||
int
|
||||
os_ioctl(os_file_handle handle, int request, ...)
|
||||
{
|
||||
int ret = -1;
|
||||
va_list args;
|
||||
|
||||
va_start(args, request);
|
||||
ret = ioctl(handle, request, args);
|
||||
va_end(args);
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
int
|
||||
os_poll(os_poll_file_handle *fds, os_nfds_t nfs, int timeout)
|
||||
{
|
||||
return poll(fds, nfs, timeout);
|
||||
}
|
||||
|
||||
bool
|
||||
os_compare_file_handle(os_file_handle handle1, os_file_handle handle2)
|
||||
{
|
||||
return handle1 == handle2;
|
||||
}
|
|
@ -1031,4 +1031,4 @@ os_socket_addr_remote(bh_socket_t socket, bh_sockaddr_t *sockaddr)
|
|||
}
|
||||
|
||||
return sockaddr_to_bh_sockaddr((struct sockaddr *)&addr_storage, sockaddr);
|
||||
}
|
||||
}
|
|
@ -67,6 +67,9 @@ typedef sem_t korp_sem;
|
|||
typedef int os_file_handle;
|
||||
typedef DIR *os_dir_stream;
|
||||
typedef int os_raw_file_handle;
|
||||
typedef struct pollfd os_poll_file_handle;
|
||||
typedef nfds_t os_nfds_t;
|
||||
typedef struct timespec os_timespec;
|
||||
|
||||
static inline os_file_handle
|
||||
os_get_invalid_handle(void)
|
||||
|
|
|
@ -112,6 +112,9 @@ os_set_signal_number_for_blocking_op(int signo);
|
|||
typedef int os_file_handle;
|
||||
typedef DIR *os_dir_stream;
|
||||
typedef int os_raw_file_handle;
|
||||
typedef struct pollfd os_poll_file_handle;
|
||||
typedef nfds_t os_nfds_t;
|
||||
typedef struct timespec os_timespec;
|
||||
|
||||
static inline os_file_handle
|
||||
os_get_invalid_handle(void)
|
||||
|
|
|
@ -1032,4 +1032,16 @@ char *
|
|||
os_realpath(const char *path, char *resolved_path)
|
||||
{
|
||||
return realpath(path, resolved_path);
|
||||
}
|
||||
|
||||
int
|
||||
os_ioctl(os_file_handle handle, int request, ...)
|
||||
{
|
||||
return BHT_ERROR;
|
||||
}
|
||||
|
||||
int
|
||||
os_poll(os_poll_file_handle *fds, os_nfds_t nfs, int timeout)
|
||||
{
|
||||
return BHT_ERROR;
|
||||
}
|
|
@ -144,6 +144,12 @@ typedef int os_file_handle;
|
|||
typedef DIR *os_dir_stream;
|
||||
typedef int os_raw_file_handle;
|
||||
|
||||
/* The below types are used in platform_api_extension.h,
|
||||
we just define them to make the compiler happy */
|
||||
typedef int os_poll_file_handle;
|
||||
typedef unsigned int os_nfds_t;
|
||||
typedef int os_timespec;
|
||||
|
||||
static inline os_file_handle
|
||||
os_get_invalid_handle(void)
|
||||
{
|
||||
|
|
|
@ -69,6 +69,9 @@ typedef sem_t korp_sem;
|
|||
typedef int os_file_handle;
|
||||
typedef DIR *os_dir_stream;
|
||||
typedef int os_raw_file_handle;
|
||||
typedef struct pollfd os_poll_file_handle;
|
||||
typedef nfds_t os_nfds_t;
|
||||
typedef struct timespec os_timespec;
|
||||
|
||||
#if WASM_DISABLE_HW_BOUND_CHECK == 0
|
||||
#if defined(BUILD_TARGET_X86_64) || defined(BUILD_TARGET_AMD_64) \
|
||||
|
|
|
@ -1664,4 +1664,24 @@ os_clock_time_get(__wasi_clockid_t clock_id, __wasi_timestamp_t precision,
|
|||
}
|
||||
#endif
|
||||
|
||||
/* Experimental */
|
||||
|
||||
/* Used in posix.c around L2259 and expect the return code
|
||||
* of ioctl() directly.
|
||||
*/
|
||||
int
|
||||
os_ioctl(os_file_handle handle, int request, ...);
|
||||
|
||||
/* Higher level API:
|
||||
* __wasi_errno_t
|
||||
* blocking_op_poll(wasm_exec_env_t exec_env, os_poll_file_handle *pfds,
|
||||
* os_nfds_t nfds, int timeout_ms, int *retp)
|
||||
* Already format the errno and expect the return code of poll() directly.
|
||||
*/
|
||||
int
|
||||
os_poll(os_poll_file_handle *pfds, os_nfds_t nfs, int timeout);
|
||||
|
||||
bool
|
||||
os_compare_file_handle(os_file_handle handle1, os_file_handle handle2);
|
||||
|
||||
#endif /* #ifndef PLATFORM_API_EXTENSION_H */
|
||||
|
|
|
@ -173,7 +173,7 @@ typedef uint8_t __wasi_eventtype_t;
|
|||
|
||||
typedef uint32_t __wasi_exitcode_t;
|
||||
|
||||
typedef uint32_t __wasi_fd_t;
|
||||
typedef int32_t __wasi_fd_t;
|
||||
|
||||
typedef uint16_t __wasi_fdflags_t;
|
||||
#define __WASI_FDFLAG_APPEND (0x0001)
|
||||
|
@ -539,7 +539,10 @@ typedef enum {
|
|||
|
||||
typedef uint16_t __wasi_ip_port_t;
|
||||
|
||||
typedef enum { IPv4 = 0, IPv6 } __wasi_addr_type_t;
|
||||
/* Ensure that __wasi_addr_type_t has a size of 4 byte (I32).
|
||||
However, it will not have the type safety of enum. */
|
||||
typedef uint32_t __wasi_addr_type_t;
|
||||
enum { IPv4 = 0, IPv6 };
|
||||
|
||||
/* n0.n1.n2.n3 */
|
||||
typedef struct __wasi_addr_ip4_t {
|
||||
|
|
|
@ -73,6 +73,16 @@ typedef int os_file_handle;
|
|||
typedef DIR *os_dir_stream;
|
||||
typedef int os_raw_file_handle;
|
||||
|
||||
struct _pollfd {
|
||||
int fd;
|
||||
short events;
|
||||
short revents;
|
||||
};
|
||||
|
||||
typedef struct _pollfd os_poll_file_handle;
|
||||
typedef unsigned long os_nfds_t;
|
||||
typedef struct timespec os_timespec;
|
||||
|
||||
static inline os_file_handle
|
||||
os_get_invalid_handle(void)
|
||||
{
|
||||
|
|
|
@ -126,6 +126,10 @@ typedef int os_file_handle;
|
|||
typedef DIR *os_dir_stream;
|
||||
typedef int os_raw_file_handle;
|
||||
|
||||
typedef struct pollfd os_poll_file_handle;
|
||||
typedef nfds_t os_nfds_t;
|
||||
typedef struct timespec os_timespec;
|
||||
|
||||
static inline os_file_handle
|
||||
os_get_invalid_handle(void)
|
||||
{
|
||||
|
|
|
@ -132,9 +132,14 @@ fdopendir(int fd);
|
|||
void
|
||||
os_set_signal_number_for_blocking_op(int signo);
|
||||
|
||||
/* The below types are used in platform_api_extension.h,
|
||||
we just define them to make the compiler happy */
|
||||
typedef int os_file_handle;
|
||||
typedef DIR *os_dir_stream;
|
||||
typedef int os_raw_file_handle;
|
||||
typedef struct pollfd os_poll_file_handle;
|
||||
typedef nfds_t os_nfds_t;
|
||||
typedef struct timespec os_timespec;
|
||||
|
||||
static inline os_file_handle
|
||||
os_get_invalid_handle(void)
|
||||
|
|
|
@ -63,6 +63,9 @@ typedef struct korp_cond {
|
|||
typedef int os_file_handle;
|
||||
typedef void *os_dir_stream;
|
||||
typedef int os_raw_file_handle;
|
||||
typedef int os_poll_file_handle;
|
||||
typedef unsigned int os_nfds_t;
|
||||
typedef int os_timespec;
|
||||
|
||||
#if WA_MATH
|
||||
/* clang-format off */
|
||||
|
|
|
@ -122,6 +122,9 @@ typedef rt_int64_t int64_t;
|
|||
typedef int os_file_handle;
|
||||
typedef void *os_dir_stream;
|
||||
typedef int os_raw_file_handle;
|
||||
typedef int os_poll_file_handle;
|
||||
typedef unsigned int os_nfds_t;
|
||||
typedef int os_timespec;
|
||||
|
||||
static inline os_file_handle
|
||||
os_get_invalid_handle(void)
|
||||
|
|
|
@ -65,6 +65,12 @@ typedef int os_file_handle;
|
|||
typedef DIR *os_dir_stream;
|
||||
typedef int os_raw_file_handle;
|
||||
|
||||
/* The below types are used in platform_api_extension.h,
|
||||
we just define them to make the compiler happy */
|
||||
typedef struct pollfd os_poll_file_handle;
|
||||
typedef nfds_t os_nfds_t;
|
||||
typedef timespec os_timespec;
|
||||
|
||||
#if WASM_DISABLE_HW_BOUND_CHECK == 0
|
||||
#if defined(BUILD_TARGET_X86_64) || defined(BUILD_TARGET_AMD_64) \
|
||||
|| defined(BUILD_TARGET_AARCH64)
|
||||
|
|
|
@ -186,6 +186,12 @@ typedef uint32_t os_raw_file_handle;
|
|||
|
||||
#define bh_socket_t windows_handle *
|
||||
|
||||
/* The below types are used in platform_api_extension.h,
|
||||
we just define them to make the compiler happy */
|
||||
typedef int os_poll_file_handle;
|
||||
typedef unsigned int os_nfds_t;
|
||||
typedef struct timespec os_timespec;
|
||||
|
||||
// UWP apps do not have stdout/stderr handles so provide a default
|
||||
// implementation of vprintf on debug builds so output from WASI libc is sent to
|
||||
// the debugger and not lost completely.
|
||||
|
|
|
@ -1810,3 +1810,39 @@ os_realpath(const char *path, char *resolved_path)
|
|||
|
||||
return resolved_path;
|
||||
}
|
||||
|
||||
bool
|
||||
os_compare_file_handle(os_file_handle handle1, os_file_handle handle2)
|
||||
{
|
||||
if (handle1->type != handle2->type) {
|
||||
return false;
|
||||
}
|
||||
|
||||
if (handle1->fdflags != handle2->fdflags
|
||||
|| handle1->access_mode != handle2->access_mode) {
|
||||
return false;
|
||||
}
|
||||
|
||||
switch (handle1->type) {
|
||||
case windows_handle_type_file:
|
||||
return handle1->raw.handle == handle2->raw.handle;
|
||||
case windows_handle_type_socket:
|
||||
return handle1->raw.socket == handle2->raw.socket;
|
||||
default:
|
||||
// Unknown handle type
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
int
|
||||
os_ioctl(os_file_handle handle, int request, ...)
|
||||
{
|
||||
return BHT_ERROR;
|
||||
}
|
||||
|
||||
// Should not be called because locked by ifdef.
|
||||
int
|
||||
os_poll(os_poll_file_handle *fds, os_nfds_t nfs, int timeout)
|
||||
{
|
||||
return BHT_ERROR;
|
||||
}
|
|
@ -50,6 +50,7 @@
|
|||
#include <zephyr/net/net_ip.h>
|
||||
#include <zephyr/net/net_core.h>
|
||||
#include <zephyr/net/net_context.h>
|
||||
#include <zephyr/net/socket.h>
|
||||
#endif /* end of KERNEL_VERSION_NUMBER < 0x030200 */
|
||||
|
||||
#ifdef CONFIG_USERSPACE
|
||||
|
@ -79,29 +80,33 @@
|
|||
#define BH_PLATFORM_ZEPHYR
|
||||
#endif
|
||||
|
||||
// Synchronization primitives for usermode
|
||||
/* Synchronization primitives for usermode.
|
||||
* The macros are prefixed with 'z' because when building
|
||||
* with WAMR_BUILD_LIBC_WASI the same functions are defined,
|
||||
* and used in the sandboxed-system-primitives (see locking.h)
|
||||
*/
|
||||
#ifdef CONFIG_USERSPACE
|
||||
#define mutex_t struct sys_mutex
|
||||
#define mutex_init(mtx) sys_mutex_init(mtx)
|
||||
#define mutex_lock(mtx, timeout) sys_mutex_lock(mtx, timeout)
|
||||
#define mutex_unlock(mtx) sys_mutex_unlock(mtx)
|
||||
#define zmutex_t struct sys_mutex
|
||||
#define zmutex_init(mtx) sys_mutex_init(mtx)
|
||||
#define zmutex_lock(mtx, timeout) sys_mutex_lock(mtx, timeout)
|
||||
#define zmutex_unlock(mtx) sys_mutex_unlock(mtx)
|
||||
|
||||
#define sem_t struct sys_sem
|
||||
#define sem_init(sem, init_count, limit) sys_sem_init(sem, init_count, limit)
|
||||
#define sem_give(sem) sys_sem_give(sem)
|
||||
#define sem_take(sem, timeout) sys_sem_take(sem, timeout)
|
||||
#define sem_count_get(sem) sys_sem_count_get(sem)
|
||||
#define zsem_t struct sys_sem
|
||||
#define zsem_init(sem, init_count, limit) sys_sem_init(sem, init_count, limit)
|
||||
#define zsem_give(sem) sys_sem_give(sem)
|
||||
#define zsem_take(sem, timeout) sys_sem_take(sem, timeout)
|
||||
#define zsem_count_get(sem) sys_sem_count_get(sem)
|
||||
#else /* else of CONFIG_USERSPACE */
|
||||
#define mutex_t struct k_mutex
|
||||
#define mutex_init(mtx) k_mutex_init(mtx)
|
||||
#define mutex_lock(mtx, timeout) k_mutex_lock(mtx, timeout)
|
||||
#define mutex_unlock(mtx) k_mutex_unlock(mtx)
|
||||
#define zmutex_t struct k_mutex
|
||||
#define zmutex_init(mtx) k_mutex_init(mtx)
|
||||
#define zmutex_lock(mtx, timeout) k_mutex_lock(mtx, timeout)
|
||||
#define zmutex_unlock(mtx) k_mutex_unlock(mtx)
|
||||
|
||||
#define sem_t struct k_sem
|
||||
#define sem_init(sem, init_count, limit) k_sem_init(sem, init_count, limit)
|
||||
#define sem_give(sem) k_sem_give(sem)
|
||||
#define sem_take(sem, timeout) k_sem_take(sem, timeout)
|
||||
#define sem_count_get(sem) k_sem_count_get(sem)
|
||||
#define zsem_t struct k_sem
|
||||
#define zsem_init(sem, init_count, limit) k_sem_init(sem, init_count, limit)
|
||||
#define zsem_give(sem) k_sem_give(sem)
|
||||
#define zsem_take(sem, timeout) k_sem_take(sem, timeout)
|
||||
#define zsem_count_get(sem) k_sem_count_get(sem)
|
||||
#endif /* end of CONFIG_USERSPACE */
|
||||
|
||||
#define BH_APPLET_PRESERVED_STACK_SIZE (2 * BH_KB)
|
||||
|
@ -111,22 +116,32 @@
|
|||
|
||||
typedef struct k_thread korp_thread;
|
||||
typedef korp_thread *korp_tid;
|
||||
typedef mutex_t korp_mutex;
|
||||
typedef zmutex_t korp_mutex;
|
||||
typedef unsigned int korp_sem;
|
||||
|
||||
/* korp_rwlock is used in platform_api_extension.h,
|
||||
we just define the type to make the compiler happy */
|
||||
typedef struct {
|
||||
int dummy;
|
||||
} korp_rwlock;
|
||||
|
||||
struct os_thread_wait_node;
|
||||
typedef struct os_thread_wait_node *os_thread_wait_list;
|
||||
typedef struct korp_cond {
|
||||
mutex_t wait_list_lock;
|
||||
zmutex_t wait_list_lock;
|
||||
os_thread_wait_list thread_wait_list;
|
||||
} korp_cond;
|
||||
|
||||
typedef struct {
|
||||
struct k_mutex mtx; // Mutex for exclusive access
|
||||
struct k_sem sem; // Semaphore for shared access
|
||||
int read_count; // Number of readers
|
||||
} korp_rwlock;
|
||||
|
||||
// TODO: Conform to Zephyr POSIX definition of rwlock:
|
||||
// struct posix_rwlock {
|
||||
// struct k_sem rd_sem;
|
||||
// struct k_sem wr_sem;
|
||||
// struct k_sem reader_active; /* blocks WR till reader has acquired lock */
|
||||
// k_tid_t wr_owner;
|
||||
// };
|
||||
|
||||
#ifndef Z_TIMEOUT_MS
|
||||
#define Z_TIMEOUT_MS(ms) ms
|
||||
#endif
|
||||
|
@ -204,14 +219,65 @@ set_exec_mem_alloc_func(exec_mem_alloc_func_t alloc_func,
|
|||
|
||||
/* The below types are used in platform_api_extension.h,
|
||||
we just define them to make the compiler happy */
|
||||
typedef int os_file_handle;
|
||||
typedef void *os_dir_stream;
|
||||
typedef int os_dir_stream;
|
||||
typedef int os_raw_file_handle;
|
||||
|
||||
// handle for file system descriptor
|
||||
typedef struct zephyr_fs_desc {
|
||||
char *path;
|
||||
union {
|
||||
struct fs_file_t file;
|
||||
struct fs_dir_t dir;
|
||||
};
|
||||
bool is_dir;
|
||||
bool used;
|
||||
} zephyr_fs_desc;
|
||||
|
||||
// definition of zephyr_handle
|
||||
typedef struct zephyr_handle {
|
||||
int fd;
|
||||
bool is_sock;
|
||||
} zephyr_handle;
|
||||
|
||||
typedef struct zephyr_handle *os_file_handle;
|
||||
#define bh_socket_t zephyr_handle *
|
||||
|
||||
typedef struct zsock_pollfd os_poll_file_handle;
|
||||
typedef unsigned int os_nfds_t;
|
||||
|
||||
// Some of these definitions will throw warning for macros
|
||||
// redefinition if CONFIG_POSIX_API=y, but it's fine.
|
||||
// Warning: the CONFIG_POSIX_API will surely be deprecated and
|
||||
// split into more macros, so we may use some ifdefs to avoid
|
||||
// the warning in the future.
|
||||
#define POLLIN ZSOCK_POLLIN
|
||||
#define POLLPRI ZSOCK_POLLPRI
|
||||
#define POLLOUT ZSOCK_POLLOUT
|
||||
#define POLLERR ZSOCK_POLLERR
|
||||
#define POLLHUP ZSOCK_POLLHUP
|
||||
#define POLLNVAL ZSOCK_POLLNVAL
|
||||
|
||||
#define FIONREAD ZFD_IOCTL_FIONREAD
|
||||
|
||||
typedef struct {
|
||||
time_t tv_sec;
|
||||
long tv_nsec;
|
||||
} os_timespec;
|
||||
|
||||
#define CLOCK_REALTIME 1
|
||||
#define CLOCK_MONOTONIC 4
|
||||
|
||||
// TODO: use it in sandboxed posix.c.
|
||||
// int os_sched_yield(void)
|
||||
// {
|
||||
// k_yield();
|
||||
// return 0;
|
||||
// }
|
||||
|
||||
static inline os_file_handle
|
||||
os_get_invalid_handle(void)
|
||||
{
|
||||
return -1;
|
||||
return NULL;
|
||||
}
|
||||
|
||||
static inline int
|
||||
|
|
|
@ -8,11 +8,20 @@ add_definitions(-DBH_PLATFORM_ZEPHYR)
|
|||
include_directories(${PLATFORM_SHARED_DIR})
|
||||
include_directories(${PLATFORM_SHARED_DIR}/../include)
|
||||
|
||||
if(${CONFIG_MINIMAL_LIBC})
|
||||
include (${CMAKE_CURRENT_LIST_DIR}/../common/math/platform_api_math.cmake)
|
||||
endif()
|
||||
|
||||
file (GLOB_RECURSE source_all ${PLATFORM_SHARED_DIR}/*.c)
|
||||
|
||||
set (PLATFORM_SHARED_SOURCE ${source_all} ${PLATFORM_COMMON_MATH_SOURCE})
|
||||
if(${CONFIG_MINIMAL_LIBC})
|
||||
include (${CMAKE_CURRENT_LIST_DIR}/../common/math/platform_api_math.cmake)
|
||||
set (source_all ${source_all} ${PLATFORM_COMMON_MATH_SOURCE})
|
||||
endif()
|
||||
|
||||
if (NOT WAMR_BUILD_LIBC_WASI EQUAL 1)
|
||||
list(REMOVE_ITEM source_all ${PLATFORM_SHARED_DIR}/zephyr_socket.c)
|
||||
list(REMOVE_ITEM source_all ${PLATFORM_SHARED_DIR}/zephyr_file.c)
|
||||
list(REMOVE_ITEM source_all ${PLATFORM_SHARED_DIR}/zephyr_clock.c)
|
||||
else()
|
||||
include (${CMAKE_CURRENT_LIST_DIR}/../common/libc-util/platform_common_libc_util.cmake)
|
||||
set(source_all ${source_all} ${PLATFORM_COMMON_LIBC_UTIL_SOURCE})
|
||||
endif ()
|
||||
|
||||
set (PLATFORM_SHARED_SOURCE ${source_all})
|
||||
|
|
66
core/shared/platform/zephyr/zephyr_clock.c
Normal file
66
core/shared/platform/zephyr/zephyr_clock.c
Normal file
|
@ -0,0 +1,66 @@
|
|||
/*
|
||||
* Copyright (C) 2024 Grenoble INP - ESISAR. All rights reserved.
|
||||
* SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
|
||||
*/
|
||||
|
||||
#include "platform_api_extension.h"
|
||||
#include "platform_api_vmcore.h"
|
||||
#include "libc_errno.h"
|
||||
|
||||
#include <zephyr/kernel.h>
|
||||
|
||||
/* Notes:
|
||||
* We are using the same implementation for __WASI_CLOCK_REALTIME and
|
||||
* __WASI_CLOCK_MONOTONIC, because it is a practical solution when there
|
||||
* is no RTC or external time source available.
|
||||
* The implementation is based on the Zephyr `k_cycle_get_32()` function or
|
||||
* the 64bits variant if available.
|
||||
* We could have used `k_uptime_get()` instead, but it is not as precise,
|
||||
* it has a millisecond resolution or depend on CONFIG_SYS_CLOCK_TICKS_PER_SEC.
|
||||
* Feel free to change the implementation if you have a better solution.
|
||||
* May look at
|
||||
* https://github.com/zephyrproject-rtos/zephyr/blob/main/lib/posix/options/clock.c
|
||||
* for reference.
|
||||
*/
|
||||
|
||||
#define NANOSECONDS_PER_SECOND 1000000000ULL
|
||||
|
||||
__wasi_errno_t
|
||||
os_clock_res_get(__wasi_clockid_t clock_id, __wasi_timestamp_t *resolution)
|
||||
{
|
||||
switch (clock_id) {
|
||||
case __WASI_CLOCK_PROCESS_CPUTIME_ID:
|
||||
case __WASI_CLOCK_THREAD_CPUTIME_ID:
|
||||
return __WASI_ENOTSUP;
|
||||
case __WASI_CLOCK_REALTIME:
|
||||
case __WASI_CLOCK_MONOTONIC:
|
||||
*resolution =
|
||||
NANOSECONDS_PER_SECOND / CONFIG_SYS_CLOCK_HW_CYCLES_PER_SEC;
|
||||
return __WASI_ESUCCESS;
|
||||
default:
|
||||
return __WASI_EINVAL;
|
||||
}
|
||||
}
|
||||
|
||||
__wasi_errno_t
|
||||
os_clock_time_get(__wasi_clockid_t clock_id, __wasi_timestamp_t precision,
|
||||
__wasi_timestamp_t *time)
|
||||
{
|
||||
(void)precision;
|
||||
|
||||
switch (clock_id) {
|
||||
case __WASI_CLOCK_PROCESS_CPUTIME_ID:
|
||||
case __WASI_CLOCK_THREAD_CPUTIME_ID:
|
||||
return __WASI_ENOTSUP;
|
||||
case __WASI_CLOCK_REALTIME:
|
||||
case __WASI_CLOCK_MONOTONIC:
|
||||
#ifdef CONFIG_TIMER_HAS_64BIT_CYCLE_COUNTER
|
||||
*time = k_cycle_get_64();
|
||||
#else
|
||||
*time = k_cycle_get_32();
|
||||
#endif
|
||||
return __WASI_ESUCCESS;
|
||||
default:
|
||||
return __WASI_EINVAL;
|
||||
}
|
||||
}
|
986
core/shared/platform/zephyr/zephyr_file.c
Normal file
986
core/shared/platform/zephyr/zephyr_file.c
Normal file
|
@ -0,0 +1,986 @@
|
|||
/*
|
||||
* Copyright (C) 2024 Grenoble INP - ESISAR. All rights reserved.
|
||||
* SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
|
||||
*/
|
||||
|
||||
#include "platform_api_extension.h"
|
||||
#include "libc_errno.h"
|
||||
|
||||
#include <string.h>
|
||||
#include <stdlib.h>
|
||||
|
||||
#include <zephyr/fs/fs.h>
|
||||
#include <zephyr/fs/fs_interface.h>
|
||||
#include <zephyr/fs/fs_sys.h>
|
||||
#include <zephyr/fs/littlefs.h>
|
||||
|
||||
/* Notes:
|
||||
* This is the implementation of a POSIX-like file system interface for Zephyr.
|
||||
* To manage our file descriptors, we created a struct `zephyr_fs_desc` that
|
||||
* represent a zephyr file descriptor and hold useful informations.
|
||||
* We also created a file descriptor table to keep track of all the file
|
||||
* descriptors.
|
||||
* To pass the file descriptor reference to the higher level abstraction, we
|
||||
* pass the index of the fd table to an `os_file_handle` struct.
|
||||
* Then in the WASI implementation layer we can retrieve the file descriptor
|
||||
* reference.
|
||||
* We also fake the stdin, stdout and stderr file descriptors.
|
||||
* We redirect the write operation on stdin, stdout and stderr to `os_printf`.
|
||||
* We do not handle write on stdin and read on stdin, stdout and stderr.
|
||||
*/
|
||||
|
||||
// No OS API wrapper (Zephyr):
|
||||
// file:
|
||||
// off_t fs_tell(struct fs_file_t *zfp)
|
||||
// file system:
|
||||
// int fs_mount(struct fs_mount_t *mp)
|
||||
// int fs_unmount(struct fs_mount_t *mp
|
||||
// int fs_readmount(int *index, const char **name)
|
||||
// int fs_statvfs(const char *path, struct fs_statvfs *stat)
|
||||
// int fs_mkfs(int fs_type, uintptr_t dev_id, void *cfg, int flags)
|
||||
// int fs_register(int type, const struct fs_file_system_t *fs)
|
||||
// int fs_unregister(int type, const struct fs_file_system_t *fs)
|
||||
|
||||
// We will take the maximum number of open files
|
||||
// from the Zephyr POSIX configuration
|
||||
#define CONFIG_WASI_MAX_OPEN_FILES 16
|
||||
|
||||
// Macro to retrieve a file system descriptor and check it's validity.
|
||||
#define GET_FILE_SYSTEM_DESCRIPTOR(fd, ptr) \
|
||||
do { \
|
||||
k_mutex_lock(&desc_array_mutex, K_FOREVER); \
|
||||
ptr = &desc_array[(int)fd]; \
|
||||
if (!ptr) { \
|
||||
k_mutex_unlock(&desc_array_mutex); \
|
||||
return __WASI_EBADF; \
|
||||
} \
|
||||
k_mutex_unlock(&desc_array_mutex); \
|
||||
} while (0)
|
||||
|
||||
// Array to keep track of file system descriptors.
|
||||
static struct zephyr_fs_desc desc_array[CONFIG_WASI_MAX_OPEN_FILES];
|
||||
|
||||
// mutex to protect the file descriptor array
|
||||
K_MUTEX_DEFINE(desc_array_mutex);
|
||||
|
||||
static char prestat_dir[MAX_FILE_NAME + 1];
|
||||
|
||||
static struct zephyr_fs_desc *
|
||||
zephyr_fs_alloc_obj(bool is_dir, const char *path, int *index)
|
||||
{
|
||||
int i;
|
||||
struct zephyr_fs_desc *ptr = NULL;
|
||||
*index = -1; // give a default value to index in case table is full
|
||||
|
||||
k_mutex_lock(&desc_array_mutex, K_FOREVER);
|
||||
for (i = 0; i < CONFIG_WASI_MAX_OPEN_FILES; i++) {
|
||||
if (desc_array[i].used == false) {
|
||||
ptr = &desc_array[i];
|
||||
ptr->used = true;
|
||||
ptr->is_dir = is_dir;
|
||||
ptr->path = strdup(path);
|
||||
if (ptr->path == NULL) {
|
||||
ptr->used = false;
|
||||
k_mutex_unlock(&desc_array_mutex);
|
||||
return NULL;
|
||||
}
|
||||
*index = i;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
k_mutex_unlock(&desc_array_mutex);
|
||||
|
||||
return ptr;
|
||||
}
|
||||
|
||||
static inline void
|
||||
zephyr_fs_free_obj(struct zephyr_fs_desc *ptr)
|
||||
{
|
||||
free(ptr->path);
|
||||
ptr->path = NULL;
|
||||
ptr->used = false;
|
||||
}
|
||||
|
||||
void
|
||||
debug_zephyr_fs_desc(const zephyr_fs_desc *desc)
|
||||
{
|
||||
if (desc == NULL) {
|
||||
os_printf("Descriptor is NULL\n");
|
||||
return;
|
||||
}
|
||||
os_printf("Descriptor found at %p\n", desc);
|
||||
os_printf(" Path: %s\n", desc->path ? desc->path : "NULL");
|
||||
os_printf(" Is Directory: %s\n", desc->is_dir ? "Yes" : "No");
|
||||
os_printf(" Used: %s\n", desc->used ? "Yes" : "No");
|
||||
|
||||
if (desc->is_dir) {
|
||||
os_printf(" Directory: %p\n", desc->dir);
|
||||
}
|
||||
else {
|
||||
os_printf(" File: %p\n", desc->file);
|
||||
}
|
||||
}
|
||||
|
||||
/* /!\ Needed for socket to work */
|
||||
__wasi_errno_t
|
||||
os_fstat(os_file_handle handle, struct __wasi_filestat_t *buf)
|
||||
{
|
||||
struct zephyr_fs_desc *ptr = NULL;
|
||||
int socktype, rc;
|
||||
|
||||
if (!handle->is_sock) {
|
||||
GET_FILE_SYSTEM_DESCRIPTOR(handle->fd, ptr);
|
||||
// debug_zephyr_fs_desc(ptr);
|
||||
|
||||
/* We treat the case of std[in/out/err] */
|
||||
if (ptr->path != NULL
|
||||
&& (!strcmp(ptr->path, "stdin") || !strcmp(ptr->path, "stdout")
|
||||
|| !strcmp(ptr->path, "stderr"))) {
|
||||
buf->st_filetype = __WASI_FILETYPE_CHARACTER_DEVICE;
|
||||
buf->st_size = 0;
|
||||
buf->st_atim = 0;
|
||||
buf->st_mtim = 0;
|
||||
buf->st_ctim = 0;
|
||||
return __WASI_ESUCCESS;
|
||||
}
|
||||
|
||||
return os_fstatat(handle, ptr->path, buf, 0);
|
||||
}
|
||||
else {
|
||||
// socklen_t socktypelen = sizeof(socktype);
|
||||
// rc = zsock_getsockopt(handle->fd, SOL_SOCKET, SO_TYPE, &socktype,
|
||||
// &socktypelen); Using `zsock_getsockopt` will add a dependency on the
|
||||
// network stack
|
||||
// TODO: may add a type to the `zephyr_handle`.
|
||||
rc = 1;
|
||||
socktype = SOCK_STREAM;
|
||||
if (rc < 0) {
|
||||
return convert_errno(-rc);
|
||||
}
|
||||
|
||||
switch (socktype) {
|
||||
case SOCK_DGRAM:
|
||||
buf->st_filetype = __WASI_FILETYPE_SOCKET_DGRAM;
|
||||
break;
|
||||
case SOCK_STREAM:
|
||||
buf->st_filetype = __WASI_FILETYPE_SOCKET_STREAM;
|
||||
break;
|
||||
default:
|
||||
buf->st_filetype = __WASI_FILETYPE_UNKNOWN;
|
||||
break;
|
||||
}
|
||||
buf->st_size = 0;
|
||||
buf->st_atim = 0;
|
||||
buf->st_mtim = 0;
|
||||
buf->st_ctim = 0;
|
||||
return __WASI_ESUCCESS;
|
||||
}
|
||||
}
|
||||
|
||||
__wasi_errno_t
|
||||
os_fstatat(os_file_handle handle, const char *path,
|
||||
struct __wasi_filestat_t *buf, __wasi_lookupflags_t lookup_flags)
|
||||
{
|
||||
struct fs_dirent entry;
|
||||
int rc;
|
||||
|
||||
if (handle->fd < 0) {
|
||||
return __WASI_EBADF;
|
||||
}
|
||||
|
||||
// Get file information using Zephyr's fs_stat function
|
||||
rc = fs_stat(path, &entry);
|
||||
if (rc < 0) {
|
||||
return convert_errno(-rc);
|
||||
}
|
||||
|
||||
// Fill in the __wasi_filestat_t structure
|
||||
buf->st_dev = 0; // Zephyr's fs_stat doesn't provide a device ID
|
||||
buf->st_ino = 0; // Zephyr's fs_stat doesn't provide an inode number
|
||||
buf->st_filetype = entry.type == FS_DIR_ENTRY_DIR
|
||||
? __WASI_FILETYPE_DIRECTORY
|
||||
: __WASI_FILETYPE_REGULAR_FILE;
|
||||
buf->st_nlink = 1; // Zephyr's fs_stat doesn't provide a link count
|
||||
buf->st_size = entry.size;
|
||||
buf->st_atim = 0; // Zephyr's fs_stat doesn't provide timestamps
|
||||
buf->st_mtim = 0;
|
||||
buf->st_ctim = 0;
|
||||
|
||||
return __WASI_ESUCCESS;
|
||||
}
|
||||
|
||||
__wasi_errno_t
|
||||
os_file_get_fdflags(os_file_handle handle, __wasi_fdflags_t *flags)
|
||||
{
|
||||
struct zephyr_fs_desc *ptr = NULL;
|
||||
|
||||
GET_FILE_SYSTEM_DESCRIPTOR(handle->fd, ptr);
|
||||
|
||||
if ((ptr->file.flags & FS_O_APPEND) != 0) {
|
||||
*flags |= __WASI_FDFLAG_APPEND;
|
||||
}
|
||||
/* Others flags:
|
||||
* - __WASI_FDFLAG_DSYNC
|
||||
* - __WASI_FDFLAG_RSYNC
|
||||
* - __WASI_FDFLAG_SYNC
|
||||
* - __WASI_FDFLAG_NONBLOCK
|
||||
* Have no equivalent in Zephyr.
|
||||
*/
|
||||
return __WASI_ESUCCESS;
|
||||
}
|
||||
|
||||
__wasi_errno_t
|
||||
os_file_set_fdflags(os_file_handle handle, __wasi_fdflags_t flags)
|
||||
{
|
||||
struct zephyr_fs_desc *ptr = NULL;
|
||||
|
||||
GET_FILE_SYSTEM_DESCRIPTOR(handle->fd, ptr);
|
||||
|
||||
if ((flags & __WASI_FDFLAG_APPEND) != 0) {
|
||||
ptr->file.flags |= FS_O_APPEND;
|
||||
}
|
||||
/* Same as above */
|
||||
return __WASI_ESUCCESS;
|
||||
}
|
||||
|
||||
__wasi_errno_t
|
||||
os_fdatasync(os_file_handle handle)
|
||||
{
|
||||
return os_fsync(handle);
|
||||
}
|
||||
|
||||
__wasi_errno_t
|
||||
os_fsync(os_file_handle handle)
|
||||
{
|
||||
struct zephyr_fs_desc *ptr = NULL;
|
||||
int rc = 0;
|
||||
|
||||
GET_FILE_SYSTEM_DESCRIPTOR(handle->fd, ptr);
|
||||
|
||||
if (ptr->is_dir) {
|
||||
return __WASI_EISDIR;
|
||||
}
|
||||
|
||||
rc = fs_sync(&ptr->file);
|
||||
if (rc < 0) {
|
||||
return convert_errno(-rc);
|
||||
}
|
||||
|
||||
return __WASI_ESUCCESS;
|
||||
}
|
||||
|
||||
__wasi_errno_t
|
||||
os_open_preopendir(const char *path, os_file_handle *out)
|
||||
{
|
||||
int rc, index;
|
||||
struct zephyr_fs_desc *ptr;
|
||||
|
||||
*out = BH_MALLOC(sizeof(struct zephyr_handle));
|
||||
if (*out == NULL) {
|
||||
return __WASI_ENOMEM;
|
||||
}
|
||||
|
||||
ptr = zephyr_fs_alloc_obj(true, path, &index);
|
||||
if (ptr == NULL) {
|
||||
BH_FREE(*out);
|
||||
return __WASI_EMFILE;
|
||||
}
|
||||
|
||||
fs_dir_t_init(&ptr->dir);
|
||||
|
||||
rc = fs_opendir(&ptr->dir, path);
|
||||
if (rc < 0) {
|
||||
zephyr_fs_free_obj(ptr);
|
||||
BH_FREE(*out);
|
||||
return convert_errno(-rc);
|
||||
}
|
||||
|
||||
(*out)->fd = index;
|
||||
(*out)->is_sock = false;
|
||||
|
||||
strncpy(prestat_dir, path, MAX_FILE_NAME + 1);
|
||||
prestat_dir[MAX_FILE_NAME] = '\0';
|
||||
|
||||
return __WASI_ESUCCESS;
|
||||
}
|
||||
|
||||
static int
|
||||
wasi_flags_to_zephyr(__wasi_oflags_t oflags, __wasi_fdflags_t fd_flags,
|
||||
__wasi_lookupflags_t lookup_flags,
|
||||
wasi_libc_file_access_mode access_mode)
|
||||
{
|
||||
int mode = 0;
|
||||
|
||||
// Convert open flags.
|
||||
if ((oflags & __WASI_O_CREAT) != 0) {
|
||||
mode |= FS_O_CREATE;
|
||||
}
|
||||
if (((oflags & __WASI_O_EXCL) != 0) || ((oflags & __WASI_O_TRUNC) != 0)
|
||||
|| ((oflags & __WASI_O_DIRECTORY) != 0)) {
|
||||
/* Zephyr is not POSIX no equivalent for these flags */
|
||||
/* __WASI_O_DIRECTORY: Open shouldn't handle directories */
|
||||
// TODO: log warning
|
||||
}
|
||||
|
||||
// Convert file descriptor flags.
|
||||
if ((fd_flags & __WASI_FDFLAG_APPEND) != 0) {
|
||||
mode |= FS_O_APPEND;
|
||||
}
|
||||
if (((fd_flags & __WASI_FDFLAG_DSYNC) != 0)
|
||||
|| ((fd_flags & __WASI_FDFLAG_RSYNC) != 0)
|
||||
|| ((fd_flags & __WASI_FDFLAG_SYNC) != 0)
|
||||
|| ((fd_flags & __WASI_FDFLAG_NONBLOCK) != 0)) {
|
||||
/* Zephyr is not POSIX no equivalent for these flags */
|
||||
// TODO: log warning
|
||||
}
|
||||
|
||||
// Convert lookup flag.
|
||||
if ((lookup_flags & __WASI_LOOKUP_SYMLINK_FOLLOW) == 0) {
|
||||
/* Zephyr is not POSIX no equivalent for these flags */
|
||||
// TODO: log warning
|
||||
return __WASI_ENOTSUP;
|
||||
}
|
||||
|
||||
// Convert access mode.
|
||||
switch (access_mode) {
|
||||
case WASI_LIBC_ACCESS_MODE_READ_WRITE:
|
||||
mode |= FS_O_RDWR;
|
||||
break;
|
||||
case WASI_LIBC_ACCESS_MODE_READ_ONLY:
|
||||
mode |= FS_O_READ;
|
||||
break;
|
||||
case WASI_LIBC_ACCESS_MODE_WRITE_ONLY:
|
||||
mode |= FS_O_WRITE;
|
||||
break;
|
||||
default:
|
||||
// TODO: log warning
|
||||
break;
|
||||
}
|
||||
return mode;
|
||||
}
|
||||
|
||||
__wasi_errno_t
|
||||
os_openat(os_file_handle handle, const char *path, __wasi_oflags_t oflags,
|
||||
__wasi_fdflags_t fd_flags, __wasi_lookupflags_t lookup_flags,
|
||||
wasi_libc_file_access_mode access_mode, os_file_handle *out)
|
||||
{
|
||||
/*
|
||||
* `handle` will be unused because zephyr doesn't expose an openat
|
||||
* function and don't seem to have the concept of relative path.
|
||||
* We fill `out` with a new file descriptor.
|
||||
*/
|
||||
int rc, index;
|
||||
struct zephyr_fs_desc *ptr = NULL;
|
||||
char abs_path[MAX_FILE_NAME + 1];
|
||||
|
||||
*out = BH_MALLOC(sizeof(struct zephyr_handle));
|
||||
if (*out == NULL) {
|
||||
return __WASI_ENOMEM;
|
||||
}
|
||||
|
||||
snprintf(abs_path, MAX_FILE_NAME, "%s/%s", prestat_dir, path);
|
||||
int zmode =
|
||||
wasi_flags_to_zephyr(oflags, fd_flags, lookup_flags, access_mode);
|
||||
|
||||
ptr = zephyr_fs_alloc_obj(false, abs_path, &index);
|
||||
if (!ptr && (index < 0)) {
|
||||
BH_FREE(*out);
|
||||
return __WASI_EMFILE;
|
||||
}
|
||||
|
||||
fs_file_t_init(&ptr->file);
|
||||
rc = fs_open(&ptr->file, abs_path, zmode);
|
||||
if (rc < 0) {
|
||||
zephyr_fs_free_obj(ptr);
|
||||
BH_FREE(*out);
|
||||
return convert_errno(-rc);
|
||||
}
|
||||
|
||||
(*out)->fd = index;
|
||||
(*out)->is_sock = false;
|
||||
|
||||
return __WASI_ESUCCESS;
|
||||
}
|
||||
|
||||
__wasi_errno_t
|
||||
os_file_get_access_mode(os_file_handle handle,
|
||||
wasi_libc_file_access_mode *access_mode)
|
||||
{
|
||||
struct zephyr_fs_desc *ptr = NULL;
|
||||
|
||||
if (handle->is_sock) {
|
||||
// for socket we can use the following code
|
||||
// TODO: Need to determine better logic
|
||||
*access_mode = WASI_LIBC_ACCESS_MODE_READ_WRITE;
|
||||
return __WASI_ESUCCESS;
|
||||
}
|
||||
|
||||
GET_FILE_SYSTEM_DESCRIPTOR(handle->fd, ptr);
|
||||
|
||||
if ((ptr->file.flags & FS_O_RDWR) != 0) {
|
||||
*access_mode = WASI_LIBC_ACCESS_MODE_READ_WRITE;
|
||||
}
|
||||
else if ((ptr->file.flags & FS_O_READ) != 0) {
|
||||
*access_mode = WASI_LIBC_ACCESS_MODE_READ_ONLY;
|
||||
}
|
||||
else if ((ptr->file.flags & FS_O_WRITE) != 0) {
|
||||
*access_mode = WASI_LIBC_ACCESS_MODE_WRITE_ONLY;
|
||||
}
|
||||
else {
|
||||
// we return read/write by default
|
||||
*access_mode = WASI_LIBC_ACCESS_MODE_READ_WRITE;
|
||||
}
|
||||
return __WASI_ESUCCESS;
|
||||
}
|
||||
|
||||
__wasi_errno_t
|
||||
os_close(os_file_handle handle, bool is_stdio)
|
||||
{
|
||||
int rc;
|
||||
struct zephyr_fs_desc *ptr = NULL;
|
||||
|
||||
if (is_stdio)
|
||||
return __WASI_ESUCCESS;
|
||||
|
||||
GET_FILE_SYSTEM_DESCRIPTOR(handle->fd, ptr);
|
||||
|
||||
rc = ptr->is_dir ? fs_closedir(&ptr->dir) : fs_close(&ptr->file);
|
||||
zephyr_fs_free_obj(ptr); // free in any case.
|
||||
BH_FREE(handle);
|
||||
if (rc < 0) {
|
||||
return convert_errno(-rc);
|
||||
}
|
||||
|
||||
return __WASI_ESUCCESS;
|
||||
}
|
||||
|
||||
__wasi_errno_t
|
||||
os_preadv(os_file_handle handle, const struct __wasi_iovec_t *iov, int iovcnt,
|
||||
__wasi_filesize_t offset, size_t *nread)
|
||||
{
|
||||
struct zephyr_fs_desc *ptr = NULL;
|
||||
int rc;
|
||||
ssize_t total_read = 0;
|
||||
|
||||
GET_FILE_SYSTEM_DESCRIPTOR(handle->fd, ptr);
|
||||
|
||||
// Seek to the offset
|
||||
rc = fs_seek(&ptr->file, offset, FS_SEEK_SET);
|
||||
if (rc < 0) {
|
||||
return convert_errno(-rc);
|
||||
}
|
||||
|
||||
// Read data into each buffer
|
||||
for (int i = 0; i < iovcnt; i++) {
|
||||
ssize_t bytes_read = fs_read(&ptr->file, iov[i].buf, iov[i].buf_len);
|
||||
if (bytes_read < 0) {
|
||||
return convert_errno(-bytes_read);
|
||||
}
|
||||
|
||||
total_read += bytes_read;
|
||||
|
||||
// If we read less than we asked for, stop reading
|
||||
if (bytes_read < iov[i].buf_len) {
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
*nread = total_read;
|
||||
|
||||
return __WASI_ESUCCESS;
|
||||
}
|
||||
|
||||
__wasi_errno_t
|
||||
os_pwritev(os_file_handle handle, const struct __wasi_ciovec_t *iov, int iovcnt,
|
||||
__wasi_filesize_t offset, size_t *nwritten)
|
||||
{
|
||||
struct zephyr_fs_desc *ptr = NULL;
|
||||
ssize_t total_written = 0;
|
||||
|
||||
GET_FILE_SYSTEM_DESCRIPTOR(handle->fd, ptr);
|
||||
|
||||
// Seek to the offset
|
||||
int rc = fs_seek(&ptr->file, offset, FS_SEEK_SET);
|
||||
if (rc < 0) {
|
||||
return convert_errno(-rc);
|
||||
}
|
||||
|
||||
// Write data from each buffer
|
||||
for (int i = 0; i < iovcnt; i++) {
|
||||
ssize_t bytes_written =
|
||||
fs_write(&ptr->file, iov[i].buf, iov[i].buf_len);
|
||||
if (bytes_written < 0) {
|
||||
return convert_errno(-bytes_written);
|
||||
}
|
||||
|
||||
total_written += bytes_written;
|
||||
|
||||
// If we wrote less than we asked for, stop writing
|
||||
if (bytes_written < iov[i].buf_len) {
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
*nwritten = total_written;
|
||||
|
||||
return __WASI_ESUCCESS;
|
||||
}
|
||||
|
||||
__wasi_errno_t
|
||||
os_readv(os_file_handle handle, const struct __wasi_iovec_t *iov, int iovcnt,
|
||||
size_t *nread)
|
||||
{
|
||||
struct zephyr_fs_desc *ptr = NULL;
|
||||
ssize_t total_read = 0;
|
||||
|
||||
GET_FILE_SYSTEM_DESCRIPTOR(handle->fd, ptr);
|
||||
|
||||
// Read data into each buffer
|
||||
for (int i = 0; i < iovcnt; i++) {
|
||||
ssize_t bytes_read = fs_read(&ptr->file, iov[i].buf, iov[i].buf_len);
|
||||
if (bytes_read < 0) {
|
||||
// If an error occurred, return it
|
||||
return convert_errno(-bytes_read);
|
||||
}
|
||||
|
||||
total_read += bytes_read;
|
||||
|
||||
// If we read less than we asked for, stop reading
|
||||
if (bytes_read < iov[i].buf_len) {
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
*nread = total_read;
|
||||
|
||||
return __WASI_ESUCCESS;
|
||||
}
|
||||
|
||||
/* With wasi-libc we need to redirect write on stdout/err to printf */
|
||||
// TODO: handle write on stdin
|
||||
__wasi_errno_t
|
||||
os_writev(os_file_handle handle, const struct __wasi_ciovec_t *iov, int iovcnt,
|
||||
size_t *nwritten)
|
||||
{
|
||||
struct zephyr_fs_desc *ptr = NULL;
|
||||
ssize_t total_written = 0;
|
||||
|
||||
GET_FILE_SYSTEM_DESCRIPTOR(handle->fd, ptr);
|
||||
|
||||
if (strncmp(ptr->path, "std", 3) == 0) {
|
||||
// for std[in/out/err] we don't write because they are not real opened
|
||||
// files. Instead we emulate a write operation to make it work with
|
||||
// printf.
|
||||
for (int i = 0; i < iovcnt; i++) {
|
||||
if (iov[i].buf_len == 0)
|
||||
continue;
|
||||
os_printf("%s", (char *)iov[i].buf);
|
||||
total_written += iov[i].buf_len;
|
||||
|
||||
// Clear the buffer after printing
|
||||
memset(iov[i].buf, 0, iov[i].buf_len);
|
||||
}
|
||||
*nwritten = total_written;
|
||||
|
||||
return __WASI_ESUCCESS;
|
||||
}
|
||||
|
||||
// Write data from each buffer
|
||||
for (int i = 0; i < iovcnt; i++) {
|
||||
ssize_t bytes_written =
|
||||
fs_write(&ptr->file, iov[i].buf, iov[i].buf_len);
|
||||
if (bytes_written < 0) {
|
||||
return convert_errno(-bytes_written);
|
||||
}
|
||||
|
||||
total_written += bytes_written;
|
||||
|
||||
// If we wrote less than we asked for, stop writing
|
||||
if (bytes_written < iov[i].buf_len) {
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
*nwritten = total_written;
|
||||
|
||||
return __WASI_ESUCCESS;
|
||||
}
|
||||
|
||||
__wasi_errno_t
|
||||
os_fallocate(os_file_handle handle, __wasi_filesize_t offset,
|
||||
__wasi_filesize_t length)
|
||||
{
|
||||
return __WASI_ENOSYS;
|
||||
}
|
||||
|
||||
__wasi_errno_t
|
||||
os_ftruncate(os_file_handle handle, __wasi_filesize_t size)
|
||||
{
|
||||
struct zephyr_fs_desc *ptr = NULL;
|
||||
|
||||
GET_FILE_SYSTEM_DESCRIPTOR(handle->fd, ptr);
|
||||
|
||||
int rc = fs_truncate(&ptr->file, (off_t)size);
|
||||
if (rc < 0) {
|
||||
return convert_errno(-rc);
|
||||
}
|
||||
|
||||
return __WASI_ESUCCESS;
|
||||
}
|
||||
|
||||
__wasi_errno_t
|
||||
os_futimens(os_file_handle handle, __wasi_timestamp_t access_time,
|
||||
__wasi_timestamp_t modification_time, __wasi_fstflags_t fstflags)
|
||||
{
|
||||
return __WASI_ENOSYS;
|
||||
}
|
||||
|
||||
__wasi_errno_t
|
||||
os_utimensat(os_file_handle handle, const char *path,
|
||||
__wasi_timestamp_t access_time,
|
||||
__wasi_timestamp_t modification_time, __wasi_fstflags_t fstflags,
|
||||
__wasi_lookupflags_t lookup_flags)
|
||||
{
|
||||
return __WASI_ENOSYS;
|
||||
}
|
||||
|
||||
__wasi_errno_t
|
||||
os_readlinkat(os_file_handle handle, const char *path, char *buf,
|
||||
size_t bufsize, size_t *nread)
|
||||
{
|
||||
return __WASI_ENOSYS;
|
||||
}
|
||||
|
||||
__wasi_errno_t
|
||||
os_linkat(os_file_handle from_handle, const char *from_path,
|
||||
os_file_handle to_handle, const char *to_path,
|
||||
__wasi_lookupflags_t lookup_flags)
|
||||
{
|
||||
return __WASI_ENOSYS;
|
||||
}
|
||||
|
||||
__wasi_errno_t
|
||||
os_symlinkat(const char *old_path, os_file_handle handle, const char *new_path)
|
||||
{
|
||||
return __WASI_ENOSYS;
|
||||
}
|
||||
|
||||
__wasi_errno_t
|
||||
os_mkdirat(os_file_handle handle, const char *path)
|
||||
{
|
||||
struct zephyr_fs_desc *ptr = NULL;
|
||||
int index, rc;
|
||||
char abs_path[MAX_FILE_NAME + 1];
|
||||
|
||||
if (handle == NULL) {
|
||||
return __WASI_EINVAL; // Or another appropriate error code
|
||||
}
|
||||
|
||||
snprintf(abs_path, MAX_FILE_NAME, "%s/%s", prestat_dir, path);
|
||||
|
||||
rc = fs_mkdir(abs_path);
|
||||
if (rc < 0) {
|
||||
return convert_errno(-rc);
|
||||
}
|
||||
|
||||
ptr = zephyr_fs_alloc_obj(true, abs_path, &index);
|
||||
if (!ptr) {
|
||||
fs_unlink(abs_path);
|
||||
return __WASI_EMFILE;
|
||||
}
|
||||
fs_dir_t_init(&ptr->dir);
|
||||
|
||||
handle->fd = index;
|
||||
handle->is_sock = false;
|
||||
|
||||
return __WASI_ESUCCESS;
|
||||
}
|
||||
|
||||
__wasi_errno_t
|
||||
os_renameat(os_file_handle old_handle, const char *old_path,
|
||||
os_file_handle new_handle, const char *new_path)
|
||||
{
|
||||
/* `old_handle` need to be the the fd of the file to rename.
|
||||
* `new_handle` will not be used.
|
||||
* paths need to be absolute, no relative path will be accepted.
|
||||
*/
|
||||
struct zephyr_fs_desc *ptr = NULL;
|
||||
(void)new_handle;
|
||||
|
||||
char abs_old_path[MAX_FILE_NAME + 1];
|
||||
char abs_new_path[MAX_FILE_NAME + 1];
|
||||
|
||||
snprintf(abs_old_path, MAX_FILE_NAME, "%s/%s", prestat_dir, old_path);
|
||||
snprintf(abs_new_path, MAX_FILE_NAME, "%s/%s", prestat_dir, new_path);
|
||||
|
||||
int rc = fs_rename(abs_old_path, abs_new_path);
|
||||
if (rc < 0) {
|
||||
return convert_errno(-rc);
|
||||
}
|
||||
|
||||
GET_FILE_SYSTEM_DESCRIPTOR(old_handle->fd, ptr);
|
||||
|
||||
ptr->path = strdup(new_path);
|
||||
if (ptr->path == NULL) {
|
||||
ptr->path = old_path;
|
||||
return __WASI_ENOMEM;
|
||||
}
|
||||
|
||||
return __WASI_ESUCCESS;
|
||||
}
|
||||
|
||||
__wasi_errno_t
|
||||
os_unlinkat(os_file_handle handle, const char *path, bool is_dir)
|
||||
{
|
||||
/* `old_handle` need to be the the fd of the file to unlink.
|
||||
* `path` need to be absolute, relative path will not be resolved.
|
||||
*/
|
||||
char abs_path[MAX_FILE_NAME + 1];
|
||||
struct zephyr_fs_desc *ptr = NULL;
|
||||
|
||||
snprintf(abs_path, MAX_FILE_NAME, "%s/%s", prestat_dir, path);
|
||||
|
||||
if (is_dir) {
|
||||
return __WASI_ENOTDIR;
|
||||
}
|
||||
|
||||
int rc = fs_unlink(path);
|
||||
if (rc < 0) {
|
||||
return convert_errno(-rc);
|
||||
}
|
||||
|
||||
GET_FILE_SYSTEM_DESCRIPTOR(handle->fd, ptr);
|
||||
|
||||
zephyr_fs_free_obj(ptr);
|
||||
|
||||
return __WASI_ESUCCESS;
|
||||
}
|
||||
|
||||
__wasi_errno_t
|
||||
os_lseek(os_file_handle handle, __wasi_filedelta_t offset,
|
||||
__wasi_whence_t whence, __wasi_filesize_t *new_offset)
|
||||
{
|
||||
struct zephyr_fs_desc *ptr = NULL;
|
||||
int zwhence;
|
||||
|
||||
GET_FILE_SYSTEM_DESCRIPTOR(handle->fd, ptr);
|
||||
|
||||
// They have the same value but this is more explicit
|
||||
switch (whence) {
|
||||
case __WASI_WHENCE_SET:
|
||||
zwhence = FS_SEEK_SET;
|
||||
break;
|
||||
case __WASI_WHENCE_CUR:
|
||||
zwhence = FS_SEEK_CUR;
|
||||
break;
|
||||
case __WASI_WHENCE_END:
|
||||
zwhence = FS_SEEK_END;
|
||||
break;
|
||||
default:
|
||||
return __WASI_EINVAL;
|
||||
}
|
||||
|
||||
off_t rc = fs_seek(&ptr->file, (off_t)offset, zwhence);
|
||||
if (rc < 0) {
|
||||
return convert_errno(-rc);
|
||||
}
|
||||
|
||||
*new_offset = (__wasi_filesize_t)rc;
|
||||
|
||||
return __WASI_ESUCCESS;
|
||||
}
|
||||
|
||||
__wasi_errno_t
|
||||
os_fadvise(os_file_handle handle, __wasi_filesize_t offset,
|
||||
__wasi_filesize_t length, __wasi_advice_t advice)
|
||||
{
|
||||
return __WASI_ENOSYS;
|
||||
}
|
||||
|
||||
__wasi_errno_t
|
||||
os_isatty(os_file_handle handle)
|
||||
{
|
||||
return __WASI_ENOSYS;
|
||||
}
|
||||
|
||||
os_file_handle
|
||||
os_convert_stdin_handle(os_raw_file_handle raw_stdin)
|
||||
{
|
||||
os_file_handle handle = BH_MALLOC(sizeof(struct zephyr_handle));
|
||||
if (handle == NULL) {
|
||||
return NULL;
|
||||
}
|
||||
|
||||
/* We allocate a fake stdin reference */
|
||||
if (zephyr_fs_alloc_obj(false, "stdin", &handle->fd) == NULL) {
|
||||
BH_FREE(handle);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
handle->is_sock = false;
|
||||
return handle;
|
||||
}
|
||||
|
||||
os_file_handle
|
||||
os_convert_stdout_handle(os_raw_file_handle raw_stdout)
|
||||
{
|
||||
os_file_handle handle = BH_MALLOC(sizeof(struct zephyr_handle));
|
||||
if (handle == NULL) {
|
||||
return NULL;
|
||||
}
|
||||
|
||||
/* We allocate a fake stdin reference */
|
||||
if (zephyr_fs_alloc_obj(false, "stdout", &handle->fd) == NULL) {
|
||||
BH_FREE(handle);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
handle->is_sock = false;
|
||||
return handle;
|
||||
}
|
||||
|
||||
os_file_handle
|
||||
os_convert_stderr_handle(os_raw_file_handle raw_stderr)
|
||||
{
|
||||
os_file_handle handle = BH_MALLOC(sizeof(struct zephyr_handle));
|
||||
if (handle == NULL) {
|
||||
return NULL;
|
||||
}
|
||||
|
||||
/* We allocate a fake stdin reference */
|
||||
if (zephyr_fs_alloc_obj(false, "stderr", &handle->fd) == NULL) {
|
||||
BH_FREE(handle);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
handle->is_sock = false;
|
||||
return handle;
|
||||
}
|
||||
|
||||
__wasi_errno_t
|
||||
os_fdopendir(os_file_handle handle, os_dir_stream *dir_stream)
|
||||
{
|
||||
/* Here we assume that either mdkdir or preopendir was called
|
||||
* before otherwise function will fail.
|
||||
*/
|
||||
struct zephyr_fs_desc *ptr = NULL;
|
||||
|
||||
GET_FILE_SYSTEM_DESCRIPTOR(handle->fd, ptr);
|
||||
if (!ptr->is_dir) {
|
||||
return __WASI_ENOTDIR;
|
||||
}
|
||||
|
||||
int rc = fs_opendir(&ptr->dir, ptr->path);
|
||||
if (rc < 0) {
|
||||
return convert_errno(-rc);
|
||||
}
|
||||
|
||||
/* we store the fd in the `os_dir_stream` to use other function */
|
||||
*dir_stream = handle->fd;
|
||||
|
||||
return __WASI_ESUCCESS;
|
||||
}
|
||||
|
||||
__wasi_errno_t
|
||||
os_rewinddir(os_dir_stream dir_stream)
|
||||
{
|
||||
return __WASI_ENOSYS;
|
||||
}
|
||||
|
||||
__wasi_errno_t
|
||||
os_seekdir(os_dir_stream dir_stream, __wasi_dircookie_t position)
|
||||
{
|
||||
return __WASI_ENOSYS;
|
||||
}
|
||||
|
||||
__wasi_errno_t
|
||||
os_readdir(os_dir_stream dir_stream, __wasi_dirent_t *entry,
|
||||
const char **d_name)
|
||||
{
|
||||
struct fs_dirent fs_entry;
|
||||
struct zephyr_fs_desc *ptr = NULL;
|
||||
|
||||
GET_FILE_SYSTEM_DESCRIPTOR(dir_stream, ptr);
|
||||
if (!ptr->is_dir) {
|
||||
return __WASI_ENOTDIR;
|
||||
}
|
||||
|
||||
int rc = fs_readdir(&ptr->dir, &fs_entry);
|
||||
if (rc < 0) {
|
||||
return convert_errno(-rc);
|
||||
}
|
||||
|
||||
entry->d_next = 0; // default value to start of the directory.
|
||||
entry->d_ino = 0; // no inode in zephyr
|
||||
entry->d_namlen = strlen(fs_entry.name);
|
||||
entry->d_type = fs_entry.type == FS_DIR_ENTRY_DIR
|
||||
? __WASI_FILETYPE_DIRECTORY
|
||||
: __WASI_FILETYPE_REGULAR_FILE;
|
||||
|
||||
return __WASI_ESUCCESS;
|
||||
}
|
||||
|
||||
__wasi_errno_t
|
||||
os_closedir(os_dir_stream dir_stream)
|
||||
{
|
||||
struct zephyr_fs_desc *ptr = NULL;
|
||||
|
||||
GET_FILE_SYSTEM_DESCRIPTOR(dir_stream, ptr);
|
||||
if (!ptr->is_dir) {
|
||||
return __WASI_ENOTDIR;
|
||||
}
|
||||
|
||||
int rc = fs_closedir(&ptr->dir);
|
||||
zephyr_fs_free_obj(ptr); // free in any case.
|
||||
if (rc < 0) {
|
||||
return convert_errno(-rc);
|
||||
}
|
||||
|
||||
return __WASI_ESUCCESS;
|
||||
}
|
||||
|
||||
os_dir_stream
|
||||
os_get_invalid_dir_stream()
|
||||
{
|
||||
return NULL;
|
||||
}
|
||||
|
||||
bool
|
||||
os_is_dir_stream_valid(os_dir_stream *dir_stream)
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
bool
|
||||
os_is_handle_valid(os_file_handle *handle)
|
||||
{
|
||||
if (handle == NULL || *handle == NULL) {
|
||||
return false;
|
||||
}
|
||||
return (*handle)->fd > -1;
|
||||
}
|
||||
|
||||
char *
|
||||
os_realpath(const char *path, char *resolved_path)
|
||||
{
|
||||
/* In fact we could implement a path resolving method, because every paths
|
||||
* are at one point put into memory.
|
||||
* We could then maintain a 'tree' to represent the file system.
|
||||
* --> The file system root is easily accessable with:
|
||||
* * (fs_dir_t) dir.mp->mnt_point
|
||||
* * (fs_file_t) file.mp->mnt_point
|
||||
* But we will just use absolute path for now.
|
||||
*/
|
||||
if (!path) {
|
||||
// Log error
|
||||
return NULL;
|
||||
}
|
||||
return (const char *)path;
|
||||
}
|
||||
|
||||
bool
|
||||
os_compare_file_handle(os_file_handle handle1, os_file_handle handle2)
|
||||
{
|
||||
return handle1->fd == handle2->fd && handle1->is_sock == handle2->is_sock;
|
||||
}
|
1048
core/shared/platform/zephyr/zephyr_socket.c
Normal file
1048
core/shared/platform/zephyr/zephyr_socket.c
Normal file
File diff suppressed because it is too large
Load Diff
|
@ -34,22 +34,22 @@
|
|||
static K_THREAD_STACK_ARRAY_DEFINE(mpu_stacks, BH_ZEPHYR_MPU_STACK_COUNT,
|
||||
BH_ZEPHYR_MPU_STACK_SIZE);
|
||||
static bool mpu_stack_allocated[BH_ZEPHYR_MPU_STACK_COUNT];
|
||||
static mutex_t mpu_stack_lock;
|
||||
static zmutex_t mpu_stack_lock;
|
||||
|
||||
static char *
|
||||
mpu_stack_alloc()
|
||||
{
|
||||
int i;
|
||||
|
||||
mutex_lock(&mpu_stack_lock, K_FOREVER);
|
||||
zmutex_lock(&mpu_stack_lock, K_FOREVER);
|
||||
for (i = 0; i < BH_ZEPHYR_MPU_STACK_COUNT; i++) {
|
||||
if (!mpu_stack_allocated[i]) {
|
||||
mpu_stack_allocated[i] = true;
|
||||
mutex_unlock(&mpu_stack_lock);
|
||||
zmutex_unlock(&mpu_stack_lock);
|
||||
return (char *)mpu_stacks[i];
|
||||
}
|
||||
}
|
||||
mutex_unlock(&mpu_stack_lock);
|
||||
zmutex_unlock(&mpu_stack_lock);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
|
@ -58,17 +58,17 @@ mpu_stack_free(char *stack)
|
|||
{
|
||||
int i;
|
||||
|
||||
mutex_lock(&mpu_stack_lock, K_FOREVER);
|
||||
zmutex_lock(&mpu_stack_lock, K_FOREVER);
|
||||
for (i = 0; i < BH_ZEPHYR_MPU_STACK_COUNT; i++) {
|
||||
if ((char *)mpu_stacks[i] == stack)
|
||||
mpu_stack_allocated[i] = false;
|
||||
}
|
||||
mutex_unlock(&mpu_stack_lock);
|
||||
zmutex_unlock(&mpu_stack_lock);
|
||||
}
|
||||
#endif
|
||||
|
||||
typedef struct os_thread_wait_node {
|
||||
sem_t sem;
|
||||
zsem_t sem;
|
||||
os_thread_wait_list next;
|
||||
} os_thread_wait_node;
|
||||
|
||||
|
@ -80,7 +80,7 @@ typedef struct os_thread_data {
|
|||
/* Jeff thread local root */
|
||||
void *tlr;
|
||||
/* Lock for waiting list */
|
||||
mutex_t wait_list_lock;
|
||||
zmutex_t wait_list_lock;
|
||||
/* Waiting list of other threads who are joining this thread */
|
||||
os_thread_wait_list thread_wait_list;
|
||||
/* Thread stack size */
|
||||
|
@ -107,13 +107,13 @@ static bool is_thread_sys_inited = false;
|
|||
static os_thread_data supervisor_thread_data;
|
||||
|
||||
/* Lock for thread data list */
|
||||
static mutex_t thread_data_lock;
|
||||
static zmutex_t thread_data_lock;
|
||||
|
||||
/* Thread data list */
|
||||
static os_thread_data *thread_data_list = NULL;
|
||||
|
||||
/* Lock for thread object list */
|
||||
static mutex_t thread_obj_lock;
|
||||
static zmutex_t thread_obj_lock;
|
||||
|
||||
/* Thread object list */
|
||||
static os_thread_obj *thread_obj_list = NULL;
|
||||
|
@ -121,7 +121,7 @@ static os_thread_obj *thread_obj_list = NULL;
|
|||
static void
|
||||
thread_data_list_add(os_thread_data *thread_data)
|
||||
{
|
||||
mutex_lock(&thread_data_lock, K_FOREVER);
|
||||
zmutex_lock(&thread_data_lock, K_FOREVER);
|
||||
if (!thread_data_list)
|
||||
thread_data_list = thread_data;
|
||||
else {
|
||||
|
@ -129,7 +129,7 @@ thread_data_list_add(os_thread_data *thread_data)
|
|||
os_thread_data *p = thread_data_list;
|
||||
while (p) {
|
||||
if (p == thread_data) {
|
||||
mutex_unlock(&thread_data_lock);
|
||||
zmutex_unlock(&thread_data_lock);
|
||||
return;
|
||||
}
|
||||
p = p->next;
|
||||
|
@ -139,13 +139,13 @@ thread_data_list_add(os_thread_data *thread_data)
|
|||
thread_data->next = thread_data_list;
|
||||
thread_data_list = thread_data;
|
||||
}
|
||||
mutex_unlock(&thread_data_lock);
|
||||
zmutex_unlock(&thread_data_lock);
|
||||
}
|
||||
|
||||
static void
|
||||
thread_data_list_remove(os_thread_data *thread_data)
|
||||
{
|
||||
mutex_lock(&thread_data_lock, K_FOREVER);
|
||||
zmutex_lock(&thread_data_lock, K_FOREVER);
|
||||
if (thread_data_list) {
|
||||
if (thread_data_list == thread_data)
|
||||
thread_data_list = thread_data_list->next;
|
||||
|
@ -158,32 +158,32 @@ thread_data_list_remove(os_thread_data *thread_data)
|
|||
p->next = p->next->next;
|
||||
}
|
||||
}
|
||||
mutex_unlock(&thread_data_lock);
|
||||
zmutex_unlock(&thread_data_lock);
|
||||
}
|
||||
|
||||
static os_thread_data *
|
||||
thread_data_list_lookup(k_tid_t tid)
|
||||
{
|
||||
mutex_lock(&thread_data_lock, K_FOREVER);
|
||||
zmutex_lock(&thread_data_lock, K_FOREVER);
|
||||
if (thread_data_list) {
|
||||
os_thread_data *p = thread_data_list;
|
||||
while (p) {
|
||||
if (p->tid == tid) {
|
||||
/* Found */
|
||||
mutex_unlock(&thread_data_lock);
|
||||
zmutex_unlock(&thread_data_lock);
|
||||
return p;
|
||||
}
|
||||
p = p->next;
|
||||
}
|
||||
}
|
||||
mutex_unlock(&thread_data_lock);
|
||||
zmutex_unlock(&thread_data_lock);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
static void
|
||||
thread_obj_list_add(os_thread_obj *thread_obj)
|
||||
{
|
||||
mutex_lock(&thread_obj_lock, K_FOREVER);
|
||||
zmutex_lock(&thread_obj_lock, K_FOREVER);
|
||||
if (!thread_obj_list)
|
||||
thread_obj_list = thread_obj;
|
||||
else {
|
||||
|
@ -191,14 +191,14 @@ thread_obj_list_add(os_thread_obj *thread_obj)
|
|||
thread_obj->next = thread_obj_list;
|
||||
thread_obj_list = thread_obj;
|
||||
}
|
||||
mutex_unlock(&thread_obj_lock);
|
||||
zmutex_unlock(&thread_obj_lock);
|
||||
}
|
||||
|
||||
static void
|
||||
thread_obj_list_reclaim()
|
||||
{
|
||||
os_thread_obj *p, *p_prev;
|
||||
mutex_lock(&thread_obj_lock, K_FOREVER);
|
||||
zmutex_lock(&thread_obj_lock, K_FOREVER);
|
||||
p_prev = NULL;
|
||||
p = thread_obj_list;
|
||||
while (p) {
|
||||
|
@ -219,7 +219,7 @@ thread_obj_list_reclaim()
|
|||
p = p->next;
|
||||
}
|
||||
}
|
||||
mutex_unlock(&thread_obj_lock);
|
||||
zmutex_unlock(&thread_obj_lock);
|
||||
}
|
||||
|
||||
int
|
||||
|
@ -229,10 +229,10 @@ os_thread_sys_init()
|
|||
return BHT_OK;
|
||||
|
||||
#if BH_ENABLE_ZEPHYR_MPU_STACK != 0
|
||||
mutex_init(&mpu_stack_lock);
|
||||
zmutex_init(&mpu_stack_lock);
|
||||
#endif
|
||||
mutex_init(&thread_data_lock);
|
||||
mutex_init(&thread_obj_lock);
|
||||
zmutex_init(&thread_data_lock);
|
||||
zmutex_init(&thread_obj_lock);
|
||||
|
||||
/* Initialize supervisor thread data */
|
||||
memset(&supervisor_thread_data, 0, sizeof(supervisor_thread_data));
|
||||
|
@ -265,19 +265,19 @@ os_thread_cleanup(void)
|
|||
os_thread_data *thread_data = thread_data_current();
|
||||
|
||||
bh_assert(thread_data != NULL);
|
||||
mutex_lock(&thread_data->wait_list_lock, K_FOREVER);
|
||||
zmutex_lock(&thread_data->wait_list_lock, K_FOREVER);
|
||||
if (thread_data->thread_wait_list) {
|
||||
/* Signal each joining thread */
|
||||
os_thread_wait_list head = thread_data->thread_wait_list;
|
||||
while (head) {
|
||||
os_thread_wait_list next = head->next;
|
||||
sem_give(&head->sem);
|
||||
zsem_give(&head->sem);
|
||||
/* head will be freed by joining thread */
|
||||
head = next;
|
||||
}
|
||||
thread_data->thread_wait_list = NULL;
|
||||
}
|
||||
mutex_unlock(&thread_data->wait_list_lock);
|
||||
zmutex_unlock(&thread_data->wait_list_lock);
|
||||
|
||||
thread_data_list_remove(thread_data);
|
||||
/* Set flag to true for the next thread creating to
|
||||
|
@ -342,7 +342,7 @@ os_thread_create_with_prio(korp_tid *p_tid, thread_start_routine_t start,
|
|||
}
|
||||
|
||||
memset(thread_data, 0, thread_data_size);
|
||||
mutex_init(&thread_data->wait_list_lock);
|
||||
zmutex_init(&thread_data->wait_list_lock);
|
||||
thread_data->stack_size = stack_size;
|
||||
thread_data->tid = tid;
|
||||
|
||||
|
@ -397,14 +397,14 @@ os_thread_join(korp_tid thread, void **value_ptr)
|
|||
if (!(node = BH_MALLOC(sizeof(os_thread_wait_node))))
|
||||
return BHT_ERROR;
|
||||
|
||||
sem_init(&node->sem, 0, 1);
|
||||
zsem_init(&node->sem, 0, 1);
|
||||
node->next = NULL;
|
||||
|
||||
/* Get thread data */
|
||||
thread_data = thread_data_list_lookup(thread);
|
||||
bh_assert(thread_data != NULL);
|
||||
|
||||
mutex_lock(&thread_data->wait_list_lock, K_FOREVER);
|
||||
zmutex_lock(&thread_data->wait_list_lock, K_FOREVER);
|
||||
if (!thread_data->thread_wait_list)
|
||||
thread_data->thread_wait_list = node;
|
||||
else {
|
||||
|
@ -414,10 +414,10 @@ os_thread_join(korp_tid thread, void **value_ptr)
|
|||
p = p->next;
|
||||
p->next = node;
|
||||
}
|
||||
mutex_unlock(&thread_data->wait_list_lock);
|
||||
zmutex_unlock(&thread_data->wait_list_lock);
|
||||
|
||||
/* Wait the sem */
|
||||
sem_take(&node->sem, K_FOREVER);
|
||||
zsem_take(&node->sem, K_FOREVER);
|
||||
|
||||
/* Wait some time for the thread to be actually terminated */
|
||||
k_sleep(Z_TIMEOUT_MS(100));
|
||||
|
@ -430,14 +430,14 @@ os_thread_join(korp_tid thread, void **value_ptr)
|
|||
int
|
||||
os_mutex_init(korp_mutex *mutex)
|
||||
{
|
||||
mutex_init(mutex);
|
||||
zmutex_init(mutex);
|
||||
return BHT_OK;
|
||||
}
|
||||
|
||||
int
|
||||
os_recursive_mutex_init(korp_mutex *mutex)
|
||||
{
|
||||
mutex_init(mutex);
|
||||
zmutex_init(mutex);
|
||||
return BHT_OK;
|
||||
}
|
||||
|
||||
|
@ -451,16 +451,16 @@ os_mutex_destroy(korp_mutex *mutex)
|
|||
int
|
||||
os_mutex_lock(korp_mutex *mutex)
|
||||
{
|
||||
return mutex_lock(mutex, K_FOREVER);
|
||||
return zmutex_lock(mutex, K_FOREVER);
|
||||
}
|
||||
|
||||
int
|
||||
os_mutex_unlock(korp_mutex *mutex)
|
||||
{
|
||||
#if KERNEL_VERSION_NUMBER >= 0x020200 /* version 2.2.0 */
|
||||
return mutex_unlock(mutex);
|
||||
return zmutex_unlock(mutex);
|
||||
#else
|
||||
mutex_unlock(mutex);
|
||||
zmutex_unlock(mutex);
|
||||
return 0;
|
||||
#endif
|
||||
}
|
||||
|
@ -468,7 +468,7 @@ os_mutex_unlock(korp_mutex *mutex)
|
|||
int
|
||||
os_cond_init(korp_cond *cond)
|
||||
{
|
||||
mutex_init(&cond->wait_list_lock);
|
||||
zmutex_init(&cond->wait_list_lock);
|
||||
cond->thread_wait_list = NULL;
|
||||
return BHT_OK;
|
||||
}
|
||||
|
@ -489,10 +489,10 @@ os_cond_wait_internal(korp_cond *cond, korp_mutex *mutex, bool timed, int mills)
|
|||
if (!(node = BH_MALLOC(sizeof(os_thread_wait_node))))
|
||||
return BHT_ERROR;
|
||||
|
||||
sem_init(&node->sem, 0, 1);
|
||||
zsem_init(&node->sem, 0, 1);
|
||||
node->next = NULL;
|
||||
|
||||
mutex_lock(&cond->wait_list_lock, K_FOREVER);
|
||||
zmutex_lock(&cond->wait_list_lock, K_FOREVER);
|
||||
if (!cond->thread_wait_list)
|
||||
cond->thread_wait_list = node;
|
||||
else {
|
||||
|
@ -502,15 +502,15 @@ os_cond_wait_internal(korp_cond *cond, korp_mutex *mutex, bool timed, int mills)
|
|||
p = p->next;
|
||||
p->next = node;
|
||||
}
|
||||
mutex_unlock(&cond->wait_list_lock);
|
||||
zmutex_unlock(&cond->wait_list_lock);
|
||||
|
||||
/* Unlock mutex, wait sem and lock mutex again */
|
||||
mutex_unlock(mutex);
|
||||
sem_take(&node->sem, timed ? Z_TIMEOUT_MS(mills) : K_FOREVER);
|
||||
mutex_lock(mutex, K_FOREVER);
|
||||
zmutex_unlock(mutex);
|
||||
zsem_take(&node->sem, timed ? Z_TIMEOUT_MS(mills) : K_FOREVER);
|
||||
zmutex_lock(mutex, K_FOREVER);
|
||||
|
||||
/* Remove wait node from wait list */
|
||||
mutex_lock(&cond->wait_list_lock, K_FOREVER);
|
||||
zmutex_lock(&cond->wait_list_lock, K_FOREVER);
|
||||
if (cond->thread_wait_list == node)
|
||||
cond->thread_wait_list = node->next;
|
||||
else {
|
||||
|
@ -521,7 +521,7 @@ os_cond_wait_internal(korp_cond *cond, korp_mutex *mutex, bool timed, int mills)
|
|||
p->next = node->next;
|
||||
}
|
||||
BH_FREE(node);
|
||||
mutex_unlock(&cond->wait_list_lock);
|
||||
zmutex_unlock(&cond->wait_list_lock);
|
||||
|
||||
return BHT_OK;
|
||||
}
|
||||
|
@ -559,10 +559,10 @@ int
|
|||
os_cond_signal(korp_cond *cond)
|
||||
{
|
||||
/* Signal the head wait node of wait list */
|
||||
mutex_lock(&cond->wait_list_lock, K_FOREVER);
|
||||
zmutex_lock(&cond->wait_list_lock, K_FOREVER);
|
||||
if (cond->thread_wait_list)
|
||||
sem_give(&cond->thread_wait_list->sem);
|
||||
mutex_unlock(&cond->wait_list_lock);
|
||||
zsem_give(&cond->thread_wait_list->sem);
|
||||
zmutex_unlock(&cond->wait_list_lock);
|
||||
|
||||
return BHT_OK;
|
||||
}
|
||||
|
@ -582,6 +582,67 @@ void
|
|||
os_thread_jit_write_protect_np(bool enabled)
|
||||
{}
|
||||
|
||||
int
|
||||
os_rwlock_init(korp_rwlock *lock)
|
||||
{
|
||||
if (!lock) {
|
||||
return BHT_ERROR;
|
||||
}
|
||||
|
||||
k_mutex_init(&lock->mtx);
|
||||
k_sem_init(&lock->sem, 0, K_SEM_MAX_LIMIT);
|
||||
lock->read_count = 0;
|
||||
|
||||
return BHT_OK;
|
||||
}
|
||||
|
||||
int
|
||||
os_rwlock_rdlock(korp_rwlock *lock)
|
||||
{
|
||||
/* Not implemented */
|
||||
return BHT_ERROR;
|
||||
}
|
||||
|
||||
int
|
||||
os_rwlock_wrlock(korp_rwlock *lock)
|
||||
{
|
||||
// Acquire the mutex to ensure exclusive access
|
||||
if (k_mutex_lock(&lock->mtx, K_FOREVER) != 0) {
|
||||
return BHT_ERROR;
|
||||
}
|
||||
|
||||
// Wait until there are no readers
|
||||
while (lock->read_count > 0) {
|
||||
// Release the mutex while we're waiting
|
||||
k_mutex_unlock(&lock->mtx);
|
||||
|
||||
// Wait for a short time
|
||||
k_sleep(K_MSEC(1));
|
||||
|
||||
// Re-acquire the mutex
|
||||
if (k_mutex_lock(&lock->mtx, K_FOREVER) != 0) {
|
||||
return BHT_ERROR;
|
||||
}
|
||||
}
|
||||
// At this point, we hold the mutex and there are no readers, so we have the
|
||||
// write lock
|
||||
return BHT_OK;
|
||||
}
|
||||
|
||||
int
|
||||
os_rwlock_unlock(korp_rwlock *lock)
|
||||
{
|
||||
k_mutex_unlock(&lock->mtx);
|
||||
return BHT_OK;
|
||||
}
|
||||
|
||||
int
|
||||
os_rwlock_destroy(korp_rwlock *lock)
|
||||
{
|
||||
/* Not implemented */
|
||||
return BHT_ERROR;
|
||||
}
|
||||
|
||||
int
|
||||
os_thread_detach(korp_tid thread)
|
||||
{
|
||||
|
@ -601,13 +662,88 @@ int
|
|||
os_cond_broadcast(korp_cond *cond)
|
||||
{
|
||||
os_thread_wait_node *node;
|
||||
mutex_lock(&cond->wait_list_lock, K_FOREVER);
|
||||
zmutex_lock(&cond->wait_list_lock, K_FOREVER);
|
||||
node = cond->thread_wait_list;
|
||||
while (node) {
|
||||
os_thread_wait_node *next = node->next;
|
||||
sem_give(&node->sem);
|
||||
zsem_give(&node->sem);
|
||||
node = next;
|
||||
}
|
||||
mutex_unlock(&cond->wait_list_lock);
|
||||
zmutex_unlock(&cond->wait_list_lock);
|
||||
return BHT_OK;
|
||||
}
|
||||
|
||||
korp_sem *
|
||||
os_sem_open(const char *name, int oflags, int mode, int val)
|
||||
{
|
||||
/* Not implemented */
|
||||
return NULL;
|
||||
}
|
||||
|
||||
int
|
||||
os_sem_close(korp_sem *sem)
|
||||
{
|
||||
/* Not implemented */
|
||||
return BHT_ERROR;
|
||||
}
|
||||
|
||||
int
|
||||
os_sem_wait(korp_sem *sem)
|
||||
{
|
||||
/* Not implemented */
|
||||
return BHT_ERROR;
|
||||
}
|
||||
|
||||
int
|
||||
os_sem_trywait(korp_sem *sem)
|
||||
{
|
||||
/* Not implemented */
|
||||
return BHT_ERROR;
|
||||
}
|
||||
|
||||
int
|
||||
os_sem_post(korp_sem *sem)
|
||||
{
|
||||
/* Not implemented */
|
||||
return BHT_ERROR;
|
||||
}
|
||||
|
||||
int
|
||||
os_sem_getvalue(korp_sem *sem, int *sval)
|
||||
{
|
||||
/* Not implemented */
|
||||
return BHT_ERROR;
|
||||
}
|
||||
|
||||
int
|
||||
os_sem_unlink(const char *name)
|
||||
{
|
||||
/* Not implemented */
|
||||
return BHT_ERROR;
|
||||
}
|
||||
|
||||
int
|
||||
os_blocking_op_init()
|
||||
{
|
||||
/* Not implemented */
|
||||
return BHT_ERROR;
|
||||
}
|
||||
|
||||
void
|
||||
os_begin_blocking_op()
|
||||
{
|
||||
/* Not implemented */
|
||||
}
|
||||
|
||||
void
|
||||
os_end_blocking_op()
|
||||
{
|
||||
/* Not implemented */
|
||||
}
|
||||
|
||||
int
|
||||
os_wakeup_blocking_op(korp_tid tid)
|
||||
{
|
||||
/* Not implemented */
|
||||
return BHT_ERROR;
|
||||
}
|
91
product-mini/platforms/zephyr/simple-file/CMakeLists.txt
Normal file
91
product-mini/platforms/zephyr/simple-file/CMakeLists.txt
Normal file
|
@ -0,0 +1,91 @@
|
|||
# Copyright (C) 2019 Intel Corporation. All rights reserved.
|
||||
# SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
|
||||
|
||||
cmake_minimum_required(VERSION 3.8.2)
|
||||
|
||||
find_package(Zephyr REQUIRED HINTS $ENV{ZEPHYR_BASE})
|
||||
project(wamr)
|
||||
|
||||
enable_language (ASM)
|
||||
|
||||
set (WAMR_BUILD_PLATFORM "zephyr")
|
||||
|
||||
# WAMR Configuration:
|
||||
set (WAMR_BUILD_TARGET "THUMB")
|
||||
set (WAMR_BUILD_INTERP 1)
|
||||
set (WAMR_BUILD_FAST_INTERP 0)
|
||||
set (WAMR_BUILD_AOT 1)
|
||||
set (WAMR_BUILD_LIBC_BUILTIN 1) # printf
|
||||
set (WAMR_BUILD_LIBC_WASI 1)
|
||||
set (WAMR_BUILD_LIB_PTHREAD 0)
|
||||
set (WAMR_BUILD_GLOBAL_HEAP_POOL 1)
|
||||
set (WAMR_BUILD_GLOBAL_HEAP_SIZE 131072) # 128 KB
|
||||
# set (WAMR_BUILD_GLOBAL_HEAP_SIZE 65536) # 64 KB
|
||||
|
||||
# Environment variables:
|
||||
|
||||
# Check if WAMR_ROOT_DIR is set
|
||||
if(DEFINED ENV{WAMR_ROOT_DIR})
|
||||
set(WAMR_ROOT_DIR $ENV{WAMR_ROOT_DIR})
|
||||
else()
|
||||
message(FATAL_ERROR "'WAMR_ROOT_DIR' need to be specified")
|
||||
endif()
|
||||
message("wasi-sdk was found at ${WAMR_ROOT_DIR}")
|
||||
|
||||
# Check if WASI_SDK_PATH is set
|
||||
if(NOT $ENV{WASI_SDK_PATH} STREQUAL "")
|
||||
set(WASI_SDK_PATH $ENV{WASI_SDK_PATH})
|
||||
else()
|
||||
find_program(WASM_C_COMPILER clang /opt/wasi-sdk/bin NO_DEFAULT_PATH)
|
||||
if(NOT WASM_C_COMPILER)
|
||||
message(FATAL_ERROR "'wasi-sdk' not found, please ensure wasi-sdk is installed.\
|
||||
You can download and install it from\
|
||||
https://github.com/WebAssembly/wasi-sdk/releases")
|
||||
else()
|
||||
set(WASI_SDK_PATH /opt/wasi-sdk)
|
||||
endif()
|
||||
endif()
|
||||
message("wasi-sdk was found at ${WASI_SDK_PATH}")
|
||||
|
||||
# Check if WAMR_APP_FRAMEWORK_DIR is set
|
||||
if (DEFINED ENV{WAMR_APP_FRAMEWORK_DIR})
|
||||
set(WAMR_APP_FRAMEWORK_DIR $ENV{WAMR_APP_FRAMEWORK_DIR})
|
||||
else()
|
||||
message(FATAL_ERROR "'wamr-app-framework' not found, please ensure they are installed.\
|
||||
You can download and install them from\
|
||||
https://github.com/bytecodealliance/wamr-app-framework")
|
||||
endif()
|
||||
message("wamr-app-framework was found at ${WAMR_APP_FRAMEWORK_DIR}")
|
||||
|
||||
# set the WAMR_SDK_DIR with the path specified in the environment variable
|
||||
set(WAMR_SDK_DIR
|
||||
${WAMR_APP_FRAMEWORK_DIR}/wamr-sdk
|
||||
)
|
||||
|
||||
# set the WAMR_LIBC_BUILTIN_DIR
|
||||
set(WAMR_LIBC_BUILTIN_DIR
|
||||
${WAMR_SDK_DIR}/wamr-sdk/app/libc-builtin-sysroot
|
||||
)
|
||||
|
||||
# set the WAMR_SDK_PACKAGE_OUT_DIR
|
||||
set(WAMR_SDK_PACKAGE_OUT_DIR
|
||||
${CMAKE_CURRENT_BINARY_DIR}/wamr-sdk/app-sdk/wamr-app-framework
|
||||
)
|
||||
|
||||
# # Reset linker flags
|
||||
# set(CMAKE_SHARED_LIBRARY_LINK_C_FLAGS "")
|
||||
# set(CMAKE_SHARED_LIBRARY_LINK_CXX_FLAGS "")
|
||||
|
||||
include (${WAMR_ROOT_DIR}/build-scripts/runtime_lib.cmake)
|
||||
# include (${SHARED_DIR}/utils/uncommon/shared_uncommon.cmake) # in socket-api sample
|
||||
|
||||
# Build the WAMR runtime
|
||||
target_sources(app PRIVATE
|
||||
${WAMR_RUNTIME_LIB_SOURCE}
|
||||
src/main.c)
|
||||
|
||||
# Link libraries like in samples.
|
||||
set(WASI_LIBM "${WASI_SDK_PATH}/share/wasi-sysroot/lib/wasm32-wasi/libm.a")
|
||||
set(WASI_LIBDL "${WASI_SDK_PATH}/share/wasi-sysroot/lib/wasm32-wasi/libdl.a")
|
||||
|
||||
target_link_libraries(app PUBLIC ${WASI_LIBM} ${WASI_LIBDL})
|
91
product-mini/platforms/zephyr/simple-file/README.md
Normal file
91
product-mini/platforms/zephyr/simple-file/README.md
Normal file
|
@ -0,0 +1,91 @@
|
|||
# File sample
|
||||
This sample demonstrates the use of WASI API to interact with the file system.
|
||||
|
||||
> 🛠️ **Work in progress:** The sample is functional but be aware that just a small part of WASI File System API was tested.
|
||||
> Actual Zephyr APIs:
|
||||
> * directory creation = `fs_mkdir`
|
||||
> * file opening/creation = `fs_open`
|
||||
> * file write = `fs_write`
|
||||
> * file offset = `fs_seek`
|
||||
> * file read = `fs_read`
|
||||
> * file close = `fs_close`
|
||||
> * directory close = `fs_closedir`
|
||||
|
||||
## Run Command
|
||||
* **Zephyr Build**
|
||||
1. **Build:** Replace `nucleo_h743zi` with your board name and the `WAMR_BUILD_TARGET` in `CMakeList.txt` with your target architecture.
|
||||
```bash
|
||||
ZEPHYR_BASE=~/zephyrproject/zephyr \
|
||||
WAMR_ROOT_DIR=~/wasm-micro-runtime \
|
||||
WASI_SDK_PATH=~/wasi-sdk-21.0 \
|
||||
WAMR_APP_FRAMEWORK_DIR=~/wamr-app-framework \
|
||||
west build . -b nucleo_h563zi -p always
|
||||
```
|
||||
⚠️ **Warning:** The flags `ZEPHYR_BASE`, `WAMR_ROOT_DIR`, `WASI_SDK_PATH`, and `WAMR_APP_FRAMEWORK_DIR` need to be set otherwise the build will fail.
|
||||
|
||||
2. **Flash:**
|
||||
```bash
|
||||
ZEPHYR_BASE=~/zephyrproject/zephyr west flash
|
||||
```
|
||||
|
||||
3. **Monitor:** Use a serial link to monitor the output. Personally, I use minicom.
|
||||
```bash
|
||||
minicom -D /dev/ttyACM0
|
||||
```
|
||||
|
||||
4. **Debug:** Curently investigating.
|
||||
|
||||
* **WebAssembly Module**
|
||||
|
||||
❗ **Important:** I used wasi-sdk 21 to compile the module. I still haven't tried the module with the new wasi-sdk 22.
|
||||
|
||||
1. **Compile:** in the `wasm-apps` folder.
|
||||
```bash
|
||||
~/wasi-sdk-21.0/bin/clang --sysroot=/home/user/wasi-sdk-21.0/share/wasi-sysroot -nodefaultlibs -lc -o file.wasm file.c -z stack-size=8192 -Wl,--initial-memory=65536 -Wl,--export=__heap_base -Wl,--export=__data_end
|
||||
```
|
||||
2. **generate a C header:** Use `xxd` or other tool, I also put simple python script. At application root `simple-file/`.
|
||||
```bash
|
||||
python3 to_c_header.py
|
||||
```
|
||||
Be free to modify the script to fit your needs.
|
||||
|
||||
## Output
|
||||
The output should be similar to the following:
|
||||
```bash
|
||||
*** Booting Zephyr OS build v3.6.0-4305-g2ec8f442a505 ***
|
||||
Area 3 at 0x1f0000 on flash-controller@40022000 for 65536 bytes
|
||||
[00:00:00.067,000] <inf> littlefs: LittleFS version 2.8, disk version 2.1
|
||||
[00:00:00.074,000] <inf> littlefs: FS at flash-controller@40022000:0x1f0000 is 8 0x2000-byte blocks with 512 cycle
|
||||
[00:00:00.085,000] <inf> littlefs: sizes: rd 16 ; pr 16 ; ca 64 ; la 32
|
||||
[00:00:00.092,000] <err> littlefs: WEST_TOPDIR/modules/fs/littlefs/lfs.c:1351: Corrupted dir pair at {0x0, 0x1}
|
||||
[00:00:00.103,000] <wrn> littlefs: can't mount (LFS -84); formatting
|
||||
[00:00:00.114,000] <inf> littlefs: /lfs mounted
|
||||
/lfs mount: 0
|
||||
[00:00:00.120,000] <inf> main: stdin = 0
|
||||
[00:00:00.124,000] <inf> main: stdout = 1
|
||||
[00:00:00.128,000] <inf> main: stderr = 2
|
||||
[00:00:00.133,000] <inf> main: global heap size: 131072
|
||||
[00:00:00.142,000] <inf> main: Wasm file size: 34682
|
||||
[00:00:00:000 - 2000AFE0]: WASI context initialization: START
|
||||
|
||||
[OS] os_rwlock_init
|
||||
[OS] os_rwlock_init
|
||||
[00:00:00:000 - 2000AFE0]: WASI context initialization: END
|
||||
|
||||
[00:00:00.190,000] <inf> main: main found
|
||||
Hello WebAssembly Module !
|
||||
|
||||
mkdir returned 0
|
||||
fopen Succeed
|
||||
fwrite returned 13
|
||||
fseek returned 0
|
||||
fread returned 13
|
||||
buffer read = Hello, World!
|
||||
|
||||
[00:00:00.225,000] <inf> main: main executed
|
||||
[00:00:00.230,000] <inf> main: wasi exit code: 0
|
||||
[00:00:00.239,000] <inf> main: elapsed: 178ms
|
||||
[00:00:03.158,000] <inf> phy_mii: PHY (0) Link speed 100 Mb, full duplex
|
||||
|
||||
[00:00:00.051,000] <inf> phy_mii: PHY (0) ID 7C131
|
||||
```
|
40
product-mini/platforms/zephyr/simple-file/prj.conf
Normal file
40
product-mini/platforms/zephyr/simple-file/prj.conf
Normal file
|
@ -0,0 +1,40 @@
|
|||
# Copyright (C) 2019 Intel Corporation. All rights reserved.
|
||||
# SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
|
||||
|
||||
# Log config
|
||||
CONFIG_PRINTK=y
|
||||
CONFIG_LOG=y
|
||||
CONFIG_LOG_MODE_IMMEDIATE=y
|
||||
# CONFIG_LOG_MODE_DEFERRED=y
|
||||
|
||||
CONFIG_MAIN_STACK_SIZE=8192
|
||||
# CONFIG_HEAP_MEM_POOL_SIZE=32768
|
||||
CONFIG_REQUIRES_FULL_LIBC=y
|
||||
|
||||
# Config File System
|
||||
CONFIG_POSIX_API=n
|
||||
CONFIG_FILE_SYSTEM=y
|
||||
CONFIG_FILE_SYSTEM_LITTLEFS=y
|
||||
# CONFIG_FS_LITTLEFS_BLK_DEV=y
|
||||
|
||||
# Temp Build Network stack to compile.
|
||||
CONFIG_NETWORKING=y
|
||||
CONFIG_NET_IPV4=y
|
||||
CONFIG_NET_IPV6=y
|
||||
CONFIG_NET_TCP=y
|
||||
CONFIG_NET_SOCKETS=y
|
||||
|
||||
|
||||
# Random generator
|
||||
CONFIG_TEST_RANDOM_GENERATOR=y
|
||||
|
||||
# Stack conf
|
||||
CONFIG_STACK_SENTINEL=y
|
||||
CONFIG_HW_STACK_PROTECTION=y
|
||||
|
||||
# Flash
|
||||
CONFIG_FLASH=y
|
||||
CONFIG_FLASH_MAP=y
|
||||
|
||||
# Debug
|
||||
CONFIG_DEBUG=y
|
2898
product-mini/platforms/zephyr/simple-file/src/file.h
Normal file
2898
product-mini/platforms/zephyr/simple-file/src/file.h
Normal file
File diff suppressed because it is too large
Load Diff
225
product-mini/platforms/zephyr/simple-file/src/main.c
Normal file
225
product-mini/platforms/zephyr/simple-file/src/main.c
Normal file
|
@ -0,0 +1,225 @@
|
|||
/*
|
||||
* Copyright (C) 2019 Intel Corporation. All rights reserved.
|
||||
* SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
|
||||
*/
|
||||
|
||||
// #include <autoconf.h>
|
||||
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
#include "bh_platform.h"
|
||||
#include "bh_assert.h"
|
||||
#include "bh_log.h"
|
||||
#include "wasm_export.h"
|
||||
#include "file.h"
|
||||
|
||||
#include <zephyr/kernel.h>
|
||||
#include <zephyr/device.h>
|
||||
#include <zephyr/devicetree.h>
|
||||
#include <zephyr/fs/fs.h>
|
||||
#include <zephyr/fs/littlefs.h>
|
||||
#include <zephyr/logging/log.h>
|
||||
#include <unistd.h>
|
||||
|
||||
#define CONFIG_HEAP_MEM_POOL_SIZE WASM_GLOBAL_HEAP_SIZE
|
||||
#define CONFIG_APP_STACK_SIZE 16384
|
||||
#define CONFIG_APP_HEAP_SIZE 16384
|
||||
|
||||
LOG_MODULE_REGISTER(main);
|
||||
|
||||
static char global_heap_buf[CONFIG_HEAP_MEM_POOL_SIZE] = { 0 };
|
||||
|
||||
static int app_argc;
|
||||
static char **app_argv;
|
||||
|
||||
//-------------------------------------------------------------------------------------------//
|
||||
static int
|
||||
littlefs_flash_erase(unsigned int id)
|
||||
{
|
||||
const struct flash_area *pfa;
|
||||
int rc;
|
||||
|
||||
rc = flash_area_open(id, &pfa);
|
||||
if (rc < 0) {
|
||||
LOG_ERR("FAIL: unable to find flash area %u: %d\n", id, rc);
|
||||
return rc;
|
||||
}
|
||||
|
||||
LOG_PRINTK("Area %u at 0x%x on %s for %u bytes\n", id,
|
||||
(unsigned int)pfa->fa_off, pfa->fa_dev->name,
|
||||
(unsigned int)pfa->fa_size);
|
||||
|
||||
/* Optional wipe flash contents */
|
||||
if (IS_ENABLED(CONFIG_APP_WIPE_STORAGE)) {
|
||||
rc = flash_area_erase(pfa, 0, pfa->fa_size);
|
||||
LOG_ERR("Erasing flash area ... %d", rc);
|
||||
}
|
||||
|
||||
flash_area_close(pfa);
|
||||
return rc;
|
||||
}
|
||||
#define PARTITION_NODE DT_NODELABEL(lfs1)
|
||||
|
||||
#if DT_NODE_EXISTS(PARTITION_NODE)
|
||||
FS_FSTAB_DECLARE_ENTRY(PARTITION_NODE);
|
||||
#else /* PARTITION_NODE */
|
||||
FS_LITTLEFS_DECLARE_DEFAULT_CONFIG(storage);
|
||||
static struct fs_mount_t lfs_storage_mnt = {
|
||||
.type = FS_LITTLEFS,
|
||||
.fs_data = &storage,
|
||||
.storage_dev = (void *)FIXED_PARTITION_ID(storage_partition),
|
||||
.mnt_point = "/lfs",
|
||||
};
|
||||
#endif /* PARTITION_NODE */
|
||||
|
||||
struct fs_mount_t *mountpoint =
|
||||
#if DT_NODE_EXISTS(PARTITION_NODE)
|
||||
&FS_FSTAB_ENTRY(PARTITION_NODE)
|
||||
#else
|
||||
&lfs_storage_mnt
|
||||
#endif
|
||||
;
|
||||
|
||||
static int
|
||||
littlefs_mount(struct fs_mount_t *mp)
|
||||
{
|
||||
int rc;
|
||||
|
||||
rc = littlefs_flash_erase((uintptr_t)mp->storage_dev);
|
||||
if (rc < 0) {
|
||||
return rc;
|
||||
}
|
||||
|
||||
/* Do not mount if auto-mount has been enabled */
|
||||
#if !DT_NODE_EXISTS(PARTITION_NODE) \
|
||||
|| !(FSTAB_ENTRY_DT_MOUNT_FLAGS(PARTITION_NODE) & FS_MOUNT_FLAG_AUTOMOUNT)
|
||||
rc = fs_mount(mp);
|
||||
if (rc < 0) {
|
||||
LOG_PRINTK("FAIL: mount id %" PRIuPTR " at %s: %d\n",
|
||||
(uintptr_t)mp->storage_dev, mp->mnt_point, rc);
|
||||
return rc;
|
||||
}
|
||||
LOG_PRINTK("%s mount: %d\n", mp->mnt_point, rc);
|
||||
#else
|
||||
LOG_PRINTK("%s automounted\n", mp->mnt_point);
|
||||
#endif
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
//-------------------------------------------------------------------------------------------//
|
||||
int
|
||||
main(void)
|
||||
{
|
||||
int start, end;
|
||||
start = k_uptime_get_32();
|
||||
uint8 *wasm_file_buf = NULL;
|
||||
uint32 wasm_file_size;
|
||||
wasm_module_t wasm_module = NULL;
|
||||
wasm_module_inst_t wasm_module_inst = NULL;
|
||||
RuntimeInitArgs init_args;
|
||||
char error_buf[128];
|
||||
const char *exception;
|
||||
int rc;
|
||||
|
||||
int log_verbose_level = 2;
|
||||
|
||||
memset(&init_args, 0, sizeof(RuntimeInitArgs));
|
||||
|
||||
rc = littlefs_mount(mountpoint);
|
||||
if (rc < 0) {
|
||||
LOG_ERR("FAIL: mounting %s: %d\n", mountpoint->mnt_point, rc);
|
||||
return 0;
|
||||
}
|
||||
|
||||
#if WASM_ENABLE_GLOBAL_HEAP_POOL != 0
|
||||
init_args.mem_alloc_type = Alloc_With_Pool;
|
||||
init_args.mem_alloc_option.pool.heap_buf = global_heap_buf;
|
||||
init_args.mem_alloc_option.pool.heap_size = sizeof(global_heap_buf);
|
||||
LOG_INF("global heap size: %d", sizeof(global_heap_buf));
|
||||
#else
|
||||
#error "memory allocation scheme is not defined."
|
||||
#endif
|
||||
|
||||
/* initialize runtime environment */
|
||||
if (!wasm_runtime_full_init(&init_args)) {
|
||||
LOG_ERR("Init runtime environment failed.");
|
||||
return;
|
||||
}
|
||||
|
||||
/* load WASM byte buffer from byte buffer of include file */
|
||||
wasm_file_buf = (uint8 *)wasm_test_file;
|
||||
wasm_file_size = sizeof(wasm_test_file);
|
||||
LOG_INF("Wasm file size: %d", wasm_file_size);
|
||||
|
||||
/* load WASM module */
|
||||
if (!(wasm_module = wasm_runtime_load(wasm_file_buf, wasm_file_size,
|
||||
error_buf, sizeof(error_buf)))) {
|
||||
LOG_ERR("Failed to load module: %s", error_buf);
|
||||
goto fail1;
|
||||
}
|
||||
|
||||
/* Set the WASI context */
|
||||
#if WASM_ENABLE_LIBC_WASI != 0
|
||||
#define DIR_LIST_SIZE 1
|
||||
const char *dir_list[DIR_LIST_SIZE] = {
|
||||
"/lfs",
|
||||
};
|
||||
/* No dir list => No file system
|
||||
* dir_cont = 0
|
||||
* No mapped dir list => No file system
|
||||
* map_dir_cont = 0
|
||||
* No environment variables
|
||||
* env_count = 0
|
||||
* No command line arguments
|
||||
* argv 0
|
||||
*/
|
||||
wasm_runtime_set_wasi_args(wasm_module, dir_list, DIR_LIST_SIZE, NULL, 0,
|
||||
NULL, 0, NULL, 0);
|
||||
#endif
|
||||
|
||||
/* instantiate the module */
|
||||
if (!(wasm_module_inst = wasm_runtime_instantiate(
|
||||
wasm_module, CONFIG_APP_STACK_SIZE, CONFIG_APP_HEAP_SIZE,
|
||||
error_buf, sizeof(error_buf)))) {
|
||||
LOG_ERR("Failed to instantiate module: %s", error_buf);
|
||||
goto fail2;
|
||||
}
|
||||
|
||||
/* invoke the main function */
|
||||
if (wasm_runtime_lookup_function(wasm_module_inst, "_start")
|
||||
|| wasm_runtime_lookup_function(wasm_module_inst, "__main_argc_argv")
|
||||
|| wasm_runtime_lookup_function(wasm_module_inst, "main")) {
|
||||
|
||||
LOG_INF("main found");
|
||||
wasm_application_execute_main(wasm_module_inst, 0, NULL);
|
||||
LOG_INF("main executed");
|
||||
}
|
||||
else {
|
||||
LOG_ERR("Failed to lookup function main");
|
||||
return -1;
|
||||
}
|
||||
|
||||
if ((exception = wasm_runtime_get_exception(wasm_module_inst)))
|
||||
LOG_ERR("get exception: %s", exception);
|
||||
|
||||
rc = wasm_runtime_get_wasi_exit_code(wasm_module_inst);
|
||||
LOG_INF("wasi exit code: %d", rc);
|
||||
|
||||
/* destroy the module instance */
|
||||
wasm_runtime_deinstantiate(wasm_module_inst);
|
||||
|
||||
fail2:
|
||||
/* unload the module */
|
||||
wasm_runtime_unload(wasm_module);
|
||||
|
||||
fail1:
|
||||
/* destroy runtime environment */
|
||||
wasm_runtime_destroy();
|
||||
|
||||
end = k_uptime_get_32();
|
||||
|
||||
LOG_INF("elapsed: %dms", (end - start));
|
||||
|
||||
return 0;
|
||||
}
|
32
product-mini/platforms/zephyr/simple-file/to_c_header.py
Normal file
32
product-mini/platforms/zephyr/simple-file/to_c_header.py
Normal file
|
@ -0,0 +1,32 @@
|
|||
# Copyright (C) 2024 Grenoble INP - ESISAR. All rights reserved.
|
||||
# SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
|
||||
|
||||
# Python script to convert wasm file to byte array in a .h file
|
||||
import os
|
||||
|
||||
CWD = os.getcwd()
|
||||
CMAKE_CURRENT_BINARY_DIR = os.getenv('CMAKE_CURRENT_BINARY_DIR', CWD)
|
||||
CMAKE_CURRENT_SOURCE_DIR = os.getenv('CMAKE_CURRENT_SOURCE_DIR', f'{CWD}/../src')
|
||||
|
||||
LICENCE_HEADER = """/*
|
||||
* Copyright (C) 2024 Grenoble INP - ESISAR. All rights reserved.
|
||||
* SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
|
||||
*/
|
||||
"""
|
||||
|
||||
print('CMAKE_CURRENT_BINARY_DIR:', CMAKE_CURRENT_BINARY_DIR)
|
||||
print('CMAKE_CURRENT_SOURCE_DIR:', CMAKE_CURRENT_SOURCE_DIR)
|
||||
|
||||
# Open the wasm file in binary mode and read the data
|
||||
with open(f'{CWD}/wasm-apps/file.wasm', 'rb') as f:
|
||||
wasm_bytes = f.read()
|
||||
|
||||
# Convert the bytes to a comma-separated string of hex values
|
||||
byte_array = ', '.join(f'0x{byte:02x}' for byte in wasm_bytes)
|
||||
|
||||
# Create the output string
|
||||
output = f'{LICENCE_HEADER}\nunsigned char __aligned(4) wasm_test_file[] = {{ {byte_array} }};'
|
||||
|
||||
# Write the output string to the .h file
|
||||
with open(f'{CWD}/src/file.h', 'w') as f:
|
||||
f.write(output)
|
55
product-mini/platforms/zephyr/simple-file/wasm-apps/file.c
Normal file
55
product-mini/platforms/zephyr/simple-file/wasm-apps/file.c
Normal file
|
@ -0,0 +1,55 @@
|
|||
/*
|
||||
* Copyright (C) 2024 Grenoble INP - ESISAR. All rights reserved.
|
||||
* SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
|
||||
*/
|
||||
|
||||
#include <stdio.h>
|
||||
#include <string.h>
|
||||
#include <assert.h>
|
||||
#include <sys/stat.h>
|
||||
#include <errno.h>
|
||||
|
||||
// Zephyr
|
||||
#define CWD "/lfs"
|
||||
#define FOLDER_PATH CWD "/folder"
|
||||
#define FILE_PATH CWD "folder/test.txt"
|
||||
|
||||
int
|
||||
main(int argc, char **argv)
|
||||
{
|
||||
int rc;
|
||||
const int zero = 0;
|
||||
printf("Hello WebAssembly Module !\n");
|
||||
|
||||
rc = mkdir(FOLDER_PATH, 0777);
|
||||
if (rc < 0) {
|
||||
rc = errno;
|
||||
printf("mkdir failed with error %d\n", rc);
|
||||
return -1;
|
||||
}
|
||||
printf("mkdir returned %d\n", rc);
|
||||
|
||||
FILE *file = fopen(FILE_PATH, "w+");
|
||||
if (!file) {
|
||||
printf("fopen Failed to open\n");
|
||||
return -1;
|
||||
}
|
||||
printf("fopen Succeed\n");
|
||||
|
||||
const char *data = "Hello, World!";
|
||||
size_t len = 13;
|
||||
size_t nitems = fwrite(data, sizeof(char), 13, file);
|
||||
printf("fwrite returned %d\n", (int)nitems);
|
||||
|
||||
rc = fseek(file, 0, SEEK_SET);
|
||||
printf("fseek returned %d\n", rc);
|
||||
|
||||
char buffer[32];
|
||||
nitems = fread(buffer, sizeof(char), 32, file);
|
||||
printf("fread returned %d\n", (int)nitems);
|
||||
printf("buffer read = %s\n", buffer);
|
||||
|
||||
fclose(file);
|
||||
|
||||
return 0;
|
||||
}
|
89
product-mini/platforms/zephyr/simple-http/CMakeLists.txt
Normal file
89
product-mini/platforms/zephyr/simple-http/CMakeLists.txt
Normal file
|
@ -0,0 +1,89 @@
|
|||
# Copyright (C) 2019 Intel Corporation. All rights reserved.
|
||||
# SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
|
||||
|
||||
cmake_minimum_required(VERSION 3.8.2)
|
||||
|
||||
find_package(Zephyr REQUIRED HINTS $ENV{ZEPHYR_BASE})
|
||||
project(wamr)
|
||||
|
||||
enable_language (ASM)
|
||||
|
||||
set (WAMR_BUILD_PLATFORM "zephyr")
|
||||
|
||||
# WAMR Configuration:
|
||||
set (WAMR_BUILD_TARGET "THUMB")
|
||||
set (WAMR_BUILD_INTERP 1)
|
||||
set (WAMR_BUILD_AOT 0)
|
||||
set (WAMR_BUILD_LIBC_BUILTIN 1) # printf
|
||||
set (WAMR_BUILD_LIBC_WASI 1)
|
||||
set (WAMR_BUILD_LIB_PTHREAD 0)
|
||||
set (WAMR_BUILD_GLOBAL_HEAP_POOL 1)
|
||||
set (WAMR_BUILD_GLOBAL_HEAP_SIZE 98304) # 96 KB
|
||||
|
||||
# Environment variables:
|
||||
|
||||
# Check if WAMR_ROOT_DIR is set
|
||||
if(DEFINED ENV{WAMR_ROOT_DIR})
|
||||
set(WAMR_ROOT_DIR $ENV{WAMR_ROOT_DIR})
|
||||
else()
|
||||
message(FATAL_ERROR "'WAMR_ROOT_DIR' need to be specified")
|
||||
endif()
|
||||
message("wasi-sdk was found at ${WAMR_ROOT_DIR}")
|
||||
|
||||
# Check if WASI_SDK_PATH is set
|
||||
if(NOT $ENV{WASI_SDK_PATH} STREQUAL "")
|
||||
set(WASI_SDK_PATH $ENV{WASI_SDK_PATH})
|
||||
else()
|
||||
find_program(WASM_C_COMPILER clang /opt/wasi-sdk/bin NO_DEFAULT_PATH)
|
||||
if(NOT WASM_C_COMPILER)
|
||||
message(FATAL_ERROR "'wasi-sdk' not found, please ensure wasi-sdk is installed.\
|
||||
You can download and install it from\
|
||||
https://github.com/WebAssembly/wasi-sdk/releases")
|
||||
else()
|
||||
set(WASI_SDK_PATH /opt/wasi-sdk)
|
||||
endif()
|
||||
endif()
|
||||
message("wasi-sdk was found at ${WASI_SDK_PATH}")
|
||||
|
||||
# Check if WAMR_APP_FRAMEWORK_DIR is set
|
||||
if (DEFINED ENV{WAMR_APP_FRAMEWORK_DIR})
|
||||
set(WAMR_APP_FRAMEWORK_DIR $ENV{WAMR_APP_FRAMEWORK_DIR})
|
||||
else()
|
||||
message(FATAL_ERROR "'wamr-app-framework' not found, please ensure they are installed.\
|
||||
You can download and install them from\
|
||||
https://github.com/bytecodealliance/wamr-app-framework")
|
||||
endif()
|
||||
message("wamr-app-framework was found at ${WAMR_APP_FRAMEWORK_DIR}")
|
||||
|
||||
# set the WAMR_SDK_DIR with the path specified in the environment variable
|
||||
set(WAMR_SDK_DIR
|
||||
${WAMR_APP_FRAMEWORK_DIR}/wamr-sdk
|
||||
)
|
||||
|
||||
# set the WAMR_LIBC_BUILTIN_DIR
|
||||
set(WAMR_LIBC_BUILTIN_DIR
|
||||
${WAMR_SDK_DIR}/wamr-sdk/app/libc-builtin-sysroot
|
||||
)
|
||||
|
||||
# set the WAMR_SDK_PACKAGE_OUT_DIR
|
||||
set(WAMR_SDK_PACKAGE_OUT_DIR
|
||||
${CMAKE_CURRENT_BINARY_DIR}/wamr-sdk/app-sdk/wamr-app-framework
|
||||
)
|
||||
|
||||
# # Reset linker flags
|
||||
# set(CMAKE_SHARED_LIBRARY_LINK_C_FLAGS "")
|
||||
# set(CMAKE_SHARED_LIBRARY_LINK_CXX_FLAGS "")
|
||||
|
||||
include (${WAMR_ROOT_DIR}/build-scripts/runtime_lib.cmake)
|
||||
# include (${SHARED_DIR}/utils/uncommon/shared_uncommon.cmake) # in socket-api sample
|
||||
|
||||
# Build the WAMR runtime
|
||||
target_sources(app PRIVATE
|
||||
${WAMR_RUNTIME_LIB_SOURCE}
|
||||
src/main.c)
|
||||
|
||||
# Link libraries like in samples.
|
||||
set(WASI_LIBM "${WASI_SDK_PATH}/share/wasi-sysroot/lib/wasm32-wasi/libm.a")
|
||||
set(WASI_LIBDL "${WASI_SDK_PATH}/share/wasi-sysroot/lib/wasm32-wasi/libdl.a")
|
||||
|
||||
target_link_libraries(app PUBLIC ${WASI_LIBM} ${WASI_LIBDL})
|
143
product-mini/platforms/zephyr/simple-http/README.md
Normal file
143
product-mini/platforms/zephyr/simple-http/README.md
Normal file
|
@ -0,0 +1,143 @@
|
|||
# Socket sample
|
||||
this sample demonstrates the use of WASI API to interact with sockets.
|
||||
|
||||
> ❗ **Important:** This sample was ported/adapted from the http_get zephyr sample. The original sample can be found [here]( https://github.com/zephyrproject-rtos/zephyr/blob/main/samples/net/sockets/http_get/src/http_get.c).
|
||||
|
||||
> 🛠️ **Work in progress:** The sample is functional but be aware that just a small part of WASI socket API was tested.
|
||||
> Actual Zephyr APIs:
|
||||
> * socket creation = `zsock_socket`
|
||||
> * socket connection = `zsock_connect`
|
||||
> * socket emission = `zsock_sendto`
|
||||
> * socket reception = `zsock_recvfrom`
|
||||
> * socket destruction = `zsock_close`
|
||||
>
|
||||
> With the sockets most API are in fact provided by the runtime instead of WASI because of the lack of socket support in WASI preview1.
|
||||
|
||||
## Setup
|
||||
1. Connect a network cable to the board ethernet port.
|
||||
2. Configure the network interface on the host machine
|
||||
```
|
||||
Internet Protocol Version 4 (TCP/IPv4) Properties:
|
||||
IP Address: 192.0.2.10
|
||||
Subnet Mask: 255.255.255.0
|
||||
Default Gateway: 192.0.2.2
|
||||
```
|
||||
3. Start a simple HTTP server on the host machine.
|
||||
```bash
|
||||
python3 -m http.server --bind 0.0.0.0
|
||||
```
|
||||
4. Disable any firewall that may block the connection.
|
||||
|
||||
## Configuration
|
||||
To configure the server side IP address and port modify the following lines in the `http_get.c` file.
|
||||
|
||||
1. The `HTTP_HOST` and `HTTP_PORT` macros define the server IP address and port.
|
||||
```c
|
||||
/* HTTP server to connect to */
|
||||
#define HTTP_HOST "192.0.2.10"
|
||||
/* Port to connect to, as string */
|
||||
#define HTTP_PORT "8000"
|
||||
/* HTTP path to request */
|
||||
#define HTTP_PATH "/"
|
||||
|
||||
// ...
|
||||
|
||||
#define REQUEST "GET " HTTP_PATH " HTTP/1.0\r\nHost: " HTTP_HOST "\r\n\r\n"
|
||||
```
|
||||
> 📄 **Notes:** These macros are used to build the request string, but they are not used to instantiate the address structure. Because at one point we didn't want to use `inet_pton` to convert the string to an address and it remained like this.
|
||||
|
||||
2. The `addr` structure is used to store the server address.
|
||||
```c
|
||||
addr.sin_port = htons(8000);
|
||||
addr.sin_addr.s_addr =
|
||||
htonl(0xC000020A); // hard coded IP address for 192.0.2.10
|
||||
```
|
||||
|
||||
To configure the authorized IP address(es) modify the following lines in the `main.c` file. WAMR will only allow the IP addresses in the pool to connect to the server.
|
||||
```c
|
||||
#define ADDRESS_POOL_SIZE 1
|
||||
const char *addr_pool[ADDRESS_POOL_SIZE] = {
|
||||
"192.0.2.10/24",
|
||||
};
|
||||
```
|
||||
## Run Command
|
||||
* **Zephyr Build**
|
||||
1. **Build:** Replace `nucleo_h743zi` with your board name and the `WAMR_BUILD_TARGET` in `CMakeList.txt` with your target architecture.
|
||||
```bash
|
||||
ZEPHYR_BASE=~/zephyrproject/zephyr \
|
||||
WAMR_ROOT_DIR=~/wasm-micro-runtime \
|
||||
WASI_SDK_PATH=~/wasi-sdk-21.0 \
|
||||
WAMR_APP_FRAMEWORK_DIR=~/wamr-app-framework \
|
||||
west build . -b nucleo_h563zi -p always
|
||||
```
|
||||
⚠️ **Warning:** The flags `ZEPHYR_BASE`, `WAMR_ROOT_DIR`, `WASI_SDK_PATH`, and `WAMR_APP_FRAMEWORK_DIR` need to be set otherwise the build will fail.
|
||||
|
||||
2. **Flash:**
|
||||
```bash
|
||||
ZEPHYR_BASE=~/zephyrproject/zephyr west flash
|
||||
```
|
||||
|
||||
3. **Monitor:** Use a serial link to monitor the output. Personally, I use minicom.
|
||||
```bash
|
||||
minicom -D /dev/ttyACM0
|
||||
```
|
||||
|
||||
4. **Debug:** Curently investigating.
|
||||
|
||||
* **WebAssembly Module**
|
||||
|
||||
❗ **Important:** I used wasi-sdk 21 to compile the module. I still haven't tried the module with the new wasi-sdk 22.
|
||||
|
||||
0. **Compile a static lib:** in the `wasm-apps` folder.
|
||||
* **Compile the an object:**
|
||||
```bash
|
||||
~/wasi-sdk-21.0/bin/clang --sysroot=/home/user/wasi-sdk-21.0/share/wasi-sysroot -Iinc/ -c inc/wasi_socket_ext.c -o inc/wasi_socket_ext.o
|
||||
```
|
||||
* **Create a static lib:**
|
||||
```bash
|
||||
~/wasi-sdk-21.0/bin/llvm-ar rcs inc/libwasi_socket_ext.a inc/wasi_socket_ext.o
|
||||
```
|
||||
1. **Compile:** in the `wasm-apps` folder.
|
||||
```bash
|
||||
~/wasi-sdk-21.0/bin/clang --sysroot=/home/user/wasi-sdk-21.0/share/wasi-sysroot -Iinc/ -nodefaultlibs -o http_get.wasm http_get.c -lc -Linc/ -lwasi_socket_ext -z stack-size=8192 -Wl,--initial-memory=65536 -Wl,--export=__heap_base -Wl,--export=__data_end -Wl,--allow-undefined
|
||||
```
|
||||
2. **generate a C header:** Use `xxd` or other tool, I also put simple python script. At application root `simple-http/`.
|
||||
```bash
|
||||
python3 to_c_header.py
|
||||
```
|
||||
Be free to modify the script to fit your needs.
|
||||
|
||||
## Output
|
||||
The output should be similar to the following:
|
||||
```bash
|
||||
*** Booting Zephyr OS build v3.6.0-4305-g2ec8f442a505 ***
|
||||
[00:00:00.061,000] <inf> net_config: Initializing network
|
||||
[00:00:00.067,000] <inf> net_config: Waiting interface 1 (0x2000a910) to be up...
|
||||
[00:00:03.158,000] <inf> phy_mii: PHY (0) Link speed 100 Mb, full duplex
|
||||
|
||||
[00:00:03.288,000] <inf> net_config: Interface 1 (0x2000a910) coming up
|
||||
[00:00:03.295,000] <inf> net_config: IPv4 address: 192.0.2.1
|
||||
global heap size: 131072
|
||||
Wasm file size: 36351
|
||||
main found
|
||||
[wasm-mod] Preparing HTTP GET request for http://192.0.2.10:8000/
|
||||
[wasm-mod] sock = 3
|
||||
[wasm-mod] connect rc = 0
|
||||
[wasm-mod] send rc = 36
|
||||
[wasm-mod] Response:
|
||||
|
||||
HTTP/1.0 200 OK
|
||||
Server: SimpleHTTP/0.6 Python/3.10.10
|
||||
Date: Fri, 14 Jun 2024 07:26:56 GMT
|
||||
Content-type: text/html; charset=utf-8
|
||||
Content-Length: 2821
|
||||
|
||||
# Skip the HTML content
|
||||
|
||||
[wasm-mod] len = 0 break
|
||||
|
||||
[wasm-mod] Connection closed
|
||||
main executed
|
||||
wasi exit code: 0
|
||||
elapsed: 405ms
|
||||
```
|
61
product-mini/platforms/zephyr/simple-http/prj.conf
Normal file
61
product-mini/platforms/zephyr/simple-http/prj.conf
Normal file
|
@ -0,0 +1,61 @@
|
|||
# Copyright (C) 2019 Intel Corporation. All rights reserved.
|
||||
# SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
|
||||
|
||||
# Log config
|
||||
CONFIG_PRINTK=y
|
||||
CONFIG_LOG=y
|
||||
CONFIG_LOG_MODE_IMMEDIATE=y
|
||||
CONFIG_NET_LOG=y
|
||||
|
||||
CONFIG_MAIN_STACK_SIZE=8192
|
||||
# CONFIG_HEAP_MEM_POOL_SIZE=32768
|
||||
CONFIG_REQUIRES_FULL_LIBC=y
|
||||
|
||||
# Networking config
|
||||
CONFIG_NETWORKING=y
|
||||
CONFIG_NET_IPV4=y
|
||||
CONFIG_NET_IPV6=y
|
||||
CONFIG_NET_TCP=y
|
||||
CONFIG_NET_SOCKETS=y
|
||||
CONFIG_POSIX_API=n
|
||||
|
||||
# Stack conf
|
||||
# CONFIG_NO_OPTIMIZATIONS=y
|
||||
CONFIG_STACK_SENTINEL=y
|
||||
CONFIG_HW_STACK_PROTECTION=y
|
||||
# CONFIG_STACK_CANARIES=y
|
||||
# CONFIG_ISR_STACK_SIZE=4096
|
||||
|
||||
# Network driver config
|
||||
CONFIG_TEST_RANDOM_GENERATOR=y
|
||||
|
||||
# Network address config
|
||||
CONFIG_NET_CONFIG_SETTINGS=y
|
||||
CONFIG_NET_CONFIG_NEED_IPV4=y
|
||||
CONFIG_NET_CONFIG_MY_IPV4_ADDR="192.0.2.1"
|
||||
CONFIG_NET_CONFIG_PEER_IPV4_ADDR="192.0.2.2"
|
||||
CONFIG_NET_CONFIG_MY_IPV4_GW="192.0.2.2"
|
||||
|
||||
# Config File System
|
||||
CONFIG_FILE_SYSTEM=y
|
||||
CONFIG_FILE_SYSTEM_LITTLEFS=y
|
||||
# Flash
|
||||
CONFIG_FLASH=y
|
||||
CONFIG_FLASH_MAP=y
|
||||
|
||||
# CONFIG_DNS_RESOLVER=y
|
||||
# CONFIG_DNS_SERVER_IP_ADDRESSES=y
|
||||
# CONFIG_DNS_SERVER1="192.0.2.2"
|
||||
|
||||
# Config init stack
|
||||
# CONFIG_INIT_STACKS=y
|
||||
# CONFIG_NET_PKT_RX_COUNT=100
|
||||
# CONFIG_NET_PKT_TX_COUNT=100
|
||||
# CONFIG_NET_BUF_RX_COUNT=100
|
||||
# CONFIG_NET_BUF_TX_COUNT=100
|
||||
|
||||
# Flash
|
||||
CONFIG_FLASH=y
|
||||
|
||||
# Debug
|
||||
CONFIG_DEBUG=y
|
3039
product-mini/platforms/zephyr/simple-http/src/http_get.h
Normal file
3039
product-mini/platforms/zephyr/simple-http/src/http_get.h
Normal file
File diff suppressed because it is too large
Load Diff
141
product-mini/platforms/zephyr/simple-http/src/main.c
Normal file
141
product-mini/platforms/zephyr/simple-http/src/main.c
Normal file
|
@ -0,0 +1,141 @@
|
|||
/*
|
||||
* Copyright (C) 2019 Intel Corporation. All rights reserved.
|
||||
* SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
|
||||
*/
|
||||
|
||||
// #include <autoconf.h>
|
||||
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
#include "bh_platform.h"
|
||||
#include "bh_assert.h"
|
||||
#include "bh_log.h"
|
||||
#include "wasm_export.h"
|
||||
#include "http_get.h"
|
||||
|
||||
#include <zephyr/kernel.h>
|
||||
#include <zephyr/device.h>
|
||||
#include <zephyr/devicetree.h>
|
||||
#include <zephyr/net/net_ip.h>
|
||||
#include <zephyr/net/socket.h>
|
||||
#include <zephyr/net/http/client.h>
|
||||
|
||||
#define CONFIG_HEAP_MEM_POOL_SIZE WASM_GLOBAL_HEAP_SIZE
|
||||
#define CONFIG_APP_STACK_SIZE 8192
|
||||
#define CONFIG_APP_HEAP_SIZE 8192
|
||||
|
||||
static char global_heap_buf[CONFIG_HEAP_MEM_POOL_SIZE] = { 0 };
|
||||
|
||||
static int app_argc;
|
||||
static char **app_argv;
|
||||
|
||||
int
|
||||
main(void)
|
||||
{
|
||||
int start, end;
|
||||
start = k_uptime_get_32();
|
||||
uint8 *wasm_file_buf = NULL;
|
||||
uint32 wasm_file_size;
|
||||
wasm_module_t wasm_module = NULL;
|
||||
wasm_module_inst_t wasm_module_inst = NULL;
|
||||
RuntimeInitArgs init_args;
|
||||
char error_buf[128];
|
||||
const char *exception;
|
||||
|
||||
int log_verbose_level = 2;
|
||||
|
||||
memset(&init_args, 0, sizeof(RuntimeInitArgs));
|
||||
|
||||
#if WASM_ENABLE_GLOBAL_HEAP_POOL != 0
|
||||
init_args.mem_alloc_type = Alloc_With_Pool;
|
||||
init_args.mem_alloc_option.pool.heap_buf = global_heap_buf;
|
||||
init_args.mem_alloc_option.pool.heap_size = sizeof(global_heap_buf);
|
||||
printf("global heap size: %d\n", sizeof(global_heap_buf));
|
||||
#else
|
||||
#error "memory allocation scheme is not defined."
|
||||
#endif
|
||||
|
||||
/* initialize runtime environment */
|
||||
if (!wasm_runtime_full_init(&init_args)) {
|
||||
printf("Init runtime environment failed.\n");
|
||||
return;
|
||||
}
|
||||
|
||||
bh_log_set_verbose_level(log_verbose_level);
|
||||
|
||||
/* load WASM byte buffer from byte buffer of include file */
|
||||
wasm_file_buf = (uint8 *)wasm_test_file;
|
||||
wasm_file_size = sizeof(wasm_test_file);
|
||||
printf("Wasm file size: %d\n", wasm_file_size);
|
||||
|
||||
/* load WASM module */
|
||||
if (!(wasm_module = wasm_runtime_load(wasm_file_buf, wasm_file_size,
|
||||
error_buf, sizeof(error_buf)))) {
|
||||
printf("Failed to load module: %s\n", error_buf);
|
||||
goto fail1;
|
||||
}
|
||||
|
||||
/* Set the WASI context */
|
||||
#if WASM_ENABLE_LIBC_WASI != 0
|
||||
#define ADDRESS_POOL_SIZE 1
|
||||
const char *addr_pool[ADDRESS_POOL_SIZE] = {
|
||||
"192.0.2.10/24",
|
||||
};
|
||||
/* No dir list => No file system
|
||||
* dir_cont = 0
|
||||
* No mapped dir list => No file system
|
||||
* map_dir_cont = 0
|
||||
* No environment variables
|
||||
* env_count = 0
|
||||
* No command line arguments
|
||||
* argv 0
|
||||
*/
|
||||
wasm_runtime_set_wasi_args(wasm_module, NULL, 0, NULL, 0, NULL, 0, NULL, 0);
|
||||
wasm_runtime_set_wasi_addr_pool(wasm_module, addr_pool, ADDRESS_POOL_SIZE);
|
||||
wasm_runtime_set_wasi_ns_lookup_pool(wasm_module, NULL, 0);
|
||||
#endif
|
||||
|
||||
/* instantiate the module */
|
||||
if (!(wasm_module_inst = wasm_runtime_instantiate(
|
||||
wasm_module, CONFIG_APP_STACK_SIZE, CONFIG_APP_HEAP_SIZE,
|
||||
error_buf, sizeof(error_buf)))) {
|
||||
printf("Failed to instantiate module: %s\n", error_buf);
|
||||
goto fail2;
|
||||
}
|
||||
|
||||
/* invoke the main function */
|
||||
if (wasm_runtime_lookup_function(wasm_module_inst, "_start")
|
||||
|| wasm_runtime_lookup_function(wasm_module_inst, "__main_argc_argv")) {
|
||||
|
||||
printf("main found\n");
|
||||
wasm_application_execute_main(wasm_module_inst, 0, NULL);
|
||||
printf("main executed\n");
|
||||
}
|
||||
else {
|
||||
printf("Failed to lookup function main\n");
|
||||
return -1;
|
||||
}
|
||||
|
||||
if ((exception = wasm_runtime_get_exception(wasm_module_inst)))
|
||||
printf("%s\n", exception);
|
||||
|
||||
int rc = wasm_runtime_get_wasi_exit_code(wasm_module_inst);
|
||||
printf("wasi exit code: %d\n", rc); // 1 = _WASI_E2BIG
|
||||
|
||||
/* destroy the module instance */
|
||||
wasm_runtime_deinstantiate(wasm_module_inst);
|
||||
|
||||
fail2:
|
||||
/* unload the module */
|
||||
wasm_runtime_unload(wasm_module);
|
||||
|
||||
fail1:
|
||||
/* destroy runtime environment */
|
||||
wasm_runtime_destroy();
|
||||
|
||||
end = k_uptime_get_32();
|
||||
|
||||
printf("elapsed: %dms\n", (end - start));
|
||||
|
||||
return 0;
|
||||
}
|
34
product-mini/platforms/zephyr/simple-http/to_c_header.py
Normal file
34
product-mini/platforms/zephyr/simple-http/to_c_header.py
Normal file
|
@ -0,0 +1,34 @@
|
|||
# Copyright (C) 2024 Grenoble INP - ESISAR. All rights reserved.
|
||||
# SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
|
||||
|
||||
# Python script to convert wasm file to byte array in a .h file
|
||||
import os
|
||||
|
||||
CWD = os.getcwd()
|
||||
CMAKE_CURRENT_BINARY_DIR = os.getenv('CMAKE_CURRENT_BINARY_DIR', CWD)
|
||||
CMAKE_CURRENT_SOURCE_DIR = os.getenv('CMAKE_CURRENT_SOURCE_DIR', f'{CWD}/../src')
|
||||
|
||||
LICENCE_HEADER = """/*
|
||||
* Copyright (c) 2017 Linaro Limited
|
||||
* Copyright (C) 2024 Grenoble INP - ESISAR Limited
|
||||
*
|
||||
* SPDX-License-Identifier: Apache-2.0
|
||||
*/
|
||||
"""
|
||||
|
||||
print('CMAKE_CURRENT_BINARY_DIR:', CMAKE_CURRENT_BINARY_DIR)
|
||||
print('CMAKE_CURRENT_SOURCE_DIR:', CMAKE_CURRENT_SOURCE_DIR)
|
||||
|
||||
# Open the wasm file in binary mode and read the data
|
||||
with open(f'{CWD}/wasm-apps/http_get.wasm', 'rb') as f:
|
||||
wasm_bytes = f.read()
|
||||
|
||||
# Convert the bytes to a comma-separated string of hex values
|
||||
byte_array = ', '.join(f'0x{byte:02x}' for byte in wasm_bytes)
|
||||
|
||||
# Create the output string
|
||||
output = f'unsigned char __aligned(4) wasm_test_file[] = {{ {byte_array} }};'
|
||||
|
||||
# Write the output string to the .h file
|
||||
with open(f'{CWD}/src/http_get.h', 'w') as f:
|
||||
f.write(output)
|
|
@ -0,0 +1,91 @@
|
|||
/*
|
||||
* Copyright (c) 2017 Linaro Limited
|
||||
*
|
||||
* SPDX-License-Identifier: Apache-2.0
|
||||
*/
|
||||
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
|
||||
#include <sys/socket.h>
|
||||
#include <arpa/inet.h>
|
||||
#include <unistd.h>
|
||||
#include <errno.h>
|
||||
#include <string.h>
|
||||
|
||||
#ifdef __wasi__
|
||||
#include <wasi_socket_ext.h>
|
||||
#endif
|
||||
|
||||
/* HTTP server to connect to */
|
||||
#define HTTP_HOST "192.0.2.10"
|
||||
/* Port to connect to, as string */
|
||||
#define HTTP_PORT "8000"
|
||||
/* HTTP path to request */
|
||||
#define HTTP_PATH "/"
|
||||
|
||||
#define SSTRLEN(s) (sizeof(s) - 1)
|
||||
// #define CHECK(r) { if (r == -1) { printf("Error %d: " #r "\n", errno);
|
||||
// exit(1); } }
|
||||
|
||||
#define REQUEST "GET " HTTP_PATH " HTTP/1.0\r\nHost: " HTTP_HOST "\r\n\r\n"
|
||||
|
||||
static char response[1024];
|
||||
|
||||
int
|
||||
main(int argc, char **argv)
|
||||
{
|
||||
int st, sock;
|
||||
struct sockaddr_in addr;
|
||||
int rc = 0;
|
||||
|
||||
printf("[wasm-mod] Preparing HTTP GET request for http://" HTTP_HOST
|
||||
":" HTTP_PORT HTTP_PATH "\n");
|
||||
|
||||
memset(&addr, 0, sizeof(addr));
|
||||
addr.sin_family = AF_INET;
|
||||
addr.sin_port = htons(8000);
|
||||
addr.sin_addr.s_addr =
|
||||
htonl(0xC000020A); // hard coded IP address for 192.0.2.10
|
||||
|
||||
sock = socket(AF_INET, SOCK_STREAM, IPPROTO_TCP);
|
||||
printf("[wasm-mod] sock = %d\n", sock);
|
||||
|
||||
rc = connect(sock, (struct sockaddr *)&addr, sizeof(addr));
|
||||
printf("[wasm-mod] connect rc = %d\n", rc);
|
||||
|
||||
rc = sendto(sock, (const void *)REQUEST, SSTRLEN(REQUEST), 0,
|
||||
(struct sockaddr *)&addr, sizeof(addr));
|
||||
printf("[wasm-mod] send rc = %d\n", rc);
|
||||
if (rc < 0) {
|
||||
printf("[wasm-mod] Error %d\n", errno);
|
||||
return 0;
|
||||
}
|
||||
|
||||
printf("[wasm-mod] Response:\n\n");
|
||||
|
||||
while (1) {
|
||||
socklen_t socklen = sizeof(struct sockaddr_in);
|
||||
int len = recvfrom(sock, response, sizeof(response) - 1, 0,
|
||||
(struct sockaddr *)&addr, &socklen);
|
||||
|
||||
if (len < 0) {
|
||||
printf("[wasm-mod] Error %d\n", errno);
|
||||
return 0;
|
||||
}
|
||||
|
||||
response[len] = 0;
|
||||
printf("%s", response);
|
||||
|
||||
if (len == 0) {
|
||||
printf("[wasm-mod] len = 0 break\n");
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
printf("\n");
|
||||
|
||||
(void)close(sock);
|
||||
printf("[wasm-mod] Connection closed\n");
|
||||
return 0;
|
||||
}
|
|
@ -0,0 +1,5 @@
|
|||
The lib source code are located there:
|
||||
* [wasi_socket_ext.h](../../../../../../core/iwasm/libraries/lib-socket/inc/wasi_socket_ext.h)
|
||||
* [wasi_socket_ext.c](../../../../../../core/iwasm/libraries/lib-socket/src/wasi/wasi_socket_ext.c)
|
||||
|
||||
|
BIN
samples/socket-api/file.wasm
Executable file
BIN
samples/socket-api/file.wasm
Executable file
Binary file not shown.
|
@ -88,4 +88,4 @@ compile_with_clang(udp_server.c)
|
|||
compile_with_clang(multicast_client.c)
|
||||
compile_with_clang(multicast_server.c)
|
||||
compile_with_clang(timeout_client.c)
|
||||
compile_with_clang(timeout_server.c)
|
||||
compile_with_clang(timeout_server.c)
|
Loading…
Reference in New Issue
Block a user