RFC-0112:x86 上的 ACPI 支援

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

改善 x86 的 ACPI 支援。

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

摘要

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

這個 RFC 引進了包含 ACPI 裝置和匯流排 (I2C、SPI、PCI) 裝置的複合型裝置的機制。這也會新增在 x86 主機驅動程式庫外使用更多 ACPI 功能 (接收事件、存取設定和呼叫方法) 的支援功能。

提振精神

目前,所有支援的 ACPI 僅限 ACPI 裝置 (即非 PCI 匯流排) 都會在單一 if/else 陳述式中列舉。需要存取其他 ACPI 資料的裝置 (例如 _DSD 中的資料) 屬於 x86 主機板驅動程式庫程式、對資料進行硬式編碼,或是使用裝置專用的入侵事件,為裝置提供自我設定所需的資料。

請注意,x86 主機板驅動程式是錯誤的程式:並非所有 x86 平台都必須使用 ACPI。較好的說法可能是「PC board 驅動程式」,也就是 IBM PC 平台的桌上驅動程式庫。為求簡化,我們將驅動程式庫視為 x86 板驅動程式。雖然這個 RFC 會嘗試描述 ACPI 適用於日後適用於 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 (「目前資源」),確認其是否具備 I2C/SPI 等資源。如果可以,請取得公車裝置的控制代碼 (在資源中指定),在步驟 1 的對應中查詢該帳號代碼,然後告知該把新的子項裝置和公車類型。
  3. 依照步驟 1 找到的順序發布所有裝置,包括裝置匯流排相關資訊做為繫結屬性 (例如 PCI Bus:device.function) 也會為每台公車裝置建立公車 ID。這樣做非常重要,因為我們需要區分不同地址的兩部 I2C 裝置。

發布複合型「ACPI + Real」裝置。

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

根據裝置使用的匯流排,板機驅動程式庫會使用前一個實作階段所收集到的資訊,執行以下兩種作業之一:

  1. 針對在執行階段列舉的公車 (例如 PCI、USB):提供 ACPI 透過通訊協定專屬機制所已知裝置的相關資訊 (舉例來說,若為 PCI,則這會是 Pciroot 的 GetPciPlatformInfo() 呼叫中回傳的 bus:device.function 清單)。接著,匯流排驅動程式會負責發布繫結至 ACPI 裝置的複合裝置,以及匯流機驅動程式發布的「實際」裝置。
  2. 針對在執行階段未列舉的公車 (例如 I2C、SPI):ACPI 驅動程式會發布複合裝置,並透過現有的機制 (例如 DEVICE_METADATA_I2C_CHANNELS) 通知公車驅動程式。在此情況下,匯流排驅動程式只會發布與複合式片段繫結的裝置。x86 主機板驅動程式庫會發布複合裝置。

之所以區分責任,是因為針對 PCI 等執行階段列舉的公車,裝置驅動程式會使用匯流排驅動程式提供的資訊來繫結資訊 (例如廠商 ID 和裝置 ID)。從 x86 主機板驅動程式庫發布這些複合資料,可能涉及設計一種機制,從匯流排驅動程式收集這項資訊。

同樣地,I2C 和 SPI 等其他公車沒有裝置驅動程式要繫結的資訊。他們通常只知道裝置所連接的足夠資訊 (例如 I2C 位址、SPI 晶片選取號碼),但不知道裝置連接的裝置類型。此資訊會改在 ACPI 資料表中以硬體或相容 ID 顯示。因此,以實用的方式從匯流排驅動程式發布這些複合資料,可能就牽涉到公車驅動程式不需要的資訊 (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 公開啟用、停用和安裝方法呼叫 - 系統會關閉傳遞安裝管道的裝置端,以隱含方式實作移除。
  • 位址空間處理常式與事件處理常式非常類似,將以類似的方式處理。

我們也將限制一個更危險的機制,限制僅對已加入許可清單的裝置 (AcpiAcquireGlobalLock) 公開的 FIDL 通訊協定。目前僅供 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 資料表,所以很容易失真。

先前的圖片和參考資料