mirror of
https://github.com/tillitis/tillitis-key1.git
synced 2025-04-24 17:09:21 -04:00
Compare commits
73 Commits
Author | SHA1 | Date | |
---|---|---|---|
![]() |
353d7e9f50 | ||
![]() |
f75620720f | ||
![]() |
fb1269b06e | ||
![]() |
770acc9b38 | ||
![]() |
d0c049cdba | ||
![]() |
7eca72c2c3 | ||
![]() |
d43585ee1a | ||
![]() |
d94387a9e7 | ||
![]() |
7de49d2021 | ||
![]() |
8d8f4c7faf | ||
![]() |
33f14122ad | ||
![]() |
435b1f9d29 | ||
![]() |
16a9e8c367 | ||
![]() |
3dbc31f54c | ||
![]() |
cd1a089763 | ||
![]() |
1d5d721f1e | ||
![]() |
a41360917a | ||
![]() |
b524cd0d6e | ||
![]() |
ad62f6e48f | ||
![]() |
c52442b54c | ||
![]() |
7554787678 | ||
![]() |
77fc5cf578 | ||
![]() |
9e317666d3 | ||
![]() |
df04fd56dd | ||
![]() |
13f40561ab | ||
![]() |
4ba164732d | ||
![]() |
fed9354fe9 | ||
![]() |
d82c3a706e | ||
![]() |
969df46315 | ||
![]() |
0ee971e38c | ||
![]() |
9c0311cdfc | ||
![]() |
d1abaad5da | ||
![]() |
4363637afa | ||
![]() |
5eb020275b | ||
![]() |
24ef39b739 | ||
![]() |
97de5e68fd | ||
![]() |
19ae709c81 | ||
![]() |
dd48b77047 | ||
![]() |
03c0ca7c86 | ||
![]() |
b1047b3618 | ||
![]() |
0b829cc9ee | ||
![]() |
46ef63ee2d | ||
![]() |
0b75d25431 | ||
![]() |
8f2f312531 | ||
![]() |
3126a9c51e | ||
![]() |
9a301403e1 | ||
![]() |
de32c58355 | ||
![]() |
b7ce031bd6 | ||
![]() |
d2c7fb0ba9 | ||
![]() |
179c13e9bf | ||
![]() |
050e0f2673 | ||
![]() |
aedd6102ea | ||
![]() |
f68414c4aa | ||
![]() |
75ad033e03 | ||
![]() |
05bb999759 | ||
![]() |
81ac7bffa0 | ||
![]() |
bb18d5b9e9 | ||
![]() |
8ed16fff6a | ||
![]() |
c292595ee3 | ||
![]() |
361890042a | ||
![]() |
5029eb1d39 | ||
![]() |
04ec938200 | ||
![]() |
bfc43093ec | ||
![]() |
07dc20e4e1 | ||
![]() |
0a634c76da | ||
![]() |
ab4ef5fdf9 | ||
![]() |
f3706dcfcc | ||
![]() |
a0c031eb25 | ||
![]() |
1b9bbc4eba | ||
![]() |
b443359e9c | ||
![]() |
90fca5d3dd | ||
![]() |
0af82ee566 | ||
![]() |
a5ed3cfaa9 |
33
.github/workflows/ci.yaml
vendored
33
.github/workflows/ci.yaml
vendored
@ -10,10 +10,10 @@ on:
|
||||
workflow_dispatch: {}
|
||||
|
||||
jobs:
|
||||
check-firmware:
|
||||
check-formatting:
|
||||
runs-on: ubuntu-latest
|
||||
container:
|
||||
image: ghcr.io/tillitis/tkey-builder:4
|
||||
image: ghcr.io/tillitis/tkey-builder:5rc1
|
||||
steps:
|
||||
- name: checkout
|
||||
uses: actions/checkout@v4
|
||||
@ -26,11 +26,26 @@ jobs:
|
||||
run: |
|
||||
git config --global --add safe.directory "$GITHUB_WORKSPACE"
|
||||
|
||||
- name: check indentation in firmware C code
|
||||
- name: check formatting on Verilog and C
|
||||
working-directory: hw/application_fpga
|
||||
run: |
|
||||
make -C fw/tk1 checkfmt
|
||||
make -C fw/testfw checkfmt
|
||||
make checkfmt
|
||||
|
||||
check-firmware:
|
||||
runs-on: ubuntu-latest
|
||||
container:
|
||||
image: ghcr.io/tillitis/tkey-builder:5rc1
|
||||
steps:
|
||||
- name: checkout
|
||||
uses: actions/checkout@v4
|
||||
with:
|
||||
# fetch-depth: 0
|
||||
persist-credentials: false
|
||||
|
||||
- name: fix
|
||||
# https://github.com/actions/runner-images/issues/6775
|
||||
run: |
|
||||
git config --global --add safe.directory "$GITHUB_WORKSPACE"
|
||||
|
||||
- name: run static analysis on firmware C code
|
||||
working-directory: hw/application_fpga
|
||||
@ -44,7 +59,7 @@ jobs:
|
||||
check-verilog:
|
||||
runs-on: ubuntu-latest
|
||||
container:
|
||||
image: ghcr.io/tillitis/tkey-builder:4
|
||||
image: ghcr.io/tillitis/tkey-builder:5rc1
|
||||
steps:
|
||||
- name: checkout
|
||||
uses: actions/checkout@v4
|
||||
@ -64,7 +79,7 @@ jobs:
|
||||
build-usb-firmware:
|
||||
runs-on: ubuntu-latest
|
||||
container:
|
||||
image: ghcr.io/tillitis/tkey-builder:4
|
||||
image: ghcr.io/tillitis/tkey-builder:5rc1
|
||||
steps:
|
||||
- name: checkout
|
||||
uses: actions/checkout@v4
|
||||
@ -86,7 +101,7 @@ jobs:
|
||||
commit_sha: ${{ github.sha }}
|
||||
runs-on: ubuntu-latest
|
||||
container:
|
||||
image: ghcr.io/tillitis/tkey-builder:4
|
||||
image: ghcr.io/tillitis/tkey-builder:5rc1
|
||||
steps:
|
||||
- name: checkout
|
||||
uses: actions/checkout@v4
|
||||
@ -115,7 +130,7 @@ jobs:
|
||||
needs: build-bitstream
|
||||
runs-on: ubuntu-latest
|
||||
container:
|
||||
image: ghcr.io/tillitis/tkey-builder:4
|
||||
image: ghcr.io/tillitis/tkey-builder:5rc1
|
||||
steps:
|
||||
- name: Checkout
|
||||
uses: actions/checkout@v4
|
||||
|
6
.gitignore
vendored
6
.gitignore
vendored
@ -28,6 +28,10 @@
|
||||
/testbench_verilator*
|
||||
/check.smt2
|
||||
/check.vcd
|
||||
/hw/application_fpga/tkey-libs/libblake2s.a
|
||||
/hw/application_fpga/tkey-libs/libcommon.a
|
||||
/hw/application_fpga/tkey-libs/libcrt0.a
|
||||
/hw/application_fpga/tkey-libs/libmonocypher.a
|
||||
synth.json
|
||||
synth.txt
|
||||
synth.v
|
||||
@ -49,3 +53,5 @@ verilated/
|
||||
.*.swp
|
||||
*.sch-bak
|
||||
*.sim
|
||||
compile_commands.json
|
||||
.cache
|
||||
|
83
README.md
83
README.md
@ -2,6 +2,9 @@
|
||||
|
||||
# Tillitis TKey
|
||||
|
||||
Read about current work in progress
|
||||
[here](#current-work-in-progress-in-this-repository).
|
||||
|
||||
 *The TK1 PCB, also known as
|
||||
TKey.*
|
||||
|
||||
@ -25,11 +28,11 @@ With the right application, the TKey can be used for:
|
||||
|
||||
If you want to know more about Tillitis and the TKey, visit:
|
||||
|
||||
- Main web: https://tillitis.se/
|
||||
- Shop: https://shop.tillitis.se/
|
||||
- Developer Handbook: https://dev.tillitis.se/
|
||||
- Officially supported apps: https://tillitis.se/download/
|
||||
- Other known apps: https://dev.tillitis.se/projects/
|
||||
- Main web: <https://tillitis.se/>
|
||||
- Shop: <https://shop.tillitis.se/>
|
||||
- Developer Handbook: <https://dev.tillitis.se/>
|
||||
- Officially supported apps: <https://tillitis.se/download/>
|
||||
- Other known apps: <https://dev.tillitis.se/projects/>
|
||||
|
||||
All of the TKey software, firmware, FPGA Verilog code, schematics and
|
||||
PCB design files are open source, just like all trustworthy security
|
||||
@ -56,17 +59,71 @@ releases.
|
||||
The TKey PCB [KiCad](https://www.kicad.org/) design files are kept in
|
||||
a separate repository:
|
||||
|
||||
https://github.com/tillitis/tk1-pcba
|
||||
<https://github.com/tillitis/tk1-pcba>
|
||||
|
||||
The TP1 (TKey programmer 1) PCB design files and the firmware sources
|
||||
are kept in:
|
||||
|
||||
https://github.com/tillitis/tp1
|
||||
<https://github.com/tillitis/tp1>
|
||||
|
||||
Note that the TP1 is only used for provisioning the FPGA bitstream
|
||||
into flash or the FPGA configuration memory. It's not necessary if you
|
||||
just want to develop apps for the TKey.
|
||||
|
||||
We use the tkey-libs libraries used for device app development in the
|
||||
firmware, too:
|
||||
|
||||
https://github.com/tillitis/tkey-libs
|
||||
|
||||
but keep our own copy of it in the repo. See below.
|
||||
|
||||
## Building
|
||||
|
||||
Building is probably easiest using make and Podman. Do this to see all
|
||||
targets:
|
||||
|
||||
```
|
||||
cd contrib
|
||||
make
|
||||
```
|
||||
|
||||
Build the entire FPGA bitstream, which includes the firmware, using
|
||||
Podman:
|
||||
|
||||
```
|
||||
cd contrib
|
||||
make run-make
|
||||
```
|
||||
|
||||
See the [Tillitis Developer Handbook](https://dev.tillitis.se) for
|
||||
more.
|
||||
|
||||
## Updating and working with tkey-libs
|
||||
|
||||
A copy of [tkey-libs](https://github.com/tillitis/tkey-libs) is kept
|
||||
in `hw/application_fpga/tkey-libs`. This is mostly to avoid the
|
||||
subtleties of Git submodules.
|
||||
|
||||
If you want to change something in tkey-libs, always change in the
|
||||
upstream library at:
|
||||
|
||||
https://github.com/tillitis/tkey-libs
|
||||
|
||||
You can build with an out-of-tree copy if you set `LIBDIR`, for
|
||||
example:
|
||||
|
||||
```
|
||||
make LIBDIR=~/git/tkey-libs firmware.elf
|
||||
```
|
||||
|
||||
When it's time to update the in-tree tkey-lib first tag the upstream
|
||||
repo with an `fw` prefix, like `fw-1` even if it already has an
|
||||
official version tag.
|
||||
|
||||
Easiest is probably to just remove the tkey-libs directory and then
|
||||
git clone the desired tag. Use the entire repo, but remove the .-files
|
||||
like `.git`, `.github`, et cetera.
|
||||
|
||||
## Measured boot
|
||||
|
||||
The key behind guaranteeing security even as a general computer is the
|
||||
@ -104,3 +161,15 @@ deterministically generate any cryptographic keys it needs.
|
||||
The TKey unconditional measured boot is inspired by, but not exactly
|
||||
the same as part of [TCG
|
||||
DICE](https://trustedcomputinggroup.org/work-groups/dice-architectures/).
|
||||
|
||||
# Current Work in Progress in this repository
|
||||
|
||||
We are updating the FPGA and firmware on TKey as part of the Castor
|
||||
release. This update will simplify TKey’s usage, laying the groundwork
|
||||
for future support of U2F/FIDO authentication.
|
||||
|
||||
You can track our progress through this
|
||||
[milestone](https://github.com/tillitis/tillitis-key1/milestone/1).
|
||||
|
||||
Note that main branch is in development. We try to keep status of main
|
||||
branch updated in the [release notes](/doc/release_notes.md#upcoming-release-castor).
|
||||
|
@ -12,6 +12,7 @@ RUN apt-get -qq update -y \
|
||||
clang-format \
|
||||
clang-tidy \
|
||||
cmake \
|
||||
curl \
|
||||
flex \
|
||||
g++ \
|
||||
gawk \
|
||||
@ -57,109 +58,12 @@ RUN apt-get -qq update -y \
|
||||
zlib1g-dev \
|
||||
&& rm -rf /var/lib/apt/lists/*
|
||||
|
||||
# Enable bash completion
|
||||
RUN sed -i '/#if ! shopt -oq posix; then/ s/^#//' /etc/bash.bashrc
|
||||
RUN sed -i '/# if \[ -f \/usr\/share\/bash-completion\/bash_completion \]; then/ s/^#//' /etc/bash.bashrc
|
||||
RUN sed -i '/# . \/usr\/share\/bash-completion\/bash_completion/ s/^#//' /etc/bash.bashrc
|
||||
RUN sed -i '/# elif \[ -f \/etc\/bash_completion \]; then/ s/^#//' /etc/bash.bashrc
|
||||
RUN sed -i '/# . \/etc\/bash_completion/ s/^#//' /etc/bash.bashrc
|
||||
RUN sed -i '/# fi/ s/^#//' /etc/bash.bashrc
|
||||
RUN sed -i '/#fi/ s/^#//' /etc/bash.bashrc
|
||||
|
||||
FROM base as toolsbuilder
|
||||
|
||||
RUN git clone --depth=1 https://github.com/YosysHQ/icestorm /src
|
||||
WORKDIR /src
|
||||
RUN git checkout 738af822905fdcf0466e9dd784b9ae4b0b34987f \
|
||||
&& make -j$(nproc --ignore=2) \
|
||||
&& make install \
|
||||
&& git describe --all --always --long --dirty > /usr/local/repo-commit-icestorm
|
||||
WORKDIR /
|
||||
RUN rm -rf /src
|
||||
COPY buildtools.sh /buildtools.sh
|
||||
COPY verible.sha512 /verible.sha512
|
||||
|
||||
# Custom iceprog for the RPi 2040-based programmer (will be upstreamed).
|
||||
RUN git clone -b interfaces --depth=1 https://github.com/tillitis/icestorm /src
|
||||
WORKDIR /src/iceprog
|
||||
RUN make -j$(nproc --ignore=2) \
|
||||
&& make PROGRAM_PREFIX=tillitis- install \
|
||||
&& git describe --all --always --long --dirty > /usr/local/repo-commit-tillitis--icestorm
|
||||
WORKDIR /
|
||||
RUN rm -rf /src
|
||||
|
||||
RUN git clone -b 0.45 --depth=1 https://github.com/YosysHQ/yosys /src
|
||||
WORKDIR /src
|
||||
RUN git submodule update --init \
|
||||
&& make -j$(nproc --ignore=2) \
|
||||
&& make install \
|
||||
&& git describe --all --always --long --dirty > /usr/local/repo-commit-yosys
|
||||
WORKDIR /
|
||||
RUN rm -rf /src
|
||||
|
||||
RUN git clone -b nextpnr-0.7 https://github.com/YosysHQ/nextpnr /src
|
||||
WORKDIR /src
|
||||
# Add "Fix handling of RNG seed" #1369
|
||||
RUN git cherry-pick --no-commit 6ca64526bb18ace8690872b09ca1251567c116de
|
||||
# Add early exit if place fails on timing
|
||||
RUN sed -i \
|
||||
'345i \ \ \ \ general.add_options()("exit-on-failed-target-frequency",' \
|
||||
common/kernel/command.cc
|
||||
RUN sed -i \
|
||||
'346i \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ "exit if target frequency is not achieved (use together with "' \
|
||||
common/kernel/command.cc
|
||||
RUN sed -i \
|
||||
'347i \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ "--randomize-seed option)");' \
|
||||
common/kernel/command.cc
|
||||
RUN sed -i \
|
||||
'348i \\' \
|
||||
common/kernel/command.cc
|
||||
RUN sed -i \
|
||||
'662s/if (do_route) {/if (do_route \&\& (vm.count("exit-on-failed-target-frequency") ? !had_nonfatal_error : true)) {/' \
|
||||
common/kernel/command.cc
|
||||
RUN sed -i \
|
||||
'244s/bool warn_on_failure = false/bool warn_on_failure = true/' \
|
||||
common/kernel/timing.h
|
||||
RUN cmake -DARCH=ice40 . \
|
||||
&& make -j$(nproc --ignore=2) \
|
||||
&& make install \
|
||||
&& git describe --all --always --long --dirty > /usr/local/repo-commit-nextpnr
|
||||
WORKDIR /
|
||||
RUN rm -rf /src
|
||||
|
||||
RUN git clone -b v12_0 --depth=1 https://github.com/steveicarus/iverilog /src
|
||||
WORKDIR /src
|
||||
RUN sh autoconf.sh \
|
||||
&& ./configure \
|
||||
&& make -j$(nproc --ignore=2) \
|
||||
&& make install \
|
||||
&& git describe --all --always --long --dirty > /usr/local/repo-commit-iverilog
|
||||
WORKDIR /
|
||||
RUN rm -rf /src
|
||||
|
||||
RUN git clone -b v5.028 --depth=1 https://github.com/verilator/verilator /src
|
||||
WORKDIR /src
|
||||
RUN autoconf \
|
||||
&& ./configure \
|
||||
&& make -j$(nproc --ignore=2) \
|
||||
&& make test \
|
||||
&& make install \
|
||||
&& git describe --all --always --long --dirty > /usr/local/repo-commit-verilator
|
||||
WORKDIR /
|
||||
RUN rm -rf /src
|
||||
|
||||
ADD https://github.com/chipsalliance/verible/releases/download/v0.0-3795-gf4d72375/verible-v0.0-3795-gf4d72375-linux-static-x86_64.tar.gz /src/verible.tar.gz
|
||||
WORKDIR /src
|
||||
RUN tar xvf verible.tar.gz
|
||||
RUN mv -v verible*/bin/* /usr/local/bin
|
||||
RUN verible-verilog-format --version | head -1 > /usr/local/repo-commit-verible
|
||||
WORKDIR /
|
||||
RUN rm -rf /src
|
||||
|
||||
RUN git clone -b v1.9.1 https://github.com/cocotb/cocotb.git /src
|
||||
WORKDIR /src
|
||||
RUN pip install . --break-system-packages \
|
||||
&& git describe --all --always --long --dirty > /usr/local/repo-commit-cocotb
|
||||
WORKDIR /
|
||||
RUN rm -rf /src
|
||||
RUN /buildtools.sh
|
||||
|
||||
FROM base
|
||||
LABEL org.opencontainers.image.description="Toolchain for building TKey FPGA bitstream"
|
||||
|
@ -5,7 +5,7 @@
|
||||
BUILDIMAGE=tkey-builder-local
|
||||
|
||||
# default image used when running a container
|
||||
IMAGE=ghcr.io/tillitis/tkey-builder:4
|
||||
IMAGE=ghcr.io/tillitis/tkey-builder:5rc1
|
||||
|
||||
all:
|
||||
@echo "Targets:"
|
||||
@ -23,11 +23,11 @@ all:
|
||||
|
||||
run:
|
||||
podman run --rm --mount type=bind,source="`pwd`/../",target=/build -w /build -it \
|
||||
$(IMAGE) /usr/bin/bash
|
||||
$(IMAGE) /usr/bin/bash -l
|
||||
|
||||
docker-run:
|
||||
docker run --rm --mount type=bind,source="`pwd`/../",target=/build -w /build -it \
|
||||
$(IMAGE) /usr/bin/bash
|
||||
$(IMAGE) /usr/bin/bash -l
|
||||
|
||||
run-make:
|
||||
podman run --rm --mount type=bind,source="`pwd`/../hw/application_fpga",target=/build -w /build -it \
|
||||
|
134
contrib/buildtools.sh
Executable file
134
contrib/buildtools.sh
Executable file
@ -0,0 +1,134 @@
|
||||
#! /bin/sh -e
|
||||
|
||||
# Copyright (C) 2025 Tillitis AB
|
||||
# SPDX-License-Identifier: GPL-2.0-only
|
||||
|
||||
## Build the specific versions of the tools we need to build the TKey
|
||||
## FPGA bitstream and apps.
|
||||
|
||||
cd /
|
||||
mkdir src
|
||||
|
||||
# ----------------------------------------------------------------------
|
||||
# Project icestorm
|
||||
# ----------------------------------------------------------------------
|
||||
git clone https://github.com/YosysHQ/icestorm /src/icestorm
|
||||
cd /src/icestorm
|
||||
|
||||
# No tags or releases yet. Pin down to a specific commit.
|
||||
git checkout 738af822905fdcf0466e9dd784b9ae4b0b34987f
|
||||
make -j$(nproc --ignore=2)
|
||||
make install
|
||||
git describe --all --always --long --dirty > /usr/local/repo-commit-icestorm
|
||||
|
||||
# ----------------------------------------------------------------------
|
||||
# Our own custom iceprog for the RPi 2040-based programmer. Will be
|
||||
# upstreamed.
|
||||
# ----------------------------------------------------------------------
|
||||
git clone -b interfaces --depth=1 https://github.com/tillitis/icestorm /src/icestorm-tillitis
|
||||
cd /src/icestorm-tillitis/iceprog
|
||||
make -j$(nproc --ignore=2)
|
||||
make PROGRAM_PREFIX=tillitis- install
|
||||
git describe --all --always --long --dirty > /usr/local/repo-commit-tillitis--icestorm
|
||||
|
||||
# ----------------------------------------------------------------------
|
||||
# yosys
|
||||
# ----------------------------------------------------------------------
|
||||
git clone -b 0.45 --depth=1 https://github.com/YosysHQ/yosys /src/yosys
|
||||
cd /src/yosys
|
||||
|
||||
# Make sure the digest is correct and no history has changed
|
||||
git checkout 9ed031ddd588442f22be13ce608547a5809b62f0
|
||||
|
||||
git submodule update --init
|
||||
make -j$(nproc --ignore=2)
|
||||
make install
|
||||
git describe --all --always --long --dirty > /usr/local/repo-commit-yosys
|
||||
|
||||
# ----------------------------------------------------------------------
|
||||
# nextpnr
|
||||
# ----------------------------------------------------------------------
|
||||
git clone -b nextpnr-0.7 https://github.com/YosysHQ/nextpnr /src/nextpnr
|
||||
cd /src/nextpnr
|
||||
# Make sure the digest is correct and no history has changed
|
||||
git checkout 73b7de74a5769095acb96eb6c6333ffe161452f2
|
||||
|
||||
# Add "Fix handling of RNG seed" #1369
|
||||
git cherry-pick --no-commit 6ca64526bb18ace8690872b09ca1251567c116de
|
||||
|
||||
# Add early exit if place fails on timing
|
||||
sed -i \
|
||||
'345i \ \ \ \ general.add_options()("exit-on-failed-target-frequency",' \
|
||||
common/kernel/command.cc
|
||||
sed -i \
|
||||
'346i \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ "exit if target frequency is not achieved (use together with "' \
|
||||
common/kernel/command.cc
|
||||
sed -i \
|
||||
'347i \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ "--randomize-seed option)");' \
|
||||
common/kernel/command.cc
|
||||
sed -i \
|
||||
'348i \\' \
|
||||
common/kernel/command.cc
|
||||
sed -i \
|
||||
'662s/if (do_route) {/if (do_route \&\& (vm.count("exit-on-failed-target-frequency") ? !had_nonfatal_error : true)) {/' \
|
||||
common/kernel/command.cc
|
||||
sed -i \
|
||||
'244s/bool warn_on_failure = false/bool warn_on_failure = true/' \
|
||||
common/kernel/timing.h
|
||||
|
||||
cmake -DARCH=ice40 .
|
||||
make -j$(nproc --ignore=2)
|
||||
make install
|
||||
git describe --all --always --long --dirty > /usr/local/repo-commit-nextpnr
|
||||
|
||||
# ----------------------------------------------------------------------
|
||||
# icarus verilog
|
||||
# ----------------------------------------------------------------------
|
||||
git clone -b v12_0 --depth=1 https://github.com/steveicarus/iverilog /src/iverilog
|
||||
cd /src/iverilog
|
||||
|
||||
# Make sure the digest is correct and no history has changed
|
||||
git checkout 4fd5291632232fbe1ba49b2c26bb6b2bf1c6c9cf
|
||||
sh autoconf.sh
|
||||
./configure
|
||||
make -j$(nproc --ignore=2)
|
||||
make install
|
||||
git describe --all --always --long --dirty > /usr/local/repo-commit-iverilog
|
||||
|
||||
# ----------------------------------------------------------------------
|
||||
# verilator
|
||||
# ----------------------------------------------------------------------
|
||||
git clone -b v5.028 --depth=1 https://github.com/verilator/verilator /src/verilator
|
||||
cd /src/verilator
|
||||
|
||||
# Make sure the digest is correct and no history has changed
|
||||
git checkout 8ca45df9c75c611989ae5bfc4112a32212c3dacf
|
||||
|
||||
autoconf
|
||||
./configure
|
||||
make -j$(nproc --ignore=2)
|
||||
make test
|
||||
make install
|
||||
git describe --all --always --long --dirty > /usr/local/repo-commit-verilator
|
||||
|
||||
# ----------------------------------------------------------------------
|
||||
# verible
|
||||
# ----------------------------------------------------------------------
|
||||
curl --output /src/verible.tar.gz -L https://github.com/chipsalliance/verible/releases/download/v0.0-3795-gf4d72375/verible-v0.0-3795-gf4d72375-linux-static-x86_64.tar.gz
|
||||
|
||||
# Check against the expected digest
|
||||
sha512sum -c /verible.sha512
|
||||
|
||||
cd /src
|
||||
|
||||
tar xvf verible.tar.gz
|
||||
mv -v verible*/bin/* /usr/local/bin
|
||||
verible-verilog-format --version | head -1 > /usr/local/repo-commit-verible
|
||||
|
||||
# ----------------------------------------------------------------------
|
||||
# cocotb
|
||||
# ----------------------------------------------------------------------
|
||||
git clone -b v1.9.1 https://github.com/cocotb/cocotb.git /src/cocotb
|
||||
cd /src/cocotb
|
||||
pip install . --break-system-packages
|
||||
git describe --all --always --long --dirty > /usr/local/repo-commit-cocotb
|
1
contrib/verible.sha512
Normal file
1
contrib/verible.sha512
Normal file
@ -0,0 +1 @@
|
||||
3e997b8cd494556fa107b96a6daa4e51133208a85b3c0250c0223d7194aedbc98b3f5213fedaee083edd96c317e50057aa9cdc0517197f4638be3834133e2c9f /src/verible.tar.gz
|
@ -2,6 +2,134 @@
|
||||
|
||||
Descriptions of the tagged TKey releases.
|
||||
|
||||
## Upcoming release: Castor
|
||||
|
||||
Overview of changes since TK TK1-24.03 for the Castor milestone so
|
||||
far.
|
||||
|
||||
**Note well**: BREAKING CHANGE! Older device apps WILL NOT WORK.
|
||||
|
||||
The introduction of the USB Mode Protocol between the programs running
|
||||
on the PicoRV32 CPU and the CH552 means that device apps that have not
|
||||
been changed to use the protocol will not have any way to communicate
|
||||
with the outside world.
|
||||
|
||||
### General
|
||||
|
||||
- Split repo:
|
||||
|
||||
- tk1, mta1-usb-dev, mta-usb-v1 and mta1-library moves to
|
||||
https://github.com/tillitis/tk1-pcba
|
||||
|
||||
- tp1, mta1-usb-programmer, mta1-library and KiCad-RP Pico moves to
|
||||
https://github.com/tillitis/tp1
|
||||
|
||||
For full change log [see](https://github.com/tillitis/tillitis-key1/compare/TK1-23.03.2...coming-tag)
|
||||
|
||||
### FPGA
|
||||
|
||||
- Security Monitor memory access checks are now more complete.
|
||||
|
||||
- Add SPI main controller mainly to access flash.
|
||||
|
||||
- Add system reset API. Device apps can reset the system and restart
|
||||
the firmware. The FPGA is not reset.
|
||||
|
||||
- Increase clock frequence to 24 MHz.
|
||||
|
||||
- Increase UART baudrate to 500,000.
|
||||
|
||||
- Fix missing clock cycles in timer core.
|
||||
|
||||
- Remove the UART runtime configuration API.
|
||||
|
||||
- Several clean ups and testbench changes.
|
||||
|
||||
- Make Verilator simulation work again.
|
||||
|
||||
- Add hardware clear to send (CTS) signals for communication between
|
||||
UART and CH552.
|
||||
|
||||
- Increase size of ROM and FW\_RAM.
|
||||
|
||||
- Make ROM non-executable in app mode.
|
||||
|
||||
- Remove support for access to the firmware blake2s() function from
|
||||
apps.
|
||||
|
||||
- Automatically leave firmware mode when execution leaves ROM and
|
||||
remove the now unnecessary APP\_MODE\_CTRL register.
|
||||
|
||||
- Add extra protection of UDS: When execution leaves ROM the first
|
||||
time, UDS is hardware protected from reading, as well as already
|
||||
existing UDS protection after first read and UDS being unreadable in
|
||||
app mode.
|
||||
|
||||
- Introduce interrupt handler for hardware-based privilege raising for
|
||||
system calls.
|
||||
|
||||
### Firmware
|
||||
|
||||
- At startup, fill RAM with random data using the xorwow PRNG, seeded
|
||||
by TRNG.
|
||||
|
||||
- Add support for the new USB Mode Protocol to communicate with
|
||||
different endpoints.
|
||||
|
||||
- Introduce a system call mechanism and the first syscalls: RESET,
|
||||
SET\_LED, GET\_VIDPID.
|
||||
|
||||
### CH552
|
||||
|
||||
- Use the new CTS signals for communication over the UART.
|
||||
|
||||
- Add support for two HID endpoints.
|
||||
|
||||
- Add protocol to communicate with the three different endpoints: CDC,
|
||||
HID, debug.
|
||||
|
||||
- Change USB frame sending from a software timer to instead be
|
||||
controlled by the USB Controller Protocol.
|
||||
|
||||
Note that to update the CH552 firmware you will need something like
|
||||
the Blinkinlabs CH55x Reset Controller:
|
||||
|
||||
https://shop-nl.blinkinlabs.com/products/ch55x-reset-controller
|
||||
|
||||
https://github.com/Blinkinlabs/ch55x_programmer
|
||||
|
||||
### tkey-builder
|
||||
|
||||
- New versions of:
|
||||
- clang (18.1.3, part of ubuntu 24.04)
|
||||
- icestorm (commit 738af822905fdcf0466e9dd784b9ae4b0b34987f
|
||||
)
|
||||
- yosys (0.45)
|
||||
- nextpnr (0.7) + extra patches for RNG seed handling and early exit
|
||||
- iverilog (v12)
|
||||
- verilator (v5.028)
|
||||
- verible (v0.0-3795)
|
||||
- cocotb (v1.9.1)
|
||||
|
||||
- Remove TKey Programmer (TP) toolchain:
|
||||
|
||||
- gcc-arm-none-eabi: Used for the TKey Programmer firmware, now
|
||||
moved to it's own repo.
|
||||
- libnewlib-arm-none-eabi
|
||||
- libstdc++-arm-none-eabi-newlib
|
||||
- pico-sdk
|
||||
|
||||
TP1 is now in https://github.com/tillitis/tp1
|
||||
|
||||
- Remove Go compiler support.
|
||||
|
||||
### Docs
|
||||
|
||||
- All docs now in READMEs close to the design or code.
|
||||
|
||||
- Protocol docs moved to [the Developer
|
||||
Handbook](https://dev.tillitis.se/)
|
||||
[repo](https://github.com/tillitis/dev-tillitis)
|
||||
|
||||
## TK1-24.03
|
||||
|
||||
|
@ -115,8 +115,8 @@ allowed
|
||||
* Access to compute resources. Possibly access to lab equipment
|
||||
* Will try all possible SW and HW attack vectors. In and out of scope
|
||||
* End game is to find flaws in threat model. Acquire knowledge and
|
||||
findings to produce an interesting talk at CCC, USENIX or Security
|
||||
Fest
|
||||
findings to produce an interesting talk at Chaos Communication
|
||||
Congress, USENIX or Security Fest
|
||||
|
||||
Over time (with new releases), and given feedback by the CCC Hacker,
|
||||
the TKey device should be able to withstand attacks by the CCC Hacker.
|
||||
@ -258,7 +258,7 @@ information, see the [Release Notes](/doc/release_notes.md)
|
||||
Note that this mitigates an attack from outside the CPU, not from
|
||||
an exploit towards applications running on it.
|
||||
|
||||
#### Known possible weakneses
|
||||
#### Known possible weaknesses
|
||||
|
||||
The CH552 MCU providing USB host communication contains firmware that
|
||||
implements the UART communication with the FPGA. The CH552 firmware
|
||||
@ -297,7 +297,7 @@ board, and is even shipped with a programmer to download new FPGA
|
||||
bitstreams.
|
||||
|
||||
|
||||
#### Known weakneses
|
||||
#### Known weaknesses
|
||||
|
||||
The bitstream, which includes the Unique Device Secret (UDS) as well
|
||||
as the firmware implementing the measured boot are stored as part of
|
||||
|
@ -32,7 +32,7 @@ TARGET_FREQ ?= 24
|
||||
|
||||
# Size in 32-bit words, must be divisible by 256 (pairs of EBRs, because 16
|
||||
# bits wide; an EBR is 128 32-bits words)
|
||||
BRAM_FW_SIZE ?= 1536
|
||||
BRAM_FW_SIZE ?= 2048
|
||||
|
||||
PIN_FILE ?= application_fpga_tk1.pcf
|
||||
|
||||
@ -41,13 +41,15 @@ OBJCOPY ?= llvm-objcopy
|
||||
|
||||
CC = clang
|
||||
|
||||
LIBDIR ?= tkey-libs
|
||||
|
||||
CFLAGS = \
|
||||
-target riscv32-unknown-none-elf \
|
||||
-march=rv32iczmmul \
|
||||
-mabi=ilp32 \
|
||||
-static \
|
||||
-std=gnu99 \
|
||||
-O2 \
|
||||
-Os \
|
||||
-ffast-math \
|
||||
-fno-common \
|
||||
-fno-builtin-printf \
|
||||
@ -59,7 +61,9 @@ CFLAGS = \
|
||||
-Wpedantic \
|
||||
-Wno-language-extension-token \
|
||||
-flto \
|
||||
-g
|
||||
-g \
|
||||
-I $(LIBDIR)/include \
|
||||
-I $(LIBDIR)
|
||||
|
||||
AS = clang
|
||||
|
||||
@ -67,7 +71,8 @@ ASFLAGS = \
|
||||
-target riscv32-unknown-none-elf \
|
||||
-march=rv32iczmmul \
|
||||
-mabi=ilp32 \
|
||||
-mno-relax
|
||||
-mno-relax \
|
||||
-I $(LIBDIR)/include
|
||||
|
||||
ICE40_SIM_CELLS = $(shell yosys-config --datdir/ice40/cells_sim.v)
|
||||
|
||||
@ -113,36 +118,25 @@ PICORV32_SRCS = \
|
||||
$(P)/core/picorv32/rtl/picorv32.v
|
||||
|
||||
FIRMWARE_DEPS = \
|
||||
$(P)/fw/tk1_mem.h \
|
||||
$(P)/fw/tk1/types.h \
|
||||
$(P)/fw/tk1/lib.h \
|
||||
$(P)/fw/tk1/proto.h \
|
||||
$(P)/fw/tk1/assert.h \
|
||||
$(P)/fw/tk1/led.h
|
||||
$(P)/fw/tk1/proto.h
|
||||
|
||||
FIRMWARE_OBJS = \
|
||||
$(P)/fw/tk1/main.o \
|
||||
$(P)/fw/tk1/start.o \
|
||||
$(P)/fw/tk1/proto.o \
|
||||
$(P)/fw/tk1/lib.o \
|
||||
$(P)/fw/tk1/assert.o \
|
||||
$(P)/fw/tk1/led.o \
|
||||
$(P)/fw/tk1/blake2s/blake2s.o
|
||||
$(P)/fw/tk1/blake2s/blake2s.o \
|
||||
$(P)/fw/tk1/syscall_enable.o \
|
||||
$(P)/fw/tk1/syscall_handler.o
|
||||
|
||||
FIRMWARE_SOURCES = \
|
||||
$(P)/fw/tk1/main.c \
|
||||
$(P)/fw/tk1/proto.c \
|
||||
$(P)/fw/tk1/lib.c \
|
||||
$(P)/fw/tk1/assert.c \
|
||||
$(P)/fw/tk1/led.c \
|
||||
$(P)/fw/tk1/blake2s/blake2s.c
|
||||
$(P)/fw/tk1/blake2s/blake2s.c \
|
||||
$(P)/fw/tk1/syscall_handler.c
|
||||
|
||||
TESTFW_OBJS = \
|
||||
$(P)/fw/testfw/main.o \
|
||||
$(P)/fw/testfw/start.o \
|
||||
$(P)/fw/tk1/proto.o \
|
||||
$(P)/fw/tk1/lib.o \
|
||||
$(P)/fw/tk1/blake2s/blake2s.o
|
||||
$(P)/fw/testfw/start.o
|
||||
|
||||
#-------------------------------------------------------------------
|
||||
# All: Complete build of HW and FW.
|
||||
@ -155,7 +149,10 @@ all: application_fpga.bin
|
||||
# incorrect BRAM_FW_SIZE
|
||||
# -------------------------------------------------------------------
|
||||
%_size_mismatch: %.elf phony_explicit
|
||||
@test $$($(SIZE) $< | awk 'NR==2{print $$4}') -le $$(( 32 / 8 * $(BRAM_FW_SIZE) )) \
|
||||
@test $$(( \
|
||||
$$($(SIZE) -A $< | grep text | awk 'NR==1{print $$2}') + \
|
||||
$$($(SIZE) -A $< | grep text | awk 'NR==2{print $$2}') \
|
||||
)) -le $$(( 32 / 8 * $(BRAM_FW_SIZE) )) \
|
||||
|| { printf "The 'BRAM_FW_SIZE' variable needs to be increased\n"; \
|
||||
[[ $< =~ testfw ]] && printf "Note that testfw fits if built with -Os\n"; \
|
||||
false; }
|
||||
@ -176,19 +173,29 @@ secret:
|
||||
# Firmware generation.
|
||||
# Included in the bitstream.
|
||||
#-------------------------------------------------------------------
|
||||
LDFLAGS = -T $(P)/fw/tk1/firmware.lds
|
||||
LDFLAGS = \
|
||||
-T $(P)/fw/tk1/firmware.lds \
|
||||
-Wl,--cref,-M \
|
||||
-L $(LIBDIR) -lcommon
|
||||
|
||||
# Common libraries the firmware and testfw depend on. See
|
||||
# https://github.com/tillitis/tkey-libs/
|
||||
.PHONY: tkey-libs
|
||||
tkey-libs:
|
||||
make -C $(LIBDIR)
|
||||
|
||||
$(FIRMWARE_OBJS): $(FIRMWARE_DEPS)
|
||||
$(TESTFW_OBJS): $(FIRMWARE_DEPS)
|
||||
|
||||
firmware.elf: $(FIRMWARE_OBJS) $(P)/fw/tk1/firmware.lds
|
||||
$(CC) $(CFLAGS) $(FIRMWARE_OBJS) $(LDFLAGS) -o $@
|
||||
#firmware.elf: CFLAGS += -DTKEY_DEBUG
|
||||
firmware.elf: tkey-libs $(FIRMWARE_OBJS) $(P)/fw/tk1/firmware.lds
|
||||
$(CC) $(CFLAGS) $(FIRMWARE_OBJS) $(LDFLAGS) -o $@ > $(basename $@).map
|
||||
|
||||
simfirmware.elf: CFLAGS += -DSIMULATION
|
||||
simfirmware.elf: $(FIRMWARE_OBJS) $(P)/fw/tk1/firmware.lds
|
||||
$(CC) $(CFLAGS) $(FIRMWARE_OBJS) $(LDFLAGS) -o $@
|
||||
$(CC) $(CFLAGS) $(FIRMWARE_OBJS) $(LDFLAGS) -o $@ > $(basename $@).map
|
||||
|
||||
qemu_firmware.elf: CFLAGS += -DQEMU_CONSOLE
|
||||
qemu_firmware.elf: CFLAGS += -DQEMU_DEBUG
|
||||
qemu_firmware.elf: firmware.elf
|
||||
mv firmware.elf qemu_firmware.elf
|
||||
|
||||
@ -219,8 +226,8 @@ splint:
|
||||
-fullinitblock \
|
||||
$(FIRMWARE_SOURCES)
|
||||
|
||||
testfw.elf: $(TESTFW_OBJS) $(P)/fw/tk1/firmware.lds
|
||||
$(CC) $(CFLAGS) $(TESTFW_OBJS) $(LDFLAGS) -o $@
|
||||
testfw.elf: tkey-libs $(TESTFW_OBJS) $(P)/fw/tk1/firmware.lds
|
||||
$(CC) $(CFLAGS) $(TESTFW_OBJS) $(LDFLAGS) -o $@ > $(basename $@).map
|
||||
|
||||
# Generate a fake BRAM file that will be filled in later after place-n-route
|
||||
bram_fw.hex:
|
||||
@ -241,9 +248,6 @@ check-binary-hashes:
|
||||
sha256sum -c application_fpga.bin.sha256
|
||||
|
||||
%.bin: %.elf
|
||||
$(SIZE) $<
|
||||
@test "$$($(SIZE) $< | awk 'NR==2{print $$2, $$3}')" = "0 0" \
|
||||
|| { printf "Non-empty data or bss section!\n"; false; }
|
||||
$(OBJCOPY) --input-target=elf32-littleriscv --output-target=binary $< $@
|
||||
chmod -x $@
|
||||
|
||||
@ -261,7 +265,8 @@ LINT_FLAGS = \
|
||||
-Wno-WIDTHEXPAND \
|
||||
-Wno-UNOPTFLAT \
|
||||
--timescale 1ns/1ns \
|
||||
-DNO_ICE40_DEFAULT_ASSIGNMENTS
|
||||
-DNO_ICE40_DEFAULT_ASSIGNMENTS \
|
||||
-Wno-GENUNNAMED
|
||||
|
||||
lint: $(FPGA_VERILOG_SRCS) \
|
||||
$(SIM_VERILOG_SRCS) \
|
||||
@ -303,6 +308,8 @@ fmt: $(FPGA_VERILOG_SRCS) $(SIM_VERILOG_SRCS) $(VERILATOR_VERILOG_SRCS) $(VERILO
|
||||
# Temporary fix using grep, since the verible with --verify flag only returns
|
||||
# error if the last file is malformatted.
|
||||
checkfmt: $(FPGA_VERILOG_SRCS) $(SIM_VERILOG_SRCS) $(VERILATOR_VERILOG_SRCS) $(VERILOG_SRCS)
|
||||
make -C fw/tk1 checkfmt
|
||||
make -C fw/testfw checkfmt
|
||||
$(FORMAT) $(CHECK_FORMAT_FLAGS) $^ 2>&1 | \
|
||||
grep "Needs formatting" && exit 1 || true
|
||||
.PHONY: checkfmt
|
||||
@ -353,8 +360,7 @@ tb:
|
||||
|
||||
YOSYS_FLAG ?=
|
||||
|
||||
synth.json: $(FPGA_VERILOG_SRCS) $(VERILOG_SRCS) $(PICORV32_SRCS) bram_fw.hex \
|
||||
$(P)/data/uds.hex $(P)/data/udi.hex
|
||||
synth.json: $(FPGA_VERILOG_SRCS) $(VERILOG_SRCS) $(PICORV32_SRCS) bram_fw.hex
|
||||
$(YOSYS_PATH)yosys \
|
||||
-v3 \
|
||||
-l synth.txt \
|
||||
@ -368,7 +374,7 @@ synth.json: $(FPGA_VERILOG_SRCS) $(VERILOG_SRCS) $(PICORV32_SRCS) bram_fw.hex \
|
||||
application_fpga_par.json: synth.json $(P)/data/$(PIN_FILE)
|
||||
$(NEXTPNR_PATH)nextpnr-ice40 \
|
||||
-l application_fpga_par.txt \
|
||||
--seed 9106179903728618585 \
|
||||
--seed 9416596747216415304 \
|
||||
--freq $(TARGET_FREQ) \
|
||||
--ignore-loops \
|
||||
--up5k \
|
||||
@ -481,15 +487,16 @@ clean: clean_sim clean_fw clean_tb
|
||||
.PHONY: clean
|
||||
|
||||
clean_fw:
|
||||
rm -f firmware.{elf,elf.map,bin,hex}
|
||||
rm -f firmware.{elf,map,bin,hex}
|
||||
rm -f $(FIRMWARE_OBJS)
|
||||
rm -f testfw.{elf,elf.map,bin,hex}
|
||||
rm -f testfw.{elf,map,bin,hex}
|
||||
rm -f $(TESTFW_OBJS)
|
||||
rm -f qemu_firmware.elf
|
||||
make -C tkey-libs clean
|
||||
.PHONY: clean_fw
|
||||
|
||||
clean_sim:
|
||||
rm -f simfirmware.{elf,elf.map,bin,hex}
|
||||
rm -f simfirmware.{elf,map,bin,hex}
|
||||
rm -f tb_application_fpga_sim.fst
|
||||
rm -f tb_application_fpga_sim.fst.hier
|
||||
rm -f tb/output_spram*.hex
|
||||
|
@ -11,16 +11,17 @@ The design top level is in `rtl/application_fpga.v`. It contains
|
||||
instances of all cores as well as the memory system.
|
||||
|
||||
The memory system allows the CPU to access cores in different ways
|
||||
given the current execution mode. There are two execution modes -
|
||||
firmware and application. Basically, in application mode the access is
|
||||
more restrictive.
|
||||
given the current execution mode. There are three execution modes -
|
||||
firmware, application and system call. Each mode give access to a
|
||||
different set of resources. Where app mode is the most restrictive and
|
||||
firmware mode is the least restrictive.
|
||||
|
||||
The rest of the components are under `cores`. They typically have
|
||||
their own `README.md` file documenting them and their API in detail.
|
||||
|
||||
Hardware functions with APIs, assets, and input/output are memory
|
||||
mapped starting at base address `0xc000_0000`. For specific offsets
|
||||
and bitmasks, see the file `fw/tk1_mem.h`.
|
||||
and bitmasks, see the file `tk1_mem.h` in tkey-libs.
|
||||
|
||||
Rough memory map:
|
||||
|
||||
@ -34,6 +35,7 @@ Rough memory map:
|
||||
| UART | 0xc3 |
|
||||
| Touch | 0xc4 |
|
||||
| FW\_RAM | 0xd0 |
|
||||
| Syscall | 0xe1 |
|
||||
| TK1 | 0xff |
|
||||
|
||||
## `clk_reset_gen`
|
||||
@ -96,6 +98,54 @@ hours, days) there is also a 32 bit prescaler.
|
||||
|
||||
The timer is available to use by firmware and applications.
|
||||
|
||||
## Syscall
|
||||
|
||||
System call trigger area. A 32-bit write to address 0xe1000000 will
|
||||
trigger interrupt 31, which in turn triggers a system call in the
|
||||
firmware.
|
||||
|
||||
## Interrupts
|
||||
|
||||
Triggering an interrupt will cause the CPU to execute the interrupt
|
||||
handler att address 0x10.
|
||||
|
||||
The interrupt handler is shared by all PicoRV32 interrupts but only
|
||||
interrupt 31 is enabled on the Tkey. Register `x4` can be inspected to
|
||||
determine the interrupt source. Each interrupt source is assigned one
|
||||
bit in x4. Triggered interrupts have their bit set to `1`.
|
||||
|
||||
| *Source* | *x4 Bit* |
|
||||
|----------|----------|
|
||||
| Syscall | 31 |
|
||||
|
||||
The return address is located in register `x3`. Calling the PicoRV32
|
||||
specific instruction `retirq` exits the interrupt handler and clears
|
||||
the interrupt source.
|
||||
|
||||
No registers are stored/restored when entering/exiting the interrupt
|
||||
handler. It is up to the software to store/restore as necessary.
|
||||
|
||||
Interrupts can be enabled/disabled using the PicoRV32 specific
|
||||
`maskirq` instruction.
|
||||
|
||||
## Restricted resources
|
||||
|
||||
The following table shows resource availablility for each execution
|
||||
mode:
|
||||
|
||||
| *Execution Mode* | *ROM* | *FW RAM* | *SPI* | *UDS* |
|
||||
|------------------|-------|----------|-------|-------|
|
||||
| Firmware mode | r/x | r/w | r/w | r/w* |
|
||||
| Syscall | r/x | r/w | r/w | i |
|
||||
| Application mode | r | i | i | i |
|
||||
|
||||
Legend:
|
||||
r = readable
|
||||
w = writeable
|
||||
x = executable
|
||||
i = invisible
|
||||
* = UDS words are readable only once in firmware mode.
|
||||
|
||||
## `tk1`
|
||||
|
||||
See [tk1 README](core/tk1/README.md) for details.
|
||||
@ -107,7 +157,6 @@ Contains:
|
||||
- RGB LED control.
|
||||
- General purpose input/output (GPIO) pin control.
|
||||
- Application introspection: start address and size of binary.
|
||||
- BLAKE2s function access.
|
||||
- Compound Device Identity (CDI).
|
||||
- Unique Device Identity (UDI).
|
||||
- RAM memory protection.
|
||||
@ -135,13 +184,13 @@ should make it infeasible to improve asset extraction by observing
|
||||
multiple memory dumps from the same TKey device. The attack should
|
||||
also not directly scale to multiple TKey devices.
|
||||
|
||||
The RAM address and data scrambling is done in de RAM core.
|
||||
The RAM address and data scrambling is done in the RAM core.
|
||||
|
||||
The memory protection is setup by the firmware. Access to the memory
|
||||
protection controls is disabled for applications. Before the memory
|
||||
protecetion is enabled, the RAM is filled with randomised data using
|
||||
Xorwow. So during boot the firmware perform the following steps to
|
||||
setup the memory protection:
|
||||
Xorwow. During boot the firmware perform the following steps to setup
|
||||
the memory protection:
|
||||
|
||||
1. Get a random 32-bit value from the TRNG to use as data state for
|
||||
Xorwow.
|
||||
|
@ -1 +1 @@
|
||||
8b09a7b2c9b864711e19f85de2785c8ea52f454207943c13bb17fff1ce095711 application_fpga.bin
|
||||
3d88184d4d636878d7d891e0360413b47f288eea2227435f0bfa2aad6e956f24 application_fpga.bin
|
||||
|
@ -21,6 +21,6 @@ The contents of the fw_ram is cleared when the FPGA is powered up and
|
||||
configured by the bitstream. The contents is not cleared by a system
|
||||
reset.
|
||||
|
||||
If the system_mode input is set, i.e. in app mode, no memory
|
||||
accesses are allowed. Any reads when the system_mode is set will
|
||||
If the app_mode input is set, i.e. in app mode, no memory
|
||||
accesses are allowed. Any reads when the app_mode is set will
|
||||
return an all zero word.
|
||||
|
@ -17,11 +17,11 @@ module fw_ram (
|
||||
input wire clk,
|
||||
input wire reset_n,
|
||||
|
||||
input wire system_mode,
|
||||
input wire app_mode,
|
||||
|
||||
input wire cs,
|
||||
input wire [ 3 : 0] we,
|
||||
input wire [ 8 : 0] address,
|
||||
input wire [ 9 : 0] address,
|
||||
input wire [31 : 0] write_data,
|
||||
output wire [31 : 0] read_data,
|
||||
output wire ready
|
||||
@ -34,10 +34,14 @@ module fw_ram (
|
||||
reg [31 : 0] tmp_read_data;
|
||||
reg [31 : 0] mem_read_data0;
|
||||
reg [31 : 0] mem_read_data1;
|
||||
reg [31 : 0] mem_read_data2;
|
||||
reg [31 : 0] mem_read_data3;
|
||||
reg ready_reg;
|
||||
wire system_mode_cs;
|
||||
wire app_mode_cs;
|
||||
reg bank0;
|
||||
reg bank1;
|
||||
reg bank2;
|
||||
reg bank3;
|
||||
|
||||
|
||||
//----------------------------------------------------------------
|
||||
@ -45,66 +49,257 @@ module fw_ram (
|
||||
//----------------------------------------------------------------
|
||||
assign read_data = tmp_read_data;
|
||||
assign ready = ready_reg;
|
||||
assign system_mode_cs = cs && ~system_mode;
|
||||
assign app_mode_cs = cs && ~app_mode;
|
||||
|
||||
|
||||
//----------------------------------------------------------------
|
||||
// Block RAM instances.
|
||||
//----------------------------------------------------------------
|
||||
SB_RAM40_4K fw_ram0_0 (
|
||||
SB_RAM40_4K #(
|
||||
.INIT_0(256'h0000000000000000000000000000000000000000000000000000000000000000),
|
||||
.INIT_1(256'h0000000000000000000000000000000000000000000000000000000000000000),
|
||||
.INIT_2(256'h0000000000000000000000000000000000000000000000000000000000000000),
|
||||
.INIT_3(256'h0000000000000000000000000000000000000000000000000000000000000000),
|
||||
.INIT_4(256'h0000000000000000000000000000000000000000000000000000000000000000),
|
||||
.INIT_5(256'h0000000000000000000000000000000000000000000000000000000000000000),
|
||||
.INIT_6(256'h0000000000000000000000000000000000000000000000000000000000000000),
|
||||
.INIT_7(256'h0000000000000000000000000000000000000000000000000000000000000000),
|
||||
.INIT_8(256'h0000000000000000000000000000000000000000000000000000000000000000),
|
||||
.INIT_9(256'h0000000000000000000000000000000000000000000000000000000000000000),
|
||||
.INIT_A(256'h0000000000000000000000000000000000000000000000000000000000000000),
|
||||
.INIT_B(256'h0000000000000000000000000000000000000000000000000000000000000000),
|
||||
.INIT_C(256'h0000000000000000000000000000000000000000000000000000000000000000),
|
||||
.INIT_D(256'h0000000000000000000000000000000000000000000000000000000000000000),
|
||||
.INIT_E(256'h0000000000000000000000000000000000000000000000000000000000000000),
|
||||
.INIT_F(256'h0000000000000000000000000000000000000000000000000000000000000000)
|
||||
) fw_ram0_0 (
|
||||
.RDATA(mem_read_data0[15 : 0]),
|
||||
.RADDR({3'h0, address[7 : 0]}),
|
||||
.RCLK(clk),
|
||||
.RCLKE(1'h1),
|
||||
.RE(system_mode_cs & bank0),
|
||||
.RE(app_mode_cs & bank0),
|
||||
.WADDR({3'h0, address[7 : 0]}),
|
||||
.WCLK(clk),
|
||||
.WCLKE(1'h1),
|
||||
.WDATA(write_data[15 : 0]),
|
||||
.WE((|we & system_mode_cs & bank0)),
|
||||
.WE((|we & app_mode_cs & bank0)),
|
||||
.MASK({{8{~we[1]}}, {8{~we[0]}}})
|
||||
);
|
||||
|
||||
SB_RAM40_4K fw_ram0_1 (
|
||||
SB_RAM40_4K #(
|
||||
.INIT_0(256'h0000000000000000000000000000000000000000000000000000000000000000),
|
||||
.INIT_1(256'h0000000000000000000000000000000000000000000000000000000000000000),
|
||||
.INIT_2(256'h0000000000000000000000000000000000000000000000000000000000000000),
|
||||
.INIT_3(256'h0000000000000000000000000000000000000000000000000000000000000000),
|
||||
.INIT_4(256'h0000000000000000000000000000000000000000000000000000000000000000),
|
||||
.INIT_5(256'h0000000000000000000000000000000000000000000000000000000000000000),
|
||||
.INIT_6(256'h0000000000000000000000000000000000000000000000000000000000000000),
|
||||
.INIT_7(256'h0000000000000000000000000000000000000000000000000000000000000000),
|
||||
.INIT_8(256'h0000000000000000000000000000000000000000000000000000000000000000),
|
||||
.INIT_9(256'h0000000000000000000000000000000000000000000000000000000000000000),
|
||||
.INIT_A(256'h0000000000000000000000000000000000000000000000000000000000000000),
|
||||
.INIT_B(256'h0000000000000000000000000000000000000000000000000000000000000000),
|
||||
.INIT_C(256'h0000000000000000000000000000000000000000000000000000000000000000),
|
||||
.INIT_D(256'h0000000000000000000000000000000000000000000000000000000000000000),
|
||||
.INIT_E(256'h0000000000000000000000000000000000000000000000000000000000000000),
|
||||
.INIT_F(256'h0000000000000000000000000000000000000000000000000000000000000000)
|
||||
) fw_ram0_1 (
|
||||
.RDATA(mem_read_data0[31 : 16]),
|
||||
.RADDR({3'h0, address[7 : 0]}),
|
||||
.RCLK(clk),
|
||||
.RCLKE(1'h1),
|
||||
.RE(system_mode_cs & bank0),
|
||||
.RE(app_mode_cs & bank0),
|
||||
.WADDR({3'h0, address[7 : 0]}),
|
||||
.WCLK(clk),
|
||||
.WCLKE(1'h1),
|
||||
.WDATA(write_data[31 : 16]),
|
||||
.WE((|we & system_mode_cs & bank0)),
|
||||
.WE((|we & app_mode_cs & bank0)),
|
||||
.MASK({{8{~we[3]}}, {8{~we[2]}}})
|
||||
);
|
||||
|
||||
|
||||
SB_RAM40_4K fw_ram1_0 (
|
||||
SB_RAM40_4K #(
|
||||
.INIT_0(256'h0000000000000000000000000000000000000000000000000000000000000000),
|
||||
.INIT_1(256'h0000000000000000000000000000000000000000000000000000000000000000),
|
||||
.INIT_2(256'h0000000000000000000000000000000000000000000000000000000000000000),
|
||||
.INIT_3(256'h0000000000000000000000000000000000000000000000000000000000000000),
|
||||
.INIT_4(256'h0000000000000000000000000000000000000000000000000000000000000000),
|
||||
.INIT_5(256'h0000000000000000000000000000000000000000000000000000000000000000),
|
||||
.INIT_6(256'h0000000000000000000000000000000000000000000000000000000000000000),
|
||||
.INIT_7(256'h0000000000000000000000000000000000000000000000000000000000000000),
|
||||
.INIT_8(256'h0000000000000000000000000000000000000000000000000000000000000000),
|
||||
.INIT_9(256'h0000000000000000000000000000000000000000000000000000000000000000),
|
||||
.INIT_A(256'h0000000000000000000000000000000000000000000000000000000000000000),
|
||||
.INIT_B(256'h0000000000000000000000000000000000000000000000000000000000000000),
|
||||
.INIT_C(256'h0000000000000000000000000000000000000000000000000000000000000000),
|
||||
.INIT_D(256'h0000000000000000000000000000000000000000000000000000000000000000),
|
||||
.INIT_E(256'h0000000000000000000000000000000000000000000000000000000000000000),
|
||||
.INIT_F(256'h0000000000000000000000000000000000000000000000000000000000000000)
|
||||
) fw_ram1_0 (
|
||||
.RDATA(mem_read_data1[15 : 0]),
|
||||
.RADDR({3'h0, address[7 : 0]}),
|
||||
.RCLK(clk),
|
||||
.RCLKE(1'h1),
|
||||
.RE(system_mode_cs & bank1),
|
||||
.RE(app_mode_cs & bank1),
|
||||
.WADDR({3'h0, address[7 : 0]}),
|
||||
.WCLK(clk),
|
||||
.WCLKE(1'h1),
|
||||
.WDATA(write_data[15 : 0]),
|
||||
.WE((|we & system_mode_cs & bank1)),
|
||||
.WE((|we & app_mode_cs & bank1)),
|
||||
.MASK({{8{~we[1]}}, {8{~we[0]}}})
|
||||
);
|
||||
|
||||
SB_RAM40_4K fw_ram1_1 (
|
||||
SB_RAM40_4K #(
|
||||
.INIT_0(256'h0000000000000000000000000000000000000000000000000000000000000000),
|
||||
.INIT_1(256'h0000000000000000000000000000000000000000000000000000000000000000),
|
||||
.INIT_2(256'h0000000000000000000000000000000000000000000000000000000000000000),
|
||||
.INIT_3(256'h0000000000000000000000000000000000000000000000000000000000000000),
|
||||
.INIT_4(256'h0000000000000000000000000000000000000000000000000000000000000000),
|
||||
.INIT_5(256'h0000000000000000000000000000000000000000000000000000000000000000),
|
||||
.INIT_6(256'h0000000000000000000000000000000000000000000000000000000000000000),
|
||||
.INIT_7(256'h0000000000000000000000000000000000000000000000000000000000000000),
|
||||
.INIT_8(256'h0000000000000000000000000000000000000000000000000000000000000000),
|
||||
.INIT_9(256'h0000000000000000000000000000000000000000000000000000000000000000),
|
||||
.INIT_A(256'h0000000000000000000000000000000000000000000000000000000000000000),
|
||||
.INIT_B(256'h0000000000000000000000000000000000000000000000000000000000000000),
|
||||
.INIT_C(256'h0000000000000000000000000000000000000000000000000000000000000000),
|
||||
.INIT_D(256'h0000000000000000000000000000000000000000000000000000000000000000),
|
||||
.INIT_E(256'h0000000000000000000000000000000000000000000000000000000000000000),
|
||||
.INIT_F(256'h0000000000000000000000000000000000000000000000000000000000000000)
|
||||
) fw_ram1_1 (
|
||||
.RDATA(mem_read_data1[31 : 16]),
|
||||
.RADDR({3'h0, address[7 : 0]}),
|
||||
.RCLK(clk),
|
||||
.RCLKE(1'h1),
|
||||
.RE(system_mode_cs & bank1),
|
||||
.RE(app_mode_cs & bank1),
|
||||
.WADDR({3'h0, address[7 : 0]}),
|
||||
.WCLK(clk),
|
||||
.WCLKE(1'h1),
|
||||
.WDATA(write_data[31 : 16]),
|
||||
.WE((|we & system_mode_cs & bank1)),
|
||||
.WE((|we & app_mode_cs & bank1)),
|
||||
.MASK({{8{~we[3]}}, {8{~we[2]}}})
|
||||
);
|
||||
|
||||
SB_RAM40_4K #(
|
||||
.INIT_0(256'h0000000000000000000000000000000000000000000000000000000000000000),
|
||||
.INIT_1(256'h0000000000000000000000000000000000000000000000000000000000000000),
|
||||
.INIT_2(256'h0000000000000000000000000000000000000000000000000000000000000000),
|
||||
.INIT_3(256'h0000000000000000000000000000000000000000000000000000000000000000),
|
||||
.INIT_4(256'h0000000000000000000000000000000000000000000000000000000000000000),
|
||||
.INIT_5(256'h0000000000000000000000000000000000000000000000000000000000000000),
|
||||
.INIT_6(256'h0000000000000000000000000000000000000000000000000000000000000000),
|
||||
.INIT_7(256'h0000000000000000000000000000000000000000000000000000000000000000),
|
||||
.INIT_8(256'h0000000000000000000000000000000000000000000000000000000000000000),
|
||||
.INIT_9(256'h0000000000000000000000000000000000000000000000000000000000000000),
|
||||
.INIT_A(256'h0000000000000000000000000000000000000000000000000000000000000000),
|
||||
.INIT_B(256'h0000000000000000000000000000000000000000000000000000000000000000),
|
||||
.INIT_C(256'h0000000000000000000000000000000000000000000000000000000000000000),
|
||||
.INIT_D(256'h0000000000000000000000000000000000000000000000000000000000000000),
|
||||
.INIT_E(256'h0000000000000000000000000000000000000000000000000000000000000000),
|
||||
.INIT_F(256'h0000000000000000000000000000000000000000000000000000000000000000)
|
||||
) fw_ram2_0 (
|
||||
.RDATA(mem_read_data2[15 : 0]),
|
||||
.RADDR({3'h0, address[7 : 0]}),
|
||||
.RCLK(clk),
|
||||
.RCLKE(1'h1),
|
||||
.RE(app_mode_cs & bank2),
|
||||
.WADDR({3'h0, address[7 : 0]}),
|
||||
.WCLK(clk),
|
||||
.WCLKE(1'h1),
|
||||
.WDATA(write_data[15 : 0]),
|
||||
.WE((|we & app_mode_cs & bank2)),
|
||||
.MASK({{8{~we[1]}}, {8{~we[0]}}})
|
||||
);
|
||||
|
||||
SB_RAM40_4K #(
|
||||
.INIT_0(256'h0000000000000000000000000000000000000000000000000000000000000000),
|
||||
.INIT_1(256'h0000000000000000000000000000000000000000000000000000000000000000),
|
||||
.INIT_2(256'h0000000000000000000000000000000000000000000000000000000000000000),
|
||||
.INIT_3(256'h0000000000000000000000000000000000000000000000000000000000000000),
|
||||
.INIT_4(256'h0000000000000000000000000000000000000000000000000000000000000000),
|
||||
.INIT_5(256'h0000000000000000000000000000000000000000000000000000000000000000),
|
||||
.INIT_6(256'h0000000000000000000000000000000000000000000000000000000000000000),
|
||||
.INIT_7(256'h0000000000000000000000000000000000000000000000000000000000000000),
|
||||
.INIT_8(256'h0000000000000000000000000000000000000000000000000000000000000000),
|
||||
.INIT_9(256'h0000000000000000000000000000000000000000000000000000000000000000),
|
||||
.INIT_A(256'h0000000000000000000000000000000000000000000000000000000000000000),
|
||||
.INIT_B(256'h0000000000000000000000000000000000000000000000000000000000000000),
|
||||
.INIT_C(256'h0000000000000000000000000000000000000000000000000000000000000000),
|
||||
.INIT_D(256'h0000000000000000000000000000000000000000000000000000000000000000),
|
||||
.INIT_E(256'h0000000000000000000000000000000000000000000000000000000000000000),
|
||||
.INIT_F(256'h0000000000000000000000000000000000000000000000000000000000000000)
|
||||
) fw_ram2_1 (
|
||||
.RDATA(mem_read_data2[31 : 16]),
|
||||
.RADDR({3'h0, address[7 : 0]}),
|
||||
.RCLK(clk),
|
||||
.RCLKE(1'h1),
|
||||
.RE(app_mode_cs & bank2),
|
||||
.WADDR({3'h0, address[7 : 0]}),
|
||||
.WCLK(clk),
|
||||
.WCLKE(1'h1),
|
||||
.WDATA(write_data[31 : 16]),
|
||||
.WE((|we & app_mode_cs & bank2)),
|
||||
.MASK({{8{~we[3]}}, {8{~we[2]}}})
|
||||
);
|
||||
|
||||
SB_RAM40_4K #(
|
||||
.INIT_0(256'h0000000000000000000000000000000000000000000000000000000000000000),
|
||||
.INIT_1(256'h0000000000000000000000000000000000000000000000000000000000000000),
|
||||
.INIT_2(256'h0000000000000000000000000000000000000000000000000000000000000000),
|
||||
.INIT_3(256'h0000000000000000000000000000000000000000000000000000000000000000),
|
||||
.INIT_4(256'h0000000000000000000000000000000000000000000000000000000000000000),
|
||||
.INIT_5(256'h0000000000000000000000000000000000000000000000000000000000000000),
|
||||
.INIT_6(256'h0000000000000000000000000000000000000000000000000000000000000000),
|
||||
.INIT_7(256'h0000000000000000000000000000000000000000000000000000000000000000),
|
||||
.INIT_8(256'h0000000000000000000000000000000000000000000000000000000000000000),
|
||||
.INIT_9(256'h0000000000000000000000000000000000000000000000000000000000000000),
|
||||
.INIT_A(256'h0000000000000000000000000000000000000000000000000000000000000000),
|
||||
.INIT_B(256'h0000000000000000000000000000000000000000000000000000000000000000),
|
||||
.INIT_C(256'h0000000000000000000000000000000000000000000000000000000000000000),
|
||||
.INIT_D(256'h0000000000000000000000000000000000000000000000000000000000000000),
|
||||
.INIT_E(256'h0000000000000000000000000000000000000000000000000000000000000000),
|
||||
.INIT_F(256'h0000000000000000000000000000000000000000000000000000000000000000)
|
||||
) fw_ram3_0 (
|
||||
.RDATA(mem_read_data3[15 : 0]),
|
||||
.RADDR({3'h0, address[7 : 0]}),
|
||||
.RCLK(clk),
|
||||
.RCLKE(1'h1),
|
||||
.RE(app_mode_cs & bank3),
|
||||
.WADDR({3'h0, address[7 : 0]}),
|
||||
.WCLK(clk),
|
||||
.WCLKE(1'h1),
|
||||
.WDATA(write_data[15 : 0]),
|
||||
.WE((|we & app_mode_cs & bank3)),
|
||||
.MASK({{8{~we[1]}}, {8{~we[0]}}})
|
||||
);
|
||||
|
||||
SB_RAM40_4K #(
|
||||
.INIT_0(256'h0000000000000000000000000000000000000000000000000000000000000000),
|
||||
.INIT_1(256'h0000000000000000000000000000000000000000000000000000000000000000),
|
||||
.INIT_2(256'h0000000000000000000000000000000000000000000000000000000000000000),
|
||||
.INIT_3(256'h0000000000000000000000000000000000000000000000000000000000000000),
|
||||
.INIT_4(256'h0000000000000000000000000000000000000000000000000000000000000000),
|
||||
.INIT_5(256'h0000000000000000000000000000000000000000000000000000000000000000),
|
||||
.INIT_6(256'h0000000000000000000000000000000000000000000000000000000000000000),
|
||||
.INIT_7(256'h0000000000000000000000000000000000000000000000000000000000000000),
|
||||
.INIT_8(256'h0000000000000000000000000000000000000000000000000000000000000000),
|
||||
.INIT_9(256'h0000000000000000000000000000000000000000000000000000000000000000),
|
||||
.INIT_A(256'h0000000000000000000000000000000000000000000000000000000000000000),
|
||||
.INIT_B(256'h0000000000000000000000000000000000000000000000000000000000000000),
|
||||
.INIT_C(256'h0000000000000000000000000000000000000000000000000000000000000000),
|
||||
.INIT_D(256'h0000000000000000000000000000000000000000000000000000000000000000),
|
||||
.INIT_E(256'h0000000000000000000000000000000000000000000000000000000000000000),
|
||||
.INIT_F(256'h0000000000000000000000000000000000000000000000000000000000000000)
|
||||
) fw_ram3_1 (
|
||||
.RDATA(mem_read_data3[31 : 16]),
|
||||
.RADDR({3'h0, address[7 : 0]}),
|
||||
.RCLK(clk),
|
||||
.RCLKE(1'h1),
|
||||
.RE(app_mode_cs & bank3),
|
||||
.WADDR({3'h0, address[7 : 0]}),
|
||||
.WCLK(clk),
|
||||
.WCLKE(1'h1),
|
||||
.WDATA(write_data[31 : 16]),
|
||||
.WE((|we & app_mode_cs & bank3)),
|
||||
.MASK({{8{~we[3]}}, {8{~we[2]}}})
|
||||
);
|
||||
|
||||
@ -127,17 +322,29 @@ module fw_ram (
|
||||
always @* begin : rw_mux
|
||||
bank0 = 1'h0;
|
||||
bank1 = 1'h0;
|
||||
bank2 = 1'h0;
|
||||
bank3 = 1'h0;
|
||||
tmp_read_data = 32'h0;
|
||||
|
||||
if (system_mode_cs) begin
|
||||
if (address[8]) begin
|
||||
if (app_mode_cs) begin
|
||||
case (address[9:8])
|
||||
2'b11: begin
|
||||
bank3 = 1'h1;
|
||||
tmp_read_data = mem_read_data3;
|
||||
end
|
||||
2'b10: begin
|
||||
bank2 = 1'h1;
|
||||
tmp_read_data = mem_read_data2;
|
||||
end
|
||||
2'b01: begin
|
||||
bank1 = 1'h1;
|
||||
tmp_read_data = mem_read_data1;
|
||||
end
|
||||
else begin
|
||||
2'b00: begin
|
||||
bank0 = 1'h1;
|
||||
tmp_read_data = mem_read_data0;
|
||||
end
|
||||
endcase
|
||||
end
|
||||
end
|
||||
|
||||
|
@ -23,17 +23,6 @@ and version of the device. They can be read by FW as well as
|
||||
applications.
|
||||
|
||||
|
||||
### Control of execution mode
|
||||
|
||||
```
|
||||
ADDR_SYSTEM_MODE_CTRL: 0x08
|
||||
```
|
||||
|
||||
This register controls if the device is executing in FW mode or in App
|
||||
mode. The register can be written once between power cycles, and only
|
||||
by FW. If set the device is in app mode.
|
||||
|
||||
|
||||
### Control of RGB LED
|
||||
|
||||
```
|
||||
@ -75,19 +64,7 @@ ADDR_APP_SIZE: 0x0d
|
||||
These registers provide read only information to the loaded app to
|
||||
itself - where it was loaded and its size. The values are written by
|
||||
FW as part of the loading of the app. The registers can't be written
|
||||
when the `ADDR_SYSTEM_MODE_CTRL` has been set.
|
||||
|
||||
|
||||
### Access to Blake2s
|
||||
|
||||
```
|
||||
ADDR_BLAKE2S: 0x10
|
||||
```
|
||||
|
||||
This register provides the 32-bit function pointer address to the
|
||||
Blake2s hash function in the FW. It is written by FW during boot. The
|
||||
register can't be written to when the `ADDR_SYSTEM_MODE_CTRL` has been
|
||||
set.
|
||||
in application mode.
|
||||
|
||||
|
||||
### Access to CDI
|
||||
@ -99,10 +76,10 @@ ADDR_CDI_LAST: 0x27
|
||||
|
||||
These registers provide access to the 256-bit compound device secret
|
||||
calculated by the FW as part of loading an application. The registers
|
||||
are written by the FW. The register can't be written to when the
|
||||
`ADDR_SYSTEM_MODE_CTRL` has been set. The CDI is readable by apps,
|
||||
which can then use it as a base secret for any other secrets required
|
||||
to carry out their intended use case.
|
||||
are written by the FW. The register can't be written in application
|
||||
mode. The CDI is readable by apps, which can then use it as a base
|
||||
secret for any other secrets required to carry out their intended use
|
||||
case.
|
||||
|
||||
|
||||
### Access to UDI
|
||||
|
@ -20,7 +20,8 @@ module tk1 #(
|
||||
input wire reset_n,
|
||||
|
||||
input wire cpu_trap,
|
||||
output wire system_mode,
|
||||
output wire app_mode,
|
||||
output wire fw_startup_done,
|
||||
|
||||
input wire [31 : 0] cpu_addr,
|
||||
input wire cpu_instr,
|
||||
@ -45,6 +46,8 @@ module tk1 #(
|
||||
output wire gpio3,
|
||||
output wire gpio4,
|
||||
|
||||
input wire syscall,
|
||||
|
||||
input wire cs,
|
||||
input wire we,
|
||||
input wire [ 7 : 0] address,
|
||||
@ -61,8 +64,6 @@ module tk1 #(
|
||||
localparam ADDR_NAME1 = 8'h01;
|
||||
localparam ADDR_VERSION = 8'h02;
|
||||
|
||||
localparam ADDR_SYSTEM_MODE_CTRL = 8'h08;
|
||||
|
||||
localparam ADDR_LED = 8'h09;
|
||||
localparam LED_R_BIT = 2;
|
||||
localparam LED_G_BIT = 1;
|
||||
@ -79,8 +80,6 @@ module tk1 #(
|
||||
localparam ADDR_APP_START = 8'h0c;
|
||||
localparam ADDR_APP_SIZE = 8'h0d;
|
||||
|
||||
localparam ADDR_BLAKE2S = 8'h10;
|
||||
|
||||
localparam ADDR_CDI_FIRST = 8'h20;
|
||||
localparam ADDR_CDI_LAST = 8'h27;
|
||||
|
||||
@ -105,8 +104,9 @@ module tk1 #(
|
||||
localparam TK1_VERSION = 32'h00000005;
|
||||
|
||||
localparam FW_RAM_FIRST = 32'hd0000000;
|
||||
localparam FW_RAM_LAST = 32'hd00007ff;
|
||||
localparam FW_RAM_LAST = 32'hd0000fff; // 4 KB
|
||||
|
||||
localparam FW_ROM_LAST = 32'h00001fff;
|
||||
|
||||
//----------------------------------------------------------------
|
||||
// Registers including update variables and write enable.
|
||||
@ -114,8 +114,8 @@ module tk1 #(
|
||||
reg [31 : 0] cdi_mem [0 : 7];
|
||||
reg cdi_mem_we;
|
||||
|
||||
reg system_mode_reg;
|
||||
reg system_mode_we;
|
||||
reg fw_startup_done_reg;
|
||||
reg fw_startup_done_set;
|
||||
|
||||
reg [ 2 : 0] led_reg;
|
||||
reg led_we;
|
||||
@ -133,9 +133,6 @@ module tk1 #(
|
||||
reg [31 : 0] app_size_reg;
|
||||
reg app_size_we;
|
||||
|
||||
reg [31 : 0] blake2s_addr_reg;
|
||||
reg blake2s_addr_we;
|
||||
|
||||
reg [23 : 0] cpu_trap_ctr_reg;
|
||||
reg [23 : 0] cpu_trap_ctr_new;
|
||||
reg [ 2 : 0] cpu_trap_led_reg;
|
||||
@ -187,7 +184,8 @@ module tk1 #(
|
||||
assign read_data = tmp_read_data;
|
||||
assign ready = tmp_ready;
|
||||
|
||||
assign system_mode = system_mode_reg;
|
||||
assign app_mode = fw_startup_done_reg & ~syscall;
|
||||
assign fw_startup_done = fw_startup_done_reg;
|
||||
|
||||
assign force_trap = force_trap_reg;
|
||||
|
||||
@ -199,7 +197,6 @@ module tk1 #(
|
||||
|
||||
assign system_reset = system_reset_reg;
|
||||
|
||||
|
||||
//----------------------------------------------------------------
|
||||
// Module instance.
|
||||
//----------------------------------------------------------------
|
||||
@ -250,7 +247,7 @@ module tk1 #(
|
||||
//----------------------------------------------------------------
|
||||
always @(posedge clk) begin : reg_update
|
||||
if (!reset_n) begin
|
||||
system_mode_reg <= 1'h0;
|
||||
fw_startup_done_reg <= 1'h0;
|
||||
led_reg <= 3'h6;
|
||||
gpio1_reg <= 2'h0;
|
||||
gpio2_reg <= 2'h0;
|
||||
@ -258,7 +255,6 @@ module tk1 #(
|
||||
gpio4_reg <= 1'h0;
|
||||
app_start_reg <= 32'h0;
|
||||
app_size_reg <= APP_SIZE;
|
||||
blake2s_addr_reg <= 32'h0;
|
||||
cdi_mem[0] <= 32'h0;
|
||||
cdi_mem[1] <= 32'h0;
|
||||
cdi_mem[2] <= 32'h0;
|
||||
@ -289,8 +285,8 @@ module tk1 #(
|
||||
gpio2_reg[0] <= gpio2;
|
||||
gpio2_reg[1] <= gpio2_reg[0];
|
||||
|
||||
if (system_mode_we) begin
|
||||
system_mode_reg <= 1'h1;
|
||||
if (fw_startup_done_set) begin
|
||||
fw_startup_done_reg <= 1'h1;
|
||||
end
|
||||
|
||||
if (led_we) begin
|
||||
@ -313,10 +309,6 @@ module tk1 #(
|
||||
app_size_reg <= write_data;
|
||||
end
|
||||
|
||||
if (blake2s_addr_we) begin
|
||||
blake2s_addr_reg <= write_data;
|
||||
end
|
||||
|
||||
if (cdi_mem_we) begin
|
||||
cdi_mem[address[2 : 0]] <= write_data;
|
||||
end
|
||||
@ -386,6 +378,9 @@ module tk1 #(
|
||||
//
|
||||
// Trying to execute instructions in FW-RAM.
|
||||
//
|
||||
// Executing instructions in ROM, while ROM is marked as not
|
||||
// executable.
|
||||
//
|
||||
// Trying to execute code in mem area set to be data access only.
|
||||
// This requires execution monitor to have been setup and
|
||||
// enabled.
|
||||
@ -395,7 +390,7 @@ module tk1 #(
|
||||
|
||||
if (cpu_valid) begin
|
||||
// Outside ROM area
|
||||
if (cpu_addr[31 : 30] == 2'h0 & |cpu_addr[29 : 14]) begin
|
||||
if (cpu_addr[31 : 30] == 2'h0 & |cpu_addr[29 : 13]) begin
|
||||
force_trap_set = 1'h1;
|
||||
end
|
||||
|
||||
@ -443,12 +438,22 @@ module tk1 #(
|
||||
end
|
||||
|
||||
// Outside FW_RAM
|
||||
if (cpu_addr[29 : 24] == 6'h10 & |cpu_addr[23 : 11]) begin
|
||||
if (cpu_addr[29 : 24] == 6'h10 & |cpu_addr[23 : 12]) begin
|
||||
force_trap_set = 1'h1;
|
||||
end
|
||||
|
||||
// In unused space
|
||||
if ((cpu_addr[29 : 24] > 6'h10) && (cpu_addr[29 : 24] < 6'h3f)) begin
|
||||
if ((cpu_addr[29 : 24] > 6'h10) && (cpu_addr[29 : 24] < 6'h21)) begin
|
||||
force_trap_set = 1'h1;
|
||||
end
|
||||
|
||||
// Outside SYSCALL
|
||||
if (cpu_addr[29 : 24] == 6'h21 & |cpu_addr[23 : 2]) begin
|
||||
force_trap_set = 1'h1;
|
||||
end
|
||||
|
||||
// In unused space
|
||||
if ((cpu_addr[29 : 24] > 6'h21) && (cpu_addr[29 : 24] < 6'h3f)) begin
|
||||
force_trap_set = 1'h1;
|
||||
end
|
||||
|
||||
@ -463,6 +468,12 @@ module tk1 #(
|
||||
force_trap_set = 1'h1;
|
||||
end
|
||||
|
||||
if (app_mode) begin
|
||||
if (cpu_addr <= FW_ROM_LAST) begin // Only valid as long as ROM starts at address 0x00.
|
||||
force_trap_set = 1'h1;
|
||||
end
|
||||
end
|
||||
|
||||
if (cpu_mon_en_reg) begin
|
||||
if ((cpu_addr >= cpu_mon_first_reg) && (cpu_addr <= cpu_mon_last_reg)) begin
|
||||
force_trap_set = 1'h1;
|
||||
@ -472,18 +483,30 @@ module tk1 #(
|
||||
end
|
||||
end
|
||||
|
||||
//----------------------------------------------------------------
|
||||
// fw_startup_done_ctrl
|
||||
//
|
||||
// Automatically lower privilege when executing above ROM.
|
||||
// ----------------------------------------------------------------
|
||||
always @* begin : fw_startup_done_ctrl
|
||||
fw_startup_done_set = 1'h0;
|
||||
|
||||
if (cpu_valid & cpu_instr) begin
|
||||
if (cpu_addr > FW_ROM_LAST) begin
|
||||
fw_startup_done_set = 1'h1;
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
//----------------------------------------------------------------
|
||||
// api
|
||||
//----------------------------------------------------------------
|
||||
always @* begin : api
|
||||
system_mode_we = 1'h0;
|
||||
led_we = 1'h0;
|
||||
gpio3_we = 1'h0;
|
||||
gpio4_we = 1'h0;
|
||||
app_start_we = 1'h0;
|
||||
app_size_we = 1'h0;
|
||||
blake2s_addr_we = 1'h0;
|
||||
cdi_mem_we = 1'h0;
|
||||
ram_addr_rand_we = 1'h0;
|
||||
ram_data_rand_we = 1'h0;
|
||||
@ -498,16 +521,12 @@ module tk1 #(
|
||||
spi_start = 1'h0;
|
||||
spi_tx_data_vld = 1'h0;
|
||||
|
||||
spi_enable = write_data[0];
|
||||
spi_tx_data = write_data[7 : 0];
|
||||
spi_enable = write_data[0] & !app_mode;
|
||||
spi_tx_data = write_data[7 : 0] & {8{!app_mode}};
|
||||
|
||||
if (cs) begin
|
||||
tmp_ready = 1'h1;
|
||||
if (we) begin
|
||||
if (address == ADDR_SYSTEM_MODE_CTRL) begin
|
||||
system_mode_we = 1'h1;
|
||||
end
|
||||
|
||||
if (address == ADDR_LED) begin
|
||||
led_we = 1'h1;
|
||||
end
|
||||
@ -518,41 +537,37 @@ module tk1 #(
|
||||
end
|
||||
|
||||
if (address == ADDR_APP_START) begin
|
||||
if (!system_mode_reg) begin
|
||||
if (!app_mode) begin
|
||||
app_start_we = 1'h1;
|
||||
end
|
||||
end
|
||||
|
||||
if (address == ADDR_APP_SIZE) begin
|
||||
if (!system_mode_reg) begin
|
||||
if (!app_mode) begin
|
||||
app_size_we = 1'h1;
|
||||
end
|
||||
end
|
||||
|
||||
if (address == ADDR_SYSTEM_RESET) begin
|
||||
if (!app_mode) begin
|
||||
system_reset_new = 1'h1;
|
||||
end
|
||||
|
||||
if (address == ADDR_BLAKE2S) begin
|
||||
if (!system_mode_reg) begin
|
||||
blake2s_addr_we = 1'h1;
|
||||
end
|
||||
end
|
||||
|
||||
if ((address >= ADDR_CDI_FIRST) && (address <= ADDR_CDI_LAST)) begin
|
||||
if (!system_mode_reg) begin
|
||||
if (!app_mode) begin
|
||||
cdi_mem_we = 1'h1;
|
||||
end
|
||||
end
|
||||
|
||||
if (address == ADDR_RAM_ADDR_RAND) begin
|
||||
if (!system_mode_reg) begin
|
||||
if (!app_mode) begin
|
||||
ram_addr_rand_we = 1'h1;
|
||||
end
|
||||
end
|
||||
|
||||
if (address == ADDR_RAM_DATA_RAND) begin
|
||||
if (!system_mode_reg) begin
|
||||
if (!app_mode) begin
|
||||
ram_data_rand_we = 1'h1;
|
||||
end
|
||||
end
|
||||
@ -574,16 +589,22 @@ module tk1 #(
|
||||
end
|
||||
|
||||
if (address == ADDR_SPI_EN) begin
|
||||
if (!app_mode) begin
|
||||
spi_enable_vld = 1'h1;
|
||||
end
|
||||
end
|
||||
|
||||
if (address == ADDR_SPI_XFER) begin
|
||||
if (!app_mode) begin
|
||||
spi_start = 1'h1;
|
||||
end
|
||||
end
|
||||
|
||||
if (address == ADDR_SPI_DATA) begin
|
||||
if (!app_mode) begin
|
||||
spi_tx_data_vld = 1'h1;
|
||||
end
|
||||
end
|
||||
|
||||
end
|
||||
else begin
|
||||
@ -599,10 +620,6 @@ module tk1 #(
|
||||
tmp_read_data = TK1_VERSION;
|
||||
end
|
||||
|
||||
if (address == ADDR_SYSTEM_MODE_CTRL) begin
|
||||
tmp_read_data = {32{system_mode_reg}};
|
||||
end
|
||||
|
||||
if (address == ADDR_LED) begin
|
||||
tmp_read_data = {29'h0, led_reg};
|
||||
end
|
||||
@ -619,27 +636,27 @@ module tk1 #(
|
||||
tmp_read_data = app_size_reg;
|
||||
end
|
||||
|
||||
if (address == ADDR_BLAKE2S) begin
|
||||
tmp_read_data = blake2s_addr_reg;
|
||||
end
|
||||
|
||||
if ((address >= ADDR_CDI_FIRST) && (address <= ADDR_CDI_LAST)) begin
|
||||
tmp_read_data = cdi_mem[address[2 : 0]];
|
||||
end
|
||||
|
||||
if ((address >= ADDR_UDI_FIRST) && (address <= ADDR_UDI_LAST)) begin
|
||||
if (!system_mode_reg) begin
|
||||
if (!app_mode) begin
|
||||
tmp_read_data = udi_rdata;
|
||||
end
|
||||
end
|
||||
|
||||
if (address == ADDR_SPI_XFER) begin
|
||||
if (!app_mode) begin
|
||||
tmp_read_data[0] = spi_ready;
|
||||
end
|
||||
end
|
||||
|
||||
if (address == ADDR_SPI_DATA) begin
|
||||
if (!app_mode) begin
|
||||
tmp_read_data[7 : 0] = spi_rx_data;
|
||||
end
|
||||
end
|
||||
|
||||
end
|
||||
end
|
||||
|
@ -18,7 +18,7 @@ module tb_tk1 ();
|
||||
//----------------------------------------------------------------
|
||||
// Internal constant and parameter definitions.
|
||||
//----------------------------------------------------------------
|
||||
parameter DEBUG = 1;
|
||||
parameter DEBUG = 0;
|
||||
|
||||
parameter CLK_HALF_PERIOD = 1;
|
||||
parameter CLK_PERIOD = 2 * CLK_HALF_PERIOD;
|
||||
@ -27,8 +27,6 @@ module tb_tk1 ();
|
||||
localparam ADDR_NAME1 = 8'h01;
|
||||
localparam ADDR_VERSION = 8'h02;
|
||||
|
||||
localparam ADDR_SYSTEM_MODE_CTRL = 8'h08;
|
||||
|
||||
localparam ADDR_LED = 8'h09;
|
||||
localparam LED_R_BIT = 2;
|
||||
localparam LED_G_BIT = 1;
|
||||
@ -58,10 +56,16 @@ module tb_tk1 ();
|
||||
localparam ADDR_CPU_MON_FIRST = 8'h61;
|
||||
localparam ADDR_CPU_MON_LAST = 8'h62;
|
||||
|
||||
localparam ADDR_SYSTEM_RESET = 8'h70;
|
||||
|
||||
localparam ADDR_SPI_EN = 8'h80;
|
||||
localparam ADDR_SPI_XFER = 8'h81;
|
||||
localparam ADDR_SPI_DATA = 8'h82;
|
||||
|
||||
localparam APP_RAM_START = 32'h40000000;
|
||||
|
||||
localparam ROM_START = 32'h00000000;
|
||||
localparam ROM_END = 32'h00001fff;
|
||||
|
||||
//----------------------------------------------------------------
|
||||
// Register and Wire declarations.
|
||||
@ -76,12 +80,13 @@ module tb_tk1 ();
|
||||
reg tb_clk;
|
||||
reg tb_reset_n;
|
||||
reg tb_cpu_trap;
|
||||
wire tb_system_mode;
|
||||
wire tb_app_mode;
|
||||
|
||||
reg [31 : 0] tb_cpu_addr;
|
||||
reg tb_cpu_instr;
|
||||
reg tb_cpu_valid;
|
||||
wire tb_force_trap;
|
||||
wire tb_system_reset;
|
||||
|
||||
wire [14 : 0] tb_ram_addr_rand;
|
||||
wire [31 : 0] tb_ram_data_rand;
|
||||
@ -95,6 +100,8 @@ module tb_tk1 ();
|
||||
wire tb_gpio3;
|
||||
wire tb_gpio4;
|
||||
|
||||
reg tb_syscall;
|
||||
|
||||
wire tb_spi_ss;
|
||||
wire tb_spi_sck;
|
||||
wire tb_spi_mosi;
|
||||
@ -122,12 +129,13 @@ module tb_tk1 ();
|
||||
.reset_n(tb_reset_n),
|
||||
|
||||
.cpu_trap(tb_cpu_trap),
|
||||
.system_mode(tb_system_mode),
|
||||
.app_mode(tb_app_mode),
|
||||
|
||||
.cpu_addr (tb_cpu_addr),
|
||||
.cpu_instr (tb_cpu_instr),
|
||||
.cpu_valid (tb_cpu_valid),
|
||||
.force_trap(tb_force_trap),
|
||||
.system_reset(tb_system_reset),
|
||||
|
||||
.ram_addr_rand(tb_ram_addr_rand),
|
||||
.ram_data_rand(tb_ram_data_rand),
|
||||
@ -141,6 +149,8 @@ module tb_tk1 ();
|
||||
.gpio3(tb_gpio3),
|
||||
.gpio4(tb_gpio4),
|
||||
|
||||
.syscall(tb_syscall),
|
||||
|
||||
.spi_ss (tb_spi_ss),
|
||||
.spi_sck (tb_spi_sck),
|
||||
.spi_mosi(tb_spi_mosi),
|
||||
@ -192,7 +202,7 @@ module tb_tk1 ();
|
||||
$display("------------");
|
||||
if (tb_main_monitor) begin
|
||||
$display("Inputs and outputs:");
|
||||
$display("tb_cpu_trap: 0x%1x, system_mode: 0x%1x", tb_cpu_trap, tb_system_mode);
|
||||
$display("tb_cpu_trap: 0x%1x, app_mode: 0x%1x", tb_cpu_trap, dut.app_mode);
|
||||
$display("cpu_addr: 0x%08x, cpu_instr: 0x%1x, cpu_valid: 0x%1x, force_tap: 0x%1x",
|
||||
tb_cpu_addr, tb_cpu_instr, tb_cpu_valid, tb_force_trap);
|
||||
$display("ram_addr_rand: 0x%08x, ram_data_rand: 0x%08x", tb_ram_addr_rand,
|
||||
@ -227,7 +237,6 @@ module tb_tk1 ();
|
||||
//----------------------------------------------------------------
|
||||
task reset_dut;
|
||||
begin
|
||||
$display("--- Toggle reset.");
|
||||
tb_reset_n = 0;
|
||||
#(2 * CLK_PERIOD);
|
||||
tb_reset_n = 1;
|
||||
@ -277,6 +286,8 @@ module tb_tk1 ();
|
||||
tb_gpio1 = 1'h0;
|
||||
tb_gpio2 = 1'h0;
|
||||
|
||||
tb_syscall = 1'h0;
|
||||
|
||||
tb_cs = 1'h0;
|
||||
tb_we = 1'h0;
|
||||
tb_address = 8'h0;
|
||||
@ -285,6 +296,25 @@ module tb_tk1 ();
|
||||
endtask // init_sim
|
||||
|
||||
|
||||
//----------------------------------------------------------------
|
||||
// restore_mem_bus()
|
||||
//
|
||||
// Restore memory bus to its initial state
|
||||
//----------------------------------------------------------------
|
||||
task restore_mem_bus();
|
||||
begin : restore_mem_bus
|
||||
tb_cpu_addr = 32'h0;
|
||||
tb_cpu_instr = 1'h0;
|
||||
tb_cpu_valid = 1'h0;
|
||||
|
||||
tb_cs = 1'h0;
|
||||
tb_we = 1'h0;
|
||||
tb_address = 8'h0;
|
||||
tb_write_data = 32'h0;
|
||||
end
|
||||
endtask
|
||||
|
||||
|
||||
//----------------------------------------------------------------
|
||||
// write_word()
|
||||
//
|
||||
@ -301,7 +331,7 @@ module tb_tk1 ();
|
||||
tb_write_data = word;
|
||||
tb_cs = 1;
|
||||
tb_we = 1;
|
||||
#(2 * CLK_PERIOD);
|
||||
#(CLK_PERIOD);
|
||||
tb_cs = 0;
|
||||
tb_we = 0;
|
||||
end
|
||||
@ -320,12 +350,16 @@ module tb_tk1 ();
|
||||
reg [31 : 0] read_data;
|
||||
|
||||
tb_address = address;
|
||||
tb_cpu_instr = 1'h0;
|
||||
tb_cpu_valid = 1'h1;
|
||||
tb_we = 1'h0;
|
||||
tb_cs = 1'h1;
|
||||
|
||||
#(CLK_PERIOD);
|
||||
read_data = tb_read_data;
|
||||
|
||||
#(CLK_PERIOD);
|
||||
tb_cpu_valid = 1'h0;
|
||||
tb_cs = 1'h0;
|
||||
end
|
||||
endtask // read_word
|
||||
@ -354,21 +388,138 @@ module tb_tk1 ();
|
||||
#(CLK_PERIOD);
|
||||
tb_cs = 1'h0;
|
||||
|
||||
if (DEBUG) begin
|
||||
if (read_data == expected) begin
|
||||
if (DEBUG) begin
|
||||
$display("--- Reading 0x%08x from 0x%02x.", read_data, address);
|
||||
end
|
||||
end
|
||||
else begin
|
||||
$display("--- Error: Got 0x%08x when reading from 0x%02x, expected 0x%08x", read_data,
|
||||
address, expected);
|
||||
error_ctr = error_ctr + 1;
|
||||
end
|
||||
$display("");
|
||||
end
|
||||
end
|
||||
endtask // read_check_word
|
||||
|
||||
|
||||
//----------------------------------------------------------------
|
||||
// check_equal()
|
||||
//
|
||||
// Check that two values are equal
|
||||
//----------------------------------------------------------------
|
||||
task check_equal(input [31 : 0] value, input [31 : 0] expected);
|
||||
begin : check_equal
|
||||
if (value != expected) begin
|
||||
$display("--- Error: Got 0x%08x, expected 0x%08x", value, expected);
|
||||
error_ctr = error_ctr + 1;
|
||||
end
|
||||
end
|
||||
endtask // check_equal
|
||||
|
||||
|
||||
//----------------------------------------------------------------
|
||||
// fetch_instruction()
|
||||
//
|
||||
// Simulate fetch of an instruction at specified address.
|
||||
//----------------------------------------------------------------
|
||||
task fetch_instruction(input [31 : 0] address);
|
||||
begin : fetch_instruction
|
||||
tb_cpu_addr = address;
|
||||
tb_cpu_instr = 1'h1;
|
||||
tb_cpu_valid = 1'h1;
|
||||
#(CLK_PERIOD);
|
||||
tb_cpu_addr = 32'h0;
|
||||
tb_cpu_instr = 1'h0;
|
||||
tb_cpu_valid = 1'h0;
|
||||
end
|
||||
endtask // fetch_instruction
|
||||
|
||||
// cpu_read_word()
|
||||
//
|
||||
// Read a data word from the given CPU address in the DUT.
|
||||
// the word read will be available in the global variable
|
||||
// tb_read_data.
|
||||
//----------------------------------------------------------------
|
||||
task cpu_read_word(input [31 : 0] address);
|
||||
begin : cpu_read_word
|
||||
reg [31 : 0] read_data;
|
||||
|
||||
tb_cpu_addr = address;
|
||||
tb_address = tb_cpu_addr[13:2];
|
||||
tb_cpu_instr = 1'h0;
|
||||
tb_cpu_valid = 1'h1;
|
||||
tb_we = 1'h0;
|
||||
tb_cs = 1'h1;
|
||||
|
||||
#(CLK_PERIOD);
|
||||
read_data = tb_read_data;
|
||||
|
||||
#(CLK_PERIOD);
|
||||
tb_cpu_addr = 32'h0;
|
||||
tb_cpu_valid = 1'h0;
|
||||
tb_address = 12'h0;
|
||||
tb_cs = 1'h0;
|
||||
end
|
||||
endtask // read_word
|
||||
|
||||
|
||||
//----------------------------------------------------------------
|
||||
// cpu_read_check_range_should_trap()
|
||||
//
|
||||
// Read data in a range of CPU addresses (32-bit addresses). Fail
|
||||
// if trap signal is not asserted.
|
||||
// Range is inclusive.
|
||||
//----------------------------------------------------------------
|
||||
task cpu_read_check_range_should_trap(input [31 : 0] start_address, input [31 : 0] end_address);
|
||||
begin : read_check_range_should_not_trap
|
||||
reg [32 : 0] address;
|
||||
reg error_detected;
|
||||
|
||||
address = start_address;
|
||||
error_detected = 0;
|
||||
|
||||
while (!error_detected && (address <= end_address)) begin
|
||||
reset_dut();
|
||||
cpu_read_word(address);
|
||||
if (tb_force_trap == 0) begin
|
||||
$display("--- Error: Expected trap when reading from address 0x%08x", address);
|
||||
error_ctr += 1;
|
||||
error_detected = 1;
|
||||
end
|
||||
address += 1;
|
||||
end
|
||||
end
|
||||
endtask
|
||||
|
||||
|
||||
//----------------------------------------------------------------
|
||||
// cpu_read_check_range_should_not_trap()
|
||||
//
|
||||
// Read data in a range of CPU addresses (32-bit addresses). Fail
|
||||
// if trap signal is asserted.
|
||||
// Range is inclusive.
|
||||
//----------------------------------------------------------------
|
||||
task cpu_read_check_range_should_not_trap(input [31 : 0] start_address, input [31 : 0] end_address);
|
||||
begin : read_check_should_not_trap
|
||||
reg [31 : 0] address;
|
||||
reg error_detected;
|
||||
|
||||
address = start_address;
|
||||
error_detected = 0;
|
||||
|
||||
while (!error_detected && (address <= end_address)) begin
|
||||
reset_dut();
|
||||
cpu_read_word(address);
|
||||
if (tb_force_trap == 1) begin
|
||||
$display("--- Error: Did not expected trap when reading from address 0x%08x", address);
|
||||
error_ctr += 1;
|
||||
error_detected = 1;
|
||||
end
|
||||
address += 1;
|
||||
end
|
||||
end
|
||||
endtask
|
||||
|
||||
//----------------------------------------------------------------
|
||||
// test1()
|
||||
// Read out name and version.
|
||||
@ -400,10 +551,27 @@ module tb_tk1 ();
|
||||
|
||||
$display("");
|
||||
$display("--- test2: Read out UDI started.");
|
||||
tb_syscall = 0;
|
||||
reset_dut();
|
||||
|
||||
read_check_word(ADDR_UDI_FIRST, 32'h00010203);
|
||||
read_check_word(ADDR_UDI_LAST, 32'h04050607);
|
||||
|
||||
$display("--- test2: Switch to app mode.");
|
||||
fetch_instruction(APP_RAM_START);
|
||||
|
||||
read_check_word(ADDR_UDI_FIRST, 32'h0);
|
||||
read_check_word(ADDR_UDI_LAST, 32'h0);
|
||||
|
||||
$display("--- test2: Enter syscall.");
|
||||
tb_syscall = 1;
|
||||
|
||||
read_check_word(ADDR_UDI_FIRST, 32'h00010203);
|
||||
read_check_word(ADDR_UDI_LAST, 32'h04050607);
|
||||
|
||||
$display("--- test2: Leave syscall.");
|
||||
tb_syscall = 0;
|
||||
|
||||
$display("--- test2: completed.");
|
||||
$display("");
|
||||
end
|
||||
@ -418,6 +586,10 @@ module tb_tk1 ();
|
||||
begin
|
||||
tc_ctr = tc_ctr + 1;
|
||||
|
||||
$display("--- test5: Reset DUT to switch to fw mode.");
|
||||
tb_syscall = 0;
|
||||
reset_dut();
|
||||
|
||||
$display("");
|
||||
$display("--- test3: Write and read CDI started.");
|
||||
$display("--- test3: Write CDI.");
|
||||
@ -441,9 +613,9 @@ module tb_tk1 ();
|
||||
read_check_word(ADDR_CDI_LAST + 0, 32'h70717273);
|
||||
|
||||
$display("--- test3: Switch to app mode.");
|
||||
write_word(ADDR_SYSTEM_MODE_CTRL, 32'hdeadbeef);
|
||||
fetch_instruction(APP_RAM_START);
|
||||
|
||||
$display("--- test3: Try to write CDI again.");
|
||||
$display("--- test3: Try to write CDI from app mode.");
|
||||
write_word(ADDR_CDI_FIRST + 0, 32'hfffefdfc);
|
||||
write_word(ADDR_CDI_FIRST + 1, 32'hefeeedec);
|
||||
write_word(ADDR_CDI_FIRST + 2, 32'hdfdedddc);
|
||||
@ -453,7 +625,7 @@ module tb_tk1 ();
|
||||
write_word(ADDR_CDI_FIRST + 6, 32'h8f8e8d8c);
|
||||
write_word(ADDR_CDI_FIRST + 7, 32'h7f7e7d7c);
|
||||
|
||||
$display("--- test3: Read CDI again.");
|
||||
$display("--- test3: Read CDI from app mode.");
|
||||
read_check_word(ADDR_CDI_FIRST + 0, 32'hf0f1f2f3);
|
||||
read_check_word(ADDR_CDI_FIRST + 1, 32'he0e1e2e3);
|
||||
read_check_word(ADDR_CDI_FIRST + 2, 32'hd0d1d2d3);
|
||||
@ -463,46 +635,38 @@ module tb_tk1 ();
|
||||
read_check_word(ADDR_CDI_FIRST + 6, 32'h80818283);
|
||||
read_check_word(ADDR_CDI_LAST + 0, 32'h70717273);
|
||||
|
||||
$display("--- test3: Enter syscall.");
|
||||
tb_syscall = 1;
|
||||
|
||||
$display("--- test3: Try to write CDI from syscall.");
|
||||
write_word(ADDR_CDI_FIRST + 0, 32'hfffefdfc);
|
||||
write_word(ADDR_CDI_FIRST + 1, 32'hefeeedec);
|
||||
write_word(ADDR_CDI_FIRST + 2, 32'hdfdedddc);
|
||||
write_word(ADDR_CDI_FIRST + 3, 32'hcfcecdcc);
|
||||
write_word(ADDR_CDI_FIRST + 4, 32'hafaeadac);
|
||||
write_word(ADDR_CDI_FIRST + 5, 32'h9f9e9d9c);
|
||||
write_word(ADDR_CDI_FIRST + 6, 32'h8f8e8d8c);
|
||||
write_word(ADDR_CDI_FIRST + 7, 32'h7f7e7d7c);
|
||||
|
||||
$display("--- test3: Read CDI from syscall.");
|
||||
read_check_word(ADDR_CDI_FIRST + 0, 32'hfffefdfc);
|
||||
read_check_word(ADDR_CDI_FIRST + 1, 32'hefeeedec);
|
||||
read_check_word(ADDR_CDI_FIRST + 2, 32'hdfdedddc);
|
||||
read_check_word(ADDR_CDI_FIRST + 3, 32'hcfcecdcc);
|
||||
read_check_word(ADDR_CDI_FIRST + 4, 32'hafaeadac);
|
||||
read_check_word(ADDR_CDI_FIRST + 5, 32'h9f9e9d9c);
|
||||
read_check_word(ADDR_CDI_FIRST + 6, 32'h8f8e8d8c);
|
||||
read_check_word(ADDR_CDI_LAST + 0, 32'h7f7e7d7c);
|
||||
|
||||
$display("--- test3: Leave syscall.");
|
||||
tb_syscall = 0;
|
||||
|
||||
$display("--- test3: completed.");
|
||||
$display("");
|
||||
end
|
||||
endtask // test3
|
||||
|
||||
|
||||
//----------------------------------------------------------------
|
||||
// test4()
|
||||
// Write and read blake2s entry point.
|
||||
//----------------------------------------------------------------
|
||||
task test4;
|
||||
begin
|
||||
tc_ctr = tc_ctr + 1;
|
||||
|
||||
$display("");
|
||||
$display("--- test4: Write and read blake2s entry point in fw mode started.");
|
||||
$display("--- test4: Reset DUT to switch to fw mode.");
|
||||
reset_dut();
|
||||
|
||||
$display("--- test4: Write Blake2s entry point.");
|
||||
write_word(ADDR_BLAKE2S, 32'hcafebabe);
|
||||
|
||||
$display("--- test4: Read Blake2s entry point.");
|
||||
read_check_word(ADDR_BLAKE2S, 32'hcafebabe);
|
||||
|
||||
$display("--- test4: Switch to app mode.");
|
||||
write_word(ADDR_SYSTEM_MODE_CTRL, 32'hf00ff00f);
|
||||
|
||||
$display("--- test4: Write Blake2s entry point again.");
|
||||
write_word(ADDR_BLAKE2S, 32'hdeadbeef);
|
||||
|
||||
$display("--- test4: Read Blake2s entry point again");
|
||||
read_check_word(ADDR_BLAKE2S, 32'hcafebabe);
|
||||
|
||||
$display("--- test4: completed.");
|
||||
$display("");
|
||||
end
|
||||
endtask // test4
|
||||
|
||||
|
||||
//----------------------------------------------------------------
|
||||
// test5()
|
||||
// Write and read APP start address end size.
|
||||
@ -525,7 +689,7 @@ module tb_tk1 ();
|
||||
read_check_word(ADDR_APP_SIZE, 32'h47114711);
|
||||
|
||||
$display("--- test5: Switch to app mode.");
|
||||
write_word(ADDR_SYSTEM_MODE_CTRL, 32'hf000000);
|
||||
fetch_instruction(APP_RAM_START);
|
||||
|
||||
$display("--- test5: Write app start address and size again.");
|
||||
write_word(ADDR_APP_START, 32'hdeadbeef);
|
||||
@ -543,7 +707,7 @@ module tb_tk1 ();
|
||||
|
||||
//----------------------------------------------------------------
|
||||
// test6()
|
||||
// Write RAM address and data randomizatio in fw mode.
|
||||
// Write and read RAM-address and data randomization.
|
||||
//----------------------------------------------------------------
|
||||
task test6;
|
||||
begin
|
||||
@ -552,6 +716,7 @@ module tb_tk1 ();
|
||||
$display("");
|
||||
$display("--- test6: Write RAM addr and data randomization in fw mode.");
|
||||
$display("--- test6: Reset DUT to switch to fw mode.");
|
||||
tb_syscall = 0;
|
||||
reset_dut();
|
||||
|
||||
$display("--- test6: Write to ADDR_RAM_ADDR_RAND and ADDR_RAM_DATA_RAND .");
|
||||
@ -562,9 +727,14 @@ module tb_tk1 ();
|
||||
"--- test6: Check value in dut ADDR_RAM_ADDR_RAND and ADDR_RAM_DATA_RAND registers.");
|
||||
$display("--- test6: ram_addr_rand_reg: 0x%04x, ram_data_rand_reg: 0x%08x",
|
||||
dut.ram_addr_rand, dut.ram_data_rand);
|
||||
check_equal(dut.ram_addr_rand, 15'h1337);
|
||||
check_equal(dut.ram_data_rand, 32'h47114711);
|
||||
read_check_word(ADDR_RAM_ADDR_RAND, 32'h0);
|
||||
read_check_word(ADDR_RAM_DATA_RAND, 32'h0);
|
||||
|
||||
|
||||
$display("--- test6: Switch to app mode.");
|
||||
write_word(ADDR_SYSTEM_MODE_CTRL, 32'hf000000);
|
||||
fetch_instruction(APP_RAM_START);
|
||||
|
||||
$display("--- test6: Write to ADDR_RAM_ADDR_RAND and ADDR_RAM_DATA_RAND again.");
|
||||
write_word(ADDR_RAM_ADDR_RAND, 32'hdeadbeef);
|
||||
@ -574,6 +744,30 @@ module tb_tk1 ();
|
||||
"--- test6: Check value in dut ADDR_RAM_ADDR_RAND and ADDR_RAM_DATA_RAND registers.");
|
||||
$display("--- test6: ram_addr_rand_reg: 0x%04x, ram_data_rand_reg: 0x%08x",
|
||||
dut.ram_addr_rand, dut.ram_data_rand);
|
||||
check_equal(dut.ram_addr_rand, 15'h1337);
|
||||
check_equal(dut.ram_data_rand, 32'h47114711);
|
||||
read_check_word(ADDR_RAM_ADDR_RAND, 32'h0);
|
||||
read_check_word(ADDR_RAM_DATA_RAND, 32'h0);
|
||||
|
||||
|
||||
$display("--- test6: Enter syscall.");
|
||||
tb_syscall = 1;
|
||||
|
||||
$display("--- test6: Write to ADDR_RAM_ADDR_RAND and ADDR_RAM_DATA_RAND again.");
|
||||
write_word(ADDR_RAM_ADDR_RAND, 32'hdeadbeef);
|
||||
write_word(ADDR_RAM_DATA_RAND, 32'hf00ff00f);
|
||||
|
||||
$display(
|
||||
"--- test6: Check value in dut ADDR_RAM_ADDR_RAND and ADDR_RAM_DATA_RAND registers.");
|
||||
$display("--- test6: ram_addr_rand_reg: 0x%04x, ram_data_rand_reg: 0x%08x",
|
||||
dut.ram_addr_rand, dut.ram_data_rand);
|
||||
check_equal(dut.ram_addr_rand, 15'h3eef);
|
||||
check_equal(dut.ram_data_rand, 32'hf00ff00f);
|
||||
read_check_word(ADDR_RAM_ADDR_RAND, 32'h0);
|
||||
read_check_word(ADDR_RAM_DATA_RAND, 32'h0);
|
||||
|
||||
$display("--- test6: Leave syscall.");
|
||||
tb_syscall = 0;
|
||||
|
||||
$display("--- test6: completed.");
|
||||
$display("");
|
||||
@ -655,17 +849,20 @@ module tb_tk1 ();
|
||||
write_word(ADDR_CPU_MON_LAST, 32'hdeadcafe);
|
||||
$display("--- test9: cpu_mon_first_reg: 0x%08x, cpu_mon_last_reg: 0x%08x",
|
||||
dut.cpu_mon_first_reg, dut.cpu_mon_last_reg);
|
||||
check_equal(dut.cpu_mon_first_reg, 32'h10000000);
|
||||
check_equal(dut.cpu_mon_last_reg, 32'h20000000);
|
||||
|
||||
$display("--- test9: force_trap before illegal access: 0x%1x", tb_force_trap);
|
||||
$display("--- test9: Creating an illegal access.");
|
||||
|
||||
tb_cpu_addr = 32'h13371337;
|
||||
tb_cpu_instr = 1'h1;
|
||||
tb_cpu_valid = 1'h1;
|
||||
#(2 * CLK_PERIOD);
|
||||
fetch_instruction(32'h13371337);
|
||||
$display("--- test9: cpu_addr: 0x%08x, cpu_instr: 0x%1x, cpu_valid: 0x%1x", tb_cpu_addr,
|
||||
tb_cpu_instr, tb_cpu_valid);
|
||||
check_equal(dut.cpu_mon_first_reg, 32'h10000000);
|
||||
check_equal(dut.cpu_mon_last_reg, 32'h20000000);
|
||||
|
||||
$display("--- test9: force_trap: 0x%1x", tb_force_trap);
|
||||
check_equal(tb_force_trap, 1);
|
||||
|
||||
$display("--- test9: completed.");
|
||||
$display("");
|
||||
@ -673,6 +870,66 @@ module tb_tk1 ();
|
||||
endtask // test9
|
||||
|
||||
|
||||
//----------------------------------------------------------------
|
||||
// check_inverting_spi_loopback_transfer_succeeds()
|
||||
// Do an SPI tranfer. Check that the received value is the inverse
|
||||
// of the value sent.
|
||||
//----------------------------------------------------------------
|
||||
task check_inverting_spi_loopback_transfer_succeeds(input [32 : 0] data);
|
||||
begin : check_inverting_spi_loopback_transfer
|
||||
$display("--- test10: Sending a byte.");
|
||||
write_word(ADDR_SPI_EN, 32'h1);
|
||||
write_word(ADDR_SPI_DATA, data);
|
||||
write_word(ADDR_SPI_XFER, 32'h1);
|
||||
|
||||
// Ready ready flag in SPI until it is set.
|
||||
read_word(ADDR_SPI_XFER);
|
||||
while (!tb_read_data) begin
|
||||
read_word(ADDR_SPI_XFER);
|
||||
end
|
||||
$display("--- test10: Byte should have been sent.");
|
||||
|
||||
#(2 * CLK_PERIOD);
|
||||
read_check_word(ADDR_SPI_DATA, ~data[7 : 0] & 8'hff);
|
||||
write_word(ADDR_SPI_EN, 32'h0);
|
||||
end
|
||||
endtask
|
||||
|
||||
|
||||
//----------------------------------------------------------------
|
||||
// check_spi_does_not_transfer()
|
||||
// Do an SPI transfer. Check that the SS, SCK and MISO signal are
|
||||
// not active.
|
||||
//----------------------------------------------------------------
|
||||
task check_spi_does_not_transfer;
|
||||
begin : check_spi_does_not_transfer
|
||||
reg [31 : 0] wait_ctr;
|
||||
reg error;
|
||||
localparam CLK_PER_SPI_BIT = 3;
|
||||
localparam WAIT_MARGIN = 10;
|
||||
|
||||
error = 0;
|
||||
wait_ctr = CLK_PER_SPI_BIT * 8 * WAIT_MARGIN;
|
||||
|
||||
$display("--- test10: Sending a byte.");
|
||||
write_word(ADDR_SPI_EN, 32'h1);
|
||||
write_word(ADDR_SPI_DATA, 32'haa);
|
||||
write_word(ADDR_SPI_XFER, 32'h1);
|
||||
|
||||
$display("--- test10: Waiting to see if SPI signals change state.");
|
||||
while (!error && (wait_ctr != 0)) begin
|
||||
if (~tb_spi_ss || tb_spi_sck || tb_spi_mosi) begin
|
||||
$display("--- Error: SPI signals changed state");
|
||||
error_ctr = error_ctr + 1;
|
||||
error = 1;
|
||||
end
|
||||
#(CLK_PERIOD);
|
||||
wait_ctr = wait_ctr - 1;
|
||||
end
|
||||
end
|
||||
endtask
|
||||
|
||||
|
||||
//----------------------------------------------------------------
|
||||
// test10()
|
||||
// SPI master loopback test.
|
||||
@ -683,28 +940,28 @@ module tb_tk1 ();
|
||||
tb_monitor = 0;
|
||||
tb_spi_monitor = 0;
|
||||
|
||||
restore_mem_bus();
|
||||
reset_dut();
|
||||
|
||||
$display("");
|
||||
$display("--- test10: Loopback in SPI Master started.");
|
||||
|
||||
#(CLK_PERIOD);
|
||||
|
||||
// Sending 0xa7 trough the inverting loopback.
|
||||
$display("--- test10: Sending a byte.");
|
||||
write_word(ADDR_SPI_EN, 32'h1);
|
||||
write_word(ADDR_SPI_DATA, 32'ha7);
|
||||
write_word(ADDR_SPI_XFER, 32'h1);
|
||||
check_inverting_spi_loopback_transfer_succeeds(32'ha7);
|
||||
|
||||
// Ready ready flag in SPI until it is set.
|
||||
read_word(ADDR_SPI_XFER);
|
||||
while (!tb_read_data) begin
|
||||
read_word(ADDR_SPI_XFER);
|
||||
end
|
||||
$display("--- test10: Byte should have been sent.");
|
||||
$display("--- test10: Switch to app mode.");
|
||||
fetch_instruction(APP_RAM_START);
|
||||
|
||||
// 0x58 is the inverse of 0xa7.
|
||||
#(2 * CLK_PERIOD);
|
||||
read_check_word(ADDR_SPI_DATA, 32'h58);
|
||||
write_word(ADDR_SPI_EN, 32'h0);
|
||||
check_spi_does_not_transfer();
|
||||
|
||||
$display("--- test10: Enter syscall.");
|
||||
tb_syscall = 1;
|
||||
|
||||
check_inverting_spi_loopback_transfer_succeeds(32'hc8);
|
||||
|
||||
$display("--- test10: Leave syscall.");
|
||||
tb_syscall = 0;
|
||||
|
||||
tb_monitor = 0;
|
||||
tb_spi_monitor = 0;
|
||||
@ -714,6 +971,198 @@ module tb_tk1 ();
|
||||
end
|
||||
endtask // test10
|
||||
|
||||
|
||||
//----------------------------------------------------------------
|
||||
// test11()
|
||||
// Test security monitor trap ranges.
|
||||
// - Check that reading accessible areas does not trap
|
||||
// - Check that reading the start and end of inaccessible areas
|
||||
// trap
|
||||
//----------------------------------------------------------------
|
||||
task test11;
|
||||
begin
|
||||
tc_ctr = tc_ctr + 1;
|
||||
|
||||
$display("");
|
||||
$display("--- test11: Test trap ranges.");
|
||||
|
||||
// ROM trap range: 0x00004000-0x3fffffff
|
||||
$display("--- test11: ROM");
|
||||
cpu_read_check_range_should_not_trap(32'h0, 32'h1fff);
|
||||
cpu_read_check_range_should_trap(32'h2000, 32'h200f);
|
||||
cpu_read_check_range_should_trap(32'h3ffffff0, 32'h3fffffff);
|
||||
|
||||
// RAM trap range: 0x40020000-0x7fffffff
|
||||
$display("--- test11: RAM");
|
||||
cpu_read_check_range_should_not_trap(32'h40000000, 32'h4000000f);
|
||||
cpu_read_check_range_should_trap(32'h40020000, 32'h4002000f);
|
||||
cpu_read_check_range_should_trap(32'h7ffffff0, 32'h7fffffff);
|
||||
|
||||
// Reserved trap range: 0x80000000-0xbfffffff
|
||||
$display("--- test11: Reserved");
|
||||
cpu_read_check_range_should_trap(32'h80000000, 32'h8000000f);
|
||||
cpu_read_check_range_should_trap(32'hbffffff0, 32'hbfffffff);
|
||||
|
||||
// TRNG trap range: 0xc0000400-0xc0ffffff
|
||||
$display("--- test11: TRNG");
|
||||
cpu_read_check_range_should_not_trap(32'hc0000000, 32'hc00003ff);
|
||||
cpu_read_check_range_should_trap(32'hc0000400, 32'hc000040f);
|
||||
cpu_read_check_range_should_trap(32'hc0fffff0, 32'hc0ffffff);
|
||||
|
||||
// TIMER trap range: 0xc1000400-0xc1ffffff
|
||||
$display("--- test11: TIMER");
|
||||
cpu_read_check_range_should_not_trap(32'hc1000000, 32'hc10003ff);
|
||||
cpu_read_check_range_should_trap(32'hc1000400, 32'hc100040f);
|
||||
cpu_read_check_range_should_trap(32'hc1fffff0, 32'hc1ffffff);
|
||||
|
||||
// UDS trap range: 0xc2000020-0xc2ffffff
|
||||
$display("--- test11: UDS");
|
||||
cpu_read_check_range_should_not_trap(32'hc2000000, 32'hc200001f);
|
||||
cpu_read_check_range_should_trap(32'hc2000020, 32'hc200002f);
|
||||
cpu_read_check_range_should_trap(32'hc2fffff0, 32'hc2ffffff);
|
||||
|
||||
// UART trap range: 0xc3000400-0xc3ffffff
|
||||
$display("--- test11: UART");
|
||||
cpu_read_check_range_should_not_trap(32'hc3000000, 32'hc30003ff);
|
||||
cpu_read_check_range_should_trap(32'hc3000400, 32'hc300040f);
|
||||
cpu_read_check_range_should_trap(32'hc3fffff0, 32'hc3ffffff);
|
||||
|
||||
// TOUCH_SENSE trap range: 0xc4000400-0xc4ffffff
|
||||
$display("--- test11: TOUCH_SENSE");
|
||||
cpu_read_check_range_should_not_trap(32'hc4000000, 32'hc40003ff);
|
||||
cpu_read_check_range_should_trap(32'hc4000400, 32'hc400040f);
|
||||
cpu_read_check_range_should_trap(32'hc4fffff0, 32'hc4ffffff);
|
||||
|
||||
// Unused trap range: 0xc5000000-0xcfffffff
|
||||
$display("--- test11: Unused");
|
||||
cpu_read_check_range_should_trap(32'hc5000000, 32'hc500000f);
|
||||
cpu_read_check_range_should_trap(32'hc5fffff0, 32'hc5ffffff);
|
||||
|
||||
// FW_RAM trap range: 0xd0000800-0xd0ffffff
|
||||
$display("--- test11: FW_RAM");
|
||||
cpu_read_check_range_should_not_trap(32'hd0000000, 32'hd0000fff);
|
||||
cpu_read_check_range_should_trap(32'hd0001000, 32'hd000100f);
|
||||
cpu_read_check_range_should_trap(32'hd0fffff0, 32'hd0ffffff);
|
||||
|
||||
// Unused trap range: 0xd1000000-0xfeffffff
|
||||
$display("--- test11: Unused");
|
||||
cpu_read_check_range_should_trap(32'hd1000000, 32'hd100000f);
|
||||
cpu_read_check_range_should_trap(32'he0fffff0, 32'he0ffffff);
|
||||
|
||||
// SYSCALL trap range. 0xe1000004-0xe1ffffff
|
||||
$display("--- test11: SYSCALL");
|
||||
cpu_read_check_range_should_not_trap(32'he1000000, 32'he1000003);
|
||||
cpu_read_check_range_should_trap(32'he1000004, 32'he100000f);
|
||||
cpu_read_check_range_should_trap(32'he1fffff0, 32'he1ffffff);
|
||||
|
||||
// Unused trap range: 0xe2000000-0xfeffffff
|
||||
$display("--- test11: Unused");
|
||||
cpu_read_check_range_should_trap(32'he2000000, 32'he200000f);
|
||||
cpu_read_check_range_should_trap(32'hfefffff0, 32'hfeffffff);
|
||||
|
||||
// TK1 trap range: 0xff000400-0xffffffff
|
||||
$display("--- test11: TK1");
|
||||
cpu_read_check_range_should_not_trap(32'hff000000, 32'hff0003ff);
|
||||
cpu_read_check_range_should_trap(32'hff000400, 32'hff00040f);
|
||||
cpu_read_check_range_should_trap(32'hfffffff0, 32'hffffffff);
|
||||
|
||||
$display("--- test11: completed.");
|
||||
$display("");
|
||||
end
|
||||
endtask // test11
|
||||
|
||||
|
||||
//----------------------------------------------------------------
|
||||
// test12()
|
||||
// Test ROM execution protection. Test trapping at ROM edges while
|
||||
// executing in different contexts.
|
||||
//----------------------------------------------------------------
|
||||
task test12;
|
||||
begin
|
||||
tc_ctr = tc_ctr + 1;
|
||||
|
||||
restore_mem_bus();
|
||||
|
||||
$display("");
|
||||
$display("--- test12: ROM execution allowed in firmware mode.");
|
||||
|
||||
reset_dut();
|
||||
fetch_instruction(ROM_START);
|
||||
check_equal(tb_force_trap, 0);
|
||||
|
||||
fetch_instruction(ROM_END);
|
||||
check_equal(tb_force_trap, 0);
|
||||
|
||||
$display("--- test12: ROM execution not allowed in app mode.");
|
||||
reset_dut();
|
||||
fetch_instruction(APP_RAM_START);
|
||||
fetch_instruction(ROM_START);
|
||||
check_equal(tb_force_trap, 1);
|
||||
|
||||
reset_dut();
|
||||
fetch_instruction(APP_RAM_START);
|
||||
fetch_instruction(ROM_END);
|
||||
check_equal(tb_force_trap, 1);
|
||||
|
||||
$display("--- test12: ROM execution allowed in syscalls made from app mode.");
|
||||
reset_dut();
|
||||
fetch_instruction(APP_RAM_START);
|
||||
tb_syscall = 1;
|
||||
|
||||
fetch_instruction(ROM_START);
|
||||
check_equal(tb_force_trap, 0);
|
||||
|
||||
fetch_instruction(ROM_END);
|
||||
check_equal(tb_force_trap, 0);
|
||||
|
||||
$display("--- test12: Leave syscall.");
|
||||
tb_syscall = 0;
|
||||
|
||||
$display("--- test12: completed.");
|
||||
$display("");
|
||||
end
|
||||
endtask // test12
|
||||
|
||||
|
||||
//----------------------------------------------------------------
|
||||
// test13()
|
||||
// System reset
|
||||
//----------------------------------------------------------------
|
||||
task test13;
|
||||
begin
|
||||
tc_ctr = tc_ctr + 1;
|
||||
|
||||
$display("");
|
||||
$display("--- test13: Reset allowed from firmware mode.");
|
||||
tb_syscall = 0;
|
||||
reset_dut();
|
||||
|
||||
write_word(ADDR_SYSTEM_RESET, 32'h1);
|
||||
check_equal(tb_system_reset, 1);
|
||||
|
||||
$display("--- test13: Reset not allowed from app mode.");
|
||||
reset_dut();
|
||||
fetch_instruction(APP_RAM_START);
|
||||
|
||||
write_word(ADDR_SYSTEM_RESET, 32'h1);
|
||||
check_equal(tb_system_reset, 0);
|
||||
|
||||
$display("--- test13: Reset allowed from syscall.");
|
||||
reset_dut();
|
||||
fetch_instruction(APP_RAM_START);
|
||||
tb_syscall = 1;
|
||||
|
||||
write_word(ADDR_SYSTEM_RESET, 32'h1);
|
||||
check_equal(tb_system_reset, 1);
|
||||
|
||||
tb_syscall = 0;
|
||||
|
||||
$display("--- test13: completed.");
|
||||
$display("");
|
||||
end
|
||||
endtask // test13
|
||||
|
||||
|
||||
//----------------------------------------------------------------
|
||||
// exit_with_error_code()
|
||||
//
|
||||
@ -746,7 +1195,6 @@ module tb_tk1 ();
|
||||
test1();
|
||||
test2();
|
||||
test3();
|
||||
test4();
|
||||
test5();
|
||||
test6();
|
||||
test7();
|
||||
@ -754,6 +1202,9 @@ module tb_tk1 ();
|
||||
test9();
|
||||
test9();
|
||||
test10();
|
||||
test11();
|
||||
test12();
|
||||
test13();
|
||||
|
||||
display_test_result();
|
||||
$display("");
|
||||
|
@ -6,8 +6,7 @@ Unique Device Secret core
|
||||
|
||||
This core store and protect the Unique Device Secret (UDS) asset. The
|
||||
UDS can be accessed as eight separate 32-bit words. The words can only
|
||||
be accessed as long as the system_mode input is low, implying that the
|
||||
CPU is executing the FW.
|
||||
be accessed as long as the `en` input is high.
|
||||
|
||||
The UDS words can be accessed in any order, but a given word can only
|
||||
be accessed once between reset cycles. This read once functionality is
|
||||
|
@ -17,8 +17,7 @@ module uds (
|
||||
input wire clk,
|
||||
input wire reset_n,
|
||||
|
||||
input wire system_mode,
|
||||
|
||||
input wire en,
|
||||
input wire cs,
|
||||
input wire [ 2 : 0] address,
|
||||
output wire [31 : 0] read_data,
|
||||
@ -89,7 +88,7 @@ module uds (
|
||||
if (cs) begin
|
||||
tmp_ready = 1'h1;
|
||||
|
||||
if (!system_mode) begin
|
||||
if (en) begin
|
||||
if (uds_rd_reg[address[2 : 0]] == 1'h0) begin
|
||||
uds_rd_we = 1'h1;
|
||||
end
|
||||
|
@ -37,7 +37,7 @@ module tb_uds ();
|
||||
|
||||
reg tb_clk;
|
||||
reg tb_reset_n;
|
||||
reg tb_system_mode;
|
||||
reg tb_app_mode;
|
||||
reg tb_cs;
|
||||
reg [ 7 : 0] tb_address;
|
||||
wire [31 : 0] tb_read_data;
|
||||
@ -50,7 +50,7 @@ module tb_uds ();
|
||||
.clk(tb_clk),
|
||||
.reset_n(tb_reset_n),
|
||||
|
||||
.system_mode(tb_system_mode),
|
||||
.app_mode(tb_app_mode),
|
||||
|
||||
.cs(tb_cs),
|
||||
.address(tb_address),
|
||||
@ -95,7 +95,7 @@ module tb_uds ();
|
||||
$display("State of DUT at cycle: %08d", cycle_ctr);
|
||||
$display("------------");
|
||||
$display("Inputs and outputs:");
|
||||
$display("system_mode: 0x%1x", tb_system_mode);
|
||||
$display("app_mode: 0x%1x", tb_app_mode);
|
||||
$display("cs: 0x%1x, address: 0x%02x, read_data: 0x%08x", tb_cs, tb_address, tb_read_data);
|
||||
$display("");
|
||||
|
||||
@ -160,7 +160,7 @@ module tb_uds ();
|
||||
|
||||
tb_clk = 1'h0;
|
||||
tb_reset_n = 1'h1;
|
||||
tb_system_mode = 1'h0;
|
||||
tb_app_mode = 1'h0;
|
||||
tb_cs = 1'h0;
|
||||
tb_address = 8'h0;
|
||||
end
|
||||
|
@ -1 +1 @@
|
||||
39d5aee11b8553544ba9171f83fbe6f5b7546a15c70d03325e72a2b0ca86c8f7a2b5b6bf121d1d3ffc84a502a2a1a6f3ea140d1424cd424336e055be2f394f83 firmware.bin
|
||||
77e6c9e519bce27f7be1a38c10839875ac8c75c71bef540f11569e821638af85a3e724089702a1c17af4c9caa06461ef38a3b8ad5bc5cb01ecf1f3107771708f firmware.bin
|
||||
|
@ -1,35 +1,43 @@
|
||||
# Firmware
|
||||
# Firmware implementation notes
|
||||
|
||||
## Introduction
|
||||
|
||||
This text is an introduction to, a requirement specification of,
|
||||
and some implementation notes of the TKey firmware. It also gives a
|
||||
few hint on developing and debugging the firmware.
|
||||
|
||||
This text is specific for the firmware. For a more general description
|
||||
on how to implement device apps, see [the TKey Developer
|
||||
Handbook](https://dev.tillitis.se/).
|
||||
This text is specific for the firmware, the piece of software in TKey
|
||||
ROM. For a more general description on how to implement device apps,
|
||||
see [the TKey Developer Handbook](https://dev.tillitis.se/).
|
||||
|
||||
## Definitions
|
||||
|
||||
- Firmware - software in ROM responsible for loading applications. The
|
||||
firmware is included as part of the FPGA bitstream and not
|
||||
replacable on a usual consumer TKey.
|
||||
- Device application or app - software supplied by the client which is
|
||||
received, loaded, measured, and started by the firmware.
|
||||
- Firmware: Software in ROM responsible for loading, measuring, and
|
||||
starting applications. The firmware is included as part of the FPGA
|
||||
bitstream and not replacable on a usual consumer TKey.
|
||||
- Client: Software running on a computer or a mobile phone the TKey is
|
||||
inserted into.
|
||||
- Device application or app: Software supplied by the client that runs
|
||||
on the TKey.
|
||||
|
||||
## CPU modes and firmware
|
||||
|
||||
The TKey has two modes of software operation: firmware mode and
|
||||
application mode. The TKey always starts in firmware mode and starts
|
||||
the firmware. When the firmware is about to start the application it
|
||||
switches to a more constrained environment, the application mode.
|
||||
application mode. The TKey always starts in firmware mode when it
|
||||
starts the firmware. When the application starts the hardware
|
||||
automatically switches to a more constrained environment: the
|
||||
application mode.
|
||||
|
||||
The TKey hardware cores are memory mapped. Firmware has complete
|
||||
access, except that the UDS is readable only once. The memory map is
|
||||
constrained when running in application mode, e.g. FW\_RAM and UDS
|
||||
isn't readable, and several other hardware addresses are either not
|
||||
readable or not writable for the application.
|
||||
The TKey hardware cores are memory mapped but the memory access is
|
||||
different depending on mode. Firmware has complete access, except that
|
||||
the Unique Device Secret (UDS) words are readable only once even in
|
||||
firmware mode. The memory map is constrained when running in
|
||||
application mode, e.g. FW\_RAM and UDS isn't readable, and several
|
||||
other hardware addresses are either not readable or not writable for
|
||||
the application.
|
||||
|
||||
When doing system calls from a device app the context switches back to
|
||||
firmware mode. However, the UDS is still not available, protected by
|
||||
two measures: 1) the UDS words can only be read out once and have
|
||||
already been read by firmware when measuring the app, and, 2) the UDS
|
||||
is protected by hardware after the execution leaves ROM for the first
|
||||
time.
|
||||
|
||||
See the table in [the Developer
|
||||
Handbook](https://dev.tillitis.se/memory/) for an overview about the
|
||||
@ -37,21 +45,70 @@ memory access control.
|
||||
|
||||
## Communication
|
||||
|
||||
The firmware communicates to the host via the
|
||||
`UART_{RX,TX}_{STATUS,DATA}` registers, using the framing protocol
|
||||
described in the [Framing
|
||||
Protocol](https://dev.tillitis.se/protocol/).
|
||||
The firmware communicates with the client using the
|
||||
`UART_{RX,TX}_{STATUS,DATA}` registers. On top of that is uses three
|
||||
protocols: The USB Mode protocol, the TKey framing protocol, and the
|
||||
firmware's own protocol.
|
||||
|
||||
To communicate between the CPU and the CH552 USB controller it uses an
|
||||
internal protocol, used only within the TKey, which we call the USB
|
||||
Mode Protocol. It is used in both directions.
|
||||
|
||||
| *Name* | *Size* | *Comment* |
|
||||
|----------|-----------|------------------------------------|
|
||||
| Endpoint | 1B | Origin or destination USB endpoint |
|
||||
| Length | 1B | Number of bytes following |
|
||||
| Payload | See above | Actual data from or to firmware |
|
||||
|
||||
The different endpoints:
|
||||
|
||||
| *Name* | *Value* | *Comment* |
|
||||
|--------|---------|----------------------------------------------------------------------|
|
||||
| CCID | 0x08 | USB CCID, a port for emulating a smart card |
|
||||
| CH552 | 0x10 | USB controller control |
|
||||
| DEBUG | 0x20 | A USB HID special debug pipe. Useful for debug prints. |
|
||||
| CDC | 0x40 | USB CDC-ACM, a serial port on the client. |
|
||||
| FIDO | 0x80 | A USB FIDO security token device, useful for FIDO-type applications. |
|
||||
|
||||
You can turn on and off different endpoints dynamically by sending
|
||||
commands to the `CH552` control endpoint. When the TKey starts only
|
||||
the `CH552` and the `CDC` endpoints are active. To change this, send a
|
||||
command to `CH552` in this form:
|
||||
|
||||
| *Name* | *Size* | *Comment* |
|
||||
|---------|--------|-------------------------------|
|
||||
| Command | 1B | Command to the CH552 firmware |
|
||||
| Payload | 1B | Data for the command |
|
||||
|
||||
Commands:
|
||||
|
||||
| *Name* | *Value* | *Argument* |
|
||||
|------------------|---------|----------------------|
|
||||
| Enable endpoints | 0x01 | Bitmask of endpoints |
|
||||
|
||||
On top of the USB Mode Protocol is [the TKey Framing
|
||||
Protocol](https://dev.tillitis.se/protocol/) which is described in the
|
||||
Developer Handbook.
|
||||
|
||||
The firmware uses a protocol on top of this framing layer which is
|
||||
used to bootstrap the application. All commands are initiated by the
|
||||
used to bootstrap an application. All commands are initiated by the
|
||||
client. All commands receive a reply. See [Firmware
|
||||
protocol](#firmware-protocol) for specific details.
|
||||
protocol](http://dev.tillitis.se/protocol/#firmware-protocol) in the
|
||||
Dev Handbook for specific details.
|
||||
|
||||
## Memory constraints
|
||||
|
||||
- ROM: 6 kByte.
|
||||
- FW\_RAM: 2 kByte.
|
||||
- RAM: 128 kByte.
|
||||
| *Name* | *Size* | *FW mode* | *App mode* |
|
||||
|---------|-----------|-----------|------------|
|
||||
| ROM | 8 kByte | r-x | r |
|
||||
| FW\_RAM | 4 kByte* | rw- | - |
|
||||
| RAM | 128 kByte | rwx | rwx |
|
||||
|
||||
* FW\_RAM is divided into the following areas:
|
||||
|
||||
- fw stack: 3824 bytes.
|
||||
- resetinfo: 256 bytes.
|
||||
- rest is available for .data and .bss.
|
||||
|
||||
## Firmware behaviour
|
||||
|
||||
@ -61,7 +118,7 @@ application received from the client over the USB/UART.
|
||||
The firmware binary is part of the FPGA bitstream as the initial
|
||||
values of the Block RAMs used to construct the `FW_ROM`. The `FW_ROM`
|
||||
start address is located at `0x0000_0000` in the CPU memory map, which
|
||||
is the CPU reset vector.
|
||||
is also the CPU reset vector.
|
||||
|
||||
### Firmware state machine
|
||||
|
||||
@ -125,29 +182,30 @@ is received, when state is changed to "running".
|
||||
|
||||
In "running", the loaded device app is measured, the Compound Device
|
||||
Identifier (CDI) is computed, we do some cleanup of firmware data
|
||||
structures, flip to application mode, and finally start the app, which
|
||||
ends the firmware state machine.
|
||||
structures, enable the system calls, and finally start the app, which
|
||||
ends the firmware state machine. Hardware guarantees that we leave
|
||||
firmware mode automatically when the program counter leaves ROM.
|
||||
|
||||
The device app is now running in application mode. There is no other
|
||||
means of getting back from application mode to firmware mode than
|
||||
resetting/power cycling the device. Note that ROM is still accessible
|
||||
in the memory map, so it's still possible to execute firmware code in
|
||||
application mode, but with no privileged access.
|
||||
The device app is now running in application mode. We can, however,
|
||||
return to firmware mode (excepting access to the UDS) by doing system
|
||||
calls. Note that ROM is still readable, but is now hardware protected
|
||||
from execution, except through the system call mechanism.
|
||||
|
||||
### Golden path
|
||||
|
||||
Firmware loads the application at the start of RAM (`0x4000_0000`). It
|
||||
uses the special FW\_RAM for its own stack.
|
||||
|
||||
When the firmware starts it clears all FW\_RAM, then sets up a stack
|
||||
there before jumping to `main()`.
|
||||
use a part of the special FW\_RAM for its own stack.
|
||||
|
||||
When reset is released, the CPU starts executing the firmware. It
|
||||
begins by clearing all CPU registers, and then sets up a stack for
|
||||
itself and then jumps to main().
|
||||
begins in `start.S` by clearing all CPU registers, clears all FW\_RAM,
|
||||
sets up a stack for itself there, and then jumps to `main()`. Also
|
||||
included in the assembly part of firmware is an interrupt handler for
|
||||
the system calls, but the handler is not yet enabled.
|
||||
|
||||
Beginning at `main()` it sets up the "system calls", then fills the
|
||||
entire RAM with pseudo random data and setting up the RAM address and
|
||||
data hardware scrambling with values from the True Random Number
|
||||
Generator (TRNG). It then waits for data coming in through the UART.
|
||||
Beginning at `main()` it fills the entire RAM with pseudo random data
|
||||
and setting up the RAM address and data hardware scrambling with
|
||||
values from the True Random Number Generator (TRNG). It then waits for
|
||||
data coming in through the UART.
|
||||
|
||||
Typical expected use scenario:
|
||||
|
||||
@ -176,32 +234,30 @@ Typical expected use scenario:
|
||||
([CDI]((#compound-device-identifier-computation))) is then
|
||||
computed by doing a new BLAKE2s using the Unique Device Secret
|
||||
(UDS), the application digest, and any User Supplied Secret
|
||||
(USS).
|
||||
(USS) digest already received.
|
||||
|
||||
6. The start address of the device app, currently `0x4000_0000`, is
|
||||
written to `APP_ADDR` and the size of the binary to `APP_SIZE` to
|
||||
let the device application know where it is loaded and how large
|
||||
it is, if it wants to relocate in RAM.
|
||||
|
||||
7. The firmware now clears the special `FW_RAM` where it keeps it
|
||||
stack. After this it performs no more function calls and uses no
|
||||
more automatic variables.
|
||||
7. The firmware now clears the part of the special `FW_RAM` where it
|
||||
keeps it stack.
|
||||
|
||||
8. Firmware starts the application by first switching to from
|
||||
firmware mode to application mode by writing to the `SYSTEM_MODE_CTRL`
|
||||
register. In this mode the MMIO region is restricted, e.g. some
|
||||
registers are removed (`UDS`), and some are switched from
|
||||
read/write to read-only (see [the memory
|
||||
8. The interrupt handler for system calls is enabled.
|
||||
|
||||
9. Firmware starts the application by jumping to the contents of
|
||||
`APP_ADDR`. Hardware automatically switches from firmware mode to
|
||||
application mode. In this mode some memory access is restricted,
|
||||
e.g. some addresses are inaccessible (`UDS`), and some are
|
||||
switched from read/write to read-only (see [the memory
|
||||
map](https://dev.tillitis.se/memory/)).
|
||||
|
||||
Then the firmware jumps to what is in `APP_ADDR` which starts the
|
||||
application.
|
||||
|
||||
If during this whole time any commands are received which are not
|
||||
allowed in the current state, we enter the "failed" state and execute
|
||||
an illegal instruction. An illegal instruction traps the CPU and
|
||||
hardware blinks the status LED red until a power cycle. No further
|
||||
instructions are executed.
|
||||
allowed in the current state, or any errors occur, we enter the
|
||||
"failed" state and execute an illegal instruction. An illegal
|
||||
instruction traps the CPU and hardware blinks the status LED red until
|
||||
a power cycle. No further instructions are executed.
|
||||
|
||||
### User-supplied Secret (USS)
|
||||
|
||||
@ -225,61 +281,58 @@ implementation in the FPGA at this time.
|
||||
|
||||
The firmware instead does the CDI computation using the special
|
||||
firmware-only `FW_RAM` which is invisible after switching to app mode.
|
||||
We keep the entire firmware stack in `FW_RAM` and clear it just before
|
||||
switching to app mode just in case.
|
||||
We keep the entire firmware stack in `FW_RAM` and clear the stack just
|
||||
before switching to app mode just in case.
|
||||
|
||||
We sleep for a random number of cycles before reading out the UDS,
|
||||
call `blake2s_update()` with it and then immediately call
|
||||
`blake2s_update()` again with the program digest, destroying the UDS
|
||||
stored in the internal context buffer. UDS should now not be in
|
||||
`FW_RAM` anymore. We can read UDS only once per power cycle so UDS
|
||||
should now not be available to firmware at all.
|
||||
should now not be available even to firmware.
|
||||
|
||||
Then we continue with the CDI computation by updating with an optional
|
||||
USS and then finalizing the hash, storing the resulting digest in
|
||||
USS digest and finalizing the hash, storing the resulting digest in
|
||||
`CDI`.
|
||||
|
||||
We also clear the entire `FW_RAM` where the stack lived, including the
|
||||
BLAKE2s context with the UDS, very soon after that, just before
|
||||
jumping to the application.
|
||||
### Firmware system calls
|
||||
|
||||
### Firmware services
|
||||
|
||||
The firmware exposes a BLAKE2s function through a function pointer
|
||||
located in MMIO `BLAKE2S` (see [memory
|
||||
map](system_description.md#memory-mapped-hardware-functions)) with the
|
||||
with function signature:
|
||||
|
||||
```c
|
||||
int blake2s(void *out, unsigned long outlen, const void *key,
|
||||
unsigned long keylen, const void *in, unsigned long inlen,
|
||||
blake2s_ctx *ctx);
|
||||
The firmware provides a system call mechanism through the use of the
|
||||
PicoRV32 interrupt handler. They are triggered by writing to the
|
||||
trigger address: 0xe1000000. It's typically done with a function
|
||||
signature like this:
|
||||
|
||||
```
|
||||
|
||||
where `blake2s_ctx` is:
|
||||
|
||||
```c
|
||||
typedef struct {
|
||||
uint8_t b[64]; // input buffer
|
||||
uint32_t h[8]; // chained state
|
||||
uint32_t t[2]; // total number of bytes
|
||||
size_t c; // pointer for b[]
|
||||
size_t outlen; // digest size
|
||||
} blake2s_ctx;
|
||||
int syscall(uint32_t number, uint32_t arg1);
|
||||
```
|
||||
|
||||
The `libcommon` library in
|
||||
[tkey-libs](https://github.com/tillitis/tkey-libs/)
|
||||
has a wrapper for using this function called `blake2s()` which needs
|
||||
to be maintained if you do any changes to the firmware call.
|
||||
Arguments are system call number and upto 6 generic arguments passed
|
||||
to the system call handler. The caller should place the system call
|
||||
number in the a0 register and the arguments in registers a1 to a7
|
||||
according to the RISC-V calling convention. The caller is responsible
|
||||
for saving and restoring registers.
|
||||
|
||||
The syscall handler returns execution on the next instruction after
|
||||
the store instruction to the trigger address. The return value from
|
||||
the syscall is now available in x10 (a0).
|
||||
|
||||
To add or change syscalls, see the `syscall_handler()` in
|
||||
`syscall_handler.c`.
|
||||
|
||||
Currently supported syscalls:
|
||||
|
||||
| *Name* | *Number* | *Argument* | *Description* |
|
||||
|-------------|----------|------------|----------------------------------|
|
||||
| RESET | 1 | Unused | Reset the TKey |
|
||||
| SET\_LED | 10 | Colour | Set the colour of the status LED |
|
||||
| GET\_VIDPID | 12 | Unused | Get Vendor and Product ID |
|
||||
|
||||
## Developing firmware
|
||||
|
||||
Standing in `hw/application_fpga/` you can run `make firmware.elf` to
|
||||
build just the firmware. You don't need all the FPGA development
|
||||
tools. See [the Developer Handbook](https://dev.tillitis.se/tools/)
|
||||
for the tools you need. The easiest is probably to use your OCI image,
|
||||
for the tools you need. The easiest is probably to use our OCI image,
|
||||
`ghcr.io/tillitis/tkey-builder`.
|
||||
|
||||
[Our version of qemu](https://dev.tillitis.se/tools/#qemu-emulator) is
|
||||
@ -287,11 +340,28 @@ also useful for debugging the firmware. You can attach GDB, use
|
||||
breakpoints, et cetera.
|
||||
|
||||
There is a special make target for QEMU: `qemu_firmware.elf`, which
|
||||
sets `-DQEMU_CONSOLE`, so you can use plain debug prints using the
|
||||
helper functions in `lib.c` like `htif_puts()` `htif_putinthex()`
|
||||
`htif_hexdump()` and friends. Note that these functions are only
|
||||
usable in qemu and that you might need to `make clean` before
|
||||
building, if you have already built before.
|
||||
sets `-DQEMU_DEBUG`, so you can debug prints using the `debug_*()`
|
||||
functions. Note that these functions are only usable in QEMU and that
|
||||
you might need to `make clean` before building, if you have already
|
||||
built before.
|
||||
|
||||
If you want debug prints to show up on the special TKey HID debug
|
||||
endpoint instead, define `-DTKEY_DEBUG`.
|
||||
|
||||
Note that if you use `TKEY_DEBUG` you *must* have something listening
|
||||
on the corresponding HID device. It's usually the last HID device
|
||||
created. On Linux, for instance, this means the last reported hidraw
|
||||
in `dmesg` is the one you should do `cat /dev/hidrawX` on.
|
||||
|
||||
### tkey-libs
|
||||
|
||||
Most of the utility functions that the firmware use lives in
|
||||
`tkey-libs`. The canonical place where you can find tkey-libs is at:
|
||||
|
||||
https://github.com/tillitis/tkey-libs
|
||||
|
||||
but we have vendored it in for firmware use in `../tkey-libs`. See top
|
||||
README for how to update.
|
||||
|
||||
### Test firmware
|
||||
|
||||
|
76
hw/application_fpga/fw/testapp/Makefile
Normal file
76
hw/application_fpga/fw/testapp/Makefile
Normal file
@ -0,0 +1,76 @@
|
||||
P := $(shell dirname $(realpath $(lastword $(MAKEFILE_LIST))))
|
||||
LIBDIR ?= ../../tkey-libs
|
||||
OBJCOPY ?= llvm-objcopy
|
||||
CC = clang
|
||||
CFLAGS = \
|
||||
-target riscv32-unknown-none-elf \
|
||||
-march=rv32iczmmul \
|
||||
-mabi=ilp32 \
|
||||
-mcmodel=medany \
|
||||
-static \
|
||||
-std=gnu99 \
|
||||
-O2 \
|
||||
-ffast-math \
|
||||
-fno-common \
|
||||
-fno-builtin-printf \
|
||||
-fno-builtin-putchar \
|
||||
-fno-builtin-memcpy \
|
||||
-nostdlib \
|
||||
-mno-relax \
|
||||
-Wall \
|
||||
-Wpedantic \
|
||||
-Wno-language-extension-token \
|
||||
-Werror \
|
||||
-flto \
|
||||
-g \
|
||||
-I $(LIBDIR)/include \
|
||||
-I $(LIBDIR)
|
||||
|
||||
AS = clang
|
||||
|
||||
ASFLAGS = \
|
||||
-target riscv32-unknown-none-elf \
|
||||
-march=rv32iczmmul \
|
||||
-mabi=ilp32 \
|
||||
-mno-relax
|
||||
|
||||
LDFLAGS = \
|
||||
-T $(P)/app.lds \
|
||||
-L $(LIBDIR) -lcommon
|
||||
|
||||
.PHONY: all
|
||||
all: testapp.bin
|
||||
|
||||
# Turn elf into bin for device
|
||||
%.bin: %.elf
|
||||
$(OBJCOPY) --input-target=elf32-littleriscv --output-target=binary $^ $@
|
||||
chmod a-x $@
|
||||
|
||||
.PHONY: tkey-libs
|
||||
tkey-libs:
|
||||
make -C $(LIBDIR)
|
||||
|
||||
TESTAPP_FMTFILES = \
|
||||
$(P)/main.c \
|
||||
$(P)/syscall.h
|
||||
|
||||
TESTAPP_OBJS = \
|
||||
$(P)/main.o \
|
||||
$(P)/crt0.o \
|
||||
$(P)/syscall.o
|
||||
|
||||
testapp.elf: tkey-libs $(TESTAPP_OBJS)
|
||||
$(CC) $(CFLAGS) $(TESTAPP_OBJS) $(LDFLAGS) -o $@
|
||||
|
||||
.PHONY: fmt
|
||||
fmt:
|
||||
clang-format --dry-run --ferror-limit=0 $(TESTAPP_FMTFILES)
|
||||
clang-format --verbose -i $(TESTAPP_FMTFILES)
|
||||
|
||||
.PHONY: checkfmt
|
||||
checkfmt:
|
||||
clang-format --dry-run --ferror-limit=0 --Werror $(TESTAPP_FMTFILES)
|
||||
|
||||
.PHONY: clean
|
||||
clean:
|
||||
rm -f testapp.bin testapp.elf $(TESTAPP_OBJS)
|
64
hw/application_fpga/fw/testapp/app.lds
Normal file
64
hw/application_fpga/fw/testapp/app.lds
Normal file
@ -0,0 +1,64 @@
|
||||
/*
|
||||
* SPDX-FileCopyrightText: 2022 Tillitis AB <tillitis.se>
|
||||
* SPDX-License-Identifier: BSD-2-Clause
|
||||
*/
|
||||
|
||||
OUTPUT_ARCH( "riscv" )
|
||||
ENTRY(_start)
|
||||
|
||||
MEMORY
|
||||
{
|
||||
RAM (rwx) : ORIGIN = 0x40000000, LENGTH = 0x20000 /* 128 KB */
|
||||
}
|
||||
|
||||
SECTIONS
|
||||
{
|
||||
.text.init :
|
||||
{
|
||||
*(.text.init)
|
||||
} >RAM
|
||||
|
||||
.text :
|
||||
{
|
||||
. = ALIGN(4);
|
||||
*(.text) /* .text sections (code) */
|
||||
*(.text*) /* .text* sections (code) */
|
||||
*(.rodata) /* .rodata sections (constants, strings, etc.) */
|
||||
*(.rodata*) /* .rodata* sections (constants, strings, etc.) */
|
||||
*(.srodata) /* .rodata sections (constants, strings, etc.) */
|
||||
*(.srodata*) /* .rodata* sections (constants, strings, etc.) */
|
||||
. = ALIGN(4);
|
||||
_etext = .;
|
||||
_sidata = _etext;
|
||||
} >RAM
|
||||
|
||||
.data : AT (_etext)
|
||||
{
|
||||
. = ALIGN(4);
|
||||
_sdata = .;
|
||||
. = ALIGN(4);
|
||||
*(.data) /* .data sections */
|
||||
*(.data*) /* .data* sections */
|
||||
*(.sdata) /* .sdata sections */
|
||||
*(.sdata*) /* .sdata* sections */
|
||||
. = ALIGN(4);
|
||||
_edata = .;
|
||||
} >RAM
|
||||
|
||||
/* Uninitialized data section */
|
||||
.bss :
|
||||
{
|
||||
. = ALIGN(4);
|
||||
_sbss = .;
|
||||
*(.bss)
|
||||
*(.bss*)
|
||||
*(.sbss)
|
||||
*(.sbss*)
|
||||
*(COMMON)
|
||||
|
||||
. = ALIGN(4);
|
||||
_ebss = .;
|
||||
} >RAM
|
||||
|
||||
/* libcrt0/crt0.S inits stack to start just below end of RAM */
|
||||
}
|
53
hw/application_fpga/fw/testapp/crt0.S
Normal file
53
hw/application_fpga/fw/testapp/crt0.S
Normal file
@ -0,0 +1,53 @@
|
||||
// SPDX-FileCopyrightText: 2022 Tillitis AB <tillitis.se>
|
||||
// SPDX-License-Identifier: BSD-2-Clause
|
||||
|
||||
.section ".text.init"
|
||||
.global _start
|
||||
_start:
|
||||
li x1, 0
|
||||
li x2, 0
|
||||
li x3, 0
|
||||
li x4, 0
|
||||
li x5, 0
|
||||
li x6, 0
|
||||
li x7, 0
|
||||
li x8, 0
|
||||
li x9, 0
|
||||
li x10,0
|
||||
li x11,0
|
||||
li x12,0
|
||||
li x13,0
|
||||
li x14,0
|
||||
li x15,0
|
||||
li x16,0
|
||||
li x17,0
|
||||
li x18,0
|
||||
li x19,0
|
||||
li x20,0
|
||||
li x21,0
|
||||
li x22,0
|
||||
li x23,0
|
||||
li x24,0
|
||||
li x25,0
|
||||
li x26,0
|
||||
li x27,0
|
||||
li x28,0
|
||||
li x29,0
|
||||
li x30,0
|
||||
li x31,0
|
||||
|
||||
/* init stack below 0x40020000 (TK1_RAM_BASE+TK1_RAM_SIZE) */
|
||||
li sp, 0x4001fff0
|
||||
|
||||
/* zero-init bss section */
|
||||
la a0, _sbss
|
||||
la a1, _ebss
|
||||
bge a0, a1, end_init_bss
|
||||
|
||||
loop_init_bss:
|
||||
sw zero, 0(a0)
|
||||
addi a0, a0, 4
|
||||
blt a0, a1, loop_init_bss
|
||||
|
||||
end_init_bss:
|
||||
call main
|
231
hw/application_fpga/fw/testapp/main.c
Normal file
231
hw/application_fpga/fw/testapp/main.c
Normal file
@ -0,0 +1,231 @@
|
||||
/*
|
||||
* Copyright (C) 2022, 2023 - Tillitis AB
|
||||
* SPDX-License-Identifier: GPL-2.0-only
|
||||
*/
|
||||
|
||||
#include <stdint.h>
|
||||
#include <tkey/assert.h>
|
||||
#include <tkey/io.h>
|
||||
#include <tkey/led.h>
|
||||
#include <tkey/lib.h>
|
||||
#include <tkey/tk1_mem.h>
|
||||
|
||||
#include "../tk1/proto.h"
|
||||
#include "../tk1/syscall_num.h"
|
||||
#include "syscall.h"
|
||||
|
||||
#define USBMODE_PACKET_SIZE 64
|
||||
|
||||
// clang-format off
|
||||
volatile uint32_t *tk1name0 = (volatile uint32_t *)TK1_MMIO_TK1_NAME0;
|
||||
volatile uint32_t *tk1name1 = (volatile uint32_t *)TK1_MMIO_TK1_NAME1;
|
||||
volatile uint32_t *uds = (volatile uint32_t *)TK1_MMIO_UDS_FIRST;
|
||||
volatile uint32_t *cdi = (volatile uint32_t *)TK1_MMIO_TK1_CDI_FIRST;
|
||||
volatile uint32_t *udi = (volatile uint32_t *)TK1_MMIO_TK1_UDI_FIRST;
|
||||
volatile uint8_t *fw_ram = (volatile uint8_t *)TK1_MMIO_FW_RAM_BASE;
|
||||
volatile uint32_t *system_reset = (volatile uint32_t *)TK1_MMIO_TK1_SYSTEM_RESET;
|
||||
volatile uint32_t *timer = (volatile uint32_t *)TK1_MMIO_TIMER_TIMER;
|
||||
volatile uint32_t *timer_prescaler = (volatile uint32_t *)TK1_MMIO_TIMER_PRESCALER;
|
||||
volatile uint32_t *timer_status = (volatile uint32_t *)TK1_MMIO_TIMER_STATUS;
|
||||
volatile uint32_t *timer_ctrl = (volatile uint32_t *)TK1_MMIO_TIMER_CTRL;
|
||||
volatile uint32_t *trng_status = (volatile uint32_t *)TK1_MMIO_TRNG_STATUS;
|
||||
volatile uint32_t *trng_entropy = (volatile uint32_t *)TK1_MMIO_TRNG_ENTROPY;
|
||||
// clang-format on
|
||||
|
||||
#define UDS_WORDS 8
|
||||
#define UDI_WORDS 2
|
||||
#define CDI_WORDS 8
|
||||
|
||||
void puthexn(uint8_t *p, int n)
|
||||
{
|
||||
for (int i = 0; i < n; i++) {
|
||||
puthex(IO_CDC, p[i]);
|
||||
}
|
||||
}
|
||||
|
||||
void reverseword(uint32_t *wordp)
|
||||
{
|
||||
*wordp = ((*wordp & 0xff000000) >> 24) | ((*wordp & 0x00ff0000) >> 8) |
|
||||
((*wordp & 0x0000ff00) << 8) | ((*wordp & 0x000000ff) << 24);
|
||||
}
|
||||
|
||||
uint32_t wait_timer_tick(uint32_t last_timer)
|
||||
{
|
||||
uint32_t newtimer;
|
||||
for (;;) {
|
||||
newtimer = *timer;
|
||||
if (newtimer != last_timer) {
|
||||
return newtimer;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void failmsg(char *s)
|
||||
{
|
||||
puts(IO_CDC, "FAIL: ");
|
||||
puts(IO_CDC, s);
|
||||
puts(IO_CDC, "\r\n");
|
||||
}
|
||||
|
||||
int main(void)
|
||||
{
|
||||
uint8_t in = 0;
|
||||
uint8_t available = 0;
|
||||
enum ioend endpoint = IO_NONE;
|
||||
|
||||
led_set(LED_BLUE);
|
||||
|
||||
// Wait for terminal program and a character to be typed
|
||||
if (readselect(IO_CDC, &endpoint, &available) < 0) {
|
||||
// readselect failed! I/O broken? Just redblink.
|
||||
assert(1 == 2);
|
||||
}
|
||||
|
||||
if (read(IO_CDC, &in, 1, 1) < 0) {
|
||||
// read failed! I/O broken? Just redblink.
|
||||
assert(1 == 2);
|
||||
}
|
||||
|
||||
puts(IO_CDC, "\r\nI'm testapp on:");
|
||||
// Output the TK1 core's NAME0 and NAME1
|
||||
uint32_t name;
|
||||
wordcpy_s(&name, 1, (void *)tk1name0, 1);
|
||||
reverseword(&name);
|
||||
write(IO_CDC, (const uint8_t *)&name, 4);
|
||||
puts(IO_CDC, " ");
|
||||
wordcpy_s(&name, 1, (void *)tk1name1, 1);
|
||||
reverseword(&name);
|
||||
write(IO_CDC, (const uint8_t *)&name, 4);
|
||||
puts(IO_CDC, "\r\n");
|
||||
|
||||
uint32_t zeros[8];
|
||||
memset(zeros, 0, 8 * 4);
|
||||
|
||||
int anyfailed = 0;
|
||||
|
||||
uint32_t uds_local[UDS_WORDS];
|
||||
uint32_t udi_local[UDI_WORDS];
|
||||
|
||||
// Should NOT be able to read from UDS in app-mode.
|
||||
wordcpy_s(uds_local, UDS_WORDS, (void *)uds, UDS_WORDS);
|
||||
if (!memeq(uds_local, zeros, UDS_WORDS * 4)) {
|
||||
failmsg("Read from UDS in app-mode");
|
||||
anyfailed = 1;
|
||||
}
|
||||
|
||||
// Should NOT be able to read from UDI in app-mode.
|
||||
wordcpy_s(udi_local, UDI_WORDS, (void *)udi, UDI_WORDS);
|
||||
if (!memeq(udi_local, zeros, UDI_WORDS * 4)) {
|
||||
failmsg("Read from UDI in app-mode");
|
||||
anyfailed = 1;
|
||||
}
|
||||
|
||||
// But a syscall to get parts of UDI should be able to run
|
||||
int vidpid = syscall(TK1_SYSCALL_GET_VIDPID, 0);
|
||||
|
||||
if (vidpid != 0x00010203) {
|
||||
failmsg("Expected VID/PID to be 0x00010203");
|
||||
anyfailed = 1;
|
||||
}
|
||||
|
||||
uint32_t cdi_local[CDI_WORDS];
|
||||
uint32_t cdi_local2[CDI_WORDS];
|
||||
wordcpy_s(cdi_local, CDI_WORDS, (void *)cdi, CDI_WORDS);
|
||||
|
||||
// Write to CDI should NOT have any effect in app mode.
|
||||
wordcpy_s((void *)cdi, CDI_WORDS, zeros, CDI_WORDS);
|
||||
wordcpy_s(cdi_local2, CDI_WORDS, (void *)cdi, CDI_WORDS);
|
||||
if (!memeq(cdi_local, cdi_local2, CDI_WORDS * 4)) {
|
||||
failmsg("Write to CDI in app-mode");
|
||||
anyfailed = 1;
|
||||
}
|
||||
|
||||
// Should NOT be able to reset Tkey from app mode
|
||||
puts(IO_CDC, "\r\nTesting system reset...");
|
||||
*system_reset = 1;
|
||||
puts(IO_CDC, "done.\r\n");
|
||||
|
||||
// Test FW_RAM.
|
||||
*fw_ram = 0x21;
|
||||
if (*fw_ram == 0x21) {
|
||||
failmsg("Write and read FW RAM in app-mode");
|
||||
anyfailed = 1;
|
||||
}
|
||||
|
||||
puts(IO_CDC, "\r\nTesting timer... 3");
|
||||
// Matching clock at 21 MHz, giving us timer in seconds
|
||||
*timer_prescaler = 21 * 1000000;
|
||||
|
||||
// Test timer expiration after 1s
|
||||
*timer = 1;
|
||||
// Start the timer
|
||||
*timer_ctrl = (1 << TK1_MMIO_TIMER_CTRL_START_BIT);
|
||||
while (*timer_status & (1 << TK1_MMIO_TIMER_STATUS_RUNNING_BIT)) {
|
||||
}
|
||||
// Now timer has expired and is ready to run again
|
||||
puts(IO_CDC, " 2");
|
||||
|
||||
// Test to interrupt a timer - and reads from timer register
|
||||
// Starting 10s timer and interrupting it in 3s...
|
||||
*timer = 10;
|
||||
*timer_ctrl = (1 << TK1_MMIO_TIMER_CTRL_START_BIT);
|
||||
uint32_t last_timer = 10;
|
||||
for (int i = 0; i < 3; i++) {
|
||||
last_timer = wait_timer_tick(last_timer);
|
||||
}
|
||||
|
||||
// Stop the timer
|
||||
*timer_ctrl = (1 << TK1_MMIO_TIMER_CTRL_STOP_BIT);
|
||||
puts(IO_CDC, " 1. done.\r\n");
|
||||
|
||||
if (*timer_status & (1 << TK1_MMIO_TIMER_STATUS_RUNNING_BIT)) {
|
||||
failmsg("Timer didn't stop");
|
||||
anyfailed = 1;
|
||||
}
|
||||
|
||||
if (*timer != 10) {
|
||||
failmsg("Timer didn't reset to 10");
|
||||
anyfailed = 1;
|
||||
}
|
||||
|
||||
// Check and display test results.
|
||||
puts(IO_CDC, "\r\n--> ");
|
||||
if (anyfailed) {
|
||||
puts(IO_CDC, "Some test FAILED!\r\n");
|
||||
} else {
|
||||
puts(IO_CDC, "All tests passed.\r\n");
|
||||
}
|
||||
|
||||
puts(IO_CDC, "\r\nHere are 256 bytes from the TRNG:\r\n");
|
||||
for (int j = 0; j < 8; j++) {
|
||||
for (int i = 0; i < 8; i++) {
|
||||
while ((*trng_status &
|
||||
(1 << TK1_MMIO_TRNG_STATUS_READY_BIT)) == 0) {
|
||||
}
|
||||
uint32_t rnd = *trng_entropy;
|
||||
puthexn((uint8_t *)&rnd, 4);
|
||||
puts(IO_CDC, " ");
|
||||
}
|
||||
puts(IO_CDC, "\r\n");
|
||||
}
|
||||
puts(IO_CDC, "\r\n");
|
||||
|
||||
puts(IO_CDC, "Now echoing what you type...Type + to reset device\r\n");
|
||||
for (;;) {
|
||||
if (readselect(IO_CDC, &endpoint, &available) < 0) {
|
||||
// readselect failed! I/O broken? Just redblink.
|
||||
assert(1 == 2);
|
||||
}
|
||||
|
||||
if (read(IO_CDC, &in, 1, 1) < 0) {
|
||||
// read failed! I/O broken? Just redblink.
|
||||
assert(1 == 2);
|
||||
}
|
||||
|
||||
if (in == '+') {
|
||||
syscall(TK1_SYSCALL_RESET, 0);
|
||||
}
|
||||
|
||||
write(IO_CDC, &in, 1);
|
||||
}
|
||||
}
|
85
hw/application_fpga/fw/testapp/syscall.S
Normal file
85
hw/application_fpga/fw/testapp/syscall.S
Normal file
@ -0,0 +1,85 @@
|
||||
// SPDX-FileCopyrightText: 2024 Tillitis AB <tillitis.se>
|
||||
// SPDX-License-Identifier: BSD-2-Clause
|
||||
|
||||
#include "../tk1/picorv32/custom_ops.S"
|
||||
|
||||
.section ".text"
|
||||
.globl syscall
|
||||
|
||||
|
||||
syscall:
|
||||
// Save registers to stack
|
||||
addi sp, sp, -32*4
|
||||
sw x0, 0*4(sp)
|
||||
sw x1, 1*4(sp)
|
||||
// x2 (sp) is assumed to be preserved by the interrupt handler.
|
||||
sw x3, 3*4(sp)
|
||||
sw x4, 4*4(sp)
|
||||
sw x5, 5*4(sp)
|
||||
sw x6, 6*4(sp)
|
||||
sw x7, 7*4(sp)
|
||||
sw x8, 8*4(sp)
|
||||
sw x9, 9*4(sp)
|
||||
// x10 (a0) will contain syscall return value. And should not be saved.
|
||||
sw x11, 11*4(sp)
|
||||
sw x12, 12*4(sp)
|
||||
sw x13, 13*4(sp)
|
||||
sw x14, 14*4(sp)
|
||||
sw x15, 15*4(sp)
|
||||
sw x16, 16*4(sp)
|
||||
sw x17, 17*4(sp)
|
||||
sw x18, 18*4(sp)
|
||||
sw x19, 19*4(sp)
|
||||
sw x20, 20*4(sp)
|
||||
sw x21, 21*4(sp)
|
||||
sw x22, 22*4(sp)
|
||||
sw x23, 23*4(sp)
|
||||
sw x24, 24*4(sp)
|
||||
sw x25, 25*4(sp)
|
||||
sw x26, 26*4(sp)
|
||||
sw x27, 27*4(sp)
|
||||
sw x28, 28*4(sp)
|
||||
sw x29, 29*4(sp)
|
||||
sw x30, 30*4(sp)
|
||||
sw x31, 31*4(sp)
|
||||
|
||||
// Trigger syscall interrupt
|
||||
li t1, 0xe1000000 // Syscall interrupt trigger address
|
||||
sw zero, 0(t1) // Trigger interrupt
|
||||
|
||||
// Restore registers from stack
|
||||
lw x0, 0*4(sp)
|
||||
lw x1, 1*4(sp)
|
||||
// x2 (sp) is assumed to be preserved by the interrupt handler.
|
||||
lw x3, 3*4(sp)
|
||||
lw x4, 4*4(sp)
|
||||
lw x5, 5*4(sp)
|
||||
lw x6, 6*4(sp)
|
||||
lw x7, 7*4(sp)
|
||||
lw x8, 8*4(sp)
|
||||
lw x9, 9*4(sp)
|
||||
// x10 (a0) contains syscall return value. And should not be destroyed.
|
||||
lw x11, 11*4(sp)
|
||||
lw x12, 12*4(sp)
|
||||
lw x13, 13*4(sp)
|
||||
lw x14, 14*4(sp)
|
||||
lw x15, 15*4(sp)
|
||||
lw x16, 16*4(sp)
|
||||
lw x17, 17*4(sp)
|
||||
lw x18, 18*4(sp)
|
||||
lw x19, 19*4(sp)
|
||||
lw x20, 20*4(sp)
|
||||
lw x21, 21*4(sp)
|
||||
lw x22, 22*4(sp)
|
||||
lw x23, 23*4(sp)
|
||||
lw x24, 24*4(sp)
|
||||
lw x25, 25*4(sp)
|
||||
lw x26, 26*4(sp)
|
||||
lw x27, 27*4(sp)
|
||||
lw x28, 28*4(sp)
|
||||
lw x29, 29*4(sp)
|
||||
lw x30, 30*4(sp)
|
||||
lw x31, 31*4(sp)
|
||||
addi sp, sp, 32*4
|
||||
|
||||
ret
|
11
hw/application_fpga/fw/testapp/syscall.h
Normal file
11
hw/application_fpga/fw/testapp/syscall.h
Normal file
@ -0,0 +1,11 @@
|
||||
// SPDX-FileCopyrightText: 2024 Tillitis AB <tillitis.se>
|
||||
// SPDX-License-Identifier: BSD-2-Clause
|
||||
|
||||
#include <stdint.h>
|
||||
|
||||
#ifndef TKEY_APP_SYSCALL_H
|
||||
#define TKEY_APP_SYSCALL_H
|
||||
|
||||
int syscall(uint32_t number, uint32_t arg1);
|
||||
|
||||
#endif
|
@ -3,11 +3,16 @@
|
||||
* SPDX-License-Identifier: GPL-2.0-only
|
||||
*/
|
||||
|
||||
#include "../tk1/blake2s/blake2s.h"
|
||||
#include "../tk1/lib.h"
|
||||
#include <stddef.h>
|
||||
#include <stdint.h>
|
||||
#include <tkey/assert.h>
|
||||
#include <tkey/io.h>
|
||||
#include <tkey/lib.h>
|
||||
#include <tkey/tk1_mem.h>
|
||||
|
||||
#include "../tk1/proto.h"
|
||||
#include "../tk1/types.h"
|
||||
#include "../tk1_mem.h"
|
||||
|
||||
#define USBMODE_PACKET_SIZE 64
|
||||
|
||||
// clang-format off
|
||||
volatile uint32_t *tk1name0 = (volatile uint32_t *)TK1_MMIO_TK1_NAME0;
|
||||
@ -15,80 +20,27 @@ volatile uint32_t *tk1name1 = (volatile uint32_t *)TK1_MMIO_TK1_NAME1;
|
||||
volatile uint32_t *uds = (volatile uint32_t *)TK1_MMIO_UDS_FIRST;
|
||||
volatile uint32_t *cdi = (volatile uint32_t *)TK1_MMIO_TK1_CDI_FIRST;
|
||||
volatile uint32_t *udi = (volatile uint32_t *)TK1_MMIO_TK1_UDI_FIRST;
|
||||
volatile uint32_t *system_mode_ctrl = (volatile uint32_t *)TK1_MMIO_TK1_SYSTEM_MODE_CTRL;
|
||||
volatile uint8_t *fw_ram = (volatile uint8_t *)TK1_MMIO_FW_RAM_BASE;
|
||||
volatile uint32_t *system_reset = (volatile uint32_t *)TK1_MMIO_TK1_SYSTEM_RESET;
|
||||
volatile uint32_t *timer = (volatile uint32_t *)TK1_MMIO_TIMER_TIMER;
|
||||
volatile uint32_t *timer_prescaler = (volatile uint32_t *)TK1_MMIO_TIMER_PRESCALER;
|
||||
volatile uint32_t *timer_status = (volatile uint32_t *)TK1_MMIO_TIMER_STATUS;
|
||||
volatile uint32_t *timer_ctrl = (volatile uint32_t *)TK1_MMIO_TIMER_CTRL;
|
||||
volatile uint32_t *trng_status = (volatile uint32_t *)TK1_MMIO_TRNG_STATUS;
|
||||
volatile uint32_t *trng_entropy = (volatile uint32_t *)TK1_MMIO_TRNG_ENTROPY;
|
||||
volatile uint32_t *fw_blake2s_addr = (volatile uint32_t *)TK1_MMIO_TK1_BLAKE2S;
|
||||
// clang-format on
|
||||
|
||||
#define UDS_WORDS 8
|
||||
#define UDI_WORDS 2
|
||||
#define CDI_WORDS 8
|
||||
|
||||
void *memcpy(void *dest, const void *src, size_t n)
|
||||
{
|
||||
uint8_t *src_byte = (uint8_t *)src;
|
||||
uint8_t *dest_byte = (uint8_t *)dest;
|
||||
|
||||
for (int i = 0; i < n; i++) {
|
||||
dest_byte[i] = src_byte[i];
|
||||
}
|
||||
|
||||
return dest;
|
||||
}
|
||||
|
||||
void puts(char *reason)
|
||||
{
|
||||
for (char *c = reason; *c != '\0'; c++) {
|
||||
writebyte(*c);
|
||||
}
|
||||
}
|
||||
|
||||
void putsn(char *p, int n)
|
||||
{
|
||||
for (int i = 0; i < n; i++) {
|
||||
writebyte(p[i]);
|
||||
}
|
||||
}
|
||||
|
||||
void puthex(uint8_t c)
|
||||
{
|
||||
unsigned int upper = (c >> 4) & 0xf;
|
||||
unsigned int lower = c & 0xf;
|
||||
writebyte(upper < 10 ? '0' + upper : 'a' - 10 + upper);
|
||||
writebyte(lower < 10 ? '0' + lower : 'a' - 10 + lower);
|
||||
}
|
||||
|
||||
void puthexn(uint8_t *p, int n)
|
||||
{
|
||||
for (int i = 0; i < n; i++) {
|
||||
puthex(p[i]);
|
||||
puthex(IO_CDC, p[i]);
|
||||
}
|
||||
}
|
||||
|
||||
void hexdump(void *buf, int len)
|
||||
{
|
||||
uint8_t *byte_buf = (uint8_t *)buf;
|
||||
|
||||
for (int i = 0; i < len; i++) {
|
||||
puthex(byte_buf[i]);
|
||||
if (i % 2 == 1) {
|
||||
writebyte(' ');
|
||||
}
|
||||
|
||||
if (i != 1 && i % 16 == 1) {
|
||||
puts("\r\n");
|
||||
}
|
||||
}
|
||||
|
||||
puts("\r\n");
|
||||
}
|
||||
|
||||
void reverseword(uint32_t *wordp)
|
||||
{
|
||||
*wordp = ((*wordp & 0xff000000) >> 24) | ((*wordp & 0x00ff0000) >> 8) |
|
||||
@ -124,19 +76,19 @@ int check_fwram_zero_except(unsigned int offset, uint8_t expected_val)
|
||||
if (i == offset) {
|
||||
if (val != expected_val) {
|
||||
failed_now = 1;
|
||||
puts(" wrong value at: ");
|
||||
puts(IO_CDC, " wrong value at: ");
|
||||
}
|
||||
} else {
|
||||
if (val != 0) {
|
||||
failed_now = 1;
|
||||
puts(" not zero at: ");
|
||||
puts(IO_CDC, " not zero at: ");
|
||||
}
|
||||
}
|
||||
if (failed_now) {
|
||||
failed = 1;
|
||||
reverseword(&addr);
|
||||
puthexn((uint8_t *)&addr, 4);
|
||||
puts("\r\n");
|
||||
puts(IO_CDC, "\r\n");
|
||||
}
|
||||
}
|
||||
return failed;
|
||||
@ -144,19 +96,17 @@ int check_fwram_zero_except(unsigned int offset, uint8_t expected_val)
|
||||
|
||||
void failmsg(char *s)
|
||||
{
|
||||
puts("FAIL: ");
|
||||
puts(s);
|
||||
puts("\r\n");
|
||||
puts(IO_CDC, "FAIL: ");
|
||||
puts(IO_CDC, s);
|
||||
puts(IO_CDC, "\r\n");
|
||||
}
|
||||
|
||||
int main(void)
|
||||
{
|
||||
// Function pointer to blake2s()
|
||||
volatile int (*fw_blake2s)(void *, unsigned long, const void *,
|
||||
unsigned long, const void *, unsigned long,
|
||||
blake2s_ctx *);
|
||||
uint8_t in = 0;
|
||||
uint8_t available = 0;
|
||||
enum ioend endpoint = IO_NONE;
|
||||
|
||||
uint8_t in;
|
||||
// Hard coded test UDS in ../../data/uds.hex
|
||||
// clang-format off
|
||||
uint32_t uds_test[8] = {
|
||||
@ -172,19 +122,27 @@ int main(void)
|
||||
// clang-format on
|
||||
|
||||
// Wait for terminal program and a character to be typed
|
||||
in = readbyte();
|
||||
if (readselect(IO_CDC, &endpoint, &available) < 0) {
|
||||
// readselect failed! I/O broken? Just redblink.
|
||||
assert(1 == 2);
|
||||
}
|
||||
|
||||
puts("\r\nI'm testfw on:");
|
||||
if (read(IO_CDC, &in, 1, 1) < 0) {
|
||||
// read failed! I/O broken? Just redblink.
|
||||
assert(1 == 2);
|
||||
}
|
||||
|
||||
puts(IO_CDC, "\r\nI'm testfw on:");
|
||||
// Output the TK1 core's NAME0 and NAME1
|
||||
uint32_t name;
|
||||
wordcpy_s(&name, 1, (void *)tk1name0, 1);
|
||||
reverseword(&name);
|
||||
putsn((char *)&name, 4);
|
||||
puts(" ");
|
||||
write(IO_CDC, (const uint8_t *)&name, 4);
|
||||
puts(IO_CDC, " ");
|
||||
wordcpy_s(&name, 1, (void *)tk1name1, 1);
|
||||
reverseword(&name);
|
||||
putsn((char *)&name, 4);
|
||||
puts("\r\n");
|
||||
write(IO_CDC, (const uint8_t *)&name, 4);
|
||||
puts(IO_CDC, "\r\n");
|
||||
|
||||
uint32_t zeros[8];
|
||||
memset(zeros, 0, 8 * 4);
|
||||
@ -200,11 +158,11 @@ int main(void)
|
||||
anyfailed = 1;
|
||||
}
|
||||
|
||||
puts("\r\nUDS: ");
|
||||
puts(IO_CDC, "\r\nUDS: ");
|
||||
for (int i = 0; i < UDS_WORDS * 4; i++) {
|
||||
puthex(((uint8_t *)uds_local)[i]);
|
||||
puthex(IO_CDC, ((uint8_t *)uds_local)[i]);
|
||||
}
|
||||
puts("\r\n");
|
||||
puts(IO_CDC, "\r\n");
|
||||
if (!memeq(uds_local, uds_test, UDS_WORDS * 4)) {
|
||||
failmsg("UDS not equal to test UDS");
|
||||
anyfailed = 1;
|
||||
@ -247,7 +205,7 @@ int main(void)
|
||||
}
|
||||
|
||||
// Test FW_RAM.
|
||||
puts("\r\nTesting FW_RAM (takes 15s on hw)...\r\n");
|
||||
puts(IO_CDC, "\r\nTesting FW_RAM (takes 50s on hw)...\r\n");
|
||||
for (unsigned int i = 0; i < TK1_MMIO_FW_RAM_SIZE; i++) {
|
||||
zero_fwram();
|
||||
*(volatile uint8_t *)(TK1_MMIO_FW_RAM_BASE + i) = 0x42;
|
||||
@ -257,60 +215,7 @@ int main(void)
|
||||
}
|
||||
}
|
||||
|
||||
uint32_t sw = *system_mode_ctrl;
|
||||
if (sw != 0) {
|
||||
failmsg("system_mode_ctrl is not 0 in fw mode");
|
||||
anyfailed = 1;
|
||||
}
|
||||
|
||||
// Store function pointer to blake2s() so it's reachable from app
|
||||
*fw_blake2s_addr = (uint32_t)blake2s;
|
||||
|
||||
// Turn on application mode.
|
||||
// -------------------------
|
||||
|
||||
*system_mode_ctrl = 1;
|
||||
|
||||
sw = *system_mode_ctrl;
|
||||
if (sw != 0xffffffff) {
|
||||
failmsg("system_mode_ctrl is not 0xffffffff in app mode");
|
||||
anyfailed = 1;
|
||||
}
|
||||
|
||||
// Should NOT be able to read from UDS in app-mode.
|
||||
wordcpy_s(uds_local, UDS_WORDS, (void *)uds, UDS_WORDS);
|
||||
if (!memeq(uds_local, zeros, UDS_WORDS * 4)) {
|
||||
failmsg("Read from UDS in app-mode");
|
||||
anyfailed = 1;
|
||||
}
|
||||
|
||||
// Should NOT be able to read from UDI in app-mode.
|
||||
wordcpy_s(udi_local, UDI_WORDS, (void *)udi, UDI_WORDS);
|
||||
if (!memeq(udi_local, zeros, UDI_WORDS * 4)) {
|
||||
failmsg("Read from UDI in app-mode");
|
||||
anyfailed = 1;
|
||||
}
|
||||
|
||||
uint32_t cdi_local[CDI_WORDS];
|
||||
uint32_t cdi_local2[CDI_WORDS];
|
||||
wordcpy_s(cdi_local, CDI_WORDS, (void *)cdi, CDI_WORDS);
|
||||
|
||||
// Write to CDI should NOT have any effect in app mode.
|
||||
wordcpy_s((void *)cdi, CDI_WORDS, zeros, CDI_WORDS);
|
||||
wordcpy_s(cdi_local2, CDI_WORDS, (void *)cdi, CDI_WORDS);
|
||||
if (!memeq(cdi_local, cdi_local2, CDI_WORDS * 4)) {
|
||||
failmsg("Write to CDI in app-mode");
|
||||
anyfailed = 1;
|
||||
}
|
||||
|
||||
// Test FW_RAM.
|
||||
*fw_ram = 0x21;
|
||||
if (*fw_ram == 0x21) {
|
||||
failmsg("Write and read FW RAM in app-mode");
|
||||
anyfailed = 1;
|
||||
}
|
||||
|
||||
puts("\r\nTesting timer... 3");
|
||||
puts(IO_CDC, "\r\nTesting timer... 3");
|
||||
// Matching clock at 24 MHz, giving us timer in seconds
|
||||
*timer_prescaler = 24 * 1000000;
|
||||
|
||||
@ -321,7 +226,7 @@ int main(void)
|
||||
while (*timer_status & (1 << TK1_MMIO_TIMER_STATUS_RUNNING_BIT)) {
|
||||
}
|
||||
// Now timer has expired and is ready to run again
|
||||
puts(" 2");
|
||||
puts(IO_CDC, " 2");
|
||||
|
||||
// Test to interrupt a timer - and reads from timer register
|
||||
// Starting 10s timer and interrupting it in 3s...
|
||||
@ -334,7 +239,7 @@ int main(void)
|
||||
|
||||
// Stop the timer
|
||||
*timer_ctrl = (1 << TK1_MMIO_TIMER_CTRL_STOP_BIT);
|
||||
puts(" 1. done.\r\n");
|
||||
puts(IO_CDC, " 1. done.\r\n");
|
||||
|
||||
if (*timer_status & (1 << TK1_MMIO_TIMER_STATUS_RUNNING_BIT)) {
|
||||
failmsg("Timer didn't stop");
|
||||
@ -346,41 +251,16 @@ int main(void)
|
||||
anyfailed = 1;
|
||||
}
|
||||
|
||||
// Testing the blake2s MMIO in app mode
|
||||
|
||||
fw_blake2s = (volatile int (*)(void *, unsigned long, const void *,
|
||||
unsigned long, const void *,
|
||||
unsigned long, blake2s_ctx *)) *
|
||||
fw_blake2s_addr;
|
||||
|
||||
char msg[17] = "dldlkjsdkljdslsdj";
|
||||
uint32_t digest0[8];
|
||||
uint32_t digest1[8];
|
||||
blake2s_ctx b2s_ctx;
|
||||
|
||||
blake2s(&digest0[0], 32, NULL, 0, &msg, 17, &b2s_ctx);
|
||||
fw_blake2s(&digest1[0], 32, NULL, 0, &msg, 17, &b2s_ctx);
|
||||
|
||||
puts("\r\ndigest #0: \r\n");
|
||||
hexdump((uint8_t *)digest0, 32);
|
||||
|
||||
puts("digest #1: \r\n");
|
||||
hexdump((uint8_t *)digest1, 32);
|
||||
|
||||
if (!memeq(digest0, digest1, 32)) {
|
||||
failmsg("Digests not the same");
|
||||
anyfailed = 1;
|
||||
}
|
||||
|
||||
// Check and display test results.
|
||||
puts("\r\n--> ");
|
||||
puts(IO_CDC, "\r\n--> ");
|
||||
if (anyfailed) {
|
||||
puts("Some test FAILED!\r\n");
|
||||
puts(IO_CDC, "Some test FAILED!\r\n");
|
||||
} else {
|
||||
puts("All tests passed.\r\n");
|
||||
puts(IO_CDC, "All tests passed.\r\n");
|
||||
}
|
||||
|
||||
puts("\r\nHere are 256 bytes from the TRNG:\r\n");
|
||||
puts(IO_CDC, "\r\nHere are 256 bytes from the TRNG:\r\n");
|
||||
|
||||
for (int j = 0; j < 8; j++) {
|
||||
for (int i = 0; i < 8; i++) {
|
||||
while ((*trng_status &
|
||||
@ -388,15 +268,28 @@ int main(void)
|
||||
}
|
||||
uint32_t rnd = *trng_entropy;
|
||||
puthexn((uint8_t *)&rnd, 4);
|
||||
puts(" ");
|
||||
puts(IO_CDC, " ");
|
||||
}
|
||||
puts("\r\n");
|
||||
puts(IO_CDC, "\r\n");
|
||||
}
|
||||
puts("\r\n");
|
||||
puts(IO_CDC, "\r\n");
|
||||
|
||||
puts("Now echoing what you type...\r\n");
|
||||
puts(IO_CDC, "Now echoing what you type...Type + to reset device\r\n");
|
||||
for (;;) {
|
||||
in = readbyte(); // blocks
|
||||
writebyte(in);
|
||||
if (readselect(IO_CDC, &endpoint, &available) < 0) {
|
||||
// readselect failed! I/O broken? Just redblink.
|
||||
assert(1 == 2);
|
||||
}
|
||||
|
||||
if (read(IO_CDC, &in, 1, 1) < 0) {
|
||||
// read failed! I/O broken? Just redblink.
|
||||
assert(1 == 2);
|
||||
}
|
||||
|
||||
if (in == '+') {
|
||||
*system_reset = 1;
|
||||
}
|
||||
|
||||
write(IO_CDC, &in, 1);
|
||||
}
|
||||
}
|
||||
|
@ -1,5 +1,6 @@
|
||||
# Uses ../.clang-format
|
||||
FMTFILES=main.c lib.h lib.c proto.h proto.c types.h assert.c assert.h led.c led.h
|
||||
FMTFILES=*.[ch]
|
||||
|
||||
.PHONY: fmt
|
||||
fmt:
|
||||
clang-format --dry-run --ferror-limit=0 $(FMTFILES)
|
||||
|
@ -1,29 +0,0 @@
|
||||
/*
|
||||
* Copyright (C) 2022, 2023 - Tillitis AB
|
||||
* SPDX-License-Identifier: GPL-2.0-only
|
||||
*/
|
||||
|
||||
#include "assert.h"
|
||||
#include "lib.h"
|
||||
|
||||
void assert_fail(const char *assertion, const char *file, unsigned int line,
|
||||
const char *function)
|
||||
{
|
||||
htif_puts("assert: ");
|
||||
htif_puts(assertion);
|
||||
htif_puts(" ");
|
||||
htif_puts(file);
|
||||
htif_puts(":");
|
||||
htif_putinthex(line);
|
||||
htif_puts(" ");
|
||||
htif_puts(function);
|
||||
htif_lf();
|
||||
|
||||
#ifndef S_SPLINT_S
|
||||
// Force illegal instruction to halt CPU
|
||||
asm volatile("unimp");
|
||||
#endif
|
||||
|
||||
// Not reached
|
||||
__builtin_unreachable();
|
||||
}
|
@ -1,15 +0,0 @@
|
||||
/*
|
||||
* Copyright (C) 2022, 2023 - Tillitis AB
|
||||
* SPDX-License-Identifier: GPL-2.0-only
|
||||
*/
|
||||
|
||||
#ifndef ASSERT_H
|
||||
#define ASSERT_H
|
||||
|
||||
#define assert(expr) \
|
||||
((expr) ? (void)(0) : assert_fail(#expr, __FILE__, __LINE__, __func__))
|
||||
|
||||
void assert_fail(const char *assertion, const char *file, unsigned int line,
|
||||
const char *function);
|
||||
|
||||
#endif
|
@ -6,8 +6,8 @@
|
||||
// A simple blake2s Reference Implementation.
|
||||
//======================================================================
|
||||
|
||||
#include "../types.h"
|
||||
#include "../lib.h"
|
||||
#include <stdint.h>
|
||||
|
||||
#include "blake2s.h"
|
||||
|
||||
// Dummy printf() for verbose mode
|
||||
|
@ -4,7 +4,8 @@
|
||||
#ifndef BLAKE2S_H
|
||||
#define BLAKE2S_H
|
||||
|
||||
#include "../types.h"
|
||||
#include <stdint.h>
|
||||
#include <stddef.h>
|
||||
|
||||
// state context
|
||||
typedef struct {
|
||||
|
@ -6,9 +6,14 @@
|
||||
OUTPUT_ARCH("riscv")
|
||||
ENTRY(_start)
|
||||
|
||||
/* Define stack size */
|
||||
STACK_SIZE = 0xEF0; /* 3824 B */
|
||||
|
||||
MEMORY
|
||||
{
|
||||
ROM (rx) : ORIGIN = 0x00000000, LENGTH = 0x20000 /* 128 KB */
|
||||
ROM (rx) : ORIGIN = 0x00000000, LENGTH = 0x2000 /* 8 KB */
|
||||
FWRAM (rw) : ORIGIN = 0xd0000000, LENGTH = 0xF00 /* 3840 B */
|
||||
RESETINFO (rw) : ORIGIN = 0xd0000F00, LENGTH = 0x100 /* 256 B (part of FW_RAM area) */
|
||||
RAM (rwx) : ORIGIN = 0x40000000, LENGTH = 0x20000 /* 128 KB */
|
||||
}
|
||||
|
||||
@ -28,31 +33,38 @@ SECTIONS
|
||||
.text :
|
||||
{
|
||||
. = ALIGN(4);
|
||||
_stext = .;
|
||||
*(.text) /* .text sections (code) */
|
||||
*(.text*) /* .text* sections (code) */
|
||||
*(.rodata) /* .rodata sections (constants, strings, etc.) */
|
||||
*(.rodata*) /* .rodata* sections (constants, strings, etc.) */
|
||||
*(.srodata) /* .rodata sections (constants, strings, etc.) */
|
||||
*(.srodata*) /* .rodata* sections (constants, strings, etc.) */
|
||||
*(.srodata) /* .srodata sections (constants, strings, etc.) */
|
||||
*(.srodata*) /* .srodata* sections (constants, strings, etc.) */
|
||||
. = ALIGN(4);
|
||||
_etext = .;
|
||||
_sidata = _etext;
|
||||
} >ROM
|
||||
|
||||
/* XXX We don't allow any data or BSS - but they need be defined or linking will fail */
|
||||
.stack (NOLOAD) :
|
||||
{
|
||||
. = ALIGN(16);
|
||||
_sstack = .;
|
||||
. += STACK_SIZE;
|
||||
. = ALIGN(16);
|
||||
_estack = .;
|
||||
} >FWRAM
|
||||
|
||||
.data : AT (_etext)
|
||||
.data :
|
||||
{
|
||||
. = ALIGN(4);
|
||||
_sdata = .;
|
||||
. = ALIGN(4);
|
||||
*(.data) /* .data sections */
|
||||
*(.data*) /* .data* sections */
|
||||
*(.sdata) /* .sdata sections */
|
||||
*(.sdata*) /* .sdata* sections */
|
||||
. = ALIGN(4);
|
||||
_edata = .;
|
||||
} >ROM
|
||||
} >FWRAM AT>ROM
|
||||
_sidata = LOADADDR(.data);
|
||||
|
||||
/* Uninitialized data section */
|
||||
.bss :
|
||||
@ -64,8 +76,12 @@ SECTIONS
|
||||
*(.sbss)
|
||||
*(.sbss*)
|
||||
*(COMMON)
|
||||
|
||||
. = ALIGN(4);
|
||||
_ebss = .;
|
||||
} >ROM
|
||||
} >FWRAM
|
||||
}
|
||||
|
||||
_sfwram = ORIGIN(FWRAM);
|
||||
_efwram = ORIGIN(FWRAM) + LENGTH(FWRAM);
|
||||
_sresetinfo = ORIGIN(RESETINFO);
|
||||
_eresetinfo = ORIGIN(RESETINFO) + LENGTH(RESETINFO);
|
||||
|
@ -1,15 +0,0 @@
|
||||
/*
|
||||
* Copyright (C) 2022, 2023 - Tillitis AB
|
||||
* SPDX-License-Identifier: GPL-2.0-only
|
||||
*/
|
||||
|
||||
#include "led.h"
|
||||
#include "../tk1_mem.h"
|
||||
#include "types.h"
|
||||
|
||||
static volatile uint32_t *led = (volatile uint32_t *)TK1_MMIO_TK1_LED;
|
||||
|
||||
void set_led(uint32_t led_value)
|
||||
{
|
||||
*led = led_value;
|
||||
}
|
@ -1,21 +0,0 @@
|
||||
/*
|
||||
* Copyright (C) 2022, 2023 - Tillitis AB
|
||||
* SPDX-License-Identifier: GPL-2.0-only
|
||||
*/
|
||||
|
||||
#ifndef LED_H
|
||||
#define LED_H
|
||||
|
||||
#include "../tk1_mem.h"
|
||||
#include "types.h"
|
||||
|
||||
// clang-format off
|
||||
#define LED_BLACK 0
|
||||
#define LED_RED (1 << TK1_MMIO_TK1_LED_R_BIT)
|
||||
#define LED_GREEN (1 << TK1_MMIO_TK1_LED_G_BIT)
|
||||
#define LED_BLUE (1 << TK1_MMIO_TK1_LED_B_BIT)
|
||||
#define LED_WHITE (LED_RED | LED_GREEN | LED_BLUE)
|
||||
// clang-format on
|
||||
|
||||
void set_led(uint32_t led_value);
|
||||
#endif
|
@ -1,164 +0,0 @@
|
||||
/*
|
||||
* Copyright (C) 2022-2024 - Tillitis AB
|
||||
* SPDX-License-Identifier: GPL-2.0-only
|
||||
*/
|
||||
|
||||
#include "lib.h"
|
||||
#include "assert.h"
|
||||
#include "types.h"
|
||||
|
||||
#ifdef QEMU_CONSOLE
|
||||
struct {
|
||||
uint32_t arr[2];
|
||||
} static volatile tohost __attribute__((section(".htif")));
|
||||
struct {
|
||||
uint32_t arr[2];
|
||||
} /*@unused@*/ static volatile fromhost __attribute__((section(".htif")));
|
||||
|
||||
static void htif_send(uint8_t dev, uint8_t cmd, int64_t data)
|
||||
{
|
||||
/* endian neutral encoding with ordered 32-bit writes */
|
||||
union {
|
||||
uint32_t arr[2];
|
||||
uint64_t val;
|
||||
} encode = {.val = (uint64_t)dev << 56 | (uint64_t)cmd << 48 | data};
|
||||
tohost.arr[0] = encode.arr[0];
|
||||
tohost.arr[1] = encode.arr[1];
|
||||
}
|
||||
|
||||
static void htif_set_tohost(uint8_t dev, uint8_t cmd, int64_t data)
|
||||
{
|
||||
/* send data with specified device and command */
|
||||
while (tohost.arr[0]) {
|
||||
#ifndef S_SPLINT_S
|
||||
asm volatile("" : : "r"(fromhost.arr[0]));
|
||||
asm volatile("" : : "r"(fromhost.arr[1]));
|
||||
#endif
|
||||
}
|
||||
htif_send(dev, cmd, data);
|
||||
}
|
||||
|
||||
static void htif_putchar(char ch)
|
||||
{
|
||||
htif_set_tohost((uint8_t)1, (uint8_t)1, (int64_t)ch & 0xff);
|
||||
}
|
||||
|
||||
void htif_puts(const char *s)
|
||||
{
|
||||
while (*s != '\0')
|
||||
htif_putchar(*s++);
|
||||
}
|
||||
|
||||
void htif_hexdump(void *buf, int len)
|
||||
{
|
||||
uint8_t *byte_buf = (uint8_t *)buf;
|
||||
|
||||
for (int i = 0; i < len; i++) {
|
||||
htif_puthex(byte_buf[i]);
|
||||
if (i % 2 == 1) {
|
||||
(void)htif_putchar(' ');
|
||||
}
|
||||
|
||||
if (i != 1 && i % 16 == 1) {
|
||||
htif_lf();
|
||||
}
|
||||
}
|
||||
|
||||
htif_lf();
|
||||
}
|
||||
|
||||
void htif_putc(char ch)
|
||||
{
|
||||
htif_putchar(ch);
|
||||
}
|
||||
|
||||
void htif_lf(void)
|
||||
{
|
||||
htif_putchar('\n');
|
||||
}
|
||||
|
||||
void htif_puthex(uint8_t c)
|
||||
{
|
||||
unsigned int upper = (c >> 4) & 0xf;
|
||||
unsigned int lower = c & 0xf;
|
||||
|
||||
htif_putchar(upper < 10 ? '0' + upper : 'a' - 10 + upper);
|
||||
htif_putchar(lower < 10 ? '0' + lower : 'a' - 10 + lower);
|
||||
}
|
||||
|
||||
void htif_putinthex(const uint32_t n)
|
||||
{
|
||||
uint8_t *buf = (uint8_t *)&n;
|
||||
|
||||
htif_puts("0x");
|
||||
for (int i = 3; i > -1; i--) {
|
||||
htif_puthex(buf[i]);
|
||||
}
|
||||
}
|
||||
#endif
|
||||
|
||||
void *memset(void *dest, int c, unsigned n)
|
||||
{
|
||||
uint8_t *s = dest;
|
||||
|
||||
for (; n; n--, s++)
|
||||
*s = (uint8_t)c;
|
||||
|
||||
/*@ -temptrans @*/
|
||||
return dest;
|
||||
}
|
||||
|
||||
void memcpy_s(void *dest, size_t destsize, const void *src, size_t n)
|
||||
{
|
||||
assert(dest != NULL);
|
||||
assert(src != NULL);
|
||||
assert(destsize >= n);
|
||||
|
||||
uint8_t *src_byte = (uint8_t *)src;
|
||||
uint8_t *dest_byte = (uint8_t *)dest;
|
||||
|
||||
for (size_t i = 0; i < n; i++) {
|
||||
/*@ -nullderef @*/
|
||||
/* splint complains that dest_byte and src_byte can be
|
||||
* NULL, but it seems it doesn't understand assert.
|
||||
* See above.
|
||||
*/
|
||||
dest_byte[i] = src_byte[i];
|
||||
}
|
||||
}
|
||||
|
||||
void wordcpy_s(void *dest, size_t destsize, const void *src, size_t n)
|
||||
{
|
||||
assert(dest != NULL);
|
||||
assert(src != NULL);
|
||||
assert(destsize >= n);
|
||||
|
||||
uint32_t *src_word = (uint32_t *)src;
|
||||
uint32_t *dest_word = (uint32_t *)dest;
|
||||
|
||||
for (size_t i = 0; i < n; i++) {
|
||||
dest_word[i] = src_word[i];
|
||||
}
|
||||
}
|
||||
|
||||
int memeq(void *dest, const void *src, size_t n)
|
||||
{
|
||||
uint8_t *src_byte = (uint8_t *)src;
|
||||
uint8_t *dest_byte = (uint8_t *)dest;
|
||||
int res = -1;
|
||||
|
||||
for (size_t i = 0; i < n; i++) {
|
||||
if (dest_byte[i] != src_byte[i]) {
|
||||
res = 0;
|
||||
}
|
||||
}
|
||||
|
||||
return res;
|
||||
}
|
||||
|
||||
void secure_wipe(void *v, size_t n)
|
||||
{
|
||||
volatile uint8_t *p = (volatile uint8_t *)v;
|
||||
while (n--)
|
||||
*p++ = 0;
|
||||
}
|
@ -1,32 +0,0 @@
|
||||
/*
|
||||
* Copyright (C) 2022-2024 - Tillitis AB
|
||||
* SPDX-License-Identifier: GPL-2.0-only
|
||||
*/
|
||||
|
||||
#ifndef LIB_H
|
||||
#define LIB_H
|
||||
|
||||
#include "types.h"
|
||||
|
||||
#ifdef QEMU_CONSOLE
|
||||
void htif_putc(char ch);
|
||||
void htif_lf(void);
|
||||
void htif_puthex(uint8_t c);
|
||||
void htif_putinthex(const uint32_t n);
|
||||
void htif_puts(const char *s);
|
||||
void htif_hexdump(void *buf, int len);
|
||||
#else
|
||||
#define htif_putc(ch)
|
||||
#define htif_lf(void)
|
||||
#define htif_puthex(c)
|
||||
#define htif_putinthex(n)
|
||||
#define htif_puts(s)
|
||||
#define htif_hexdump(buf, len)
|
||||
#endif /* QEMU_CONSOLE */
|
||||
|
||||
void *memset(void *dest, int c, unsigned n);
|
||||
void memcpy_s(void *dest, size_t destsize, const void *src, size_t n);
|
||||
void wordcpy_s(void *dest, size_t destsize, const void *src, size_t n);
|
||||
int memeq(void *dest, const void *src, size_t n);
|
||||
void secure_wipe(void *v, size_t n);
|
||||
#endif
|
@ -3,17 +3,21 @@
|
||||
* SPDX-License-Identifier: GPL-2.0-only
|
||||
*/
|
||||
|
||||
#include "../tk1_mem.h"
|
||||
#include "assert.h"
|
||||
#include <stdbool.h>
|
||||
#include <stddef.h>
|
||||
#include <stdint.h>
|
||||
#include <tkey/assert.h>
|
||||
#include <tkey/debug.h>
|
||||
#include <tkey/lib.h>
|
||||
#include <tkey/tk1_mem.h>
|
||||
|
||||
#include "blake2s/blake2s.h"
|
||||
#include "lib.h"
|
||||
#include "proto.h"
|
||||
#include "state.h"
|
||||
#include "types.h"
|
||||
#include "syscall_enable.h"
|
||||
|
||||
// clang-format off
|
||||
static volatile uint32_t *uds = (volatile uint32_t *)TK1_MMIO_UDS_FIRST;
|
||||
static volatile uint32_t *system_mode_ctrl = (volatile uint32_t *)TK1_MMIO_TK1_SYSTEM_MODE_CTRL;
|
||||
static volatile uint32_t *name0 = (volatile uint32_t *)TK1_MMIO_TK1_NAME0;
|
||||
static volatile uint32_t *name1 = (volatile uint32_t *)TK1_MMIO_TK1_NAME1;
|
||||
static volatile uint32_t *ver = (volatile uint32_t *)TK1_MMIO_TK1_VERSION;
|
||||
@ -21,7 +25,6 @@ static volatile uint32_t *udi = (volatile uint32_t *)TK1_MMIO_TK1_U
|
||||
static volatile uint32_t *cdi = (volatile uint32_t *)TK1_MMIO_TK1_CDI_FIRST;
|
||||
static volatile uint32_t *app_addr = (volatile uint32_t *)TK1_MMIO_TK1_APP_ADDR;
|
||||
static volatile uint32_t *app_size = (volatile uint32_t *)TK1_MMIO_TK1_APP_SIZE;
|
||||
static volatile uint32_t *fw_blake2s_addr = (volatile uint32_t *)TK1_MMIO_TK1_BLAKE2S;
|
||||
static volatile uint32_t *trng_status = (volatile uint32_t *)TK1_MMIO_TRNG_STATUS;
|
||||
static volatile uint32_t *trng_entropy = (volatile uint32_t *)TK1_MMIO_TRNG_ENTROPY;
|
||||
static volatile uint32_t *timer = (volatile uint32_t *)TK1_MMIO_TIMER_TIMER;
|
||||
@ -37,7 +40,7 @@ struct context {
|
||||
uint32_t left; // Bytes left to receive
|
||||
uint8_t digest[32]; // Program digest
|
||||
uint8_t *loadaddr; // Where we are currently loading a TKey program
|
||||
uint8_t use_uss; // Use USS?
|
||||
bool use_uss; // Use USS?
|
||||
uint8_t uss[32]; // User Supplied Secret, if any
|
||||
};
|
||||
|
||||
@ -61,26 +64,26 @@ static void scramble_ram(void);
|
||||
|
||||
static void print_hw_version(void)
|
||||
{
|
||||
htif_puts("Hello, I'm firmware with");
|
||||
htif_puts(" tk1_name0:");
|
||||
htif_putinthex(*name0);
|
||||
htif_puts(" tk1_name1:");
|
||||
htif_putinthex(*name1);
|
||||
htif_puts(" tk1_version:");
|
||||
htif_putinthex(*ver);
|
||||
htif_lf();
|
||||
debug_puts("Hello, I'm firmware with");
|
||||
debug_puts(" tk1_name0:");
|
||||
debug_putinthex(*name0);
|
||||
debug_puts(" tk1_name1:");
|
||||
debug_putinthex(*name1);
|
||||
debug_puts(" tk1_version:");
|
||||
debug_putinthex(*ver);
|
||||
debug_lf();
|
||||
}
|
||||
|
||||
static void print_digest(uint8_t *md)
|
||||
{
|
||||
htif_puts("The app digest:\n");
|
||||
debug_puts("The app digest:\n");
|
||||
for (int j = 0; j < 4; j++) {
|
||||
for (int i = 0; i < 8; i++) {
|
||||
htif_puthex(md[i + 8 * j]);
|
||||
debug_puthex(md[i + 8 * j]);
|
||||
}
|
||||
htif_lf();
|
||||
debug_lf();
|
||||
}
|
||||
htif_lf();
|
||||
debug_lf();
|
||||
}
|
||||
|
||||
static uint32_t rnd_word(void)
|
||||
@ -152,20 +155,20 @@ static enum state initial_commands(const struct frame_header *hdr,
|
||||
const uint8_t *cmd, enum state state,
|
||||
struct context *ctx)
|
||||
{
|
||||
uint8_t rsp[CMDLEN_MAXBYTES] = {0};
|
||||
uint8_t rsp[CMDSIZE] = {0};
|
||||
|
||||
switch (cmd[0]) {
|
||||
case FW_CMD_NAME_VERSION:
|
||||
htif_puts("cmd: name-version\n");
|
||||
debug_puts("cmd: name-version\n");
|
||||
if (hdr->len != 1) {
|
||||
// Bad length
|
||||
state = FW_STATE_FAIL;
|
||||
break;
|
||||
}
|
||||
|
||||
copy_name(rsp, CMDLEN_MAXBYTES, *name0);
|
||||
copy_name(&rsp[4], CMDLEN_MAXBYTES - 4, *name1);
|
||||
wordcpy_s(&rsp[8], CMDLEN_MAXBYTES / 4 - 2, (void *)ver, 1);
|
||||
copy_name(rsp, CMDSIZE, *name0);
|
||||
copy_name(&rsp[4], CMDSIZE - 4, *name1);
|
||||
wordcpy_s(&rsp[8], CMDSIZE - 8, (void *)ver, 1);
|
||||
|
||||
fwreply(*hdr, FW_RSP_NAME_VERSION, rsp);
|
||||
// still initial state
|
||||
@ -174,7 +177,7 @@ static enum state initial_commands(const struct frame_header *hdr,
|
||||
case FW_CMD_GET_UDI: {
|
||||
uint32_t udi_words[2];
|
||||
|
||||
htif_puts("cmd: get-udi\n");
|
||||
debug_puts("cmd: get-udi\n");
|
||||
if (hdr->len != 1) {
|
||||
// Bad length
|
||||
state = FW_STATE_FAIL;
|
||||
@ -183,7 +186,7 @@ static enum state initial_commands(const struct frame_header *hdr,
|
||||
|
||||
rsp[0] = STATUS_OK;
|
||||
wordcpy_s(&udi_words, 2, (void *)udi, 2);
|
||||
memcpy_s(&rsp[1], CMDLEN_MAXBYTES - 1, &udi_words, 2 * 4);
|
||||
memcpy_s(&rsp[1], CMDSIZE - 1, &udi_words, 2 * 4);
|
||||
fwreply(*hdr, FW_RSP_GET_UDI, rsp);
|
||||
// still initial state
|
||||
break;
|
||||
@ -192,7 +195,7 @@ static enum state initial_commands(const struct frame_header *hdr,
|
||||
case FW_CMD_LOAD_APP: {
|
||||
uint32_t local_app_size;
|
||||
|
||||
htif_puts("cmd: load-app(size, uss)\n");
|
||||
debug_puts("cmd: load-app(size, uss)\n");
|
||||
if (hdr->len != 128) {
|
||||
// Bad length
|
||||
state = FW_STATE_FAIL;
|
||||
@ -203,9 +206,9 @@ static enum state initial_commands(const struct frame_header *hdr,
|
||||
local_app_size =
|
||||
cmd[1] + (cmd[2] << 8) + (cmd[3] << 16) + (cmd[4] << 24);
|
||||
|
||||
htif_puts("app size: ");
|
||||
htif_putinthex(local_app_size);
|
||||
htif_lf();
|
||||
debug_puts("app size: ");
|
||||
debug_putinthex(local_app_size);
|
||||
debug_lf();
|
||||
|
||||
if (local_app_size == 0 || local_app_size > TK1_APP_MAX_SIZE) {
|
||||
rsp[0] = STATUS_BAD;
|
||||
@ -219,10 +222,10 @@ static enum state initial_commands(const struct frame_header *hdr,
|
||||
// Do we have a USS at all?
|
||||
if (cmd[5] != 0) {
|
||||
// Yes
|
||||
ctx->use_uss = TRUE;
|
||||
ctx->use_uss = true;
|
||||
memcpy_s(ctx->uss, 32, &cmd[6], 32);
|
||||
} else {
|
||||
ctx->use_uss = FALSE;
|
||||
ctx->use_uss = false;
|
||||
}
|
||||
|
||||
rsp[0] = STATUS_OK;
|
||||
@ -238,9 +241,9 @@ static enum state initial_commands(const struct frame_header *hdr,
|
||||
}
|
||||
|
||||
default:
|
||||
htif_puts("Got unknown firmware cmd: 0x");
|
||||
htif_puthex(cmd[0]);
|
||||
htif_lf();
|
||||
debug_puts("Got unknown firmware cmd: 0x");
|
||||
debug_puthex(cmd[0]);
|
||||
debug_lf();
|
||||
state = FW_STATE_FAIL;
|
||||
break;
|
||||
}
|
||||
@ -252,12 +255,12 @@ static enum state loading_commands(const struct frame_header *hdr,
|
||||
const uint8_t *cmd, enum state state,
|
||||
struct context *ctx)
|
||||
{
|
||||
uint8_t rsp[CMDLEN_MAXBYTES] = {0};
|
||||
uint8_t rsp[CMDSIZE] = {0};
|
||||
uint32_t nbytes = 0;
|
||||
|
||||
switch (cmd[0]) {
|
||||
case FW_CMD_LOAD_APP_DATA:
|
||||
htif_puts("cmd: load-app-data\n");
|
||||
debug_puts("cmd: load-app-data\n");
|
||||
if (hdr->len != 128) {
|
||||
// Bad length
|
||||
state = FW_STATE_FAIL;
|
||||
@ -279,9 +282,9 @@ static enum state loading_commands(const struct frame_header *hdr,
|
||||
blake2s_ctx b2s_ctx = {0};
|
||||
int blake2err = 0;
|
||||
|
||||
htif_puts("Fully loaded ");
|
||||
htif_putinthex(*app_size);
|
||||
htif_lf();
|
||||
debug_puts("Fully loaded ");
|
||||
debug_putinthex(*app_size);
|
||||
debug_lf();
|
||||
|
||||
// Compute Blake2S digest of the app,
|
||||
// storing it for FW_STATE_RUN
|
||||
@ -294,8 +297,7 @@ static enum state loading_commands(const struct frame_header *hdr,
|
||||
// And return the digest in final
|
||||
// response
|
||||
rsp[0] = STATUS_OK;
|
||||
memcpy_s(&rsp[1], CMDLEN_MAXBYTES - 1, &ctx->digest,
|
||||
32);
|
||||
memcpy_s(&rsp[1], CMDSIZE - 1, &ctx->digest, 32);
|
||||
fwreply(*hdr, FW_RSP_LOAD_APP_DATA_READY, rsp);
|
||||
|
||||
state = FW_STATE_RUN;
|
||||
@ -308,9 +310,9 @@ static enum state loading_commands(const struct frame_header *hdr,
|
||||
break;
|
||||
|
||||
default:
|
||||
htif_puts("Got unknown firmware cmd: 0x");
|
||||
htif_puthex(cmd[0]);
|
||||
htif_lf();
|
||||
debug_puts("Got unknown firmware cmd: 0x");
|
||||
debug_puthex(cmd[0]);
|
||||
debug_lf();
|
||||
state = FW_STATE_FAIL;
|
||||
break;
|
||||
}
|
||||
@ -325,17 +327,17 @@ static void run(const struct context *ctx)
|
||||
// CDI = hash(uds, hash(app), uss)
|
||||
compute_cdi(ctx->digest, ctx->use_uss, ctx->uss);
|
||||
|
||||
htif_puts("Flipping to app mode!\n");
|
||||
htif_puts("Jumping to ");
|
||||
htif_putinthex(*app_addr);
|
||||
htif_lf();
|
||||
debug_puts("Flipping to app mode!\n");
|
||||
debug_puts("Jumping to ");
|
||||
debug_putinthex(*app_addr);
|
||||
debug_lf();
|
||||
|
||||
// Clear the firmware stack
|
||||
// clang-format off
|
||||
#ifndef S_SPLINT_S
|
||||
asm volatile(
|
||||
"li a0, 0xd0000000;" // FW_RAM
|
||||
"li a1, 0xd0000800;" // End of 2 KB FW_RAM (just past the end)
|
||||
"la a0, _sstack;"
|
||||
"la a1, _estack;"
|
||||
"loop:;"
|
||||
"sw zero, 0(a0);"
|
||||
"addi a0, a0, 4;"
|
||||
@ -344,13 +346,10 @@ static void run(const struct context *ctx)
|
||||
#endif
|
||||
// clang-format on
|
||||
|
||||
// Flip over to application mode
|
||||
*system_mode_ctrl = 1;
|
||||
|
||||
// XXX Firmware stack now no longer available
|
||||
// Don't use any function calls!
|
||||
syscall_enable();
|
||||
|
||||
// Jump to app - doesn't return
|
||||
// Hardware is responsible for switching to app mode
|
||||
// clang-format off
|
||||
#ifndef S_SPLINT_S
|
||||
asm volatile(
|
||||
@ -404,24 +403,18 @@ int main(void)
|
||||
{
|
||||
struct context ctx = {0};
|
||||
struct frame_header hdr = {0};
|
||||
uint8_t cmd[CMDLEN_MAXBYTES] = {0};
|
||||
uint8_t cmd[CMDSIZE] = {0};
|
||||
enum state state = FW_STATE_INITIAL;
|
||||
|
||||
print_hw_version();
|
||||
|
||||
// Let the app know the function adddress for blake2s()
|
||||
*fw_blake2s_addr = (uint32_t)blake2s;
|
||||
|
||||
/*@-mustfreeonly@*/
|
||||
/* Yes, splint, this points directly to RAM and we don't care
|
||||
* about freeing anything was pointing to 0x0 before.
|
||||
*/
|
||||
ctx.loadaddr = (uint8_t *)TK1_RAM_BASE;
|
||||
/*@+mustfreeonly@*/
|
||||
ctx.use_uss = FALSE;
|
||||
|
||||
uint8_t mode = 0;
|
||||
uint8_t mode_bytes_left = 0;
|
||||
ctx.use_uss = false;
|
||||
|
||||
scramble_ram();
|
||||
|
||||
@ -432,18 +425,19 @@ int main(void)
|
||||
for (;;) {
|
||||
switch (state) {
|
||||
case FW_STATE_INITIAL:
|
||||
if (readcommand(&hdr, cmd, state, &mode,
|
||||
&mode_bytes_left) == -1) {
|
||||
if (readcommand(&hdr, cmd, state) == -1) {
|
||||
state = FW_STATE_FAIL;
|
||||
break;
|
||||
}
|
||||
|
||||
debug_puts("cmd: \n");
|
||||
debug_hexdump(cmd, hdr.len);
|
||||
|
||||
state = initial_commands(&hdr, cmd, state, &ctx);
|
||||
break;
|
||||
|
||||
case FW_STATE_LOADING:
|
||||
if (readcommand(&hdr, cmd, state, &mode,
|
||||
&mode_bytes_left) == -1) {
|
||||
if (readcommand(&hdr, cmd, state) == -1) {
|
||||
state = FW_STATE_FAIL;
|
||||
break;
|
||||
}
|
||||
@ -458,9 +452,9 @@ int main(void)
|
||||
case FW_STATE_FAIL:
|
||||
// fallthrough
|
||||
default:
|
||||
htif_puts("firmware state 0x");
|
||||
htif_puthex(state);
|
||||
htif_lf();
|
||||
debug_puts("firmware state 0x");
|
||||
debug_puthex(state);
|
||||
debug_lf();
|
||||
assert(1 == 2);
|
||||
break; // Not reached
|
||||
}
|
||||
|
7
hw/application_fpga/fw/tk1/picorv32/README.md
Normal file
7
hw/application_fpga/fw/tk1/picorv32/README.md
Normal file
@ -0,0 +1,7 @@
|
||||
# PicoRV32
|
||||
|
||||
## custom_ops.S
|
||||
|
||||
Custom PicoRV32 instructions are located in `custom_ops.S`.
|
||||
`custom_ops.S` is imported from upstream PicoRV32 commit:
|
||||
YosysHQ/picorv32@70f3c33
|
102
hw/application_fpga/fw/tk1/picorv32/custom_ops.S
Normal file
102
hw/application_fpga/fw/tk1/picorv32/custom_ops.S
Normal file
@ -0,0 +1,102 @@
|
||||
// This is free and unencumbered software released into the public domain.
|
||||
//
|
||||
// Anyone is free to copy, modify, publish, use, compile, sell, or
|
||||
// distribute this software, either in source code form or as a compiled
|
||||
// binary, for any purpose, commercial or non-commercial, and by any
|
||||
// means.
|
||||
|
||||
#define regnum_q0 0
|
||||
#define regnum_q1 1
|
||||
#define regnum_q2 2
|
||||
#define regnum_q3 3
|
||||
|
||||
#define regnum_x0 0
|
||||
#define regnum_x1 1
|
||||
#define regnum_x2 2
|
||||
#define regnum_x3 3
|
||||
#define regnum_x4 4
|
||||
#define regnum_x5 5
|
||||
#define regnum_x6 6
|
||||
#define regnum_x7 7
|
||||
#define regnum_x8 8
|
||||
#define regnum_x9 9
|
||||
#define regnum_x10 10
|
||||
#define regnum_x11 11
|
||||
#define regnum_x12 12
|
||||
#define regnum_x13 13
|
||||
#define regnum_x14 14
|
||||
#define regnum_x15 15
|
||||
#define regnum_x16 16
|
||||
#define regnum_x17 17
|
||||
#define regnum_x18 18
|
||||
#define regnum_x19 19
|
||||
#define regnum_x20 20
|
||||
#define regnum_x21 21
|
||||
#define regnum_x22 22
|
||||
#define regnum_x23 23
|
||||
#define regnum_x24 24
|
||||
#define regnum_x25 25
|
||||
#define regnum_x26 26
|
||||
#define regnum_x27 27
|
||||
#define regnum_x28 28
|
||||
#define regnum_x29 29
|
||||
#define regnum_x30 30
|
||||
#define regnum_x31 31
|
||||
|
||||
#define regnum_zero 0
|
||||
#define regnum_ra 1
|
||||
#define regnum_sp 2
|
||||
#define regnum_gp 3
|
||||
#define regnum_tp 4
|
||||
#define regnum_t0 5
|
||||
#define regnum_t1 6
|
||||
#define regnum_t2 7
|
||||
#define regnum_s0 8
|
||||
#define regnum_s1 9
|
||||
#define regnum_a0 10
|
||||
#define regnum_a1 11
|
||||
#define regnum_a2 12
|
||||
#define regnum_a3 13
|
||||
#define regnum_a4 14
|
||||
#define regnum_a5 15
|
||||
#define regnum_a6 16
|
||||
#define regnum_a7 17
|
||||
#define regnum_s2 18
|
||||
#define regnum_s3 19
|
||||
#define regnum_s4 20
|
||||
#define regnum_s5 21
|
||||
#define regnum_s6 22
|
||||
#define regnum_s7 23
|
||||
#define regnum_s8 24
|
||||
#define regnum_s9 25
|
||||
#define regnum_s10 26
|
||||
#define regnum_s11 27
|
||||
#define regnum_t3 28
|
||||
#define regnum_t4 29
|
||||
#define regnum_t5 30
|
||||
#define regnum_t6 31
|
||||
|
||||
// x8 is s0 and also fp
|
||||
#define regnum_fp 8
|
||||
|
||||
#define r_type_insn(_f7, _rs2, _rs1, _f3, _rd, _opc) \
|
||||
.word (((_f7) << 25) | ((_rs2) << 20) | ((_rs1) << 15) | ((_f3) << 12) | ((_rd) << 7) | ((_opc) << 0))
|
||||
|
||||
#define picorv32_getq_insn(_rd, _qs) \
|
||||
r_type_insn(0b0000000, 0, regnum_ ## _qs, 0b100, regnum_ ## _rd, 0b0001011)
|
||||
|
||||
#define picorv32_setq_insn(_qd, _rs) \
|
||||
r_type_insn(0b0000001, 0, regnum_ ## _rs, 0b010, regnum_ ## _qd, 0b0001011)
|
||||
|
||||
#define picorv32_retirq_insn() \
|
||||
r_type_insn(0b0000010, 0, 0, 0b000, 0, 0b0001011)
|
||||
|
||||
#define picorv32_maskirq_insn(_rd, _rs) \
|
||||
r_type_insn(0b0000011, 0, regnum_ ## _rs, 0b110, regnum_ ## _rd, 0b0001011)
|
||||
|
||||
#define picorv32_waitirq_insn(_rd) \
|
||||
r_type_insn(0b0000100, 0, 0, 0b100, regnum_ ## _rd, 0b0001011)
|
||||
|
||||
#define picorv32_timer_insn(_rd, _rs) \
|
||||
r_type_insn(0b0000101, 0, regnum_ ## _rs, 0b110, regnum_ ## _rd, 0b0001011)
|
||||
|
@ -3,27 +3,20 @@
|
||||
* SPDX-License-Identifier: GPL-2.0-only
|
||||
*/
|
||||
|
||||
#include "proto.h"
|
||||
#include "../tk1_mem.h"
|
||||
#include "assert.h"
|
||||
#include "led.h"
|
||||
#include "lib.h"
|
||||
#include "state.h"
|
||||
#include "types.h"
|
||||
#include <stdint.h>
|
||||
#include <tkey/assert.h>
|
||||
#include <tkey/debug.h>
|
||||
#include <tkey/io.h>
|
||||
#include <tkey/led.h>
|
||||
#include <tkey/lib.h>
|
||||
#include <tkey/tk1_mem.h>
|
||||
|
||||
// clang-format off
|
||||
static volatile uint32_t *can_rx = (volatile uint32_t *)TK1_MMIO_UART_RX_STATUS;
|
||||
static volatile uint32_t *rx = (volatile uint32_t *)TK1_MMIO_UART_RX_DATA;
|
||||
static volatile uint32_t *can_tx = (volatile uint32_t *)TK1_MMIO_UART_TX_STATUS;
|
||||
static volatile uint32_t *tx = (volatile uint32_t *)TK1_MMIO_UART_TX_DATA;
|
||||
// clang-format on
|
||||
#include "proto.h"
|
||||
#include "state.h"
|
||||
|
||||
static uint8_t genhdr(uint8_t id, uint8_t endpoint, uint8_t status,
|
||||
enum cmdlen len);
|
||||
static int parseframe(uint8_t b, struct frame_header *hdr);
|
||||
static void write(uint8_t *buf, size_t nbytes);
|
||||
static int read(uint8_t *buf, size_t bufsize, size_t nbytes, uint8_t *mode,
|
||||
uint8_t *mode_bytes_left);
|
||||
static size_t bytelen(enum cmdlen cmdlen);
|
||||
|
||||
static uint8_t genhdr(uint8_t id, uint8_t endpoint, uint8_t status,
|
||||
@ -32,29 +25,59 @@ static uint8_t genhdr(uint8_t id, uint8_t endpoint, uint8_t status,
|
||||
return (id << 5) | (endpoint << 3) | (status << 2) | len;
|
||||
}
|
||||
|
||||
int readcommand(struct frame_header *hdr, uint8_t *cmd, int state,
|
||||
uint8_t *mode, uint8_t *mode_bytes_left)
|
||||
int readcommand(struct frame_header *hdr, uint8_t *cmd, int state)
|
||||
{
|
||||
uint8_t in = 0;
|
||||
uint8_t available = 0;
|
||||
enum ioend endpoint = IO_NONE;
|
||||
|
||||
set_led((state == FW_STATE_LOADING) ? LED_BLACK : LED_WHITE);
|
||||
in = readbyte(mode, mode_bytes_left);
|
||||
led_set((state == FW_STATE_LOADING) ? LED_BLACK : LED_WHITE);
|
||||
|
||||
if (parseframe(in, hdr) == -1) {
|
||||
htif_puts("Couldn't parse header\n");
|
||||
debug_puts("readcommand\n");
|
||||
|
||||
if (readselect(IO_CDC, &endpoint, &available) < 0) {
|
||||
return -1;
|
||||
}
|
||||
|
||||
(void)memset(cmd, 0, CMDLEN_MAXBYTES);
|
||||
// Now we know the size of the cmd frame, read it all
|
||||
if (read(cmd, CMDLEN_MAXBYTES, hdr->len, mode, mode_bytes_left) != 0) {
|
||||
htif_puts("read: buffer overrun\n");
|
||||
if (read(IO_CDC, &in, 1, 1) == -1) {
|
||||
return -1;
|
||||
}
|
||||
|
||||
debug_puts("read 1 byte\n");
|
||||
|
||||
if (parseframe(in, hdr) == -1) {
|
||||
debug_puts("Couldn't parse header\n");
|
||||
return -1;
|
||||
}
|
||||
|
||||
debug_puts("parseframe succeeded\n");
|
||||
|
||||
(void)memset(cmd, 0, CMDSIZE);
|
||||
|
||||
// Now we know the size of the cmd frame, read it all
|
||||
uint8_t n = 0;
|
||||
while (n < hdr->len) {
|
||||
// Wait for something to be available
|
||||
if (readselect(IO_CDC, &endpoint, &available) < 0) {
|
||||
return -1;
|
||||
}
|
||||
|
||||
// Read as much as is available of what we expect
|
||||
available = available > hdr->len ? hdr->len : available;
|
||||
|
||||
assert(n < CMDSIZE);
|
||||
int n_bytes_read =
|
||||
read(IO_CDC, &cmd[n], CMDSIZE - n, available);
|
||||
if (n_bytes_read < 0) {
|
||||
return -1;
|
||||
}
|
||||
|
||||
n += n_bytes_read;
|
||||
}
|
||||
|
||||
// Is it for us?
|
||||
if (hdr->endpoint != DST_FW) {
|
||||
htif_puts("Message not meant for us\n");
|
||||
debug_puts("Message not meant for us\n");
|
||||
return -1;
|
||||
}
|
||||
|
||||
@ -86,6 +109,7 @@ void fwreply(struct frame_header hdr, enum fwcmd rspcode, uint8_t *buf)
|
||||
{
|
||||
size_t nbytes = 0;
|
||||
enum cmdlen len = 0; // length covering (rspcode + length of buf)
|
||||
uint8_t frame[1 + 128]; // Frame header + longest response
|
||||
|
||||
switch (rspcode) {
|
||||
case FW_RSP_NAME_VERSION:
|
||||
@ -109,94 +133,23 @@ void fwreply(struct frame_header hdr, enum fwcmd rspcode, uint8_t *buf)
|
||||
break;
|
||||
|
||||
default:
|
||||
htif_puts("fwreply(): Unknown response code: 0x");
|
||||
htif_puthex(rspcode);
|
||||
htif_lf();
|
||||
debug_puts("fwreply(): Unknown response code: 0x");
|
||||
debug_puthex(rspcode);
|
||||
debug_lf();
|
||||
return;
|
||||
}
|
||||
|
||||
nbytes = bytelen(len);
|
||||
|
||||
// Mode Protocol Header
|
||||
writebyte(MODE_CDC);
|
||||
writebyte(2);
|
||||
|
||||
// Frame Protocol Header
|
||||
writebyte(genhdr(hdr.id, hdr.endpoint, 0x0, len));
|
||||
frame[0] = genhdr(hdr.id, hdr.endpoint, 0x0, len);
|
||||
// App protocol header
|
||||
frame[1] = rspcode;
|
||||
|
||||
// FW protocol header
|
||||
writebyte(rspcode);
|
||||
nbytes--;
|
||||
// Payload
|
||||
memcpy(&frame[2], buf, nbytes - 1);
|
||||
|
||||
while (nbytes > 0) {
|
||||
// Limit transfers to 64 bytes (2 byte header + 62 byte data) to
|
||||
// fit in a single USB frame.
|
||||
size_t tx_count = nbytes > 62 ? 62 : nbytes;
|
||||
// Mode Protocol Header
|
||||
writebyte(MODE_CDC);
|
||||
writebyte(tx_count & 0xff);
|
||||
|
||||
// Data
|
||||
write(buf, tx_count);
|
||||
nbytes -= tx_count;
|
||||
buf += tx_count;
|
||||
}
|
||||
}
|
||||
|
||||
void writebyte(uint8_t b)
|
||||
{
|
||||
for (;;) {
|
||||
if (*can_tx) {
|
||||
*tx = b;
|
||||
return;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
static void write(uint8_t *buf, size_t nbytes)
|
||||
{
|
||||
for (int i = 0; i < nbytes; i++) {
|
||||
writebyte(buf[i]);
|
||||
}
|
||||
}
|
||||
|
||||
uint8_t readbyte_(void)
|
||||
{
|
||||
for (;;) {
|
||||
if (*can_rx) {
|
||||
uint32_t b = *rx;
|
||||
return b;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
uint8_t readbyte(uint8_t *mode, uint8_t *mode_bytes_left)
|
||||
{
|
||||
if (*mode_bytes_left == 0) {
|
||||
*mode = readbyte_();
|
||||
if (*mode != MODE_CDC) {
|
||||
htif_puts("We only support MODE_CDC\n");
|
||||
} else {
|
||||
*mode_bytes_left = readbyte_();
|
||||
}
|
||||
}
|
||||
uint8_t b = readbyte_();
|
||||
*mode_bytes_left -= 1;
|
||||
return b;
|
||||
}
|
||||
|
||||
static int read(uint8_t *buf, size_t bufsize, size_t nbytes, uint8_t *mode,
|
||||
uint8_t *mode_bytes_left)
|
||||
{
|
||||
if (nbytes > bufsize) {
|
||||
return -1;
|
||||
}
|
||||
|
||||
for (int n = 0; n < nbytes; n++) {
|
||||
buf[n] = readbyte(mode, mode_bytes_left);
|
||||
}
|
||||
|
||||
return 0;
|
||||
write(IO_CDC, frame, 1 + nbytes);
|
||||
}
|
||||
|
||||
// bytelen returns the number of bytes a cmdlen takes
|
||||
|
@ -3,17 +3,12 @@
|
||||
* SPDX-License-Identifier: GPL-2.0-only
|
||||
*/
|
||||
|
||||
#include "types.h"
|
||||
#include <stddef.h>
|
||||
#include <stdint.h>
|
||||
|
||||
#ifndef PROTO_H
|
||||
#define PROTO_H
|
||||
|
||||
enum mode {
|
||||
MODE_TKEYCTRL = 0x20,
|
||||
MODE_CDC = 0x40,
|
||||
MODE_HID = 0x80,
|
||||
};
|
||||
|
||||
enum endpoints {
|
||||
DST_HW_IFPGA,
|
||||
DST_HW_AFPGA,
|
||||
@ -28,7 +23,7 @@ enum cmdlen {
|
||||
LEN_128
|
||||
};
|
||||
|
||||
#define CMDLEN_MAXBYTES 128
|
||||
#define CMDSIZE 128
|
||||
|
||||
// clang-format off
|
||||
enum fwcmd {
|
||||
@ -57,9 +52,6 @@ struct frame_header {
|
||||
};
|
||||
|
||||
/*@ -exportlocal @*/
|
||||
void writebyte(uint8_t b);
|
||||
uint8_t readbyte(uint8_t *mode, uint8_t *mode_bytes_left);
|
||||
void fwreply(struct frame_header hdr, enum fwcmd rspcode, uint8_t *buf);
|
||||
int readcommand(struct frame_header *hdr, uint8_t *cmd, int state,
|
||||
uint8_t *mode, uint8_t *mode_bytes_left);
|
||||
int readcommand(struct frame_header *hdr, uint8_t *cmd, int state);
|
||||
#endif
|
||||
|
@ -1,11 +1,111 @@
|
||||
/*
|
||||
* Copyright (C) 2022, 2023 - Tillitis AB
|
||||
* Copyright (C) 2022-2025 - Tillitis AB
|
||||
* SPDX-License-Identifier: GPL-2.0-only
|
||||
*/
|
||||
|
||||
#include <tkey/tk1_mem.h>
|
||||
#include "picorv32/custom_ops.S" // PicoRV32 custom instructions
|
||||
|
||||
#define illegal_insn() .word 0
|
||||
|
||||
// Variables in bss
|
||||
.lcomm irq_ret_addr, 4
|
||||
.lcomm app_sp, 4
|
||||
|
||||
.section ".text.init"
|
||||
.globl _start
|
||||
_start:
|
||||
j init
|
||||
|
||||
/*
|
||||
* IRQ handler
|
||||
*/
|
||||
.=0x10
|
||||
irq_handler:
|
||||
// PicoRV32 stores the IRQ bitmask in x4.
|
||||
// If bit 31 is 1: IRQ31 was triggered.
|
||||
li t4, (1 << 31)
|
||||
beq x4, t4, irq_source_ok
|
||||
unexpected_irq_source:
|
||||
illegal_insn()
|
||||
j unexpected_irq_source
|
||||
irq_source_ok:
|
||||
|
||||
// Save interrupt return address (x3)
|
||||
la t0, irq_ret_addr
|
||||
sw x3, 0(t0)
|
||||
|
||||
// Save app stack pointer. App is responsible for saving the rest of
|
||||
// the registers.
|
||||
la t0, app_sp
|
||||
sw sp, 0(t0)
|
||||
|
||||
// Setup firmware stack pointer
|
||||
la sp, _estack
|
||||
|
||||
// Run syscall handler
|
||||
call syscall_handler
|
||||
|
||||
// Restore app stack pointer
|
||||
la t0, app_sp
|
||||
lw sp, 0(t0)
|
||||
|
||||
// Restore interrupt return address (x3)
|
||||
la t0, irq_ret_addr
|
||||
lw x3, 0(t0)
|
||||
|
||||
// Verify that interrupt return address (x3) is in app RAM
|
||||
li t0, TK1_RAM_BASE // 0x40000000
|
||||
blt x3, t0, x3_invalid
|
||||
li t0, TK1_RAM_BASE + TK1_RAM_SIZE // 0x40020000
|
||||
bge x3, t0, x3_invalid
|
||||
j x3_valid
|
||||
x3_invalid:
|
||||
illegal_insn()
|
||||
j x3_invalid
|
||||
x3_valid:
|
||||
|
||||
// Remove data left over from the syscall handling
|
||||
mv x0, zero
|
||||
mv x1, zero
|
||||
// x2 (sp) is assumed to be preserved by the interrupt handler
|
||||
// x3 (interrupt return address) need to be preserved
|
||||
mv x4, zero
|
||||
mv x5, zero
|
||||
mv x6, zero
|
||||
mv x7, zero
|
||||
mv x8, zero
|
||||
mv x9, zero
|
||||
// x10 (a0) contains syscall return value. And should not be destroyed.
|
||||
mv x11, zero
|
||||
mv x12, zero
|
||||
mv x13, zero
|
||||
mv x14, zero
|
||||
mv x15, zero
|
||||
mv x16, zero
|
||||
mv x17, zero
|
||||
mv x18, zero
|
||||
mv x19, zero
|
||||
mv x20, zero
|
||||
mv x21, zero
|
||||
mv x22, zero
|
||||
mv x23, zero
|
||||
mv x24, zero
|
||||
mv x25, zero
|
||||
mv x26, zero
|
||||
mv x27, zero
|
||||
mv x28, zero
|
||||
mv x29, zero
|
||||
mv x30, zero
|
||||
mv x31, zero
|
||||
|
||||
picorv32_retirq_insn() // Return from interrupt
|
||||
|
||||
/*
|
||||
* Init
|
||||
*/
|
||||
.=0x100
|
||||
init:
|
||||
li x1, 0
|
||||
li x2, 0
|
||||
li x3, 0
|
||||
@ -39,17 +139,24 @@ _start:
|
||||
li x31,0
|
||||
|
||||
/* Clear FW_RAM */
|
||||
li a0, 0xd0000000 // TK1_MMIO_FW_RAM_BASE
|
||||
li a1, 0xd0000800 // TK1_MMIO_FW_RAM_BASE + TK1_MMIO_FW_RAM_SIZE
|
||||
la a0, _sfwram
|
||||
la a1, _efwram
|
||||
clear:
|
||||
sw zero, 0(a0)
|
||||
addi a0, a0, 4
|
||||
blt a0, a1, clear
|
||||
|
||||
/*
|
||||
* Init stack at top of fw_ram.
|
||||
*/
|
||||
li sp, 0xd0000800 // 2 kiB (TK1_MMIO_FW_RAM_SIZE)
|
||||
/* Zero-init bss section */
|
||||
la a0, _sbss
|
||||
la a1, _ebss
|
||||
|
||||
loop_init_bss:
|
||||
sw zero, 0(a0)
|
||||
addi a0, a0, 4
|
||||
blt a0, a1, loop_init_bss
|
||||
|
||||
/* Init stack */
|
||||
la sp, _estack
|
||||
|
||||
call main
|
||||
|
||||
|
12
hw/application_fpga/fw/tk1/syscall_enable.S
Normal file
12
hw/application_fpga/fw/tk1/syscall_enable.S
Normal file
@ -0,0 +1,12 @@
|
||||
#include "../tk1/picorv32/custom_ops.S"
|
||||
|
||||
.section ".text"
|
||||
.globl syscall_enable
|
||||
|
||||
|
||||
syscall_enable:
|
||||
/* Enable syscall IRQ */
|
||||
li t0, 0x7fffffff // IRQ31 mask
|
||||
picorv32_maskirq_insn(zero, t0) // Enable IRQs
|
||||
|
||||
ret
|
9
hw/application_fpga/fw/tk1/syscall_enable.h
Normal file
9
hw/application_fpga/fw/tk1/syscall_enable.h
Normal file
@ -0,0 +1,9 @@
|
||||
// Copyright (C) 2025 - Tillitis AB
|
||||
// SPDX-License-Identifier: GPL-2.0-only
|
||||
|
||||
#ifndef TKEY_SYSCALL_ENABLE_H
|
||||
#define TKEY_SYSCALL_ENABLE_H
|
||||
|
||||
void syscall_enable(void);
|
||||
|
||||
#endif
|
37
hw/application_fpga/fw/tk1/syscall_handler.c
Normal file
37
hw/application_fpga/fw/tk1/syscall_handler.c
Normal file
@ -0,0 +1,37 @@
|
||||
/*
|
||||
* Copyright (C) 2025 - Tillitis AB
|
||||
* SPDX-License-Identifier: GPL-2.0-only
|
||||
*/
|
||||
|
||||
#include <stdint.h>
|
||||
#include <tkey/assert.h>
|
||||
#include <tkey/led.h>
|
||||
|
||||
#include "../tk1/syscall_num.h"
|
||||
|
||||
// clang-format off
|
||||
static volatile uint32_t *system_reset = (volatile uint32_t *)TK1_MMIO_TK1_SYSTEM_RESET;
|
||||
static volatile uint32_t *udi = (volatile uint32_t *)TK1_MMIO_TK1_UDI_FIRST;
|
||||
// clang-format on
|
||||
|
||||
int32_t syscall_handler(uint32_t number, uint32_t arg1)
|
||||
{
|
||||
switch (number) {
|
||||
case TK1_SYSCALL_RESET:
|
||||
*system_reset = 1;
|
||||
return 0;
|
||||
case TK1_SYSCALL_SET_LED:
|
||||
led_set(arg1);
|
||||
return 0;
|
||||
case TK1_SYSCALL_GET_VIDPID:
|
||||
// UDI is 2 words: VID/PID & serial. Return just the
|
||||
// first word. Serial is kept secret to the device
|
||||
// app.
|
||||
return udi[0];
|
||||
default:
|
||||
assert(1 == 2);
|
||||
}
|
||||
|
||||
assert(1 == 2);
|
||||
return -1; // This should never run
|
||||
}
|
13
hw/application_fpga/fw/tk1/syscall_num.h
Normal file
13
hw/application_fpga/fw/tk1/syscall_num.h
Normal file
@ -0,0 +1,13 @@
|
||||
// Copyright (C) 2025 - Tillitis AB
|
||||
// SPDX-License-Identifier: GPL-2.0-only
|
||||
|
||||
#ifndef TKEY_SYSCALL_NUM_H
|
||||
#define TKEY_SYSCALL_NUM_H
|
||||
|
||||
enum syscall_num {
|
||||
TK1_SYSCALL_RESET = 1,
|
||||
TK1_SYSCALL_SET_LED = 10,
|
||||
TK1_SYSCALL_GET_VIDPID = 12,
|
||||
};
|
||||
|
||||
#endif
|
@ -1,22 +0,0 @@
|
||||
/*
|
||||
* Copyright (C) 2022 - Tillitis AB
|
||||
* SPDX-License-Identifier: GPL-2.0-only
|
||||
*/
|
||||
|
||||
#ifndef TYPES_H
|
||||
#define TYPES_H
|
||||
|
||||
typedef unsigned int uintptr_t;
|
||||
typedef unsigned long long uint64_t;
|
||||
typedef unsigned int uint32_t;
|
||||
typedef int int32_t;
|
||||
typedef long long int64_t;
|
||||
typedef unsigned char uint8_t;
|
||||
typedef unsigned long size_t;
|
||||
|
||||
#define NULL ((char *)0)
|
||||
|
||||
#define FALSE 0
|
||||
#define TRUE !FALSE
|
||||
|
||||
#endif
|
@ -57,11 +57,13 @@ module application_fpga (
|
||||
localparam UART_PREFIX = 6'h03;
|
||||
localparam TOUCH_SENSE_PREFIX = 6'h04;
|
||||
localparam FW_RAM_PREFIX = 6'h10;
|
||||
localparam SYSCALL_PREFIX = 6'h21;
|
||||
localparam TK1_PREFIX = 6'h3f;
|
||||
|
||||
// Instruction used to cause a trap.
|
||||
localparam ILLEGAL_INSTRUCTION = 32'h0;
|
||||
|
||||
localparam IRQ31_IRQ_MASK = 2 ** 31;
|
||||
|
||||
//----------------------------------------------------------------
|
||||
// Registers, memories with associated wires.
|
||||
@ -80,16 +82,18 @@ module application_fpga (
|
||||
wire reset_n;
|
||||
|
||||
/* verilator lint_off UNOPTFLAT */
|
||||
reg [31 : 0] cpu_irq;
|
||||
wire cpu_trap;
|
||||
wire cpu_valid;
|
||||
wire cpu_instr;
|
||||
wire [03 : 0] cpu_wstrb;
|
||||
/* verilator lint_off UNUSED */
|
||||
wire [31 : 0] cpu_eoi;
|
||||
wire [31 : 0] cpu_addr;
|
||||
wire [31 : 0] cpu_wdata;
|
||||
|
||||
reg rom_cs;
|
||||
reg [11 : 0] rom_address;
|
||||
reg [10 : 0] rom_address;
|
||||
wire [31 : 0] rom_read_data;
|
||||
wire rom_ready;
|
||||
|
||||
@ -128,7 +132,7 @@ module application_fpga (
|
||||
|
||||
reg fw_ram_cs;
|
||||
reg [ 3 : 0] fw_ram_we;
|
||||
reg [ 8 : 0] fw_ram_address;
|
||||
reg [ 9 : 0] fw_ram_address;
|
||||
reg [31 : 0] fw_ram_write_data;
|
||||
wire [31 : 0] fw_ram_read_data;
|
||||
wire fw_ram_ready;
|
||||
@ -139,13 +143,18 @@ module application_fpga (
|
||||
wire [31 : 0] touch_sense_read_data;
|
||||
wire touch_sense_ready;
|
||||
|
||||
reg irq31_cs;
|
||||
reg irq31_we;
|
||||
reg irq31_eoi;
|
||||
|
||||
reg tk1_cs;
|
||||
reg tk1_we;
|
||||
reg [ 7 : 0] tk1_address;
|
||||
reg [31 : 0] tk1_write_data;
|
||||
wire [31 : 0] tk1_read_data;
|
||||
wire tk1_ready;
|
||||
wire system_mode;
|
||||
wire app_mode;
|
||||
wire fw_startup_done;
|
||||
wire force_trap;
|
||||
wire [14 : 0] ram_addr_rand;
|
||||
wire [31 : 0] ram_data_rand;
|
||||
@ -171,7 +180,12 @@ module application_fpga (
|
||||
.CATCH_MISALIGN (0),
|
||||
.COMPRESSED_ISA (1),
|
||||
.ENABLE_FAST_MUL (1),
|
||||
.BARREL_SHIFTER (1)
|
||||
.BARREL_SHIFTER (1),
|
||||
.ENABLE_IRQ (1),
|
||||
.ENABLE_IRQ_QREGS(0),
|
||||
.ENABLE_IRQ_TIMER(0),
|
||||
.MASKED_IRQ (~IRQ31_IRQ_MASK),
|
||||
.LATCHED_IRQ (IRQ31_IRQ_MASK)
|
||||
) cpu (
|
||||
.clk(clk),
|
||||
.resetn(reset_n),
|
||||
@ -185,11 +199,12 @@ module application_fpga (
|
||||
.mem_rdata(muxed_rdata_reg),
|
||||
.mem_instr(cpu_instr),
|
||||
|
||||
.irq(cpu_irq),
|
||||
.eoi(cpu_eoi),
|
||||
|
||||
// Defined unused ports. Makes lint happy. But
|
||||
// we still needs to help lint with empty ports.
|
||||
/* verilator lint_off PINCONNECTEMPTY */
|
||||
.irq(32'h0),
|
||||
.eoi(),
|
||||
.trace_valid(),
|
||||
.trace_data(),
|
||||
.mem_la_read(),
|
||||
@ -240,7 +255,7 @@ module application_fpga (
|
||||
.clk(clk),
|
||||
.reset_n(reset_n),
|
||||
|
||||
.system_mode(system_mode),
|
||||
.app_mode(app_mode),
|
||||
|
||||
.cs(fw_ram_cs),
|
||||
.we(fw_ram_we),
|
||||
@ -280,7 +295,7 @@ module application_fpga (
|
||||
.clk(clk),
|
||||
.reset_n(reset_n),
|
||||
|
||||
.system_mode(system_mode),
|
||||
.en(~fw_startup_done),
|
||||
|
||||
.cs(uds_cs),
|
||||
.address(uds_address),
|
||||
@ -326,7 +341,8 @@ module application_fpga (
|
||||
.clk(clk),
|
||||
.reset_n(reset_n),
|
||||
|
||||
.system_mode(system_mode),
|
||||
.app_mode(app_mode),
|
||||
.fw_startup_done(fw_startup_done),
|
||||
|
||||
.cpu_addr (cpu_addr),
|
||||
.cpu_instr (cpu_instr),
|
||||
@ -353,6 +369,8 @@ module application_fpga (
|
||||
.gpio3(app_gpio3),
|
||||
.gpio4(app_gpio4),
|
||||
|
||||
.syscall(irq31_eoi),
|
||||
|
||||
.cs(tk1_cs),
|
||||
.we(tk1_we),
|
||||
.address(tk1_address),
|
||||
@ -379,6 +397,20 @@ module application_fpga (
|
||||
end
|
||||
|
||||
|
||||
//----------------------------------------------------------------
|
||||
// irq_ctrl
|
||||
// Interrupt logic
|
||||
//----------------------------------------------------------------
|
||||
always @* begin : irq_ctrl
|
||||
reg irq31_set;
|
||||
|
||||
irq31_set = irq31_cs & irq31_we;
|
||||
cpu_irq = {irq31_set, 31'h0};
|
||||
|
||||
irq31_eoi = cpu_eoi[31];
|
||||
end
|
||||
|
||||
|
||||
//----------------------------------------------------------------
|
||||
// cpu_mem_ctrl
|
||||
// CPU memory decode and control logic.
|
||||
@ -394,7 +426,7 @@ module application_fpga (
|
||||
muxed_rdata_new = 32'h0;
|
||||
|
||||
rom_cs = 1'h0;
|
||||
rom_address = cpu_addr[13 : 2];
|
||||
rom_address = cpu_addr[12 : 2];
|
||||
|
||||
ram_cs = 1'h0;
|
||||
ram_we = 4'h0;
|
||||
@ -403,7 +435,7 @@ module application_fpga (
|
||||
|
||||
fw_ram_cs = 1'h0;
|
||||
fw_ram_we = cpu_wstrb;
|
||||
fw_ram_address = cpu_addr[10 : 2];
|
||||
fw_ram_address = cpu_addr[11 : 2];
|
||||
fw_ram_write_data = cpu_wdata;
|
||||
|
||||
trng_cs = 1'h0;
|
||||
@ -428,6 +460,9 @@ module application_fpga (
|
||||
touch_sense_we = |cpu_wstrb;
|
||||
touch_sense_address = cpu_addr[9 : 2];
|
||||
|
||||
irq31_cs = 1'h0;
|
||||
irq31_we = |cpu_wstrb;
|
||||
|
||||
tk1_cs = 1'h0;
|
||||
tk1_we = |cpu_wstrb;
|
||||
tk1_address = cpu_addr[9 : 2];
|
||||
@ -500,6 +535,11 @@ module application_fpga (
|
||||
muxed_ready_new = fw_ram_ready;
|
||||
end
|
||||
|
||||
SYSCALL_PREFIX: begin
|
||||
irq31_cs = 1'h1;
|
||||
muxed_ready_new = 1'h1;
|
||||
end
|
||||
|
||||
TK1_PREFIX: begin
|
||||
tk1_cs = 1'h1;
|
||||
muxed_rdata_new = tk1_read_data;
|
||||
|
@ -70,11 +70,13 @@ module application_fpga_sim (
|
||||
localparam UART_PREFIX = 6'h03;
|
||||
localparam TOUCH_SENSE_PREFIX = 6'h04;
|
||||
localparam FW_RAM_PREFIX = 6'h10;
|
||||
localparam SYSCALL_PREFIX = 6'h21;
|
||||
localparam TK1_PREFIX = 6'h3f;
|
||||
|
||||
// Instruction used to cause a trap.
|
||||
localparam ILLEGAL_INSTRUCTION = 32'h0;
|
||||
|
||||
localparam IRQ31_IRQ_MASK = 2 ** 31;
|
||||
|
||||
//----------------------------------------------------------------
|
||||
// Registers, memories with associated wires.
|
||||
@ -92,16 +94,18 @@ module application_fpga_sim (
|
||||
wire reset_n;
|
||||
|
||||
/* verilator lint_off UNOPTFLAT */
|
||||
reg [31 : 0] cpu_irq;
|
||||
wire cpu_trap;
|
||||
wire cpu_valid;
|
||||
wire cpu_instr;
|
||||
wire [ 3 : 0] cpu_wstrb;
|
||||
/* verilator lint_off UNUSED */
|
||||
wire [31 : 0] cpu_eoi;
|
||||
wire [31 : 0] cpu_addr;
|
||||
wire [31 : 0] cpu_wdata;
|
||||
|
||||
reg rom_cs;
|
||||
reg [11 : 0] rom_address;
|
||||
reg [10 : 0] rom_address;
|
||||
wire [31 : 0] rom_read_data;
|
||||
wire rom_ready;
|
||||
|
||||
@ -140,7 +144,7 @@ module application_fpga_sim (
|
||||
|
||||
reg fw_ram_cs;
|
||||
reg [ 3 : 0] fw_ram_we;
|
||||
reg [ 8 : 0] fw_ram_address;
|
||||
reg [ 9 : 0] fw_ram_address;
|
||||
reg [31 : 0] fw_ram_write_data;
|
||||
wire [31 : 0] fw_ram_read_data;
|
||||
wire fw_ram_ready;
|
||||
@ -151,13 +155,18 @@ module application_fpga_sim (
|
||||
wire [31 : 0] touch_sense_read_data;
|
||||
wire touch_sense_ready;
|
||||
|
||||
reg irq31_cs;
|
||||
reg irq31_we;
|
||||
reg irq31_eoi;
|
||||
|
||||
reg tk1_cs;
|
||||
reg tk1_we;
|
||||
reg [ 7 : 0] tk1_address;
|
||||
reg [31 : 0] tk1_write_data;
|
||||
wire [31 : 0] tk1_read_data;
|
||||
wire tk1_ready;
|
||||
wire system_mode;
|
||||
wire app_mode;
|
||||
wire fw_startup_done;
|
||||
wire force_trap;
|
||||
wire [14 : 0] ram_addr_rand;
|
||||
wire [31 : 0] ram_data_rand;
|
||||
@ -182,7 +191,12 @@ module application_fpga_sim (
|
||||
.CATCH_MISALIGN (0),
|
||||
.COMPRESSED_ISA (1),
|
||||
.ENABLE_FAST_MUL (1),
|
||||
.BARREL_SHIFTER (1)
|
||||
.BARREL_SHIFTER (1),
|
||||
.ENABLE_IRQ (1),
|
||||
.ENABLE_IRQ_QREGS(0),
|
||||
.ENABLE_IRQ_TIMER(0),
|
||||
.MASKED_IRQ (~IRQ31_IRQ_MASK),
|
||||
.LATCHED_IRQ (IRQ31_IRQ_MASK)
|
||||
) cpu (
|
||||
.clk(clk),
|
||||
.resetn(reset_n),
|
||||
@ -196,11 +210,12 @@ module application_fpga_sim (
|
||||
.mem_rdata(muxed_rdata_reg),
|
||||
.mem_instr(cpu_instr),
|
||||
|
||||
.irq(cpu_irq),
|
||||
.eoi(cpu_eoi),
|
||||
|
||||
// Defined unused ports. Makes lint happy. But
|
||||
// we still needs to help lint with empty ports.
|
||||
/* verilator lint_off PINCONNECTEMPTY */
|
||||
.irq(32'h0),
|
||||
.eoi(),
|
||||
.trace_valid(),
|
||||
.trace_data(),
|
||||
.mem_la_read(),
|
||||
@ -251,7 +266,7 @@ module application_fpga_sim (
|
||||
.clk(clk),
|
||||
.reset_n(reset_n),
|
||||
|
||||
.system_mode(system_mode),
|
||||
.app_mode(app_mode),
|
||||
|
||||
.cs(fw_ram_cs),
|
||||
.we(fw_ram_we),
|
||||
@ -291,7 +306,7 @@ module application_fpga_sim (
|
||||
.clk(clk),
|
||||
.reset_n(reset_n),
|
||||
|
||||
.system_mode(system_mode),
|
||||
.en(~fw_startup_done),
|
||||
|
||||
.cs(uds_cs),
|
||||
.address(uds_address),
|
||||
@ -339,7 +354,8 @@ module application_fpga_sim (
|
||||
.clk(clk),
|
||||
.reset_n(reset_n),
|
||||
|
||||
.system_mode(system_mode),
|
||||
.app_mode(app_mode),
|
||||
.fw_startup_done(fw_startup_done),
|
||||
|
||||
.cpu_addr (cpu_addr),
|
||||
.cpu_instr (cpu_instr),
|
||||
@ -366,6 +382,8 @@ module application_fpga_sim (
|
||||
.gpio3(app_gpio3),
|
||||
.gpio4(app_gpio4),
|
||||
|
||||
.syscall(irq31_eoi),
|
||||
|
||||
.cs(tk1_cs),
|
||||
.we(tk1_we),
|
||||
.address(tk1_address),
|
||||
@ -391,6 +409,20 @@ module application_fpga_sim (
|
||||
end
|
||||
|
||||
|
||||
//----------------------------------------------------------------
|
||||
// irq_ctrl
|
||||
// Interrupt logic
|
||||
//----------------------------------------------------------------
|
||||
always @* begin : irq_ctrl
|
||||
reg irq31_set;
|
||||
|
||||
irq31_set = irq31_cs & irq31_we;
|
||||
cpu_irq = {irq31_set, 31'h0};
|
||||
|
||||
irq31_eoi = cpu_eoi[31];
|
||||
end
|
||||
|
||||
|
||||
//----------------------------------------------------------------
|
||||
// cpu_mem_ctrl
|
||||
// CPU memory decode and control logic.
|
||||
@ -408,7 +440,7 @@ module application_fpga_sim (
|
||||
muxed_rdata_new = 32'h0;
|
||||
|
||||
rom_cs = 1'h0;
|
||||
rom_address = cpu_addr[13 : 2];
|
||||
rom_address = cpu_addr[12 : 2];
|
||||
|
||||
ram_cs = 1'h0;
|
||||
ram_we = 4'h0;
|
||||
@ -417,7 +449,7 @@ module application_fpga_sim (
|
||||
|
||||
fw_ram_cs = 1'h0;
|
||||
fw_ram_we = cpu_wstrb;
|
||||
fw_ram_address = cpu_addr[10 : 2];
|
||||
fw_ram_address = cpu_addr[11 : 2];
|
||||
fw_ram_write_data = cpu_wdata;
|
||||
|
||||
trng_cs = 1'h0;
|
||||
@ -442,6 +474,9 @@ module application_fpga_sim (
|
||||
touch_sense_we = |cpu_wstrb;
|
||||
touch_sense_address = cpu_addr[9 : 2];
|
||||
|
||||
irq31_cs = 1'h0;
|
||||
irq31_we = |cpu_wstrb;
|
||||
|
||||
tk1_cs = 1'h0;
|
||||
tk1_we = |cpu_wstrb;
|
||||
tk1_address = cpu_addr[9 : 2];
|
||||
@ -534,6 +569,13 @@ module application_fpga_sim (
|
||||
muxed_ready_new = fw_ram_ready;
|
||||
end
|
||||
|
||||
SYSCALL_PREFIX: begin
|
||||
`verbose($display("Access to syscall interrupt trigger");)
|
||||
ascii_state = "Syscall IRQ trigger";
|
||||
irq31_cs = 1'h1;
|
||||
muxed_ready_new = 1'h1;
|
||||
end
|
||||
|
||||
TK1_PREFIX: begin
|
||||
`verbose($display("Access to TK1 core");)
|
||||
ascii_state = "TK1 core";
|
||||
|
26
hw/application_fpga/tkey-libs/LICENSE
Normal file
26
hw/application_fpga/tkey-libs/LICENSE
Normal file
@ -0,0 +1,26 @@
|
||||
BSD 2-Clause License
|
||||
|
||||
Copyright 2022 Tillitis AB <tillitis.se>
|
||||
|
||||
Redistribution and use in source and binary forms, with or without
|
||||
modification, are permitted provided that the following conditions are
|
||||
met:
|
||||
|
||||
1. Redistributions of source code must retain the above copyright
|
||||
notice, this list of conditions and the following disclaimer.
|
||||
|
||||
2. Redistributions in binary form must reproduce the above copyright
|
||||
notice, this list of conditions and the following disclaimer in the
|
||||
documentation and/or other materials provided with the distribution.
|
||||
|
||||
THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
|
||||
"AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
|
||||
LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
|
||||
A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
|
||||
HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
|
||||
SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
|
||||
LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
|
||||
DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
|
||||
THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
|
||||
(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
|
||||
OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
24
hw/application_fpga/tkey-libs/LICENSES/BSD-2-Clause.txt
Normal file
24
hw/application_fpga/tkey-libs/LICENSES/BSD-2-Clause.txt
Normal file
@ -0,0 +1,24 @@
|
||||
Copyright 2022 Tillitis AB <tillitis.se>
|
||||
|
||||
Redistribution and use in source and binary forms, with or without
|
||||
modification, are permitted provided that the following conditions are
|
||||
met:
|
||||
|
||||
1. Redistributions of source code must retain the above copyright
|
||||
notice, this list of conditions and the following disclaimer.
|
||||
|
||||
2. Redistributions in binary form must reproduce the above copyright
|
||||
notice, this list of conditions and the following disclaimer in the
|
||||
documentation and/or other materials provided with the distribution.
|
||||
|
||||
THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
|
||||
"AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
|
||||
LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
|
||||
A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
|
||||
HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
|
||||
SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
|
||||
LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
|
||||
DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
|
||||
THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
|
||||
(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
|
||||
OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
121
hw/application_fpga/tkey-libs/LICENSES/CC0-1.0.txt
Normal file
121
hw/application_fpga/tkey-libs/LICENSES/CC0-1.0.txt
Normal file
@ -0,0 +1,121 @@
|
||||
Creative Commons Legal Code
|
||||
|
||||
CC0 1.0 Universal
|
||||
|
||||
CREATIVE COMMONS CORPORATION IS NOT A LAW FIRM AND DOES NOT PROVIDE
|
||||
LEGAL SERVICES. DISTRIBUTION OF THIS DOCUMENT DOES NOT CREATE AN
|
||||
ATTORNEY-CLIENT RELATIONSHIP. CREATIVE COMMONS PROVIDES THIS
|
||||
INFORMATION ON AN "AS-IS" BASIS. CREATIVE COMMONS MAKES NO WARRANTIES
|
||||
REGARDING THE USE OF THIS DOCUMENT OR THE INFORMATION OR WORKS
|
||||
PROVIDED HEREUNDER, AND DISCLAIMS LIABILITY FOR DAMAGES RESULTING FROM
|
||||
THE USE OF THIS DOCUMENT OR THE INFORMATION OR WORKS PROVIDED
|
||||
HEREUNDER.
|
||||
|
||||
Statement of Purpose
|
||||
|
||||
The laws of most jurisdictions throughout the world automatically confer
|
||||
exclusive Copyright and Related Rights (defined below) upon the creator
|
||||
and subsequent owner(s) (each and all, an "owner") of an original work of
|
||||
authorship and/or a database (each, a "Work").
|
||||
|
||||
Certain owners wish to permanently relinquish those rights to a Work for
|
||||
the purpose of contributing to a commons of creative, cultural and
|
||||
scientific works ("Commons") that the public can reliably and without fear
|
||||
of later claims of infringement build upon, modify, incorporate in other
|
||||
works, reuse and redistribute as freely as possible in any form whatsoever
|
||||
and for any purposes, including without limitation commercial purposes.
|
||||
These owners may contribute to the Commons to promote the ideal of a free
|
||||
culture and the further production of creative, cultural and scientific
|
||||
works, or to gain reputation or greater distribution for their Work in
|
||||
part through the use and efforts of others.
|
||||
|
||||
For these and/or other purposes and motivations, and without any
|
||||
expectation of additional consideration or compensation, the person
|
||||
associating CC0 with a Work (the "Affirmer"), to the extent that he or she
|
||||
is an owner of Copyright and Related Rights in the Work, voluntarily
|
||||
elects to apply CC0 to the Work and publicly distribute the Work under its
|
||||
terms, with knowledge of his or her Copyright and Related Rights in the
|
||||
Work and the meaning and intended legal effect of CC0 on those rights.
|
||||
|
||||
1. Copyright and Related Rights. A Work made available under CC0 may be
|
||||
protected by copyright and related or neighboring rights ("Copyright and
|
||||
Related Rights"). Copyright and Related Rights include, but are not
|
||||
limited to, the following:
|
||||
|
||||
i. the right to reproduce, adapt, distribute, perform, display,
|
||||
communicate, and translate a Work;
|
||||
ii. moral rights retained by the original author(s) and/or performer(s);
|
||||
iii. publicity and privacy rights pertaining to a person's image or
|
||||
likeness depicted in a Work;
|
||||
iv. rights protecting against unfair competition in regards to a Work,
|
||||
subject to the limitations in paragraph 4(a), below;
|
||||
v. rights protecting the extraction, dissemination, use and reuse of data
|
||||
in a Work;
|
||||
vi. database rights (such as those arising under Directive 96/9/EC of the
|
||||
European Parliament and of the Council of 11 March 1996 on the legal
|
||||
protection of databases, and under any national implementation
|
||||
thereof, including any amended or successor version of such
|
||||
directive); and
|
||||
vii. other similar, equivalent or corresponding rights throughout the
|
||||
world based on applicable law or treaty, and any national
|
||||
implementations thereof.
|
||||
|
||||
2. Waiver. To the greatest extent permitted by, but not in contravention
|
||||
of, applicable law, Affirmer hereby overtly, fully, permanently,
|
||||
irrevocably and unconditionally waives, abandons, and surrenders all of
|
||||
Affirmer's Copyright and Related Rights and associated claims and causes
|
||||
of action, whether now known or unknown (including existing as well as
|
||||
future claims and causes of action), in the Work (i) in all territories
|
||||
worldwide, (ii) for the maximum duration provided by applicable law or
|
||||
treaty (including future time extensions), (iii) in any current or future
|
||||
medium and for any number of copies, and (iv) for any purpose whatsoever,
|
||||
including without limitation commercial, advertising or promotional
|
||||
purposes (the "Waiver"). Affirmer makes the Waiver for the benefit of each
|
||||
member of the public at large and to the detriment of Affirmer's heirs and
|
||||
successors, fully intending that such Waiver shall not be subject to
|
||||
revocation, rescission, cancellation, termination, or any other legal or
|
||||
equitable action to disrupt the quiet enjoyment of the Work by the public
|
||||
as contemplated by Affirmer's express Statement of Purpose.
|
||||
|
||||
3. Public License Fallback. Should any part of the Waiver for any reason
|
||||
be judged legally invalid or ineffective under applicable law, then the
|
||||
Waiver shall be preserved to the maximum extent permitted taking into
|
||||
account Affirmer's express Statement of Purpose. In addition, to the
|
||||
extent the Waiver is so judged Affirmer hereby grants to each affected
|
||||
person a royalty-free, non transferable, non sublicensable, non exclusive,
|
||||
irrevocable and unconditional license to exercise Affirmer's Copyright and
|
||||
Related Rights in the Work (i) in all territories worldwide, (ii) for the
|
||||
maximum duration provided by applicable law or treaty (including future
|
||||
time extensions), (iii) in any current or future medium and for any number
|
||||
of copies, and (iv) for any purpose whatsoever, including without
|
||||
limitation commercial, advertising or promotional purposes (the
|
||||
"License"). The License shall be deemed effective as of the date CC0 was
|
||||
applied by Affirmer to the Work. Should any part of the License for any
|
||||
reason be judged legally invalid or ineffective under applicable law, such
|
||||
partial invalidity or ineffectiveness shall not invalidate the remainder
|
||||
of the License, and in such case Affirmer hereby affirms that he or she
|
||||
will not (i) exercise any of his or her remaining Copyright and Related
|
||||
Rights in the Work or (ii) assert any associated claims and causes of
|
||||
action with respect to the Work, in either case contrary to Affirmer's
|
||||
express Statement of Purpose.
|
||||
|
||||
4. Limitations and Disclaimers.
|
||||
|
||||
a. No trademark or patent rights held by Affirmer are waived, abandoned,
|
||||
surrendered, licensed or otherwise affected by this document.
|
||||
b. Affirmer offers the Work as-is and makes no representations or
|
||||
warranties of any kind concerning the Work, express, implied,
|
||||
statutory or otherwise, including without limitation warranties of
|
||||
title, merchantability, fitness for a particular purpose, non
|
||||
infringement, or the absence of latent or other defects, accuracy, or
|
||||
the present or absence of errors, whether or not discoverable, all to
|
||||
the greatest extent permissible under applicable law.
|
||||
c. Affirmer disclaims responsibility for clearing rights of other persons
|
||||
that may apply to the Work or any use thereof, including without
|
||||
limitation any person's Copyright and Related Rights in the Work.
|
||||
Further, Affirmer disclaims responsibility for obtaining any necessary
|
||||
consents, permissions or other rights required for any use of the
|
||||
Work.
|
||||
d. Affirmer understands and acknowledges that Creative Commons is not a
|
||||
party to this document and has no duty or obligation with respect to
|
||||
this CC0 or use of the Work.
|
101
hw/application_fpga/tkey-libs/Makefile
Normal file
101
hw/application_fpga/tkey-libs/Makefile
Normal file
@ -0,0 +1,101 @@
|
||||
OBJCOPY ?= llvm-objcopy
|
||||
|
||||
CC = clang
|
||||
|
||||
INCLUDE=include
|
||||
|
||||
# Set QEMU_DEBUG and TKEY_DEBUG below when compiling tkey-libs if you
|
||||
# want debug prints from tkey-libs functions.
|
||||
#
|
||||
# - QEMU_DEBUG: the debug port on our qemu emulator
|
||||
#
|
||||
# - TKEY_DEBUG: The extra HID endpoint on a real TKey which you can
|
||||
# listen on for debug prints.
|
||||
#
|
||||
# NOTE WELL: If you just want debug prints on either of them in *your
|
||||
# own device app* you just need to include tkey/debug.h and define
|
||||
# either of them. You don't need to recompile tkey-libs.
|
||||
|
||||
CFLAGS = -target riscv32-unknown-none-elf -march=rv32iczmmul -mabi=ilp32 \
|
||||
-mcmodel=medany -static -std=gnu99 -O2 -ffast-math -fno-common \
|
||||
-fno-builtin-printf -fno-builtin-putchar -nostdlib -mno-relax -flto \
|
||||
-Wall -Werror=implicit-function-declaration \
|
||||
-I $(INCLUDE) -I .
|
||||
|
||||
AS = clang
|
||||
AR = llvm-ar
|
||||
ASFLAGS = -target riscv32-unknown-none-elf -march=rv32iczmmul -mabi=ilp32 \
|
||||
-mcmodel=medany -mno-relax
|
||||
|
||||
LDFLAGS=-T app.lds -L libcommon/ -lcommon -L libcrt0/ -lcrt0
|
||||
|
||||
|
||||
.PHONY: all
|
||||
all: libcrt0.a libcommon.a libmonocypher.a libblake2s.a
|
||||
|
||||
IMAGE=ghcr.io/tillitis/tkey-builder:4
|
||||
|
||||
podman:
|
||||
podman run --rm --mount type=bind,source=$(CURDIR),target=/src \
|
||||
-w /src -it $(IMAGE) make -j
|
||||
|
||||
.PHONY: check
|
||||
check:
|
||||
clang-tidy -header-filter=.* -checks=cert-* libcommon/*.c -- $(CFLAGS)
|
||||
|
||||
# C runtime library
|
||||
libcrt0.a: libcrt0/crt0.o
|
||||
$(AR) -qc $@ libcrt0/crt0.o
|
||||
|
||||
# Common C functions
|
||||
LIBOBJS=libcommon/assert.o libcommon/led.o libcommon/lib.o \
|
||||
libcommon/proto.o libcommon/touch.o libcommon/io.o
|
||||
|
||||
libcommon.a: $(LIBOBJS)
|
||||
$(AR) -qc $@ $(LIBOBJS)
|
||||
$(LIBOBJS): include/tkey/assert.h include/tkey/led.h \
|
||||
include/tkey/lib.h include/tkey/proto.h include/tkey/tk1_mem.h \
|
||||
include/tkey/touch.h include/tkey/debug.h
|
||||
|
||||
# Monocypher
|
||||
MONOOBJS=monocypher/monocypher.o monocypher/monocypher-ed25519.o
|
||||
libmonocypher.a: $(MONOOBJS)
|
||||
$(AR) -qc $@ $(MONOOBJS)
|
||||
$MONOOBJS: monocypher/monocypher-ed25519.h monocypher/monocypher.h
|
||||
|
||||
# blake2s
|
||||
B2OBJS=blake2s/blake2s.o
|
||||
libblake2s.a: $(B2OBJS)
|
||||
$(AR) -qc $@ $(B2OBJS)
|
||||
$B2OBJS: blake2s/blake2s.h
|
||||
|
||||
LIBS=libcrt0.a libcommon.a
|
||||
|
||||
.PHONY: clean
|
||||
clean:
|
||||
rm -f $(LIBS) $(LIBOBJS) libcrt0/crt0.o
|
||||
rm -f libmonocypher.a $(MONOOBJS)
|
||||
rm -f libblake2s.a $(B2OBJS)
|
||||
|
||||
# Create compile_commands.json for clangd and LSP
|
||||
.PHONY: clangd
|
||||
clangd: compile_commands.json
|
||||
compile_commands.json:
|
||||
$(MAKE) clean
|
||||
bear -- make all
|
||||
|
||||
# Uses ../.clang-format
|
||||
FMTFILES=include/tkey/*.h libcommon/*.c
|
||||
.PHONY: fmt
|
||||
fmt:
|
||||
clang-format --dry-run --ferror-limit=0 $(FMTFILES)
|
||||
clang-format --verbose -i $(FMTFILES)
|
||||
.PHONY: checkfmt
|
||||
checkfmt:
|
||||
clang-format --dry-run --ferror-limit=0 --Werror $(FMTFILES)
|
||||
|
||||
.PHONY: update-mem-include
|
||||
update-mem-include:
|
||||
cp -af ../tillitis-key1/hw/application_fpga/fw/tk1_mem.h \
|
||||
include/tkey/tk1_mem.h
|
||||
echo "Remember to update header include guard!"
|
33
hw/application_fpga/tkey-libs/README-DIST.txt
Normal file
33
hw/application_fpga/tkey-libs/README-DIST.txt
Normal file
@ -0,0 +1,33 @@
|
||||
tkey-libs binary distribution
|
||||
|
||||
This is the binary distribution of:
|
||||
|
||||
https://github.com/tillitis/tkey-libs
|
||||
|
||||
Which is an SDK for developing device apps for the Tillitis TKey in C.
|
||||
Please see the TKey Developer Handbook for more:
|
||||
|
||||
https://dev.tillitis.se/
|
||||
|
||||
and the company web site:
|
||||
|
||||
https://tillitis.se/
|
||||
|
||||
You should be able to use this distribution directly in device apps
|
||||
simply by pointing LIBDIR to where you unpacked this archive:
|
||||
|
||||
make LIBDIR=~/Download/tkey-libs
|
||||
|
||||
Copyright Tillitis AB.
|
||||
|
||||
These programs are free software: you can redistribute it and/or
|
||||
modify it under the terms of the BSD-2-Clause license.
|
||||
|
||||
See LICENSE for the full BSD-2-Clause license text.
|
||||
|
||||
Note that:
|
||||
|
||||
- Monocypher is Copyright Loup Vaillant and released under CC0
|
||||
1.0 Universal, see monocypher/LICENSE.
|
||||
- blake2s is Copyright Markku-Juhani O. Saarinen and released under CC0
|
||||
1.0 Universal, see blake2s/LICENSE.
|
147
hw/application_fpga/tkey-libs/README.md
Normal file
147
hw/application_fpga/tkey-libs/README.md
Normal file
@ -0,0 +1,147 @@
|
||||
[](https://github.com/tillitis/tkey-libs/actions/workflows/ci.yaml)
|
||||
|
||||
# Device libraries for the Tillitis TKey
|
||||
|
||||
- C runtime: libcrt0.
|
||||
- Common C functions including protocol calls: libcommon.
|
||||
- Cryptographic functions: libmonocypher. Based on
|
||||
[Monocypher](https://github.com/LoupVaillant/Monocypher) version
|
||||
4.0.2
|
||||
- BLAKE2s hash function: libblake2s.
|
||||
|
||||
Release notes in [RELEASE.md](RELEASE.md).
|
||||
|
||||
## Licenses
|
||||
|
||||
Unless otherwise noted, the project sources are copyright Tillitis AB,
|
||||
licensed under the terms and conditions of the "BSD-2-Clause" license.
|
||||
See [LICENSE](LICENSE) for the full license text.
|
||||
|
||||
Until Oct 8, 2024, the license was GPL-2.0 Only.
|
||||
|
||||
External source code we have imported are isolated in their own
|
||||
directories. They may be released under other licenses. This is noted
|
||||
with a similar `LICENSE` file in every directory containing imported
|
||||
sources.
|
||||
|
||||
Imported sources:
|
||||
|
||||
- [Monocypher](https://github.com/LoupVaillant/Monocypher) (BSD-2) by
|
||||
Loup Vaillant.
|
||||
|
||||
- blake2s (CC-0), originally based on the reference implementation in
|
||||
[RFC 7693](https://www.rfc-editor.org/rfc/rfc7693.html) written by
|
||||
Markku-Juhani O. Saarinen ([original
|
||||
repository](https://github.com/mjosaarinen/blake2_mjosref). Imported
|
||||
from [Joachim Strömbergson's
|
||||
fork](https://github.com/secworks/blake2s/) used as a model for a
|
||||
hardware implementation.
|
||||
|
||||
### SPDX tags
|
||||
|
||||
The project uses single-line references to Unique License Identifiers
|
||||
as defined by the Linux Foundation's [SPDX project](https://spdx.org/)
|
||||
on its own source files, but not necessarily imported files. The line
|
||||
in each individual source file identifies the license applicable to
|
||||
that file.
|
||||
|
||||
The current set of valid, predefined SPDX identifiers can be found on
|
||||
the SPDX License List at:
|
||||
|
||||
https://spdx.org/licenses/
|
||||
|
||||
We attempt to follow the [REUSE
|
||||
specification](https://reuse.software/).
|
||||
|
||||
## Hardware support
|
||||
|
||||
### Bellatrix and earlier
|
||||
|
||||
Please note that:
|
||||
|
||||
- For reading, only use the blocking `uart_read()`.
|
||||
|
||||
- Only `IO_UART` and `IO_QEMU` destinations are useful for writing as
|
||||
in `write(IO_UART, ...)`, `puts(IO_UART, ...)`, and so on.
|
||||
|
||||
- Defining `QEMU_DEBUG` works with all the `debug_*` functions, but
|
||||
`TKEY_DEBUG` does not.
|
||||
|
||||
## Building
|
||||
|
||||
In order to build, you must have the `make`, `clang`, `llvm`, and
|
||||
`lld` packages installed.
|
||||
|
||||
Version 15 or higher of LLVM/Clang is necessary for the RV32IC\_Zmmul
|
||||
architecture we are using. For more detailed information on the
|
||||
supported build and development environment, please refer to the
|
||||
[Developer Handbook](https://dev.tillitis.se/).
|
||||
## Building using Podman
|
||||
|
||||
You can also build the libraries with our OCI image
|
||||
`ghcr.io/tillitis/tkey-builder`.
|
||||
|
||||
The easiest way to build this is if you have `make` installed:
|
||||
|
||||
```
|
||||
make podman
|
||||
```
|
||||
|
||||
You can also specify a different image by using
|
||||
`IMAGE=localhost/tkey-builder-local`.
|
||||
|
||||
Or use Podman directly:
|
||||
|
||||
```
|
||||
podman run --rm --mount type=bind,source=.,target=/src -w /src -it ghcr.io/tillitis/tkey-builder:4 make -j
|
||||
```
|
||||
|
||||
## Minimal application build
|
||||
|
||||
You will typically need to link at least the `libcrt0` C runtime
|
||||
otherwise your program won't even reach `main()`.
|
||||
|
||||
We provide a linker script in `apps.lds` which shows the linker the
|
||||
memory layout.
|
||||
|
||||
Minimal compilation would look something like:
|
||||
|
||||
```
|
||||
clang -target riscv32-unknown-none-elf -march=rv32iczmmul -mabi=ilp32 \
|
||||
-mcmodel=medany -static -std=gnu99 -O2 -ffast-math -fno-common \
|
||||
-fno-builtin-printf -fno-builtin-putchar -nostdlib -mno-relax -flto \
|
||||
-Wall -Werror=implicit-function-declaration \
|
||||
-I ../tkey-libs/include \
|
||||
-I ../tkey-libs -c -o foo.o foo.c
|
||||
|
||||
clang -target riscv32-unknown-none-elf -march=rv32iczmmul -mabi=ilp32 \
|
||||
-mcmodel=medany -static -ffast-math -fno-common -nostdlib \
|
||||
-T ../tkey-libs/app.lds \
|
||||
-L ../tkey-libs -lcrt0 \
|
||||
-I ../tkey-libs -o foo.elf foo.o
|
||||
|
||||
```
|
||||
|
||||
## Makefile example
|
||||
|
||||
See `example-app/Makefile` for an example Makefile for a simple device
|
||||
application.
|
||||
|
||||
## Debug output
|
||||
|
||||
If you want to have debug prints in your program you can use the
|
||||
`debug_putchar()`, `debug_puts()`, `debug_putinthex()`,
|
||||
`debug_hexdump()` and friends. See `include/tkey/debug.h` for list of
|
||||
functions.
|
||||
|
||||
These functions will be turned on if you define either of these when
|
||||
compiling your program and linking with `libcommon`:
|
||||
|
||||
- `QEMU_DEBUG`: Uses the special debug port only available in qemu to
|
||||
print to the qemu console.
|
||||
- `TKEY_DEBUG`: Uses the extra HID device.
|
||||
|
||||
Note that if you use `TKEY_DEBUG` you *must* have something listening
|
||||
on the corresponding HID device. It's usually the last HID device
|
||||
created. On Linux, for instance, this means the last reported hidraw
|
||||
in `dmesg` is the one you should do `cat /dev/hidrawX` on.
|
191
hw/application_fpga/tkey-libs/RELEASE.md
Normal file
191
hw/application_fpga/tkey-libs/RELEASE.md
Normal file
@ -0,0 +1,191 @@
|
||||
# Release notes
|
||||
|
||||
## Upcoming release
|
||||
|
||||
- NOTE WELL! Rewritten I/O functions with new signatures and
|
||||
semantics!
|
||||
- `blake2s()` with new signature.
|
||||
|
||||
### BLAKE2s hash function
|
||||
|
||||
The `blake2s()` function no longer call the firmware.
|
||||
|
||||
- The `blake2s.h` header file has moved to `blake2s/blake2s.h`.
|
||||
|
||||
- The `blake2s()` hash function has changed signature. It's now defined
|
||||
as:
|
||||
|
||||
```
|
||||
// All-in-one convenience function.
|
||||
int blake2s(void *out, size_t outlen, // return buffer for digest
|
||||
const void *key, size_t keylen, // optional secret key
|
||||
const void *in, size_t inlen); // data to be hashed
|
||||
|
||||
```
|
||||
|
||||
- The component functions `blake2s_init()`, `blake2s_update()`, and
|
||||
`blake2s_final()` are now available.
|
||||
|
||||
### I/O
|
||||
|
||||
The Castor TKey hardware supports more USB endpoints:
|
||||
|
||||
- CDC - the same thing as older versions.
|
||||
- FIDO security token, for FIDO-like apps.
|
||||
- CCID, smart card interface.
|
||||
- DEBUG, a HID debug port.
|
||||
|
||||
The communication is still over a single UART. To differ between the
|
||||
endpoints we use an internal USB Mode Protocol between programs
|
||||
running on the PicoRV32 and the CH552 USB Controller.
|
||||
|
||||
The I/O functions has changed accordingly. Please use:
|
||||
|
||||
- `readselect()` with appropriate bitmask (e.g. `IO_CDC|IO_FIDO`) to
|
||||
see if there's anything to read in the endpoints you are interested
|
||||
in. Data from endpoints not mentioned in the bitmask will be
|
||||
discarded.
|
||||
|
||||
- `read()` is now non-blocking and returns the number of bytes read
|
||||
from the endpoint you specify, because more might not be available
|
||||
yet.
|
||||
|
||||
- `write()` now takes an endpoint destination.
|
||||
|
||||
- We also introduce generic `putchar()`, `puts()`, `puthex()`,
|
||||
`putinthex()`, and `hexdump()` functions that take a destination
|
||||
argument.
|
||||
|
||||
We recommend you use only these functions for I/O on Castor and going
|
||||
forward.
|
||||
|
||||
For compatibility to develop device apps for the Bellatrix platform
|
||||
and earlier, use the low-level, blocking function `uart_read()` for
|
||||
reads and *only* the `IO_UART` and `IO_QEMU` destinations for output
|
||||
functions like `write()`, `puts()`.
|
||||
|
||||
### Debug prints
|
||||
|
||||
The optionally built debug prints have changed. You now use
|
||||
`debug_puts()` et cetera instead of `qemu_*()`.
|
||||
|
||||
You define the debug output endpoint when you compile your program by
|
||||
including `debug.h` and defining `QEMU_DEBUG` for the qemu debug port
|
||||
or `TKEY_DEBUG` for output on the DEBUG HID endpoint. If you don't
|
||||
define either, they won't appear in your code.
|
||||
|
||||
Similiarly, `assert()` now also follows `QEMU_DEBUG` or `TKEY_DEBUG`,
|
||||
and prints something on either before halting the CPU.
|
||||
|
||||
Note that on the Bellatrix platform only `QEMU_DEBUG` works.
|
||||
|
||||
## v0.1.2
|
||||
|
||||
From now on tkey-libs is licensed under the BSD-2-Clause license,
|
||||
moving from the previous GPLv2-only.
|
||||
|
||||
Note: There is a possibility that this update may impact the generated
|
||||
CDI for an app that relies on this library. It is recommended to
|
||||
always check for potential CDI changes for each specific app with
|
||||
every update. If the generated CDI does change, and if applicable, it
|
||||
should be clearly communicated to end users to prevent unintentional
|
||||
changes to their identity.
|
||||
|
||||
Changes:
|
||||
- New license, BSD-2-Clause
|
||||
- Reuse compliant, see https://reuse.software/
|
||||
- Fix row alignment in qemu_hexdump
|
||||
- Update memory map, tk1_mem.h, from canonical tillitis-key1 repo
|
||||
- Added make target for creating compile_commands.json for clangd
|
||||
- Added missing include in touch.h
|
||||
|
||||
Full changelog:
|
||||
[v0.1.1...v0.1.2](https://github.com/tillitis/tkey-libs/compare/v0.1.1...v0.1.2)
|
||||
|
||||
## v0.1.1
|
||||
|
||||
This is a minor release correcting a mistake and syncing with the
|
||||
latest HW release, TK1-24.03.
|
||||
|
||||
|
||||
Note: There is a possibility that this update may impact the generated
|
||||
CDI for an app that relies on this library. It is recommended to
|
||||
always check for potential CDI changes for each specific app with
|
||||
every update. If the generated CDI does change, and if applicable, it
|
||||
should be clearly communicated to end users to prevent unintentional
|
||||
changes to their identity.
|
||||
|
||||
Changes:
|
||||
- Update memory map, tk1_mem.h, to match the latest TK1-24.03 release.
|
||||
- Default to tkey-builder:4 for the podman target
|
||||
- Default to have QEMU debug enabled in tkey-libs. Mistakenly removed
|
||||
in previous release.
|
||||
- Revise readme accordingly
|
||||
|
||||
Full changelog:
|
||||
[v0.1.0...v0.1.1](https://github.com/tillitis/tkey-libs/compare/v0.1.0...v0.1.1)
|
||||
|
||||
## v0.1.0
|
||||
|
||||
This release contains some changes that forces applications that use
|
||||
tkey-libs to be updated to work with this release.
|
||||
|
||||
Note: It is highly likely that this update will affect the CDI of the
|
||||
TKey. It is advised to always verify this for each specific app, for
|
||||
every update. If the CDI changes, and it is applicable, it should be
|
||||
stated clearly to end users to avoid unknowingly changing the TKey
|
||||
identity.
|
||||
|
||||
Breaking changes:
|
||||
- Check destination buffer's size for read(). To prevent writing
|
||||
outside of destination buffer.
|
||||
- Renaming LED-functions to follow led_*().
|
||||
|
||||
Changes:
|
||||
- New function, secure_wipe(), to clean memory of secret data.
|
||||
- New function, touch_wait(). Waits for a touch by the user, with
|
||||
selectable timeout.
|
||||
- New function, led_get(). Get the value of the applied LED color.
|
||||
- Upgraded Monocypher to 4.0.2.
|
||||
- Add variable AR in Makefile to enabling passing llvm-ar from command
|
||||
line.
|
||||
- Update example app to use led.h.
|
||||
- Don't have QEMU debug enabled by default.
|
||||
- Minor tweaks and formatting.
|
||||
|
||||
Full changelog:
|
||||
[v0.0.2...v0.1.0](https://github.com/tillitis/tkey-libs/compare/v0.0.2...v0.1.0)
|
||||
|
||||
## v0.0.2
|
||||
|
||||
This release contains some changes that forces applications that use
|
||||
tkey-libs to be updated to work with this release.
|
||||
|
||||
Breaking changes:
|
||||
- Introducing include hierarchy to make it less generic, e.g.,
|
||||
`#include <tkey/led.h>`.
|
||||
- Use stdint.h/stddef.h infavor of types.h.
|
||||
- Library .a files built on top level to simplify inclusion.
|
||||
- Upgraded Monocypher to 4.0.1.
|
||||
- QEMU debug behaviour changed, instead of defining `NODEBUG` to
|
||||
disable debug, one has to enable it by defining `QEMU_DEBUG`.
|
||||
|
||||
Changes:
|
||||
- Introduce functions to control the LED, led.h and led.c.
|
||||
- New function, assert() to make an illegal instruction and forcing
|
||||
the CPU to halt.
|
||||
- Add functions memcpy_s(), wordcpy_s(), memeq() from firmware
|
||||
- Adding `const` to MMIO variables and qemu_* functions.
|
||||
- Minor tweaks, clean up and bugfixes.
|
||||
|
||||
Full changelog:
|
||||
[v0.0.1...v0.0.2](https://github.com/tillitis/tkey-libs/compare/v0.0.1...v0.0.2)
|
||||
|
||||
|
||||
## v0.0.1
|
||||
|
||||
Just ripped from
|
||||
|
||||
https://github.com/tillitis/tillitis-key1-apps
|
||||
|
||||
No semantic changes.
|
39
hw/application_fpga/tkey-libs/REUSE.toml
Normal file
39
hw/application_fpga/tkey-libs/REUSE.toml
Normal file
@ -0,0 +1,39 @@
|
||||
# SPDX-FileCopyrightText: 2024 Tillitis AB <tillitis.se>
|
||||
# SPDX-License-Identifier: BSD-2-Clause
|
||||
version = 1
|
||||
|
||||
[[annotations]]
|
||||
path = ".github/workflows/*"
|
||||
SPDX-FileCopyrightText = "2022 Tillitis AB <tillitis.se>"
|
||||
SPDX-License-Identifier = "BSD-2-Clause"
|
||||
|
||||
[[annotations]]
|
||||
path = [
|
||||
".clang-format",
|
||||
".editorconfig",
|
||||
".gitignore",
|
||||
"example-app/Makefile",
|
||||
"monocypher/README.md",
|
||||
"Makefile",
|
||||
"README-DIST.txt",
|
||||
"README.md",
|
||||
"RELEASE.md"
|
||||
]
|
||||
SPDX-FileCopyrightText = "2022 Tillitis AB <tillitis.se>"
|
||||
SPDX-License-Identifier = "BSD-2-Clause"
|
||||
|
||||
[[annotations]]
|
||||
path = [
|
||||
"blake2s/*",
|
||||
]
|
||||
|
||||
SPDX-FileCopyrightText = "Markku-Juhani O. Saarinen"
|
||||
SPDX-License-Identifier = "CC0-1.0"
|
||||
|
||||
[[annotations]]
|
||||
path = [
|
||||
"blake2s/Makefile",
|
||||
]
|
||||
|
||||
SPDX-FileCopyrightText = "2014 Secworks Sweden AB"
|
||||
SPDX-License-Identifier = "BSD-2-Clause"
|
64
hw/application_fpga/tkey-libs/app.lds
Normal file
64
hw/application_fpga/tkey-libs/app.lds
Normal file
@ -0,0 +1,64 @@
|
||||
/*
|
||||
* SPDX-FileCopyrightText: 2022 Tillitis AB <tillitis.se>
|
||||
* SPDX-License-Identifier: BSD-2-Clause
|
||||
*/
|
||||
|
||||
OUTPUT_ARCH( "riscv" )
|
||||
ENTRY(_start)
|
||||
|
||||
MEMORY
|
||||
{
|
||||
RAM (rwx) : ORIGIN = 0x40000000, LENGTH = 0x20000 /* 128 KB */
|
||||
}
|
||||
|
||||
SECTIONS
|
||||
{
|
||||
.text.init :
|
||||
{
|
||||
*(.text.init)
|
||||
} >RAM
|
||||
|
||||
.text :
|
||||
{
|
||||
. = ALIGN(4);
|
||||
*(.text) /* .text sections (code) */
|
||||
*(.text*) /* .text* sections (code) */
|
||||
*(.rodata) /* .rodata sections (constants, strings, etc.) */
|
||||
*(.rodata*) /* .rodata* sections (constants, strings, etc.) */
|
||||
*(.srodata) /* .rodata sections (constants, strings, etc.) */
|
||||
*(.srodata*) /* .rodata* sections (constants, strings, etc.) */
|
||||
. = ALIGN(4);
|
||||
_etext = .;
|
||||
_sidata = _etext;
|
||||
} >RAM
|
||||
|
||||
.data : AT (_etext)
|
||||
{
|
||||
. = ALIGN(4);
|
||||
_sdata = .;
|
||||
. = ALIGN(4);
|
||||
*(.data) /* .data sections */
|
||||
*(.data*) /* .data* sections */
|
||||
*(.sdata) /* .sdata sections */
|
||||
*(.sdata*) /* .sdata* sections */
|
||||
. = ALIGN(4);
|
||||
_edata = .;
|
||||
} >RAM
|
||||
|
||||
/* Uninitialized data section */
|
||||
.bss :
|
||||
{
|
||||
. = ALIGN(4);
|
||||
_sbss = .;
|
||||
*(.bss)
|
||||
*(.bss*)
|
||||
*(.sbss)
|
||||
*(.sbss*)
|
||||
*(COMMON)
|
||||
|
||||
. = ALIGN(4);
|
||||
_ebss = .;
|
||||
} >RAM
|
||||
|
||||
/* libcrt0/crt0.S inits stack to start just below end of RAM */
|
||||
}
|
116
hw/application_fpga/tkey-libs/blake2s/LICENSE
Normal file
116
hw/application_fpga/tkey-libs/blake2s/LICENSE
Normal file
@ -0,0 +1,116 @@
|
||||
CC0 1.0 Universal
|
||||
|
||||
Statement of Purpose
|
||||
|
||||
The laws of most jurisdictions throughout the world automatically confer
|
||||
exclusive Copyright and Related Rights (defined below) upon the creator and
|
||||
subsequent owner(s) (each and all, an "owner") of an original work of
|
||||
authorship and/or a database (each, a "Work").
|
||||
|
||||
Certain owners wish to permanently relinquish those rights to a Work for the
|
||||
purpose of contributing to a commons of creative, cultural and scientific
|
||||
works ("Commons") that the public can reliably and without fear of later
|
||||
claims of infringement build upon, modify, incorporate in other works, reuse
|
||||
and redistribute as freely as possible in any form whatsoever and for any
|
||||
purposes, including without limitation commercial purposes. These owners may
|
||||
contribute to the Commons to promote the ideal of a free culture and the
|
||||
further production of creative, cultural and scientific works, or to gain
|
||||
reputation or greater distribution for their Work in part through the use and
|
||||
efforts of others.
|
||||
|
||||
For these and/or other purposes and motivations, and without any expectation
|
||||
of additional consideration or compensation, the person associating CC0 with a
|
||||
Work (the "Affirmer"), to the extent that he or she is an owner of Copyright
|
||||
and Related Rights in the Work, voluntarily elects to apply CC0 to the Work
|
||||
and publicly distribute the Work under its terms, with knowledge of his or her
|
||||
Copyright and Related Rights in the Work and the meaning and intended legal
|
||||
effect of CC0 on those rights.
|
||||
|
||||
1. Copyright and Related Rights. A Work made available under CC0 may be
|
||||
protected by copyright and related or neighboring rights ("Copyright and
|
||||
Related Rights"). Copyright and Related Rights include, but are not limited
|
||||
to, the following:
|
||||
|
||||
i. the right to reproduce, adapt, distribute, perform, display, communicate,
|
||||
and translate a Work;
|
||||
|
||||
ii. moral rights retained by the original author(s) and/or performer(s);
|
||||
|
||||
iii. publicity and privacy rights pertaining to a person's image or likeness
|
||||
depicted in a Work;
|
||||
|
||||
iv. rights protecting against unfair competition in regards to a Work,
|
||||
subject to the limitations in paragraph 4(a), below;
|
||||
|
||||
v. rights protecting the extraction, dissemination, use and reuse of data in
|
||||
a Work;
|
||||
|
||||
vi. database rights (such as those arising under Directive 96/9/EC of the
|
||||
European Parliament and of the Council of 11 March 1996 on the legal
|
||||
protection of databases, and under any national implementation thereof,
|
||||
including any amended or successor version of such directive); and
|
||||
|
||||
vii. other similar, equivalent or corresponding rights throughout the world
|
||||
based on applicable law or treaty, and any national implementations thereof.
|
||||
|
||||
2. Waiver. To the greatest extent permitted by, but not in contravention of,
|
||||
applicable law, Affirmer hereby overtly, fully, permanently, irrevocably and
|
||||
unconditionally waives, abandons, and surrenders all of Affirmer's Copyright
|
||||
and Related Rights and associated claims and causes of action, whether now
|
||||
known or unknown (including existing as well as future claims and causes of
|
||||
action), in the Work (i) in all territories worldwide, (ii) for the maximum
|
||||
duration provided by applicable law or treaty (including future time
|
||||
extensions), (iii) in any current or future medium and for any number of
|
||||
copies, and (iv) for any purpose whatsoever, including without limitation
|
||||
commercial, advertising or promotional purposes (the "Waiver"). Affirmer makes
|
||||
the Waiver for the benefit of each member of the public at large and to the
|
||||
detriment of Affirmer's heirs and successors, fully intending that such Waiver
|
||||
shall not be subject to revocation, rescission, cancellation, termination, or
|
||||
any other legal or equitable action to disrupt the quiet enjoyment of the Work
|
||||
by the public as contemplated by Affirmer's express Statement of Purpose.
|
||||
|
||||
3. Public License Fallback. Should any part of the Waiver for any reason be
|
||||
judged legally invalid or ineffective under applicable law, then the Waiver
|
||||
shall be preserved to the maximum extent permitted taking into account
|
||||
Affirmer's express Statement of Purpose. In addition, to the extent the Waiver
|
||||
is so judged Affirmer hereby grants to each affected person a royalty-free,
|
||||
non transferable, non sublicensable, non exclusive, irrevocable and
|
||||
unconditional license to exercise Affirmer's Copyright and Related Rights in
|
||||
the Work (i) in all territories worldwide, (ii) for the maximum duration
|
||||
provided by applicable law or treaty (including future time extensions), (iii)
|
||||
in any current or future medium and for any number of copies, and (iv) for any
|
||||
purpose whatsoever, including without limitation commercial, advertising or
|
||||
promotional purposes (the "License"). The License shall be deemed effective as
|
||||
of the date CC0 was applied by Affirmer to the Work. Should any part of the
|
||||
License for any reason be judged legally invalid or ineffective under
|
||||
applicable law, such partial invalidity or ineffectiveness shall not
|
||||
invalidate the remainder of the License, and in such case Affirmer hereby
|
||||
affirms that he or she will not (i) exercise any of his or her remaining
|
||||
Copyright and Related Rights in the Work or (ii) assert any associated claims
|
||||
and causes of action with respect to the Work, in either case contrary to
|
||||
Affirmer's express Statement of Purpose.
|
||||
|
||||
4. Limitations and Disclaimers.
|
||||
|
||||
a. No trademark or patent rights held by Affirmer are waived, abandoned,
|
||||
surrendered, licensed or otherwise affected by this document.
|
||||
|
||||
b. Affirmer offers the Work as-is and makes no representations or warranties
|
||||
of any kind concerning the Work, express, implied, statutory or otherwise,
|
||||
including without limitation warranties of title, merchantability, fitness
|
||||
for a particular purpose, non infringement, or the absence of latent or
|
||||
other defects, accuracy, or the present or absence of errors, whether or not
|
||||
discoverable, all to the greatest extent permissible under applicable law.
|
||||
|
||||
c. Affirmer disclaims responsibility for clearing rights of other persons
|
||||
that may apply to the Work or any use thereof, including without limitation
|
||||
any person's Copyright and Related Rights in the Work. Further, Affirmer
|
||||
disclaims responsibility for obtaining any necessary consents, permissions
|
||||
or other rights required for any use of the Work.
|
||||
|
||||
d. Affirmer understands and acknowledges that Creative Commons is not a
|
||||
party to this document and has no duty or obligation with respect to this
|
||||
CC0 or use of the Work.
|
||||
|
||||
For more information, please see
|
||||
<http://creativecommons.org/publicdomain/zero/1.0/>
|
52
hw/application_fpga/tkey-libs/blake2s/Makefile
Normal file
52
hw/application_fpga/tkey-libs/blake2s/Makefile
Normal file
@ -0,0 +1,52 @@
|
||||
#===================================================================
|
||||
#
|
||||
# Makefile
|
||||
# --------
|
||||
# Makefile for building the blake2s model.
|
||||
#
|
||||
#
|
||||
# Author: Joachim Strombergson
|
||||
# Copyright (c) 2014, Secworks Sweden AB
|
||||
# All rights reserved.
|
||||
#
|
||||
# Redistribution and use in source and binary forms, with or
|
||||
# without modification, are permitted provided that the following
|
||||
# conditions are met:
|
||||
#
|
||||
# 1. Redistributions of source code must retain the above copyright
|
||||
# notice, this list of conditions and the following disclaimer.
|
||||
#
|
||||
# 2. Redistributions in binary form must reproduce the above copyright
|
||||
# notice, this list of conditions and the following disclaimer in
|
||||
# the documentation and/or other materials provided with the
|
||||
# distribution.
|
||||
#
|
||||
# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
|
||||
# "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
|
||||
# LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
|
||||
# FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE
|
||||
# COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
|
||||
# INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
|
||||
# BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
|
||||
# LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
|
||||
# CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT,
|
||||
# STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
|
||||
# ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF
|
||||
# ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
#
|
||||
#===================================================================
|
||||
|
||||
SRC = blake2s_test.c blake2s.c
|
||||
INC = blake2s.h
|
||||
|
||||
CC = clang
|
||||
CC_FLAGS = -Wall
|
||||
|
||||
blake2s_test: $(SRC) $(INC)
|
||||
$(CC) $(CC_FLAGS) -o $@ $(SRC) -I $(INC)
|
||||
|
||||
|
||||
clean:
|
||||
rm -f ./blake2s_test
|
||||
rm -f *.log
|
||||
rm -f *.txt
|
354
hw/application_fpga/tkey-libs/blake2s/blake2s.c
Normal file
354
hw/application_fpga/tkey-libs/blake2s/blake2s.c
Normal file
@ -0,0 +1,354 @@
|
||||
//======================================================================
|
||||
//
|
||||
// blake2s.c
|
||||
// ---------
|
||||
//
|
||||
// A simple BLAKE2s reference implementation.
|
||||
//
|
||||
// See LICENSE for license terms.
|
||||
// See README.md in the repo root for info about source code origin.
|
||||
//======================================================================
|
||||
|
||||
#include <stdint.h>
|
||||
#include "blake2s.h"
|
||||
|
||||
#define VERBOSE 0
|
||||
#define SHOW_V 0
|
||||
#define SHOW_M_WORDS 0
|
||||
|
||||
#if VERBOSE || SHOW_V || SHOW_M_WORDS
|
||||
#include <stdio.h>
|
||||
#endif
|
||||
|
||||
// Cyclic right rotation.
|
||||
#ifndef ROTR32
|
||||
#define ROTR32(x, y) (((x) >> (y)) ^ ((x) << (32 - (y))))
|
||||
#endif
|
||||
|
||||
|
||||
// Little-endian byte access.
|
||||
#define B2S_GET32(p) \
|
||||
(((uint32_t) ((uint8_t *) (p))[0]) ^ \
|
||||
(((uint32_t) ((uint8_t *) (p))[1]) << 8) ^ \
|
||||
(((uint32_t) ((uint8_t *) (p))[2]) << 16) ^ \
|
||||
(((uint32_t) ((uint8_t *) (p))[3]) << 24))
|
||||
|
||||
|
||||
// Initialization Vector.
|
||||
static const uint32_t blake2s_iv[8] = {
|
||||
0x6a09e667, 0xbb67ae85, 0x3c6ef372, 0xa54ff53a,
|
||||
0x510e527f, 0x9b05688c, 0x1f83d9ab, 0x5be0cd19
|
||||
};
|
||||
|
||||
|
||||
#if VERBOSE || SHOW_V
|
||||
//------------------------------------------------------------------
|
||||
//------------------------------------------------------------------
|
||||
void print_v(uint32_t *v) {
|
||||
printf("0x%08x, 0x%08x, 0x%08x, 0x%08x\n", v[0], v[1], v[2], v[3]);
|
||||
printf("0x%08x, 0x%08x, 0x%08x, 0x%08x\n", v[4], v[5], v[6], v[7]);
|
||||
printf("0x%08x, 0x%08x, 0x%08x, 0x%08x\n", v[8], v[9], v[10], v[11]);
|
||||
printf("0x%08x, 0x%08x, 0x%08x, 0x%08x\n", v[12], v[13], v[14], v[15]);
|
||||
printf("\n");
|
||||
}
|
||||
|
||||
|
||||
//------------------------------------------------------------------
|
||||
// print_ctx()
|
||||
// Print the contents of the context data structure.
|
||||
//------------------------------------------------------------------
|
||||
void print_ctx(blake2s_ctx *ctx) {
|
||||
printf("Chained state (h):\n");
|
||||
printf("0x%08x, 0x%08x, 0x%08x, 0x%08x, ",
|
||||
ctx->h[0], ctx->h[1], ctx->h[2], ctx->h[3]);
|
||||
printf("0x%08x, 0x%08x, 0x%08x, 0x%08x",
|
||||
ctx->h[4], ctx->h[5], ctx->h[6], ctx->h[7]);
|
||||
printf("\n");
|
||||
|
||||
printf("Byte counter (t):\n");
|
||||
printf("0x%08x, 0x%08x", ctx->t[0], ctx->t[1]);
|
||||
printf("\n");
|
||||
|
||||
printf("\n");
|
||||
}
|
||||
|
||||
#endif
|
||||
|
||||
//------------------------------------------------------------------
|
||||
// B2S_G macro redefined as a G function.
|
||||
// Allows us to output intermediate values for debugging.
|
||||
//------------------------------------------------------------------
|
||||
void G(uint32_t *v, uint32_t a, uint32_t b, uint32_t c, uint32_t d, uint32_t x, uint32_t y) {
|
||||
#if VERBOSE
|
||||
printf("G started.\n");
|
||||
#endif
|
||||
|
||||
#if SHOW_V
|
||||
printf("v before processing:\n");
|
||||
print_v(&v[0]);
|
||||
#endif
|
||||
|
||||
#if SHOW_M_WORDS
|
||||
printf("x: 0x%08x, y: 0x%08x\n", x, y);
|
||||
#endif
|
||||
|
||||
v[a] = v[a] + v[b] + x;
|
||||
v[d] = ROTR32(v[d] ^ v[a], 16);
|
||||
v[c] = v[c] + v[d];
|
||||
v[b] = ROTR32(v[b] ^ v[c], 12);
|
||||
v[a] = v[a] + v[b] + y;
|
||||
v[d] = ROTR32(v[d] ^ v[a], 8);
|
||||
v[c] = v[c] + v[d];
|
||||
v[b] = ROTR32(v[b] ^ v[c], 7);
|
||||
|
||||
#if SHOW_V
|
||||
printf("v after processing:\n");
|
||||
print_v(&v[0]);
|
||||
#endif
|
||||
|
||||
#if VERBOSE
|
||||
printf("G completed.\n\n");
|
||||
#endif
|
||||
}
|
||||
|
||||
|
||||
//------------------------------------------------------------------
|
||||
// Compression function. "last" flag indicates last block.
|
||||
//------------------------------------------------------------------
|
||||
static void blake2s_compress(blake2s_ctx *ctx, int last)
|
||||
{
|
||||
const uint8_t sigma[10][16] = {
|
||||
{0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15},
|
||||
{14, 10, 4, 8, 9, 15, 13, 6, 1, 12, 0, 2, 11, 7, 5, 3},
|
||||
{11, 8, 12, 0, 5, 2, 15, 13, 10, 14, 3, 6, 7, 1, 9, 4},
|
||||
{7, 9, 3, 1, 13, 12, 11, 14, 2, 6, 5, 10, 4, 0, 15, 8},
|
||||
{9, 0, 5, 7, 2, 4, 10, 15, 14, 1, 11, 12, 6, 8, 3, 13},
|
||||
{2, 12, 6, 10, 0, 11, 8, 3, 4, 13, 7, 5, 15, 14, 1, 9},
|
||||
{12, 5, 1, 15, 14, 13, 4, 10, 0, 7, 6, 3, 9, 2, 8, 11},
|
||||
{13, 11, 7, 14, 12, 1, 3, 9, 5, 0, 15, 4, 8, 6, 2, 10},
|
||||
{6, 15, 14, 9, 11, 3, 0, 8, 12, 2, 13, 7, 1, 4, 10, 5},
|
||||
{10, 2, 8, 4, 7, 6, 1, 5, 15, 11, 9, 14, 3, 12, 13, 0}
|
||||
};
|
||||
|
||||
int i;
|
||||
uint32_t v[16], m[16];
|
||||
|
||||
#if VERBOSE
|
||||
printf("blake2s_compress started.\n");
|
||||
#endif
|
||||
|
||||
// init work variables
|
||||
for (i = 0; i < 8; i++) {
|
||||
v[i] = ctx->h[i];
|
||||
v[i + 8] = blake2s_iv[i];
|
||||
}
|
||||
|
||||
// low 32 bits of offset
|
||||
// high 32 bits
|
||||
#if VERBOSE
|
||||
printf("t[0]: 0x%08x, t[1]: 0x%08x\n", ctx->t[0], ctx->t[1]);
|
||||
#endif
|
||||
v[12] ^= ctx->t[0];
|
||||
v[13] ^= ctx->t[1];
|
||||
|
||||
// last block flag set ?
|
||||
if (last) {
|
||||
v[14] = ~v[14];
|
||||
}
|
||||
|
||||
// get little-endian words
|
||||
for (i = 0; i < 16; i++) {
|
||||
m[i] = B2S_GET32(&ctx->b[4 * i]);
|
||||
}
|
||||
|
||||
#if VERBOSE
|
||||
printf("v before G processing:\n");
|
||||
print_v(&v[0]);
|
||||
#endif
|
||||
|
||||
// Ten rounds of the G function applied on rows, diagonal.
|
||||
for (i = 0; i < 10; i++) {
|
||||
#if VERBOSE
|
||||
printf("Round %02d:\n", (i + 1));
|
||||
printf("Row processing started.\n");
|
||||
#endif
|
||||
|
||||
G(&v[0], 0, 4, 8, 12, m[sigma[i][ 0]], m[sigma[i][ 1]]);
|
||||
G(&v[0], 1, 5, 9, 13, m[sigma[i][ 2]], m[sigma[i][ 3]]);
|
||||
G(&v[0], 2, 6, 10, 14, m[sigma[i][ 4]], m[sigma[i][ 5]]);
|
||||
G(&v[0], 3, 7, 11, 15, m[sigma[i][ 6]], m[sigma[i][ 7]]);
|
||||
|
||||
#if VERBOSE
|
||||
printf("Row processing completed.\n");
|
||||
printf("Diagonal processing started.\n");
|
||||
#endif
|
||||
|
||||
G(&v[0], 0, 5, 10, 15, m[sigma[i][ 8]], m[sigma[i][ 9]]);
|
||||
G(&v[0], 1, 6, 11, 12, m[sigma[i][10]], m[sigma[i][11]]);
|
||||
G(&v[0], 2, 7, 8, 13, m[sigma[i][12]], m[sigma[i][13]]);
|
||||
G(&v[0], 3, 4, 9, 14, m[sigma[i][14]], m[sigma[i][15]]);
|
||||
|
||||
#if VERBOSE
|
||||
printf("Diagonal processing completed.\n");
|
||||
printf("\n");
|
||||
#endif
|
||||
}
|
||||
|
||||
#if VERBOSE
|
||||
printf("v after G processing:\n");
|
||||
print_v(&v[0]);
|
||||
#endif
|
||||
|
||||
// Update the hash state.
|
||||
for (i = 0; i < 8; ++i) {
|
||||
ctx->h[i] ^= v[i] ^ v[i + 8];
|
||||
}
|
||||
|
||||
#if VERBOSE
|
||||
printf("blake2s_compress completed.\n");
|
||||
#endif
|
||||
}
|
||||
|
||||
|
||||
//------------------------------------------------------------------
|
||||
// Initialize the hashing context "ctx" with optional key "key".
|
||||
// 1 <= outlen <= 32 gives the digest size in bytes.
|
||||
// Secret key (also <= 32 bytes) is optional (keylen = 0).
|
||||
//------------------------------------------------------------------
|
||||
int blake2s_init(blake2s_ctx *ctx, size_t outlen,
|
||||
const void *key, size_t keylen) // (keylen=0: no key)
|
||||
{
|
||||
size_t i;
|
||||
|
||||
#if VERBOSE
|
||||
printf("blake2s_init started.\n");
|
||||
printf("Context before blake2s_init processing:\n");
|
||||
print_ctx(ctx);
|
||||
#endif
|
||||
|
||||
if (outlen == 0 || outlen > 32 || keylen > 32)
|
||||
return -1; // illegal parameters
|
||||
|
||||
for (i = 0; i < 8; i++) // state, "param block"
|
||||
ctx->h[i] = blake2s_iv[i];
|
||||
ctx->h[0] ^= 0x01010000 ^ (keylen << 8) ^ outlen;
|
||||
|
||||
ctx->t[0] = 0; // input count low word
|
||||
ctx->t[1] = 0; // input count high word
|
||||
ctx->c = 0; // pointer within buffer
|
||||
ctx->outlen = outlen;
|
||||
|
||||
for (i = keylen; i < 64; i++) // zero input block
|
||||
ctx->b[i] = 0;
|
||||
if (keylen > 0) {
|
||||
blake2s_update(ctx, key, keylen);
|
||||
ctx->c = 64; // at the end
|
||||
}
|
||||
|
||||
#if VERBOSE
|
||||
printf("Context after blake2s_init processing:\n");
|
||||
print_ctx(ctx);
|
||||
printf("blake2s_init completed.\n");
|
||||
#endif
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
//------------------------------------------------------------------
|
||||
// Add "inlen" bytes from "in" into the hash.
|
||||
//------------------------------------------------------------------
|
||||
void blake2s_update(blake2s_ctx *ctx,
|
||||
const void *in, size_t inlen) // data bytes
|
||||
{
|
||||
size_t i;
|
||||
|
||||
#if VERBOSE
|
||||
printf("blake2s_update started.\n");
|
||||
printf("Context before blake2s_update processing:\n");
|
||||
print_ctx(ctx);
|
||||
#endif
|
||||
|
||||
for (i = 0; i < inlen; i++) {
|
||||
if (ctx->c == 64) { // buffer full ?
|
||||
ctx->t[0] += ctx->c; // add counters
|
||||
if (ctx->t[0] < ctx->c) // carry overflow ?
|
||||
ctx->t[1]++; // high word
|
||||
blake2s_compress(ctx, 0); // compress (not last)
|
||||
ctx->c = 0; // counter to zero
|
||||
}
|
||||
ctx->b[ctx->c++] = ((const uint8_t *) in)[i];
|
||||
}
|
||||
|
||||
#if VERBOSE
|
||||
printf("Context after blake2s_update processing:\n");
|
||||
print_ctx(ctx);
|
||||
printf("blake2s_update completed.\n");
|
||||
#endif
|
||||
}
|
||||
|
||||
|
||||
//------------------------------------------------------------------
|
||||
// Generate the message digest (size given in init).
|
||||
// Result placed in "out".
|
||||
//------------------------------------------------------------------
|
||||
void blake2s_final(blake2s_ctx *ctx, void *out)
|
||||
{
|
||||
size_t i;
|
||||
|
||||
#if VERBOSE
|
||||
printf("blake2s_final started.\n");
|
||||
printf("Context before blake2s_final processing:\n");
|
||||
print_ctx(ctx);
|
||||
#endif
|
||||
|
||||
ctx->t[0] += ctx->c; // mark last block offset
|
||||
|
||||
// carry overflow
|
||||
// high word
|
||||
if (ctx->t[0] < ctx->c) {
|
||||
ctx->t[1]++;
|
||||
}
|
||||
|
||||
// fill up with zeros
|
||||
// final block flag = 1
|
||||
while (ctx->c < 64) {
|
||||
ctx->b[ctx->c++] = 0;
|
||||
}
|
||||
blake2s_compress(ctx, 1);
|
||||
|
||||
// little endian convert and store
|
||||
for (i = 0; i < ctx->outlen; i++) {
|
||||
((uint8_t *) out)[i] =
|
||||
(ctx->h[i >> 2] >> (8 * (i & 3))) & 0xFF;
|
||||
}
|
||||
|
||||
#if VERBOSE
|
||||
printf("Context after blake2s_final processing:\n");
|
||||
print_ctx(ctx);
|
||||
printf("blake2s_final completed.\n");
|
||||
#endif
|
||||
}
|
||||
|
||||
|
||||
//------------------------------------------------------------------
|
||||
// Convenience function for all-in-one computation.
|
||||
//------------------------------------------------------------------
|
||||
int blake2s(void *out, size_t outlen,
|
||||
const void *key, size_t keylen,
|
||||
const void *in, size_t inlen)
|
||||
{
|
||||
blake2s_ctx ctx;
|
||||
|
||||
if (blake2s_init(&ctx, outlen, key, keylen))
|
||||
return -1;
|
||||
|
||||
blake2s_update(&ctx, in, inlen);
|
||||
|
||||
blake2s_final(&ctx, out);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
//======================================================================
|
||||
//======================================================================
|
45
hw/application_fpga/tkey-libs/blake2s/blake2s.h
Normal file
45
hw/application_fpga/tkey-libs/blake2s/blake2s.h
Normal file
@ -0,0 +1,45 @@
|
||||
//======================================================================
|
||||
//
|
||||
// blake2s.h
|
||||
// ---------
|
||||
// BLAKE2s Hashing Context and API Prototypes
|
||||
//
|
||||
// See LICENSE for license terms.
|
||||
// See README.md in the repo root for info about source code origin.
|
||||
//======================================================================
|
||||
|
||||
#ifndef BLAKE2S_H
|
||||
#define BLAKE2S_H
|
||||
|
||||
#include <stdint.h>
|
||||
#include <stddef.h>
|
||||
|
||||
// state context
|
||||
typedef struct {
|
||||
uint8_t b[64]; // input buffer
|
||||
uint32_t h[8]; // chained state
|
||||
uint32_t t[2]; // total number of bytes
|
||||
size_t c; // pointer for b[]
|
||||
size_t outlen; // digest size
|
||||
} blake2s_ctx;
|
||||
|
||||
// Initialize the hashing context "ctx" with optional key "key".
|
||||
// 1 <= outlen <= 32 gives the digest size in bytes.
|
||||
// Secret key (also <= 32 bytes) is optional (keylen = 0).
|
||||
int blake2s_init(blake2s_ctx *ctx, size_t outlen,
|
||||
const void *key, size_t keylen); // secret key
|
||||
|
||||
// Add "inlen" bytes from "in" into the hash.
|
||||
void blake2s_update(blake2s_ctx *ctx, // context
|
||||
const void *in, size_t inlen); // data to be hashed
|
||||
|
||||
// Generate the message digest (size given in init).
|
||||
// Result placed in "out".
|
||||
void blake2s_final(blake2s_ctx *ctx, void *out);
|
||||
|
||||
// All-in-one convenience function.
|
||||
int blake2s(void *out, size_t outlen, // return buffer for digest
|
||||
const void *key, size_t keylen, // optional secret key
|
||||
const void *in, size_t inlen); // data to be hashed
|
||||
|
||||
#endif
|
138
hw/application_fpga/tkey-libs/blake2s/blake2s_test.c
Normal file
138
hw/application_fpga/tkey-libs/blake2s/blake2s_test.c
Normal file
@ -0,0 +1,138 @@
|
||||
//======================================================================
|
||||
//
|
||||
// blake2s_test.c
|
||||
// --------------
|
||||
//
|
||||
//======================================================================
|
||||
|
||||
#include <stdio.h>
|
||||
#include "blake2s.h"
|
||||
|
||||
|
||||
//------------------------------------------------------------------
|
||||
//------------------------------------------------------------------
|
||||
void print_message(uint8_t *m, int mlen) {
|
||||
printf("The message:\n");
|
||||
for (int i = 1 ; i <= mlen ; i++) {
|
||||
printf("0x%02x ", m[(i - 1)]);
|
||||
if (i % 8 == 0) {
|
||||
printf("\n");
|
||||
}
|
||||
}
|
||||
printf("\n");
|
||||
}
|
||||
|
||||
|
||||
//------------------------------------------------------------------
|
||||
//------------------------------------------------------------------
|
||||
void print_digest(uint8_t *md) {
|
||||
printf("The digest:\n");
|
||||
for (int j = 0 ; j < 4 ; j++) {
|
||||
for (int i = 0 ; i < 8 ; i++) {
|
||||
printf("0x%02x ", md[i + 8 * j]);
|
||||
}
|
||||
printf("\n");
|
||||
}
|
||||
printf("\n");
|
||||
}
|
||||
|
||||
|
||||
//------------------------------------------------------------------
|
||||
// test_zero_length()
|
||||
// Test with a zero length mwssage.
|
||||
//------------------------------------------------------------------
|
||||
void test_zero_length() {
|
||||
|
||||
uint8_t md[32];
|
||||
|
||||
printf("Testing zero byte message.\n");
|
||||
blake2s(md, 32, NULL, 0, NULL, 0);
|
||||
print_digest(md);
|
||||
printf("\n");
|
||||
}
|
||||
|
||||
|
||||
//------------------------------------------------------------------
|
||||
// test_abc_message()
|
||||
// Test with a zero length mwssage.
|
||||
//------------------------------------------------------------------
|
||||
void test_abc_message() {
|
||||
|
||||
uint8_t md[32];
|
||||
uint8_t msg[64] = {'a', 'b', 'c'};
|
||||
|
||||
printf("Testing with RFC 7693 three byte 'abc' message.\n");
|
||||
print_message(msg, 3);
|
||||
|
||||
blake2s(md, 32, NULL, 0, msg, 3);
|
||||
print_digest(md);
|
||||
printf("\n");
|
||||
}
|
||||
|
||||
|
||||
//------------------------------------------------------------------
|
||||
// test_one_block_message()
|
||||
// Test with a 64 byte message, filling one block.
|
||||
//------------------------------------------------------------------
|
||||
void test_one_block_message() {
|
||||
|
||||
uint8_t md[32];
|
||||
uint8_t msg[64];
|
||||
|
||||
for (uint8_t i = 0 ; i < 64 ; i++) {
|
||||
msg[i] = i;
|
||||
}
|
||||
|
||||
printf("Testing with 64 byte message.\n");
|
||||
print_message(msg, 64);
|
||||
|
||||
blake2s(md, 32, NULL, 0, msg, 64);
|
||||
print_digest(md);
|
||||
printf("\n");
|
||||
}
|
||||
|
||||
|
||||
//------------------------------------------------------------------
|
||||
// test_one_block_one_byte_message()
|
||||
// Test with a 65 byte message, filling one block and a single
|
||||
// byte in the next block.
|
||||
//------------------------------------------------------------------
|
||||
void test_one_block_one_byte_message() {
|
||||
|
||||
uint8_t md[32];
|
||||
uint8_t msg[65];
|
||||
|
||||
for (uint8_t i = 0 ; i < 65 ; i++) {
|
||||
msg[i] = i;
|
||||
}
|
||||
|
||||
printf("Testing with 65 byte message.\n");
|
||||
print_message(msg, 65);
|
||||
|
||||
blake2s(md, 32, NULL, 0, msg, 65);
|
||||
print_digest(md);
|
||||
printf("\n");
|
||||
}
|
||||
|
||||
|
||||
//------------------------------------------------------------------
|
||||
//------------------------------------------------------------------
|
||||
int main(void) {
|
||||
printf("\n");
|
||||
printf("BLAKE2s reference model started. Performing a set of tests..\n");
|
||||
printf("Performing a set of tests.\n");
|
||||
|
||||
test_zero_length();
|
||||
test_abc_message();
|
||||
test_one_block_message();
|
||||
test_one_block_one_byte_message();
|
||||
|
||||
printf("BLAKE2s reference model completed.\n");
|
||||
printf("\n");
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
//======================================================================
|
||||
/// EOF blake2s_test.c
|
||||
//======================================================================
|
33
hw/application_fpga/tkey-libs/example-app/Makefile
Normal file
33
hw/application_fpga/tkey-libs/example-app/Makefile
Normal file
@ -0,0 +1,33 @@
|
||||
P := $(shell dirname $(realpath $(lastword $(MAKEFILE_LIST))))
|
||||
LIBDIR ?= $(P)/../
|
||||
OBJCOPY ?= llvm-objcopy
|
||||
CC = clang
|
||||
|
||||
# If you want debug_puts() etcetera to output something on our QEMU
|
||||
# debug port, use -DQEMU_DEBUG below, or -DTKEY_DEBUG to use Tkeys USB debug pipe
|
||||
CFLAGS = -g -target riscv32-unknown-none-elf -march=rv32iczmmul -mabi=ilp32 -mcmodel=medany \
|
||||
-static -std=gnu99 -O2 -ffast-math -fno-common -fno-builtin-printf \
|
||||
-fno-builtin-putchar -nostdlib -mno-relax -flto \
|
||||
-Wall -Werror=implicit-function-declaration \
|
||||
-I $(LIBDIR)/include -I $(LIBDIR)
|
||||
# -DQEMU_DEBUG -DTKEY_DEBUG
|
||||
|
||||
INCLUDE=$(LIBDIR)/include
|
||||
|
||||
LDFLAGS=-T $(LIBDIR)/app.lds -L $(LIBDIR) -lcommon -lcrt0
|
||||
|
||||
.PHONY: all
|
||||
all: blue.bin
|
||||
|
||||
# Turn elf into bin for device
|
||||
%.bin: %.elf
|
||||
$(OBJCOPY) --input-target=elf32-littleriscv --output-target=binary $^ $@
|
||||
chmod a-x $@
|
||||
|
||||
BLUEOBJS=blue.o
|
||||
blue.elf: blue.o
|
||||
$(CC) $(CFLAGS) $(BLUEOBJS) $(LDFLAGS) -I $(LIBDIR) -o $@
|
||||
|
||||
.PHONY: clean
|
||||
clean:
|
||||
rm -f blue.bin blue.elf $(BLUEOBJS)
|
31
hw/application_fpga/tkey-libs/example-app/blue.c
Normal file
31
hw/application_fpga/tkey-libs/example-app/blue.c
Normal file
@ -0,0 +1,31 @@
|
||||
// SPDX-FileCopyrightText: 2023 Tillitis AB <tillitis.se>
|
||||
// SPDX-License-Identifier: BSD-2-Clause
|
||||
|
||||
#include <stdint.h>
|
||||
#include <tkey/led.h>
|
||||
#include <tkey/tk1_mem.h>
|
||||
#include <tkey/debug.h>
|
||||
|
||||
#define SLEEPTIME 100000
|
||||
|
||||
void sleep(uint32_t n)
|
||||
{
|
||||
for (volatile int i = 0; i < n; i++);
|
||||
}
|
||||
|
||||
int main(void)
|
||||
{
|
||||
debug_puts("Hello, world!\n");
|
||||
debug_puts("Going to sleep between blinks: ");
|
||||
debug_putinthex(SLEEPTIME);
|
||||
debug_lf();
|
||||
|
||||
for (;;) {
|
||||
led_set(LED_RED);
|
||||
sleep(SLEEPTIME);
|
||||
led_set(LED_GREEN);
|
||||
sleep(SLEEPTIME);
|
||||
led_set(LED_BLUE);
|
||||
sleep(SLEEPTIME);
|
||||
}
|
||||
}
|
28
hw/application_fpga/tkey-libs/include/tkey/assert.h
Normal file
28
hw/application_fpga/tkey-libs/include/tkey/assert.h
Normal file
@ -0,0 +1,28 @@
|
||||
// SPDX-FileCopyrightText: 2022 Tillitis AB <tillitis.se>
|
||||
// SPDX-License-Identifier: BSD-2-Clause
|
||||
|
||||
#ifndef TKEY_ASSERT_H
|
||||
#define TKEY_ASSERT_H
|
||||
|
||||
#include <tkey/io.h>
|
||||
|
||||
#if defined(QEMU_DEBUG)
|
||||
#define assert(expr) \
|
||||
((expr) ? (void)(0) \
|
||||
: assert_fail(IO_QEMU, #expr, __FILE__, __LINE__, __func__))
|
||||
|
||||
#elif defined(TKEY_DEBUG)
|
||||
|
||||
#define assert(expr) \
|
||||
((expr) ? (void)(0) \
|
||||
: assert_fail(IO_DEBUG, #expr, __FILE__, __LINE__, __func__))
|
||||
|
||||
#else
|
||||
|
||||
#define assert(expr) ((expr) ? (void)(0) : assert_halt())
|
||||
#endif
|
||||
|
||||
void assert_fail(enum ioend dest, const char *assertion, const char *file,
|
||||
unsigned int line, const char *function);
|
||||
void assert_halt(void);
|
||||
#endif
|
39
hw/application_fpga/tkey-libs/include/tkey/debug.h
Normal file
39
hw/application_fpga/tkey-libs/include/tkey/debug.h
Normal file
@ -0,0 +1,39 @@
|
||||
// SPDX-FileCopyrightText: 2023 Tillitis AB <tillitis.se>
|
||||
// SPDX-License-Identifier: BSD-2-Clause
|
||||
|
||||
#ifndef TKEY_DEBUG_H
|
||||
#define TKEY_DEBUG_H
|
||||
|
||||
#include <stdint.h>
|
||||
|
||||
#include "io.h"
|
||||
|
||||
#if defined(QEMU_DEBUG)
|
||||
#define debug_putchar(ch) putchar(IO_QEMU, ch)
|
||||
#define debug_lf() putchar(IO_QEMU, '\n')
|
||||
#define debug_putinthex(ch) putinthex(IO_QEMU, ch)
|
||||
#define debug_puts(s) puts(IO_QEMU, s)
|
||||
#define debug_puthex(ch) puthex(IO_QEMU, ch)
|
||||
#define debug_hexdump(buf, len) hexdump(IO_QEMU, buf, len)
|
||||
|
||||
#elif defined(TKEY_DEBUG)
|
||||
|
||||
#define debug_putchar(ch) putchar(IO_DEBUG, ch)
|
||||
#define debug_lf() putchar(IO_DEBUG, '\n')
|
||||
#define debug_putinthex(ch) putinthex(IO_DEBUG, ch)
|
||||
#define debug_puts(s) puts(IO_DEBUG, s)
|
||||
#define debug_puthex(ch) puthex(IO_DEBUG, ch)
|
||||
#define debug_hexdump(buf, len) hexdump(IO_DEBUG, buf, len)
|
||||
|
||||
#else
|
||||
|
||||
#define debug_putchar(ch)
|
||||
#define debug_lf()
|
||||
#define debug_putinthex(n)
|
||||
#define debug_puts(s)
|
||||
#define debug_puthex(ch)
|
||||
#define debug_hexdump(buf, len)
|
||||
|
||||
#endif
|
||||
|
||||
#endif
|
42
hw/application_fpga/tkey-libs/include/tkey/io.h
Normal file
42
hw/application_fpga/tkey-libs/include/tkey/io.h
Normal file
@ -0,0 +1,42 @@
|
||||
// SPDX-FileCopyrightText: 2025 Tillitis AB <tillitis.se>
|
||||
// SPDX-License-Identifier: BSD-2-Clause
|
||||
|
||||
#include <stddef.h>
|
||||
#include <stdint.h>
|
||||
|
||||
#ifndef TKEY_IO_H
|
||||
#define TKEY_IO_H
|
||||
|
||||
// I/O endpoints. Keep it as bits possible to use in a bitmask in
|
||||
// readselect().
|
||||
//
|
||||
// Note that the values for IO_CH552, IO_CDC, IO_FIDO, IO_CCID and IO_DEBUG
|
||||
// should be kept the same in the code for the CH552 side.
|
||||
enum ioend {
|
||||
IO_NONE = 0x00, // No endpoint
|
||||
IO_UART = 0x01, // Only destination, raw UART access
|
||||
IO_QEMU = 0x02, // Only destination, QEMU debug port
|
||||
IO_CH552 = 0x04, // Internal CH552 control port
|
||||
IO_CDC = 0x08, // CDC "serial" port
|
||||
IO_FIDO = 0x10, // FIDO security token port
|
||||
IO_CCID = 0x20, // CCID "smart card" port
|
||||
IO_DEBUG = 0x40, // Debug port over USB HID
|
||||
};
|
||||
|
||||
enum ch552cmd {
|
||||
SET_ENDPOINTS = 0x01, // Config USB endpoints on the CH552
|
||||
CH552_CMD_MAX,
|
||||
};
|
||||
|
||||
void write(enum ioend dest, const uint8_t *buf, size_t nbytes);
|
||||
int read(enum ioend src, uint8_t *buf, size_t bufsize, size_t nbytes);
|
||||
int uart_read(uint8_t *buf, size_t bufsize, size_t nbytes);
|
||||
int readselect(int bitmask, enum ioend *endpoint, uint8_t *len);
|
||||
void putchar(enum ioend dest, const uint8_t ch);
|
||||
void puthex(enum ioend dest, const uint8_t ch);
|
||||
void putinthex(enum ioend dest, const uint32_t n);
|
||||
void puts(enum ioend dest, const char *s);
|
||||
void hexdump(enum ioend dest, void *buf, int len);
|
||||
void config_endpoints(enum ioend endpoints);
|
||||
|
||||
#endif
|
21
hw/application_fpga/tkey-libs/include/tkey/led.h
Normal file
21
hw/application_fpga/tkey-libs/include/tkey/led.h
Normal file
@ -0,0 +1,21 @@
|
||||
// SPDX-FileCopyrightText: 2022 Tillitis AB <tillitis.se>
|
||||
// SPDX-License-Identifier: BSD-2-Clause
|
||||
|
||||
#ifndef TKEY_LED_H
|
||||
#define TKEY_LED_H
|
||||
|
||||
#include <stdint.h>
|
||||
#include <tkey/tk1_mem.h>
|
||||
|
||||
// clang-format off
|
||||
#define LED_BLACK 0
|
||||
#define LED_RED (1 << TK1_MMIO_TK1_LED_R_BIT)
|
||||
#define LED_GREEN (1 << TK1_MMIO_TK1_LED_G_BIT)
|
||||
#define LED_BLUE (1 << TK1_MMIO_TK1_LED_B_BIT)
|
||||
#define LED_WHITE (LED_RED | LED_GREEN | LED_BLUE)
|
||||
// clang-format on
|
||||
|
||||
uint32_t led_get(void);
|
||||
void led_set(uint32_t ledvalue);
|
||||
void led_flash_forever(uint32_t ledvalue);
|
||||
#endif
|
18
hw/application_fpga/tkey-libs/include/tkey/lib.h
Normal file
18
hw/application_fpga/tkey-libs/include/tkey/lib.h
Normal file
@ -0,0 +1,18 @@
|
||||
// SPDX-FileCopyrightText: 2022 Tillitis AB <tillitis.se>
|
||||
// SPDX-License-Identifier: BSD-2-Clause
|
||||
|
||||
#ifndef TKEY_LIB_H
|
||||
#define TKEY_LIB_H
|
||||
|
||||
#include <stddef.h>
|
||||
#include <stdint.h>
|
||||
|
||||
void *memset(void *dest, int c, unsigned n);
|
||||
void *memcpy(void *dest, const void *src, unsigned n);
|
||||
void memcpy_s(void *dest, size_t destsize, const void *src, size_t n);
|
||||
void *wordcpy(void *dest, const void *src, unsigned n);
|
||||
void wordcpy_s(void *dest, size_t destsize, const void *src, size_t n);
|
||||
int memeq(void *dest, const void *src, size_t n);
|
||||
void secure_wipe(void *v, size_t n);
|
||||
size_t strlen(const char *str);
|
||||
#endif
|
39
hw/application_fpga/tkey-libs/include/tkey/proto.h
Normal file
39
hw/application_fpga/tkey-libs/include/tkey/proto.h
Normal file
@ -0,0 +1,39 @@
|
||||
// SPDX-FileCopyrightText: 2022 Tillitis AB <tillitis.se>
|
||||
// SPDX-License-Identifier: BSD-2-Clause
|
||||
|
||||
#include <stddef.h>
|
||||
#include <stdint.h>
|
||||
|
||||
#ifndef TKEY_PROTO_H
|
||||
#define TKEY_PROTO_H
|
||||
|
||||
enum endpoints {
|
||||
DST_HW_IFPGA = 0x00,
|
||||
DST_HW_AFPGA = 0x01,
|
||||
DST_FW = 0x02,
|
||||
DST_SW = 0x03
|
||||
};
|
||||
|
||||
enum cmdlen {
|
||||
LEN_1,
|
||||
LEN_4,
|
||||
LEN_32,
|
||||
LEN_128
|
||||
};
|
||||
|
||||
#define CMDLEN_MAXBYTES 128
|
||||
|
||||
enum status {
|
||||
STATUS_OK,
|
||||
STATUS_BAD
|
||||
};
|
||||
|
||||
struct frame_header {
|
||||
uint8_t id;
|
||||
enum endpoints endpoint;
|
||||
size_t len;
|
||||
};
|
||||
|
||||
uint8_t genhdr(uint8_t id, uint8_t endpoint, uint8_t status, enum cmdlen len);
|
||||
int parseframe(uint8_t b, struct frame_header *hdr);
|
||||
#endif
|
@ -1,12 +1,12 @@
|
||||
/*
|
||||
* Tillitis TKey Memory Map
|
||||
*
|
||||
* Copyright (c) 2022, 2023, 2024 Tillitis AB
|
||||
* SPDX-License-Identifier: GPL-2.0-or-later
|
||||
* SPDX-FileCopyrightText: 2022 Tillitis AB <tillitis.se>
|
||||
* SPDX-License-Identifier: BSD-2-Clause
|
||||
*
|
||||
* Note that this file is also included in at least qemu
|
||||
* (GPL-2.0-or-later) besides tillitis-key1 (GPL-2.0-only) and
|
||||
* tkey-libs (GPL-2.0-only) so it's licensed as GPL v2 or later.
|
||||
* Note that this file is also in tillitis-key1 and qemu
|
||||
* (GPL-2.0-or-later). Needs to stay in sync and have a compatible
|
||||
* license.
|
||||
*/
|
||||
|
||||
// clang-format off
|
||||
@ -15,16 +15,18 @@
|
||||
#define TKEY_TK1_MEM_H
|
||||
|
||||
/*
|
||||
|
||||
The canonical location of this file is in:
|
||||
|
||||
https://github.com/tillitis/tkey-libs
|
||||
|
||||
Under:
|
||||
|
||||
include/tkey/tk1_mem.h
|
||||
|
||||
The contents are mostly derived from the Verilog code in
|
||||
|
||||
https://github.com/tillitis/tillitis-key1
|
||||
|
||||
/hw/application_fpga/fw/tk1_mem.h
|
||||
|
||||
The contents are derived from the Verilog code. For use by QEMU model,
|
||||
firmware, and apps.
|
||||
|
||||
Memory map
|
||||
|
||||
Top level prefix, the first 2 bits in a 32-bit address:
|
||||
@ -34,7 +36,7 @@
|
||||
ROM 0b00 30 bit address
|
||||
RAM 0b01 30 bit address
|
||||
Reserved 0b10
|
||||
MMIO 0b11 6 bits for core select, 24 bits rest
|
||||
Cores 0b11 6 bits for core select, 24 bits rest
|
||||
|
||||
Address Prefix, the first 8 bits in a 32-bit address:
|
||||
|
||||
@ -42,18 +44,19 @@
|
||||
--------------------
|
||||
ROM 0x00
|
||||
RAM 0x40
|
||||
MMIO 0xc0
|
||||
MMIO TRNG 0xc0
|
||||
MMIO TIMER 0xc1
|
||||
MMIO UDS 0xc2
|
||||
MMIO UART 0xc3
|
||||
MMIO TOUCH 0xc4
|
||||
MMIO FW_RAM 0xd0
|
||||
MMIO QEMU 0xfe Not used in real hardware
|
||||
MMIO TK1 0xff
|
||||
TRNG 0xc0
|
||||
TIMER 0xc1
|
||||
UDS 0xc2
|
||||
UART 0xc3
|
||||
TOUCH 0xc4
|
||||
FW_RAM 0xd0
|
||||
QEMU 0xfe Not used in real hardware
|
||||
TK1 0xff
|
||||
*/
|
||||
|
||||
#define TK1_ROM_BASE 0x00000000
|
||||
#define TK1_ROM_SIZE 0x2000
|
||||
|
||||
#define TK1_RAM_BASE 0x40000000
|
||||
#define TK1_RAM_SIZE 0x20000
|
||||
|
||||
@ -63,8 +66,8 @@
|
||||
#define TK1_APP_MAX_SIZE 0x20000
|
||||
|
||||
#define TK1_MMIO_FW_RAM_BASE 0xd0000000
|
||||
// FW_RAM is 2048 bytes
|
||||
#define TK1_MMIO_FW_RAM_SIZE 0x800
|
||||
// FW_RAM is 4096 bytes
|
||||
#define TK1_MMIO_FW_RAM_SIZE 0x1000
|
||||
|
||||
#define TK1_MMIO_TRNG_BASE 0xc0000000
|
||||
#define TK1_MMIO_TRNG_STATUS 0xc0000024
|
||||
@ -106,10 +109,6 @@
|
||||
#define TK1_MMIO_TK1_NAME1 0xff000004
|
||||
#define TK1_MMIO_TK1_VERSION 0xff000008
|
||||
|
||||
// Deprecated - use _SYSTEM_MODE_CTRL instead
|
||||
#define TK1_MMIO_TK1_SWITCH_APP 0xff000020
|
||||
#define TK1_MMIO_TK1_SYSTEM_MODE_CTRL 0xff000020
|
||||
|
||||
#define TK1_MMIO_TK1_LED 0xff000024
|
||||
#define TK1_MMIO_TK1_LED_R_BIT 2
|
||||
#define TK1_MMIO_TK1_LED_G_BIT 1
|
||||
@ -124,8 +123,6 @@
|
||||
#define TK1_MMIO_TK1_APP_ADDR 0xff000030
|
||||
#define TK1_MMIO_TK1_APP_SIZE 0xff000034
|
||||
|
||||
#define TK1_MMIO_TK1_BLAKE2S 0xff000040
|
||||
|
||||
#define TK1_MMIO_TK1_CDI_FIRST 0xff000080
|
||||
#define TK1_MMIO_TK1_CDI_LAST 0xff00009c
|
||||
|
17
hw/application_fpga/tkey-libs/include/tkey/touch.h
Normal file
17
hw/application_fpga/tkey-libs/include/tkey/touch.h
Normal file
@ -0,0 +1,17 @@
|
||||
// SPDX-FileCopyrightText: 2023 Tillitis AB <tillitis.se>
|
||||
// SPDX-License-Identifier: BSD-2-Clause
|
||||
|
||||
#ifndef TKEY_TOUCH_H
|
||||
#define TKEY_TOUCH_H
|
||||
|
||||
#include <stdbool.h>
|
||||
#include <stdint.h>
|
||||
#include <tkey/tk1_mem.h>
|
||||
|
||||
// touchwait() waits for a touch event while blinking color on the
|
||||
// status LED. timeout_s is the timeout in seconds.
|
||||
//
|
||||
// If a touch event occurs it returns true. If the timeout expires it
|
||||
// returns false.
|
||||
bool touch_wait(int color, int timeout_s);
|
||||
#endif
|
35
hw/application_fpga/tkey-libs/libcommon/assert.c
Normal file
35
hw/application_fpga/tkey-libs/libcommon/assert.c
Normal file
@ -0,0 +1,35 @@
|
||||
// SPDX-FileCopyrightText: 2022 Tillitis AB <tillitis.se>
|
||||
// SPDX-License-Identifier: BSD-2-Clause
|
||||
|
||||
#include <tkey/assert.h>
|
||||
#include <tkey/io.h>
|
||||
#include <tkey/lib.h>
|
||||
|
||||
void assert_fail(enum ioend dest, const char *assertion, const char *file,
|
||||
unsigned int line, const char *function)
|
||||
{
|
||||
puts(dest, "assert: ");
|
||||
puts(dest, assertion);
|
||||
puts(dest, " ");
|
||||
puts(dest, file);
|
||||
puts(dest, ":");
|
||||
putinthex(dest, line);
|
||||
puts(dest, " ");
|
||||
puts(dest, function);
|
||||
puts(dest, "\n");
|
||||
|
||||
// Force illegal instruction to halt CPU
|
||||
asm volatile("unimp");
|
||||
|
||||
// Not reached
|
||||
__builtin_unreachable();
|
||||
}
|
||||
|
||||
void assert_halt(void)
|
||||
{
|
||||
// Force illegal instruction to halt CPU
|
||||
asm volatile("unimp");
|
||||
|
||||
// Not reached
|
||||
__builtin_unreachable();
|
||||
}
|
382
hw/application_fpga/tkey-libs/libcommon/io.c
Normal file
382
hw/application_fpga/tkey-libs/libcommon/io.c
Normal file
@ -0,0 +1,382 @@
|
||||
// SPDX-FileCopyrightText: 2025 Tillitis AB <tillitis.se>
|
||||
// SPDX-License-Identifier: BSD-2-Clause
|
||||
|
||||
#include <stdint.h>
|
||||
#include <tkey/assert.h>
|
||||
#include <tkey/debug.h>
|
||||
#include <tkey/lib.h>
|
||||
#include <tkey/proto.h>
|
||||
#include <tkey/tk1_mem.h>
|
||||
|
||||
// Maximum payload size sent over the USB Mode Protocol.
|
||||
//
|
||||
// USB Mode Protocol:
|
||||
// 1 byte mode
|
||||
// 1 byte length
|
||||
//
|
||||
// Our USB Mode Protocol packets has room for 255 bytes according to
|
||||
// the header but we send at most 64 bytes of payload + the 2 byte
|
||||
// header. The header is removed in the USB controller and the maximum
|
||||
// payload fits in a single USB frame on the other side.
|
||||
#define USBMODE_PACKET_SIZE 64
|
||||
|
||||
static void hex(uint8_t buf[2], const uint8_t c);
|
||||
static int discard(size_t nbytes);
|
||||
static uint8_t readbyte(void);
|
||||
static void writebyte(uint8_t b);
|
||||
|
||||
struct usb_mode {
|
||||
enum ioend endpoint; // Current USB endpoint with data
|
||||
uint8_t len; // Data available in from current USB mode.
|
||||
};
|
||||
|
||||
static struct usb_mode cur_endpoint = {
|
||||
IO_NONE,
|
||||
0,
|
||||
};
|
||||
|
||||
// clang-format off
|
||||
static volatile uint32_t* const can_rx = (volatile uint32_t *)TK1_MMIO_UART_RX_STATUS;
|
||||
static volatile uint32_t* const rx = (volatile uint32_t *)TK1_MMIO_UART_RX_DATA;
|
||||
static volatile uint32_t* const can_tx = (volatile uint32_t *)TK1_MMIO_UART_TX_STATUS;
|
||||
static volatile uint32_t* const tx = (volatile uint32_t *)TK1_MMIO_UART_TX_DATA;
|
||||
static volatile uint8_t* const debugtx = (volatile uint8_t *)TK1_MMIO_QEMU_DEBUG;
|
||||
// clang-format on
|
||||
|
||||
// writebyte blockingly writes byte b to UART
|
||||
static void writebyte(uint8_t b)
|
||||
{
|
||||
for (;;) {
|
||||
if (*can_tx) {
|
||||
*tx = b;
|
||||
return;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// write_with_header writes nbytes of buf to UART with a USB Mode
|
||||
// Protocol header telling the receiver about the mode and length.
|
||||
static void write_with_header(enum ioend dest, const uint8_t *buf,
|
||||
size_t nbytes)
|
||||
{
|
||||
// USB Mode Protocol header:
|
||||
// 1 byte mode
|
||||
// 1 byte length
|
||||
|
||||
writebyte(dest);
|
||||
writebyte(nbytes);
|
||||
|
||||
for (int i = 0; i < nbytes; i++) {
|
||||
writebyte(buf[i]);
|
||||
}
|
||||
}
|
||||
|
||||
// write blockingly writes nbytes bytes of data from buf to dest which
|
||||
// is either:
|
||||
//
|
||||
// - IO_UART: Low-level UART access, no USB Mode Header added.
|
||||
//
|
||||
// - IO_QEMU: QEMU debug port
|
||||
//
|
||||
// - IO_CH552: Internal communication between the FPGA and the
|
||||
// CH552, with header.
|
||||
//
|
||||
// - IO_CDC: Through the UART for the CDC endpoint, with header.
|
||||
//
|
||||
// - IO_FIDO: Through the UART for the FIDO endpoint, with header.
|
||||
//
|
||||
// - IO_CCID: Through the UART for the CCID endpoint, with header.
|
||||
//
|
||||
// - IO_DEBUG: Through the UART for the DEBUG endpoint (USB HID), with
|
||||
// header.
|
||||
void write(enum ioend dest, const uint8_t *buf, size_t nbytes)
|
||||
{
|
||||
if (dest == IO_QEMU) {
|
||||
for (int i = 0; i < nbytes; i++) {
|
||||
*debugtx = buf[i];
|
||||
}
|
||||
|
||||
return;
|
||||
} else if (dest == IO_UART) {
|
||||
for (int i = 0; i < nbytes; i++) {
|
||||
writebyte(buf[i]);
|
||||
}
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
while (nbytes > 0) {
|
||||
// We split the data into chunks that will fit in the
|
||||
// USB Mode Protocol and fits neatly in the USB frames
|
||||
// on the other side of the USB controller.
|
||||
uint8_t len =
|
||||
nbytes < USBMODE_PACKET_SIZE ? nbytes : USBMODE_PACKET_SIZE;
|
||||
|
||||
write_with_header(dest, (const uint8_t *)buf, len);
|
||||
|
||||
buf += len;
|
||||
nbytes -= len;
|
||||
}
|
||||
}
|
||||
|
||||
// readbyte reads a byte from UART and returns it. Blocking.
|
||||
static uint8_t readbyte(void)
|
||||
{
|
||||
for (;;) {
|
||||
if (*can_rx) {
|
||||
return *rx;
|
||||
}
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
// read reads into buf of size bufsize from UART, nbytes or less, from
|
||||
// the current USB endpoint. It doesn't block.
|
||||
//
|
||||
// Returns the number of bytes read. Empty data returns 0.
|
||||
int read(enum ioend src, uint8_t *buf, size_t bufsize, size_t nbytes)
|
||||
{
|
||||
if (buf == NULL || nbytes > bufsize) {
|
||||
return -1;
|
||||
}
|
||||
|
||||
if (src == IO_NONE || src == IO_UART || src == IO_QEMU) {
|
||||
// Destination only endpoints
|
||||
return -1;
|
||||
}
|
||||
|
||||
if (src != cur_endpoint.endpoint) {
|
||||
// No data for this source available right now.
|
||||
return 0;
|
||||
}
|
||||
|
||||
int n = 0;
|
||||
|
||||
for (n = 0; n < nbytes; n++) {
|
||||
buf[n] = readbyte();
|
||||
cur_endpoint.len--;
|
||||
}
|
||||
|
||||
return n;
|
||||
}
|
||||
|
||||
// uart_read reads blockingly into buf o size bufsize from UART nbytes
|
||||
// bytes.
|
||||
//
|
||||
// Returns negative on error.
|
||||
int uart_read(uint8_t *buf, size_t bufsize, size_t nbytes)
|
||||
{
|
||||
if (nbytes > bufsize) {
|
||||
return -1;
|
||||
}
|
||||
|
||||
for (int n = 0; n < nbytes; n++) {
|
||||
buf[n] = readbyte();
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
// discard nbytes of what's available.
|
||||
//
|
||||
// Returns how many bytes were discarded.
|
||||
static int discard(size_t nbytes)
|
||||
{
|
||||
int n = 0;
|
||||
uint8_t len = nbytes < cur_endpoint.len ? nbytes : cur_endpoint.len;
|
||||
|
||||
for (n = 0; n < len; n++) {
|
||||
(void)readbyte();
|
||||
cur_endpoint.len--;
|
||||
}
|
||||
|
||||
return n;
|
||||
}
|
||||
|
||||
// readselect blocks and returns when there is something readable from
|
||||
// some mode.
|
||||
//
|
||||
// Use like this:
|
||||
//
|
||||
// readselect(IO_CDC|IO_FIDO, &endpoint, &len)
|
||||
//
|
||||
// to wait for some data from either the CDC or the FIDO endpoint.
|
||||
//
|
||||
// NOTE WELL: You need to call readselect() first, before doing any
|
||||
// calls to read().
|
||||
//
|
||||
// Only endpoints available for read are:
|
||||
//
|
||||
// - IO_CH552
|
||||
// - IO_CDC
|
||||
// - IO_FIDO
|
||||
// - IO_CCID
|
||||
// - IO_DEBUG
|
||||
//
|
||||
// If you need blocking low-level UART reads, use uart_read() instead.
|
||||
//
|
||||
// Sets endpoint of the first endpoint in the bitmask with data
|
||||
// available. Indicates how many bytes available in len.
|
||||
//
|
||||
// Returns non-zero on error.
|
||||
int readselect(int bitmask, enum ioend *endpoint, uint8_t *len)
|
||||
{
|
||||
if ((bitmask & IO_UART) || (bitmask & IO_QEMU)) {
|
||||
// Not possible to use readselect() on these
|
||||
// endpoints.
|
||||
return -1;
|
||||
}
|
||||
|
||||
for (;;) {
|
||||
// Check what is in the current UART buffer.
|
||||
//
|
||||
// - If nothing known, block until something comes along.
|
||||
//
|
||||
// - If not in bitmask, discard the data available
|
||||
// from that endpoint.
|
||||
//
|
||||
// - If in the bitmask, return the first endpoint with
|
||||
// data available and indicate how much data in len.
|
||||
if (cur_endpoint.len == 0) {
|
||||
// Read USB Mode Protocol header:
|
||||
// 1 byte mode
|
||||
// 1 byte length
|
||||
cur_endpoint.endpoint = readbyte();
|
||||
cur_endpoint.len = readbyte();
|
||||
}
|
||||
|
||||
*len = cur_endpoint.len;
|
||||
|
||||
if (cur_endpoint.endpoint & bitmask) {
|
||||
*endpoint = cur_endpoint.endpoint;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
// Not the USB endpoint caller asked for. Discard the
|
||||
// rest from this endpoint.
|
||||
if (discard(*len) != *len) {
|
||||
// We couldn't discard what the USB Mode
|
||||
// Protocol itself reported was available!
|
||||
// Something's fishy. Halt.
|
||||
assert(1 == 2);
|
||||
}
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
void putchar(enum ioend dest, const uint8_t ch)
|
||||
{
|
||||
write(dest, &ch, 1);
|
||||
}
|
||||
|
||||
static void hex(uint8_t buf[2], const uint8_t c)
|
||||
{
|
||||
unsigned int upper = (c >> 4) & 0xf;
|
||||
unsigned int lower = c & 0xf;
|
||||
|
||||
buf[0] = upper < 10 ? '0' + upper : 'a' - 10 + upper;
|
||||
buf[1] = lower < 10 ? '0' + lower : 'a' - 10 + lower;
|
||||
}
|
||||
|
||||
void puthex(enum ioend dest, const uint8_t c)
|
||||
{
|
||||
uint8_t hexbuf[2] = {0};
|
||||
|
||||
hex(hexbuf, c);
|
||||
write(dest, hexbuf, 2);
|
||||
}
|
||||
|
||||
// Size of of a maximum integer in hex text format
|
||||
#define INTBUFSIZE 10
|
||||
|
||||
void putinthex(enum ioend dest, const uint32_t n)
|
||||
{
|
||||
uint8_t buf[INTBUFSIZE] = {0};
|
||||
uint8_t hexbuf[2] = {0};
|
||||
uint8_t *intbuf = (uint8_t *)&n;
|
||||
int j = 0;
|
||||
|
||||
buf[j++] = '0';
|
||||
buf[j++] = 'x';
|
||||
|
||||
for (int i = 3; i > -1; i--) {
|
||||
hex(hexbuf, intbuf[i]);
|
||||
buf[j++] = hexbuf[0];
|
||||
buf[j++] = hexbuf[1];
|
||||
}
|
||||
|
||||
write(dest, buf, INTBUFSIZE);
|
||||
}
|
||||
|
||||
void puts(enum ioend dest, const char *s)
|
||||
{
|
||||
write(dest, (const uint8_t *)s, strlen(s));
|
||||
}
|
||||
|
||||
// Size of a hex row: Contains 16 bytes where each byte is printed as
|
||||
// 3 characters (hex + hex + space). Every row ends with newline or at
|
||||
// most CR+LF.
|
||||
#define FULLROW (16 * 3)
|
||||
#define ROWBUFSIZE (FULLROW + 2)
|
||||
|
||||
void hexdump(enum ioend dest, void *buf, int len)
|
||||
{
|
||||
uint8_t rowbuf[ROWBUFSIZE] = {0};
|
||||
uint8_t hexbuf[2] = {0};
|
||||
uint8_t *byte_buf = (uint8_t *)buf;
|
||||
|
||||
int rowpos = 0;
|
||||
for (int i = 0; i < len; i++) {
|
||||
hex(hexbuf, byte_buf[i]);
|
||||
rowbuf[rowpos++] = hexbuf[0];
|
||||
rowbuf[rowpos++] = hexbuf[1];
|
||||
rowbuf[rowpos++] = ' ';
|
||||
|
||||
// If the row is full, print it now.
|
||||
if (rowpos == FULLROW) {
|
||||
if (dest == IO_CDC) {
|
||||
rowbuf[rowpos++] = '\r';
|
||||
}
|
||||
rowbuf[rowpos++] = '\n';
|
||||
write(dest, rowbuf, rowpos);
|
||||
rowpos = 0;
|
||||
}
|
||||
}
|
||||
|
||||
// If final row wasn't full, print it now.
|
||||
if (rowpos != 0) {
|
||||
if (dest == IO_CDC) {
|
||||
rowbuf[rowpos++] = '\r';
|
||||
}
|
||||
rowbuf[rowpos++] = '\n';
|
||||
write(dest, rowbuf, rowpos);
|
||||
}
|
||||
}
|
||||
|
||||
// Configure USB endpoints that should be enabled/disabled
|
||||
//
|
||||
// Allowed options are:
|
||||
// - IO_FIDO (can't be used used together with IO_CCID)
|
||||
// - IO_CCID (can't be used used together with IO_FIDO)
|
||||
// - IO_DEBUG
|
||||
//
|
||||
// The following are always enabled:
|
||||
// - IO_CDC
|
||||
// - IO_CH552
|
||||
//
|
||||
// Use like this:
|
||||
//
|
||||
// config_endpoints(IO_FIDO|IO_DEBUG)
|
||||
//
|
||||
void config_endpoints(enum ioend endpoints)
|
||||
{
|
||||
uint8_t cmdbuf[2] = {0};
|
||||
|
||||
cmdbuf[0] = SET_ENDPOINTS;
|
||||
cmdbuf[1] = endpoints;
|
||||
|
||||
write(IO_CH552, cmdbuf, 2);
|
||||
}
|
31
hw/application_fpga/tkey-libs/libcommon/led.c
Normal file
31
hw/application_fpga/tkey-libs/libcommon/led.c
Normal file
@ -0,0 +1,31 @@
|
||||
// SPDX-FileCopyrightText: 2022 Tillitis AB <tillitis.se>
|
||||
// SPDX-License-Identifier: BSD-2-Clause
|
||||
|
||||
#include <stdint.h>
|
||||
#include <tkey/led.h>
|
||||
|
||||
// clang-format off
|
||||
static volatile uint32_t* const led = (volatile uint32_t *)TK1_MMIO_TK1_LED;
|
||||
// clang-format on
|
||||
|
||||
void led_set(uint32_t ledvalue)
|
||||
{
|
||||
*led = ledvalue;
|
||||
}
|
||||
|
||||
uint32_t led_get()
|
||||
{
|
||||
return *led;
|
||||
}
|
||||
|
||||
void led_flash_forever(uint32_t ledvalue)
|
||||
{
|
||||
int led_on = 0;
|
||||
|
||||
for (;;) {
|
||||
*led = led_on ? ledvalue : LED_BLACK;
|
||||
for (volatile int i = 0; i < 800000; i++) {
|
||||
}
|
||||
led_on = !led_on;
|
||||
}
|
||||
}
|
101
hw/application_fpga/tkey-libs/libcommon/lib.c
Normal file
101
hw/application_fpga/tkey-libs/libcommon/lib.c
Normal file
@ -0,0 +1,101 @@
|
||||
// SPDX-FileCopyrightText: 2022 Tillitis AB <tillitis.se>
|
||||
// SPDX-License-Identifier: BSD-2-Clause
|
||||
|
||||
#include <stdint.h>
|
||||
#include <tkey/assert.h>
|
||||
#include <tkey/lib.h>
|
||||
#include <tkey/tk1_mem.h>
|
||||
|
||||
void *memset(void *dest, int c, unsigned n)
|
||||
{
|
||||
uint8_t *s = dest;
|
||||
|
||||
for (; n; n--, s++)
|
||||
*s = c;
|
||||
|
||||
return dest;
|
||||
}
|
||||
|
||||
__attribute__((used)) void *memcpy(void *dest, const void *src, unsigned n)
|
||||
{
|
||||
uint8_t *src_byte = (uint8_t *)src;
|
||||
uint8_t *dest_byte = (uint8_t *)dest;
|
||||
|
||||
for (int i = 0; i < n; i++) {
|
||||
dest_byte[i] = src_byte[i];
|
||||
}
|
||||
|
||||
return dest;
|
||||
}
|
||||
|
||||
void memcpy_s(void *dest, size_t destsize, const void *src, size_t n)
|
||||
{
|
||||
assert(dest != NULL);
|
||||
assert(src != NULL);
|
||||
assert(destsize >= n);
|
||||
|
||||
uint8_t *src_byte = (uint8_t *)src;
|
||||
uint8_t *dest_byte = (uint8_t *)dest;
|
||||
|
||||
for (size_t i = 0; i < n; i++) {
|
||||
dest_byte[i] = src_byte[i];
|
||||
}
|
||||
}
|
||||
|
||||
__attribute__((used)) void *wordcpy(void *dest, const void *src, unsigned n)
|
||||
{
|
||||
uint32_t *src_word = (uint32_t *)src;
|
||||
uint32_t *dest_word = (uint32_t *)dest;
|
||||
|
||||
for (int i = 0; i < n; i++) {
|
||||
dest_word[i] = src_word[i];
|
||||
}
|
||||
|
||||
return dest;
|
||||
}
|
||||
|
||||
void wordcpy_s(void *dest, size_t destsize, const void *src, size_t n)
|
||||
{
|
||||
assert(dest != NULL);
|
||||
assert(src != NULL);
|
||||
assert(destsize >= n);
|
||||
|
||||
uint32_t *src_word = (uint32_t *)src;
|
||||
uint32_t *dest_word = (uint32_t *)dest;
|
||||
|
||||
for (size_t i = 0; i < n; i++) {
|
||||
dest_word[i] = src_word[i];
|
||||
}
|
||||
}
|
||||
|
||||
int memeq(void *dest, const void *src, size_t n)
|
||||
{
|
||||
uint8_t *src_byte = (uint8_t *)src;
|
||||
uint8_t *dest_byte = (uint8_t *)dest;
|
||||
int res = -1;
|
||||
|
||||
for (size_t i = 0; i < n; i++) {
|
||||
if (dest_byte[i] != src_byte[i]) {
|
||||
res = 0;
|
||||
}
|
||||
}
|
||||
|
||||
return res;
|
||||
}
|
||||
|
||||
void secure_wipe(void *v, size_t n)
|
||||
{
|
||||
volatile uint8_t *p = (volatile uint8_t *)v;
|
||||
while (n--)
|
||||
*p++ = 0;
|
||||
}
|
||||
|
||||
size_t strlen(const char *str)
|
||||
{
|
||||
const char *s;
|
||||
|
||||
for (s = str; *s; ++s)
|
||||
;
|
||||
|
||||
return (s - str);
|
||||
}
|
51
hw/application_fpga/tkey-libs/libcommon/proto.c
Normal file
51
hw/application_fpga/tkey-libs/libcommon/proto.c
Normal file
@ -0,0 +1,51 @@
|
||||
// SPDX-FileCopyrightText: 2022 Tillitis AB <tillitis.se>
|
||||
// SPDX-License-Identifier: BSD-2-Clause
|
||||
|
||||
#include <stddef.h>
|
||||
#include <stdint.h>
|
||||
#include <tkey/assert.h>
|
||||
#include <tkey/debug.h>
|
||||
#include <tkey/proto.h>
|
||||
#include <tkey/tk1_mem.h>
|
||||
|
||||
uint8_t genhdr(uint8_t id, uint8_t endpoint, uint8_t status, enum cmdlen len)
|
||||
{
|
||||
return (id << 5) | (endpoint << 3) | (status << 2) | len;
|
||||
}
|
||||
|
||||
int parseframe(uint8_t b, struct frame_header *hdr)
|
||||
{
|
||||
if ((b & 0x80) != 0) {
|
||||
// Bad version
|
||||
return -1;
|
||||
}
|
||||
|
||||
if ((b & 0x4) != 0) {
|
||||
// Must be 0
|
||||
return -1;
|
||||
}
|
||||
|
||||
hdr->id = (b & 0x60) >> 5;
|
||||
hdr->endpoint = (b & 0x18) >> 3;
|
||||
|
||||
// Length
|
||||
switch (b & 0x3) {
|
||||
case LEN_1:
|
||||
hdr->len = 1;
|
||||
break;
|
||||
case LEN_4:
|
||||
hdr->len = 4;
|
||||
break;
|
||||
case LEN_32:
|
||||
hdr->len = 32;
|
||||
break;
|
||||
case LEN_128:
|
||||
hdr->len = 128;
|
||||
break;
|
||||
default:
|
||||
// Unknown length
|
||||
return -1;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
67
hw/application_fpga/tkey-libs/libcommon/touch.c
Normal file
67
hw/application_fpga/tkey-libs/libcommon/touch.c
Normal file
@ -0,0 +1,67 @@
|
||||
// SPDX-FileCopyrightText: 2023 Tillitis AB <tillitis.se>
|
||||
// SPDX-License-Identifier: BSD-2-Clause
|
||||
|
||||
#include <stdbool.h>
|
||||
#include <tkey/debug.h>
|
||||
#include <tkey/led.h>
|
||||
#include <tkey/touch.h>
|
||||
|
||||
// CPU clock frequenzy in Hz
|
||||
#define CPUFREQ 18000000
|
||||
|
||||
// clang-format off
|
||||
static volatile uint32_t *timer = (volatile uint32_t *)TK1_MMIO_TIMER_TIMER;
|
||||
static volatile uint32_t *timer_prescaler = (volatile uint32_t *)TK1_MMIO_TIMER_PRESCALER;
|
||||
static volatile uint32_t *timer_status = (volatile uint32_t *)TK1_MMIO_TIMER_STATUS;
|
||||
static volatile uint32_t *timer_ctrl = (volatile uint32_t *)TK1_MMIO_TIMER_CTRL;
|
||||
static volatile uint32_t *touch = (volatile uint32_t *)TK1_MMIO_TOUCH_STATUS;
|
||||
// clang-format on
|
||||
|
||||
// Returns !0 if touch sensor has been touched
|
||||
#define touched() (*touch & (1 << TK1_MMIO_TOUCH_STATUS_EVENT_BIT))
|
||||
|
||||
bool touch_wait(int color, int timeout_s)
|
||||
{
|
||||
int ledon = 0;
|
||||
int orig_color = led_get();
|
||||
uint32_t time = 0;
|
||||
uint32_t lasttime = 0;
|
||||
|
||||
// Tick once every decisecond
|
||||
*timer_prescaler = CPUFREQ / 10;
|
||||
*timer = timeout_s * 10; // Seconds
|
||||
|
||||
// Start timer
|
||||
*timer_ctrl |= (1 << TK1_MMIO_TIMER_CTRL_START_BIT);
|
||||
|
||||
// Acknowledge any stray touch events before waiting for real
|
||||
// touch
|
||||
*touch = 0;
|
||||
|
||||
// Blink until either the touch sensor has been touched or the
|
||||
// timer hits 0.
|
||||
while (!touched() && *timer_status != 0) {
|
||||
time = *timer;
|
||||
if (time % 2 == 0 && time != lasttime) {
|
||||
lasttime = time;
|
||||
ledon = !ledon;
|
||||
led_set(ledon ? color : LED_BLACK);
|
||||
}
|
||||
}
|
||||
|
||||
// Restore LED
|
||||
led_set(orig_color);
|
||||
|
||||
// Do we have a timeout?
|
||||
if (*timer_status == 0) {
|
||||
return false;
|
||||
}
|
||||
|
||||
// Stop timer
|
||||
*timer_ctrl |= (1 << TK1_MMIO_TIMER_CTRL_STOP_BIT);
|
||||
|
||||
// Confirm touch event
|
||||
*touch = 0;
|
||||
|
||||
return true;
|
||||
}
|
53
hw/application_fpga/tkey-libs/libcrt0/crt0.S
Normal file
53
hw/application_fpga/tkey-libs/libcrt0/crt0.S
Normal file
@ -0,0 +1,53 @@
|
||||
// SPDX-FileCopyrightText: 2022 Tillitis AB <tillitis.se>
|
||||
// SPDX-License-Identifier: BSD-2-Clause
|
||||
|
||||
.section ".text.init"
|
||||
.global _start
|
||||
_start:
|
||||
li x1, 0
|
||||
li x2, 0
|
||||
li x3, 0
|
||||
li x4, 0
|
||||
li x5, 0
|
||||
li x6, 0
|
||||
li x7, 0
|
||||
li x8, 0
|
||||
li x9, 0
|
||||
li x10,0
|
||||
li x11,0
|
||||
li x12,0
|
||||
li x13,0
|
||||
li x14,0
|
||||
li x15,0
|
||||
li x16,0
|
||||
li x17,0
|
||||
li x18,0
|
||||
li x19,0
|
||||
li x20,0
|
||||
li x21,0
|
||||
li x22,0
|
||||
li x23,0
|
||||
li x24,0
|
||||
li x25,0
|
||||
li x26,0
|
||||
li x27,0
|
||||
li x28,0
|
||||
li x29,0
|
||||
li x30,0
|
||||
li x31,0
|
||||
|
||||
/* init stack below 0x40020000 (TK1_RAM_BASE+TK1_RAM_SIZE) */
|
||||
li sp, 0x4001fff0
|
||||
|
||||
/* zero-init bss section */
|
||||
la a0, _sbss
|
||||
la a1, _ebss
|
||||
bge a0, a1, end_init_bss
|
||||
|
||||
loop_init_bss:
|
||||
sw zero, 0(a0)
|
||||
addi a0, a0, 4
|
||||
blt a0, a1, loop_init_bss
|
||||
|
||||
end_init_bss:
|
||||
call main
|
116
hw/application_fpga/tkey-libs/monocypher/LICENSE
Normal file
116
hw/application_fpga/tkey-libs/monocypher/LICENSE
Normal file
@ -0,0 +1,116 @@
|
||||
CC0 1.0 Universal
|
||||
|
||||
Statement of Purpose
|
||||
|
||||
The laws of most jurisdictions throughout the world automatically confer
|
||||
exclusive Copyright and Related Rights (defined below) upon the creator and
|
||||
subsequent owner(s) (each and all, an "owner") of an original work of
|
||||
authorship and/or a database (each, a "Work").
|
||||
|
||||
Certain owners wish to permanently relinquish those rights to a Work for the
|
||||
purpose of contributing to a commons of creative, cultural and scientific
|
||||
works ("Commons") that the public can reliably and without fear of later
|
||||
claims of infringement build upon, modify, incorporate in other works, reuse
|
||||
and redistribute as freely as possible in any form whatsoever and for any
|
||||
purposes, including without limitation commercial purposes. These owners may
|
||||
contribute to the Commons to promote the ideal of a free culture and the
|
||||
further production of creative, cultural and scientific works, or to gain
|
||||
reputation or greater distribution for their Work in part through the use and
|
||||
efforts of others.
|
||||
|
||||
For these and/or other purposes and motivations, and without any expectation
|
||||
of additional consideration or compensation, the person associating CC0 with a
|
||||
Work (the "Affirmer"), to the extent that he or she is an owner of Copyright
|
||||
and Related Rights in the Work, voluntarily elects to apply CC0 to the Work
|
||||
and publicly distribute the Work under its terms, with knowledge of his or her
|
||||
Copyright and Related Rights in the Work and the meaning and intended legal
|
||||
effect of CC0 on those rights.
|
||||
|
||||
1. Copyright and Related Rights. A Work made available under CC0 may be
|
||||
protected by copyright and related or neighboring rights ("Copyright and
|
||||
Related Rights"). Copyright and Related Rights include, but are not limited
|
||||
to, the following:
|
||||
|
||||
i. the right to reproduce, adapt, distribute, perform, display, communicate,
|
||||
and translate a Work;
|
||||
|
||||
ii. moral rights retained by the original author(s) and/or performer(s);
|
||||
|
||||
iii. publicity and privacy rights pertaining to a person's image or likeness
|
||||
depicted in a Work;
|
||||
|
||||
iv. rights protecting against unfair competition in regards to a Work,
|
||||
subject to the limitations in paragraph 4(a), below;
|
||||
|
||||
v. rights protecting the extraction, dissemination, use and reuse of data in
|
||||
a Work;
|
||||
|
||||
vi. database rights (such as those arising under Directive 96/9/EC of the
|
||||
European Parliament and of the Council of 11 March 1996 on the legal
|
||||
protection of databases, and under any national implementation thereof,
|
||||
including any amended or successor version of such directive); and
|
||||
|
||||
vii. other similar, equivalent or corresponding rights throughout the world
|
||||
based on applicable law or treaty, and any national implementations thereof.
|
||||
|
||||
2. Waiver. To the greatest extent permitted by, but not in contravention of,
|
||||
applicable law, Affirmer hereby overtly, fully, permanently, irrevocably and
|
||||
unconditionally waives, abandons, and surrenders all of Affirmer's Copyright
|
||||
and Related Rights and associated claims and causes of action, whether now
|
||||
known or unknown (including existing as well as future claims and causes of
|
||||
action), in the Work (i) in all territories worldwide, (ii) for the maximum
|
||||
duration provided by applicable law or treaty (including future time
|
||||
extensions), (iii) in any current or future medium and for any number of
|
||||
copies, and (iv) for any purpose whatsoever, including without limitation
|
||||
commercial, advertising or promotional purposes (the "Waiver"). Affirmer makes
|
||||
the Waiver for the benefit of each member of the public at large and to the
|
||||
detriment of Affirmer's heirs and successors, fully intending that such Waiver
|
||||
shall not be subject to revocation, rescission, cancellation, termination, or
|
||||
any other legal or equitable action to disrupt the quiet enjoyment of the Work
|
||||
by the public as contemplated by Affirmer's express Statement of Purpose.
|
||||
|
||||
3. Public License Fallback. Should any part of the Waiver for any reason be
|
||||
judged legally invalid or ineffective under applicable law, then the Waiver
|
||||
shall be preserved to the maximum extent permitted taking into account
|
||||
Affirmer's express Statement of Purpose. In addition, to the extent the Waiver
|
||||
is so judged Affirmer hereby grants to each affected person a royalty-free,
|
||||
non transferable, non sublicensable, non exclusive, irrevocable and
|
||||
unconditional license to exercise Affirmer's Copyright and Related Rights in
|
||||
the Work (i) in all territories worldwide, (ii) for the maximum duration
|
||||
provided by applicable law or treaty (including future time extensions), (iii)
|
||||
in any current or future medium and for any number of copies, and (iv) for any
|
||||
purpose whatsoever, including without limitation commercial, advertising or
|
||||
promotional purposes (the "License"). The License shall be deemed effective as
|
||||
of the date CC0 was applied by Affirmer to the Work. Should any part of the
|
||||
License for any reason be judged legally invalid or ineffective under
|
||||
applicable law, such partial invalidity or ineffectiveness shall not
|
||||
invalidate the remainder of the License, and in such case Affirmer hereby
|
||||
affirms that he or she will not (i) exercise any of his or her remaining
|
||||
Copyright and Related Rights in the Work or (ii) assert any associated claims
|
||||
and causes of action with respect to the Work, in either case contrary to
|
||||
Affirmer's express Statement of Purpose.
|
||||
|
||||
4. Limitations and Disclaimers.
|
||||
|
||||
a. No trademark or patent rights held by Affirmer are waived, abandoned,
|
||||
surrendered, licensed or otherwise affected by this document.
|
||||
|
||||
b. Affirmer offers the Work as-is and makes no representations or warranties
|
||||
of any kind concerning the Work, express, implied, statutory or otherwise,
|
||||
including without limitation warranties of title, merchantability, fitness
|
||||
for a particular purpose, non infringement, or the absence of latent or
|
||||
other defects, accuracy, or the present or absence of errors, whether or not
|
||||
discoverable, all to the greatest extent permissible under applicable law.
|
||||
|
||||
c. Affirmer disclaims responsibility for clearing rights of other persons
|
||||
that may apply to the Work or any use thereof, including without limitation
|
||||
any person's Copyright and Related Rights in the Work. Further, Affirmer
|
||||
disclaims responsibility for obtaining any necessary consents, permissions
|
||||
or other rights required for any use of the Work.
|
||||
|
||||
d. Affirmer understands and acknowledges that Creative Commons is not a
|
||||
party to this document and has no duty or obligation with respect to this
|
||||
CC0 or use of the Work.
|
||||
|
||||
For more information, please see
|
||||
<http://creativecommons.org/publicdomain/zero/1.0/>
|
5
hw/application_fpga/tkey-libs/monocypher/README.md
Normal file
5
hw/application_fpga/tkey-libs/monocypher/README.md
Normal file
@ -0,0 +1,5 @@
|
||||
# Monocypher
|
||||
|
||||
A ed25519 implementation from https://github.com/LoupVaillant/Monocypher
|
||||
|
||||
Small changes made for building.
|
500
hw/application_fpga/tkey-libs/monocypher/monocypher-ed25519.c
Normal file
500
hw/application_fpga/tkey-libs/monocypher/monocypher-ed25519.c
Normal file
@ -0,0 +1,500 @@
|
||||
// Monocypher version 4.0.2
|
||||
//
|
||||
// This file is dual-licensed. Choose whichever licence you want from
|
||||
// the two licences listed below.
|
||||
//
|
||||
// The first licence is a regular 2-clause BSD licence. The second licence
|
||||
// is the CC-0 from Creative Commons. It is intended to release Monocypher
|
||||
// to the public domain. The BSD licence serves as a fallback option.
|
||||
//
|
||||
// SPDX-License-Identifier: BSD-2-Clause OR CC0-1.0
|
||||
//
|
||||
// ------------------------------------------------------------------------
|
||||
//
|
||||
// Copyright (c) 2017-2019, Loup Vaillant
|
||||
// All rights reserved.
|
||||
//
|
||||
//
|
||||
// Redistribution and use in source and binary forms, with or without
|
||||
// modification, are permitted provided that the following conditions are
|
||||
// met:
|
||||
//
|
||||
// 1. Redistributions of source code must retain the above copyright
|
||||
// notice, this list of conditions and the following disclaimer.
|
||||
//
|
||||
// 2. Redistributions in binary form must reproduce the above copyright
|
||||
// notice, this list of conditions and the following disclaimer in the
|
||||
// documentation and/or other materials provided with the
|
||||
// distribution.
|
||||
//
|
||||
// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
|
||||
// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
|
||||
// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
|
||||
// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
|
||||
// HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
|
||||
// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
|
||||
// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
|
||||
// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
|
||||
// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
|
||||
// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
|
||||
// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
//
|
||||
// ------------------------------------------------------------------------
|
||||
//
|
||||
// Written in 2017-2019 by Loup Vaillant
|
||||
//
|
||||
// To the extent possible under law, the author(s) have dedicated all copyright
|
||||
// and related neighboring rights to this software to the public domain
|
||||
// worldwide. This software is distributed without any warranty.
|
||||
//
|
||||
// You should have received a copy of the CC0 Public Domain Dedication along
|
||||
// with this software. If not, see
|
||||
// <https://creativecommons.org/publicdomain/zero/1.0/>
|
||||
|
||||
#include "monocypher-ed25519.h"
|
||||
|
||||
#ifdef MONOCYPHER_CPP_NAMESPACE
|
||||
namespace MONOCYPHER_CPP_NAMESPACE {
|
||||
#endif
|
||||
|
||||
/////////////////
|
||||
/// Utilities ///
|
||||
/////////////////
|
||||
#define FOR(i, min, max) for (size_t i = min; i < max; i++)
|
||||
#define COPY(dst, src, size) FOR(_i_, 0, size) (dst)[_i_] = (src)[_i_]
|
||||
#define ZERO(buf, size) FOR(_i_, 0, size) (buf)[_i_] = 0
|
||||
#define WIPE_CTX(ctx) crypto_wipe(ctx , sizeof(*(ctx)))
|
||||
#define WIPE_BUFFER(buffer) crypto_wipe(buffer, sizeof(buffer))
|
||||
#define MIN(a, b) ((a) <= (b) ? (a) : (b))
|
||||
typedef uint8_t u8;
|
||||
typedef uint64_t u64;
|
||||
|
||||
// Returns the smallest positive integer y such that
|
||||
// (x + y) % pow_2 == 0
|
||||
// Basically, it's how many bytes we need to add to "align" x.
|
||||
// Only works when pow_2 is a power of 2.
|
||||
// Note: we use ~x+1 instead of -x to avoid compiler warnings
|
||||
static size_t align(size_t x, size_t pow_2)
|
||||
{
|
||||
return (~x + 1) & (pow_2 - 1);
|
||||
}
|
||||
|
||||
static u64 load64_be(const u8 s[8])
|
||||
{
|
||||
return((u64)s[0] << 56)
|
||||
| ((u64)s[1] << 48)
|
||||
| ((u64)s[2] << 40)
|
||||
| ((u64)s[3] << 32)
|
||||
| ((u64)s[4] << 24)
|
||||
| ((u64)s[5] << 16)
|
||||
| ((u64)s[6] << 8)
|
||||
| (u64)s[7];
|
||||
}
|
||||
|
||||
static void store64_be(u8 out[8], u64 in)
|
||||
{
|
||||
out[0] = (in >> 56) & 0xff;
|
||||
out[1] = (in >> 48) & 0xff;
|
||||
out[2] = (in >> 40) & 0xff;
|
||||
out[3] = (in >> 32) & 0xff;
|
||||
out[4] = (in >> 24) & 0xff;
|
||||
out[5] = (in >> 16) & 0xff;
|
||||
out[6] = (in >> 8) & 0xff;
|
||||
out[7] = in & 0xff;
|
||||
}
|
||||
|
||||
static void load64_be_buf (u64 *dst, const u8 *src, size_t size) {
|
||||
FOR(i, 0, size) { dst[i] = load64_be(src + i*8); }
|
||||
}
|
||||
|
||||
///////////////
|
||||
/// SHA 512 ///
|
||||
///////////////
|
||||
static u64 rot(u64 x, int c ) { return (x >> c) | (x << (64 - c)); }
|
||||
static u64 ch (u64 x, u64 y, u64 z) { return (x & y) ^ (~x & z); }
|
||||
static u64 maj(u64 x, u64 y, u64 z) { return (x & y) ^ ( x & z) ^ (y & z); }
|
||||
static u64 big_sigma0(u64 x) { return rot(x, 28) ^ rot(x, 34) ^ rot(x, 39); }
|
||||
static u64 big_sigma1(u64 x) { return rot(x, 14) ^ rot(x, 18) ^ rot(x, 41); }
|
||||
static u64 lit_sigma0(u64 x) { return rot(x, 1) ^ rot(x, 8) ^ (x >> 7); }
|
||||
static u64 lit_sigma1(u64 x) { return rot(x, 19) ^ rot(x, 61) ^ (x >> 6); }
|
||||
|
||||
static const u64 K[80] = {
|
||||
0x428a2f98d728ae22,0x7137449123ef65cd,0xb5c0fbcfec4d3b2f,0xe9b5dba58189dbbc,
|
||||
0x3956c25bf348b538,0x59f111f1b605d019,0x923f82a4af194f9b,0xab1c5ed5da6d8118,
|
||||
0xd807aa98a3030242,0x12835b0145706fbe,0x243185be4ee4b28c,0x550c7dc3d5ffb4e2,
|
||||
0x72be5d74f27b896f,0x80deb1fe3b1696b1,0x9bdc06a725c71235,0xc19bf174cf692694,
|
||||
0xe49b69c19ef14ad2,0xefbe4786384f25e3,0x0fc19dc68b8cd5b5,0x240ca1cc77ac9c65,
|
||||
0x2de92c6f592b0275,0x4a7484aa6ea6e483,0x5cb0a9dcbd41fbd4,0x76f988da831153b5,
|
||||
0x983e5152ee66dfab,0xa831c66d2db43210,0xb00327c898fb213f,0xbf597fc7beef0ee4,
|
||||
0xc6e00bf33da88fc2,0xd5a79147930aa725,0x06ca6351e003826f,0x142929670a0e6e70,
|
||||
0x27b70a8546d22ffc,0x2e1b21385c26c926,0x4d2c6dfc5ac42aed,0x53380d139d95b3df,
|
||||
0x650a73548baf63de,0x766a0abb3c77b2a8,0x81c2c92e47edaee6,0x92722c851482353b,
|
||||
0xa2bfe8a14cf10364,0xa81a664bbc423001,0xc24b8b70d0f89791,0xc76c51a30654be30,
|
||||
0xd192e819d6ef5218,0xd69906245565a910,0xf40e35855771202a,0x106aa07032bbd1b8,
|
||||
0x19a4c116b8d2d0c8,0x1e376c085141ab53,0x2748774cdf8eeb99,0x34b0bcb5e19b48a8,
|
||||
0x391c0cb3c5c95a63,0x4ed8aa4ae3418acb,0x5b9cca4f7763e373,0x682e6ff3d6b2b8a3,
|
||||
0x748f82ee5defb2fc,0x78a5636f43172f60,0x84c87814a1f0ab72,0x8cc702081a6439ec,
|
||||
0x90befffa23631e28,0xa4506cebde82bde9,0xbef9a3f7b2c67915,0xc67178f2e372532b,
|
||||
0xca273eceea26619c,0xd186b8c721c0c207,0xeada7dd6cde0eb1e,0xf57d4f7fee6ed178,
|
||||
0x06f067aa72176fba,0x0a637dc5a2c898a6,0x113f9804bef90dae,0x1b710b35131c471b,
|
||||
0x28db77f523047d84,0x32caab7b40c72493,0x3c9ebe0a15c9bebc,0x431d67c49c100d4c,
|
||||
0x4cc5d4becb3e42b6,0x597f299cfc657e2a,0x5fcb6fab3ad6faec,0x6c44198c4a475817
|
||||
};
|
||||
|
||||
static void sha512_compress(crypto_sha512_ctx *ctx)
|
||||
{
|
||||
u64 a = ctx->hash[0]; u64 b = ctx->hash[1];
|
||||
u64 c = ctx->hash[2]; u64 d = ctx->hash[3];
|
||||
u64 e = ctx->hash[4]; u64 f = ctx->hash[5];
|
||||
u64 g = ctx->hash[6]; u64 h = ctx->hash[7];
|
||||
|
||||
FOR (j, 0, 16) {
|
||||
u64 in = K[j] + ctx->input[j];
|
||||
u64 t1 = big_sigma1(e) + ch (e, f, g) + h + in;
|
||||
u64 t2 = big_sigma0(a) + maj(a, b, c);
|
||||
h = g; g = f; f = e; e = d + t1;
|
||||
d = c; c = b; b = a; a = t1 + t2;
|
||||
}
|
||||
size_t i16 = 0;
|
||||
FOR(i, 1, 5) {
|
||||
i16 += 16;
|
||||
FOR (j, 0, 16) {
|
||||
ctx->input[j] += lit_sigma1(ctx->input[(j- 2) & 15]);
|
||||
ctx->input[j] += lit_sigma0(ctx->input[(j-15) & 15]);
|
||||
ctx->input[j] += ctx->input[(j- 7) & 15];
|
||||
u64 in = K[i16 + j] + ctx->input[j];
|
||||
u64 t1 = big_sigma1(e) + ch (e, f, g) + h + in;
|
||||
u64 t2 = big_sigma0(a) + maj(a, b, c);
|
||||
h = g; g = f; f = e; e = d + t1;
|
||||
d = c; c = b; b = a; a = t1 + t2;
|
||||
}
|
||||
}
|
||||
|
||||
ctx->hash[0] += a; ctx->hash[1] += b;
|
||||
ctx->hash[2] += c; ctx->hash[3] += d;
|
||||
ctx->hash[4] += e; ctx->hash[5] += f;
|
||||
ctx->hash[6] += g; ctx->hash[7] += h;
|
||||
}
|
||||
|
||||
// Write 1 input byte
|
||||
static void sha512_set_input(crypto_sha512_ctx *ctx, u8 input)
|
||||
{
|
||||
size_t word = ctx->input_idx >> 3;
|
||||
size_t byte = ctx->input_idx & 7;
|
||||
ctx->input[word] |= (u64)input << (8 * (7 - byte));
|
||||
}
|
||||
|
||||
// Increment a 128-bit "word".
|
||||
static void sha512_incr(u64 x[2], u64 y)
|
||||
{
|
||||
x[1] += y;
|
||||
if (x[1] < y) {
|
||||
x[0]++;
|
||||
}
|
||||
}
|
||||
|
||||
void crypto_sha512_init(crypto_sha512_ctx *ctx)
|
||||
{
|
||||
ctx->hash[0] = 0x6a09e667f3bcc908;
|
||||
ctx->hash[1] = 0xbb67ae8584caa73b;
|
||||
ctx->hash[2] = 0x3c6ef372fe94f82b;
|
||||
ctx->hash[3] = 0xa54ff53a5f1d36f1;
|
||||
ctx->hash[4] = 0x510e527fade682d1;
|
||||
ctx->hash[5] = 0x9b05688c2b3e6c1f;
|
||||
ctx->hash[6] = 0x1f83d9abfb41bd6b;
|
||||
ctx->hash[7] = 0x5be0cd19137e2179;
|
||||
ctx->input_size[0] = 0;
|
||||
ctx->input_size[1] = 0;
|
||||
ctx->input_idx = 0;
|
||||
ZERO(ctx->input, 16);
|
||||
}
|
||||
|
||||
void crypto_sha512_update(crypto_sha512_ctx *ctx,
|
||||
const u8 *message, size_t message_size)
|
||||
{
|
||||
// Avoid undefined NULL pointer increments with empty messages
|
||||
if (message_size == 0) {
|
||||
return;
|
||||
}
|
||||
|
||||
// Align ourselves with word boundaries
|
||||
if ((ctx->input_idx & 7) != 0) {
|
||||
size_t nb_bytes = MIN(align(ctx->input_idx, 8), message_size);
|
||||
FOR (i, 0, nb_bytes) {
|
||||
sha512_set_input(ctx, message[i]);
|
||||
ctx->input_idx++;
|
||||
}
|
||||
message += nb_bytes;
|
||||
message_size -= nb_bytes;
|
||||
}
|
||||
|
||||
// Align ourselves with block boundaries
|
||||
if ((ctx->input_idx & 127) != 0) {
|
||||
size_t nb_words = MIN(align(ctx->input_idx, 128), message_size) >> 3;
|
||||
load64_be_buf(ctx->input + (ctx->input_idx >> 3), message, nb_words);
|
||||
ctx->input_idx += nb_words << 3;
|
||||
message += nb_words << 3;
|
||||
message_size -= nb_words << 3;
|
||||
}
|
||||
|
||||
// Compress block if needed
|
||||
if (ctx->input_idx == 128) {
|
||||
sha512_incr(ctx->input_size, 1024); // size is in bits
|
||||
sha512_compress(ctx);
|
||||
ctx->input_idx = 0;
|
||||
ZERO(ctx->input, 16);
|
||||
}
|
||||
|
||||
// Process the message block by block
|
||||
FOR (i, 0, message_size >> 7) { // number of blocks
|
||||
load64_be_buf(ctx->input, message, 16);
|
||||
sha512_incr(ctx->input_size, 1024); // size is in bits
|
||||
sha512_compress(ctx);
|
||||
ctx->input_idx = 0;
|
||||
ZERO(ctx->input, 16);
|
||||
message += 128;
|
||||
}
|
||||
message_size &= 127;
|
||||
|
||||
if (message_size != 0) {
|
||||
// Remaining words
|
||||
size_t nb_words = message_size >> 3;
|
||||
load64_be_buf(ctx->input, message, nb_words);
|
||||
ctx->input_idx += nb_words << 3;
|
||||
message += nb_words << 3;
|
||||
message_size -= nb_words << 3;
|
||||
|
||||
// Remaining bytes
|
||||
FOR (i, 0, message_size) {
|
||||
sha512_set_input(ctx, message[i]);
|
||||
ctx->input_idx++;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void crypto_sha512_final(crypto_sha512_ctx *ctx, u8 hash[64])
|
||||
{
|
||||
// Add padding bit
|
||||
if (ctx->input_idx == 0) {
|
||||
ZERO(ctx->input, 16);
|
||||
}
|
||||
sha512_set_input(ctx, 128);
|
||||
|
||||
// Update size
|
||||
sha512_incr(ctx->input_size, ctx->input_idx * 8);
|
||||
|
||||
// Compress penultimate block (if any)
|
||||
if (ctx->input_idx > 111) {
|
||||
sha512_compress(ctx);
|
||||
ZERO(ctx->input, 14);
|
||||
}
|
||||
// Compress last block
|
||||
ctx->input[14] = ctx->input_size[0];
|
||||
ctx->input[15] = ctx->input_size[1];
|
||||
sha512_compress(ctx);
|
||||
|
||||
// Copy hash to output (big endian)
|
||||
FOR (i, 0, 8) {
|
||||
store64_be(hash + i*8, ctx->hash[i]);
|
||||
}
|
||||
|
||||
WIPE_CTX(ctx);
|
||||
}
|
||||
|
||||
void crypto_sha512(u8 hash[64], const u8 *message, size_t message_size)
|
||||
{
|
||||
crypto_sha512_ctx ctx;
|
||||
crypto_sha512_init (&ctx);
|
||||
crypto_sha512_update(&ctx, message, message_size);
|
||||
crypto_sha512_final (&ctx, hash);
|
||||
}
|
||||
|
||||
////////////////////
|
||||
/// HMAC SHA 512 ///
|
||||
////////////////////
|
||||
void crypto_sha512_hmac_init(crypto_sha512_hmac_ctx *ctx,
|
||||
const u8 *key, size_t key_size)
|
||||
{
|
||||
// hash key if it is too long
|
||||
if (key_size > 128) {
|
||||
crypto_sha512(ctx->key, key, key_size);
|
||||
key = ctx->key;
|
||||
key_size = 64;
|
||||
}
|
||||
// Compute inner key: padded key XOR 0x36
|
||||
FOR (i, 0, key_size) { ctx->key[i] = key[i] ^ 0x36; }
|
||||
FOR (i, key_size, 128) { ctx->key[i] = 0x36; }
|
||||
// Start computing inner hash
|
||||
crypto_sha512_init (&ctx->ctx);
|
||||
crypto_sha512_update(&ctx->ctx, ctx->key, 128);
|
||||
}
|
||||
|
||||
void crypto_sha512_hmac_update(crypto_sha512_hmac_ctx *ctx,
|
||||
const u8 *message, size_t message_size)
|
||||
{
|
||||
crypto_sha512_update(&ctx->ctx, message, message_size);
|
||||
}
|
||||
|
||||
void crypto_sha512_hmac_final(crypto_sha512_hmac_ctx *ctx, u8 hmac[64])
|
||||
{
|
||||
// Finish computing inner hash
|
||||
crypto_sha512_final(&ctx->ctx, hmac);
|
||||
// Compute outer key: padded key XOR 0x5c
|
||||
FOR (i, 0, 128) {
|
||||
ctx->key[i] ^= 0x36 ^ 0x5c;
|
||||
}
|
||||
// Compute outer hash
|
||||
crypto_sha512_init (&ctx->ctx);
|
||||
crypto_sha512_update(&ctx->ctx, ctx->key , 128);
|
||||
crypto_sha512_update(&ctx->ctx, hmac, 64);
|
||||
crypto_sha512_final (&ctx->ctx, hmac); // outer hash
|
||||
WIPE_CTX(ctx);
|
||||
}
|
||||
|
||||
void crypto_sha512_hmac(u8 hmac[64], const u8 *key, size_t key_size,
|
||||
const u8 *message, size_t message_size)
|
||||
{
|
||||
crypto_sha512_hmac_ctx ctx;
|
||||
crypto_sha512_hmac_init (&ctx, key, key_size);
|
||||
crypto_sha512_hmac_update(&ctx, message, message_size);
|
||||
crypto_sha512_hmac_final (&ctx, hmac);
|
||||
}
|
||||
|
||||
////////////////////
|
||||
/// HKDF SHA 512 ///
|
||||
////////////////////
|
||||
void crypto_sha512_hkdf_expand(u8 *okm, size_t okm_size,
|
||||
const u8 *prk, size_t prk_size,
|
||||
const u8 *info, size_t info_size)
|
||||
{
|
||||
int not_first = 0;
|
||||
u8 ctr = 1;
|
||||
u8 blk[64];
|
||||
|
||||
while (okm_size > 0) {
|
||||
size_t out_size = MIN(okm_size, sizeof(blk));
|
||||
|
||||
crypto_sha512_hmac_ctx ctx;
|
||||
crypto_sha512_hmac_init(&ctx, prk , prk_size);
|
||||
if (not_first) {
|
||||
// For some reason HKDF uses some kind of CBC mode.
|
||||
// For some reason CTR mode alone wasn't enough.
|
||||
// Like what, they didn't trust HMAC in 2010? Really??
|
||||
crypto_sha512_hmac_update(&ctx, blk , sizeof(blk));
|
||||
}
|
||||
crypto_sha512_hmac_update(&ctx, info, info_size);
|
||||
crypto_sha512_hmac_update(&ctx, &ctr, 1);
|
||||
crypto_sha512_hmac_final(&ctx, blk);
|
||||
|
||||
COPY(okm, blk, out_size);
|
||||
|
||||
not_first = 1;
|
||||
okm += out_size;
|
||||
okm_size -= out_size;
|
||||
ctr++;
|
||||
}
|
||||
}
|
||||
|
||||
void crypto_sha512_hkdf(u8 *okm , size_t okm_size,
|
||||
const u8 *ikm , size_t ikm_size,
|
||||
const u8 *salt, size_t salt_size,
|
||||
const u8 *info, size_t info_size)
|
||||
{
|
||||
// Extract
|
||||
u8 prk[64];
|
||||
crypto_sha512_hmac(prk, salt, salt_size, ikm, ikm_size);
|
||||
|
||||
// Expand
|
||||
crypto_sha512_hkdf_expand(okm, okm_size, prk, sizeof(prk), info, info_size);
|
||||
}
|
||||
|
||||
///////////////
|
||||
/// Ed25519 ///
|
||||
///////////////
|
||||
void crypto_ed25519_key_pair(u8 secret_key[64], u8 public_key[32], u8 seed[32])
|
||||
{
|
||||
u8 a[64];
|
||||
COPY(a, seed, 32); // a[ 0..31] = seed
|
||||
crypto_wipe(seed, 32);
|
||||
COPY(secret_key, a, 32); // secret key = seed
|
||||
crypto_sha512(a, a, 32); // a[ 0..31] = scalar
|
||||
crypto_eddsa_trim_scalar(a, a); // a[ 0..31] = trimmed scalar
|
||||
crypto_eddsa_scalarbase(public_key, a); // public key = [trimmed scalar]B
|
||||
COPY(secret_key + 32, public_key, 32); // secret key includes public half
|
||||
WIPE_BUFFER(a);
|
||||
}
|
||||
|
||||
static void hash_reduce(u8 h[32],
|
||||
const u8 *a, size_t a_size,
|
||||
const u8 *b, size_t b_size,
|
||||
const u8 *c, size_t c_size,
|
||||
const u8 *d, size_t d_size)
|
||||
{
|
||||
u8 hash[64];
|
||||
crypto_sha512_ctx ctx;
|
||||
crypto_sha512_init (&ctx);
|
||||
crypto_sha512_update(&ctx, a, a_size);
|
||||
crypto_sha512_update(&ctx, b, b_size);
|
||||
crypto_sha512_update(&ctx, c, c_size);
|
||||
crypto_sha512_update(&ctx, d, d_size);
|
||||
crypto_sha512_final (&ctx, hash);
|
||||
crypto_eddsa_reduce(h, hash);
|
||||
}
|
||||
|
||||
static void ed25519_dom_sign(u8 signature [64], const u8 secret_key[32],
|
||||
const u8 *dom, size_t dom_size,
|
||||
const u8 *message, size_t message_size)
|
||||
{
|
||||
u8 a[64]; // secret scalar and prefix
|
||||
u8 r[32]; // secret deterministic "random" nonce
|
||||
u8 h[32]; // publically verifiable hash of the message (not wiped)
|
||||
u8 R[32]; // first half of the signature (allows overlapping inputs)
|
||||
const u8 *pk = secret_key + 32;
|
||||
|
||||
crypto_sha512(a, secret_key, 32);
|
||||
crypto_eddsa_trim_scalar(a, a);
|
||||
hash_reduce(r, dom, dom_size, a + 32, 32, message, message_size, 0, 0);
|
||||
crypto_eddsa_scalarbase(R, r);
|
||||
hash_reduce(h, dom, dom_size, R, 32, pk, 32, message, message_size);
|
||||
COPY(signature, R, 32);
|
||||
crypto_eddsa_mul_add(signature + 32, h, a, r);
|
||||
|
||||
WIPE_BUFFER(a);
|
||||
WIPE_BUFFER(r);
|
||||
}
|
||||
|
||||
void crypto_ed25519_sign(u8 signature [64], const u8 secret_key[64],
|
||||
const u8 *message, size_t message_size)
|
||||
{
|
||||
ed25519_dom_sign(signature, secret_key, 0, 0, message, message_size);
|
||||
}
|
||||
|
||||
int crypto_ed25519_check(const u8 signature[64], const u8 public_key[32],
|
||||
const u8 *msg, size_t msg_size)
|
||||
{
|
||||
u8 h_ram[32];
|
||||
hash_reduce(h_ram, signature, 32, public_key, 32, msg, msg_size, 0, 0);
|
||||
return crypto_eddsa_check_equation(signature, public_key, h_ram);
|
||||
}
|
||||
|
||||
static const u8 domain[34] = "SigEd25519 no Ed25519 collisions\1";
|
||||
|
||||
void crypto_ed25519_ph_sign(uint8_t signature[64], const uint8_t secret_key[64],
|
||||
const uint8_t message_hash[64])
|
||||
{
|
||||
ed25519_dom_sign(signature, secret_key, domain, sizeof(domain),
|
||||
message_hash, 64);
|
||||
}
|
||||
|
||||
int crypto_ed25519_ph_check(const uint8_t sig[64], const uint8_t pk[32],
|
||||
const uint8_t msg_hash[64])
|
||||
{
|
||||
u8 h_ram[32];
|
||||
hash_reduce(h_ram, domain, sizeof(domain), sig, 32, pk, 32, msg_hash, 64);
|
||||
return crypto_eddsa_check_equation(sig, pk, h_ram);
|
||||
}
|
||||
|
||||
|
||||
#ifdef MONOCYPHER_CPP_NAMESPACE
|
||||
}
|
||||
#endif
|
140
hw/application_fpga/tkey-libs/monocypher/monocypher-ed25519.h
Normal file
140
hw/application_fpga/tkey-libs/monocypher/monocypher-ed25519.h
Normal file
@ -0,0 +1,140 @@
|
||||
// Monocypher version 4.0.2
|
||||
//
|
||||
// This file is dual-licensed. Choose whichever licence you want from
|
||||
// the two licences listed below.
|
||||
//
|
||||
// The first licence is a regular 2-clause BSD licence. The second licence
|
||||
// is the CC-0 from Creative Commons. It is intended to release Monocypher
|
||||
// to the public domain. The BSD licence serves as a fallback option.
|
||||
//
|
||||
// SPDX-License-Identifier: BSD-2-Clause OR CC0-1.0
|
||||
//
|
||||
// ------------------------------------------------------------------------
|
||||
//
|
||||
// Copyright (c) 2017-2019, Loup Vaillant
|
||||
// All rights reserved.
|
||||
//
|
||||
//
|
||||
// Redistribution and use in source and binary forms, with or without
|
||||
// modification, are permitted provided that the following conditions are
|
||||
// met:
|
||||
//
|
||||
// 1. Redistributions of source code must retain the above copyright
|
||||
// notice, this list of conditions and the following disclaimer.
|
||||
//
|
||||
// 2. Redistributions in binary form must reproduce the above copyright
|
||||
// notice, this list of conditions and the following disclaimer in the
|
||||
// documentation and/or other materials provided with the
|
||||
// distribution.
|
||||
//
|
||||
// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
|
||||
// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
|
||||
// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
|
||||
// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
|
||||
// HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
|
||||
// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
|
||||
// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
|
||||
// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
|
||||
// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
|
||||
// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
|
||||
// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
//
|
||||
// ------------------------------------------------------------------------
|
||||
//
|
||||
// Written in 2017-2019 by Loup Vaillant
|
||||
//
|
||||
// To the extent possible under law, the author(s) have dedicated all copyright
|
||||
// and related neighboring rights to this software to the public domain
|
||||
// worldwide. This software is distributed without any warranty.
|
||||
//
|
||||
// You should have received a copy of the CC0 Public Domain Dedication along
|
||||
// with this software. If not, see
|
||||
// <https://creativecommons.org/publicdomain/zero/1.0/>
|
||||
|
||||
#ifndef ED25519_H
|
||||
#define ED25519_H
|
||||
|
||||
#include "monocypher.h"
|
||||
|
||||
#ifdef MONOCYPHER_CPP_NAMESPACE
|
||||
namespace MONOCYPHER_CPP_NAMESPACE {
|
||||
#elif defined(__cplusplus)
|
||||
extern "C" {
|
||||
#endif
|
||||
|
||||
////////////////////////
|
||||
/// Type definitions ///
|
||||
////////////////////////
|
||||
|
||||
// Do not rely on the size or content on any of those types,
|
||||
// they may change without notice.
|
||||
typedef struct {
|
||||
uint64_t hash[8];
|
||||
uint64_t input[16];
|
||||
uint64_t input_size[2];
|
||||
size_t input_idx;
|
||||
} crypto_sha512_ctx;
|
||||
|
||||
typedef struct {
|
||||
uint8_t key[128];
|
||||
crypto_sha512_ctx ctx;
|
||||
} crypto_sha512_hmac_ctx;
|
||||
|
||||
|
||||
// SHA 512
|
||||
// -------
|
||||
void crypto_sha512_init (crypto_sha512_ctx *ctx);
|
||||
void crypto_sha512_update(crypto_sha512_ctx *ctx,
|
||||
const uint8_t *message, size_t message_size);
|
||||
void crypto_sha512_final (crypto_sha512_ctx *ctx, uint8_t hash[64]);
|
||||
void crypto_sha512(uint8_t hash[64],
|
||||
const uint8_t *message, size_t message_size);
|
||||
|
||||
// SHA 512 HMAC
|
||||
// ------------
|
||||
void crypto_sha512_hmac_init(crypto_sha512_hmac_ctx *ctx,
|
||||
const uint8_t *key, size_t key_size);
|
||||
void crypto_sha512_hmac_update(crypto_sha512_hmac_ctx *ctx,
|
||||
const uint8_t *message, size_t message_size);
|
||||
void crypto_sha512_hmac_final(crypto_sha512_hmac_ctx *ctx, uint8_t hmac[64]);
|
||||
void crypto_sha512_hmac(uint8_t hmac[64],
|
||||
const uint8_t *key , size_t key_size,
|
||||
const uint8_t *message, size_t message_size);
|
||||
|
||||
// SHA 512 HKDF
|
||||
// ------------
|
||||
void crypto_sha512_hkdf_expand(uint8_t *okm, size_t okm_size,
|
||||
const uint8_t *prk, size_t prk_size,
|
||||
const uint8_t *info, size_t info_size);
|
||||
void crypto_sha512_hkdf(uint8_t *okm , size_t okm_size,
|
||||
const uint8_t *ikm , size_t ikm_size,
|
||||
const uint8_t *salt, size_t salt_size,
|
||||
const uint8_t *info, size_t info_size);
|
||||
|
||||
// Ed25519
|
||||
// -------
|
||||
// Signatures (EdDSA with curve25519 + SHA-512)
|
||||
// --------------------------------------------
|
||||
void crypto_ed25519_key_pair(uint8_t secret_key[64],
|
||||
uint8_t public_key[32],
|
||||
uint8_t seed[32]);
|
||||
void crypto_ed25519_sign(uint8_t signature [64],
|
||||
const uint8_t secret_key[64],
|
||||
const uint8_t *message, size_t message_size);
|
||||
int crypto_ed25519_check(const uint8_t signature [64],
|
||||
const uint8_t public_key[32],
|
||||
const uint8_t *message, size_t message_size);
|
||||
|
||||
// Pre-hash variants
|
||||
void crypto_ed25519_ph_sign(uint8_t signature [64],
|
||||
const uint8_t secret_key [64],
|
||||
const uint8_t message_hash[64]);
|
||||
int crypto_ed25519_ph_check(const uint8_t signature [64],
|
||||
const uint8_t public_key [32],
|
||||
const uint8_t message_hash[64]);
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#endif
|
||||
|
||||
#endif // ED25519_H
|
2956
hw/application_fpga/tkey-libs/monocypher/monocypher.c
Normal file
2956
hw/application_fpga/tkey-libs/monocypher/monocypher.c
Normal file
File diff suppressed because it is too large
Load Diff
321
hw/application_fpga/tkey-libs/monocypher/monocypher.h
Normal file
321
hw/application_fpga/tkey-libs/monocypher/monocypher.h
Normal file
@ -0,0 +1,321 @@
|
||||
// Monocypher version 4.0.2
|
||||
//
|
||||
// This file is dual-licensed. Choose whichever licence you want from
|
||||
// the two licences listed below.
|
||||
//
|
||||
// The first licence is a regular 2-clause BSD licence. The second licence
|
||||
// is the CC-0 from Creative Commons. It is intended to release Monocypher
|
||||
// to the public domain. The BSD licence serves as a fallback option.
|
||||
//
|
||||
// SPDX-License-Identifier: BSD-2-Clause OR CC0-1.0
|
||||
//
|
||||
// ------------------------------------------------------------------------
|
||||
//
|
||||
// Copyright (c) 2017-2019, Loup Vaillant
|
||||
// All rights reserved.
|
||||
//
|
||||
//
|
||||
// Redistribution and use in source and binary forms, with or without
|
||||
// modification, are permitted provided that the following conditions are
|
||||
// met:
|
||||
//
|
||||
// 1. Redistributions of source code must retain the above copyright
|
||||
// notice, this list of conditions and the following disclaimer.
|
||||
//
|
||||
// 2. Redistributions in binary form must reproduce the above copyright
|
||||
// notice, this list of conditions and the following disclaimer in the
|
||||
// documentation and/or other materials provided with the
|
||||
// distribution.
|
||||
//
|
||||
// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
|
||||
// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
|
||||
// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
|
||||
// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
|
||||
// HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
|
||||
// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
|
||||
// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
|
||||
// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
|
||||
// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
|
||||
// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
|
||||
// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
//
|
||||
// ------------------------------------------------------------------------
|
||||
//
|
||||
// Written in 2017-2019 by Loup Vaillant
|
||||
//
|
||||
// To the extent possible under law, the author(s) have dedicated all copyright
|
||||
// and related neighboring rights to this software to the public domain
|
||||
// worldwide. This software is distributed without any warranty.
|
||||
//
|
||||
// You should have received a copy of the CC0 Public Domain Dedication along
|
||||
// with this software. If not, see
|
||||
// <https://creativecommons.org/publicdomain/zero/1.0/>
|
||||
|
||||
#ifndef MONOCYPHER_H
|
||||
#define MONOCYPHER_H
|
||||
|
||||
#include <stddef.h>
|
||||
#include <stdint.h>
|
||||
|
||||
#ifdef MONOCYPHER_CPP_NAMESPACE
|
||||
namespace MONOCYPHER_CPP_NAMESPACE {
|
||||
#elif defined(__cplusplus)
|
||||
extern "C" {
|
||||
#endif
|
||||
|
||||
// Constant time comparisons
|
||||
// -------------------------
|
||||
|
||||
// Return 0 if a and b are equal, -1 otherwise
|
||||
int crypto_verify16(const uint8_t a[16], const uint8_t b[16]);
|
||||
int crypto_verify32(const uint8_t a[32], const uint8_t b[32]);
|
||||
int crypto_verify64(const uint8_t a[64], const uint8_t b[64]);
|
||||
|
||||
|
||||
// Erase sensitive data
|
||||
// --------------------
|
||||
void crypto_wipe(void *secret, size_t size);
|
||||
|
||||
|
||||
// Authenticated encryption
|
||||
// ------------------------
|
||||
void crypto_aead_lock(uint8_t *cipher_text,
|
||||
uint8_t mac [16],
|
||||
const uint8_t key [32],
|
||||
const uint8_t nonce[24],
|
||||
const uint8_t *ad, size_t ad_size,
|
||||
const uint8_t *plain_text, size_t text_size);
|
||||
int crypto_aead_unlock(uint8_t *plain_text,
|
||||
const uint8_t mac [16],
|
||||
const uint8_t key [32],
|
||||
const uint8_t nonce[24],
|
||||
const uint8_t *ad, size_t ad_size,
|
||||
const uint8_t *cipher_text, size_t text_size);
|
||||
|
||||
// Authenticated stream
|
||||
// --------------------
|
||||
typedef struct {
|
||||
uint64_t counter;
|
||||
uint8_t key[32];
|
||||
uint8_t nonce[8];
|
||||
} crypto_aead_ctx;
|
||||
|
||||
void crypto_aead_init_x(crypto_aead_ctx *ctx,
|
||||
const uint8_t key[32], const uint8_t nonce[24]);
|
||||
void crypto_aead_init_djb(crypto_aead_ctx *ctx,
|
||||
const uint8_t key[32], const uint8_t nonce[8]);
|
||||
void crypto_aead_init_ietf(crypto_aead_ctx *ctx,
|
||||
const uint8_t key[32], const uint8_t nonce[12]);
|
||||
|
||||
void crypto_aead_write(crypto_aead_ctx *ctx,
|
||||
uint8_t *cipher_text,
|
||||
uint8_t mac[16],
|
||||
const uint8_t *ad , size_t ad_size,
|
||||
const uint8_t *plain_text, size_t text_size);
|
||||
int crypto_aead_read(crypto_aead_ctx *ctx,
|
||||
uint8_t *plain_text,
|
||||
const uint8_t mac[16],
|
||||
const uint8_t *ad , size_t ad_size,
|
||||
const uint8_t *cipher_text, size_t text_size);
|
||||
|
||||
|
||||
// General purpose hash (BLAKE2b)
|
||||
// ------------------------------
|
||||
|
||||
// Direct interface
|
||||
void crypto_blake2b(uint8_t *hash, size_t hash_size,
|
||||
const uint8_t *message, size_t message_size);
|
||||
|
||||
void crypto_blake2b_keyed(uint8_t *hash, size_t hash_size,
|
||||
const uint8_t *key, size_t key_size,
|
||||
const uint8_t *message, size_t message_size);
|
||||
|
||||
// Incremental interface
|
||||
typedef struct {
|
||||
// Do not rely on the size or contents of this type,
|
||||
// for they may change without notice.
|
||||
uint64_t hash[8];
|
||||
uint64_t input_offset[2];
|
||||
uint64_t input[16];
|
||||
size_t input_idx;
|
||||
size_t hash_size;
|
||||
} crypto_blake2b_ctx;
|
||||
|
||||
void crypto_blake2b_init(crypto_blake2b_ctx *ctx, size_t hash_size);
|
||||
void crypto_blake2b_keyed_init(crypto_blake2b_ctx *ctx, size_t hash_size,
|
||||
const uint8_t *key, size_t key_size);
|
||||
void crypto_blake2b_update(crypto_blake2b_ctx *ctx,
|
||||
const uint8_t *message, size_t message_size);
|
||||
void crypto_blake2b_final(crypto_blake2b_ctx *ctx, uint8_t *hash);
|
||||
|
||||
|
||||
// Password key derivation (Argon2)
|
||||
// --------------------------------
|
||||
#define CRYPTO_ARGON2_D 0
|
||||
#define CRYPTO_ARGON2_I 1
|
||||
#define CRYPTO_ARGON2_ID 2
|
||||
|
||||
typedef struct {
|
||||
uint32_t algorithm; // Argon2d, Argon2i, Argon2id
|
||||
uint32_t nb_blocks; // memory hardness, >= 8 * nb_lanes
|
||||
uint32_t nb_passes; // CPU hardness, >= 1 (>= 3 recommended for Argon2i)
|
||||
uint32_t nb_lanes; // parallelism level (single threaded anyway)
|
||||
} crypto_argon2_config;
|
||||
|
||||
typedef struct {
|
||||
const uint8_t *pass;
|
||||
const uint8_t *salt;
|
||||
uint32_t pass_size;
|
||||
uint32_t salt_size; // 16 bytes recommended
|
||||
} crypto_argon2_inputs;
|
||||
|
||||
typedef struct {
|
||||
const uint8_t *key; // may be NULL if no key
|
||||
const uint8_t *ad; // may be NULL if no additional data
|
||||
uint32_t key_size; // 0 if no key (32 bytes recommended otherwise)
|
||||
uint32_t ad_size; // 0 if no additional data
|
||||
} crypto_argon2_extras;
|
||||
|
||||
extern const crypto_argon2_extras crypto_argon2_no_extras;
|
||||
|
||||
void crypto_argon2(uint8_t *hash, uint32_t hash_size, void *work_area,
|
||||
crypto_argon2_config config,
|
||||
crypto_argon2_inputs inputs,
|
||||
crypto_argon2_extras extras);
|
||||
|
||||
|
||||
// Key exchange (X-25519)
|
||||
// ----------------------
|
||||
|
||||
// Shared secrets are not quite random.
|
||||
// Hash them to derive an actual shared key.
|
||||
void crypto_x25519_public_key(uint8_t public_key[32],
|
||||
const uint8_t secret_key[32]);
|
||||
void crypto_x25519(uint8_t raw_shared_secret[32],
|
||||
const uint8_t your_secret_key [32],
|
||||
const uint8_t their_public_key [32]);
|
||||
|
||||
// Conversion to EdDSA
|
||||
void crypto_x25519_to_eddsa(uint8_t eddsa[32], const uint8_t x25519[32]);
|
||||
|
||||
// scalar "division"
|
||||
// Used for OPRF. Be aware that exponential blinding is less secure
|
||||
// than Diffie-Hellman key exchange.
|
||||
void crypto_x25519_inverse(uint8_t blind_salt [32],
|
||||
const uint8_t private_key[32],
|
||||
const uint8_t curve_point[32]);
|
||||
|
||||
// "Dirty" versions of x25519_public_key().
|
||||
// Use with crypto_elligator_rev().
|
||||
// Leaks 3 bits of the private key.
|
||||
void crypto_x25519_dirty_small(uint8_t pk[32], const uint8_t sk[32]);
|
||||
void crypto_x25519_dirty_fast (uint8_t pk[32], const uint8_t sk[32]);
|
||||
|
||||
|
||||
// Signatures
|
||||
// ----------
|
||||
|
||||
// EdDSA with curve25519 + BLAKE2b
|
||||
void crypto_eddsa_key_pair(uint8_t secret_key[64],
|
||||
uint8_t public_key[32],
|
||||
uint8_t seed[32]);
|
||||
void crypto_eddsa_sign(uint8_t signature [64],
|
||||
const uint8_t secret_key[64],
|
||||
const uint8_t *message, size_t message_size);
|
||||
int crypto_eddsa_check(const uint8_t signature [64],
|
||||
const uint8_t public_key[32],
|
||||
const uint8_t *message, size_t message_size);
|
||||
|
||||
// Conversion to X25519
|
||||
void crypto_eddsa_to_x25519(uint8_t x25519[32], const uint8_t eddsa[32]);
|
||||
|
||||
// EdDSA building blocks
|
||||
void crypto_eddsa_trim_scalar(uint8_t out[32], const uint8_t in[32]);
|
||||
void crypto_eddsa_reduce(uint8_t reduced[32], const uint8_t expanded[64]);
|
||||
void crypto_eddsa_mul_add(uint8_t r[32],
|
||||
const uint8_t a[32],
|
||||
const uint8_t b[32],
|
||||
const uint8_t c[32]);
|
||||
void crypto_eddsa_scalarbase(uint8_t point[32], const uint8_t scalar[32]);
|
||||
int crypto_eddsa_check_equation(const uint8_t signature[64],
|
||||
const uint8_t public_key[32],
|
||||
const uint8_t h_ram[32]);
|
||||
|
||||
|
||||
// Chacha20
|
||||
// --------
|
||||
|
||||
// Specialised hash.
|
||||
// Used to hash X25519 shared secrets.
|
||||
void crypto_chacha20_h(uint8_t out[32],
|
||||
const uint8_t key[32],
|
||||
const uint8_t in [16]);
|
||||
|
||||
// Unauthenticated stream cipher.
|
||||
// Don't forget to add authentication.
|
||||
uint64_t crypto_chacha20_djb(uint8_t *cipher_text,
|
||||
const uint8_t *plain_text,
|
||||
size_t text_size,
|
||||
const uint8_t key[32],
|
||||
const uint8_t nonce[8],
|
||||
uint64_t ctr);
|
||||
uint32_t crypto_chacha20_ietf(uint8_t *cipher_text,
|
||||
const uint8_t *plain_text,
|
||||
size_t text_size,
|
||||
const uint8_t key[32],
|
||||
const uint8_t nonce[12],
|
||||
uint32_t ctr);
|
||||
uint64_t crypto_chacha20_x(uint8_t *cipher_text,
|
||||
const uint8_t *plain_text,
|
||||
size_t text_size,
|
||||
const uint8_t key[32],
|
||||
const uint8_t nonce[24],
|
||||
uint64_t ctr);
|
||||
|
||||
|
||||
// Poly 1305
|
||||
// ---------
|
||||
|
||||
// This is a *one time* authenticator.
|
||||
// Disclosing the mac reveals the key.
|
||||
// See crypto_lock() on how to use it properly.
|
||||
|
||||
// Direct interface
|
||||
void crypto_poly1305(uint8_t mac[16],
|
||||
const uint8_t *message, size_t message_size,
|
||||
const uint8_t key[32]);
|
||||
|
||||
// Incremental interface
|
||||
typedef struct {
|
||||
// Do not rely on the size or contents of this type,
|
||||
// for they may change without notice.
|
||||
uint8_t c[16]; // chunk of the message
|
||||
size_t c_idx; // How many bytes are there in the chunk.
|
||||
uint32_t r [4]; // constant multiplier (from the secret key)
|
||||
uint32_t pad[4]; // random number added at the end (from the secret key)
|
||||
uint32_t h [5]; // accumulated hash
|
||||
} crypto_poly1305_ctx;
|
||||
|
||||
void crypto_poly1305_init (crypto_poly1305_ctx *ctx, const uint8_t key[32]);
|
||||
void crypto_poly1305_update(crypto_poly1305_ctx *ctx,
|
||||
const uint8_t *message, size_t message_size);
|
||||
void crypto_poly1305_final (crypto_poly1305_ctx *ctx, uint8_t mac[16]);
|
||||
|
||||
|
||||
// Elligator 2
|
||||
// -----------
|
||||
|
||||
// Elligator mappings proper
|
||||
void crypto_elligator_map(uint8_t curve [32], const uint8_t hidden[32]);
|
||||
int crypto_elligator_rev(uint8_t hidden[32], const uint8_t curve [32],
|
||||
uint8_t tweak);
|
||||
|
||||
// Easy to use key pair generation
|
||||
void crypto_elligator_key_pair(uint8_t hidden[32], uint8_t secret_key[32],
|
||||
uint8_t seed[32]);
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#endif
|
||||
|
||||
#endif // MONOCYPHER_H
|
93
hw/application_fpga/tkey-libs/tools/spdx-ensure
Executable file
93
hw/application_fpga/tkey-libs/tools/spdx-ensure
Executable file
@ -0,0 +1,93 @@
|
||||
#!/bin/bash
|
||||
# SPDX-FileCopyrightText: 2022 Tillitis AB <tillitis.se>
|
||||
# SPDX-License-Identifier: BSD-2-Clause
|
||||
set -eu
|
||||
|
||||
# Check for the SPDX tag in all files in the repo. Exit with a non-zero code if
|
||||
# some is missing. The missingok arrays below contain files and directories
|
||||
# with files where the the tag is not required.
|
||||
|
||||
cd "${0%/*}"
|
||||
cd ..
|
||||
|
||||
tag="SPDX-License-Identifier:"
|
||||
|
||||
missingok_dirs=(
|
||||
.github/workflows/
|
||||
LICENSES/
|
||||
)
|
||||
|
||||
missingok_files=(
|
||||
.clang-format
|
||||
.editorconfig
|
||||
.gitignore
|
||||
LICENSE
|
||||
Makefile
|
||||
README.md
|
||||
README-DIST.txt
|
||||
RELEASE.md
|
||||
example-app/Makefile
|
||||
monocypher/LICENSE
|
||||
monocypher/README.md
|
||||
blake2s/*
|
||||
)
|
||||
|
||||
is_missingok() {
|
||||
item="$1"
|
||||
# ok for empty files
|
||||
[[ -f "$item" ]] && [[ ! -s "$item" ]] && return 0
|
||||
for fileok in "${missingok_files[@]}"; do
|
||||
[[ "$item" = "$fileok" ]] && return 0
|
||||
done
|
||||
for dirok in "${missingok_dirs[@]}"; do
|
||||
[[ "$item" =~ ^$dirok ]] && return 0
|
||||
done
|
||||
return 1
|
||||
}
|
||||
|
||||
printf "* Checking for SPDX tags in %s\n" "$PWD"
|
||||
|
||||
mapfile -t repofiles < <(git ls-files || true)
|
||||
if [[ -z "${repofiles[*]}" ]]; then
|
||||
printf "* No files in the repo?!\n"
|
||||
exit 1
|
||||
fi
|
||||
|
||||
failed=0
|
||||
|
||||
printed=0
|
||||
for fileok in "${missingok_files[@]}"; do
|
||||
[[ -f "$fileok" ]] && continue
|
||||
if (( !printed )); then
|
||||
printf "* Some files in missingok_files are themselves missing:\n"
|
||||
printed=1
|
||||
failed=1
|
||||
fi
|
||||
printf "%s\n" "$fileok"
|
||||
done
|
||||
|
||||
printed=0
|
||||
for dirok in "${missingok_dirs[@]}"; do
|
||||
[[ -d "$dirok" ]] && continue
|
||||
if (( !printed )); then
|
||||
printf "* Some dirs in missingok_dirs are themselves missing:\n"
|
||||
printed=1
|
||||
failed=1
|
||||
fi
|
||||
printf "%s\n" "$dirok"
|
||||
done
|
||||
|
||||
printed=0
|
||||
for file in "${repofiles[@]}"; do
|
||||
is_missingok "$file" && continue
|
||||
if ! grep -q "$tag" "$file"; then
|
||||
if (( !printed )); then
|
||||
printf "* Files missing the SPDX tag:\n"
|
||||
printed=1
|
||||
failed=1
|
||||
fi
|
||||
printf "%s\n" "$file"
|
||||
fi
|
||||
done
|
||||
|
||||
exit "$failed"
|
@ -1,19 +0,0 @@
|
||||
Copyright 2017 WCH
|
||||
Device ID modifications copyright 2023 Tillitis AB
|
||||
|
||||
Permission is hereby granted, free of charge, to any person obtaining a copy of
|
||||
this software and associated documentation files (the "Software"), to deal in
|
||||
the Software without restriction, including without limitation the rights to
|
||||
use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of
|
||||
the Software, and to permit persons to whom the Software is furnished to do so,
|
||||
subject to the following conditions:
|
||||
|
||||
The above copyright notice and this permission notice shall be included in all
|
||||
copies or substantial portions of the Software.
|
||||
|
||||
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS
|
||||
FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR
|
||||
COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER
|
||||
IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
|
||||
CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
|
117
hw/usb_interface/ch552_fw/LICENSES/GPL-2.0-only.txt
Normal file
117
hw/usb_interface/ch552_fw/LICENSES/GPL-2.0-only.txt
Normal file
@ -0,0 +1,117 @@
|
||||
GNU GENERAL PUBLIC LICENSE
|
||||
Version 2, June 1991
|
||||
|
||||
Copyright (C) 1989, 1991 Free Software Foundation, Inc.
|
||||
51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA
|
||||
|
||||
Everyone is permitted to copy and distribute verbatim copies of this license document, but changing it is not allowed.
|
||||
|
||||
Preamble
|
||||
|
||||
The licenses for most software are designed to take away your freedom to share and change it. By contrast, the GNU General Public License is intended to guarantee your freedom to share and change free software--to make sure the software is free for all its users. This General Public License applies to most of the Free Software Foundation's software and to any other program whose authors commit to using it. (Some other Free Software Foundation software is covered by the GNU Lesser General Public License instead.) You can apply it to your programs, too.
|
||||
|
||||
When we speak of free software, we are referring to freedom, not price. Our General Public Licenses are designed to make sure that you have the freedom to distribute copies of free software (and charge for this service if you wish), that you receive source code or can get it if you want it, that you can change the software or use pieces of it in new free programs; and that you know you can do these things.
|
||||
|
||||
To protect your rights, we need to make restrictions that forbid anyone to deny you these rights or to ask you to surrender the rights. These restrictions translate to certain responsibilities for you if you distribute copies of the software, or if you modify it.
|
||||
|
||||
For example, if you distribute copies of such a program, whether gratis or for a fee, you must give the recipients all the rights that you have. You must make sure that they, too, receive or can get the source code. And you must show them these terms so they know their rights.
|
||||
|
||||
We protect your rights with two steps: (1) copyright the software, and (2) offer you this license which gives you legal permission to copy, distribute and/or modify the software.
|
||||
|
||||
Also, for each author's protection and ours, we want to make certain that everyone understands that there is no warranty for this free software. If the software is modified by someone else and passed on, we want its recipients to know that what they have is not the original, so that any problems introduced by others will not reflect on the original authors' reputations.
|
||||
|
||||
Finally, any free program is threatened constantly by software patents. We wish to avoid the danger that redistributors of a free program will individually obtain patent licenses, in effect making the program proprietary. To prevent this, we have made it clear that any patent must be licensed for everyone's free use or not licensed at all.
|
||||
|
||||
The precise terms and conditions for copying, distribution and modification follow.
|
||||
|
||||
TERMS AND CONDITIONS FOR COPYING, DISTRIBUTION AND MODIFICATION
|
||||
|
||||
0. This License applies to any program or other work which contains a notice placed by the copyright holder saying it may be distributed under the terms of this General Public License. The "Program", below, refers to any such program or work, and a "work based on the Program" means either the Program or any derivative work under copyright law: that is to say, a work containing the Program or a portion of it, either verbatim or with modifications and/or translated into another language. (Hereinafter, translation is included without limitation in the term "modification".) Each licensee is addressed as "you".
|
||||
|
||||
Activities other than copying, distribution and modification are not covered by this License; they are outside its scope. The act of running the Program is not restricted, and the output from the Program is covered only if its contents constitute a work based on the Program (independent of having been made by running the Program). Whether that is true depends on what the Program does.
|
||||
|
||||
1. You may copy and distribute verbatim copies of the Program's source code as you receive it, in any medium, provided that you conspicuously and appropriately publish on each copy an appropriate copyright notice and disclaimer of warranty; keep intact all the notices that refer to this License and to the absence of any warranty; and give any other recipients of the Program a copy of this License along with the Program.
|
||||
|
||||
You may charge a fee for the physical act of transferring a copy, and you may at your option offer warranty protection in exchange for a fee.
|
||||
|
||||
2. You may modify your copy or copies of the Program or any portion of it, thus forming a work based on the Program, and copy and distribute such modifications or work under the terms of Section 1 above, provided that you also meet all of these conditions:
|
||||
|
||||
a) You must cause the modified files to carry prominent notices stating that you changed the files and the date of any change.
|
||||
|
||||
b) You must cause any work that you distribute or publish, that in whole or in part contains or is derived from the Program or any part thereof, to be licensed as a whole at no charge to all third parties under the terms of this License.
|
||||
|
||||
c) If the modified program normally reads commands interactively when run, you must cause it, when started running for such interactive use in the most ordinary way, to print or display an announcement including an appropriate copyright notice and a notice that there is no warranty (or else, saying that you provide a warranty) and that users may redistribute the program under these conditions, and telling the user how to view a copy of this License. (Exception: if the Program itself is interactive but does not normally print such an announcement, your work based on the Program is not required to print an announcement.)
|
||||
|
||||
These requirements apply to the modified work as a whole. If identifiable sections of that work are not derived from the Program, and can be reasonably considered independent and separate works in themselves, then this License, and its terms, do not apply to those sections when you distribute them as separate works. But when you distribute the same sections as part of a whole which is a work based on the Program, the distribution of the whole must be on the terms of this License, whose permissions for other licensees extend to the entire whole, and thus to each and every part regardless of who wrote it.
|
||||
|
||||
Thus, it is not the intent of this section to claim rights or contest your rights to work written entirely by you; rather, the intent is to exercise the right to control the distribution of derivative or collective works based on the Program.
|
||||
|
||||
In addition, mere aggregation of another work not based on the Program with the Program (or with a work based on the Program) on a volume of a storage or distribution medium does not bring the other work under the scope of this License.
|
||||
|
||||
3. You may copy and distribute the Program (or a work based on it, under Section 2) in object code or executable form under the terms of Sections 1 and 2 above provided that you also do one of the following:
|
||||
|
||||
a) Accompany it with the complete corresponding machine-readable source code, which must be distributed under the terms of Sections 1 and 2 above on a medium customarily used for software interchange; or,
|
||||
|
||||
b) Accompany it with a written offer, valid for at least three years, to give any third party, for a charge no more than your cost of physically performing source distribution, a complete machine-readable copy of the corresponding source code, to be distributed under the terms of Sections 1 and 2 above on a medium customarily used for software interchange; or,
|
||||
|
||||
c) Accompany it with the information you received as to the offer to distribute corresponding source code. (This alternative is allowed only for noncommercial distribution and only if you received the program in object code or executable form with such an offer, in accord with Subsection b above.)
|
||||
|
||||
The source code for a work means the preferred form of the work for making modifications to it. For an executable work, complete source code means all the source code for all modules it contains, plus any associated interface definition files, plus the scripts used to control compilation and installation of the executable. However, as a special exception, the source code distributed need not include anything that is normally distributed (in either source or binary form) with the major components (compiler, kernel, and so on) of the operating system on which the executable runs, unless that component itself accompanies the executable.
|
||||
|
||||
If distribution of executable or object code is made by offering access to copy from a designated place, then offering equivalent access to copy the source code from the same place counts as distribution of the source code, even though third parties are not compelled to copy the source along with the object code.
|
||||
|
||||
4. You may not copy, modify, sublicense, or distribute the Program except as expressly provided under this License. Any attempt otherwise to copy, modify, sublicense or distribute the Program is void, and will automatically terminate your rights under this License. However, parties who have received copies, or rights, from you under this License will not have their licenses terminated so long as such parties remain in full compliance.
|
||||
|
||||
5. You are not required to accept this License, since you have not signed it. However, nothing else grants you permission to modify or distribute the Program or its derivative works. These actions are prohibited by law if you do not accept this License. Therefore, by modifying or distributing the Program (or any work based on the Program), you indicate your acceptance of this License to do so, and all its terms and conditions for copying, distributing or modifying the Program or works based on it.
|
||||
|
||||
6. Each time you redistribute the Program (or any work based on the Program), the recipient automatically receives a license from the original licensor to copy, distribute or modify the Program subject to these terms and conditions. You may not impose any further restrictions on the recipients' exercise of the rights granted herein. You are not responsible for enforcing compliance by third parties to this License.
|
||||
|
||||
7. If, as a consequence of a court judgment or allegation of patent infringement or for any other reason (not limited to patent issues), conditions are imposed on you (whether by court order, agreement or otherwise) that contradict the conditions of this License, they do not excuse you from the conditions of this License. If you cannot distribute so as to satisfy simultaneously your obligations under this License and any other pertinent obligations, then as a consequence you may not distribute the Program at all. For example, if a patent license would not permit royalty-free redistribution of the Program by all those who receive copies directly or indirectly through you, then the only way you could satisfy both it and this License would be to refrain entirely from distribution of the Program.
|
||||
|
||||
If any portion of this section is held invalid or unenforceable under any particular circumstance, the balance of the section is intended to apply and the section as a whole is intended to apply in other circumstances.
|
||||
|
||||
It is not the purpose of this section to induce you to infringe any patents or other property right claims or to contest validity of any such claims; this section has the sole purpose of protecting the integrity of the free software distribution system, which is implemented by public license practices. Many people have made generous contributions to the wide range of software distributed through that system in reliance on consistent application of that system; it is up to the author/donor to decide if he or she is willing to distribute software through any other system and a licensee cannot impose that choice.
|
||||
|
||||
This section is intended to make thoroughly clear what is believed to be a consequence of the rest of this License.
|
||||
|
||||
8. If the distribution and/or use of the Program is restricted in certain countries either by patents or by copyrighted interfaces, the original copyright holder who places the Program under this License may add an explicit geographical distribution limitation excluding those countries, so that distribution is permitted only in or among countries not thus excluded. In such case, this License incorporates the limitation as if written in the body of this License.
|
||||
|
||||
9. The Free Software Foundation may publish revised and/or new versions of the General Public License from time to time. Such new versions will be similar in spirit to the present version, but may differ in detail to address new problems or concerns.
|
||||
|
||||
Each version is given a distinguishing version number. If the Program specifies a version number of this License which applies to it and "any later version", you have the option of following the terms and conditions either of that version or of any later version published by the Free Software Foundation. If the Program does not specify a version number of this License, you may choose any version ever published by the Free Software Foundation.
|
||||
|
||||
10. If you wish to incorporate parts of the Program into other free programs whose distribution conditions are different, write to the author to ask for permission. For software which is copyrighted by the Free Software Foundation, write to the Free Software Foundation; we sometimes make exceptions for this. Our decision will be guided by the two goals of preserving the free status of all derivatives of our free software and of promoting the sharing and reuse of software generally.
|
||||
|
||||
NO WARRANTY
|
||||
|
||||
11. BECAUSE THE PROGRAM IS LICENSED FREE OF CHARGE, THERE IS NO WARRANTY FOR THE PROGRAM, TO THE EXTENT PERMITTED BY APPLICABLE LAW. EXCEPT WHEN OTHERWISE STATED IN WRITING THE COPYRIGHT HOLDERS AND/OR OTHER PARTIES PROVIDE THE PROGRAM "AS IS" WITHOUT WARRANTY OF ANY KIND, EITHER EXPRESSED OR IMPLIED, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. THE ENTIRE RISK AS TO THE QUALITY AND PERFORMANCE OF THE PROGRAM IS WITH YOU. SHOULD THE PROGRAM PROVE DEFECTIVE, YOU ASSUME THE COST OF ALL NECESSARY SERVICING, REPAIR OR CORRECTION.
|
||||
|
||||
12. IN NO EVENT UNLESS REQUIRED BY APPLICABLE LAW OR AGREED TO IN WRITING WILL ANY COPYRIGHT HOLDER, OR ANY OTHER PARTY WHO MAY MODIFY AND/OR REDISTRIBUTE THE PROGRAM AS PERMITTED ABOVE, BE LIABLE TO YOU FOR DAMAGES, INCLUDING ANY GENERAL, SPECIAL, INCIDENTAL OR CONSEQUENTIAL DAMAGES ARISING OUT OF THE USE OR INABILITY TO USE THE PROGRAM (INCLUDING BUT NOT LIMITED TO LOSS OF DATA OR DATA BEING RENDERED INACCURATE OR LOSSES SUSTAINED BY YOU OR THIRD PARTIES OR A FAILURE OF THE PROGRAM TO OPERATE WITH ANY OTHER PROGRAMS), EVEN IF SUCH HOLDER OR OTHER PARTY HAS BEEN ADVISED OF THE POSSIBILITY OF SUCH DAMAGES.
|
||||
|
||||
END OF TERMS AND CONDITIONS
|
||||
|
||||
How to Apply These Terms to Your New Programs
|
||||
|
||||
If you develop a new program, and you want it to be of the greatest possible use to the public, the best way to achieve this is to make it free software which everyone can redistribute and change under these terms.
|
||||
|
||||
To do so, attach the following notices to the program. It is safest to attach them to the start of each source file to most effectively convey the exclusion of warranty; and each file should have at least the "copyright" line and a pointer to where the full notice is found.
|
||||
|
||||
one line to give the program's name and an idea of what it does. Copyright (C) yyyy name of author
|
||||
|
||||
This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation; either version 2 of the License, or (at your option) any later version.
|
||||
|
||||
This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details.
|
||||
|
||||
You should have received a copy of the GNU General Public License along with this program; if not, write to the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. Also add information on how to contact you by electronic and paper mail.
|
||||
|
||||
If the program is interactive, make it output a short notice like this when it starts in an interactive mode:
|
||||
|
||||
Gnomovision version 69, Copyright (C) year name of author Gnomovision comes with ABSOLUTELY NO WARRANTY; for details type `show w'. This is free software, and you are welcome to redistribute it under certain conditions; type `show c' for details.
|
||||
|
||||
The hypothetical commands `show w' and `show c' should show the appropriate parts of the General Public License. Of course, the commands you use may be called something other than `show w' and `show c'; they could even be mouse-clicks or menu items--whatever suits your program.
|
||||
|
||||
You should also get your employer (if you work as a programmer) or your school, if any, to sign a "copyright disclaimer" for the program, if necessary. Here is a sample; alter the names:
|
||||
|
||||
Yoyodyne, Inc., hereby disclaims all copyright interest in the program `Gnomovision' (which makes passes at compilers) written by James Hacker.
|
||||
|
||||
signature of Ty Coon, 1 April 1989 Ty Coon, President of Vice
|
18
hw/usb_interface/ch552_fw/LICENSES/MIT.txt
Normal file
18
hw/usb_interface/ch552_fw/LICENSES/MIT.txt
Normal file
@ -0,0 +1,18 @@
|
||||
MIT License
|
||||
|
||||
Copyright (c) <year> <copyright holders>
|
||||
|
||||
Permission is hereby granted, free of charge, to any person obtaining a copy of this software and
|
||||
associated documentation files (the "Software"), to deal in the Software without restriction, including
|
||||
without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||
copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the
|
||||
following conditions:
|
||||
|
||||
The above copyright notice and this permission notice shall be included in all copies or substantial
|
||||
portions of the Software.
|
||||
|
||||
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT
|
||||
LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO
|
||||
EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER
|
||||
IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE
|
||||
USE OR OTHER DEALINGS IN THE SOFTWARE.
|
@ -1,37 +1,87 @@
|
||||
TARGET = usb_device_cdc
|
||||
#######################################################
|
||||
|
||||
CH554_SDCC=~/ch554_sdcc/
|
||||
# Toolchain
|
||||
CC = sdcc
|
||||
OBJCOPY = objcopy
|
||||
PACK_HEX = packihx
|
||||
CHPROG = chprog
|
||||
|
||||
# Adjust the XRAM location and size to leave space for the USB DMA buffers
|
||||
# Buffer layout in XRAM:
|
||||
# 0x0000 Ep0Buffer[8]
|
||||
# 0x0040 Ep1Buffer[8]
|
||||
# 0x0080 EP2Buffer[2*64]
|
||||
#
|
||||
# This takes a total of 256bytes, so there are 768 bytes left.
|
||||
#XRAM_SIZE = 0x0300
|
||||
#XRAM_LOC = 0x0100
|
||||
#######################################################
|
||||
|
||||
XRAM_SIZE = 0x0400
|
||||
XRAM_LOC = 0x0000
|
||||
TARGET = usb_device
|
||||
|
||||
FREQ_SYS = 16000000
|
||||
OUT_DIR = _out
|
||||
|
||||
XRAM_SIZE = 0x0400 # 1 KB on-chip xRAM
|
||||
XRAM_LOC = 0x0000 # xRAM area starts at address 0 in the External Data Address Space
|
||||
CODE_SIZE = 0x3800 # 14 KB program storage area
|
||||
FREQ_SYS = 16000000 # 16 MHz system clock
|
||||
|
||||
EXTRA_FLAGS = -DBUILD_CODE
|
||||
|
||||
CFLAGS = \
|
||||
-V \
|
||||
-mmcs51 \
|
||||
--model-small \
|
||||
--xram-size $(XRAM_SIZE) \
|
||||
--xram-loc $(XRAM_LOC) \
|
||||
--code-size $(CODE_SIZE) \
|
||||
-Iinc \
|
||||
-DFREQ_SYS=$(FREQ_SYS) \
|
||||
$(EXTRA_FLAGS)
|
||||
|
||||
LFLAGS = \
|
||||
$(CFLAGS)
|
||||
|
||||
C_FILES = \
|
||||
src/debug.c \
|
||||
src/flash.c \
|
||||
src/gpio.c \
|
||||
src/lib.c \
|
||||
src/main.c \
|
||||
src/print.c
|
||||
|
||||
# Create a .rel file for each .c file in $(OUT_DIR)/
|
||||
RELS = $(patsubst %.c,$(OUT_DIR)/%.rel,$(C_FILES))
|
||||
|
||||
OUT_SUBDIRS = $(sort $(dir $(RELS)))
|
||||
|
||||
# Ensure out directory exists
|
||||
$(OUT_DIR):
|
||||
mkdir -p $(OUT_SUBDIRS)
|
||||
|
||||
$(OUT_DIR)/%.rel: %.c | $(OUT_DIR)
|
||||
$(CC) -c $(CFLAGS) $< -o $@
|
||||
|
||||
usb_strings.h: encode_usb_strings.py
|
||||
./encode_usb_strings.py
|
||||
|
||||
C_FILES = \
|
||||
main.c \
|
||||
include/debug.c \
|
||||
include/print.c
|
||||
# Compile the final ihx file
|
||||
$(TARGET).ihx: $(RELS)
|
||||
$(CC) $(RELS) $(LFLAGS) -o $(TARGET).ihx
|
||||
|
||||
pre-flash:
|
||||
$(TARGET).hex: $(TARGET).ihx
|
||||
$(PACK_HEX) $(TARGET).ihx > $(TARGET).hex
|
||||
|
||||
$(TARGET).bin: $(TARGET).ihx
|
||||
$(OBJCOPY) -I ihex -O binary $(TARGET).ihx $(TARGET).bin
|
||||
|
||||
flash_patched: usb_device_cdc.bin
|
||||
./inject_serial_number.py -i usb_device_cdc.bin -o patched.bin
|
||||
${CHPROG} patched.bin
|
||||
flash: $(TARGET).bin
|
||||
$(CHPROG) $(TARGET).bin
|
||||
|
||||
flash_patched: $(TARGET).bin
|
||||
./inject_serial_number.py -i $(TARGET).bin -o patched.bin
|
||||
$(CHPROG) patched.bin
|
||||
rm patched.bin
|
||||
|
||||
include Makefile.include
|
||||
.DEFAULT_GOAL := all
|
||||
all: $(TARGET).bin $(TARGET).hex
|
||||
|
||||
clean:
|
||||
rm -rf $(OUT_DIR) \
|
||||
$(TARGET).lk \
|
||||
$(TARGET).map \
|
||||
$(TARGET).mem \
|
||||
$(TARGET).ihx \
|
||||
$(TARGET).hex \
|
||||
$(TARGET).bin
|
||||
|
@ -1,70 +0,0 @@
|
||||
#######################################################
|
||||
|
||||
# toolchain
|
||||
CC = sdcc
|
||||
OBJCOPY = objcopy
|
||||
PACK_HEX = packihx
|
||||
WCHISP ?= wchisptool -g -f
|
||||
|
||||
#######################################################
|
||||
|
||||
EXTRA_FLAGS = -D BUILD_CODE
|
||||
|
||||
FREQ_SYS ?= 24000000
|
||||
|
||||
XRAM_SIZE ?= 0x0400
|
||||
|
||||
XRAM_LOC ?= 0x0000
|
||||
|
||||
CODE_SIZE ?= 0x3800
|
||||
|
||||
ROOT_DIR := $(dir $(abspath $(lastword $(MAKEFILE_LIST))))
|
||||
|
||||
CFLAGS := -V -mmcs51 --model-small \
|
||||
--xram-size $(XRAM_SIZE) --xram-loc $(XRAM_LOC) \
|
||||
--code-size $(CODE_SIZE) \
|
||||
-I$(ROOT_DIR)include -DFREQ_SYS=$(FREQ_SYS) \
|
||||
$(EXTRA_FLAGS)
|
||||
|
||||
LFLAGS := $(CFLAGS)
|
||||
|
||||
RELS := $(C_FILES:.c=.rel)
|
||||
|
||||
print-% : ; @echo $* = $($*)
|
||||
|
||||
%.rel : %.c
|
||||
$(CC) -c $(CFLAGS) $<
|
||||
|
||||
# Note: SDCC will dump all of the temporary files into this one, so strip the paths from RELS
|
||||
# For now, get around this by stripping the paths off of the RELS list.
|
||||
|
||||
$(TARGET).ihx: $(RELS)
|
||||
$(CC) $(notdir $(RELS)) $(LFLAGS) -o $(TARGET).ihx
|
||||
|
||||
$(TARGET).hex: $(TARGET).ihx
|
||||
$(PACK_HEX) $(TARGET).ihx > $(TARGET).hex
|
||||
|
||||
$(TARGET).bin: $(TARGET).ihx
|
||||
$(OBJCOPY) -I ihex -O binary $(TARGET).ihx $(TARGET).bin
|
||||
|
||||
flash: $(TARGET).bin pre-flash
|
||||
$(WCHISP) $(TARGET).bin
|
||||
|
||||
.DEFAULT_GOAL := all
|
||||
all: $(TARGET).bin $(TARGET).hex
|
||||
|
||||
clean:
|
||||
rm -f \
|
||||
$(notdir $(RELS:.rel=.asm)) \
|
||||
$(notdir $(RELS:.rel=.lst)) \
|
||||
$(notdir $(RELS:.rel=.mem)) \
|
||||
$(notdir $(RELS:.rel=.rel)) \
|
||||
$(notdir $(RELS:.rel=.rst)) \
|
||||
$(notdir $(RELS:.rel=.sym)) \
|
||||
$(notdir $(RELS:.rel=.adb)) \
|
||||
$(TARGET).lk \
|
||||
$(TARGET).map \
|
||||
$(TARGET).mem \
|
||||
$(TARGET).ihx \
|
||||
$(TARGET).hex \
|
||||
$(TARGET).bin
|
@ -27,4 +27,38 @@ Flash the firmware to a device:
|
||||
|
||||
## Re-programming the firmware
|
||||
|
||||
By design, once the USB to serial firmware is loaded onto the chip, there isn't an intended way to reflash it using only software. However, if 3.3V is applied to the D+ line through a 10K resistor during power-up, then the CH552 will enter bootloader mode, and a new firmware can be programmed onto the chip. Note that the CH552 flash is only guaranteed for a few hundred flash cycles.
|
||||
By design, once the USB to serial firmware is loaded onto the chip,
|
||||
there isn't an intended way to reflash it using only software.
|
||||
However, if 3.3V is applied to the D+ line through a 10K resistor
|
||||
during power-up, then the CH552 will enter bootloader mode, and a new
|
||||
firmware can be programmed onto the chip.
|
||||
|
||||
The Blinkinlabs CH55x Reset Controller can help you do this:
|
||||
|
||||
https://shop-nl.blinkinlabs.com/products/ch55x-reset-controller
|
||||
|
||||
https://github.com/Blinkinlabs/ch55x_programmer
|
||||
|
||||
Note that the CH552 flash is only guaranteed for a few hundred flash
|
||||
cycles.
|
||||
|
||||
## License
|
||||
|
||||
Originally based on reference firmware for the CH552 by WCH released
|
||||
under the MIT license:
|
||||
|
||||
https://www.wch-ic.com/
|
||||
|
||||
The oldest files Copyright 1999.
|
||||
|
||||
Much changed and added to by Tillitis.
|
||||
|
||||
Check licenses using the reuse tool:
|
||||
|
||||
https://github.com/fsfe/reuse-tool
|
||||
|
||||
Note that so far you need to specify this directory as root, as in:
|
||||
|
||||
```
|
||||
$ reuse --root . lint
|
||||
```
|
||||
|
12
hw/usb_interface/ch552_fw/REUSE.toml
Normal file
12
hw/usb_interface/ch552_fw/REUSE.toml
Normal file
@ -0,0 +1,12 @@
|
||||
# SPDX-FileCopyrightText: 2025 Tillitis AB <tillitis.se>
|
||||
# SPDX-License-Identifier: BSD-2-Clause
|
||||
version = 1
|
||||
|
||||
[[annotations]]
|
||||
path = [
|
||||
".gitignore",
|
||||
"Makefile",
|
||||
"README.md",
|
||||
]
|
||||
SPDX-FileCopyrightText = "2022 Tillitis AB <tillitis.se>"
|
||||
SPDX-License-Identifier = "GPL-2.0-only"
|
Binary file not shown.
@ -1,4 +1,7 @@
|
||||
#!/usr/bin/env python3
|
||||
# SPDX-FileCopyrightText: 2021 Mullvad VPN AB <mullvad.se>
|
||||
# SPDX-FileCopyrightText: 2022 Tillitis AB <tillitis.se>
|
||||
# SPDX-License-Identifier: GPL-2.0-only
|
||||
|
||||
def descriptor_to_string(descriptor):
|
||||
""" Convert a bytes object containing a USB string descriptor into a python string"""
|
||||
@ -20,37 +23,52 @@ def descriptor_to_string(descriptor):
|
||||
def string_to_descriptor(string):
|
||||
""" Convert a python string into a bytes object containing a USB string descriptor"""
|
||||
descriptor = bytearray()
|
||||
descriptor.append(0x00) # placeholder for length
|
||||
descriptor.append(0x03)
|
||||
descriptor.append(0x00) # Placeholder for length
|
||||
descriptor.append(0x03) # Descriptor type (String)
|
||||
descriptor.extend(string.encode('utf-16')[2:]) # crop the BOM
|
||||
descriptor[0] = len(descriptor)
|
||||
descriptor[0] = len(descriptor) # Set length of this descriptor (in bytes)
|
||||
|
||||
return bytes(descriptor)
|
||||
|
||||
def format_descriptor(name, value):
|
||||
descriptor = string_to_descriptor(value)
|
||||
formatted = [
|
||||
'unsigned char FLASH {}[] = {{ // "{}"'.format(name, value), # Add string as a comment
|
||||
' {}, // Length of this descriptor (in bytes)'.format(descriptor[0]),
|
||||
' 0x03, // Descriptor type (String)'
|
||||
]
|
||||
|
||||
formatted.extend(
|
||||
[
|
||||
' ' + ', '.join(
|
||||
["'{}', 0".format(chr(b)) if b != 0x00 else "0x00" for b in descriptor[2 + i:2 + i + 8:2]]
|
||||
) + ','
|
||||
for i in range(0, len(descriptor[2:]), 8) # 8 bytes = 4 characters
|
||||
]
|
||||
)
|
||||
formatted.append('};\n')
|
||||
return '\n'.join(formatted)
|
||||
|
||||
if __name__ == "__main__":
|
||||
manufacturer = 'Tillitis'
|
||||
product = 'MTA1-USB-V1'
|
||||
serial = "68de5d27-e223-4874-bc76-a54d6e84068f"
|
||||
strings = {
|
||||
"ProdDesc": "MTA1-USB-V1",
|
||||
"ManufDesc": "Tillitis",
|
||||
"SerialDesc": "68de5d27-e223-4874-bc76-a54d6e84068f",
|
||||
"CdcCtrlInterfaceDesc": "CDC-Ctrl",
|
||||
"CdcDataInterfaceDesc": "CDC-Data",
|
||||
"FidoInterfaceDesc": "FIDO",
|
||||
"CcidInterfaceDesc": "CCID",
|
||||
"DebugInterfaceDesc": "DEBUG"
|
||||
}
|
||||
|
||||
with open('usb_strings.h', 'w') as f:
|
||||
f.write('#ifndef USB_STRINGS\n')
|
||||
f.write('#define USB_STRINGS\n')
|
||||
|
||||
f.write('unsigned char __code ProdDesc[]={{ // "{}"\n'.format(product))
|
||||
f.write(' ')
|
||||
f.write(', '.join(['0x{:02x}'.format(i) for i in string_to_descriptor(product)]))
|
||||
f.write('\n};\n\n')
|
||||
|
||||
f.write('unsigned char __code ManufDesc[]={{ // "{}"\n'.format(manufacturer))
|
||||
f.write(' ')
|
||||
f.write(', '.join(['0x{:02x}'.format(i) for i in string_to_descriptor(manufacturer)]))
|
||||
f.write('\n};\n\n')
|
||||
|
||||
f.write('unsigned char __code SerialDesc[]={{ // "{}"\n'.format(serial))
|
||||
f.write(' ')
|
||||
f.write(', '.join(['0x{:02x}'.format(i) for i in string_to_descriptor(serial)]))
|
||||
f.write('\n};\n\n')
|
||||
with open('inc/usb_strings.h', 'w') as f:
|
||||
f.write('#ifndef __USB_STRINGS_H__\n')
|
||||
f.write('#define __USB_STRINGS_H__\n')
|
||||
f.write('\n')
|
||||
f.write('#include "mem.h"\n')
|
||||
f.write('\n')
|
||||
|
||||
for name, value in strings.items():
|
||||
f.write(format_descriptor(name, value) + '\n')
|
||||
|
||||
f.write('#endif\n')
|
||||
|
@ -1,3 +1,7 @@
|
||||
// SPDX-FileCopyrightText: 1999 WCH <wch-ic.com>
|
||||
// SPDX-FileCopyrightText: 2022 Tillitis AB <tillitis.se>
|
||||
// SPDX-License-Identifier: MIT
|
||||
|
||||
/*--------------------------------------------------------------------------
|
||||
CH554.H
|
||||
Header file for CH554 microcontrollers.
|
Some files were not shown because too many files have changed in this diff Show More
Loading…
x
Reference in New Issue
Block a user