| RFC-0112:x86 的 ACPI 支援 | |
|---|---|
| 狀態 | 已接受 |
| 區域 |
|
| 說明 | 改善 x86 的 ACPI 支援。 |
| 問題 | |
| Gerrit 變更 | |
| 作者 | |
| 審查人員 | |
| 提交日期 (年-月-日) | 2021-06-11 |
| 評論日期 (年-月-日) | 2021-07-21 |
摘要
大多數 x86 平台都使用進階設定與電源介面 (ACPI),提供裝置拓撲、設定的相關資訊,並為 OS 提供電源管理功能。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 (「目前資源」),確認是否有 I2C/SPI/等資源。如果是,請取得匯流排裝置的控制代碼 (在資源中指定),在步驟 1 的對應中查詢該控制代碼,並告知其新的子裝置和匯流排類型。
- 按照步驟 1 探索到的順序發布所有裝置,包括與裝置匯流排相關的資訊,做為繫結屬性 (例如 PCI 匯流排:device.function),並為每個匯流排裝置建立匯流排 ID。這點很重要,因為我們需要區分不同匯流排上相同位址的兩個 I2C 裝置。
發布複合式「ACPI + 實際」裝置。
為了存取裝置所在匯流排提供的資源,以及 ACPI 提供的設定方法,我們需要建立複合裝置,其中包含匯流排驅動程式發布的「實際」裝置,以及 x86 主機板驅動程式庫發布的 ACPI 裝置。
板驅動程式庫會根據在先前實作階段收集到的資訊,執行下列其中一項操作,具體取決於裝置使用的匯流排:
- 針對在執行階段列舉的匯流排 (例如 PCI、USB):透過通訊協定專屬機制 (例如針對 PCI,這會是 Pciroot 的
GetPciPlatformInfo()呼叫傳回的匯流排:裝置.函式清單),提供 ACPI 已知的裝置相關資訊。接著,匯流排驅動程式會負責發布複合裝置,這些裝置會繫結至 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 父項:
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 表格所帶來的效益。