| # Get started with driver development |
| |
| This guide provides step-by-step instructions that walk you through the basic |
| workflows of building, running, debugging, and updating |
| [drivers][driver-concepts] in a Fuchsia system using the |
| [Fuchsia SDK][using-the-sdk]. |
| |
| Important: This guide is the driver equivalent of the |
| [_Get started with the Fuchsia SDK_][get-started-sdk] guide. If you haven't |
| already, it's strongly recommended that you first complete the _Get started |
| with the Fuchsia SDK_ guide to become familiar with the comprehensive set of |
| Fuchsia SDK-based workflows. |
| |
| Complete the following sections: |
| |
| 1. [Prerequisites](#prerequisites). |
| 2. [Clone the SDK driver samples repository](#clone-the-sdk-driver-samples-repository). |
| 3. [Start the emulator](#start-the-emulator). |
| 4. [Build and load the sample driver](#build-and-load-the-sample-driver). |
| 5. [Build and run a tools component](#build-and-run-a-tools-component). |
| 6. [Debug the sample driver](#debug-the-sample-driver). |
| 7. [Modify and reload the sample driver](#modify-and-reload-the-sample-driver). |
| |
| Found an issue? Please [let us know][sdk-bug]{:.external}. |
| |
| ## 1. Prerequisites {:#prerequisites} |
| |
| Before you begin, complete the prerequisite steps below: |
| |
| * [Check host machine requirements](#check-host-machine-requirements) |
| * [Install dependencies](#install-dependencies) |
| * [Generate Fuchsia-specific SSH keys](#generate-fuchsia-specific-ssh-keys) |
| |
| ### Check host machine requirements {:#check-host-machine-requirements} |
| |
| This guide requires that your host machine meets the following criteria: |
| |
| * A Linux machine. **macOS** is not supported yet. |
| * Has at least 15 GB of storage space. |
| * Supports [KVM][kvm]{:.external} (Kernel Virtual Machine) for running a |
| [QEMU][qemu]{:.external}-based emulator. |
| * IPv6 is enabled. |
| |
| ### Install dependencies {:#install-dependencies} |
| |
| `git` and `bazel` need to be installed on the host machine. |
| You need Bazel 5.1 or higher. |
| |
| Note: You only need to complete these steps once on your host machine. |
| |
| Do the following: |
| |
| 1. [Install Git][git-install]{:.external}. |
| |
| 1. [Install Bazel][bazel-install]{:.external} – the easiest install option is |
| to download the [Bazelisk binary][bazelisk-download]{:.external} and rename |
| it to `bazel` in a convenient place on your path. |
| |
| ### Generate Fuchsia-specific SSH keys {:#generate-fuchsia-specific-ssh-keys} |
| |
| The `ffx` tool requires that [Fuchsia-specific SSH keys][fuchsia-ssh-keys] are |
| stored on the host machine for connecting to Fuchsia devices (including the |
| Fuchsia emulator). |
| |
| To check if your host machine already has Fuchsia SSH keys, do the following: |
| |
| 1. Scan the `$HOME/.ssh` directory for Fuchsia SSH keys: |
| |
| ```posix-terminal |
| ls $HOME/.ssh | grep fuchsia |
| ``` |
| |
| 1. Verify that the following `fuchsia_*` files are present: |
| |
| ```none {:.devsite-disable-click-to-copy} |
| $ ls $HOME/.ssh | grep fuchsia |
| fuchsia_authorized_keys |
| fuchsia_ed25519 |
| fuchsia_ed25519.pub |
| ``` |
| |
| **If you don’t see these files**, you need to generate Fuchsia SSH keys on the |
| host machine: |
| |
| 1. Generate a new private and public SSH key pair: |
| |
| Note: These Fuchsia SSH keys are only used for connecting to Fuchsia |
| devices during development. Generating these SSH keys won't alter your |
| current SSH settings. |
| |
| ```posix-terminal |
| [[ -f "${HOME}/.ssh/fuchsia_ed25519" ]] || ssh-keygen -P "" -t ed25519 -f "${HOME}/.ssh/fuchsia_ed25519" -C "${USER}@$(hostname -f) Shared SSH Key for Fuchsia" |
| ``` |
| |
| 1. Generate a `fuchsia_authorized_keys` file: |
| |
| ```posix-terminal |
| [[ -f "${HOME}/.ssh/fuchsia_authorized_keys" ]] || ssh-keygen -y -f "${HOME}/.ssh/fuchsia_ed25519" > "${HOME}/.ssh/fuchsia_authorized_keys" |
| ``` |
| |
| 1. Verify that Fuchsia SSH keys are generated: |
| |
| ```posix-terminal |
| ls $HOME/.ssh | grep fuchsia |
| ``` |
| |
| This command prints output similar to the following: |
| |
| ```none {:.devsite-disable-click-to-copy} |
| $ ls $HOME/.ssh | grep fuchsia |
| fuchsia_authorized_keys |
| fuchsia_ed25519 |
| fuchsia_ed25519.pub |
| ``` |
| |
| ## 2. Clone the SDK driver samples repository {:#clone-the-sdk-driver-samples-repository} |
| |
| Clone the [SDK driver samples repository][sdk-driver-sample-repo]{:.external} |
| on your host machine. This repository contains sample driver components and the |
| Bazel-based Fuchsia SDK. |
| |
| The tasks include: |
| |
| * Bootstrap the SDK driver samples repository. |
| * Verify that you can build the sample driver components and run `ffx` |
| commands. |
| |
| Do the following: |
| |
| 1. In a terminal, change to your home directory: |
| |
| Note: This guide uses the home directory (`$HOME`) as a base directory. This |
| is where a new work directory (`drivers`) will be created for this guide. You |
| may also select a different base directory (for instance, |
| `cd $HOME/my-fuchsia-project`). |
| |
| ```posix-terminal |
| cd $HOME |
| ``` |
| |
| 2. Clone the SDK driver samples repository: |
| |
| ```posix-terminal |
| git clone https://fuchsia.googlesource.com/sdk-samples/drivers --recurse-submodules |
| ``` |
| |
| This creates a new directory named `drivers`, which clones the content of the |
| SDK driver samples repository. |
| |
| 3. Go to the new directory: |
| |
| ```posix-terminal |
| cd drivers |
| ``` |
| |
| 4. To verify the Fuchsia SDK environment setup, build the sample drivers: |
| |
| ```posix-terminal |
| bazel build --config=fuchsia_x64 //src/qemu_edu |
| ``` |
| |
| The first build may take a few minutes to download dependencies, such as |
| Bazel build rules, [Clang][clang], and [Fuchsia IDK][fuchsia-idk] (which |
| includes the `ffx` tool). |
| |
| When finished successfully, it prints output similar to the following in the |
| end: |
| |
| ```none {:.devsite-disable-click-to-copy} |
| $ bazel build --config=fuchsia_x64 //src/qemu_edu |
| ... |
| INFO: Elapsed time: 131.746s, Critical Path: 26.89s |
| INFO: 722 processes: 454 internal, 268 linux-sandbox. |
| INFO: Build completed successfully, 722 total actions |
| ``` |
| |
| 5. To verify that you can use the `ffx` tool in your environment, run the |
| following command: |
| |
| ```posix-terminal |
| tools/ffx version -v |
| ``` |
| |
| This command prints output similar to the following: |
| |
| ```none {:.devsite-disable-click-to-copy} |
| $ tools/ffx version -v |
| ffx: |
| abi-revision: 0xA56735A6690E09D8 |
| api-level: 8 |
| build-version: 2022-06-09T20:02:48+00:00 |
| integration-commit-hash: dfddeea2221689c800ca1db7a7c7d1f2cb0bd99f |
| integration-commit-time: Thu, 09 Jun 2022 20:02:48 +0000 |
| |
| daemon: |
| abi-revision: 0xA56735A6690E09D8 |
| api-level: 8 |
| build-version: 2022-06-09T20:02:48+00:00 |
| integration-commit-hash: dfddeea2221689c800ca1db7a7c7d1f2cb0bd99f |
| integration-commit-time: Thu, 09 Jun 2022 20:02:48 +0000 |
| ``` |
| |
| At this point, you only need to confirm that you can run this `ffx` command |
| without any errors. |
| |
| Note: To ensure that you’re using the right version of `ffx` (which needs to |
| match the version of the SDK), consider updating your `PATH` to include the |
| SDK's `tools` directory where `ffx` is located (for instance, |
| `export PATH="$PATH:$HOME/drivers/tools"`). However, if you don't |
| wish to update your `PATH`, ensure that you specify the relative path to |
| this `ffx` tool (`tools/ffx`) whenever you run `ffx` commands. |
| |
| ## 3. Start the emulator {:#start-the-emulator} |
| |
| Start the [Fuchsia emulator][femu] on the host machine while configuring the |
| emulator instance to use Fuchsia’s new [driver framework][driver-framework] |
| (DFv2). |
| |
| The tasks include: |
| |
| * Download Fuchsia's Workstation prebuilt image from Google Cloud Storage. |
| * Start the Fuchsia emulator. |
| * Set the emulator instance as your host machine’s default target device. |
| * Start the Fuchsia package server. |
| * Register the system package repository to the emulator instance. |
| |
| Do the following: |
| |
| 1. Download the latest Workstation image for the emulator: |
| |
| ```posix-terminal |
| tools/ffx product-bundle get workstation.qemu-x64 |
| ``` |
| |
| This command may take a few minutes to download the image and product |
| metadata. |
| |
| Once the download is finished, the `ffx product-bundle get` command creates |
| a local Fuchsia package repository named `workstation.qemu-x64` on your host |
| machine. This package repository hosts additional system packages for this |
| Workstation prebuilt image. Later in Step 7 you’ll register this package |
| repository to the emulator instance. |
| |
| 2. Stop all emulator instances: |
| |
| ```posix-terminal |
| tools/ffx emu stop --all |
| ``` |
| |
| 3. Start the Fuchsia emulator: |
| |
| ```posix-terminal |
| tools/ffx emu start workstation.qemu-x64 --headless --kernel-args "driver_manager.use_driver_framework_v2=true" --kernel-args "driver_manager.root-driver=fuchsia-boot:///#meta/platform-bus.cm" --kernel-args "devmgr.enable-ephemeral=true" |
| ``` |
| |
| This command starts a headless emulator instance running the Workstation |
| prebuilt image. |
| |
| When the instance is up and running, the command prints output similar to |
| the following: |
| |
| ```none {:.devsite-disable-click-to-copy} |
| $ tools/ffx emu start workstation.qemu-x64 --headless --kernel-args "driver_manager.use_driver_framework_v2=true" --kernel-args "driver_manager.root-driver=fuchsia-boot:///#meta/platform-bus.cm" -- kernel-args "devmgr.enable-ephemeral=true" |
| Logging to "/home/alice/.local/share/Fuchsia/ffx/emu/instances/fuchsia-emulator/emulator.log" |
| Waiting for Fuchsia to start (up to 60 seconds). |
| Emulator is ready. |
| ``` |
| |
| 4. Verify that the new emulator instance is running: |
| |
| ```posix-terminal |
| tools/ffx emu list |
| ``` |
| |
| This command prints output similar to the following: |
| |
| ```none {:.devsite-disable-click-to-copy} |
| $ tools/ffx emu list |
| [Active] fuchsia-emulator |
| ``` |
| |
| 5. Set the default target device: |
| |
| ```posix-terminal |
| tools/ffx target default set fuchsia-emulator |
| ``` |
| |
| This command exits silently without output. |
| |
| 6. Start the Fuchsia package server: |
| |
| ```posix-terminal |
| tools/ffx repository server start |
| ``` |
| |
| This command prints output similar to the following: |
| |
| ```none {:.devsite-disable-click-to-copy} |
| $ tools/ffx repository server start |
| ffx repository server is listening on [::]:8083 |
| ``` |
| |
| 7. Register the system package repository (`workstation.qemu-x64`) to the |
| target device: |
| |
| ```posix-terminal |
| tools/ffx target repository register -r workstation.qemu-x64 --alias fuchsia.com |
| ``` |
| |
| This command exits silently without output. |
| |
| ## 4. Build and load the sample driver {:#build-and-load-the-sample-driver} |
| |
| The Fuchsia emulator (launched in the [Start the emulator](#start-the-emulator) |
| section above) is configured to create a virtual device named |
| [`edu`][edu-device], which is an educational device for writing drivers. |
| In the previous section, when the emulator started, Fuchsia’s driver framework |
| detected this `edu` device in the system, but it wasn’t able to find a driver |
| that could serve the `edu` device. So the `edu` device was left unmatched. |
| |
| In this section, we build and publish the [`qemu_edu`][qemu-edu] sample driver |
| (which is a Fuchsia component). Upon detecting a new driver, the driver |
| framework will discover that this new `qemu_edu` driver is a match for |
| the `edu` device. Once matched, the `qemu_edu` driver starts providing the `edu` |
| device’s services (capabilities) to other components in the system – one of the |
| services provided by the `edu` device is that it computes a factorial given |
| an integer. |
| |
| The tasks include: |
| |
| * View the drivers that are currently loaded in the emulator instance. |
| * Build and publish the `qemu_edu` driver component. |
| * Verify that the `qemu_edu` driver is loaded to the emulator instance. |
| * View detailed information on the `qemu_edu` component. |
| |
| Do the following: |
| |
| 1. View the list of the currently loaded drivers: |
| |
| ```posix-terminal |
| tools/ffx driver list --loaded |
| ``` |
| |
| This command prints output similar to the following: |
| |
| ```none {:.devsite-disable-click-to-copy} |
| $ tools/ffx driver list --loaded |
| 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 |
| ``` |
| |
| 2. Build and publish the `qemu_edu` driver component: |
| |
| ```posix-terminal |
| bazel run --config=fuchsia_x64 //src/qemu_edu:pkg.component |
| ``` |
| |
| This command prints output similar to the following: |
| |
| ```none {:.devsite-disable-click-to-copy} |
| $ bazel run --config=fuchsia_x64 //src/qemu_edu:pkg.component |
| INFO: Analyzed target //src/qemu_edu:pkg.component (6 packages loaded, 162 targets configured). |
| INFO: Found 1 target... |
| Target //src/qemu_edu:pkg.component up-to-date: |
| bazel-bin/src/qemu_edu/pkg.component_run_component.sh |
| INFO: Elapsed time: 1.660s, Critical Path: 0.49s |
| INFO: 21 processes: 12 internal, 8 linux-sandbox, 1 local. |
| INFO: Build completed successfully, 21 total actions |
| INFO: Build completed successfully, 21 total actions |
| added repository bazel.pkg.component |
| Registering fuchsia-pkg://bazel.pkg.component/qemu_edu#meta/qemu_edu.cm |
| Successfully bound: |
| Node 'root.sys.platform.platform-passthrough.PCI0.bus.00_06_0_', Driver 'fuchsia-pkg://bazel.pkg.component/qemu_edu#meta/qemu_edu.cm'. |
| ``` |
| |
| 3. Verify that the `qemu_edu` driver is now loaded to the Fuchsia emulator |
| instance: |
| |
| ```posix-terminal |
| tools/ffx driver list --loaded |
| ``` |
| |
| This command prints output similar to the following: |
| |
| ```none {:.devsite-disable-click-to-copy} |
| $ tools/ffx driver list --loaded |
| 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 |
| {{ '<strong>' }}fuchsia-pkg://bazel.pkg.component/qemu_edu#meta/qemu_edu.cm{{ '</strong>' }} |
| ``` |
| |
| Notice that the `qemu_edu` driver is shown at the bottom of the loaded |
| drivers list. |
| |
| 4. View the `qemu_edu` component information: |
| |
| ```posix-terminal |
| tools/ffx component show qemu_edu.cm |
| ``` |
| |
| This command prints output similar to the following: |
| |
| ```none {:.devsite-disable-click-to-copy} |
| $ tools/ffx component show qemu_edu.cm |
| Moniker: /bootstrap/universe-pkg-drivers:root.sys.platform.platform-passthrough.PCI0.bus.00_06_0_ |
| URL: fuchsia-pkg://bazel.pkg.component/qemu_edu#meta/qemu_edu.cm |
| Type: CML dynamic component |
| Component State: Resolved |
| Incoming Capabilities: fuchsia.device.fs.Exporter |
| fuchsia.driver.compat.Service |
| fuchsia.logger.LogSink |
| pkg |
| Merkle root: a4832605ffe6bf6ddad3aad0d3d36c435ee2e66f79d43cd0b818d2aae20f7755 |
| Execution State: Running |
| Start reason: Instance is in a single_run collection |
| Outgoing Capabilities: qemu-edu |
| ``` |
| |
| 5. View device logs: |
| |
| ```posix-terminal |
| tools/ffx log --filter qemu_edu |
| ``` |
| |
| This command prints output similar to the following: |
| |
| ```none {:.devsite-disable-click-to-copy} |
| $ tools/ffx log --filter qemu_edu |
| ... |
| [176.540][core/pkg-resolver][pkg-resolver][I] resolved fuchsia-pkg://bazel.pkg.component/qemu_edu to a4832605ffe6bf6ddad3aad0d3d36c435ee2e66f79d43cd0b818d2aae20f7755 with TUF |
| [176.542][bootstrap/driver_index][driver_index,driver][I] Registered driver successfully: fuchsia-pkg://bazel.pkg.component/qemu_edu#meta/qemu_edu.cm. |
| [176.571][core/pkg-resolver][pkg-resolver][I] Fetching blobs for fuchsia-pkg://bazel.pkg.component/qemu_edu: [] |
| [176.573][core/pkg-resolver][pkg-resolver][I] resolved fuchsia-pkg://bazel.pkg.component/qemu_edu to a4832605ffe6bf6ddad3aad0d3d36c435ee2e66f79d43cd0b818d2aae20f7755 with TUF |
| [176.577][bootstrap/driver_manager][driver_manager.cm][I]: [driver_runner.cc:858] Binding fuchsia-pkg://bazel.pkg.component/qemu_edu#meta/qemu_edu.cm to 00_06_0_ |
| [176.908][bootstrap/driver-hosts:driver-host-3][driver_host2.cm][I]: [driver_host.cc:289] Started 'fuchsia-pkg://bazel.pkg.component/qemu_edu#meta/qemu_edu.cm' |
| ``` |
| |
| Press `CTRL+C` to exit. |
| |
| ## 5. Build and run a tools component {:#build-and-run-a-tools-component} |
| |
| The `qemu_edu` driver sample has a “tools” component named `eductl`, which can |
| interact with the sample driver. Developers create these tools components for |
| testing and debugging drivers during development. |
| |
| In this case, the `eductl` component contacts the `qemu_edu` driver and passes |
| an integer as input. The driver (using the resource of the `edu` virtual device) |
| computes the integer's factorial and returns the result to the `eductl` |
| component. The component then prints the result in the log. |
| |
| The tasks include: |
| |
| * Build and run the `eductl` component. |
| * Verify that the component can interact with the `qemu_edu` driver. |
| |
| Do the following: |
| |
| 1. Build and run the `eductl` component: |
| |
| ```posix-terminal |
| bazel run --config=fuchsia_x64 //src/qemu_edu:eductl_pkg.eductl_component |
| ``` |
| |
| This command prints output similar to the following: |
| |
| ```none {:.devsite-disable-click-to-copy} |
| $ bazel run --config=fuchsia_x64 //src/qemu_edu:eductl_pkg.eductl_component |
| INFO: Analyzed target //src/qemu_edu:eductl_pkg.eductl_component (0 packages loaded, 14 targets configured). |
| INFO: Found 1 target... |
| Target //src/qemu_edu:eductl_pkg.eductl_component up-to-date: |
| bazel-bin/src/qemu_edu/eductl_pkg.eductl_component_run_component.sh |
| INFO: Elapsed time: 1.667s, Critical Path: 1.22s |
| INFO: 23 processes: 7 internal, 15 linux-sandbox, 1 local. |
| INFO: Build completed successfully, 23 total actions |
| INFO: Build completed successfully, 23 total actions |
| added repository bazel.eductl.pkg.eductl.component |
| URL: fuchsia-pkg://bazel.eductl.pkg.eductl.component/eductl#meta/eductl.cm |
| Moniker: /core/ffx-laboratory:eductl |
| Creating component instance... |
| Starting component instance... |
| Success! The component instance has been started. |
| ``` |
| |
| 2. View the device logs of the `eductl` component: |
| |
| ```posix-terminal |
| tools/ffx log --filter eductl dump |
| ``` |
| |
| This command prints output similar to the following: |
| |
| ```none {:.devsite-disable-click-to-copy} |
| $ tools/ffx log --filter eductl dump |
| ... |
| [367.076][core/pkg-resolver][pkg-resolver][I] resolved fuchsia-pkg://bazel.eductl.pkg.eductl.component/eductl to 4fe2e38ed56693bf720565c3ee5e6f8314a64c601cae67288db5e8d30f1a9265 with TUF |
| [367.080][core/pkg-resolver][pkg-resolver][I] Fetching blobs for fuchsia-pkg://bazel.eductl.pkg.eductl.component/eductl: [] |
| [367.081][core/pkg-resolver][pkg-resolver][I] resolved fuchsia-pkg://bazel.eductl.pkg.eductl.component/eductl to 4fe2e38ed56693bf720565c3ee5e6f8314a64c601cae67288db5e8d30f1a9265 with TUF |
| {{ '<strong>' }}[367.166][core/ffx-laboratory:eductl][][I] Factorial(12) = 479001600{{ '</strong>' }} |
| [367.173][core/pkg-resolver][pkg-resolver][I] removing repository fuchsia-pkg://bazel.eductl.pkg.eductl.component |
| [367.173][core/pkg-resolver][pkg-resolver][I] closing fuchsia-pkg://bazel.eductl.pkg.eductl.component |
| [367.176][core/pkg-resolver][pkg-resolver][I] AutoClient for "http://10.0.2.2:8083/bazel.eductl.pkg.eductl.component/auto" stopping |
| ``` |
| |
| The output `Factorial(12) = 479001600` shows that the `eductl` component |
| passed 12 as input to the driver and received the result from the driver. |
| (For the default input, see this [`eductl.cml`][eductl-cml] file.) |
| |
| ## 6. Debug the sample driver {:#debug-the-sample-driver} |
| |
| Use the Fuchsia debugger ([`zxdb`][zxdb-user-guide]) to step through the |
| sample driver’s code as the driver is running on the emulator instance. |
| |
| The tasks include: |
| |
| * Identify the driver host (which is a component) that is running the |
| `qemu_edu` driver. |
| * Start the Fuchsia debugger and connect it to the emulator instance. |
| * Attach the debugger to the driver host. |
| * Set a breakpoint on the driver’s code. |
| * Run the tools component, which triggers the driver to execute its |
| instructions. |
| * Step through the driver’s code. |
| |
| Do the following: |
| |
| 1. View the list of the running driver hosts: |
| |
| ```posix-terminal |
| tools/ffx driver list-hosts |
| ``` |
| |
| This command prints output similar to the following: |
| |
| ```none {:.devsite-disable-click-to-copy} |
| $ tools/ffx driver list-hosts |
| Driver Host: 4690 |
| fuchsia-boot:///#meta/block.core.cm |
| fuchsia-boot:///#meta/bus-pci.cm |
| fuchsia-boot:///#meta/fvm.cm |
| fuchsia-boot:///#meta/hid.cm |
| fuchsia-boot:///#meta/netdevice-migration.cm |
| fuchsia-boot:///#meta/network-device.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 |
| |
| Driver Host: 7820 |
| fuchsia-boot:///#meta/intel-rtc.cm |
| |
| Driver Host: 7903 |
| fuchsia-boot:///#meta/pc-ps2.cm |
| |
| Driver Host: 50125 |
| fuchsia-pkg://bazel.pkg.component/qemu_edu#meta/qemu_edu.cm |
| ``` |
| |
| Make a note of the PID of the `qemu_edu` driver host (`50125` in the |
| example above). |
| |
| 2. Start the Fuchsia debugger: |
| |
| ```posix-terminal |
| tools/ffx debug connect |
| ``` |
| |
| This command prints output similar to the following: |
| |
| ```none {:.devsite-disable-click-to-copy} |
| $ tools/ffx debug connect |
| Connecting (use "disconnect" to cancel)... |
| Connected successfully. |
| 👉 To get started, try "status" or "help". |
| [zxdb] |
| ``` |
| |
| 3. Attach the debugger to the `qemu_edu` driver host: |
| |
| <pre class="devsite-click-to-copy"> |
| <span class="no-select">[zxdb] </span>attach <var>PID</var> |
| </pre> |
| |
| Replace `PID` with the PID of the `qemu_edu` driver host identified |
| in Step 1, for example: |
| |
| ```none {:.devsite-disable-click-to-copy} |
| [zxdb] attach 50125 |
| ``` |
| |
| This command prints output similar to the following: |
| |
| ```none {:.devsite-disable-click-to-copy} |
| [zxdb] attach 50125 |
| Attached Process 1 state=Running koid=50125 name=driver_host2.cm |
| Downloading symbols... |
| Symbol downloading complete. 7 succeeded, 0 failed. |
| [zxdb] |
| ``` |
| |
| 4. Set a breakpoint at the driver’s `ComputeFactorial` function: |
| |
| <pre class="devsite-click-to-copy"> |
| <span class="no-select">[zxdb] </span>break QemuEduDriver::ComputeFactorial |
| </pre> |
| |
| This command prints output similar to the following: |
| |
| ```none {:.devsite-disable-click-to-copy} |
| [zxdb] break QemuEduDriver::ComputeFactorial |
| Created Breakpoint 1 @ QemuEduDriver::ComputeFactorial |
| 177 void QemuEduDriver::ComputeFactorial(ComputeFactorialRequestView request, |
| ◉ 178 ComputeFactorialCompleter::Sync& completer) { |
| 179 // Write a value into the factorial register. |
| [zxdb] |
| ``` |
| |
| 5. In different terminal, run the tools component: |
| |
| Note: In this new terminal, make sure that you change to the same work |
| directory (for instance, `cd $HOME/drivers`). |
| |
| ```posix-terminal |
| bazel run --config=fuchsia_x64 //src/qemu_edu:eductl_pkg.eductl_component |
| ``` |
| |
| In the `zxdb` terminal, verify that the debugger is stopped at the driver’s |
| `ComputeFactorial` function, for example: |
| |
| ```none {:.devsite-disable-click-to-copy} |
| 🛑 thread 2 on bp 1 qemu_edu::QemuEduDriver::ComputeFactorial(qemu_edu::QemuEduDriver*, fidl::WireServer<fuchsia_hardware_qemuedu::Device>::ComputeFactorialRequestView, fidl::Completer<fidl::internal::WireCompleterBase<fuchsia_hardware_qemuedu::Device::ComputeFactorial> >::Sync&) • qemu_edu.cc:178 |
| 176 |
| 177 void QemuEduDriver::ComputeFactorial(ComputeFactorialRequestView request, |
| ▶ 178 ComputeFactorialCompleter::Sync& completer) { |
| 179 // Write a value into the factorial register. |
| 180 uint32_t input = request->input; |
| [zxdb] |
| ``` |
| |
| 6. In the `zxdb` terminal, view the source code around the current breakpoint: |
| |
| <pre class="devsite-click-to-copy"> |
| <span class="no-select">[zxdb] </span>list |
| </pre> |
| |
| This command prints output similar to the following: |
| |
| ```none {:.devsite-disable-click-to-copy} |
| [zxdb] list |
| 173 }); |
| 174 return outgoing_.Serve(std::move(outgoing_dir)); |
| 175 } |
| 176 |
| 177 void QemuEduDriver::ComputeFactorial(ComputeFactorialRequestView request, |
| ▶ 178 ComputeFactorialCompleter::Sync& completer) { |
| 179 // Write a value into the factorial register. |
| 180 uint32_t input = request->input; |
| 181 |
| 182 mmio_->Write32(input, regs::kFactorialCompoutationOffset); |
| 183 |
| 184 // Busy wait on the factorial status bit. |
| 185 while (true) { |
| 186 const auto status = regs::Status::Get().ReadFrom(&*mmio_); |
| 187 if (!status.busy()) |
| 188 break; |
| [zxdb] |
| ``` |
| |
| 7. In the `zxdb` terminal, step through the code using the `next` |
| command until the value of `factorial` is read from the device (that is, |
| until the line 194 is reached): |
| |
| <pre class="devsite-click-to-copy"> |
| <span class="no-select">[zxdb] </span>next |
| </pre> |
| |
| The last `next` command prints output similar to the following: |
| |
| ```none {:.devsite-disable-click-to-copy} |
| ... |
| [zxdb] next |
| 🛑 thread 2 qemu_edu::QemuEduDriver::ComputeFactorial(qemu_edu::QemuEduDriver*, fidl::WireServer<fuchsia_hardware_qemuedu::Device>::ComputeFactorialRequestView, fidl::Completer<fidl::internal::WireCompleterBase<fuchsia_hardware_qemuedu::Device::ComputeFactorial> >::Sync&) • qemu_edu.cc:194 |
| 192 uint32_t factorial = mmio_->Read32(regs::kFactorialCompoutationOffset); |
| 193 |
| ▶ 194 FDF_SLOG(INFO, "Replying with", KV("factorial", factorial)); |
| 195 completer.Reply(factorial); |
| 196 } |
| [zxdb] |
| ``` |
| |
| 8. Print the `factorial` variable: |
| |
| <pre class="devsite-click-to-copy"> |
| <span class="no-select">[zxdb] </span>print factorial |
| </pre> |
| |
| This command prints output similar to the following: |
| |
| ```none {:.devsite-disable-click-to-copy} |
| [zxdb] print factorial |
| 479001600 |
| [zxdb] |
| ``` |
| |
| 1. To exit the `zxdb` terminal, type `exit` or press `Ctrl-D`. |
| |
| Note: For more information on usages and best practices on `zxdb`, see the |
| [zxdb user guide][zxdb-user-guide]. |
| |
| ## 7. Modify and reload the sample driver {:#modify-and-reload-the-sample-driver} |
| |
| Update the source code of the sample driver and reload it to the emulator |
| instance. |
| |
| The tasks include: |
| |
| * Restart the emulator instance to unload the `qemu_edu` driver. |
| * Update the source code of the `qemu_edu` driver. |
| * Load the updated driver. |
| * Run the tools component to verify the change. |
| |
| Do the following: |
| |
| 1. Stop the emulator instance: |
| |
| ```posix-terminal |
| tools/ffx emu stop |
| ``` |
| |
| This command stops the currently running emulator instance. |
| |
| 1. Start a new instance of the Fuchsia emulator: |
| |
| ```posix-terminal |
| tools/ffx emu start workstation.qemu-x64 --headless --kernel-args "driver_manager.use_driver_framework_v2=true" --kernel-args "driver_manager.root-driver=fuchsia-boot:///#meta/platform-bus.cm" --kernel-args "devmgr.enable-ephemeral=true" |
| ``` |
| |
| This command starts a headless emulator instance running the Workstation |
| prebuilt image. |
| |
| 1. Use a text editor to open the source code of the sample driver, for example: |
| |
| ```posix-terminal |
| nano src/qemu_edu/qemu_edu.cc |
| ``` |
| |
| 1. In the `QemuEduDriver::ComputeFactorial` function, |
| between the line |
| `uint32_t factorial = mmio_->Read32(regs::kFactorialCompoutationOffset);` |
| (Line 192) and the `FDF_SLOG()` call (Line 194), add the following line: |
| |
| ``` |
| factorial=12345; |
| ``` |
| |
| The function should look like below: |
| |
| ```none {:.devsite-disable-click-to-copy} |
| void QemuEduDriver::ComputeFactorial(ComputeFactorialRequestView request, |
| ComputeFactorialCompleter::Sync& completer) { |
| // Write a value into the factorial register. |
| uint32_t input = request->input; |
| |
| mmio_->Write32(input, regs::kFactorialCompoutationOffset); |
| |
| // Busy wait on the factorial status bit. |
| while (true) { |
| const auto status = regs::Status::Get().ReadFrom(&*mmio_); |
| if (!status.busy()) |
| break; |
| } |
| |
| // Return the result. |
| uint32_t factorial = mmio_->Read32(regs::kFactorialCompoutationOffset); |
| {{ '<strong>' }}factorial = 12345;{{ '</strong>' }} |
| FDF_SLOG(INFO, "Replying with", KV("factorial", factorial)); |
| completer.Reply(factorial); |
| } |
| ``` |
| |
| The function is now updated to return the value of `12345` only. |
| |
| 1. Save the file and close the text editor. |
| |
| 1. Rebuild and run the modified sample driver: |
| |
| ```posix-terminal |
| bazel run --config=fuchsia_x64 //src/qemu_edu:pkg.component |
| ``` |
| |
| 1. Run the tools component: |
| |
| ```posix-terminal |
| bazel run --config=fuchsia_x64 //src/qemu_edu:eductl_pkg.eductl_component |
| ``` |
| |
| 1. To verify that change, view the device logs of the tools component: |
| |
| ```posix-terminal |
| tools/ffx log --filter eductl dump |
| ``` |
| |
| This command prints output similar to the following: |
| |
| ```none {:.devsite-disable-click-to-copy} |
| $ tools/ffx log --filter eductl dump |
| ... |
| [43.349][core/pkg-resolver][pkg-resolver][I] resolved fuchsia-pkg://bazel.eductl.pkg.eductl.component/eductl to 4fe2e38ed56693bf720565c3ee5e6f8314a64c601cae67288db5e8d30f1a9265 with TUF |
| [43.354][core/pkg-resolver][pkg-resolver][I] Fetching blobs for fuchsia-pkg://bazel.eductl.pkg.eductl.component/eductl: [] |
| [43.355][core/pkg-resolver][pkg-resolver][I] resolved fuchsia-pkg://bazel.eductl.pkg.eductl.component/eductl to 4fe2e38ed56693bf720565c3ee5e6f8314a64c601cae67288db5e8d30f1a9265 with TUF |
| {{ '<strong>' }}[43.439][core/ffx-laboratory:eductl][][I] Factorial(12) = 12345{{ '</strong>' }} |
| [43.448][core/pkg-resolver][pkg-resolver][I] removing repository fuchsia-pkg://bazel.eductl.pkg.eductl.component |
| [43.449][core/pkg-resolver][pkg-resolver][I] closing fuchsia-pkg://bazel.eductl.pkg.eductl.component |
| [43.452][core/pkg-resolver][pkg-resolver][I] AutoClient for "http://10.0.2.2:8083/bazel.eductl.pkg.eductl.component/auto" stopping. |
| ``` |
| |
| The line in the logs shows that the `qemu_edu` driver returned the |
| hardcoded value of `12345` as the factorial of 12 to the tools component. |
| |
| **Congratulations! You’re now all set with the Fuchsia driver development!** |
| |
| ## Next steps {:#next-steps} |
| |
| Learn more about how the `qemu_edu` driver works in the |
| [Driver sample walkthrough: qemu_edu][driver-sample-walkthrough] guide. |
| |
| ## Appendices |
| |
| ### Clean up the environment {:#clean-up-the-environment} |
| |
| If you run into a problem while following this guide and decide to start over |
| from the beginning, consider running the commands below to clean up |
| your development environment (that is, to clean up directories, build artifacts, |
| downloaded files, symlinks, configuration settings, and more). |
| |
| Remove the package repositories created in this guide: |
| |
| ```posix-terminal |
| tools/ffx repository remove workstation.qemu-x64 |
| ``` |
| |
| ```posix-terminal |
| tools/ffx repository server stop |
| ``` |
| |
| ```posix-terminal |
| rm -rf $HOME/.package_repos/sdk-samples |
| ``` |
| |
| Remove all existing configurations and data of `ffx`: |
| |
| ```posix-terminal |
| tools/ffx daemon stop |
| ``` |
| |
| ```posix-terminal |
| rm -rf $HOME/.local/share/Fuchsia/ffx |
| ``` |
| |
| Remove the `drivers` directory and its artifacts: |
| |
| Caution: If the SDK samples repository is cloned to a different location |
| than `$HOME/drivers`, adjust the directory path in the command below. |
| Be extremely careful with the directory path when you run the `rm -rf |
| <DIR>` command. |
| |
| ```posix-terminal |
| rm -rf $HOME/drivers |
| ``` |
| |
| When Bazel fails to build, try the commands below: |
| |
| Caution: Running `bazel clean` or deleting the `$HOME/.cache/bazel` directory |
| deletes all the artifacts downloaded by Bazel, which can be around 4 GB. |
| This means Bazel will need to download those dependencies again |
| the next time you run `bazel build`. |
| |
| ```posix-terminal |
| bazel clean --expunge |
| ``` |
| |
| ```posix-terminal |
| bazel shutdown && rm -rf $HOME/.cache/bazel |
| ``` |
| |
| Other clean up commands: |
| |
| ```posix-terminal |
| killall ffx |
| ``` |
| |
| ```posix-terminal |
| killall pm |
| ``` |
| |
| <!-- Reference links --> |
| |
| [using-the-sdk]: /docs/development/sdk/index.md |
| [get-started-sdk]: /docs/get-started/sdk/index.md |
| [sdk-bug]: https://bugs.fuchsia.dev/p/fuchsia/issues/entry?template=Bazel |
| [kvm]: https://www.linux-kvm.org/page/Main_Page |
| [qemu]: https://www.qemu.org/ |
| [bazel]: https://bazel.build/docs |
| [git]: https://git-scm.com/ |
| [git-install]: https://git-scm.com/book/en/v2/Getting-Started-Installing-Git |
| [bazel-install]: https://bazel.build/install |
| [bazelisk-download]: https://github.com/bazelbuild/bazelisk/releases |
| [fuchsia-ssh-keys]: /docs/development/sdk/ffx/create-ssh-keys-for-devices.md |
| [ticket-01]: https://bugs.fuchsia.dev/p/fuchsia/issues/detail?id=97909 |
| [sdk-driver-sample-repo]: https://fuchsia.googlesource.com/sdk-samples/drivers |
| [clang]: https://clang.llvm.org/ |
| [fuchsia-idk]: /docs/development/idk/README.md |
| [edu-device]: https://fuchsia.googlesource.com/third_party/qemu/+/refs/heads/main/docs/specs/edu.txt |
| [qemu-edu]: https://fuchsia.googlesource.com/sdk-samples/drivers/+/refs/heads/main/src/qemu_edu/ |
| [eductl-cml]: https://fuchsia.googlesource.com/sdk-samples/drivers/+/refs/heads/main/src/qemu_edu/meta/eductl.cml |
| [zxdb-user-guide]: /docs/development/debugger/README.md |
| [driver-concepts]: /docs/concepts/drivers/README.md |
| [driver-sample-walkthrough]: /docs/development/sdk/driver-sample-qemu-edu.md |
| [driver-framework]: /docs/concepts/drivers/driver_framework.md |
| [femu]: /docs/development/sdk/ffx/start-the-fuchsia-emulator.md |