mirror of
https://github.com/google/comprehensive-rust.git
synced 2026-06-21 00:12:59 +02:00
bazel: build and test bare-metal examples
This configures Bazel targets for the bare-metal examples. We now also
have test targets for them:
bazel test //:bare_metal_tests
will compile all the code and run a simple test in QEMU (boot the
binaries, send `"q"` to them on stdin).
The Cargo-based workflow has been kept: I expect that students will
keep using it in class, so we should keep testing it in CI.
This commit is contained in:
@@ -68,6 +68,24 @@ jobs:
|
||||
working-directory: ${{ matrix.directory }}
|
||||
run: cargo build
|
||||
|
||||
bare-metal-test:
|
||||
name: Bare-metal tests
|
||||
runs-on: ubuntu-latest
|
||||
steps:
|
||||
- name: Checkout
|
||||
uses: actions/checkout@v6
|
||||
|
||||
- name: Setup Bazel cache
|
||||
uses: ./.github/workflows/setup-bazel-cache
|
||||
|
||||
- name: Install QEMU
|
||||
uses: ./.github/workflows/apt-get-install
|
||||
with:
|
||||
packages: qemu-system-arm
|
||||
|
||||
- name: Run QEMU tests
|
||||
run: bazel test //:bare_metal_tests
|
||||
|
||||
find-languages:
|
||||
runs-on: ubuntu-latest
|
||||
outputs:
|
||||
|
||||
+20
@@ -0,0 +1,20 @@
|
||||
"""Root BUILD file for Comprehensive Rust workspace.
|
||||
|
||||
This file defines a central test_suite for running manual QEMU tests.
|
||||
"""
|
||||
|
||||
package(default_visibility = ["//visibility:public"])
|
||||
|
||||
test_suite(
|
||||
name = "bare_metal_tests",
|
||||
tags = ["manual"],
|
||||
tests = [
|
||||
"//src/bare-metal/aps/examples:improved_test",
|
||||
"//src/bare-metal/aps/examples:logger_test",
|
||||
"//src/bare-metal/aps/examples:minimal_test",
|
||||
"//src/bare-metal/aps/examples:psci_test",
|
||||
"//src/bare-metal/aps/examples:rt_test",
|
||||
"//src/bare-metal/aps/examples:safemmio_test",
|
||||
"//src/exercises/bare-metal/rtc:rtc_test",
|
||||
],
|
||||
)
|
||||
|
||||
@@ -282,3 +282,115 @@ Use `--mochaOpts.grep` to run a single test within a file:
|
||||
```bash
|
||||
npm test -- --spec redbox --mochaOpts.grep "should be hidden by default"
|
||||
```
|
||||
|
||||
## Bazel Bare-Metal and Microcontroller Integration
|
||||
|
||||
This project integrates Bazel rules for bare-metal AArch64 and microcontroller
|
||||
target platforms. Key findings and conventions include:
|
||||
|
||||
### Checking Bazel Version
|
||||
|
||||
Always check the `.bazelversion` file at the workspace root (e.g., `9.1.1`)
|
||||
before inspecting the host Bazel version.
|
||||
|
||||
### Target Platforms & Constraints
|
||||
|
||||
Bare-metal and microcontroller examples specify target CPU/OS constraint
|
||||
configurations (e.g., `os:none`):
|
||||
|
||||
- `aarch64-unknown-none`: Mapped in `platforms/BUILD.bazel` to
|
||||
`@platforms//os:none` and `@platforms//cpu:aarch64`.
|
||||
- `thumbv7em-none-eabihf`: Mapped to `@platforms//os:none` and
|
||||
`@platforms//cpu:armv7e-mf` (matching rules_rust's internal CPU naming
|
||||
convention).
|
||||
|
||||
### Wildcard Host Builds & Compatibility
|
||||
|
||||
To prevent raw target compilation failures during wildcard host commands (like
|
||||
`bazel build //...` or `bazel test //...`), all target-specific `rust_binary`
|
||||
targets declare compatibility constraints:
|
||||
|
||||
```bazel
|
||||
rust_binary(
|
||||
name = "my_target",
|
||||
...
|
||||
target_compatible_with = ["@platforms//os:none"],
|
||||
)
|
||||
```
|
||||
|
||||
This causes Bazel to automatically skip building these targets on host
|
||||
configurations (where OS is Linux/macOS) instead of failing.
|
||||
|
||||
### Cargo Universe Imports & Host Splicing
|
||||
|
||||
When importing external crates via `rules_rust`'s Cargo Universe
|
||||
(`crate.from_cargo`), the host platform triple (e.g.,
|
||||
`x86_64-unknown-linux-gnu`) must be included in `supported_platform_triples`:
|
||||
|
||||
```bazel
|
||||
crate.from_cargo(
|
||||
...
|
||||
supported_platform_triples = [
|
||||
"x86_64-unknown-linux-gnu",
|
||||
"aarch64-unknown-none",
|
||||
],
|
||||
)
|
||||
```
|
||||
|
||||
Even if the imported dependencies are purely for bare-metal targets,
|
||||
`cargo-bazel` runs on the host during the splicing phase and invokes
|
||||
`cargo tree` to perform feature and dependency resolution. Excluding the host
|
||||
execution platform triple prevents Bazel from resolving a host cargo toolchain,
|
||||
resulting in feature generation failures during the analysis phase.
|
||||
|
||||
### Hermetic Binary Extraction (Objcopy)
|
||||
|
||||
Since host systems may lack target-specific `rust-objcopy` executables, the
|
||||
extraction of `.bin` flat images is managed hermetically inside the Bazel
|
||||
sandbox using a `genrule` target pointing to the nightly compiler's bundled
|
||||
`rust-objcopy` tool:
|
||||
|
||||
```bazel
|
||||
genrule(
|
||||
name = "my_target_bin",
|
||||
srcs = [":my_target"],
|
||||
outs = ["my_target.bin"],
|
||||
cmd = "$(execpath @rust_host_tools_nightly//:rust-objcopy) -O binary $(location :my_target) $@",
|
||||
tools = ["@rust_host_tools_nightly//:rust-objcopy"],
|
||||
)
|
||||
```
|
||||
|
||||
### Host-Executed QEMU Tests, Runners & Platform Transitions
|
||||
|
||||
By default, Bazel test and binary runner targets run on the host system. Since
|
||||
the target binaries require cross-compiling, we use Starlark configuration
|
||||
transitions in `platforms/transition.bzl` (via rules like `aarch64_binary` or
|
||||
`thumbv7em_binary`) to transition the target binary's compilation mode to the
|
||||
target platform while letting the wrapper `sh_test` or `sh_binary` execute on
|
||||
the host:
|
||||
|
||||
```bazel
|
||||
# In platforms/transition.bzl:
|
||||
def _aarch64_transition_impl(settings, attr):
|
||||
return {"//command_line_option:platforms": ["//platforms:aarch64-unknown-none"]}
|
||||
|
||||
# In target BUILD.bazel:
|
||||
aarch64_binary(
|
||||
name = "my_target_bin_aarch64",
|
||||
dep = ":my_target_bin",
|
||||
)
|
||||
|
||||
# Automated host test (non-interactive, pipes 'q'):
|
||||
sh_test(
|
||||
name = "my_target_test",
|
||||
srcs = ["run_test.sh"],
|
||||
data = [":my_target_bin_aarch64"],
|
||||
)
|
||||
|
||||
# Interactive host runner (run via `bazel run`):
|
||||
sh_binary(
|
||||
name = "my_target_run",
|
||||
srcs = ["run_test.sh"],
|
||||
data = [":my_target_bin_aarch64"],
|
||||
)
|
||||
```
|
||||
|
||||
@@ -3,12 +3,26 @@ module(
|
||||
version = "0.1.0",
|
||||
)
|
||||
|
||||
bazel_dep(name = "platforms", version = "1.1.0")
|
||||
bazel_dep(name = "rules_rust", version = "0.70.0")
|
||||
bazel_dep(name = "rules_shell", version = "0.8.0")
|
||||
bazel_dep(name = "toolchains_llvm", version = "1.7.0")
|
||||
|
||||
# Remove when https://github.com/bazelbuild/rules_rust/pull/4019 is
|
||||
# released and we update past version 0.70.0.
|
||||
git_override(
|
||||
module_name = "rules_rust",
|
||||
commit = "d2d856d13f89f234298db1606ece7afd1c3eee1f",
|
||||
remote = "https://github.com/bazelbuild/rules_rust.git",
|
||||
)
|
||||
|
||||
rust = use_extension("@rules_rust//rust:extensions.bzl", "rust")
|
||||
rust.toolchain(
|
||||
edition = "2024",
|
||||
extra_target_triples = [
|
||||
"aarch64-unknown-none",
|
||||
"thumbv7em-none-eabihf",
|
||||
],
|
||||
)
|
||||
use_repo(rust, "rust_toolchains")
|
||||
|
||||
@@ -87,3 +101,62 @@ crate.from_specs(
|
||||
host_tools = "@rust_host_tools_nightly",
|
||||
)
|
||||
use_repo(crate, "svgbob_plugin")
|
||||
|
||||
# Bare-Metal and Microcontroller Examples
|
||||
#
|
||||
# Note: Host triple is required in supported_platform_triples below so
|
||||
# cargo-bazel can invoke cargo tree on the host during splicing.
|
||||
crate.from_cargo(
|
||||
name = "bare_metal_alloc_example",
|
||||
cargo_lockfile = "//src/bare-metal/alloc-example:Cargo.lock",
|
||||
manifests = ["//src/bare-metal/alloc-example:Cargo.toml"],
|
||||
supported_platform_triples = [
|
||||
"x86_64-unknown-linux-gnu",
|
||||
"aarch64-unknown-none",
|
||||
],
|
||||
)
|
||||
use_repo(crate, "bare_metal_alloc_example")
|
||||
|
||||
crate.from_cargo(
|
||||
name = "bare_metal_aps",
|
||||
cargo_lockfile = "//src/bare-metal/aps/examples:Cargo.lock",
|
||||
manifests = ["//src/bare-metal/aps/examples:Cargo.toml"],
|
||||
supported_platform_triples = [
|
||||
"x86_64-unknown-linux-gnu",
|
||||
"aarch64-unknown-none",
|
||||
],
|
||||
)
|
||||
use_repo(crate, "bare_metal_aps")
|
||||
|
||||
crate.from_cargo(
|
||||
name = "bare_metal_microcontrollers",
|
||||
cargo_lockfile = "//src/bare-metal/microcontrollers/examples:Cargo.lock",
|
||||
manifests = ["//src/bare-metal/microcontrollers/examples:Cargo.toml"],
|
||||
supported_platform_triples = [
|
||||
"x86_64-unknown-linux-gnu",
|
||||
"thumbv7em-none-eabihf",
|
||||
],
|
||||
)
|
||||
use_repo(crate, "bare_metal_microcontrollers")
|
||||
|
||||
crate.from_cargo(
|
||||
name = "bare_metal_compass",
|
||||
cargo_lockfile = "//src/exercises/bare-metal/compass:Cargo.lock",
|
||||
manifests = ["//src/exercises/bare-metal/compass:Cargo.toml"],
|
||||
supported_platform_triples = [
|
||||
"x86_64-unknown-linux-gnu",
|
||||
"thumbv7em-none-eabihf",
|
||||
],
|
||||
)
|
||||
use_repo(crate, "bare_metal_compass")
|
||||
|
||||
crate.from_cargo(
|
||||
name = "bare_metal_rtc",
|
||||
cargo_lockfile = "//src/exercises/bare-metal/rtc:Cargo.lock",
|
||||
manifests = ["//src/exercises/bare-metal/rtc:Cargo.toml"],
|
||||
supported_platform_triples = [
|
||||
"x86_64-unknown-linux-gnu",
|
||||
"aarch64-unknown-none",
|
||||
],
|
||||
)
|
||||
use_repo(crate, "bare_metal_rtc")
|
||||
|
||||
Generated
+2262
-595
File diff suppressed because one or more lines are too long
@@ -0,0 +1,33 @@
|
||||
# platforms/BUILD.bazel
|
||||
"""Target Platform Definitions for Embedded Cross-Compilation.
|
||||
|
||||
In Bazel, platforms represent execution and target build environments.
|
||||
We define target platforms by declaring their constraint values (CPU
|
||||
architecture and Operating System). The registered Rust toolchain
|
||||
matches these constraint combinations to determine which
|
||||
compiler/linker options to use:
|
||||
|
||||
- `aarch64-unknown-none` represents AArch64 bare-metal (no OS)
|
||||
environments.
|
||||
|
||||
- `thumbv7em-none-eabihf` represents ARM Cortex-M4F microcontroller
|
||||
environments.
|
||||
"""
|
||||
|
||||
package(default_visibility = ["//visibility:public"])
|
||||
|
||||
platform(
|
||||
name = "aarch64-unknown-none",
|
||||
constraint_values = [
|
||||
"@platforms//os:none",
|
||||
"@platforms//cpu:aarch64",
|
||||
],
|
||||
)
|
||||
|
||||
platform(
|
||||
name = "thumbv7em-none-eabihf",
|
||||
constraint_values = [
|
||||
"@platforms//os:none",
|
||||
"@platforms//cpu:armv7e-mf",
|
||||
],
|
||||
)
|
||||
@@ -0,0 +1,62 @@
|
||||
"""Starlark Configuration Transitions for Cross-Compilation.
|
||||
|
||||
In Bazel, test targets (like sh_test) are host-executed. If the global
|
||||
invocation sets --platforms=//platforms:aarch64-unknown-none, Bazel
|
||||
attempts to run the test runners themselves on the target bare-metal
|
||||
platform. Because there are no test execution toolchains for
|
||||
bare-metal targets, this results in analysis failures.
|
||||
|
||||
To resolve this, we keep the global invocation targeting the host
|
||||
platform, and use these custom rules (aarch64_binary,
|
||||
thumbv7em_binary) to apply a "transition". A transition modifies the
|
||||
configuration (the --platforms flag) for the dependency edge to the
|
||||
target binary. This ensures:
|
||||
|
||||
1. The binaries are always compiled for their specific bare-metal
|
||||
target platform.
|
||||
|
||||
2. The parent test targets (sh_test) are built and run on the host
|
||||
platform.
|
||||
"""
|
||||
|
||||
def _aarch64_transition_impl(settings, attr):
|
||||
return {"//command_line_option:platforms": ["//platforms:aarch64-unknown-none"]}
|
||||
|
||||
_aarch64_transition = transition(
|
||||
implementation = _aarch64_transition_impl,
|
||||
inputs = [],
|
||||
outputs = ["//command_line_option:platforms"],
|
||||
)
|
||||
|
||||
def _transition_rule_impl(ctx):
|
||||
# Retrieve the files from the transitioned target
|
||||
return [DefaultInfo(files = ctx.attr.dep[0][DefaultInfo].files)]
|
||||
|
||||
aarch64_binary = rule(
|
||||
implementation = _transition_rule_impl,
|
||||
attrs = {
|
||||
"dep": attr.label(cfg = _aarch64_transition),
|
||||
"_allowlist_function_transition": attr.label(
|
||||
default = "@bazel_tools//tools/allowlists/function_transition_allowlist",
|
||||
),
|
||||
},
|
||||
)
|
||||
|
||||
def _thumbv7em_transition_impl(settings, attr):
|
||||
return {"//command_line_option:platforms": ["//platforms:thumbv7em-none-eabihf"]}
|
||||
|
||||
_thumbv7em_transition = transition(
|
||||
implementation = _thumbv7em_transition_impl,
|
||||
inputs = [],
|
||||
outputs = ["//command_line_option:platforms"],
|
||||
)
|
||||
|
||||
thumbv7em_binary = rule(
|
||||
implementation = _transition_rule_impl,
|
||||
attrs = {
|
||||
"dep": attr.label(cfg = _thumbv7em_transition),
|
||||
"_allowlist_function_transition": attr.label(
|
||||
default = "@bazel_tools//tools/allowlists/function_transition_allowlist",
|
||||
),
|
||||
},
|
||||
)
|
||||
@@ -0,0 +1,28 @@
|
||||
"""Bazel BUILD file for AArch64 Bare-Metal Allocator Example.
|
||||
|
||||
This package defines the allocator example target. Because this code
|
||||
targets AArch64 bare-metal platforms and not the host OS:
|
||||
|
||||
1. The raw `rust_binary` is constrained using `target_compatible_with`
|
||||
to run only on `os:none` to prevent compilation errors during
|
||||
wildcard host builds.
|
||||
"""
|
||||
|
||||
load("@rules_rust//rust:defs.bzl", "rust_binary")
|
||||
|
||||
package(default_visibility = ["//visibility:public"])
|
||||
|
||||
rust_binary(
|
||||
name = "alloc-example",
|
||||
srcs = ["src/main.rs"],
|
||||
edition = "2024",
|
||||
rustc_flags = [
|
||||
"-C",
|
||||
"linker=rust-lld",
|
||||
],
|
||||
target_compatible_with = ["@platforms//os:none"],
|
||||
deps = [
|
||||
"@bare_metal_alloc_example//:buddy_system_allocator",
|
||||
"@bare_metal_alloc_example//:panic-halt",
|
||||
],
|
||||
)
|
||||
@@ -0,0 +1,373 @@
|
||||
"""Bazel BUILD file for AArch64 Bare-Metal APS Examples.
|
||||
|
||||
This package defines six distinct bare-metal demonstration binaries
|
||||
along with their binary extraction genrules and host-executed QEMU
|
||||
testing scripts. Because this code targets AArch64 bare-metal
|
||||
platforms and not the host OS:
|
||||
|
||||
1. The raw `rust_binary` targets are constrained using
|
||||
`target_compatible_with` to run only on `os:none` to prevent
|
||||
compilation errors during wildcard host builds.
|
||||
|
||||
2. We extract flat binary images via `genrule` targets using the
|
||||
hermetic host toolchain's `rust-objcopy`.
|
||||
|
||||
3. We wrap each binary target in a platform transition
|
||||
(`aarch64_binary`) so they are built for the AArch64 bare-metal
|
||||
target platform during host-executed tests.
|
||||
"""
|
||||
|
||||
load("@rules_rust//rust:defs.bzl", "rust_binary")
|
||||
load("@rules_shell//shell:sh_binary.bzl", "sh_binary")
|
||||
load("@rules_shell//shell:sh_test.bzl", "sh_test")
|
||||
load("//platforms:transition.bzl", "aarch64_binary")
|
||||
|
||||
package(default_visibility = ["//visibility:public"])
|
||||
|
||||
rust_binary(
|
||||
name = "improved",
|
||||
srcs = glob(["src/**/*.rs"]),
|
||||
compile_data = glob(["src/**/*.S"]),
|
||||
crate_root = "src/main_improved.rs",
|
||||
edition = "2024",
|
||||
linker_script = ":image.ld",
|
||||
rustc_flags = [
|
||||
"-C",
|
||||
"linker=rust-lld",
|
||||
],
|
||||
target_compatible_with = ["@platforms//os:none"],
|
||||
deps = [
|
||||
"@bare_metal_aps//:aarch64-paging",
|
||||
"@bare_metal_aps//:aarch64-rt",
|
||||
"@bare_metal_aps//:arm-pl011-uart",
|
||||
"@bare_metal_aps//:bitflags",
|
||||
"@bare_metal_aps//:log",
|
||||
"@bare_metal_aps//:safe-mmio",
|
||||
"@bare_metal_aps//:smccc",
|
||||
"@bare_metal_aps//:spin",
|
||||
"@bare_metal_aps//:zerocopy",
|
||||
],
|
||||
)
|
||||
|
||||
rust_binary(
|
||||
name = "logger",
|
||||
srcs = glob(["src/**/*.rs"]),
|
||||
compile_data = glob(["src/**/*.S"]),
|
||||
crate_root = "src/main_logger.rs",
|
||||
edition = "2024",
|
||||
linker_script = ":image.ld",
|
||||
rustc_flags = [
|
||||
"-C",
|
||||
"linker=rust-lld",
|
||||
],
|
||||
target_compatible_with = ["@platforms//os:none"],
|
||||
deps = [
|
||||
"@bare_metal_aps//:aarch64-paging",
|
||||
"@bare_metal_aps//:aarch64-rt",
|
||||
"@bare_metal_aps//:arm-pl011-uart",
|
||||
"@bare_metal_aps//:bitflags",
|
||||
"@bare_metal_aps//:log",
|
||||
"@bare_metal_aps//:safe-mmio",
|
||||
"@bare_metal_aps//:smccc",
|
||||
"@bare_metal_aps//:spin",
|
||||
"@bare_metal_aps//:zerocopy",
|
||||
],
|
||||
)
|
||||
|
||||
rust_binary(
|
||||
name = "minimal",
|
||||
srcs = glob(["src/**/*.rs"]),
|
||||
compile_data = glob(["src/**/*.S"]),
|
||||
crate_root = "src/main_minimal.rs",
|
||||
edition = "2024",
|
||||
linker_script = ":image.ld",
|
||||
rustc_flags = [
|
||||
"-C",
|
||||
"linker=rust-lld",
|
||||
],
|
||||
target_compatible_with = ["@platforms//os:none"],
|
||||
deps = [
|
||||
"@bare_metal_aps//:aarch64-paging",
|
||||
"@bare_metal_aps//:aarch64-rt",
|
||||
"@bare_metal_aps//:arm-pl011-uart",
|
||||
"@bare_metal_aps//:bitflags",
|
||||
"@bare_metal_aps//:log",
|
||||
"@bare_metal_aps//:safe-mmio",
|
||||
"@bare_metal_aps//:smccc",
|
||||
"@bare_metal_aps//:spin",
|
||||
"@bare_metal_aps//:zerocopy",
|
||||
],
|
||||
)
|
||||
|
||||
rust_binary(
|
||||
name = "psci",
|
||||
srcs = glob(["src/**/*.rs"]),
|
||||
compile_data = glob(["src/**/*.S"]),
|
||||
crate_root = "src/main_psci.rs",
|
||||
edition = "2024",
|
||||
linker_script = ":image.ld",
|
||||
rustc_flags = [
|
||||
"-C",
|
||||
"linker=rust-lld",
|
||||
],
|
||||
target_compatible_with = ["@platforms//os:none"],
|
||||
deps = [
|
||||
"@bare_metal_aps//:aarch64-paging",
|
||||
"@bare_metal_aps//:aarch64-rt",
|
||||
"@bare_metal_aps//:arm-pl011-uart",
|
||||
"@bare_metal_aps//:bitflags",
|
||||
"@bare_metal_aps//:log",
|
||||
"@bare_metal_aps//:safe-mmio",
|
||||
"@bare_metal_aps//:smccc",
|
||||
"@bare_metal_aps//:spin",
|
||||
"@bare_metal_aps//:zerocopy",
|
||||
],
|
||||
)
|
||||
|
||||
rust_binary(
|
||||
name = "rt",
|
||||
srcs = glob(["src/**/*.rs"]),
|
||||
compile_data = glob(["src/**/*.S"]),
|
||||
crate_root = "src/main_rt.rs",
|
||||
edition = "2024",
|
||||
linker_script = ":image.ld",
|
||||
rustc_flags = [
|
||||
"-C",
|
||||
"linker=rust-lld",
|
||||
],
|
||||
target_compatible_with = ["@platforms//os:none"],
|
||||
deps = [
|
||||
"@bare_metal_aps//:aarch64-paging",
|
||||
"@bare_metal_aps//:aarch64-rt",
|
||||
"@bare_metal_aps//:arm-pl011-uart",
|
||||
"@bare_metal_aps//:bitflags",
|
||||
"@bare_metal_aps//:log",
|
||||
"@bare_metal_aps//:safe-mmio",
|
||||
"@bare_metal_aps//:smccc",
|
||||
"@bare_metal_aps//:spin",
|
||||
"@bare_metal_aps//:zerocopy",
|
||||
],
|
||||
)
|
||||
|
||||
rust_binary(
|
||||
name = "safemmio",
|
||||
srcs = glob(["src/**/*.rs"]),
|
||||
compile_data = glob(["src/**/*.S"]),
|
||||
crate_root = "src/main_safemmio.rs",
|
||||
edition = "2024",
|
||||
linker_script = ":image.ld",
|
||||
rustc_flags = [
|
||||
"-C",
|
||||
"linker=rust-lld",
|
||||
],
|
||||
target_compatible_with = ["@platforms//os:none"],
|
||||
deps = [
|
||||
"@bare_metal_aps//:aarch64-paging",
|
||||
"@bare_metal_aps//:aarch64-rt",
|
||||
"@bare_metal_aps//:arm-pl011-uart",
|
||||
"@bare_metal_aps//:bitflags",
|
||||
"@bare_metal_aps//:log",
|
||||
"@bare_metal_aps//:safe-mmio",
|
||||
"@bare_metal_aps//:smccc",
|
||||
"@bare_metal_aps//:spin",
|
||||
"@bare_metal_aps//:zerocopy",
|
||||
],
|
||||
)
|
||||
|
||||
genrule(
|
||||
name = "improved_bin",
|
||||
srcs = [":improved"],
|
||||
outs = ["improved.bin"],
|
||||
cmd = "$(execpath @rust_host_tools_nightly//:rust-objcopy) -O binary $(location :improved) $@",
|
||||
tools = ["@rust_host_tools_nightly//:rust-objcopy"],
|
||||
)
|
||||
|
||||
genrule(
|
||||
name = "logger_bin",
|
||||
srcs = [":logger"],
|
||||
outs = ["logger.bin"],
|
||||
cmd = "$(execpath @rust_host_tools_nightly//:rust-objcopy) -O binary $(location :logger) $@",
|
||||
tools = ["@rust_host_tools_nightly//:rust-objcopy"],
|
||||
)
|
||||
|
||||
genrule(
|
||||
name = "minimal_bin",
|
||||
srcs = [":minimal"],
|
||||
outs = ["minimal.bin"],
|
||||
cmd = "$(execpath @rust_host_tools_nightly//:rust-objcopy) -O binary $(location :minimal) $@",
|
||||
tools = ["@rust_host_tools_nightly//:rust-objcopy"],
|
||||
)
|
||||
|
||||
genrule(
|
||||
name = "psci_bin",
|
||||
srcs = [":psci"],
|
||||
outs = ["psci.bin"],
|
||||
cmd = "$(execpath @rust_host_tools_nightly//:rust-objcopy) -O binary $(location :psci) $@",
|
||||
tools = ["@rust_host_tools_nightly//:rust-objcopy"],
|
||||
)
|
||||
|
||||
genrule(
|
||||
name = "rt_bin",
|
||||
srcs = [":rt"],
|
||||
outs = ["rt.bin"],
|
||||
cmd = "$(execpath @rust_host_tools_nightly//:rust-objcopy) -O binary $(location :rt) $@",
|
||||
tools = ["@rust_host_tools_nightly//:rust-objcopy"],
|
||||
)
|
||||
|
||||
genrule(
|
||||
name = "safemmio_bin",
|
||||
srcs = [":safemmio"],
|
||||
outs = ["safemmio.bin"],
|
||||
cmd = "$(execpath @rust_host_tools_nightly//:rust-objcopy) -O binary $(location :safemmio) $@",
|
||||
tools = ["@rust_host_tools_nightly//:rust-objcopy"],
|
||||
)
|
||||
|
||||
aarch64_binary(
|
||||
name = "improved_bin_aarch64",
|
||||
dep = ":improved_bin",
|
||||
)
|
||||
|
||||
aarch64_binary(
|
||||
name = "logger_bin_aarch64",
|
||||
dep = ":logger_bin",
|
||||
)
|
||||
|
||||
aarch64_binary(
|
||||
name = "minimal_bin_aarch64",
|
||||
dep = ":minimal_bin",
|
||||
)
|
||||
|
||||
aarch64_binary(
|
||||
name = "psci_bin_aarch64",
|
||||
dep = ":psci_bin",
|
||||
)
|
||||
|
||||
aarch64_binary(
|
||||
name = "rt_bin_aarch64",
|
||||
dep = ":rt_bin",
|
||||
)
|
||||
|
||||
aarch64_binary(
|
||||
name = "safemmio_bin_aarch64",
|
||||
dep = ":safemmio_bin",
|
||||
)
|
||||
|
||||
sh_test(
|
||||
name = "improved_test",
|
||||
srcs = ["run_test.sh"],
|
||||
args = ["improved"],
|
||||
tags = [
|
||||
"manual",
|
||||
"qemu",
|
||||
],
|
||||
data = [":improved_bin_aarch64"],
|
||||
)
|
||||
|
||||
sh_test(
|
||||
name = "logger_test",
|
||||
srcs = ["run_test.sh"],
|
||||
args = ["logger"],
|
||||
tags = [
|
||||
"manual",
|
||||
"qemu",
|
||||
],
|
||||
data = [":logger_bin_aarch64"],
|
||||
)
|
||||
|
||||
sh_test(
|
||||
name = "minimal_test",
|
||||
srcs = ["run_test.sh"],
|
||||
args = ["minimal"],
|
||||
tags = [
|
||||
"manual",
|
||||
"qemu",
|
||||
],
|
||||
data = [":minimal_bin_aarch64"],
|
||||
)
|
||||
|
||||
sh_test(
|
||||
name = "psci_test",
|
||||
srcs = ["run_test.sh"],
|
||||
args = ["psci"],
|
||||
tags = [
|
||||
"manual",
|
||||
"qemu",
|
||||
],
|
||||
data = [":psci_bin_aarch64"],
|
||||
)
|
||||
|
||||
sh_test(
|
||||
name = "rt_test",
|
||||
srcs = ["run_test.sh"],
|
||||
args = ["rt"],
|
||||
tags = [
|
||||
"manual",
|
||||
"qemu",
|
||||
],
|
||||
data = [":rt_bin_aarch64"],
|
||||
)
|
||||
|
||||
sh_test(
|
||||
name = "safemmio_test",
|
||||
srcs = ["run_test.sh"],
|
||||
args = ["safemmio"],
|
||||
tags = [
|
||||
"manual",
|
||||
"qemu",
|
||||
],
|
||||
data = [":safemmio_bin_aarch64"],
|
||||
)
|
||||
|
||||
filegroup(
|
||||
name = "bins",
|
||||
srcs = [
|
||||
":improved_bin",
|
||||
":logger_bin",
|
||||
":minimal_bin",
|
||||
":psci_bin",
|
||||
":rt_bin",
|
||||
":safemmio_bin",
|
||||
],
|
||||
)
|
||||
|
||||
sh_binary(
|
||||
name = "improved_run",
|
||||
srcs = ["run_test.sh"],
|
||||
args = ["improved"],
|
||||
data = [":improved_bin_aarch64"],
|
||||
)
|
||||
|
||||
sh_binary(
|
||||
name = "logger_run",
|
||||
srcs = ["run_test.sh"],
|
||||
args = ["logger"],
|
||||
data = [":logger_bin_aarch64"],
|
||||
)
|
||||
|
||||
sh_binary(
|
||||
name = "minimal_run",
|
||||
srcs = ["run_test.sh"],
|
||||
args = ["minimal"],
|
||||
data = [":minimal_bin_aarch64"],
|
||||
)
|
||||
|
||||
sh_binary(
|
||||
name = "psci_run",
|
||||
srcs = ["run_test.sh"],
|
||||
args = ["psci"],
|
||||
data = [":psci_bin_aarch64"],
|
||||
)
|
||||
|
||||
sh_binary(
|
||||
name = "rt_run",
|
||||
srcs = ["run_test.sh"],
|
||||
args = ["rt"],
|
||||
data = [":rt_bin_aarch64"],
|
||||
)
|
||||
|
||||
sh_binary(
|
||||
name = "safemmio_run",
|
||||
srcs = ["run_test.sh"],
|
||||
args = ["safemmio"],
|
||||
data = [":safemmio_bin_aarch64"],
|
||||
)
|
||||
Executable
+22
@@ -0,0 +1,22 @@
|
||||
#!/bin/bash
|
||||
# Copyright 2026 Google LLC
|
||||
# SPDX-License-Identifier: Apache-2.0
|
||||
|
||||
set -euo pipefail
|
||||
|
||||
BIN_NAME="$1"
|
||||
BIN_PATH="src/bare-metal/aps/examples/${BIN_NAME}.bin"
|
||||
# Detect if running as an automated test under 'bazel test'
|
||||
NON_INTERACTIVE="${TEST_SRCDIR:-}"
|
||||
|
||||
if [ ! -f "$BIN_PATH" ]; then
|
||||
echo "Error: Binary not found at $BIN_PATH" >&2
|
||||
exit 1
|
||||
fi
|
||||
|
||||
echo "Running ${BIN_NAME}.bin under QEMU..."
|
||||
if [ -n "$NON_INTERACTIVE" ]; then
|
||||
echo "q" | qemu-system-aarch64 -machine virt -cpu max -serial mon:stdio -display none -kernel "$BIN_PATH"
|
||||
else
|
||||
qemu-system-aarch64 -machine virt -cpu max -serial mon:stdio -display none -kernel "$BIN_PATH"
|
||||
fi
|
||||
@@ -0,0 +1,146 @@
|
||||
"""Bazel BUILD file for ARM Cortex-M Microcontroller Examples.
|
||||
|
||||
This package defines board support and hardware abstraction layer
|
||||
(HAL) binaries for microcontrollers. Because this code targets ARM
|
||||
Cortex-M microcontrollers and not the host OS:
|
||||
|
||||
1. The raw `rust_binary` targets are constrained using
|
||||
`target_compatible_with` to run only on `os:none` to prevent
|
||||
compilation errors during wildcard host builds.
|
||||
"""
|
||||
|
||||
load("@rules_rust//rust:defs.bzl", "rust_binary")
|
||||
|
||||
package(default_visibility = ["//visibility:public"])
|
||||
|
||||
rust_binary(
|
||||
name = "board_support",
|
||||
srcs = glob(["src/bin/**/*.rs"]),
|
||||
crate_root = "src/bin/board_support.rs",
|
||||
edition = "2024",
|
||||
rustc_flags = [
|
||||
"-C",
|
||||
"linker=rust-lld",
|
||||
"-C",
|
||||
"link-arg=-Tlink.x",
|
||||
],
|
||||
target_compatible_with = ["@platforms//os:none"],
|
||||
deps = [
|
||||
"@bare_metal_microcontrollers//:cortex-m-rt",
|
||||
"@bare_metal_microcontrollers//:embedded-hal",
|
||||
"@bare_metal_microcontrollers//:microbit-v2",
|
||||
"@bare_metal_microcontrollers//:nrf52833-hal",
|
||||
"@bare_metal_microcontrollers//:nrf52833-pac",
|
||||
"@bare_metal_microcontrollers//:panic-halt",
|
||||
],
|
||||
)
|
||||
|
||||
rust_binary(
|
||||
name = "hal",
|
||||
srcs = glob(["src/bin/**/*.rs"]),
|
||||
crate_root = "src/bin/hal.rs",
|
||||
edition = "2024",
|
||||
rustc_flags = [
|
||||
"-C",
|
||||
"linker=rust-lld",
|
||||
"-C",
|
||||
"link-arg=-Tlink.x",
|
||||
],
|
||||
target_compatible_with = ["@platforms//os:none"],
|
||||
deps = [
|
||||
"@bare_metal_microcontrollers//:cortex-m-rt",
|
||||
"@bare_metal_microcontrollers//:embedded-hal",
|
||||
"@bare_metal_microcontrollers//:microbit-v2",
|
||||
"@bare_metal_microcontrollers//:nrf52833-hal",
|
||||
"@bare_metal_microcontrollers//:nrf52833-pac",
|
||||
"@bare_metal_microcontrollers//:panic-halt",
|
||||
],
|
||||
)
|
||||
|
||||
rust_binary(
|
||||
name = "minimal",
|
||||
srcs = glob(["src/bin/**/*.rs"]),
|
||||
crate_root = "src/bin/minimal.rs",
|
||||
edition = "2024",
|
||||
rustc_flags = [
|
||||
"-C",
|
||||
"linker=rust-lld",
|
||||
"-C",
|
||||
"link-arg=-Tlink.x",
|
||||
],
|
||||
target_compatible_with = ["@platforms//os:none"],
|
||||
deps = [
|
||||
"@bare_metal_microcontrollers//:cortex-m-rt",
|
||||
"@bare_metal_microcontrollers//:embedded-hal",
|
||||
"@bare_metal_microcontrollers//:microbit-v2",
|
||||
"@bare_metal_microcontrollers//:nrf52833-hal",
|
||||
"@bare_metal_microcontrollers//:nrf52833-pac",
|
||||
"@bare_metal_microcontrollers//:panic-halt",
|
||||
],
|
||||
)
|
||||
|
||||
rust_binary(
|
||||
name = "mmio",
|
||||
srcs = glob(["src/bin/**/*.rs"]),
|
||||
crate_root = "src/bin/mmio.rs",
|
||||
edition = "2024",
|
||||
rustc_flags = [
|
||||
"-C",
|
||||
"linker=rust-lld",
|
||||
"-C",
|
||||
"link-arg=-Tlink.x",
|
||||
],
|
||||
target_compatible_with = ["@platforms//os:none"],
|
||||
deps = [
|
||||
"@bare_metal_microcontrollers//:cortex-m-rt",
|
||||
"@bare_metal_microcontrollers//:embedded-hal",
|
||||
"@bare_metal_microcontrollers//:microbit-v2",
|
||||
"@bare_metal_microcontrollers//:nrf52833-hal",
|
||||
"@bare_metal_microcontrollers//:nrf52833-pac",
|
||||
"@bare_metal_microcontrollers//:panic-halt",
|
||||
],
|
||||
)
|
||||
|
||||
rust_binary(
|
||||
name = "pac",
|
||||
srcs = glob(["src/bin/**/*.rs"]),
|
||||
crate_root = "src/bin/pac.rs",
|
||||
edition = "2024",
|
||||
rustc_flags = [
|
||||
"-C",
|
||||
"linker=rust-lld",
|
||||
"-C",
|
||||
"link-arg=-Tlink.x",
|
||||
],
|
||||
target_compatible_with = ["@platforms//os:none"],
|
||||
deps = [
|
||||
"@bare_metal_microcontrollers//:cortex-m-rt",
|
||||
"@bare_metal_microcontrollers//:embedded-hal",
|
||||
"@bare_metal_microcontrollers//:microbit-v2",
|
||||
"@bare_metal_microcontrollers//:nrf52833-hal",
|
||||
"@bare_metal_microcontrollers//:nrf52833-pac",
|
||||
"@bare_metal_microcontrollers//:panic-halt",
|
||||
],
|
||||
)
|
||||
|
||||
rust_binary(
|
||||
name = "typestate",
|
||||
srcs = glob(["src/bin/**/*.rs"]),
|
||||
crate_root = "src/bin/typestate.rs",
|
||||
edition = "2024",
|
||||
rustc_flags = [
|
||||
"-C",
|
||||
"linker=rust-lld",
|
||||
"-C",
|
||||
"link-arg=-Tlink.x",
|
||||
],
|
||||
target_compatible_with = ["@platforms//os:none"],
|
||||
deps = [
|
||||
"@bare_metal_microcontrollers//:cortex-m-rt",
|
||||
"@bare_metal_microcontrollers//:embedded-hal",
|
||||
"@bare_metal_microcontrollers//:microbit-v2",
|
||||
"@bare_metal_microcontrollers//:nrf52833-hal",
|
||||
"@bare_metal_microcontrollers//:nrf52833-pac",
|
||||
"@bare_metal_microcontrollers//:panic-halt",
|
||||
],
|
||||
)
|
||||
@@ -0,0 +1,33 @@
|
||||
"""Bazel BUILD file for Microcontroller Compass Exercise.
|
||||
|
||||
This package defines the compass exercise target. Because this code
|
||||
targets ARM Cortex-M microcontrollers and not the host OS:
|
||||
|
||||
1. The raw `rust_binary` target is constrained using
|
||||
`target_compatible_with` to run only on `os:none` to prevent
|
||||
compilation errors during wildcard host builds.
|
||||
"""
|
||||
|
||||
load("@rules_rust//rust:defs.bzl", "rust_binary")
|
||||
|
||||
package(default_visibility = ["//visibility:public"])
|
||||
|
||||
rust_binary(
|
||||
name = "compass",
|
||||
srcs = ["src/main.rs"],
|
||||
edition = "2024",
|
||||
rustc_flags = [
|
||||
"-C",
|
||||
"linker=rust-lld",
|
||||
"-C",
|
||||
"link-arg=-Tlink.x",
|
||||
],
|
||||
target_compatible_with = ["@platforms//os:none"],
|
||||
deps = [
|
||||
"@bare_metal_compass//:cortex-m-rt",
|
||||
"@bare_metal_compass//:embedded-hal",
|
||||
"@bare_metal_compass//:lsm303agr",
|
||||
"@bare_metal_compass//:microbit-v2",
|
||||
"@bare_metal_compass//:panic-halt",
|
||||
],
|
||||
)
|
||||
@@ -0,0 +1,85 @@
|
||||
"""Bazel BUILD file for PL031 RTC Bare-Metal Exercise.
|
||||
|
||||
This package defines the bare-metal binary and its binary
|
||||
extraction/testing targets. Because this code runs directly on AArch64
|
||||
hardware (under QEMU) and not the host OS:
|
||||
|
||||
1. The raw `rust_binary` is constrained using `target_compatible_with`
|
||||
to run only on `os:none` to prevent compilation errors during
|
||||
wildcard host builds.
|
||||
|
||||
2. We extract the binary flat image via a `genrule` using the hermetic
|
||||
host toolchain's `rust-objcopy`.
|
||||
|
||||
3. We declare a custom platform transition target (`rtc_bin_aarch64`)
|
||||
to build the binary for the AArch64 bare-metal target platform,
|
||||
allowing host-executed tests to depend on it.
|
||||
"""
|
||||
|
||||
load("@rules_rust//rust:defs.bzl", "rust_binary")
|
||||
load("@rules_shell//shell:sh_binary.bzl", "sh_binary")
|
||||
load("@rules_shell//shell:sh_test.bzl", "sh_test")
|
||||
load("//platforms:transition.bzl", "aarch64_binary")
|
||||
|
||||
package(default_visibility = ["//visibility:public"])
|
||||
|
||||
rust_binary(
|
||||
name = "rtc",
|
||||
srcs = [
|
||||
"src/exceptions.rs",
|
||||
"src/logger.rs",
|
||||
"src/main.rs",
|
||||
"src/pl031.rs",
|
||||
],
|
||||
edition = "2024",
|
||||
linker_script = ":memory.ld",
|
||||
rustc_flags = [
|
||||
"-C",
|
||||
"linker=rust-lld",
|
||||
"-C",
|
||||
"link-arg=-Timage.ld",
|
||||
],
|
||||
target_compatible_with = ["@platforms//os:none"],
|
||||
deps = [
|
||||
"@bare_metal_rtc//:aarch64-paging",
|
||||
"@bare_metal_rtc//:aarch64-rt",
|
||||
"@bare_metal_rtc//:arm-gic",
|
||||
"@bare_metal_rtc//:arm-pl011-uart",
|
||||
"@bare_metal_rtc//:bitflags",
|
||||
"@bare_metal_rtc//:chrono",
|
||||
"@bare_metal_rtc//:log",
|
||||
"@bare_metal_rtc//:safe-mmio",
|
||||
"@bare_metal_rtc//:smccc",
|
||||
"@bare_metal_rtc//:spin",
|
||||
"@bare_metal_rtc//:zerocopy",
|
||||
],
|
||||
)
|
||||
|
||||
genrule(
|
||||
name = "rtc_bin",
|
||||
srcs = [":rtc"],
|
||||
outs = ["rtc.bin"],
|
||||
cmd = "$(execpath @rust_host_tools_nightly//:rust-objcopy) -O binary $(location :rtc) $@",
|
||||
tools = ["@rust_host_tools_nightly//:rust-objcopy"],
|
||||
)
|
||||
|
||||
aarch64_binary(
|
||||
name = "rtc_bin_aarch64",
|
||||
dep = ":rtc_bin",
|
||||
)
|
||||
|
||||
sh_test(
|
||||
name = "rtc_test",
|
||||
srcs = ["rtc_test.sh"],
|
||||
tags = [
|
||||
"manual",
|
||||
"qemu",
|
||||
],
|
||||
data = [":rtc_bin_aarch64"],
|
||||
)
|
||||
|
||||
sh_binary(
|
||||
name = "rtc_run",
|
||||
srcs = ["rtc_test.sh"],
|
||||
data = [":rtc_bin_aarch64"],
|
||||
)
|
||||
Executable
+21
@@ -0,0 +1,21 @@
|
||||
#!/bin/bash
|
||||
# Copyright 2026 Google LLC
|
||||
# SPDX-License-Identifier: Apache-2.0
|
||||
|
||||
set -euo pipefail
|
||||
|
||||
BIN_PATH="src/exercises/bare-metal/rtc/rtc.bin"
|
||||
# Detect if running as an automated test under 'bazel test'
|
||||
NON_INTERACTIVE="${TEST_SRCDIR:-}"
|
||||
|
||||
if [ ! -f "$BIN_PATH" ]; then
|
||||
echo "Error: rtc.bin not found at $BIN_PATH" >&2
|
||||
exit 1
|
||||
fi
|
||||
|
||||
echo "Running rtc.bin under QEMU..."
|
||||
if [ -n "$NON_INTERACTIVE" ]; then
|
||||
echo "q" | qemu-system-aarch64 -machine virt,gic-version=3 -cpu max -serial mon:stdio -display none -kernel "$BIN_PATH"
|
||||
else
|
||||
qemu-system-aarch64 -machine virt,gic-version=3 -cpu max -serial mon:stdio -display none -kernel "$BIN_PATH"
|
||||
fi
|
||||
Reference in New Issue
Block a user