| RFC-0192:Fuchsia 上的裝置樹狀架構 | |
|---|---|
| 狀態 | 已接受 |
| 區域 |
|
| 說明 | 使用裝置樹狀結構描述硬體配置的策略 |
| 問題 | |
| Gerrit 變更 | |
| 作者 | |
| 審查人員 | |
| 提交日期 (年-月-日) | 2022-08-03 |
| 審查日期 (年-月-日) | 2022-10-01 |
摘要
扁平化裝置樹狀結構 (「FDT」或簡稱「裝置樹狀結構」) 是一種廣泛使用的格式,可描述主機板上的硬體配置。雖然用途與 ACPI 大致相似,但運作的抽象層級低得多,因此會將更多複雜性推入作業系統。FDT 規格定義了二進位裝置樹狀結構 BLOB (「DTB」) 格式,以及編譯裝置樹狀結構 BLOB 的來源格式 (「DTS」)。
這項 RFC 提案採用實用方法,在 Fuchsia 中導入對裝置樹狀結構的支援,但不會將裝置樹狀結構 (無論是版面配置或二進位格式) 視為 ABI。而是由主機板驅動程式自行定義裝置樹狀結構的確切 ABI,並與韌體共用。另請注意,這項 RFC 僅與主機板驅動程式使用裝置樹狀結構有關。如果或當核心剖析裝置樹狀結構時,將有另一份 RFC 說明該裝置樹狀結構的格式。
提振精神
單靠主機板驅動程式無法持續擴大 Fuchsia 的硬體支援,原因如下:
- 我們希望能夠疊代硬體設定,而不必重新組裝/重建 Fuchsia 映像檔。
- 開發人員廣泛使用裝置樹狀結構,我們希望在開發人員所在之處提供支援。裝置樹狀結構也有相對健全的生態系統。
- 目前撰寫的方式不適合多個機構之間的協作。
- 這會導致韌體和主機板驅動程式庫程式重複偵測系統中的可用硬體。
- 支援多個相關開發板時 (即共用 SoC 或 SoC 系列),這些檔案無法妥善擴充。
- 如要支援多個開發板,您必須在整個開發板驅動程式庫中新增條件,或使用多個開發板驅動程式。
- 雖然可以採用乾淨的方式執行這項操作,但相較於裝置樹狀結構,您更容易產生義大利麵式程式碼。
- 有了裝置樹狀結構,就能更輕鬆地使用單一 Fuchsia 映像檔支援多個開發板 (但請注意,我們目前並非以「通用」Fuchsia 映像檔為目標)。
Devicetree 可提供硬體設定的單一事實來源,方便與系統的其餘部分分開操作 (方便開機韌體和負責啟動的團隊修改),也方便組合 (允許在以相同 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 的說明解讀。
裝置樹狀結構的角色
裝置樹狀結構僅用於說明硬體配置資訊。產品設定必須透過產品組裝完成。無論主機板執行的產品為何,裝置樹狀結構都只應包含主機板的真實資訊,而非設定可能有所不同的驅動程式行為,例如預先分配的記憶體緩衝區大小或分割區對應。
裝置樹狀結構與 ACPI
我們偏好使用 ACPI,而非裝置樹狀結構。如果主機板支援 ACPI,就應使用 ACPI 開機。如果主機板支援 ACPI,就不得使用裝置樹狀結構。這是因為 Fuchsia 會為每個支援的架構提供單一 ACPI 開發板驅動程式庫。ACPI 提供的抽象層級較高,且標準化程度高,因此更容易支援。
相容性
我們的裝置樹狀結構繫結不會嘗試與 Linux 或任何其他 OS 維持相容性,尤其是裝置驅動程式庫繫結。這是因為與 ACPI 不同,裝置樹狀結構並未廣泛標準化,且繫結的確切版面配置和意義會因 OS 版本而異。不過,我們會採用規格中說明的來源和二進位格式。
Fuchsia 平台不會嘗試指定裝置樹狀結構的確切格式,也不會嘗試使用單一主機板驅動程式庫程式支援所有主機板,而是會根據規格定義一組繫結,提供常見功能 (例如中斷、GPIO、匯流排) 的支援。使用裝置樹狀結構的板載驅動程式「應」支援本 RFC 中定義的繫結,但「可」視需要定義自己的繫結,以支援額外功能。
我們也會提供方法,讓裝置樹狀結構指定要以哪個主機板驅動程式庫為目標 (例如透過根節點的屬性,如 fuchsia,board-driver = "vim3-devicetree"),主機板驅動程式應使用這個方法,確保剖析的裝置樹狀結構相容。
此外,我們也會定義主機板驅動程式必須向下游驅動程式公開的介面。這個介面與 ACPI 介面非常相似,我們會盡量讓 ACPI 和裝置樹狀結構保持一致,以便驅動程式在兩者之間真正保持獨立。
將裝置樹狀結構傳遞至 Fuchsia。
我們已有類型為「ZBI_TYPE_DEVICETREE」的 ZBI 項目。這個 ZBI 項目包含裝置樹狀結構 Blob。我們唯一需要進行的變更,就是更新說明文件,反映主機板驅動程式庫可能會取用此項目。
開發板「可以」選擇使用裝置樹狀結構。如果是這種情況,系統啟動載入程式應該會知道這項事實,且啟動載入程式「應」將裝置樹狀結構做為 ZBI_TYPE_DEVICETREE 項目傳遞。如有需要,主機板「可能」會直接在 ZBI 中納入裝置樹狀結構 (例如在啟動期間,啟動載入程式內建支援 ZBI 之前)。
一般來說,啟動載入程式「應該」從非揮發性儲存空間載入裝置樹狀結構、驗證其真實性,並在執行階段將其附加至 ZBI。不過,如果需要,他們「可以」使用替代機制 (例如編譯到系統啟動載入程式中),且「可以」視情況略過驗證 (例如開發人員主機板)。
Fuchsia 平台實作
我們將為想實作這組繫結的開發板驅動程式提供程式庫。這個程式庫會利用樹狀結構中的現有裝置樹狀結構剖析器。此外,我們將實作參考板驅動程式庫和裝置樹狀結構,利用這個程式庫啟動實際系統。前者會成為 SDK 的一部分,並位於樹狀結構中,但後者最終可能會移出樹狀結構。
裝置樹狀結構的可讀性
裝置樹狀結構的一項缺點是來源格式可能相當不透明,因為裝置樹狀結構編譯器不支援具名常數。常見的解決方法是使用包含 #define 陳述式的 C 標頭檔,為常數宣告可讀取的名稱,然後加入這些標頭檔,以便在裝置樹狀結構來源中使用。我們會在 fuchsia.git 中實作這個方法,日後也會支援從繫結程式庫產生這類標頭檔。
一般來說,支援搭配裝置樹狀結構使用的驅動程式,會包含一個目錄,其中含有供裝置樹狀結構來源檔案使用的標頭。這些標頭會定義參照驅動程式庫公開資源時使用的值,例如 GPIO 驅動程式庫可能會有 PULL_UP、PULL_DOWN 等常數。裝置樹狀結構來源檔案建構規則隨後會依據使用的驅動程式而定,這些規則會用於驗證裝置樹狀結構 (請參閱「說明文件」),也會新增至提供給 C 前置處理器的 include 路徑。
裝置樹狀結構的可審查性
為方便審查裝置樹狀結構,我們也會推出裝置樹狀結構「黃金」檔案。這些黃金檔案是將裝置樹狀結構來源編譯為二進位檔,然後再編譯回原始碼的輸出內容,因此原始碼變更對最終裝置樹狀結構的影響一目瞭然。編譯主機板驅動程式庫和裝置樹狀結構時,我們會編譯及反編譯裝置樹狀結構來源,如果輸出內容與黃金標準不同,就會導致建構失敗。
舉例來說,如果多個開發板都包含通用的裝置樹狀結構來源檔案 (例如 SoC 定義的檔案),就適合使用這項功能。審查人員可能無法立即瞭解變更「共用」裝置樹狀結構檔案的影響。使用黃金檔案時,每個裝置樹狀結構的最終輸出內容一目瞭然。
節點數
每個裝置樹狀結構節點都會對應至 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 節定義的標準屬性中,我們可能會支援下列屬性:compatible、phandle、status、#address-cells、#size-cells、reg、ranges。我們省略 virtual-reg,因為開機載入程式跳至核心時的 MMU 狀態與主機板驅動程式庫無關 (因為該狀態位於使用者空間)。我們省略了 dma-ranges 和 dma-coherent,因為這些屬性在 Fuchsia 上沒有直接對應的項目。
在 Fuchsia 上:
- compatible - 適用陣列中的第一個值會公開為繫結屬性
fuchsia.devicetree.first_compatible。日後推出更精密的繫結系統 (含優先順序) 時,可能會使用其他值。- 此外,我們也允許節點定義自己的繫結屬性,可能透過命名空間屬性 (例如
bind,<prop-name> = <value>會對應至繫結屬性prop-name,值為value)。
- 此外,我們也允許節點定義自己的繫結屬性,可能透過命名空間屬性 (例如
- phandle - 用於在裝置樹狀結構中,正確識別裝置節點。由裝置樹狀結構編譯器產生,且僅在執行階段使用。
- status - 可在主機板驅動程式庫中使用,控制是否發布節點。在實作這項 RFC 時,我們會調查是否要從支援的繫結中省略狀態,如果省略狀態能大幅提升裝置樹狀結構來源檔案的清晰度,我們可能會選擇省略。
- 具體來說,我們可能會鼓勵將裝置樹狀結構來源檔案組合在一起 (將單一 SoC 定義分割到多個檔案中,並只在最終板載檔案中加入必要的檔案),而不是將這些檔案納入一個檔案中,並透過 status 屬性停用/啟用 IP 區塊。
- #address-cells、#size-cells - 將在主機板驅動程式庫中使用,判斷其他值的大小。
- reg - 用於可從樹狀結構根目錄定址的節點,板載驅動程式庫會使用這個節點判斷實體記憶體區域。這些記憶體區域會透過
GetMmio(int index)FIDL 呼叫提供給子節點,可能透過平台匯流排驅動程式提供。 - 範圍 - 用於主機板驅動程式庫,判斷子項位址範圍如何對應至父項。
中斷
中斷繫結會如規格第 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 等匯流排的節點會稱為 i2c000、spi000 等。請注意,即使裝置樹狀結構只能代表這類型的單一父項,我們仍會為父項編號,以維持與 ACPI 的相容性。
GPIO
GPIO 與其他資源的主要差異在於,GPIO 具有一定數量的用戶端設定。舉例來說,用戶端可能想啟用內部上拉/下拉電阻,或是接腳可能為高/低電位。
GPIO 控制器節點必須具有 #gpio-cells 屬性,定義用於識別節點公開 GPIO 的儲存格數量。此外,該物件必須具有空白的 gpio-controller 屬性。
如果 GPIO 控制器節點沒有 compatible 字串,系統會改為向 GPIO 控制器節點的父項提供與子項節點相關的中繼資料。適用於單一邏輯「控制器」公開多個針腳組的 SoC。
我們會定義下列中繼資料,讓控制器驅動程式瞭解每個插腳執行個體預期的設定。請注意,這項中繼資料並非裝置樹狀結構專用。不過,我們會為裝置樹狀結構定義幾項慣例:
- 最後一個設定格包含
GpioConfiguration標記。 - 其他儲存格則會放入每個圖釘中繼資料的
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,其中 NNN 是 clocks 陣列中時鐘的索引。每個片段都會公開 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,以及一個特殊的 MUX,可在主機和周邊模式之間路由傳輸其中一個 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 區域新增至平台裝置的定義。 - 請參閱中斷資源,並將中斷節點新增至裝置群組,其中包含「interrupts」部分所述的屬性。
- 請參閱時鐘資源,並將時鐘節點新增至裝置群組,其中包含「時鐘」一節所述的屬性。
如要繫結至這個觸控螢幕裝置,裝置驅動程式庫程式的複合繫結檔案會如下所示:
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 使用裝置樹狀結構的方式,以及我們支援裝置樹狀結構的方法。具體來說,我們希望主機板擁有者瞭解如何在嘗試啟動的主機板上使用裝置樹狀結構,瞭解我們的方法與其他作業系統的不同之處,以及如何實際運作。
此外,我們也會要求驅動程式指定預期使用的裝置樹狀結構架構,並將其納入建構作業。為確保文件符合預期,且裝置樹狀結構正確無誤,我們將實作結構定義驗證,以便根據這些結構定義驗證正式版裝置樹狀結構。
缺點、替代方案和未知事項
缺點:可讀性
相較之下,裝置樹狀結構較難解讀。特別是,將不同來源檔案組合在一起以產生最終輸出的模式,表示您需要剖析所有來源檔案,才能瞭解最終結果。
我們希望透過工具 (即黃金檔案) 解決這個問題,但使用裝置樹狀結構時,這可能仍會是摩擦點。
替代方案:繼續使用純主機板驅動程式
我們可以繼續在主機板驅動程式中以程式輔助方式表示所有硬體設定,但這需要編寫程式碼並重建驅動程式庫,才能表示變更。如上所述,主機板驅動程式並非永續做法,無法持續擴展 Fuchsia 的主機板生態系統。
替代方案:使用其他機制描述硬體
我們可以採用其他資料機制來描述硬體配置。相較於假設的替代方案,裝置樹狀結構的主要優點如下:
- 硬體生態系統的參與者廣泛使用且熟悉。
- 常見的建構區塊 (例如中斷支援) 定義明確,且容易採用。
- 我們能夠運用現有工具。
裝置樹狀結構的主要缺點如下:
- 沒有明確的跨作業系統標準化措施。大多數活動都以 Linux 為中心。
- 許多現有繫結僅適用於 Linux 驅動程式庫。
- 除了硬體設定外,也容易遭到濫用 (例如產品專屬設定)。
- 多個裝置樹狀結構重疊並變更彼此節點時的複雜度 (例如
status = "disabled"/status = "okay"可以停用/啟用節點)。
此外,目前也沒有明顯的替代方案 (大多數作業系統都使用裝置樹狀結構或主機板檔案來解決這個問題)。裝置樹狀結構自 1994 年以來就已存在,並已成為描述硬體的主要方式。
替代方案:定義穩定的裝置樹狀結構結構定義,Fuchsia 平台會強制執行
我們可以定義單一裝置樹狀結構架構,由單一通用「裝置樹狀結構」板載驅動程式庫支援,並將其設為使用裝置樹狀結構的正式方式。
這樣一來,我們就能更接近為所有使用裝置樹狀結構的系統提供單一 Fuchsia 映像檔的目標,但與 ACPI 等項目相比,裝置樹狀結構的差異極大,因此這項工作非常龐大,可能需要大量演進。
這項 RFC 並未排除日後採用這類結構定義,但我們認為目前採用裝置樹狀結構最實際的做法,就是上述做法。
替代方案:透過更廣泛的生態系統穩定裝置樹狀結構繫結
我們可以與使用裝置樹狀結構的其他群組合作,在更廣泛的生態系統中標準化繫結。
這項工作可能需要多年時間,超出本 RFC 的範圍。Fuchsia 應該無法主導這項工作,因為絕大多數的裝置樹狀結構都不是為 Fuchsia 編寫。
替代方案:自行推出 DSL
我們可以推出自己的 DSL,與 FIDL 和繫結規則整合,而不使用裝置樹狀結構。這可能是我們日後想做的事,但撰寫本文時,我們還沒有具體的實作想法,不知道這個 DSL 會是什麼樣子。如果我們日後決定需要 DSL,實作這項 RFC 的經驗應該會對 DSL 設計產生寶貴影響。
既有技術和參考資料
- Linux 和裝置樹狀結構 - Linux 如何使用裝置樹狀結構的總覽。
- ARM 的裝置樹狀結構 - 2009 年的演講,當時 Linux 正在考慮採用 ARM 的裝置樹狀結構。
- 裝置樹狀結構:過去、現在、未來 - 2019 年的演講,內容是關於 Linux 上的裝置樹狀結構狀態。
- devicetree.org - devicetree 規格組織。
- ACPI 與 DT - 討論如何在 Linux 中統一 ACPI 和裝置樹狀結構介面。