Skip to content
Draft
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
32 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
5b7e40d
feat: 移除 per_cpu 依赖并重构 HOST_SP_EL0 以支持多 CPU 环境
ZR233 Jan 29, 2026
bfa876e
feat: 更新版本号至 0.3.0,并添加 VCpuError 错误处理
ZR233 Feb 2, 2026
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
2 changes: 1 addition & 1 deletion CHANGELOG.md
Original file line number Diff line number Diff line change
@@ -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.

Expand Down
40 changes: 15 additions & 25 deletions Cargo.toml
Original file line number Diff line number Diff line change
@@ -1,35 +1,25 @@
[package]
edition = "2024"
name = "arm_vcpu"
version = "0.1.1"
authors = [
"KeYang Hu <keyang.hu@qq.com>",
"Mingxian Su <aarkegz@gmail.com>",
"ShiMei Tang <shimei820@gmail.com>",
"DeBin Luo <luodeb@outlook.com>",
"周睿 <zrufo747@outlook.com>"
"KeYang Hu <keyang.hu@qq.com>",
"Mingxian Su <aarkegz@gmail.com>",
"ShiMei Tang <shimei820@gmail.com>",
"DeBin Luo <luodeb@outlook.com>",
"周睿 <zrufo747@outlook.com>",
]
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.3.0"

[dependencies]
aarch64-cpu = "11.0"
log = "0.4"
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"]}

axaddrspace = "0.1"
axdevice_base = "0.1.0"
axvcpu = "0.1.0"
axvisor_api = "0.1.0"
spin = "0.10"
thiserror = {version = "2", default-features = false}
anyhow = {version = "1.0", default-features = false}
axvm-types.workspace = true
40 changes: 22 additions & 18 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,16 @@ 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, VCpuError, handle_irq};

use aarch64_cpu::registers::{ESR_EL2, HCR_EL2, Readable, SCTLR_EL1, VTCR_EL2, VTTBR_EL2};
use axaddrspace::{
GuestPhysAddr,
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 axvm_types::{
addr::GuestPhysAddr,
device::{AccessWidth, SysRegAddr},
};
use axerrno::{AxError, AxResult};
use axvcpu::AxVCpuExitReason;
use log::error;

numeric_enum_macro::numeric_enum! {
#[repr(u8)]
Expand Down Expand Up @@ -71,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<AxVCpuExitReason> {
pub fn handle_exception_sync(ctx: &mut TrapFrame) -> Result<AxVCpuExitReason, VCpuError> {
match exception_class() {
Some(ESR_EL2::EC::Value::DataAbortLowerEL) => {
let elr = ctx.exception_pc();
Expand Down Expand Up @@ -127,7 +127,7 @@ pub fn handle_exception_sync(ctx: &mut TrapFrame) -> AxResult<AxVCpuExitReason>
}
}

fn handle_data_abort(context_frame: &mut TrapFrame) -> AxResult<AxVCpuExitReason> {
fn handle_data_abort(context_frame: &mut TrapFrame) -> Result<AxVCpuExitReason, VCpuError> {
let addr = exception_fault_addr()?;
let access_width = exception_data_abort_access_width();
let is_write = exception_data_abort_access_is_write();
Expand All @@ -144,12 +144,12 @@ fn handle_data_abort(context_frame: &mut TrapFrame) -> AxResult<AxVCpuExitReason

let width = match AccessWidth::try_from(access_width) {
Ok(access_width) => 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() {
Expand All @@ -162,7 +162,7 @@ fn handle_data_abort(context_frame: &mut TrapFrame) -> AxResult<AxVCpuExitReason

if !exception_data_abort_is_translate_fault() {
if exception_data_abort_is_permission_fault() {
return Err(AxError::Unsupported);
return Err(VCpuError::Unsupported);
} else {
panic!("Core data abort is not translate fault {:#x}", addr,);
}
Expand Down Expand Up @@ -195,7 +195,7 @@ fn handle_data_abort(context_frame: &mut TrapFrame) -> AxResult<AxVCpuExitReason
/// # Returns
/// * `AxResult<AxVCpuExitReason>` - 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<AxVCpuExitReason> {
fn handle_system_register(context_frame: &mut TrapFrame) -> Result<AxVCpuExitReason, VCpuError> {
let iss = ESR_EL2.read(ESR_EL2::ISS);

let addr = exception_sysreg_addr(iss.try_into().unwrap());
Expand Down Expand Up @@ -223,7 +223,7 @@ fn handle_system_register(context_frame: &mut TrapFrame) -> AxResult<AxVCpuExitR
/// calling convention is used) is a psci call. This function handles them all.
///
/// Returns `None` if the HVC is not a psci call.
fn handle_psci_call(ctx: &mut TrapFrame) -> Option<AxResult<AxVCpuExitReason>> {
fn handle_psci_call(ctx: &mut TrapFrame) -> Option<Result<AxVCpuExitReason, VCpuError>> {
const PSCI_FN_RANGE_32: core::ops::RangeInclusive<u64> = 0x8400_0000..=0x8400_001F;
const PSCI_FN_RANGE_64: core::ops::RangeInclusive<u64> = 0xC400_0000..=0xC400_001F;

Expand Down Expand Up @@ -263,7 +263,7 @@ fn handle_psci_call(ctx: &mut TrapFrame) -> Option<AxResult<AxVCpuExitReason>> {
///
/// 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<AxVCpuExitReason> {
fn handle_smc64_exception(ctx: &mut TrapFrame) -> Result<AxVCpuExitReason, VCpuError> {
// Is this a psci call?
if let Some(result) = handle_psci_call(ctx) {
result
Expand All @@ -281,9 +281,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 +290,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
13 changes: 6 additions & 7 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 axerrno::{AxResult, ax_err};
use tock_registers::interfaces::*;
use aarch64_cpu::registers::*;

use crate::{GuestPhysAddr, VCpuError};

/// Retrieves the Exception Syndrome Register (ESR) value from EL2.
///
Expand Down Expand Up @@ -88,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<usize> {
fn translate_far_to_hpfar(far: usize) -> Result<usize, VCpuError> {
/*
* We have
* PAR[PA_Shift - 1 : 12] = PA[PA_Shift - 1 : 12]
Expand All @@ -105,7 +104,7 @@ fn translate_far_to_hpfar(far: usize) -> AxResult<usize> {
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)
}
Expand All @@ -129,7 +128,7 @@ fn translate_far_to_hpfar(far: usize) -> AxResult<usize> {
/// # Returns
/// * `AxResult<GuestPhysAddr>` - The guest physical address that caused the exception, wrapped in an `AxResult`.
#[inline(always)]
pub fn exception_fault_addr() -> AxResult<GuestPhysAddr> {
pub fn exception_fault_addr() -> Result<GuestPhysAddr, VCpuError> {
let far = FAR_EL2.get() as usize;
let hpfar =
if (exception_esr() & ESR_ELx_S1PTW) == 0 && exception_data_abort_is_permission_fault() {
Expand Down
Loading
Loading