mycelium_kernel/wasm/
wasi.rs1use super::Host;
2
3const __WASI_ESUCCESS: u16 = 0;
6const __WASI_EIO: u16 = 29; const __WASI_STDOUT: u32 = 1;
9
10fn get_element_ptr(base: u32, offset: u32, scale: u32) -> Result<u32, wasmi::Trap> {
11 let byte_offset = offset
12 .checked_mul(scale)
13 .ok_or(wasmi::TrapKind::MemoryAccessOutOfBounds)?;
14 Ok(base
15 .checked_add(byte_offset)
16 .ok_or(wasmi::TrapKind::MemoryAccessOutOfBounds)?)
17}
18
19fn mem_read<T: wasmi::LittleEndianConvert>(
21 mem: &[u8],
22 base: u32,
23 offset: u32,
24 scale: u32,
25) -> Result<T, wasmi::Trap> {
26 let addr = get_element_ptr(base, offset, scale)?;
27 let slice = mem
28 .get(addr as usize..)
29 .ok_or(wasmi::TrapKind::MemoryAccessOutOfBounds)?;
30 Ok(T::from_little_endian(slice).map_err(|_| wasmi::TrapKind::MemoryAccessOutOfBounds)?)
31}
32
33fn mem_write<T: wasmi::LittleEndianConvert>(
35 mem: &mut [u8],
36 value: T,
37 base: u32,
38 offset: u32,
39 scale: u32,
40) -> Result<(), wasmi::Trap> {
41 let addr = get_element_ptr(base, offset, scale)?;
42
43 let addr_after = get_element_ptr(addr, core::mem::size_of::<T>() as u32, 1)?;
49 let slice = mem
50 .get_mut(addr as usize..addr_after as usize)
51 .ok_or(wasmi::TrapKind::MemoryAccessOutOfBounds)?;
52 T::into_little_endian(value, slice);
53 Ok(())
54}
55
56fn mem_slice(mem: &[u8], addr: u32, len: u32) -> Result<&[u8], wasmi::Trap> {
58 let end = get_element_ptr(addr, len, 1)?;
59 Ok(mem
60 .get(addr as usize..end as usize)
61 .ok_or(wasmi::TrapKind::MemoryAccessOutOfBounds)?)
62}
63
64#[allow(dead_code)] fn mem_slice_mut(mem: &mut [u8], addr: u32, len: u32) -> Result<&mut [u8], wasmi::Trap> {
66 let end = get_element_ptr(addr, len, 1)?;
67 Ok(mem
68 .get_mut(addr as usize..end as usize)
69 .ok_or(wasmi::TrapKind::MemoryAccessOutOfBounds)?)
70}
71
72#[tracing::instrument(skip(host))]
73pub fn fd_write(
74 host: &mut Host,
75 fd: u32,
76 iovs: u32,
77 iovs_len: u32,
78 nwritten: u32,
79) -> Result<u16, wasmi::Trap> {
80 if fd != __WASI_STDOUT {
81 return Ok(__WASI_EIO);
82 }
83
84 host.memory.with_direct_access_mut(|mem| {
85 let mut bytes_written = 0u32;
86 for idx in 0..iovs_len {
87 let iov = get_element_ptr(iovs, 8, idx)?;
89 let buf = mem_read::<u32>(mem, iov, 0, 4)?;
90 let buf_len = mem_read::<u32>(mem, iov, 1, 4)?;
91
92 let buf_slice = mem_slice(mem, buf, buf_len)?;
94 let buf_str = core::str::from_utf8(buf_slice);
95 tracing::info!(?buf_slice, ?buf_str, "fd_write");
96
97 bytes_written = bytes_written.saturating_add(buf_len);
98 }
99
100 mem_write::<u32>(mem, bytes_written, nwritten, 0, 0)?;
102 Ok(__WASI_ESUCCESS)
103 })
104}