Skip to content

Commit 6e2a3fb

Browse files
committed
allow WASM to write data in a file
1 parent d288c3d commit 6e2a3fb

File tree

1 file changed

+233
-21
lines changed

1 file changed

+233
-21
lines changed

src/wasm/mod.rs

Lines changed: 233 additions & 21 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,8 @@
1+
use alloc::borrow::ToOwned;
12
use alloc::collections::VecDeque;
3+
use alloc::string::String;
24
use alloc::vec::Vec;
5+
use core::ffi::CStr;
36
use core::future;
47
use core::hint::black_box;
58
use core::mem::MaybeUninit;
@@ -11,7 +14,7 @@ use wasmtime::*;
1114
use zerocopy::IntoBytes;
1215

1316
use crate::executor::{WakerRegistration, spawn};
14-
use crate::fd;
17+
use crate::fd::{self, remove_object};
1518
use crate::kernel::systemtime::now_micros;
1619

1720
mod capi;
@@ -44,14 +47,47 @@ pub fn measure_fibonacci(n: u64) {
4447
);
4548
}
4649

50+
#[derive(Debug, Clone, PartialEq)]
51+
enum Descriptor {
52+
None,
53+
Stdin,
54+
Stdout,
55+
Stderr,
56+
Directory(String),
57+
RawFd(fd::FileDescriptor),
58+
}
59+
60+
impl Descriptor {
61+
#[inline]
62+
pub fn is_none(&self) -> bool {
63+
*self == Self::None
64+
}
65+
}
66+
67+
bitflags! {
68+
/// Options for opening files
69+
#[derive(Debug, Copy, Clone, Default)]
70+
pub(crate) struct Oflags: i32 {
71+
/// Create file if it does not exist.
72+
const OFLAGS_CREAT = 1 << 0;
73+
/// Fail if not a directory.
74+
const OFLAGS_DIRECTORY = 1 << 1;
75+
/// Fail if file already exists.
76+
const OFLAGS_EXCL = 1 << 2;
77+
/// Truncate file to size 0.
78+
const OFLAGS_TRUNC = 1 << 3;
79+
}
80+
}
81+
4782
pub(crate) static WASM_MANAGER: InterruptTicketMutex<Option<WasmManager>> =
4883
InterruptTicketMutex::new(None);
4984
pub(crate) static INPUT: InterruptTicketMutex<VecDeque<Vec<u8>>> =
5085
InterruptTicketMutex::new(VecDeque::new());
5186
static OUTPUT: InterruptTicketMutex<WasmStdout> = InterruptTicketMutex::new(WasmStdout::new());
87+
static FD: InterruptTicketMutex<Vec<Descriptor>> = InterruptTicketMutex::new(Vec::new());
5288

5389
struct WasmStdout {
54-
pub data: VecDeque<Vec<u8>>,
90+
pub data: VecDeque<(Descriptor, Vec<u8>)>,
5591
pub waker: WakerRegistration,
5692
}
5793

@@ -63,8 +99,8 @@ impl WasmStdout {
6399
}
64100
}
65101

66-
pub fn write(&mut self, buf: &[u8]) {
67-
self.data.push_back(buf.to_vec());
102+
pub fn write(&mut self, desc: &Descriptor, buf: &[u8]) {
103+
self.data.push_back((desc.clone(), buf.to_vec()));
68104
self.waker.wake();
69105
}
70106
}
@@ -91,6 +127,80 @@ impl WasmManager {
91127
crate::arch::kernel::systemtime::now_micros()
92128
})
93129
.unwrap();
130+
linker
131+
.func_wrap(
132+
"wasi_snapshot_preview1",
133+
"path_open",
134+
|mut caller: Caller<'_, _>,
135+
_fd: i32,
136+
_dirflags: i32,
137+
path_ptr: i32,
138+
path_len: i32,
139+
oflags: i32,
140+
_fs_rights_base: Rights,
141+
_fs_rights_inheriting: Rights,
142+
_fdflags: i32,
143+
fd_ptr: i32| {
144+
let oflags = Oflags::from_bits(oflags).unwrap();
145+
if let Some(Extern::Memory(mem)) = caller.get_export("memory") {
146+
let mut path = vec![0u8; path_len.try_into().unwrap()];
147+
148+
let _ = mem.read(
149+
caller.as_context_mut(),
150+
path_ptr.try_into().unwrap(),
151+
path.as_mut_bytes(),
152+
);
153+
let path = "/".to_owned() + str::from_utf8(&path).unwrap();
154+
155+
let mut flags = fd::OpenOption::empty();
156+
if oflags.contains(Oflags::OFLAGS_CREAT) {
157+
flags |= fd::OpenOption::O_CREAT;
158+
}
159+
if oflags.contains(Oflags::OFLAGS_TRUNC) {
160+
flags |= fd::OpenOption::O_TRUNC;
161+
}
162+
flags |= fd::OpenOption::O_RDWR;
163+
164+
let mode = fd::AccessPermission::from_bits(0).unwrap();
165+
let mut c_path = vec![0u8; path.len() + 1];
166+
c_path[..path.len()].copy_from_slice(path.as_bytes());
167+
let path = CStr::from_bytes_until_nul(&c_path)
168+
.unwrap()
169+
.to_str()
170+
.unwrap();
171+
{
172+
let raw_fd = crate::fs::open(path, flags, mode).unwrap();
173+
let mut guard = FD.lock();
174+
for (i, entry) in guard.iter_mut().enumerate() {
175+
if entry.is_none() {
176+
*entry = Descriptor::RawFd(raw_fd);
177+
let _ = mem.write(
178+
caller.as_context_mut(),
179+
fd_ptr.try_into().unwrap(),
180+
i.as_bytes(),
181+
);
182+
183+
guard.push(Descriptor::RawFd(raw_fd));
184+
185+
return ERRNO_SUCCESS.raw() as i32;
186+
}
187+
}
188+
189+
let new_fd: i32 = (guard.len() - 1).try_into().unwrap();
190+
let _ = mem.write(
191+
caller.as_context_mut(),
192+
fd_ptr.try_into().unwrap(),
193+
new_fd.as_bytes(),
194+
);
195+
}
196+
197+
return ERRNO_SUCCESS.raw() as i32;
198+
}
199+
200+
ERRNO_INVAL.raw() as i32
201+
},
202+
)
203+
.unwrap();
94204
linker
95205
.func_wrap(
96206
"wasi_snapshot_preview1",
@@ -148,10 +258,17 @@ impl WasmManager {
148258
"wasi_snapshot_preview1",
149259
"fd_write",
150260
|mut caller: Caller<'_, u32>,
151-
_fd: i32,
261+
fd: i32,
152262
iovs_ptr: i32,
153263
iovs_len: i32,
154264
nwritten_ptr: i32| {
265+
let desc = match fd {
266+
fd::STDIN_FILENO => Descriptor::Stdin,
267+
fd::STDOUT_FILENO => Descriptor::Stdout,
268+
fd::STDERR_FILENO => Descriptor::Stderr,
269+
_ => Descriptor::RawFd(fd),
270+
};
271+
155272
if let Some(Extern::Memory(mem)) = caller.get_export("memory") {
156273
let mut iovs = vec![0i32; (2 * iovs_len).try_into().unwrap()];
157274
let _ = mem.read(
@@ -182,7 +299,9 @@ impl WasmManager {
182299
iovs[i].try_into().unwrap(),
183300
unsafe { data.assume_init_mut() },
184301
);
185-
OUTPUT.lock().write(unsafe { data.assume_init_mut() });
302+
OUTPUT
303+
.lock()
304+
.write(&desc, unsafe { data.assume_init_mut() });
186305
nwritten_bytes += len;
187306

188307
i += 2;
@@ -300,6 +419,43 @@ impl WasmManager {
300419
},
301420
)
302421
.unwrap();
422+
linker
423+
.func_wrap(
424+
"wasi_snapshot_preview1",
425+
"fd_prestat_get",
426+
|mut caller: Caller<'_, _>, fd: i32, prestat_ptr: i32| {
427+
let guard = FD.lock();
428+
if fd < guard.len().try_into().unwrap()
429+
&& let Some(Extern::Memory(mem)) = caller.get_export("memory")
430+
&& let Descriptor::Directory(name) = &guard[fd as usize]
431+
{
432+
let stat = Prestat {
433+
tag: PREOPENTYPE_DIR.raw(),
434+
u: PrestatU {
435+
dir: PrestatDir {
436+
pr_name_len: name.len(),
437+
},
438+
},
439+
};
440+
441+
let _ = mem.write(
442+
caller.as_context_mut(),
443+
prestat_ptr.try_into().unwrap(),
444+
unsafe {
445+
core::slice::from_raw_parts(
446+
(&stat as *const _) as *const u8,
447+
size_of::<Prestat>(),
448+
)
449+
},
450+
);
451+
452+
return ERRNO_SUCCESS.raw() as i32;
453+
}
454+
455+
ERRNO_BADF.raw() as i32
456+
},
457+
)
458+
.unwrap();
303459
linker
304460
.func_wrap(
305461
"wasi_snapshot_preview1",
@@ -331,7 +487,46 @@ impl WasmManager {
331487
)
332488
.unwrap();
333489
linker
334-
.func_wrap("wasi_snapshot_preview1", "fd_close", |_fd: i32| {
490+
.func_wrap(
491+
"wasi_snapshot_preview1",
492+
"fd_prestat_dir_name",
493+
|mut caller: Caller<'_, _>, fd: i32, path_ptr: i32, path_len: i32| {
494+
let guard = FD.lock();
495+
if fd < guard.len().try_into().unwrap()
496+
&& let Descriptor::Directory(path) = &guard[fd as usize]
497+
{
498+
if let Some(Extern::Memory(mem)) = caller.get_export(
499+
"memory
500+
",
501+
) {
502+
if path_len < path.len().try_into().unwrap() {
503+
return ERRNO_INVAL.raw() as i32;
504+
}
505+
506+
let _ = mem.write(
507+
caller.as_context_mut(),
508+
path_ptr.try_into().unwrap(),
509+
path.as_bytes(),
510+
);
511+
}
512+
513+
return ERRNO_SUCCESS.raw() as i32;
514+
}
515+
516+
ERRNO_BADF.raw() as i32
517+
},
518+
)
519+
.unwrap();
520+
linker
521+
.func_wrap("wasi_snapshot_preview1", "fd_close", |fd: i32| {
522+
let mut guard = FD.lock();
523+
if fd < guard.len().try_into().unwrap()
524+
&& let Descriptor::RawFd(os_fd) = guard[fd as usize]
525+
{
526+
let _obj = remove_object(os_fd);
527+
guard[fd as usize] = Descriptor::None;
528+
}
529+
335530
ERRNO_SUCCESS.raw() as i32
336531
})
337532
.unwrap();
@@ -382,21 +577,20 @@ impl WasmManager {
382577
}
383578
}
384579

385-
#[hermit_macro::system]
386-
#[unsafe(no_mangle)]
387-
pub extern "C" fn sys_unload_binary() -> i32 {
388-
*WASM_MANAGER.lock() = None;
389-
390-
0
391-
}
392-
393580
async fn wasm_run() {
394581
loop {
395-
let obj = crate::core_scheduler()
396-
.get_object(fd::STDOUT_FILENO)
397-
.unwrap();
582+
while let Some((fd, data)) = OUTPUT.lock().data.pop_front() {
583+
let obj = match fd {
584+
Descriptor::Stdout => crate::core_scheduler()
585+
.get_object(fd::STDOUT_FILENO)
586+
.unwrap(),
587+
Descriptor::Stderr => crate::core_scheduler()
588+
.get_object(fd::STDERR_FILENO)
589+
.unwrap(),
590+
Descriptor::RawFd(raw_fd) => crate::core_scheduler().get_object(raw_fd).unwrap(),
591+
_ => panic!("Unsuppted {fd:?}"),
592+
};
398593

399-
while let Some(data) = OUTPUT.lock().data.pop_front() {
400594
obj.write(&data).await.unwrap();
401595
}
402596

@@ -426,15 +620,33 @@ pub extern "C" fn sys_load_binary(ptr: *const u8, len: usize) -> i32 {
426620
let end = now_micros();
427621
info!("Time to initiate WASM module {} usec", end - start);
428622

429-
if let Some(ref mut wasm_manager) = crate::wasm::WASM_MANAGER.lock().as_mut() {
430-
let _ = wasm_manager.call_func::<(), ()>("hello_world", ());
623+
{
624+
let mut guard = FD.lock();
625+
guard.push(Descriptor::Stdin);
626+
guard.push(Descriptor::Stdout);
627+
guard.push(Descriptor::Stderr);
628+
guard.push(Descriptor::Directory(String::from("tmp")));
629+
guard.push(Descriptor::Directory(String::from("root")));
431630
}
432631

632+
/*if let Some(ref mut wasm_manager) = crate::wasm::WASM_MANAGER.lock().as_mut() {
633+
let _ = wasm_manager.call_func::<(), ()>("hello_world", ());
634+
}*/
635+
433636
spawn(wasm_run());
434637

435638
0
436639
}
437640

641+
#[hermit_macro::system]
642+
#[unsafe(no_mangle)]
643+
pub extern "C" fn sys_unload_binary() -> i32 {
644+
*WASM_MANAGER.lock() = None;
645+
FD.lock().clear();
646+
647+
0
648+
}
649+
438650
#[hermit_macro::system]
439651
#[unsafe(no_mangle)]
440652
pub extern "C" fn sys_dhrystone() -> i32 {

0 commit comments

Comments
 (0)