This repository combines all pieces of TwPM code into one build target. For more info about TwPM project go to TwPM's official site.
This repository contains just a bit of glue code and some Makefiles. All of the real code lives in other repositories included as submodules, be sure to clone them as well:
$ git clone https://github.com/Dasharo/TwPM_toplevel.git
$ cd TwPM_toplevel
$ git submodule update --init --checkout
All components are expected to be build within Nix shell. If you haven't got Nix installed yet, follow official installation instructions.
Note: most of commands used require experimental Nix features to be enabled. This can be done permanently by setting
experimental-features = nix-command flakesin your
nix.conf
, or by adding--extra-experimental-features "nix-command flakes"
tonix
command invocations.
Shell can be started by typing:
nix develop
Nix will automatically download all packages and launch shell. Packages from Host OS will still be available. If you want to start a clean environment you can do:
nix-shell --pure $(nix build --no-link --json .#devShells.x86_64-linux.default | jq -r '.[].drvPath')
This environment is still running on your host. If you want clean and isolated environment you can use Docker or Podman to create isolated environment:
nix run .#sdk.copyToDockerDaemon
Note: skopeo (the tool that is used internally for copying image to Docker) does not work with Docker newer than 25.0.0 due to #2202. Until this is solved, you can use the following workaround:
nix run .#sdk.copyTo -- docker-archive:sdk.tar:twpm-sdk:latest docker load < sdk.tar rm sdk.tar
or for Podman:
nix run .#sdk.copyToPodman
Both commands will print name of container:
Copy to Docker daemon image twpm-sdk:40hahn4y8k477rhn006fx524463vkaag
Getting image source signatures
Copying blob 3250b1004e0f done
Copying config 004a96a585 done
Writing manifest to image destination
To run container do:
docker run --rm -it --mount type=tmpfs,destination=/tmp \
-v $PWD:/work -w /work -u $(id -u):$(id -g) \
twpm-sdk:40hahn4y8k477rhn006fx524463vkaag
If you to want to flash device from container you must start it in privileged mode and give access to USB:
docker run --privileged -v /dev/bus/usb:/dev/bus/usb --rm -it \ --mount type=tmpfs,destination=/tmp -v $PWD:/work -w /work \ -u $(id -u):$(id -g) twpm-sdk:40hahn4y8k477rhn006fx524463vkaag
If you want to flash device without sudo
add this to
/etc/udev/rules.d/90-orangecrab.rules
ACTION=="add|change", ATTRS{idVendor}=="1209", ATTRS{idProduct}=="5af0", OWNER="<enter_your_user_name_here>"
Remember to replace
<enter_your_user_name_here>
with your username.
After creating .rules
file type
udevadm control --reload-rules
for changes to take effect.
To build everything at once start TwPM SDK environment as described in the section above and type:
make
This will build TwPM with LPC interface. If you wish to use SPI interface, run this instead:
make spi
There is no automatic detection for switching between SPI and LPC, make clean
must be run when doing so.
Components of TwPM may also be built separately. Such approach is most useful to developers and hackers to quickly test modified code without having to build everything from scratch.
Note that if you already have built whole project earlier, make
should be able
to detect which components have changed and rebuild only those. In that case you
can follow the easy path.
TBD: description of building and hacking TPM stack and platform glue code.
As of now, flashing is done in two separate steps. First part (the FPGA bitstream) is flashed to persistent memory. The second part (TPM software stack) on the other hand is loaded to the memory, and it disappears after power loss. As a consequence, the platform to which the TwPM is connected must be started after that part is loaded. Depending on the platform's firmware, it may be enough to reboot after uploading the software stack, but in some cases platform won't boot without it, or booting may take unreasonably long amount of time.
This limitation will be removed as the project progresses.
To flash firmware enter bootloader mode on OrangeCrab by connecting USB while holding on-board button pressed. Alternatively, RST pin may be shorted to ground instead of reconnecting USB - this is especially useful when many jumper wires are already connected to the platform.
If done properly, the RGB LED will start to alternate between colors. In that state, type:
$ dfu-util -D build/fpga/twpm.dfu
It may return the error after the flashing, due to inability to read status register or request reboot, because the reboot already took place at that point. As long as the progress bar reaches 100%, the bitstream is flashed successfully.
UART is accessible on following pins
Pin | Function |
---|---|
GND | Ground |
0 | RX |
1 | TX |
UART is configured to run at 115200n8 (115200 baud rate, 8 data bits, 1 stop bit, parity off, flow control off).
To connect do
minicom -D /dev/ttyUSB0 -b 115200
Make sure you have UART configured properly: while in Minicom press Ctrl+A O, go to Serial Port Setup menu, make sure that Flow Control is disabled, and make sure data bits, stop bits and parity is configured properly to the same values as listed above.
Currently firmware must be uploaded through UART as there is no support for booting from SPI yet.
Connect UART as described in the section above. Make sure you have programmed the bitstream already.
After powering-on the board you will greated by NEORV32 bootloader:
<< NEORV32 Bootloader >>
BLDV: Nov 24 2023
HWV: 0x01090007
CLK: 0x03010b00
MISA: 0x40801105
XISA: 0x00000c83
SOC: 0x80878003
IMEM: 0x00010000
DMEM: 0x00010000
Autoboot in 3s. Press any key to abort.
Aborted.
Available CMDs:
h: Help
r: Restart
u: Upload
s: Store to flash
l: Load from flash
e: Execute
CMD:>
Press immediately any key to interrupt autoboot process, then press u to enter upload mode.
From another terminal type:
dd if=build/firmware/zephyr_with_header.bin of=/dev/ttyUSB0
/dev/ttyUSB0
is the same UART on which Minicom is running and this command must be executed while Minicom is running.
When update is complete press e to boot. After few seconds you should be greated by TwPM firmware.
That's how full boot log looks like:
<< NEORV32 Bootloader >>
BLDV: Nov 24 2023
HWV: 0x01090007
CLK: 0x03010b00
MISA: 0x40801105
XISA: 0x00000c83
SOC: 0x80878003
IMEM: 0x00010000
DMEM: 0x00010000
Autoboot in 3s. Press any key to abort.
Aborted.
Available CMDs:
h: Help
r: Restart
u: Upload
s: Store to flash
l: Load from flash
e: Execute
CMD:> u
Awaiting neorv32_exe.bin... OK
CMD:> e
Booting from 0x80000000...
*** Booting Zephyr OS build 71194e41ac04 ***
[00:00:00.005,000] <inf> main: Starting TwPM on orangecrab
[00:00:00.006,000] <wrn> nv: TwPM was built with CONFIG_TWPM_NV_EMULATE. Changes are NOT persistent!
[00:00:02.904,000] <inf> nv: NV commit
[00:00:02.905,000] <inf> init: TPM manufacture OK
[00:00:04.599,000] <inf> nv: NV commit
[00:00:04.601,000] <inf> test: TPM command result: {TPM_RC_SUCCESS}
[00:00:04.723,000] <inf> nv: NV commit
[00:00:04.734,000] <inf> test: HASH: 12f411d0eebfb9c4d81df9f1cb10e22e9841a91428ea7f00969fa7f29db0f7fa
Diamond has been used only for development purposes and is not tested as widely as Trellis toolchain.
Lattice Diamond is a proprietary synthesis tool, the tool is available for free, however it requires account registration to obtain license. TwPM FPGA design can be synthesized using Diamond by doing:
make FPGA_TOOLCHAIN=diamond
Diamond is available through Nix as part of TwPM SDK extension, to launch shell with Diamond installed type:
nix develop .#with-diamond
When using Docker/Podman type:
nix run .#sdk-diamond.copyToDockerDaemon
Diamond will check MAC address of NIC so you need to run with --network=host
for license to work. When inside shell set LM_LICENSE_FILE
environment
variable.
Diamond GUI can be launched using
nix run .#diamond
This project was partially funded through the NGI Assure Fund, a fund established by NLnet with financial support from the European Commission's Next Generation Internet programme, under the aegis of DG Communications Networks, Content and Technology under grant agreement No 957073.