66 lines
3.2 KiB
Rust
66 lines
3.2 KiB
Rust
// Generate syscall numbers and status codes from the C++ headers so Rust
|
|
// never becomes another hand-maintained copy of the syscall table.
|
|
//
|
|
// programs/include/Api/Syscall.hpp -> pub const SYS_*: u64
|
|
// kernel/src/Common/StatusCodes.hpp -> pub enum Status (positive values,
|
|
// matching montauk/statuscodes.h)
|
|
|
|
use std::env;
|
|
use std::fs;
|
|
use std::path::PathBuf;
|
|
|
|
fn main() {
|
|
let manifest = PathBuf::from(env::var("CARGO_MANIFEST_DIR").unwrap());
|
|
let repo = manifest.join("../../..");
|
|
let syscall_hpp = repo.join("programs/include/Api/Syscall.hpp");
|
|
let status_hpp = repo.join("kernel/src/Common/StatusCodes.hpp");
|
|
println!("cargo:rerun-if-changed={}", syscall_hpp.display());
|
|
println!("cargo:rerun-if-changed={}", status_hpp.display());
|
|
|
|
let mut out = String::from("// @generated by montauk-rt/build.rs - do not edit.\n\n");
|
|
|
|
// static constexpr uint64_t SYS_NAME = 123; (decimal literals only)
|
|
let syscalls = fs::read_to_string(&syscall_hpp).expect("read Syscall.hpp");
|
|
let mut count = 0;
|
|
for line in syscalls.lines() {
|
|
let line = line.trim();
|
|
let Some(rest) = line.strip_prefix("static constexpr uint64_t SYS_") else { continue };
|
|
let Some((name, value)) = rest.split_once('=') else { continue };
|
|
let value = value.split(';').next().unwrap_or("").trim();
|
|
if value.is_empty() || !value.bytes().all(|b| b.is_ascii_digit()) {
|
|
continue;
|
|
}
|
|
out.push_str(&format!("pub const SYS_{}: u64 = {};\n", name.trim(), value));
|
|
count += 1;
|
|
}
|
|
assert!(count > 100, "parsed only {count} syscalls from {}", syscall_hpp.display());
|
|
|
|
// enum StatusCodes { Success = 0, GenericFailure = -1, ... };
|
|
let status = fs::read_to_string(&status_hpp).expect("read StatusCodes.hpp");
|
|
let body = status
|
|
.split_once("enum StatusCodes")
|
|
.and_then(|(_, rest)| rest.split_once('{'))
|
|
.and_then(|(_, rest)| rest.split_once('}'))
|
|
.map(|(body, _)| body)
|
|
.expect("enum StatusCodes not found");
|
|
out.push_str("\n/// Kernel status codes, stored positive like montauk/statuscodes.h.\n");
|
|
out.push_str("/// The kernel returns them negated; see [`Status::from_result`].\n");
|
|
out.push_str("#[derive(Clone, Copy, Debug, PartialEq, Eq)]\n#[repr(i32)]\npub enum Status {\n");
|
|
let mut variants = Vec::new();
|
|
for entry in body.split(',') {
|
|
let entry = entry.split("//").next().unwrap_or("").trim();
|
|
let Some((name, value)) = entry.split_once('=') else { continue };
|
|
let value: i32 = value.trim().parse().expect("status value");
|
|
out.push_str(&format!(" {} = {},\n", name.trim(), -value));
|
|
variants.push((name.trim().to_string(), -value));
|
|
}
|
|
out.push_str("}\n\nimpl Status {\n pub const fn from_code(code: i32) -> Status {\n match code {\n");
|
|
for (name, value) in &variants {
|
|
out.push_str(&format!(" {} => Status::{},\n", value, name));
|
|
}
|
|
out.push_str(" _ => Status::GenericFailure,\n }\n }\n}\n");
|
|
|
|
let dest = PathBuf::from(env::var("OUT_DIR").unwrap()).join("abi.rs");
|
|
fs::write(dest, out).expect("write abi.rs");
|
|
}
|