src/dragonball/dbs_device/README.md
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:
DeviceIo] and [DeviceIoMut]: trait for device to handle trapped MMIO/PIO access requests.IoManager]: IO manager to handle trapped MMIO/PIO access requests.IoManagerContext]: trait for IO manager context object to support device hotplug at runtime.ResourceConstraint], Resource and [DeviceResources]: resource allocation requirements and constraints.The dbs-device crate is designed to support the virtual machine's device model.
The core concepts of device model are Memory-mapped I/O and port-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:
ResourceConstraint].DeviceResources] object.DeviceIo::get_trapped_io_resources()]DeviceIO]
handler to process those trapped MMIO/PIO access requests.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:
DeviceIo] trait would pass a immutable reference &self to method, so the implementation of device would provide
interior mutability and thread-safe protection itselfDeviceIoMut] trait would pass a mutable reference &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.