Crates.io | dbs-device |
lib.rs | dbs-device |
version | 0.2.0 |
source | src |
created_at | 2022-03-07 09:14:48.737361 |
updated_at | 2022-10-24 09:45:26.398344 |
description | Device model for Dragonball Sandbox |
homepage | https://github.com/openanolis/dragonball-sandbox |
repository | https://github.com/openanolis/dragonball-sandbox/tree/main/crates/dbs-device |
max_upload_size | |
id | 544912 |
size | 75,658 |
The dbs-device
crate, as a counterpart of vm-device, defines device model for the Dragonball Secure Sandbox.
The dbs-device
crate shares some common concepts and data structures with vm-device, but it also diverges from
vm-device due to different VMM designs.
The dbs-device crate provides:
The dbs-device crate is designed to support the virtual machine's device model.
The core concepts of device model are Port I/O and Memory-mapped I/O, which are two main methods of performing I/O between CPU and devices.
The device model provided by the dbs-device crate works as below:
First, a vm needs to create an IoManager to help it dispatch I/O events to devices. And an IoManager has two types of bus, the PIO bus and the MMIO bus, to handle different types of IO.
Then, when creating a device, it needs to implement the DeviceIo or DeviceIoMut trait to receive read or write events send by driver in guest OS:
read()
and write()
methods is used to deal with MMIO eventspio_read()
and pio_write()
methods is used to deal with PIO eventsget_assigned_resources()
method is used to get all resources assigned to the deviceget_trapped_io_resources()
method is used to get only MMIO/PIO resources assigned to the deviceThe difference of DeviceIo and DeviceIoMut is the reference type of self
passed to method:
&self
to method, so the implementation of device would provide
interior mutability and thread-safe protection itself&mut self
to method, and it can give mutability to device
which is wrapped by Mutex
directly to simplify the difficulty of achieving interior mutability.Additionally, the DeviceIo trait has an auto implement for Mutex<T: DeviceIoMut>
Last, the device needs to be added to IoManager by using register_device_io()
, and the function would add device
to PIO bus and/or MMIO bus by the resources it have. If a device has not only MMIO resource but PIO resource,
it would be added to both pio bus and mmio bus. So the device would wrapped by Arc<T>
.
From now on, the IoManager will dispatch I/O requests for the registered address ranges to the device.
use std::sync::Arc;
use dbs_device::device_manager::IoManager;
use dbs_device::resources::{DeviceResources, Resource};
use dbs_device::{DeviceIo, IoAddress, PioAddress};
struct DummyDevice {}
impl DeviceIo for DummyDevice {
fn read(&self, base: IoAddress, offset: IoAddress, data: &mut [u8]) {
println!(
"mmio read, base: 0x{:x}, offset: 0x{:x}",
base.raw_value(),
offset.raw_value()
);
}
fn write(&self, base: IoAddress, offset: IoAddress, data: &[u8]) {
println!(
"mmio write, base: 0x{:x}, offset: 0x{:x}",
base.raw_value(),
offset.raw_value()
);
}
fn pio_read(&self, base: PioAddress, offset: PioAddress, data: &mut [u8]) {
println!(
"pio read, base: 0x{:x}, offset: 0x{:x}",
base.raw_value(),
offset.raw_value()
);
}
fn pio_write(&self, base: PioAddress, offset: PioAddress, data: &[u8]) {
println!(
"pio write, base: 0x{:x}, offset: 0x{:x}",
base.raw_value(),
offset.raw_value()
);
}
}
// Allocate resources for device
let mut resources = DeviceResources::new();
resources.append(Resource::MmioAddressRange {
base: 0,
size: 4096,
});
resources.append(Resource::PioAddressRange { base: 0, size: 32 });
// Register device to `IoManager` with resources
let device = Arc::new(DummyDevice {});
let mut manager = IoManager::new();
manager.register_device_io(device, &resources).unwrap();
// Dispatch I/O event from `IoManager` to device
manager.mmio_write(0, &vec![0, 1]).unwrap();
let mut buffer = vec![0; 4];
manager.pio_read(0, &mut buffer);
This project is licensed under Apache License, Version 2.0.