For security related issues please see SECURITY.md.
There is a container image with all the build dependencies and there are some
make
shortcuts to use it.
Tip
It is highly recommended to use the container for development.
Accessing USB devices, like the flashing tool and the bitbox, is easier outside of the container. So it is recommended to install the J-Link Software on your development machine to follow the instructions below.
Dependency | Version** |
---|---|
Arm GNU Toolchain | 8-2018-q4 |
HIDAPI | 0.11.2 |
cmake | 3.10 |
git | 2.34 |
Protobuf Compiler | 21.2 |
Python Probobuf Runtime | 5.27.3 |
SEGGER J-Link Software and Documentation Pack | 6.34g |
Graphviz | 2.42.2 |
Doxygen | 1.9.1 |
cmocka | 1.1.5 |
* See the complete list of dependences in the Dockerfile.
** The versions here are known to be working. Newer versions should work.
Run the following commands to fetch the container image and run it:
make dockerpull
make dockerdev
dockerpull
will use docker pull
to fetch the current container image.
dockerdev
will use docker run
and docker exec
to run a container in the
background and enter it. dockerdev
will mount the project root using the same
path inside the container, which lets you use your preferred editor/IDE outside
the container.
Note
The current development container is defined in
.containerversion. This is the version that is pulled
with dockerpull
and built with dockerinit
.
Note
make dockerdev
will enter an already running container if it exists.
Run the following command to build the container:
make dockerinit
dockerinit
is a shortcut to run docker build
. Use this if you need to
permanently update the container image (Dockerfile). Don't forget
to update the container version file.
Tip
For temporary changes you should enter the container running docker exec
with user id 0.
Caution
Brew usually only supports the latest versions of software packages. It is not easy to get a working development environment using brew. Any discrepancies between your environment and the containerized environment may lead to CI build failures, since CI uses the container.
Important
If you use compiler versions different from CI you will not be able to reproducibly build the firmware. Different compilers typically lead to slightly different binary outputs.
Make sure you have Homebrew installed. Install the dependencies with:
brew install hidapi cmake protobuf@21
brew install automake libtool
brew tap osx-cross/arm
brew install arm-gcc-bin
Go to bitbox02-firmware and fork the repository.
Run the following commands to check out your fork:
git clone --recurse-submodules [email protected]:<username>/bitbox02-firmware.git
cd bitbox02-firmware
Tip
If you have already cloned the repository without the --recurse-submodules
argument, run:
git submodule update --init --recursive
Tip
Add the original repo as a second remote so that you can sync the master
branch.
git remote add upstream https://github.com/bitboxswiss/bitbox02-firmware
Run the following commands to enter the container and build the firmware:
make dockerdev
make firmware
Tip
If you have multiple cores you can speed up compilation by passing -j<N>
, for example -j8
.
Run the following commands to enter the container and build the bootloader:
make dockerdev
make bootloader
Note
To create a bootloader for a development or a production device, use make bootloader-devdevice
or make bootloader-production
respectively.
Note
To run unsigned firmwares you need a development bootloader.
The Multi edition firmware can be built as a simulator for linux-amd64. To build it, run:
make simulator
Connect the J-Link probe to the debug pins on the BitBox02 prototype board. The pinout of the board and the Arm JTAG/SWD 10-pin connector can be seen in the table below.
Signal | Bitbox02 # | Arm JTAG/SWD # |
---|---|---|
VCC | 1 | 1 |
CLK | 2 | 4 |
GND | 3 | 3, 5 |
DIO | 4 | 2 |
See bitbox schematics and Arm JTAG/SWD interface
Plug both the J-Link probe and the BitBox02 into the computer using USB. A USB hub can be used.
Load the bootloader by JLink (requires JLinkExe
in $PATH
).
make jlink-flash-bootloader
Note
To flash a bootloader for a development device
make jlink-flash-bootloader-development
.
Load the firmware by JLink:
make jlink-flash-firmware
Tip
This method does not require a J-Link probe while developing.
Install the BitBox02 Python CLI client.
Load the firmware through the bootloader:
make flash-dev-firmware
make docs
To view the results, open build/docs/html/index.html
in a web browser.
Run it with:
./build-build/bin/simulator
This launches a server simulating the firmware. The send_message tool can connect to it with:
./py/send_message.py --simulator
If you choose to create a wallet by restoring a mnemonic, the simulator will automatically use this mnemonic:
boring mistake dish oyster truth pigeon viable emerge sort crash wire portion cannon couple enact box walk height pull today solid off enable tide
The debug firmware enables pretty printing of panics over RTT.
Run the following commands to build the debug firmware.
make dockerdev
make firmware-debug
Run the following command to run the J-Link GDB Server.
make jlink-gdb-server
Important
The J-Link GDB Server must be left running in the background.
Run the following command to connect with telnet to the J-Link GDB Server to see the RTT output.
make rtt-client
Run the following command to run GDB. GDB will connect to the J-Link GDB server, flash the debug firmware and then start execution from the bootloader (as if the device was just plugged in).
make run-debug
Tip
After rebuilding the firmware, exit GDB and rerun run-debug
to flash and reset the device.
Tip
The initial set of GDB commands that are run are specified in the gdb init script. You may want to modify it if you are debugging something specific.
Tip
In debug builds you can use the following functions to log:
util_log(fmt, args...)
use ::util::log::log!(fmt, args...)
in C you can also format with hex using util_dbg_hex
:
uint8_t arr[] = {1,2};
util_log("%s", util_dbg_hex(arr, sizeof(arr)));
in rust you can format with hex using the built in hex formatter or the hex crate:
let arr = [1, 2];
log!("{:02x?}", arr)
log!("{}", hex::encode(arr))
CMocka https://cmocka.org/ is used for mocking in the unit tests. To compile the tests, the CMocka library needs to be installed on your system. CMocka is available through most package managers, like brew and apt.
Note
If you compiled it yourself from souce, the library will, by default, be installed into /usr/local/ directory instead of /usr/. If the library is not on the library path by default, you might need to export the following environment variable:
export LD_LIBRARY_PATH=${LD_LIBRARY_PATH}:/usr/local/lib64/
Then you can run the tests by executing
make run-unit-tests # or make -C build-build test
Rust unit tests, if not invoked via make run-rust-unit-tests
, must be run with
-- --test-threads 1
due to unsafe concurrent access to SafeData
, mock_sd()
and mock_memory()
.
gcovr or lcov/genhtml can be used to generate HTML coverage reports using the following commands:
make coverage # or make -C build-build coverage
make -C build-build coverage-lcovr
The build systems supports sccache/ccache, you just need to have it available in your path. You can install it into your dev container with the following commands:
docker exec -u 0 -it bitbox02-firmware-dev bash -c 'apt update && apt install -y libssl-dev && CARGO_HOME=/opt/cargo cargo install --locked sccache'
There is a Python api library in py/bitbox02
.
Run pip install -r py/requirements.txt
to install the deps (virtualenv recommended).
make -C py/bitbox02
to generate the protobuf files.
To kick off some api calls:
./py/send_message.py