RFC-0112:x86 上的 ACPI 支援

RFC-0112:x86 上的 ACPI 支援
狀態已接受
區域
  • 裝置
說明

改善 x86 的 ACPI 支援。

問題
Gerrit 變更
作者
審查人員
提交日期 (年-月-日)2021-06-11
審查日期 (年-月-日)2021-07-21

摘要

大多數 x86 平台都會使用進階設定和電源介面 (ACPI),提供裝置拓撲和設定的相關資訊,並為作業系統提供電源管理功能。Fuchsia 目前的 ACPI 支援非常有限:不支援由其他匯流排驅動程式 (例如 PCI) 列舉的 ACPI 裝置,也不支援存取 x86 板驅動程式庫以外的裝置專屬設定或電源管理方法的裝置。

本 RFC 介紹發布複合裝置的機制,這類裝置包含 ACPI 裝置和匯流排 (即 I2C、SPI、PCI) 裝置。此外,這個版本也支援在 x86 主機板驅動程式庫以外使用更多 ACPI 功能 (接收事件、存取設定及呼叫方法)。

提振精神

目前,所有支援 ACPI 的裝置 (即不在 PCI 匯流排上) 都列舉在單一 if/else 陳述式中。需要存取其他 ACPI 資料 (例如來自 _DSD 的資料) 的裝置,不是 x86 主機板驅動程式庫的一部分,就是硬式編碼資料,或是使用裝置專屬的駭客,為裝置提供設定自身所需的資料。

請注意,x86 主機板驅動程式是誤稱,並非所有 x86 平台都一定會使用 ACPI。更合適的詞彙可能是「PC 板驅動程式」,也就是 IBM PC 平台的板驅動程式庫。為簡化說明,我們仍將驅動程式庫稱為「x86 開發板驅動程式」。雖然這項 RFC 嘗試概述適用於 x86 和 ARM 的合理通用 ACPI 方法,但 RFC 的主要重點是 x86 板載驅動程式庫的變更,而未來的 ARM ACPI 工作可能需要使用獨立的板載驅動程式庫。

這種做法無法擴大規模。由於我們想支援更多裝置,因此會遇到硬式編碼值彼此衝突的情況,或是 x86 板驅動程式庫中的驅動程式數量變得龐大。這項 RFC 可讓我們新增更多 x86 平台和電源管理支援,而不會在主機板驅動程式庫中承擔更多技術債務。

設計

x86 上的每個現有裝置都會獲得對應的 ACPI 裝置 (只要裝置在 ACPI 表格中有項目)。每個 ACPI 裝置都會由 x86 主機板驅動程式庫發布,並提供裝置 ACPI 設定和方法的存取權。x86 主機板驅動程式庫也會發布複合裝置,這些裝置是「實際」裝置和 ACPI 裝置的子項。如果驅動程式庫想使用其中一個裝置,會繫結至複合裝置,而不是直接繫結至「實際」裝置。主機板驅動程式庫也會在靜態列舉的匯流排 (即 I2C、SPI) 上探索裝置,並發布中繼資料,告知匯流排驅動程式子項裝置的數量。

少數裝置也會取得 ACPI 全域鎖定等更危險的 ACPI 作業存取權。實際上,並非許多裝置都需要存取這項功能,因此這項功能只會向 x86 主機板驅動程式庫程式允許的裝置公開。

以下範例顯示透過 SPI 匯流排連線的 TPM 裝置,其裝置樹狀結構的單一分支可能如下所示。

SPI 的裝置樹狀架構分支

實作

探索裝置關係,並在系統上發布 ACPI 裝置。

探索 ACPI 裝置時,我們需要判斷特定裝置是否為匯流排驅動程式庫,如果是,則為哪種匯流排。這項資訊非常重要,因為可讓我們判斷下一步新增的複合裝置應如何與 ACPI 和實際對應項目繫結。ACPI 無法簡單地從裝置判斷這兩項屬性,也無法保證匯流排上的裝置會是匯流排的子項。因此,裝置探索和發布程序必須分成三個階段:

  1. 在樹狀結構中探索裝置,設定裝置 ACPI 控制代碼與內部表示法的對應,包括最終發布裝置時所需的資訊,例如父項裝置、控制代碼和匯流排類型。
  2. 針對每部裝置,請檢查其 _CRS (「Current Resources」),確認是否有 I2C/SPI 等資源。如果是,請取得匯流排裝置的控制代碼 (在資源中指定),在步驟 1 的對應中查閱該控制代碼,並告知新的子項裝置和匯流排類型。
  3. 依據步驟 1 中探索到的順序發布所有裝置,包括與裝置匯流排相關的資訊,做為繫結屬性 (例如 PCI 匯流排:裝置.功能),並為每個匯流排裝置建立匯流排 ID。這項資訊非常重要,因為我們需要區分不同匯流排上相同地址的兩個 I2C 裝置。

發布「ACPI + real」複合裝置。

如要存取裝置所在匯流排提供的資源,以及 ACPI 提供的設定方法,我們需要建立複合裝置,其中包含匯流排驅動程式發布的「實際」裝置,以及 x86 板驅動程式庫發布的 ACPI 裝置。

根據實作階段收集到的資訊,視裝置使用的匯流排而定,板載驅動程式庫會執行下列其中一項操作:

  1. 如果是執行階段列舉的匯流排 (例如 PCI、USB),請透過通訊協定專屬機制提供 ACPI 已知的裝置資訊 (例如,如果是 PCI,這會是匯流排:裝置.函式清單,做為 Pciroot 的 GetPciPlatformInfo() 呼叫傳回)。然後,匯流排驅動程式會負責發布繫結至 ACPI 裝置和匯流排驅動程式發布的「實際」裝置的複合裝置。
  2. 對於未在執行階段列舉的匯流排 (例如 I2C、SPI):ACPI 驅動程式會發布複合裝置,並使用現有機制 (例如 DEVICE_METADATA_I2C_CHANNELS) 通知匯流排驅動程式其子項。在本例中,匯流排驅動程式只會發布繫結至複合片段的裝置。x86 板驅動程式庫會發布複合裝置。

之所以要區分責任,是因為對於 PCI 等執行階段列舉的匯流排,裝置驅動程式會使用匯流排驅動程式提供的資訊進行繫結 (例如供應商和裝置 ID)。如要從 x86 板驅動程式庫發布這些複合項目,必須設計機制,從匯流排驅動程式收集這項資訊。

同樣地,I2C 和 SPI 等其他匯流排也沒有裝置驅動程式想要繫結的資訊。通常只知道足夠的資訊來處理裝置 (例如 I2C 位址、SPI 晶片選取號碼),但不知道裝置連接的是哪種裝置。這項資訊會以硬體或相容 ID 的形式,出現在 ACPI 表格中。因此,以實用的方式發布匯流排驅動程式的這些複合資料,會涉及向匯流排驅動程式提供他不需要的資訊 (HID 和 CID)。

繫結程式範例

在第一種情況中,x86 板載驅動程式庫會告知匯流排哪些裝置需要組成複合裝置,而匯流排驅動程式會發布含有兩個片段的複合裝置。舉例來說,PCI 匯流排驅動程式可能會發布含有兩個片段的複合裝置。第一個會繫結至 PCI 匯流排上的裝置,繫結程式類似於:

BIND_PROTOCOL == PCI
BIND_PCI_TOPO == 0x5a

第二個會繫結至 ACPI 匯流排發布的對等裝置:

BIND_PROTOCOL == ACPI
BIND_ACPI_BUS_TYPE == PCI
BIND_PCI_TOPO == 0x5a

在第二種情況下,x86 主機板驅動程式庫會使用其所知的每個匯流排資訊,建立兩個片段,與上述情況類似。舉例來說,I2C 複合裝置會透過類似下列的繫結程式,繫結至 I2C 父項:

BIND_PROTOCOL == I2C
BIND_I2C_ADDRESS == 0xaa
BIND_I2C_BUS_ID == 0

對應的 ACPI 繫結程式會如下所示:

BIND_PROTOCOL == ACPI
BIND_ACPI_BUS_TYPE == I2C
BIND_I2C_ADDRESS == 0xaa
BIND_I2C_BUS_ID == 0

透過 FIDL 公開 ACPI 事件、設定和方法

x86 開發板驅動程式庫會使用 ACPICA 程式庫與 ACPI 介接。我們會以 FIDL 介面形式,向每個裝置公開 ACPICA 程式庫的子集 (日後可能會公開更多,但這涵蓋撰寫本文時所有樹狀結構內驅動程式使用的所有內容):

  • AcpiEvaluateObject - 裝置可任意存取,評估樹狀結構中的方法,以控制裝置狀態或取得設定資訊。我們會限制裝置只能評估自身及其子項的方法。
  • 事件處理常式 - ACPI 支援三種事件類型:固定事件、一般用途事件和裝置物件通知。這三種方式大致上類似:裝置可以啟用/停用事件,並安裝事件處理常式,在收到事件時呼叫。我們會透過 FIDL 公開啟用、停用和安裝方法呼叫,移除作業會透過關閉傳遞至安裝作業的管道裝置端,以隱含方式實作。
  • 位址空間處理常式 - 與事件處理常式非常相似,處理方式也類似。

我們將限制另一種危險機制,只允許已列入許可清單的裝置使用,並將其納入獨立的 FIDL 通訊協定中,AcpiAcquireGlobalLock。這項功能目前僅供 acpi-ec 驅動程式庫使用,且在 EC 以外的地區似乎不常見。我們會根據 HID 將其加入許可清單,首先只會加入 ACPI EC HID。

遷移司機

此時,我們已準備好開始將驅動程式遷移至 ACPI。如果是目前使用 x86 板載驅動程式庫的驅動程式,則需要重新編寫程式碼,才能使用新的 ACPI-over-FIDL 通訊協定。對於 x86 板載驅動程式庫以外的驅動程式 (例如 Intel I2C 驅動程式庫或 I2C HID 驅動程式庫),這項作業相對簡單,只要將現有的硬式編碼設定值,替換為從 ACPI 判斷的新值即可。

效能

預期成效影響不大。大部分的新負荷來自於目前在 x86 主機板驅動程式庫中的驅動程式,這些驅動程式會移至自己的驅動程式,並強制執行 IPC 與 ACPI 互動。

安全性考量

  • ACPI 方法可以執行任何動作 - 最終,即使採用上述範圍設定,ACPI 方法仍可執行任何動作 (例如在不適當的時機關閉硬體電源),因此任何有權呼叫該方法的驅動程式庫,都能執行任何動作。因此,我們需要信任使用 ACPI 的任何驅動程式 (以及 ACPI 表格本身)。這與現狀並無不同,因為所有 ACPI 驅動程式都在主機板驅動程式庫中。另請注意,所有主機板驅動程式的權限相同,且主機板驅動程式庫可能由外部提供 (即並非在 fuchsia.git 中編寫及建構)。未來可能出現稽核和控管問題。

隱私權注意事項

無。

測試

由於 ACPI 假設可存取整個系統,因此我們會大量採用單元測試,測試主機板驅動程式庫實作。這些單元測試會驗證所有功能是否正常運作 (例如匯流排類型推斷、裝置探索等)。我們也會加入測試,確保 ACPI 裝置實作的所有 FIDL 方法都正確無誤。

裝置驅動程式將能相當輕鬆地模擬新的 ACPI FIDL 通訊協定,因此我們將能為先前無法測試 (或難以測試) 的裝置驅動程式編寫單元和整合測試。

說明文件

FIDL ACPI 通訊協定會包含使用方式和限制的說明文件。您需要撰寫一些說明文件,說明 ACPI 系統裝置的「ACPI+real」複合模型,以及驅動程式應如何處理該情境中的繫結。

缺點、替代方案和未知事項

不支援任意匯流排類型

如要支援透過 ACPI 公開的 x86 系統新匯流排類型,必須修改 x86 主機板驅動程式庫。很遺憾,這是 ACPI 實作方式的限制:不支援「一般」或「不明」匯流排。我們預期這項作業的維護負擔相對較小,而且可輕鬆抵銷因能夠存取主機板驅動程式庫外的 ACPI 表格而帶來的效益。

既有技術和參考資料