Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
24 changes: 20 additions & 4 deletions MODULE.bazel.lock

Large diffs are not rendered by default.

163 changes: 163 additions & 0 deletions target/earlgrey/tests/bootinfo/BUILD.bazel
Original file line number Diff line number Diff line change
@@ -0,0 +1,163 @@
# Licensed under the Apache-2.0 license
# SPDX-License-Identifier: Apache-2.0

load("@pigweed//pw_kernel/tooling:rust_app.bzl", "rust_app")
load("@pigweed//pw_kernel/tooling:system_image.bzl", "system_image")
load("@pigweed//pw_kernel/tooling:target_codegen.bzl", "target_codegen")
load("@pigweed//pw_kernel/tooling:target_linker_script.bzl", "target_linker_script")
load("@pigweed//pw_kernel/tooling/panic_detector:rust_binary_no_panics_test.bzl", "rust_binary_no_panics_test")
load("@rules_rust//rust:defs.bzl", "rust_binary")
load("//target/earlgrey:defs.bzl", "TARGET_COMPATIBLE_WITH")
load("//target/earlgrey/signing/keys:defs.bzl", "FPGA_ECDSA_KEY", "SILICON_ECDSA_KEY")
load("//target/earlgrey/tooling:opentitan_runner.bzl", "opentitan_test")

package(default_visibility = ["//visibility:public"])

rust_app(
name = "bootinfo",
srcs = [
"bootinfo.rs",
],
codegen_crate_name = "bootinfo_codegen",
edition = "2024",
system_config = "@pigweed//pw_kernel/target:system_config_file",
tags = ["kernel"],
visibility = ["//visibility:public"],
deps = [
"//hal/blocking/flash",
"//services/flash:client",
"//target/earlgrey/util",
"//util/error",
"//util/ipc",
"//util/panic",
"@pigweed//pw_kernel/userspace",
"@pigweed//pw_log/rust:pw_log",
"@pigweed//pw_status/rust:pw_status",
"@rust_crates//:aligned",
"@rust_crates//:base64ct",
"@rust_crates//:sha2",
"@rust_crates//:zerocopy",
],
)

rust_app(
name = "flash_server",
srcs = [
"flash_server.rs",
],
codegen_crate_name = "flash_server_codegen",
edition = "2024",
system_config = "@pigweed//pw_kernel/target:system_config_file",
tags = ["kernel"],
visibility = ["//visibility:public"],
deps = [
"//hal/blocking/flash",
"//services/flash:server",
"//target/earlgrey/drivers:eflash_driver",
"//target/earlgrey/registers:flash_ctrl_core",
"//target/earlgrey/util",
"//util/error",
"//util/ipc",
"//util/panic",
"//util/types",
"@pigweed//pw_kernel/userspace",
"@pigweed//pw_log/rust:pw_log",
"@pigweed//pw_status/rust:pw_status",
],
)

system_image(
name = "bootinfo_image",
apps = [
":bootinfo",
":flash_server",
],
kernel = ":target",
platform = "//target/earlgrey",
system_config = ":system_config",
tags = ["kernel"],
)

target_linker_script(
name = "linker_script",
system_config = ":system_config",
tags = ["kernel"],
template = "//target/earlgrey:linker_script_template",
)

filegroup(
name = "system_config",
srcs = ["system.json5"],
)

target_codegen(
name = "codegen",
arch = "@pigweed//pw_kernel/arch/riscv:arch_riscv",
system_config = ":system_config",
)

rust_binary(
name = "target",
srcs = [
"target.rs",
],
edition = "2024",
tags = ["kernel"],
target_compatible_with = TARGET_COMPATIBLE_WITH,
deps = [
":codegen",
":linker_script",
"//target/earlgrey:entry",
"@pigweed//pw_kernel/arch/riscv:arch_riscv",
"@pigweed//pw_kernel/kernel",
"@pigweed//pw_kernel/subsys/console:console_backend",
"@pigweed//pw_kernel/target:target_common",
"@pigweed//pw_kernel/userspace",
"@pigweed//pw_log/rust:pw_log",
],
)

opentitan_test(
name = "bootinfo_hyper310_test",
ecdsa_key = FPGA_ECDSA_KEY,
environment = "//target/earlgrey/env:hyper310",
interface = "hyper310",
tags = [
"hardware",
"hyper310",
],
target = ":bootinfo_image",
)

opentitan_test(
name = "bootinfo_hyper340_test",
ecdsa_key = FPGA_ECDSA_KEY,
environment = "//target/earlgrey/env:hyper340",
interface = "hyper340",
tags = [
"hardware",
"hyper340",
],
target = ":bootinfo_image",
)

opentitan_test(
name = "bootinfo_silicon_test",
ecdsa_key = SILICON_ECDSA_KEY,
environment = "//target/earlgrey/env:teacup",
interface = "teacup",
tags = [
"earlgrey_silicon",
"hardware",
],
target = ":bootinfo_image",
)

rust_binary_no_panics_test(
name = "no_panics",
apps = [
"bootinfo",
"flash_server",
],
binary = ":bootinfo_image",
)
49 changes: 49 additions & 0 deletions target/earlgrey/tests/bootinfo/README.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,49 @@
# Boot Info Test

The `bootinfo` test suite is a custom userspace application that validates and prints critical chip identity, cryptographic certification, and secure boot state data extracted from retention SRAM and hardware flash INFO partitions.

## Overview of Operation

The test process executes sequentially across three main data sources and safely outputs its findings to the console via `pw_log`:

### 1. Retention SRAM Dump (Boot Log & Reset Reasons)
* Maps and directly reads the 4KiB Retention RAM structure (`0x4060_0000`).
* Verifies the SHA256 checksum guarding the `BootLog` structure using the embedded RustCrypto SHA256 engine.
* Displays the primary and chosen `ROM_EXT` and `BL0` boot slots, firmware domains, software/hardware strap state, minimum security versions, and the chip's current `OwnershipState` (e.g. `LockedOwner`).
* Dumps the 32-bit hardware reset reasons and the last recorded kernel shutdown reason.

### 2. DICE Certificate Extraction
* Connects to the `FlashIpcServer` via userspace IPC channels to safely request Read transactions against Bank 0 Page 9 (the UDS/FactoryCerts page) and Bank 1 Page 9 (containing the `CDI0` and `CDI1` DICE chain certificates).
* Sequentially parses all embedded DER-encoded X.509/CWT personalization certificates using `PersoCertificate::from_bytes`.
* Encodes and PEM-wraps the DER data utilizing the secure, constant-time `base64ct` crate, neatly chunking output into 64-character line-wrapped standard headers.

### 3. Ownership Info Extraction (`OWNER_PAGE_0`)
* Issues IPC reads targeting Flash INFO Bank 1, Page 2 to extract the 2048-byte hardware `owner_block_t`.
* Parses the `TlvHeader` tag, `config_version`, and `update_mode` strings.
* Supports decoding, extracting, and hex-encoding coordinates for all supported OpenTitan public key algorithms:
* **ECDSA P-256**: Hexadecimal `X` and `Y` public coordinates.
* **SPX+ (SLH-DSA)**: Pure or Prehashed SPX data.
* **Hybrid P256 + SPX+**: Combined hexadecimal coordinates for both public key mechanisms in sequence.

## Resilient Hardware Fallback

Physical silicon and FPGA hardware boards (such as the CW340 or CW310) often start with unprovisioned or blank FactoryCerts partitions, which naturally trigger hardware Flash Read Errors (`0x464f0004`) due to ECC integrity mismatches.

To ensure safe and thorough execution on developer workstations, the `bootinfo` test implements resilient error-handlers for all INFO partition reads. Rather than aborting, the test gracefully skips faulted or unprovisioned regions, allowing valid structures (like `CDI_0` or the Ownership page) to be perfectly extracted, dumped, and validated.

## Executing the Test

### To compile the bootinfo image:
```bash
bazel build //target/earlgrey/tests/bootinfo:bootinfo_image
```

### To run on the CW340 (Hyper340 Luna Board) FPGA:
```bash
bazel test //target/earlgrey/tests/bootinfo:bootinfo_hyper340_test
```

### To run on the CW310 (Hyper310 Bergen Board) FPGA:
```bash
bazel test //target/earlgrey/tests/bootinfo:bootinfo_hyper310_test
```
Loading