diff options
105 files changed, 3621 insertions, 1094 deletions
diff --git a/.cirrus.yml b/.cirrus.yml index c270a09..d2dc34e 100644 --- a/.cirrus.yml +++ b/.cirrus.yml @@ -1,9 +1,9 @@ env: CIRRUS_CLONE_DEPTH: 1 -freebsd_12_task: +freebsd_13_task: freebsd_instance: - image: freebsd-12-1-release-amd64 + image: freebsd-13-0-release-amd64 install_script: pkg install -y bison gmake pkgconf build_script: @@ -8,6 +8,8 @@ *.tab.[ch] lex.yy.c *.lex.c +.*.swp +dtc-parser.h /dtc /fdtdump /convert-dtsv0 @@ -17,3 +19,11 @@ lex.yy.c /fdtoverlay /patches /.pc + +# cscope files +cscope.* +ncscope.* + +.eggs/ +build/ +dist/ @@ -25,19 +25,22 @@ package { license { name: "external_dtc_license", visibility: [":__subpackages__"], - license_kinds: [ - "SPDX-license-identifier-BSD", - "SPDX-license-identifier-BSD-2-Clause", - "SPDX-license-identifier-GPL", - "SPDX-license-identifier-GPL-2.0", - "SPDX-license-identifier-ISC", - "SPDX-license-identifier-LGPL", - "SPDX-license-identifier-LGPL-2.1", - ], - license_text: [ - "NOTICE", - "README.license", - ], + license_kinds: ["SPDX-license-identifier-GPL-2.0"], + license_text: ["GPL"], +} + +license { + name: "external_dtc_libfdt_license", + visibility: [":__subpackages__"], + license_kinds: ["SPDX-license-identifier-BSD-2-Clause"], + license_text: ["BSD-2-Clause"], +} + +license { + name: "external_dtc_tests_license", + visibility: [":__subpackages__"], + license_kinds: ["SPDX-license-identifier-LGPL-2.1+"], + license_text: ["LGPL"], } cc_defaults { @@ -88,3 +91,21 @@ cc_binary_host { "util.c", ], } + +cc_binary_host { + name: "fdtoverlay", + defaults: ["dt_defaults"], + srcs: [ + "fdtoverlay.c", + "util.c", + ], +} + +cc_binary_host { + name: "fdtdump", + defaults: ["dt_defaults"], + srcs: [ + "fdtdump.c", + "util.c", + ], +} diff --git a/CONTRIBUTING.md b/CONTRIBUTING.md new file mode 100644 index 0000000..940dd1a --- /dev/null +++ b/CONTRIBUTING.md @@ -0,0 +1,79 @@ +# Contributing to dtc or libfdt + +There are two ways to submit changes for dtc or libfdt: + +* Post patches directly to the the + [devicetree-compiler](mailto:devicetree-compiler@vger.kernel.org) + mailing list. +* Submit pull requests via + [Github](https://github.com/dgibson/dtc/pulls) + +## Adding a new function to libfdt.h + +The shared library uses `libfdt/version.lds` to list the exported +functions, so add your new function there. Check that your function +works with pylibfdt. If it cannot be supported, put the declaration in +`libfdt.h` behind `#ifndef SWIG` so that swig ignores it. + +## Tests + +Test files are kept in the `tests/` directory. Use `make check` to build and run +all tests. + +If you want to adjust a test file, be aware that `tree_tree1.dts` is compiled +and checked against a binary tree from assembler macros in `trees.S`. So +if you change that file you must change `tree.S` also. + +## Developer's Certificate of Origin + +Like many other projects, dtc and libfdt have adopted the "Developer's +Certificate of Origin" (Signed-off-by) process created by the Linux +kernel community to improve tracking of who did what. Here's how it +works (this is a very slight modification of the description from +`Documentation/process/submitting-patches.rst` in the kernel tree): + +The sign-off is a simple line at the end of the explanation for the +patch, which certifies that you wrote it or otherwise have the right +to pass it on as an open-source patch. The rules are pretty simple: +if you can certify the below: + + Developer's Certificate of Origin 1.1 + + By making a contribution to this project, I certify that: + + (a) The contribution was created in whole or in part by me and I + have the right to submit it under the open source license + indicated in the file; or + + (b) The contribution is based upon previous work that, to the best + of my knowledge, is covered under an appropriate open source + license and I have the right under that license to submit that + work with modifications, whether created in whole or in part + by me, under the same open source license (unless I am + permitted to submit under a different license), as indicated + in the file; or + + (c) The contribution was provided directly to me by some other + person who certified (a), (b) or (c) and I have not modified + it. + + (d) I understand and agree that this project and the contribution + are public and that a record of the contribution (including all + personal information I submit with it, including my sign-off) is + maintained indefinitely and may be redistributed consistent with + this project or the open source license(s) involved. + +then you just add a line saying:: + + Signed-off-by: Random J Developer <random@developer.example.org> + +using your real name (sorry, no pseudonyms or anonymous +contributions.) This will be done for you automatically if you use +`git commit -s`. Reverts should also include "Signed-off-by". `git +revert -s` does that for you. + +Any further SoBs (Signed-off-by:'s) following the author's SoB are +from people handling and transporting the patch, but were not involved +in its development. SoB chains should reflect the **real** route a +patch took as it was propagated to the maintainers, with the first SoB +entry signalling primary authorship of a single author. diff --git a/Documentation/manual.txt b/Documentation/manual.txt index adf5ccb..cf4b253 100644 --- a/Documentation/manual.txt +++ b/Documentation/manual.txt @@ -45,7 +45,7 @@ The gitweb interface for the upstream repository is: Patches should be sent to the maintainers: David Gibson <david@gibson.dropbear.id.au> - Jon Loeliger <jdl@jdl.com> + Jon Loeliger <loeliger@gmail.com> and CCed to <devicetree-compiler@vger.kernel.org>. 2) Description @@ -712,7 +712,7 @@ The syntax of the fdtget command is: where options are: - <type> s=string, i=int, u=unsigned, x=hex + <type> s=string, i=int, u=unsigned, x=hex, r=raw Optional modifier prefix: hh or b=byte, h=2 byte, l=4 byte (default) @@ -0,0 +1,503 @@ +Valid-License-Identifier: LGPL-2.1 +Valid-License-Identifier: LGPL-2.1+ +SPDX-URL: https://spdx.org/licenses/LGPL-2.1.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 Lesser General Public License (LGPL) version 2.1 only' use: + SPDX-License-Identifier: LGPL-2.1 + For 'GNU Lesser General Public License (LGPL) version 2.1 or any later + version' use: + SPDX-License-Identifier: LGPL-2.1+ +License-Text: + +GNU LESSER GENERAL PUBLIC LICENSE +Version 2.1, February 1999 + +Copyright (C) 1991, 1999 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. + +[This is the first released version of the Lesser GPL. It also counts as +the successor of the GNU Library Public License, version 2, hence the +version number 2.1.] + +Preamble + +The licenses for most software are designed to take away your freedom to +share and change it. By contrast, the GNU General Public Licenses are +intended to guarantee your freedom to share and change free software--to +make sure the software is free for all its users. + +This license, the Lesser General Public License, applies to some specially +designated software packages--typically libraries--of the Free Software +Foundation and other authors who decide to use it. You can use it too, but +we suggest you first think carefully about whether this license or the +ordinary General Public License is the better strategy to use in any +particular case, based on the explanations below. + +When we speak of free software, we are referring to freedom of use, 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 and use pieces of it in new free +programs; and that you are informed that you can do these things. + +To protect your rights, we need to make restrictions that forbid +distributors to deny you these rights or to ask you to surrender these +rights. These restrictions translate to certain responsibilities for you if +you distribute copies of the library or if you modify it. + +For example, if you distribute copies of the library, whether gratis or for +a fee, you must give the recipients all the rights that we gave you. You +must make sure that they, too, receive or can get the source code. If you +link other code with the library, you must provide complete object files to +the recipients, so that they can relink them with the library after making +changes to the library and recompiling it. And you must show them these +terms so they know their rights. + +We protect your rights with a two-step method: (1) we copyright the +library, and (2) we offer you this license, which gives you legal +permission to copy, distribute and/or modify the library. + +To protect each distributor, we want to make it very clear that there is no +warranty for the free library. Also, if the library is modified by someone +else and passed on, the recipients should know that what they have is not +the original version, so that the original author's reputation will not be +affected by problems that might be introduced by others. + +Finally, software patents pose a constant threat to the existence of any +free program. We wish to make sure that a company cannot effectively +restrict the users of a free program by obtaining a restrictive license +from a patent holder. Therefore, we insist that any patent license obtained +for a version of the library must be consistent with the full freedom of +use specified in this license. + +Most GNU software, including some libraries, is covered by the ordinary GNU +General Public License. This license, the GNU Lesser General Public +License, applies to certain designated libraries, and is quite different +from the ordinary General Public License. We use this license for certain +libraries in order to permit linking those libraries into non-free +programs. + +When a program is linked with a library, whether statically or using a +shared library, the combination of the two is legally speaking a combined +work, a derivative of the original library. The ordinary General Public +License therefore permits such linking only if the entire combination fits +its criteria of freedom. The Lesser General Public License permits more lax +criteria for linking other code with the library. + +We call this license the "Lesser" General Public License because it does +Less to protect the user's freedom than the ordinary General Public +License. It also provides other free software developers Less of an +advantage over competing non-free programs. These disadvantages are the +reason we use the ordinary General Public License for many +libraries. However, the Lesser license provides advantages in certain +special circumstances. + +For example, on rare occasions, there may be a special need to encourage +the widest possible use of a certain library, so that it becomes a de-facto +standard. To achieve this, non-free programs must be allowed to use the +library. A more frequent case is that a free library does the same job as +widely used non-free libraries. In this case, there is little to gain by +limiting the free library to free software only, so we use the Lesser +General Public License. + +In other cases, permission to use a particular library in non-free programs +enables a greater number of people to use a large body of free +software. For example, permission to use the GNU C Library in non-free +programs enables many more people to use the whole GNU operating system, as +well as its variant, the GNU/Linux operating system. + +Although the Lesser General Public License is Less protective of the users' +freedom, it does ensure that the user of a program that is linked with the +Library has the freedom and the wherewithal to run that program using a +modified version of the Library. + +The precise terms and conditions for copying, distribution and modification +follow. Pay close attention to the difference between a "work based on the +library" and a "work that uses the library". The former contains code +derived from the library, whereas the latter must be combined with the +library in order to run. + +TERMS AND CONDITIONS FOR COPYING, DISTRIBUTION AND MODIFICATION + +0. This License Agreement applies to any software library or other program + which contains a notice placed by the copyright holder or other + authorized party saying it may be distributed under the terms of this + Lesser General Public License (also called "this License"). Each + licensee is addressed as "you". + + A "library" means a collection of software functions and/or data + prepared so as to be conveniently linked with application programs + (which use some of those functions and data) to form executables. + + The "Library", below, refers to any such software library or work which + has been distributed under these terms. A "work based on the Library" + means either the Library or any derivative work under copyright law: + that is to say, a work containing the Library or a portion of it, either + verbatim or with modifications and/or translated straightforwardly into + another language. (Hereinafter, translation is included without + limitation in the term "modification".) + + "Source code" for a work means the preferred form of the work for making + modifications to it. For a library, 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 library. + + Activities other than copying, distribution and modification are not + covered by this License; they are outside its scope. The act of running + a program using the Library is not restricted, and output from such a + program is covered only if its contents constitute a work based on the + Library (independent of the use of the Library in a tool for writing + it). Whether that is true depends on what the Library does and what the + program that uses the Library does. + +1. You may copy and distribute verbatim copies of the Library's complete + 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 + distribute a copy of this License along with the Library. + + 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 Library or any portion of it, + thus forming a work based on the Library, 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) The modified work must itself be a software library. + + b) You must cause the files modified to carry prominent notices stating + that you changed the files and the date of any change. + + c) You must cause the whole of the work to be licensed at no charge to + all third parties under the terms of this License. + + d) If a facility in the modified Library refers to a function or a table + of data to be supplied by an application program that uses the + facility, other than as an argument passed when the facility is + invoked, then you must make a good faith effort to ensure that, in + the event an application does not supply such function or table, the + facility still operates, and performs whatever part of its purpose + remains meaningful. + + (For example, a function in a library to compute square roots has a + purpose that is entirely well-defined independent of the + application. Therefore, Subsection 2d requires that any + application-supplied function or table used by this function must be + optional: if the application does not supply it, the square root + function must still compute square roots.) + + These requirements apply to the modified work as a whole. If + identifiable sections of that work are not derived from the Library, 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 Library, 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 Library. + + In addition, mere aggregation of another work not based on the Library + with the Library (or with a work based on the Library) on a volume of a + storage or distribution medium does not bring the other work under the + scope of this License. + +3. You may opt to apply the terms of the ordinary GNU General Public + License instead of this License to a given copy of the Library. To do + this, you must alter all the notices that refer to this License, so that + they refer to the ordinary GNU General Public License, version 2, + instead of to this License. (If a newer version than version 2 of the + ordinary GNU General Public License has appeared, then you can specify + that version instead if you wish.) Do not make any other change in these + notices. + + Once this change is made in a given copy, it is irreversible for that + copy, so the ordinary GNU General Public License applies to all + subsequent copies and derivative works made from that copy. + + This option is useful when you wish to copy part of the code of the + Library into a program that is not a library. + +4. You may copy and distribute the Library (or a portion or derivative of + it, under Section 2) in object code or executable form under the terms + of Sections 1 and 2 above provided that you 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. + + If distribution of 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 satisfies the requirement to distribute the + source code, even though third parties are not compelled to copy the + source along with the object code. + +5. A program that contains no derivative of any portion of the Library, but + is designed to work with the Library by being compiled or linked with + it, is called a "work that uses the Library". Such a work, in isolation, + is not a derivative work of the Library, and therefore falls outside the + scope of this License. + + However, linking a "work that uses the Library" with the Library creates + an executable that is a derivative of the Library (because it contains + portions of the Library), rather than a "work that uses the + library". The executable is therefore covered by this License. Section 6 + states terms for distribution of such executables. + + When a "work that uses the Library" uses material from a header file + that is part of the Library, the object code for the work may be a + derivative work of the Library even though the source code is + not. Whether this is true is especially significant if the work can be + linked without the Library, or if the work is itself a library. The + threshold for this to be true is not precisely defined by law. + + If such an object file uses only numerical parameters, data structure + layouts and accessors, and small macros and small inline functions (ten + lines or less in length), then the use of the object file is + unrestricted, regardless of whether it is legally a derivative + work. (Executables containing this object code plus portions of the + Library will still fall under Section 6.) + + Otherwise, if the work is a derivative of the Library, you may + distribute the object code for the work under the terms of Section + 6. Any executables containing that work also fall under Section 6, + whether or not they are linked directly with the Library itself. + +6. As an exception to the Sections above, you may also combine or link a + "work that uses the Library" with the Library to produce a work + containing portions of the Library, and distribute that work under terms + of your choice, provided that the terms permit modification of the work + for the customer's own use and reverse engineering for debugging such + modifications. + + You must give prominent notice with each copy of the work that the + Library is used in it and that the Library and its use are covered by + this License. You must supply a copy of this License. If the work during + execution displays copyright notices, you must include the copyright + notice for the Library among them, as well as a reference directing the + user to the copy of this License. Also, you must do one of these things: + + a) Accompany the work with the complete corresponding machine-readable + source code for the Library including whatever changes were used in + the work (which must be distributed under Sections 1 and 2 above); + and, if the work is an executable linked with the Library, with the + complete machine-readable "work that uses the Library", as object + code and/or source code, so that the user can modify the Library and + then relink to produce a modified executable containing the modified + Library. (It is understood that the user who changes the contents of + definitions files in the Library will not necessarily be able to + recompile the application to use the modified definitions.) + + b) Use a suitable shared library mechanism for linking with the + Library. A suitable mechanism is one that (1) uses at run time a copy + of the library already present on the user's computer system, rather + than copying library functions into the executable, and (2) will + operate properly with a modified version of the library, if the user + installs one, as long as the modified version is interface-compatible + with the version that the work was made with. + + c) Accompany the work with a written offer, valid for at least three + years, to give the same user the materials specified in Subsection + 6a, above, for a charge no more than the cost of performing this + distribution. + + d) If distribution of the work is made by offering access to copy from a + designated place, offer equivalent access to copy the above specified + materials from the same place. + + e) Verify that the user has already received a copy of these materials + or that you have already sent this user a copy. + + For an executable, the required form of the "work that uses the Library" + must include any data and utility programs needed for reproducing the + executable from it. However, as a special exception, the materials to be + 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. + + It may happen that this requirement contradicts the license restrictions + of other proprietary libraries that do not normally accompany the + operating system. Such a contradiction means you cannot use both them + and the Library together in an executable that you distribute. + +7. You may place library facilities that are a work based on the Library + side-by-side in a single library together with other library facilities + not covered by this License, and distribute such a combined library, + provided that the separate distribution of the work based on the Library + and of the other library facilities is otherwise permitted, and provided + that you do these two things: + + a) Accompany the combined library with a copy of the same work based on + the Library, uncombined with any other library facilities. This must + be distributed under the terms of the Sections above. + + b) Give prominent notice with the combined library of the fact that part + of it is a work based on the Library, and explaining where to find + the accompanying uncombined form of the same work. + +8. You may not copy, modify, sublicense, link with, or distribute the + Library except as expressly provided under this License. Any attempt + otherwise to copy, modify, sublicense, link with, or distribute the + Library 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. + +9. 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 Library or its derivative works. These actions are prohibited by law + if you do not accept this License. Therefore, by modifying or + distributing the Library (or any work based on the Library), you + indicate your acceptance of this License to do so, and all its terms and + conditions for copying, distributing or modifying the Library or works + based on it. + +10. Each time you redistribute the Library (or any work based on the + Library), the recipient automatically receives a license from the + original licensor to copy, distribute, link with or modify the Library + 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 with this License. + +11. 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 Library at all. For example, if a patent license + would not permit royalty-free redistribution of the Library 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 Library. + + 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. + +12. If the distribution and/or use of the Library is restricted in certain + countries either by patents or by copyrighted interfaces, the original + copyright holder who places the Library 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. + +13. The Free Software Foundation may publish revised and/or new versions of + the Lesser 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 Library + 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 Library does not specify a license + version number, you may choose any version ever published by the Free + Software Foundation. + +14. If you wish to incorporate parts of the Library into other free + programs whose distribution conditions are incompatible with these, + 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 + +15. BECAUSE THE LIBRARY IS LICENSED FREE OF CHARGE, THERE IS NO WARRANTY + FOR THE LIBRARY, TO THE EXTENT PERMITTED BY APPLICABLE LAW. EXCEPT WHEN + OTHERWISE STATED IN WRITING THE COPYRIGHT HOLDERS AND/OR OTHER PARTIES + PROVIDE THE LIBRARY "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 LIBRARY IS WITH + YOU. SHOULD THE LIBRARY PROVE DEFECTIVE, YOU ASSUME THE COST OF ALL + NECESSARY SERVICING, REPAIR OR CORRECTION. + +16. 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 LIBRARY 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 LIBRARY + (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 LIBRARY TO OPERATE WITH ANY OTHER SOFTWARE), 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 Libraries + +If you develop a new library, and you want it to be of the greatest +possible use to the public, we recommend making it free software that +everyone can redistribute and change. You can do so by permitting +redistribution under these terms (or, alternatively, under the terms of the +ordinary General Public License). + +To apply these terms, attach the following notices to the library. It is +safest to attach them to the start of each source file to most effectively +convey the exclusion of warranty; and each file should have at least the +"copyright" line and a pointer to where the full notice is found. + +one line to give the library's name and an idea of what it does. +Copyright (C) year name of author + +This library is free software; you can redistribute it and/or modify it +under the terms of the GNU Lesser General Public License as published by +the Free Software Foundation; either version 2.1 of the License, or (at +your option) any later version. + +This library 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 Lesser General Public License +for more details. + +You should have received a copy of the GNU Lesser General Public License +along with this library; 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. + +You should also get your employer (if you work as a programmer) or your +school, if any, to sign a "copyright disclaimer" for the library, if +necessary. Here is a sample; alter the names: + +Yoyodyne, Inc., hereby disclaims all copyright interest in +the library `Frob' (a library for tweaking knobs) written +by James Random Hacker. + +signature of Ty Coon, 1 April 1990 +Ty Coon, President of Vice +That's all there is to it! @@ -0,0 +1,880 @@ + 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. + + <one line to give the program's name and a brief idea of what it does.> + Copyright (C) <year> <name of author> + + This program is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 2 of the License, or + (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License along + with this program; if not, write to the Free Software Foundation, Inc., + 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. + +Also add information on how to contact you by electronic and paper mail. + +If the program is interactive, make it output a short notice like this +when it starts in an interactive mode: + + Gnomovision version 69, Copyright (C) year name of author + Gnomovision comes with ABSOLUTELY NO WARRANTY; for details type `show w'. + This is free software, and you are welcome to redistribute it + under certain conditions; type `show c' for details. + +The hypothetical commands `show w' and `show c' should show the appropriate +parts of the General Public License. Of course, the commands you use may +be called something other than `show w' and `show c'; they could even be +mouse-clicks or menu items--whatever suits your program. + +You should also get your employer (if you work as a programmer) or your +school, if any, to sign a "copyright disclaimer" for the program, if +necessary. Here is a sample; alter the names: + + Yoyodyne, Inc., hereby disclaims all copyright interest in the program + `Gnomovision' (which makes passes at compilers) written by James Hacker. + + <signature of Ty Coon>, 1 April 1989 + Ty Coon, President of Vice + +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. + +================================================================= + +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) <year> <owner> . 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. + +================================================================= + +Valid-License-Identifier: LGPL-2.1 +Valid-License-Identifier: LGPL-2.1+ +SPDX-URL: https://spdx.org/licenses/LGPL-2.1.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 Lesser General Public License (LGPL) version 2.1 only' use: + SPDX-License-Identifier: LGPL-2.1 + For 'GNU Lesser General Public License (LGPL) version 2.1 or any later + version' use: + SPDX-License-Identifier: LGPL-2.1+ +License-Text: + +GNU LESSER GENERAL PUBLIC LICENSE +Version 2.1, February 1999 + +Copyright (C) 1991, 1999 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. + +[This is the first released version of the Lesser GPL. It also counts as +the successor of the GNU Library Public License, version 2, hence the +version number 2.1.] + +Preamble + +The licenses for most software are designed to take away your freedom to +share and change it. By contrast, the GNU General Public Licenses are +intended to guarantee your freedom to share and change free software--to +make sure the software is free for all its users. + +This license, the Lesser General Public License, applies to some specially +designated software packages--typically libraries--of the Free Software +Foundation and other authors who decide to use it. You can use it too, but +we suggest you first think carefully about whether this license or the +ordinary General Public License is the better strategy to use in any +particular case, based on the explanations below. + +When we speak of free software, we are referring to freedom of use, 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 and use pieces of it in new free +programs; and that you are informed that you can do these things. + +To protect your rights, we need to make restrictions that forbid +distributors to deny you these rights or to ask you to surrender these +rights. These restrictions translate to certain responsibilities for you if +you distribute copies of the library or if you modify it. + +For example, if you distribute copies of the library, whether gratis or for +a fee, you must give the recipients all the rights that we gave you. You +must make sure that they, too, receive or can get the source code. If you +link other code with the library, you must provide complete object files to +the recipients, so that they can relink them with the library after making +changes to the library and recompiling it. And you must show them these +terms so they know their rights. + +We protect your rights with a two-step method: (1) we copyright the +library, and (2) we offer you this license, which gives you legal +permission to copy, distribute and/or modify the library. + +To protect each distributor, we want to make it very clear that there is no +warranty for the free library. Also, if the library is modified by someone +else and passed on, the recipients should know that what they have is not +the original version, so that the original author's reputation will not be +affected by problems that might be introduced by others. + +Finally, software patents pose a constant threat to the existence of any +free program. We wish to make sure that a company cannot effectively +restrict the users of a free program by obtaining a restrictive license +from a patent holder. Therefore, we insist that any patent license obtained +for a version of the library must be consistent with the full freedom of +use specified in this license. + +Most GNU software, including some libraries, is covered by the ordinary GNU +General Public License. This license, the GNU Lesser General Public +License, applies to certain designated libraries, and is quite different +from the ordinary General Public License. We use this license for certain +libraries in order to permit linking those libraries into non-free +programs. + +When a program is linked with a library, whether statically or using a +shared library, the combination of the two is legally speaking a combined +work, a derivative of the original library. The ordinary General Public +License therefore permits such linking only if the entire combination fits +its criteria of freedom. The Lesser General Public License permits more lax +criteria for linking other code with the library. + +We call this license the "Lesser" General Public License because it does +Less to protect the user's freedom than the ordinary General Public +License. It also provides other free software developers Less of an +advantage over competing non-free programs. These disadvantages are the +reason we use the ordinary General Public License for many +libraries. However, the Lesser license provides advantages in certain +special circumstances. + +For example, on rare occasions, there may be a special need to encourage +the widest possible use of a certain library, so that it becomes a de-facto +standard. To achieve this, non-free programs must be allowed to use the +library. A more frequent case is that a free library does the same job as +widely used non-free libraries. In this case, there is little to gain by +limiting the free library to free software only, so we use the Lesser +General Public License. + +In other cases, permission to use a particular library in non-free programs +enables a greater number of people to use a large body of free +software. For example, permission to use the GNU C Library in non-free +programs enables many more people to use the whole GNU operating system, as +well as its variant, the GNU/Linux operating system. + +Although the Lesser General Public License is Less protective of the users' +freedom, it does ensure that the user of a program that is linked with the +Library has the freedom and the wherewithal to run that program using a +modified version of the Library. + +The precise terms and conditions for copying, distribution and modification +follow. Pay close attention to the difference between a "work based on the +library" and a "work that uses the library". The former contains code +derived from the library, whereas the latter must be combined with the +library in order to run. + +TERMS AND CONDITIONS FOR COPYING, DISTRIBUTION AND MODIFICATION + +0. This License Agreement applies to any software library or other program + which contains a notice placed by the copyright holder or other + authorized party saying it may be distributed under the terms of this + Lesser General Public License (also called "this License"). Each + licensee is addressed as "you". + + A "library" means a collection of software functions and/or data + prepared so as to be conveniently linked with application programs + (which use some of those functions and data) to form executables. + + The "Library", below, refers to any such software library or work which + has been distributed under these terms. A "work based on the Library" + means either the Library or any derivative work under copyright law: + that is to say, a work containing the Library or a portion of it, either + verbatim or with modifications and/or translated straightforwardly into + another language. (Hereinafter, translation is included without + limitation in the term "modification".) + + "Source code" for a work means the preferred form of the work for making + modifications to it. For a library, 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 library. + + Activities other than copying, distribution and modification are not + covered by this License; they are outside its scope. The act of running + a program using the Library is not restricted, and output from such a + program is covered only if its contents constitute a work based on the + Library (independent of the use of the Library in a tool for writing + it). Whether that is true depends on what the Library does and what the + program that uses the Library does. + +1. You may copy and distribute verbatim copies of the Library's complete + 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 + distribute a copy of this License along with the Library. + + 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 Library or any portion of it, + thus forming a work based on the Library, 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) The modified work must itself be a software library. + + b) You must cause the files modified to carry prominent notices stating + that you changed the files and the date of any change. + + c) You must cause the whole of the work to be licensed at no charge to + all third parties under the terms of this License. + + d) If a facility in the modified Library refers to a function or a table + of data to be supplied by an application program that uses the + facility, other than as an argument passed when the facility is + invoked, then you must make a good faith effort to ensure that, in + the event an application does not supply such function or table, the + facility still operates, and performs whatever part of its purpose + remains meaningful. + + (For example, a function in a library to compute square roots has a + purpose that is entirely well-defined independent of the + application. Therefore, Subsection 2d requires that any + application-supplied function or table used by this function must be + optional: if the application does not supply it, the square root + function must still compute square roots.) + + These requirements apply to the modified work as a whole. If + identifiable sections of that work are not derived from the Library, 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 Library, 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 Library. + + In addition, mere aggregation of another work not based on the Library + with the Library (or with a work based on the Library) on a volume of a + storage or distribution medium does not bring the other work under the + scope of this License. + +3. You may opt to apply the terms of the ordinary GNU General Public + License instead of this License to a given copy of the Library. To do + this, you must alter all the notices that refer to this License, so that + they refer to the ordinary GNU General Public License, version 2, + instead of to this License. (If a newer version than version 2 of the + ordinary GNU General Public License has appeared, then you can specify + that version instead if you wish.) Do not make any other change in these + notices. + + Once this change is made in a given copy, it is irreversible for that + copy, so the ordinary GNU General Public License applies to all + subsequent copies and derivative works made from that copy. + + This option is useful when you wish to copy part of the code of the + Library into a program that is not a library. + +4. You may copy and distribute the Library (or a portion or derivative of + it, under Section 2) in object code or executable form under the terms + of Sections 1 and 2 above provided that you 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. + + If distribution of 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 satisfies the requirement to distribute the + source code, even though third parties are not compelled to copy the + source along with the object code. + +5. A program that contains no derivative of any portion of the Library, but + is designed to work with the Library by being compiled or linked with + it, is called a "work that uses the Library". Such a work, in isolation, + is not a derivative work of the Library, and therefore falls outside the + scope of this License. + + However, linking a "work that uses the Library" with the Library creates + an executable that is a derivative of the Library (because it contains + portions of the Library), rather than a "work that uses the + library". The executable is therefore covered by this License. Section 6 + states terms for distribution of such executables. + + When a "work that uses the Library" uses material from a header file + that is part of the Library, the object code for the work may be a + derivative work of the Library even though the source code is + not. Whether this is true is especially significant if the work can be + linked without the Library, or if the work is itself a library. The + threshold for this to be true is not precisely defined by law. + + If such an object file uses only numerical parameters, data structure + layouts and accessors, and small macros and small inline functions (ten + lines or less in length), then the use of the object file is + unrestricted, regardless of whether it is legally a derivative + work. (Executables containing this object code plus portions of the + Library will still fall under Section 6.) + + Otherwise, if the work is a derivative of the Library, you may + distribute the object code for the work under the terms of Section + 6. Any executables containing that work also fall under Section 6, + whether or not they are linked directly with the Library itself. + +6. As an exception to the Sections above, you may also combine or link a + "work that uses the Library" with the Library to produce a work + containing portions of the Library, and distribute that work under terms + of your choice, provided that the terms permit modification of the work + for the customer's own use and reverse engineering for debugging such + modifications. + + You must give prominent notice with each copy of the work that the + Library is used in it and that the Library and its use are covered by + this License. You must supply a copy of this License. If the work during + execution displays copyright notices, you must include the copyright + notice for the Library among them, as well as a reference directing the + user to the copy of this License. Also, you must do one of these things: + + a) Accompany the work with the complete corresponding machine-readable + source code for the Library including whatever changes were used in + the work (which must be distributed under Sections 1 and 2 above); + and, if the work is an executable linked with the Library, with the + complete machine-readable "work that uses the Library", as object + code and/or source code, so that the user can modify the Library and + then relink to produce a modified executable containing the modified + Library. (It is understood that the user who changes the contents of + definitions files in the Library will not necessarily be able to + recompile the application to use the modified definitions.) + + b) Use a suitable shared library mechanism for linking with the + Library. A suitable mechanism is one that (1) uses at run time a copy + of the library already present on the user's computer system, rather + than copying library functions into the executable, and (2) will + operate properly with a modified version of the library, if the user + installs one, as long as the modified version is interface-compatible + with the version that the work was made with. + + c) Accompany the work with a written offer, valid for at least three + years, to give the same user the materials specified in Subsection + 6a, above, for a charge no more than the cost of performing this + distribution. + + d) If distribution of the work is made by offering access to copy from a + designated place, offer equivalent access to copy the above specified + materials from the same place. + + e) Verify that the user has already received a copy of these materials + or that you have already sent this user a copy. + + For an executable, the required form of the "work that uses the Library" + must include any data and utility programs needed for reproducing the + executable from it. However, as a special exception, the materials to be + 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. + + It may happen that this requirement contradicts the license restrictions + of other proprietary libraries that do not normally accompany the + operating system. Such a contradiction means you cannot use both them + and the Library together in an executable that you distribute. + +7. You may place library facilities that are a work based on the Library + side-by-side in a single library together with other library facilities + not covered by this License, and distribute such a combined library, + provided that the separate distribution of the work based on the Library + and of the other library facilities is otherwise permitted, and provided + that you do these two things: + + a) Accompany the combined library with a copy of the same work based on + the Library, uncombined with any other library facilities. This must + be distributed under the terms of the Sections above. + + b) Give prominent notice with the combined library of the fact that part + of it is a work based on the Library, and explaining where to find + the accompanying uncombined form of the same work. + +8. You may not copy, modify, sublicense, link with, or distribute the + Library except as expressly provided under this License. Any attempt + otherwise to copy, modify, sublicense, link with, or distribute the + Library 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. + +9. 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 Library or its derivative works. These actions are prohibited by law + if you do not accept this License. Therefore, by modifying or + distributing the Library (or any work based on the Library), you + indicate your acceptance of this License to do so, and all its terms and + conditions for copying, distributing or modifying the Library or works + based on it. + +10. Each time you redistribute the Library (or any work based on the + Library), the recipient automatically receives a license from the + original licensor to copy, distribute, link with or modify the Library + 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 with this License. + +11. 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 Library at all. For example, if a patent license + would not permit royalty-free redistribution of the Library 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 Library. + + 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. + +12. If the distribution and/or use of the Library is restricted in certain + countries either by patents or by copyrighted interfaces, the original + copyright holder who places the Library 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. + +13. The Free Software Foundation may publish revised and/or new versions of + the Lesser 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 Library + 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 Library does not specify a license + version number, you may choose any version ever published by the Free + Software Foundation. + +14. If you wish to incorporate parts of the Library into other free + programs whose distribution conditions are incompatible with these, + 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 + +15. BECAUSE THE LIBRARY IS LICENSED FREE OF CHARGE, THERE IS NO WARRANTY + FOR THE LIBRARY, TO THE EXTENT PERMITTED BY APPLICABLE LAW. EXCEPT WHEN + OTHERWISE STATED IN WRITING THE COPYRIGHT HOLDERS AND/OR OTHER PARTIES + PROVIDE THE LIBRARY "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 LIBRARY IS WITH + YOU. SHOULD THE LIBRARY PROVE DEFECTIVE, YOU ASSUME THE COST OF ALL + NECESSARY SERVICING, REPAIR OR CORRECTION. + +16. 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 LIBRARY 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 LIBRARY + (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 LIBRARY TO OPERATE WITH ANY OTHER SOFTWARE), 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 Libraries + +If you develop a new library, and you want it to be of the greatest +possible use to the public, we recommend making it free software that +everyone can redistribute and change. You can do so by permitting +redistribution under these terms (or, alternatively, under the terms of the +ordinary General Public License). + +To apply these terms, attach the following notices to the library. It is +safest to attach them to the start of each source file to most effectively +convey the exclusion of warranty; and each file should have at least the +"copyright" line and a pointer to where the full notice is found. + +one line to give the library's name and an idea of what it does. +Copyright (C) year name of author + +This library is free software; you can redistribute it and/or modify it +under the terms of the GNU Lesser General Public License as published by +the Free Software Foundation; either version 2.1 of the License, or (at +your option) any later version. + +This library 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 Lesser General Public License +for more details. + +You should have received a copy of the GNU Lesser General Public License +along with this library; 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. + +You should also get your employer (if you work as a programmer) or your +school, if any, to sign a "copyright disclaimer" for the library, if +necessary. Here is a sample; alter the names: + +Yoyodyne, Inc., hereby disclaims all copyright interest in +the library `Frob' (a library for tweaking knobs) written +by James Random Hacker. + +signature of Ty Coon, 1 April 1990 +Ty Coon, President of Vice +That's all there is to it! diff --git a/MANIFEST.in b/MANIFEST.in new file mode 100644 index 0000000..0eee931 --- /dev/null +++ b/MANIFEST.in @@ -0,0 +1,11 @@ +# SPDX-License-Identifier: (GPL-2.0-or-later OR BSD-2-Clause) + +global-exclude * +include README +include GPL +include BSD-2-Clause +include setup.py +include pylibfdt/libfdt.i +include libfdt/libfdt.h +include libfdt/fdt.h +include libfdt/libfdt_env.h @@ -1,3 +1,19 @@ +# This project was upgraded with external_updater. +# Usage: tools/external_updater/updater.sh update dtc +# For more info, check https://cs.android.com/android/platform/superproject/+/master:tools/external_updater/README.md + +name: "dtc" +description: "Device tree compiler tools (dtc) and libfdt." third_party { + url { + type: GIT + value: "https://git.kernel.org/pub/scm/utils/dtc/dtc.git" + } + version: "v1.6.1" license_type: RESTRICTED + last_upgrade_date { + year: 2023 + month: 1 + day: 18 + } } diff --git a/MODULE_LICENSE_BSD b/MODULE_LICENSE_BSD new file mode 100644 index 0000000..e69de29 --- /dev/null +++ b/MODULE_LICENSE_BSD diff --git a/MODULE_LICENSE_LGPL b/MODULE_LICENSE_LGPL new file mode 100644 index 0000000..e69de29 --- /dev/null +++ b/MODULE_LICENSE_LGPL @@ -11,7 +11,7 @@ # VERSION = 1 PATCHLEVEL = 6 -SUBLEVEL = 0 +SUBLEVEL = 1 EXTRAVERSION = LOCAL_VERSION = CONFIG_LOCALVERSION = @@ -21,7 +21,7 @@ CONFIG_LOCALVERSION = ASSUME_MASK ?= 0 CPPFLAGS = -I libfdt -I . -DFDT_ASSUME_MASK=$(ASSUME_MASK) -WARNINGS = -Wall -Wpointer-arith -Wcast-qual -Wnested-externs \ +WARNINGS = -Wall -Wpointer-arith -Wcast-qual -Wnested-externs -Wsign-compare \ -Wstrict-prototypes -Wmissing-prototypes -Wredundant-decls -Wshadow CFLAGS = -g -Os $(SHAREDLIB_CFLAGS) -Werror $(WARNINGS) $(EXTRA_CFLAGS) @@ -59,6 +59,7 @@ ifeq ($(NO_YAML),1) CFLAGS += -DNO_YAML else LDLIBS_dtc += $(shell $(PKG_CONFIG) --libs yaml-0.1) + CFLAGS += $(shell $(PKG_CONFIG) --cflags yaml-0.1) endif ifeq ($(HOSTOS),darwin) @@ -197,6 +198,13 @@ LIBFDT_lib = $(LIBFDT_dir)/$(LIBFDT_LIB) LIBFDT_include = $(addprefix $(LIBFDT_dir)/,$(LIBFDT_INCLUDES)) LIBFDT_version = $(addprefix $(LIBFDT_dir)/,$(LIBFDT_VERSION)) +ifeq ($(STATIC_BUILD),1) + CFLAGS += -static + LIBFDT_dep = $(LIBFDT_archive) +else + LIBFDT_dep = $(LIBFDT_lib) +endif + include $(LIBFDT_dir)/Makefile.libfdt .PHONY: libfdt @@ -260,11 +268,11 @@ convert-dtsv0: $(CONVERT_OBJS) fdtdump: $(FDTDUMP_OBJS) -fdtget: $(FDTGET_OBJS) $(LIBFDT_lib) +fdtget: $(FDTGET_OBJS) $(LIBFDT_dep) -fdtput: $(FDTPUT_OBJS) $(LIBFDT_lib) +fdtput: $(FDTPUT_OBJS) $(LIBFDT_dep) -fdtoverlay: $(FDTOVERLAY_OBJS) $(LIBFDT_lib) +fdtoverlay: $(FDTOVERLAY_OBJS) $(LIBFDT_dep) dist: git archive --format=tar --prefix=dtc-$(dtc_version)/ HEAD \ @@ -380,4 +388,8 @@ clean: libfdt_clean pylibfdt_clean tests_clean @$(VECHO) BISON $@ $(BISON) -b $(basename $(basename $@)) -d $< +# Some checks expect dtc-parser.h, so create link +dtc-parser.h: dtc-parser.tab.h + ln -s $^ $@ + FORCE: @@ -1,340 +0,0 @@ - GNU GENERAL PUBLIC LICENSE - Version 2, June 1991 - - Copyright (C) 1989, 1991 Free Software Foundation, Inc. - 59 Temple Place, Suite 330, Boston, MA 02111-1307 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 Library General Public License instead.) You can apply it to -your programs, too. - - When we speak of free software, we are referring to freedom, not -price. Our General Public Licenses are designed to make sure that you -have the freedom to distribute copies of free software (and charge for -this service if you wish), that you receive source code or can get it -if you want it, that you can change the software or use pieces of it -in new free programs; and that you know you can do these things. - - To protect your rights, we need to make restrictions that forbid -anyone to deny you these rights or to ask you to surrender the rights. -These restrictions translate to certain responsibilities for you if you -distribute copies of the software, or if you modify it. - - For example, if you distribute copies of such a program, whether -gratis or for a fee, you must give the recipients all the rights that -you have. You must make sure that they, too, receive or can get the -source code. And you must show them these terms so they know their -rights. - - We protect your rights with two steps: (1) copyright the software, and -(2) offer you this license which gives you legal permission to copy, -distribute and/or modify the software. - - Also, for each author's protection and ours, we want to make certain -that everyone understands that there is no warranty for this free -software. If the software is modified by someone else and passed on, we -want its recipients to know that what they have is not the original, so -that any problems introduced by others will not reflect on the original -authors' reputations. - - Finally, any free program is threatened constantly by software -patents. We wish to avoid the danger that redistributors of a free -program will individually obtain patent licenses, in effect making the -program proprietary. To prevent this, we have made it clear that any -patent must be licensed for everyone's free use or not licensed at all. - - The precise terms and conditions for copying, distribution and -modification follow. - - GNU GENERAL PUBLIC LICENSE - TERMS AND CONDITIONS FOR COPYING, DISTRIBUTION AND MODIFICATION - - 0. This License applies to any program or other work which contains -a notice placed by the copyright holder saying it may be distributed -under the terms of this General Public License. The "Program", below, -refers to any such program or work, and a "work based on the Program" -means either the Program or any derivative work under copyright law: -that is to say, a work containing the Program or a portion of it, -either verbatim or with modifications and/or translated into another -language. (Hereinafter, translation is included without limitation in -the term "modification".) Each licensee is addressed as "you". - -Activities other than copying, distribution and modification are not -covered by this License; they are outside its scope. The act of -running the Program is not restricted, and the output from the Program -is covered only if its contents constitute a work based on the -Program (independent of having been made by running the Program). -Whether that is true depends on what the Program does. - - 1. You may copy and distribute verbatim copies of the Program's -source code as you receive it, in any medium, provided that you -conspicuously and appropriately publish on each copy an appropriate -copyright notice and disclaimer of warranty; keep intact all the -notices that refer to this License and to the absence of any warranty; -and give any other recipients of the Program a copy of this License -along with the Program. - -You may charge a fee for the physical act of transferring a copy, and -you may at your option offer warranty protection in exchange for a fee. - - 2. You may modify your copy or copies of the Program or any portion -of it, thus forming a work based on the Program, and copy and -distribute such modifications or work under the terms of Section 1 -above, provided that you also meet all of these conditions: - - a) You must cause the modified files to carry prominent notices - stating that you changed the files and the date of any change. - - b) You must cause any work that you distribute or publish, that in - whole or in part contains or is derived from the Program or any - part thereof, to be licensed as a whole at no charge to all third - parties under the terms of this License. - - c) If the modified program normally reads commands interactively - when run, you must cause it, when started running for such - interactive use in the most ordinary way, to print or display an - announcement including an appropriate copyright notice and a - notice that there is no warranty (or else, saying that you provide - a warranty) and that users may redistribute the program under - these conditions, and telling the user how to view a copy of this - License. (Exception: if the Program itself is interactive but - does not normally print such an announcement, your work based on - the Program is not required to print an announcement.) - -These requirements apply to the modified work as a whole. If -identifiable sections of that work are not derived from the Program, -and can be reasonably considered independent and separate works in -themselves, then this License, and its terms, do not apply to those -sections when you distribute them as separate works. But when you -distribute the same sections as part of a whole which is a work based -on the Program, the distribution of the whole must be on the terms of -this License, whose permissions for other licensees extend to the -entire whole, and thus to each and every part regardless of who wrote it. - -Thus, it is not the intent of this section to claim rights or contest -your rights to work written entirely by you; rather, the intent is to -exercise the right to control the distribution of derivative or -collective works based on the Program. - -In addition, mere aggregation of another work not based on the Program -with the Program (or with a work based on the Program) on a volume of -a storage or distribution medium does not bring the other work under -the scope of this License. - - 3. You may copy and distribute the Program (or a work based on it, -under Section 2) in object code or executable form under the terms of -Sections 1 and 2 above provided that you also do one of the following: - - a) Accompany it with the complete corresponding machine-readable - source code, which must be distributed under the terms of Sections - 1 and 2 above on a medium customarily used for software interchange; or, - - b) Accompany it with a written offer, valid for at least three - years, to give any third party, for a charge no more than your - cost of physically performing source distribution, a complete - machine-readable copy of the corresponding source code, to be - distributed under the terms of Sections 1 and 2 above on a medium - customarily used for software interchange; or, - - c) Accompany it with the information you received as to the offer - to distribute corresponding source code. (This alternative is - allowed only for noncommercial distribution and only if you - received the program in object code or executable form with such - an offer, in accord with Subsection b above.) - -The source code for a work means the preferred form of the work for -making modifications to it. For an executable work, complete source -code means all the source code for all modules it contains, plus any -associated interface definition files, plus the scripts used to -control compilation and installation of the executable. However, as a -special exception, the source code distributed need not include -anything that is normally distributed (in either source or binary -form) with the major components (compiler, kernel, and so on) of the -operating system on which the executable runs, unless that component -itself accompanies the executable. - -If distribution of executable or object code is made by offering -access to copy from a designated place, then offering equivalent -access to copy the source code from the same place counts as -distribution of the source code, even though third parties are not -compelled to copy the source along with the object code. - - 4. You may not copy, modify, sublicense, or distribute the Program -except as expressly provided under this License. Any attempt -otherwise to copy, modify, sublicense or distribute the Program is -void, and will automatically terminate your rights under this License. -However, parties who have received copies, or rights, from you under -this License will not have their licenses terminated so long as such -parties remain in full compliance. - - 5. You are not required to accept this License, since you have not -signed it. However, nothing else grants you permission to modify or -distribute the Program or its derivative works. These actions are -prohibited by law if you do not accept this License. Therefore, by -modifying or distributing the Program (or any work based on the -Program), you indicate your acceptance of this License to do so, and -all its terms and conditions for copying, distributing or modifying -the Program or works based on it. - - 6. Each time you redistribute the Program (or any work based on the -Program), the recipient automatically receives a license from the -original licensor to copy, distribute or modify the Program subject to -these terms and conditions. You may not impose any further -restrictions on the recipients' exercise of the rights granted herein. -You are not responsible for enforcing compliance by third parties to -this License. - - 7. If, as a consequence of a court judgment or allegation of patent -infringement or for any other reason (not limited to patent issues), -conditions are imposed on you (whether by court order, agreement or -otherwise) that contradict the conditions of this License, they do not -excuse you from the conditions of this License. If you cannot -distribute so as to satisfy simultaneously your obligations under this -License and any other pertinent obligations, then as a consequence you -may not distribute the Program at all. For example, if a patent -license would not permit royalty-free redistribution of the Program by -all those who receive copies directly or indirectly through you, then -the only way you could satisfy both it and this License would be to -refrain entirely from distribution of the Program. - -If any portion of this section is held invalid or unenforceable under -any particular circumstance, the balance of the section is intended to -apply and the section as a whole is intended to apply in other -circumstances. - -It is not the purpose of this section to induce you to infringe any -patents or other property right claims or to contest validity of any -such claims; this section has the sole purpose of protecting the -integrity of the free software distribution system, which is -implemented by public license practices. Many people have made -generous contributions to the wide range of software distributed -through that system in reliance on consistent application of that -system; it is up to the author/donor to decide if he or she is willing -to distribute software through any other system and a licensee cannot -impose that choice. - -This section is intended to make thoroughly clear what is believed to -be a consequence of the rest of this License. - - 8. If the distribution and/or use of the Program is restricted in -certain countries either by patents or by copyrighted interfaces, the -original copyright holder who places the Program under this License -may add an explicit geographical distribution limitation excluding -those countries, so that distribution is permitted only in or among -countries not thus excluded. In such case, this License incorporates -the limitation as if written in the body of this License. - - 9. The Free Software Foundation may publish revised and/or new versions -of the General Public License from time to time. Such new versions will -be similar in spirit to the present version, but may differ in detail to -address new problems or concerns. - -Each version is given a distinguishing version number. If the Program -specifies a version number of this License which applies to it and "any -later version", you have the option of following the terms and conditions -either of that version or of any later version published by the Free -Software Foundation. If the Program does not specify a version number of -this License, you may choose any version ever published by the Free Software -Foundation. - - 10. If you wish to incorporate parts of the Program into other free -programs whose distribution conditions are different, write to the author -to ask for permission. For software which is copyrighted by the Free -Software Foundation, write to the Free Software Foundation; we sometimes -make exceptions for this. Our decision will be guided by the two goals -of preserving the free status of all derivatives of our free software and -of promoting the sharing and reuse of software generally. - - NO WARRANTY - - 11. BECAUSE THE PROGRAM IS LICENSED FREE OF CHARGE, THERE IS NO WARRANTY -FOR THE PROGRAM, TO THE EXTENT PERMITTED BY APPLICABLE LAW. EXCEPT WHEN -OTHERWISE STATED IN WRITING THE COPYRIGHT HOLDERS AND/OR OTHER PARTIES -PROVIDE THE PROGRAM "AS IS" WITHOUT WARRANTY OF ANY KIND, EITHER EXPRESSED -OR IMPLIED, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF -MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. THE ENTIRE RISK AS -TO THE QUALITY AND PERFORMANCE OF THE PROGRAM IS WITH YOU. SHOULD THE -PROGRAM PROVE DEFECTIVE, YOU ASSUME THE COST OF ALL NECESSARY SERVICING, -REPAIR OR CORRECTION. - - 12. IN NO EVENT UNLESS REQUIRED BY APPLICABLE LAW OR AGREED TO IN WRITING -WILL ANY COPYRIGHT HOLDER, OR ANY OTHER PARTY WHO MAY MODIFY AND/OR -REDISTRIBUTE THE PROGRAM AS PERMITTED ABOVE, BE LIABLE TO YOU FOR DAMAGES, -INCLUDING ANY GENERAL, SPECIAL, INCIDENTAL OR CONSEQUENTIAL DAMAGES ARISING -OUT OF THE USE OR INABILITY TO USE THE PROGRAM (INCLUDING BUT NOT LIMITED -TO LOSS OF DATA OR DATA BEING RENDERED INACCURATE OR LOSSES SUSTAINED BY -YOU OR THIRD PARTIES OR A FAILURE OF THE PROGRAM TO OPERATE WITH ANY OTHER -PROGRAMS), EVEN IF SUCH HOLDER OR OTHER PARTY HAS BEEN ADVISED OF THE -POSSIBILITY OF SUCH DAMAGES. - - END OF TERMS AND CONDITIONS - - How to Apply These Terms to Your New Programs - - If you develop a new program, and you want it to be of the greatest -possible use to the public, the best way to achieve this is to make it -free software which everyone can redistribute and change under these terms. - - To do so, attach the following notices to the program. It is safest -to attach them to the start of each source file to most effectively -convey the exclusion of warranty; and each file should have at least -the "copyright" line and a pointer to where the full notice is found. - - <one line to give the program's name and a brief idea of what it does.> - Copyright (C) <year> <name of author> - - This program is free software; you can redistribute it and/or modify - it under the terms of the GNU General Public License as published by - the Free Software Foundation; either version 2 of the License, or - (at your option) any later version. - - This program is distributed in the hope that it will be useful, - but WITHOUT ANY WARRANTY; without even the implied warranty of - MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - GNU General Public License for more details. - - You should have received a copy of the GNU General Public License - along with this program; if not, write to the Free Software - Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA - - -Also add information on how to contact you by electronic and paper mail. - -If the program is interactive, make it output a short notice like this -when it starts in an interactive mode: - - Gnomovision version 69, Copyright (C) year name of author - Gnomovision comes with ABSOLUTELY NO WARRANTY; for details type `show w'. - This is free software, and you are welcome to redistribute it - under certain conditions; type `show c' for details. - -The hypothetical commands `show w' and `show c' should show the appropriate -parts of the General Public License. Of course, the commands you use may -be called something other than `show w' and `show c'; they could even be -mouse-clicks or menu items--whatever suits your program. - -You should also get your employer (if you work as a programmer) or your -school, if any, to sign a "copyright disclaimer" for the program, if -necessary. Here is a sample; alter the names: - - Yoyodyne, Inc., hereby disclaims all copyright interest in the program - `Gnomovision' (which makes passes at compilers) written by James Hacker. - - <signature of Ty Coon>, 1 April 1989 - Ty Coon, President of Vice - -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 Library General -Public License instead of this License. @@ -1,91 +0,0 @@ -The source tree contains the Device Tree Compiler (dtc) toolchain for -working with device tree source and binary files and also libfdt, a -utility library for reading and manipulating the binary format. - -DTC and LIBFDT are maintained by: - -David Gibson <david@gibson.dropbear.id.au> -Jon Loeliger <jdl@jdl.com> - - -Python library --------------- - -A Python library is also available. To build this you will need to install -swig and Python development files. On Debian distributions: - - sudo apt-get install swig python3-dev - -The library provides an Fdt class which you can use like this: - -$ PYTHONPATH=../pylibfdt python3 ->>> import libfdt ->>> fdt = libfdt.Fdt(open('test_tree1.dtb', mode='rb').read()) ->>> node = fdt.path_offset('/subnode@1') ->>> print(node) -124 ->>> prop_offset = fdt.first_property_offset(node) ->>> prop = fdt.get_property_by_offset(prop_offset) ->>> print('%s=%s' % (prop.name, prop.as_str())) -compatible=subnode1 ->>> node2 = fdt.path_offset('/') ->>> print(fdt.getprop(node2, 'compatible').as_str()) -test_tree1 - -You will find tests in tests/pylibfdt_tests.py showing how to use each -method. Help is available using the Python help command, e.g.: - - $ cd pylibfdt - $ python3 -c "import libfdt; help(libfdt)" - -If you add new features, please check code coverage: - - $ sudo apt-get install python3-coverage - $ cd tests - # It's just 'coverage' on most other distributions - $ python3-coverage run pylibfdt_tests.py - $ python3-coverage html - # Open 'htmlcov/index.html' in your browser - - -To install the library via the normal setup.py method, use: - - ./pylibfdt/setup.py install [--prefix=/path/to/install_dir] - -If --prefix is not provided, the default prefix is used, typically '/usr' -or '/usr/local'. See Python's distutils documentation for details. You can -also install via the Makefile if you like, but the above is more common. - -To install both libfdt and pylibfdt you can use: - - make install [SETUP_PREFIX=/path/to/install_dir] \ - [PREFIX=/path/to/install_dir] - -To disable building the python library, even if swig and Python are available, -use: - - make NO_PYTHON=1 - - -More work remains to support all of libfdt, including access to numeric -values. - - -Tests ------ - -Test files are kept in the tests/ directory. Use 'make check' to build and run -all tests. - -If you want to adjust a test file, be aware that tree_tree1.dts is compiled -and checked against a binary tree from assembler macros in trees.S. So -if you change that file you must change tree.S also. - - -Mailing list ------------- -The following list is for discussion about dtc and libfdt implementation -mailto:devicetree-compiler@vger.kernel.org - -Core device tree bindings are discussed on the devicetree-spec list: -mailto:devicetree-spec@vger.kernel.org diff --git a/README.md b/README.md new file mode 100644 index 0000000..8f1a5d2 --- /dev/null +++ b/README.md @@ -0,0 +1,100 @@ +# Device Tree Compiler and libfdt + +The source tree contains the Device Tree Compiler (dtc) toolchain for +working with device tree source and binary files and also libfdt, a +utility library for reading and manipulating the binary format. + +dtc and libfdt are maintained by: + +* [David Gibson `<david@gibson.dropbear.id.au>`](mailto:david@gibson.dropbear.id.au) + +## Python library + +A Python library wrapping libfdt is also available. To build this you +will need to install `swig` and Python development files. On Debian +distributions: + +``` +$ sudo apt-get install swig python3-dev +``` + +The library provides an `Fdt` class which you can use like this: + +``` +$ PYTHONPATH=../pylibfdt python3 +>>> import libfdt +>>> fdt = libfdt.Fdt(open('test_tree1.dtb', mode='rb').read()) +>>> node = fdt.path_offset('/subnode@1') +>>> print(node) +124 +>>> prop_offset = fdt.first_property_offset(node) +>>> prop = fdt.get_property_by_offset(prop_offset) +>>> print('%s=%s' % (prop.name, prop.as_str())) +compatible=subnode1 +>>> node2 = fdt.path_offset('/') +>>> print(fdt.getprop(node2, 'compatible').as_str()) +test_tree1 +``` + +You will find tests in `tests/pylibfdt_tests.py` showing how to use each +method. Help is available using the Python help command, e.g.: + +``` +$ cd pylibfdt +$ python3 -c "import libfdt; help(libfdt)" +``` + +If you add new features, please check code coverage: + +``` +$ sudo apt-get install python3-coverage +$ cd tests +# It's just 'coverage' on most other distributions +$ python3-coverage run pylibfdt_tests.py +$ python3-coverage html +# Open 'htmlcov/index.html' in your browser +``` + +The library can be installed with pip from a local source tree: + +``` +$ pip install . [--user|--prefix=/path/to/install_dir] +``` + +Or directly from a remote git repo: + +``` +$ pip install git+git://git.kernel.org/pub/scm/utils/dtc/dtc.git@main +``` + +The install depends on libfdt shared library being installed on the +host system first. Generally, using `--user` or `--prefix` is not +necessary and pip will use the default location for the Python +installation which varies if the user is root or not. + +You can also install everything via make if you like, but pip is +recommended. + +To install both libfdt and pylibfdt you can use: + +``` +$ make install [PREFIX=/path/to/install_dir] +``` + +To disable building the python library, even if swig and Python are available, +use: + +``` +$ make NO_PYTHON=1 +``` + +More work remains to support all of libfdt, including access to numeric +values. + +## Mailing lists + +* The [devicetree-compiler](mailto:devicetree-compiler@vger.kernel.org) + list is for discussion about dtc and libfdt implementation. +* Core device tree bindings are discussed on the + [devicetree-spec](mailto:devicetree-spec@vger.kernel.org) list. + @@ -143,6 +143,14 @@ static void check_nodes_props(struct check *c, struct dt_info *dti, struct node check_nodes_props(c, dti, child); } +static bool is_multiple_of(int multiple, int divisor) +{ + if (divisor == 0) + return multiple == 0; + else + return (multiple % divisor) == 0; +} + static bool run_check(struct check *c, struct dt_info *dti) { struct node *dt = dti->dt; @@ -297,19 +305,20 @@ ERROR(duplicate_property_names, check_duplicate_property_names, NULL); #define LOWERCASE "abcdefghijklmnopqrstuvwxyz" #define UPPERCASE "ABCDEFGHIJKLMNOPQRSTUVWXYZ" #define DIGITS "0123456789" -#define PROPNODECHARS LOWERCASE UPPERCASE DIGITS ",._+*#?-" +#define NODECHARS LOWERCASE UPPERCASE DIGITS ",._+-@" +#define PROPCHARS LOWERCASE UPPERCASE DIGITS ",._+*#?-" #define PROPNODECHARSSTRICT LOWERCASE UPPERCASE DIGITS ",-" static void check_node_name_chars(struct check *c, struct dt_info *dti, struct node *node) { - int n = strspn(node->name, c->data); + size_t n = strspn(node->name, c->data); if (n < strlen(node->name)) FAIL(c, dti, node, "Bad character '%c' in node name", node->name[n]); } -ERROR(node_name_chars, check_node_name_chars, PROPNODECHARS "@"); +ERROR(node_name_chars, check_node_name_chars, NODECHARS); static void check_node_name_chars_strict(struct check *c, struct dt_info *dti, struct node *node) @@ -330,6 +339,20 @@ static void check_node_name_format(struct check *c, struct dt_info *dti, } ERROR(node_name_format, check_node_name_format, NULL, &node_name_chars); +static void check_node_name_vs_property_name(struct check *c, + struct dt_info *dti, + struct node *node) +{ + if (!node->parent) + return; + + if (get_property(node->parent, node->name)) { + FAIL(c, dti, node, "node name and property name conflict"); + } +} +WARNING(node_name_vs_property_name, check_node_name_vs_property_name, + NULL, &node_name_chars); + static void check_unit_address_vs_reg(struct check *c, struct dt_info *dti, struct node *node) { @@ -363,14 +386,14 @@ static void check_property_name_chars(struct check *c, struct dt_info *dti, struct property *prop; for_each_property(node, prop) { - int n = strspn(prop->name, c->data); + size_t n = strspn(prop->name, c->data); if (n < strlen(prop->name)) FAIL_PROP(c, dti, node, prop, "Bad character '%c' in property name", prop->name[n]); } } -ERROR(property_name_chars, check_property_name_chars, PROPNODECHARS); +ERROR(property_name_chars, check_property_name_chars, PROPCHARS); static void check_property_name_chars_strict(struct check *c, struct dt_info *dti, @@ -380,7 +403,7 @@ static void check_property_name_chars_strict(struct check *c, for_each_property(node, prop) { const char *name = prop->name; - int n = strspn(name, c->data); + size_t n = strspn(name, c->data); if (n == strlen(prop->name)) continue; @@ -497,7 +520,7 @@ static cell_t check_phandle_prop(struct check *c, struct dt_info *dti, phandle = propval_cell(prop); - if ((phandle == 0) || (phandle == -1)) { + if (!phandle_is_valid(phandle)) { FAIL_PROP(c, dti, node, prop, "bad value (0x%x) in %s property", phandle, prop->name); return 0; @@ -556,7 +579,7 @@ static void check_name_properties(struct check *c, struct dt_info *dti, if (!prop) return; /* No name property, that's fine */ - if ((prop->val.len != node->basenamelen+1) + if ((prop->val.len != node->basenamelen + 1U) || (memcmp(prop->val.val, node->name, node->basenamelen) != 0)) { FAIL(c, dti, node, "\"name\" property is incorrect (\"%s\" instead" " of base node name)", prop->val.val); @@ -657,7 +680,6 @@ ERROR(omit_unused_nodes, fixup_omit_unused_nodes, NULL, &phandle_references, &pa */ WARNING_IF_NOT_CELL(address_cells_is_cell, "#address-cells"); WARNING_IF_NOT_CELL(size_cells_is_cell, "#size-cells"); -WARNING_IF_NOT_CELL(interrupt_cells_is_cell, "#interrupt-cells"); WARNING_IF_NOT_STRING(device_type_is_string, "device_type"); WARNING_IF_NOT_STRING(model_is_string, "model"); @@ -672,8 +694,7 @@ static void check_names_is_string_list(struct check *c, struct dt_info *dti, struct property *prop; for_each_property(node, prop) { - const char *s = strrchr(prop->name, '-'); - if (!s || !streq(s, "-names")) + if (!strends(prop->name, "-names")) continue; c->data = prop->name; @@ -753,7 +774,7 @@ static void check_reg_format(struct check *c, struct dt_info *dti, size_cells = node_size_cells(node->parent); entrylen = (addr_cells + size_cells) * sizeof(cell_t); - if (!entrylen || (prop->val.len % entrylen) != 0) + if (!is_multiple_of(prop->val.len, entrylen)) FAIL_PROP(c, dti, node, prop, "property has invalid length (%d bytes) " "(#address-cells == %d, #size-cells == %d)", prop->val.len, addr_cells, size_cells); @@ -794,7 +815,7 @@ static void check_ranges_format(struct check *c, struct dt_info *dti, "#size-cells (%d) differs from %s (%d)", ranges, c_size_cells, node->parent->fullpath, p_size_cells); - } else if ((prop->val.len % entrylen) != 0) { + } else if (!is_multiple_of(prop->val.len, entrylen)) { FAIL_PROP(c, dti, node, prop, "\"%s\" property has invalid length (%d bytes) " "(parent #address-cells == %d, child #address-cells == %d, " "#size-cells == %d)", ranges, prop->val.len, @@ -871,7 +892,7 @@ static void check_pci_device_bus_num(struct check *c, struct dt_info *dti, struc } else { cells = (cell_t *)prop->val.val; min_bus = fdt32_to_cpu(cells[0]); - max_bus = fdt32_to_cpu(cells[0]); + max_bus = fdt32_to_cpu(cells[1]); } if ((bus_num < min_bus) || (bus_num > max_bus)) FAIL_PROP(c, dti, node, prop, "PCI bus number %d out of range, expected (%d - %d)", @@ -891,10 +912,8 @@ static void check_pci_device_reg(struct check *c, struct dt_info *dti, struct no return; prop = get_property(node, "reg"); - if (!prop) { - FAIL(c, dti, node, "missing PCI reg property"); + if (!prop) return; - } cells = (cell_t *)prop->val.val; if (cells[1] || cells[2]) @@ -1363,15 +1382,15 @@ struct provider { }; static void check_property_phandle_args(struct check *c, - struct dt_info *dti, - struct node *node, - struct property *prop, - const struct provider *provider) + struct dt_info *dti, + struct node *node, + struct property *prop, + const struct provider *provider) { struct node *root = dti->dt; - int cell, cellsize = 0; + unsigned int cell, cellsize = 0; - if (prop->val.len % sizeof(cell_t)) { + if (!is_multiple_of(prop->val.len, sizeof(cell_t))) { FAIL_PROP(c, dti, node, prop, "property size (%d) is invalid, expected multiple of %zu", prop->val.len, sizeof(cell_t)); @@ -1381,14 +1400,15 @@ static void check_property_phandle_args(struct check *c, for (cell = 0; cell < prop->val.len / sizeof(cell_t); cell += cellsize + 1) { struct node *provider_node; struct property *cellprop; - int phandle; + cell_t phandle; + unsigned int expected; phandle = propval_cell_n(prop, cell); /* * Some bindings use a cell value 0 or -1 to skip over optional * entries when each index position has a specific definition. */ - if (phandle == 0 || phandle == -1) { + if (!phandle_is_valid(phandle)) { /* Give up if this is an overlay with external references */ if (dti->dtsflags & DTSF_PLUGIN) break; @@ -1431,10 +1451,12 @@ static void check_property_phandle_args(struct check *c, break; } - if (prop->val.len < ((cell + cellsize + 1) * sizeof(cell_t))) { + expected = (cell + cellsize + 1) * sizeof(cell_t); + if ((expected <= cell) || prop->val.len < expected) { FAIL_PROP(c, dti, node, prop, - "property size (%d) too small for cell size %d", + "property size (%d) too small for cell size %u", prop->val.len, cellsize); + break; } } } @@ -1454,7 +1476,8 @@ static void check_provider_cells_property(struct check *c, } #define WARNING_PROPERTY_PHANDLE_CELLS(nm, propname, cells_name, ...) \ static struct provider nm##_provider = { (propname), (cells_name), __VA_ARGS__ }; \ - WARNING(nm##_property, check_provider_cells_property, &nm##_provider, &phandle_references); + WARNING_IF_NOT_CELL(nm##_is_cell, cells_name); \ + WARNING(nm##_property, check_provider_cells_property, &nm##_provider, &nm##_is_cell, &phandle_references); WARNING_PROPERTY_PHANDLE_CELLS(clocks, "clocks", "#clock-cells"); WARNING_PROPERTY_PHANDLE_CELLS(cooling_device, "cooling-device", "#cooling-cells"); @@ -1475,24 +1498,17 @@ WARNING_PROPERTY_PHANDLE_CELLS(thermal_sensors, "thermal-sensors", "#thermal-sen static bool prop_is_gpio(struct property *prop) { - char *str; - /* * *-gpios and *-gpio can appear in property names, * so skip over any false matches (only one known ATM) */ - if (strstr(prop->name, "nr-gpio")) - return false; - - str = strrchr(prop->name, '-'); - if (str) - str++; - else - str = prop->name; - if (!(streq(str, "gpios") || streq(str, "gpio"))) + if (strends(prop->name, ",nr-gpios")) return false; - return true; + return strends(prop->name, "-gpios") || + streq(prop->name, "gpios") || + strends(prop->name, "-gpio") || + streq(prop->name, "gpio"); } static void check_gpios_property(struct check *c, @@ -1527,13 +1543,10 @@ static void check_deprecated_gpio_property(struct check *c, struct property *prop; for_each_property(node, prop) { - char *str; - if (!prop_is_gpio(prop)) continue; - str = strstr(prop->name, "gpio"); - if (!streq(str, "gpio")) + if (!strends(prop->name, "gpio")) continue; FAIL_PROP(c, dti, node, prop, @@ -1563,21 +1576,106 @@ static void check_interrupt_provider(struct check *c, struct node *node) { struct property *prop; + bool irq_provider = node_is_interrupt_provider(node); - if (!node_is_interrupt_provider(node)) + prop = get_property(node, "#interrupt-cells"); + if (irq_provider && !prop) { + FAIL(c, dti, node, + "Missing '#interrupt-cells' in interrupt provider"); return; + } - prop = get_property(node, "#interrupt-cells"); - if (!prop) + if (!irq_provider && prop) { FAIL(c, dti, node, - "Missing #interrupt-cells in interrupt provider"); + "'#interrupt-cells' found, but node is not an interrupt provider"); + return; + } +} +WARNING(interrupt_provider, check_interrupt_provider, NULL, &interrupts_extended_is_cell); - prop = get_property(node, "#address-cells"); - if (!prop) +static void check_interrupt_map(struct check *c, + struct dt_info *dti, + struct node *node) +{ + struct node *root = dti->dt; + struct property *prop, *irq_map_prop; + size_t cellsize, cell, map_cells; + + irq_map_prop = get_property(node, "interrupt-map"); + if (!irq_map_prop) + return; + + if (node->addr_cells < 0) { FAIL(c, dti, node, - "Missing #address-cells in interrupt provider"); + "Missing '#address-cells' in interrupt-map provider"); + return; + } + cellsize = node_addr_cells(node); + cellsize += propval_cell(get_property(node, "#interrupt-cells")); + + prop = get_property(node, "interrupt-map-mask"); + if (prop && (prop->val.len != (cellsize * sizeof(cell_t)))) + FAIL_PROP(c, dti, node, prop, + "property size (%d) is invalid, expected %zu", + prop->val.len, cellsize * sizeof(cell_t)); + + if (!is_multiple_of(irq_map_prop->val.len, sizeof(cell_t))) { + FAIL_PROP(c, dti, node, irq_map_prop, + "property size (%d) is invalid, expected multiple of %zu", + irq_map_prop->val.len, sizeof(cell_t)); + return; + } + + map_cells = irq_map_prop->val.len / sizeof(cell_t); + for (cell = 0; cell < map_cells; ) { + struct node *provider_node; + struct property *cellprop; + int phandle; + size_t parent_cellsize; + + if ((cell + cellsize) >= map_cells) { + FAIL_PROP(c, dti, node, irq_map_prop, + "property size (%d) too small, expected > %zu", + irq_map_prop->val.len, (cell + cellsize) * sizeof(cell_t)); + break; + } + cell += cellsize; + + phandle = propval_cell_n(irq_map_prop, cell); + if (!phandle_is_valid(phandle)) { + /* Give up if this is an overlay with external references */ + if (!(dti->dtsflags & DTSF_PLUGIN)) + FAIL_PROP(c, dti, node, irq_map_prop, + "Cell %zu is not a phandle(%d)", + cell, phandle); + break; + } + + provider_node = get_node_by_phandle(root, phandle); + if (!provider_node) { + FAIL_PROP(c, dti, node, irq_map_prop, + "Could not get phandle(%d) node for (cell %zu)", + phandle, cell); + break; + } + + cellprop = get_property(provider_node, "#interrupt-cells"); + if (cellprop) { + parent_cellsize = propval_cell(cellprop); + } else { + FAIL(c, dti, node, "Missing property '#interrupt-cells' in node %s or bad phandle (referred from interrupt-map[%zu])", + provider_node->fullpath, cell); + break; + } + + cellprop = get_property(provider_node, "#address-cells"); + if (cellprop) + parent_cellsize += propval_cell(cellprop); + + cell += 1 + parent_cellsize; + } } -WARNING(interrupt_provider, check_interrupt_provider, NULL); +WARNING(interrupt_map, check_interrupt_map, NULL, &phandle_references, &addr_size_cells, &interrupt_provider); static void check_interrupts_property(struct check *c, struct dt_info *dti, @@ -1586,13 +1684,13 @@ static void check_interrupts_property(struct check *c, struct node *root = dti->dt; struct node *irq_node = NULL, *parent = node; struct property *irq_prop, *prop = NULL; - int irq_cells, phandle; + cell_t irq_cells, phandle; irq_prop = get_property(node, "interrupts"); if (!irq_prop) return; - if (irq_prop->val.len % sizeof(cell_t)) + if (!is_multiple_of(irq_prop->val.len, sizeof(cell_t))) FAIL_PROP(c, dti, node, irq_prop, "size (%d) is invalid, expected multiple of %zu", irq_prop->val.len, sizeof(cell_t)); @@ -1605,7 +1703,7 @@ static void check_interrupts_property(struct check *c, prop = get_property(parent, "interrupt-parent"); if (prop) { phandle = propval_cell(prop); - if ((phandle == 0) || (phandle == -1)) { + if (!phandle_is_valid(phandle)) { /* Give up if this is an overlay with * external references */ if (dti->dtsflags & DTSF_PLUGIN) @@ -1641,7 +1739,7 @@ static void check_interrupts_property(struct check *c, } irq_cells = propval_cell(prop); - if (irq_prop->val.len % (irq_cells * sizeof(cell_t))) { + if (!is_multiple_of(irq_prop->val.len, irq_cells * sizeof(cell_t))) { FAIL_PROP(c, dti, node, prop, "size is (%d), expected multiple of %d", irq_prop->val.len, (int)(irq_cells * sizeof(cell_t))); @@ -1752,7 +1850,7 @@ WARNING(graph_port, check_graph_port, NULL, &graph_nodes); static struct node *get_remote_endpoint(struct check *c, struct dt_info *dti, struct node *endpoint) { - int phandle; + cell_t phandle; struct node *node; struct property *prop; @@ -1762,7 +1860,7 @@ static struct node *get_remote_endpoint(struct check *c, struct dt_info *dti, phandle = propval_cell(prop); /* Give up if this is an overlay with external references */ - if (phandle == 0 || phandle == -1) + if (!phandle_is_valid(phandle)) return NULL; node = get_node_by_phandle(dti->dt, phandle); @@ -1798,7 +1896,7 @@ WARNING(graph_endpoint, check_graph_endpoint, NULL, &graph_nodes); static struct check *check_table[] = { &duplicate_node_names, &duplicate_property_names, &node_name_chars, &node_name_format, &property_name_chars, - &name_is_string, &name_properties, + &name_is_string, &name_properties, &node_name_vs_property_name, &duplicate_label, @@ -1806,7 +1904,7 @@ static struct check *check_table[] = { &phandle_references, &path_references, &omit_unused_nodes, - &address_cells_is_cell, &size_cells_is_cell, &interrupt_cells_is_cell, + &address_cells_is_cell, &size_cells_is_cell, &device_type_is_string, &model_is_string, &status_is_string, &label_is_string, @@ -1841,26 +1939,43 @@ static struct check *check_table[] = { &chosen_node_is_root, &chosen_node_bootargs, &chosen_node_stdout_path, &clocks_property, + &clocks_is_cell, &cooling_device_property, + &cooling_device_is_cell, &dmas_property, + &dmas_is_cell, &hwlocks_property, + &hwlocks_is_cell, &interrupts_extended_property, + &interrupts_extended_is_cell, &io_channels_property, + &io_channels_is_cell, &iommus_property, + &iommus_is_cell, &mboxes_property, + &mboxes_is_cell, &msi_parent_property, + &msi_parent_is_cell, &mux_controls_property, + &mux_controls_is_cell, &phys_property, + &phys_is_cell, &power_domains_property, + &power_domains_is_cell, &pwms_property, + &pwms_is_cell, &resets_property, + &resets_is_cell, &sound_dai_property, + &sound_dai_is_cell, &thermal_sensors_property, + &thermal_sensors_is_cell, &deprecated_gpio_property, &gpios_property, &interrupts_property, &interrupt_provider, + &interrupt_map, &alias_paths, @@ -1884,7 +1999,7 @@ static void enable_warning_error(struct check *c, bool warn, bool error) static void disable_warning_error(struct check *c, bool warn, bool error) { - int i; + unsigned int i; /* Lowering level, also lower it for things this is the prereq * for */ @@ -1905,7 +2020,7 @@ static void disable_warning_error(struct check *c, bool warn, bool error) void parse_checks_option(bool warn, bool error, const char *arg) { - int i; + unsigned int i; const char *name = arg; bool enable = true; @@ -1932,7 +2047,7 @@ void parse_checks_option(bool warn, bool error, const char *arg) void process_checks(bool force, struct dt_info *dti) { - int i; + unsigned int i; int error = 0; for (i = 0; i < ARRAY_SIZE(check_table); i++) { diff --git a/convert-dtsv0-lexer.l b/convert-dtsv0-lexer.l index f52e8a1..7a66f57 100644 --- a/convert-dtsv0-lexer.l +++ b/convert-dtsv0-lexer.l @@ -94,7 +94,7 @@ static const struct { <INITIAL>[0-9a-fA-F]+ { unsigned long long val; int obase = 16, width = 0; - int i; + unsigned int i; val = strtoull(yytext, NULL, cbase); @@ -21,10 +21,10 @@ void data_free(struct data d) free(d.val); } -struct data data_grow_for(struct data d, int xlen) +struct data data_grow_for(struct data d, unsigned int xlen) { struct data nd; - int newsize; + unsigned int newsize; if (xlen == 0) return d; @@ -84,7 +84,7 @@ struct data data_copy_file(FILE *f, size_t maxlen) while (!feof(f) && (d.len < maxlen)) { size_t chunksize, ret; - if (maxlen == -1) + if (maxlen == (size_t)-1) chunksize = 4096; else chunksize = maxlen - d.len; diff --git a/dtc-lexer.l b/dtc-lexer.l index f0faa28..758ce5c 100644 --- a/dtc-lexer.l +++ b/dtc-lexer.l @@ -57,7 +57,7 @@ static void PRINTF(1, 2) lexical_error(const char *fmt, ...); push_input_file(name); } -<*>^"#"(line)?[ \t]+[0-9]+[ \t]+{STRING}([ \t]+[0-9]+)? { +<*>^"#"(line)?[ \t]+[0-9]+[ \t]+{STRING}([ \t]+[0-9]+)* { char *line, *fnstart, *fnend; struct data fn; /* skip text before line # */ @@ -200,7 +200,7 @@ static void PRINTF(1, 2) lexical_error(const char *fmt, ...); return DT_LABEL_REF; } -<*>"&{/"{PATHCHAR}*\} { /* new-style path reference */ +<*>"&{"{PATHCHAR}*\} { /* new-style path reference */ yytext[yyleng-1] = '\0'; DPRINT("Ref: %s\n", yytext+2); yylval.labelref = xstrdup(yytext+2); diff --git a/dtc-parser.y b/dtc-parser.y index cf0e361..b4acf7f 100644 --- a/dtc-parser.y +++ b/dtc-parser.y @@ -23,6 +23,12 @@ extern void yyerror(char const *s); extern struct dt_info *parser_output; extern bool treesource_error; + +static bool is_ref_relative(const char *ref) +{ + return ref[0] != '/' && strchr(&ref[1], '/'); +} + %} %union { @@ -169,6 +175,8 @@ devicetree: */ if (!($<flags>-1 & DTSF_PLUGIN)) ERROR(&@2, "Label or path %s not found", $1); + else if (is_ref_relative($1)) + ERROR(&@2, "Label-relative reference %s not supported in plugin", $1); $$ = add_orphan_node( name_node(build_node(NULL, NULL, NULL), ""), @@ -178,6 +186,9 @@ devicetree: { struct node *target = get_node_by_ref($1, $3); + if (($<flags>-1 & DTSF_PLUGIN) && is_ref_relative($3)) + ERROR(&@2, "Label-relative reference %s not supported in plugin", $3); + if (target) { add_label(&target->labels, $2); merge_nodes(target, $4); @@ -193,6 +204,8 @@ devicetree: * so $-1 is what we want (plugindecl) */ if ($<flags>-1 & DTSF_PLUGIN) { + if (is_ref_relative($2)) + ERROR(&@2, "Label-relative reference %s not supported in plugin", $2); add_orphan_node($1, $3, $2); } else { struct node *target = get_node_by_ref($1, $2); @@ -481,8 +494,8 @@ integer_rela: ; integer_shift: - integer_shift DT_LSHIFT integer_add { $$ = $1 << $3; } - | integer_shift DT_RSHIFT integer_add { $$ = $1 >> $3; } + integer_shift DT_LSHIFT integer_add { $$ = ($3 < 64) ? ($1 << $3) : 0; } + | integer_shift DT_RSHIFT integer_add { $$ = ($3 < 64) ? ($1 >> $3) : 0; } | integer_add ; @@ -12,7 +12,7 @@ * Command line options */ int quiet; /* Level of quietness */ -int reservenum; /* Number of memory reservation slots */ +unsigned int reservenum;/* Number of memory reservation slots */ int minsize; /* Minimum blob size */ int padsize; /* Additional padding to blob */ int alignsize; /* Additional padding to blob accroding to the alignsize */ @@ -122,6 +122,8 @@ static const char *guess_type_by_name(const char *fname, const char *fallback) return "dts"; if (!strcasecmp(s, ".yaml")) return "yaml"; + if (!strcasecmp(s, ".dtbo")) + return "dtb"; if (!strcasecmp(s, ".dtb")) return "dtb"; return fallback; @@ -195,7 +197,7 @@ int main(int argc, char *argv[]) depname = optarg; break; case 'R': - reservenum = strtol(optarg, NULL, 0); + reservenum = strtoul(optarg, NULL, 0); break; case 'S': minsize = strtol(optarg, NULL, 0); @@ -35,7 +35,7 @@ * Command line options */ extern int quiet; /* Level of quietness */ -extern int reservenum; /* Number of memory reservation slots */ +extern unsigned int reservenum; /* Number of memory reservation slots */ extern int minsize; /* Minimum blob size */ extern int padsize; /* Additional padding to blob */ extern int alignsize; /* Additional padding to blob accroding to the alignsize */ @@ -51,6 +51,11 @@ extern int annotate; /* annotate .dts with input source location */ typedef uint32_t cell_t; +static inline bool phandle_is_valid(cell_t phandle) +{ + return phandle != 0 && phandle != ~0U; +} + static inline uint16_t dtb_ld16(const void *p) { const uint8_t *bp = (const uint8_t *)p; @@ -86,6 +91,16 @@ static inline uint64_t dtb_ld64(const void *p) #define streq(a, b) (strcmp((a), (b)) == 0) #define strstarts(s, prefix) (strncmp((s), (prefix), strlen(prefix)) == 0) #define strprefixeq(a, n, b) (strlen(b) == (n) && (memcmp(a, b, n) == 0)) +static inline bool strends(const char *str, const char *suffix) +{ + unsigned int len, suffix_len; + + len = strlen(str); + suffix_len = strlen(suffix); + if (len < suffix_len) + return false; + return streq(str + len - suffix_len, suffix); +} #define ALIGN(x, a) (((x) + (a) - 1) & ~((a) - 1)) @@ -101,17 +116,23 @@ enum markertype { TYPE_UINT64, TYPE_STRING, }; + +static inline bool is_type_marker(enum markertype type) +{ + return type >= TYPE_UINT8; +} + extern const char *markername(enum markertype markertype); struct marker { enum markertype type; - int offset; + unsigned int offset; char *ref; struct marker *next; }; struct data { - int len; + unsigned int len; char *val; struct marker *markers; }; @@ -125,11 +146,26 @@ struct data { for_each_marker(m) \ if ((m)->type == (t)) -size_t type_marker_length(struct marker *m); +static inline struct marker *next_type_marker(struct marker *m) +{ + for_each_marker(m) + if (is_type_marker(m->type)) + break; + return m; +} + +static inline size_t type_marker_length(struct marker *m) +{ + struct marker *next = next_type_marker(m->next); + + if (next) + return next->offset - m->offset; + return 0; +} void data_free(struct data d); -struct data data_grow_for(struct data d, int xlen); +struct data data_grow_for(struct data d, unsigned int xlen); struct data data_copy_mem(const char *mem, int len); struct data data_copy_escape_string(const char *s, int len); @@ -253,7 +289,7 @@ void append_to_property(struct node *node, const char *get_unitname(struct node *node); struct property *get_property(struct node *node, const char *propname); cell_t propval_cell(struct property *prop); -cell_t propval_cell_n(struct property *prop, int n); +cell_t propval_cell_n(struct property *prop, unsigned int n); struct property *get_property_by_label(struct node *tree, const char *label, struct node **node); struct marker *get_marker_label(struct node *tree, const char *label, @@ -18,10 +18,10 @@ #include "util.h" #define FDT_MAGIC_SIZE 4 -#define MAX_VERSION 17 +#define MAX_VERSION 17U #define ALIGN(x, a) (((x) + ((a) - 1)) & ~((a) - 1)) -#define PALIGN(p, a) ((void *)(ALIGN((unsigned long)(p), (a)))) +#define PALIGN(p, a) ((void *)(ALIGN((uintptr_t)(p), (a)))) #define GET_CELL(p) (p += 4, *((const fdt32_t *)(p-4))) static const char *tagname(uint32_t tag) @@ -163,7 +163,7 @@ static const char * const usage_opts_help[] = { USAGE_COMMON_OPTS_HELP }; -static bool valid_header(char *p, off_t len) +static bool valid_header(char *p, size_t len) { if (len < sizeof(struct fdt_header) || fdt_magic(p) != FDT_MAGIC || @@ -217,7 +217,7 @@ int main(int argc, char *argv[]) char *p = buf; char *endp = buf + len; - fdt_set_magic(smagic, FDT_MAGIC); + fdt32_st(smagic, FDT_MAGIC); /* poor man's memmem */ while ((endp - p) >= FDT_MAGIC_SIZE) { @@ -235,7 +235,7 @@ int main(int argc, char *argv[]) } ++p; } - if (!p || endp - p < sizeof(struct fdt_header)) + if (!p || (size_t)(endp - p) < sizeof(struct fdt_header)) die("%s: could not locate fdt magic\n", file); printf("%s: found fdt at offset %#tx\n", file, p - buf); buf = p; @@ -62,8 +62,14 @@ static int show_cell_list(struct display_info *disp, const char *data, int len, for (i = 0; i < len; i += size, p += size) { if (i) printf(" "); - value = size == 4 ? fdt32_ld((const fdt32_t *)p) : - size == 2 ? (*p << 8) | p[1] : *p; + switch (size) { + case 4: value = fdt32_ld((const fdt32_t *)p); break; + case 2: value = fdt16_ld((const fdt16_t *)p); break; + case 1: + default: + value = *p; + break; + } printf(fmt, value); } @@ -91,6 +97,11 @@ static int show_data(struct display_info *disp, const char *data, int len) if (len == 0) return 0; + if (disp->type == 'r') { + fwrite(data, 1, len, stdout); + return 0; + } + is_string = (disp->type) == 's' || (!disp->type && util_is_printable_string(data, len)); if (is_string) { @@ -433,6 +433,8 @@ int main(int argc, char *argv[]) if (utilfdt_decode_type(optarg, &disp.type, &disp.size)) usage("Invalid type string"); + if (disp.type == 'r') + usage("Unsupported raw data type"); break; case 'v': @@ -124,7 +124,8 @@ static void asm_emit_cell(void *e, cell_t val) { FILE *f = e; - fprintf(f, "\t.byte 0x%02x; .byte 0x%02x; .byte 0x%02x; .byte 0x%02x\n", + fprintf(f, "\t.byte\t0x%02x\n" "\t.byte\t0x%02x\n" + "\t.byte\t0x%02x\n" "\t.byte\t0x%02x\n", (val >> 24) & 0xff, (val >> 16) & 0xff, (val >> 8) & 0xff, val & 0xff); } @@ -134,9 +135,9 @@ static void asm_emit_string(void *e, const char *str, int len) FILE *f = e; if (len != 0) - fprintf(f, "\t.string\t\"%.*s\"\n", len, str); + fprintf(f, "\t.asciz\t\"%.*s\"\n", len, str); else - fprintf(f, "\t.string\t\"%s\"\n", str); + fprintf(f, "\t.asciz\t\"%s\"\n", str); } static void asm_emit_align(void *e, int a) @@ -149,7 +150,7 @@ static void asm_emit_align(void *e, int a) static void asm_emit_data(void *e, struct data d) { FILE *f = e; - int off = 0; + unsigned int off = 0; struct marker *m = d.markers; for_each_marker_of_type(m, LABEL) @@ -219,7 +220,7 @@ static struct emitter asm_emitter = { static int stringtable_insert(struct data *d, const char *str) { - int i; + unsigned int i; /* FIXME: do this more efficiently? */ @@ -295,7 +296,7 @@ static struct data flatten_reserve_list(struct reserve_info *reservelist, { struct reserve_info *re; struct data d = empty_data; - int j; + unsigned int j; for (re = reservelist; re; re = re->next) { d = data_append_re(d, re->address, re->size); @@ -345,7 +346,7 @@ static void make_fdt_header(struct fdt_header *fdt, void dt_to_blob(FILE *f, struct dt_info *dti, int version) { struct version_info *vi = NULL; - int i; + unsigned int i; struct data blob = empty_data; struct data reservebuf = empty_data; struct data dtbuf = empty_data; @@ -438,7 +439,7 @@ static void dump_stringtable_asm(FILE *f, struct data strbuf) while (p < (strbuf.val + strbuf.len)) { len = strlen(p); - fprintf(f, "\t.string \"%s\"\n", p); + fprintf(f, "\t.asciz \"%s\"\n", p); p += len+1; } } @@ -446,7 +447,7 @@ static void dump_stringtable_asm(FILE *f, struct data strbuf) void dt_to_asm(FILE *f, struct dt_info *dti, int version) { struct version_info *vi = NULL; - int i; + unsigned int i; struct data strbuf = empty_data; struct reserve_info *re; const char *symprefix = "dt"; diff --git a/fuzzing/Android.bp b/fuzzing/Android.bp index ddda130..857c611 100644 --- a/fuzzing/Android.bp +++ b/fuzzing/Android.bp @@ -6,10 +6,17 @@ package { cc_fuzz { name: "libfdt_fuzzer", srcs: [ - "libfdt_fuzzer.cpp", + "libfdt_fuzzer.c", ], static_libs: [ "libfdt", ], + corpus: ["corpus/*"], + fuzz_config: { + cc: [ + "ptosi@google.com", + ], + }, host_supported: true, } + diff --git a/fuzzing/corpus/crash-a5b94d95681291f3057eea7f0233c8f1529b2f59 b/fuzzing/corpus/crash-a5b94d95681291f3057eea7f0233c8f1529b2f59 Binary files differnew file mode 100644 index 0000000..dbab42e --- /dev/null +++ b/fuzzing/corpus/crash-a5b94d95681291f3057eea7f0233c8f1529b2f59 diff --git a/fuzzing/corpus/hardy-octopus b/fuzzing/corpus/hardy-octopus Binary files differnew file mode 100644 index 0000000..81615e9 --- /dev/null +++ b/fuzzing/corpus/hardy-octopus diff --git a/fuzzing/corpus/header-truncated b/fuzzing/corpus/header-truncated Binary files differnew file mode 100644 index 0000000..1db29d8 --- /dev/null +++ b/fuzzing/corpus/header-truncated diff --git a/fuzzing/corpus/header-v-1 b/fuzzing/corpus/header-v-1 Binary files differnew file mode 100644 index 0000000..a773d07 --- /dev/null +++ b/fuzzing/corpus/header-v-1 diff --git a/fuzzing/corpus/header-v0 b/fuzzing/corpus/header-v0 Binary files differnew file mode 100644 index 0000000..f22ec6a --- /dev/null +++ b/fuzzing/corpus/header-v0 diff --git a/fuzzing/corpus/meson-g12a-sei510-android.dtb b/fuzzing/corpus/meson-g12a-sei510-android.dtb Binary files differnew file mode 100644 index 0000000..317175d --- /dev/null +++ b/fuzzing/corpus/meson-g12a-sei510-android.dtb diff --git a/fuzzing/corpus/oob_by_one b/fuzzing/corpus/oob_by_one Binary files differnew file mode 100644 index 0000000..216523c --- /dev/null +++ b/fuzzing/corpus/oob_by_one diff --git a/fuzzing/corpus/quirks.dtb b/fuzzing/corpus/quirks.dtb Binary files differnew file mode 100644 index 0000000..676024a --- /dev/null +++ b/fuzzing/corpus/quirks.dtb diff --git a/fuzzing/libfdt_fuzzer.c b/fuzzing/libfdt_fuzzer.c new file mode 100644 index 0000000..b271714 --- /dev/null +++ b/fuzzing/libfdt_fuzzer.c @@ -0,0 +1,170 @@ +/* + * Copyright (C) 2022 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +/* Ensure assert() catches logical errors during fuzzing */ +#ifdef NDEBUG +#undef NDEBUG +#endif + +#include <inttypes.h> +#include <assert.h> +#include <stdbool.h> +#include <stdint.h> +#include <stdio.h> +#include <stdlib.h> +#include <ctype.h> + +#include <sanitizer/asan_interface.h> +#include <sanitizer/msan_interface.h> + +#include "libfdt.h" +#include "libfdt_env.h" + +/* check memory region is valid, for the purpose of tooling such as asan */ +static void check_mem(const void *mem, size_t len) { + + assert(mem); + +#if __has_feature(memory_sanitizer) + /* dumps if check fails */ + __msan_check_mem_is_initialized((void *)mem, len); +#endif + +#if __has_feature(address_sanitizer) || defined(__SANITIZE_ADDRESS__) + assert(!__asan_region_is_poisoned((void *)mem, len)); +#else + const volatile uint8_t *mem8 = mem; + + /* Read each byte of memory for instrumentation */ + for(size_t i = 0; i < len; i++) { + (void)mem8[i]; + } +#endif +} + +static bool phandle_is_valid(uint32_t phandle) { + return phandle != 0 && phandle != UINT32_MAX; +} + +static void walk_node_properties(const void *device_tree, int node) { + int property, len = 0; + + fdt_for_each_property_offset(property, device_tree, node) { + const struct fdt_property *prop = fdt_get_property_by_offset(device_tree, + property, &len); + if (!prop) + continue; + check_mem(prop->data, fdt32_to_cpu(prop->len)); + + const char *prop_name = fdt_string(device_tree, prop->nameoff); + if (prop_name != NULL) { + check_mem(prop_name, strlen(prop_name)); + } + } +} + + +static void walk_device_tree(const void *device_tree, int parent_node) { + int len = 0; + const char *node_name = fdt_get_name(device_tree, parent_node, &len); + if (node_name != NULL) { + check_mem(node_name, len); + } + + uint32_t phandle = fdt_get_phandle(device_tree, parent_node); + if (phandle_is_valid(phandle)) { + int node = fdt_node_offset_by_phandle(device_tree, phandle); + assert(node >= 0); // it should at least find parent_node + } + + char path_buf[64]; + if(fdt_get_path(device_tree, parent_node, path_buf, sizeof(path_buf)) == 0) { + fdt_path_offset(device_tree, path_buf); + } + + fdt_parent_offset(device_tree, parent_node); + + // Exercise sub-node search string functions + fdt_subnode_offset(device_tree, parent_node, "a"); + fdt_get_property(device_tree, parent_node, "reg", &len); + + // Check for a stringlist node called 'stringlist' (added to corpus) + const int sl_count = fdt_stringlist_count(device_tree, + parent_node, "stringlist"); + if (sl_count > 0) { + for (int i = 0; i < sl_count; i++) { + fdt_stringlist_get(device_tree, parent_node, "stringlist", i, &len); + } + + fdt_stringlist_search(device_tree, parent_node, "stringlist", "a"); + } + + walk_node_properties(device_tree, parent_node); + + // recursively walk the node's children + for (int node = fdt_first_subnode(device_tree, parent_node); node >= 0; + node = fdt_next_subnode(device_tree, node)) { + walk_device_tree(device_tree, node); + } +} + + +static void walk_mem_rsv(const void *device_tree) { + const int n = fdt_num_mem_rsv(device_tree); + uint64_t address, size; + + for (int i = 0; i < n; i++) { + fdt_get_mem_rsv(device_tree, i, &address, &size); + } +} + + +// Information on device tree is available in external/dtc/Documentation/ +// folder. +int LLVMFuzzerTestOneInput(const uint8_t *data, size_t size) { + int rc; + + // Non-zero return values are reserved for future use. + if (size < FDT_V17_SIZE) return 0; + + // Produce coverage of checking function + rc = fdt_check_full(data, size); + fdt_strerror(rc); + + // Don't continue if the library rejected the input + if (rc != 0) return 0; + + // Cover reading functions + walk_device_tree(data, /* parent_node */ 0); + walk_mem_rsv(data); + + // Cover phandle functions + uint32_t phandle; + fdt_generate_phandle(data, &phandle); + + // Try and get a path by alias + fdt_path_offset(data, "a"); + + // Try to get an alias + fdt_get_alias(data, "a"); + + // Exercise common search functions + fdt_node_offset_by_compatible(data, 0, "a"); + fdt_node_offset_by_prop_value(data, 0, "x", "42", 3); + + return 0; +} + diff --git a/fuzzing/libfdt_fuzzer.cpp b/fuzzing/libfdt_fuzzer.cpp deleted file mode 100644 index 4a0b1fc..0000000 --- a/fuzzing/libfdt_fuzzer.cpp +++ /dev/null @@ -1,42 +0,0 @@ -#include <assert.h> -#include <stdint.h> -#include <stdio.h> -#include <stdlib.h> - -#include "libfdt.h" -#include "libfdt_env.h" - -void walk_device_tree(const void *device_tree, int parent_node) { - int len = 0; - const char *node_name = fdt_get_name(device_tree, parent_node, &len); - if (node_name != NULL) { - // avoid clang complaining about unused variable node_name and force - // ASan to validate string pointer in strlen call. - assert(strlen(node_name) == len); - } - - uint32_t phandle = fdt_get_phandle(device_tree, parent_node); - if (phandle != 0) { - assert(parent_node == fdt_node_offset_by_phandle(device_tree, phandle)); - } - - // recursively walk the node's children - for (int node = fdt_first_subnode(device_tree, parent_node); node >= 0; - node = fdt_next_subnode(device_tree, node)) { - walk_device_tree(device_tree, node); - } -} - -// Information on device tree is available in external/dtc/Documentation/ -// folder. -extern "C" int LLVMFuzzerTestOneInput(const uint8_t *data, size_t size) { - // Non-zero return values are reserved for future use. - if (size < FDT_V17_SIZE) return 0; - - if (fdt_check_header(data) != 0) return 0; - - int root_node_offset = 0; - walk_device_tree(data, root_node_offset); - - return 0; -}
\ No newline at end of file diff --git a/libfdt/Android.bp b/libfdt/Android.bp index 8f729b4..8f4bdfd 100644 --- a/libfdt/Android.bp +++ b/libfdt/Android.bp @@ -1,11 +1,7 @@ package { // See: http://go/android-license-faq - // A large-scale-change added 'default_applicable_licenses' to import - // all of the 'license_kinds' from "external_dtc_license" - // to get the below license kinds: - // SPDX-license-identifier-BSD // SPDX-license-identifier-BSD-2-Clause - default_applicable_licenses: ["external_dtc_license"], + default_applicable_licenses: ["external_dtc_libfdt_license"], } cc_library { diff --git a/libfdt/acpi.c b/libfdt/acpi.c index ba51734..5869726 100644 --- a/libfdt/acpi.c +++ b/libfdt/acpi.c @@ -31,13 +31,10 @@ #include "libacpi.h" uint8_t acpi_csum(const void *base, int n) { - uint8_t *p; - uint8_t sum; + const uint8_t *p = base; + uint8_t sum = 0; int bytesDone; - p = (uint8_t*)base; - - sum = 0; for (bytesDone = 0; bytesDone < n; bytesDone++) { sum += *p; p++; diff --git a/libfdt/fdt.c b/libfdt/fdt.c index 17ac7d6..c17cad5 100644 --- a/libfdt/fdt.c +++ b/libfdt/fdt.c @@ -22,6 +22,10 @@ int32_t fdt_ro_probe_(const void *fdt) if (can_assume(VALID_DTB)) return totalsize; + /* The device tree must be at an 8-byte aligned address */ + if ((uintptr_t)fdt & 7) + return -FDT_ERR_ALIGNMENT; + if (fdt_magic(fdt) == FDT_MAGIC) { /* Complete tree */ if (!can_assume(LATEST)) { @@ -86,6 +90,10 @@ int fdt_check_header(const void *fdt) { size_t hdrsize; + /* The device tree must be at an 8-byte aligned address */ + if ((uintptr_t)fdt & 7) + return -FDT_ERR_ALIGNMENT; + if (fdt_magic(fdt) != FDT_MAGIC) return -FDT_ERR_BADMAGIC; if (!can_assume(LATEST)) { @@ -219,10 +227,11 @@ uint32_t fdt_next_tag(const void *fdt, int startoffset, int *nextoffset) int fdt_check_node_offset_(const void *fdt, int offset) { - if (can_assume(VALID_INPUT)) - return offset; - if ((offset < 0) || (offset % FDT_TAGSIZE) - || (fdt_next_tag(fdt, offset, &offset) != FDT_BEGIN_NODE)) + if (!can_assume(VALID_INPUT) + && ((offset < 0) || (offset % FDT_TAGSIZE))) + return -FDT_ERR_BADOFFSET; + + if (fdt_next_tag(fdt, offset, &offset) != FDT_BEGIN_NODE) return -FDT_ERR_BADOFFSET; return offset; @@ -230,8 +239,11 @@ int fdt_check_node_offset_(const void *fdt, int offset) int fdt_check_prop_offset_(const void *fdt, int offset) { - if ((offset < 0) || (offset % FDT_TAGSIZE) - || (fdt_next_tag(fdt, offset, &offset) != FDT_PROP)) + if (!can_assume(VALID_INPUT) + && ((offset < 0) || (offset % FDT_TAGSIZE))) + return -FDT_ERR_BADOFFSET; + + if (fdt_next_tag(fdt, offset, &offset) != FDT_PROP) return -FDT_ERR_BADOFFSET; return offset; @@ -319,9 +331,12 @@ const char *fdt_find_string_(const char *strtab, int tabsize, const char *s) int fdt_move(const void *fdt, void *buf, int bufsize) { + if (!can_assume(VALID_INPUT) && bufsize < 0) + return -FDT_ERR_NOSPACE; + FDT_RO_PROBE(fdt); - if (fdt_totalsize(fdt) > bufsize) + if (fdt_totalsize(fdt) > (unsigned int)bufsize) return -FDT_ERR_NOSPACE; memmove(buf, fdt, fdt_totalsize(fdt)); diff --git a/libfdt/fdt_addresses.c b/libfdt/fdt_addresses.c index 9a82cd0..c40ba09 100644 --- a/libfdt/fdt_addresses.c +++ b/libfdt/fdt_addresses.c @@ -73,7 +73,7 @@ int fdt_appendprop_addrrange(void *fdt, int parent, int nodeoffset, /* check validity of address */ prop = data; if (addr_cells == 1) { - if ((addr > UINT32_MAX) || ((UINT32_MAX + 1 - addr) < size)) + if ((addr > UINT32_MAX) || (((uint64_t) UINT32_MAX + 1 - addr) < size)) return -FDT_ERR_BADVALUE; fdt32_st(prop, (uint32_t)addr); diff --git a/libfdt/fdt_check.c b/libfdt/fdt_check.c index 7f6a96c..71390ee 100644 --- a/libfdt/fdt_check.c +++ b/libfdt/fdt_check.c @@ -19,9 +19,12 @@ int fdt_check_full(const void *fdt, size_t bufsize) unsigned int depth = 0; const void *prop; const char *propname; + bool expect_end = false; if (bufsize < FDT_V1_SIZE) return -FDT_ERR_TRUNCATED; + if (bufsize < fdt_header_size(fdt)) + return -FDT_ERR_TRUNCATED; err = fdt_check_header(fdt); if (err != 0) return err; @@ -39,6 +42,10 @@ int fdt_check_full(const void *fdt, size_t bufsize) if (nextoffset < 0) return nextoffset; + /* If we see two root nodes, something is wrong */ + if (expect_end && tag != FDT_END) + return -FDT_ERR_BADSTRUCTURE; + switch (tag) { case FDT_NOP: break; @@ -52,12 +59,24 @@ int fdt_check_full(const void *fdt, size_t bufsize) depth++; if (depth > INT_MAX) return -FDT_ERR_BADSTRUCTURE; + + /* The root node must have an empty name */ + if (depth == 1) { + const char *name; + int len; + + name = fdt_get_name(fdt, offset, &len); + if (!name || *name || len) + return -FDT_ERR_BADSTRUCTURE; + } break; case FDT_END_NODE: if (depth == 0) return -FDT_ERR_BADSTRUCTURE; depth--; + if (depth == 0) + expect_end = true; break; case FDT_PROP: diff --git a/libfdt/fdt_overlay.c b/libfdt/fdt_overlay.c index b310e49..5c0c398 100644 --- a/libfdt/fdt_overlay.c +++ b/libfdt/fdt_overlay.c @@ -40,37 +40,22 @@ static uint32_t overlay_get_target_phandle(const void *fdto, int fragment) return fdt32_to_cpu(*val); } -/** - * overlay_get_target - retrieves the offset of a fragment's target - * @fdt: Base device tree blob - * @fdto: Device tree overlay blob - * @fragment: node offset of the fragment in the overlay - * @pathp: pointer which receives the path of the target (or NULL) - * - * overlay_get_target() retrieves the target offset in the base - * device tree of a fragment, no matter how the actual targeting is - * done (through a phandle or a path) - * - * returns: - * the targeted node offset in the base device tree - * Negative error code on error - */ -static int overlay_get_target(const void *fdt, const void *fdto, - int fragment, char const **pathp) +int fdt_overlay_target_offset(const void *fdt, const void *fdto, + int fragment_offset, char const **pathp) { uint32_t phandle; const char *path = NULL; int path_len = 0, ret; /* Try first to do a phandle based lookup */ - phandle = overlay_get_target_phandle(fdto, fragment); + phandle = overlay_get_target_phandle(fdto, fragment_offset); if (phandle == (uint32_t)-1) return -FDT_ERR_BADPHANDLE; /* no phandle, try path */ if (!phandle) { /* And then a path based lookup */ - path = fdt_getprop(fdto, fragment, "target-path", &path_len); + path = fdt_getprop(fdto, fragment_offset, "target-path", &path_len); if (path) ret = fdt_path_offset(fdt, path); else @@ -241,6 +226,7 @@ static int overlay_update_local_node_references(void *fdto, if (fixup_len % sizeof(uint32_t)) return -FDT_ERR_BADOVERLAY; + fixup_len /= sizeof(uint32_t); tree_val = fdt_getprop(fdto, tree_node, name, &tree_len); if (!tree_val) { @@ -250,7 +236,7 @@ static int overlay_update_local_node_references(void *fdto, return tree_len; } - for (i = 0; i < (fixup_len / sizeof(uint32_t)); i++) { + for (i = 0; i < fixup_len; i++) { fdt32_t adj_val; uint32_t poffset; @@ -635,7 +621,7 @@ static int overlay_merge(void *fdt, void *fdto) if (overlay < 0) return overlay; - target = overlay_get_target(fdt, fdto, fragment, NULL); + target = fdt_overlay_target_offset(fdt, fdto, fragment, NULL); if (target < 0) return target; @@ -778,7 +764,7 @@ static int overlay_symbol_update(void *fdt, void *fdto) return -FDT_ERR_BADOVERLAY; /* get the target of the fragment */ - ret = overlay_get_target(fdt, fdto, fragment, &target_path); + ret = fdt_overlay_target_offset(fdt, fdto, fragment, &target_path); if (ret < 0) return ret; target = ret; @@ -800,7 +786,7 @@ static int overlay_symbol_update(void *fdt, void *fdto) if (!target_path) { /* again in case setprop_placeholder changed it */ - ret = overlay_get_target(fdt, fdto, fragment, &target_path); + ret = fdt_overlay_target_offset(fdt, fdto, fragment, &target_path); if (ret < 0) return ret; target = ret; diff --git a/libfdt/fdt_ro.c b/libfdt/fdt_ro.c index e03570a..a62ec78 100644 --- a/libfdt/fdt_ro.c +++ b/libfdt/fdt_ro.c @@ -10,6 +10,14 @@ #include "libfdt_internal.h" +/* Check if a buffer contains a nul-terminated string. + * Used for checking property values which should be strings. + */ +static bool is_nul_string(const char *buf, const size_t buf_len) { + return buf_len > 0 && buf[buf_len - 1] == '\0' && + strnlen(buf, buf_len) == buf_len - 1; +} + static int fdt_nodename_eq_(const void *fdt, int offset, const char *s, int len) { @@ -53,7 +61,7 @@ const char *fdt_get_string(const void *fdt, int stroffset, int *lenp) err = -FDT_ERR_BADOFFSET; absoffset = stroffset + fdt_off_dt_strings(fdt); - if (absoffset >= totalsize) + if (absoffset >= (unsigned)totalsize) goto fail; len = totalsize - absoffset; @@ -61,17 +69,19 @@ const char *fdt_get_string(const void *fdt, int stroffset, int *lenp) if (stroffset < 0) goto fail; if (can_assume(LATEST) || fdt_version(fdt) >= 17) { - if (stroffset >= fdt_size_dt_strings(fdt)) + if ((unsigned)stroffset >= fdt_size_dt_strings(fdt)) goto fail; if ((fdt_size_dt_strings(fdt) - stroffset) < len) len = fdt_size_dt_strings(fdt) - stroffset; } } else if (fdt_magic(fdt) == FDT_SW_MAGIC) { - if ((stroffset >= 0) - || (stroffset < -fdt_size_dt_strings(fdt))) + unsigned int sw_stroffset = -stroffset; + + if ((stroffset >= 0) || + (sw_stroffset > fdt_size_dt_strings(fdt))) goto fail; - if ((-stroffset) < len) - len = -stroffset; + if (sw_stroffset < len) + len = sw_stroffset; } else { err = -FDT_ERR_INTERNAL; goto fail; @@ -157,8 +167,8 @@ int fdt_generate_phandle(const void *fdt, uint32_t *phandle) static const struct fdt_reserve_entry *fdt_mem_rsv(const void *fdt, int n) { - int offset = n * sizeof(struct fdt_reserve_entry); - int absoffset = fdt_off_mem_rsvmap(fdt) + offset; + unsigned int offset = n * sizeof(struct fdt_reserve_entry); + unsigned int absoffset = fdt_off_mem_rsvmap(fdt) + offset; if (!can_assume(VALID_INPUT)) { if (absoffset < fdt_off_mem_rsvmap(fdt)) @@ -179,8 +189,8 @@ int fdt_get_mem_rsv(const void *fdt, int n, uint64_t *address, uint64_t *size) if (!can_assume(VALID_INPUT) && !re) return -FDT_ERR_BADOFFSET; - *address = fdt64_ld(&re->address); - *size = fdt64_ld(&re->size); + *address = fdt64_ld_(&re->address); + *size = fdt64_ld_(&re->size); return 0; } @@ -190,7 +200,7 @@ int fdt_num_mem_rsv(const void *fdt) const struct fdt_reserve_entry *re; for (i = 0; (re = fdt_mem_rsv(fdt, i)) != NULL; i++) { - if (fdt64_ld(&re->size) == 0) + if (fdt64_ld_(&re->size) == 0) return i; } return -FDT_ERR_TRUNCATED; @@ -253,6 +263,12 @@ int fdt_path_offset_namelen(const void *fdt, const char *path, int namelen) FDT_RO_PROBE(fdt); + if (namelen < 1) + return -FDT_ERR_BADPATH; + + if (namelen < 1) + return -FDT_ERR_BADPATH; + /* see if we have an alias */ if (*path != '/') { const char *q = memchr(path, '/', end - p); @@ -368,7 +384,7 @@ static const struct fdt_property *fdt_get_property_by_offset_(const void *fdt, prop = fdt_offset_ptr_(fdt, offset); if (lenp) - *lenp = fdt32_ld(&prop->len); + *lenp = fdt32_ld_(&prop->len); return prop; } @@ -406,7 +422,7 @@ static const struct fdt_property *fdt_get_property_namelen_(const void *fdt, offset = -FDT_ERR_INTERNAL; break; } - if (fdt_string_eq_(fdt, fdt32_ld(&prop->nameoff), + if (fdt_string_eq_(fdt, fdt32_ld_(&prop->nameoff), name, namelen)) { if (poffset) *poffset = offset; @@ -459,7 +475,7 @@ const void *fdt_getprop_namelen(const void *fdt, int nodeoffset, /* Handle realignment */ if (!can_assume(LATEST) && fdt_version(fdt) < 0x10 && - (poffset + sizeof(*prop)) % 8 && fdt32_ld(&prop->len) >= 8) + (poffset + sizeof(*prop)) % 8 && fdt32_ld_(&prop->len) >= 8) return prop->data + 4; return prop->data; } @@ -477,22 +493,22 @@ const void *fdt_getprop_by_offset(const void *fdt, int offset, int namelen; if (!can_assume(VALID_INPUT)) { - name = fdt_get_string(fdt, fdt32_ld(&prop->nameoff), + name = fdt_get_string(fdt, fdt32_ld_(&prop->nameoff), &namelen); + *namep = name; if (!name) { if (lenp) *lenp = namelen; return NULL; } - *namep = name; } else { - *namep = fdt_string(fdt, fdt32_ld(&prop->nameoff)); + *namep = fdt_string(fdt, fdt32_ld_(&prop->nameoff)); } } /* Handle realignment */ if (!can_assume(LATEST) && fdt_version(fdt) < 0x10 && - (offset + sizeof(*prop)) % 8 && fdt32_ld(&prop->len) >= 8) + (offset + sizeof(*prop)) % 8 && fdt32_ld_(&prop->len) >= 8) return prop->data + 4; return prop->data; } @@ -517,19 +533,33 @@ uint32_t fdt_get_phandle(const void *fdt, int nodeoffset) return 0; } - return fdt32_ld(php); + return fdt32_ld_(php); } const char *fdt_get_alias_namelen(const void *fdt, const char *name, int namelen) { + const char *prop; int aliasoffset; + int prop_len; aliasoffset = fdt_path_offset(fdt, "/aliases"); if (aliasoffset < 0) return NULL; - return fdt_getprop_namelen(fdt, aliasoffset, name, namelen, NULL); + prop = fdt_getprop_namelen(fdt, aliasoffset, name, namelen, &prop_len); + if (prop && !can_assume(VALID_INPUT)) { + /* Validate the alias value. From the devicetree spec v0.3: + * "An alias value is a device path and is encoded as a string. + * The value representes the full path to a node, ..." + * A full path must start at the root to prevent recursion. + */ + if (prop_len == 0 || *prop != '/' || !is_nul_string(prop, prop_len)) { + prop = NULL; + } + } + + return prop; } const char *fdt_get_alias(const void *fdt, const char *name) @@ -680,7 +710,7 @@ int fdt_node_offset_by_phandle(const void *fdt, uint32_t phandle) { int offset; - if ((phandle == 0) || (phandle == -1)) + if ((phandle == 0) || (phandle == ~0U)) return -FDT_ERR_BADPHANDLE; FDT_RO_PROBE(fdt); diff --git a/libfdt/fdt_rw.c b/libfdt/fdt_rw.c index 93e4a2b..3621d36 100644 --- a/libfdt/fdt_rw.c +++ b/libfdt/fdt_rw.c @@ -59,7 +59,7 @@ static int fdt_splice_(void *fdt, void *splicepoint, int oldlen, int newlen) if ((oldlen < 0) || (soff + oldlen < soff) || (soff + oldlen > dsize)) return -FDT_ERR_BADOFFSET; - if ((p < (char *)fdt) || (dsize + newlen < oldlen)) + if ((p < (char *)fdt) || (dsize + newlen < (unsigned)oldlen)) return -FDT_ERR_BADOFFSET; if (dsize - oldlen + newlen > fdt_totalsize(fdt)) return -FDT_ERR_NOSPACE; @@ -349,7 +349,10 @@ int fdt_add_subnode_namelen(void *fdt, int parentoffset, return offset; /* Try to place the new node after the parent's properties */ - fdt_next_tag(fdt, parentoffset, &nextoffset); /* skip the BEGIN_NODE */ + tag = fdt_next_tag(fdt, parentoffset, &nextoffset); + /* the fdt_subnode_offset_namelen() should ensure this never hits */ + if (!can_assume(LIBFDT_FLAWLESS) && (tag != FDT_BEGIN_NODE)) + return -FDT_ERR_INTERNAL; do { offset = nextoffset; tag = fdt_next_tag(fdt, offset, &nextoffset); @@ -391,7 +394,9 @@ int fdt_del_node(void *fdt, int nodeoffset) } static void fdt_packblocks_(const char *old, char *new, - int mem_rsv_size, int struct_size) + int mem_rsv_size, + int struct_size, + int strings_size) { int mem_rsv_off, struct_off, strings_off; @@ -406,8 +411,7 @@ static void fdt_packblocks_(const char *old, char *new, fdt_set_off_dt_struct(new, struct_off); fdt_set_size_dt_struct(new, struct_size); - memmove(new + strings_off, old + fdt_off_dt_strings(old), - fdt_size_dt_strings(old)); + memmove(new + strings_off, old + fdt_off_dt_strings(old), strings_size); fdt_set_off_dt_strings(new, strings_off); fdt_set_size_dt_strings(new, fdt_size_dt_strings(old)); } @@ -428,12 +432,14 @@ int fdt_open_into(const void *fdt, void *buf, int bufsize) if (can_assume(LATEST) || fdt_version(fdt) >= 17) { struct_size = fdt_size_dt_struct(fdt); - } else { + } else if (fdt_version(fdt) == 16) { struct_size = 0; while (fdt_next_tag(fdt, struct_size, &struct_size) != FDT_END) ; if (struct_size < 0) return struct_size; + } else { + return -FDT_ERR_BADVERSION; } if (can_assume(LIBFDT_ORDER) || @@ -465,7 +471,8 @@ int fdt_open_into(const void *fdt, void *buf, int bufsize) return -FDT_ERR_NOSPACE; } - fdt_packblocks_(fdt, tmp, mem_rsv_size, struct_size); + fdt_packblocks_(fdt, tmp, mem_rsv_size, struct_size, + fdt_size_dt_strings(fdt)); memmove(buf, tmp, newsize); fdt_set_magic(buf, FDT_MAGIC); @@ -485,7 +492,8 @@ int fdt_pack(void *fdt) mem_rsv_size = (fdt_num_mem_rsv(fdt)+1) * sizeof(struct fdt_reserve_entry); - fdt_packblocks_(fdt, fdt, mem_rsv_size, fdt_size_dt_struct(fdt)); + fdt_packblocks_(fdt, fdt, mem_rsv_size, fdt_size_dt_struct(fdt), + fdt_size_dt_strings(fdt)); fdt_set_totalsize(fdt, fdt_data_size_(fdt)); return 0; diff --git a/libfdt/fdt_strerror.c b/libfdt/fdt_strerror.c index 768db66..d852b77 100644 --- a/libfdt/fdt_strerror.c +++ b/libfdt/fdt_strerror.c @@ -39,8 +39,9 @@ static struct fdt_errtabent fdt_errtable[] = { FDT_ERRTABENT(FDT_ERR_BADOVERLAY), FDT_ERRTABENT(FDT_ERR_NOPHANDLES), FDT_ERRTABENT(FDT_ERR_BADFLAGS), + FDT_ERRTABENT(FDT_ERR_ALIGNMENT), }; -#define FDT_ERRTABSIZE (sizeof(fdt_errtable) / sizeof(fdt_errtable[0])) +#define FDT_ERRTABSIZE ((int)(sizeof(fdt_errtable) / sizeof(fdt_errtable[0]))) const char *fdt_strerror(int errval) { @@ -48,7 +49,7 @@ const char *fdt_strerror(int errval) return "<valid offset/length>"; else if (errval == 0) return "<no error>"; - else if (errval > -FDT_ERRTABSIZE) { + else if (-errval < FDT_ERRTABSIZE) { const char *s = fdt_errtable[-errval].str; if (s) diff --git a/libfdt/fdt_sw.c b/libfdt/fdt_sw.c index 94ce4bb..4c569ee 100644 --- a/libfdt/fdt_sw.c +++ b/libfdt/fdt_sw.c @@ -93,8 +93,8 @@ static inline uint32_t sw_flags(void *fdt) static void *fdt_grab_space_(void *fdt, size_t len) { - int offset = fdt_size_dt_struct(fdt); - int spaceleft; + unsigned int offset = fdt_size_dt_struct(fdt); + unsigned int spaceleft; spaceleft = fdt_totalsize(fdt) - fdt_off_dt_struct(fdt) - fdt_size_dt_strings(fdt); @@ -108,8 +108,8 @@ static void *fdt_grab_space_(void *fdt, size_t len) int fdt_create_with_flags(void *buf, int bufsize, uint32_t flags) { - const size_t hdrsize = FDT_ALIGN(sizeof(struct fdt_header), - sizeof(struct fdt_reserve_entry)); + const int hdrsize = FDT_ALIGN(sizeof(struct fdt_header), + sizeof(struct fdt_reserve_entry)); void *fdt = buf; if (bufsize < hdrsize) @@ -152,6 +152,9 @@ int fdt_resize(void *fdt, void *buf, int bufsize) FDT_SW_PROBE(fdt); + if (bufsize < 0) + return -FDT_ERR_NOSPACE; + headsize = fdt_off_dt_struct(fdt) + fdt_size_dt_struct(fdt); tailsize = fdt_size_dt_strings(fdt); @@ -159,7 +162,7 @@ int fdt_resize(void *fdt, void *buf, int bufsize) headsize + tailsize > fdt_totalsize(fdt)) return -FDT_ERR_INTERNAL; - if ((headsize + tailsize) > bufsize) + if ((headsize + tailsize) > (unsigned)bufsize) return -FDT_ERR_NOSPACE; oldtail = (char *)fdt + fdt_totalsize(fdt) - tailsize; @@ -247,18 +250,18 @@ int fdt_end_node(void *fdt) static int fdt_add_string_(void *fdt, const char *s) { char *strtab = (char *)fdt + fdt_totalsize(fdt); - int strtabsize = fdt_size_dt_strings(fdt); - int len = strlen(s) + 1; - int struct_top, offset; + unsigned int strtabsize = fdt_size_dt_strings(fdt); + unsigned int len = strlen(s) + 1; + unsigned int struct_top, offset; - offset = -strtabsize - len; + offset = strtabsize + len; struct_top = fdt_off_dt_struct(fdt) + fdt_size_dt_struct(fdt); - if (fdt_totalsize(fdt) + offset < struct_top) + if (fdt_totalsize(fdt) - offset < struct_top) return 0; /* no more room :( */ - memcpy(strtab + offset, s, len); + memcpy(strtab - offset, s, len); fdt_set_size_dt_strings(fdt, strtabsize + len); - return offset; + return -offset; } /* Must only be used to roll back in case of error */ @@ -374,7 +377,7 @@ int fdt_finish(void *fdt) fdt_set_totalsize(fdt, newstroffset + fdt_size_dt_strings(fdt)); /* And fix up fields that were keeping intermediate state. */ - fdt_set_last_comp_version(fdt, FDT_FIRST_SUPPORTED_VERSION); + fdt_set_last_comp_version(fdt, FDT_LAST_COMPATIBLE_VERSION); fdt_set_magic(fdt, FDT_MAGIC); return 0; diff --git a/libfdt/fdt_wip.c b/libfdt/fdt_wip.c index f64139e..c2d7566 100644 --- a/libfdt/fdt_wip.c +++ b/libfdt/fdt_wip.c @@ -23,7 +23,7 @@ int fdt_setprop_inplace_namelen_partial(void *fdt, int nodeoffset, if (!propval) return proplen; - if (proplen < (len + idx)) + if ((unsigned)proplen < (len + idx)) return -FDT_ERR_NOSPACE; memcpy((char *)propval + idx, val, len); diff --git a/libfdt/libfdt.h b/libfdt/libfdt.h index 544d3ef..a7f432c 100644 --- a/libfdt/libfdt.h +++ b/libfdt/libfdt.h @@ -14,6 +14,7 @@ extern "C" { #endif #define FDT_FIRST_SUPPORTED_VERSION 0x02 +#define FDT_LAST_COMPATIBLE_VERSION 0x10 #define FDT_LAST_SUPPORTED_VERSION 0x11 /* Error codes: informative error codes */ @@ -101,7 +102,11 @@ extern "C" { /* FDT_ERR_BADFLAGS: The function was passed a flags field that * contains invalid flags or an invalid combination of flags. */ -#define FDT_ERR_MAX 18 +#define FDT_ERR_ALIGNMENT 19 + /* FDT_ERR_ALIGNMENT: The device tree base address is not 8-byte + * aligned. */ + +#define FDT_ERR_MAX 19 /* constants */ #define FDT_MAX_PHANDLE 0xfffffffe @@ -122,11 +127,16 @@ static inline void *fdt_offset_ptr_w(void *fdt, int offset, int checklen) uint32_t fdt_next_tag(const void *fdt, int offset, int *nextoffset); /* - * Alignment helpers: - * These helpers access words from a device tree blob. They're - * built to work even with unaligned pointers on platforms (ike - * ARM) that don't like unaligned loads and stores + * External helpers to access words from a device tree blob. They're built + * to work even with unaligned pointers on platforms (such as ARMv5) that don't + * like unaligned loads and stores. */ +static inline uint16_t fdt16_ld(const fdt16_t *p) +{ + const uint8_t *bp = (const uint8_t *)p; + + return ((uint16_t)bp[0] << 8) | bp[1]; +} static inline uint32_t fdt32_ld(const fdt32_t *p) { @@ -184,23 +194,23 @@ int fdt_next_node(const void *fdt, int offset, int *depth); /** * fdt_first_subnode() - get offset of first direct subnode - * * @fdt: FDT blob * @offset: Offset of node to check - * @return offset of first subnode, or -FDT_ERR_NOTFOUND if there is none + * + * Return: offset of first subnode, or -FDT_ERR_NOTFOUND if there is none */ int fdt_first_subnode(const void *fdt, int offset); /** * fdt_next_subnode() - get offset of next direct subnode + * @fdt: FDT blob + * @offset: Offset of previous subnode * * After first calling fdt_first_subnode(), call this function repeatedly to * get direct subnodes of a parent node. * - * @fdt: FDT blob - * @offset: Offset of previous subnode - * @return offset of next subnode, or -FDT_ERR_NOTFOUND if there are no more - * subnodes + * Return: offset of next subnode, or -FDT_ERR_NOTFOUND if there are no more + * subnodes */ int fdt_next_subnode(const void *fdt, int offset); @@ -225,7 +235,6 @@ int fdt_next_subnode(const void *fdt, int offset); * Note that this is implemented as a macro and @node is used as * iterator in the loop. The parent variable be constant or even a * literal. - * */ #define fdt_for_each_subnode(node, fdt, parent) \ for (node = fdt_first_subnode(fdt, parent); \ @@ -269,17 +278,21 @@ fdt_set_hdr_(size_dt_struct); /** * fdt_header_size - return the size of the tree's header * @fdt: pointer to a flattened device tree + * + * Return: size of DTB header in bytes */ size_t fdt_header_size(const void *fdt); /** - * fdt_header_size_ - internal function which takes a version number + * fdt_header_size_ - internal function to get header size from a version number + * @version: devicetree version number + * + * Return: size of DTB header in bytes */ size_t fdt_header_size_(uint32_t version); /** * fdt_check_header - sanity check a device tree header - * @fdt: pointer to data which might be a flattened device tree * * fdt_check_header() checks that the given buffer contains what @@ -404,8 +417,7 @@ static inline uint32_t fdt_get_max_phandle(const void *fdt) * highest phandle value in the device tree blob) will be returned in the * @phandle parameter. * - * Returns: - * 0 on success or a negative error-code on failure + * Return: 0 on success or a negative error-code on failure */ int fdt_generate_phandle(const void *fdt, uint32_t *phandle); @@ -425,9 +437,11 @@ int fdt_num_mem_rsv(const void *fdt); /** * fdt_get_mem_rsv - retrieve one memory reserve map entry * @fdt: pointer to the device tree blob - * @address, @size: pointers to 64-bit variables + * @n: index of reserve map entry + * @address: pointer to 64-bit variable to hold the start address + * @size: pointer to 64-bit variable to hold the size of the entry * - * On success, *address and *size will contain the address and size of + * On success, @address and @size will contain the address and size of * the n-th reserve map entry from the device tree blob, in * native-endian format. * @@ -450,6 +464,8 @@ int fdt_get_mem_rsv(const void *fdt, int n, uint64_t *address, uint64_t *size); * namelen characters of name for matching the subnode name. This is * useful for finding subnodes based on a portion of a larger string, * such as a full path. + * + * Return: offset of the subnode or -FDT_ERR_NOTFOUND if name not found. */ #ifndef SWIG /* Not available in Python */ int fdt_subnode_offset_namelen(const void *fdt, int parentoffset, @@ -489,6 +505,8 @@ int fdt_subnode_offset(const void *fdt, int parentoffset, const char *name); * * Identical to fdt_path_offset(), but only consider the first namelen * characters of path as the path name. + * + * Return: offset of the node or negative libfdt error value otherwise */ #ifndef SWIG /* Not available in Python */ int fdt_path_offset_namelen(const void *fdt, const char *path, int namelen); @@ -588,9 +606,9 @@ int fdt_next_property_offset(const void *fdt, int offset); /** * fdt_for_each_property_offset - iterate over all properties of a node * - * @property_offset: property offset (int, lvalue) - * @fdt: FDT blob (const void *) - * @node: node offset (int) + * @property: property offset (int, lvalue) + * @fdt: FDT blob (const void *) + * @node: node offset (int) * * This is actually a wrapper around a for loop and would be used like so: * @@ -653,6 +671,9 @@ const struct fdt_property *fdt_get_property_by_offset(const void *fdt, * * Identical to fdt_get_property(), but only examine the first namelen * characters of name for matching the property name. + * + * Return: pointer to the structure representing the property, or NULL + * if not found */ #ifndef SWIG /* Not available in Python */ const struct fdt_property *fdt_get_property_namelen(const void *fdt, @@ -745,6 +766,8 @@ const void *fdt_getprop_by_offset(const void *fdt, int offset, * * Identical to fdt_getprop(), but only examine the first namelen * characters of name for matching the property name. + * + * Return: pointer to the property's value or NULL on error */ #ifndef SWIG /* Not available in Python */ const void *fdt_getprop_namelen(const void *fdt, int nodeoffset, @@ -766,10 +789,10 @@ static inline void *fdt_getprop_namelen_w(void *fdt, int nodeoffset, * @lenp: pointer to an integer variable (will be overwritten) or NULL * * fdt_getprop() retrieves a pointer to the value of the property - * named 'name' of the node at offset nodeoffset (this will be a + * named @name of the node at offset @nodeoffset (this will be a * pointer to within the device blob itself, not a copy of the value). - * If lenp is non-NULL, the length of the property value is also - * returned, in the integer pointed to by lenp. + * If @lenp is non-NULL, the length of the property value is also + * returned, in the integer pointed to by @lenp. * * returns: * pointer to the property's value @@ -814,8 +837,11 @@ uint32_t fdt_get_phandle(const void *fdt, int nodeoffset); * @name: name of the alias th look up * @namelen: number of characters of name to consider * - * Identical to fdt_get_alias(), but only examine the first namelen - * characters of name for matching the alias name. + * Identical to fdt_get_alias(), but only examine the first @namelen + * characters of @name for matching the alias name. + * + * Return: a pointer to the expansion of the alias named @name, if it exists, + * NULL otherwise */ #ifndef SWIG /* Not available in Python */ const char *fdt_get_alias_namelen(const void *fdt, @@ -828,7 +854,7 @@ const char *fdt_get_alias_namelen(const void *fdt, * @name: name of the alias th look up * * fdt_get_alias() retrieves the value of a given alias. That is, the - * value of the property named 'name' in the node /aliases. + * value of the property named @name in the node /aliases. * * returns: * a pointer to the expansion of the alias named 'name', if it exists @@ -1004,14 +1030,13 @@ int fdt_node_offset_by_prop_value(const void *fdt, int startoffset, int fdt_node_offset_by_phandle(const void *fdt, uint32_t phandle); /** - * fdt_node_check_compatible: check a node's compatible property + * fdt_node_check_compatible - check a node's compatible property * @fdt: pointer to the device tree blob * @nodeoffset: offset of a tree node * @compatible: string to match against * - * * fdt_node_check_compatible() returns 0 if the given node contains a - * 'compatible' property with the given string as one of its elements, + * @compatible property with the given string as one of its elements, * it returns non-zero otherwise, or on error. * * returns: @@ -1075,7 +1100,7 @@ int fdt_node_offset_by_compatible(const void *fdt, int startoffset, * one or more strings, each terminated by \0, as is found in a device tree * "compatible" property. * - * @return: 1 if the string is found in the list, 0 not found, or invalid list + * Return: 1 if the string is found in the list, 0 not found, or invalid list */ int fdt_stringlist_contains(const char *strlist, int listlen, const char *str); @@ -1084,7 +1109,8 @@ int fdt_stringlist_contains(const char *strlist, int listlen, const char *str); * @fdt: pointer to the device tree blob * @nodeoffset: offset of a tree node * @property: name of the property containing the string list - * @return: + * + * Return: * the number of strings in the given property * -FDT_ERR_BADVALUE if the property value is not NUL-terminated * -FDT_ERR_NOTFOUND if the property does not exist @@ -1104,7 +1130,7 @@ int fdt_stringlist_count(const void *fdt, int nodeoffset, const char *property); * small-valued cell properties, such as #address-cells, when searching for * the empty string. * - * @return: + * return: * the index of the string in the list of strings * -FDT_ERR_BADVALUE if the property value is not NUL-terminated * -FDT_ERR_NOTFOUND if the property does not exist or does not contain @@ -1128,7 +1154,7 @@ int fdt_stringlist_search(const void *fdt, int nodeoffset, const char *property, * If non-NULL, the length of the string (on success) or a negative error-code * (on failure) will be stored in the integer pointer to by lenp. * - * @return: + * Return: * A pointer to the string at the given index in the string list or NULL on * failure. On success the length of the string will be stored in the memory * location pointed to by the lenp parameter, if non-NULL. On failure one of @@ -1217,6 +1243,8 @@ int fdt_size_cells(const void *fdt, int nodeoffset); * starting from the given index, and using only the first characters * of the name. It is useful when you want to manipulate only one value of * an array and you have a string that doesn't end with \0. + * + * Return: 0 on success, negative libfdt error value otherwise */ #ifndef SWIG /* Not available in Python */ int fdt_setprop_inplace_namelen_partial(void *fdt, int nodeoffset, @@ -1330,8 +1358,13 @@ static inline int fdt_setprop_inplace_u64(void *fdt, int nodeoffset, /** * fdt_setprop_inplace_cell - change the value of a single-cell property + * @fdt: pointer to the device tree blob + * @nodeoffset: offset of the node containing the property + * @name: name of the property to change the value of + * @val: new value of the 32-bit cell * * This is an alternative name for fdt_setprop_inplace_u32() + * Return: 0 on success, negative libfdt error number otherwise. */ static inline int fdt_setprop_inplace_cell(void *fdt, int nodeoffset, const char *name, uint32_t val) @@ -1403,7 +1436,7 @@ int fdt_nop_node(void *fdt, int nodeoffset); /** * fdt_create_with_flags - begin creation of a new fdt - * @fdt: pointer to memory allocated where fdt will be created + * @buf: pointer to memory allocated where fdt will be created * @bufsize: size of the memory space at fdt * @flags: a valid combination of FDT_CREATE_FLAG_ flags, or 0. * @@ -1421,7 +1454,7 @@ int fdt_create_with_flags(void *buf, int bufsize, uint32_t flags); /** * fdt_create - begin creation of a new fdt - * @fdt: pointer to memory allocated where fdt will be created + * @buf: pointer to memory allocated where fdt will be created * @bufsize: size of the memory space at fdt * * fdt_create() is equivalent to fdt_create_with_flags() with flags=0. @@ -1486,7 +1519,8 @@ int fdt_pack(void *fdt); /** * fdt_add_mem_rsv - add one memory reserve map entry * @fdt: pointer to the device tree blob - * @address, @size: 64-bit values (native endian) + * @address: 64-bit start address of the reserve map entry + * @size: 64-bit size of the reserved region * * Adds a reserve map entry to the given blob reserving a region at * address address of length size. @@ -1691,8 +1725,14 @@ static inline int fdt_setprop_u64(void *fdt, int nodeoffset, const char *name, /** * fdt_setprop_cell - set a property to a single cell value + * @fdt: pointer to the device tree blob + * @nodeoffset: offset of the node whose property to change + * @name: name of the property to change + * @val: 32-bit integer value for the property (native endian) * * This is an alternative name for fdt_setprop_u32() + * + * Return: 0 on success, negative libfdt error value otherwise. */ static inline int fdt_setprop_cell(void *fdt, int nodeoffset, const char *name, uint32_t val) @@ -1863,8 +1903,14 @@ static inline int fdt_appendprop_u64(void *fdt, int nodeoffset, /** * fdt_appendprop_cell - append a single cell value to a property + * @fdt: pointer to the device tree blob + * @nodeoffset: offset of the node whose property to change + * @name: name of the property to change + * @val: 32-bit integer value to append to the property (native endian) * * This is an alternative name for fdt_appendprop_u32() + * + * Return: 0 on success, negative libfdt error value otherwise. */ static inline int fdt_appendprop_cell(void *fdt, int nodeoffset, const char *name, uint32_t val) @@ -1967,13 +2013,16 @@ int fdt_delprop(void *fdt, int nodeoffset, const char *name); * fdt_add_subnode_namelen - creates a new node based on substring * @fdt: pointer to the device tree blob * @parentoffset: structure block offset of a node - * @name: name of the subnode to locate + * @name: name of the subnode to create * @namelen: number of characters of name to consider * - * Identical to fdt_add_subnode(), but use only the first namelen - * characters of name as the name of the new node. This is useful for + * Identical to fdt_add_subnode(), but use only the first @namelen + * characters of @name as the name of the new node. This is useful for * creating subnodes based on a portion of a larger string, such as a * full path. + * + * Return: structure block offset of the created subnode (>=0), + * negative libfdt error value otherwise */ #ifndef SWIG /* Not available in Python */ int fdt_add_subnode_namelen(void *fdt, int parentoffset, @@ -1992,7 +2041,7 @@ int fdt_add_subnode_namelen(void *fdt, int parentoffset, * * This function will insert data into the blob, and will therefore * change the offsets of some existing nodes. - + * * returns: * structure block offset of the created nodeequested subnode (>=0), on * success @@ -2067,6 +2116,24 @@ int fdt_del_node(void *fdt, int nodeoffset); */ int fdt_overlay_apply(void *fdt, void *fdto); +/** + * fdt_overlay_target_offset - retrieves the offset of a fragment's target + * @fdt: Base device tree blob + * @fdto: Device tree overlay blob + * @fragment_offset: node offset of the fragment in the overlay + * @pathp: pointer which receives the path of the target (or NULL) + * + * fdt_overlay_target_offset() retrieves the target offset in the base + * device tree of a fragment, no matter how the actual targeting is + * done (through a phandle or a path) + * + * returns: + * the targeted node offset in the base device tree + * Negative error code on error + */ +int fdt_overlay_target_offset(const void *fdt, const void *fdto, + int fragment_offset, char const **pathp); + /**********************************************************************/ /* Debugging / informational functions */ /**********************************************************************/ diff --git a/libfdt/libfdt_internal.h b/libfdt/libfdt_internal.h index d4e0bd4..16bda19 100644 --- a/libfdt/libfdt_internal.h +++ b/libfdt/libfdt_internal.h @@ -46,6 +46,25 @@ static inline struct fdt_reserve_entry *fdt_mem_rsv_w_(void *fdt, int n) return (void *)(uintptr_t)fdt_mem_rsv_(fdt, n); } +/* + * Internal helpers to access tructural elements of the device tree + * blob (rather than for exaple reading integers from within property + * values). We assume that we are either given a naturally aligned + * address for the platform or if we are not, we are on a platform + * where unaligned memory reads will be handled in a graceful manner. + * If not the external helpers fdtXX_ld() from libfdt.h can be used + * instead. + */ +static inline uint32_t fdt32_ld_(const fdt32_t *p) +{ + return fdt32_to_cpu(*p); +} + +static inline uint64_t fdt64_ld_(const fdt64_t *p) +{ + return fdt64_to_cpu(*p); +} + #define FDT_SW_MAGIC (~FDT_MAGIC) /**********************************************************************/ diff --git a/libfdt/meson.build b/libfdt/meson.build new file mode 100644 index 0000000..240bdf4 --- /dev/null +++ b/libfdt/meson.build @@ -0,0 +1,61 @@ +version_script = '-Wl,--version-script=@0@'.format(meson.current_source_dir() / 'version.lds') +if not cc.has_link_argument(version_script) + version_script = [] +endif + +sources = files( + 'fdt.c', + 'fdt_addresses.c', + 'fdt_check.c', + 'fdt_empty_tree.c', + 'fdt_overlay.c', + 'fdt_ro.c', + 'fdt_rw.c', + 'fdt_strerror.c', + 'fdt_sw.c', + 'fdt_wip.c', +) + +libfdt = library( + 'fdt', sources, + version: '1.6.0', + link_args: ['-Wl,--no-undefined', version_script], + link_depends: 'version.lds', + install: true, +) + +libfdt_a = static_library( + 'fdt', sources, + install: true, +) + +libfdt_inc = include_directories('.') + +if static_build + link_with = libfdt_a +else + link_with = libfdt +endif + +libfdt_dep = declare_dependency( + include_directories: libfdt_inc, + link_with: link_with, +) + +install_headers( + files( + 'fdt.h', + 'libfdt.h', + 'libfdt_env.h', + ) +) + +pkgconfig = import('pkgconfig') + +pkgconfig.generate( + libraries: libfdt, + version: meson.project_version(), + filebase: 'libfdt', + name: 'libfdt', + description: 'Flat Device Tree manipulation', +) diff --git a/libfdt/rules.mk b/libfdt/rules.mk new file mode 100644 index 0000000..c785aa2 --- /dev/null +++ b/libfdt/rules.mk @@ -0,0 +1,53 @@ +# Copyright (c) 2022, Google, Inc. 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. + +# This file is not used in the Android build process! It's used only by Trusty. + + +LOCAL_DIR := $(GET_LOCAL_DIR) + +MODULE := $(LOCAL_DIR) + +MODULE_SRCS := \ + $(LOCAL_DIR)/fdt.c \ + $(LOCAL_DIR)/fdt_check.c \ + $(LOCAL_DIR)/fdt_ro.c \ + $(LOCAL_DIR)/fdt_wip.c \ + $(LOCAL_DIR)/fdt_sw.c \ + $(LOCAL_DIR)/fdt_rw.c \ + $(LOCAL_DIR)/fdt_strerror.c \ + $(LOCAL_DIR)/fdt_empty_tree.c \ + $(LOCAL_DIR)/fdt_addresses.c \ + $(LOCAL_DIR)/fdt_overlay.c \ + $(LOCAL_DIR)/acpi.c \ + + +MODULE_COMPILEFLAGS += \ + -Wno-sign-compare \ + -Wno-macro-redefined \ + +MODULE_EXPORT_INCLUDES += \ + $(LOCAL_DIR) \ + +include make/library.mk diff --git a/libfdt/version.lds b/libfdt/version.lds index 7ab85f1..cbce5d4 100644 --- a/libfdt/version.lds +++ b/libfdt/version.lds @@ -77,6 +77,7 @@ LIBFDT_1.2 { fdt_appendprop_addrrange; fdt_setprop_inplace_namelen_partial; fdt_create_with_flags; + fdt_overlay_target_offset; local: *; }; @@ -438,7 +438,7 @@ cell_t propval_cell(struct property *prop) return fdt32_to_cpu(*((fdt32_t *)prop->val.val)); } -cell_t propval_cell_n(struct property *prop, int n) +cell_t propval_cell_n(struct property *prop, unsigned int n) { assert(prop->val.len / sizeof(cell_t) >= n); return fdt32_to_cpu(*((fdt32_t *)prop->val.val + n)); @@ -526,7 +526,7 @@ struct node *get_node_by_path(struct node *tree, const char *path) p = strchr(path, '/'); for_each_child(tree, child) { - if (p && strprefixeq(path, p - path, child->name)) + if (p && strprefixeq(path, (size_t)(p - path), child->name)) return get_node_by_path(child, p+1); else if (!p && streq(path, child->name)) return child; @@ -559,7 +559,7 @@ struct node *get_node_by_phandle(struct node *tree, cell_t phandle) { struct node *child, *node; - if ((phandle == 0) || (phandle == -1)) { + if (!phandle_is_valid(phandle)) { assert(generate_fixups); return NULL; } @@ -581,12 +581,39 @@ struct node *get_node_by_phandle(struct node *tree, cell_t phandle) struct node *get_node_by_ref(struct node *tree, const char *ref) { + struct node *target = tree; + const char *label = NULL, *path = NULL; + if (streq(ref, "/")) return tree; - else if (ref[0] == '/') - return get_node_by_path(tree, ref); + + if (ref[0] == '/') + path = ref; else - return get_node_by_label(tree, ref); + label = ref; + + if (label) { + const char *slash = strchr(label, '/'); + char *buf = NULL; + + if (slash) { + buf = xstrndup(label, slash - label); + label = buf; + path = slash + 1; + } + + target = get_node_by_label(tree, label); + + free(buf); + + if (!target) + return NULL; + } + + if (path) + target = get_node_by_path(target, path); + + return target; } cell_t get_node_phandle(struct node *root, struct node *node) @@ -594,7 +621,7 @@ cell_t get_node_phandle(struct node *root, struct node *node) static cell_t phandle = 1; /* FIXME: ick, static local */ struct data d = empty_data; - if ((node->phandle != 0) && (node->phandle != -1)) + if (phandle_is_valid(node->phandle)) return node->phandle; while (get_node_by_phandle(root, phandle)) diff --git a/meson.build b/meson.build new file mode 100644 index 0000000..78251eb --- /dev/null +++ b/meson.build @@ -0,0 +1,139 @@ +project('dtc', 'c', + version: '1.6.0', + license: ['GPL2+', 'BSD-2'], + default_options: 'werror=true', +) + +cc = meson.get_compiler('c') + +add_project_arguments( + cc.get_supported_arguments([ + '-Wpointer-arith', + '-Wcast-qual', + '-Wnested-externs', + '-Wstrict-prototypes', + '-Wmissing-prototypes', + '-Wredundant-decls', + '-Wshadow' + ]), + language: 'c' +) + +if host_machine.system() == 'windows' + add_project_arguments( + '-D__USE_MINGW_ANSI_STDIO=1', + language: 'c' + ) +endif + +add_project_arguments( + '-DFDT_ASSUME_MASK=' + get_option('assume-mask').to_string(), + language: 'c' +) + +if get_option('static-build') + static_build = true + extra_link_args = ['-static'] +else + static_build = false + extra_link_args = [] +endif + +yamltree = 'yamltree.c' +yaml = dependency('yaml-0.1', required: get_option('yaml'), static: static_build) +if not yaml.found() + add_project_arguments('-DNO_YAML', language: 'c') + yamltree = [] +endif + +valgrind = dependency('valgrind', required: get_option('valgrind')) +if not valgrind.found() + add_project_arguments('-DNO_VALGRIND', language: 'c') +endif + +py = import('python') +py = py.find_installation(required: get_option('python')) +swig = find_program('swig', required: get_option('python')) + +version_gen_h = vcs_tag( + input: 'version_gen.h.in', + output: 'version_gen.h', +) + +subdir('libfdt') + +if get_option('tools') + flex = find_program('flex', required: true) + bison = find_program('bison', required: true) + + util_dep = declare_dependency( + sources: ['util.c', version_gen_h], + include_directories: '.', + dependencies: libfdt_dep + ) + + lgen = generator( + flex, + output: '@PLAINNAME@.lex.c', + arguments: ['-o', '@OUTPUT@', '@INPUT@'], + ) + + pgen = generator( + bison, + output: ['@BASENAME@.tab.c', '@BASENAME@.tab.h'], + arguments: ['@INPUT@', '--defines=@OUTPUT1@', '--output=@OUTPUT0@'], + ) + + if cc.check_header('fnmatch.h') + executable( + 'convert-dtsv0', + [ + lgen.process('convert-dtsv0-lexer.l'), + 'srcpos.c', + ], + dependencies: util_dep, + install: true, + link_args: extra_link_args, + ) + endif + + executable( + 'dtc', + [ + lgen.process('dtc-lexer.l'), + pgen.process('dtc-parser.y'), + 'checks.c', + 'data.c', + 'dtc.c', + 'flattree.c', + 'fstree.c', + 'livetree.c', + 'srcpos.c', + 'treesource.c', + yamltree, + ], + dependencies: [util_dep, yaml], + install: true, + link_args: extra_link_args, + ) + + foreach e: ['fdtdump', 'fdtget', 'fdtput', 'fdtoverlay'] + executable(e, files(e + '.c'), dependencies: util_dep, install: true, link_args: extra_link_args) + endforeach + + install_data( + 'dtdiff', + install_dir: get_option('prefix') / get_option('bindir'), + install_mode: 'rwxr-xr-x', + ) +endif + +if not meson.is_cross_build() + if py.found() and swig.found() + subdir('pylibfdt') + endif + + if get_option('tools') + subdir('tests') + endif +endif diff --git a/meson_options.txt b/meson_options.txt new file mode 100644 index 0000000..82621c3 --- /dev/null +++ b/meson_options.txt @@ -0,0 +1,12 @@ +option('tools', type: 'boolean', value: true, + description: 'Build tools') +option('assume-mask', type: 'integer', value: 0, + description: 'Control the assumptions made (e.g. risking security issues) in the code.') +option('yaml', type: 'feature', value: 'auto', + description: 'YAML support') +option('valgrind', type: 'feature', value: 'auto', + description: 'Valgrind support') +option('python', type: 'feature', value: 'auto', + description: 'Build pylibfdt Python library') +option('static-build', type: 'boolean', value: false, + description: 'Build static binaries') diff --git a/pylibfdt/Makefile.pylibfdt b/pylibfdt/Makefile.pylibfdt index 6866a0b..82f565e 100644 --- a/pylibfdt/Makefile.pylibfdt +++ b/pylibfdt/Makefile.pylibfdt @@ -9,16 +9,15 @@ PYLIBFDT_CLEANFILES = $(PYLIBFDT_CLEANFILES_L:%=$(PYLIBFDT_dir)/%) PYLIBFDT_CLEANDIRS_L = build __pycache__ PYLIBFDT_CLEANDIRS = $(PYLIBFDT_CLEANDIRS_L:%=$(PYLIBFDT_dir)/%) -SETUP = $(PYLIBFDT_dir)/setup.py -SETUPFLAGS = +SETUP = ./setup.py ifndef V SETUPFLAGS += --quiet endif -$(PYMODULE): $(PYLIBFDT_srcs) $(LIBFDT_archive) $(SETUP) $(VERSION_FILE) +$(PYMODULE): $(PYLIBFDT_srcs) $(LIBFDT_archive) $(SETUP) @$(VECHO) PYMOD $@ - $(PYTHON) $(SETUP) $(SETUPFLAGS) build_ext --build-lib=../$(PYLIBFDT_dir) + $(PYTHON) $(SETUP) $(SETUPFLAGS) build_ext --build-lib=$(PYLIBFDT_dir) install_pylibfdt: $(PYMODULE) @$(VECHO) INSTALL-PYLIB diff --git a/pylibfdt/libfdt.i b/pylibfdt/libfdt.i index 3e09d3a..f9f7e7e 100644 --- a/pylibfdt/libfdt.i +++ b/pylibfdt/libfdt.i @@ -443,6 +443,29 @@ class FdtRo(object): """ return fdt_get_alias(self._fdt, name) + def get_path(self, nodeoffset, quiet=()): + """Get the full path of a node + + Args: + nodeoffset: Node offset to check + + Returns: + Full path to the node + + Raises: + FdtException if an error occurs + """ + size = 1024 + while True: + ret, path = fdt_get_path(self._fdt, nodeoffset, size) + if ret == -NOSPACE: + size = size * 2 + continue + err = check_err(ret, quiet) + if err: + return err + return path + def parent_offset(self, nodeoffset, quiet=()): """Get the offset of a node's parent @@ -716,6 +739,21 @@ class Property(bytearray): def as_int64(self): return self.as_cell('q') + def as_list(self, fmt): + return list(map(lambda x: x[0], struct.iter_unpack('>' + fmt, self))) + + def as_uint32_list(self): + return self.as_list('L') + + def as_int32_list(self): + return self.as_list('l') + + def as_uint64_list(self): + return self.as_list('Q') + + def as_int64_list(self): + return self.as_list('q') + def as_str(self): """Unicode is supported by decoding from UTF-8""" if self[-1] != 0: @@ -724,6 +762,13 @@ class Property(bytearray): raise ValueError('Property contains embedded nul characters') return self[:-1].decode('utf-8') + def as_stringlist(self): + """Unicode is supported by decoding from UTF-8""" + if self[-1] != 0: + raise ValueError('Property lacks nul termination') + parts = self[:-1].split(b'\x00') + return list(map(lambda x: x.decode('utf-8'), parts)) + class FdtSw(FdtRo): """Software interface to create a device tree from scratch @@ -1009,7 +1054,7 @@ typedef uint32_t fdt32_t; } $1 = (void *)PyByteArray_AsString($input); fdt = $1; - fdt = fdt; /* avoid unused variable warning */ + (void)fdt; /* avoid unused variable warning */ } /* Some functions do change the device tree, so use void * */ @@ -1020,7 +1065,7 @@ typedef uint32_t fdt32_t; } $1 = PyByteArray_AsString($input); fdt = $1; - fdt = fdt; /* avoid unused variable warning */ + (void)fdt; /* avoid unused variable warning */ } /* typemap used for fdt_get_property_by_offset() */ @@ -1040,14 +1085,16 @@ typedef uint32_t fdt32_t; /* typemap used for fdt_getprop() */ %typemap(out) (const void *) { - if (!$1) + if (!$1) { $result = Py_None; - else + Py_INCREF($result); + } else { %#if PY_VERSION_HEX >= 0x03000000 - $result = Py_BuildValue("y#", $1, *arg4); + $result = Py_BuildValue("y#", $1, (Py_ssize_t)*arg4); %#else - $result = Py_BuildValue("s#", $1, *arg4); + $result = Py_BuildValue("s#", $1, (Py_ssize_t)*arg4); %#endif + } } /* typemap used for fdt_setprop() */ @@ -1091,6 +1138,11 @@ typedef uint32_t fdt32_t; } } +%include "cstring.i" + +%cstring_output_maxsize(char *buf, int buflen); +int fdt_get_path(const void *fdt, int nodeoffset, char *buf, int buflen); + /* We have both struct fdt_property and a function fdt_property() */ %warnfilter(302) fdt_property; diff --git a/pylibfdt/meson.build b/pylibfdt/meson.build new file mode 100644 index 0000000..f684cbb --- /dev/null +++ b/pylibfdt/meson.build @@ -0,0 +1,12 @@ +setup_py = find_program('../setup.py') +setup_py = [setup_py.path(), '--quiet', '--top-builddir', meson.project_build_root()] + +custom_target( + 'pylibfdt', + input: 'libfdt.i', + output: '_libfdt.so', + command: [setup_py, 'build_ext', '--build-lib=' + meson.current_build_dir()], + build_by_default: true, +) + +meson.add_install_script(setup_py, 'install', '--prefix=' + get_option('prefix'), '--root=$DESTDIR') diff --git a/pylibfdt/setup.py b/pylibfdt/setup.py deleted file mode 100755 index 53f2bef..0000000 --- a/pylibfdt/setup.py +++ /dev/null @@ -1,48 +0,0 @@ -#!/usr/bin/env python3 -# SPDX-License-Identifier: (GPL-2.0-or-later OR BSD-2-Clause) - -# While Python 3 is the default, it's also possible to invoke -# this setup.py script with Python 2. - -""" -setup.py file for SWIG libfdt -Copyright (C) 2017 Google, Inc. -Written by Simon Glass <sjg@chromium.org> -""" - -from distutils.core import setup, Extension -import os -import re -import sys - - -VERSION_PATTERN = '^#define DTC_VERSION "DTC ([^"]*)"$' - - -def get_version(): - version_file = "../version_gen.h" - f = open(version_file, 'rt') - m = re.match(VERSION_PATTERN, f.readline()) - return m.group(1) - - -setupdir = os.path.dirname(os.path.abspath(sys.argv[0])) -os.chdir(setupdir) - -libfdt_module = Extension( - '_libfdt', - sources=['libfdt.i'], - include_dirs=['../libfdt'], - libraries=['fdt'], - library_dirs=['../libfdt'], - swig_opts=['-I../libfdt'], -) - -setup( - name='libfdt', - version=get_version(), - author='Simon Glass <sjg@chromium.org>', - description='Python binding for libfdt', - ext_modules=[libfdt_module], - py_modules=['libfdt'], -) diff --git a/setup.py b/setup.py new file mode 100755 index 0000000..a8e54a3 --- /dev/null +++ b/setup.py @@ -0,0 +1,77 @@ +#!/usr/bin/env python3 +# SPDX-License-Identifier: (GPL-2.0-or-later OR BSD-2-Clause) + +# While Python 3 is the default, it's also possible to invoke +# this setup.py script with Python 2. + +""" +setup.py file for SWIG libfdt +Copyright (C) 2017 Google, Inc. +Written by Simon Glass <sjg@chromium.org> +""" + +from setuptools import setup, Extension +from setuptools.command.build_py import build_py as _build_py + +import os +import re +import sys + +srcdir = os.path.dirname(__file__) + +with open(os.path.join(srcdir, "README"), "r") as fh: + long_description = fh.read() + +def get_top_builddir(): + if '--top-builddir' in sys.argv: + index = sys.argv.index('--top-builddir') + sys.argv.pop(index) + return sys.argv.pop(index) + else: + return srcdir + +top_builddir = get_top_builddir() + +libfdt_module = Extension( + '_libfdt', + sources=[os.path.join(srcdir, 'pylibfdt/libfdt.i')], + define_macros=[('PY_SSIZE_T_CLEAN', None)], + include_dirs=[os.path.join(srcdir, 'libfdt')], + libraries=['fdt'], + library_dirs=[os.path.join(top_builddir, 'libfdt')], + swig_opts=['-I' + os.path.join(srcdir, 'libfdt')], +) + +class build_py(_build_py): + def run(self): + self.run_command("build_ext") + return super().run() + +setup( + name='libfdt', + use_scm_version={ + "root": srcdir, + }, + cmdclass = {'build_py' : build_py}, + setup_requires = ['setuptools_scm'], + author='Simon Glass', + author_email='sjg@chromium.org', + description='Python binding for libfdt', + ext_modules=[libfdt_module], + package_dir={'': os.path.join(srcdir, 'pylibfdt')}, + py_modules=['libfdt'], + + long_description=long_description, + long_description_content_type="text/plain", + url="https://git.kernel.org/pub/scm/utils/dtc/dtc.git", + license="BSD", + license_files=["GPL", "BSD-2-Clause"], + + classifiers=[ + "Programming Language :: Python :: 3", + "License :: OSI Approved :: BSD License", + "License :: OSI Approved :: GNU General Public License v2 or later (GPLv2+)", + "Operating System :: OS Independent", + ], + +) @@ -20,7 +20,7 @@ struct search_path { static struct search_path *search_path_head, **search_path_tail; /* Detect infinite include recursion. */ -#define MAX_SRCFILE_DEPTH (100) +#define MAX_SRCFILE_DEPTH (200) static int srcfile_depth; /* = 0 */ static char *get_dirname(const char *path) diff --git a/tests/.gitignore b/tests/.gitignore index d3f1434..03bdde2 100644 --- a/tests/.gitignore +++ b/tests/.gitignore @@ -54,6 +54,7 @@ tmp.* /property_iterate /propname_escapes /references +/relref_merge /root_node /rw_tree1 /rw_oom diff --git a/tests/Android.bp b/tests/Android.bp new file mode 100644 index 0000000..70fa746 --- /dev/null +++ b/tests/Android.bp @@ -0,0 +1,12 @@ +// Copyright 2022 The Android Open Source Project +package { + default_applicable_licenses: [ + "external_dtc_license", + "external_dtc_tests_license", + ], +} + +filegroup { + name: "external_dtc_tests", + srcs: ["**/*"], +} diff --git a/tests/Makefile.tests b/tests/Makefile.tests index cb66c9f..2d36c5d 100644 --- a/tests/Makefile.tests +++ b/tests/Makefile.tests @@ -18,7 +18,7 @@ LIB_TESTS_L = get_mem_rsv \ open_pack rw_tree1 rw_oom set_name setprop del_property del_node \ appendprop1 appendprop2 propname_escapes \ string_escapes references path-references phandle_format \ - boot-cpuid incbin \ + boot-cpuid incbin relref_merge \ extra-terminating-null \ dtbs_equal_ordered \ dtb_reverse dtbs_equal_unordered \ @@ -32,11 +32,15 @@ LIB_TESTS_L = get_mem_rsv \ fs_tree1 LIB_TESTS = $(LIB_TESTS_L:%=$(TESTS_PREFIX)%) -LIBTREE_TESTS_L = truncated_property truncated_string truncated_memrsv +LIBTREE_TESTS_L = truncated_property truncated_string truncated_memrsv \ + two_roots named_root + LIBTREE_TESTS = $(LIBTREE_TESTS_L:%=$(TESTS_PREFIX)%) -DL_LIB_TESTS_L = asm_tree_dump value-labels -DL_LIB_TESTS = $(DL_LIB_TESTS_L:%=$(TESTS_PREFIX)%) +ifneq ($(STATIC_BUILD),1) + DL_LIB_TESTS_L = asm_tree_dump value-labels + DL_LIB_TESTS = $(DL_LIB_TESTS_L:%=$(TESTS_PREFIX)%) +endif TESTS = $(LIB_TESTS) $(LIBTREE_TESTS) $(DL_LIB_TESTS) @@ -58,17 +62,17 @@ TESTS_CLEANDIRS = $(TESTS_CLEANDIRS_L:%=$(TESTS_PREFIX)%) .PHONY: tests tests: $(TESTS) $(TESTS_TREES) -$(LIB_TESTS): %: $(TESTS_PREFIX)testutils.o util.o $(LIBFDT_lib) +$(LIB_TESTS): %: $(TESTS_PREFIX)testutils.o util.o $(LIBFDT_dep) # Not necessary on all platforms; allow -ldl to be excluded instead of forcing # other platforms to patch it out. LIBDL = -ldl -$(DL_LIB_TESTS): %: %.o $(TESTS_PREFIX)testutils.o util.o $(LIBFDT_lib) +$(DL_LIB_TESTS): %: %.o $(TESTS_PREFIX)testutils.o util.o $(LIBFDT_dep) @$(VECHO) LD [libdl] $@ $(LINK.c) -o $@ $^ $(LIBDL) $(LIBTREE_TESTS): %: $(TESTS_PREFIX)testutils.o $(TESTS_PREFIX)trees.o \ - util.o $(LIBFDT_lib) + util.o $(LIBFDT_dep) $(TESTS_PREFIX)dumptrees: $(TESTS_PREFIX)trees.o diff --git a/tests/bad-interrupt-map-mask.dts b/tests/bad-interrupt-map-mask.dts new file mode 100644 index 0000000..10eaffd --- /dev/null +++ b/tests/bad-interrupt-map-mask.dts @@ -0,0 +1,20 @@ +/dts-v1/; + +/ { + interrupt-parent = <&intc>; + intc: interrupt-controller { + #interrupt-cells = <3>; + interrupt-controller; + }; + + node { + #address-cells = <0>; + #interrupt-cells = <1>; + interrupt-map = <1 &intc 1 2 3>; + interrupt-map-mask = <0 0>; + + child { + interrupts = <1>; + }; + }; +}; diff --git a/tests/bad-interrupt-map-parent.dts b/tests/bad-interrupt-map-parent.dts new file mode 100644 index 0000000..fe88ce2 --- /dev/null +++ b/tests/bad-interrupt-map-parent.dts @@ -0,0 +1,17 @@ +/dts-v1/; + +/ { + interrupt-parent = <&intc>; + intc: interrupt-controller { + }; + + node { + #address-cells = <0>; + #interrupt-cells = <1>; + interrupt-map = <1 &intc 1 2 3>; + + child { + interrupts = <1>; + }; + }; +}; diff --git a/tests/bad-interrupt-map.dts b/tests/bad-interrupt-map.dts new file mode 100644 index 0000000..6df8f93 --- /dev/null +++ b/tests/bad-interrupt-map.dts @@ -0,0 +1,19 @@ +/dts-v1/; + +/ { + interrupt-parent = <&intc>; + intc: interrupt-controller { + #interrupt-cells = <3>; + interrupt-controller; + }; + + node { + /* Missing #address-cells = <0>; */ + #interrupt-cells = <1>; + interrupt-map = <1 &intc 1 2 3>; + + child { + interrupts = <1>; + }; + }; +}; diff --git a/tests/base01.asm b/tests/base01.asm index 266e446..63f2eca 100644 --- a/tests/base01.asm +++ b/tests/base01.asm @@ -32,7 +32,7 @@ _dt_reserve_map: dt_struct_start: _dt_struct_start: .long OF_DT_BEGIN_NODE - .string "" + .asciz "" .balign 4 .long OF_DT_PROP .long 0xa @@ -58,7 +58,7 @@ _dt_struct_start: .long 0x2 .balign 4 .long OF_DT_BEGIN_NODE - .string "memory@0" + .asciz "memory@0" .balign 4 .long OF_DT_PROP .long 0x7 @@ -77,7 +77,7 @@ _dt_struct_start: .balign 4 .long OF_DT_END_NODE .long OF_DT_BEGIN_NODE - .string "cpus" + .asciz "cpus" .balign 4 .long OF_DT_PROP .long 0x4 @@ -151,22 +151,22 @@ _dt_struct_end: .globl dt_strings_start dt_strings_start: _dt_strings_start: - .string "model" - .string "compatible" - .string "#address-cells" - .string "#size-cells" - .string "device_type" - .string "reg" - .string "d10" - .string "d23" - .string "b101" - .string "o17" - .string "hd00d" - .string "stuff" - .string "bad-d-1" - .string "bad-d-2" - .string "bad-o-1" - .string "bad-o-2" + .asciz "model" + .asciz "compatible" + .asciz "#address-cells" + .asciz "#size-cells" + .asciz "device_type" + .asciz "reg" + .asciz "d10" + .asciz "d23" + .asciz "b101" + .asciz "o17" + .asciz "hd00d" + .asciz "stuff" + .asciz "bad-d-1" + .asciz "bad-d-2" + .asciz "bad-o-1" + .asciz "bad-o-2" .globl dt_strings_end dt_strings_end: _dt_strings_end: diff --git a/tests/dumptrees.c b/tests/dumptrees.c index aecb326..08967b3 100644 --- a/tests/dumptrees.c +++ b/tests/dumptrees.c @@ -24,13 +24,15 @@ static struct { TREE(ovf_size_strings), TREE(truncated_property), TREE(truncated_string), TREE(truncated_memrsv), + TREE(two_roots), + TREE(named_root) }; #define NUM_TREES (sizeof(trees) / sizeof(trees[0])) int main(int argc, char *argv[]) { - int i; + unsigned int i; if (argc != 2) { fprintf(stderr, "Missing output directory argument\n"); diff --git a/tests/fs_tree1.c b/tests/fs_tree1.c index dff3880..978f6a3 100644 --- a/tests/fs_tree1.c +++ b/tests/fs_tree1.c @@ -54,7 +54,7 @@ static void mkfile(const char *name, void *data, size_t len) rc = write(fd, data, len); if (rc < 0) FAIL("write(\"%s\"): %s", name, strerror(errno)); - if (rc != len) + if ((unsigned)rc != len) FAIL("write(\"%s\"): short write", name); rc = close(fd); diff --git a/tests/get_name.c b/tests/get_name.c index 5a35103..d20bf30 100644 --- a/tests/get_name.c +++ b/tests/get_name.c @@ -34,12 +34,14 @@ static void check_name(void *fdt, const char *path) offset, getname, len); if (!getname) FAIL("fdt_get_name(%d): %s", offset, fdt_strerror(len)); + if (len < 0) + FAIL("negative name length (%d) for returned node name\n", len); if (strcmp(getname, checkname) != 0) FAIL("fdt_get_name(%s) returned \"%s\" instead of \"%s\"", path, getname, checkname); - if (len != strlen(getname)) + if ((unsigned)len != strlen(getname)) FAIL("fdt_get_name(%s) returned length %d instead of %zd", path, len, strlen(getname)); diff --git a/tests/good-gpio.dts b/tests/good-gpio.dts new file mode 100644 index 0000000..65d1c17 --- /dev/null +++ b/tests/good-gpio.dts @@ -0,0 +1,12 @@ +/dts-v1/; + +/ { + gpio: gpio-controller { + #gpio-cells = <3>; + }; + + node { + foo,nr-gpios = <1>; + foo-gpios = <&gpio 1 2 3>; + }; +}; diff --git a/tests/integer-expressions.c b/tests/integer-expressions.c index 6f33d81..2f164d9 100644 --- a/tests/integer-expressions.c +++ b/tests/integer-expressions.c @@ -59,7 +59,7 @@ int main(int argc, char *argv[]) void *fdt; const fdt32_t *res; int reslen; - int i; + unsigned int i; test_init(argc, argv); diff --git a/tests/meson.build b/tests/meson.build new file mode 100644 index 0000000..4ac154a --- /dev/null +++ b/tests/meson.build @@ -0,0 +1,137 @@ +trees = static_library('trees', files('trees.S'), c_args: '-D__ASSEMBLY__', + include_directories: libfdt_inc) + +dumptrees = executable('dumptrees', files('dumptrees.c'), + link_with: trees, dependencies: libfdt_dep) + +dumptrees_dtb = custom_target( + 'dumptrees', + command: [dumptrees, meson.current_build_dir()], + output: [ + 'test_tree1.dtb', + 'bad_node_char.dtb', + 'bad_node_format.dtb', + 'bad_prop_char.dtb', + 'ovf_size_strings.dtb', + 'truncated_property.dtb', + 'truncated_string.dtb', + 'truncated_memrsv.dtb', + ] +) + +testutil_dep = declare_dependency(sources: ['testutils.c'], link_with: trees) + +tests = [ + 'add_subnode_with_nops', + 'addr_size_cells', + 'addr_size_cells2', + 'appendprop1', + 'appendprop2', + 'appendprop_addrrange', + 'boot-cpuid', + 'char_literal', + 'check_full', + 'check_header', + 'check_path', + 'del_node', + 'del_property', + 'dtb_reverse', + 'dtbs_equal_ordered', + 'dtbs_equal_unordered', + 'extra-terminating-null', + 'find_property', + 'fs_tree1', + 'get_alias', + 'get_mem_rsv', + 'get_name', + 'get_path', + 'get_phandle', + 'get_prop_offset', + 'getprop', + 'incbin', + 'integer-expressions', + 'mangle-layout', + 'move_and_save', + 'node_check_compatible', + 'node_offset_by_compatible', + 'node_offset_by_phandle', + 'node_offset_by_prop_value', + 'nop_node', + 'nop_property', + 'nopulate', + 'notfound', + 'open_pack', + 'overlay', + 'overlay_bad_fixup', + 'parent_offset', + 'path-references', + 'path_offset', + 'path_offset_aliases', + 'phandle_format', + 'property_iterate', + 'propname_escapes', + 'references', + 'relref_merge', + 'root_node', + 'rw_oom', + 'rw_tree1', + 'set_name', + 'setprop', + 'setprop_inplace', + 'sized_cells', + 'string_escapes', + 'stringlist', + 'subnode_iterate', + 'subnode_offset', + 'supernode_atdepth_offset', + 'sw_states', + 'sw_tree1', + 'utilfdt_test', +] + +tests += [ + 'truncated_memrsv', + 'truncated_property', + 'truncated_string', +] + +dl = cc.find_library('dl', required: false) +if dl.found() and not static_build + tests += [ + 'asm_tree_dump', + 'value-labels', + ] +endif + +test_deps = [testutil_dep, util_dep, libfdt_dep] +if not static_build + test_deps += [dl] +endif + +foreach t: tests + executable(t, files(t + '.c'), dependencies: test_deps, link_args: extra_link_args) +endforeach + +run_tests = find_program('run_tests.sh') + +env = [] +if not py.found() + env += 'NO_PYTHON=1' +else + env += [ + 'PYTHON=' + py.path(), + 'PYTHONPATH=' + meson.source_root() / 'pylibfdt', + ] +endif +if not yaml.found() + env += 'NO_YAML=1' +endif + +test( + 'run-test', + run_tests, + workdir: meson.current_build_dir(), + depends: dumptrees_dtb, + env: env, + timeout: 1800, # mostly for valgrind +) diff --git a/tests/nopulate.c b/tests/nopulate.c index 2ae1753..e06a0b3 100644 --- a/tests/nopulate.c +++ b/tests/nopulate.c @@ -43,7 +43,8 @@ static int nopulate_struct(char *buf, const char *fdt) int main(int argc, char *argv[]) { char *fdt, *fdt2, *buf; - int newsize, struct_start, struct_end_old, struct_end_new, delta; + int newsize, struct_end_old, struct_end_new, delta; + unsigned int struct_start; const char *inname; char outname[PATH_MAX]; diff --git a/tests/overlay.c b/tests/overlay.c index 91afa72..f3dd310 100644 --- a/tests/overlay.c +++ b/tests/overlay.c @@ -35,7 +35,11 @@ static int fdt_getprop_u32_by_poffset(void *fdt, const char *path, return node_off; val = fdt_getprop(fdt, node_off, name, &len); - if (!val || (len < (sizeof(uint32_t) * (poffset + 1)))) + if (val && len < 0) + FAIL("fdt_getprop() returns negative length"); + if (!val && len < 0) + return len; + if (!val || ((unsigned)len < (sizeof(uint32_t) * (poffset + 1)))) return -FDT_ERR_NOTFOUND; *out = fdt32_to_cpu(*(val + poffset)); diff --git a/tests/overlay_overlay_nosugar.dts b/tests/overlay_overlay_nosugar.dts index b6d841b..b5947e9 100644 --- a/tests/overlay_overlay_nosugar.dts +++ b/tests/overlay_overlay_nosugar.dts @@ -48,7 +48,7 @@ }; }; - fragment@5 { + fragment@4 { target = <&test>; __overlay__ { @@ -58,7 +58,7 @@ }; }; - fragment@6 { + fragment@5 { target = <&test>; __overlay__ { @@ -66,7 +66,7 @@ }; }; - fragment@7 { + fragment@6 { target = <&test>; __overlay__ { @@ -74,7 +74,7 @@ }; }; - fragment@8 { + fragment@7 { target = <&test>; __overlay__ { diff --git a/tests/path-references.c b/tests/path-references.c index 4db61a5..b914576 100644 --- a/tests/path-references.c +++ b/tests/path-references.c @@ -53,7 +53,7 @@ int main(int argc, char *argv[]) void *fdt; const char *p; int len, multilen; - int n1, n2, n3, n4; + int n1, n2, n3, n4, n5; test_init(argc, argv); fdt = load_blob_arg(argc, argv); @@ -89,6 +89,12 @@ int main(int argc, char *argv[]) check_ref(fdt, n3, "/foobar/baz"); check_ref(fdt, n4, "/foo/baz"); + n5 = fdt_path_offset(fdt, "/bar/baz"); + if (n5 < 0) + FAIL("fdt_path_offset(/bar/baz): %s", fdt_strerror(n5)); + + check_ref(fdt, n5, "/bar/baz"); + check_rref(fdt); PASS(); diff --git a/tests/path-references.dts b/tests/path-references.dts index 1fb7d70..dd9ccfc 100644 --- a/tests/path-references.dts +++ b/tests/path-references.dts @@ -25,4 +25,13 @@ lref = &n3; }; }; + n5: bar { + baz { + }; + }; +}; + +n6: &{n5/baz} { + ref = &{n6/}; + lref = &{n5/baz}; }; diff --git a/tests/phandle-args-overflow.dts b/tests/phandle-args-overflow.dts new file mode 100644 index 0000000..8c8c5d7 --- /dev/null +++ b/tests/phandle-args-overflow.dts @@ -0,0 +1,18 @@ +/dts-v1/; + +/* + * https://github.com/dgibson/dtc/issues/64 + * + * Certain dtc versions had a bug where this input caused an infinite + * loop in check_property_phandle_args(). + * + */ + +/ { + clocks = <&ref &ref>; + + ref: poc { + phandle = <1>; + #clock-cells = <0xffffffff>; + }; +}; diff --git a/tests/phandle_format.c b/tests/phandle_format.c index d00618f..0febb32 100644 --- a/tests/phandle_format.c +++ b/tests/phandle_format.c @@ -45,7 +45,7 @@ int main(int argc, char *argv[]) FAIL("fdt_path_offset(/node4): %s", fdt_strerror(n4)); h4 = fdt_get_phandle(fdt, n4); - if ((h4 == 0) || (h4 == -1)) + if ((h4 == 0) || (h4 == ~0U)) FAIL("/node4 has bad phandle 0x%x\n", h4); if (phandle_format & PHANDLE_LEGACY) diff --git a/tests/property_iterate.c b/tests/property_iterate.c index 9a67f49..0b6af9b 100644 --- a/tests/property_iterate.c +++ b/tests/property_iterate.c @@ -23,7 +23,7 @@ static void test_node(void *fdt, int parent_offset) uint32_t properties; const fdt32_t *prop; int offset, property; - int count; + unsigned int count; int len; /* diff --git a/tests/pylibfdt_tests.py b/tests/pylibfdt_tests.py index 64b5bd1..68d6aaa 100644 --- a/tests/pylibfdt_tests.py +++ b/tests/pylibfdt_tests.py @@ -348,6 +348,19 @@ class PyLibfdtBasicTests(unittest.TestCase): self.assertEqual("/subnode@1/subsubnode", self.fdt3.get_alias('ss1')) self.assertEqual("/subnode@1/subsubnode/subsubsubnode", self.fdt3.get_alias('sss1')) + def testGetPath(self): + """Test for the get_path() method""" + node = self.fdt.path_offset('/subnode@1') + node2 = self.fdt.path_offset('/subnode@1/subsubnode') + self.assertEqual("/subnode@1", self.fdt.get_path(node)) + self.assertEqual("/subnode@1/subsubnode", self.fdt.get_path(node2)) + + with self.assertRaises(FdtException) as e: + self.fdt.get_path(-1) + self.assertEqual(e.exception.err, -libfdt.BADOFFSET) + + self.assertEqual(-libfdt.BADOFFSET, self.fdt.get_path(-1, quiet=(libfdt.BADOFFSET,))) + def testParentOffset(self): """Test for the parent_offset() method""" self.assertEqual(-libfdt.NOTFOUND, @@ -382,6 +395,25 @@ class PyLibfdtBasicTests(unittest.TestCase): self.get_prop("prop-uint64").as_uint64()) self.assertEqual(-2, self.get_prop("prop-int64").as_int64()) + def testGetIntListProperties(self): + """Test that we can access properties as integer lists""" + self.assertEqual([128, -16, -2], + self.get_prop("prop-int32-array").as_int32_list()) + self.assertEqual([0x1, 0x98765432, 0xdeadbeef], + self.get_prop("prop-uint32-array").as_uint32_list()) + self.assertEqual([0x100000000, -2], + self.get_prop("prop-int64-array").as_int64_list()) + self.assertEqual([0x100000000, 0x1], + self.get_prop("prop-uint64-array").as_uint64_list()) + + def testGetStringlistProperties(self): + """Test that we can access properties as string list""" + node = self.fdt.path_offset('/subnode@1/subsubnode') + self.assertEqual(["subsubnode1", "subsubnode"], + self.fdt.getprop(node, "compatible").as_stringlist()) + self.assertEqual(["this is a placeholder string", "string2"], + self.fdt.getprop(node, "placeholder").as_stringlist()) + def testReserveMap(self): """Test that we can access the memory reserve map""" self.assertEqual(2, self.fdt.num_mem_rsv()) diff --git a/tests/references.c b/tests/references.c index d18e722..cb1daaa 100644 --- a/tests/references.c +++ b/tests/references.c @@ -106,7 +106,7 @@ int main(int argc, char *argv[]) if ((h4 == 0x2000) || (h4 == 0x1) || (h4 == 0)) FAIL("/node4 has bad phandle, 0x%x", h4); - if ((h5 == 0) || (h5 == -1)) + if ((h5 == 0) || (h5 == ~0U)) FAIL("/node5 has bad phandle, 0x%x", h5); if ((h5 == h4) || (h5 == h2) || (h5 == h1)) FAIL("/node5 has duplicate phandle, 0x%x", h5); diff --git a/tests/relref_merge.c b/tests/relref_merge.c new file mode 100644 index 0000000..5daab2e --- /dev/null +++ b/tests/relref_merge.c @@ -0,0 +1,51 @@ +// SPDX-License-Identifier: LGPL-2.1-or-later +/* + * libfdt - Flat Device Tree manipulation + * Testcase for label relative child references in dtc + * Copyright (C) 2006 David Gibson, IBM Corporation. + * Copyright (C) 2020 Ahmad Fatoum, Pengutronix. + */ +#include <stdlib.h> +#include <stdio.h> +#include <string.h> +#include <stdint.h> + +#include <libfdt.h> + +#include "tests.h" +#include "testdata.h" + +static void check_exist(void *fdt, const char *path) +{ + int sn = fdt_path_offset(fdt, path); + if (sn < 0) + FAIL("%s expected but not found: %s", path, fdt_strerror(sn)); +} + +static void check_doesnt_exist(void *fdt, const char *path) +{ + int sn = fdt_path_offset(fdt, path); + if (sn >= 0) + FAIL("%s found but not expected %d", path, sn); +} + +int main(int argc, char *argv[]) +{ + void *fdt; + + test_init(argc, argv); + fdt = load_blob_arg(argc, argv); + + check_exist(fdt, "/node/subnode1"); + check_exist(fdt, "/node/keep-me"); + check_doesnt_exist(fdt, "/node/remove-me"); + + check_doesnt_exist(fdt, "/node2"); + check_doesnt_exist(fdt, "/node/subnode3"); + + check_exist(fdt, "/node/subnode4"); + + check_exist(fdt, "/node/subnode1/add-me"); + + PASS(); +} diff --git a/tests/relref_merge.dts b/tests/relref_merge.dts new file mode 100644 index 0000000..d8660eb --- /dev/null +++ b/tests/relref_merge.dts @@ -0,0 +1,40 @@ +/dts-v1/; + +/ { + node_label: node { + keep-me {}; + remove-me {}; + + subnode1 { + property-inline1; + property-inline2; + property-inline3; + }; + + subnode2 { + property-inline1; + }; + + subnode3 { + property-inline1; + }; + }; + + node2_label: node2 { + property-inline1; + }; +}; +/omit-if-no-ref/ &{node_label/subnode1}; +/omit-if-no-ref/ &node2_label; +/delete-node/ &{node_label/subnode3}; + +&{node_label/} { + /delete-node/ remove-me; + + subnode4 { }; +}; + +label: &{node_label/subnode1} { + selfref = &{node_label/subnode1}; + add-me { }; +}; diff --git a/tests/run_tests.sh b/tests/run_tests.sh index 294585b..0cabd13 100755 --- a/tests/run_tests.sh +++ b/tests/run_tests.sh @@ -195,7 +195,7 @@ asm_to_so_test () { run_fdtget_test () { expect="$1" shift - printf "fdtget-runtest.sh %s $*: " "$(echo $expect)" + printf "fdtget-runtest.sh \"%s\" $*: " "$expect" base_run_test sh "$SRCDIR/fdtget-runtest.sh" "$expect" "$@" } @@ -288,7 +288,7 @@ dtc_overlay_tests () { run_test check_path overlay_overlay.test.dtb exists "/__local_fixups__" # Without syntactic sugar - run_dtc_test -I dts -O dtb -o overlay_overlay_nosugar.test.dtb "$SRCDIR/overlay_overlay.dts" + run_dtc_test -I dts -O dtb -o overlay_overlay_nosugar.test.dtb "$SRCDIR/overlay_overlay_nosugar.dts" run_test check_path overlay_overlay_nosugar.test.dtb not-exists "/__symbols__" run_test check_path overlay_overlay_nosugar.test.dtb exists "/__fixups__" run_test check_path overlay_overlay_nosugar.test.dtb exists "/__local_fixups__" @@ -513,12 +513,15 @@ libfdt_tests () { run_dtc_test -I fs -O dtb -o fs.test_tree1.test.dtb $FSBASE/test_tree1 run_test dtbs_equal_unordered -m fs.test_tree1.test.dtb test_tree1.dtb + ## https://github.com/dgibson/dtc/issues/64 + check_tests "$SRCDIR/phandle-args-overflow.dts" clocks_property + # check full tests for good in test_tree1.dtb; do run_test check_full $good done for bad in truncated_property.dtb truncated_string.dtb \ - truncated_memrsv.dtb; do + truncated_memrsv.dtb two_roots.dtb named_root.dtb; do run_test check_full -n $bad done } @@ -604,11 +607,15 @@ dtc_tests () { run_dtc_test -I dts -O asm -o oasm_$tree.test.s "$SRCDIR/$tree" asm_to_so_test oasm_$tree run_dtc_test -I dts -O dtb -o $tree.test.dtb "$SRCDIR/$tree" - run_test asm_tree_dump ./oasm_$tree.test.so oasm_$tree.test.dtb - run_wrap_test cmp oasm_$tree.test.dtb $tree.test.dtb + if [ -x ./asm_tree_dump ]; then + run_test asm_tree_dump ./oasm_$tree.test.so oasm_$tree.test.dtb + run_wrap_test cmp oasm_$tree.test.dtb $tree.test.dtb + fi done - run_test value-labels ./oasm_value-labels.dts.test.so + if [ -x ./value-labels ]; then + run_test value-labels ./oasm_value-labels.dts.test.so + fi # Check -Odts mode preserve all dtb information for tree in test_tree1.dtb dtc_tree1.test.dtb dtc_escapes.test.dtb \ @@ -666,6 +673,9 @@ dtc_tests () { tree1_tests dtc_tree1_merge_path.test.dtb test_tree1.dtb run_wrap_error_test $DTC -I dts -O dtb -o /dev/null "$SRCDIR/test_label_ref.dts" + run_dtc_test -I dts -O dtb -o dtc_relref_merge.test.dtb "$SRCDIR/relref_merge.dts" + run_test relref_merge dtc_relref_merge.test.dtb + # Check prop/node delete functionality run_dtc_test -I dts -O dtb -o dtc_tree1_delete.test.dtb "$SRCDIR/test_tree1_delete.dts" tree1_tests dtc_tree1_delete.test.dtb @@ -691,7 +701,7 @@ dtc_tests () { run_sh_test "$SRCDIR/dtc-fatal.sh" -I dts -O dtb "$SRCDIR/nonexist-node-ref2.dts" check_tests "$SRCDIR/bad-name-property.dts" name_properties - check_tests "$SRCDIR/bad-ncells.dts" address_cells_is_cell size_cells_is_cell interrupt_cells_is_cell + check_tests "$SRCDIR/bad-ncells.dts" address_cells_is_cell size_cells_is_cell interrupts_extended_is_cell check_tests "$SRCDIR/bad-string-props.dts" device_type_is_string model_is_string status_is_string label_is_string compatible_is_string_list names_is_string_list check_tests "$SRCDIR/bad-chosen.dts" chosen_node_is_root check_tests "$SRCDIR/bad-chosen.dts" chosen_node_bootargs @@ -709,12 +719,17 @@ dtc_tests () { check_tests "$SRCDIR/unit-addr-unique.dts" unique_unit_address check_tests "$SRCDIR/bad-phandle-cells.dts" interrupts_extended_property check_tests "$SRCDIR/bad-gpio.dts" gpios_property + check_tests "$SRCDIR/good-gpio.dts" -n gpios_property check_tests "$SRCDIR/bad-graph.dts" graph_child_address check_tests "$SRCDIR/bad-graph.dts" graph_port check_tests "$SRCDIR/bad-graph.dts" graph_endpoint run_sh_test "$SRCDIR/dtc-checkfails.sh" deprecated_gpio_property -- -Wdeprecated_gpio_property -I dts -O dtb "$SRCDIR/bad-gpio.dts" + run_sh_test "$SRCDIR/dtc-checkfails.sh" -n deprecated_gpio_property -- -Wdeprecated_gpio_property -I dts -O dtb "$SRCDIR/good-gpio.dts" check_tests "$SRCDIR/bad-interrupt-cells.dts" interrupts_property check_tests "$SRCDIR/bad-interrupt-controller.dts" interrupt_provider + check_tests "$SRCDIR/bad-interrupt-map.dts" interrupt_map + check_tests "$SRCDIR/bad-interrupt-map-parent.dts" interrupt_map + check_tests "$SRCDIR/bad-interrupt-map-mask.dts" interrupt_map run_sh_test "$SRCDIR/dtc-checkfails.sh" node_name_chars -- -I dtb -O dtb bad_node_char.dtb run_sh_test "$SRCDIR/dtc-checkfails.sh" node_name_format -- -I dtb -O dtb bad_node_format.dtb run_sh_test "$SRCDIR/dtc-checkfails.sh" property_name_chars -- -I dtb -O dtb bad_prop_char.dtb @@ -738,7 +753,7 @@ dtc_tests () { # Check warning options - run_sh_test "$SRCDIR/dtc-checkfails.sh" address_cells_is_cell interrupt_cells_is_cell -n size_cells_is_cell -- -Wno_size_cells_is_cell -I dts -O dtb "$SRCDIR/bad-ncells.dts" + run_sh_test "$SRCDIR/dtc-checkfails.sh" address_cells_is_cell interrupts_extended_is_cell -n size_cells_is_cell -- -Wno_size_cells_is_cell -I dts -O dtb "$SRCDIR/bad-ncells.dts" run_sh_test "$SRCDIR/dtc-fails.sh" -n test-warn-output.test.dtb -I dts -O dtb "$SRCDIR/bad-ncells.dts" run_sh_test "$SRCDIR/dtc-fails.sh" test-error-output.test.dtb -I dts -O dtb bad-ncells.dts -Esize_cells_is_cell run_sh_test "$SRCDIR/dtc-checkfails.sh" always_fail -- -Walways_fail -I dts -O dtb "$SRCDIR/test_tree1.dts" @@ -850,6 +865,8 @@ fdtget_tests () { run_fdtget_test 8000 -tx $dtb /cpus/PowerPC,970@1 d-cache-size run_fdtget_test "61 62 63 0" -tbx $dtb /randomnode tricky1 run_fdtget_test "a b c d de ea ad be ef" -tbx $dtb /randomnode blob + run_fdtget_test "MyBoardName\0MyBoardFamilyName\0" -tr $dtb / compatible + run_fdtget_test "\012\013\014\015\336\352\255\276\357" -tr $dtb /randomnode blob # Here the property size is not a multiple of 4 bytes, so it should fail run_wrap_error_test $DTGET -tlx $dtb /randomnode mixed diff --git a/tests/set_name.c b/tests/set_name.c index a62cb58..5020305 100644 --- a/tests/set_name.c +++ b/tests/set_name.c @@ -39,7 +39,11 @@ static void check_set_name(void *fdt, const char *path, const char *newname) FAIL("fdt_get_name(%s) returned \"%s\" instead of \"%s\"", path, getname, oldname); - if (len != strlen(getname)) + if (len < 0) + FAIL("fdt_get_name(%s) returned negative length: %d", + path, len); + + if ((unsigned)len != strlen(getname)) FAIL("fdt_get_name(%s) returned length %d instead of %zd", path, len, strlen(getname)); @@ -51,12 +55,14 @@ static void check_set_name(void *fdt, const char *path, const char *newname) getname = fdt_get_name(fdt, offset, &len); if (!getname) FAIL("fdt_get_name(%d): %s", offset, fdt_strerror(len)); + if (len < 0) + FAIL("negative name length (%d) for returned node name\n", len); if (strcmp(getname, newname) != 0) FAIL("fdt_get_name(%s) returned \"%s\" instead of \"%s\"", path, getname, newname); - if (len != strlen(getname)) + if ((unsigned)len != strlen(getname)) FAIL("fdt_get_name(%s) returned length %d instead of %zd", path, len, strlen(getname)); } diff --git a/tests/setprop_inplace.c b/tests/setprop_inplace.c index 7e1198d..61a0da1 100644 --- a/tests/setprop_inplace.c +++ b/tests/setprop_inplace.c @@ -58,7 +58,7 @@ int main(int argc, char *argv[]) TEST_STRING_1); verbose_printf("Old string value was \"%s\"\n", strp); - xstr = strdup(strp); + xstr = xstrdup(strp); xlen = strlen(xstr); for (i = 0; i < xlen; i++) xstr[i] = toupper(xstr[i]); diff --git a/tests/subnode_iterate.c b/tests/subnode_iterate.c index 2dc9b2d..2553a51 100644 --- a/tests/subnode_iterate.c +++ b/tests/subnode_iterate.c @@ -23,7 +23,7 @@ static void test_node(void *fdt, int parent_offset) uint32_t subnodes; const fdt32_t *prop; int offset; - int count; + unsigned int count; int len; /* This property indicates the number of subnodes to expect */ diff --git a/tests/test01.asm b/tests/test01.asm index bbf66c7..73fa603 100644 --- a/tests/test01.asm +++ b/tests/test01.asm @@ -44,7 +44,7 @@ _dt_reserve_map: dt_struct_start: _dt_struct_start: .long OF_DT_BEGIN_NODE - .string "" + .asciz "" .balign 4 .long OF_DT_PROP .long 0xc @@ -76,7 +76,7 @@ _dt_struct_start: .long 0x2 .balign 4 .long OF_DT_BEGIN_NODE - .string "cpus" + .asciz "cpus" .balign 4 .long OF_DT_PROP .long 0x4 @@ -94,7 +94,7 @@ _dt_struct_start: .long 0x0 .balign 4 .long OF_DT_BEGIN_NODE - .string "PowerPC,970@0" + .asciz "PowerPC,970@0" .balign 4 .long OF_DT_PROP .long 0xc @@ -139,7 +139,7 @@ _dt_struct_start: .balign 4 .long OF_DT_END_NODE .long OF_DT_BEGIN_NODE - .string "PowerPC,970@1" + .asciz "PowerPC,970@1" .balign 4 .long OF_DT_PROP .long 0xc @@ -181,7 +181,7 @@ _dt_struct_start: .long OF_DT_END_NODE .long OF_DT_END_NODE .long OF_DT_BEGIN_NODE - .string "randomnode" + .asciz "randomnode" .balign 4 .long OF_DT_PROP .long 0x13 @@ -216,7 +216,7 @@ _dt_struct_start: .balign 4 .long OF_DT_END_NODE .long OF_DT_BEGIN_NODE - .string "memory@0" + .asciz "memory@0" .balign 4 .long OF_DT_PROP .long 0x7 @@ -242,7 +242,7 @@ memreg: .balign 4 .long OF_DT_END_NODE .long OF_DT_BEGIN_NODE - .string "chosen" + .asciz "chosen" .balign 4 .long OF_DT_PROP .long 0xf @@ -267,25 +267,25 @@ _dt_struct_end: .globl dt_strings_start dt_strings_start: _dt_strings_start: - .string "model" - .string "compatible" - .string "#address-cells" - .string "#size-cells" - .string "linux,phandle" - .string "name" - .string "device_type" - .string "reg" - .string "clock-frequency" - .string "timebase-frequency" - .string "linux,boot-cpu" - .string "i-cache-size" - .string "d-cache-size" - .string "string" - .string "blob" - .string "ref" - .string "mixed" - .string "bootargs" - .string "linux,platform" + .asciz "model" + .asciz "compatible" + .asciz "#address-cells" + .asciz "#size-cells" + .asciz "linux,phandle" + .asciz "name" + .asciz "device_type" + .asciz "reg" + .asciz "clock-frequency" + .asciz "timebase-frequency" + .asciz "linux,boot-cpu" + .asciz "i-cache-size" + .asciz "d-cache-size" + .asciz "string" + .asciz "blob" + .asciz "ref" + .asciz "mixed" + .asciz "bootargs" + .asciz "linux,platform" .globl dt_strings_end dt_strings_end: _dt_strings_end: diff --git a/tests/test_props.dts b/tests/test_props.dts index 7e59bd1..5089023 100644 --- a/tests/test_props.dts +++ b/tests/test_props.dts @@ -8,4 +8,8 @@ prop-hex64 = /bits/ 64 <0xdeadbeef01abcdef>; prop-uint64 = /bits/ 64 <9223372036854775807>; prop-int64 = /bits/ 64 <0xfffffffffffffffe>; + prop-int32-array = <128>, <(-16)>, <0xfffffffe>; + prop-uint32-array = <0x1>, <0x98765432>, <0xdeadbeef>; + prop-int64-array = /bits/ 64 <0x100000000 0xfffffffffffffffe>; + prop-uint64-array = /bits/ 64 <0x100000000 0x1>; }; diff --git a/tests/testdata.h b/tests/testdata.h index 0d08efb..4f9e3ba 100644 --- a/tests/testdata.h +++ b/tests/testdata.h @@ -55,4 +55,6 @@ extern struct fdt_header bad_prop_char; extern struct fdt_header ovf_size_strings; extern struct fdt_header truncated_string; extern struct fdt_header truncated_memrsv; +extern struct fdt_header two_roots; +extern struct fdt_header named_root; #endif /* ! __ASSEMBLY */ diff --git a/tests/tests.h b/tests/tests.h index 1017366..bf8f23c 100644 --- a/tests/tests.h +++ b/tests/tests.h @@ -83,7 +83,7 @@ void cleanup(void); void check_mem_rsv(void *fdt, int n, uint64_t addr, uint64_t size); void check_property(void *fdt, int nodeoffset, const char *name, - int len, const void *val); + unsigned int len, const void *val); #define check_property_cell(fdt, nodeoffset, name, val) \ ({ \ fdt32_t x = cpu_to_fdt32(val); \ diff --git a/tests/testutils.c b/tests/testutils.c index 5e494c5..10129c0 100644 --- a/tests/testutils.c +++ b/tests/testutils.c @@ -88,7 +88,7 @@ void check_mem_rsv(void *fdt, int n, uint64_t addr, uint64_t size) } void check_property(void *fdt, int nodeoffset, const char *name, - int len, const void *val) + unsigned int len, const void *val) { const struct fdt_property *prop; int retlen, namelen; @@ -101,6 +101,9 @@ void check_property(void *fdt, int nodeoffset, const char *name, if (! prop) FAIL("Error retrieving \"%s\" pointer: %s", name, fdt_strerror(retlen)); + if (retlen < 0) + FAIL("negative name length (%d) for returned property\n", + retlen); tag = fdt32_to_cpu(prop->tag); nameoff = fdt32_to_cpu(prop->nameoff); @@ -112,13 +115,16 @@ void check_property(void *fdt, int nodeoffset, const char *name, propname = fdt_get_string(fdt, nameoff, &namelen); if (!propname) FAIL("Couldn't get property name: %s", fdt_strerror(namelen)); - if (namelen != strlen(propname)) + if (namelen < 0) + FAIL("negative name length (%d) for returned string\n", + namelen); + if ((unsigned)namelen != strlen(propname)) FAIL("Incorrect prop name length: %d instead of %zd", namelen, strlen(propname)); if (!streq(propname, name)) FAIL("Property name mismatch \"%s\" instead of \"%s\"", propname, name); - if (proplen != retlen) + if (proplen != (unsigned)retlen) FAIL("Length retrieved for \"%s\" by fdt_get_property()" " differs from stored length (%d != %d)", name, retlen, proplen); diff --git a/tests/trees.S b/tests/trees.S index efab287..d69f7f1 100644 --- a/tests/trees.S +++ b/tests/trees.S @@ -1,174 +1,187 @@ #include <fdt.h> #include "testdata.h" -#define FDTLONG(val) \ - .byte ((val) >> 24) & 0xff ; \ - .byte ((val) >> 16) & 0xff ; \ - .byte ((val) >> 8) & 0xff ; \ - .byte (val) & 0xff ; - -#define TREE_HDR(tree) \ - .balign 8 ; \ - .globl tree ; \ -tree: \ - FDTLONG(FDT_MAGIC) ; \ - FDTLONG(tree##_end - tree) ; \ - FDTLONG(tree##_struct - tree) ; \ - FDTLONG(tree##_strings - tree) ; \ - FDTLONG(tree##_rsvmap - tree) ; \ - FDTLONG(0x11) ; \ - FDTLONG(0x10) ; \ - FDTLONG(0) ; \ - FDTLONG(tree##_strings_end - tree##_strings) ; \ - FDTLONG(tree##_struct_end - tree##_struct) ; - -#define RSVMAP_ENTRY(addrh, addrl, lenh, lenl) \ - FDTLONG(addrh) ; \ - FDTLONG(addrl) ; \ - FDTLONG(lenh) ; \ - FDTLONG(lenl) - -#define EMPTY_RSVMAP(tree) \ - .balign 8 ; \ -tree##_rsvmap: ; \ - RSVMAP_ENTRY(0, 0, 0, 0) \ -tree##_rsvmap_end: ; - -#define PROPHDR(tree, name, len) \ - FDTLONG(FDT_PROP) ; \ - FDTLONG(len) ; \ - FDTLONG(tree##_##name - tree##_strings) ; - -#define PROP_EMPTY(tree, name) \ - PROPHDR(tree, name, 0) ; - -#define PROP_INT(tree, name, val) \ - PROPHDR(tree, name, 4) \ - FDTLONG(val) ; - -#define PROP_INT64(tree, name, valh, vall) \ - PROPHDR(tree, name, 8) \ - FDTLONG(valh) ; \ - FDTLONG(vall) ; - -#define PROP_STR(tree, name, str) \ - PROPHDR(tree, name, 55f - 54f) \ -54: \ - .string str ; \ -55: \ - .balign 4 ; - -#define BEGIN_NODE(name) \ - FDTLONG(FDT_BEGIN_NODE) ; \ - .string name ; \ - .balign 4 ; - -#define END_NODE \ - FDTLONG(FDT_END_NODE) ; - -#define STRING(tree, name, str) \ -tree##_##name: ; \ - .string str ; + .macro fdtlong val + .byte ((\val) >> 24) & 0xff + .byte ((\val) >> 16) & 0xff + .byte ((\val) >> 8) & 0xff + .byte (\val) & 0xff + .endm + + .macro treehdr tree + .balign 8 + .globl \tree +\tree : + fdtlong FDT_MAGIC + fdtlong (\tree\()_end - \tree) + fdtlong (\tree\()_struct - \tree) + fdtlong (\tree\()_strings - \tree) + fdtlong (\tree\()_rsvmap - \tree) + fdtlong 0x11 + fdtlong 0x10 + fdtlong 0 + fdtlong (\tree\()_strings_end - \tree\()_strings) + fdtlong (\tree\()_struct_end - \tree\()_struct) + .endm + + .macro rsvmape addrh, addrl, lenh, lenl + fdtlong \addrh + fdtlong \addrl + fdtlong \lenh + fdtlong \lenl + .endm + + .macro empty_rsvmap tree + .balign 8 +\tree\()_rsvmap: + rsvmape 0, 0, 0, 0 +\tree\()_rsvmap_end: + .endm + + .macro prophdr tree, name, len + fdtlong FDT_PROP + fdtlong \len + fdtlong (\tree\()_\name - \tree\()_strings) + .endm + + .macro propnil tree, name + prophdr \tree, \name, 0 + .endm + + .macro propu32 tree, name, val + prophdr \tree, \name, 4 + fdtlong \val + .endm + + .macro propu64 tree, name, valh, vall + prophdr \tree, \name, 8 + fdtlong \valh + fdtlong \vall + .endm + + .macro propstr tree, name, str:vararg + prophdr \tree, \name, (55f - 54f) +54: + .asciz \str +55: + .balign 4 + .endm + + .macro beginn name:vararg + fdtlong FDT_BEGIN_NODE + .asciz \name + .balign 4 + .endm + + .macro endn + fdtlong FDT_END_NODE + .endm + + .macro string tree, name, str:vararg +\tree\()_\name : + .asciz \str + .endm + .data - TREE_HDR(test_tree1) + treehdr test_tree1 .balign 8 test_tree1_rsvmap: - RSVMAP_ENTRY(TEST_ADDR_1H, TEST_ADDR_1L, TEST_SIZE_1H, TEST_SIZE_1L) - RSVMAP_ENTRY(TEST_ADDR_2H, TEST_ADDR_2L, TEST_SIZE_2H, TEST_SIZE_2L) - RSVMAP_ENTRY(0, 0, 0, 0) + rsvmape TEST_ADDR_1H, TEST_ADDR_1L, TEST_SIZE_1H, TEST_SIZE_1L + rsvmape TEST_ADDR_2H, TEST_ADDR_2L, TEST_SIZE_2H, TEST_SIZE_2L + rsvmape 0, 0, 0, 0 test_tree1_rsvmap_end: test_tree1_struct: - BEGIN_NODE("") - PROP_STR(test_tree1, compatible, "test_tree1") - PROP_INT(test_tree1, prop_int, TEST_VALUE_1) - PROP_INT64(test_tree1, prop_int64, TEST_VALUE64_1H, TEST_VALUE64_1L) - PROP_STR(test_tree1, prop_str, TEST_STRING_1) - PROP_INT(test_tree1, address_cells, 1) - PROP_INT(test_tree1, size_cells, 0) - - BEGIN_NODE("subnode@1") - PROP_STR(test_tree1, compatible, "subnode1") - PROP_INT(test_tree1, reg, 1) - PROP_INT(test_tree1, prop_int, TEST_VALUE_1) - - BEGIN_NODE("subsubnode") - PROP_STR(test_tree1, compatible, "subsubnode1\0subsubnode") - PROP_STR(test_tree1, placeholder, "this is a placeholder string\0string2") - PROP_INT(test_tree1, prop_int, TEST_VALUE_1) - END_NODE - - BEGIN_NODE("ss1") - END_NODE - - END_NODE - - BEGIN_NODE("subnode@2") - PROP_INT(test_tree1, reg, 2) - PROP_INT(test_tree1, linux_phandle, PHANDLE_1) - PROP_INT(test_tree1, prop_int, TEST_VALUE_2) - PROP_INT(test_tree1, address_cells, 1) - PROP_INT(test_tree1, size_cells, 0) - - BEGIN_NODE("subsubnode@0") - PROP_INT(test_tree1, reg, 0) - PROP_INT(test_tree1, phandle, PHANDLE_2) - PROP_STR(test_tree1, compatible, "subsubnode2\0subsubnode") - PROP_INT(test_tree1, prop_int, TEST_VALUE_2) - END_NODE - - BEGIN_NODE("ss2") - END_NODE - - END_NODE - - END_NODE - FDTLONG(FDT_END) + beginn "" + propstr test_tree1, compatible, "test_tree1" + propu32 test_tree1, prop_int, TEST_VALUE_1 + propu64 test_tree1, prop_int64, TEST_VALUE64_1H, TEST_VALUE64_1L + propstr test_tree1, prop_str, TEST_STRING_1 + propu32 test_tree1, address_cells, 1 + propu32 test_tree1, size_cells, 0 + + beginn "subnode@1" + propstr test_tree1, compatible, "subnode1" + propu32 test_tree1, reg, 1 + propu32 test_tree1, prop_int, TEST_VALUE_1 + + beginn "subsubnode" + propstr test_tree1, compatible, "subsubnode1\0subsubnode" + propstr test_tree1, placeholder, "this is a placeholder string\0string2" + propu32 test_tree1, prop_int, TEST_VALUE_1 + endn + + beginn "ss1" + endn + + endn + + beginn "subnode@2" + propu32 test_tree1, reg, 2 + propu32 test_tree1, linux_phandle, PHANDLE_1 + propu32 test_tree1, prop_int, TEST_VALUE_2 + propu32 test_tree1, address_cells, 1 + propu32 test_tree1, size_cells, 0 + + beginn "subsubnode@0" + propu32 test_tree1, reg, 0 + propu32 test_tree1, phandle, PHANDLE_2 + propstr test_tree1, compatible, "subsubnode2\0subsubnode" + propu32 test_tree1, prop_int, TEST_VALUE_2 + endn + + beginn "ss2" + endn + + endn + + endn + fdtlong FDT_END test_tree1_struct_end: test_tree1_strings: - STRING(test_tree1, compatible, "compatible") - STRING(test_tree1, prop_int, "prop-int") - STRING(test_tree1, prop_int64, "prop-int64") - STRING(test_tree1, prop_str, "prop-str") - STRING(test_tree1, linux_phandle, "linux,phandle") - STRING(test_tree1, phandle, "phandle") - STRING(test_tree1, reg, "reg") - STRING(test_tree1, placeholder, "placeholder") - STRING(test_tree1, address_cells, "#address-cells") - STRING(test_tree1, size_cells, "#size-cells") + string test_tree1, compatible, "compatible" + string test_tree1, prop_int, "prop-int" + string test_tree1, prop_int64, "prop-int64" + string test_tree1, prop_str, "prop-str" + string test_tree1, linux_phandle, "linux,phandle" + string test_tree1, phandle, "phandle" + string test_tree1, reg, "reg" + string test_tree1, placeholder, "placeholder" + string test_tree1, address_cells, "#address-cells" + string test_tree1, size_cells, "#size-cells" test_tree1_strings_end: test_tree1_end: - TREE_HDR(truncated_property) - EMPTY_RSVMAP(truncated_property) + treehdr truncated_property + empty_rsvmap truncated_property truncated_property_struct: - BEGIN_NODE("") - PROPHDR(truncated_property, prop_truncated, 4) + beginn "" + prophdr truncated_property, prop_truncated, 4 /* Oops, no actual property data here */ truncated_property_struct_end: truncated_property_strings: - STRING(truncated_property, prop_truncated, "truncated") + string truncated_property, prop_truncated, "truncated" truncated_property_strings_end: truncated_property_end: - TREE_HDR(bad_node_char) - EMPTY_RSVMAP(bad_node_char) + treehdr bad_node_char + empty_rsvmap bad_node_char bad_node_char_struct: - BEGIN_NODE("") - BEGIN_NODE("sub$node") - END_NODE - END_NODE - FDTLONG(FDT_END) + beginn "" + beginn "sub$node" + endn + endn + fdtlong FDT_END bad_node_char_struct_end: bad_node_char_strings: @@ -176,15 +189,15 @@ bad_node_char_strings_end: bad_node_char_end: - TREE_HDR(bad_node_format) - EMPTY_RSVMAP(bad_node_format) + treehdr bad_node_format + empty_rsvmap bad_node_format bad_node_format_struct: - BEGIN_NODE("") - BEGIN_NODE("subnode@1@2") - END_NODE - END_NODE - FDTLONG(FDT_END) + beginn "" + beginn "subnode@1@2" + endn + endn + fdtlong FDT_END bad_node_format_struct_end: bad_node_format_strings: @@ -192,18 +205,18 @@ bad_node_format_strings_end: bad_node_format_end: - TREE_HDR(bad_prop_char) - EMPTY_RSVMAP(bad_prop_char) + treehdr bad_prop_char + empty_rsvmap bad_prop_char bad_prop_char_struct: - BEGIN_NODE("") - PROP_INT(bad_prop_char, prop, TEST_VALUE_1) - END_NODE - FDTLONG(FDT_END) + beginn "" + propu32 bad_prop_char, prop, TEST_VALUE_1 + endn + fdtlong FDT_END bad_prop_char_struct_end: bad_prop_char_strings: - STRING(bad_prop_char, prop, "prop$erty") + string bad_prop_char, prop, "prop$erty" bad_prop_char_strings_end: bad_prop_char_end: @@ -212,62 +225,60 @@ bad_prop_char_end: .balign 8 .globl ovf_size_strings ovf_size_strings: - FDTLONG(FDT_MAGIC) - FDTLONG(ovf_size_strings_end - ovf_size_strings) - FDTLONG(ovf_size_strings_struct - ovf_size_strings) - FDTLONG(ovf_size_strings_strings - ovf_size_strings) - FDTLONG(ovf_size_strings_rsvmap - ovf_size_strings) - FDTLONG(0x11) - FDTLONG(0x10) - FDTLONG(0) - FDTLONG(0xffffffff) - FDTLONG(ovf_size_strings_struct_end - ovf_size_strings_struct) - EMPTY_RSVMAP(ovf_size_strings) + fdtlong FDT_MAGIC + fdtlong (ovf_size_strings_end - ovf_size_strings) + fdtlong (ovf_size_strings_struct - ovf_size_strings) + fdtlong (ovf_size_strings_strings - ovf_size_strings) + fdtlong (ovf_size_strings_rsvmap - ovf_size_strings) + fdtlong 0x11 + fdtlong 0x10 + fdtlong 0 + fdtlong 0xffffffff + fdtlong (ovf_size_strings_struct_end - ovf_size_strings_struct) + empty_rsvmap ovf_size_strings ovf_size_strings_struct: - BEGIN_NODE("") - PROP_INT(ovf_size_strings, bad_string, 0) - END_NODE - FDTLONG(FDT_END) + beginn "" + propu32 ovf_size_strings, bad_string, 0 + endn + fdtlong FDT_END ovf_size_strings_struct_end: ovf_size_strings_strings: - STRING(ovf_size_strings, x, "x") + string ovf_size_strings, x, "x" ovf_size_strings_bad_string = ovf_size_strings_strings + 0x10000000 ovf_size_strings_strings_end: ovf_size_strings_end: /* truncated_string */ - TREE_HDR(truncated_string) - EMPTY_RSVMAP(truncated_string) + treehdr truncated_string + empty_rsvmap truncated_string truncated_string_struct: - BEGIN_NODE("") - PROP_EMPTY(truncated_string, good_string) - PROP_EMPTY(truncated_string, bad_string) - END_NODE - FDTLONG(FDT_END) + beginn "" + propnil truncated_string, good_string + propnil truncated_string, bad_string + endn + fdtlong FDT_END truncated_string_struct_end: truncated_string_strings: - STRING(truncated_string, good_string, "good") + string truncated_string, good_string, "good" truncated_string_bad_string: - .byte 'b' - .byte 'a' - .byte 'd' + .ascii "bad" /* NOTE: terminating \0 deliberately missing */ truncated_string_strings_end: truncated_string_end: /* truncated_memrsv */ - TREE_HDR(truncated_memrsv) + treehdr truncated_memrsv truncated_memrsv_struct: - BEGIN_NODE("") - END_NODE - FDTLONG(FDT_END) + beginn "" + endn + fdtlong FDT_END truncated_memrsv_struct_end: truncated_memrsv_strings: @@ -275,7 +286,41 @@ truncated_memrsv_strings_end: .balign 8 truncated_memrsv_rsvmap: - RSVMAP_ENTRY(TEST_ADDR_1H, TEST_ADDR_1L, TEST_SIZE_1H, TEST_SIZE_1L) + rsvmape TEST_ADDR_1H, TEST_ADDR_1L, TEST_SIZE_1H, TEST_SIZE_1L truncated_memrsv_rsvmap_end: truncated_memrsv_end: + + + /* two root nodes */ + treehdr two_roots + empty_rsvmap two_roots + +two_roots_struct: + beginn "" + endn + beginn "" + endn + fdtlong FDT_END +two_roots_struct_end: + +two_roots_strings: +two_roots_strings_end: + +two_roots_end: + + + /* root node with a non-empty name */ + treehdr named_root + empty_rsvmap named_root + +named_root_struct: + beginn "fake" + endn + fdtlong FDT_END +named_root_struct_end: + +named_root_strings: +named_root_strings_end: + +named_root_end: diff --git a/tests/type-preservation.dt.yaml b/tests/type-preservation.dt.yaml index ee8cfde..a0cc64c 100644 --- a/tests/type-preservation.dt.yaml +++ b/tests/type-preservation.dt.yaml @@ -13,8 +13,11 @@ int64: [!u64 [0x200000000]] int64-array: [!u64 [0x100000000, 0x0]] a-string-with-nulls: ["foo\0bar", "baz"] + a-phandle: [[!phandle 0x1]] + a-phandle-with-args: [[!phandle 0x1, 0x0, 0x1], [!phandle 0x1, 0x2, 0x3]] subsubnode: compatible: ["subsubnode1", "subsubnode"] + phandle: [[0x1]] subsubsubnode: compatible: ["subsubsubnode1", [0x1234], "subsubsubnode"] ... diff --git a/tests/type-preservation.dts b/tests/type-preservation.dts index 3e380ba..921ea21 100644 --- a/tests/type-preservation.dts +++ b/tests/type-preservation.dts @@ -16,9 +16,12 @@ int64 = /bits/ 64 <0x200000000>; int64-array = /bits/ 64 <0x100000000 0x00> int64_array_label_end:; a-string-with-nulls = "foo\0bar", "baz"; + a-phandle = <&subsub1>; + a-phandle-with-args = <&subsub1 0x00 0x01>, <&subsub1 0x02 0x03>; subsub1: subsubnode { compatible = "subsubnode1", "subsubnode"; + phandle = <0x01>; subsubsub1: subsubsubnode { compatible = "subsubsubnode1", <0x1234>, valuea: valueb: "subsubsubnode"; diff --git a/tests/utilfdt_test.c b/tests/utilfdt_test.c index c621759..ba6462f 100644 --- a/tests/utilfdt_test.c +++ b/tests/utilfdt_test.c @@ -73,6 +73,9 @@ static void check_sizes(char *modifier, int expected_size) *ptr = 's'; check(fmt, 's', -1); + + *ptr = 'r'; + check(fmt, 'r', -1); } static void test_utilfdt_decode_type(void) @@ -90,7 +93,7 @@ static void test_utilfdt_decode_type(void) /* try every other character */ checkfail(""); for (ch = ' '; ch < 127; ch++) { - if (!strchr("iuxs", ch)) { + if (!strchr("iuxsr", ch)) { *fmt = ch; fmt[1] = '\0'; checkfail(fmt); diff --git a/treesource.c b/treesource.c index 061ba8c..33fedee 100644 --- a/treesource.c +++ b/treesource.c @@ -124,27 +124,6 @@ static void write_propval_int(FILE *f, const char *p, size_t len, size_t width) } } -static bool has_data_type_information(struct marker *m) -{ - return m->type >= TYPE_UINT8; -} - -static struct marker *next_type_marker(struct marker *m) -{ - while (m && !has_data_type_information(m)) - m = m->next; - return m; -} - -size_t type_marker_length(struct marker *m) -{ - struct marker *next = next_type_marker(m->next); - - if (next) - return next->offset - m->offset; - return 0; -} - static const char *delim_start[] = { [TYPE_UINT8] = "[", [TYPE_UINT16] = "/bits/ 16 <", @@ -229,26 +208,39 @@ static void write_propval(FILE *f, struct property *prop) size_t chunk_len = (m->next ? m->next->offset : len) - m->offset; size_t data_len = type_marker_length(m) ? : len - m->offset; const char *p = &prop->val.val[m->offset]; + struct marker *m_phandle; - if (has_data_type_information(m)) { + if (is_type_marker(m->type)) { emit_type = m->type; fprintf(f, " %s", delim_start[emit_type]); } else if (m->type == LABEL) fprintf(f, " %s:", m->ref); - else if (m->offset) - fputc(' ', f); - if (emit_type == TYPE_NONE) { - assert(chunk_len == 0); + if (emit_type == TYPE_NONE || chunk_len == 0) continue; - } switch(emit_type) { case TYPE_UINT16: write_propval_int(f, p, chunk_len, 2); break; case TYPE_UINT32: - write_propval_int(f, p, chunk_len, 4); + m_phandle = prop->val.markers; + for_each_marker_of_type(m_phandle, REF_PHANDLE) + if (m->offset == m_phandle->offset) + break; + + if (m_phandle) { + if (m_phandle->ref[0] == '/') + fprintf(f, "&{%s}", m_phandle->ref); + else + fprintf(f, "&%s", m_phandle->ref); + if (chunk_len > 4) { + fputc(' ', f); + write_propval_int(f, p + 4, chunk_len - 4, 4); + } + } else { + write_propval_int(f, p, chunk_len, 4); + } break; case TYPE_UINT64: write_propval_int(f, p, chunk_len, 8); @@ -33,6 +33,17 @@ char *xstrdup(const char *s) return d; } +char *xstrndup(const char *s, size_t n) +{ + size_t len = strnlen(s, n) + 1; + char *d = xmalloc(len); + + memcpy(d, s, len - 1); + d[len - 1] = '\0'; + + return d; +} + int xavsprintf_append(char **strp, const char *fmt, va_list ap) { int n, size = 0; /* start with 128 bytes */ @@ -353,11 +364,11 @@ int utilfdt_decode_type(const char *fmt, int *type, int *size) } /* we should now have a type */ - if ((*fmt == '\0') || !strchr("iuxs", *fmt)) + if ((*fmt == '\0') || !strchr("iuxsr", *fmt)) return -1; /* convert qualifier (bhL) to byte size */ - if (*fmt != 's') + if (*fmt != 's' && *fmt != 'r') *size = qualifier == 'b' ? 1 : qualifier == 'h' ? 2 : qualifier == 'l' ? 4 : -1; @@ -2,6 +2,7 @@ #ifndef UTIL_H #define UTIL_H +#include <stdlib.h> #include <stdarg.h> #include <stdbool.h> #include <getopt.h> @@ -12,10 +13,10 @@ */ #ifdef __GNUC__ -#ifdef __clang__ -#define PRINTF(i, j) __attribute__((format (printf, i, j))) -#else +#if __GNUC__ >= 5 || (__GNUC__ == 4 && __GNUC_MINOR__ >= 4) #define PRINTF(i, j) __attribute__((format (gnu_printf, i, j))) +#else +#define PRINTF(i, j) __attribute__((format (printf, i, j))) #endif #define NORETURN __attribute__((noreturn)) #else @@ -60,6 +61,7 @@ static inline void *xrealloc(void *p, size_t len) } extern char *xstrdup(const char *s); +extern char *xstrndup(const char *s, size_t len); extern int PRINTF(2, 3) xasprintf(char **strp, const char *fmt, ...); extern int PRINTF(2, 3) xasprintf_append(char **strp, const char *fmt, ...); @@ -142,6 +144,7 @@ int utilfdt_write_err(const char *filename, const void *blob); * i signed integer * u unsigned integer * x hex + * r raw * * TODO: Implement ll modifier (8 bytes) * TODO: Implement o type (octal) @@ -159,7 +162,7 @@ int utilfdt_decode_type(const char *fmt, int *type, int *size); */ #define USAGE_TYPE_MSG \ - "<type>\ts=string, i=int, u=unsigned, x=hex\n" \ + "<type>\ts=string, i=int, u=unsigned, x=hex, r=raw\n" \ "\tOptional modifier prefix:\n" \ "\t\thh or b=byte, h=2 byte, l=4 byte (default)"; diff --git a/version_gen.h.in b/version_gen.h.in new file mode 100644 index 0000000..7771abb --- /dev/null +++ b/version_gen.h.in @@ -0,0 +1 @@ +#define DTC_VERSION "DTC @VCS_TAG@" @@ -29,11 +29,12 @@ char *yaml_error_name[] = { (emitter)->problem, __func__, __LINE__); \ }) -static void yaml_propval_int(yaml_emitter_t *emitter, struct marker *markers, char *data, int len, int width) +static void yaml_propval_int(yaml_emitter_t *emitter, struct marker *markers, + char *data, unsigned int seq_offset, unsigned int len, int width) { yaml_event_t event; void *tag; - int off, start_offset = markers->offset; + unsigned int off; switch(width) { case 1: tag = "!u8"; break; @@ -66,7 +67,7 @@ static void yaml_propval_int(yaml_emitter_t *emitter, struct marker *markers, ch m = markers; is_phandle = false; for_each_marker_of_type(m, REF_PHANDLE) { - if (m->offset == (start_offset + off)) { + if (m->offset == (seq_offset + off)) { is_phandle = true; break; } @@ -112,8 +113,9 @@ static void yaml_propval_string(yaml_emitter_t *emitter, char *str, int len) static void yaml_propval(yaml_emitter_t *emitter, struct property *prop) { yaml_event_t event; - int len = prop->val.len; + unsigned int len = prop->val.len; struct marker *m = prop->val.markers; + struct marker *markers = prop->val.markers; /* Emit the property name */ yaml_scalar_event_initialize(&event, NULL, @@ -151,19 +153,19 @@ static void yaml_propval(yaml_emitter_t *emitter, struct property *prop) switch(m->type) { case TYPE_UINT16: - yaml_propval_int(emitter, m, data, chunk_len, 2); + yaml_propval_int(emitter, markers, data, m->offset, chunk_len, 2); break; case TYPE_UINT32: - yaml_propval_int(emitter, m, data, chunk_len, 4); + yaml_propval_int(emitter, markers, data, m->offset, chunk_len, 4); break; case TYPE_UINT64: - yaml_propval_int(emitter, m, data, chunk_len, 8); + yaml_propval_int(emitter, markers, data, m->offset, chunk_len, 8); break; case TYPE_STRING: yaml_propval_string(emitter, data, chunk_len); break; default: - yaml_propval_int(emitter, m, data, chunk_len, 1); + yaml_propval_int(emitter, markers, data, m->offset, chunk_len, 1); break; } } |