From d5d8ae997b642557ed9684320f2405bcff36110d Mon Sep 17 00:00:00 2001 From: Debin Date: Thu, 27 Mar 2025 18:31:46 +0800 Subject: [PATCH 01/10] feat(vcpu): add interrupt injection support and enhance system register handling - Add interrupt injection support to Aarch64VCpu - Implement get_sysreg_device function for system register access - Update GuestSystemRegisters to include CNTHCTL_EL2 - Modify exception handling to use SysRegAddr - Adjust vcpu initialization to enable virtual IRQ and FIQ --- Cargo.toml | 3 ++ src/context_frame.rs | 3 ++ src/exception.rs | 15 ++++---- src/lib.rs | 2 ++ src/sysreg/cntp_ctl_el0.rs | 50 ++++++++++++++++++++++++++ src/sysreg/cntp_tval_el0.rs | 72 +++++++++++++++++++++++++++++++++++++ src/sysreg/cntpct_el0.rs | 55 ++++++++++++++++++++++++++++ src/sysreg/mod.rs | 22 ++++++++++++ src/vcpu.rs | 32 ++++++++++++----- 9 files changed, 240 insertions(+), 14 deletions(-) create mode 100644 src/sysreg/cntp_ctl_el0.rs create mode 100644 src/sysreg/cntp_tval_el0.rs create mode 100644 src/sysreg/cntpct_el0.rs create mode 100644 src/sysreg/mod.rs diff --git a/Cargo.toml b/Cargo.toml index e193ea6..87d70b2 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -17,3 +17,6 @@ aarch64_sysreg = "0.1.1" axaddrspace = { git = "https://github.com/arceos-hypervisor/axaddrspace.git" } axvcpu = { git = "https://github.com/arceos-hypervisor/axvcpu.git" } +axhal = { git = "https://github.com/arceos-hypervisor/arceos.git", branch = "vmm_inject_interrupt" } +axdevice_base = { git = "https://github.com/arceos-hypervisor/axdevice_crates.git"} +axvisor_api = { git = "https://github.com/arceos-hypervisor/axvisor_api.git", branch = "inject_interrupt" } diff --git a/src/context_frame.rs b/src/context_frame.rs index 6da0d38..a9833bf 100644 --- a/src/context_frame.rs +++ b/src/context_frame.rs @@ -156,6 +156,7 @@ pub struct GuestSystemRegisters { cntv_ctl_el0: u32, cntp_tval_el0: u32, cntv_tval_el0: u32, + pub cnthctl_el2: u64, // vpidr and vmpidr vpidr_el2: u32, @@ -220,6 +221,7 @@ impl GuestSystemRegisters { asm!("mrs {0:x}, CNTP_TVAL_EL0", out(reg) self.cntp_tval_el0); asm!("mrs {0:x}, CNTV_TVAL_EL0", out(reg) self.cntv_tval_el0); asm!("mrs {0}, CNTVCT_EL0", out(reg) self.cntvct_el0); + asm!("mrs {0}, CNTHCTL_EL2", out(reg) self.cnthctl_el2); // MRS!("self.vpidr_el2, VPIDR_EL2, "x"); asm!("mrs {0}, VMPIDR_EL2", out(reg) self.vmpidr_el2); @@ -265,6 +267,7 @@ impl GuestSystemRegisters { asm!("msr CNTV_CVAL_EL0, {0}", in(reg) self.cntv_cval_el0); asm!("msr CNTKCTL_EL1, {0:x}", in (reg) self.cntkctl_el1); asm!("msr CNTV_CTL_EL0, {0:x}", in (reg) self.cntv_ctl_el0); + asm!("msr CNTHCTL_EL2, {0}", in(reg) self.cnthctl_el2); // The restoration of SP_EL0 is done in `exception_return_el2`, // which move the value from `self.ctx.sp_el0` to `SP_EL0`. // asm!("msr SP_EL0, {0}", in(reg) self.sp_el0); diff --git a/src/exception.rs b/src/exception.rs index 738178e..40047e8 100644 --- a/src/exception.rs +++ b/src/exception.rs @@ -1,9 +1,5 @@ use aarch64_cpu::registers::{ESR_EL2, HCR_EL2, Readable, SCTLR_EL1, VTCR_EL2, VTTBR_EL2}; -use axaddrspace::GuestPhysAddr; -use axerrno::{AxError, AxResult}; -use axvcpu::{AccessWidth, AxVCpuExitReason}; - use crate::TrapFrame; use crate::exception_utils::{ exception_class, exception_class_value, exception_data_abort_access_is_write, @@ -13,6 +9,10 @@ use crate::exception_utils::{ exception_esr, exception_fault_addr, exception_next_instruction_step, exception_sysreg_addr, exception_sysreg_direction_write, exception_sysreg_gpr, }; +use axaddrspace::GuestPhysAddr; +use axaddrspace::device::{AccessWidth, SysRegAddr}; +use axerrno::{AxError, AxResult}; +use axvcpu::AxVCpuExitReason; numeric_enum_macro::numeric_enum! { #[repr(u8)] @@ -203,11 +203,14 @@ fn handle_system_register(context_frame: &mut TrapFrame) -> AxResult for SysCntpCtlEl0 { + fn emu_type(&self) -> EmuDeviceType { + EmuDeviceType::EmuDeviceTConsole + } + + fn address_range(&self) -> SysRegAddrRange { + SysRegAddrRange { + start: SysRegAddr::new(SystemRegType::CNTP_CTL_EL0 as usize), + end: SysRegAddr::new(SystemRegType::CNTP_CTL_EL0 as usize), + } + } + + fn handle_read( + &self, + addr: ::Addr, + width: AccessWidth, + ) -> AxResult { + todo!() + } + + fn handle_write( + &self, + addr: ::Addr, + width: AccessWidth, + val: usize, + ) -> AxResult { + info!("Write to emulator register: {:?}, value: {}", addr, val); + Ok(()) + } +} + +pub struct SysCntpCtlEl0 { + // Fields +} + +impl SysCntpCtlEl0 { + pub fn new() -> Self { + Self { + // Initialize fields + } + } +} diff --git a/src/sysreg/cntp_tval_el0.rs b/src/sysreg/cntp_tval_el0.rs new file mode 100644 index 0000000..6642043 --- /dev/null +++ b/src/sysreg/cntp_tval_el0.rs @@ -0,0 +1,72 @@ +extern crate alloc; + +use aarch64_sysreg::SystemRegType; + +use aarch64_cpu::registers::{CNTPCT_EL0, Readable}; + +use axaddrspace::{ + GuestPhysAddrRange, + device::{AccessWidth, DeviceAddrRange, SysRegAddr, SysRegAddrRange}, +}; + +use axdevice_base::{BaseDeviceOps, EmuDeviceType}; + +use axhal::irq::inject_interrupt; +use axvisor_api::time::{current_time_nanos, register_timer}; + +use core::time::Duration; + +use alloc::boxed::Box; + +use axerrno::AxResult; + +impl BaseDeviceOps for SysCntpTvalEl0 { + fn emu_type(&self) -> EmuDeviceType { + EmuDeviceType::EmuDeviceTConsole + } + + fn address_range(&self) -> SysRegAddrRange { + SysRegAddrRange { + start: SysRegAddr::new(SystemRegType::CNTP_TVAL_EL0 as usize), + end: SysRegAddr::new(SystemRegType::CNTP_TVAL_EL0 as usize), + } + } + + fn handle_read( + &self, + addr: ::Addr, + width: AccessWidth, + ) -> AxResult { + todo!() + } + + fn handle_write( + &self, + addr: ::Addr, + width: AccessWidth, + val: usize, + ) -> AxResult { + info!("Write to emulator register: {:?}, value: {}", addr, val); + let now = current_time_nanos(); + info!("Current time: {}, deadline: {}", now, now + val as u64); + register_timer( + Duration::from_nanos(now + val as u64), + Box::new(|_| { + inject_interrupt(30); + }), + ); + Ok(()) + } +} + +pub struct SysCntpTvalEl0 { + // Fields +} + +impl SysCntpTvalEl0 { + pub fn new() -> Self { + Self { + // Initialize fields + } + } +} diff --git a/src/sysreg/cntpct_el0.rs b/src/sysreg/cntpct_el0.rs new file mode 100644 index 0000000..be3254a --- /dev/null +++ b/src/sysreg/cntpct_el0.rs @@ -0,0 +1,55 @@ +use aarch64_sysreg::SystemRegType; + +use aarch64_cpu::registers::{CNTPCT_EL0, Readable}; + +use axaddrspace::{ + GuestPhysAddrRange, + device::{AccessWidth, DeviceAddrRange, SysRegAddr, SysRegAddrRange}, +}; + +use axdevice_base::{BaseDeviceOps, EmuDeviceType}; + +use axerrno::AxResult; + +impl BaseDeviceOps for SysCntpctEl0 { + fn emu_type(&self) -> EmuDeviceType { + EmuDeviceType::EmuDeviceTConsole + } + + fn address_range(&self) -> SysRegAddrRange { + SysRegAddrRange { + start: SysRegAddr::new(SystemRegType::CNTPCT_EL0 as usize), + end: SysRegAddr::new(SystemRegType::CNTPCT_EL0 as usize), + } + } + + fn handle_read( + &self, + addr: ::Addr, + width: AccessWidth, + ) -> AxResult { + Ok(CNTPCT_EL0.get() as usize) + } + + fn handle_write( + &self, + addr: ::Addr, + width: AccessWidth, + val: usize, + ) -> AxResult { + info!("Write to emulator register: {:?}, value: {}", addr, val); + Ok(()) + } +} + +pub struct SysCntpctEl0 { + // Fields +} + +impl SysCntpctEl0 { + pub fn new() -> Self { + Self { + // Initialize fields + } + } +} diff --git a/src/sysreg/mod.rs b/src/sysreg/mod.rs new file mode 100644 index 0000000..bafcf1e --- /dev/null +++ b/src/sysreg/mod.rs @@ -0,0 +1,22 @@ +extern crate alloc; + +use alloc::sync::Arc; +use alloc::{vec, vec::Vec}; +use axdevice_base::BaseSysRegDeviceOps; + +mod cntp_ctl_el0; +pub use cntp_ctl_el0::SysCntpCtlEl0; + +mod cntpct_el0; +pub use cntpct_el0::SysCntpctEl0; + +mod cntp_tval_el0; +pub use cntp_tval_el0::SysCntpTvalEl0; + +pub fn get_sysreg_device() -> Vec> { + vec![ + Arc::new(SysCntpCtlEl0::new()), + Arc::new(SysCntpctEl0::new()), + Arc::new(SysCntpTvalEl0::new()), + ] +} diff --git a/src/vcpu.rs b/src/vcpu.rs index e64ae57..91158dc 100644 --- a/src/vcpu.rs +++ b/src/vcpu.rs @@ -3,14 +3,14 @@ use core::marker::PhantomData; use aarch64_cpu::registers::{CNTHCTL_EL2, HCR_EL2, SP_EL0, SPSR_EL1, VTCR_EL2}; use tock_registers::interfaces::{ReadWriteable, Readable, Writeable}; -use axaddrspace::{GuestPhysAddr, HostPhysAddr}; -use axerrno::AxResult; -use axvcpu::{AxVCpuExitReason, AxVCpuHal}; - use crate::TrapFrame; use crate::context_frame::GuestSystemRegisters; use crate::exception::{TrapKind, handle_exception_sync}; use crate::exception_utils::exception_class_value; +use axaddrspace::{GuestPhysAddr, HostPhysAddr}; +use axerrno::AxResult; +use axhal::irq::inject_interrupt; +use axvcpu::{AxVCpuExitReason, AxVCpuHal}; #[percpu::def_percpu] static HOST_SP_EL0: u64 = 0; @@ -121,6 +121,11 @@ impl axvcpu::AxArchVCpu for Aarch64VCpu { fn set_gpr(&mut self, idx: usize, val: usize) { self.ctx.set_gpr(idx, val); } + + fn inject_interrupt(&mut self, vector: usize) -> AxResult { + inject_interrupt(vector); + Ok(()) + } } // Private function @@ -151,9 +156,13 @@ impl Aarch64VCpu { + VTCR_EL2::SL0.val(0b01) + VTCR_EL2::T0SZ.val(64 - 39)) .into(); - self.guest_system_regs.hcr_el2 = - (HCR_EL2::VM::Enable + HCR_EL2::RW::EL1IsAarch64 + HCR_EL2::TSC::EnableTrapEl1SmcToEl2) - .into(); + self.guest_system_regs.hcr_el2 = (HCR_EL2::VM::Enable + + HCR_EL2::RW::EL1IsAarch64 + + HCR_EL2::IMO::EnableVirtualIRQ + + HCR_EL2::FMO::EnableVirtualFIQ + + HCR_EL2::TSC::EnableTrapEl1SmcToEl2 + + HCR_EL2::RW::EL1IsAarch64) + .into(); // self.system_regs.hcr_el2 |= 1<<27; // + HCR_EL2::IMO::EnableVirtualIRQ).into(); @@ -203,7 +212,14 @@ impl Aarch64VCpu { } // the dummy return value, the real return value is in x0 when `return_run_guest` returns - 0 + let exit_reason: usize; + core::arch::asm!( + "mov {}, x0", + out(reg) exit_reason, + options(nostack) + ); + exit_reason + } /// Restores guest system control registers. From 1b8da5e53e271b02189e6977120d405e68aca55f Mon Sep 17 00:00:00 2001 From: Debin Date: Mon, 31 Mar 2025 22:45:08 +0800 Subject: [PATCH 02/10] feat(sysreg): update handle_read and handle_write to use unused parameters --- src/sysreg/cntp_tval_el0.rs | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/src/sysreg/cntp_tval_el0.rs b/src/sysreg/cntp_tval_el0.rs index 6642043..b54832c 100644 --- a/src/sysreg/cntp_tval_el0.rs +++ b/src/sysreg/cntp_tval_el0.rs @@ -34,8 +34,8 @@ impl BaseDeviceOps for SysCntpTvalEl0 { fn handle_read( &self, - addr: ::Addr, - width: AccessWidth, + _addr: ::Addr, + _width: AccessWidth, ) -> AxResult { todo!() } @@ -43,7 +43,7 @@ impl BaseDeviceOps for SysCntpTvalEl0 { fn handle_write( &self, addr: ::Addr, - width: AccessWidth, + _width: AccessWidth, val: usize, ) -> AxResult { info!("Write to emulator register: {:?}, value: {}", addr, val); From 32866b47bd3f108876a7dd94d30d20ab262e97db Mon Sep 17 00:00:00 2001 From: aarkegz Date: Mon, 7 Apr 2025 15:07:11 +0800 Subject: [PATCH 03/10] update dependecies --- Cargo.toml | 5 ++--- src/lib.rs | 4 ++-- src/sysreg/cntp_tval_el0.rs | 11 +++-------- src/vcpu.rs | 4 +--- 4 files changed, 8 insertions(+), 16 deletions(-) diff --git a/Cargo.toml b/Cargo.toml index 87d70b2..bd9a6d9 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -16,7 +16,6 @@ percpu = "0.1.4" aarch64_sysreg = "0.1.1" axaddrspace = { git = "https://github.com/arceos-hypervisor/axaddrspace.git" } -axvcpu = { git = "https://github.com/arceos-hypervisor/axvcpu.git" } -axhal = { git = "https://github.com/arceos-hypervisor/arceos.git", branch = "vmm_inject_interrupt" } -axdevice_base = { git = "https://github.com/arceos-hypervisor/axdevice_crates.git"} +axvcpu = { git = "https://github.com/arceos-hypervisor/axvcpu.git", branch = "inject_interrupt" } +axdevice_base = { git = "https://github.com/arceos-hypervisor/axdevice_crates.git", branch = "inject_interrupt" } axvisor_api = { git = "https://github.com/arceos-hypervisor/axvisor_api.git", branch = "inject_interrupt" } diff --git a/src/lib.rs b/src/lib.rs index 0f51160..e6221e1 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -12,11 +12,11 @@ mod exception_utils; mod exception; mod pcpu; mod smc; -mod vcpu; mod sysreg; +mod vcpu; -pub use self::sysreg::get_sysreg_device; pub use self::pcpu::Aarch64PerCpu; +pub use self::sysreg::get_sysreg_device; pub use self::vcpu::{Aarch64VCpu, Aarch64VCpuCreateConfig}; /// context frame for aarch64 diff --git a/src/sysreg/cntp_tval_el0.rs b/src/sysreg/cntp_tval_el0.rs index 6642043..5a54b12 100644 --- a/src/sysreg/cntp_tval_el0.rs +++ b/src/sysreg/cntp_tval_el0.rs @@ -8,17 +8,12 @@ use axaddrspace::{ GuestPhysAddrRange, device::{AccessWidth, DeviceAddrRange, SysRegAddr, SysRegAddrRange}, }; - use axdevice_base::{BaseDeviceOps, EmuDeviceType}; - -use axhal::irq::inject_interrupt; +use axerrno::AxResult; use axvisor_api::time::{current_time_nanos, register_timer}; -use core::time::Duration; - use alloc::boxed::Box; - -use axerrno::AxResult; +use core::time::Duration; impl BaseDeviceOps for SysCntpTvalEl0 { fn emu_type(&self) -> EmuDeviceType { @@ -52,7 +47,7 @@ impl BaseDeviceOps for SysCntpTvalEl0 { register_timer( Duration::from_nanos(now + val as u64), Box::new(|_| { - inject_interrupt(30); + axvisor_api::arch::hardware_inject_virtual_interrupt(30); }), ); Ok(()) diff --git a/src/vcpu.rs b/src/vcpu.rs index 91158dc..883576c 100644 --- a/src/vcpu.rs +++ b/src/vcpu.rs @@ -9,7 +9,6 @@ use crate::exception::{TrapKind, handle_exception_sync}; use crate::exception_utils::exception_class_value; use axaddrspace::{GuestPhysAddr, HostPhysAddr}; use axerrno::AxResult; -use axhal::irq::inject_interrupt; use axvcpu::{AxVCpuExitReason, AxVCpuHal}; #[percpu::def_percpu] @@ -123,7 +122,7 @@ impl axvcpu::AxArchVCpu for Aarch64VCpu { } fn inject_interrupt(&mut self, vector: usize) -> AxResult { - inject_interrupt(vector); + axvisor_api::arch::hardware_inject_virtual_interrupt(vector as u8); Ok(()) } } @@ -219,7 +218,6 @@ impl Aarch64VCpu { options(nostack) ); exit_reason - } /// Restores guest system control registers. From 4017f66587dc3c491987c92a8589ab86257d59ac Mon Sep 17 00:00:00 2001 From: aarkegz Date: Mon, 14 Apr 2025 15:21:56 +0800 Subject: [PATCH 04/10] update percpu --- Cargo.toml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Cargo.toml b/Cargo.toml index bd9a6d9..a1acd33 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -12,7 +12,7 @@ tock-registers = "0.8" numeric-enum-macro = "0.2" axerrno = "0.1.0" -percpu = "0.1.4" +percpu = "0.2" aarch64_sysreg = "0.1.1" axaddrspace = { git = "https://github.com/arceos-hypervisor/axaddrspace.git" } From aba4be448788758601dc1998c08dec402ed69fa6 Mon Sep 17 00:00:00 2001 From: hky1999 Date: Tue, 1 Apr 2025 14:44:30 +0800 Subject: [PATCH 05/10] Update percpu version to 0.2.0 (#25) --- Cargo.toml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Cargo.toml b/Cargo.toml index a1acd33..371b918 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -12,7 +12,7 @@ tock-registers = "0.8" numeric-enum-macro = "0.2" axerrno = "0.1.0" -percpu = "0.2" +percpu = { version = "0.2.0", features = ["arm-el2"] } aarch64_sysreg = "0.1.1" axaddrspace = { git = "https://github.com/arceos-hypervisor/axaddrspace.git" } From 1793cb16512e12f82f875247925226ef57ad5e93 Mon Sep 17 00:00:00 2001 From: Debin Date: Sat, 10 May 2025 17:27:05 +0800 Subject: [PATCH 06/10] Fix (workaround): correct return value handling for run_guest function (#26) * fix(vcpu): correct return value handling for `run_guest` function - Update the `run_guest` function to properly handle the return value from `vmexit_trampoline` - Use inline assembly to extract the exit reason from x0 register - Return the extracted exit reason instead of a dummy value * format code * refactor(exception): update vmexit_trampoline and vcpu handling - Add unsafe annotation to vmexit_trampoline function - Implement temporary workaround for issue [#22](https://github.com/arceos-hypervisor/arm_vcpu/issues/22) in vcpu.rs - Include related PR and issue references in vcpu.rs * format code * refactor(exception): remove unnecessary unsafe(naked) attribute - Replace #[unsafe(naked)] with #[naked] for the vmexit_trampoline function - This change simplifies the code without affecting functionality * ci: switch to stable Rust toolchain - Update dtolnay/rust-toolchain action from nightly to stable - This change ensures more consistent and reliable builds * ci: update Rust toolchain to nightly-2024-12-25 for documentation build * ci: fix incorrect way to specify rust toolchain version in doc job --------- Co-authored-by: aarkegz --- .github/workflows/ci.yml | 2 ++ src/vcpu.rs | 16 ++++++++++------ 2 files changed, 12 insertions(+), 6 deletions(-) diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index 5f23219..b32ea82 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -43,6 +43,8 @@ jobs: steps: - uses: actions/checkout@v4 - uses: dtolnay/rust-toolchain@nightly + with: + toolchain: nightly-2024-12-25 - name: Build docs continue-on-error: ${{ github.ref != env.default-branch && github.event_name != 'pull_request' }} run: | diff --git a/src/vcpu.rs b/src/vcpu.rs index 883576c..b85180d 100644 --- a/src/vcpu.rs +++ b/src/vcpu.rs @@ -210,13 +210,17 @@ impl Aarch64VCpu { ); } - // the dummy return value, the real return value is in x0 when `return_run_guest` returns + // When `vmexit_trampoline` returns, it will come back here, with its return value stored in x0. Extract it and return `run_guest`. + // Related PR: https://github.com/arceos-hypervisor/arm_vcpu/pull/26 + // Related issue: https://github.com/arceos-hypervisor/arm_vcpu/issues/22 + // This is a temporary workaround for the issue. let exit_reason: usize; - core::arch::asm!( - "mov {}, x0", - out(reg) exit_reason, - options(nostack) - ); + unsafe { + core::arch::asm!( + "mov {}, x0", + out(reg) exit_reason + ); + } exit_reason } From a43f8f873062225aaaa8b0310a267a482eae90d9 Mon Sep 17 00:00:00 2001 From: szy <673586548@qq.com> Date: Wed, 14 May 2025 10:54:33 +0800 Subject: [PATCH 07/10] Fixed bug: missing stack pointer setup in some handler (#27) Co-authored-by: songzhy --- src/exception.S | 2 ++ 1 file changed, 2 insertions(+) diff --git a/src/exception.S b/src/exception.S index 0c4dcb6..9513703 100644 --- a/src/exception.S +++ b/src/exception.S @@ -71,6 +71,7 @@ .macro HANDLE_CURRENT_IRQ .p2align 7 SAVE_REGS_FROM_EL1 + mov x0, sp bl current_el_irq_handler b .Lexception_return_el2 .endm @@ -78,6 +79,7 @@ .macro HANDLE_CURRENT_SYNC .p2align 7 SAVE_REGS_FROM_EL1 + mov x0, sp bl current_el_sync_handler b .Lexception_return_el2 .endm From c099cef098baed200a74103812502bdaec69e15f Mon Sep 17 00:00:00 2001 From: Su Mingxian Date: Mon, 26 May 2025 18:59:04 +0800 Subject: [PATCH 08/10] Add a `#[naked]` version of `run_guest`, to fix #22 the return value issue (#28) * add a `#[naked]` version of `run_guest`, to be tested * remove the old version of `run_guest` * formatted * add more detailed comments * mark `run_guest_panic` as never returns * add a paragraph describing why using x0 is safe --- src/vcpu.rs | 52 +++++++++++++++++++++++++++++----------------------- 1 file changed, 29 insertions(+), 23 deletions(-) diff --git a/src/vcpu.rs b/src/vcpu.rs index b85180d..d35acfd 100644 --- a/src/vcpu.rs +++ b/src/vcpu.rs @@ -191,37 +191,43 @@ 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`. - #[inline(never)] - unsafe fn run_guest(&mut self) -> usize { + #[naked] + 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 + // the dummy return value `0` of `run_guest` as the actual return value. By replacing the + // original `run_guest` with the current naked one, we eliminate the dummy code path of the + // original version, and ensure that the compiler does not perform any unexpected return + // value optimization. unsafe { - // Save function call context. - core::arch::asm!( + core::arch::naked_asm!( // Save host context. save_regs_to_stack!(), + // Save current host stack top to `self.host_stack_top`. + // + // 'extern "C"' here specifies the aapcs64 calling convention, according to which + // the first and only parameter, the pointer of self, should be in x0: "mov x9, sp", - "mov x10, x11", - // Save current host stack top in the `Aarch64VCpu` struct. - "str x9, [x10]", - "mov x0, x11", + "add x0, x0, {host_stack_top_offset}", + "str x9, [x0]", + // Go to `context_vm_entry`. "b context_vm_entry", - // in(reg) here is dangerous, because the compiler may use the register we want to use, creating a conflict. - in("x11") &self.host_stack_top as *const _ as usize, - options(nostack) + // Panic if the control flow comes back here, which should never happen. + "b {run_guest_panic}", + host_stack_top_offset = const core::mem::size_of::(), + run_guest_panic = sym Self::run_guest_panic, ); } + } - // When `vmexit_trampoline` returns, it will come back here, with its return value stored in x0. Extract it and return `run_guest`. - // Related PR: https://github.com/arceos-hypervisor/arm_vcpu/pull/26 - // Related issue: https://github.com/arceos-hypervisor/arm_vcpu/issues/22 - // This is a temporary workaround for the issue. - let exit_reason: usize; - unsafe { - core::arch::asm!( - "mov {}, x0", - out(reg) exit_reason - ); - } - exit_reason + /// This function is called when the control flow comes back to `run_guest`. To provide a error + /// message for debugging purposes. + /// + /// This function may fail as the stack may have been corrupted when this function is called. + /// But we won't handle it here for now. + unsafe fn run_guest_panic() -> ! { + panic!("run_guest_panic"); } /// Restores guest system control registers. From 17e6688894d248dc20faa879891dd5055cd24fe2 Mon Sep 17 00:00:00 2001 From: Debin Date: Fri, 6 Jun 2025 15:25:40 +0800 Subject: [PATCH 09/10] refactor(sysreg): remove unused imports and simplify code - Remove unused imports for GuestPhysAddrRange and BaseMmioDeviceOps - Simplify import statements for axaddrspace and aarch64_cpu - Update function parameters to use _ to ignore unused values --- src/sysreg/cntp_ctl_el0.rs | 9 ++++----- src/sysreg/cntp_tval_el0.rs | 8 +++----- src/sysreg/cntpct_el0.rs | 13 ++++++------- 3 files changed, 13 insertions(+), 17 deletions(-) diff --git a/src/sysreg/cntp_ctl_el0.rs b/src/sysreg/cntp_ctl_el0.rs index 2b41113..0c04bda 100644 --- a/src/sysreg/cntp_ctl_el0.rs +++ b/src/sysreg/cntp_ctl_el0.rs @@ -1,9 +1,8 @@ use aarch64_sysreg::SystemRegType; -use axaddrspace::GuestPhysAddrRange; use axaddrspace::device::{AccessWidth, DeviceAddrRange, SysRegAddr, SysRegAddrRange}; use axdevice_base::EmuDeviceType; -use axdevice_base::{BaseDeviceOps, BaseMmioDeviceOps}; +use axdevice_base::BaseDeviceOps; use axerrno::AxResult; impl BaseDeviceOps for SysCntpCtlEl0 { @@ -20,8 +19,8 @@ impl BaseDeviceOps for SysCntpCtlEl0 { fn handle_read( &self, - addr: ::Addr, - width: AccessWidth, + _addr: ::Addr, + _width: AccessWidth, ) -> AxResult { todo!() } @@ -29,7 +28,7 @@ impl BaseDeviceOps for SysCntpCtlEl0 { fn handle_write( &self, addr: ::Addr, - width: AccessWidth, + _width: AccessWidth, val: usize, ) -> AxResult { info!("Write to emulator register: {:?}, value: {}", addr, val); diff --git a/src/sysreg/cntp_tval_el0.rs b/src/sysreg/cntp_tval_el0.rs index 1efa7be..972a3d4 100644 --- a/src/sysreg/cntp_tval_el0.rs +++ b/src/sysreg/cntp_tval_el0.rs @@ -2,12 +2,10 @@ extern crate alloc; use aarch64_sysreg::SystemRegType; -use aarch64_cpu::registers::{CNTPCT_EL0, Readable}; -use axaddrspace::{ - GuestPhysAddrRange, - device::{AccessWidth, DeviceAddrRange, SysRegAddr, SysRegAddrRange}, -}; +use axaddrspace:: + device::{AccessWidth, DeviceAddrRange, SysRegAddr, SysRegAddrRange} +; use axdevice_base::{BaseDeviceOps, EmuDeviceType}; use axerrno::AxResult; use axvisor_api::time::{current_time_nanos, register_timer}; diff --git a/src/sysreg/cntpct_el0.rs b/src/sysreg/cntpct_el0.rs index be3254a..43e6cc8 100644 --- a/src/sysreg/cntpct_el0.rs +++ b/src/sysreg/cntpct_el0.rs @@ -2,10 +2,9 @@ use aarch64_sysreg::SystemRegType; use aarch64_cpu::registers::{CNTPCT_EL0, Readable}; -use axaddrspace::{ - GuestPhysAddrRange, - device::{AccessWidth, DeviceAddrRange, SysRegAddr, SysRegAddrRange}, -}; +use axaddrspace:: + device::{AccessWidth, DeviceAddrRange, SysRegAddr, SysRegAddrRange} +; use axdevice_base::{BaseDeviceOps, EmuDeviceType}; @@ -25,8 +24,8 @@ impl BaseDeviceOps for SysCntpctEl0 { fn handle_read( &self, - addr: ::Addr, - width: AccessWidth, + _addr: ::Addr, + _width: AccessWidth, ) -> AxResult { Ok(CNTPCT_EL0.get() as usize) } @@ -34,7 +33,7 @@ impl BaseDeviceOps for SysCntpctEl0 { fn handle_write( &self, addr: ::Addr, - width: AccessWidth, + _width: AccessWidth, val: usize, ) -> AxResult { info!("Write to emulator register: {:?}, value: {}", addr, val); From ed236902f8c5c00fb0545c2376008fb1023675c3 Mon Sep 17 00:00:00 2001 From: Debin Date: Mon, 16 Jun 2025 11:06:34 +0800 Subject: [PATCH 10/10] refactor: clean up import statements and comment out unused function --- src/sysreg/cntp_tval_el0.rs | 5 +---- src/vcpu.rs | 8 ++++---- 2 files changed, 5 insertions(+), 8 deletions(-) diff --git a/src/sysreg/cntp_tval_el0.rs b/src/sysreg/cntp_tval_el0.rs index 972a3d4..a685168 100644 --- a/src/sysreg/cntp_tval_el0.rs +++ b/src/sysreg/cntp_tval_el0.rs @@ -2,10 +2,7 @@ extern crate alloc; use aarch64_sysreg::SystemRegType; - -use axaddrspace:: - device::{AccessWidth, DeviceAddrRange, SysRegAddr, SysRegAddrRange} -; +use axaddrspace::device::{AccessWidth, DeviceAddrRange, SysRegAddr, SysRegAddrRange}; use axdevice_base::{BaseDeviceOps, EmuDeviceType}; use axerrno::AxResult; use axvisor_api::time::{current_time_nanos, register_timer}; diff --git a/src/vcpu.rs b/src/vcpu.rs index d35acfd..46e9d4f 100644 --- a/src/vcpu.rs +++ b/src/vcpu.rs @@ -121,10 +121,10 @@ impl axvcpu::AxArchVCpu for Aarch64VCpu { self.ctx.set_gpr(idx, val); } - fn inject_interrupt(&mut self, vector: usize) -> AxResult { - axvisor_api::arch::hardware_inject_virtual_interrupt(vector as u8); - Ok(()) - } + // fn inject_interrupt(&mut self, vector: usize) -> AxResult { + // axvisor_api::arch::hardware_inject_virtual_interrupt(vector as u8); + // Ok(()) + // } } // Private function