diff --git a/Cargo.toml b/Cargo.toml index c639cb9..b17ce62 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -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" } \ No newline at end of file +page_table_multiarch = "0.5" + +axaddrspace = { git = "https://github.com/arceos-hypervisor/axaddrspace.git" } diff --git a/src/arch_vcpu.rs b/src/arch_vcpu.rs index 1742310..1973033 100644 --- a/src/arch_vcpu.rs +++ b/src/arch_vcpu.rs @@ -1,4 +1,6 @@ -use axaddrspace::{GuestPhysAddr, HostPhysAddr}; +use page_table_multiarch::{MappingFlags, PageSize}; + +use axaddrspace::{GuestPhysAddr, GuestVirtAddr, HostPhysAddr}; use axerrno::AxResult; use crate::exit::AxVCpuExitReason; @@ -6,15 +8,20 @@ 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; + /// 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. @@ -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; @@ -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); +} diff --git a/src/hal.rs b/src/hal.rs index f8c16ea..b0f03db 100644 --- a/src/hal.rs +++ b/src/hal.rs @@ -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` - Some containing the physical address of the allocated frame, or None if allocation fails. - fn alloc_frame() -> Option; - - /// 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. /// diff --git a/src/lib.rs b/src/lib.rs index 56fa431..17e4b4c 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -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::*; diff --git a/src/percpu.rs b/src/percpu.rs index baf748f..8114ebc 100644 --- a/src/percpu.rs +++ b/src/percpu.rs @@ -64,6 +64,11 @@ impl AxPerCpu { } } + /// Return the CPU id, or `None` if the per-CPU state is not initialized. + pub fn cpu_id(&self) -> Option { + 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"); diff --git a/src/vcpu.rs b/src/vcpu.rs index 878338a..ab445ab 100644 --- a/src/vcpu.rs +++ b/src/vcpu.rs @@ -98,6 +98,14 @@ impl AxVCpu { }) } + 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 @@ -233,6 +241,11 @@ impl AxVCpu { 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]