From aa978f1a2d49afe97b2090089ce9affbfa80d60b Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E5=91=A8=E7=9D=BF?= Date: Mon, 8 Sep 2025 15:41:21 +0800 Subject: [PATCH 01/32] fix: irq settings refactor: add page level detect and remove feature --- .cargo/config.toml | 2 + Cargo.toml | 24 +++++------- src/exception_utils.rs | 3 +- src/pcpu.rs | 7 +--- src/vcpu.rs | 89 ++++++++++++++++++------------------------ 5 files changed, 51 insertions(+), 74 deletions(-) create mode 100644 .cargo/config.toml diff --git a/.cargo/config.toml b/.cargo/config.toml new file mode 100644 index 0000000..62d33ee --- /dev/null +++ b/.cargo/config.toml @@ -0,0 +1,2 @@ +[build] +target = "aarch64-unknown-none-softfloat" \ No newline at end of file diff --git a/Cargo.toml b/Cargo.toml index 655fb6d..4d0b023 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -1,22 +1,19 @@ [package] -edition = "2024" -name = "arm_vcpu" -version = "0.1.1" authors = [ - "KeYang Hu ", - "Mingxian Su ", - "ShiMei Tang ", - "DeBin Luo ", - "周睿 " + "KeYang Hu ", + "Mingxian Su ", + "ShiMei Tang ", + "DeBin Luo ", + "周睿 ", ] +categories = ["embedded", "no-std"] description = "Aarch64 VCPU implementation for Arceos Hypervisor" +edition = "2024" +keywords = ["hypervisor", "aarch64", "vcpu"] license = "MIT OR Apache-2.0" +name = "arm_vcpu" repository = "https://github.com/arceos-hypervisor/arm_vcpu" -categories = ["embedded", "no-std"] -keywords = ["hypervisor", "aarch64", "vcpu"] - -[features] -4-level-ept = [] +version = "0.1.1" [dependencies] log = "0.4" @@ -24,7 +21,6 @@ spin = "0.10" aarch64-cpu = "10.0" numeric-enum-macro = "0.2" -tock-registers = "0.9" axerrno = "0.1.0" percpu = {version = "0.2.0", features = ["arm-el2"]} diff --git a/src/exception_utils.rs b/src/exception_utils.rs index 0ae5e37..f2889ed 100644 --- a/src/exception_utils.rs +++ b/src/exception_utils.rs @@ -1,7 +1,6 @@ -use aarch64_cpu::registers::{ESR_EL2, FAR_EL2, PAR_EL1}; +use aarch64_cpu::registers::*; use axaddrspace::GuestPhysAddr; use axerrno::{AxResult, ax_err}; -use tock_registers::interfaces::*; /// Retrieves the Exception Syndrome Register (ESR) value from EL2. /// diff --git a/src/pcpu.rs b/src/pcpu.rs index 296cbbb..7e88aff 100644 --- a/src/pcpu.rs +++ b/src/pcpu.rs @@ -3,7 +3,6 @@ use core::{cell::OnceCell, marker::PhantomData}; use aarch64_cpu::registers::*; use axerrno::AxResult; use axvcpu::{AxArchPerCpu, AxVCpuHal}; -use tock_registers::interfaces::ReadWriteable; /// Per-CPU data. A pointer to this struct is loaded into TP when a CPU starts. This structure #[repr(C)] @@ -56,11 +55,7 @@ impl AxArchPerCpu for Aarch64PerCpu { VBAR_EL2.set(exception_vector_base_vcpu as usize as _); HCR_EL2.modify( - HCR_EL2::VM::Enable - + HCR_EL2::RW::EL1IsAarch64 - + HCR_EL2::IMO::EnableVirtualIRQ - + HCR_EL2::FMO::EnableVirtualFIQ - + HCR_EL2::TSC::EnableTrapEl1SmcToEl2, + HCR_EL2::VM::Enable + HCR_EL2::RW::EL1IsAarch64 + HCR_EL2::TSC::EnableTrapEl1SmcToEl2, ); // Note that `ICH_HCR_EL2` is not the same as `HCR_EL2`. diff --git a/src/vcpu.rs b/src/vcpu.rs index 724463c..5e0b22c 100644 --- a/src/vcpu.rs +++ b/src/vcpu.rs @@ -167,60 +167,15 @@ impl Aarch64VCpu { self.guest_system_regs.sctlr_el1 = 0x30C50830; self.guest_system_regs.pmcr_el0 = 0; - // use 3 level ept paging - // - 4KiB granule (TG0) - // - 39-bit address space (T0_SZ) - // - start at level 1 (SL0) - #[cfg(not(feature = "4-level-ept"))] - { - self.guest_system_regs.vtcr_el2 = (VTCR_EL2::PS::PA_40B_1TB - + VTCR_EL2::TG0::Granule4KB + self.guest_system_regs.vtcr_el2 = probe_vtcr_support() + + (VTCR_EL2::TG0::Granule4KB + VTCR_EL2::SH0::Inner + VTCR_EL2::ORGN0::NormalWBRAWA - + VTCR_EL2::IRGN0::NormalWBRAWA - + VTCR_EL2::SL0.val(0b01) - + VTCR_EL2::T0SZ.val(64 - 39)) - .into(); - } + + VTCR_EL2::IRGN0::NormalWBRAWA) + .value; - // use 4 level ept paging - // - 4KiB granule (TG0) - // - 48-bit address space (T0_SZ) - // - start at level 0 (SL0) - #[cfg(feature = "4-level-ept")] - { - // read PARange (bits 3:0) - let parange = (ID_AA64MMFR0_EL1.get() & 0xF) as u8; - // ARM Definition: 0x5 indicates 48 bits PA, 0x4 indicates 44 bits PA, and so on. - if parange <= 0x4 { - panic!( - "CPU only supports {}-bit PA (< 44), \ - cannot enable 4-level EPT paging!", - match parange { - 0x0 => 32, - 0x1 => 36, - 0x2 => 40, - 0x3 => 42, - 0x4 => 44, - _ => 48, - } - ); - } - self.guest_system_regs.vtcr_el2 = (VTCR_EL2::PS::PA_48B_256TB - + VTCR_EL2::TG0::Granule4KB - + VTCR_EL2::SH0::Inner - + VTCR_EL2::ORGN0::NormalWBRAWA - + VTCR_EL2::IRGN0::NormalWBRAWA - + VTCR_EL2::SL0.val(0b10) // 0b10 means start at level 0 - + VTCR_EL2::T0SZ.val(64 - 48)) - .into(); - } - - let mut hcr_el2 = HCR_EL2::VM::Enable - + HCR_EL2::RW::EL1IsAarch64 - + HCR_EL2::FMO::EnableVirtualFIQ - + HCR_EL2::TSC::EnableTrapEl1SmcToEl2 - + HCR_EL2::RW::EL1IsAarch64; + let mut hcr_el2 = + HCR_EL2::VM::Enable + HCR_EL2::TSC::EnableTrapEl1SmcToEl2 + HCR_EL2::RW::EL1IsAarch64; if !config.passthrough_interrupt { // Set HCR_EL2.IMO will trap IRQs to EL2 while enabling virtual IRQs. @@ -228,7 +183,7 @@ impl Aarch64VCpu { // We must choose one of the two: // - Enable virtual IRQs and trap physical IRQs to EL2. // - Disable virtual IRQs and pass through physical IRQs to EL1. - hcr_el2 += HCR_EL2::IMO::EnableVirtualIRQ; + hcr_el2 += HCR_EL2::IMO::EnableVirtualIRQ + HCR_EL2::FMO::EnableVirtualFIQ; } self.guest_system_regs.hcr_el2 = hcr_el2.into(); @@ -441,3 +396,33 @@ impl Aarch64VCpu { } } } + +fn probe_vtcr_support() -> u64 { + let pa_bits = match ID_AA64MMFR0_EL1.read_as_enum(ID_AA64MMFR0_EL1::PARange) { + Some(ID_AA64MMFR0_EL1::PARange::Value::Bits_32) => 32, + Some(ID_AA64MMFR0_EL1::PARange::Value::Bits_36) => 36, + Some(ID_AA64MMFR0_EL1::PARange::Value::Bits_40) => 40, + Some(ID_AA64MMFR0_EL1::PARange::Value::Bits_42) => 42, + Some(ID_AA64MMFR0_EL1::PARange::Value::Bits_44) => 44, + Some(ID_AA64MMFR0_EL1::PARange::Value::Bits_48) => 48, + Some(ID_AA64MMFR0_EL1::PARange::Value::Bits_52) => 52, + _ => 32, + }; + + let mut val = match pa_bits { + 44.. => VTCR_EL2::SL0::Granule4KBLevel0 + VTCR_EL2::T0SZ.val(64 - 48), + _ => VTCR_EL2::SL0::Granule4KBLevel1 + VTCR_EL2::T0SZ.val(64 - 39), + }; + + match pa_bits { + 52..=64 => val += VTCR_EL2::PS::PA_52B_4PB, + 48..=51 => val += VTCR_EL2::PS::PA_48B_256TB, + 44..=47 => val += VTCR_EL2::PS::PA_44B_16TB, + 42..=43 => val += VTCR_EL2::PS::PA_42B_4TB, + 40..=41 => val += VTCR_EL2::PS::PA_40B_1TB, + 36..=39 => val += VTCR_EL2::PS::PA_36B_64GB, + _ => val += VTCR_EL2::PS::PA_32B_4GB, + } + + val.value +} From c6eaba4fc0a7941b42ed2ade356a5f595baeddd3 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E5=91=A8=E7=9D=BF?= Date: Mon, 8 Sep 2025 15:48:10 +0800 Subject: [PATCH 02/32] fix: ci --- .github/workflows/ci.yml | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index c91435c..8764187 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -44,16 +44,16 @@ jobs: - uses: actions/checkout@v4 - uses: dtolnay/rust-toolchain@nightly with: - toolchain: nightly-2024-12-25 + toolchain: nightly-2025-05-20 - name: Build docs continue-on-error: ${{ github.ref != env.default-branch && github.event_name != 'pull_request' }} run: | cargo doc --no-deps --all-features - printf '' $(cargo tree | head -1 | cut -d' ' -f1) > target/doc/index.html + printf '' $(cargo tree | head -1 | cut -d' ' -f1) > target/aarch64-unknown-none-softfloat/doc/index.html - name: Deploy to Github Pages if: ${{ github.ref == env.default-branch }} uses: JamesIves/github-pages-deploy-action@v4 with: single-commit: true branch: gh-pages - folder: target/doc + folder: target/aarch64-unknown-none-softfloat/doc From b1f5da90e18101348da85ee74e32fc7bc87af026 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E5=91=A8=E7=9D=BF?= Date: Tue, 9 Sep 2025 11:16:57 +0800 Subject: [PATCH 03/32] feat: add max gpt level api --- Cargo.toml | 3 ++- src/lib.rs | 1 + src/pcpu.rs | 6 +++++- src/vcpu.rs | 33 +++++++++++++++++++++++++++------ 4 files changed, 35 insertions(+), 8 deletions(-) diff --git a/Cargo.toml b/Cargo.toml index 4d0b023..594b78b 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -27,5 +27,6 @@ percpu = {version = "0.2.0", features = ["arm-el2"]} axaddrspace = "0.1" axdevice_base = "0.1.0" -axvcpu = "0.1.0" +axvcpu = {git="https://github.com/arceos-hypervisor/axvcpu.git", branch="next"} +# axvcpu = "0.1.0" axvisor_api = "0.1.0" diff --git a/src/lib.rs b/src/lib.rs index 7328d2a..c30954c 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -29,3 +29,4 @@ pub fn has_hardware_support() -> bool { // Current just return true by default. true } + diff --git a/src/pcpu.rs b/src/pcpu.rs index 7e88aff..5960732 100644 --- a/src/pcpu.rs +++ b/src/pcpu.rs @@ -23,7 +23,7 @@ static ORI_EXCEPTION_VECTOR_BASE: usize = 0; #[percpu::def_percpu] pub static IRQ_HANDLER: OnceCell<&(dyn Fn() + Send + Sync)> = OnceCell::new(); -unsafe extern "C" { +unsafe extern { fn exception_vector_base_vcpu(); } @@ -83,4 +83,8 @@ impl AxArchPerCpu for Aarch64PerCpu { HCR_EL2.set(HCR_EL2::VM::Disable.into()); Ok(()) } + + fn max_guest_page_table_levels(&self) -> usize { + crate::vcpu::max_gpt_level(crate::vcpu::pa_bits()) + } } diff --git a/src/vcpu.rs b/src/vcpu.rs index 5e0b22c..213e5d5 100644 --- a/src/vcpu.rs +++ b/src/vcpu.rs @@ -215,7 +215,7 @@ impl Aarch64VCpu { /// When a VM-Exit happens when guest's vCpu is running, /// the control flow will be redirected to this function through `return_run_guest`. #[unsafe(naked)] - unsafe extern "C" fn run_guest(&mut self) -> usize { + unsafe extern fn run_guest(&mut self) -> usize { // Fixes: https://github.com/arceos-hypervisor/arm_vcpu/issues/22 // // The original issue seems to be caused by an unexpected compiler optimization that takes @@ -397,8 +397,8 @@ impl Aarch64VCpu { } } -fn probe_vtcr_support() -> u64 { - let pa_bits = match ID_AA64MMFR0_EL1.read_as_enum(ID_AA64MMFR0_EL1::PARange) { +pub(crate) fn pa_bits() -> usize { + match ID_AA64MMFR0_EL1.read_as_enum(ID_AA64MMFR0_EL1::PARange) { Some(ID_AA64MMFR0_EL1::PARange::Value::Bits_32) => 32, Some(ID_AA64MMFR0_EL1::PARange::Value::Bits_36) => 36, Some(ID_AA64MMFR0_EL1::PARange::Value::Bits_40) => 40, @@ -407,10 +407,31 @@ fn probe_vtcr_support() -> u64 { Some(ID_AA64MMFR0_EL1::PARange::Value::Bits_48) => 48, Some(ID_AA64MMFR0_EL1::PARange::Value::Bits_52) => 52, _ => 32, - }; + } +} + +#[allow(dead_code)] +pub(crate) fn current_gpt_level() -> usize { + let t0sz = VTCR_EL2.read(VTCR_EL2::T0SZ) as usize; + match t0sz { + 16..=25 => 4, + 26..=35 => 3, + _ => 2, + } +} + +pub(crate) fn max_gpt_level(pa_bits: usize) -> usize { + match pa_bits { + 44.. => 4, + _ => 3, + } +} + +fn probe_vtcr_support() -> u64 { + let pa_bits = pa_bits(); - let mut val = match pa_bits { - 44.. => VTCR_EL2::SL0::Granule4KBLevel0 + VTCR_EL2::T0SZ.val(64 - 48), + let mut val = match max_gpt_level(pa_bits) { + 4 => VTCR_EL2::SL0::Granule4KBLevel0 + VTCR_EL2::T0SZ.val(64 - 48), _ => VTCR_EL2::SL0::Granule4KBLevel1 + VTCR_EL2::T0SZ.val(64 - 39), }; From 07f37ba6bc4745980d23518df7a72a4c95cddc82 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E5=91=A8=E7=9D=BF?= Date: Tue, 9 Sep 2025 11:59:46 +0800 Subject: [PATCH 04/32] fmt code --- src/exception.rs | 2 +- src/lib.rs | 1 - 2 files changed, 1 insertion(+), 2 deletions(-) diff --git a/src/exception.rs b/src/exception.rs index c7357da..5363805 100644 --- a/src/exception.rs +++ b/src/exception.rs @@ -340,7 +340,7 @@ fn current_el_sync_handler(tf: &mut TrapFrame) { /// invoked as part of the low-level hypervisor or VM exit handling routines. #[unsafe(naked)] #[unsafe(no_mangle)] -unsafe extern "C" fn vmexit_trampoline() -> ! { +unsafe extern fn vmexit_trampoline() -> ! { core::arch::naked_asm!( // Curretly `sp` points to the base address of `Aarch64VCpu.ctx`, which stores guest's `TrapFrame`. "add x9, sp, 34 * 8", // Skip the exception frame. diff --git a/src/lib.rs b/src/lib.rs index c30954c..7328d2a 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -29,4 +29,3 @@ pub fn has_hardware_support() -> bool { // Current just return true by default. true } - From 52b1ed3a919ac9cb447200d14496ed8ecafc5d3d Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E5=91=A8=E7=9D=BF?= Date: Tue, 9 Sep 2025 12:00:59 +0800 Subject: [PATCH 05/32] fix: change function signature of run_guest to use "C" calling convention --- src/vcpu.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/vcpu.rs b/src/vcpu.rs index 213e5d5..371b22c 100644 --- a/src/vcpu.rs +++ b/src/vcpu.rs @@ -215,7 +215,7 @@ impl Aarch64VCpu { /// When a VM-Exit happens when guest's vCpu is running, /// the control flow will be redirected to this function through `return_run_guest`. #[unsafe(naked)] - unsafe extern fn run_guest(&mut self) -> usize { + unsafe extern "C" fn run_guest(&mut self) -> usize { // Fixes: https://github.com/arceos-hypervisor/arm_vcpu/issues/22 // // The original issue seems to be caused by an unexpected compiler optimization that takes From 980a003da1c11470fce5c3f51147b6e171eb25fb Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E5=91=A8=E7=9D=BF?= Date: Tue, 9 Sep 2025 12:01:30 +0800 Subject: [PATCH 06/32] fix: specify calling convention for external function declaration --- src/pcpu.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/pcpu.rs b/src/pcpu.rs index 5960732..1345623 100644 --- a/src/pcpu.rs +++ b/src/pcpu.rs @@ -23,7 +23,7 @@ static ORI_EXCEPTION_VECTOR_BASE: usize = 0; #[percpu::def_percpu] pub static IRQ_HANDLER: OnceCell<&(dyn Fn() + Send + Sync)> = OnceCell::new(); -unsafe extern { +unsafe extern "C" { fn exception_vector_base_vcpu(); } From b24cc3635c049302ab8d58d3b54007bb5a053a96 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E5=91=A8=E7=9D=BF?= Date: Tue, 9 Sep 2025 12:02:38 +0800 Subject: [PATCH 07/32] fix: specify "C" calling convention for vmexit_trampoline function --- src/exception.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/exception.rs b/src/exception.rs index 5363805..c7357da 100644 --- a/src/exception.rs +++ b/src/exception.rs @@ -340,7 +340,7 @@ fn current_el_sync_handler(tf: &mut TrapFrame) { /// invoked as part of the low-level hypervisor or VM exit handling routines. #[unsafe(naked)] #[unsafe(no_mangle)] -unsafe extern fn vmexit_trampoline() -> ! { +unsafe extern "C" fn vmexit_trampoline() -> ! { core::arch::naked_asm!( // Curretly `sp` points to the base address of `Aarch64VCpu.ctx`, which stores guest's `TrapFrame`. "add x9, sp, 34 * 8", // Skip the exception frame. From 50fd1099eafd758907cea55fb984bad38ef17c4c Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E5=91=A8=E7=9D=BF?= Date: Tue, 11 Nov 2025 17:11:19 +0800 Subject: [PATCH 08/32] fix: add target architecture configuration for aarch64 --- src/lib.rs | 1 + 1 file changed, 1 insertion(+) diff --git a/src/lib.rs b/src/lib.rs index 7328d2a..8d3112a 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -1,4 +1,5 @@ #![no_std] +#![cfg(target_arch = "aarch64")] #![feature(doc_cfg)] #![doc = include_str!("../README.md")] From fd870a0d9cc12843c1d1da15ac44b9a4e6c9b82b Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E5=91=A8=E7=9D=BF?= Date: Thu, 13 Nov 2025 16:53:51 +0800 Subject: [PATCH 09/32] fix: remove "C" calling convention specification for vmexit_trampoline and run_guest functions --- src/exception.rs | 2 +- src/pcpu.rs | 2 +- src/vcpu.rs | 2 +- 3 files changed, 3 insertions(+), 3 deletions(-) diff --git a/src/exception.rs b/src/exception.rs index c7357da..5363805 100644 --- a/src/exception.rs +++ b/src/exception.rs @@ -340,7 +340,7 @@ fn current_el_sync_handler(tf: &mut TrapFrame) { /// invoked as part of the low-level hypervisor or VM exit handling routines. #[unsafe(naked)] #[unsafe(no_mangle)] -unsafe extern "C" fn vmexit_trampoline() -> ! { +unsafe extern fn vmexit_trampoline() -> ! { core::arch::naked_asm!( // Curretly `sp` points to the base address of `Aarch64VCpu.ctx`, which stores guest's `TrapFrame`. "add x9, sp, 34 * 8", // Skip the exception frame. diff --git a/src/pcpu.rs b/src/pcpu.rs index 1345623..5960732 100644 --- a/src/pcpu.rs +++ b/src/pcpu.rs @@ -23,7 +23,7 @@ static ORI_EXCEPTION_VECTOR_BASE: usize = 0; #[percpu::def_percpu] pub static IRQ_HANDLER: OnceCell<&(dyn Fn() + Send + Sync)> = OnceCell::new(); -unsafe extern "C" { +unsafe extern { fn exception_vector_base_vcpu(); } diff --git a/src/vcpu.rs b/src/vcpu.rs index 371b22c..213e5d5 100644 --- a/src/vcpu.rs +++ b/src/vcpu.rs @@ -215,7 +215,7 @@ impl Aarch64VCpu { /// When a VM-Exit happens when guest's vCpu is running, /// the control flow will be redirected to this function through `return_run_guest`. #[unsafe(naked)] - unsafe extern "C" fn run_guest(&mut self) -> usize { + unsafe extern fn run_guest(&mut self) -> usize { // Fixes: https://github.com/arceos-hypervisor/arm_vcpu/issues/22 // // The original issue seems to be caused by an unexpected compiler optimization that takes From fca8924a2536ea4f9ea359a685aae4e507bd0169 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E5=91=A8=E7=9D=BF?= Date: Thu, 13 Nov 2025 17:18:51 +0800 Subject: [PATCH 10/32] fix: update axaddrspace dependency version to 0.2 and format axvcpu declaration --- Cargo.toml | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/Cargo.toml b/Cargo.toml index 594b78b..a346c60 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -25,8 +25,8 @@ numeric-enum-macro = "0.2" axerrno = "0.1.0" percpu = {version = "0.2.0", features = ["arm-el2"]} -axaddrspace = "0.1" +axaddrspace = "0.2" axdevice_base = "0.1.0" -axvcpu = {git="https://github.com/arceos-hypervisor/axvcpu.git", branch="next"} +axvcpu = {git = "https://github.com/arceos-hypervisor/axvcpu.git", branch = "next"} # axvcpu = "0.1.0" axvisor_api = "0.1.0" From 077e76b99ef279626d6e9afe8a4342b0283dcde5 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E5=91=A8=E7=9D=BF?= Date: Thu, 13 Nov 2025 17:23:17 +0800 Subject: [PATCH 11/32] fix: revert axvcpu dependency to version 0.1.0 --- Cargo.toml | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/Cargo.toml b/Cargo.toml index a346c60..5500c74 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -27,6 +27,5 @@ percpu = {version = "0.2.0", features = ["arm-el2"]} axaddrspace = "0.2" axdevice_base = "0.1.0" -axvcpu = {git = "https://github.com/arceos-hypervisor/axvcpu.git", branch = "next"} -# axvcpu = "0.1.0" +axvcpu = "0.1.0" axvisor_api = "0.1.0" From e5edb7c37301fa36293d98a9246faab1069ba1ec Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E5=91=A8=E7=9D=BF?= Date: Fri, 14 Nov 2025 10:46:45 +0800 Subject: [PATCH 12/32] fix: update aarch64-cpu dependency to version 11.0 and add CpuHal trait for interrupt handling --- Cargo.toml | 3 +-- src/lib.rs | 4 ++++ 2 files changed, 5 insertions(+), 2 deletions(-) diff --git a/Cargo.toml b/Cargo.toml index 5500c74..b5848c6 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -19,13 +19,12 @@ version = "0.1.1" log = "0.4" spin = "0.10" -aarch64-cpu = "10.0" +aarch64-cpu = "11.0" numeric-enum-macro = "0.2" axerrno = "0.1.0" percpu = {version = "0.2.0", features = ["arm-el2"]} axaddrspace = "0.2" -axdevice_base = "0.1.0" axvcpu = "0.1.0" axvisor_api = "0.1.0" diff --git a/src/lib.rs b/src/lib.rs index 8d3112a..4319b22 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -30,3 +30,7 @@ pub fn has_hardware_support() -> bool { // Current just return true by default. true } + +pub trait CpuHal { + fn inject_interrupt(irq: usize); +} \ No newline at end of file From 0590e26765d32be07d052984d86e1250d66827b5 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E5=91=A8=E7=9D=BF?= Date: Fri, 14 Nov 2025 14:23:13 +0800 Subject: [PATCH 13/32] fix: refactor vcpu and exception handling, update dependencies, and implement CpuHal trait --- Cargo.toml | 7 +- src/exception.rs | 13 ++- src/exception_utils.rs | 2 +- src/exit.rs | 192 +++++++++++++++++++++++++++++++++++++++++ src/lib.rs | 47 +++++++++- src/pcpu.rs | 37 ++------ src/vcpu.rs | 36 ++++---- 7 files changed, 272 insertions(+), 62 deletions(-) create mode 100644 src/exit.rs diff --git a/Cargo.toml b/Cargo.toml index b5848c6..9ba9525 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -21,10 +21,11 @@ spin = "0.10" aarch64-cpu = "11.0" numeric-enum-macro = "0.2" +axvm-types.workspace = true axerrno = "0.1.0" percpu = {version = "0.2.0", features = ["arm-el2"]} -axaddrspace = "0.2" -axvcpu = "0.1.0" -axvisor_api = "0.1.0" +# axaddrspace = "0.2" +# axvcpu = "0.1.0" +# axvisor_api = "0.1.0" diff --git a/src/exception.rs b/src/exception.rs index 5363805..10cc5fd 100644 --- a/src/exception.rs +++ b/src/exception.rs @@ -1,4 +1,4 @@ -use crate::TrapFrame; +use crate::{TrapFrame, handle_irq}; use crate::exception_utils::{ exception_class, exception_class_value, exception_data_abort_access_is_write, exception_data_abort_access_reg, exception_data_abort_access_reg_width, @@ -9,13 +9,12 @@ use crate::exception_utils::{ }; use aarch64_cpu::registers::{ESR_EL2, HCR_EL2, Readable, SCTLR_EL1, VTCR_EL2, VTTBR_EL2}; -use axaddrspace::{ - GuestPhysAddr, +use axvm_types::{ + addr::GuestPhysAddr, device::{AccessWidth, SysRegAddr}, }; use axerrno::{AxError, AxResult}; -use axvcpu::AxVCpuExitReason; -use log::error; +use crate::exit::AxVCpuExitReason; numeric_enum_macro::numeric_enum! { #[repr(u8)] @@ -281,9 +280,7 @@ fn handle_smc64_exception(ctx: &mut TrapFrame) -> AxResult { /// which is registered at [`crate::pcpu::IRQ_HANDLER`] during `Aarch64PerCpu::new()`. #[unsafe(no_mangle)] fn current_el_irq_handler(_tf: &mut TrapFrame) { - unsafe { crate::pcpu::IRQ_HANDLER.current_ref_raw() } - .get() - .unwrap()() + handle_irq(); } /// Handles synchronous exceptions that occur from the current exception level. diff --git a/src/exception_utils.rs b/src/exception_utils.rs index f2889ed..705d86e 100644 --- a/src/exception_utils.rs +++ b/src/exception_utils.rs @@ -1,5 +1,5 @@ use aarch64_cpu::registers::*; -use axaddrspace::GuestPhysAddr; +use axvm_types::addr::GuestPhysAddr; use axerrno::{AxResult, ax_err}; /// Retrieves the Exception Syndrome Register (ESR) value from EL2. diff --git a/src/exit.rs b/src/exit.rs new file mode 100644 index 0000000..3e42930 --- /dev/null +++ b/src/exit.rs @@ -0,0 +1,192 @@ +use axvm_types::{ + addr::GuestPhysAddr, + device::{AccessWidth, SysRegAddr}, + mem::MappingFlags, +}; + +/// Reasons for VM-Exits returned by [AxArchVCpu::run]. +/// +/// When a guest virtual CPU executes, various conditions can cause control to be +/// transferred back to the hypervisor. This enum represents all possible exit reasons +/// that can occur during VCpu execution. +/// +/// # VM Exit Categories +/// +/// - **I/O Operations**: MMIO reads/writes, port I/O, system register access +/// - **System Events**: Hypercalls, interrupts, nested page faults +/// - **Power Management**: CPU power state changes, system shutdown +/// - **Multiprocessing**: IPI sending, secondary CPU bring-up +/// - **Error Conditions**: Entry failures, invalid states +/// +/// # Compatibility Note +/// +/// This enum draws inspiration from [kvm-ioctls](https://github.com/rust-vmm/kvm-ioctls/blob/main/src/ioctls/vcpu.rs) +/// for consistency with existing virtualization frameworks. +#[non_exhaustive] +#[derive(Debug)] +pub enum AxVCpuExitReason { + /// A guest instruction triggered a hypercall to the hypervisor. + /// + /// Hypercalls are a mechanism for the guest OS to request services from + /// the hypervisor, similar to system calls in a traditional OS. + Hypercall { + /// The hypercall number identifying the requested service + nr: u64, + /// Arguments passed to the hypercall (up to 6 parameters) + args: [u64; 6], + }, + + /// The guest performed a Memory-Mapped I/O (MMIO) read operation. + /// + /// MMIO reads occur when the guest accesses device registers or other + /// hardware-mapped memory regions that require hypervisor emulation. + MmioRead { + /// Guest physical address being read from + addr: GuestPhysAddr, + /// Width/size of the memory access (8, 16, 32, or 64 bits) + width: AccessWidth, + /// Index of the guest register that will receive the read value + reg: usize, + /// Width of the destination register + reg_width: AccessWidth, + /// Whether to sign-extend the read value to fill the register + signed_ext: bool, + }, + + /// The guest performed a Memory-Mapped I/O (MMIO) write operation. + /// + /// MMIO writes occur when the guest writes to device registers or other + /// hardware-mapped memory regions that require hypervisor emulation. + MmioWrite { + /// Guest physical address being written to + addr: GuestPhysAddr, + /// Width/size of the memory access (8, 16, 32, or 64 bits) + width: AccessWidth, + /// Data being written to the memory location + data: u64, + }, + + /// The guest performed a system register read operation. + /// + /// System registers are architecture-specific control and status registers: + /// - **x86_64**: Model-Specific Registers (MSRs) + /// - **RISC-V**: Control and Status Registers (CSRs) + /// - **AArch64**: System registers accessible via MRS instruction + SysRegRead { + /// Address/identifier of the system register being read + /// + /// - **x86_64/RISC-V**: Direct register address + /// - **AArch64**: ESR_EL2.ISS format (`000000`) + /// compatible with the `aarch64_sysreg` crate numbering scheme + addr: SysRegAddr, + /// Index of the guest register that will receive the read value + /// + /// **Note**: Unused on x86_64 where the result is always stored in `[edx:eax]` + reg: usize, + }, + + /// The guest performed a system register write operation. + /// + /// System registers are architecture-specific control and status registers: + /// - **x86_64**: Model-Specific Registers (MSRs) + /// - **RISC-V**: Control and Status Registers (CSRs) + /// - **AArch64**: System registers accessible via MSR instruction + SysRegWrite { + /// Address/identifier of the system register being written + /// + /// - **x86_64/RISC-V**: Direct register address + /// - **AArch64**: ESR_EL2.ISS format (`000000`) + /// compatible with the `aarch64_sysreg` crate numbering scheme + addr: SysRegAddr, + /// Data being written to the system register + value: u64, + }, + + /// An external interrupt was delivered to the VCpu. + /// + /// This represents hardware interrupts from external devices that need + /// to be processed by the guest or hypervisor. + /// + /// **Note**: This enum may be extended with additional fields in the future. + /// Use `..` in pattern matching to ensure forward compatibility. + ExternalInterrupt, + + /// Request to bring up a secondary CPU core. + /// + /// This exit reason is used during the multi-core VM boot process when + /// the primary CPU requests that a secondary CPU be started. The specific + /// mechanism varies by architecture: + /// + /// - **ARM**: PSCI (Power State Coordination Interface) calls + /// - **x86**: SIPI (Startup Inter-Processor Interrupt) + /// - **RISC-V**: SBI (Supervisor Binary Interface) calls + CpuUp { + /// Target CPU identifier to be started + /// + /// Format varies by architecture: + /// - **AArch64**: MPIDR register affinity fields + /// - **x86_64**: APIC ID of the target CPU + /// - **RISC-V**: Hart ID of the target CPU + target_cpu: u64, + /// Guest physical address where the secondary CPU should begin execution + entry_point: GuestPhysAddr, + /// Argument to pass to the secondary CPU + /// + /// - **AArch64**: Value to set in `x0` register at startup + /// - **RISC-V**: Value to set in `a1` register (`a0` gets the hartid) + /// - **x86_64**: Currently unused + arg: u64, + }, + + /// The guest VCpu has been powered down. + /// + /// This indicates the VCpu has executed a power-down instruction or + /// hypercall and should be suspended. The VCpu may be resumed later. + CpuDown { + /// Power state information (currently unused) + /// + /// Reserved for future use with PSCI_POWER_STATE or similar mechanisms + _state: u64, + }, + + /// The guest has requested system-wide shutdown. + /// + /// This indicates the entire virtual machine should be powered off, + /// not just the current VCpu. + SystemDown, + + /// No special handling required - the VCpu handled the exit internally. + /// + /// This provides an opportunity for the hypervisor to: + /// - Check virtual device states + /// - Process pending interrupts + /// - Handle background tasks + /// - Perform scheduling decisions + /// + /// The VCpu can typically be resumed immediately after these checks. + Nothing, + + /// The guest is attempting to send an Inter-Processor Interrupt (IPI). + /// + /// IPIs are used for inter-CPU communication in multi-core systems. + /// This does **not** include Startup IPIs (SIPI), which are handled + /// by the [`AxVCpuExitReason::CpuUp`] variant. + SendIPI { + /// Target CPU identifier to receive the IPI + /// + /// This field is invalid if `send_to_all` or `send_to_self` is true. + target_cpu: u64, + /// Auxiliary field for complex target CPU specifications + /// + /// Currently used only on AArch64 where: + /// - `target_cpu` contains `Aff3.Aff2.Aff1.0` + /// - `target_cpu_aux` contains a bitmask for `Aff0` values + target_cpu_aux: u64, + /// Whether to broadcast the IPI to all CPUs except the sender + send_to_all: bool, + /// Whether to send the IPI to the current CPU (self-IPI) + send_to_self: bool, + /// IPI vector/interrupt number to deliver + vector: u64, + }, +} diff --git a/src/lib.rs b/src/lib.rs index 4319b22..e828360 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -10,10 +10,13 @@ mod context_frame; #[macro_use] mod exception_utils; mod exception; +mod exit; mod pcpu; mod smc; mod vcpu; +use core::sync::atomic::{AtomicBool, Ordering}; + pub use self::pcpu::Aarch64PerCpu; pub use self::vcpu::{Aarch64VCpu, Aarch64VCpuCreateConfig, Aarch64VCpuSetupConfig}; @@ -32,5 +35,45 @@ pub fn has_hardware_support() -> bool { } pub trait CpuHal { - fn inject_interrupt(irq: usize); -} \ No newline at end of file + fn irq_hanlder(&self); + fn inject_interrupt(&self, irq: usize); +} + +struct NopHal; + +impl CpuHal for NopHal { + fn irq_hanlder(&self) { + unimplemented!() + } + fn inject_interrupt(&self, _irq: usize) { + unimplemented!() + } +} + +static mut HAL: &dyn CpuHal = &NopHal; +static INIT: AtomicBool = AtomicBool::new(false); + +fn hal() -> &'static dyn CpuHal { + unsafe { HAL } +} + +fn handle_irq() { + hal().irq_hanlder(); +} + +fn inject_interrupt(irq: usize) { + hal().inject_interrupt(irq); +} + +pub fn init_hal(hal: &'static dyn CpuHal) { + if INIT + .compare_exchange(false, true, Ordering::SeqCst, Ordering::SeqCst) + .is_ok() + { + unsafe { + HAL = hal; + } + } else { + panic!("arm_vcpu hal has been initialized"); + } +} diff --git a/src/pcpu.rs b/src/pcpu.rs index 5960732..c65f98d 100644 --- a/src/pcpu.rs +++ b/src/pcpu.rs @@ -1,42 +1,28 @@ -use core::{cell::OnceCell, marker::PhantomData}; +use core::cell::OnceCell; use aarch64_cpu::registers::*; use axerrno::AxResult; -use axvcpu::{AxArchPerCpu, AxVCpuHal}; + +use crate::CpuHal; /// Per-CPU data. A pointer to this struct is loaded into TP when a CPU starts. This structure #[repr(C)] #[repr(align(4096))] -pub struct Aarch64PerCpu { +pub struct Aarch64PerCpu { /// per cpu id pub cpu_id: usize, - _phantom: PhantomData, + ori_vbar: u64, } -#[percpu::def_percpu] -static ORI_EXCEPTION_VECTOR_BASE: usize = 0; - -/// IRQ handler registered by underlying host OS during per-cpu initialization, -/// for dispatching IRQs to the host OS. -/// -/// Set `IRQ_HANDLER` as per-cpu variable to avoid the need of `OnceLock`. -#[percpu::def_percpu] -pub static IRQ_HANDLER: OnceCell<&(dyn Fn() + Send + Sync)> = OnceCell::new(); - -unsafe extern { +unsafe extern "C" { fn exception_vector_base_vcpu(); } -impl AxArchPerCpu for Aarch64PerCpu { +impl Aarch64PerCpu { fn new(cpu_id: usize) -> AxResult { - // Register IRQ handler for this CPU. - let _ = unsafe { IRQ_HANDLER.current_ref_mut_raw() } - .set(&|| H::irq_hanlder()) - .map(|_| {}); - Ok(Self { cpu_id, - _phantom: PhantomData, + ori_vbar: VBAR_EL2.get(), }) } @@ -45,11 +31,6 @@ impl AxArchPerCpu for Aarch64PerCpu { } fn hardware_enable(&mut self) -> AxResult { - // First we save origin `exception_vector_base`. - // Safety: - // Todo: take care of `preemption` - unsafe { ORI_EXCEPTION_VECTOR_BASE.write_current_raw(VBAR_EL2.get() as usize) } - // Set current `VBAR_EL2` to `exception_vector_base_vcpu` // defined in this crate. VBAR_EL2.set(exception_vector_base_vcpu as usize as _); @@ -78,7 +59,7 @@ impl AxArchPerCpu for Aarch64PerCpu { // Reset `VBAR_EL2` into previous value. // Safety: // Todo: take care of `preemption` - VBAR_EL2.set(unsafe { ORI_EXCEPTION_VECTOR_BASE.read_current_raw() } as _); + VBAR_EL2.set(self.ori_vbar); HCR_EL2.set(HCR_EL2::VM::Disable.into()); Ok(()) diff --git a/src/vcpu.rs b/src/vcpu.rs index 213e5d5..d750e5e 100644 --- a/src/vcpu.rs +++ b/src/vcpu.rs @@ -1,14 +1,17 @@ use core::marker::PhantomData; use aarch64_cpu::registers::*; -use axaddrspace::{GuestPhysAddr, HostPhysAddr, device::SysRegAddr}; use axerrno::AxResult; -use axvcpu::{AxArchVCpu, AxVCpuExitReason, AxVCpuHal}; +use axvm_types::{ + addr::{GuestPhysAddr, HostPhysAddr}, + device::SysRegAddr, +}; -use crate::TrapFrame; use crate::context_frame::GuestSystemRegisters; use crate::exception::{TrapKind, handle_exception_sync}; use crate::exception_utils::exception_class_value; +use crate::exit::AxVCpuExitReason; +use crate::{TrapFrame, inject_interrupt}; #[percpu::def_percpu] static HOST_SP_EL0: u64 = 0; @@ -37,7 +40,7 @@ pub struct VmCpuRegisters { /// A virtual CPU within a guest #[repr(C)] #[derive(Debug)] -pub struct Aarch64VCpu { +pub struct Aarch64VCpu { // 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! ctx: TrapFrame, @@ -45,7 +48,6 @@ pub struct Aarch64VCpu { guest_system_regs: GuestSystemRegisters, /// The MPIDR_EL1 value for the vCPU. mpidr: u64, - _phantom: PhantomData, } /// Configuration for creating a new `Aarch64VCpu` @@ -69,12 +71,8 @@ pub struct Aarch64VCpuSetupConfig { pub passthrough_timer: bool, } -impl axvcpu::AxArchVCpu for Aarch64VCpu { - type CreateConfig = Aarch64VCpuCreateConfig; - - type SetupConfig = Aarch64VCpuSetupConfig; - - fn new(_vm_id: usize, _vcpu_id: usize, config: Self::CreateConfig) -> AxResult { +impl Aarch64VCpu { + fn new(_vm_id: usize, _vcpu_id: usize, config: Aarch64VCpuCreateConfig) -> AxResult { let mut ctx = TrapFrame::default(); ctx.set_argument(config.dtb_addr); @@ -83,11 +81,10 @@ impl axvcpu::AxArchVCpu for Aarch64VCpu { host_stack_top: 0, guest_system_regs: GuestSystemRegisters::default(), mpidr: config.mpidr_el1, - _phantom: PhantomData, }) } - fn setup(&mut self, config: Self::SetupConfig) -> AxResult { + fn setup(&mut self, config: Aarch64VCpuSetupConfig) -> AxResult { self.init_hv(config); Ok(()) } @@ -131,7 +128,8 @@ impl axvcpu::AxArchVCpu for Aarch64VCpu { } fn inject_interrupt(&mut self, vector: usize) -> AxResult { - axvisor_api::arch::hardware_inject_virtual_interrupt(vector as u8); + inject_interrupt(vector); + // axvisor_api::arch::hardware_inject_virtual_interrupt(vector as u8); Ok(()) } @@ -142,7 +140,7 @@ impl axvcpu::AxArchVCpu for Aarch64VCpu { } // Private function -impl Aarch64VCpu { +impl Aarch64VCpu { fn init_hv(&mut self, config: Aarch64VCpuSetupConfig) { self.ctx.spsr = (SPSR_EL1::M::EL1h + SPSR_EL1::I::Masked @@ -209,13 +207,13 @@ impl Aarch64VCpu { } /// Private functions related to vcpu runtime control flow. -impl Aarch64VCpu { +impl Aarch64VCpu { /// Save host context and run guest. /// /// When a VM-Exit happens when guest's vCpu is running, /// the control flow will be redirected to this function through `return_run_guest`. #[unsafe(naked)] - unsafe extern fn run_guest(&mut self) -> usize { + unsafe extern "C" fn run_guest(&mut self) -> usize { // Fixes: https://github.com/arceos-hypervisor/arm_vcpu/issues/22 // // The original issue seems to be caused by an unexpected compiler optimization that takes @@ -303,9 +301,7 @@ impl Aarch64VCpu { let result = match exit_reason { TrapKind::Synchronous => handle_exception_sync(&mut self.ctx), - TrapKind::Irq => Ok(AxVCpuExitReason::ExternalInterrupt { - vector: H::irq_fetch() as _, - }), + TrapKind::Irq => Ok(AxVCpuExitReason::ExternalInterrupt), _ => panic!("Unhandled exception {:?}", exit_reason), }; From d536df8fb4bf9162537b38e2d82d1d2b8534a4e4 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E5=91=A8=E7=9D=BF?= Date: Fri, 14 Nov 2025 14:38:16 +0800 Subject: [PATCH 14/32] =?UTF-8?q?fix:=20=E5=AF=BC=E5=85=A5=20axvm=5Ftypes?= =?UTF-8?q?=20=E7=9A=84=E5=9C=B0=E5=9D=80=E5=92=8C=E8=AE=BE=E5=A4=87?= =?UTF-8?q?=E6=A8=A1=E5=9D=97?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- src/lib.rs | 3 +++ 1 file changed, 3 insertions(+) diff --git a/src/lib.rs b/src/lib.rs index e828360..6eb66d5 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -19,6 +19,9 @@ use core::sync::atomic::{AtomicBool, Ordering}; pub use self::pcpu::Aarch64PerCpu; pub use self::vcpu::{Aarch64VCpu, Aarch64VCpuCreateConfig, Aarch64VCpuSetupConfig}; +pub use axvm_types::addr::*; +pub use axvm_types::device::*; +pub use exit::*; /// context frame for aarch64 pub type TrapFrame = context_frame::Aarch64ContextFrame; From 601906f5e61fad92890dab4be66b249c40ac83f9 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E5=91=A8=E7=9D=BF?= Date: Mon, 17 Nov 2025 10:58:59 +0800 Subject: [PATCH 15/32] =?UTF-8?q?fix:=20=E9=87=8D=E6=9E=84=20Aarch64PerCpu?= =?UTF-8?q?=20=E7=BB=93=E6=9E=84=E4=BD=93=EF=BC=8C=E7=A7=BB=E9=99=A4=20cpu?= =?UTF-8?q?=5Fid=20=E5=AD=97=E6=AE=B5=E5=B9=B6=E8=B0=83=E6=95=B4=E6=96=B9?= =?UTF-8?q?=E6=B3=95=E5=8F=AF=E8=A7=81=E6=80=A7?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- src/pcpu.rs | 19 +++++++------------ 1 file changed, 7 insertions(+), 12 deletions(-) diff --git a/src/pcpu.rs b/src/pcpu.rs index c65f98d..d830cba 100644 --- a/src/pcpu.rs +++ b/src/pcpu.rs @@ -9,8 +9,6 @@ use crate::CpuHal; #[repr(C)] #[repr(align(4096))] pub struct Aarch64PerCpu { - /// per cpu id - pub cpu_id: usize, ori_vbar: u64, } @@ -19,18 +17,17 @@ unsafe extern "C" { } impl Aarch64PerCpu { - fn new(cpu_id: usize) -> AxResult { - Ok(Self { - cpu_id, + pub fn new() -> Self { + Self { ori_vbar: VBAR_EL2.get(), - }) + } } - fn is_enabled(&self) -> bool { + pub fn is_enabled(&self) -> bool { HCR_EL2.is_set(HCR_EL2::VM) } - fn hardware_enable(&mut self) -> AxResult { + pub fn hardware_enable(&mut self) { // Set current `VBAR_EL2` to `exception_vector_base_vcpu` // defined in this crate. VBAR_EL2.set(exception_vector_base_vcpu as usize as _); @@ -51,11 +48,9 @@ impl Aarch64PerCpu { // value = in(reg) 0, // } // } - - Ok(()) } - fn hardware_disable(&mut self) -> AxResult { + pub fn hardware_disable(&mut self) -> AxResult { // Reset `VBAR_EL2` into previous value. // Safety: // Todo: take care of `preemption` @@ -65,7 +60,7 @@ impl Aarch64PerCpu { Ok(()) } - fn max_guest_page_table_levels(&self) -> usize { + pub fn max_guest_page_table_levels(&self) -> usize { crate::vcpu::max_gpt_level(crate::vcpu::pa_bits()) } } From a6a16effab6dd9e4bbefc368ae59c7a221c86af5 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E5=91=A8=E7=9D=BF?= Date: Mon, 17 Nov 2025 12:01:08 +0800 Subject: [PATCH 16/32] fix: add logs --- src/exception.rs | 18 +++++++++++++----- 1 file changed, 13 insertions(+), 5 deletions(-) diff --git a/src/exception.rs b/src/exception.rs index 10cc5fd..1cd68ad 100644 --- a/src/exception.rs +++ b/src/exception.rs @@ -1,4 +1,3 @@ -use crate::{TrapFrame, handle_irq}; use crate::exception_utils::{ exception_class, exception_class_value, exception_data_abort_access_is_write, exception_data_abort_access_reg, exception_data_abort_access_reg_width, @@ -7,14 +6,17 @@ use crate::exception_utils::{ exception_esr, exception_fault_addr, exception_next_instruction_step, exception_sysreg_addr, exception_sysreg_direction_write, exception_sysreg_gpr, }; +use crate::{TrapFrame, handle_irq}; -use aarch64_cpu::registers::{ESR_EL2, HCR_EL2, Readable, SCTLR_EL1, VTCR_EL2, VTTBR_EL2}; +use crate::exit::AxVCpuExitReason; +use aarch64_cpu::registers::{ + ESR_EL2, FAR_EL2, HCR_EL2, HPFAR_EL2, Readable, SCTLR_EL1, SPSR_EL2, VTCR_EL2, VTTBR_EL2, +}; +use axerrno::{AxError, AxResult}; use axvm_types::{ addr::GuestPhysAddr, device::{AccessWidth, SysRegAddr}, }; -use axerrno::{AxError, AxResult}; -use crate::exit::AxVCpuExitReason; numeric_enum_macro::numeric_enum! { #[repr(u8)] @@ -289,10 +291,16 @@ fn current_el_sync_handler(tf: &mut TrapFrame) { let esr = ESR_EL2.extract(); let ec = ESR_EL2.read(ESR_EL2::EC); let iss = ESR_EL2.read(ESR_EL2::ISS); + let far = FAR_EL2.get(); + let hpfar = HPFAR_EL2.get(); + let spsr_el2 = SPSR_EL2.get(); error!("ESR_EL2: {:#x}", esr.get()); error!("Exception Class: {ec:#x}"); error!("Instruction Specific Syndrome: {iss:#x}"); + error!("FAR_EL2: {far:#x}"); + error!("HPFAR_EL2: {hpfar:#x}"); + error!("SPSR_EL2: {spsr_el2:#x}"); panic!( "Unhandled synchronous exception from current EL: {:#x?}", @@ -337,7 +345,7 @@ fn current_el_sync_handler(tf: &mut TrapFrame) { /// invoked as part of the low-level hypervisor or VM exit handling routines. #[unsafe(naked)] #[unsafe(no_mangle)] -unsafe extern fn vmexit_trampoline() -> ! { +unsafe extern "C" fn vmexit_trampoline() -> ! { core::arch::naked_asm!( // Curretly `sp` points to the base address of `Aarch64VCpu.ctx`, which stores guest's `TrapFrame`. "add x9, sp, 34 * 8", // Skip the exception frame. From 14daa15530bd264178fd864fef15986b46bab62c Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E5=91=A8=E7=9D=BF?= Date: Tue, 25 Nov 2025 10:24:34 +0800 Subject: [PATCH 17/32] =?UTF-8?q?fix:=20=E5=B0=86=20Aarch64VCpu=20?= =?UTF-8?q?=E7=9A=84=E6=96=B9=E6=B3=95=E5=8F=AF=E8=A7=81=E6=80=A7=E4=BB=8E?= =?UTF-8?q?=E7=A7=81=E6=9C=89=E6=94=B9=E4=B8=BA=E5=85=AC=E6=9C=89?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- src/vcpu.rs | 20 ++++++++++---------- 1 file changed, 10 insertions(+), 10 deletions(-) diff --git a/src/vcpu.rs b/src/vcpu.rs index d750e5e..534b795 100644 --- a/src/vcpu.rs +++ b/src/vcpu.rs @@ -72,7 +72,7 @@ pub struct Aarch64VCpuSetupConfig { } impl Aarch64VCpu { - fn new(_vm_id: usize, _vcpu_id: usize, config: Aarch64VCpuCreateConfig) -> AxResult { + pub fn new(config: Aarch64VCpuCreateConfig) -> AxResult { let mut ctx = TrapFrame::default(); ctx.set_argument(config.dtb_addr); @@ -84,24 +84,24 @@ impl Aarch64VCpu { }) } - fn setup(&mut self, config: Aarch64VCpuSetupConfig) -> AxResult { + pub fn setup(&mut self, config: Aarch64VCpuSetupConfig) -> AxResult { self.init_hv(config); Ok(()) } - fn set_entry(&mut self, entry: GuestPhysAddr) -> AxResult { + pub fn set_entry(&mut self, entry: GuestPhysAddr) -> AxResult { debug!("set vcpu entry:{entry:?}"); self.set_elr(entry.as_usize()); Ok(()) } - fn set_ept_root(&mut self, ept_root: HostPhysAddr) -> AxResult { + pub fn set_ept_root(&mut self, ept_root: HostPhysAddr) -> AxResult { debug!("set vcpu ept root:{ept_root:#x}"); self.guest_system_regs.vttbr_el2 = ept_root.as_usize() as u64; Ok(()) } - fn run(&mut self) -> AxResult { + pub fn run(&mut self) -> AxResult { // Run guest. let exit_reson = unsafe { // Save host SP_EL0 to the ctx becase it's used as current task ptr. @@ -115,25 +115,25 @@ impl Aarch64VCpu { self.vmexit_handler(trap_kind) } - fn bind(&mut self) -> AxResult { + pub fn bind(&mut self) -> AxResult { Ok(()) } - fn unbind(&mut self) -> AxResult { + pub fn unbind(&mut self) -> AxResult { Ok(()) } - fn set_gpr(&mut self, idx: usize, val: usize) { + pub fn set_gpr(&mut self, idx: usize, val: usize) { self.ctx.set_gpr(idx, val); } - fn inject_interrupt(&mut self, vector: usize) -> AxResult { + pub fn inject_interrupt(&mut self, vector: usize) -> AxResult { inject_interrupt(vector); // axvisor_api::arch::hardware_inject_virtual_interrupt(vector as u8); Ok(()) } - fn set_return_value(&mut self, val: usize) { + pub fn set_return_value(&mut self, val: usize) { // Return value is stored in x0. self.ctx.set_argument(val); } From e7a6327cddf3d0ef49d63d79a128f0527d709690 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E5=91=A8=E7=9D=BF?= Date: Wed, 26 Nov 2025 14:37:45 +0800 Subject: [PATCH 18/32] =?UTF-8?q?feat:=20=E6=B7=BB=E5=8A=A0=20set=5Fdtb=5F?= =?UTF-8?q?addr=20=E6=96=B9=E6=B3=95=E4=BB=A5=E8=AE=BE=E7=BD=AE=20vcpu=20?= =?UTF-8?q?=E7=9A=84=20dtb=20=E5=9C=B0=E5=9D=80?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- src/vcpu.rs | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/src/vcpu.rs b/src/vcpu.rs index 534b795..043bb5e 100644 --- a/src/vcpu.rs +++ b/src/vcpu.rs @@ -89,6 +89,12 @@ impl Aarch64VCpu { Ok(()) } + pub fn set_dtb_addr(&mut self, dtb_addr: GuestPhysAddr) -> AxResult { + debug!("set vcpu dtb addr:{dtb_addr:?}"); + self.ctx.set_argument(dtb_addr.as_usize()); + Ok(()) + } + pub fn set_entry(&mut self, entry: GuestPhysAddr) -> AxResult { debug!("set vcpu entry:{entry:?}"); self.set_elr(entry.as_usize()); From df6618de9eb7a525a5b1346d7c27dbb618372e9e Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E5=91=A8=E7=9D=BF?= Date: Thu, 27 Nov 2025 14:46:36 +0800 Subject: [PATCH 19/32] =?UTF-8?q?fix:=20=E7=A7=BB=E9=99=A4=E6=9C=AA?= =?UTF-8?q?=E4=BD=BF=E7=94=A8=E7=9A=84=E5=AF=BC=E5=85=A5=E4=BB=A5=E6=B8=85?= =?UTF-8?q?=E7=90=86=E4=BB=A3=E7=A0=81?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- src/exit.rs | 1 - src/pcpu.rs | 2 -- src/vcpu.rs | 2 -- 3 files changed, 5 deletions(-) diff --git a/src/exit.rs b/src/exit.rs index 3e42930..469c718 100644 --- a/src/exit.rs +++ b/src/exit.rs @@ -1,7 +1,6 @@ use axvm_types::{ addr::GuestPhysAddr, device::{AccessWidth, SysRegAddr}, - mem::MappingFlags, }; /// Reasons for VM-Exits returned by [AxArchVCpu::run]. diff --git a/src/pcpu.rs b/src/pcpu.rs index d830cba..52cb990 100644 --- a/src/pcpu.rs +++ b/src/pcpu.rs @@ -3,8 +3,6 @@ use core::cell::OnceCell; use aarch64_cpu::registers::*; use axerrno::AxResult; -use crate::CpuHal; - /// Per-CPU data. A pointer to this struct is loaded into TP when a CPU starts. This structure #[repr(C)] #[repr(align(4096))] diff --git a/src/vcpu.rs b/src/vcpu.rs index 043bb5e..a57b2e6 100644 --- a/src/vcpu.rs +++ b/src/vcpu.rs @@ -1,5 +1,3 @@ -use core::marker::PhantomData; - use aarch64_cpu::registers::*; use axerrno::AxResult; use axvm_types::{ From 7c7c8ea465adccb68f4a455feb737fa2193815e9 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E5=91=A8=E7=9D=BF?= Date: Fri, 28 Nov 2025 09:33:34 +0800 Subject: [PATCH 20/32] =?UTF-8?q?fix:=20=E7=A7=BB=E9=99=A4=E6=9C=AA?= =?UTF-8?q?=E4=BD=BF=E7=94=A8=E7=9A=84=20OnceCell=20=E5=AF=BC=E5=85=A5?= =?UTF-8?q?=E4=BB=A5=E6=B8=85=E7=90=86=E4=BB=A3=E7=A0=81?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- src/pcpu.rs | 2 -- 1 file changed, 2 deletions(-) diff --git a/src/pcpu.rs b/src/pcpu.rs index 52cb990..609bf1b 100644 --- a/src/pcpu.rs +++ b/src/pcpu.rs @@ -1,5 +1,3 @@ -use core::cell::OnceCell; - use aarch64_cpu::registers::*; use axerrno::AxResult; From 48e90f2ef0ed8bd3c6d1af2922f5de89f989c534 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E5=91=A8=E7=9D=BF?= Date: Fri, 28 Nov 2025 14:12:09 +0800 Subject: [PATCH 21/32] fmt code --- src/exception_utils.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/exception_utils.rs b/src/exception_utils.rs index 705d86e..78ef106 100644 --- a/src/exception_utils.rs +++ b/src/exception_utils.rs @@ -1,6 +1,6 @@ use aarch64_cpu::registers::*; -use axvm_types::addr::GuestPhysAddr; use axerrno::{AxResult, ax_err}; +use axvm_types::addr::GuestPhysAddr; /// Retrieves the Exception Syndrome Register (ESR) value from EL2. /// From 9b4a8d1d396fd624bc39bbe854e6d71477354e18 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E5=91=A8=E7=9D=BF?= Date: Fri, 19 Dec 2025 13:42:51 +0800 Subject: [PATCH 22/32] =?UTF-8?q?feat:=20=E6=B7=BB=E5=8A=A0=20pa=5Frange?= =?UTF-8?q?=20=E6=96=B9=E6=B3=95=E4=BB=A5=E8=8E=B7=E5=8F=96=E7=89=A9?= =?UTF-8?q?=E7=90=86=E5=9C=B0=E5=9D=80=E8=8C=83=E5=9B=B4?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- src/pcpu.rs | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/src/pcpu.rs b/src/pcpu.rs index 609bf1b..61a037e 100644 --- a/src/pcpu.rs +++ b/src/pcpu.rs @@ -59,4 +59,9 @@ impl Aarch64PerCpu { pub fn max_guest_page_table_levels(&self) -> usize { crate::vcpu::max_gpt_level(crate::vcpu::pa_bits()) } + + pub fn pa_range(&self) -> core::ops::Range { + let pa_bits = crate::vcpu::pa_bits(); + 0..(1 << pa_bits) + } } From 012bc4cd730512f12d9cb2f63380c3b6b4fa728d Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E5=91=A8=E7=9D=BF?= Date: Fri, 19 Dec 2025 15:41:57 +0800 Subject: [PATCH 23/32] =?UTF-8?q?fix:=20=E4=BF=AE=E6=AD=A3=20hardware=5Fen?= =?UTF-8?q?able=20=E6=96=B9=E6=B3=95=E4=B8=AD=E7=9A=84=E7=B1=BB=E5=9E=8B?= =?UTF-8?q?=E8=BD=AC=E6=8D=A2=E4=BB=A5=E7=A1=AE=E4=BF=9D=E5=AE=89=E5=85=A8?= =?UTF-8?q?=E6=80=A7?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- src/pcpu.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/pcpu.rs b/src/pcpu.rs index 61a037e..14de0af 100644 --- a/src/pcpu.rs +++ b/src/pcpu.rs @@ -26,7 +26,7 @@ impl Aarch64PerCpu { pub fn hardware_enable(&mut self) { // Set current `VBAR_EL2` to `exception_vector_base_vcpu` // defined in this crate. - VBAR_EL2.set(exception_vector_base_vcpu as usize as _); + VBAR_EL2.set(exception_vector_base_vcpu as *const () as usize as _); HCR_EL2.modify( HCR_EL2::VM::Enable + HCR_EL2::RW::EL1IsAarch64 + HCR_EL2::TSC::EnableTrapEl1SmcToEl2, From ad5d5dbd9745381fc7d85a10a1a1eae9f8ee9df9 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E5=91=A8=E7=9D=BF?= Date: Fri, 19 Dec 2025 16:14:11 +0800 Subject: [PATCH 24/32] =?UTF-8?q?feat:=20=E6=B7=BB=E5=8A=A0=20ctx=20?= =?UTF-8?q?=E5=92=8C=20ctx=5Fmut=20=E6=96=B9=E6=B3=95=E4=BB=A5=E8=AE=BF?= =?UTF-8?q?=E9=97=AE=E5=92=8C=E4=BF=AE=E6=94=B9=20TrapFrame?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- src/vcpu.rs | 8 ++++++++ 1 file changed, 8 insertions(+) diff --git a/src/vcpu.rs b/src/vcpu.rs index a57b2e6..9da3dea 100644 --- a/src/vcpu.rs +++ b/src/vcpu.rs @@ -141,6 +141,14 @@ impl Aarch64VCpu { // Return value is stored in x0. self.ctx.set_argument(val); } + + pub fn ctx(&self) -> &TrapFrame { + &self.ctx + } + + pub fn ctx_mut(&mut self) -> &mut TrapFrame { + &mut self.ctx + } } // Private function From aa0347e6f640a06ac6d71617f0423726e9f4f4a2 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E5=91=A8=E7=9D=BF?= Date: Fri, 19 Dec 2025 16:46:27 +0800 Subject: [PATCH 25/32] =?UTF-8?q?fix:=20=E7=A7=BB=E9=99=A4=E6=9C=AA?= =?UTF-8?q?=E4=BD=BF=E7=94=A8=E7=9A=84=20bind=20=E5=92=8C=20unbind=20?= =?UTF-8?q?=E6=96=B9=E6=B3=95=E4=BB=A5=E6=B8=85=E7=90=86=E4=BB=A3=E7=A0=81?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- src/vcpu.rs | 17 ----------------- 1 file changed, 17 deletions(-) diff --git a/src/vcpu.rs b/src/vcpu.rs index 9da3dea..9eb6a15 100644 --- a/src/vcpu.rs +++ b/src/vcpu.rs @@ -119,21 +119,12 @@ impl Aarch64VCpu { self.vmexit_handler(trap_kind) } - pub fn bind(&mut self) -> AxResult { - Ok(()) - } - - pub fn unbind(&mut self) -> AxResult { - Ok(()) - } - pub fn set_gpr(&mut self, idx: usize, val: usize) { self.ctx.set_gpr(idx, val); } pub fn inject_interrupt(&mut self, vector: usize) -> AxResult { inject_interrupt(vector); - // axvisor_api::arch::hardware_inject_virtual_interrupt(vector as u8); Ok(()) } @@ -141,14 +132,6 @@ impl Aarch64VCpu { // Return value is stored in x0. self.ctx.set_argument(val); } - - pub fn ctx(&self) -> &TrapFrame { - &self.ctx - } - - pub fn ctx_mut(&mut self) -> &mut TrapFrame { - &mut self.ctx - } } // Private function From 6a25a0102f3fdc2349015c27fc14a20775c93c1b Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E5=91=A8=E7=9D=BF?= Date: Mon, 22 Dec 2025 10:29:37 +0800 Subject: [PATCH 26/32] =?UTF-8?q?feat:=20=E6=B7=BB=E5=8A=A0=20setup=5Fcurr?= =?UTF-8?q?ent=5Fcpu=20=E6=96=B9=E6=B3=95=E4=BB=A5=E8=AE=BE=E7=BD=AE?= =?UTF-8?q?=E5=BD=93=E5=89=8D=20CPU=20=E7=9A=84=20VMID=20=E5=B9=B6?= =?UTF-8?q?=E5=A4=84=E7=90=86=20TLB=20=E5=A4=B1=E6=95=88?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- src/vcpu.rs | 28 +++++++++++++++++++++++++--- 1 file changed, 25 insertions(+), 3 deletions(-) diff --git a/src/vcpu.rs b/src/vcpu.rs index 9eb6a15..f0bd18a 100644 --- a/src/vcpu.rs +++ b/src/vcpu.rs @@ -1,3 +1,5 @@ +use core::fmt::Arguments; + use aarch64_cpu::registers::*; use axerrno::AxResult; use axvm_types::{ @@ -88,23 +90,43 @@ impl Aarch64VCpu { } pub fn set_dtb_addr(&mut self, dtb_addr: GuestPhysAddr) -> AxResult { - debug!("set vcpu dtb addr:{dtb_addr:?}"); + debug!("vCPU{} set vcpu dtb addr:{dtb_addr:?}", self.mpidr); self.ctx.set_argument(dtb_addr.as_usize()); Ok(()) } pub fn set_entry(&mut self, entry: GuestPhysAddr) -> AxResult { - debug!("set vcpu entry:{entry:?}"); + debug!("vCPU{} set vcpu entry:{entry:?}", self.mpidr); self.set_elr(entry.as_usize()); Ok(()) } pub fn set_ept_root(&mut self, ept_root: HostPhysAddr) -> AxResult { - debug!("set vcpu ept root:{ept_root:#x}"); + debug!("vCPU{} set vcpu ept root:{ept_root:#x}", self.mpidr); self.guest_system_regs.vttbr_el2 = ept_root.as_usize() as u64; Ok(()) } + pub fn setup_current_cpu(&mut self, vmid: usize) -> AxResult { + // Set VMID then invalidate stage-2 TLB for this VMID to avoid stale translations. + let vmid_mask: u64 = 0xffff << 48; + let mut vttbr = self.guest_system_regs.vttbr_el2; + vttbr = (vttbr & !vmid_mask) | ((vmid as u64 & 0xffff) << 48); + VTTBR_EL2.set(vttbr); + + unsafe { + core::arch::asm!( + "dsb ishst", // ensure VTTBR write visible before TLB invalidation + "tlbi vmalls12e1is", // invalidate stage-2 by VMID (inner-shareable) + "dsb ish", // ensure completion of invalidation + "isb", // sync context + options(nostack, preserves_flags) + ); + } + + Ok(()) + } + pub fn run(&mut self) -> AxResult { // Run guest. let exit_reson = unsafe { From b7cd8e47d11e1b504b312bc4ecfc7224a17e341e Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E5=91=A8=E7=9D=BF?= Date: Mon, 22 Dec 2025 12:18:12 +0800 Subject: [PATCH 27/32] =?UTF-8?q?fix:=20=E8=B0=83=E6=95=B4=20Cargo.toml=20?= =?UTF-8?q?=E4=B8=AD=E7=9A=84=E4=BE=9D=E8=B5=96=E9=A1=BA=E5=BA=8F=E4=BB=A5?= =?UTF-8?q?=E6=8F=90=E9=AB=98=E5=8F=AF=E8=AF=BB=E6=80=A7?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- Cargo.toml | 11 +++-------- 1 file changed, 3 insertions(+), 8 deletions(-) diff --git a/Cargo.toml b/Cargo.toml index 9ba9525..123d914 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -16,16 +16,11 @@ repository = "https://github.com/arceos-hypervisor/arm_vcpu" version = "0.1.1" [dependencies] -log = "0.4" -spin = "0.10" - aarch64-cpu = "11.0" +log = "0.4" numeric-enum-macro = "0.2" -axvm-types.workspace = true +spin = "0.10" axerrno = "0.1.0" +axvm-types.workspace = true percpu = {version = "0.2.0", features = ["arm-el2"]} - -# axaddrspace = "0.2" -# axvcpu = "0.1.0" -# axvisor_api = "0.1.0" From f484d8beb72775a4491f3f7d2ca826bba8b238d7 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E5=91=A8=E7=9D=BF?= Date: Mon, 22 Dec 2025 14:28:15 +0800 Subject: [PATCH 28/32] =?UTF-8?q?feat:=20=E6=B7=BB=E5=8A=A0=20pt=5Flevel?= =?UTF-8?q?=20=E5=AD=97=E6=AE=B5=E4=BB=A5=E6=94=AF=E6=8C=81=E4=B8=8D?= =?UTF-8?q?=E5=90=8C=E7=9A=84=E9=A1=B5=E8=A1=A8=E7=BA=A7=E5=88=AB=E9=85=8D?= =?UTF-8?q?=E7=BD=AE?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- src/vcpu.rs | 26 ++++++++++++++++++++------ 1 file changed, 20 insertions(+), 6 deletions(-) diff --git a/src/vcpu.rs b/src/vcpu.rs index f0bd18a..fb5433d 100644 --- a/src/vcpu.rs +++ b/src/vcpu.rs @@ -48,6 +48,7 @@ pub struct Aarch64VCpu { guest_system_regs: GuestSystemRegisters, /// The MPIDR_EL1 value for the vCPU. mpidr: u64, + pub pt_level: usize, } /// Configuration for creating a new `Aarch64VCpu` @@ -60,6 +61,7 @@ pub struct Aarch64VCpuCreateConfig { pub mpidr_el1: u64, /// The address of the device tree blob. pub dtb_addr: usize, + pub pt_level: usize, } /// Configuration for setting up a new `Aarch64VCpu` @@ -81,6 +83,7 @@ impl Aarch64VCpu { host_stack_top: 0, guest_system_regs: GuestSystemRegisters::default(), mpidr: config.mpidr_el1, + pt_level: config.pt_level, }) } @@ -110,6 +113,17 @@ impl Aarch64VCpu { pub fn setup_current_cpu(&mut self, vmid: usize) -> AxResult { // Set VMID then invalidate stage-2 TLB for this VMID to avoid stale translations. let vmid_mask: u64 = 0xffff << 48; + let val = match self.pt_level { + 4 => VTCR_EL2::SL0::Granule4KBLevel0 + VTCR_EL2::T0SZ.val(64 - 48), + _ => VTCR_EL2::SL0::Granule4KBLevel1 + VTCR_EL2::T0SZ.val(64 - 39), + } + (VTCR_EL2::TG0::Granule4KB + + VTCR_EL2::SH0::Inner + + VTCR_EL2::ORGN0::NormalWBRAWA + + VTCR_EL2::IRGN0::NormalWBRAWA) + .value; + self.guest_system_regs.vtcr_el2 = val.value; + VTCR_EL2.set(self.guest_system_regs.vtcr_el2); + let mut vttbr = self.guest_system_regs.vttbr_el2; vttbr = (vttbr & !vmid_mask) | ((vmid as u64 & 0xffff) << 48); VTTBR_EL2.set(vttbr); @@ -182,12 +196,12 @@ impl Aarch64VCpu { self.guest_system_regs.sctlr_el1 = 0x30C50830; self.guest_system_regs.pmcr_el0 = 0; - self.guest_system_regs.vtcr_el2 = probe_vtcr_support() - + (VTCR_EL2::TG0::Granule4KB - + VTCR_EL2::SH0::Inner - + VTCR_EL2::ORGN0::NormalWBRAWA - + VTCR_EL2::IRGN0::NormalWBRAWA) - .value; + // self.guest_system_regs.vtcr_el2 = probe_vtcr_support() + // + (VTCR_EL2::TG0::Granule4KB + // + VTCR_EL2::SH0::Inner + // + VTCR_EL2::ORGN0::NormalWBRAWA + // + VTCR_EL2::IRGN0::NormalWBRAWA) + // .value; let mut hcr_el2 = HCR_EL2::VM::Enable + HCR_EL2::TSC::EnableTrapEl1SmcToEl2 + HCR_EL2::RW::EL1IsAarch64; From 7c3c6d84cb1468a6f7cca5418c3c47c263f931a3 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E5=91=A8=E7=9D=BF?= Date: Mon, 22 Dec 2025 14:32:18 +0800 Subject: [PATCH 29/32] =?UTF-8?q?fix:=20=E4=BF=AE=E5=A4=8D=20vtcr=5Fel2=20?= =?UTF-8?q?=E7=9A=84=E8=AE=BE=E7=BD=AE=E9=80=BB=E8=BE=91=EF=BC=8C=E7=A7=BB?= =?UTF-8?q?=E9=99=A4=E5=A4=9A=E4=BD=99=E7=9A=84=E5=80=BC=E8=AE=A1=E7=AE=97?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- src/vcpu.rs | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/src/vcpu.rs b/src/vcpu.rs index fb5433d..60f2690 100644 --- a/src/vcpu.rs +++ b/src/vcpu.rs @@ -119,8 +119,7 @@ impl Aarch64VCpu { } + (VTCR_EL2::TG0::Granule4KB + VTCR_EL2::SH0::Inner + VTCR_EL2::ORGN0::NormalWBRAWA - + VTCR_EL2::IRGN0::NormalWBRAWA) - .value; + + VTCR_EL2::IRGN0::NormalWBRAWA); self.guest_system_regs.vtcr_el2 = val.value; VTCR_EL2.set(self.guest_system_regs.vtcr_el2); From 84042ae5fdbfe6d4c9ea4076d8caf5d48ca55d19 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E5=91=A8=E7=9D=BF?= Date: Mon, 22 Dec 2025 16:53:28 +0800 Subject: [PATCH 30/32] =?UTF-8?q?feat:=20=E6=B7=BB=E5=8A=A0=20pa=5Fbits=20?= =?UTF-8?q?=E5=AD=97=E6=AE=B5=E4=BB=A5=E6=94=AF=E6=8C=81=E7=89=A9=E7=90=86?= =?UTF-8?q?=E5=9C=B0=E5=9D=80=E4=BD=8D=E6=95=B0=E9=85=8D=E7=BD=AE?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- src/pcpu.rs | 4 ++++ src/vcpu.rs | 34 +++++++++++++++++++++++++++++----- 2 files changed, 33 insertions(+), 5 deletions(-) diff --git a/src/pcpu.rs b/src/pcpu.rs index 14de0af..ae02837 100644 --- a/src/pcpu.rs +++ b/src/pcpu.rs @@ -60,6 +60,10 @@ impl Aarch64PerCpu { crate::vcpu::max_gpt_level(crate::vcpu::pa_bits()) } + pub fn pa_bits(&self) -> usize { + crate::vcpu::pa_bits() + } + pub fn pa_range(&self) -> core::ops::Range { let pa_bits = crate::vcpu::pa_bits(); 0..(1 << pa_bits) diff --git a/src/vcpu.rs b/src/vcpu.rs index 60f2690..3ef7550 100644 --- a/src/vcpu.rs +++ b/src/vcpu.rs @@ -49,6 +49,7 @@ pub struct Aarch64VCpu { /// The MPIDR_EL1 value for the vCPU. mpidr: u64, pub pt_level: usize, + pub pa_bits: usize, } /// Configuration for creating a new `Aarch64VCpu` @@ -61,7 +62,6 @@ pub struct Aarch64VCpuCreateConfig { pub mpidr_el1: u64, /// The address of the device tree blob. pub dtb_addr: usize, - pub pt_level: usize, } /// Configuration for setting up a new `Aarch64VCpu` @@ -78,12 +78,16 @@ impl Aarch64VCpu { let mut ctx = TrapFrame::default(); ctx.set_argument(config.dtb_addr); + let pa_bits = pa_bits(); + let pt_level = max_gpt_level(pa_bits); + Ok(Self { ctx, host_stack_top: 0, guest_system_regs: GuestSystemRegisters::default(), mpidr: config.mpidr_el1, - pt_level: config.pt_level, + pt_level, + pa_bits, }) } @@ -113,18 +117,38 @@ impl Aarch64VCpu { pub fn setup_current_cpu(&mut self, vmid: usize) -> AxResult { // Set VMID then invalidate stage-2 TLB for this VMID to avoid stale translations. let vmid_mask: u64 = 0xffff << 48; - let val = match self.pt_level { + let mut val = match self.pt_level { 4 => VTCR_EL2::SL0::Granule4KBLevel0 + VTCR_EL2::T0SZ.val(64 - 48), _ => VTCR_EL2::SL0::Granule4KBLevel1 + VTCR_EL2::T0SZ.val(64 - 39), - } + (VTCR_EL2::TG0::Granule4KB + }; + + val = val + + match self.pa_bits { + 52..=64 => VTCR_EL2::PS::PA_52B_4PB, + 48..=51 => VTCR_EL2::PS::PA_48B_256TB, + 44..=47 => VTCR_EL2::PS::PA_44B_16TB, + 42..=43 => VTCR_EL2::PS::PA_42B_4TB, + 40..=41 => VTCR_EL2::PS::PA_40B_1TB, + 36..=39 => VTCR_EL2::PS::PA_36B_64GB, + _ => VTCR_EL2::PS::PA_32B_4GB, + }; + + val = val + + VTCR_EL2::TG0::Granule4KB + VTCR_EL2::SH0::Inner + VTCR_EL2::ORGN0::NormalWBRAWA - + VTCR_EL2::IRGN0::NormalWBRAWA); + + VTCR_EL2::IRGN0::NormalWBRAWA; + self.guest_system_regs.vtcr_el2 = val.value; VTCR_EL2.set(self.guest_system_regs.vtcr_el2); + debug!( + "vCPU {:#x} set pt level: {}, pt bits: {}", + self.mpidr, self.pt_level, self.pa_bits + ); let mut vttbr = self.guest_system_regs.vttbr_el2; vttbr = (vttbr & !vmid_mask) | ((vmid as u64 & 0xffff) << 48); + self.guest_system_regs.vttbr_el2 = vttbr; VTTBR_EL2.set(vttbr); unsafe { From 5b7e40dbf67d760e202114ba9431e81c2b45f9e7 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E5=91=A8=E7=9D=BF?= Date: Thu, 29 Jan 2026 17:33:58 +0800 Subject: [PATCH 31/32] =?UTF-8?q?feat:=20=E7=A7=BB=E9=99=A4=20per=5Fcpu=20?= =?UTF-8?q?=E4=BE=9D=E8=B5=96=E5=B9=B6=E9=87=8D=E6=9E=84=20HOST=5FSP=5FEL0?= =?UTF-8?q?=20=E4=BB=A5=E6=94=AF=E6=8C=81=E5=A4=9A=20CPU=20=E7=8E=AF?= =?UTF-8?q?=E5=A2=83?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- Cargo.toml | 1 - src/lib.rs | 12 ++++++++++++ src/vcpu.rs | 34 +++++++++++++++++++++++++++++----- 3 files changed, 41 insertions(+), 6 deletions(-) diff --git a/Cargo.toml b/Cargo.toml index 123d914..5efa730 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -23,4 +23,3 @@ spin = "0.10" axerrno = "0.1.0" axvm-types.workspace = true -percpu = {version = "0.2.0", features = ["arm-el2"]} diff --git a/src/lib.rs b/src/lib.rs index 6eb66d5..5df7c78 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -6,6 +6,9 @@ #[macro_use] extern crate log; +#[macro_use] +extern crate alloc; + mod context_frame; #[macro_use] mod exception_utils; @@ -19,6 +22,7 @@ use core::sync::atomic::{AtomicBool, Ordering}; pub use self::pcpu::Aarch64PerCpu; pub use self::vcpu::{Aarch64VCpu, Aarch64VCpuCreateConfig, Aarch64VCpuSetupConfig}; +use alloc::vec::Vec; pub use axvm_types::addr::*; pub use axvm_types::device::*; pub use exit::*; @@ -40,6 +44,8 @@ pub fn has_hardware_support() -> bool { pub trait CpuHal { fn irq_hanlder(&self); fn inject_interrupt(&self, irq: usize); + /// Cpu hard id list + fn cpu_list(&self) -> Vec; } struct NopHal; @@ -51,6 +57,10 @@ impl CpuHal for NopHal { fn inject_interrupt(&self, _irq: usize) { unimplemented!() } + + fn cpu_list(&self) -> Vec { + unimplemented!() + } } static mut HAL: &dyn CpuHal = &NopHal; @@ -79,4 +89,6 @@ pub fn init_hal(hal: &'static dyn CpuHal) { } else { panic!("arm_vcpu hal has been initialized"); } + + unsafe { vcpu::init_host_sp_el0() }; } diff --git a/src/vcpu.rs b/src/vcpu.rs index 3ef7550..62a297f 100644 --- a/src/vcpu.rs +++ b/src/vcpu.rs @@ -1,6 +1,7 @@ -use core::fmt::Arguments; +use core::{cell::UnsafeCell, fmt::Arguments}; use aarch64_cpu::registers::*; +use alloc::collections::btree_map::BTreeMap; use axerrno::AxResult; use axvm_types::{ addr::{GuestPhysAddr, HostPhysAddr}, @@ -13,17 +14,40 @@ use crate::exception_utils::exception_class_value; use crate::exit::AxVCpuExitReason; use crate::{TrapFrame, inject_interrupt}; -#[percpu::def_percpu] -static HOST_SP_EL0: u64 = 0; +// #[percpu::def_percpu] +static HOST_SP_EL0: SpContainer = SpContainer(UnsafeCell::new(BTreeMap::new())); + +struct SpContainer(UnsafeCell>); + +unsafe impl Send for SpContainer {} +unsafe impl Sync for SpContainer {} + +fn current_cpu_id() -> usize { + let mpidr = MPIDR_EL1.get() as usize; + mpidr & 0xff_ff_ff +} + +pub(crate) unsafe fn init_host_sp_el0() { + let cpu_list = super::hal().cpu_list(); + let host_sp_el0_map = unsafe { &mut *HOST_SP_EL0.0.get() }; + for cpu_id in cpu_list { + host_sp_el0_map.insert(cpu_id, 0); + } +} /// Save host's `SP_EL0` to the current percpu region. unsafe fn save_host_sp_el0() { - unsafe { HOST_SP_EL0.write_current_raw(SP_EL0.get()) } + unsafe { (&mut *HOST_SP_EL0.0.get()).insert(current_cpu_id(), SP_EL0.get()) }; } /// Restore host's `SP_EL0` from the current percpu region. unsafe fn restore_host_sp_el0() { - SP_EL0.set(unsafe { HOST_SP_EL0.read_current_raw() }); + SP_EL0.set(unsafe { + (&*HOST_SP_EL0.0.get()) + .get(¤t_cpu_id()) + .copied() + .expect("Host SP_EL0 not saved!") + }); } /// (v)CPU register state that must be saved or restored when entering/exiting a VM or switching From bfa876e7bf97736b682779cc832bdbea61e44ce0 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E5=91=A8=E7=9D=BF?= Date: Mon, 2 Feb 2026 15:54:38 +0800 Subject: [PATCH 32/32] =?UTF-8?q?feat:=20=E6=9B=B4=E6=96=B0=E7=89=88?= =?UTF-8?q?=E6=9C=AC=E5=8F=B7=E8=87=B3=200.3.0=EF=BC=8C=E5=B9=B6=E6=B7=BB?= =?UTF-8?q?=E5=8A=A0=20VCpuError=20=E9=94=99=E8=AF=AF=E5=A4=84=E7=90=86?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- CHANGELOG.md | 2 +- Cargo.toml | 6 +++--- src/exception.rs | 19 +++++++++---------- src/exception_utils.rs | 10 +++++----- src/exit.rs | 5 +---- src/lib.rs | 13 +++++++++++-- src/pcpu.rs | 5 +++-- src/vcpu.rs | 34 ++++++++++++++++++---------------- 8 files changed, 51 insertions(+), 43 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index a397674..e13aaf8 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,4 +1,4 @@ -## 0.1.1 +## 0.3.0 - Support the new 4-level-ept feature. By default, level 3 ept is used. After enabling this feature, level 4 ept is used. diff --git a/Cargo.toml b/Cargo.toml index 5efa730..9b3afbd 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -13,13 +13,13 @@ keywords = ["hypervisor", "aarch64", "vcpu"] license = "MIT OR Apache-2.0" name = "arm_vcpu" repository = "https://github.com/arceos-hypervisor/arm_vcpu" -version = "0.1.1" +version = "0.3.0" [dependencies] aarch64-cpu = "11.0" log = "0.4" numeric-enum-macro = "0.2" spin = "0.10" - -axerrno = "0.1.0" +thiserror = {version = "2", default-features = false} +anyhow = {version = "1.0", default-features = false} axvm-types.workspace = true diff --git a/src/exception.rs b/src/exception.rs index 1cd68ad..af24e8c 100644 --- a/src/exception.rs +++ b/src/exception.rs @@ -6,13 +6,12 @@ use crate::exception_utils::{ exception_esr, exception_fault_addr, exception_next_instruction_step, exception_sysreg_addr, exception_sysreg_direction_write, exception_sysreg_gpr, }; -use crate::{TrapFrame, handle_irq}; +use crate::{TrapFrame, VCpuError, handle_irq}; use crate::exit::AxVCpuExitReason; use aarch64_cpu::registers::{ ESR_EL2, FAR_EL2, HCR_EL2, HPFAR_EL2, Readable, SCTLR_EL1, SPSR_EL2, VTCR_EL2, VTTBR_EL2, }; -use axerrno::{AxError, AxResult}; use axvm_types::{ addr::GuestPhysAddr, device::{AccessWidth, SysRegAddr}, @@ -72,7 +71,7 @@ core::arch::global_asm!( /// details about the exception including the instruction pointer, faulting address, exception /// syndrome register (ESR), and system control registers. /// -pub fn handle_exception_sync(ctx: &mut TrapFrame) -> AxResult { +pub fn handle_exception_sync(ctx: &mut TrapFrame) -> Result { match exception_class() { Some(ESR_EL2::EC::Value::DataAbortLowerEL) => { let elr = ctx.exception_pc(); @@ -128,7 +127,7 @@ pub fn handle_exception_sync(ctx: &mut TrapFrame) -> AxResult } } -fn handle_data_abort(context_frame: &mut TrapFrame) -> AxResult { +fn handle_data_abort(context_frame: &mut TrapFrame) -> Result { let addr = exception_fault_addr()?; let access_width = exception_data_abort_access_width(); let is_write = exception_data_abort_access_is_write(); @@ -145,12 +144,12 @@ fn handle_data_abort(context_frame: &mut TrapFrame) -> AxResult access_width, - Err(_) => return Err(AxError::InvalidInput), + Err(_) => return Err(VCpuError::InvalidArg("access width invalid")), }; let reg_width = match AccessWidth::try_from(reg_width) { Ok(reg_width) => reg_width, - Err(_) => return Err(AxError::InvalidInput), + Err(_) => return Err(VCpuError::InvalidArg("reg width invalid")), }; if !exception_data_abort_handleable() { @@ -163,7 +162,7 @@ fn handle_data_abort(context_frame: &mut TrapFrame) -> AxResult AxResult` - An `AxResult` containing an `AxVCpuExitReason` indicating /// whether the operation was a read or write and the relevant details. -fn handle_system_register(context_frame: &mut TrapFrame) -> AxResult { +fn handle_system_register(context_frame: &mut TrapFrame) -> Result { let iss = ESR_EL2.read(ESR_EL2::ISS); let addr = exception_sysreg_addr(iss.try_into().unwrap()); @@ -224,7 +223,7 @@ fn handle_system_register(context_frame: &mut TrapFrame) -> AxResult Option> { +fn handle_psci_call(ctx: &mut TrapFrame) -> Option> { const PSCI_FN_RANGE_32: core::ops::RangeInclusive = 0x8400_0000..=0x8400_001F; const PSCI_FN_RANGE_64: core::ops::RangeInclusive = 0xC400_0000..=0xC400_001F; @@ -264,7 +263,7 @@ fn handle_psci_call(ctx: &mut TrapFrame) -> Option> { /// /// This function will judge if the SMC call is a PSCI call, if so, it will handle it as a PSCI call. /// Otherwise, it will forward the SMC call to the ATF directly. -fn handle_smc64_exception(ctx: &mut TrapFrame) -> AxResult { +fn handle_smc64_exception(ctx: &mut TrapFrame) -> Result { // Is this a psci call? if let Some(result) = handle_psci_call(ctx) { result diff --git a/src/exception_utils.rs b/src/exception_utils.rs index 78ef106..7a7e2e0 100644 --- a/src/exception_utils.rs +++ b/src/exception_utils.rs @@ -1,6 +1,6 @@ use aarch64_cpu::registers::*; -use axerrno::{AxResult, ax_err}; -use axvm_types::addr::GuestPhysAddr; + +use crate::{GuestPhysAddr, VCpuError}; /// Retrieves the Exception Syndrome Register (ESR) value from EL2. /// @@ -87,7 +87,7 @@ macro_rules! arm_at { /// /// # Errors /// Returns a `BadState` error if the translation is aborted (indicated by the `F` bit in `PAR_EL1`). -fn translate_far_to_hpfar(far: usize) -> AxResult { +fn translate_far_to_hpfar(far: usize) -> Result { /* * We have * PAR[PA_Shift - 1 : 12] = PA[PA_Shift - 1 : 12] @@ -104,7 +104,7 @@ fn translate_far_to_hpfar(far: usize) -> AxResult { let tmp = PAR_EL1.get(); PAR_EL1.set(par); if (tmp & PAR_EL1::F::TranslationAborted.value) != 0 { - ax_err!(BadState, "PAR_EL1::F::TranslationAborted value") + Err(VCpuError::BadState("PAR_EL1::F::TranslationAborted")) } else { Ok(par_to_far(tmp) as usize) } @@ -128,7 +128,7 @@ fn translate_far_to_hpfar(far: usize) -> AxResult { /// # Returns /// * `AxResult` - The guest physical address that caused the exception, wrapped in an `AxResult`. #[inline(always)] -pub fn exception_fault_addr() -> AxResult { +pub fn exception_fault_addr() -> Result { let far = FAR_EL2.get() as usize; let hpfar = if (exception_esr() & ESR_ELx_S1PTW) == 0 && exception_data_abort_is_permission_fault() { diff --git a/src/exit.rs b/src/exit.rs index 469c718..0f1d289 100644 --- a/src/exit.rs +++ b/src/exit.rs @@ -1,7 +1,4 @@ -use axvm_types::{ - addr::GuestPhysAddr, - device::{AccessWidth, SysRegAddr}, -}; +use crate::{AccessWidth, GuestPhysAddr, SysRegAddr}; /// Reasons for VM-Exits returned by [AxArchVCpu::run]. /// diff --git a/src/lib.rs b/src/lib.rs index 5df7c78..37c7300 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -23,8 +23,7 @@ use core::sync::atomic::{AtomicBool, Ordering}; pub use self::pcpu::Aarch64PerCpu; pub use self::vcpu::{Aarch64VCpu, Aarch64VCpuCreateConfig, Aarch64VCpuSetupConfig}; use alloc::vec::Vec; -pub use axvm_types::addr::*; -pub use axvm_types::device::*; +pub use axvm_types::{addr::*, device::*}; pub use exit::*; /// context frame for aarch64 @@ -92,3 +91,13 @@ pub fn init_hal(hal: &'static dyn CpuHal) { unsafe { vcpu::init_host_sp_el0() }; } + +#[derive(Debug, thiserror::Error, Clone)] +pub enum VCpuError { + #[error("Bad state: {0}")] + BadState(&'static str), + #[error("Invalid argument: {0}")] + InvalidArg(&'static str), + #[error("Unsupported operation")] + Unsupported, +} diff --git a/src/pcpu.rs b/src/pcpu.rs index ae02837..bddc800 100644 --- a/src/pcpu.rs +++ b/src/pcpu.rs @@ -1,5 +1,6 @@ use aarch64_cpu::registers::*; -use axerrno::AxResult; + +use crate::VCpuError; /// Per-CPU data. A pointer to this struct is loaded into TP when a CPU starts. This structure #[repr(C)] @@ -46,7 +47,7 @@ impl Aarch64PerCpu { // } } - pub fn hardware_disable(&mut self) -> AxResult { + pub fn hardware_disable(&mut self) -> Result<(), VCpuError> { // Reset `VBAR_EL2` into previous value. // Safety: // Todo: take care of `preemption` diff --git a/src/vcpu.rs b/src/vcpu.rs index 62a297f..fba1973 100644 --- a/src/vcpu.rs +++ b/src/vcpu.rs @@ -2,17 +2,19 @@ use core::{cell::UnsafeCell, fmt::Arguments}; use aarch64_cpu::registers::*; use alloc::collections::btree_map::BTreeMap; -use axerrno::AxResult; use axvm_types::{ addr::{GuestPhysAddr, HostPhysAddr}, device::SysRegAddr, }; -use crate::context_frame::GuestSystemRegisters; -use crate::exception::{TrapKind, handle_exception_sync}; -use crate::exception_utils::exception_class_value; -use crate::exit::AxVCpuExitReason; -use crate::{TrapFrame, inject_interrupt}; +use crate::{ + TrapFrame, VCpuError, + context_frame::GuestSystemRegisters, + exception::{TrapKind, handle_exception_sync}, + exception_utils::exception_class_value, + exit::AxVCpuExitReason, + inject_interrupt, +}; // #[percpu::def_percpu] static HOST_SP_EL0: SpContainer = SpContainer(UnsafeCell::new(BTreeMap::new())); @@ -98,7 +100,7 @@ pub struct Aarch64VCpuSetupConfig { } impl Aarch64VCpu { - pub fn new(config: Aarch64VCpuCreateConfig) -> AxResult { + pub fn new(config: Aarch64VCpuCreateConfig) -> Result { let mut ctx = TrapFrame::default(); ctx.set_argument(config.dtb_addr); @@ -115,30 +117,30 @@ impl Aarch64VCpu { }) } - pub fn setup(&mut self, config: Aarch64VCpuSetupConfig) -> AxResult { + pub fn setup(&mut self, config: Aarch64VCpuSetupConfig) -> Result<(), VCpuError> { self.init_hv(config); Ok(()) } - pub fn set_dtb_addr(&mut self, dtb_addr: GuestPhysAddr) -> AxResult { + pub fn set_dtb_addr(&mut self, dtb_addr: GuestPhysAddr) -> Result<(), VCpuError> { debug!("vCPU{} set vcpu dtb addr:{dtb_addr:?}", self.mpidr); self.ctx.set_argument(dtb_addr.as_usize()); Ok(()) } - pub fn set_entry(&mut self, entry: GuestPhysAddr) -> AxResult { + pub fn set_entry(&mut self, entry: GuestPhysAddr) -> Result<(), VCpuError> { debug!("vCPU{} set vcpu entry:{entry:?}", self.mpidr); self.set_elr(entry.as_usize()); Ok(()) } - pub fn set_ept_root(&mut self, ept_root: HostPhysAddr) -> AxResult { + pub fn set_ept_root(&mut self, ept_root: HostPhysAddr) -> Result<(), VCpuError> { debug!("vCPU{} set vcpu ept root:{ept_root:#x}", self.mpidr); self.guest_system_regs.vttbr_el2 = ept_root.as_usize() as u64; Ok(()) } - pub fn setup_current_cpu(&mut self, vmid: usize) -> AxResult { + pub fn setup_current_cpu(&mut self, vmid: usize) -> Result<(), VCpuError> { // Set VMID then invalidate stage-2 TLB for this VMID to avoid stale translations. let vmid_mask: u64 = 0xffff << 48; let mut val = match self.pt_level { @@ -188,7 +190,7 @@ impl Aarch64VCpu { Ok(()) } - pub fn run(&mut self) -> AxResult { + pub fn run(&mut self) -> Result { // Run guest. let exit_reson = unsafe { // Save host SP_EL0 to the ctx becase it's used as current task ptr. @@ -206,7 +208,7 @@ impl Aarch64VCpu { self.ctx.set_gpr(idx, val); } - pub fn inject_interrupt(&mut self, vector: usize) -> AxResult { + pub fn inject_interrupt(&mut self, vector: usize) -> Result<(), VCpuError> { inject_interrupt(vector); Ok(()) } @@ -357,7 +359,7 @@ impl Aarch64VCpu { /// - [`AxVCpuExitReason`]: a wrappered VM-Exit reason needed to be handled by the hypervisor. /// /// This function may panic for unhandled exceptions. - fn vmexit_handler(&mut self, exit_reason: TrapKind) -> AxResult { + fn vmexit_handler(&mut self, exit_reason: TrapKind) -> Result { trace!( "Aarch64VCpu vmexit_handler() esr:{:#x} ctx:{:#x?}", exception_class_value(), @@ -415,7 +417,7 @@ impl Aarch64VCpu { write: bool, value: u64, reg: usize, - ) -> AxResult> { + ) -> Result, VCpuError> { const SYSREG_ICC_SGI1R_EL1: SysRegAddr = SysRegAddr::new(0x3A_3016); // ICC_SGI1R_EL1 match (addr, write) {