驱动程序中的协议

什么是协议?

协议是严格的接口定义。

以太网驱动程序发布了符合 ZX_PROTOCOL_ETHERNET_IMPL 的接口。 这意味着它必须提供一组在数据结构中定义的函数 (在本例中为 ethernet_impl_protocol_ops_t)。

这些函数是所有实现该协议的设备通用的功能,例如, 所有以太网设备都必须提供相应的功能, 界面。

当然,其他协议对其功能有不同的要求 必须提供。 例如,块存储设备将发布一个符合 "代码块实现协议"(ZX_PROTOCOL_BLOCK_IMPL)和 提供由 block_protocol_ops_t 定义的函数。 此协议包含一个函数,该函数以块为单位返回设备的大小, 示例。

在许多情况下,协议用于简化驱动程序的 接口的通用实现例如,“屏蔽”规则驱动程序实现 通用块接口,并绑定到实现块核心协议的设备, 而“以太网”驱动程序对以太网接口和以太网接口执行相同的操作 协议。有些协议(如本文提到的两种协议)会利用共享内存, 非 RPC 信号,实现更高效、更低的延迟和更高的吞吐量 会实现的值。

类表示一个承诺,承诺设备会实现某个接口或协议。 设备存在于设备文件系统中,位于拓扑路径下,例如 /sys/platform/pci/00:02:00/e1000。如果是特定类,则也会显示 用作 /dev/class/CLASSNAME/... 下的别名。e1000 驱动程序会实现 Ethermac 接口,因此它也会显示在 /dev/class/ethermac/000 处。名称 是唯一的,但无意义,并且是按需分配的。

协议示例:

  • PCI 根协议 (ZX_PROTOCOL_PCIROOT),
  • PCI 设备协议 (ZX_PROTOCOL_PCI),以及
  • 以太网实现协议 (ZX_PROTOCOL_ETHERNET_IMPL)。

括号内的名称是与相应协议对应的 C 语言常量,仅供参考。

依赖于平台与不依赖于平台

上面,我们提到ZX_PROTOCOL_ETHERNET_IMPL“接近”使用的函数 但少了一步 这是因为中间还有另一个协议 ZX_PROTOCOL_ETHERNET, 客户端和驱动程序。 该附加协议旨在处理所有以太网网络通用的功能 驱动程序(以免代码重复)。 此类功能包括缓冲区管理、状态报告和管理功能 函数。

这实际上是“依赖于平台”与“不依赖于平台”分离; 通用代码存在于与平台无关的部分(一次),以及特定于驱动程序的代码 在依赖于平台的部分中实现。

这种架构在多个地方重复出现。 举例来说,对于块设备,硬件驱动程序会绑定到总线(例如,PCI) 并提供 ZX_PROTOCOL_BLOCK_IMPL 协议。 独立于平台的驱动程序会绑定到 ZX_PROTOCOL_BLOCK_IMPL,并发布 面向客户端的协议 ZX_PROTOCOL_BLOCK

在显示控制器、I2C 总线和串行驱动程序中,您也会看到这种情况。

进程 / 协议映射

为简单起见,我们没有谈到进程分离 因为这与司机有关 为了了解具体问题,我们来看看其他操作系统是如何处理它们的。 并将其与 Fuchsia 方法进行比较。

在单体式内核(例如 Linux)中,许多驱动程序都在内核中实现。 这意味着它们共享相同的地址空间,并且实际上位于同一个 “process”

这种方法的主要问题是故障隔离 / 利用。 不良驱动程序可能会导致整个内核被删除,因为它位于同一个地址中 因此拥有对所有内核内存和资源的特权访问。 遭到入侵的驱动程序也会出于同样的原因带来安全威胁。

另一种极端做法就是,将每项司机服务都放在自己的部门 被一些微内核操作系统使用。 它的主要缺点是,如果一个司机依赖于另一个司机的服务, 内核必须至少影响一个上下文切换操作(如果不是数据传输) 在两个驱动程序进程之间实现预期目标。 虽然微内核操作系统通常设计为运行速度快, 高频率执行操作是不可取的。

Fuchsia 采用的方法基于驱动程序主机的概念。 驱动程序主机是包含协议栈(即一个或多个 可协同工作的协议。 驱动程序主机从 ELF 共享库(称为动态共享对象、 或 DSO)。

协议栈可有效地创建完整的“驱动程序”用于 由依赖于平台和独立于平台的组件组成的设备; 存储到一个独立的进程容器中

对于高级阅读器,请查看以下 driver dump 命令: Fuchsia 命令行。它会显示设备树,并向您展示 进程 ID、DSO 名称以及其他有用信息。

下面是一个高度编辑的版本,仅显示 PCI 以太网驱动程序部分:

1. [root]
2.    [sys]
3.       <sys> pid=1416 /boot/driver/bus-acpi.so
4.          [acpi] pid=1416 /boot/driver/bus-acpi.so
5.          [pci] pid=1416 /boot/driver/bus-acpi.so
            ...
6.             [00:02:00] pid=1416 /boot/driver/bus-pci.so
7.                <00:02:00> pid=2052 /boot/driver/bus-pci.proxy.so
8.                   [e1000] pid=2052 /boot/driver/e1000.so
9.                      [ethernet] pid=2052 /boot/driver/ethernet.so

在上面的代码中,您可以看到进程 ID 1416(第 3-6 行) 是高级配置与电源接口 (ACPI) 驱动程序, 由 DSO bus-acpi.so 提供。

在主要枚举期间,ACPI DSO 检测到了 PCI 总线。 这会导致发布一个 ZX_PROTOCOL_PCI_ROOT 的父级(第 5 行, 导致出现 [pci] 条目), 这随后会导致驱动程序主机加载 bus-pci.so DSO 并与其绑定。 DSO 是“基本 PCI 驱动程序”这也是在本课程中 。

在绑定期间,基础 PCI 驱动程序枚举 PCI 总线,并找到以太网 卡(第 6 行检测总线 0、设备 2,函数 0,显示为 [00:02:00])。 (当然,还找到了许多其他设备,但是我们已经将它们从 (为简单起见,请参见上文列表)。

随后,检测到此设备会导致基础 PCI 驱动程序发布新的父级 ZX_PROTOCOL_PCI 以及设备的 VID 和 DID。 此外,还创建了一个新的驱动程序主机(进程 ID 2052),并随 bus-pci.proxy.so DSO(第 7 行)。 此代理充当从新驱动程序主机 (pid 2052) 到基础 PCI 的接口 驱动程序 (pid 1416)。

在此处,我们决定“断开”将设备驱动程序推进到自己的 进程 - 新的驱动程序主机和基础 PCI 驱动程序现在分在两个 不同进程

然后,新的驱动程序主机 2052 会查找匹配的子项 (e1000.so 第 8 行 DSO;之所以将其视为匹配,是因为它具有 ZX_PROTOCOL_PCI 且正确的 VID 和 DID)。 DSO 发布 ZX_PROTOCOL_ETHERNET_IMPL,以绑定到匹配的 子级(第 9 行的 ethernet.so DSO;它被视为匹配,因为它具有 ZX_PROTOCOL_ETHERNET_IMPL 协议)。

此链未显示出最终 DSO (ethernet.so) 发布的是 ZX_PROTOCOL_ETHERNET - 这是客户端可以使用的部分, 当然,没有进一步的“设备”涉及的绑定。

驱动程序框架版本 2 (DFv2)

如果启用了驱动程序框架版本 2,driver dump 将略微显示 不同的树。

$ driver dump
[root] pid=4766 fuchsia-boot:///#meta/platform-bus.cm
   [sys] pid=4766
      [platform] pid=4766
         [pt] pid=4766 fuchsia-boot:///#meta/platform-bus-x86.cm
            [acpi] pid=4766
               [acpi-pwrbtn] pid=4766 fuchsia-boot:///#meta/hid.cm
               ...
            [PCI0] pid=4766 fuchsia-boot:///#meta/bus-pci.cm
               [bus] pid=4766
                 ...
                 [00_04_0] pid=4766 fuchsia-boot:///#meta/virtio_ethernet.cm
                    [virtio-net] pid=4766 fuchsia-boot:///#meta/netdevice-migration.cm
                       [netdevice-migration] pid=4766 fuchsia-boot:///#meta/network-device.cm
                          [network-device] pid=4766
        ...

请务必注意,节点(设备在 Google Cloud 中 DFv2)没有关联的 .so 文件。而是包含 附加到指定节点的驱动程序的组件清单。