RFC-0192:Fuchsia 上的设备树

RFC-0192:Fuchsia 上的设备树
状态已接受
领域
  • 设备
说明

使用设备树描述硬件布局的策略

问题
Gerrit 更改
  • 706886
作者
审核人
提交日期(年-月-日)2022-08-03
审核日期(年-月-日)2022-10-01

总结

扁平化设备树(“FDT”或简称“设备树”)是一种被广泛用于描述主板上硬件布局的格式。它们的用途与 ACPI 大致相似,但它们在抽象级别低得多的抽象级别运行,这会使操作系统变得更加复杂。FDT 规范定义了二进制设备树 blob(“DTB”)格式,以及编译设备树 blob 的源格式(“DTS”)。

此 RFC 提出了一种实用方法,用于在 Fuchsia 中引入对设备树的支持,而无需将设备树(其布局或二进制格式)作为 ABI 进行提交。设备树的确切 ABI 由板驱动程序在它们与固件之间定义。另请注意,此 RFC 仅涉及板驱动程序对设备树的使用。当内核解析设备树时或当内核解析设备树时,会有一条单独的 RFC 描述设备树的格式。

设计初衷

单靠板驱动程序无法持续增强 Fuchsia 的硬件支持,原因如下:

  1. 我们希望能够在不重新组装/重新构建 Fuchsia 映像的情况下对硬件配置进行迭代。
  2. 设备树被开发者广泛使用,我们希望满足开发者的需求。设备树还有一个相对可靠的生态系统。
  3. 目前的编写方式使其不适合多个组织之间的协作。
  4. 它们在固件和开发板驱动程序之间产生重复工作,以检测系统中的可用硬件。
  5. 在支持多个相关开发板(即共享 SoC 或 SoC 系列)时,它们不能很好地扩展。
    • 如需支持多个开发板,必须在整个板驱动程序中添加条件,或具有多个开发板驱动程序。
    • 虽然可以采用干净的方式执行此操作,但最终生成意大利面代码要比生成设备树容易得多。
    • 借助设备树,您可以更轻松地通过单个紫红色映像支持多个开发板(但请注意,在此阶段,我们并不打算使用“通用”紫红色映像)。

设备树提供了解决这些问题的解决方案,它提供硬件配置单一可信来源,易于与系统其余部分分开操作(易于通过启动固件和启动开发组进行修改),并且易于组合(允许在基于相同 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。

设计

本文档中的“必须”“不得”“必需”“会”“不会”“应”“不应”“建议”“可以”和“非强制”等关键字应按 IETF RFC 2119 中的说明进行解释。

Devicetree 的作用

设备树仅用于描述硬件布局信息。产品配置必须通过 Product Assembly 完成。设备树应仅包含关于主板的真实信息(无论其运行的产品为何),而不应配置可能会变化的驱动程序的行为,例如预分配的内存缓冲区大小或分区映射。

设备树与 ACPI

相较于设备树,我们更倾向于使用 ACPI。如果开发板支持 ACPI,则应使用 ACPI 启动它。设备树不得在支持 ACPI 的开发板上使用。 这是因为 Fuchsia 为每个受支持的架构提供了单个 ACPI 开发板驱动程序。ACPI 提供的抽象级别越高,其标准化程度也越高,因此提供支持起来要容易得多。

兼容性

我们的设备树绑定不会尝试保持与 Linux 或任何其他操作系统的兼容性,尤其是对于设备驱动程序绑定。这只是因为与 ACPI 不同,设备树没有广泛标准化,并且绑定的确切布局和含义因操作系统版本而异。不过,我们将采用规范中所述的源格式和二进制格式。

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 平台实现

我们将为希望实现这组绑定的板级驱动程序提供一个库。此库将利用树中的现有设备树解析器。此外,我们还将实现一个利用此库启动实际系统的参考开发板驱动程序和设备树。前者将是 SDK 的一部分并存在于树中,但后者最终可能会从树中移出。

设备树的可读性

对设备树的一个批评是源格式可能非常不透明,因为设备树编译器不支持命名常量。解决此问题的一种常用方法是,使用包含 #define 语句的 C 头文件(用于声明人类可读的常量名称),然后添加这些头文件,以便在设备树源代码中使用它们。我们将在 fuchsia.git 中实现此方法,未来我们还将支持通过绑定库生成此类头文件。

从广义上讲,支持与设备树搭配使用的驱动程序将有一个目录,其中包含供设备树源文件使用的标头。这些头文件将定义引用驱动程序公开的资源时使用的值 - GPIO 驱动程序可能具有 PULL_UPPULL_DOWN 等的常量。然后,设备树源文件构建规则将依赖于它们使用的驱动程序,这些驱动程序将用于验证设备树(请参阅文档),并添加到提供给 C 预处理器的 include 路径中。

设备树的可审核性

为了提高设备树的可审核性,我们还将引入设备树“golden”文件。这些黄金文件将是将设备树源代码编译为二进制文件,然后还原为源代码的输出,这样一来,源代码更改对最终设备树的影响就显而易见。在编译板驱动程序和设备树时,我们将编译和反编译设备树源代码,如果输出结果与黄金状态不同,构建就会失败。

例如,当多个开发板包含通用设备树源文件(例如,由 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 节中定义的标准属性中,我们可能支持:compatiblephandlestatus#address-cells#size-cellsregranges。我们省略了 virtual-reg,因为引导加载程序跳转到内核时,MMU 的状态与板驱动程序无关(因为它位于用户空间中)。我们省略了 dma-ranges 和 dma-coherent,因为这些属性在 Fuchsia 上没有直接等效项。

在 Fuchsia 上:

  • compatible - 兼容数组中的第一个值将作为绑定属性 fuchsia.devicetree.first_compatible 公开。将来,当有更复杂的绑定系统(具有优先级)时,可能会使用其他值。
    • 此外,我们将允许节点通过命名空间型属性定义自己的绑定属性(例如,bind,<prop-name> = <value> 将对应于具有值为 value 的绑定属性 prop-name)。
  • phandle - 用于唯一标识设备树中的设备节点。由设备树编译器生成,仅在运行时使用。
  • status - 可在开发板驱动程序中使用,以控制是否发布节点。我们将调查在实现此 RFC 期间从我们支持的绑定中省略 status 的必要性,如果这能够显著提高设备树源文件的清晰度,则可以选择忽略它。
    • 具体而言,我们可能需要建议将设备树源文件组合在一起(将单个 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-cells 属性,用于定义用于标识节点公开的 GPIO 的单元数量。此外,还必须具有 gpio-controller 属性,该属性为空。

如果 GPIO 控制器节点没有 compatible 字符串,则系统会改为向 GPIO 控制器节点的父级提供与其子节点相关的元数据。这适用于单个逻辑“控制器”公开多组 PIN 码库的 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 的 fragment 父级。如果指定了多个 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>;

一个供电节点只能引用一个调节器。这些 fragment 应公开 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 属性中指定时钟标识符数组并在 clock-names 属性中指定可选名称数组来定义时钟。

使用时钟的设备将有名为 clk-<name>(如果存在 clock-names)或 clk-NNN 的 fragment 父级,其中 NNNclocks 数组中时钟的索引。其中每个 fragment 都将公开 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。

如果我们具体关注此等式的“多路复用器”部分,它具有以下资源:

  • 一个 MMIO 区域。
  • 1 个中断。
  • 一个时钟。

其设备树节点应如下所示:

/ { // 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 的代码。 实现过程本身不太可能会特别复杂,因为在此阶段,系统不会向树外 SDK 添加任何 API。

最终,这些 API 将成为驱动程序 SDK 的一部分,但首先,我们计划在树内证明设计,这样可以更轻松地进行快速迭代。

性能

此 RFC 不太可能增加任何明显的运行时性能开销,因为建议的大多数逻辑在启动时发生一次。

安全注意事项

设备树是由系统固件提供或包含在 ZBI 中的二进制 blob,本质上是系统的可信部分。此外,驱动程序只能访问属于其节点的资源。虽然他们可以检查子节点的名称和属性,但由于系统性质,他们无法访问其子节点拥有的任何资源 - 资源访问权限是由板驱动程序通过复合节点的 fragment 父级明确授予的。

不过,驱动程序将能够解析设备树中的属性,如果编写不小心,可能会使它们容易遭到利用。具体而言,我们将为驱动程序提供相关功能,使其能够为希望包含在设备树中的配置数据定义架构,但此解析代码可能容易被利用,因此我们应确保能够轻松地测试使用此类配置数据的驱动程序(或对其进行模糊测试)。

开发板驱动程序不是 Fuchsia 平台的一部分,因此,设备树库或开发板驱动程序的任何安全修复程序都需要由上述开发板驱动程序的所有者提取,并且需要重新构建新的开发板驱动程序。

隐私注意事项

对设备树的访问将受到限制,因为它可用于对设备进行指纹识别。

测试

最初,我们将使用单元测试来验证开发板驱动程序的各项功能。最终,我们将使用任意设备树进行集成测试,以创建设备拓扑。

我们还会对设备树解析器进行模糊测试。

我们还将提供相关工具,用于根据已知的设备树架构验证设备树。

文档

我们将在 fuchsia.dev 上的文档中记录 Fuchsia 使用设备树和支持设备树的方法。具体而言,我们希望董事会所有者了解如何在他们想要构建的开发板上使用设备树 - 了解我们的方法与其他操作系统有何不同,以及如何实际操作。

此外,我们还要求驱动程序指定它们要使用的设备树架构,并将其包含在 build 中。为确保文档符合预期和设备树正确性,我们将实现架构验证,以便根据这些架构验证生产设备树。

缺点、替代方案和未知情况

缺点:可读性

设备树相对来说较难读取。具体而言,将不同源文件组合在一起以生成最终输出的模式意味着,您需要解析所有源文件才能理解最终结果。

我们希望通过工具(即黄金文件)解决此问题,但在使用设备树时,这可能会成为一个阻碍。

替代方案:继续使用纯电路板驱动程序

我们可以继续在板驱动程序中以编程方式表示所有硬件配置,这需要编写代码并重新构建驱动程序,才能表达更改。如上所述,单板驱动程序无法持续扩展 Fuchsia 的板级生态系统。

替代方案:使用其他机制来描述硬件

我们可以使用另一种基于数据的机制来描述硬件布局。与假设的替代方案相比,设备树的主要优势包括:

  • 硬件生态系统的参与者广泛使用且熟悉。
  • 常用构建块(例如中断支持)具有明确定义,并且易于采用。
  • 我们能够利用现有工具。

设备树的主要缺点包括:

  • 没有明确的跨操作系统标准化工作。大多数活动都在 Linux 上居中。
    • 许多现有绑定专为 Linux 驱动程序编写。
  • 不仅仅是硬件配置(例如产品专用配置),也容易滥用。
  • 多个设备树叠加并更改彼此的节点时的复杂性(例如 status = "disabled"/status = "okay" 可以停用/启用节点)。

此外,目前还没有发现设备树的明显替代方案(大多数操作系统都使用设备树或板级文件来解决此问题)。设备树自 1994 年问世以来,已被深深作为描述硬件的主要方式。

替代方案:定义由 Fuchsia 平台强制执行的稳定的设备树架构

我们可以定义一个由单个通用“设备树”板驱动程序支持的单一设备树架构,并使其成为使用设备树的官方方式。

这将使我们更接近为使用设备树的所有系统使用单个 Fuchsia 映像的目标,但设备树中的广泛差异(与 ACPI 等相比)使得这项工作是一项非常庞大的工作,并且可能需要进行大量演变。

此 RFC 并不排除将来采用此类架构,但我们认为目前采用设备树的最实用方法是上面介绍的方法。

替代方案:通过更广泛的生态系统稳定设备树绑定

我们可以与使用设备树的其他群组合作,在更广泛的生态系统中实现绑定标准化。

这项工作可能需要多年的努力,超出了本 RFC 的讨论范围。仅仅因为绝大多数设备树都不是针对 Fuchsia 编写的,Fuchsia 不太可能能够主导这项工作。

替代方案:构建我们自己的 DSL

我们可以推出自己的 DSL,它与 FIDL 和绑定规则集成,而不是使用设备树。我们未来可能想要这样做,但在撰写本文时,还没有关于此 DSL 的具体实现想法。如果我们确定将来有必要使用 DSL,那么实现此 RFC 获得的经验可能对于影响其设计具有重要价值。

早期技术和参考资料