This directory contains integration tests for the OpenTitan Earlgrey target, running on the Pigweed Maize microkernel.
Each subdirectory here represents a test suite or a specific test target:
drivers/gpio: Tests the GPIO driver functionality, verifying that pins can be configured, read, written, and toggled.eflash: Tests the embedded flash driver operations (erase, program, read) using a secure flash_server userspace process.ipc/user: Tests userspace IPC channel communication between different processes on the microkernel.logging: Tests the microkernel logging subsystems and pw_log routing.threads/kernel: Tests kernel-level threading, context switching, and scheduling invariants.uart: Tests UART driver initialization and loopback communication (using interrupt-driven RX/TX).unittest_runner: Runs the upstream Pigweed kernel unit and integration test suite on the target hardware.usbdev: Tests basic USB device controller initialization and host-side enumeration.usbdfu: Tests USB Device Firmware Upgrade (DFU) protocol, including loopback download/upload verification and certificate reading.usbserial: Tests USB CDC-ACM (Virtual Serial Port) bidirectional data transmission using an echo loop.When writing new integration tests, you can choose between two main patterns depending on whether the test requires host-side interaction (like USB or JTAG) or is self-contained on the target.
Self-contained tests run entirely on the Ibex core and report their results via the UART console. The Bazel test runner (opentitan_test macro) monitors the console output to determine success or failure.
PASS\n in the console output. Ensure your firmware prints this (e.g., pw_log::info!("✅ TEST PASS") or similar) when all assertions succeed.FAIL: .+\n for failures. If an assertion fails or a panic occurs, ensure the output matches this pattern.opentitan_test rule using exit_success and exit_failure attributes.Example firmware structure:
#[entry] fn entry() -> Result<(), Error> { pw_log::info!("🔄 MY_TEST START"); let result = run_my_test_logic(); match result { Ok(()) => { pw_log::info!("PASS"); // Triggers Bazel test success Ok(()) } Err(e) => { pw_log::error!("FAIL: {:?}", e); // Triggers Bazel test failure Err(Error::Unknown) } } }
If your test involves external interfaces (e.g., verifying USB enumeration, DFU transfers, or JTAG operations), you must write a host-based test harness that runs on the host machine and coordinates with the target.
opentitan_rust_binary (which applies the necessary transition for opentitanlib compatibility) and link it via the test_harness attribute of opentitan_test.transport.reset(UartRx::Clear)?) to ensure a clean boot and capture early boot logs.lc_ctrl) and print it to the console (e.g., Serial Number: <hex>) early in the boot sequence. If using USB, also use this Device ID to populate the USB Serial Number string descriptor.device_by_id_with_timeout(vid, pid, Some(serial), timeout)).UartConsole::wait_for to synchronize host actions with target states (e.g., waiting for 🔄 RUNNING before starting USB transfers).