mirror of
https://github.com/tillitis/tillitis-key1.git
synced 2025-07-04 10:56:42 -04:00
Compare commits
17 commits
Author | SHA1 | Date | |
---|---|---|---|
![]() |
e10f7007a4 | ||
![]() |
93704287d5 | ||
![]() |
ba7df35064 | ||
![]() |
2746070402 | ||
![]() |
b70d42471b | ||
![]() |
8e7108f7ee | ||
![]() |
6e793bea26 | ||
![]() |
d34e8e2c12 | ||
![]() |
91471c2962 | ||
![]() |
0a0f5bcec8 | ||
![]() |
7e859bd06a | ||
![]() |
403013a0e8 | ||
![]() |
c9a7910965 | ||
![]() |
50966f010d | ||
![]() |
e9ddf29ce9 | ||
![]() |
1ff6e0262f | ||
![]() |
81f3195592 |
81 changed files with 1773 additions and 2492 deletions
8
.github/workflows/ci.yaml
vendored
8
.github/workflows/ci.yaml
vendored
|
@ -31,9 +31,6 @@ jobs:
|
||||||
run: |
|
run: |
|
||||||
make checkfmt
|
make checkfmt
|
||||||
|
|
||||||
- name: check for SPDX tags
|
|
||||||
run: ./LICENSES/spdx-ensure
|
|
||||||
|
|
||||||
check-firmware:
|
check-firmware:
|
||||||
runs-on: ubuntu-latest
|
runs-on: ubuntu-latest
|
||||||
container:
|
container:
|
||||||
|
@ -151,3 +148,8 @@ jobs:
|
||||||
- name: check matching hashes for firmware.bin & application_fpga.bin
|
- name: check matching hashes for firmware.bin & application_fpga.bin
|
||||||
working-directory: hw/application_fpga
|
working-directory: hw/application_fpga
|
||||||
run: make check-binary-hashes
|
run: make check-binary-hashes
|
||||||
|
|
||||||
|
|
||||||
|
# TODO? first deal with hw/boards/ and hw/production_test/
|
||||||
|
# - name: check for SPDX tags
|
||||||
|
# run: ./LICENSES/spdx-ensure
|
||||||
|
|
4
.gitignore
vendored
4
.gitignore
vendored
|
@ -28,11 +28,11 @@
|
||||||
/testbench_verilator*
|
/testbench_verilator*
|
||||||
/check.smt2
|
/check.smt2
|
||||||
/check.vcd
|
/check.vcd
|
||||||
/hw/application_fpga/tkey-libs/libblake2s.a
|
|
||||||
/hw/application_fpga/tkey-libs/libcommon.a
|
/hw/application_fpga/tkey-libs/libcommon.a
|
||||||
/hw/application_fpga/tkey-libs/libcrt0.a
|
/hw/application_fpga/tkey-libs/libcrt0.a
|
||||||
/hw/application_fpga/tkey-libs/libmonocypher.a
|
/hw/application_fpga/tkey-libs/libmonocypher.a
|
||||||
/hw/application_fpga/tools/tkeyimage/tkeyimage
|
/hw/application_fpga/tkey-libs/libblake2s.a
|
||||||
|
/hw/application_fpga/tools/partition_table/partition_table
|
||||||
/hw/application_fpga/tools/b2s/b2s
|
/hw/application_fpga/tools/b2s/b2s
|
||||||
synth.json
|
synth.json
|
||||||
synth.txt
|
synth.txt
|
||||||
|
|
|
@ -2,13 +2,11 @@
|
||||||
|
|
||||||
## Main license
|
## Main license
|
||||||
|
|
||||||
Unless otherwise noted, the project sources are copyright Tillitis AB,
|
Unless otherwise noted, the project sources are licensed under the
|
||||||
but you can redistribute it and/or modify it under the terms of the
|
terms and conditions of the "GNU General Public License v2.0 only".
|
||||||
GNU General Public License version 2 as published by the Free Software
|
|
||||||
Foundation. See `gpl-2.0.txt`.
|
|
||||||
|
|
||||||
This directory contains copies of the license texts used by the
|
The `LICENSES/` directory contains copies of the license texts used by
|
||||||
sources included in the project source tree.
|
the sources included in the project source tree.
|
||||||
|
|
||||||
## SPDX
|
## SPDX
|
||||||
|
|
||||||
|
@ -21,21 +19,3 @@ The current set of valid, predefined SPDX identifiers can be found on
|
||||||
the SPDX License List at:
|
the SPDX License List at:
|
||||||
|
|
||||||
https://spdx.org/licenses/
|
https://spdx.org/licenses/
|
||||||
|
|
||||||
## Notable imported projects
|
|
||||||
|
|
||||||
- ch552 firmware: `hw/usb_interface/ch552_fw/`
|
|
||||||
|
|
||||||
Originally by WCH under MIT. Much changed by Tillitis.
|
|
||||||
|
|
||||||
- picorv32: `hw/application_fpga/core/picorv32`
|
|
||||||
|
|
||||||
From https://github.com/YosysHQ/picorv32
|
|
||||||
|
|
||||||
ISC.
|
|
||||||
|
|
||||||
- PicoRV32 custom ops: `hw/application_fpga/fw/tk1/picorv32/`
|
|
||||||
|
|
||||||
- tkey-libs: `hw/application_fpga/tkey-libs/`
|
|
||||||
|
|
||||||
BSD2. From https://github.com/tillitis/tkey-libs
|
|
||||||
|
|
|
@ -1,338 +0,0 @@
|
||||||
GNU GENERAL PUBLIC LICENSE
|
|
||||||
Version 2, June 1991
|
|
||||||
|
|
||||||
Copyright (C) 1989, 1991 Free Software Foundation, Inc.,
|
|
||||||
<https://fsf.org/>
|
|
||||||
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.
|
|
||||||
|
|
||||||
GNU GENERAL PUBLIC LICENSE
|
|
||||||
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 a brief idea of what it does.>
|
|
||||||
Copyright (C) <year> <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, see <https://www.gnu.org/licenses/>.
|
|
||||||
|
|
||||||
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 Moe Ghoul>, 1 April 1989
|
|
||||||
Moe Ghoul, President of Vice
|
|
||||||
|
|
||||||
This General Public License does not permit incorporating your program into
|
|
||||||
proprietary programs. If your program is a subroutine library, you may
|
|
||||||
consider it more useful to permit linking proprietary applications with the
|
|
||||||
library. If this is what you want to do, use the GNU Lesser General
|
|
||||||
Public License instead of this License.
|
|
245
LICENSES/gpl-v2.only.txt
Normal file
245
LICENSES/gpl-v2.only.txt
Normal file
|
@ -0,0 +1,245 @@
|
||||||
|
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.
|
|
@ -16,73 +16,34 @@ LICENSES/
|
||||||
doc/
|
doc/
|
||||||
hw/application_fpga/core/picorv32/
|
hw/application_fpga/core/picorv32/
|
||||||
hw/application_fpga/core/uart/
|
hw/application_fpga/core/uart/
|
||||||
|
hw/application_fpga/fw/tk1/blake2s/
|
||||||
)
|
)
|
||||||
|
|
||||||
missingok_files=(
|
missingok_files=(
|
||||||
.editorconfig
|
.editorconfig
|
||||||
.gitattributes
|
.gitattributes
|
||||||
.gitignore
|
.gitignore
|
||||||
.clang-format
|
|
||||||
README.md
|
README.md
|
||||||
contrib/99-tillitis.rules
|
contrib/99-tillitis.rules
|
||||||
contrib/Dockerfile
|
contrib/Dockerfile
|
||||||
contrib/Makefile
|
contrib/Makefile
|
||||||
contrib/verible.sha512
|
dco.md
|
||||||
|
|
||||||
hw/application_fpga/README.md
|
|
||||||
hw/application_fpga/core/clk_reset_gen/README.md
|
|
||||||
hw/application_fpga/core/fw_ram/README.md
|
|
||||||
hw/application_fpga/core/ram/README.md
|
|
||||||
hw/application_fpga/core/rom/README.md
|
|
||||||
hw/application_fpga/core/tk1/tb/udi.hex
|
|
||||||
hw/application_fpga/core/uds/README.md
|
|
||||||
hw/application_fpga/fw/README.md
|
|
||||||
hw/application_fpga/fw/tk1/picorv32/README.md
|
|
||||||
hw/application_fpga/apps/Makefile
|
|
||||||
hw/application_fpga/apps/README.md
|
|
||||||
hw/application_fpga/application_fpga.bin.sha256
|
hw/application_fpga/application_fpga.bin.sha256
|
||||||
hw/application_fpga/config.vlt
|
hw/application_fpga/config.vlt
|
||||||
hw/application_fpga/core/timer/README.md
|
hw/application_fpga/core/timer/README.md
|
||||||
hw/application_fpga/core/tk1/README.md
|
hw/application_fpga/core/tk1/README.md
|
||||||
hw/application_fpga/core/touch_sense/README.md
|
hw/application_fpga/core/touch_sense/README.md
|
||||||
hw/application_fpga/core/trng/README.md
|
hw/application_fpga/core/trng/README.md
|
||||||
|
hw/application_fpga/core/uds/README.txt
|
||||||
hw/application_fpga/data/udi.hex
|
hw/application_fpga/data/udi.hex
|
||||||
hw/application_fpga/data/uds.hex
|
hw/application_fpga/data/uds.hex
|
||||||
hw/application_fpga/firmware.bin.sha512
|
hw/application_fpga/firmware.bin.sha512
|
||||||
|
hw/application_fpga/fw/.clang-format
|
||||||
hw/application_fpga/fw/testfw/Makefile
|
hw/application_fpga/fw/testfw/Makefile
|
||||||
hw/application_fpga/fw/tk1/Makefile
|
hw/application_fpga/fw/tk1/Makefile
|
||||||
|
hw/application_fpga/tools/makehex/makehex.py
|
||||||
|
hw/application_fpga/tools/reset-tk1
|
||||||
hw/application_fpga/tools/tpt/README.md
|
hw/application_fpga/tools/tpt/README.md
|
||||||
hw/usb_interface/ch552_fw/.gitignore
|
|
||||||
hw/usb_interface/ch552_fw/LICENSES/GPL-2.0-only.txt
|
|
||||||
hw/usb_interface/ch552_fw/LICENSES/MIT.txt
|
|
||||||
hw/usb_interface/ch552_fw/Makefile
|
|
||||||
hw/usb_interface/ch552_fw/README.md
|
|
||||||
|
|
||||||
# tkey-libs is assumed to be REUSE compliant
|
|
||||||
hw/application_fpga/tkey-libs/LICENSE
|
|
||||||
hw/application_fpga/tkey-libs/LICENSES/BSD-2-Clause.txt
|
|
||||||
hw/application_fpga/tkey-libs/LICENSES/CC0-1.0.txt
|
|
||||||
hw/application_fpga/tkey-libs/Makefile
|
|
||||||
hw/application_fpga/tkey-libs/README-DIST.txt
|
|
||||||
hw/application_fpga/tkey-libs/README.md
|
|
||||||
hw/application_fpga/tkey-libs/RELEASE.md
|
|
||||||
hw/application_fpga/tkey-libs/blake2s/LICENSE
|
|
||||||
hw/application_fpga/tkey-libs/blake2s/Makefile
|
|
||||||
hw/application_fpga/tkey-libs/blake2s/blake2s.c
|
|
||||||
hw/application_fpga/tkey-libs/blake2s/blake2s.h
|
|
||||||
hw/application_fpga/tkey-libs/blake2s/blake2s_test.c
|
|
||||||
hw/application_fpga/tkey-libs/example-app/Makefile
|
|
||||||
hw/application_fpga/tkey-libs/monocypher/LICENSE
|
|
||||||
hw/application_fpga/tkey-libs/monocypher/README.md
|
|
||||||
|
|
||||||
hw/application_fpga/tools/README.md
|
|
||||||
hw/application_fpga/tools/b2s/README.md
|
|
||||||
hw/application_fpga/tools/b2s/go.mod
|
|
||||||
hw/application_fpga/tools/b2s/go.sum
|
|
||||||
hw/application_fpga/tools/default_partition.bin
|
|
||||||
hw/application_fpga/tools/tkeyimage/README.md
|
|
||||||
hw/application_fpga/tools/tkeyimage/go.mod
|
|
||||||
hw/application_fpga/tools/tkeyimage/go.sum
|
|
||||||
)
|
)
|
||||||
|
|
||||||
is_missingok() {
|
is_missingok() {
|
||||||
|
|
87
README.md
87
README.md
|
@ -40,17 +40,9 @@ software and hardware should be.
|
||||||
|
|
||||||
## Licensing
|
## Licensing
|
||||||
|
|
||||||
Unless otherwise noted, the project sources are copyright Tillitis AB.
|
|
||||||
but you can redistribute it and/or modify it under the terms of the
|
|
||||||
GNU General Public License version 2 as published by the Free Software
|
|
||||||
Foundation.
|
|
||||||
|
|
||||||
See [LICENSES](./LICENSES/README.md) for more information about
|
See [LICENSES](./LICENSES/README.md) for more information about
|
||||||
the projects' licenses.
|
the projects' licenses.
|
||||||
|
|
||||||
Each imported project is typically kept in its own directory with its
|
|
||||||
own LICENSE file.
|
|
||||||
|
|
||||||
## Repositories
|
## Repositories
|
||||||
|
|
||||||
This repository contains the FPGA design, the source of the
|
This repository contains the FPGA design, the source of the
|
||||||
|
@ -85,84 +77,27 @@ https://github.com/tillitis/tkey-libs
|
||||||
|
|
||||||
but keep our own copy of it in the repo. See below.
|
but keep our own copy of it in the repo. See below.
|
||||||
|
|
||||||
## Building & flashing
|
## Building
|
||||||
|
|
||||||
These instructions assume you're using a Linux distribution. Most of
|
Building is probably easiest using make and Podman. Do this to see all
|
||||||
them also assume you're using our OCI image
|
targets:
|
||||||
[tkey-builder](https://ghcr.io/tillitis/tkey-builder). If you want to
|
|
||||||
run native tools, look in `contrib/Dockerfile` and
|
|
||||||
`contrib/buildtools.sh` for the tools and versions to use.
|
|
||||||
|
|
||||||
### FPGA
|
|
||||||
|
|
||||||
You need a [TKey
|
|
||||||
Unlocked](https://shop.tillitis.se/products/tkey-not-provisioned), a
|
|
||||||
[the TP1 TKey Programmer
|
|
||||||
board](https://shop.tillitis.se/products/tkey-dev-kit), and probably a
|
|
||||||
[Blinkinlabs CH55x Reset
|
|
||||||
Controller](https://shop-nl.blinkinlabs.com/products/ch55x-reset-controller)
|
|
||||||
to use this on real hardware.
|
|
||||||
|
|
||||||
Building is probably easiest using make and Podman.
|
|
||||||
|
|
||||||
To build everything and then flash the resulting bitstream with the
|
|
||||||
testloadapp in app slot 0 and the partition table copies in one go,
|
|
||||||
place the TKey Unlocked in the TP1, then do:
|
|
||||||
|
|
||||||
```
|
|
||||||
cd contrib
|
|
||||||
make flash
|
|
||||||
```
|
|
||||||
|
|
||||||
This uses the make target `prog_flash` in
|
|
||||||
`hw/application_fpga/Makefile` behind the scenes, but mounts your TP1
|
|
||||||
device into the container.
|
|
||||||
|
|
||||||
To see all targets:
|
|
||||||
|
|
||||||
```
|
```
|
||||||
cd contrib
|
cd contrib
|
||||||
make
|
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
|
See the [Tillitis Developer Handbook](https://dev.tillitis.se) for
|
||||||
more.
|
more.
|
||||||
|
|
||||||
### USB Controller
|
|
||||||
|
|
||||||
The TKey uses a WCH CH552 chip as a USB controller. It has its own
|
|
||||||
firmware.
|
|
||||||
|
|
||||||
Build:
|
|
||||||
|
|
||||||
```
|
|
||||||
cd contrib
|
|
||||||
make run
|
|
||||||
cd hw/usb_interface/ch552_fw
|
|
||||||
make
|
|
||||||
```
|
|
||||||
|
|
||||||
To flash the controller with new firmware you need hardware like the
|
|
||||||
[Blinkinlabs CH55x Reset
|
|
||||||
Controller](https://shop-nl.blinkinlabs.com/products/ch55x-reset-controller)
|
|
||||||
and a USB-A to USB-C converter.
|
|
||||||
|
|
||||||
[Reset Controller source](https://github.com/Blinkinlabs/ch55x_programmer).
|
|
||||||
|
|
||||||
You also need [chprog](https://github.com/ole00/chprog).
|
|
||||||
|
|
||||||
The bootloader identifies itself as USB VID 4348, PID 55e0. To be able
|
|
||||||
to access it and run `chprog` without root you need to allow your user
|
|
||||||
to access it. Place `contrib/99-tillitis.rules` in `/etc/udev/rules.d`
|
|
||||||
and run `udevadm control --reload`. Now you can add your user to the
|
|
||||||
`dialout` group and access it.
|
|
||||||
|
|
||||||
1. Connect the Reset Controller to your computer through "DUT\_IN"/"PC".
|
|
||||||
2. Connect the TKey to "DUT\_OUT"/"DUT".
|
|
||||||
3. Press the "Bootloader" button.
|
|
||||||
4. Run `make flash_patched` in `hw/usb_interface/ch552_fw` outside of
|
|
||||||
a container.
|
|
||||||
|
|
||||||
## Updating and working with tkey-libs
|
## Updating and working with tkey-libs
|
||||||
|
|
||||||
A copy of [tkey-libs](https://github.com/tillitis/tkey-libs) is kept
|
A copy of [tkey-libs](https://github.com/tillitis/tkey-libs) is kept
|
||||||
|
|
|
@ -9,19 +9,17 @@ IMAGE=ghcr.io/tillitis/tkey-builder:5rc1
|
||||||
|
|
||||||
all:
|
all:
|
||||||
@echo "Targets:"
|
@echo "Targets:"
|
||||||
@echo "run Run a shell using image '$(IMAGE)' (Podman)"
|
@echo "run Run a shell using image '$(IMAGE)' (Podman)"
|
||||||
@echo "run-make Build the FPGA bitstream using image '$(IMAGE)' (Podman)"
|
@echo "run-make Build the FPGA bitstream using image '$(IMAGE)' (Podman)"
|
||||||
@echo "run-make-ch552 Build the CH552 firmware using image '$(IMAGE)' (Podman)"
|
@echo "run-tb Run all the testbenches using image '$(IMAGE)' (Podman)"
|
||||||
@echo "run-tb Run all the testbenches using image '$(IMAGE)' (Podman)"
|
@echo "run-make-no-clean Like run-make but without cleaning first, useful for iterative firmware dev"
|
||||||
@echo "run-make-no-clean Like run-make but without cleaning first, useful for iterative firmware dev"
|
@echo "run-make-clean_fw Like run-make but cleans only firmware"
|
||||||
@echo "run-make-ch552-no-clean Like run-make-ch552 but without cleaning first, useful for iterative firmware dev"
|
@echo "flash Program the SPI flash on the TKey - needs an existing bitstream"
|
||||||
@echo "run-make-clean_fw Like run-make but cleans only firmware"
|
@echo "pull Pull down the image '$(IMAGE)' (Podman)"
|
||||||
@echo "flash Build bitstream and testloadapp.bin then program them and the partition table onto the TKey SPI flash"
|
@echo "build-image Build a toolchain image named '$(BUILDIMAGE)' (Podman)"
|
||||||
@echo "pull Pull down the image '$(IMAGE)' (Podman)"
|
@echo " A newly built image can be used like: make IMAGE=$(BUILDIMAGE) run"
|
||||||
@echo "build-image Build a toolchain image named '$(BUILDIMAGE)' (Podman)"
|
@echo "docker-run Run a shell using image '$(IMAGE)' (Docker)"
|
||||||
@echo " A newly built image can be used like: make IMAGE=$(BUILDIMAGE) run"
|
@echo "docker-build-image Build a toolchain image named '$(BUILDIMAGE)' (Docker)"
|
||||||
@echo "docker-run Run a shell using image '$(IMAGE)' (Docker)"
|
|
||||||
@echo "docker-build-image Build a toolchain image named '$(BUILDIMAGE)' (Docker)"
|
|
||||||
|
|
||||||
run:
|
run:
|
||||||
podman run --rm --mount type=bind,source="`pwd`/../",target=/build -w /build -it \
|
podman run --rm --mount type=bind,source="`pwd`/../",target=/build -w /build -it \
|
||||||
|
@ -35,10 +33,6 @@ run-make:
|
||||||
podman run --rm --mount type=bind,source="`pwd`/../hw/application_fpga",target=/build -w /build -it \
|
podman run --rm --mount type=bind,source="`pwd`/../hw/application_fpga",target=/build -w /build -it \
|
||||||
$(IMAGE) make clean application_fpga.bin
|
$(IMAGE) make clean application_fpga.bin
|
||||||
|
|
||||||
run-make-ch552:
|
|
||||||
podman run --rm --mount type=bind,source="`pwd`/../hw/usb_interface/ch552_fw",target=/build -w /build -it \
|
|
||||||
$(IMAGE) make clean usb_device.bin
|
|
||||||
|
|
||||||
run-tb:
|
run-tb:
|
||||||
podman run --rm --mount type=bind,source="`pwd`/../hw/application_fpga",target=/build -w /build -it \
|
podman run --rm --mount type=bind,source="`pwd`/../hw/application_fpga",target=/build -w /build -it \
|
||||||
$(IMAGE) make clean_tb tb
|
$(IMAGE) make clean_tb tb
|
||||||
|
@ -51,10 +45,6 @@ run-make-no-clean:
|
||||||
podman run --rm --mount type=bind,source="`pwd`/../hw/application_fpga",target=/build -w /build -it \
|
podman run --rm --mount type=bind,source="`pwd`/../hw/application_fpga",target=/build -w /build -it \
|
||||||
$(IMAGE) make application_fpga.bin
|
$(IMAGE) make application_fpga.bin
|
||||||
|
|
||||||
run-make-ch552-no-clean:
|
|
||||||
podman run --rm --mount type=bind,source="`pwd`/../hw/usb_interface/ch552_fw",target=/build -w /build -it \
|
|
||||||
$(IMAGE) make usb_device.bin
|
|
||||||
|
|
||||||
run-make-clean_fw:
|
run-make-clean_fw:
|
||||||
podman run --rm --mount type=bind,source="`pwd`/../hw/application_fpga",target=/build -w /build -it \
|
podman run --rm --mount type=bind,source="`pwd`/../hw/application_fpga",target=/build -w /build -it \
|
||||||
$(IMAGE) make clean_fw application_fpga.bin
|
$(IMAGE) make clean_fw application_fpga.bin
|
||||||
|
@ -64,7 +54,7 @@ flash:
|
||||||
--device /dev/bus/usb/$(lsusb | grep -m 1 1209:8886 | awk '{ printf "%s/%s", $2, substr($4,1,3) }') \
|
--device /dev/bus/usb/$(lsusb | grep -m 1 1209:8886 | awk '{ printf "%s/%s", $2, substr($4,1,3) }') \
|
||||||
--mount type=bind,source="`pwd`/../hw/application_fpga",target=/build \
|
--mount type=bind,source="`pwd`/../hw/application_fpga",target=/build \
|
||||||
-w /build \
|
-w /build \
|
||||||
-it $(IMAGE) make prog_flash
|
-it $(IMAGE) tillitis-iceprog /build/application_fpga.bin
|
||||||
|
|
||||||
|
|
||||||
pull:
|
pull:
|
||||||
|
|
|
@ -4,12 +4,8 @@ Descriptions of the tagged TKey releases.
|
||||||
|
|
||||||
## Upcoming release: Castor
|
## Upcoming release: Castor
|
||||||
|
|
||||||
Overview of changes since [TK1-24.03
|
Overview of changes since TK TK1-24.03 for the Castor milestone so
|
||||||
Bellatrix](https://github.com/tillitis/tillitis-key1/releases/tag/TK1-24.03)
|
far.
|
||||||
for the Castor milestone so far.
|
|
||||||
|
|
||||||
Main branch in the repository contains Castor design and specifically
|
|
||||||
the tag `TK1-Castor-alpha-1` reflects the upcoming release.
|
|
||||||
|
|
||||||
**Note well**: BREAKING CHANGE! Older device apps WILL NOT WORK.
|
**Note well**: BREAKING CHANGE! Older device apps WILL NOT WORK.
|
||||||
|
|
||||||
|
@ -18,50 +14,38 @@ 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
|
been changed to use the protocol will not have any way to communicate
|
||||||
with the outside world.
|
with the outside world.
|
||||||
|
|
||||||
### How to test TK1-Castor-alpha
|
|
||||||
|
|
||||||
To test this alpha release you will need:
|
|
||||||
|
|
||||||
- Tkey Unlocked
|
|
||||||
- TKey Programmer Board
|
|
||||||
- CH55x Reset Controller from [Blinkinlabs](https://shop-nl.blinkinlabs.com/products/ch55x-reset-controller)
|
|
||||||
|
|
||||||
Read
|
|
||||||
[here](https://github.com/tillitis/tillitis-key1/blob/main/README.md#building--flashing)
|
|
||||||
for instructions.
|
|
||||||
|
|
||||||
### General
|
### General
|
||||||
|
|
||||||
- Split repo:
|
- Split repo:
|
||||||
|
|
||||||
- tk1, mta1-usb-dev, mta-usb-v1 and mta1-library moves to
|
- tk1, mta1-usb-dev, mta-usb-v1 and mta1-library moves to
|
||||||
<https://github.com/tillitis/tk1-pcba>
|
https://github.com/tillitis/tk1-pcba
|
||||||
|
|
||||||
- tp1, mta1-usb-programmer, mta1-library and KiCad-RP Pico moves to
|
- tp1, mta1-usb-programmer, mta1-library and KiCad-RP Pico moves to
|
||||||
<https://github.com/tillitis/tp1>
|
https://github.com/tillitis/tp1
|
||||||
|
|
||||||
For full change log [see](https://github.com/tillitis/tillitis-key1/compare/TK1-23.03.2...coming-tag)
|
For full change log [see](https://github.com/tillitis/tillitis-key1/compare/TK1-23.03.2...coming-tag)
|
||||||
|
|
||||||
### FPGA
|
### FPGA
|
||||||
|
|
||||||
- Make Security Monitor memory access checks more complete.
|
- Security Monitor memory access checks are now more complete.
|
||||||
|
|
||||||
- Add SPI main controller mainly to access the flash chip.
|
- Add SPI main controller mainly to access the flash chip.
|
||||||
|
|
||||||
- Add system reset API. Device apps can reset the FPGA and restart
|
- Add system reset API. Device apps can reset the system and restart
|
||||||
the firmware.
|
the firmware. The FPGA is not reset.
|
||||||
|
|
||||||
- Increase clock frequence to 24 MHz.
|
- Increase clock frequence to 24 MHz.
|
||||||
|
|
||||||
- Increase UART baudrate to 500,000.
|
- Increase UART baudrate to 500,000.
|
||||||
|
|
||||||
- Fix UART baudrate counter issues noticable at higher baudrates.
|
|
||||||
|
|
||||||
- Fix missing clock cycles in timer core.
|
- Fix missing clock cycles in timer core.
|
||||||
|
|
||||||
- Remove the UART runtime configuration API.
|
- Remove the UART runtime configuration API.
|
||||||
|
|
||||||
- Several minor clean ups of design and testbench.
|
- Several clean ups and testbench changes.
|
||||||
|
|
||||||
|
- Make Verilator simulation work again.
|
||||||
|
|
||||||
- Add hardware clear to send (CTS) signals for communication between
|
- Add hardware clear to send (CTS) signals for communication between
|
||||||
UART and CH552.
|
UART and CH552.
|
||||||
|
@ -70,19 +54,19 @@ For full change log [see](https://github.com/tillitis/tillitis-key1/compare/TK1-
|
||||||
|
|
||||||
- Make ROM non-executable in app mode.
|
- Make ROM non-executable in app mode.
|
||||||
|
|
||||||
- Remove MMIO address for access to the firmware blake2s() function
|
- Remove support for access to the firmware blake2s() function from
|
||||||
from apps.
|
apps.
|
||||||
|
|
||||||
- Automatically leave firmware mode when execution leaves ROM and
|
- Automatically leave firmware mode when execution leaves ROM and
|
||||||
remove the now unnecessary APP\_MODE\_CTRL register.
|
remove the now unnecessary APP\_MODE\_CTRL register.
|
||||||
|
|
||||||
- Change UDS read protection: When execution leaves ROM the first
|
- Add extra protection of UDS: When execution leaves ROM the first
|
||||||
time, UDS is hardware protected from reads. The already existing
|
time, UDS is hardware protected from reading, as well as already
|
||||||
protection that UDS is protected after the first read is also still
|
existing UDS protection after first read and UDS being unreadable in
|
||||||
available.
|
app mode.
|
||||||
|
|
||||||
- Introduce interrupt handler for hardware-based privilege raising and
|
- Introduce interrupt handler for hardware-based privilege raising for
|
||||||
automatically privelege lowering for system calls.
|
system calls.
|
||||||
|
|
||||||
### Firmware
|
### Firmware
|
||||||
|
|
||||||
|
@ -90,65 +74,27 @@ For full change log [see](https://github.com/tillitis/tillitis-key1/compare/TK1-
|
||||||
by TRNG.
|
by TRNG.
|
||||||
|
|
||||||
- Add support for the new USB Mode Protocol to communicate with
|
- Add support for the new USB Mode Protocol to communicate with
|
||||||
different USB endpoints in the USB controller.
|
different endpoints.
|
||||||
|
|
||||||
- Support a filesystem on flash: There's space for two pre-loaded
|
- Support a filesystem on flash.
|
||||||
apps and four storage areas for device apps.
|
|
||||||
|
|
||||||
A typical use is that app slot 0 will contain a loader app for
|
- Add a system call mechanism and system calls: `RESET`, `ALLOC_AREA`,
|
||||||
verified boot and app slot 1 contains the app to be verified.
|
`DEALLOC_AREA`, `WRITE_DATA`, `READ_DATA`, `PRELOAD_DELETE`,
|
||||||
|
`PRELOAD_STORE`, `PRELOAD_STORE_FIN`, `PRELOAD_GET_DIGSIG`,
|
||||||
- Automatically start an app in flash app slot 0 after power cycle and
|
`STATUS`, and `GET_VIDPID`. See [firmware's
|
||||||
when instructed to by reset intentions.
|
README](../hw/application_fpga/fw/README.md) for documentation.
|
||||||
|
|
||||||
The automatically started app is trusted by the firmware by
|
|
||||||
including an app digest in the firmware ROM. This means we extend
|
|
||||||
the user's trust in the firmware to the first app, but only if it's
|
|
||||||
measured to the correct digest by the firmware. Anything else is a
|
|
||||||
hard error which halts the CPU.
|
|
||||||
|
|
||||||
- Support chaining of apps through soft resets, including support for
|
|
||||||
verifying that the next app is the expected one (exact measured
|
|
||||||
digest the previous app expected), and leaving data for the next app
|
|
||||||
to use.
|
|
||||||
|
|
||||||
- Add a system call mechanism and system calls. See [firmware's
|
|
||||||
README](../hw/application_fpga/fw/README.md) for documentation, but
|
|
||||||
its probably easier to use the the syscall wrappers in libsyscall in
|
|
||||||
[tkey-libs](https://github.com/tillitis/tkey-libs) if you're writing
|
|
||||||
in C.
|
|
||||||
|
|
||||||
- Harmonize with [tkey-libs](https://github.com/tillitis/tkey-libs).
|
- Harmonize with [tkey-libs](https://github.com/tillitis/tkey-libs).
|
||||||
Import tkey-libs to this repo for convenience.
|
Import tkey-libs to this repo for convenience.
|
||||||
|
|
||||||
- Rewrite test firmware to work with the new leaving ROM-scenario.
|
### CH552
|
||||||
Introduce a separate `testapp` for the app mode parts.
|
|
||||||
|
|
||||||
### Device apps
|
|
||||||
|
|
||||||
Introduce some device apps mostly for testing.
|
|
||||||
|
|
||||||
- `reset_test`: Test the different types of soft reset.
|
|
||||||
|
|
||||||
- `testapp`: Tests in app mode that used to live in `testfw`.
|
|
||||||
|
|
||||||
- `testloadapp`: A simple loader app for management and verification
|
|
||||||
of a second app.
|
|
||||||
|
|
||||||
- `defaultapp`: An app that immediately resets the TKey to load an app
|
|
||||||
from the client, just like earlier releases.
|
|
||||||
|
|
||||||
### CH552 firmware
|
|
||||||
|
|
||||||
- Use the new CTS signals for communication over the UART.
|
- Use the new CTS signals for communication over the UART.
|
||||||
|
|
||||||
- Add support for two HID endpoints (security token and our debug
|
- Add support for two HID endpoints.
|
||||||
HID).
|
|
||||||
|
|
||||||
- Add support for CCID endpoint.
|
- Add protocol to communicate with the three different endpoints: CDC,
|
||||||
|
HID, debug.
|
||||||
- Add a protocol to communicate with the different endpoints: CDC,
|
|
||||||
CCID, FIDO, debug.
|
|
||||||
|
|
||||||
- Change USB frame sending from a software timer to instead be
|
- Change USB frame sending from a software timer to instead be
|
||||||
controlled by the USB Controller Protocol.
|
controlled by the USB Controller Protocol.
|
||||||
|
@ -156,15 +102,9 @@ Introduce some device apps mostly for testing.
|
||||||
Note that to update the CH552 firmware you will need something like
|
Note that to update the CH552 firmware you will need something like
|
||||||
the Blinkinlabs CH55x Reset Controller:
|
the Blinkinlabs CH55x Reset Controller:
|
||||||
|
|
||||||
<https://shop-nl.blinkinlabs.com/products/ch55x-reset-controller>
|
https://shop-nl.blinkinlabs.com/products/ch55x-reset-controller
|
||||||
|
|
||||||
<https://github.com/Blinkinlabs/ch55x_programmer>
|
https://github.com/Blinkinlabs/ch55x_programmer
|
||||||
|
|
||||||
### Tooling
|
|
||||||
|
|
||||||
- Add tools to parse and generate partition tables and flash images.
|
|
||||||
|
|
||||||
- Add tool to compute a print a BLAKE2s digest, optionally as C code.
|
|
||||||
|
|
||||||
### tkey-builder
|
### tkey-builder
|
||||||
|
|
||||||
|
@ -187,13 +127,10 @@ the Blinkinlabs CH55x Reset Controller:
|
||||||
- libstdc++-arm-none-eabi-newlib
|
- libstdc++-arm-none-eabi-newlib
|
||||||
- pico-sdk
|
- pico-sdk
|
||||||
|
|
||||||
TP1 is now in <https://github.com/tillitis/tp1>
|
TP1 is now in https://github.com/tillitis/tp1
|
||||||
|
|
||||||
- Remove Go compiler support.
|
- Remove Go compiler support.
|
||||||
|
|
||||||
- Introduce buildtools.sh for building upstream tools for inclusion
|
|
||||||
in the image.
|
|
||||||
|
|
||||||
### Docs
|
### Docs
|
||||||
|
|
||||||
- All docs now in READMEs close to the design or code.
|
- All docs now in READMEs close to the design or code.
|
||||||
|
@ -218,7 +155,6 @@ the following digest:
|
||||||
```
|
```
|
||||||
|
|
||||||
### FPGA
|
### FPGA
|
||||||
|
|
||||||
- Security Monitor now prevents access to RAM outside of the physical
|
- Security Monitor now prevents access to RAM outside of the physical
|
||||||
memory. If it detects an access outside of the RAM address space, it
|
memory. If it detects an access outside of the RAM address space, it
|
||||||
will halt the CPU.
|
will halt the CPU.
|
||||||
|
@ -230,7 +166,6 @@ the following digest:
|
||||||
- Complete testbenches and add 9 tests for the FPGA cores.
|
- Complete testbenches and add 9 tests for the FPGA cores.
|
||||||
|
|
||||||
### Firmware
|
### Firmware
|
||||||
|
|
||||||
- Protect zeroisation against compiler optimisation by using
|
- Protect zeroisation against compiler optimisation by using
|
||||||
secure_wipe(), fixing a memset() that was removed during
|
secure_wipe(), fixing a memset() that was removed during
|
||||||
compilation.
|
compilation.
|
||||||
|
@ -245,35 +180,31 @@ the following digest:
|
||||||
- Fix warnings from splint.
|
- Fix warnings from splint.
|
||||||
|
|
||||||
### TP1
|
### TP1
|
||||||
|
|
||||||
- New plastic clip o and update of BOM.
|
- New plastic clip o and update of BOM.
|
||||||
- Build TP1 firmware in CI.
|
- Build TP1 firmware in CI.
|
||||||
|
|
||||||
### CH552
|
### CH552
|
||||||
|
|
||||||
- Fixed a bug where a byte of data could in some rare circumstances be
|
- Fixed a bug where a byte of data could in some rare circumstances be
|
||||||
dropped, causing a client app to hang.
|
dropped, causing a client app to hang.
|
||||||
- General clean-up of code, translated all comments to English.
|
- General clean-up of code, translated all comments to English.
|
||||||
|
|
||||||
### TK1
|
### TK1
|
||||||
|
|
||||||
- New injection moulded plastic case
|
- New injection moulded plastic case
|
||||||
|
|
||||||
### tkey-builder
|
### tkey-builder
|
||||||
|
|
||||||
- Updated to version 3. Bumping Ubuntu to 23.10, Yosys to 0.36 and
|
- Updated to version 3. Bumping Ubuntu to 23.10, Yosys to 0.36 and
|
||||||
nextpnr to 0.6.
|
nextpnr to 0.6.
|
||||||
- Updated to version 4. Bumping pico-sdk to 1.5.1, adding clang-tidy
|
- Updated to version 4. Bumping pico-sdk to 1.5.1, adding clang-tidy
|
||||||
and splint.
|
and splint.
|
||||||
|
|
||||||
### Docs
|
### Docs
|
||||||
|
|
||||||
- Fixing broken links, cleaning up docs and READMEs.
|
- Fixing broken links, cleaning up docs and READMEs.
|
||||||
- Clarify warm boot attack mitigations and scope for Bellatrix in
|
- Clarify warm boot attack mitigations and scope for Bellatrix in
|
||||||
threat model.
|
threat model.
|
||||||
|
|
||||||
For full change log [see](https://github.com/tillitis/tillitis-key1/compare/TK1-23.03.2...TK1-24.03)
|
For full change log [see](https://github.com/tillitis/tillitis-key1/compare/TK1-23.03.2...TK1-24.03)
|
||||||
|
|
||||||
|
|
||||||
## TK1-23.03.2
|
## TK1-23.03.2
|
||||||
|
|
||||||
This is the official release of the "Bellatrix" version of the
|
This is the official release of the "Bellatrix" version of the
|
||||||
|
@ -303,8 +234,8 @@ This bug fix release contains the following changes:
|
||||||
- Change the firmware protocol max frame size back to 128 bytes
|
- Change the firmware protocol max frame size back to 128 bytes
|
||||||
- Correct a bug with the reading out of UDS
|
- Correct a bug with the reading out of UDS
|
||||||
|
|
||||||
## TK1-23.03
|
|
||||||
|
|
||||||
|
## TK1-23.03
|
||||||
This is the official release of the "Bellatrix" version of
|
This is the official release of the "Bellatrix" version of
|
||||||
the Tillitis TKey device. This version is ready for general
|
the Tillitis TKey device. This version is ready for general
|
||||||
use.
|
use.
|
||||||
|
@ -318,6 +249,7 @@ shasum -a256 application_fpga.bin
|
||||||
f11d6b0f57c5405598206dcfea284008413391a2c51f124a2e2ae8600cb78f0b application_fpga.bin
|
f11d6b0f57c5405598206dcfea284008413391a2c51f124a2e2ae8600cb78f0b application_fpga.bin
|
||||||
```
|
```
|
||||||
|
|
||||||
|
|
||||||
### New and improved functionality
|
### New and improved functionality
|
||||||
|
|
||||||
- (ALL) The TKey HW design, FW, protocol and first applications has
|
- (ALL) The TKey HW design, FW, protocol and first applications has
|
||||||
|
@ -381,16 +313,18 @@ f11d6b0f57c5405598206dcfea284008413391a2c51f124a2e2ae8600cb78f0b application_fp
|
||||||
- (TOOLS) There is now a version of iceprog able to write to the FPGA
|
- (TOOLS) There is now a version of iceprog able to write to the FPGA
|
||||||
bitstream to the NVCM and lock the NVCM from external access
|
bitstream to the NVCM and lock the NVCM from external access
|
||||||
|
|
||||||
### Bugs fixed
|
|
||||||
|
|
||||||
|
### Bugs fixed
|
||||||
- No known bugs have been fixed. Numerous issues has been closed.
|
- No known bugs have been fixed. Numerous issues has been closed.
|
||||||
|
|
||||||
|
|
||||||
### Limitations
|
### Limitations
|
||||||
|
|
||||||
- The RAM address and data scrambling in this release is not
|
- The RAM address and data scrambling in this release is not
|
||||||
cryptographically secure. It his however randomized every time
|
cryptographically secure. It his however randomized every time
|
||||||
a TKey device is powered up.
|
a TKey device is powered up.
|
||||||
|
|
||||||
|
|
||||||
## engineering-release-2
|
## engineering-release-2
|
||||||
|
|
||||||
### New and improved functionality
|
### New and improved functionality
|
||||||
|
|
149
doc/toolchain_setup.md
Normal file
149
doc/toolchain_setup.md
Normal file
|
@ -0,0 +1,149 @@
|
||||||
|
# Toolchain setup
|
||||||
|
|
||||||
|
**NOTE:** Documentation migrated to dev.tillitis.se, this is kept for
|
||||||
|
history. This is likely to be outdated.
|
||||||
|
|
||||||
|
Here are instructions for setting up the tools required to build the
|
||||||
|
project. Tested on Ubuntu 22.10.
|
||||||
|
|
||||||
|
## General development environment
|
||||||
|
|
||||||
|
The following is intended to be a complete list of the packages that
|
||||||
|
are required for doing all of the following:
|
||||||
|
|
||||||
|
- building and developing [TKey device and client
|
||||||
|
apps](https://github.com/tillitis/tillitis-key1-apps)
|
||||||
|
- building our [QEMU machine](https://github.com/tillitis/qemu/tree/tk1)
|
||||||
|
(useful for apps dev)
|
||||||
|
- building and developing firmware and FPGA gateware (which also
|
||||||
|
requires building the toolchain below)
|
||||||
|
|
||||||
|
```
|
||||||
|
sudo apt install build-essential clang lld llvm bison flex libreadline-dev \
|
||||||
|
gawk tcl-dev libffi-dev git mercurial graphviz \
|
||||||
|
xdot pkg-config python3 libftdi-dev \
|
||||||
|
python3-dev libeigen3-dev \
|
||||||
|
libboost-dev libboost-filesystem-dev \
|
||||||
|
libboost-thread-dev libboost-program-options-dev \
|
||||||
|
libboost-iostreams-dev cmake libusb-1.0-0-dev \
|
||||||
|
ninja-build libglib2.0-dev libpixman-1-dev \
|
||||||
|
golang clang-format \
|
||||||
|
gcc-arm-none-eabi libnewlib-arm-none-eabi \
|
||||||
|
libstdc++-arm-none-eabi-newlib
|
||||||
|
```
|
||||||
|
|
||||||
|
## Device permissions
|
||||||
|
|
||||||
|
To allow sudo-less programming, you can install a udev rule that will
|
||||||
|
assign the tkey programmer, and also an unprogrammed CH552, to the
|
||||||
|
dialout group. You will also need to add your user to this group:
|
||||||
|
|
||||||
|
```
|
||||||
|
sudo cp contrib/99-tillitis.rules /etc/udev/rules.d
|
||||||
|
sudo udevadm control --reload-rules
|
||||||
|
sudo usermod -aG dialout ${USER}
|
||||||
|
```
|
||||||
|
|
||||||
|
To apply the new group, log out and then log back in.
|
||||||
|
|
||||||
|
You can check the device permissions to determine if the group was
|
||||||
|
successfully applied. First, use lsusb to find the location of the
|
||||||
|
programmer:
|
||||||
|
|
||||||
|
```
|
||||||
|
lsusb -d 1209:8886
|
||||||
|
Bus 001 Device 023: ID 1209:8886 Generic TP-1
|
||||||
|
```
|
||||||
|
|
||||||
|
Then, you can check the permissions by using the bus and device
|
||||||
|
number reported above. Note that this pair is ephemeral and may
|
||||||
|
change after every device insertion:
|
||||||
|
|
||||||
|
```
|
||||||
|
ls -l /dev/bus/usb/001/023
|
||||||
|
crw-rw---- 1 root dialout 189, 22 Feb 16 14:58 /dev/bus/usb/001/023
|
||||||
|
```
|
||||||
|
|
||||||
|
## Gateware: Yosys/Icestorm toolchain
|
||||||
|
|
||||||
|
If the LED of your TKey is steady white when you plug it, then the
|
||||||
|
firmware is running and it's already usable! If you want to develop
|
||||||
|
TKey apps, then only the above general development environment is
|
||||||
|
needed.
|
||||||
|
|
||||||
|
Compiling and installing Yosys and friends is only needed if your TKey
|
||||||
|
is not already running the required firmware and FPGA gateware, or if
|
||||||
|
you want to do development on these components.
|
||||||
|
|
||||||
|
These steps are used to build and install the
|
||||||
|
[icestorm](http://bygone.clairexen.net/icestorm/) toolchain. The
|
||||||
|
binaries are installed in `/usr/local`. Note that if you have or
|
||||||
|
install other versions of these tools locally, they could conflict
|
||||||
|
(case in point: `yosys` installed on MacOS using brew).
|
||||||
|
|
||||||
|
git clone https://github.com/YosysHQ/icestorm
|
||||||
|
cd icestorm
|
||||||
|
git checkout d20a5e9001f46262bf0cef220f1a6943946e421d
|
||||||
|
make -j$(nproc)
|
||||||
|
sudo make install
|
||||||
|
cd ..
|
||||||
|
|
||||||
|
# Custom iceprog for the RPi 2040-based programmer (will be upstreamed).
|
||||||
|
# Note: install dependencies for building tillitis-iceprog on Ubuntu:
|
||||||
|
# sudo apt install libftdi-dev libusb-1.0-0-dev
|
||||||
|
git clone -b interfaces https://github.com/tillitis/icestorm tillitis--icestorm
|
||||||
|
cd tillitis--icestorm/iceprog
|
||||||
|
make
|
||||||
|
sudo make PROGRAM_PREFIX=tillitis- install
|
||||||
|
cd ../..
|
||||||
|
|
||||||
|
git clone https://github.com/YosysHQ/yosys
|
||||||
|
cd yosys
|
||||||
|
git checkout yosys-0.26
|
||||||
|
make -j$(nproc)
|
||||||
|
sudo make install
|
||||||
|
cd ..
|
||||||
|
|
||||||
|
git clone https://github.com/YosysHQ/nextpnr
|
||||||
|
cd nextpnr
|
||||||
|
git checkout nextpnr-0.5
|
||||||
|
cmake -DARCH=ice40 -DCMAKE_INSTALL_PREFIX=/usr/local .
|
||||||
|
make -j$(nproc)
|
||||||
|
sudo make install
|
||||||
|
cd ..
|
||||||
|
|
||||||
|
References:
|
||||||
|
* http://bygone.clairexen.net/icestorm/
|
||||||
|
|
||||||
|
## Firmware: riscv toolchain
|
||||||
|
|
||||||
|
The TKey implements a [picorv32](https://github.com/YosysHQ/picorv32)
|
||||||
|
soft core CPU, which is a RISC-V microcontroller with the C
|
||||||
|
instructions and Zmmul extension, multiply without divide
|
||||||
|
(RV32ICZmmul). You can read
|
||||||
|
[more](https://www.sifive.com/blog/all-aboard-part-1-compiler-args)
|
||||||
|
about it.
|
||||||
|
|
||||||
|
The project uses the LLVM/Clang suite and version 15 or later is
|
||||||
|
required. As of writing Ubuntu 22.10 has version 15 packaged. You may
|
||||||
|
be able to get it installed on older Ubuntu and Debian using the
|
||||||
|
instructions on https://apt.llvm.org/ . There are also binary releases
|
||||||
|
here: https://github.com/llvm/llvm-project/releases
|
||||||
|
|
||||||
|
References:
|
||||||
|
* https://github.com/YosysHQ/picorv32
|
||||||
|
|
||||||
|
If your available `objcopy` and `size` commands is anything other than
|
||||||
|
the default `llvm-objcopy` and `llvm-size` define `OBJCOPY` and `SIZE`
|
||||||
|
to whatever they're called on your system before calling `make`.
|
||||||
|
|
||||||
|
## CH552 USB to Serial firmware
|
||||||
|
|
||||||
|
The USB to Serial firmware runs on the CH552 microcontroller, and
|
||||||
|
provides a USB CDC profile which should work with the default drivers
|
||||||
|
on all major operating systems. MTA1-USB-V1 and TK-1 devices come
|
||||||
|
with the CH552 microcontroller pre-programmed.
|
||||||
|
|
||||||
|
Toolchain setup and build instructions for this firmware are detailed
|
||||||
|
in the
|
||||||
|
[ch552_fw directory](../hw/usb_interface/ch552_fw/README.md)
|
|
@ -134,7 +134,6 @@ FIRMWARE_OBJS = \
|
||||||
$(P)/fw/tk1/partition_table.o \
|
$(P)/fw/tk1/partition_table.o \
|
||||||
$(P)/fw/tk1/auth_app.o \
|
$(P)/fw/tk1/auth_app.o \
|
||||||
$(P)/fw/tk1/rng.o \
|
$(P)/fw/tk1/rng.o \
|
||||||
$(P)/fw/tk1/reset.o \
|
|
||||||
$(P)/fw/tk1/preload_app.o \
|
$(P)/fw/tk1/preload_app.o \
|
||||||
$(P)/fw/tk1/mgmt_app.o
|
$(P)/fw/tk1/mgmt_app.o
|
||||||
|
|
||||||
|
@ -185,11 +184,6 @@ LDFLAGS = \
|
||||||
-Wl,--cref,-M \
|
-Wl,--cref,-M \
|
||||||
-L $(LIBDIR) -lcommon -lblake2s
|
-L $(LIBDIR) -lcommon -lblake2s
|
||||||
|
|
||||||
QEMU_LDFLAGS = \
|
|
||||||
-T $(P)/fw/tk1/qemu_firmware.lds \
|
|
||||||
-Wl,--cref,-M \
|
|
||||||
-L $(LIBDIR) -lcommon -lblake2s
|
|
||||||
|
|
||||||
# Common libraries the firmware and testfw depend on. See
|
# Common libraries the firmware and testfw depend on. See
|
||||||
# https://github.com/tillitis/tkey-libs/
|
# https://github.com/tillitis/tkey-libs/
|
||||||
.PHONY: tkey-libs
|
.PHONY: tkey-libs
|
||||||
|
@ -211,8 +205,8 @@ qemu_firmware.elf: CFLAGS += -DQEMU_DEBUG
|
||||||
qemu_firmware.elf: ASFLAGS += -DQEMU_DEBUG
|
qemu_firmware.elf: ASFLAGS += -DQEMU_DEBUG
|
||||||
qemu_firmware.elf: CFLAGS += -DQEMU_SYSCALL
|
qemu_firmware.elf: CFLAGS += -DQEMU_SYSCALL
|
||||||
qemu_firmware.elf: ASFLAGS += -DQEMU_SYSCALL
|
qemu_firmware.elf: ASFLAGS += -DQEMU_SYSCALL
|
||||||
qemu_firmware.elf: tkey-libs $(FIRMWARE_OBJS) $(P)/fw/tk1/qemu_firmware.lds
|
qemu_firmware.elf: firmware.elf
|
||||||
$(CC) $(CFLAGS) $(FIRMWARE_OBJS) $(QEMU_LDFLAGS) -o $@ > $(basename $@).map
|
mv firmware.elf qemu_firmware.elf
|
||||||
|
|
||||||
# Create compile_commands.json for clangd and LSP
|
# Create compile_commands.json for clangd and LSP
|
||||||
.PHONY: clangd
|
.PHONY: clangd
|
||||||
|
@ -255,11 +249,11 @@ bram_fw.hex:
|
||||||
$(ICESTORM_PATH)icebram -v -g 32 $(BRAM_FW_SIZE) > $@
|
$(ICESTORM_PATH)icebram -v -g 32 $(BRAM_FW_SIZE) > $@
|
||||||
|
|
||||||
firmware.hex: firmware.bin firmware_size_mismatch
|
firmware.hex: firmware.bin firmware_size_mismatch
|
||||||
python3 $(P)/tools/makehex.py $< $(BRAM_FW_SIZE) > $@
|
python3 $(P)/tools/makehex/makehex.py $< $(BRAM_FW_SIZE) > $@
|
||||||
simfirmware.hex: simfirmware.bin simfirmware_size_mismatch
|
simfirmware.hex: simfirmware.bin simfirmware_size_mismatch
|
||||||
python3 $(P)/tools/makehex.py $< $(BRAM_FW_SIZE) > $@
|
python3 $(P)/tools/makehex/makehex.py $< $(BRAM_FW_SIZE) > $@
|
||||||
testfw.hex: testfw.bin testfw_size_mismatch
|
testfw.hex: testfw.bin testfw_size_mismatch
|
||||||
python3 $(P)/tools/makehex.py $< $(BRAM_FW_SIZE) > $@
|
python3 $(P)/tools/makehex/makehex.py $< $(BRAM_FW_SIZE) > $@
|
||||||
|
|
||||||
.PHONY: check-binary-hashes
|
.PHONY: check-binary-hashes
|
||||||
check-binary-hashes:
|
check-binary-hashes:
|
||||||
|
@ -331,7 +325,6 @@ fmt: $(FPGA_VERILOG_SRCS) $(SIM_VERILOG_SRCS) $(VERILATOR_VERILOG_SRCS) $(VERILO
|
||||||
checkfmt: $(FPGA_VERILOG_SRCS) $(SIM_VERILOG_SRCS) $(VERILATOR_VERILOG_SRCS) $(VERILOG_SRCS)
|
checkfmt: $(FPGA_VERILOG_SRCS) $(SIM_VERILOG_SRCS) $(VERILATOR_VERILOG_SRCS) $(VERILOG_SRCS)
|
||||||
make -C fw/tk1 checkfmt
|
make -C fw/tk1 checkfmt
|
||||||
make -C fw/testfw checkfmt
|
make -C fw/testfw checkfmt
|
||||||
make -C apps checkfmt
|
|
||||||
$(FORMAT) $(CHECK_FORMAT_FLAGS) $^ 2>&1 | \
|
$(FORMAT) $(CHECK_FORMAT_FLAGS) $^ 2>&1 | \
|
||||||
grep "Needs formatting" && exit 1 || true
|
grep "Needs formatting" && exit 1 || true
|
||||||
.PHONY: checkfmt
|
.PHONY: checkfmt
|
||||||
|
@ -396,7 +389,7 @@ synth.json: $(FPGA_VERILOG_SRCS) $(VERILOG_SRCS) $(PICORV32_SRCS) bram_fw.hex
|
||||||
application_fpga_par.json: synth.json $(P)/data/$(PIN_FILE)
|
application_fpga_par.json: synth.json $(P)/data/$(PIN_FILE)
|
||||||
$(NEXTPNR_PATH)nextpnr-ice40 \
|
$(NEXTPNR_PATH)nextpnr-ice40 \
|
||||||
-l application_fpga_par.txt \
|
-l application_fpga_par.txt \
|
||||||
--seed 18160564147838858264 \
|
--seed 9416596747216415304 \
|
||||||
--freq $(TARGET_FREQ) \
|
--freq $(TARGET_FREQ) \
|
||||||
--ignore-loops \
|
--ignore-loops \
|
||||||
--up5k \
|
--up5k \
|
||||||
|
@ -472,23 +465,17 @@ tb_application_fpga: $(SIM_VERILOG_SRCS) \
|
||||||
#-------------------------------------------------------------------
|
#-------------------------------------------------------------------
|
||||||
|
|
||||||
prog_flash: check-hardware application_fpga.bin
|
prog_flash: check-hardware application_fpga.bin
|
||||||
tillitis-iceprog application_fpga.bin
|
sudo tillitis-iceprog application_fpga.bin
|
||||||
make -C apps
|
|
||||||
(cd tools && ./load_preloaded_app.sh 0 ../apps/testloadapp.bin)
|
|
||||||
.PHONY: prog_flash
|
.PHONY: prog_flash
|
||||||
|
|
||||||
prog_flash_bs: check-hardware application_fpga.bin
|
|
||||||
tillitis-iceprog application_fpga.bin
|
|
||||||
.PHONY: prog_flash_bs
|
|
||||||
|
|
||||||
prog_flash_testfw: check-hardware application_fpga_testfw.bin
|
prog_flash_testfw: check-hardware application_fpga_testfw.bin
|
||||||
tillitis-iceprog application_fpga_testfw.bin
|
sudo tillitis-iceprog application_fpga_testfw.bin
|
||||||
.PHONY: prog_flash_testfw
|
.PHONY: prog_flash_testfw
|
||||||
|
|
||||||
check-hardware:
|
check-hardware:
|
||||||
@tillitis-iceprog -t >/dev/null 2>&1 || \
|
@sudo tillitis-iceprog -t >/dev/null 2>&1 || \
|
||||||
{ echo "Programmer not plugged in or not accessible"; false; }
|
{ echo "Programmer not plugged in or not accessible"; false; }
|
||||||
@if tillitis-iceprog -t 2>&1 | grep -qi "^flash.id:\( 0x\(00\|ff\)\)\{4\}"; then \
|
@if sudo tillitis-iceprog -t 2>&1 | grep -qi "^flash.id:\( 0x\(00\|ff\)\)\{4\}"; then \
|
||||||
echo "No USB stick in the programmer?"; false; else true; fi
|
echo "No USB stick in the programmer?"; false; else true; fi
|
||||||
.PHONY: check-hardware
|
.PHONY: check-hardware
|
||||||
|
|
||||||
|
@ -512,7 +499,6 @@ clean: clean_sim clean_fw clean_tb
|
||||||
rm -f lint_issues.txt
|
rm -f lint_issues.txt
|
||||||
rm -f tools/tpt/*.hex
|
rm -f tools/tpt/*.hex
|
||||||
rm -rf tools/tpt/__pycache__
|
rm -rf tools/tpt/__pycache__
|
||||||
make -C apps clean
|
|
||||||
.PHONY: clean
|
.PHONY: clean
|
||||||
|
|
||||||
clean_fw:
|
clean_fw:
|
||||||
|
@ -561,8 +547,7 @@ help:
|
||||||
@echo "tb_application_fpga Build testbench simulation for the design"
|
@echo "tb_application_fpga Build testbench simulation for the design"
|
||||||
@echo "lint Run lint on Verilog source files."
|
@echo "lint Run lint on Verilog source files."
|
||||||
@echo "tb Run all testbenches"
|
@echo "tb Run all testbenches"
|
||||||
@echo "prog_flash Program device flash with FGPA bitstream (including firmware), partition table, and testloadapp.bin (using the RPi Pico-based programmer)."
|
@echo "prog_flash Program device flash with FGPA bitstream including firmware (using the RPi Pico-based programmer)."
|
||||||
@echo "prog_flash_bs Program device flash with FGPA bitstream including firmware (using the RPi Pico-based programmer)."
|
|
||||||
@echo "prog_flash_testfw Program device flash as above, but with testfw."
|
@echo "prog_flash_testfw Program device flash as above, but with testfw."
|
||||||
@echo "clean Delete all generated files."
|
@echo "clean Delete all generated files."
|
||||||
@echo "clean_fw Delete only generated files for firmware. Useful for fw devs."
|
@echo "clean_fw Delete only generated files for firmware. Useful for fw devs."
|
||||||
|
|
|
@ -1,4 +1,4 @@
|
||||||
## TKey hardware design
|
# TKey hardware design
|
||||||
|
|
||||||

|

|
||||||
|
|
||||||
|
@ -16,9 +16,8 @@ firmware, application and system call. Each mode give access to a
|
||||||
different set of resources. Where app mode is the most restrictive and
|
different set of resources. Where app mode is the most restrictive and
|
||||||
firmware mode is the least restrictive.
|
firmware mode is the least restrictive.
|
||||||
|
|
||||||
The rest of the components are under `cores`, except the firmware,
|
The rest of the components are under `cores`. They typically have
|
||||||
which is under `fw/tk1`. They typically have their own `README.md`
|
their own `README.md` file documenting them and their API in detail.
|
||||||
file documenting them and their API in detail.
|
|
||||||
|
|
||||||
Hardware functions with APIs, assets, and input/output are memory
|
Hardware functions with APIs, assets, and input/output are memory
|
||||||
mapped starting at base address `0xc000_0000`. For specific offsets
|
mapped starting at base address `0xc000_0000`. For specific offsets
|
||||||
|
@ -39,11 +38,6 @@ Rough memory map:
|
||||||
| Syscall | 0xe1 |
|
| Syscall | 0xe1 |
|
||||||
| TK1 | 0xff |
|
| TK1 | 0xff |
|
||||||
|
|
||||||
## Firmware
|
|
||||||
|
|
||||||
Firmware is kept in ROM. See the [Firmware implementation
|
|
||||||
notes](fw/README.md).
|
|
||||||
|
|
||||||
## `clk_reset_gen`
|
## `clk_reset_gen`
|
||||||
|
|
||||||
Generator for system clock and system reset.
|
Generator for system clock and system reset.
|
||||||
|
|
|
@ -1 +1 @@
|
||||||
dfba361c83337c6bac2364d1fd8f115eeb7feeae5faabbdf0713c79b44bbd78d application_fpga.bin
|
c770fe25034655241d9e0152b03fcf691c548bc50d30b574a5213abc5b36fe25 application_fpga.bin
|
||||||
|
|
|
@ -1,123 +0,0 @@
|
||||||
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 \
|
|
||||||
-Os \
|
|
||||||
-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) \
|
|
||||||
-I include \
|
|
||||||
-I ../
|
|
||||||
|
|
||||||
AS = clang
|
|
||||||
|
|
||||||
ASFLAGS = \
|
|
||||||
-target riscv32-unknown-none-elf \
|
|
||||||
-march=rv32iczmmul \
|
|
||||||
-mabi=ilp32 \
|
|
||||||
-mno-relax
|
|
||||||
|
|
||||||
LDFLAGS = \
|
|
||||||
-T $(LIBDIR)/app.lds \
|
|
||||||
-L $(LIBDIR) -lcrt0 -lcommon -lmonocypher -lblake2s
|
|
||||||
|
|
||||||
.PHONY: all
|
|
||||||
all: defaultapp.bin reset_test.bin testapp.bin testloadapp.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)
|
|
||||||
|
|
||||||
OBJS=syscall.o
|
|
||||||
|
|
||||||
# syscall.o: syscall.S
|
|
||||||
# $(CC) $(CFLAGS) $(DEFAULTAPP_OBJS) $(LDFLAGS) -o $@
|
|
||||||
|
|
||||||
# defaultapp
|
|
||||||
DEFAULTAPP_FMTFILES = *.[ch]
|
|
||||||
|
|
||||||
DEFAULTAPP_OBJS = \
|
|
||||||
$(P)/defaultapp/main.o
|
|
||||||
|
|
||||||
defaultapp.elf: tkey-libs $(OBJS) $(DEFAULTAPP_OBJS)
|
|
||||||
$(CC) $(CFLAGS) $(OBJS) $(DEFAULTAPP_OBJS) $(LDFLAGS) -o $@
|
|
||||||
|
|
||||||
# reset_test
|
|
||||||
|
|
||||||
RESET_TEST_FMTFILES = *.[ch]
|
|
||||||
|
|
||||||
RESET_TEST_OBJS = \
|
|
||||||
$(P)/reset_test/main.o
|
|
||||||
|
|
||||||
reset_test.elf: tkey-libs $(RESET_TEST_OBJS)
|
|
||||||
$(CC) $(CFLAGS) $(OBJS) $(RESET_TEST_OBJS) $(LDFLAGS) -o $@
|
|
||||||
|
|
||||||
# testapp
|
|
||||||
|
|
||||||
TESTAPP_OBJS = \
|
|
||||||
$(P)/testapp/main.o
|
|
||||||
|
|
||||||
testapp.elf: tkey-libs $(TESTAPP_OBJS)
|
|
||||||
$(CC) $(CFLAGS) $(OBJS) $(TESTAPP_OBJS) $(LDFLAGS) -o $@
|
|
||||||
|
|
||||||
# testloadapp
|
|
||||||
|
|
||||||
TESTLOADAPP_OBJS = \
|
|
||||||
$(P)/testloadapp/main.o
|
|
||||||
|
|
||||||
testloadapp.elf: tkey-libs $(TESTLOADAPP_OBJS)
|
|
||||||
$(CC) $(CFLAGS) $(OBJS) $(TESTLOADAPP_OBJS) $(LDFLAGS) -o $@
|
|
||||||
|
|
||||||
.PHONY: fmt
|
|
||||||
fmt:
|
|
||||||
clang-format --dry-run --ferror-limit=0 defaultapp/*.[ch]
|
|
||||||
clang-format --verbose -i defaultapp/*.[ch]
|
|
||||||
|
|
||||||
clang-format --dry-run --ferror-limit=0 reset_test/*.[ch]
|
|
||||||
clang-format --verbose -i reset_test/*.[ch]
|
|
||||||
|
|
||||||
clang-format --dry-run --ferror-limit=0 testapp/*.[ch]
|
|
||||||
clang-format --verbose -i testapp/*.[ch]
|
|
||||||
|
|
||||||
clang-format --dry-run --ferror-limit=0 testloadapp/*.[ch]
|
|
||||||
clang-format --verbose -i testloadapp/*.[ch]
|
|
||||||
|
|
||||||
.PHONY: checkfmt
|
|
||||||
checkfmt:
|
|
||||||
clang-format --dry-run --ferror-limit=0 defaultapp/*.[ch]
|
|
||||||
|
|
||||||
clang-format --dry-run --ferror-limit=0 reset_test/*.[ch]
|
|
||||||
|
|
||||||
clang-format --dry-run --ferror-limit=0 testapp/*.[ch]
|
|
||||||
|
|
||||||
clang-format --dry-run --ferror-limit=0 testloadapp/*.[ch]
|
|
||||||
|
|
||||||
.PHONY: clean
|
|
||||||
clean:
|
|
||||||
rm -f *.elf *.bin $(OBJS) $(DEFAULTAPP_OBJS) $(RESET_TEST_OBJS) \
|
|
||||||
$(TESTAPP_OBJS) $(TESTLOADAPP_OBJS)
|
|
||||||
|
|
|
@ -1,36 +0,0 @@
|
||||||
# Test applications
|
|
||||||
|
|
||||||
- `defaultapp`: Immediately resets the TKey with the intention to
|
|
||||||
start an app from the client, replicating the behaviour of earlier
|
|
||||||
generations.
|
|
||||||
- `testapp`: Runs through a couple of tests that are now impossible
|
|
||||||
to do in the `testfw`.
|
|
||||||
- `reset_test`: Interactively test different reset scenarios.
|
|
||||||
- `testloadapp`: Interactively test management app things like
|
|
||||||
installing an app (hardcoded for a small happy blinking app, see
|
|
||||||
`blink.h` for the entire binary!) and to test verified boot.
|
|
||||||
|
|
||||||
## Build
|
|
||||||
|
|
||||||
```
|
|
||||||
$ make
|
|
||||||
```
|
|
||||||
|
|
||||||
will build all the .elf and .bin files on the top level.
|
|
||||||
|
|
||||||
## Use
|
|
||||||
|
|
||||||
Use `tkey-runapp` from
|
|
||||||
[tkey-devtools](https://github.com/tillitis/tkey-devtools) to load the
|
|
||||||
apps:
|
|
||||||
|
|
||||||
```
|
|
||||||
$ tkey-runapp testapp.bin
|
|
||||||
```
|
|
||||||
|
|
||||||
All of these test apps are controlled through the USB CDC, typically
|
|
||||||
by running picocom or similar terminal program, like:
|
|
||||||
|
|
||||||
```
|
|
||||||
$ picocom /dev/ttyACM1
|
|
||||||
```
|
|
|
@ -1,18 +0,0 @@
|
||||||
// Copyright (C) 2025 - Tillitis AB
|
|
||||||
// SPDX-License-Identifier: GPL-2.0-only
|
|
||||||
|
|
||||||
#include <fw/tk1/reset.h>
|
|
||||||
#include <fw/tk1/syscall_num.h>
|
|
||||||
#include <syscall.h>
|
|
||||||
#include <tkey/debug.h>
|
|
||||||
#include <tkey/led.h>
|
|
||||||
|
|
||||||
int main(void)
|
|
||||||
{
|
|
||||||
struct reset rst = {0};
|
|
||||||
|
|
||||||
led_set(LED_BLUE);
|
|
||||||
|
|
||||||
rst.type = START_CLIENT;
|
|
||||||
syscall(TK1_SYSCALL_RESET, (uint32_t)&rst, 0, 0);
|
|
||||||
}
|
|
|
@ -101,7 +101,7 @@ module tk1 #(
|
||||||
|
|
||||||
localparam TK1_NAME0 = 32'h746B3120; // "tk1 "
|
localparam TK1_NAME0 = 32'h746B3120; // "tk1 "
|
||||||
localparam TK1_NAME1 = 32'h6d6b6466; // "mkdf"
|
localparam TK1_NAME1 = 32'h6d6b6466; // "mkdf"
|
||||||
localparam TK1_VERSION = 32'h00000006;
|
localparam TK1_VERSION = 32'h00000005;
|
||||||
|
|
||||||
localparam FW_RAM_FIRST = 32'hd0000000;
|
localparam FW_RAM_FIRST = 32'hd0000000;
|
||||||
localparam FW_RAM_LAST = 32'hd0000fff; // 4 KB
|
localparam FW_RAM_LAST = 32'hd0000fff; // 4 KB
|
||||||
|
|
|
@ -1,2 +1,2 @@
|
||||||
073570c0
|
00010203
|
||||||
04050607
|
04050607
|
||||||
|
|
|
@ -1 +1 @@
|
||||||
4be2767d5ddd30b5422f4b58075365cb6d988259e88ffa14d6d243560b289f54eaf0c351e9d744cff8ec3a18b1830f3925a86f36bd2096c12eccce25ed44993c firmware.bin
|
e72557c38bee1e16114f550b16fc04412bfba09274d7b1fe971ab6b2ef4f06421d976276175ea4df3b7d590599eb052b85a812b689d728be5031ae412b2f8d24 firmware.bin
|
||||||
|
|
|
@ -65,11 +65,10 @@ The different endpoints:
|
||||||
|
|
||||||
| *Name* | *Value* | *Comment* |
|
| *Name* | *Value* | *Comment* |
|
||||||
|--------|---------|----------------------------------------------------------------------|
|
|--------|---------|----------------------------------------------------------------------|
|
||||||
| CH552 | 0x04 | USB controller control |
|
| DEBUG | 0x20 | A USB HID special debug pipe. Useful for debug prints. |
|
||||||
| CDC | 0x08 | USB CDC-ACM, a serial port on the client. |
|
| CH552 | 0x10 | USB controller control |
|
||||||
| FIDO | 0x10 | A USB FIDO security token device, useful for FIDO-type applications. |
|
| CDC | 0x40 | USB CDC-ACM, a serial port on the client. |
|
||||||
| CCID | 0x20 | USB CCID, a port for emulating a smart card |
|
| FIDO | 0x80 | A USB FIDO security token device, useful for FIDO-type applications. |
|
||||||
| DEBUG | 0x40 | A USB HID special debug pipe. Useful for debug prints. |
|
|
||||||
|
|
||||||
You can turn on and off different endpoints dynamically by sending
|
You can turn on and off different endpoints dynamically by sending
|
||||||
commands to the `CH552` control endpoint. When the TKey starts only
|
commands to the `CH552` control endpoint. When the TKey starts only
|
||||||
|
@ -163,7 +162,6 @@ stateDiagram-v2
|
||||||
S0 --> S1
|
S0 --> S1
|
||||||
S0 --> S4: Default
|
S0 --> S4: Default
|
||||||
S0 --> S3
|
S0 --> S3
|
||||||
S0 --> SE: Unknown reset type
|
|
||||||
|
|
||||||
S1 --> S1: Other commands
|
S1 --> S1: Other commands
|
||||||
S1 --> S2: LOAD_APP
|
S1 --> S2: LOAD_APP
|
||||||
|
@ -192,8 +190,8 @@ States:
|
||||||
- *LOADING*: Expecting application data from client. Allows only the
|
- *LOADING*: Expecting application data from client. Allows only the
|
||||||
command `LOAD_APP_DATA` to continue loading the device app.
|
command `LOAD_APP_DATA` to continue loading the device app.
|
||||||
- *LOAD_FLASH*: Loading an app from flash. Allows no commands.
|
- *LOAD_FLASH*: Loading an app from flash. Allows no commands.
|
||||||
- *LOAD_FLASH_MGMT*: Loading an app from flash and registering it as a
|
- *LOAD_FLASH_MGMT*: Loading and verifyiing a device app from flash.
|
||||||
prospective managment app. Allows no commands.
|
Allows no commands.
|
||||||
- *START*: Computes CDI. Possibly verifies app. Starts the
|
- *START*: Computes CDI. Possibly verifies app. Starts the
|
||||||
application. Does not return to firmware. Allows no commands.
|
application. Does not return to firmware. Allows no commands.
|
||||||
- *FAIL* - Halts CPU. Allows no commands.
|
- *FAIL* - Halts CPU. Allows no commands.
|
||||||
|
@ -208,7 +206,6 @@ Allowed data in state *INITIAL*:
|
||||||
| `FLASH1_VER` | *LOAD_FLASH* |
|
| `FLASH1_VER` | *LOAD_FLASH* |
|
||||||
| `CLIENT` | *WAITCOMMAND* |
|
| `CLIENT` | *WAITCOMMAND* |
|
||||||
| `CLIENT_VER` | *WAITCOMMAND* |
|
| `CLIENT_VER` | *WAITCOMMAND* |
|
||||||
| unknown | *FAIL* |
|
|
||||||
|
|
||||||
I/O in state *LOAD_FLASH*:
|
I/O in state *LOAD_FLASH*:
|
||||||
|
|
||||||
|
@ -222,16 +219,15 @@ I/O in state *LOAD_FLASH_MGMT*:
|
||||||
|--------------------|--------------|
|
|--------------------|--------------|
|
||||||
| Last app data read | *START* |
|
| Last app data read | *START* |
|
||||||
|
|
||||||
Commands in state *WAITCOMMAND*:
|
Commands in state `waitcommand`:
|
||||||
|
|
||||||
| *command* | *next state* |
|
| *command* | *next state* |
|
||||||
|-----------------------|--------------------------------------------|
|
|-----------------------|--------------|
|
||||||
| `FW_CMD_NAME_VERSION` | unchanged |
|
| `FW_CMD_NAME_VERSION` | unchanged |
|
||||||
| `FW_CMD_GET_UDI` | unchanged |
|
| `FW_CMD_GET_UDI` | unchanged |
|
||||||
| `FW_CMD_LOAD_APP` | *LOADING* or unchanged on invalid app size |
|
| `FW_CMD_LOAD_APP` | *LOADING* |
|
||||||
| | |
|
|
||||||
|
|
||||||
Commands in state *LOADING*:
|
Commands in state `loading`:
|
||||||
|
|
||||||
| *command* | *next state* |
|
| *command* | *next state* |
|
||||||
|------------------------|------------------------------------|
|
|------------------------|------------------------------------|
|
||||||
|
@ -248,23 +244,17 @@ Plain text explanation of the states:
|
||||||
- *INITIAL*: Start here. Check the `FW_RAM` for the `resetinfo` type
|
- *INITIAL*: Start here. Check the `FW_RAM` for the `resetinfo` type
|
||||||
for what to do next.
|
for what to do next.
|
||||||
|
|
||||||
For type `FLASH0` transition to *LOAD_FLASH_MGMT* because the app in
|
For all types which begins with `FLASH_*`, set next state to
|
||||||
slot 0 is considered a special management app. For all other types
|
*LOAD_FLASH*, otherwise set next state to *WAITCOMMAND*.
|
||||||
beginning with `FLASH*` transition to *LOAD_FLASH* to load an
|
|
||||||
ordinary app from flash.
|
|
||||||
|
|
||||||
For type `CLIENT*` transitionto *WAITCOMMAND* to expect a device app
|
|
||||||
from the client.
|
|
||||||
|
|
||||||
If type is unknown, error out.
|
|
||||||
|
|
||||||
- *LOAD_FLASH*: Load device app from flash into RAM, app slot taken
|
- *LOAD_FLASH*: Load device app from flash into RAM, app slot taken
|
||||||
from context. Compute a BLAKE2s digest over the entire app.
|
from context. Compute a BLAKE2s digest over the entire app.
|
||||||
Transition to *START*.
|
Transition to *START*.
|
||||||
|
|
||||||
- *LOAD_FLASH_MGMT*: Load device app from flash into RAM, app slot
|
- *LOAD_FLASH_MGMT*: Load device app from flash into RAM, app slot
|
||||||
always 0. Compute a BLAKE2s digest over the entire app. Register the
|
alway 0. Compute a BLAKE2s digest over the entire app. Register the
|
||||||
app as a prospective management app. Transition to *START*.
|
app as a prospective management app if it later goes through
|
||||||
|
verification. Transition to *START*.
|
||||||
|
|
||||||
- *WAITCOMMAND*: Wait for commands from the client. Transition to
|
- *WAITCOMMAND*: Wait for commands from the client. Transition to
|
||||||
*LOADING* on `LOAD_APP` command, which also sets the size of the
|
*LOADING* on `LOAD_APP` command, which also sets the size of the
|
||||||
|
@ -275,8 +265,7 @@ Plain text explanation of the states:
|
||||||
|
|
||||||
- *START*: Compute the Compound Device Identifier (CDI). If we have a
|
- *START*: Compute the Compound Device Identifier (CDI). If we have a
|
||||||
registered verification digest, verify that the app we are about to
|
registered verification digest, verify that the app we are about to
|
||||||
start is indeed the correct app. This also means that a prospective
|
start is indeed the correct app.
|
||||||
management app is now verified.
|
|
||||||
|
|
||||||
Clean up firmware data structures, enable the system calls, and
|
Clean up firmware data structures, enable the system calls, and
|
||||||
start the app, which ends the firmware state machine. Hardware
|
start the app, which ends the firmware state machine. Hardware
|
||||||
|
@ -299,38 +288,29 @@ state.
|
||||||
|
|
||||||
### Golden path from start to default app
|
### Golden path from start to default app
|
||||||
|
|
||||||
Firmware will load the device application at the start of RAM
|
Firmware loads the device application at the start of RAM
|
||||||
(`0x4000_0000`) from either flash or from the client through the UART.
|
(`0x4000_0000`) from either flash or from the client through the UART.
|
||||||
Firmware is using a part of the FW\_RAM for its own stack.
|
Firmware uses a part of the FW\_RAM for its own stack.
|
||||||
|
|
||||||
When reset is released, the CPU starts executing the firmware. It
|
When reset is released, the CPU starts executing the firmware. It
|
||||||
begins in `start.S` by clearing all CPU registers, clears all FW\_RAM,
|
begins in `start.S` by clearing all CPU registers, clears all FW\_RAM,
|
||||||
except the part reserved for the resetinfo area, sets up a stack for
|
sets up a stack for itself there, and then jumps to `main()`. Also
|
||||||
itself there, and then jumps to `main()`. Also included in the
|
included in the assembly part of firmware is an interrupt handler for
|
||||||
assembly part of firmware is an interrupt handler for the system
|
the system calls, but the handler is not yet enabled.
|
||||||
calls, but the handler is not yet enabled.
|
|
||||||
|
|
||||||
Beginning at `main()` it fills the entire RAM with pseudo random data
|
Beginning at `main()` it fills the entire RAM with pseudo random data
|
||||||
and setting up the RAM address and data hardware scrambling with
|
and setting up the RAM address and data hardware scrambling with
|
||||||
values from the True Random Number Generator (TRNG).
|
values from the True Random Number Generator (TRNG).
|
||||||
|
|
||||||
Firmware then proceeds to:
|
1. Check the special resetinfo area in FW\_RAM for reset type. Type
|
||||||
|
|
||||||
1. Read the partition table from flash and store in FW\_RAM.
|
|
||||||
|
|
||||||
2. Reset the CH552 USB controller to a known state, only allowing the
|
|
||||||
CDC USB endpoint and the internal command channel between the CPU
|
|
||||||
and the CH552.
|
|
||||||
|
|
||||||
3. Check the special resetinfo area in FW\_RAM for reset type. Type
|
|
||||||
zero means default behaviour, load from flash app slot 0, expecting
|
zero means default behaviour, load from flash app slot 0, expecting
|
||||||
the app there to have a specific hardcoded BLAKE2s digest.
|
the app there to have a specific hardcoded BLAKE2s digest.
|
||||||
|
|
||||||
4. Load app data from flash slot 0 into RAM.
|
2. Load app data from flash slot 0 into RAM.
|
||||||
|
|
||||||
5. Compute a BLAKE2s digest of the loaded app.
|
3. Compute a BLAKE2s digest of the loaded app.
|
||||||
|
|
||||||
6. Compare the computed digest against the allowed app digest
|
4. Compare the computed digest against the allowed app digest
|
||||||
hardcoded in the firmware. If it's not equal, halt CPU.
|
hardcoded in the firmware. If it's not equal, halt CPU.
|
||||||
|
|
||||||
7. [Start the device app](#start-the-device-app).
|
7. [Start the device app](#start-the-device-app).
|
||||||
|
@ -391,9 +371,9 @@ Such a verified boot loader app:
|
||||||
|
|
||||||
- Can be specifically trusted by firmware to be able to do filesystem
|
- Can be specifically trusted by firmware to be able to do filesystem
|
||||||
management to be able to update an app slot on flash. Add the app's
|
management to be able to update an app slot on flash. Add the app's
|
||||||
digest to `allowed_app_digest` in `mgmt_app.c` to allow it to use
|
digest to `allowed_app_digest` in `mgmt_app.c` to allow it to allow
|
||||||
`PRELOAD_DELETE`, `PRELOAD_STORE`, `PRELOAD_STORE_FIN`, and
|
it to use `PRELOAD_DELETE`, `PRELOAD_STORE`, and
|
||||||
`PRELOAD_GET_DIGSIG`.
|
`PRELOAD_STORE_FIN`.
|
||||||
|
|
||||||
It works like this:
|
It works like this:
|
||||||
|
|
||||||
|
@ -433,7 +413,7 @@ The loader shares the secret with the next app by putting it in the
|
||||||
part of `resetinfo` that is reserved for inter-app communication.
|
part of `resetinfo` that is reserved for inter-app communication.
|
||||||
|
|
||||||
The next app can now use the secret as a seed for it's own key
|
The next app can now use the secret as a seed for it's own key
|
||||||
material. Depending on the app's behaviour and the number of keys it
|
material. Depending on the app's behaviour and the numer of keys it
|
||||||
needs it can derive more keys, for instance by having nonces stored on
|
needs it can derive more keys, for instance by having nonces stored on
|
||||||
its flash area and doing:
|
its flash area and doing:
|
||||||
|
|
||||||
|
@ -553,9 +533,8 @@ struct reset {
|
||||||
};
|
};
|
||||||
|
|
||||||
struct reset rst;
|
struct reset rst;
|
||||||
uint32_t len; // Length of data in next_app_data.
|
|
||||||
|
|
||||||
syscall(TK1_SYSCALL_RESET, (uint32_t)&rst, len, 0);
|
syscall(TK1_SYSCALL_RESET, (uint32_t)&rst, 0, 0);
|
||||||
```
|
```
|
||||||
|
|
||||||
Resets the TKey. Does not return.
|
Resets the TKey. Does not return.
|
||||||
|
@ -564,7 +543,7 @@ You can pass data to the firmware about the reset type `type` and a
|
||||||
digest that the next app must have. You can also leave some data to
|
digest that the next app must have. You can also leave some data to
|
||||||
the next app in the chain in `next_app_data`.
|
the next app in the chain in `next_app_data`.
|
||||||
|
|
||||||
The types of reset are defined in `reset.h`:
|
The types of the reset are defined in `resetinfo.h`:
|
||||||
|
|
||||||
| *Name* | *Comment* |
|
| *Name* | *Comment* |
|
||||||
|--------------------|------------------------------------------------|
|
|--------------------|------------------------------------------------|
|
||||||
|
@ -598,15 +577,12 @@ success.
|
||||||
uint32_t offset = 0;
|
uint32_t offset = 0;
|
||||||
uint8_t buf[17];
|
uint8_t buf[17];
|
||||||
|
|
||||||
syscall(TK1_SYSCALL_WRITE_DATA, offset, (uint32_t)buf, sizeof(buf))
|
TK1_SYSCALL_WRITE_DATA, offset, (uint32_t)buf, sizeof(buf))
|
||||||
```
|
```
|
||||||
|
|
||||||
Write data in `buf` to the app's flash area at byte `offset` within
|
Write data in `buf` to the app's flash area at byte `offset` within
|
||||||
the area. Returns 0 on success.
|
the area. Returns 0 on success.
|
||||||
|
|
||||||
At most 4096 bytes can be written at once and `offset` must be a
|
|
||||||
multiple of 4096 bytes.
|
|
||||||
|
|
||||||
#### `READ_DATA`
|
#### `READ_DATA`
|
||||||
|
|
||||||
```
|
```
|
||||||
|
@ -618,20 +594,6 @@ syscall(TK1_SYSCALL_READ_DATA, offset, (uint32_t)buf, sizeof(buf);
|
||||||
|
|
||||||
Read into `buf` at byte `offset` from the app's flash area.
|
Read into `buf` at byte `offset` from the app's flash area.
|
||||||
|
|
||||||
#### `ERASE_DATA`
|
|
||||||
|
|
||||||
```
|
|
||||||
uint32_t offset = 0;
|
|
||||||
uint32_t size = 4096;
|
|
||||||
|
|
||||||
syscall(TK1_SYSCALL_ERASE_DATA, offset, size, 0);
|
|
||||||
```
|
|
||||||
|
|
||||||
Erase `size` bytes from `offset` within the area. Returns 0 on
|
|
||||||
success.
|
|
||||||
|
|
||||||
Both `size` and `offset` must be a multiple of 4096 bytes.
|
|
||||||
|
|
||||||
#### `PRELOAD_DELETE`
|
#### `PRELOAD_DELETE`
|
||||||
|
|
||||||
```
|
```
|
||||||
|
@ -653,14 +615,9 @@ syscall(TK1_SYSCALL_PRELOAD_STORE, offset, (uint32_t)appbinary,
|
||||||
```
|
```
|
||||||
|
|
||||||
Store an app, or possible just a block of an app, from the `appbinary`
|
Store an app, or possible just a block of an app, from the `appbinary`
|
||||||
buffer in flash slot 1 at byte `offset`.
|
buffer in flash slot 1 at byte `offset` If you can't find your entire
|
||||||
|
app in the buffer, call `PRELOAD_STORE` many times as you receive the
|
||||||
If you can't fit your entire app in the buffer, call `PRELOAD_STORE`
|
binary from the client. Returns 0 on success.
|
||||||
many times as you receive the binary from the client. Returns 0 on
|
|
||||||
success.
|
|
||||||
|
|
||||||
At most 4096 bytes can be written at once and `offset` must be a
|
|
||||||
multiple of 4096 bytes.
|
|
||||||
|
|
||||||
Only available for the verified management app.
|
Only available for the verified management app.
|
||||||
|
|
||||||
|
@ -679,8 +636,7 @@ Finalize storing of an app where the complete binary size is
|
||||||
`app_size` in flash slot 1. Returns 0 on success. Only available for
|
`app_size` in flash slot 1. Returns 0 on success. Only available for
|
||||||
the verified management app.
|
the verified management app.
|
||||||
|
|
||||||
Compute a BLAKE2s hash digest over the entire binary. Pass the result
|
Compute the `app_digest` with BLAKE2s over the entire binary.
|
||||||
in `app_digest`.
|
|
||||||
|
|
||||||
Sign `app_digest` with your Ed25519 private key and pass the
|
Sign `app_digest` with your Ed25519 private key and pass the
|
||||||
resulting signature in `app_signature`.
|
resulting signature in `app_signature`.
|
||||||
|
@ -737,9 +693,6 @@ functions. Note that these functions are only usable in QEMU and that
|
||||||
you might need to `make clean` before building, if you have already
|
you might need to `make clean` before building, if you have already
|
||||||
built before.
|
built before.
|
||||||
|
|
||||||
To build a flash image file suitable for use with qemu, use the
|
|
||||||
`tools/tkeyimage` program. See its documentation.
|
|
||||||
|
|
||||||
If you want debug prints to show up on the special TKey HID debug
|
If you want debug prints to show up on the special TKey HID debug
|
||||||
endpoint instead, define `-DTKEY_DEBUG`. This might mean you can't fit
|
endpoint instead, define `-DTKEY_DEBUG`. This might mean you can't fit
|
||||||
the firmware in the ROM space available, however. You will get a
|
the firmware in the ROM space available, however. You will get a
|
||||||
|
@ -768,27 +721,7 @@ initiated before starting for the first time. You need a [TKey
|
||||||
Programmer Board](https://shop.tillitis.se/products/tkey-dev-kit) for
|
Programmer Board](https://shop.tillitis.se/products/tkey-dev-kit) for
|
||||||
this part.
|
this part.
|
||||||
|
|
||||||
If you just want to build and flash the bitstream, the testloadapp in
|
1. Choose your pre-loaded app. You /must/ have a pre-loaded app, for
|
||||||
app slot 0, and the partition table copies in one go, place the TKey
|
|
||||||
Unlocked in the TP1, then:
|
|
||||||
|
|
||||||
Using Podman, from the top level directory:
|
|
||||||
|
|
||||||
```
|
|
||||||
cd contrib
|
|
||||||
make flash
|
|
||||||
```
|
|
||||||
|
|
||||||
Using native tools:
|
|
||||||
|
|
||||||
```
|
|
||||||
cd hw/application_fpga
|
|
||||||
make prog_flash
|
|
||||||
```
|
|
||||||
|
|
||||||
If you want to prepare the filesystem yourself:
|
|
||||||
|
|
||||||
1. Choose your pre-loaded app. You *must* have a pre-loaded app, for
|
|
||||||
example `testloadapp`. Build it with the OCI image we use. The
|
example `testloadapp`. Build it with the OCI image we use. The
|
||||||
binary needs to produce the BLAKE2s digest in `allowed_app_digest`
|
binary needs to produce the BLAKE2s digest in `allowed_app_digest`
|
||||||
`tk1/mgmt_app.c`.
|
`tk1/mgmt_app.c`.
|
||||||
|
@ -808,10 +741,10 @@ If you want to use a different pre-loaded app you have to
|
||||||
2. Update the `allowed_app_digest` in `tk1/mgmt_app.c`.
|
2. Update the `allowed_app_digest` in `tk1/mgmt_app.c`.
|
||||||
|
|
||||||
3. Create a new `default_partition.bin` using the
|
3. Create a new `default_partition.bin` using the
|
||||||
`tools/tkeyimage`, typically:
|
`tools/partition_table`, typically:
|
||||||
|
|
||||||
```
|
```
|
||||||
$ tkeyimage -app0 path/to/your/app.bin -o default_partition.bin
|
$ partition_table -app0 path/to/your/app.bin -o default_partition.bin
|
||||||
```
|
```
|
||||||
|
|
||||||
4. Flash the filesystem image:
|
4. Flash the filesystem image:
|
||||||
|
@ -835,5 +768,19 @@ ordinary `application_fpga/Makefile` to be able to fit in ROM.
|
||||||
|
|
||||||
### Test apps
|
### Test apps
|
||||||
|
|
||||||
There are a couple of test apps, see `../apps`.
|
There are a couple of test apps. All of them are controlled through
|
||||||
|
the USB CDC, typically by running picocom or similar terminal program,
|
||||||
|
like:
|
||||||
|
|
||||||
|
```
|
||||||
|
$ picocom /dev/ttyACM1
|
||||||
|
```
|
||||||
|
|
||||||
|
or similar.
|
||||||
|
|
||||||
|
- `fw/testapp`: Runs through a couple of tests that are now impossible
|
||||||
|
to do in the `testfw`.
|
||||||
|
- `fw/reset_test`: Interactively test different reset scenarios.
|
||||||
|
- `fw/testloadapp`: Interactively test management app things like
|
||||||
|
installing an app (hardcoded for a small happy blinking app, see
|
||||||
|
`blink.h` for the entire binary!) and to test verified boot.
|
||||||
|
|
75
hw/application_fpga/fw/reset_test/Makefile
Normal file
75
hw/application_fpga/fw/reset_test/Makefile
Normal file
|
@ -0,0 +1,75 @@
|
||||||
|
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) \
|
||||||
|
-DTKEY_DEBUG
|
||||||
|
|
||||||
|
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: reset_test.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)
|
||||||
|
|
||||||
|
RESET_TEST_FMTFILES = *.[ch]
|
||||||
|
|
||||||
|
RESET_TEST_OBJS = \
|
||||||
|
$(P)/main.o \
|
||||||
|
$(P)/crt0.o \
|
||||||
|
$(P)/syscall.o
|
||||||
|
|
||||||
|
reset_test.elf: tkey-libs $(RESET_TEST_OBJS)
|
||||||
|
$(CC) $(CFLAGS) $(RESET_TEST_OBJS) $(LDFLAGS) -o $@
|
||||||
|
|
||||||
|
.PHONY: fmt
|
||||||
|
fmt:
|
||||||
|
clang-format --dry-run --ferror-limit=0 $(RESET_TEST_FMTFILES)
|
||||||
|
clang-format --verbose -i $(RESET_TEST_FMTFILES)
|
||||||
|
|
||||||
|
.PHONY: checkfmt
|
||||||
|
checkfmt:
|
||||||
|
clang-format --dry-run --ferror-limit=0 --Werror $(RESET_TEST_FMTFILES)
|
||||||
|
|
||||||
|
.PHONY: clean
|
||||||
|
clean:
|
||||||
|
rm -f reset_test.bin reset_test.elf $(RESET_TEST_OBJS)
|
64
hw/application_fpga/fw/reset_test/app.lds
Normal file
64
hw/application_fpga/fw/reset_test/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/reset_test/crt0.S
Normal file
53
hw/application_fpga/fw/reset_test/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
|
|
@ -1,11 +1,9 @@
|
||||||
// Copyright (C) 2022, 2023 - Tillitis AB
|
/*
|
||||||
// SPDX-License-Identifier: GPL-2.0-only
|
* Copyright (C) 2022, 2023 - Tillitis AB
|
||||||
|
* SPDX-License-Identifier: GPL-2.0-only
|
||||||
|
*/
|
||||||
|
|
||||||
#include <fw/tk1/proto.h>
|
|
||||||
#include <fw/tk1/reset.h>
|
|
||||||
#include <fw/tk1/syscall_num.h>
|
|
||||||
#include <stdint.h>
|
#include <stdint.h>
|
||||||
#include <syscall.h>
|
|
||||||
#include <tkey/assert.h>
|
#include <tkey/assert.h>
|
||||||
#include <tkey/debug.h>
|
#include <tkey/debug.h>
|
||||||
#include <tkey/io.h>
|
#include <tkey/io.h>
|
||||||
|
@ -13,6 +11,11 @@
|
||||||
#include <tkey/lib.h>
|
#include <tkey/lib.h>
|
||||||
#include <tkey/tk1_mem.h>
|
#include <tkey/tk1_mem.h>
|
||||||
|
|
||||||
|
#include "../testapp/syscall.h"
|
||||||
|
#include "../tk1/proto.h"
|
||||||
|
#include "../tk1/resetinfo.h"
|
||||||
|
#include "../tk1/syscall_num.h"
|
||||||
|
|
||||||
// Converts a single hex character to its integer value
|
// Converts a single hex character to its integer value
|
||||||
static uint8_t hex_char_to_byte(uint8_t c)
|
static uint8_t hex_char_to_byte(uint8_t c)
|
||||||
{
|
{
|
|
@ -1,7 +1,7 @@
|
||||||
// SPDX-FileCopyrightText: 2024 Tillitis AB <tillitis.se>
|
// SPDX-FileCopyrightText: 2024 Tillitis AB <tillitis.se>
|
||||||
// SPDX-License-Identifier: BSD-2-Clause
|
// SPDX-License-Identifier: BSD-2-Clause
|
||||||
|
|
||||||
#include "../fw/tk1/picorv32/custom_ops.S"
|
#include "../tk1/picorv32/custom_ops.S"
|
||||||
|
|
||||||
.section ".text"
|
.section ".text"
|
||||||
.globl syscall
|
.globl syscall
|
74
hw/application_fpga/fw/testapp/Makefile
Normal file
74
hw/application_fpga/fw/testapp/Makefile
Normal file
|
@ -0,0 +1,74 @@
|
||||||
|
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 = *.[ch]
|
||||||
|
|
||||||
|
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
|
|
@ -1,9 +1,8 @@
|
||||||
// Copyright (C) 2022, 2023 - Tillitis AB
|
/*
|
||||||
// SPDX-License-Identifier: GPL-2.0-only
|
* Copyright (C) 2022, 2023 - Tillitis AB
|
||||||
|
* SPDX-License-Identifier: GPL-2.0-only
|
||||||
|
*/
|
||||||
|
|
||||||
#include <fw/tk1/proto.h>
|
|
||||||
#include <fw/tk1/reset.h>
|
|
||||||
#include <fw/tk1/syscall_num.h>
|
|
||||||
#include <stdint.h>
|
#include <stdint.h>
|
||||||
#include <tkey/assert.h>
|
#include <tkey/assert.h>
|
||||||
#include <tkey/io.h>
|
#include <tkey/io.h>
|
||||||
|
@ -11,6 +10,9 @@
|
||||||
#include <tkey/lib.h>
|
#include <tkey/lib.h>
|
||||||
#include <tkey/tk1_mem.h>
|
#include <tkey/tk1_mem.h>
|
||||||
|
|
||||||
|
#include "../tk1/proto.h"
|
||||||
|
#include "../tk1/resetinfo.h"
|
||||||
|
#include "../tk1/syscall_num.h"
|
||||||
#include "syscall.h"
|
#include "syscall.h"
|
||||||
|
|
||||||
#define USBMODE_PACKET_SIZE 64
|
#define USBMODE_PACKET_SIZE 64
|
||||||
|
@ -18,7 +20,6 @@
|
||||||
// clang-format off
|
// clang-format off
|
||||||
volatile uint32_t *tk1name0 = (volatile uint32_t *)TK1_MMIO_TK1_NAME0;
|
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 *tk1name1 = (volatile uint32_t *)TK1_MMIO_TK1_NAME1;
|
||||||
volatile uint32_t *tk1version = (volatile uint32_t *)TK1_MMIO_TK1_VERSION;
|
|
||||||
volatile uint32_t *uds = (volatile uint32_t *)TK1_MMIO_UDS_FIRST;
|
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 *cdi = (volatile uint32_t *)TK1_MMIO_TK1_CDI_FIRST;
|
||||||
volatile uint32_t *udi = (volatile uint32_t *)TK1_MMIO_TK1_UDI_FIRST;
|
volatile uint32_t *udi = (volatile uint32_t *)TK1_MMIO_TK1_UDI_FIRST;
|
||||||
|
@ -97,9 +98,6 @@ int main(void)
|
||||||
reverseword(&name);
|
reverseword(&name);
|
||||||
write(IO_CDC, (const uint8_t *)&name, 4);
|
write(IO_CDC, (const uint8_t *)&name, 4);
|
||||||
puts(IO_CDC, "\r\n");
|
puts(IO_CDC, "\r\n");
|
||||||
puts(IO_CDC, "Version: ");
|
|
||||||
putinthex(IO_CDC, *tk1version);
|
|
||||||
puts(IO_CDC, "\r\n");
|
|
||||||
|
|
||||||
uint32_t zeros[8];
|
uint32_t zeros[8];
|
||||||
memset(zeros, 0, 8 * 4);
|
memset(zeros, 0, 8 * 4);
|
||||||
|
@ -126,8 +124,8 @@ int main(void)
|
||||||
// But a syscall to get parts of UDI should be able to run
|
// But a syscall to get parts of UDI should be able to run
|
||||||
int vidpid = syscall(TK1_SYSCALL_GET_VIDPID, 0, 0, 0);
|
int vidpid = syscall(TK1_SYSCALL_GET_VIDPID, 0, 0, 0);
|
||||||
|
|
||||||
if (vidpid != 0x073570c0) {
|
if (vidpid != 0x00010203) {
|
||||||
failmsg("Expected VID/PID to be 0x073570c0");
|
failmsg("Expected VID/PID to be 0x00010203");
|
||||||
anyfailed = 1;
|
anyfailed = 1;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -147,7 +145,7 @@ int main(void)
|
||||||
}
|
}
|
||||||
puts(IO_CDC, "done.\r\n");
|
puts(IO_CDC, "done.\r\n");
|
||||||
|
|
||||||
puts(IO_CDC, "\r\nReading data from storage area...");
|
puts(IO_CDC, "\r\nReading from storage area...");
|
||||||
|
|
||||||
uint8_t in_data[14] = {0};
|
uint8_t in_data[14] = {0};
|
||||||
if (syscall(TK1_SYSCALL_READ_DATA, 0, (uint32_t)in_data,
|
if (syscall(TK1_SYSCALL_READ_DATA, 0, (uint32_t)in_data,
|
||||||
|
@ -160,28 +158,6 @@ int main(void)
|
||||||
}
|
}
|
||||||
puts(IO_CDC, "done.\r\n");
|
puts(IO_CDC, "done.\r\n");
|
||||||
|
|
||||||
puts(IO_CDC, "\r\nErasing written data from storage area...");
|
|
||||||
|
|
||||||
if (syscall(TK1_SYSCALL_ERASE_DATA, 0, 4096, 0) != 0) {
|
|
||||||
failmsg("Failed to erase storage area");
|
|
||||||
}
|
|
||||||
puts(IO_CDC, "done.\r\n");
|
|
||||||
|
|
||||||
puts(IO_CDC, "\r\nVerify erased storage area data...");
|
|
||||||
|
|
||||||
if (syscall(TK1_SYSCALL_READ_DATA, 0, (uint32_t)in_data,
|
|
||||||
sizeof(in_data)) != 0) {
|
|
||||||
failmsg("Failed to write to storage area");
|
|
||||||
}
|
|
||||||
uint8_t check_data[sizeof(in_data)] = {0xff, 0xff, 0xff, 0xff, 0xff,
|
|
||||||
0xff, 0xff, 0xff, 0xff, 0xff,
|
|
||||||
0xff, 0xff, 0xff, 0xff};
|
|
||||||
if (!memeq(in_data, check_data, sizeof(check_data))) {
|
|
||||||
failmsg("Failed to read back data from storage area");
|
|
||||||
anyfailed = 1;
|
|
||||||
}
|
|
||||||
puts(IO_CDC, "done.\r\n");
|
|
||||||
|
|
||||||
puts(IO_CDC, "\r\nDeallocating storage area...");
|
puts(IO_CDC, "\r\nDeallocating storage area...");
|
||||||
|
|
||||||
if (syscall(TK1_SYSCALL_DEALLOC_AREA, 0, 0, 0) != 0) {
|
if (syscall(TK1_SYSCALL_DEALLOC_AREA, 0, 0, 0) != 0) {
|
||||||
|
@ -214,8 +190,8 @@ int main(void)
|
||||||
}
|
}
|
||||||
|
|
||||||
puts(IO_CDC, "\r\nTesting timer... 3");
|
puts(IO_CDC, "\r\nTesting timer... 3");
|
||||||
// Matching clock at 24 MHz, giving us timer in seconds
|
// Matching clock at 21 MHz, giving us timer in seconds
|
||||||
*timer_prescaler = 24 * 1000000;
|
*timer_prescaler = 21 * 1000000;
|
||||||
|
|
||||||
// Test timer expiration after 1s
|
// Test timer expiration after 1s
|
||||||
*timer = 1;
|
*timer = 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
|
|
@ -1,5 +1,7 @@
|
||||||
// Copyright (C) 2022, 2023 - Tillitis AB
|
/*
|
||||||
// SPDX-License-Identifier: GPL-2.0-only
|
* Copyright (C) 2022, 2023 - Tillitis AB
|
||||||
|
* SPDX-License-Identifier: GPL-2.0-only
|
||||||
|
*/
|
||||||
|
|
||||||
#include <stddef.h>
|
#include <stddef.h>
|
||||||
#include <stdint.h>
|
#include <stdint.h>
|
||||||
|
|
|
@ -1,5 +1,7 @@
|
||||||
// Copyright (C) 2022, 2023 - Tillitis AB
|
/*
|
||||||
// SPDX-License-Identifier: GPL-2.0-only
|
* Copyright (C) 2022, 2023 - Tillitis AB
|
||||||
|
* SPDX-License-Identifier: GPL-2.0-only
|
||||||
|
*/
|
||||||
|
|
||||||
.section ".text.init"
|
.section ".text.init"
|
||||||
.globl _start
|
.globl _start
|
||||||
|
@ -36,7 +38,7 @@ _start:
|
||||||
li x30,0
|
li x30,0
|
||||||
li x31,0
|
li x31,0
|
||||||
|
|
||||||
// Clear all RAM
|
/* Clear all RAM */
|
||||||
li a0, 0x40000000 // TK1_RAM_BASE
|
li a0, 0x40000000 // TK1_RAM_BASE
|
||||||
li a1, 0x40020000 // TK1_RAM_BASE + TK1_RAM_SIZE
|
li a1, 0x40020000 // TK1_RAM_BASE + TK1_RAM_SIZE
|
||||||
clear:
|
clear:
|
||||||
|
@ -44,9 +46,9 @@ clear:
|
||||||
addi a0, a0, 4
|
addi a0, a0, 4
|
||||||
blt a0, a1, clear
|
blt a0, a1, clear
|
||||||
|
|
||||||
// NOTE WELL
|
/*
|
||||||
// For testfw we init stack at top of RAM
|
* For testfw we init stack at top of RAM
|
||||||
//
|
*/
|
||||||
li sp, 0x40020000 // TK1_RAM_BASE + TK1_RAM_SIZE
|
li sp, 0x40020000 // TK1_RAM_BASE + TK1_RAM_SIZE
|
||||||
|
|
||||||
call main
|
call main
|
||||||
|
|
73
hw/application_fpga/fw/testloadapp/Makefile
Normal file
73
hw/application_fpga/fw/testloadapp/Makefile
Normal file
|
@ -0,0 +1,73 @@
|
||||||
|
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 \
|
||||||
|
-Os \
|
||||||
|
-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 $(LIBDIR)/app.lds \
|
||||||
|
-L $(LIBDIR) -lcrt0 -lcommon -lmonocypher -lblake2s
|
||||||
|
|
||||||
|
.PHONY: all
|
||||||
|
all: testloadapp.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)
|
||||||
|
|
||||||
|
TESTLOADAPP_FMTFILES = *.[ch]
|
||||||
|
|
||||||
|
TESTLOADAPP_OBJS = \
|
||||||
|
$(P)/main.o \
|
||||||
|
../testapp/syscall.o \
|
||||||
|
|
||||||
|
testloadapp.elf: tkey-libs $(TESTLOADAPP_OBJS)
|
||||||
|
$(CC) $(CFLAGS) $(TESTLOADAPP_OBJS) $(LDFLAGS) -o $@
|
||||||
|
|
||||||
|
.PHONY: fmt
|
||||||
|
fmt:
|
||||||
|
clang-format --dry-run --ferror-limit=0 $(TESTLOADAPP_FMTFILES)
|
||||||
|
clang-format --verbose -i $(TESTLOADAPP_FMTFILES)
|
||||||
|
|
||||||
|
.PHONY: checkfmt
|
||||||
|
checkfmt:
|
||||||
|
clang-format --dry-run --ferror-limit=0 --Werror $(TESTLOADAPP_FMTFILES)
|
||||||
|
|
||||||
|
.PHONY: clean
|
||||||
|
clean:
|
||||||
|
rm -f testloadapp.bin testloadapp.elf $(TESTLOADAPP_OBJS)
|
|
@ -1,6 +1,3 @@
|
||||||
// Copyright (C) 2025 - Tillitis AB
|
|
||||||
// SPDX-License-Identifier: GPL-2.0-only
|
|
||||||
|
|
||||||
#ifndef BLINK_APP_H
|
#ifndef BLINK_APP_H
|
||||||
#define BLINK_APP_H
|
#define BLINK_APP_H
|
||||||
|
|
|
@ -1,19 +1,15 @@
|
||||||
// Copyright (C) 2025 - Tillitis AB
|
|
||||||
// SPDX-License-Identifier: GPL-2.0-only
|
|
||||||
|
|
||||||
#include <blake2s/blake2s.h>
|
#include <blake2s/blake2s.h>
|
||||||
#include <fw/tk1/reset.h>
|
|
||||||
#include <fw/tk1/syscall_num.h>
|
|
||||||
#include <monocypher/monocypher-ed25519.h>
|
#include <monocypher/monocypher-ed25519.h>
|
||||||
#include <stdint.h>
|
#include <stdint.h>
|
||||||
#include <tkey/assert.h>
|
|
||||||
#include <tkey/debug.h>
|
#include <tkey/debug.h>
|
||||||
#include <tkey/led.h>
|
|
||||||
#include <tkey/lib.h>
|
#include <tkey/lib.h>
|
||||||
#include <tkey/tk1_mem.h>
|
#include <tkey/tk1_mem.h>
|
||||||
|
|
||||||
|
#include "../testapp/syscall.h"
|
||||||
|
#include "../tk1/resetinfo.h"
|
||||||
|
#include "../tk1/syscall_num.h"
|
||||||
#include "blink.h"
|
#include "blink.h"
|
||||||
#include "syscall.h"
|
#include "tkey/assert.h"
|
||||||
|
|
||||||
// clang-format off
|
// clang-format off
|
||||||
static volatile uint32_t *cdi = (volatile uint32_t *) TK1_MMIO_TK1_CDI_FIRST;
|
static volatile uint32_t *cdi = (volatile uint32_t *) TK1_MMIO_TK1_CDI_FIRST;
|
||||||
|
@ -154,11 +150,7 @@ void reset_from_client(void)
|
||||||
|
|
||||||
rst.type = START_CLIENT;
|
rst.type = START_CLIENT;
|
||||||
|
|
||||||
// Give the next in chain something to look at.
|
syscall(TK1_SYSCALL_RESET, (uint32_t)&rst, 0, 0);
|
||||||
memset(rst.next_app_data, 17, sizeof(rst.next_app_data));
|
|
||||||
|
|
||||||
syscall(TK1_SYSCALL_RESET, (uint32_t)&rst, sizeof(rst.next_app_data),
|
|
||||||
0);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
int main(void)
|
int main(void)
|
||||||
|
@ -169,8 +161,6 @@ int main(void)
|
||||||
uint8_t available;
|
uint8_t available;
|
||||||
uint8_t in = 0;
|
uint8_t in = 0;
|
||||||
|
|
||||||
led_set(LED_BLUE);
|
|
||||||
|
|
||||||
// Generate a key pair from CDI
|
// Generate a key pair from CDI
|
||||||
crypto_ed25519_key_pair(secret_key, pubkey, (uint8_t *)cdi);
|
crypto_ed25519_key_pair(secret_key, pubkey, (uint8_t *)cdi);
|
||||||
|
|
|
@ -14,8 +14,8 @@
|
||||||
|
|
||||||
static volatile uint32_t *cdi = (volatile uint32_t *)TK1_MMIO_TK1_CDI_FIRST;
|
static volatile uint32_t *cdi = (volatile uint32_t *)TK1_MMIO_TK1_CDI_FIRST;
|
||||||
|
|
||||||
// Calculates the authentication digest based on a supplied nonce and
|
/* Calculates the authentication digest based on a supplied nonce and the CDI.
|
||||||
// the CDI. Requires that the CDI is already calculated and stored
|
* Requires that the CDI is already calculated and stored */
|
||||||
static void calculate_auth_digest(uint8_t *nonce, uint8_t *auth_digest)
|
static void calculate_auth_digest(uint8_t *nonce, uint8_t *auth_digest)
|
||||||
{
|
{
|
||||||
assert(nonce != NULL);
|
assert(nonce != NULL);
|
||||||
|
@ -31,7 +31,7 @@ static void calculate_auth_digest(uint8_t *nonce, uint8_t *auth_digest)
|
||||||
blake2s_final(&ctx, auth_digest);
|
blake2s_final(&ctx, auth_digest);
|
||||||
}
|
}
|
||||||
|
|
||||||
// Generates a 16 byte nonce
|
/* Generates a 16 byte nonce */
|
||||||
static void generate_nonce(uint32_t *nonce)
|
static void generate_nonce(uint32_t *nonce)
|
||||||
{
|
{
|
||||||
assert(nonce != NULL);
|
assert(nonce != NULL);
|
||||||
|
@ -41,9 +41,8 @@ static void generate_nonce(uint32_t *nonce)
|
||||||
}
|
}
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
/* Returns the authentication digest and random nonce. Requires that the CDI is
|
||||||
// Returns the authentication digest and random nonce. Requires that
|
* already calculated and stored */
|
||||||
// the CDI is already calculated and stored
|
|
||||||
void auth_app_create(struct auth_metadata *auth_table)
|
void auth_app_create(struct auth_metadata *auth_table)
|
||||||
{
|
{
|
||||||
assert(auth_table != NULL);
|
assert(auth_table != NULL);
|
||||||
|
|
|
@ -10,12 +10,36 @@
|
||||||
#include "flash.h"
|
#include "flash.h"
|
||||||
#include "spi.h"
|
#include "spi.h"
|
||||||
|
|
||||||
|
// 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;
|
||||||
|
// clang-format on
|
||||||
|
|
||||||
|
// CPU clock frequency in Hz
|
||||||
|
#define CPUFREQ 21000000
|
||||||
#define PAGE_SIZE 256
|
#define PAGE_SIZE 256
|
||||||
|
|
||||||
static bool flash_is_busy(void);
|
static bool flash_is_busy(void);
|
||||||
static void flash_wait_busy(void);
|
static void flash_wait_busy(void);
|
||||||
static void flash_write_enable(void);
|
static void flash_write_enable(void);
|
||||||
|
|
||||||
|
static void delay(int timeout_ms)
|
||||||
|
{
|
||||||
|
// Tick once every centisecond
|
||||||
|
*timer_prescaler = CPUFREQ / 100;
|
||||||
|
*timer = timeout_ms / 10;
|
||||||
|
|
||||||
|
*timer_ctrl |= (1 << TK1_MMIO_TIMER_CTRL_START_BIT);
|
||||||
|
|
||||||
|
while (*timer_status != 0) {
|
||||||
|
}
|
||||||
|
|
||||||
|
// Stop timer
|
||||||
|
*timer_ctrl |= (1 << TK1_MMIO_TIMER_CTRL_STOP_BIT);
|
||||||
|
}
|
||||||
|
|
||||||
static bool flash_is_busy(void)
|
static bool flash_is_busy(void)
|
||||||
{
|
{
|
||||||
uint8_t tx_buf = READ_STATUS_REG_1;
|
uint8_t tx_buf = READ_STATUS_REG_1;
|
||||||
|
@ -34,8 +58,9 @@ static bool flash_is_busy(void)
|
||||||
// Blocking until !busy
|
// Blocking until !busy
|
||||||
static void flash_wait_busy(void)
|
static void flash_wait_busy(void)
|
||||||
{
|
{
|
||||||
while (flash_is_busy())
|
while (flash_is_busy()) {
|
||||||
;
|
delay(10);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
static void flash_write_enable(void)
|
static void flash_write_enable(void)
|
||||||
|
@ -176,11 +201,7 @@ int flash_write_data(uint32_t address, uint8_t *data, size_t size)
|
||||||
return -1;
|
return -1;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (size <= 0) {
|
if (size <= 0 || size > 4096) {
|
||||||
return -1;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (address % 256 != 0) {
|
|
||||||
return -1;
|
return -1;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -188,12 +209,6 @@ int flash_write_data(uint32_t address, uint8_t *data, size_t size)
|
||||||
uint8_t *p_data = data;
|
uint8_t *p_data = data;
|
||||||
size_t n_bytes = 0;
|
size_t n_bytes = 0;
|
||||||
|
|
||||||
// Page Program allows 1-256 bytes of a page to be written. A page is
|
|
||||||
// 256 bytes. Behavior when writing past the end of a page is device
|
|
||||||
// specific.
|
|
||||||
//
|
|
||||||
// We set the address LSByte to 0 and only write 256 bytes or less in
|
|
||||||
// each transfer.
|
|
||||||
uint8_t tx_buf[4] = {
|
uint8_t tx_buf[4] = {
|
||||||
PAGE_PROGRAM, /* tx_buf[0] */
|
PAGE_PROGRAM, /* tx_buf[0] */
|
||||||
(address >> ADDR_BYTE_3_BIT) & 0xFF, /* tx_buf[1] */
|
(address >> ADDR_BYTE_3_BIT) & 0xFF, /* tx_buf[1] */
|
||||||
|
|
|
@ -1,5 +1,7 @@
|
||||||
// Copyright (C) 2022, 2023 - Tillitis AB
|
/*
|
||||||
// SPDX-License-Identifier: GPL-2.0-only
|
* Copyright (C) 2022, 2023 - Tillitis AB
|
||||||
|
* SPDX-License-Identifier: GPL-2.0-only
|
||||||
|
*/
|
||||||
|
|
||||||
#include <blake2s/blake2s.h>
|
#include <blake2s/blake2s.h>
|
||||||
#include <stdbool.h>
|
#include <stdbool.h>
|
||||||
|
@ -15,7 +17,7 @@
|
||||||
#include "partition_table.h"
|
#include "partition_table.h"
|
||||||
#include "preload_app.h"
|
#include "preload_app.h"
|
||||||
#include "proto.h"
|
#include "proto.h"
|
||||||
#include "reset.h"
|
#include "resetinfo.h"
|
||||||
#include "state.h"
|
#include "state.h"
|
||||||
#include "syscall_enable.h"
|
#include "syscall_enable.h"
|
||||||
|
|
||||||
|
@ -36,7 +38,7 @@ static volatile uint32_t *timer_status = (volatile uint32_t *)TK1_MMIO_TIMER
|
||||||
static volatile uint32_t *timer_ctrl = (volatile uint32_t *)TK1_MMIO_TIMER_CTRL;
|
static volatile uint32_t *timer_ctrl = (volatile uint32_t *)TK1_MMIO_TIMER_CTRL;
|
||||||
static volatile uint32_t *ram_addr_rand = (volatile uint32_t *)TK1_MMIO_TK1_RAM_ADDR_RAND;
|
static volatile uint32_t *ram_addr_rand = (volatile uint32_t *)TK1_MMIO_TK1_RAM_ADDR_RAND;
|
||||||
static volatile uint32_t *ram_data_rand = (volatile uint32_t *)TK1_MMIO_TK1_RAM_DATA_RAND;
|
static volatile uint32_t *ram_data_rand = (volatile uint32_t *)TK1_MMIO_TK1_RAM_DATA_RAND;
|
||||||
static volatile struct reset *resetinfo = (volatile struct reset *)TK1_MMIO_RESETINFO_BASE;
|
static volatile struct reset *resetinfo = (volatile struct reset *)TK1_MMIO_RESETINFO_BASE;
|
||||||
// clang-format on
|
// clang-format on
|
||||||
|
|
||||||
struct partition_table_storage part_table_storage;
|
struct partition_table_storage part_table_storage;
|
||||||
|
@ -250,8 +252,6 @@ static enum state initial_commands(const struct frame_header *hdr,
|
||||||
|
|
||||||
ctx->left = *app_size;
|
ctx->left = *app_size;
|
||||||
|
|
||||||
led_set(LED_BLACK);
|
|
||||||
|
|
||||||
state = FW_STATE_LOADING;
|
state = FW_STATE_LOADING;
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
@ -444,19 +444,7 @@ static enum state start_where(struct context *ctx)
|
||||||
{
|
{
|
||||||
assert(ctx != NULL);
|
assert(ctx != NULL);
|
||||||
|
|
||||||
debug_puts("resetinfo->type: ");
|
// Where do we start? Read resetinfo 'startfrom'
|
||||||
debug_putinthex(resetinfo->type);
|
|
||||||
debug_lf();
|
|
||||||
|
|
||||||
debug_puts(" ->app_digest: \n");
|
|
||||||
debug_hexdump((void *)resetinfo->app_digest, RESET_DIGEST_SIZE);
|
|
||||||
debug_lf();
|
|
||||||
|
|
||||||
debug_puts(" ->next_app_data: \n");
|
|
||||||
debug_hexdump((void *)resetinfo->next_app_data, RESET_DATA_SIZE);
|
|
||||||
debug_lf();
|
|
||||||
|
|
||||||
// Where do we start?
|
|
||||||
switch (resetinfo->type) {
|
switch (resetinfo->type) {
|
||||||
case START_DEFAULT:
|
case START_DEFAULT:
|
||||||
// fallthrough
|
// fallthrough
|
||||||
|
@ -508,6 +496,8 @@ int main(void)
|
||||||
uint8_t cmd[CMDSIZE] = {0};
|
uint8_t cmd[CMDSIZE] = {0};
|
||||||
enum state state = FW_STATE_INITIAL;
|
enum state state = FW_STATE_INITIAL;
|
||||||
|
|
||||||
|
led_set(LED_BLUE);
|
||||||
|
|
||||||
print_hw_version();
|
print_hw_version();
|
||||||
|
|
||||||
/*@-mustfreeonly@*/
|
/*@-mustfreeonly@*/
|
||||||
|
@ -521,17 +511,10 @@ int main(void)
|
||||||
scramble_ram();
|
scramble_ram();
|
||||||
|
|
||||||
if (part_table_read(&part_table_storage) != 0) {
|
if (part_table_read(&part_table_storage) != 0) {
|
||||||
// Couldn't read partition table
|
// Couldn't read or create partition table
|
||||||
debug_puts("Couldn't read partition table\n");
|
|
||||||
assert(1 == 2);
|
assert(1 == 2);
|
||||||
}
|
}
|
||||||
|
|
||||||
// Reset the USB controller to only enable the USB CDC
|
|
||||||
// endpoint and the internal command channel.
|
|
||||||
config_endpoints(IO_CDC | IO_CH552);
|
|
||||||
|
|
||||||
led_set(LED_WHITE);
|
|
||||||
|
|
||||||
#if defined(SIMULATION)
|
#if defined(SIMULATION)
|
||||||
run(&ctx);
|
run(&ctx);
|
||||||
#endif
|
#endif
|
||||||
|
@ -584,7 +567,6 @@ int main(void)
|
||||||
|
|
||||||
if (mgmt_app_init(ctx.digest) != 0) {
|
if (mgmt_app_init(ctx.digest) != 0) {
|
||||||
state = FW_STATE_FAIL;
|
state = FW_STATE_FAIL;
|
||||||
break;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
state = FW_STATE_START;
|
state = FW_STATE_START;
|
||||||
|
@ -622,7 +604,7 @@ int main(void)
|
||||||
}
|
}
|
||||||
|
|
||||||
/*@ -compdestroy @*/
|
/*@ -compdestroy @*/
|
||||||
// We don't care about memory leaks here.
|
/* We don't care about memory leaks here. */
|
||||||
|
|
||||||
return (int)0xcafebabe;
|
return (int)0xcafebabe;
|
||||||
}
|
}
|
||||||
|
|
|
@ -11,14 +11,11 @@
|
||||||
// Lock down what app can start from flash slot 0.
|
// Lock down what app can start from flash slot 0.
|
||||||
//
|
//
|
||||||
// To update this, compute the BLAKE2s digest of the app.bin
|
// To update this, compute the BLAKE2s digest of the app.bin
|
||||||
// clang-format off
|
|
||||||
static const uint8_t allowed_app_digest[32] = {
|
static const uint8_t allowed_app_digest[32] = {
|
||||||
0x85, 0x29, 0xe3, 0x25, 0xf5, 0x8d, 0x53, 0x5f,
|
0xb6, 0x86, 0x1b, 0x26, 0xef, 0x69, 0x77, 0x12, 0xed, 0x6c, 0xca,
|
||||||
0xe1, 0x2a, 0x77, 0x92, 0xe7, 0xdc, 0x4b, 0x4d,
|
0xe8, 0x35, 0xb4, 0x5c, 0x01, 0x07, 0x71, 0xab, 0xce, 0x3f, 0x30,
|
||||||
0x01, 0x85, 0x17, 0xca, 0xfd, 0x54, 0x83, 0xb3,
|
0x79, 0xda, 0xe6, 0xf9, 0xee, 0x4b, 0xe2, 0x06, 0x95, 0x33,
|
||||||
0xbb, 0x28, 0x4f, 0xa1, 0x98, 0x5f, 0x9e, 0x56,
|
|
||||||
};
|
};
|
||||||
// clang-format on
|
|
||||||
|
|
||||||
static uint8_t current_app_digest[32];
|
static uint8_t current_app_digest[32];
|
||||||
|
|
||||||
|
@ -34,7 +31,7 @@ int mgmt_app_init(uint8_t app_digest[32])
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
// Authenticate an management app
|
/* Authenticate an management app */
|
||||||
bool mgmt_app_authenticate(void)
|
bool mgmt_app_authenticate(void)
|
||||||
{
|
{
|
||||||
return memeq(current_app_digest, allowed_app_digest, 32) != 0;
|
return memeq(current_app_digest, allowed_app_digest, 32) != 0;
|
||||||
|
|
|
@ -17,20 +17,22 @@ enum part_status part_get_status(void)
|
||||||
return part_status;
|
return part_status;
|
||||||
}
|
}
|
||||||
|
|
||||||
static void part_checksum(struct partition_table *part_table,
|
static void part_digest(struct partition_table *part_table, uint8_t *out_digest,
|
||||||
uint8_t *out_digest, size_t out_len);
|
size_t out_len);
|
||||||
|
|
||||||
// part_digest computes a checksum over the partition table to detect
|
static void part_digest(struct partition_table *part_table, uint8_t *out_digest,
|
||||||
// flash problems
|
size_t out_len)
|
||||||
static void part_checksum(struct partition_table *part_table,
|
|
||||||
uint8_t *out_digest, size_t out_len)
|
|
||||||
{
|
{
|
||||||
int blake2err = 0;
|
int blake2err = 0;
|
||||||
|
|
||||||
|
uint8_t key[16] = {
|
||||||
|
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
|
||||||
|
};
|
||||||
|
|
||||||
assert(part_table != NULL);
|
assert(part_table != NULL);
|
||||||
assert(out_digest != NULL);
|
assert(out_digest != NULL);
|
||||||
|
|
||||||
blake2err = blake2s(out_digest, out_len, NULL, 0, part_table,
|
blake2err = blake2s(out_digest, out_len, key, sizeof(key), part_table,
|
||||||
sizeof(struct partition_table));
|
sizeof(struct partition_table));
|
||||||
|
|
||||||
assert(blake2err == 0);
|
assert(blake2err == 0);
|
||||||
|
@ -48,7 +50,7 @@ int part_table_read(struct partition_table_storage *storage)
|
||||||
ADDR_PARTITION_TABLE_0,
|
ADDR_PARTITION_TABLE_0,
|
||||||
ADDR_PARTITION_TABLE_1,
|
ADDR_PARTITION_TABLE_1,
|
||||||
};
|
};
|
||||||
uint8_t check_digest[PART_CHECKSUM_SIZE] = {0};
|
uint8_t check_digest[PART_DIGEST_SIZE] = {0};
|
||||||
|
|
||||||
if (storage == NULL) {
|
if (storage == NULL) {
|
||||||
return -1;
|
return -1;
|
||||||
|
@ -62,10 +64,10 @@ int part_table_read(struct partition_table_storage *storage)
|
||||||
sizeof(*storage)) != 0) {
|
sizeof(*storage)) != 0) {
|
||||||
return -1;
|
return -1;
|
||||||
}
|
}
|
||||||
part_checksum(&storage->table, check_digest,
|
part_digest(&storage->table, check_digest,
|
||||||
sizeof(check_digest));
|
sizeof(check_digest));
|
||||||
|
|
||||||
if (memeq(check_digest, storage->checksum,
|
if (memeq(check_digest, storage->check_digest,
|
||||||
sizeof(check_digest))) {
|
sizeof(check_digest))) {
|
||||||
if (i == 1) {
|
if (i == 1) {
|
||||||
part_status = PART_SLOT0_INVALID;
|
part_status = PART_SLOT0_INVALID;
|
||||||
|
@ -89,8 +91,8 @@ int part_table_write(struct partition_table_storage *storage)
|
||||||
return -1;
|
return -1;
|
||||||
}
|
}
|
||||||
|
|
||||||
part_checksum(&storage->table, storage->checksum,
|
part_digest(&storage->table, storage->check_digest,
|
||||||
sizeof(storage->checksum));
|
sizeof(storage->check_digest));
|
||||||
|
|
||||||
for (int i = 0; i < 2; i++) {
|
for (int i = 0; i < 2; i++) {
|
||||||
flash_sector_erase(offset[i]);
|
flash_sector_erase(offset[i]);
|
||||||
|
|
|
@ -6,25 +6,25 @@
|
||||||
|
|
||||||
#include <stdint.h>
|
#include <stdint.h>
|
||||||
|
|
||||||
// ---- Flash ---- ----
|
/* ---- Flash ---- ---- */
|
||||||
// name size start addr
|
/* name size start addr */
|
||||||
// ---- ---- ----
|
/* ---- ---- ---- */
|
||||||
// bitstream 128KiB 0x00
|
/* bitstream 128KiB 0x00 */
|
||||||
// ---- ---- ----
|
/* ---- ---- ---- */
|
||||||
// Partition 64KiB 0x20000
|
/* Partition 64KiB 0x20000 */
|
||||||
// ---- ---- ----
|
/* ---- ---- ---- */
|
||||||
// Pre load 1 128KiB 0x30000
|
/* Pre load 1 128KiB 0x30000 */
|
||||||
// Pre load 2 128KiB 0x50000
|
/* Pre load 2 128KiB 0x50000 */
|
||||||
// ---- ---- ----
|
/* ---- ---- ---- */
|
||||||
// storage 1 128KiB 0x70000
|
/* storage 1 128KiB 0x70000 */
|
||||||
// storage 2 128KiB 0x90000
|
/* storage 2 128KiB 0x90000 */
|
||||||
// storage 3 128KiB 0xB0000
|
/* storage 3 128KiB 0xB0000 */
|
||||||
// storage 4 128KiB 0xD0000
|
/* storage 4 128KiB 0xD0000 */
|
||||||
// ---- ---- ----
|
/* ---- ---- ---- */
|
||||||
// Partition2 64KiB 0xf0000
|
/* Partition2 64KiB 0xf0000 */
|
||||||
|
|
||||||
// To simplify all blocks are aligned with the 64KiB blocks on the
|
/* To simplify all blocks are aligned with the 64KiB blocks on the W25Q80DL
|
||||||
// W25Q80DL flash.
|
* flash. */
|
||||||
|
|
||||||
#define PART_TABLE_VERSION 1
|
#define PART_TABLE_VERSION 1
|
||||||
|
|
||||||
|
@ -46,33 +46,30 @@
|
||||||
#define SIZE_STORAGE_AREA 0x20000UL // 128KiB
|
#define SIZE_STORAGE_AREA 0x20000UL // 128KiB
|
||||||
#define N_STORAGE_AREA 4
|
#define N_STORAGE_AREA 4
|
||||||
|
|
||||||
#define PART_CHECKSUM_SIZE 32
|
#define PART_DIGEST_SIZE 16
|
||||||
|
|
||||||
enum part_status {
|
enum part_status {
|
||||||
PART_SLOT0_INVALID = 1,
|
PART_SLOT0_INVALID = 1,
|
||||||
};
|
};
|
||||||
|
|
||||||
// Partition Table
|
/* Partition Table */
|
||||||
// ----------------------------------------------------------------------
|
/*- Table header */
|
||||||
// - Table header
|
/* - 1 bytes Version */
|
||||||
// - 1 bytes Version
|
/**/
|
||||||
//
|
/*- Pre-loaded device app 1 */
|
||||||
// - Pre-loaded device app 1
|
/* - 4 bytes length. */
|
||||||
// - 4 bytes length.
|
/* - 32 bytes digest. */
|
||||||
// - 32 bytes digest.
|
/* - 64 bytes signature. */
|
||||||
// - 64 bytes signature.
|
/**/
|
||||||
//
|
/*- Pre-loaded device app 2 */
|
||||||
// - Pre-loaded device app 2
|
/* - 4 bytes length. */
|
||||||
// - 4 bytes length.
|
/* - 32 bytes digest. */
|
||||||
// - 32 bytes digest.
|
/* - 64 bytes signature. */
|
||||||
// - 64 bytes signature.
|
/**/
|
||||||
//
|
/*- Device app storage area */
|
||||||
// - Device app storage area
|
/* - 1 byte status. */
|
||||||
// - 1 byte status.
|
/* - 16 bytes random nonce. */
|
||||||
// - 16 bytes random nonce.
|
/* - 16 bytes authentication tag. */
|
||||||
// - 16 bytes authentication tag.
|
|
||||||
//
|
|
||||||
// - Checksum over the above
|
|
||||||
|
|
||||||
struct auth_metadata {
|
struct auth_metadata {
|
||||||
uint8_t nonce[16];
|
uint8_t nonce[16];
|
||||||
|
@ -102,7 +99,7 @@ struct partition_table {
|
||||||
|
|
||||||
struct partition_table_storage {
|
struct partition_table_storage {
|
||||||
struct partition_table table;
|
struct partition_table table;
|
||||||
uint8_t checksum[PART_CHECKSUM_SIZE]; // Helps detect flash problems
|
uint8_t check_digest[PART_DIGEST_SIZE];
|
||||||
} __attribute__((packed));
|
} __attribute__((packed));
|
||||||
|
|
||||||
enum part_status part_get_status(void);
|
enum part_status part_get_status(void);
|
||||||
|
|
|
@ -2,11 +2,6 @@
|
||||||
|
|
||||||
## custom_ops.S
|
## custom_ops.S
|
||||||
|
|
||||||
We have imported the custom Custom PicoRV32 instructions in
|
Custom PicoRV32 instructions are located in `custom_ops.S`.
|
||||||
`custom_ops.S` from https://github.com/YosysHQ/picorv32/ tag v1.0,
|
`custom_ops.S` is imported from upstream PicoRV32 commit:
|
||||||
commit 6d145b708d5dfa4caa3445bc599927cebc3291d8.
|
YosysHQ/picorv32@70f3c33
|
||||||
|
|
||||||
Upstream path is `picorv32/firmware/custom_ops.S`.
|
|
||||||
|
|
||||||
The picorv32 firmware is public domain, which we chose to mark as
|
|
||||||
CC0-1.0.
|
|
||||||
|
|
|
@ -1,6 +1,3 @@
|
||||||
// SPDX-FileCopyrightText: Claire Xenia Wolf <claire@yosyshq.com>
|
|
||||||
// SPDX-License-Identifier: CC0-1.0
|
|
||||||
|
|
||||||
// This is free and unencumbered software released into the public domain.
|
// This is free and unencumbered software released into the public domain.
|
||||||
//
|
//
|
||||||
// Anyone is free to copy, modify, publish, use, compile, sell, or
|
// Anyone is free to copy, modify, publish, use, compile, sell, or
|
||||||
|
|
|
@ -18,72 +18,58 @@ static uint32_t slot_to_start_address(uint8_t slot)
|
||||||
return ADDR_PRE_LOADED_APP_0 + slot * SIZE_PRE_LOADED_APP;
|
return ADDR_PRE_LOADED_APP_0 + slot * SIZE_PRE_LOADED_APP;
|
||||||
}
|
}
|
||||||
|
|
||||||
// Loads a preloaded app from flash to app RAM
|
/* Loads a preloaded app from flash to app RAM */
|
||||||
int preload_load(struct partition_table *part_table, uint8_t from_slot)
|
int preload_load(struct partition_table *part_table, uint8_t from_slot)
|
||||||
{
|
{
|
||||||
if (part_table == NULL) {
|
if (part_table == NULL) {
|
||||||
return -1;
|
return -5;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (from_slot >= N_PRELOADED_APP) {
|
if (from_slot >= N_PRELOADED_APP) {
|
||||||
return -1;
|
return -4;
|
||||||
}
|
}
|
||||||
|
|
||||||
// Check for a valid app in flash
|
/*Check for a valid app in flash */
|
||||||
if (part_table->pre_app_data[from_slot].size == 0 &&
|
if (part_table->pre_app_data[from_slot].size == 0) {
|
||||||
part_table->pre_app_data[from_slot].size <= TK1_APP_MAX_SIZE) {
|
|
||||||
return -1;
|
return -1;
|
||||||
}
|
}
|
||||||
uint8_t *loadaddr = (uint8_t *)TK1_RAM_BASE;
|
uint8_t *loadaddr = (uint8_t *)TK1_RAM_BASE;
|
||||||
|
|
||||||
// Read from flash, straight into RAM
|
/* Read from flash, straight into RAM */
|
||||||
int ret = flash_read_data(slot_to_start_address(from_slot), loadaddr,
|
int ret = flash_read_data(slot_to_start_address(from_slot), loadaddr,
|
||||||
part_table->pre_app_data[from_slot].size);
|
part_table->pre_app_data[from_slot].size);
|
||||||
|
|
||||||
return ret;
|
return ret;
|
||||||
}
|
}
|
||||||
|
|
||||||
// preload_store stores chunks of an app in app slot to_slot. data is a buffer
|
/* Expects to receive chunks of data up to 4096 bytes to store into the
|
||||||
// of size size to be written at byte offset in the slot. offset needs to be
|
* preloaded area. The offset needs to be kept and updated between each call.
|
||||||
// kept and updated between each call. offset must be a multiple of 256.
|
* Once done, call preload_store_finalize() with the last parameters.
|
||||||
//
|
* */
|
||||||
// When all data has been written call preload_store_finalize() with the last
|
|
||||||
// parameters.
|
|
||||||
//
|
|
||||||
// Returns 0 on success.
|
|
||||||
int preload_store(struct partition_table *part_table, uint32_t offset,
|
int preload_store(struct partition_table *part_table, uint32_t offset,
|
||||||
uint8_t *data, size_t size, uint8_t to_slot)
|
uint8_t *data, size_t size, uint8_t to_slot)
|
||||||
{
|
{
|
||||||
if (part_table == NULL || data == NULL) {
|
if (part_table == NULL || data == NULL) {
|
||||||
return -1;
|
return -5;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (to_slot >= N_PRELOADED_APP) {
|
if (to_slot >= N_PRELOADED_APP) {
|
||||||
return -1;
|
return -4;
|
||||||
}
|
}
|
||||||
|
|
||||||
// Check if we are allowed to store
|
/* Check if we are allowed to store */
|
||||||
if (!mgmt_app_authenticate()) {
|
if (!mgmt_app_authenticate()) {
|
||||||
return -1;
|
return -3;
|
||||||
}
|
}
|
||||||
|
|
||||||
// Check for a valid app in flash, bale out if it already
|
/* Check for a valid app in flash, bale out if it already exists */
|
||||||
// exists
|
|
||||||
if (part_table->pre_app_data[to_slot].size != 0) {
|
if (part_table->pre_app_data[to_slot].size != 0) {
|
||||||
return -1;
|
return -1;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (offset > SIZE_PRE_LOADED_APP) {
|
if ((offset + size) > SIZE_PRE_LOADED_APP || size > 4096) {
|
||||||
return -1;
|
/* Writing outside of area */
|
||||||
}
|
return -2;
|
||||||
|
|
||||||
if (size > SIZE_PRE_LOADED_APP) {
|
|
||||||
return -1;
|
|
||||||
}
|
|
||||||
|
|
||||||
if ((offset + size) > SIZE_PRE_LOADED_APP) {
|
|
||||||
// Writing outside of area
|
|
||||||
return -1;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
uint32_t address = slot_to_start_address(to_slot) + offset;
|
uint32_t address = slot_to_start_address(to_slot) + offset;
|
||||||
|
@ -101,38 +87,26 @@ int preload_store_finalize(struct partition_table_storage *part_table_storage,
|
||||||
{
|
{
|
||||||
struct partition_table *part_table = &part_table_storage->table;
|
struct partition_table *part_table = &part_table_storage->table;
|
||||||
|
|
||||||
if (part_table == NULL) {
|
if (part_table == NULL || app_digest == NULL || app_signature == NULL) {
|
||||||
return -1;
|
return -5;
|
||||||
}
|
|
||||||
|
|
||||||
// Allow data to point only to app RAM
|
|
||||||
if (app_digest < (uint8_t *)TK1_RAM_BASE ||
|
|
||||||
app_digest >= (uint8_t *)(TK1_RAM_BASE + TK1_RAM_SIZE)) {
|
|
||||||
return -1;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (app_signature < (uint8_t *)TK1_RAM_BASE ||
|
|
||||||
app_signature >= (uint8_t *)(TK1_RAM_BASE + TK1_RAM_SIZE)) {
|
|
||||||
return -1;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
if (to_slot >= N_PRELOADED_APP) {
|
if (to_slot >= N_PRELOADED_APP) {
|
||||||
return -1;
|
return -4;
|
||||||
}
|
}
|
||||||
|
|
||||||
// Check if we are allowed to store
|
/* Check if we are allowed to store */
|
||||||
if (!mgmt_app_authenticate()) {
|
if (!mgmt_app_authenticate()) {
|
||||||
return -1;
|
return -3;
|
||||||
}
|
}
|
||||||
|
|
||||||
// Check for a valid app in flash, bale out if it already
|
/* Check for a valid app in flash, bale out if it already exists */
|
||||||
// exists
|
|
||||||
if (part_table->pre_app_data[to_slot].size != 0) {
|
if (part_table->pre_app_data[to_slot].size != 0) {
|
||||||
return -1;
|
return -1;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (app_size == 0 || app_size > SIZE_PRE_LOADED_APP) {
|
if (app_size == 0 || app_size > SIZE_PRE_LOADED_APP) {
|
||||||
return -1;
|
return -2;
|
||||||
}
|
}
|
||||||
|
|
||||||
part_table->pre_app_data[to_slot].size = app_size;
|
part_table->pre_app_data[to_slot].size = app_size;
|
||||||
|
@ -147,7 +121,7 @@ int preload_store_finalize(struct partition_table_storage *part_table_storage,
|
||||||
debug_lf();
|
debug_lf();
|
||||||
|
|
||||||
if (part_table_write(part_table_storage) != 0) {
|
if (part_table_write(part_table_storage) != 0) {
|
||||||
return -1;
|
return -6;
|
||||||
}
|
}
|
||||||
|
|
||||||
return 0;
|
return 0;
|
||||||
|
@ -159,19 +133,19 @@ int preload_delete(struct partition_table_storage *part_table_storage,
|
||||||
struct partition_table *part_table = &part_table_storage->table;
|
struct partition_table *part_table = &part_table_storage->table;
|
||||||
|
|
||||||
if (part_table_storage == NULL) {
|
if (part_table_storage == NULL) {
|
||||||
return -1;
|
return -5;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (slot >= N_PRELOADED_APP) {
|
if (slot >= N_PRELOADED_APP) {
|
||||||
return -1;
|
return -4;
|
||||||
}
|
}
|
||||||
|
|
||||||
// Check if we are allowed to delete
|
/* Check if we are allowed to deleted */
|
||||||
if (!mgmt_app_authenticate()) {
|
if (!mgmt_app_authenticate()) {
|
||||||
return -1;
|
return -3;
|
||||||
}
|
}
|
||||||
|
|
||||||
// Check for a valid app in flash
|
/*Check for a valid app in flash */
|
||||||
if (part_table->pre_app_data[slot].size == 0) {
|
if (part_table->pre_app_data[slot].size == 0) {
|
||||||
// Nothing to do.
|
// Nothing to do.
|
||||||
return 0;
|
return 0;
|
||||||
|
@ -186,10 +160,10 @@ int preload_delete(struct partition_table_storage *part_table_storage,
|
||||||
sizeof(part_table->pre_app_data[slot].signature));
|
sizeof(part_table->pre_app_data[slot].signature));
|
||||||
|
|
||||||
if (part_table_write(part_table_storage) != 0) {
|
if (part_table_write(part_table_storage) != 0) {
|
||||||
return -1;
|
return -6;
|
||||||
}
|
}
|
||||||
|
|
||||||
// Assumes the area is 64 KiB block aligned
|
/* Assumes the area is 64 KiB block aligned */
|
||||||
flash_block_64_erase(
|
flash_block_64_erase(
|
||||||
slot_to_start_address(slot)); // Erase first 64 KB block
|
slot_to_start_address(slot)); // Erase first 64 KB block
|
||||||
flash_block_64_erase(slot_to_start_address(slot) +
|
flash_block_64_erase(slot_to_start_address(slot) +
|
||||||
|
@ -203,16 +177,16 @@ int preload_get_digsig(struct partition_table *part_table,
|
||||||
uint8_t slot)
|
uint8_t slot)
|
||||||
{
|
{
|
||||||
if (part_table == NULL || app_digest == NULL || app_signature == NULL) {
|
if (part_table == NULL || app_digest == NULL || app_signature == NULL) {
|
||||||
return -1;
|
return -5;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (slot >= N_PRELOADED_APP) {
|
if (slot >= N_PRELOADED_APP) {
|
||||||
return -1;
|
return -4;
|
||||||
}
|
}
|
||||||
|
|
||||||
// Check if we are allowed to read
|
/* Check if we are allowed to read */
|
||||||
if (!mgmt_app_authenticate()) {
|
if (!mgmt_app_authenticate()) {
|
||||||
return -1;
|
return -3;
|
||||||
}
|
}
|
||||||
|
|
||||||
memcpy_s(app_digest, 32, part_table->pre_app_data[slot].digest,
|
memcpy_s(app_digest, 32, part_table->pre_app_data[slot].digest,
|
||||||
|
|
|
@ -1,5 +1,7 @@
|
||||||
// Copyright (C) 2022, 2023 - Tillitis AB
|
/*
|
||||||
// SPDX-License-Identifier: GPL-2.0-only
|
* Copyright (C) 2022, 2023 - Tillitis AB
|
||||||
|
* SPDX-License-Identifier: GPL-2.0-only
|
||||||
|
*/
|
||||||
|
|
||||||
#include <stdint.h>
|
#include <stdint.h>
|
||||||
#include <tkey/assert.h>
|
#include <tkey/assert.h>
|
||||||
|
|
|
@ -1,5 +1,7 @@
|
||||||
// Copyright (C) 2022, 2023 - Tillitis AB
|
/*
|
||||||
// SPDX-License-Identifier: GPL-2.0-only
|
* Copyright (C) 2022, 2023 - Tillitis AB
|
||||||
|
* SPDX-License-Identifier: GPL-2.0-only
|
||||||
|
*/
|
||||||
|
|
||||||
#include <stddef.h>
|
#include <stddef.h>
|
||||||
#include <stdint.h>
|
#include <stdint.h>
|
||||||
|
|
|
@ -1,87 +0,0 @@
|
||||||
/*
|
|
||||||
* Copyright (C) 2022, 2023 - Tillitis AB
|
|
||||||
* SPDX-License-Identifier: GPL-2.0-only
|
|
||||||
*/
|
|
||||||
|
|
||||||
OUTPUT_ARCH("riscv")
|
|
||||||
ENTRY(_start)
|
|
||||||
|
|
||||||
/* Define stack size */
|
|
||||||
STACK_SIZE = 3000;
|
|
||||||
|
|
||||||
MEMORY
|
|
||||||
{
|
|
||||||
ROM (rx) : ORIGIN = 0x00000000, LENGTH = 128k
|
|
||||||
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 */
|
|
||||||
}
|
|
||||||
|
|
||||||
SECTIONS
|
|
||||||
{
|
|
||||||
.text.init :
|
|
||||||
{
|
|
||||||
*(.text.init)
|
|
||||||
} >ROM
|
|
||||||
|
|
||||||
.htif :
|
|
||||||
{
|
|
||||||
. = ALIGN(0x00000000);
|
|
||||||
*(.htif)
|
|
||||||
} >ROM
|
|
||||||
|
|
||||||
.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) /* .srodata sections (constants, strings, etc.) */
|
|
||||||
*(.srodata*) /* .srodata* sections (constants, strings, etc.) */
|
|
||||||
. = ALIGN(4);
|
|
||||||
_etext = .;
|
|
||||||
} >ROM
|
|
||||||
|
|
||||||
.stack (NOLOAD) :
|
|
||||||
{
|
|
||||||
. = ALIGN(16);
|
|
||||||
_sstack = .;
|
|
||||||
. += STACK_SIZE;
|
|
||||||
. = ALIGN(16);
|
|
||||||
_estack = .;
|
|
||||||
} >FWRAM
|
|
||||||
|
|
||||||
.data :
|
|
||||||
{
|
|
||||||
. = ALIGN(4);
|
|
||||||
_sdata = .;
|
|
||||||
*(.data) /* .data sections */
|
|
||||||
*(.data*) /* .data* sections */
|
|
||||||
*(.sdata) /* .sdata sections */
|
|
||||||
*(.sdata*) /* .sdata* sections */
|
|
||||||
. = ALIGN(4);
|
|
||||||
_edata = .;
|
|
||||||
} >FWRAM AT>ROM
|
|
||||||
_sidata = LOADADDR(.data);
|
|
||||||
|
|
||||||
/* Uninitialized data section */
|
|
||||||
.bss :
|
|
||||||
{
|
|
||||||
. = ALIGN(4);
|
|
||||||
_sbss = .;
|
|
||||||
*(.bss)
|
|
||||||
*(.bss*)
|
|
||||||
*(.sbss)
|
|
||||||
*(.sbss*)
|
|
||||||
*(COMMON)
|
|
||||||
. = ALIGN(4);
|
|
||||||
_ebss = .;
|
|
||||||
} >FWRAM
|
|
||||||
}
|
|
||||||
|
|
||||||
_sfwram = ORIGIN(FWRAM);
|
|
||||||
_efwram = ORIGIN(FWRAM) + LENGTH(FWRAM);
|
|
||||||
_sresetinfo = ORIGIN(RESETINFO);
|
|
||||||
_eresetinfo = ORIGIN(RESETINFO) + LENGTH(RESETINFO);
|
|
|
@ -1,59 +0,0 @@
|
||||||
// Copyright (C) 2025 - Tillitis AB
|
|
||||||
// SPDX-License-Identifier: GPL-2.0-only
|
|
||||||
|
|
||||||
#include <stdint.h>
|
|
||||||
#include <tkey/assert.h>
|
|
||||||
#include <tkey/lib.h>
|
|
||||||
#include <tkey/tk1_mem.h>
|
|
||||||
|
|
||||||
#include "reset.h"
|
|
||||||
|
|
||||||
// clang-format off
|
|
||||||
static volatile uint32_t *system_reset = (volatile uint32_t *)TK1_MMIO_TK1_SYSTEM_RESET;
|
|
||||||
static volatile struct reset *resetinfo = (volatile struct reset *)TK1_MMIO_RESETINFO_BASE;
|
|
||||||
// clang-format on
|
|
||||||
|
|
||||||
int reset(struct reset *userreset, size_t nextlen)
|
|
||||||
{
|
|
||||||
if ((uint32_t)userreset < TK1_RAM_BASE ||
|
|
||||||
(uint32_t)userreset >= TK1_RAM_BASE + TK1_RAM_SIZE) {
|
|
||||||
return -1;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (nextlen > sizeof(resetinfo->next_app_data)) {
|
|
||||||
return -1;
|
|
||||||
}
|
|
||||||
|
|
||||||
(void)memset((void *)resetinfo, 0, sizeof(*resetinfo));
|
|
||||||
resetinfo->type = userreset->type;
|
|
||||||
memcpy((void *)resetinfo->app_digest, userreset->app_digest,
|
|
||||||
sizeof(resetinfo->app_digest));
|
|
||||||
memcpy((void *)resetinfo->next_app_data, userreset->next_app_data,
|
|
||||||
nextlen);
|
|
||||||
|
|
||||||
// Do the actual reset.
|
|
||||||
*system_reset = 1;
|
|
||||||
|
|
||||||
// Should not be reached.
|
|
||||||
assert(1 == 2);
|
|
||||||
|
|
||||||
__builtin_unreachable();
|
|
||||||
}
|
|
||||||
|
|
||||||
int reset_data(uint8_t *next_app_data)
|
|
||||||
{
|
|
||||||
if ((uint32_t)next_app_data < TK1_RAM_BASE ||
|
|
||||||
(uint32_t)next_app_data >= TK1_RAM_BASE + TK1_RAM_SIZE) {
|
|
||||||
return -1;
|
|
||||||
}
|
|
||||||
|
|
||||||
if ((uint32_t)next_app_data + RESET_DATA_SIZE >
|
|
||||||
TK1_RAM_BASE + TK1_RAM_SIZE) {
|
|
||||||
return -1;
|
|
||||||
}
|
|
||||||
|
|
||||||
memcpy(next_app_data, (void *)resetinfo->next_app_data,
|
|
||||||
RESET_DATA_SIZE);
|
|
||||||
|
|
||||||
return 0;
|
|
||||||
}
|
|
|
@ -1,16 +1,13 @@
|
||||||
// Copyright (C) 2025 - Tillitis AB
|
// Copyright (C) 2025 - Tillitis AB
|
||||||
// SPDX-License-Identifier: GPL-2.0-only
|
// SPDX-License-Identifier: GPL-2.0-only
|
||||||
|
|
||||||
#ifndef TKEY_RESET_H
|
#ifndef TKEY_RESETINFO_H
|
||||||
#define TKEY_RESET_H
|
#define TKEY_RESETINFO_H
|
||||||
|
|
||||||
#include <stddef.h>
|
|
||||||
#include <stdint.h>
|
#include <stdint.h>
|
||||||
|
|
||||||
#define TK1_MMIO_RESETINFO_BASE 0xd0000f00
|
#define TK1_MMIO_RESETINFO_BASE 0xd0000f00
|
||||||
#define TK1_MMIO_RESETINFO_SIZE 0x100
|
#define TK1_MMIO_RESETINFO_SIZE 0x100
|
||||||
#define RESET_DIGEST_SIZE 32
|
|
||||||
#define RESET_DATA_SIZE 220
|
|
||||||
|
|
||||||
enum reset_start {
|
enum reset_start {
|
||||||
START_DEFAULT = 0, // Probably cold boot
|
START_DEFAULT = 0, // Probably cold boot
|
||||||
|
@ -23,11 +20,9 @@ enum reset_start {
|
||||||
};
|
};
|
||||||
|
|
||||||
struct reset {
|
struct reset {
|
||||||
enum reset_start type;
|
uint32_t type; // Reset type
|
||||||
uint8_t app_digest[RESET_DIGEST_SIZE];
|
uint8_t app_digest[32]; // Program digest
|
||||||
uint8_t next_app_data[RESET_DATA_SIZE];
|
uint8_t next_app_data[220]; // Data to leave around for next app
|
||||||
};
|
};
|
||||||
|
|
||||||
int reset(struct reset *userreset, size_t nextlen);
|
|
||||||
int reset_data(uint8_t *next_app_data);
|
|
||||||
#endif
|
#endif
|
|
@ -10,7 +10,8 @@
|
||||||
static volatile uint32_t *trng_status = (volatile uint32_t *)TK1_MMIO_TRNG_STATUS;
|
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 *trng_entropy = (volatile uint32_t *)TK1_MMIO_TRNG_ENTROPY;
|
||||||
// clang-format on
|
// clang-format on
|
||||||
|
//
|
||||||
|
//
|
||||||
uint32_t rng_get_word(void)
|
uint32_t rng_get_word(void)
|
||||||
{
|
{
|
||||||
while ((*trng_status & (1 << TK1_MMIO_TRNG_STATUS_READY_BIT)) == 0) {
|
while ((*trng_status & (1 << TK1_MMIO_TRNG_STATUS_READY_BIT)) == 0) {
|
||||||
|
|
|
@ -20,7 +20,7 @@ static void spi_disable(void);
|
||||||
static void spi_write(uint8_t *cmd, size_t size);
|
static void spi_write(uint8_t *cmd, size_t size);
|
||||||
static void spi_read(uint8_t *buf, size_t size);
|
static void spi_read(uint8_t *buf, size_t size);
|
||||||
|
|
||||||
// Returns non-zero when the SPI-master is ready, and zero if not
|
// returns non-zero when the SPI-master is ready, and zero if not
|
||||||
// ready. This can be used to check if the SPI-master is available
|
// ready. This can be used to check if the SPI-master is available
|
||||||
// in the hardware.
|
// in the hardware.
|
||||||
static int spi_ready(void)
|
static int spi_ready(void)
|
||||||
|
|
|
@ -1,5 +1,7 @@
|
||||||
// Copyright (C) 2022-2025 - Tillitis AB
|
/*
|
||||||
// SPDX-License-Identifier: GPL-2.0-only
|
* Copyright (C) 2022-2025 - Tillitis AB
|
||||||
|
* SPDX-License-Identifier: GPL-2.0-only
|
||||||
|
*/
|
||||||
|
|
||||||
#include <tkey/tk1_mem.h>
|
#include <tkey/tk1_mem.h>
|
||||||
|
|
||||||
|
@ -26,7 +28,9 @@
|
||||||
_start:
|
_start:
|
||||||
j init
|
j init
|
||||||
|
|
||||||
// IRQ handler
|
/*
|
||||||
|
* IRQ handler
|
||||||
|
*/
|
||||||
.=0x10
|
.=0x10
|
||||||
irq_handler:
|
irq_handler:
|
||||||
// PicoRV32 stores the IRQ bitmask in x4.
|
// PicoRV32 stores the IRQ bitmask in x4.
|
||||||
|
@ -108,8 +112,9 @@ x3_valid:
|
||||||
|
|
||||||
picorv32_retirq_insn() // Return from interrupt
|
picorv32_retirq_insn() // Return from interrupt
|
||||||
|
|
||||||
// Init
|
/*
|
||||||
|
* Init
|
||||||
|
*/
|
||||||
.=0x100
|
.=0x100
|
||||||
init:
|
init:
|
||||||
li x1, 0
|
li x1, 0
|
||||||
|
@ -144,7 +149,7 @@ init:
|
||||||
li x30,0
|
li x30,0
|
||||||
li x31,0
|
li x31,0
|
||||||
|
|
||||||
// Clear FW_RAM
|
/* Clear FW_RAM */
|
||||||
la a0, _sfwram
|
la a0, _sfwram
|
||||||
la a1, _efwram
|
la a1, _efwram
|
||||||
clear:
|
clear:
|
||||||
|
@ -152,7 +157,7 @@ clear:
|
||||||
addi a0, a0, 4
|
addi a0, a0, 4
|
||||||
blt a0, a1, clear
|
blt a0, a1, clear
|
||||||
|
|
||||||
// Zero-init bss section
|
/* Zero-init bss section */
|
||||||
la a0, _sbss
|
la a0, _sbss
|
||||||
la a1, _ebss
|
la a1, _ebss
|
||||||
|
|
||||||
|
@ -161,7 +166,7 @@ loop_init_bss:
|
||||||
addi a0, a0, 4
|
addi a0, a0, 4
|
||||||
blt a0, a1, loop_init_bss
|
blt a0, a1, loop_init_bss
|
||||||
|
|
||||||
// Init stack
|
/* Init stack */
|
||||||
la sp, _estack
|
la sp, _estack
|
||||||
|
|
||||||
call main
|
call main
|
||||||
|
|
|
@ -1,5 +1,7 @@
|
||||||
// Copyright (C) 2023 - Tillitis AB
|
/*
|
||||||
// SPDX-License-Identifier: GPL-2.0-only
|
* Copyright (C) 2023 - Tillitis AB
|
||||||
|
* SPDX-License-Identifier: GPL-2.0-only
|
||||||
|
*/
|
||||||
|
|
||||||
#ifndef STATE_H
|
#ifndef STATE_H
|
||||||
#define STATE_H
|
#define STATE_H
|
||||||
|
|
|
@ -6,20 +6,18 @@
|
||||||
#include <stdint.h>
|
#include <stdint.h>
|
||||||
#include <tkey/debug.h>
|
#include <tkey/debug.h>
|
||||||
#include <tkey/lib.h>
|
#include <tkey/lib.h>
|
||||||
#include <tkey/tk1_mem.h>
|
|
||||||
|
|
||||||
#include "auth_app.h"
|
#include "auth_app.h"
|
||||||
#include "flash.h"
|
#include "flash.h"
|
||||||
#include "partition_table.h"
|
#include "partition_table.h"
|
||||||
#include "storage.h"
|
#include "storage.h"
|
||||||
|
|
||||||
// Returns the index of the first empty area.
|
/* Returns the index of the first empty area. If there is no empty area -1 is
|
||||||
//
|
* returned. */
|
||||||
// Returns -1 on errors.
|
|
||||||
static int get_first_empty(struct partition_table *part_table)
|
static int get_first_empty(struct partition_table *part_table)
|
||||||
{
|
{
|
||||||
if (part_table == NULL) {
|
if (part_table == NULL) {
|
||||||
return -1;
|
return -4;
|
||||||
}
|
}
|
||||||
|
|
||||||
for (uint8_t i = 0; i < N_STORAGE_AREA; i++) {
|
for (uint8_t i = 0; i < N_STORAGE_AREA; i++) {
|
||||||
|
@ -27,14 +25,13 @@ static int get_first_empty(struct partition_table *part_table)
|
||||||
return i;
|
return i;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
return -1;
|
return -1;
|
||||||
}
|
}
|
||||||
|
|
||||||
static int index_to_address(int index, uint32_t *address)
|
static int index_to_address(int index, uint32_t *address)
|
||||||
{
|
{
|
||||||
if (address == NULL) {
|
if (address == NULL) {
|
||||||
return -1;
|
return -4;
|
||||||
}
|
}
|
||||||
|
|
||||||
if ((index < 0) || (index >= N_STORAGE_AREA)) {
|
if ((index < 0) || (index >= N_STORAGE_AREA)) {
|
||||||
|
@ -46,13 +43,12 @@ static int index_to_address(int index, uint32_t *address)
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
// Returns the index of the area an app has allocated.
|
/* Returns the index of the area an app has allocated. If no area is
|
||||||
//
|
* authenticated -1 is returned. */
|
||||||
// Returns -1 on errors.
|
|
||||||
static int storage_get_area(struct partition_table *part_table)
|
static int storage_get_area(struct partition_table *part_table)
|
||||||
{
|
{
|
||||||
if (part_table == NULL) {
|
if (part_table == NULL) {
|
||||||
return -1;
|
return -4;
|
||||||
}
|
}
|
||||||
|
|
||||||
for (uint8_t i = 0; i < N_STORAGE_AREA; i++) {
|
for (uint8_t i = 0; i < N_STORAGE_AREA; i++) {
|
||||||
|
@ -63,85 +59,85 @@ static int storage_get_area(struct partition_table *part_table)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
return -1;
|
return -1;
|
||||||
}
|
}
|
||||||
|
|
||||||
// Allocate a new area for an app. Returns zero on success.
|
/* Allocate a new area for an app. Returns zero if a new area is allocated, one
|
||||||
|
* if an area already was allocated, and negative values for errors. */
|
||||||
int storage_allocate_area(struct partition_table_storage *part_table_storage)
|
int storage_allocate_area(struct partition_table_storage *part_table_storage)
|
||||||
{
|
{
|
||||||
if (part_table_storage == NULL) {
|
if (part_table_storage == NULL) {
|
||||||
return -1;
|
return -4;
|
||||||
}
|
}
|
||||||
|
|
||||||
struct partition_table *part_table = &part_table_storage->table;
|
struct partition_table *part_table = &part_table_storage->table;
|
||||||
|
|
||||||
if (storage_get_area(part_table) != -1) {
|
if (storage_get_area(part_table) != -1) {
|
||||||
/* Already has an area */
|
/* Already has an area */
|
||||||
return 0;
|
return 1;
|
||||||
}
|
}
|
||||||
|
|
||||||
int index = get_first_empty(part_table);
|
int index = get_first_empty(part_table);
|
||||||
if (index < 0) {
|
if (index == -1) {
|
||||||
/* No empty slot */
|
/* No empty slot */
|
||||||
return -1;
|
return -1;
|
||||||
}
|
}
|
||||||
|
|
||||||
uint32_t start_address = 0;
|
uint32_t start_address = 0;
|
||||||
|
int err = index_to_address(index, &start_address);
|
||||||
if (index_to_address(index, &start_address) != 0) {
|
if (err) {
|
||||||
return -1;
|
return -3;
|
||||||
}
|
}
|
||||||
|
|
||||||
// Allocate the empty index found
|
/* Allocate the empty index found */
|
||||||
// Erase area first
|
/* Erase area first */
|
||||||
|
|
||||||
// Assumes the area is 64 KiB block aligned
|
/* Assumes the area is 64 KiB block aligned */
|
||||||
flash_block_64_erase(start_address); // Erase first 64 KB block
|
flash_block_64_erase(start_address); // Erase first 64 KB block
|
||||||
flash_block_64_erase(start_address +
|
flash_block_64_erase(start_address +
|
||||||
0x10000); // Erase second 64 KB block
|
0x10000); // Erase second 64 KB block
|
||||||
|
|
||||||
// Write partition table lastly
|
/* Write partition table lastly */
|
||||||
part_table->app_storage[index].status = 0x01;
|
part_table->app_storage[index].status = 0x01;
|
||||||
auth_app_create(&part_table->app_storage[index].auth);
|
auth_app_create(&part_table->app_storage[index].auth);
|
||||||
|
|
||||||
if (part_table_write(part_table_storage) != 0) {
|
if (part_table_write(part_table_storage) != 0) {
|
||||||
return -1;
|
return -5;
|
||||||
}
|
}
|
||||||
|
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
// Dealloacate a previously allocated storage area.
|
/* Dealloacate a previously allocated storage area. Returns zero on success, and
|
||||||
//
|
* non-zero on errors. */
|
||||||
// Returns zero on success, and non-zero on errors.
|
|
||||||
int storage_deallocate_area(struct partition_table_storage *part_table_storage)
|
int storage_deallocate_area(struct partition_table_storage *part_table_storage)
|
||||||
{
|
{
|
||||||
if (part_table_storage == NULL) {
|
if (part_table_storage == NULL) {
|
||||||
return -1;
|
return -4;
|
||||||
}
|
}
|
||||||
|
|
||||||
struct partition_table *part_table = &part_table_storage->table;
|
struct partition_table *part_table = &part_table_storage->table;
|
||||||
|
|
||||||
int index = storage_get_area(part_table);
|
int index = storage_get_area(part_table);
|
||||||
if (index < 0) {
|
if (index == -1) {
|
||||||
// No area to deallocate
|
/* No area to deallocate */
|
||||||
return -1;
|
return -1;
|
||||||
}
|
}
|
||||||
|
|
||||||
uint32_t start_address = 0;
|
uint32_t start_address = 0;
|
||||||
if (index_to_address(index, &start_address) != 0) {
|
int err = index_to_address(index, &start_address);
|
||||||
return -1;
|
if (err) {
|
||||||
|
return -3;
|
||||||
}
|
}
|
||||||
|
|
||||||
// Erase area first
|
/* Erase area first */
|
||||||
|
|
||||||
// Assumes the area is 64 KiB block aligned
|
/* Assumes the area is 64 KiB block aligned */
|
||||||
flash_block_64_erase(start_address); // Erase first 64 KB block
|
flash_block_64_erase(start_address); // Erase first 64 KB block
|
||||||
flash_block_64_erase(start_address +
|
flash_block_64_erase(start_address +
|
||||||
0x10000); // Erase second 64 KB block
|
0x10000); // Erase second 64 KB block
|
||||||
|
|
||||||
// Clear partition table lastly
|
/* Clear partition table lastly */
|
||||||
part_table->app_storage[index].status = 0;
|
part_table->app_storage[index].status = 0;
|
||||||
|
|
||||||
(void)memset(part_table->app_storage[index].auth.nonce, 0x00,
|
(void)memset(part_table->app_storage[index].auth.nonce, 0x00,
|
||||||
|
@ -152,51 +148,46 @@ int storage_deallocate_area(struct partition_table_storage *part_table_storage)
|
||||||
sizeof(part_table->app_storage[index].auth.authentication_digest));
|
sizeof(part_table->app_storage[index].auth.authentication_digest));
|
||||||
|
|
||||||
if (part_table_write(part_table_storage) != 0) {
|
if (part_table_write(part_table_storage) != 0) {
|
||||||
return -1;
|
return -5;
|
||||||
}
|
}
|
||||||
|
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
// Erases sector. Offset of a sector to begin erasing, must be a
|
/* Erases sector. Offset of a sector to begin erasing, must be a multiple of
|
||||||
// multiple of the sector size. Size to erase in bytes, must be a
|
* the sector size. Size to erase in bytes, must be a multiple of the sector *
|
||||||
// multiple of the sector size.
|
* size. Returns zero on success, negative error code on failure */
|
||||||
//
|
|
||||||
// Returns zero on success, negative error code on failure
|
|
||||||
int storage_erase_sector(struct partition_table *part_table, uint32_t offset,
|
int storage_erase_sector(struct partition_table *part_table, uint32_t offset,
|
||||||
size_t size)
|
size_t size)
|
||||||
{
|
{
|
||||||
if (part_table == NULL) {
|
if (part_table == NULL) {
|
||||||
return -1;
|
return -4;
|
||||||
}
|
}
|
||||||
|
|
||||||
int index = storage_get_area(part_table);
|
int index = storage_get_area(part_table);
|
||||||
if (index == -1) {
|
if (index == -1) {
|
||||||
// No allocated area
|
/* No allocated area */
|
||||||
return -1;
|
return -1;
|
||||||
}
|
}
|
||||||
|
|
||||||
uint32_t start_address = 0;
|
uint32_t start_address = 0;
|
||||||
if (index_to_address(index, &start_address) != 0) {
|
int err = index_to_address(index, &start_address);
|
||||||
return -1;
|
if (err) {
|
||||||
|
return -3;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (offset > SIZE_STORAGE_AREA) {
|
/* Cannot only erase entire sectors */
|
||||||
return -1;
|
|
||||||
}
|
|
||||||
|
|
||||||
// Cannot only erase entire sectors
|
|
||||||
if (offset % 4096 != 0) {
|
if (offset % 4096 != 0) {
|
||||||
return -1;
|
return -2;
|
||||||
}
|
}
|
||||||
|
|
||||||
// Cannot erase less than one sector
|
/* Cannot erase less than one sector */
|
||||||
if (size < 4096 || size > SIZE_STORAGE_AREA || size % 4096 != 0) {
|
if (size < 4096 || size > SIZE_STORAGE_AREA || size % 4096 != 0) {
|
||||||
return -1;
|
return -2;
|
||||||
}
|
}
|
||||||
|
|
||||||
if ((offset + size) > SIZE_STORAGE_AREA) {
|
if ((offset + size) >= SIZE_STORAGE_AREA) {
|
||||||
return -1;
|
return -2;
|
||||||
}
|
}
|
||||||
|
|
||||||
uint32_t address = start_address + offset;
|
uint32_t address = start_address + offset;
|
||||||
|
@ -213,45 +204,32 @@ int storage_erase_sector(struct partition_table *part_table, uint32_t offset,
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
// Writes the specified data to the offset inside of the allocated area.
|
/* Writes the specified data to the offset inside of the
|
||||||
// Assumes area has been erased before hand. Offset must be a multiple of 256.
|
* allocated area. Assumes area has been erased before hand.
|
||||||
//
|
* Currently only handles writes to one sector, hence max size of 4096 bytes.
|
||||||
// Returns zero on success.
|
* Returns zero on success. */
|
||||||
int storage_write_data(struct partition_table *part_table, uint32_t offset,
|
int storage_write_data(struct partition_table *part_table, uint32_t offset,
|
||||||
uint8_t *data, size_t size)
|
uint8_t *data, size_t size)
|
||||||
{
|
{
|
||||||
if (part_table == NULL) {
|
if (part_table == NULL || data == NULL) {
|
||||||
return -1;
|
return -4;
|
||||||
}
|
|
||||||
|
|
||||||
// Allow data to point only to app RAM
|
|
||||||
if (data < (uint8_t *)TK1_RAM_BASE ||
|
|
||||||
data >= (uint8_t *)(TK1_RAM_BASE + TK1_RAM_SIZE)) {
|
|
||||||
return -1;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
int index = storage_get_area(part_table);
|
int index = storage_get_area(part_table);
|
||||||
if (index == -1) {
|
if (index == -1) {
|
||||||
// No allocated area
|
/* No allocated area */
|
||||||
return -1;
|
return -1;
|
||||||
}
|
}
|
||||||
|
|
||||||
uint32_t start_address = 0;
|
uint32_t start_address = 0;
|
||||||
if (index_to_address(index, &start_address) != 0) {
|
int err = index_to_address(index, &start_address);
|
||||||
return -1;
|
if (err) {
|
||||||
|
return -3;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (offset > SIZE_STORAGE_AREA) {
|
if ((offset + size) > SIZE_STORAGE_AREA || size > 4096) {
|
||||||
return -1;
|
/* Writing outside of area */
|
||||||
}
|
return -2;
|
||||||
|
|
||||||
if (size > SIZE_STORAGE_AREA) {
|
|
||||||
return -1;
|
|
||||||
}
|
|
||||||
|
|
||||||
if ((offset + size) > SIZE_STORAGE_AREA) {
|
|
||||||
// Writing outside of area
|
|
||||||
return -1;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
uint32_t address = start_address + offset;
|
uint32_t address = start_address + offset;
|
||||||
|
@ -263,48 +241,31 @@ int storage_write_data(struct partition_table *part_table, uint32_t offset,
|
||||||
return flash_write_data(address, data, size);
|
return flash_write_data(address, data, size);
|
||||||
}
|
}
|
||||||
|
|
||||||
// Reads size bytes of data at the specified offset inside of the
|
/* Reads size bytes of data at the specified offset inside of
|
||||||
// allocated area.
|
* the allocated area. Returns zero on success. Only read limit
|
||||||
//
|
* is the size of the allocated area */
|
||||||
// Only read limit is the size of the allocated area.
|
|
||||||
//
|
|
||||||
// Returns zero on success.
|
|
||||||
int storage_read_data(struct partition_table *part_table, uint32_t offset,
|
int storage_read_data(struct partition_table *part_table, uint32_t offset,
|
||||||
uint8_t *data, size_t size)
|
uint8_t *data, size_t size)
|
||||||
{
|
{
|
||||||
if (part_table == NULL) {
|
if (part_table == NULL || data == NULL) {
|
||||||
return -1;
|
return -4;
|
||||||
}
|
|
||||||
|
|
||||||
// Allow data to point only to app RAM
|
|
||||||
if (data < (uint8_t *)TK1_RAM_BASE ||
|
|
||||||
data >= (uint8_t *)(TK1_RAM_BASE + TK1_RAM_SIZE)) {
|
|
||||||
return -1;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
int index = storage_get_area(part_table);
|
int index = storage_get_area(part_table);
|
||||||
if (index == -1) {
|
if (index == -1) {
|
||||||
// No allocated area
|
/* No allocated area */
|
||||||
return -1;
|
return -1;
|
||||||
}
|
}
|
||||||
|
|
||||||
uint32_t start_address = 0;
|
uint32_t start_address = 0;
|
||||||
|
int err = index_to_address(index, &start_address);
|
||||||
if (index_to_address(index, &start_address) != 0) {
|
if (err) {
|
||||||
return -1;
|
return -3;
|
||||||
}
|
|
||||||
|
|
||||||
if (offset > SIZE_STORAGE_AREA) {
|
|
||||||
return -1;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (size > 4096) {
|
|
||||||
return -1;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
if ((offset + size) > SIZE_STORAGE_AREA) {
|
if ((offset + size) > SIZE_STORAGE_AREA) {
|
||||||
// Reading outside of area
|
/* Reading outside of area */
|
||||||
return -1;
|
return -2;
|
||||||
}
|
}
|
||||||
|
|
||||||
uint32_t address = start_address + offset;
|
uint32_t address = start_address + offset;
|
||||||
|
|
|
@ -1,6 +1,3 @@
|
||||||
// SPDX-FileCopyrightText: 2025 Tillitis AB <tillitis.se>
|
|
||||||
// SPDX-License-Identifier: GPL-2.0-only
|
|
||||||
|
|
||||||
#ifdef QEMU_SYSCALL
|
#ifdef QEMU_SYSCALL
|
||||||
|
|
||||||
#define picorv32_maskirq_insn(...)
|
#define picorv32_maskirq_insn(...)
|
||||||
|
@ -16,7 +13,7 @@
|
||||||
|
|
||||||
|
|
||||||
syscall_enable:
|
syscall_enable:
|
||||||
// Enable syscall IRQ
|
/* Enable syscall IRQ */
|
||||||
li t0, 0x7fffffff // IRQ31 mask
|
li t0, 0x7fffffff // IRQ31 mask
|
||||||
picorv32_maskirq_insn(zero, t0) // Enable IRQs
|
picorv32_maskirq_insn(zero, t0) // Enable IRQs
|
||||||
|
|
||||||
|
|
|
@ -1,5 +1,7 @@
|
||||||
// Copyright (C) 2025 - Tillitis AB
|
/*
|
||||||
// SPDX-License-Identifier: GPL-2.0-only
|
* Copyright (C) 2025 - Tillitis AB
|
||||||
|
* SPDX-License-Identifier: GPL-2.0-only
|
||||||
|
*/
|
||||||
|
|
||||||
#include <stdint.h>
|
#include <stdint.h>
|
||||||
#include <tkey/assert.h>
|
#include <tkey/assert.h>
|
||||||
|
@ -9,12 +11,15 @@
|
||||||
|
|
||||||
#include "partition_table.h"
|
#include "partition_table.h"
|
||||||
#include "preload_app.h"
|
#include "preload_app.h"
|
||||||
#include "reset.h"
|
|
||||||
#include "storage.h"
|
#include "storage.h"
|
||||||
#include "syscall_num.h"
|
|
||||||
|
#include "../tk1/resetinfo.h"
|
||||||
|
#include "../tk1/syscall_num.h"
|
||||||
|
|
||||||
// clang-format off
|
// 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;
|
static volatile uint32_t *udi = (volatile uint32_t *)TK1_MMIO_TK1_UDI_FIRST;
|
||||||
|
static volatile struct reset *resetinfo = (volatile struct reset *)TK1_MMIO_RESETINFO_BASE;
|
||||||
// clang-format on
|
// clang-format on
|
||||||
|
|
||||||
extern struct partition_table_storage part_table_storage;
|
extern struct partition_table_storage part_table_storage;
|
||||||
|
@ -23,9 +28,24 @@ extern uint8_t part_status;
|
||||||
int32_t syscall_handler(uint32_t number, uint32_t arg1, uint32_t arg2,
|
int32_t syscall_handler(uint32_t number, uint32_t arg1, uint32_t arg2,
|
||||||
uint32_t arg3)
|
uint32_t arg3)
|
||||||
{
|
{
|
||||||
|
struct reset *userreset = (struct reset *)arg1;
|
||||||
|
|
||||||
switch (number) {
|
switch (number) {
|
||||||
case TK1_SYSCALL_RESET:
|
case TK1_SYSCALL_RESET:
|
||||||
return reset((struct reset *)arg1, (size_t)arg2);
|
if (arg2 > sizeof(resetinfo->next_app_data)) {
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
|
||||||
|
(void)memset((void *)resetinfo, 0, sizeof(*resetinfo));
|
||||||
|
resetinfo->type = userreset->type;
|
||||||
|
memcpy((void *)resetinfo->app_digest, userreset->app_digest,
|
||||||
|
32);
|
||||||
|
memcpy((void *)resetinfo->next_app_data,
|
||||||
|
userreset->next_app_data, arg2);
|
||||||
|
*system_reset = 1;
|
||||||
|
|
||||||
|
// Should not be reached.
|
||||||
|
assert(1 == 2);
|
||||||
break;
|
break;
|
||||||
|
|
||||||
case TK1_SYSCALL_ALLOC_AREA:
|
case TK1_SYSCALL_ALLOC_AREA:
|
||||||
|
@ -33,39 +53,31 @@ int32_t syscall_handler(uint32_t number, uint32_t arg1, uint32_t arg2,
|
||||||
debug_puts("couldn't allocate storage area\n");
|
debug_puts("couldn't allocate storage area\n");
|
||||||
return -1;
|
return -1;
|
||||||
}
|
}
|
||||||
return 0;
|
|
||||||
|
|
||||||
|
return 0;
|
||||||
case TK1_SYSCALL_DEALLOC_AREA:
|
case TK1_SYSCALL_DEALLOC_AREA:
|
||||||
if (storage_deallocate_area(&part_table_storage) < 0) {
|
if (storage_deallocate_area(&part_table_storage) < 0) {
|
||||||
debug_puts("couldn't deallocate storage area\n");
|
debug_puts("couldn't deallocate storage area\n");
|
||||||
return -1;
|
return -1;
|
||||||
}
|
}
|
||||||
return 0;
|
|
||||||
|
|
||||||
|
return 0;
|
||||||
case TK1_SYSCALL_WRITE_DATA:
|
case TK1_SYSCALL_WRITE_DATA:
|
||||||
if (storage_write_data(&part_table_storage.table, arg1,
|
if (storage_write_data(&part_table_storage.table, arg1,
|
||||||
(uint8_t *)arg2, arg3) < 0) {
|
(uint8_t *)arg2, arg3) < 0) {
|
||||||
debug_puts("couldn't write storage area\n");
|
debug_puts("couldn't write storage area\n");
|
||||||
return -1;
|
return -1;
|
||||||
}
|
}
|
||||||
return 0;
|
|
||||||
|
|
||||||
|
return 0;
|
||||||
case TK1_SYSCALL_READ_DATA:
|
case TK1_SYSCALL_READ_DATA:
|
||||||
if (storage_read_data(&part_table_storage.table, arg1,
|
if (storage_read_data(&part_table_storage.table, arg1,
|
||||||
(uint8_t *)arg2, arg3) < 0) {
|
(uint8_t *)arg2, arg3) < 0) {
|
||||||
debug_puts("couldn't read storage area\n");
|
debug_puts("couldn't read storage area\n");
|
||||||
return -1;
|
return -1;
|
||||||
}
|
}
|
||||||
return 0;
|
|
||||||
|
|
||||||
case TK1_SYSCALL_ERASE_DATA:
|
|
||||||
if (storage_erase_sector(&part_table_storage.table, arg1,
|
|
||||||
arg2) < 0) {
|
|
||||||
debug_puts("couldn't erase storage area\n");
|
|
||||||
return -1;
|
|
||||||
}
|
|
||||||
return 0;
|
return 0;
|
||||||
|
|
||||||
case TK1_SYSCALL_GET_VIDPID:
|
case TK1_SYSCALL_GET_VIDPID:
|
||||||
// UDI is 2 words: VID/PID & serial. Return just the
|
// UDI is 2 words: VID/PID & serial. Return just the
|
||||||
// first word. Serial is kept secret to the device
|
// first word. Serial is kept secret to the device
|
||||||
|
@ -99,10 +111,6 @@ int32_t syscall_handler(uint32_t number, uint32_t arg1, uint32_t arg2,
|
||||||
case TK1_SYSCALL_STATUS:
|
case TK1_SYSCALL_STATUS:
|
||||||
return part_get_status();
|
return part_get_status();
|
||||||
|
|
||||||
case TK1_SYSCALL_GET_APP_DATA:
|
|
||||||
// arg1 next_app_data
|
|
||||||
return reset_data((uint8_t *)arg1);
|
|
||||||
|
|
||||||
default:
|
default:
|
||||||
assert(1 == 2);
|
assert(1 == 2);
|
||||||
}
|
}
|
||||||
|
|
|
@ -18,7 +18,6 @@ enum syscall_num {
|
||||||
TK1_SYSCALL_PRELOAD_GET_DIGSIG = 11,
|
TK1_SYSCALL_PRELOAD_GET_DIGSIG = 11,
|
||||||
TK1_SYSCALL_REG_MGMT = 12,
|
TK1_SYSCALL_REG_MGMT = 12,
|
||||||
TK1_SYSCALL_STATUS = 13,
|
TK1_SYSCALL_STATUS = 13,
|
||||||
TK1_SYSCALL_GET_APP_DATA = 14,
|
|
||||||
};
|
};
|
||||||
|
|
||||||
#endif
|
#endif
|
||||||
|
|
|
@ -32,7 +32,6 @@ The Castor TKey hardware supports more USB endpoints:
|
||||||
|
|
||||||
- CDC - the same thing as older versions.
|
- CDC - the same thing as older versions.
|
||||||
- FIDO security token, for FIDO-like apps.
|
- FIDO security token, for FIDO-like apps.
|
||||||
- CCID, smart card interface.
|
|
||||||
- DEBUG, a HID debug port.
|
- DEBUG, a HID debug port.
|
||||||
|
|
||||||
The communication is still over a single UART. To differ between the
|
The communication is still over a single UART. To differ between the
|
||||||
|
|
|
@ -10,22 +10,20 @@
|
||||||
// I/O endpoints. Keep it as bits possible to use in a bitmask in
|
// I/O endpoints. Keep it as bits possible to use in a bitmask in
|
||||||
// readselect().
|
// readselect().
|
||||||
//
|
//
|
||||||
// Note that the values for IO_CH552, IO_CDC, IO_FIDO, IO_CCID and IO_DEBUG
|
// Note that the DEBUG, CDC, and FIDO should be kept the same on
|
||||||
// should be kept the same in the code for the CH552 side.
|
// the CH552 side.
|
||||||
enum ioend {
|
enum ioend {
|
||||||
IO_NONE = 0x00, // No endpoint
|
IO_NONE = 0x00, // No endpoint
|
||||||
IO_UART = 0x01, // Only destination, raw UART access
|
IO_UART = 0x01, // Only destination, raw UART access
|
||||||
IO_QEMU = 0x02, // Only destination, QEMU debug port
|
IO_QEMU = 0x02, // Only destination, QEMU debug port
|
||||||
IO_CH552 = 0x04, // Internal CH552 control port
|
IO_CH552 = 0x10, // Internal CH552 control port
|
||||||
IO_CDC = 0x08, // CDC "serial" port
|
IO_DEBUG = 0x20, // HID debug port
|
||||||
IO_FIDO = 0x10, // FIDO security token port
|
IO_CDC = 0x40, // CDC "serial port"
|
||||||
IO_CCID = 0x20, // CCID "smart card" port
|
IO_FIDO = 0x80, // FIDO security token port
|
||||||
IO_DEBUG = 0x40, // Debug port over USB HID
|
|
||||||
};
|
};
|
||||||
|
|
||||||
enum ch552cmd {
|
enum ch552cmd {
|
||||||
SET_ENDPOINTS = 0x01, // Config USB endpoints on the CH552
|
SET_ENDPOINTS = 0x01, // Config USB endpoints on the CH552
|
||||||
CH552_CMD_MAX,
|
|
||||||
};
|
};
|
||||||
|
|
||||||
void write(enum ioend dest, const uint8_t *buf, size_t nbytes);
|
void write(enum ioend dest, const uint8_t *buf, size_t nbytes);
|
||||||
|
|
|
@ -74,20 +74,15 @@ static void write_with_header(enum ioend dest, const uint8_t *buf,
|
||||||
// write blockingly writes nbytes bytes of data from buf to dest which
|
// write blockingly writes nbytes bytes of data from buf to dest which
|
||||||
// is either:
|
// is either:
|
||||||
//
|
//
|
||||||
// - IO_UART: Low-level UART access, no USB Mode Header added.
|
|
||||||
//
|
|
||||||
// - IO_QEMU: QEMU debug port
|
// - IO_QEMU: QEMU debug port
|
||||||
//
|
//
|
||||||
// - IO_CH552: Internal communication between the FPGA and the
|
// - IO_UART: Low-level UART access, no USB Mode Header added.
|
||||||
// CH552, with header.
|
|
||||||
//
|
//
|
||||||
// - IO_CDC: Through the UART for the CDC endpoint, 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_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 HID endpoint, with
|
||||||
//
|
|
||||||
// - IO_DEBUG: Through the UART for the DEBUG endpoint (USB HID), with
|
|
||||||
// header.
|
// header.
|
||||||
void write(enum ioend dest, const uint8_t *buf, size_t nbytes)
|
void write(enum ioend dest, const uint8_t *buf, size_t nbytes)
|
||||||
{
|
{
|
||||||
|
@ -208,11 +203,9 @@ static int discard(size_t nbytes)
|
||||||
//
|
//
|
||||||
// Only endpoints available for read are:
|
// Only endpoints available for read are:
|
||||||
//
|
//
|
||||||
// - IO_CH552
|
// - IO_DEBUG
|
||||||
// - IO_CDC
|
// - IO_CDC
|
||||||
// - IO_FIDO
|
// - IO_FIDO
|
||||||
// - IO_CCID
|
|
||||||
// - IO_DEBUG
|
|
||||||
//
|
//
|
||||||
// If you need blocking low-level UART reads, use uart_read() instead.
|
// If you need blocking low-level UART reads, use uart_read() instead.
|
||||||
//
|
//
|
||||||
|
@ -359,8 +352,7 @@ void hexdump(enum ioend dest, void *buf, int len)
|
||||||
// Configure USB endpoints that should be enabled/disabled
|
// Configure USB endpoints that should be enabled/disabled
|
||||||
//
|
//
|
||||||
// Allowed options are:
|
// Allowed options are:
|
||||||
// - IO_FIDO (can't be used used together with IO_CCID)
|
// - IO_FIDO
|
||||||
// - IO_CCID (can't be used used together with IO_FIDO)
|
|
||||||
// - IO_DEBUG
|
// - IO_DEBUG
|
||||||
//
|
//
|
||||||
// The following are always enabled:
|
// The following are always enabled:
|
||||||
|
|
|
@ -1,33 +0,0 @@
|
||||||
# Tools
|
|
||||||
|
|
||||||
We have developed some tools necessary for the build.
|
|
||||||
|
|
||||||
- `app_bin_to_spram_hex.py`: Script used to include a device app in a
|
|
||||||
testbench simulation.
|
|
||||||
|
|
||||||
- `b2s`: Compute and print a BLAKE2s digest over a file. Used for the
|
|
||||||
digest of the app in app slot 0 included in the firmware.
|
|
||||||
|
|
||||||
- `default_partition.bin`: Default partition table for the flash.
|
|
||||||
|
|
||||||
- `load_preloaded_app.sh`: Script to load two copies of the partition
|
|
||||||
table to flash and a pre-loaded to app slot 0 or 1. Needs
|
|
||||||
`default_partition.bin`, generated with `tkeyimage` and the binary
|
|
||||||
of the device app to load. Call like: `./load_preloaded_app 0
|
|
||||||
path/to/binary`.
|
|
||||||
|
|
||||||
- `makehex.py`: Used to build hex version of firmware ROM for FPGA
|
|
||||||
bitstream build.
|
|
||||||
|
|
||||||
- `patch_uds_udi.py`: Script used to patch in the Unique Device Secret
|
|
||||||
in `data/uds.hex` and the Unique Device Identifier in `data/udi.hex`
|
|
||||||
into the bitstream without having to rebuild the entire bitstream.
|
|
||||||
|
|
||||||
- `run_pnr.sh`: Script to run place and route with `nextpnr` in order
|
|
||||||
to find a routing seed that will meet desired timing.
|
|
||||||
|
|
||||||
- `tkeyimage`: Utility to create and parse flash images with a TKey
|
|
||||||
filesystem or the partition table
|
|
||||||
|
|
||||||
- `tpt/tpt.py`: Utility to create the Unique Device Secret (UDS) and
|
|
||||||
Unique Device Identity (UDI) interactively.
|
|
|
@ -20,7 +20,7 @@ func printCDigest(digest [blake2s.Size]byte, fileName string) {
|
||||||
fmt.Printf("const uint8_t digest[32] = {\n")
|
fmt.Printf("const uint8_t digest[32] = {\n")
|
||||||
|
|
||||||
for _, n := range digest {
|
for _, n := range digest {
|
||||||
fmt.Printf("0x%02x, ", n)
|
fmt.Printf("0x%x, ", n)
|
||||||
}
|
}
|
||||||
|
|
||||||
fmt.Printf("\n}; \n")
|
fmt.Printf("\n}; \n")
|
||||||
|
|
28
hw/application_fpga/tools/create_flash_image.py
Executable file
28
hw/application_fpga/tools/create_flash_image.py
Executable file
|
@ -0,0 +1,28 @@
|
||||||
|
#!/usr/bin/env python3
|
||||||
|
|
||||||
|
import argparse
|
||||||
|
|
||||||
|
FLASH_SIZE_BYTES = 1 * 1024 * 1024
|
||||||
|
PRELOADED_APP_0_START = 0x30000
|
||||||
|
|
||||||
|
|
||||||
|
def run(output_path, preloaded_app_0_path):
|
||||||
|
with (
|
||||||
|
open(output_path, "wb") as output_file,
|
||||||
|
open(preloaded_app_0_path, "rb") as preloaded_app_0_file,
|
||||||
|
):
|
||||||
|
content = bytearray(b"\xFF") * FLASH_SIZE_BYTES
|
||||||
|
preloaded_app = preloaded_app_0_file.read()
|
||||||
|
content[
|
||||||
|
PRELOADED_APP_0_START : PRELOADED_APP_0_START + len(preloaded_app)
|
||||||
|
] = preloaded_app
|
||||||
|
output_file.write(content)
|
||||||
|
|
||||||
|
|
||||||
|
if __name__ == "__main__":
|
||||||
|
arg_parser = argparse.ArgumentParser()
|
||||||
|
arg_parser.add_argument("OUTPUT_PATH")
|
||||||
|
arg_parser.add_argument("PRELOADED_APP_0_PATH")
|
||||||
|
args = arg_parser.parse_args()
|
||||||
|
|
||||||
|
run(args.OUTPUT_PATH, args.PRELOADED_APP_0_PATH)
|
Binary file not shown.
|
@ -1,7 +1,5 @@
|
||||||
#!/bin/bash -e
|
#!/bin/bash -e
|
||||||
|
|
||||||
# SPDX-FileCopyrightText: 2025 Tillitis AB <tillitis.se>
|
|
||||||
# SPDX-License-Identifier: GPL-2.0-only
|
|
||||||
if [ $# != 2 ]
|
if [ $# != 2 ]
|
||||||
then
|
then
|
||||||
echo "Usage: $0 slot_num app_file"
|
echo "Usage: $0 slot_num app_file"
|
||||||
|
|
|
@ -1,8 +1,5 @@
|
||||||
#!/usr/bin/env python3
|
#!/usr/bin/env python3
|
||||||
#
|
#
|
||||||
# SPDX-FileCopyrightText: Claire Xenia Wolf <claire@yosyshq.com>
|
|
||||||
# SPDX-License-Identifier: CC0-1.0
|
|
||||||
|
|
||||||
# This is free and unencumbered software released into the public domain.
|
# This is free and unencumbered software released into the public domain.
|
||||||
#
|
#
|
||||||
# Anyone is free to copy, modify, publish, use, compile, sell, or
|
# Anyone is free to copy, modify, publish, use, compile, sell, or
|
|
@ -1,4 +1,4 @@
|
||||||
module tkeyimage
|
module partition_table
|
||||||
|
|
||||||
go 1.23.0
|
go 1.23.0
|
||||||
|
|
172
hw/application_fpga/tools/partition_table/partition_table.go
Normal file
172
hw/application_fpga/tools/partition_table/partition_table.go
Normal file
|
@ -0,0 +1,172 @@
|
||||||
|
package main
|
||||||
|
|
||||||
|
import (
|
||||||
|
"encoding/binary"
|
||||||
|
"flag"
|
||||||
|
"fmt"
|
||||||
|
"io"
|
||||||
|
"os"
|
||||||
|
|
||||||
|
"golang.org/x/crypto/blake2s"
|
||||||
|
)
|
||||||
|
|
||||||
|
type PreLoadedAppData struct {
|
||||||
|
Size uint32
|
||||||
|
Digest [32]uint8
|
||||||
|
Signature [64]uint8
|
||||||
|
}
|
||||||
|
|
||||||
|
type Auth struct {
|
||||||
|
Nonce [16]uint8
|
||||||
|
AuthDigest [16]uint8
|
||||||
|
}
|
||||||
|
|
||||||
|
type AppStorage struct {
|
||||||
|
Status uint8
|
||||||
|
Auth Auth
|
||||||
|
}
|
||||||
|
|
||||||
|
type PartTable struct {
|
||||||
|
Version uint8
|
||||||
|
PreLoadedAppData [2]PreLoadedAppData
|
||||||
|
AppStorage [4]AppStorage
|
||||||
|
}
|
||||||
|
|
||||||
|
type PartTableStorage struct {
|
||||||
|
PartTable PartTable
|
||||||
|
Digest [16]uint8
|
||||||
|
}
|
||||||
|
|
||||||
|
type Flash struct {
|
||||||
|
Bitstream [0x20000]uint8
|
||||||
|
PartitionTableStorage PartTableStorage
|
||||||
|
PartitionTablePadding [64*1024 - 349]uint8
|
||||||
|
PreLoadedApp0 [0x20000]uint8
|
||||||
|
PreLoadedApp1 [0x20000]uint8
|
||||||
|
AppStorage [4][0x20000]uint8
|
||||||
|
EndPadding [0x10000]uint8
|
||||||
|
}
|
||||||
|
|
||||||
|
func readStruct[T PartTableStorage | Flash](filename string) T {
|
||||||
|
var s T
|
||||||
|
|
||||||
|
file, err := os.Open(filename)
|
||||||
|
if err != nil {
|
||||||
|
panic(err)
|
||||||
|
}
|
||||||
|
|
||||||
|
if err := binary.Read(file, binary.LittleEndian, &s); err != nil {
|
||||||
|
panic(err)
|
||||||
|
}
|
||||||
|
|
||||||
|
sLen, err := file.Seek(0, io.SeekCurrent)
|
||||||
|
if err != nil {
|
||||||
|
panic(err)
|
||||||
|
}
|
||||||
|
|
||||||
|
fmt.Fprintf(os.Stderr, "INFO: %T struct is %d byte long\n", *new(T), sLen)
|
||||||
|
|
||||||
|
return s
|
||||||
|
}
|
||||||
|
|
||||||
|
func printPartTableStorageCondensed(storage PartTableStorage) {
|
||||||
|
fmt.Printf("Partition Table Storage\n")
|
||||||
|
fmt.Printf(" Partition Table\n")
|
||||||
|
fmt.Printf(" Header\n")
|
||||||
|
fmt.Printf(" Version : %d\n", storage.PartTable.Version)
|
||||||
|
|
||||||
|
for i, appData := range storage.PartTable.PreLoadedAppData {
|
||||||
|
fmt.Printf(" Preloaded App %d\n", i)
|
||||||
|
fmt.Printf(" Size : %d\n", appData.Size)
|
||||||
|
fmt.Printf(" Digest : %x\n", appData.Digest[:16])
|
||||||
|
fmt.Printf(" %x\n", appData.Digest[16:])
|
||||||
|
fmt.Printf(" Signature : %x\n", appData.Signature[:16])
|
||||||
|
fmt.Printf(" %x\n", appData.Signature[16:32])
|
||||||
|
fmt.Printf(" %x\n", appData.Signature[32:48])
|
||||||
|
fmt.Printf(" %x\n", appData.Signature[48:])
|
||||||
|
}
|
||||||
|
fmt.Printf(" Digest : %x\n", storage.Digest)
|
||||||
|
}
|
||||||
|
|
||||||
|
func calculateStorageDigest(data []byte) []byte {
|
||||||
|
key := [16]byte{}
|
||||||
|
|
||||||
|
hash, err := blake2s.New128(key[:])
|
||||||
|
if err != nil {
|
||||||
|
panic(err)
|
||||||
|
}
|
||||||
|
|
||||||
|
hash.Write(data)
|
||||||
|
digest := hash.Sum([]byte{})
|
||||||
|
|
||||||
|
return digest
|
||||||
|
}
|
||||||
|
|
||||||
|
func generatePartTableStorage(outputFilename string, app0Filename string) {
|
||||||
|
storage := PartTableStorage{
|
||||||
|
PartTable: PartTable{
|
||||||
|
Version: 1,
|
||||||
|
PreLoadedAppData: [2]PreLoadedAppData{},
|
||||||
|
AppStorage: [4]AppStorage{},
|
||||||
|
},
|
||||||
|
}
|
||||||
|
|
||||||
|
if app0Filename != "" {
|
||||||
|
stat, err := os.Stat(app0Filename)
|
||||||
|
if err != nil {
|
||||||
|
panic(err)
|
||||||
|
}
|
||||||
|
storage.PartTable.PreLoadedAppData[0].Size = uint32(stat.Size())
|
||||||
|
}
|
||||||
|
|
||||||
|
buf := make([]byte, 4096, 4096)
|
||||||
|
len, err := binary.Encode(buf, binary.LittleEndian, storage.PartTable)
|
||||||
|
if err != nil {
|
||||||
|
panic(err)
|
||||||
|
}
|
||||||
|
fmt.Printf("buf - len: %d, data: %x\n", len, buf[:len])
|
||||||
|
|
||||||
|
digest := calculateStorageDigest(buf[:len])
|
||||||
|
copy(storage.Digest[:], digest)
|
||||||
|
fmt.Printf("digest: %x\n", digest)
|
||||||
|
|
||||||
|
storageFile, err := os.Create(outputFilename)
|
||||||
|
if err != nil {
|
||||||
|
panic(err)
|
||||||
|
}
|
||||||
|
|
||||||
|
if err := binary.Write(storageFile, binary.LittleEndian, storage); err != nil {
|
||||||
|
panic(err)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func main() {
|
||||||
|
input := ""
|
||||||
|
output := ""
|
||||||
|
app0 := ""
|
||||||
|
flash := false
|
||||||
|
|
||||||
|
flag.StringVar(&input, "i", "", "Input binary dump file. Cannot be used with -o.")
|
||||||
|
flag.StringVar(&output, "o", "", "Output binary dump file. Cannot be used with -i.")
|
||||||
|
flag.StringVar(&app0, "app0", "", "Binary in pre loaded app slot 0. Can be used with -o.")
|
||||||
|
flag.BoolVar(&flash, "f", false, "Treat input file as a dump of the entire flash memory.")
|
||||||
|
flag.Parse()
|
||||||
|
|
||||||
|
if (input == "" && output == "") || (input != "" && output != "") {
|
||||||
|
flag.Usage()
|
||||||
|
os.Exit(1)
|
||||||
|
}
|
||||||
|
|
||||||
|
if input != "" {
|
||||||
|
var storage PartTableStorage
|
||||||
|
|
||||||
|
if flash {
|
||||||
|
storage = readStruct[Flash](input).PartitionTableStorage
|
||||||
|
} else {
|
||||||
|
storage = readStruct[PartTableStorage](input)
|
||||||
|
}
|
||||||
|
printPartTableStorageCondensed(storage)
|
||||||
|
} else if output != "" {
|
||||||
|
generatePartTableStorage(output, app0)
|
||||||
|
}
|
||||||
|
}
|
15
hw/application_fpga/tools/reset-tk1
Executable file
15
hw/application_fpga/tools/reset-tk1
Executable file
|
@ -0,0 +1,15 @@
|
||||||
|
#!/bin/sh
|
||||||
|
set -eu
|
||||||
|
|
||||||
|
cd "${0%/*}"
|
||||||
|
cd ../../production_test
|
||||||
|
|
||||||
|
if [ ! -e venv ]; then
|
||||||
|
python3 -m venv venv
|
||||||
|
. ./venv/bin/activate
|
||||||
|
pip3 install -r requirements.txt
|
||||||
|
else
|
||||||
|
. ./venv/bin/activate
|
||||||
|
fi
|
||||||
|
|
||||||
|
./reset.py
|
|
@ -1,8 +1,5 @@
|
||||||
#!/bin/bash
|
#!/bin/bash
|
||||||
|
|
||||||
# SPDX-FileCopyrightText: 2025 Tillitis AB <tillitis.se>
|
|
||||||
# SPDX-License-Identifier: GPL-2.0-only
|
|
||||||
|
|
||||||
help() {
|
help() {
|
||||||
echo "Usage: $(basename $0) [OPTION]"
|
echo "Usage: $(basename $0) [OPTION]"
|
||||||
echo "Run multiple place and route threads with nextpnr-ice40"
|
echo "Run multiple place and route threads with nextpnr-ice40"
|
||||||
|
|
|
@ -1,114 +0,0 @@
|
||||||
# tkeyimage
|
|
||||||
|
|
||||||
A tool to parse or generate partition table or entire filesystems for
|
|
||||||
the TKey.
|
|
||||||
|
|
||||||
- Parse with `-i file.bin` for "input".
|
|
||||||
- Generate with `-o file.bin` for "output".
|
|
||||||
|
|
||||||
Add `-f` to parse or generate an entire flash image file.
|
|
||||||
|
|
||||||
## Usage
|
|
||||||
|
|
||||||
### Inspect a partition table dump
|
|
||||||
|
|
||||||
Dump the entire data from flash, then inspect:
|
|
||||||
|
|
||||||
```
|
|
||||||
$ tillitis-iceprog -R 1M dump.bin
|
|
||||||
$ ./tkeyimage -i dump.bin -f
|
|
||||||
INFO: main.Flash struct is 1048576 byte long
|
|
||||||
Partition Table Storage
|
|
||||||
Partition Table
|
|
||||||
Header
|
|
||||||
Version : 1
|
|
||||||
Preloaded App 0
|
|
||||||
Size : 23796
|
|
||||||
Digest : 00000000000000000000000000000000
|
|
||||||
00000000000000000000000000000000
|
|
||||||
Signature : 00000000000000000000000000000000
|
|
||||||
00000000000000000000000000000000
|
|
||||||
00000000000000000000000000000000
|
|
||||||
00000000000000000000000000000000
|
|
||||||
Preloaded App 1
|
|
||||||
Size : 264
|
|
||||||
Digest : 96bb4c90603dbbbe09b9a1d7259b5e9e
|
|
||||||
61bedd89a897105c30c9d4bf66a98d97
|
|
||||||
Signature : ccb60c034e559b8c695f25233b80c245
|
|
||||||
e099316324e1a4e68a14c82d834eee58
|
|
||||||
5700cd5c29b64e74159a4dbf3fed030a
|
|
||||||
140e981fb3b6972c125afb4d4497da0a
|
|
||||||
Digest : 4628f142764f724e45e05b20363960967705cfcee8285b2d9d207e04a46e275e
|
|
||||||
```
|
|
||||||
|
|
||||||
Read only the first copy of the partition table from flash to file,
|
|
||||||
then inspect:
|
|
||||||
|
|
||||||
```
|
|
||||||
$ tillitis-iceprog -o 128k -r partition.bin
|
|
||||||
$ ./tkeyimage -i partition.bin
|
|
||||||
INFO: main.PartTableStorage struct is 365 byte long
|
|
||||||
Partition Table Storage
|
|
||||||
Partition Table
|
|
||||||
Header
|
|
||||||
Version : 1
|
|
||||||
Preloaded App 0
|
|
||||||
Size : 23796
|
|
||||||
Digest : 00000000000000000000000000000000
|
|
||||||
00000000000000000000000000000000
|
|
||||||
Signature : 00000000000000000000000000000000
|
|
||||||
00000000000000000000000000000000
|
|
||||||
00000000000000000000000000000000
|
|
||||||
00000000000000000000000000000000
|
|
||||||
Preloaded App 1
|
|
||||||
Size : 0
|
|
||||||
Digest : 00000000000000000000000000000000
|
|
||||||
00000000000000000000000000000000
|
|
||||||
Signature : 00000000000000000000000000000000
|
|
||||||
00000000000000000000000000000000
|
|
||||||
00000000000000000000000000000000
|
|
||||||
00000000000000000000000000000000
|
|
||||||
Digest : 40c6dbb4c8fda561369ec54a907452ae352ccbd736ba7824c4e173fd438b7d7a
|
|
||||||
```
|
|
||||||
|
|
||||||
### Generate a partition table
|
|
||||||
|
|
||||||
If you want to generate just a partition table:
|
|
||||||
|
|
||||||
```
|
|
||||||
$ ./tkeyimage -o partition.bin
|
|
||||||
```
|
|
||||||
|
|
||||||
With an app in slot 0, filling in the size in the partition table:
|
|
||||||
|
|
||||||
```
|
|
||||||
$ ./tkeyimage -o partition.bin -app0 ../../fw/testloadapp/testloadapp.bin
|
|
||||||
```
|
|
||||||
|
|
||||||
### Generate flash image
|
|
||||||
|
|
||||||
The program can also generate an entire flash image for use either
|
|
||||||
with real hardware or qemu.
|
|
||||||
|
|
||||||
Generate like this:
|
|
||||||
|
|
||||||
```
|
|
||||||
$ ./tkeyimage -o flash.bin -f -app0 ../../fw/testloadapp/testloadapp.bin
|
|
||||||
```
|
|
||||||
|
|
||||||
Using `-app0` is mandatory because TKey firmware won't start without
|
|
||||||
an app in slot 0.
|
|
||||||
|
|
||||||
The qemu args to use to run with `flash.bin` as the flash are:
|
|
||||||
|
|
||||||
```
|
|
||||||
-drive file=flash.bin,if=mtd,format=raw,index=0
|
|
||||||
```
|
|
||||||
|
|
||||||
A complete command example:
|
|
||||||
|
|
||||||
```
|
|
||||||
$ qemu-system-riscv32 -nographic -M tk1-castor,fifo=chrid \
|
|
||||||
-bios qemu_firmware.elf -chardev pty,id=chrid -s -d guest_errors \
|
|
||||||
-drive file=flash.bin,if=mtd,format=raw,index=0
|
|
||||||
```
|
|
|
@ -1,266 +0,0 @@
|
||||||
// SPDX-FileCopyrightText: 2025 Tillitis AB <tillitis.se>
|
|
||||||
// SPDX-License-Identifier: BSD-2-Clause
|
|
||||||
|
|
||||||
package main
|
|
||||||
|
|
||||||
import (
|
|
||||||
"encoding/binary"
|
|
||||||
"flag"
|
|
||||||
"fmt"
|
|
||||||
"io"
|
|
||||||
"os"
|
|
||||||
|
|
||||||
"golang.org/x/crypto/blake2s"
|
|
||||||
)
|
|
||||||
|
|
||||||
// Maximum allowed size in bytes of a preloaded app.
|
|
||||||
const MaxAppSize = (128 * 1024)
|
|
||||||
|
|
||||||
// Size in bytes of the partition table binary. Find out with -o and
|
|
||||||
// check the file size.
|
|
||||||
const PartitionSize = 365
|
|
||||||
|
|
||||||
type PreLoadedAppData struct {
|
|
||||||
Size uint32
|
|
||||||
Digest [32]uint8
|
|
||||||
Signature [64]uint8
|
|
||||||
}
|
|
||||||
|
|
||||||
type Auth struct {
|
|
||||||
Nonce [16]uint8
|
|
||||||
AuthDigest [16]uint8
|
|
||||||
}
|
|
||||||
|
|
||||||
type AppStorage struct {
|
|
||||||
Status uint8
|
|
||||||
Auth Auth
|
|
||||||
}
|
|
||||||
|
|
||||||
type PartTable struct {
|
|
||||||
Version uint8
|
|
||||||
PreLoadedAppData [2]PreLoadedAppData
|
|
||||||
AppStorage [4]AppStorage
|
|
||||||
}
|
|
||||||
|
|
||||||
type PartTableStorage struct {
|
|
||||||
PartTable PartTable
|
|
||||||
Checksum [32]byte
|
|
||||||
}
|
|
||||||
|
|
||||||
func (p *PartTableStorage) GenChecksum() {
|
|
||||||
buf := make([]byte, 4096)
|
|
||||||
len, err := binary.Encode(buf, binary.LittleEndian, p.PartTable)
|
|
||||||
if err != nil {
|
|
||||||
panic(err)
|
|
||||||
}
|
|
||||||
|
|
||||||
p.Checksum = blake2s.Sum256(buf[:len])
|
|
||||||
}
|
|
||||||
|
|
||||||
// Name Size Start addr
|
|
||||||
// ---- ---- ----
|
|
||||||
// Bitstream 128KiB 0x00
|
|
||||||
// ---- ---- ----
|
|
||||||
// Partition 64KiB 0x20000
|
|
||||||
// ---- ---- ----
|
|
||||||
// Pre load 0 128KiB 0x30000
|
|
||||||
// Pre load 1 128KiB 0x50000
|
|
||||||
// ---- ---- ----
|
|
||||||
// storage 0 128KiB 0x70000
|
|
||||||
// storage 1 128KiB 0x90000
|
|
||||||
// storage 2 128KiB 0xB0000
|
|
||||||
// storage 3 128KiB 0xD0000
|
|
||||||
// ---- ---- ----
|
|
||||||
// Partition2 64KiB 0xf0000
|
|
||||||
type Flash struct {
|
|
||||||
Bitstream [0x20000]uint8 // Reserved for FPGA bitstream
|
|
||||||
PartitionTable PartTableStorage // 0x20000 partition table
|
|
||||||
PartitionTablePadding [64*1024 - PartitionSize]uint8 // ~64k padding
|
|
||||||
PreLoadedApp0 [0x20000]uint8 // 0x30000
|
|
||||||
PreLoadedApp1 [0x20000]uint8 // 0x50000
|
|
||||||
AppStorage [4][0x20000]uint8 // 0x70000, 4 * 128 storage for apps
|
|
||||||
PartitionTable2 PartTableStorage // 0xf0000 second copy of table
|
|
||||||
PartitionTablePadding2 [64*1024 - PartitionSize]uint8 // ~64k padding
|
|
||||||
}
|
|
||||||
|
|
||||||
func readStruct[T PartTableStorage | Flash](filename string) T {
|
|
||||||
var s T
|
|
||||||
|
|
||||||
file, err := os.Open(filename)
|
|
||||||
if err != nil {
|
|
||||||
panic(err)
|
|
||||||
}
|
|
||||||
|
|
||||||
if err := binary.Read(file, binary.LittleEndian, &s); err != nil {
|
|
||||||
panic(err)
|
|
||||||
}
|
|
||||||
|
|
||||||
sLen, err := file.Seek(0, io.SeekCurrent)
|
|
||||||
if err != nil {
|
|
||||||
panic(err)
|
|
||||||
}
|
|
||||||
|
|
||||||
fmt.Fprintf(os.Stderr, "INFO: %T struct is %d byte long\n", *new(T), sLen)
|
|
||||||
|
|
||||||
return s
|
|
||||||
}
|
|
||||||
|
|
||||||
func printPartTableStorageCondensed(storage PartTableStorage) {
|
|
||||||
fmt.Printf("Partition Table Storage\n")
|
|
||||||
fmt.Printf(" Partition Table\n")
|
|
||||||
fmt.Printf(" Header\n")
|
|
||||||
fmt.Printf(" Version : %d\n", storage.PartTable.Version)
|
|
||||||
|
|
||||||
for i, appData := range storage.PartTable.PreLoadedAppData {
|
|
||||||
fmt.Printf(" Preloaded App %d\n", i)
|
|
||||||
fmt.Printf(" Size : %d\n", appData.Size)
|
|
||||||
fmt.Printf(" Digest : %x\n", appData.Digest[:16])
|
|
||||||
fmt.Printf(" %x\n", appData.Digest[16:])
|
|
||||||
fmt.Printf(" Signature : %x\n", appData.Signature[:16])
|
|
||||||
fmt.Printf(" %x\n", appData.Signature[16:32])
|
|
||||||
fmt.Printf(" %x\n", appData.Signature[32:48])
|
|
||||||
fmt.Printf(" %x\n", appData.Signature[48:])
|
|
||||||
}
|
|
||||||
fmt.Printf(" Digest : %x\n", storage.Checksum)
|
|
||||||
}
|
|
||||||
|
|
||||||
func genPartitionFile(outputFilename string, app0Filename string) {
|
|
||||||
partition := newPartTable(app0Filename)
|
|
||||||
partition.GenChecksum()
|
|
||||||
|
|
||||||
storageFile, err := os.Create(outputFilename)
|
|
||||||
if err != nil {
|
|
||||||
panic(err)
|
|
||||||
}
|
|
||||||
|
|
||||||
if err := binary.Write(storageFile, binary.LittleEndian, partition); err != nil {
|
|
||||||
panic(err)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// newPartTable generates a new partition table suitable for storage.
|
|
||||||
// If given app0Filename it also fills in the size of the file.
|
|
||||||
//
|
|
||||||
// When you're done with filling in the struct, remember to call
|
|
||||||
// GenChecksum().
|
|
||||||
//
|
|
||||||
// It returns the partition table.
|
|
||||||
func newPartTable(app0Filename string) PartTableStorage {
|
|
||||||
storage := PartTableStorage{
|
|
||||||
PartTable: PartTable{
|
|
||||||
Version: 1,
|
|
||||||
PreLoadedAppData: [2]PreLoadedAppData{},
|
|
||||||
AppStorage: [4]AppStorage{},
|
|
||||||
},
|
|
||||||
}
|
|
||||||
|
|
||||||
if app0Filename != "" {
|
|
||||||
stat, err := os.Stat(app0Filename)
|
|
||||||
if err != nil {
|
|
||||||
panic(err)
|
|
||||||
}
|
|
||||||
storage.PartTable.PreLoadedAppData[0].Size = uint32(stat.Size())
|
|
||||||
}
|
|
||||||
|
|
||||||
return storage
|
|
||||||
}
|
|
||||||
|
|
||||||
func memset(s []byte, c byte) {
|
|
||||||
for i := range s {
|
|
||||||
s[i] = c
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
func genFlashFile(outputFilename string, app0Filename string) {
|
|
||||||
var flash Flash
|
|
||||||
|
|
||||||
// Set all bits in flash to erased.
|
|
||||||
memset(flash.Bitstream[:], 0xff)
|
|
||||||
// partition0 will be filled in below
|
|
||||||
memset(flash.PartitionTablePadding[:], 0xff)
|
|
||||||
memset(flash.PreLoadedApp0[:], 0xff)
|
|
||||||
memset(flash.PreLoadedApp1[:], 0xff)
|
|
||||||
memset(flash.AppStorage[0][:], 0xff)
|
|
||||||
memset(flash.AppStorage[1][:], 0xff)
|
|
||||||
memset(flash.AppStorage[2][:], 0xff)
|
|
||||||
memset(flash.AppStorage[3][:], 0xff)
|
|
||||||
// partition1 will be filled in below
|
|
||||||
memset(flash.PartitionTablePadding2[:], 0xff)
|
|
||||||
|
|
||||||
partition := newPartTable(app0Filename)
|
|
||||||
partition.GenChecksum()
|
|
||||||
|
|
||||||
flash.PartitionTable = partition
|
|
||||||
flash.PartitionTable2 = partition
|
|
||||||
|
|
||||||
// Read the entire file.
|
|
||||||
appBuf, err := os.ReadFile(app0Filename)
|
|
||||||
if err != nil {
|
|
||||||
panic(err)
|
|
||||||
}
|
|
||||||
|
|
||||||
if len(appBuf) > MaxAppSize {
|
|
||||||
fmt.Printf("max app size is 128 k")
|
|
||||||
os.Exit(1)
|
|
||||||
}
|
|
||||||
|
|
||||||
copy(flash.PreLoadedApp0[:], appBuf)
|
|
||||||
|
|
||||||
storageFile, err := os.Create(outputFilename)
|
|
||||||
if err != nil {
|
|
||||||
panic(err)
|
|
||||||
}
|
|
||||||
|
|
||||||
if err := binary.Write(storageFile, binary.LittleEndian, flash); err != nil {
|
|
||||||
panic(err)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
func main() {
|
|
||||||
var input string
|
|
||||||
var output string
|
|
||||||
var app0 string
|
|
||||||
var flash bool
|
|
||||||
|
|
||||||
flag.StringVar(&input, "i", "", "Input binary file. Cannot be used with -o.")
|
|
||||||
flag.StringVar(&output, "o", "", "Output binary file. Cannot be used with -i. If used with -f, -app0 must also be specified.")
|
|
||||||
flag.StringVar(&app0, "app0", "", "Binary in pre loaded app slot 0. Can be used with -o.")
|
|
||||||
flag.BoolVar(&flash, "f", false, "Treat file as a dump of the entire flash memory.")
|
|
||||||
flag.Parse()
|
|
||||||
|
|
||||||
if len(flag.Args()) > 0 {
|
|
||||||
fmt.Printf("superfluous args\n")
|
|
||||||
flag.Usage()
|
|
||||||
os.Exit(1)
|
|
||||||
}
|
|
||||||
|
|
||||||
if (input == "" && output == "") || (input != "" && output != "") {
|
|
||||||
flag.Usage()
|
|
||||||
os.Exit(1)
|
|
||||||
}
|
|
||||||
|
|
||||||
if input != "" {
|
|
||||||
var storage PartTableStorage
|
|
||||||
|
|
||||||
if flash {
|
|
||||||
storage = readStruct[Flash](input).PartitionTable
|
|
||||||
} else {
|
|
||||||
storage = readStruct[PartTableStorage](input)
|
|
||||||
}
|
|
||||||
printPartTableStorageCondensed(storage)
|
|
||||||
os.Exit(0)
|
|
||||||
}
|
|
||||||
|
|
||||||
if output != "" {
|
|
||||||
if flash {
|
|
||||||
if app0 == "" {
|
|
||||||
fmt.Printf("need -app0 path/to/app\n")
|
|
||||||
os.Exit(1)
|
|
||||||
}
|
|
||||||
|
|
||||||
genFlashFile(output, app0)
|
|
||||||
} else {
|
|
||||||
genPartitionFile(output, app0)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
0
hw/application_fpga/tools/tpt/__init__.py
Normal file
0
hw/application_fpga/tools/tpt/__init__.py
Normal file
|
@ -51,20 +51,16 @@ def format_descriptor(name, value):
|
||||||
|
|
||||||
if __name__ == "__main__":
|
if __name__ == "__main__":
|
||||||
strings = {
|
strings = {
|
||||||
"ProdDesc": "Tillitis TKEY-USB-V2",
|
"ProdDesc": "MTA1-USB-V1",
|
||||||
"ManufDesc": "Tillitis",
|
"ManufDesc": "Tillitis",
|
||||||
"SerialDesc": "68de5d27-e223-4874-bc76-a54d6e84068f",
|
"SerialDesc": "68de5d27-e223-4874-bc76-a54d6e84068f",
|
||||||
"CdcCtrlInterfaceDesc": "CDC-Ctrl",
|
"CdcCtrlInterfaceDesc": "CDC-Ctrl",
|
||||||
"CdcDataInterfaceDesc": "CDC-Data",
|
"CdcDataInterfaceDesc": "CDC-Data",
|
||||||
"FidoInterfaceDesc": "FIDO",
|
"FidoInterfaceDesc": "FIDO",
|
||||||
"CcidInterfaceDesc": "CCID",
|
|
||||||
"DebugInterfaceDesc": "DEBUG"
|
"DebugInterfaceDesc": "DEBUG"
|
||||||
}
|
}
|
||||||
|
|
||||||
with open('inc/usb_strings.h', 'w') as f:
|
with open('inc/usb_strings.h', 'w') as f:
|
||||||
f.write('// SPDX-FileCopyrightText: 2024 Tillitis AB <tillitis.se>\n')
|
|
||||||
f.write('// SPDX-License-Identifier: MIT\n')
|
|
||||||
f.write('\n')
|
|
||||||
f.write('#ifndef __USB_STRINGS_H__\n')
|
f.write('#ifndef __USB_STRINGS_H__\n')
|
||||||
f.write('#define __USB_STRINGS_H__\n')
|
f.write('#define __USB_STRINGS_H__\n')
|
||||||
f.write('\n')
|
f.write('\n')
|
||||||
|
|
|
@ -94,13 +94,6 @@ Header file for CH554 microcontrollers.
|
||||||
#define USB_CDC_REQ_TYPE_SET_CONTROL_LINE_STATE 0x22
|
#define USB_CDC_REQ_TYPE_SET_CONTROL_LINE_STATE 0x22
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
/* USB CCID (Smart Card) class request code */
|
|
||||||
#ifndef USB_CCID_REQ_TYPE
|
|
||||||
#define USB_CCID_REQ_TYPE_ABORT 0x01
|
|
||||||
#define USB_CCID_REQ_TYPE_GET_CLOCK_FREQUENCIES 0x02
|
|
||||||
#define USB_CCID_REQ_TYPE_GET_DATA_RATES 0x03
|
|
||||||
#endif
|
|
||||||
|
|
||||||
/* USB request type for hub class request */
|
/* USB request type for hub class request */
|
||||||
#ifndef HUB_GET_HUB_DESCRIPTOR
|
#ifndef HUB_GET_HUB_DESCRIPTOR
|
||||||
#define HUB_CLEAR_HUB_FEATURE 0x20
|
#define HUB_CLEAR_HUB_FEATURE 0x20
|
||||||
|
@ -207,8 +200,7 @@ Header file for CH554 microcontrollers.
|
||||||
#define USB_IDX_INTERFACE_CDC_CTRL_STR 0x04
|
#define USB_IDX_INTERFACE_CDC_CTRL_STR 0x04
|
||||||
#define USB_IDX_INTERFACE_CDC_DATA_STR 0x05
|
#define USB_IDX_INTERFACE_CDC_DATA_STR 0x05
|
||||||
#define USB_IDX_INTERFACE_FIDO_STR 0x06
|
#define USB_IDX_INTERFACE_FIDO_STR 0x06
|
||||||
#define USB_IDX_INTERFACE_CCID_STR 0x07
|
#define USB_IDX_INTERFACE_DEBUG_STR 0x07
|
||||||
#define USB_IDX_INTERFACE_DEBUG_STR 0x08
|
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
#ifndef USB_DEVICE_ADDR
|
#ifndef USB_DEVICE_ADDR
|
||||||
|
|
|
@ -8,16 +8,14 @@ enum ioend {
|
||||||
IO_NONE = 0x00, // No endpoint
|
IO_NONE = 0x00, // No endpoint
|
||||||
IO_UART = 0x01, // Only destination, raw UART access
|
IO_UART = 0x01, // Only destination, raw UART access
|
||||||
IO_QEMU = 0x02, // Only destination, QEMU debug port
|
IO_QEMU = 0x02, // Only destination, QEMU debug port
|
||||||
IO_CH552 = 0x04, // Internal CH552 control port
|
IO_CH552 = 0x10, // Internal CH552 control port
|
||||||
IO_CDC = 0x08, // CDC "serial" port
|
IO_DEBUG = 0x20, // HID debug port
|
||||||
IO_FIDO = 0x10, // FIDO security token port
|
IO_CDC = 0x40, // CDC "serial port"
|
||||||
IO_CCID = 0x20, // CCID "smart card" port
|
IO_FIDO = 0x80, // FIDO security token port
|
||||||
IO_DEBUG = 0x40, // Debug port over USB HID
|
|
||||||
};
|
};
|
||||||
|
|
||||||
enum ch552cmd {
|
enum ch552cmd {
|
||||||
SET_ENDPOINTS = 0x01, // Config USB endpoints on the CH552
|
SET_ENDPOINTS = 0x01, // Config enabled/disabled USB endpoints on the CH552
|
||||||
CH552_CMD_MAX,
|
|
||||||
};
|
};
|
||||||
|
|
||||||
#endif
|
#endif
|
||||||
|
|
|
@ -6,14 +6,12 @@
|
||||||
|
|
||||||
#include "mem.h"
|
#include "mem.h"
|
||||||
|
|
||||||
unsigned char FLASH ProdDesc[] = { // "Tillitis TKEY-USB-V2"
|
unsigned char FLASH ProdDesc[] = { // "MTA1-USB-V1"
|
||||||
42, // Length of this descriptor (in bytes)
|
24, // Length of this descriptor (in bytes)
|
||||||
0x03, // Descriptor type (String)
|
0x03, // Descriptor type (String)
|
||||||
'T', 0, 'i', 0, 'l', 0, 'l', 0,
|
'M', 0, 'T', 0, 'A', 0, '1', 0,
|
||||||
'i', 0, 't', 0, 'i', 0, 's', 0,
|
'-', 0, 'U', 0, 'S', 0, 'B', 0,
|
||||||
' ', 0, 'T', 0, 'K', 0, 'E', 0,
|
'-', 0, 'V', 0, '1', 0,
|
||||||
'Y', 0, '-', 0, 'U', 0, 'S', 0,
|
|
||||||
'B', 0, '-', 0, 'V', 0, '2', 0,
|
|
||||||
};
|
};
|
||||||
|
|
||||||
unsigned char FLASH ManufDesc[] = { // "Tillitis"
|
unsigned char FLASH ManufDesc[] = { // "Tillitis"
|
||||||
|
@ -57,12 +55,6 @@ unsigned char FLASH FidoInterfaceDesc[] = { // "FIDO"
|
||||||
'F', 0, 'I', 0, 'D', 0, 'O', 0,
|
'F', 0, 'I', 0, 'D', 0, 'O', 0,
|
||||||
};
|
};
|
||||||
|
|
||||||
unsigned char FLASH CcidInterfaceDesc[] = { // "CCID"
|
|
||||||
10, // Length of this descriptor (in bytes)
|
|
||||||
0x03, // Descriptor type (String)
|
|
||||||
'C', 0, 'C', 0, 'I', 0, 'D', 0,
|
|
||||||
};
|
|
||||||
|
|
||||||
unsigned char FLASH DebugInterfaceDesc[] = { // "DEBUG"
|
unsigned char FLASH DebugInterfaceDesc[] = { // "DEBUG"
|
||||||
12, // Length of this descriptor (in bytes)
|
12, // Length of this descriptor (in bytes)
|
||||||
0x03, // Descriptor type (String)
|
0x03, // Descriptor type (String)
|
||||||
|
|
File diff suppressed because it is too large
Load diff
Loading…
Add table
Add a link
Reference in a new issue