diff --git a/BUILD.md b/BUILD.md index 67f6f8508..0c246e9e5 100644 --- a/BUILD.md +++ b/BUILD.md @@ -2,21 +2,6 @@ # Build BitBox02 firmware and bootloader -## Dependencies - -- [HIDAPI](https://github.com/signal11/hidapi) -- [GNU ARM Embedded Toolchain](https://developer.arm.com/open-source/gnu-toolchain/gnu-rm/downloads) -- SEGGER J-Link software - - [All packages and versions](https://www.segger.com/downloads/jlink/#J-LinkSoftwareAndDocumentationPack) - - Newer versions should work, but if not, go to "Older versions" and get version 6.34g - - [OSX package](https://www.segger.com/downloads/jlink/JLink_MacOSX_V630d.pkg) - - [Linux 64bit](https://www.segger.com/downloads/jlink/JLink_Linux_x86_64.tgz) - - [others](https://www.segger.com/downloads/jlink/) -- cmake -- git -- Install the pre-built [protobuf python binary](https://github.com/protocolbuffers/protobuf/releases) - - Then install the included [Python Protocol Buffers](https://github.com/protocolbuffers/protobuf/tree/master/python#installation) runtime library - ## Reporting issues @@ -25,129 +10,218 @@ For security related issues please see [SECURITY.md](SECURITY.md). ## Development environment -### Install development environment as a Docker container +There is a container image with all the build dependencies and there are some +`make` shortcuts to use it. -The container will contain all tools needed to build the project but it is still necessary to get -the J-Link software to flash the bootloader. Run the commands below to build the container and -execute a persistent one. +> [!TIP] +> It is highly recommended to use the container for development. -```sh -make dockerinit -make dockerdev -``` +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. + +### Development Dependencies* + +| Dependency | Version** | +| ---------- | -------- | +| [Arm GNU Toolchain](https://developer.arm.com/downloads/-/gnu-rm) | 8-2018-q4 | +| [HIDAPI](https://github.com/signal11/hidapi) | 0.11.2 | +| [cmake](https://cmake.org/download/) | 3.10 | +| [git](https://git-scm.com/downloads) | 2.34 | +| [Protobuf Compiler](https://github.com/protocolbuffers/protobuf/releases) | 21.2 | +| [Python Probobuf Runtime](https://github.com/protocolbuffers/protobuf/tree/master/python#installation) | 5.27.3 | +| [SEGGER J-Link Software and Documentation Pack](https://www.segger.com/downloads/jlink) | 6.34g | +| Graphviz | 2.42.2 | +| Doxygen | 1.9.1 | +| [cmocka](https://cmocka.org/files/1.1/) | 1.1.5 | -If you do not want to build the docker image locally, or are not working on it, it may be more straightforward to -pull the image from docker instead of building it. This should be a bit faster and there should not be any issues with -`make dockerdev` expecting specific version of the image. +* See the complete list of dependences in the Dockerfile. + +** The versions here are known to be working. Newer versions should +work. + +### Setup containerized environment + +Run the following commands to fetch the container image and run it: ```sh 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. -The docker container will not allow you to access the hosts USB devices by default which means that -it is necessary to flash the device in a terminal not running in docker. +> [!NOTE] +> The current development container is defined in +> [.containerversion](.containerversion). This is the version that is pulled +> with `dockerpull` and built with `dockerinit`. > [!NOTE] -> Current development container is defined in the file `.containerversion` +> `make dockerdev` will enter an already running container if it exists. -The docker container mounts the repo it was launched from, so you can freely edit your fork in your preferred IDE and -the changes will be reflected in the docker container. +Run the following command to build the container: -**It is highly recommended you develop using this docker container as not all of local setup is completely up to date -with every Operating system.** +```sh +make dockerinit +``` + +`dockerinit` is a shortcut to run `docker build`. Use this if you need to +permanently update the container image ([Dockerfile](Dockerfile)). Don't forget +to update the [container version file](.containerversion). + +> [!TIP] +> For temporary changes you should enter the container running `docker exec` +> with user id 0. -### Install development environment on macOS +### Setup development environment on macOS with brew -Make sure you have [Homebrew](https://brew.sh) installed. -Install the dependencies with: +> [!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](https://brew.sh) installed. Install the +dependencies with: ```sh -brew install hidapi cmake protobuf -brew install automake libtool # for building some code in the external/ folder +brew install hidapi cmake protobuf@21 +brew install automake libtool brew tap osx-cross/arm brew install arm-gcc-bin ``` -## Simulator - -The Multi edition firmware can be built as a simulator for linux-amd64. To build it, run: - - make -j simulator +## Contributor instructions -Run it with: +### Check out the repository - ./build-build/bin/simulator +#### 1. Fork the repository on github. -This launches a server simulating the firmware. The send_message tool can connect to it with: +Go to [bitbox02-firmware](https://github.com/bitboxswiss/bitbox02-firmware) and fork the repository. - ./py/send_message.py --simulator +#### 2. Check out your fork -If you choose to create a wallet by restoring a mnemonic, the simulator will automatically use this -mnemonic: +Run the following commands to check out your fork: - boring mistake dish oyster truth pigeon viable emerge sort crash wire portion cannon couple enact box walk height pull today solid off enable tide +```sh +git clone --recurse-submodules git@github.com:/bitbox02-firmware.git +cd bitbox02-firmware +``` -## Instructions +> [!TIP] +> If you have already cloned the repository without the `--recurse-submodules` +> argument, run: +> +> ```sh +> git submodule update --init --recursive +> ``` -Connect the J-Link to the debug pins on the BitBox02 prototype board. +> [!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 +> ``` -Plug in both the J-Link hardware and the BitBox02 device into USB ports on your computer or a hub connected to your computer. +### Build the firmware -Build the firmware: +Run the following commands to enter the container and build the firmware: ```sh -git clone --recurse-submodules https://github.com/BitBoxSwiss/bitbox02-firmware && cd bitbox02-firmware -# or via ssh -git clone --recurse-submodules git@github.com:BitBoxSwiss/bitbox02-firmware.git && cd bitbox02-firmware -make firmware # requires a GNU ARM toolchain for cross-compiling +make dockerdev +make firmware ``` -If you have already cloned the repository without the `--recurse-submodules` argument, run: +> [!TIP] +> If you have multiple cores you can speed up compilation by passing `-j`, for example `-j8`. -```sh -git submodule update --init --recursive -``` +### Build the bootloader -Build the bootloader: +Run the following commands to enter the container and build the bootloader: ```sh +make dockerdev make bootloader ``` -(to create a bootloader for a devdevice or a production device, use `make bootloader-devdevice` or -`make bootloader-production` respectively). +> [!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. + +### Build the simulator -Load the bootloader by JLink (requires JLinkExe in PATH). +The Multi edition firmware can be built as a simulator for linux-amd64. To build it, run: ```sh -make jlink-flash-bootloader +make simulator ``` -You need to install the [BitBox02 Python Library](#BitBox02-Python-library) before you can flash the built firmware. +### Flash instructions + +#### Connect J-Link probe + +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](doc/bb02_v2.10_schematics.pdf) and [Arm JTAG/SWD +interface](https://developer.arm.com/documentation/101636/0100/Debug-and-Trace/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 firmware by the bootloader (requires loading bootloader.bin by JLink, if not already loaded on the device): +#### Flash bootloader using J-Link + +Load the bootloader by JLink (requires `JLinkExe` in `$PATH`). ```sh -make flash-dev-firmware +make jlink-flash-bootloader ``` +> [!NOTE] +> To flash a bootloader for a development device +> `make jlink-flash-bootloader-development`. + +#### Flash firmware using J-Link + Load the firmware by JLink: ```sh make jlink-flash-firmware ``` -### Build reference documentation (Doxygen) +#### Flash firmware using bootloader and python cli client + +> [!TIP] +> This method does not require a J-Link probe while developing. -Dependencies: +Install the [BitBox02 Python CLI client](#bitbox02-python-cli-client). + +Load the firmware through the bootloader: ```sh -brew install graphviz doxygen +make flash-dev-firmware ``` -Build: +### Build reference documentation (Doxygen) ```sh make docs @@ -155,48 +229,106 @@ make docs To view the results, open `build/docs/html/index.html` in a web browser. -### BitBox02 Python library +### Debugging -There is a Python api library in `py/bitbox02`. +#### Debugging using the simulator -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: +Run it with: ```sh -./py/send_message.py +./build-build/bin/simulator ``` -### Unit tests +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 + + +#### Debugging using the J-Link probe and GDB + +The *debug firmware* enables pretty printing of panics over [RTT](https://www.segger.com/products/debug-probes/j-link/technology/about-real-time-transfer/). -We are using CMocka [https://cmocka.org/](https://cmocka.org/) for unit tests. To run the tests, the CMocka library -needs to be installed on your system. +Run the following commands to build the debug firmware. -If you're on a Mac, you can use the brew command to install it: +```sh +make dockerdev +make firmware-debug +``` + +Run the following command to run the J-Link GDB Server. ```sh -brew install cmocka +make jlink-gdb-server ``` -Alternatively, you can get CMocka by cloning the git repository and following these instructions: +> [!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. ```sh -git clone git://git.cryptomilk.org/projects/cmocka.git -cd cmocka -mkdir build && cd build -cmake .. -make && sudo make install +make rtt-client ``` -By default, the library will be installed into /usr/local/lib64 directory under Linux x86\_64. -If the library is not on the library path by default, you might need to export the following environment variable: +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). ```sh -export LD_LIBRARY_PATH=${LD_LIBRARY_PATH}:/usr/local/lib64/ +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](./scripts/jlink.gdb). You may want to modify it if you are debugging +> something specific. + +> [!TIP] +> In debug builds you can use the following functions to log: +> ```c +> util_log(fmt, args...) +> ``` +> ```rust +> use ::util::log::log!(fmt, args...) +> ``` +> in C you can also format with hex using `util_dbg_hex`: +> ```c +> 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: +> ```rust +> let arr = [1, 2]; +> log!("{:02x?}", arr) +> log!("{}", hex::encode(arr)) +> ``` + +### Unit tests + +CMocka [https://cmocka.org/](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: +> ```sh +> export LD_LIBRARY_PATH=${LD_LIBRARY_PATH}:/usr/local/lib64/ +> ``` + Then you can run the tests by executing ```sh @@ -220,9 +352,26 @@ make -C build-build coverage-lcovr ### SCCache / CCache -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: +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' ``` + +## BitBox02 Python Library + +There is a Python api library in `py/bitbox02`. + +### BitBox02 CLI client + +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: + +```sh +./py/send_message.py +```