use core::marker::PhantomData;
use x86_vlapic::X86VlapicHostOps;
use crate::{
X86GuestPhysAddr, X86HostPhysAddr, X86HostVirtAddr, X86VcpuError, X86VcpuResult,
types::X86_PAGE_SIZE_4K,
};
pub trait X86HostOps: X86VlapicHostOps {
fn alloc_frame() -> Option<X86HostPhysAddr>;
fn dealloc_frame(paddr: X86HostPhysAddr);
fn alloc_contiguous_frames(frame_count: usize, frame_align: usize) -> Option<X86HostPhysAddr>;
fn dealloc_contiguous_frames(start_paddr: X86HostPhysAddr, frame_count: usize);
fn phys_to_virt(paddr: X86HostPhysAddr) -> X86HostVirtAddr;
fn read_guest_u8(paddr: X86GuestPhysAddr) -> X86VcpuResult<u8>;
fn nanos_to_ticks(nanos: u64) -> u64;
fn poll_host_interrupt() -> Option<u8>;
}
#[derive(Debug)]
pub struct PhysFrame<H: X86HostOps> {
start_paddr: Option<X86HostPhysAddr>,
_host: PhantomData<fn() -> H>,
}
impl<H: X86HostOps> PhysFrame<H> {
pub fn alloc() -> X86VcpuResult<Self> {
let start_paddr = <H as X86HostOps>::alloc_frame().ok_or(X86VcpuError::NoMemory)?;
assert_ne!(start_paddr.as_usize(), 0);
Ok(Self {
start_paddr: Some(start_paddr),
_host: PhantomData,
})
}
pub fn alloc_zero() -> X86VcpuResult<Self> {
let mut frame = Self::alloc()?;
frame.fill(0);
Ok(frame)
}
pub const unsafe fn uninit() -> Self {
Self {
start_paddr: None,
_host: PhantomData,
}
}
pub fn start_paddr(&self) -> X86HostPhysAddr {
self.start_paddr.expect("uninitialized PhysFrame")
}
pub fn as_mut_ptr(&self) -> *mut u8 {
<H as X86HostOps>::phys_to_virt(self.start_paddr()).as_mut_ptr()
}
pub fn fill(&mut self, byte: u8) {
unsafe { core::ptr::write_bytes(self.as_mut_ptr(), byte, X86_PAGE_SIZE_4K) };
}
}
impl<H: X86HostOps> Drop for PhysFrame<H> {
fn drop(&mut self) {
if let Some(start_paddr) = self.start_paddr {
<H as X86HostOps>::dealloc_frame(start_paddr);
log::debug!("[x86_vcpu] deallocated PhysFrame({start_paddr:#x})");
}
}
}
#[cfg(feature = "svm")]
pub(crate) fn alloc_contiguous_frames<H: X86HostOps>(
frame_count: usize,
frame_align: usize,
) -> Option<X86HostPhysAddr> {
<H as X86HostOps>::alloc_contiguous_frames(frame_count, frame_align)
}
#[cfg(feature = "svm")]
pub(crate) fn dealloc_contiguous_frames<H: X86HostOps>(
start_paddr: X86HostPhysAddr,
frame_count: usize,
) {
<H as X86HostOps>::dealloc_contiguous_frames(start_paddr, frame_count);
}
#[cfg(any(feature = "vmx", feature = "svm"))]
pub(crate) fn read_guest_u8<H: X86HostOps>(paddr: X86GuestPhysAddr) -> X86VcpuResult<u8> {
H::read_guest_u8(paddr)
}
#[cfg(any(feature = "vmx", feature = "svm"))]
pub(crate) fn nanos_to_ticks<H: X86HostOps>(nanos: u64) -> u64 {
H::nanos_to_ticks(nanos)
}