Skip to content
Merged
Show file tree
Hide file tree
Changes from 6 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
1 change: 1 addition & 0 deletions src/pcpu.rs
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
use core::{cell::OnceCell, marker::PhantomData};

use aarch64_cpu::registers::*;

use axerrno::AxResult;
use axvcpu::{AxArchPerCpu, AxVCpuHal};
use tock_registers::interfaces::ReadWriteable;
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