From a5c48af07bfa810a2e99dcd08e7622b8911e5ad3 Mon Sep 17 00:00:00 2001 From: "Panagiotis \"Ivory\" Vasilopoulos" Date: Sat, 25 Oct 2025 17:57:04 +0200 Subject: [PATCH] feat(uhyve): use v2 interface, MmioWrite exits on x86_64 MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit This also removes the usage of ExitArgs, as it is a single integer. Co-authored-by: Ellen Εμιλία Άννα Zscheile Helped-by: Jonathan Klimt --- Cargo.lock | 51 ++++++++++++++++++++++++++++++-- Cargo.toml | 3 +- src/fd/stdio.rs | 19 +++++++++--- src/fs/uhyve.rs | 17 ++++++++--- src/syscalls/interfaces/uhyve.rs | 30 +++++++++---------- 5 files changed, 92 insertions(+), 28 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index c249437705..cdce274482 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -13,6 +13,17 @@ dependencies = [ "tock-registers 0.8.1", ] +[[package]] +name = "aarch64" +version = "0.0.14" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "2df0852593ebb4ed15e4fce123daf16a272b8d4449ae75050d6b9d7cea461a21" +dependencies = [ + "aarch64-cpu 10.0.0", + "memory_addresses", + "tock-registers 0.9.0", +] + [[package]] name = "aarch64-cpu" version = "9.4.0" @@ -22,6 +33,15 @@ dependencies = [ "tock-registers 0.8.1", ] +[[package]] +name = "aarch64-cpu" +version = "10.0.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "6a21cd0131c25c438e19cd6a774adf7e3f64f7f4d723022882facc2dee0f8bc9" +dependencies = [ + "tock-registers 0.9.0", +] + [[package]] name = "aarch64-cpu" version = "11.1.0" @@ -810,6 +830,12 @@ version = "0.5.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "2304e00983f87ffb38b55b444b5e3b60a884b5d30c0fca7d82fe33449bbe55ea" +[[package]] +name = "hermit-abi" +version = "0.5.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "fc0fef456e4baa96da950455cd02c081ca953b141298e41db3fc7e36b1da849c" + [[package]] name = "hermit-entry" version = "0.10.5" @@ -819,7 +845,7 @@ dependencies = [ "align-address", "const_parse", "time", - "uhyve-interface", + "uhyve-interface 0.1.3", ] [[package]] @@ -878,7 +904,7 @@ dependencies = [ "tock-registers 0.10.1", "trapframe", "uart_16550", - "uhyve-interface", + "uhyve-interface 0.2.0", "virtio-spec", "volatile 0.6.1", "x86_64", @@ -1978,6 +2004,12 @@ version = "0.8.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "696941a0aee7e276a165a978b37918fd5d22c55c3d6bda197813070ca9c0f21c" +[[package]] +name = "tock-registers" +version = "0.9.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "2b9e2fdb3a1e862c0661768b7ed25390811df1947a8acbfbefe09b47078d93c4" + [[package]] name = "tock-registers" version = "0.10.1" @@ -2016,7 +2048,20 @@ version = "0.1.3" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "7390116b0481b52dbc7d979f858dcc426494714a3ba03e9534d26c8ea41b899e" dependencies = [ - "aarch64", + "aarch64 0.0.13", + "memory_addresses", + "num_enum", + "x86_64", +] + +[[package]] +name = "uhyve-interface" +version = "0.2.0" +source = "git+https://github.com/n0toose/uhyve?branch=uhyve_if_v2-mmiowrite#9e0e18004a6937dd306b4488582cf6b735e2ce1c" +dependencies = [ + "aarch64 0.0.14", + "bitflags 2.10.0", + "hermit-abi", "memory_addresses", "num_enum", "x86_64", diff --git a/Cargo.toml b/Cargo.toml index ea95196676..0af730ff6c 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -146,7 +146,7 @@ thiserror = { version = "2", default-features = false } time = { version = "0.3", default-features = false } volatile = "0.6" zerocopy = { version = "0.8", default-features = false } -uhyve-interface = "0.1.3" +uhyve-interface = "0.2.0" [dependencies.smoltcp] version = "0.12" @@ -215,6 +215,7 @@ exclude = [ ] [patch.crates-io] +uhyve-interface = { git = "https://github.com/n0toose/uhyve", branch = 'uhyve_if_v2-mmiowrite' } x86_64 = { git = "https://github.com/rust-osdev/x86_64.git" } # FIXME: remove once merged: https://github.com/rcore-os/trapframe-rs/pull/16 trapframe = { git = "https://github.com/hermit-os/trapframe-rs", branch = "global_asm" } diff --git a/src/fd/stdio.rs b/src/fd/stdio.rs index 22ed092706..87bac7b28a 100644 --- a/src/fd/stdio.rs +++ b/src/fd/stdio.rs @@ -4,9 +4,12 @@ use core::task::Poll; use async_trait::async_trait; use embedded_io::{Read, ReadReady, Write}; -use uhyve_interface::parameters::WriteParams; -use uhyve_interface::{GuestVirtAddr, Hypercall}; +use memory_addresses::VirtAddr; +use uhyve_interface::GuestPhysAddr; +use uhyve_interface::v2::Hypercall; +use uhyve_interface::v2::parameters::WriteParams; +use crate::arch::mm::paging; use crate::console::{CONSOLE, CONSOLE_WAKER}; use crate::fd::{ AccessPermission, FileAttr, ObjectInterface, PollEvent, STDERR_FILENO, STDOUT_FILENO, @@ -166,7 +169,11 @@ impl ObjectInterface for UhyveStdout { async fn write(&self, buf: &[u8]) -> io::Result { let write_params = WriteParams { fd: STDOUT_FILENO, - buf: GuestVirtAddr::new(buf.as_ptr() as u64), + buf: GuestPhysAddr::new( + paging::virtual_to_physical(VirtAddr::from_ptr(buf.as_ptr())) + .unwrap() + .as_u64(), + ), len: buf.len(), }; uhyve_hypercall(Hypercall::FileWrite(&write_params)); @@ -206,7 +213,11 @@ impl ObjectInterface for UhyveStderr { async fn write(&self, buf: &[u8]) -> io::Result { let write_params = WriteParams { fd: STDERR_FILENO, - buf: GuestVirtAddr::new(buf.as_ptr() as u64), + buf: GuestPhysAddr::new( + paging::virtual_to_physical(VirtAddr::from_ptr(buf.as_ptr())) + .unwrap() + .as_u64(), + ), len: buf.len(), }; uhyve_hypercall(Hypercall::FileWrite(&write_params)); diff --git a/src/fs/uhyve.rs b/src/fs/uhyve.rs index dce0a4fe58..9525ea5612 100644 --- a/src/fs/uhyve.rs +++ b/src/fs/uhyve.rs @@ -9,10 +9,11 @@ use async_lock::Mutex; use async_trait::async_trait; use embedded_io::{ErrorType, Read, Write}; use memory_addresses::VirtAddr; -use uhyve_interface::parameters::{ +use uhyve_interface::GuestPhysAddr; +use uhyve_interface::v2::Hypercall; +use uhyve_interface::v2::parameters::{ CloseParams, LseekParams, OpenParams, ReadParams, UnlinkParams, WriteParams, }; -use uhyve_interface::{GuestPhysAddr, GuestVirtAddr, Hypercall}; use crate::arch::mm::paging; use crate::env::fdt; @@ -56,7 +57,11 @@ impl Read for UhyveFileHandleInner { fn read(&mut self, buf: &mut [u8]) -> Result { let mut read_params = ReadParams { fd: self.0, - buf: GuestVirtAddr::new(buf.as_mut_ptr() as u64), + buf: GuestPhysAddr::new( + paging::virtual_to_physical(VirtAddr::from_ptr(buf.as_mut_ptr())) + .unwrap() + .as_u64(), + ), len: buf.len(), ret: 0, }; @@ -74,7 +79,11 @@ impl Write for UhyveFileHandleInner { fn write(&mut self, buf: &[u8]) -> Result { let write_params = WriteParams { fd: self.0, - buf: GuestVirtAddr::new(buf.as_ptr() as u64), + buf: GuestPhysAddr::new( + paging::virtual_to_physical(VirtAddr::from_ptr(buf.as_ptr())) + .unwrap() + .as_u64(), + ), len: buf.len(), }; uhyve_hypercall(Hypercall::FileWrite(&write_params)); diff --git a/src/syscalls/interfaces/uhyve.rs b/src/syscalls/interfaces/uhyve.rs index 06dde48495..20b33a7f7d 100644 --- a/src/syscalls/interfaces/uhyve.rs +++ b/src/syscalls/interfaces/uhyve.rs @@ -1,14 +1,14 @@ use core::ptr; use memory_addresses::VirtAddr; -use uhyve_interface::parameters::{ExitParams, SerialWriteBufferParams}; -use uhyve_interface::{Hypercall, HypercallAddress}; +use uhyve_interface::v2::parameters::SerialWriteBufferParams; +use uhyve_interface::v2::{Hypercall, HypercallAddress}; use crate::arch; use crate::arch::mm::paging::{self, virtual_to_physical}; use crate::syscalls::interfaces::SyscallInterface; -/// perform a SerialWriteBuffer hypercall with `buf` as payload. +/// perform a SerialWriteBuffer hypercall with `buf` as payload #[inline] #[cfg_attr(target_arch = "riscv64", expect(dead_code))] pub(crate) fn serial_buf_hypercall(buf: &[u8]) { @@ -31,9 +31,11 @@ fn data_addr(data: &T) -> u64 { #[inline] fn hypercall_data(hypercall: &Hypercall<'_>) -> u64 { match hypercall { - Hypercall::Cmdsize(data) => data_addr(*data), - Hypercall::Cmdval(data) => data_addr(*data), - Hypercall::Exit(data) => data_addr(*data), + // As we are encoding an exit code (max 32 bits) into "an + // address", and memory_addresses complains if an address + // has any bits above the 48th one set to 1, we encode + // potential negative numbers into a u32, then a u64. + Hypercall::Exit(exit_code) => (*exit_code) as u32 as u64, Hypercall::FileClose(data) => data_addr(*data), Hypercall::FileLseek(data) => data_addr(*data), Hypercall::FileOpen(data) => data_addr(*data), @@ -50,16 +52,13 @@ fn hypercall_data(hypercall: &Hypercall<'_>) -> u64 { #[inline] #[allow(unused_variables)] // until riscv64 is implemented pub(crate) fn uhyve_hypercall(hypercall: Hypercall<'_>) { - let ptr = HypercallAddress::from(&hypercall) as u16; + let ptr = HypercallAddress::from(&hypercall) as u64; let data = hypercall_data(&hypercall); #[cfg(target_arch = "x86_64")] - unsafe { - use x86_64::instructions::port::Port; - - let data = - u32::try_from(data).expect("Hypercall data must lie in the first 4GiB of memory"); - Port::new(ptr).write(data); + { + let ptr = ptr as *mut u64; + unsafe { ptr.write_volatile(data) }; } #[cfg(target_arch = "aarch64")] @@ -67,7 +66,7 @@ pub(crate) fn uhyve_hypercall(hypercall: Hypercall<'_>) { use core::arch::asm; asm!( "str x8, [{ptr}]", - ptr = in(reg) u64::from(ptr), + ptr = in(reg) ptr, in("x8") data, options(nostack), ); @@ -81,8 +80,7 @@ pub struct Uhyve; impl SyscallInterface for Uhyve { fn shutdown(&self, error_code: i32) -> ! { - let sysexit = ExitParams { arg: error_code }; - uhyve_hypercall(Hypercall::Exit(&sysexit)); + uhyve_hypercall(Hypercall::Exit(error_code)); loop { arch::processor::halt();