在驱动程序加载失败时进行调试

本指南介绍了在 Fuchsia 系统中无法加载新驱动程序时调试该驱动程序的最佳实践。

检查您的驱动程序当前是否在系统中运行

在 Fuchsia 中,当驱动程序与表示硬件或虚拟设备的节点匹配时,该驱动程序便会在系统中加载。匹配和加载后,驱动程序便会开始运行,并为系统中的其他组件提供服务。

如需查看驱动程序是否已在 Fuchsia 系统中加载(即当前正在运行),请运行以下命令:

ffx driver list --loaded

此命令会输出系统中加载的驱动程序列表,例如:

$ ffx driver list --loaded
fuchsia-boot:///#meta/bus-pci.cm
fuchsia-boot:///#meta/fvm.cm
fuchsia-boot:///#meta/hid.cm
fuchsia-boot:///#meta/intel-rtc.cm
fuchsia-boot:///#meta/netdevice-migration.cm
fuchsia-boot:///#meta/network-device.cm
fuchsia-boot:///#meta/pc-ps2.cm
fuchsia-boot:///#meta/platform-bus-x86.cm
fuchsia-boot:///#meta/platform-bus.cm
fuchsia-boot:///#meta/ramdisk.cm
fuchsia-boot:///#meta/sysmem.cm
fuchsia-boot:///#meta/virtio_block.cm
fuchsia-boot:///#meta/virtio_ethernet.cm
fuchsia-pkg://fuchsia.com/virtual_audio#meta/virtual_audio_driver.cm
fuchsia-pkg://bazel.pkg.component/qemu_edu#meta/qemu_edu.cm
fuchsia-boot:///#meta/block.core.cm
fuchsia-boot:///#meta/intel-i2c-dfv2.cm

或者,如果您知道确切的驱动程序组件,也可以使用 ffx component show 命令查看组件的状态,例如:

$ ffx component show intel-i2c-dfv2
               Moniker: /bootstrap/boot-drivers:root.sys.platform.pt.pci.00_15_2.composite
                   URL: fuchsia-boot:///#meta/intel-i2c-dfv2.cm
                  Type: CML dynamic component
       Component State: Resolved
 Incoming Capabilities: fuchsia.boot.Items
                        fuchsia.driver.compat.Service
                        fuchsia.logger.LogSink
                        pkg
  Exposed Capabilities: diagnostics
                        fuchsia.driver.compat.Service
       Execution State: Running
          Start reason: Instance is in a single_run collection
 Outgoing Capabilities: fuchsia.driver.compat.Service

如果您发现系统未加载您的驱动程序,请参阅下一部分,了解您可以采取哪些步骤来调试问题。

调试的最佳实践

在编写新 Fuchsia 驱动程序的初始阶段,您首先需要确保新组件在 Fuchsia 系统中被识别为驱动程序。该组件在 Fuchsia 系统中列为驱动程序后,您就可以开始编写绑定规则,以便驱动程序可以绑定到系统中表示目标设备的特定节点。将驱动程序绑定到目标节点后(因而驱动程序在系统中成功加载),您就可以继续进行下一开发环节,即开始为驱动程序实现功能。

调试未能在 Fuchsia 系统中加载的驱动程序时,请考虑以下步骤:

  1. 检查组件清单
  2. 向驱动程序框架注册驱动程序
  3. 验证绑定规则是否正确

1. 检查组件清单

如需让 Fuchsia 系统将组件视为驱动程序,必须在组件清单 (.cml) 中将该组件的 runner 字段设置为 driver,例如:

    program: {
        runner: 'driver',
        ...
    }

2. 向驱动程序框架注册驱动程序

接下来,确认您的组件已在 Fuchsia 系统中列为驱动程序。

为了让某个组件被识别为驱动程序,您需要在 Fuchsia 系统中明确地将组件注册为驱动程序。如果某个组件在系统中未显示为驱动程序,则表示驱动程序框架不知道该组件,因此系统永远不会考虑将此类组件用于驱动程序绑定。因此,在 Fuchsia 系统中以驱动程序形式显示新组件应该是编写新驱动程序时的第一个里程碑。

要在 Fuchsia 系统中将组件注册为驱动程序,请执行以下操作:

  1. 将 Fuchsia 软件包(包含驱动程序组件)上传到 Fuchsia 软件包服务器

  2. 在系统中将该组件注册为驱动程序:

    ffx driver register <URL>
    

    URL 替换为 Fuchsia 软件包服务器中的组件网址,例如:

    ffx driver register fuchsia-pkg://fuchsia.com/my_example#meta/my_new_driver.cm
    
  3. 查看系统中当前注册(但不一定正在运行)的驱动程序列表:

    ffx driver list
    

    此命令会输出类似于以下内容的输出:

    $ ffx driver list
    fuchsia-boot:///#meta/block.core.cm
    fuchsia-boot:///#meta/bus-pci.cm
    fuchsia-boot:///#meta/fvm.cm
    fuchsia-boot:///#meta/hid-input-report.cm
    fuchsia-boot:///#meta/hid.cm
    fuchsia-boot:///#meta/intel-rtc.cm
    fuchsia-boot:///#meta/netdevice-migration.cm
    fuchsia-boot:///#meta/network-device.cm
    fuchsia-boot:///#meta/pc-ps2.cm
    fuchsia-boot:///#meta/platform-bus-x86.cm
    fuchsia-boot:///#meta/platform-bus.cm
    fuchsia-boot:///#meta/ramdisk.cm
    fuchsia-boot:///#meta/sysmem.cm
    fuchsia-boot:///#meta/virtio_block.cm
    fuchsia-boot:///#meta/virtio_ethernet.cm
    fuchsia-boot:///#meta/zxcrypt.cm
    fuchsia-pkg://fuchsia.com/virtual_audio#meta/virtual_audio_driver.cm
    fuchsia-pkg://fuchsia.com/my_example#meta/my_new_driver.cm
    

    验证新驱动程序组件是否显示在此列表中。

3. 验证绑定规则是否正确

最后,开始检查驱动程序的绑定规则。

驱动程序的绑定规则决定它可以在 Fuchsia 系统中绑定到哪些节点。驱动程序框架仅在驱动程序与系统中特定节点的节点属性匹配时才会加载驱动程序。如果您的驱动程序已在系统中注册,但未加载(因此未运行),请检查驱动程序的绑定规则,并验证它们是否已正确写入以匹配 Fuchsia 系统中目标节点的绑定属性。

如需查看 Fuchsia 系统中的所有节点及其节点属性,请运行以下命令:

ffx driver list-devices -v

此命令会输出类似于以下内容的输出:

$ ffx driver list-devices -v
...
Name : I2C2
Moniker : root.sys.platform.pt.acpi.I2C2
Driver : None
6 Properties
[ 1/ 6] : Key fuchsia.BIND_ACPI_ID Value 0x000034
[ 2/ 6] : Key fuchsia.BIND_PCI_TOPO Value 0x0000aa
[ 3/ 6] : Key fuchsia.BIND_ACPI_BUS_TYPE Value 0x000001
[ 4/ 6] : Key "fuchsia.hardware.acpi.Device" Value true
[ 5/ 6] : Key fuchsia.BIND_PROTOCOL Value 0x00001e
[ 6/ 6] : Key "fuchsia.platform.DRIVER_FRAMEWORK_VERSION" Value 0x000002
...
Name : 00_15_2
Moniker : root.sys.platform.pt.pci.00_15_2
Driver : None
9 Properties
[ 1/ 9] : Key fuchsia.BIND_PROTOCOL Value 0x00001f
[ 2/ 9] : Key fuchsia.BIND_PCI_VID Value 0x008086
[ 3/ 9] : Key fuchsia.BIND_PCI_DID Value 0x009d62
[ 4/ 9] : Key fuchsia.BIND_PCI_CLASS Value 0x000011
[ 5/ 9] : Key fuchsia.BIND_PCI_SUBCLASS Value 0x000080
[ 6/ 9] : Key fuchsia.BIND_PCI_INTERFACE Value 0x000000
[ 7/ 9] : Key fuchsia.BIND_PCI_REVISION Value 0x000021
[ 8/ 9] : Key fuchsia.BIND_PCI_TOPO Value 0x0000aa
[ 9/ 9] : Key "fuchsia.platform.DRIVER_FRAMEWORK_VERSION" Value 0x000002
...

调试绑定规则时,建议的做法是直观检查此命令的输出,以确保您的 Fuchsia 系统包含具有正确节点属性的节点。另请注意,一个节点只能有一个驱动程序绑定到它。因此,您需要确保 Fuchsia 系统中的目标节点尚未绑定驱动程序。

上面的示例输出显示了 intel-i2c 驱动程序可绑定到的 PCI 节点和 ACPI 节点。您可以通过以下方式针对这两个节点编写驱动程序的绑定规则:

primary node "pci" {
    fuchsia.driver.framework.dfv2 == true;

    fuchsia.BIND_PROTOCOL == fuchsia.pci.BIND_PROTOCOL.DEVICE;
    fuchsia.BIND_PCI_VID == fuchsia.pci.BIND_PCI_VID.INTEL;
    accept fuchsia.BIND_PCI_DID {
        // For now we only add the DID for the touchpad.
        fuchsia.intel.platform.pci.BIND_PCI_DID.SUNRISE_POINT_SERIALIO_I2C2,
    }
}

node "acpi" {
    fuchsia.driver.framework.dfv2 == true;

    fuchsia.BIND_ACPI_ID == 0x000034;
    fuchsia.BIND_PCI_TOPO == 0x0000aa;
    fuchsia.BIND_ACPI_BUS_TYPE == 0x000001;
}

对于 ACPI 节点,请直观验证绑定规则中指定的 ACPI 值是否与 ACPI 节点属性中的值匹配(如上述 ffx 命令的输出中所示)。对于 PCI 节点,请直接检查 PCI 绑定库,检查库中定义的值是否与 PCI 节点的属性值相匹配。(如需详细了解这两种方法,请参阅为驱动程序编写绑定规则。)

附录

错误:未找到驱动程序生命周期

在 Fuchsia 系统中将组件注册为驱动程序后,您可能会在设备日志中看到与以下内容类似的错误消息 (ffx log):

Failed to start driver; driver lifecycle not found url=<DRIVER_URL>

如果您遇到此错误,请确保在驱动程序组件的源代码的末尾添加 FUCHSIA_DRIVER_EXPORT() 宏,例如:

// Register driver hooks with the framework
FUCHSIA_DRIVER_EXPORT(qemu_edu::QemuEduDriver);

如需详细了解此宏,请参阅驱动程序 Codelab 中的实现驱动程序钩子