use core::{
fmt::{Debug, Formatter, LowerHex, UpperHex},
ops::{Add, AddAssign},
};
use bitflags::bitflags;
pub const X86_PAGE_SIZE_4K: usize = 0x1000;
pub type X86VcpuResult<T = ()> = Result<T, X86VcpuError>;
#[derive(Clone, Copy, Debug, Eq, PartialEq)]
pub enum X86VcpuError {
InvalidInput,
InvalidData,
Unsupported,
BadState,
NoMemory,
ResourceBusy,
}
impl From<x86_vlapic::X86VlapicError> for X86VcpuError {
fn from(err: x86_vlapic::X86VlapicError) -> Self {
match err {
x86_vlapic::X86VlapicError::InvalidInput => Self::InvalidInput,
x86_vlapic::X86VlapicError::InvalidData => Self::InvalidData,
x86_vlapic::X86VlapicError::Unsupported => Self::Unsupported,
x86_vlapic::X86VlapicError::NoMemory => Self::NoMemory,
x86_vlapic::X86VlapicError::BadState => Self::BadState,
}
}
}
macro_rules! define_addr_type {
($name:ident, $debug_prefix:literal) => {
#[derive(Clone, Copy, Eq, PartialEq, Ord, PartialOrd)]
pub struct $name(usize);
impl $name {
pub const fn from_usize(addr: usize) -> Self {
Self(addr)
}
pub const fn as_usize(self) -> usize {
self.0
}
pub const fn as_ptr<T>(self) -> *const T {
self.0 as *const T
}
pub const fn as_mut_ptr<T>(self) -> *mut T {
self.0 as *mut T
}
}
impl From<usize> for $name {
fn from(value: usize) -> Self {
Self::from_usize(value)
}
}
impl From<$name> for usize {
fn from(value: $name) -> Self {
value.as_usize()
}
}
impl Add<usize> for $name {
type Output = Self;
fn add(self, rhs: usize) -> Self::Output {
Self(self.0 + rhs)
}
}
impl AddAssign<usize> for $name {
fn add_assign(&mut self, rhs: usize) {
self.0 += rhs;
}
}
impl Debug for $name {
fn fmt(&self, f: &mut Formatter<'_>) -> core::fmt::Result {
write!(f, "{}({:#x})", $debug_prefix, self.0)
}
}
impl LowerHex for $name {
fn fmt(&self, f: &mut Formatter<'_>) -> core::fmt::Result {
write!(f, "{:#x}", self.0)
}
}
impl UpperHex for $name {
fn fmt(&self, f: &mut Formatter<'_>) -> core::fmt::Result {
write!(f, "{:#X}", self.0)
}
}
};
}
define_addr_type!(X86GuestPhysAddr, "GPA");
define_addr_type!(X86GuestVirtAddr, "GVA");
define_addr_type!(X86HostPhysAddr, "HPA");
define_addr_type!(X86HostVirtAddr, "HVA");
#[derive(Clone, Copy, Eq, PartialEq, Ord, PartialOrd)]
pub struct X86Port(u16);
impl X86Port {
pub const fn new(port: u16) -> Self {
Self(port)
}
pub const fn number(self) -> u16 {
self.0
}
}
impl From<u16> for X86Port {
fn from(value: u16) -> Self {
Self::new(value)
}
}
impl Debug for X86Port {
fn fmt(&self, f: &mut Formatter<'_>) -> core::fmt::Result {
write!(f, "X86Port({:#x})", self.0)
}
}
#[derive(Clone, Copy, Eq, PartialEq, Ord, PartialOrd)]
pub struct X86MsrAddr(usize);
impl X86MsrAddr {
pub const fn new(addr: usize) -> Self {
Self(addr)
}
pub const fn addr(self) -> usize {
self.0
}
}
impl From<usize> for X86MsrAddr {
fn from(value: usize) -> Self {
Self::new(value)
}
}
impl Debug for X86MsrAddr {
fn fmt(&self, f: &mut Formatter<'_>) -> core::fmt::Result {
write!(f, "MSR({:#x})", self.0)
}
}
#[derive(Clone, Copy, Debug, Eq, PartialEq, Ord, PartialOrd)]
pub enum X86AccessWidth {
Byte,
Word,
Dword,
Qword,
}
impl X86AccessWidth {
pub const fn size(self) -> usize {
match self {
Self::Byte => 1,
Self::Word => 2,
Self::Dword => 4,
Self::Qword => 8,
}
}
pub fn bits_range(self) -> core::ops::Range<usize> {
match self {
Self::Byte => 0..8,
Self::Word => 0..16,
Self::Dword => 0..32,
Self::Qword => 0..64,
}
}
}
impl TryFrom<usize> for X86AccessWidth {
type Error = X86VcpuError;
fn try_from(value: usize) -> Result<Self, Self::Error> {
match value {
1 => Ok(Self::Byte),
2 => Ok(Self::Word),
4 => Ok(Self::Dword),
8 => Ok(Self::Qword),
_ => Err(X86VcpuError::InvalidInput),
}
}
}
impl From<X86AccessWidth> for usize {
fn from(value: X86AccessWidth) -> Self {
value.size()
}
}
bitflags! {
#[derive(Clone, Copy, Debug, Eq, PartialEq)]
pub struct X86AccessFlags: usize {
const READ = 1 << 0;
const WRITE = 1 << 1;
const EXECUTE = 1 << 2;
}
}
#[derive(Clone, Copy, Debug, Eq, PartialEq)]
pub struct X86NestedPageFaultInfo {
pub fault_guest_paddr: X86GuestPhysAddr,
pub access_flags: X86AccessFlags,
}
#[derive(Clone, Copy, Debug, Eq, PartialEq)]
pub struct X86NestedPagingConfig {
pub root_paddr: X86HostPhysAddr,
pub levels: usize,
pub gpa_bits: usize,
pub mode: usize,
}
impl X86NestedPagingConfig {
pub const fn new(
root_paddr: X86HostPhysAddr,
levels: usize,
gpa_bits: usize,
mode: usize,
) -> Self {
Self {
root_paddr,
levels,
gpa_bits,
mode,
}
}
}
#[derive(Debug)]
#[non_exhaustive]
pub enum X86VmExit {
Hypercall {
nr: u64,
args: [u64; 6],
},
PortIoRead {
port: X86Port,
width: X86AccessWidth,
},
PortIoWrite {
port: X86Port,
width: X86AccessWidth,
data: u64,
},
MmioRead {
addr: X86GuestPhysAddr,
width: X86AccessWidth,
reg: usize,
reg_width: X86AccessWidth,
signed_ext: bool,
},
MmioWrite {
addr: X86GuestPhysAddr,
width: X86AccessWidth,
data: u64,
},
MsrRead {
addr: X86MsrAddr,
},
MsrWrite {
addr: X86MsrAddr,
value: u64,
},
NestedPageFault {
addr: X86GuestPhysAddr,
access_flags: X86AccessFlags,
},
ExternalInterrupt {
vector: u8,
},
PreemptionTimer,
InterruptEnd {
vector: Option<u8>,
},
Halt,
SystemDown,
FailEntry {
hardware_entry_failure_reason: usize,
},
Nothing,
}