diff options
author | Sascha Hauer <s.hauer@pengutronix.de> | 2013-11-13 15:00:57 +0100 |
---|---|---|
committer | Sascha Hauer <s.hauer@pengutronix.de> | 2014-01-27 11:52:06 +0100 |
commit | 136ce91fb5d9194546bfcf49ac87a614a3a458c5 (patch) | |
tree | b243649344d993e48469f77fd6eace4a4d9f56da | |
parent | 6c37a935b85774f56871a75f2069c8041068d34c (diff) | |
download | dt-utils-3507fdbe5fcda15e6abd26936a8381927cb9a65c.tar.gz dt-utils-3507fdbe5fcda15e6abd26936a8381927cb9a65c.tar.xz |
2nd commitv0.2.0
Signed-off-by: Sascha Hauer <s.hauer@pengutronix.de>
-rw-r--r-- | .gitignore | 12 | ||||
-rw-r--r-- | COPYING | 502 | ||||
-rw-r--r-- | Makefile.am | 78 | ||||
-rw-r--r-- | NEWS | 17 | ||||
-rw-r--r-- | README | 262 | ||||
-rwxr-xr-x | autogen.sh | 25 | ||||
-rw-r--r-- | configure.ac | 68 | ||||
-rw-r--r-- | m4/.gitignore | 6 | ||||
-rw-r--r-- | sizes.h | 56 | ||||
-rw-r--r-- | src/.gitignore | 7 | ||||
-rw-r--r-- | src/crc32.c | 112 | ||||
-rw-r--r-- | src/dt/common.h (renamed from common.h) | 17 | ||||
-rw-r--r-- | src/dt/dt.h (renamed from of.h) | 25 | ||||
-rw-r--r-- | src/dt/fdt.h | 73 | ||||
-rw-r--r-- | src/dt/list.h (renamed from list.h) | 0 | ||||
-rw-r--r-- | src/fdt.c | 485 | ||||
-rw-r--r-- | src/fdtdump.c | 76 | ||||
-rw-r--r-- | src/libdt.c (renamed from of.c) | 109 | ||||
-rw-r--r-- | src/libdt.pc.in | 11 | ||||
-rw-r--r-- | src/libdt.sym | 74 | ||||
-rw-r--r-- | src/state.c | 1309 |
21 files changed, 3254 insertions, 70 deletions
diff --git a/.gitignore b/.gitignore new file mode 100644 index 0000000..1c6e7d1 --- /dev/null +++ b/.gitignore @@ -0,0 +1,12 @@ +*.o +.deps/ +.libs/ +Makefile +Makefile.in +/aclocal.m4 +/autom4te.cache +/build-aux +/config.* +/configure +/libtool +/stamp-h1 @@ -0,0 +1,502 @@ + GNU LESSER GENERAL PUBLIC LICENSE + Version 2.1, February 1999 + + Copyright (C) 1991, 1999 Free Software Foundation, Inc. + 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA + Everyone is permitted to copy and distribute verbatim copies + of this license document, but changing it is not allowed. + +[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. + + GNU LESSER GENERAL PUBLIC LICENSE + 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 a brief 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 St, 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/Makefile.am b/Makefile.am new file mode 100644 index 0000000..23bce08 --- /dev/null +++ b/Makefile.am @@ -0,0 +1,78 @@ +EXTRA_DIST = +CLEANFILES = +ACLOCAL_AMFLAGS = -I m4 ${ACLOCAL_FLAGS} +AM_MAKEFLAGS = --no-print-directory + +AM_CPPFLAGS = \ + -include $(top_builddir)/config.h \ + -DSYSCONFDIR=\""$(sysconfdir)"\" \ + -DLIBEXECDIR=\""$(libexecdir)"\" \ + -I${top_srcdir}/src/dt \ + -I${top_srcdir}/src + +AM_CFLAGS = ${my_CFLAGS} \ + -fvisibility=hidden \ + -ffunction-sections \ + -fdata-sections + +AM_LDFLAGS = \ + -Wl,--gc-sections \ + -Wl,--as-needed + +SED_PROCESS = \ + $(AM_V_GEN)$(MKDIR_P) $(dir $@) && $(SED) \ + -e 's,@VERSION\@,$(VERSION),g' \ + -e 's,@prefix\@,$(prefix),g' \ + -e 's,@exec_prefix\@,$(exec_prefix),g' \ + -e 's,@libdir\@,$(libdir),g' \ + -e 's,@includedir\@,$(includedir),g' \ + < $< > $@ || rm $@ + +%.pc: %.pc.in Makefile + $(SED_PROCESS) + +LIBDT_CURRENT=2 +LIBDT_REVISION=0 +LIBDT_AGE=2 + +pkginclude_HEADERS =\ + src/dt/dt.h \ + src/dt/fdt.h \ + src/dt/list.h +lib_LTLIBRARIES = src/libdt.la + +bin_PROGRAMS = state fdtdump +state_SOURCES = src/state.c +state_CFLAGS = $(LIBDT_CFLAGS) +state_LDADD = src/libdt.la + +fdtdump_SOURCES = src/fdtdump.c +fdtdump_CFLAGS = $(LIBDT_CFLAGS) +fdtdump_LDADD = src/libdt.la + +src_libdt_la_SOURCES =\ + src/crc32.c \ + src/libdt-private.h \ + src/libdt.c \ + src/fdt.c + +src_libdt_la_CFLAGS = $(UDEV_CFLAGS) +src_libdt_la_LIBADD = $(UDEV_LIBS) + +EXTRA_DIST += src/libdt.sym + +src_libdt_la_LDFLAGS = $(AM_LDFLAGS) \ + -version-info $(LIBDT_CURRENT):$(LIBDT_REVISION):$(LIBDT_AGE) \ + -Wl,--version-script=$(top_srcdir)/src/libdt.sym +src_libdt_la_DEPENDENCIES = ${top_srcdir}/src/libdt.sym + +pkgconfigdir = $(libdir)/pkgconfig +pkgconfig_DATA = src/libdt.pc +EXTRA_DIST += src/libdt.pc.in +CLEANFILES += src/libdt.pc + +TESTS = src/test-libdt + +check_PROGRAMS = src/test-libdt +src_test_libdt_SOURCES = src/test-libdt.c +src_test_libdt_LDADD = src/libdt.la @@ -0,0 +1,17 @@ +libabc 4 +======== +Use separate include directory: /usr/include/libabc/libabc.h. + +Create .xz tarball. + +libabc 3 +======== +Add functionality. Export symbols for 'thing'. + +libabc 2 +======== +Add support for 'thing'. + +libabc 1 +======== +Initial release. @@ -0,0 +1,262 @@ +/* + This is free and unencumbered software released into the public domain. + + Anyone is free to copy, modify, publish, use, compile, sell, or + distribute this software, either in source code form or as a compiled + binary, for any purpose, commercial or non-commercial, and by any + means. + + In jurisdictions that recognize copyright laws, the author or authors + of this software dedicate any and all copyright interest in the + software to the public domain. We make this dedication for the benefit + of the public at large and to the detriment of our heirs and + successors. We intend this dedication to be an overt act of + relinquishment in perpetuity of all present and future rights to this + software under copyright law. + + Unless you really want to, do not even mention that the copied content + originates from this skeleton library. Its sole purpose is to be copied + into other projects. + + The above statements apply to all content in this skeleton library, even + when the COPYING files, or the headers in the files state otherwise, + they are just common examples. +*/ + +Questions, feedback, patches please email: + linux-hotplug@vger.kernel.org +or: + Kay Sievers <kay.sievers@vrfy.org> + Lennart Poettering <lennart@poettering.net> + +Why bother? + - To make things easy for library users, distribution packagers and + developers of library bindings for other programming languages. If + you want your stuff to be used and commonly available, try to play + nice, and give them what they are used to. It makes their life a + lot easier. + +use autotools + - Every custom config/makefile/build system is worse for everybody + than autotools is. + - We are all used to autotools, it works, nobody cares. + - It's only two simple files to edit and include in git, which are + well understood by many many people, not just you. + - Ignore all crap autotools create in the source tree. never check + the created files into git. + - Never, ever, install config.h. That's internal to your sources + and is nothing to install. + - And really, anything but autotools is realy an option. Just get + over it. Everything else is an experiment, and it will come back + to you sooner or later. Why? think cross compilation, installation/ + uninstallation, build root integration, separate object trees, + standard adherence, tarball handling, make distcheck, testing, + portability between distros, ... + +If you use the GPL, always use the GPL's "(or later)" clause + - Developers are not lawyers, libraries should be able to be linked + to any version of the GPL. Remember that GPL2-only is incompatible + with LGPL3! + +Use LGPL (for the shared libraries) if you don't care about politics + - It protects the code, but does not restrict its use. Low-level + library interfaces are mostly used like kernel syscall or proc/sysfs + interfaces, which are usually without any restrictions. + +Zero global state -- Make your library threads-aware, but *not* thread-safe! + - An app can use liba and libb. libb internally can also use liba -- + without you knowing. Both you and libb can run liba code at the + very same time in different threads and operate at the same global + variables, without telling you about that. Loadable modules make + this problem even more prominent, since the libraries they pull in + are generally completely unknown by the main application. And + *every* program has loadable modules, think NSS! + - Avoid locking and mutexes, they are very unlikely to work correctly, + and incredibly hard to get right. + - Always use a library context object. every thread should then + operate on its own context. Do not imply context objects via TLS. It + won't work. TLS inheritance to new threads will get in your way. TLS + is a problem in itself, not a solution. + - Do not use gcc constructors, or destructors, you can only loose if + you do. Do not use _fini() or _ini(), don't even use your own + explicit library initializer/destructor functions. It just won't + work if your library is pulled in indirectly from another library + or even a shared module (i.e. dlopen()) + - Always use O_CLOEXEC, SOCK_CLOEXEC and friends. It's not an + option, it's a must. + - Don't use global variables (it includes static variables defined + inside functions). Ever. And under no circumstances export global + variables. It's madness. + +Use a common prefix for _all_ exported symbols + - Avoids namespace clashes + - Also, hacking is not a contest of finding the shortest possible + function name. And nobody cares about your 80ch line limit! + - If you use a drop-in library in your own library make sure to hide its + symbols with symbol versioning. Don't forget to hide *all* symbols, and + don't install the header file of the used drop-in library. + +Do not expose any complex structures in your API + - Use get() and set() instead. + - All objects should be opaque. + - Exporting structs in headers is OK in very few cases only: usually + those where you define standard binary formats (think: file + formats, datagram headers, ...) or where you define well-known + primitive types (think struct timeval, struct iovec, uuid + type). + - Why bother? Because struct stat, struct dirent and friends are + disasters. Particularly horrible are structs with fixed-size + strings. + +Use the de-facto standardized function names + - It's abc_new(), abc_free(), abc_ref(), abc_unref(). Don't invent + your own names, and don't use the confusing kernel-style ref + counting. Function names: _get() is for accessing properties of + objects, not for refcounting. + +Stick to kernel coding style + - Just because you are otherwise not bound by the kernel guidelines + when your write userspace libraries doesn't mean you have to give + up the good things it defines. + +Avoid callbacks in your API + - Language bindings want iterators. + - Programmers want iterators too. + +Never call exit(), abort(), be very careful with assert() + - Always return error codes. + - Libraries need to be safe for usage in critical processes that + need to recover from errors instead of getting killed (think PID 1!). + +Avoid thinking about main loops/event dispatchers. + - Get your stuff right in the kernel: fds are awesome, expose them + in userspace and in the library, because people can easily integrate + them with their own poll() loops of whatever kind they have. + - Don't hide file descriptors away in your headers. + - Never add blocking kernel syscalls, and never add blocking library + calls either (with very few exceptions). Userspace code is primarily + asynchronous around event loops, and blocking calls are generally + incompatible with that. + - Corollary of that: always O_NONBLOCK! + +Functions should return int and negative errors instead of NULL + - Return NULL in malloc() is fine, return NULL in fopen() is not! + - Pass allocated objects as parameter (yes, ctx_t** is OK!) + - Returning kernel style negative <errno.h> error codes is cool in + userspace too. Do it! + +Provide pkgconfig files + - Apps want to add a single line to their configure file, + they do not want to fiddle with the parameters, dependencies + to setup and link your library. + - It's just how we do these things today on Linux, and everything + else is just horribly messy. + +Avoid *hidden* fork()/exec() in libraries + - Apps generally do not expect signals and react allergic to them. + - Mutexes, locks, threads of the app might get confused. Mixing + mutexes and fork() equals failure. It just can't work, and + pthread_atfork() is not a solution for that, because it's broken + (even POSIX acknowledges that, just read the POSIX man + pages!). fork() safety for mutex-ridden code is not an + afterthought, it's a broken right from the beginning. + +Make your code safe for unexpected termination and any point: + - Do not leave files dirty or temporary files around. + - This is a tricky, since you need to design your stuff like this + from the beginning, it's not an afterthought, since you generally + do not have a place to clean up your stuff on exit. gcc + destructors are NOT the answer. + +Use symbol versioning + - Only with that, RPM can handle dependencies for added symbols + - Hide all internal symbols! *This is important!* + +Always provide logging/debugging, but do not clutter stderr + - Allow the app to hook the libs logging into its logging facility. + - Use conditional logging, do not filter too late. + - Do not burn cycles with printf() to /dev/null. + - By default: do not generate any output on stdout/stderr. + +Always use 'make distcheck' to create tarballs + - Never release anything that does not pass distcheck. It will + likely be broken for others too + +Use ./autogen.sh to bootstrap the git repo + - Always test bootstrapping with 'git clean -x -f -d' before + release (careful, it force-deletes all uncommitted files). + +Avoid any spec files or debian/ subdirs in git trees + - Distribution specific things do not belong in upstream trees, + but into distro packages + +Update NEWS to let developers know what has changed + - It's the history of the project, stuff that packagers need to know + when putting a new version in the distro. The interesting changes + or added/removed functionality from version to version. This is + not a commit changelog. + - If you want to provide ChangeLog, use the one generated + by git, do not maintain your own. + +use standard types + - The kernel's u8, u16, ... correspond to uint8_t, uint16_t in + userspace from <inttypes.h>. Don't define your own typedefs + for that, don't include the kernel types in common headers. + - Use enums, not #define for constants, wherever possible. In + userspace you have debuggers, and they are much nicer to use if + you have proper enum identifiers instead of macro definitions, + because the debugger can translate binary values back to enum + identifiers, but not macros. However, be careful with enums in + function prototypes: they might change the int type they are + resolved to as you add new enum values. + +Always guard for multiple inclusions of headers + - You must place '#ifndef libabc, #define libabc, #endif' in your + header files. There is no way around that. + +Be careful with variadic functions + - It's great if you provide them, but you must accompany them with + "v" variants (i.e. functions taking a va_arg object), and provide + non-variadic variants as well. This is important to get language + wrappers right. + +Don't put "extern" in front of your function prototypes in headers + - It has no effect, no effect at all. + +Never use sysv IPC, always use POSIX IPC + - Shmops and semops are horrors. Don't use them, ever. POSIX IPC is + much much much nicer. + +Avoid multiplexed functions ala ioctl()/prctl() style variadic functions + - Type-safety is awesome! + +Executing out-of-process tools and parsing their output is usually +not acceptable in libraries + - Tools should be built on top of their own lib. + - Always separate 'mechanism' from 'policy'. Make access to functionality + simple, but do not try to hide things that need to be decided by the + caller. Keep automagic at its minimum. Don't do hidden fork() do not + implicitly maintain cache files, ... + +Function calls with 15 arguments are a bad idea. If you have tons of +booleans in a function call, then replace them by a flag argument! + - Think about the invocation! foo(0, 1, 0, 1, 0, 0, 0, 1) is unreadable! + foo(FOO_QUUX|FOO_BAR|FOO_WALDO) much nicer. + +Don't be afraid of C99. Use it. + - It's 12 years old. And it's nice. + +Never expose fixed size strings in your API + - Pass malloc()ed strings out, or ask the caller to provide you with + a buffer, and return ENOSPC if too short. + +Glibc has byteswapping calls, don't invent your own: + - le32toh(), htole32() all those are documented in endian(3) + - bswap_32(), bswap_16(), bswap_64(). #include <byteswap.h> + - Don't use the versions provided by the linux kernel headers cpu_to_*() , *_to_cpu. + stick to the glibc API. + +Don't typedef pointers to structs! + +Don't write your own LISP interpreter and do not include it in your +library. :) diff --git a/autogen.sh b/autogen.sh new file mode 100755 index 0000000..0d60b0a --- /dev/null +++ b/autogen.sh @@ -0,0 +1,25 @@ +#!/bin/sh -e + +if [ -f .git/hooks/pre-commit.sample -a ! -f .git/hooks/pre-commit ] ; then + cp -p .git/hooks/pre-commit.sample .git/hooks/pre-commit && \ + chmod +x .git/hooks/pre-commit && \ + echo "Activated pre-commit hook." +fi + +autoreconf --install --symlink + +libdir() { + echo $(cd $1/$(gcc -print-multi-os-directory); pwd) +} + +args="--prefix=/usr \ +--sysconfdir=/etc \ +--libdir=$(libdir /usr/lib)" + +echo +echo "----------------------------------------------------------------" +echo "Initialized build system. For a common configuration please run:" +echo "----------------------------------------------------------------" +echo +echo "./configure CFLAGS='-g -O0' $args" +echo diff --git a/configure.ac b/configure.ac new file mode 100644 index 0000000..f1d4bbe --- /dev/null +++ b/configure.ac @@ -0,0 +1,68 @@ +AC_PREREQ(2.60) +AC_INIT([dt], + [4], + [s.hauer@pengutronix.de], + [dt], + [http://www.pengutronix.de/dt/]) +AC_CONFIG_SRCDIR([src/libdt.c]) +AC_CONFIG_AUX_DIR([build-aux]) +AM_INIT_AUTOMAKE([check-news foreign 1.11 -Wall -Wno-portability silent-rules tar-pax no-dist-gzip dist-xz subdir-objects]) +AC_PROG_CC_STDC +AC_USE_SYSTEM_EXTENSIONS +AC_SYS_LARGEFILE +AC_CONFIG_MACRO_DIR([m4]) +AM_SILENT_RULES([yes]) +LT_INIT([disable-static pic-only]) +AC_PREFIX_DEFAULT([/usr]) + +AC_PROG_SED +AC_PROG_MKDIR_P + +AC_ARG_ENABLE([logging], + AS_HELP_STRING([--disable-logging], [disable system logging @<:@default=enabled@:>@]), + [], enable_logging=yes) +AS_IF([test "x$enable_logging" = "xyes"], [ + AC_DEFINE(ENABLE_LOGGING, [1], [System logging.]) +]) + +AC_ARG_ENABLE([debug], + AS_HELP_STRING([--enable-debug], [enable debug messages @<:@default=disabled@:>@]), + [], [enable_debug=no]) +AS_IF([test "x$enable_debug" = "xyes"], [ + AC_DEFINE(ENABLE_DEBUG, [1], [Debug messages.]) +]) + +AC_CHECK_FUNCS([__secure_getenv secure_getenv]) + +my_CFLAGS="-Wall \ +-Wmissing-declarations -Wmissing-prototypes \ +-Wnested-externs -Wpointer-arith \ +-Wpointer-arith -Wsign-compare -Wchar-subscripts \ +-Wstrict-prototypes -Wshadow \ +-Wformat-security -Wtype-limits" +AC_SUBST([my_CFLAGS]) + +PKG_CHECK_MODULES(UDEV, [libudev]) + +AC_CONFIG_HEADERS(config.h) +AC_CONFIG_FILES([ + Makefile +]) + +AC_OUTPUT +AC_MSG_RESULT([ + $PACKAGE $VERSION + ===== + + prefix: ${prefix} + sysconfdir: ${sysconfdir} + libdir: ${libdir} + includedir: ${includedir} + + compiler: ${CC} + cflags: ${CFLAGS} + ldflags: ${LDFLAGS} + + logging: ${enable_logging} + debug: ${enable_debug} +]) diff --git a/m4/.gitignore b/m4/.gitignore new file mode 100644 index 0000000..8bab51c --- /dev/null +++ b/m4/.gitignore @@ -0,0 +1,6 @@ +libtool.m4 +ltoptions.m4 +ltsugar.m4 +ltversion.m4 +lt~obsolete.m4 + @@ -0,0 +1,56 @@ +/* + * 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. + */ +/* Size defintions + * Copyright (C) ARM Limited 1998. All rights reserved. + */ + +#ifndef __sizes_h +#define __sizes_h 1 + +/* handy sizes */ +#define SZ_1 0x00000001 +#define SZ_2 0x00000002 +#define SZ_4 0x00000004 +#define SZ_8 0x00000008 +#define SZ_16 0x00000010 +#define SZ_32 0x00000020 +#define SZ_64 0x00000040 +#define SZ_128 0x00000080 +#define SZ_256 0x00000100 +#define SZ_512 0x00000200 + +#define SZ_1K 0x00000400 +#define SZ_2K 0x00000800 +#define SZ_4K 0x00001000 +#define SZ_8K 0x00002000 +#define SZ_16K 0x00004000 +#define SZ_32K 0x00008000 +#define SZ_64K 0x00010000 +#define SZ_128K 0x00020000 +#define SZ_256K 0x00040000 +#define SZ_512K 0x00080000 + +#define SZ_1M 0x00100000 +#define SZ_2M 0x00200000 +#define SZ_4M 0x00400000 +#define SZ_8M 0x00800000 +#define SZ_16M 0x01000000 +#define SZ_32M 0x02000000 +#define SZ_64M 0x04000000 +#define SZ_128M 0x08000000 +#define SZ_256M 0x10000000 +#define SZ_512M 0x20000000 + +#define SZ_1G 0x40000000 +#define SZ_2G 0x80000000 + +#endif /* __sizes_h */ diff --git a/src/.gitignore b/src/.gitignore new file mode 100644 index 0000000..5e25d6d --- /dev/null +++ b/src/.gitignore @@ -0,0 +1,7 @@ +.dirstamp +.deps/ +.libs/ +*.la +*.lo +libabc.pc +test-libabc diff --git a/src/crc32.c b/src/crc32.c new file mode 100644 index 0000000..8d4dddc --- /dev/null +++ b/src/crc32.c @@ -0,0 +1,112 @@ +/* + * This file is derived from crc32.c from the zlib-1.1.3 distribution + * by Jean-loup Gailly and Mark Adler. + */ + +/* crc32.c -- compute the CRC-32 of a data stream + * Copyright (C) 1995-1998 Mark Adler + * For conditions of distribution and use, see copyright notice in zlib.h + */ + +#include <stdint.h> + +/* ======================================================================== + * Table of CRC-32's of all single-byte values (made by make_crc_table) + */ +static const uint32_t crc_table[256] = { + 0x00000000L, 0x77073096L, 0xee0e612cL, 0x990951baL, 0x076dc419L, + 0x706af48fL, 0xe963a535L, 0x9e6495a3L, 0x0edb8832L, 0x79dcb8a4L, + 0xe0d5e91eL, 0x97d2d988L, 0x09b64c2bL, 0x7eb17cbdL, 0xe7b82d07L, + 0x90bf1d91L, 0x1db71064L, 0x6ab020f2L, 0xf3b97148L, 0x84be41deL, + 0x1adad47dL, 0x6ddde4ebL, 0xf4d4b551L, 0x83d385c7L, 0x136c9856L, + 0x646ba8c0L, 0xfd62f97aL, 0x8a65c9ecL, 0x14015c4fL, 0x63066cd9L, + 0xfa0f3d63L, 0x8d080df5L, 0x3b6e20c8L, 0x4c69105eL, 0xd56041e4L, + 0xa2677172L, 0x3c03e4d1L, 0x4b04d447L, 0xd20d85fdL, 0xa50ab56bL, + 0x35b5a8faL, 0x42b2986cL, 0xdbbbc9d6L, 0xacbcf940L, 0x32d86ce3L, + 0x45df5c75L, 0xdcd60dcfL, 0xabd13d59L, 0x26d930acL, 0x51de003aL, + 0xc8d75180L, 0xbfd06116L, 0x21b4f4b5L, 0x56b3c423L, 0xcfba9599L, + 0xb8bda50fL, 0x2802b89eL, 0x5f058808L, 0xc60cd9b2L, 0xb10be924L, + 0x2f6f7c87L, 0x58684c11L, 0xc1611dabL, 0xb6662d3dL, 0x76dc4190L, + 0x01db7106L, 0x98d220bcL, 0xefd5102aL, 0x71b18589L, 0x06b6b51fL, + 0x9fbfe4a5L, 0xe8b8d433L, 0x7807c9a2L, 0x0f00f934L, 0x9609a88eL, + 0xe10e9818L, 0x7f6a0dbbL, 0x086d3d2dL, 0x91646c97L, 0xe6635c01L, + 0x6b6b51f4L, 0x1c6c6162L, 0x856530d8L, 0xf262004eL, 0x6c0695edL, + 0x1b01a57bL, 0x8208f4c1L, 0xf50fc457L, 0x65b0d9c6L, 0x12b7e950L, + 0x8bbeb8eaL, 0xfcb9887cL, 0x62dd1ddfL, 0x15da2d49L, 0x8cd37cf3L, + 0xfbd44c65L, 0x4db26158L, 0x3ab551ceL, 0xa3bc0074L, 0xd4bb30e2L, + 0x4adfa541L, 0x3dd895d7L, 0xa4d1c46dL, 0xd3d6f4fbL, 0x4369e96aL, + 0x346ed9fcL, 0xad678846L, 0xda60b8d0L, 0x44042d73L, 0x33031de5L, + 0xaa0a4c5fL, 0xdd0d7cc9L, 0x5005713cL, 0x270241aaL, 0xbe0b1010L, + 0xc90c2086L, 0x5768b525L, 0x206f85b3L, 0xb966d409L, 0xce61e49fL, + 0x5edef90eL, 0x29d9c998L, 0xb0d09822L, 0xc7d7a8b4L, 0x59b33d17L, + 0x2eb40d81L, 0xb7bd5c3bL, 0xc0ba6cadL, 0xedb88320L, 0x9abfb3b6L, + 0x03b6e20cL, 0x74b1d29aL, 0xead54739L, 0x9dd277afL, 0x04db2615L, + 0x73dc1683L, 0xe3630b12L, 0x94643b84L, 0x0d6d6a3eL, 0x7a6a5aa8L, + 0xe40ecf0bL, 0x9309ff9dL, 0x0a00ae27L, 0x7d079eb1L, 0xf00f9344L, + 0x8708a3d2L, 0x1e01f268L, 0x6906c2feL, 0xf762575dL, 0x806567cbL, + 0x196c3671L, 0x6e6b06e7L, 0xfed41b76L, 0x89d32be0L, 0x10da7a5aL, + 0x67dd4accL, 0xf9b9df6fL, 0x8ebeeff9L, 0x17b7be43L, 0x60b08ed5L, + 0xd6d6a3e8L, 0xa1d1937eL, 0x38d8c2c4L, 0x4fdff252L, 0xd1bb67f1L, + 0xa6bc5767L, 0x3fb506ddL, 0x48b2364bL, 0xd80d2bdaL, 0xaf0a1b4cL, + 0x36034af6L, 0x41047a60L, 0xdf60efc3L, 0xa867df55L, 0x316e8eefL, + 0x4669be79L, 0xcb61b38cL, 0xbc66831aL, 0x256fd2a0L, 0x5268e236L, + 0xcc0c7795L, 0xbb0b4703L, 0x220216b9L, 0x5505262fL, 0xc5ba3bbeL, + 0xb2bd0b28L, 0x2bb45a92L, 0x5cb36a04L, 0xc2d7ffa7L, 0xb5d0cf31L, + 0x2cd99e8bL, 0x5bdeae1dL, 0x9b64c2b0L, 0xec63f226L, 0x756aa39cL, + 0x026d930aL, 0x9c0906a9L, 0xeb0e363fL, 0x72076785L, 0x05005713L, + 0x95bf4a82L, 0xe2b87a14L, 0x7bb12baeL, 0x0cb61b38L, 0x92d28e9bL, + 0xe5d5be0dL, 0x7cdcefb7L, 0x0bdbdf21L, 0x86d3d2d4L, 0xf1d4e242L, + 0x68ddb3f8L, 0x1fda836eL, 0x81be16cdL, 0xf6b9265bL, 0x6fb077e1L, + 0x18b74777L, 0x88085ae6L, 0xff0f6a70L, 0x66063bcaL, 0x11010b5cL, + 0x8f659effL, 0xf862ae69L, 0x616bffd3L, 0x166ccf45L, 0xa00ae278L, + 0xd70dd2eeL, 0x4e048354L, 0x3903b3c2L, 0xa7672661L, 0xd06016f7L, + 0x4969474dL, 0x3e6e77dbL, 0xaed16a4aL, 0xd9d65adcL, 0x40df0b66L, + 0x37d83bf0L, 0xa9bcae53L, 0xdebb9ec5L, 0x47b2cf7fL, 0x30b5ffe9L, + 0xbdbdf21cL, 0xcabac28aL, 0x53b39330L, 0x24b4a3a6L, 0xbad03605L, + 0xcdd70693L, 0x54de5729L, 0x23d967bfL, 0xb3667a2eL, 0xc4614ab8L, + 0x5d681b02L, 0x2a6f2b94L, 0xb40bbe37L, 0xc30c8ea1L, 0x5a05df1bL, + 0x2d02ef8dL +}; + +/* ========================================================================= */ +#define DO1(buf) crc = crc_table[((int)crc ^ (*buf++)) & 0xff] ^ (crc >> 8); +#define DO2(buf) DO1(buf); DO1(buf); +#define DO4(buf) DO2(buf); DO2(buf); +#define DO8(buf) DO4(buf); DO4(buf); + +/* ========================================================================= */ +uint32_t crc32(uint32_t crc, const void *_buf, unsigned int len) +{ + const unsigned char *buf = _buf; + + crc = crc ^ 0xffffffffL; + while (len >= 8) { + DO8(buf); + len -= 8; + } + + if (len) do { + DO1(buf); + } while (--len); + + return crc ^ 0xffffffffL; +} + +/* No ones complement version. JFFS2 (and other things ?) + * don't use ones compliment in their CRC calculations. + */ +uint32_t crc32_no_comp(uint32_t crc, const void *_buf, unsigned int len) +{ + const unsigned char *buf = _buf; + + while (len >= 8) { + DO8(buf); + len -= 8; + } + + if (len) do { + DO1(buf); + } while (--len); + + return crc; +} diff --git a/common.h b/src/dt/common.h index 4ccec88..9668c4e 100644 --- a/common.h +++ b/src/dt/common.h @@ -1,5 +1,9 @@ +#ifndef __DT_COMMON_H +#define __DT_COMMON_H #include <stdlib.h> +#include <string.h> +#include <stdint.h> /** * container_of - cast a member of a structure out to the containing structure @@ -105,4 +109,17 @@ static inline size_t strlcpy(char *dest, const char *src, size_t size) return ret; } +#define cpu_to_be32 __cpu_to_be32 +#define be32_to_cpu __be32_to_cpu + +#define ALIGN(x, a) __ALIGN_MASK(x, (typeof(x))(a) - 1) +#define __ALIGN_MASK(x, mask) (((x) + (mask)) & ~(mask)) + +#define ARRAY_SIZE(arr) (sizeof(arr) / sizeof((arr)[0])) + #endif + +uint32_t crc32(uint32_t crc, const void *_buf, unsigned int len); +uint32_t crc32_no_comp(uint32_t crc, const void *_buf, unsigned int len); + +#endif /* __DT_COMMON_H */ @@ -1,7 +1,10 @@ -#ifndef __OF_H -#define __OF_H +#ifndef __DT_DT_H +#define __DT_DT_H -#include "list.h" +#include <stdint.h> +#include <dt/list.h> +#include <dt/common.h> +#include <asm/byteorder.h> /* Default string compare functions */ #define of_compat_cmp(s1, s2, l) strcasecmp((s1), (s2)) @@ -224,7 +227,16 @@ void *of_flatten_dtb(struct device_node *node); int of_add_memory(struct device_node *node, bool dump); void of_add_memory_bank(struct device_node *node, bool dump, int r, uint64_t base, uint64_t size); -int of_find_path(struct device_node *node, const char *propname, char **outpath); + +struct of_path { + char *devpath; + off_t offset; + size_t size; + struct udev_device *dev; + struct device_node *node; +}; + +int of_find_path(struct device_node *node, const char *propname, struct of_path *op); #define for_each_node_by_name(dn, name) \ for (dn = of_find_node_by_name(NULL, name); dn; \ @@ -365,4 +377,7 @@ static inline struct device_node *of_find_root_node(struct device_node *node) return node; } -#endif /* __OF_H */ + +struct device_node *of_read_proc_devicetree(void); + +#endif /* __DT_DT_H */ diff --git a/src/dt/fdt.h b/src/dt/fdt.h new file mode 100644 index 0000000..35278e3 --- /dev/null +++ b/src/dt/fdt.h @@ -0,0 +1,73 @@ +#ifndef _FDT_H +#define _FDT_H + +#ifndef __ASSEMBLY__ + +#define _B(n) ((unsigned long long)((uint8_t *)&x)[n]) + +#define fdt32_to_cpu(x) be32_to_cpu(x) +#define cpu_to_fdt32(x) cpu_to_be32(x) + +static inline uint64_t fdt64_to_cpu(uint64_t x) +{ + return (_B(0) << 56) | (_B(1) << 48) | (_B(2) << 40) | (_B(3) << 32) + | (_B(4) << 24) | (_B(5) << 16) | (_B(6) << 8) | _B(7); +} +#define cpu_to_fdt64(x) fdt64_to_cpu(x) +#undef _B + +struct fdt_header { + uint32_t magic; /* magic word FDT_MAGIC */ + uint32_t totalsize; /* total size of DT block */ + uint32_t off_dt_struct; /* offset to structure */ + uint32_t off_dt_strings; /* offset to strings */ + uint32_t off_mem_rsvmap; /* offset to memory reserve map */ + uint32_t version; /* format version */ + uint32_t last_comp_version; /* last compatible version */ + + /* version 2 fields below */ + uint32_t boot_cpuid_phys; /* Which physical CPU id we're + booting on */ + /* version 3 fields below */ + uint32_t size_dt_strings; /* size of the strings block */ + + /* version 17 fields below */ + uint32_t size_dt_struct; /* size of the structure block */ +}; + +struct fdt_reserve_entry { + uint64_t address; + uint64_t size; +}; + +struct fdt_node_header { + uint32_t tag; + char name[0]; +}; + +struct fdt_property { + uint32_t tag; + uint32_t len; + uint32_t nameoff; + char data[0]; +}; + +#endif /* !__ASSEMBLY */ + +#define FDT_MAGIC 0xd00dfeed /* 4: version, 4: total size */ +#define FDT_TAGSIZE sizeof(uint32_t) + +#define FDT_BEGIN_NODE 0x1 /* Start node: full name */ +#define FDT_END_NODE 0x2 /* End node */ +#define FDT_PROP 0x3 /* Property: name off, + size, content */ +#define FDT_NOP 0x4 /* nop */ +#define FDT_END 0x9 + +#define FDT_V1_SIZE (7*sizeof(uint32_t)) +#define FDT_V2_SIZE (FDT_V1_SIZE + sizeof(uint32_t)) +#define FDT_V3_SIZE (FDT_V2_SIZE + sizeof(uint32_t)) +#define FDT_V16_SIZE FDT_V3_SIZE +#define FDT_V17_SIZE (FDT_V16_SIZE + sizeof(uint32_t)) + +#endif /* _FDT_H */ diff --git a/src/fdt.c b/src/fdt.c new file mode 100644 index 0000000..903ed68 --- /dev/null +++ b/src/fdt.c @@ -0,0 +1,485 @@ +/* + * dtb.c - flat devicetree functions + * + * Copyright (c) 2013 Sascha Hauer <s.hauer@pengutronix.de>, Pengutronix + * + * based on Linux devicetree support + * + * See file CREDITS for list of people who contributed to this + * project. + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 2 + * as published by the Free Software Foundation. + * + * 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. + */ + +#include <stdio.h> +#include <linux/types.h> +#include <asm/byteorder.h> +#include <stdint.h> +#include <errno.h> +#include <string.h> +#include <stdlib.h> +#include <ctype.h> +#include <sys/types.h> +#include <dirent.h> +#include <sys/stat.h> +#include <sys/types.h> +#include <sys/stat.h> +#include <fcntl.h> +#include <unistd.h> +#include <libudev.h> +#include <dt/fdt.h> +#include <dt/dt.h> + +static inline uint32_t dt_struct_advance(struct fdt_header *f, uint32_t dt, int size) +{ + dt += size; + dt = ALIGN(dt, 4); + + if (dt > f->off_dt_struct + f->size_dt_struct) + return 0; + + return dt; +} + +static inline char *dt_string(struct fdt_header *f, char *strstart, uint32_t ofs) +{ + if (ofs > f->size_dt_strings) + return NULL; + else + return strstart + ofs; +} + +/** + * of_unflatten_dtb - unflatten a dtb binary blob + * @root - node in which the fdt blob should be merged into or NULL + * @infdt - the fdt blob to unflatten + * + * Parse a flat device tree binary blob and return a pointer to the + * unflattened tree. + */ +struct device_node *of_unflatten_dtb(struct device_node *root, void *infdt) +{ + const void *nodep; /* property node pointer */ + uint32_t tag; /* tag */ + int len; /* length of the property */ + const struct fdt_property *fdt_prop; + const char *pathp, *name; + struct device_node *node = NULL; + struct property *p; + uint32_t dt_struct; + struct fdt_node_header *fnh; + void *dt_strings; + struct fdt_header f; + int ret, merge = 0; + unsigned int maxlen; + struct fdt_header *fdt = infdt; + + if (fdt->magic != cpu_to_fdt32(FDT_MAGIC)) { + pr_err("bad magic: 0x%08x\n", fdt32_to_cpu(fdt->magic)); + return ERR_PTR(-EINVAL); + } + + if (fdt->version != cpu_to_fdt32(17)) { + pr_err("bad dt version: 0x%08x\n", fdt32_to_cpu(fdt->version)); + return ERR_PTR(-EINVAL); + } + + f.totalsize = fdt32_to_cpu(fdt->totalsize); + f.off_dt_struct = fdt32_to_cpu(fdt->off_dt_struct); + f.size_dt_struct = fdt32_to_cpu(fdt->size_dt_struct); + f.off_dt_strings = fdt32_to_cpu(fdt->off_dt_strings); + f.size_dt_strings = fdt32_to_cpu(fdt->size_dt_strings); + + if (f.off_dt_struct + f.size_dt_struct > f.totalsize) { + pr_err("unflatten: dt size exceeds total size\n"); + return ERR_PTR(-ESPIPE); + } + + if (f.off_dt_strings + f.size_dt_strings > f.totalsize) { + pr_err("unflatten: string size exceeds total size\n"); + return ERR_PTR(-ESPIPE); + } + + dt_struct = f.off_dt_struct; + dt_strings = (void *)fdt + f.off_dt_strings; + + if (root) { + pr_debug("unflatten: merging into existing tree\n"); + merge = 1; + } else { + root = of_new_node(NULL, NULL); + if (!root) + return ERR_PTR(-ENOMEM); + } + + while (1) { + tag = be32_to_cpu(*(uint32_t *)(infdt + dt_struct)); + + switch (tag) { + case FDT_BEGIN_NODE: + fnh = infdt + dt_struct; + pathp = name = fnh->name; + maxlen = (unsigned long)fdt + f.off_dt_struct + + f.size_dt_struct - (unsigned long)name; + + len = strnlen(name, maxlen + 1); + if (len > maxlen) { + ret = -ESPIPE; + goto err; + } + + dt_struct = dt_struct_advance(&f, dt_struct, + sizeof(struct fdt_node_header) + len + 1); + if (!dt_struct) { + ret = -ESPIPE; + goto err; + } + + if (!node) { + node = root; + } else { + if (merge) + node = of_get_child_by_name(node, + pathp); + if (!merge || !node) + node = of_new_node(node, pathp); + } + + break; + + case FDT_END_NODE: + if (!node) { + pr_err("unflatten: too many end nodes\n"); + ret = -EINVAL; + goto err; + } + + node = node->parent; + + dt_struct = dt_struct_advance(&f, dt_struct, FDT_TAGSIZE); + if (!dt_struct) { + ret = -ESPIPE; + goto err; + } + + break; + + case FDT_PROP: + fdt_prop = infdt + dt_struct; + len = fdt32_to_cpu(fdt_prop->len); + nodep = fdt_prop->data; + + name = dt_string(&f, dt_strings, fdt32_to_cpu(fdt_prop->nameoff)); + if (!name) { + ret = -ESPIPE; + goto err; + } + + dt_struct = dt_struct_advance(&f, dt_struct, + sizeof(struct fdt_property) + len); + if (!dt_struct) { + ret = -ESPIPE; + goto err; + } + + p = NULL; + if (merge) + p = of_find_property(node, name, NULL); + if (merge && p) { + free(p->value); + p->value = xzalloc(len); + p->length = len; + memcpy(p->value, nodep, len); + } else { + p = of_new_property(node, name, nodep, len); + if (!strcmp(name, "phandle") && len == 4) + node->phandle = be32_to_cpu(*(__be32 *)p->value); + } + + break; + + case FDT_NOP: + dt_struct = dt_struct_advance(&f, dt_struct, FDT_TAGSIZE); + if (!dt_struct) { + ret = -ESPIPE; + goto err; + } + + break; + + case FDT_END: + return root; + + default: + pr_err("unflatten: Unknown tag 0x%08X\n", tag); + ret = -EINVAL; + goto err; + } + } +err: + of_delete_node(root); + + return ERR_PTR(ret); +} + +struct fdt { + void *dt; + uint32_t dt_nextofs; + uint32_t dt_size; + char *strings; + uint32_t str_nextofs; + uint32_t str_size; +}; + +static inline uint32_t dt_next_ofs(uint32_t curofs, uint32_t len) +{ + return ALIGN(curofs + len, 4); +} + +static int lstrcpy(char *dest, const char *src) +{ + int len = 0; + int maxlen = 1023; + + while (*src) { + *dest++ = *src++; + len++; + if (!maxlen) + return -ENOSPC; + maxlen--; + } + + return len; +} + +static int fdt_ensure_space(struct fdt *fdt, int dtsize) +{ + /* + * We assume strings and names have a maximum length of 1024 + * whereas properties can be longer. We allocate new memory + * if we have less than 1024 bytes (+ the property size left. + */ + if (fdt->str_size - fdt->str_nextofs < 1024) { + fdt->strings = realloc(fdt->strings, fdt->str_size * 2); + if (!fdt->strings) + return -ENOMEM; + fdt->str_size *= 2; + } + + if (fdt->dt_size - fdt->dt_nextofs < 1024 + dtsize) { + fdt->dt = realloc(fdt->dt, fdt->dt_size * 2); + if (!fdt->dt) + return -ENOMEM; + fdt->dt_size *= 2; + } + + return 0; +} + +static inline int dt_add_string(struct fdt *fdt, const char *str) +{ + uint32_t ret; + int len; + + if (fdt_ensure_space(fdt, 0) < 0) + return -ENOMEM; + + len = lstrcpy(fdt->strings + fdt->str_nextofs, str); + if (len < 0) + return -ENOSPC; + + ret = fdt->str_nextofs; + + fdt->str_nextofs += len + 1; + + return ret; +} + +static int __of_flatten_dtb(struct fdt *fdt, struct device_node *node) +{ + struct property *p; + struct device_node *n; + int ret; + unsigned int len; + struct fdt_node_header *nh; + + if (fdt_ensure_space(fdt, 0) < 0) + return -ENOMEM; + + nh = fdt->dt + fdt->dt_nextofs; + nh->tag = cpu_to_fdt32(FDT_BEGIN_NODE); + len = lstrcpy(nh->name, node->name); + fdt->dt_nextofs = dt_next_ofs(fdt->dt_nextofs, 4 + len + 1); + + list_for_each_entry(p, &node->properties, list) { + struct fdt_property *fp; + + if (fdt_ensure_space(fdt, p->length) < 0) + return -ENOMEM; + + fp = fdt->dt + fdt->dt_nextofs; + + fp->tag = cpu_to_fdt32(FDT_PROP); + fp->len = cpu_to_fdt32(p->length); + fp->nameoff = cpu_to_fdt32(dt_add_string(fdt, p->name)); + memcpy(fp->data, p->value, p->length); + fdt->dt_nextofs = dt_next_ofs(fdt->dt_nextofs, + sizeof(struct fdt_property) + p->length); + } + + list_for_each_entry(n, &node->children, parent_list) { + ret = __of_flatten_dtb(fdt, n); + if (ret) + return ret; + } + + nh = fdt->dt + fdt->dt_nextofs; + nh->tag = cpu_to_fdt32(FDT_END_NODE); + fdt->dt_nextofs = dt_next_ofs(fdt->dt_nextofs, + sizeof(struct fdt_node_header)); + + if (fdt_ensure_space(fdt, 0) < 0) + return -ENOMEM; + + return 0; +} + +#define BUFSIZE (64 * 1024) + +/** + * of_flatten_dtb - flatten a barebox internal devicetree to a dtb + * @node - the root node of the tree to be unflattened + */ +void *of_flatten_dtb(struct device_node *node) +{ + int ret; + struct fdt_header header = {}; + struct fdt fdt = {}; + uint32_t ofs; + struct fdt_node_header *nh; + + header.magic = cpu_to_fdt32(FDT_MAGIC); + header.version = cpu_to_fdt32(0x11); + header.last_comp_version = cpu_to_fdt32(0x10); + + fdt.dt = xzalloc(BUFSIZE); + fdt.dt_size = BUFSIZE; + + fdt.strings = xzalloc(BUFSIZE); + fdt.str_size = BUFSIZE; + + memset(fdt.dt, 0, BUFSIZE); + + ofs = sizeof(struct fdt_header); + + header.off_mem_rsvmap = cpu_to_fdt32(ofs); + ofs += sizeof(struct fdt_reserve_entry) * OF_MAX_RESERVE_MAP; + + fdt.dt_nextofs = ofs; + + ret = __of_flatten_dtb(&fdt, node); + if (ret) + goto out_free; + nh = fdt.dt + fdt.dt_nextofs; + nh->tag = cpu_to_fdt32(FDT_END); + fdt.dt_nextofs = dt_next_ofs(fdt.dt_nextofs, sizeof(struct fdt_node_header)); + + header.off_dt_struct = cpu_to_fdt32(ofs); + header.size_dt_struct = cpu_to_fdt32(fdt.dt_nextofs - ofs); + + header.off_dt_strings = cpu_to_fdt32(fdt.dt_nextofs); + header.size_dt_strings = cpu_to_fdt32(fdt.str_nextofs); + + if (fdt.dt_size - fdt.dt_nextofs < fdt.str_nextofs) { + fdt.dt = realloc(fdt.dt, fdt.dt_nextofs + fdt.str_nextofs); + if (!fdt.dt) + goto out_free; + } + + memcpy(fdt.dt + fdt.dt_nextofs, fdt.strings, fdt.str_nextofs); + + header.totalsize = cpu_to_fdt32(fdt.dt_nextofs + fdt.str_nextofs); + + memcpy(fdt.dt, &header, sizeof(header)); + + free(fdt.strings); + + return fdt.dt; + +out_free: + free(fdt.strings); + free(fdt.dt); + + return NULL; +} + +/* + * The last entry is the zeroed sentinel, the one before is + * reserved for the reservemap entry for the dtb itself. + */ +#define OF_MAX_FREE_RESERVE_MAP (OF_MAX_RESERVE_MAP - 2) + +static struct of_reserve_map of_reserve_map; + +int of_add_reserve_entry(uint64_t start, uint64_t end) +{ + int e = of_reserve_map.num_entries; + + if (e >= OF_MAX_FREE_RESERVE_MAP) + return -ENOSPC; + + of_reserve_map.start[e] = start; + of_reserve_map.end[e] = end; + of_reserve_map.num_entries++; + + return 0; +} + +struct of_reserve_map *of_get_reserve_map(void) +{ + return &of_reserve_map; +} + +void of_clean_reserve_map(void) +{ + of_reserve_map.num_entries = 0; +} + +/** + * fdt_add_reserve_map - Add reserve map entries to a devicetree binary + * @__fdt: The devicetree blob + * + * This adds the reservemap entries previously colllected in + * of_add_reserve_entry() to a devicetree binary blob. This also + * adds the devicetree itself to the reserved list, so after calling + * this function the tree should not be relocated anymore. + */ +void fdt_add_reserve_map(void *__fdt) +{ + struct fdt_header *fdt = __fdt; + struct of_reserve_map *res = &of_reserve_map; + struct fdt_reserve_entry *fdt_res = + __fdt + be32_to_cpu(fdt->off_mem_rsvmap); + int i; + + for (i = 0; i < res->num_entries; i++) { + of_write_number(&fdt_res->address, res->start[i], 2); + of_write_number(&fdt_res->size, res->end[i] - res->start[i] + 1, + 2); + fdt_res++; + } + + of_write_number(&fdt_res->address, (unsigned long)__fdt, 2); + of_write_number(&fdt_res->size, be32_to_cpu(fdt->totalsize), 2); + fdt_res++; + + of_write_number(&fdt_res->address, 0, 2); + of_write_number(&fdt_res->size, 0, 2); +} diff --git a/src/fdtdump.c b/src/fdtdump.c new file mode 100644 index 0000000..d438a84 --- /dev/null +++ b/src/fdtdump.c @@ -0,0 +1,76 @@ +#include <linux/types.h> + +#include <stdio.h> +#include <dt/dt.h> +#include <sys/types.h> +#include <sys/stat.h> +#include <fcntl.h> +#include <unistd.h> +#include <errno.h> + +void *read_file(const char *filename, size_t *size) +{ + int fd; + struct stat s; + void *buf = NULL; + int ret; + + if (stat(filename, &s)) + return NULL; + + buf = xzalloc(s.st_size + 1); + + fd = open(filename, O_RDONLY); + if (fd < 0) + goto err_out; + + if (read(fd, buf, s.st_size) < s.st_size) + goto err_out1; + + close(fd); + + if (size) + *size = s.st_size; + + return buf; + +err_out1: + close(fd); +err_out: + free(buf); + + return NULL; +} + +int main(int argc, char *argv[]) +{ + void *fdt; + struct device_node *root; + const char *dtbfile = NULL; + + if (argc > 1) + dtbfile = argv[1]; + + if (dtbfile) { + fdt = read_file(dtbfile, NULL); + if (!fdt) { + fprintf(stderr, "Could not read %s: %s\n", dtbfile, strerror(errno)); + exit(1); + } + + root = of_unflatten_dtb(NULL, fdt); + } else { + root = of_read_proc_devicetree(); + } + + if (IS_ERR(root)) { + fprintf(stderr, "Could not unflatten dtb: %s\n", strerror(-PTR_ERR(root))); + exit(1); + } + + printf("/dts-v1/;\n/"); + + of_print_nodes(root, 0); + + exit(0); +} @@ -1,5 +1,5 @@ /* - * base.c - basic devicetree functions + * of.c - basic devicetree functions * * Copyright (c) 2012 Sascha Hauer <s.hauer@pengutronix.de>, Pengutronix * @@ -17,7 +17,6 @@ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. */ -#define _GNU_SOURCE #include <stdio.h> #include <linux/types.h> #include <asm/byteorder.h> @@ -34,7 +33,7 @@ #include <fcntl.h> #include <unistd.h> #include <libudev.h> -#include "of.h" +#include <dt.h> static int is_printable_string(const void *data, int len) { @@ -1888,10 +1887,13 @@ int scan_proc_dir(struct device_node *node, const char *path) if (dirent->d_name[0] == '.') continue; - asprintf(&cur, "%s/%s", path, dirent->d_name); + ret = asprintf(&cur, "%s/%s", path, dirent->d_name); + if (ret < 0) + return -ENOMEM; + ret = stat(cur, &s); if (ret) - return ret; + return -errno; if (S_ISREG(s.st_mode)) { int fd; @@ -1903,7 +1905,7 @@ int scan_proc_dir(struct device_node *node, const char *path) buf = xzalloc(s.st_size); ret = read(fd, buf, s.st_size); if (ret < 0) - return ret; + return -errno; close(fd); of_new_property(node, dirent->d_name, buf, s.st_size); @@ -1930,13 +1932,16 @@ struct device_node *of_read_proc_devicetree(void) root = of_new_node(NULL, NULL); + ret = scan_proc_dir(root, "/sys/firmware/devicetree/base"); + if (!ret) + return root; + ret = scan_proc_dir(root, "/proc/device-tree"); - if (ret) { - of_delete_node(root); - return NULL; - } + if (!ret) + return root; - return root; + of_delete_node(root); + return ERR_PTR(ret); } struct udev_device *of_find_device_by_node_path(const char *of_full_path) @@ -1948,19 +1953,22 @@ struct udev_device *of_find_device_by_node_path(const char *of_full_path) udev = udev_new(); if (!udev) { - printf("Can't create udev\n"); - exit(1); + fprintf(stderr, "Can't create udev\n"); + return NULL; } enumerate = udev_enumerate_new(udev); udev_enumerate_add_match_property(enumerate, "OF_FULLNAME", of_full_path); udev_enumerate_scan_devices(enumerate); devices = udev_enumerate_get_list_entry(enumerate); + udev_list_entry_foreach(dev_list_entry, devices) { const char *path; - /* Get the filename of the /sys entry for the device - and create a udev_device object (dev) representing it */ + /* + * Get the filename of the /sys entry for the device + * and create a udev_device object (dev) representing it + */ path = udev_list_entry_get_name(dev_list_entry); dev = udev_device_new_from_syspath(udev, path); @@ -1982,11 +1990,10 @@ struct udev_device *device_find_partition(struct udev_device *dev, const char *n struct udev_list_entry *devices, *dev_list_entry; struct udev_device *part; - /* Create the udev object */ udev = udev_new(); if (!udev) { - printf("Can't create udev\n"); - exit(1); + fprintf(stderr, "Can't create udev\n"); + return NULL; } enumerate = udev_enumerate_new(udev); @@ -2010,14 +2017,6 @@ struct udev_device *device_find_partition(struct udev_device *dev, const char *n return NULL; } -struct of_path { - char *devpath; - off_t offset; - size_t size; - struct udev_device *dev; - struct device_node *node; -}; - struct of_path_type { const char *name; int (*parse)(struct of_path *op, const char *str); @@ -2046,10 +2045,13 @@ static int of_path_type_partname(struct of_path *op, const char *name) return 0; } - asprintf(&op->devpath, "%s/eeprom", udev_device_get_syspath(op->dev)); + ret = asprintf(&op->devpath, "%s/eeprom", udev_device_get_syspath(op->dev)); + if (ret < 0) + return -ENOMEM; + ret = stat(op->devpath, &s); if (ret) - return ret; + return -errno; for_each_child_of_node(op->node, node) { const char *partname; @@ -2066,8 +2068,10 @@ static int of_path_type_partname(struct of_path *op, const char *name) a_cells = of_n_addr_cells(node); s_cells = of_n_size_cells(node); - op->offset = of_read_number(reg, a_cells);; - op->size = of_read_number(reg + a_cells, s_cells);; + + op->offset = of_read_number(reg, a_cells); + op->size = of_read_number(reg + a_cells, s_cells); + break; } } @@ -2137,13 +2141,14 @@ out: * device-path = &mmc0, "partname:0"; * device-path = &norflash, "partname:barebox-environment"; */ -int of_find_path(struct device_node *node, const char *propname, char **outpath) +int of_find_path(struct device_node *node, const char *propname, struct of_path *op) { - struct of_path op = {}; struct device_node *rnode; const char *path, *str; int i, len, ret; + memset(op, 0, sizeof(*op)); + path = of_get_property(node, propname, &len); if (!path) return -EINVAL; @@ -2152,10 +2157,10 @@ int of_find_path(struct device_node *node, const char *propname, char **outpath) if (!rnode) return -ENODEV; - op.node = rnode; + op->node = rnode; - op.dev = of_find_device_by_node_path(rnode->full_name); - if (!op.dev) + op->dev = of_find_device_by_node_path(rnode->full_name); + if (!op->dev) return -ENODEV; i = 1; @@ -2165,42 +2170,16 @@ int of_find_path(struct device_node *node, const char *propname, char **outpath) if (ret) break; - ret = of_path_parse_one(&op, str); + ret = of_path_parse_one(op, str); if (ret) return ret; } - if (!op.devpath) + if (!op->devpath) return -ENOENT; - printf("devpath: %s ofs: 0x%08lx size: 0x%08x\n", op.devpath, op.offset, op.size); - - return 0; -} - -int main(int argc, char *argv[]) -{ - struct device_node *root, *node; - char *devnode; - - root = of_read_proc_devicetree(); - root_node = root; - - node = of_find_node_by_path_or_alias(root, argv[1]); - if (!node) { - printf("no such node: %s\n", argv[1]); - return 1; - } - - of_find_path(node, argv[2], &devnode); - - return 0; - - of_print_nodes(root, 0); - - for_each_compatible_node(node, NULL, "barebox,state") { - of_print_nodes(node, 0); - } + pr_debug("%s: devpath: %s ofs: 0x%08llx size: 0x%08lx\n", + __func__, op->devpath, op->offset, op->size); return 0; } diff --git a/src/libdt.pc.in b/src/libdt.pc.in new file mode 100644 index 0000000..2fc7b76 --- /dev/null +++ b/src/libdt.pc.in @@ -0,0 +1,11 @@ +prefix=@prefix@ +exec_prefix=@exec_prefix@ +libdir=@libdir@ +includedir=@includedir@ + +Name: libabc +Description: Library for something with abc +Version: @VERSION@ +Libs: -L${libdir} -labc +Libs.private: +Cflags: -I${includedir} diff --git a/src/libdt.sym b/src/libdt.sym new file mode 100644 index 0000000..c034ea2 --- /dev/null +++ b/src/libdt.sym @@ -0,0 +1,74 @@ +LIBDT_1 { +global: + of_print_property; + of_n_addr_cells; + of_n_size_cells; + of_find_property; + of_alias_scan; + of_alias_get_id; + of_alias_get; + of_find_node_by_alias; + of_find_node_by_phandle; + of_get_tree_max_phandle; + of_node_create_phandle; + of_get_property; + of_device_is_compatible; + of_find_node_by_name; + of_find_node_by_type; + of_find_compatible_node; + of_find_node_with_property; + of_match_node; + of_find_matching_node_and_match; + of_property_read_u32_index; + of_property_read_u8_array; + of_property_read_u16_array; + of_property_read_u32_array; + of_property_read_u64; + of_property_read_string; + of_property_read_string_index; + of_property_match_string; + of_property_count_strings; + of_prop_next_u32; + of_prop_next_string; + of_property_write_bool; + of_property_write_u8_array; + of_property_write_u16_array; + of_property_write_u32_array; + of_property_write_u64_array; + of_parse_phandle; + of_parse_phandle_with_args; + of_count_phandle_with_args; + of_machine_is_compatible; + of_find_node_by_path_from; + of_find_node_by_path; + of_find_node_by_path_or_alias; + of_modalias_node; + of_get_root_node; + of_set_root_node; + of_device_is_available; + of_get_parent; + of_get_next_available_child; + of_get_child_count; + of_get_available_child_count; + of_get_child_by_name; + of_print_nodes; + of_new_node; + of_new_property; + of_delete_property; + of_set_property; + of_create_node; + of_delete_node; + of_device_enable; + of_device_enable_path; + of_device_disable; + of_device_disable_path; + of_read_proc_devicetree; + of_find_device_by_node_path; + device_find_partition; + of_find_path; + of_unflatten_dtb; + crc32; + crc32_no_comp; +local: + *; +}; diff --git a/src/state.c b/src/state.c new file mode 100644 index 0000000..97c6b4a --- /dev/null +++ b/src/state.c @@ -0,0 +1,1309 @@ +/* + * state.c - state handling tool + * + * Copyright (c) 2014 Sascha Hauer <s.hauer@pengutronix.de>, Pengutronix + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 2 + * as published by the Free Software Foundation. + * + * 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. + */ +#include <libudev.h> +#include <common.h> +#include <dirent.h> +#include <getopt.h> +#include <stdint.h> +#include <stdlib.h> +#include <string.h> +#include <unistd.h> +#include <ctype.h> +#include <errno.h> +#include <fcntl.h> +#include <stdio.h> +#include <dt.h> + +#include <asm/byteorder.h> +#include <linux/types.h> +#include <mtd/mtd-abi.h> +#include <sys/ioctl.h> +#include <sys/types.h> +#include <sys/stat.h> + +static int verbose; + +enum state_variable_type { + STATE_TYPE_INVALID = 0, + STATE_TYPE_ENUM, + STATE_TYPE_U32, + STATE_TYPE_MAC, +}; + +struct state_backend; + +struct state { + struct list_head variables; + const char *name; + struct list_head list; + struct state_backend *backend; + uint32_t magic; + int dirty; +}; + +struct state_backend { + int (*load)(struct state_backend *backend, struct state *state); + int (*save)(struct state_backend *backend, struct state *state); + const char *name; + char *path; +}; + +/* list of all registered state instances */ +static LIST_HEAD(state_list); + +/* instance of a single variable */ +struct state_variable { + enum state_variable_type type; + struct list_head list; + char *name; + void *raw; + int raw_size; + int index; +}; + +/* A variable type (uint32, enum32) */ +struct variable_type { + enum state_variable_type type; + const char *type_name; + struct list_head list; + int (*export)(struct state_variable *, struct device_node *); + int (*init)(struct state_variable *, struct device_node *); + struct state_variable *(*create)(struct state *state, + const char *name, struct device_node *); + char *(*get)(struct state_variable *); + int (*set)(struct state_variable *, const char *val); + void (*info)(struct state_variable *); +}; + +/* + * uint32 + */ +struct state_uint32 { + struct state_variable var; + struct param_d *param; + uint32_t value; + uint32_t value_default; +}; + +static int state_var_compare(struct list_head *a, struct list_head *b) +{ + struct state_variable *va = list_entry(a, struct state_variable, list); + struct state_variable *vb = list_entry(b, struct state_variable, list); + + if (va->index == vb->index) + return 0; + + return va->index < vb->index ? -1 : 1; +} + +static int state_add_variable(struct state *state, struct state_variable *var) +{ + list_add_sort(&var->list, &state->variables, state_var_compare); + + return 0; +} + +static inline struct state_uint32 *to_state_uint32(struct state_variable *s) +{ + return container_of(s, struct state_uint32, var); +} + +static int state_uint32_export(struct state_variable *var, + struct device_node *node) +{ + struct state_uint32 *su32 = to_state_uint32(var); + int ret; + + ret = of_property_write_u32(node, "default", su32->value_default); + if (ret) + return ret; + + return of_property_write_u32(node, "value", su32->value); +} + +static int state_uint32_init(struct state_variable *sv, + struct device_node *node) +{ + int len; + const __be32 *value, *value_default; + struct state_uint32 *su32 = to_state_uint32(sv); + + value_default = of_get_property(node, "default", &len); + if (value_default && len != sizeof(uint32_t)) + return -EINVAL; + + value = of_get_property(node, "value", &len); + if (value && len != sizeof(uint32_t)) + return -EINVAL; + + if (value_default) + su32->value_default = be32_to_cpu(*value_default); + if (value) + su32->value = be32_to_cpu(*value); + else + su32->value = su32->value_default; + + return 0; +} + +static struct state_variable *state_uint32_create(struct state *state, + const char *name, struct device_node *node) +{ + struct state_uint32 *su32; + + su32 = xzalloc(sizeof(*su32)); + + pr_debug("%s: %s\n", __func__, name); + + su32->var.raw_size = sizeof(uint32_t); + su32->var.raw = &su32->value; + + return &su32->var; +} + +static int state_uint32_set(struct state_variable *var, const char *val) +{ + struct state_uint32 *su32 = to_state_uint32(var); + + su32->value = strtoul(val, NULL, 0); + + return 0; +} + +static char *state_uint32_get(struct state_variable *var) +{ + struct state_uint32 *su32 = to_state_uint32(var); + char *str; + int ret; + + ret = asprintf(&str, "%d", su32->value); + if (ret < 0) + return ERR_PTR(-ENOMEM); + + return str; +} + +/* + * enum32 + */ +struct state_enum32 { + struct state_variable var; + struct param_d *param; + uint32_t value; + uint32_t value_default; + const char **names; + int num_names; +}; + +static inline struct state_enum32 *to_state_enum32(struct state_variable *s) +{ + return container_of(s, struct state_enum32, var); +} + +static int state_enum32_export(struct state_variable *var, + struct device_node *node) +{ + struct state_enum32 *enum32 = to_state_enum32(var); + int ret, i, len; + char *prop, *str; + + ret = of_property_write_u32(node, "default", enum32->value_default); + if (ret) + return ret; + + ret = of_property_write_u32(node, "value", enum32->value); + if (ret) + return ret; + + len = 0; + + for (i = 0; i < enum32->num_names; i++) + len += strlen(enum32->names[i]) + 1; + + prop = xzalloc(len); + str = prop; + + for (i = 0; i < enum32->num_names; i++) + str += sprintf(str, "%s", enum32->names[i]) + 1; + + ret = of_set_property(node, "names", prop, len, 1); + + free(prop); + + return ret; +} + +static int state_enum32_init(struct state_variable *sv, struct device_node *node) +{ + struct state_enum32 *enum32 = to_state_enum32(sv); + int len; + const __be32 *value, *value_default; + + value = of_get_property(node, "value", &len); + if (value && len != sizeof(uint32_t)) + return -EINVAL; + + value_default = of_get_property(node, "default", &len); + if (value_default && len != sizeof(uint32_t)) + return -EINVAL; + + if (value_default) + enum32->value_default = be32_to_cpu(*value_default); + if (value) + enum32->value = be32_to_cpu(*value); + else + enum32->value = enum32->value_default; + + return 0; +} + +static struct state_variable *state_enum32_create(struct state *state, + const char *name, struct device_node *node) +{ + struct state_enum32 *enum32; + int ret, i, num_names; + + enum32 = xzalloc(sizeof(*enum32)); + + num_names = of_property_count_strings(node, "names"); + + enum32->names = xzalloc(sizeof(char *) * num_names); + enum32->num_names = num_names; + enum32->var.raw_size = sizeof(uint32_t); + enum32->var.raw = &enum32->value; + + for (i = 0; i < num_names; i++) { + const char *name; + + ret = of_property_read_string_index(node, "names", i, &name); + if (ret) + goto out; + enum32->names[i] = strdup(name); + } + + pr_debug("%s: %s\n", __func__, name); + + return &enum32->var; +out: + free(enum32->names); + free(enum32); + return ERR_PTR(ret); +} + +static int state_enum32_set(struct state_variable *sv, const char *val) +{ + struct state_enum32 *enum32 = to_state_enum32(sv); + int i; + + for (i = 0; i < enum32->num_names; i++) { + if (!strcmp(enum32->names[i], val)) { + enum32->value = i; + return 0; + } + } + + return -EINVAL; +} + +static char *state_enum32_get(struct state_variable *var) +{ + struct state_enum32 *enum32 = to_state_enum32(var); + char *str; + int ret; + + ret = asprintf(&str, "%s", enum32->names[enum32->value]); + if (ret < 0) + return ERR_PTR(-ENOMEM); + + return str; +} + +static void state_enum32_info(struct state_variable *var) +{ + struct state_enum32 *enum32 = to_state_enum32(var); + int i; + + printf(", values=["); + + for (i = 0; i < enum32->num_names; i++) + printf("%s%s", enum32->names[i], + i == enum32->num_names - 1 ? "" : ","); + printf("]"); +} + +/* + * MAC address + */ +struct state_mac { + struct state_variable var; + struct param_d *param; + uint8_t value[6]; + uint8_t value_default[6]; +}; + +static inline struct state_mac *to_state_mac(struct state_variable *s) +{ + return container_of(s, struct state_mac, var); +} + +static int state_mac_export(struct state_variable *var, + struct device_node *node) +{ + struct state_mac *mac = to_state_mac(var); + int ret; + + ret = of_property_write_u8_array(node, "default", mac->value_default, 6); + if (ret) + return ret; + + return of_property_write_u8_array(node, "value", mac->value, 6); +} + +static int state_mac_init(struct state_variable *sv, struct device_node *node) +{ + struct state_mac *mac = to_state_mac(sv); + uint8_t value[6] = {}; + uint8_t value_default[6] = {}; + + of_property_read_u8_array(node, "default", value_default, 6); + memcpy(mac->value_default, value_default, 6); + + if (!of_property_read_u8_array(node, "value", value, 6)) + memcpy(mac->value, value, 6); + else + memcpy(mac->value, value_default, 6); + + return 0; +} + +static struct state_variable *state_mac_create(struct state *state, + const char *name, struct device_node *node) +{ + struct state_mac *mac; + int ret; + + mac = xzalloc(sizeof(*mac)); + + mac->var.raw_size = 6; + mac->var.raw = mac->value; + + pr_debug("%s: %s\n", __func__, name); + + return &mac->var; +out: + free(mac); + return ERR_PTR(ret); +} + +int string_to_ethaddr(const char *str, uint8_t enetaddr[6]) +{ + int reg; + char *e; + + if (!str || strlen(str) != 17) { + memset(enetaddr, 0, 6); + return -EINVAL; + } + + if (str[2] != ':' || str[5] != ':' || str[8] != ':' || + str[11] != ':' || str[14] != ':') + return -EINVAL; + + for (reg = 0; reg < 6; ++reg) { + enetaddr[reg] = strtoul(str, &e, 16); + str = e + 1; + } + + return 0; +} + +static int state_mac_set(struct state_variable *var, const char *val) +{ + struct state_mac *mac = to_state_mac(var); + char mac_save[6]; + int ret; + + ret = string_to_ethaddr(val, mac_save); + if (ret) + return ret; + + memcpy(mac->value, mac_save, 6); + + return 0; +} + +static char *state_mac_get(struct state_variable *var) +{ + struct state_mac *mac = to_state_mac(var); + char *str; + int ret; + + ret = asprintf(&str, "%02x:%02x:%02x:%02x:%02x:%02x", + mac->value[0], mac->value[1], mac->value[2], + mac->value[3], mac->value[4], mac->value[5]); + if (ret < 0) + return ERR_PTR(-ENOMEM); + + return str; +} + +static struct variable_type types[] = { + { + .type = STATE_TYPE_U32, + .type_name = "uint32", + .export = state_uint32_export, + .init = state_uint32_init, + .create = state_uint32_create, + .set = state_uint32_set, + .get = state_uint32_get, + }, { + .type = STATE_TYPE_ENUM, + .type_name = "enum32", + .export = state_enum32_export, + .init = state_enum32_init, + .create = state_enum32_create, + .set = state_enum32_set, + .get = state_enum32_get, + .info = state_enum32_info, + }, { + .type = STATE_TYPE_MAC, + .type_name = "mac", + .export = state_mac_export, + .init = state_mac_init, + .create = state_mac_create, + .set = state_mac_set, + .get = state_mac_get, + }, +}; + +static struct variable_type *state_find_type(enum state_variable_type type) +{ + int i; + + for (i = 0; i < ARRAY_SIZE(types); i++) { + if (type == types[i].type) { + return &types[i]; + } + } + + return NULL; +} + +static struct variable_type *state_find_type_by_name(const char *name) +{ + int i; + + for (i = 0; i < ARRAY_SIZE(types); i++) { + if (!strcmp(name, types[i].type_name)) { + return &types[i]; + } + } + + return NULL; +} + +/* + * Generic state functions + */ + +static struct state *state_new(const char *name) +{ + struct state *state; + int ret; + + state = xzalloc(sizeof(*state)); + state->name = name; + INIT_LIST_HEAD(&state->variables); + + list_add_tail(&state->list, &state_list); + + return state; +} + +static void state_release(struct state *state) +{ + free(state); +} + +static struct device_node *state_to_node(struct state *state) +{ + struct device_node *root, *node; + struct state_variable *sv; + int ret; + + root = of_new_node(NULL, NULL); + + list_for_each_entry(sv, &state->variables, list) { + struct variable_type *vtype; + char *name; + + asprintf(&name, "%s@%d", sv->name, sv->index); + node = of_new_node(root, name); + free(name); + + vtype = state_find_type(sv->type); + if (!vtype) { + ret = -ENOENT; + goto out; + } + + of_set_property(node, "type", vtype->type_name, + strlen(vtype->type_name) + 1, 1); + + ret = vtype->export(sv, node); + if (ret) + goto out; + } + + of_property_write_u32(root, "magic", state->magic); + + return root; +out: + of_delete_node(root); + return ERR_PTR(ret); +} + +static struct state_variable *state_find_var(struct state *state, const char *name) +{ + struct state_variable *sv; + + list_for_each_entry(sv, &state->variables, list) { + if (!strcmp(sv->name, name)) + return sv; + } + + return NULL; +} + +static char *state_get_var(struct state *state, const char *var) +{ + struct state_variable *sv; + struct variable_type *vtype; + + sv = state_find_var(state, var); + if (!sv) + return NULL; + + vtype = state_find_type(sv->type); + + return vtype->get(sv); +} + +static int state_set_var(struct state *state, const char *var, const char *val) +{ + struct state_variable *sv; + struct variable_type *vtype; + int ret; + + sv = state_find_var(state, var); + if (!sv) + return -ENOENT; + + vtype = state_find_type(sv->type); + + if (!vtype->set) + return -EPERM; + + ret = vtype->set(sv, val); + if (ret) + return ret; + + state->dirty = 1; + + return 0; +} + +static int state_variable_from_node(struct state *state, struct device_node *node, + bool create) +{ + struct variable_type *vtype; + struct state_variable *sv; + char *name, *indexs; + int index = 0; + const char *type_name = NULL; + + of_property_read_string(node, "type", &type_name); + if (!type_name) + return -EINVAL; + + vtype = state_find_type_by_name(type_name); + if (!vtype) + return -ENOENT; + + name = strdup(node->name); + indexs = strchr(name, '@'); + if (indexs) { + *indexs++ = 0; + index = strtoul(indexs, NULL, 10); + } + + if (create) { + sv = vtype->create(state, name, node); + if (IS_ERR(sv)) { + int ret = PTR_ERR(sv); + pr_err("failed to create %s: %s\n", name, strerror(-ret)); + return ret; + } + sv->name = name; + sv->type = vtype->type; + sv->index = index; + state_add_variable(state, sv); + } else { + sv = state_find_var(state, name); + if (IS_ERR(sv)) { + int ret = PTR_ERR(sv); + pr_err("no such variable: %s: %s\n", name, strerror(-ret)); + return ret; + } + } + + vtype->init(sv, node); + + return 0; +} + +int state_from_node(struct state *state, struct device_node *node, bool create) +{ + struct device_node *child; + int ret; + uint32_t magic; + + of_property_read_u32(node, "magic", &magic); + + if (create) { + state->magic = magic; + } else { + if (state->magic && state->magic != magic) { + pr_err("invalid magic 0x%08x, should be 0x%08x\n", + magic, state->magic); + return -EINVAL; + } + } + + for_each_child_of_node(node, child) { + ret = state_variable_from_node(state, child, create); + if (ret) + return ret; + } + + return 0; +} + +/* + * state_new_from_node - create a new state instance from a device_node + * + * @name The name of the new state instance + * @node The device_node describing the new state instance + */ +struct state *state_new_from_node(const char *name, struct device_node *node) +{ + struct state *state; + int ret; + + state = state_new(name); + if (!state) + return ERR_PTR(-EINVAL); + + ret = state_from_node(state, node, 1); + if (ret) { + state_release(state); + return ERR_PTR(ret); + } + + return state; +} + +/* + * state_by_name - find a state instance by name + * + * @name The name of the state instance + */ +struct state *state_by_name(const char *name) +{ + struct state *s; + + list_for_each_entry(s, &state_list, list) { + if (!strcmp(name, s->name)) + return s; + } + + return NULL; +} + +/* + * state_load - load a state from the backing store + * + * @state The state instance to load + */ +int state_load(struct state *state) +{ + int ret; + + if (!state->backend) + return -ENOSYS; + + ret = state->backend->load(state->backend, state); + if (ret) + return ret; + + state->dirty = 0; + + return 0; +} + +/* + * state_save - save a state to the backing store + * + * @state The state instance to save + */ +int state_save(struct state *state) +{ + int ret; + + if (!state->backend) + return -ENOSYS; + + ret = state->backend->save(state->backend, state); + if (ret) + return ret; + + state->dirty = 0; + + return 0; +} + +void state_info(void) +{ + struct state *s; + + printf("registered state instances:\n"); + + list_for_each_entry(s, &state_list, list) { + printf("%-20s ", s->name); + if (s->backend) + printf("(backend: %s, path: %s)\n", s->backend->name, s->backend->path); + else + printf("(no backend)\n"); + } +} + +static int get_meminfo(const char *path, struct mtd_info_user *meminfo) +{ + int fd, ret; + + fd = open(path, O_RDWR); + if (fd < 0) + return -errno; + + ret = ioctl(fd, MEMGETINFO, meminfo); + + close(fd); + + if (ret) + return -errno; + + return 0; +} + +/* + * Raw backend implementation + */ +struct state_backend_raw { + struct state_backend backend; + struct state *state; + unsigned long size_data; /* The raw data size (without magic and crc) */ + unsigned long size_full; + unsigned long step; /* The step in bytes between two copies */ + off_t offset; /* offset in the storage file */ + size_t size; /* size of the storage area */ + int need_erase; + int num_copy_read; /* The first successfully read copy */ +}; + +struct backend_raw_header { + uint32_t magic; + uint16_t reserved; + uint16_t data_len; + uint32_t data_crc; + uint32_t header_crc; +}; + +static int backend_raw_load_one(struct state_backend_raw *backend_raw, + int fd, off_t offset) +{ + struct state *state = backend_raw->state; + uint32_t crc; + void *off; + struct state_variable *sv; + struct backend_raw_header header = {}; + int ret, len; + void *buf; + + ret = lseek(fd, offset, SEEK_SET); + if (ret < 0) + return ret; + + ret = read(fd, &header, sizeof(header)); + if (ret < 0) + return ret; + if (ret < sizeof(header)) + return -EINVAL; + + crc = crc32(0, &header, sizeof(header) - sizeof(uint32_t)); + if (crc != header.header_crc) { + pr_err("invalid header crc, calculated 0x%08x, found 0x%08x\n", + crc, header.header_crc); + return -EINVAL; + } + + if (state->magic && state->magic != header.magic) { + pr_err("invalid magic 0x%08x, should be 0x%08x\n", + header.magic, state->magic); + return -EINVAL; + } + + buf = xzalloc(header.data_len); + + ret = read(fd, buf, header.data_len); + if (ret < 0) + return ret; + if (ret < header.data_len) + return -EINVAL; + + crc = crc32(0, buf, header.data_len); + if (crc != header.data_crc) { + pr_err("invalid crc, calculated 0x%08x, found 0x%08x\n", + crc, header.data_crc); + return -EINVAL; + } + + off = buf; + len = header.data_len; + + list_for_each_entry(sv, &state->variables, list) { + if (len < sv->raw_size) { + break; + } + memcpy(sv->raw, off, sv->raw_size); + off += sv->raw_size; + len -= sv->raw_size; + } + + free(buf); + + return 0; +} + +static int state_backend_raw_load(struct state_backend *backend, struct state *state) +{ + struct state_backend_raw *backend_raw = container_of(backend, + struct state_backend_raw, backend); + int ret = 0, fd, i; + + fd = open(backend->path, O_RDONLY); + if (fd < 0) + return fd; + + for (i = 0; i < 2; i++) { + off_t offset = backend_raw->offset + i * backend_raw->step; + + ret = backend_raw_load_one(backend_raw, fd, offset); + if (!ret) { + backend_raw->num_copy_read = i; + pr_debug("copy %d successfully loaded\n", i); + break; + } + } + + close(fd); + + return ret; +} + +static int backend_raw_write_one(struct state_backend_raw *backend_raw, + int fd, int num, void *buf, size_t size) +{ + int ret; + off_t offset = backend_raw->offset + num * backend_raw->step; + + pr_debug(&backend_raw->state->dev, "%s: 0x%08lx 0x%08x\n", + __func__, offset, size); + + if (backend_raw->need_erase) { + struct erase_info_user erase = { + .start = offset, + .length = backend_raw->step, + }; + + ret = ioctl(fd, MEMERASE, &erase); + if (ret < 0) + return -errno; + } + + ret = lseek(fd, offset, SEEK_SET); + if (ret < 0) + return -errno; + + ret = write(fd, buf, size); + if (ret < 0) + return -errno; + + return 0; +} + +static int state_backend_raw_save(struct state_backend *backend, struct state *state) +{ + struct state_backend_raw *backend_raw = container_of(backend, + struct state_backend_raw, backend); + int ret = 0, size, fd; + void *buf, *freep, *off, *data, *tmp; + struct backend_raw_header *header; + struct state_variable *sv; + + size = backend_raw->size_data + sizeof(struct backend_raw_header); + + freep = off = buf = xzalloc(size); + + header = buf; + data = buf + sizeof(*header); + + tmp = data; + list_for_each_entry(sv, &state->variables, list) { + memcpy(tmp, sv->raw, sv->raw_size); + tmp += sv->raw_size; + } + + header->magic = state->magic; + header->data_len = backend_raw->size_data; + header->data_crc = crc32(0, data, backend_raw->size_data); + header->header_crc = crc32(0, header, sizeof(*header) - sizeof(uint32_t)); + + fd = open(backend->path, O_WRONLY); + if (fd < 0) + return fd; + + ret = backend_raw_write_one(backend_raw, fd, !backend_raw->num_copy_read, buf, size); + if (ret) + goto out; + + ret = backend_raw_write_one(backend_raw, fd, backend_raw->num_copy_read, buf, size); + if (ret) + goto out; + + pr_debug("wrote state to %s\n", backend->path); +out: + close(fd); + free(buf); + + return ret; +} + +/* + * state_backend_raw_file - create a raw file backend store for a state instance + * + * @state The state instance to work on + * @path The path where the state will be stored to + * @offset The offset in the storage file + * @size The maximum size to use in the storage file + * + * This backend stores raw binary data from a state instance. The binary data is + * protected with a magic value which has to match and a crc32 that must be valid. + * Up to four copies are stored if there is sufficient space available. + * @path can be a path to a device or a regular file. When it's a device @size may + * be 0. The four copies a spread to different eraseblocks if approriate for this + * device. + */ +int state_backend_raw_file(struct state *state, const char *path, off_t offset, + size_t size) +{ + struct state_backend_raw *backend_raw; + struct state_backend *backend; + struct state_variable *sv; + int ret; + struct stat s; + struct mtd_info_user meminfo; + + if (state->backend) + return -EBUSY; + + ret = stat(path, &s); + if (!ret && !S_ISCHR(s.st_mode)) { + if (size == 0) + size = s.st_size; + else if (offset + size > s.st_size) + return -EINVAL; + } + + backend_raw = xzalloc(sizeof(*backend_raw)); + backend = &backend_raw->backend; + + backend->load = state_backend_raw_load; + backend->save = state_backend_raw_save; + backend->path = strdup(path); + backend->name = "raw"; + + list_for_each_entry(sv, &state->variables, list) + backend_raw->size_data += sv->raw_size; + + backend_raw->state = state; + backend_raw->offset = offset; + backend_raw->size_full = backend_raw->size_data + sizeof(struct backend_raw_header); + + state->backend = backend; + + ret = get_meminfo(backend->path, &meminfo); + if (!ret) { + if (!size) + size = meminfo.size; + backend_raw->need_erase = 1; + backend_raw->step = ALIGN(backend_raw->size_full, meminfo.erasesize); + if (verbose) + fprintf(stderr, "%s is a mtd of size %d, adjust stepsize to %ld\n", + path, meminfo.size, backend_raw->step); + } else { + backend_raw->step = backend_raw->size_full; + } + + backend_raw->size = size; + + if (backend_raw->size / backend_raw->step < 2) { + pr_err("not enough space for two copies, have %d, need %d\n", + backend_raw->size, backend_raw->step * 2); + ret = -ENOSPC; + goto err; + } + + return 0; +err: + free(backend_raw); + return ret; +} + +static struct state *state_get(const char *name) +{ + struct device_node *root, *node; + char *path; + struct state *state; + int ret; + const char *backend_type = NULL; + struct of_path op; + struct state_variable *v; + + root = of_read_proc_devicetree(); + if (IS_ERR(root)) { + fprintf(stderr, "Unable to read devicetree from /proc/device-tree: %s\n", + strerror(-PTR_ERR(root))); + return ERR_CAST(root); + } + + of_set_root_node(root); + + node = of_find_node_by_path_or_alias(root, name); + if (!node) { + fprintf(stderr, "no such node: %s\n", name); + return ERR_PTR(-ENOENT); + } + + if (verbose > 1) { + printf("found state node %s:\n", node->full_name); + of_print_nodes(node, 0); + } + + state = state_new_from_node("state", node); + if (IS_ERR(state)) { + fprintf(stderr, "unable to initlialize state: %s\n", + strerror(PTR_ERR(state))); + return ERR_CAST(state); + } + + ret = of_find_path(node, "backend", &op); + if (ret) { + fprintf(stderr, "Cannot find backend path in %s\n", node->full_name); + return ERR_PTR(ret); + } + + of_property_read_string(node, "backend-type", &backend_type); + if (!strcmp(backend_type, "raw")) + ret = state_backend_raw_file(state, op.devpath, op.offset, op.size); + else + fprintf(stderr, "invalid backend type: %s\n", backend_type); + + if (ret) { + fprintf(stderr, "Cannot initialize backend: %s\n", strerror(-ret)); + return ERR_PTR(ret); + } + + return state; +} + +enum opt { + OPT_DUMP_SHELL = 1, +}; + +static struct option long_options[] = { + {"get", required_argument, 0, 'g' }, + {"set", required_argument, 0, 's' }, + {"name", required_argument, 0, 'n' }, + {"dump", no_argument, 0, 'd' }, + {"dump-shell", no_argument, 0, OPT_DUMP_SHELL }, + {"init", no_argument, 0, 'i' }, + {"verbose", no_argument, 0, 'v' }, + {"help", no_argument, 0, 'h' }, +}; + +static void usage(char *name) +{ + printf( +"Usage: %s [OPTIONS]\n" +"\n" +"-g, --get <variable> get the value of a variable\n" +"-s, --set <variable>=<value> set the value of a variable\n" +"-n, --name <name> specify the state to use (default=\"state\")\n" +"-d, --dump dump the state\n" +"--dump-shell dump the state suitable for shell sourcing\n" +"--init initialize the state (do not load from storage)\n" +"-v, --verbose increase verbosity\n" +"--help this help\n", + name); +} + +#define state_for_each_var(state, var) \ + list_for_each_entry(var, &(state)->variables, list) + +struct state_set_get { + char *arg; + int get; + struct list_head list; +}; + +int main(int argc, char *argv[]) +{ + struct state *state; + struct state_variable *v; + int ret, c, option_index; + int do_dump = 0, do_dump_shell = 0, do_initialize = 0; + struct state_set_get *sg; + struct list_head sg_list; + char *statename = "state"; + + INIT_LIST_HEAD(&sg_list); + + while (1) { + c = getopt_long(argc, argv, "hg:s:divn:", long_options, &option_index); + if (c < 0) + break; + switch (c) { + case 'h': + usage(argv[0]); + exit(0); + case 'g': + sg = xzalloc(sizeof(*sg)); + sg->get = 1; + sg->arg = optarg; + list_add_tail(&sg->list, &sg_list); + break; + case 's': + sg = xzalloc(sizeof(*sg)); + sg->get = 0; + sg->arg = optarg; + list_add_tail(&sg->list, &sg_list); + break; + case 'd': + do_dump = 1; + break; + case 'i': + do_initialize = 1; + break; + case OPT_DUMP_SHELL: + do_dump_shell = 1; + break; + case 'v': + verbose++; + break; + case 'n': + statename = optarg; + } + } + + state = state_get(statename); + if (IS_ERR(state)) + exit(1); + + ret = state_load(state); + if (!do_initialize && ret) { + fprintf(stderr, "Cannot load state: %s\n", strerror(-ret)); + exit(1); + } + + if (do_dump) { + state_for_each_var(state, v) { + struct variable_type *vtype; + vtype = state_find_type(v->type); + printf("%s=%s", v->name, vtype->get(v)); + if (verbose) { + printf(", type=%s", vtype->type_name); + if (vtype->info) + vtype->info(v); + } + printf("\n"); + } + } + + if (do_dump_shell) { + state_for_each_var(state, v) { + struct variable_type *vtype; + vtype = state_find_type(v->type); + printf("STATE_%s=\"%s\"\n", v->name, vtype->get(v)); + } + } + + list_for_each_entry(sg, &sg_list, list) { + if (sg->get) { + char *val = state_get_var(state, sg->arg); + if (!val) { + fprintf(stderr, "no such variable: %s\n", sg->arg); + exit (1); + } + + printf("%s\n", val); + } else { + char *var, *val; + + var = sg->arg; + val = index(sg->arg, '='); + if (!val) { + fprintf(stderr, "usage: -s var=val\n"); + exit (1); + } + *val++ = '\0'; + ret = state_set_var(state, var, val); + if (ret) { + fprintf(stderr, "Failed to set variable %s to %s: %s\n", + var, val, strerror(-ret)); + exit(1); + } + } + } + + if (state->dirty) { + ret = state_save(state); + if (ret) { + fprintf(stderr, "Failed to save state: %s\n", strerror(-ret)); + exit(1); + } + } + + return 0; +} |