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