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 ![The Application FPGA block diagram](../../doc/images/application_fpga_block_diagram.png) @@ -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;