uhyve_interface/
lib.rs

1//! # Uhyve Hypervisor Interface
2//!
3//! The Uhyve hypercall interface works as follows:
4//!
5//! - On `x86_64` you use an out port instruction. The address of the `out`-port corresponds to the
6//!   hypercall you want to use. You can obtain it from the [`IoPorts`] enum. The data send to
7//!   that port is the physical memory address (of the VM) of the parameters of that hypercall.
8//! - 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.
9
10#![cfg_attr(not(feature = "std"), no_std)]
11
12// TODO: Throw this out, once https://github.com/rust-lang/rfcs/issues/2783 or https://github.com/rust-lang/rust/issues/86772 is resolved
13use num_enum::TryFromPrimitive;
14
15pub mod parameters;
16
17pub use memory_addresses::{PhysAddr as GuestPhysAddr, VirtAddr as GuestVirtAddr};
18
19#[cfg(not(target_pointer_width = "64"))]
20compile_error!("Using uhyve-interface on a non-64-bit system is not (yet?) supported");
21use parameters::*;
22
23/// The version of the Uhyve interface. Note: This is not the same as the semver of the crate but
24/// should be increased on every version bump that changes the API.
25pub const UHYVE_INTERFACE_VERSION: u32 = 1;
26
27/// Enum containing all valid port mappings for hypercalls.
28///
29/// The discriminants of this enum are the respective ports, so one can get the code by calling
30/// e.g., `HypercallPorts::FileWrite as u16`.
31#[non_exhaustive]
32#[repr(u16)]
33#[derive(Debug, Eq, PartialEq, TryFromPrimitive, Clone, Copy, Hash)]
34pub enum HypercallAddress {
35	/// Port address = `0x400`
36	FileWrite = 0x400,
37	/// Port address = `0x440`
38	FileOpen = 0x440,
39	/// Port address = `0x480`
40	FileClose = 0x480,
41	/// Port address = `0x500`
42	FileRead = 0x500,
43	/// Port address = `0x540`
44	Exit = 0x540,
45	/// Port address = `0x580`
46	FileLseek = 0x580,
47	#[deprecated = "was never really in use"]
48	/// Port address = `0x640`
49	Netwrite = 0x640,
50	#[deprecated = "was never really in use"]
51	/// Port address = `0x680`
52	Netread = 0x680,
53	#[deprecated = "was never really in use"]
54	/// Port address = `0x700`
55	Netstat = 0x700,
56	/// Port address = `0x740`
57	Cmdsize = 0x740,
58	/// Port address = `0x780`
59	Cmdval = 0x780,
60	/// Port address = `0x800`
61	Uart = 0x800,
62	/// Port address = `0x840`
63	FileUnlink = 0x840,
64	/// Port address = `0x880`
65	SerialBufferWrite = 0x880,
66}
67// TODO: Remove this in the next major version
68impl From<Hypercall<'_>> for HypercallAddress {
69	fn from(value: Hypercall) -> Self {
70		match value {
71			Hypercall::Cmdsize(_) => Self::Cmdsize,
72			Hypercall::Cmdval(_) => Self::Cmdval,
73			Hypercall::Exit(_) => Self::Exit,
74			Hypercall::FileClose(_) => Self::FileClose,
75			Hypercall::FileLseek(_) => Self::FileLseek,
76			Hypercall::FileOpen(_) => Self::FileOpen,
77			Hypercall::FileRead(_) => Self::FileRead,
78			Hypercall::FileWrite(_) => Self::FileWrite,
79			Hypercall::FileUnlink(_) => Self::FileUnlink,
80			Hypercall::SerialWriteByte(_) => Self::Uart,
81			Hypercall::SerialWriteBuffer(_) => Self::SerialBufferWrite,
82		}
83	}
84}
85impl From<&Hypercall<'_>> for HypercallAddress {
86	fn from(value: &Hypercall) -> Self {
87		match value {
88			Hypercall::Cmdsize(_) => Self::Cmdsize,
89			Hypercall::Cmdval(_) => Self::Cmdval,
90			Hypercall::Exit(_) => Self::Exit,
91			Hypercall::FileClose(_) => Self::FileClose,
92			Hypercall::FileLseek(_) => Self::FileLseek,
93			Hypercall::FileOpen(_) => Self::FileOpen,
94			Hypercall::FileRead(_) => Self::FileRead,
95			Hypercall::FileWrite(_) => Self::FileWrite,
96			Hypercall::FileUnlink(_) => Self::FileUnlink,
97			Hypercall::SerialWriteByte(_) => Self::Uart,
98			Hypercall::SerialWriteBuffer(_) => Self::SerialBufferWrite,
99		}
100	}
101}
102
103/// Hypervisor calls available in Uhyve with their respective parameters. See the [module level documentation](crate) on how to invoke them.
104#[non_exhaustive]
105#[derive(Debug)]
106pub enum Hypercall<'a> {
107	/// Get the size of the argument and environment strings. Used to allocate memory for
108	/// [`Hypercall::Cmdval`].
109	Cmdsize(&'a mut CmdsizeParams),
110	/// Copy the argument and environment strings into the VM. Usually preceeeded by
111	/// [`Hypercall::Cmdsize`] so that the guest can allocate the memory for this call.
112	Cmdval(&'a CmdvalParams),
113	/// Exit the VM and return a status.
114	Exit(&'a ExitParams),
115	FileClose(&'a mut CloseParams),
116	FileLseek(&'a mut LseekParams),
117	FileOpen(&'a mut OpenParams),
118	FileRead(&'a mut ReadParams),
119	FileWrite(&'a WriteParams),
120	FileUnlink(&'a mut UnlinkParams),
121	/// Write a char to the terminal.
122	SerialWriteByte(u8),
123	/// Write a buffer to the terminal.
124	SerialWriteBuffer(&'a SerialWriteBufferParams),
125}
126impl Hypercall<'_> {
127	// TODO: Remove this in the next major version
128	/// Get a hypercall's port address.
129	pub fn port(&self) -> u16 {
130		HypercallAddress::from(self) as u16
131	}
132}
133
134// Networkports (not used at the moment)
135// TODO: Remove this
136pub const UHYVE_PORT_NETWRITE: u16 = 0x640;
137
138// FIXME: Do not use a fix number of arguments
139/// The maximum number of items in an argument of environment vector.
140pub const MAX_ARGC_ENVC: usize = 128;