驅動程式中的通訊協定

什麼是通訊協定?

通訊協定是一種嚴格的介面定義。

乙太網路驅動程式庫發布了與 ZX_PROTOCOL_ETHERNET_IMPL 相符的介面。這表示必須提供資料結構中定義的一組函式 (在本例中為 ethernet_impl_protocol_ops_t)。

這些函式適用於所有實作通訊協定的裝置。舉例來說,所有乙太網路裝置都必須提供可查詢介面 MAC 位址的函式。

其他通訊協定當然對其必須提供函式有不同的要求。舉例來說,區塊裝置會發布符合「區塊實作通訊協定」(ZX_PROTOCOL_BLOCK_IMPL) 的介面,並提供 block_protocol_ops_t 定義的函式。例如,這個通訊協定含有會傳回裝置區塊大小的函式。

在許多情況下,通訊協定會使用通訊協定的常見實作,讓驅動程式更簡單。舉例來說,「block」驅動程式庫會實作通用區塊介面,並繫結至實作 Block Core 通訊協定的裝置,而「乙太網路」驅動程式庫也會對乙太網路介面和乙太網路通訊協定執行相同作業。有些通訊協定 (例如此處引用的兩個通訊協定) 使用共用記憶體和非 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 等單體式核心中,許多驅動程式會在核心內實作。 這意味著這些儲存空間共用的位址空間相同,而且實際上會存放在相同的「程序」中。

這種方法的主要問題是錯誤隔離 / 利用。不良的驅動程式庫會佔用整個核心,因為此核心位於相同的位址空間,因此有權存取所有核心記憶體和資源。就算驅動程式庫遭到入侵,也會基於相同原因帶來安全性威脅。

另一個極端做法,就是將每項和每個驅動程式庫服務都放到各自的程序中,一些微核心作業系統會使用。其主要的缺點是,如果其中一個驅動程式庫依賴另一個驅動程式庫的服務,則核心必須在兩個驅動程式庫程式程序之間至少效果切換作業 (如果不能同時進行資料移轉)。雖然微核心作業系統通常設計為在這類作業中快速運作,但以高頻率執行並不理想。

Fuchsia 採取的做法是以驅動程式代管程序的概念為基礎。驅動程式代管程序是一個包含通訊協定堆疊的程序,也就是一或多個搭配運作的通訊協定。驅動程式主機會從 ELF 共用資料庫 (稱為動態共用物件或 DSO) 載入驅動程式。

通訊協定堆疊可有效地在獨立的程序容器中,為裝置建立完整的「驅動程式庫」,其中包含與平台相依和平台的獨立元件。

對於進階讀取器,請查看 Fuchsia 指令列提供的 driver dump 指令。這項工具會顯示裝置的樹狀結構,並顯示程序 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 行) 是 DSO bus-acpi.so 實作的進階設定和電源介面 (ACPI) 驅動程式庫。

在主要列舉期間,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 的新父項。此外,已透過 bus-pci.proxy.so DSO (第 7 行) 建立新的驅動程式代管程序 (程序 ID 2052)。這個 Proxy 可做為新驅動程式代管程序 (pid 2052) 至基礎 PCI 驅動程式庫 (pid 1416) 的介面。

這時我們做出決定,就要將裝置驅動程式庫「永久」納入自己的程序:新的驅動程式代管程序和基礎 PCI 驅動程式庫現在分為兩個不同的程序。

新的驅動程式代管程序 2052 會找到相符的子項 (第 8 行上的 e1000.so DSO;由於其有 ZX_PROTOCOL_PCI 和正確的 VID 和 DID,因此系統視為相符)。DSO 會發布 ZX_PROTOCOL_ETHERNET_IMPL,該 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
        ...

請務必指出,節點 (裝置在 DFv2 中稱為節點) 並未擁有相關聯的 .so 檔案。相反地,使用附加至指定節點的驅動程式庫元件資訊清單網址。