use crate::abi::progress_thunk;
pub use crate::abi::{BARYL_SCAN_NO_MATCH, ProgressFn, ProgressSink, ScanRange};
mod generated {
#![allow(non_camel_case_types, non_upper_case_globals, dead_code)]
include!("generated.rs");
}
pub use generated::*;
impl EngineVtable {
pub const ABSENT: EngineVtable = EngineVtable {
phys_to_host_translate: None,
phys_read_into: None,
phys_write_from: None,
phys_scan_for_pattern: None,
phys_scan_for_u64: None,
phys_scan_for_u32: None,
jit_flush_page: None,
icount: None,
clamp_icount_budget: None,
guest_mac: None,
};
}
#[derive(Debug, Clone, Copy, PartialEq, Eq)]
pub struct PhysAccessError;
impl core::fmt::Display for PhysAccessError {
fn fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result {
write!(f, "physical memory access failed")
}
}
impl core::error::Error for PhysAccessError {}
impl EngRef {
pub fn read_phys_u64(&self, pa: u64) -> Option<u64> {
let read = unsafe { (*self.vtable).phys_read_into }?;
let mut buf = [0u8; 8];
let rc = unsafe { read(*self, pa, buf.as_mut_ptr(), 8) };
(rc == 0).then(|| u64::from_le_bytes(buf))
}
pub fn phys_host(&self, pa: u64) -> Option<(*mut u8, u64)> {
let host_fn = unsafe { (*self.vtable).phys_to_host_translate }?;
let mut len = 0u64;
let p = unsafe { host_fn(*self, pa, &raw mut len) };
(!p.is_null()).then_some((p, len))
}
pub fn read_phys_into(&self, buf: &mut [u8], pa: u64) -> Result<(), PhysAccessError> {
let f = unsafe { (*self.vtable).phys_read_into }.ok_or(PhysAccessError)?;
match unsafe { f(*self, pa, buf.as_mut_ptr(), buf.len() as u64) } {
0 => Ok(()),
_ => Err(PhysAccessError),
}
}
pub fn write_phys_from(&self, buf: &[u8], pa: u64) -> Result<(), PhysAccessError> {
let f = unsafe { (*self.vtable).phys_write_from }.ok_or(PhysAccessError)?;
match unsafe { f(*self, pa, buf.as_ptr(), buf.len() as u64) } {
0 => Ok(()),
_ => Err(PhysAccessError),
}
}
pub fn phys_scan_for_pattern(
&self,
range: ScanRange,
pat: &[u8],
progress: Option<ProgressSink<'_>>,
) -> Option<u64> {
let f = unsafe { (*self.vtable).phys_scan_for_pattern }?;
let mut progress = progress;
let (obj, cb) = progress_thunk(&mut progress);
let hit = unsafe {
f(
*self,
range.start,
range.end,
range.stride,
pat.as_ptr(),
pat.len() as u64,
obj,
cb,
)
};
(hit != BARYL_SCAN_NO_MATCH).then_some(hit)
}
pub fn phys_scan_for_u64(
&self,
range: ScanRange,
target: u64,
progress: Option<ProgressSink<'_>>,
) -> Option<u64> {
let f = unsafe { (*self.vtable).phys_scan_for_u64 }?;
let mut progress = progress;
let (obj, cb) = progress_thunk(&mut progress);
let hit = unsafe { f(*self, range.start, range.end, range.stride, target, obj, cb) };
(hit != BARYL_SCAN_NO_MATCH).then_some(hit)
}
pub fn phys_scan_for_u32(
&self,
range: ScanRange,
target: u32,
progress: Option<ProgressSink<'_>>,
) -> Option<u64> {
let f = unsafe { (*self.vtable).phys_scan_for_u32 }?;
let mut progress = progress;
let (obj, cb) = progress_thunk(&mut progress);
let hit = unsafe { f(*self, range.start, range.end, range.stride, target, obj, cb) };
(hit != BARYL_SCAN_NO_MATCH).then_some(hit)
}
pub fn jit_flush_page(&self, pa: u64) {
let Some(flush) = (unsafe { (*self.vtable).jit_flush_page }) else {
return;
};
unsafe { flush(*self, pa) };
}
pub fn icount(&self) -> u64 {
let Some(f) = (unsafe { (*self.vtable).icount }) else {
return 0;
};
unsafe { f(*self) }
}
pub fn clamp_icount_budget(&self, max: u64) -> u64 {
let Some(f) = (unsafe { (*self.vtable).clamp_icount_budget }) else {
return 0;
};
unsafe { f(*self, max) }
}
pub fn guest_mac(&self) -> Option<[u8; 6]> {
let f = unsafe { (*self.vtable).guest_mac }?;
let mut out = [0u8; 6];
(unsafe { f(*self, out.as_mut_ptr()) } == 0).then_some(out)
}
}