Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
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: 1 addition & 1 deletion .github/workflows/ci.yml
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,7 @@ jobs:
strategy:
fail-fast: false
matrix:
rust-toolchain: [nightly-2024-12-25, nightly]
rust-toolchain: [nightly-2025-05-20, nightly]
targets: [aarch64-unknown-none-softfloat]
steps:
- uses: actions/checkout@v4
Expand Down
18 changes: 9 additions & 9 deletions Cargo.toml
Original file line number Diff line number Diff line change
@@ -1,20 +1,20 @@
[package]
edition = "2024"
name = "arm_vcpu"
version = "0.1.0"
edition = "2024"

[dependencies]
log = "0.4.21"
spin = "0.9"
log = "0.4"
spin = "0.10"

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

axerrno = "0.1.0"
percpu = { version = "0.2.0", features = ["arm-el2"] }
percpu = {version = "0.2.0", features = ["arm-el2"]}

axaddrspace = { git = "https://github.com/arceos-hypervisor/axaddrspace.git" }
axvcpu = { git = "https://github.com/arceos-hypervisor/axvcpu.git" }
axdevice_base = { git = "https://github.com/arceos-hypervisor/axdevice_crates.git" }
axvisor_api = { git = "https://github.com/arceos-hypervisor/axvisor_api.git" }
axaddrspace = {git = "https://github.com/arceos-hypervisor/axaddrspace.git"}
axdevice_base = {git = "https://github.com/arceos-hypervisor/axdevice_crates.git"}
axvcpu = {git = "https://github.com/arceos-hypervisor/axvcpu.git"}
axvisor_api = {git = "https://github.com/arceos-hypervisor/axvisor_api.git"}
3 changes: 1 addition & 2 deletions rust-toolchain.toml
Original file line number Diff line number Diff line change
@@ -1,8 +1,7 @@
[toolchain]
profile = "minimal"
channel = "nightly-2024-12-25"
channel = "nightly-2025-05-20"
components = ["rust-src", "llvm-tools", "rustfmt", "clippy"]
targets = [
"aarch64-unknown-none",
"aarch64-unknown-none-softfloat",
]
29 changes: 13 additions & 16 deletions src/exception.rs
Original file line number Diff line number Diff line change
Expand Up @@ -58,8 +58,7 @@ core::arch::global_asm!(
///
/// # Arguments
///
/// * `ctx` - A mutable reference to the `TrapFrame`, which contains the saved state of the
/// guest VM's CPU registers at the time of the exception.
/// * `ctx` - A mutable reference to the `TrapFrame`, which contains the saved state of the guest VM's CPU registers at the time of the exception.
///
/// # Returns
///
Expand Down Expand Up @@ -295,8 +294,8 @@ fn current_el_sync_handler(tf: &mut TrapFrame) {
let iss = ESR_EL2.read(ESR_EL2::ISS);

error!("ESR_EL2: {:#x}", esr.get());
error!("Exception Class: {:#x}", ec);
error!("Instruction Specific Syndrome: {:#x}", iss);
error!("Exception Class: {ec:#x}");
error!("Instruction Specific Syndrome: {iss:#x}");

panic!(
"Unhandled synchronous exception from current EL: {:#x?}",
Expand Down Expand Up @@ -339,20 +338,18 @@ fn current_el_sync_handler(tf: &mut TrapFrame) {
///
/// - This function is not typically called directly from Rust code. Instead, it is
/// invoked as part of the low-level hypervisor or VM exit handling routines.
#[naked]
#[unsafe(naked)]
#[unsafe(no_mangle)]
unsafe extern "C" fn vmexit_trampoline() -> ! {
unsafe {
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.
// Currently `x9` points to `&Aarch64VCpu.host_stack_top`, see `run_guest()` in vcpu.rs.
"ldr x10, [x9]", // Get `host_stack_top` value from `&Aarch64VCpu.host_stack_top`.
"mov sp, x10", // Set `sp` as the host stack top.
restore_regs_from_stack!(), // Restore host function context frame.
"ret", // Control flow is handed back to Aarch64VCpu.run(), simulating the normal return of the `run_guest` function.
)
}
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.
// Currently `x9` points to `&Aarch64VCpu.host_stack_top`, see `run_guest()` in vcpu.rs.
"ldr x10, [x9]", // Get `host_stack_top` value from `&Aarch64VCpu.host_stack_top`.
"mov sp, x10", // Set `sp` as the host stack top.
restore_regs_from_stack!(), // Restore host function context frame.
"ret", // Control flow is handed back to Aarch64VCpu.run(), simulating the normal return of the `run_guest` function.
)
}

/// Deal with invalid aarch64 exception.
Expand Down
1 change: 0 additions & 1 deletion src/lib.rs
Original file line number Diff line number Diff line change
@@ -1,5 +1,4 @@
#![no_std]
#![feature(naked_functions)]
#![feature(doc_cfg)]
#![doc = include_str!("../README.md")]

Expand Down
58 changes: 27 additions & 31 deletions src/vcpu.rs
Original file line number Diff line number Diff line change
@@ -1,10 +1,9 @@
use core::marker::PhantomData;

use aarch64_cpu::registers::{CNTHCTL_EL2, HCR_EL2, SP_EL0, SPSR_EL1, VTCR_EL2};
use aarch64_cpu::registers::*;
use axaddrspace::{GuestPhysAddr, HostPhysAddr, device::SysRegAddr};
use axerrno::AxResult;
use axvcpu::{AxArchVCpu, AxVCpuExitReason, AxVCpuHal};
use tock_registers::interfaces::{ReadWriteable, Readable, Writeable};

use crate::TrapFrame;
use crate::context_frame::GuestSystemRegisters;
Expand Down Expand Up @@ -75,7 +74,7 @@ impl<H: AxVCpuHal> axvcpu::AxArchVCpu for Aarch64VCpu<H> {

type SetupConfig = Aarch64VCpuSetupConfig;

fn new(vm_id: usize, vcpu_id: usize, config: Self::CreateConfig) -> AxResult<Self> {
fn new(_vm_id: usize, _vcpu_id: usize, config: Self::CreateConfig) -> AxResult<Self> {
let mut ctx = TrapFrame::default();
ctx.set_argument(config.dtb_addr);

Expand All @@ -94,13 +93,13 @@ impl<H: AxVCpuHal> axvcpu::AxArchVCpu for Aarch64VCpu<H> {
}

fn set_entry(&mut self, entry: GuestPhysAddr) -> AxResult {
debug!("set vcpu entry:{:?}", entry);
debug!("set vcpu entry:{entry:?}");
self.set_elr(entry.as_usize());
Ok(())
}

fn set_ept_root(&mut self, ept_root: HostPhysAddr) -> AxResult {
debug!("set vcpu ept root:{:#x}", ept_root);
debug!("set vcpu ept root:{ept_root:#x}");
self.guest_system_regs.vttbr_el2 = ept_root.as_usize() as u64;
Ok(())
}
Expand Down Expand Up @@ -237,7 +236,7 @@ impl<H: AxVCpuHal> Aarch64VCpu<H> {
///
/// When a VM-Exit happens when guest's vCpu is running,
/// the control flow will be redirected to this function through `return_run_guest`.
#[naked]
#[unsafe(naked)]
unsafe extern "C" fn run_guest(&mut self) -> usize {
// Fixes: https://github.com/arceos-hypervisor/arm_vcpu/issues/22
//
Expand All @@ -246,25 +245,23 @@ impl<H: AxVCpuHal> Aarch64VCpu<H> {
// 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 {
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",
"add x0, x0, {host_stack_top_offset}",
"str x9, [x0]",
// Go to `context_vm_entry`.
"b context_vm_entry",
// 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::<TrapFrame>(),
run_guest_panic = sym Self::run_guest_panic,
);
}
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",
"add x0, x0, {host_stack_top_offset}",
"str x9, [x0]",
// Go to `context_vm_entry`.
"b context_vm_entry",
// 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::<TrapFrame>(),
run_guest_panic = sym Self::run_guest_panic,
);
}

/// This function is called when the control flow comes back to `run_guest`. To provide a error
Expand Down Expand Up @@ -342,7 +339,7 @@ impl<H: AxVCpuHal> Aarch64VCpu<H> {
return Ok(exit_reason);
}

return result;
result
}
Ok(AxVCpuExitReason::SysRegWrite { addr, value }) => {
if let Some(exit_reason) =
Expand All @@ -351,9 +348,9 @@ impl<H: AxVCpuHal> Aarch64VCpu<H> {
return Ok(exit_reason);
}

return result;
result
}
r => return r,
r => r,
}
}

Expand All @@ -371,7 +368,7 @@ impl<H: AxVCpuHal> Aarch64VCpu<H> {

match (addr, write) {
(SYSREG_ICC_SGI1R_EL1, true) => {
debug!("arm_vcpu ICC_SGI1R_EL1 write: {:#x}", value);
debug!("arm_vcpu ICC_SGI1R_EL1 write: {value:#x}");

// TODO: support RangeSelector

Expand All @@ -397,8 +394,7 @@ impl<H: AxVCpuHal> Aarch64VCpu<H> {
let target_list = value & 0xffff;

debug!(
"arm_vcpu ICC_SGI1R_EL1 write: aff3:{:#x} aff2:{:#x} aff1:{:#x} intid:{:#x} target_list:{:#x}",
aff3, aff2, aff1, intid, target_list
"arm_vcpu ICC_SGI1R_EL1 write: aff3:{aff3:#x} aff2:{aff2:#x} aff1:{aff1:#x} intid:{intid:#x} target_list:{target_list:#x}"
);

Ok(Some(AxVCpuExitReason::SendIPI {
Expand Down