Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
38 changes: 16 additions & 22 deletions src/frame.rs
Original file line number Diff line number Diff line change
@@ -1,37 +1,28 @@
use core::marker::PhantomData;

use axaddrspace::HostPhysAddr;
use axerrno::{ax_err_type, AxResult};
use memory_addr::{PhysAddr, VirtAddr};

pub(crate) use memory_addr::PAGE_SIZE_4K as PAGE_SIZE;
use axvcpu::AxVCpuHal;

/// Low-level resource interfaces that must be implemented by the crate user.
#[crate_interface::def_interface]
pub trait PhysFrameIf {
/// Request to allocate a 4K-sized physical frame.
fn alloc_frame() -> Option<PhysAddr>;
/// Request to free a allocated physical frame.
fn dealloc_frame(paddr: PhysAddr);
/// Returns a virtual address that maps to the given physical address.
///
/// Used to access the physical memory directly in PhysFrame implementation through `as_mut_ptr()`.
fn phys_to_virt(paddr: PhysAddr) -> VirtAddr;
}
pub(crate) use memory_addr::PAGE_SIZE_4K as PAGE_SIZE;

/// A 4K-sized contiguous physical memory page, it will deallocate the page
/// automatically on drop.
#[derive(Debug)]
pub struct PhysFrame {
pub struct PhysFrame<H: AxVCpuHal> {
start_paddr: Option<HostPhysAddr>,
_marker: PhantomData<H>,
}

impl PhysFrame {
impl<H: AxVCpuHal> PhysFrame<H> {
pub fn alloc() -> AxResult<Self> {
let start_paddr = crate_interface::call_interface!(PhysFrameIf::alloc_frame)
let start_paddr = H::alloc_frame()
.ok_or_else(|| ax_err_type!(NoMemory, "allocate physical frame failed"))?;
assert_ne!(start_paddr.as_usize(), 0);
debug!("[AxVM] allocated PhysFrame({:#x})", start_paddr);
Ok(Self {
start_paddr: Some(start_paddr),
_marker: PhantomData,
})
}

Expand All @@ -42,26 +33,29 @@ impl PhysFrame {
}

pub const unsafe fn uninit() -> Self {
Self { start_paddr: None }
Self {
start_paddr: None,
_marker: PhantomData,
}
}

pub fn start_paddr(&self) -> HostPhysAddr {
self.start_paddr.expect("uninitialized PhysFrame")
}

pub fn as_mut_ptr(&self) -> *mut u8 {
crate_interface::call_interface!(PhysFrameIf::phys_to_virt(self.start_paddr())).as_mut_ptr()
H::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, PAGE_SIZE) }
}
}

impl Drop for PhysFrame {
impl<H: AxVCpuHal> Drop for PhysFrame<H> {
fn drop(&mut self) {
if let Some(start_paddr) = self.start_paddr {
crate_interface::call_interface!(PhysFrameIf::dealloc_frame(start_paddr));
H::dealloc_frame(start_paddr);
debug!("[AxVM] deallocated PhysFrame({:#x})", start_paddr);
}
}
Expand Down
1 change: 0 additions & 1 deletion src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -28,6 +28,5 @@ cfg_if::cfg_if! {
}

pub use ept::GuestPageWalkInfo;
pub use frame::PhysFrameIf;
pub use regs::GeneralRegisters;
pub use vender::has_hardware_support;
8 changes: 4 additions & 4 deletions src/vmx/percpu.rs
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@ use x86::bits64::vmx;
use x86_64::registers::control::{Cr0, Cr4, Cr4Flags};

use axerrno::{ax_err, ax_err_type, AxResult};
use axvcpu::AxArchPerCpu;
use axvcpu::{AxArchPerCpu, AxVCpuHal};
use memory_addr::PAGE_SIZE_4K as PAGE_SIZE;

use crate::msr::Msr;
Expand All @@ -14,7 +14,7 @@ use crate::vmx::structs::{FeatureControl, FeatureControlFlags, VmxBasic, VmxRegi
/// This structure holds the state information specific to a CPU core
/// when operating in VMX mode, including the VMCS revision identifier and
/// the VMX region.
pub struct VmxPerCpuState {
pub struct VmxPerCpuState<H: AxVCpuHal> {
/// The VMCS (Virtual Machine Control Structure) revision identifier.
///
/// This identifier is used to ensure compatibility between the software
Expand All @@ -25,10 +25,10 @@ pub struct VmxPerCpuState {
///
/// This region typically contains the VMCS and other state information
/// required for managing virtual machines on this particular CPU.
vmx_region: VmxRegion,
vmx_region: VmxRegion<H>,
}

impl AxArchPerCpu for VmxPerCpuState {
impl<H: AxVCpuHal> AxArchPerCpu for VmxPerCpuState<H> {
fn new(_cpu_id: usize) -> AxResult<Self> {
Ok(Self {
vmcs_revision_id: 0,
Expand Down
24 changes: 13 additions & 11 deletions src/vmx/structs.rs
Original file line number Diff line number Diff line change
@@ -1,20 +1,22 @@
use bit_field::BitField;
use bitflags::bitflags;

use memory_addr::PAGE_SIZE_4K as PAGE_SIZE;

use axaddrspace::HostPhysAddr;
use axerrno::AxResult;
use memory_addr::PAGE_SIZE_4K as PAGE_SIZE;
use axvcpu::AxVCpuHal;

use crate::frame::PhysFrame;
use crate::msr::{Msr, MsrReadWrite};

/// VMCS/VMXON region in 4K size. (SDM Vol. 3C, Section 24.2)
#[derive(Debug)]
pub struct VmxRegion {
frame: PhysFrame,
pub struct VmxRegion<H: AxVCpuHal> {
frame: PhysFrame<H>,
}

impl VmxRegion {
impl<H: AxVCpuHal> VmxRegion<H> {
pub const unsafe fn uninit() -> Self {
Self {
frame: PhysFrame::uninit(),
Expand All @@ -41,12 +43,12 @@ impl VmxRegion {
// I/O bitmap A contains one bit for each I/O port in the range 0000H through 7FFFH;
// I/O bitmap B contains bits for ports in the range 8000H through FFFFH.
#[derive(Debug)]
pub struct IOBitmap {
io_bitmap_a_frame: PhysFrame,
io_bitmap_b_frame: PhysFrame,
pub struct IOBitmap<H: AxVCpuHal> {
io_bitmap_a_frame: PhysFrame<H>,
io_bitmap_b_frame: PhysFrame<H>,
}

impl IOBitmap {
impl<H: AxVCpuHal> IOBitmap<H> {
pub fn passthrough_all() -> AxResult<Self> {
Ok(Self {
io_bitmap_a_frame: PhysFrame::alloc_zero()?,
Expand Down Expand Up @@ -101,11 +103,11 @@ impl IOBitmap {
}

#[derive(Debug)]
pub struct MsrBitmap {
frame: PhysFrame,
pub struct MsrBitmap<H: AxVCpuHal> {
frame: PhysFrame<H>,
}

impl MsrBitmap {
impl<H: AxVCpuHal> MsrBitmap<H> {
pub fn passthrough_all() -> AxResult<Self> {
Ok(Self {
frame: PhysFrame::alloc_zero()?,
Expand Down
24 changes: 12 additions & 12 deletions src/vmx/vcpu.rs
Original file line number Diff line number Diff line change
Expand Up @@ -11,7 +11,7 @@ use x86_64::registers::control::{Cr0, Cr0Flags, Cr3, Cr4, Cr4Flags, EferFlags};

use axaddrspace::{GuestPhysAddr, GuestVirtAddr, HostPhysAddr, NestedPageFaultInfo};
use axerrno::{ax_err, ax_err_type, AxResult};
use axvcpu::{AccessWidth, AxArchVCpu, AxVCpuExitReason};
use axvcpu::{AccessWidth, AxArchVCpu, AxVCpuExitReason, AxVCpuHal};

use super::as_axerr;
use super::definitions::VmxExitReason;
Expand Down Expand Up @@ -65,23 +65,23 @@ const CR0_PE: usize = 1 << 0;

/// A virtual CPU within a guest.
#[repr(C)]
pub struct VmxVcpu {
pub struct VmxVcpu<H: AxVCpuHal> {
// DO NOT modify `guest_regs` and `host_stack_top` and their order unless you do know what you are doing!
// DO NOT add anything before or between them unless you do know what you are doing!
guest_regs: GeneralRegisters,
host_stack_top: u64,
launched: bool,
vmcs: VmxRegion,
io_bitmap: IOBitmap,
msr_bitmap: MsrBitmap,
vmcs: VmxRegion<H>,
io_bitmap: IOBitmap<H>,
msr_bitmap: MsrBitmap<H>,
pending_events: VecDeque<(u8, Option<u32>)>,
xstate: XState,
entry: Option<GuestPhysAddr>,
ept_root: Option<HostPhysAddr>,
// is_host: bool, temporary removed because we don't care about type 1.5 now
}

impl VmxVcpu {
impl<H: AxVCpuHal> VmxVcpu<H> {
/// Create a new [`VmxVcpu`].
pub fn new() -> AxResult<Self> {
let vmcs_revision_id = super::read_vmcs_revision_id();
Expand Down Expand Up @@ -352,7 +352,7 @@ impl VmxVcpu {
}

// Implementation of private methods
impl VmxVcpu {
impl<H: AxVCpuHal> VmxVcpu<H> {
#[allow(dead_code)]
fn setup_io_bitmap(&mut self) -> AxResult {
// By default, I/O bitmap is set as `intercept_all`.
Expand Down Expand Up @@ -657,7 +657,7 @@ impl VmxVcpu {

// Implementaton for type1.5 hypervisor
// #[cfg(feature = "type1_5")]
impl VmxVcpu {
impl<H: AxVCpuHal> VmxVcpu<H> {
fn set_cr(&mut self, cr_idx: usize, val: u64) {
(|| -> AxResult {
// debug!("set guest CR{} to val {:#x}", cr_idx, val);
Expand Down Expand Up @@ -731,7 +731,7 @@ macro_rules! vmx_entry_with {
}
}

impl VmxVcpu {
impl<H: AxVCpuHal> VmxVcpu<H> {
#[naked]
/// Enter guest with vmlaunch.
///
Expand Down Expand Up @@ -1018,7 +1018,7 @@ impl VmxVcpu {
}
}

impl Drop for VmxVcpu {
impl<H: AxVCpuHal> Drop for VmxVcpu<H> {
fn drop(&mut self) {
unsafe { vmx::vmclear(self.vmcs.phys_addr().as_usize() as u64).unwrap() };
info!("[HV] dropped VmxVcpu(vmcs: {:#x})", self.vmcs.phys_addr());
Expand All @@ -1041,7 +1041,7 @@ fn get_tr_base(tr: SegmentSelector, gdt: &DescriptorTablePointer<u64>) -> u64 {
}
}

impl Debug for VmxVcpu {
impl<H: AxVCpuHal> Debug for VmxVcpu<H> {
fn fmt(&self, f: &mut Formatter) -> Result {
(|| -> AxResult<Result> {
Ok(f.debug_struct("VmxVcpu")
Expand All @@ -1062,7 +1062,7 @@ impl Debug for VmxVcpu {
}
}

impl AxArchVCpu for VmxVcpu {
impl<H: AxVCpuHal> AxArchVCpu for VmxVcpu<H> {
type CreateConfig = ();

type SetupConfig = ();
Expand Down