Skip to content
Draft
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
30 commits
Select commit Hold shift + click to select a range
aa978f1
fix: irq settings
ZR233 Sep 8, 2025
c6eaba4
fix: ci
ZR233 Sep 8, 2025
b1f5da9
feat: add max gpt level api
ZR233 Sep 9, 2025
07f37ba
fmt code
ZR233 Sep 9, 2025
52b1ed3
fix: change function signature of run_guest to use "C" calling conven…
ZR233 Sep 9, 2025
980a003
fix: specify calling convention for external function declaration
ZR233 Sep 9, 2025
b24cc36
fix: specify "C" calling convention for vmexit_trampoline function
ZR233 Sep 9, 2025
50fd109
fix: add target architecture configuration for aarch64
ZR233 Nov 11, 2025
fd870a0
fix: remove "C" calling convention specification for vmexit_trampolin…
ZR233 Nov 13, 2025
fca8924
fix: update axaddrspace dependency version to 0.2 and format axvcpu d…
ZR233 Nov 13, 2025
077e76b
fix: revert axvcpu dependency to version 0.1.0
ZR233 Nov 13, 2025
e5edb7c
fix: update aarch64-cpu dependency to version 11.0 and add CpuHal tra…
ZR233 Nov 14, 2025
0590e26
fix: refactor vcpu and exception handling, update dependencies, and i…
ZR233 Nov 14, 2025
d536df8
fix: 导入 axvm_types 的地址和设备模块
ZR233 Nov 14, 2025
601906f
fix: 重构 Aarch64PerCpu 结构体,移除 cpu_id 字段并调整方法可见性
ZR233 Nov 17, 2025
a6a16ef
fix: add logs
ZR233 Nov 17, 2025
14daa15
fix: 将 Aarch64VCpu 的方法可见性从私有改为公有
ZR233 Nov 25, 2025
e7a6327
feat: 添加 set_dtb_addr 方法以设置 vcpu 的 dtb 地址
ZR233 Nov 26, 2025
df6618d
fix: 移除未使用的导入以清理代码
ZR233 Nov 27, 2025
7c7c8ea
fix: 移除未使用的 OnceCell 导入以清理代码
ZR233 Nov 28, 2025
48e90f2
fmt code
ZR233 Nov 28, 2025
9b4a8d1
feat: 添加 pa_range 方法以获取物理地址范围
ZR233 Dec 19, 2025
012bc4c
fix: 修正 hardware_enable 方法中的类型转换以确保安全性
ZR233 Dec 19, 2025
ad5d5db
feat: 添加 ctx 和 ctx_mut 方法以访问和修改 TrapFrame
ZR233 Dec 19, 2025
aa0347e
fix: 移除未使用的 bind 和 unbind 方法以清理代码
ZR233 Dec 19, 2025
6a25a01
feat: 添加 setup_current_cpu 方法以设置当前 CPU 的 VMID 并处理 TLB 失效
ZR233 Dec 22, 2025
b7cd8e4
fix: 调整 Cargo.toml 中的依赖顺序以提高可读性
ZR233 Dec 22, 2025
f484d8b
feat: 添加 pt_level 字段以支持不同的页表级别配置
ZR233 Dec 22, 2025
7c3c6d8
fix: 修复 vtcr_el2 的设置逻辑,移除多余的值计算
ZR233 Dec 22, 2025
84042ae
feat: 添加 pa_bits 字段以支持物理地址位数配置
ZR233 Dec 22, 2025
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 2 additions & 0 deletions .cargo/config.toml
Original file line number Diff line number Diff line change
@@ -0,0 +1,2 @@
[build]
target = "aarch64-unknown-none-softfloat"
6 changes: 3 additions & 3 deletions .github/workflows/ci.yml
Original file line number Diff line number Diff line change
Expand Up @@ -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 '<meta http-equiv="refresh" content="0;url=%s/index.html">' $(cargo tree | head -1 | cut -d' ' -f1) > target/doc/index.html
printf '<meta http-equiv="refresh" content="0;url=%s/index.html">' $(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
35 changes: 13 additions & 22 deletions Cargo.toml
Original file line number Diff line number Diff line change
@@ -1,35 +1,26 @@
[package]
edition = "2024"
name = "arm_vcpu"
version = "0.1.1"
authors = [
"KeYang Hu <[email protected]>",
"Mingxian Su <[email protected]>",
"ShiMei Tang <[email protected]>",
"DeBin Luo <[email protected]>",
"周睿 <[email protected]>"
"KeYang Hu <[email protected]>",
"Mingxian Su <[email protected]>",
"ShiMei Tang <[email protected]>",
"DeBin Luo <[email protected]>",
"周睿 <[email protected]>",
]
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]
aarch64-cpu = "11.0"
log = "0.4"
spin = "0.10"

aarch64-cpu = "10.0"
numeric-enum-macro = "0.2"
tock-registers = "0.9"
spin = "0.10"

axerrno = "0.1.0"
axvm-types.workspace = true
percpu = {version = "0.2.0", features = ["arm-el2"]}

axaddrspace = "0.1"
axdevice_base = "0.1.0"
axvcpu = "0.1.0"
axvisor_api = "0.1.0"
25 changes: 15 additions & 10 deletions src/exception.rs
Original file line number Diff line number Diff line change
@@ -1,4 +1,3 @@
use crate::TrapFrame;
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,
Expand All @@ -7,15 +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 axaddrspace::{
GuestPhysAddr,
device::{AccessWidth, SysRegAddr},
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 axvcpu::AxVCpuExitReason;
use log::error;
use axvm_types::{
addr::GuestPhysAddr,
device::{AccessWidth, SysRegAddr},
};

numeric_enum_macro::numeric_enum! {
#[repr(u8)]
Expand Down Expand Up @@ -281,9 +282,7 @@ fn handle_smc64_exception(ctx: &mut TrapFrame) -> AxResult<AxVCpuExitReason> {
/// 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.
Expand All @@ -292,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?}",
Expand Down
5 changes: 2 additions & 3 deletions src/exception_utils.rs
Original file line number Diff line number Diff line change
@@ -1,7 +1,6 @@
use aarch64_cpu::registers::{ESR_EL2, FAR_EL2, PAR_EL1};
use axaddrspace::GuestPhysAddr;
use aarch64_cpu::registers::*;
use axerrno::{AxResult, ax_err};
use tock_registers::interfaces::*;
use axvm_types::addr::GuestPhysAddr;

/// Retrieves the Exception Syndrome Register (ESR) value from EL2.
///
Expand Down
191 changes: 191 additions & 0 deletions src/exit.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,191 @@
use axvm_types::{
addr::GuestPhysAddr,
device::{AccessWidth, SysRegAddr},
};

/// 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 (`<op0><op2><op1><CRn>00000<CRm>0`)
/// 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 (`<op0><op2><op1><CRn>00000<CRm>0`)
/// 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,
},
}
Loading
Loading