Next Generation WASM Microkernel Operating System
wasm
os
rust
microkernel
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
8use crate::profile::Profile;
9use crate::tracing::OutputOptions;
10use crate::{Options, build, qemu};
11use clap::{Parser, ValueHint};
12use std::path::PathBuf;
13use std::process::{Command, Stdio};
14use std::{fs, thread};
15
16#[derive(Debug, Parser)]
17pub struct Cmd {
18 /// The path to the build configuration file
19 #[clap(value_hint = ValueHint::FilePath)]
20 profile: PathBuf,
21 /// The TCP port to listen for debug connections on.
22 #[clap(long, default_value = "1234")]
23 gdb_port: u16,
24 /// Extra arguments passed to QEMU.
25 #[clap(raw = true, conflicts_with = "norun")]
26 qemu_args: Vec<String>,
27 /// Do not start a new k23 instance; just run `lldb`
28 #[clap(long, short, conflicts_with = "gdb_port", conflicts_with = "qemu_args")]
29 norun: bool,
30}
31
32impl Cmd {
33 pub fn run(&self, opts: &Options, output: &OutputOptions) -> crate::Result<()> {
34 let profile = Profile::from_file(&self.profile)?;
35
36 let target_dir = opts
37 .target_dir
38 .clone()
39 .unwrap_or(PathBuf::from("target"))
40 .canonicalize()?;
41
42 let (kernel, loader) = if !self.norun {
43 let qemu_opts = qemu::QemuOptions {
44 wait_for_debugger: true,
45 gdb_port: self.gdb_port,
46 qemu_args: self.qemu_args.clone(),
47 };
48
49 let kernel = build::build_kernel(opts, output, &profile)?;
50 let loader = build::build_loader(opts, output, &profile, &kernel)?;
51
52 let mut qemu = qemu::spawn(&qemu_opts, profile, &loader, false, &[])?;
53 thread::spawn(move || qemu.0.wait().unwrap().exit_ok().unwrap());
54
55 (kernel, loader)
56 } else {
57 let kernel = target_dir
58 .join(profile.kernel.target.resolve(&profile).name())
59 .join("debug")
60 .join("kernel");
61
62 let loader = target_dir
63 .join(profile.loader.target.resolve(&profile).name())
64 .join("debug")
65 .join("loader");
66
67 (kernel, loader)
68 };
69
70 let lldb_script = target_dir.join("lldb_script.txt");
71 fs::write(
72 &lldb_script,
73 format!(
74 r#"
75 target create {loader}
76 target modules add {kernel}
77 target modules load --file {kernel} -s 0xffffffc000000000
78 gdb-remote localhost:{gdb_port}
79 "#,
80 loader = loader.display(),
81 kernel = kernel.display(),
82 gdb_port = self.gdb_port,
83 ),
84 )?;
85
86 Command::new("rust-lldb")
87 .args(["-s", lldb_script.to_str().unwrap()])
88 .stdin(Stdio::inherit())
89 .stdout(Stdio::inherit())
90 .stderr(Stdio::inherit())
91 .output()?;
92
93 Ok(())
94 }
95}