pub mod arch;
use std::{fmt::Debug, hash::Hash};
use vmi_core::{
AddressContext, Pa, VcpuId, View, VmiCore, VmiError,
driver::{VmiDriver, VmiRead, VmiSetProtection},
};
pub use self::arch::ArchAdapter;
pub trait TagType: Debug + Copy + Eq + Hash {}
impl<T> TagType for T where T: Debug + Copy + Eq + Hash {}
#[derive(Debug, Clone, Copy)]
pub struct PageEntryUpdate {
pub view: View,
pub ctx: AddressContext,
pub pa: Pa,
}
#[derive(Debug)]
pub enum PageTableMonitorEvent {
PageIn(PageEntryUpdate),
PageOut(PageEntryUpdate),
}
pub struct PageTableMonitor<Driver, Tag = &'static str>
where
Driver: VmiRead + VmiSetProtection,
Driver::Architecture: ArchAdapter<Driver, Tag>,
Tag: TagType,
{
inner: <Driver::Architecture as ArchAdapter<Driver, Tag>>::Monitor,
}
pub trait PageTableMonitorAdapter<Driver, Tag>
where
Driver: VmiDriver,
{
fn new() -> Self;
fn monitored_tables(&self) -> usize;
fn monitored_entries(&self) -> usize;
fn paged_in_entries(&self) -> usize;
fn dump(&self);
fn monitor(
&mut self,
vmi: &VmiCore<Driver>,
ctx: impl Into<AddressContext>,
view: View,
tag: Tag,
) -> Result<(), VmiError>;
fn unmonitor(
&mut self,
vmi: &VmiCore<Driver>,
ctx: impl Into<AddressContext>,
view: View,
) -> Result<(), VmiError>;
fn unmonitor_all(&mut self, vmi: &VmiCore<Driver>);
fn unmonitor_view(&mut self, vmi: &VmiCore<Driver>, view: View);
fn mark_dirty_entry(&mut self, entry_pa: Pa, view: View, vcpu_id: VcpuId) -> bool;
fn process_dirty_entries(
&mut self,
vmi: &VmiCore<Driver>,
vcpu_id: VcpuId,
) -> Result<Vec<PageTableMonitorEvent>, VmiError>;
}
impl<Driver, Tag> PageTableMonitor<Driver, Tag>
where
Driver: VmiRead + VmiSetProtection,
Driver::Architecture: ArchAdapter<Driver, Tag>,
Tag: TagType,
{
#[expect(clippy::new_without_default)]
pub fn new() -> Self {
Self {
inner: <Driver::Architecture as ArchAdapter<Driver, Tag>>::Monitor::new(),
}
}
pub fn monitored_tables(&self) -> usize {
self.inner.monitored_tables()
}
pub fn monitored_entries(&self) -> usize {
self.inner.monitored_entries()
}
pub fn paged_in_entries(&self) -> usize {
self.inner.paged_in_entries()
}
pub fn dump(&self) {
self.inner.dump();
}
pub fn monitor(
&mut self,
vmi: &VmiCore<Driver>,
ctx: impl Into<AddressContext>,
view: View,
tag: Tag,
) -> Result<(), VmiError> {
self.inner.monitor(vmi, ctx, view, tag)
}
pub fn unmonitor(
&mut self,
vmi: &VmiCore<Driver>,
ctx: impl Into<AddressContext>,
view: View,
) -> Result<(), VmiError> {
self.inner.unmonitor(vmi, ctx, view)
}
pub fn unmonitor_all(&mut self, vmi: &VmiCore<Driver>) {
self.inner.unmonitor_all(vmi);
}
pub fn unmonitor_view(&mut self, vmi: &VmiCore<Driver>, view: View) {
self.inner.unmonitor_view(vmi, view);
}
pub fn mark_dirty_entry(&mut self, entry_pa: Pa, view: View, vcpu_id: VcpuId) -> bool {
self.inner.mark_dirty_entry(entry_pa, view, vcpu_id)
}
pub fn process_dirty_entries(
&mut self,
vmi: &VmiCore<Driver>,
vcpu_id: VcpuId,
) -> Result<Vec<PageTableMonitorEvent>, VmiError> {
self.inner.process_dirty_entries(vmi, vcpu_id)
}
}