use std::io::Write;
use std::sync::{Arc, Mutex};
use nixvm::abi::Arch;
use nixvm::fs::MountTable;
use nixvm::kernel::Kernel;
use nixvm::vcpu::Backend;
use nixvm::vcpu::GuestMemory;
use nixvm::vcpu::interp::InterpBackend;
use nixvm::vcpu::mem::{PAGE_SIZE, Prot};
#[derive(Clone)]
struct SharedBuf(Arc<Mutex<Vec<u8>>>);
impl Write for SharedBuf {
fn write(&mut self, buf: &[u8]) -> std::io::Result<usize> {
self.0.lock().unwrap().extend_from_slice(buf);
Ok(buf.len())
}
fn flush(&mut self) -> std::io::Result<()> {
Ok(())
}
}
#[test]
fn hello_world_runs_and_exits() {
let base = 0x1_0000u64;
let code = base;
let data = base + PAGE_SIZE; let stack = base + 60 * PAGE_SIZE;
let program: [u32; 9] = [
0xD280_0020,
0xD282_0001,
0xF2A0_0021,
0xD280_0062,
0xD280_0808,
0xD400_0001,
0xD280_0000,
0xD280_0BA8,
0xD400_0001,
];
let mut mem = GuestMemory::new(base, 64 * PAGE_SIZE);
mem.map(code, PAGE_SIZE, Prot::rx()).unwrap();
mem.map(data, PAGE_SIZE, Prot::READ).unwrap();
let mut bytes = Vec::new();
for w in program {
bytes.extend_from_slice(&w.to_le_bytes());
}
mem.write_init(code, &bytes).unwrap();
mem.write_init(data, b"hi\n").unwrap();
let backend = InterpBackend::new(Arch::Aarch64).unwrap();
let vcpu = backend.new_vcpu(code, stack).unwrap();
let captured = Arc::new(Mutex::new(Vec::new()));
let mut kernel = Kernel::new(Arch::Aarch64, MountTable::new());
kernel.set_stdout(Box::new(SharedBuf(captured.clone())));
let exit_code = kernel.run(vcpu, mem).unwrap();
assert_eq!(exit_code, 0, "guest should exit with status 0");
assert_eq!(&*captured.lock().unwrap(), b"hi\n", "guest should print hi");
assert!(
kernel.unsupported().is_empty(),
"unexpected: {:?}",
kernel.unsupported()
);
}