blob: 291d1fadde886532893118d835b5d13d440d17e6 [file] [log] [blame] [view]
# Debug a driver when it fails to load
This guide provides best practices for debugging a new driver when it fails to load in your
Fuchsia system.
## Check if your driver is currently running in the system {:#check-if-your-driver-is-currently-running-in-the-system}
In Fuchsia, a driver gets loaded in the system when the driver is matched to a
[node][drivers-and-nodes] that represents a hardware or virtual device. Once matched and
loaded, the driver starts running and provides services to other components in the system.
To see if a driver is loaded (that is, currently running) in your Fuchsia system,
run the following command:
```posix-terminal
ffx driver list --loaded
```
This command prints the list of drivers loaded in the system, for example:
```none {:.devsite-disable-click-to-copy}
$ 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
```
Alternatively, if you know the exact driver component, you can use the
[`ffx component show`][ffx-component-show] command to view the state of the component,
for example:
```none {:.devsite-disable-click-to-copy}
$ 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
{{ '<strong>' }}Execution State: Running{{ '</strong>' }}
Start reason: Instance is in a single_run collection
Outgoing Capabilities: fuchsia.driver.compat.Service
```
If you discover that your driver is not loaded in the system, see the next section for the steps
you can take to debug the issue.
## Best practices for debugging {:#best-practices-for-debugging}
During the initial phase of writing a new Fuchsia driver, youd first want to make sure that your
new component is recognized as a driver in your Fuchsia system. Once the component is listed as
a driver in your Fuchsia system, you can start working on [writing bind rules][write-bind-rules]
so that your driver can bind to a specific node that represents your target device in the system.
When you have the driver bound to your target node (thus, the driver is successfully loaded in the
system), you can then move on to the next phrase of development, which is to start implementing
features for the driver.
When debugging a driver that fails to load in your Fuchsia system, consider the following steps:
1. [Check the component manifest](#check-the-component-manifest).
1. [Register your driver with the driver framework](#register-your-driver-with-the-driver-framework).
1. [Verify that the bind rules are correct](#verify-that-the-bind-rules-are-correct).
### 1. Check the component manifest {:#check-the-component-manifest}
For a Fuchsia system to view a component as a driver, the components `runner` field in the
[component manifest][component-manifests] (`.cml`) must be set to `driver`, for example:
```none {:.devsite-disable-click-to-copy}
program: {
runner: 'driver',
...
}
```
### 2. Register your driver with the driver framework {:#register-your-driver-with-the-driver-framework}
Next, confirm that your component is listed as a driver in your Fuchsia system.
For a component to be recognized as a driver, you need to explicitly register the component as
a driver in your Fuchsia system. If a component does not appear as a driver in the system,
it means that the [driver framework][driver-framework] is not aware of the component, therefore
such a component will never be considered for [driver binding][driver-binding]. So having your
new component appear as a driver in your Fuchsia system should be the first milestone when
writing a new driver.
To register a component as a driver in your Fuchsia system, do the following:
1. Upload the Fuchsia package (that contains the driver component) to your
[Fuchsia package server][fuchsia-package-server].
Note: The `bazel` commands can execute the building, uploading, and registering
of a driver package at once. If your Fuchsia development environment uses the
Bazel build system, you can replace steps 1 and 2 here with the
[`bazel run`][bazel-run] command.
1. Register the component as a driver in the system:
```posix-terminal
ffx driver register <URL>
```
Replace `URL` with the component URL from your Fuchsia package server, for example:
```none {:.devsite-disable-click-to-copy}
ffx driver register fuchsia-pkg://fuchsia.com/my_example#meta/my_new_driver.cm
```
1. View the list of drivers currently registered (but not necessarily running) in the system:
```posix-terminal
ffx driver list
```
This command prints output similar to the following:
```none {:.devsite-disable-click-to-copy}
$ 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
```
Verify that your new driver component appears in this list.
### 3. Verify that the bind rules are correct {:#verify-that-the-bind-rules-are-correct}
At last, start examining the bind rules of your driver.
A drivers bind rules determine which nodes it can bind to in a Fuchsia system. The driver
framework loads drivers only when they match the node properties of specific nodes in the system.
If your driver is registered in the system, but is not loaded (therefore is not running), then
check the drivers bind rules and verify that they are correctly written to match the bind
properties of the target node in your Fuchsia system.
To view all nodes and their node properties in your Fuchsia system, run the following command:
```posix-terminal
ffx driver list-devices -v
```
This command prints output similar to the following:
```none {:.devsite-disable-click-to-copy}
$ ffx driver list-devices -v
...
Name : I2C2
Moniker : root.sys.platform.pt.acpi.I2C2
Driver : None
5 Properties
[ 1/ 5] : Key fuchsia.BIND_ACPI_ID Value 0x000034
[ 2/ 5] : Key fuchsia.BIND_PCI_TOPO Value 0x0000aa
[ 3/ 5] : Key fuchsia.BIND_ACPI_BUS_TYPE Value 0x000001
[ 4/ 5] : Key "fuchsia.hardware.acpi.Device" Value true
[ 5/ 5] : Key fuchsia.BIND_PROTOCOL Value 0x00001e
...
Name : 00_15_2
Moniker : root.sys.platform.pt.pci.00_15_2
Driver : None
8 Properties
[ 1/ 8] : Key fuchsia.BIND_PROTOCOL Value 0x00001f
[ 2/ 8] : Key fuchsia.BIND_PCI_VID Value 0x008086
[ 3/ 8] : Key fuchsia.BIND_PCI_DID Value 0x009d62
[ 4/ 8] : Key fuchsia.BIND_PCI_CLASS Value 0x000011
[ 5/ 8] : Key fuchsia.BIND_PCI_SUBCLASS Value 0x000080
[ 6/ 8] : Key fuchsia.BIND_PCI_INTERFACE Value 0x000000
[ 7/ 8] : Key fuchsia.BIND_PCI_REVISION Value 0x000021
[ 8/ 8] : Key fuchsia.BIND_PCI_TOPO Value 0x0000aa
...
```
When debugging bind rules, a recommended practice is to visually examine the output from this
command to ensure that your Fuchsia system contains nodes with the right node properties. Also,
keep in mind that a node is allowed to have only one driver bound to it. So you want to make sure
that the target node in your Fuchsia system does not have a driver already bound to it.
The example output above shows a PCI node and an ACPI node, which the `intel-i2c` driver can
bind to. You may write the drivers bind rules against these two nodes in the following way:
```none {:.devsite-disable-click-to-copy}
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;
}
```
For the ACPI node, visually verify that the ACPI values specified in the bind rules match the
values the ACPI node properties (shown in the output of the `ffx` command above). And for
the PCI node, examine the [PCI bind library][fuchsia-pci-bind] directly to check if the values
defined in the library match the values of the PCI node's properties. (For more information
on these two approaches, see [Write bind rules for a driver][write-bind-rules].)
## Appendices
### Error: driver lifecycle not found {:#error-driver-lifecycle-not-found}
After registering a component as a driver in your Fuchsia system, you may see an error message
similar to the following in the device logs ([`ffx log`][ffx-log]):
```none {:.devsite-disable-click-to-copy}
Failed to start driver; driver lifecycle not found url=<DRIVER_URL>
```
If you run into this error, make sure that the `FUCHSIA_DRIVER_EXPORT()` macro is added
at the end of your driver component’s source code, for example:
```none {:.devsite-disable-click-to-copy}
// Register driver hooks with the framework
FUCHSIA_DRIVER_EXPORT(qemu_edu::QemuEduDriver);
```
For more information on this macro, see [Implement driver hooks][implement-driver-hooks] in
the Driver codelab.
<!-- Reference links -->
[drivers-and-nodes]: /docs/concepts/drivers/drivers_and_nodes.md
[write-bind-rules]: /docs/development/sdk/write-bind-rules-for-driver.md
[component-manifests]: /docs/concepts/components/v2/component_manifests.md
[driver-framework]: /docs/concepts/drivers/driver_framework.md
[driver-binding]: /docs/concepts/drivers/driver_binding.md
[fuchsia-package-server]: /docs/development/tools/ffx/workflows/create-a-package-repository.md
[bazel-run]: https://fuchsia.googlesource.com/sdk-samples/drivers
[fuchsia-pci-bind]: https://cs.opensource.google/fuchsia/fuchsia/+/main:src/devices/bind/fuchsia.pci/fuchsia.pci.bind
[ffx-component-show]: /docs/development/tools/ffx/workflows/view-component-information.md
[ffx-log]: /docs/development/tools/ffx/workflows/view-device-logs.md
[implement-driver-hooks]: /docs/development/drivers/tutorials/sdk_build_driver/driver-binding.md#implement_driver_hooks