2 个不稳定版本

0.2.0 2022 年 10 月 24 日
0.1.0 2022 年 3 月 7 日

#974硬件支持

Download history 57/week @ 2024-03-11 38/week @ 2024-03-18 35/week @ 2024-03-25 56/week @ 2024-04-01 4/week @ 2024-04-08 13/week @ 2024-04-15 13/week @ 2024-04-22 12/week @ 2024-04-29 10/week @ 2024-05-06 10/week @ 2024-05-13 14/week @ 2024-05-20 9/week @ 2024-05-27 9/week @ 2024-06-03 18/week @ 2024-06-10 7/week @ 2024-06-17 18/week @ 2024-06-24

52 每月下载量
5 个crates中使用 (4 直接)

Apache-2.0

65KB
1K SLoC

dbs-device

作为 vm-device 的对应物,`dbs-device` crate 定义了 Dragonball 安全沙盒的设备模型。`dbs-device` crate 与 vm-device 共享一些共同的概念和数据结构,但由于 VMM 设计的不同,它也不同于 vm-device

`dbs-device` crate 提供:

设计

`dbs-device` crate 设计用于支持虚拟机的设备模型。

设备模型的核心概念是 端口 I/O内存映射 I/O,这是 CPU 和设备之间进行 I/O 的两种主要方法。

`dbs-device` crate 提供的设备模型工作如下:

  • VMM 创建一个全局资源管理器、设备管理器和 IO 管理器。
  • 设备管理器创建由 VMM 配置的虚拟设备
    • 创建设备对象
    • 查询设备分配要求和约束,设备返回一个 ResourceConstraint 数组。
    • 从资源管理器为设备分配资源,资源管理器返回一个 DeviceResources 对象。
    • 将分配的资源分配给设备。
  • 设备管理器将设备注册到IO管理器。
  • 虚拟机访问那些捕获的MMIO/PIO地址范围,并触发VM IO退出事件进入VMM。
  • VMM解析VM退出事件并将这些事件调度到IO管理器。
  • IO管理器通过搜索捕获的地址范围查找设备,并调用设备的 DeviceIO 处理器来处理这些捕获的MMIO/PIO访问请求。

使用方法

首先,一个虚拟机需要创建一个 IoManager 来帮助它将I/O事件调度到设备。一个 IoManager 有两种类型的总线,即PIO总线和解密总线,以处理不同类型的I/O。

然后,在创建设备时,需要实现 DeviceIoDeviceIoMut 特性,以接收来自虚拟机操作系统中驱动程序发送的读取或写入事件

  • read()write() 方法用于处理MMIO事件
  • pio_read()pio_write() 方法用于处理PIO事件
  • get_assigned_resources() 方法用于获取分配给设备的所有资源
  • get_trapped_io_resources() 方法用于获取分配给设备的仅MMIO/PIO资源

DeviceIoDeviceIoMut 的区别在于传递给方法的 self 的引用类型

  • DeviceIo 特性会将不可变引用 &self 传递给方法,因此设备实现将提供内部可变性和线程安全保护
  • DeviceIoMut 特性会将可变引用 &mut self 传递给方法,并且它可以直接给被 Mutex 包裹的设备提供可变性,以简化实现内部可变性的难度。

此外,DeviceIo 特性具有为 Mutex<T: DeviceIoMut> 的自动实现

最后,需要使用register_device_io()函数将设备添加到IoManager,该函数会根据所拥有的资源将设备添加到PIO总线或MMIO总线。如果一个设备既有MMIO资源又有PIO资源,它将被添加到pio总线和mmio总线。因此,设备将被Arc<T>封装。

从现在起,IoManager将为已注册的地址范围向设备派遣I/O请求。

示例

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);

许可证

本项目采用Apache License, Version 2.0授权。

依赖项

~300–760KB
~18K SLoC