驱动开发硬核特训 · Day 11(上篇):虚拟总线驱动模型深度剖析 - 无形之总线,驱动之桥梁

发布于:2025-04-18 ⋅ 阅读:(48) ⋅ 点赞:(0)

🔍

B站相应的视屏教程
📌 内核:博文+视频 - 总线驱动模型实战全解析
敬请关注,记得标为原始粉丝。


🔧

在 Linux 内核的驱动模型体系中,虚拟总线驱动模型常常因“无硬件”而被忽略,却又在现代虚拟化、模拟设备、模块内通信中发挥着至关重要的作用。它不仅是一种总线机制,更是内核中“驱动模型思想”与“运行时绑定策略”的典型代表。

本文将围绕以下四个核心维度展开:

  • 什么是虚拟总线驱动模型?
  • 它与平台驱动、I2C/SPI 总线驱动有何不同?
  • 它的结构与使用方式有何特点?
  • 实际案例剖析:以 virtio-blk 驱动为核心代码,讲解其如何体现“虚拟总线”机制。

一、驱动模型中的虚拟总线是什么?

在 Linux 中,驱动模型基于“设备(device)- 驱动(driver)- 总线(bus)”的三元关系运作。每个 device 和 driver 都必须挂载到某种 bus 上,由总线完成它们的“匹配”和“绑定”。

通常我们熟悉的总线包括:

  • I2C 总线(i2c_driver, i2c_client
  • SPI 总线(spi_driver, spi_device
  • PCI 总线(pci_driver, pci_device
  • 平台总线(platform_driver, platform_device

虚拟总线(virtual bus)是一种不依赖真实硬件接口的逻辑抽象,用于管理和匹配“逻辑上的设备与驱动”。

定义特点:

  • 不依赖真实物理硬件:比如 virtio、vhost、rpmsg 等驱动,都是在软件层实现的“虚拟硬件”,不通过 GPIO/I2C/SPI 接口通信。
  • 设备和驱动的注册通常通过软件创建,如 virtio_register_driver()device_register()
  • 匹配过程依赖于 name/ID,而不是物理探测或者 probe 地址
  • 常用于虚拟机、模拟设备、通信桥梁、文件系统内设备等场景

二、虚拟总线 ≠ 平台总线

有观点认为“虚拟设备使用 platform_driver 注册,也是一种虚拟总线”。这在一些情况下成立,比如:

platform_device_register(&virtual_device);

但本质上:

特性 虚拟总线驱动(virtio等) 平台驱动模型
总线结构 自定义 bus_type(如 virtio_bus) 使用统一的 platform_bus_type
匹配方式 通常使用 .id_table.name 通过 of_match_table 或 name
用途 虚拟化、内核模块通信等 系统级通用外设(真实或虚拟)
是否专属硬件接口 否,纯软件逻辑实现 是,逻辑上绑定 SoC 资源

结论:虚拟总线驱动是一种独立的驱动模型分类,并不属于 platform_driver 的子集。尽管它们都支持无硬件匹配,但模型设计初衷和系统层级不同。


三、结构解析:虚拟总线驱动的典型框架

virtio 框架为代表,虚拟总线驱动模型通常包括以下结构:

1. 定义一个虚拟总线(bus_type

struct bus_type virtio_bus = {
    .name = "virtio",
    .match = virtio_device_match,
    .probe = virtio_device_probe,
    .remove = virtio_device_remove,
    // ...
};

其中:

  • .match() 决定设备和驱动如何匹配
  • .probe() 驱动初始化时调用
  • .remove() 卸载时清理资源

2. 注册一个虚拟设备(struct virtio_device

virtio_device_register(vdev);

通常在底层虚拟机框架、前端驱动(如 vhost、qemu、virtio-mmio)中调用。

3. 注册一个虚拟驱动(virtio_driver

static struct virtio_driver virtio_blk = {
    .driver.name = "virtio-blk",
    .id_table = id_table,
    .probe = virtblk_probe,
    .remove = virtblk_remove,
};
module_virtio_driver(virtio_blk);
  • id_table 用于匹配
  • probe() 中注册 block 设备、初始化 virtqueue

4. 匹配机制(run-time binding)

设备与驱动的匹配过程由 .id_table.match() 共同决定,通常基于 virtio_id


四、核心优势与关键概念

特性 描述
抽象性高 无需真实硬件,适合模拟设备、容器通信、用户态桥接等
内核模块通信机制 如 rpmsg 驱动、virtio 控制台等都使用虚拟总线构建了模块间的通信桥
启动速度快、兼容性好 虚拟设备无需依赖物理探测与 IRQ 绑定,初始化更快
更适合复杂的软件架构 比如在 KVM/QEMU 中提供虚拟设备,Guest 端使用 virtio 驱动访问

五、实际代码举例(精简版)

virtio_blk 为例:

static const struct virtio_device_id id_table[] = {
    { VIRTIO_ID_BLOCK, VIRTIO_DEV_ANY_ID },
    { 0 },
};

static struct virtio_driver virtio_blk = {
    .driver.name   = "virtio-blk",
    .id_table      = id_table,
    .probe         = virtblk_probe,
    .remove        = virtblk_remove,
};
module_virtio_driver(virtio_blk);

注册总线的代码:

bus_register(&virtio_bus);  // 在 init 函数中注册

注册虚拟设备的调用:

device_register(&vdev->dev);
bus_add_device(&virtio_bus, &vdev->dev);

匹配调用链:

driver_register() → bus_add_driver() → match() → driver->probe()

六、小结与回顾

虚拟总线驱动模型是 Linux 驱动模型体系中的一颗“明珠”:

  • 它代表了纯软件抽象驱动匹配机制
  • 是虚拟化、模拟驱动、模块通信的核心机制;
  • 与 platform_driver 虽结构相似,但目的和范畴不同;
  • 是设备模型理念中的“运行时适配”机制的典范。

七、预告下篇内容

下篇我们将脱离 virtio 框架,采用更贴近“纯虚拟驱动模型”的方式,在 Linux 内核中模拟创建一个“虚拟设备 + 虚拟驱动”的完整结构,用代码一步步解释设备模型如何支持这种“无硬件运行时适配”。


如果你觉得“虚拟总线驱动”只是内核开发中的“边角料”,那么这篇文章希望让你看到它背后隐藏的真正价值。

Day 11(下篇)即将到来:“纯虚拟设备模型实战开发”!



网站公告

今日签到

点亮在社区的每一天
去签到