use core::fmt::{Debug, Formatter, LowerHex, UpperHex};
pub type ArmVcpuResult<T = ()> = Result<T, ArmVcpuError>;
#[derive(Clone, Copy, Debug, Eq, PartialEq)]
pub enum ArmVcpuError {
InvalidInput,
Unsupported,
BadState,
}
#[derive(Clone, Copy, Eq, PartialEq, Ord, PartialOrd)]
pub struct ArmGuestPhysAddr(usize);
impl ArmGuestPhysAddr {
pub const fn from_usize(addr: usize) -> Self {
Self(addr)
}
pub const fn as_usize(self) -> usize {
self.0
}
}
impl From<usize> for ArmGuestPhysAddr {
fn from(value: usize) -> Self {
Self::from_usize(value)
}
}
impl From<ArmGuestPhysAddr> for usize {
fn from(value: ArmGuestPhysAddr) -> Self {
value.as_usize()
}
}
impl Debug for ArmGuestPhysAddr {
fn fmt(&self, f: &mut Formatter<'_>) -> core::fmt::Result {
write!(f, "GPA({:#x})", self.0)
}
}
impl LowerHex for ArmGuestPhysAddr {
fn fmt(&self, f: &mut Formatter<'_>) -> core::fmt::Result {
write!(f, "{:#x}", self.0)
}
}
impl UpperHex for ArmGuestPhysAddr {
fn fmt(&self, f: &mut Formatter<'_>) -> core::fmt::Result {
write!(f, "{:#X}", self.0)
}
}
#[derive(Clone, Copy, Eq, PartialEq, Ord, PartialOrd)]
pub struct ArmSysRegAddr(usize);
impl ArmSysRegAddr {
pub const fn new(addr: usize) -> Self {
Self(addr)
}
pub const fn addr(self) -> usize {
self.0
}
}
impl From<usize> for ArmSysRegAddr {
fn from(value: usize) -> Self {
Self::new(value)
}
}
impl From<ArmSysRegAddr> for usize {
fn from(value: ArmSysRegAddr) -> Self {
value.addr()
}
}
impl Debug for ArmSysRegAddr {
fn fmt(&self, f: &mut Formatter<'_>) -> core::fmt::Result {
write!(f, "ArmSysRegAddr({:#x})", self.0)
}
}
impl LowerHex for ArmSysRegAddr {
fn fmt(&self, f: &mut Formatter<'_>) -> core::fmt::Result {
write!(f, "{:#x}", self.0)
}
}
impl UpperHex for ArmSysRegAddr {
fn fmt(&self, f: &mut Formatter<'_>) -> core::fmt::Result {
write!(f, "{:#X}", self.0)
}
}
#[derive(Clone, Copy, Debug, Eq, PartialEq, Ord, PartialOrd)]
pub enum ArmAccessWidth {
Byte,
Word,
Dword,
Qword,
}
impl ArmAccessWidth {
pub const fn size(self) -> usize {
match self {
Self::Byte => 1,
Self::Word => 2,
Self::Dword => 4,
Self::Qword => 8,
}
}
}
impl TryFrom<usize> for ArmAccessWidth {
type Error = ArmVcpuError;
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(ArmVcpuError::InvalidInput),
}
}
}
impl From<ArmAccessWidth> for usize {
fn from(value: ArmAccessWidth) -> Self {
value.size()
}
}
#[derive(Clone, Copy, Debug, Eq, PartialEq)]
pub struct ArmNestedPagingConfig {
pub root_paddr: usize,
pub levels: usize,
pub gpa_bits: usize,
pub mode: usize,
}
impl ArmNestedPagingConfig {
pub const fn new(root_paddr: usize, levels: usize, gpa_bits: usize, mode: usize) -> Self {
Self {
root_paddr,
levels,
gpa_bits,
mode,
}
}
}
#[derive(Clone, Copy, Debug, Eq, PartialEq)]
pub enum ArmGicCpuInterfaceRegister {
Control,
PriorityMask,
RunningPriority,
}
#[non_exhaustive]
#[derive(Debug)]
pub enum ArmVmExit {
Hypercall {
nr: u64,
args: [u64; 6],
},
MmioRead {
addr: ArmGuestPhysAddr,
width: ArmAccessWidth,
reg: usize,
reg_width: ArmAccessWidth,
signed_ext: bool,
},
MmioWrite {
addr: ArmGuestPhysAddr,
width: ArmAccessWidth,
data: u64,
},
SysRegRead {
addr: ArmSysRegAddr,
reg: usize,
},
SysRegWrite {
addr: ArmSysRegAddr,
value: u64,
},
GicCpuInterfaceRead {
register: ArmGicCpuInterfaceRegister,
destination: usize,
},
GicCpuInterfaceWrite {
register: ArmGicCpuInterfaceRegister,
value: u64,
},
ExternalInterrupt {
token: Option<usize>,
},
WaitForInterrupt,
CpuDown {
state: u64,
},
CpuUp {
target_cpu: u64,
entry_point: ArmGuestPhysAddr,
arg: u64,
},
SystemDown,
SendIPI {
value: u64,
},
DeactivateInterrupt {
intid: u32,
},
Nothing,
}