diff --git a/COPYING b/COPYING index d159169d1..0e8db929e 100644 --- a/COPYING +++ b/COPYING @@ -1,339 +1,16 @@ - GNU GENERAL PUBLIC LICENSE - Version 2, June 1991 +OpenOCD is provided under: - 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. + SPDX-License-Identifier: GPL-2.0-or-later - Preamble +Being under the terms of the GNU General Public License version 2 or +later, according with: - 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. + LICENSES/preferred/GPL-2.0 - 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. +In addition, other licenses may also apply. Please see: - 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. + LICENSES/license-rules.txt - 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. +for more details. - 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, write to the Free Software Foundation, Inc., - 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. - -Also add information on how to contact you by electronic and paper mail. - -If the program is interactive, make it output a short notice like this -when it starts in an interactive mode: - - Gnomovision version 69, Copyright (C) year name of author - Gnomovision comes with ABSOLUTELY NO WARRANTY; for details type `show w'. - This is free software, and you are welcome to redistribute it - under certain conditions; type `show c' for details. - -The hypothetical commands `show w' and `show c' should show the appropriate -parts of the General Public License. Of course, the commands you use may -be called something other than `show w' and `show c'; they could even be -mouse-clicks or menu items--whatever suits your program. - -You should also get your employer (if you work as a programmer) or your -school, if any, to sign a "copyright disclaimer" for the program, if -necessary. Here is a sample; alter the names: - - Yoyodyne, Inc., hereby disclaims all copyright interest in the program - `Gnomovision' (which makes passes at compilers) written by James Hacker. - - , 1 April 1989 - Ty Coon, 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. +All contributions to OpenOCD are subject to this COPYING file. diff --git a/LICENSES/license-rules.txt b/LICENSES/license-rules.txt new file mode 100644 index 000000000..8d0c0a0ee --- /dev/null +++ b/LICENSES/license-rules.txt @@ -0,0 +1,218 @@ +# SPDX-License-Identifier: GPL-2.0-or-later OR GFDL-1.2-no-invariants-or-later + +OpenOCD licensing rules +======================= + +The OpenOCD source code is provided under the terms of the GNU General +Public License version 2 or later (GPL-2.0-or-later), as provided in +LICENSES/preferred/GPL-2.0. + +The OpenOCD documentation is provided under the terms of the GNU Free +Documentation License version 1.2 or later without Invariant Sections +(GFDL-1.2-no-invariants-or-later). + +Few stand-alone applications coexist in the same code tree of OpenOCD +and are provided under the terms of the GNU General Public License +version 3 (GPL-3.0), as provided in LICENSES/stand-alone/GPL-3.0. + +This documentation file provides a description of how each source file +should be annotated to make its license clear and unambiguous. +It doesn't replace the OpenOCD's license. + +The license described in the COPYING file applies to the OpenOCD source +as a whole, though individual source files can have a different license +which is required to be compatible with the GPL-2.0: + + GPL-1.0-or-later : GNU General Public License v1.0 or later + GPL-2.0-or-later : GNU General Public License v2.0 or later + LGPL-2.0 : GNU Library General Public License v2 only + LGPL-2.0-or-later : GNU Library General Public License v2 or later + LGPL-2.1 : GNU Lesser General Public License v2.1 only + LGPL-2.1-or-later : GNU Lesser General Public License v2.1 or later + +Aside from that, individual files can be provided under a dual license, +e.g. one of the compatible GPL variants and alternatively under a +permissive license like BSD, MIT etc. + +The common way of expressing the license of a source file is to add the +matching boilerplate text into the top comment of the file. Due to +formatting, typos etc. these "boilerplates" are hard to validate for +tools which are used in the context of license compliance. + +An alternative to boilerplate text is the use of Software Package Data +Exchange (SPDX) license identifiers in each source file. SPDX license +identifiers are machine parsable and precise shorthands for the license +under which the content of the file is contributed. SPDX license +identifiers are managed by the SPDX Workgroup at the Linux Foundation and +have been agreed on by partners throughout the industry, tool vendors, and +legal teams. For further information see https://spdx.org/ + +OpenOCD requires the precise SPDX identifier in all source files. +The valid identifiers used in OpenOCD are explained in the section +`License identifiers` and have been retrieved from the official SPDX +license list at https://spdx.org/licenses/ along with the license texts. + +License identifier syntax +------------------------- + +1. Placement: + + The SPDX license identifier in OpenOCD files shall be added at the + first possible line in a file which can contain a comment. For the + majority of files this is the first line, except for scripts which + require the '#!PATH_TO_INTERPRETER' in the first line. For those + scripts the SPDX identifier goes into the second line. + +2. Style: + + The SPDX license identifier is added in form of a comment. The comment + style depends on the file type:: + + C source: // SPDX-License-Identifier: + C header: /* SPDX-License-Identifier: */ + ASM: /* SPDX-License-Identifier: */ + makefiles: # SPDX-License-Identifier: + scripts: # SPDX-License-Identifier: + texinfo: @c SPDX-License-Identifier: + text: # SPDX-License-Identifier: + + If a specific tool cannot handle the standard comment style, then the + appropriate comment mechanism which the tool accepts shall be used. This + is the reason for having the "/\* \*/" style comment in C header + files. There was build breakage observed with generated .lds files where + 'ld' failed to parse the C++ comment. This has been fixed by now, but + there are still older assembler tools which cannot handle C++ style + comments. + +3. Syntax: + + A is either an SPDX short form license + identifier found on the SPDX License List, or the combination of two + SPDX short form license identifiers separated by "WITH" when a license + exception applies. When multiple licenses apply, an expression consists + of keywords "AND", "OR" separating sub-expressions and surrounded by + "(", ")" . + + License identifiers for licenses like [L]GPL with the 'or later' option + are constructed by using a "-or-later": + + // SPDX-License-Identifier: GPL-2.0-or-later + // SPDX-License-Identifier: LGPL-2.1-or-later + + WITH should be used when there is a modifier to a license needed. + Exceptions can only be used with particular License identifiers. The + valid License identifiers are listed in the tags of the exception text + file. + + OR should be used if the file is dual licensed and only one license is + to be selected. For example, some source files are available under dual + licenses: + + // SPDX-License-Identifier: GPL-2.0-or-later OR BSD-1-Clause + // SPDX-License-Identifier: GPL-2.0-or-later OR BSD-2-Clause + // SPDX-License-Identifier: GPL-2.0-or-later OR BSD-3-Clause + + AND should be used if the file has multiple licenses whose terms all + apply to use the file. For example, if code is inherited from another + project and permission has been given to put it in OpenOCD, but the + original license terms need to remain in effect:: + + // SPDX-License-Identifier: GPL-2.0-or-later AND MIT + +License identifiers +------------------- + +The licenses currently used, as well as the licenses for code added to +OpenOCD, can be broken down into: + +1. `Preferred licenses`: + + Whenever possible these licenses should be used as they are known to be + fully compatible and widely used. These licenses are available from the + directory: + + LICENSES/preferred/ + + in the OpenOCD source tree. + + The files in this directory contain the full license text and + `Metatags`. The file names are identical to the SPDX license + identifier which shall be used for the license in source files. + + Examples: + + LICENSES/preferred/GPL-2.0 + + Contains the GPL version 2 license text and the required metatags. + + `Metatags`: + + The following meta tags must be available in a license file: + + - Valid-License-Identifier: + + One or more lines which declare which License Identifiers are valid + inside the project to reference this particular license text. Usually + this is a single valid identifier, but e.g. for licenses with the 'or + later' options two identifiers are valid. + + - SPDX-URL: + + The URL of the SPDX page which contains additional information related + to the license. + + - Usage-Guidance: + + Freeform text for usage advice. The text must include correct examples + for the SPDX license identifiers as they should be put into source + files according to the `License identifier syntax` guidelines. + + - License-Text: + + All text after this tag is treated as the original license text + + File format examples:: + + Valid-License-Identifier: GPL-2.0 + Valid-License-Identifier: GPL-2.0-only + Valid-License-Identifier: GPL-2.0-or-later + SPDX-URL: https://spdx.org/licenses/GPL-2.0.html + Usage-Guide: + To use this license in source code, put one of the following SPDX + tag/value pairs into a comment according to the placement + guidelines in the licensing rules documentation. + For 'GNU General Public License (GPL) version 2 only' use: + SPDX-License-Identifier: GPL-2.0 + or + SPDX-License-Identifier: GPL-2.0-only + For 'GNU General Public License (GPL) version 2 or any later version' use: + SPDX-License-Identifier: GPL-2.0-or-later + License-Text: + Full license text + +2. Stand-alone licenses: + + These licenses should only be used for stand-alone applications that are + distributed with OpenOCD but are not included in the OpenOCD binary. + These licenses are available from the directory: + + LICENSES/stand-alone/ + + in the OpenOCD source tree. + + Examples: + + SPDX-License-Identifier: GPL-3.0 + +The format and requirements of the license files in the other sub-directories +of directory + + LICENSES + +have to follow the same format and requirements of the `Preferred licenses`. + +All SPDX license identifiers and exceptions must have a corresponding file +in the LICENSES subdirectories. This is required to allow tool +verification (e.g. checkpatch.pl) and to have the licenses ready to read +and extract right from the source, which is recommended by various FOSS +organizations, e.g. the `FSFE REUSE initiative `. diff --git a/LICENSES/preferred/BSD-1-Clause b/LICENSES/preferred/BSD-1-Clause new file mode 100644 index 000000000..c63b05bf5 --- /dev/null +++ b/LICENSES/preferred/BSD-1-Clause @@ -0,0 +1,28 @@ +Valid-License-Identifier: BSD-1-Clause +SPDX-URL: https://spdx.org/licenses/BSD-1-Clause.html +Usage-Guide: + To use the BSD 1-clause License put the following SPDX + tag/value pair into a comment according to the placement guidelines in + the licensing rules documentation: + SPDX-License-Identifier: BSD-1-Clause +License-Text: + +Copyright (c) . All rights reserved. + +Redistribution and use in source and binary forms, with or without +modification, are permitted provided that the following conditions are met: + +1. Redistributions of source code must retain the above copyright notice, + this list of conditions and the following disclaimer. + +THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" +AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE +IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE +ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE +LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR +CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF +SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS +INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN +CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) +ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE +POSSIBILITY OF SUCH DAMAGE. diff --git a/LICENSES/preferred/BSD-2-Clause b/LICENSES/preferred/BSD-2-Clause new file mode 100644 index 000000000..da366e2ce --- /dev/null +++ b/LICENSES/preferred/BSD-2-Clause @@ -0,0 +1,32 @@ +Valid-License-Identifier: BSD-2-Clause +SPDX-URL: https://spdx.org/licenses/BSD-2-Clause.html +Usage-Guide: + To use the BSD 2-clause "Simplified" License put the following SPDX + tag/value pair into a comment according to the placement guidelines in + the licensing rules documentation: + SPDX-License-Identifier: BSD-2-Clause +License-Text: + +Copyright (c) . All rights reserved. + +Redistribution and use in source and binary forms, with or without +modification, are permitted provided that the following conditions are met: + +1. Redistributions of source code must retain the above copyright notice, + this list of conditions and the following disclaimer. + +2. Redistributions in binary form must reproduce the above copyright + notice, this list of conditions and the following disclaimer in the + documentation and/or other materials provided with the distribution. + +THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" +AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE +IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE +ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE +LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR +CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF +SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS +INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN +CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) +ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE +POSSIBILITY OF SUCH DAMAGE. diff --git a/LICENSES/preferred/BSD-3-Clause b/LICENSES/preferred/BSD-3-Clause new file mode 100644 index 000000000..34c7f057c --- /dev/null +++ b/LICENSES/preferred/BSD-3-Clause @@ -0,0 +1,36 @@ +Valid-License-Identifier: BSD-3-Clause +SPDX-URL: https://spdx.org/licenses/BSD-3-Clause.html +Usage-Guide: + To use the BSD 3-clause "New" or "Revised" License put the following SPDX + tag/value pair into a comment according to the placement guidelines in + the licensing rules documentation: + SPDX-License-Identifier: BSD-3-Clause +License-Text: + +Copyright (c) . All rights reserved. + +Redistribution and use in source and binary forms, with or without +modification, are permitted provided that the following conditions are met: + +1. Redistributions of source code must retain the above copyright notice, + this list of conditions and the following disclaimer. + +2. Redistributions in binary form must reproduce the above copyright + notice, this list of conditions and the following disclaimer in the + documentation and/or other materials provided with the distribution. + +3. Neither the name of the copyright holder nor the names of its + contributors may be used to endorse or promote products derived from this + software without specific prior written permission. + +THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" +AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE +IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE +ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE +LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR +CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF +SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS +INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN +CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) +ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE +POSSIBILITY OF SUCH DAMAGE. diff --git a/LICENSES/preferred/GFDL-1.2 b/LICENSES/preferred/GFDL-1.2 new file mode 100644 index 000000000..9217d9c8e --- /dev/null +++ b/LICENSES/preferred/GFDL-1.2 @@ -0,0 +1,412 @@ +Valid-License-Identifier: GPL-2.0-or-later OR GFDL-1.2-no-invariants-or-later +Valid-License-Identifier: GFDL-1.2-no-invariants-or-later +SPDX-URL: https://spdx.org/licenses/GFDL-1.2-no-invariants-or-later.html +Usage-Guide: + The GNU Free Documentation License should only be used without + Invariant Sections, Front-Cover Texts or Back-Cover Texts. + It should not be used for new documents. + To use the license in source code, put the following SPDX tag/value pair + into a comment according to the placement guidelines in the licensing + rules documentation: + SPDX-License-Identifier: GPL-2.0-or-later OR GFDL-1.2-no-invariants-or-later + or + SPDX-License-Identifier: GFDL-1.2-no-invariants-or-later +License-Text: + + GNU Free Documentation License + Version 1.2, November 2002 + + + Copyright (C) 2000,2001,2002 Free Software Foundation, Inc. + 51 Franklin St, 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. + + +0. PREAMBLE + +The purpose of this License is to make a manual, textbook, or other +functional and useful document "free" in the sense of freedom: to +assure everyone the effective freedom to copy and redistribute it, +with or without modifying it, either commercially or noncommercially. +Secondarily, this License preserves for the author and publisher a way +to get credit for their work, while not being considered responsible +for modifications made by others. + +This License is a kind of "copyleft", which means that derivative +works of the document must themselves be free in the same sense. It +complements the GNU General Public License, which is a copyleft +license designed for free software. + +We have designed this License in order to use it for manuals for free +software, because free software needs free documentation: a free +program should come with manuals providing the same freedoms that the +software does. But this License is not limited to software manuals; +it can be used for any textual work, regardless of subject matter or +whether it is published as a printed book. We recommend this License +principally for works whose purpose is instruction or reference. + + +1. APPLICABILITY AND DEFINITIONS + +This License applies to any manual or other work, in any medium, that +contains a notice placed by the copyright holder saying it can be +distributed under the terms of this License. Such a notice grants a +world-wide, royalty-free license, unlimited in duration, to use that +work under the conditions stated herein. The "Document", below, +refers to any such manual or work. Any member of the public is a +licensee, and is addressed as "you". You accept the license if you +copy, modify or distribute the work in a way requiring permission +under copyright law. + +A "Modified Version" of the Document means any work containing the +Document or a portion of it, either copied verbatim, or with +modifications and/or translated into another language. + +A "Secondary Section" is a named appendix or a front-matter section of +the Document that deals exclusively with the relationship of the +publishers or authors of the Document to the Document's overall subject +(or to related matters) and contains nothing that could fall directly +within that overall subject. (Thus, if the Document is in part a +textbook of mathematics, a Secondary Section may not explain any +mathematics.) The relationship could be a matter of historical +connection with the subject or with related matters, or of legal, +commercial, philosophical, ethical or political position regarding +them. + +The "Invariant Sections" are certain Secondary Sections whose titles +are designated, as being those of Invariant Sections, in the notice +that says that the Document is released under this License. If a +section does not fit the above definition of Secondary then it is not +allowed to be designated as Invariant. The Document may contain zero +Invariant Sections. If the Document does not identify any Invariant +Sections then there are none. + +The "Cover Texts" are certain short passages of text that are listed, +as Front-Cover Texts or Back-Cover Texts, in the notice that says that +the Document is released under this License. A Front-Cover Text may +be at most 5 words, and a Back-Cover Text may be at most 25 words. + +A "Transparent" copy of the Document means a machine-readable copy, +represented in a format whose specification is available to the +general public, that is suitable for revising the document +straightforwardly with generic text editors or (for images composed of +pixels) generic paint programs or (for drawings) some widely available +drawing editor, and that is suitable for input to text formatters or +for automatic translation to a variety of formats suitable for input +to text formatters. A copy made in an otherwise Transparent file +format whose markup, or absence of markup, has been arranged to thwart +or discourage subsequent modification by readers is not Transparent. +An image format is not Transparent if used for any substantial amount +of text. A copy that is not "Transparent" is called "Opaque". + +Examples of suitable formats for Transparent copies include plain +ASCII without markup, Texinfo input format, LaTeX input format, SGML +or XML using a publicly available DTD, and standard-conforming simple +HTML, PostScript or PDF designed for human modification. Examples of +transparent image formats include PNG, XCF and JPG. Opaque formats +include proprietary formats that can be read and edited only by +proprietary word processors, SGML or XML for which the DTD and/or +processing tools are not generally available, and the +machine-generated HTML, PostScript or PDF produced by some word +processors for output purposes only. + +The "Title Page" means, for a printed book, the title page itself, +plus such following pages as are needed to hold, legibly, the material +this License requires to appear in the title page. For works in +formats which do not have any title page as such, "Title Page" means +the text near the most prominent appearance of the work's title, +preceding the beginning of the body of the text. + +A section "Entitled XYZ" means a named subunit of the Document whose +title either is precisely XYZ or contains XYZ in parentheses following +text that translates XYZ in another language. (Here XYZ stands for a +specific section name mentioned below, such as "Acknowledgements", +"Dedications", "Endorsements", or "History".) To "Preserve the Title" +of such a section when you modify the Document means that it remains a +section "Entitled XYZ" according to this definition. + +The Document may include Warranty Disclaimers next to the notice which +states that this License applies to the Document. These Warranty +Disclaimers are considered to be included by reference in this +License, but only as regards disclaiming warranties: any other +implication that these Warranty Disclaimers may have is void and has +no effect on the meaning of this License. + + +2. VERBATIM COPYING + +You may copy and distribute the Document in any medium, either +commercially or noncommercially, provided that this License, the +copyright notices, and the license notice saying this License applies +to the Document are reproduced in all copies, and that you add no other +conditions whatsoever to those of this License. You may not use +technical measures to obstruct or control the reading or further +copying of the copies you make or distribute. However, you may accept +compensation in exchange for copies. If you distribute a large enough +number of copies you must also follow the conditions in section 3. + +You may also lend copies, under the same conditions stated above, and +you may publicly display copies. + + +3. COPYING IN QUANTITY + +If you publish printed copies (or copies in media that commonly have +printed covers) of the Document, numbering more than 100, and the +Document's license notice requires Cover Texts, you must enclose the +copies in covers that carry, clearly and legibly, all these Cover +Texts: Front-Cover Texts on the front cover, and Back-Cover Texts on +the back cover. Both covers must also clearly and legibly identify +you as the publisher of these copies. The front cover must present +the full title with all words of the title equally prominent and +visible. You may add other material on the covers in addition. +Copying with changes limited to the covers, as long as they preserve +the title of the Document and satisfy these conditions, can be treated +as verbatim copying in other respects. + +If the required texts for either cover are too voluminous to fit +legibly, you should put the first ones listed (as many as fit +reasonably) on the actual cover, and continue the rest onto adjacent +pages. + +If you publish or distribute Opaque copies of the Document numbering +more than 100, you must either include a machine-readable Transparent +copy along with each Opaque copy, or state in or with each Opaque copy +a computer-network location from which the general network-using +public has access to download using public-standard network protocols +a complete Transparent copy of the Document, free of added material. +If you use the latter option, you must take reasonably prudent steps, +when you begin distribution of Opaque copies in quantity, to ensure +that this Transparent copy will remain thus accessible at the stated +location until at least one year after the last time you distribute an +Opaque copy (directly or through your agents or retailers) of that +edition to the public. + +It is requested, but not required, that you contact the authors of the +Document well before redistributing any large number of copies, to give +them a chance to provide you with an updated version of the Document. + + +4. MODIFICATIONS + +You may copy and distribute a Modified Version of the Document under +the conditions of sections 2 and 3 above, provided that you release +the Modified Version under precisely this License, with the Modified +Version filling the role of the Document, thus licensing distribution +and modification of the Modified Version to whoever possesses a copy +of it. In addition, you must do these things in the Modified Version: + +A. Use in the Title Page (and on the covers, if any) a title distinct + from that of the Document, and from those of previous versions + (which should, if there were any, be listed in the History section + of the Document). You may use the same title as a previous version + if the original publisher of that version gives permission. +B. List on the Title Page, as authors, one or more persons or entities + responsible for authorship of the modifications in the Modified + Version, together with at least five of the principal authors of the + Document (all of its principal authors, if it has fewer than five), + unless they release you from this requirement. +C. State on the Title page the name of the publisher of the + Modified Version, as the publisher. +D. Preserve all the copyright notices of the Document. +E. Add an appropriate copyright notice for your modifications + adjacent to the other copyright notices. +F. Include, immediately after the copyright notices, a license notice + giving the public permission to use the Modified Version under the + terms of this License, in the form shown in the Addendum below. +G. Preserve in that license notice the full lists of Invariant Sections + and required Cover Texts given in the Document's license notice. +H. Include an unaltered copy of this License. +I. Preserve the section Entitled "History", Preserve its Title, and add + to it an item stating at least the title, year, new authors, and + publisher of the Modified Version as given on the Title Page. If + there is no section Entitled "History" in the Document, create one + stating the title, year, authors, and publisher of the Document as + given on its Title Page, then add an item describing the Modified + Version as stated in the previous sentence. +J. Preserve the network location, if any, given in the Document for + public access to a Transparent copy of the Document, and likewise + the network locations given in the Document for previous versions + it was based on. These may be placed in the "History" section. + You may omit a network location for a work that was published at + least four years before the Document itself, or if the original + publisher of the version it refers to gives permission. +K. For any section Entitled "Acknowledgements" or "Dedications", + Preserve the Title of the section, and preserve in the section all + the substance and tone of each of the contributor acknowledgements + and/or dedications given therein. +L. Preserve all the Invariant Sections of the Document, + unaltered in their text and in their titles. Section numbers + or the equivalent are not considered part of the section titles. +M. Delete any section Entitled "Endorsements". Such a section + may not be included in the Modified Version. +N. Do not retitle any existing section to be Entitled "Endorsements" + or to conflict in title with any Invariant Section. +O. Preserve any Warranty Disclaimers. + +If the Modified Version includes new front-matter sections or +appendices that qualify as Secondary Sections and contain no material +copied from the Document, you may at your option designate some or all +of these sections as invariant. To do this, add their titles to the +list of Invariant Sections in the Modified Version's license notice. +These titles must be distinct from any other section titles. + +You may add a section Entitled "Endorsements", provided it contains +nothing but endorsements of your Modified Version by various +parties--for example, statements of peer review or that the text has +been approved by an organization as the authoritative definition of a +standard. + +You may add a passage of up to five words as a Front-Cover Text, and a +passage of up to 25 words as a Back-Cover Text, to the end of the list +of Cover Texts in the Modified Version. Only one passage of +Front-Cover Text and one of Back-Cover Text may be added by (or +through arrangements made by) any one entity. If the Document already +includes a cover text for the same cover, previously added by you or +by arrangement made by the same entity you are acting on behalf of, +you may not add another; but you may replace the old one, on explicit +permission from the previous publisher that added the old one. + +The author(s) and publisher(s) of the Document do not by this License +give permission to use their names for publicity for or to assert or +imply endorsement of any Modified Version. + + +5. COMBINING DOCUMENTS + +You may combine the Document with other documents released under this +License, under the terms defined in section 4 above for modified +versions, provided that you include in the combination all of the +Invariant Sections of all of the original documents, unmodified, and +list them all as Invariant Sections of your combined work in its +license notice, and that you preserve all their Warranty Disclaimers. + +The combined work need only contain one copy of this License, and +multiple identical Invariant Sections may be replaced with a single +copy. If there are multiple Invariant Sections with the same name but +different contents, make the title of each such section unique by +adding at the end of it, in parentheses, the name of the original +author or publisher of that section if known, or else a unique number. +Make the same adjustment to the section titles in the list of +Invariant Sections in the license notice of the combined work. + +In the combination, you must combine any sections Entitled "History" +in the various original documents, forming one section Entitled +"History"; likewise combine any sections Entitled "Acknowledgements", +and any sections Entitled "Dedications". You must delete all sections +Entitled "Endorsements". + + +6. COLLECTIONS OF DOCUMENTS + +You may make a collection consisting of the Document and other documents +released under this License, and replace the individual copies of this +License in the various documents with a single copy that is included in +the collection, provided that you follow the rules of this License for +verbatim copying of each of the documents in all other respects. + +You may extract a single document from such a collection, and distribute +it individually under this License, provided you insert a copy of this +License into the extracted document, and follow this License in all +other respects regarding verbatim copying of that document. + + +7. AGGREGATION WITH INDEPENDENT WORKS + +A compilation of the Document or its derivatives with other separate +and independent documents or works, in or on a volume of a storage or +distribution medium, is called an "aggregate" if the copyright +resulting from the compilation is not used to limit the legal rights +of the compilation's users beyond what the individual works permit. +When the Document is included in an aggregate, this License does not +apply to the other works in the aggregate which are not themselves +derivative works of the Document. + +If the Cover Text requirement of section 3 is applicable to these +copies of the Document, then if the Document is less than one half of +the entire aggregate, the Document's Cover Texts may be placed on +covers that bracket the Document within the aggregate, or the +electronic equivalent of covers if the Document is in electronic form. +Otherwise they must appear on printed covers that bracket the whole +aggregate. + + +8. TRANSLATION + +Translation is considered a kind of modification, so you may +distribute translations of the Document under the terms of section 4. +Replacing Invariant Sections with translations requires special +permission from their copyright holders, but you may include +translations of some or all Invariant Sections in addition to the +original versions of these Invariant Sections. You may include a +translation of this License, and all the license notices in the +Document, and any Warranty Disclaimers, provided that you also include +the original English version of this License and the original versions +of those notices and disclaimers. In case of a disagreement between +the translation and the original version of this License or a notice +or disclaimer, the original version will prevail. + +If a section in the Document is Entitled "Acknowledgements", +"Dedications", or "History", the requirement (section 4) to Preserve +its Title (section 1) will typically require changing the actual +title. + + +9. TERMINATION + +You may not copy, modify, sublicense, or distribute the Document except +as expressly provided for under this License. Any other attempt to +copy, modify, sublicense or distribute the Document 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. + + +10. FUTURE REVISIONS OF THIS LICENSE + +The Free Software Foundation may publish new, revised versions +of the GNU Free Documentation 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. See +https://www.gnu.org/licenses/. + +Each version of the License is given a distinguishing version number. +If the Document specifies that a particular numbered version of this +License "or any later version" applies to it, you have the option of +following the terms and conditions either of that specified version or +of any later version that has been published (not as a draft) by the +Free Software Foundation. If the Document does not specify a version +number of this License, you may choose any version ever published (not +as a draft) by the Free Software Foundation. + + +ADDENDUM: How to use this License for your documents + +To use this License in a document you have written, include a copy of +the License in the document and put the following copyright and +license notices just after the title page: + + Copyright (c) YEAR YOUR NAME. + Permission is granted to copy, distribute and/or modify this document + under the terms of the GNU Free Documentation License, Version 1.2 + or any later version published by the Free Software Foundation; + with no Invariant Sections, no Front-Cover Texts, and no Back-Cover Texts. + A copy of the license is included in the section entitled "GNU + Free Documentation License". + +If you have Invariant Sections, Front-Cover Texts and Back-Cover Texts, +replace the "with...Texts." line with this: + + with the Invariant Sections being LIST THEIR TITLES, with the + Front-Cover Texts being LIST, and with the Back-Cover Texts being LIST. + +If you have Invariant Sections without Cover Texts, or some other +combination of the three, merge those two alternatives to suit the +situation. + +If your document contains nontrivial examples of program code, we +recommend releasing these examples in parallel under your choice of +free software license, such as the GNU General Public License, +to permit their use in free software. diff --git a/LICENSES/preferred/GPL-2.0 b/LICENSES/preferred/GPL-2.0 new file mode 100644 index 000000000..2ca4651c3 --- /dev/null +++ b/LICENSES/preferred/GPL-2.0 @@ -0,0 +1,355 @@ +Valid-License-Identifier: GPL-2.0 +Valid-License-Identifier: GPL-2.0-only +Valid-License-Identifier: GPL-2.0-or-later +SPDX-URL: https://spdx.org/licenses/GPL-2.0.html +Usage-Guide: + To use this license in source code, put one of the following SPDX + tag/value pairs into a comment according to the placement + guidelines in the licensing rules documentation. + For 'GNU General Public License (GPL) version 2 only' use: + SPDX-License-Identifier: GPL-2.0 + or + SPDX-License-Identifier: GPL-2.0-only + For 'GNU General Public License (GPL) version 2 or any later version' use: + SPDX-License-Identifier: GPL-2.0-or-later +License-Text: + + 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. + + 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, write to the Free Software Foundation, Inc., + 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. + +Also add information on how to contact you by electronic and paper mail. + +If the program is interactive, make it output a short notice like this +when it starts in an interactive mode: + + Gnomovision version 69, Copyright (C) year name of author + Gnomovision comes with ABSOLUTELY NO WARRANTY; for details type `show w'. + This is free software, and you are welcome to redistribute it + under certain conditions; type `show c' for details. + +The hypothetical commands `show w' and `show c' should show the appropriate +parts of the General Public License. Of course, the commands you use may +be called something other than `show w' and `show c'; they could even be +mouse-clicks or menu items--whatever suits your program. + +You should also get your employer (if you work as a programmer) or your +school, if any, to sign a "copyright disclaimer" for the program, if +necessary. Here is a sample; alter the names: + + Yoyodyne, Inc., hereby disclaims all copyright interest in the program + `Gnomovision' (which makes passes at compilers) written by James Hacker. + + , 1 April 1989 + Ty Coon, 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/preferred/gfdl-1.2.texi.readme b/LICENSES/preferred/gfdl-1.2.texi.readme new file mode 100644 index 000000000..9375c7913 --- /dev/null +++ b/LICENSES/preferred/gfdl-1.2.texi.readme @@ -0,0 +1,4 @@ +# SPDX-License-Identifier: GPL-2.0-or-later OR GFDL-1.2-no-invariants-or-later + +The texinfo version of the license gfdl-1.2 is distributed in the +file doc/fdl.texi . diff --git a/LICENSES/stand-alone/GPL-3.0 b/LICENSES/stand-alone/GPL-3.0 new file mode 100644 index 000000000..97dde3ee8 --- /dev/null +++ b/LICENSES/stand-alone/GPL-3.0 @@ -0,0 +1,690 @@ +Valid-License-Identifier: GPL-3.0 +Valid-License-Identifier: GPL-3.0-only +Valid-License-Identifier: GPL-3.0-or-later +SPDX-URL: https://spdx.org/licenses/GPL-3.0.html +Usage-Guide: + To use this license in source code, put one of the following SPDX + tag/value pairs into a comment according to the placement + guidelines in the licensing rules documentation. + For 'GNU General Public License (GPL) version 3 only' use: + SPDX-License-Identifier: GPL-3.0 + or + SPDX-License-Identifier: GPL-3.0-only + For 'GNU General Public License (GPL) version 3 or any later version' use: + SPDX-License-Identifier: GPL-3.0-or-later +License-Text: + + GNU GENERAL PUBLIC LICENSE + Version 3, 29 June 2007 + + Copyright (C) 2007 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 GNU General Public License is a free, copyleft license for +software and other kinds of works. + + The licenses for most software and other practical works are designed +to take away your freedom to share and change the works. By contrast, +the GNU General Public License is intended to guarantee your freedom to +share and change all versions of a program--to make sure it remains free +software for all its users. We, the Free Software Foundation, use the +GNU General Public License for most of our software; it applies also to +any other work released this way by its authors. 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 +them 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 prevent others from denying you +these rights or asking you to surrender the rights. Therefore, you have +certain responsibilities if you distribute copies of the software, or if +you modify it: responsibilities to respect the freedom of others. + + For example, if you distribute copies of such a program, whether +gratis or for a fee, you must pass on to the recipients the same +freedoms that you received. 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. + + Developers that use the GNU GPL protect your rights with two steps: +(1) assert copyright on the software, and (2) offer you this License +giving you legal permission to copy, distribute and/or modify it. + + For the developers' and authors' protection, the GPL clearly explains +that there is no warranty for this free software. For both users' and +authors' sake, the GPL requires that modified versions be marked as +changed, so that their problems will not be attributed erroneously to +authors of previous versions. + + Some devices are designed to deny users access to install or run +modified versions of the software inside them, although the manufacturer +can do so. This is fundamentally incompatible with the aim of +protecting users' freedom to change the software. The systematic +pattern of such abuse occurs in the area of products for individuals to +use, which is precisely where it is most unacceptable. Therefore, we +have designed this version of the GPL to prohibit the practice for those +products. If such problems arise substantially in other domains, we +stand ready to extend this provision to those domains in future versions +of the GPL, as needed to protect the freedom of users. + + Finally, every program is threatened constantly by software patents. +States should not allow patents to restrict development and use of +software on general-purpose computers, but in those that do, we wish to +avoid the special danger that patents applied to a free program could +make it effectively proprietary. To prevent this, the GPL assures that +patents cannot be used to render the program non-free. + + The precise terms and conditions for copying, distribution and +modification follow. + + TERMS AND CONDITIONS + + 0. Definitions. + + "This License" refers to version 3 of the GNU General Public License. + + "Copyright" also means copyright-like laws that apply to other kinds of +works, such as semiconductor masks. + + "The Program" refers to any copyrightable work licensed under this +License. Each licensee is addressed as "you". "Licensees" and +"recipients" may be individuals or organizations. + + To "modify" a work means to copy from or adapt all or part of the work +in a fashion requiring copyright permission, other than the making of an +exact copy. The resulting work is called a "modified version" of the +earlier work or a work "based on" the earlier work. + + A "covered work" means either the unmodified Program or a work based +on the Program. + + To "propagate" a work means to do anything with it that, without +permission, would make you directly or secondarily liable for +infringement under applicable copyright law, except executing it on a +computer or modifying a private copy. Propagation includes copying, +distribution (with or without modification), making available to the +public, and in some countries other activities as well. + + To "convey" a work means any kind of propagation that enables other +parties to make or receive copies. Mere interaction with a user through +a computer network, with no transfer of a copy, is not conveying. + + An interactive user interface displays "Appropriate Legal Notices" +to the extent that it includes a convenient and prominently visible +feature that (1) displays an appropriate copyright notice, and (2) +tells the user that there is no warranty for the work (except to the +extent that warranties are provided), that licensees may convey the +work under this License, and how to view a copy of this License. If +the interface presents a list of user commands or options, such as a +menu, a prominent item in the list meets this criterion. + + 1. Source Code. + + The "source code" for a work means the preferred form of the work +for making modifications to it. "Object code" means any non-source +form of a work. + + A "Standard Interface" means an interface that either is an official +standard defined by a recognized standards body, or, in the case of +interfaces specified for a particular programming language, one that +is widely used among developers working in that language. + + The "System Libraries" of an executable work include anything, other +than the work as a whole, that (a) is included in the normal form of +packaging a Major Component, but which is not part of that Major +Component, and (b) serves only to enable use of the work with that +Major Component, or to implement a Standard Interface for which an +implementation is available to the public in source code form. A +"Major Component", in this context, means a major essential component +(kernel, window system, and so on) of the specific operating system +(if any) on which the executable work runs, or a compiler used to +produce the work, or an object code interpreter used to run it. + + The "Corresponding Source" for a work in object code form means all +the source code needed to generate, install, and (for an executable +work) run the object code and to modify the work, including scripts to +control those activities. However, it does not include the work's +System Libraries, or general-purpose tools or generally available free +programs which are used unmodified in performing those activities but +which are not part of the work. For example, Corresponding Source +includes interface definition files associated with source files for +the work, and the source code for shared libraries and dynamically +linked subprograms that the work is specifically designed to require, +such as by intimate data communication or control flow between those +subprograms and other parts of the work. + + The Corresponding Source need not include anything that users +can regenerate automatically from other parts of the Corresponding +Source. + + The Corresponding Source for a work in source code form is that +same work. + + 2. Basic Permissions. + + All rights granted under this License are granted for the term of +copyright on the Program, and are irrevocable provided the stated +conditions are met. This License explicitly affirms your unlimited +permission to run the unmodified Program. The output from running a +covered work is covered by this License only if the output, given its +content, constitutes a covered work. This License acknowledges your +rights of fair use or other equivalent, as provided by copyright law. + + You may make, run and propagate covered works that you do not +convey, without conditions so long as your license otherwise remains +in force. You may convey covered works to others for the sole purpose +of having them make modifications exclusively for you, or provide you +with facilities for running those works, provided that you comply with +the terms of this License in conveying all material for which you do +not control copyright. Those thus making or running the covered works +for you must do so exclusively on your behalf, under your direction +and control, on terms that prohibit them from making any copies of +your copyrighted material outside their relationship with you. + + Conveying under any other circumstances is permitted solely under +the conditions stated below. Sublicensing is not allowed; section 10 +makes it unnecessary. + + 3. Protecting Users' Legal Rights From Anti-Circumvention Law. + + No covered work shall be deemed part of an effective technological +measure under any applicable law fulfilling obligations under article +11 of the WIPO copyright treaty adopted on 20 December 1996, or +similar laws prohibiting or restricting circumvention of such +measures. + + When you convey a covered work, you waive any legal power to forbid +circumvention of technological measures to the extent such circumvention +is effected by exercising rights under this License with respect to +the covered work, and you disclaim any intention to limit operation or +modification of the work as a means of enforcing, against the work's +users, your or third parties' legal rights to forbid circumvention of +technological measures. + + 4. Conveying Verbatim Copies. + + You may convey 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; +keep intact all notices stating that this License and any +non-permissive terms added in accord with section 7 apply to the code; +keep intact all notices of the absence of any warranty; and give all +recipients a copy of this License along with the Program. + + You may charge any price or no price for each copy that you convey, +and you may offer support or warranty protection for a fee. + + 5. Conveying Modified Source Versions. + + You may convey a work based on the Program, or the modifications to +produce it from the Program, in the form of source code under the +terms of section 4, provided that you also meet all of these conditions: + + a) The work must carry prominent notices stating that you modified + it, and giving a relevant date. + + b) The work must carry prominent notices stating that it is + released under this License and any conditions added under section + 7. This requirement modifies the requirement in section 4 to + "keep intact all notices". + + c) You must license the entire work, as a whole, under this + License to anyone who comes into possession of a copy. This + License will therefore apply, along with any applicable section 7 + additional terms, to the whole of the work, and all its parts, + regardless of how they are packaged. This License gives no + permission to license the work in any other way, but it does not + invalidate such permission if you have separately received it. + + d) If the work has interactive user interfaces, each must display + Appropriate Legal Notices; however, if the Program has interactive + interfaces that do not display Appropriate Legal Notices, your + work need not make them do so. + + A compilation of a covered work with other separate and independent +works, which are not by their nature extensions of the covered work, +and which are not combined with it such as to form a larger program, +in or on a volume of a storage or distribution medium, is called an +"aggregate" if the compilation and its resulting copyright are not +used to limit the access or legal rights of the compilation's users +beyond what the individual works permit. Inclusion of a covered work +in an aggregate does not cause this License to apply to the other +parts of the aggregate. + + 6. Conveying Non-Source Forms. + + You may convey a covered work in object code form under the terms +of sections 4 and 5, provided that you also convey the +machine-readable Corresponding Source under the terms of this License, +in one of these ways: + + a) Convey the object code in, or embodied in, a physical product + (including a physical distribution medium), accompanied by the + Corresponding Source fixed on a durable physical medium + customarily used for software interchange. + + b) Convey the object code in, or embodied in, a physical product + (including a physical distribution medium), accompanied by a + written offer, valid for at least three years and valid for as + long as you offer spare parts or customer support for that product + model, to give anyone who possesses the object code either (1) a + copy of the Corresponding Source for all the software in the + product that is covered by this License, on a durable physical + medium customarily used for software interchange, for a price no + more than your reasonable cost of physically performing this + conveying of source, or (2) access to copy the + Corresponding Source from a network server at no charge. + + c) Convey individual copies of the object code with a copy of the + written offer to provide the Corresponding Source. This + alternative is allowed only occasionally and noncommercially, and + only if you received the object code with such an offer, in accord + with subsection 6b. + + d) Convey the object code by offering access from a designated + place (gratis or for a charge), and offer equivalent access to the + Corresponding Source in the same way through the same place at no + further charge. You need not require recipients to copy the + Corresponding Source along with the object code. If the place to + copy the object code is a network server, the Corresponding Source + may be on a different server (operated by you or a third party) + that supports equivalent copying facilities, provided you maintain + clear directions next to the object code saying where to find the + Corresponding Source. Regardless of what server hosts the + Corresponding Source, you remain obligated to ensure that it is + available for as long as needed to satisfy these requirements. + + e) Convey the object code using peer-to-peer transmission, provided + you inform other peers where the object code and Corresponding + Source of the work are being offered to the general public at no + charge under subsection 6d. + + A separable portion of the object code, whose source code is excluded +from the Corresponding Source as a System Library, need not be +included in conveying the object code work. + + A "User Product" is either (1) a "consumer product", which means any +tangible personal property which is normally used for personal, family, +or household purposes, or (2) anything designed or sold for incorporation +into a dwelling. In determining whether a product is a consumer product, +doubtful cases shall be resolved in favor of coverage. For a particular +product received by a particular user, "normally used" refers to a +typical or common use of that class of product, regardless of the status +of the particular user or of the way in which the particular user +actually uses, or expects or is expected to use, the product. A product +is a consumer product regardless of whether the product has substantial +commercial, industrial or non-consumer uses, unless such uses represent +the only significant mode of use of the product. + + "Installation Information" for a User Product means any methods, +procedures, authorization keys, or other information required to install +and execute modified versions of a covered work in that User Product from +a modified version of its Corresponding Source. The information must +suffice to ensure that the continued functioning of the modified object +code is in no case prevented or interfered with solely because +modification has been made. + + If you convey an object code work under this section in, or with, or +specifically for use in, a User Product, and the conveying occurs as +part of a transaction in which the right of possession and use of the +User Product is transferred to the recipient in perpetuity or for a +fixed term (regardless of how the transaction is characterized), the +Corresponding Source conveyed under this section must be accompanied +by the Installation Information. But this requirement does not apply +if neither you nor any third party retains the ability to install +modified object code on the User Product (for example, the work has +been installed in ROM). + + The requirement to provide Installation Information does not include a +requirement to continue to provide support service, warranty, or updates +for a work that has been modified or installed by the recipient, or for +the User Product in which it has been modified or installed. Access to a +network may be denied when the modification itself materially and +adversely affects the operation of the network or violates the rules and +protocols for communication across the network. + + Corresponding Source conveyed, and Installation Information provided, +in accord with this section must be in a format that is publicly +documented (and with an implementation available to the public in +source code form), and must require no special password or key for +unpacking, reading or copying. + + 7. Additional Terms. + + "Additional permissions" are terms that supplement the terms of this +License by making exceptions from one or more of its conditions. +Additional permissions that are applicable to the entire Program shall +be treated as though they were included in this License, to the extent +that they are valid under applicable law. If additional permissions +apply only to part of the Program, that part may be used separately +under those permissions, but the entire Program remains governed by +this License without regard to the additional permissions. + + When you convey a copy of a covered work, you may at your option +remove any additional permissions from that copy, or from any part of +it. (Additional permissions may be written to require their own +removal in certain cases when you modify the work.) You may place +additional permissions on material, added by you to a covered work, +for which you have or can give appropriate copyright permission. + + Notwithstanding any other provision of this License, for material you +add to a covered work, you may (if authorized by the copyright holders of +that material) supplement the terms of this License with terms: + + a) Disclaiming warranty or limiting liability differently from the + terms of sections 15 and 16 of this License; or + + b) Requiring preservation of specified reasonable legal notices or + author attributions in that material or in the Appropriate Legal + Notices displayed by works containing it; or + + c) Prohibiting misrepresentation of the origin of that material, or + requiring that modified versions of such material be marked in + reasonable ways as different from the original version; or + + d) Limiting the use for publicity purposes of names of licensors or + authors of the material; or + + e) Declining to grant rights under trademark law for use of some + trade names, trademarks, or service marks; or + + f) Requiring indemnification of licensors and authors of that + material by anyone who conveys the material (or modified versions of + it) with contractual assumptions of liability to the recipient, for + any liability that these contractual assumptions directly impose on + those licensors and authors. + + All other non-permissive additional terms are considered "further +restrictions" within the meaning of section 10. If the Program as you +received it, or any part of it, contains a notice stating that it is +governed by this License along with a term that is a further +restriction, you may remove that term. If a license document contains +a further restriction but permits relicensing or conveying under this +License, you may add to a covered work material governed by the terms +of that license document, provided that the further restriction does +not survive such relicensing or conveying. + + If you add terms to a covered work in accord with this section, you +must place, in the relevant source files, a statement of the +additional terms that apply to those files, or a notice indicating +where to find the applicable terms. + + Additional terms, permissive or non-permissive, may be stated in the +form of a separately written license, or stated as exceptions; +the above requirements apply either way. + + 8. Termination. + + You may not propagate or modify a covered work except as expressly +provided under this License. Any attempt otherwise to propagate or +modify it is void, and will automatically terminate your rights under +this License (including any patent licenses granted under the third +paragraph of section 11). + + However, if you cease all violation of this License, then your +license from a particular copyright holder is reinstated (a) +provisionally, unless and until the copyright holder explicitly and +finally terminates your license, and (b) permanently, if the copyright +holder fails to notify you of the violation by some reasonable means +prior to 60 days after the cessation. + + Moreover, your license from a particular copyright holder is +reinstated permanently if the copyright holder notifies you of the +violation by some reasonable means, this is the first time you have +received notice of violation of this License (for any work) from that +copyright holder, and you cure the violation prior to 30 days after +your receipt of the notice. + + Termination of your rights under this section does not terminate the +licenses of parties who have received copies or rights from you under +this License. If your rights have been terminated and not permanently +reinstated, you do not qualify to receive new licenses for the same +material under section 10. + + 9. Acceptance Not Required for Having Copies. + + You are not required to accept this License in order to receive or +run a copy of the Program. Ancillary propagation of a covered work +occurring solely as a consequence of using peer-to-peer transmission +to receive a copy likewise does not require acceptance. However, +nothing other than this License grants you permission to propagate or +modify any covered work. These actions infringe copyright if you do +not accept this License. Therefore, by modifying or propagating a +covered work, you indicate your acceptance of this License to do so. + + 10. Automatic Licensing of Downstream Recipients. + + Each time you convey a covered work, the recipient automatically +receives a license from the original licensors, to run, modify and +propagate that work, subject to this License. You are not responsible +for enforcing compliance by third parties with this License. + + An "entity transaction" is a transaction transferring control of an +organization, or substantially all assets of one, or subdividing an +organization, or merging organizations. If propagation of a covered +work results from an entity transaction, each party to that +transaction who receives a copy of the work also receives whatever +licenses to the work the party's predecessor in interest had or could +give under the previous paragraph, plus a right to possession of the +Corresponding Source of the work from the predecessor in interest, if +the predecessor has it or can get it with reasonable efforts. + + You may not impose any further restrictions on the exercise of the +rights granted or affirmed under this License. For example, you may +not impose a license fee, royalty, or other charge for exercise of +rights granted under this License, and you may not initiate litigation +(including a cross-claim or counterclaim in a lawsuit) alleging that +any patent claim is infringed by making, using, selling, offering for +sale, or importing the Program or any portion of it. + + 11. Patents. + + A "contributor" is a copyright holder who authorizes use under this +License of the Program or a work on which the Program is based. The +work thus licensed is called the contributor's "contributor version". + + A contributor's "essential patent claims" are all patent claims +owned or controlled by the contributor, whether already acquired or +hereafter acquired, that would be infringed by some manner, permitted +by this License, of making, using, or selling its contributor version, +but do not include claims that would be infringed only as a +consequence of further modification of the contributor version. For +purposes of this definition, "control" includes the right to grant +patent sublicenses in a manner consistent with the requirements of +this License. + + Each contributor grants you a non-exclusive, worldwide, royalty-free +patent license under the contributor's essential patent claims, to +make, use, sell, offer for sale, import and otherwise run, modify and +propagate the contents of its contributor version. + + In the following three paragraphs, a "patent license" is any express +agreement or commitment, however denominated, not to enforce a patent +(such as an express permission to practice a patent or covenant not to +sue for patent infringement). To "grant" such a patent license to a +party means to make such an agreement or commitment not to enforce a +patent against the party. + + If you convey a covered work, knowingly relying on a patent license, +and the Corresponding Source of the work is not available for anyone +to copy, free of charge and under the terms of this License, through a +publicly available network server or other readily accessible means, +then you must either (1) cause the Corresponding Source to be so +available, or (2) arrange to deprive yourself of the benefit of the +patent license for this particular work, or (3) arrange, in a manner +consistent with the requirements of this License, to extend the patent +license to downstream recipients. "Knowingly relying" means you have +actual knowledge that, but for the patent license, your conveying the +covered work in a country, or your recipient's use of the covered work +in a country, would infringe one or more identifiable patents in that +country that you have reason to believe are valid. + + If, pursuant to or in connection with a single transaction or +arrangement, you convey, or propagate by procuring conveyance of, a +covered work, and grant a patent license to some of the parties +receiving the covered work authorizing them to use, propagate, modify +or convey a specific copy of the covered work, then the patent license +you grant is automatically extended to all recipients of the covered +work and works based on it. + + A patent license is "discriminatory" if it does not include within +the scope of its coverage, prohibits the exercise of, or is +conditioned on the non-exercise of one or more of the rights that are +specifically granted under this License. You may not convey a covered +work if you are a party to an arrangement with a third party that is +in the business of distributing software, under which you make payment +to the third party based on the extent of your activity of conveying +the work, and under which the third party grants, to any of the +parties who would receive the covered work from you, a discriminatory +patent license (a) in connection with copies of the covered work +conveyed by you (or copies made from those copies), or (b) primarily +for and in connection with specific products or compilations that +contain the covered work, unless you entered into that arrangement, +or that patent license was granted, prior to 28 March 2007. + + Nothing in this License shall be construed as excluding or limiting +any implied license or other defenses to infringement that may +otherwise be available to you under applicable patent law. + + 12. No Surrender of Others' Freedom. + + If 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 convey a +covered work so as to satisfy simultaneously your obligations under this +License and any other pertinent obligations, then as a consequence you may +not convey it at all. For example, if you agree to terms that obligate you +to collect a royalty for further conveying from those to whom you convey +the Program, the only way you could satisfy both those terms and this +License would be to refrain entirely from conveying the Program. + + 13. Use with the GNU Affero General Public License. + + Notwithstanding any other provision of this License, you have +permission to link or combine any covered work with a work licensed +under version 3 of the GNU Affero General Public License into a single +combined work, and to convey the resulting work. The terms of this +License will continue to apply to the part which is the covered work, +but the special requirements of the GNU Affero General Public License, +section 13, concerning interaction through a network will apply to the +combination as such. + + 14. Revised Versions of this License. + + The Free Software Foundation may publish revised and/or new versions of +the GNU 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 that a certain numbered version of the GNU General +Public License "or any later version" applies to it, you have the +option of following the terms and conditions either of that numbered +version or of any later version published by the Free Software +Foundation. If the Program does not specify a version number of the +GNU General Public License, you may choose any version ever published +by the Free Software Foundation. + + If the Program specifies that a proxy can decide which future +versions of the GNU General Public License can be used, that proxy's +public statement of acceptance of a version permanently authorizes you +to choose that version for the Program. + + Later license versions may give you additional or different +permissions. However, no additional obligations are imposed on any +author or copyright holder as a result of your choosing to follow a +later version. + + 15. Disclaimer of Warranty. + + 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. + + 16. Limitation of Liability. + + IN NO EVENT UNLESS REQUIRED BY APPLICABLE LAW OR AGREED TO IN WRITING +WILL ANY COPYRIGHT HOLDER, OR ANY OTHER PARTY WHO MODIFIES AND/OR CONVEYS +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. + + 17. Interpretation of Sections 15 and 16. + + If the disclaimer of warranty and limitation of liability provided +above cannot be given local legal effect according to their terms, +reviewing courts shall apply local law that most closely approximates +an absolute waiver of all civil liability in connection with the +Program, unless a warranty or assumption of liability accompanies a +copy of the Program in return for a fee. + + 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 +state 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 3 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 does terminal interaction, make it output a short +notice like this when it starts in an interactive mode: + + Copyright (C) + This program 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, your program's commands +might be different; for a GUI interface, you would use an "about box". + + You should also get your employer (if you work as a programmer) or school, +if any, to sign a "copyright disclaimer" for the program, if necessary. +For more information on this, and how to apply and follow the GNU GPL, see +. + + The GNU 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. But first, please read +. diff --git a/Makefile.am b/Makefile.am index 5d699b934..26ce1362e 100644 --- a/Makefile.am +++ b/Makefile.am @@ -44,7 +44,6 @@ if INTERNAL_JIMTCL AM_CPPFLAGS += -I$(top_srcdir)/jimtcl \ -I$(top_builddir)/jimtcl endif -EXTRA_DIST_NEWS != ls $(srcdir)/NEWS-* EXTRA_DIST += \ BUGS \ HACKING \ @@ -53,6 +52,14 @@ EXTRA_DIST += \ README.macOS \ $(EXTRA_DIST_NEWS) \ Doxyfile.in \ + LICENSES/license-rules.txt \ + LICENSES/preferred/BSD-1-Clause \ + LICENSES/preferred/BSD-2-Clause \ + LICENSES/preferred/BSD-3-Clause \ + LICENSES/preferred/GFDL-1.2 \ + LICENSES/preferred/gfdl-1.2.texi.readme \ + LICENSES/preferred/GPL-2.0 \ + LICENSES/stand-alone/GPL-3.0 \ tools/logger.pl \ tools/rlink_make_speed_table \ tools/st7_dtc_as \ @@ -118,6 +125,8 @@ uninstall-hook: distclean-local: rm -rf Doxyfile doxygen rm -f $(srcdir)/jimtcl/configure.gnu +# FIXME: workaround for jimtcl 0.80 only. Remove from jimtcl 0.81 + rm -f jimtcl/examples.api/Makefile # We want every change to have Signed-off-by. This is tricky to enforce in # Travis, because it automatically makes temporary commits when merging. So diff --git a/NEWS b/NEWS index 36ee8fd2e..9db6c5fee 100644 --- a/NEWS +++ b/NEWS @@ -2,232 +2,29 @@ This file includes highlights of the changes made in the OpenOCD source archive release. JTAG Layer: - * add debug level 4 for verbose I/O debug - * bitbang, add read buffer to improve performance - * Cadence SystemVerilog Direct Programming Interface (DPI) adapter driver - * CMSIS-DAP v2 (USB bulk based) adapter driver - * Cypress KitProg adapter driver - * FTDI FT232R sync bitbang adapter driver - * Linux GPIOD bitbang adapter driver through libgpiod - * Mellanox rshim USB or PCIe adapter driver - * Nuvoton Nu-Link and Nu-Link2 adapter drivers - * NXP IMX GPIO mmap based adapter driver - * ST-Link consolidate all versions in single config - * ST-Link read properly old USB serial numbers - * STLink/V3 support (for ST devices only !) - * STM8 SWIM transport - * TI XDS110 adapter driver - * Xilinx XVC/PCIe adapter driver Boundary Scan: Target Layer: - * 64 bit address support - * ARCv2 target support - * ARM Cortex-A hypervisor mode support - * ARM Cortex-M fast PC sampling support for profiling - * ARM generic CTI support - * ARM generic mem-ap target support - * ARMv7-A MMU tools - * ARMv7m traces add TCP stream server - * ARMv8 AARCH64 target support and semihosting support - * ARMv8 AARCH64 disassembler support through capstone library - * ARMv8-M target support - * EnSilica eSi-RISC target support, including instruction tracing - eSi-Trace support - * MIPS64 target support - * Motorola SREC S6 record image file support - * RISC-V target support - * SEGGER Real Time Transfer (RTT) initial support (for single target, - Cortex-M only) - * ST STM8 target support - * Various MIPS32 target improvements Flash Layer: - * Atheros (ath79) SPI interface support - * Atmel atmega128rfa1 support - * Atmel SAM D21, D51, DA1, E51, E53, E54, G55, R30 support - * Atmel SAMC2?N* support - * Cypress PSoC5LP, PSoC6 support - * EnSilica eSi-RISC support - * Foshan Synwit Tech SWM050 support - * Maxim Integrated MAX32XXX support - * Nordic Semiconductor nRF51822, nRF52810, nRF52832 support - * NXP Kinetis K27, K28, KE1x, KEAx, KL28, KL8x, KV5x, KWx support - * Renesas RPC HF support - * SH QSPI support - * SiFive Freedom E support - * Silicon Labs EFR-family, EZR32HG support - * ST BlueNRG support - * ST STM32 QUAD/OCTO-SPI interface support for Flash, FRAM and EEPROM - * ST STM32F72x, STM32F4x3, STM32H7xx support - * ST STM32G0xx, STM32G4xx, STM32L4x, STM32WB, STM32WL support - * ST STM32L5x support (non secure mode) - * TI CC13xx, CC26xx, CC32xx support - * TI MSP432 support - * Winner Micro w600 support - * Xilinx XCF platform support - * Various discrete SPI NOR flashes support Board, Target, and Interface Configuration Scripts: - * 8devices LIMA board config - * Achilles Instant-Development Kit Arria 10 board config - * Amazon Kindle 2 and DX board config - * Analog Devices ADSP-SC58x, ADSP-SC584-EZBRD board config - * Andes Technology ADP-XC7KFF676 board config - * Andes Technology Corvette-F1 board config - * ARM Musca A board config - * Arty Spartan 7 FPGA board config - * Atmel SAMD10 Xplained mini board config - * Atmel SAMD11 Xplained Pro board config - * Atmel SAM G55 Xplained Pro board config - * AVNET UltraZED EG StarterKit board config - * Blue Pill STM32F103C8 board config - * DP Busblaster v4.1a board config - * DPTechnics DPT-Board-v1 board config - * Emcraft imx8 SOM BSB board config - * Globalscale ESPRESSObin board config - * Kasli board config - * Kintex Ultrascale XCKU040 board config - * Knovative KC-100 board config - * LeMaker HiKey board config - * Microchip (Atmel) SAME54 Xplained Pro board config - * Microchip (Atmel) SAML11 Xplained Pro board config - * Nordic module NRF52 board config - * Numato Lab Mimas A7 board config - * NXP Freedom FRDM-LS1012A board config - * NXP IMX7SABRE board config - * NXP IMX8MP-EVK board config - * NXP MC-IMX8M-EVK board config - * QuickLogic QuickFeather board config - * Renesas R-Car E2, H2, M2 board config - * Renesas R-Car Salvator-X(S) board config - * Renesas RZ/A1H GR-Peach board config - * Rigado BMD-300 board config - * Sayma AMC board config - * Sifive e31arty, e51arty, hifive1 board config - * ST B-L475E-IOT01A board config - * ST BlueNRG idb007v1, idb008v1, idb011v1 board config - * ST STM32F412g discovery board config - * ST STM32F413h discovery board config - * ST STM32F469i discovery board config - * ST STM32F7 Nucleo board config - * ST STM32F723e discovery board config - * ST STM32F746g discovery board config - * ST STM32F769i discovery board config - * ST STM32H735g discovery board config - * ST STM32H743zi Nucleo board config - * ST STM32H745i discovery board config - * ST STM32H747i discovery board config - * ST STM32H750b discovery board config - * ST STM32H7b3i discovery board config - * ST STM32H7x_dual_qspi board config - * ST STM32H7x3i Eval boards config - * ST STM32L073 Nucleo board config - * ST STM32L476g discovery board config - * ST STM32L496g discovery board config - * ST STM32L4p5g discovery board config - * ST STM32L4r9i discovery board config - * ST STM32L5 Nucleo board config - * ST STM32MP15x DK2 board config - * ST STM32WB Nucleo board config - * ST STM8L152R8 Nucleo board config - * Synopsys DesignWare ARC EM board config - * Synopsys DesignWare ARC HSDK board config - * TI BeagleBone family boards config - * TI CC13xx, CC26xx, CC32xx LaunchPad board config - * TI MSP432 LaunchPad board config - * Tocoding Poplar board config - * TP-Link WDR4300 board config - * Allwinner V3s target config - * Andes Technology NDS V5 target config - * Atmel atmega128rfa1 target config - * ARM corelink SSE-200 target config - * Atheros_ar9344 target config - * Cypress PSoC5LP, PSoC6 target config - * EnSilica eSi-RISC target config - * Foshan Synwit Tech SWM050 target config - * GigaDevice GD32VF103 target config - * Hisilicon Hi3798 target config - * Hisilicon Hi6220 target config - * Infineon TLE987x target config - * Marvell Armada 3700 target config - * Maxim Integrated MAX32XXX target config - * Mellanox BlueField target config - * Microchip (Atmel) SAME5x, SAML1x target config - * NXP IMX6SX, IMX6UL, IMX7, IMX7ULP, IMX8 target config - * NXP Kinetis KE1xZ, KE1xF target config - * NXP LPC84x, LPC8Nxx, LS1012A, NHS31xx target config - * Qualcomm QCA4531 target config - * QuickLogic EOS S3 target config - * Renesas R-Car E2, H2, M2 target config - * Renesas R-Car Gen3 target config - * Renesas RZ/A1H target config - * Rockchip RK3308 target config - * ST BlueNRG target config - * ST STM32G0, STM32G4, STM32H7, STM32L0, STM32L5 target config - * ST STM32MP15x target config - * ST STM32WBx, STM32WLEx target config - * ST STM8L152, S003, S103, S105 target config - * Synopsys DesignWare ARC EM target config - * Synopsys DesignWare ARC HS Development Kit SoC target config - * TI CC13xx, CC26xx, CC32xx target config - * TI TNETC4401 target config - * Xilinx UltraScale+ target config - * Altera 5M570Z (MAXV family) CPLD config - * Xilinx Ultrascale, XCF CPLD config - * Intel (Altera) Arria10 FPGA config - * Cadence SystemVerilog Direct Programming Interface (DPI) interface config - * Cypress KitProg interface config - * Digilent SMT2 NC interface config - * DLN-2 example of Linux GPIOD interface config - * FTDI C232HM interface config - * HIE JTAG Debugger interface config - * In-Circuit's ICprog interface config - * isodebug isolated JTAG/SWD+UART interface config - * Mellanox rshim USB or PCIe interface config - * Nuvoton Nu-Link interface config - * NXP IMX GPIO mmap based interface config - * Steppenprobe open hardware interface config - * TI XDS110 interface config Server Layer: - * 64 bit address support - * default bind to IPv4 localhost - * gdb: allow multiple connections - * gdb: architecture element support - * gdb: vCont, vRun support - * telnet: handle Ctrl+A, Ctrl+E and Ctrl+K RTOS: - * Chromium-EC rtos support - * hwthread pseudo rtos support - * NuttX rtos support - * RIOT rtos support Documentation: - * Improve STM32 flash driver - * Various typo fix and improvements Build and Release: - * Add libutil to support jimtcl version 0.80 - * Clang warning fixes - * GitHub workflow for Win32 snapshot binaries - * Handle Tcl return values consistently - * Mitigation for CVE-2018-5704: Prevent some forms of Cross - Protocol Scripting attacks - * Support for libftdi 1.5 - * Travis-CI basic support - * Update libjaylink to version 0.2.0 - * Update jimtcl to version 0.79 - * Use external (optional) library capstone for ARM and AARCH64 disassembly This release also contains a number of other important functional and cosmetic bugfixes. For more details about what has changed since the last release, see the git repository history: -http://sourceforge.net/p/openocd/code/ci/v0.11.0-rc2/log/?path= +http://sourceforge.net/p/openocd/code/ci/v0.x.0/log/?path= For older NEWS, see the NEWS files associated with each release diff --git a/NEWS-0.11.0 b/NEWS-0.11.0 new file mode 100644 index 000000000..4542aa28f --- /dev/null +++ b/NEWS-0.11.0 @@ -0,0 +1,238 @@ +This file includes highlights of the changes made in the OpenOCD +source archive release. + +JTAG Layer: + * add debug level 4 for verbose I/O debug + * bitbang, add read buffer to improve performance + * Cadence SystemVerilog Direct Programming Interface (DPI) adapter driver + * CMSIS-DAP v2 (USB bulk based) adapter driver + * Cypress KitProg adapter driver + * FTDI FT232R sync bitbang adapter driver + * Linux GPIOD bitbang adapter driver through libgpiod + * Mellanox rshim USB or PCIe adapter driver + * Nuvoton Nu-Link and Nu-Link2 adapter drivers + * NXP IMX GPIO mmap based adapter driver + * ST-Link consolidate all versions in single config + * ST-Link read properly old USB serial numbers + * STLink/V3 support (for ST devices only !) + * STM8 SWIM transport + * TI XDS110 adapter driver + * Xilinx XVC/PCIe adapter driver + +Boundary Scan: + +Target Layer: + * 64 bit address support + * ARCv2 target support + * ARM Cortex-A hypervisor mode support + * ARM Cortex-M fast PC sampling support for profiling + * ARM generic CTI support + * ARM generic mem-ap target support + * ARMv7-A MMU tools + * ARMv7m traces add TCP stream server + * ARMv8 AARCH64 target support and semihosting support + * ARMv8 AARCH64 disassembler support through capstone library + * ARMv8-M target support + * EnSilica eSi-RISC target support, including instruction tracing + eSi-Trace support + * MIPS64 target support + * Motorola SREC S6 record image file support + * RISC-V target support + * SEGGER Real Time Transfer (RTT) initial support (for single target, + Cortex-M only) + * ST STM8 target support + * Various MIPS32 target improvements + +Flash Layer: + * Atheros (ath79) SPI interface support + * Atmel atmega128rfa1 support + * Atmel SAM D21, D51, DA1, E51, E53, E54, G55, R30 support + * Atmel SAMC2?N* support + * Cypress PSoC5LP, PSoC6 support + * EnSilica eSi-RISC support + * Foshan Synwit Tech SWM050 support + * Maxim Integrated MAX32XXX support + * Nordic Semiconductor nRF51822, nRF52810, nRF52832 support + * NXP Kinetis K27, K28, KE1x, KEAx, KL28, KL8x, KV5x, KWx support + * Renesas RPC HF support + * SH QSPI support + * SiFive Freedom E support + * Silicon Labs EFR-family, EZR32HG support + * ST BlueNRG support + * ST STM32 QUAD/OCTO-SPI interface support for Flash, FRAM and EEPROM + * ST STM32F72x, STM32F4x3, STM32H7xx support + * ST STM32G0xx, STM32G4xx, STM32L4x, STM32WB, STM32WL support + * ST STM32L5x support (non secure mode) + * TI CC13xx, CC26xx, CC32xx support + * TI MSP432 support + * Winner Micro w600 support + * Xilinx XCF platform support + * Various discrete SPI NOR flashes support + +Board, Target, and Interface Configuration Scripts: + * 8devices LIMA board config + * Achilles Instant-Development Kit Arria 10 board config + * Amazon Kindle 2 and DX board config + * Analog Devices ADSP-SC58x, ADSP-SC584-EZBRD board config + * Andes Technology ADP-XC7KFF676 board config + * Andes Technology Corvette-F1 board config + * ARM Musca A board config + * Arty Spartan 7 FPGA board config + * Atmel SAMD10 Xplained mini board config + * Atmel SAMD11 Xplained Pro board config + * Atmel SAM G55 Xplained Pro board config + * AVNET UltraZED EG StarterKit board config + * Blue Pill STM32F103C8 board config + * DP Busblaster v4.1a board config + * DPTechnics DPT-Board-v1 board config + * Emcraft imx8 SOM BSB board config + * Globalscale ESPRESSObin board config + * Kasli board config + * Kintex Ultrascale XCKU040 board config + * Knovative KC-100 board config + * LeMaker HiKey board config + * Microchip (Atmel) SAME54 Xplained Pro board config + * Microchip (Atmel) SAML11 Xplained Pro board config + * Nordic module NRF52 board config + * Numato Lab Mimas A7 board config + * NXP Freedom FRDM-LS1012A board config + * NXP IMX7SABRE board config + * NXP IMX8MP-EVK board config + * NXP MC-IMX8M-EVK board config + * QuickLogic QuickFeather board config + * Renesas R-Car E2, H2, M2 board config + * Renesas R-Car Salvator-X(S) board config + * Renesas RZ/A1H GR-Peach board config + * Rigado BMD-300 board config + * Sayma AMC board config + * Sifive e31arty, e51arty, hifive1 board config + * ST B-L475E-IOT01A board config + * ST BlueNRG idb007v1, idb008v1, idb011v1 board config + * ST STM32F412g discovery board config + * ST STM32F413h discovery board config + * ST STM32F469i discovery board config + * ST STM32F7 Nucleo board config + * ST STM32F723e discovery board config + * ST STM32F746g discovery board config + * ST STM32F769i discovery board config + * ST STM32H735g discovery board config + * ST STM32H743zi Nucleo board config + * ST STM32H745i discovery board config + * ST STM32H747i discovery board config + * ST STM32H750b discovery board config + * ST STM32H7b3i discovery board config + * ST STM32H7x_dual_qspi board config + * ST STM32H7x3i Eval boards config + * ST STM32L073 Nucleo board config + * ST STM32L476g discovery board config + * ST STM32L496g discovery board config + * ST STM32L4p5g discovery board config + * ST STM32L4r9i discovery board config + * ST STM32L5 Nucleo board config + * ST STM32MP15x DK2 board config + * ST STM32WB Nucleo board config + * ST STM8L152R8 Nucleo board config + * Synopsys DesignWare ARC EM board config + * Synopsys DesignWare ARC HSDK board config + * TI BeagleBone family boards config + * TI CC13xx, CC26xx, CC32xx LaunchPad board config + * TI MSP432 LaunchPad board config + * Tocoding Poplar board config + * TP-Link WDR4300 board config + * Allwinner V3s target config + * Andes Technology NDS V5 target config + * Atmel atmega128rfa1 target config + * ARM corelink SSE-200 target config + * Atheros_ar9344 target config + * Cypress PSoC5LP, PSoC6 target config + * EnSilica eSi-RISC target config + * Foshan Synwit Tech SWM050 target config + * GigaDevice GD32VF103 target config + * Hisilicon Hi3798 target config + * Hisilicon Hi6220 target config + * Infineon TLE987x target config + * Marvell Armada 3700 target config + * Maxim Integrated MAX32XXX target config + * Mellanox BlueField target config + * Microchip (Atmel) SAME5x, SAML1x target config + * NXP IMX6SX, IMX6UL, IMX7, IMX7ULP, IMX8 target config + * NXP Kinetis KE1xZ, KE1xF target config + * NXP LPC84x, LPC8Nxx, LS1012A, NHS31xx target config + * Qualcomm QCA4531 target config + * QuickLogic EOS S3 target config + * Renesas R-Car E2, H2, M2 target config + * Renesas R-Car Gen3 target config + * Renesas RZ/A1H target config + * Rockchip RK3308 target config + * ST BlueNRG target config + * ST STM32G0, STM32G4, STM32H7, STM32L0, STM32L5 target config + * ST STM32MP15x target config + * ST STM32WBx, STM32WLEx target config + * ST STM8L152, S003, S103, S105 target config + * Synopsys DesignWare ARC EM target config + * Synopsys DesignWare ARC HS Development Kit SoC target config + * TI CC13xx, CC26xx, CC32xx target config + * TI TNETC4401 target config + * Xilinx UltraScale+ target config + * Altera 5M570Z (MAXV family) CPLD config + * Xilinx Ultrascale, XCF CPLD config + * Intel (Altera) Arria10 FPGA config + * Cadence SystemVerilog Direct Programming Interface (DPI) interface config + * Cypress KitProg interface config + * Digilent SMT2 NC interface config + * DLN-2 example of Linux GPIOD interface config + * FTDI C232HM interface config + * HIE JTAG Debugger interface config + * In-Circuit's ICprog interface config + * isodebug isolated JTAG/SWD+UART interface config + * Mellanox rshim USB or PCIe interface config + * Nuvoton Nu-Link interface config + * NXP IMX GPIO mmap based interface config + * Steppenprobe open hardware interface config + * TI XDS110 interface config + +Server Layer: + * 64 bit address support + * default bind to IPv4 localhost + * gdb: allow multiple connections + * gdb: architecture element support + * gdb: vCont, vRun support + * telnet: handle Ctrl+A, Ctrl+E and Ctrl+K + +RTOS: + * Chromium-EC rtos support + * hwthread pseudo rtos support + * NuttX rtos support + * RIOT rtos support + +Documentation: + * Improve STM32 flash driver + * Various typo fix and improvements + +Build and Release: + * Add libutil to support jimtcl version 0.80 + * Clang warning fixes + * GitHub workflow for Win32 snapshot binaries + * Handle Tcl return values consistently + * Mitigation for CVE-2018-5704: Prevent some forms of Cross + Protocol Scripting attacks + * Support for libftdi 1.5 + * Travis-CI basic support + * Update libjaylink to version 0.2.0 + * Update jimtcl to version 0.79 + * Use external (optional) library capstone for ARM and AARCH64 disassembly + + +This release also contains a number of other important functional and +cosmetic bugfixes. For more details about what has changed since the +last release, see the git repository history: + +http://sourceforge.net/p/openocd/code/ci/v0.11.0/log/?path= + + +For older NEWS, see the NEWS files associated with each release +(i.e. NEWS-). + +For more information about contributing test reports, bug fixes, or new +features and device support, please read the new Developer Manual (or +the BUGS and PATCHES.txt files in the source archive). diff --git a/README b/README index fb3051f21..34dac0b1b 100644 --- a/README +++ b/README @@ -220,12 +220,11 @@ You'll also need: Additionally, for building from git: -- autoconf >= 2.64 +- autoconf >= 2.69 - automake >= 1.14 - texinfo >= 5.0 -USB-based adapters depend on libusb-1.0 and some older drivers require -libusb-0.1 or libusb-compat-0.1. A compatible implementation, such as +USB-based adapters depend on libusb-1.0. A compatible implementation, such as FreeBSD's, additionally needs the corresponding .pc files. USB-Blaster, ASIX Presto and OpenJTAG interface adapter diff --git a/README.Windows b/README.Windows index 6c616f38a..7326a356c 100644 --- a/README.Windows +++ b/README.Windows @@ -40,10 +40,6 @@ WinUSB.sys to the composite parent instead of the specific interface. To do that one needs to activate an advanced option in the Zadig installer. -For the old drivers that use libusb-0.1 API you might need to link -against libusb-win32 headers and install the corresponding driver with -Zadig. - If you need to use the same adapter with other applications that may require another driver, a solution for Windows Vista and above is to activate the IgnoreHWSerNum registry setting for the USB device. diff --git a/README.macOS b/README.macOS index c532e67c6..91d5e9261 100644 --- a/README.macOS +++ b/README.macOS @@ -27,14 +27,14 @@ With Homebrew you can either run: brew install [--HEAD] openocd (where optional --HEAD asks brew to install the current git version) or - brew install libtool automake libusb [libusb-compat] [hidapi] [libftdi] + brew install libtool automake libusb [hidapi] [libftdi] (to install the needed dependencies and then proceed with the manual building procedure) For building with MacPorts you need to run: sudo port install libtool automake autoconf pkgconfig \ - libusb [libusb-compat] [libftdi1] + libusb [libftdi1] You should also specify LDFLAGS and CPPFLAGS to allow configure to use MacPorts' libraries, so run configure like this: diff --git a/configure.ac b/configure.ac index 955b1b0e9..f9185e7f8 100644 --- a/configure.ac +++ b/configure.ac @@ -1,5 +1,5 @@ -AC_PREREQ(2.64) -AC_INIT([openocd], [0.11.0-rc2+dev], +AC_PREREQ([2.69]) +AC_INIT([openocd], [0.11.0+dev], [OpenOCD Mailing List ]) AC_CONFIG_SRCDIR([src/openocd.c]) AC_CONFIG_AUX_DIR([.]) @@ -121,12 +121,10 @@ m4_define([USB1_ADAPTERS], [[cmsis_dap_v2], [CMSIS-DAP v2 Compliant Debugger], [CMSIS_DAP_USB]], [[osbdm], [OSBDM (JTAG only) Programmer], [OSBDM]], [[opendous], [eStick/opendous JTAG Programmer], [OPENDOUS]], - [[aice], [Andes JTAG Programmer], [AICE]]]) - -m4_define([USB0_ADAPTERS], - [[[usbprog], [USBProg JTAG Programmer], [USBPROG]], + [[armjtagew], [Olimex ARM-JTAG-EW Programmer], [ARMJTAGEW]], [[rlink], [Raisonance RLink JTAG Programmer], [RLINK]], - [[armjtagew], [Olimex ARM-JTAG-EW Programmer], [ARMJTAGEW]]]) + [[usbprog], [USBProg JTAG Programmer], [USBPROG]], + [[aice], [Andes JTAG Programmer], [AICE]]]) m4_define([HIDAPI_ADAPTERS], [[[cmsis_dap], [CMSIS-DAP Compliant Debugger], [CMSIS_DAP_HID]], @@ -247,7 +245,6 @@ m4_define([AC_ARG_ADAPTERS], [ AC_ARG_ADAPTERS([ USB1_ADAPTERS, - USB0_ADAPTERS, HIDAPI_ADAPTERS, HIDAPI_USB1_ADAPTERS, LIBFTDI_ADAPTERS, @@ -282,18 +279,6 @@ AC_ARG_ENABLE([amtjtagaccel], AS_HELP_STRING([--enable-amtjtagaccel], [Enable building the Amontec JTAG-Accelerator driver]), [build_amtjtagaccel=$enableval], [build_amtjtagaccel=no]) -AC_ARG_ENABLE([zy1000_master], - AS_HELP_STRING([--enable-zy1000-master], [Use ZY1000 JTAG master registers]), - [build_zy1000_master=$enableval], [build_zy1000_master=no]) - -AC_ARG_ENABLE([zy1000], - AS_HELP_STRING([--enable-zy1000], [Enable ZY1000 interface]), - [build_zy1000=$enableval], [build_zy1000=no]) - -AC_ARG_ENABLE([ioutil], - AS_HELP_STRING([--enable-ioutil], [Enable ioutil functions - useful for standalone OpenOCD implementations]), - [build_ioutil=$enableval], [build_ioutil=no]) - AS_CASE(["${host_cpu}"], [arm*|aarch64], [ AC_ARG_ENABLE([bcm2835gpio], @@ -327,11 +312,6 @@ AC_ARG_ENABLE([gw16012], AS_HELP_STRING([--enable-gw16012], [Enable building support for the Gateworks GW16012 JTAG Programmer]), [build_gw16012=$enableval], [build_gw16012=no]) -AC_ARG_ENABLE([oocd_trace], - AS_HELP_STRING([--enable-oocd_trace], - [Enable building support for some prototype OpenOCD+trace ETM capture hardware]), - [build_oocd_trace=$enableval], [build_oocd_trace=no]) - AC_ARG_ENABLE([buspirate], AS_HELP_STRING([--enable-buspirate], [Enable building support for the Buspirate]), [build_buspirate=$enableval], [build_buspirate=no]) @@ -367,10 +347,6 @@ AS_CASE([$host_os], ]) ]) -AC_ARG_ENABLE([minidriver_dummy], - AS_HELP_STRING([--enable-minidriver-dummy], [Enable the dummy minidriver.]), - [build_minidriver_dummy=$enableval], [build_minidriver_dummy=no]) - AC_ARG_ENABLE([internal-jimtcl], AS_HELP_STRING([--disable-internal-jimtcl], [Disable building internal jimtcl]), [use_internal_jimtcl=$enableval], [use_internal_jimtcl=yes]) @@ -380,43 +356,10 @@ AC_ARG_ENABLE([internal-libjaylink], [Disable building internal libjaylink]), [use_internal_libjaylink=$enableval], [use_internal_libjaylink=yes]) -build_minidriver=no -AC_MSG_CHECKING([whether to enable ZY1000 minidriver]) -AS_IF([test "x$build_zy1000" = "xyes"], [ - AS_IF([test "x$build_minidriver" = "xyes"], [ - AC_MSG_ERROR([Multiple minidriver options have been enabled.]) - ]) - AC_DEFINE([HAVE_JTAG_MINIDRIVER_H], [1], - [Define to 1 if you have the header file.]) - build_minidriver=yes -]) -AC_MSG_RESULT([$build_zy1000]) - AC_ARG_ENABLE([remote-bitbang], AS_HELP_STRING([--enable-remote-bitbang], [Enable building support for the Remote Bitbang jtag driver]), [build_remote_bitbang=$enableval], [build_remote_bitbang=yes]) -AC_MSG_CHECKING([whether to enable dummy minidriver]) -AS_IF([test "x$build_minidriver_dummy" = "xyes"], [ - AS_IF([test "x$build_minidriver" = "xyes"], [ - AC_MSG_ERROR([Multiple minidriver options have been enabled.]) - ]) - build_minidriver=yes - AC_DEFINE([BUILD_MINIDRIVER_DUMMY], [1], [Use the dummy minidriver.]) - AC_DEFINE([HAVE_JTAG_MINIDRIVER_H], [1], - [Define to 1 if you have the header file.]) -]) -AC_MSG_RESULT([$build_minidriver_dummy]) - -AC_MSG_CHECKING([whether standard drivers can be built]) -AS_IF([test "x$build_minidriver" = "xyes"], [ - AC_MSG_RESULT([no]) - AC_MSG_WARN([Using the minidriver disables all other drivers.]) - sleep 2 -], [ - AC_MSG_RESULT([yes]) -]) - AS_CASE(["${host_cpu}"], [i?86|x86*], [], [ @@ -529,18 +472,6 @@ AS_IF([test "x$build_ep93xx" = "xyes"], [ AC_DEFINE([BUILD_EP93XX], [0], [0 if you don't want ep93xx.]) ]) -AS_IF([test "x$build_zy1000" = "xyes"], [ - AC_DEFINE([BUILD_ZY1000], [1], [1 if you want ZY1000.]) -], [ - AC_DEFINE([BUILD_ZY1000], [0], [0 if you don't want ZY1000.]) -]) - -AS_IF([test "x$build_zy1000_master" = "xyes"], [ - AC_DEFINE([BUILD_ZY1000_MASTER], [1], [1 if you want ZY1000 JTAG master registers.]) -], [ - AC_DEFINE([BUILD_ZY1000_MASTER], [0], [0 if you don't want ZY1000 JTAG master registers.]) -]) - AS_IF([test "x$build_at91rm9200" = "xyes"], [ build_bitbang=yes AC_DEFINE([BUILD_AT91RM9200], [1], [1 if you want at91rm9200.]) @@ -599,12 +530,6 @@ AS_IF([test "x$build_gw16012" = "xyes"], [ AC_DEFINE([BUILD_GW16012], [0], [0 if you don't want the Gateworks GW16012 driver.]) ]) -AS_IF([test "x$build_oocd_trace" = "xyes"], [ - AC_DEFINE([BUILD_OOCD_TRACE], [1], [1 if you want the OpenOCD+trace ETM capture driver.]) -], [ - AC_DEFINE([BUILD_OOCD_TRACE], [0], [0 if you don't want the OpenOCD+trace ETM capture driver.]) -]) - AS_IF([test "x$build_buspirate" = "xyes"], [ AC_DEFINE([BUILD_BUSPIRATE], [1], [1 if you want the Buspirate JTAG driver.]) ], [ @@ -655,8 +580,6 @@ PKG_CHECK_MODULES([LIBUSB1], [libusb-1.0], [ AC_MSG_WARN([libusb-1.x not found, trying legacy libusb-0.1 as a fallback; consider installing libusb-1.x instead]) ]) -PKG_CHECK_MODULES([LIBUSB0], [libusb], [use_libusb0=yes], [use_libusb0=no]) - AC_ARG_WITH([capstone], AS_HELP_STRING([--with-capstone], [Use Capstone disassembly library (default=auto)]) , [ @@ -701,9 +624,6 @@ PKG_CHECK_MODULES([LIBJAYLINK], [libjaylink >= 0.2], m4_define([PROCESS_ADAPTERS], [ m4_foreach([adapter], [$1], [ - AS_IF([test "x$build_zy1000" = "xyes"], [ - ADAPTER_VAR([adapter])=no - ]) AS_IF([test $2], [ AS_IF([test "x$ADAPTER_VAR([adapter])" != "xno"], [ AC_DEFINE([BUILD_]ADAPTER_SYM([adapter]), [1], [1 if you want the ]ADAPTER_DESC([adapter]).) @@ -721,7 +641,6 @@ m4_define([PROCESS_ADAPTERS], [ ]) PROCESS_ADAPTERS([USB1_ADAPTERS], ["x$use_libusb1" = "xyes"], [libusb-1.x]) -PROCESS_ADAPTERS([USB0_ADAPTERS], ["x$use_libusb0" = "xyes"], [libusb-0.1]) PROCESS_ADAPTERS([HIDAPI_ADAPTERS], ["x$use_hidapi" = "xyes"], [hidapi]) PROCESS_ADAPTERS([HIDAPI_USB1_ADAPTERS], ["x$use_hidapi" = "xyes" -a "x$use_libusb1" = "xyes"], [hidapi and libusb-1.x]) PROCESS_ADAPTERS([LIBFTDI_ADAPTERS], ["x$use_libftdi" = "xyes"], [libftdi]) @@ -765,9 +684,6 @@ AM_CONDITIONAL([PARPORT], [test "x$build_parport" = "xyes"]) AM_CONDITIONAL([DUMMY], [test "x$build_dummy" = "xyes"]) AM_CONDITIONAL([GIVEIO], [test "x$parport_use_giveio" = "xyes"]) AM_CONDITIONAL([EP93XX], [test "x$build_ep93xx" = "xyes"]) -AM_CONDITIONAL([ZY1000], [test "x$build_zy1000" = "xyes"]) -AM_CONDITIONAL([ZY1000_MASTER], [test "x$build_zy1000_master" = "xyes"]) -AM_CONDITIONAL([IOUTIL], [test "x$build_ioutil" = "xyes"]) AM_CONDITIONAL([AT91RM9200], [test "x$build_at91rm9200" = "xyes"]) AM_CONDITIONAL([BCM2835GPIO], [test "x$build_bcm2835gpio" = "xyes"]) AM_CONDITIONAL([IMX_GPIO], [test "x$build_imx_gpio" = "xyes"]) @@ -777,12 +693,10 @@ AM_CONDITIONAL([JTAG_DPI], [test "x$build_jtag_dpi" = "xyes" -o "x$build_jtag_dp AM_CONDITIONAL([USB_BLASTER_DRIVER], [test "x$enable_usb_blaster" != "xno" -o "x$enable_usb_blaster_2" != "xno"]) AM_CONDITIONAL([AMTJTAGACCEL], [test "x$build_amtjtagaccel" = "xyes"]) AM_CONDITIONAL([GW16012], [test "x$build_gw16012" = "xyes"]) -AM_CONDITIONAL([OOCD_TRACE], [test "x$build_oocd_trace" = "xyes"]) AM_CONDITIONAL([REMOTE_BITBANG], [test "x$build_remote_bitbang" = "xyes"]) AM_CONDITIONAL([BUSPIRATE], [test "x$build_buspirate" = "xyes"]) AM_CONDITIONAL([SYSFSGPIO], [test "x$build_sysfsgpio" = "xyes"]) AM_CONDITIONAL([XLNX_PCIE_XVC], [test "x$build_xlnx_pcie_xvc" = "xyes"]) -AM_CONDITIONAL([USE_LIBUSB0], [test "x$use_libusb0" = "xyes"]) AM_CONDITIONAL([USE_LIBUSB1], [test "x$use_libusb1" = "xyes"]) AM_CONDITIONAL([IS_CYGWIN], [test "x$is_cygwin" = "xyes"]) AM_CONDITIONAL([IS_MINGW], [test "x$is_mingw" = "xyes"]) @@ -796,9 +710,6 @@ AM_CONDITIONAL([USE_LIBJAYLINK], [test "x$use_libjaylink" = "xyes"]) AM_CONDITIONAL([RSHIM], [test "x$build_rshim" = "xyes"]) AM_CONDITIONAL([HAVE_CAPSTONE], [test "x$enable_capstone" != "xno"]) -AM_CONDITIONAL([MINIDRIVER], [test "x$build_minidriver" = "xyes"]) -AM_CONDITIONAL([MINIDRIVER_DUMMY], [test "x$build_minidriver_dummy" = "xyes"]) - AM_CONDITIONAL([INTERNAL_JIMTCL], [test "x$use_internal_jimtcl" = "xyes"]) AM_CONDITIONAL([INTERNAL_LIBJAYLINK], [test "x$use_internal_libjaylink" = "xyes"]) @@ -853,6 +764,8 @@ AS_IF([test "x$gcc_warnings" = "xyes"], [ AC_SUBST([GCC_WARNINGS], [$GCC_WARNINGS]) ]) +AC_SUBST(EXTRA_DIST_NEWS, ["$(echo $srcdir/NEWS-*)"]) + AC_CONFIG_FILES([ Makefile src/gnulib/Makefile @@ -863,7 +776,7 @@ echo echo echo OpenOCD configuration summary echo -------------------------------------------------- -m4_foreach([adapter], [USB1_ADAPTERS, USB0_ADAPTERS, +m4_foreach([adapter], [USB1_ADAPTERS, HIDAPI_ADAPTERS, HIDAPI_USB1_ADAPTERS, LIBFTDI_ADAPTERS, LIBFTDI_USB1_ADAPTERS, LIBGPIOD_ADAPTERS, @@ -882,26 +795,3 @@ m4_foreach([adapter], [USB1_ADAPTERS, USB0_ADAPTERS, ]) ]) echo - -AS_IF([test "x$build_oocd_trace" = "xyes"], [ - echo 'WARNING! Deprecated configure option (--enable-oocd_trace)' - echo 'The oocd_trace driver is deprecated and will be removed in the next release.' - echo 'If you regularly use this driver, please report to the OpenOCD Mailing List.' - echo -]) - -AS_IF([test "x$build_zy1000" = "xyes" -o "x$build_zy1000_master" = "xyes"], [ - echo 'WARNING! Deprecated configure option (--enable-zy1000, --enable-zy1000-master)' - echo 'Support for the ZY1000 platform is deprecated and will be removed in the next' - echo 'release. If you regularly use this platform, please report to the OpenOCD' - echo 'Mailing List.' - echo -]) - -AS_IF([test "x$build_ioutil" = "xyes"], [ - echo 'WARNING! Deprecated configure option (--enable-ioutil)' - echo 'Support for the ioutil functions is deprecated and will be removed in the next' - echo 'release. If you regularly depend on this functionality, please report to the' - echo 'OpenOCD Mailing List.' - echo -]) diff --git a/contrib/60-openocd.rules b/contrib/60-openocd.rules index e0864b827..a3046be8f 100644 --- a/contrib/60-openocd.rules +++ b/contrib/60-openocd.rules @@ -32,8 +32,19 @@ ATTRS{idVendor}=="0403", ATTRS{idProduct}=="8220", MODE="660", GROUP="plugdev", ATTRS{idVendor}=="0403", ATTRS{idProduct}=="8a98", MODE="660", GROUP="plugdev", TAG+="uaccess" ATTRS{idVendor}=="0403", ATTRS{idProduct}=="8a99", MODE="660", GROUP="plugdev", TAG+="uaccess" +# Marvell OpenRD JTAGKey FT2232D B +ATTRS{idVendor}=="0403", ATTRS{idProduct}=="9e90", MODE="660", GROUP="plugdev", TAG+="uaccess" + # XDS100v2 ATTRS{idVendor}=="0403", ATTRS{idProduct}=="a6d0", MODE="660", GROUP="plugdev", TAG+="uaccess" +# XDS100v3 +ATTRS{idVendor}=="0403", ATTRS{idProduct}=="a6d1", MODE="660", GROUP="plugdev", TAG+="uaccess" + +# OOCDLink +ATTRS{idVendor}=="0403", ATTRS{idProduct}=="baf8", MODE="660", GROUP="plugdev", TAG+="uaccess" + +# Kristech KT-Link +ATTRS{idVendor}=="0403", ATTRS{idProduct}=="bbe2", MODE="660", GROUP="plugdev", TAG+="uaccess" # Xverve Signalyzer Tool (DT-USB-ST), Signalyzer LITE (DT-USB-SLITE) ATTRS{idVendor}=="0403", ATTRS{idProduct}=="bca0", MODE="660", GROUP="plugdev", TAG+="uaccess" @@ -90,6 +101,12 @@ ATTRS{idVendor}=="04b4", ATTRS{idProduct}=="f139", MODE="660", GROUP="plugdev", # Cypress KitProg in CMSIS-DAP mode ATTRS{idVendor}=="04b4", ATTRS{idProduct}=="f138", MODE="660", GROUP="plugdev", TAG+="uaccess" +# Infineon DAP miniWiggler v3 +ATTRS{idVendor}=="058b", ATTRS{idProduct}=="0043", MODE="660", GROUP="plugdev", TAG+="uaccess" + +# Hitex LPC1768-Stick +ATTRS{idVendor}=="0640", ATTRS{idProduct}=="0026", MODE="660", GROUP="plugdev", TAG+="uaccess" + # Hilscher NXHX Boards ATTRS{idVendor}=="0640", ATTRS{idProduct}=="0028", MODE="660", GROUP="plugdev", TAG+="uaccess" @@ -99,8 +116,14 @@ ATTRS{idVendor}=="0640", ATTRS{idProduct}=="002c", MODE="660", GROUP="plugdev", # Hitex STM32-PerformanceStick ATTRS{idVendor}=="0640", ATTRS{idProduct}=="002d", MODE="660", GROUP="plugdev", TAG+="uaccess" +# Hitex Cortino +ATTRS{idVendor}=="0640", ATTRS{idProduct}=="0032", MODE="660", GROUP="plugdev", TAG+="uaccess" + # Altera USB Blaster ATTRS{idVendor}=="09fb", ATTRS{idProduct}=="6001", MODE="660", GROUP="plugdev", TAG+="uaccess" +# Altera USB Blaster2 +ATTRS{idVendor}=="09fb", ATTRS{idProduct}=="6010", MODE="660", GROUP="plugdev", TAG+="uaccess" +ATTRS{idVendor}=="09fb", ATTRS{idProduct}=="6810", MODE="660", GROUP="plugdev", TAG+="uaccess" # Amontec JTAGkey-HiSpeed ATTRS{idVendor}=="0fbb", ATTRS{idProduct}=="1000", MODE="660", GROUP="plugdev", TAG+="uaccess" @@ -146,6 +169,9 @@ ATTRS{idVendor}=="15ba", ATTRS{idProduct}=="002a", MODE="660", GROUP="plugdev", # Olimex ARM-USB-OCD-H ATTRS{idVendor}=="15ba", ATTRS{idProduct}=="002b", MODE="660", GROUP="plugdev", TAG+="uaccess" +# ixo-usb-jtag - Emulation of a Altera Bus Blaster I on a Cypress FX2 IC +ATTRS{idVendor}=="16c0", ATTRS{idProduct}=="06ad", MODE="660", GROUP="plugdev", TAG+="uaccess" + # USBprog with OpenOCD firmware ATTRS{idVendor}=="1781", ATTRS{idProduct}=="0c63", MODE="660", GROUP="plugdev", TAG+="uaccess" @@ -160,6 +186,15 @@ ATTRS{idVendor}=="1cbe", ATTRS{idProduct}=="02a5", MODE="660", GROUP="plugdev", # TI Tiva-based ICDI and XDS110 probes in DFU mode ATTRS{idVendor}=="1cbe", ATTRS{idProduct}=="00ff", MODE="660", GROUP="plugdev", TAG+="uaccess" +# isodebug v1 +ATTRS{idVendor}=="22b7", ATTRS{idProduct}=="150d", MODE="660", GROUP="plugdev", TAG+="uaccess" + +# PLS USB/JTAG Adapter for SPC5xxx +ATTRS{idVendor}=="263d", ATTRS{idProduct}=="4001", MODE="660", GROUP="plugdev", TAG+="uaccess" + +# Numato Mimas A7 - Artix 7 FPGA Board +ATTRS{idVendor}=="2a19", ATTRS{idProduct}=="1009", MODE="660", GROUP="plugdev", TAG+="uaccess" + # Ambiq Micro EVK and Debug boards. ATTRS{idVendor}=="2aec", ATTRS{idProduct}=="6010", MODE="660", GROUP="plugdev", TAG+="uaccess" ATTRS{idVendor}=="2aec", ATTRS{idProduct}=="6011", MODE="660", GROUP="plugdev", TAG+="uaccess" diff --git a/contrib/loaders/checksum/riscv_crc.c b/contrib/loaders/checksum/riscv_crc.c index b7e86c13b..e437b6616 100644 --- a/contrib/loaders/checksum/riscv_crc.c +++ b/contrib/loaders/checksum/riscv_crc.c @@ -1,3 +1,8 @@ +/* + * SPDX-License-Identifier: GPL-2.0-or-later + * Copyright (C) 2009-2021 Free Software Foundation, Inc. + */ + /* Copied from https://github.com/gcc-mirror/gcc/blob/master/libiberty/crc32.c * and then tweaked a little. */ diff --git a/doc/fdl.texi b/doc/fdl.texi index 33b2a1646..2189f80a6 100644 --- a/doc/fdl.texi +++ b/doc/fdl.texi @@ -1,6 +1,5 @@ @c -*-texinfo-*- -@node License -@appendix The GNU Free Documentation License. +@c The GNU Free Documentation License. @center Version 1.2, November 2002 @c This file is intended to be included within another document, @@ -396,7 +395,7 @@ The Free Software Foundation may publish new, revised versions of the GNU Free Documentation 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. See -@uref{http://www.gnu.org/copyleft/}. +@uref{https://www.gnu.org/licenses/}. Each version of the License is given a distinguishing version number. If the Document specifies that a particular numbered version of this @@ -408,7 +407,8 @@ number of this License, you may choose any version ever published (not as a draft) by the Free Software Foundation. @end enumerate -@unnumberedsec ADDENDUM: How to use this License for your documents +@page +@heading ADDENDUM: How to use this License for your documents To use this License in a document you have written, include a copy of the License in the document and put the following copyright and diff --git a/doc/manual/jtag.txt b/doc/manual/jtag.txt index 8f0804ce9..2653fc78f 100644 --- a/doc/manual/jtag.txt +++ b/doc/manual/jtag.txt @@ -36,7 +36,6 @@ asynchronous transactions. - declared in @c src/jtag/minidriver.h - used @a only by the core and minidriver implementations: - @c jtag_driver.c (in-tree OpenOCD drivers) - - @c zy1000/build/include/jtag_minidriver.h (ZY1000 minidriver) - future implementations (on other embedded hosts) - interface device drivers do @b not need this API. diff --git a/doc/manual/style.txt b/doc/manual/style.txt index dad3bb440..755709fb0 100644 --- a/doc/manual/style.txt +++ b/doc/manual/style.txt @@ -114,9 +114,9 @@ pthreads require modest and predictable stack usage. - static inline functions should be preferred over macros: @code -/** do NOT define macro-like functions like this... */ +/* do NOT define macro-like functions like this... */ #define CUBE(x) ((x) * (x) * (x)) -/** instead, define the same expression using a C99 inline function */ +/* instead, define the same expression using a C99 inline function */ static inline int cube(int x) { return x * x * x; } @endcode - Functions should be declared static unless required by other modules @@ -135,13 +135,13 @@ should write statements like the following: @code // separate statements should be preferred result = foo(); -if (ERROR_OK != result) +if (result != ERROR_OK) ... @endcode More directly, do @b not combine these kinds of statements: @code // Combined statements should be avoided -if (ERROR_OK != (result = foo())) +if ((result = foo()) != ERROR_OK) return result; @endcode diff --git a/doc/openocd.texi b/doc/openocd.texi index 2382dd358..fc6b04d8a 100644 --- a/doc/openocd.texi +++ b/doc/openocd.texi @@ -298,7 +298,6 @@ The OpenOCD Bug Tracker is hosted on SourceForge: @cindex dongles @cindex FTDI @cindex wiggler -@cindex zy1000 @cindex printer port @cindex USB Adapter @cindex RTCK @@ -307,12 +306,7 @@ Defined: @b{dongle}: A small device that plugs into a computer and serves as an adapter .... [snip] In the OpenOCD case, this generally refers to @b{a small adapter} that -attaches to your computer via USB or the parallel port. One -exception is the Ultimate Solutions ZY1000, packaged as a small box you -attach via an ethernet cable. The ZY1000 has the advantage that it does not -require any drivers to be installed on the developer PC. It also has -a built in web interface. It supports RTCK/RCLK or adaptive clocking -and has a built-in relay to power cycle targets remotely. +attaches to your computer via USB or the parallel port. @section Choosing a Dongle @@ -334,26 +328,6 @@ Ethernet port needed? RTCK support (also known as ``adaptive clocking'')? @end enumerate -@section Stand-alone JTAG Probe - -The ZY1000 from Ultimate Solutions is technically not a dongle but a -stand-alone JTAG probe that, unlike most dongles, doesn't require any drivers -running on the developer's host computer. -Once installed on a network using DHCP or a static IP assignment, users can -access the ZY1000 probe locally or remotely from any host with access to the -IP address assigned to the probe. -The ZY1000 provides an intuitive web interface with direct access to the -OpenOCD debugger. -Users may also run a GDBSERVER directly on the ZY1000 to take full advantage -of GCC & GDB to debug any distribution of embedded Linux or NetBSD running on -the target. -The ZY1000 supports RTCK & RCLK or adaptive clocking and has a built-in relay -to power cycle the target remotely. - -For more information, visit: - -@b{ZY1000} See: @url{http://www.ultsol.com/index.php/component/content/article/8/210-zylin-zy1000-main} - @section USB FT2232 Based There are many USB JTAG dongles on the market, many of them based @@ -2155,9 +2129,6 @@ disables the gdb server. When using "pipe", also use log_output to redirect the log output to a file so as not to flood the stdin/out pipes. -The -p/--pipe option is deprecated and a warning is printed -as it is equivalent to passing in -c "gdb_port pipe; log_output openocd.log". - Any other string is interpreted as named pipe to listen to. Output pipe is the same name as input pipe, but with 'o' appended, e.g. /var/gdb, /var/gdbo. @@ -3126,6 +3097,15 @@ Specifies the adapter layout to use. Pairs of vendor IDs and product IDs of the device. @end deffn +@deffn {Config Command} {hla_stlink_backend} (usb | tcp [port]) +@emph{ST-Link only:} Choose between 'exclusive' USB communication (the default backend) or +'shared' mode using ST-Link TCP server (the default port is 7184). + +@emph{Note:} ST-Link TCP server is a binary application provided by ST +available from @url{https://www.st.com/en/development-tools/st-link-server.html, +ST-LINK server software module}. +@end deffn + @deffn {Command} {hla_command} command Execute a custom adapter-specific command. The @var{command} string is passed as is to the underlying adapter layout handler. @@ -3146,6 +3126,17 @@ An error is returned for any AP number above the maximum allowed value. @emph{Note:} Either these same adapters and their older versions are also supported by @ref{hla_interface, the hla interface driver}. +@deffn {Config Command} {st-link backend} (usb | tcp [port]) +Choose between 'exclusive' USB communication (the default backend) or +'shared' mode using ST-Link TCP server (the default port is 7184). + +@emph{Note:} ST-Link TCP server is a binary application provided by ST +available from @url{https://www.st.com/en/development-tools/st-link-server.html, +ST-LINK server software module}. + +@emph{Note:} ST-Link TCP server does not support the SWIM transport. +@end deffn + @deffn {Config Command} {st-link serial} serial Specifies the serial number of the adapter. @end deffn @@ -3205,20 +3196,6 @@ The string will be of the format "DDDD:BB:SS.F" such as "0000:65:00.1". @end deffn @end deffn -@deffn {Interface Driver} {ZY1000} -This is the Zylin ZY1000 JTAG debugger. -@end deffn - -@quotation Note -This defines some driver-specific commands, -which are not currently documented here. -@end quotation - -@deffn Command power [@option{on}|@option{off}] -Turn power switch to target on/off. -No arguments: print status. -@end deffn - @deffn {Interface Driver} {bcm2835gpio} This SoC is present in Raspberry Pi which is a cheap single-board computer exposing some GPIOs on its expansion header. @@ -4532,7 +4509,13 @@ The current implementation supports eSi-32xx cores. @item @code{hla_target} -- a Cortex-M alternative to work with HL adapters like ST-Link. @item @code{ls1_sap} -- this is the SAP on NXP LS102x CPUs, allowing access to physical memory addresses independently of CPU cores. -@item @code{mem_ap} -- this is an ARM debug infrastructure Access Port without a CPU, through which bus read and write cycles can be generated; it may be useful for working with non-CPU hardware behind an AP or during development of support for new CPUs. +@item @code{mem_ap} -- this is an ARM debug infrastructure Access Port without +a CPU, through which bus read and write cycles can be generated; it may be +useful for working with non-CPU hardware behind an AP or during development of +support for new CPUs. +It's possible to connect a GDB client to this target (the GDB port has to be +specified, @xref{gdbportoverride,,option -gdb-port}), and a fake ARM core will +be emulated to comply to GDB remote protocol. @item @code{mips_m4k} -- a MIPS core. @item @code{mips_mips64} -- a MIPS64 core. @item @code{nds32_v2} -- this is an Andes NDS32 v2 core. @@ -5035,6 +5018,19 @@ when reset disables PLLs needed to use a fast clock. @* After target hardware trace configuration was changed @end itemize +@quotation Note +OpenOCD events are not supposed to be preempt by another event, but this +is not enforced in current code. Only the target event @b{resumed} is +executed with polling disabled; this avoids polling to trigger the event +@b{halted}, reversing the logical order of execution of their handlers. +Future versions of OpenOCD will prevent the event preemption and will +disable the schedule of polling during the event execution. Do not rely +on polling in any event handler; this means, don't expect the status of +a core to change during the execution of the handler. The event handler +will have to enable polling or use @command{$target_name arp_poll} to +check if the core has changed status. +@end quotation + @node Flash Commands @chapter Flash Commands @@ -7189,6 +7185,17 @@ the chip identification register, and autoconfigures itself. flash bank $_FLASHNAME stm32l4x 0 0 0 0 $_TARGETNAME @end example +If you use OTP (One-Time Programmable) memory define it as a second bank +as per the following example. +@example +flash bank $_FLASHNAME stm32l4x 0x1FFF7000 0 0 0 $_TARGETNAME +@end example + +@deffn Command {stm32l4x otp} num (@option{enable}|@option{disable}|@option{show}) +Enables or disables OTP write commands for bank @var{num}. +The @var{num} parameter is a value shown by @command{flash banks}. +@end deffn + Note that some devices have been found that have a flash size register that contains an invalid value, to workaround this issue you can override the probed value used by the flash driver. However, specifying a wrong value might lead to a completely @@ -7248,6 +7255,20 @@ Area A for bank 1. The above example set WRP1AR_END=255, WRP1AR_START=0. This will effectively write protect all sectors in flash bank 1. @end deffn +@deffn Command {stm32l4x wrp_info} num [device_bank] +List the protected areas using WRP. +The @var{num} parameter is a value shown by @command{flash banks}. +@var{device_bank} parameter is optional, possible values 'bank1' or 'bank2', +if not specified, the command will display the whole flash protected areas. + +@b{Note:} @var{device_bank} is different from banks created using @code{flash bank}. +Devices supported in this flash driver, can have main flash memory organized +in single or dual-banks mode. +Thus the usage of @var{device_bank} is meaningful only in dual-bank mode, to get +write protected areas in a specific @var{device_bank} + +@end deffn + @deffn Command {stm32l4x option_load} num Forces a re-load of the option byte registers. Will cause a system reset of the device. The @var{num} parameter is a value shown by @command{flash banks}. @@ -8255,66 +8276,6 @@ with handlers for that event. @end quotation @end deffn -@section I/O Utilities - -These commands are available when -OpenOCD is built with @option{--enable-ioutil}. -They are mainly useful on embedded targets, -notably the ZY1000. -Hosts with operating systems have complementary tools. - -@emph{Note:} there are several more such commands. - -@deffn Command append_file filename [string]* -Appends the @var{string} parameters to -the text file @file{filename}. -Each string except the last one is followed by one space. -The last string is followed by a newline. -@end deffn - -@deffn Command cat filename -Reads and displays the text file @file{filename}. -@end deffn - -@deffn Command cp src_filename dest_filename -Copies contents from the file @file{src_filename} -into @file{dest_filename}. -@end deffn - -@deffn Command ip -@emph{No description provided.} -@end deffn - -@deffn Command ls -@emph{No description provided.} -@end deffn - -@deffn Command mac -@emph{No description provided.} -@end deffn - -@deffn Command meminfo -Display available RAM memory on OpenOCD host. -Used in OpenOCD regression testing scripts. -@end deffn - -@deffn Command peek -@emph{No description provided.} -@end deffn - -@deffn Command poke -@emph{No description provided.} -@end deffn - -@deffn Command rm filename -@c "rm" has both normal and Jim-level versions?? -Unlinks the file @file{filename}. -@end deffn - -@deffn Command trunc filename -Removes all data in the file @file{filename}. -@end deffn - @anchor{memoryaccess} @section Memory access commands @cindex memory access @@ -8836,29 +8797,6 @@ how the event caused trouble. @end deffn -@deffn {Trace Port Driver} oocd_trace -This driver isn't available unless OpenOCD was explicitly configured -with the @option{--enable-oocd_trace} option. You probably don't want -to configure it unless you've built the appropriate prototype hardware; -it's @emph{proof-of-concept} software. - -Use the @option{oocd_trace} driver if you are configuring an ETM that's -connected to an off-chip trace connector. - -@deffn {Config Command} {oocd_trace config} target tty -Associates the ETM for @var{target} with a trace driver which -collects data through the serial port @var{tty}. -@end deffn - -@deffn Command {oocd_trace resync} -Re-synchronizes with the capture clock. -@end deffn - -@deffn Command {oocd_trace status} -Reports whether the capture clock is locked or not. -@end deffn -@end deffn - @anchor{armcrosstrigger} @section ARM Cross-Trigger Interface @cindex CTI @@ -9081,23 +9019,6 @@ cables (FT2232), but might be unsafe if used with targets running at very low speeds, like the 32kHz startup clock of an AT91RM9200. @end deffn -@subsection ARM720T specific commands -@cindex ARM720T - -These commands are available to ARM720T based CPUs, -which are implementations of the ARMv4T architecture -based on the ARM7TDMI-S integer core. -They are available in addition to the ARM and ARM7/ARM9 commands. - -@deffn Command {arm720t cp15} opcode [value] -@emph{DEPRECATED -- avoid using this. -Use the @command{arm mrc} or @command{arm mcr} commands instead.} - -Display cp15 register returned by the ARM instruction @var{opcode}; -else if a @var{value} is provided, that value is written to that register. -The @var{opcode} should be the value of either an MRC or MCR instruction. -@end deffn - @subsection ARM9 specific commands @cindex ARM9 @@ -9151,18 +9072,6 @@ shown in bits 38..33 of table 9-9 in the ARM920T TRM. (Not all registers can be written.) @end deffn -@deffn Command {arm920t cp15i} opcode [value [address]] -@emph{DEPRECATED -- avoid using this. -Use the @command{arm mrc} or @command{arm mcr} commands instead.} - -Interpreted access using ARM instruction @var{opcode}, which should -be the value of either an MRC or MCR instruction -(as shown tables 9-11, 9-12, and 9-13 in the ARM920T TRM). -If no @var{value} is provided, the result is displayed. -Else if that value is written using the specified @var{address}, -or using zero if no other address is provided. -@end deffn - @deffn Command {arm920t read_cache} filename Dump the content of ICache and DCache to a file named @file{filename}. @end deffn @@ -9470,61 +9379,146 @@ Selects whether interrupts will be processed when single stepping @end deffn -@subsection ARMv7-M specific commands +@subsection ARM CoreSight TPIU and SWO specific commands @cindex tracing @cindex SWO @cindex SWV @cindex TPIU -@cindex ITM -@cindex ETM -@deffn Command {tpiu config} (@option{disable} | ((@option{external} | @option{internal (@var{filename} | @var{:port} | -)}) @ - (@option{sync @var{port_width}} | ((@option{manchester} | @option{uart}) @var{formatter_enable})) @ - @var{TRACECLKIN_freq} [@var{trace_freq}])) - -ARMv7-M architecture provides several modules to generate debugging +ARM CoreSight provides several modules to generate debugging information internally (ITM, DWT and ETM). Their output is directed -through TPIU to be captured externally either on an SWO pin (this +through TPIU or SWO modules to be captured externally either on an SWO pin (this configuration is called SWV) or on a synchronous parallel trace port. -This command configures the TPIU module of the target and, if internal -capture mode is selected, starts to capture trace output by using the -debugger adapter features. +ARM CoreSight provides independent HW blocks named TPIU and SWO each with its +own functionality. Embedded in Cortex-M3 and M4, ARM provides an optional HW +block that includes both TPIU and SWO functionalities and is again named TPIU, +which causes quite some confusion. +The registers map of all the TPIU and SWO implementations allows using a single +driver that detects at runtime the features available. -Some targets require additional actions to be performed in the -@b{trace-config} handler for trace port to be activated. +The @command{tpiu} is used for either TPIU or SWO. +A convenient alias @command{swo} is available to help distinguish, in scripts, +the commands for SWO from the commands for TPIU. -Command options: +@deffn Command {swo} ... +Alias of @command{tpiu ...}. Can be used in scripts to distinguish the commands +for SWO from the commands for TPIU. +@end deffn + +@deffn Command {tpiu create} tpiu_name configparams... +Creates a TPIU or a SWO object. The two commands are equivalent. +Add the object in a list and add new commands (@command{@var{tpiu_name}}) +which are used for various purposes including additional configuration. + +@itemize @bullet +@item @var{tpiu_name} -- the name of the TPIU or SWO object. +This name is also used to create the object's command, referred to here +as @command{$tpiu_name}, and in other places where the TPIU or SWO needs to be identified. +@item @var{configparams} -- all parameters accepted by @command{$tpiu_name configure} are permitted. + +You @emph{must} set here the AP and MEM_AP base_address through @code{-dap @var{dap_name}}, +@code{-ap-num @var{ap_number}} and @code{-baseaddr @var{base_address}}. +@end itemize +@end deffn + +@deffn Command {tpiu names} +Lists all the TPIU or SWO objects created so far. The two commands are equivalent. +@end deffn + +@deffn Command {tpiu init} +Initialize all registered TPIU and SWO. The two commands are equivalent. +These commands are used internally during initialization. They can be issued +at any time after the initialization, too. +@end deffn + +@deffn Command {$tpiu_name cget} queryparm +Each configuration parameter accepted by @command{$tpiu_name configure} can be +individually queried, to return its current value. +The @var{queryparm} is a parameter name accepted by that command, such as @code{-dap}. +@end deffn + +@deffn Command {$tpiu_name configure} configparams... +The options accepted by this command may also be specified as parameters +to @command{tpiu create}. Their values can later be queried one at a time by +using the @command{$tpiu_name cget} command. + +@itemize @bullet +@item @code{-dap} @var{dap_name} -- names the DAP used to access this +TPIU. @xref{dapdeclaration,,DAP declaration}, on how to create and manage DAP instances. + +@item @code{-ap-num} @var{ap_number} -- sets DAP access port for TPIU, +@var{ap_number} is the numeric index of the DAP AP the TPIU is connected to. + +@item @code{-baseaddr} @var{base_address} -- sets the TPIU @var{base_address} where +to access the TPIU in the DAP AP memory space. + +@item @code{-protocol} (@option{sync}|@option{uart}|@option{manchester}) -- sets the +protocol used for trace data: @itemize @minus -@item @option{disable} disable TPIU handling; -@item @option{external} configure TPIU to let user capture trace -output externally (with an additional UART or logic analyzer hardware). -@item @option{internal (@var{filename} | @var{:port} | -)} configure TPIU and debug adapter to -gather trace data then: - -@itemize @minus -@item append it to a regular file or a named pipe if @var{filename} is specified. -@item listen to a TCP/IP port if @var{:port} is specified, then broadcast the trace data over this port. -@item if '-' is specified, OpenOCD will forward trace data to @command{tcl_trace} command. -@*@b{Note:} while broadcasting to file or TCP, the forwarding to @command{tcl_trace} will remain active. +@item @option{sync} -- synchronous parallel trace output mode, using @var{port_width} + data bits (default); +@item @option{uart} -- use asynchronous SWO mode with NRZ (same as regular UART 8N1) coding; +@item @option{manchester} -- use asynchronous SWO mode with Manchester coding. @end itemize -@item @option{sync @var{port_width}} use synchronous parallel trace output -mode, and set port width to @var{port_width}. -@item @option{manchester} use asynchronous SWO mode with Manchester -coding. -@item @option{uart} use asynchronous SWO mode with NRZ (same as -regular UART 8N1) coding. -@item @var{formatter_enable} is @option{on} or @option{off} to enable -or disable TPIU formatter which needs to be used when both ITM and ETM -data is to be output via SWO. -@item @var{TRACECLKIN_freq} this should be specified to match target's -current TRACECLKIN frequency (usually the same as HCLK). -@item @var{trace_freq} trace port frequency. Can be omitted in -internal mode to let the adapter driver select the maximum supported -rate automatically. +@item @code{-event} @var{event_name} @var{event_body} -- assigns an event handler, +a TCL string which is evaluated when the event is triggered. The events +@code{pre-enable}, @code{post-enable}, @code{pre-disable} and @code{post-disable} +are defined for TPIU/SWO. +A typical use case for the event @code{pre-enable} is to enable the trace clock +of the TPIU. + +@item @code{-output} (@option{external}|@option{:}@var{port}|@var{filename}|@option{-}) -- specifies +the destination of the trace data: +@itemize @minus +@item @option{external} -- configure TPIU/SWO to let user capture trace +output externally, either with an additional UART or with a logic analyzer (default); +@item @option{-} -- configure TPIU/SWO and debug adapter to gather trace data +and forward it to @command{tcl_trace} command; +@item @option{:}@var{port} -- configure TPIU/SWO and debug adapter to gather +trace data, open a TCP server at port @var{port} and send the trace data to +each connected client; +@item @var{filename} -- configure TPIU/SWO and debug adapter to +gather trace data and append it to @var{filename}, which can be +either a regular file or a named pipe. @end itemize +@item @code{-traceclk} @var{TRACECLKIN_freq} -- mandatory parameter. +Specifies the frequency in Hz of the trace clock. For the TPIU embedded in +Cortex-M3 or M4, this is usually the same frequency as HCLK. For protocol +@option{sync} this is twice the frequency of the pin data rate. + +@item @code{-pin-freq} @var{trace_freq} -- specifies the expected data rate +in Hz of the SWO pin. Parameter used only on protocols @option{uart} and +@option{manchester}. Can be omitted to let the adapter driver select the +maximum supported rate automatically. + +@item @code{-port-width} @var{port_width} -- sets to @var{port_width} the width +of the synchronous parallel port used for trace output. Parameter used only on +protocol @option{sync}. If not specified, default value is @var{1}. + +@item @code{-formatter} (@option{0}|@option{1}) -- specifies if the formatter +should be enabled. Parameter used only on protocol @option{sync}. If not specified, +default value is @var{0}. +@end itemize +@end deffn + +@deffn Command {$tpiu_name enable} +Uses the parameters specified by the previous @command{$tpiu_name configure} +to configure and enable the TPIU or the SWO. +If required, the adapter is also configured and enabled to receive the trace +data. +This command can be used before @command{init}, but it will take effect only +after the @command{init}. +@end deffn + +@deffn Command {$tpiu_name disable} +Disable the TPIU or the SWO, terminating the receiving of the trace data. +@end deffn + + + Example usage: @enumerate @item STM32L152 board is programmed with an application that configures @@ -9552,12 +9546,20 @@ baud with our custom divisor to get 12MHz) @item OpenOCD invocation line: @example openocd -f interface/stlink.cfg \ - -c "transport select hla_swd" \ - -f target/stm32l1.cfg \ - -c "tpiu config external uart off 24000000 12000000" +-c "transport select hla_swd" \ +-f target/stm32l1.cfg \ +-c "stm32l1.tpiu configure -protocol uart" \ +-c "stm32l1.tpiu configure -traceclk 24000000 -pin-freq 12000000" \ +-c "stm32l1.tpiu enable" @end example @end enumerate -@end deffn + +@subsection ARMv7-M specific commands +@cindex tracing +@cindex SWO +@cindex SWV +@cindex ITM +@cindex ETM @deffn Command {itm port} @var{port} (@option{0}|@option{1}|@option{on}|@option{off}) Enable or disable trace output for ITM stimulus @var{port} (counting @@ -11932,6 +11934,8 @@ foreach who @{A B C D E@} @} @end example +@node License +@appendix The GNU Free Documentation License. @include fdl.texi @node OpenOCD Concept Index diff --git a/src/Makefile.am b/src/Makefile.am index 41153fb61..ac2381e49 100644 --- a/src/Makefile.am +++ b/src/Makefile.am @@ -69,6 +69,7 @@ BUILT_SOURCES += %D%/startup_tcl.inc # Convert .tcl to c-array %D%/startup_tcl.inc: $(STARTUP_TCL_SRCS) + mkdir -p %D% cat $^ | $(BIN2C) > $@ || { rm -f $@; false; } # add generated files to make clean list diff --git a/src/flash/nand/lpc32xx.c b/src/flash/nand/lpc32xx.c index d516522f3..6443beb39 100644 --- a/src/flash/nand/lpc32xx.c +++ b/src/flash/nand/lpc32xx.c @@ -60,14 +60,14 @@ static const int lp_ooblayout[] = { 58, 59, 60, 61, 62, 63 }; -typedef struct { +struct dmac_ll { volatile uint32_t dma_src; volatile uint32_t dma_dest; volatile uint32_t next_lli; volatile uint32_t next_ctrl; -} dmac_ll_t; +}; -static dmac_ll_t dmalist[(2048/256) * 2 + 1]; +static struct dmac_ll dmalist[(2048/256) * 2 + 1]; /* nand device lpc32xx */ @@ -867,14 +867,14 @@ static int lpc32xx_make_dma_list(uint32_t target_mem_base, uint32_t page_size, dmalist[i*2].dma_src = (do_read ? dmasrc : (dmasrc + i * 256)); dmalist[i*2].dma_dest = (do_read ? (dmadst + i * 256) : dmadst); dmalist[i*2].next_lli = - target_mem_base + (i*2 + 1) * sizeof(dmac_ll_t); + target_mem_base + (i*2 + 1) * sizeof(struct dmac_ll); dmalist[i*2].next_ctrl = ctrl; dmalist[(i*2) + 1].dma_src = 0x20020034;/* SLC_ECC */ dmalist[(i*2) + 1].dma_dest = target_mem_base + ECC_OFFS + i * 4; dmalist[(i*2) + 1].next_lli = - target_mem_base + (i*2 + 2) * sizeof(dmac_ll_t); + target_mem_base + (i*2 + 2) * sizeof(struct dmac_ll); dmalist[(i*2) + 1].next_ctrl = ecc_ctrl; } @@ -1063,7 +1063,7 @@ static int lpc32xx_write_page_slc(struct nand_device *nand, XXX: Assumes host and target have same byte sex. */ retval = target_write_memory(target, target_mem_base, 4, - nll * sizeof(dmac_ll_t) / 4, + nll * sizeof(struct dmac_ll) / 4, (uint8_t *)dmalist); if (ERROR_OK != retval) { LOG_ERROR("Could not write DMA descriptors to IRAM"); @@ -1104,7 +1104,7 @@ static int lpc32xx_write_page_slc(struct nand_device *nand, /* Write first descriptor to DMA controller */ retval = target_write_memory(target, 0x31000100, 4, - sizeof(dmac_ll_t) / 4, + sizeof(struct dmac_ll) / 4, (uint8_t *)dmalist); if (ERROR_OK != retval) { LOG_ERROR("Could not write DMA descriptor to DMAC"); @@ -1161,7 +1161,7 @@ static int lpc32xx_write_page_slc(struct nand_device *nand, /* Write OOB descriptor to DMA controller */ retval = target_write_memory(target, 0x31000100, 4, - sizeof(dmac_ll_t) / 4, + sizeof(struct dmac_ll) / 4, (uint8_t *)(&dmalist[nll-1])); if (ERROR_OK != retval) { LOG_ERROR("Could not write OOB DMA descriptor to DMAC"); @@ -1460,7 +1460,7 @@ static int lpc32xx_read_page_slc(struct nand_device *nand, XXX: Assumes host and target have same byte sex. */ retval = target_write_memory(target, target_mem_base, 4, - nll * sizeof(dmac_ll_t) / 4, + nll * sizeof(struct dmac_ll) / 4, (uint8_t *)dmalist); if (ERROR_OK != retval) { LOG_ERROR("Could not write DMA descriptors to IRAM"); @@ -1489,7 +1489,7 @@ static int lpc32xx_read_page_slc(struct nand_device *nand, /* Write first descriptor to DMA controller */ retval = target_write_memory(target, 0x31000100, 4, - sizeof(dmac_ll_t) / 4, (uint8_t *)dmalist); + sizeof(struct dmac_ll) / 4, (uint8_t *)dmalist); if (ERROR_OK != retval) { LOG_ERROR("Could not write DMA descriptor to DMAC"); return retval; diff --git a/src/flash/nor/atsame5.c b/src/flash/nor/atsame5.c index ed0bef463..50e56a72a 100644 --- a/src/flash/nor/atsame5.c +++ b/src/flash/nor/atsame5.c @@ -113,7 +113,7 @@ struct samd_part { }; /* See SAM D5x/E5x Family Silicon Errata and Data Sheet Clarification - * DS80000748B */ + * DS80000748K */ /* Known SAMD51 parts. */ static const struct samd_part samd51_parts[] = { { 0x00, "SAMD51P20A", 1024, 256 }, @@ -134,6 +134,8 @@ static const struct samd_part same51_parts[] = { { 0x02, "SAME51J19A", 512, 192 }, { 0x03, "SAME51J18A", 256, 128 }, { 0x04, "SAME51J20A", 1024, 256 }, + { 0x05, "SAME51G19A", 512, 192 }, /* New in rev D */ + { 0x06, "SAME51G18A", 256, 128 }, /* New in rev D */ }; /* Known SAME53 parts. */ diff --git a/src/flash/nor/cfi.c b/src/flash/nor/cfi.c index 5f5071e69..c9eb38b9b 100644 --- a/src/flash/nor/cfi.c +++ b/src/flash/nor/cfi.c @@ -832,17 +832,13 @@ int cfi_flash_bank_cmd(struct flash_bank *bank, unsigned int argc, const char ** return ERROR_FLASH_BANK_INVALID; } - cfi_info = malloc(sizeof(struct cfi_flash_bank)); - cfi_info->probed = false; - cfi_info->erase_region_info = NULL; - cfi_info->pri_ext = NULL; + cfi_info = calloc(1, sizeof(struct cfi_flash_bank)); + if (cfi_info == NULL) { + LOG_ERROR("No memory for flash bank info"); + return ERROR_FAIL; + } bank->driver_priv = cfi_info; - cfi_info->x16_as_x8 = false; - cfi_info->jedec_probe = false; - cfi_info->not_cfi = false; - cfi_info->data_swap = false; - for (unsigned i = 6; i < argc; i++) { if (strcmp(argv[i], "x16_as_x8") == 0) cfi_info->x16_as_x8 = true; diff --git a/src/flash/nor/numicro.c b/src/flash/nor/numicro.c index 7609fa81c..1971daa24 100644 --- a/src/flash/nor/numicro.c +++ b/src/flash/nor/numicro.c @@ -1243,7 +1243,7 @@ static uint32_t numicro_fmc_cmd(struct target *target, uint32_t cmd, uint32_t ad retval = target_read_u32(target, NUMICRO_FLASH_ISPTRG, &status); if (retval != ERROR_OK) return retval; - LOG_DEBUG("status: 0x%" PRIx32 "", status); + LOG_DEBUG("status: 0x%" PRIx32 "", status); if ((status & (ISPTRG_ISPGO)) == 0) break; if (timeout-- <= 0) { @@ -1512,7 +1512,7 @@ static int numicro_erase(struct flash_bank *bank, unsigned int first, retval = target_read_u32(target, NUMICRO_FLASH_ISPTRG, &status); if (retval != ERROR_OK) return retval; - LOG_DEBUG("status: 0x%" PRIx32 "", status); + LOG_DEBUG("status: 0x%" PRIx32 "", status); if (status == 0) break; if (timeout-- <= 0) { @@ -1601,7 +1601,7 @@ static int numicro_write(struct flash_bank *bank, const uint8_t *buffer, retval = target_read_u32(target, NUMICRO_FLASH_ISPTRG, &status); if (retval != ERROR_OK) return retval; - LOG_DEBUG("status: 0x%" PRIx32 "", status); + LOG_DEBUG("status: 0x%" PRIx32 "", status); if (status == 0) break; if (timeout-- <= 0) { diff --git a/src/flash/nor/stm32l4x.c b/src/flash/nor/stm32l4x.c index 55a8d8ff3..594bce039 100644 --- a/src/flash/nor/stm32l4x.c +++ b/src/flash/nor/stm32l4x.c @@ -116,6 +116,19 @@ #define FLASH_ERASE_TIMEOUT 250 + +/* relevant STM32L4 flags ****************************************************/ +#define F_NONE 0 +/* this flag indicates if the device flash is with dual bank architecture */ +#define F_HAS_DUAL_BANK BIT(0) +/* this flags is used for dual bank devices only, it indicates if the + * 4 WRPxx are usable if the device is configured in single-bank mode */ +#define F_USE_ALL_WRPXX BIT(1) +/* this flag indicates if the device embeds a TrustZone security feature */ +#define F_HAS_TZ BIT(2) +/* end of STM32L4 flags ******************************************************/ + + enum stm32l4_flash_reg_index { STM32_FLASH_ACR_INDEX, STM32_FLASH_KEYR_INDEX, @@ -130,6 +143,13 @@ enum stm32l4_flash_reg_index { STM32_FLASH_REG_INDEX_NUM, }; +enum stm32l4_rdp { + RDP_LEVEL_0 = 0xAA, + RDP_LEVEL_0_5 = 0x55, /* for devices with TrustZone enabled */ + RDP_LEVEL_1 = 0x00, + RDP_LEVEL_2 = 0xCC +}; + static const uint32_t stm32l4_flash_regs[STM32_FLASH_REG_INDEX_NUM] = { [STM32_FLASH_ACR_INDEX] = 0x000, [STM32_FLASH_KEYR_INDEX] = 0x008, @@ -167,10 +187,12 @@ struct stm32l4_part_info { const struct stm32l4_rev *revs; const size_t num_revs; const uint16_t max_flash_size_kb; - const bool has_dual_bank; + const uint32_t flags; /* one bit per feature, see STM32L4 flags: macros F_XXX */ const uint32_t flash_regs_base; const uint32_t *default_flash_regs; const uint32_t fsize_addr; + const uint32_t otp_base; + const uint32_t otp_size; }; struct stm32l4_flash_bank { @@ -183,6 +205,24 @@ struct stm32l4_flash_bank { uint32_t wrpxxr_mask; const struct stm32l4_part_info *part_info; const uint32_t *flash_regs; + bool otp_enabled; + enum stm32l4_rdp rdp; + bool tzen; +}; + +enum stm32_bank_id { + STM32_BANK1, + STM32_BANK2, + STM32_ALL_BANKS +}; + +struct stm32l4_wrp { + enum stm32l4_flash_reg_index reg_idx; + uint32_t value; + bool used; + int first; + int last; + int offset; }; /* human readable list of families this drivers supports (sorted alphabetically) */ @@ -259,10 +299,12 @@ static const struct stm32l4_part_info stm32l4_parts[] = { .num_revs = ARRAY_SIZE(stm32_415_revs), .device_str = "STM32L47/L48xx", .max_flash_size_kb = 1024, - .has_dual_bank = true, + .flags = F_HAS_DUAL_BANK, .flash_regs_base = 0x40022000, .default_flash_regs = stm32l4_flash_regs, .fsize_addr = 0x1FFF75E0, + .otp_base = 0x1FFF7000, + .otp_size = 1024, }, { .id = 0x435, @@ -270,10 +312,12 @@ static const struct stm32l4_part_info stm32l4_parts[] = { .num_revs = ARRAY_SIZE(stm32_435_revs), .device_str = "STM32L43/L44xx", .max_flash_size_kb = 256, - .has_dual_bank = false, + .flags = F_NONE, .flash_regs_base = 0x40022000, .default_flash_regs = stm32l4_flash_regs, .fsize_addr = 0x1FFF75E0, + .otp_base = 0x1FFF7000, + .otp_size = 1024, }, { .id = 0x460, @@ -281,10 +325,12 @@ static const struct stm32l4_part_info stm32l4_parts[] = { .num_revs = ARRAY_SIZE(stm32_460_revs), .device_str = "STM32G07/G08xx", .max_flash_size_kb = 128, - .has_dual_bank = false, + .flags = F_NONE, .flash_regs_base = 0x40022000, .default_flash_regs = stm32l4_flash_regs, .fsize_addr = 0x1FFF75E0, + .otp_base = 0x1FFF7000, + .otp_size = 1024, }, { .id = 0x461, @@ -292,10 +338,12 @@ static const struct stm32l4_part_info stm32l4_parts[] = { .num_revs = ARRAY_SIZE(stm32_461_revs), .device_str = "STM32L49/L4Axx", .max_flash_size_kb = 1024, - .has_dual_bank = true, + .flags = F_HAS_DUAL_BANK, .flash_regs_base = 0x40022000, .default_flash_regs = stm32l4_flash_regs, .fsize_addr = 0x1FFF75E0, + .otp_base = 0x1FFF7000, + .otp_size = 1024, }, { .id = 0x462, @@ -303,10 +351,12 @@ static const struct stm32l4_part_info stm32l4_parts[] = { .num_revs = ARRAY_SIZE(stm32_462_revs), .device_str = "STM32L45/L46xx", .max_flash_size_kb = 512, - .has_dual_bank = false, + .flags = F_NONE, .flash_regs_base = 0x40022000, .default_flash_regs = stm32l4_flash_regs, .fsize_addr = 0x1FFF75E0, + .otp_base = 0x1FFF7000, + .otp_size = 1024, }, { .id = 0x464, @@ -314,10 +364,12 @@ static const struct stm32l4_part_info stm32l4_parts[] = { .num_revs = ARRAY_SIZE(stm32_464_revs), .device_str = "STM32L41/L42xx", .max_flash_size_kb = 128, - .has_dual_bank = false, + .flags = F_NONE, .flash_regs_base = 0x40022000, .default_flash_regs = stm32l4_flash_regs, .fsize_addr = 0x1FFF75E0, + .otp_base = 0x1FFF7000, + .otp_size = 1024, }, { .id = 0x466, @@ -325,10 +377,12 @@ static const struct stm32l4_part_info stm32l4_parts[] = { .num_revs = ARRAY_SIZE(stm32_466_revs), .device_str = "STM32G03/G04xx", .max_flash_size_kb = 64, - .has_dual_bank = false, + .flags = F_NONE, .flash_regs_base = 0x40022000, .default_flash_regs = stm32l4_flash_regs, .fsize_addr = 0x1FFF75E0, + .otp_base = 0x1FFF7000, + .otp_size = 1024, }, { .id = 0x468, @@ -336,10 +390,12 @@ static const struct stm32l4_part_info stm32l4_parts[] = { .num_revs = ARRAY_SIZE(stm32_468_revs), .device_str = "STM32G43/G44xx", .max_flash_size_kb = 128, - .has_dual_bank = false, + .flags = F_NONE, .flash_regs_base = 0x40022000, .default_flash_regs = stm32l4_flash_regs, .fsize_addr = 0x1FFF75E0, + .otp_base = 0x1FFF7000, + .otp_size = 1024, }, { .id = 0x469, @@ -347,10 +403,12 @@ static const struct stm32l4_part_info stm32l4_parts[] = { .num_revs = ARRAY_SIZE(stm32_469_revs), .device_str = "STM32G47/G48xx", .max_flash_size_kb = 512, - .has_dual_bank = true, + .flags = F_HAS_DUAL_BANK | F_USE_ALL_WRPXX, .flash_regs_base = 0x40022000, .default_flash_regs = stm32l4_flash_regs, .fsize_addr = 0x1FFF75E0, + .otp_base = 0x1FFF7000, + .otp_size = 1024, }, { .id = 0x470, @@ -358,10 +416,12 @@ static const struct stm32l4_part_info stm32l4_parts[] = { .num_revs = ARRAY_SIZE(stm32_470_revs), .device_str = "STM32L4R/L4Sxx", .max_flash_size_kb = 2048, - .has_dual_bank = true, + .flags = F_HAS_DUAL_BANK | F_USE_ALL_WRPXX, .flash_regs_base = 0x40022000, .default_flash_regs = stm32l4_flash_regs, .fsize_addr = 0x1FFF75E0, + .otp_base = 0x1FFF7000, + .otp_size = 1024, }, { .id = 0x471, @@ -369,10 +429,12 @@ static const struct stm32l4_part_info stm32l4_parts[] = { .num_revs = ARRAY_SIZE(stm32_471_revs), .device_str = "STM32L4P5/L4Q5x", .max_flash_size_kb = 1024, - .has_dual_bank = true, + .flags = F_HAS_DUAL_BANK | F_USE_ALL_WRPXX, .flash_regs_base = 0x40022000, .default_flash_regs = stm32l4_flash_regs, .fsize_addr = 0x1FFF75E0, + .otp_base = 0x1FFF7000, + .otp_size = 1024, }, { .id = 0x472, @@ -380,10 +442,12 @@ static const struct stm32l4_part_info stm32l4_parts[] = { .num_revs = ARRAY_SIZE(stm32_472_revs), .device_str = "STM32L55/L56xx", .max_flash_size_kb = 512, - .has_dual_bank = true, + .flags = F_HAS_DUAL_BANK | F_USE_ALL_WRPXX | F_HAS_TZ, .flash_regs_base = 0x40022000, .default_flash_regs = stm32l5_ns_flash_regs, .fsize_addr = 0x0BFA05E0, + .otp_base = 0x0BFA0000, + .otp_size = 512, }, { .id = 0x479, @@ -391,10 +455,12 @@ static const struct stm32l4_part_info stm32l4_parts[] = { .num_revs = ARRAY_SIZE(stm32_479_revs), .device_str = "STM32G49/G4Axx", .max_flash_size_kb = 512, - .has_dual_bank = false, + .flags = F_NONE, .flash_regs_base = 0x40022000, .default_flash_regs = stm32l4_flash_regs, .fsize_addr = 0x1FFF75E0, + .otp_base = 0x1FFF7000, + .otp_size = 1024, }, { .id = 0x495, @@ -402,10 +468,12 @@ static const struct stm32l4_part_info stm32l4_parts[] = { .num_revs = ARRAY_SIZE(stm32_495_revs), .device_str = "STM32WB5x", .max_flash_size_kb = 1024, - .has_dual_bank = false, + .flags = F_NONE, .flash_regs_base = 0x58004000, .default_flash_regs = stm32l4_flash_regs, .fsize_addr = 0x1FFF75E0, + .otp_base = 0x1FFF7000, + .otp_size = 1024, }, { .id = 0x496, @@ -413,10 +481,12 @@ static const struct stm32l4_part_info stm32l4_parts[] = { .num_revs = ARRAY_SIZE(stm32_496_revs), .device_str = "STM32WB3x", .max_flash_size_kb = 512, - .has_dual_bank = false, + .flags = F_NONE, .flash_regs_base = 0x58004000, .default_flash_regs = stm32l4_flash_regs, .fsize_addr = 0x1FFF75E0, + .otp_base = 0x1FFF7000, + .otp_size = 1024, }, { .id = 0x497, @@ -424,10 +494,12 @@ static const struct stm32l4_part_info stm32l4_parts[] = { .num_revs = ARRAY_SIZE(stm32_497_revs), .device_str = "STM32WLEx", .max_flash_size_kb = 256, - .has_dual_bank = false, + .flags = F_NONE, .flash_regs_base = 0x58004000, .default_flash_regs = stm32l4_flash_regs, .fsize_addr = 0x1FFF75E0, + .otp_base = 0x1FFF7000, + .otp_size = 1024, }, }; @@ -439,7 +511,11 @@ FLASH_BANK_COMMAND_HANDLER(stm32l4_flash_bank_command) if (CMD_ARGC < 6) return ERROR_COMMAND_SYNTAX_ERROR; - stm32l4_info = malloc(sizeof(struct stm32l4_flash_bank)); + /* fix-up bank base address: 0 is used for normal flash memory */ + if (bank->base == 0) + bank->base = STM32_FLASH_BANK_BASE; + + stm32l4_info = calloc(1, sizeof(struct stm32l4_flash_bank)); if (!stm32l4_info) return ERROR_FAIL; /* Checkme: What better error to use?*/ bank->driver_priv = stm32l4_info; @@ -449,11 +525,129 @@ FLASH_BANK_COMMAND_HANDLER(stm32l4_flash_bank_command) bank->write_start_alignment = bank->write_end_alignment = 8; stm32l4_info->probed = false; + stm32l4_info->otp_enabled = false; stm32l4_info->user_bank_size = bank->size; return ERROR_OK; } +/* bitmap helper extension */ +struct range { + unsigned int start; + unsigned int end; +}; + +static void bitmap_to_ranges(unsigned long *bitmap, unsigned int nbits, + struct range *ranges, unsigned int *ranges_count) { + *ranges_count = 0; + bool last_bit = 0, cur_bit; + for (unsigned int i = 0; i < nbits; i++) { + cur_bit = test_bit(i, bitmap); + + if (cur_bit && !last_bit) { + (*ranges_count)++; + ranges[*ranges_count - 1].start = i; + ranges[*ranges_count - 1].end = i; + } else if (cur_bit && last_bit) { + /* update (increment) the end this range */ + ranges[*ranges_count - 1].end = i; + } + + last_bit = cur_bit; + } +} + +static inline int range_print_one(struct range *range, char *str) +{ + if (range->start == range->end) + return sprintf(str, "[%d]", range->start); + + return sprintf(str, "[%d,%d]", range->start, range->end); +} + +static char *range_print_alloc(struct range *ranges, unsigned int ranges_count) +{ + /* each range will be printed like the following: [start,end] + * start and end, both are unsigned int, an unsigned int takes 10 characters max + * plus 3 characters for '[', ',' and ']' + * thus means each range can take maximum 23 character + * after each range we add a ' ' as separator and finally we need the '\0' + * if the ranges_count is zero we reserve one char for '\0' to return an empty string */ + char *str = calloc(1, ranges_count * (24 * sizeof(char)) + 1); + char *ptr = str; + + for (unsigned int i = 0; i < ranges_count; i++) { + ptr += range_print_one(&(ranges[i]), ptr); + + if (i < ranges_count - 1) + *(ptr++) = ' '; + } + + return str; +} + +/* end of bitmap helper extension */ + +static inline bool stm32l4_is_otp(struct flash_bank *bank) +{ + struct stm32l4_flash_bank *stm32l4_info = bank->driver_priv; + return bank->base == stm32l4_info->part_info->otp_base; +} + +static int stm32l4_otp_enable(struct flash_bank *bank, bool enable) +{ + struct stm32l4_flash_bank *stm32l4_info = bank->driver_priv; + + if (!stm32l4_is_otp(bank)) + return ERROR_FAIL; + + char *op_str = enable ? "enabled" : "disabled"; + + LOG_INFO("OTP memory (bank #%d) is %s%s for write commands", + bank->bank_number, + stm32l4_info->otp_enabled == enable ? "already " : "", + op_str); + + stm32l4_info->otp_enabled = enable; + + return ERROR_OK; +} + +static inline bool stm32l4_otp_is_enabled(struct flash_bank *bank) +{ + struct stm32l4_flash_bank *stm32l4_info = bank->driver_priv; + return stm32l4_info->otp_enabled; +} + +static void stm32l4_sync_rdp_tzen(struct flash_bank *bank, uint32_t optr_value) +{ + struct stm32l4_flash_bank *stm32l4_info = bank->driver_priv; + + bool tzen = false; + + if (stm32l4_info->part_info->flags & F_HAS_TZ) + tzen = (optr_value & FLASH_TZEN) != 0; + + uint32_t rdp = optr_value & FLASH_RDP_MASK; + + /* for devices without TrustZone: + * RDP level 0 and 2 values are to 0xAA and 0xCC + * Any other value corresponds to RDP level 1 + * for devices with TrusZone: + * RDP level 0 and 2 values are 0xAA and 0xCC + * RDP level 0.5 value is 0x55 only if TZEN = 1 + * Any other value corresponds to RDP level 1, including 0x55 if TZEN = 0 + */ + + if (rdp != RDP_LEVEL_0 && rdp != RDP_LEVEL_2) { + if (!tzen || (tzen && rdp != RDP_LEVEL_0_5)) + rdp = RDP_LEVEL_1; + } + + stm32l4_info->tzen = tzen; + stm32l4_info->rdp = rdp; +} + static inline uint32_t stm32l4_get_flash_reg(struct flash_bank *bank, uint32_t reg_offset) { struct stm32l4_flash_bank *stm32l4_info = bank->driver_priv; @@ -635,53 +829,125 @@ err_lock: return retval2; } -static int stm32l4_protect_check(struct flash_bank *bank) +static int stm32l4_get_one_wrpxy(struct flash_bank *bank, struct stm32l4_wrp *wrpxy, + enum stm32l4_flash_reg_index reg_idx, int offset) +{ + struct stm32l4_flash_bank *stm32l4_info = bank->driver_priv; + int ret; + + wrpxy->reg_idx = reg_idx; + wrpxy->offset = offset; + + ret = stm32l4_read_flash_reg_by_index(bank, wrpxy->reg_idx , &wrpxy->value); + if (ret != ERROR_OK) + return ret; + + wrpxy->first = (wrpxy->value & stm32l4_info->wrpxxr_mask) + wrpxy->offset; + wrpxy->last = ((wrpxy->value >> 16) & stm32l4_info->wrpxxr_mask) + wrpxy->offset; + wrpxy->used = wrpxy->first <= wrpxy->last; + + return ERROR_OK; +} + +static int stm32l4_get_all_wrpxy(struct flash_bank *bank, enum stm32_bank_id dev_bank_id, + struct stm32l4_wrp *wrpxy, unsigned int *n_wrp) +{ + struct stm32l4_flash_bank *stm32l4_info = bank->driver_priv; + int ret; + + *n_wrp = 0; + + /* for single bank devices there is 2 WRP regions. + * for dual bank devices there is 2 WRP regions per bank, + * if configured as single bank only 2 WRP are usable + * except for STM32L4R/S/P/Q, G4 cat3, L5 ... all 4 WRP are usable + * note: this should be revised, if a device will have the SWAP banks option + */ + + int wrp2y_sectors_offset = -1; /* -1 : unused */ + + /* if bank_id is BANK1 or ALL_BANKS */ + if (dev_bank_id != STM32_BANK2) { + /* get FLASH_WRP1AR */ + ret = stm32l4_get_one_wrpxy(bank, &wrpxy[(*n_wrp)++], STM32_FLASH_WRP1AR_INDEX, 0); + if (ret != ERROR_OK) + return ret; + + /* get WRP1BR */ + ret = stm32l4_get_one_wrpxy(bank, &wrpxy[(*n_wrp)++], STM32_FLASH_WRP1BR_INDEX, 0); + if (ret != ERROR_OK) + return ret; + + /* for some devices (like STM32L4R/S) in single-bank mode, the 4 WRPxx are usable */ + if ((stm32l4_info->part_info->flags & F_USE_ALL_WRPXX) && !stm32l4_info->dual_bank_mode) + wrp2y_sectors_offset = 0; + } + + /* if bank_id is BANK2 or ALL_BANKS */ + if (dev_bank_id != STM32_BANK1 && stm32l4_info->dual_bank_mode) + wrp2y_sectors_offset = stm32l4_info->bank1_sectors; + + if (wrp2y_sectors_offset > -1) { + /* get WRP2AR */ + ret = stm32l4_get_one_wrpxy(bank, &wrpxy[(*n_wrp)++], STM32_FLASH_WRP2AR_INDEX, wrp2y_sectors_offset); + if (ret != ERROR_OK) + return ret; + + /* get WRP2BR */ + ret = stm32l4_get_one_wrpxy(bank, &wrpxy[(*n_wrp)++], STM32_FLASH_WRP2BR_INDEX, wrp2y_sectors_offset); + if (ret != ERROR_OK) + return ret; + } + + return ERROR_OK; +} + +static int stm32l4_write_one_wrpxy(struct flash_bank *bank, struct stm32l4_wrp *wrpxy) { struct stm32l4_flash_bank *stm32l4_info = bank->driver_priv; - uint32_t wrp1ar, wrp1br, wrp2ar, wrp2br; - stm32l4_read_flash_reg_by_index(bank, STM32_FLASH_WRP1AR_INDEX, &wrp1ar); - stm32l4_read_flash_reg_by_index(bank, STM32_FLASH_WRP1BR_INDEX, &wrp1br); - if (stm32l4_info->part_info->has_dual_bank) { - stm32l4_read_flash_reg_by_index(bank, STM32_FLASH_WRP2AR_INDEX, &wrp2ar); - stm32l4_read_flash_reg_by_index(bank, STM32_FLASH_WRP2BR_INDEX, &wrp2br); - } else { - /* prevent uninitialized errors */ - wrp2ar = 0; - wrp2br = 0; + int wrp_start = wrpxy->first - wrpxy->offset; + int wrp_end = wrpxy->last - wrpxy->offset; + + uint32_t wrp_value = (wrp_start & stm32l4_info->wrpxxr_mask) | ((wrp_end & stm32l4_info->wrpxxr_mask) << 16); + + return stm32l4_write_option(bank, stm32l4_info->flash_regs[wrpxy->reg_idx], wrp_value, 0xffffffff); +} + +static int stm32l4_write_all_wrpxy(struct flash_bank *bank, struct stm32l4_wrp *wrpxy, unsigned int n_wrp) +{ + int ret; + + for (unsigned int i = 0; i < n_wrp; i++) { + ret = stm32l4_write_one_wrpxy(bank, &wrpxy[i]); + if (ret != ERROR_OK) + return ret; } - const uint8_t wrp1a_start = wrp1ar & stm32l4_info->wrpxxr_mask; - const uint8_t wrp1a_end = (wrp1ar >> 16) & stm32l4_info->wrpxxr_mask; - const uint8_t wrp1b_start = wrp1br & stm32l4_info->wrpxxr_mask; - const uint8_t wrp1b_end = (wrp1br >> 16) & stm32l4_info->wrpxxr_mask; - const uint8_t wrp2a_start = wrp2ar & stm32l4_info->wrpxxr_mask; - const uint8_t wrp2a_end = (wrp2ar >> 16) & stm32l4_info->wrpxxr_mask; - const uint8_t wrp2b_start = wrp2br & stm32l4_info->wrpxxr_mask; - const uint8_t wrp2b_end = (wrp2br >> 16) & stm32l4_info->wrpxxr_mask; + return ERROR_OK; +} - for (unsigned int i = 0; i < bank->num_sectors; i++) { - if (i < stm32l4_info->bank1_sectors) { - if (((i >= wrp1a_start) && - (i <= wrp1a_end)) || - ((i >= wrp1b_start) && - (i <= wrp1b_end))) - bank->sectors[i].is_protected = 1; - else - bank->sectors[i].is_protected = 0; - } else { - assert(stm32l4_info->part_info->has_dual_bank == true); - uint8_t snb; - snb = i - stm32l4_info->bank1_sectors; - if (((snb >= wrp2a_start) && - (snb <= wrp2a_end)) || - ((snb >= wrp2b_start) && - (snb <= wrp2b_end))) - bank->sectors[i].is_protected = 1; - else - bank->sectors[i].is_protected = 0; +static int stm32l4_protect_check(struct flash_bank *bank) +{ + unsigned int n_wrp; + struct stm32l4_wrp wrpxy[4]; + + int ret = stm32l4_get_all_wrpxy(bank, STM32_ALL_BANKS, wrpxy, &n_wrp); + if (ret != ERROR_OK) + return ret; + + /* initialize all sectors as unprotected */ + for (unsigned int i = 0; i < bank->num_sectors; i++) + bank->sectors[i].is_protected = 0; + + /* now check WRPxy and mark the protected sectors */ + for (unsigned int i = 0; i < n_wrp; i++) { + if (wrpxy[i].used) { + for (int s = wrpxy[i].first; s <= wrpxy[i].last; s++) + bank->sectors[s].is_protected = 1; } } + return ERROR_OK; } @@ -693,6 +959,11 @@ static int stm32l4_erase(struct flash_bank *bank, unsigned int first, assert((first <= last) && (last < bank->num_sectors)); + if (stm32l4_is_otp(bank)) { + LOG_ERROR("cannot erase OTP memory"); + return ERROR_FLASH_OPER_UNSUPPORTED; + } + if (bank->target->state != TARGET_HALTED) { LOG_ERROR("Target not halted"); return ERROR_TARGET_NOT_HALTED; @@ -743,40 +1014,133 @@ err_lock: return retval2; } -static int stm32l4_protect(struct flash_bank *bank, int set, unsigned int first, - unsigned int last) +static int stm32l4_protect(struct flash_bank *bank, int set, unsigned int first, unsigned int last) { struct target *target = bank->target; struct stm32l4_flash_bank *stm32l4_info = bank->driver_priv; + int ret = ERROR_OK; + unsigned int i; + + if (stm32l4_is_otp(bank)) { + LOG_ERROR("cannot protect/unprotect OTP memory"); + return ERROR_FLASH_OPER_UNSUPPORTED; + } if (target->state != TARGET_HALTED) { LOG_ERROR("Target not halted"); return ERROR_TARGET_NOT_HALTED; } - int ret = ERROR_OK; - /* Bank 2 */ - uint32_t reg_value = 0xFF; /* Default to bank un-protected */ + /* the requested sectors could be located into bank1 and/or bank2 */ + bool use_bank2 = false; if (last >= stm32l4_info->bank1_sectors) { - if (set == 1) { - uint8_t begin = first > stm32l4_info->bank1_sectors ? first : 0x00; - reg_value = ((last & 0xFF) << 16) | begin; + if (first < stm32l4_info->bank1_sectors) { + /* the requested sectors for (un)protection are shared between + * bank 1 and 2, then split the operation */ + + /* 1- deal with bank 1 sectors */ + LOG_DEBUG("The requested sectors for %s are shared between bank 1 and 2", + set ? "protection" : "unprotection"); + ret = stm32l4_protect(bank, set, first, stm32l4_info->bank1_sectors - 1); + if (ret != ERROR_OK) + return ret; + + /* 2- then continue with bank 2 sectors */ + first = stm32l4_info->bank1_sectors; } - ret = stm32l4_write_option(bank, stm32l4_info->flash_regs[STM32_FLASH_WRP2AR_INDEX], reg_value, 0xffffffff); + use_bank2 = true; } - /* Bank 1 */ - reg_value = 0xFF; /* Default to bank un-protected */ - if (first < stm32l4_info->bank1_sectors) { - if (set == 1) { - uint8_t end = last >= stm32l4_info->bank1_sectors ? 0xFF : last; - reg_value = (end << 16) | (first & 0xFF); + + /* refresh the sectors' protection */ + ret = stm32l4_protect_check(bank); + if (ret != ERROR_OK) + return ret; + + /* check if the desired protection is already configured */ + for (i = first; i <= last; i++) { + if (bank->sectors[i].is_protected != set) + break; + else if (i == last) { + LOG_INFO("The specified sectors are already %s", set ? "protected" : "unprotected"); + return ERROR_OK; } - - ret = stm32l4_write_option(bank, stm32l4_info->flash_regs[STM32_FLASH_WRP1AR_INDEX], reg_value, 0xffffffff); } - return ret; + /* all sectors from first to last (or part of them) could have different + * protection other than the requested */ + unsigned int n_wrp; + struct stm32l4_wrp wrpxy[4]; + + ret = stm32l4_get_all_wrpxy(bank, use_bank2 ? STM32_BANK2 : STM32_BANK1, wrpxy, &n_wrp); + if (ret != ERROR_OK) + return ret; + + /* use bitmap and range helpers to optimize the WRP usage */ + DECLARE_BITMAP(pages, bank->num_sectors); + bitmap_zero(pages, bank->num_sectors); + + for (i = 0; i < n_wrp; i++) { + if (wrpxy[i].used) { + for (int p = wrpxy[i].first; p <= wrpxy[i].last; p++) + set_bit(p, pages); + } + } + + /* we have at most 'n_wrp' WRP areas + * add one range if the user is trying to protect a fifth range */ + struct range ranges[n_wrp + 1]; + unsigned int ranges_count = 0; + + bitmap_to_ranges(pages, bank->num_sectors, ranges, &ranges_count); + + /* pretty-print the currently protected ranges */ + if (ranges_count > 0) { + char *ranges_str = range_print_alloc(ranges, ranges_count); + LOG_DEBUG("current protected areas: %s", ranges_str); + free(ranges_str); + } else + LOG_DEBUG("current protected areas: none"); + + if (set) { /* flash protect */ + for (i = first; i <= last; i++) + set_bit(i, pages); + } else { /* flash unprotect */ + for (i = first; i <= last; i++) + clear_bit(i, pages); + } + + /* check the ranges_count after the user request */ + bitmap_to_ranges(pages, bank->num_sectors, ranges, &ranges_count); + + /* pretty-print the requested areas for protection */ + if (ranges_count > 0) { + char *ranges_str = range_print_alloc(ranges, ranges_count); + LOG_DEBUG("requested areas for protection: %s", ranges_str); + free(ranges_str); + } else + LOG_DEBUG("requested areas for protection: none"); + + if (ranges_count > n_wrp) { + LOG_ERROR("cannot set the requested protection " + "(only %u write protection areas are available)" , n_wrp); + return ERROR_FAIL; + } + + /* re-init all WRPxy as disabled (first > last)*/ + for (i = 0; i < n_wrp; i++) { + wrpxy[i].first = wrpxy[i].offset + 1; + wrpxy[i].last = wrpxy[i].offset; + } + + /* then configure WRPxy areas */ + for (i = 0; i < ranges_count; i++) { + wrpxy[i].first = ranges[i].start; + wrpxy[i].last = ranges[i].end; + } + + /* finally write WRPxy registers */ + return stm32l4_write_all_wrpxy(bank, wrpxy, n_wrp); } /* Count is in double-words */ @@ -883,6 +1247,11 @@ static int stm32l4_write(struct flash_bank *bank, const uint8_t *buffer, { int retval = ERROR_OK, retval2; + if (stm32l4_is_otp(bank) && !stm32l4_otp_is_enabled(bank)) { + LOG_ERROR("OTP memory is disabled for write commands"); + return ERROR_FAIL; + } + if (bank->target->state != TARGET_HALTED) { LOG_ERROR("Target not halted"); return ERROR_TARGET_NOT_HALTED; @@ -1001,6 +1370,44 @@ static int stm32l4_probe(struct flash_bank *bank) LOG_INFO("device idcode = 0x%08" PRIx32 " (%s)", stm32l4_info->idcode, device_info); + /* read flash option register */ + retval = stm32l4_read_flash_reg_by_index(bank, STM32_FLASH_OPTR_INDEX, &options); + if (retval != ERROR_OK) + return retval; + + stm32l4_sync_rdp_tzen(bank, options); + + if (part_info->flags & F_HAS_TZ) + LOG_INFO("TZEN = %d : TrustZone %s by option bytes", + stm32l4_info->tzen, + stm32l4_info->tzen ? "enabled" : "disabled"); + + LOG_INFO("RDP level %s (0x%02X)", + stm32l4_info->rdp == RDP_LEVEL_0 ? "0" : stm32l4_info->rdp == RDP_LEVEL_0_5 ? "0.5" : "1", + stm32l4_info->rdp); + + if (stm32l4_is_otp(bank)) { + bank->size = part_info->otp_size; + + LOG_INFO("OTP size is %d bytes, base address is " TARGET_ADDR_FMT, bank->size, bank->base); + + /* OTP memory is considered as one sector */ + free(bank->sectors); + bank->num_sectors = 1; + bank->sectors = alloc_block_array(0, part_info->otp_size, 1); + + if (!bank->sectors) { + LOG_ERROR("failed to allocate bank sectors"); + return ERROR_FAIL; + } + + stm32l4_info->probed = true; + return ERROR_OK; + } else if (bank->base != STM32_FLASH_BANK_BASE) { + LOG_ERROR("invalid bank base address"); + return ERROR_FAIL; + } + /* get flash size from target. */ retval = target_read_u16(target, part_info->fsize_addr, &flash_size_kb); @@ -1025,11 +1432,6 @@ static int stm32l4_probe(struct flash_bank *bank) /* did we assign a flash size? */ assert((flash_size_kb != 0xffff) && flash_size_kb); - /* read flash option register */ - retval = stm32l4_read_flash_reg_by_index(bank, STM32_FLASH_OPTR_INDEX, &options); - if (retval != ERROR_OK) - return retval; - stm32l4_info->bank1_sectors = 0; stm32l4_info->hole_sectors = 0; @@ -1175,7 +1577,6 @@ static int stm32l4_probe(struct flash_bank *bank) free(bank->sectors); bank->size = (flash_size_kb + gap_size_kb) * 1024; - bank->base = STM32_FLASH_BANK_BASE; bank->num_sectors = num_pages; bank->sectors = malloc(sizeof(struct flash_sector) * bank->num_sectors); if (bank->sectors == NULL) { @@ -1227,6 +1628,7 @@ static int get_stm32l4_info(struct flash_bank *bank, char *buf, int buf_size) if (stm32l4_info->probed) snprintf(buf + buf_len, buf_size - buf_len, " - %s-bank", + stm32l4_is_otp(bank) ? "OTP" : stm32l4_info->dual_bank_mode ? "Flash dual" : "Flash single"); return ERROR_OK; @@ -1244,9 +1646,14 @@ static int stm32l4_mass_erase(struct flash_bank *bank) struct target *target = bank->target; struct stm32l4_flash_bank *stm32l4_info = bank->driver_priv; + if (stm32l4_is_otp(bank)) { + LOG_ERROR("cannot erase OTP memory"); + return ERROR_FLASH_OPER_UNSUPPORTED; + } + uint32_t action = FLASH_MER1; - if (stm32l4_info->part_info->has_dual_bank) + if (stm32l4_info->part_info->flags & F_HAS_DUAL_BANK) action |= FLASH_MER2; if (target->state != TARGET_HALTED) { @@ -1410,6 +1817,11 @@ COMMAND_HANDLER(stm32l4_handle_lock_command) if (ERROR_OK != retval) return retval; + if (stm32l4_is_otp(bank)) { + LOG_ERROR("cannot lock/unlock OTP memory"); + return ERROR_FLASH_OPER_UNSUPPORTED; + } + target = bank->target; if (target->state != TARGET_HALTED) { @@ -1419,7 +1831,8 @@ COMMAND_HANDLER(stm32l4_handle_lock_command) /* set readout protection level 1 by erasing the RDP option byte */ struct stm32l4_flash_bank *stm32l4_info = bank->driver_priv; - if (stm32l4_write_option(bank, stm32l4_info->flash_regs[STM32_FLASH_OPTR_INDEX], 0, 0x000000FF) != ERROR_OK) { + if (stm32l4_write_option(bank, stm32l4_info->flash_regs[STM32_FLASH_OPTR_INDEX], + RDP_LEVEL_1, FLASH_RDP_MASK) != ERROR_OK) { command_print(CMD, "%s failed to lock device", bank->driver->name); return ERROR_OK; } @@ -1439,6 +1852,11 @@ COMMAND_HANDLER(stm32l4_handle_unlock_command) if (ERROR_OK != retval) return retval; + if (stm32l4_is_otp(bank)) { + LOG_ERROR("cannot lock/unlock OTP memory"); + return ERROR_FLASH_OPER_UNSUPPORTED; + } + target = bank->target; if (target->state != TARGET_HALTED) { @@ -1448,7 +1866,7 @@ COMMAND_HANDLER(stm32l4_handle_unlock_command) struct stm32l4_flash_bank *stm32l4_info = bank->driver_priv; if (stm32l4_write_option(bank, stm32l4_info->flash_regs[STM32_FLASH_OPTR_INDEX], - RDP_LEVEL_0, 0x000000FF) != ERROR_OK) { + RDP_LEVEL_0, FLASH_RDP_MASK) != ERROR_OK) { command_print(CMD, "%s failed to unlock device", bank->driver->name); return ERROR_OK; } @@ -1456,6 +1874,105 @@ COMMAND_HANDLER(stm32l4_handle_unlock_command) return ERROR_OK; } +COMMAND_HANDLER(stm32l4_handle_wrp_info_command) +{ + if (CMD_ARGC < 1 || CMD_ARGC > 2) + return ERROR_COMMAND_SYNTAX_ERROR; + + struct flash_bank *bank; + int retval = CALL_COMMAND_HANDLER(flash_command_get_bank, 0, &bank); + if (ERROR_OK != retval) + return retval; + + if (stm32l4_is_otp(bank)) { + LOG_ERROR("OTP memory does not have write protection areas"); + return ERROR_FLASH_OPER_UNSUPPORTED; + } + + struct stm32l4_flash_bank *stm32l4_info = bank->driver_priv; + enum stm32_bank_id dev_bank_id = STM32_ALL_BANKS; + if (CMD_ARGC == 2) { + if (strcmp(CMD_ARGV[1], "bank1") == 0) + dev_bank_id = STM32_BANK1; + else if (strcmp(CMD_ARGV[1], "bank2") == 0) + dev_bank_id = STM32_BANK2; + else + return ERROR_COMMAND_ARGUMENT_INVALID; + } + + if (dev_bank_id == STM32_BANK2) { + if (!(stm32l4_info->part_info->flags & F_HAS_DUAL_BANK)) { + LOG_ERROR("this device has no second bank"); + return ERROR_FAIL; + } else if (!stm32l4_info->dual_bank_mode) { + LOG_ERROR("this device is configured in single bank mode"); + return ERROR_FAIL; + } + } + + int ret; + unsigned int n_wrp, i; + struct stm32l4_wrp wrpxy[4]; + + ret = stm32l4_get_all_wrpxy(bank, dev_bank_id, wrpxy, &n_wrp); + if (ret != ERROR_OK) + return ret; + + /* use bitmap and range helpers to better describe protected areas */ + DECLARE_BITMAP(pages, bank->num_sectors); + bitmap_zero(pages, bank->num_sectors); + + for (i = 0; i < n_wrp; i++) { + if (wrpxy[i].used) { + for (int p = wrpxy[i].first; p <= wrpxy[i].last; p++) + set_bit(p, pages); + } + } + + /* we have at most 'n_wrp' WRP areas */ + struct range ranges[n_wrp]; + unsigned int ranges_count = 0; + + bitmap_to_ranges(pages, bank->num_sectors, ranges, &ranges_count); + + if (ranges_count > 0) { + /* pretty-print the protected ranges */ + char *ranges_str = range_print_alloc(ranges, ranges_count); + command_print(CMD, "protected areas: %s", ranges_str); + free(ranges_str); + } else + command_print(CMD, "no protected areas"); + + return ERROR_OK; +} + +COMMAND_HANDLER(stm32l4_handle_otp_command) +{ + if (CMD_ARGC < 2) + return ERROR_COMMAND_SYNTAX_ERROR; + + struct flash_bank *bank; + int retval = CALL_COMMAND_HANDLER(flash_command_get_bank, 0, &bank); + if (ERROR_OK != retval) + return retval; + + if (!stm32l4_is_otp(bank)) { + command_print(CMD, "the specified bank is not an OTP memory"); + return ERROR_FAIL; + } + if (strcmp(CMD_ARGV[1], "enable") == 0) + stm32l4_otp_enable(bank, true); + else if (strcmp(CMD_ARGV[1], "disable") == 0) + stm32l4_otp_enable(bank, false); + else if (strcmp(CMD_ARGV[1], "show") == 0) + command_print(CMD, "OTP memory bank #%d is %s for write commands.", + bank->bank_number, stm32l4_otp_is_enabled(bank) ? "enabled" : "disabled"); + else + return ERROR_COMMAND_SYNTAX_ERROR; + + return ERROR_OK; +} + static const struct command_registration stm32l4_exec_command_handlers[] = { { .name = "lock", @@ -1492,6 +2009,13 @@ static const struct command_registration stm32l4_exec_command_handlers[] = { .usage = "bank_id reg_offset value mask", .help = "Write device option bit fields with provided value.", }, + { + .name = "wrp_info", + .handler = stm32l4_handle_wrp_info_command, + .mode = COMMAND_EXEC, + .usage = "bank_id [bank1|bank2]", + .help = "list the protected areas using WRP", + }, { .name = "option_load", .handler = stm32l4_handle_option_load_command, @@ -1499,6 +2023,13 @@ static const struct command_registration stm32l4_exec_command_handlers[] = { .usage = "bank_id", .help = "Force re-load of device options (will cause device reset).", }, + { + .name = "otp", + .handler = stm32l4_handle_otp_command, + .mode = COMMAND_EXEC, + .usage = " ", + .help = "OTP (One Time Programmable) memory write enable/disable", + }, COMMAND_REGISTRATION_DONE }; diff --git a/src/flash/nor/stm32l4x.h b/src/flash/nor/stm32l4x.h index 3e810a03c..41b5ff82d 100644 --- a/src/flash/nor/stm32l4x.h +++ b/src/flash/nor/stm32l4x.h @@ -56,9 +56,9 @@ #define OPTKEY1 0x08192A3B #define OPTKEY2 0x4C5D6E7F -#define RDP_LEVEL_0 0xAA -#define RDP_LEVEL_1 0xBB -#define RDP_LEVEL_2 0xCC +/* FLASH_OPTR register bits */ +#define FLASH_RDP_MASK 0xFF +#define FLASH_TZEN (1 << 31) /* other registers */ #define DBGMCU_IDCODE_G0 0x40015800 diff --git a/src/flash/nor/stmqspi.c b/src/flash/nor/stmqspi.c index a013336a0..11aa43898 100644 --- a/src/flash/nor/stmqspi.c +++ b/src/flash/nor/stmqspi.c @@ -52,14 +52,6 @@ #undef SPIFLASH_READ #undef SPIFLASH_PAGE_PROGRAM -#define READ_REG(a) \ -({ \ - uint32_t _result; \ - \ - retval = target_read_u32(target, io_base + (a), &_result); \ - (retval == ERROR_OK) ? _result : 0x0; \ -}) - /* saved mode settings */ #define QSPI_MODE (stmqspi_info->saved_ccr & \ (0xF0000000U | QSPI_DCYC_MASK | QSPI_4LINE_MODE | QSPI_ALTB_MODE | QSPI_ADDR4)) @@ -156,23 +148,6 @@ #define OPI_CMD(cmd) ((OPI_MODE ? ((((uint16_t)(cmd)) << 8) | (~(cmd) & 0xFFU)) : (cmd))) -#define OCTOSPI_CMD(mode, ccr, ir) \ -({ \ - retval = target_write_u32(target, io_base + OCTOSPI_CR, \ - OCTOSPI_MODE | (mode)); \ - if (retval == ERROR_OK) \ - retval = target_write_u32(target, io_base + OCTOSPI_TCR, \ - (stmqspi_info->saved_tcr & ~OCTOSPI_DCYC_MASK) | \ - ((OPI_MODE && ((mode) == OCTOSPI_READ_MODE)) ? \ - (OPI_DUMMY << OCTOSPI_DCYC_POS) : 0)); \ - if (retval == ERROR_OK) \ - retval = target_write_u32(target, io_base + OCTOSPI_CCR, ccr); \ - if (retval == ERROR_OK) \ - retval = target_write_u32(target, io_base + OCTOSPI_IR, \ - OPI_CMD(ir)); \ - retval; \ -}) - /* convert uint32_t into 4 uint8_t in little endian byte order */ static inline uint32_t h_to_le_32(uint32_t val) { @@ -208,6 +183,35 @@ struct stmqspi_flash_bank { unsigned int sfdp_dummy2; /* number of dummy bytes for SFDP read for flash2 */ }; +static inline int octospi_cmd(struct flash_bank *bank, uint32_t mode, + uint32_t ccr, uint32_t ir) +{ + struct target *target = bank->target; + const struct stmqspi_flash_bank *stmqspi_info = bank->driver_priv; + const uint32_t io_base = stmqspi_info->io_base; + + int retval = target_write_u32(target, io_base + OCTOSPI_CR, + OCTOSPI_MODE | mode); + + if (retval != ERROR_OK) + return retval; + + retval = target_write_u32(target, io_base + OCTOSPI_TCR, + (stmqspi_info->saved_tcr & ~OCTOSPI_DCYC_MASK) | + ((OPI_MODE && (mode == OCTOSPI_READ_MODE)) ? + (OPI_DUMMY << OCTOSPI_DCYC_POS) : 0)); + + if (retval != ERROR_OK) + return retval; + + retval = target_write_u32(target, io_base + OCTOSPI_CCR, ccr); + + if (retval != ERROR_OK) + return retval; + + return target_write_u32(target, io_base + OCTOSPI_IR, OPI_CMD(ir)); +} + FLASH_BANK_COMMAND_HANDLER(stmqspi_flash_bank_command) { struct stmqspi_flash_bank *stmqspi_info; @@ -242,19 +246,19 @@ static int poll_busy(struct flash_bank *bank, int timeout) struct target *target = bank->target; struct stmqspi_flash_bank *stmqspi_info = bank->driver_priv; uint32_t io_base = stmqspi_info->io_base; - uint32_t spi_sr; - int retval; long long endtime; endtime = timeval_ms() + timeout; do { - spi_sr = READ_REG(SPI_SR); - if ((spi_sr & BIT(SPI_BUSY)) == 0) { - if (retval == ERROR_OK) { - /* Clear transmit finished flag */ - retval = target_write_u32(target, io_base + SPI_FCR, BIT(SPI_TCF)); - } + uint32_t spi_sr; + int retval = target_read_u32(target, io_base + SPI_SR, &spi_sr); + + if (retval != ERROR_OK) return retval; + + if ((spi_sr & BIT(SPI_BUSY)) == 0) { + /* Clear transmit finished flag */ + return target_write_u32(target, io_base + SPI_FCR, BIT(SPI_TCF)); } else LOG_DEBUG("busy: 0x%08X", spi_sr); alive_sleep(1); @@ -264,6 +268,21 @@ static int poll_busy(struct flash_bank *bank, int timeout) return ERROR_FLASH_OPERATION_FAILED; } +static int stmqspi_abort(struct flash_bank *bank) +{ + struct target *target = bank->target; + const struct stmqspi_flash_bank *stmqspi_info = bank->driver_priv; + const uint32_t io_base = stmqspi_info->io_base; + uint32_t cr; + + int retval = target_read_u32(target, io_base + SPI_CR, &cr); + + if (retval != ERROR_OK) + cr = 0; + + return target_write_u32(target, io_base + SPI_CR, cr | BIT(SPI_ABORT)); +} + /* Set to memory-mapped mode, e.g. after an error */ static int set_mm_mode(struct flash_bank *bank) { @@ -278,8 +297,7 @@ static int set_mm_mode(struct flash_bank *bank) return retval; /* Abort any previous operation */ - retval = target_write_u32(target, io_base + SPI_CR, - READ_REG(SPI_CR) | BIT(SPI_ABORT)); + retval = stmqspi_abort(bank); if (retval != ERROR_OK) return retval; @@ -321,8 +339,7 @@ static int read_status_reg(struct flash_bank *bank, uint16_t *status) int count, retval; /* Abort any previous operation */ - retval = target_write_u32(target, io_base + SPI_CR, - READ_REG(SPI_CR) | BIT(SPI_ABORT)); + retval = stmqspi_abort(bank); if (retval != ERROR_OK) return retval; @@ -340,7 +357,8 @@ static int read_status_reg(struct flash_bank *bank, uint16_t *status) /* Read status */ if (IS_OCTOSPI) { - retval = OCTOSPI_CMD(OCTOSPI_READ_MODE, OCTOSPI_CCR_READ_STATUS, SPIFLASH_READ_STATUS); + retval = octospi_cmd(bank, OCTOSPI_READ_MODE, OCTOSPI_CCR_READ_STATUS, + SPIFLASH_READ_STATUS); if (OPI_MODE) { /* Dummy address 0, only required for 8-line mode */ retval = target_write_u32(target, io_base + SPI_AR, 0); @@ -355,7 +373,8 @@ static int read_status_reg(struct flash_bank *bank, uint16_t *status) *status = 0; /* for debugging only */ - (void)READ_REG(SPI_SR); + uint32_t dummy; + (void)target_read_u32(target, io_base + SPI_SR, &dummy); for ( ; count > 0; --count) { if ((stmqspi_info->saved_cr & (BIT(SPI_DUAL_FLASH) | BIT(SPI_FSEL_FLASH))) @@ -416,8 +435,7 @@ static int qspi_write_enable(struct flash_bank *bank) int retval; /* Abort any previous operation */ - retval = target_write_u32(target, io_base + SPI_CR, - READ_REG(SPI_CR) | BIT(SPI_ABORT)); + retval = stmqspi_abort(bank); if (retval != ERROR_OK) return retval; @@ -428,7 +446,8 @@ static int qspi_write_enable(struct flash_bank *bank) /* Send write enable command */ if (IS_OCTOSPI) { - retval = OCTOSPI_CMD(OCTOSPI_WRITE_MODE, OCTOSPI_CCR_WRITE_ENABLE, SPIFLASH_WRITE_ENABLE); + retval = octospi_cmd(bank, OCTOSPI_WRITE_MODE, OCTOSPI_CCR_WRITE_ENABLE, + SPIFLASH_WRITE_ENABLE); if (OPI_MODE) { /* Dummy address 0, only required for 8-line mode */ retval = target_write_u32(target, io_base + SPI_AR, 0); @@ -527,7 +546,7 @@ COMMAND_HANDLER(stmqspi_handle_mass_erase_command) /* Send Mass Erase command */ if (IS_OCTOSPI) - retval = OCTOSPI_CMD(OCTOSPI_WRITE_MODE, OCTOSPI_CCR_MASS_ERASE, + retval = octospi_cmd(bank, OCTOSPI_WRITE_MODE, OCTOSPI_CCR_MASS_ERASE, stmqspi_info->dev.chip_erase_cmd); else retval = target_write_u32(target, io_base + QSPI_CCR, QSPI_CCR_MASS_ERASE); @@ -714,10 +733,15 @@ COMMAND_HANDLER(stmqspi_handle_set) bank->size = stmqspi_info->dev.size_in_bytes << dual; io_base = stmqspi_info->io_base; - fsize = (READ_REG(SPI_DCR) >> SPI_FSIZE_POS) & (BIT(SPI_FSIZE_LEN) - 1); + + uint32_t dcr; + retval = target_read_u32(target, io_base + SPI_DCR, &dcr); + if (retval != ERROR_OK) return retval; + fsize = (dcr >> SPI_FSIZE_POS) & (BIT(SPI_FSIZE_LEN) - 1); + LOG_DEBUG("FSIZE = 0x%04x", fsize); if (bank->size == BIT(fsize + 1)) LOG_DEBUG("FSIZE in DCR(1) matches actual capacity. Beware of silicon bug in H7, L4+, MP1."); @@ -823,8 +847,7 @@ COMMAND_HANDLER(stmqspi_handle_cmd) } /* Abort any previous operation */ - retval = target_write_u32(target, io_base + SPI_CR, - READ_REG(SPI_CR) | BIT(SPI_ABORT)); + retval = stmqspi_abort(bank); if (retval != ERROR_OK) return retval; @@ -842,7 +865,7 @@ COMMAND_HANDLER(stmqspi_handle_cmd) goto err; if (IS_OCTOSPI) - retval = OCTOSPI_CMD(OCTOSPI_WRITE_MODE, + retval = octospi_cmd(bank, OCTOSPI_WRITE_MODE, (OCTOSPI_MODE_CCR & OCTOSPI_NO_ALTB & OCTOSPI_NO_ADDR & ((num_write == 1) ? OCTOSPI_NO_DATA : ~0U)), cmd_byte); else @@ -879,7 +902,7 @@ COMMAND_HANDLER(stmqspi_handle_cmd) if (retval != ERROR_OK) goto err; if (IS_OCTOSPI) - retval = OCTOSPI_CMD(OCTOSPI_READ_MODE, + retval = octospi_cmd(bank, OCTOSPI_READ_MODE, (OCTOSPI_MODE_CCR & OCTOSPI_NO_DDTR & OCTOSPI_NO_ALTB & ~OCTOSPI_ADDR4 & ((num_write == 1) ? OCTOSPI_NO_ADDR : ~0U)) | (((num_write - 2) & 0x3U) << SPI_ADSIZE_POS), cmd_byte); @@ -930,7 +953,7 @@ static int qspi_erase_sector(struct flash_bank *bank, unsigned int sector) /* Send Sector Erase command */ if (IS_OCTOSPI) - retval = OCTOSPI_CMD(OCTOSPI_WRITE_MODE, OCTOSPI_CCR_SECTOR_ERASE, + retval = octospi_cmd(bank, OCTOSPI_WRITE_MODE, OCTOSPI_CCR_SECTOR_ERASE, stmqspi_info->dev.erase_cmd); else retval = target_write_u32(target, io_base + QSPI_CCR, QSPI_CCR_SECTOR_ERASE); @@ -1059,7 +1082,6 @@ static int stmqspi_blank_check(struct flash_bank *bank) { struct target *target = bank->target; struct stmqspi_flash_bank *stmqspi_info = bank->driver_priv; - uint32_t io_base = stmqspi_info->io_base; struct duration bench; struct reg_param reg_params[2]; struct armv7m_algorithm armv7m_info; @@ -1082,8 +1104,7 @@ static int stmqspi_blank_check(struct flash_bank *bank) } /* Abort any previous operation */ - retval = target_write_u32(target, io_base + SPI_CR, - READ_REG(SPI_CR) | BIT(SPI_ABORT)); + retval = stmqspi_abort(bank); if (retval != ERROR_OK) return retval; @@ -1568,7 +1589,6 @@ static int stmqspi_read(struct flash_bank *bank, uint8_t *buffer, { struct target *target = bank->target; struct stmqspi_flash_bank *stmqspi_info = bank->driver_priv; - uint32_t io_base = stmqspi_info->io_base; int retval; LOG_DEBUG("%s: offset=0x%08" PRIx32 " count=0x%08" PRIx32, @@ -1590,8 +1610,7 @@ static int stmqspi_read(struct flash_bank *bank, uint8_t *buffer, } /* Abort any previous operation */ - retval = target_write_u32(target, io_base + SPI_CR, - READ_REG(SPI_CR) | BIT(SPI_ABORT)); + retval = stmqspi_abort(bank); if (retval != ERROR_OK) return retval; @@ -1608,7 +1627,6 @@ static int stmqspi_write(struct flash_bank *bank, const uint8_t *buffer, { struct target *target = bank->target; struct stmqspi_flash_bank *stmqspi_info = bank->driver_priv; - uint32_t io_base = stmqspi_info->io_base; unsigned int dual, sector; bool octal_dtr; int retval; @@ -1653,8 +1671,7 @@ static int stmqspi_write(struct flash_bank *bank, const uint8_t *buffer, } /* Abort any previous operation */ - retval = target_write_u32(target, io_base + SPI_CR, - READ_REG(SPI_CR) | BIT(SPI_ABORT)); + retval = stmqspi_abort(bank); if (retval != ERROR_OK) return retval; @@ -1671,7 +1688,6 @@ static int stmqspi_verify(struct flash_bank *bank, const uint8_t *buffer, { struct target *target = bank->target; struct stmqspi_flash_bank *stmqspi_info = bank->driver_priv; - uint32_t io_base = stmqspi_info->io_base; unsigned int dual; bool octal_dtr; int retval; @@ -1704,8 +1720,7 @@ static int stmqspi_verify(struct flash_bank *bank, const uint8_t *buffer, } /* Abort any previous operation */ - retval = target_write_u32(target, io_base + SPI_CR, - READ_REG(SPI_CR) | BIT(SPI_ABORT)); + retval = stmqspi_abort(bank); if (retval != ERROR_OK) return retval; @@ -1757,8 +1772,8 @@ static int find_sfdp_dummy(struct flash_bank *bank, int len) /* Read SFDP block */ if (IS_OCTOSPI) - retval = OCTOSPI_CMD(OCTOSPI_READ_MODE, OCTOSPI_CCR_READ_SFDP(len), - SPIFLASH_READ_SFDP); + retval = octospi_cmd(bank, OCTOSPI_READ_MODE, + OCTOSPI_CCR_READ_SFDP(len), SPIFLASH_READ_SFDP); else retval = target_write_u32(target, io_base + QSPI_CCR, QSPI_CCR_READ_SFDP); if (retval != ERROR_OK) @@ -1804,8 +1819,7 @@ static int find_sfdp_dummy(struct flash_bank *bank, int len) err: /* Abort operation */ - retval = target_write_u32(target, io_base + SPI_CR, - READ_REG(SPI_CR) | BIT(SPI_ABORT)); + retval = stmqspi_abort(bank); return retval; } @@ -1880,8 +1894,8 @@ static int read_sfdp_block(struct flash_bank *bank, uint32_t addr, /* Read SFDP block */ if (IS_OCTOSPI) - retval = OCTOSPI_CMD(OCTOSPI_READ_MODE, OCTOSPI_CCR_READ_SFDP(len), - SPIFLASH_READ_SFDP); + retval = octospi_cmd(bank, OCTOSPI_READ_MODE, + OCTOSPI_CCR_READ_SFDP(len), SPIFLASH_READ_SFDP); else retval = target_write_u32(target, io_base + QSPI_CCR, QSPI_CCR_READ_SFDP); if (retval != ERROR_OK) @@ -1959,8 +1973,7 @@ static int read_flash_id(struct flash_bank *bank, uint32_t *id1, uint32_t *id2) /* SPIFLASH_READ_MID causes device in octal mode to go berserk, so don't use in this case */ for (type = (IS_OCTOSPI && OPI_MODE) ? 1 : 0; type < 2 ; type++) { /* Abort any previous operation */ - retval = target_write_u32(target, io_base + SPI_CR, - READ_REG(SPI_CR) | BIT(SPI_ABORT)); + retval = stmqspi_abort(bank); if (retval != ERROR_OK) goto err; @@ -1986,14 +1999,16 @@ static int read_flash_id(struct flash_bank *bank, uint32_t *id1, uint32_t *id2) switch (type) { case 0: if (IS_OCTOSPI) - retval = OCTOSPI_CMD(OCTOSPI_READ_MODE, OCTOSPI_CCR_READ_MID, SPIFLASH_READ_MID); + retval = octospi_cmd(bank, OCTOSPI_READ_MODE, + OCTOSPI_CCR_READ_MID, SPIFLASH_READ_MID); else retval = target_write_u32(target, io_base + QSPI_CCR, QSPI_CCR_READ_MID); break; case 1: if (IS_OCTOSPI) - retval = OCTOSPI_CMD(OCTOSPI_READ_MODE, OCTOSPI_CCR_READ_ID, SPIFLASH_READ_ID); + retval = octospi_cmd(bank, OCTOSPI_READ_MODE, + OCTOSPI_CCR_READ_ID, SPIFLASH_READ_ID); else retval = target_write_u32(target, io_base + QSPI_CCR, QSPI_CCR_READ_ID); break; @@ -2013,7 +2028,8 @@ static int read_flash_id(struct flash_bank *bank, uint32_t *id1, uint32_t *id2) } /* for debugging only */ - (void)READ_REG(SPI_SR); + uint32_t dummy; + (void)target_read_u32(target, io_base + SPI_SR, &dummy); /* Read ID from Data Register */ for (len1 = 0, len2 = 0; count > 0; --count) { @@ -2092,8 +2108,7 @@ static int stmqspi_probe(struct flash_bank *bank) } /* Abort any previous operation */ - retval = target_write_u32(target, io_base + SPI_CR, - READ_REG(SPI_CR) | BIT(SPI_ABORT)); + retval = stmqspi_abort(bank); if (retval != ERROR_OK) return retval; @@ -2112,43 +2127,59 @@ static int stmqspi_probe(struct flash_bank *bank) if (data == magic) { LOG_DEBUG("QSPI_ABR register present"); stmqspi_info->octo = false; - } else if (READ_REG(OCTOSPI_MAGIC) == OCTO_MAGIC_ID) { - LOG_DEBUG("OCTOSPI_MAGIC present"); - stmqspi_info->octo = true; } else { - LOG_ERROR("No QSPI, no OCTOSPI at 0x%08" PRIx32, io_base); - stmqspi_info->probed = false; - stmqspi_info->dev.name = "none"; - return ERROR_FAIL; + uint32_t magic_id; + + retval = target_read_u32(target, io_base + OCTOSPI_MAGIC, &magic_id); + + if (retval == ERROR_OK && magic_id == OCTO_MAGIC_ID) { + LOG_DEBUG("OCTOSPI_MAGIC present"); + stmqspi_info->octo = true; + } else { + LOG_ERROR("No QSPI, no OCTOSPI at 0x%08" PRIx32, io_base); + stmqspi_info->probed = false; + stmqspi_info->dev.name = "none"; + return ERROR_FAIL; + } } /* save current FSEL and DFM bits in QSPI/OCTOSPI_CR, current QSPI/OCTOSPI_CCR value */ - stmqspi_info->saved_cr = READ_REG(SPI_CR); + retval = target_read_u32(target, io_base + SPI_CR, &stmqspi_info->saved_cr); if (retval == ERROR_OK) - stmqspi_info->saved_ccr = READ_REG(SPI_CCR); + retval = target_read_u32(target, io_base + SPI_CCR, &stmqspi_info->saved_ccr); if (IS_OCTOSPI) { - uint32_t mtyp; + uint32_t dcr1; + + retval = target_read_u32(target, io_base + OCTOSPI_DCR1, &dcr1); - mtyp = ((READ_REG(OCTOSPI_DCR1) & OCTOSPI_MTYP_MASK)) >> OCTOSPI_MTYP_POS; if (retval == ERROR_OK) - stmqspi_info->saved_tcr = READ_REG(OCTOSPI_TCR); + retval = target_read_u32(target, io_base + OCTOSPI_TCR, + &stmqspi_info->saved_tcr); + if (retval == ERROR_OK) - stmqspi_info->saved_ir = READ_REG(OCTOSPI_IR); - if ((mtyp != 0x0) && (mtyp != 0x1)) { - retval = ERROR_FAIL; - LOG_ERROR("Only regular SPI protocol supported in OCTOSPI"); - } - if (retval == ERROR_OK) { - LOG_DEBUG("OCTOSPI at 0x%08" PRIx64 ", io_base at 0x%08" PRIx32 ", OCTOSPI_CR 0x%08" - PRIx32 ", OCTOSPI_CCR 0x%08" PRIx32 ", %d-byte addr", bank->base, io_base, - stmqspi_info->saved_cr, stmqspi_info->saved_ccr, SPI_ADSIZE); - } else { + retval = target_read_u32(target, io_base + OCTOSPI_IR, + &stmqspi_info->saved_ir); + + if (retval != ERROR_OK) { LOG_ERROR("No OCTOSPI at io_base 0x%08" PRIx32, io_base); stmqspi_info->probed = false; stmqspi_info->dev.name = "none"; return ERROR_FAIL; } + + const uint32_t mtyp = (dcr1 & OCTOSPI_MTYP_MASK) >> OCTOSPI_MTYP_POS; + + if ((mtyp != 0x0) && (mtyp != 0x1)) { + LOG_ERROR("Only regular SPI protocol supported in OCTOSPI"); + stmqspi_info->probed = false; + stmqspi_info->dev.name = "none"; + return ERROR_FAIL; + } + + LOG_DEBUG("OCTOSPI at 0x%08" PRIx64 ", io_base at 0x%08" PRIx32 ", OCTOSPI_CR 0x%08" + PRIx32 ", OCTOSPI_CCR 0x%08" PRIx32 ", %d-byte addr", bank->base, io_base, + stmqspi_info->saved_cr, stmqspi_info->saved_ccr, SPI_ADSIZE); } else { if (retval == ERROR_OK) { LOG_DEBUG("QSPI at 0x%08" PRIx64 ", io_base at 0x%08" PRIx32 ", QSPI_CR 0x%08" @@ -2301,10 +2332,14 @@ static int stmqspi_probe(struct flash_bank *bank) /* Set correct size value */ bank->size = stmqspi_info->dev.size_in_bytes << dual; - fsize = ((READ_REG(SPI_DCR) >> SPI_FSIZE_POS) & (BIT(SPI_FSIZE_LEN) - 1)); + uint32_t dcr; + retval = target_read_u32(target, io_base + SPI_DCR, &dcr); + if (retval != ERROR_OK) goto err; + fsize = (dcr >> SPI_FSIZE_POS) & (BIT(SPI_FSIZE_LEN) - 1); + LOG_DEBUG("FSIZE = 0x%04x", fsize); if (bank->size == BIT((fsize + 1))) LOG_DEBUG("FSIZE in DCR(1) matches actual capacity. Beware of silicon bug in H7, L4+, MP1."); diff --git a/src/flash/startup.tcl b/src/flash/startup.tcl index 280a059a3..7d9dbc7da 100644 --- a/src/flash/startup.tcl +++ b/src/flash/startup.tcl @@ -119,14 +119,3 @@ proc stm32g4x args { eval stm32l4x $args } proc stm32l5x args { eval stm32l4x $args } proc stm32wbx args { eval stm32l4x $args } proc stm32wlx args { eval stm32l4x $args } - -# ease migration to updated flash driver -proc stm32x args { - echo "DEPRECATED! use 'stm32f1x $args' not 'stm32x $args'" - eval stm32f1x $args -} - -proc stm32f2xxx args { - echo "DEPRECATED! use 'stm32f2x $args' not 'stm32f2xxx $args'" - eval stm32f2x $args -} diff --git a/src/helper/Makefile.am b/src/helper/Makefile.am index ad6ec118f..f54d9de5e 100644 --- a/src/helper/Makefile.am +++ b/src/helper/Makefile.am @@ -18,7 +18,6 @@ noinst_LTLIBRARIES += %D%/libhelper.la %D%/binarybuffer.h \ %D%/bits.h \ %D%/configuration.h \ - %D%/ioutil.h \ %D%/list.h \ %D%/util.h \ %D%/types.h \ @@ -34,12 +33,6 @@ noinst_LTLIBRARIES += %D%/libhelper.la %D%/base64.c \ %D%/base64.h -if IOUTIL -%C%_libhelper_la_SOURCES += %D%/ioutil.c -else -%C%_libhelper_la_SOURCES += %D%/ioutil_stubs.c -endif - %C%_libhelper_la_CFLAGS = $(AM_CFLAGS) if IS_MINGW # FD_* macros are sloppy with their signs on MinGW32 platform diff --git a/src/helper/command.c b/src/helper/command.c index 96b124496..fdf1bbeed 100644 --- a/src/helper/command.c +++ b/src/helper/command.c @@ -117,6 +117,40 @@ static void command_log_capture_finish(struct log_capture_state *state) free(state); } +/* + * FIXME: workaround for memory leak in jimtcl 0.80 + * Jim API Jim_CreateCommand() converts the command name in a Jim object and + * does not free the object. Fixed for jimtcl 0.81 by e4416cf86f0b + * Use the internal jimtcl API Jim_CreateCommandObj, not exported by jim.h, + * and override the bugged API through preprocessor's macro. + * This workaround works only when jimtcl is compiled as OpenOCD submodule. + * If jimtcl is linked-in from a precompiled library, either static or dynamic, + * the symbol Jim_CreateCommandObj is not exported and the build will use the + * bugged API. + * To be removed when OpenOCD will switch to jimtcl 0.81 + */ +#if JIM_VERSION == 80 +static int workaround_createcommand(Jim_Interp *interp, const char *cmdName, + Jim_CmdProc *cmdProc, void *privData, Jim_DelCmdProc *delProc); +int Jim_CreateCommandObj(Jim_Interp *interp, Jim_Obj *cmdNameObj, + Jim_CmdProc *cmdProc, void *privData, Jim_DelCmdProc *delProc) +__attribute__((weak, alias("workaround_createcommand"))); +static int workaround_createcommand(Jim_Interp *interp, const char *cmdName, + Jim_CmdProc *cmdProc, void *privData, Jim_DelCmdProc *delProc) +{ + if ((void *)Jim_CreateCommandObj == (void *)workaround_createcommand) + return Jim_CreateCommand(interp, cmdName, cmdProc, privData, delProc); + + Jim_Obj *cmd_name = Jim_NewStringObj(interp, cmdName, -1); + Jim_IncrRefCount(cmd_name); + int retval = Jim_CreateCommandObj(interp, cmd_name, cmdProc, privData, delProc); + Jim_DecrRefCount(interp, cmd_name); + return retval; +} +#define Jim_CreateCommand workaround_createcommand +#endif /* JIM_VERSION == 80 */ +/* FIXME: end of workaround for memory leak in jimtcl 0.80 */ + static int command_retval_set(Jim_Interp *interp, int retval) { int *return_retval = Jim_GetAssocData(interp, "retval"); diff --git a/src/helper/ioutil.c b/src/helper/ioutil.c deleted file mode 100644 index ffdeca898..000000000 --- a/src/helper/ioutil.c +++ /dev/null @@ -1,534 +0,0 @@ -/*************************************************************************** - * Copyright (C) 2007-2010 by Øyvind Harboe * - * * - * 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 . * - ***************************************************************************/ - -/* this file contains various functionality useful to standalone systems */ - -#ifdef HAVE_CONFIG_H -#include "config.h" -#endif - -#include "log.h" -#include "time_support.h" - -#ifdef HAVE_ARPA_INET_H -#include -#endif -#ifdef HAVE_DIRENT_H -#include -#endif -#ifdef HAVE_NETDB_H -#include -#endif -#ifdef HAVE_NET_IF_H -#include -#endif -#ifdef HAVE_SYS_IOCTL_H -#include -#endif -#ifdef HAVE_SYS_STAT_H -#include -#endif -#ifdef HAVE_IFADDRS_H -#include -#endif -#ifdef HAVE_MALLOC_H -#include -#endif - -/* loads a file and returns a pointer to it in memory. The file contains - * a 0 byte(sentinel) after len bytes - the length of the file. */ -static int load_file(const char *fileName, char **data, size_t *len) -{ - /* ensure returned length is always sane */ - *len = 0; - - FILE *pFile; - pFile = fopen(fileName, "rb"); - if (pFile == NULL) { - LOG_ERROR("Can't open %s", fileName); - return ERROR_FAIL; - } - if (fseek(pFile, 0, SEEK_END) != 0) { - LOG_ERROR("Can't open %s", fileName); - fclose(pFile); - return ERROR_FAIL; - } - long fsize = ftell(pFile); - if (fsize == -1) { - LOG_ERROR("Can't open %s", fileName); - fclose(pFile); - return ERROR_FAIL; - } - *len = fsize; - - if (fseek(pFile, 0, SEEK_SET) != 0) { - LOG_ERROR("Can't open %s", fileName); - fclose(pFile); - return ERROR_FAIL; - } - *data = malloc(*len + 1); - if (*data == NULL) { - LOG_ERROR("Can't open %s", fileName); - fclose(pFile); - return ERROR_FAIL; - } - - if (fread(*data, 1, *len, pFile) != *len) { - fclose(pFile); - free(*data); - LOG_ERROR("Can't open %s", fileName); - return ERROR_FAIL; - } - fclose(pFile); - - /* 0-byte after buffer (not included in *len) serves as a sentinel */ - (*data)[*len] = 0; - - return ERROR_OK; -} - -COMMAND_HANDLER(handle_cat_command) -{ - if (CMD_ARGC != 1) - return ERROR_COMMAND_SYNTAX_ERROR; - - /* NOTE!!! we only have line printing capability so we print the entire file as a single - * line. */ - char *data; - size_t len; - - int retval = load_file(CMD_ARGV[0], &data, &len); - if (retval == ERROR_OK) { - command_print(CMD, "%s", data); - free(data); - } else - command_print(CMD, "%s not found", CMD_ARGV[0]); - - return ERROR_OK; -} - -COMMAND_HANDLER(handle_trunc_command) -{ - if (CMD_ARGC != 1) - return ERROR_COMMAND_SYNTAX_ERROR; - - FILE *config_file = NULL; - config_file = fopen(CMD_ARGV[0], "w"); - if (config_file != NULL) - fclose(config_file); - - return ERROR_OK; -} - -#ifdef HAVE_MALLOC_H -COMMAND_HANDLER(handle_meminfo_command) -{ - static int prev; - struct mallinfo info; - - if (CMD_ARGC != 0) - return ERROR_COMMAND_SYNTAX_ERROR; - - info = mallinfo(); - - if (prev > 0) - command_print(CMD, "Diff: %d", prev - info.fordblks); - prev = info.fordblks; - - command_print(CMD, "Available ram: %d", info.fordblks); - - return ERROR_OK; -} -#endif - -COMMAND_HANDLER(handle_append_command) -{ - if (CMD_ARGC < 1) - return ERROR_COMMAND_SYNTAX_ERROR; - - int retval = ERROR_FAIL; - FILE *config_file = NULL; - - config_file = fopen(CMD_ARGV[0], "a"); - if (config_file != NULL) { - fseek(config_file, 0, SEEK_END); - - unsigned i; - for (i = 1; i < CMD_ARGC; i++) { - if (fwrite(CMD_ARGV[i], 1, strlen(CMD_ARGV[i]), - config_file) != strlen(CMD_ARGV[i])) - break; - if (i != CMD_ARGC - 1) { - if (fwrite(" ", 1, 1, config_file) != 1) - break; - } - } - if ((i == CMD_ARGC) && (fwrite("\n", 1, 1, config_file) == 1)) - retval = ERROR_OK; - - fclose(config_file); - } - - return retval; -} - -COMMAND_HANDLER(handle_cp_command) -{ - if (CMD_ARGC != 2) - return ERROR_COMMAND_SYNTAX_ERROR; - - /* NOTE!!! we only have line printing capability so we print the entire file as a single - * line. */ - char *data; - size_t len; - - int retval = load_file(CMD_ARGV[0], &data, &len); - if (retval != ERROR_OK) - return retval; - - FILE *f = fopen(CMD_ARGV[1], "wb"); - if (f == NULL) - retval = ERROR_COMMAND_SYNTAX_ERROR; - - size_t pos = 0; - for (;; ) { - size_t chunk = len - pos; - static const size_t maxChunk = 512 * 1024; /* ~1/sec */ - if (chunk > maxChunk) - chunk = maxChunk; - - if ((retval == ERROR_OK) && (fwrite(data + pos, 1, chunk, f) != chunk)) - retval = ERROR_COMMAND_SYNTAX_ERROR; - - if (retval != ERROR_OK) - break; - - command_print(CMD, "%zu", len - pos); - - pos += chunk; - - if (pos == len) - break; - } - - if (retval == ERROR_OK) - command_print(CMD, "Copied %s to %s", CMD_ARGV[0], CMD_ARGV[1]); - else - command_print(CMD, "copy failed"); - - free(data); - if (f != NULL) - fclose(f); - - if (retval != ERROR_OK) - unlink(CMD_ARGV[1]); - - return retval; -} - -COMMAND_HANDLER(handle_rm_command) -{ - if (CMD_ARGC != 1) - return ERROR_COMMAND_SYNTAX_ERROR; - - bool del = false; - if (rmdir(CMD_ARGV[0]) == 0) - del = true; - else if (unlink(CMD_ARGV[0]) == 0) - del = true; - - return del ? ERROR_OK : ERROR_FAIL; -} - -static int ioutil_Jim_Command_ls(Jim_Interp *interp, - int argc, - Jim_Obj * const *argv) -{ - if (argc != 2) { - Jim_WrongNumArgs(interp, 1, argv, "ls ?dir?"); - return JIM_ERR; - } - - const char *name = Jim_GetString(argv[1], NULL); - - DIR *dirp = NULL; - dirp = opendir(name); - if (dirp == NULL) - return JIM_ERR; - Jim_Obj *objPtr = Jim_NewListObj(interp, NULL, 0); - - for (;; ) { - struct dirent *entry = NULL; - entry = readdir(dirp); - if (entry == NULL) - break; - - if ((strcmp(".", entry->d_name) == 0) || (strcmp("..", entry->d_name) == 0)) - continue; - - Jim_ListAppendElement(interp, objPtr, - Jim_NewStringObj(interp, entry->d_name, strlen(entry->d_name))); - } - closedir(dirp); - - Jim_SetResult(interp, objPtr); - - return JIM_OK; -} - -static int ioutil_Jim_Command_peek(Jim_Interp *interp, - int argc, - Jim_Obj *const *argv) -{ - if (argc != 2) { - Jim_WrongNumArgs(interp, 1, argv, "peek ?address?"); - return JIM_ERR; - } - - long address; - if (Jim_GetLong(interp, argv[1], &address) != JIM_OK) - return JIM_ERR; - - int value = *((volatile int *) address); - - Jim_SetResult(interp, Jim_NewIntObj(interp, value)); - - return JIM_OK; -} - -static int ioutil_Jim_Command_poke(Jim_Interp *interp, - int argc, - Jim_Obj *const *argv) -{ - if (argc != 3) { - Jim_WrongNumArgs(interp, 1, argv, "poke ?address? ?value?"); - return JIM_ERR; - } - - long address; - if (Jim_GetLong(interp, argv[1], &address) != JIM_OK) - return JIM_ERR; - long value; - if (Jim_GetLong(interp, argv[2], &value) != JIM_OK) - return JIM_ERR; - - *((volatile int *) address) = value; - - return JIM_OK; -} - -/* not so pretty code to fish out ip number*/ -static int ioutil_Jim_Command_ip(Jim_Interp *interp, int argc, - Jim_Obj *const *argv) -{ -#if !defined(__CYGWIN__) - Jim_Obj *tclOutput = Jim_NewStringObj(interp, "", 0); - - struct ifaddrs *ifa = NULL, *ifp = NULL; - - if (getifaddrs(&ifp) < 0) - return JIM_ERR; - - for (ifa = ifp; ifa; ifa = ifa->ifa_next) { - char ip[200]; - socklen_t salen; - - if (ifa->ifa_addr->sa_family == AF_INET) - salen = sizeof(struct sockaddr_in); - else if (ifa->ifa_addr->sa_family == AF_INET6) - salen = sizeof(struct sockaddr_in6); - else - continue; - - if (getnameinfo(ifa->ifa_addr, salen, ip, sizeof(ip), NULL, 0, - NI_NUMERICHOST) < 0) - continue; - - Jim_AppendString(interp, tclOutput, ip, strlen(ip)); - break; - - } - - freeifaddrs(ifp); -#else - Jim_Obj *tclOutput = Jim_NewStringObj(interp, "fixme!!!", 0); - LOG_ERROR("NOT IMPLEMENTED!!!"); -#endif - Jim_SetResult(interp, tclOutput); - - return JIM_OK; -} - -#ifdef HAVE_SYS_IOCTL_H -#ifdef SIOCGIFHWADDR -/* not so pretty code to fish out eth0 mac address */ -static int ioutil_Jim_Command_mac(Jim_Interp *interp, int argc, - Jim_Obj *const *argv) -{ - struct ifreq *ifr, *ifend; - struct ifreq ifreq; - struct ifconf ifc; - struct ifreq ifs[5]; - int SockFD; - - SockFD = socket(AF_INET, SOCK_DGRAM, 0); - if (SockFD < 0) - return JIM_ERR; - - ifc.ifc_len = sizeof(ifs); - ifc.ifc_req = ifs; - if (ioctl(SockFD, SIOCGIFCONF, &ifc) < 0) { - close(SockFD); - return JIM_ERR; - } - - ifend = ifs + (ifc.ifc_len / sizeof(struct ifreq)); - for (ifr = ifc.ifc_req; ifr < ifend; ifr++) { - /* if (ifr->ifr_addr.sa_family == AF_INET) */ - { - if (strcmp("eth0", ifr->ifr_name) != 0) - continue; - strncpy(ifreq.ifr_name, ifr->ifr_name, sizeof(ifreq.ifr_name) - 1); - if (ioctl(SockFD, SIOCGIFHWADDR, &ifreq) < 0) { - close(SockFD); - return JIM_ERR; - } - - close(SockFD); - - Jim_Obj *tclOutput = Jim_NewStringObj(interp, "", 0); - - char buffer[256]; - sprintf(buffer, "%02x-%02x-%02x-%02x-%02x-%02x", - ifreq.ifr_hwaddr.sa_data[0]&0xff, - ifreq.ifr_hwaddr.sa_data[1]&0xff, - ifreq.ifr_hwaddr.sa_data[2]&0xff, - ifreq.ifr_hwaddr.sa_data[3]&0xff, - ifreq.ifr_hwaddr.sa_data[4]&0xff, - ifreq.ifr_hwaddr.sa_data[5]&0xff); - - Jim_AppendString(interp, tclOutput, buffer, strlen(buffer)); - - Jim_SetResult(interp, tclOutput); - - return JIM_OK; - } - } - close(SockFD); - - return JIM_ERR; - -} -#endif -#endif - -static const struct command_registration ioutil_command_handlers[] = { - { - .name = "cat", - .handler = handle_cat_command, - .mode = COMMAND_ANY, - .help = "display text file content", - .usage = "file_name", - }, - { - .name = "trunc", - .handler = handle_trunc_command, - .mode = COMMAND_ANY, - .help = "truncate a file to zero length", - .usage = "file_name", - }, - { - .name = "cp", - .handler = handle_cp_command, - .mode = COMMAND_ANY, - .help = "copy a file", - .usage = "src_file_name dst_file_name", - }, - { - .name = "append_file", - .handler = handle_append_command, - .mode = COMMAND_ANY, - .help = "append a variable number of strings to a file", - .usage = "file_name [, [, ...]]", - }, -#ifdef HAVE_MALLOC_H - { - .name = "meminfo", - .handler = handle_meminfo_command, - .mode = COMMAND_ANY, - .help = "display free heap space", - .usage = "", - }, -#endif - { - .name = "rm", - .mode = COMMAND_ANY, - .handler = handle_rm_command, - .help = "remove a directory or file", - .usage = "file_name", - }, - - /* - * Peek and poke are security holes -- they manipulate - * server-internal addresses. - */ - - /* jim handlers */ - { - .name = "peek", - .mode = COMMAND_ANY, - .jim_handler = ioutil_Jim_Command_peek, - .help = "peek at a memory address", - .usage = "address", - }, - { - .name = "poke", - .mode = COMMAND_ANY, - .jim_handler = ioutil_Jim_Command_poke, - .help = "poke at a memory address", - .usage = "address value", - }, - { - .name = "ls", - .mode = COMMAND_ANY, - .jim_handler = ioutil_Jim_Command_ls, - .help = "show a listing of files", - .usage = "dirname", - }, -#ifdef HAVE_SYS_IOCTL_H -#ifdef SIOCGIFHWADDR - { - .name = "mac", - .mode = COMMAND_ANY, - .jim_handler = ioutil_Jim_Command_mac, - .help = "show MAC address", - }, -#endif -#endif - { - .name = "ip", - .jim_handler = ioutil_Jim_Command_ip, - .mode = COMMAND_ANY, - .help = "show IP address", - }, - COMMAND_REGISTRATION_DONE -}; - -int ioutil_init(struct command_context *cmd_ctx) -{ - return register_commands(cmd_ctx, NULL, ioutil_command_handlers); -} diff --git a/src/helper/ioutil.h b/src/helper/ioutil.h deleted file mode 100644 index f060aab09..000000000 --- a/src/helper/ioutil.h +++ /dev/null @@ -1,25 +0,0 @@ -/*************************************************************************** - * Copyright (C) 2009 Zachary T Welch * - * * - * 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 . * - ***************************************************************************/ - -#ifndef OPENOCD_HELPER_IOUTIL_H -#define OPENOCD_HELPER_IOUTIL_H - -struct command_context; - -int ioutil_init(struct command_context *cmd_ctx); - -#endif /* OPENOCD_HELPER_IOUTIL_H */ diff --git a/src/helper/ioutil_stubs.c b/src/helper/ioutil_stubs.c deleted file mode 100644 index 0d81fe665..000000000 --- a/src/helper/ioutil_stubs.c +++ /dev/null @@ -1,28 +0,0 @@ -/*************************************************************************** - * Copyright (C) 2009 Zachary T Welch * - * * - * 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 . * - ***************************************************************************/ - -#ifdef HAVE_CONFIG_H -#include -#endif -#include "ioutil.h" -#include "log.h" - -int ioutil_init(struct command_context *cmd_ctx) -{ - LOG_DEBUG("libocdhelper was built without I/O utility support"); - return ERROR_OK; -} diff --git a/src/helper/options.c b/src/helper/options.c index 246c6a8b5..f996749ea 100644 --- a/src/helper/options.c +++ b/src/helper/options.c @@ -55,7 +55,6 @@ static const struct option long_options[] = { {"search", required_argument, 0, 's'}, {"log_output", required_argument, 0, 'l'}, {"command", required_argument, 0, 'c'}, - {"pipe", no_argument, 0, 'p'}, {0, 0, 0, 0} }; @@ -282,7 +281,7 @@ int parse_cmdline_args(struct command_context *cmd_ctx, int argc, char *argv[]) /* getopt_long stores the option index here. */ int option_index = 0; - c = getopt_long(argc, argv, "hvd::l:f:s:c:p", long_options, &option_index); + c = getopt_long(argc, argv, "hvd::l:f:s:c:", long_options, &option_index); /* Detect the end of the options. */ if (c == -1) @@ -322,13 +321,6 @@ int parse_cmdline_args(struct command_context *cmd_ctx, int argc, char *argv[]) if (optarg) add_config_command(optarg); break; - case 'p': - /* to replicate the old syntax this needs to be synchronous - * otherwise the gdb stdin will overflow with the warning message */ - command_run_line(cmd_ctx, "gdb_port pipe; log_output openocd.log"); - LOG_WARNING("deprecated option: -p/--pipe. Use '-c \"gdb_port pipe; " - "log_output openocd.log\"' instead."); - break; default: /* '?' */ /* getopt will emit an error message, all we have to do is bail. */ return ERROR_FAIL; diff --git a/src/jtag/Makefile.am b/src/jtag/Makefile.am index b82914bcb..4ed5e7aa0 100644 --- a/src/jtag/Makefile.am +++ b/src/jtag/Makefile.am @@ -3,33 +3,6 @@ noinst_LTLIBRARIES += %D%/libjtag.la JTAG_SRCS = %D%/commands.c %C%_libjtag_la_LIBADD = -BUILT_SOURCES += %D%/minidriver_imp.h -CLEANFILES += %D%/minidriver_imp.h - -if MINIDRIVER - -if ZY1000 -JTAG_SRCS += %D%/zy1000/zy1000.c -JTAG_MINIDRIVER_DIR = %D%/zy1000 -endif -if MINIDRIVER_DUMMY -JTAG_SRCS += %D%/minidummy/minidummy.c -JTAG_MINIDRIVER_DIR = %D%/minidummy -endif - -MINIDRIVER_IMP_DIR = %D%/minidriver - -%D%/jtag_minidriver.h: $(JTAG_MINIDRIVER_DIR)/jtag_minidriver.h - cp $< $@ - -BUILT_SOURCES += %D%/jtag_minidriver.h - -CLEANFILES += %D%/jtag_minidriver.h - -else - -MINIDRIVER_IMP_DIR = %D%/drivers - if HLADAPTER include %D%/hla/Makefile.am %C%_libjtag_la_LIBADD += $(top_builddir)/%D%/hla/libocdhla.la @@ -43,13 +16,6 @@ endif include %D%/drivers/Makefile.am %C%_libjtag_la_LIBADD += $(top_builddir)/%D%/drivers/libocdjtagdrivers.la -endif -# endif // MINIDRIVER - -%D%/minidriver_imp.h: $(MINIDRIVER_IMP_DIR)/minidriver_imp.h - cp $< $@ - - %C%_libjtag_la_SOURCES = \ %D%/adapter.c \ %D%/core.c \ @@ -63,8 +29,6 @@ endif %D%/interfaces.h \ %D%/minidriver.h \ %D%/jtag.h \ - %D%/minidriver/minidriver_imp.h \ - %D%/minidummy/jtag_minidriver.h \ %D%/swd.h \ %D%/swim.h \ %D%/tcl.h \ diff --git a/src/jtag/adapter.c b/src/jtag/adapter.c index 13368ab4a..97ede5045 100644 --- a/src/jtag/adapter.c +++ b/src/jtag/adapter.c @@ -493,7 +493,6 @@ COMMAND_HANDLER(handle_adapter_reset_de_assert) (srst == VALUE_DEASSERT) ? SRST_DEASSERT : SRST_ASSERT); } -#ifndef HAVE_JTAG_MINIDRIVER_H #ifdef HAVE_LIBUSB_GET_PORT_NUMBERS COMMAND_HANDLER(handle_usb_location_command) { @@ -518,7 +517,6 @@ static const struct command_registration adapter_usb_command_handlers[] = { #endif /* HAVE_LIBUSB_GET_PORT_NUMBERS */ COMMAND_REGISTRATION_DONE }; -#endif /* MINIDRIVER */ static const struct command_registration adapter_srst_command_handlers[] = { { @@ -584,7 +582,6 @@ static const struct command_registration adapter_command_handlers[] = { .help = "Declare transports the adapter supports.", .usage = "transport ... ", }, -#ifndef HAVE_JTAG_MINIDRIVER_H { .name = "usb", .mode = COMMAND_ANY, @@ -592,7 +589,6 @@ static const struct command_registration adapter_command_handlers[] = { .usage = "", .chain = adapter_usb_command_handlers, }, -#endif /* MINIDRIVER */ { .name = "assert", .handler = handle_adapter_reset_de_assert, diff --git a/src/jtag/aice/Makefile.am b/src/jtag/aice/Makefile.am index 97e38258a..b6a7ba922 100644 --- a/src/jtag/aice/Makefile.am +++ b/src/jtag/aice/Makefile.am @@ -1,6 +1,6 @@ noinst_LTLIBRARIES += %D%/libocdaice.la -%C%_libocdaice_la_CPPFLAGS = -I$(top_srcdir)/src/jtag/drivers $(AM_CPPFLAGS) $(LIBUSB1_CFLAGS) $(LIBUSB0_CFLAGS) +%C%_libocdaice_la_CPPFLAGS = -I$(top_srcdir)/src/jtag/drivers $(AM_CPPFLAGS) $(LIBUSB1_CFLAGS) %C%_libocdaice_la_SOURCES = \ %D%/aice_transport.c \ %D%/aice_interface.c \ diff --git a/src/jtag/core.c b/src/jtag/core.c index ac589063b..37924aad0 100644 --- a/src/jtag/core.c +++ b/src/jtag/core.c @@ -427,7 +427,6 @@ static void jtag_add_scan_check(struct jtag_tap *active, void (*jtag_add_scan)( for (int i = 0; i < in_num_fields; i++) { if ((in_fields[i].check_value != NULL) && (in_fields[i].in_value != NULL)) { - /* this is synchronous for a minidriver */ jtag_add_callback4(jtag_check_value_mask_callback, (jtag_callback_data_t)in_fields[i].in_value, (jtag_callback_data_t)in_fields[i].check_value, @@ -954,12 +953,6 @@ int default_interface_jtag_execute_queue(void) int result = jtag->jtag_ops->execute_queue(); -#if !HAVE_JTAG_MINIDRIVER_H - /* Only build this if we use a regular driver with a command queue. - * Otherwise jtag_command_queue won't be found at compile/link time. Its - * definition is in jtag/commands.c, which is only built/linked by - * jtag/Makefile.am if MINIDRIVER_DUMMY || !MINIDRIVER, but those variables - * aren't accessible here. Use HAVE_JTAG_MINIDRIVER_H */ struct jtag_command *cmd = jtag_command_queue; while (debug_level >= LOG_LVL_DEBUG_IO && cmd) { switch (cmd->type) { @@ -1018,7 +1011,6 @@ int default_interface_jtag_execute_queue(void) } cmd = cmd->next; } -#endif return result; } diff --git a/src/jtag/drivers/Makefile.am b/src/jtag/drivers/Makefile.am index f7a54b003..da60f366e 100644 --- a/src/jtag/drivers/Makefile.am +++ b/src/jtag/drivers/Makefile.am @@ -27,12 +27,6 @@ DRIVERFILES += %D%/libusb_helper.c %C%_libocdjtagdrivers_la_LIBADD += $(LIBUSB1_LIBS) endif -if USE_LIBUSB0 -DRIVERFILES += %D%/usb_common.c -%C%_libocdjtagdrivers_la_CPPFLAGS += $(LIBUSB0_CFLAGS) -%C%_libocdjtagdrivers_la_LIBADD += $(LIBUSB0_LIBS) -endif - if USE_LIBFTDI %C%_libocdjtagdrivers_la_CPPFLAGS += $(LIBFTDI_CFLAGS) %C%_libocdjtagdrivers_la_LIBADD += $(LIBFTDI_LIBS) @@ -203,7 +197,6 @@ DRIVERHEADERS = \ %D%/rlink_dtc_cmd.h \ %D%/rlink_ep1_cmd.h \ %D%/rlink_st7.h \ - %D%/usb_common.h \ %D%/versaloon/usbtoxxx/usbtoxxx.h \ %D%/versaloon/usbtoxxx/usbtoxxx_internal.h \ %D%/versaloon/versaloon.h \ diff --git a/src/jtag/drivers/arm-jtag-ew.c b/src/jtag/drivers/arm-jtag-ew.c index 754f93767..b98beaebc 100644 --- a/src/jtag/drivers/arm-jtag-ew.c +++ b/src/jtag/drivers/arm-jtag-ew.c @@ -24,7 +24,7 @@ #include #include "helper/system.h" #include -#include "usb_common.h" +#include "libusb_helper.h" #define USB_VID 0x15ba #define USB_PID 0x001e @@ -76,7 +76,7 @@ static void armjtagew_tap_append_scan(int length, uint8_t *buffer, struct scan_c /* ARM-JTAG-EW lowlevel functions */ struct armjtagew { - struct usb_dev_handle *usb_handle; + struct libusb_device_handle *usb_handle; }; static struct armjtagew *armjtagew_usb_open(void); @@ -685,35 +685,37 @@ static int armjtagew_tap_execute(void) static struct armjtagew *armjtagew_usb_open(void) { - usb_init(); - const uint16_t vids[] = { USB_VID, 0 }; const uint16_t pids[] = { USB_PID, 0 }; - struct usb_dev_handle *dev; - if (jtag_usb_open(vids, pids, &dev) != ERROR_OK) + struct libusb_device_handle *dev; + + if (jtag_libusb_open(vids, pids, NULL, &dev, NULL) != ERROR_OK) return NULL; struct armjtagew *result = malloc(sizeof(struct armjtagew)); result->usb_handle = dev; #if 0 - /* usb_set_configuration required under win32 */ - usb_set_configuration(dev, dev->config[0].bConfigurationValue); + /* libusb_set_configuration required under win32 */ + struct libusb_config_descriptor *config; + struct libusb_device *usb_dev = libusb_get_device(dev); + libusb_get_config_descriptor(usb_dev, 0, &config); + libusb_set_configuration(dev, config->bConfigurationValue); #endif - usb_claim_interface(dev, 0); + libusb_claim_interface(dev, 0); #if 0 /* * This makes problems under Mac OS X. And is not needed * under Windows. Hopefully this will not break a linux build */ - usb_set_altinterface(dev, 0); + libusb_set_interface_alt_setting(dev, 0, 0); #endif return result; } static void armjtagew_usb_close(struct armjtagew *armjtagew) { - usb_close(armjtagew->usb_handle); + libusb_close(armjtagew->usb_handle); free(armjtagew); } @@ -726,13 +728,13 @@ static int armjtagew_usb_message(struct armjtagew *armjtagew, int out_length, in if (result == out_length) { result = armjtagew_usb_read(armjtagew, in_length); if (result != in_length) { - LOG_ERROR("usb_bulk_read failed (requested=%d, result=%d)", + LOG_ERROR("jtag_libusb_bulk_read failed (requested=%d, result=%d)", in_length, result); return -1; } } else { - LOG_ERROR("usb_bulk_write failed (requested=%d, result=%d)", out_length, result); + LOG_ERROR("jtag_libusb_bulk_write failed (requested=%d, result=%d)", out_length, result); return -1; } return 0; @@ -742,6 +744,7 @@ static int armjtagew_usb_message(struct armjtagew *armjtagew, int out_length, in static int armjtagew_usb_write(struct armjtagew *armjtagew, int out_length) { int result; + int transferred; if (out_length > ARMJTAGEW_OUT_BUFFER_SIZE) { LOG_ERROR("armjtagew_write illegal out_length=%d (max=%d)", @@ -750,29 +753,34 @@ static int armjtagew_usb_write(struct armjtagew *armjtagew, int out_length) return -1; } - result = usb_bulk_write(armjtagew->usb_handle, ARMJTAGEW_EPT_BULK_OUT, - (char *)usb_out_buffer, out_length, ARMJTAGEW_USB_TIMEOUT); + result = jtag_libusb_bulk_write(armjtagew->usb_handle, ARMJTAGEW_EPT_BULK_OUT, + (char *)usb_out_buffer, out_length, ARMJTAGEW_USB_TIMEOUT, &transferred); LOG_DEBUG_IO("armjtagew_usb_write, out_length = %d, result = %d", out_length, result); #ifdef _DEBUG_USB_COMMS_ armjtagew_debug_buffer(usb_out_buffer, out_length); #endif - return result; + if (result != ERROR_OK) + return -1; + return transferred; } /* Read data from USB into in_buffer. */ static int armjtagew_usb_read(struct armjtagew *armjtagew, int exp_in_length) { - int result = usb_bulk_read(armjtagew->usb_handle, ARMJTAGEW_EPT_BULK_IN, - (char *)usb_in_buffer, exp_in_length, ARMJTAGEW_USB_TIMEOUT); + int transferred; + int result = jtag_libusb_bulk_read(armjtagew->usb_handle, ARMJTAGEW_EPT_BULK_IN, + (char *)usb_in_buffer, exp_in_length, ARMJTAGEW_USB_TIMEOUT, &transferred); LOG_DEBUG_IO("armjtagew_usb_read, result = %d", result); #ifdef _DEBUG_USB_COMMS_ armjtagew_debug_buffer(usb_in_buffer, result); #endif - return result; + if (result != ERROR_OK) + return -1; + return transferred; } #ifdef _DEBUG_USB_COMMS_ diff --git a/src/jtag/drivers/cmsis_dap.c b/src/jtag/drivers/cmsis_dap.c index e2762e1a3..6d60b7104 100644 --- a/src/jtag/drivers/cmsis_dap.c +++ b/src/jtag/drivers/cmsis_dap.c @@ -170,10 +170,6 @@ static const char * const info_caps_str[] = { "JTAG Supported" }; -/* max clock speed (kHz) */ -#define DAP_MAX_CLOCK 5000 - - struct pending_transfer_result { uint8_t cmd; uint32_t data; @@ -230,16 +226,12 @@ static int cmsis_dap_open(void) { const struct cmsis_dap_backend *backend = NULL; - struct cmsis_dap *dap = malloc(sizeof(struct cmsis_dap)); + struct cmsis_dap *dap = calloc(1, sizeof(struct cmsis_dap)); if (dap == NULL) { LOG_ERROR("unable to allocate memory"); return ERROR_FAIL; } - dap->caps = 0; - dap->mode = 0; - dap->packet_size = 0; /* initialized by backend */ - if (cmsis_dap_backend >= 0) { /* Use forced backend */ backend = cmsis_dap_backends[cmsis_dap_backend]; @@ -262,17 +254,7 @@ static int cmsis_dap_open(void) return ERROR_FAIL; } - assert(dap->packet_size > 0); - dap->backend = backend; - dap->packet_buffer = malloc(dap->packet_size); - - if (dap->packet_buffer == NULL) { - LOG_ERROR("unable to allocate memory"); - dap->backend->close(dap); - free(dap); - return ERROR_FAIL; - } cmsis_dap_handle = dap; @@ -326,17 +308,14 @@ static int cmsis_dap_xfer(struct cmsis_dap *dap, int txlen) static int cmsis_dap_cmd_DAP_SWJ_Pins(uint8_t pins, uint8_t mask, uint32_t delay, uint8_t *input) { int retval; - uint8_t *buffer = cmsis_dap_handle->packet_buffer; + uint8_t *command = cmsis_dap_handle->command; - buffer[0] = 0; /* report number */ - buffer[1] = CMD_DAP_SWJ_PINS; - buffer[2] = pins; - buffer[3] = mask; - buffer[4] = delay & 0xff; - buffer[5] = (delay >> 8) & 0xff; - buffer[6] = (delay >> 16) & 0xff; - buffer[7] = (delay >> 24) & 0xff; - retval = cmsis_dap_xfer(cmsis_dap_handle, 8); + command[0] = CMD_DAP_SWJ_PINS; + command[1] = pins; + command[2] = mask; + h_u32_to_le(&command[3], delay); + + retval = cmsis_dap_xfer(cmsis_dap_handle, 7); if (retval != ERROR_OK) { LOG_ERROR("CMSIS-DAP command CMD_DAP_SWJ_PINS failed."); @@ -344,7 +323,7 @@ static int cmsis_dap_cmd_DAP_SWJ_Pins(uint8_t pins, uint8_t mask, uint32_t delay } if (input) - *input = buffer[1]; + *input = cmsis_dap_handle->response[1]; return ERROR_OK; } @@ -352,19 +331,17 @@ static int cmsis_dap_cmd_DAP_SWJ_Pins(uint8_t pins, uint8_t mask, uint32_t delay static int cmsis_dap_cmd_DAP_SWJ_Clock(uint32_t swj_clock) { int retval; - uint8_t *buffer = cmsis_dap_handle->packet_buffer; + uint8_t *command = cmsis_dap_handle->command; /* set clock in Hz */ swj_clock *= 1000; - buffer[0] = 0; /* report number */ - buffer[1] = CMD_DAP_SWJ_CLOCK; - buffer[2] = swj_clock & 0xff; - buffer[3] = (swj_clock >> 8) & 0xff; - buffer[4] = (swj_clock >> 16) & 0xff; - buffer[5] = (swj_clock >> 24) & 0xff; - retval = cmsis_dap_xfer(cmsis_dap_handle, 6); - if (retval != ERROR_OK || buffer[1] != DAP_OK) { + command[0] = CMD_DAP_SWJ_CLOCK; + h_u32_to_le(&command[1], swj_clock); + + retval = cmsis_dap_xfer(cmsis_dap_handle, 5); + + if (retval != ERROR_OK || cmsis_dap_handle->response[1] != DAP_OK) { LOG_ERROR("CMSIS-DAP command CMD_DAP_SWJ_CLOCK failed."); return ERROR_JTAG_DEVICE_ERROR; } @@ -376,7 +353,7 @@ static int cmsis_dap_cmd_DAP_SWJ_Clock(uint32_t swj_clock) static int cmsis_dap_cmd_DAP_SWJ_Sequence(uint8_t s_len, const uint8_t *sequence) { int retval; - uint8_t *buffer = cmsis_dap_handle->packet_buffer; + uint8_t *command = cmsis_dap_handle->command; #ifdef CMSIS_DAP_JTAG_DEBUG LOG_DEBUG("cmsis-dap TMS sequence: len=%d", s_len); @@ -386,14 +363,12 @@ static int cmsis_dap_cmd_DAP_SWJ_Sequence(uint8_t s_len, const uint8_t *sequence printf("\n"); #endif - buffer[0] = 0; /* report number */ - buffer[1] = CMD_DAP_SWJ_SEQ; - buffer[2] = s_len; - bit_copy(&buffer[3], 0, sequence, 0, s_len); + command[0] = CMD_DAP_SWJ_SEQ; + command[1] = s_len; + bit_copy(&command[2], 0, sequence, 0, s_len); - retval = cmsis_dap_xfer(cmsis_dap_handle, DIV_ROUND_UP(s_len, 8) + 3); - - if (retval != ERROR_OK || buffer[1] != DAP_OK) + retval = cmsis_dap_xfer(cmsis_dap_handle, 2 + DIV_ROUND_UP(s_len, 8)); + if (retval != ERROR_OK || cmsis_dap_handle->response[1] != DAP_OK) return ERROR_FAIL; return ERROR_OK; @@ -402,19 +377,19 @@ static int cmsis_dap_cmd_DAP_SWJ_Sequence(uint8_t s_len, const uint8_t *sequence static int cmsis_dap_cmd_DAP_Info(uint8_t info, uint8_t **data) { int retval; - uint8_t *buffer = cmsis_dap_handle->packet_buffer; + uint8_t *command = cmsis_dap_handle->command; - buffer[0] = 0; /* report number */ - buffer[1] = CMD_DAP_INFO; - buffer[2] = info; - retval = cmsis_dap_xfer(cmsis_dap_handle, 3); + command[0] = CMD_DAP_INFO; + command[1] = info; + + retval = cmsis_dap_xfer(cmsis_dap_handle, 2); if (retval != ERROR_OK) { LOG_ERROR("CMSIS-DAP command CMD_INFO failed."); return ERROR_JTAG_DEVICE_ERROR; } - *data = &(buffer[1]); + *data = &cmsis_dap_handle->response[1]; return ERROR_OK; } @@ -422,15 +397,15 @@ static int cmsis_dap_cmd_DAP_Info(uint8_t info, uint8_t **data) static int cmsis_dap_cmd_DAP_LED(uint8_t led, uint8_t state) { int retval; - uint8_t *buffer = cmsis_dap_handle->packet_buffer; + uint8_t *command = cmsis_dap_handle->command; - buffer[0] = 0; /* report number */ - buffer[1] = CMD_DAP_LED; - buffer[2] = led; - buffer[3] = state; - retval = cmsis_dap_xfer(cmsis_dap_handle, 4); + command[0] = CMD_DAP_LED; + command[1] = led; + command[2] = state; - if (retval != ERROR_OK || buffer[1] != 0x00) { + retval = cmsis_dap_xfer(cmsis_dap_handle, 3); + + if (retval != ERROR_OK || cmsis_dap_handle->response[1] != DAP_OK) { LOG_ERROR("CMSIS-DAP command CMD_LED failed."); return ERROR_JTAG_DEVICE_ERROR; } @@ -441,19 +416,19 @@ static int cmsis_dap_cmd_DAP_LED(uint8_t led, uint8_t state) static int cmsis_dap_cmd_DAP_Connect(uint8_t mode) { int retval; - uint8_t *buffer = cmsis_dap_handle->packet_buffer; + uint8_t *command = cmsis_dap_handle->command; - buffer[0] = 0; /* report number */ - buffer[1] = CMD_DAP_CONNECT; - buffer[2] = mode; - retval = cmsis_dap_xfer(cmsis_dap_handle, 3); + command[0] = CMD_DAP_CONNECT; + command[1] = mode; + + retval = cmsis_dap_xfer(cmsis_dap_handle, 2); if (retval != ERROR_OK) { LOG_ERROR("CMSIS-DAP command CMD_CONNECT failed."); return ERROR_JTAG_DEVICE_ERROR; } - if (buffer[1] != mode) { + if (cmsis_dap_handle->response[1] != mode) { LOG_ERROR("CMSIS-DAP failed to connect in mode (%d)", mode); return ERROR_JTAG_DEVICE_ERROR; } @@ -464,13 +439,13 @@ static int cmsis_dap_cmd_DAP_Connect(uint8_t mode) static int cmsis_dap_cmd_DAP_Disconnect(void) { int retval; - uint8_t *buffer = cmsis_dap_handle->packet_buffer; + uint8_t *command = cmsis_dap_handle->command; - buffer[0] = 0; /* report number */ - buffer[1] = CMD_DAP_DISCONNECT; - retval = cmsis_dap_xfer(cmsis_dap_handle, 2); + command[0] = CMD_DAP_DISCONNECT; - if (retval != ERROR_OK || buffer[1] != DAP_OK) { + retval = cmsis_dap_xfer(cmsis_dap_handle, 1); + + if (retval != ERROR_OK || cmsis_dap_handle->response[1] != DAP_OK) { LOG_ERROR("CMSIS-DAP command CMD_DISCONNECT failed."); return ERROR_JTAG_DEVICE_ERROR; } @@ -481,18 +456,16 @@ static int cmsis_dap_cmd_DAP_Disconnect(void) static int cmsis_dap_cmd_DAP_TFER_Configure(uint8_t idle, uint16_t retry_count, uint16_t match_retry) { int retval; - uint8_t *buffer = cmsis_dap_handle->packet_buffer; + uint8_t *command = cmsis_dap_handle->command; - buffer[0] = 0; /* report number */ - buffer[1] = CMD_DAP_TFER_CONFIGURE; - buffer[2] = idle; - buffer[3] = retry_count & 0xff; - buffer[4] = (retry_count >> 8) & 0xff; - buffer[5] = match_retry & 0xff; - buffer[6] = (match_retry >> 8) & 0xff; - retval = cmsis_dap_xfer(cmsis_dap_handle, 7); + command[0] = CMD_DAP_TFER_CONFIGURE; + command[1] = idle; + h_u16_to_le(&command[2], retry_count); + h_u16_to_le(&command[4], match_retry); - if (retval != ERROR_OK || buffer[1] != DAP_OK) { + retval = cmsis_dap_xfer(cmsis_dap_handle, 6); + + if (retval != ERROR_OK || cmsis_dap_handle->response[1] != DAP_OK) { LOG_ERROR("CMSIS-DAP command CMD_TFER_Configure failed."); return ERROR_JTAG_DEVICE_ERROR; } @@ -503,14 +476,14 @@ static int cmsis_dap_cmd_DAP_TFER_Configure(uint8_t idle, uint16_t retry_count, static int cmsis_dap_cmd_DAP_SWD_Configure(uint8_t cfg) { int retval; - uint8_t *buffer = cmsis_dap_handle->packet_buffer; + uint8_t *command = cmsis_dap_handle->command; - buffer[0] = 0; /* report number */ - buffer[1] = CMD_DAP_SWD_CONFIGURE; - buffer[2] = cfg; - retval = cmsis_dap_xfer(cmsis_dap_handle, 3); + command[0] = CMD_DAP_SWD_CONFIGURE; + command[1] = cfg; - if (retval != ERROR_OK || buffer[1] != DAP_OK) { + retval = cmsis_dap_xfer(cmsis_dap_handle, 2); + + if (retval != ERROR_OK || cmsis_dap_handle->response[1] != DAP_OK) { LOG_ERROR("CMSIS-DAP command CMD_SWD_Configure failed."); return ERROR_JTAG_DEVICE_ERROR; } @@ -522,15 +495,14 @@ static int cmsis_dap_cmd_DAP_SWD_Configure(uint8_t cfg) static int cmsis_dap_cmd_DAP_Delay(uint16_t delay_us) { int retval; - uint8_t *buffer = cmsis_dap_handle->packet_buffer; + uint8_t *command = cmsis_dap_handle->command; - buffer[0] = 0; /* report number */ - buffer[1] = CMD_DAP_DELAY; - buffer[2] = delay_us & 0xff; - buffer[3] = (delay_us >> 8) & 0xff; - retval = cmsis_dap_xfer(cmsis_dap_handle, 4); + command[0] = CMD_DAP_DELAY; + h_u16_to_le(&command[1], delay_us); - if (retval != ERROR_OK || buffer[1] != DAP_OK) { + retval = cmsis_dap_xfer(cmsis_dap_handle, 3); + + if (retval != ERROR_OK || cmsis_dap_handle->response[1] != DAP_OK) { LOG_ERROR("CMSIS-DAP command CMD_Delay failed."); return ERROR_JTAG_DEVICE_ERROR; } @@ -541,7 +513,7 @@ static int cmsis_dap_cmd_DAP_Delay(uint16_t delay_us) static void cmsis_dap_swd_write_from_queue(struct cmsis_dap *dap) { - uint8_t *buffer = dap->packet_buffer; + uint8_t *command = cmsis_dap_handle->command; struct pending_request_block *block = &pending_fifo[pending_fifo_put_idx]; LOG_DEBUG_IO("Executing %d queued transactions from FIFO index %d", block->transfer_count, pending_fifo_put_idx); @@ -554,11 +526,10 @@ static void cmsis_dap_swd_write_from_queue(struct cmsis_dap *dap) if (block->transfer_count == 0) goto skip; - size_t idx = 0; - buffer[idx++] = 0; /* report number */ - buffer[idx++] = CMD_DAP_TFER; - buffer[idx++] = 0x00; /* DAP Index */ - buffer[idx++] = block->transfer_count; + command[0] = CMD_DAP_TFER; + command[1] = 0x00; /* DAP Index */ + command[2] = block->transfer_count; + size_t idx = 3; for (int i = 0; i < block->transfer_count; i++) { struct pending_transfer_result *transfer = &(block->transfers[i]); @@ -589,12 +560,10 @@ static void cmsis_dap_swd_write_from_queue(struct cmsis_dap *dap) data &= ~CORUNDETECT; } - buffer[idx++] = (cmd >> 1) & 0x0f; + command[idx++] = (cmd >> 1) & 0x0f; if (!(cmd & SWD_CMD_RnW)) { - buffer[idx++] = (data) & 0xff; - buffer[idx++] = (data >> 8) & 0xff; - buffer[idx++] = (data >> 16) & 0xff; - buffer[idx++] = (data >> 24) & 0xff; + h_u32_to_le(&command[idx], data); + idx += 4; } } @@ -620,7 +589,6 @@ skip: static void cmsis_dap_swd_read_process(struct cmsis_dap *dap, int timeout_ms) { - uint8_t *buffer = dap->packet_buffer; struct pending_request_block *block = &pending_fifo[pending_fifo_get_idx]; if (pending_fifo_block_count == 0) @@ -637,30 +605,33 @@ static void cmsis_dap_swd_read_process(struct cmsis_dap *dap, int timeout_ms) goto skip; } - if (buffer[2] & 0x08) { - LOG_DEBUG("CMSIS-DAP Protocol Error @ %d (wrong parity)", buffer[1]); + uint8_t *resp = dap->response; + uint8_t transfer_count = resp[1]; + uint8_t ack = resp[2] & 0x07; + if (resp[2] & 0x08) { + LOG_DEBUG("CMSIS-DAP Protocol Error @ %d (wrong parity)", transfer_count); queued_retval = ERROR_FAIL; goto skip; } - uint8_t ack = buffer[2] & 0x07; if (ack != SWD_ACK_OK) { - LOG_DEBUG("SWD ack not OK @ %d %s", buffer[1], + LOG_DEBUG("SWD ack not OK @ %d %s", transfer_count, ack == SWD_ACK_WAIT ? "WAIT" : ack == SWD_ACK_FAULT ? "FAULT" : "JUNK"); queued_retval = ack == SWD_ACK_WAIT ? ERROR_WAIT : ERROR_FAIL; goto skip; } - if (block->transfer_count != buffer[1]) + if (block->transfer_count != transfer_count) LOG_ERROR("CMSIS-DAP transfer count mismatch: expected %d, got %d", - block->transfer_count, buffer[1]); + block->transfer_count, transfer_count); - LOG_DEBUG_IO("Received results of %d queued transactions FIFO index %d", buffer[1], pending_fifo_get_idx); + LOG_DEBUG_IO("Received results of %d queued transactions FIFO index %d", + transfer_count, pending_fifo_get_idx); size_t idx = 3; - for (int i = 0; i < buffer[1]; i++) { + for (int i = 0; i < transfer_count; i++) { struct pending_transfer_result *transfer = &(block->transfers[i]); if (transfer->cmd & SWD_CMD_RnW) { static uint32_t last_read; - uint32_t data = le_to_h_u32(&buffer[idx]); + uint32_t data = le_to_h_u32(&resp[idx]); uint32_t tmp = data; idx += 4; @@ -934,24 +905,20 @@ static int cmsis_dap_init(void) if (data[0] == 2) { /* short */ uint16_t pkt_sz = data[1] + (data[2] << 8); + if (pkt_sz != cmsis_dap_handle->packet_size) { - /* 4 bytes of command header + 5 bytes per register - * write. For bulk read sequences just 4 bytes are - * needed per transfer, so this is suboptimal. */ - pending_queue_len = (pkt_sz - 4) / 5; + /* 4 bytes of command header + 5 bytes per register + * write. For bulk read sequences just 4 bytes are + * needed per transfer, so this is suboptimal. */ + pending_queue_len = (pkt_sz - 4) / 5; - if (cmsis_dap_handle->packet_size != pkt_sz + 1) { - /* reallocate buffer */ - cmsis_dap_handle->packet_size = pkt_sz + 1; - cmsis_dap_handle->packet_buffer = realloc(cmsis_dap_handle->packet_buffer, - cmsis_dap_handle->packet_size); - if (cmsis_dap_handle->packet_buffer == NULL) { - LOG_ERROR("unable to reallocate memory"); - return ERROR_FAIL; - } + free(cmsis_dap_handle->packet_buffer); + retval = cmsis_dap_handle->backend->packet_buffer_alloc(cmsis_dap_handle, pkt_sz); + if (retval != ERROR_OK) + return retval; + + LOG_DEBUG("CMSIS-DAP: Packet Size = %" PRIu16, pkt_sz); } - - LOG_DEBUG("CMSIS-DAP: Packet Size = %" PRId16, pkt_sz); } /* INFO_ID_PKT_CNT - byte */ @@ -1168,20 +1135,21 @@ static void cmsis_dap_flush(void) LOG_DEBUG_IO("Flushing %d queued sequences (%d bytes) with %d pending scan results to capture", queued_seq_count, queued_seq_buf_end, pending_scan_result_count); - /* prep CMSIS-DAP packet */ - uint8_t *buffer = cmsis_dap_handle->packet_buffer; - buffer[0] = 0; /* report number */ - buffer[1] = CMD_DAP_JTAG_SEQ; - buffer[2] = queued_seq_count; - memcpy(buffer + 3, queued_seq_buf, queued_seq_buf_end); + /* prepare CMSIS-DAP packet */ + uint8_t *command = cmsis_dap_handle->command; + command[0] = CMD_DAP_JTAG_SEQ; + command[1] = queued_seq_count; + memcpy(&command[2], queued_seq_buf, queued_seq_buf_end); #ifdef CMSIS_DAP_JTAG_DEBUG - debug_parse_cmsis_buf(buffer, queued_seq_buf_end + 3); + debug_parse_cmsis_buf(command, queued_seq_buf_end + 2); #endif /* send command to USB device */ - int retval = cmsis_dap_xfer(cmsis_dap_handle, queued_seq_buf_end + 3); - if (retval != ERROR_OK || buffer[1] != DAP_OK) { + int retval = cmsis_dap_xfer(cmsis_dap_handle, queued_seq_buf_end + 2); + + uint8_t *resp = cmsis_dap_handle->response; + if (retval != ERROR_OK || resp[1] != DAP_OK) { LOG_ERROR("CMSIS-DAP command CMD_DAP_JTAG_SEQ failed."); exit(-1); } @@ -1189,7 +1157,7 @@ static void cmsis_dap_flush(void) #ifdef CMSIS_DAP_JTAG_DEBUG LOG_DEBUG_IO("USB response buf:"); for (int c = 0; c < queued_seq_buf_end + 3; ++c) - printf("%02X ", buffer[c]); + printf("%02X ", resp[c]); printf("\n"); #endif @@ -1200,10 +1168,10 @@ static void cmsis_dap_flush(void) i, pending_scan_result_count, scan->length, scan->first + 2, scan->buffer_offset); #ifdef CMSIS_DAP_JTAG_DEBUG for (uint32_t b = 0; b < DIV_ROUND_UP(scan->length, 8); ++b) - printf("%02X ", buffer[2+scan->first+b]); + printf("%02X ", resp[2+scan->first+b]); printf("\n"); #endif - bit_copy(scan->buffer, scan->buffer_offset, buffer + 2 + scan->first, 0, scan->length); + bit_copy(scan->buffer, scan->buffer_offset, &resp[2 + scan->first], 0, scan->length); } /* reset */ @@ -1545,9 +1513,6 @@ static int cmsis_dap_execute_queue(void) static int cmsis_dap_speed(int speed) { - if (speed > DAP_MAX_CLOCK) - LOG_INFO("High speed (adapter speed %d) may be limited by adapter firmware.", speed); - if (speed == 0) { LOG_ERROR("RTCK not supported. Set nonzero \"adapter speed\"."); return ERROR_JTAG_NOT_IMPLEMENTED; @@ -1580,22 +1545,21 @@ COMMAND_HANDLER(cmsis_dap_handle_cmd_command) { int retval; unsigned i; - uint8_t *buffer = cmsis_dap_handle->packet_buffer; - - buffer[0] = 0; /* report number */ + uint8_t *command = cmsis_dap_handle->command; for (i = 0; i < CMD_ARGC; i++) - buffer[i + 1] = strtoul(CMD_ARGV[i], NULL, 16); + command[i] = strtoul(CMD_ARGV[i], NULL, 16); - retval = cmsis_dap_xfer(cmsis_dap_handle, CMD_ARGC + 1); + retval = cmsis_dap_xfer(cmsis_dap_handle, CMD_ARGC); if (retval != ERROR_OK) { LOG_ERROR("CMSIS-DAP command failed."); return ERROR_JTAG_DEVICE_ERROR; } + uint8_t *resp = cmsis_dap_handle->response; LOG_INFO("Returned data %02" PRIx8 " %02" PRIx8 " %02" PRIx8 " %02" PRIx8, - buffer[1], buffer[2], buffer[3], buffer[4]); + resp[1], resp[2], resp[3], resp[4]); return ERROR_OK; } diff --git a/src/jtag/drivers/cmsis_dap.h b/src/jtag/drivers/cmsis_dap.h index 054621cd5..c9f24c896 100644 --- a/src/jtag/drivers/cmsis_dap.h +++ b/src/jtag/drivers/cmsis_dap.h @@ -13,6 +13,9 @@ struct cmsis_dap { uint16_t packet_size; int packet_count; uint8_t *packet_buffer; + uint16_t packet_buffer_size; + uint8_t *command; + uint8_t *response; uint8_t caps; uint8_t mode; }; @@ -23,10 +26,13 @@ struct cmsis_dap_backend { void (*close)(struct cmsis_dap *dap); int (*read)(struct cmsis_dap *dap, int timeout_ms); int (*write)(struct cmsis_dap *dap, int len, int timeout_ms); + int (*packet_buffer_alloc)(struct cmsis_dap *dap, unsigned int pkt_sz); }; extern const struct cmsis_dap_backend cmsis_dap_hid_backend; extern const struct cmsis_dap_backend cmsis_dap_usb_backend; extern const struct command_registration cmsis_dap_usb_subcommand_handlers[]; +#define REPORT_ID_SIZE 1 + #endif diff --git a/src/jtag/drivers/cmsis_dap_usb_bulk.c b/src/jtag/drivers/cmsis_dap_usb_bulk.c index 9c7644947..28f8e3a26 100644 --- a/src/jtag/drivers/cmsis_dap_usb_bulk.c +++ b/src/jtag/drivers/cmsis_dap_usb_bulk.c @@ -51,6 +51,9 @@ struct cmsis_dap_backend_data { static int cmsis_dap_usb_interface = -1; +static void cmsis_dap_usb_close(struct cmsis_dap *dap); +static int cmsis_dap_usb_alloc(struct cmsis_dap *dap, unsigned int pkt_sz); + static int cmsis_dap_usb_open(struct cmsis_dap *dap, uint16_t vids[], uint16_t pids[], char *serial) { int err; @@ -357,12 +360,24 @@ static int cmsis_dap_usb_open(struct cmsis_dap *dap, uint16_t vids[], uint16_t p return ERROR_FAIL; } - dap->packet_size = packet_size + 1; /* "+ 1" for compatibility with the HID backend */ + dap->packet_size = packet_size; + dap->packet_buffer_size = packet_size; dap->bdata->usb_ctx = ctx; dap->bdata->dev_handle = dev_handle; dap->bdata->ep_out = ep_out; dap->bdata->ep_in = ep_in; dap->bdata->interface = interface_num; + + dap->packet_buffer = malloc(dap->packet_buffer_size); + if (dap->packet_buffer == NULL) { + LOG_ERROR("unable to allocate memory"); + cmsis_dap_usb_close(dap); + return ERROR_FAIL; + } + + dap->command = dap->packet_buffer; + dap->response = dap->packet_buffer; + return ERROR_OK; } @@ -382,6 +397,8 @@ static void cmsis_dap_usb_close(struct cmsis_dap *dap) libusb_exit(dap->bdata->usb_ctx); free(dap->bdata); dap->bdata = NULL; + free(dap->packet_buffer); + dap->packet_buffer = NULL; } static int cmsis_dap_usb_read(struct cmsis_dap *dap, int timeout_ms) @@ -400,7 +417,7 @@ static int cmsis_dap_usb_read(struct cmsis_dap *dap, int timeout_ms) } } - memset(&dap->packet_buffer[transferred], 0, dap->packet_size - transferred); + memset(&dap->packet_buffer[transferred], 0, dap->packet_buffer_size - transferred); return transferred; } @@ -412,7 +429,7 @@ static int cmsis_dap_usb_write(struct cmsis_dap *dap, int txlen, int timeout_ms) /* skip the first byte that is only used by the HID backend */ err = libusb_bulk_transfer(dap->bdata->dev_handle, dap->bdata->ep_out, - dap->packet_buffer + 1, txlen - 1, &transferred, timeout_ms); + dap->packet_buffer, txlen, &transferred, timeout_ms); if (err) { if (err == LIBUSB_ERROR_TIMEOUT) { return ERROR_TIMEOUT_REACHED; @@ -425,6 +442,24 @@ static int cmsis_dap_usb_write(struct cmsis_dap *dap, int txlen, int timeout_ms) return transferred; } +static int cmsis_dap_usb_alloc(struct cmsis_dap *dap, unsigned int pkt_sz) +{ + uint8_t *buf = malloc(pkt_sz); + if (buf == NULL) { + LOG_ERROR("unable to allocate CMSIS-DAP packet buffer"); + return ERROR_FAIL; + } + + dap->packet_buffer = buf; + dap->packet_size = pkt_sz; + dap->packet_buffer_size = pkt_sz; + + dap->command = dap->packet_buffer; + dap->response = dap->packet_buffer; + + return ERROR_OK; +} + COMMAND_HANDLER(cmsis_dap_handle_usb_interface_command) { if (CMD_ARGC == 1) @@ -452,4 +487,5 @@ const struct cmsis_dap_backend cmsis_dap_usb_backend = { .close = cmsis_dap_usb_close, .read = cmsis_dap_usb_read, .write = cmsis_dap_usb_write, + .packet_buffer_alloc = cmsis_dap_usb_alloc, }; diff --git a/src/jtag/drivers/cmsis_dap_usb_hid.c b/src/jtag/drivers/cmsis_dap_usb_hid.c index 681aef171..e83ad1feb 100644 --- a/src/jtag/drivers/cmsis_dap_usb_hid.c +++ b/src/jtag/drivers/cmsis_dap_usb_hid.c @@ -40,12 +40,13 @@ #include "cmsis_dap.h" -#define PACKET_SIZE (64 + 1) /* 64 bytes plus report id */ - struct cmsis_dap_backend_data { hid_device *dev_handle; }; +static void cmsis_dap_hid_close(struct cmsis_dap *dap); +static int cmsis_dap_hid_alloc(struct cmsis_dap *dap, unsigned int pkt_sz); + static int cmsis_dap_hid_open(struct cmsis_dap *dap, uint16_t vids[], uint16_t pids[], char *serial) { hid_device *dev = NULL; @@ -145,7 +146,7 @@ static int cmsis_dap_hid_open(struct cmsis_dap *dap, uint16_t vids[], uint16_t p * without this info we cannot communicate with the adapter. * For the moment we have to hard code the packet size */ - dap->packet_size = PACKET_SIZE; + unsigned int packet_size = 64; /* atmel cmsis-dap uses 512 byte reports */ /* except when it doesn't e.g. with mEDBG on SAMD10 Xplained @@ -153,10 +154,18 @@ static int cmsis_dap_hid_open(struct cmsis_dap *dap, uint16_t vids[], uint16_t p /* TODO: HID report descriptor should be parsed instead of * hardcoding a match by VID */ if (target_vid == 0x03eb && target_pid != 0x2145 && target_pid != 0x2175) - dap->packet_size = 512 + 1; + packet_size = 512; dap->bdata->dev_handle = dev; + int retval = cmsis_dap_hid_alloc(dap, packet_size); + if (retval != ERROR_OK) { + cmsis_dap_hid_close(dap); + return ERROR_FAIL; + } + + dap->command = dap->packet_buffer + REPORT_ID_SIZE; + dap->response = dap->packet_buffer; return ERROR_OK; } @@ -166,11 +175,13 @@ static void cmsis_dap_hid_close(struct cmsis_dap *dap) hid_exit(); free(dap->bdata); dap->bdata = NULL; + free(dap->packet_buffer); + dap->packet_buffer = NULL; } static int cmsis_dap_hid_read(struct cmsis_dap *dap, int timeout_ms) { - int retval = hid_read_timeout(dap->bdata->dev_handle, dap->packet_buffer, dap->packet_size, timeout_ms); + int retval = hid_read_timeout(dap->bdata->dev_handle, dap->packet_buffer, dap->packet_buffer_size, timeout_ms); if (retval == 0) { return ERROR_TIMEOUT_REACHED; @@ -186,11 +197,13 @@ static int cmsis_dap_hid_write(struct cmsis_dap *dap, int txlen, int timeout_ms) { (void) timeout_ms; + dap->packet_buffer[0] = 0; /* HID report number */ + /* Pad the rest of the TX buffer with 0's */ - memset(dap->packet_buffer + txlen, 0, dap->packet_size - txlen); + memset(dap->command + txlen, 0, dap->packet_size - txlen); /* write data to device */ - int retval = hid_write(dap->bdata->dev_handle, dap->packet_buffer, dap->packet_size); + int retval = hid_write(dap->bdata->dev_handle, dap->packet_buffer, dap->packet_buffer_size); if (retval == -1) { LOG_ERROR("error writing data: %ls", hid_error(dap->bdata->dev_handle)); return ERROR_FAIL; @@ -199,10 +212,30 @@ static int cmsis_dap_hid_write(struct cmsis_dap *dap, int txlen, int timeout_ms) return retval; } +static int cmsis_dap_hid_alloc(struct cmsis_dap *dap, unsigned int pkt_sz) +{ + unsigned int packet_buffer_size = pkt_sz + REPORT_ID_SIZE; + uint8_t *buf = malloc(packet_buffer_size); + if (buf == NULL) { + LOG_ERROR("unable to allocate CMSIS-DAP packet buffer"); + return ERROR_FAIL; + } + + dap->packet_buffer = buf; + dap->packet_size = pkt_sz; + dap->packet_buffer_size = packet_buffer_size; + + dap->command = dap->packet_buffer + REPORT_ID_SIZE; + dap->response = dap->packet_buffer; + + return ERROR_OK; +} + const struct cmsis_dap_backend cmsis_dap_hid_backend = { .name = "hid", .open = cmsis_dap_hid_open, .close = cmsis_dap_hid_close, .read = cmsis_dap_hid_read, .write = cmsis_dap_hid_write, + .packet_buffer_alloc = cmsis_dap_hid_alloc, }; diff --git a/src/jtag/drivers/jtag_usb_common.c b/src/jtag/drivers/jtag_usb_common.c index f18ea54a2..fdd713783 100644 --- a/src/jtag/drivers/jtag_usb_common.c +++ b/src/jtag/drivers/jtag_usb_common.c @@ -51,7 +51,7 @@ bool jtag_usb_location_equal(uint8_t dev_bus, uint8_t *port_path, goto done; } - string_length -= 1; + string_length -= strnlen(ptr, string_length); /* check bus mismatch */ if (atoi(ptr) != dev_bus) goto done; @@ -69,7 +69,7 @@ bool jtag_usb_location_equal(uint8_t dev_bus, uint8_t *port_path, break; path_step++; - string_length -= 2; + string_length -= strnlen(ptr, string_length) + 1; }; /* walked the full path, all elements match */ diff --git a/src/jtag/drivers/nulink_usb.c b/src/jtag/drivers/nulink_usb.c index 00738ee4e..48a5c792e 100644 --- a/src/jtag/drivers/nulink_usb.c +++ b/src/jtag/drivers/nulink_usb.c @@ -253,7 +253,7 @@ static int nulink_usb_write_debug_reg(void *handle, uint32_t addr, uint32_t val) { struct nulink_usb_handle_s *h = handle; - LOG_DEBUG("nulink_usb_write_debug_reg 0x%08" PRIX32 "0x%08" PRIX32, addr, val); + LOG_DEBUG("nulink_usb_write_debug_reg 0x%08" PRIX32 " 0x%08" PRIX32, addr, val); nulink_usb_init_buffer(handle, 8 + 12 * 1); /* set command ID */ @@ -503,7 +503,7 @@ static int nulink_usb_read_mem8(void *handle, uint32_t addr, uint16_t len, aligned_addr = aligned_addr * 4; offset = addr - aligned_addr; LOG_DEBUG("nulink_usb_read_mem8: unaligned address addr 0x%08" PRIx32 - "/aligned addr 0x%08" PRIx32 "offset %" PRIu32, + "/aligned addr 0x%08" PRIx32 " offset %" PRIu32, addr, aligned_addr, offset); addr = aligned_addr; diff --git a/src/jtag/drivers/rlink.c b/src/jtag/drivers/rlink.c index d15dba750..41f36c116 100644 --- a/src/jtag/drivers/rlink.c +++ b/src/jtag/drivers/rlink.c @@ -34,7 +34,7 @@ #include "rlink_st7.h" #include "rlink_ep1_cmd.h" #include "rlink_dtc_cmd.h" -#include "usb_common.h" +#include "libusb_helper.h" /* This feature is made useless by running the DTC all the time. When automatic, the LED is on *whenever the DTC is running. Otherwise, USB messages are sent to turn it on and off. */ @@ -97,19 +97,20 @@ #define ST7_PC_TDO ST7_PC_IO9 #define ST7_PA_DBGACK ST7_PA_IO10 -static usb_dev_handle *pHDev; +static libusb_device_handle *pHDev; /* * ep1 commands are up to USB_EP1OUT_SIZE bytes in length. * This function takes care of zeroing the unused bytes before sending the packet. * Any reply packet is not handled by this function. */ -static int ep1_generic_commandl(usb_dev_handle *pHDev_param, size_t length, ...) +static int ep1_generic_commandl(libusb_device_handle *pHDev_param, size_t length, ...) { uint8_t usb_buffer[USB_EP1OUT_SIZE]; uint8_t *usb_buffer_p; va_list ap; int usb_ret; + int transferred; if (length > sizeof(usb_buffer)) length = sizeof(usb_buffer); @@ -128,25 +129,29 @@ static int ep1_generic_commandl(usb_dev_handle *pHDev_param, size_t length, ...) sizeof(usb_buffer) - (usb_buffer_p - usb_buffer) ); - usb_ret = usb_bulk_write( + usb_ret = jtag_libusb_bulk_write( pHDev_param, USB_EP1OUT_ADDR, (char *)usb_buffer, sizeof(usb_buffer), - USB_TIMEOUT_MS + USB_TIMEOUT_MS, + &transferred ); - return usb_ret; + if (usb_ret != ERROR_OK) + return usb_ret; + return transferred; } #if 0 static ssize_t ep1_memory_read( - usb_dev_handle *pHDev, uint16_t addr, + libusb_device_handle *pHDev_param, uint16_t addr, size_t length, uint8_t *buffer) { uint8_t usb_buffer[USB_EP1OUT_SIZE]; int usb_ret; size_t remain; ssize_t count; + int transferred; usb_buffer[0] = EP1_CMD_MEMORY_READ; memset( @@ -168,22 +173,24 @@ static ssize_t ep1_memory_read( usb_buffer[2] = addr; usb_buffer[3] = length; - usb_ret = usb_bulk_write( - pHDev, USB_EP1OUT_ADDR, - usb_buffer, sizeof(usb_buffer), - USB_TIMEOUT_MS + usb_ret = jtag_libusb_bulk_write( + pHDev_param, USB_EP1OUT_ADDR, + (char *)usb_buffer, sizeof(usb_buffer), + USB_TIMEOUT_MS, + &transferred ); - if (usb_ret < sizeof(usb_buffer)) + if (usb_ret != ERROR_OK || transferred < (int)sizeof(usb_buffer)) break; - usb_ret = usb_bulk_read( - pHDev, USB_EP1IN_ADDR, - buffer, length, - USB_TIMEOUT_MS + usb_ret = jtag_libusb_bulk_read( + pHDev_param, USB_EP1IN_ADDR, + (char *)buffer, length, + USB_TIMEOUT_MS, + &transferred ); - if (usb_ret < length) + if (usb_ret != ERROR_OK || transferred < (int)length) break; addr += length; @@ -196,7 +203,7 @@ static ssize_t ep1_memory_read( } #endif -static ssize_t ep1_memory_write(usb_dev_handle *pHDev_param, uint16_t addr, +static ssize_t ep1_memory_write(libusb_device_handle *pHDev_param, uint16_t addr, size_t length, uint8_t const *buffer) { uint8_t usb_buffer[USB_EP1OUT_SIZE]; @@ -229,13 +236,16 @@ static ssize_t ep1_memory_write(usb_dev_handle *pHDev_param, uint16_t addr, sizeof(usb_buffer) - 4 - length ); - usb_ret = usb_bulk_write( + int transferred; + + usb_ret = jtag_libusb_bulk_write( pHDev_param, USB_EP1OUT_ADDR, (char *)usb_buffer, sizeof(usb_buffer), - USB_TIMEOUT_MS + USB_TIMEOUT_MS, + &transferred ); - if ((size_t)usb_ret < sizeof(usb_buffer)) + if (usb_ret != ERROR_OK || transferred < (int)sizeof(usb_buffer)) break; addr += length; @@ -249,7 +259,7 @@ static ssize_t ep1_memory_write(usb_dev_handle *pHDev_param, uint16_t addr, #if 0 -static ssize_t ep1_memory_writel(usb_dev_handle *pHDev, uint16_t addr, +static ssize_t ep1_memory_writel(libusb_device_handle *pHDev_param, uint16_t addr, size_t length, ...) { uint8_t buffer[USB_EP1OUT_SIZE - 4]; @@ -269,7 +279,7 @@ static ssize_t ep1_memory_writel(usb_dev_handle *pHDev, uint16_t addr, remain--; } - return ep1_memory_write(pHDev, addr, length, buffer); + return ep1_memory_write(pHDev_param, addr, length, buffer); } #endif @@ -286,7 +296,7 @@ static ssize_t ep1_memory_writel(usb_dev_handle *pHDev, uint16_t addr, static uint8_t dtc_entry_download; /* The buffer is specially formatted to represent a valid image to load into the DTC. */ -static int dtc_load_from_buffer(usb_dev_handle *pHDev_param, const uint8_t *buffer, +static int dtc_load_from_buffer(libusb_device_handle *pHDev_param, const uint8_t *buffer, size_t length) { struct header_s { @@ -401,6 +411,7 @@ static int dtc_start_download(void) { int usb_err; uint8_t ep2txr; + int transferred; /* set up for download mode and make sure EP2 is set up to transmit */ usb_err = ep1_generic_commandl( @@ -418,12 +429,13 @@ static int dtc_start_download(void) return usb_err; /* read back ep2txr */ - usb_err = usb_bulk_read( + usb_err = jtag_libusb_bulk_read( pHDev, USB_EP1IN_ADDR, (char *)&ep2txr, 1, - USB_TIMEOUT_MS + USB_TIMEOUT_MS, + &transferred ); - if (usb_err < 0) + if (usb_err != ERROR_OK) return usb_err; usb_err = ep1_generic_commandl( @@ -447,17 +459,18 @@ static int dtc_start_download(void) return usb_err; /* wait for completion */ - usb_err = usb_bulk_read( + usb_err = jtag_libusb_bulk_read( pHDev, USB_EP1IN_ADDR, (char *)&ep2txr, 1, - USB_TIMEOUT_MS + USB_TIMEOUT_MS, + &transferred ); return usb_err; } static int dtc_run_download( - usb_dev_handle *pHDev_param, + libusb_device_handle *pHDev_param, uint8_t *command_buffer, int command_buffer_size, uint8_t *reply_buffer, @@ -467,14 +480,16 @@ static int dtc_run_download( char dtc_status; int usb_err; int i; + int transferred; LOG_DEBUG("%d/%d", command_buffer_size, reply_buffer_size); - usb_err = usb_bulk_write( + usb_err = jtag_libusb_bulk_write( pHDev_param, USB_EP2OUT_ADDR, (char *)command_buffer, USB_EP2BANK_SIZE, - USB_TIMEOUT_MS + USB_TIMEOUT_MS, + &transferred ); if (usb_err < 0) return usb_err; @@ -493,11 +508,12 @@ static int dtc_run_download( if (usb_err < 0) return usb_err; - usb_err = usb_bulk_read( + usb_err = jtag_libusb_bulk_read( pHDev_param, USB_EP1IN_ADDR, &dtc_status, 1, - USB_TIMEOUT_MS + USB_TIMEOUT_MS, + &transferred ); if (usb_err < 0) return usb_err; @@ -507,20 +523,21 @@ static int dtc_run_download( if (!--i) { LOG_ERROR("too many retries waiting for DTC status"); - return -ETIMEDOUT; + return LIBUSB_ERROR_TIMEOUT; } } if (reply_buffer && reply_buffer_size) { - usb_err = usb_bulk_read( + usb_err = jtag_libusb_bulk_read( pHDev_param, USB_EP2IN_ADDR, (char *)reply_buffer, reply_buffer_size, - USB_TIMEOUT_MS + USB_TIMEOUT_MS, + &transferred ); - if (usb_err < reply_buffer_size) { + if (usb_err != ERROR_OK || transferred < reply_buffer_size) { LOG_ERROR("Read of endpoint 2 returned %d, expected %d", usb_err, reply_buffer_size ); @@ -644,7 +661,7 @@ static int dtc_queue_run(void) reply_buffer, sizeof(reply_buffer) ); if (usb_err < 0) { - LOG_ERROR("dtc_run_download: %s", usb_strerror()); + LOG_ERROR("dtc_run_download: %s", libusb_error_name(usb_err)); exit(1); } @@ -919,6 +936,7 @@ static void rlink_reset(int trst, int srst) { uint8_t bitmap; int usb_err; + int transferred; /* Read port A for bit op */ usb_err = ep1_generic_commandl( @@ -929,17 +947,18 @@ static void rlink_reset(int trst, int srst) 1 ); if (usb_err < 0) { - LOG_ERROR("%s", usb_strerror()); + LOG_ERROR("%s", libusb_error_name(usb_err)); exit(1); } - usb_err = usb_bulk_read( + usb_err = jtag_libusb_bulk_read( pHDev, USB_EP1IN_ADDR, (char *)&bitmap, 1, - USB_TIMEOUT_MS + USB_TIMEOUT_MS, + &transferred ); - if (usb_err < 1) { - LOG_ERROR("%s", usb_strerror()); + if (usb_err != ERROR_OK || transferred < 1) { + LOG_ERROR("%s", libusb_error_name(usb_err)); exit(1); } @@ -964,17 +983,18 @@ static void rlink_reset(int trst, int srst) 1 ); if (usb_err < 0) { - LOG_ERROR("%s", usb_strerror()); + LOG_ERROR("%s", libusb_error_name(usb_err)); exit(1); } - usb_err = usb_bulk_read( + usb_err = jtag_libusb_bulk_read( pHDev, USB_EP1IN_ADDR, (char *)&bitmap, 1, - USB_TIMEOUT_MS + USB_TIMEOUT_MS, + &transferred ); - if (usb_err < 1) { - LOG_ERROR("%s", usb_strerror()); + if (usb_err != ERROR_OK || transferred < 1) { + LOG_ERROR("%s", libusb_error_name(usb_err)); exit(1); } @@ -994,17 +1014,18 @@ static void rlink_reset(int trst, int srst) EP1_CMD_DTC_GET_CACHED_STATUS ); if (usb_err < 0) { - LOG_ERROR("%s", usb_strerror()); + LOG_ERROR("%s", libusb_error_name(usb_err)); exit(1); } - usb_err = usb_bulk_read( + usb_err = jtag_libusb_bulk_read( pHDev, USB_EP1IN_ADDR, (char *)&bitmap, 1, - USB_TIMEOUT_MS + USB_TIMEOUT_MS, + &transferred ); - if (usb_err < 1) { - LOG_ERROR("%s", usb_strerror()); + if (usb_err != ERROR_OK || transferred < 1) { + LOG_ERROR("%s", libusb_error_name(usb_err)); exit(1); } } @@ -1391,8 +1412,9 @@ static int rlink_speed(int speed) exit(1); } - if (dtc_start_download() < 0) { - LOG_ERROR("starting DTC: %s", usb_strerror()); + int ret = dtc_start_download(); + if (ret < 0) { + LOG_ERROR("starting DTC: %s", libusb_error_name(ret)); exit(1); } @@ -1444,19 +1466,28 @@ static int rlink_init(void) { int i, j, retries; uint8_t reply_buffer[USB_EP1IN_SIZE]; + int transferred; - usb_init(); const uint16_t vids[] = { USB_IDVENDOR, 0 }; const uint16_t pids[] = { USB_IDPRODUCT, 0 }; - if (jtag_usb_open(vids, pids, &pHDev) != ERROR_OK) + if (jtag_libusb_open(vids, pids, NULL, &pHDev, NULL) != ERROR_OK) return ERROR_FAIL; - struct usb_device *dev = usb_device(pHDev); - if (dev->descriptor.bNumConfigurations > 1) { + struct libusb_device_descriptor descriptor; + struct libusb_device *usb_dev = libusb_get_device(pHDev); + int r = libusb_get_device_descriptor(usb_dev, &descriptor); + if (r < 0) { + LOG_ERROR("error %d getting device descriptor", r); + return ERROR_FAIL; + } + + if (descriptor.bNumConfigurations > 1) { LOG_ERROR("Whoops! NumConfigurations is not 1, don't know what to do..."); return ERROR_FAIL; } - if (dev->config->bNumInterfaces > 1) { + struct libusb_config_descriptor *config; + libusb_get_config_descriptor(usb_dev, 0, &config); + if (config->bNumInterfaces > 1) { LOG_ERROR("Whoops! NumInterfaces is not 1, don't know what to do..."); return ERROR_FAIL; } @@ -1464,29 +1495,27 @@ static int rlink_init(void) LOG_DEBUG("Opened device, pHDev = %p", pHDev); /* usb_set_configuration required under win32 */ - usb_set_configuration(pHDev, dev->config[0].bConfigurationValue); + libusb_set_configuration(pHDev, config->bConfigurationValue); retries = 3; do { - i = usb_claim_interface(pHDev, 0); - if (i) { - LOG_ERROR("usb_claim_interface: %s", usb_strerror()); -#ifdef LIBUSB_HAS_DETACH_KERNEL_DRIVER_NP - j = usb_detach_kernel_driver_np(pHDev, 0); - if (j) - LOG_ERROR("detach kernel driver: %s", usb_strerror()); -#endif + i = libusb_claim_interface(pHDev, 0); + if (i != LIBUSB_SUCCESS) { + LOG_ERROR("usb_claim_interface: %s", libusb_error_name(i)); + j = libusb_detach_kernel_driver(pHDev, 0); + if (j != LIBUSB_SUCCESS) + LOG_ERROR("detach kernel driver: %s", libusb_error_name(j)); } else { LOG_DEBUG("interface claimed!"); break; } } while (--retries); - if (i) { + if (i != LIBUSB_SUCCESS) { LOG_ERROR("Initialisation failed."); return ERROR_FAIL; } - if (usb_set_altinterface(pHDev, 0) != 0) { + if (libusb_set_interface_alt_setting(pHDev, 0, 0) != LIBUSB_SUCCESS) { LOG_ERROR("Failed to set interface."); return ERROR_FAIL; } @@ -1506,20 +1535,21 @@ static int rlink_init(void) EP1_CMD_GET_FWREV ); if (j < USB_EP1OUT_SIZE) { - LOG_ERROR("USB write error: %s", usb_strerror()); + LOG_ERROR("USB write error: %s", libusb_error_name(j)); return ERROR_FAIL; } - j = usb_bulk_read( + j = jtag_libusb_bulk_read( pHDev, USB_EP1IN_ADDR, (char *)reply_buffer, sizeof(reply_buffer), - 200 + 200, + &transferred ); - if (j != -ETIMEDOUT) + if (j != LIBUSB_ERROR_TIMEOUT) break; } - if (j < (int)sizeof(reply_buffer)) { - LOG_ERROR("USB read error: %s", usb_strerror()); + if (j != ERROR_OK || transferred != (int)sizeof(reply_buffer)) { + LOG_ERROR("USB read error: %s", libusb_error_name(j)); return ERROR_FAIL; } LOG_DEBUG(INTERFACE_NAME " firmware version: %d.%d.%d", @@ -1552,10 +1582,11 @@ static int rlink_init(void) ST7_PE_ADAPTER_SENSE_OUT ); - usb_bulk_read( + jtag_libusb_bulk_read( pHDev, USB_EP1IN_ADDR, (char *)reply_buffer, 1, - USB_TIMEOUT_MS + USB_TIMEOUT_MS, + &transferred ); if ((reply_buffer[0] & ST7_PE_ADAPTER_SENSE_IN) != 0) @@ -1576,10 +1607,11 @@ static int rlink_init(void) 0x00 /* OR */ ); - usb_bulk_read( + jtag_libusb_bulk_read( pHDev, USB_EP1IN_ADDR, (char *)reply_buffer, 1, - USB_TIMEOUT_MS + USB_TIMEOUT_MS, + &transferred ); @@ -1655,8 +1687,8 @@ static int rlink_quit(void) ~0 ); - usb_release_interface(pHDev, 0); - usb_close(pHDev); + libusb_release_interface(pHDev, 0); + libusb_close(pHDev); return ERROR_OK; } diff --git a/src/jtag/drivers/stlink_usb.c b/src/jtag/drivers/stlink_usb.c index a6d7c3a1b..a43ef8e96 100644 --- a/src/jtag/drivers/stlink_usb.c +++ b/src/jtag/drivers/stlink_usb.c @@ -1,4 +1,7 @@ /*************************************************************************** + * Copyright (C) 2020 by Tarek Bochkati * + * Tarek Bochkati * + * * * SWIM contributions by Ake Rehnman * * Copyright (C) 2017 Ake Rehnman * * ake.rehnman(at)gmail.com * @@ -43,6 +46,16 @@ #include +#include + +#ifdef HAVE_ARPA_INET_H +#include +#endif + +#ifdef HAVE_NETINET_TCP_H +#include +#endif + #include "libusb_helper.h" #ifdef HAVE_LIBUSB1 @@ -120,12 +133,48 @@ struct stlink_usb_version { uint32_t flags; }; -/** */ -struct stlink_usb_handle_s { +struct stlink_usb_priv_s { /** */ struct libusb_device_handle *fd; /** */ struct libusb_transfer *trans; +}; + +struct stlink_tcp_priv_s { + /** */ + int fd; + /** */ + bool connected; + /** */ + uint32_t device_id; + /** */ + uint32_t connect_id; + /** */ + uint8_t *send_buf; + /** */ + uint8_t *recv_buf; +}; + +struct stlink_backend_s { + /** */ + int (*open)(void *handle, struct hl_interface_param_s *param); + /** */ + int (*close)(void *handle); + /** */ + int (*xfer_noerrcheck)(void *handle, const uint8_t *buf, int size); + /** */ + int (*read_trace)(void *handle, const uint8_t *buf, int size); +}; + +/** */ +struct stlink_usb_handle_s { + /** */ + struct stlink_backend_s *backend; + /** */ + union { + struct stlink_usb_priv_s usb_backend_priv; + struct stlink_tcp_priv_s tcp_backend_priv; + }; /** */ uint8_t rx_ep; /** */ @@ -133,13 +182,13 @@ struct stlink_usb_handle_s { /** */ uint8_t trace_ep; /** */ - uint8_t cmdbuf[STLINK_SG_SIZE]; + uint8_t *cmdbuf; /** */ uint8_t cmdidx; /** */ uint8_t direction; /** */ - uint8_t databuf[STLINK_DATA_SIZE]; + uint8_t *databuf; /** */ uint32_t max_mem_packet; /** */ @@ -162,6 +211,26 @@ struct stlink_usb_handle_s { bool reconnect_pending; }; +/** */ +static inline int stlink_usb_open(void *handle, struct hl_interface_param_s *param) +{ + struct stlink_usb_handle_s *h = handle; + return h->backend->open(handle, param); +} + +/** */ +static inline int stlink_usb_close(void *handle) +{ + struct stlink_usb_handle_s *h = handle; + return h->backend->close(handle); +} +/** */ +static inline int stlink_usb_xfer_noerrcheck(void *handle, const uint8_t *buf, int size) +{ + struct stlink_usb_handle_s *h = handle; + return h->backend->xfer_noerrcheck(handle, buf, size); +} + #define STLINK_SWIM_ERR_OK 0x00 #define STLINK_SWIM_BUSY 0x01 #define STLINK_DEBUG_ERR_OK 0x80 @@ -307,6 +376,39 @@ struct stlink_usb_handle_s { #define REQUEST_SENSE 0x03 #define REQUEST_SENSE_LENGTH 18 +/* STLINK TCP commands */ +#define STLINK_TCP_CMD_REFRESH_DEVICE_LIST 0x00 +#define STLINK_TCP_CMD_GET_NB_DEV 0x01 +#define STLINK_TCP_CMD_GET_DEV_INFO 0x02 +#define STLINK_TCP_CMD_OPEN_DEV 0x03 +#define STLINK_TCP_CMD_CLOSE_DEV 0x04 +#define STLINK_TCP_CMD_SEND_USB_CMD 0x05 +#define STLINK_TCP_CMD_GET_SERVER_VERSION 0x06 +#define STLINK_TCP_CMD_GET_NB_OF_DEV_CLIENTS 0x07 + +/* STLINK TCP constants */ +#define OPENOCD_STLINK_TCP_API_VERSION 1 +#define STLINK_TCP_REQUEST_WRITE 0 +#define STLINK_TCP_REQUEST_READ 1 +#define STLINK_TCP_REQUEST_READ_SWO 3 +#define STLINK_TCP_SS_SIZE 4 +#define STLINK_TCP_USB_CMD_SIZE 32 +#define STLINK_TCP_SERIAL_SIZE 32 +#define STLINK_TCP_SEND_BUFFER_SIZE 10240 +#define STLINK_TCP_RECV_BUFFER_SIZE 10240 + +/* STLINK TCP command status */ +#define STLINK_TCP_SS_OK 0x00000001 +#define STLINK_TCP_SS_MEMORY_PROBLEM 0x00001000 +#define STLINK_TCP_SS_TIMEOUT 0x00001001 +#define STLINK_TCP_SS_BAD_PARAMETER 0x00001002 +#define STLINK_TCP_SS_OPEN_ERR 0x00001003 +#define STLINK_TCP_SS_TRUNCATED_DATA 0x00001052 +#define STLINK_TCP_SS_CMD_NOT_AVAILABLE 0x00001053 +#define STLINK_TCP_SS_TCP_ERROR 0x00002001 +#define STLINK_TCP_SS_TCP_CANT_CONNECT 0x00002002 +#define STLINK_TCP_SS_WIN32_ERROR 0x00010000 + /* * Map the relevant features, quirks and workaround for specific firmware * version of stlink @@ -381,8 +483,6 @@ static unsigned int stlink_usb_block(void *handle) return STLINK_MAX_RW8; } - - #ifdef USE_LIBUSB_ASYNCIO static LIBUSB_CALL void sync_transfer_cb(struct libusb_transfer *transfer) @@ -546,7 +646,7 @@ static int stlink_usb_xfer_v1_get_status(void *handle) /* read status */ memset(h->cmdbuf, 0, STLINK_SG_SIZE); - ret = jtag_libusb_bulk_read(h->fd, h->rx_ep, (char *)h->cmdbuf, 13, + ret = jtag_libusb_bulk_read(h->usb_backend_priv.fd, h->rx_ep, (char *)h->cmdbuf, 13, STLINK_READ_TIMEOUT, &tr); if (ret || tr != 13) return ERROR_FAIL; @@ -603,7 +703,7 @@ static int stlink_usb_xfer_rw(void *handle, int cmdsize, const uint8_t *buf, int } return jtag_libusb_bulk_transfer_n( - h->fd, + h->usb_backend_priv.fd, transfers, n_transfers, STLINK_WRITE_TIMEOUT); @@ -616,20 +716,20 @@ static int stlink_usb_xfer_rw(void *handle, int cmdsize, const uint8_t *buf, int assert(handle != NULL); - ret = jtag_libusb_bulk_write(h->fd, h->tx_ep, (char *)h->cmdbuf, + ret = jtag_libusb_bulk_write(h->usb_backend_priv.fd, h->tx_ep, (char *)h->cmdbuf, cmdsize, STLINK_WRITE_TIMEOUT, &tr); if (ret || tr != cmdsize) return ERROR_FAIL; if (h->direction == h->tx_ep && size) { - ret = jtag_libusb_bulk_write(h->fd, h->tx_ep, (char *)buf, + ret = jtag_libusb_bulk_write(h->usb_backend_priv.fd, h->tx_ep, (char *)buf, size, STLINK_WRITE_TIMEOUT, &tr); if (ret || tr != size) { LOG_DEBUG("bulk write failed"); return ERROR_FAIL; } } else if (h->direction == h->rx_ep && size) { - ret = jtag_libusb_bulk_read(h->fd, h->rx_ep, (char *)buf, + ret = jtag_libusb_bulk_read(h->usb_backend_priv.fd, h->rx_ep, (char *)buf, size, STLINK_READ_TIMEOUT, &tr); if (ret || tr != size) { LOG_DEBUG("bulk read failed"); @@ -668,13 +768,29 @@ static int stlink_usb_xfer_v1_get_sense(void *handle) return ERROR_OK; } +/** */ +static int stlink_usb_usb_read_trace(void *handle, const uint8_t *buf, int size) +{ + struct stlink_usb_handle_s *h = handle; + int tr, ret; + + ret = jtag_libusb_bulk_read(h->usb_backend_priv.fd, h->trace_ep, (char *)buf, size, + STLINK_READ_TIMEOUT, &tr); + if (ret || tr != size) { + LOG_ERROR("bulk trace read failed"); + return ERROR_FAIL; + } + + return ERROR_OK; +} + /* transfers block in cmdbuf indicates number of bytes in the following data phase. Ignore the (eventual) error code in the received packet. */ -static int stlink_usb_xfer_noerrcheck(void *handle, const uint8_t *buf, int size) +static int stlink_usb_usb_xfer_noerrcheck(void *handle, const uint8_t *buf, int size) { int err, cmdsize = STLINK_CMD_SIZE_V2; struct stlink_usb_handle_s *h = handle; @@ -707,6 +823,117 @@ static int stlink_usb_xfer_noerrcheck(void *handle, const uint8_t *buf, int size return ERROR_OK; } + +static int stlink_tcp_send_cmd(void *handle, int send_size, int recv_size, bool check_tcp_status) +{ + struct stlink_usb_handle_s *h = handle; + + assert(handle != NULL); + + /* send the TCP command */ + int sent_size = send(h->tcp_backend_priv.fd, (void *)h->tcp_backend_priv.send_buf, send_size, 0); + if (sent_size != send_size) { + LOG_ERROR("failed to send USB CMD"); + if (sent_size == -1) + LOG_DEBUG("socket send error: %s (errno %d)", strerror(errno), errno); + else + LOG_DEBUG("sent size %d (expected %d)", sent_size, send_size); + return ERROR_FAIL; + } + + keep_alive(); + + /* read the TCP response */ + int received_size = recv(h->tcp_backend_priv.fd, (void *)h->tcp_backend_priv.recv_buf, recv_size, 0); + if (received_size != recv_size) { + LOG_ERROR("failed to receive USB CMD response"); + if (received_size == -1) + LOG_DEBUG("socket recv error: %s (errno %d)", strerror(errno), errno); + else + LOG_DEBUG("received size %d (expected %d)", received_size, recv_size); + return ERROR_FAIL; + } + + if (check_tcp_status) { + uint32_t tcp_ss = le_to_h_u32(h->tcp_backend_priv.recv_buf); + if (tcp_ss != STLINK_TCP_SS_OK) { + LOG_ERROR("TCP error status 0x%X", tcp_ss); + return ERROR_FAIL; + } + } + + return ERROR_OK; +} + +/** */ +static int stlink_tcp_xfer_noerrcheck(void *handle, const uint8_t *buf, int size) +{ + struct stlink_usb_handle_s *h = handle; + + int send_size = STLINK_TCP_USB_CMD_SIZE; + int recv_size = STLINK_TCP_SS_SIZE; + + assert(handle != NULL); + + /* prepare the TCP command */ + h->tcp_backend_priv.send_buf[0] = STLINK_TCP_CMD_SEND_USB_CMD; + memset(&h->tcp_backend_priv.send_buf[1], 0, 3); /* reserved for alignment and future use, must be zero */ + h_u32_to_le(&h->tcp_backend_priv.send_buf[4], h->tcp_backend_priv.connect_id); + /* tcp_backend_priv.send_buf[8..23] already contains the constructed stlink command */ + h->tcp_backend_priv.send_buf[24] = h->direction; + memset(&h->tcp_backend_priv.send_buf[25], 0, 3); /* reserved for alignment and future use, must be zero */ + + h_u32_to_le(&h->tcp_backend_priv.send_buf[28], size); + + /* + * if the xfer is a write request (tx_ep) + * > then buf content will be copied + * into &cmdbuf[32]. + * else : the xfer is a read or trace read request (rx_ep or trace_ep) + * > the buf content will be filled from &databuf[4]. + * + * note : if h->direction is trace_ep, h->cmdbuf is zeros. + */ + + if (h->direction == h->tx_ep) { /* STLINK_TCP_REQUEST_WRITE */ + send_size += size; + if (send_size > STLINK_TCP_SEND_BUFFER_SIZE) { + LOG_ERROR("STLINK_TCP command buffer overflow"); + return ERROR_FAIL; + } + memcpy(&h->tcp_backend_priv.send_buf[32], buf, size); + } else { /* STLINK_TCP_REQUEST_READ or STLINK_TCP_REQUEST_READ_SWO */ + recv_size += size; + if (recv_size > STLINK_TCP_RECV_BUFFER_SIZE) { + LOG_ERROR("STLINK_TCP data buffer overflow"); + return ERROR_FAIL; + } + } + + int ret = stlink_tcp_send_cmd(h, send_size, recv_size, true); + if (ret != ERROR_OK) + return ret; + + if (h->direction != h->tx_ep) { + /* the read data is located in tcp_backend_priv.recv_buf[4] */ + /* most of the case it will be copying the data from tcp_backend_priv.recv_buf[4] + * to handle->cmd_buff which are the same, so let's avoid unnecessary copying */ + if (buf != &h->tcp_backend_priv.recv_buf[4]) + memcpy((uint8_t *)buf, &h->tcp_backend_priv.recv_buf[4], size); + } + + return ERROR_OK; +} + +/** */ +static int stlink_tcp_read_trace(void *handle, const uint8_t *buf, int size) +{ + struct stlink_usb_handle_s *h = handle; + + stlink_usb_init_buffer(h, h->trace_ep, 0); + return stlink_tcp_xfer_noerrcheck(handle, buf, size); +} + /** Converts an STLINK status code held in the first byte of a response to an openocd error, logs any error/wait status as debug output. @@ -853,20 +1080,12 @@ static int stlink_cmd_allow_retry(void *handle, const uint8_t *buf, int size) static int stlink_usb_read_trace(void *handle, const uint8_t *buf, int size) { struct stlink_usb_handle_s *h = handle; - int tr, ret; assert(handle != NULL); assert(h->version.flags & STLINK_F_HAS_TRACE); - ret = jtag_libusb_bulk_read(h->fd, h->trace_ep, (char *)buf, size, - STLINK_READ_TIMEOUT, &tr); - if (ret || tr != size) { - LOG_ERROR("bulk trace read failed"); - return ERROR_FAIL; - } - - return ERROR_OK; + return h->backend->read_trace(handle, buf, size); } /* @@ -1749,7 +1968,7 @@ static int stlink_usb_trace_read(void *handle, uint8_t *buf, size_t *size) return res; size_t bytes_avail = le_to_h_u16(h->databuf); - *size = bytes_avail < *size ? bytes_avail : *size - 1; + *size = bytes_avail < *size ? bytes_avail : *size; if (*size > 0) { res = stlink_usb_read_trace(handle, buf, *size); @@ -2716,18 +2935,68 @@ static int stlink_speed(void *handle, int khz, bool query) } /** */ -static int stlink_usb_close(void *handle) +static int stlink_usb_usb_close(void *handle) { struct stlink_usb_handle_s *h = handle; - if (h && h->fd) { + if (!h) + return ERROR_OK; + + if (h->usb_backend_priv.fd) { stlink_usb_exit_mode(h); /* do not check return code, it prevent us from closing jtag_libusb */ - jtag_libusb_close(h->fd); + jtag_libusb_close(h->usb_backend_priv.fd); } - free(h); + free(h->cmdbuf); + free(h->databuf); + + return ERROR_OK; +} + +/** */ +static int stlink_tcp_close(void *handle) +{ + struct stlink_usb_handle_s *h = handle; + + if (!h) + return ERROR_OK; + + int ret = ERROR_OK; + if (h->tcp_backend_priv.connected) { + if (h->tcp_backend_priv.connect_id) { + stlink_usb_exit_mode(h); + + /* close the stlink */ + h->tcp_backend_priv.send_buf[0] = STLINK_TCP_CMD_CLOSE_DEV; + memset(&h->tcp_backend_priv.send_buf[1], 0, 4); /* reserved */ + h_u32_to_le(&h->tcp_backend_priv.send_buf[4], h->tcp_backend_priv.connect_id); + ret = stlink_tcp_send_cmd(h, 8, 4, true); + if (ret != ERROR_OK) + LOG_ERROR("cannot close the STLINK"); + } + + if (close_socket(h->tcp_backend_priv.fd) != 0) + LOG_ERROR("error closing the socket, errno: %s", strerror(errno)); + } + + free(h->tcp_backend_priv.send_buf); + free(h->tcp_backend_priv.recv_buf); + + return ret; +} + +/** */ +static int stlink_close(void *handle) +{ + if (handle != NULL) { + struct stlink_usb_handle_s *h = handle; + + stlink_usb_close(handle); + + free(h); + } return ERROR_OK; } @@ -2812,27 +3081,16 @@ static char *stlink_usb_get_alternate_serial(libusb_device_handle *device, } /** */ -static int stlink_usb_open(struct hl_interface_param_s *param, enum stlink_mode mode, void **fd) +static int stlink_usb_usb_open(void *handle, struct hl_interface_param_s *param) { + struct stlink_usb_handle_s *h = handle; int err, retry_count = 1; - struct stlink_usb_handle_s *h; - LOG_DEBUG("stlink_usb_open"); + h->cmdbuf = malloc(STLINK_SG_SIZE); + h->databuf = malloc(STLINK_DATA_SIZE); - h = calloc(1, sizeof(struct stlink_usb_handle_s)); - - if (h == 0) { - LOG_DEBUG("malloc failed"); + if (h->cmdbuf == NULL || h->databuf == NULL) return ERROR_FAIL; - } - - h->st_mode = mode; - - for (unsigned i = 0; param->vid[i]; i++) { - LOG_DEBUG("transport: %d vid: 0x%04x pid: 0x%04x serial: %s", - h->st_mode, param->vid[i], param->pid[i], - param->serial ? param->serial : ""); - } /* On certain host USB configurations(e.g. MacBook Air) @@ -2845,25 +3103,25 @@ static int stlink_usb_open(struct hl_interface_param_s *param, enum stlink_mode */ do { if (jtag_libusb_open(param->vid, param->pid, param->serial, - &h->fd, stlink_usb_get_alternate_serial) != ERROR_OK) { + &h->usb_backend_priv.fd, stlink_usb_get_alternate_serial) != ERROR_OK) { LOG_ERROR("open failed"); - goto error_open; + return ERROR_FAIL; } - jtag_libusb_set_configuration(h->fd, 0); + jtag_libusb_set_configuration(h->usb_backend_priv.fd, 0); - if (libusb_claim_interface(h->fd, 0) != ERROR_OK) { + if (libusb_claim_interface(h->usb_backend_priv.fd, 0) != ERROR_OK) { LOG_DEBUG("claim interface failed"); - goto error_open; + return ERROR_FAIL; } /* RX EP is common for all versions */ h->rx_ep = STLINK_RX_EP; uint16_t pid; - if (jtag_libusb_get_pid(libusb_get_device(h->fd), &pid) != ERROR_OK) { + if (jtag_libusb_get_pid(libusb_get_device(h->usb_backend_priv.fd), &pid) != ERROR_OK) { LOG_DEBUG("libusb_get_pid failed"); - goto error_open; + return ERROR_FAIL; } /* wrap version for first read */ @@ -2903,21 +3161,21 @@ static int stlink_usb_open(struct hl_interface_param_s *param, enum stlink_mode } else if (h->version.stlink == 1 || retry_count == 0) { LOG_ERROR("read version failed"); - goto error_open; + return ERROR_FAIL; } else { - err = libusb_release_interface(h->fd, 0); + err = libusb_release_interface(h->usb_backend_priv.fd, 0); if (err != ERROR_OK) { LOG_ERROR("release interface failed"); - goto error_open; + return ERROR_FAIL; } - err = libusb_reset_device(h->fd); + err = libusb_reset_device(h->usb_backend_priv.fd); if (err != ERROR_OK) { LOG_ERROR("reset device failed"); - goto error_open; + return ERROR_FAIL; } - jtag_libusb_close(h->fd); + jtag_libusb_close(h->usb_backend_priv.fd); /* Give the device one second to settle down and reenumerate. @@ -2927,8 +3185,265 @@ static int stlink_usb_open(struct hl_interface_param_s *param, enum stlink_mode } } while (1); + return ERROR_OK; +} + +/** */ +static int stlink_tcp_open(void *handle, struct hl_interface_param_s *param) +{ + struct stlink_usb_handle_s *h = handle; + int ret; + + /* SWIM is not supported using stlink-server */ + if (h->st_mode == STLINK_MODE_DEBUG_SWIM) { + LOG_ERROR("stlink-server does not support SWIM mode"); + return ERROR_FAIL; + } + + h->tcp_backend_priv.send_buf = malloc(STLINK_TCP_SEND_BUFFER_SIZE); + h->tcp_backend_priv.recv_buf = malloc(STLINK_TCP_RECV_BUFFER_SIZE); + + if (h->tcp_backend_priv.send_buf == NULL || h->tcp_backend_priv.recv_buf == NULL) + return ERROR_FAIL; + + h->cmdbuf = &h->tcp_backend_priv.send_buf[8]; + h->databuf = &h->tcp_backend_priv.recv_buf[4]; + + /* configure directions */ + h->rx_ep = STLINK_TCP_REQUEST_READ; + h->tx_ep = STLINK_TCP_REQUEST_WRITE; + h->trace_ep = STLINK_TCP_REQUEST_READ_SWO; + + h->tcp_backend_priv.fd = socket(AF_INET, SOCK_STREAM, IPPROTO_TCP); + h->tcp_backend_priv.connected = false; + h->tcp_backend_priv.device_id = 0; + h->tcp_backend_priv.connect_id = 0; + + if (h->tcp_backend_priv.fd == -1) { + LOG_ERROR("error creating the socket, errno: %s", strerror(errno)); + return ERROR_FAIL; + } + + struct sockaddr_in serv; + memset(&serv, 0, sizeof(struct sockaddr_in)); + serv.sin_family = AF_INET; + serv.sin_port = htons(param->stlink_tcp_port); + serv.sin_addr.s_addr = inet_addr("127.0.0.1"); + + LOG_DEBUG("socket : %x", h->tcp_backend_priv.fd); + + int optval = 1; + if (setsockopt(h->tcp_backend_priv.fd, IPPROTO_TCP, TCP_NODELAY, (const void *)&optval, sizeof(int)) == -1) { + LOG_ERROR("cannot set sock option 'TCP_NODELAY', errno: %s", strerror(errno)); + return ERROR_FAIL; + } + + optval = STLINK_TCP_RECV_BUFFER_SIZE; + if (setsockopt(h->tcp_backend_priv.fd, SOL_SOCKET, SO_RCVBUF, (const void *)&optval, sizeof(int)) == -1) { + LOG_ERROR("cannot set sock option 'SO_RCVBUF', errno: %s", strerror(errno)); + return ERROR_FAIL; + } + + optval = STLINK_TCP_SEND_BUFFER_SIZE; + if (setsockopt(h->tcp_backend_priv.fd, SOL_SOCKET, SO_SNDBUF, (const void *)&optval, sizeof(int)) == -1) { + LOG_ERROR("cannot set sock option 'SO_SNDBUF', errno: %s", strerror(errno)); + return ERROR_FAIL; + } + + if (connect(h->tcp_backend_priv.fd, (const struct sockaddr *)&serv, sizeof(serv)) == -1) { + LOG_ERROR("cannot connect to stlink server, errno: %s", strerror(errno)); + return ERROR_FAIL; + } + + h->tcp_backend_priv.connected = true; + + LOG_INFO("connected to stlink-server"); + + /* print stlink-server version */ + h->tcp_backend_priv.send_buf[0] = STLINK_TCP_CMD_GET_SERVER_VERSION; + h->tcp_backend_priv.send_buf[1] = OPENOCD_STLINK_TCP_API_VERSION; + memset(&h->tcp_backend_priv.send_buf[2], 0, 2); /* reserved */ + ret = stlink_tcp_send_cmd(h, 4, 16, false); + if (ret != ERROR_OK) { + LOG_ERROR("cannot get the stlink-server version"); + return ERROR_FAIL; + } + + uint32_t api_ver = le_to_h_u32(&h->tcp_backend_priv.recv_buf[0]); + uint32_t ver_major = le_to_h_u32(&h->tcp_backend_priv.recv_buf[4]); + uint32_t ver_minor = le_to_h_u32(&h->tcp_backend_priv.recv_buf[8]); + uint32_t ver_build = le_to_h_u32(&h->tcp_backend_priv.recv_buf[12]); + LOG_INFO("stlink-server API v%d, version %d.%d.%d", + api_ver, ver_major, ver_minor, ver_build); + + /* in stlink-server API v1 sending more than 1428 bytes will cause stlink-server + * to crash in windows: select a safe default value (1K) */ + if (api_ver < 2) + h->max_mem_packet = (1 << 10); + + /* refresh stlink list (re-enumerate) */ + h->tcp_backend_priv.send_buf[0] = STLINK_TCP_CMD_REFRESH_DEVICE_LIST; + h->tcp_backend_priv.send_buf[1] = 0; /* don't clear the list, just refresh it */ + ret = stlink_tcp_send_cmd(h, 2, 4, true); + if (ret != ERROR_OK) + return ret; + + /* get the number of connected stlinks */ + h->tcp_backend_priv.send_buf[0] = STLINK_TCP_CMD_GET_NB_DEV; + ret = stlink_tcp_send_cmd(h, 1, 4, false); + if (ret != ERROR_OK) + return ret; + + uint32_t connected_stlinks = le_to_h_u32(h->tcp_backend_priv.recv_buf); + + if (connected_stlinks == 0) { + LOG_ERROR("no ST-LINK detected"); + return ERROR_FAIL; + } + + LOG_DEBUG("%d ST-LINK detected", connected_stlinks); + + if (connected_stlinks > 255) { + LOG_WARNING("STLink server cannot handle more than 255 ST-LINK connected"); + connected_stlinks = 255; + } + + /* list all connected ST-Link and seek for the requested vid:pid and serial */ + char serial[STLINK_TCP_SERIAL_SIZE + 1] = {0}; + uint8_t stlink_used; + bool stlink_id_matched = false; + bool stlink_serial_matched = (param->serial == NULL); + + for (uint32_t stlink_id = 0; stlink_id < connected_stlinks; stlink_id++) { + /* get the stlink info */ + h->tcp_backend_priv.send_buf[0] = STLINK_TCP_CMD_GET_DEV_INFO; + h->tcp_backend_priv.send_buf[1] = (uint8_t)stlink_id; + memset(&h->tcp_backend_priv.send_buf[2], 0, 2); /* reserved */ + h_u32_to_le(&h->tcp_backend_priv.send_buf[4], 41); /* size of TDeviceInfo2 */ + ret = stlink_tcp_send_cmd(h, 8, 45, true); + if (ret != ERROR_OK) + return ret; + + h->tcp_backend_priv.device_id = le_to_h_u32(&h->tcp_backend_priv.recv_buf[4]); + memcpy(serial, &h->tcp_backend_priv.recv_buf[8], STLINK_TCP_SERIAL_SIZE); + h->vid = le_to_h_u16(&h->tcp_backend_priv.recv_buf[40]); + h->pid = le_to_h_u16(&h->tcp_backend_priv.recv_buf[42]); + stlink_used = h->tcp_backend_priv.recv_buf[44]; + + /* check the vid:pid */ + for (int i = 0; param->vid[i]; i++) { + if (param->vid[i] == h->vid && param->pid[i] == h->pid) { + stlink_id_matched = true; + break; + } + } + + if (!stlink_id_matched) + continue; + + /* check the serial if specified */ + if (param->serial) { + /* ST-Link server fixes the buggy serial returned by old ST-Link DFU + * for further details refer to stlink_usb_get_alternate_serial + * so if the user passes the buggy serial, we need to fix it before + * comparing with the serial returned by ST-Link server */ + if (strlen(param->serial) == STLINK_SERIAL_LEN / 2) { + char fixed_serial[STLINK_SERIAL_LEN + 1]; + + for (unsigned int i = 0; i < STLINK_SERIAL_LEN; i += 2) + sprintf(fixed_serial + i, "%02X", param->serial[i / 2]); + + fixed_serial[STLINK_SERIAL_LEN] = '\0'; + + stlink_serial_matched = strcmp(fixed_serial, serial) == 0; + } else + stlink_serial_matched = strcmp(param->serial, serial) == 0; + } + + if (!stlink_serial_matched) + LOG_DEBUG("Device serial number '%s' doesn't match requested serial '%s'", + serial, param->serial); + else /* exit the search loop if there is match */ + break; + } + + if (!stlink_id_matched) { + LOG_ERROR("ST-LINK open failed (vid/pid mismatch)"); + return ERROR_FAIL; + } + + if (!stlink_serial_matched) { + LOG_ERROR("ST-LINK open failed (serial mismatch)"); + return ERROR_FAIL; + } + + /* check if device is 'exclusively' used by another application */ + if (stlink_used) { + LOG_ERROR("the selected device is already used"); + return ERROR_FAIL; + } + + LOG_DEBUG("transport: vid: 0x%04x pid: 0x%04x serial: %s", h->vid, h->pid, serial); + + /* now let's open the stlink */ + h->tcp_backend_priv.send_buf[0] = STLINK_TCP_CMD_OPEN_DEV; + memset(&h->tcp_backend_priv.send_buf[1], 0, 4); /* reserved */ + h_u32_to_le(&h->tcp_backend_priv.send_buf[4], h->tcp_backend_priv.device_id); + ret = stlink_tcp_send_cmd(h, 8, 8, true); + if (ret != ERROR_OK) + return ret; + + h->tcp_backend_priv.connect_id = le_to_h_u32(&h->tcp_backend_priv.recv_buf[4]); + + /* get stlink version */ + return stlink_usb_version(h); +} + +static struct stlink_backend_s stlink_usb_backend = { + .open = stlink_usb_usb_open, + .close = stlink_usb_usb_close, + .xfer_noerrcheck = stlink_usb_usb_xfer_noerrcheck, + .read_trace = stlink_usb_usb_read_trace, +}; + +static struct stlink_backend_s stlink_tcp_backend = { + .open = stlink_tcp_open, + .close = stlink_tcp_close, + .xfer_noerrcheck = stlink_tcp_xfer_noerrcheck, + .read_trace = stlink_tcp_read_trace, +}; + +static int stlink_open(struct hl_interface_param_s *param, enum stlink_mode mode, void **fd) +{ + struct stlink_usb_handle_s *h; + + LOG_DEBUG("stlink_open"); + + h = calloc(1, sizeof(struct stlink_usb_handle_s)); + + if (h == 0) { + LOG_DEBUG("malloc failed"); + return ERROR_FAIL; + } + + h->st_mode = mode; + + for (unsigned i = 0; param->vid[i]; i++) { + LOG_DEBUG("transport: %d vid: 0x%04x pid: 0x%04x serial: %s", + h->st_mode, param->vid[i], param->pid[i], + param->serial ? param->serial : ""); + } + + if (param->use_stlink_tcp) + h->backend = &stlink_tcp_backend; + else + h->backend = &stlink_usb_backend; + + if (stlink_usb_open(h, param) != ERROR_OK) + goto error_open; + /* check if mode is supported */ - err = ERROR_OK; + int err = ERROR_OK; switch (h->st_mode) { case STLINK_MODE_DEBUG_SWD: @@ -2972,37 +3487,39 @@ static int stlink_usb_open(struct hl_interface_param_s *param, enum stlink_mode return ERROR_OK; } - /* get cpuid, so we can determine the max page size - * start with a safe default */ - h->max_mem_packet = (1 << 10); + /* set max_mem_packet if it was not set by the low-level interface */ + if (h->max_mem_packet == 0) { + /* get cpuid, so we can determine the max page size + * start with a safe default */ + h->max_mem_packet = (1 << 10); - uint8_t buffer[4]; - stlink_usb_open_ap(h, 0); - err = stlink_usb_read_mem32(h, CPUID, 4, buffer); - if (err == ERROR_OK) { - uint32_t cpuid = le_to_h_u32(buffer); - int i = (cpuid >> 4) & 0xf; - if (i == 4 || i == 3) { - /* Cortex-M3/M4 has 4096 bytes autoincrement range */ - h->max_mem_packet = (1 << 12); + uint8_t buffer[4]; + stlink_usb_open_ap(h, 0); + err = stlink_usb_read_mem32(h, CPUID, 4, buffer); + if (err == ERROR_OK) { + uint32_t cpuid = le_to_h_u32(buffer); + int i = (cpuid >> 4) & 0xf; + if (i == 4 || i == 3) { + /* Cortex-M3/M4 has 4096 bytes autoincrement range */ + h->max_mem_packet = (1 << 12); + } } - } - LOG_DEBUG("Using TAR autoincrement: %" PRIu32, h->max_mem_packet); + LOG_DEBUG("Using TAR autoincrement: %" PRIu32, h->max_mem_packet); + } *fd = h; return ERROR_OK; error_open: - stlink_usb_close(h); - + stlink_close(h); return ERROR_FAIL; } static int stlink_usb_hl_open(struct hl_interface_param_s *param, void **fd) { - return stlink_usb_open(param, stlink_get_mode(param->transport), fd); + return stlink_open(param, stlink_get_mode(param->transport), fd); } static int stlink_config_trace(void *handle, bool enabled, @@ -3012,8 +3529,20 @@ static int stlink_config_trace(void *handle, bool enabled, { struct stlink_usb_handle_s *h = handle; - if (enabled && (!(h->version.flags & STLINK_F_HAS_TRACE) || - pin_protocol != TPIU_PIN_PROTOCOL_ASYNC_UART)) { + if (!(h->version.flags & STLINK_F_HAS_TRACE)) { + LOG_ERROR("The attached ST-LINK version doesn't support trace"); + return ERROR_FAIL; + } + + if (!enabled) { + stlink_usb_trace_disable(h); + return ERROR_OK; + } + + assert(trace_freq != NULL); + assert(prescaler != NULL); + + if (pin_protocol != TPIU_PIN_PROTOCOL_ASYNC_UART) { LOG_ERROR("The attached ST-LINK version doesn't support this trace mode"); return ERROR_FAIL; } @@ -3022,14 +3551,12 @@ static int stlink_config_trace(void *handle, bool enabled, STLINK_V3_TRACE_MAX_HZ : STLINK_TRACE_MAX_HZ; /* Only concern ourselves with the frequency if the STlink is processing it. */ - if (enabled && *trace_freq > max_trace_freq) { + if (*trace_freq > max_trace_freq) { LOG_ERROR("ST-LINK doesn't support SWO frequency higher than %u", max_trace_freq); return ERROR_FAIL; } - stlink_usb_trace_disable(h); - if (!*trace_freq) *trace_freq = max_trace_freq; @@ -3051,8 +3578,7 @@ static int stlink_config_trace(void *handle, bool enabled, *prescaler = presc; - if (!enabled) - return ERROR_OK; + stlink_usb_trace_disable(h); h->trace.source_hz = *trace_freq; @@ -3152,7 +3678,7 @@ struct hl_layout_api_s stlink_usb_layout_api = { /** */ .open = stlink_usb_hl_open, /** */ - .close = stlink_usb_close, + .close = stlink_close, /** */ .idcode = stlink_usb_idcode, /** */ @@ -3671,6 +4197,32 @@ COMMAND_HANDLER(stlink_dap_vid_pid) return ERROR_OK; } +/** */ +COMMAND_HANDLER(stlink_dap_backend_command) +{ + /* default values */ + bool use_stlink_tcp = false; + uint16_t stlink_tcp_port = 7184; + + if (CMD_ARGC == 0 || CMD_ARGC > 2) + return ERROR_COMMAND_SYNTAX_ERROR; + else if (strcmp(CMD_ARGV[0], "usb") == 0) { + if (CMD_ARGC > 1) + return ERROR_COMMAND_SYNTAX_ERROR; + /* else use_stlink_tcp = false (already the case ) */ + } else if (strcmp(CMD_ARGV[0], "tcp") == 0) { + use_stlink_tcp = true; + if (CMD_ARGC == 2) + COMMAND_PARSE_NUMBER(u16, CMD_ARGV[1], stlink_tcp_port); + } else + return ERROR_COMMAND_SYNTAX_ERROR; + + stlink_dap_param.use_stlink_tcp = use_stlink_tcp; + stlink_dap_param.stlink_tcp_port = stlink_tcp_port; + + return ERROR_OK; +} + /** */ static const struct command_registration stlink_dap_subcommand_handlers[] = { { @@ -3687,6 +4239,13 @@ static const struct command_registration stlink_dap_subcommand_handlers[] = { .help = "USB VID and PID of the adapter", .usage = "(vid pid)+", }, + { + .name = "backend", + .handler = &stlink_dap_backend_command, + .mode = COMMAND_CONFIG, + .help = "select which ST-Link backend to use", + .usage = "usb | tcp [port]", + }, COMMAND_REGISTRATION_DONE }; @@ -3729,7 +4288,7 @@ static int stlink_dap_init(void) return ERROR_FAIL; } - retval = stlink_usb_open(&stlink_dap_param, mode, (void **)&stlink_dap_handle); + retval = stlink_open(&stlink_dap_param, mode, (void **)&stlink_dap_handle); if (retval != ERROR_OK) return retval; @@ -3749,7 +4308,7 @@ static int stlink_dap_quit(void) free((void *)stlink_dap_param.serial); stlink_dap_param.serial = NULL; - return stlink_usb_close(stlink_dap_handle); + return stlink_close(stlink_dap_handle); } /** */ diff --git a/src/jtag/drivers/usb_blaster/ublast2_access_libusb.c b/src/jtag/drivers/usb_blaster/ublast2_access_libusb.c index 15028b7ea..d55bf85cd 100644 --- a/src/jtag/drivers/usb_blaster/ublast2_access_libusb.c +++ b/src/jtag/drivers/usb_blaster/ublast2_access_libusb.c @@ -134,13 +134,18 @@ static int load_usb_blaster_firmware(struct libusb_device_handle *libusb_dev, return ERROR_FAIL; } + if (libusb_claim_interface(libusb_dev, 0)) { + LOG_ERROR("unable to claim interface"); + return ERROR_JTAG_INIT_FAILED; + } + ublast2_firmware_image.base_address = 0; ublast2_firmware_image.base_address_set = false; int ret = image_open(&ublast2_firmware_image, low->firmware_path, "ihex"); if (ret != ERROR_OK) { LOG_ERROR("Could not load firmware image"); - return ret; + goto error_release_usb; } /** A host loader program must write 0x01 to the CPUCS register @@ -168,7 +173,7 @@ static int load_usb_blaster_firmware(struct libusb_device_handle *libusb_dev, &ublast2_firmware_image, i); if (ret != ERROR_OK) { LOG_ERROR("Error while downloading the firmware"); - return ret; + goto error_close_firmware; } } @@ -183,9 +188,18 @@ static int load_usb_blaster_firmware(struct libusb_device_handle *libusb_dev, 1, 100); +error_close_firmware: image_close(&ublast2_firmware_image); - return ERROR_OK; +error_release_usb: + /* + * Release claimed interface. Most probably it is already disconnected + * and re-enumerated as new devices after firmware upload, so we do + * not need to care about errors. + */ + libusb_release_interface(libusb_dev, 0); + + return ret; } static int ublast2_libusb_init(struct ublast_lowlevel *low) @@ -229,6 +243,12 @@ static int ublast2_libusb_init(struct ublast_lowlevel *low) } } + if (libusb_claim_interface(low->libusb_dev, 0)) { + LOG_ERROR("unable to claim interface"); + jtag_libusb_close(low->libusb_dev); + return ERROR_JTAG_INIT_FAILED; + } + char buffer[5]; jtag_libusb_control_transfer(low->libusb_dev, LIBUSB_REQUEST_TYPE_VENDOR | @@ -247,6 +267,9 @@ static int ublast2_libusb_init(struct ublast_lowlevel *low) static int ublast2_libusb_quit(struct ublast_lowlevel *low) { + if (libusb_release_interface(low->libusb_dev, 0)) + LOG_ERROR("usb release interface failed"); + jtag_libusb_close(low->libusb_dev); return ERROR_OK; }; diff --git a/src/jtag/drivers/usb_common.c b/src/jtag/drivers/usb_common.c deleted file mode 100644 index 1b7602d19..000000000 --- a/src/jtag/drivers/usb_common.c +++ /dev/null @@ -1,57 +0,0 @@ -/*************************************************************************** - * Copyright (C) 2009 by Zachary T Welch * - * * - * 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 . * - ***************************************************************************/ - -#ifdef HAVE_CONFIG_H -#include "config.h" -#endif -#include "usb_common.h" -#include "log.h" - - -static bool jtag_usb_match(struct usb_device *dev, - const uint16_t vids[], const uint16_t pids[]) -{ - for (unsigned i = 0; vids[i] && pids[i]; i++) { - if (dev->descriptor.idVendor == vids[i] && - dev->descriptor.idProduct == pids[i]) - return true; - } - return false; -} - -int jtag_usb_open(const uint16_t vids[], const uint16_t pids[], - struct usb_dev_handle **out) -{ - usb_find_busses(); - usb_find_devices(); - - struct usb_bus *busses = usb_get_busses(); - for (struct usb_bus *bus = busses; bus; bus = bus->next) { - for (struct usb_device *dev = bus->devices; dev; dev = dev->next) { - if (!jtag_usb_match(dev, vids, pids)) - continue; - - *out = usb_open(dev); - if (NULL == *out) { - LOG_ERROR("usb_open() failed with %s", usb_strerror()); - return ERROR_FAIL; - } - return ERROR_OK; - } - } - return ERROR_FAIL; -} diff --git a/src/jtag/drivers/usb_common.h b/src/jtag/drivers/usb_common.h deleted file mode 100644 index 4d2bd2686..000000000 --- a/src/jtag/drivers/usb_common.h +++ /dev/null @@ -1,26 +0,0 @@ -/*************************************************************************** - * Copyright (C) 2009 by Zachary T Welch * - * * - * 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 . * - ***************************************************************************/ - -#ifndef OPENOCD_JTAG_DRIVERS_USB_COMMON_H -#define OPENOCD_JTAG_DRIVERS_USB_COMMON_H - -#include - -int jtag_usb_open(const uint16_t vids[], const uint16_t pids[], - struct usb_dev_handle **out); - -#endif /* OPENOCD_JTAG_DRIVERS_USB_COMMON_H */ diff --git a/src/jtag/drivers/usbprog.c b/src/jtag/drivers/usbprog.c index 627e4653d..44db61ec0 100644 --- a/src/jtag/drivers/usbprog.c +++ b/src/jtag/drivers/usbprog.c @@ -34,7 +34,7 @@ #include #include -#include "usb_common.h" +#include "libusb_helper.h" #define VID 0x1781 #define PID 0x0c63 @@ -64,7 +64,7 @@ static void usbprog_scan(bool ir_scan, enum scan_type type, uint8_t *buffer, int #define WRITE_TMS_CHAIN 0x0A struct usbprog_jtag { - struct usb_dev_handle *usb_handle; + struct libusb_device_handle *usb_handle; }; static struct usbprog_jtag *usbprog_jtag_handle; @@ -350,21 +350,19 @@ struct usb_bus *busses; struct usbprog_jtag *usbprog_jtag_open(void) { - usb_set_debug(10); - usb_init(); - const uint16_t vids[] = { VID, 0 }; const uint16_t pids[] = { PID, 0 }; - struct usb_dev_handle *dev; - if (jtag_usb_open(vids, pids, &dev) != ERROR_OK) + struct libusb_device_handle *dev; + + if (jtag_libusb_open(vids, pids, NULL, &dev, NULL) != ERROR_OK) return NULL; struct usbprog_jtag *tmp = malloc(sizeof(struct usbprog_jtag)); tmp->usb_handle = dev; - usb_set_configuration(dev, 1); - usb_claim_interface(dev, 0); - usb_set_altinterface(dev, 0); + libusb_set_configuration(dev, 1); + libusb_claim_interface(dev, 0); + libusb_set_interface_alt_setting(dev, 0, 0); return tmp; } @@ -372,21 +370,23 @@ struct usbprog_jtag *usbprog_jtag_open(void) #if 0 static void usbprog_jtag_close(struct usbprog_jtag *usbprog_jtag) { - usb_close(usbprog_jtag->usb_handle); + libusb_close(usbprog_jtag->usb_handle); free(usbprog_jtag); } #endif static unsigned char usbprog_jtag_message(struct usbprog_jtag *usbprog_jtag, char *msg, int msglen) { - int res = usb_bulk_write(usbprog_jtag->usb_handle, 3, msg, msglen, 100); + int transferred; + + int res = jtag_libusb_bulk_write(usbprog_jtag->usb_handle, 3, msg, msglen, 100, &transferred); if ((msg[0] == 2) || (msg[0] == 1) || (msg[0] == 4) || (msg[0] == 0) || (msg[0] == 6) || (msg[0] == 0x0A) || (msg[0] == 9)) return 1; - if (res == msglen) { + if (res == ERROR_OK && transferred == msglen) { /* LOG_INFO("HALLLLOOO %i",(int)msg[0]); */ - res = usb_bulk_read(usbprog_jtag->usb_handle, 0x82, msg, 2, 100); - if (res > 0) + res = jtag_libusb_bulk_read(usbprog_jtag->usb_handle, 0x82, msg, 2, 100, &transferred); + if (res == ERROR_OK && transferred > 0) return (unsigned char)msg[1]; else return -1; @@ -428,11 +428,13 @@ static void usbprog_jtag_write_and_read(struct usbprog_jtag *usbprog_jtag, char bufindex++; } - if (usb_bulk_write(usbprog_jtag->usb_handle, 3, tmp, 64, 1000) == 64) { + int transferred; + int res = jtag_libusb_bulk_write(usbprog_jtag->usb_handle, 3, tmp, 64, 1000, &transferred); + if (res == ERROR_OK && transferred == 64) { /* LOG_INFO("HALLLLOOO2 %i",(int)tmp[0]); */ usleep(1); int timeout = 0; - while (usb_bulk_read(usbprog_jtag->usb_handle, 0x82, tmp, 64, 1000) < 1) { + while (jtag_libusb_bulk_read(usbprog_jtag->usb_handle, 0x82, tmp, 64, 1000, &transferred) != ERROR_OK) { timeout++; if (timeout > 10) break; @@ -469,12 +471,13 @@ static void usbprog_jtag_read_tdo(struct usbprog_jtag *usbprog_jtag, char *buffe tmp[1] = (char)(send_bits >> 8); /* high */ tmp[2] = (char)(send_bits); /* low */ - usb_bulk_write(usbprog_jtag->usb_handle, 3, tmp, 3, 1000); + int transferred; + jtag_libusb_bulk_write(usbprog_jtag->usb_handle, 3, tmp, 3, 1000, &transferred); /* LOG_INFO("HALLLLOOO3 %i",(int)tmp[0]); */ int timeout = 0; usleep(1); - while (usb_bulk_read(usbprog_jtag->usb_handle, 0x82, tmp, 64, 10) < 1) { + while (jtag_libusb_bulk_read(usbprog_jtag->usb_handle, 0x82, tmp, 64, 10, &transferred) != ERROR_OK) { timeout++; if (timeout > 10) break; @@ -513,7 +516,8 @@ static void usbprog_jtag_write_tdi(struct usbprog_jtag *usbprog_jtag, char *buff tmp[3 + i] = buffer[bufindex]; bufindex++; } - usb_bulk_write(usbprog_jtag->usb_handle, 3, tmp, 64, 1000); + int transferred; + jtag_libusb_bulk_write(usbprog_jtag->usb_handle, 3, tmp, 64, 1000, &transferred); } } @@ -582,15 +586,15 @@ static void usbprog_jtag_tms_collect(char tms_scan) static void usbprog_jtag_tms_send(struct usbprog_jtag *usbprog_jtag) { - int i; /* LOG_INFO("TMS SEND"); */ if (tms_chain_index > 0) { char tmp[tms_chain_index + 2]; tmp[0] = WRITE_TMS_CHAIN; tmp[1] = (char)(tms_chain_index); - for (i = 0; i < tms_chain_index + 1; i++) + for (int i = 0; i < tms_chain_index + 1; i++) tmp[2 + i] = tms_chain[i]; - usb_bulk_write(usbprog_jtag->usb_handle, 3, tmp, tms_chain_index + 2, 1000); + int transferred; + jtag_libusb_bulk_write(usbprog_jtag->usb_handle, 3, tmp, tms_chain_index + 2, 1000, &transferred); tms_chain_index = 0; } } diff --git a/src/jtag/hla/hla_interface.c b/src/jtag/hla/hla_interface.c index 6691a9a32..04e01d252 100644 --- a/src/jtag/hla/hla_interface.c +++ b/src/jtag/hla/hla_interface.c @@ -35,7 +35,7 @@ #include -static struct hl_interface_s hl_if = { {0, 0, { 0 }, { 0 }, HL_TRANSPORT_UNKNOWN, false, -1}, 0, 0 }; +static struct hl_interface_s hl_if = { {0, 0, { 0 }, { 0 }, HL_TRANSPORT_UNKNOWN, false, -1, false, 7184}, 0, 0 }; int hl_interface_open(enum hl_transports tr) { @@ -292,6 +292,31 @@ COMMAND_HANDLER(hl_interface_handle_vid_pid_command) return ERROR_OK; } +COMMAND_HANDLER(hl_interface_handle_stlink_backend_command) +{ + /* default values */ + bool use_stlink_tcp = false; + uint16_t stlink_tcp_port = 7184; + + if (CMD_ARGC == 0 || CMD_ARGC > 2) + return ERROR_COMMAND_SYNTAX_ERROR; + else if (strcmp(CMD_ARGV[0], "usb") == 0) { + if (CMD_ARGC > 1) + return ERROR_COMMAND_SYNTAX_ERROR; + /* else use_stlink_tcp = false (already the case ) */ + } else if (strcmp(CMD_ARGV[0], "tcp") == 0) { + use_stlink_tcp = true; + if (CMD_ARGC == 2) + COMMAND_PARSE_NUMBER(u16, CMD_ARGV[1], stlink_tcp_port); + } else + return ERROR_COMMAND_SYNTAX_ERROR; + + hl_if.param.use_stlink_tcp = use_stlink_tcp; + hl_if.param.stlink_tcp_port = stlink_tcp_port; + + return ERROR_OK; +} + COMMAND_HANDLER(interface_handle_hla_command) { if (CMD_ARGC != 1) @@ -336,6 +361,13 @@ static const struct command_registration hl_interface_command_handlers[] = { .help = "the vendor and product ID of the adapter", .usage = "(vid pid)* ", }, + { + .name = "hla_stlink_backend", + .handler = &hl_interface_handle_stlink_backend_command, + .mode = COMMAND_CONFIG, + .help = "select which ST-Link backend to use", + .usage = "usb | tcp [port]", + }, { .name = "hla_command", .handler = &interface_handle_hla_command, diff --git a/src/jtag/hla/hla_interface.h b/src/jtag/hla/hla_interface.h index b6e4a8b92..a1c95cde1 100644 --- a/src/jtag/hla/hla_interface.h +++ b/src/jtag/hla/hla_interface.h @@ -46,6 +46,10 @@ struct hl_interface_param_s { bool connect_under_reset; /** Initial interface clock clock speed */ int initial_interface_speed; + /** */ + bool use_stlink_tcp; + /** */ + uint16_t stlink_tcp_port; }; struct hl_interface_s { diff --git a/src/jtag/interface.h b/src/jtag/interface.h index 0884868a8..58bfd02b0 100644 --- a/src/jtag/interface.h +++ b/src/jtag/interface.h @@ -27,7 +27,7 @@ #include #include -#include +#include /* @file * The "Cable Helper API" is what the cable drivers can use to help diff --git a/src/jtag/interfaces.c b/src/jtag/interfaces.c index 061a78f9c..63faa9561 100644 --- a/src/jtag/interfaces.c +++ b/src/jtag/interfaces.c @@ -42,11 +42,6 @@ * that contain an adapter_driver structure that can added to this list. */ -#if BUILD_ZY1000 == 1 -extern struct adapter_driver zy1000_adapter_driver; -#elif defined(BUILD_MINIDRIVER_DUMMY) -extern struct adapter_driver minidummy_adapter_driver; -#else /* standard drivers */ #if BUILD_PARPORT == 1 extern struct adapter_driver parport_adapter_driver; #endif @@ -152,21 +147,12 @@ extern struct adapter_driver stlink_dap_adapter_driver; #if BUILD_RSHIM == 1 extern struct adapter_driver rshim_dap_adapter_driver; #endif -#endif /* standard drivers */ /** * The list of built-in JTAG interfaces, containing entries for those * drivers that were enabled by the @c configure script. - * - * The list should be defined to contain either one minidriver interface - * or some number of standard driver interfaces, never both. */ struct adapter_driver *adapter_drivers[] = { -#if BUILD_ZY1000 == 1 - &zy1000_adapter_driver, -#elif defined(BUILD_MINIDRIVER_DUMMY) - &minidummy_adapter_driver, -#else /* standard drivers */ #if BUILD_PARPORT == 1 &parport_adapter_driver, #endif @@ -272,6 +258,5 @@ struct adapter_driver *adapter_drivers[] = { #if BUILD_RSHIM == 1 &rshim_dap_adapter_driver, #endif -#endif /* standard drivers */ NULL, }; diff --git a/src/jtag/jtag.h b/src/jtag/jtag.h index cc403df46..feb4614fa 100644 --- a/src/jtag/jtag.h +++ b/src/jtag/jtag.h @@ -47,15 +47,6 @@ typedef enum tap_state { TAP_INVALID = -1, -#if BUILD_ZY1000 - /* These are the old numbers. Leave as-is for now... */ - TAP_RESET = 0, TAP_IDLE = 8, - TAP_DRSELECT = 1, TAP_DRCAPTURE = 2, TAP_DRSHIFT = 3, TAP_DREXIT1 = 4, - TAP_DRPAUSE = 5, TAP_DREXIT2 = 6, TAP_DRUPDATE = 7, - TAP_IRSELECT = 9, TAP_IRCAPTURE = 10, TAP_IRSHIFT = 11, TAP_IREXIT1 = 12, - TAP_IRPAUSE = 13, TAP_IREXIT2 = 14, TAP_IRUPDATE = 15, - -#else /* Proper ARM recommended numbers */ TAP_DREXIT2 = 0x0, TAP_DREXIT1 = 0x1, @@ -73,8 +64,6 @@ typedef enum tap_state { TAP_IRUPDATE = 0xd, TAP_IRCAPTURE = 0xe, TAP_RESET = 0x0f, - -#endif } tap_state_t; /** @@ -636,9 +625,6 @@ bool jtag_poll_get_enabled(void); */ void jtag_poll_set_enabled(bool value); - -/* The minidriver may have inline versions of some of the low - * level APIs that are used in inner loops. */ #include int jim_jtag_newtap(Jim_Interp *interp, int argc, Jim_Obj *const *argv); diff --git a/src/jtag/minidriver.h b/src/jtag/minidriver.h index ad830cc13..c6fdfafd3 100644 --- a/src/jtag/minidriver.h +++ b/src/jtag/minidriver.h @@ -45,7 +45,7 @@ /* this header will be provided by the minidriver implementation, */ /* and it may provide additional declarations that must be defined. */ -#include +#include int interface_jtag_add_ir_scan(struct jtag_tap *active, const struct scan_field *fields, diff --git a/src/jtag/minidriver/minidriver_imp.h b/src/jtag/minidriver/minidriver_imp.h deleted file mode 100644 index 11d0fae72..000000000 --- a/src/jtag/minidriver/minidriver_imp.h +++ /dev/null @@ -1,30 +0,0 @@ -/*************************************************************************** - * Copyright (C) 2005 by Dominic Rath * - * Copyright (C) 2007,2008 Øyvind Harboe * - * Copyright (C) 2009 Zachary T Welch * - * * - * 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 . * - ***************************************************************************/ - -#ifndef OPENOCD_JTAG_MINIDRIVER_MINIDRIVER_IMP_H -#define OPENOCD_JTAG_MINIDRIVER_MINIDRIVER_IMP_H - -#include - -#define jtag_add_callback(callback, in) interface_jtag_add_callback(callback, in) - -#define jtag_add_callback4(callback, in, data1, data2, data3) \ - interface_jtag_add_callback4(callback, in, data1, data2, data3) - -#endif /* OPENOCD_JTAG_MINIDRIVER_MINIDRIVER_IMP_H */ diff --git a/src/jtag/minidummy/jtag_minidriver.h b/src/jtag/minidummy/jtag_minidriver.h deleted file mode 100644 index 1708356a5..000000000 --- a/src/jtag/minidummy/jtag_minidriver.h +++ /dev/null @@ -1,21 +0,0 @@ -/*************************************************************************** - * Copyright (C) 2007-2008 by Øyvind Harboe * - * * - * 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 . * - ***************************************************************************/ - -#define interface_jtag_add_callback(callback, in) callback(in) - -#define interface_jtag_add_callback4(callback, in, data1, data2, data3) \ - jtag_set_error(callback(in, data1, data2, data3)) diff --git a/src/jtag/minidummy/minidummy.c b/src/jtag/minidummy/minidummy.c deleted file mode 100644 index 7ee206732..000000000 --- a/src/jtag/minidummy/minidummy.c +++ /dev/null @@ -1,176 +0,0 @@ -/*************************************************************************** - * Copyright (C) 2007-2008 by Øyvind Harboe * - * * - * 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 . * - ***************************************************************************/ - -#ifdef HAVE_CONFIG_H -#include "config.h" -#endif - -#include -#include -#include -#include - -static struct jtag_interface minidummy_interface = { - .execute_queue = NULL, -}; - -struct adapter_driver minidummy_adapter_driver = { - .name = "minidummy", - .transports = jtag_only, - .commands = NULL, - - .init = NULL, - .quit = NULL, - .speed = NULL, - .khz = NULL, - .speed_div = NULL, - .power_dropout = NULL, - .srst_asserted = NULL, - - .jtag_ops = &minidummy_interface, -}; - -int interface_jtag_execute_queue(void) -{ - /* synchronously do the operation here */ - - return ERROR_OK; -} - -int interface_jtag_add_ir_scan(struct jtag_tap *active, const struct scan_field *fields, - tap_state_t state) -{ - /* synchronously do the operation here */ - - return ERROR_OK; -} - -int interface_jtag_add_plain_ir_scan(int num_bits, const uint8_t *out_bits, - uint8_t *in_bits, tap_state_t state) -{ - /* synchronously do the operation here */ - - return ERROR_OK; -} - -int interface_jtag_add_dr_scan(struct jtag_tap *active, int num_fields, - const struct scan_field *fields, tap_state_t state) -{ - /* synchronously do the operation here */ - - return ERROR_OK; -} - -int interface_jtag_add_plain_dr_scan(int num_bits, const uint8_t *out_bits, - uint8_t *in_bits, tap_state_t state) -{ - /* synchronously do the operation here */ - - return ERROR_OK; -} - -int interface_jtag_add_tlr(void) -{ - /* synchronously do the operation here */ - - return ERROR_OK; -} - -int interface_jtag_add_reset(int req_trst, int req_srst) -{ - /* synchronously do the operation here */ - - return ERROR_OK; -} - -int interface_jtag_add_runtest(int num_cycles, tap_state_t state) -{ - /* synchronously do the operation here */ - - return ERROR_OK; -} - -int interface_jtag_add_clocks(int num_cycles) -{ - /* synchronously do the operation here */ - - return ERROR_OK; -} - -int interface_jtag_add_sleep(uint32_t us) -{ - jtag_sleep(us); - return ERROR_OK; -} - -int interface_jtag_add_pathmove(int num_states, const tap_state_t *path) -{ - int state_count; - int tms = 0; - - state_count = 0; - - tap_state_t cur_state = cmd_queue_cur_state; - - while (num_states) { - if (tap_state_transition(cur_state, false) == path[state_count]) - tms = 0; - else if (tap_state_transition(cur_state, true) == path[state_count]) - tms = 1; - else { - LOG_ERROR("BUG: %s -> %s isn't a valid TAP transition", - tap_state_name(cur_state), tap_state_name(path[state_count])); - exit(-1); - } - - /* synchronously do the operation here */ - - cur_state = path[state_count]; - state_count++; - num_states--; - } - - - /* synchronously do the operation here */ - - return ERROR_OK; -} - -int interface_add_tms_seq(unsigned num_bits, const uint8_t *seq, enum tap_state state) -{ - /* synchronously do the operation here */ - - return ERROR_OK; -} - -void embeddedice_write_dcc(struct jtag_tap *tap, int reg_addr, const uint8_t *buffer, - int little, int count) -{ - int i; - for (i = 0; i < count; i++) { - embeddedice_write_reg_inner(tap, reg_addr, fast_target_buffer_get_u32(buffer, little)); - buffer += 4; - } -} - -int arm11_run_instr_data_to_core_noack_inner(struct jtag_tap *tap, uint32_t opcode, - uint32_t *data, size_t count) -{ - int arm11_run_instr_data_to_core_noack_inner_default(struct jtag_tap *tap, - uint32_t opcode, uint32_t *data, size_t count); - return arm11_run_instr_data_to_core_noack_inner_default(tap, opcode, data, count); -} diff --git a/src/jtag/startup.tcl b/src/jtag/startup.tcl index 82327a39b..f1e69e591 100644 --- a/src/jtag/startup.tcl +++ b/src/jtag/startup.tcl @@ -29,7 +29,7 @@ proc init_reset { mode } { ######### # TODO: power_restore and power_dropout are currently neither -# documented nor supported except on ZY1000. +# documented nor supported. proc power_restore {} { echo "Sensed power restore, running reset init and halting GDB." @@ -55,7 +55,7 @@ proc power_dropout {} { ######### # TODO: srst_deasserted and srst_asserted are currently neither -# documented nor supported except on ZY1000. +# documented nor supported. proc srst_deasserted {} { echo "Sensed nSRST deasserted, running reset init and halting GDB." @@ -117,23 +117,8 @@ proc jtag_ntrst_assert_width args { # JTAG-specific names despite the fact that the operations were not # specific to JTAG, or otherwise had troublesome/misleading names. # -# FIXME phase these aids out after about April 2011 +# FIXME phase these aids out after some releases # -proc jtag_khz args { - echo "DEPRECATED! use 'adapter speed' not 'jtag_khz'" - eval adapter speed $args -} - -proc jtag_nsrst_delay args { - echo "DEPRECATED! use 'adapter srst delay' not 'jtag_nsrst_delay'" - eval adapter srst delay $args -} - -proc jtag_nsrst_assert_width args { - echo "DEPRECATED! use 'adapter srst pulse_width' not 'jtag_nsrst_assert_width'" - eval adapter srst pulse_width $args -} - proc jtag_reset args { echo "DEPRECATED! use 'adapter \[de\]assert' not 'jtag_reset'" switch $args { @@ -150,32 +135,6 @@ proc jtag_reset args { } } -# stlink migration helpers -proc stlink_device_desc args { - echo "DEPRECATED! use 'hla_device_desc' not 'stlink_device_desc'" - eval hla_device_desc $args -} - -proc stlink_serial args { - echo "DEPRECATED! use 'hla_serial' not 'stlink_serial'" - eval hla_serial $args -} - -proc stlink_layout args { - echo "DEPRECATED! use 'hla_layout' not 'stlink_layout'" - eval hla_layout $args -} - -proc stlink_vid_pid args { - echo "DEPRECATED! use 'hla_vid_pid' not 'stlink_vid_pid'" - eval hla_vid_pid $args -} - -proc stlink args { - echo "DEPRECATED! use 'hla' not 'stlink'" - eval hla $args -} - proc adapter_khz args { echo "DEPRECATED! use 'adapter speed' not 'adapter_khz'" eval adapter speed $args diff --git a/src/jtag/zy1000/jtag_minidriver.h b/src/jtag/zy1000/jtag_minidriver.h deleted file mode 100644 index 7d1ede5d4..000000000 --- a/src/jtag/zy1000/jtag_minidriver.h +++ /dev/null @@ -1,182 +0,0 @@ -/*************************************************************************** - * Copyright (C) 2007-2010 by Øyvind Harboe * - * * - * 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 . * - ***************************************************************************/ - -/* used to test manual mode */ -#define TEST_MANUAL() 0 -#define VERBOSE(a) - -#if BUILD_ZY1000_MASTER - -#define ZY1000_PEEK(a, b) do {b = *((volatile uint32_t *)(a)); } while (0) -#define ZY1000_POKE(a, b) do {*((volatile uint32_t *)(a)) = b; } while (0) -extern volatile void *zy1000_jtag_master; -#define ZY1000_JTAG_BASE ((unsigned long)zy1000_jtag_master) - -#else - -/* redirect this to TCP/IP */ -#define ZY1000_JTAG_BASE 0 -extern void zy1000_tcpout(uint32_t address, uint32_t data); -extern uint32_t zy1000_tcpin(uint32_t address); -#define ZY1000_PEEK(a, b) b = zy1000_tcpin(a) -#define ZY1000_POKE(a, b) zy1000_tcpout(a, b) - -#endif - -#if BUILD_ZY1000_MASTER -/* FIFO empty? */ -static inline void waitIdle(void) -{ - uint32_t empty; - do { - ZY1000_PEEK(ZY1000_JTAG_BASE + 0x10, empty); - } while ((empty & 0x100) == 0); -} - -static inline void zy1000_flush_readqueue(void) -{ - /* Not used w/hardware fifo */ -} -static inline void zy1000_flush_callbackqueue(void) -{ - /* Not used w/hardware fifo */ -} -#else -extern void waitIdle(void); -void zy1000_flush_readqueue(void); -void zy1000_flush_callbackqueue(void); -void zy1000_jtag_add_callback4(jtag_callback_t callback, - jtag_callback_data_t data0, - jtag_callback_data_t data1, - jtag_callback_data_t data2, - jtag_callback_data_t data3); -void zy1000_jtag_add_callback(jtag_callback1_t callback, jtag_callback_data_t data0); -#endif - -static inline void waitQueue(void) -{ -/* waitIdle(); */ -} - -static inline void sampleShiftRegister(void) -{ -#if 0 - uint32_t dummy; - waitIdle(); - ZY1000_PEEK(ZY1000_JTAG_BASE + 0xc, dummy); -#endif -} - -static inline void setCurrentState(enum tap_state state) -{ - uint32_t a; - a = state; - int repeat = 0; - if (state == TAP_RESET) { - /* The FPGA nor we know the current state of the CPU TAP */ - /* controller. This will move it to TAP for sure. */ - /* */ - /* 5 should be enough here, 7 is what OpenOCD uses */ - repeat = 7; - } - waitQueue(); - sampleShiftRegister(); - ZY1000_POKE(ZY1000_JTAG_BASE + 0x8, (repeat << 8) | (a << 4) | a); - -} - -/* - * Enter state and cause repeat transitions *out* of that state. So if the endState != state, then - * the transition from state to endState counts as a transition out of state. - */ -static inline void shiftValueInner(const enum tap_state state, - const enum tap_state endState, - int repeat, - uint32_t value) -{ - uint32_t a, b; - a = state; - b = endState; - waitQueue(); - sampleShiftRegister(); - ZY1000_POKE(ZY1000_JTAG_BASE + 0xc, value); -#if 1 -#if TEST_MANUAL() - if ((state == TAP_DRSHIFT) && (endState != TAP_DRSHIFT)) { - int i; - setCurrentState(state); - for (i = 0; i < repeat; i++) { - int tms; - tms = 0; - if ((i == repeat-1) && (state != endState)) - tms = 1; - /* shift out value */ - waitIdle(); - ZY1000_POKE(ZY1000_JTAG_BASE + 0x28, (((value >> i)&1) << 1) | tms); - } - waitIdle(); - ZY1000_POKE(ZY1000_JTAG_BASE + 0x28, 0); - waitIdle(); - /* ZY1000_POKE(ZY1000_JTAG_BASE + 0x20, TAP_DRSHIFT); // set this state and things - * break => expected */ - ZY1000_POKE(ZY1000_JTAG_BASE + 0x20, TAP_DRPAUSE); /* set this and things will - * work => expected. Not - * setting this is not - * sufficient to make things - * break. */ - setCurrentState(endState); - } else - ZY1000_POKE(ZY1000_JTAG_BASE + 0x8, (repeat << 8) | (a << 4) | b); - -#else - /* fast version */ - ZY1000_POKE(ZY1000_JTAG_BASE + 0x8, (repeat << 8) | (a << 4) | b); -#endif -#else - /* maximum debug version */ - if ((repeat > 0) && ((state == TAP_DRSHIFT) || (state == TAP_SI))) { - int i; - /* sample shift register for every bit. */ - for (i = 0; i < repeat-1; i++) { - sampleShiftRegister(); - ZY1000_POKE(ZY1000_JTAG_BASE + 0xc, value >> i); - ZY1000_POKE(ZY1000_JTAG_BASE + 0x8, (1 << 8) | (a << 4) | a); - } - sampleShiftRegister(); - ZY1000_POKE(ZY1000_JTAG_BASE + 0xc, value >> (repeat-1)); - ZY1000_POKE(ZY1000_JTAG_BASE + 0x8, (1 << 8) | (a << 4) | b); - } else { - sampleShiftRegister(); - ZY1000_POKE(ZY1000_JTAG_BASE + 0x8, (repeat << 8) | (a << 4) | b); - } - sampleShiftRegister(); -#endif -} - -#if BUILD_ZY1000_MASTER -#define interface_jtag_add_callback(callback, in) callback(in) -#define interface_jtag_add_callback4(callback, in, data1, data2, \ - data3) jtag_set_error(callback(in, data1, data2, data3)) -#else -#define interface_jtag_add_callback(callback, in) zy1000_jtag_add_callback(callback, in) -#define interface_jtag_add_callback4(callback, in, data1, data2, data3) zy1000_jtag_add_callback4( \ - callback, \ - in, \ - data1, \ - data2, \ - data3) -#endif diff --git a/src/jtag/zy1000/zy1000.c b/src/jtag/zy1000/zy1000.c deleted file mode 100644 index 669e6f45c..000000000 --- a/src/jtag/zy1000/zy1000.c +++ /dev/null @@ -1,1259 +0,0 @@ -/*************************************************************************** - * Copyright (C) 2007-2010 by Øyvind Harboe * - * * - * 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 . * - ***************************************************************************/ - -/* This file supports the zy1000 debugger: - * - * http://www.ultsol.com/index.php/component/content/article/8/33-zylin-zy1000-jtag-probe - * - * The zy1000 is a standalone debugger that has a web interface and - * requires no drivers on the developer host as all communication - * is via TCP/IP. The zy1000 gets it performance(~400-700kBytes/s - * DCC downloads @ 16MHz target) as it has an FPGA to hardware - * accelerate the JTAG commands, while offering *very* low latency - * between OpenOCD and the FPGA registers. - * - * The disadvantage of the zy1000 is that it has a feeble CPU compared to - * a PC(ca. 50-500 DMIPS depending on how one counts it), whereas a PC - * is on the order of 10000 DMIPS(i.e. at a factor of 20-200). - * - * The zy1000 revc hardware is using an Altera Nios CPU, whereas the - * revb is using ARM7 + Xilinx. - * - * See Zylin web pages or contact Zylin for more information. - * - * The reason this code is in OpenOCD rather than OpenOCD linked with the - * ZY1000 code is that OpenOCD is the long road towards getting - * libopenocd into place. libopenocd will support both low performance, - * low latency systems(embedded) and high performance high latency - * systems(PCs). - */ -#ifdef HAVE_CONFIG_H -#include "config.h" -#endif - -#include - -#include -#include -#include -#include -#include - -#include - -/* Assume we're connecting to a revc w/60MHz clock. */ -#define ZYLIN_KHZ 60000 - -/* The software needs to check if it's in RCLK mode or not */ -static bool zy1000_rclk; - -static int zy1000_khz(int khz, int *jtag_speed) -{ - if (khz == 0) - *jtag_speed = 0; - else { - int speed; - /* Round speed up to nearest divisor. - * - * E.g. 16000kHz - * (64000 + 15999) / 16000 = 4 - * (4 + 1) / 2 = 2 - * 2 * 2 = 4 - * - * 64000 / 4 = 16000 - * - * E.g. 15999 - * (64000 + 15998) / 15999 = 5 - * (5 + 1) / 2 = 3 - * 3 * 2 = 6 - * - * 64000 / 6 = 10666 - * - */ - speed = (ZYLIN_KHZ + (khz - 1)) / khz; - speed = (speed + 1) / 2; - speed *= 2; - if (speed > 8190) { - /* maximum dividend */ - speed = 8190; - } - *jtag_speed = speed; - } - return ERROR_OK; -} - -static int zy1000_speed_div(int speed, int *khz) -{ - if (speed == 0) - *khz = 0; - else - *khz = ZYLIN_KHZ / speed; - - return ERROR_OK; -} - -static bool readPowerDropout(void) -{ - uint32_t state; - /* sample and clear power dropout */ - ZY1000_POKE(ZY1000_JTAG_BASE + 0x10, 0x80); - ZY1000_PEEK(ZY1000_JTAG_BASE + 0x10, state); - bool powerDropout; - powerDropout = (state & 0x80) != 0; - return powerDropout; -} - - -static bool readSRST(void) -{ - uint32_t state; - /* sample and clear SRST sensing */ - ZY1000_POKE(ZY1000_JTAG_BASE + 0x10, 0x00000040); - ZY1000_PEEK(ZY1000_JTAG_BASE + 0x10, state); - bool srstAsserted; - srstAsserted = (state & 0x40) != 0; - return srstAsserted; -} - -static int zy1000_srst_asserted(int *srst_asserted) -{ - *srst_asserted = readSRST(); - return ERROR_OK; -} - -static int zy1000_power_dropout(int *dropout) -{ - *dropout = readPowerDropout(); - return ERROR_OK; -} - -/* Wait for SRST to assert or deassert */ -static void waitSRST(bool asserted) -{ - bool first = true; - int64_t start = 0; - int64_t total = 0; - const char *mode = asserted ? "assert" : "deassert"; - - for (;; ) { - bool srstAsserted = readSRST(); - if ((asserted && srstAsserted) || (!asserted && !srstAsserted)) { - if (total > 1) - LOG_USER("SRST took %dms to %s", (int)total, mode); - break; - } - - if (first) { - first = false; - start = timeval_ms(); - } - - total = timeval_ms() - start; - - keep_alive(); - - if (total > 5000) { - LOG_ERROR("SRST took too long to %s: %" PRId64 "ms", mode, total); - break; - } - } -} - -void zy1000_reset(int trst, int srst) -{ - LOG_DEBUG("zy1000 trst=%d, srst=%d", trst, srst); - - /* flush the JTAG FIFO. Not flushing the queue before messing with - * reset has such interesting bugs as causing hard to reproduce - * RCLK bugs as RCLK will stop responding when TRST is asserted - */ - waitIdle(); - - if (!srst) - ZY1000_POKE(ZY1000_JTAG_BASE + 0x14, 0x00000001); - else { - /* Danger!!! if clk != 0 when in - * idle in TAP_IDLE, reset halt on str912 will fail. - */ - ZY1000_POKE(ZY1000_JTAG_BASE + 0x10, 0x00000001); - - waitSRST(true); - } - - if (!trst) - ZY1000_POKE(ZY1000_JTAG_BASE + 0x14, 0x00000002); - else { - /* assert reset */ - ZY1000_POKE(ZY1000_JTAG_BASE + 0x10, 0x00000002); - } - - if (trst || (srst && (jtag_get_reset_config() & RESET_SRST_PULLS_TRST))) { - /* we're now in the RESET state until trst is deasserted */ - ZY1000_POKE(ZY1000_JTAG_BASE + 0x20, TAP_RESET); - } else { - /* We'll get RCLK failure when we assert TRST, so clear any false positives here */ - ZY1000_POKE(ZY1000_JTAG_BASE + 0x14, 0x400); - } - - /* wait for srst to float back up */ - if ((!srst && ((jtag_get_reset_config() & RESET_TRST_PULLS_SRST) == 0)) || - (!srst && !trst && (jtag_get_reset_config() & RESET_TRST_PULLS_SRST))) - waitSRST(false); -} - -int zy1000_speed(int speed) -{ - /* flush JTAG master FIFO before setting speed */ - waitIdle(); - - zy1000_rclk = false; - - if (speed == 0) { - /*0 means RCLK*/ - ZY1000_POKE(ZY1000_JTAG_BASE + 0x10, 0x100); - zy1000_rclk = true; - LOG_DEBUG("jtag_speed using RCLK"); - } else { - if (speed > 8190 || speed < 2) { - LOG_USER( - "valid ZY1000 jtag_speed=[8190,2]. With divisor is %dkHz / even values between 8190-2, i.e. min %dHz, max %dMHz", - ZYLIN_KHZ, - (ZYLIN_KHZ * 1000) / 8190, - ZYLIN_KHZ / (2 * 1000)); - return ERROR_COMMAND_SYNTAX_ERROR; - } - - int khz; - speed &= ~1; - zy1000_speed_div(speed, &khz); - LOG_USER("jtag_speed %d => JTAG clk=%d kHz", speed, khz); - ZY1000_POKE(ZY1000_JTAG_BASE + 0x14, 0x100); - ZY1000_POKE(ZY1000_JTAG_BASE + 0x1c, speed); - } - return ERROR_OK; -} - -static bool savePower; - -static void setPower(bool power) -{ - savePower = power; - if (power) - ZY1000_POKE(ZY1000_JTAG_BASE + 0x14, 0x8); - else - ZY1000_POKE(ZY1000_JTAG_BASE + 0x10, 0x8); -} - -COMMAND_HANDLER(handle_power_command) -{ - switch (CMD_ARGC) { - case 1: { - bool enable; - COMMAND_PARSE_ON_OFF(CMD_ARGV[0], enable); - setPower(enable); - } - /* fall through */ - case 0: - LOG_INFO("Target power %s", savePower ? "on" : "off"); - break; - default: - return ERROR_COMMAND_SYNTAX_ERROR; - } - - return ERROR_OK; -} - -#if !BUILD_ZY1000_MASTER -static char *tcp_server = "notspecified"; -static int jim_zy1000_server(Jim_Interp *interp, int argc, Jim_Obj * const *argv) -{ - if (argc != 2) - return JIM_ERR; - - tcp_server = strdup(Jim_GetString(argv[1], NULL)); - - return JIM_OK; -} -#endif - -static int zylinjtag_Jim_Command_powerstatus(Jim_Interp *interp, - int argc, - Jim_Obj * const *argv) -{ - if (argc != 1) { - Jim_WrongNumArgs(interp, 1, argv, "powerstatus"); - return JIM_ERR; - } - - bool dropout = readPowerDropout(); - - Jim_SetResult(interp, Jim_NewIntObj(interp, dropout)); - - return JIM_OK; -} - -int zy1000_quit(void) -{ - - return ERROR_OK; -} - -int interface_jtag_execute_queue(void) -{ - uint32_t empty; - - waitIdle(); - - /* We must make sure to write data read back to memory location before we return - * from this fn - */ - zy1000_flush_readqueue(); - - /* and handle any callbacks... */ - zy1000_flush_callbackqueue(); - - if (zy1000_rclk) { - /* Only check for errors when using RCLK to speed up - * jtag over TCP/IP - */ - ZY1000_PEEK(ZY1000_JTAG_BASE + 0x10, empty); - /* clear JTAG error register */ - ZY1000_POKE(ZY1000_JTAG_BASE + 0x14, 0x400); - - if ((empty&0x400) != 0) { - LOG_WARNING("RCLK timeout"); - /* the error is informative only as we don't want to break the firmware if there - * is a false positive. - */ - /* return ERROR_FAIL; */ - } - } - return ERROR_OK; -} - -static void writeShiftValue(uint8_t *data, int bits); - -/* here we shuffle N bits out/in */ -static inline void scanBits(const uint8_t *out_value, - uint8_t *in_value, - int num_bits, - bool pause_now, - tap_state_t shiftState, - tap_state_t end_state) -{ - tap_state_t pause_state = shiftState; - for (int j = 0; j < num_bits; j += 32) { - int k = num_bits - j; - if (k > 32) { - k = 32; - /* we have more to shift out */ - } else if (pause_now) { - /* this was the last to shift out this time */ - pause_state = end_state; - } - - /* we have (num_bits + 7)/8 bytes of bits to toggle out. */ - /* bits are pushed out LSB to MSB */ - uint32_t value; - value = 0; - if (out_value != NULL) { - for (int l = 0; l < k; l += 8) - value |= out_value[(j + l)/8]<= 32 is not defined by the C standard - * and will in fact shift by &0x1f bits on nios */ - } - - shiftValueInner(shiftState, pause_state, k, value); - - if (in_value != NULL) - writeShiftValue(in_value + (j/8), k); - } -} - -static inline void scanFields(int num_fields, - const struct scan_field *fields, - tap_state_t shiftState, - tap_state_t end_state) -{ - for (int i = 0; i < num_fields; i++) { - scanBits(fields[i].out_value, - fields[i].in_value, - fields[i].num_bits, - (i == num_fields-1), - shiftState, - end_state); - } -} - -int interface_jtag_add_ir_scan(struct jtag_tap *active, - const struct scan_field *fields, - tap_state_t state) -{ - int scan_size = 0; - struct jtag_tap *tap, *nextTap; - tap_state_t pause_state = TAP_IRSHIFT; - - for (tap = jtag_tap_next_enabled(NULL); tap != NULL; tap = nextTap) { - nextTap = jtag_tap_next_enabled(tap); - if (nextTap == NULL) - pause_state = state; - scan_size = tap->ir_length; - - /* search the list */ - if (tap == active) { - scanFields(1, fields, TAP_IRSHIFT, pause_state); - /* update device information */ - buf_cpy(fields[0].out_value, tap->cur_instr, scan_size); - - tap->bypass = 0; - } else { - /* if a device isn't listed, set it to BYPASS */ - assert(scan_size <= 32); - shiftValueInner(TAP_IRSHIFT, pause_state, scan_size, 0xffffffff); - - /* Optimization code will check what the cur_instr is set to, so - * we must set it to bypass value. - */ - buf_set_ones(tap->cur_instr, tap->ir_length); - - tap->bypass = 1; - } - } - - return ERROR_OK; -} - -int interface_jtag_add_plain_ir_scan(int num_bits, - const uint8_t *out_bits, - uint8_t *in_bits, - tap_state_t state) -{ - scanBits(out_bits, in_bits, num_bits, true, TAP_IRSHIFT, state); - return ERROR_OK; -} - -int interface_jtag_add_dr_scan(struct jtag_tap *active, - int num_fields, - const struct scan_field *fields, - tap_state_t state) -{ - struct jtag_tap *tap, *nextTap; - tap_state_t pause_state = TAP_DRSHIFT; - for (tap = jtag_tap_next_enabled(NULL); tap != NULL; tap = nextTap) { - nextTap = jtag_tap_next_enabled(tap); - if (nextTap == NULL) - pause_state = state; - - /* Find a range of fields to write to this tap */ - if (tap == active) { - assert(!tap->bypass); - - scanFields(num_fields, fields, TAP_DRSHIFT, pause_state); - } else { - /* Shift out a 0 for disabled tap's */ - assert(tap->bypass); - shiftValueInner(TAP_DRSHIFT, pause_state, 1, 0); - } - } - return ERROR_OK; -} - -int interface_jtag_add_plain_dr_scan(int num_bits, - const uint8_t *out_bits, - uint8_t *in_bits, - tap_state_t state) -{ - scanBits(out_bits, in_bits, num_bits, true, TAP_DRSHIFT, state); - return ERROR_OK; -} - -int interface_jtag_add_tlr(void) -{ - setCurrentState(TAP_RESET); - return ERROR_OK; -} - -int interface_jtag_add_reset(int req_trst, int req_srst) -{ - zy1000_reset(req_trst, req_srst); - return ERROR_OK; -} - -static int zy1000_jtag_add_clocks(int num_cycles, tap_state_t state, tap_state_t clockstate) -{ - /* num_cycles can be 0 */ - setCurrentState(clockstate); - - /* execute num_cycles, 32 at the time. */ - int i; - for (i = 0; i < num_cycles; i += 32) { - int num; - num = 32; - if (num_cycles-i < num) - num = num_cycles-i; - shiftValueInner(clockstate, clockstate, num, 0); - } - -#if !TEST_MANUAL() - /* finish in end_state */ - setCurrentState(state); -#else - tap_state_t t = TAP_IDLE; - /* test manual drive code on any target */ - int tms; - uint8_t tms_scan = tap_get_tms_path(t, state); - int tms_count = tap_get_tms_path_len(tap_get_state(), tap_get_end_state()); - - for (i = 0; i < tms_count; i++) { - tms = (tms_scan >> i) & 1; - waitIdle(); - ZY1000_POKE(ZY1000_JTAG_BASE + 0x28, tms); - } - waitIdle(); - ZY1000_POKE(ZY1000_JTAG_BASE + 0x20, state); -#endif - - return ERROR_OK; -} - -int interface_jtag_add_runtest(int num_cycles, tap_state_t state) -{ - return zy1000_jtag_add_clocks(num_cycles, state, TAP_IDLE); -} - -int interface_jtag_add_clocks(int num_cycles) -{ - return zy1000_jtag_add_clocks(num_cycles, cmd_queue_cur_state, cmd_queue_cur_state); -} - -int interface_add_tms_seq(unsigned num_bits, const uint8_t *seq, enum tap_state state) -{ - /*wait for the fifo to be empty*/ - waitIdle(); - - for (unsigned i = 0; i < num_bits; i++) { - int tms; - - if (((seq[i/8] >> (i % 8)) & 1) == 0) - tms = 0; - else - tms = 1; - - waitIdle(); - ZY1000_POKE(ZY1000_JTAG_BASE + 0x28, tms); - } - - waitIdle(); - if (state != TAP_INVALID) - ZY1000_POKE(ZY1000_JTAG_BASE + 0x20, state); - else { - /* this would be normal if - * we are switching to SWD mode */ - } - return ERROR_OK; -} - -int interface_jtag_add_pathmove(int num_states, const tap_state_t *path) -{ - int state_count; - int tms = 0; - - state_count = 0; - - tap_state_t cur_state = cmd_queue_cur_state; - - uint8_t seq[16]; - memset(seq, 0, sizeof(seq)); - assert(num_states < (int)((sizeof(seq) * 8))); - - while (num_states) { - if (tap_state_transition(cur_state, false) == path[state_count]) - tms = 0; - else if (tap_state_transition(cur_state, true) == path[state_count]) - tms = 1; - else { - LOG_ERROR("BUG: %s -> %s isn't a valid TAP transition", - tap_state_name(cur_state), tap_state_name(path[state_count])); - exit(-1); - } - - seq[state_count/8] = seq[state_count/8] | (tms << (state_count % 8)); - - cur_state = path[state_count]; - state_count++; - num_states--; - } - - return interface_add_tms_seq(state_count, seq, cur_state); -} - -static void jtag_pre_post_bits(struct jtag_tap *tap, int *pre, int *post) -{ - /* bypass bits before and after */ - int pre_bits = 0; - int post_bits = 0; - - bool found = false; - struct jtag_tap *cur_tap, *nextTap; - for (cur_tap = jtag_tap_next_enabled(NULL); cur_tap != NULL; cur_tap = nextTap) { - nextTap = jtag_tap_next_enabled(cur_tap); - if (cur_tap == tap) - found = true; - else { - if (found) - post_bits++; - else - pre_bits++; - } - } - *pre = pre_bits; - *post = post_bits; -} - -void embeddedice_write_dcc(struct jtag_tap *tap, - int reg_addr, - const uint8_t *buffer, - int little, - int count) -{ -#if 0 - int i; - for (i = 0; i < count; i++) { - embeddedice_write_reg_inner(tap, reg_addr, fast_target_buffer_get_u32(buffer, - little)); - buffer += 4; - } -#else - int pre_bits; - int post_bits; - jtag_pre_post_bits(tap, &pre_bits, &post_bits); - - if ((pre_bits > 32) || (post_bits + 6 > 32)) { - int i; - for (i = 0; i < count; i++) { - embeddedice_write_reg_inner(tap, reg_addr, - fast_target_buffer_get_u32(buffer, little)); - buffer += 4; - } - } else { - int i; - for (i = 0; i < count; i++) { - /* Fewer pokes means we get to use the FIFO more efficiently */ - shiftValueInner(TAP_DRSHIFT, TAP_DRSHIFT, pre_bits, 0); - shiftValueInner(TAP_DRSHIFT, TAP_DRSHIFT, 32, - fast_target_buffer_get_u32(buffer, little)); - /* Danger! here we need to exit into the TAP_IDLE state to make - * DCC pick up this value. - */ - shiftValueInner(TAP_DRSHIFT, TAP_IDLE, 6 + post_bits, - (reg_addr | (1 << 5))); - buffer += 4; - } - } -#endif -} - -int arm11_run_instr_data_to_core_noack_inner(struct jtag_tap *tap, - uint32_t opcode, - uint32_t *data, - size_t count) -{ - /* bypass bits before and after */ - int pre_bits; - int post_bits; - jtag_pre_post_bits(tap, &pre_bits, &post_bits); - post_bits += 2; - - if ((pre_bits > 32) || (post_bits > 32)) { - int arm11_run_instr_data_to_core_noack_inner_default(struct jtag_tap *tap, - uint32_t opcode, uint32_t *data, size_t count); - return arm11_run_instr_data_to_core_noack_inner_default(tap, opcode, data, count); - } else { - static const uint8_t zero; - - /* FIX!!!!!! the target_write_memory() API started this nasty problem - * with unaligned uint32_t * pointers... */ - const uint8_t *t = (const uint8_t *)data; - - while (--count > 0) { -#if 1 - /* Danger! This code doesn't update cmd_queue_cur_state, so - * invoking jtag_add_pathmove() before jtag_add_dr_scan() after - * this loop would fail! - */ - shiftValueInner(TAP_DRSHIFT, TAP_DRSHIFT, pre_bits, 0); - - uint32_t value; - value = *t++; - value |= (*t++<<8); - value |= (*t++<<16); - value |= (*t++<<24); - - shiftValueInner(TAP_DRSHIFT, TAP_DRSHIFT, 32, value); - /* minimum 2 bits */ - shiftValueInner(TAP_DRSHIFT, TAP_DRPAUSE, post_bits, 0); - - /* copy & paste from arm11_dbgtap.c */ - /* TAP_DREXIT2, TAP_DRUPDATE, TAP_IDLE, TAP_IDLE, TAP_IDLE, TAP_DRSELECT, - * TAP_DRCAPTURE, TAP_DRSHIFT */ - /* KLUDGE! we have to flush the fifo or the Nios CPU locks up. - * This is probably a bug in the Avalon bus(cross clocking bridge?) - * or in the jtag registers module. - */ - waitIdle(); - ZY1000_POKE(ZY1000_JTAG_BASE + 0x28, 1); - ZY1000_POKE(ZY1000_JTAG_BASE + 0x28, 1); - ZY1000_POKE(ZY1000_JTAG_BASE + 0x28, 0); - ZY1000_POKE(ZY1000_JTAG_BASE + 0x28, 0); - ZY1000_POKE(ZY1000_JTAG_BASE + 0x28, 0); - ZY1000_POKE(ZY1000_JTAG_BASE + 0x28, 1); - ZY1000_POKE(ZY1000_JTAG_BASE + 0x28, 0); - ZY1000_POKE(ZY1000_JTAG_BASE + 0x28, 0); - /* we don't have to wait for the queue to empty here */ - ZY1000_POKE(ZY1000_JTAG_BASE + 0x20, TAP_DRSHIFT); - waitIdle(); -#else - static const tap_state_t arm11_MOVE_DRPAUSE_IDLE_DRPAUSE_with_delay[] = { - TAP_DREXIT2, TAP_DRUPDATE, TAP_IDLE, TAP_IDLE, TAP_IDLE, - TAP_DRSELECT, TAP_DRCAPTURE, TAP_DRSHIFT - }; - - struct scan_field fields[2] = { - { .num_bits = 32, .out_value = t }, - { .num_bits = 2, .out_value = &zero }, - }; - t += 4; - - jtag_add_dr_scan(tap, - 2, - fields, - TAP_IDLE); - - jtag_add_pathmove(ARRAY_SIZE(arm11_MOVE_DRPAUSE_IDLE_DRPAUSE_with_delay), - arm11_MOVE_DRPAUSE_IDLE_DRPAUSE_with_delay); -#endif - } - - struct scan_field fields[2] = { - { .num_bits = 32, .out_value = t }, - { .num_bits = 2, .out_value = &zero }, - }; - - /* This will happen on the last iteration updating cmd_queue_cur_state - * so we don't have to track it during the common code path - */ - jtag_add_dr_scan(tap, - 2, - fields, - TAP_IDLE); - - return jtag_execute_queue(); - } -} - -static const struct command_registration zy1000_commands[] = { - { - .name = "power", - .handler = handle_power_command, - .mode = COMMAND_ANY, - .help = "Turn power switch to target on/off. " - "With no arguments, prints status.", - .usage = "('on'|'off)", - }, -#if !BUILD_ZY1000_MASTER - { - .name = "zy1000_server", - .mode = COMMAND_ANY, - .jim_handler = jim_zy1000_server, - .help = "Tcpip address for ZY1000 server.", - .usage = "address", - }, -#endif - { - .name = "powerstatus", - .mode = COMMAND_ANY, - .jim_handler = zylinjtag_Jim_Command_powerstatus, - .help = "Returns power status of target", - }, - COMMAND_REGISTRATION_DONE -}; - -#if !BUILD_ZY1000_MASTER - -static int tcp_ip = -1; - -/* Write large packets if we can */ -static size_t out_pos; -static uint8_t out_buffer[16384]; -static size_t in_pos; -static size_t in_write; -static uint8_t in_buffer[16384]; - -static bool flush_writes(void) -{ - bool ok = (write(tcp_ip, out_buffer, out_pos) == (int)out_pos); - out_pos = 0; - return ok; -} - -static bool writeLong(uint32_t l) -{ - int i; - for (i = 0; i < 4; i++) { - uint8_t c = (l >> (i*8))&0xff; - out_buffer[out_pos++] = c; - if (out_pos >= sizeof(out_buffer)) { - if (!flush_writes()) - return false; - } - } - return true; -} - -static bool readLong(uint32_t *out_data) -{ - uint32_t data = 0; - int i; - for (i = 0; i < 4; i++) { - uint8_t c; - if (in_pos == in_write) { - /* If we have some data that we can send, send them before - * we wait for more data - */ - if (out_pos > 0) { - if (!flush_writes()) - return false; - } - - /* read more */ - int t; - t = read(tcp_ip, in_buffer, sizeof(in_buffer)); - if (t < 1) - return false; - in_write = (size_t) t; - in_pos = 0; - } - c = in_buffer[in_pos++]; - - data |= (c << (i*8)); - } - *out_data = data; - return true; -} - -enum ZY1000_CMD { - ZY1000_CMD_POKE = 0x0, - ZY1000_CMD_PEEK = 0x8, - ZY1000_CMD_SLEEP = 0x1, - ZY1000_CMD_WAITIDLE = 2 -}; - -#include /* for socket(), connect(), send(), and recv() */ -#include /* for sockaddr_in and inet_addr() */ - -/* We initialize this late since we need to know the server address - * first. - */ -static void tcpip_open(void) -{ - if (tcp_ip >= 0) - return; - - struct sockaddr_in echoServAddr;/* Echo server address */ - - /* Create a reliable, stream socket using TCP */ - tcp_ip = socket(PF_INET, SOCK_STREAM, IPPROTO_TCP); - if (tcp_ip < 0) { - fprintf(stderr, "Failed to connect to zy1000 server\n"); - exit(-1); - } - - /* Construct the server address structure */ - memset(&echoServAddr, 0, sizeof(echoServAddr)); /* Zero out structure */ - echoServAddr.sin_family = AF_INET; /* Internet address family */ - echoServAddr.sin_addr.s_addr = inet_addr(tcp_server); /* Server IP address */ - echoServAddr.sin_port = htons(7777); /* Server port */ - - /* Establish the connection to the echo server */ - if (connect(tcp_ip, (struct sockaddr *) &echoServAddr, sizeof(echoServAddr)) < 0) { - fprintf(stderr, "Failed to connect to zy1000 server\n"); - exit(-1); - } - - int flag = 1; - setsockopt(tcp_ip, /* socket affected */ - IPPROTO_TCP, /* set option at TCP level */ - TCP_NODELAY, /* name of option */ - (char *)&flag, /* the cast is historical cruft */ - sizeof(int)); /* length of option value */ - -} - -/* send a poke */ -void zy1000_tcpout(uint32_t address, uint32_t data) -{ - tcpip_open(); - if (!writeLong((ZY1000_CMD_POKE << 24) | address) || !writeLong(data)) { - fprintf(stderr, "Could not write to zy1000 server\n"); - exit(-1); - } -} - -/* By sending the wait to the server, we avoid a readback - * of status. Radically improves performance for this operation - * with long ping times. - */ -void waitIdle(void) -{ - tcpip_open(); - if (!writeLong((ZY1000_CMD_WAITIDLE << 24))) { - fprintf(stderr, "Could not write to zy1000 server\n"); - exit(-1); - } -} - -uint32_t zy1000_tcpin(uint32_t address) -{ - tcpip_open(); - - zy1000_flush_readqueue(); - - uint32_t data; - if (!writeLong((ZY1000_CMD_PEEK << 24) | address) || !readLong(&data)) { - fprintf(stderr, "Could not read from zy1000 server\n"); - exit(-1); - } - return data; -} - -int interface_jtag_add_sleep(uint32_t us) -{ - tcpip_open(); - if (!writeLong((ZY1000_CMD_SLEEP << 24)) || !writeLong(us)) { - fprintf(stderr, "Could not read from zy1000 server\n"); - exit(-1); - } - return ERROR_OK; -} - -/* queue a readback */ -#define readqueue_size 16384 -static struct { - uint8_t *dest; - int bits; -} readqueue[readqueue_size]; - -static int readqueue_pos; - -/* flush the readqueue, this means reading any data that - * we're expecting and store them into the final position - */ -void zy1000_flush_readqueue(void) -{ - if (readqueue_pos == 0) { - /* simply debugging by allowing easy breakpoints when there - * is something to do. */ - return; - } - int i; - tcpip_open(); - for (i = 0; i < readqueue_pos; i++) { - uint32_t value; - if (!readLong(&value)) { - fprintf(stderr, "Could not read from zy1000 server\n"); - exit(-1); - } - - uint8_t *in_value = readqueue[i].dest; - int k = readqueue[i].bits; - - /* we're shifting in data to MSB, shift data to be aligned for returning the value */ - value >>= 32-k; - - for (int l = 0; l < k; l += 8) - in_value[l/8] = (value >> l)&0xff; - } - readqueue_pos = 0; -} - -/* By queuing the callback's we avoid flushing the - * read queue until jtag_execute_queue(). This can - * reduce latency dramatically for cases where - * callbacks are used extensively. -*/ -#define callbackqueue_size 128 -static struct callbackentry { - jtag_callback_t callback; - jtag_callback_data_t data0; - jtag_callback_data_t data1; - jtag_callback_data_t data2; - jtag_callback_data_t data3; -} callbackqueue[callbackqueue_size]; - -static int callbackqueue_pos; - -void zy1000_jtag_add_callback4(jtag_callback_t callback, - jtag_callback_data_t data0, - jtag_callback_data_t data1, - jtag_callback_data_t data2, - jtag_callback_data_t data3) -{ - if (callbackqueue_pos >= callbackqueue_size) - zy1000_flush_callbackqueue(); - - callbackqueue[callbackqueue_pos].callback = callback; - callbackqueue[callbackqueue_pos].data0 = data0; - callbackqueue[callbackqueue_pos].data1 = data1; - callbackqueue[callbackqueue_pos].data2 = data2; - callbackqueue[callbackqueue_pos].data3 = data3; - callbackqueue_pos++; - - /* KLUDGE! - * make callbacks synchronous for now as minidriver requires callback - * to be synchronous. - * - * We can get away with making read and writes asynchronous so we - * don't completely kill performance. - */ - zy1000_flush_callbackqueue(); -} - -static int zy1000_jtag_convert_to_callback4(jtag_callback_data_t data0, - jtag_callback_data_t data1, - jtag_callback_data_t data2, - jtag_callback_data_t data3) -{ - ((jtag_callback1_t)data1)(data0); - return ERROR_OK; -} - -void zy1000_jtag_add_callback(jtag_callback1_t callback, jtag_callback_data_t data0) -{ - zy1000_jtag_add_callback4(zy1000_jtag_convert_to_callback4, - data0, - (jtag_callback_data_t)callback, - 0, - 0); -} - -void zy1000_flush_callbackqueue(void) -{ - /* we have to flush the read queue so we have access to - the data the callbacks will use - */ - zy1000_flush_readqueue(); - int i; - for (i = 0; i < callbackqueue_pos; i++) { - struct callbackentry *entry = &callbackqueue[i]; - jtag_set_error(entry->callback(entry->data0, entry->data1, entry->data2, - entry->data3)); - } - callbackqueue_pos = 0; -} - -static void writeShiftValue(uint8_t *data, int bits) -{ - waitIdle(); - - if (!writeLong((ZY1000_CMD_PEEK << 24) | (ZY1000_JTAG_BASE + 0xc))) { - fprintf(stderr, "Could not read from zy1000 server\n"); - exit(-1); - } - - if (readqueue_pos >= readqueue_size) - zy1000_flush_readqueue(); - - readqueue[readqueue_pos].dest = data; - readqueue[readqueue_pos].bits = bits; - readqueue_pos++; - - /* KLUDGE!!! minidriver requires readqueue to be synchronous */ - zy1000_flush_readqueue(); -} - -#else - -static void writeShiftValue(uint8_t *data, int bits) -{ - uint32_t value; - waitIdle(); - ZY1000_PEEK(ZY1000_JTAG_BASE + 0xc, value); - VERBOSE(LOG_INFO("getShiftValue %08x", value)); - - /* data in, LSB to MSB */ - /* we're shifting in data to MSB, shift data to be aligned for returning the value */ - value >>= 32 - bits; - - for (int l = 0; l < bits; l += 8) - data[l/8] = (value >> l)&0xff; -} - -#endif - -#if BUILD_ZY1000_MASTER - -#ifdef WATCHDOG_BASE -/* If we connect to port 8888 we must send a char every 10s or the board resets itself */ -static void watchdog_server(cyg_addrword_t data) -{ - int so_reuseaddr_option = 1; - - int fd = socket(AF_INET, SOCK_STREAM, 0); - if (fd == -1) { - LOG_ERROR("error creating socket: %s", strerror(errno)); - exit(-1); - } - - setsockopt(fd, SOL_SOCKET, SO_REUSEADDR, (void *) &so_reuseaddr_option, - sizeof(int)); - - struct sockaddr_in sin; - unsigned int address_size; - address_size = sizeof(sin); - memset(&sin, 0, sizeof(sin)); - sin.sin_family = AF_INET; - sin.sin_addr.s_addr = INADDR_ANY; - sin.sin_port = htons(8888); - - if (bind(fd, (struct sockaddr *) &sin, sizeof(sin)) == -1) { - LOG_ERROR("couldn't bind to socket: %s", strerror(errno)); - exit(-1); - } - - if (listen(fd, 1) == -1) { - LOG_ERROR("couldn't listen on socket: %s", strerror(errno)); - exit(-1); - } - - - for (;; ) { - int watchdog_ip = accept(fd, (struct sockaddr *) &sin, &address_size); - - /* Start watchdog, must be reset every 10 seconds. */ - HAL_WRITE_UINT32(WATCHDOG_BASE + 4, 4); - - if (watchdog_ip < 0) { - LOG_ERROR("couldn't open watchdog socket: %s", strerror(errno)); - exit(-1); - } - - int flag = 1; - setsockopt(watchdog_ip, /* socket affected */ - IPPROTO_TCP, /* set option at TCP level */ - TCP_NODELAY, /* name of option */ - (char *)&flag, /* the cast is historical cruft */ - sizeof(int)); /* length of option value */ - - - char buf; - for (;; ) { - if (read(watchdog_ip, &buf, 1) == 1) { - /* Reset timer */ - HAL_WRITE_UINT32(WATCHDOG_BASE + 8, 0x1234); - /* Echo so we can telnet in and see that resetting works */ - write(watchdog_ip, &buf, 1); - } else { - /* Stop tickling the watchdog, the CPU will reset in < 10 seconds - * now. - */ - return; - } - - } - - /* Never reached */ - } -} -#endif - -#endif - -#if BUILD_ZY1000_MASTER -int interface_jtag_add_sleep(uint32_t us) -{ - jtag_sleep(us); - return ERROR_OK; -} -#endif - -#if BUILD_ZY1000_MASTER -volatile void *zy1000_jtag_master; -#include -#endif - -int zy1000_init(void) -{ -#if BUILD_ZY1000_MASTER - int fd = open("/dev/mem", O_RDWR | O_SYNC); - if (fd == -1) { - LOG_ERROR("No access to /dev/mem"); - return ERROR_FAIL; - } -#ifndef REGISTERS_BASE -#define REGISTERS_BASE 0x9002000 -#define REGISTERS_SPAN 128 -#endif - - zy1000_jtag_master = mmap(0, - REGISTERS_SPAN, - PROT_READ | PROT_WRITE, - MAP_SHARED, - fd, - REGISTERS_BASE); - - if (zy1000_jtag_master == (void *) -1) { - close(fd); - LOG_ERROR("No access to /dev/mem"); - return ERROR_FAIL; - } -#endif - - ZY1000_POKE(ZY1000_JTAG_BASE + 0x10, 0x30); /* Turn on LED1 & LED2 */ - - setPower(true); /* on by default */ - - /* deassert resets. Important to avoid infinite loop waiting for SRST to deassert */ - zy1000_reset(0, 0); - - return ERROR_OK; -} - -static struct jtag_interface zy1000_interface = { - .supported = DEBUG_CAP_TMS_SEQ, - .execute_queue = NULL, -}; - -struct adapter_driver zy1000_adapter_driver = { - .name = "ZY1000", - .transports = jtag_only, - .commands = zy1000_commands, - - .init = zy1000_init, - .quit = zy1000_quit, - .speed = zy1000_speed, - .khz = zy1000_khz, - .speed_div = zy1000_speed_div, - .power_dropout = zy1000_power_dropout, - .srst_asserted = zy1000_srst_asserted, - - .jtag_ops = &zy1000_interface, -}; diff --git a/src/openocd.c b/src/openocd.c index 83c35458b..fcefdbe70 100644 --- a/src/openocd.c +++ b/src/openocd.c @@ -30,7 +30,6 @@ #include #include #include -#include #include #include #include @@ -38,6 +37,7 @@ #include #include #include +#include #include #include @@ -173,6 +173,10 @@ COMMAND_HANDLER(handle_init_command) return ERROR_FAIL; command_context_mode(CMD_CTX, COMMAND_EXEC); + /* in COMMAND_EXEC, after target_examine(), only tpiu or only swo */ + if (command_run_line(CMD_CTX, "tpiu init") != ERROR_OK) + return ERROR_FAIL; + /* initialize telnet subsystem */ gdb_target_add_all(all_targets); @@ -255,6 +259,7 @@ static struct command_context *setup_command_handler(Jim_Interp *interp) &pld_register_commands, &cti_register_commands, &dap_register_commands, + &arm_tpiu_swo_register_commands, NULL }; for (unsigned i = 0; NULL != command_registrants[i]; i++) { @@ -335,9 +340,6 @@ int openocd_main(int argc, char *argv[]) if (util_init(cmd_ctx) != ERROR_OK) return EXIT_FAILURE; - if (ioutil_init(cmd_ctx) != ERROR_OK) - return EXIT_FAILURE; - if (rtt_init() != ERROR_OK) return EXIT_FAILURE; @@ -355,6 +357,7 @@ int openocd_main(int argc, char *argv[]) flash_free_all_banks(); gdb_service_free(); + arm_tpiu_swo_cleanup_all(); server_free(); unregister_all_commands(cmd_ctx, NULL); diff --git a/src/rtos/FreeRTOS.c b/src/rtos/FreeRTOS.c index 215f55d62..5334b0dcf 100644 --- a/src/rtos/FreeRTOS.c +++ b/src/rtos/FreeRTOS.c @@ -215,7 +215,7 @@ static int FreeRTOS_get_thread_reg_list(struct rtos *rtos, threadid_t thread_id, static int FreeRTOS_get_thread_reg(struct rtos *rtos, threadid_t thread_id, uint32_t reg_num, struct rtos_reg *reg); static int FreeRTOS_set_reg(struct rtos *rtos, uint32_t reg_num, uint8_t *reg_value); -static int FreeRTOS_get_symbol_list_to_lookup(symbol_table_elem_t *symbol_list[]); +static int FreeRTOS_get_symbol_list_to_lookup(struct symbol_table_elem *symbol_list[]); struct rtos_type FreeRTOS_rtos = { .name = "FreeRTOS", @@ -790,11 +790,11 @@ static int FreeRTOS_set_reg(struct rtos *rtos, uint32_t reg_num, uint8_t *reg_va reg_num, reg_value); } -static int FreeRTOS_get_symbol_list_to_lookup(symbol_table_elem_t *symbol_list[]) +static int FreeRTOS_get_symbol_list_to_lookup(struct symbol_table_elem *symbol_list[]) { unsigned int i; *symbol_list = calloc( - ARRAY_SIZE(FreeRTOS_symbol_list), sizeof(symbol_table_elem_t)); + ARRAY_SIZE(FreeRTOS_symbol_list), sizeof(struct symbol_table_elem)); for (i = 0; i < ARRAY_SIZE(FreeRTOS_symbol_list); i++) { (*symbol_list)[i].symbol_name = FreeRTOS_symbol_list[i].name; diff --git a/src/rtos/ThreadX.c b/src/rtos/ThreadX.c index 53788c794..40413328a 100644 --- a/src/rtos/ThreadX.c +++ b/src/rtos/ThreadX.c @@ -39,7 +39,7 @@ static bool ThreadX_detect_rtos(struct target *target); static int ThreadX_create(struct target *target); static int ThreadX_update_threads(struct rtos *rtos); static int ThreadX_get_thread_reg_list(struct rtos *rtos, int64_t thread_id, struct rtos_reg **reg_list, int *num_regs); -static int ThreadX_get_symbol_list_to_lookup(symbol_table_elem_t *symbol_list[]); +static int ThreadX_get_symbol_list_to_lookup(struct symbol_table_elem *symbol_list[]); @@ -477,11 +477,11 @@ static int ThreadX_get_thread_reg_list(struct rtos *rtos, int64_t thread_id, return rtos_generic_stack_read(rtos->target, stacking_info, stack_ptr, reg_list, num_regs); } -static int ThreadX_get_symbol_list_to_lookup(symbol_table_elem_t *symbol_list[]) +static int ThreadX_get_symbol_list_to_lookup(struct symbol_table_elem *symbol_list[]) { unsigned int i; *symbol_list = calloc( - ARRAY_SIZE(ThreadX_symbol_list), sizeof(symbol_table_elem_t)); + ARRAY_SIZE(ThreadX_symbol_list), sizeof(struct symbol_table_elem)); for (i = 0; i < ARRAY_SIZE(ThreadX_symbol_list); i++) (*symbol_list)[i].symbol_name = ThreadX_symbol_list[i]; diff --git a/src/rtos/chibios.c b/src/rtos/chibios.c index a56d3ce05..29abede80 100644 --- a/src/rtos/chibios.c +++ b/src/rtos/chibios.c @@ -107,7 +107,7 @@ static int chibios_create(struct target *target); static int chibios_update_threads(struct rtos *rtos); static int chibios_get_thread_reg_list(struct rtos *rtos, int64_t thread_id, struct rtos_reg **reg_list, int *num_regs); -static int chibios_get_symbol_list_to_lookup(symbol_table_elem_t *symbol_list[]); +static int chibios_get_symbol_list_to_lookup(struct symbol_table_elem *symbol_list[]); struct rtos_type chibios_rtos = { .name = "chibios", @@ -131,7 +131,7 @@ enum chibios_symbol_values { CHIBIOS_VAL_CH_DEBUG = 2 }; -static symbol_table_elem_t chibios_symbol_list[] = { +static struct symbol_table_elem chibios_symbol_list[] = { { "rlist", 0, true}, /* Thread ready list */ { "ch", 0, true}, /* System data structure */ { "ch_debug", 0, false}, /* Memory Signature containing offsets of fields in rlist */ @@ -497,7 +497,7 @@ static int chibios_get_thread_reg_list(struct rtos *rtos, int64_t thread_id, return rtos_generic_stack_read(rtos->target, param->stacking_info, stack_ptr, reg_list, num_regs); } -static int chibios_get_symbol_list_to_lookup(symbol_table_elem_t *symbol_list[]) +static int chibios_get_symbol_list_to_lookup(struct symbol_table_elem *symbol_list[]) { *symbol_list = malloc(sizeof(chibios_symbol_list)); diff --git a/src/rtos/chromium-ec.c b/src/rtos/chromium-ec.c index ae12a3bf5..1476f1969 100644 --- a/src/rtos/chromium-ec.c +++ b/src/rtos/chromium-ec.c @@ -360,12 +360,12 @@ static int chromium_ec_get_thread_reg_list(struct rtos *rtos, stack_ptr, reg_list, num_regs); } -static int chromium_ec_get_symbol_list_to_lookup(symbol_table_elem_t *symbol_list[]) +static int chromium_ec_get_symbol_list_to_lookup(struct symbol_table_elem *symbol_list[]) { size_t s; *symbol_list = calloc(ARRAY_SIZE(chromium_ec_symbol_list), - sizeof(symbol_table_elem_t)); + sizeof(struct symbol_table_elem)); if (!(*symbol_list)) { LOG_ERROR("Chromium-EC: out of memory"); return ERROR_FAIL; diff --git a/src/rtos/eCos.c b/src/rtos/eCos.c index e6b70730b..9501a5522 100644 --- a/src/rtos/eCos.c +++ b/src/rtos/eCos.c @@ -31,7 +31,7 @@ static bool eCos_detect_rtos(struct target *target); static int eCos_create(struct target *target); static int eCos_update_threads(struct rtos *rtos); static int eCos_get_thread_reg_list(struct rtos *rtos, int64_t thread_id, struct rtos_reg **reg_list, int *num_regs); -static int eCos_get_symbol_list_to_lookup(symbol_table_elem_t *symbol_list[]); +static int eCos_get_symbol_list_to_lookup(struct symbol_table_elem *symbol_list[]); struct eCos_thread_state { int value; @@ -351,11 +351,11 @@ static int eCos_get_thread_reg_list(struct rtos *rtos, int64_t thread_id, return -1; } -static int eCos_get_symbol_list_to_lookup(symbol_table_elem_t *symbol_list[]) +static int eCos_get_symbol_list_to_lookup(struct symbol_table_elem *symbol_list[]) { unsigned int i; *symbol_list = calloc( - ARRAY_SIZE(eCos_symbol_list), sizeof(symbol_table_elem_t)); + ARRAY_SIZE(eCos_symbol_list), sizeof(struct symbol_table_elem)); for (i = 0; i < ARRAY_SIZE(eCos_symbol_list); i++) (*symbol_list)[i].symbol_name = eCos_symbol_list[i]; diff --git a/src/rtos/embKernel.c b/src/rtos/embKernel.c index 2f04963b4..994cbc091 100644 --- a/src/rtos/embKernel.c +++ b/src/rtos/embKernel.c @@ -36,7 +36,7 @@ static int embKernel_create(struct target *target); static int embKernel_update_threads(struct rtos *rtos); static int embKernel_get_thread_reg_list(struct rtos *rtos, int64_t thread_id, struct rtos_reg **reg_list, int *num_regs); -static int embKernel_get_symbol_list_to_lookup(symbol_table_elem_t *symbol_list[]); +static int embKernel_get_symbol_list_to_lookup(struct symbol_table_elem *symbol_list[]); struct rtos_type embKernel_rtos = { .name = "embKernel", @@ -330,10 +330,10 @@ static int embKernel_get_thread_reg_list(struct rtos *rtos, int64_t thread_id, return rtos_generic_stack_read(rtos->target, param->stacking_info, stack_ptr, reg_list, num_regs); } -static int embKernel_get_symbol_list_to_lookup(symbol_table_elem_t *symbol_list[]) +static int embKernel_get_symbol_list_to_lookup(struct symbol_table_elem *symbol_list[]) { unsigned int i; - *symbol_list = calloc(ARRAY_SIZE(embKernel_symbol_list), sizeof(symbol_table_elem_t)); + *symbol_list = calloc(ARRAY_SIZE(embKernel_symbol_list), sizeof(struct symbol_table_elem)); for (i = 0; i < ARRAY_SIZE(embKernel_symbol_list); i++) (*symbol_list)[i].symbol_name = embKernel_symbol_list[i]; diff --git a/src/rtos/hwthread.c b/src/rtos/hwthread.c index 4051a5de2..a1a048af3 100644 --- a/src/rtos/hwthread.c +++ b/src/rtos/hwthread.c @@ -35,7 +35,7 @@ static int hwthread_get_thread_reg(struct rtos *rtos, int64_t thread_id, uint32_t reg_num, struct rtos_reg *rtos_reg); static int hwthread_get_thread_reg_list(struct rtos *rtos, int64_t thread_id, struct rtos_reg **reg_list, int *num_regs); -static int hwthread_get_symbol_list_to_lookup(symbol_table_elem_t *symbol_list[]); +static int hwthread_get_symbol_list_to_lookup(struct symbol_table_elem *symbol_list[]); static int hwthread_smp_init(struct target *target); static int hwthread_set_reg(struct rtos *rtos, uint32_t reg_num, uint8_t *reg_value); static bool hwthread_needs_fake_step(struct target *target, int64_t thread_id); @@ -338,10 +338,10 @@ static int hwthread_set_reg(struct rtos *rtos, uint32_t reg_num, uint8_t *reg_va return reg->type->set(reg, reg_value); } -static int hwthread_get_symbol_list_to_lookup(symbol_table_elem_t *symbol_list[]) +static int hwthread_get_symbol_list_to_lookup(struct symbol_table_elem *symbol_list[]) { /* return an empty list, we don't have any symbols to look up */ - *symbol_list = calloc(1, sizeof(symbol_table_elem_t)); + *symbol_list = calloc(1, sizeof(struct symbol_table_elem)); (*symbol_list)[0].symbol_name = NULL; return 0; } diff --git a/src/rtos/linux.c b/src/rtos/linux.c index 0cb4b54c8..4b96a931d 100644 --- a/src/rtos/linux.c +++ b/src/rtos/linux.c @@ -246,11 +246,11 @@ static const char * const linux_symbol_list[] = { NULL }; -static int linux_get_symbol_list_to_lookup(symbol_table_elem_t *symbol_list[]) +static int linux_get_symbol_list_to_lookup(struct symbol_table_elem *symbol_list[]) { unsigned int i; - *symbol_list = (symbol_table_elem_t *) - calloc(ARRAY_SIZE(linux_symbol_list), sizeof(symbol_table_elem_t)); + *symbol_list = (struct symbol_table_elem *) + calloc(ARRAY_SIZE(linux_symbol_list), sizeof(struct symbol_table_elem)); for (i = 0; i < ARRAY_SIZE(linux_symbol_list); i++) (*symbol_list)[i].symbol_name = linux_symbol_list[i]; diff --git a/src/rtos/mqx.c b/src/rtos/mqx.c index f45c15d23..0914e3104 100644 --- a/src/rtos/mqx.c +++ b/src/rtos/mqx.c @@ -540,9 +540,9 @@ static int mqx_get_thread_reg_list( } /* API function, export list of required symbols */ -static int mqx_get_symbol_list_to_lookup(symbol_table_elem_t *symbol_list[]) +static int mqx_get_symbol_list_to_lookup(struct symbol_table_elem *symbol_list[]) { - *symbol_list = calloc(ARRAY_SIZE(mqx_symbol_list), sizeof(symbol_table_elem_t)); + *symbol_list = calloc(ARRAY_SIZE(mqx_symbol_list), sizeof(struct symbol_table_elem)); if (NULL == *symbol_list) return ERROR_FAIL; /* export required symbols */ diff --git a/src/rtos/nuttx.c b/src/rtos/nuttx.c index df5dbe1c6..e637d053c 100644 --- a/src/rtos/nuttx.c +++ b/src/rtos/nuttx.c @@ -378,12 +378,12 @@ static int nuttx_get_thread_reg_list(struct rtos *rtos, int64_t thread_id, (uint32_t)thread_id + xcpreg_offset, reg_list, num_regs); } -static int nuttx_get_symbol_list_to_lookup(symbol_table_elem_t *symbol_list[]) +static int nuttx_get_symbol_list_to_lookup(struct symbol_table_elem *symbol_list[]) { unsigned int i; - *symbol_list = (symbol_table_elem_t *) calloc(1, - sizeof(symbol_table_elem_t) * ARRAY_SIZE(nuttx_symbol_list)); + *symbol_list = (struct symbol_table_elem *) calloc(1, + sizeof(struct symbol_table_elem) * ARRAY_SIZE(nuttx_symbol_list)); for (i = 0; i < ARRAY_SIZE(nuttx_symbol_list); i++) (*symbol_list)[i].symbol_name = nuttx_symbol_list[i]; diff --git a/src/rtos/riot.c b/src/rtos/riot.c index 15cbb0f85..dcba8381c 100644 --- a/src/rtos/riot.c +++ b/src/rtos/riot.c @@ -35,7 +35,7 @@ static int riot_create(struct target *target); static int riot_update_threads(struct rtos *rtos); static int riot_get_thread_reg_list(struct rtos *rtos, int64_t thread_id, struct rtos_reg **reg_list, int *num_regs); -static int riot_get_symbol_list_to_lookup(symbol_table_elem_t *symbol_list[]); +static int riot_get_symbol_list_to_lookup(struct symbol_table_elem *symbol_list[]); struct riot_thread_state { int value; @@ -360,9 +360,9 @@ static int riot_get_thread_reg_list(struct rtos *rtos, int64_t thread_id, num_regs); } -static int riot_get_symbol_list_to_lookup(symbol_table_elem_t *symbol_list[]) +static int riot_get_symbol_list_to_lookup(struct symbol_table_elem *symbol_list[]) { - *symbol_list = calloc(ARRAY_SIZE(riot_symbol_list), sizeof(symbol_table_elem_t)); + *symbol_list = calloc(ARRAY_SIZE(riot_symbol_list), sizeof(struct symbol_table_elem)); if (*symbol_list == NULL) { LOG_ERROR("RIOT: out of memory"); diff --git a/src/rtos/rtos.c b/src/rtos/rtos.c index 9a470c64a..8e1b7e972 100644 --- a/src/rtos/rtos.c +++ b/src/rtos/rtos.c @@ -184,9 +184,9 @@ int gdb_thread_packet(struct connection *connection, char const *packet, int pac return target->rtos->gdb_thread_packet(connection, packet, packet_size); } -static symbol_table_elem_t *next_symbol(struct rtos *os, char *cur_symbol, uint64_t cur_addr) +static struct symbol_table_elem *next_symbol(struct rtos *os, char *cur_symbol, uint64_t cur_addr) { - symbol_table_elem_t *s; + struct symbol_table_elem *s; if (!os->symbols) os->type->get_symbol_list_to_lookup(&os->symbols); @@ -208,7 +208,7 @@ static symbol_table_elem_t *next_symbol(struct rtos *os, char *cur_symbol, uint6 * if 'symbol' is not declared optional */ static bool is_symbol_mandatory(const struct rtos *os, const char *symbol) { - for (symbol_table_elem_t *s = os->symbols; s->symbol_name; ++s) { + for (struct symbol_table_elem *s = os->symbols; s->symbol_name; ++s) { if (!strcmp(s->symbol_name, symbol)) return !s->optional; } @@ -240,7 +240,7 @@ int rtos_qsymbol(struct connection *connection, char const *packet, int packet_s uint64_t addr = 0; size_t reply_len; char reply[GDB_BUFFER_SIZE + 1], cur_sym[GDB_BUFFER_SIZE / 2 + 1] = ""; /* Extra byte for null-termination */ - symbol_table_elem_t *next_sym = NULL; + struct symbol_table_elem *next_sym = NULL; struct target *target = get_target_from_connection(connection); struct rtos *os = target->rtos; diff --git a/src/rtos/rtos.h b/src/rtos/rtos.h index 9d8ccfe4a..7609a9f4f 100644 --- a/src/rtos/rtos.h +++ b/src/rtos/rtos.h @@ -31,11 +31,11 @@ struct reg; /** * Table should be terminated by an element with NULL in symbol_name */ -typedef struct symbol_table_elem_struct { +struct symbol_table_elem { const char *symbol_name; symbol_address_t address; bool optional; -} symbol_table_elem_t; +}; struct thread_detail { threadid_t threadid; @@ -47,7 +47,7 @@ struct thread_detail { struct rtos { const struct rtos_type *type; - symbol_table_elem_t *symbols; + struct symbol_table_elem *symbols; struct target *target; /* add a context variable instead of global variable */ /* The thread currently selected by gdb. */ @@ -81,7 +81,7 @@ struct rtos_type { struct rtos_reg **reg_list, int *num_regs); int (*get_thread_reg)(struct rtos *rtos, threadid_t thread_id, uint32_t reg_num, struct rtos_reg *reg); - int (*get_symbol_list_to_lookup)(symbol_table_elem_t *symbol_list[]); + int (*get_symbol_list_to_lookup)(struct symbol_table_elem *symbol_list[]); int (*clean)(struct target *target); char * (*ps_command)(struct target *target); int (*set_reg)(struct rtos *rtos, uint32_t reg_num, uint8_t *reg_value); diff --git a/src/rtos/uCOS-III.c b/src/rtos/uCOS-III.c index 304d07c59..d62a2199b 100644 --- a/src/rtos/uCOS-III.c +++ b/src/rtos/uCOS-III.c @@ -508,9 +508,9 @@ static int uCOS_III_get_thread_reg_list(struct rtos *rtos, threadid_t threadid, num_regs); } -static int uCOS_III_get_symbol_list_to_lookup(symbol_table_elem_t *symbol_list[]) +static int uCOS_III_get_symbol_list_to_lookup(struct symbol_table_elem *symbol_list[]) { - *symbol_list = calloc(ARRAY_SIZE(uCOS_III_symbol_list), sizeof(symbol_table_elem_t)); + *symbol_list = calloc(ARRAY_SIZE(uCOS_III_symbol_list), sizeof(struct symbol_table_elem)); if (*symbol_list == NULL) { LOG_ERROR("uCOS-III: out of memory"); return ERROR_FAIL; diff --git a/src/server/gdb_server.c b/src/server/gdb_server.c index ac00dd008..d9f5d08fa 100644 --- a/src/server/gdb_server.c +++ b/src/server/gdb_server.c @@ -726,7 +726,7 @@ static void gdb_signal_reply(struct target *target, struct connection *connectio { struct gdb_connection *gdb_connection = connection->priv; char sig_reply[65]; - char stop_reason[20]; + char stop_reason[32]; char current_thread[25]; int sig_reply_len; int signal_var; @@ -3617,7 +3617,7 @@ static int gdb_target_start(struct target *target, const char *port) ret = add_service("gdb", port, target->gdb_max_connections, &gdb_new_connection, &gdb_input, - &gdb_connection_closed, gdb_service, NULL); + &gdb_connection_closed, gdb_service); /* initialize all targets gdb service with the same pointer */ { struct target_list *head; diff --git a/src/server/rtt_server.c b/src/server/rtt_server.c index 3c885cce0..d49e4d000 100644 --- a/src/server/rtt_server.c +++ b/src/server/rtt_server.c @@ -126,7 +126,7 @@ COMMAND_HANDLER(handle_rtt_start_command) COMMAND_PARSE_NUMBER(uint, CMD_ARGV[1], service->channel); ret = add_service("rtt", CMD_ARGV[0], CONNECTION_LIMIT_UNLIMITED, - rtt_new_connection, rtt_input, rtt_connection_closed, service, NULL); + rtt_new_connection, rtt_input, rtt_connection_closed, service); if (ret != ERROR_OK) { free(service); diff --git a/src/server/server.c b/src/server/server.c index 4de98891c..d47b81223 100644 --- a/src/server/server.c +++ b/src/server/server.c @@ -211,8 +211,7 @@ int add_service(char *name, new_connection_handler_t new_connection_handler, input_handler_t input_handler, connection_closed_handler_t connection_closed_handler, - void *priv, - struct service **new_service) + void *priv) { struct service *c, **p; struct hostent *hp; @@ -348,10 +347,6 @@ int add_service(char *name, ; *p = c; - /* if new_service is not NULL, return the created service into it */ - if (new_service) - *new_service = c; - return ERROR_OK; } diff --git a/src/server/server.h b/src/server/server.h index 4ae6e95d4..de18d2b4b 100644 --- a/src/server/server.h +++ b/src/server/server.h @@ -78,7 +78,7 @@ struct service { int add_service(char *name, const char *port, int max_connections, new_connection_handler_t new_connection_handler, input_handler_t in_handler, connection_closed_handler_t close_handler, - void *priv, struct service **new_service); + void *priv); int remove_service(const char *name, const char *port); int server_host_os_entry(void); diff --git a/src/server/tcl_server.c b/src/server/tcl_server.c index 07213ae79..1ecb827a1 100644 --- a/src/server/tcl_server.c +++ b/src/server/tcl_server.c @@ -285,7 +285,7 @@ int tcl_init(void) return add_service("tcl", tcl_port, CONNECTION_LIMIT_UNLIMITED, &tcl_new_connection, &tcl_input, - &tcl_closed, NULL, NULL); + &tcl_closed, NULL); } COMMAND_HANDLER(handle_tcl_port_command) diff --git a/src/server/telnet_server.c b/src/server/telnet_server.c index 4f88d3a54..e9de4f033 100644 --- a/src/server/telnet_server.c +++ b/src/server/telnet_server.c @@ -596,6 +596,12 @@ static int telnet_input(struct connection *connection) telnet_history_up(connection); } else if (*buf_p == 'B') { /* cursor down */ telnet_history_down(connection); + } else if (*buf_p == 'F') { /* end key */ + telnet_move_cursor(connection, t_con->line_size); + t_con->state = TELNET_STATE_DATA; + } else if (*buf_p == 'H') { /* home key */ + telnet_move_cursor(connection, 0); + t_con->state = TELNET_STATE_DATA; } else if (*buf_p == '3') t_con->last_escape = *buf_p; else @@ -694,7 +700,7 @@ int telnet_init(char *banner) int ret = add_service("telnet", telnet_port, CONNECTION_LIMIT_UNLIMITED, telnet_new_connection, telnet_input, telnet_connection_closed, - telnet_service, NULL); + telnet_service); if (ret != ERROR_OK) { free(telnet_service); diff --git a/src/target/Makefile.am b/src/target/Makefile.am index 1d30747b6..34a78517a 100644 --- a/src/target/Makefile.am +++ b/src/target/Makefile.am @@ -1,9 +1,3 @@ -if OOCD_TRACE -OOCD_TRACE_FILES = %D%/oocd_trace.c -else -OOCD_TRACE_FILES = -endif - %C%_libtarget_la_LIBADD = %D%/openrisc/libopenrisc.la \ %D%/riscv/libriscv.la @@ -111,8 +105,8 @@ ARM_DEBUG_SRC = \ %D%/trace.c \ %D%/etb.c \ %D%/etm.c \ - $(OOCD_TRACE_FILES) \ %D%/etm_dummy.c \ + %D%/arm_tpiu_swo.c \ %D%/arm_cti.c AVR32_SRC = \ @@ -214,6 +208,7 @@ ARC_SRC = \ %D%/etb.h \ %D%/etm.h \ %D%/etm_dummy.h \ + %D%/arm_tpiu_swo.h \ %D%/image.h \ %D%/mips32.h \ %D%/mips64.h \ @@ -223,7 +218,6 @@ ARC_SRC = \ %D%/mips32_pracc.h \ %D%/mips32_dmaacc.h \ %D%/mips64_pracc.h \ - %D%/oocd_trace.h \ %D%/register.h \ %D%/target.h \ %D%/target_type.h \ diff --git a/src/target/aarch64.c b/src/target/aarch64.c index d111a0568..d6b12cd59 100644 --- a/src/target/aarch64.c +++ b/src/target/aarch64.c @@ -1651,7 +1651,6 @@ static int aarch64_add_hybrid_breakpoint(struct target *target, return aarch64_set_hybrid_breakpoint(target, breakpoint); /* ??? */ } - static int aarch64_remove_breakpoint(struct target *target, struct breakpoint *breakpoint) { struct aarch64_common *aarch64 = target_to_aarch64(target); @@ -1673,26 +1672,307 @@ static int aarch64_remove_breakpoint(struct target *target, struct breakpoint *b return ERROR_OK; } +/* Setup hardware Watchpoint Register Pair */ +static int aarch64_set_watchpoint(struct target *target, + struct watchpoint *watchpoint) +{ + int retval; + int wp_i = 0; + uint32_t control, offset, length; + struct aarch64_common *aarch64 = target_to_aarch64(target); + struct armv8_common *armv8 = &aarch64->armv8_common; + struct aarch64_brp *wp_list = aarch64->wp_list; + + if (watchpoint->set) { + LOG_WARNING("watchpoint already set"); + return ERROR_OK; + } + + while (wp_list[wp_i].used && (wp_i < aarch64->wp_num)) + wp_i++; + if (wp_i >= aarch64->wp_num) { + LOG_ERROR("ERROR Can not find free Watchpoint Register Pair"); + return ERROR_TARGET_RESOURCE_NOT_AVAILABLE; + } + + control = (1 << 0) /* enable */ + | (3 << 1) /* both user and privileged access */ + | (1 << 13); /* higher mode control */ + + switch (watchpoint->rw) { + case WPT_READ: + control |= 1 << 3; + break; + case WPT_WRITE: + control |= 2 << 3; + break; + case WPT_ACCESS: + control |= 3 << 3; + break; + } + + /* Match up to 8 bytes. */ + offset = watchpoint->address & 7; + length = watchpoint->length; + if (offset + length > sizeof(uint64_t)) { + length = sizeof(uint64_t) - offset; + LOG_WARNING("Adjust watchpoint match inside 8-byte boundary"); + } + for (; length > 0; offset++, length--) + control |= (1 << offset) << 5; + + wp_list[wp_i].value = watchpoint->address & 0xFFFFFFFFFFFFFFF8ULL; + wp_list[wp_i].control = control; + + retval = aarch64_dap_write_memap_register_u32(target, armv8->debug_base + + CPUV8_DBG_WVR_BASE + 16 * wp_list[wp_i].BRPn, + (uint32_t)(wp_list[wp_i].value & 0xFFFFFFFF)); + if (retval != ERROR_OK) + return retval; + retval = aarch64_dap_write_memap_register_u32(target, armv8->debug_base + + CPUV8_DBG_WVR_BASE + 4 + 16 * wp_list[wp_i].BRPn, + (uint32_t)(wp_list[wp_i].value >> 32)); + if (retval != ERROR_OK) + return retval; + + retval = aarch64_dap_write_memap_register_u32(target, armv8->debug_base + + CPUV8_DBG_WCR_BASE + 16 * wp_list[wp_i].BRPn, + control); + if (retval != ERROR_OK) + return retval; + LOG_DEBUG("wp %i control 0x%0" PRIx32 " value 0x%" TARGET_PRIxADDR, wp_i, + wp_list[wp_i].control, wp_list[wp_i].value); + + /* Ensure that halting debug mode is enable */ + retval = aarch64_set_dscr_bits(target, DSCR_HDE, DSCR_HDE); + if (retval != ERROR_OK) { + LOG_DEBUG("Failed to set DSCR.HDE"); + return retval; + } + + wp_list[wp_i].used = 1; + watchpoint->set = wp_i + 1; + + return ERROR_OK; +} + +/* Clear hardware Watchpoint Register Pair */ +static int aarch64_unset_watchpoint(struct target *target, + struct watchpoint *watchpoint) +{ + int retval, wp_i; + struct aarch64_common *aarch64 = target_to_aarch64(target); + struct armv8_common *armv8 = &aarch64->armv8_common; + struct aarch64_brp *wp_list = aarch64->wp_list; + + if (!watchpoint->set) { + LOG_WARNING("watchpoint not set"); + return ERROR_OK; + } + + wp_i = watchpoint->set - 1; + if ((wp_i < 0) || (wp_i >= aarch64->wp_num)) { + LOG_DEBUG("Invalid WP number in watchpoint"); + return ERROR_OK; + } + LOG_DEBUG("rwp %i control 0x%0" PRIx32 " value 0x%0" PRIx64, wp_i, + wp_list[wp_i].control, wp_list[wp_i].value); + wp_list[wp_i].used = 0; + wp_list[wp_i].value = 0; + wp_list[wp_i].control = 0; + retval = aarch64_dap_write_memap_register_u32(target, armv8->debug_base + + CPUV8_DBG_WCR_BASE + 16 * wp_list[wp_i].BRPn, + wp_list[wp_i].control); + if (retval != ERROR_OK) + return retval; + retval = aarch64_dap_write_memap_register_u32(target, armv8->debug_base + + CPUV8_DBG_WVR_BASE + 16 * wp_list[wp_i].BRPn, + wp_list[wp_i].value); + if (retval != ERROR_OK) + return retval; + + retval = aarch64_dap_write_memap_register_u32(target, armv8->debug_base + + CPUV8_DBG_WVR_BASE + 4 + 16 * wp_list[wp_i].BRPn, + (uint32_t)wp_list[wp_i].value); + if (retval != ERROR_OK) + return retval; + watchpoint->set = 0; + + return ERROR_OK; +} + +static int aarch64_add_watchpoint(struct target *target, + struct watchpoint *watchpoint) +{ + int retval; + struct aarch64_common *aarch64 = target_to_aarch64(target); + + if (aarch64->wp_num_available < 1) { + LOG_INFO("no hardware watchpoint available"); + return ERROR_TARGET_RESOURCE_NOT_AVAILABLE; + } + + retval = aarch64_set_watchpoint(target, watchpoint); + if (retval == ERROR_OK) + aarch64->wp_num_available--; + + return retval; +} + +static int aarch64_remove_watchpoint(struct target *target, + struct watchpoint *watchpoint) +{ + struct aarch64_common *aarch64 = target_to_aarch64(target); + + if (watchpoint->set) { + aarch64_unset_watchpoint(target, watchpoint); + aarch64->wp_num_available++; + } + + return ERROR_OK; +} + +/** + * find out which watchpoint hits + * get exception address and compare the address to watchpoints + */ +int aarch64_hit_watchpoint(struct target *target, + struct watchpoint **hit_watchpoint) +{ + if (target->debug_reason != DBG_REASON_WATCHPOINT) + return ERROR_FAIL; + + struct armv8_common *armv8 = target_to_armv8(target); + + uint64_t exception_address; + struct watchpoint *wp; + + exception_address = armv8->dpm.wp_pc; + + if (exception_address == 0xFFFFFFFF) + return ERROR_FAIL; + + /**********************************************************/ + /* see if a watchpoint address matches a value read from */ + /* the EDWAR register. Testing shows that on some ARM CPUs*/ + /* the EDWAR value needs to have 8 added to it so we add */ + /* that check as well not sure if that is a core bug) */ + /**********************************************************/ + for (exception_address = armv8->dpm.wp_pc; exception_address <= (armv8->dpm.wp_pc + 8); + exception_address += 8) { + for (wp = target->watchpoints; wp; wp = wp->next) { + if ((exception_address >= wp->address) && (exception_address < (wp->address + wp->length))) { + *hit_watchpoint = wp; + if (exception_address != armv8->dpm.wp_pc) + LOG_DEBUG("watchpoint hit required EDWAR to be increased by 8"); + return ERROR_OK; + } + } + } + + return ERROR_FAIL; +} + /* * Cortex-A8 Reset functions */ +static int aarch64_enable_reset_catch(struct target *target, bool enable) +{ + struct armv8_common *armv8 = target_to_armv8(target); + uint32_t edecr; + int retval; + + retval = mem_ap_read_atomic_u32(armv8->debug_ap, + armv8->debug_base + CPUV8_DBG_EDECR, &edecr); + LOG_DEBUG("EDECR = 0x%08" PRIx32 ", enable=%d", edecr, enable); + if (retval != ERROR_OK) + return retval; + + if (enable) + edecr |= ECR_RCE; + else + edecr &= ~ECR_RCE; + + return mem_ap_write_atomic_u32(armv8->debug_ap, + armv8->debug_base + CPUV8_DBG_EDECR, edecr); +} + +static int aarch64_clear_reset_catch(struct target *target) +{ + struct armv8_common *armv8 = target_to_armv8(target); + uint32_t edesr; + int retval; + bool was_triggered; + + /* check if Reset Catch debug event triggered as expected */ + retval = mem_ap_read_atomic_u32(armv8->debug_ap, + armv8->debug_base + CPUV8_DBG_EDESR, &edesr); + if (retval != ERROR_OK) + return retval; + + was_triggered = !!(edesr & ESR_RC); + LOG_DEBUG("Reset Catch debug event %s", + was_triggered ? "triggered" : "NOT triggered!"); + + if (was_triggered) { + /* clear pending Reset Catch debug event */ + edesr &= ~ESR_RC; + retval = mem_ap_write_atomic_u32(armv8->debug_ap, + armv8->debug_base + CPUV8_DBG_EDESR, edesr); + if (retval != ERROR_OK) + return retval; + } + + return ERROR_OK; +} + static int aarch64_assert_reset(struct target *target) { struct armv8_common *armv8 = target_to_armv8(target); + enum reset_types reset_config = jtag_get_reset_config(); + int retval; LOG_DEBUG(" "); - /* FIXME when halt is requested, make it work somehow... */ - /* Issue some kind of warm reset. */ if (target_has_event_action(target, TARGET_EVENT_RESET_ASSERT)) target_handle_event(target, TARGET_EVENT_RESET_ASSERT); - else if (jtag_get_reset_config() & RESET_HAS_SRST) { + else if (reset_config & RESET_HAS_SRST) { + bool srst_asserted = false; + + if (target->reset_halt) { + if (target_was_examined(target)) { + + if (reset_config & RESET_SRST_NO_GATING) { + /* + * SRST needs to be asserted *before* Reset Catch + * debug event can be set up. + */ + adapter_assert_reset(); + srst_asserted = true; + + /* make sure to clear all sticky errors */ + mem_ap_write_atomic_u32(armv8->debug_ap, + armv8->debug_base + CPUV8_DBG_DRCR, DRCR_CSE); + } + + /* set up Reset Catch debug event to halt the CPU after reset */ + retval = aarch64_enable_reset_catch(target, true); + if (retval != ERROR_OK) + LOG_WARNING("%s: Error enabling Reset Catch debug event; the CPU will not halt immediately after reset!", + target_name(target)); + } else { + LOG_WARNING("%s: Target not examined, will not halt immediately after reset!", + target_name(target)); + } + } + /* REVISIT handle "pulls" cases, if there's * hardware that needs them to work. */ - adapter_assert_reset(); + if (!srst_asserted) + adapter_assert_reset(); } else { LOG_ERROR("%s: how to reset?", target_name(target)); return ERROR_FAIL; @@ -1721,23 +2001,37 @@ static int aarch64_deassert_reset(struct target *target) if (!target_was_examined(target)) return ERROR_OK; - retval = aarch64_poll(target); - if (retval != ERROR_OK) - return retval; - retval = aarch64_init_debug_access(target); if (retval != ERROR_OK) return retval; + retval = aarch64_poll(target); + if (retval != ERROR_OK) + return retval; + if (target->reset_halt) { + /* clear pending Reset Catch debug event */ + retval = aarch64_clear_reset_catch(target); + if (retval != ERROR_OK) + LOG_WARNING("%s: Clearing Reset Catch debug event failed", + target_name(target)); + + /* disable Reset Catch debug event */ + retval = aarch64_enable_reset_catch(target, false); + if (retval != ERROR_OK) + LOG_WARNING("%s: Disabling Reset Catch debug event failed", + target_name(target)); + if (target->state != TARGET_HALTED) { LOG_WARNING("%s: ran after reset and before halt ...", target_name(target)); retval = target_halt(target); + if (retval != ERROR_OK) + return retval; } } - return retval; + return ERROR_OK; } static int aarch64_write_cpu_memory_slow(struct target *target, @@ -2367,7 +2661,20 @@ static int aarch64_examine_first(struct target *target) aarch64->brp_list[i].BRPn = i; } - LOG_DEBUG("Configured %i hw breakpoints", aarch64->brp_num); + /* Setup Watchpoint Register Pairs */ + aarch64->wp_num = (uint32_t)((debug >> 20) & 0x0F) + 1; + aarch64->wp_num_available = aarch64->wp_num; + aarch64->wp_list = calloc(aarch64->wp_num, sizeof(struct aarch64_brp)); + for (i = 0; i < aarch64->wp_num; i++) { + aarch64->wp_list[i].used = 0; + aarch64->wp_list[i].type = BRP_NORMAL; + aarch64->wp_list[i].value = 0; + aarch64->wp_list[i].control = 0; + aarch64->wp_list[i].BRPn = i; + } + + LOG_DEBUG("Configured %i hw breakpoints, %i watchpoints", + aarch64->brp_num, aarch64->wp_num); target->state = TARGET_UNKNOWN; target->debug_reason = DBG_REASON_NOTHALTED; @@ -2883,8 +3190,9 @@ struct target_type aarch64_target = { .add_context_breakpoint = aarch64_add_context_breakpoint, .add_hybrid_breakpoint = aarch64_add_hybrid_breakpoint, .remove_breakpoint = aarch64_remove_breakpoint, - .add_watchpoint = NULL, - .remove_watchpoint = NULL, + .add_watchpoint = aarch64_add_watchpoint, + .remove_watchpoint = aarch64_remove_watchpoint, + .hit_watchpoint = aarch64_hit_watchpoint, .commands = aarch64_command_handlers, .target_create = aarch64_target_create, diff --git a/src/target/aarch64.h b/src/target/aarch64.h index d7886a3d7..7c0ddf868 100644 --- a/src/target/aarch64.h +++ b/src/target/aarch64.h @@ -62,6 +62,11 @@ struct aarch64_common { int brp_num_available; struct aarch64_brp *brp_list; + /* Watchpoint register pairs */ + int wp_num; + int wp_num_available; + struct aarch64_brp *wp_list; + struct armv8_common armv8_common; enum aarch64_isrmasking_mode isrmasking_mode; diff --git a/src/target/arc.c b/src/target/arc.c index 8e568455e..694ac6f85 100644 --- a/src/target/arc.c +++ b/src/target/arc.c @@ -227,7 +227,7 @@ static int arc_get_register(struct reg *reg) if (desc->is_core) { /* Accessing to R61/R62 registers causes Jtag hang */ - if (desc->arch_num == CORE_R61_NUM || desc->arch_num == CORE_R62_NUM) { + if (desc->arch_num == ARC_R61 || desc->arch_num == ARC_R62) { LOG_ERROR("It is forbidden to read core registers 61 and 62."); return ERROR_FAIL; } @@ -267,8 +267,8 @@ static int arc_set_register(struct reg *reg, uint8_t *buf) return ERROR_TARGET_NOT_HALTED; /* Accessing to R61/R62 registers causes Jtag hang */ - if (desc->is_core && (desc->arch_num == CORE_R61_NUM || - desc->arch_num == CORE_R62_NUM)) { + if (desc->is_core && (desc->arch_num == ARC_R61 || + desc->arch_num == ARC_R62)) { LOG_ERROR("It is forbidden to write core registers 61 and 62."); return ERROR_FAIL; } diff --git a/src/target/arc.h b/src/target/arc.h index aeb326cb5..8d44bfa41 100644 --- a/src/target/arc.h +++ b/src/target/arc.h @@ -45,9 +45,52 @@ #define AUX_STATUS32_REG_HALT_BIT BIT(0) #define AUX_STATUS32_REG_IE_BIT BIT(31) /* STATUS32[31] = IE field */ -/* Reserved core registers */ -#define CORE_R61_NUM (61) -#define CORE_R62_NUM (62) +/* ARC register numbers */ +enum { + ARC_R0, + ARC_R1, + ARC_R2, + ARC_R3, + ARC_R4, + ARC_R5, + ARC_R6, + ARC_R7, + ARC_R8, + ARC_R9, + ARC_R10, + ARC_R11, + ARC_R12, + ARC_R13, + ARC_R14, + ARC_R15, + ARC_R16, + ARC_R17, + ARC_R18, + ARC_R19, + ARC_R20, + ARC_R21, + ARC_R22, + ARC_R23, + ARC_R24, + ARC_R25, + ARC_GP = 26, + ARC_FP = 27, + ARC_SP = 28, + ARC_ILINK = 29, + ARC_R30, + ARC_BLINK = 31, + ARC_LP_COUNT = 60, + + /* Reserved registers */ + ARC_R61 = 61, + ARC_R62 = 62, + + ARC_PCL = 63, + ARC_PC = 64, + ARC_LP_START = 65, + ARC_LP_END = 66, + ARC_STATUS32 = 67, +}; #define CORE_REG_MAX_NUMBER (63) diff --git a/src/target/arc_cmd.c b/src/target/arc_cmd.c index 18f5cb8f4..5c5247b88 100644 --- a/src/target/arc_cmd.c +++ b/src/target/arc_cmd.c @@ -382,7 +382,7 @@ static int jim_arc_get_core_reg(Jim_Interp *interp, int argc, Jim_Obj * const *a /* Register number */ JIM_CHECK_RETVAL(arc_cmd_jim_get_uint32(&goi, ®num)); - if (regnum > CORE_REG_MAX_NUMBER || regnum == CORE_R61_NUM || regnum == CORE_R62_NUM) { + if (regnum > CORE_REG_MAX_NUMBER || regnum == ARC_R61 || regnum == ARC_R62) { Jim_SetResultFormatted(goi.interp, "Core register number %i " "is invalid. Must less then 64 and not 61 and 62.", regnum); return JIM_ERR; @@ -425,7 +425,7 @@ static int jim_arc_set_core_reg(Jim_Interp *interp, int argc, Jim_Obj * const *a /* Register number */ JIM_CHECK_RETVAL(arc_cmd_jim_get_uint32(&goi, ®num)); - if (regnum > CORE_REG_MAX_NUMBER || regnum == CORE_R61_NUM || regnum == CORE_R62_NUM) { + if (regnum > CORE_REG_MAX_NUMBER || regnum == ARC_R61 || regnum == ARC_R62) { Jim_SetResultFormatted(goi.interp, "Core register number %i " "is invalid. Must less then 64 and not 61 and 62.", regnum); return JIM_ERR; diff --git a/src/target/arm11_dbgtap.c b/src/target/arm11_dbgtap.c index 60be0096f..823ce5cc1 100644 --- a/src/target/arm11_dbgtap.c +++ b/src/target/arm11_dbgtap.c @@ -562,11 +562,7 @@ static const tap_state_t arm11_MOVE_DRPAUSE_IDLE_DRPAUSE_with_delay[] = { TAP_DRSHIFT }; -/* This inner loop can be implemented by the minidriver, oftentimes in hardware... The - * minidriver can call the default implementation as a fallback or implement it - * from scratch. - */ -int arm11_run_instr_data_to_core_noack_inner_default(struct jtag_tap *tap, +static int arm11_run_instr_data_to_core_noack_inner(struct jtag_tap *tap, uint32_t opcode, uint32_t *data, size_t count) @@ -629,21 +625,6 @@ int arm11_run_instr_data_to_core_noack_inner_default(struct jtag_tap *tap, return retval; } -int arm11_run_instr_data_to_core_noack_inner(struct jtag_tap *tap, - uint32_t opcode, - uint32_t *data, - size_t count); - -#ifndef HAVE_JTAG_MINIDRIVER_H -int arm11_run_instr_data_to_core_noack_inner(struct jtag_tap *tap, - uint32_t opcode, - uint32_t *data, - size_t count) -{ - return arm11_run_instr_data_to_core_noack_inner_default(tap, opcode, data, count); -} -#endif - /** Execute one instruction via ITR repeatedly while * passing data to the core via DTR on each execution. * diff --git a/src/target/arm720t.c b/src/target/arm720t.c index e04cab2e7..daa44e46a 100644 --- a/src/target/arm720t.c +++ b/src/target/arm720t.c @@ -233,16 +233,6 @@ static void arm720t_pre_restore_context(struct target *target) arm720t_write_cp15(target, 0xee060f10, arm720t->far_reg); } -static int arm720t_verify_pointer(struct command_invocation *cmd, - struct arm720t_common *arm720t) -{ - if (arm720t->common_magic != ARM720T_COMMON_MAGIC) { - command_print(cmd, "target is not an ARM720"); - return ERROR_TARGET_INVALID; - } - return ERROR_OK; -} - static int arm720t_arch_state(struct target *target) { struct arm720t_common *arm720t = target_to_arm720(target); @@ -441,55 +431,6 @@ static int arm720t_target_create(struct target *target, Jim_Interp *interp) return arm720t_init_arch_info(target, arm720t, target->tap); } -COMMAND_HANDLER(arm720t_handle_cp15_command) -{ - int retval; - struct target *target = get_current_target(CMD_CTX); - struct arm720t_common *arm720t = target_to_arm720(target); - - retval = arm720t_verify_pointer(CMD, arm720t); - if (retval != ERROR_OK) - return retval; - - if (target->state != TARGET_HALTED) { - command_print(CMD, "target must be stopped for \"%s\" command", CMD_NAME); - return ERROR_OK; - } - - /* one or more argument, access a single register (write if second argument is given */ - if (CMD_ARGC >= 1) { - uint32_t opcode; - COMMAND_PARSE_NUMBER(u32, CMD_ARGV[0], opcode); - - if (CMD_ARGC == 1) { - uint32_t value; - retval = arm720t_read_cp15(target, opcode, &value); - if (retval != ERROR_OK) { - command_print(CMD, "couldn't access cp15 with opcode 0x%8.8" PRIx32 "", opcode); - return ERROR_OK; - } - - retval = jtag_execute_queue(); - if (retval != ERROR_OK) - return retval; - - command_print(CMD, "0x%8.8" PRIx32 ": 0x%8.8" PRIx32 "", opcode, value); - } else if (CMD_ARGC == 2) { - uint32_t value; - COMMAND_PARSE_NUMBER(u32, CMD_ARGV[1], value); - - retval = arm720t_write_cp15(target, opcode, value); - if (retval != ERROR_OK) { - command_print(CMD, "couldn't access cp15 with opcode 0x%8.8" PRIx32 "", opcode); - return ERROR_OK; - } - command_print(CMD, "0x%8.8" PRIx32 ": 0x%8.8" PRIx32 "", opcode, value); - } - } - - return ERROR_OK; -} - static int arm720t_mrc(struct target *target, int cpnum, uint32_t op1, uint32_t op2, uint32_t CRn, uint32_t CRm, @@ -523,30 +464,10 @@ static int arm720t_mcr(struct target *target, int cpnum, value); } -static const struct command_registration arm720t_exec_command_handlers[] = { - { - .name = "cp15", - .handler = arm720t_handle_cp15_command, - .mode = COMMAND_EXEC, - /* prefer using less error-prone "arm mcr" or "arm mrc" */ - .help = "display/modify cp15 register using ARM opcode" - " (DEPRECATED)", - .usage = "instruction [value]", - }, - COMMAND_REGISTRATION_DONE -}; - static const struct command_registration arm720t_command_handlers[] = { { .chain = arm7_9_command_handlers, }, - { - .name = "arm720t", - .mode = COMMAND_ANY, - .help = "arm720t command group", - .usage = "", - .chain = arm720t_exec_command_handlers, - }, COMMAND_REGISTRATION_DONE }; diff --git a/src/target/arm920t.c b/src/target/arm920t.c index c96975a77..a45dc6420 100644 --- a/src/target/arm920t.c +++ b/src/target/arm920t.c @@ -245,8 +245,8 @@ static int arm920t_read_cp15_interpreted(struct target *target, uint32_t cp15_opcode, uint32_t address, uint32_t *value) { struct arm *arm = target_to_arm(target); - uint32_t *regs_p[1]; - uint32_t regs[2]; + uint32_t *regs_p[16]; + uint32_t regs[16]; uint32_t cp15c15 = 0x0; struct reg *r = arm->core_cache->reg_list; @@ -295,7 +295,7 @@ int arm920t_write_cp15_interpreted(struct target *target, { uint32_t cp15c15 = 0x0; struct arm *arm = target_to_arm(target); - uint32_t regs[2]; + uint32_t regs[16]; struct reg *r = arm->core_cache->reg_list; /* load value, address into R0, R1 */ @@ -1511,80 +1511,6 @@ COMMAND_HANDLER(arm920t_handle_cp15_command) return ERROR_OK; } -COMMAND_HANDLER(arm920t_handle_cp15i_command) -{ - int retval; - struct target *target = get_current_target(CMD_CTX); - struct arm920t_common *arm920t = target_to_arm920(target); - - retval = arm920t_verify_pointer(CMD, arm920t); - if (retval != ERROR_OK) - return retval; - - - if (target->state != TARGET_HALTED) { - command_print(CMD, "target must be stopped for " - "\"%s\" command", CMD_NAME); - return ERROR_OK; - } - - /* one argument, read a register. - * two arguments, write it. - */ - if (CMD_ARGC >= 1) { - uint32_t opcode; - COMMAND_PARSE_NUMBER(u32, CMD_ARGV[0], opcode); - - if (CMD_ARGC == 1) { - uint32_t value; - retval = arm920t_read_cp15_interpreted(target, - opcode, 0x0, &value); - if (retval != ERROR_OK) { - command_print(CMD, - "couldn't execute %8.8" PRIx32, - opcode); - /* REVISIT why lie? "return retval"? */ - return ERROR_OK; - } - - command_print(CMD, "%8.8" PRIx32 ": %8.8" PRIx32, - opcode, value); - } else if (CMD_ARGC == 2) { - uint32_t value; - COMMAND_PARSE_NUMBER(u32, CMD_ARGV[1], value); - retval = arm920t_write_cp15_interpreted(target, - opcode, value, 0); - if (retval != ERROR_OK) { - command_print(CMD, - "couldn't execute %8.8" PRIx32, - opcode); - /* REVISIT why lie? "return retval"? */ - return ERROR_OK; - } - command_print(CMD, "%8.8" PRIx32 ": %8.8" PRIx32, - opcode, value); - } else if (CMD_ARGC == 3) { - uint32_t value; - COMMAND_PARSE_NUMBER(u32, CMD_ARGV[1], value); - uint32_t address; - COMMAND_PARSE_NUMBER(u32, CMD_ARGV[2], address); - retval = arm920t_write_cp15_interpreted(target, - opcode, value, address); - if (retval != ERROR_OK) { - command_print(CMD, - "couldn't execute %8.8" PRIx32, opcode); - /* REVISIT why lie? "return retval"? */ - return ERROR_OK; - } - command_print(CMD, "%8.8" PRIx32 ": %8.8" PRIx32 - " %8.8" PRIx32, opcode, value, address); - } - } else - return ERROR_COMMAND_SYNTAX_ERROR; - - return ERROR_OK; -} - COMMAND_HANDLER(arm920t_handle_cache_info_command) { int retval; @@ -1640,15 +1566,6 @@ static const struct command_registration arm920t_exec_command_handlers[] = { .help = "display/modify cp15 register", .usage = "regnum [value]", }, - { - .name = "cp15i", - .handler = arm920t_handle_cp15i_command, - .mode = COMMAND_EXEC, - /* prefer using less error-prone "arm mcr" or "arm mrc" */ - .help = "display/modify cp15 register using ARM opcode" - " (DEPRECATED)", - .usage = "instruction [value [address]]", - }, { .name = "cache_info", .handler = arm920t_handle_cache_info_command, diff --git a/src/target/arm_semihosting.c b/src/target/arm_semihosting.c index 723be577e..9de7048f4 100644 --- a/src/target/arm_semihosting.c +++ b/src/target/arm_semihosting.c @@ -123,6 +123,22 @@ static int post_result(struct target *target) uint64_t pc = buf_get_u64(arm->core_cache->reg_list[32].value, 0, 64); buf_set_u64(arm->pc->value, 0, 64, pc + 4); arm->pc->dirty = true; + } else if (arm->core_state == ARM_STATE_ARM) { + /* return value in R0 */ + buf_set_u32(arm->core_cache->reg_list[0].value, 0, 32, target->semihosting->result); + arm->core_cache->reg_list[0].dirty = true; + + uint32_t pc = buf_get_u32(arm->core_cache->reg_list[32].value, 0, 32); + buf_set_u32(arm->pc->value, 0, 32, pc + 4); + arm->pc->dirty = true; + } else if (arm->core_state == ARM_STATE_THUMB) { + /* return value in R0 */ + buf_set_u32(arm->core_cache->reg_list[0].value, 0, 32, target->semihosting->result); + arm->core_cache->reg_list[0].dirty = true; + + uint32_t pc = buf_get_u32(arm->core_cache->reg_list[32].value, 0, 32); + buf_set_u32(arm->pc->value, 0, 32, pc + 2); + arm->pc->dirty = true; } } else { /* resume execution, this will be pc+2 to skip over the @@ -275,6 +291,16 @@ int arm_semihosting(struct target *target, int *retval) if (target->debug_reason != DBG_REASON_BREAKPOINT) return 0; + /* According to ARM Semihosting for AArch32 and AArch64: + * The HLT encodings are new in version 2.0 of the semihosting specification. + * Where possible, have semihosting callers continue to use the previously + * existing trap instructions to ensure compatibility with legacy semihosting + * implementations. + * These trap instructions are HLT for A64, SVC on A+R profile A32 or T32, + * and BKPT on M profile. + * However, it is necessary to change from SVC to HLT instructions to support + * AArch32 semihosting properly in a mixed AArch32/AArch64 system. */ + if (arm->core_state == ARM_STATE_AARCH64) { uint32_t insn = 0; r = arm->pc; @@ -284,9 +310,38 @@ int arm_semihosting(struct target *target, int *retval) if (*retval != ERROR_OK) return 1; - /* bkpt 0xAB */ + /* HLT 0xF000 */ if (insn != 0xD45E0000) return 0; + } else if (arm->core_state == ARM_STATE_ARM) { + r = arm->pc; + pc = buf_get_u32(arm->pc->value, 0, 32); + + /* A32 instruction => check for HLT 0xF000 (0xE10F0070) */ + uint32_t insn = 0; + + *retval = target_read_u32(target, pc, &insn); + + if (*retval != ERROR_OK) + return 1; + + /* HLT 0xF000*/ + if (insn != 0xE10F0070) + return 0; + } else if (arm->core_state == ARM_STATE_THUMB) { + r = arm->pc; + pc = buf_get_u32(arm->pc->value, 0, 32); + + /* T32 instruction => check for HLT 0x3C (0xBABC) */ + uint16_t insn = 0; + *retval = target_read_u16(target, pc, &insn); + + if (*retval != ERROR_OK) + return 1; + + /* HLT 0x3C*/ + if (insn != 0xBABC) + return 0; } else return 1; } else { diff --git a/src/target/arm_tpiu_swo.c b/src/target/arm_tpiu_swo.c new file mode 100644 index 000000000..2da52e892 --- /dev/null +++ b/src/target/arm_tpiu_swo.c @@ -0,0 +1,1189 @@ +/* SPDX-License-Identifier: GPL-2.0-or-later */ + +/** + * @file + * This file implements support for the ARM CoreSight components Trace Port + * Interface Unit (TPIU) and Serial Wire Output (SWO). It also supports the + * CoreSight TPIU-Lite and the special TPIU version present with Cortex-M3 + * and Cortex-M4 (that includes SWO). + */ + +/* + * Relevant specifications from ARM include: + * + * CoreSight(tm) Components Technical Reference Manual ARM DDI 0314H + * CoreSight(tm) TPIU-Lite Technical Reference Manual ARM DDI 0317A + * Cortex(tm)-M3 Technical Reference Manual ARM DDI 0337G + * Cortex(tm)-M4 Technical Reference Manual ARM DDI 0439B + * CoreSight(tm) SoC-400 Technical Reference Manual ARM DDI 0480F + */ + +#ifdef HAVE_CONFIG_H +#include "config.h" +#endif + +#include +#include + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include "arm_tpiu_swo.h" + +/* START_DEPRECATED_TPIU */ +#include +#include +#define MSG "DEPRECATED \'tpiu config\' command: " +/* END_DEPRECATED_TPIU */ + +#define TCP_SERVICE_NAME "tpiu_swo_trace" + +/* default for Cortex-M3 and Cortex-M4 specific TPIU */ +#define TPIU_SWO_DEFAULT_BASE 0xE0040000 + +#define TPIU_SSPSR_OFFSET 0x000 +#define TPIU_CSPSR_OFFSET 0x004 +#define TPIU_ACPR_OFFSET 0x010 +#define TPIU_SPPR_OFFSET 0x0F0 +#define TPIU_FFSR_OFFSET 0x300 +#define TPIU_FFCR_OFFSET 0x304 +#define TPIU_FSCR_OFFSET 0x308 +#define TPIU_DEVID_OFFSET 0xfc8 + +#define TPIU_ACPR_MAX_PRESCALER 0x1fff +#define TPIU_SPPR_PROTOCOL_SYNC (TPIU_PIN_PROTOCOL_SYNC) +#define TPIU_SPPR_PROTOCOL_MANCHESTER (TPIU_PIN_PROTOCOL_ASYNC_MANCHESTER) +#define TPIU_SPPR_PROTOCOL_UART (TPIU_PIN_PROTOCOL_ASYNC_UART) +#define TPIU_DEVID_NOSUPPORT_SYNC BIT(9) +#define TPIU_DEVID_SUPPORT_MANCHESTER BIT(10) +#define TPIU_DEVID_SUPPORT_UART BIT(11) + +enum arm_tpiu_swo_event { + TPIU_SWO_EVENT_PRE_ENABLE, + TPIU_SWO_EVENT_POST_ENABLE, + TPIU_SWO_EVENT_PRE_DISABLE, + TPIU_SWO_EVENT_POST_DISABLE, +}; + +static const Jim_Nvp nvp_arm_tpiu_swo_event[] = { + { .value = TPIU_SWO_EVENT_PRE_ENABLE, .name = "pre-enable" }, + { .value = TPIU_SWO_EVENT_POST_ENABLE, .name = "post-enable" }, + { .value = TPIU_SWO_EVENT_PRE_DISABLE, .name = "pre-disable" }, + { .value = TPIU_SWO_EVENT_POST_DISABLE, .name = "post-disable" }, +}; + +struct arm_tpiu_swo_event_action { + enum arm_tpiu_swo_event event; + Jim_Interp *interp; + Jim_Obj *body; + struct arm_tpiu_swo_event_action *next; +}; + +struct arm_tpiu_swo_object { + struct list_head lh; + struct adiv5_mem_ap_spot spot; + char *name; + struct arm_tpiu_swo_event_action *event_action; + /* record enable before init */ + bool deferred_enable; + bool enabled; + bool en_capture; + /** Handle to output trace data in INTERNAL capture mode */ + /** Synchronous output port width */ + uint32_t port_width; + FILE *file; + /** output mode */ + unsigned int pin_protocol; + /** Enable formatter */ + bool en_formatter; + /** frequency of TRACECLKIN (usually matches HCLK) */ + unsigned int traceclkin_freq; + /** SWO pin frequency */ + unsigned int swo_pin_freq; + /** where to dump the captured output trace data */ + char *out_filename; + /** track TCP connections */ + struct list_head connections; + /* START_DEPRECATED_TPIU */ + bool recheck_ap_cur_target; + /* END_DEPRECATED_TPIU */ +}; + +struct arm_tpiu_swo_connection { + struct list_head lh; + struct connection *connection; +}; + +struct arm_tpiu_swo_priv_connection { + struct arm_tpiu_swo_object *obj; +}; + +static LIST_HEAD(all_tpiu_swo); + +#define ARM_TPIU_SWO_TRACE_BUF_SIZE 4096 + +static int arm_tpiu_swo_poll_trace(void *priv) +{ + struct arm_tpiu_swo_object *obj = priv; + uint8_t buf[ARM_TPIU_SWO_TRACE_BUF_SIZE]; + size_t size = sizeof(buf); + struct arm_tpiu_swo_connection *c; + + int retval = adapter_poll_trace(buf, &size); + if (retval != ERROR_OK || !size) + return retval; + + target_call_trace_callbacks(/*target*/NULL, size, buf); + + if (obj->file) { + if (fwrite(buf, 1, size, obj->file) == size) { + fflush(obj->file); + } else { + LOG_ERROR("Error writing to the SWO trace destination file"); + return ERROR_FAIL; + } + } + + if (obj->out_filename && obj->out_filename[0] == ':') + list_for_each_entry(c, &obj->connections, lh) + if (connection_write(c->connection, buf, size) != (int)size) + retval = ERROR_FAIL; + + return ERROR_OK; +} + +static void arm_tpiu_swo_handle_event(struct arm_tpiu_swo_object *obj, enum arm_tpiu_swo_event event) +{ + for (struct arm_tpiu_swo_event_action *ea = obj->event_action; ea; ea = ea->next) { + if (ea->event != event) + continue; + + LOG_DEBUG("TPIU/SWO: %s event: %s (%d) action : %s", + obj->name, + Jim_Nvp_value2name_simple(nvp_arm_tpiu_swo_event, event)->name, + event, + Jim_GetString(ea->body, NULL)); + + /* prevent event execution to change current target */ + struct command_context *cmd_ctx = current_command_context(ea->interp); + struct target *saved_target = cmd_ctx->current_target; + int retval = Jim_EvalObj(ea->interp, ea->body); + cmd_ctx->current_target = saved_target; + + if (retval == JIM_RETURN) + retval = ea->interp->returnCode; + if (retval == JIM_OK || retval == ERROR_COMMAND_CLOSE_CONNECTION) + return; + + Jim_MakeErrorMessage(ea->interp); + LOG_USER("Error executing event %s on TPIU/SWO %s:\n%s", + Jim_Nvp_value2name_simple(nvp_arm_tpiu_swo_event, event)->name, + obj->name, + Jim_GetString(Jim_GetResult(ea->interp), NULL)); + /* clean both error code and stacktrace before return */ + Jim_Eval(ea->interp, "error \"\" \"\""); + return; + } +} + +static void arm_tpiu_swo_close_output(struct arm_tpiu_swo_object *obj) +{ + if (obj->file) { + fclose(obj->file); + obj->file = NULL; + } + if (obj->out_filename && obj->out_filename[0] == ':') + remove_service(TCP_SERVICE_NAME, &obj->out_filename[1]); +} + +int arm_tpiu_swo_cleanup_all(void) +{ + struct arm_tpiu_swo_object *obj, *tmp; + + list_for_each_entry_safe(obj, tmp, &all_tpiu_swo, lh) { + if (obj->enabled) + arm_tpiu_swo_handle_event(obj, TPIU_SWO_EVENT_PRE_DISABLE); + + arm_tpiu_swo_close_output(obj); + + if (obj->en_capture) { + target_unregister_timer_callback(arm_tpiu_swo_poll_trace, obj); + + int retval = adapter_config_trace(false, 0, 0, NULL, 0, NULL); + if (retval != ERROR_OK) + LOG_ERROR("Failed to stop adapter's trace"); + } + + if (obj->enabled) + arm_tpiu_swo_handle_event(obj, TPIU_SWO_EVENT_POST_DISABLE); + + struct arm_tpiu_swo_event_action *ea = obj->event_action; + while (ea) { + struct arm_tpiu_swo_event_action *next = ea->next; + Jim_DecrRefCount(ea->interp, ea->body); + free(ea); + ea = next; + } + + free(obj->name); + free(obj->out_filename); + free(obj); + } + + return ERROR_OK; +} + +static int arm_tpiu_swo_service_new_connection(struct connection *connection) +{ + struct arm_tpiu_swo_priv_connection *priv = connection->service->priv; + struct arm_tpiu_swo_object *obj = priv->obj; + struct arm_tpiu_swo_connection *c = malloc(sizeof(*c)); + if (!c) { + LOG_ERROR("Out of memory"); + return ERROR_FAIL; + } + c->connection = connection; + list_add(&c->lh, &obj->connections); + return ERROR_OK; +} + +static int arm_tpiu_swo_service_input(struct connection *connection) +{ + /* read a dummy buffer to check if the connection is still active */ + long dummy; + int bytes_read = connection_read(connection, &dummy, sizeof(dummy)); + + if (bytes_read == 0) { + return ERROR_SERVER_REMOTE_CLOSED; + } else if (bytes_read == -1) { + LOG_ERROR("error during read: %s", strerror(errno)); + return ERROR_SERVER_REMOTE_CLOSED; + } + + return ERROR_OK; +} + +static int arm_tpiu_swo_service_connection_closed(struct connection *connection) +{ + struct arm_tpiu_swo_priv_connection *priv = connection->service->priv; + struct arm_tpiu_swo_object *obj = priv->obj; + struct arm_tpiu_swo_connection *c, *tmp; + + list_for_each_entry_safe(c, tmp, &obj->connections, lh) + if (c->connection == connection) { + list_del(&c->lh); + free(c); + return ERROR_OK; + } + LOG_ERROR("Failed to find connection to close!"); + return ERROR_FAIL; +} + +COMMAND_HANDLER(handle_arm_tpiu_swo_event_list) +{ + struct arm_tpiu_swo_object *obj = CMD_DATA; + + command_print(CMD, "Event actions for TPIU/SWO %s\n", obj->name); + command_print(CMD, "%-25s | Body", "Event"); + command_print(CMD, "------------------------- | " + "----------------------------------------"); + + for (struct arm_tpiu_swo_event_action *ea = obj->event_action; ea; ea = ea->next) { + Jim_Nvp *opt = Jim_Nvp_value2name_simple(nvp_arm_tpiu_swo_event, ea->event); + command_print(CMD, "%-25s | %s", + opt->name, Jim_GetString(ea->body, NULL)); + } + command_print(CMD, "***END***"); + return ERROR_OK; +} + +enum arm_tpiu_swo_cfg_param { + CFG_PORT_WIDTH, + CFG_PROTOCOL, + CFG_FORMATTER, + CFG_TRACECLKIN, + CFG_BITRATE, + CFG_OUTFILE, + CFG_EVENT, +}; + +static const Jim_Nvp nvp_arm_tpiu_swo_config_opts[] = { + { .name = "-port-width", .value = CFG_PORT_WIDTH }, + { .name = "-protocol", .value = CFG_PROTOCOL }, + { .name = "-formatter", .value = CFG_FORMATTER }, + { .name = "-traceclk", .value = CFG_TRACECLKIN }, + { .name = "-pin-freq", .value = CFG_BITRATE }, + { .name = "-output", .value = CFG_OUTFILE }, + { .name = "-event", .value = CFG_EVENT }, + /* handled by mem_ap_spot, added for Jim_GetOpt_NvpUnknown() */ + { .name = "-dap", .value = -1 }, + { .name = "-ap-num", .value = -1 }, + { .name = "-baseaddr", .value = -1 }, + { .name = NULL, .value = -1 }, +}; + +static const Jim_Nvp nvp_arm_tpiu_swo_protocol_opts[] = { + { .name = "sync", .value = TPIU_SPPR_PROTOCOL_SYNC }, + { .name = "uart", .value = TPIU_SPPR_PROTOCOL_UART }, + { .name = "manchester", .value = TPIU_SPPR_PROTOCOL_MANCHESTER }, + { .name = NULL, .value = -1 }, +}; + +static const Jim_Nvp nvp_arm_tpiu_swo_bool_opts[] = { + { .name = "on", .value = 1 }, + { .name = "yes", .value = 1 }, + { .name = "1", .value = 1 }, + { .name = "true", .value = 1 }, + { .name = "off", .value = 0 }, + { .name = "no", .value = 0 }, + { .name = "0", .value = 0 }, + { .name = "false", .value = 0 }, + { .name = NULL, .value = -1 }, +}; + +static int arm_tpiu_swo_configure(Jim_GetOptInfo *goi, struct arm_tpiu_swo_object *obj) +{ + assert(obj != NULL); + + if (goi->isconfigure && obj->enabled) { + Jim_SetResultFormatted(goi->interp, "Cannot configure TPIU/SWO; %s is enabled!", obj->name); + return JIM_ERR; + } + + /* parse config or cget options ... */ + while (goi->argc > 0) { + Jim_SetEmptyResult(goi->interp); + + int e = adiv5_jim_mem_ap_spot_configure(&obj->spot, goi); + if (e == JIM_OK) + continue; + if (e == JIM_ERR) + return e; + + Jim_Nvp *n; + e = Jim_GetOpt_Nvp(goi, nvp_arm_tpiu_swo_config_opts, &n); + if (e != JIM_OK) { + Jim_GetOpt_NvpUnknown(goi, nvp_arm_tpiu_swo_config_opts, 0); + return e; + } + + switch (n->value) { + case CFG_PORT_WIDTH: + if (goi->isconfigure) { + jim_wide port_width; + e = Jim_GetOpt_Wide(goi, &port_width); + if (e != JIM_OK) + return e; + if (port_width < 1 || port_width > 32) { + Jim_SetResultString(goi->interp, "Invalid port width!", -1); + return JIM_ERR; + } + obj->port_width = (uint32_t)port_width; + } else { + if (goi->argc) + goto err_no_params; + Jim_SetResult(goi->interp, Jim_NewIntObj(goi->interp, obj->port_width)); + } + break; + case CFG_PROTOCOL: + if (goi->isconfigure) { + Jim_Nvp *p; + e = Jim_GetOpt_Nvp(goi, nvp_arm_tpiu_swo_protocol_opts, &p); + if (e != JIM_OK) + return e; + obj->pin_protocol = p->value; + } else { + if (goi->argc) + goto err_no_params; + Jim_Nvp *p; + e = Jim_Nvp_value2name(goi->interp, nvp_arm_tpiu_swo_protocol_opts, obj->pin_protocol, &p); + if (e != JIM_OK) { + Jim_SetResultString(goi->interp, "protocol error", -1); + return JIM_ERR; + } + Jim_SetResult(goi->interp, Jim_NewStringObj(goi->interp, p->name, -1)); + } + break; + case CFG_FORMATTER: + if (goi->isconfigure) { + Jim_Nvp *p; + e = Jim_GetOpt_Nvp(goi, nvp_arm_tpiu_swo_bool_opts, &p); + if (e != JIM_OK) + return e; + obj->en_formatter = p->value; + } else { + if (goi->argc) + goto err_no_params; + Jim_Nvp *p; + e = Jim_Nvp_value2name(goi->interp, nvp_arm_tpiu_swo_bool_opts, obj->en_formatter, &p); + if (e != JIM_OK) { + Jim_SetResultString(goi->interp, "formatter error", -1); + return JIM_ERR; + } + Jim_SetResult(goi->interp, Jim_NewStringObj(goi->interp, p->name, -1)); + } + break; + case CFG_TRACECLKIN: + if (goi->isconfigure) { + jim_wide clk; + e = Jim_GetOpt_Wide(goi, &clk); + if (e != JIM_OK) + return e; + obj->traceclkin_freq = clk; + } else { + if (goi->argc) + goto err_no_params; + Jim_SetResult(goi->interp, Jim_NewIntObj(goi->interp, obj->traceclkin_freq)); + } + break; + case CFG_BITRATE: + if (goi->isconfigure) { + jim_wide clk; + e = Jim_GetOpt_Wide(goi, &clk); + if (e != JIM_OK) + return e; + obj->swo_pin_freq = clk; + } else { + if (goi->argc) + goto err_no_params; + Jim_SetResult(goi->interp, Jim_NewIntObj(goi->interp, obj->swo_pin_freq)); + } + break; + case CFG_OUTFILE: + if (goi->isconfigure) { + const char *s; + e = Jim_GetOpt_String(goi, &s, NULL); + if (e != JIM_OK) + return e; + if (s[0] == ':') { + char *end; + long port = strtol(s + 1, &end, 0); + if (port <= 0 || port > UINT16_MAX || *end != '\0') { + Jim_SetResultFormatted(goi->interp, "Invalid TCP port \'%s\'", s + 1); + return JIM_ERR; + } + } + free(obj->out_filename); + obj->out_filename = strdup(s); + if (!obj->out_filename) { + LOG_ERROR("Out of memory"); + return JIM_ERR; + } + } else { + if (goi->argc) + goto err_no_params; + if (obj->out_filename) + Jim_SetResult(goi->interp, Jim_NewStringObj(goi->interp, obj->out_filename, -1)); + } + break; + case CFG_EVENT: + if (goi->isconfigure) { + if (goi->argc < 2) { + Jim_WrongNumArgs(goi->interp, goi->argc, goi->argv, "-event ?event-name? ?EVENT-BODY?"); + return JIM_ERR; + } + } else { + if (goi->argc != 1) { + Jim_WrongNumArgs(goi->interp, goi->argc, goi->argv, "-event ?event-name?"); + return JIM_ERR; + } + } + + { + Jim_Nvp *p; + Jim_Obj *o; + struct arm_tpiu_swo_event_action *ea = obj->event_action; + + e = Jim_GetOpt_Nvp(goi, nvp_arm_tpiu_swo_event, &p); + if (e != JIM_OK) { + Jim_GetOpt_NvpUnknown(goi, nvp_arm_tpiu_swo_event, 1); + return e; + } + + while (ea) { + /* replace existing? */ + if (ea->event == (enum arm_tpiu_swo_event)p->value) + break; + ea = ea->next; + } + + if (goi->isconfigure) { + if (!ea) { + ea = calloc(1, sizeof(*ea)); + if (!ea) { + LOG_ERROR("Out of memory"); + return JIM_ERR; + } + ea->next = obj->event_action; + obj->event_action = ea; + } + if (ea->body) + Jim_DecrRefCount(ea->interp, ea->body); + ea->event = p->value; + ea->interp = goi->interp; + Jim_GetOpt_Obj(goi, &o); + ea->body = Jim_DuplicateObj(goi->interp, o); + Jim_IncrRefCount(ea->body); + } else { + if (ea) + Jim_SetResult(goi->interp, Jim_DuplicateObj(goi->interp, ea->body)); + } + } + break; + } + } + + return JIM_OK; + +err_no_params: + Jim_WrongNumArgs(goi->interp, goi->argc, goi->argv, "NO PARAMS"); + return JIM_ERR; +} + +static int jim_arm_tpiu_swo_configure(Jim_Interp *interp, int argc, Jim_Obj * const *argv) +{ + Jim_GetOptInfo goi; + + Jim_GetOpt_Setup(&goi, interp, argc - 1, argv + 1); + goi.isconfigure = !strcmp(Jim_GetString(argv[0], NULL), "configure"); + if (goi.argc < 1) { + Jim_WrongNumArgs(goi.interp, goi.argc, goi.argv, + "missing: -option ..."); + return JIM_ERR; + } + struct arm_tpiu_swo_object *obj = Jim_CmdPrivData(interp); + return arm_tpiu_swo_configure(&goi, obj); +} + +static int wrap_write_u32(struct target *target, struct adiv5_ap *tpiu_ap, + target_addr_t address, uint32_t value) +{ + if (transport_is_hla()) + return target_write_u32(target, address, value); + else + return mem_ap_write_atomic_u32(tpiu_ap, address, value); +} + +static int wrap_read_u32(struct target *target, struct adiv5_ap *tpiu_ap, + target_addr_t address, uint32_t *value) +{ + if (transport_is_hla()) + return target_read_u32(target, address, value); + else + return mem_ap_read_atomic_u32(tpiu_ap, address, value); +} + +static int jim_arm_tpiu_swo_enable(Jim_Interp *interp, int argc, Jim_Obj *const *argv) +{ + struct arm_tpiu_swo_object *obj = Jim_CmdPrivData(interp); + struct command_context *cmd_ctx = current_command_context(interp); + struct adiv5_ap *tpiu_ap = dap_ap(obj->spot.dap, obj->spot.ap_num); + uint32_t value; + int retval; + + if (argc != 1) { + Jim_WrongNumArgs(interp, 1, argv, "Too many parameters"); + return JIM_ERR; + } + + if (cmd_ctx->mode == COMMAND_CONFIG) { + LOG_DEBUG("%s: enable deferred", obj->name); + obj->deferred_enable = true; + return JIM_OK; + } + + if (obj->enabled) + return JIM_OK; + + if (transport_is_hla() && obj->spot.ap_num > 0) { + LOG_ERROR("Invalid access port %d. Only AP#0 allowed with hla transport", obj->spot.ap_num); + return JIM_ERR; + } + + if (!obj->traceclkin_freq) { + LOG_ERROR("Trace clock-in frequency not set"); + return JIM_ERR; + } + + if (obj->pin_protocol == TPIU_SPPR_PROTOCOL_MANCHESTER || obj->pin_protocol == TPIU_SPPR_PROTOCOL_UART) + if (!obj->swo_pin_freq) { + LOG_ERROR("SWO pin frequency not set"); + return JIM_ERR; + } + + struct target *target = get_current_target(cmd_ctx); + + /* START_DEPRECATED_TPIU */ + if (obj->recheck_ap_cur_target) { + if (strcmp(target->type->name, "cortex_m") && + strcmp(target->type->name, "hla_target")) { + LOG_ERROR(MSG "Current target is not a Cortex-M nor a HLA"); + return JIM_ERR; + } + if (!target_was_examined(target)) { + LOG_ERROR(MSG "Current target not examined yet"); + return JIM_ERR; + } + struct cortex_m_common *cm = target_to_cm(target); + obj->recheck_ap_cur_target = false; + obj->spot.ap_num = cm->armv7m.debug_ap->ap_num; + tpiu_ap = dap_ap(obj->spot.dap, obj->spot.ap_num); + if (obj->spot.ap_num == 0) + LOG_INFO(MSG "Confirmed TPIU %s is on AP 0", obj->name); + else + LOG_INFO(MSG "Target %s is on AP %d. Revised command is " + "\'tpiu create %s -dap %s -ap-num %d\'", + target_name(target), obj->spot.ap_num, + obj->name, adiv5_dap_name(obj->spot.dap), obj->spot.ap_num); + } + /* END_DEPRECATED_TPIU */ + + /* trigger the event before any attempt to R/W in the TPIU/SWO */ + arm_tpiu_swo_handle_event(obj, TPIU_SWO_EVENT_PRE_ENABLE); + + retval = wrap_read_u32(target, tpiu_ap, obj->spot.base + TPIU_DEVID_OFFSET, &value); + if (retval != ERROR_OK) { + LOG_ERROR("Unable to read %s", obj->name); + return JIM_ERR; + } + switch (obj->pin_protocol) { + case TPIU_SPPR_PROTOCOL_SYNC: + value = !(value & TPIU_DEVID_NOSUPPORT_SYNC); + break; + case TPIU_SPPR_PROTOCOL_UART: + value &= TPIU_DEVID_SUPPORT_UART; + break; + case TPIU_SPPR_PROTOCOL_MANCHESTER: + value &= TPIU_DEVID_SUPPORT_MANCHESTER; + break; + default: + value = 0; + } + if (!value) { + Jim_Nvp *p; + Jim_Nvp_value2name(interp, nvp_arm_tpiu_swo_protocol_opts, obj->pin_protocol, &p); + LOG_ERROR("%s does not support protocol %s", obj->name, p->name); + return JIM_ERR; + } + + if (obj->pin_protocol == TPIU_SPPR_PROTOCOL_SYNC) { + retval = wrap_read_u32(target, tpiu_ap, obj->spot.base + TPIU_SSPSR_OFFSET, &value); + if (!(value & BIT(obj->port_width - 1))) { + LOG_ERROR("TPIU does not support port-width of %d bits", obj->port_width); + return JIM_ERR; + } + } + + uint16_t prescaler = 1; /* dummy value */ + unsigned int swo_pin_freq = obj->swo_pin_freq; /* could be replaced */ + + if (obj->out_filename && strcmp(obj->out_filename, "external") && obj->out_filename[0]) { + if (obj->out_filename[0] == ':') { + struct arm_tpiu_swo_priv_connection *priv = malloc(sizeof(*priv)); + if (!priv) { + LOG_ERROR("Out of memory"); + return JIM_ERR; + } + priv->obj = obj; + LOG_INFO("starting trace server for %s on %s", obj->name, &obj->out_filename[1]); + retval = add_service("tpiu_swo_trace", &obj->out_filename[1], + CONNECTION_LIMIT_UNLIMITED, arm_tpiu_swo_service_new_connection, + arm_tpiu_swo_service_input, arm_tpiu_swo_service_connection_closed, + priv); + if (retval != ERROR_OK) { + LOG_ERROR("Can't configure trace TCP port %s", &obj->out_filename[1]); + return JIM_ERR; + } + } else if (strcmp(obj->out_filename, "-")) { + obj->file = fopen(obj->out_filename, "ab"); + if (!obj->file) { + LOG_ERROR("Can't open trace destination file \"%s\"", obj->out_filename); + return JIM_ERR; + } + } + + retval = adapter_config_trace(true, obj->pin_protocol, obj->port_width, + &swo_pin_freq, obj->traceclkin_freq, &prescaler); + if (retval != ERROR_OK) { + LOG_ERROR("Failed to start adapter's trace"); + arm_tpiu_swo_close_output(obj); + return JIM_ERR; + } + + if (obj->swo_pin_freq != swo_pin_freq) + LOG_INFO("SWO pin data rate adjusted by adapter to %d Hz", swo_pin_freq); + obj->swo_pin_freq = swo_pin_freq; + + target_register_timer_callback(arm_tpiu_swo_poll_trace, 1, + TARGET_TIMER_TYPE_PERIODIC, obj); + + obj->en_capture = true; + } else if (obj->pin_protocol == TPIU_SPPR_PROTOCOL_MANCHESTER || obj->pin_protocol == TPIU_SPPR_PROTOCOL_UART) { + prescaler = (obj->traceclkin_freq + obj->swo_pin_freq / 2) / obj->swo_pin_freq; + if (prescaler > TPIU_ACPR_MAX_PRESCALER) + prescaler = TPIU_ACPR_MAX_PRESCALER; + swo_pin_freq = obj->traceclkin_freq / prescaler; + + if (obj->swo_pin_freq != swo_pin_freq) + LOG_INFO("SWO pin data rate adjusted to %d Hz", swo_pin_freq); + obj->swo_pin_freq = swo_pin_freq; + } + + retval = wrap_write_u32(target, tpiu_ap, obj->spot.base + TPIU_CSPSR_OFFSET, BIT(obj->port_width - 1)); + if (retval != ERROR_OK) + goto error_exit; + + retval = wrap_write_u32(target, tpiu_ap, obj->spot.base + TPIU_ACPR_OFFSET, prescaler - 1); + if (retval != ERROR_OK) + goto error_exit; + + retval = wrap_write_u32(target, tpiu_ap, obj->spot.base + TPIU_SPPR_OFFSET, obj->pin_protocol); + if (retval != ERROR_OK) + goto error_exit; + + retval = wrap_read_u32(target, tpiu_ap, obj->spot.base + TPIU_FFCR_OFFSET, &value); + if (retval != ERROR_OK) + goto error_exit; + if (obj->en_formatter) + value |= BIT(1); + else + value &= ~BIT(1); + retval = wrap_write_u32(target, tpiu_ap, obj->spot.base + TPIU_FFCR_OFFSET, value); + if (retval != ERROR_OK) + goto error_exit; + + arm_tpiu_swo_handle_event(obj, TPIU_SWO_EVENT_POST_ENABLE); + + obj->enabled = true; + return JIM_OK; + +error_exit: + LOG_ERROR("Error!"); + + if (obj->en_capture) { + obj->en_capture = false; + + arm_tpiu_swo_close_output(obj); + + target_unregister_timer_callback(arm_tpiu_swo_poll_trace, obj); + + retval = adapter_config_trace(false, 0, 0, NULL, 0, NULL); + if (retval != ERROR_OK) { + LOG_ERROR("Failed to stop adapter's trace"); + return JIM_ERR; + } + } + return JIM_ERR; +} + +static int jim_arm_tpiu_swo_disable(Jim_Interp *interp, int argc, Jim_Obj *const *argv) +{ + struct arm_tpiu_swo_object *obj = Jim_CmdPrivData(interp); + + if (argc != 1) { + Jim_WrongNumArgs(interp, 1, argv, "Too many parameters"); + return JIM_ERR; + } + + if (!obj->enabled) + return JIM_OK; + obj->enabled = false; + + arm_tpiu_swo_handle_event(obj, TPIU_SWO_EVENT_PRE_DISABLE); + + if (obj->en_capture) { + obj->en_capture = false; + + arm_tpiu_swo_close_output(obj); + + target_unregister_timer_callback(arm_tpiu_swo_poll_trace, obj); + + int retval = adapter_config_trace(false, 0, 0, NULL, 0, NULL); + if (retval != ERROR_OK) { + LOG_ERROR("Failed to stop adapter's trace"); + return JIM_ERR; + } + } + + arm_tpiu_swo_handle_event(obj, TPIU_SWO_EVENT_POST_DISABLE); + return JIM_OK; +} + +static const struct command_registration arm_tpiu_swo_instance_command_handlers[] = { + { + .name = "configure", + .mode = COMMAND_ANY, + .jim_handler = jim_arm_tpiu_swo_configure, + .help = "configure a new TPIU/SWO for use", + .usage = "[attribute value ...]", + }, + { + .name = "cget", + .mode = COMMAND_ANY, + .jim_handler = jim_arm_tpiu_swo_configure, + .help = "returns the specified TPIU/SWO attribute", + .usage = "attribute", + }, + { + .name = "eventlist", + .mode = COMMAND_ANY, + .handler = handle_arm_tpiu_swo_event_list, + .help = "displays a table of events defined for this TPIU/SWO", + .usage = "", + }, + { + .name = "enable", + .mode = COMMAND_ANY, + .jim_handler = jim_arm_tpiu_swo_enable, + .usage = "", + .help = "Enables the TPIU/SWO output", + }, + { + .name = "disable", + .mode = COMMAND_EXEC, + .jim_handler = jim_arm_tpiu_swo_disable, + .usage = "", + .help = "Disables the TPIU/SWO output", + }, + COMMAND_REGISTRATION_DONE +}; + +static int arm_tpiu_swo_create(Jim_Interp *interp, struct arm_tpiu_swo_object *obj) +{ + struct command_context *cmd_ctx; + Jim_Cmd *cmd; + int e; + + cmd_ctx = current_command_context(interp); + assert(cmd_ctx != NULL); + + /* does this command exist? */ + cmd = Jim_GetCommand(interp, Jim_NewStringObj(interp, obj->name, -1), JIM_ERRMSG); + if (cmd) { + Jim_SetResultFormatted(interp, "Command: %s Exists", obj->name); + return JIM_ERR; + } + + /* now - create the new tpiu/swo name command */ + const struct command_registration obj_commands[] = { + { + .name = obj->name, + .mode = COMMAND_ANY, + .help = "tpiu/swo instance command group", + .usage = "", + .chain = arm_tpiu_swo_instance_command_handlers, + }, + COMMAND_REGISTRATION_DONE + }; + e = register_commands(cmd_ctx, NULL, obj_commands); + if (ERROR_OK != e) + return JIM_ERR; + + struct command *c = command_find_in_context(cmd_ctx, obj->name); + assert(c); + command_set_handler_data(c, obj); + + list_add_tail(&obj->lh, &all_tpiu_swo); + + return JIM_OK; +} + +static int jim_arm_tpiu_swo_create(Jim_Interp *interp, int argc, Jim_Obj *const *argv) +{ + Jim_GetOptInfo goi; + Jim_GetOpt_Setup(&goi, interp, argc - 1, argv + 1); + if (goi.argc < 1) { + Jim_WrongNumArgs(goi.interp, 1, goi.argv, "?name? ..options..."); + return JIM_ERR; + } + + struct arm_tpiu_swo_object *obj = calloc(1, sizeof(struct arm_tpiu_swo_object)); + if (!obj) { + LOG_ERROR("Out of memory"); + return JIM_ERR; + } + INIT_LIST_HEAD(&obj->connections); + adiv5_mem_ap_spot_init(&obj->spot); + obj->spot.base = TPIU_SWO_DEFAULT_BASE; + obj->port_width = 1; + + Jim_Obj *n; + Jim_GetOpt_Obj(&goi, &n); + obj->name = strdup(Jim_GetString(n, NULL)); + if (!obj->name) { + LOG_ERROR("Out of memory"); + free(obj); + return JIM_ERR; + } + + /* Do the rest as "configure" options */ + goi.isconfigure = 1; + int e = arm_tpiu_swo_configure(&goi, obj); + if (e != JIM_OK) + goto err_exit; + + if (!obj->spot.dap || obj->spot.ap_num == DP_APSEL_INVALID) { + Jim_SetResultString(goi.interp, "-dap and -ap-num required when creating TPIU", -1); + goto err_exit; + } + + e = arm_tpiu_swo_create(goi.interp, obj); + if (e != JIM_OK) + goto err_exit; + + return JIM_OK; + +err_exit: + free(obj->name); + free(obj->out_filename); + free(obj); + return JIM_ERR; +} + +static int jim_arm_tpiu_swo_names(Jim_Interp *interp, int argc, Jim_Obj *const *argv) +{ + struct arm_tpiu_swo_object *obj; + + if (argc != 1) { + Jim_WrongNumArgs(interp, 1, argv, "Too many parameters"); + return JIM_ERR; + } + Jim_SetResult(interp, Jim_NewListObj(interp, NULL, 0)); + list_for_each_entry(obj, &all_tpiu_swo, lh) { + Jim_ListAppendElement(interp, Jim_GetResult(interp), + Jim_NewStringObj(interp, obj->name, -1)); + } + return JIM_OK; +} + +static int jim_arm_tpiu_swo_init(Jim_Interp *interp, int argc, Jim_Obj *const *argv) +{ + struct command_context *cmd_ctx = current_command_context(interp); + struct arm_tpiu_swo_object *obj; + int retval = JIM_OK; + + if (argc != 1) { + Jim_WrongNumArgs(interp, 1, argv, "Too many parameters"); + return JIM_ERR; + } + list_for_each_entry(obj, &all_tpiu_swo, lh) { + if (!obj->deferred_enable) + continue; + LOG_DEBUG("%s: running enable during init", obj->name); + int retval2 = command_run_linef(cmd_ctx, "%s enable", obj->name); + if (retval2 != ERROR_OK) + retval = JIM_ERR; + } + return retval; +} + +/* START_DEPRECATED_TPIU */ +/* DEPRECATED: emulation of old command 'tpiu config' */ +COMMAND_HANDLER(handle_tpiu_deprecated_config_command) +{ + struct target *target = get_current_target(CMD_CTX); + struct arm_tpiu_swo_object *obj = NULL; + int retval; + + if (strcmp(target->type->name, "cortex_m") && + strcmp(target->type->name, "hla_target")) { + LOG_ERROR(MSG "Current target is not a Cortex-M nor a HLA"); + return ERROR_FAIL; + } + + if (!list_empty(&all_tpiu_swo)) { + obj = list_first_entry(&all_tpiu_swo, typeof(*obj), lh); + LOG_INFO(MSG "Using %s", obj->name); + } else { + struct cortex_m_common *cm = target_to_cm(target); + struct adiv5_private_config *pc = target->private_config; + struct adiv5_dap *dap = pc->dap; + int ap_num = pc->ap_num; + bool set_recheck_ap_cur_target = false; + + LOG_INFO(MSG "Adding a TPIU \'%s.tpiu\' in the configuration", target_name(target)); + + if (ap_num == DP_APSEL_INVALID && transport_is_hla()) + ap_num = 0; /* HLA should only support AP 0 */ + + if (ap_num == DP_APSEL_INVALID && target_was_examined(target)) + ap_num = cm->armv7m.debug_ap->ap_num; + + if (ap_num == DP_APSEL_INVALID) { + LOG_INFO(MSG "Target %s uses AP autodetection. Adding TPIU on AP 0; can be revised later", + target_name(target)); + ap_num = 0; + set_recheck_ap_cur_target = true; + } + + LOG_INFO(MSG "Running: \'tpiu create %s.tpiu -dap %s -ap-num %d\'", + target_name(target), adiv5_dap_name(dap), ap_num); + + retval = command_run_linef(CMD_CTX, "tpiu create %s.tpiu -dap %s -ap-num %d", + target_name(target), adiv5_dap_name(dap), ap_num); + if (retval != ERROR_OK) + return retval; + + obj = list_first_entry(&all_tpiu_swo, typeof(*obj), lh); + if (set_recheck_ap_cur_target) + obj->recheck_ap_cur_target = true; + } + + unsigned int cmd_idx = 0; + if (CMD_ARGC == cmd_idx) + return ERROR_COMMAND_SYNTAX_ERROR; + + if (!strcmp(CMD_ARGV[cmd_idx], "disable")) { + if (CMD_ARGC != cmd_idx + 1) + return ERROR_COMMAND_SYNTAX_ERROR; + LOG_INFO(MSG "Running: \'%s disable\'", obj->name); + return command_run_linef(CMD_CTX, "%s disable", obj->name); + } + + const char *output = NULL; + const char *protocol; + const char *formatter = NULL; + const char *port_width = NULL; + const char *trace_clk; + const char *pin_clk = NULL; + if (!strcmp(CMD_ARGV[cmd_idx], "internal")) { + cmd_idx++; + if (CMD_ARGC == cmd_idx) + return ERROR_COMMAND_SYNTAX_ERROR; + output = CMD_ARGV[cmd_idx]; + } else if (strcmp(CMD_ARGV[cmd_idx], "external")) + return ERROR_COMMAND_SYNTAX_ERROR; + cmd_idx++; + if (CMD_ARGC == cmd_idx) + return ERROR_COMMAND_SYNTAX_ERROR; + if (!strcmp(CMD_ARGV[cmd_idx], "sync")) { + protocol = CMD_ARGV[cmd_idx]; + cmd_idx++; + if (CMD_ARGC == cmd_idx) + return ERROR_COMMAND_SYNTAX_ERROR; + port_width = CMD_ARGV[cmd_idx]; + } else { + if (strcmp(CMD_ARGV[cmd_idx], "manchester") && strcmp(CMD_ARGV[cmd_idx], "uart")) + return ERROR_COMMAND_SYNTAX_ERROR; + protocol = CMD_ARGV[cmd_idx]; + cmd_idx++; + if (CMD_ARGC == cmd_idx) + return ERROR_COMMAND_SYNTAX_ERROR; + formatter = CMD_ARGV[cmd_idx]; + } + cmd_idx++; + if (CMD_ARGC == cmd_idx) + return ERROR_COMMAND_SYNTAX_ERROR; + trace_clk = CMD_ARGV[cmd_idx]; + cmd_idx++; + if (CMD_ARGC != cmd_idx) { + pin_clk = CMD_ARGV[cmd_idx]; + cmd_idx++; + } + if (CMD_ARGC != cmd_idx) + return ERROR_COMMAND_SYNTAX_ERROR; + + LOG_INFO(MSG "Running: \'%s configure -protocol %s -traceclk %s" "%s%s" "%s%s" "%s%s" "%s%s\'", + obj->name, protocol, trace_clk, + pin_clk ? " -pin-freq " : "", pin_clk ? pin_clk : "", + output ? " -output " : "", output ? output : "", + formatter ? " -formatter " : "", formatter ? formatter : "", + port_width ? " -port-width " : "", port_width ? port_width : ""); + + retval = command_run_linef(CMD_CTX, + "%s configure -protocol %s -traceclk %s" "%s%s" "%s%s" "%s%s" "%s%s", + obj->name, protocol, trace_clk, + pin_clk ? " -pin-freq " : "", pin_clk ? pin_clk : "", + output ? " -output " : "", output ? output : "", + formatter ? " -formatter " : "", formatter ? formatter : "", + port_width ? " -port-width " : "", port_width ? port_width : ""); + if (retval != ERROR_OK) + return retval; + + LOG_INFO(MSG "Running: \'%s enable\'", obj->name); + retval = command_run_linef(CMD_CTX, "%s enable", obj->name); + if (retval != ERROR_OK) + return retval; + + target_handle_event(target, TARGET_EVENT_TRACE_CONFIG); + return ERROR_OK; +} + +static const struct command_registration arm_tpiu_deprecated_subcommand_handlers[] = { + { + .name = "config", + .handler = handle_tpiu_deprecated_config_command, + .mode = COMMAND_ANY, + .help = "Configure TPIU features, DEPRECATED, use \'tpiu create\'", + .usage = "(disable | " + "((external | internal ( | <:port> | -)) " + "(sync | ((manchester | uart) )) " + " []))", + }, + COMMAND_REGISTRATION_DONE +}; + +const struct command_registration arm_tpiu_deprecated_command_handlers[] = { + { + .name = "tpiu", + .chain = arm_tpiu_deprecated_subcommand_handlers, + .usage = "", + .help = "tpiu command group", + }, + COMMAND_REGISTRATION_DONE +}; +/* END_DEPRECATED_TPIU */ + +static const struct command_registration arm_tpiu_swo_subcommand_handlers[] = { + { + .name = "create", + .mode = COMMAND_ANY, + .jim_handler = jim_arm_tpiu_swo_create, + .usage = "name [-dap dap] [-ap-num num] [-address baseaddr]", + .help = "Creates a new TPIU or SWO object", + }, + { + .name = "names", + .mode = COMMAND_ANY, + .jim_handler = jim_arm_tpiu_swo_names, + .usage = "", + .help = "Lists all registered TPIU and SWO objects by name", + }, + { + .name = "init", + .mode = COMMAND_EXEC, + .jim_handler = jim_arm_tpiu_swo_init, + .usage = "", + .help = "Initialize TPIU and SWO", + }, + COMMAND_REGISTRATION_DONE +}; + +static const struct command_registration arm_tpiu_swo_command_handlers[] = { + { + .name = "tpiu", + .chain = arm_tpiu_swo_subcommand_handlers, + .usage = "", + .help = "tpiu command group", + }, + { + .name = "swo", + .chain = arm_tpiu_swo_subcommand_handlers, + .usage = "", + .help = "swo command group", + }, + COMMAND_REGISTRATION_DONE +}; + +int arm_tpiu_swo_register_commands(struct command_context *cmd_ctx) +{ + return register_commands(cmd_ctx, NULL, arm_tpiu_swo_command_handlers); +} diff --git a/src/target/arm_tpiu_swo.h b/src/target/arm_tpiu_swo.h new file mode 100644 index 000000000..5904ce291 --- /dev/null +++ b/src/target/arm_tpiu_swo.h @@ -0,0 +1,21 @@ +/* SPDX-License-Identifier: GPL-2.0-or-later */ + +#ifndef OPENOCD_TARGET_ARM_TPIU_SWO_H +#define OPENOCD_TARGET_ARM_TPIU_SWO_H + +/* Values should match TPIU_SPPR_PROTOCOL_xxx */ +enum tpiu_pin_protocol { + TPIU_PIN_PROTOCOL_SYNC = 0, /**< synchronous trace output */ + TPIU_PIN_PROTOCOL_ASYNC_MANCHESTER = 1, /**< asynchronous output with Manchester coding */ + TPIU_PIN_PROTOCOL_ASYNC_UART = 2, /**< asynchronous output with NRZ coding */ +}; + +/* START_DEPRECATED_TPIU */ +/* DEPRECATED: emulation of old command 'tpiu config' */ +extern const struct command_registration arm_tpiu_deprecated_command_handlers[]; +/* END_DEPRECATED_TPIU */ + +int arm_tpiu_swo_register_commands(struct command_context *cmd_ctx); +int arm_tpiu_swo_cleanup_all(void); + +#endif /* OPENOCD_TARGET_ARM_TPIU_SWO_H */ diff --git a/src/target/armv7m.c b/src/target/armv7m.c index f14ce0d88..101094a97 100644 --- a/src/target/armv7m.c +++ b/src/target/armv7m.c @@ -166,10 +166,10 @@ int armv7m_restore_context(struct target *target) * packing of ARMV7M_PMSK_BPRI_FLTMSK_CTRL! * See also comments in the register table above */ for (i = cache->num_regs - 1; i >= 0; i--) { - if (cache->reg_list[i].dirty) { - armv7m->arm.write_core_reg(target, &cache->reg_list[i], i, - ARM_MODE_ANY, cache->reg_list[i].value); - } + struct reg *r = &cache->reg_list[i]; + + if (r->exist && r->dirty) + armv7m->arm.write_core_reg(target, r, i, ARM_MODE_ANY, r->value); } return ERROR_OK; diff --git a/src/target/armv7m_trace.c b/src/target/armv7m_trace.c index 10f14221d..74ffaf5a4 100644 --- a/src/target/armv7m_trace.c +++ b/src/target/armv7m_trace.c @@ -24,133 +24,7 @@ #include #include #include - -#define TRACE_BUF_SIZE 4096 - -static int armv7m_poll_trace(void *target) -{ - struct armv7m_common *armv7m = target_to_armv7m(target); - uint8_t buf[TRACE_BUF_SIZE]; - size_t size = sizeof(buf); - int retval; - - retval = adapter_poll_trace(buf, &size); - if (retval != ERROR_OK || !size) - return retval; - - target_call_trace_callbacks(target, size, buf); - - switch (armv7m->trace_config.internal_channel) { - case TRACE_INTERNAL_CHANNEL_FILE: - if (armv7m->trace_config.trace_file != NULL) { - if (fwrite(buf, 1, size, armv7m->trace_config.trace_file) == size) - fflush(armv7m->trace_config.trace_file); - else { - LOG_ERROR("Error writing to the trace destination file"); - return ERROR_FAIL; - } - } - break; - case TRACE_INTERNAL_CHANNEL_TCP: - if (armv7m->trace_config.trace_service != NULL) { - /* broadcast to all service connections */ - struct connection *connection = armv7m->trace_config.trace_service->connections; - retval = ERROR_OK; - while (connection) { - if (connection_write(connection, buf, size) != (int) size) - retval = ERROR_FAIL; - - connection = connection->next; - } - - if (retval != ERROR_OK) { - LOG_ERROR("Error streaming the trace to TCP/IP port"); - return ERROR_FAIL; - } - } - break; - case TRACE_INTERNAL_CHANNEL_TCL_ONLY: - /* nothing to do : - * the trace data is sent to TCL by calling the target_call_trace_callbacks - **/ - break; - default: - LOG_ERROR("unsupported trace internal channel"); - return ERROR_FAIL; - } - - return ERROR_OK; -} - -int armv7m_trace_tpiu_config(struct target *target) -{ - struct armv7m_common *armv7m = target_to_armv7m(target); - struct armv7m_trace_config *trace_config = &armv7m->trace_config; - uint16_t prescaler; - int retval; - - target_unregister_timer_callback(armv7m_poll_trace, target); - - retval = adapter_config_trace(trace_config->config_type == TRACE_CONFIG_TYPE_INTERNAL, - trace_config->pin_protocol, trace_config->port_size, - &trace_config->trace_freq, trace_config->traceclkin_freq, &prescaler); - - if (retval != ERROR_OK) - return retval; - - if (trace_config->config_type == TRACE_CONFIG_TYPE_EXTERNAL) { - prescaler = trace_config->traceclkin_freq / trace_config->trace_freq; - - if (trace_config->traceclkin_freq % trace_config->trace_freq) { - prescaler++; - - int trace_freq = trace_config->traceclkin_freq / prescaler; - LOG_INFO("Can not obtain %u trace port frequency from %u " - "TRACECLKIN frequency, using %u instead", - trace_config->trace_freq, trace_config->traceclkin_freq, - trace_freq); - - trace_config->trace_freq = trace_freq; - } - } - - if (!trace_config->trace_freq) { - LOG_ERROR("Trace port frequency is 0, can't enable TPIU"); - return ERROR_FAIL; - } - - retval = target_write_u32(target, TPIU_CSPSR, 1 << trace_config->port_size); - if (retval != ERROR_OK) - return retval; - - retval = target_write_u32(target, TPIU_ACPR, prescaler - 1); - if (retval != ERROR_OK) - return retval; - - retval = target_write_u32(target, TPIU_SPPR, trace_config->pin_protocol); - if (retval != ERROR_OK) - return retval; - - uint32_t ffcr; - retval = target_read_u32(target, TPIU_FFCR, &ffcr); - if (retval != ERROR_OK) - return retval; - if (trace_config->formatter) - ffcr |= (1 << 1); - else - ffcr &= ~(1 << 1); - retval = target_write_u32(target, TPIU_FFCR, ffcr); - if (retval != ERROR_OK) - return retval; - - if (trace_config->config_type == TRACE_CONFIG_TYPE_INTERNAL) - target_register_timer_callback(armv7m_poll_trace, 1, - TARGET_TIMER_TYPE_PERIODIC, target); - - target_call_event_callbacks(target, TARGET_EVENT_TRACE_CONFIG); - - return ERROR_OK; -} +#include int armv7m_trace_itm_config(struct target *target) { @@ -162,6 +36,33 @@ int armv7m_trace_itm_config(struct target *target) if (retval != ERROR_OK) return retval; + /* pg315 of CoreSight Components + * It is recommended that the ITMEn bit is cleared and waits for the + * ITMBusy bit to be cleared, before changing any fields in the + * Control Register, otherwise the behavior can be unpredictable. + */ + uint32_t itm_tcr; + retval = target_read_u32(target, ITM_TCR, &itm_tcr); + if (retval != ERROR_OK) + return retval; + retval = target_write_u32(target, + ITM_TCR, + itm_tcr & ~ITM_TCR_ITMENA_BIT + ); + if (retval != ERROR_OK) + return retval; + + int64_t then = timeval_ms() + 1000; + do { + retval = target_read_u32(target, ITM_TCR, &itm_tcr); + if (retval != ERROR_OK) + return retval; + if (timeval_ms() > then) { + LOG_ERROR("timeout waiting for ITM_TCR_BUSY_BIT"); + return ERROR_FAIL; + } + } while (itm_tcr & ITM_TCR_BUSY_BIT); + /* Enable ITM, TXENA, set TraceBusID and other parameters */ retval = target_write_u32(target, ITM_TCR, (1 << 0) | (1 << 3) | (trace_config->itm_diff_timestamps << 1) | @@ -182,182 +83,6 @@ int armv7m_trace_itm_config(struct target *target) return ERROR_OK; } -static void close_trace_channel(struct armv7m_common *armv7m) -{ - switch (armv7m->trace_config.internal_channel) { - case TRACE_INTERNAL_CHANNEL_FILE: - if (armv7m->trace_config.trace_file) - fclose(armv7m->trace_config.trace_file); - armv7m->trace_config.trace_file = NULL; - break; - case TRACE_INTERNAL_CHANNEL_TCP: - if (armv7m->trace_config.trace_service) - remove_service(armv7m->trace_config.trace_service->name, armv7m->trace_config.trace_service->port); - armv7m->trace_config.trace_service = NULL; - break; - case TRACE_INTERNAL_CHANNEL_TCL_ONLY: - /* nothing to do: - * the trace polling is disabled in the beginning of armv7m_trace_tpiu_config - **/ - break; - default: - LOG_ERROR("unsupported trace internal channel"); - } -} - -static int trace_new_connection(struct connection *connection) -{ - /* nothing to do */ - return ERROR_OK; -} - -static int trace_input(struct connection *connection) -{ - /* create a dummy buffer to check if the connection is still active */ - const int buf_len = 100; - unsigned char buf[buf_len]; - int bytes_read = connection_read(connection, buf, buf_len); - - if (bytes_read == 0) - return ERROR_SERVER_REMOTE_CLOSED; - else if (bytes_read == -1) { - LOG_ERROR("error during read: %s", strerror(errno)); - return ERROR_SERVER_REMOTE_CLOSED; - } - - return ERROR_OK; -} - -static int trace_connection_closed(struct connection *connection) -{ - /* nothing to do, no connection->priv to free */ - return ERROR_OK; -} - -extern struct command_context *global_cmd_ctx; - -int armv7m_trace_tpiu_exit(struct target *target) -{ - struct armv7m_common *armv7m = target_to_armv7m(target); - - if (global_cmd_ctx->mode == COMMAND_CONFIG || - armv7m->trace_config.config_type == TRACE_CONFIG_TYPE_DISABLED) - return ERROR_OK; - - close_trace_channel(armv7m); - armv7m->trace_config.config_type = TRACE_CONFIG_TYPE_DISABLED; - return armv7m_trace_tpiu_config(target); -} - -COMMAND_HANDLER(handle_tpiu_config_command) -{ - struct target *target = get_current_target(CMD_CTX); - struct armv7m_common *armv7m = target_to_armv7m(target); - - unsigned int cmd_idx = 0; - - if (CMD_ARGC == cmd_idx) - return ERROR_COMMAND_SYNTAX_ERROR; - if (!strcmp(CMD_ARGV[cmd_idx], "disable")) { - if (CMD_ARGC == cmd_idx + 1) { - close_trace_channel(armv7m); - - armv7m->trace_config.config_type = TRACE_CONFIG_TYPE_DISABLED; - if (CMD_CTX->mode == COMMAND_EXEC) - return armv7m_trace_tpiu_config(target); - else - return ERROR_OK; - } - } else if (!strcmp(CMD_ARGV[cmd_idx], "external") || - !strcmp(CMD_ARGV[cmd_idx], "internal")) { - close_trace_channel(armv7m); - - armv7m->trace_config.config_type = TRACE_CONFIG_TYPE_EXTERNAL; - if (!strcmp(CMD_ARGV[cmd_idx], "internal")) { - cmd_idx++; - if (CMD_ARGC == cmd_idx) - return ERROR_COMMAND_SYNTAX_ERROR; - - armv7m->trace_config.config_type = TRACE_CONFIG_TYPE_INTERNAL; - armv7m->trace_config.internal_channel = TRACE_INTERNAL_CHANNEL_TCL_ONLY; - - if (strcmp(CMD_ARGV[cmd_idx], "-") != 0) { - if (CMD_ARGV[cmd_idx][0] == ':') { - armv7m->trace_config.internal_channel = TRACE_INTERNAL_CHANNEL_TCP; - - int ret = add_service("armv7m_trace", &(CMD_ARGV[cmd_idx][1]), - CONNECTION_LIMIT_UNLIMITED, trace_new_connection, trace_input, - trace_connection_closed, NULL, &armv7m->trace_config.trace_service); - if (ret != ERROR_OK) { - LOG_ERROR("Can't configure trace TCP port"); - return ERROR_FAIL; - } - } else { - armv7m->trace_config.internal_channel = TRACE_INTERNAL_CHANNEL_FILE; - armv7m->trace_config.trace_file = fopen(CMD_ARGV[cmd_idx], "ab"); - if (!armv7m->trace_config.trace_file) { - LOG_ERROR("Can't open trace destination file"); - return ERROR_FAIL; - } - } - } - } - cmd_idx++; - if (CMD_ARGC == cmd_idx) - return ERROR_COMMAND_SYNTAX_ERROR; - - if (!strcmp(CMD_ARGV[cmd_idx], "sync")) { - armv7m->trace_config.pin_protocol = TPIU_PIN_PROTOCOL_SYNC; - - cmd_idx++; - if (CMD_ARGC == cmd_idx) - return ERROR_COMMAND_SYNTAX_ERROR; - - COMMAND_PARSE_NUMBER(u32, CMD_ARGV[cmd_idx], armv7m->trace_config.port_size); - } else { - if (!strcmp(CMD_ARGV[cmd_idx], "manchester")) - armv7m->trace_config.pin_protocol = TPIU_PIN_PROTOCOL_ASYNC_MANCHESTER; - else if (!strcmp(CMD_ARGV[cmd_idx], "uart")) - armv7m->trace_config.pin_protocol = TPIU_PIN_PROTOCOL_ASYNC_UART; - else - return ERROR_COMMAND_SYNTAX_ERROR; - - cmd_idx++; - if (CMD_ARGC == cmd_idx) - return ERROR_COMMAND_SYNTAX_ERROR; - - COMMAND_PARSE_ON_OFF(CMD_ARGV[cmd_idx], armv7m->trace_config.formatter); - } - - cmd_idx++; - if (CMD_ARGC == cmd_idx) - return ERROR_COMMAND_SYNTAX_ERROR; - - COMMAND_PARSE_NUMBER(uint, CMD_ARGV[cmd_idx], armv7m->trace_config.traceclkin_freq); - - cmd_idx++; - if (CMD_ARGC != cmd_idx) { - COMMAND_PARSE_NUMBER(uint, CMD_ARGV[cmd_idx], armv7m->trace_config.trace_freq); - cmd_idx++; - } else { - if (armv7m->trace_config.config_type != TRACE_CONFIG_TYPE_INTERNAL) { - LOG_ERROR("Trace port frequency can't be omitted in external capture mode"); - return ERROR_COMMAND_SYNTAX_ERROR; - } - armv7m->trace_config.trace_freq = 0; - } - - if (CMD_ARGC == cmd_idx) { - if (CMD_CTX->mode == COMMAND_EXEC) - return armv7m_trace_tpiu_config(target); - else - return ERROR_OK; - } - } - - return ERROR_COMMAND_SYNTAX_ERROR; -} - COMMAND_HANDLER(handle_itm_port_command) { struct target *target = get_current_target(CMD_CTX); @@ -380,8 +105,9 @@ COMMAND_HANDLER(handle_itm_port_command) if (CMD_CTX->mode == COMMAND_EXEC) return armv7m_trace_itm_config(target); - else - return ERROR_OK; + + armv7m->trace_config.itm_deferred_config = true; + return ERROR_OK; } COMMAND_HANDLER(handle_itm_ports_command) @@ -399,23 +125,10 @@ COMMAND_HANDLER(handle_itm_ports_command) if (CMD_CTX->mode == COMMAND_EXEC) return armv7m_trace_itm_config(target); - else - return ERROR_OK; -} -static const struct command_registration tpiu_command_handlers[] = { - { - .name = "config", - .handler = handle_tpiu_config_command, - .mode = COMMAND_ANY, - .help = "Configure TPIU features", - .usage = "(disable | " - "((external | internal ( | <:port> | -)) " - "(sync | ((manchester | uart) )) " - " []))", - }, - COMMAND_REGISTRATION_DONE -}; + armv7m->trace_config.itm_deferred_config = true; + return ERROR_OK; +} static const struct command_registration itm_command_handlers[] = { { @@ -436,13 +149,6 @@ static const struct command_registration itm_command_handlers[] = { }; const struct command_registration armv7m_trace_command_handlers[] = { - { - .name = "tpiu", - .mode = COMMAND_ANY, - .help = "tpiu command group", - .usage = "", - .chain = tpiu_command_handlers, - }, { .name = "itm", .mode = COMMAND_ANY, diff --git a/src/target/armv7m_trace.h b/src/target/armv7m_trace.h index cdf79e74c..eaee6a48f 100644 --- a/src/target/armv7m_trace.h +++ b/src/target/armv7m_trace.h @@ -18,33 +18,14 @@ #ifndef OPENOCD_TARGET_ARMV7M_TRACE_H #define OPENOCD_TARGET_ARMV7M_TRACE_H -#include #include #include /** * @file - * Holds the interface to TPIU, ITM and DWT configuration functions. + * Holds the interface to ITM and DWT configuration functions. */ -enum trace_config_type { - TRACE_CONFIG_TYPE_DISABLED, /**< tracing is disabled */ - TRACE_CONFIG_TYPE_EXTERNAL, /**< trace output is captured externally */ - TRACE_CONFIG_TYPE_INTERNAL /**< trace output is handled by OpenOCD adapter driver */ -}; - -enum trace_internal_channel { - TRACE_INTERNAL_CHANNEL_TCL_ONLY, /** trace data is sent only to 'tcl_trace' */ - TRACE_INTERNAL_CHANNEL_FILE, /** trace data is appended to a file */ - TRACE_INTERNAL_CHANNEL_TCP /** trace data is appended to a TCP/IP port*/ -}; - -enum tpiu_pin_protocol { - TPIU_PIN_PROTOCOL_SYNC, /**< synchronous trace output */ - TPIU_PIN_PROTOCOL_ASYNC_MANCHESTER, /**< asynchronous output with Manchester coding */ - TPIU_PIN_PROTOCOL_ASYNC_UART /**< asynchronous output with NRZ coding */ -}; - enum itm_ts_prescaler { ITM_TS_PRESCALE1, /**< no prescaling for the timestamp counter */ ITM_TS_PRESCALE4, /**< refclock divided by 4 for the timestamp counter */ @@ -53,19 +34,6 @@ enum itm_ts_prescaler { }; struct armv7m_trace_config { - /** Currently active trace capture mode */ - enum trace_config_type config_type; - - /** The used channel when internal mode is selected */ - enum trace_internal_channel internal_channel; - - /** Currently active trace output mode */ - enum tpiu_pin_protocol pin_protocol; - /** TPIU formatter enable/disable (in async mode) */ - bool formatter; - /** Synchronous output port width */ - uint32_t port_size; - /** Bitmask of currently enabled ITM stimuli */ uint32_t itm_ter[8]; /** Identifier for multi-source trace stream formatting */ @@ -78,27 +46,12 @@ struct armv7m_trace_config { bool itm_async_timestamps; /** Enable synchronisation packet transmission (for sync port only) */ bool itm_synchro_packets; - - /** Current frequency of TRACECLKIN (usually matches HCLK) */ - unsigned int traceclkin_freq; - /** Current frequency of trace port */ - unsigned int trace_freq; - /** Handle to output trace data in INTERNAL capture mode via file */ - FILE *trace_file; - /** Handle to output trace data in INTERNAL capture mode via tcp */ - struct service *trace_service; + /** Config ITM after target examine */ + bool itm_deferred_config; }; extern const struct command_registration armv7m_trace_command_handlers[]; -/** - * Configure hardware accordingly to the current TPIU target settings - */ -int armv7m_trace_tpiu_config(struct target *target); -/** - * Disable TPIU data gathering at exit - */ -int armv7m_trace_tpiu_exit(struct target *target); /** * Configure hardware accordingly to the current ITM target settings */ diff --git a/src/target/armv8.c b/src/target/armv8.c index 95efdc90b..6bf3b110d 100644 --- a/src/target/armv8.c +++ b/src/target/armv8.c @@ -1098,13 +1098,6 @@ int armv8_handle_cache_info_command(struct command_invocation *cmd, static int armv8_setup_semihosting(struct target *target, int enable) { - struct arm *arm = target_to_arm(target); - - if (arm->core_state != ARM_STATE_AARCH64) { - LOG_ERROR("semihosting only supported in AArch64 state\n"); - return ERROR_FAIL; - } - return ERROR_OK; } diff --git a/src/target/armv8_dpm.c b/src/target/armv8_dpm.c index 1e88a445f..e7d0f864e 100644 --- a/src/target/armv8_dpm.c +++ b/src/target/armv8_dpm.c @@ -1465,8 +1465,10 @@ int armv8_dpm_setup(struct arm_dpm *dpm) } /* watchpoint setup */ - target->type->add_watchpoint = dpmv8_add_watchpoint; - target->type->remove_watchpoint = dpmv8_remove_watchpoint; + if (!target->type->add_watchpoint) { + target->type->add_watchpoint = dpmv8_add_watchpoint; + target->type->remove_watchpoint = dpmv8_remove_watchpoint; + } /* FIXME add vector catch support */ diff --git a/src/target/armv8_dpm.h b/src/target/armv8_dpm.h index ee6f699de..a6cade345 100644 --- a/src/target/armv8_dpm.h +++ b/src/target/armv8_dpm.h @@ -16,6 +16,7 @@ #define OPENOCD_TARGET_ARMV8_DPM_H #include "arm_dpm.h" +#include "helper/bits.h" /* forward-declare struct armv8_common */ struct armv8_common; @@ -96,6 +97,12 @@ void armv8_dpm_report_wfar(struct arm_dpm *dpm, uint64_t wfar); #define DRCR_RESTART (1 << 1) #define DRCR_CLEAR_EXCEPTIONS (1 << 2) +/* ECR (Execution Control Register) bits */ +#define ECR_RCE BIT(1) + +/* ESR (Event Status Register) bits */ +#define ESR_RC BIT(1) + /* PRSR (processor debug status register) bits */ #define PRSR_PU (1 << 0) #define PRSR_SPD (1 << 1) diff --git a/src/target/cortex_a.c b/src/target/cortex_a.c index d27c298b6..5018a91d4 100644 --- a/src/target/cortex_a.c +++ b/src/target/cortex_a.c @@ -3143,7 +3143,6 @@ static const struct command_registration cortex_a_command_handlers[] = { struct target_type cortexa_target = { .name = "cortex_a", - .deprecated_name = "cortex_a8", .poll = cortex_a_poll, .arch_state = armv7a_arch_state, diff --git a/src/target/cortex_m.c b/src/target/cortex_m.c index ce2c426ce..6dc33c867 100644 --- a/src/target/cortex_m.c +++ b/src/target/cortex_m.c @@ -521,7 +521,7 @@ static int cortex_m_debug_entry(struct target *target) for (i = 0; i < num_regs; i++) { r = &armv7m->arm.core_cache->reg_list[i]; - if (!r->valid) + if (r->exist && !r->valid) arm->read_core_reg(target, r, i, ARM_MODE_ANY); } @@ -1648,8 +1648,6 @@ void cortex_m_deinit_target(struct target *target) { struct cortex_m_common *cortex_m = target_to_cm(target); - armv7m_trace_tpiu_exit(target); - free(cortex_m->fp_comparator_list); cortex_m_dwt_free(target); @@ -2082,10 +2080,8 @@ int cortex_m_examine(struct target *target) if (retval != ERROR_OK) return retval; - if (armv7m->trace_config.config_type != TRACE_CONFIG_TYPE_DISABLED) { - armv7m_trace_tpiu_config(target); + if (armv7m->trace_config.itm_deferred_config) armv7m_trace_itm_config(target); - } /* NOTE: FPB and DWT are both optional. */ @@ -2485,6 +2481,11 @@ static const struct command_registration cortex_m_command_handlers[] = { { .chain = armv7m_trace_command_handlers, }, + /* START_DEPRECATED_TPIU */ + { + .chain = arm_tpiu_deprecated_command_handlers, + }, + /* END_DEPRECATED_TPIU */ { .name = "cortex_m", .mode = COMMAND_EXEC, @@ -2500,7 +2501,6 @@ static const struct command_registration cortex_m_command_handlers[] = { struct target_type cortexm_target = { .name = "cortex_m", - .deprecated_name = "cortex_m3", .poll = cortex_m_poll, .arch_state = armv7m_arch_state, diff --git a/src/target/cortex_m.h b/src/target/cortex_m.h index b470fbd70..1e2197b1a 100644 --- a/src/target/cortex_m.h +++ b/src/target/cortex_m.h @@ -35,6 +35,8 @@ #define ITM_TER0 0xE0000E00 #define ITM_TPR 0xE0000E40 #define ITM_TCR 0xE0000E80 +#define ITM_TCR_ITMENA_BIT BIT(0) +#define ITM_TCR_BUSY_BIT BIT(23) #define ITM_LAR 0xE0000FB0 #define ITM_LAR_KEY 0xC5ACCE55 diff --git a/src/target/embeddedice.c b/src/target/embeddedice.c index 7c53c45c5..a29508baf 100644 --- a/src/target/embeddedice.c +++ b/src/target/embeddedice.c @@ -645,7 +645,6 @@ int embeddedice_handshake(struct arm_jtag *jtag_info, int hsbit, uint32_t timeou return ERROR_TARGET_TIMEOUT; } -#ifndef HAVE_JTAG_MINIDRIVER_H /** * This is an inner loop of the open loop DCC write of data to target */ @@ -660,6 +659,3 @@ void embeddedice_write_dcc(struct jtag_tap *tap, buffer += 4; } } -#else -/* provided by minidriver */ -#endif diff --git a/src/target/etm.c b/src/target/etm.c index faa941fed..19f3691bd 100644 --- a/src/target/etm.c +++ b/src/target/etm.c @@ -27,11 +27,6 @@ #include "register.h" #include "etm_dummy.h" -#if BUILD_OOCD_TRACE == 1 -#include "oocd_trace.h" -#endif - - /* * ARM "Embedded Trace Macrocell" (ETM) support -- direct JTAG access. * @@ -642,9 +637,6 @@ static int etm_write_reg(struct reg *reg, uint32_t value) static struct etm_capture_driver *etm_capture_drivers[] = { &etb_capture_driver, &etm_dummy_capture_driver, -#if BUILD_OOCD_TRACE == 1 - &oocd_trace_capture_driver, -#endif NULL }; diff --git a/src/target/hla_target.c b/src/target/hla_target.c index 3d41387fd..cd57dd207 100644 --- a/src/target/hla_target.c +++ b/src/target/hla_target.c @@ -226,7 +226,7 @@ static int adapter_load_context(struct target *target) for (int i = 0; i < num_regs; i++) { struct reg *r = &armv7m->arm.core_cache->reg_list[i]; - if (!r->valid) + if (r->exist && !r->valid) armv7m->arm.read_core_reg(target, r, i, ARM_MODE_ANY); } @@ -630,12 +630,16 @@ static const struct command_registration adapter_command_handlers[] = { { .chain = rtt_target_command_handlers, }, + /* START_DEPRECATED_TPIU */ + { + .chain = arm_tpiu_deprecated_command_handlers, + }, + /* END_DEPRECATED_TPIU */ COMMAND_REGISTRATION_DONE }; struct target_type hla_target = { .name = "hla_target", - .deprecated_name = "stm32_stlink", .init_target = adapter_init_target, .deinit_target = cortex_m_deinit_target, diff --git a/src/target/image.c b/src/target/image.c index fd5eff80a..e63cd0f9c 100644 --- a/src/target/image.c +++ b/src/target/image.c @@ -1052,7 +1052,7 @@ int image_calculate_checksum(const uint8_t *buffer, uint32_t nbytes, uint32_t *c keep_alive(); } - LOG_DEBUG("Calculating checksum done; checksum=0x%x", crc); + LOG_DEBUG("Calculating checksum done; checksum=0x%" PRIx32, crc); *checksum = crc; return ERROR_OK; diff --git a/src/target/mem_ap.c b/src/target/mem_ap.c index 7ed41c63c..89c0c02c0 100644 --- a/src/target/mem_ap.c +++ b/src/target/mem_ap.c @@ -20,6 +20,7 @@ #include "target_type.h" #include "arm.h" #include "arm_adi_v5.h" +#include "register.h" #include @@ -55,6 +56,9 @@ static int mem_ap_target_create(struct target *target, Jim_Interp *interp) target->arch_info = mem_ap; + if (!target->gdb_port_override) + target->gdb_port_override = strdup("disabled"); + return ERROR_OK; } @@ -62,6 +66,7 @@ static int mem_ap_init_target(struct command_context *cmd_ctx, struct target *ta { LOG_DEBUG("%s", __func__); target->state = TARGET_UNKNOWN; + target->debug_reason = DBG_REASON_UNDEFINED; return ERROR_OK; } @@ -82,8 +87,10 @@ static int mem_ap_arch_state(struct target *target) static int mem_ap_poll(struct target *target) { - if (target->state == TARGET_UNKNOWN) + if (target->state == TARGET_UNKNOWN) { target->state = TARGET_RUNNING; + target->debug_reason = DBG_REASON_NOTHALTED; + } return ERROR_OK; } @@ -92,6 +99,8 @@ static int mem_ap_halt(struct target *target) { LOG_DEBUG("%s", __func__); target->state = TARGET_HALTED; + target->debug_reason = DBG_REASON_DBGRQ; + target_call_event_callbacks(target, TARGET_EVENT_HALTED); return ERROR_OK; } @@ -100,6 +109,7 @@ static int mem_ap_resume(struct target *target, int current, target_addr_t addre { LOG_DEBUG("%s", __func__); target->state = TARGET_RUNNING; + target->debug_reason = DBG_REASON_NOTHALTED; return ERROR_OK; } @@ -108,12 +118,15 @@ static int mem_ap_step(struct target *target, int current, target_addr_t address { LOG_DEBUG("%s", __func__); target->state = TARGET_HALTED; + target->debug_reason = DBG_REASON_DBGRQ; + target_call_event_callbacks(target, TARGET_EVENT_HALTED); return ERROR_OK; } static int mem_ap_assert_reset(struct target *target) { target->state = TARGET_RESET; + target->debug_reason = DBG_REASON_UNDEFINED; LOG_DEBUG("%s", __func__); return ERROR_OK; @@ -127,6 +140,7 @@ static int mem_ap_examine(struct target *target) mem_ap->ap = dap_ap(mem_ap->arm.dap, mem_ap->ap_num); target_set_examined(target); target->state = TARGET_UNKNOWN; + target->debug_reason = DBG_REASON_UNDEFINED; return mem_ap_init(mem_ap->ap); } @@ -135,15 +149,85 @@ static int mem_ap_examine(struct target *target) static int mem_ap_deassert_reset(struct target *target) { - if (target->reset_halt) + if (target->reset_halt) { target->state = TARGET_HALTED; - else + target->debug_reason = DBG_REASON_DBGRQ; + target_call_event_callbacks(target, TARGET_EVENT_HALTED); + } else { target->state = TARGET_RUNNING; + target->debug_reason = DBG_REASON_NOTHALTED; + } LOG_DEBUG("%s", __func__); return ERROR_OK; } +static int mem_ap_reg_get(struct reg *reg) +{ + return ERROR_OK; +} + +static int mem_ap_reg_set(struct reg *reg, uint8_t *buf) +{ + return ERROR_OK; +} + +static struct reg_arch_type mem_ap_reg_arch_type = { + .get = mem_ap_reg_get, + .set = mem_ap_reg_set, +}; + +const char *mem_ap_get_gdb_arch(struct target *target) +{ + return "arm"; +} + +/* + * Dummy ARM register emulation: + * reg[0..15]: 32 bits, r0~r12, sp, lr, pc + * reg[16..23]: 96 bits, f0~f7 + * reg[24]: 32 bits, fps + * reg[25]: 32 bits, cpsr + * + * Set 'exist' only to reg[0..15], so initial response to GDB is correct + */ +#define NUM_REGS 26 +#define MAX_REG_SIZE 96 +#define REG_EXIST(n) ((n) < 16) +#define REG_SIZE(n) ((((n) >= 16) && ((n) < 24)) ? 96 : 32) + +struct mem_ap_alloc_reg_list { + /* reg_list must be the first field */ + struct reg *reg_list[NUM_REGS]; + struct reg regs[NUM_REGS]; + uint8_t regs_value[MAX_REG_SIZE / 8]; +}; + +static int mem_ap_get_gdb_reg_list(struct target *target, struct reg **reg_list[], + int *reg_list_size, enum target_register_class reg_class) +{ + struct mem_ap_alloc_reg_list *mem_ap_alloc = calloc(1, sizeof(struct mem_ap_alloc_reg_list)); + if (!mem_ap_alloc) { + LOG_ERROR("Out of memory"); + return ERROR_FAIL; + } + + *reg_list = mem_ap_alloc->reg_list; + *reg_list_size = NUM_REGS; + struct reg *regs = mem_ap_alloc->regs; + + for (int i = 0; i < NUM_REGS; i++) { + regs[i].number = i; + regs[i].value = mem_ap_alloc->regs_value; + regs[i].size = REG_SIZE(i); + regs[i].exist = REG_EXIST(i); + regs[i].type = &mem_ap_reg_arch_type; + (*reg_list)[i] = ®s[i]; + } + + return ERROR_OK; +} + static int mem_ap_read_memory(struct target *target, target_addr_t address, uint32_t size, uint32_t count, uint8_t *buffer) { @@ -192,6 +276,9 @@ struct target_type mem_ap_target = { .assert_reset = mem_ap_assert_reset, .deassert_reset = mem_ap_deassert_reset, + .get_gdb_arch = mem_ap_get_gdb_arch, + .get_gdb_reg_list = mem_ap_get_gdb_reg_list, + .read_memory = mem_ap_read_memory, .write_memory = mem_ap_write_memory, }; diff --git a/src/target/mips32_pracc.c b/src/target/mips32_pracc.c index d6bd1c58a..f8643fa2d 100644 --- a/src/target/mips32_pracc.c +++ b/src/target/mips32_pracc.c @@ -317,7 +317,7 @@ void pracc_add(struct pracc_queue_info *ctx, uint32_t addr, uint32_t instr) if (ctx->retval != ERROR_OK) /* On previous out of memory, return */ return; if (ctx->code_count == ctx->max_code) { - void *p = realloc(ctx->pracc_list, sizeof(pa_list) * (ctx->max_code + PRACC_BLOCK)); + void *p = realloc(ctx->pracc_list, sizeof(struct pa_list) * (ctx->max_code + PRACC_BLOCK)); if (p) { ctx->max_code += PRACC_BLOCK; ctx->pracc_list = p; diff --git a/src/target/mips32_pracc.h b/src/target/mips32_pracc.h index 911a69c5b..30edaec0a 100644 --- a/src/target/mips32_pracc.h +++ b/src/target/mips32_pracc.h @@ -47,10 +47,10 @@ #define PRACC_BLOCK 128 /* 1 Kbyte */ -typedef struct { +struct pa_list { uint32_t instr; uint32_t addr; -} pa_list; +}; struct pracc_queue_info { struct mips_ejtag *ejtag_info; @@ -59,7 +59,7 @@ struct pracc_queue_info { int code_count; int store_count; int max_code; /* max instructions with currently allocated memory */ - pa_list *pracc_list; /* Code and store addresses at dmseg */ + struct pa_list *pracc_list; /* Code and store addresses at dmseg */ }; void pracc_queue_init(struct pracc_queue_info *ctx); diff --git a/src/target/mips64_pracc.c b/src/target/mips64_pracc.c index 3080046f3..dbad248fc 100644 --- a/src/target/mips64_pracc.c +++ b/src/target/mips64_pracc.c @@ -24,7 +24,7 @@ #define STACK_DEPTH 32 -typedef struct { +struct mips64_pracc_context { uint64_t *local_iparam; unsigned num_iparam; uint64_t *local_oparam; @@ -34,7 +34,7 @@ typedef struct { uint64_t stack[STACK_DEPTH]; unsigned stack_offset; struct mips_ejtag *ejtag_info; -} mips64_pracc_context; +}; static int wait_for_pracc_rw(struct mips_ejtag *ejtag_info, uint32_t *ctrl) { @@ -61,7 +61,7 @@ static int wait_for_pracc_rw(struct mips_ejtag *ejtag_info, uint32_t *ctrl) return ERROR_OK; } -static int mips64_pracc_exec_read(mips64_pracc_context *ctx, uint64_t address) +static int mips64_pracc_exec_read(struct mips64_pracc_context *ctx, uint64_t address) { struct mips_ejtag *ejtag_info = ctx->ejtag_info; unsigned offset; @@ -149,7 +149,7 @@ static int mips64_pracc_exec_read(mips64_pracc_context *ctx, uint64_t address) return jtag_execute_queue(); } -static int mips64_pracc_exec_write(mips64_pracc_context *ctx, uint64_t address) +static int mips64_pracc_exec_write(struct mips64_pracc_context *ctx, uint64_t address) { uint32_t ejtag_ctrl; uint64_t data; @@ -214,7 +214,7 @@ int mips64_pracc_exec(struct mips_ejtag *ejtag_info, { uint32_t ejtag_ctrl; uint64_t address = 0, address_prev = 0, data; - mips64_pracc_context ctx; + struct mips64_pracc_context ctx; int retval; int pass = 0; bool first_time_call = true; diff --git a/src/target/mips_ejtag.c b/src/target/mips_ejtag.c index 4b049fb4e..d4c019fbe 100644 --- a/src/target/mips_ejtag.c +++ b/src/target/mips_ejtag.c @@ -268,7 +268,7 @@ error: int mips_ejtag_exit_debug(struct mips_ejtag *ejtag_info) { - pa_list pracc_list = {.instr = MIPS32_DRET(ejtag_info->isa), .addr = 0}; + struct pa_list pracc_list = {.instr = MIPS32_DRET(ejtag_info->isa), .addr = 0}; struct pracc_queue_info ctx = {.max_code = 1, .pracc_list = &pracc_list, .code_count = 1, .store_count = 0}; /* execute our dret instruction */ diff --git a/src/target/oocd_trace.c b/src/target/oocd_trace.c deleted file mode 100644 index f38916a0b..000000000 --- a/src/target/oocd_trace.c +++ /dev/null @@ -1,417 +0,0 @@ -/*************************************************************************** - * Copyright (C) 2007 by Dominic Rath * - * Dominic.Rath@gmx.de * - * * - * 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 . * - ***************************************************************************/ - -#ifdef HAVE_CONFIG_H -#include "config.h" -#endif - -#include "arm.h" -#include "etm.h" -#include "oocd_trace.h" - -/* - * This is "proof of concept" code, for prototype hardware: - * https://lists.berlios.de/pipermail/openocd-development/2007-September/000336.html - */ - -static int oocd_trace_read_reg(struct oocd_trace *oocd_trace, int reg, uint32_t *value) -{ - size_t bytes_written, bytes_read, bytes_to_read; - uint8_t cmd; - - cmd = 0x10 | (reg & 0x7); - bytes_written = write(oocd_trace->tty_fd, &cmd, 1); - if (bytes_written < 1) - return ERROR_FAIL; - - bytes_to_read = 4; - while (bytes_to_read > 0) { - bytes_read = read(oocd_trace->tty_fd, ((uint8_t *)value) + 4 - bytes_to_read, bytes_to_read); - bytes_to_read -= bytes_read; - } - - LOG_DEBUG("reg #%i: 0x%8.8x", reg, *value); - - return ERROR_OK; -} - -static int oocd_trace_write_reg(struct oocd_trace *oocd_trace, int reg, uint32_t value) -{ - size_t bytes_written; - uint8_t data[5]; - - data[0] = 0x18 | (reg & 0x7); - data[1] = value & 0xff; - data[2] = (value & 0xff00) >> 8; - data[3] = (value & 0xff0000) >> 16; - data[4] = (value & 0xff000000) >> 24; - - bytes_written = write(oocd_trace->tty_fd, data, 5); - if (bytes_written < 5) - return ERROR_FAIL; - - LOG_DEBUG("reg #%i: 0x%8.8x", reg, value); - - return ERROR_OK; -} - -static int oocd_trace_read_memory(struct oocd_trace *oocd_trace, uint8_t *data, uint32_t address, uint32_t size) -{ - size_t bytes_written, bytes_to_read; - ssize_t bytes_read; - uint8_t cmd; - - oocd_trace_write_reg(oocd_trace, OOCD_TRACE_ADDRESS, address); - oocd_trace_write_reg(oocd_trace, OOCD_TRACE_SDRAM_COUNTER, size); - - cmd = 0x20; - bytes_written = write(oocd_trace->tty_fd, &cmd, 1); - if (bytes_written < 1) - return ERROR_FAIL; - - bytes_to_read = size * 16; - while (bytes_to_read > 0) { - bytes_read = read(oocd_trace->tty_fd, - ((uint8_t *)data) + (size * 16) - bytes_to_read, bytes_to_read); - if (bytes_read < 0) - LOG_DEBUG("read() returned %zi (%s)", bytes_read, strerror(errno)); - else - bytes_to_read -= bytes_read; - } - - return ERROR_OK; -} - -static int oocd_trace_init(struct etm_context *etm_ctx) -{ - uint8_t trash[256]; - struct oocd_trace *oocd_trace = etm_ctx->capture_driver_priv; - size_t bytes_read; - - oocd_trace->tty_fd = open(oocd_trace->tty, O_RDWR | O_NOCTTY | O_NONBLOCK); - - if (oocd_trace->tty_fd < 0) { - LOG_ERROR("can't open tty"); - return ERROR_ETM_CAPTURE_INIT_FAILED; - } - - /* clear input & output buffers, then switch to "blocking mode" */ - tcflush(oocd_trace->tty_fd, TCOFLUSH); - tcflush(oocd_trace->tty_fd, TCIFLUSH); - fcntl(oocd_trace->tty_fd, F_SETFL, fcntl(oocd_trace->tty_fd, F_GETFL) & ~O_NONBLOCK); - - tcgetattr(oocd_trace->tty_fd, &oocd_trace->oldtio); /* save current port settings */ - - bzero(&oocd_trace->newtio, sizeof(oocd_trace->newtio)); - oocd_trace->newtio.c_cflag = CS8 | CLOCAL | CREAD | B2500000; - - oocd_trace->newtio.c_iflag = IGNPAR | IGNBRK | IXON | IXOFF; - oocd_trace->newtio.c_oflag = 0; - - /* set input mode (non-canonical, no echo,...) */ - oocd_trace->newtio.c_lflag = 0; - - cfmakeraw(&oocd_trace->newtio); - oocd_trace->newtio.c_cc[VTIME] = 1; /* inter-character timer used */ - oocd_trace->newtio.c_cc[VMIN] = 0; /* blocking read until 0 chars received */ - - tcflush(oocd_trace->tty_fd, TCIFLUSH); - tcsetattr(oocd_trace->tty_fd, TCSANOW, &oocd_trace->newtio); - - /* occasionally one bogus character is left in the input buffer - * read up any leftover characters to ensure communication is in sync */ - do { - bytes_read = read(oocd_trace->tty_fd, trash, sizeof(trash)); - if (bytes_read) - LOG_DEBUG("%zi bytes read", bytes_read); - } while (bytes_read > 0); - - return ERROR_OK; -} - -static trace_status_t oocd_trace_status(struct etm_context *etm_ctx) -{ - struct oocd_trace *oocd_trace = etm_ctx->capture_driver_priv; - uint32_t status; - - oocd_trace_read_reg(oocd_trace, OOCD_TRACE_STATUS, &status); - - /* if tracing is currently idle, return this information */ - if (etm_ctx->capture_status == TRACE_IDLE) - return etm_ctx->capture_status; - else if (etm_ctx->capture_status & TRACE_RUNNING) { - /* check Full bit to identify an overflow */ - if (status & 0x4) - etm_ctx->capture_status |= TRACE_OVERFLOWED; - - /* check Triggered bit to identify trigger condition */ - if (status & 0x2) - etm_ctx->capture_status |= TRACE_TRIGGERED; - - if (status & 0x1) { - etm_ctx->capture_status &= ~TRACE_RUNNING; - etm_ctx->capture_status |= TRACE_COMPLETED; - } - } - - return etm_ctx->capture_status; -} - -static int oocd_trace_read_trace(struct etm_context *etm_ctx) -{ - struct oocd_trace *oocd_trace = etm_ctx->capture_driver_priv; - uint32_t status, address; - uint32_t first_frame = 0x0; - uint32_t num_frames = 1048576; - uint8_t *trace_data; - uint32_t i; - - oocd_trace_read_reg(oocd_trace, OOCD_TRACE_STATUS, &status); - oocd_trace_read_reg(oocd_trace, OOCD_TRACE_ADDRESS, &address); - - /* check if we overflowed, and adjust first frame of the trace accordingly - * if we didn't overflow, read only up to the frame that would be written next, - * i.e. don't read invalid entries - */ - if (status & 0x4) - first_frame = address; - else - num_frames = address; - - /* read data into temporary array for unpacking - * one frame from OpenOCD + trace corresponds to 16 trace cycles - */ - trace_data = malloc(sizeof(uint8_t) * num_frames * 16); - oocd_trace_read_memory(oocd_trace, trace_data, first_frame, num_frames); - - if (etm_ctx->trace_depth > 0) - free(etm_ctx->trace_data); - - etm_ctx->trace_depth = num_frames * 16; - etm_ctx->trace_data = malloc(sizeof(struct etmv1_trace_data) * etm_ctx->trace_depth); - - for (i = 0; i < num_frames * 16; i++) { - etm_ctx->trace_data[i].pipestat = (trace_data[i] & 0x7); - etm_ctx->trace_data[i].packet = (trace_data[i] & 0x78) >> 3; - etm_ctx->trace_data[i].flags = 0; - - if ((trace_data[i] & 0x80) >> 7) - etm_ctx->trace_data[i].flags |= ETMV1_TRACESYNC_CYCLE; - - if (etm_ctx->trace_data[i].pipestat == STAT_TR) { - etm_ctx->trace_data[i].pipestat = etm_ctx->trace_data[i].packet & 0x7; - etm_ctx->trace_data[i].flags |= ETMV1_TRIGGER_CYCLE; - } - } - - free(trace_data); - - return ERROR_OK; -} - -static int oocd_trace_start_capture(struct etm_context *etm_ctx) -{ - struct oocd_trace *oocd_trace = etm_ctx->capture_driver_priv; - uint32_t control = 0x1; /* 0x1: enabled */ - uint32_t trigger_count; - - if (((etm_ctx->control & ETM_PORT_MODE_MASK) != ETM_PORT_NORMAL) - || ((etm_ctx->control & ETM_PORT_WIDTH_MASK) != ETM_PORT_4BIT)) { - LOG_DEBUG("OpenOCD + trace only supports normal 4-bit ETM mode"); - return ERROR_ETM_PORTMODE_NOT_SUPPORTED; - } - - if ((etm_ctx->control & ETM_PORT_CLOCK_MASK) == ETM_PORT_HALF_CLOCK) - control |= 0x2; /* half rate clock, capture at twice the clock rate */ - - /* OpenOCD + trace holds up to 16 million samples, - * but trigger counts is set in multiples of 16 */ - trigger_count = (1048576 * /* trigger_percent */ 50) / 100; - - /* capturing always starts at address zero */ - oocd_trace_write_reg(oocd_trace, OOCD_TRACE_ADDRESS, 0x0); - oocd_trace_write_reg(oocd_trace, OOCD_TRACE_TRIGGER_COUNTER, trigger_count); - oocd_trace_write_reg(oocd_trace, OOCD_TRACE_CONTROL, control); - - /* we're starting a new trace, initialize capture status */ - etm_ctx->capture_status = TRACE_RUNNING; - - return ERROR_OK; -} - -static int oocd_trace_stop_capture(struct etm_context *etm_ctx) -{ - struct oocd_trace *oocd_trace = etm_ctx->capture_driver_priv; - - /* trace stopped, just clear running flag, but preserve others */ - etm_ctx->capture_status &= ~TRACE_RUNNING; - - oocd_trace_write_reg(oocd_trace, OOCD_TRACE_CONTROL, 0x0); - - return ERROR_OK; -} - -COMMAND_HANDLER(handle_oocd_trace_config_command) -{ - struct target *target; - struct arm *arm; - - if (CMD_ARGC != 2) - return ERROR_COMMAND_SYNTAX_ERROR; - - target = get_current_target(CMD_CTX); - arm = target_to_arm(target); - if (!is_arm(arm)) { - command_print(CMD, "current target isn't an ARM"); - return ERROR_FAIL; - } - - if (arm->etm) { - struct oocd_trace *oocd_trace = malloc(sizeof(struct oocd_trace)); - - arm->etm->capture_driver_priv = oocd_trace; - oocd_trace->etm_ctx = arm->etm; - - /* copy name of TTY device used to communicate with OpenOCD + trace */ - oocd_trace->tty = strndup(CMD_ARGV[1], 256); - } else - LOG_ERROR("target has no ETM defined, OpenOCD + trace left unconfigured"); - - return ERROR_OK; -} - -COMMAND_HANDLER(handle_oocd_trace_status_command) -{ - struct target *target; - struct arm *arm; - struct oocd_trace *oocd_trace; - uint32_t status; - - target = get_current_target(CMD_CTX); - - arm = target_to_arm(target); - if (!is_arm(arm)) { - command_print(CMD, "current target isn't an ARM"); - return ERROR_FAIL; - } - - if (!arm->etm) { - command_print(CMD, "current target doesn't have an ETM configured"); - return ERROR_FAIL; - } - - if (strcmp(arm->etm->capture_driver->name, "oocd_trace") != 0) { - command_print(CMD, "current target's ETM capture driver isn't 'oocd_trace'"); - return ERROR_FAIL; - } - - oocd_trace = (struct oocd_trace *)arm->etm->capture_driver_priv; - - oocd_trace_read_reg(oocd_trace, OOCD_TRACE_STATUS, &status); - - if (status & 0x8) - command_print(CMD, "trace clock locked"); - else - command_print(CMD, "no trace clock"); - - return ERROR_OK; -} - -COMMAND_HANDLER(handle_oocd_trace_resync_command) -{ - struct target *target; - struct arm *arm; - struct oocd_trace *oocd_trace; - size_t bytes_written; - uint8_t cmd_array[1]; - - target = get_current_target(CMD_CTX); - - arm = target_to_arm(target); - if (!is_arm(arm)) { - command_print(CMD, "current target isn't an ARM"); - return ERROR_FAIL; - } - - if (!arm->etm) { - command_print(CMD, "current target doesn't have an ETM configured"); - return ERROR_FAIL; - } - - if (strcmp(arm->etm->capture_driver->name, "oocd_trace") != 0) { - command_print(CMD, "current target's ETM capture driver isn't 'oocd_trace'"); - return ERROR_FAIL; - } - - oocd_trace = (struct oocd_trace *)arm->etm->capture_driver_priv; - - cmd_array[0] = 0xf0; - - bytes_written = write(oocd_trace->tty_fd, cmd_array, 1); - if (bytes_written < 1) - return ERROR_FAIL; - - command_print(CMD, "requesting traceclock resync"); - LOG_DEBUG("resyncing traceclk pll"); - - return ERROR_OK; -} - -static const struct command_registration oocd_trace_all_command_handlers[] = { - { - .name = "config", - .handler = handle_oocd_trace_config_command, - .mode = COMMAND_CONFIG, - .usage = " ", - }, - { - .name = "status", - .handler = handle_oocd_trace_status_command, - .mode = COMMAND_EXEC, - .usage = "", - .help = "display OpenOCD + trace status", - }, - { - .name = "resync", - .handler = handle_oocd_trace_resync_command, - .mode = COMMAND_EXEC, - .usage = "", - .help = "resync OpenOCD + trace capture clock", - }, - COMMAND_REGISTRATION_DONE -}; -static const struct command_registration oocd_trace_command_handlers[] = { - { - .name = "oocd_trace", - .mode = COMMAND_ANY, - .help = "OpenOCD trace capture driver command group", - .usage = "", - .chain = oocd_trace_all_command_handlers, - }, - COMMAND_REGISTRATION_DONE -}; - -struct etm_capture_driver oocd_trace_capture_driver = { - .name = "oocd_trace", - .commands = oocd_trace_command_handlers, - .init = oocd_trace_init, - .status = oocd_trace_status, - .start_capture = oocd_trace_start_capture, - .stop_capture = oocd_trace_stop_capture, - .read_trace = oocd_trace_read_trace, -}; diff --git a/src/target/oocd_trace.h b/src/target/oocd_trace.h deleted file mode 100644 index e7584e4c9..000000000 --- a/src/target/oocd_trace.h +++ /dev/null @@ -1,53 +0,0 @@ -/*************************************************************************** - * Copyright (C) 2007 by Dominic Rath * - * Dominic.Rath@gmx.de * - * * - * 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 . * - ***************************************************************************/ - -#ifndef OPENOCD_TARGET_OOCD_TRACE_H -#define OPENOCD_TARGET_OOCD_TRACE_H - -#include - -/* registers */ -enum { - OOCD_TRACE_ID = 0x7, - OOCD_TRACE_ADDRESS = 0x0, - OOCD_TRACE_TRIGGER_COUNTER = 0x01, - OOCD_TRACE_CONTROL = 0x2, - OOCD_TRACE_STATUS = 0x3, - OOCD_TRACE_SDRAM_COUNTER = 0x4, -}; - -/* commands */ -enum { - OOCD_TRACE_NOP = 0x0, - OOCD_TRACE_READ_REG = 0x10, - OOCD_TRACE_WRITE_REG = 0x18, - OOCD_TRACE_READ_RAM = 0x20, -/* OOCD_TRACE_WRITE_RAM = 0x28, */ - OOCD_TRACE_RESYNC = 0xf0, -}; - -struct oocd_trace { - struct etm_context *etm_ctx; - char *tty; - int tty_fd; - struct termios oldtio, newtio; -}; - -extern struct etm_capture_driver oocd_trace_capture_driver; - -#endif /* OPENOCD_TARGET_OOCD_TRACE_H */ diff --git a/src/target/openrisc/jsp_server.c b/src/target/openrisc/jsp_server.c index b4b25665d..4dbe63527 100644 --- a/src/target/openrisc/jsp_server.c +++ b/src/target/openrisc/jsp_server.c @@ -207,8 +207,7 @@ int jsp_init(struct or1k_jtag *jtag_info, char *banner) jsp_new_connection, jsp_input, jsp_connection_closed, - jsp_service, - NULL); + jsp_service); } COMMAND_HANDLER(handle_jsp_port_command) diff --git a/src/target/riscv/riscv.c b/src/target/riscv/riscv.c index ef05118fe..4b8b804ad 100644 --- a/src/target/riscv/riscv.c +++ b/src/target/riscv/riscv.c @@ -1918,7 +1918,7 @@ static int riscv_checksum_memory(struct target *target, struct reg_param reg_params[2]; int retval; - LOG_DEBUG("address=0x%" TARGET_PRIxADDR "; count=0x%x", address, count); + LOG_DEBUG("address=0x%" TARGET_PRIxADDR "; count=0x%" PRIx32, address, count); static const uint8_t riscv32_crc_code[] = { #include "../../contrib/loaders/checksum/riscv32_crc.inc" @@ -1929,7 +1929,7 @@ static int riscv_checksum_memory(struct target *target, static const uint8_t *crc_code; - int xlen = riscv_xlen(target); + unsigned xlen = riscv_xlen(target); unsigned crc_code_size; if (xlen == 32) { crc_code = riscv32_crc_code; @@ -1991,7 +1991,7 @@ static int riscv_checksum_memory(struct target *target, target_free_working_area(target, crc_algorithm); - LOG_DEBUG("checksum=0x%x, result=%d", *checksum, retval); + LOG_DEBUG("checksum=0x%" PRIx32 ", result=%d", *checksum, retval); return retval; } diff --git a/src/target/startup.tcl b/src/target/startup.tcl index ca39b1816..a8f78ab49 100644 --- a/src/target/startup.tcl +++ b/src/target/startup.tcl @@ -179,12 +179,6 @@ proc using_hla {} { ######### -# Temporary migration aid. May be removed starting in January 2011. -proc armv4_5 params { - echo "DEPRECATED! use 'arm $params' not 'armv4_5 $params'" - arm $params -} - # Target/chain configuration scripts can either execute commands directly # or define a procedure which is executed once all configuration # scripts have completed. @@ -212,14 +206,3 @@ proc init_target_events {} { # Additionally board config scripts can define a procedure init_board that will be executed after init and init_targets proc init_board {} { } - -# deprecated target name cmds -proc cortex_m3 args { - echo "DEPRECATED! use 'cortex_m' not 'cortex_m3'" - eval cortex_m $args -} - -proc cortex_a8 args { - echo "DEPRECATED! use 'cortex_a' not 'cortex_a8'" - eval cortex_a $args -} diff --git a/src/target/target.c b/src/target/target.c index 86178a043..84c74e500 100644 --- a/src/target/target.c +++ b/src/target/target.c @@ -637,7 +637,18 @@ int target_resume(struct target *target, int current, target_addr_t address, * we poll. The CPU can even halt at the current PC as a result of * a software breakpoint being inserted by (a bug?) the application. */ + /* + * resume() triggers the event 'resumed'. The execution of TCL commands + * in the event handler causes the polling of targets. If the target has + * already halted for a breakpoint, polling will run the 'halted' event + * handler before the pending 'resumed' handler. + * Disable polling during resume() to guarantee the execution of handlers + * in the correct order. + */ + bool save_poll = jtag_poll_get_enabled(); + jtag_poll_set_enabled(false); retval = target->type->resume(target, current, address, handle_breakpoints, debug_execution); + jtag_poll_set_enabled(save_poll); if (retval != ERROR_OK) return retval; @@ -4087,7 +4098,7 @@ COMMAND_HANDLER(handle_wp_command) } enum watchpoint_rw type = WPT_ACCESS; - uint32_t addr = 0; + target_addr_t addr = 0; uint32_t length = 0; uint32_t data_value = 0x0; uint32_t data_mask = 0xffffffff; @@ -4117,7 +4128,7 @@ COMMAND_HANDLER(handle_wp_command) /* fall through */ case 2: COMMAND_PARSE_NUMBER(u32, CMD_ARGV[1], length); - COMMAND_PARSE_NUMBER(u32, CMD_ARGV[0], addr); + COMMAND_PARSE_ADDRESS(CMD_ARGV[0], addr); break; default: @@ -4137,8 +4148,8 @@ COMMAND_HANDLER(handle_rwp_command) if (CMD_ARGC != 1) return ERROR_COMMAND_SYNTAX_ERROR; - uint32_t addr; - COMMAND_PARSE_NUMBER(u32, CMD_ARGV[0], addr); + target_addr_t addr; + COMMAND_PARSE_ADDRESS(CMD_ARGV[0], addr); struct target *target = get_current_target(CMD_CTX); watchpoint_remove(target, addr); @@ -4966,6 +4977,11 @@ no_params: } if (goi->isconfigure) { + /* START_DEPRECATED_TPIU */ + if (n->value == TARGET_EVENT_TRACE_CONFIG) + LOG_INFO("DEPRECATED target event %s", n->name); + /* END_DEPRECATED_TPIU */ + bool replace = true; if (teap == NULL) { /* create new */ @@ -5694,15 +5710,6 @@ static int target_create(Jim_GetOptInfo *goi) /* found */ break; } - - /* check for deprecated name */ - if (target_types[x]->deprecated_name) { - if (0 == strcmp(cp, target_types[x]->deprecated_name)) { - /* found */ - LOG_WARNING("target name is deprecated use: \'%s\'", target_types[x]->name); - break; - } - } } if (target_types[x] == NULL) { Jim_SetResultFormatted(goi->interp, "Unknown target type %s, try one of ", cp); @@ -5742,9 +5749,6 @@ static int target_create(Jim_GetOptInfo *goi) memcpy(target->type, target_types[x], sizeof(struct target_type)); - /* will be set by "-endian" */ - target->endianness = TARGET_ENDIAN_UNKNOWN; - /* default to first core, override with -coreid */ target->coreid = 0; diff --git a/src/target/target_type.h b/src/target/target_type.h index 87ef829ae..f7b4c94a6 100644 --- a/src/target/target_type.h +++ b/src/target/target_type.h @@ -40,7 +40,6 @@ struct target_type { * field directly, use target_type_name() instead. */ const char *name; - const char *deprecated_name; /* poll current target status */ int (*poll)(struct target *target); diff --git a/src/transport/transport.h b/src/transport/transport.h index 6bf6aaced..e04f78063 100644 --- a/src/transport/transport.h +++ b/src/transport/transport.h @@ -98,7 +98,7 @@ bool transport_is_dapdirect_jtag(void); bool transport_is_dapdirect_swd(void); bool transport_is_swim(void); -#if BUILD_HLADAPTER && !HAVE_JTAG_MINIDRIVER_H +#if BUILD_HLADAPTER bool transport_is_hla(void); #else static inline bool transport_is_hla(void) diff --git a/tcl/board/altera_sockit.cfg b/tcl/board/altera_sockit.cfg index eb4c863fa..b7c7993fe 100644 --- a/tcl/board/altera_sockit.cfg +++ b/tcl/board/altera_sockit.cfg @@ -12,7 +12,7 @@ adapter driver usb_blaster source [find target/altera_fpgasoc.cfg] # If the USB Blaster II were supported, these settings would be needed -#usb_blaster_vid_pid 0x6810 0x09fb +#usb_blaster_vid_pid 0x09fb 0x6810 #usb_blaster_device_desc "USB-Blaster II" adapter speed 100 diff --git a/tcl/board/ampere_emag8180.cfg b/tcl/board/ampere_emag8180.cfg new file mode 100644 index 000000000..a122e0288 --- /dev/null +++ b/tcl/board/ampere_emag8180.cfg @@ -0,0 +1,38 @@ +# +# OpenOCD Board Configuration for eMAG Development Platform +# +# Copyright (c) 2019-2021, Ampere Computing LLC +# +# 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; +# +# + +# +# Configure JTAG speed +# + +adapter speed 2000 + +# +# Configure Resets +# + +jtag_ntrst_delay 100 +reset_config trst_only + +# +# Configure Targets +# + +source [find target/ampere_emag.cfg] diff --git a/tcl/board/olimex_stm32_h405.cfg b/tcl/board/olimex_stm32_h405.cfg new file mode 100644 index 000000000..f2f1d7f24 --- /dev/null +++ b/tcl/board/olimex_stm32_h405.cfg @@ -0,0 +1,8 @@ +# SPDX-License-Identifier: GPL-2.0-or-later +# Olimex STM32-H405 eval board +# https://www.olimex.com/Products/ARM/ST/STM32-H405/ + +# Work-area size (RAM size) = 128kB for STM32F405RG device +set WORKAREASIZE 0x20000 + +source [find target/stm32f4x.cfg] diff --git a/tcl/board/ti_am642evm.cfg b/tcl/board/ti_am642evm.cfg new file mode 100644 index 000000000..e97fdcf13 --- /dev/null +++ b/tcl/board/ti_am642evm.cfg @@ -0,0 +1,24 @@ +# SPDX-License-Identifier: GPL-2.0-or-later +# Copyright (C) 2019-2021 Texas Instruments Incorporated - http://www.ti.com/ +# +# Texas Instruments AM642 EVM +# + +# AM642 EVM has an xds110 onboard. +source [find interface/xds110.cfg] + +transport select jtag + +# default JTAG configuration has only SRST and no TRST +reset_config srst_only srst_push_pull + +# delay after SRST goes inactive +adapter srst delay 20 + +if { ![info exists SOC] } { + set SOC am642 +} + +source [find target/ti_k3.cfg] + +adapter speed 250 diff --git a/tcl/board/ti_am654evm.cfg b/tcl/board/ti_am654evm.cfg new file mode 100644 index 000000000..a661f6068 --- /dev/null +++ b/tcl/board/ti_am654evm.cfg @@ -0,0 +1,24 @@ +# SPDX-License-Identifier: GPL-2.0-or-later +# Copyright (C) 2019-2021 Texas Instruments Incorporated - http://www.ti.com/ +# +# Texas Instruments AM654 EVM/IDK Base Board +# + +# AM654 EVM has an xds110 onboard. +source [find interface/xds110.cfg] + +transport select jtag + +# default JTAG configuration has only SRST and no TRST +reset_config srst_only srst_push_pull + +# delay after SRST goes inactive +adapter srst delay 70 + +if { ![info exists SOC] } { + set SOC am654 +} + +source [find target/ti_k3.cfg] + +adapter speed 2500 diff --git a/tcl/board/ti_j7200evm.cfg b/tcl/board/ti_j7200evm.cfg new file mode 100644 index 000000000..cc70056fb --- /dev/null +++ b/tcl/board/ti_j7200evm.cfg @@ -0,0 +1,24 @@ +# SPDX-License-Identifier: GPL-2.0-or-later +# Copyright (C) 2019-2021 Texas Instruments Incorporated - http://www.ti.com/ +# +# Texas Instruments J7200 EVM +# + +# J7200 EVM has an xds110 onboard. +source [find interface/xds110.cfg] + +transport select jtag + +# default JTAG configuration has only SRST and no TRST +reset_config srst_only srst_push_pull + +# delay after SRST goes inactive +adapter srst delay 20 + +if { ![info exists SOC] } { + set SOC j7200 +} + +source [find target/ti_k3.cfg] + +adapter speed 2500 diff --git a/tcl/board/ti_j721evm.cfg b/tcl/board/ti_j721evm.cfg new file mode 100644 index 000000000..d0c4b7496 --- /dev/null +++ b/tcl/board/ti_j721evm.cfg @@ -0,0 +1,24 @@ +# SPDX-License-Identifier: GPL-2.0-or-later +# Copyright (C) 2019-2021 Texas Instruments Incorporated - http://www.ti.com/ +# +# Texas Instruments J721E EVM +# + +# J721E EVM has an xds110 onboard. +source [find interface/xds110.cfg] + +transport select jtag + +# default JTAG configuration has only SRST and no TRST +reset_config srst_only srst_push_pull + +# delay after SRST goes inactive +adapter srst delay 20 + +if { ![info exists SOC] } { + set SOC j721e +} + +source [find target/ti_k3.cfg] + +adapter speed 2500 diff --git a/tcl/board/zy1000.cfg b/tcl/board/zy1000.cfg deleted file mode 100644 index e0d1ccf84..000000000 --- a/tcl/board/zy1000.cfg +++ /dev/null @@ -1,117 +0,0 @@ -#Script for ZY1000 - -#Atmel ties SRST & TRST together, at which point it makes -#no sense to use TRST, but use TMS instead. -# -#The annoying thing with tying SRST & TRST together is that -#there is no way to halt the CPU *before and during* the -#SRST reset, which means that the CPU will run a number -#of cycles before it can be halted(as much as milliseconds). -reset_config srst_only srst_pulls_trst - - -if { [info exists CHIPNAME] } { - set _CHIPNAME $CHIPNAME -} else { - set _CHIPNAME zy1000 -} - -if { [info exists ENDIAN] } { - set _ENDIAN $ENDIAN -} else { - set _ENDIAN little -} - - -#jtag scan chain -if { [info exists CPUTAPID] } { - set _CPUTAPID $CPUTAPID -} else { - set _CPUTAPID 0x1f0f0f0f -} -jtag newtap $_CHIPNAME cpu -irlen 4 -ircapture 0x1 -irmask 0xf -expected-id $_CPUTAPID - -set _TARGETNAME $_CHIPNAME.cpu -target create $_TARGETNAME arm7tdmi -endian $_ENDIAN -chain-position $_TARGETNAME - -# at CPU CLK <32kHz this must be disabled -arm7_9 fast_memory_access enable -arm7_9 dcc_downloads enable - -set _FLASHNAME $_CHIPNAME.flash -flash bank $_FLASHNAME cfi 0x01000000 0x200000 2 2 $_TARGETNAME - -$_TARGETNAME configure -event reset-init { - # Set up chip selects & timings - mww 0xFFE00000 0x0100273D - mww 0xFFE00004 0x08002125 - mww 0xFFEe0008 0x02002125 - mww 0xFFE0000c 0x03002125 - mww 0xFFE00010 0x40000000 - mww 0xFFE00014 0x50000000 - mww 0xFFE00018 0x60000000 - mww 0xFFE0001c 0x70000000 - mww 0xFFE00020 0x00000001 - mww 0xFFE00024 0x00000000 - - # remap - mww 0xFFFFF124 0xFFFFFFFF - mww 0xffff0010 0x100 - mww 0xffff0034 0x100 - - #disable 16x5x UART interrupts - mww 0x08020004 0 -} - -$_TARGETNAME configure -event gdb-attach { - # Without this gdb-attach will first time as probe will fail - reset init -} - -# required for usable performance. Used for lots of -# other things than flash programming. -$_TARGETNAME configure -work-area-phys 0x00020000 -work-area-size 0x20000 -work-area-backup 0 - -adapter speed 16000 - - -proc production_info {} { - return "Serial number is official MAC number. Format XXXXXXXXXXXX" -} - -# There is no return value from this procedure. If it is -# successful it does not throw an exception -# -# Progress messages are output via puts -proc production {firmwarefile serialnumber} { - if {[string length $serialnumber]!=12} { - echo "Invalid serial number" - return - } - - echo "Power cycling target" - power off - sleep 3000 - power on - sleep 1000 - reset init - flash write_image erase $firmwarefile 0x1000000 bin - verify_image $firmwarefile 0x1000000 bin - - # Big endian... weee!!!! - echo "Setting MAC number to $serialnumber" - flash fillw [expr 0x1030000-0x8] "0x[string range $serialnumber 2 3][string range $serialnumber 0 1]0000" 1 - flash fillw [expr 0x1030000-0x4] "0x[string range $serialnumber 10 11][string range $serialnumber 8 9][string range $serialnumber 6 7][string range $serialnumber 4 5]" 1 - echo "Production successful" -} - - -proc production_test {} { - power on - sleep 1000 - target_request debugmsgs enable - reset run - sleep 25000 - target_request debugmsgs disable - return "See IP address above..." -} diff --git a/tcl/interface/ftdi/miniwiggler.cfg b/tcl/interface/ftdi/miniwiggler.cfg new file mode 100644 index 000000000..6e53daede --- /dev/null +++ b/tcl/interface/ftdi/miniwiggler.cfg @@ -0,0 +1,34 @@ +# SPDX-License-Identifier: GPL-2.0-or-later +# +# Infineon DAP miniWiggler V3 +# +# https://www.infineon.com/cms/en/product/evaluation-boards/kit_miniwiggler_3_usb/ +# +# Layout: FTDI FT2232 +# ADBUS0 TCK +# ADBUS1 TDI +# ADBUS2 TDO +# ADBUS3 TMS +# ADBUS4 nOE (output enable) +# ADBUS5 +# ADBUS6 +# ADBUS7 Blue LED +# +# ACBUS0 nTRST +# ACBUS1 nSRST +# ACUBS2 +# ACBUS3 +# ACBUS4 +# ACBUS5 +# ACBUS6 +# ACBUS7 +# + +adapter driver ftdi +ftdi_device_desc "DAS JDS miniWiggler V3.1" +ftdi_vid_pid 0x058b 0x0043 + +ftdi_channel 0 +ftdi_layout_init 0x0008 0x001b +ftdi_layout_signal nTRST -data 0x0100 -oe 0x0100 +ftdi_layout_signal nSRST -data 0x0200 -oe 0x0200 diff --git a/tcl/interface/ftdi/pls_spc5.cfg b/tcl/interface/ftdi/pls_spc5.cfg new file mode 100644 index 000000000..806f920fe --- /dev/null +++ b/tcl/interface/ftdi/pls_spc5.cfg @@ -0,0 +1,36 @@ +# SPDX-License-Identifier: GPL-2.0-or-later +# +# PLS SPC5-UDESTK +# +# https://www.st.com/en/development-tools/spc5-udestk.html +# +# Reference the SPC56D Discovery schematics. +# +# Layout: FTDI FT2232 +# ADBUS0 TCK +# ADBUS1 TDI +# ADBUS2 TDO +# ADBUS3 TMS +# ADBUS4 TMS +# ADBUS5 RTCK +# ADBUS6 +# ADBUS7 LED1 +# +# ACBUS0 nTRST +# ACBUS1 nSRST (external pull-down) +# ACUBS2 +# ACBUS3 +# ACBUS4 +# ACBUS5 nSRST direction (input=L, output=H, external pull-down) +# ACBUS6 TMS direction (input=L, output=H, external pull-up) +# ACBUS7 LED2 +# + +adapter driver ftdi +ftdi_device_desc "PLS USB/JTAG Adapter for SPC5xxx" +ftdi_vid_pid 0x263d 0x4001 + +ftdi_channel 0 +ftdi_layout_init 0x0008 0x000b +ftdi_layout_signal nTRST -data 0x0100 -oe 0x0100 +ftdi_layout_signal nSRST -ndata 0x2000 -oe 0x2000 diff --git a/tcl/target/ampere_emag.cfg b/tcl/target/ampere_emag.cfg new file mode 100644 index 000000000..7115a839d --- /dev/null +++ b/tcl/target/ampere_emag.cfg @@ -0,0 +1,112 @@ +# +# OpenOCD Target Configuration for eMAG ARMv8 Processor +# +# Copyright (c) 2019-2021, Ampere Computing LLC +# +# 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; +# +# + +# +# Configure defaults for target +# Can be overriden in board configuration file +# + +if { [info exists CHIPNAME] } { + set _CHIPNAME $CHIPNAME +} else { + set _CHIPNAME emag +} + +if { [info exists NUMCORES] } { + set _NUMCORES $NUMCORES +} else { + set _NUMCORES 32 +} + +if { [info exists ENDIAN] } { + set _ENDIAN $ENDIAN +} else { + set _ENDIAN little +} + +if { [info exists CPUTAPID ] } { + set _CPUTAPID $CPUTAPID +} else { + set _CPUTAPID 0x4BA00477 +} + +# +# Configure JTAG TAP +# + +jtag newtap $_CHIPNAME cpu -irlen 4 -ircapture 0x1 -irmask 0x3 -expected-id $_CPUTAPID +set _TAPNAME $_CHIPNAME.cpu + +set _DAPNAME ${_TAPNAME}_dap +set _APNUM 1 +dap create $_DAPNAME -chain-position $_TAPNAME +$_DAPNAME apsel $_APNUM + +# Create the DAP AP0 MEM-AP AHB-AP target +target create AHB mem_ap -endian $_ENDIAN -dap $_DAPNAME -ap-num 0 + +# Create the DAP AP1 MEM-AP APB-AP target +target create APB mem_ap -endian $_ENDIAN -dap $_DAPNAME -ap-num 1 + +# +# Configure target CPUs +# + +# Build string used to enable smp mode +set _SMP_STR "target smp" + +for {set _i 0} {$_i < $_NUMCORES} {incr _i} { + # Format a string to reference which CPU target to use + set _TARGETNAME [format "${_TAPNAME}_%02d" $_i] + + # Create and configure Cross Trigger Interface (CTI) - required for halt and resume + set _CTINAME $_TARGETNAME.cti + cti create $_CTINAME -dap $_DAPNAME -ap-num $_APNUM -baseaddr [expr 0xFC020000 + ($_i << 20)] + + # Create the target + target create $_TARGETNAME aarch64 -endian $_ENDIAN -dap $_DAPNAME -ap-num $_APNUM -cti $_CTINAME -coreid $_i + set _SMP_STR "$_SMP_STR $_TARGETNAME" + + # Clear CTI output/input enables that are not configured by OpenOCD for aarch64 + $_TARGETNAME configure -event examine-start [subst { + $_CTINAME write INEN0 0x00000000 + $_CTINAME write INEN1 0x00000000 + $_CTINAME write INEN2 0x00000000 + $_CTINAME write INEN3 0x00000000 + $_CTINAME write INEN4 0x00000000 + $_CTINAME write INEN5 0x00000000 + $_CTINAME write INEN6 0x00000000 + $_CTINAME write INEN7 0x00000000 + $_CTINAME write INEN8 0x00000000 + + $_CTINAME write OUTEN2 0x00000000 + $_CTINAME write OUTEN3 0x00000000 + $_CTINAME write OUTEN4 0x00000000 + $_CTINAME write OUTEN5 0x00000000 + $_CTINAME write OUTEN6 0x00000000 + $_CTINAME write OUTEN7 0x00000000 + $_CTINAME write OUTEN8 0x00000000 + }] + + # Enable OpenOCD HWTHREAD RTOS feature for GDB thread (CPU) selection support + # This feature presents CPU cores ("hardware threads") in an SMP system as threads to GDB + $_TARGETNAME configure -rtos hwthread +} +eval $_SMP_STR diff --git a/tcl/target/bcm2711.cfg b/tcl/target/bcm2711.cfg new file mode 100644 index 000000000..f8d2b3a65 --- /dev/null +++ b/tcl/target/bcm2711.cfg @@ -0,0 +1,62 @@ +# SPDX-License-Identifier: GPL-2.0-or-later + +# The Broadcom BCM2711 used in Raspberry Pi 4 +# No documentation was found on Broadcom website + +# Partial information is available in raspberry pi website: +# https://www.raspberrypi.org/documentation/hardware/raspberrypi/bcm2711/ + +if { [info exists CHIPNAME] } { + set _CHIPNAME $CHIPNAME +} else { + set _CHIPNAME bcm2711 +} + +if { [info exists CHIPCORES] } { + set _cores $CHIPCORES +} else { + set _cores 4 +} + +if { [info exists USE_SMP] } { + set _USE_SMP $USE_SMP +} else { + set _USE_SMP 0 +} + +if { [info exists DAP_TAPID] } { + set _DAP_TAPID $DAP_TAPID +} else { + set _DAP_TAPID 0x4ba00477 +} + +jtag newtap $_CHIPNAME cpu -expected-id $_DAP_TAPID -irlen 4 +adapter speed 4000 + +dap create $_CHIPNAME.dap -chain-position $_CHIPNAME.cpu + +# MEM-AP for direct access +target create $_CHIPNAME.ap mem_ap -dap $_CHIPNAME.dap -ap-num 0 + +# these addresses are obtained from the ROM table via 'dap info 0' command +set _DBGBASE {0x80410000 0x80510000 0x80610000 0x80710000} +set _CTIBASE {0x80420000 0x80520000 0x80620000 0x80720000} + +set _smp_command "target smp" + +for { set _core 0 } { $_core < $_cores } { incr _core } { + set _CTINAME $_CHIPNAME.cti$_core + set _TARGETNAME $_CHIPNAME.cpu$_core + + cti create $_CTINAME -dap $_CHIPNAME.dap -ap-num 0 -baseaddr [lindex $_CTIBASE $_core] + target create $_TARGETNAME aarch64 -dap $_CHIPNAME.dap -ap-num 0 -dbgbase [lindex $_DBGBASE $_core] -cti $_CTINAME + + set _smp_command "$_smp_command $_TARGETNAME" +} + +if {$_USE_SMP} { + eval $_smp_command +} + +# default target is cpu0 +targets $_CHIPNAME.cpu0 diff --git a/tcl/target/bcm2835.cfg b/tcl/target/bcm2835.cfg new file mode 100644 index 000000000..32a03666c --- /dev/null +++ b/tcl/target/bcm2835.cfg @@ -0,0 +1,24 @@ +# SPDX-License-Identifier: GPL-2.0-or-later + +# This is the Broadcom chip used in the Raspberry Pi Model A, B, B+, +# the Compute Module, and the Raspberry Pi Zero. + +# Partial information is available in raspberry pi website: +# https://www.raspberrypi.org/documentation/hardware/raspberrypi/bcm2835 + +if { [info exists CHIPNAME] } { + set _CHIPNAME $CHIPNAME +} else { + set _CHIPNAME bcm2835 +} + +if { [info exists DAP_TAPID] } { + set _DAP_TAPID $DAP_TAPID +} else { + set _DAP_TAPID 0x07b7617F +} + +jtag newtap $_CHIPNAME cpu -expected-id $_DAP_TAPID -irlen 5 +adapter speed 4000 + +target create $_CHIPNAME.cpu0 arm11 -chain-position $_CHIPNAME.cpu diff --git a/tcl/target/bcm2836.cfg b/tcl/target/bcm2836.cfg new file mode 100644 index 000000000..04921315e --- /dev/null +++ b/tcl/target/bcm2836.cfg @@ -0,0 +1,59 @@ +# SPDX-License-Identifier: GPL-2.0-or-later + +# The Broadcom chip used in the Raspberry Pi 2 Model B + +# Partial information is available in raspberry pi website: +# https://www.raspberrypi.org/documentation/hardware/raspberrypi/bcm2836 + +if { [info exists CHIPNAME] } { + set _CHIPNAME $CHIPNAME +} else { + set _CHIPNAME bcm2836 +} + +if { [info exists CHIPCORES] } { + set _cores $CHIPCORES +} else { + set _cores 4 +} + +if { [info exists USE_SMP] } { + set _USE_SMP $USE_SMP +} else { + set _USE_SMP 0 +} + +if { [info exists DAP_TAPID] } { + set _DAP_TAPID $DAP_TAPID +} else { + set _DAP_TAPID 0x4ba00477 +} + +jtag newtap $_CHIPNAME cpu -expected-id $_DAP_TAPID -irlen 4 +adapter speed 4000 + +dap create $_CHIPNAME.dap -chain-position $_CHIPNAME.cpu + +# MEM-AP for direct access +target create $_CHIPNAME.ap mem_ap -dap $_CHIPNAME.dap -ap-num 0 + +# these addresses are obtained from the ROM table via 'dap info 0' command +set _DBGBASE {0x80010000 0x80012000 0x80014000 0x80016000} + +set _smp_command "target smp" + +for { set _core 0 } { $_core < $_cores } { incr _core } { + set _TARGETNAME $_CHIPNAME.cpu$_core + + target create $_TARGETNAME cortex_a -dap $_CHIPNAME.dap -coreid $_core -dbgbase [lindex $_DBGBASE $_core] + $_TARGETNAME configure -event reset-assert-post { cortex_a dbginit } + + set _smp_command "$_smp_command $_CHIPNAME.cpu$_core" +} + +if {$_USE_SMP} { + eval $_smp_command +} + +# default target is cpu0 +targets $_CHIPNAME.cpu0 diff --git a/tcl/target/bcm2837.cfg b/tcl/target/bcm2837.cfg new file mode 100644 index 000000000..749de3103 --- /dev/null +++ b/tcl/target/bcm2837.cfg @@ -0,0 +1,64 @@ +# SPDX-License-Identifier: GPL-2.0-or-later + +# This is the Broadcom chip used in the Raspberry Pi 3, +# and in later models of the Raspberry Pi 2. + +# Partial information is available in raspberry pi website: +# https://www.raspberrypi.org/documentation/hardware/raspberrypi/bcm2837 +# https://www.raspberrypi.org/documentation/hardware/raspberrypi/bcm2837b0 + +if { [info exists CHIPNAME] } { + set _CHIPNAME $CHIPNAME +} else { + set _CHIPNAME bcm2837 +} + +if { [info exists CHIPCORES] } { + set _cores $CHIPCORES +} else { + set _cores 4 +} + +if { [info exists USE_SMP] } { + set _USE_SMP $USE_SMP +} else { + set _USE_SMP 0 +} + +if { [info exists DAP_TAPID] } { + set _DAP_TAPID $DAP_TAPID +} else { + set _DAP_TAPID 0x4ba00477 +} + +jtag newtap $_CHIPNAME cpu -expected-id $_DAP_TAPID -irlen 4 +adapter speed 4000 + +dap create $_CHIPNAME.dap -chain-position $_CHIPNAME.cpu + +# MEM-AP for direct access +target create $_CHIPNAME.ap mem_ap -dap $_CHIPNAME.dap -ap-num 0 + +# these addresses are obtained from the ROM table via 'dap info 0' command +set _DBGBASE {0x80010000 0x80012000 0x80014000 0x80016000} +set _CTIBASE {0x80018000 0x80019000 0x8001a000 0x8001b000} + +set _smp_command "target smp" + +for { set _core 0 } { $_core < $_cores } { incr _core } { + set _CTINAME $_CHIPNAME.cti$_core + set _TARGETNAME $_CHIPNAME.cpu$_core + + cti create $_CTINAME -dap $_CHIPNAME.dap -ap-num 0 -baseaddr [lindex $_CTIBASE $_core] + target create $_TARGETNAME aarch64 -dap $_CHIPNAME.dap -ap-num 0 -dbgbase [lindex $_DBGBASE $_core] -cti $_CTINAME + $_TARGETNAME configure -event reset-assert-post { aarch64 dbginit } + + set _smp_command "$_smp_command $_TARGETNAME" +} + +if {$_USE_SMP} { + eval $_smp_command +} + +# default target is cpu0 +targets $_CHIPNAME.cpu0 diff --git a/tcl/target/eos_s3.cfg b/tcl/target/eos_s3.cfg index f6016fb30..150ef4e31 100644 --- a/tcl/target/eos_s3.cfg +++ b/tcl/target/eos_s3.cfg @@ -26,7 +26,7 @@ if { [info exists CPUTAPID] } { } } -swj_newdap $_CHIPNAME cpu -irlen 4 -irmask 0xf -expected-id _CPUTAPID +swj_newdap $_CHIPNAME cpu -irlen 4 -irmask 0xf -expected-id $_CPUTAPID dap create $_CHIPNAME.dap -chain-position $_CHIPNAME.cpu set _TARGETNAME $_CHIPNAME.cpu diff --git a/tcl/target/rk3399.cfg b/tcl/target/rk3399.cfg new file mode 100644 index 000000000..1e90414fd --- /dev/null +++ b/tcl/target/rk3399.cfg @@ -0,0 +1,79 @@ +# SPDX-License-Identifier: GPL-2.0-or-later +# Rockchip RK3399 Target +# https://rockchip.fr/RK3399%20datasheet%20V1.8.pdf +# https://rockchip.fr/Rockchip%20RK3399%20TRM%20V1.4%20Part1.pdf + +if { [info exists CHIPNAME] } { + set _CHIPNAME $CHIPNAME +} else { + set _CHIPNAME rk3399 +} + +# +# Main DAP +# +if { [info exists DAP_TAPID] } { + set _DAP_TAPID $DAP_TAPID +} else { + set _DAP_TAPID 0x5ba02477 +} + +adapter speed 12000 + +transport select swd + +# declare the one SWD tap to access the DAP +swd newdap $_CHIPNAME cpu -expected-id $_DAP_TAPID -ignore-version + +# create the DAP +dap create $_CHIPNAME.dap -chain-position $_CHIPNAME.cpu +target create $_CHIPNAME.ahb mem_ap -dap $_CHIPNAME.dap -ap-num 0 +set _TARGETNAME $_CHIPNAME.lcore +# declare the 6 main application cores +set _smp_command "" + +set $_TARGETNAME.base(0) 0x80030000 +set $_TARGETNAME.base(1) 0x80032000 +set $_TARGETNAME.base(2) 0x80034000 +set $_TARGETNAME.base(3) 0x80036000 +set $_TARGETNAME.cti(0) 0x80038000 +set $_TARGETNAME.cti(1) 0x80039000 +set $_TARGETNAME.cti(2) 0x8003a000 +set $_TARGETNAME.cti(3) 0x8003b000 + + +set _TARGETNAME $_CHIPNAME.bcore +set $_TARGETNAME.base(4) 0x80210000 +set $_TARGETNAME.base(5) 0x80310000 +set $_TARGETNAME.cti(4) 0x80220000 +set $_TARGETNAME.cti(5) 0x80320000 + +set _cores 6 +for { set _core 0 } { $_core < $_cores } { incr _core 1 } { + if {$_core < 4} { + set _TARGETNAME $_CHIPNAME.lcore + } else { + set _TARGETNAME $_CHIPNAME.bcore + } + + + cti create cti$_core -dap $_CHIPNAME.dap -baseaddr [set $_TARGETNAME.cti($_core)] -ap-num 1 + + target create ${_TARGETNAME}$_core aarch64 \ + -dap $_CHIPNAME.dap -coreid $_core -cti cti$_core \ + -dbgbase [set $_TARGETNAME.base($_core)] + + if { $_core != 0 } { + ${_TARGETNAME}$_core configure -defer-examine + } else { + # uncomment to use hardware threads pseudo rtos + # ${_TARGETNAME}$_core configure -rtos hwthread" + ${_TARGETNAME}$_core configure -work-area-size 0x30000 -work-area-phys 0xff8c0000 \ + -work-area-backup 0 + } + set _smp_command "$_smp_command ${_TARGETNAME}$_core" +} + +target smp $_smp_command + +targets rk3399.lcore0 diff --git a/tcl/target/stm32f4x.cfg b/tcl/target/stm32f4x.cfg index 15875336e..e94837f83 100644 --- a/tcl/target/stm32f4x.cfg +++ b/tcl/target/stm32f4x.cfg @@ -38,6 +38,8 @@ if { [info exists CPUTAPID] } { swj_newdap $_CHIPNAME cpu -irlen 4 -ircapture 0x1 -irmask 0xf -expected-id $_CPUTAPID dap create $_CHIPNAME.dap -chain-position $_CHIPNAME.cpu +tpiu create $_CHIPNAME.tpiu -dap stm32f4x.dap -ap-num 0 -baseaddr 0xE0040000 + if {[using_jtag]} { jtag newtap $_CHIPNAME bs -irlen 5 } @@ -89,13 +91,37 @@ $_TARGETNAME configure -event examine-end { mmw 0xE0042008 0x00001800 0 } -$_TARGETNAME configure -event trace-config { - # Set TRACE_IOEN; TRACE_MODE is set to async; when using sync - # change this value accordingly to configure trace pins - # assignment - mmw 0xE0042004 0x00000020 0 +proc proc_post_enable {_chipname} { + targets $_chipname.cpu + + if { [$_chipname.tpiu cget -protocol] eq "sync" } { + switch [$_chipname.tpiu cget -port-width] { + 1 { + mmw 0xE0042004 0x00000060 0x000000c0 + mmw 0x40021020 0x00000000 0x0000ff00 + mmw 0x40021000 0x000000a0 0x000000f0 + mmw 0x40021008 0x000000f0 0x00000000 + } + 2 { + mmw 0xE0042004 0x000000a0 0x000000c0 + mmw 0x40021020 0x00000000 0x000fff00 + mmw 0x40021000 0x000002a0 0x000003f0 + mmw 0x40021008 0x000003f0 0x00000000 + } + 4 { + mmw 0xE0042004 0x000000e0 0x000000c0 + mmw 0x40021020 0x00000000 0x0fffff00 + mmw 0x40021000 0x00002aa0 0x00003ff0 + mmw 0x40021008 0x00003ff0 0x00000000 + } + } + } else { + mmw 0xE0042004 0x00000020 0x000000c0 + } } +$_CHIPNAME.tpiu configure -event post-enable "proc_post_enable $_CHIPNAME" + $_TARGETNAME configure -event reset-init { # Configure PLL to boost clock to HSI x 4 (64 MHz) mww 0x40023804 0x08012008 ;# RCC_PLLCFGR 16 Mhz /8 (M) * 128 (N) /4(P) diff --git a/tcl/target/stm32g0x.cfg b/tcl/target/stm32g0x.cfg index 50836ea82..7df530655 100644 --- a/tcl/target/stm32g0x.cfg +++ b/tcl/target/stm32g0x.cfg @@ -38,8 +38,8 @@ target create $_TARGETNAME cortex_m -endian $_ENDIAN -dap $_CHIPNAME.dap $_TARGETNAME configure -work-area-phys 0x20000000 -work-area-size $_WORKAREASIZE -work-area-backup 0 -set _FLASHNAME $_CHIPNAME.flash -flash bank $_FLASHNAME stm32l4x 0 0 0 0 $_TARGETNAME +flash bank $_CHIPNAME.flash stm32l4x 0x08000000 0 0 0 $_TARGETNAME +flash bank $_CHIPNAME.otp stm32l4x 0x1fff7000 0 0 0 $_TARGETNAME # reasonable default adapter speed 2000 diff --git a/tcl/target/stm32g4x.cfg b/tcl/target/stm32g4x.cfg index 9f144a07e..360447bd5 100644 --- a/tcl/target/stm32g4x.cfg +++ b/tcl/target/stm32g4x.cfg @@ -47,8 +47,8 @@ target create $_TARGETNAME cortex_m -endian $_ENDIAN -dap $_CHIPNAME.dap $_TARGETNAME configure -work-area-phys 0x20000000 -work-area-size $_WORKAREASIZE -work-area-backup 0 -set _FLASHNAME $_CHIPNAME.flash -flash bank $_FLASHNAME stm32l4x 0 0 0 0 $_TARGETNAME +flash bank $_CHIPNAME.flash stm32l4x 0x08000000 0 0 0 $_TARGETNAME +flash bank $_CHIPNAME.otp stm32l4x 0x1fff7000 0 0 0 $_TARGETNAME if { [info exists QUADSPI] && $QUADSPI } { set a [llength [flash list]] diff --git a/tcl/target/stm32h7x.cfg b/tcl/target/stm32h7x.cfg index 8258e5031..26d0d9301 100644 --- a/tcl/target/stm32h7x.cfg +++ b/tcl/target/stm32h7x.cfg @@ -77,6 +77,8 @@ if {![using_hla]} { # STM32H7 provides an APB-AP at access port 2, which allows the access to # the debug and trace features on the system APB System Debug Bus (APB-D). target create $_CHIPNAME.ap2 mem_ap -dap $_CHIPNAME.dap -ap-num 2 + swo create $_CHIPNAME.swo -dap $_CHIPNAME.dap -ap-num 2 -baseaddr 0xE00E3000 + tpiu create $_CHIPNAME.tpiu -dap $_CHIPNAME.dap -ap-num 2 -baseaddr 0xE00F5000 } target create $_CHIPNAME.cpu0 cortex_m -endian $_ENDIAN -dap $_CHIPNAME.dap -ap-num 0 @@ -178,13 +180,20 @@ $_CHIPNAME.cpu0 configure -event examine-end { stm32h7x_dbgmcu_mmw 0x03C 0x00000800 0 # DBGMCU_APB4FZ1 |= WDGLSD1 | WDGLSD2 stm32h7x_dbgmcu_mmw 0x054 0x000C0000 0 -} -$_CHIPNAME.cpu0 configure -event trace-config { - # Set TRACECLKEN; TRACE_MODE is set to async; when using sync - # change this value accordingly to configure trace pins - # assignment + # Enable clock for tracing + # DBGMCU_CR |= TRACECLKEN stm32h7x_dbgmcu_mmw 0x004 0x00100000 0 + + # RM0399 (id 0x450) M7+M4 with SWO Funnel + # RM0433 (id 0x450) M7 with SWO Funnel + # RM0455 (id 0x480) M7 without SWO Funnel + # RM0468 (id 0x483) M7 without SWO Funnel + # Enable CM7 and CM4 slave ports in SWO trace Funnel + # Works ok also on devices single core and without SWO funnel + # Hack, use stm32h7x_dbgmcu_mmw with big offset to control SWTF + # SWTF_CTRL |= ENS0 | ENS1 + stm32h7x_dbgmcu_mmw 0x3000 0x00000003 0 } $_CHIPNAME.cpu0 configure -event reset-init { diff --git a/tcl/target/stm32l4x.cfg b/tcl/target/stm32l4x.cfg index 7f08f3c4b..589979193 100644 --- a/tcl/target/stm32l4x.cfg +++ b/tcl/target/stm32l4x.cfg @@ -47,8 +47,8 @@ target create $_TARGETNAME cortex_m -endian $_ENDIAN -dap $_CHIPNAME.dap $_TARGETNAME configure -work-area-phys 0x20000000 -work-area-size $_WORKAREASIZE -work-area-backup 0 -set _FLASHNAME $_CHIPNAME.flash -flash bank $_FLASHNAME stm32l4x 0 0 0 0 $_TARGETNAME +flash bank $_CHIPNAME.flash stm32l4x 0x08000000 0 0 0 $_TARGETNAME +flash bank $_CHIPNAME.otp stm32l4x 0x1fff7000 0 0 0 $_TARGETNAME if { [info exists QUADSPI] && $QUADSPI } { set a [llength [flash list]] diff --git a/tcl/target/stm32l5x.cfg b/tcl/target/stm32l5x.cfg index bf5636094..92083b9e0 100644 --- a/tcl/target/stm32l5x.cfg +++ b/tcl/target/stm32l5x.cfg @@ -53,7 +53,8 @@ target create $_TARGETNAME cortex_m -endian $_ENDIAN -dap $_CHIPNAME.dap $_TARGETNAME configure -work-area-phys 0x20000000 -work-area-size $_WORKAREASIZE -work-area-backup 0 # declare non-secure flash -flash bank $_CHIPNAME.flash_ns stm32l4x 0 0 0 0 $_TARGETNAME +flash bank $_CHIPNAME.flash_ns stm32l4x 0x08000000 0 0 0 $_TARGETNAME +flash bank $_CHIPNAME.otp stm32l4x 0x0BFA0000 0 0 0 $_TARGETNAME # Common knowledges tells JTAG speed should be <= F_CPU/6. # F_CPU after reset is MSI 4MHz, so use F_JTAG = 500 kHz to stay on diff --git a/tcl/target/stm32mp15x.cfg b/tcl/target/stm32mp15x.cfg index 4a8bc866c..1b2ae7d5e 100644 --- a/tcl/target/stm32mp15x.cfg +++ b/tcl/target/stm32mp15x.cfg @@ -64,6 +64,9 @@ cti create $_CHIPNAME.cti.cpu0 -dap $_CHIPNAME.dap -ap-num 1 -baseaddr 0xE00D800 cti create $_CHIPNAME.cti.cpu1 -dap $_CHIPNAME.dap -ap-num 1 -baseaddr 0xE00D9000 cti create $_CHIPNAME.cti.cm4 -dap $_CHIPNAME.dap -ap-num 2 -baseaddr 0xE0043000 +swo create $_CHIPNAME.swo -dap $_CHIPNAME.dap -ap-num 1 -baseaddr 0xE0083000 +tpiu create $_CHIPNAME.tpiu -dap $_CHIPNAME.dap -ap-num 1 -baseaddr 0xE0093000 + # interface does not work while srst is asserted # this is target specific, valid for every board # Errata "2.3.5 Incorrect reset of glitch-free kernel clock switch" requires @@ -108,9 +111,13 @@ proc detect_cpu1 {} { if {! $dual_core} {$::_CHIPNAME.cpu1 configure -defer-examine} } +proc rcc_enable_traceclk {} { + $::_CHIPNAME.ap2 mww 0x5000080c 0x301 +} + # FIXME: most of handler below will be removed once reset framework get merged $_CHIPNAME.ap1 configure -event reset-deassert-pre {adapter deassert srst deassert trst;dap init;catch {$::_CHIPNAME.dap apid 1}} -$_CHIPNAME.ap2 configure -event reset-deassert-pre {dbgmcu_enable_debug} +$_CHIPNAME.ap2 configure -event reset-deassert-pre {dbgmcu_enable_debug;rcc_enable_traceclk} $_CHIPNAME.cpu0 configure -event reset-deassert-pre {$::_CHIPNAME.cpu0 arp_examine} $_CHIPNAME.cpu1 configure -event reset-deassert-pre {$::_CHIPNAME.cpu1 arp_examine allow-defer} $_CHIPNAME.cpu0 configure -event reset-deassert-post {toggle_cpu0_dbg_claim0} @@ -118,4 +125,4 @@ $_CHIPNAME.cm4 configure -event reset-deassert-post {$::_CHIPNAME.cm4 arp_exami $_CHIPNAME.ap1 configure -event examine-start {dap init} $_CHIPNAME.ap2 configure -event examine-start {dbgmcu_enable_debug} $_CHIPNAME.cpu0 configure -event examine-end {detect_cpu1} -$_CHIPNAME.ap2 configure -event examine-end {$::_CHIPNAME.cm4 arp_examine} +$_CHIPNAME.ap2 configure -event examine-end {rcc_enable_traceclk;$::_CHIPNAME.cm4 arp_examine} diff --git a/tcl/target/stm32wbx.cfg b/tcl/target/stm32wbx.cfg index 90f53bb96..6467667de 100644 --- a/tcl/target/stm32wbx.cfg +++ b/tcl/target/stm32wbx.cfg @@ -46,8 +46,8 @@ target create $_TARGETNAME cortex_m -endian $_ENDIAN -dap $_CHIPNAME.dap $_TARGETNAME configure -work-area-phys 0x20000000 -work-area-size $_WORKAREASIZE -work-area-backup 0 -set _FLASHNAME $_CHIPNAME.flash -flash bank $_FLASHNAME stm32l4x 0 0 0 0 $_TARGETNAME +flash bank $_CHIPNAME.flash stm32l4x 0x08000000 0 0 0 $_TARGETNAME +flash bank $_CHIPNAME.otp stm32l4x 0x1fff7000 0 0 0 $_TARGETNAME # Common knowledges tells JTAG speed should be <= F_CPU/6. # F_CPU after reset is MSI 4MHz, so use F_JTAG = 500 kHz to stay on diff --git a/tcl/target/stm32wlx.cfg b/tcl/target/stm32wlx.cfg index ba16fab6b..961850ad1 100644 --- a/tcl/target/stm32wlx.cfg +++ b/tcl/target/stm32wlx.cfg @@ -46,8 +46,8 @@ target create $_TARGETNAME cortex_m -endian $_ENDIAN -dap $_CHIPNAME.dap $_TARGETNAME configure -work-area-phys 0x20000000 -work-area-size $_WORKAREASIZE -work-area-backup 0 -set _FLASHNAME $_CHIPNAME.flash -flash bank $_FLASHNAME stm32l4x 0 0 0 0 $_TARGETNAME +flash bank $_CHIPNAME.flash stm32l4x 0x08000000 0 0 0 $_TARGETNAME +flash bank $_CHIPNAME.otp stm32l4x 0x1fff7000 0 0 0 $_TARGETNAME # Common knowledges tells JTAG speed should be <= F_CPU/6. # F_CPU after reset is MSI 4MHz, so use F_JTAG = 500 kHz to stay on diff --git a/tcl/target/ti_k3.cfg b/tcl/target/ti_k3.cfg new file mode 100644 index 000000000..d2aa53160 --- /dev/null +++ b/tcl/target/ti_k3.cfg @@ -0,0 +1,256 @@ +# SPDX-License-Identifier: GPL-2.0-or-later +# Copyright (C) 2019-2021 Texas Instruments Incorporated - http://www.ti.com/ +# +# Texas Instruments K3 devices: +# * AM654x: https://www.ti.com/lit/pdf/spruid7 +# Has 4 ARMV8 Cores and 2 R5 Cores and an M3 +# * J721E: https://www.ti.com/lit/pdf/spruil1 +# Has 2 ARMV8 Cores and 6 R5 Cores and an M3 +# * J7200: https://www.ti.com/lit/pdf/spruiu1 +# Has 2 ARMV8 Cores and 4 R5 Cores and an M3 +# * AM642: https://www.ti.com/lit/pdf/spruim2 +# Has 2 ARMV8 Cores and 4 R5 Cores, M4F and an M3 +# + +if { [info exists SOC] } { + set _soc $SOC +} else { + set _soc am654 +} + +# set V8_SMP_DEBUG to non 0 value in board if you'd like to use SMP debug +if { [info exists V8_SMP_DEBUG] } { + set _v8_smp_debug $V8_SMP_DEBUG +} else { + set _v8_smp_debug 0 +} + +# Common Definitions + +# CM3 the very first processor - all current SoCs have it. +set CM3_CTIBASE {0x3C016000} + +# M3 power-ap unlock offsets +set _m3_ap_unlock_offsets {0xf0 0x44} + +# All the ARMV8s are the next processors. +# CL0,CORE0 CL0,CORE1 CL1,CORE0 CL1,CORE1 +set ARMV8_DBGBASE {0x90410000 0x90510000 0x90810000 0x90910000} +set ARMV8_CTIBASE {0x90420000 0x90520000 0x90820000 0x90920000} + +# And we add up the R5s +# (0)MCU 0 (1)MCU 1 (2)MAIN_0_0 (3)MAIN_0_1 (4)MAIN_1_0 (5)MAIN_1_1 +set R5_DBGBASE {0x9d010000 0x9d012000 0x9d410000 0x9d412000 0x9d510000 0x9d512000} +set R5_CTIBASE {0x9d018000 0x9d019000 0x9d418000 0x9d419000 0x9d518000 0x9d519000} + +# Finally an M4F +set CM4_CTIBASE {0x20001000} + +# M4 may be present on some very few SoCs +set _mcu_m4_cores 0 +# M4 power-ap unlock offsets +set _m4_ap_unlock_offsets {0xf0 0x60} + +# Set configuration overrides for each SOC +switch $_soc { + am654 { + set _CHIPNAME am654 + set _K3_DAP_TAPID 0x0bb5a02f + + # AM654 has 2 clusters of 2 A53 cores each. + set _armv8_cpu_name a53 + set _armv8_cores 4 + + # AM654 has 1 cluster of 2 R5s cores. + set _r5_cores 2 + set _mcu_r5_cores 2 + set _mcu_base_core_id 0 + set _main0_r5_cores 0 + set _main0_base_core_id 0 + set _main1_r5_cores 0 + set _main1_base_core_id 0 + + # M3 power-ap unlock offsets + set _m3_ap_unlock_offsets {0xf0 0x50} + } + am642 { + set _CHIPNAME am642 + set _K3_DAP_TAPID 0x0bb3802f + + # AM642 has 1 clusters of 2 A53 cores each. + set _armv8_cpu_name a53 + set _armv8_cores 2 + set ARMV8_DBGBASE {0x90010000 0x90110000} + set ARMV8_CTIBASE {0x90020000 0x90120000} + + # AM642 has 2 cluster of 2 R5s cores. + set _r5_cores 4 + set _mcu_r5_cores 0 + set _mcu_base_core_id 0 + set _main0_r5_cores 2 + set _main0_base_core_id 0 + set _main1_r5_cores 2 + set _main1_base_core_id 2 + set R5_DBGBASE {0x9d410000 0x9d412000 0x9d510000 0x9d512000} + set R5_CTIBASE {0x9d418000 0x9d419000 0x9d518000 0x9d519000} + + # M4 processor + set _mcu_m4_cores 1 + } + j721e { + set _CHIPNAME j721e + set _K3_DAP_TAPID 0x0bb6402f + # J721E has 1 cluster of 2 A72 cores. + set _armv8_cpu_name a72 + set _armv8_cores 2 + + # J721E has 3 clusters of 2 R5 cores each. + set _r5_cores 6 + set _mcu_r5_cores 2 + set _mcu_base_core_id 0 + set _main0_r5_cores 2 + set _main0_base_core_id 2 + set _main1_r5_cores 2 + set _main1_base_core_id 4 + } + j7200 { + set _CHIPNAME j7200 + set _K3_DAP_TAPID 0x0bb6d02f + + # J7200 has 1 cluster of 2 A72 cores. + set _armv8_cpu_name a72 + set _armv8_cores 2 + + # J7200 has 2 clusters of 2 R5 cores each. + set _r5_cores 4 + set _mcu_r5_cores 2 + set _mcu_base_core_id 0 + set _main0_r5_cores 2 + set _main0_base_core_id 2 + set _main1_r5_cores 0 + set _main1_base_core_id 0 + set R5_DBGBASE {0x9d010000 0x9d012000 0x9d110000 0x9d112000} + set R5_CTIBASE {0x9d018000 0x9d019000 0x9d118000 0x9d119000} + + # M3 CTI base + set CM3_CTIBASE {0x20001000} + } + default { + echo "'$_soc' is invalid!" + } +} + +jtag newtap $_CHIPNAME cpu -irlen 4 -expected-id $_K3_DAP_TAPID -ignore-version +dap create $_CHIPNAME.dap -chain-position $_CHIPNAME.cpu + +set _TARGETNAME $_CHIPNAME.cpu + +set _CTINAME $_CHIPNAME.cti + +# M3 is always present +cti create $_CTINAME.m3 -dap $_CHIPNAME.dap -ap-num 7 -baseaddr [lindex $CM3_CTIBASE 0] +target create $_TARGETNAME.m3 cortex_m -dap $_CHIPNAME.dap -ap-num 7 -defer-examine +$_TARGETNAME.m3 configure -event reset-assert { } + +proc m3_up { args } { + # To access M3, we need to enable the JTAG access for the same. + # Ensure Power-AP unlocked + $::_CHIPNAME.dap apreg 3 [lindex $::_m3_ap_unlock_offsets 0] 0x00190000 + $::_CHIPNAME.dap apreg 3 [lindex $::_m3_ap_unlock_offsets 1] 0x00102098 + + $::_TARGETNAME.m3 arp_examine +} + +set _v8_smp_targets "" + +for { set _core 0 } { $_core < $_armv8_cores } { incr _core } { + + cti create $_CTINAME.$_armv8_cpu_name.$_core -dap $_CHIPNAME.dap -ap-num 1 \ + -baseaddr [lindex $ARMV8_CTIBASE $_core] + + target create $_TARGETNAME.$_armv8_cpu_name.$_core aarch64 -dap $_CHIPNAME.dap \ + -dbgbase [lindex $ARMV8_DBGBASE $_core] -cti $_CTINAME.$_armv8_cpu_name.$_core -defer-examine + + set _v8_smp_targets "$_v8_smp_targets $_TARGETNAME.$_armv8_cpu_name.$_core" +} + +# Setup ARMV8 proc commands based on CPU to prevent people confusing SoCs +set _armv8_up_cmd "$_armv8_cpu_name"_up +# Available if V8_SMP_DEBUG is set to non-zero value +set _armv8_smp_cmd "$_armv8_cpu_name"_smp + +if { $_v8_smp_debug == 0 } { + proc $_armv8_up_cmd { args } { + foreach { _core } [set args] { + $::_TARGETNAME.$::_armv8_cpu_name.$_core arp_examine + $::_TARGETNAME.$::_armv8_cpu_name.$_core aarch64 dbginit + } + } +} else { + proc $_armv8_smp_cmd { args } { + for { set _core 0 } { $_core < $::_armv8_cores } { incr _core } { + $::_TARGETNAME.$::_armv8_cpu_name.$_core arp_examine + $::_TARGETNAME.$::_armv8_cpu_name.$_core aarch64 dbginit + $::_TARGETNAME.$::_armv8_cpu_name.$_core aarch64 smp on + } + # Set Default target are core 0 + targets $::_TARGETNAME.$::_armv8_cpu_name.0 + } + + # Declare SMP + target smp $:::_v8_smp_targets +} + +for { set _core 0 } { $_core < $_r5_cores } { incr _core } { + cti create $_CTINAME.r5.$_core -dap $_CHIPNAME.dap -ap-num 1 \ + -baseaddr [lindex $R5_CTIBASE $_core] + + # inactive core examination will fail - wait till startup of additional core + target create $_TARGETNAME.r5.$_core cortex_r4 -dap $_CHIPNAME.dap \ + -dbgbase [lindex $R5_DBGBASE $_core] -ap-num 1 -defer-examine +} + +if { $_mcu_r5_cores != 0 } { + proc mcu_r5_up { args } { + foreach { _core } [set args] { + set _core [expr {$_core + $::_mcu_base_core_id}] + $::_TARGETNAME.r5.$_core arp_examine + $::_TARGETNAME.r5.$_core cortex_r4 dbginit + } + } +} + +if { $_main0_r5_cores != 0 } { + proc main0_r5_up { args } { + foreach { _core } [set args] { + set _core [expr {$_core + $::_main0_base_core_id}] + $::_TARGETNAME.r5.$_core arp_examine + $::_TARGETNAME.r5.$_core cortex_r4 dbginit + } + } +} + +if { $_main1_r5_cores != 0 } { + proc main1_r5_up { args } { + foreach { _core } [set args] { + set _core [expr {$_core + $::_main1_base_core_id}] + $::_TARGETNAME.r5.$_core arp_examine + $::_TARGETNAME.r5.$_core cortex_r4 dbginit + } + } +} + +if { $_mcu_m4_cores != 0 } { + cti create $_CTINAME.m4 -dap $_CHIPNAME.dap -ap-num 8 -baseaddr [lindex $CM4_CTIBASE 0] + target create $_TARGETNAME.m4 cortex_m -dap $_CHIPNAME.dap -ap-num 8 -defer-examine + $_TARGETNAME.m4 configure -event reset-assert { } + + proc m4_up { args } { + # To access M4, we need to enable the JTAG access for the same. + # Ensure Power-AP unlocked + $::_CHIPNAME.dap apreg 3 [lindex $::_m4_ap_unlock_offsets 0] 0x00190000 + $::_CHIPNAME.dap apreg 3 [lindex $::_m4_ap_unlock_offsets 1] 0x00102098 + + $::_TARGETNAME.m4 arp_examine + } +}