diff --git a/lib/runtime-core/src/types.rs b/lib/runtime-core/src/types.rs index 9ee5270dd73..d9e983f34dc 100644 --- a/lib/runtime-core/src/types.rs +++ b/lib/runtime-core/src/types.rs @@ -77,6 +77,19 @@ where { const TYPE: Type; } + +unsafe impl WasmExternType for i8 { + const TYPE: Type = Type::I32; +} +unsafe impl WasmExternType for u8 { + const TYPE: Type = Type::I32; +} +unsafe impl WasmExternType for i16 { + const TYPE: Type = Type::I32; +} +unsafe impl WasmExternType for u16 { + const TYPE: Type = Type::I32; +} unsafe impl WasmExternType for i32 { const TYPE: Type = Type::I32; } diff --git a/lib/wasi/src/lib.rs b/lib/wasi/src/lib.rs index b62f84dfb98..3dcb2f7cb7e 100644 --- a/lib/wasi/src/lib.rs +++ b/lib/wasi/src/lib.rs @@ -1,3 +1,4 @@ +mod ptr; mod state; mod syscalls; mod utils; diff --git a/lib/wasi/src/ptr.rs b/lib/wasi/src/ptr.rs new file mode 100644 index 00000000000..f6d1c4ce4f8 --- /dev/null +++ b/lib/wasi/src/ptr.rs @@ -0,0 +1,112 @@ +use std::{cell::Cell, fmt, marker::PhantomData, mem}; +use wasmer_runtime_core::{ + memory::Memory, + types::{Type, ValueError, ValueType, WasmExternType}, +}; + +pub struct Array; +pub struct Item; + +#[repr(transparent)] +pub struct WasmPtr { + offset: u32, + _phantom: PhantomData<(T, Ty)>, +} + +impl WasmPtr { + #[inline] + pub fn new(offset: u32) -> Self { + Self { + offset, + _phantom: PhantomData, + } + } + + #[inline] + pub fn offset(self) -> u32 { + self.offset + } +} + +impl WasmPtr { + #[inline] + pub fn deref<'a>(self, memory: &'a Memory) -> Option<&'a Cell> { + if (self.offset as usize) + mem::size_of::() >= memory.size().bytes().0 { + return None; + } + unsafe { + let cell_ptr = memory + .view::() + .get_unchecked((self.offset() as usize) / mem::size_of::()) + as *const _; + Some(&*cell_ptr) + } + } +} + +impl WasmPtr { + #[inline] + pub fn deref<'a>(self, memory: &'a Memory, index: u32, length: u32) -> Option<&'a [Cell]> { + if (self.offset as usize) + (mem::size_of::() * ((index + length) as usize)) + >= memory.size().bytes().0 + { + return None; + } + + unsafe { + let cell_ptrs = memory.view::().get_unchecked( + ((self.offset as usize) / mem::size_of::()) + (index as usize) + ..((self.offset() as usize) / mem::size_of::()) + + ((index + length) as usize), + ) as *const _; + Some(&*cell_ptrs) + } + } +} + +unsafe impl WasmExternType for WasmPtr { + const TYPE: Type = Type::I32; +} + +impl ValueType for WasmPtr { + fn into_le(self, buffer: &mut [u8]) { + buffer[..mem::size_of::()].copy_from_slice(&self.offset.to_le_bytes()); + } + fn from_le(buffer: &[u8]) -> Result { + if buffer.len() >= mem::size_of::() { + let mut array = [0u8; mem::size_of::()]; + array.copy_from_slice(&buffer[..mem::size_of::()]); + Ok(Self { + offset: u32::from_le_bytes(array), + _phantom: PhantomData, + }) + } else { + Err(ValueError::BufferTooSmall) + } + } +} + +impl Clone for WasmPtr { + fn clone(&self) -> Self { + Self { + offset: self.offset, + _phantom: PhantomData, + } + } +} + +impl Copy for WasmPtr {} + +impl PartialEq for WasmPtr { + fn eq(&self, other: &Self) -> bool { + self.offset == other.offset + } +} + +impl Eq for WasmPtr {} + +impl fmt::Debug for WasmPtr { + fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { + write!(f, "WasmPtr({:#x})", self.offset) + } +} diff --git a/lib/wasi/src/syscalls/mod.rs b/lib/wasi/src/syscalls/mod.rs index 0c5f2f9b018..0c0298383e8 100644 --- a/lib/wasi/src/syscalls/mod.rs +++ b/lib/wasi/src/syscalls/mod.rs @@ -1,4 +1,12 @@ -use crate::state::WasiState; +#![allow(unused)] + +mod types; + +use self::types::*; +use crate::{ + ptr::{Array, WasmPtr}, + state::WasiState, +}; use wasmer_runtime_core::{memory::Memory, vm::Ctx}; #[allow(clippy::mut_from_ref)] @@ -6,23 +14,38 @@ fn get_wasi_state(ctx: &Ctx) -> &mut WasiState { unsafe { &mut *(ctx.data as *mut WasiState) } } +#[must_use] fn write_buffer_array( memory: &Memory, from: &[Vec], - ptr_buffer_offset: u32, - buffer_offset: u32, -) { - let mut current_buffer_offset = buffer_offset; - for (i, sub_buffer) in from.iter().enumerate() { - memory.view::()[(ptr_buffer_offset as usize)..][i].set(current_buffer_offset); - for (cell, &byte) in memory.view()[(current_buffer_offset as usize)..] - .iter() - .zip(sub_buffer.iter()) + ptr_buffer: WasmPtr, Array>, + buffer: WasmPtr, +) -> __wasi_errno_t { + let ptrs = if let Some(cells) = ptr_buffer.deref(memory, 0, from.len() as u32) { + cells + } else { + return __WASI_EOVERFLOW; + }; + + let mut current_buffer_offset = 0; + for ((i, sub_buffer), ptr) in from.iter().enumerate().zip(ptrs.iter()) { + ptr.set(WasmPtr::new(buffer.offset() + current_buffer_offset)); + + let cells = if let Some(cells) = + buffer.deref(memory, current_buffer_offset, sub_buffer.len() as u32) { + cells + } else { + return __WASI_EOVERFLOW; + }; + + for (cell, &byte) in cells.iter().zip(sub_buffer.iter()) { cell.set(byte); } current_buffer_offset += sub_buffer.len() as u32; } + + __WASI_ESUCCESS } /// ### `args_get()` @@ -34,11 +57,15 @@ fn write_buffer_array( /// - `char *argv_buf` /// A pointer to a buffer to write the argument string data. /// -pub fn args_get(ctx: &mut Ctx, ptr_buffer_offset: u32, buffer_offset: u32) { +pub fn args_get( + ctx: &mut Ctx, + argv: WasmPtr, Array>, + argv_buf: WasmPtr, +) -> __wasi_errno_t { let state = get_wasi_state(ctx); let memory = ctx.memory(0); - write_buffer_array(memory, &*state.args, ptr_buffer_offset, buffer_offset); + write_buffer_array(memory, &*state.args, argv, argv_buf) } /// ### `args_sizes_get()` @@ -48,21 +75,38 @@ pub fn args_get(ctx: &mut Ctx, ptr_buffer_offset: u32, buffer_offset: u32) { /// The number of arguments. /// - `size_t *argv_buf_size` /// The size of the argument string data. -pub fn args_sizes_get(ctx: &mut Ctx, argc_out: u32, argv_buf_size_out: u32) { - let state = get_wasi_state(ctx); +pub fn args_sizes_get( + ctx: &mut Ctx, + argc: WasmPtr, + argv_buf_size: WasmPtr, +) -> __wasi_errno_t { let memory = ctx.memory(0); - let arg_count = state.args.len(); - let total_arg_size: usize = state.args.iter().map(|v| v.len()).sum(); + if let (Some(argc), Some(argv_buf_size)) = (argc.deref(memory), argv_buf_size.deref(memory)) { + let state = get_wasi_state(ctx); + + argc.set(state.args.len() as u32); + argv_buf_size.set(state.args.iter().map(|v| v.len() as u32).sum()); - memory.view::()[(argc_out / 4) as usize].set(arg_count as u32); - memory.view::()[(argv_buf_size_out / 4) as usize].set(total_arg_size as u32); + __WASI_ESUCCESS + } else { + __WASI_EOVERFLOW + } } -pub fn clock_res_get(ctx: &mut Ctx) { +pub fn clock_res_get( + ctx: &mut Ctx, + clock_id: __wasi_clockid_t, + resolution: WasmPtr<__wasi_timestamp_t>, +) -> __wasi_errno_t { unimplemented!() } -pub fn clock_time_get(ctx: &mut Ctx) { +pub fn clock_time_get( + ctx: &mut Ctx, + clock_id: __wasi_clockid_t, + precision: __wasi_timestamp_t, + time: WasmPtr<__wasi_timestamp_t>, +) -> __wasi_errno_t { unimplemented!() } @@ -74,11 +118,15 @@ pub fn clock_time_get(ctx: &mut Ctx) { /// A pointer to a buffer to write the environment variable pointers. /// - `char *environ_buf` /// A pointer to a buffer to write the environment variable string data. -pub fn environ_get(ctx: &mut Ctx, environ: u32, environ_buf: u32) { +pub fn environ_get( + ctx: &mut Ctx, + environ: WasmPtr, Array>, + environ_buf: WasmPtr, +) -> __wasi_errno_t { let state = get_wasi_state(ctx); let memory = ctx.memory(0); - write_buffer_array(memory, &*state.args, environ, environ_buf); + write_buffer_array(memory, &*state.args, environ, environ_buf) } /// ### `environ_sizes_get()` @@ -88,131 +136,326 @@ pub fn environ_get(ctx: &mut Ctx, environ: u32, environ_buf: u32) { /// The number of environment variables. /// - `size_t *environ_buf_size` /// The size of the environment variable string data. -pub fn environ_sizes_get(ctx: &mut Ctx, environ_count_out: u32, environ_buf_size_out: u32) { - let state = get_wasi_state(ctx); +pub fn environ_sizes_get( + ctx: &mut Ctx, + environ_count: WasmPtr, + environ_buf_size: WasmPtr, +) -> __wasi_errno_t { let memory = ctx.memory(0); - let env_count = state.envs.len(); - let total_env_size: usize = state.envs.iter().map(|v| v.len()).sum(); + if let (Some(environ_count), Some(environ_buf_size)) = + (environ_count.deref(memory), environ_buf_size.deref(memory)) + { + let state = get_wasi_state(ctx); - memory.view::()[(environ_count_out / 4) as usize].set(env_count as u32); - memory.view::()[(environ_buf_size_out / 4) as usize].set(total_env_size as u32); -} + environ_count.set(state.envs.len() as u32); + environ_buf_size.set(state.envs.iter().map(|v| v.len() as u32).sum()); -pub fn fd_advise(ctx: &mut Ctx) { - unimplemented!() -} -pub fn fd_allocate(ctx: &mut Ctx) { - unimplemented!() -} -pub fn fd_close(ctx: &mut Ctx) { - unimplemented!() -} -pub fn fd_datasync(ctx: &mut Ctx) { - unimplemented!() -} -pub fn fd_fdstat_get(ctx: &mut Ctx) { - unimplemented!() -} -pub fn fd_fdstat_set_flags(ctx: &mut Ctx) { - unimplemented!() -} -pub fn fd_fdstat_set_rights(ctx: &mut Ctx) { - unimplemented!() -} -pub fn fd_filestat_get(ctx: &mut Ctx) { - unimplemented!() -} -pub fn fd_filestat_set_size(ctx: &mut Ctx) { - unimplemented!() -} -pub fn fd_filestat_set_times(ctx: &mut Ctx) { - unimplemented!() -} -pub fn fd_pread(ctx: &mut Ctx) { - unimplemented!() -} -pub fn fd_prestat_get(ctx: &mut Ctx) { - unimplemented!() -} -pub fn fd_prestat_dir_name(ctx: &mut Ctx) { - unimplemented!() -} -pub fn fd_pwrite(ctx: &mut Ctx) { - unimplemented!() -} -pub fn fd_read(ctx: &mut Ctx) { - unimplemented!() -} -pub fn fd_readdir(ctx: &mut Ctx) { - unimplemented!() -} -pub fn fd_renumber(ctx: &mut Ctx) { - unimplemented!() + __WASI_ESUCCESS + } else { + __WASI_EOVERFLOW + } } -pub fn fd_seek(ctx: &mut Ctx) { + +pub fn fd_advise( + ctx: &mut Ctx, + fd: __wasi_fd_t, + offset: __wasi_filesize_t, + len: __wasi_filesize_t, + advice: __wasi_advice_t, +) -> __wasi_errno_t { unimplemented!() } -pub fn fd_sync(ctx: &mut Ctx) { +pub fn fd_allocate( + ctx: &mut Ctx, + fd: __wasi_fd_t, + offset: __wasi_filesize_t, + len: __wasi_filesize_t, +) -> __wasi_errno_t { unimplemented!() } -pub fn fd_tell(ctx: &mut Ctx) { +pub fn fd_close(ctx: &mut Ctx, fd: __wasi_fd_t) -> __wasi_errno_t { unimplemented!() } -pub fn fd_write(ctx: &mut Ctx) { +pub fn fd_datasync(ctx: &mut Ctx, fd: __wasi_fd_t) -> __wasi_errno_t { unimplemented!() } -pub fn path_create_directory(ctx: &mut Ctx) { +pub fn fd_fdstat_get( + ctx: &mut Ctx, + fd: __wasi_fd_t, + buf: WasmPtr<__wasi_fdstat_t>, +) -> __wasi_errno_t { unimplemented!() } -pub fn path_filestat_get(ctx: &mut Ctx) { +pub fn fd_fdstat_set_flags( + ctx: &mut Ctx, + fd: __wasi_fd_t, + flags: __wasi_fdflags_t, +) -> __wasi_errno_t { unimplemented!() } -pub fn path_filestat_set_times(ctx: &mut Ctx) { +pub fn fd_fdstat_set_rights( + ctx: &mut Ctx, + fd: __wasi_fd_t, + fs_rights_base: __wasi_rights_t, + fs_rights_inheriting: __wasi_rights_t, +) -> __wasi_errno_t { unimplemented!() } -pub fn path_link(ctx: &mut Ctx) { +pub fn fd_filestat_get( + ctx: &mut Ctx, + fd: __wasi_fd_t, + buf: WasmPtr<__wasi_filestat_t>, +) -> __wasi_errno_t { unimplemented!() } -pub fn path_open(ctx: &mut Ctx) { +pub fn fd_filestat_set_size( + ctx: &mut Ctx, + fd: __wasi_fd_t, + st_size: __wasi_filesize_t, +) -> __wasi_errno_t { unimplemented!() } -pub fn path_readlink(ctx: &mut Ctx) { +pub fn fd_filestat_set_times( + ctx: &mut Ctx, + fd: __wasi_fd_t, + st_atim: __wasi_timestamp_t, + st_mtim: __wasi_timestamp_t, + fst_flags: __wasi_fstflags_t, +) -> __wasi_errno_t { unimplemented!() } -pub fn path_remove_directory(ctx: &mut Ctx) { +pub fn fd_pread( + ctx: &mut Ctx, + fd: __wasi_fd_t, + iovs: WasmPtr<__wasi_iovec_t, Array>, + iovs_len: u32, + offset: __wasi_filesize_t, + nread: WasmPtr, +) -> __wasi_errno_t { unimplemented!() } -pub fn path_rename(ctx: &mut Ctx) { +pub fn fd_prestat_get( + ctx: &mut Ctx, + fd: __wasi_fd_t, + buf: WasmPtr<__wasi_fdstat_t>, +) -> __wasi_errno_t { unimplemented!() } -pub fn path_symlink(ctx: &mut Ctx) { +pub fn fd_prestat_dir_name( + ctx: &mut Ctx, + fd: __wasi_fd_t, + path: WasmPtr, + path_len: u32, +) -> __wasi_errno_t { unimplemented!() } -pub fn path_unlink_file(ctx: &mut Ctx) { +pub fn fd_pwrite( + ctx: &mut Ctx, + fd: __wasi_fd_t, + iovs: WasmPtr<__wasi_ciovec_t, Array>, + iovs_len: u32, + offset: __wasi_filesize_t, + nwritten: WasmPtr, +) -> __wasi_errno_t { unimplemented!() } -pub fn poll_oneoff(ctx: &mut Ctx) { +pub fn fd_read( + ctx: &mut Ctx, + fd: __wasi_fd_t, + iovs: WasmPtr<__wasi_iovec_t, Array>, + iovs_len: u32, + nread: WasmPtr, +) -> __wasi_errno_t { unimplemented!() } -pub fn proc_exit(ctx: &mut Ctx) { +pub fn fd_readdir( + ctx: &mut Ctx, + fd: __wasi_fd_t, + buf: WasmPtr, + buf_len: u32, + cookie: __wasi_dircookie_t, + bufused: WasmPtr, +) -> __wasi_errno_t { + unimplemented!() +} +pub fn fd_renumber(ctx: &mut Ctx, from: __wasi_fd_t, to: __wasi_fd_t) -> __wasi_errno_t { + unimplemented!() +} +pub fn fd_seek( + ctx: &mut Ctx, + fd: __wasi_fd_t, + offset: __wasi_filedelta_t, + whence: __wasi_whence_t, + newoffset: WasmPtr<__wasi_filesize_t>, +) -> __wasi_errno_t { + unimplemented!() +} +pub fn fd_sync(ctx: &mut Ctx, fd: __wasi_fd_t) -> __wasi_errno_t { + unimplemented!() +} +pub fn fd_tell( + ctx: &mut Ctx, + fd: __wasi_fd_t, + offset: WasmPtr<__wasi_filesize_t>, +) -> __wasi_errno_t { + unimplemented!() +} +pub fn fd_write( + ctx: &mut Ctx, + fd: __wasi_fd_t, + iovs: WasmPtr<__wasi_ciovec_t, Array>, + iovs_len: u32, + nwritten: WasmPtr, +) -> __wasi_errno_t { + unimplemented!() +} +pub fn path_create_directory( + ctx: &mut Ctx, + fd: __wasi_fd_t, + path: WasmPtr, + path_len: u32, +) -> __wasi_errno_t { + unimplemented!() +} +pub fn path_filestat_get( + ctx: &mut Ctx, + fd: __wasi_fd_t, + flags: __wasi_lookupflags_t, + path: WasmPtr, + path_len: u32, + buf: WasmPtr<__wasi_filestat_t>, +) -> __wasi_errno_t { + unimplemented!() +} +pub fn path_filestat_set_times( + ctx: &mut Ctx, + fd: __wasi_fd_t, + flags: __wasi_lookupflags_t, + path: WasmPtr, + path_len: u32, + st_atim: __wasi_timestamp_t, + st_mtim: __wasi_timestamp_t, + fst_flags: __wasi_fstflags_t, +) -> __wasi_errno_t { unimplemented!() } -pub fn proc_raise(ctx: &mut Ctx) { +pub fn path_link( + ctx: &mut Ctx, + old_fd: __wasi_fd_t, + old_flags: __wasi_lookupflags_t, + old_path: WasmPtr, + old_path_len: u32, + new_fd: __wasi_fd_t, + new_path: WasmPtr, + new_path_len: u32, +) -> __wasi_errno_t { + unimplemented!() +} +pub fn path_open( + ctx: &mut Ctx, + dirfd: __wasi_fd_t, + dirflags: __wasi_lookupflags_t, + path: WasmPtr, + path_len: u32, + o_flags: __wasi_oflags_t, + fs_rights_base: __wasi_rights_t, + fs_rights_inheriting: __wasi_rights_t, + fs_flags: __wasi_fdflags_t, + fd: WasmPtr<__wasi_fd_t>, +) -> __wasi_errno_t { unimplemented!() } -pub fn random_get(ctx: &mut Ctx) { +pub fn path_readlink( + ctx: &mut Ctx, + fd: __wasi_fd_t, + path: WasmPtr, + path_len: u32, + buf: WasmPtr, + buf_len: u32, + bufused: WasmPtr, +) -> __wasi_errno_t { unimplemented!() } -pub fn sched_yield(ctx: &mut Ctx) { - unimplemented!() +pub fn path_remove_directory( + ctx: &mut Ctx, + fd: __wasi_fd_t, + path: WasmPtr, + path_len: u32, +) -> __wasi_errno_t { + unimplemented!() +} +pub fn path_rename( + ctx: &mut Ctx, + old_fd: __wasi_fd_t, + old_path: WasmPtr, + old_path_len: u32, + new_fd: __wasi_fd_t, + new_path: WasmPtr, + new_path_len: u32, +) -> __wasi_errno_t { + unimplemented!() +} +pub fn path_symlink( + ctx: &mut Ctx, + old_path: WasmPtr, + old_path_len: u32, + fd: __wasi_fd_t, + new_path: WasmPtr, + new_path_len: u32, +) -> __wasi_errno_t { + unimplemented!() +} +pub fn path_unlink_file( + ctx: &mut Ctx, + fd: __wasi_fd_t, + path: WasmPtr, + path_len: u32, +) -> __wasi_errno_t { + unimplemented!() +} +pub fn poll_oneoff( + ctx: &mut Ctx, + in_: WasmPtr<__wasi_subscription_t, Array>, + out_: WasmPtr<__wasi_event_t, Array>, + nsubscriptions: u32, + nevents: WasmPtr, +) -> __wasi_errno_t { + unimplemented!() +} +pub fn proc_exit(ctx: &mut Ctx, rval: __wasi_exitcode_t) { + unimplemented!() +} +pub fn proc_raise(ctx: &mut Ctx, sig: __wasi_signal_t) -> __wasi_errno_t { + unimplemented!() +} +pub fn random_get(ctx: &mut Ctx, buf: WasmPtr, buf_len: u32) -> __wasi_errno_t { + unimplemented!() +} +pub fn sched_yield(ctx: &mut Ctx) -> __wasi_errno_t { + unimplemented!() } -pub fn sock_recv(ctx: &mut Ctx) { +pub fn sock_recv( + ctx: &mut Ctx, + sock: __wasi_fd_t, + ri_data: WasmPtr<__wasi_iovec_t, Array>, + ri_data_len: u32, + ri_flags: __wasi_riflags_t, + ro_datalen: WasmPtr, + ro_flags: WasmPtr<__wasi_roflags_t>, +) -> __wasi_errno_t { unimplemented!() } -pub fn sock_send(ctx: &mut Ctx) { +pub fn sock_send( + ctx: &mut Ctx, + sock: __wasi_fd_t, + si_data: WasmPtr<__wasi_ciovec_t, Array>, + si_data_len: u32, + si_flags: __wasi_siflags_t, + so_datalen: WasmPtr, +) -> __wasi_errno_t { unimplemented!() } -pub fn sock_shutdown(ctx: &mut Ctx) { +pub fn sock_shutdown(ctx: &mut Ctx, sock: __wasi_fd_t, how: __wasi_sdflags_t) -> __wasi_errno_t { unimplemented!() } diff --git a/lib/wasi/src/syscalls/types.rs b/lib/wasi/src/syscalls/types.rs index 6a927a30119..7995e86bec8 100644 --- a/lib/wasi/src/syscalls/types.rs +++ b/lib/wasi/src/syscalls/types.rs @@ -1,5 +1,8 @@ #![allow(non_camel_case_types)] +use crate::ptr::{Array, WasmPtr}; +use wasmer_runtime_core::types::{ValueError, ValueType}; + pub type __wasi_advice_t = u8; pub const __WASI_ADVICE_DONTNEED: u8 = 0; pub const __WASI_ADVICE_NOREUSE: u8 = 1; @@ -11,7 +14,7 @@ pub const __WASI_ADVICE_WILLNEED: u8 = 5; #[derive(Debug, Copy, Clone, PartialEq, Eq)] #[repr(C)] pub struct __wasi_ciovec_t { - pub buf: u32, + pub buf: WasmPtr, pub buf_len: u32, } @@ -205,7 +208,7 @@ pub type __wasi_inode_t = u64; #[derive(Debug, Copy, Clone, PartialEq, Eq)] #[repr(C)] pub struct __wasi_iovec_t { - pub buf: u32, + pub buf: WasmPtr, pub buf_len: u32, } @@ -220,7 +223,7 @@ pub const __WASI_O_DIRECTORY: u16 = 1 << 1; pub const __WASI_O_EXCL: u16 = 1 << 2; pub const __WASI_O_TRUNC: u16 = 1 << 3; -pub type __wasi_riflags = u16; +pub type __wasi_riflags_t = u16; pub const __WASI_SOCK_RECV_PEEK: u16 = 1 << 0; pub const __WASI_SOCK_RECV_WAITALL: u16 = 1 << 1;