RFC-0192:Fuchsia 上的裝置樹狀結構

RFC-0192:Fuchsia 上的裝置樹狀結構
狀態已接受
區域
  • 裝置
說明

使用裝置樹狀結構描述硬體版面配置的策略

問題
Gerrit 變更
作者
審查人員
提交日期 (年-月-日)2022-08-03
審查日期 (年-月-日)2022-10-01

摘要

扁平化裝置樹狀結構 (「FDT」或「devicetrees」) 是一種廣泛用於描述電路板上硬體版面配置的格式。雖然這些 API 的運作層級較低,因此可將更多複雜性推送至作業系統,但它們與 ACPI 的用途大致相同。FDT 規格定義了二進位裝置樹 blob 格式 (「DTB」),以及用於編譯裝置樹 blob 的來源格式 (「DTS」)。

這份 RFC 提出了務實的方法,可在 Fuchsia 中支援裝置樹狀結構,而無須將裝置樹狀結構 (其版面配置或二進位格式) 做為 ABI。相反地,裝置樹狀結構的確切 ABI 則由板卡驅動程式定義,以便在其與韌體之間定義。另請注意,此 RFC 僅涉及板卡驅動程式使用裝置樹狀結構的情形。如果或當核心剖析裝置樹狀結構時,會有個獨立的 RFC 說明該裝置樹狀結構的格式。

提振精神

基於以下多項原因,單靠主機板驅動程式無法持續擴大 Fuchsia 的硬體支援:

  1. 我們希望能夠重複執行硬體設定,而不需要重新組合/重建 Fuchsia 映像檔。
  2. Devicetree 廣泛用於開發人員,我們希望能與開發人員在他們所在的位置進行交流。Devicetree 也擁有相對健全的生態系統。
  3. 但由於現今的寫法,不利於多個機構之間的協作。
  4. 這會導致韌體和板卡驅動程式庫在偵測系統中可用的硬體時,重複執行相同的工作。
  5. 在支援多個相關電路板 (即共用 SoC 或 SoC 系列) 時,這些電路板無法順利擴充。
    • 如要支援多個電路板,您必須在整個電路板驅動程式庫中新增條件式,或是使用多個電路板驅動程式。
    • 雖然可以以簡潔的方式執行這項操作,但比起使用裝置樹狀結構,更容易產生意義不明的程式碼。
    • 透過裝置樹狀結構,您可以更輕鬆地透過單一 Fuchsia 映像檔支援多個電路板 (不過請注意,我們目前並未著重於「通用」Fuchsia 映像檔)。

裝置樹可為這些問題提供解決方案,為硬體設定提供單一來源,方便與系統其他部分分開操作 (可輕鬆透過啟動韌體和負責啟動作業的群組進行修改),也能輕鬆組合 (可輕鬆在基於相同 SoC 系列的板卡之間共用設定)。

請注意,這項 RFC 的目標並非完全淘汰板卡驅動程式。板卡驅動程式仍是 Fuchsia 驅動程式庫程式拓樸結構的核心部分,這份 RFC 建議使用裝置樹狀結構來補足板卡驅動程式,以提高其彈性。任何無法透過裝置樹狀結構表示的內容,仍可在板卡驅動程式庫中實作。

相關人員

協助人員:

cpu@google.com

審查者:

  • surajmalhotra@google.com
  • curtisgalloway@google.com
  • gkalsi@google.com
  • bradenkell@google.com
  • cja@google.com
  • dpursell@google.com

諮詢:

  • aaronwood@google.com
  • mcgrathr@google.com

社會化:

我們已在內部分享這份提案的簡要概要。

詞彙解釋

  • 板級驅動程式:可向驅動程式庫架構說明系統上現有的硬體。系統中只有一個板卡驅動程式庫例項。
  • 韌體:系統首次開機時執行的部分,負責載入 Zircon 並啟動。

設計

本文件中的關鍵字「MUST」、「MUST NOT」、「REQUIRED」、「SHALL」、「SHALL NOT」、「SHOULD」、「SHOULD NOT」、「RECOMMENDED」、「MAY」和「OPTIONAL」應依 IETF RFC 2119 所述進行解讀。

Devicetree 的角色

裝置樹狀結構僅用於描述硬體版面配置資訊。產品設定必須透過產品組合完成。無論所執行的產品為何,裝置樹都應只包含板卡的實際資訊,而非設定可能有所不同的驅動程式行為,例如預先配置的記憶體緩衝區大小或分割區對應項目。

Devicetree 與 ACPI

我們建議使用 ACPI 而非裝置樹狀結構。如果電路板支援 ACPI,應使用 ACPI 進行開機。在支援 ACPI 的板子上,請務必不要使用裝置樹狀結構。這是因為 Fuchsia 會為每個支援的架構提供單一 ACPI 開發板驅動程式庫。ACPI 提供更高層級的抽象化和標準化程度,因此更容易支援。

相容性

我們的裝置樹狀結構繫結不會嘗試維持與 Linux 或任何其他作業系統的相容性,特別是裝置驅動程式庫繫結。這主要是因為與 ACPI 不同,裝置樹狀結構並未廣泛標準化,且不同 OS 版本的繫結確切版面配置和含義各異。不過,我們會採用 spec 中所述的來源和二進位檔格式。

作為平台,Fuchsia 不會嘗試指定裝置樹狀結構的確切格式,也不會嘗試透過單一板卡驅動程式庫支援每個板卡,而是會根據規格定義一組繫結,以便支援常見功能 (例如中斷、GPIO、匯流排)。使用裝置樹狀結構的板卡驅動程式應支援此 RFC 中定義的繫結,但可視需要定義自己的繫結,以支援其他功能。

我們也會提供一種方法,讓裝置樹狀結構指定要寫入目標的板卡驅動程式庫 (例如透過 fuchsia,board-driver = "vim3-devicetree" 等根節點的屬性),以確保板卡驅動程式會剖析相容的裝置樹狀結構。

此外,我們也會定義介面,讓電路板驅動程式必須向下游驅動程式公開。這個介面會與 ACPI 介面非常相似,我們會嘗試讓 ACPI 和裝置樹狀結構互相配合,讓驅動程式能夠真正不受兩者影響。

將 Devicetree 傳遞至 Fuchsia。

我們已經有類型為 ZBI_TYPE_DEVICETREE 的 ZBI 項目。這個 ZBI 項目的內容是裝置樹 blob。我們在這裡需要做的唯一變更,就是更新文件,反映出該文件可能會由板卡驅動程式庫使用。

主機板可以選擇使用裝置樹狀結構。如果是這種情況,系統啟動載入程式應會知道這項事實,並且應將裝置樹狀結構傳遞為 ZBI_TYPE_DEVICETREE 項目。如有需要,主機板在組裝時,可以直接將裝置樹狀結構納入 ZBI (例如在啟動時,開機載入程式尚未內建 ZBI 支援之前)。

一般來說,系統啟動載入程式應從非揮發性儲存空間載入裝置樹狀結構、驗證其真實性,並在執行階段附加至 ZBI。不過,如果需要,他們可以使用其他機制 (例如將其編譯至系統啟動載入程式),並視需要略過驗證 (例如開發人員板)。

Fuchsia 平台實作

我們會為希望實作這組繫結的板卡驅動程式提供程式庫。這個程式庫會利用樹狀結構中的現有 devicetree 剖析器。此外,我們還會實作參考板驅動程式庫和裝置樹狀結構,以便利用這個程式庫啟動實際系統。前者將成為 SDK 的一部分,並位於樹狀結構中,但後者可能最終會移出樹狀結構。

裝置樹的可讀性

對裝置樹的批評之一是,由於裝置樹編譯器不支援命名的常數,因此來源格式可能相當不透明。解決這個問題的常見方法是使用含有 #define 陳述式的 C 標頭檔案,為常數宣告人類可讀的名稱,然後加入這些標頭檔案,以便在裝置樹狀結構來源中使用。我們會在 fuchsia.git 中實作這項做法,日後也會支援從繫結程式庫產生這類標頭檔案。

一般來說,支援與裝置樹狀結構搭配使用的驅動程式,會包含一個目錄,其中包含裝置樹狀結構來源檔案可用的標頭。這些標頭會定義在參照驅動程式庫公開的資源時使用的值。GPIO 驅動程式庫可能會有 PULL_UPPULL_DOWN 等常數。裝置樹狀結構來源檔案的建構規則會依賴所使用的驅動程式,這些驅動程式會用於驗證裝置樹狀結構 (請參閱說明文件),並新增至提供給 C 預處理器的包含路徑。

裝置樹狀結構的可查閱性

為了方便檢查裝置樹狀結構,我們也會推出裝置樹狀結構的「黃金」檔案。這些黃金檔案是將裝置樹狀結構來源編譯為二進位檔,然後再轉回原始碼的輸出結果,這樣一來,您就能清楚瞭解來源變更對最終裝置樹狀結構的影響。編譯板卡驅動程式庫和裝置樹時,我們會編譯及反編譯裝置樹來源,如果輸出內容與黃金檔案不同,則會導致建構失敗。

這項功能的動機是,例如在多個電路板包含共同的裝置樹狀結構來源檔案 (例如由 SoC 定義的內容) 的情況下。審查員可能無法立即瞭解變更「共用」裝置樹狀結構檔案的後果。黃金檔案可讓您清楚瞭解每個裝置樹狀結構在裝置上使用的最終輸出內容。

節點數

每個 devicetree 節點都會對應至 Fuchsia 裝置節點。Fuchsia 裝置節點將是複合節點,這些節點是代表裝置樹狀節點的子項,以及代表裝置消耗的資源 (例如 I2C 裝置、GPIO 等) 的節點。這與 ACPI 使用的做法類似。請注意,以下範例並未列舉所有內容,僅是為了說明我們最初支援的資源類型。日後可視需要新增其他資源類型。特別是,本文所述的 FIDL 介面和繫結規則並非最終版本,而是用來說明介面將支援哪些功能的假設例子。這些介面日後預計會接受更徹底的審查。

裝置中繼資料節點

裝置中繼資料節點會公開下列 FIDL 通訊協定。這個通訊協定可做為通用的「非結構化中繼資料」通訊協定,供裝置驅動程式使用。

library fuchsia.hardware.metadata;

using zx;

/// Maximum length of a property key.
const PROP_MAX: uint32 = 128;

/// Reasonable maximum for amount of data in a byte array.
const MAX_BYTE_ARRAY_LENGTH: uint32 = 4096;

/// Reasonable maximum length for a string.
const MAX_STRING_LENGTH: uint32 = 4096;

/// Reasonable maximum number of entries for a string array.
const MAX_STRING_ARRAY_LENGTH: uint32 = 4096;

/// Maximum number of properties in a dictionary.
const MAX_PROPERTIES: uint32 = 128;

type Value = flexible union {
    /// True if property is present but has no value.
    1: present bool;
    /// Little-endian 32-bit value.
    2: u32 uint32;
    /// Little-endian 64-bit value.
    3: u64 uint64;
    /// String or string array.
    4: string vector<string:MAX_STRING_LENGTH>:MAX_STRING_ARRAY_LENGTH;
    /// Byte array
    5: bytes vector<uint8>:MAX_BYTE_ARRAY_LENGTH;
    /// Child node.
    6: node Dictionary;
};

type Property = flexible table {
    /// Name of the property.
    1: name string:PROP_MAX;
    /// Value of the property.
    2: value Value;
};

type Dictionary = struct {
    /// List of properties. There may be duplicate property names, in which case the first one should win.
    1: properties vector<Property>:MAX_PROPERTIES;
};


protocol NodeMetadata {
    /// Get unstructured metadata belonging to this node.
    GetMetadata() -> (Dictionary) error zx.status;

};

繫結

每個章節都會說明裝置樹狀結構繫結,以及在 Fuchsia 上使用功能的方式。

慣例和標準資源

我們會使用 0.3 版規格第 2.2 節所述的慣例。

在第 2.3 節定義的標準屬性中,我們可能會支援以下屬性:compatiblephandlestatus#address-cells#size-cellsregranges。我們會省略 virtual-reg,因為在啟動載入程式跳至核心時,MMU 的狀態與板卡驅動程式庫無關 (因為它位於使用者空間)。我們省略 dma-rangesdma-coherent,因為這些屬性在 Fuchsia 上沒有直接對應項目。

在 Fuchsia 上:

  • compatible:compatible 陣列中的首個值會公開為繫結屬性 fuchsia.devicetree.first_compatible。日後可能會提供更精密的繫結系統 (含優先順序),屆時可能會使用其他值。
    • 此外,我們會允許節點定義自己的繫結屬性,可能是透過命名空間屬性 (例如 bind,<prop-name> = <value> 會對應繫結屬性 prop-name,其值為 value)。
  • phandle:用於在裝置樹狀結構中識別裝置節點。由裝置樹編譯器產生,僅在執行階段使用。
  • status:可用於板卡驅動程式庫,用於控制是否發布節點。我們將在實作此 RFC 期間,調查從支援的繫結中省略 status 是否可行,並且如果這麼做能大幅改善 devicetree 來源檔案的清晰度,我們可能會選擇省略。
    • 具體來說,我們建議您將裝置樹狀結構來源檔案組合在一起 (將單一 SoC 定義分割至多個檔案,並只在最終的板卡檔案中加入必要的定義),而非將這些定義加入單一檔案,並透過 status 屬性停用/啟用 IP 區塊。
  • #address-cells#size-cells - 會在板卡驅動程式庫中使用,用於判斷其他值的大小。
  • reg:針對可從樹狀結構根節點尋址的節點,板卡驅動程式庫會使用此屬性來判斷實體記憶體區域。這些記憶體區域會透過 GetMmio(int index) Fidl 呼叫 (可能會透過平台匯流排驅動程式) 提供給子節點。
  • ranges:在板卡驅動程式庫中使用,用於判斷子項位址範圍如何對應至父項。

中斷

中斷繫結會依據規格第 2.4 節的定義。

板卡驅動程式庫會向每個中斷控制器驅動程式庫提供下列中繼資料:

/// Data for an individual interrupt.
type InterruptData = flexible table {
    /// The cells associated with an interrupt. The size of this vector
    /// is determined by the `#interrupt-cells` property.
    1: cells vector<uint32>:MAX;
};

/// Data for an interrupt controller.
type InterruptControllerData = flexible table {
    /// This vector contains all of the interrupts discovered by the board driver.
    1: configuration vector<InterruptData>:MAX;
};

每個中斷驅動程式庫都會針對每個中斷事件發布一個節點。節點將具有下列繫結規則:

fuchsia.devicetree.node_type == INTERRUPT;
fuchsia.devicetree.phandle == <phandle of interrupt controller devicetree node>;
fuchsia.devicetree.cellN == <nth configuration cell>;

請注意,phandle 是每個裝置樹狀結構的專屬值,且應僅用於板卡驅動程式庫產生的繫結規則。

節點會發布下列 FIDL 服務:

library fuchsia.hardware.interrupt;

protocol Provider {
    /// Return the interrupt represented by this provider.
    Get(struct {}) -> (resource struct { irq zx.interrupt; }) error zx.status;
};

在大多數情況下,中斷會直接對應至實體硬體中斷,但在某些情況下 (例如 GPIO),中斷可能會進行多重處理,並涉及中介驅動程式庫。我們可能會在日後進行相關工作,以便在核心內處理這些中斷,但這類工作不在本文的討論範圍。

I2C、SPI、UART 和其他周邊匯流排

這些匯流排上的裝置會模擬為控制器裝置的子項。為判斷控制器的匯流排類型,我們會為每種支援的匯流排類型定義額外的「相容」值。舉例來說,i2c 控制器的最後相容值為 fuchsia,i2c-controller

我們將定義公車專屬的裝置樹狀結構屬性,用於填入 Fuchsia 公車驅動程式所使用的中繼資料。這些屬性可能會與其他作業系統使用的等效屬性保持一致,但確切的格式會在 //docs 中記錄。

代表 I2C/SPI/等匯流排的節點會稱為 i2c000spi000 等。請注意,雖然裝置樹狀結構只能代表這類型態的單一父項,但我們仍會為父項編號,以便與 ACPI 相容。

GPIO

GPIO 與其他資源的主要差異在於,GPIO 具有一定程度的用戶端設定。舉例來說,用戶端可能會想啟用內部上拉/下拉電阻,或是引腳可能會處於高/低電位。

GPIO 控制器節點必須具有 #gpio-cells 屬性,定義用於識別節點公開的 GPIO 的單元格數量。此外,它必須具有空白的 gpio-controller 屬性。

如果 GPIO 控制器節點沒有 compatible 字串,則 GPIO 控制器節點的父項節點會改為提供與子項節點相關的中繼資料。這適用於 SoC,其中單一邏輯「控制器」會公開多組引腳群組。

我們將定義下列中繼資料,讓控制器驅動程式瞭解每個引腳例項的預期設定。請注意,此中繼資料並非裝置樹狀結構專屬。不過,我們會定義幾個裝置樹狀結構的慣例:

  1. 最後一個設定儲存格包含 GpioConfiguration 標記。
  2. 其他儲存格會放入每個圖釘中繼資料的 data 向量。

中繼資料類型可能會如下所示:

library fuchsia.hardware.gpio;

using fuchsia.driver.framework;

/// Maximum number of properties a pin can have.
const uint32 MAX_PIN_PROPERTIES = 32;
/// Maximum number of configuration cells a driver can have.
const uint32 MAX_PIN_CELLS = 8;

/// GPIO configuration flags.
type GpioConfiguration = flexible bits {
    /// If this bit is set, GPIO is active-low. Otherwise, GPIO is active-high.
    GPIO_ACTIVE_LOW = 0x1,
    // more properties here as appropriate.
};

type GpioPinMetadata = flexible table {
    /// Properties the published device should have.
    1: expected_properties vector<fuchsia.driver.framework.NodePropertyValue>:MAX_PIN_PROPERTIES;
    /// Arbitrary, driver-specific data. This will likely encode the pin number.
    2: data vector<uint32>:MAX_PIN_CELLS;
    /// GPIO configuration flags.
    3: flags GpioConfiguration;
};

type GpioMetadata = flexible table {
    /// Standard metadata for GPIO pins.
    /// The GPIO controller driver should publish a GPIO pin node for each of these.
    1: pins vector<GpioPinMetadata>:MAX;
};

此外,GPIO 控制器通常是更大型「針腳控制器」的一部分,由單一驅動程式庫管理一組 GPIO 控制器。為支援這項功能,如果驅動程式庫不會繫結至個別 GPIO 控制器節點 (也就是沒有設定相容或其他繫結屬性),我們會將此中繼資料提供給父項節點。

每個已發布的圖釘都應具備下列屬性:

fuchsia.devicetree.node_type == GPIO;
fuchsia.devicetree.phandle == <phandle>;
fuchsia.devicetree.cellN == <nth configuration cell>;

如要使用 GPIO 的裝置樹狀結構節點,應使用類似 <name>-gpios 的屬性。這些會成為名為 gpio-<name>NNN 的片段父項。如果有多個 gpios 已命名,系統會根據索引為其指派編號。這些節點應會公開 fuchsia.hardware.gpio.Gpio 通訊協定。

如要讓驅動程式庫繫結至 GPIO,則需要繫結規則,例如:

node "gpio" {
    fuchsia.resource.name == "example";
    fuchsia.resource.index == 0; // zeroth gpio in the "example-gpios" list.
    fuchsia.hardware.gpio.Gpio == ZirconTransport;
}

電壓調節器

我們會將電壓調節器視為 GPIO,但不會向調節器驅動程式提供任何中繼資料。系統會根據屬性中標示為 -supply 的使用方式,推斷出調節器節點。

單一調節器應對應至單一裝置樹狀結構節點,因此不需要額外設定。

監管機制驅動程式應發布具有下列屬性的節點:

fuchsia.devicetree.node_type == REGULATOR;
fuchsia.devicetree.phandle == <phandle>;

供應節點只能參照單一調節器。這些片段應會公開 fuchsia.hardware.vreg.Vreg 通訊協定。

接著,規範器使用者會使用以下繫結規則:

node "regulator" {
    fuchsia.resource.name == "vdd"; // equivalent to vdd-supply in devicetree.
    fuchsia.hardware.vreg.Vreg == ZirconTransport;
}

時鐘和其他資源

這些裝置可以有多個例項。

時脈與電壓調節器非常相似,由於時鐘驅動程式應知道匯出的時鐘數量,因此不需要中繼資料。時鐘控制器節點應定義 #clock-cells,也就是用於識別時鐘裝置所需的儲存格數量。

應具備下列屬性:

fuchsia.devicetree.node_type == CLOCK;
fuchsia.devicetree.phandle == <phandle>;
fuchsia.devicetree.cellN == <nth configuration cell>;

時鐘使用者可以透過在 clocks 屬性中指定時鐘 ID 陣列,以及在 clock-names 屬性中指定選用名稱陣列,定義時鐘。

使用時鐘的裝置會具有名為 clk-<name> (如果有 clock-names) 或 clk-NNN 的片段父項,其中 NNNclocks 陣列中時鐘的索引。每個片段都會公開 fuchsia.hardware.clock.Device 通訊協定。

如要繫結至時鐘節點,驅動程式庫會使用以下繫結規則:

// If clock-names is expected:
node "clock-input" {
    fuchsia.resource.name == "input";
    fuchsia.hardware.clock.Device == ZirconTransport;
}

// If clock-names is not expected:
node "clock-input" {
    fuchsia.resource.index == 0;
    fuchsia.hardware.clock.Device == ZirconTransport;
}

端對端示例

舉例來說,我們以 vim3 USB PHY 為例。嚴格來說,Fuchsia 驅動程式會控制兩個 USB PHY 和特殊的多路器,在主機和周邊模式之間路由其中一個 PHY。

如果我們專注於這個等式中的「mux」部分,它有以下資源:

  • 一個 MMIO 區域。
  • 一個中斷。
  • 一個時鐘。

其裝置樹狀結構節點會如下所示:

/ { // Root node of the devicetree.
    // 64 bit addresses.
    #address-cells = <2>;
    #size-cells = <2>;
    #interrupt-parent = <&gic>;

    usb-mux@ffe09000 {
        compatible = "amlogic,g12b-usb-mux";
        reg = <0x0 0xffe09000 0x0 0xa0>; // MMIO region.
        interrupts = <GIC_SPI 16 INTERRUPT_MODE_EDGE_HIGH>; // Interrupt.
        clocks = <&clk CLK_G12B_USB>; // Clocks.
        clock-names = "usb"; // Clock names.
    };

    gic: interrupt-controller@ff000000 {
        compatible = "arm,gic-400";
        interrupt-controller; // This is an interrupt controller.
        #interrupt-cells = <3>; // 3 32-bit values are used to identify interrupt on this controller.
    };
};

在這個節點版面配置中 (具體來說是 usb-mux 節點),裝置樹板驅動程式會執行下列操作:

  • 請查看 reg 節點,並將 0xffe09000...0xffe090a0 中的 MMIO 區域新增至平台裝置定義。
  • 查看中斷資源,並將中斷節點新增至裝置群組,並使用「中斷」一節所述的屬性。
  • 查看時鐘資源,並將時鐘節點加入裝置群組,並使用「時鐘」一節所述的屬性。

如要繫結至這部觸控螢幕裝置,裝置驅動程式庫程式的複合繫結檔案會如下所示:

composite g12b_usb_mux;

primary node "pdev" {
    fuchsia.devicetree.first_compatible == "amlogic,g12b-usb-mux";
    fuchsia.hardware.platform.device.PDev == ZirconTransport;
}

node "clock-usb" {
    fuchsia.hardware.clock.Device == ZirconTransport;
    fuchsia.resource.name == "usb";
}

node "interrupt" {
    fuchsia.hardware.interrupt.Provider == ZirconTransport;
    fuchsia.resource.index == 0;
}

請注意,驅動程式庫看到的繫結屬性與用於比對複合物屬性時使用的屬性不同,因為我們會利用裝置群組提供的轉換 API。

實作

我們可能會在多個 CL 中導入實作此 RFC 的程式碼。實作程序本身不太可能特別複雜,因為這個階段不會將任何 API 新增至樹狀結構外 SDK。

這些 API 最終會成為驅動程式庫 SDK 的一部分,但我們首先打算樹狀結構內驗證設計,因為這裡更容易快速迭代。

成效

由於大部分的提案邏輯會在開機時發生一次,因此這個 RFC 不太可能會增加任何重大的執行階段效能負擔。

安全性考量

裝置樹是系統韌體提供或包含在 ZBI 中的二進位 Blob,本質上是系統的可信任部分。此外,驅動程式只能存取屬於其節點的資源。雖然它們可以檢查子節點的名稱和屬性,但由於系統的特性,它們無法存取子節點擁有的任何資源,因為資源存取權是由板卡驅動程式透過複合節點的片段父項明確授予。

不過,驅動程式可以剖析裝置樹狀結構中的屬性,如果編寫不當,可能會遭到濫用。具體來說,我們會提供驅動程式定義設定資料的結構定義,這些資料應包含在裝置樹狀結構中,但這段剖析程式碼可能會遭到濫用,因此我們應確保使用這類設定資料的驅動程式可輕鬆進行測試 (或模糊測試)。

板卡驅動程式庫並非 Fuchsia 平台的一部分,因此裝置樹狀結構庫或板卡驅動程式庫的任何安全性修正,都必須由該板卡驅動程式的擁有者吸收,並重新建構新的板卡驅動程式庫。

隱私權注意事項

裝置樹狀結構的存取權會受到限制,因為這項資料可能會用於建立裝置指紋。

測試

一開始,我們會使用單元測試來驗證板卡驅動程式庫的個別功能。最後,我們會使用任意裝置樹狀結構進行整合測試,以建立裝置拓樸圖。

我們也會對裝置樹剖析器進行模糊測試。

我們也會提供工具,讓您根據已知的裝置樹狀結構定義驗證裝置樹狀結構。

說明文件

我們會在 fuchsia.dev 的文件中說明 Fuchsia 如何使用裝置樹狀結構,以及我們如何支援裝置樹狀結構。具體來說,我們希望板卡擁有者瞭解如何在他們要啟動的板卡上使用裝置樹狀結構,以及我們的做法與其他作業系統的差異,以及如何實際讓裝置樹狀結構運作。

此外,我們會要求驅動程式指定要使用的 devicetree 架構,並將這些架構納入版本中。為確保說明文件符合預期,並確保裝置樹狀結構正確無誤,我們將實作結構定義驗證,以便正式版裝置樹狀結構能根據這些結構進行驗證。

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

缺點:可讀性

裝置樹狀結構比較難以閱讀。具體來說,將不同來源檔案組合在一起產生最終輸出內容的模式,表示您需要剖析所有來源檔案才能瞭解最終結果。

我們希望透過工具 (即黃金檔案) 解決這個問題,但這可能會成為使用裝置樹狀結構時的摩擦點。

替代方案:繼續使用純板卡驅動程式

我們可以繼續在電路板驅動程式中以程式輔助方式表示所有硬體設定,這需要編寫程式碼並重新建構驅動程式庫,才能表示變更。如上所述,板卡驅動程式並非可持續擴展 Fuchsia 板卡生態系統的方法。

替代做法:使用其他機制來說明硬體

我們可以使用其他資料為基礎的機制來描述硬體版面配置。相較於假設的替代方案,裝置樹的主要優點如下:

  • 硬體生態系統參與者廣泛使用且熟悉的格式。
  • 常見的構成元素 (例如中斷支援) 已清楚定義,且容易採用。
  • 我們可以利用現有的工具。

Devicetree 的主要缺點如下:

  • 沒有明確的跨作業系統標準化努力。大部分的活動都以 Linux 為主。
    • 許多現有的繫結都是專為 Linux 驅動程式庫編寫。
  • 容易遭到濫用,用於其他硬體設定 (例如產品專屬設定)。
  • 當多個裝置樹狀結構重疊並變更彼此的節點時,會造成複雜性 (例如 status = "disabled"/status = "okay" 可以停用/啟用節點)。

此外,目前尚未有任何明顯的裝置樹狀結構替代方案 (大多數作業系統都會使用裝置樹狀結構或板卡檔案來解決這個問題)。裝置樹狀結構自 1994 年推出以來,一直是描述硬體的主要方式。

替代做法:定義 Fuchsia 平台規定的穩定裝置樹狀結構定義

我們可以定義單一裝置樹狀結構定義,並由單一通用「裝置樹狀結構」板卡驅動程式庫程式支援,並將其設為使用裝置樹狀結構的官方方式。

這將使我們更接近目標,即為所有使用裝置樹狀結構的系統提供單一 Fuchsia 映像檔,但裝置樹狀結構的差異很大 (與 ACPI 等相比),因此這項工作規模龐大,可能需要大量的演進。

這份 RFC 並未排除日後採用這類結構定義的可能性,但我們認為,目前採用裝置樹狀結構最實際的方法就是上述方法。

替代做法:透過更廣泛的生態系統,穩定裝置樹系繫結

我們可以與其他使用裝置樹狀結構的團隊合作,在更廣泛的生態系統中將繫結標準化。

這項工作可能需要好幾年的時間,且不在本 RFC 的範圍內。由於絕大多數裝置樹狀結構並非為 Fuchsia 編寫,因此 Fuchsia 不太可能能主導這項工作。

替代方案:自行推出 DSL

我們可以不使用裝置樹,而是自行推出可與 FIDL 整合的 DSL,並且繫結規則。這可能是我們日後想做的事,但在撰寫本文時,我們並沒有具體的實作想法,不知道這個 DSL 會是什麼樣子。如果我們決定日後需要 DSL,實作此 RFC 所學到的經驗,很可能會對其設計產生重大影響。

既有技術與參考資料