diff --git a/Cargo.lock b/Cargo.lock index e11b486f35..d82396cf43 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -2,6 +2,16 @@ # It is not intended for manual editing. version = 4 +[[package]] +name = "aarch64" +version = "0.0.11" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0adf345d8b4e2861016511db094993ee8a9f74195f55ccf62d1305d35ab91bfa" +dependencies = [ + "aarch64-cpu", + "tock-registers 0.8.1", +] + [[package]] name = "aarch64" version = "0.0.13" @@ -598,7 +608,7 @@ dependencies = [ name = "hermit-kernel" version = "0.8.0" dependencies = [ - "aarch64", + "aarch64 0.0.13", "ahash", "align-address", "anstyle", @@ -644,6 +654,7 @@ dependencies = [ "tock-registers 0.9.0", "trapframe", "uart_16550", + "uhyve-interface", "virtio-spec", "volatile 0.6.1", "x86", @@ -1676,6 +1687,18 @@ dependencies = [ "x86", ] +[[package]] +name = "uhyve-interface" +version = "0.1.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "4a2459b911a74b04f4b4b0659aad453a3672d5997589d1aed3b0053af12c22e6" +dependencies = [ + "aarch64 0.0.11", + "memory_addresses", + "num_enum", + "x86_64", +] + [[package]] name = "unicode-ident" version = "1.0.14" diff --git a/Cargo.toml b/Cargo.toml index 14fa107be0..7e68d07702 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -132,6 +132,7 @@ talc = { version = "4" } time = { version = "0.3", default-features = false } volatile = "0.6" zerocopy = { version = "0.8", default-features = false } +uhyve-interface = "0.1.2" [dependencies.smoltcp] version = "0.12" diff --git a/src/fs/uhyve.rs b/src/fs/uhyve.rs index e71aeb4b46..e7782d9f85 100644 --- a/src/fs/uhyve.rs +++ b/src/fs/uhyve.rs @@ -3,14 +3,14 @@ use alloc::boxed::Box; use alloc::string::{String, ToString}; use alloc::sync::Arc; use alloc::vec::Vec; -#[cfg(any(target_arch = "x86_64", target_arch = "aarch64"))] -use core::ptr; use async_lock::Mutex; use async_trait::async_trait; -use memory_addresses::{PhysAddr, VirtAddr}; -#[cfg(target_arch = "x86_64")] -use x86::io::outl; +use memory_addresses::VirtAddr; +use uhyve_interface::parameters::{ + CloseParams, LseekParams, OpenParams, ReadParams, UnlinkParams, WriteParams, +}; +use uhyve_interface::{GuestPhysAddr, GuestVirtAddr, Hypercall}; use crate::arch::mm::paging; use crate::env::is_uhyve; @@ -18,144 +18,7 @@ use crate::fs::{ self, AccessPermission, FileAttr, NodeKind, ObjectInterface, OpenOption, SeekWhence, VfsNode, }; use crate::io; - -/// forward a request to the hypervisor uhyve -#[inline] -#[cfg(target_arch = "x86_64")] -fn uhyve_send(port: u16, data: &mut T) { - let ptr = VirtAddr::from_ptr(ptr::from_mut(data)); - let physical_address = paging::virtual_to_physical(ptr).unwrap(); - - unsafe { - outl(port, physical_address.as_u64() as u32); - } -} - -/// forward a request to the hypervisor uhyve -#[inline] -#[cfg(target_arch = "aarch64")] -fn uhyve_send(port: u16, data: &mut T) { - use core::arch::asm; - - let ptr = VirtAddr::from_ptr(ptr::from_mut(data)); - let physical_address = paging::virtual_to_physical(ptr).unwrap(); - - unsafe { - asm!( - "str x8, [{port}]", - port = in(reg) u64::from(port), - in("x8") physical_address.as_u64(), - options(nostack), - ); - } -} - -/// forward a request to the hypervisor uhyve -#[inline] -#[cfg(target_arch = "riscv64")] -fn uhyve_send(_port: u16, _data: &mut T) { - todo!() -} - -const UHYVE_PORT_WRITE: u16 = 0x400; -const UHYVE_PORT_OPEN: u16 = 0x440; -const UHYVE_PORT_CLOSE: u16 = 0x480; -const UHYVE_PORT_READ: u16 = 0x500; -const UHYVE_PORT_LSEEK: u16 = 0x580; -const UHYVE_PORT_UNLINK: u16 = 0x840; - -#[repr(C, packed)] -struct SysOpen { - name: PhysAddr, - flags: i32, - mode: u32, - ret: i32, -} - -impl SysOpen { - fn new(name: VirtAddr, flags: i32, mode: u32) -> SysOpen { - SysOpen { - name: paging::virtual_to_physical(name).unwrap(), - flags, - mode, - ret: -1, - } - } -} - -#[repr(C, packed)] -struct SysClose { - fd: i32, - ret: i32, -} - -impl SysClose { - fn new(fd: i32) -> SysClose { - SysClose { fd, ret: -1 } - } -} - -#[repr(C, packed)] -struct SysRead { - fd: i32, - buf: *const u8, - len: usize, - ret: isize, -} - -impl SysRead { - fn new(fd: i32, buf: *const u8, len: usize) -> SysRead { - SysRead { - fd, - buf, - len, - ret: -1, - } - } -} - -#[repr(C, packed)] -struct SysWrite { - fd: i32, - buf: *const u8, - len: usize, -} - -impl SysWrite { - pub fn new(fd: i32, buf: *const u8, len: usize) -> SysWrite { - SysWrite { fd, buf, len } - } -} - -#[repr(C, packed)] -struct SysLseek { - pub fd: i32, - pub offset: isize, - pub whence: i32, -} - -impl SysLseek { - fn new(fd: i32, offset: isize, whence: SeekWhence) -> SysLseek { - let whence: i32 = num::ToPrimitive::to_i32(&whence).unwrap(); - - SysLseek { fd, offset, whence } - } -} - -#[repr(C, packed)] -struct SysUnlink { - name: PhysAddr, - ret: i32, -} - -impl SysUnlink { - fn new(name: VirtAddr) -> SysUnlink { - SysUnlink { - name: paging::virtual_to_physical(name).unwrap(), - ret: -1, - } - } -} +use crate::syscalls::interfaces::uhyve::uhyve_hypercall; #[derive(Debug)] struct UhyveFileHandleInner(i32); @@ -166,29 +29,42 @@ impl UhyveFileHandleInner { } fn read(&mut self, buf: &mut [u8]) -> io::Result { - let mut sysread = SysRead::new(self.0, buf.as_mut_ptr(), buf.len()); - uhyve_send(UHYVE_PORT_READ, &mut sysread); + let mut read_params = ReadParams { + fd: self.0, + buf: GuestVirtAddr::new(buf.as_mut_ptr() as u64), + len: buf.len(), + ret: 0, + }; + uhyve_hypercall(Hypercall::FileRead(&mut read_params)); - if sysread.ret >= 0 { - Ok(sysread.ret.try_into().unwrap()) + if read_params.ret >= 0 { + Ok(read_params.ret.try_into().unwrap()) } else { Err(io::Error::EIO) } } fn write(&mut self, buf: &[u8]) -> io::Result { - let mut syswrite = SysWrite::new(self.0, buf.as_ptr(), buf.len()); - uhyve_send(UHYVE_PORT_WRITE, &mut syswrite); + let write_params = WriteParams { + fd: self.0, + buf: GuestVirtAddr::new(buf.as_ptr() as u64), + len: buf.len(), + }; + uhyve_hypercall(Hypercall::FileWrite(&write_params)); - Ok(syswrite.len) + Ok(write_params.len) } fn lseek(&self, offset: isize, whence: SeekWhence) -> io::Result { - let mut syslseek = SysLseek::new(self.0, offset, whence); - uhyve_send(UHYVE_PORT_LSEEK, &mut syslseek); + let mut lseek_params = LseekParams { + fd: self.0, + offset, + whence: num::ToPrimitive::to_i32(&whence).unwrap(), + }; + uhyve_hypercall(Hypercall::FileLseek(&mut lseek_params)); - if syslseek.offset >= 0 { - Ok(syslseek.offset) + if lseek_params.offset >= 0 { + Ok(lseek_params.offset) } else { Err(io::Error::EINVAL) } @@ -197,8 +73,12 @@ impl UhyveFileHandleInner { impl Drop for UhyveFileHandleInner { fn drop(&mut self) { - let mut sysclose = SysClose::new(self.0); - uhyve_send(UHYVE_PORT_CLOSE, &mut sysclose); + let mut close_params = CloseParams { fd: self.0, ret: 0 }; + uhyve_hypercall(Hypercall::FileClose(&mut close_params)); + if close_params.ret != 0 { + let ret = close_params.ret; // circumvent packed field access + panic!("Can't close fd {} - return value {ret}", self.0,); + } } } @@ -274,11 +154,20 @@ impl VfsNode for UhyveDirectory { path }; - let mut sysopen = SysOpen::new(VirtAddr::from_ptr(path.as_ptr()), opt.bits(), mode.bits()); - uhyve_send(UHYVE_PORT_OPEN, &mut sysopen); + let mut open_params = OpenParams { + name: GuestPhysAddr::new( + paging::virtual_to_physical(VirtAddr::from_ptr(path.as_ptr())) + .unwrap() + .as_u64(), + ), + flags: opt.bits(), + mode: mode.bits() as i32, + ret: -1, + }; + uhyve_hypercall(Hypercall::FileOpen(&mut open_params)); - if sysopen.ret > 0 { - Ok(Arc::new(UhyveFileHandle::new(sysopen.ret))) + if open_params.ret > 0 { + Ok(Arc::new(UhyveFileHandle::new(open_params.ret))) } else { Err(io::Error::EIO) } @@ -295,10 +184,17 @@ impl VfsNode for UhyveDirectory { .collect() }; - let mut sysunlink = SysUnlink::new(VirtAddr::from_ptr(path.as_ptr())); - uhyve_send(UHYVE_PORT_UNLINK, &mut sysunlink); + let mut unlink_params = UnlinkParams { + name: GuestPhysAddr::new( + paging::virtual_to_physical(VirtAddr::from_ptr(path.as_ptr())) + .unwrap() + .as_u64(), + ), + ret: -1, + }; + uhyve_hypercall(Hypercall::FileUnlink(&mut unlink_params)); - if sysunlink.ret == 0 { + if unlink_params.ret == 0 { Ok(()) } else { Err(io::Error::EIO) diff --git a/src/syscalls/interfaces/uhyve.rs b/src/syscalls/interfaces/uhyve.rs index f26fffd6dd..f632cc8ab5 100644 --- a/src/syscalls/interfaces/uhyve.rs +++ b/src/syscalls/interfaces/uhyve.rs @@ -1,53 +1,78 @@ +use core::ptr; + use memory_addresses::VirtAddr; +use uhyve_interface::parameters::ExitParams; +use uhyve_interface::{Hypercall, HypercallAddress}; +#[cfg(target_arch = "x86_64")] +use x86::io::*; use crate::arch; use crate::arch::mm::paging; use crate::syscalls::interfaces::SyscallInterface; -const UHYVE_PORT_EXIT: u16 = 0x540; +#[inline] +/// calculates the physical address of the struct passed as reference. +fn data_addr(data: &T) -> u64 { + paging::virtual_to_physical(VirtAddr::from_ptr(ptr::from_ref(data))) + .unwrap() + .as_u64() +} + +#[inline] +/// calculates the hypercall data argument +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), + Hypercall::FileClose(data) => data_addr(*data), + Hypercall::FileLseek(data) => data_addr(*data), + Hypercall::FileOpen(data) => data_addr(*data), + Hypercall::FileRead(data) => data_addr(*data), + Hypercall::FileUnlink(data) => data_addr(*data), + Hypercall::FileWrite(data) => data_addr(*data), + Hypercall::SerialWriteBuffer(data) => data_addr(*data), + Hypercall::SerialWriteByte(byte) => u64::from(*byte), + h => todo!("unimplemented hypercall {h:?}"), + } +} -/// forward a request to the hypervisor uhyve #[inline] -fn uhyve_send(port: u16, data: &mut T) { - let ptr = VirtAddr::from_ptr(data); - let physical_address = paging::virtual_to_physical(ptr).unwrap(); +/// Perform a hypercall to the uhyve hypervisor +pub(crate) fn uhyve_hypercall(hypercall: Hypercall<'_>) { + let ptr = HypercallAddress::from(&hypercall) as u16; + let data = hypercall_data(&hypercall); #[cfg(target_arch = "x86_64")] unsafe { - x86::io::outl(port, physical_address.as_u64() as u32); + outl( + ptr, + data.try_into() + .expect("Hypercall data must lie in the first 4GiB of memory"), + ); } #[cfg(target_arch = "aarch64")] unsafe { - core::arch::asm!( - "str x8, [{port}]", - port = in(reg) u64::from(port), - in("x8") physical_address.as_u64(), + use core::arch::asm; + asm!( + "str x8, [{ptr}]", + ptr = in(reg) u64::from(ptr), + in("x8") data, options(nostack), ); } #[cfg(target_arch = "riscv64")] - todo!("uhyve_send(port = {port}, physical_address = {physical_address:p})"); -} - -#[repr(C, packed)] -struct SysExit { - arg: i32, -} - -impl SysExit { - fn new(arg: i32) -> SysExit { - SysExit { arg } - } + todo!() } pub struct Uhyve; impl SyscallInterface for Uhyve { fn shutdown(&self, error_code: i32) -> ! { - let mut sysexit = SysExit::new(error_code); - uhyve_send(UHYVE_PORT_EXIT, &mut sysexit); + let sysexit = ExitParams { arg: error_code }; + uhyve_hypercall(Hypercall::Exit(&sysexit)); loop { arch::processor::halt(); diff --git a/src/syscalls/mod.rs b/src/syscalls/mod.rs index 0f5a428b2d..ba749419da 100644 --- a/src/syscalls/mod.rs +++ b/src/syscalls/mod.rs @@ -33,7 +33,7 @@ use crate::{env, io}; mod condvar; mod entropy; mod futex; -mod interfaces; +pub(crate) mod interfaces; #[cfg(feature = "mmap")] mod mmap; mod processor;