Skip to content

Commit 811cdd1

Browse files
committed
hello world
1 parent fb6b016 commit 811cdd1

7 files changed

Lines changed: 160 additions & 13 deletions

File tree

.gitignore

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,4 @@
1+
*.wasm
12
/target
23
.idea
34
.DS_Store

kernel/src/shell.rs

Lines changed: 18 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -31,7 +31,7 @@ use crate::mem::{Mmap, PhysicalAddress, with_kernel_aspace};
3131
use crate::state::global;
3232
use crate::{arch, irq};
3333

34-
static COMMANDS: &[Command] = &[PANIC, FAULT, VERSION, SHUTDOWN];
34+
static COMMANDS: &[Command] = &[PANIC, FAULT, VERSION, SHUTDOWN, HELLOWORLD];
3535

3636
pub fn init(devtree: &'static DeviceTree, sched: &'static Executor, num_cpus: usize) {
3737
// The `Barrier` below is here so that the maybe verbose startup logging is
@@ -186,6 +186,23 @@ const SHUTDOWN: Command = Command::new("shutdown")
186186
Ok(())
187187
});
188188

189+
const HELLOWORLD: Command = Command::new("helloworld")
190+
.with_help("run a Hello World WASM module to test WASI integration.")
191+
.with_fn(|ctx| {
192+
tracing::info!(target: "shell", "Running Hello World WASM module...");
193+
194+
match crate::wasm::hello_world::run() {
195+
Ok(()) => {
196+
tracing::info!(target: "shell", "Hello World completed successfully!");
197+
Ok(())
198+
}
199+
Err(e) => {
200+
tracing::error!(target: "shell", "Failed to run Hello World: {}", e);
201+
Err(ctx.other_error("WASM execution failed"))
202+
}
203+
}
204+
});
205+
189206
#[derive(Debug)]
190207
pub struct Command<'cmd> {
191208
name: &'cmd str,

kernel/src/tests/smoke.rs

Lines changed: 11 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -8,14 +8,15 @@
88
use crate::tests::wast::wast_tests;
99

1010
wast_tests!(
11-
fib "../../../tests/fib.wast",
12-
fib_imported "../../../tests/fib_imported.wast",
13-
hostfunc_rs "../../../tests/hostfunc_rs.wast",
14-
hostfunc_wat "../../../tests/hostfunc_wat.wast",
15-
test_io_functions "../../../tests/test_io_functions.wast",
16-
test_process_functions "../../../tests/test_process_functions.wast",
17-
test_memory_functions "../../../tests/test_memory_functions.wast",
18-
test_time_functions "../../../tests/test_time_functions.wast",
19-
test_filesystem_stubs "../../../tests/test_filesystem_stubs.wast",
20-
test_wasi_io "../../../tests/test_wasi_io.wast",
11+
// fib "../../../tests/fib.wast",
12+
// fib_imported "../../../tests/fib_imported.wast",
13+
// hostfunc_rs "../../../tests/hostfunc_rs.wast",
14+
// hostfunc_wat "../../../tests/hostfunc_wat.wast",
15+
// test_io_functions "../../../tests/test_io_functions.wast",
16+
// test_process_functions "../../../tests/test_process_functions.wast",
17+
// test_memory_functions "../../../tests/test_memory_functions.wast",
18+
// test_time_functions "../../../tests/test_time_functions.wast",
19+
// test_filesystem_stubs "../../../tests/test_filesystem_stubs.wast",
20+
// test_wasi_io "../../../tests/test_wasi_io.wast",
21+
test_hello_world "../../../tests/test_hello_world.wast",
2122
);

kernel/src/wasm/hello_world.rs

Lines changed: 95 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,95 @@
1+
// Copyright 2025 Jonas Kruckenberg
2+
//
3+
// Licensed under the Apache License, Version 2.0, <LICENSE-APACHE or
4+
// http://apache.org/licenses/LICENSE-2.0> or the MIT license <LICENSE-MIT or
5+
// http://opensource.org/licenses/MIT>, at your option. This file may not be
6+
// copied, modified, or distributed except according to those terms.
7+
8+
//! Hello World WASM module for testing WASI integration
9+
10+
use crate::wasm::{Engine, Linker, Module, Store};
11+
use crate::wasm::host_funcs;
12+
use crate::wasm::vm::{ConstExprEvaluator, instance_alloc::PlaceholderAllocatorDontUse};
13+
use wasmparser::Validator;
14+
use wast::parser::ParseBuffer;
15+
16+
/// The Hello World WAT module source
17+
const HELLO_WORLD_WAT: &str = r#"
18+
(module
19+
;; Import fd_write from WASI
20+
(import "wasi_snapshot_preview1" "fd_write"
21+
(func $fd_write (param i32 i32 i32 i32) (result i32)))
22+
23+
;; Memory with at least 1 page
24+
(memory (export "memory") 1)
25+
26+
;; Data segment with our message
27+
(data (i32.const 8) "Hello World from WASI!\n")
28+
29+
;; IoVec structure at offset 0
30+
;; Points to our string at offset 8, length 23
31+
(data (i32.const 0) "\08\00\00\00\17\00\00\00")
32+
33+
;; Start function
34+
(func $main (export "_start")
35+
;; Call fd_write(stdout=1, iovs=0, iovs_len=1, nwritten=100)
36+
i32.const 1 ;; fd: stdout
37+
i32.const 0 ;; iovs: pointer to IoVec array
38+
i32.const 1 ;; iovs_len: we have 1 IoVec
39+
i32.const 100 ;; nwritten: where to store bytes written
40+
call $fd_write
41+
drop ;; ignore return value
42+
)
43+
)
44+
"#;
45+
46+
/// Run the Hello World WASM module
47+
pub fn run() -> Result<(), &'static str> {
48+
tracing::debug!("Running Hello World WASM module");
49+
50+
// Parse WAT to WASM
51+
let buf = ParseBuffer::new(HELLO_WORLD_WAT)
52+
.map_err(|_| "Failed to create parse buffer")?;
53+
let mut wat = wast::parser::parse::<wast::Wat>(&buf)
54+
.map_err(|_| "Failed to parse WAT")?;
55+
56+
// Convert to WASM bytes
57+
let wasm_bytes = wat.encode()
58+
.map_err(|_| "Failed to encode WAT to WASM")?;
59+
60+
// Create engine
61+
let engine = Engine::default();
62+
63+
// Create allocator and store
64+
let alloc = &PlaceholderAllocatorDontUse as &(dyn crate::wasm::vm::InstanceAllocator + Send + Sync);
65+
let mut store = Store::new(&engine, alloc, ());
66+
67+
// Create validator and module from WASM bytes
68+
let mut validator = Validator::new();
69+
let module = Module::from_bytes(&engine, &mut validator, &wasm_bytes)
70+
.map_err(|_| "Failed to create module")?;
71+
72+
// Create linker and register host functions
73+
let mut linker = Linker::new(&engine);
74+
host_funcs::register_host_functions(&mut linker)
75+
.map_err(|_| "Failed to register host functions")?;
76+
77+
// Create const expression evaluator
78+
let mut const_eval = ConstExprEvaluator::default();
79+
80+
// Instantiate module
81+
let instance = linker.instantiate(&mut store, &mut const_eval, &module)
82+
.map_err(|_| "Failed to instantiate module")?;
83+
84+
// Get and call _start function
85+
let start = instance
86+
.get_func(&mut store, "_start")
87+
.ok_or("No _start function found")?;
88+
89+
// Call the function
90+
start.call(&mut store, &[], &mut [])
91+
.map_err(|_| "Failed to call _start")?;
92+
93+
tracing::debug!("Hello World WASM module completed successfully");
94+
Ok(())
95+
}

kernel/src/wasm/mod.rs

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -14,6 +14,7 @@ mod cranelift;
1414
mod engine;
1515
mod func;
1616
mod global;
17+
pub mod hello_world;
1718
pub mod host_funcs;
1819
mod indices;
1920
mod instance;
@@ -30,7 +31,7 @@ mod type_registry;
3031
mod types;
3132
mod utils;
3233
mod values;
33-
mod vm;
34+
pub(crate) mod vm;
3435

3536
pub use engine::Engine;
3637
pub use func::{Caller, Func};

kernel/src/wasm/vm/mod.rs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -9,7 +9,7 @@ mod builtins;
99
mod code_object;
1010
mod const_eval;
1111
mod instance;
12-
mod instance_alloc;
12+
pub(crate) mod instance_alloc;
1313
mod memory;
1414
mod mmap_vec;
1515
mod provenance;

tests/test_hello_world.wast

Lines changed: 32 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,32 @@
1+
;; Test that loads and runs our Hello World WASM program
2+
;; This will demonstrate that stdout works with real WASM programs
3+
4+
(module $hello_world
5+
;; Import fd_write from WASI
6+
(import "wasi_snapshot_preview1" "fd_write"
7+
(func $fd_write (param i32 i32 i32 i32) (result i32)))
8+
9+
;; Memory with at least 1 page
10+
(memory (export "memory") 1)
11+
12+
;; Data segment with our message
13+
(data (i32.const 8) "Hello World from WASIiiiiiiiii!\n")
14+
15+
;; IoVec structure at offset 0
16+
;; Points to our string at offset 8, length 23
17+
(data (i32.const 0) "\08\00\00\00\21\00\00\00")
18+
19+
;; Start function
20+
(func $main (export "_start") (result i32)
21+
;; Call fd_write(stdout=1, iovs=0, iovs_len=1, nwritten=100)
22+
i32.const 1 ;; fd: stdout
23+
i32.const 0 ;; iovs: pointer to IoVec array
24+
i32.const 1 ;; iovs_len: we have 1 IoVec
25+
i32.const 100 ;; nwritten: where to store bytes written
26+
call $fd_write
27+
;; Return the result
28+
)
29+
)
30+
31+
;; The module should successfully execute _start and return 0 (success)
32+
(assert_return (invoke "_start") (i32.const 0))

0 commit comments

Comments
 (0)