Skip to content

chipsalliance/caliptra-mcu-sw

Repository files navigation

Caliptra MCU firmware and software

Building

Install rustup to manage your Rust toolchain:

curl --proto '=https' --tlsv1.2 -sSf https://sh.rustup.rs | sh

(You may need to open a new shell or source $HOME/.cargo/env.)

Do a full clone of the repository

git clone --recursive https://github.com/chipsalliance/caliptra-mcu-sw.git

Now you should be able to run all checks and builds:

cargo xtask precheckin

Commands such as cargo b and cargo t will also work, but won't execute the extra tests and RISC-V firmware builds.

Documentation

Directory structure

  • emulator/: Emulator to run the ROM and RT firmware
  • rom/: ROM code
  • runtime/: runtime firmware
  • tests/: firmware and end-to-end tests
  • xtask/: all of the tooling for building, checking, and running everything.

Runtime layout

The runtime (or "firmware") uses Tock as the kernel. Any RISC-V code that needs to run in M-mode, e.g., low-level drivers, should run in the Tock board or a capsule loaded by the board.

In Tock, the "board" is the code that runs that does all of the hardware initialization and starts the Tock kernel. The Tock board is essentially a custom a kernel for each SoC.

The applications are higher-level RISC-V code that only interact with the rest of the world through Tock system calls. For instance, an app might be responsible for running a PLDM flow and uses a Tock capsule to interact with the MCTP stack to communicate with the rest of the SoC.

The Tock kernel allows us to run multiple applications at the same time.

Each app and board will be buildable through xtask, which will produce ELF, TAB, or raw binaries, as needed.

runtime/ directory layout

  • apps/: Higher-level applications that the firmware runs in U-mode
    • lib/: shared code for applications, e.g., the Embassy async executor and Tock Future implementation.
  • boards/: Kernels
  • chips/: microcontroller-specific drivers
  • capsules/: kernel modules
  • drivers/: reusable low-level drivers

Policies

  • cargo xtask. All builds, tools, emulators, binaries, etc., should be runnable from cargo xtask for consistency.

  • NO bash or Makefiles. It's Rust / cargo xtask or nothing. This is better for cross-platform compatibility and consistency.

  • no_std-compatible for all ROM / runtime code and libraries

  • Run cargo xtask precheckin before pushing changes. This can be done, for example, by creating a file .git/hooks/pre-push with the contents:

#!/bin/sh
cargo xtask precheckin

Generating Registers from RDL files

You can run the registers RDL to Rust autogenerator as an xtask:

cargo xtask registers-autogen

By default, this generates Rust register files from the pre-defined RDL files contained in the hw/ directory.

If you only want to check the output, you can use --check.

cargo xtask registers-autogen --check

Quickly checking new RDL files

For testing and quick development, can also run additional RDL files directly with the command-line flags. For example, if you want to use the RDL device.rdl (which defines a type devtype) and mount it to the memory location 0x90000000, you can do so with:

cargo xtask registers-autogen --files device.rdl --addrmap devtype@0x90000000

The Autogenerated Root Bus

The register autogenerator generates several pieces of code for each peripheral (corresponding to an RDL instance present in the addrmap):

  • A set of Tock register bit fields
  • A set of Tock registers (for the firmware to use in drivers)
  • A trait used to emulate the peripheral (with default implementations for each method)
  • An emulator_registers_generated::AutoRootBus that maps reads and writes to each peripheral trait

Development

When implementing a new emulator peripheral and firmware driver, the workflow will typically be:

  • Add the RDL files to hw/ (or add a new submodule linking to them)
  • In xtask/src/registers.rs:
    • Add a reference to the new RDL files to parse
    • Create a new addrmap if encessary in the scopes array (if the new instances are not present in the existing addrmaps).
  • Run cargo xtask registers-autogen
  • Implement the new trait for your peripheral in emulator/periph/src
  • Add your new peripheral as an argument to the AutoRootBus in emulator/app/src/main.rs.
  • Implement your driver in runtime/src/ using the autogenerated Tock registers.