diff --git a/.github/workflows/ci.yaml b/.github/workflows/ci.yaml
index 8f44243..875995d 100644
--- a/.github/workflows/ci.yaml
+++ b/.github/workflows/ci.yaml
@@ -31,9 +31,6 @@ jobs:
run: |
make checkfmt
- - name: check for SPDX tags
- run: ./LICENSES/spdx-ensure
-
check-firmware:
runs-on: ubuntu-latest
container:
@@ -151,3 +148,8 @@ jobs:
- name: check matching hashes for firmware.bin & application_fpga.bin
working-directory: hw/application_fpga
run: make check-binary-hashes
+
+
+ # TODO? first deal with hw/boards/ and hw/production_test/
+ # - name: check for SPDX tags
+ # run: ./LICENSES/spdx-ensure
diff --git a/.gitignore b/.gitignore
index cf1c889..c819d02 100644
--- a/.gitignore
+++ b/.gitignore
@@ -28,11 +28,11 @@
/testbench_verilator*
/check.smt2
/check.vcd
-/hw/application_fpga/tkey-libs/libblake2s.a
/hw/application_fpga/tkey-libs/libcommon.a
/hw/application_fpga/tkey-libs/libcrt0.a
/hw/application_fpga/tkey-libs/libmonocypher.a
-/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
synth.json
synth.txt
diff --git a/LICENSES/README.md b/LICENSES/README.md
index 7874a75..8830ede 100644
--- a/LICENSES/README.md
+++ b/LICENSES/README.md
@@ -2,13 +2,11 @@
## Main license
-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 `gpl-2.0.txt`.
+Unless otherwise noted, the project sources are licensed under the
+terms and conditions of the "GNU General Public License v2.0 only".
-This directory contains copies of the license texts used by the
-sources included in the project source tree.
+The `LICENSES/` directory contains copies of the license texts used by
+the sources included in the project source tree.
## SPDX
@@ -21,21 +19,3 @@ The current set of valid, predefined SPDX identifiers can be found on
the SPDX License List at:
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
diff --git a/LICENSES/gpl-2.0.txt b/LICENSES/gpl-2.0.txt
deleted file mode 100644
index 9efa6fb..0000000
--- a/LICENSES/gpl-2.0.txt
+++ /dev/null
@@ -1,338 +0,0 @@
- GNU GENERAL PUBLIC LICENSE
- Version 2, June 1991
-
- Copyright (C) 1989, 1991 Free Software Foundation, Inc.,
-
- 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.
-
-
- Copyright (C)
-
- 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 .
-
-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.
-
- , 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.
diff --git a/LICENSES/gpl-v2.only.txt b/LICENSES/gpl-v2.only.txt
new file mode 100644
index 0000000..708a516
--- /dev/null
+++ b/LICENSES/gpl-v2.only.txt
@@ -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.
diff --git a/LICENSES/spdx-ensure b/LICENSES/spdx-ensure
index 3385211..ece9e26 100755
--- a/LICENSES/spdx-ensure
+++ b/LICENSES/spdx-ensure
@@ -16,73 +16,34 @@ LICENSES/
doc/
hw/application_fpga/core/picorv32/
hw/application_fpga/core/uart/
+hw/application_fpga/fw/tk1/blake2s/
)
missingok_files=(
.editorconfig
.gitattributes
.gitignore
-.clang-format
README.md
contrib/99-tillitis.rules
contrib/Dockerfile
contrib/Makefile
-contrib/verible.sha512
-
-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
+dco.md
hw/application_fpga/application_fpga.bin.sha256
hw/application_fpga/config.vlt
hw/application_fpga/core/timer/README.md
hw/application_fpga/core/tk1/README.md
hw/application_fpga/core/touch_sense/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/uds.hex
hw/application_fpga/firmware.bin.sha512
+hw/application_fpga/fw/.clang-format
hw/application_fpga/fw/testfw/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/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() {
diff --git a/README.md b/README.md
index 11dc8fa..9cd4878 100644
--- a/README.md
+++ b/README.md
@@ -40,17 +40,9 @@ software and hardware should be.
## 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
the projects' licenses.
-Each imported project is typically kept in its own directory with its
-own LICENSE file.
-
## Repositories
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.
-## Building & flashing
+## Building
-These instructions assume you're using a Linux distribution. Most of
-them also assume you're using our OCI image
-[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:
+Building is probably easiest using make and Podman. Do this to see all
+targets:
```
cd contrib
make
```
+Build the entire FPGA bitstream, which includes the firmware, using
+Podman:
+
+```
+cd contrib
+make run-make
+```
+
See the [Tillitis Developer Handbook](https://dev.tillitis.se) for
more.
-### 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
A copy of [tkey-libs](https://github.com/tillitis/tkey-libs) is kept
diff --git a/contrib/Makefile b/contrib/Makefile
index 8c925e1..e37cd4e 100644
--- a/contrib/Makefile
+++ b/contrib/Makefile
@@ -9,19 +9,17 @@ IMAGE=ghcr.io/tillitis/tkey-builder:5rc1
all:
@echo "Targets:"
- @echo "run Run a shell 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-make-no-clean Like run-make but without cleaning first, useful for iterative firmware dev"
- @echo "run-make-ch552-no-clean Like run-make-ch552 but without cleaning first, useful for iterative firmware dev"
- @echo "run-make-clean_fw Like run-make but cleans only firmware"
- @echo "flash Build bitstream and testloadapp.bin then program them and the partition table onto the TKey SPI flash"
- @echo "pull Pull down the image '$(IMAGE)' (Podman)"
- @echo "build-image Build a toolchain image named '$(BUILDIMAGE)' (Podman)"
- @echo " A newly built image can be used like: make IMAGE=$(BUILDIMAGE) run"
- @echo "docker-run Run a shell using image '$(IMAGE)' (Docker)"
- @echo "docker-build-image Build a toolchain image named '$(BUILDIMAGE)' (Docker)"
+ @echo "run Run a shell using image '$(IMAGE)' (Podman)"
+ @echo "run-make Build the FPGA bitstream 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-clean_fw Like run-make but cleans only firmware"
+ @echo "flash Program the SPI flash on the TKey - needs an existing bitstream"
+ @echo "pull Pull down the image '$(IMAGE)' (Podman)"
+ @echo "build-image Build a toolchain image named '$(BUILDIMAGE)' (Podman)"
+ @echo " A newly built image can be used like: make IMAGE=$(BUILDIMAGE) run"
+ @echo "docker-run Run a shell using image '$(IMAGE)' (Docker)"
+ @echo "docker-build-image Build a toolchain image named '$(BUILDIMAGE)' (Docker)"
run:
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 \
$(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:
podman run --rm --mount type=bind,source="`pwd`/../hw/application_fpga",target=/build -w /build -it \
$(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 \
$(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:
podman run --rm --mount type=bind,source="`pwd`/../hw/application_fpga",target=/build -w /build -it \
$(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) }') \
--mount type=bind,source="`pwd`/../hw/application_fpga",target=/build \
-w /build \
- -it $(IMAGE) make prog_flash
+ -it $(IMAGE) tillitis-iceprog /build/application_fpga.bin
pull:
diff --git a/doc/release_notes.md b/doc/release_notes.md
index 66ce98f..e68a258 100644
--- a/doc/release_notes.md
+++ b/doc/release_notes.md
@@ -4,12 +4,8 @@ Descriptions of the tagged TKey releases.
## Upcoming release: Castor
-Overview of changes since [TK1-24.03
-Bellatrix](https://github.com/tillitis/tillitis-key1/releases/tag/TK1-24.03)
-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.
+Overview of changes since TK TK1-24.03 for the Castor milestone so
+far.
**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
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
- 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
- - 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
For full change log [see](https://github.com/tillitis/tillitis-key1/compare/TK1-23.03.2...coming-tag)
### 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 system reset API. Device apps can reset the FPGA and restart
- the firmware.
+- Add system reset API. Device apps can reset the system and restart
+ the firmware. The FPGA is not reset.
- Increase clock frequence to 24 MHz.
- Increase UART baudrate to 500,000.
-- Fix UART baudrate counter issues noticable at higher baudrates.
-
- Fix missing clock cycles in timer core.
- 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
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.
-- Remove MMIO address for access to the firmware blake2s() function
- from apps.
+- Remove support for access to the firmware blake2s() function from
+ apps.
- Automatically leave firmware mode when execution leaves ROM and
remove the now unnecessary APP\_MODE\_CTRL register.
-- Change UDS read protection: When execution leaves ROM the first
- time, UDS is hardware protected from reads. The already existing
- protection that UDS is protected after the first read is also still
- available.
+- Add extra protection of UDS: When execution leaves ROM the first
+ time, UDS is hardware protected from reading, as well as already
+ existing UDS protection after first read and UDS being unreadable in
+ app mode.
-- Introduce interrupt handler for hardware-based privilege raising and
- automatically privelege lowering for system calls.
+- Introduce interrupt handler for hardware-based privilege raising for
+ system calls.
### Firmware
@@ -90,65 +74,27 @@ For full change log [see](https://github.com/tillitis/tillitis-key1/compare/TK1-
by TRNG.
- 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
- apps and four storage areas for device apps.
+- Support a filesystem on flash.
- A typical use is that app slot 0 will contain a loader app for
- verified boot and app slot 1 contains the app to be verified.
-
-- Automatically start an app in flash app slot 0 after power cycle and
- when instructed to by reset intentions.
-
- 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.
+- Add a system call mechanism and system calls: `RESET`, `ALLOC_AREA`,
+ `DEALLOC_AREA`, `WRITE_DATA`, `READ_DATA`, `PRELOAD_DELETE`,
+ `PRELOAD_STORE`, `PRELOAD_STORE_FIN`, `PRELOAD_GET_DIGSIG`,
+ `STATUS`, and `GET_VIDPID`. See [firmware's
+ README](../hw/application_fpga/fw/README.md) for documentation.
- Harmonize with [tkey-libs](https://github.com/tillitis/tkey-libs).
Import tkey-libs to this repo for convenience.
-- Rewrite test firmware to work with the new leaving ROM-scenario.
- 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
+### CH552
- Use the new CTS signals for communication over the UART.
-- Add support for two HID endpoints (security token and our debug
- HID).
+- Add support for two HID endpoints.
-- Add support for CCID endpoint.
-
-- Add a protocol to communicate with the different endpoints: CDC,
- CCID, FIDO, debug.
+- Add protocol to communicate with the three different endpoints: CDC,
+ HID, debug.
- Change USB frame sending from a software timer to instead be
controlled by the USB Controller Protocol.
@@ -156,15 +102,9 @@ Introduce some device apps mostly for testing.
Note that to update the CH552 firmware you will need something like
the Blinkinlabs CH55x Reset Controller:
-
+https://shop-nl.blinkinlabs.com/products/ch55x-reset-controller
-
-
-### 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.
+https://github.com/Blinkinlabs/ch55x_programmer
### tkey-builder
@@ -187,13 +127,10 @@ the Blinkinlabs CH55x Reset Controller:
- libstdc++-arm-none-eabi-newlib
- pico-sdk
- TP1 is now in
+ TP1 is now in https://github.com/tillitis/tp1
- Remove Go compiler support.
-- Introduce buildtools.sh for building upstream tools for inclusion
- in the image.
-
### Docs
- All docs now in READMEs close to the design or code.
@@ -218,7 +155,6 @@ the following digest:
```
### FPGA
-
- Security Monitor now prevents access to RAM outside of the physical
memory. If it detects an access outside of the RAM address space, it
will halt the CPU.
@@ -230,7 +166,6 @@ the following digest:
- Complete testbenches and add 9 tests for the FPGA cores.
### Firmware
-
- Protect zeroisation against compiler optimisation by using
secure_wipe(), fixing a memset() that was removed during
compilation.
@@ -245,35 +180,31 @@ the following digest:
- Fix warnings from splint.
### TP1
-
- New plastic clip o and update of BOM.
- Build TP1 firmware in CI.
### CH552
-
- Fixed a bug where a byte of data could in some rare circumstances be
dropped, causing a client app to hang.
- General clean-up of code, translated all comments to English.
### TK1
-
- New injection moulded plastic case
### tkey-builder
-
- Updated to version 3. Bumping Ubuntu to 23.10, Yosys to 0.36 and
nextpnr to 0.6.
- Updated to version 4. Bumping pico-sdk to 1.5.1, adding clang-tidy
and splint.
### Docs
-
- Fixing broken links, cleaning up docs and READMEs.
- Clarify warm boot attack mitigations and scope for Bellatrix in
threat model.
For full change log [see](https://github.com/tillitis/tillitis-key1/compare/TK1-23.03.2...TK1-24.03)
+
## TK1-23.03.2
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
- 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
the Tillitis TKey device. This version is ready for general
use.
@@ -318,6 +249,7 @@ shasum -a256 application_fpga.bin
f11d6b0f57c5405598206dcfea284008413391a2c51f124a2e2ae8600cb78f0b application_fpga.bin
```
+
### New and improved functionality
- (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
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.
+
### Limitations
- The RAM address and data scrambling in this release is not
cryptographically secure. It his however randomized every time
a TKey device is powered up.
+
## engineering-release-2
### New and improved functionality
diff --git a/doc/toolchain_setup.md b/doc/toolchain_setup.md
new file mode 100644
index 0000000..e0e2454
--- /dev/null
+++ b/doc/toolchain_setup.md
@@ -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)
diff --git a/hw/application_fpga/Makefile b/hw/application_fpga/Makefile
index 35d13ed..e7ab9f4 100644
--- a/hw/application_fpga/Makefile
+++ b/hw/application_fpga/Makefile
@@ -134,7 +134,6 @@ FIRMWARE_OBJS = \
$(P)/fw/tk1/partition_table.o \
$(P)/fw/tk1/auth_app.o \
$(P)/fw/tk1/rng.o \
- $(P)/fw/tk1/reset.o \
$(P)/fw/tk1/preload_app.o \
$(P)/fw/tk1/mgmt_app.o
@@ -185,11 +184,6 @@ LDFLAGS = \
-Wl,--cref,-M \
-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
# https://github.com/tillitis/tkey-libs/
.PHONY: tkey-libs
@@ -211,8 +205,8 @@ qemu_firmware.elf: CFLAGS += -DQEMU_DEBUG
qemu_firmware.elf: ASFLAGS += -DQEMU_DEBUG
qemu_firmware.elf: CFLAGS += -DQEMU_SYSCALL
qemu_firmware.elf: ASFLAGS += -DQEMU_SYSCALL
-qemu_firmware.elf: tkey-libs $(FIRMWARE_OBJS) $(P)/fw/tk1/qemu_firmware.lds
- $(CC) $(CFLAGS) $(FIRMWARE_OBJS) $(QEMU_LDFLAGS) -o $@ > $(basename $@).map
+qemu_firmware.elf: firmware.elf
+ mv firmware.elf qemu_firmware.elf
# Create compile_commands.json for clangd and LSP
.PHONY: clangd
@@ -255,11 +249,11 @@ bram_fw.hex:
$(ICESTORM_PATH)icebram -v -g 32 $(BRAM_FW_SIZE) > $@
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
- python3 $(P)/tools/makehex.py $< $(BRAM_FW_SIZE) > $@
+ python3 $(P)/tools/makehex/makehex.py $< $(BRAM_FW_SIZE) > $@
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
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)
make -C fw/tk1 checkfmt
make -C fw/testfw checkfmt
- make -C apps checkfmt
$(FORMAT) $(CHECK_FORMAT_FLAGS) $^ 2>&1 | \
grep "Needs formatting" && exit 1 || true
.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)
$(NEXTPNR_PATH)nextpnr-ice40 \
-l application_fpga_par.txt \
- --seed 18160564147838858264 \
+ --seed 9416596747216415304 \
--freq $(TARGET_FREQ) \
--ignore-loops \
--up5k \
@@ -472,23 +465,17 @@ tb_application_fpga: $(SIM_VERILOG_SRCS) \
#-------------------------------------------------------------------
prog_flash: check-hardware application_fpga.bin
- tillitis-iceprog application_fpga.bin
- make -C apps
- (cd tools && ./load_preloaded_app.sh 0 ../apps/testloadapp.bin)
+ sudo tillitis-iceprog application_fpga.bin
.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
- tillitis-iceprog application_fpga_testfw.bin
+ sudo tillitis-iceprog application_fpga_testfw.bin
.PHONY: prog_flash_testfw
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; }
- @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
.PHONY: check-hardware
@@ -512,7 +499,6 @@ clean: clean_sim clean_fw clean_tb
rm -f lint_issues.txt
rm -f tools/tpt/*.hex
rm -rf tools/tpt/__pycache__
- make -C apps clean
.PHONY: clean
clean_fw:
@@ -561,8 +547,7 @@ help:
@echo "tb_application_fpga Build testbench simulation for the design"
@echo "lint Run lint on Verilog source files."
@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_bs Program device flash with FGPA bitstream including firmware (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_testfw Program device flash as above, but with testfw."
@echo "clean Delete all generated files."
@echo "clean_fw Delete only generated files for firmware. Useful for fw devs."
diff --git a/hw/application_fpga/README.md b/hw/application_fpga/README.md
index 7a9023a..7abc497 100644
--- a/hw/application_fpga/README.md
+++ b/hw/application_fpga/README.md
@@ -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
firmware mode is the least restrictive.
-The rest of the components are under `cores`, except the firmware,
-which is under `fw/tk1`. They typically have their own `README.md`
-file documenting them and their API in detail.
+The rest of the components are under `cores`. They typically have
+their own `README.md` file documenting them and their API in detail.
Hardware functions with APIs, assets, and input/output are memory
mapped starting at base address `0xc000_0000`. For specific offsets
@@ -39,11 +38,6 @@ Rough memory map:
| Syscall | 0xe1 |
| TK1 | 0xff |
-## Firmware
-
-Firmware is kept in ROM. See the [Firmware implementation
-notes](fw/README.md).
-
## `clk_reset_gen`
Generator for system clock and system reset.
diff --git a/hw/application_fpga/application_fpga.bin.sha256 b/hw/application_fpga/application_fpga.bin.sha256
index 70c38b2..ec93b6a 100644
--- a/hw/application_fpga/application_fpga.bin.sha256
+++ b/hw/application_fpga/application_fpga.bin.sha256
@@ -1 +1 @@
-dfba361c83337c6bac2364d1fd8f115eeb7feeae5faabbdf0713c79b44bbd78d application_fpga.bin
+c770fe25034655241d9e0152b03fcf691c548bc50d30b574a5213abc5b36fe25 application_fpga.bin
diff --git a/hw/application_fpga/apps/Makefile b/hw/application_fpga/apps/Makefile
deleted file mode 100644
index b8ce38c..0000000
--- a/hw/application_fpga/apps/Makefile
+++ /dev/null
@@ -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)
-
diff --git a/hw/application_fpga/apps/README.md b/hw/application_fpga/apps/README.md
deleted file mode 100644
index ca69f88..0000000
--- a/hw/application_fpga/apps/README.md
+++ /dev/null
@@ -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
-```
diff --git a/hw/application_fpga/apps/defaultapp/main.c b/hw/application_fpga/apps/defaultapp/main.c
deleted file mode 100644
index 93dd91a..0000000
--- a/hw/application_fpga/apps/defaultapp/main.c
+++ /dev/null
@@ -1,18 +0,0 @@
-// Copyright (C) 2025 - Tillitis AB
-// SPDX-License-Identifier: GPL-2.0-only
-
-#include
-#include
-#include
-#include
-#include
-
-int main(void)
-{
- struct reset rst = {0};
-
- led_set(LED_BLUE);
-
- rst.type = START_CLIENT;
- syscall(TK1_SYSCALL_RESET, (uint32_t)&rst, 0, 0);
-}
diff --git a/hw/application_fpga/core/tk1/rtl/tk1.v b/hw/application_fpga/core/tk1/rtl/tk1.v
index bcdfc1d..0aba642 100644
--- a/hw/application_fpga/core/tk1/rtl/tk1.v
+++ b/hw/application_fpga/core/tk1/rtl/tk1.v
@@ -101,7 +101,7 @@ module tk1 #(
localparam TK1_NAME0 = 32'h746B3120; // "tk1 "
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_LAST = 32'hd0000fff; // 4 KB
diff --git a/hw/application_fpga/data/udi.hex b/hw/application_fpga/data/udi.hex
index c127fdf..9bc5559 100644
--- a/hw/application_fpga/data/udi.hex
+++ b/hw/application_fpga/data/udi.hex
@@ -1,2 +1,2 @@
-073570c0
+00010203
04050607
diff --git a/hw/application_fpga/firmware.bin.sha512 b/hw/application_fpga/firmware.bin.sha512
index bf75d58..a20a8d6 100644
--- a/hw/application_fpga/firmware.bin.sha512
+++ b/hw/application_fpga/firmware.bin.sha512
@@ -1 +1 @@
-4be2767d5ddd30b5422f4b58075365cb6d988259e88ffa14d6d243560b289f54eaf0c351e9d744cff8ec3a18b1830f3925a86f36bd2096c12eccce25ed44993c firmware.bin
+e72557c38bee1e16114f550b16fc04412bfba09274d7b1fe971ab6b2ef4f06421d976276175ea4df3b7d590599eb052b85a812b689d728be5031ae412b2f8d24 firmware.bin
diff --git a/.clang-format b/hw/application_fpga/fw/.clang-format
similarity index 100%
rename from .clang-format
rename to hw/application_fpga/fw/.clang-format
diff --git a/hw/application_fpga/fw/README.md b/hw/application_fpga/fw/README.md
index 9f5771a..17e9040 100644
--- a/hw/application_fpga/fw/README.md
+++ b/hw/application_fpga/fw/README.md
@@ -65,11 +65,10 @@ The different endpoints:
| *Name* | *Value* | *Comment* |
|--------|---------|----------------------------------------------------------------------|
-| CH552 | 0x04 | USB controller control |
-| CDC | 0x08 | USB CDC-ACM, a serial port on the client. |
-| FIDO | 0x10 | A USB FIDO security token device, useful for FIDO-type applications. |
-| CCID | 0x20 | USB CCID, a port for emulating a smart card |
-| DEBUG | 0x40 | A USB HID special debug pipe. Useful for debug prints. |
+| DEBUG | 0x20 | A USB HID special debug pipe. Useful for debug prints. |
+| CH552 | 0x10 | USB controller control |
+| CDC | 0x40 | USB CDC-ACM, a serial port on the client. |
+| FIDO | 0x80 | A USB FIDO security token device, useful for FIDO-type applications. |
You can turn on and off different endpoints dynamically by sending
commands to the `CH552` control endpoint. When the TKey starts only
@@ -163,7 +162,6 @@ stateDiagram-v2
S0 --> S1
S0 --> S4: Default
S0 --> S3
- S0 --> SE: Unknown reset type
S1 --> S1: Other commands
S1 --> S2: LOAD_APP
@@ -192,8 +190,8 @@ States:
- *LOADING*: Expecting application data from client. Allows only the
command `LOAD_APP_DATA` to continue loading the device app.
- *LOAD_FLASH*: Loading an app from flash. Allows no commands.
-- *LOAD_FLASH_MGMT*: Loading an app from flash and registering it as a
- prospective managment app. Allows no commands.
+- *LOAD_FLASH_MGMT*: Loading and verifyiing a device app from flash.
+ Allows no commands.
- *START*: Computes CDI. Possibly verifies app. Starts the
application. Does not return to firmware. Allows no commands.
- *FAIL* - Halts CPU. Allows no commands.
@@ -208,7 +206,6 @@ Allowed data in state *INITIAL*:
| `FLASH1_VER` | *LOAD_FLASH* |
| `CLIENT` | *WAITCOMMAND* |
| `CLIENT_VER` | *WAITCOMMAND* |
-| unknown | *FAIL* |
I/O in state *LOAD_FLASH*:
@@ -222,16 +219,15 @@ I/O in state *LOAD_FLASH_MGMT*:
|--------------------|--------------|
| Last app data read | *START* |
-Commands in state *WAITCOMMAND*:
+Commands in state `waitcommand`:
-| *command* | *next state* |
-|-----------------------|--------------------------------------------|
-| `FW_CMD_NAME_VERSION` | unchanged |
-| `FW_CMD_GET_UDI` | unchanged |
-| `FW_CMD_LOAD_APP` | *LOADING* or unchanged on invalid app size |
-| | |
+| *command* | *next state* |
+|-----------------------|--------------|
+| `FW_CMD_NAME_VERSION` | unchanged |
+| `FW_CMD_GET_UDI` | unchanged |
+| `FW_CMD_LOAD_APP` | *LOADING* |
-Commands in state *LOADING*:
+Commands in state `loading`:
| *command* | *next state* |
|------------------------|------------------------------------|
@@ -248,23 +244,17 @@ Plain text explanation of the states:
- *INITIAL*: Start here. Check the `FW_RAM` for the `resetinfo` type
for what to do next.
- For type `FLASH0` transition to *LOAD_FLASH_MGMT* because the app in
- slot 0 is considered a special management app. For all other types
- 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.
+ For all types which begins with `FLASH_*`, set next state to
+ *LOAD_FLASH*, otherwise set next state to *WAITCOMMAND*.
- *LOAD_FLASH*: Load device app from flash into RAM, app slot taken
from context. Compute a BLAKE2s digest over the entire app.
Transition to *START*.
- *LOAD_FLASH_MGMT*: Load device app from flash into RAM, app slot
- always 0. Compute a BLAKE2s digest over the entire app. Register the
- app as a prospective management app. Transition to *START*.
+ alway 0. Compute a BLAKE2s digest over the entire app. Register the
+ app as a prospective management app if it later goes through
+ verification. Transition to *START*.
- *WAITCOMMAND*: Wait for commands from the client. Transition to
*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
registered verification digest, verify that the app we are about to
- start is indeed the correct app. This also means that a prospective
- management app is now verified.
+ start is indeed the correct app.
Clean up firmware data structures, enable the system calls, and
start the app, which ends the firmware state machine. Hardware
@@ -299,38 +288,29 @@ state.
### 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.
-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
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
-itself there, and then jumps to `main()`. Also included in the
-assembly part of firmware is an interrupt handler for the system
-calls, but the handler is not yet enabled.
+sets up a stack for itself there, and then jumps to `main()`. Also
+included in the assembly part of firmware is an interrupt handler for
+the system calls, but the handler is not yet enabled.
Beginning at `main()` it fills the entire RAM with pseudo random data
and setting up the RAM address and data hardware scrambling with
values from the True Random Number Generator (TRNG).
-Firmware then proceeds to:
-
-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
+1. Check the special resetinfo area in FW\_RAM for reset type. Type
zero means default behaviour, load from flash app slot 0, expecting
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.
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
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
- `PRELOAD_DELETE`, `PRELOAD_STORE`, `PRELOAD_STORE_FIN`, and
- `PRELOAD_GET_DIGSIG`.
+ digest to `allowed_app_digest` in `mgmt_app.c` to allow it to allow
+ it to use `PRELOAD_DELETE`, `PRELOAD_STORE`, and
+ `PRELOAD_STORE_FIN`.
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.
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
its flash area and doing:
@@ -553,9 +533,8 @@ struct reset {
};
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.
@@ -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
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* |
|--------------------|------------------------------------------------|
@@ -598,15 +577,12 @@ success.
uint32_t offset = 0;
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
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`
```
@@ -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.
-#### `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`
```
@@ -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`
-buffer in flash slot 1 at byte `offset`.
-
-If you can't fit your entire app in the buffer, call `PRELOAD_STORE`
-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.
+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
+binary from the client. Returns 0 on success.
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
the verified management app.
-Compute a BLAKE2s hash digest over the entire binary. Pass the result
-in `app_digest`.
+Compute the `app_digest` with BLAKE2s over the entire binary.
Sign `app_digest` with your Ed25519 private key and pass the
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
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
endpoint instead, define `-DTKEY_DEBUG`. This might mean you can't fit
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
this part.
-If you just want to build and flash the bitstream, the testloadapp in
-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
+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
binary needs to produce the BLAKE2s digest in `allowed_app_digest`
`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`.
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:
@@ -835,5 +768,19 @@ ordinary `application_fpga/Makefile` to be able to fit in ROM.
### 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.
diff --git a/hw/application_fpga/fw/reset_test/Makefile b/hw/application_fpga/fw/reset_test/Makefile
new file mode 100644
index 0000000..4e0986a
--- /dev/null
+++ b/hw/application_fpga/fw/reset_test/Makefile
@@ -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)
diff --git a/hw/application_fpga/fw/reset_test/app.lds b/hw/application_fpga/fw/reset_test/app.lds
new file mode 100644
index 0000000..421122c
--- /dev/null
+++ b/hw/application_fpga/fw/reset_test/app.lds
@@ -0,0 +1,64 @@
+/*
+ * SPDX-FileCopyrightText: 2022 Tillitis AB
+ * 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 */
+}
diff --git a/hw/application_fpga/fw/reset_test/crt0.S b/hw/application_fpga/fw/reset_test/crt0.S
new file mode 100644
index 0000000..f484b7d
--- /dev/null
+++ b/hw/application_fpga/fw/reset_test/crt0.S
@@ -0,0 +1,53 @@
+// SPDX-FileCopyrightText: 2022 Tillitis AB
+// 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
diff --git a/hw/application_fpga/apps/reset_test/main.c b/hw/application_fpga/fw/reset_test/main.c
similarity index 94%
rename from hw/application_fpga/apps/reset_test/main.c
rename to hw/application_fpga/fw/reset_test/main.c
index c3b3998..154e24d 100644
--- a/hw/application_fpga/apps/reset_test/main.c
+++ b/hw/application_fpga/fw/reset_test/main.c
@@ -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
-#include
-#include
#include
-#include
#include
#include
#include
@@ -13,6 +11,11 @@
#include
#include
+#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
static uint8_t hex_char_to_byte(uint8_t c)
{
diff --git a/hw/application_fpga/apps/syscall.S b/hw/application_fpga/fw/reset_test/syscall.S
similarity index 97%
rename from hw/application_fpga/apps/syscall.S
rename to hw/application_fpga/fw/reset_test/syscall.S
index 17712ab..5fc9b3f 100644
--- a/hw/application_fpga/apps/syscall.S
+++ b/hw/application_fpga/fw/reset_test/syscall.S
@@ -1,7 +1,7 @@
// SPDX-FileCopyrightText: 2024 Tillitis AB
// SPDX-License-Identifier: BSD-2-Clause
-#include "../fw/tk1/picorv32/custom_ops.S"
+#include "../tk1/picorv32/custom_ops.S"
.section ".text"
.globl syscall
diff --git a/hw/application_fpga/fw/testapp/Makefile b/hw/application_fpga/fw/testapp/Makefile
new file mode 100644
index 0000000..afc13f8
--- /dev/null
+++ b/hw/application_fpga/fw/testapp/Makefile
@@ -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)
diff --git a/hw/application_fpga/fw/testapp/app.lds b/hw/application_fpga/fw/testapp/app.lds
new file mode 100644
index 0000000..421122c
--- /dev/null
+++ b/hw/application_fpga/fw/testapp/app.lds
@@ -0,0 +1,64 @@
+/*
+ * SPDX-FileCopyrightText: 2022 Tillitis AB
+ * 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 */
+}
diff --git a/hw/application_fpga/fw/testapp/crt0.S b/hw/application_fpga/fw/testapp/crt0.S
new file mode 100644
index 0000000..f484b7d
--- /dev/null
+++ b/hw/application_fpga/fw/testapp/crt0.S
@@ -0,0 +1,53 @@
+// SPDX-FileCopyrightText: 2022 Tillitis AB
+// 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
diff --git a/hw/application_fpga/apps/testapp/main.c b/hw/application_fpga/fw/testapp/main.c
similarity index 84%
rename from hw/application_fpga/apps/testapp/main.c
rename to hw/application_fpga/fw/testapp/main.c
index 6b773d0..f85902b 100644
--- a/hw/application_fpga/apps/testapp/main.c
+++ b/hw/application_fpga/fw/testapp/main.c
@@ -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
-#include
-#include
#include
#include
#include
@@ -11,6 +10,9 @@
#include
#include
+#include "../tk1/proto.h"
+#include "../tk1/resetinfo.h"
+#include "../tk1/syscall_num.h"
#include "syscall.h"
#define USBMODE_PACKET_SIZE 64
@@ -18,7 +20,6 @@
// clang-format off
volatile uint32_t *tk1name0 = (volatile uint32_t *)TK1_MMIO_TK1_NAME0;
volatile uint32_t *tk1name1 = (volatile uint32_t *)TK1_MMIO_TK1_NAME1;
-volatile uint32_t *tk1version = (volatile uint32_t *)TK1_MMIO_TK1_VERSION;
volatile uint32_t *uds = (volatile uint32_t *)TK1_MMIO_UDS_FIRST;
volatile uint32_t *cdi = (volatile uint32_t *)TK1_MMIO_TK1_CDI_FIRST;
volatile uint32_t *udi = (volatile uint32_t *)TK1_MMIO_TK1_UDI_FIRST;
@@ -97,9 +98,6 @@ int main(void)
reverseword(&name);
write(IO_CDC, (const uint8_t *)&name, 4);
puts(IO_CDC, "\r\n");
- puts(IO_CDC, "Version: ");
- putinthex(IO_CDC, *tk1version);
- puts(IO_CDC, "\r\n");
uint32_t zeros[8];
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
int vidpid = syscall(TK1_SYSCALL_GET_VIDPID, 0, 0, 0);
- if (vidpid != 0x073570c0) {
- failmsg("Expected VID/PID to be 0x073570c0");
+ if (vidpid != 0x00010203) {
+ failmsg("Expected VID/PID to be 0x00010203");
anyfailed = 1;
}
@@ -147,7 +145,7 @@ int main(void)
}
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};
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, "\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...");
if (syscall(TK1_SYSCALL_DEALLOC_AREA, 0, 0, 0) != 0) {
@@ -214,8 +190,8 @@ int main(void)
}
puts(IO_CDC, "\r\nTesting timer... 3");
- // Matching clock at 24 MHz, giving us timer in seconds
- *timer_prescaler = 24 * 1000000;
+ // Matching clock at 21 MHz, giving us timer in seconds
+ *timer_prescaler = 21 * 1000000;
// Test timer expiration after 1s
*timer = 1;
diff --git a/hw/application_fpga/fw/testapp/syscall.S b/hw/application_fpga/fw/testapp/syscall.S
new file mode 100644
index 0000000..5fc9b3f
--- /dev/null
+++ b/hw/application_fpga/fw/testapp/syscall.S
@@ -0,0 +1,85 @@
+// SPDX-FileCopyrightText: 2024 Tillitis AB
+// 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
diff --git a/hw/application_fpga/apps/include/syscall.h b/hw/application_fpga/fw/testapp/syscall.h
similarity index 100%
rename from hw/application_fpga/apps/include/syscall.h
rename to hw/application_fpga/fw/testapp/syscall.h
diff --git a/hw/application_fpga/fw/testfw/main.c b/hw/application_fpga/fw/testfw/main.c
index 656a266..2051cd2 100644
--- a/hw/application_fpga/fw/testfw/main.c
+++ b/hw/application_fpga/fw/testfw/main.c
@@ -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
#include
diff --git a/hw/application_fpga/fw/testfw/start.S b/hw/application_fpga/fw/testfw/start.S
index 26d6186..6ed1408 100644
--- a/hw/application_fpga/fw/testfw/start.S
+++ b/hw/application_fpga/fw/testfw/start.S
@@ -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"
.globl _start
@@ -36,7 +38,7 @@ _start:
li x30,0
li x31,0
- // Clear all RAM
+ /* Clear all RAM */
li a0, 0x40000000 // TK1_RAM_BASE
li a1, 0x40020000 // TK1_RAM_BASE + TK1_RAM_SIZE
clear:
@@ -44,9 +46,9 @@ clear:
addi a0, a0, 4
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
call main
diff --git a/hw/application_fpga/fw/testloadapp/Makefile b/hw/application_fpga/fw/testloadapp/Makefile
new file mode 100644
index 0000000..785ab37
--- /dev/null
+++ b/hw/application_fpga/fw/testloadapp/Makefile
@@ -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)
diff --git a/hw/application_fpga/apps/testloadapp/blink.h b/hw/application_fpga/fw/testloadapp/blink.h
similarity index 95%
rename from hw/application_fpga/apps/testloadapp/blink.h
rename to hw/application_fpga/fw/testloadapp/blink.h
index 9aeb21f..a597e50 100644
--- a/hw/application_fpga/apps/testloadapp/blink.h
+++ b/hw/application_fpga/fw/testloadapp/blink.h
@@ -1,6 +1,3 @@
-// Copyright (C) 2025 - Tillitis AB
-// SPDX-License-Identifier: GPL-2.0-only
-
#ifndef BLINK_APP_H
#define BLINK_APP_H
diff --git a/hw/application_fpga/apps/testloadapp/main.c b/hw/application_fpga/fw/testloadapp/main.c
similarity index 91%
rename from hw/application_fpga/apps/testloadapp/main.c
rename to hw/application_fpga/fw/testloadapp/main.c
index 98300ac..dbd704c 100644
--- a/hw/application_fpga/apps/testloadapp/main.c
+++ b/hw/application_fpga/fw/testloadapp/main.c
@@ -1,19 +1,15 @@
-// Copyright (C) 2025 - Tillitis AB
-// SPDX-License-Identifier: GPL-2.0-only
-
#include
-#include
-#include
#include
#include
-#include
#include
-#include
#include
#include
+#include "../testapp/syscall.h"
+#include "../tk1/resetinfo.h"
+#include "../tk1/syscall_num.h"
#include "blink.h"
-#include "syscall.h"
+#include "tkey/assert.h"
// clang-format off
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;
- // Give the next in chain something to look at.
- memset(rst.next_app_data, 17, sizeof(rst.next_app_data));
-
- syscall(TK1_SYSCALL_RESET, (uint32_t)&rst, sizeof(rst.next_app_data),
- 0);
+ syscall(TK1_SYSCALL_RESET, (uint32_t)&rst, 0, 0);
}
int main(void)
@@ -169,8 +161,6 @@ int main(void)
uint8_t available;
uint8_t in = 0;
- led_set(LED_BLUE);
-
// Generate a key pair from CDI
crypto_ed25519_key_pair(secret_key, pubkey, (uint8_t *)cdi);
diff --git a/hw/application_fpga/fw/tk1/auth_app.c b/hw/application_fpga/fw/tk1/auth_app.c
index d9175e1..1fdc8ab 100644
--- a/hw/application_fpga/fw/tk1/auth_app.c
+++ b/hw/application_fpga/fw/tk1/auth_app.c
@@ -14,8 +14,8 @@
static volatile uint32_t *cdi = (volatile uint32_t *)TK1_MMIO_TK1_CDI_FIRST;
-// Calculates the authentication digest based on a supplied nonce and
-// the CDI. Requires that the CDI is already calculated and stored
+/* Calculates the authentication digest based on a supplied nonce and the CDI.
+ * Requires that the CDI is already calculated and stored */
static void calculate_auth_digest(uint8_t *nonce, uint8_t *auth_digest)
{
assert(nonce != NULL);
@@ -31,7 +31,7 @@ static void calculate_auth_digest(uint8_t *nonce, uint8_t *auth_digest)
blake2s_final(&ctx, auth_digest);
}
-// Generates a 16 byte nonce
+/* Generates a 16 byte nonce */
static void generate_nonce(uint32_t *nonce)
{
assert(nonce != NULL);
@@ -41,9 +41,8 @@ static void generate_nonce(uint32_t *nonce)
}
return;
}
-
-// Returns the authentication digest and random nonce. Requires that
-// the CDI is already calculated and stored
+/* Returns the authentication digest and random nonce. Requires that the CDI is
+ * already calculated and stored */
void auth_app_create(struct auth_metadata *auth_table)
{
assert(auth_table != NULL);
diff --git a/hw/application_fpga/fw/tk1/flash.c b/hw/application_fpga/fw/tk1/flash.c
index 5c0d374..d6d0c87 100644
--- a/hw/application_fpga/fw/tk1/flash.c
+++ b/hw/application_fpga/fw/tk1/flash.c
@@ -10,12 +10,36 @@
#include "flash.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
static bool flash_is_busy(void);
static void flash_wait_busy(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)
{
uint8_t tx_buf = READ_STATUS_REG_1;
@@ -34,8 +58,9 @@ static bool flash_is_busy(void)
// Blocking until !busy
static void flash_wait_busy(void)
{
- while (flash_is_busy())
- ;
+ while (flash_is_busy()) {
+ delay(10);
+ }
}
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;
}
- if (size <= 0) {
- return -1;
- }
-
- if (address % 256 != 0) {
+ if (size <= 0 || size > 4096) {
return -1;
}
@@ -188,12 +209,6 @@ int flash_write_data(uint32_t address, uint8_t *data, size_t size)
uint8_t *p_data = data;
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] = {
PAGE_PROGRAM, /* tx_buf[0] */
(address >> ADDR_BYTE_3_BIT) & 0xFF, /* tx_buf[1] */
diff --git a/hw/application_fpga/fw/tk1/main.c b/hw/application_fpga/fw/tk1/main.c
index 658d3ef..d190446 100644
--- a/hw/application_fpga/fw/tk1/main.c
+++ b/hw/application_fpga/fw/tk1/main.c
@@ -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
#include
@@ -15,7 +17,7 @@
#include "partition_table.h"
#include "preload_app.h"
#include "proto.h"
-#include "reset.h"
+#include "resetinfo.h"
#include "state.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 *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 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
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;
- led_set(LED_BLACK);
-
state = FW_STATE_LOADING;
break;
}
@@ -444,19 +444,7 @@ static enum state start_where(struct context *ctx)
{
assert(ctx != NULL);
- debug_puts("resetinfo->type: ");
- 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?
+ // Where do we start? Read resetinfo 'startfrom'
switch (resetinfo->type) {
case START_DEFAULT:
// fallthrough
@@ -508,6 +496,8 @@ int main(void)
uint8_t cmd[CMDSIZE] = {0};
enum state state = FW_STATE_INITIAL;
+ led_set(LED_BLUE);
+
print_hw_version();
/*@-mustfreeonly@*/
@@ -521,17 +511,10 @@ int main(void)
scramble_ram();
if (part_table_read(&part_table_storage) != 0) {
- // Couldn't read partition table
- debug_puts("Couldn't read partition table\n");
+ // Couldn't read or create partition table
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)
run(&ctx);
#endif
@@ -584,7 +567,6 @@ int main(void)
if (mgmt_app_init(ctx.digest) != 0) {
state = FW_STATE_FAIL;
- break;
}
state = FW_STATE_START;
@@ -622,7 +604,7 @@ int main(void)
}
/*@ -compdestroy @*/
- // We don't care about memory leaks here.
+ /* We don't care about memory leaks here. */
return (int)0xcafebabe;
}
diff --git a/hw/application_fpga/fw/tk1/mgmt_app.c b/hw/application_fpga/fw/tk1/mgmt_app.c
index 83b8433..4632aa9 100644
--- a/hw/application_fpga/fw/tk1/mgmt_app.c
+++ b/hw/application_fpga/fw/tk1/mgmt_app.c
@@ -11,14 +11,11 @@
// Lock down what app can start from flash slot 0.
//
// To update this, compute the BLAKE2s digest of the app.bin
-// clang-format off
static const uint8_t allowed_app_digest[32] = {
- 0x85, 0x29, 0xe3, 0x25, 0xf5, 0x8d, 0x53, 0x5f,
- 0xe1, 0x2a, 0x77, 0x92, 0xe7, 0xdc, 0x4b, 0x4d,
- 0x01, 0x85, 0x17, 0xca, 0xfd, 0x54, 0x83, 0xb3,
- 0xbb, 0x28, 0x4f, 0xa1, 0x98, 0x5f, 0x9e, 0x56,
+ 0xb6, 0x86, 0x1b, 0x26, 0xef, 0x69, 0x77, 0x12, 0xed, 0x6c, 0xca,
+ 0xe8, 0x35, 0xb4, 0x5c, 0x01, 0x07, 0x71, 0xab, 0xce, 0x3f, 0x30,
+ 0x79, 0xda, 0xe6, 0xf9, 0xee, 0x4b, 0xe2, 0x06, 0x95, 0x33,
};
-// clang-format on
static uint8_t current_app_digest[32];
@@ -34,7 +31,7 @@ int mgmt_app_init(uint8_t app_digest[32])
return 0;
}
-// Authenticate an management app
+/* Authenticate an management app */
bool mgmt_app_authenticate(void)
{
return memeq(current_app_digest, allowed_app_digest, 32) != 0;
diff --git a/hw/application_fpga/fw/tk1/partition_table.c b/hw/application_fpga/fw/tk1/partition_table.c
index 110719a..a75b2d9 100644
--- a/hw/application_fpga/fw/tk1/partition_table.c
+++ b/hw/application_fpga/fw/tk1/partition_table.c
@@ -17,20 +17,22 @@ enum part_status part_get_status(void)
return part_status;
}
-static void part_checksum(struct partition_table *part_table,
- uint8_t *out_digest, size_t out_len);
+static void part_digest(struct partition_table *part_table, uint8_t *out_digest,
+ size_t out_len);
-// part_digest computes a checksum over the partition table to detect
-// flash problems
-static void part_checksum(struct partition_table *part_table,
- uint8_t *out_digest, size_t out_len)
+static void part_digest(struct partition_table *part_table, uint8_t *out_digest,
+ size_t out_len)
{
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(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));
assert(blake2err == 0);
@@ -48,7 +50,7 @@ int part_table_read(struct partition_table_storage *storage)
ADDR_PARTITION_TABLE_0,
ADDR_PARTITION_TABLE_1,
};
- uint8_t check_digest[PART_CHECKSUM_SIZE] = {0};
+ uint8_t check_digest[PART_DIGEST_SIZE] = {0};
if (storage == NULL) {
return -1;
@@ -62,10 +64,10 @@ int part_table_read(struct partition_table_storage *storage)
sizeof(*storage)) != 0) {
return -1;
}
- part_checksum(&storage->table, check_digest,
- sizeof(check_digest));
+ part_digest(&storage->table, check_digest,
+ sizeof(check_digest));
- if (memeq(check_digest, storage->checksum,
+ if (memeq(check_digest, storage->check_digest,
sizeof(check_digest))) {
if (i == 1) {
part_status = PART_SLOT0_INVALID;
@@ -89,8 +91,8 @@ int part_table_write(struct partition_table_storage *storage)
return -1;
}
- part_checksum(&storage->table, storage->checksum,
- sizeof(storage->checksum));
+ part_digest(&storage->table, storage->check_digest,
+ sizeof(storage->check_digest));
for (int i = 0; i < 2; i++) {
flash_sector_erase(offset[i]);
diff --git a/hw/application_fpga/fw/tk1/partition_table.h b/hw/application_fpga/fw/tk1/partition_table.h
index 097942e..dd4fa84 100644
--- a/hw/application_fpga/fw/tk1/partition_table.h
+++ b/hw/application_fpga/fw/tk1/partition_table.h
@@ -6,25 +6,25 @@
#include
-// ---- Flash ---- ----
-// name size start addr
-// ---- ---- ----
-// bitstream 128KiB 0x00
-// ---- ---- ----
-// Partition 64KiB 0x20000
-// ---- ---- ----
-// Pre load 1 128KiB 0x30000
-// Pre load 2 128KiB 0x50000
-// ---- ---- ----
-// storage 1 128KiB 0x70000
-// storage 2 128KiB 0x90000
-// storage 3 128KiB 0xB0000
-// storage 4 128KiB 0xD0000
-// ---- ---- ----
-// Partition2 64KiB 0xf0000
+/* ---- Flash ---- ---- */
+/* name size start addr */
+/* ---- ---- ---- */
+/* bitstream 128KiB 0x00 */
+/* ---- ---- ---- */
+/* Partition 64KiB 0x20000 */
+/* ---- ---- ---- */
+/* Pre load 1 128KiB 0x30000 */
+/* Pre load 2 128KiB 0x50000 */
+/* ---- ---- ---- */
+/* storage 1 128KiB 0x70000 */
+/* storage 2 128KiB 0x90000 */
+/* storage 3 128KiB 0xB0000 */
+/* storage 4 128KiB 0xD0000 */
+/* ---- ---- ---- */
+/* Partition2 64KiB 0xf0000 */
-// To simplify all blocks are aligned with the 64KiB blocks on the
-// W25Q80DL flash.
+/* To simplify all blocks are aligned with the 64KiB blocks on the W25Q80DL
+ * flash. */
#define PART_TABLE_VERSION 1
@@ -46,33 +46,30 @@
#define SIZE_STORAGE_AREA 0x20000UL // 128KiB
#define N_STORAGE_AREA 4
-#define PART_CHECKSUM_SIZE 32
+#define PART_DIGEST_SIZE 16
enum part_status {
PART_SLOT0_INVALID = 1,
};
-// Partition Table
-// ----------------------------------------------------------------------
-// - Table header
-// - 1 bytes Version
-//
-// - Pre-loaded device app 1
-// - 4 bytes length.
-// - 32 bytes digest.
-// - 64 bytes signature.
-//
-// - Pre-loaded device app 2
-// - 4 bytes length.
-// - 32 bytes digest.
-// - 64 bytes signature.
-//
-// - Device app storage area
-// - 1 byte status.
-// - 16 bytes random nonce.
-// - 16 bytes authentication tag.
-//
-// - Checksum over the above
+/* Partition Table */
+/*- Table header */
+/* - 1 bytes Version */
+/**/
+/*- Pre-loaded device app 1 */
+/* - 4 bytes length. */
+/* - 32 bytes digest. */
+/* - 64 bytes signature. */
+/**/
+/*- Pre-loaded device app 2 */
+/* - 4 bytes length. */
+/* - 32 bytes digest. */
+/* - 64 bytes signature. */
+/**/
+/*- Device app storage area */
+/* - 1 byte status. */
+/* - 16 bytes random nonce. */
+/* - 16 bytes authentication tag. */
struct auth_metadata {
uint8_t nonce[16];
@@ -102,7 +99,7 @@ struct partition_table {
struct partition_table_storage {
struct partition_table table;
- uint8_t checksum[PART_CHECKSUM_SIZE]; // Helps detect flash problems
+ uint8_t check_digest[PART_DIGEST_SIZE];
} __attribute__((packed));
enum part_status part_get_status(void);
diff --git a/hw/application_fpga/fw/tk1/picorv32/README.md b/hw/application_fpga/fw/tk1/picorv32/README.md
index 07077ff..761be04 100644
--- a/hw/application_fpga/fw/tk1/picorv32/README.md
+++ b/hw/application_fpga/fw/tk1/picorv32/README.md
@@ -2,11 +2,6 @@
## custom_ops.S
-We have imported the custom Custom PicoRV32 instructions in
-`custom_ops.S` from https://github.com/YosysHQ/picorv32/ tag v1.0,
-commit 6d145b708d5dfa4caa3445bc599927cebc3291d8.
-
-Upstream path is `picorv32/firmware/custom_ops.S`.
-
-The picorv32 firmware is public domain, which we chose to mark as
-CC0-1.0.
+Custom PicoRV32 instructions are located in `custom_ops.S`.
+`custom_ops.S` is imported from upstream PicoRV32 commit:
+YosysHQ/picorv32@70f3c33
diff --git a/hw/application_fpga/fw/tk1/picorv32/custom_ops.S b/hw/application_fpga/fw/tk1/picorv32/custom_ops.S
index af380a6..71889b9 100644
--- a/hw/application_fpga/fw/tk1/picorv32/custom_ops.S
+++ b/hw/application_fpga/fw/tk1/picorv32/custom_ops.S
@@ -1,6 +1,3 @@
-// SPDX-FileCopyrightText: Claire Xenia Wolf
-// SPDX-License-Identifier: CC0-1.0
-
// This is free and unencumbered software released into the public domain.
//
// Anyone is free to copy, modify, publish, use, compile, sell, or
diff --git a/hw/application_fpga/fw/tk1/preload_app.c b/hw/application_fpga/fw/tk1/preload_app.c
index 971077d..499bbe5 100644
--- a/hw/application_fpga/fw/tk1/preload_app.c
+++ b/hw/application_fpga/fw/tk1/preload_app.c
@@ -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;
}
-// 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)
{
if (part_table == NULL) {
- return -1;
+ return -5;
}
if (from_slot >= N_PRELOADED_APP) {
- return -1;
+ return -4;
}
- // Check for a valid app in flash
- if (part_table->pre_app_data[from_slot].size == 0 &&
- part_table->pre_app_data[from_slot].size <= TK1_APP_MAX_SIZE) {
+ /*Check for a valid app in flash */
+ if (part_table->pre_app_data[from_slot].size == 0) {
return -1;
}
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,
part_table->pre_app_data[from_slot].size);
return ret;
}
-// preload_store stores chunks of an app in app slot to_slot. data is a buffer
-// of size size to be written at byte offset in the slot. offset needs to be
-// kept and updated between each call. offset must be a multiple of 256.
-//
-// When all data has been written call preload_store_finalize() with the last
-// parameters.
-//
-// Returns 0 on success.
+/* Expects to receive chunks of data up to 4096 bytes to store into the
+ * preloaded area. The offset needs to be kept and updated between each call.
+ * Once done, call preload_store_finalize() with the last parameters.
+ * */
int preload_store(struct partition_table *part_table, uint32_t offset,
uint8_t *data, size_t size, uint8_t to_slot)
{
if (part_table == NULL || data == NULL) {
- return -1;
+ return -5;
}
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()) {
- return -1;
+ return -3;
}
- // Check for a valid app in flash, bale out if it already
- // exists
+ /* Check for a valid app in flash, bale out if it already exists */
if (part_table->pre_app_data[to_slot].size != 0) {
return -1;
}
- if (offset > SIZE_PRE_LOADED_APP) {
- return -1;
- }
-
- if (size > SIZE_PRE_LOADED_APP) {
- return -1;
- }
-
- if ((offset + size) > SIZE_PRE_LOADED_APP) {
- // Writing outside of area
- return -1;
+ if ((offset + size) > SIZE_PRE_LOADED_APP || size > 4096) {
+ /* Writing outside of area */
+ return -2;
}
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;
- if (part_table == NULL) {
- return -1;
- }
-
- // 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 (part_table == NULL || app_digest == NULL || app_signature == NULL) {
+ return -5;
}
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()) {
- return -1;
+ return -3;
}
- // Check for a valid app in flash, bale out if it already
- // exists
+ /* Check for a valid app in flash, bale out if it already exists */
if (part_table->pre_app_data[to_slot].size != 0) {
return -1;
}
if (app_size == 0 || app_size > SIZE_PRE_LOADED_APP) {
- return -1;
+ return -2;
}
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();
if (part_table_write(part_table_storage) != 0) {
- return -1;
+ return -6;
}
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;
if (part_table_storage == NULL) {
- return -1;
+ return -5;
}
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()) {
- 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) {
// Nothing to do.
return 0;
@@ -186,10 +160,10 @@ int preload_delete(struct partition_table_storage *part_table_storage,
sizeof(part_table->pre_app_data[slot].signature));
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(
slot_to_start_address(slot)); // Erase first 64 KB block
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)
{
if (part_table == NULL || app_digest == NULL || app_signature == NULL) {
- return -1;
+ return -5;
}
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()) {
- return -1;
+ return -3;
}
memcpy_s(app_digest, 32, part_table->pre_app_data[slot].digest,
diff --git a/hw/application_fpga/fw/tk1/proto.c b/hw/application_fpga/fw/tk1/proto.c
index 4ddf1c4..22affee 100644
--- a/hw/application_fpga/fw/tk1/proto.c
+++ b/hw/application_fpga/fw/tk1/proto.c
@@ -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
#include
diff --git a/hw/application_fpga/fw/tk1/proto.h b/hw/application_fpga/fw/tk1/proto.h
index 3a0d8ce..0c4ebda 100644
--- a/hw/application_fpga/fw/tk1/proto.h
+++ b/hw/application_fpga/fw/tk1/proto.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
#include
diff --git a/hw/application_fpga/fw/tk1/qemu_firmware.lds b/hw/application_fpga/fw/tk1/qemu_firmware.lds
deleted file mode 100644
index 73a63f5..0000000
--- a/hw/application_fpga/fw/tk1/qemu_firmware.lds
+++ /dev/null
@@ -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);
diff --git a/hw/application_fpga/fw/tk1/reset.c b/hw/application_fpga/fw/tk1/reset.c
deleted file mode 100644
index 93a1fb4..0000000
--- a/hw/application_fpga/fw/tk1/reset.c
+++ /dev/null
@@ -1,59 +0,0 @@
-// Copyright (C) 2025 - Tillitis AB
-// SPDX-License-Identifier: GPL-2.0-only
-
-#include
-#include
-#include
-#include
-
-#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;
-}
diff --git a/hw/application_fpga/fw/tk1/reset.h b/hw/application_fpga/fw/tk1/resetinfo.h
similarity index 55%
rename from hw/application_fpga/fw/tk1/reset.h
rename to hw/application_fpga/fw/tk1/resetinfo.h
index f763d89..0a26ace 100644
--- a/hw/application_fpga/fw/tk1/reset.h
+++ b/hw/application_fpga/fw/tk1/resetinfo.h
@@ -1,16 +1,13 @@
// Copyright (C) 2025 - Tillitis AB
// SPDX-License-Identifier: GPL-2.0-only
-#ifndef TKEY_RESET_H
-#define TKEY_RESET_H
+#ifndef TKEY_RESETINFO_H
+#define TKEY_RESETINFO_H
-#include
#include
#define TK1_MMIO_RESETINFO_BASE 0xd0000f00
#define TK1_MMIO_RESETINFO_SIZE 0x100
-#define RESET_DIGEST_SIZE 32
-#define RESET_DATA_SIZE 220
enum reset_start {
START_DEFAULT = 0, // Probably cold boot
@@ -23,11 +20,9 @@ enum reset_start {
};
struct reset {
- enum reset_start type;
- uint8_t app_digest[RESET_DIGEST_SIZE];
- uint8_t next_app_data[RESET_DATA_SIZE];
+ uint32_t type; // Reset type
+ uint8_t app_digest[32]; // Program digest
+ 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
diff --git a/hw/application_fpga/fw/tk1/rng.c b/hw/application_fpga/fw/tk1/rng.c
index 242679f..258b327 100644
--- a/hw/application_fpga/fw/tk1/rng.c
+++ b/hw/application_fpga/fw/tk1/rng.c
@@ -10,7 +10,8 @@
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;
// clang-format on
-
+//
+//
uint32_t rng_get_word(void)
{
while ((*trng_status & (1 << TK1_MMIO_TRNG_STATUS_READY_BIT)) == 0) {
diff --git a/hw/application_fpga/fw/tk1/spi.c b/hw/application_fpga/fw/tk1/spi.c
index 815039d..b2cd3bd 100644
--- a/hw/application_fpga/fw/tk1/spi.c
+++ b/hw/application_fpga/fw/tk1/spi.c
@@ -20,7 +20,7 @@ static void spi_disable(void);
static void spi_write(uint8_t *cmd, 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
// in the hardware.
static int spi_ready(void)
diff --git a/hw/application_fpga/fw/tk1/start.S b/hw/application_fpga/fw/tk1/start.S
index d0be087..f947e1e 100644
--- a/hw/application_fpga/fw/tk1/start.S
+++ b/hw/application_fpga/fw/tk1/start.S
@@ -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
@@ -26,7 +28,9 @@
_start:
j init
-// IRQ handler
+/*
+ * IRQ handler
+*/
.=0x10
irq_handler:
// PicoRV32 stores the IRQ bitmask in x4.
@@ -108,8 +112,9 @@ x3_valid:
picorv32_retirq_insn() // Return from interrupt
-// Init
-
+/*
+ * Init
+*/
.=0x100
init:
li x1, 0
@@ -144,7 +149,7 @@ init:
li x30,0
li x31,0
- // Clear FW_RAM
+ /* Clear FW_RAM */
la a0, _sfwram
la a1, _efwram
clear:
@@ -152,7 +157,7 @@ clear:
addi a0, a0, 4
blt a0, a1, clear
- // Zero-init bss section
+ /* Zero-init bss section */
la a0, _sbss
la a1, _ebss
@@ -161,7 +166,7 @@ loop_init_bss:
addi a0, a0, 4
blt a0, a1, loop_init_bss
- // Init stack
+ /* Init stack */
la sp, _estack
call main
diff --git a/hw/application_fpga/fw/tk1/state.h b/hw/application_fpga/fw/tk1/state.h
index 5df5385..fd085dd 100644
--- a/hw/application_fpga/fw/tk1/state.h
+++ b/hw/application_fpga/fw/tk1/state.h
@@ -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
#define STATE_H
diff --git a/hw/application_fpga/fw/tk1/storage.c b/hw/application_fpga/fw/tk1/storage.c
index 1ba1f28..a8f5c4e 100644
--- a/hw/application_fpga/fw/tk1/storage.c
+++ b/hw/application_fpga/fw/tk1/storage.c
@@ -6,20 +6,18 @@
#include
#include
#include
-#include
#include "auth_app.h"
#include "flash.h"
#include "partition_table.h"
#include "storage.h"
-// Returns the index of the first empty area.
-//
-// Returns -1 on errors.
+/* Returns the index of the first empty area. If there is no empty area -1 is
+ * returned. */
static int get_first_empty(struct partition_table *part_table)
{
if (part_table == NULL) {
- return -1;
+ return -4;
}
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 -1;
}
static int index_to_address(int index, uint32_t *address)
{
if (address == NULL) {
- return -1;
+ return -4;
}
if ((index < 0) || (index >= N_STORAGE_AREA)) {
@@ -46,13 +43,12 @@ static int index_to_address(int index, uint32_t *address)
return 0;
}
-// Returns the index of the area an app has allocated.
-//
-// Returns -1 on errors.
+/* Returns the index of the area an app has allocated. If no area is
+ * authenticated -1 is returned. */
static int storage_get_area(struct partition_table *part_table)
{
if (part_table == NULL) {
- return -1;
+ return -4;
}
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;
}
-// 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)
{
if (part_table_storage == NULL) {
- return -1;
+ return -4;
}
struct partition_table *part_table = &part_table_storage->table;
if (storage_get_area(part_table) != -1) {
/* Already has an area */
- return 0;
+ return 1;
}
int index = get_first_empty(part_table);
- if (index < 0) {
+ if (index == -1) {
/* No empty slot */
return -1;
}
uint32_t start_address = 0;
-
- if (index_to_address(index, &start_address) != 0) {
- return -1;
+ int err = index_to_address(index, &start_address);
+ if (err) {
+ return -3;
}
- // Allocate the empty index found
- // Erase area first
+ /* Allocate the empty index found */
+ /* 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 +
0x10000); // Erase second 64 KB block
- // Write partition table lastly
+ /* Write partition table lastly */
part_table->app_storage[index].status = 0x01;
auth_app_create(&part_table->app_storage[index].auth);
if (part_table_write(part_table_storage) != 0) {
- return -1;
+ return -5;
}
return 0;
}
-// Dealloacate a previously allocated storage area.
-//
-// Returns zero on success, and non-zero on errors.
+/* Dealloacate a previously allocated storage area. Returns zero on success, and
+ * non-zero on errors. */
int storage_deallocate_area(struct partition_table_storage *part_table_storage)
{
if (part_table_storage == NULL) {
- return -1;
+ return -4;
}
struct partition_table *part_table = &part_table_storage->table;
int index = storage_get_area(part_table);
- if (index < 0) {
- // No area to deallocate
+ if (index == -1) {
+ /* No area to deallocate */
return -1;
}
uint32_t start_address = 0;
- if (index_to_address(index, &start_address) != 0) {
- return -1;
+ int err = index_to_address(index, &start_address);
+ 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 +
0x10000); // Erase second 64 KB block
- // Clear partition table lastly
+ /* Clear partition table lastly */
part_table->app_storage[index].status = 0;
(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));
if (part_table_write(part_table_storage) != 0) {
- return -1;
+ return -5;
}
return 0;
}
-// Erases sector. Offset of a sector to begin erasing, must be a
-// multiple of the sector size. Size to erase in bytes, must be a
-// multiple of the sector size.
-//
-// Returns zero on success, negative error code on failure
+/* Erases sector. Offset of a sector to begin erasing, must be a multiple of
+ * the sector size. Size to erase in bytes, must be a multiple of the sector *
+ * size. Returns zero on success, negative error code on failure */
int storage_erase_sector(struct partition_table *part_table, uint32_t offset,
size_t size)
{
if (part_table == NULL) {
- return -1;
+ return -4;
}
int index = storage_get_area(part_table);
if (index == -1) {
- // No allocated area
+ /* No allocated area */
return -1;
}
uint32_t start_address = 0;
- if (index_to_address(index, &start_address) != 0) {
- return -1;
+ int err = index_to_address(index, &start_address);
+ if (err) {
+ return -3;
}
- if (offset > SIZE_STORAGE_AREA) {
- return -1;
- }
-
- // Cannot only erase entire sectors
+ /* Cannot only erase entire sectors */
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) {
- return -1;
+ return -2;
}
- if ((offset + size) > SIZE_STORAGE_AREA) {
- return -1;
+ if ((offset + size) >= SIZE_STORAGE_AREA) {
+ return -2;
}
uint32_t address = start_address + offset;
@@ -213,45 +204,32 @@ int storage_erase_sector(struct partition_table *part_table, uint32_t offset,
return 0;
}
-// Writes the specified data to the offset inside of the allocated area.
-// Assumes area has been erased before hand. Offset must be a multiple of 256.
-//
-// Returns zero on success.
+/* Writes the specified data to the offset inside of the
+ * 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. */
int storage_write_data(struct partition_table *part_table, uint32_t offset,
uint8_t *data, size_t size)
{
- if (part_table == NULL) {
- return -1;
- }
-
- // 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;
+ if (part_table == NULL || data == NULL) {
+ return -4;
}
int index = storage_get_area(part_table);
if (index == -1) {
- // No allocated area
+ /* No allocated area */
return -1;
}
uint32_t start_address = 0;
- if (index_to_address(index, &start_address) != 0) {
- return -1;
+ int err = index_to_address(index, &start_address);
+ if (err) {
+ return -3;
}
- if (offset > SIZE_STORAGE_AREA) {
- return -1;
- }
-
- if (size > SIZE_STORAGE_AREA) {
- return -1;
- }
-
- if ((offset + size) > SIZE_STORAGE_AREA) {
- // Writing outside of area
- return -1;
+ if ((offset + size) > SIZE_STORAGE_AREA || size > 4096) {
+ /* Writing outside of area */
+ return -2;
}
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);
}
-// Reads size bytes of data at the specified offset inside of the
-// allocated area.
-//
-// Only read limit is the size of the allocated area.
-//
-// Returns zero on success.
+/* Reads size bytes of data at the specified offset inside of
+ * the allocated area. Returns zero on success. Only read limit
+ * is the size of the allocated area */
int storage_read_data(struct partition_table *part_table, uint32_t offset,
uint8_t *data, size_t size)
{
- if (part_table == NULL) {
- return -1;
- }
-
- // 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;
+ if (part_table == NULL || data == NULL) {
+ return -4;
}
int index = storage_get_area(part_table);
if (index == -1) {
- // No allocated area
+ /* No allocated area */
return -1;
}
uint32_t start_address = 0;
-
- if (index_to_address(index, &start_address) != 0) {
- return -1;
- }
-
- if (offset > SIZE_STORAGE_AREA) {
- return -1;
- }
-
- if (size > 4096) {
- return -1;
+ int err = index_to_address(index, &start_address);
+ if (err) {
+ return -3;
}
if ((offset + size) > SIZE_STORAGE_AREA) {
- // Reading outside of area
- return -1;
+ /* Reading outside of area */
+ return -2;
}
uint32_t address = start_address + offset;
diff --git a/hw/application_fpga/fw/tk1/syscall_enable.S b/hw/application_fpga/fw/tk1/syscall_enable.S
index 88b6b0f..2060ddb 100644
--- a/hw/application_fpga/fw/tk1/syscall_enable.S
+++ b/hw/application_fpga/fw/tk1/syscall_enable.S
@@ -1,6 +1,3 @@
-// SPDX-FileCopyrightText: 2025 Tillitis AB
-// SPDX-License-Identifier: GPL-2.0-only
-
#ifdef QEMU_SYSCALL
#define picorv32_maskirq_insn(...)
@@ -16,7 +13,7 @@
syscall_enable:
- // Enable syscall IRQ
+ /* Enable syscall IRQ */
li t0, 0x7fffffff // IRQ31 mask
picorv32_maskirq_insn(zero, t0) // Enable IRQs
diff --git a/hw/application_fpga/fw/tk1/syscall_handler.c b/hw/application_fpga/fw/tk1/syscall_handler.c
index e916e21..7a24021 100644
--- a/hw/application_fpga/fw/tk1/syscall_handler.c
+++ b/hw/application_fpga/fw/tk1/syscall_handler.c
@@ -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
#include
@@ -9,12 +11,15 @@
#include "partition_table.h"
#include "preload_app.h"
-#include "reset.h"
#include "storage.h"
-#include "syscall_num.h"
+
+#include "../tk1/resetinfo.h"
+#include "../tk1/syscall_num.h"
// clang-format off
+static volatile uint32_t *system_reset = (volatile uint32_t *)TK1_MMIO_TK1_SYSTEM_RESET;
static volatile uint32_t *udi = (volatile uint32_t *)TK1_MMIO_TK1_UDI_FIRST;
+static volatile struct reset *resetinfo = (volatile struct reset *)TK1_MMIO_RESETINFO_BASE;
// clang-format on
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,
uint32_t arg3)
{
+ struct reset *userreset = (struct reset *)arg1;
+
switch (number) {
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;
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");
return -1;
}
- return 0;
+ return 0;
case TK1_SYSCALL_DEALLOC_AREA:
if (storage_deallocate_area(&part_table_storage) < 0) {
debug_puts("couldn't deallocate storage area\n");
return -1;
}
- return 0;
+ return 0;
case TK1_SYSCALL_WRITE_DATA:
if (storage_write_data(&part_table_storage.table, arg1,
(uint8_t *)arg2, arg3) < 0) {
debug_puts("couldn't write storage area\n");
return -1;
}
- return 0;
+ return 0;
case TK1_SYSCALL_READ_DATA:
if (storage_read_data(&part_table_storage.table, arg1,
(uint8_t *)arg2, arg3) < 0) {
debug_puts("couldn't read storage area\n");
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;
-
case TK1_SYSCALL_GET_VIDPID:
// UDI is 2 words: VID/PID & serial. Return just the
// 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:
return part_get_status();
- case TK1_SYSCALL_GET_APP_DATA:
- // arg1 next_app_data
- return reset_data((uint8_t *)arg1);
-
default:
assert(1 == 2);
}
diff --git a/hw/application_fpga/fw/tk1/syscall_num.h b/hw/application_fpga/fw/tk1/syscall_num.h
index 14109a0..f7255d6 100644
--- a/hw/application_fpga/fw/tk1/syscall_num.h
+++ b/hw/application_fpga/fw/tk1/syscall_num.h
@@ -18,7 +18,6 @@ enum syscall_num {
TK1_SYSCALL_PRELOAD_GET_DIGSIG = 11,
TK1_SYSCALL_REG_MGMT = 12,
TK1_SYSCALL_STATUS = 13,
- TK1_SYSCALL_GET_APP_DATA = 14,
};
#endif
diff --git a/hw/application_fpga/tkey-libs/RELEASE.md b/hw/application_fpga/tkey-libs/RELEASE.md
index 347e2dc..3e63be6 100644
--- a/hw/application_fpga/tkey-libs/RELEASE.md
+++ b/hw/application_fpga/tkey-libs/RELEASE.md
@@ -32,7 +32,6 @@ The Castor TKey hardware supports more USB endpoints:
- CDC - the same thing as older versions.
- FIDO security token, for FIDO-like apps.
-- CCID, smart card interface.
- DEBUG, a HID debug port.
The communication is still over a single UART. To differ between the
diff --git a/hw/application_fpga/tkey-libs/include/tkey/io.h b/hw/application_fpga/tkey-libs/include/tkey/io.h
index 60c5f60..4c2cff1 100644
--- a/hw/application_fpga/tkey-libs/include/tkey/io.h
+++ b/hw/application_fpga/tkey-libs/include/tkey/io.h
@@ -10,22 +10,20 @@
// I/O endpoints. Keep it as bits possible to use in a bitmask in
// readselect().
//
-// Note that the values for IO_CH552, IO_CDC, IO_FIDO, IO_CCID and IO_DEBUG
-// should be kept the same in the code for the CH552 side.
+// Note that the DEBUG, CDC, and FIDO should be kept the same on
+// the CH552 side.
enum ioend {
IO_NONE = 0x00, // No endpoint
IO_UART = 0x01, // Only destination, raw UART access
IO_QEMU = 0x02, // Only destination, QEMU debug port
- IO_CH552 = 0x04, // Internal CH552 control port
- IO_CDC = 0x08, // CDC "serial" port
- IO_FIDO = 0x10, // FIDO security token port
- IO_CCID = 0x20, // CCID "smart card" port
- IO_DEBUG = 0x40, // Debug port over USB HID
+ IO_CH552 = 0x10, // Internal CH552 control port
+ IO_DEBUG = 0x20, // HID debug port
+ IO_CDC = 0x40, // CDC "serial port"
+ IO_FIDO = 0x80, // FIDO security token port
};
enum ch552cmd {
SET_ENDPOINTS = 0x01, // Config USB endpoints on the CH552
- CH552_CMD_MAX,
};
void write(enum ioend dest, const uint8_t *buf, size_t nbytes);
diff --git a/hw/application_fpga/tkey-libs/libcommon/io.c b/hw/application_fpga/tkey-libs/libcommon/io.c
index 03d67a1..737b340 100644
--- a/hw/application_fpga/tkey-libs/libcommon/io.c
+++ b/hw/application_fpga/tkey-libs/libcommon/io.c
@@ -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
// is either:
//
-// - IO_UART: Low-level UART access, no USB Mode Header added.
-//
// - IO_QEMU: QEMU debug port
//
-// - IO_CH552: Internal communication between the FPGA and the
-// CH552, with header.
+// - IO_UART: Low-level UART access, no USB Mode Header added.
//
// - IO_CDC: Through the UART for the CDC endpoint, with header.
//
// - IO_FIDO: Through the UART for the FIDO endpoint, with header.
//
-// - IO_CCID: Through the UART for the CCID endpoint, with header.
-//
-// - IO_DEBUG: Through the UART for the DEBUG endpoint (USB HID), with
+// - IO_DEBUG: Through the UART for the DEBUG HID endpoint, with
// header.
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:
//
-// - IO_CH552
+// - IO_DEBUG
// - IO_CDC
// - IO_FIDO
-// - IO_CCID
-// - IO_DEBUG
//
// 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
//
// Allowed options are:
-// - IO_FIDO (can't be used used together with IO_CCID)
-// - IO_CCID (can't be used used together with IO_FIDO)
+// - IO_FIDO
// - IO_DEBUG
//
// The following are always enabled:
diff --git a/hw/application_fpga/tools/README.md b/hw/application_fpga/tools/README.md
deleted file mode 100644
index d419260..0000000
--- a/hw/application_fpga/tools/README.md
+++ /dev/null
@@ -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.
diff --git a/hw/application_fpga/tools/b2s/b2s.go b/hw/application_fpga/tools/b2s/b2s.go
index bfd9afe..7b73672 100644
--- a/hw/application_fpga/tools/b2s/b2s.go
+++ b/hw/application_fpga/tools/b2s/b2s.go
@@ -20,7 +20,7 @@ func printCDigest(digest [blake2s.Size]byte, fileName string) {
fmt.Printf("const uint8_t digest[32] = {\n")
for _, n := range digest {
- fmt.Printf("0x%02x, ", n)
+ fmt.Printf("0x%x, ", n)
}
fmt.Printf("\n}; \n")
diff --git a/hw/application_fpga/tools/create_flash_image.py b/hw/application_fpga/tools/create_flash_image.py
new file mode 100755
index 0000000..d82bfff
--- /dev/null
+++ b/hw/application_fpga/tools/create_flash_image.py
@@ -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)
diff --git a/hw/application_fpga/tools/default_partition.bin b/hw/application_fpga/tools/default_partition.bin
index 38fa3af..271bf5c 100644
Binary files a/hw/application_fpga/tools/default_partition.bin and b/hw/application_fpga/tools/default_partition.bin differ
diff --git a/hw/application_fpga/tools/load_preloaded_app.sh b/hw/application_fpga/tools/load_preloaded_app.sh
index 23186a5..28f3b24 100755
--- a/hw/application_fpga/tools/load_preloaded_app.sh
+++ b/hw/application_fpga/tools/load_preloaded_app.sh
@@ -1,7 +1,5 @@
#!/bin/bash -e
-# SPDX-FileCopyrightText: 2025 Tillitis AB
-# SPDX-License-Identifier: GPL-2.0-only
if [ $# != 2 ]
then
echo "Usage: $0 slot_num app_file"
diff --git a/hw/application_fpga/tools/makehex.py b/hw/application_fpga/tools/makehex/makehex.py
similarity index 86%
rename from hw/application_fpga/tools/makehex.py
rename to hw/application_fpga/tools/makehex/makehex.py
index a8b4d50..7f6cb71 100755
--- a/hw/application_fpga/tools/makehex.py
+++ b/hw/application_fpga/tools/makehex/makehex.py
@@ -1,8 +1,5 @@
#!/usr/bin/env python3
#
-# SPDX-FileCopyrightText: Claire Xenia Wolf
-# SPDX-License-Identifier: CC0-1.0
-
# This is free and unencumbered software released into the public domain.
#
# Anyone is free to copy, modify, publish, use, compile, sell, or
diff --git a/hw/application_fpga/tools/tkeyimage/go.mod b/hw/application_fpga/tools/partition_table/go.mod
similarity index 80%
rename from hw/application_fpga/tools/tkeyimage/go.mod
rename to hw/application_fpga/tools/partition_table/go.mod
index 6ede5b7..f14a95d 100644
--- a/hw/application_fpga/tools/tkeyimage/go.mod
+++ b/hw/application_fpga/tools/partition_table/go.mod
@@ -1,4 +1,4 @@
-module tkeyimage
+module partition_table
go 1.23.0
diff --git a/hw/application_fpga/tools/tkeyimage/go.sum b/hw/application_fpga/tools/partition_table/go.sum
similarity index 100%
rename from hw/application_fpga/tools/tkeyimage/go.sum
rename to hw/application_fpga/tools/partition_table/go.sum
diff --git a/hw/application_fpga/tools/partition_table/partition_table.go b/hw/application_fpga/tools/partition_table/partition_table.go
new file mode 100644
index 0000000..f7774a6
--- /dev/null
+++ b/hw/application_fpga/tools/partition_table/partition_table.go
@@ -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)
+ }
+}
diff --git a/hw/application_fpga/tools/reset-tk1 b/hw/application_fpga/tools/reset-tk1
new file mode 100755
index 0000000..839290f
--- /dev/null
+++ b/hw/application_fpga/tools/reset-tk1
@@ -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
diff --git a/hw/application_fpga/tools/run_pnr.sh b/hw/application_fpga/tools/run_pnr.sh
index 21a5cb1..68f9e70 100755
--- a/hw/application_fpga/tools/run_pnr.sh
+++ b/hw/application_fpga/tools/run_pnr.sh
@@ -1,8 +1,5 @@
#!/bin/bash
-# SPDX-FileCopyrightText: 2025 Tillitis AB
-# SPDX-License-Identifier: GPL-2.0-only
-
help() {
echo "Usage: $(basename $0) [OPTION]"
echo "Run multiple place and route threads with nextpnr-ice40"
diff --git a/hw/application_fpga/tools/tkeyimage/README.md b/hw/application_fpga/tools/tkeyimage/README.md
deleted file mode 100644
index 3c4e417..0000000
--- a/hw/application_fpga/tools/tkeyimage/README.md
+++ /dev/null
@@ -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
-```
diff --git a/hw/application_fpga/tools/tkeyimage/tkeyimage.go b/hw/application_fpga/tools/tkeyimage/tkeyimage.go
deleted file mode 100644
index d411c5d..0000000
--- a/hw/application_fpga/tools/tkeyimage/tkeyimage.go
+++ /dev/null
@@ -1,266 +0,0 @@
-// SPDX-FileCopyrightText: 2025 Tillitis AB
-// 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)
- }
- }
-}
diff --git a/hw/application_fpga/tools/tpt/__init__.py b/hw/application_fpga/tools/tpt/__init__.py
new file mode 100644
index 0000000..e69de29
diff --git a/hw/usb_interface/ch552_fw/encode_usb_strings.py b/hw/usb_interface/ch552_fw/encode_usb_strings.py
index cc263e7..08a86dd 100755
--- a/hw/usb_interface/ch552_fw/encode_usb_strings.py
+++ b/hw/usb_interface/ch552_fw/encode_usb_strings.py
@@ -51,20 +51,16 @@ def format_descriptor(name, value):
if __name__ == "__main__":
strings = {
- "ProdDesc": "Tillitis TKEY-USB-V2",
+ "ProdDesc": "MTA1-USB-V1",
"ManufDesc": "Tillitis",
"SerialDesc": "68de5d27-e223-4874-bc76-a54d6e84068f",
"CdcCtrlInterfaceDesc": "CDC-Ctrl",
"CdcDataInterfaceDesc": "CDC-Data",
"FidoInterfaceDesc": "FIDO",
- "CcidInterfaceDesc": "CCID",
"DebugInterfaceDesc": "DEBUG"
}
with open('inc/usb_strings.h', 'w') as f:
- f.write('// SPDX-FileCopyrightText: 2024 Tillitis AB \n')
- f.write('// SPDX-License-Identifier: MIT\n')
- f.write('\n')
f.write('#ifndef __USB_STRINGS_H__\n')
f.write('#define __USB_STRINGS_H__\n')
f.write('\n')
diff --git a/hw/usb_interface/ch552_fw/inc/ch554_usb.h b/hw/usb_interface/ch552_fw/inc/ch554_usb.h
index 2277adc..723b5b5 100644
--- a/hw/usb_interface/ch552_fw/inc/ch554_usb.h
+++ b/hw/usb_interface/ch552_fw/inc/ch554_usb.h
@@ -94,13 +94,6 @@ Header file for CH554 microcontrollers.
#define USB_CDC_REQ_TYPE_SET_CONTROL_LINE_STATE 0x22
#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 */
#ifndef HUB_GET_HUB_DESCRIPTOR
#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_DATA_STR 0x05
#define USB_IDX_INTERFACE_FIDO_STR 0x06
-#define USB_IDX_INTERFACE_CCID_STR 0x07
-#define USB_IDX_INTERFACE_DEBUG_STR 0x08
+#define USB_IDX_INTERFACE_DEBUG_STR 0x07
#endif
#ifndef USB_DEVICE_ADDR
diff --git a/hw/usb_interface/ch552_fw/inc/io.h b/hw/usb_interface/ch552_fw/inc/io.h
index 3856c6d..614c5ef 100644
--- a/hw/usb_interface/ch552_fw/inc/io.h
+++ b/hw/usb_interface/ch552_fw/inc/io.h
@@ -8,16 +8,14 @@ enum ioend {
IO_NONE = 0x00, // No endpoint
IO_UART = 0x01, // Only destination, raw UART access
IO_QEMU = 0x02, // Only destination, QEMU debug port
- IO_CH552 = 0x04, // Internal CH552 control port
- IO_CDC = 0x08, // CDC "serial" port
- IO_FIDO = 0x10, // FIDO security token port
- IO_CCID = 0x20, // CCID "smart card" port
- IO_DEBUG = 0x40, // Debug port over USB HID
+ IO_CH552 = 0x10, // Internal CH552 control port
+ IO_DEBUG = 0x20, // HID debug port
+ IO_CDC = 0x40, // CDC "serial port"
+ IO_FIDO = 0x80, // FIDO security token port
};
enum ch552cmd {
- SET_ENDPOINTS = 0x01, // Config USB endpoints on the CH552
- CH552_CMD_MAX,
+ SET_ENDPOINTS = 0x01, // Config enabled/disabled USB endpoints on the CH552
};
#endif
diff --git a/hw/usb_interface/ch552_fw/inc/usb_strings.h b/hw/usb_interface/ch552_fw/inc/usb_strings.h
index d697d4b..2c2b9b8 100644
--- a/hw/usb_interface/ch552_fw/inc/usb_strings.h
+++ b/hw/usb_interface/ch552_fw/inc/usb_strings.h
@@ -6,14 +6,12 @@
#include "mem.h"
-unsigned char FLASH ProdDesc[] = { // "Tillitis TKEY-USB-V2"
- 42, // Length of this descriptor (in bytes)
+unsigned char FLASH ProdDesc[] = { // "MTA1-USB-V1"
+ 24, // Length of this descriptor (in bytes)
0x03, // Descriptor type (String)
- 'T', 0, 'i', 0, 'l', 0, 'l', 0,
- 'i', 0, 't', 0, 'i', 0, 's', 0,
- ' ', 0, 'T', 0, 'K', 0, 'E', 0,
- 'Y', 0, '-', 0, 'U', 0, 'S', 0,
- 'B', 0, '-', 0, 'V', 0, '2', 0,
+ 'M', 0, 'T', 0, 'A', 0, '1', 0,
+ '-', 0, 'U', 0, 'S', 0, 'B', 0,
+ '-', 0, 'V', 0, '1', 0,
};
unsigned char FLASH ManufDesc[] = { // "Tillitis"
@@ -57,12 +55,6 @@ unsigned char FLASH FidoInterfaceDesc[] = { // "FIDO"
'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"
12, // Length of this descriptor (in bytes)
0x03, // Descriptor type (String)
diff --git a/hw/usb_interface/ch552_fw/src/main.c b/hw/usb_interface/ch552_fw/src/main.c
index 35c98d7..e45e19e 100644
--- a/hw/usb_interface/ch552_fw/src/main.c
+++ b/hw/usb_interface/ch552_fw/src/main.c
@@ -55,12 +55,6 @@ const uint8_t *pDescr = NULL; // USB configuration flag
#define FIDO_EPIN_ADDR 0x83 // FIDO Endpoint IN Address
#define FIDO_EPIN_SIZE MAX_PACKET_SIZE // FIDO Endpoint IN Size
-#define CCID_BULK_EPOUT_ADDR 0x03 // CCID Bulk Endpoint OUT Address
-#define CCID_BULK_EPOUT_SIZE MAX_PACKET_SIZE // CCID Bulk Endpoint OUT Size
-
-#define CCID_BULK_EPIN_ADDR 0x83 // CCID Bulk Endpoint IN Address
-#define CCID_BULK_EPIN_SIZE MAX_PACKET_SIZE // CCID Bulk Endpoint IN Size
-
#define DEBUG_EPOUT_ADDR 0x04 // DEBUG Endpoint OUT Address
#define DEBUG_EPOUT_SIZE MAX_PACKET_SIZE // DEBUG Endpoint OUT Size
@@ -70,47 +64,21 @@ const uint8_t *pDescr = NULL; // USB configuration flag
#define CDC_CTRL_FS_BINTERVAL 32 // Gives 32 ms polling interval at Full Speed for interrupt transfers
#define CDC_DATA_FS_BINTERVAL 0 // bInterval is ignored for BULK transfers
#define FIDO_FS_BINTERVAL 2 // Gives 2 ms polling interval at Full Speed for interrupt transfers
-#define CCID_BULK_FS_BINTERVAL 0 // bInterval is ignored for BULK transfers
#define DEBUG_FS_BINTERVAL 2 // Gives 2 ms polling interval at Full Speed for interrupt transfers
-#define MAX_CFG_DESC_SIZE (9+66+77+32) // Size of CfgDesc+CdcDesc+MAX(FidoDesc,CcidDesc)+DebugDesc
-
+#define CFG_DESC_SIZE 139U // Size of Cfg_Desc
#define NUM_INTERFACES 4 // Number of interfaces
-#define CHANGE_ME 0x00 // Value placeholder
-
#define FIDO_REPORT_DESC_SIZE 47 // Size of FidoReportDesc
#define DEBUG_REPORT_DESC_SIZE 34 // Size of DebugReportDesc
-#define CCID_VALUE_BCDCCID 0x0110
-#define CCID_VALUE_DWPROTOCOLS 0x00000002
-#define CCID_VALUE_DWDEFAULTCLOCK 3580
-#define CCID_VALUE_DWMAXIUMUMCLOCK 3580
-#define CCID_VALUE_DWDATARATE 9600
-#define CCID_VALUE_DWMAXDATARATE 9600
-#define CCID_VALUE_DWMAXIFSD 254
-#define CCID_VALUE_DWSYNCPROTOCOLS 0x0
-#define CCID_VALUE_DWMECHANICAL 0x0
-#define CCID_VALUE_DWFEATURES 0x000400FE
-#define CCID_VALUE_DWMAXCCIDMESSAGELENGTH 3072
-#define CCID_VALUE_WLCDLAYOUT 0x0
-
-#define MIN(a, b) (((a) < (b)) ? (a) : (b))
-#define MAX(a, b) (((a) > (b)) ? (a) : (b))
-
-#define LOBYTE(x) ((uint8_t)( (x) & 0x00FFU))
-#define HIBYTE(x) ((uint8_t)(((x) >> 8U) & 0x00FFU))
-
-#define BYTE0(x) ((uint8_t)( (x) & 0x000000FFU)) // Least significant byte
-#define BYTE1(x) ((uint8_t)(((x) >> 8) & 0x000000FFU)) // Second byte
-#define BYTE2(x) ((uint8_t)(((x) >> 16) & 0x000000FFU)) // Third byte
-#define BYTE3(x) ((uint8_t)(((x) >> 24) & 0x000000FFU)) // Most significant byte
+#define LOBYTE(x) ((uint8_t)( (x) & 0x00FFU))
+#define HIBYTE(x) ((uint8_t)(((x) & 0xFF00U) >> 8U))
IDATA uint8_t FidoInterfaceNum = 0;
-IDATA uint8_t CcidInterfaceNum = 0;
IDATA uint8_t DebugInterfaceNum = 0;
-XDATA uint8_t ActiveCfgDesc[MAX_CFG_DESC_SIZE];
+XDATA uint8_t ActiveCfgDesc[CFG_DESC_SIZE];
XDATA uint8_t ActiveCfgDescSize = 0;
// Device Descriptor
@@ -123,9 +91,9 @@ FLASH uint8_t DevDesc[] = {
0x02, /* bDeviceSubClass: Common Class */
0x01, /* bDeviceProtocol: IAD (Interface Association Descriptor) */
DEFAULT_EP0_SIZE, /* bMaxPacketSize */
- 0x09, /* idVendor */ // VID LOBYTE
+ 0x07, /* idVendor */ // VID LOBYTE
0x12, /* idVendor */ // VID HIBYTE
- 0x85, /* idProduct */ // PID LOBYTE
+ 0x87, /* idProduct */ // PID LOBYTE
0x88, /* idProduct */ // PID HIBYTE
0x00, /* bcdDevice (device release number in binary-coded decimal (BCD) format, low byte, i.e. YY) rel. XX.YY */
0x01, /* bcdDevice (device release number in binary-coded decimal (BCD) format, high byte, i.e. XX) rel. XX.YY */
@@ -133,7 +101,6 @@ FLASH uint8_t DevDesc[] = {
USB_IDX_PRODUCT_STR, /* Index of product string */
USB_IDX_SERIAL_STR, /* Index of serial number string */
0x01, /* bNumConfigurations */
- /* 18 */
};
// Configuration Descriptor
@@ -141,9 +108,9 @@ FLASH uint8_t CfgDesc[] = {
/******************** Configuration Descriptor ********************/
0x09, /* bLength: Configuration Descriptor size */
USB_DESC_TYPE_CONFIGURATION, /* bDescriptorType: Configuration */
- CHANGE_ME, /* wTotalLength (low byte): Bytes returned */
+ CFG_DESC_SIZE, /* wTotalLength (low byte): Bytes returned */
0x00, /* wTotalLength (high byte): Bytes returned */
- CHANGE_ME, /* bNumInterfaces: 1 CDC Ctrl + 1 CDC Data, 1 FIDO or 1 CCID, 1 DEBUG ) */
+ NUM_INTERFACES, /* bNumInterfaces: 4 interfaces (1 CDC Ctrl, 1 CDC Data, 1 FIDO, 1 DEBUG ) */
0x01, /* bConfigurationValue: Configuration value */
0x00, /* iConfiguration: Index of string descriptor describing the configuration */
0xA0, /* bmAttributes: Bus powered and Support Remote Wake-up */
@@ -159,17 +126,17 @@ FLASH uint8_t CdcDesc[] = {
USB_DESC_TYPE_INTERFACE_ASSOCIATION, /* bDescriptorType: Interface Association */
0x00, /* bFirstInterface: 0 */
0x02, /* bInterfaceCount: 2 */
- USB_DEV_CLASS_CDC_CONTROL, /* bFunctionClass: Communications & CDC Control */
+ 0x02, /* bFunctionClass: Communications & CDC Control */
0x02, /* bFunctionSubClass: Abstract Control Model */
0x01, /* bFunctionProtocol: Common AT commands */
0x00, /* iFunction: Index of string descriptor */
- /******************** Interface, CDC Ctrl Descriptor (one endpoint) ********************/
+ /******************** Interface 0, CDC Ctrl Descriptor (one endpoint) ********************/
/* 8 */
0x09, /* bLength: Interface Descriptor size */
USB_DESC_TYPE_INTERFACE, /* bDescriptorType: Interface */
- CHANGE_ME, /* bInterfaceNumber: Number of Interface */
+ 0x00, /* bInterfaceNumber: Number of Interface */
0x00, /* bAlternateSetting: Alternate setting */
- 0x01, /* bNumEndpoints: Number of endpoints in Interface */
+ 0x01, /* bNumEndpoints */
USB_DEV_CLASS_CDC_CONTROL, /* bInterfaceClass: Communications and CDC Control */
0x02, /* bInterfaceSubClass : Abstract Control Model */
0x01, /* bInterfaceProtocol : AT Commands: V.250 etc */
@@ -177,14 +144,14 @@ FLASH uint8_t CdcDesc[] = {
/******************** Header Functional Descriptor ********************/
/* 17 */
0x05, /* bFunctionLength: Size of this descriptor in bytes */
- USB_DESC_TYPE_CS_INTERFACE, /* bDescriptorType: Class-Specific Interface */
+ USB_DESC_TYPE_CS_INTERFACE, /* bDescriptorType: CS_INTERFACE (24h) */
0x00, /* bDescriptorSubtype: Header Functional Descriptor */
0x10, /* bcdCDC (low byte): CDC version 1.10 */
0x01, /* bcdCDC (high byte): CDC version 1.10 */
/******************** Call Management Functional Descriptor (no data interface, bmCapabilities=03, bDataInterface=01) ********************/
/* 22 */
0x05, /* bFunctionLength: Size of this descriptor */
- USB_DESC_TYPE_CS_INTERFACE, /* bDescriptorType: Class-Specific Interface */
+ USB_DESC_TYPE_CS_INTERFACE, /* bDescriptorType: CS_INTERFACE (24h) */
0x01, /* bDescriptorSubtype: Call Management Functional Descriptor */
0x00, /* bmCapabilities:
D7..2: 0x00 (RESERVED,
@@ -196,7 +163,7 @@ FLASH uint8_t CdcDesc[] = {
/******************** Abstract Control Management Functional Descriptor ********************/
/* 27 */
0x04, /* bLength */
- USB_DESC_TYPE_CS_INTERFACE, /* bDescriptorType: Class-Specific Interface */
+ 0x24, /* bDescriptorType: CS_INTERFACE (24h) */
0x02, /* bDescriptorSubtype: Abstract Control Management Functional Descriptor */
0x02, /* bmCapabilities:
D7..4: 0x00 (RESERVED, Reset to zero)
@@ -207,7 +174,7 @@ FLASH uint8_t CdcDesc[] = {
/******************** Union Functional Descriptor. CDC Ctrl interface numbered 0; CDC Data interface numbered 1 ********************/
/* 31 */
0x05, /* bLength */
- USB_DESC_TYPE_CS_INTERFACE, /* bDescriptorType: Class-Specific Interface */
+ 0x24, /* bDescriptorType: CS_INTERFACE (24h) */
0x06, /* bDescriptorSubtype: Union Functional Descriptor */
0x00, /* bControlInterface: Interface number 0 (Control interface) */
0x01, /* bSubordinateInterface0: Interface number 1 (Data interface) */
@@ -220,13 +187,13 @@ FLASH uint8_t CdcDesc[] = {
LOBYTE(CDC_CTRL_EPIN_SIZE), /* wMaxPacketSize (low byte): 8 Byte max */
HIBYTE(CDC_CTRL_EPIN_SIZE), /* wMaxPacketSize (high byte): 8 Byte max */
CDC_CTRL_FS_BINTERVAL, /* bInterval: Polling Interval */
- /******************** Interface, CDC Data Descriptor (two endpoints) ********************/
+ /******************** Interface 1, CDC Data Descriptor (two endpoints) ********************/
/* 43 */
0x09, /* bLength: Interface Descriptor size */
USB_DESC_TYPE_INTERFACE, /* bDescriptorType: Interface */
- CHANGE_ME, /* bInterfaceNumber: Number of Interface */
+ 0x01, /* bInterfaceNumber: Number of Interface */
0x00, /* bAlternateSetting: Alternate setting */
- 0x02, /* bNumEndpoints: Number of endpoints in Interface */
+ 0x02, /* bNumEndpoints */
USB_DEV_CLASS_CDC_DATA, /* bInterfaceClass: CDC Data */
0x00, /* bInterfaceSubClass : 1=BOOT, 0=no boot */
0x00, /* bInterfaceProtocol : 0=none, 1=keyboard, 2=mouse */
@@ -254,12 +221,12 @@ FLASH uint8_t CdcDesc[] = {
// FIDO Descriptor
FLASH uint8_t FidoDesc[] = {
- /******************** Interface, FIDO Descriptor (two endpoints) ********************/
+ /******************** Interface 2, FIDO Descriptor (two endpoints) ********************/
0x09, /* bLength: Interface Descriptor size */
USB_DESC_TYPE_INTERFACE, /* bDescriptorType: Interface */
- CHANGE_ME, /* bInterfaceNumber: Number of Interface */
+ 0x02, /* bInterfaceNumber: Number of Interface */
0x00, /* bAlternateSetting: Alternate setting */
- 0x02, /* bNumEndpoints: Number of endpoints in Interface */
+ 0x02, /* bNumEndpoints: 2 */
USB_DEV_CLASS_HID, /* bInterfaceClass: Human Interface Device */
0x00, /* bInterfaceSubClass : 1=BOOT, 0=no boot */
0x00, /* bInterfaceProtocol : 0=none, 1=keyboard, 2=mouse */
@@ -296,207 +263,14 @@ FLASH uint8_t FidoDesc[] = {
/* 32 */
};
-// CCID Descriptor
-FLASH uint8_t CcidDesc[] = {
- /******************** Interface, CCID Descriptor (two endpoints) ********************/
- 0x09, /* bLength: Interface Descriptor size */
- USB_DESC_TYPE_INTERFACE, /* bDescriptorType: Interface */
- CHANGE_ME, /* bInterfaceNumber: Number of Interface */
- 0x00, /* bAlternateSetting: Alternate setting */
- 0x02, /* bNumEndpoints: Number of endpoints in Interface */
- USB_DEV_CLASS_SMART_CARD, /* bInterfaceClass: Smart Card */
- 0x00, /* bInterfaceSubClass : Subclass code */
- 0x00, /* bInterfaceProtocol : For Integrated Circuit(s) Cards Interface Devices (CCID): 00h
- Note: For competitiveness, values 01h and 02h are reserved for Integrated Circuit(s)
- Cards Devices (USB-ICC) and other values are reserved for future use. */
- USB_IDX_INTERFACE_CCID_STR, /* iInterface: Index of string descriptor */
- /******************** CCID Device Descriptor ********************/
- /* 9 */
- 0x36, /* bLength: Size of this descriptor in bytes */
- USB_DESC_TYPE_HID, /* bDescriptorType: HID */
- LOBYTE(CCID_VALUE_BCDCCID), /* bcdCCID (low byte)*/
- HIBYTE(CCID_VALUE_BCDCCID), /* bcdCCID (high byte): 0x0110
- CCID Specification Release Number in Binary-Coded Decimal (i.e., 2.10 is 0210h) */
- 0x00, /* bMaxSlotIndex: 0
- The index of the highest available slot on this device.
- All slots are consecutive starting at 00h.
- i.e. 0Fh = 16 slots on this device numbered 00h to 0Fh. */
- 0x07, /* bVoltageSupport: 7
- This value indicates what voltages the CCID can supply to its slots.
- It is a bitwise OR operation performed on the following values:
- - 01h 5.0V
- - 02h 3.0V
- - 04h 1.8V
- Other bits are RFU */
- BYTE0(CCID_VALUE_DWPROTOCOLS), /* dwProtocols */
- BYTE1(CCID_VALUE_DWPROTOCOLS), /* dwProtocols */
- BYTE2(CCID_VALUE_DWPROTOCOLS), /* dwProtocols */
- BYTE3(CCID_VALUE_DWPROTOCOLS), /* dwProtocols: T=1
- RRRR –Upper Word- is RFU = 0000h
- PPPP –Lower Word- Encodes the supported protocol types.
- A ‘1’ in a given bit position indicates support for the associated ISO protocol.
- 0001h = Protocol T=0
- 0002h = Protocol T=1
- All other bits are reserved and must be set to zero.
- The field is intended to correspond to the PCSC specification definitions.
- See PCSC Part3. Table 3-1 Tag 0x0120.
- Example: 00000003h indicates support for T = 0 and T = 1. */
- BYTE0(CCID_VALUE_DWDEFAULTCLOCK), /* dwDefaultClock */
- BYTE1(CCID_VALUE_DWDEFAULTCLOCK), /* dwDefaultClock */
- BYTE2(CCID_VALUE_DWDEFAULTCLOCK), /* dwDefaultClock */
- BYTE3(CCID_VALUE_DWDEFAULTCLOCK), /* dwDefaultClock: 3580 KHz
- Default ICC clock frequency in KHz. This is an integer value.
- Example: 3.58 MHz is encoded as the integer value 3580. (00000DFCh)
- This is used in ETU and waiting time calculations.
- It is the clock frequency used when reading the ATR data. */
- BYTE0(CCID_VALUE_DWMAXIUMUMCLOCK),/* dwMaximumClock */
- BYTE1(CCID_VALUE_DWMAXIUMUMCLOCK),/* dwMaximumClock */
- BYTE2(CCID_VALUE_DWMAXIUMUMCLOCK),/* dwMaximumClock */
- BYTE3(CCID_VALUE_DWMAXIUMUMCLOCK),/* dwMaximumClock: 3580 KHz
- Maximum supported ICC clock frequency in KHz. This is an integer value.
- Example: 14.32 MHz is encoded as the integer value 14320. (000037F0h) */
- 0x00, /* bNumClockSupported: 0
- The number of clock frequencies that are supported by the CCID.
- If the value is 00h, the supported clock frequencies are assumed to be the default clock
- frequency defined by dwDefaultClock and the maximum clock frequency defined by dwMaximumClock.
- The reader must implement the command PC_to_RDR_SetDataRateAndClockFrequency if more than one
- clock frequency is supported. */
- BYTE0(CCID_VALUE_DWDATARATE), /* dwDataRate */
- BYTE1(CCID_VALUE_DWDATARATE), /* dwDataRate */
- BYTE2(CCID_VALUE_DWDATARATE), /* dwDataRate */
- BYTE3(CCID_VALUE_DWDATARATE), /* dwDataRate: 9600 bps
- Default ICC I/O data rate in bps. This is an integer value.
- Example: 9600 bps is encoded as the integer value 9600. (00002580h) */
- BYTE0(CCID_VALUE_DWMAXDATARATE), /* dwMaxDataRate */
- BYTE1(CCID_VALUE_DWMAXDATARATE), /* dwMaxDataRate */
- BYTE2(CCID_VALUE_DWMAXDATARATE), /* dwMaxDataRate */
- BYTE3(CCID_VALUE_DWMAXDATARATE), /* dwMaxDataRate: 9600 bps
- Maximum supported ICC I/O data rate in bps.
- Example: 115.2Kbps is encoded as the integer value 115200. (0001C200h) */
- 0x00, /* bNumDataRatesSupported: 0
- The number of data rates that are supported by the CCID.
- If the value is 00h, all data rates between the default data rate dwDataRate and the
- maximum data rate dwMaxDataRate are supported. */
- BYTE0(CCID_VALUE_DWMAXIFSD), /* dwMaxIFSD */
- BYTE1(CCID_VALUE_DWMAXIFSD), /* dwMaxIFSD */
- BYTE2(CCID_VALUE_DWMAXIFSD), /* dwMaxIFSD */
- BYTE3(CCID_VALUE_DWMAXIFSD), /* dwMaxIFSD: 254
- Indicates the maximum IFSD (Information Field Size for Device) supported by CCID for protocol T=1. */
- BYTE0(CCID_VALUE_DWSYNCPROTOCOLS),/* dwSynchProtocols */
- BYTE1(CCID_VALUE_DWSYNCPROTOCOLS),/* dwSynchProtocols */
- BYTE2(CCID_VALUE_DWSYNCPROTOCOLS),/* dwSynchProtocols */
- BYTE3(CCID_VALUE_DWSYNCPROTOCOLS),/* dwSynchProtocols: 0
- RRRR-Upper Word- is RFU = 0000h
- PPPP-Lower Word- encodes the supported protocol types.
- A ‘1’ in a given bit position indicates support for the associated protocol.
- 0001h indicates support for the 2-wire protocol
- 0002h indicates support for the 3-wire protocol
- 0004h indicates support for the I2C protocol
- All other values are outside of this specification, and must be handled by vendor-supplied drivers. */
- BYTE0(CCID_VALUE_DWMECHANICAL), /* dwMechanical */
- BYTE1(CCID_VALUE_DWMECHANICAL), /* dwMechanical */
- BYTE2(CCID_VALUE_DWMECHANICAL), /* dwMechanical */
- BYTE3(CCID_VALUE_DWMECHANICAL), /* dwMechanical: 0
- The value is a bitwise OR operation performed on the following values:
- - 00000000h No special characteristics
- - 00000001h Card accept mechanism
- - 00000002h Card ejection mechanism
- - 00000004h Card capture mechanism
- - 00000008h Card lock/unlock mechanism */
- BYTE0(CCID_VALUE_DWFEATURES), /* dwFeatures */
- BYTE1(CCID_VALUE_DWFEATURES), /* dwFeatures */
- BYTE2(CCID_VALUE_DWFEATURES), /* dwFeatures */
- BYTE3(CCID_VALUE_DWFEATURES), /* dwFeatures: 0x000400FE
- Automatic parameter configuration based on ATR data
- Automatic activation of ICC on inserting
- Automatic ICC voltage selection
- Automatic ICC clock frequency change according to active parameters provided by the Host or self determined
- Automatic baud rate change according to active parameters provided by the Host or self determined
- Automatic parameters negotiation made by the CCID
- Automatic PPS made by the CCID according to the active parameters
- Short and Extended APDU level exchange with CCID
- This value indicates what intelligent features the CCID has.
- The value is a bitwise OR operation performed on the following values:
- - 00000000h No special characteristics
- - 00000002h Automatic parameter configuration based on ATR data
- - 00000004h Automatic activation of ICC on inserting
- - 00000008h Automatic ICC voltage selection
- - 00000010h Automatic ICC clock frequency change according to active parameters provided by the Host or self determined
- - 00000020h Automatic baud rate change according to active parameters provided by the Host or self determined
- - 00000040h Automatic parameters negotiation made by the CCID (use of warm or cold resets or PPS according to a
- manufacturer proprietary algorithm to select the communication parameters with the ICC)
- - 00000080h Automatic PPS made by the CCID according to the active parameters
- - 00000100h CCID can set ICC in clock stop mode
- - 00000200h NAD value other than 00 accepted (T=1 protocol in use)
- - 00000400h Automatic IFSD exchange as first exchange (T=1 protocol in use)
- Only one of the following values may be present to select a level of exchange:
- - 00010000h TPDU level exchanges with CCID
- - 00020000h Short APDU level exchange with CCID
- - 00040000h Short and Extended APDU level exchange with CCID
- - If none of those values is indicated the level of exchange is character.
- Only one of the values 00000040h and 00000080h may be present.
- When value 00000040h is present the host shall not try to change the FI, DI, and protocol currently selected.
- When an APDU level for exchanges is selected, one of the values 00000040h or 00000080h must be present, as well as the
- value 00000002h.
- To support selective suspend:
- - 00100000h USB Wake up signaling supported on card insertion and removal
- When bit 20th, as shown above, is set bit D5 in bmAttributes of the Standard Configuration Descriptor must be set to 1. */
- BYTE0(CCID_VALUE_DWMAXCCIDMESSAGELENGTH),/* dwMaxCCIDMessageLength */
- BYTE1(CCID_VALUE_DWMAXCCIDMESSAGELENGTH),/* dwMaxCCIDMessageLength */
- BYTE2(CCID_VALUE_DWMAXCCIDMESSAGELENGTH),/* dwMaxCCIDMessageLength */
- BYTE3(CCID_VALUE_DWMAXCCIDMESSAGELENGTH),/* dwMaxCCIDMessageLength: 3072
- For extended APDU level the value shall be between 261 + 10 (header) and 65544 +10,
- otherwise the minimum value is the wMaxPacketSize of the Bulk-OUT endpoint. */
- 0xFF, /* bClassGetResponse: echo
- Significant only for CCID that offers an APDU level for exchanges.
- Indicates the default class value used by the CCID when it sends a Get Response command to perform the transportation of an APDU by T=0 protocol.
- Value FFh indicates that the CCID echoes the class of the APDU. */
- 0xFF, /* bClassEnvelope: echo
- Significant only for CCID that offers an extended APDU level for exchanges.
- Indicates the default class value used by the CCID when it sends an Envelope command to perform the transportation of an extended APDU by T=0 protocol.
- Value FFh indicates that the CCID echoes the class of the APDU.*/
- LOBYTE(CCID_VALUE_WLCDLAYOUT), /* wLcdLayout */
- HIBYTE(CCID_VALUE_WLCDLAYOUT), /* wLcdLayout: none
- Number of lines and characters for the LCD display used to send messages for PIN entry.
- XX: number of lines
- YY: number of characters per line.
- XXYY=0000h no LCD. */
- 0x00, /* bPINSupport: 0
- This value indicates what PIN support features the CCID has.
- The value is a bitwise OR operation performed on the following values:
- 0x01 PIN Verification supported
- 0x02 PIN Modification supported */
- 0x01, /* bMaxCCIDBusySlots: 1
- Maximum number of slots which can be simultaneously busy.*/
- /******************** CCID Endpoint descriptor (Bulk-OUT) ********************/
- /* 63 */
- 0x07, /* bLength: Endpoint Descriptor size */
- USB_DESC_TYPE_ENDPOINT, /* bDescriptorType: Endpoint */
- CCID_BULK_EPOUT_ADDR, /* bEndpointAddress: Endpoint Address (OUT) */
- USB_EP_TYPE_BULK, /* bmAttributes: Bulk Endpoint */
- LOBYTE(CCID_BULK_EPOUT_SIZE), /* wMaxPacketSize (low byte): 64 Byte max */
- HIBYTE(CCID_BULK_EPOUT_SIZE), /* wMaxPacketSize (high byte): 64 Byte max */
- CCID_BULK_FS_BINTERVAL, /* bInterval: Polling Interval */
- /******************** CCID Endpoint descriptor (Bulk-IN) ********************/
- /* 70 */
- 0x07, /* bLength: Endpoint Descriptor size */
- USB_DESC_TYPE_ENDPOINT, /* bDescriptorType: Endpoint */
- CCID_BULK_EPIN_ADDR, /* bEndpointAddress: Endpoint Address (IN) */
- USB_EP_TYPE_BULK, /* bmAttributes: Bulk Endpoint */
- LOBYTE(CCID_BULK_EPIN_SIZE), /* wMaxPacketSize (low byte): 64 Byte max */
- HIBYTE(CCID_BULK_EPIN_SIZE), /* wMaxPacketSize (high byte): 64 Byte max */
- CCID_BULK_FS_BINTERVAL, /* bInterval: Polling Interval */
- /* 77 */
-};
-
// DEBUG Descriptor
FLASH uint8_t DebugDesc[] = {
- /******************** Interface, DEBUG Descriptor (two endpoints) ********************/
+ /******************** Interface 3, DEBUG Descriptor (two endpoints) ********************/
0x09, /* bLength: Interface Descriptor size */
USB_DESC_TYPE_INTERFACE, /* bDescriptorType: Interface */
- CHANGE_ME, /* bInterfaceNumber: Number of Interface */
+ 0x03, /* bInterfaceNumber: Number of Interface */
0x00, /* bAlternateSetting: Alternate setting */
- 0x02, /* bNumEndpoints: Number of endpoints in Interface */
+ 0x02, /* bNumEndpoints: 2 */
USB_DEV_CLASS_HID, /* bInterfaceClass: Human Interface Device */
0x00, /* bInterfaceSubClass : 1=BOOT, 0=no boot */
0x00, /* bInterfaceProtocol : 0=none, 1=keyboard, 2=mouse */
@@ -652,11 +426,11 @@ volatile IDATA uint8_t DebugUartRxBufByteCount = 0;
/** Endpoint handling */
volatile IDATA uint8_t UsbEp2ByteCount = 0; // Represents the data received by USB endpoint 2 (CDC)
-volatile IDATA uint8_t UsbEp3ByteCount = 0; // Represents the data received by USB endpoint 3 (FIDO or CCID)
+volatile IDATA uint8_t UsbEp3ByteCount = 0; // Represents the data received by USB endpoint 3 (FIDO)
volatile IDATA uint8_t UsbEp4ByteCount = 0; // Represents the data received by USB endpoint 4 (DEBUG)
volatile IDATA uint8_t Endpoint2UploadBusy = 0; // Whether the upload endpoint 2 (CDC) is busy
-volatile IDATA uint8_t Endpoint3UploadBusy = 0; // Whether the upload endpoint 3 (FIDO or CCID) is busy
+volatile IDATA uint8_t Endpoint3UploadBusy = 0; // Whether the upload endpoint 3 (FIDO) is busy
volatile IDATA uint8_t Endpoint4UploadBusy = 0; // Whether the upload endpoint 4 (DEBUG) is busy
/** CH552 variables */
@@ -671,9 +445,6 @@ IDATA uint8_t CdcDataAvailable = 0;
/** FIDO variables */
IDATA uint8_t FidoDataAvailable = 0;
-/** CCID variables */
-IDATA uint8_t CcidDataAvailable = 0;
-
/** Frame data */
#define MAX_FRAME_SIZE 64
XDATA uint8_t FrameBuf[MAX_FRAME_SIZE] = { 0 };
@@ -768,10 +539,9 @@ void CreateCfgDescriptor(uint8_t ep_config)
uint8_t num_iface = 0; // Interface number
FidoInterfaceNum = 0xFF; // Set as invalid until we have parsed each interface
- CcidInterfaceNum = 0xFF; // Set as invalid until we have parsed each interface
DebugInterfaceNum = 0xFF; // Set as invalid until we have parsed each interface
- memset(ActiveCfgDesc, 0, MAX_CFG_DESC_SIZE); // Clean the descriptor
+ memset(ActiveCfgDesc, 0, CFG_DESC_SIZE); // Clean the descriptor
uint8_t cfg_desc_size = sizeof(CfgDesc);
memcpy(ActiveCfgDesc, CfgDesc, cfg_desc_size);
@@ -780,10 +550,7 @@ void CreateCfgDescriptor(uint8_t ep_config)
if (ep_config & IO_CDC) {
uint8_t cdc_desc_size = sizeof(CdcDesc);
memcpy(ActiveCfgDesc + ActiveCfgDescSize, CdcDesc, cdc_desc_size);
- ActiveCfgDesc[ActiveCfgDescSize + 10] = num_iface;
- num_iface++;
- ActiveCfgDesc[ActiveCfgDescSize + 45] = num_iface;
- num_iface++;
+ num_iface += 2;
ActiveCfgDescSize += cdc_desc_size;
}
@@ -796,15 +563,6 @@ void CreateCfgDescriptor(uint8_t ep_config)
ActiveCfgDescSize += fido_desc_size;
}
- if (ep_config & IO_CCID) {
- uint8_t ccid_desc_size = sizeof(CcidDesc);
- memcpy(ActiveCfgDesc + ActiveCfgDescSize, CcidDesc, ccid_desc_size);
- ActiveCfgDesc[ActiveCfgDescSize + 2] = num_iface;
- CcidInterfaceNum = num_iface;
- num_iface++;
- ActiveCfgDescSize += ccid_desc_size;
- }
-
if (ep_config & IO_DEBUG) {
uint8_t debug_desc_size = sizeof(DebugDesc);
memcpy(ActiveCfgDesc + ActiveCfgDescSize, DebugDesc, debug_desc_size);
@@ -847,244 +605,179 @@ void usb_irq_setup_handler(void)
SetupReq = UsbSetupBuf->bRequest;
// Class-Specific Requests, i.e. HID request, CDC request etc.
- if ( ((UsbSetupBuf->bmRequestType & USB_REQ_TYPE_MASK) == USB_REQ_TYPE_CLASS) ||
- ((UsbSetupBuf->bmRequestType & USB_REQ_TYPE_MASK) == USB_REQ_TYPE_VENDOR)) {
-
- printStrSetup("Class/Vendor-Specific Request = ");
+ if ((UsbSetupBuf->bmRequestType & USB_REQ_TYPE_MASK) != USB_REQ_TYPE_STANDARD) {
+ printStrSetup("Class-Specific ");
+ printStrSetup("SetupReq=");
+ printStrSetup("0x");
printNumU8HexSetup(SetupReq);
- printStrSetup("\n\t");
-
+ printStrSetup(" ");
switch(SetupReq) {
case USB_HID_REQ_TYPE_GET_REPORT:
- printStrSetup("HID GET_REPORT\n");
+ printStrSetup("HID Get Report\n");
break;
case USB_HID_REQ_TYPE_GET_IDLE:
- printStrSetup("HID GET_IDLE\n");
+ printStrSetup("HID Get Idle\n");
break;
case USB_HID_REQ_TYPE_GET_PROTOCOL:
- printStrSetup("HID GET_PROTOCOL\n");
+ printStrSetup("HID Get Protocol\n");
break;
case USB_HID_REQ_TYPE_SET_REPORT:
- printStrSetup("HID SET_REPORT\n");
+ printStrSetup("HID Set Report\n");
break;
case USB_HID_REQ_TYPE_SET_IDLE:
- printStrSetup("HID SET_IDLE\n");
+ printStrSetup("HID Set Idle\n");
break;
case USB_HID_REQ_TYPE_SET_PROTOCOL:
- printStrSetup("HID SET_PROTOCOL\n");
+ printStrSetup("HID Set Protocol\n");
break;
case USB_CDC_REQ_TYPE_SET_LINE_CODING:
- printStrSetup("CDC SET_LINE_CODING\n");
+ printStrSetup("CDC Set Line Coding\n");
break;
case USB_CDC_REQ_TYPE_GET_LINE_CODING:
- printStrSetup("CDC GET_LINE_CODING\n");
+ printStrSetup("CDC Get Line Coding\n");
pDescr = LineCoding;
len = sizeof(LineCoding);
- SetupLen = MIN(SetupLen, len); // Limit total length
- len = (SetupLen >= DEFAULT_EP0_SIZE) ? DEFAULT_EP0_SIZE : SetupLen; // The length of this transmission
- memcpy(Ep0Buffer, pDescr, len); // Copy upload data
+ len = SetupLen >= DEFAULT_EP0_SIZE ? DEFAULT_EP0_SIZE : SetupLen; // The length of this transmission
+ memcpy(Ep0Buffer, pDescr, len);
SetupLen -= len;
pDescr += len;
break;
- case USB_CDC_REQ_TYPE_SET_CONTROL_LINE_STATE:
- printStrSetup("CDC SET_CONTROL_LINE_STATE\n");
+ case USB_CDC_REQ_TYPE_SET_CONTROL_LINE_STATE: // Generates RS-232/V.24 style control signals
+ printStrSetup("CDC Set Control Line State\n");
break;
default:
- printStrSetup("Unsupported Request!\n");
- len = 0xFF; // Unsupported Request
+ len = 0xFF; // Command not supported
+ printStrSetup("Unsupported\n");
break;
- } // END switch(SetupReq)
- } // END Class/Vendor-Specific Requests
-
- // Standard Request
- else if (((UsbSetupBuf->bmRequestType & USB_REQ_TYPE_MASK) == USB_REQ_TYPE_STANDARD)) {
-
- printStrSetup("Standard Request = ");
- printNumU8HexSetup(SetupReq);
- printStrSetup("\n\t");
+ }
+ } // END Non-standard request
+ else { // Standard Requests
+ // Request code
switch (SetupReq) {
- case USB_GET_DESCRIPTOR:
- printStrSetup("GET_DESCRIPTOR: wValueH = ");
- printNumU8HexSetup(UsbSetupBuf->wValueH);
- printStrSetup("\n\t\t");
-
+ case USB_GET_DESCRIPTOR: {
switch (UsbSetupBuf->wValueH) {
- case USB_DESC_TYPE_DEVICE:
- printStrSetup("DEVICE\n");
+ case USB_DESC_TYPE_DEVICE: // Device descriptor
pDescr = DevDesc; // Send the device descriptor to the buffer to be sent
len = sizeof(DevDesc);
- SetupLen = MIN(SetupLen, len); // Limit total length
- len = (SetupLen >= DEFAULT_EP0_SIZE) ? DEFAULT_EP0_SIZE : SetupLen; // The length of this transmission
- memcpy(Ep0Buffer, pDescr, len); // Copy upload data
- SetupLen -= len;
- pDescr += len;
+ printStrSetup("DevDesc\n");
break;
-
- case USB_DESC_TYPE_DEVICE_QUALIFIER:
- printStrSetup("DEVICE_QUALIFIER\n");
- break;
-
- case USB_DESC_TYPE_CONFIGURATION:
- printStrSetup("CONFIGURATION\n");
+ case USB_DESC_TYPE_CONFIGURATION: // Configuration descriptor
pDescr = ActiveCfgDesc; // Send the configuration descriptor to the buffer to be sent
- len = ActiveCfgDescSize; // Dynamic value based on what endpoints are enabled
- SetupLen = MIN(SetupLen, len); // Limit total length
- len = (SetupLen >= DEFAULT_EP0_SIZE) ? DEFAULT_EP0_SIZE : SetupLen; // The length of this transmission
- memcpy(Ep0Buffer, pDescr, len); // Copy upload data
- SetupLen -= len;
- pDescr += len;
+ len = sizeof(ActiveCfgDesc);
+ printStrSetup("CfgDesc\n");
break;
-
- case USB_DESC_TYPE_STRING:
- printStrSetup("STRING: wValueL = ");
- printNumU8HexSetup(UsbSetupBuf->wValueL);
- printStrSetup("\n\t\t\t");
-
+ case USB_DESC_TYPE_STRING: // String descriptors
if (UsbSetupBuf->wValueL == USB_IDX_LANGID_STR) {
- printStrSetup("LangDesc\n");
pDescr = LangDesc;
len = sizeof(LangDesc);
+ printStrSetup("LangDesc\n");
} else if (UsbSetupBuf->wValueL == USB_IDX_MFC_STR) {
- printStrSetup("ManufDesc\n");
pDescr = ManufDesc;
len = sizeof(ManufDesc);
+ printStrSetup("ManufDesc\n");
} else if (UsbSetupBuf->wValueL == USB_IDX_PRODUCT_STR) {
- printStrSetup("ProdDesc\n");
pDescr = ProdDesc;
len = sizeof(ProdDesc);
+ printStrSetup("ProdDesc\n");
} else if (UsbSetupBuf->wValueL == USB_IDX_SERIAL_STR) {
- printStrSetup("SerialDesc\n");
pDescr = SerialDesc;
len = sizeof(SerialDesc);
+ printStrSetup("SerialDesc\n");
} else if (UsbSetupBuf->wValueL == USB_IDX_INTERFACE_CDC_CTRL_STR) {
- printStrSetup("CdcCtrlInterfaceDesc\n");
pDescr = CdcCtrlInterfaceDesc;
len = sizeof(CdcCtrlInterfaceDesc);
+ printStrSetup("CdcCtrlInterfaceDesc\n");
} else if (UsbSetupBuf->wValueL == USB_IDX_INTERFACE_CDC_DATA_STR) {
- printStrSetup("CdcDataInterfaceDesc\n");
pDescr = CdcDataInterfaceDesc;
len = sizeof(CdcDataInterfaceDesc);
+ printStrSetup("CdcDataInterfaceDesc\n");
} else if (UsbSetupBuf->wValueL == USB_IDX_INTERFACE_FIDO_STR) {
- printStrSetup("FidoHidInterfaceDesc\n");
pDescr = FidoInterfaceDesc;
len = sizeof(FidoInterfaceDesc);
- } else if (UsbSetupBuf->wValueL == USB_IDX_INTERFACE_CCID_STR) {
- printStrSetup("CcidInterfaceDesc\n");
- pDescr = CcidInterfaceDesc;
- len = sizeof(CcidInterfaceDesc);
+ printStrSetup("FidoHidInterfaceDesc\n");
} else if (UsbSetupBuf->wValueL == USB_IDX_INTERFACE_DEBUG_STR) {
- printStrSetup("DebugInterfaceDesc\n");
pDescr = DebugInterfaceDesc;
len = sizeof(DebugInterfaceDesc);
+ printStrSetup("DebugInterfaceDesc\n");
} else {
- printStrSetup("Unknown String!\n");
- len = 0xFF; // Unsupported
- break; // Early exit
+ printStrSetup("Error: USB_DESC_TYPE_STRING\n");
}
- SetupLen = MIN(SetupLen, len); // Limit total length
- len = (SetupLen >= DEFAULT_EP0_SIZE) ? DEFAULT_EP0_SIZE : SetupLen; // The length of this transmission
- memcpy(Ep0Buffer, pDescr, len); // Copy upload data
- SetupLen -= len;
- pDescr += len;
break;
-
case USB_DESC_TYPE_HID:
- printStrSetup("HID: wValueL = ");
- printNumU8HexSetup(UsbSetupBuf->wValueL);
- printStrSetup("\n");
-
if (UsbSetupBuf->wIndexL == FidoInterfaceNum) { // Interface number for FIDO
- printStrSetup("FidoCfgDesc\n");
pDescr = FidoCfgDesc;
len = sizeof(FidoCfgDesc);
+ printStrSetup("FidoCfgDesc\n");
} else if (UsbSetupBuf->wIndexL == DebugInterfaceNum) { // Interface number for DEBUG
- printStrSetup("DebugCfgDesc\n");
pDescr = DebugCfgDesc;
len = sizeof(DebugCfgDesc);
- } else {
- printStrSetup("Unknown HID Interface!\n");
- len = 0xFF; // Unsupported
- break; // Early exit
+ printStrSetup("DebugCfgDesc\n");
}
- SetupLen = MIN(SetupLen, len); // Limit total length
- len = (SetupLen >= DEFAULT_EP0_SIZE) ? DEFAULT_EP0_SIZE : SetupLen; // The length of this transmission
- memcpy(Ep0Buffer, pDescr, len); // Copy upload data
- SetupLen -= len;
- pDescr += len;
break;
-
case USB_DESC_TYPE_REPORT:
- printStrSetup("REPORT: wIndexL = ");
- printNumU8HexSetup(UsbSetupBuf->wIndexL);
- printStrSetup("\n");
-
if (UsbSetupBuf->wIndexL == FidoInterfaceNum) { // Interface number for FIDO
- printStrSetup("FidoReportDesc\n");
pDescr = FidoReportDesc;
len = sizeof(FidoReportDesc);
+ printStrSetup("FidoReportDesc\n");
} else if (UsbSetupBuf->wIndexL == DebugInterfaceNum) { // Interface number for DEBUG
- printStrSetup("DebugReportDesc\n");
pDescr = DebugReportDesc;
len = sizeof(DebugReportDesc);
- } else {
- printStrSetup("Unknown Report!\n");
- len = 0xFF; // Unknown Report
- break; // Early exit
+ printStrSetup("DebugReportDesc\n");
}
- SetupLen = MIN(SetupLen, len); // Limit total length
- len = (SetupLen >= DEFAULT_EP0_SIZE) ? DEFAULT_EP0_SIZE : SetupLen; // The length of this transmission
- memcpy(Ep0Buffer, pDescr, len); // Copy upload data
- SetupLen -= len;
- pDescr += len;
break;
-
- case USB_DESC_TYPE_DEBUG:
- printStrSetup("DEBUG\n");
- break;
-
default:
- printStrSetup("Unknown descriptor!\n");
- len = 0xFF; // Unknown descriptor
+ len = 0xFF; // Unsupported command or error
+ printStrSetup("Unsupported\n");
break;
- } // END switch (UsbSetupBuf->wValueH)
- break;
+ }
+
+ if (SetupLen > len) {
+ SetupLen = len; // Limit total length
+ }
+
+ len = SetupLen >= DEFAULT_EP0_SIZE ? DEFAULT_EP0_SIZE : SetupLen; // This transmission length
+ memcpy(Ep0Buffer, pDescr, len); // Copy upload data
+ SetupLen -= len;
+ pDescr += len;
+ }
+ break;
case USB_SET_ADDRESS:
- printStrSetup("SET_ADDRESS\n");
SetupLen = UsbSetupBuf->wValueL; // Temporary storage of USB device address
+ printStrSetup("SetAddress\n");
break;
case USB_GET_CONFIGURATION:
- printStrSetup("GET_CONFIGURATION\n");
Ep0Buffer[0] = UsbConfig;
if (SetupLen >= 1) {
len = 1;
}
+ printStrSetup("GetConfig\n");
break;
case USB_SET_CONFIGURATION:
- printStrSetup("SET_CONFIGURATION\n");
UsbConfig = UsbSetupBuf->wValueL;
+ printStrSetup("SetConfig\n");
break;
case USB_GET_INTERFACE:
- printStrSetup("GET_INTERFACE\n");
+ printStrSetup("GetInterface\n");
break;
- case USB_CLEAR_FEATURE:
- printStrSetup("CLEAR_FEATURE\n");
+ case USB_CLEAR_FEATURE: // Clear Feature
+ printStrSetup("ClearFeature\n");
if ((UsbSetupBuf->bmRequestType & USB_REQ_RECIP_MASK) == USB_REQ_RECIP_DEVICE) { // Remove device
if ((((uint16_t) UsbSetupBuf->wValueH << 8) | UsbSetupBuf->wValueL) == 0x01) {
if (CfgDesc[7] & 0x20) {
// Wake
} else {
- printStrSetup("Operation failed\n");
len = 0xFF; // Operation failed
+ printStrSetup("Unsupported\n");
}
} else {
- printStrSetup("Operation failed\n");
len = 0xFF; // Operation failed
+ printStrSetup("Unsupported\n");
}
} else if ((UsbSetupBuf->bmRequestType & USB_REQ_RECIP_MASK) == USB_REQ_RECIP_ENDP) { // Endpoint
switch (UsbSetupBuf->wIndexL) {
@@ -1113,18 +806,18 @@ void usb_irq_setup_handler(void)
UEP1_CTRL = (UEP1_CTRL & ~(bUEP_R_TOG | MASK_UEP_R_RES)) | UEP_R_RES_ACK; // Set endpoint 1 OUT (RX) ACK
break;
default:
- printStrSetup("Unsupported endpoint\n");
- len = 0xFF; // Unsupported endpoint
+ len = 0xFF; // Unsupported endpoint
+ printStrSetup("Unsupported\n");
break;
- } // END switch (UsbSetupBuf->wIndexL)
+ }
} else {
- printStrSetup("Unsupported\n");
len = 0xFF; // It's not that the endpoint doesn't support it
+ printStrSetup("Unsupported\n");
}
break;
- case USB_SET_FEATURE:
- printStrSetup("SET_FEATURE\n");
+ case USB_SET_FEATURE: // Set Feature
+ printStrSetup("SetFeature\n");
if (( UsbSetupBuf->bmRequestType & USB_REQ_RECIP_MASK) == USB_REQ_RECIP_DEVICE) { // Set up the device
if ((((uint16_t) UsbSetupBuf->wValueH << 8) | UsbSetupBuf->wValueL) == 0x01) {
if (CfgDesc[7] & 0x20) {
@@ -1176,17 +869,17 @@ void usb_irq_setup_handler(void)
break;
}
} else {
- printStrSetup("Operation failed\n");
len = 0xFF; // Operation failed
+ printStrSetup("Unsupported\n");
}
} else {
- printStrSetup("Operation failed\n");
len = 0xFF; // Operation failed
+ printStrSetup("Unsupported\n");
}
break;
case USB_GET_STATUS:
- printStrSetup("GET_STATUS\n");
+ printStrSetup("GetStatus\n");
Ep0Buffer[0] = 0x00;
Ep0Buffer[1] = 0x00;
if (SetupLen >= 2) {
@@ -1200,15 +893,9 @@ void usb_irq_setup_handler(void)
len = 0xFF; // Operation failed
printStrSetup("Unsupported\n");
break;
+
} // END switch (SetupReq)
} // END Standard request
-
- // Unknown Request
- else {
- printStrSetup("Unknown Request Type!\n");
- len = 0xFF; // Operation failed
- } // END Unknown Request
-
} else {
len = 0xFF; // Packet length error
}
@@ -1249,9 +936,8 @@ void DeviceInterrupt(void)IRQ_USB // USB interrupt service routine, using regist
case UIS_TOKEN_IN | 0: // Endpoint 0 IN (TX)
switch (SetupReq) {
case USB_GET_DESCRIPTOR:
- /* Continue sending descriptor in multiple packets if needed. Started from SETUP routine */
- len = (SetupLen >= DEFAULT_EP0_SIZE) ? DEFAULT_EP0_SIZE : SetupLen; // The length of this transmission
- memcpy(Ep0Buffer, pDescr, len); // Copy upload data
+ len = SetupLen >= DEFAULT_EP0_SIZE ? DEFAULT_EP0_SIZE : SetupLen; // The length of this transmission
+ memcpy(Ep0Buffer, pDescr, len); // Load upload data
SetupLen -= len;
pDescr += len;
UEP0_T_LEN = len;
@@ -1268,24 +954,24 @@ void DeviceInterrupt(void)IRQ_USB // USB interrupt service routine, using regist
}
break;
- case UIS_TOKEN_IN | 1: // Endpoint 1 IN (TX)
+ case UIS_TOKEN_IN | 1: // Endpoint 1 IN (TX), Endpoint interrupts upload
UEP1_T_LEN = 0; // Transmit length must be cleared (Endpoint 1)
UEP1_CTRL = (UEP1_CTRL & ~MASK_UEP_T_RES) | UEP_T_RES_NAK; // Default answer NAK
break;
- case UIS_TOKEN_IN | 2: // Endpoint 2 IN (TX)
+ case UIS_TOKEN_IN | 2: // Endpoint 2 IN (TX), Endpoint bulk upload
UEP2_T_LEN = 0; // Transmit length must be cleared (Endpoint 2)
UEP2_CTRL = (UEP2_CTRL & ~MASK_UEP_T_RES) | UEP_T_RES_NAK; // Default answer NAK
Endpoint2UploadBusy = 0; // Clear busy flag
break;
- case UIS_TOKEN_IN | 3: // Endpoint 3 IN (TX)
+ case UIS_TOKEN_IN | 3: // Endpoint 3 IN (TX), Endpoint bulk upload
UEP3_T_LEN = 0; // Transmit length must be cleared (Endpoint 3)
UEP3_CTRL = (UEP3_CTRL & ~MASK_UEP_T_RES) | UEP_T_RES_NAK; // Default answer NAK
Endpoint3UploadBusy = 0; // Clear busy flag
break;
- case UIS_TOKEN_IN | 4: // Endpoint 4 IN (TX)
+ case UIS_TOKEN_IN | 4: // Endpoint 4 IN (TX), Endpoint bulk upload
UEP4_T_LEN = 0; // Transmit length must be cleared (Endpoint 4)
UEP4_CTRL = (UEP4_CTRL & ~MASK_UEP_T_RES) | UEP_T_RES_NAK; // Default answer NAK
UEP4_CTRL ^= bUEP_T_TOG; // Sync flag flip
@@ -1294,8 +980,7 @@ void DeviceInterrupt(void)IRQ_USB // USB interrupt service routine, using regist
case UIS_TOKEN_OUT | 0: // Endpoint 0 OUT (RX)
switch (SetupReq) {
- case USB_CDC_REQ_TYPE_SET_LINE_CODING:
- /* We ignore line coding here because baudrate to the FPGA should not change */
+ case USB_CDC_REQ_TYPE_SET_LINE_CODING: // We ignore line coding here because baudrate to the FPGA should not change
if (U_TOG_OK) {
UEP0_T_LEN = 0;
UEP0_CTRL |= UEP_R_RES_ACK | UEP_T_RES_ACK; // Prepare to upload 0 packages
@@ -1304,7 +989,6 @@ void DeviceInterrupt(void)IRQ_USB // USB interrupt service routine, using regist
default:
UEP0_T_LEN = 0;
UEP0_CTRL |= UEP_R_RES_ACK | UEP_T_RES_NAK; // Status phase, responds to IN with NAK
- break;
}
break;
@@ -1316,7 +1000,7 @@ void DeviceInterrupt(void)IRQ_USB // USB interrupt service routine, using regist
}
break;
- case UIS_TOKEN_OUT | 2: // Endpoint 2 OUT (RX)
+ case UIS_TOKEN_OUT | 2: // Endpoint 2 OUT (RX), Endpoint batch download
// Out-of-sync packets will be dropped
if (U_TOG_OK) {
UsbEp2ByteCount = USB_RX_LEN; // Length of received data
@@ -1324,7 +1008,7 @@ void DeviceInterrupt(void)IRQ_USB // USB interrupt service routine, using regist
}
break;
- case UIS_TOKEN_OUT | 3: // Endpoint 3 OUT (RX)
+ case UIS_TOKEN_OUT | 3: // Endpoint 3 OUT (RX), Endpoint batch download
// Out-of-sync packets will be dropped
if (U_TOG_OK) {
UsbEp3ByteCount = USB_RX_LEN; // Length of received data
@@ -1332,7 +1016,7 @@ void DeviceInterrupt(void)IRQ_USB // USB interrupt service routine, using regist
}
break;
- case UIS_TOKEN_OUT | 4: // Endpoint 4 OUT (RX)
+ case UIS_TOKEN_OUT | 4: // Endpoint 4 OUT (RX), Endpoint batch download
// Out-of-sync packets will be dropped
if (U_TOG_OK) {
UsbEp4ByteCount = USB_RX_LEN; // Length of received data
@@ -1530,7 +1214,7 @@ void main()
UART1Setup(); // For communication with FPGA
UART1Clean(); // Clean register from spurious data
- printStrSetup("\nStartup\n");
+ printStrSetup("Startup\n");
uint8_t ActiveEndpoints = RESET_KEEP;
@@ -1544,11 +1228,6 @@ void main()
ActiveEndpoints |= IO_CH552;
}
- // FIDO and CCID can't be enabled at the same time. Disable both!
- if ((ActiveEndpoints & IO_FIDO) && (ActiveEndpoints & IO_CCID)) {
- ActiveEndpoints &= ~(IO_FIDO | IO_CCID);
- }
-
CreateCfgDescriptor(ActiveEndpoints);
USBDeviceCfg();
@@ -1580,18 +1259,14 @@ void main()
UEP2_CTRL = (UEP2_CTRL & ~MASK_UEP_R_RES) | UEP_R_RES_ACK; // Enable Endpoint 2 to ACK again
}
- // Check if Endpoint 3 (FIDO or CCID) has received data
+ // Check if Endpoint 3 (FIDO) has received data
if (UsbEp3ByteCount) {
Ep3ByteLen = UsbEp3ByteCount; // UsbEp3ByteCount can be maximum 64 bytes
memcpy(UartTxBuf, Ep3Buffer, Ep3ByteLen);
UsbEp3ByteCount = 0;
- if (ActiveEndpoints & IO_FIDO) {
- CH554UART1SendByte(IO_FIDO); // Send FIDO mode header
- } else if (ActiveEndpoints & IO_CCID) {
- CH554UART1SendByte(IO_CCID); // Send CCID mode header
- }
- CH554UART1SendByte(Ep3ByteLen); // Send length (always 64 bytes for FIDO, variable for CCID)
+ CH554UART1SendByte(IO_FIDO); // Send FIDO mode header
+ CH554UART1SendByte(Ep3ByteLen); // Send length (always 64 bytes)
CH554UART1SendBuffer(UartTxBuf, Ep3ByteLen);
UEP3_CTRL = (UEP3_CTRL & ~MASK_UEP_R_RES) | UEP_R_RES_ACK; // Enable Endpoint 3 to ACK again
}
@@ -1614,7 +1289,6 @@ void main()
FrameMode = UartRxBuf[UartRxBufOutputPointer]; // Extract frame mode
if ((FrameMode == IO_CDC) ||
(FrameMode == IO_FIDO) ||
- (FrameMode == IO_CCID) ||
(FrameMode == IO_DEBUG) ||
(FrameMode == IO_CH552)) {
@@ -1687,58 +1361,19 @@ void main()
// Copy FIDO data from UartRxBuf to FrameBuf
if (FrameStarted && !FrameDiscard && !FidoDataAvailable) {
if (FrameMode == IO_FIDO) {
- if ((FrameRemainingBytes >= MAX_FRAME_SIZE) &&
- (UartRxBufByteCount >= MAX_FRAME_SIZE)) {
- circular_copy(FrameBuf,
- UartRxBuf,
- UART_RX_BUF_SIZE,
- UartRxBufOutputPointer,
- MAX_FRAME_SIZE);
- FrameBufLength = MAX_FRAME_SIZE;
- // Update output pointer
- UartRxBufOutputPointer = increment_pointer(UartRxBufOutputPointer,
- MAX_FRAME_SIZE,
- UART_RX_BUF_SIZE);
- FrameRemainingBytes -= MAX_FRAME_SIZE;
- FidoDataAvailable = 1;
- cts_start();
- }
- }
- }
-
- // Copy CCID data from UartRxBuf to FrameBuf
- if (FrameStarted && !FrameDiscard && !CcidDataAvailable) {
- if (FrameMode == IO_CCID) {
- if ((FrameRemainingBytes >= MAX_FRAME_SIZE) &&
- (UartRxBufByteCount >= MAX_FRAME_SIZE)) {
- circular_copy(FrameBuf,
- UartRxBuf,
- UART_RX_BUF_SIZE,
- UartRxBufOutputPointer,
- MAX_FRAME_SIZE);
- FrameBufLength = MAX_FRAME_SIZE;
- // Update output pointer
- UartRxBufOutputPointer = increment_pointer(UartRxBufOutputPointer,
- MAX_FRAME_SIZE,
- UART_RX_BUF_SIZE);
- FrameRemainingBytes -= MAX_FRAME_SIZE;
- CcidDataAvailable = 1;
- cts_start();
- }
- else if ((FrameRemainingBytes < MAX_FRAME_SIZE) &&
- (UartRxBufByteCount >= FrameRemainingBytes)) {
+ // Check if a complete frame has been received
+ if (UartRxBufByteCount >= FrameRemainingBytes) {
circular_copy(FrameBuf,
UartRxBuf,
UART_RX_BUF_SIZE,
UartRxBufOutputPointer,
FrameRemainingBytes);
- FrameBufLength = FrameRemainingBytes;
+ FrameBufLength = MAX_FRAME_SIZE;
// Update output pointer
UartRxBufOutputPointer = increment_pointer(UartRxBufOutputPointer,
FrameRemainingBytes,
UART_RX_BUF_SIZE);
- FrameRemainingBytes -= FrameRemainingBytes;
- CcidDataAvailable = 1;
+ FidoDataAvailable = 1;
cts_start();
}
}
@@ -1884,25 +1519,6 @@ void main()
FrameStarted = 0;
}
- // Check if we should upload data to Endpoint 3 (CCID)
- if (CcidDataAvailable && !Endpoint3UploadBusy) {
-
- // Write upload endpoint
- memcpy(Ep3Buffer + MAX_PACKET_SIZE, /* Copy to IN buffer of Endpoint 3 */
- FrameBuf,
- FrameBufLength);
-
- Endpoint3UploadBusy = 1; // Set busy flag
- UEP3_T_LEN = FrameBufLength; // Set the number of data bytes that Endpoint 3 is ready to send
- UEP3_CTRL = (UEP3_CTRL & ~MASK_UEP_T_RES) | UEP_T_RES_ACK; // Answer ACK
-
- CcidDataAvailable = 0;
- FrameBufLength = 0;
-
- // Get next header and data
- FrameStarted = 0;
- }
-
// Check if we should upload data to Endpoint 4 (DEBUG)
if (DebugDataAvailable && !Endpoint4UploadBusy) {
@@ -1935,10 +1551,9 @@ void main()
// Check if we should handle CH552 data
if (CH552DataAvailable) {
- // Check command range
- if (FrameBuf[0] < CH552_CMD_MAX) {
- switch (FrameBuf[0]) {
- case SET_ENDPOINTS:
+ switch (FrameBuf[0]) {
+
+ case SET_ENDPOINTS: {
cts_stop(); // Stop UART data from FPGA
RESET_KEEP = FrameBuf[1]; // Save endpoints to persistent register
SAFE_MOD = 0x55; // Start reset sequence
@@ -1946,10 +1561,13 @@ void main()
GLOBAL_CFG = bSW_RESET;
while (1)
;
- break;
- default:
- break;
- } // END switch(FrameBuf[0])
+ }
+ break;
+
+ default: {
+ }
+ break;
+
}
CH552DataAvailable = 0;