RFC-0112:在 x86 上支援 ACPI | |
---|---|
狀態 | 已接受 |
區域 |
|
說明 | 改善 x86 上的 ACPI 支援功能。 |
問題 | |
Gerrit 變更 | |
作者 | |
審查人員 | |
提交日期 (年-月-日) | 2021-06-11 |
審查日期 (年-月-日) | 2021-07-21 |
摘要
進階設定和電源介面 (ACPI) 可用於大多數 x86 平台,用於提供裝置拓樸、設定相關資訊,以及為作業系統提供電源管理功能。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 試圖概略說明 ACPI 的合理通用方法,以便日後同時適用於 x86 和 ARM,但 RFC 的主要重點是 x86 主機板驅動程式庫的變更,而日後的 ARM ACPI 工作可能需要使用不同的主機板驅動程式庫。
這種做法無法擴展。由於我們希望支援更多裝置,因此會遇到硬式編碼值彼此衝突,或是 x86 主機板驅動程式庫中的驅動程式數量變得龐大等情況。這項 RFC 可讓我們新增更多 x86 平台和電源管理支援功能,而不會在板卡驅動程式庫中增加更多技術債務。
設計
x86 上的每個現有裝置都會獲得對應的 ACPI 裝置 (只要裝置在 ACPI 資料表中具有項目)。每個 ACPI 裝置都會由 x86 板卡驅動程式庫發布,並提供存取裝置 ACPI 設定和方法的權限。x86 主機板驅動程式庫也會發布複合裝置,這些裝置是「實際」裝置和 ACPI 裝置的子項。因此,如果有驅動程式庫想要使用其中一個裝置,就會將自己繫結至複合裝置,而非直接繫結至「實際」裝置。板卡驅動程式庫也會在靜態列舉的匯流排 (例如 I2C、SPI) 上發現裝置,並發布中繼資料,告知匯流排驅動程式其子裝置數量。
少數裝置也會獲得更危險的 ACPI 作業存取權,例如取得 ACPI 全域鎖定。實際上,只有少數裝置需要存取這項功能,因此這項功能只會公開給 x86 主機板驅動程式庫中允許的一組裝置。
以下是透過 SPI 匯流排連線的 TPM 裝置,裝置樹狀結構的單一分支可能的樣貌。
實作
探索裝置關係,並在系統上發布 ACPI 裝置。
在探索 ACPI 裝置時,我們需要判斷特定裝置是否為匯流排驅動程式庫,如果是,則判斷該匯流排的類型。這項資訊很重要,因為可讓我們判斷下一個步驟中新增的複合裝置應如何繫結其 ACPI 和實際對應項目。ACPI 沒有簡單的方法,可從裝置判斷這兩個屬性,也無法保證匯流排上的裝置會是匯流排的子項。因此,您必須將裝置探索和發布程序分為三個階段:
- 探索樹狀結構中的裝置,並將裝置的 ACPI 句柄對應至其內部表示法,其中包含最終發布裝置時所需的資訊,例如其父項裝置、句柄和匯流排類型。
- 針對每部裝置,請檢查其 _CRS (「Current Resources」),瞭解是否有 I2C/SPI 等資源。如果是,請取得匯流排裝置的句柄 (在資源中指定),在步驟 1 的對應項目中查詢該句柄,並告知匯流排其新的子裝置和匯流排類型。
- 依照步驟 1 中發現的順序發布所有裝置,包括與裝置匯流排相關的資訊,做為繫結屬性 (例如 PCI 匯流排:device.function),並為每個匯流排裝置建立匯流排 ID。這點很重要,因為我們需要區分不同匯流程式碼的相同位址,例如兩個 I2C 裝置。
發布複合「ACPI + 實體」裝置。
為了存取裝置所在的匯流排提供的資源,以及 ACPI 提供的設定方法,我們需要建立複合裝置,其中包含由匯流排驅動程式發布的「實際」裝置,以及由 x86 主機板驅動程式庫發布的 ACPI 裝置。
根據裝置使用的匯流排,板級驅動程式庫會根據在實作前階段收集到的資訊,執行下列任一操作:
- 針對在執行階段列舉的匯流排 (例如 PCI、USB):透過特定通訊協定機制,提供 ACPI 已知的裝置資訊 (例如針對 PCI,這會是 bus:device.functions 清單,做為 Pciroot 的
GetPciPlatformInfo()
呼叫的一部分傳回)。接著,匯流排驅動程式將負責發布繫結至 ACPI 裝置的複合裝置,以及由匯流排驅動程式發布的「實際」裝置。 - 對於未在執行階段列舉的匯流排 (例如 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 父項繫結至其 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 介接。我們會將 ACPICA 程式庫的子集公開給每部裝置,做為 FIDL 介面 (我們可能會在日後公開更多內容,但這會涵蓋撰寫本文時所有樹狀結構內的驅動程式所使用的所有內容):
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 資料表,就能輕鬆抵銷這項作業帶來的好處。