diff --git a/doc/crates.js b/doc/crates.js index 03ca93387a..a5dfadc6d0 100644 --- a/doc/crates.js +++ b/doc/crates.js @@ -1 +1 @@ -window.ALL_CRATES = ["___Theseus_Crates___","acpi","acpi_table","acpi_table_handler","ap_start","apic","app_io","async_channel","ata","atomic_linked_list","block_allocator","block_cache","bootloader_modules","captain","catch_unwind","color","compositor","console","context_switch","context_switch_avx","context_switch_regular","context_switch_sse","cow_arc","crate_metadata","crate_name_utils","crate_swap","debug_info","debugit","deferred_interrupt_tasks","device_manager","dfqueue","displayable","dmar","e1000","entryflags_x86_64","environment","ethernet_smoltcp_device","event_types","exceptions_early","exceptions_full","fadt","fault_crate_swap","fault_log","first_application","font","frame_allocator","framebuffer","framebuffer_compositor","framebuffer_drawer","framebuffer_printer","fs_node","gdt","heap","heapfile","hpet","http_client","intel_ethernet","interrupts","io","ioapic","iommu","ixgbe","kernel_config","keyboard","keycodes_ascii","libterm","libtest","lockable","logger","madt","mapper_spillful","memfs","memory","memory_initialization","memory_structs","memory_x86_64","mlx5","mlx_ethernet","mod_mgmt","mouse","mouse_data","multicore_bringup","multiple_heaps","mutex_sleep","nano_core","network_interface_card","network_manager","nic_buffers","nic_initialization","nic_queues","ota_update_client","page_allocator","page_table_entry","panic_entry","panic_wrapper","path","pause","pci","percent_encoding","physical_nic","pic","pit_clock","pmu_x86","port_io","print","ps2","rendezvous","root","rsdp","rsdt","rtc","runqueue","runqueue_priority","runqueue_round_robin","scheduler","scheduler_priority","scheduler_round_robin","sdt","serial_port","serial_port_basic","shapes","simd_personality","simd_test","simple_ipc","single_simd_task_optimization","slabmalloc","slabmalloc_safe","slabmalloc_unsafe","smoltcp_helper","spawn","stack","stack_trace","stack_trace_frame_pointers","state_store","state_transfer","stdio","storage_device","storage_manager","task","task_fs","terminal_print","test_thread_local","text_display","text_terminal","thread_local_macro","tlb_shootdown","tsc","tss","unified_channel","unwind","util","vfs_node","vga_buffer","virtual_nic","wait_condition","wait_queue","window","window_inner","window_manager"]; \ No newline at end of file +window.ALL_CRATES = ["___Theseus_Crates___","acpi","acpi_table","acpi_table_handler","ap_start","apic","app_io","async_channel","ata","atomic_linked_list","block_allocator","block_cache","bootloader_modules","captain","catch_unwind","color","compositor","console","context_switch","context_switch_avx","context_switch_regular","context_switch_sse","cow_arc","crate_metadata","crate_name_utils","crate_swap","debug_info","debugit","deferred_interrupt_tasks","device_manager","dfqueue","displayable","dmar","e1000","entryflags_x86_64","environment","ethernet_smoltcp_device","event_types","exceptions_early","exceptions_full","fadt","fault_crate_swap","fault_log","first_application","font","frame_allocator","framebuffer","framebuffer_compositor","framebuffer_drawer","framebuffer_printer","fs_node","gdt","heap","heapfile","hpet","http_client","intel_ethernet","interrupts","io","ioapic","iommu","ixgbe","kernel_config","keyboard","keycodes_ascii","libterm","libtest","lockable","logger","madt","mapper_spillful","memfs","memory","memory_initialization","memory_structs","memory_x86_64","mlx5","mlx_ethernet","mod_mgmt","mouse","mouse_data","multicore_bringup","multiple_heaps","mutex_sleep","nano_core","network_interface_card","network_manager","nic_buffers","nic_initialization","nic_queues","ota_update_client","page_allocator","page_table_entry","panic_entry","panic_wrapper","path","pause","pci","percent_encoding","physical_nic","pic","pit_clock","pmu_x86","port_io","print","ps2","rendezvous","root","rsdp","rsdt","rtc","runqueue","runqueue_priority","runqueue_round_robin","scheduler","scheduler_priority","scheduler_round_robin","sdt","serial_port","serial_port_basic","shapes","simd_personality","simd_test","simple_ipc","single_simd_task_optimization","slabmalloc","slabmalloc_safe","slabmalloc_unsafe","smoltcp_helper","spawn","stack","stack_trace","stack_trace_frame_pointers","state_store","state_transfer","stdio","storage_device","storage_manager","task","task_fs","terminal_print","test_thread_local","text_display","text_terminal","thread_local_macro","tlb_shootdown","tsc","tss","unified_channel","unwind","util","vfs_node","vga_buffer","virtual_nic","wait_condition","wait_queue","wasi_interpreter","window","window_inner","window_manager"]; \ No newline at end of file diff --git a/doc/implementors/core/marker/trait.Freeze.js b/doc/implementors/core/marker/trait.Freeze.js index 637a532da0..894195f8fd 100644 --- a/doc/implementors/core/marker/trait.Freeze.js +++ b/doc/implementors/core/marker/trait.Freeze.js @@ -105,6 +105,7 @@ implementors["vga_buffer"] = [{"text":"impl Freeze for VirtualNic<S, T, U, V>","synthetic":true,"types":["virtual_nic::VirtualNic"]}]; implementors["wait_condition"] = [{"text":"impl<F> !Freeze for WaitCondition<F>","synthetic":true,"types":["wait_condition::WaitCondition"]},{"text":"impl<'wc, F> Freeze for SatisfiedWaitCondition<'wc, F>","synthetic":true,"types":["wait_condition::SatisfiedWaitCondition"]}]; implementors["wait_queue"] = [{"text":"impl Freeze for WaitGuard","synthetic":true,"types":["wait_queue::WaitGuard"]},{"text":"impl Freeze for WaitError","synthetic":true,"types":["wait_queue::WaitError"]},{"text":"impl !Freeze for WaitQueue","synthetic":true,"types":["wait_queue::WaitQueue"]}]; +implementors["wasi_interpreter"] = [{"text":"impl Freeze for HostExternals","synthetic":true,"types":["wasi_interpreter::HostExternals"]}]; implementors["window"] = [{"text":"impl Freeze for Window","synthetic":true,"types":["window::Window"]}]; implementors["window_inner"] = [{"text":"impl Freeze for WindowMovingStatus","synthetic":true,"types":["window_inner::WindowMovingStatus"]},{"text":"impl Freeze for WindowInner","synthetic":true,"types":["window_inner::WindowInner"]}]; implementors["window_manager"] = [{"text":"impl Freeze for WindowManager","synthetic":true,"types":["window_manager::WindowManager"]}]; diff --git a/doc/implementors/core/marker/trait.Send.js b/doc/implementors/core/marker/trait.Send.js index c1242f3427..92bdbe6400 100644 --- a/doc/implementors/core/marker/trait.Send.js +++ b/doc/implementors/core/marker/trait.Send.js @@ -105,6 +105,7 @@ implementors["vga_buffer"] = [{"text":"impl Send for VirtualNic<S, T, U, V>","synthetic":true,"types":["virtual_nic::VirtualNic"]}]; implementors["wait_condition"] = [{"text":"impl<F> Send for WaitCondition<F> where
    F: Send
","synthetic":true,"types":["wait_condition::WaitCondition"]},{"text":"impl<'wc, F> Send for SatisfiedWaitCondition<'wc, F> where
    F: Sync
","synthetic":true,"types":["wait_condition::SatisfiedWaitCondition"]}]; implementors["wait_queue"] = [{"text":"impl Send for WaitGuard","synthetic":true,"types":["wait_queue::WaitGuard"]},{"text":"impl Send for WaitError","synthetic":true,"types":["wait_queue::WaitError"]},{"text":"impl Send for WaitQueue","synthetic":true,"types":["wait_queue::WaitQueue"]}]; +implementors["wasi_interpreter"] = [{"text":"impl !Send for HostExternals","synthetic":true,"types":["wasi_interpreter::HostExternals"]}]; implementors["window"] = [{"text":"impl Send for Window","synthetic":true,"types":["window::Window"]}]; implementors["window_inner"] = [{"text":"impl Send for WindowMovingStatus","synthetic":true,"types":["window_inner::WindowMovingStatus"]},{"text":"impl Send for WindowInner","synthetic":true,"types":["window_inner::WindowInner"]}]; implementors["window_manager"] = [{"text":"impl Send for WindowManager","synthetic":true,"types":["window_manager::WindowManager"]}]; diff --git a/doc/implementors/core/marker/trait.Sync.js b/doc/implementors/core/marker/trait.Sync.js index a70032aac8..0c8fc79b30 100644 --- a/doc/implementors/core/marker/trait.Sync.js +++ b/doc/implementors/core/marker/trait.Sync.js @@ -105,6 +105,7 @@ implementors["vga_buffer"] = [{"text":"impl Sync for VirtualNic<S, T, U, V>","synthetic":true,"types":["virtual_nic::VirtualNic"]}]; implementors["wait_condition"] = [{"text":"impl<F> Sync for WaitCondition<F> where
    F: Sync
","synthetic":true,"types":["wait_condition::WaitCondition"]},{"text":"impl<'wc, F> Sync for SatisfiedWaitCondition<'wc, F> where
    F: Sync
","synthetic":true,"types":["wait_condition::SatisfiedWaitCondition"]}]; implementors["wait_queue"] = [{"text":"impl Sync for WaitGuard","synthetic":true,"types":["wait_queue::WaitGuard"]},{"text":"impl Sync for WaitError","synthetic":true,"types":["wait_queue::WaitError"]},{"text":"impl Sync for WaitQueue","synthetic":true,"types":["wait_queue::WaitQueue"]}]; +implementors["wasi_interpreter"] = [{"text":"impl !Sync for HostExternals","synthetic":true,"types":["wasi_interpreter::HostExternals"]}]; implementors["window"] = [{"text":"impl Sync for Window","synthetic":true,"types":["window::Window"]}]; implementors["window_inner"] = [{"text":"impl Sync for WindowMovingStatus","synthetic":true,"types":["window_inner::WindowMovingStatus"]},{"text":"impl Sync for WindowInner","synthetic":true,"types":["window_inner::WindowInner"]}]; implementors["window_manager"] = [{"text":"impl Sync for WindowManager","synthetic":true,"types":["window_manager::WindowManager"]}]; diff --git a/doc/implementors/core/marker/trait.Unpin.js b/doc/implementors/core/marker/trait.Unpin.js index dea8b5fe66..d5b9e69c2d 100644 --- a/doc/implementors/core/marker/trait.Unpin.js +++ b/doc/implementors/core/marker/trait.Unpin.js @@ -105,6 +105,7 @@ implementors["vga_buffer"] = [{"text":"impl Unpin for VirtualNic<S, T, U, V> where
    S: Unpin,
    U: Unpin
","synthetic":true,"types":["virtual_nic::VirtualNic"]}]; implementors["wait_condition"] = [{"text":"impl<F> Unpin for WaitCondition<F> where
    F: Unpin
","synthetic":true,"types":["wait_condition::WaitCondition"]},{"text":"impl<'wc, F> Unpin for SatisfiedWaitCondition<'wc, F>","synthetic":true,"types":["wait_condition::SatisfiedWaitCondition"]}]; implementors["wait_queue"] = [{"text":"impl Unpin for WaitGuard","synthetic":true,"types":["wait_queue::WaitGuard"]},{"text":"impl Unpin for WaitError","synthetic":true,"types":["wait_queue::WaitError"]},{"text":"impl Unpin for WaitQueue","synthetic":true,"types":["wait_queue::WaitQueue"]}]; +implementors["wasi_interpreter"] = [{"text":"impl Unpin for HostExternals","synthetic":true,"types":["wasi_interpreter::HostExternals"]}]; implementors["window"] = [{"text":"impl Unpin for Window","synthetic":true,"types":["window::Window"]}]; implementors["window_inner"] = [{"text":"impl Unpin for WindowMovingStatus","synthetic":true,"types":["window_inner::WindowMovingStatus"]},{"text":"impl Unpin for WindowInner","synthetic":true,"types":["window_inner::WindowInner"]}]; implementors["window_manager"] = [{"text":"impl Unpin for WindowManager","synthetic":true,"types":["window_manager::WindowManager"]}]; diff --git a/doc/implementors/wasmi/host/trait.Externals.js b/doc/implementors/wasmi/host/trait.Externals.js new file mode 100644 index 0000000000..c9b7d2d747 --- /dev/null +++ b/doc/implementors/wasmi/host/trait.Externals.js @@ -0,0 +1,3 @@ +(function() {var implementors = {}; +implementors["wasi_interpreter"] = [{"text":"impl Externals for HostExternals","synthetic":false,"types":["wasi_interpreter::HostExternals"]}]; +if (window.register_implementors) {window.register_implementors(implementors);} else {window.pending_implementors = implementors;}})() \ No newline at end of file diff --git a/doc/search-index.js b/doc/search-index.js index 8306d5047a..2e0610ed01 100644 --- a/doc/search-index.js +++ b/doc/search-index.js @@ -155,6 +155,7 @@ var searchIndex = JSON.parse('{\ "virtual_nic":{"doc":"This crate defines a struct that enables language-level …","t":[3,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11],"n":["VirtualNic","borrow","borrow_mut","drop","from","get_received_frame","id","into","mac_address","new","poll_receive","send_packet","send_packet_on_queue","try_from","try_into","type_id"],"q":["virtual_nic","","","","","","","","","","","","","","",""],"d":["A structure that contains a set of RxQueues and TxQueues …","","","","","","","","","Create a new VirtualNIC with the given parameters. For …","","","Send a packet on the specified queue.","","",""],"i":[0,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1],"f":[null,[[]],[[]],[[]],[[]],[[],[["option",4],["receivedframe",3]]],[[],["u8",15]],[[]],[[]],[[["vec",3],["rxqueue",3],["mutexirqsafe",3],["txqueue",3],["usize",15],["vec",3]],[["virtualnic",3],["str",15],["result",4]]],[[],[["result",4],["str",15]]],[[["transmitbuffer",3]],[["result",4],["str",15]]],[[["usize",15],["transmitbuffer",3]],[["result",4],["str",15]]],[[],["result",4]],[[],["result",4]],[[],["typeid",3]]],"p":[[3,"VirtualNic"]]},\ "wait_condition":{"doc":"Simple condition variables that are convenience wrappers …","t":[3,3,25,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11],"n":["SatisfiedWaitCondition","WaitCondition","WaitConditionFn","borrow","borrow","borrow_mut","borrow_mut","condition_satisfied","from","from","into","into","new","notify_one","notify_specific","try_from","try_from","try_into","try_into","type_id","type_id","wait"],"q":["wait_condition","","","","","","","","","","","","","","","","","","","","",""],"d":["A type wrapper that guarantees a given condition has been …","A condition variable that allows multiple Tasks to wait …","The closure type that can be used within a WaitCondition: …","","","","","This function should be invoked after the wait condition …","","","","","Create a new WaitCondition in which Tasks can wait for a …","Wake up a random Task that is waiting on this condition.","Wake up a specific Task that is waiting on this condition.","","","","","","","Waits for the condition to be true in a blocking fashion …"],"i":[0,0,0,1,2,1,2,1,1,2,1,2,1,2,2,1,2,1,2,1,2,1],"f":[null,null,null,[[]],[[]],[[]],[[]],[[],[["option",4],["satisfiedwaitcondition",3]]],[[]],[[]],[[]],[[]],[[],["waitcondition",3]],[[],["bool",15]],[[["taskref",3]],["bool",15]],[[],["result",4]],[[],["result",4]],[[],["result",4]],[[],["result",4]],[[],["typeid",3]],[[],["typeid",3]],[[],[["result",4],["waiterror",4]]]],"p":[[3,"WaitCondition"],[3,"SatisfiedWaitCondition"]]},\ "wait_queue":{"doc":"","t":[13,13,13,13,4,3,3,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11],"n":["Interrupted","NoCurrentTask","SpuriousWakeup","Timeout","WaitError","WaitGuard","WaitQueue","block_again","borrow","borrow","borrow","borrow_mut","borrow_mut","borrow_mut","drop","eq","fmt","from","from","from","into","into","into","new","new","notify_one","notify_specific","task","try_from","try_from","try_from","try_into","try_into","try_into","type_id","type_id","type_id","wait","wait_until","wait_until_mut","with_capacity"],"q":["wait_queue","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","",""],"d":["","","","","Errors that may occur while waiting on a …","An object that holds a blocked Task that will be …","A queue in which multiple Tasks can wait for other Tasks …","Blocks the task guarded by this waitguard, which is …","","","","","","","","","","","","","","","","Blocks the given Task and returns a new WaitGuard object …","Create a new empty WaitQueue.","Wake up one random Task that is waiting on this queue.","Wake up a specific Task that is waiting on this queue.","Returns a reference to the Task being blocked in this …","","","","","","","","","","Puts the current Task to sleep where it blocks on this …","Similar to wait, but this function blocks until the given …","Similar to wait_until, but this function accepts a …","Create a new empty WaitQueue."],"i":[1,1,1,1,0,0,0,2,2,3,1,2,3,1,2,1,1,2,3,1,2,3,1,2,3,3,3,2,2,3,1,2,3,1,2,3,1,3,3,3,3],"f":[null,null,null,null,null,null,null,[[]],[[]],[[]],[[]],[[]],[[]],[[]],[[]],[[["waiterror",4]],["bool",15]],[[["formatter",3]],["result",6]],[[]],[[]],[[]],[[]],[[]],[[]],[[["taskref",3]],["waitguard",3]],[[],["waitqueue",3]],[[],["bool",15]],[[["taskref",3]],["bool",15]],[[],["taskref",3]],[[],["result",4]],[[],["result",4]],[[],["result",4]],[[],["result",4]],[[],["result",4]],[[],["result",4]],[[],["typeid",3]],[[],["typeid",3]],[[],["typeid",3]],[[],[["waiterror",4],["result",4]]],[[["fn",8]],[["result",4],["waiterror",4]]],[[["fnmut",8]],[["result",4],["waiterror",4]]],[[["usize",15]],["waitqueue",3]]],"p":[[4,"WaitError"],[3,"WaitGuard"],[3,"WaitQueue"]]},\ +"wasi_interpreter":{"doc":"Interpreter for executing WASI-compliant WASM binaries.","t":[3,11,11,11,11,5,11,11,11,11,11,14,11,11,11],"n":["HostExternals","as_any","as_any_mut","borrow","borrow_mut","execute_binary","from","into","into_any","into_any_rc","invoke_index","sig","try_from","try_into","type_id"],"q":["wasi_interpreter","","","","","","","","","","","","","",""],"d":["Theseus and wasmi I/O required to execute WASI system …","","","","","Executes a WASI-compliant WebAssembly binary.","","","","","Function used by wasmi to invoke a system call given a …","Macro to efficiently generate wasmi function signature.","","",""],"i":[0,1,1,1,1,0,1,1,1,1,1,0,1,1,1],"f":[null,[[],["any",8]],[[],["any",8]],[[]],[[]],[[["string",3],["vec",3],["vec",3],["u8",15]],["isize",15]],[[]],[[]],[[["box",3],["global",3]],[["box",3],["any",8],["global",3]]],[[["rc",3]],[["any",8],["rc",3]]],[[["usize",15],["runtimeargs",3]],[["trap",3],["result",4],["option",4]]],null,[[],["result",4]],[[],["result",4]],[[],["typeid",3]]],"p":[[3,"HostExternals"]]},\ "window":{"doc":"A Window object should be owned by an application. It can …","t":[3,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11],"n":["Window","area","borrow","borrow_mut","drop","framebuffer","framebuffer_mut","from","handle_event","into","is_active","new","render","try_from","try_into","type_id"],"q":["window","","","","","","","","","","","","","","",""],"d":["This struct is the application-facing representation of a …","Returns a Rectangle describing the position and …","","","","Returns an immutable reference to this window’s virtual …","Returns a mutable reference to this window’s virtual …","","Tries to receive an Event that has been sent to this …","","Returns true if this window is the currently active …","Creates a new window to be displayed on screen. ","Renders the area of this Window specified by the given …","","",""],"i":[0,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1],"f":[null,[[],["rectangle",3]],[[]],[[]],[[]],[[],[["framebuffer",3],["mutexguardref",6],["windowinner",3]]],[[],[["framebuffer",3],["mutexguardrefmut",6],["windowinner",3]]],[[]],[[],[["str",15],["result",4],["option",4]]],[[]],[[],["bool",15]],[[["color",3],["usize",15],["coord",3]],[["str",15],["window",3],["result",4]]],[[["option",4],["rectangle",3]],[["result",4],["str",15]]],[[],["result",4]],[[],["result",4]],[[],["typeid",3]]],"p":[[3,"Window"]]},\ "window_inner":{"doc":"The WindowInner struct is the internal representation of …","t":[17,17,13,13,3,4,12,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,12,11,11,11,11,12,11,11,11,11,11,11],"n":["DEFAULT_BORDER_SIZE","DEFAULT_TITLE_BAR_HEIGHT","Moving","Stationary","WindowInner","WindowMovingStatus","border_size","borrow","borrow","borrow_mut","borrow_mut","contains","content_area","framebuffer","framebuffer_mut","from","from","get_border_size","get_pixel","get_position","get_size","get_title_bar_height","into","into","moving","new","resize","send_event","set_position","title_bar_height","try_from","try_from","try_into","try_into","type_id","type_id"],"q":["window_inner","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","",""],"d":["","","The window is currently in motion. The enclosed Coord …","The window is not in motion.","The WindowInner struct is the internal system-facing …","Whether a window is moving (being dragged by the mouse).","The width of the border in pixels. By default, there is a …","","","","","Returns true if the given coordinate (relative to the …","Returns the position and dimensions of the Window’s …","Returns an immutable reference to this window’s virtual …","Returns a mutable reference to this window’s virtual …","","","Returns the size of the Window border in pixels. There …","Returns the pixel value at the given coordinate, if the …","Gets the top-left position of the window relative to the …","Gets the size of a window in pixels","Returns the size of the Window title bar in pixels. …","","","Whether a window is moving or stationary.","Creates a new WindowInner object backed by the given …","Resizes and moves this window to fit the given Rectangle …","Sends the given event to this window.","Sets the top-left position of the window relative to the …","The height of title bar in pixels. By default, there is …","","","","","",""],"i":[0,0,1,1,0,0,2,1,2,1,2,2,2,2,2,1,2,2,2,2,2,2,1,2,2,2,2,2,2,2,1,2,1,2,1,2],"f":[null,null,null,null,null,null,null,[[]],[[]],[[]],[[]],[[["coord",3]],["bool",15]],[[],["rectangle",3]],[[],["framebuffer",3]],[[],["framebuffer",3]],[[]],[[]],[[],["usize",15]],[[["coord",3]],[["option",4],["alphapixel",3]]],[[],["coord",3]],[[]],[[],["usize",15]],[[]],[[]],null,[[["queue",3],["alphapixel",3],["framebuffer",3],["coord",3],["event",4]],["windowinner",3]],[[["rectangle",3]],[["result",4],["str",15]]],[[["event",4]],[["event",4],["result",4]]],[[["coord",3]]],null,[[],["result",4]],[[],["result",4]],[[],["result",4]],[[],["result",4]],[[],["typeid",3]],[[],["typeid",3]]],"p":[[4,"WindowMovingStatus"],[3,"WindowInner"]]},\ "window_manager":{"doc":"This crate acts as a manager of a list of windows. It …","t":[7,3,11,11,11,12,11,11,5,11,11,11,11,11,11,11,11,11,11,11,11,11],"n":["WINDOW_MANAGER","WindowManager","borrow","borrow_mut","delete_window","final_fb","from","get_screen_size","init","into","is_active","move_active_window","move_floating_border","refresh_active_window","refresh_bottom_windows","refresh_mouse","refresh_top","refresh_windows","set_active","try_from","try_into","type_id"],"q":["window_manager","","","","","","","","","","","","","","","","","","","","",""],"d":["The instance of the default window manager","Window manager structure which maintains a list of …","","","delete a window and refresh its region","The final framebuffer which is mapped to the screen (the …","","Returns the (width, height) in pixels of the screen …","Initialize the window manager. It returns …","","Returns true if the given window is the currently active …","take active window’s base position and current mouse, …","Move the floating border when a window is moving.","Refresh the part in bounding_box of the active window. …","Refresh the region in bounding_box. Only render the …","Refresh the mouse display","Refresh the region of bounding_box in the top framebuffer","Refresh the part in bounding_box of every window. …","Sets one window as active, push last active (if exists) …","","",""],"i":[0,0,1,1,1,1,1,1,0,1,1,1,1,1,1,1,1,1,1,1,1,1],"f":[null,null,[[]],[[]],[[["arc",3]],[["result",4],["str",15]]],null,[[]],[[]],[[],[["str",15],["result",4]]],[[]],[[["arc",3]],["bool",15]],[[],[["result",4],["str",15]]],[[],[["result",4],["str",15]]],[[["option",4],["rectangle",3]],[["result",4],["str",15]]],[[["bool",15]],[["result",4],["str",15]]],[[],[["result",4],["str",15]]],[[],[["result",4],["str",15]]],[[],[["result",4],["str",15]]],[[["bool",15],["arc",3]],[["str",15],["result",4],["bool",15]]],[[],["result",4]],[[],["result",4]],[[],["typeid",3]]],"p":[[3,"WindowManager"]]}\ diff --git a/doc/source-files.js b/doc/source-files.js index e9ddee28b0..2b2a24ae5d 100644 --- a/doc/source-files.js +++ b/doc/source-files.js @@ -155,6 +155,7 @@ sourcesIndex["vga_buffer"] = {"name":"","files":["lib.rs"]}; sourcesIndex["virtual_nic"] = {"name":"","files":["lib.rs"]}; sourcesIndex["wait_condition"] = {"name":"","files":["lib.rs"]}; sourcesIndex["wait_queue"] = {"name":"","files":["lib.rs"]}; +sourcesIndex["wasi_interpreter"] = {"name":"","files":["lib.rs","posix_file_system.rs","wasi_definitions.rs","wasi_syscalls.rs","wasmi_state_machine.rs"]}; sourcesIndex["window"] = {"name":"","files":["lib.rs"]}; sourcesIndex["window_inner"] = {"name":"","files":["lib.rs"]}; sourcesIndex["window_manager"] = {"name":"","files":["lib.rs"]}; diff --git a/doc/src/wasi_interpreter/lib.rs.html b/doc/src/wasi_interpreter/lib.rs.html new file mode 100644 index 0000000000..0d06106260 --- /dev/null +++ b/doc/src/wasi_interpreter/lib.rs.html @@ -0,0 +1,319 @@ +lib.rs - source + +
  1
+  2
+  3
+  4
+  5
+  6
+  7
+  8
+  9
+ 10
+ 11
+ 12
+ 13
+ 14
+ 15
+ 16
+ 17
+ 18
+ 19
+ 20
+ 21
+ 22
+ 23
+ 24
+ 25
+ 26
+ 27
+ 28
+ 29
+ 30
+ 31
+ 32
+ 33
+ 34
+ 35
+ 36
+ 37
+ 38
+ 39
+ 40
+ 41
+ 42
+ 43
+ 44
+ 45
+ 46
+ 47
+ 48
+ 49
+ 50
+ 51
+ 52
+ 53
+ 54
+ 55
+ 56
+ 57
+ 58
+ 59
+ 60
+ 61
+ 62
+ 63
+ 64
+ 65
+ 66
+ 67
+ 68
+ 69
+ 70
+ 71
+ 72
+ 73
+ 74
+ 75
+ 76
+ 77
+ 78
+ 79
+ 80
+ 81
+ 82
+ 83
+ 84
+ 85
+ 86
+ 87
+ 88
+ 89
+ 90
+ 91
+ 92
+ 93
+ 94
+ 95
+ 96
+ 97
+ 98
+ 99
+100
+101
+102
+103
+104
+105
+106
+107
+108
+109
+110
+111
+112
+113
+114
+115
+116
+117
+118
+119
+120
+121
+122
+123
+124
+125
+126
+127
+128
+129
+130
+131
+132
+133
+134
+135
+136
+137
+138
+139
+140
+141
+142
+143
+144
+145
+146
+147
+148
+149
+150
+151
+152
+153
+154
+155
+156
+
+//! Interpreter for executing WASI-compliant WASM binaries.
+//!
+//! `wasi_interpreter` provides an interface between the `wasmi` crate (used to interpret
+//! WebAssembly) and Theseus under the assumption of a WASI interface.
+//!
+//! This library exposes a public method called `execute_binary` to allow for the execution of a
+//! WebAssembly binary given directory permissions (in accordance to the WASI capabilities model)
+//! and arguments.
+//!
+//! This library depends on the following modules:
+//! * wasi_definitions
+//! * wasi_syscalls
+//! * posix_file_system
+//! * wasmi_state_machine
+//!
+
+#![no_std]
+
+#[macro_use]
+mod wasi_definitions;
+mod posix_file_system;
+mod wasi_syscalls;
+mod wasmi_state_machine;
+
+#[macro_use]
+extern crate alloc;
+extern crate app_io;
+extern crate core2;
+extern crate fs_node;
+extern crate root;
+extern crate task;
+extern crate wasmi;
+
+use alloc::string::String;
+use alloc::sync::Arc;
+use alloc::vec::Vec;
+use core::convert::TryFrom;
+use core::str::FromStr;
+use posix_file_system::FileDescriptorTable;
+use wasi_definitions::SystemCall;
+use wasmi::{Externals, MemoryRef, Module, RuntimeArgs, RuntimeValue, Signature, Trap, ValueType};
+
+/// Theseus and wasmi I/O required to execute WASI system calls.
+pub struct HostExternals {
+    /// WebAssembly memory buffer provided by wasmi.
+    memory: Option<MemoryRef>,
+    /// Exit code returned WebAssembly binary.
+    exit_code: wasi::Exitcode,
+    /// POSIX-style file descriptor table abstraction for interacting with Theseus I/O.
+    fd_table: FileDescriptorTable,
+    /// POSIX-formatted environment variables provided by Theseus.
+    /// (i.e. KEY=VALUE)
+    theseus_env_vars: Vec<String>,
+    /// POSIX-formatted arguments.
+    /// (i.e. PROGRAM_NAME arg1 arg2 ...)
+    theseus_args: Vec<String>,
+}
+
+impl Externals for HostExternals {
+    /// Function used by wasmi to invoke a system call given a specified system call number and
+    /// wasm arguments.
+    fn invoke_index(
+        &mut self,
+        index: usize,
+        wasmi_args: RuntimeArgs,
+    ) -> Result<Option<RuntimeValue>, Trap> {
+        wasi_syscalls::execute_system_call(SystemCall::try_from(index).unwrap(), self, wasmi_args)
+    }
+}
+
+/// Executes a WASI-compliant WebAssembly binary.
+///
+/// This function constructs a wasmi state machine from a WebAssembly binary, constructs a
+/// HostExternals object consisting of any necessary Theseus or wasmi I/O, opens file descriptors
+/// for accessible directories, and executes.
+///
+/// # Arguments
+/// * `wasm_binary`: a WASI-compliant WebAssembly binary as a byte vector
+/// * `args`: a POSIX-formatted string vector of arguments to WebAssembly binary
+/// * `preopen_dirs`: a string vector of directory paths to grant WASI access to
+///
+pub fn execute_binary(wasm_binary: Vec<u8>, args: Vec<String>, preopen_dirs: Vec<String>) -> isize {
+    // Load wasm binary and prepare it for instantiation.
+    let module = Module::from_buffer(&wasm_binary).unwrap();
+
+    // Construct wasmi WebAssembly state machine.
+    let state_machine = wasmi_state_machine::ProcessStateMachine::new(
+        &module,
+        |wasm_interface: &str, fn_name: &str, fn_signature: &Signature| -> Result<usize, ()> {
+            // Match WebAssembly function import to corresponding system call number.
+            // Currently supports `wasi_snapshot_preview1`.
+            if wasm_interface.eq("wasi_snapshot_preview1") {
+                let system_call = SystemCall::from_str(fn_name)
+                    .expect(&format!("Unknown WASI function {}", fn_name));
+                // Verify that signature of system call matches expected signature.
+                if fn_signature.eq(&system_call.into()) {
+                    return Ok(system_call.into());
+                }
+            }
+            Err(())
+        },
+    )
+    .unwrap();
+
+    // Populate environment variables.
+    let pwd: String = task::get_my_current_task()
+        .unwrap()
+        .get_env()
+        .lock()
+        .get_wd_path();
+
+    let mut theseus_env_vars: Vec<String> = Vec::new();
+    theseus_env_vars.push(format!("PWD={}", pwd));
+
+    // Construct initial host externals.
+    let mut ext: HostExternals = HostExternals {
+        memory: state_machine.memory,
+        exit_code: 0,
+        fd_table: FileDescriptorTable::new(),
+        theseus_env_vars: theseus_env_vars,
+        theseus_args: args,
+    };
+
+    // Open permitted directories in file descriptor table prior to execution.
+    // NOTE: WASI relies on an assumption that all preopened directories occupy the lowest possible
+    // file descriptors (3, 4, ...). The `open_path` function below conforms to this standard.
+    for preopen_dir in preopen_dirs.iter() {
+        let _curr_fd: wasi::Fd = ext
+            .fd_table
+            .open_path(
+                &preopen_dir,
+                Arc::clone(
+                    &task::get_my_current_task()
+                        .unwrap()
+                        .get_env()
+                        .lock()
+                        .working_dir,
+                ),
+                wasi::LOOKUPFLAGS_SYMLINK_FOLLOW,
+                wasi::OFLAGS_DIRECTORY,
+                wasi_definitions::FULL_DIR_RIGHTS,
+                wasi_definitions::FULL_FILE_RIGHTS | wasi_definitions::FULL_DIR_RIGHTS,
+                0,
+            )
+            .unwrap();
+    }
+
+    // Execute WebAssembly binary.
+    state_machine
+        .module
+        .invoke_export("_start", &[], &mut ext)
+        .ok();
+
+    // Return resulting WebAssembly exit code.
+    isize::try_from(ext.exit_code).unwrap()
+}
+
+
+ \ No newline at end of file diff --git a/doc/src/wasi_interpreter/posix_file_system.rs.html b/doc/src/wasi_interpreter/posix_file_system.rs.html new file mode 100644 index 0000000000..73b3d48073 --- /dev/null +++ b/doc/src/wasi_interpreter/posix_file_system.rs.html @@ -0,0 +1,1013 @@ +posix_file_system.rs - source + +
  1
+  2
+  3
+  4
+  5
+  6
+  7
+  8
+  9
+ 10
+ 11
+ 12
+ 13
+ 14
+ 15
+ 16
+ 17
+ 18
+ 19
+ 20
+ 21
+ 22
+ 23
+ 24
+ 25
+ 26
+ 27
+ 28
+ 29
+ 30
+ 31
+ 32
+ 33
+ 34
+ 35
+ 36
+ 37
+ 38
+ 39
+ 40
+ 41
+ 42
+ 43
+ 44
+ 45
+ 46
+ 47
+ 48
+ 49
+ 50
+ 51
+ 52
+ 53
+ 54
+ 55
+ 56
+ 57
+ 58
+ 59
+ 60
+ 61
+ 62
+ 63
+ 64
+ 65
+ 66
+ 67
+ 68
+ 69
+ 70
+ 71
+ 72
+ 73
+ 74
+ 75
+ 76
+ 77
+ 78
+ 79
+ 80
+ 81
+ 82
+ 83
+ 84
+ 85
+ 86
+ 87
+ 88
+ 89
+ 90
+ 91
+ 92
+ 93
+ 94
+ 95
+ 96
+ 97
+ 98
+ 99
+100
+101
+102
+103
+104
+105
+106
+107
+108
+109
+110
+111
+112
+113
+114
+115
+116
+117
+118
+119
+120
+121
+122
+123
+124
+125
+126
+127
+128
+129
+130
+131
+132
+133
+134
+135
+136
+137
+138
+139
+140
+141
+142
+143
+144
+145
+146
+147
+148
+149
+150
+151
+152
+153
+154
+155
+156
+157
+158
+159
+160
+161
+162
+163
+164
+165
+166
+167
+168
+169
+170
+171
+172
+173
+174
+175
+176
+177
+178
+179
+180
+181
+182
+183
+184
+185
+186
+187
+188
+189
+190
+191
+192
+193
+194
+195
+196
+197
+198
+199
+200
+201
+202
+203
+204
+205
+206
+207
+208
+209
+210
+211
+212
+213
+214
+215
+216
+217
+218
+219
+220
+221
+222
+223
+224
+225
+226
+227
+228
+229
+230
+231
+232
+233
+234
+235
+236
+237
+238
+239
+240
+241
+242
+243
+244
+245
+246
+247
+248
+249
+250
+251
+252
+253
+254
+255
+256
+257
+258
+259
+260
+261
+262
+263
+264
+265
+266
+267
+268
+269
+270
+271
+272
+273
+274
+275
+276
+277
+278
+279
+280
+281
+282
+283
+284
+285
+286
+287
+288
+289
+290
+291
+292
+293
+294
+295
+296
+297
+298
+299
+300
+301
+302
+303
+304
+305
+306
+307
+308
+309
+310
+311
+312
+313
+314
+315
+316
+317
+318
+319
+320
+321
+322
+323
+324
+325
+326
+327
+328
+329
+330
+331
+332
+333
+334
+335
+336
+337
+338
+339
+340
+341
+342
+343
+344
+345
+346
+347
+348
+349
+350
+351
+352
+353
+354
+355
+356
+357
+358
+359
+360
+361
+362
+363
+364
+365
+366
+367
+368
+369
+370
+371
+372
+373
+374
+375
+376
+377
+378
+379
+380
+381
+382
+383
+384
+385
+386
+387
+388
+389
+390
+391
+392
+393
+394
+395
+396
+397
+398
+399
+400
+401
+402
+403
+404
+405
+406
+407
+408
+409
+410
+411
+412
+413
+414
+415
+416
+417
+418
+419
+420
+421
+422
+423
+424
+425
+426
+427
+428
+429
+430
+431
+432
+433
+434
+435
+436
+437
+438
+439
+440
+441
+442
+443
+444
+445
+446
+447
+448
+449
+450
+451
+452
+453
+454
+455
+456
+457
+458
+459
+460
+461
+462
+463
+464
+465
+466
+467
+468
+469
+470
+471
+472
+473
+474
+475
+476
+477
+478
+479
+480
+481
+482
+483
+484
+485
+486
+487
+488
+489
+490
+491
+492
+493
+494
+495
+496
+497
+498
+499
+500
+501
+502
+503
+
+//! Types for interacting with Theseus standard I/O and file system via POSIX-style abstraction.
+//!
+//! This module provides APIs to:
+//! * interact with a file descriptor table (open path, close fd, get underlying Theseus handle).
+//! * read, write, or seek a file system node or standard I/O
+//!
+//! This abstraction is necessary as WASI assumes a POSIX-style file descriptor table interface.
+//!
+
+use alloc::string::String;
+use alloc::vec::Vec;
+use core::{cmp, convert::TryFrom as _};
+use core2::io::{Read, Write};
+use fs_node::{DirRef, FileOrDir, FileRef, FsNode};
+use hashbrown::HashMap;
+use memfs::MemFile;
+use path::Path;
+
+const FIRST_NONRESERVED_FD: wasi::Fd = 3;
+
+/// File types that can be accessed through file descriptor table.
+pub enum PosixNodeOrStdio {
+    /// Standard input.
+    Stdin,
+    /// Standard output.
+    Stdout,
+    /// Standard error.
+    Stderr,
+    /// An underlying file system node.
+    Inode(PosixNode),
+}
+
+impl PosixNodeOrStdio {
+    /// Writes data from the given `buffer` to this file.
+    ///
+    /// The number of bytes written is dictated by the length of the given `buffer`.
+    ///
+    /// # Arguments
+    /// * `buffer`: the buffer from which data will be written.
+    ///
+    /// # Return
+    /// If successful, returns the number of bytes written to this file.
+    /// Otherwise, returns a wasi::Errno.
+    pub fn write(&mut self, buffer: &[u8]) -> Result<usize, wasi::Errno> {
+        match self {
+            PosixNodeOrStdio::Stdin => Err(wasi::ERRNO_NOTSUP),
+            PosixNodeOrStdio::Stdout => match app_io::stdout().unwrap().lock().write_all(buffer) {
+                Ok(_) => Ok(buffer.len()),
+                Err(_) => Err(wasi::ERRNO_IO),
+            },
+            PosixNodeOrStdio::Stderr => match app_io::stderr().unwrap().lock().write_all(buffer) {
+                Ok(_) => Ok(buffer.len()),
+                Err(_) => Err(wasi::ERRNO_IO),
+            },
+            PosixNodeOrStdio::Inode(posix_node) => posix_node.write(buffer),
+        }
+    }
+
+    /// Reads data from this file into the given `buffer`.
+    ///
+    /// The number of bytes read is dictated by the length of the given `buffer`.
+    ///
+    /// # Arguments
+    /// * `buffer`: the buffer into which the data will be read.
+    ///
+    /// # Return
+    /// If successful, returns the number of bytes read into this file.
+    /// Otherwise, returns a wasi::Errno.
+    pub fn read(&mut self, buffer: &mut [u8]) -> Result<usize, wasi::Errno> {
+        match self {
+            PosixNodeOrStdio::Stdin => match app_io::stdin().unwrap().lock().read(buffer) {
+                Ok(bytes_read) => Ok(bytes_read),
+                Err(_) => Err(wasi::ERRNO_IO),
+            },
+            PosixNodeOrStdio::Stdout => Err(wasi::ERRNO_NOTSUP),
+            PosixNodeOrStdio::Stderr => Err(wasi::ERRNO_NOTSUP),
+            PosixNodeOrStdio::Inode(posix_node) => posix_node.read(buffer),
+        }
+    }
+
+    /// Move the offset of this file.
+    ///
+    /// # Arguments
+    /// * `offset`: the number of bytes to move.
+    /// * `whence`: the base from which the offset is relative.
+    ///
+    /// # Return
+    /// If successful, returns the resulting offset of this file.
+    /// Otherwise, returns a wasi::Errno.
+    pub fn seek(
+        &mut self,
+        offset: wasi::Filedelta,
+        whence: wasi::Whence,
+    ) -> Result<usize, wasi::Errno> {
+        match self {
+            PosixNodeOrStdio::Stdin => Err(wasi::ERRNO_NOTSUP),
+            PosixNodeOrStdio::Stdout => Err(wasi::ERRNO_NOTSUP),
+            PosixNodeOrStdio::Stderr => Err(wasi::ERRNO_NOTSUP),
+            PosixNodeOrStdio::Inode(posix_node) => posix_node.seek(offset, whence),
+        }
+    }
+}
+
+/// A wrapper around Theseus FileOrDir to provide WASI-expected POSIX features.
+pub struct PosixNode {
+    /// Underlying Theseus FileOrDir.
+    pub theseus_file_or_dir: FileOrDir,
+    /// File system ights that apply to this file descriptor.
+    fs_rights_base: wasi::Rights,
+    /// Maximum set of rights applied to file descriptors opened through this file descriptor.
+    fs_rights_inheriting: wasi::Rights,
+    /// File descriptor flags.
+    /// NOTE: contains unused flags for synchornized I/O, non-blocking mode.
+    fs_flags: wasi::Fdflags,
+    /// Offset of this file descriptor.
+    offset: usize,
+}
+
+impl PosixNode {
+    /// Instantiates a new PosixNode.
+    ///
+    /// # Arguments
+    /// * `file_or_dir`: underlying Theseus FileOrDir.
+    /// * `fs_rights`: rights applying to this file descriptor.
+    /// * `fs_rights_inheriting`: rights applying to inherting file descriptors.
+    /// * `fs_flags`: file descriptor flags.
+    ///
+    /// # Return
+    /// Returns a PosixNode of a FileOrDir with specified permissions.
+    pub fn new(
+        file_or_dir: FileOrDir,
+        fs_rights_base: wasi::Rights,
+        fs_rights_inheriting: wasi::Rights,
+        fs_flags: wasi::Fdflags,
+    ) -> PosixNode {
+        PosixNode {
+            theseus_file_or_dir: file_or_dir,
+            fs_rights_base: fs_rights_base,
+            fs_rights_inheriting: fs_rights_inheriting,
+            fs_flags: fs_flags,
+            offset: 0,
+        }
+    }
+
+    /// Get path relative to working directory of this file descriptor.
+    ///
+    /// # Return
+    /// Returns relative path of file descriptor as a string.
+    pub fn get_relative_path(&self) -> String {
+        let absolute_path = Path::new(self.theseus_file_or_dir.get_absolute_path());
+        let wd_path = Path::new(
+            task::get_my_current_task()
+                .unwrap()
+                .get_env()
+                .lock()
+                .get_wd_path(),
+        );
+
+        let relative_path: Path = absolute_path.relative(&wd_path).unwrap();
+        String::from(relative_path)
+    }
+
+    /// Get file system rights of this file descriptor.
+    ///
+    /// # Return
+    /// Returns file system rights of this file descriptor.
+    pub fn fs_rights_base(&self) -> wasi::Rights {
+        self.fs_rights_base
+    }
+
+    /// Get inheriting file system rights of this file descriptor.
+    ///
+    /// # Return
+    /// Returns inheriting file system rights of this file descriptor.
+    pub fn fs_rights_inheriting(&self) -> wasi::Rights {
+        self.fs_rights_inheriting
+    }
+
+    /// Get file descriptor flags of this file descriptor.
+    ///
+    /// # Return
+    /// Returns file descriptor flags of this file descriptor.
+    pub fn fs_flags(&self) -> wasi::Fdflags {
+        self.fs_flags
+    }
+
+    /// Set file descriptor flags of this file descriptor if allowed.
+    ///
+    /// # Return
+    /// If successful, returns ().
+    /// Otherwise, returns a wasi::Errno.
+    pub fn set_fs_flags(&mut self, new_flags: wasi::Fdflags) -> Result<(), wasi::Errno> {
+        // Verify that file descriptor has right to set flags.
+        if self.fs_rights_base() & wasi::RIGHTS_FD_FDSTAT_SET_FLAGS == 0 {
+            return Err(wasi::ERRNO_ACCES);
+        }
+
+        self.fs_flags = new_flags;
+        Ok(())
+    }
+
+    /// Writes data from the given `buffer` to this file system node if allowed.
+    ///
+    /// The number of bytes written is dictated by the length of the given `buffer`.
+    ///
+    /// # Arguments
+    /// * `buffer`: the buffer from which data will be written.
+    ///
+    /// # Return
+    /// If successful, returns the number of bytes written to this file system node.
+    /// Otherwise, returns a wasi::Errno.
+    /// NOTE: Returns wasi::ERRNO_NOBUFS on Theseus file write error.
+    pub fn write(&mut self, buffer: &[u8]) -> Result<usize, wasi::Errno> {
+        // Verify that file descriptor has right to write.
+        if self.fs_rights_base() & wasi::RIGHTS_FD_WRITE == 0 {
+            return Err(wasi::ERRNO_ACCES);
+        }
+
+        match self.theseus_file_or_dir.clone() {
+            FileOrDir::File(file_ref) => {
+                // Check flags for append mode.
+                let is_append_mode: bool = (self.fs_flags() & wasi::FDFLAGS_APPEND) != 0;
+
+                if is_append_mode {
+                    // Write to end of file.
+                    let end_of_file_offset: usize = file_ref.lock().size();
+                    match file_ref.lock().write(buffer, end_of_file_offset) {
+                        Ok(bytes_written) => Ok(bytes_written),
+                        Err(_) => Err(wasi::ERRNO_NOBUFS),
+                    }
+                } else {
+                    // Write at offset of file and update offset.
+                    let offset = self.offset;
+                    match file_ref.lock().write(buffer, offset) {
+                        Ok(bytes_written) => {
+                            self.offset = self.offset.checked_add(bytes_written).unwrap();
+                            Ok(bytes_written)
+                        }
+                        Err(_) => Err(wasi::ERRNO_NOBUFS),
+                    }
+                }
+            }
+            FileOrDir::Dir { .. } => Err(wasi::ERRNO_ISDIR),
+        }
+    }
+
+    /// Reads data from this file system node into the given `buffer` if allowed.
+    ///
+    /// The number of bytes read is dictated by the length of the given `buffer`.
+    ///
+    /// # Arguments
+    /// * `buffer`: the buffer into which the data will be read.
+    ///
+    /// # Return
+    /// If successful, returns the number of bytes read into this file system node.
+    /// Otherwise, returns a wasi::Errno.
+    pub fn read(&mut self, buffer: &mut [u8]) -> Result<usize, wasi::Errno> {
+        // Verify that file descriptor has right to read.
+        if self.fs_rights_base() & wasi::RIGHTS_FD_READ == 0 {
+            return Err(wasi::ERRNO_ACCES);
+        }
+
+        match self.theseus_file_or_dir.clone() {
+            FileOrDir::File(file_ref) => {
+                // Read at offset of file and update offset.
+                let offset = self.offset;
+                match file_ref.lock().read(buffer, offset) {
+                    Ok(bytes_read) => {
+                        self.offset = self.offset.checked_add(bytes_read).unwrap();
+                        Ok(bytes_read)
+                    }
+                    Err(_) => Err(wasi::ERRNO_NOBUFS),
+                }
+            }
+            FileOrDir::Dir { .. } => Err(wasi::ERRNO_ISDIR),
+        }
+    }
+
+    /// Move the offset of this file system node.
+    ///
+    /// # Arguments
+    /// * `offset`: the number of bytes to move.
+    /// * `whence`: the base from which the offset is relative.
+    ///
+    /// # Return
+    /// If successful, returns the resulting offset of this file system node.
+    /// Otherwise, returns a wasi::Errno.
+    pub fn seek(
+        &mut self,
+        delta: wasi::Filedelta,
+        whence: wasi::Whence,
+    ) -> Result<usize, wasi::Errno> {
+        // Verify that file descriptor has right to seek.
+        if self.fs_rights_base() & wasi::RIGHTS_FD_SEEK == 0 {
+            return Err(wasi::ERRNO_ACCES);
+        }
+
+        match self.theseus_file_or_dir.clone() {
+            FileOrDir::File(file_ref) => {
+                let max_offset: usize = file_ref.lock().size();
+
+                let signed_to_file_offset = |x: i64| -> usize {
+                    cmp::min(usize::try_from(cmp::max(0, x)).unwrap(), max_offset)
+                };
+
+                let new_offset: usize = match whence {
+                    wasi::WHENCE_CUR => {
+                        signed_to_file_offset(i64::try_from(self.offset).unwrap() + delta)
+                    }
+                    wasi::WHENCE_END => {
+                        signed_to_file_offset(i64::try_from(max_offset).unwrap() + delta)
+                    }
+                    wasi::WHENCE_SET => signed_to_file_offset(delta),
+                    _ => {
+                        return Err(wasi::ERRNO_SPIPE);
+                    }
+                };
+
+                self.offset = new_offset;
+                Ok(new_offset)
+            }
+            FileOrDir::Dir { .. } => Err(wasi::ERRNO_ISDIR),
+        }
+    }
+}
+
+/// File descriptor table.
+pub struct FileDescriptorTable {
+    /// HashMap from file descriptor number to POSIX-style file.
+    fd_table: HashMap<wasi::Fd, PosixNodeOrStdio>,
+}
+
+impl FileDescriptorTable {
+    /// Instantiates a new FileDescriptorTable with stdio entries filled.
+    ///
+    /// # Returns
+    /// Returns a new FileDescriptorTable consisting of stdio entries.
+    pub fn new() -> FileDescriptorTable {
+        let mut fd_table = HashMap::new();
+        fd_table.insert(wasi::FD_STDIN, PosixNodeOrStdio::Stdin);
+        fd_table.insert(wasi::FD_STDOUT, PosixNodeOrStdio::Stdout);
+        fd_table.insert(wasi::FD_STDERR, PosixNodeOrStdio::Stderr);
+        FileDescriptorTable { fd_table: fd_table }
+    }
+
+    /// Open file or directory at path in accordance to given open flags and insert in fd table.
+    ///
+    /// # Arguments
+    /// * `path`: &str representing path of file or directory to open.
+    /// * `starting_dir`: Theseus directory from which to search path from.
+    /// * `lookup_flags`: flags determining behavior of path resolution.
+    /// * `open_flags`: flags determining behavior of opening a file or directory.
+    /// * `fs_rights`: rights applying to this file descriptor.
+    /// * `fs_rights_inheriting`: rights applying to inherting file descriptors.
+    /// * `fs_flags`: file descriptor flags.
+    ///
+    /// # Return
+    /// If successful, returns resulting file descriptor number.
+    /// Otherwise, returns a wasi::Errno.
+    pub fn open_path(
+        &mut self,
+        path: &str,
+        starting_dir: DirRef,
+        lookup_flags: wasi::Lookupflags,
+        open_flags: wasi::Oflags,
+        fs_rights_base: wasi::Rights,
+        fs_rights_inheriting: wasi::Rights,
+        fs_flags: wasi::Fdflags,
+    ) -> Result<wasi::Fd, wasi::Errno> {
+        // NOTE: https://docs.rs/wasi/0.9.0+wasi-snapshot-preview1/wasi/constant.LOOKUPFLAGS_SYMLINK_FOLLOW.html
+        // Unused as symlinks are currently not implemented.
+        let _symlink_follow: bool = (lookup_flags & wasi::LOOKUPFLAGS_SYMLINK_FOLLOW) != 0;
+
+        // Parse open flags.
+        let create_file_if_no_exist: bool = (open_flags & wasi::OFLAGS_CREAT) != 0;
+        let fail_if_not_dir: bool = (open_flags & wasi::OFLAGS_DIRECTORY) != 0;
+        let fail_if_file_exists: bool = (open_flags & wasi::OFLAGS_EXCL) != 0;
+        let truncate_file_to_size_zero: bool = (open_flags & wasi::OFLAGS_TRUNC) != 0;
+
+        // Find first unused file descriptor number.
+        // TODO: Potentially can implement a more efficient search data structure.
+        let mut fd: wasi::Fd = FIRST_NONRESERVED_FD;
+        while self.fd_table.contains_key(&fd) {
+            fd += 1;
+        }
+
+        // Split path into parent directory path and base path.
+        let file_path: Path = Path::new(String::from(path));
+        let mut file_path_tokens: Vec<&str> = file_path.components().collect();
+        file_path_tokens.truncate(file_path_tokens.len().saturating_sub(1));
+        let parent_dir_path: Path = Path::new(file_path_tokens.join("/"));
+        let base_name: &str = file_path.basename();
+        let base_path: Path = Path::new(String::from(base_name));
+
+        // Get parent directory.
+        let parent_dir: DirRef = match parent_dir_path.get(&starting_dir) {
+            Some(file_or_dir) => match file_or_dir {
+                FileOrDir::File { .. } => {
+                    return Err(wasi::ERRNO_NOENT);
+                }
+                FileOrDir::Dir(dir_ref) => dir_ref,
+            },
+            None => {
+                return Err(wasi::ERRNO_NOENT);
+            }
+        };
+
+        // Open file or directory at path in accordance to open flags.
+        let opened_file_or_dir: FileOrDir = match base_path.get(&parent_dir) {
+            Some(file_or_dir) => match file_or_dir {
+                FileOrDir::File { .. } => {
+                    if fail_if_file_exists {
+                        return Err(wasi::ERRNO_EXIST);
+                    } else if fail_if_not_dir {
+                        return Err(wasi::ERRNO_NOTDIR);
+                    } else {
+                        if truncate_file_to_size_zero {
+                            // HACK: Truncate file by overwriting file.
+                            let new_file: FileRef =
+                                MemFile::new(String::from(base_name), &parent_dir).unwrap();
+                            FileOrDir::File(new_file)
+                        } else {
+                            file_or_dir
+                        }
+                    }
+                }
+                FileOrDir::Dir { .. } => file_or_dir,
+            },
+            None => {
+                if create_file_if_no_exist {
+                    let new_file: FileRef =
+                        MemFile::new(String::from(base_name), &parent_dir).unwrap();
+                    FileOrDir::File(new_file)
+                } else {
+                    return Err(wasi::ERRNO_NOENT);
+                }
+            }
+        };
+
+        // Insert POSIX-style file in file descriptor table with given rights and flags.
+        self.fd_table.insert(
+            fd,
+            PosixNodeOrStdio::Inode(PosixNode::new(
+                opened_file_or_dir,
+                fs_rights_base,
+                fs_rights_inheriting,
+                fs_flags,
+            )),
+        );
+
+        Ok(fd)
+    }
+
+    /// Close a given file descriptor if not standard I/O.
+    ///
+    /// # Arguments
+    /// * `fd`: file descriptor number to be closed.
+    ///
+    /// # Return
+    /// If successful, returns ().
+    /// Otherwise, returns a wasi::Errno.
+    pub fn close_fd(&mut self, fd: wasi::Fd) -> Result<(), wasi::Errno> {
+        if self.fd_table.contains_key(&fd)
+            && fd != wasi::FD_STDIN
+            && fd != wasi::FD_STDOUT
+            && fd != wasi::FD_STDERR
+        {
+            self.fd_table.remove(&fd);
+            return Ok(());
+        }
+        Err(wasi::ERRNO_BADF)
+    }
+
+    /// Get POSIX-style file from file descriptor number.
+    ///
+    /// # Arguments
+    /// * `fd`: file descriptor number to access.
+    ///
+    /// # Return
+    /// Returns corresponding POSIX-style file if exists.
+    pub fn get_posix_node_or_stdio(&mut self, fd: wasi::Fd) -> Option<&mut PosixNodeOrStdio> {
+        self.fd_table.get_mut(&fd)
+    }
+
+    /// Get file system node from file descriptor number.
+    ///
+    /// This method makes it easier to access an underlying file system node from a fd number.
+    ///
+    /// # Arguments
+    /// * `fd`: file descriptor number to access.
+    ///
+    /// # Return
+    /// Returns corresponding file system node if exists.
+    pub fn get_posix_node(&mut self, fd: wasi::Fd) -> Option<&mut PosixNode> {
+        match self.get_posix_node_or_stdio(fd) {
+            Some(posix_node_or_stdio) => match posix_node_or_stdio {
+                PosixNodeOrStdio::Inode(posix_node) => Some(posix_node),
+                _ => None,
+            },
+            None => None,
+        }
+    }
+}
+
+
+ \ No newline at end of file diff --git a/doc/src/wasi_interpreter/wasi_definitions.rs.html b/doc/src/wasi_interpreter/wasi_definitions.rs.html new file mode 100644 index 0000000000..7cbe6e9065 --- /dev/null +++ b/doc/src/wasi_interpreter/wasi_definitions.rs.html @@ -0,0 +1,473 @@ +wasi_definitions.rs - source + +
  1
+  2
+  3
+  4
+  5
+  6
+  7
+  8
+  9
+ 10
+ 11
+ 12
+ 13
+ 14
+ 15
+ 16
+ 17
+ 18
+ 19
+ 20
+ 21
+ 22
+ 23
+ 24
+ 25
+ 26
+ 27
+ 28
+ 29
+ 30
+ 31
+ 32
+ 33
+ 34
+ 35
+ 36
+ 37
+ 38
+ 39
+ 40
+ 41
+ 42
+ 43
+ 44
+ 45
+ 46
+ 47
+ 48
+ 49
+ 50
+ 51
+ 52
+ 53
+ 54
+ 55
+ 56
+ 57
+ 58
+ 59
+ 60
+ 61
+ 62
+ 63
+ 64
+ 65
+ 66
+ 67
+ 68
+ 69
+ 70
+ 71
+ 72
+ 73
+ 74
+ 75
+ 76
+ 77
+ 78
+ 79
+ 80
+ 81
+ 82
+ 83
+ 84
+ 85
+ 86
+ 87
+ 88
+ 89
+ 90
+ 91
+ 92
+ 93
+ 94
+ 95
+ 96
+ 97
+ 98
+ 99
+100
+101
+102
+103
+104
+105
+106
+107
+108
+109
+110
+111
+112
+113
+114
+115
+116
+117
+118
+119
+120
+121
+122
+123
+124
+125
+126
+127
+128
+129
+130
+131
+132
+133
+134
+135
+136
+137
+138
+139
+140
+141
+142
+143
+144
+145
+146
+147
+148
+149
+150
+151
+152
+153
+154
+155
+156
+157
+158
+159
+160
+161
+162
+163
+164
+165
+166
+167
+168
+169
+170
+171
+172
+173
+174
+175
+176
+177
+178
+179
+180
+181
+182
+183
+184
+185
+186
+187
+188
+189
+190
+191
+192
+193
+194
+195
+196
+197
+198
+199
+200
+201
+202
+203
+204
+205
+206
+207
+208
+209
+210
+211
+212
+213
+214
+215
+216
+217
+218
+219
+220
+221
+222
+223
+224
+225
+226
+227
+228
+229
+230
+231
+232
+233
+
+//! WASI system call, signature, and permission definitions as well as mappings.
+//!
+//! This module contains the following:
+//! * Macros for easily defining wasmi function signatures.
+//! * SystemCall enum type consisting of supported system calls.
+//! * Mapping from system call string to SystemCall type.
+//! * Mapping between system call number and SystemCall type.
+//! * Mapping from SystemCall type to wasmi signature.
+//! * Definitions of WASI rights for full file and directory permissions.
+//!
+//! Signature macro from tomaka/redshirt:
+//! <https://github.com/tomaka/redshirt/blob/4df506f68821353a7fd67bb94c4223df6b683e1b/kernel/core/src/primitives.rs>
+//!
+
+use alloc::vec::Vec;
+use core::convert::TryFrom;
+use core::str::FromStr;
+use wasmi::{Signature, ValueType};
+
+/// Generates wasmi function signature.
+///
+/// # Arguments
+/// * `params`: function signature argument types.
+/// * `ret_ty`: function signature return type.
+///
+/// # Return
+/// Returns requested wasmi signature.
+pub fn get_signature(
+    params: impl Iterator<Item = ValueType>,
+    ret_ty: impl Into<Option<ValueType>>,
+) -> Signature {
+    wasmi::Signature::new(
+        params.map(wasmi::ValueType::from).collect::<Vec<_>>(),
+        ret_ty.into().map(wasmi::ValueType::from),
+    )
+}
+
+/// Macro to efficiently generate wasmi function signature.
+///
+/// Usage examples:
+///     sig!((I32))
+///     sig!((I32, I32)->I32)
+///
+#[macro_export]
+macro_rules! sig {
+    (($($p:ident),*)) => {{
+        let params = core::iter::empty();
+        $(let params = params.chain(core::iter::once(ValueType::$p));)*
+        $crate::wasi_definitions::get_signature(params, None)
+    }};
+    (($($p:ident),*) -> $ret:ident) => {{
+        let params = core::iter::empty();
+        $(let params = params.chain(core::iter::once(ValueType::$p));)*
+        $crate::wasi_definitions::get_signature(params, Some($crate::ValueType::$ret))
+    }};
+}
+
+/// WASI system calls that are currently supported.
+#[derive(Copy, Clone, Debug)]
+pub enum SystemCall {
+    ProcExit,
+    FdClose,
+    FdWrite,
+    FdSeek,
+    FdRead,
+    FdFdstatGet,
+    EnvironSizesGet,
+    EnvironGet,
+    FdPrestatGet,
+    FdPrestatDirName,
+    PathOpen,
+    FdFdstatSetFlags,
+    ArgsSizesGet,
+    ArgsGet,
+    ClockTimeGet,
+}
+
+impl FromStr for SystemCall {
+    type Err = &'static str;
+
+    /// Get SystemCall type from imported function name string.
+    ///
+    /// # Arguments:
+    /// * `fn_name`: system call string representation.
+    ///
+    /// # Return
+    /// Returns SystemCall enum corresponding to given system call string.
+    fn from_str(fn_name: &str) -> Result<Self, Self::Err> {
+        match fn_name {
+            "proc_exit" => Ok(SystemCall::ProcExit),
+            "fd_close" => Ok(SystemCall::FdClose),
+            "fd_write" => Ok(SystemCall::FdWrite),
+            "fd_seek" => Ok(SystemCall::FdSeek),
+            "fd_read" => Ok(SystemCall::FdRead),
+            "fd_fdstat_get" => Ok(SystemCall::FdFdstatGet),
+            "environ_sizes_get" => Ok(SystemCall::EnvironSizesGet),
+            "environ_get" => Ok(SystemCall::EnvironGet),
+            "fd_prestat_get" => Ok(SystemCall::FdPrestatGet),
+            "fd_prestat_dir_name" => Ok(SystemCall::FdPrestatDirName),
+            "path_open" => Ok(SystemCall::PathOpen),
+            "fd_fdstat_set_flags" => Ok(SystemCall::FdFdstatSetFlags),
+            "args_sizes_get" => Ok(SystemCall::ArgsSizesGet),
+            "args_get" => Ok(SystemCall::ArgsGet),
+            "clock_time_get" => Ok(SystemCall::ClockTimeGet),
+            _ => Err("Unknown WASI system call."),
+        }
+    }
+}
+
+impl TryFrom<usize> for SystemCall {
+    type Error = &'static str;
+
+    /// Get SystemCall type from system call number.
+    ///
+    /// # Arguments:
+    /// * `syscall_index`: system call number.
+    ///
+    /// # Return
+    /// Returns SystemCall enum corresponding to given system call number.
+    fn try_from(syscall_index: usize) -> Result<Self, Self::Error> {
+        match syscall_index {
+            0 => Ok(SystemCall::ProcExit),
+            1 => Ok(SystemCall::FdClose),
+            2 => Ok(SystemCall::FdWrite),
+            3 => Ok(SystemCall::FdSeek),
+            4 => Ok(SystemCall::FdRead),
+            5 => Ok(SystemCall::FdFdstatGet),
+            6 => Ok(SystemCall::EnvironSizesGet),
+            7 => Ok(SystemCall::EnvironGet),
+            8 => Ok(SystemCall::FdPrestatGet),
+            9 => Ok(SystemCall::FdPrestatDirName),
+            10 => Ok(SystemCall::PathOpen),
+            11 => Ok(SystemCall::FdFdstatSetFlags),
+            12 => Ok(SystemCall::ArgsSizesGet),
+            13 => Ok(SystemCall::ArgsGet),
+            14 => Ok(SystemCall::ClockTimeGet),
+            _ => Err("Unknown WASI system call."),
+        }
+    }
+}
+
+impl Into<usize> for SystemCall {
+    /// Get system call number from this SystemCall enum.
+    ///
+    /// # Return
+    /// Returns system call number of this SystemCall enum.
+    fn into(self) -> usize {
+        match self {
+            SystemCall::ProcExit => 0,
+            SystemCall::FdClose => 1,
+            SystemCall::FdWrite => 2,
+            SystemCall::FdSeek => 3,
+            SystemCall::FdRead => 4,
+            SystemCall::FdFdstatGet => 5,
+            SystemCall::EnvironSizesGet => 6,
+            SystemCall::EnvironGet => 7,
+            SystemCall::FdPrestatGet => 8,
+            SystemCall::FdPrestatDirName => 9,
+            SystemCall::PathOpen => 10,
+            SystemCall::FdFdstatSetFlags => 11,
+            SystemCall::ArgsSizesGet => 12,
+            SystemCall::ArgsGet => 13,
+            SystemCall::ClockTimeGet => 14,
+        }
+    }
+}
+
+impl Into<Signature> for SystemCall {
+    /// Get wasmi function signature of SystemCall enum.
+    ///
+    /// # Return
+    /// Returns wasmi function signature of this SystemCall enum.
+    fn into(self) -> Signature {
+        match self {
+            SystemCall::ProcExit => sig!((I32)),
+            SystemCall::FdClose => sig!((I32)->I32),
+            SystemCall::FdWrite => sig!((I32,I32,I32,I32)->I32),
+            SystemCall::FdSeek => sig!((I32,I64,I32,I32)->I32),
+            SystemCall::FdRead => sig!((I32,I32,I32,I32)->I32),
+            SystemCall::FdFdstatGet => sig!((I32,I32)->I32),
+            SystemCall::EnvironSizesGet => sig!((I32,I32)->I32),
+            SystemCall::EnvironGet => sig!((I32,I32)->I32),
+            SystemCall::FdPrestatGet => sig!((I32,I32)->I32),
+            SystemCall::FdPrestatDirName => sig!((I32,I32,I32)->I32),
+            SystemCall::PathOpen => sig!((I32,I32,I32,I32,I32,I64,I64,I32,I32)->I32),
+            SystemCall::FdFdstatSetFlags => sig!((I32,I32)->I32),
+            SystemCall::ArgsSizesGet => sig!((I32,I32)->I32),
+            SystemCall::ArgsGet => sig!((I32,I32)->I32),
+            SystemCall::ClockTimeGet => sig!((I32,I64,I32)->I32),
+        }
+    }
+}
+
+/// WASI rights of a directory with full permissions.
+pub const FULL_DIR_RIGHTS: wasi::Rights = wasi::RIGHTS_FD_FDSTAT_SET_FLAGS
+    | wasi::RIGHTS_FD_SYNC
+    | wasi::RIGHTS_FD_ADVISE
+    | wasi::RIGHTS_PATH_CREATE_DIRECTORY
+    | wasi::RIGHTS_PATH_CREATE_FILE
+    | wasi::RIGHTS_PATH_LINK_SOURCE
+    | wasi::RIGHTS_PATH_LINK_TARGET
+    | wasi::RIGHTS_PATH_OPEN
+    | wasi::RIGHTS_FD_READDIR
+    | wasi::RIGHTS_PATH_READLINK
+    | wasi::RIGHTS_PATH_RENAME_SOURCE
+    | wasi::RIGHTS_PATH_RENAME_TARGET
+    | wasi::RIGHTS_PATH_FILESTAT_GET
+    | wasi::RIGHTS_PATH_FILESTAT_SET_SIZE
+    | wasi::RIGHTS_PATH_FILESTAT_SET_TIMES
+    | wasi::RIGHTS_FD_FILESTAT_GET
+    | wasi::RIGHTS_FD_FILESTAT_SET_SIZE
+    | wasi::RIGHTS_FD_FILESTAT_SET_TIMES
+    | wasi::RIGHTS_PATH_SYMLINK
+    | wasi::RIGHTS_PATH_REMOVE_DIRECTORY
+    | wasi::RIGHTS_PATH_UNLINK_FILE
+    | wasi::RIGHTS_POLL_FD_READWRITE;
+
+/// WASI rights of a file with full permissions.
+pub const FULL_FILE_RIGHTS: wasi::Rights = wasi::RIGHTS_FD_DATASYNC
+    | wasi::RIGHTS_FD_READ
+    | wasi::RIGHTS_FD_SEEK
+    | wasi::RIGHTS_FD_FDSTAT_SET_FLAGS
+    | wasi::RIGHTS_FD_SYNC
+    | wasi::RIGHTS_FD_TELL
+    | wasi::RIGHTS_FD_WRITE
+    | wasi::RIGHTS_FD_ADVISE
+    | wasi::RIGHTS_FD_ALLOCATE
+    | wasi::RIGHTS_FD_FILESTAT_GET
+    | wasi::RIGHTS_FD_FILESTAT_SET_SIZE
+    | wasi::RIGHTS_FD_FILESTAT_SET_TIMES
+    | wasi::RIGHTS_POLL_FD_READWRITE
+    | wasi::RIGHTS_FD_FILESTAT_SET_TIMES
+    | wasi::RIGHTS_POLL_FD_READWRITE;
+
+
+ \ No newline at end of file diff --git a/doc/src/wasi_interpreter/wasi_syscalls.rs.html b/doc/src/wasi_interpreter/wasi_syscalls.rs.html new file mode 100644 index 0000000000..001f9c7ce9 --- /dev/null +++ b/doc/src/wasi_interpreter/wasi_syscalls.rs.html @@ -0,0 +1,1393 @@ +wasi_syscalls.rs - source + +
  1
+  2
+  3
+  4
+  5
+  6
+  7
+  8
+  9
+ 10
+ 11
+ 12
+ 13
+ 14
+ 15
+ 16
+ 17
+ 18
+ 19
+ 20
+ 21
+ 22
+ 23
+ 24
+ 25
+ 26
+ 27
+ 28
+ 29
+ 30
+ 31
+ 32
+ 33
+ 34
+ 35
+ 36
+ 37
+ 38
+ 39
+ 40
+ 41
+ 42
+ 43
+ 44
+ 45
+ 46
+ 47
+ 48
+ 49
+ 50
+ 51
+ 52
+ 53
+ 54
+ 55
+ 56
+ 57
+ 58
+ 59
+ 60
+ 61
+ 62
+ 63
+ 64
+ 65
+ 66
+ 67
+ 68
+ 69
+ 70
+ 71
+ 72
+ 73
+ 74
+ 75
+ 76
+ 77
+ 78
+ 79
+ 80
+ 81
+ 82
+ 83
+ 84
+ 85
+ 86
+ 87
+ 88
+ 89
+ 90
+ 91
+ 92
+ 93
+ 94
+ 95
+ 96
+ 97
+ 98
+ 99
+100
+101
+102
+103
+104
+105
+106
+107
+108
+109
+110
+111
+112
+113
+114
+115
+116
+117
+118
+119
+120
+121
+122
+123
+124
+125
+126
+127
+128
+129
+130
+131
+132
+133
+134
+135
+136
+137
+138
+139
+140
+141
+142
+143
+144
+145
+146
+147
+148
+149
+150
+151
+152
+153
+154
+155
+156
+157
+158
+159
+160
+161
+162
+163
+164
+165
+166
+167
+168
+169
+170
+171
+172
+173
+174
+175
+176
+177
+178
+179
+180
+181
+182
+183
+184
+185
+186
+187
+188
+189
+190
+191
+192
+193
+194
+195
+196
+197
+198
+199
+200
+201
+202
+203
+204
+205
+206
+207
+208
+209
+210
+211
+212
+213
+214
+215
+216
+217
+218
+219
+220
+221
+222
+223
+224
+225
+226
+227
+228
+229
+230
+231
+232
+233
+234
+235
+236
+237
+238
+239
+240
+241
+242
+243
+244
+245
+246
+247
+248
+249
+250
+251
+252
+253
+254
+255
+256
+257
+258
+259
+260
+261
+262
+263
+264
+265
+266
+267
+268
+269
+270
+271
+272
+273
+274
+275
+276
+277
+278
+279
+280
+281
+282
+283
+284
+285
+286
+287
+288
+289
+290
+291
+292
+293
+294
+295
+296
+297
+298
+299
+300
+301
+302
+303
+304
+305
+306
+307
+308
+309
+310
+311
+312
+313
+314
+315
+316
+317
+318
+319
+320
+321
+322
+323
+324
+325
+326
+327
+328
+329
+330
+331
+332
+333
+334
+335
+336
+337
+338
+339
+340
+341
+342
+343
+344
+345
+346
+347
+348
+349
+350
+351
+352
+353
+354
+355
+356
+357
+358
+359
+360
+361
+362
+363
+364
+365
+366
+367
+368
+369
+370
+371
+372
+373
+374
+375
+376
+377
+378
+379
+380
+381
+382
+383
+384
+385
+386
+387
+388
+389
+390
+391
+392
+393
+394
+395
+396
+397
+398
+399
+400
+401
+402
+403
+404
+405
+406
+407
+408
+409
+410
+411
+412
+413
+414
+415
+416
+417
+418
+419
+420
+421
+422
+423
+424
+425
+426
+427
+428
+429
+430
+431
+432
+433
+434
+435
+436
+437
+438
+439
+440
+441
+442
+443
+444
+445
+446
+447
+448
+449
+450
+451
+452
+453
+454
+455
+456
+457
+458
+459
+460
+461
+462
+463
+464
+465
+466
+467
+468
+469
+470
+471
+472
+473
+474
+475
+476
+477
+478
+479
+480
+481
+482
+483
+484
+485
+486
+487
+488
+489
+490
+491
+492
+493
+494
+495
+496
+497
+498
+499
+500
+501
+502
+503
+504
+505
+506
+507
+508
+509
+510
+511
+512
+513
+514
+515
+516
+517
+518
+519
+520
+521
+522
+523
+524
+525
+526
+527
+528
+529
+530
+531
+532
+533
+534
+535
+536
+537
+538
+539
+540
+541
+542
+543
+544
+545
+546
+547
+548
+549
+550
+551
+552
+553
+554
+555
+556
+557
+558
+559
+560
+561
+562
+563
+564
+565
+566
+567
+568
+569
+570
+571
+572
+573
+574
+575
+576
+577
+578
+579
+580
+581
+582
+583
+584
+585
+586
+587
+588
+589
+590
+591
+592
+593
+594
+595
+596
+597
+598
+599
+600
+601
+602
+603
+604
+605
+606
+607
+608
+609
+610
+611
+612
+613
+614
+615
+616
+617
+618
+619
+620
+621
+622
+623
+624
+625
+626
+627
+628
+629
+630
+631
+632
+633
+634
+635
+636
+637
+638
+639
+640
+641
+642
+643
+644
+645
+646
+647
+648
+649
+650
+651
+652
+653
+654
+655
+656
+657
+658
+659
+660
+661
+662
+663
+664
+665
+666
+667
+668
+669
+670
+671
+672
+673
+674
+675
+676
+677
+678
+679
+680
+681
+682
+683
+684
+685
+686
+687
+688
+689
+690
+691
+692
+693
+
+//! WASI system call implementations.
+//!
+//! This module implements system calls required by WASI. These system calls interact with wasmi
+//! memory and Theseus I/O (standard I/O, file system, arguments, environment variables, etc.).
+//!
+//! Documentation on system call behavior:
+//! <https://docs.rs/wasi/0.10.2+wasi-snapshot-preview1/wasi/index.html>
+//! <https://github.com/WebAssembly/wasi-libc/blob/ad5133410f66b93a2381db5b542aad5e0964db96/libc-bottom-half/headers/public/wasi/api.h>
+//!
+//! The WASI crate documentation is useful for understanding WASI crate types and for a high-level
+//! understanding of WASI standards. The wasi-lib.c API header is far more useful, however, for
+//! understanding implementation details such as exact arguments passed into WASI system calls.
+//!
+//! Inspiration for some implementations is borrowed from tomaka/redshirt:
+//! <https://github.com/tomaka/redshirt/blob/4df506f68821353a7fd67bb94c4223df6b683e1b/kernel/core/src/extrinsics/wasi.rs>
+//!
+
+use crate::posix_file_system::{PosixNode, PosixNodeOrStdio};
+use crate::wasi_definitions::SystemCall;
+use crate::HostExternals;
+use alloc::string::String;
+use alloc::vec::Vec;
+use core::convert::TryFrom as _;
+use fs_node::{DirRef, FileOrDir};
+use wasmi::{MemoryRef, RuntimeArgs, RuntimeValue, Trap};
+
+/// Helper function to support retrieving args/env sizes.
+///
+/// # Arguments
+/// * `list`: string vector of which size is being retrieved (args or env).
+/// * `argc_out`: pointer to store length of list.
+/// * `argv_buf_size_out`: pointer to store total length of data in list. This includes null
+/// terminating bytes used by strings.
+/// * `memory`: wasmi memory buffer.
+///
+/// # Return
+/// A WASI errno.
+fn args_or_env_sizes_get(
+    list: &Vec<String>,
+    argc_out: u32,
+    argv_buf_size_out: u32,
+    memory: &MemoryRef,
+) -> Result<Option<RuntimeValue>, Trap> {
+    // Compute length of list.
+    let argc: wasi::Size = list.len();
+    // Compute length of data within list.
+    let argv_buf_size: wasi::Size = list
+        .iter()
+        .fold(0, |s, a| s.saturating_add(a.len()).saturating_add(1));
+
+    // Write lengths to memory
+    memory.set(argc_out, &argc.to_le_bytes()).unwrap();
+    memory
+        .set(argv_buf_size_out, &argv_buf_size.to_le_bytes())
+        .unwrap();
+
+    return Ok(Some(RuntimeValue::I32(From::from(wasi::ERRNO_SUCCESS))));
+}
+
+/// Helper function to support retrieving args/env data.
+///
+/// # Arguments
+/// * `list`: string vector of which data is being retrieved (args or env).
+/// * `argv_pointers`: buffer to store pointers to each element in list.
+/// * `argv_data`: buffer to store data in list. This includes null terminating bytes for each
+/// element in list.
+/// * `memory`: wasmi memory buffer.
+///
+/// # Return
+/// A WASI errno.
+fn args_or_env_get(
+    list: &Vec<String>,
+    argv_pointers: u32,
+    argv_data: u32,
+    memory: &MemoryRef,
+) -> Result<Option<RuntimeValue>, Trap> {
+    let mut argv_pointers_pos: u32 = 0;
+    let mut argv_data_pos: u32 = 0;
+
+    for arg in list.iter() {
+        let arg = arg.as_bytes();
+
+        // Write pointer to current arg to argv_pointers buffer.
+        memory
+            .set(
+                argv_pointers.checked_add(argv_pointers_pos).unwrap(),
+                &(argv_data.checked_add(argv_data_pos).unwrap()).to_le_bytes(),
+            )
+            .unwrap();
+        argv_pointers_pos = argv_pointers_pos.checked_add(4).unwrap();
+
+        // Write content of current arg to argv_data buffer.
+        memory
+            .set(argv_data.checked_add(argv_data_pos).unwrap(), &arg)
+            .unwrap();
+        argv_data_pos = argv_data_pos
+            .checked_add(u32::try_from(arg.len()).unwrap())
+            .unwrap();
+
+        // Write null terminating byte to argv_data buffer.
+        memory
+            .set(argv_data.checked_add(argv_data_pos).unwrap(), &[0])
+            .unwrap();
+        argv_data_pos = argv_data_pos.checked_add(1).unwrap();
+    }
+
+    return Ok(Some(RuntimeValue::I32(From::from(wasi::ERRNO_SUCCESS))));
+}
+
+/// Executes specified system calls by interacting with wasmi memory and Theseus I/O.
+///
+/// # Arguments
+/// * `system_call`: SystemCall enum specifying which system call to execute.
+/// * `h_ext`: object containing wasmi memory and Theseus I/O.
+/// * `wasmi_args`: system call arguments.
+///
+/// # Return
+/// Returns result of wasmi RuntimeValue on success or wasmi Trap on error used by wasmi to
+/// continue binary execution.
+pub fn execute_system_call(
+    system_call: SystemCall,
+    h_ext: &mut HostExternals,
+    wasmi_args: RuntimeArgs,
+) -> Result<Option<RuntimeValue>, Trap> {
+    // Handles to wasmi memory and Theseus I/O.
+    let ref mut memory = match h_ext.memory {
+        Some(ref mut mem) => mem,
+        None => {
+            return Ok(Some(RuntimeValue::I32(From::from(wasi::ERRNO_NOMEM))));
+        }
+    };
+    let ref mut fd_table = h_ext.fd_table;
+    let ref theseus_env_vars = h_ext.theseus_env_vars;
+    let ref theseus_args = h_ext.theseus_args;
+
+    match system_call {
+        // Terminate process with given exit code.
+        //
+        // # Arguments
+        // * `exit_code`: the exit code being returned by the process.
+        //
+        // # Return
+        // None.
+        SystemCall::ProcExit => {
+            let exit_code: wasi::Exitcode = wasmi_args.nth_checked(0)?;
+            h_ext.exit_code = exit_code;
+            Ok(None)
+        }
+
+        // Close a file descriptor. This is similar to close in POSIX.
+        //
+        // # Arguments
+        // * `fd`: the file descriptor number to close.
+        //
+        // # Return
+        // A WASI errno.
+        SystemCall::FdClose => {
+            let fd: wasi::Fd = wasmi_args.nth_checked(0).unwrap();
+            match fd_table.close_fd(fd) {
+                Ok(_) => Ok(Some(RuntimeValue::I32(From::from(wasi::ERRNO_SUCCESS)))),
+                Err(wasi_error) => Ok(Some(RuntimeValue::I32(From::from(wasi_error)))),
+            }
+        }
+
+        // Write to a file descriptor. This is similar to writev in POSIX.
+        //
+        // # Arguments
+        // * `fd`: the file descriptor number to write to.
+        // * `iovs`: pointer to list of scatter/gather vectors from which to retrieve data. each
+        // element in list consists of a 32 bit pointer to a data vector and a 32 bit length
+        // associated with that data vector (8 bytes).
+        // * `iovs_len`: the length of the array pointed to by `iovs`.
+        // * `ret_ptr`: pointer to write number of bytes written to.
+        //
+        // # Return
+        // A WASI errno.
+        SystemCall::FdWrite => {
+            // Fetch file to write to.
+            let posix_node_or_stdio: &mut PosixNodeOrStdio = {
+                let fd: wasi::Fd = wasmi_args.nth_checked(0).unwrap();
+                match fd_table.get_posix_node_or_stdio(fd) {
+                    Some(pn) => pn,
+                    None => {
+                        return Ok(Some(RuntimeValue::I32(From::from(wasi::ERRNO_BADF))));
+                    }
+                }
+            };
+
+            let iovs: u32 = wasmi_args.nth_checked(1).unwrap();
+            let iovs_len: wasi::Size = {
+                let len: u32 = wasmi_args.nth_checked(2).unwrap();
+                wasi::Size::try_from(len).unwrap()
+            };
+
+            // convert iovs into vector of (ptr,len) pairs.
+            let data_pointers = memory.get(iovs, 4 * iovs_len * 2);
+            let mut data_out = Vec::with_capacity(iovs_len * 2);
+
+            for elt in data_pointers.unwrap().chunks(4) {
+                data_out.push(u32::from_le_bytes(<[u8; 4]>::try_from(elt).unwrap()));
+            }
+
+            let mut total_written: usize = 0;
+
+            for ptr_and_len in data_out.chunks(2) {
+                let ptr: u32 = ptr_and_len[0];
+                let len: wasi::Size = wasi::Size::try_from(ptr_and_len[1]).unwrap();
+
+                // retrieve data to write.
+                let char_arr = memory.get(ptr, len).unwrap();
+
+                let bytes_written: wasi::Size = match posix_node_or_stdio.write(&char_arr) {
+                    Ok(bytes_written) => bytes_written,
+                    Err(wasi_errno) => {
+                        return Ok(Some(RuntimeValue::I32(From::from(wasi_errno))));
+                    }
+                };
+                total_written = total_written.checked_add(bytes_written).unwrap();
+            }
+
+            // write bytes written to return pointer.
+            let ret_ptr: u32 = wasmi_args.nth_checked(3).unwrap();
+            memory.set(ret_ptr, &total_written.to_le_bytes()).unwrap();
+            return Ok(Some(RuntimeValue::I32(From::from(wasi::ERRNO_SUCCESS))));
+        }
+
+        // Move the offset of a file descriptor. This is similar to lseek in POSIX.
+        //
+        // # Arguments
+        // * `fd`: the file descriptor number to seek.
+        // * `offset`: the number of bytes to move.
+        // * `whence`: the base from which the offset is relative.
+        // * `ret_ptr`: pointer to write new offset to.
+        //
+        // # Return
+        // A WASI errno.
+        SystemCall::FdSeek => {
+            // fetch file to seek.
+            let posix_node_or_stdio: &mut PosixNodeOrStdio = {
+                let fd: wasi::Fd = wasmi_args.nth_checked(0).unwrap();
+                match fd_table.get_posix_node_or_stdio(fd) {
+                    Some(pn) => pn,
+                    None => {
+                        return Ok(Some(RuntimeValue::I32(From::from(wasi::ERRNO_BADF))));
+                    }
+                }
+            };
+
+            let offset: wasi::Filedelta = wasmi_args.nth_checked(1).unwrap();
+            let whence: wasi::Whence = wasmi_args.nth_checked(2).unwrap();
+
+            // move offset.
+            let new_offset: wasi::Filesize = match posix_node_or_stdio.seek(offset, whence) {
+                Ok(new_offset) => wasi::Filesize::try_from(new_offset).unwrap(),
+                Err(wasi_errno) => {
+                    return Ok(Some(RuntimeValue::I32(From::from(wasi_errno))));
+                }
+            };
+
+            // write new offset to return pointer.
+            let ret_ptr: u32 = wasmi_args.nth_checked(3).unwrap();
+            memory.set(ret_ptr, &new_offset.to_le_bytes()).unwrap();
+            return Ok(Some(RuntimeValue::I32(From::from(wasi::ERRNO_SUCCESS))));
+        }
+
+        // Read from a file descriptor. This is similar to readv in POSIX.
+        //
+        // # Arguments
+        // * `fd`: the file descriptor number to read from.
+        // * `iovs`: pointer to list of scatter/gather vectors to which to store data. each element
+        // in list consists of a 32 bit pointer to a data vector and a 32 bit length associated with
+        // that data vector (8 bytes).
+        // * `iovs_len`: the length of the array pointed to by `iovs`.
+        // * `ret_ptr`: pointer to write number of bytes read from.
+        //
+        // # Return
+        // A WASI errno.
+        SystemCall::FdRead => {
+            // fetch file to read from.
+            let posix_node_or_stdio: &mut PosixNodeOrStdio = {
+                let fd: wasi::Fd = wasmi_args.nth_checked(0).unwrap();
+                match fd_table.get_posix_node_or_stdio(fd) {
+                    Some(pn) => pn,
+                    None => {
+                        return Ok(Some(RuntimeValue::I32(From::from(wasi::ERRNO_BADF))));
+                    }
+                }
+            };
+
+            let iovs: u32 = wasmi_args.nth_checked(1).unwrap();
+            let iovs_len: wasi::Size = {
+                let len: u32 = wasmi_args.nth_checked(2).unwrap();
+                wasi::Size::try_from(len).unwrap()
+            };
+
+            // convert iovs into vector of (ptr,len) pairs.
+            let input_pointers = memory.get(iovs, 4 * iovs_len * 2);
+            let mut data_in = Vec::with_capacity(iovs_len * 2);
+
+            for elt in input_pointers.unwrap().chunks(4) {
+                data_in.push(u32::from_le_bytes(<[u8; 4]>::try_from(elt).unwrap()));
+            }
+
+            let mut total_read: wasi::Size = 0;
+
+            for ptr_and_len in data_in.chunks(2) {
+                let ptr: u32 = ptr_and_len[0];
+                let len: wasi::Size = wasi::Size::try_from(ptr_and_len[1]).unwrap();
+
+                let ref mut read_buf = vec![0; len];
+
+                // retrieve data to read.
+                let bytes_read: wasi::Size = match posix_node_or_stdio.read(read_buf) {
+                    Ok(bytes_written) => bytes_written,
+                    Err(wasi_errno) => {
+                        return Ok(Some(RuntimeValue::I32(From::from(wasi_errno))));
+                    }
+                };
+
+                memory.set(ptr, &read_buf[0..bytes_read]).unwrap();
+                total_read = total_read.checked_add(bytes_read).unwrap();
+            }
+
+            // write bytes read to return pointer.
+            let ret_ptr: u32 = wasmi_args.nth_checked(3).unwrap();
+            memory.set(ret_ptr, &total_read.to_le_bytes()).unwrap();
+            return Ok(Some(RuntimeValue::I32(From::from(wasi::ERRNO_SUCCESS))));
+        }
+
+        // Get the attributes of a file descriptor.
+        // This returns similar flags to fsync(fd, F_GETFL) in POSIX.
+        //
+        // # Arguments
+        // * `fd`: the file descriptor number to get attributes of.
+        // * `stat_buf`: the buffer to store file descriptor's attributes.
+        //
+        // # Return
+        // A WASI errno.
+        SystemCall::FdFdstatGet => {
+            // fetch file system node to retrieve attributes from.
+            let posix_node: &mut PosixNode = {
+                let fd: wasi::Fd = wasmi_args.nth_checked(0).unwrap();
+                match fd_table.get_posix_node(fd) {
+                    Some(pn) => pn,
+                    None => {
+                        return Ok(Some(RuntimeValue::I32(From::from(wasi::ERRNO_BADF))));
+                    }
+                }
+            };
+
+            // fetch attributes.
+            let stat: wasi::Fdstat = match posix_node.theseus_file_or_dir {
+                FileOrDir::Dir { .. } => wasi::Fdstat {
+                    fs_filetype: wasi::FILETYPE_DIRECTORY,
+                    fs_flags: posix_node.fs_flags(),
+                    fs_rights_base: posix_node.fs_rights_base(),
+                    fs_rights_inheriting: posix_node.fs_rights_inheriting(),
+                },
+                FileOrDir::File { .. } => wasi::Fdstat {
+                    fs_filetype: wasi::FILETYPE_REGULAR_FILE,
+                    fs_flags: posix_node.fs_flags(),
+                    fs_rights_base: posix_node.fs_rights_base(),
+                    fs_rights_inheriting: posix_node.fs_rights_inheriting(),
+                },
+            };
+
+            let stat_buf: u32 = wasmi_args.nth_checked(1).unwrap();
+
+            // write attributes to stat_buf.
+            memory.set(stat_buf, &[0; 24]).unwrap();
+            memory.set(stat_buf, &[stat.fs_filetype]).unwrap();
+            memory
+                .set(
+                    stat_buf.checked_add(2).unwrap(),
+                    &stat.fs_flags.to_le_bytes(),
+                )
+                .unwrap();
+            memory
+                .set(
+                    stat_buf.checked_add(8).unwrap(),
+                    &stat.fs_rights_base.to_le_bytes(),
+                )
+                .unwrap();
+            memory
+                .set(
+                    stat_buf.checked_add(16).unwrap(),
+                    &stat.fs_rights_inheriting.to_le_bytes(),
+                )
+                .unwrap();
+
+            return Ok(Some(RuntimeValue::I32(From::from(wasi::ERRNO_SUCCESS))));
+        }
+
+        // Return environment variable data sizes.
+        //
+        // # Arguments
+        // * `envc_ptr`: the buffer to store the number of environment variables.
+        // * `envv_buf_size_ptr`: the buffer to store the total length of environment variables.
+        //
+        // # Return
+        // A WASI errno.
+        SystemCall::EnvironSizesGet => {
+            let envc_ptr: u32 = wasmi_args.nth_checked(0).unwrap();
+            let envv_buf_size_ptr: u32 = wasmi_args.nth_checked(1).unwrap();
+            args_or_env_sizes_get(theseus_env_vars, envc_ptr, envv_buf_size_ptr, memory)
+        }
+
+        // Return environment variable data.
+        //
+        // # Arguments
+        // * `envv_pointers`: the buffer to store pointers to each environment variable.
+        // * `envv_data`: the buffer to store environment variables.
+        //
+        // # Return
+        // A WASI errno.
+        SystemCall::EnvironGet => {
+            let envv_pointers: u32 = wasmi_args.nth_checked(0).unwrap();
+            let envv_data: u32 = wasmi_args.nth_checked(1).unwrap();
+            args_or_env_get(theseus_env_vars, envv_pointers, envv_data, memory)
+        }
+
+        // Return a description of the given preopened file descriptor.
+        //
+        // The preopened descriptor consists of a wasi::Preopentype and the length of the underlying
+        // file name (the relative file path).
+        //
+        // # Arguments
+        // * `fd`: the file descriptor number to get preopened description of.
+        // * `ret_ptr`: the pointer to write preopened file descriptor.
+        //
+        // # Return
+        // A WASI errno.
+        SystemCall::FdPrestatGet => {
+            // fetch file to retrieve attributes from.
+            let posix_node: &mut PosixNode = {
+                let fd: wasi::Fd = wasmi_args.nth_checked(0).unwrap();
+                match fd_table.get_posix_node(fd) {
+                    Some(pn) => pn,
+                    None => {
+                        return Ok(Some(RuntimeValue::I32(From::from(wasi::ERRNO_BADF))));
+                    }
+                }
+            };
+
+            // get directory name (relative path).
+            let pr_name_len: u32 = match posix_node.theseus_file_or_dir {
+                FileOrDir::File { .. } => {
+                    return Ok(Some(RuntimeValue::I32(From::from(wasi::ERRNO_NOTDIR))));
+                }
+                FileOrDir::Dir { .. } => {
+                    u32::try_from(posix_node.get_relative_path().chars().count()).unwrap()
+                }
+            };
+
+            let ret_ptr: u32 = wasmi_args.nth_checked(1).unwrap();
+
+            // write preopened file descriptor to ret_ptr.
+            // wasi::PREOPENTYPE_DIR is of type u8 but memory is aligned in sets of 4 bytes.
+            memory.set(ret_ptr, &[0; 8]).unwrap();
+            memory.set(ret_ptr, &[wasi::PREOPENTYPE_DIR]).unwrap();
+            memory
+                .set(ret_ptr.checked_add(4).unwrap(), &pr_name_len.to_le_bytes())
+                .unwrap();
+
+            return Ok(Some(RuntimeValue::I32(From::from(wasi::ERRNO_SUCCESS))));
+        }
+
+        // Return the directory name of the given preopened file descriptor.
+        //
+        // # Arguments
+        // * `fd`: the file descriptor number to get name of.
+        // * `path`: the buffer into which to write the preopened directory name.
+        // * `path_len`: the length of the preopened directory name.
+        //
+        // # Return
+        // A WASI errno.
+        SystemCall::FdPrestatDirName => {
+            // fetch file to retrieve name of.
+            let posix_node: &mut PosixNode = {
+                let fd: wasi::Fd = wasmi_args.nth_checked(0).unwrap();
+                match fd_table.get_posix_node(fd) {
+                    Some(pn) => pn,
+                    None => {
+                        return Ok(Some(RuntimeValue::I32(From::from(wasi::ERRNO_BADF))));
+                    }
+                }
+            };
+
+            // get directory name (relative path).
+            let name = match posix_node.theseus_file_or_dir {
+                FileOrDir::File { .. } => {
+                    return Ok(Some(RuntimeValue::I32(From::from(wasi::ERRNO_NOTDIR))));
+                }
+                FileOrDir::Dir { .. } => posix_node.get_relative_path(),
+            };
+
+            let path: u32 = wasmi_args.nth_checked(1).unwrap();
+            let path_out_len: wasi::Size = {
+                let len: u32 = wasmi_args.nth_checked(2).unwrap();
+                wasi::Size::try_from(len).unwrap()
+            };
+
+            // write directory name to path.
+            memory.set(path, &name.as_bytes()[..path_out_len]).unwrap();
+
+            return Ok(Some(RuntimeValue::I32(From::from(wasi::ERRNO_SUCCESS))));
+        }
+
+        // Open file or directory. This is similar to openat in POSIX.
+        //
+        // # Arguments
+        // * `fd`: the file descriptor number to open from.
+        // * `dirflags`: flags determining the method of how the path is resolved.
+        // * `path`: the relative path of the file or directory to open, relative to fd directory.
+        // * `path_len`: length of path buffer containing path to open.
+        // * `open_flags`: the method by which to open the file. this includes modes such as
+        // whether to create a file if it doesn't exist, truncate existing files, etc.
+        // * `fs_rights_base`: rights applying to the file being opened. this includes rights such
+        // as whether reading, writing, setting flags, etc. are permitted.
+        // * `fs_rights_inheriting`: rights inherited by files opened by the resulting opened file.
+        // * `fs_flags`: file descriptor flags. this includes modes such as append mode when
+        // writign to files.
+        // * `ret_ptr`: the pointer to write the file descriptor of the opened file or directory.
+        //
+        // # Return
+        // A WASI errno.
+        SystemCall::PathOpen => {
+            // fetch file system node to open from.
+            let posix_node: &mut PosixNode = {
+                let fd: wasi::Fd = wasmi_args.nth_checked(0).unwrap();
+                match fd_table.get_posix_node(fd) {
+                    Some(pn) => pn,
+                    None => {
+                        return Ok(Some(RuntimeValue::I32(From::from(wasi::ERRNO_BADF))));
+                    }
+                }
+            };
+
+            // verify that file descriptor has rights to open path from.
+            if posix_node.fs_rights_base() & wasi::RIGHTS_PATH_OPEN == 0 {
+                return Ok(Some(RuntimeValue::I32(From::from(wasi::ERRNO_ACCES))));
+            }
+
+            // fetch underlying directory.
+            let parent_dir: DirRef = match posix_node.theseus_file_or_dir.clone() {
+                FileOrDir::File { .. } => {
+                    return Ok(Some(RuntimeValue::I32(From::from(wasi::ERRNO_NOTDIR))));
+                }
+                FileOrDir::Dir(dir_ref) => dir_ref.clone(),
+            };
+
+            let lookup_flags: wasi::Lookupflags = wasmi_args.nth_checked(1).unwrap();
+
+            // access path to open.
+            let path = {
+                let path: u32 = wasmi_args.nth_checked(2).unwrap();
+                let path_len: wasi::Size = {
+                    let len: u32 = wasmi_args.nth_checked(3).unwrap();
+                    wasi::Size::try_from(len).unwrap()
+                };
+                let path_utf8 = memory.get(path, path_len).unwrap();
+                String::from_utf8(path_utf8).unwrap()
+            };
+
+            let maximum_rights: wasi::Rights = posix_node.fs_rights_inheriting();
+
+            let open_flags: wasi::Oflags = wasmi_args.nth_checked(4).unwrap();
+            let mut fs_rights_base: wasi::Rights = wasmi_args.nth_checked(5).unwrap();
+            let mut fs_rights_inheriting: wasi::Rights = wasmi_args.nth_checked(6).unwrap();
+            let fs_flags: wasi::Fdflags = wasmi_args.nth_checked(7).unwrap();
+
+            // set rights from parent file descriptor's inheriting rights.
+            fs_rights_base &= maximum_rights;
+            fs_rights_inheriting &= maximum_rights;
+
+            // open path from file descriptor.
+            let opened_fd: wasi::Fd = match fd_table.open_path(
+                &path,
+                parent_dir,
+                lookup_flags,
+                open_flags,
+                fs_rights_base,
+                fs_rights_inheriting,
+                fs_flags,
+            ) {
+                Ok(fd) => fd,
+                Err(wasi_error) => {
+                    return Ok(Some(RuntimeValue::I32(From::from(wasi_error))));
+                }
+            };
+
+            // write opened file descriptor to return pointer.
+            let opened_fd_ptr: u32 = wasmi_args.nth_checked(8).unwrap();
+            memory.set(opened_fd_ptr, &opened_fd.to_le_bytes()).unwrap();
+            return Ok(Some(RuntimeValue::I32(From::from(wasi::ERRNO_SUCCESS))));
+        }
+
+        // Adjust the flags associated with a file descriptor.
+        // This is similar to fcntl(fd, F_SETFL, flags) in POSIX.
+        //
+        // # Arguments
+        // * `fd`: the file descriptor being modified.
+        // * `flags`: the desired values of the file descriptor flags.
+        //
+        // # Return
+        // A WASI errno.
+        SystemCall::FdFdstatSetFlags => {
+            // fetch file system node to modify flags.
+            let posix_node: &mut PosixNode = {
+                let fd: wasi::Fd = wasmi_args.nth_checked(0).unwrap();
+                match fd_table.get_posix_node(fd) {
+                    Some(pn) => pn,
+                    None => {
+                        return Ok(Some(RuntimeValue::I32(From::from(wasi::ERRNO_BADF))));
+                    }
+                }
+            };
+
+            // set flags of file.
+            let flags: wasi::Fdflags = wasmi_args.nth_checked(1).unwrap();
+            match posix_node.set_fs_flags(flags) {
+                Ok(_) => {}
+                Err(wasi_error) => {
+                    return Ok(Some(RuntimeValue::I32(From::from(wasi_error))));
+                }
+            };
+
+            return Ok(Some(RuntimeValue::I32(From::from(wasi::ERRNO_SUCCESS))));
+        }
+
+        // Return argument data sizes.
+        //
+        // # Arguments
+        // * `argc_ptr`: the buffer to store the number of arguments.
+        // * `argv_buf_size_ptr`: the buffer to store the total length of arguments data.
+        //
+        // # Return
+        // A WASI errno.
+        SystemCall::ArgsSizesGet => {
+            let argc_ptr: u32 = wasmi_args.nth_checked(0).unwrap();
+            let argv_buf_size_ptr: u32 = wasmi_args.nth_checked(1).unwrap();
+            args_or_env_sizes_get(theseus_args, argc_ptr, argv_buf_size_ptr, memory)
+        }
+
+        // Return arguments.
+        //
+        // # Arguments
+        // * `argv_pointers`: the buffer to store pointers to each argument.
+        // * `argv_data`: the buffer to store arguments data.
+        //
+        // # Return
+        // A WASI errno.
+        SystemCall::ArgsGet => {
+            let argv_pointers: u32 = wasmi_args.nth_checked(0).unwrap();
+            let argv_data: u32 = wasmi_args.nth_checked(1).unwrap();
+            args_or_env_get(theseus_args, argv_pointers, argv_data, memory)
+        }
+
+        // Return time value of a clock. This is similar to clock_gettime in POSIX.
+        //
+        // # Arguments
+        // * `clock_id`: The clock for which to return the time.
+        // * `precision`: The maximum lag (exclusive) that the returned time value may have, compared to its
+        // actual value.
+        // * `ret_ptr`: The buffer in which to store the time.
+        //
+        // # Return
+        // A WASI errno.
+        SystemCall::ClockTimeGet => {
+            let clock_id: wasi::Clockid = wasmi_args.nth_checked(0).unwrap();
+            let _precision: wasi::Timestamp = wasmi_args.nth_checked(1).unwrap();
+
+            // TODO: use rtc value converted to unix timestamp.
+            let unix_timestamp = 0;
+
+            // fetch time.
+            let timestamp: wasi::Timestamp = match clock_id {
+                wasi::CLOCKID_MONOTONIC => unimplemented!(),
+                wasi::CLOCKID_PROCESS_CPUTIME_ID => unimplemented!(),
+                wasi::CLOCKID_REALTIME => unix_timestamp,
+                wasi::CLOCKID_THREAD_CPUTIME_ID => unimplemented!(),
+                _ => {
+                    return Ok(Some(RuntimeValue::I32(From::from(wasi::ERRNO_NOTSUP))));
+                }
+            };
+
+            // write time to return pointer.
+            let ret_ptr: u32 = wasmi_args.nth_checked(2).unwrap();
+            memory.set(ret_ptr, &timestamp.to_le_bytes()).unwrap();
+            return Ok(Some(RuntimeValue::I32(From::from(wasi::ERRNO_SUCCESS))));
+        }
+    }
+}
+
+
+ \ No newline at end of file diff --git a/doc/src/wasi_interpreter/wasmi_state_machine.rs.html b/doc/src/wasi_interpreter/wasmi_state_machine.rs.html new file mode 100644 index 0000000000..c6d16f18af --- /dev/null +++ b/doc/src/wasi_interpreter/wasmi_state_machine.rs.html @@ -0,0 +1,375 @@ +wasmi_state_machine.rs - source + +
  1
+  2
+  3
+  4
+  5
+  6
+  7
+  8
+  9
+ 10
+ 11
+ 12
+ 13
+ 14
+ 15
+ 16
+ 17
+ 18
+ 19
+ 20
+ 21
+ 22
+ 23
+ 24
+ 25
+ 26
+ 27
+ 28
+ 29
+ 30
+ 31
+ 32
+ 33
+ 34
+ 35
+ 36
+ 37
+ 38
+ 39
+ 40
+ 41
+ 42
+ 43
+ 44
+ 45
+ 46
+ 47
+ 48
+ 49
+ 50
+ 51
+ 52
+ 53
+ 54
+ 55
+ 56
+ 57
+ 58
+ 59
+ 60
+ 61
+ 62
+ 63
+ 64
+ 65
+ 66
+ 67
+ 68
+ 69
+ 70
+ 71
+ 72
+ 73
+ 74
+ 75
+ 76
+ 77
+ 78
+ 79
+ 80
+ 81
+ 82
+ 83
+ 84
+ 85
+ 86
+ 87
+ 88
+ 89
+ 90
+ 91
+ 92
+ 93
+ 94
+ 95
+ 96
+ 97
+ 98
+ 99
+100
+101
+102
+103
+104
+105
+106
+107
+108
+109
+110
+111
+112
+113
+114
+115
+116
+117
+118
+119
+120
+121
+122
+123
+124
+125
+126
+127
+128
+129
+130
+131
+132
+133
+134
+135
+136
+137
+138
+139
+140
+141
+142
+143
+144
+145
+146
+147
+148
+149
+150
+151
+152
+153
+154
+155
+156
+157
+158
+159
+160
+161
+162
+163
+164
+165
+166
+167
+168
+169
+170
+171
+172
+173
+174
+175
+176
+177
+178
+179
+180
+181
+182
+183
+184
+
+//! Module for resolving memory and function imports from WebAssembly module into state machine.
+//!
+//! Subset of functionality borrowed from tomaka/redshirt:
+//! <https://github.com/tomaka/redshirt/blob/4df506f68821353a7fd67bb94c4223df6b683e1b/kernel/core/src/scheduler/vm.rs>
+//!
+
+use alloc::string::String;
+use core::{cell::RefCell, convert::TryFrom as _};
+
+use wasmi::{Module, Signature};
+
+#[derive(Debug)]
+pub enum NewErr {
+    /// Error in the interpreter.
+    Interpreter(wasmi::Error),
+    /// If a "memory" symbol is provided, it must be a memory.
+    MemoryIsntMemory,
+    /// A memory object has both been imported and exported.
+    MultipleMemoriesNotSupported,
+    /// If a "__indirect_function_table" symbol is provided, it must be a table.
+    IndirectTableIsntTable,
+}
+
+pub struct ProcessStateMachine {
+    /// Original module, with resolved imports.
+    pub module: wasmi::ModuleRef,
+
+    /// Memory of the module instantiation.
+    ///
+    /// Right now we only support one unique `Memory` object per process. This is it.
+    /// Contains `None` if the process doesn't export any memory object, which means it doesn't use
+    /// any memory.
+    pub memory: Option<wasmi::MemoryRef>,
+
+    /// Table of the indirect function calls.
+    ///
+    /// In WASM, function pointers are in reality indices in a table called
+    /// `__indirect_function_table`. This is this table, if it exists.
+    pub indirect_table: Option<wasmi::TableRef>,
+}
+
+impl ProcessStateMachine {
+    /// Creates a new process state machine from the given module.
+    ///
+    /// The closure is called for each import that the module has. It must assign a number to each
+    /// import, or return an error if the import can't be resolved. When the VM calls one of these
+    /// functions, this number will be returned back in order for the user to know how to handle
+    /// the call.
+    ///
+    /// A single main thread (whose user data is passed by parameter) is automatically created and
+    /// is paused at the start of the "_start" function of the module.
+    pub fn new(
+        module: &Module,
+        mut symbols: impl FnMut(&str, &str, &Signature) -> Result<usize, ()>,
+    ) -> Result<Self, NewErr> {
+        struct ImportResolve<'a> {
+            func: RefCell<&'a mut dyn FnMut(&str, &str, &Signature) -> Result<usize, ()>>,
+            memory: RefCell<&'a mut Option<wasmi::MemoryRef>>,
+        }
+
+        impl<'a> wasmi::ImportResolver for ImportResolve<'a> {
+            fn resolve_func(
+                &self,
+                module_name: &str,
+                field_name: &str,
+                signature: &wasmi::Signature,
+            ) -> Result<wasmi::FuncRef, wasmi::Error> {
+                let closure = &mut **self.func.borrow_mut();
+                let index = match closure(module_name, field_name, signature) {
+                    Ok(i) => i,
+                    Err(_) => {
+                        return Err(wasmi::Error::Instantiation(format!(
+                            "Couldn't resolve `{}`:`{}`",
+                            module_name, field_name
+                        )))
+                    }
+                };
+
+                Ok(wasmi::FuncInstance::alloc_host(signature.clone(), index))
+            }
+
+            fn resolve_global(
+                &self,
+                _module_name: &str,
+                _field_name: &str,
+                _global_type: &wasmi::GlobalDescriptor,
+            ) -> Result<wasmi::GlobalRef, wasmi::Error> {
+                Err(wasmi::Error::Instantiation(String::from(
+                    "Importing globals is not supported yet",
+                )))
+            }
+
+            fn resolve_memory(
+                &self,
+                _module_name: &str,
+                _field_name: &str,
+                memory_type: &wasmi::MemoryDescriptor,
+            ) -> Result<wasmi::MemoryRef, wasmi::Error> {
+                let mut mem = self.memory.borrow_mut();
+                if mem.is_some() {
+                    return Err(wasmi::Error::Instantiation(String::from(
+                        "Only one memory object is supported yet",
+                    )));
+                }
+
+                let new_mem = wasmi::MemoryInstance::alloc(
+                    wasmi::memory_units::Pages(usize::try_from(memory_type.initial()).unwrap()),
+                    memory_type
+                        .maximum()
+                        .map(|p| wasmi::memory_units::Pages(usize::try_from(p).unwrap())),
+                )
+                .unwrap();
+                **mem = Some(new_mem.clone());
+                Ok(new_mem)
+            }
+
+            fn resolve_table(
+                &self,
+                _module_name: &str,
+                _field_name: &str,
+                _table_type: &wasmi::TableDescriptor,
+            ) -> Result<wasmi::TableRef, wasmi::Error> {
+                Err(wasmi::Error::Instantiation(String::from(
+                    "Importing tables is not supported yet",
+                )))
+            }
+        }
+
+        let (not_started, imported_memory) = {
+            let mut imported_memory = None;
+            let resolve = ImportResolve {
+                func: RefCell::new(&mut symbols),
+                memory: RefCell::new(&mut imported_memory),
+            };
+            let not_started =
+                wasmi::ModuleInstance::new(&module, &resolve).map_err(NewErr::Interpreter)?;
+            (not_started, imported_memory)
+        };
+
+        // TODO: WASM has a special "start" instruction that can be used to designate a function
+        // that must be executed before the module is considered initialized. It is unclear whether
+        // this is intended to be a function that for example initializes global variables, or if
+        // this is an equivalent of "_start". In practice, Rust never seems to generate such as
+        // "start" instruction, so for now we ignore it. The code below panics if there is such
+        // a "start" item, so we will fortunately not blindly run into troubles.
+        let module = not_started.assert_no_start();
+
+        let memory = if let Some(imported_mem) = imported_memory {
+            if module
+                .export_by_name("memory")
+                .map_or(false, |m| m.as_memory().is_some())
+            {
+                return Err(NewErr::MultipleMemoriesNotSupported);
+            }
+            Some(imported_mem)
+        } else if let Some(mem) = module.export_by_name("memory") {
+            if let Some(mem) = mem.as_memory() {
+                Some(mem.clone())
+            } else {
+                return Err(NewErr::MemoryIsntMemory);
+            }
+        } else {
+            None
+        };
+
+        let indirect_table = if let Some(tbl) = module.export_by_name("__indirect_function_table") {
+            if let Some(tbl) = tbl.as_table() {
+                Some(tbl.clone())
+            } else {
+                return Err(NewErr::IndirectTableIsntTable);
+            }
+        } else {
+            None
+        };
+
+        let state_machine = ProcessStateMachine {
+            module,
+            memory,
+            indirect_table,
+        };
+
+        Ok(state_machine)
+    }
+}
+
+
+ \ No newline at end of file diff --git a/doc/wasi_interpreter/all.html b/doc/wasi_interpreter/all.html new file mode 100644 index 0000000000..ea3a077e92 --- /dev/null +++ b/doc/wasi_interpreter/all.html @@ -0,0 +1,7 @@ +List of all items in this crate + +

List of all items[] + +

Structs

Macros

Functions

+ \ No newline at end of file diff --git a/doc/wasi_interpreter/fn.execute_binary.html b/doc/wasi_interpreter/fn.execute_binary.html new file mode 100644 index 0000000000..bf05150107 --- /dev/null +++ b/doc/wasi_interpreter/fn.execute_binary.html @@ -0,0 +1,15 @@ +execute_binary in wasi_interpreter - Rust + +

Function wasi_interpreter::execute_binary[][src]

pub fn execute_binary(
    wasm_binary: Vec<u8>,
    args: Vec<String>,
    preopen_dirs: Vec<String>
) -> isize
Expand description

Executes a WASI-compliant WebAssembly binary.

+

This function constructs a wasmi state machine from a WebAssembly binary, constructs a +HostExternals object consisting of any necessary Theseus or wasmi I/O, opens file descriptors +for accessible directories, and executes.

+

Arguments

+
    +
  • wasm_binary: a WASI-compliant WebAssembly binary as a byte vector
  • +
  • args: a POSIX-formatted string vector of arguments to WebAssembly binary
  • +
  • preopen_dirs: a string vector of directory paths to grant WASI access to
  • +
+
+ \ No newline at end of file diff --git a/doc/wasi_interpreter/index.html b/doc/wasi_interpreter/index.html new file mode 100644 index 0000000000..6eb42bdc08 --- /dev/null +++ b/doc/wasi_interpreter/index.html @@ -0,0 +1,24 @@ +wasi_interpreter - Rust + +

Crate wasi_interpreter[][src]

Expand description

Interpreter for executing WASI-compliant WASM binaries.

+

wasi_interpreter provides an interface between the wasmi crate (used to interpret +WebAssembly) and Theseus under the assumption of a WASI interface.

+

This library exposes a public method called execute_binary to allow for the execution of a +WebAssembly binary given directory permissions (in accordance to the WASI capabilities model) +and arguments.

+

This library depends on the following modules:

+
    +
  • wasi_definitions
  • +
  • wasi_syscalls
  • +
  • posix_file_system
  • +
  • wasmi_state_machine
  • +
+

Macros

+
sig

Macro to efficiently generate wasmi function signature.

+

Structs

+
HostExternals

Theseus and wasmi I/O required to execute WASI system calls.

+

Functions

+
execute_binary

Executes a WASI-compliant WebAssembly binary.

+
+ \ No newline at end of file diff --git a/doc/wasi_interpreter/macro.sig!.html b/doc/wasi_interpreter/macro.sig!.html new file mode 100644 index 0000000000..59c8bae047 --- /dev/null +++ b/doc/wasi_interpreter/macro.sig!.html @@ -0,0 +1,10 @@ + + + + + + +

Redirecting to macro.sig.html...

+ + + \ No newline at end of file diff --git a/doc/wasi_interpreter/macro.sig.html b/doc/wasi_interpreter/macro.sig.html new file mode 100644 index 0000000000..caee1f37ce --- /dev/null +++ b/doc/wasi_interpreter/macro.sig.html @@ -0,0 +1,14 @@ +sig in wasi_interpreter - Rust + +

Macro wasi_interpreter::sig[][src]

+macro_rules! sig {
+    (($($p:ident),*)) => { ... };
+    (($($p:ident),*) -> $ret:ident) => { ... };
+}
+
Expand description

Macro to efficiently generate wasmi function signature.

+

Usage examples: +sig!((I32)) +sig!((I32, I32)->I32)

+
+ \ No newline at end of file diff --git a/doc/wasi_interpreter/sidebar-items.js b/doc/wasi_interpreter/sidebar-items.js new file mode 100644 index 0000000000..346a549e8d --- /dev/null +++ b/doc/wasi_interpreter/sidebar-items.js @@ -0,0 +1 @@ +initSidebarItems({"fn":[["execute_binary","Executes a WASI-compliant WebAssembly binary."]],"macro":[["sig","Macro to efficiently generate wasmi function signature."]],"struct":[["HostExternals","Theseus and wasmi I/O required to execute WASI system calls."]]}); \ No newline at end of file diff --git a/doc/wasi_interpreter/struct.HostExternals.html b/doc/wasi_interpreter/struct.HostExternals.html new file mode 100644 index 0000000000..38a2d2bfb5 --- /dev/null +++ b/doc/wasi_interpreter/struct.HostExternals.html @@ -0,0 +1,25 @@ +HostExternals in wasi_interpreter - Rust + +

Struct wasi_interpreter::HostExternals[][src]

pub struct HostExternals { /* fields omitted */ }
Expand description

Theseus and wasmi I/O required to execute WASI system calls.

+

Trait Implementations

impl Externals for HostExternals[src]

fn invoke_index(
    &mut self,
    index: usize,
    wasmi_args: RuntimeArgs<'_>
) -> Result<Option<RuntimeValue>, Trap>
[src]

Function used by wasmi to invoke a system call given a specified system call number and +wasm arguments.

+

Auto Trait Implementations

impl !Send for HostExternals

impl !Sync for HostExternals

impl Unpin for HostExternals

Blanket Implementations

impl<T> Any for T where
    T: 'static + ?Sized
[src]

pub fn type_id(&self) -> TypeId[src]

Gets the TypeId of self. Read more

+

impl<T> Borrow<T> for T where
    T: ?Sized
[src]

pub fn borrow(&self) -> &T[src]

Immutably borrows from an owned value. Read more

+

impl<T> BorrowMut<T> for T where
    T: ?Sized
[src]

pub fn borrow_mut(&mut self) -> &mut T[src]

Mutably borrows from an owned value. Read more

+

impl<T> Downcast for T where
    T: Any

pub fn into_any(self: Box<T, Global>) -> Box<dyn Any + 'static, Global>

Convert Box<dyn Trait> (where Trait: Downcast) to Box<dyn Any>. Box<dyn Any> can +then be further downcast into Box<ConcreteType> where ConcreteType implements Trait. Read more

+

pub fn into_any_rc(self: Rc<T>) -> Rc<dyn Any + 'static>

Convert Rc<Trait> (where Trait: Downcast) to Rc<Any>. Rc<Any> can then be +further downcast into Rc<ConcreteType> where ConcreteType implements Trait. Read more

+

pub fn as_any(&self) -> &(dyn Any + 'static)

Convert &Trait (where Trait: Downcast) to &Any. This is needed since Rust cannot +generate &Any’s vtable from &Trait’s. Read more

+

pub fn as_any_mut(&mut self) -> &mut (dyn Any + 'static)

Convert &mut Trait (where Trait: Downcast) to &Any. This is needed since Rust cannot +generate &mut Any’s vtable from &mut Trait’s. Read more

+

impl<T> From<T> for T[src]

pub fn from(t: T) -> T[src]

Performs the conversion.

+

impl<T, U> Into<U> for T where
    U: From<T>, 
[src]

pub fn into(self) -> U[src]

Performs the conversion.

+

impl<T, U> TryFrom<U> for T where
    U: Into<T>, 
[src]

type Error = Infallible

The type returned in the event of a conversion error.

+

pub fn try_from(value: U) -> Result<T, <T as TryFrom<U>>::Error>[src]

Performs the conversion.

+

impl<T, U> TryInto<U> for T where
    U: TryFrom<T>, 
[src]

type Error = <U as TryFrom<T>>::Error

The type returned in the event of a conversion error.

+

pub fn try_into(self) -> Result<U, <U as TryFrom<T>>::Error>[src]

Performs the conversion.

+

impl<T> Erased for T

+ \ No newline at end of file