This codelab walks through the process of defining a new board configuration in Fuchsia using the Bazel build system. Board configurations are crucial for specifying the hardware-specific components, drivers, and settings required to run Fuchsia on a particular device.
Prerequisites
- Familiarity with Fuchsia's software assembly concepts.
- Basic understanding of Bazel build rules.
What is a board configuration?
A board configuration in Fuchsia encapsulates all the necessary information to build a system image for a specific piece of hardware. This includes:
- Hardware identification: Name and version.
- Code: Board-specific drivers and platform features.
- Storage layout: How partitions are arranged.
- Boot process: Kernel arguments and device tree information.
- Filesystem details: Options like compression.
Board configurations are defined using the fuchsia_board_configuration rule in
BUILD.bazel files, typically located within the //boards directory.
Writing a board configuration
Let's explore the key attributes of the fuchsia_board_configuration rule with
examples.
Basic setup
Every board configuration needs a name, board name, and partitions config. For example:
# //boards/my_awesome_board/BUILD.bazel
load(
"@rules_fuchsia//fuchsia:assembly.bzl",
"fuchsia_board_configuration",
)
fuchsia_board_configuration(
name = "my_awesome_board", # Target name for the build system
board_name = "my_awesome_board", # Identifier used by tools like ffx
version = "1.2.3.4", # Version of the board configuration
partitions_configuration = "//boards/partitions/my_awesome_board",
# ... more attributes to come
)
Partitions configuration
The partitions_configuration field points to a
fuchsia_partitions_configuration target, typically defined in a BUILD.bazel
file within a subdirectory of //boards/partitions. This target defines the
layout and types of partitions for the board, such as where the ZBI,
VBMeta, and FXFS are located.
These images and partitions are often organized into different ABR slots.
For example in //boards/partitions/my_awesome_board/BUILD.bazel:
load(
"@rules_fuchsia//fuchsia:assembly.bzl",
"PARTITION_TYPE",
"SLOT",
"fuchsia_bootloader_partition",
"fuchsia_partition",
"fuchsia_partitions_configuration",
)
# Standard Fuchsia partitions
fuchsia_partition(
name = "zircon_a",
partition_name = "zircon_a",
slot = SLOT.A,
type = PARTITION_TYPE.ZBI,
)
fuchsia_partition(
name = "vbmeta_a",
partition_name = "vbmeta_a",
slot = SLOT.A,
type = PARTITION_TYPE.VBMETA,
)
fuchsia_partition(
name = "fxfs",
partition_name = "fvm", # Or "fxfs" depending on board
type = PARTITION_TYPE.FXFS,
)
# ... (typically define all slots A, B, R for ZBI/VBMeta)
# Board-specific bootloader partition
fuchsia_bootloader_partition(
name = "my_bootloader",
image = "//boards/my_awesome_board/firmware:my_awesome_bootloader.img",
partition_name = "bootloader",
# The type is used by the board's paver driver to map to a particular
# partition during Over-the-Air (OTA) updates.
type = "",
)
# The main configuration, referencing the partition targets
fuchsia_partitions_configuration(
name = "my_awesome_board",
# `ffx` compares `hardware_revision` to the fastboot variable `hw-revision`,
# and refused to flash the device is they do not match. This ensures that
# the wrong image is not flashed to the wrong board.
hardware_revision = "my_awesome_board_rev1",
bootloader_partitions = [
":my_bootloader",
],
partitions = [
":zircon_a",
":vbmeta_a",
":fxfs",
# ... and other partition targets
],
)
Explanation:
fuchsia_partitiondefines individual partitions like ZBI, VBMeta, and FXFS, specifying their name, type, and slot if applicable.fuchsia_bootloader_partitiondefines bootloader partitions, linking to the bootloader image target. Assembly treats bootloader partitions as "unslotted".- Define a
fuchsia_partitions_configurationtarget that describes the partitions on the device. This is required for all boards.
Including code: Board-specific vs. platform
There are two primary ways to include code in your board configuration:
- Board Input Bundles (BIBs): For code tightly coupled to the board hardware.
- Provided features: For requesting generic capabilities from the Fuchsia platform
Board input bundles (BIBs)
BIBs are used to package board-specific drivers, configurations, and other files
that are unique to the hardware. These are defined using the
fuchsia_board_input_bundle rule. For example:
# //boards/my_awesome_board/BUILD.bazel
load(
"@rules_fuchsia//fuchsia:assembly.bzl",
"fuchsia_board_input_bundle",
)
# BIB for a board-specific compass driver
fuchsia_board_input_bundle(
name = "my-compass",
bootfs_driver_packages = [
"//src/devices/board/drivers/my-compass",
],
)
The BIB can be included in the board configuration using the
board_input_bundles attribute. For example:
# //boards/my_awesome_board/BUILD.bazel
fuchsia_board_configuration(
name = "my_awesome_board",
board_name = "my_awesome_board",
version = "1.2.3.4",
partitions_configuration = "//boards/partitions/my_awesome_board",
board_input_bundles = [
":my-compass", # Reference the BIB target
],
)
It is best practice to create a single BIB for each logical group of hardware
that may also be found on other boards. This allow similar boards to share
BIBs. Examples include compass, paver, rtc, etc.
Provided features
This attribute allows the board to declare that it supports or requires certain platform-level features. The assembly system can then include the necessary platform code based on these flags.
This mechanism decouples the board definition from the implementation details of common platform features. Instead of the board providing the code, it declares the need for it. For example:
# //boards/my_awesome_board/BUILD.bazel
fuchsia_board_configuration(
name = "my_awesome_board",
board_name = "my_awesome_board",
version = "1.2.3.4",
partitions_configuration = "//boards/partitions/my_awesome_board",
provided_features = [
"fuchsia::driver_runtime",
"fuchsia::vulkan_support",
],
)
In this case, the board is stating it has hardware requiring platform-provided runtime drivers and Vulkan support.
Device tree
If your board uses a device tree, you can specify the .dtb binary target using
the devicetree attribute. For example:
# In //boards/my_awesome_board/BUILD.bazel
fuchsia_board_configuration(
name = "my_awesome_board",
board_name = "my_awesome_board",
version = "1.2.3.4",
partitions_configuration = "//boards/partitions/my_awesome_board",
devicetree = "//boards/my_awesome_board/firmware:board.dtb",
)
Filesystem options
The filesystems attribute takes a dictionary to configure various aspects of
the images, such as ZBI compression. For a full list of available options, see
BoardFilesystemConfig. For example:
# In //boards/my_awesome_board/BUILD.bazel
fuchsia_board_configuration(
name = "my_awesome_board",
board_name = "my_awesome_board",
version = "1.2.3.4",
partitions_configuration = "//boards/partitions/my_awesome_board",
filesystems = {
"zbi": {
"compression": "zstd.max",
},
},
)
You can also configure vbmeta signing keys in the filesystems attribute. For
example:
# In //boards/my_awesome_board/BUILD.bazel
fuchsia_board_configuration(
name = "my_awesome_board",
board_name = "my_awesome_board",
version = "1.2.3.4",
partitions_configuration = "//boards/partitions/my_awesome_board",
filesystems = {
"vbmeta": {
"key": "//path/to/my:vbmeta_private_key",
"key_metadata": "//path/to/my:vbmeta_key_metadata",
},
},
)
Post-processing script
If your board requires additional image processing steps after the standard
assembly (e.g., to create a vendor-specific boot image format), you can use the
post_processing_script attribute.
Define a
fuchsia_post_processing_scripttarget. For example:# In //boards/my_awesome_board/BUILD.bazel load( "@rules_fuchsia//fuchsia:assembly.bzl", "fuchsia_post_processing_script", ) fuchsia_post_processing_script( name = "my_post_processing_script", post_processing_script_path = "tools/sign_image.sh", post_processing_script_args = [ "-i", "zbi", "-o", "zbi.signed", ], post_processing_script_inputs = { "//path/to/keys:private_key": "keys/private_key", }, )Reference it in your board configuration. For example:
# In //boards/my_awesome_board/BUILD.bazel fuchsia_board_configuration( name = "my_awesome_board", board_name = "my_awesome_board", version = "1.2.3.4", partitions_configuration = "//boards/partitions/my_awesome_board", post_processing_script = ":my_post_processing_script", )
Next steps
This codelab covered the basics of defining a new board configuration using
Bazel in Fuchsia. You've seen how to use
fuchsia_board_configuration and related
rules to specify everything from drivers to filesystem options.
To continue learning, you can:
- Explore the existing board configurations in the
//boardsdirectory, paying attention to theBUILD.bazelfiles in subdirectories likex64,arm64, andvim3. - Dive deeper into Fuchsia Software Assembly Concepts.