Skip to content

Commit f4aa715

Browse files
Support running WASM+WASI binaries via the wasmi interpreter (#472)
* See `applications/wasm` for examples on how to run WASM binaries. * Key components and details: * `kernel/wasm_interpreter` is the main interface between `wasmi` and the rest of Theseus. * `applications/wasm` is the user frontend for invoking a WASM binary, which allows specifying access to directories, preopening files, and passing arguments to the WASM application. * Basic WASI system calls are supported. * WASM binaries are currently located in `extra_files/`, as are some test/demo files that are used by those WASM binaries.
1 parent a685e06 commit f4aa715

25 files changed

+2253
-1
lines changed

.gitignore

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -27,6 +27,7 @@ github_pages/doc/
2727
*.idea/
2828
*.vscode/
2929
*.code-workspace
30+
*.swp
3031

3132
# log files
3233
*.pcap

Cargo.lock

Lines changed: 99 additions & 0 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

Makefile

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -132,7 +132,7 @@ iso: $(iso)
132132

133133

134134
### This target builds an .iso OS image from all of the compiled crates.
135-
$(iso): clean-old-build build
135+
$(iso): clean-old-build build extra_files
136136
# after building kernel and application modules, copy the kernel boot image files
137137
@mkdir -p $(GRUB_ISOFILES)/boot/grub
138138
@cp $(nano_core_binary) $(GRUB_ISOFILES)/boot/kernel.bin

applications/wasm/Cargo.toml

Lines changed: 24 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,24 @@
1+
[package]
2+
name = "wasm"
3+
version = "0.1.0"
4+
authors = ["Vikram Mullick <vikram1.mullick@gmail.com>"]
5+
edition = "2018"
6+
description = "Application for running WASI-compliant WebAssembly binaries from Theseus command line"
7+
8+
[dependencies]
9+
getopts = "0.2.21"
10+
11+
[dependencies.app_io]
12+
path = "../../kernel/app_io"
13+
14+
[dependencies.task]
15+
path = "../../kernel/task"
16+
17+
[dependencies.path]
18+
path = "../../kernel/path"
19+
20+
[dependencies.fs_node]
21+
path = "../../kernel/fs_node"
22+
23+
[dependencies.wasi_interpreter]
24+
path = "../../kernel/wasi_interpreter"

applications/wasm/src/lib.rs

Lines changed: 150 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,150 @@
1+
//! Application for running WASI-compliant WebAssembly binaries from Theseus command line.
2+
//!
3+
//! USAGE:
4+
//! wasm [option]... WASM_BINARY_PATH [arg]...
5+
//!
6+
//! EXAMPLES:
7+
//!
8+
//! Running a WebAssembly Binary:
9+
//! wasm example.wasm
10+
//!
11+
//! Preopening Multiple Directories:
12+
//! wasm --dir DIR1 --dir DIR2 example.wasm
13+
//!
14+
//! Passing Arguments/Flags to WebAssembly Binary:
15+
//! wasm --dir . example.wasm ARG1 ARG2 ARG3
16+
//!
17+
18+
#![no_std]
19+
20+
#[macro_use]
21+
extern crate alloc;
22+
#[macro_use]
23+
extern crate app_io;
24+
extern crate fs_node;
25+
extern crate getopts;
26+
extern crate path;
27+
extern crate task;
28+
extern crate wasi_interpreter;
29+
30+
use alloc::{string::String, sync::Arc, vec::Vec};
31+
use fs_node::FileOrDir;
32+
use getopts::{Options, ParsingStyle};
33+
use path::Path;
34+
35+
pub fn main(args: Vec<String>) -> isize {
36+
// Parse command line options.
37+
let mut opts = Options::new();
38+
39+
// StopAtFirstFree allows arguments to be passed to WebAssembly program.
40+
opts.parsing_style(ParsingStyle::StopAtFirstFree);
41+
42+
opts.optmulti("d", "dir", "directories to grant file system access", "DIR");
43+
opts.optflag("h", "help", "print this help menu");
44+
45+
let matches = match opts.parse(&args) {
46+
Ok(m) => m,
47+
Err(_f) => {
48+
println!("{}", _f);
49+
print_usage(opts);
50+
return -1;
51+
}
52+
};
53+
54+
if matches.opt_present("h") {
55+
print_usage(opts);
56+
return 0;
57+
}
58+
59+
let preopened_dirs: Vec<String> = matches.opt_strs("d");
60+
61+
// Get current working directory.
62+
let curr_wr = Arc::clone(
63+
&task::get_my_current_task()
64+
.unwrap()
65+
.get_env()
66+
.lock()
67+
.working_dir,
68+
);
69+
70+
// Verify passed preopened directories are real directories.
71+
for dir in preopened_dirs.iter() {
72+
let dir_path = Path::new(dir.clone());
73+
74+
match dir_path.get(&curr_wr) {
75+
Some(file_dir_enum) => match file_dir_enum {
76+
FileOrDir::Dir(_) => {}
77+
FileOrDir::File(file) => {
78+
println!("{:?} is a file.", file.lock().get_name());
79+
return -1;
80+
}
81+
},
82+
_ => {
83+
println!("Couldn't find dir at path '{}'", dir_path);
84+
return -1;
85+
}
86+
};
87+
}
88+
89+
let args: Vec<String> = matches.free;
90+
91+
// Verify that arguments is non-empty.
92+
if args.is_empty() {
93+
println!("No WebAssembly path specified.");
94+
print_usage(opts);
95+
return -1;
96+
}
97+
98+
let wasm_binary_path = Path::new(args[0].clone());
99+
100+
// Parse inputted WebAssembly binary path into byte array.
101+
let wasm_binary: Vec<u8> = match wasm_binary_path.get(&curr_wr) {
102+
Some(file_dir_enum) => match file_dir_enum {
103+
FileOrDir::Dir(directory) => {
104+
println!("{:?} is a directory.", directory.lock().get_name());
105+
return -1;
106+
}
107+
FileOrDir::File(file) => {
108+
let file_locked = file.lock();
109+
let file_size = file_locked.size();
110+
let mut wasm_binary_as_bytes = vec![0; file_size];
111+
112+
let _num_bytes_read = match file_locked.read(&mut wasm_binary_as_bytes, 0) {
113+
Ok(num) => num,
114+
Err(e) => {
115+
println!("Failed to read {:?}, error {:?}", file_locked.get_name(), e);
116+
return -1;
117+
}
118+
};
119+
wasm_binary_as_bytes
120+
}
121+
},
122+
_ => {
123+
println!("Couldn't find file at path '{}'", wasm_binary_path);
124+
return -1;
125+
}
126+
};
127+
128+
// Execute wasm binary.
129+
wasi_interpreter::execute_binary(wasm_binary, args, preopened_dirs);
130+
131+
0
132+
}
133+
134+
fn print_usage(opts: Options) {
135+
println!("{}", opts.usage(USAGE));
136+
}
137+
138+
const USAGE: &'static str = "USAGE:
139+
wasm [option]... WASM_BINARY_PATH [arg]...
140+
141+
EXAMPLES:
142+
143+
Running a WebAssembly Binary:
144+
wasm example.wasm
145+
146+
Preopening Multiple Directories:
147+
wasm --dir DIR1 --dir DIR2 example.wasm
148+
149+
Passing Arguments/Flags to WebAssembly Binary:
150+
wasm --dir . example.wasm ARG1 ARG2 ARG3";
Lines changed: 21 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,21 @@
1+
It is a period of civil war.
2+
Rebel spaceships, striking
3+
from a hidden base, have won
4+
their first victory against
5+
the evil Galactic Empire.
6+
7+
During the battle, Rebel
8+
spies managed to steal secret
9+
plans to the Empire's
10+
ultimate weapon, the DEATH
11+
STAR, an armored space
12+
station with enough power to
13+
destroy an entire planet.
14+
15+
Pursued by the Empire's
16+
sinister agents, Princess
17+
Leia races home aboard her
18+
starship, custodian of the
19+
stolen plans that can save
20+
her people and restore
21+
freedom to the galaxy....
Lines changed: 19 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,19 @@
1+
There is unrest in the Galactic
2+
Senate. Several thousand solar
3+
systems have declared their
4+
intentions to leave the Republic.
5+
6+
This separatist movement,
7+
under the leadership of the
8+
mysterious Count Dooku, has
9+
made it difficult for the limited
10+
number of Jedi Knights to maintain
11+
peace and order in the galaxy.
12+
13+
Senator Amidala, the former
14+
Queen of Naboo, is returning
15+
to the Galactic Senate to vote
16+
on the critical issue of creating
17+
an ARMY OF THE REPUBLIC
18+
to assist the overwhelmed
19+
Jedi....
Lines changed: 20 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,20 @@
1+
Luke Skywalker has returned to
2+
his home planet of Tatooine in
3+
an attempt to rescue his
4+
friend Han Solo from the
5+
clutches of the vile gangster
6+
Jabba the Hutt.
7+
8+
Little does Luke know that the
9+
GALACTIC EMPIRE has secretly
10+
begun construction on a new
11+
armored space station even
12+
more powerful than the first
13+
dreaded Death Star.
14+
15+
When completed, this ultimate
16+
weapon will spell certain doom
17+
for the small band of rebels
18+
struggling to restore freedom
19+
to the galaxy...
20+

0 commit comments

Comments
 (0)