-
Notifications
You must be signed in to change notification settings - Fork 29
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
First version of hypercall interface V2
- Loading branch information
1 parent
5f26fb2
commit 0e58c7d
Showing
6 changed files
with
295 additions
and
3 deletions.
There are no files selected for viewing
Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.
Oops, something went wrong.
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -1,6 +1,6 @@ | ||
[package] | ||
name = "uhyve-interface" | ||
version = "0.1.2" | ||
version = "0.2.0" | ||
edition = "2021" | ||
authors = [ | ||
"Jonathan Klimt <[email protected]>", | ||
|
@@ -15,6 +15,7 @@ categories = ["os"] | |
[dependencies] | ||
num_enum = { version = "0.7", default-features = false } | ||
log = { version = "0.4", optional = true } | ||
bitflags = "2.6.0" | ||
|
||
[features] | ||
std = ["dep:log"] | ||
|
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,92 @@ | ||
//! # Uhyve Hypervisor Interface V2 | ||
//! | ||
//! The Uhyve hypercall interface works as follows: | ||
//! | ||
//! - The guest writes (or reads) to the respective [`HypercallAddress`](v2::HypercallAddress). The 64-bit value written to that location is the guest's physical memory address of the hypercall's parameter. | ||
//! - The hypervisor handles the hypercall. Depending on the Hypercall, the hypervisor might change the parameters struct in the guest's memory. | ||
// 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::v2::parameters::*; | ||
|
||
/// Enum containing all valid MMIO addresses for hypercalls. | ||
/// | ||
/// The discriminants of this enum are the respective addresses, so one can get the code by calling | ||
/// e.g., `HypercallAddress::Exit as u64`. | ||
#[non_exhaustive] | ||
#[repr(u64)] | ||
#[derive(Debug, Eq, PartialEq, TryFromPrimitive)] | ||
pub enum HypercallAddress { | ||
Exit = 0x1010, | ||
SerialWriteByte = 0x1020, | ||
SerialWriteBuffer = 0x1030, | ||
SerialReadByte = 0x1040, | ||
SerialReadBuffer = 0x1050, | ||
GetTime = 0x1060, | ||
Sleep = 0x1070, | ||
FileWrite = 0x1100, | ||
FileOpen = 0x1110, | ||
FileClose = 0x1120, | ||
FileRead = 0x1130, | ||
FileLseek = 0x1140, | ||
FileUnlink = 0x1150, | ||
SharedMemOpen = 0x1200, | ||
SharedMemClose = 0x1210, | ||
} | ||
impl From<Hypercall<'_>> for HypercallAddress { | ||
fn from(value: Hypercall) -> Self { | ||
match value { | ||
Hypercall::Exit(_) => Self::Exit, | ||
Hypercall::FileClose(_) => Self::FileClose, | ||
Hypercall::FileLseek(_) => Self::FileLseek, | ||
Hypercall::FileOpen(_) => Self::FileOpen, | ||
Hypercall::FileRead(_) => Self::FileRead, | ||
Hypercall::FileUnlink(_) => Self::FileUnlink, | ||
Hypercall::FileWrite(_) => Self::FileWrite, | ||
Hypercall::GetTime(_) => Self::GetTime, | ||
Hypercall::SerialReadBuffer(_) => Self::SerialReadBuffer, | ||
Hypercall::SerialReadByte => Self::SerialReadByte, | ||
Hypercall::SerialWriteBuffer(_) => Self::SerialWriteBuffer, | ||
Hypercall::SerialWriteByte(_) => Self::SerialWriteByte, | ||
Hypercall::Sleep(_) => Self::Sleep, | ||
Hypercall::SharedMemOpen(_) => Self::SharedMemOpen, | ||
Hypercall::SharedMemClose(_) => Self::SharedMemClose, | ||
} | ||
} | ||
} | ||
|
||
/// 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> { | ||
/// Exit the VM and return a status code. | ||
Exit(i32), | ||
FileClose(&'a mut CloseParams), | ||
FileLseek(&'a mut LseekParams), | ||
FileOpen(&'a mut OpenParams), | ||
FileRead(&'a mut ReadPrams), | ||
FileWrite(&'a WriteParams), | ||
FileUnlink(&'a mut UnlinkParams), | ||
/// Write a char to the terminal. | ||
SerialWriteByte(u8), | ||
/// Write a buffer to the terminal | ||
SerialWriteBuffer(&'a SerialWriteBufferParams), | ||
/// Read a single byte from the terminal | ||
SerialReadByte, | ||
/// Read a buffer from the terminal | ||
SerialReadBuffer(&'a SerialReadBufferParams), | ||
SharedMemOpen(&'a SharedMemOpenParams), | ||
SharedMemClose(&'a SharedMemCloseParams), | ||
/// Get system time | ||
GetTime(&'a TimeParams), | ||
/// Suspend the vm for (at least) the specified duration. | ||
Sleep(&'a SleepParams), | ||
} | ||
impl<'a> Hypercall<'a> { | ||
/// Get a hypercall's port address. | ||
pub fn port(self) -> u16 { | ||
HypercallAddress::from(self) as u16 | ||
} | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,196 @@ | ||
//! Parameters for [Hypercalls](crate::v2::Hypercall). | ||
use core::num::NonZeroU16; | ||
|
||
use bitflags::bitflags; | ||
|
||
use crate::{GuestPhysAddr, GuestVirtAddr}; | ||
|
||
/// Parameters for a [`Exit`](crate::v2::Hypercall::Exit) hypercall. | ||
#[repr(C, packed)] | ||
#[derive(Debug, Copy, Clone)] | ||
pub struct ExitParams { | ||
/// The return code of the guest. | ||
pub arg: i32, | ||
} | ||
|
||
/// Parameters for a [`FileUnlink`](crate::v2::Hypercall::FileUnlink) hypercall. | ||
#[repr(C, packed)] | ||
#[derive(Debug, Copy, Clone)] | ||
pub struct UnlinkParams { | ||
/// Address of the file that should be unlinked. | ||
pub name: GuestPhysAddr, | ||
/// On success, `0` is returned. On error, `-1` is returned. | ||
pub ret: i32, | ||
} | ||
|
||
/// Parameters for a [`FileWrite`](crate::v2::Hypercall::FileWrite) hypercall. | ||
#[repr(C, packed)] | ||
#[derive(Debug, Copy, Clone)] | ||
pub struct WriteParams { | ||
/// File descriptor of the file. | ||
pub fd: i32, | ||
/// Buffer to be written into the file. | ||
pub buf: GuestVirtAddr, | ||
/// Number of bytes in the buffer to be written. | ||
pub len: usize, | ||
} | ||
|
||
/// Parameters for a [`FileRead`](crate::v2::Hypercall::FileRead) hypercall. | ||
#[repr(C, packed)] | ||
#[derive(Debug, Copy, Clone)] | ||
pub struct ReadPrams { | ||
/// File descriptor of the file. | ||
pub fd: i32, | ||
/// Buffer to read the file into. | ||
pub buf: GuestVirtAddr, | ||
/// Number of bytes to read into the buffer. | ||
pub len: usize, | ||
/// Number of bytes read on success. `-1` on failure. | ||
pub ret: isize, | ||
} | ||
|
||
/// Parameters for a [`FileClose`](crate::v2::Hypercall::FileClose) hypercall. | ||
#[repr(C, packed)] | ||
#[derive(Debug, Copy, Clone)] | ||
pub struct CloseParams { | ||
/// File descriptor of the file. | ||
pub fd: i32, | ||
/// Zero on success, `-1` on failure. | ||
pub ret: i32, | ||
} | ||
|
||
/// Parameters for a [`FileOpen`](crate::v2::Hypercall::FileOpen) hypercall. | ||
#[repr(C, packed)] | ||
#[derive(Debug, Copy, Clone)] | ||
pub struct OpenParams { | ||
/// Pathname of the file to be opened. | ||
pub name: GuestPhysAddr, | ||
/// Posix file access mode flags. | ||
pub flags: i32, | ||
/// Access permissions upon opening/creating a file. | ||
pub mode: i32, | ||
/// File descriptor upon successful opening or `-1` upon failure. | ||
pub ret: i32, | ||
} | ||
|
||
/// Parameters for a [`FileLseek`](crate::v2::Hypercall::FileLseek) hypercall | ||
#[repr(C, packed)] | ||
#[derive(Debug, Copy, Clone)] | ||
pub struct LseekParams { | ||
/// File descriptor of the file. | ||
pub fd: i32, | ||
/// Offset in the file. | ||
pub offset: isize, | ||
/// `whence` value of the lseek call. | ||
pub whence: i32, | ||
} | ||
|
||
/// Parameters for a [`SerialWriteBuffer`](crate::v2::Hypercall::SerialWriteBuffer) hypercall. | ||
#[repr(C, packed)] | ||
#[derive(Debug, Copy, Clone)] | ||
pub struct SerialWriteBufferParams { | ||
/// Address of the buffer to be printed. | ||
pub buf: GuestPhysAddr, | ||
/// Length of the buffer. | ||
pub len: usize, | ||
} | ||
|
||
/// Parameters for a [`SerialReadBuffer`](crate::v2::Hypercall::SerialReadBuffer) hypercall. | ||
#[repr(C, packed)] | ||
#[derive(Debug, Copy, Clone)] | ||
pub struct SerialReadBufferParams { | ||
/// Address to write to. | ||
pub buf: GuestPhysAddr, | ||
/// length of `buf`. | ||
pub maxlen: usize, | ||
/// Amount of bytes acutally written. | ||
pub len: usize, | ||
} | ||
|
||
/// Parameters for a [`GetTime`](crate::v2::Hypercall::GetTime) hypercall. This follows the semantics of POSIX's `struct timeval` | ||
#[repr(C, packed)] | ||
#[derive(Debug, Copy, Clone)] | ||
pub struct TimeParams { | ||
/// Seconds since the Unix Epoch. | ||
pub seconds: u64, | ||
/// Microseconds since the Unix Epoch (in addition to the `seconds`). | ||
pub u_seconds: u64, | ||
} | ||
|
||
/// Parameters for a [`Sleep`](crate::v2::Hypercall::Sleep) hypercall. | ||
#[repr(C, packed)] | ||
#[derive(Debug, Copy, Clone)] | ||
pub struct SleepParams { | ||
/// Desired seconds duration (seconds, milliseconds). | ||
pub sleep_duration: (u16, u16), | ||
/// Actual sleep duration. (Appoximately: does not include vm entry/exit duration). Might not be supported. | ||
pub actual_sleep_duration: Option<(NonZeroU16, NonZeroU16)>, | ||
} | ||
|
||
#[repr(u8)] | ||
#[derive(Debug, Copy, Clone)] | ||
pub enum SharedMemOpenError { | ||
/// The shared memory due to invalid parameters. | ||
InvalidParams, | ||
/// New shared memory creation was requested, but the shared memory already exists. | ||
AlreadyExisting, | ||
/// There limit of shared memories is exceeded. | ||
TooManySharedMems, | ||
/// Unspecified error | ||
Unspecified, | ||
} | ||
|
||
#[derive(Debug, Copy, Clone)] | ||
pub struct SharedMemFlags(u8); | ||
bitflags! { | ||
impl SharedMemFlags: u8 { | ||
/// The shared memory should be created if not present. | ||
const CREATE = 0b0000_0001; | ||
/// Return an error if the shared memory exists. | ||
const CREATE_EXCLUSIVE = 0b0000_0010; | ||
/// Map the shared memory in read-only mode. | ||
const READ_ONLY = 0b0000_0100; | ||
/// Experimental = Create a shared memory, that can only be written by the current VM. | ||
const CREATE_EXCLUSIVE_WRITE = 0b0000_1000; | ||
} | ||
} | ||
|
||
/// Parameters for a [`SharedMemOpen`](crate::v2::Hypercall::SharedMemOpen) hypercall. | ||
#[repr(C, packed)] | ||
#[derive(Debug, Copy, Clone)] | ||
pub struct SharedMemOpenParams { | ||
/// Address of the mapped shared memory in the guest. Is set by the host. | ||
pub buf: Result<GuestPhysAddr, SharedMemOpenError>, | ||
/// length of `buf`. | ||
pub len: usize, | ||
/// Address of the shared memory identifier utf8 string. | ||
pub identifier: GuestPhysAddr, | ||
/// length of `identifier` in bytes. | ||
pub identifier_len: usize, | ||
/// Flags for opening the shared memory. | ||
pub flags: SharedMemFlags, | ||
} | ||
|
||
#[repr(u8)] | ||
#[derive(Debug, Copy, Clone)] | ||
pub enum SharedMemCloseError { | ||
/// The identifier is not valid. | ||
InvalidIdentifier, | ||
/// The shared memory does not exist. | ||
NotExisting, | ||
/// Unspecified error. | ||
Unspecified, | ||
} | ||
|
||
/// Parameters for a [`SharedMemClose`](crate::v2::Hypercall::SharedMemOpen) hypercall. | ||
#[repr(C, packed)] | ||
#[derive(Debug, Copy, Clone)] | ||
pub struct SharedMemCloseParams { | ||
/// Address of the shared memory identifier utf8 string. | ||
pub identifier: GuestPhysAddr, | ||
/// length of `identifier` in bytes. | ||
pub identifier_len: usize, | ||
/// Flags for Closeing the shared memory. | ||
pub result: Result<(), SharedMemCloseError>, | ||
} |