1+ use alloc:: borrow:: ToOwned ;
12use alloc:: collections:: VecDeque ;
3+ use alloc:: string:: String ;
24use alloc:: vec:: Vec ;
5+ use core:: ffi:: CStr ;
36use core:: future;
47use core:: hint:: black_box;
58use core:: mem:: MaybeUninit ;
@@ -11,7 +14,7 @@ use wasmtime::*;
1114use zerocopy:: IntoBytes ;
1215
1316use crate :: executor:: { WakerRegistration , spawn} ;
14- use crate :: fd;
17+ use crate :: fd:: { self , remove_object } ;
1518use crate :: kernel:: systemtime:: now_micros;
1619
1720mod 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+
4782pub ( crate ) static WASM_MANAGER : InterruptTicketMutex < Option < WasmManager > > =
4883 InterruptTicketMutex :: new ( None ) ;
4984pub ( crate ) static INPUT : InterruptTicketMutex < VecDeque < Vec < u8 > > > =
5085 InterruptTicketMutex :: new ( VecDeque :: new ( ) ) ;
5186static OUTPUT : InterruptTicketMutex < WasmStdout > = InterruptTicketMutex :: new ( WasmStdout :: new ( ) ) ;
87+ static FD : InterruptTicketMutex < Vec < Descriptor > > = InterruptTicketMutex :: new ( Vec :: new ( ) ) ;
5288
5389struct 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-
393580async 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) ]
440652pub extern "C" fn sys_dhrystone ( ) -> i32 {
0 commit comments