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
4 changes: 2 additions & 2 deletions .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: [x86_64-unknown-linux-gnu, x86_64-unknown-none, riscv64gc-unknown-none-elf, aarch64-unknown-none-softfloat]
steps:
- uses: actions/checkout@v4
Expand Down Expand Up @@ -42,7 +42,7 @@ 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: |
Expand Down
9 changes: 7 additions & 2 deletions Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -3,11 +3,16 @@ name = "axvcpu"
authors = ["aarkegz <aarkegz@gmail.com>"]
version = "0.1.0"
edition = "2024"
categories = ["Virtualization", "no-std"]
description = "Virtual CPU abstraction for ArceOS hypervisor"
repository = "https://github.com/arceos-hypervisor/axvcpu"
keywords = ["vcpu", "hypervisor", "arceos"]
license = "GPL-3.0-or-later OR Apache-2.0 OR MulanPSL-2.0" # MulanPubL2 is not included in SPDX

[dependencies]
axerrno = "0.1.0"
memory_addr = "0.4"
percpu = "0.2.0"

axaddrspace = { git = "https://github.com/arceos-hypervisor/axaddrspace.git" }
axvisor_api = { git = "https://github.com/arceos-hypervisor/axvisor_api.git" }
axaddrspace = "=0.1.0"
axvisor_api = "=0.1.0"
166 changes: 165 additions & 1 deletion README.md
Original file line number Diff line number Diff line change
@@ -1,3 +1,167 @@
# AxVCpu

Virtual CPU interface and wrapper for [`ArceOS`](https://github.com/arceos-org/arceos).
[![CI](https://github.com/arceos-hypervisor/x86_vcpu/actions/workflows/ci.yml/badge.svg?branch=master)](https://github.com/arceos-hypervisor/x86_vcpu/actions/workflows/ci.yml)

AxVCpu is a virtual CPU abstraction library for ArceOS hypervisors, providing a unified, architecture-independent interface for managing virtual CPUs in hypervisor environments.

## Features

- **Architecture Agnostic**: Unified interface supporting multiple architectures (x86_64, ARM64, RISC-V)
- **State Management**: Robust VCpu lifecycle management with clear state transitions
- **Per-CPU Virtualization**: Efficient per-CPU state management and resource isolation
- **Hardware Abstraction**: Clean separation between architecture-specific and common operations
- **CPU Affinity**: Support for CPU binding and affinity management
- **Exit Handling**: Comprehensive VM exit reason handling and processing

## Architecture

AxVCpu follows a layered architecture design:

```
┌─────────────────────────────────────────┐
│ Application Layer │ ← Hypervisor/VMM
├─────────────────────────────────────────┤
│ AxVCpu Core Interface │ ← Main API
├─────────────────────────────────────────┤
│ Architecture Abstraction │ ← AxArchVCpu trait
├─────────────────────────────────────────┤
│ Hardware Abstraction Layer │ ← AxVCpuHal trait
├─────────────────────────────────────────┤
│ Architecture-Specific Backends │ ← x86_64, ARM64, etc.
└─────────────────────────────────────────┘
```

## Core Components

### VCpu State Machine

```
Created → Free → Ready → Running → Blocked
↓ ↓ ↓ ↓ ↓
└───────┴──────┴────────┴────────┘
Invalid
```

- **Created**: Initial state after VCpu creation
- **Free**: Initialized and ready to be bound to a physical CPU
- **Ready**: Bound to a physical CPU and ready for execution
- **Running**: Currently executing on a physical CPU
- **Blocked**: Execution blocked (waiting for I/O, etc.)
- **Invalid**: Error state when transitions fail

### Key Traits

- `AxArchVCpu`: Architecture-specific VCpu implementation interface
- `AxVCpuHal`: Hardware abstraction layer for hypervisor operations
- `AxVCpuExitReason`: VM exit reason enumeration and handling

## Quick Start

Add AxVCpu to your `Cargo.toml`:

```toml
[dependencies]
axvcpu = "0.1.0"
```

### Basic Usage

```rust
use axvcpu::{AxVCpu, VCpuState};

// Mock implementation for example
struct MyArchVCpu;
impl AxArchVCpu for MyArchVCpu {
// Implement required methods...
}

// Create a new virtual CPU
let vcpu = AxVCpu::<MyArchVCpu>::new(
vm_id, // VM identifier
vcpu_id, // VCpu identifier
favor_cpu, // Preferred physical CPU
cpu_set, // CPU affinity mask
config // Architecture-specific config
)?;

// Check VCpu state
assert_eq!(vcpu.state(), VCpuState::Created);

// Setup the VCpu
vcpu.setup(entry_addr, ept_root, setup_config)?;

// Bind to current physical CPU and run
vcpu.bind()?;
let exit_reason = vcpu.run()?;

// Handle VM exit
match exit_reason {
AxVCpuExitReason::Halt => {
println!("Guest halted");
},
AxVCpuExitReason::Io { port, is_write, .. } => {
println!("I/O access on port {}", port);
},
// ... handle other exit reasons
}
```

## Architecture Implementation

To implement AxVCpu for a new architecture:

```rust
use axvcpu::AxArchVCpu;

struct MyArchVCpu {
// Architecture-specific fields
}

impl AxArchVCpu for MyArchVCpu {
type CreateConfig = MyCreateConfig;
type SetupConfig = MySetupConfig;

fn new(vm_id: VMId, vcpu_id: VCpuId, config: Self::CreateConfig) -> AxResult<Self> {
// Initialize architecture-specific VCpu
Ok(Self { /* ... */ })
}

fn set_entry(&mut self, entry: GuestPhysAddr) -> AxResult {
// Set guest entry point
Ok(())
}

fn set_ept_root(&mut self, ept_root: HostPhysAddr) -> AxResult {
// Configure memory virtualization
Ok(())
}

fn setup(&mut self, config: Self::SetupConfig) -> AxResult {
// Complete VCpu initialization
Ok(())
}

fn run(&mut self) -> AxResult<AxVCpuExitReason> {
// Execute guest code until VM exit
Ok(AxVCpuExitReason::Halt)
}

// Implement other required methods...
}
```

## Related Projects

- [ArceOS](https://github.com/arceos-org/arceos) - A component-based OS kernel
- [AxVisor](https://github.com/arceos-hypervisor/axvisor) - A hypervisor implemented based on the ArceOS unikernel framework.

## License

This project is licensed under multiple licenses. You may choose to use this project under any of the following licenses:

- **[GPL-3.0-or-later](LICENSE.GPLv3)** - GNU General Public License v3.0 or later
- **[Apache-2.0](LICENSE.Apache2)** - Apache License 2.0
- **[MulanPubL-2.0](LICENSE.MulanPubL2)** - Mulan Public License 2.0
- **[MulanPSL2](LICENSE.MulanPSL2)** - Mulan Permissive Software License v2

You may use this software under the terms of any of these licenses at your option.
59 changes: 40 additions & 19 deletions src/arch_vcpu.rs
Original file line number Diff line number Diff line change
Expand Up @@ -4,55 +4,76 @@ use axvisor_api::vmm::{VCpuId, VMId};

use crate::exit::AxVCpuExitReason;

/// A trait for architecture-specific vcpu.
/// Architecture-specific virtual CPU trait definition.
///
/// This trait is an abstraction for virtual CPUs of different architectures.
/// This trait provides an abstraction layer for implementing virtual CPUs across
/// different hardware architectures (x86_64, ARM64, RISC-V, etc.). Each architecture
/// must implement this trait to provide the necessary low-level virtualization primitives.
pub trait AxArchVCpu: Sized {
/// The configuration for creating a new [`AxArchVCpu`]. Used by [`AxArchVCpu::new`].
/// Architecture-specific configuration for VCpu creation.
///
/// This associated type allows each architecture to define its own
/// configuration parameters needed during VCpu initialization.
type CreateConfig;
/// The configuration for setting up a created [`AxArchVCpu`]. Used by [`AxArchVCpu::setup`].

/// Architecture-specific configuration for VCpu setup.
///
/// This associated type allows each architecture to specify additional
/// configuration parameters needed after basic VCpu creation but before execution.
type SetupConfig;

/// Create a new `AxArchVCpu`.
/// Creates a new architecture-specific VCpu instance.
fn new(vm_id: VMId, vcpu_id: VCpuId, config: Self::CreateConfig) -> AxResult<Self>;

/// Set the entry point of the vcpu.
/// Sets the guest entry point where VCpu execution will begin.
///
/// It's guaranteed that this function is called only once, before [`AxArchVCpu::setup`] being called.
fn set_entry(&mut self, entry: GuestPhysAddr) -> AxResult;

/// Set the EPT root of the vcpu.
/// Sets the Extended Page Table (EPT) root for memory translation.
///
/// It's guaranteed that this function is called only once, before [`AxArchVCpu::setup`] being called.
/// The EPT root defines the top-level page table used for guest-to-host
/// physical address translation in hardware virtualization.
fn set_ept_root(&mut self, ept_root: HostPhysAddr) -> AxResult;

/// Setup the vcpu.
/// Completes VCpu initialization and prepares it for execution.
///
/// It's guaranteed that this function is called only once, after [`AxArchVCpu::set_entry`] and [`AxArchVCpu::set_ept_root`] being called.
/// This method performs any final architecture-specific setup needed
/// before the VCpu can be bound and executed.
fn setup(&mut self, config: Self::SetupConfig) -> AxResult;

/// Run the vcpu until a vm-exit occurs.
/// Executes the VCpu until a VM exit occurs.
///
/// This is the core execution method that transfers control to the guest VCpu
/// and runs until the guest triggers a VM exit condition that requires
/// hypervisor intervention.
fn run(&mut self) -> AxResult<AxVCpuExitReason>;

/// Bind the vcpu to the current physical CPU.
/// Binds the VCpu to the current physical CPU for execution.
///
/// This method performs any necessary architecture-specific initialization
/// to prepare the VCpu for execution on the current physical CPU.
fn bind(&mut self) -> AxResult;

/// Unbind the vcpu from the current physical CPU.
/// Unbinds the VCpu from the current physical CPU.
///
/// This method performs cleanup and state preservation when moving
/// the VCpu away from the current physical CPU.
fn unbind(&mut self) -> AxResult;

/// Set the value of a general-purpose register according to the given index.
/// Sets the value of a general-purpose register.
fn set_gpr(&mut self, reg: usize, val: usize);

/// Inject an interrupt to the vcpu.
/// Inject an interrupt to the VCpu.
///
/// It's guaranteed (for implementors, and required for callers) that this function is called
/// on the physical CPU where the vcpu is running or queueing.
/// on the physical CPU where the VCpu is running or queueing.
///
/// It's not guaranteed that the vcpu is running or bound to the current physical CPU when this
/// It's not guaranteed that the VCpu is running or bound to the current physical CPU when this
/// function is called. It means sometimes an irq queue is necessary to buffer the interrupts
/// until the vcpu is running.
/// until the VCpu is running.
fn inject_interrupt(&mut self, vector: usize) -> AxResult;

/// Set return value of the vcpu.
/// Sets the return value that will be delivered to the guest.
fn set_return_value(&mut self, val: usize);
}
Loading