Skip to content
Draft
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
4 changes: 3 additions & 1 deletion Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -9,4 +9,6 @@ axerrno = "0.1.0"
memory_addr = "0.3.1"
percpu = "0.1.4"

axaddrspace = { git = "https://github.com/arceos-hypervisor/axaddrspace.git" }
page_table_multiarch = "0.5"

axaddrspace = { git = "https://github.com/arceos-hypervisor/axaddrspace.git" }
52 changes: 50 additions & 2 deletions src/arch_vcpu.rs
Original file line number Diff line number Diff line change
@@ -1,20 +1,27 @@
use axaddrspace::{GuestPhysAddr, HostPhysAddr};
use page_table_multiarch::{MappingFlags, PageSize};

use axaddrspace::{GuestPhysAddr, GuestVirtAddr, HostPhysAddr};
use axerrno::AxResult;

use crate::exit::AxVCpuExitReason;

/// A trait for architecture-specific vcpu.
///
/// This trait is an abstraction for virtual CPUs of different architectures.
pub trait AxArchVCpu: Sized {
pub trait AxArchVCpu: Sized + AxVcpuAccessGuestState {
/// The configuration for creating a new [`AxArchVCpu`]. Used by [`AxArchVCpu::new`].
type CreateConfig;
/// The configuration for setting up a created [`AxArchVCpu`]. Used by [`AxArchVCpu::setup`].
type SetupConfig;
/// The configuration for setting up a new [`AxArchVCpu`] for host VM. Used by [`AxArchVCpu::setup_from_context`] in type 1.5 scenario.
type HostContext;

/// Create a new `AxArchVCpu`.
fn new(config: Self::CreateConfig) -> AxResult<Self>;

/// Load current vcpu state into a pre-constructed `HostContext` structure.
fn load_context(&self, config: &mut Self::HostContext) -> AxResult;

/// Set the entry point of the vcpu.
///
/// It's guaranteed that this function is called only once, before [`AxArchVCpu::setup`] being called.
Expand All @@ -30,6 +37,9 @@ pub trait AxArchVCpu: Sized {
/// It's guaranteed that this function is called only once, after [`AxArchVCpu::set_entry`] and [`AxArchVCpu::set_ept_root`] being called.
fn setup(&mut self, config: Self::SetupConfig) -> AxResult;

/// Setup the vcpu from a pre-constructed `HostContext` structure.
fn setup_from_context(&mut self, config: Self::HostContext) -> AxResult;

/// Run the vcpu until a vm-exit occurs.
fn run(&mut self) -> AxResult<AxVCpuExitReason>;

Expand All @@ -42,3 +52,41 @@ pub trait AxArchVCpu: Sized {
/// Set the value of a general-purpose register according to the given index.
fn set_gpr(&mut self, reg: usize, val: usize);
}

pub trait AxVcpuAccessGuestState {
/// The type of the general-purpose registers.
/// This type should be a struct that contains the general-purpose registers of the architecture.
/// TODO: maybe we can seperate this into a independent crate.
type GeneralRegisters;

fn regs(&self) -> &Self::GeneralRegisters;
fn regs_mut(&mut self) -> &mut Self::GeneralRegisters;

fn read_gpr(&self, reg: usize) -> usize;
fn write_gpr(&mut self, reg: usize, val: usize);

fn instr_pointer(&self) -> usize;
fn set_instr_pointer(&mut self, val: usize);

fn stack_pointer(&self) -> usize;
fn set_stack_pointer(&mut self, val: usize);

fn frame_pointer(&self) -> usize;
fn set_frame_pointer(&mut self, val: usize);

fn return_value(&self) -> usize;
fn set_return_value(&mut self, val: usize);

fn guest_is_privileged(&self) -> bool;
fn guest_page_table_query(
&self,
gva: GuestVirtAddr,
) -> Option<(GuestPhysAddr, MappingFlags, PageSize)>;

/// Get the current EPT root entry.
/// Todo: get entry type instead of the raw address.
fn current_ept_root(&self) -> HostPhysAddr;
fn eptp_list_region(&self) -> HostPhysAddr;

fn dump(&self);
}
26 changes: 2 additions & 24 deletions src/hal.rs
Original file line number Diff line number Diff line change
Expand Up @@ -2,30 +2,8 @@ use axaddrspace::{HostPhysAddr, HostVirtAddr};

/// The interfaces which the underlying software (kernel or hypervisor) must implement.
pub trait AxVCpuHal {
/// Allocates a frame and returns its host physical address.
///
/// # Returns
///
/// * `Option<HostPhysAddr>` - Some containing the physical address of the allocated frame, or None if allocation fails.
fn alloc_frame() -> Option<HostPhysAddr>;

/// Deallocates a frame given its physical address.
///
/// # Parameters
///
/// * `paddr` - The physical address of the frame to deallocate.
fn dealloc_frame(paddr: HostPhysAddr);

/// Converts a host physical address to a host virtual address.
///
/// # Parameters
///
/// * `paddr` - The physical address to convert.
///
/// # Returns
///
/// * `HostVirtAddr` - The corresponding virtual address.
fn phys_to_virt(paddr: HostPhysAddr) -> HostVirtAddr;
type EPTTranslator: axaddrspace::EPTTranslator;
type PagingHandler: page_table_multiarch::PagingHandler;

/// Converts a host virtual address to a host physical address.
///
Expand Down
2 changes: 1 addition & 1 deletion src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -12,7 +12,7 @@ mod hal;
mod percpu;
mod vcpu;

pub use arch_vcpu::AxArchVCpu;
pub use arch_vcpu::{AxArchVCpu, AxVcpuAccessGuestState};
pub use hal::AxVCpuHal;
pub use percpu::*;
pub use vcpu::*;
Expand Down
5 changes: 5 additions & 0 deletions src/percpu.rs
Original file line number Diff line number Diff line change
Expand Up @@ -64,6 +64,11 @@ impl<A: AxArchPerCpu> AxPerCpu<A> {
}
}

/// Return the CPU id, or `None` if the per-CPU state is not initialized.
pub fn cpu_id(&self) -> Option<usize> {
self.cpu_id
}

/// Return the architecture-specific per-CPU state. Panics if the per-CPU state is not initialized.
pub fn arch_checked(&self) -> &A {
assert!(self.cpu_id.is_some(), "per-CPU state is not initialized");
Expand Down
13 changes: 13 additions & 0 deletions src/vcpu.rs
Original file line number Diff line number Diff line change
Expand Up @@ -98,6 +98,14 @@ impl<A: AxArchVCpu> AxVCpu<A> {
})
}

pub fn setup_from_context(&self, ept_root: HostPhysAddr, ctx: A::HostContext) -> AxResult {
self.manipulate_arch_vcpu(VCpuState::Created, VCpuState::Free, |arch_vcpu| {
arch_vcpu.set_ept_root(ept_root)?;
arch_vcpu.setup_from_context(ctx)?;
Ok(())
})
}

/// Get the id of the vcpu.
pub const fn id(&self) -> usize {
self.inner_const.id
Expand Down Expand Up @@ -233,6 +241,11 @@ impl<A: AxArchVCpu> AxVCpu<A> {
pub fn set_gpr(&self, reg: usize, val: usize) {
self.get_arch_vcpu().set_gpr(reg, val);
}

/// Set the return value of the vcpu.
pub fn set_return_value(&self, ret: usize) {
self.get_arch_vcpu().set_return_value(ret);
}
}

#[percpu::def_percpu]
Expand Down
Loading