Skip to content

Commit d2ab97d

Browse files
committed
feat: refactor memory management and introduce PhysFrame abstraction
1 parent 81eea9f commit d2ab97d

File tree

5 files changed

+130
-13
lines changed

5 files changed

+130
-13
lines changed

Cargo.toml

Lines changed: 3 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -13,11 +13,11 @@ keywords = ["x86", "vcpu", "hypervisor", "arceos"]
1313
license = "GPL-3.0-or-later OR Apache-2.0 OR MulanPSL-2.0" # MulanPubL2 is not included in SPDX
1414

1515
[dependencies]
16-
log = "0.4.19"
16+
log = "0.4"
1717
cfg-if = "1.0"
1818
bitflags = "2.2"
1919
bit_field = "0.10"
20-
paste = "1.0.15"
20+
paste = "1.0"
2121
x86 = "0.52"
2222
x86_64 = "0.15"
2323
raw-cpuid = "11.0"
@@ -28,11 +28,10 @@ page_table_entry = "0.5"
2828
memory_addr = "0.4"
2929
crate_interface = "0.1"
3030

31-
axaddrspace = "0.2.0"
31+
# axaddrspace = "0.2.0"
3232
axvcpu = "0.1.0"
3333
x86_vlapic = "0.1.0"
3434
axdevice_base = "0.1.0"
35-
axvisor_api = "0.1.0"
3635

3736
spin = { version = "0.9", default-features = false }
3837

src/lib.rs

Lines changed: 43 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -15,6 +15,7 @@ pub(crate) mod msr;
1515
#[macro_use]
1616
pub(crate) mod regs;
1717
mod ept;
18+
pub(crate) mod mem;
1819

1920
cfg_if::cfg_if! {
2021
if #[cfg(feature = "vmx")] {
@@ -30,3 +31,45 @@ cfg_if::cfg_if! {
3031
pub use ept::GuestPageWalkInfo;
3132
pub use regs::GeneralRegisters;
3233
pub use vender::has_hardware_support;
34+
35+
pub type HostVirtAddr = usize;
36+
pub type HostPhysAddr = usize;
37+
38+
/// Hardware abstraction layer for memory management.
39+
pub trait Hal {
40+
/// Allocates a frame and returns its host physical address. The
41+
///
42+
/// # Returns
43+
///
44+
/// * `Option<HostPhysAddr>` - Some containing the physical address of the allocated frame, or None if allocation fails.
45+
fn alloc_frame() -> Option<HostPhysAddr>;
46+
47+
/// Deallocates a frame given its physical address.
48+
///
49+
/// # Parameters
50+
///
51+
/// * `paddr` - The physical address of the frame to deallocate.
52+
fn dealloc_frame(paddr: HostPhysAddr);
53+
54+
/// Converts a host physical address to a host virtual address.
55+
///
56+
/// # Parameters
57+
///
58+
/// * `paddr` - The physical address to convert.
59+
///
60+
/// # Returns
61+
///
62+
/// * `HostVirtAddr` - The corresponding virtual address.
63+
fn phys_to_virt(paddr: HostPhysAddr) -> HostVirtAddr;
64+
65+
/// Converts a host virtual address to a host physical address.
66+
///
67+
/// # Parameters
68+
///
69+
/// * `vaddr` - The virtual address to convert.
70+
///
71+
/// # Returns
72+
///
73+
/// * `HostPhysAddr` - The corresponding physical address.
74+
fn virt_to_phys(vaddr: HostVirtAddr) -> HostPhysAddr;
75+
}

src/mem.rs

Lines changed: 70 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,70 @@
1+
use core::marker::PhantomData;
2+
3+
use crate::{Hal, HostPhysAddr};
4+
5+
/// A physical frame which will be automatically deallocated when dropped.
6+
///
7+
/// The frame is allocated using the [`AxMmHal`] implementation. The size of the frame is likely to
8+
/// be 4 KiB but the actual size is determined by the [`AxMmHal`] implementation.
9+
#[derive(Debug)]
10+
pub struct PhysFrame<H: Hal> {
11+
start_paddr: Option<HostPhysAddr>,
12+
_marker: PhantomData<H>,
13+
}
14+
15+
impl<H: Hal> PhysFrame<H> {
16+
/// Allocate a [`PhysFrame`].
17+
pub fn alloc() -> AxResult<Self> {
18+
let start_paddr = H::alloc_frame()
19+
.ok_or_else(|| ax_err_type!(NoMemory, "allocate physical frame failed"))?;
20+
assert_ne!(start_paddr.as_usize(), 0);
21+
Ok(Self {
22+
start_paddr: Some(start_paddr),
23+
_marker: PhantomData,
24+
})
25+
}
26+
27+
/// Allocate a [`PhysFrame`] and fill it with zeros.
28+
pub fn alloc_zero() -> AxResult<Self> {
29+
let mut f = Self::alloc()?;
30+
f.fill(0);
31+
Ok(f)
32+
}
33+
34+
/// Create an uninitialized [`PhysFrame`].
35+
///
36+
/// # Safety
37+
///
38+
/// The caller must ensure that the [`PhysFrame`] is only used as a placeholder and never
39+
/// accessed.
40+
pub const unsafe fn uninit() -> Self {
41+
Self {
42+
start_paddr: None,
43+
_marker: PhantomData,
44+
}
45+
}
46+
47+
/// Get the starting physical address of the frame.
48+
pub fn start_paddr(&self) -> HostPhysAddr {
49+
self.start_paddr.expect("uninitialized PhysFrame")
50+
}
51+
52+
/// Get a mutable pointer to the frame.
53+
pub fn as_mut_ptr(&self) -> *mut u8 {
54+
H::phys_to_virt(self.start_paddr()).as_mut_ptr()
55+
}
56+
57+
/// Fill the frame with a byte. Works only when the frame is 4 KiB in size.
58+
pub fn fill(&mut self, byte: u8) {
59+
unsafe { core::ptr::write_bytes(self.as_mut_ptr(), byte, PAGE_SIZE) }
60+
}
61+
}
62+
63+
impl<H: AxMmHal> Drop for PhysFrame<H> {
64+
fn drop(&mut self) {
65+
if let Some(start_paddr) = self.start_paddr {
66+
H::dealloc_frame(start_paddr);
67+
debug!("[AxVM] deallocated PhysFrame({start_paddr:#x})");
68+
}
69+
}
70+
}

src/vmx/structs.rs

Lines changed: 6 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -3,14 +3,17 @@ use bitflags::bitflags;
33

44
use memory_addr::PAGE_SIZE_4K as PAGE_SIZE;
55

6-
use axaddrspace::{AxMmHal, HostPhysAddr, PhysFrame};
76
use axerrno::AxResult;
87

9-
use crate::msr::{Msr, MsrReadWrite};
8+
use crate::{
9+
Hal, HostPhysAddr,
10+
mem::PhysFrame,
11+
msr::{Msr, MsrReadWrite},
12+
};
1013

1114
/// VMCS/VMXON region in 4K size. (SDM Vol. 3C, Section 24.2)
1215
#[derive(Debug)]
13-
pub struct VmxRegion<H: AxMmHal> {
16+
pub struct VmxRegion<H: Hal> {
1417
frame: PhysFrame<H>,
1518
}
1619

src/vmx/vcpu.rs

Lines changed: 8 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -22,7 +22,6 @@ use axaddrspace::{
2222
use axdevice_base::BaseDeviceOps;
2323
use axerrno::{AxResult, ax_err, ax_err_type};
2424
use axvcpu::{AxArchVCpu, AxVCpuExitReason, AxVCpuHal};
25-
use axvisor_api::vmm::{VCpuId, VMId};
2625

2726
use super::VmxExitInfo;
2827
use super::as_axerr;
@@ -32,13 +31,16 @@ use super::vmcs::{
3231
self, ApicAccessExitType, VmcsControl32, VmcsControl64, VmcsControlNW, VmcsGuest16,
3332
VmcsGuest32, VmcsGuest64, VmcsGuestNW, VmcsHost16, VmcsHost32, VmcsHost64, VmcsHostNW,
3433
};
35-
use crate::{ept::GuestPageWalkInfo, msr::Msr, regs::GeneralRegisters};
34+
use crate::{Hal, ept::GuestPageWalkInfo, msr::Msr, regs::GeneralRegisters};
3635

3736
const VMX_PREEMPTION_TIMER_SET_VALUE: u32 = 1_000_000;
3837

3938
const QEMU_EXIT_PORT: u16 = 0x604;
4039
const QEMU_EXIT_MAGIC: u64 = 0x2000;
4140

41+
pub type VCpuId = usize;
42+
pub type VMId = usize;
43+
4244
pub struct XState {
4345
host_xcr0: u64,
4446
guest_xcr0: u64,
@@ -153,7 +155,7 @@ const CR0_PE: usize = 1 << 0;
153155

154156
/// A virtual CPU within a guest.
155157
#[repr(C)]
156-
pub struct VmxVcpu<H: AxVCpuHal> {
158+
pub struct VmxVcpu<H: Hal> {
157159
// The order of `guest_regs` and `host_stack_top` is mandatory. They must be the first two fields. If you want to
158160
// change the order or the type of these fields, you must also change the assembly in this file.
159161
/// Guest general-purpose registers.
@@ -175,11 +177,11 @@ pub struct VmxVcpu<H: AxVCpuHal> {
175177

176178
// VMCS-related fields
177179
/// The VMCS region.
178-
vmcs: VmxRegion<H::MmHal>,
180+
vmcs: VmxRegion<H>,
179181
/// The I/O bitmap for the VMCS.
180-
io_bitmap: IOBitmap<H::MmHal>,
182+
io_bitmap: IOBitmap<H>,
181183
/// The MSR bitmap for the VMCS.
182-
msr_bitmap: MsrBitmap<H::MmHal>,
184+
msr_bitmap: MsrBitmap<H>,
183185

184186
// Interrupt-related fields
185187
/// Pending events to be injected to the guest.

0 commit comments

Comments
 (0)