Skip to content
Merged
Show file tree
Hide file tree
Changes from 3 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: [riscv64gc-unknown-none-elf]
steps:
- uses: actions/checkout@v4
Expand Down Expand Up @@ -36,7 +36,7 @@ jobs:
strategy:
fail-fast: false
matrix:
rust-toolchain: [nightly-2024-12-25]
rust-toolchain: [nightly-2025-05-20]
targets: [riscv64gc-unknown-none-elf]
permissions:
contents: write
Expand Down
13 changes: 12 additions & 1 deletion Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -2,9 +2,20 @@
name = "riscv_vcpu"
version = "0.1.0"
edition = "2024"
authors = [
"KeYang Hu <[email protected]>",
"Mingxian Su <[email protected]>",
"Peizhong Qiu <[email protected]>",
"周睿 <[email protected]>"
]
description = "ArceOS-Hypervisor riscv vcpu module"
license = "MIT OR Apache-2.0"
repository = "https://github.com/arceos-hypervisor/riscv_vcpu"
categories = ["embedded", "no-std"]
keywords = ["hypervisor", "riscv", "vcpu"]

[dependencies]
log = "0.4.19"
log = "0.4"
cfg-if = "1.0"
bitflags = "2.2"
bit_field = "0.10"
Expand Down
59 changes: 57 additions & 2 deletions README.md
Original file line number Diff line number Diff line change
@@ -1,5 +1,60 @@
# riscv_vcpu
# **riscv_vcpu**

riscv64 virtual CPU (vCPU) implementation for hypervisors. This crate provides the core vCPU structure and virtualization-related interface support specifically designed for the riscv64 architecture.

[![CI](https://github.com/arceos-hypervisor/riscv_vcpu/actions/workflows/ci.yml/badge.svg?branch=master)](https://github.com/arceos-hypervisor/riscv_vcpu/actions/workflows/ci.yml)
[![License](https://img.shields.io/badge/License-MIT%20OR%20Apache--2.0-blue.svg)]

## Overview

riscv_vcpu implements a minimal RISC-V Virtual CPU (VCPU) abstraction layer compliant with the RISC-V Hypervisor Extension (RVH). Designed for embedded hypervisors and educational use, it can operates in no_std environments.

## Features

- **Complete vCPU Implementation**: Full virtual CPU structure for riscv64 guests
- **Exception Handling**: Comprehensive trap and exception handling for virtualized environments
- **EPT (Extended Page Tables)**: Memory virtualization support
- **VMCS Management**: Virtual Machine Control Structure operations
- **Per-CPU Support**: Efficient per-CPU data structures and management
- **No-std Compatible**: Works in bare-metal and embedded environments

## Usage

Add this to your `Cargo.toml`:

```toml
[dependencies]
riscv_vcpu = "0.1"
```

## Basic Usage

```rust
use riscv_vcpu::{RISCVVCpu, RISCVVCpuCreateConfig, has_hardware_support};

// Check if hardware virtualization is supported
if has_hardware_support() {
// Create vCPU configuration
let config = RISCVVCpuCreateConfig::default();

// Create and configure the virtual CPU
let vcpu = RISCVVCpu::new(config)?;

// Run the virtual CPU
vcpu.run()?;
}
```

## Related Projects

+ [ArceOS](https://github.com/arceos-org/arceos) - An experimental modular OS (or Unikernel)
+ [AxVisor](https://github.com/arceos-hypervisor/axvisor) - Hypervisor implementation

## License

This project is dual-licensed under either:

- MIT License ([LICENSE-MIT](LICENSE-MIT) or <http://opensource.org/licenses/MIT>)
- Apache License, Version 2.0 ([LICENSE-APACHE](LICENSE-APACHE) or <http://www.apache.org/licenses/LICENSE-2.0>)

Definition of the vCPU structure and virtualization-related interface support for the AArch64 architecture.
at your option.
7 changes: 7 additions & 0 deletions rust-toolchain.toml
Original file line number Diff line number Diff line change
@@ -0,0 +1,7 @@
[toolchain]
channel = "nightly-2025-05-20"
components = ["rust-src", "llvm-tools", "rustfmt", "clippy"]
profile = "minimal"
targets = [
"riscv64gc-unknown-none-elf",
]
122 changes: 60 additions & 62 deletions src/detect.rs
Original file line number Diff line number Diff line change
Expand Up @@ -151,67 +151,65 @@ struct TrapFrame {
// This function should not be used in conventional trap handling,
// as it does not preserve a special trap stack, and it's designed to
// handle exceptions only rather than interrupts.
#[naked]
#[unsafe(naked)]
unsafe extern "C" fn on_detect_trap() -> ! {
unsafe {
naked_asm!(
".p2align 2",
"addi sp, sp, -8*21",
"sd ra, 0*8(sp)",
"sd tp, 1*8(sp)",
"sd a0, 2*8(sp)",
"sd a1, 3*8(sp)",
"sd a2, 4*8(sp)",
"sd a3, 5*8(sp)",
"sd a4, 6*8(sp)",
"sd a5, 7*8(sp)",
"sd a6, 8*8(sp)",
"sd a7, 9*8(sp)",
"sd t0, 10*8(sp)",
"sd t1, 11*8(sp)",
"sd t2, 12*8(sp)",
"sd t3, 13*8(sp)",
"sd t4, 14*8(sp)",
"sd t5, 15*8(sp)",
"sd t6, 16*8(sp)",
"csrr t0, sstatus",
"sd t0, 17*8(sp)",
"csrr t1, sepc",
"sd t1, 18*8(sp)",
"csrr t2, scause",
"sd t2, 19*8(sp)",
"csrr t3, stval",
"sd t3, 20*8(sp)",
"mv a0, sp",
"call {rust_detect_trap}",
"ld t0, 17*8(sp)",
"csrw sstatus, t0",
"ld t1, 18*8(sp)",
"csrw sepc, t1",
"ld t2, 19*8(sp)",
"csrw scause, t2",
"ld t3, 20*8(sp)",
"csrw stval, t3",
"ld ra, 0*8(sp)",
"ld tp, 1*8(sp)",
"ld a0, 2*8(sp)",
"ld a1, 3*8(sp)",
"ld a2, 4*8(sp)",
"ld a3, 5*8(sp)",
"ld a4, 6*8(sp)",
"ld a5, 7*8(sp)",
"ld a6, 8*8(sp)",
"ld a7, 9*8(sp)",
"ld t0, 10*8(sp)",
"ld t1, 11*8(sp)",
"ld t2, 12*8(sp)",
"ld t3, 13*8(sp)",
"ld t4, 14*8(sp)",
"ld t5, 15*8(sp)",
"ld t6, 16*8(sp)",
"addi sp, sp, 8*21",
"sret",
rust_detect_trap = sym rust_detect_trap,
)
}
naked_asm!(
".p2align 2",
"addi sp, sp, -8*21",
"sd ra, 0*8(sp)",
"sd tp, 1*8(sp)",
"sd a0, 2*8(sp)",
"sd a1, 3*8(sp)",
"sd a2, 4*8(sp)",
"sd a3, 5*8(sp)",
"sd a4, 6*8(sp)",
"sd a5, 7*8(sp)",
"sd a6, 8*8(sp)",
"sd a7, 9*8(sp)",
"sd t0, 10*8(sp)",
"sd t1, 11*8(sp)",
"sd t2, 12*8(sp)",
"sd t3, 13*8(sp)",
"sd t4, 14*8(sp)",
"sd t5, 15*8(sp)",
"sd t6, 16*8(sp)",
"csrr t0, sstatus",
"sd t0, 17*8(sp)",
"csrr t1, sepc",
"sd t1, 18*8(sp)",
"csrr t2, scause",
"sd t2, 19*8(sp)",
"csrr t3, stval",
"sd t3, 20*8(sp)",
"mv a0, sp",
"call {rust_detect_trap}",
"ld t0, 17*8(sp)",
"csrw sstatus, t0",
"ld t1, 18*8(sp)",
"csrw sepc, t1",
"ld t2, 19*8(sp)",
"csrw scause, t2",
"ld t3, 20*8(sp)",
"csrw stval, t3",
"ld ra, 0*8(sp)",
"ld tp, 1*8(sp)",
"ld a0, 2*8(sp)",
"ld a1, 3*8(sp)",
"ld a2, 4*8(sp)",
"ld a3, 5*8(sp)",
"ld a4, 6*8(sp)",
"ld a5, 7*8(sp)",
"ld a6, 8*8(sp)",
"ld a7, 9*8(sp)",
"ld t0, 10*8(sp)",
"ld t1, 11*8(sp)",
"ld t2, 12*8(sp)",
"ld t3, 13*8(sp)",
"ld t4, 14*8(sp)",
"ld t5, 15*8(sp)",
"ld t6, 16*8(sp)",
"addi sp, sp, 8*21",
"sret",
rust_detect_trap = sym rust_detect_trap,
)
}
1 change: 0 additions & 1 deletion src/lib.rs
Original file line number Diff line number Diff line change
@@ -1,6 +1,5 @@
#![no_std]
#![feature(doc_cfg)]
#![feature(naked_functions)]
#![feature(riscv_ext_intrinsics)]
#![doc = include_str!("../README.md")]

Expand Down
8 changes: 3 additions & 5 deletions src/vcpu.rs
Original file line number Diff line number Diff line change
@@ -1,5 +1,3 @@
use core::ops::{Shl, Shr};

use crate::sbi_console::*;
use axaddrspace::device::AccessWidth;
use riscv::register::hstatus;
Expand Down Expand Up @@ -49,7 +47,7 @@ impl<H: AxVCpuHal> axvcpu::AxArchVCpu for RISCVVCpu<H> {

type SetupConfig = ();

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 regs = VmCpuRegisters::default();
// Setup the guest's general purpose registers.
// `a0` is the hartid
Expand Down Expand Up @@ -145,7 +143,7 @@ impl<H: AxVCpuHal> axvcpu::AxArchVCpu for RISCVVCpu<H> {
}
}

fn inject_interrupt(&mut self, vector: usize) -> AxResult {
fn inject_interrupt(&mut self, _vector: usize) -> AxResult {
unimplemented!("RISCVVCpu::inject_interrupt is not implemented yet");
}

Expand Down Expand Up @@ -424,7 +422,7 @@ impl<H: AxVCpuHal> RISCVVCpu<H> {
}

/// Handle a guest page fault. Return an exit reason.
fn handle_guest_page_fault(&mut self, writing: bool) -> AxResult<AxVCpuExitReason> {
fn handle_guest_page_fault(&mut self, _writing: bool) -> AxResult<AxVCpuExitReason> {
let fault_addr = self.regs.trap_csrs.gpt_page_fault_addr();
let sepc = self.regs.guest_regs.sepc;
let sepc_vaddr = GuestVirtAddr::from(sepc);
Expand Down