From 9ce5a7f7c5eefa3b8ebe9c635890d61bef72b1e9 Mon Sep 17 00:00:00 2001 From: hky1999 <976929993@qq.com> Date: Tue, 18 Mar 2025 22:03:16 +0800 Subject: [PATCH 01/10] [feat] bring host VM concept into axvcpu, do compile --- src/arch_vcpu.rs | 5 +++++ src/vcpu.rs | 17 +++++++++++++++++ 2 files changed, 22 insertions(+) diff --git a/src/arch_vcpu.rs b/src/arch_vcpu.rs index 1742310..2d997e2 100644 --- a/src/arch_vcpu.rs +++ b/src/arch_vcpu.rs @@ -11,10 +11,15 @@ pub trait AxArchVCpu: Sized { type CreateConfig; /// The configuration for setting up a created [`AxArchVCpu`]. Used by [`AxArchVCpu::setup`]. type SetupConfig; + /// The configuration for creating a new [`AxArchVCpu`] for host VM. Used by [`AxArchVCpu::new_host`] in type 1.5 scenario. + type HostConfig; /// Create a new `AxArchVCpu`. fn new(config: Self::CreateConfig) -> AxResult; + /// Create a new `AxArchVCpu` for host VM. + fn new_host(config: Self::HostConfig) -> AxResult; + /// Set the entry point of the vcpu. /// /// It's guaranteed that this function is called only once, before [`AxArchVCpu::setup`] being called. diff --git a/src/vcpu.rs b/src/vcpu.rs index 878338a..33b989c 100644 --- a/src/vcpu.rs +++ b/src/vcpu.rs @@ -235,6 +235,23 @@ impl AxVCpu { } } +impl AxVCpu { + /// Create a new [`AxVCpu`] for host VM. + pub fn new_host(id: usize, ctx: A::HostConfig, phys_cpu_set: Option) -> AxResult { + Ok(Self { + inner_const: AxVCpuInnerConst { + id, + favor_phys_cpu: 0, + phys_cpu_set, + }, + inner_mut: RefCell::new(AxVCpuInnerMut { + state: VCpuState::Created, + }), + arch_vcpu: UnsafeCell::new(A::new_host(ctx)?), + }) + } +} + #[percpu::def_percpu] static mut CURRENT_VCPU: Option<*mut u8> = None; From 44609481656f406b5d9c1bd0c6250e9a8509a9c4 Mon Sep 17 00:00:00 2001 From: hky1999 <976929993@qq.com> Date: Sat, 22 Mar 2025 18:14:59 +0800 Subject: [PATCH 02/10] [refactor] introduce PagingHandler and EPTTranslator --- Cargo.toml | 4 +++- src/hal.rs | 26 ++------------------------ 2 files changed, 5 insertions(+), 25 deletions(-) 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/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. /// From 4a484197a451dc8f821b03f7788d589068b878f0 Mon Sep 17 00:00:00 2001 From: hky1999 <976929993@qq.com> Date: Fri, 28 Mar 2025 22:00:57 +0800 Subject: [PATCH 03/10] [feat] introduce AxVcpuAccessGuestState --- src/arch_vcpu.rs | 29 +++++++++++++++++++++++++++-- src/lib.rs | 2 +- 2 files changed, 28 insertions(+), 3 deletions(-) diff --git a/src/arch_vcpu.rs b/src/arch_vcpu.rs index 2d997e2..bbd984e 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,7 +8,7 @@ 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`]. @@ -47,3 +49,26 @@ 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 { + 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)>; +} 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::*; From 013eb92f5aca95a64e6186f3cb1171319b7e98ea Mon Sep 17 00:00:00 2001 From: hky1999 <976929993@qq.com> Date: Thu, 3 Apr 2025 00:08:39 +0800 Subject: [PATCH 04/10] [feat] add load_host api and eptp list related api --- src/arch_vcpu.rs | 7 +++++++ 1 file changed, 7 insertions(+) diff --git a/src/arch_vcpu.rs b/src/arch_vcpu.rs index bbd984e..ff82741 100644 --- a/src/arch_vcpu.rs +++ b/src/arch_vcpu.rs @@ -22,6 +22,9 @@ pub trait AxArchVCpu: Sized + AxVcpuAccessGuestState { /// Create a new `AxArchVCpu` for host VM. fn new_host(config: Self::HostConfig) -> AxResult; + /// Construct a new `HostConfig` for current vcpu state. + fn load_host(&self) -> AxResult; + /// Set the entry point of the vcpu. /// /// It's guaranteed that this function is called only once, before [`AxArchVCpu::setup`] being called. @@ -71,4 +74,8 @@ pub trait AxVcpuAccessGuestState { &self, gva: GuestVirtAddr, ) -> Option<(GuestPhysAddr, MappingFlags, PageSize)>; + + fn append_eptp_list(&mut self, idx: usize, eptp: HostPhysAddr) -> AxResult; + fn remove_eptp_list_entry(&mut self, idx: usize) -> AxResult; + fn get_eptp_list_entry(&self, idx: usize) -> AxResult; } From ef1705ee547a1519fba62c3020256ea672866859 Mon Sep 17 00:00:00 2001 From: hky1999 <976929993@qq.com> Date: Mon, 7 Apr 2025 23:14:49 +0800 Subject: [PATCH 05/10] [feat] add set_return_value api --- src/vcpu.rs | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/src/vcpu.rs b/src/vcpu.rs index 33b989c..a606820 100644 --- a/src/vcpu.rs +++ b/src/vcpu.rs @@ -233,6 +233,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); + } } impl AxVCpu { From c1d2cc561e974aaa1cdac2767dd67f2e5e956d22 Mon Sep 17 00:00:00 2001 From: hky1999 <976929993@qq.com> Date: Tue, 8 Apr 2025 00:27:38 +0800 Subject: [PATCH 06/10] [feat] introduce the concept of GeneralRegisters --- src/arch_vcpu.rs | 8 ++++++++ src/percpu.rs | 5 +++++ 2 files changed, 13 insertions(+) diff --git a/src/arch_vcpu.rs b/src/arch_vcpu.rs index ff82741..515c204 100644 --- a/src/arch_vcpu.rs +++ b/src/arch_vcpu.rs @@ -54,6 +54,14 @@ pub trait AxArchVCpu: Sized + AxVcpuAccessGuestState { } 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); 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"); From 86d356fc8f142349fad0a7bce13db178448e83a5 Mon Sep 17 00:00:00 2001 From: hky1999 <976929993@qq.com> Date: Thu, 10 Apr 2025 11:57:50 +0800 Subject: [PATCH 07/10] [feat] modify load_host API in AxArchVCpu --- src/arch_vcpu.rs | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/arch_vcpu.rs b/src/arch_vcpu.rs index 515c204..8239133 100644 --- a/src/arch_vcpu.rs +++ b/src/arch_vcpu.rs @@ -22,8 +22,8 @@ pub trait AxArchVCpu: Sized + AxVcpuAccessGuestState { /// Create a new `AxArchVCpu` for host VM. fn new_host(config: Self::HostConfig) -> AxResult; - /// Construct a new `HostConfig` for current vcpu state. - fn load_host(&self) -> AxResult; + /// Load current vcpu state into a pre-constructed `HostConfig` structure. + fn load_host(&self, config: &mut Self::HostConfig) -> AxResult; /// Set the entry point of the vcpu. /// From ff915a9a124570f2be77dc56651b2e6799080802 Mon Sep 17 00:00:00 2001 From: hky1999 <976929993@qq.com> Date: Wed, 16 Apr 2025 23:59:26 +0800 Subject: [PATCH 08/10] [refactor] pass host ctx during setup --- src/arch_vcpu.rs | 14 +++++++------- src/vcpu.rs | 25 ++++++++----------------- 2 files changed, 15 insertions(+), 24 deletions(-) diff --git a/src/arch_vcpu.rs b/src/arch_vcpu.rs index 8239133..e96570a 100644 --- a/src/arch_vcpu.rs +++ b/src/arch_vcpu.rs @@ -13,17 +13,14 @@ pub trait AxArchVCpu: Sized + AxVcpuAccessGuestState { type CreateConfig; /// The configuration for setting up a created [`AxArchVCpu`]. Used by [`AxArchVCpu::setup`]. type SetupConfig; - /// The configuration for creating a new [`AxArchVCpu`] for host VM. Used by [`AxArchVCpu::new_host`] in type 1.5 scenario. - type HostConfig; + /// 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; - /// Create a new `AxArchVCpu` for host VM. - fn new_host(config: Self::HostConfig) -> AxResult; - - /// Load current vcpu state into a pre-constructed `HostConfig` structure. - fn load_host(&self, config: &mut Self::HostConfig) -> 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. /// @@ -40,6 +37,9 @@ pub trait AxArchVCpu: Sized + AxVcpuAccessGuestState { /// 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; diff --git a/src/vcpu.rs b/src/vcpu.rs index a606820..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 @@ -240,23 +248,6 @@ impl AxVCpu { } } -impl AxVCpu { - /// Create a new [`AxVCpu`] for host VM. - pub fn new_host(id: usize, ctx: A::HostConfig, phys_cpu_set: Option) -> AxResult { - Ok(Self { - inner_const: AxVCpuInnerConst { - id, - favor_phys_cpu: 0, - phys_cpu_set, - }, - inner_mut: RefCell::new(AxVCpuInnerMut { - state: VCpuState::Created, - }), - arch_vcpu: UnsafeCell::new(A::new_host(ctx)?), - }) - } -} - #[percpu::def_percpu] static mut CURRENT_VCPU: Option<*mut u8> = None; From 39db2484116087f3cd5f9e74fce652e7debe017d Mon Sep 17 00:00:00 2001 From: hky1999 <976929993@qq.com> Date: Fri, 18 Apr 2025 19:11:05 +0800 Subject: [PATCH 09/10] [refactor] modify eptp related apis --- src/arch_vcpu.rs | 7 ++++--- 1 file changed, 4 insertions(+), 3 deletions(-) diff --git a/src/arch_vcpu.rs b/src/arch_vcpu.rs index e96570a..1ab2224 100644 --- a/src/arch_vcpu.rs +++ b/src/arch_vcpu.rs @@ -83,7 +83,8 @@ pub trait AxVcpuAccessGuestState { gva: GuestVirtAddr, ) -> Option<(GuestPhysAddr, MappingFlags, PageSize)>; - fn append_eptp_list(&mut self, idx: usize, eptp: HostPhysAddr) -> AxResult; - fn remove_eptp_list_entry(&mut self, idx: usize) -> AxResult; - fn get_eptp_list_entry(&self, idx: usize) -> AxResult; + /// 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; } From 63f085e371cf215e701eeeb33641ea33d8fe11a5 Mon Sep 17 00:00:00 2001 From: hky1999 <976929993@qq.com> Date: Fri, 9 May 2025 17:12:44 +0800 Subject: [PATCH 10/10] [wip] add dump method in AxVcpuAccessGuestState for debug --- src/arch_vcpu.rs | 2 ++ 1 file changed, 2 insertions(+) diff --git a/src/arch_vcpu.rs b/src/arch_vcpu.rs index 1ab2224..1973033 100644 --- a/src/arch_vcpu.rs +++ b/src/arch_vcpu.rs @@ -87,4 +87,6 @@ pub trait AxVcpuAccessGuestState { /// Todo: get entry type instead of the raw address. fn current_ept_root(&self) -> HostPhysAddr; fn eptp_list_region(&self) -> HostPhysAddr; + + fn dump(&self); }