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.
A board configuration in Fuchsia encapsulates all the necessary information to build a system image for a specific piece of hardware. This includes:
Board configurations are defined using the fuchsia_board_configuration rule in BUILD.bazel files, typically located within the //boards directory.
Let's explore the key attributes of the fuchsia_board_configuration rule with examples.
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 )
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_partition defines individual partitions like ZBI, VBMeta, and FXFS, specifying their name, type, and slot if applicable.fuchsia_bootloader_partition defines bootloader partitions, linking to the bootloader image target. Assembly treats bootloader partitions as “unslotted”.fuchsia_partitions_configuration target that describes the partitions on the device. This is required for all boards.There are two primary ways to include code in your board configuration:
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", {{"<strong>"}} board_input_bundles = [ ":my-compass", # Reference the BIB target ], {{"</strong>"}} )
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.
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", {{"<strong>"}} provided_features = [ "fuchsia::driver_runtime", "fuchsia::vulkan_support", ], {{"</strong>"}} )
In this case, the board is stating it has hardware requiring platform-provided runtime drivers and Vulkan support.
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", {{"<strong>"}} devicetree = "//boards/my_awesome_board/firmware:board.dtb", {{"</strong>"}} )
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", {{"<strong>"}} filesystems = { "zbi": { "compression": "zstd.max", }, }, {{"</strong>"}} )
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", {{"<strong>"}} filesystems = { "vbmeta": { "key": "//path/to/my:vbmeta_private_key", "key_metadata": "//path/to/my:vbmeta_key_metadata", }, }, {{"</strong>"}} )
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.
fuchsia_post_processing_script target. For example:```bazel
# 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",
},
)
```
```bazel
# 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",
{{"<strong>"}}
post_processing_script = ":my_post_processing_script",
{{"</strong>"}}
)
```
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:
//boards directory, paying attention to the BUILD.bazel files in subdirectories like x64, arm64, and vim3.