diff --git a/src/hypercall.rs b/src/hypercall.rs index 9e667f9d..e36dafa4 100644 --- a/src/hypercall.rs +++ b/src/hypercall.rs @@ -4,7 +4,10 @@ use std::{ os::unix::ffi::OsStrExt, }; -use uhyve_interface::{parameters::*, GuestPhysAddr, Hypercall, HypercallAddress, MAX_ARGC_ENVC}; +use uhyve_interface::{ + v1::{parameters::*, Hypercall, HypercallAddress, MAX_ARGC_ENVC}, + GuestPhysAddr, +}; use crate::{ consts::BOOT_PML4, diff --git a/src/linux/x86_64/kvm_cpu.rs b/src/linux/x86_64/kvm_cpu.rs index ac31c2fd..6ab4872c 100644 --- a/src/linux/x86_64/kvm_cpu.rs +++ b/src/linux/x86_64/kvm_cpu.rs @@ -2,7 +2,7 @@ use std::sync::Arc; use kvm_bindings::*; use kvm_ioctls::{VcpuExit, VcpuFd, VmFd}; -use uhyve_interface::{GuestPhysAddr, Hypercall}; +use uhyve_interface::{v1::Hypercall, GuestPhysAddr}; use vmm_sys_util::eventfd::EventFd; use x86_64::registers::control::{Cr0Flags, Cr4Flags}; diff --git a/src/macos/aarch64/vcpu.rs b/src/macos/aarch64/vcpu.rs index bdfbb614..73b0b4cc 100644 --- a/src/macos/aarch64/vcpu.rs +++ b/src/macos/aarch64/vcpu.rs @@ -4,7 +4,7 @@ use std::sync::Arc; use log::debug; -use uhyve_interface::{GuestPhysAddr, Hypercall}; +use uhyve_interface::{v1::Hypercall, GuestPhysAddr}; use xhypervisor::{ self, create_vm, map_mem, MemPerm, Register, SystemRegister, VirtualCpuExitReason, }; diff --git a/src/macos/x86_64/vcpu.rs b/src/macos/x86_64/vcpu.rs index 7a155942..819b2d54 100644 --- a/src/macos/x86_64/vcpu.rs +++ b/src/macos/x86_64/vcpu.rs @@ -7,7 +7,7 @@ use std::{ use burst::x86::{disassemble_64, InstructionOperation, OperandType}; use log::{debug, trace}; -use uhyve_interface::{GuestPhysAddr, Hypercall}; +use uhyve_interface::{v1::Hypercall, GuestPhysAddr}; use x86_64::{ registers::control::{Cr0Flags, Cr4Flags}, structures::gdt::SegmentSelector, diff --git a/src/vm.rs b/src/vm.rs index f3b9e65b..ac2de51b 100644 --- a/src/vm.rs +++ b/src/vm.rs @@ -268,7 +268,7 @@ impl UhyveVm { phys_addr_range: self.mem.guest_address.as_u64() ..self.mem.guest_address.as_u64() + self.mem.memory_size as u64, serial_port_base: self.verbose().then(|| { - SerialPortBase::new((uhyve_interface::HypercallAddress::Uart as u16).into()) + SerialPortBase::new((uhyve_interface::v1::HypercallAddress::Uart as u16).into()) .unwrap() }), device_tree: Some(FDT_ADDR.as_u64().try_into().unwrap()), diff --git a/tests/test-kernels/src/bin/serial.rs b/tests/test-kernels/src/bin/serial.rs index dd1af2af..47a41af8 100644 --- a/tests/test-kernels/src/bin/serial.rs +++ b/tests/test-kernels/src/bin/serial.rs @@ -1,6 +1,9 @@ #[cfg(target_os = "hermit")] use hermit as _; -use uhyve_interface::{parameters::SerialWriteBufferParams, GuestPhysAddr, HypercallAddress}; +use uhyve_interface::{ + v1::{parameters::SerialWriteBufferParams, HypercallAddress}, + GuestPhysAddr, +}; #[cfg(target_arch = "x86_64")] use x86_64::{ instructions::port::Port, diff --git a/uhyve-interface/src/lib.rs b/uhyve-interface/src/lib.rs index d925a491..670fa906 100644 --- a/uhyve-interface/src/lib.rs +++ b/uhyve-interface/src/lib.rs @@ -1,19 +1,10 @@ //! # Uhyve Hypervisor Interface -//! -//! The Uhyve hypercall interface works as follows: -//! -//! - On `x86_64` you use an out port instruction. The address of the `out`-port corresponds to the -//! hypercall you want to use. You can obtain it from the [`IoPorts`] enum. The data send to -//! that port is the physical memory address (of the VM) of the parameters of that hypercall. -//! - On `aarch64` you write to the respective [`HypercallAddress`]. The 64-bit value written to that location is the guest's physical memory address of the hypercall's parameter. #![cfg_attr(not(feature = "std"), no_std)] -// TODO: Throw this out, once https://github.com/rust-lang/rfcs/issues/2783 or https://github.com/rust-lang/rust/issues/86772 is resolved -use num_enum::TryFromPrimitive; - pub mod elf; -pub mod parameters; +/// Version 1 of the Hypercall Interface +pub mod v1; #[cfg(target_arch = "aarch64")] pub use ::aarch64::paging::PhysAddr as GuestPhysAddr; @@ -26,123 +17,7 @@ pub use ::x86_64::addr::VirtAddr as GuestVirtAddr; #[cfg(not(target_pointer_width = "64"))] compile_error!("Using uhyve-interface on a non-64-bit system is not (yet?) supported"); -use parameters::*; /// The version of the Uhyve interface. Note: This is not the same as the semver of the crate but /// should be increased on every version bump that changes the API. -pub const UHYVE_INTERFACE_VERSION: u32 = 1; - -/// Enum containing all valid port mappings for hypercalls. -/// -/// The discriminants of this enum are the respective ports, so one can get the code by calling -/// e.g., `HypercallPorts::FileWrite as u16`. -#[non_exhaustive] -#[repr(u16)] -#[derive(Debug, Eq, PartialEq, TryFromPrimitive)] -pub enum HypercallAddress { - /// Port address = `0x400` - FileWrite = 0x400, - /// Port address = `0x440` - FileOpen = 0x440, - /// Port address = `0x480` - FileClose = 0x480, - /// Port address = `0x500` - FileRead = 0x500, - /// Port address = `0x540` - Exit = 0x540, - /// Port address = `0x580` - FileLseek = 0x580, - #[deprecated = "was never really in use"] - /// Port address = `0x640` - Netwrite = 0x640, - #[deprecated = "was never really in use"] - /// Port address = `0x680` - Netread = 0x680, - #[deprecated = "was never really in use"] - /// Port address = `0x700` - Netstat = 0x700, - /// Port address = `0x740` - Cmdsize = 0x740, - /// Port address = `0x780` - Cmdval = 0x780, - /// Port address = `0x800` - Uart = 0x800, - /// Port address = `0x840` - FileUnlink = 0x840, - /// Port address = `0x880` - SerialBufferWrite = 0x880, -} -// TODO: Remove this in the next major version -impl From> for HypercallAddress { - fn from(value: Hypercall) -> Self { - match value { - Hypercall::Cmdsize(_) => Self::Cmdsize, - Hypercall::Cmdval(_) => Self::Cmdval, - Hypercall::Exit(_) => Self::Exit, - Hypercall::FileClose(_) => Self::FileClose, - Hypercall::FileLseek(_) => Self::FileLseek, - Hypercall::FileOpen(_) => Self::FileOpen, - Hypercall::FileRead(_) => Self::FileRead, - Hypercall::FileWrite(_) => Self::FileWrite, - Hypercall::FileUnlink(_) => Self::FileUnlink, - Hypercall::SerialWriteByte(_) => Self::Uart, - Hypercall::SerialWriteBuffer(_) => Self::SerialBufferWrite, - } - } -} -impl From<&Hypercall<'_>> for HypercallAddress { - fn from(value: &Hypercall) -> Self { - match value { - Hypercall::Cmdsize(_) => Self::Cmdsize, - Hypercall::Cmdval(_) => Self::Cmdval, - Hypercall::Exit(_) => Self::Exit, - Hypercall::FileClose(_) => Self::FileClose, - Hypercall::FileLseek(_) => Self::FileLseek, - Hypercall::FileOpen(_) => Self::FileOpen, - Hypercall::FileRead(_) => Self::FileRead, - Hypercall::FileWrite(_) => Self::FileWrite, - Hypercall::FileUnlink(_) => Self::FileUnlink, - Hypercall::SerialWriteByte(_) => Self::Uart, - Hypercall::SerialWriteBuffer(_) => Self::SerialBufferWrite, - } - } -} - -/// Hypervisor calls available in Uhyve with their respective parameters. See the [module level documentation](crate) on how to invoke them. -#[non_exhaustive] -#[derive(Debug)] -pub enum Hypercall<'a> { - /// Get the size of the argument and environment strings. Used to allocate memory for - /// [`Hypercall::Cmdval`]. - Cmdsize(&'a mut CmdsizeParams), - /// Copy the argument and environment strings into the VM. Usually preceeeded by - /// [`Hypercall::Cmdsize`] so that the guest can allocate the memory for this call. - Cmdval(&'a CmdvalParams), - /// Exit the VM and return a status. - Exit(&'a ExitParams), - FileClose(&'a mut CloseParams), - FileLseek(&'a mut LseekParams), - FileOpen(&'a mut OpenParams), - FileRead(&'a mut ReadParams), - FileWrite(&'a WriteParams), - FileUnlink(&'a mut UnlinkParams), - /// Write a char to the terminal. - SerialWriteByte(u8), - /// Write a buffer to the terminal. - SerialWriteBuffer(&'a SerialWriteBufferParams), -} -impl<'a> Hypercall<'a> { - // TODO: Remove this in the next major version - /// Get a hypercall's port address. - pub fn port(self) -> u16 { - HypercallAddress::from(self) as u16 - } -} - -// Networkports (not used at the moment) -// TODO: Remove this -pub const UHYVE_PORT_NETWRITE: u16 = 0x640; - -// FIXME: Do not use a fix number of arguments -/// The maximum number of items in an argument of environment vector. -pub const MAX_ARGC_ENVC: usize = 128; +pub const UHYVE_INTERFACE_VERSION: u32 = 2; diff --git a/uhyve-interface/src/v1/mod.rs b/uhyve-interface/src/v1/mod.rs new file mode 100644 index 00000000..b3015c20 --- /dev/null +++ b/uhyve-interface/src/v1/mod.rs @@ -0,0 +1,111 @@ +//! # Uhyve Hypervisor Interface V1 +//! +//! The Uhyve hypercall interface works as follows: +//! +//! - On `x86_64` you use an out port instruction. The address of the `out`-port corresponds to the +//! hypercall you want to use. You can obtain it from the [`HypercallAddress`](v1::HypercallAddress) enum. The data send to +//! that port is the physical memory address (of the VM) of the parameters of that hypercall. +//! - On `aarch64` you write to the respective [`HypercallAddress`](v1::HypercallAddress). The 64-bit value written to that location is the guest's physical memory address of the hypercall's parameter. + +// TODO: Throw this out, once https://github.com/rust-lang/rfcs/issues/2783 or https://github.com/rust-lang/rust/issues/86772 is resolved + +use num_enum::TryFromPrimitive; + +pub mod parameters; +use crate::v1::parameters::*; + +/// Enum containing all valid port mappings for hypercalls. +/// +/// The discriminants of this enum are the respective ports, so one can get the code by calling +/// e.g., `HypercallPorts::FileWrite as u16`. +#[non_exhaustive] +#[repr(u16)] +#[derive(Debug, Eq, PartialEq, TryFromPrimitive)] +pub enum HypercallAddress { + /// Port address = `0x400` + FileWrite = 0x400, + /// Port address = `0x440` + FileOpen = 0x440, + /// Port address = `0x480` + FileClose = 0x480, + /// Port address = `0x500` + FileRead = 0x500, + /// Port address = `0x540` + Exit = 0x540, + /// Port address = `0x580` + FileLseek = 0x580, + #[deprecated = "was never really in use"] + /// Port address = `0x640` + Netwrite = 0x640, + #[deprecated = "was never really in use"] + /// Port address = `0x680` + Netread = 0x680, + #[deprecated = "was never really in use"] + /// Port address = `0x700` + Netstat = 0x700, + /// Port address = `0x740` + Cmdsize = 0x740, + /// Port address = `0x780` + Cmdval = 0x780, + /// Port address = `0x800` + Uart = 0x800, + /// Port address = `0x840` + FileUnlink = 0x840, + /// Port address = `0x880` + SerialBufferWrite = 0x880, +} +impl From> for HypercallAddress { + fn from(value: Hypercall) -> Self { + match value { + Hypercall::Cmdsize(_) => Self::Cmdsize, + Hypercall::Cmdval(_) => Self::Cmdval, + Hypercall::Exit(_) => Self::Exit, + Hypercall::FileClose(_) => Self::FileClose, + Hypercall::FileLseek(_) => Self::FileLseek, + Hypercall::FileOpen(_) => Self::FileOpen, + Hypercall::FileRead(_) => Self::FileRead, + Hypercall::FileWrite(_) => Self::FileWrite, + Hypercall::FileUnlink(_) => Self::FileUnlink, + Hypercall::SerialWriteByte(_) => Self::Uart, + Hypercall::SerialWriteBuffer(_) => Self::SerialBufferWrite, + } + } +} + +/// Hypervisor calls available in Uhyve with their respective parameters. See the [module level documentation](crate) on how to invoke them. +#[non_exhaustive] +#[derive(Debug)] +pub enum Hypercall<'a> { + /// Get the size of the argument and environment strings. Used to allocate memory for + /// [`Hypercall::Cmdval`]. + Cmdsize(&'a mut CmdsizeParams), + /// Copy the argument and environment strings into the VM. Usually preceeeded by + /// [`Hypercall::Cmdsize`] so that the guest can allocate the memory for this call. + Cmdval(&'a CmdvalParams), + /// Exit the VM and return a status. + Exit(&'a ExitParams), + FileClose(&'a mut CloseParams), + FileLseek(&'a mut LseekParams), + FileOpen(&'a mut OpenParams), + FileRead(&'a mut ReadParams), + FileWrite(&'a WriteParams), + FileUnlink(&'a mut UnlinkParams), + /// Write a char to the terminal. + SerialWriteByte(u8), + /// Write a buffer to the terminal. + SerialWriteBuffer(&'a SerialWriteBufferParams), +} +impl<'a> Hypercall<'a> { + /// Get a hypercall's port address. + pub fn port(self) -> u16 { + HypercallAddress::from(self) as u16 + } +} + +// Networkports (not used at the moment) +// TODO: Remove this +pub const UHYVE_PORT_NETWRITE: u16 = 0x640; + +// FIXME: Do not use a fix number of arguments +/// The maximum number of items in an argument of environment vector. +pub const MAX_ARGC_ENVC: usize = 128; diff --git a/uhyve-interface/src/parameters.rs b/uhyve-interface/src/v1/parameters.rs similarity index 76% rename from uhyve-interface/src/parameters.rs rename to uhyve-interface/src/v1/parameters.rs index e255ae08..4b7691f7 100644 --- a/uhyve-interface/src/parameters.rs +++ b/uhyve-interface/src/v1/parameters.rs @@ -1,8 +1,8 @@ //! Parameters for hypercalls. -use crate::{GuestPhysAddr, GuestVirtAddr, MAX_ARGC_ENVC}; +use crate::{v1::MAX_ARGC_ENVC, GuestPhysAddr, GuestVirtAddr}; -/// Parameters for a [`Cmdsize`](crate::Hypercall::Cmdsize) hypercall which provides the lengths of the items in the argument end environment vector. +/// Parameters for a [`Cmdsize`](crate::v1::Hypercall::Cmdsize) hypercall which provides the lengths of the items in the argument end environment vector. #[repr(C, packed)] #[derive(Debug, Copy, Clone)] pub struct CmdsizeParams { @@ -21,7 +21,7 @@ impl CmdsizeParams { /// - `path` is usually the path and name of the application. E.g., "/home/hermit/app" /// - `args` is a list of strings that form the parameters. (E.g., `["-v", "myarg"]`) /// - /// Note that this hypercall only transfers the sizes. It usually has to be followed up with the [`Cmdval` Hypercall](crate::Hypercall::Cmdval). + /// Note that this hypercall only transfers the sizes. It usually has to be followed up with the [`Cmdval` Hypercall](crate::v1::Hypercall::Cmdval). pub fn update(&mut self, path: &std::path::Path, args: &[String]) { self.argc = 0; @@ -47,7 +47,7 @@ impl CmdsizeParams { } } -/// Parameters for a [`Cmdval`](crate::Hypercall::Cmdval) hypercall, which copies the arguments end environment of the application into the VM's memory. +/// Parameters for a [`Cmdval`](crate::v1::Hypercall::Cmdval) hypercall, which copies the arguments end environment of the application into the VM's memory. #[repr(C, packed)] #[derive(Debug, Copy, Clone)] pub struct CmdvalParams { @@ -57,7 +57,7 @@ pub struct CmdvalParams { pub envp: GuestPhysAddr, } -/// Parameters for a [`Exit`](crate::Hypercall::Exit) hypercall. +/// Parameters for a [`Exit`](crate::v1::Hypercall::Exit) hypercall. #[repr(C, packed)] #[derive(Debug, Copy, Clone)] pub struct ExitParams { @@ -65,7 +65,7 @@ pub struct ExitParams { pub arg: i32, } -/// Parameters for a [`FileUnlink`](crate::Hypercall::FileUnlink) hypercall. +/// Parameters for a [`FileUnlink`](crate::v1::Hypercall::FileUnlink) hypercall. #[repr(C, packed)] #[derive(Debug, Copy, Clone)] pub struct UnlinkParams { @@ -75,7 +75,7 @@ pub struct UnlinkParams { pub ret: i32, } -/// Parameters for a [`FileWrite`](crate::Hypercall::FileWrite) hypercall. +/// Parameters for a [`FileWrite`](crate::v1::Hypercall::FileWrite) hypercall. #[repr(C, packed)] #[derive(Debug, Copy, Clone)] pub struct WriteParams { @@ -87,7 +87,7 @@ pub struct WriteParams { pub len: usize, } -/// Parameters for a [`FileRead`](crate::Hypercall::FileRead) hypercall. +/// Parameters for a [`FileRead`](crate::v1::Hypercall::FileRead) hypercall. #[repr(C, packed)] #[derive(Debug, Copy, Clone)] pub struct ReadParams { @@ -101,7 +101,7 @@ pub struct ReadParams { pub ret: isize, } -/// Parameters for a [`FileClose`](crate::Hypercall::FileClose) hypercall. +/// Parameters for a [`FileClose`](crate::v1::Hypercall::FileClose) hypercall. #[repr(C, packed)] #[derive(Debug, Copy, Clone)] pub struct CloseParams { @@ -111,7 +111,7 @@ pub struct CloseParams { pub ret: i32, } -/// Parameters for a [`FileOpen`](crate::Hypercall::FileOpen) hypercall. +/// Parameters for a [`FileOpen`](crate::v1::Hypercall::FileOpen) hypercall. #[repr(C, packed)] #[derive(Debug, Copy, Clone)] pub struct OpenParams { @@ -125,7 +125,7 @@ pub struct OpenParams { pub ret: i32, } -/// Parameters for a [`FileLseek`](crate::Hypercall::FileLseek) hypercall +/// Parameters for a [`FileLseek`](crate::v1::Hypercall::FileLseek) hypercall #[repr(C, packed)] #[derive(Debug, Copy, Clone)] pub struct LseekParams { @@ -137,7 +137,7 @@ pub struct LseekParams { pub whence: i32, } -/// Parameters for a [`SerialWriteBuffer`](crate::Hypercall::SerialWriteBuffer) hypercall. +/// Parameters for a [`SerialWriteBuffer`](crate::v1::Hypercall::SerialWriteBuffer) hypercall. #[repr(C, packed)] #[derive(Debug, Copy, Clone)] pub struct SerialWriteBufferParams {