OS-Agnostic Virtual Device Abstraction Layer
English | 中文
axdevice is a reusable, OS-agnostic device abstraction layer for virtual machines. It provides unified management for emulated devices and dispatches guest accesses to MMIO, system-register, and port-based devices in #![no_std] environments.
This crate currently exports two core types:
AxVmDeviceConfig- Wraps a list ofEmulatedDeviceConfigitems used to initialize VM devicesAxVmDevices- Manages device collections, dispatches device access requests, and allocates IVC channels
The crate is suitable for hypervisors and low-level OS components targeting AArch64 or RISC-V.
- Rust nightly toolchain
- Rust components: rust-src, clippy, rustfmt
# Install rustup (if not installed)
curl --proto '=https' --tlsv1.2 -sSf https://sh.rustup.rs | sh
# Install nightly toolchain and components
rustup install nightly
rustup component add rust-src clippy rustfmt --toolchain nightly# 1. Enter the repository
cd axdevice
# 2. Code check (format + clippy + build)
./scripts/check.sh
# 3. Run tests
./scripts/test.shAdd to your Cargo.toml:
[dependencies]
axdevice = "0.2.2"use std::sync::{Arc, Mutex};
use axaddrspace::device::AccessWidth;
use axaddrspace::{GuestPhysAddr, GuestPhysAddrRange};
use axdevice::{AxVmDeviceConfig, AxVmDevices};
use axdevice_base::BaseDeviceOps;
use axerrno::AxResult;
use axvmconfig::EmulatedDeviceType;
struct MockMmioDevice {
range: GuestPhysAddrRange,
last_write: Mutex<Option<usize>>,
}
impl MockMmioDevice {
fn new(base: usize, size: usize) -> Self {
Self {
range: GuestPhysAddrRange::new(
GuestPhysAddr::from(base),
GuestPhysAddr::from(base + size),
),
last_write: Mutex::new(None),
}
}
}
impl BaseDeviceOps<GuestPhysAddrRange> for MockMmioDevice {
fn address_range(&self) -> GuestPhysAddrRange {
self.range
}
fn emu_type(&self) -> EmulatedDeviceType {
EmulatedDeviceType::IVCChannel
}
fn handle_read(&self, _addr: GuestPhysAddr, _width: AccessWidth) -> AxResult<usize> {
Ok(0xDEAD_BEEF)
}
fn handle_write(&self, addr: GuestPhysAddr, _width: AccessWidth, val: usize) -> AxResult {
let offset = addr.as_usize() - self.range.start.as_usize();
assert_eq!(offset, 0x40);
*self.last_write.lock().unwrap() = Some(val);
Ok(())
}
}
fn main() {
let config = AxVmDeviceConfig::new(vec![]);
let mut devices = AxVmDevices::new(config);
let mock = Arc::new(MockMmioDevice::new(0x1000_0000, 0x1000));
devices.add_mmio_dev(mock.clone());
let width = AccessWidth::try_from(4).unwrap();
let addr = GuestPhysAddr::from(0x1000_0040);
devices.handle_mmio_write(addr, width, 0x1234_5678).unwrap();
let value = devices.handle_mmio_read(addr, width).unwrap();
assert_eq!(value, 0xDEAD_BEEF);
assert_eq!(*mock.last_write.lock().unwrap(), Some(0x1234_5678));
}Generate and view API documentation:
cargo doc --no-deps --openOnline documentation: docs.rs/axdevice
- Fork the repository and create a branch
- Run local check:
./scripts/check.sh - Run local tests:
./scripts/test.sh - Submit PR and pass CI checks
Licensed under the Apache License, Version 2.0. See LICENSE for details.